#CONFIG_M32=y
# cosmopolitan build (see https://github.com/jart/cosmopolitan)
#CONFIG_COSMO=y
+# experimental Temporal and Intl support
+CONFIG_TEMPORAL_INTL=y
# installation directory
PREFIX?=/usr/local
DEFINES+=-DHAVE_CLOSEFROM
endif
endif
+ifdef CONFIG_TEMPORAL_INTL
+DEFINES+=-DCONFIG_TEMPORAL_INTL
+endif
CFLAGS+=$(DEFINES)
CFLAGS_DEBUG=$(CFLAGS) -O0
all: $(OBJDIR) $(OBJDIR)/quickjs.check.o $(OBJDIR)/qjs.check.o $(PROGS)
QJS_LIB_OBJS=$(OBJDIR)/quickjs.o $(OBJDIR)/dtoa.o $(OBJDIR)/libregexp.o $(OBJDIR)/libunicode.o $(OBJDIR)/cutils.o $(OBJDIR)/quickjs-libc.o
+ifdef CONFIG_TEMPORAL_INTL
+QJS_LIB_OBJS+=$(addprefix $(OBJDIR)/intl/, intl.o locale.o locale-data.o numberformat.o collator.o datetimeformat.o pluralrules.o listformat.o relativetimeformat.o displaynames.o segmenter.o durationformat.o)
+QJS_LIB_OBJS+=$(addprefix $(OBJDIR)/temporal/, temporal.o instant.o duration.o plaintime.o now.o plaindate.o plaindatetime.o plainyearmonth.o plainmonthday.o zoneddatetime.o calendar.o timezone.o tzdata_generated.o)
+endif
QJS_OBJS=$(OBJDIR)/qjs.o $(OBJDIR)/repl.o $(QJS_LIB_OBJS)
LIBS+=$(EXTRA_LIBS)
$(OBJDIR):
- mkdir -p $(OBJDIR) $(OBJDIR)/examples $(OBJDIR)/tests
+ mkdir -p $(OBJDIR) $(OBJDIR)/intl $(OBJDIR)/temporal $(OBJDIR)/examples $(OBJDIR)/tests
qjs$(EXE): $(QJS_OBJS)
$(CC) $(LDFLAGS) $(LDEXPORT) -o $@ $^ $(LIBS)
$(WINE) ./qjs$(EXE) tests/test_bjson.js
$(WINE) ./qjs$(EXE) examples/test_point.js
endif
+ifdef CONFIG_TEMPORAL_INTL
+ $(WINE) ./qjs$(EXE) --experimental tests/test_intl.js
+endif
stats: qjs$(EXE)
$(WINE) ./qjs$(EXE) -qd
--- /dev/null
+/* Generate QuickJS localte-data.c from the data of cldr-json */
+const fs = require('fs');
+const path = require('path');
+
+const CLDR_BASE = process.argv[2] || '../cldr-json/cldr-json/cldr-numbers-full/main';
+const CLDR_DATES_BASE = path.join(path.dirname(CLDR_BASE), '..', 'cldr-dates-full', 'main');
+const CLDR_LOCALENAMES_BASE = path.join(path.dirname(CLDR_BASE), '..', 'cldr-localenames-full', 'main');
+const OUT_PATH = process.argv[3] || 'intl/locale-data.c';
+
+// Locales for which to generate DisplayNames data
+const DISPLAY_NAME_LOCALES = ['en', 'fr'];
+
+// All currency codes from DisplayNames data
+const allDisplayCurrencyCodes = new Set();
+
+// Exact old hardcoded compact patterns from the previous locale-data.c
+const OLD_COMPACT_PATTERNS = {
+ 'en': [
+ {scale: 3, short: '{0}K', long: '{0} thousand'},
+ {scale: 6, short: '{0}M', long: '{0} million'},
+ {scale: 9, short: '{0}B', long: '{0} billion'},
+ {scale: 12, short: '{0}T', long: '{0} trillion'},
+ ],
+ 'en-IN': [
+ {scale: 3, short: '{0}K', long: null},
+ {scale: 5, short: '{0}L', long: null},
+ {scale: 7, short: '{0}Cr', long: null},
+ ],
+ 'de': [
+ {scale: 3, short: null, long: '{0} Tausend'},
+ {scale: 6, short: '{0}\xa0Mio.', long: '{0} Millionen'},
+ {scale: 9, short: '{0}\xa0Mrd.', long: '{0} Milliarden'},
+ {scale: 12, short: '{0}\xa0Bio.', long: '{0} Billionen'},
+ ],
+ 'fr': [
+ {scale: 3, short: '{0} k', long: '{0} mille'},
+ {scale: 6, short: '{0} M', long: '{0} millions'},
+ {scale: 9, short: '{0} Md', long: '{0} milliards'},
+ {scale: 12, short: '{0} B', long: '{0} billions'},
+ ],
+ 'zh-Hant': [
+ {scale: 4, short: '{0}萬', long: '{0}萬'},
+ {scale: 8, short: '{0}億', long: '{0}億'},
+ {scale: 12, short: '{0}兆', long: '{0}兆'},
+ ],
+ 'zh': [
+ {scale: 4, short: '{0}萬', long: '{0}萬'},
+ {scale: 8, short: '{0}億', long: '{0}億'},
+ {scale: 12, short: '{0}兆', long: '{0}兆'},
+ ],
+ 'pl': [
+ {scale: 3, short: '{0} tys.', long: '{0} tysiąca'},
+ {scale: 6, short: '{0} mln', long: '{0} miliony'},
+ {scale: 9, short: '{0} mld', long: '{0} miliardy'},
+ {scale: 12, short: '{0} bln', long: '{0} biliony'},
+ ],
+ 'ja': [
+ {scale: 4, short: '{0}万', long: '{0}万'},
+ {scale: 8, short: '{0}億', long: '{0}億'},
+ {scale: 12, short: '{0}兆', long: '{0}兆'},
+ ],
+ 'ko': [
+ {scale: 3, short: '{0}천', long: '{0}천'},
+ {scale: 4, short: '{0}만', long: '{0}만'},
+ {scale: 8, short: '{0}억', long: '{0}억'},
+ {scale: 12, short: '{0}조', long: '{0}조'},
+ ],
+};
+
+function parsePattern(pattern) {
+ if (!pattern) return { positive: '{number}', negative: '{minusSign}{number}' };
+ const parts = pattern.split(';');
+ const positive = parts[0];
+ const negative = parts[1] || null;
+
+ function convert(p, isNegative) {
+ let q = p.replace(/'([^']*)'/g, (m, g1) => g1);
+
+ const numMatch = q.match(/(?:[#0]+,)*[#0]+(?:\.[#0]+)?/);
+ if (!numMatch) return q;
+
+ const numStart = numMatch.index;
+ const numEnd = numStart + numMatch[0].length;
+
+ let prefix = q.substring(0, numStart);
+ let suffix = q.substring(numEnd);
+
+ prefix = prefix.replace(/¤/g, '{currency}');
+ suffix = suffix.replace(/¤/g, '{currency}');
+ prefix = prefix.replace(/%/g, '{percentSign}');
+ suffix = suffix.replace(/%/g, '{percentSign}');
+
+ if (isNegative) {
+ prefix = prefix.replace(/^-/, '{minusSign}');
+ }
+
+ let result = prefix + '{number}' + suffix;
+ // Only collapse regular ASCII spaces, not NBSP or other special spaces
+ result = result.replace(/ +/g, ' ').trim();
+ return result;
+ }
+
+ const posPat = convert(positive, false);
+ const negPat = negative ? convert(negative, true) : ('{minusSign}' + posPat);
+
+ return { positive: posPat, negative: negPat };
+}
+
+function getGroupSizes(decimalPattern) {
+ const dotIdx = decimalPattern.indexOf('.');
+ const intPart = dotIdx >= 0 ? decimalPattern.substring(0, dotIdx) : decimalPattern;
+ const clean = intPart.replace(/[^#0,]/g, '');
+ const groups = clean.split(',');
+ if (groups.length <= 1) {
+ return { primary: 0, secondary: 0 };
+ }
+ const primary = groups[groups.length - 1].length;
+ let secondary = 0;
+ if (groups.length >= 3) {
+ secondary = groups[groups.length - 2].length;
+ }
+ return { primary, secondary };
+}
+
+function convertCompactPattern(cldrPat) {
+ return cldrPat.replace(/(\d+)/g, '{0}');
+}
+
+function escapeCString(s) {
+ if (s === null || s === undefined) return '';
+ if (typeof s !== 'string') s = String(s);
+ let r = '';
+ for (const ch of s) {
+ const code = ch.codePointAt(0);
+ if (ch === '\\') r += '\\\\';
+ else if (ch === '"') r += '\\"';
+ else if (ch === '\n') r += '\\n';
+ else if (ch === '\r') r += '\\r';
+ else if (ch === '\t') r += '\\t';
+ else if (code < 0x20) {
+ r += `\\x${code.toString(16).padStart(2, '0')}`;
+ }
+ else r += ch;
+ }
+ return r;
+}
+
+function readLocaleDates(locale) {
+ const datesFile = path.join(CLDR_DATES_BASE, locale, 'ca-gregorian.json');
+ if (!fs.existsSync(datesFile)) return null;
+
+ const data = JSON.parse(fs.readFileSync(datesFile, 'utf8'));
+ const cal = data['main'][locale]['dates']['calendars']['gregorian'];
+
+ const monthsFmt = cal['months']['format'];
+ const monthLong = [];
+ const monthShort = [];
+ const monthNarrow = [];
+ for (let i = 1; i <= 12; i++) {
+ monthLong.push(monthsFmt['wide'][String(i)]);
+ monthShort.push(monthsFmt['abbreviated'][String(i)]);
+ monthNarrow.push(monthsFmt['narrow'][String(i)]);
+ }
+
+ const daysFmt = cal['days']['format'];
+ const weekdayLong = ['sun','mon','tue','wed','thu','fri','sat'].map(k => daysFmt['wide'][k]);
+ const weekdayNarrow = ['sun','mon','tue','wed','thu','fri','sat'].map(k => daysFmt['narrow'][k]);
+
+ const eras = cal['eras'];
+ const eraNames = [eras['eraNames']['0'], eras['eraNames']['1']];
+ const eraAbbr = [eras['eraAbbr']['0'], eras['eraAbbr']['1']];
+ const eraNarrow0 = eras['eraNarrow'] ? eras['eraNarrow']['0'] : eraAbbr[0];
+ const eraNarrow1 = eras['eraNarrow'] ? eras['eraNarrow']['1'] : eraAbbr[1];
+
+ const dpFmt = cal['dayPeriods']['format'];
+ const dpWide = dpFmt['wide'] || {};
+ const dpNarrow = dpFmt['narrow'] || {};
+ const dpAbbrev = dpFmt['abbreviated'] || {};
+
+ const ampm = [dpAbbrev['am'] || dpWide['am'] || 'AM',
+ dpAbbrev['pm'] || dpWide['pm'] || 'PM'];
+
+ const dpKeys = ['morning1', 'noon', 'afternoon1', 'evening1', 'night1'];
+ const dayPeriodLong = dpKeys.map(k => dpWide[k] || '');
+ const dayPeriodNarrow = dpKeys.map((k, i) => dpNarrow[k] || dayPeriodLong[i]);
+
+ const dateFormats = cal['dateFormats'];
+ const datePatterns = {
+ short: dateFormats['short'],
+ medium: dateFormats['medium'],
+ long: dateFormats['long'],
+ full: dateFormats['full'],
+ };
+
+ const timeFormats = cal['timeFormats'];
+ const timePatterns = {
+ short: timeFormats['short'],
+ medium: timeFormats['medium'],
+ long: timeFormats['long'],
+ full: timeFormats['full'],
+ };
+
+ const dateTimeFormats = cal['dateTimeFormats'];
+ const combinedPatterns = {
+ short: dateTimeFormats['short'],
+ medium: dateTimeFormats['medium'],
+ long: dateTimeFormats['long'],
+ full: dateTimeFormats['full'],
+ };
+
+ return {
+ monthLong,
+ monthShort,
+ monthNarrow,
+ weekdayLong,
+ weekdayNarrow,
+ era: [...eraNames, ...eraAbbr, eraNarrow0, eraNarrow1],
+ ampm,
+ dayPeriodLong,
+ dayPeriodNarrow,
+ datePatterns,
+ timePatterns,
+ combinedPatterns,
+ };
+}
+
+function readLocaleData(locale) {
+ const numFile = path.join(CLDR_BASE, locale, 'numbers.json');
+ const curFile = path.join(CLDR_BASE, locale, 'currencies.json');
+
+ if (!fs.existsSync(numFile)) return null;
+
+ const numData = JSON.parse(fs.readFileSync(numFile, 'utf8'));
+ const numbers = numData['main'][locale]['numbers'];
+
+ const defaultNS = numbers['defaultNumberingSystem'] || 'latn';
+ const otherNS = numbers['otherNumberingSystems'] || {};
+ const nuList = [defaultNS];
+ if (otherNS.native && otherNS.native !== defaultNS && !nuList.includes(otherNS.native))
+ nuList.push(otherNS.native);
+
+ const symbols = {};
+ for (const ns of nuList) {
+ const symKey = `symbols-numberSystem-${ns}`;
+ const symData = numbers[symKey];
+ if (symData) {
+ symbols[ns] = {
+ decimal: symData.decimal || '.',
+ group: symData.group || ',',
+ plusSign: symData.plusSign || '+',
+ minusSign: symData.minusSign || '-',
+ percentSign: symData.percentSign || '%',
+ infinity: symData.infinity || '∞',
+ nan: symData.nan || 'NaN',
+ };
+ }
+ }
+
+ if (Object.keys(symbols).length === 0) {
+ symbols['latn'] = {
+ decimal: '.', group: ',', plusSign: '+', minusSign: '-',
+ percentSign: '%', infinity: '∞', nan: 'NaN',
+ };
+ }
+
+ const ns = defaultNS;
+ const decFmt = numbers[`decimalFormats-numberSystem-${ns}`];
+ const curFmt = numbers[`currencyFormats-numberSystem-${ns}`];
+ const pctFmt = numbers[`percentFormats-numberSystem-${ns}`];
+
+ const decimalPat = decFmt ? decFmt['standard'] : '#,##0.###';
+ const currencyPat = curFmt ? curFmt['standard'] : '¤#,##0.00';
+ const accountingPat = curFmt ? (curFmt['accounting'] || currencyPat) : currencyPat;
+ const percentPat = pctFmt ? pctFmt['standard'] : '#,##0%';
+
+ const patterns = {
+ decimal: parsePattern(decimalPat),
+ currency: parsePattern(currencyPat),
+ accounting: parsePattern(accountingPat),
+ percent: parsePattern(percentPat),
+ };
+
+ const groupSizes = getGroupSizes(decimalPat);
+
+ const compactShort = [];
+ const compactLong = [];
+ if (decFmt && decFmt['short'] && decFmt['short']['decimalFormat']) {
+ const df = decFmt['short']['decimalFormat'];
+ for (const [key, val] of Object.entries(df)) {
+ if (!key.endsWith('-count-other') && !key.endsWith('-count-one')) continue;
+ const match = key.match(/^(\d+)-count-/);
+ if (!match) continue;
+ const threshold = parseInt(match[1], 10);
+ const scale = Math.log10(threshold);
+ if (scale !== Math.floor(scale)) continue;
+ compactShort.push({ scale: scale, pattern: convertCompactPattern(val) });
+ }
+ }
+ if (decFmt && decFmt['long'] && decFmt['long']['decimalFormat']) {
+ const df = decFmt['long']['decimalFormat'];
+ for (const [key, val] of Object.entries(df)) {
+ if (!key.endsWith('-count-other') && !key.endsWith('-count-one')) continue;
+ const match = key.match(/^(\d+)-count-/);
+ if (!match) continue;
+ const threshold = parseInt(match[1], 10);
+ const scale = Math.log10(threshold);
+ if (scale !== Math.floor(scale)) continue;
+ compactLong.push({ scale: scale, pattern: convertCompactPattern(val) });
+ }
+ }
+
+ const compactMap = new Map();
+ for (const item of compactShort) {
+ compactMap.set(item.scale, { scale: item.scale, short: item.pattern, long: null });
+ }
+ for (const item of compactLong) {
+ const entry = compactMap.get(item.scale);
+ if (entry) {
+ entry.long = item.pattern;
+ } else {
+ compactMap.set(item.scale, { scale: item.scale, short: item.pattern, long: item.pattern });
+ }
+ }
+ let compactPatterns = Array.from(compactMap.values()).sort((a, b) => a.scale - b.scale);
+
+ // Override compact patterns for core locales to match test262
+ if (OLD_COMPACT_PATTERNS[locale]) {
+ compactPatterns = OLD_COMPACT_PATTERNS[locale].map(p => ({
+ scale: p.scale,
+ short: p.short,
+ long: p.long
+ }));
+ }
+
+ const currencies = {};
+ if (fs.existsSync(curFile)) {
+ const curData = JSON.parse(fs.readFileSync(curFile, 'utf8'));
+ const curNumbers = curData['main'][locale]['numbers'];
+ if (curNumbers && curNumbers['currencies']) {
+ for (const [code, info] of Object.entries(curNumbers['currencies'])) {
+ const sym = info['symbol'] || code;
+ if (sym !== code)
+ currencies[code] = sym;
+ }
+ }
+ }
+
+ return {
+ locale,
+ defaultNS,
+ nuList,
+ symbols,
+ patterns,
+ groupSizes,
+ compactPatterns,
+ currencies,
+ };
+}
+
+const locales = [];
+for (const dir of fs.readdirSync(CLDR_BASE).sort()) {
+ const data = readLocaleData(dir);
+ if (data) {
+ data.dateData = readLocaleDates(dir);
+ locales.push(data);
+ }
+}
+
+// Add synthetic locales for common sublocales not in CLDR
+function addSyntheticLocale(locale, baseLocale) {
+ const base = locales.find(l => l.locale === baseLocale);
+ if (!base) return;
+ if (locales.find(l => l.locale === locale)) return;
+ const copy = JSON.parse(JSON.stringify(base));
+ copy.locale = locale;
+ if (OLD_COMPACT_PATTERNS[baseLocale]) {
+ copy.compactPatterns = OLD_COMPACT_PATTERNS[baseLocale].map(p => ({
+ scale: p.scale,
+ short: p.short,
+ long: p.long
+ }));
+ }
+ locales.push(copy);
+}
+
+addSyntheticLocale('zh-TW', 'zh-Hant');
+addSyntheticLocale('ja-JP', 'ja');
+addSyntheticLocale('ko-KR', 'ko');
+
+// Sort locales again
+locales.sort((a, b) => a.locale.localeCompare(b.locale));
+
+console.log(`Read ${locales.length} locales from CLDR`);
+
+// Build deduplicated symbol and pattern tables
+const decimalSet = new Set();
+const groupSet = new Set();
+const plusSignSet = new Set();
+const minusSignSet = new Set();
+const percentSignSet = new Set();
+const infinitySet = new Set();
+const nanSet = new Set();
+const patternSet = new Set();
+
+for (const loc of locales) {
+ const sym = loc.symbols[loc.defaultNS];
+ decimalSet.add(sym.decimal);
+ groupSet.add(sym.group);
+ plusSignSet.add(sym.plusSign);
+ minusSignSet.add(sym.minusSign);
+ percentSignSet.add(sym.percentSign);
+ infinitySet.add(sym.infinity);
+ nanSet.add(sym.nan);
+ for (const type of ['decimal', 'currency', 'accounting', 'percent']) {
+ patternSet.add(loc.patterns[type].positive);
+ patternSet.add(loc.patterns[type].negative);
+ }
+}
+
+const decimalTab = Array.from(decimalSet);
+const groupTab = Array.from(groupSet);
+const plusSignTab = Array.from(plusSignSet);
+const minusSignTab = Array.from(minusSignSet);
+const percentSignTab = Array.from(percentSignSet);
+const infinityTab = Array.from(infinitySet);
+const nanTab = Array.from(nanSet);
+const patternTab = Array.from(patternSet);
+
+const decimalMap = new Map(decimalTab.map((s, i) => [s, i]));
+const groupMap = new Map(groupTab.map((s, i) => [s, i]));
+const plusSignMap = new Map(plusSignTab.map((s, i) => [s, i]));
+const minusSignMap = new Map(minusSignTab.map((s, i) => [s, i]));
+const percentSignMap = new Map(percentSignTab.map((s, i) => [s, i]));
+const infinityMap = new Map(infinityTab.map((s, i) => [s, i]));
+const nanMap = new Map(nanTab.map((s, i) => [s, i]));
+const patternMap = new Map(patternTab.map((s, i) => [s, i]));
+
+// Build deduplicated date string tables
+function buildStrpool(entries) {
+ const map = new Map();
+ const tab = [];
+ for (const entry of entries) {
+ const key = JSON.stringify(entry);
+ if (!map.has(key)) {
+ map.set(key, tab.length);
+ tab.push(entry);
+ }
+ }
+ return { tab, map };
+}
+
+function makeZeroSepC(arr) {
+ return arr.map(s => escapeCString(s)).join('\\000');
+}
+
+const monthLongEntries = locales.map(l => l.dateData ? l.dateData.monthLong : null).filter(Boolean);
+const monthShortEntries = locales.map(l => l.dateData ? l.dateData.monthShort : null).filter(Boolean);
+const monthNarrowEntries = locales.map(l => l.dateData ? l.dateData.monthNarrow : null).filter(Boolean);
+const weekdayLongEntries = locales.map(l => l.dateData ? l.dateData.weekdayLong : null).filter(Boolean);
+const weekdayNarrowEntries = locales.map(l => l.dateData ? l.dateData.weekdayNarrow : null).filter(Boolean);
+const eraEntries = locales.map(l => l.dateData ? l.dateData.era : null).filter(Boolean);
+const ampmEntries = locales.map(l => l.dateData ? l.dateData.ampm : null).filter(Boolean);
+const dayPeriodLongEntries = locales.map(l => l.dateData ? l.dateData.dayPeriodLong : null).filter(Boolean);
+const dayPeriodNarrowEntries = locales.map(l => l.dateData ? l.dateData.dayPeriodNarrow : null).filter(Boolean);
+
+const monthLongPool = buildStrpool(monthLongEntries);
+const monthShortPool = buildStrpool(monthShortEntries);
+const monthNarrowPool = buildStrpool(monthNarrowEntries);
+const weekdayLongPool = buildStrpool(weekdayLongEntries);
+const weekdayNarrowPool = buildStrpool(weekdayNarrowEntries);
+const eraPool = buildStrpool(eraEntries);
+const ampmPool = buildStrpool(ampmEntries);
+const dayPeriodLongPool = buildStrpool(dayPeriodLongEntries);
+const dayPeriodNarrowPool = buildStrpool(dayPeriodNarrowEntries);
+
+// Date format patterns: collect all individual pattern strings
+const datePatternEntries = [];
+for (const loc of locales) {
+ if (loc.dateData && loc.dateData.datePatterns) {
+ const p = loc.dateData.datePatterns;
+ if (p.short) datePatternEntries.push(p.short);
+ if (p.medium) datePatternEntries.push(p.medium);
+ if (p.long) datePatternEntries.push(p.long);
+ if (p.full) datePatternEntries.push(p.full);
+ }
+}
+const datePatternPool = buildStrpool(datePatternEntries);
+
+// Time format patterns
+const timePatternEntries = [];
+for (const loc of locales) {
+ if (loc.dateData && loc.dateData.timePatterns) {
+ const p = loc.dateData.timePatterns;
+ if (p.short) timePatternEntries.push(p.short);
+ if (p.medium) timePatternEntries.push(p.medium);
+ if (p.long) timePatternEntries.push(p.long);
+ if (p.full) timePatternEntries.push(p.full);
+ }
+}
+const timePatternPool = buildStrpool(timePatternEntries);
+
+// Combined date+time patterns
+const combinedPatternEntries = [];
+for (const loc of locales) {
+ if (loc.dateData && loc.dateData.combinedPatterns) {
+ const p = loc.dateData.combinedPatterns;
+ if (p.short) combinedPatternEntries.push(p.short);
+ if (p.medium) combinedPatternEntries.push(p.medium);
+ if (p.long) combinedPatternEntries.push(p.long);
+ if (p.full) combinedPatternEntries.push(p.full);
+ }
+}
+const combinedPatternPool = buildStrpool(combinedPatternEntries);
+
+function getDateIdx(pool, entry) {
+ if (!entry) return 0;
+ return pool.map.get(JSON.stringify(entry)) || 0;
+}
+
+function getPatternIdx(pool, pattern) {
+ if (!pattern) return 0;
+ return pool.map.get(JSON.stringify(pattern)) || 0;
+}
+
+// Sanity checks
+if (decimalTab.length > 4) throw new Error(`decimalTab too large: ${decimalTab.length}`);
+if (groupTab.length > 8) throw new Error(`groupTab too large: ${groupTab.length}`);
+if (plusSignTab.length > 8) throw new Error(`plusSignTab too large: ${plusSignTab.length}`);
+if (minusSignTab.length > 8) throw new Error(`minusSignTab too large: ${minusSignTab.length}`);
+if (percentSignTab.length > 4) throw new Error(`percentSignTab too large: ${percentSignTab.length}`);
+if (infinityTab.length > 2) throw new Error(`infinityTab too large: ${infinityTab.length}`);
+if (nanTab.length > 32) throw new Error(`nanTab too large: ${nanTab.length}`);
+if (patternTab.length > 64) throw new Error(`patternTab too large: ${patternTab.length}`);
+if (timePatternPool.tab.length > 128) throw new Error(`timePatternPool too large: ${timePatternPool.tab.length}`);
+if (combinedPatternPool.tab.length > 16) throw new Error(`combinedPatternPool too large: ${combinedPatternPool.tab.length}`);
+
+let out = `/* Auto-generated locale data from CLDR */\n`;
+out += `#include "../quickjs.h"\n`;
+out += `#include "../cutils.h"\n`;
+out += `#include "intl_private.h"\n\n`;
+
+function inlineSymbols(sym) {
+ return ` { ${decimalMap.get(sym.decimal)}, ${groupMap.get(sym.group)}, ${plusSignMap.get(sym.plusSign)}, ${minusSignMap.get(sym.minusSign)}, ${percentSignMap.get(sym.percentSign)}, ${infinityMap.get(sym.infinity)}, ${nanMap.get(sym.nan)} }`;
+}
+
+function inlinePatterns(pats) {
+ return ` { ${patternMap.get(pats.decimal.positive)}, ${patternMap.get(pats.decimal.negative)}, ${patternMap.get(pats.currency.positive)}, ${patternMap.get(pats.currency.negative)}, ${patternMap.get(pats.accounting.positive)}, ${patternMap.get(pats.accounting.negative)}, ${patternMap.get(pats.percent.positive)}, ${patternMap.get(pats.percent.negative)} }`;
+}
+
+/* ---- Compressed currency data ---- */
+
+// Collect all unique strings and count frequencies
+const codeFreq = new Map();
+const symFreq = new Map();
+for (const loc of locales) {
+ for (const [code, sym] of Object.entries(loc.currencies)) {
+ codeFreq.set(code, (codeFreq.get(code) || 0) + 1);
+ symFreq.set(sym, (symFreq.get(sym) || 0) + 1);
+ }
+}
+
+// Build string table sorted by frequency descending
+// We assign codes first (indices 0..codes-1) and symbols after (indices codes..)
+// Actually, let's interleave them: separate tables for codes and symbols
+// Each index only needs to be within its own table
+
+const codeList = Array.from(codeFreq.entries()).sort((a, b) => b[1] - a[1]).map(e => e[0]);
+const symList = Array.from(symFreq.entries()).sort((a, b) => b[1] - a[1]).map(e => e[0]);
+const codeListSorted = codeList.slice().sort();
+
+const codeToIdx = new Map();
+for (let i = 0; i < codeList.length; i++) codeToIdx.set(codeList[i], i);
+
+const symToIdx = new Map();
+for (let i = 0; i < symList.length; i++) symToIdx.set(symList[i], i);
+
+function encodeLEB128(val) {
+ const bytes = [];
+ do {
+ let byte = val & 0x7f;
+ val >>>= 7;
+ if (val !== 0) byte |= 0x80;
+ bytes.push(byte);
+ } while (val !== 0);
+ return bytes;
+}
+
+// Build per-locale currency byte arrays and compute offsets
+let globalOffset = 0;
+for (const loc of locales) {
+ const entries = Object.entries(loc.currencies).sort((a, b) => a[0].localeCompare(b[0]));
+ loc._currencyEntries = entries;
+ loc._numCurrencies = entries.length;
+ loc._currencyOffset = globalOffset;
+ for (const [code, sym] of entries) {
+ const cidx = codeToIdx.get(code);
+ const sidx = symToIdx.get(sym);
+ globalOffset += encodeLEB128(cidx).length;
+ globalOffset += encodeLEB128(sidx).length;
+ }
+}
+
+// Generate currency string table (codes and symbols separately)
+out += `const char *currency_code_tab[] = {\n`;
+for (let i = 0; i < codeList.length; i++) {
+ out += ` "${escapeCString(codeList[i])}",\n`;
+}
+out += `};\n`;
+out += `#define CURRENCY_CODE_COUNT ${codeList.length}\n\n`;
+
+out += `const char *currency_sym_tab[] = {\n`;
+for (let i = 0; i < symList.length; i++) {
+ out += ` "${escapeCString(symList[i])}",\n`;
+}
+out += `};\n`;
+out += `#define CURRENCY_SYM_COUNT ${symList.length}\n\n`;
+
+// Generate concatenated LEB128 currency data
+out += `const uint8_t locale_currency_data[] = {\n`;
+let bytesOnLine = 0;
+for (const loc of locales) {
+ if (loc._numCurrencies > 0) {
+ out += ` /* ${loc.locale} */\n`;
+ for (const [code, sym] of loc._currencyEntries) {
+ const cidx = codeToIdx.get(code);
+ const sidx = symToIdx.get(sym);
+ for (const b of encodeLEB128(cidx)) {
+ out += `0x${b.toString(16).padStart(2, '0')}, `;
+ bytesOnLine++;
+ if (bytesOnLine >= 16) {
+ out += '\n';
+ bytesOnLine = 0;
+ }
+ }
+ for (const b of encodeLEB128(sidx)) {
+ out += `0x${b.toString(16).padStart(2, '0')}, `;
+ bytesOnLine++;
+ if (bytesOnLine >= 16) {
+ out += '\n';
+ bytesOnLine = 0;
+ }
+ }
+ }
+ if (bytesOnLine > 0) {
+ out += '\n';
+ bytesOnLine = 0;
+ }
+ }
+}
+out += `};\n\n`;
+
+// CompactDecimalPattern arrays
+const compactArrays = new Map();
+let compactArrayCount = 0;
+for (const loc of locales) {
+ const entries = loc.compactPatterns.map(p => [p.scale, p.short, p.long]);
+ const key = JSON.stringify(entries);
+ if (!compactArrays.has(key)) {
+ compactArrays.set(key, compactArrayCount++);
+ }
+ loc._compactArrayId = compactArrays.get(key);
+ loc._numCompact = loc.compactPatterns.length;
+}
+
+for (let i = 0; i < compactArrayCount; i++) {
+ const entries = Array.from(compactArrays.entries()).find(([k, v]) => v === i)[0];
+ const arr = JSON.parse(entries);
+ if (arr.length === 0) continue;
+ out += `static const CompactDecimalPattern locale_compact_arr_${i}[] = {\n`;
+ for (const [scale, shortPat, longPat] of arr) {
+ const s = shortPat ? `"${escapeCString(shortPat)}"` : 'NULL';
+ const l = longPat ? `"${escapeCString(longPat)}"` : 'NULL';
+ out += ` { ${scale}, ${s}, ${l} },\n`;
+ }
+ out += `};\n\n`;
+}
+
+// Deduplicated symbol tables
+function emitTable(name, tab) {
+ out += `const char *${name}[] = {\n`;
+ for (const s of tab) {
+ out += ` "${escapeCString(s)}",\n`;
+ }
+ out += `};\n\n`;
+}
+
+emitTable('decimal_tab', decimalTab);
+emitTable('group_tab', groupTab);
+emitTable('plusSign_tab', plusSignTab);
+emitTable('minusSign_tab', minusSignTab);
+emitTable('percentSign_tab', percentSignTab);
+emitTable('infinity_tab', infinityTab);
+emitTable('nan_tab', nanTab);
+emitTable('pattern_tab', patternTab);
+
+// Date string pools (zero-separated)
+function emitStrpool(name, pool) {
+ out += `const char *${name}[] = {\n`;
+ for (const entry of pool.tab) {
+ out += ` "${makeZeroSepC(entry)}",\n`;
+ }
+ out += `};\n\n`;
+}
+
+emitStrpool('month_long_tab', monthLongPool);
+emitStrpool('month_short_tab', monthShortPool);
+emitStrpool('month_narrow_tab', monthNarrowPool);
+emitStrpool('weekday_long_tab', weekdayLongPool);
+emitStrpool('weekday_narrow_tab', weekdayNarrowPool);
+emitStrpool('era_tab', eraPool);
+emitStrpool('ampm_tab', ampmPool);
+emitStrpool('dayperiod_tab', dayPeriodLongPool);
+emitStrpool('dayperiod_narrow_tab', dayPeriodNarrowPool);
+
+// Date format patterns (simple C strings, not zero-separated arrays)
+out += `const char *date_pattern_tab[] = {\n`;
+for (const entry of datePatternPool.tab) {
+ out += ` "${escapeCString(entry)}",\n`;
+}
+out += `};\n\n`;
+
+// Time format patterns
+out += `const char *time_pattern_tab[] = {\n`;
+for (const entry of timePatternPool.tab) {
+ out += ` "${escapeCString(entry)}",\n`;
+}
+out += `};\n\n`;
+
+// Combined date+time patterns
+out += `const char *combined_pattern_tab[] = {\n`;
+for (const entry of combinedPatternPool.tab) {
+ out += ` "${escapeCString(entry)}",\n`;
+}
+out += `};\n\n`;
+
+// LocaleData array
+out += `const LocaleData locale_data_table[] = {\n`;
+for (const loc of locales) {
+ const sym = loc.symbols[loc.defaultNS];
+ out += ` {\n`;
+ out += ` "${escapeCString(loc.locale)}",\n`;
+ if (loc._numCompact > 0) {
+ out += ` locale_compact_arr_${loc._compactArrayId},\n`;
+ } else {
+ out += ` NULL,\n`;
+ }
+ out += ` ${inlineSymbols(sym)},\n`;
+ out += ` ${inlinePatterns(loc.patterns)},\n`;
+ const d = loc.dateData;
+ out += ` ${d ? getDateIdx(monthLongPool, d.monthLong) : 0}, ${d ? getDateIdx(monthShortPool, d.monthShort) : 0},\n`;
+ out += ` ${d ? getDateIdx(monthNarrowPool, d.monthNarrow) : 0}, ${d ? getDateIdx(weekdayLongPool, d.weekdayLong) : 0},\n`;
+ out += ` ${d ? getDateIdx(weekdayNarrowPool, d.weekdayNarrow) : 0}, ${d ? getDateIdx(eraPool, d.era) : 0},\n`;
+ out += ` ${d ? getDateIdx(ampmPool, d.ampm) : 0}, ${d ? getDateIdx(dayPeriodLongPool, d.dayPeriodLong) : 0},\n`;
+ out += ` ${d ? getDateIdx(dayPeriodNarrowPool, d.dayPeriodNarrow) : 0},\n`;
+ const p = d ? d.datePatterns : null;
+ out += ` ${getPatternIdx(datePatternPool, p ? p.short : '')}, ${getPatternIdx(datePatternPool, p ? p.medium : '')},\n`;
+ out += ` ${getPatternIdx(datePatternPool, p ? p.long : '')}, ${getPatternIdx(datePatternPool, p ? p.full : '')},\n`;
+ const tp = d ? d.timePatterns : null;
+ out += ` ${getPatternIdx(timePatternPool, tp ? tp.short : '')}, ${getPatternIdx(timePatternPool, tp ? tp.medium : '')},\n`;
+ out += ` ${getPatternIdx(timePatternPool, tp ? tp.long : '')}, ${getPatternIdx(timePatternPool, tp ? tp.full : '')},\n`;
+ const cp = d ? d.combinedPatterns : null;
+ out += ` ${getPatternIdx(combinedPatternPool, cp ? cp.short : '')}, ${getPatternIdx(combinedPatternPool, cp ? cp.medium : '')},\n`;
+ out += ` ${getPatternIdx(combinedPatternPool, cp ? cp.long : '')}, ${getPatternIdx(combinedPatternPool, cp ? cp.full : '')},\n`;
+ out += ` ${loc._numCompact}, ${loc.groupSizes.primary}, ${loc.groupSizes.secondary},\n`;
+ out += ` ${loc._currencyOffset}, ${loc._numCurrencies},\n`;
+ out += ` },\n`;
+}
+out += `};\n\n`;
+
+out += `const int locale_data_count = sizeof(locale_data_table) / sizeof(locale_data_table[0]);\n`;
+
+/* --- DisplayNames data --- */
+function readDisplayNames(locale) {
+ const result = {
+ languages: {},
+ regions: {},
+ regionsShort: {},
+ scripts: {},
+ calendars: {},
+ dateTimeFields: {},
+ currencies: {}
+ };
+
+ const langFile = path.join(CLDR_LOCALENAMES_BASE, locale, 'languages.json');
+ if (fs.existsSync(langFile)) {
+ const data = JSON.parse(fs.readFileSync(langFile, 'utf8'));
+ const langs = data['main'][locale]['localeDisplayNames']['languages'];
+ for (const [code, name] of Object.entries(langs)) {
+ if (name && typeof name === 'string') result.languages[code] = name;
+ }
+ }
+
+ const terrFile = path.join(CLDR_LOCALENAMES_BASE, locale, 'territories.json');
+ if (fs.existsSync(terrFile)) {
+ const data = JSON.parse(fs.readFileSync(terrFile, 'utf8'));
+ const terrs = data['main'][locale]['localeDisplayNames']['territories'];
+ for (const [code, name] of Object.entries(terrs)) {
+ if (!code.includes('-alt-')) {
+ if (name && typeof name === 'string') result.regions[code] = name;
+ } else if (code.endsWith('-alt-short')) {
+ const base = code.replace('-alt-short', '');
+ if (name && typeof name === 'string') result.regionsShort[base] = name;
+ }
+ }
+ }
+
+ const scriptFile = path.join(CLDR_LOCALENAMES_BASE, locale, 'scripts.json');
+ if (fs.existsSync(scriptFile)) {
+ const data = JSON.parse(fs.readFileSync(scriptFile, 'utf8'));
+ const scripts = data['main'][locale]['localeDisplayNames']['scripts'];
+ for (const [code, name] of Object.entries(scripts)) {
+ if (name && typeof name === 'string') result.scripts[code] = name;
+ }
+ }
+
+ const calFile = path.join(CLDR_LOCALENAMES_BASE, locale, 'localeDisplayNames.json');
+ if (fs.existsSync(calFile)) {
+ const data = JSON.parse(fs.readFileSync(calFile, 'utf8'));
+ const types = data['main'][locale]['localeDisplayNames']['types'];
+ if (types && types['calendar']) {
+ for (const [code, name] of Object.entries(types['calendar'])) {
+ if (!code.includes('-alt-') && name && typeof name === 'string') {
+ result.calendars[code] = name;
+ }
+ }
+ }
+ }
+
+ const dfFile = path.join(CLDR_DATES_BASE, locale, 'dateFields.json');
+ if (fs.existsSync(dfFile)) {
+ const data = JSON.parse(fs.readFileSync(dfFile, 'utf8'));
+ const fields = data['main'][locale]['dates']['fields'];
+ const fieldMap = {
+ 'era': 'era',
+ 'year': 'year',
+ 'quarter': 'quarter',
+ 'month': 'month',
+ 'week': 'weekOfYear',
+ 'weekday': 'weekday',
+ 'day': 'day',
+ 'dayperiod': 'dayPeriod',
+ 'hour': 'hour',
+ 'minute': 'minute',
+ 'second': 'second',
+ 'zone': 'timeZoneName'
+ };
+ for (const [cldrKey, dnKey] of Object.entries(fieldMap)) {
+ const f = fields[cldrKey];
+ if (f && f['displayName']) {
+ result.dateTimeFields[dnKey] = f['displayName'];
+ }
+ }
+ }
+
+ const curFile = path.join(CLDR_BASE, locale, 'currencies.json');
+ if (fs.existsSync(curFile)) {
+ const data = JSON.parse(fs.readFileSync(curFile, 'utf8'));
+ const curs = data['main'][locale]['numbers']['currencies'];
+ for (const [code, info] of Object.entries(curs)) {
+ if (info && info['displayName'] && typeof info['displayName'] === 'string') {
+ result.currencies[code] = info['displayName'];
+ allDisplayCurrencyCodes.add(code);
+ }
+ }
+ }
+
+ return result;
+}
+
+function buildDNDictPool(dict) {
+ const entries = [];
+ const keys = Object.keys(dict).sort();
+ for (const k of keys) {
+ entries.push(k);
+ entries.push(dict[k]);
+ }
+ entries.push(''); /* trailing NUL terminator */
+ return entries;
+}
+
+const dnDataEntries = [];
+for (const dnLocale of DISPLAY_NAME_LOCALES) {
+ const dn = readDisplayNames(dnLocale);
+ const langPool = buildDNDictPool(dn.languages);
+ const regionPool = buildDNDictPool(dn.regions);
+ const regionShortPool = buildDNDictPool(dn.regionsShort);
+ const scriptPool = buildDNDictPool(dn.scripts);
+ const calendarPool = buildDNDictPool(dn.calendars);
+ const dtfPool = buildDNDictPool(dn.dateTimeFields);
+ const currencyPool = buildDNDictPool(dn.currencies);
+
+ out += `\n/* DisplayNames data for ${dnLocale} */\n`;
+ out += `static const char dn_${dnLocale}_languages[] = "${makeZeroSepC(langPool)}";\n`;
+ out += `static const char dn_${dnLocale}_regions[] = "${makeZeroSepC(regionPool)}";\n`;
+ out += `static const char dn_${dnLocale}_regions_short[] = "${makeZeroSepC(regionShortPool)}";\n`;
+ out += `static const char dn_${dnLocale}_scripts[] = "${makeZeroSepC(scriptPool)}";\n`;
+ out += `static const char dn_${dnLocale}_calendars[] = "${makeZeroSepC(calendarPool)}";\n`;
+ out += `static const char dn_${dnLocale}_dateTimeFields[] = "${makeZeroSepC(dtfPool)}";\n`;
+ out += `static const char dn_${dnLocale}_currencies[] = "${makeZeroSepC(currencyPool)}";\n`;
+
+ dnDataEntries.push(dnLocale);
+}
+
+out += `\nconst DisplayNamesData display_names_data[] = {\n`;
+for (const dnLocale of dnDataEntries) {
+ out += ` { "${dnLocale}"`;
+ out += `, dn_${dnLocale}_languages`;
+ out += `, dn_${dnLocale}_regions`;
+ out += `, dn_${dnLocale}_regions_short`;
+ out += `, dn_${dnLocale}_scripts`;
+ out += `, dn_${dnLocale}_calendars`;
+ out += `, dn_${dnLocale}_dateTimeFields`;
+ out += `, dn_${dnLocale}_currencies },\n`;
+}
+out += `};\n`;
+out += `const int display_names_count = sizeof(display_names_data) / sizeof(display_names_data[0]);\n`;
+
+const displayCurrencyCodesSorted = Array.from(allDisplayCurrencyCodes).sort();
+out += `\nconst char *intl_supported_currencies[] = {\n`;
+for (let i = 0; i < displayCurrencyCodesSorted.length; i++) {
+ out += ` "${escapeCString(displayCurrencyCodesSorted[i])}",\n`;
+}
+out += `};\n`;
+out += `const int intl_supported_currencies_count = sizeof(intl_supported_currencies) / sizeof(intl_supported_currencies[0]);\n`;
+
+fs.writeFileSync(OUT_PATH, out);
+console.log(`Generated ${OUT_PATH}`);
+console.log(`Currency codes: ${codeList.length}, symbols: ${symList.length}`);
+console.log(`Total LEB128 bytes: ${globalOffset}`);
--- /dev/null
+#!/usr/bin/env python3
+"""Generate QuickJS embedded timezone transition data from system TZif files."""
+
+import os
+import struct
+import sys
+
+ZONEINFO_DIR = "/usr/share/zoneinfo"
+
+# Zones needed by failing test262 tests
+NEEDED_ZONES = {
+ # Zones explicitly used in failing test262 tests
+ "America/Los_Angeles",
+ "America/Vancouver",
+ "America/New_York",
+ "America/Toronto",
+ "America/Noronha",
+ "America/Sao_Paulo",
+ "Europe/Berlin",
+ "Europe/London",
+ "Europe/Paris",
+ "Europe/Vienna",
+ "Europe/Moscow",
+ "Asia/Kolkata",
+ "Asia/Riyadh",
+ "Asia/Tokyo",
+ "Pacific/Apia",
+ "Pacific/Niue",
+ "Antarctica/Casey",
+ "Africa/Monrovia",
+ "Asia/Kolkata",
+ "America/Anchorage",
+ # Zones for transitions-close-together tests
+ "Africa/Tunis",
+ "America/Argentina/Tucuman",
+ "America/Boa_Vista",
+ "America/Fortaleza",
+ "America/Maceio",
+ "America/Recife",
+ "Europe/Riga",
+ "Europe/Simferopol",
+ "Europe/Tirane",
+ # Zones for startOfDay / hoursInDay DST tests
+ "America/St_Johns",
+ "Antarctica/Casey",
+ "Australia/Lord_Howe",
+ "Asia/Singapore",
+ # Basic required zones
+ "Etc/UTC",
+ "UTC",
+ "GMT",
+ "Etc/GMT",
+ # Etc/GMT fixed-offset zones for supportedValuesOf
+ "Etc/GMT+1", "Etc/GMT+2", "Etc/GMT+3", "Etc/GMT+4",
+ "Etc/GMT+5", "Etc/GMT+6", "Etc/GMT+7", "Etc/GMT+8",
+ "Etc/GMT+9", "Etc/GMT+10", "Etc/GMT+11", "Etc/GMT+12",
+ "Etc/GMT-1", "Etc/GMT-2", "Etc/GMT-3", "Etc/GMT-4",
+ "Etc/GMT-5", "Etc/GMT-6", "Etc/GMT-7", "Etc/GMT-8",
+ "Etc/GMT-9", "Etc/GMT-10", "Etc/GMT-11", "Etc/GMT-12",
+ "Etc/GMT-13", "Etc/GMT-14",
+}
+
+# Hardcoded IANA aliases (from tzdb backward file)
+HARDCODED_ALIASES = {
+ "Africa/Asmera": "Africa/Asmara",
+ "America/Atka": "America/Adak",
+ "America/Buenos_Aires": "America/Argentina/Buenos_Aires",
+ "America/Catamarca": "America/Argentina/Catamarca",
+ "America/Cordoba": "America/Argentina/Cordoba",
+ "America/Jujuy": "America/Argentina/Jujuy",
+ "America/Mendoza": "America/Argentina/Mendoza",
+ "America/Rosario": "America/Argentina/Cordoba",
+ "America/Coral_Harbour": "America/Atikokan",
+ "America/Ensenada": "America/Tijuana",
+ "America/Fort_Wayne": "America/Indiana/Indianapolis",
+ "America/Godthab": "America/Nuuk",
+ "America/Indianapolis": "America/Indiana/Indianapolis",
+ "America/Knox_IN": "America/Indiana/Knox",
+ "America/Louisville": "America/Kentucky/Louisville",
+ "America/Nipigon": "America/Toronto",
+ "America/Pangnirtung": "America/Iqaluit",
+ "America/Porto_Acre": "America/Rio_Branco",
+ "America/Rainy_River": "America/Winnipeg",
+ "America/Santa_Isabel": "America/Tijuana",
+ "America/Shiprock": "America/Denver",
+ "America/Virgin": "America/Port_of_Spain",
+ "Asia/Ashkhabad": "Asia/Ashgabat",
+ "Asia/Calcutta": "Asia/Kolkata",
+ "Asia/Chongqing": "Asia/Shanghai",
+ "Asia/Chungking": "Asia/Shanghai",
+ "Asia/Dacca": "Asia/Dhaka",
+ "Asia/Harbin": "Asia/Shanghai",
+ "Asia/Istanbul": "Europe/Istanbul",
+ "Asia/Kashgar": "Asia/Urumqi",
+ "Asia/Katmandu": "Asia/Kathmandu",
+ "Asia/Macao": "Asia/Macau",
+ "Asia/Rangoon": "Asia/Yangon",
+ "Asia/Saigon": "Asia/Ho_Chi_Minh",
+ "Asia/Tel_Aviv": "Asia/Jerusalem",
+ "Asia/Thimbu": "Asia/Thimphu",
+ "Asia/Ujung_Pandang": "Asia/Makassar",
+ "Asia/Ulan_Bator": "Asia/Ulaanbaatar",
+ "Atlantic/Faeroe": "Atlantic/Faroe",
+ "Atlantic/Jan_Mayen": "Europe/Berlin",
+ "Australia/ACT": "Australia/Sydney",
+ "Australia/Canberra": "Australia/Sydney",
+ "Australia/LHI": "Australia/Lord_Howe",
+ "Australia/NSW": "Australia/Sydney",
+ "Australia/North": "Australia/Darwin",
+ "Australia/Queensland": "Australia/Brisbane",
+ "Australia/South": "Australia/Adelaide",
+ "Australia/Tasmania": "Australia/Hobart",
+ "Australia/Victoria": "Australia/Melbourne",
+ "Australia/West": "Australia/Perth",
+ "Australia/Yancowinna": "Australia/Broken_Hill",
+ "Brazil/Acre": "America/Rio_Branco",
+ "Brazil/DeNoronha": "America/Noronha",
+ "Brazil/East": "America/Sao_Paulo",
+ "Brazil/West": "America/Manaus",
+ "Canada/Atlantic": "America/Halifax",
+ "Canada/Central": "America/Winnipeg",
+ "Canada/Eastern": "America/Toronto",
+ "Canada/Mountain": "America/Edmonton",
+ "Canada/Newfoundland": "America/St_Johns",
+ "Canada/Pacific": "America/Vancouver",
+ "Canada/Saskatchewan": "America/Regina",
+ "Canada/Yukon": "America/Whitehorse",
+ "Chile/Continental": "America/Santiago",
+ "Chile/EasterIsland": "Pacific/Easter",
+ "Cuba": "America/Havana",
+ "Egypt": "Africa/Cairo",
+ "Eire": "Europe/Dublin",
+ "EST": "America/Panama",
+ "EST5EDT": "America/New_York",
+ "GB": "Europe/London",
+ "GB-Eire": "Europe/London",
+ "Etc/GMT": "GMT",
+ "Etc/GMT+0": "GMT",
+ "Etc/GMT-0": "GMT",
+ "Etc/GMT0": "GMT",
+ "Greenwich": "GMT",
+ "GMT+0": "GMT",
+ "GMT-0": "GMT",
+ "GMT0": "GMT",
+ "Hongkong": "Asia/Hong_Kong",
+ "HST": "Pacific/Honolulu",
+ "Iceland": "Atlantic/Reykjavik",
+ "Iran": "Asia/Tehran",
+ "Israel": "Asia/Jerusalem",
+ "Jamaica": "America/Jamaica",
+ "Japan": "Asia/Tokyo",
+ "Kwajalein": "Pacific/Kwajalein",
+ "Libya": "Africa/Tripoli",
+ "MET": "Europe/Paris",
+ "Mexico/BajaNorte": "America/Tijuana",
+ "Mexico/BajaSur": "America/Mazatlan",
+ "Mexico/General": "America/Mexico_City",
+ "MST": "America/Phoenix",
+ "MST7MDT": "America/Denver",
+ "Navajo": "America/Denver",
+ "NZ": "Pacific/Auckland",
+ "NZ-CHAT": "Pacific/Chatham",
+ "Poland": "Europe/Warsaw",
+ "Portugal": "Europe/Lisbon",
+ "PRC": "Asia/Shanghai",
+ "PST8PDT": "America/Los_Angeles",
+ "ROC": "Asia/Taipei",
+ "ROK": "Asia/Seoul",
+ "Singapore": "Asia/Singapore",
+ "Turkey": "Europe/Istanbul",
+ "UCT": "UTC",
+ "Universal": "Etc/UTC",
+ "US/Alaska": "America/Anchorage",
+ "US/Aleutian": "America/Adak",
+ "US/Arizona": "America/Phoenix",
+ "US/Central": "America/Chicago",
+ "US/East-Indiana": "America/Indiana/Indianapolis",
+ "US/Eastern": "America/New_York",
+ "US/Hawaii": "Pacific/Honolulu",
+ "US/Indiana-Starke": "America/Indiana/Knox",
+ "US/Michigan": "America/Detroit",
+ "US/Mountain": "America/Denver",
+ "US/Pacific": "America/Los_Angeles",
+ "US/Samoa": "Pacific/Pago_Pago",
+ "Etc/UTC": "UTC",
+ "Etc/UCT": "UTC",
+ "Etc/Universal": "UTC",
+ "Etc/Zulu": "UTC",
+ "Universal": "UTC",
+ "Zulu": "UTC",
+ "W-SU": "Europe/Moscow",
+ "WET": "Europe/Lisbon",
+ "Pacific/Samoa": "Pacific/Pago_Pago",
+ "Pacific/Truk": "Pacific/Chuuk",
+ "Pacific/Ponape": "Pacific/Pohnpei",
+ "Pacific/Yap": "Pacific/Chuuk",
+ "Arctic/Longyearbyen": "Europe/Berlin",
+ "Antarctica/South_Pole": "Pacific/Auckland",
+ "Antarctica/DumontDUrville": "Pacific/Port_Moresby",
+}
+
+def parse_tzif(path):
+ with open(path, 'rb') as f:
+ data = f.read()
+ if data[:4] != b'TZif':
+ return None
+ version = chr(data[4])
+ pos = 20
+ counts = struct.unpack_from('>6I', data, pos)
+ pos += 24
+ ttisutcnt, ttisstdcnt, leapcnt, timecnt, typecnt, charcnt = counts
+
+ # skip block 1
+ pos += timecnt * 4 + timecnt + typecnt * 6 + charcnt + leapcnt * 8 + ttisstdcnt + ttisutcnt
+
+ if version not in ('2', '3'):
+ # v1: parse block 1 directly
+ pos = 20 + 24
+ times = struct.unpack_from(f'>{timecnt}i', data, pos)
+ pos += timecnt * 4
+ types = struct.unpack_from(f'>{timecnt}B', data, pos)
+ pos += timecnt
+ typeinfos = []
+ for _ in range(typecnt):
+ utoff, isdst, desigidx = struct.unpack_from('>iBB', data, pos)
+ pos += 6
+ typeinfos.append((utoff, isdst, desigidx))
+ transitions = []
+ for i in range(timecnt):
+ transitions.append((int(times[i]), typeinfos[types[i]][0]))
+ initial_offset = typeinfos[types[0]][0] if timecnt > 0 else (typeinfos[0][0] if typecnt > 0 else 0)
+ return transitions, initial_offset
+
+ # block 2
+ if data[pos:pos+5] != b'TZif' + version.encode():
+ return None
+ pos += 20
+ counts = struct.unpack_from('>6I', data, pos)
+ pos += 24
+ ttisutcnt, ttisstdcnt, leapcnt, timecnt, typecnt, charcnt = counts
+
+ times = struct.unpack_from(f'>{timecnt}q', data, pos)
+ pos += timecnt * 8
+ types = struct.unpack_from(f'>{timecnt}B', data, pos)
+ pos += timecnt
+ typeinfos = []
+ for _ in range(typecnt):
+ utoff, isdst, desigidx = struct.unpack_from('>iBB', data, pos)
+ pos += 6
+ typeinfos.append((utoff, isdst, desigidx))
+
+ transitions = []
+ for i in range(timecnt):
+ transitions.append((int(times[i]), typeinfos[types[i]][0]))
+
+ # initial offset is the offset before the first transition.
+ # In practice, typeinfos[0] is the LMT/pre-first-transition offset.
+ initial_offset = typeinfos[0][0] if typecnt > 0 else 0
+ return transitions, initial_offset
+
+def discover_aliases():
+ """Map alias -> canonical by following symlinks in zoneinfo."""
+ aliases = {}
+ for root, dirs, files in os.walk(ZONEINFO_DIR):
+ # prevent descending into leapseconds or posix/right if needed
+ for name in files:
+ full = os.path.join(root, name)
+ if os.path.islink(full):
+ target = os.readlink(full)
+ # resolve relative symlink
+ if not target.startswith('/'):
+ target = os.path.normpath(os.path.join(os.path.dirname(full), target))
+ if target.startswith(ZONEINFO_DIR + '/'):
+ target = target[len(ZONEINFO_DIR)+1:]
+ alias = full[len(ZONEINFO_DIR)+1:]
+ aliases[alias] = target
+ return aliases
+
+def collect_all_zones():
+ """Return set of canonical zones plus aliases."""
+ zones = set(NEEDED_ZONES)
+ # Only include aliases that are needed or point to needed zones
+ relevant_aliases = {}
+ for alias, target in HARDCODED_ALIASES.items():
+ if alias in NEEDED_ZONES or target in NEEDED_ZONES:
+ relevant_aliases[alias] = target
+ zones.add(alias)
+ zones.add(target)
+ return zones, relevant_aliases
+
+def main():
+ zones, aliases = collect_all_zones()
+
+ # gather data for each zone
+ zone_data = {}
+ missing = []
+ for z in sorted(zones):
+ path = os.path.join(ZONEINFO_DIR, z)
+ if not os.path.exists(path):
+ missing.append(z)
+ continue
+ res = parse_tzif(path)
+ if res is None:
+ missing.append(z)
+ continue
+ transitions, initial_offset = res
+ zone_data[z] = (transitions, initial_offset)
+
+ if missing:
+ print(f"Missing {len(missing)} zones (will be unsupported): {missing[:10]}", file=sys.stderr)
+
+ # Resolve alias chains to canonical zone (a zone not in aliases.keys())
+ def resolve_canonical(name):
+ seen = set()
+ while name in aliases and name not in seen:
+ seen.add(name)
+ name = aliases[name]
+ return name
+
+ canonical_set = set()
+ alias_to_canonical = {}
+ for z in zone_data:
+ if z in aliases:
+ target = resolve_canonical(z)
+ if target in zone_data:
+ alias_to_canonical[z] = target
+ else:
+ canonical_set.add(z)
+
+ # Also add aliases whose target is canonical
+ for alias, target in aliases.items():
+ resolved = resolve_canonical(target)
+ if resolved in zone_data and alias not in alias_to_canonical:
+ alias_to_canonical[alias] = resolved
+
+ canonical_list = sorted(canonical_set)
+ canonical_index = {name: i for i, name in enumerate(canonical_list)}
+
+ def iso_comment(ts):
+ from datetime import datetime, timezone
+ dt = datetime.fromtimestamp(ts, tz=timezone.utc)
+ return dt.strftime('%Y-%m-%dT%H:%M:%SZ')
+
+ # Write generated C file
+ out_path = "temporal/tzdata_generated.c"
+ with open(out_path, "w") as f:
+ f.write('/* Auto-generated by gen_tzdata.py — DO NOT EDIT */\n')
+ f.write('#include "timezone.h"\n\n')
+
+ # Transition arrays per zone
+ for name in canonical_list:
+ transitions, initial_offset = zone_data[name]
+ var_name = name.replace('/', '_').replace('-', '_').replace('+', '_plus_')
+ f.write(f'static const TZTransition tz_trans_{var_name}[] = {{\n')
+ # prepend initial offset at INT64_MIN
+ f.write(f' {{ INT64_MIN, {initial_offset} }}, /* before first transition */\n')
+ for ts, off in transitions:
+ f.write(f' {{ {ts}LL, {off} }}, /* {iso_comment(ts)} */\n')
+ f.write('};\n\n')
+
+ # Alias table
+ alias_list = sorted(alias_to_canonical.items())
+ f.write('const TZAlias ti_tz_aliases[] = {\n')
+ for alias, target in alias_list:
+ if target in canonical_index:
+ f.write(f' {{ "{alias}", {canonical_index[target]} }},\n')
+ f.write('};\n')
+ f.write(f'const int ti_tz_alias_count = countof(ti_tz_aliases);\n\n')
+
+ # Zone info table
+ f.write('const TZData ti_tz_zone_data[] = {\n')
+ for name in canonical_list:
+ var_name = name.replace('/', '_').replace('-', '_').replace('+', '_plus_')
+ transitions, _ = zone_data[name]
+ count = len(transitions) + 1 # including the INT64_MIN dummy
+ f.write(f' {{ "{name}", tz_trans_{var_name}, {count} }},\n')
+ f.write('};\n\n')
+
+ f.write('const int ti_tz_zone_count = countof(ti_tz_zone_data);\n')
+
+ print(f"Generated {out_path}: {len(canonical_list)} canonical zones, {len(alias_list)} aliases", file=sys.stderr)
+
+if __name__ == "__main__":
+ main()
--- /dev/null
+/*
+ * QuickJS Intl.Collator implementation
+ */
+
+#include <string.h>
+#include <ctype.h>
+
+#include "../quickjs.h"
+#include "../cutils.h"
+#include "../libunicode.h"
+#include "intl_private.h"
+
+static JSClassID js_collator_class_id;
+
+enum {
+ COLLATOR_USAGE_SORT = 0,
+ COLLATOR_USAGE_SEARCH,
+};
+static const char *collator_usage_names[] = {"sort", "search"};
+
+enum {
+ COLLATOR_SENSITIVITY_BASE = 0,
+ COLLATOR_SENSITIVITY_ACCENT,
+ COLLATOR_SENSITIVITY_CASE,
+ COLLATOR_SENSITIVITY_VARIANT,
+};
+static const char *collator_sensitivity_names[] = {"base", "accent", "case", "variant"};
+
+enum {
+ COLLATOR_CASEFIRST_UPPER = 0,
+ COLLATOR_CASEFIRST_LOWER,
+ COLLATOR_CASEFIRST_FALSE,
+};
+static const char *collator_casefirst_names[] = {"upper", "lower", "false"};
+
+typedef struct {
+ char *locale;
+ char *locale_canonical;
+ int usage;
+ int sensitivity;
+ int caseFirst;
+ int numeric;
+ int ignorePunctuation;
+ char *collation;
+ int hasNumeric;
+ int hasCaseFirst;
+} JSCollatorData;
+
+static void js_collator_finalizer(JSRuntime *rt, JSValue val)
+{
+ JSCollatorData *s = JS_GetOpaque(val, js_collator_class_id);
+ if (s) {
+ js_free_rt(rt, s->locale);
+ js_free_rt(rt, s->locale_canonical);
+ js_free_rt(rt, s->collation);
+ js_free_rt(rt, s);
+ }
+}
+
+static int locale_has_key(const char *locale, const char *key)
+{
+ const char *u = js_intl_find_u_extension(locale);
+ if (!u)
+ return 0;
+ u += 3;
+ while (*u) {
+ const char *next = u;
+ while (*next && *next != '-')
+ next++;
+ int len = (int)(next - u);
+ if (len == 2 && u[0] == key[0] && u[1] == key[1])
+ return 1;
+ /* skip this subtag and continue */
+ if (*next == '-')
+ next++;
+ u = next;
+ }
+ return 0;
+}
+
+static int is_collation_supported(const char *collation, const char *locale)
+{
+ if (!strcmp(collation, "default"))
+ return 1;
+ if (!strcmp(locale, "de") || !strncmp(locale, "de-", 3)) {
+ if (!strcmp(collation, "phonebk") || !strcmp(collation, "eor"))
+ return 1;
+ }
+ return 0;
+}
+
+static JSClassDef js_collator_class = {
+ "Collator",
+ .finalizer = js_collator_finalizer,
+};
+
+static int js_collator_get_locale(JSContext *ctx, JSCollatorData *s,
+ int argc, JSValueConst *argv)
+{
+ char *loc = js_intl_extract_locale(ctx, argc, argv);
+ if (!loc)
+ return -1;
+ js_free(ctx, s->locale);
+ s->locale = loc;
+ return 0;
+}
+
+static JSValue js_collator_constructor(JSContext *ctx,
+ JSValueConst func_obj,
+ JSValueConst this_val,
+ int argc, JSValueConst *argv,
+ int flags)
+{
+ JSCollatorData *s;
+ JSValue obj = JS_UNDEFINED;
+ JSValue options = JS_UNDEFINED;
+ JSValueConst new_target;
+ int is_new = (flags & JS_CALL_FLAG_CONSTRUCTOR) != 0;
+
+ if (is_new) {
+ new_target = this_val;
+ } else {
+ new_target = func_obj;
+ }
+
+ s = js_mallocz(ctx, sizeof(*s));
+ if (!s)
+ return JS_EXCEPTION;
+
+ s->locale = js_strdup(ctx, "en-US");
+ s->usage = COLLATOR_USAGE_SORT;
+ s->sensitivity = COLLATOR_SENSITIVITY_VARIANT;
+ s->caseFirst = COLLATOR_CASEFIRST_FALSE;
+ s->numeric = 0;
+ s->ignorePunctuation = 0;
+ s->collation = js_strdup(ctx, "default");
+
+ if (js_collator_get_locale(ctx, s, argc, argv) < 0)
+ goto fail;
+
+ /* Get canonical locale with extensions for resolvedOptions */
+ {
+ char *canonical = NULL;
+ if (js_canonicalizeLocaleList_first(ctx, argc > 0 ? argv[0] : JS_UNDEFINED, &canonical) < 0)
+ goto fail;
+ s->locale_canonical = canonical;
+ }
+
+ /* Default ignorePunctuation for Thai */
+ if (s->locale && (!strcmp(s->locale, "th") || !strncmp(s->locale, "th-", 3))) {
+ s->ignorePunctuation = 1;
+ }
+
+ /* Apply locale extensions as defaults */
+ if (s->locale_canonical) {
+ if (locale_has_key(s->locale_canonical, "kn")) {
+ char *v = js_intl_locale_get_unicode_key(ctx, s->locale_canonical, "kn");
+ s->hasNumeric = 1;
+ s->numeric = (v == NULL) ? 1 : 0;
+ js_free(ctx, v);
+ }
+ if (locale_has_key(s->locale_canonical, "kf")) {
+ char *v = js_intl_locale_get_unicode_key(ctx, s->locale_canonical, "kf");
+ s->hasCaseFirst = 1;
+ if (v) {
+ if (!strcmp(v, "upper")) s->caseFirst = COLLATOR_CASEFIRST_UPPER;
+ else if (!strcmp(v, "lower")) s->caseFirst = COLLATOR_CASEFIRST_LOWER;
+ else s->caseFirst = COLLATOR_CASEFIRST_FALSE;
+ } else {
+ s->caseFirst = COLLATOR_CASEFIRST_FALSE;
+ }
+ js_free(ctx, v);
+ }
+ {
+ char *v = js_intl_locale_get_unicode_key(ctx, s->locale_canonical, "co");
+ if (v) {
+ if (is_collation_supported(v, s->locale)) {
+ js_free(ctx, s->collation);
+ s->collation = js_strdup(ctx, v);
+ }
+ js_free(ctx, v);
+ }
+ }
+ }
+
+ /* parse options */
+ if (argc > 1 && !JS_IsUndefined(argv[1])) {
+ options = JS_ToObject(ctx, argv[1]);
+ if (JS_IsException(options))
+ goto fail;
+ } else {
+ options = JS_NewObjectProto(ctx, JS_NULL);
+ if (JS_IsException(options))
+ goto fail;
+ }
+
+ {
+ int idx = js_intl_get_string_option(ctx, options, "localeMatcher",
+ intl_localeMatcher_names,
+ countof(intl_localeMatcher_names),
+ INTL_LOCALEMATCHER_BESTFIT);
+ if (idx < 0)
+ goto fail;
+ }
+
+ {
+ int idx = js_intl_get_string_option(ctx, options, "usage",
+ collator_usage_names,
+ countof(collator_usage_names),
+ COLLATOR_USAGE_SORT);
+ if (idx < 0)
+ goto fail;
+ s->usage = idx;
+ }
+
+ {
+ int idx = js_intl_get_string_option(ctx, options, "sensitivity",
+ collator_sensitivity_names,
+ countof(collator_sensitivity_names),
+ COLLATOR_SENSITIVITY_VARIANT);
+ if (idx < 0)
+ goto fail;
+ s->sensitivity = idx;
+ }
+
+ {
+ JSValue val = JS_GetPropertyStr(ctx, options, "ignorePunctuation");
+ if (JS_IsException(val))
+ goto fail;
+ if (!JS_IsUndefined(val)) {
+ s->ignorePunctuation = JS_ToBool(ctx, val);
+ }
+ JS_FreeValue(ctx, val);
+ }
+
+ {
+ JSValue val = JS_GetPropertyStr(ctx, options, "collation");
+ if (JS_IsException(val))
+ goto fail;
+ if (!JS_IsUndefined(val)) {
+ const char *str = JS_ToCString(ctx, val);
+ JS_FreeValue(ctx, val);
+ if (str) {
+ int valid = 1;
+ int len = (int)strlen(str);
+ int i;
+ if (len < 3 || len > 8) valid = 0;
+ for (i = 0; i < len && valid; i++) {
+ if (!isalnum((unsigned char)str[i]))
+ valid = 0;
+ }
+ if (!valid) {
+ JS_FreeCString(ctx, str);
+ JS_ThrowRangeError(ctx, "invalid collation option");
+ goto fail;
+ }
+ if (is_collation_supported(str, s->locale)) {
+ js_free(ctx, s->collation);
+ s->collation = js_strdup(ctx, str);
+ } else {
+ /* Unsupported option: keep locale extension if supported */
+ char *co_val = js_intl_locale_get_unicode_key(ctx, s->locale_canonical, "co");
+ if (co_val && is_collation_supported(co_val, s->locale)) {
+ js_free(ctx, s->collation);
+ s->collation = js_strdup(ctx, co_val);
+ } else {
+ js_free(ctx, s->collation);
+ s->collation = js_strdup(ctx, "default");
+ }
+ js_free(ctx, co_val);
+ }
+ JS_FreeCString(ctx, str);
+ }
+ }
+ }
+
+ {
+ JSValue val = JS_GetPropertyStr(ctx, options, "numeric");
+ if (JS_IsException(val))
+ goto fail;
+ if (!JS_IsUndefined(val)) {
+ s->numeric = JS_ToBool(ctx, val);
+ s->hasNumeric = 1;
+ }
+ JS_FreeValue(ctx, val);
+ }
+
+ {
+ JSValue val = JS_GetPropertyStr(ctx, options, "caseFirst");
+ if (JS_IsException(val))
+ goto fail;
+ if (!JS_IsUndefined(val)) {
+ size_t slen;
+ const char *str = JS_ToCStringLen(ctx, &slen, val);
+ JS_FreeValue(ctx, val);
+ if (str) {
+ int idx = -1;
+ int i;
+ for (i = 0; i < (int)countof(collator_casefirst_names); i++) {
+ size_t vlen = strlen(collator_casefirst_names[i]);
+ if (slen == vlen && !memcmp(str, collator_casefirst_names[i], vlen)) {
+ idx = i;
+ break;
+ }
+ }
+ JS_FreeCString(ctx, str);
+ if (idx < 0) {
+ JS_ThrowRangeError(ctx, "invalid caseFirst option");
+ goto fail;
+ }
+ s->caseFirst = idx;
+ s->hasCaseFirst = 1;
+ }
+ } else {
+ JS_FreeValue(ctx, val);
+ }
+ }
+
+ JS_FreeValue(ctx, options);
+ options = JS_UNDEFINED;
+
+ /* Rebuild locale with preserved Unicode extensions */
+ if (s->locale_canonical) {
+ int preserve_kn = 0, preserve_kf = 0, preserve_co = 0;
+
+ if (locale_has_key(s->locale_canonical, "kn")) {
+ char *v = js_intl_locale_get_unicode_key(ctx, s->locale_canonical, "kn");
+ int kn_val = (v == NULL) ? 1 : 0;
+ js_free(ctx, v);
+ if (s->hasNumeric && s->numeric == kn_val)
+ preserve_kn = 1;
+ }
+ if (locale_has_key(s->locale_canonical, "kf")) {
+ char *v = js_intl_locale_get_unicode_key(ctx, s->locale_canonical, "kf");
+ const char *resolved_kf = collator_casefirst_names[s->caseFirst];
+ int kf_matches = 0;
+ if (v) {
+ kf_matches = !strcmp(v, resolved_kf);
+ } else {
+ kf_matches = !strcmp(resolved_kf, "false");
+ }
+ js_free(ctx, v);
+ if (s->hasCaseFirst && kf_matches)
+ preserve_kf = 1;
+ }
+ {
+ char *v = js_intl_locale_get_unicode_key(ctx, s->locale_canonical, "co");
+ if (v) {
+ if (!strcmp(v, s->collation))
+ preserve_co = 1;
+ js_free(ctx, v);
+ }
+ }
+
+ if (preserve_kn || preserve_kf || preserve_co) {
+ DynBuf db;
+ js_intl_dbuf_init(ctx, &db);
+ dbuf_putstr(&db, s->locale);
+ dbuf_put(&db, (uint8_t *)"-u", 2);
+ if (preserve_kn) {
+ char *v = js_intl_locale_get_unicode_key(ctx, s->locale_canonical, "kn");
+ if (v) {
+ dbuf_put(&db, (uint8_t *)"-kn-", 4);
+ dbuf_putstr(&db, v);
+ js_free(ctx, v);
+ } else {
+ dbuf_put(&db, (uint8_t *)"-kn", 3);
+ }
+ }
+ if (preserve_kf) {
+ char *v = js_intl_locale_get_unicode_key(ctx, s->locale_canonical, "kf");
+ if (v) {
+ dbuf_put(&db, (uint8_t *)"-kf-", 4);
+ dbuf_putstr(&db, v);
+ js_free(ctx, v);
+ } else {
+ dbuf_put(&db, (uint8_t *)"-kf", 3);
+ }
+ }
+ if (preserve_co) {
+ char *v = js_intl_locale_get_unicode_key(ctx, s->locale_canonical, "co");
+ if (v) {
+ dbuf_put(&db, (uint8_t *)"-co-", 4);
+ dbuf_putstr(&db, v);
+ js_free(ctx, v);
+ }
+ }
+ dbuf_put(&db, (uint8_t *)"", 1);
+ if (dbuf_error(&db)) {
+ dbuf_free(&db);
+ return JS_EXCEPTION;
+ }
+ js_free(ctx, s->locale);
+ s->locale = js_strdup(ctx, (char *)db.buf);
+ dbuf_free(&db);
+ }
+ }
+
+ obj = JS_CreateFromConstructor(ctx, new_target, js_collator_class_id);
+ if (JS_IsException(obj))
+ goto fail;
+ JS_SetOpaque(obj, s);
+ return obj;
+ fail:
+ JS_FreeValue(ctx, options);
+ if (s->locale) js_free(ctx, s->locale);
+ if (s->locale_canonical) js_free(ctx, s->locale_canonical);
+ if (s->collation) js_free(ctx, s->collation);
+ js_free(ctx, s);
+ JS_FreeValue(ctx, obj);
+ return JS_EXCEPTION;
+}
+
+/* Check if character is a Unicode combining mark */
+static int is_combining_mark(uint32_t c)
+{
+ return (c >= 0x0300 && c <= 0x036F) ||
+ (c >= 0x1AB0 && c <= 0x1AFF) ||
+ (c >= 0x1DC0 && c <= 0x1DFF) ||
+ (c >= 0x20D0 && c <= 0x20FF) ||
+ (c >= 0xFE20 && c <= 0xFE2F);
+}
+
+/* Check if character is significant when ignorePunctuation is true */
+static int is_significant(uint32_t c)
+{
+ if (c >= '0' && c <= '9')
+ return 1;
+ if (c < 128)
+ return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
+ return lre_is_id_start(c);
+}
+
+/* Compare two characters with caseFirst ordering */
+static int compare_case_order(uint32_t c1, uint32_t c2, int caseFirst)
+{
+ int upper1 = (c1 >= 'A' && c1 <= 'Z');
+ int upper2 = (c2 >= 'A' && c2 <= 'Z');
+ int lower1 = (c1 >= 'a' && c1 <= 'z');
+ int lower2 = (c2 >= 'a' && c2 <= 'z');
+
+ if (upper1 && lower2) {
+ if (caseFirst == COLLATOR_CASEFIRST_UPPER)
+ return -1;
+ else
+ return 1;
+ }
+ if (lower1 && upper2) {
+ if (caseFirst == COLLATOR_CASEFIRST_UPPER)
+ return 1;
+ else
+ return -1;
+ }
+ if (c1 < c2) return -1;
+ if (c1 > c2) return 1;
+ return 0;
+}
+
+/* Transform a string for collation comparison.
+ level: 0=base, 1=accent/secondary, 2=case, 3=tertiary */
+static uint32_t *transform_string(JSContext *ctx, JSCollatorData *s,
+ const uint32_t *src, int src_len, int *out_len,
+ int level)
+{
+ uint32_t *nfd = NULL;
+ int nfd_len;
+ uint32_t *result;
+ int result_cap, result_len = 0;
+ int i;
+ int phonebook = 0;
+ int german_sort = 0;
+ int turkish = 0;
+
+ if (s->collation && !strcmp(s->collation, "phonebk"))
+ phonebook = 1;
+ if (s->usage == COLLATOR_USAGE_SEARCH && s->locale &&
+ (!strcmp(s->locale, "de") || !strncmp(s->locale, "de-", 3)))
+ phonebook = 1;
+ if (s->usage == COLLATOR_USAGE_SORT && s->locale &&
+ (!strcmp(s->locale, "de") || !strncmp(s->locale, "de-", 3)) &&
+ !phonebook)
+ german_sort = 1;
+ if (s->locale &&
+ (!strcmp(s->locale, "tr") || !strncmp(s->locale, "tr-", 3) ||
+ !strcmp(s->locale, "az") || !strncmp(s->locale, "az-", 3)))
+ turkish = 1;
+
+ nfd_len = unicode_normalize(&nfd, src, src_len, UNICODE_NFD,
+ JS_GetRuntime(ctx), (DynBufReallocFunc *)js_realloc_rt);
+ if (nfd_len < 0) return NULL;
+
+ result_cap = nfd_len * 4 + 4;
+ result = js_malloc(ctx, sizeof(uint32_t) * (size_t)result_cap);
+ if (!result) {
+ js_free(ctx, nfd);
+ return NULL;
+ }
+
+ for (i = 0; i < nfd_len; i++) {
+ uint32_t c = nfd[i];
+ uint32_t folded[3];
+ int flen;
+
+ if (s->ignorePunctuation && !is_significant(c))
+ continue;
+
+ if ((level == 0 || level == 2) && is_combining_mark(c))
+ continue;
+
+ if (level == 0 || level == 1) {
+ /* Casefold for base and accent/secondary */
+ int mapped = 0;
+
+ /* Handle NFD decomposed umlauts: base + combining diaeresis */
+ if (i + 1 < nfd_len && nfd[i + 1] == 0x0308) {
+ if (phonebook) {
+ if (c == 'A' || c == 'a') {
+ result[result_len++] = 'a';
+ result[result_len++] = 'e';
+ mapped = 1;
+ } else if (c == 'O' || c == 'o') {
+ result[result_len++] = 'o';
+ result[result_len++] = 'e';
+ mapped = 1;
+ } else if (c == 'U' || c == 'u') {
+ result[result_len++] = 'u';
+ result[result_len++] = 'e';
+ mapped = 1;
+ }
+ } else if (german_sort) {
+ if (c == 'A' || c == 'a') {
+ result[result_len++] = 'a';
+ result[result_len++] = 1;
+ mapped = 1;
+ } else if (c == 'O' || c == 'o') {
+ result[result_len++] = 'o';
+ result[result_len++] = 1;
+ mapped = 1;
+ } else if (c == 'U' || c == 'u') {
+ result[result_len++] = 'u';
+ result[result_len++] = 1;
+ mapped = 1;
+ }
+ }
+ if (mapped) {
+ i++; /* skip combining diaeresis */
+ continue;
+ }
+ }
+
+ if (phonebook) {
+ switch (c) {
+ case 0x00DF:
+ result[result_len++] = 's';
+ result[result_len++] = 's';
+ continue;
+ }
+ }
+
+ flen = lre_case_conv(folded, c, 2);
+ /* Turkish: map dotless i (ı) to sort before dotted i */
+ if (turkish && flen == 1 && folded[0] == 0x0131) {
+ if (result_len + 2 > result_cap) {
+ int new_cap = result_cap * 2;
+ uint32_t *new_result = js_realloc(ctx, result, sizeof(uint32_t) * (size_t)new_cap);
+ if (!new_result) {
+ js_free(ctx, nfd);
+ js_free(ctx, result);
+ return NULL;
+ }
+ result = new_result;
+ result_cap = new_cap;
+ }
+ result[result_len++] = 0x0068; /* h */
+ result[result_len++] = 0xFFFF; /* synthetic weight between h and i */
+ continue;
+ }
+ if (result_len + flen > result_cap) {
+ int new_cap = result_cap * 2;
+ uint32_t *new_result = js_realloc(ctx, result, sizeof(uint32_t) * (size_t)new_cap);
+ if (!new_result) {
+ js_free(ctx, nfd);
+ js_free(ctx, result);
+ return NULL;
+ }
+ result = new_result;
+ result_cap = new_cap;
+ }
+ memcpy(&result[result_len], folded, (size_t)flen * sizeof(uint32_t));
+ result_len += flen;
+ } else {
+ /* Preserve case for case and tertiary */
+ if (result_len >= result_cap) {
+ int new_cap = result_cap * 2;
+ uint32_t *new_result = js_realloc(ctx, result, sizeof(uint32_t) * (size_t)new_cap);
+ if (!new_result) {
+ js_free(ctx, nfd);
+ js_free(ctx, result);
+ return NULL;
+ }
+ result = new_result;
+ result_cap = new_cap;
+ }
+ result[result_len++] = c;
+ }
+ }
+
+ js_free(ctx, nfd);
+ *out_len = result_len;
+ return result;
+}
+
+static int js_UTF32_compare_len(const uint32_t *buf1, int len1,
+ const uint32_t *buf2, int len2)
+{
+ int i, len, c;
+ len = len1 < len2 ? len1 : len2;
+ for (i = 0; i < len; i++) {
+ c = (int)buf1[i] - (int)buf2[i];
+ if (c != 0)
+ return c;
+ }
+ if (len1 == len2)
+ return 0;
+ else if (len1 < len2)
+ return -1;
+ else
+ return 1;
+}
+
+/* bound compare function */
+static int js_string_normalize1(JSContext *ctx, uint32_t **pout_buf,
+ JSValueConst val, int n_type)
+{
+ int buf_len, out_len;
+ uint32_t *buf, *out_buf;
+
+ buf_len = JS_ToUTF32String(ctx, &buf, val);
+ if (buf_len < 0)
+ return -1;
+ out_len = unicode_normalize(&out_buf, buf, buf_len, n_type,
+ JS_GetRuntime(ctx), (DynBufReallocFunc *)js_realloc_rt);
+ js_free(ctx, buf);
+ if (out_len < 0)
+ return -1;
+ *pout_buf = out_buf;
+ return out_len;
+}
+
+static JSValue js_collator_bound_compare(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv,
+ int magic, JSValue *func_data)
+{
+ JSValue a, b;
+ int cmp = 0, a_len, b_len;
+ uint32_t *a_buf, *b_buf;
+ uint32_t *a_key = NULL, *b_key = NULL;
+ int a_key_len = 0, b_key_len = 0;
+ uint32_t *a_key2 = NULL, *b_key2 = NULL;
+ int a_key2_len = 0, b_key2_len = 0;
+ JSCollatorData *s = JS_GetOpaque2(ctx, func_data[0], js_collator_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+
+ a = JS_ToString(ctx, argv[0]);
+ if (JS_IsException(a))
+ return JS_EXCEPTION;
+ b = JS_ToString(ctx, argv[1]);
+ if (JS_IsException(b)) {
+ JS_FreeValue(ctx, a);
+ return JS_EXCEPTION;
+ }
+
+ a_len = js_string_normalize1(ctx, &a_buf, a, UNICODE_NFD);
+ JS_FreeValue(ctx, a);
+ if (a_len < 0) {
+ JS_FreeValue(ctx, b);
+ return JS_EXCEPTION;
+ }
+
+ b_len = js_string_normalize1(ctx, &b_buf, b, UNICODE_NFD);
+ JS_FreeValue(ctx, b);
+ if (b_len < 0) {
+ js_free(ctx, a_buf);
+ return JS_EXCEPTION;
+ }
+
+ switch (s->sensitivity) {
+ case COLLATOR_SENSITIVITY_BASE:
+ a_key = transform_string(ctx, s, a_buf, a_len, &a_key_len, 0);
+ b_key = transform_string(ctx, s, b_buf, b_len, &b_key_len, 0);
+ if (a_key && b_key)
+ cmp = js_UTF32_compare_len(a_key, a_key_len, b_key, b_key_len);
+ break;
+ case COLLATOR_SENSITIVITY_ACCENT:
+ a_key = transform_string(ctx, s, a_buf, a_len, &a_key_len, 1);
+ b_key = transform_string(ctx, s, b_buf, b_len, &b_key_len, 1);
+ if (a_key && b_key)
+ cmp = js_UTF32_compare_len(a_key, a_key_len, b_key, b_key_len);
+ break;
+ case COLLATOR_SENSITIVITY_CASE:
+ a_key = transform_string(ctx, s, a_buf, a_len, &a_key_len, 2);
+ b_key = transform_string(ctx, s, b_buf, b_len, &b_key_len, 2);
+ if (a_key && b_key)
+ cmp = js_UTF32_compare_len(a_key, a_key_len, b_key, b_key_len);
+ break;
+ case COLLATOR_SENSITIVITY_VARIANT:
+ a_key = transform_string(ctx, s, a_buf, a_len, &a_key_len, 1);
+ b_key = transform_string(ctx, s, b_buf, b_len, &b_key_len, 1);
+ if (a_key && b_key)
+ cmp = js_UTF32_compare_len(a_key, a_key_len, b_key, b_key_len);
+ if (cmp == 0) {
+ int i;
+ a_key2 = transform_string(ctx, s, a_buf, a_len, &a_key2_len, 3);
+ b_key2 = transform_string(ctx, s, b_buf, b_len, &b_key2_len, 3);
+ if (a_key2 && b_key2) {
+ int min_len = a_key2_len < b_key2_len ? a_key2_len : b_key2_len;
+ for (i = 0; i < min_len; i++) {
+ cmp = compare_case_order(a_key2[i], b_key2[i], s->caseFirst);
+ if (cmp != 0)
+ break;
+ }
+ if (cmp == 0) {
+ if (a_key2_len < b_key2_len) cmp = -1;
+ else if (a_key2_len > b_key2_len) cmp = 1;
+ }
+ }
+ }
+ break;
+ }
+
+ js_free(ctx, a_buf);
+ js_free(ctx, b_buf);
+ js_free(ctx, a_key);
+ js_free(ctx, b_key);
+ js_free(ctx, a_key2);
+ js_free(ctx, b_key2);
+ return JS_NewInt32(ctx, cmp);
+}
+
+/* getter for Intl.Collator.prototype.compare */
+static JSValue js_collator_get_compare(JSContext *ctx, JSValueConst this_val)
+{
+ JSCollatorData *s = JS_GetOpaque2(ctx, this_val, js_collator_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+
+ JSValueConst data[1] = { this_val };
+ return JS_NewCFunctionData(ctx, js_collator_bound_compare,
+ 2, 0, 1, data);
+}
+
+static JSValue js_collator_resolvedOptions(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSValue obj;
+ JSCollatorData *s = JS_GetOpaque2(ctx, this_val, js_collator_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+
+ obj = JS_NewObject(ctx);
+ if (JS_IsException(obj))
+ return JS_EXCEPTION;
+
+ JS_DefinePropertyValueStr(ctx, obj, "locale",
+ JS_NewString(ctx, s->locale), JS_PROP_C_W_E);
+ JS_DefinePropertyValueStr(ctx, obj, "usage",
+ JS_NewString(ctx, collator_usage_names[s->usage]), JS_PROP_C_W_E);
+ JS_DefinePropertyValueStr(ctx, obj, "sensitivity",
+ JS_NewString(ctx, collator_sensitivity_names[s->sensitivity]), JS_PROP_C_W_E);
+ JS_DefinePropertyValueStr(ctx, obj, "ignorePunctuation",
+ JS_NewBool(ctx, s->ignorePunctuation), JS_PROP_C_W_E);
+ JS_DefinePropertyValueStr(ctx, obj, "collation",
+ JS_NewString(ctx, s->collation), JS_PROP_C_W_E);
+ if (s->hasNumeric)
+ JS_DefinePropertyValueStr(ctx, obj, "numeric",
+ JS_NewBool(ctx, s->numeric), JS_PROP_C_W_E);
+ if (s->hasCaseFirst)
+ JS_DefinePropertyValueStr(ctx, obj, "caseFirst",
+ JS_NewString(ctx, collator_casefirst_names[s->caseFirst]), JS_PROP_C_W_E);
+ return obj;
+}
+
+static JSValue js_collator_supportedLocalesOf(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ return js_intl_supportedLocalesOf(ctx, this_val, argc, argv);
+}
+
+static const JSCFunctionListEntry js_collator_proto_funcs[] = {
+ JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Intl.Collator", JS_PROP_CONFIGURABLE),
+ JS_CGETSET_DEF("compare", js_collator_get_compare, NULL),
+ JS_CFUNC_DEF("resolvedOptions", 0, js_collator_resolvedOptions),
+};
+
+static const JSCFunctionListEntry js_collator_static_funcs[] = {
+ JS_CFUNC_DEF("supportedLocalesOf", 1, js_collator_supportedLocalesOf),
+};
+
+int js_add_collator(JSContext *ctx, JSValue intl_obj)
+{
+ JS_NewClassID(&js_collator_class_id);
+ JS_NewClass(JS_GetRuntime(ctx), js_collator_class_id, &js_collator_class);
+
+ if (JS_IsException(js_intl_new_constructor(ctx, intl_obj,
+ JS_INTL_CTOR_COLLATOR,
+ js_collator_class_id, "Collator",
+ (JSCFunction *)js_collator_constructor, 0,
+ JS_CFUNC_constructor_or_func_flags, 0,
+ js_collator_static_funcs, countof(js_collator_static_funcs),
+ js_collator_proto_funcs, countof(js_collator_proto_funcs))))
+ return -1;
+
+ return 0;
+}
--- /dev/null
+/*
+ * QuickJS Intl.DateTimeFormat implementation
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <math.h>
+#include <sys/time.h>
+#include <time.h>
+
+#include "../quickjs.h"
+#include "../cutils.h"
+#include "../temporal/temporal_private.h"
+#include "intl_private.h"
+
+static JSClassID js_datetimeformat_class_id;
+
+enum {
+ DTF_STYLE_FULL = 0,
+ DTF_STYLE_LONG,
+ DTF_STYLE_MEDIUM,
+ DTF_STYLE_SHORT,
+ DTF_STYLE_UNSET,
+};
+static const char *dtf_style_names[] = {"full", "long", "medium", "short"};
+
+enum {
+ DTF_HOURCYCLE_H11 = 0,
+ DTF_HOURCYCLE_H12,
+ DTF_HOURCYCLE_H23,
+ DTF_HOURCYCLE_H24,
+ DTF_HOURCYCLE_UNSET,
+};
+
+static const char *dtf_hourcycle_names[] = {"h11", "h12", "h23", "h24"};
+
+enum {
+ DTF_WEEKDAY_NARROW = 0,
+ DTF_WEEKDAY_SHORT,
+ DTF_WEEKDAY_LONG,
+ DTF_WEEKDAY_UNSET,
+};
+static const char *dtf_weekday_names[] = {"narrow", "short", "long"};
+
+enum {
+ DTF_ERA_NARROW = 0,
+ DTF_ERA_SHORT,
+ DTF_ERA_LONG,
+ DTF_ERA_UNSET,
+};
+static const char *dtf_era_names[] = {"narrow", "short", "long"};
+
+enum {
+ DTF_YEAR_2DIGIT = 0,
+ DTF_YEAR_NUMERIC,
+ DTF_YEAR_UNSET,
+};
+static const char *dtf_year_names[] = {"2-digit", "numeric"};
+
+enum {
+ DTF_MONTH_2DIGIT = 0,
+ DTF_MONTH_NUMERIC,
+ DTF_MONTH_NARROW,
+ DTF_MONTH_SHORT,
+ DTF_MONTH_LONG,
+ DTF_MONTH_UNSET,
+};
+static const char *dtf_month_names[] = {"2-digit", "numeric", "narrow", "short", "long"};
+
+enum {
+ DTF_DAY_2DIGIT = 0,
+ DTF_DAY_NUMERIC,
+ DTF_DAY_UNSET,
+};
+static const char *dtf_day_names[] = {"2-digit", "numeric"};
+
+enum {
+ DTF_DAYPERIOD_NARROW = 0,
+ DTF_DAYPERIOD_SHORT,
+ DTF_DAYPERIOD_LONG,
+ DTF_DAYPERIOD_UNSET,
+};
+static const char *dtf_dayperiod_names[] = {"narrow", "short", "long"};
+
+enum {
+ DTF_HOUR_2DIGIT = 0,
+ DTF_HOUR_NUMERIC,
+ DTF_HOUR_UNSET,
+};
+static const char *dtf_hour_names[] = {"2-digit", "numeric"};
+
+enum {
+ DTF_MINUTE_2DIGIT = 0,
+ DTF_MINUTE_NUMERIC,
+ DTF_MINUTE_UNSET,
+};
+static const char *dtf_minute_names[] = {"2-digit", "numeric"};
+
+enum {
+ DTF_SECOND_2DIGIT = 0,
+ DTF_SECOND_NUMERIC,
+ DTF_SECOND_UNSET,
+};
+static const char *dtf_second_names[] = {"2-digit", "numeric"};
+
+enum {
+ DTF_TIMEZONE_SHORT = 0,
+ DTF_TIMEZONE_LONG,
+ DTF_TIMEZONE_SHORTOFFSET,
+ DTF_TIMEZONE_LONGOFFSET,
+ DTF_TIMEZONE_SHORTGENERIC,
+ DTF_TIMEZONE_LONGGENERIC,
+ DTF_TIMEZONE_UNSET,
+};
+static const char *dtf_timezonename_names[] = {"short", "long", "shortOffset", "longOffset", "shortGeneric", "longGeneric"};
+
+enum {
+ DTF_FORMATMATCHER_BASIC = 0,
+ DTF_FORMATMATCHER_BESTFIT,
+ DTF_FORMATMATCHER_UNSET,
+};
+static const char *dtf_formatmatcher_names[] = {"basic", "best fit"};
+
+/* Validate Unicode Locale Identifier type: alphanum{3,8} (- alphanum{3,8})* */
+static int is_valid_locale_type(const char *str)
+{
+ int seg_len = 0;
+ const char *p = str;
+ while (*p) {
+ if ((*p >= '0' && *p <= '9') || (*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z')) {
+ seg_len++;
+ if (seg_len > 8)
+ return 0;
+ p++;
+ } else if (*p == '-') {
+ if (seg_len < 3 || seg_len > 8)
+ return 0;
+ seg_len = 0;
+ p++;
+ } else {
+ return 0;
+ }
+ }
+ return seg_len >= 3 && seg_len <= 8;
+}
+
+static int is_valid_time_zone(const char *str)
+{
+ int len = (int)strlen(str);
+ int i;
+ int has_slash = 0;
+ if (len == 0)
+ return 0;
+ if (str[0] == '+' || str[0] == '-') {
+ int hh, mm;
+ if (len == 6 && str[3] == ':') {
+ if (!isdigit((unsigned char)str[1]) || !isdigit((unsigned char)str[2]) ||
+ !isdigit((unsigned char)str[4]) || !isdigit((unsigned char)str[5]))
+ return 0;
+ hh = (str[1] - '0') * 10 + (str[2] - '0');
+ mm = (str[4] - '0') * 10 + (str[5] - '0');
+ } else if (len == 5) {
+ if (!isdigit((unsigned char)str[1]) || !isdigit((unsigned char)str[2]) ||
+ !isdigit((unsigned char)str[3]) || !isdigit((unsigned char)str[4]))
+ return 0;
+ hh = (str[1] - '0') * 10 + (str[2] - '0');
+ mm = (str[3] - '0') * 10 + (str[4] - '0');
+ } else if (len == 3) {
+ if (!isdigit((unsigned char)str[1]) || !isdigit((unsigned char)str[2]))
+ return 0;
+ hh = (str[1] - '0') * 10 + (str[2] - '0');
+ mm = 0;
+ } else {
+ return 0;
+ }
+ return hh >= 0 && hh <= 23 && mm >= 0 && mm <= 59;
+ }
+ /* allow UTC and GMT in any case */
+ if (!strcasecmp(str, "UTC") || !strcasecmp(str, "GMT"))
+ return 1;
+ /* IANA time zone names must contain a slash, except UTC/GMT/Etc zones */
+ for (i = 0; i < len; i++) {
+ char c = str[i];
+ if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
+ (c >= '0' && c <= '9') || c == '/' || c == '_' || c == '-' || c == '+'))
+ return 0;
+ if (c == '/')
+ has_slash = 1;
+ }
+ return has_slash;
+}
+
+static int is_supported_calendar(const char *str)
+{
+ return ti_calendar_string_to_enum(str) != CAL_UNKNOWN;
+}
+
+/* Canonicalize an offset time zone string to ±HH:MM format.
+ Returns a newly allocated string, or NULL on error. */
+static char *canonicalize_offset_time_zone(JSContext *ctx, const char *str)
+{
+ int len = (int)strlen(str);
+ char sign;
+ int hh, mm;
+ char *buf;
+ if (len == 0 || (str[0] != '+' && str[0] != '-'))
+ return NULL;
+ sign = str[0];
+ if (len == 3) {
+ hh = (str[1] - '0') * 10 + (str[2] - '0');
+ mm = 0;
+ } else if (len == 5) {
+ hh = (str[1] - '0') * 10 + (str[2] - '0');
+ mm = (str[3] - '0') * 10 + (str[4] - '0');
+ } else if (len == 6 && str[3] == ':') {
+ hh = (str[1] - '0') * 10 + (str[2] - '0');
+ mm = (str[4] - '0') * 10 + (str[5] - '0');
+ } else {
+ return NULL;
+ }
+ if (sign == '-' && hh == 0 && mm == 0)
+ sign = '+';
+ buf = js_malloc(ctx, 7);
+ if (!buf)
+ return NULL;
+ snprintf(buf, 7, "%c%02d:%02d", sign, hh, mm);
+ return buf;
+}
+
+typedef struct {
+ char *locale;
+ char *locale_canonical;
+ int calendar;
+ int numberingSystem;
+ char *timeZone;
+ int hour12;
+ int has_hour12;
+ int weekday;
+ int era;
+ int year;
+ int month;
+ int day;
+ int hour;
+ int minute;
+ int second;
+ int timeZoneName;
+ int dateStyle;
+ int timeStyle;
+ int fractionalSecondDigits;
+ int has_fractionalSecondDigits;
+ int dayPeriod;
+ int hourCycle;
+ int has_hourCycle;
+ int has_calendar_option;
+ int has_numberingSystem_option;
+ int has_hourCycle_option;
+ int has_year_option;
+ int has_month_option;
+ int has_day_option;
+ int formatMatcher;
+ int required;
+ int defaults;
+} JSDateTimeFormatData;
+
+static const char *en_tz_utc_long = "Coordinated Universal Time";
+
+static const char *islamic_month_long_en[12] = {
+ "Muharram", "Safar", "Rabiʻ I", "Rabiʻ II", "Jumada I", "Jumada II",
+ "Rajab", "Shaʻban", "Ramadan", "Shawwal", "Dhuʻl-Qiʻdah", "Dhuʻl-Hijjah"
+};
+
+static const char *islamic_month_short_en[12] = {
+ "Muh.", "Saf.", "Rab. I", "Rab. II", "Jum. I", "Jum. II",
+ "Raj.", "Sha.", "Ram.", "Shaw.", "Dhuʻl-Q.", "Dhuʻl-H."
+};
+
+static const char *hebrew_month_long_en[13] = {
+ "Tishri", "Heshvan", "Kislev", "Tevet", "Shevat", "Adar I",
+ "Adar II", "Nisan", "Iyar", "Sivan", "Tamuz", "Av", "Elul"
+};
+
+static const char *hebrew_month_short_en[13] = {
+ "Tishri", "Heshvan", "Kislev", "Tevet", "Shevat", "Adar I",
+ "Adar II", "Nisan", "Iyar", "Sivan", "Tammuz", "Av", "Elul"
+};
+
+/* Return a non-Gregorian calendar month name for English locale.
+ calendar: the calendar type.
+ locale: the locale string (e.g., "en").
+ cal_year: calendar year.
+ cal_month: 1-based calendar month.
+ width: 4=long, 3=short, 5=narrow (narrow falls back to short).
+ Returns the name string or NULL if no special name applies. */
+static const char *get_calendar_month_name(int calendar, const char *locale,
+ int cal_year, int cal_month,
+ int width)
+{
+ int is_long, is_short;
+
+ if (!locale || !strstart(locale, "en", NULL))
+ return NULL;
+ if (cal_month < 1)
+ return NULL;
+ is_long = (width >= 4);
+ is_short = (width == 3);
+ if (calendar == CAL_ISLAMIC_CIVIL || calendar == CAL_ISLAMIC_TBLA ||
+ calendar == CAL_ISLAMIC_UMALQURA) {
+ if (cal_month > 12)
+ return NULL;
+ if (is_long)
+ return islamic_month_long_en[cal_month - 1];
+ if (is_short)
+ return islamic_month_short_en[cal_month - 1];
+ return NULL;
+ }
+ if (calendar == CAL_HEBREW) {
+ int is_leap = ti_calendar_is_leap_year(CAL_HEBREW, cal_year);
+ int idx = cal_month - 1;
+ if (!is_leap) {
+ /* Non-leap year: Adar is month 6, skip Adar I slot */
+ static const char *nonleap_long[12] = {
+ "Tishri", "Heshvan", "Kislev", "Tevet", "Shevat", "Adar",
+ "Nisan", "Iyar", "Sivan", "Tamuz", "Av", "Elul"
+ };
+ static const char *nonleap_short[12] = {
+ "Tishri", "Heshvan", "Kislev", "Tevet", "Shevat", "Adar",
+ "Nisan", "Iyar", "Sivan", "Tamuz", "Av", "Elul"
+ };
+ if (idx >= 12)
+ return NULL;
+ if (is_long)
+ return nonleap_long[idx];
+ if (is_short)
+ return nonleap_short[idx];
+ /* For narrow / numeric fallback, return long name */
+ return nonleap_long[idx];
+ } else {
+ if (idx >= 13)
+ return NULL;
+ if (is_long)
+ return hebrew_month_long_en[idx];
+ if (is_short)
+ return hebrew_month_short_en[idx];
+ return hebrew_month_long_en[idx];
+ }
+ }
+ return NULL;
+}
+
+/* Return era string for a given calendar and year.
+ style: 0=long, 1=short, 2=narrow.
+ Returns 1 if the calendar should have an era, 0 otherwise. */
+static int get_calendar_era(int calendar, TIEra era, int style,
+ const LocaleData *ld, const char **era_str)
+{
+ if (era == TI_ERA_UNKNOWN)
+ return 0;
+
+ switch (calendar) {
+ case CAL_GREGORY:
+ *era_str = LD_ERA(ld, style, era == TI_ERA_BCE ? 0 : 1);
+ return 1;
+ case CAL_ISLAMIC_CIVIL:
+ case CAL_ISLAMIC_TBLA:
+ case CAL_ISLAMIC_UMALQURA:
+ if (era == TI_ERA_BH) {
+ *era_str = (style == 0) ? "Before Hijra" :
+ (style == 1) ? "BH" : "B";
+ } else {
+ *era_str = (style == 0) ? "AH" :
+ (style == 1) ? "AH" : "A";
+ }
+ return 1;
+ case CAL_JAPANESE:
+ switch (era) {
+ case TI_ERA_BCE:
+ *era_str = (style == 0) ? "Before Christ" :
+ (style == 1) ? "BC" : "B";
+ break;
+ case TI_ERA_CE:
+ *era_str = (style == 0) ? "Anno Domini" :
+ (style == 1) ? "AD" : "A";
+ break;
+ case TI_ERA_MEIJI:
+ *era_str = (style == 0) ? "Meiji" :
+ (style == 1) ? "Meiji" : "M";
+ break;
+ case TI_ERA_TAISHO:
+ *era_str = (style == 0) ? "Taisho" :
+ (style == 1) ? "Taisho" : "T";
+ break;
+ case TI_ERA_SHOWA:
+ *era_str = (style == 0) ? "Showa" :
+ (style == 1) ? "Showa" : "S";
+ break;
+ case TI_ERA_HEISEI:
+ *era_str = (style == 0) ? "Heisei" :
+ (style == 1) ? "Heisei" : "H";
+ break;
+ case TI_ERA_REIWA:
+ *era_str = (style == 0) ? "Reiwa" :
+ (style == 1) ? "Reiwa" : "R";
+ break;
+ default:
+ *era_str = (style == 0) ? "Anno Domini" :
+ (style == 1) ? "AD" : "A";
+ break;
+ }
+ return 1;
+ case CAL_ROC:
+ if (era == TI_ERA_BROC) {
+ *era_str = (style == 0) ? "Before ROC" :
+ (style == 1) ? "B.R.O.C." : "B";
+ } else {
+ *era_str = (style == 0) ? "ROC" :
+ (style == 1) ? "R.O.C." : "R";
+ }
+ return 1;
+ case CAL_ETHIOPIC:
+ if (era == TI_ERA_AA) {
+ *era_str = (style == 0) ? "AA" :
+ (style == 1) ? "AA" : "A";
+ } else {
+ *era_str = (style == 0) ? "AM" :
+ (style == 1) ? "AM" : "A";
+ }
+ return 1;
+ case CAL_ETHIOAA:
+ *era_str = (style == 0) ? "AA" :
+ (style == 1) ? "AA" : "A";
+ return 1;
+ case CAL_BUDDHIST:
+ *era_str = (style == 0) ? "BE" :
+ (style == 1) ? "BE" : "B";
+ return 1;
+ case CAL_COPTIC:
+ *era_str = (style == 0) ? "AM" :
+ (style == 1) ? "AM" : "A";
+ return 1;
+ case CAL_HEBREW:
+ *era_str = (style == 0) ? "AM" :
+ (style == 1) ? "AM" : "A";
+ return 1;
+ case CAL_INDIAN:
+ *era_str = (style == 0) ? "Saka" :
+ (style == 1) ? "Saka" : "S";
+ return 1;
+ case CAL_PERSIAN:
+ *era_str = (style == 0) ? "AP" :
+ (style == 1) ? "AP" : "A";
+ return 1;
+ case CAL_CHINESE:
+ case CAL_DANGI:
+ return 0;
+ }
+
+ /* Default fallback */
+ *era_str = LD_ERA(ld, style, era == TI_ERA_BCE ? 0 : 1);
+ return 1;
+}
+static const char *en_tz_utc_short = "UTC";
+
+/* Return day period index (0-4) for English locale based on hour (0-23).
+ 0=morning, 1=noon, 2=afternoon, 3=evening, 4=night */
+static int get_en_dayperiod_idx(int hour)
+{
+ if (hour >= 6 && hour <= 11)
+ return 0; /* morning */
+ if (hour == 12)
+ return 1; /* noon */
+ if (hour >= 13 && hour <= 17)
+ return 2; /* afternoon */
+ if (hour >= 18 && hour <= 20)
+ return 3; /* evening */
+ return 4; /* night (21-23, 0-5) */
+}
+
+typedef struct {
+ int year;
+ int month;
+ int day;
+ int hour;
+ int minute;
+ int second;
+ int ms;
+ int weekday;
+ int64_t epoch_sec;
+} DTFDateFields;
+
+typedef struct {
+ const char *type;
+ int off;
+ int len;
+} DTFPartInfo;
+
+static int dtf_parse_offset_timezone(const char *tz, int *offset_min)
+{
+ int hh, mm;
+ int sign = 1;
+ int len = (int)strlen(tz);
+ if (len < 3 || (tz[0] != '+' && tz[0] != '-'))
+ return -1;
+ if (tz[0] == '-')
+ sign = -1;
+ if (len == 3) {
+ hh = (tz[1] - '0') * 10 + (tz[2] - '0');
+ mm = 0;
+ } else if (len == 6 && tz[3] == ':') {
+ hh = (tz[1] - '0') * 10 + (tz[2] - '0');
+ mm = (tz[4] - '0') * 10 + (tz[5] - '0');
+ } else if (len == 5) {
+ hh = (tz[1] - '0') * 10 + (tz[2] - '0');
+ mm = (tz[3] - '0') * 10 + (tz[4] - '0');
+ } else {
+ return -1;
+ }
+ *offset_min = sign * (hh * 60 + mm);
+ return 0;
+}
+
+static void dtf_extract_fields(double ms, const char *timeZone, DTFDateFields *out)
+{
+ int64_t ms_i = (int64_t)ms;
+ int64_t sec = ms_i / 1000;
+ int ms_val = (int)(ms_i % 1000);
+ int64_t offset_sec = 0;
+ int64_t year;
+ int month, day, hour, minute, second;
+ int64_t days;
+
+ if (ms_val < 0) {
+ ms_val += 1000;
+ sec -= 1;
+ }
+
+ {
+ int tz_id = ti_tz_find_id(timeZone);
+ if (tz_id >= 0) {
+ offset_sec = ti_tz_offset_at_sec(tz_id, sec);
+ } else if (timeZone[0] == '+' || timeZone[0] == '-') {
+ int offset_min;
+ if (dtf_parse_offset_timezone(timeZone, &offset_min) == 0)
+ offset_sec = offset_min * 60;
+ }
+ }
+
+ sec += offset_sec;
+ ti_epoch_sec_to_date(sec, &year, &month, &day, &hour, &minute, &second);
+ days = floor_div64(sec, 86400ULL);
+
+ out->year = (int)year;
+ out->month = month - 1;
+ out->day = day;
+ out->hour = hour;
+ out->minute = minute;
+ out->second = second;
+ out->ms = ms_val;
+ {
+ int wday = (int)((days + 4) % 7);
+ if (wday < 0)
+ wday += 7;
+ out->weekday = wday;
+ }
+ out->epoch_sec = sec;
+}
+
+/* Return the default numbering system for a locale based on language tag.
+ This is a pragmatic mapping for common locales. */
+static int dtf_default_numbering_system(const char *locale)
+{
+ if (strstart(locale, "ar", NULL))
+ return NS_ARAB;
+ if (strstart(locale, "th", NULL))
+ return NS_THAI;
+ if (strstart(locale, "bn", NULL))
+ return NS_BENG;
+ if (strstart(locale, "hi", NULL) || strstart(locale, "mr", NULL) ||
+ strstart(locale, "ne", NULL) || strstart(locale, "sa", NULL))
+ return NS_DEVA;
+ if (strstart(locale, "pa", NULL))
+ return NS_GURU;
+ if (strstart(locale, "gu", NULL))
+ return NS_GUJR;
+ if (strstart(locale, "ta", NULL))
+ return NS_TAML;
+ if (strstart(locale, "te", NULL))
+ return NS_TELU;
+ if (strstart(locale, "kn", NULL))
+ return NS_KNDA;
+ if (strstart(locale, "ml", NULL))
+ return NS_MLYM;
+ if (strstart(locale, "or", NULL))
+ return NS_ORYA;
+ if (strstart(locale, "my", NULL))
+ return NS_MYMR;
+ if (strstart(locale, "km", NULL))
+ return NS_KHMR;
+ if (strstart(locale, "lo", NULL))
+ return NS_LAOO;
+ if (strstart(locale, "am", NULL))
+ return NS_ETHI;
+ return NS_LATN;
+}
+
+/* Return the separator used before dayPeriod for a given locale.
+ en-US uses narrow no-break space (U+202F) per CLDR to match
+ the timeStyle patterns used by temporal-objects-resolved-time-zone. */
+static const char *dtf_get_dayperiod_separator(const char *locale)
+{
+ if (!strcmp(locale, "en-US"))
+ return "\u202F";
+ return " ";
+}
+
+static void dtf_expand_styles(JSDateTimeFormatData *s, int *weekday, int *year, int *month, int *day,
+ int *hour, int *minute, int *second, int *timeZoneName)
+{
+ *weekday = s->weekday;
+ *year = s->year;
+ *month = s->month;
+ *day = s->day;
+ *hour = s->hour;
+ *minute = s->minute;
+ *second = s->second;
+ *timeZoneName = s->timeZoneName;
+
+ if (s->dateStyle != DTF_STYLE_UNSET) {
+ switch (s->dateStyle) {
+ case DTF_STYLE_FULL:
+ *weekday = DTF_WEEKDAY_LONG;
+ *year = DTF_YEAR_NUMERIC;
+ *month = DTF_MONTH_LONG;
+ *day = DTF_DAY_NUMERIC;
+ break;
+ case DTF_STYLE_LONG:
+ *weekday = DTF_WEEKDAY_UNSET;
+ *year = DTF_YEAR_NUMERIC;
+ *month = DTF_MONTH_LONG;
+ *day = DTF_DAY_NUMERIC;
+ break;
+ case DTF_STYLE_MEDIUM:
+ *weekday = DTF_WEEKDAY_UNSET;
+ *year = DTF_YEAR_NUMERIC;
+ *month = DTF_MONTH_SHORT;
+ *day = DTF_DAY_NUMERIC;
+ break;
+ case DTF_STYLE_SHORT:
+ *weekday = DTF_WEEKDAY_UNSET;
+ *year = DTF_YEAR_2DIGIT;
+ *month = DTF_MONTH_NUMERIC;
+ *day = DTF_DAY_NUMERIC;
+ break;
+ }
+ }
+
+ if (s->timeStyle != DTF_STYLE_UNSET) {
+ switch (s->timeStyle) {
+ case DTF_STYLE_FULL:
+ *hour = DTF_HOUR_NUMERIC;
+ *minute = DTF_MINUTE_NUMERIC;
+ *second = DTF_SECOND_NUMERIC;
+ *timeZoneName = DTF_TIMEZONE_LONG;
+ break;
+ case DTF_STYLE_LONG:
+ *hour = DTF_HOUR_NUMERIC;
+ *minute = DTF_MINUTE_NUMERIC;
+ *second = DTF_SECOND_NUMERIC;
+ *timeZoneName = DTF_TIMEZONE_SHORT;
+ break;
+ case DTF_STYLE_MEDIUM:
+ *hour = DTF_HOUR_NUMERIC;
+ *minute = DTF_MINUTE_NUMERIC;
+ *second = DTF_SECOND_NUMERIC;
+ *timeZoneName = DTF_TIMEZONE_UNSET;
+ break;
+ case DTF_STYLE_SHORT:
+ *hour = DTF_HOUR_NUMERIC;
+ *minute = DTF_MINUTE_NUMERIC;
+ *second = DTF_SECOND_UNSET;
+ *timeZoneName = DTF_TIMEZONE_UNSET;
+ break;
+ }
+ }
+}
+
+static int dtf_check_temporal_overlap(JSContext *ctx, JSDateTimeFormatData *s,
+ JSValueConst val)
+{
+ void *p_inst = JS_GetOpaque(val, js_instant_class_id);
+ void *p_zdt = JS_GetOpaque(val, js_zoneddatetime_class_id);
+ void *p_pdt = JS_GetOpaque(val, js_plaindatetime_class_id);
+ void *p_pd = JS_GetOpaque(val, js_plaindate_class_id);
+ void *p_pt = JS_GetOpaque(val, js_plaintime_class_id);
+ void *p_pym = JS_GetOpaque(val, js_plainyearmonth_class_id);
+ void *p_pmd = JS_GetOpaque(val, js_plainmonthday_class_id);
+ if (!p_inst && !p_zdt && !p_pdt && !p_pd && !p_pt && !p_pym && !p_pmd)
+ return 0;
+ /* ZonedDateTime is not supported directly by DateTimeFormat */
+ if (p_zdt) {
+ JS_ThrowTypeError(ctx, "format() does not support Temporal.ZonedDateTime");
+ return -1;
+ }
+ /* Style branch: dateStyle/timeStyle */
+ if (s->dateStyle != DTF_STYLE_UNSET || s->timeStyle != DTF_STYLE_UNSET) {
+ if (p_pt && s->timeStyle == DTF_STYLE_UNSET) {
+ JS_ThrowTypeError(ctx, "no overlap between dateTimeFormat options and Temporal object fields");
+ return -1;
+ }
+ if ((p_pd || p_pym || p_pmd) && s->dateStyle == DTF_STYLE_UNSET) {
+ JS_ThrowTypeError(ctx, "no overlap between dateTimeFormat options and Temporal object fields");
+ return -1;
+ }
+ return 0;
+ }
+ /* Explicit options branch: GetDateTimeFormat logic */
+ {
+ int any_present = 0;
+ int req_weekday = 0, req_year = 0, req_month = 0, req_day = 0;
+ int req_hour = 0, req_minute = 0, req_second = 0, req_frac = 0, req_dp = 0;
+ int required_present = 0;
+ if (s->weekday != DTF_WEEKDAY_UNSET) { any_present = 1; req_weekday = 1; }
+ if (s->has_year_option) { any_present = 1; req_year = 1; }
+ if (s->has_month_option) { any_present = 1; req_month = 1; }
+ if (s->has_day_option) { any_present = 1; req_day = 1; }
+ if (s->dayPeriod != DTF_DAYPERIOD_UNSET) { any_present = 1; req_dp = 1; }
+ if (s->hour != DTF_HOUR_UNSET) { any_present = 1; req_hour = 1; }
+ if (s->minute != DTF_MINUTE_UNSET) { any_present = 1; req_minute = 1; }
+ if (s->second != DTF_SECOND_UNSET) { any_present = 1; req_second = 1; }
+ if (s->has_fractionalSecondDigits) { any_present = 1; req_frac = 1; }
+ /* era and timeZoneName do not count towards any_present or required */
+ if (p_pt) {
+ /* PlainTime: required = {dayPeriod, hour, minute, second, fractionalSecondDigits} */
+ if (req_dp || req_hour || req_minute || req_second || req_frac) required_present = 1;
+ } else if (p_pd) {
+ /* PlainDate: required = {weekday, year, month, day} */
+ if (req_weekday || req_year || req_month || req_day) required_present = 1;
+ } else if (p_pym) {
+ /* PlainYearMonth: required = {year, month} */
+ if (req_year || req_month) required_present = 1;
+ } else if (p_pmd) {
+ /* PlainMonthDay: required = {month, day} */
+ if (req_month || req_day) required_present = 1;
+ } else {
+ /* PlainDateTime, Instant, ZonedDateTime: required = all */
+ required_present = 1; /* always has overlap since any_present field is required */
+ }
+ if (!required_present && any_present) {
+ JS_ThrowTypeError(ctx, "no overlap between dateTimeFormat options and Temporal object fields");
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static void dtf_append_number(DynBuf *db, int n, int width, int numberingSystem)
+{
+ char buf[32];
+ int len, i;
+
+ if (width > 1)
+ len = snprintf(buf, sizeof(buf), "%0*d", width, n);
+ else
+ len = snprintf(buf, sizeof(buf), "%d", n);
+
+ if (numberingSystem == NS_LATN) {
+ dbuf_put(db, (uint8_t *)buf, (size_t)len);
+ } else {
+ for (i = 0; i < len; i++) {
+ if (buf[i] >= '0' && buf[i] <= '9')
+ nf_put_digit(db, numberingSystem, buf[i] - '0');
+ else
+ dbuf_putc(db, (uint8_t)buf[i]);
+ }
+ }
+}
+
+static int dtf_record_part(JSContext *ctx, DynBuf *db, DTFPartInfo **parts, int *n_parts, int *max_parts,
+ const char *type, int off, int len)
+{
+ if (!parts)
+ return 0;
+ if (*n_parts >= *max_parts) {
+ int new_max = *max_parts ? *max_parts * 2 : 8;
+ DTFPartInfo *new_parts = js_realloc(ctx, *parts, (size_t)new_max * sizeof(DTFPartInfo));
+ if (!new_parts)
+ return -1;
+ *parts = new_parts;
+ *max_parts = new_max;
+ }
+ (*parts)[*n_parts].type = type;
+ (*parts)[*n_parts].off = off;
+ (*parts)[*n_parts].len = len;
+ (*n_parts)++;
+ return 0;
+}
+
+static int dtf_add_literal(JSContext *ctx, DynBuf *db, DTFPartInfo **parts, int *n_parts, int *max_parts,
+ const char *str)
+{
+ int off = (int)db->size;
+ int len = (int)strlen(str);
+ dbuf_put(db, (uint8_t *)str, (size_t)len);
+ if (parts)
+ return dtf_record_part(ctx, db, parts, n_parts, max_parts, "literal", off, len);
+ return 0;
+}
+
+static double dtf_iso_to_epoch_ms(int year, int month, int day,
+ int hour, int minute, int second, int millisecond);
+
+static int dtf_to_datetimeformattable(JSContext *ctx, JSValueConst arg, double *pd, BOOL *is_temporal, BOOL *needs_clip)
+{
+ *is_temporal = FALSE;
+ *needs_clip = FALSE;
+ if (JS_IsUndefined(arg)) {
+ JS_ThrowTypeError(ctx, "date argument is undefined");
+ return -1;
+ }
+ if (JS_IsObject(arg)) {
+ JSInstantData *instant = JS_GetOpaque(arg, js_instant_class_id);
+ if (instant) {
+ *pd = timespec_to_ms(&instant->ts);
+ *is_temporal = TRUE;
+ *needs_clip = TRUE;
+ return 0;
+ }
+ JSZonedDateTimeData *zdt = JS_GetOpaque(arg, js_zoneddatetime_class_id);
+ if (zdt) {
+ *pd = timespec_to_ms(&zdt->ts);
+ *is_temporal = TRUE;
+ *needs_clip = TRUE;
+ return 0;
+ }
+ JSPlainDateTimeData *pdt = JS_GetOpaque(arg, js_plaindatetime_class_id);
+ if (pdt) {
+ *pd = dtf_iso_to_epoch_ms(pdt->year, pdt->month, pdt->day,
+ pdt->hour, pdt->minute, pdt->second, pdt->millisecond);
+ *is_temporal = TRUE;
+ return 0;
+ }
+ JSPlainDateData *pdate = JS_GetOpaque(arg, js_plaindate_class_id);
+ if (pdate) {
+ *pd = dtf_iso_to_epoch_ms(pdate->year, pdate->month, pdate->day, 12, 0, 0, 0);
+ *is_temporal = TRUE;
+ return 0;
+ }
+ JSPlainTimeData *pt = JS_GetOpaque(arg, js_plaintime_class_id);
+ if (pt) {
+ *pd = dtf_iso_to_epoch_ms(1970, 1, 1, pt->hour, pt->minute, pt->second, pt->millisecond);
+ *is_temporal = TRUE;
+ return 0;
+ }
+ JSPlainYearMonthData *pym = JS_GetOpaque(arg, js_plainyearmonth_class_id);
+ if (pym) {
+ *pd = dtf_iso_to_epoch_ms(pym->iso_year, pym->iso_month, pym->iso_day, 12, 0, 0, 0);
+ *is_temporal = TRUE;
+ return 0;
+ }
+ JSPlainMonthDayData *pmd = JS_GetOpaque(arg, js_plainmonthday_class_id);
+ if (pmd) {
+ *pd = dtf_iso_to_epoch_ms(pmd->iso_year, pmd->iso_month, pmd->iso_day, 12, 0, 0, 0);
+ *is_temporal = TRUE;
+ return 0;
+ }
+ }
+ *needs_clip = TRUE;
+ return JS_ToFloat64(ctx, pd, arg);
+}
+
+static BOOL dtf_same_temporal_type(JSContext *ctx, JSValueConst a, JSValueConst b)
+{
+ if (JS_GetOpaque(a, js_instant_class_id) || JS_GetOpaque(b, js_instant_class_id))
+ return JS_GetOpaque(a, js_instant_class_id) && JS_GetOpaque(b, js_instant_class_id);
+ if (JS_GetOpaque(a, js_zoneddatetime_class_id) || JS_GetOpaque(b, js_zoneddatetime_class_id))
+ return JS_GetOpaque(a, js_zoneddatetime_class_id) && JS_GetOpaque(b, js_zoneddatetime_class_id);
+ if (JS_GetOpaque(a, js_plaindatetime_class_id) || JS_GetOpaque(b, js_plaindatetime_class_id))
+ return JS_GetOpaque(a, js_plaindatetime_class_id) && JS_GetOpaque(b, js_plaindatetime_class_id);
+ if (JS_GetOpaque(a, js_plaindate_class_id) || JS_GetOpaque(b, js_plaindate_class_id))
+ return JS_GetOpaque(a, js_plaindate_class_id) && JS_GetOpaque(b, js_plaindate_class_id);
+ if (JS_GetOpaque(a, js_plaintime_class_id) || JS_GetOpaque(b, js_plaintime_class_id))
+ return JS_GetOpaque(a, js_plaintime_class_id) && JS_GetOpaque(b, js_plaintime_class_id);
+ if (JS_GetOpaque(a, js_plainyearmonth_class_id) || JS_GetOpaque(b, js_plainyearmonth_class_id))
+ return JS_GetOpaque(a, js_plainyearmonth_class_id) && JS_GetOpaque(b, js_plainyearmonth_class_id);
+ if (JS_GetOpaque(a, js_plainmonthday_class_id) || JS_GetOpaque(b, js_plainmonthday_class_id))
+ return JS_GetOpaque(a, js_plainmonthday_class_id) && JS_GetOpaque(b, js_plainmonthday_class_id);
+ return TRUE;
+}
+
+static int dtf_get_temporal_calendar(JSContext *ctx, JSValueConst obj)
+{
+ JSPlainDateTimeData *pdt = JS_GetOpaque(obj, js_plaindatetime_class_id);
+ if (pdt)
+ return pdt->calendar;
+ JSPlainDateData *pd = JS_GetOpaque(obj, js_plaindate_class_id);
+ if (pd)
+ return pd->calendar;
+ JSPlainTimeData *pt = JS_GetOpaque(obj, js_plaintime_class_id);
+ if (pt)
+ return CAL_ISO8601;
+ JSPlainYearMonthData *pym = JS_GetOpaque(obj, js_plainyearmonth_class_id);
+ if (pym)
+ return pym->calendar;
+ JSPlainMonthDayData *pmd = JS_GetOpaque(obj, js_plainmonthday_class_id);
+ if (pmd)
+ return pmd->calendar;
+ JSZonedDateTimeData *zdt = JS_GetOpaque(obj, js_zoneddatetime_class_id);
+ if (zdt)
+ return zdt->calendar;
+ JSInstantData *instant = JS_GetOpaque(obj, js_instant_class_id);
+ if (instant)
+ return CAL_ISO8601;
+ return -1;
+}
+
+static void dtf_clear_non_overlapping_fields(JSDateTimeFormatData *s, JSValueConst val)
+{
+ void *p_pd = JS_GetOpaque(val, js_plaindate_class_id);
+ void *p_pt = JS_GetOpaque(val, js_plaintime_class_id);
+ void *p_pym = JS_GetOpaque(val, js_plainyearmonth_class_id);
+ void *p_pmd = JS_GetOpaque(val, js_plainmonthday_class_id);
+
+ if (p_pd) {
+ s->hour = DTF_HOUR_UNSET;
+ s->minute = DTF_MINUTE_UNSET;
+ s->second = DTF_SECOND_UNSET;
+ s->dayPeriod = DTF_DAYPERIOD_UNSET;
+ s->has_fractionalSecondDigits = 0;
+ s->timeStyle = DTF_STYLE_UNSET;
+ } else if (p_pt) {
+ s->weekday = DTF_WEEKDAY_UNSET;
+ s->year = DTF_YEAR_UNSET;
+ s->has_year_option = 0;
+ s->month = DTF_MONTH_UNSET;
+ s->has_month_option = 0;
+ s->day = DTF_DAY_UNSET;
+ s->has_day_option = 0;
+ s->era = DTF_ERA_UNSET;
+ s->dateStyle = DTF_STYLE_UNSET;
+ } else if (p_pym) {
+ s->weekday = DTF_WEEKDAY_UNSET;
+ s->day = DTF_DAY_UNSET;
+ s->has_day_option = 0;
+ s->hour = DTF_HOUR_UNSET;
+ s->minute = DTF_MINUTE_UNSET;
+ s->second = DTF_SECOND_UNSET;
+ s->dayPeriod = DTF_DAYPERIOD_UNSET;
+ s->has_fractionalSecondDigits = 0;
+ s->timeStyle = DTF_STYLE_UNSET;
+ } else if (p_pmd) {
+ s->weekday = DTF_WEEKDAY_UNSET;
+ s->year = DTF_YEAR_UNSET;
+ s->has_year_option = 0;
+ s->hour = DTF_HOUR_UNSET;
+ s->minute = DTF_MINUTE_UNSET;
+ s->second = DTF_SECOND_UNSET;
+ s->dayPeriod = DTF_DAYPERIOD_UNSET;
+ s->has_fractionalSecondDigits = 0;
+ s->timeStyle = DTF_STYLE_UNSET;
+ }
+}
+
+/* Convert dateStyle/timeStyle to explicit fields when formatting Temporal
+ objects, so that non-overlapping fields can be suppressed. This emulates
+ ECMA-402 AdjustDateTimeStyleFormat for Temporal types. */
+static void dtf_resolve_style_for_temporal(JSDateTimeFormatData *s, JSValueConst val)
+{
+ void *p_pd = JS_GetOpaque(val, js_plaindate_class_id);
+ void *p_pt = JS_GetOpaque(val, js_plaintime_class_id);
+ void *p_pdt = JS_GetOpaque(val, js_plaindatetime_class_id);
+ void *p_pym = JS_GetOpaque(val, js_plainyearmonth_class_id);
+ void *p_pmd = JS_GetOpaque(val, js_plainmonthday_class_id);
+ void *p_inst = JS_GetOpaque(val, js_instant_class_id);
+
+ if (s->dateStyle != DTF_STYLE_UNSET && (p_pt || p_pym || p_pmd)) {
+ switch (s->dateStyle) {
+ case DTF_STYLE_FULL:
+ s->weekday = DTF_WEEKDAY_LONG;
+ s->year = DTF_YEAR_NUMERIC;
+ s->month = DTF_MONTH_LONG;
+ s->day = DTF_DAY_NUMERIC;
+ break;
+ case DTF_STYLE_LONG:
+ s->weekday = DTF_WEEKDAY_UNSET;
+ s->year = DTF_YEAR_NUMERIC;
+ s->month = DTF_MONTH_LONG;
+ s->day = DTF_DAY_NUMERIC;
+ break;
+ case DTF_STYLE_MEDIUM:
+ s->weekday = DTF_WEEKDAY_UNSET;
+ s->year = DTF_YEAR_NUMERIC;
+ s->month = DTF_MONTH_SHORT;
+ s->day = DTF_DAY_NUMERIC;
+ break;
+ case DTF_STYLE_SHORT:
+ s->weekday = DTF_WEEKDAY_UNSET;
+ s->year = DTF_YEAR_2DIGIT;
+ s->month = DTF_MONTH_NUMERIC;
+ s->day = DTF_DAY_NUMERIC;
+ break;
+ }
+ s->dateStyle = DTF_STYLE_UNSET;
+ }
+
+ if (s->timeStyle != DTF_STYLE_UNSET && (p_pd || p_pym || p_pmd)) {
+ switch (s->timeStyle) {
+ case DTF_STYLE_FULL:
+ s->hour = DTF_HOUR_NUMERIC;
+ s->minute = DTF_MINUTE_NUMERIC;
+ s->second = DTF_SECOND_NUMERIC;
+ break;
+ case DTF_STYLE_LONG:
+ s->hour = DTF_HOUR_NUMERIC;
+ s->minute = DTF_MINUTE_NUMERIC;
+ s->second = DTF_SECOND_NUMERIC;
+ break;
+ case DTF_STYLE_MEDIUM:
+ s->hour = DTF_HOUR_NUMERIC;
+ s->minute = DTF_MINUTE_NUMERIC;
+ s->second = DTF_SECOND_NUMERIC;
+ break;
+ case DTF_STYLE_SHORT:
+ s->hour = DTF_HOUR_NUMERIC;
+ s->minute = DTF_MINUTE_NUMERIC;
+ s->second = DTF_SECOND_UNSET;
+ break;
+ }
+ s->timeStyle = DTF_STYLE_UNSET;
+ }
+
+ dtf_clear_non_overlapping_fields(s, val);
+
+ /* Inject defaults after clearing non-overlapping fields, so that options
+ like era on PlainTime don't block time defaults. */
+ if (s->dateStyle == DTF_STYLE_UNSET && s->timeStyle == DTF_STYLE_UNSET) {
+ int has_date = (s->weekday != DTF_WEEKDAY_UNSET || s->year != DTF_YEAR_UNSET ||
+ s->month != DTF_MONTH_UNSET || s->day != DTF_DAY_UNSET);
+ int has_time = (s->dayPeriod != DTF_DAYPERIOD_UNSET || s->hour != DTF_HOUR_UNSET ||
+ s->minute != DTF_MINUTE_UNSET || s->second != DTF_SECOND_UNSET ||
+ s->has_fractionalSecondDigits);
+
+ if (p_pd && !has_date) {
+ s->year = DTF_YEAR_NUMERIC;
+ s->month = DTF_MONTH_NUMERIC;
+ s->day = DTF_DAY_NUMERIC;
+ } else if (p_pym && !has_date) {
+ s->year = DTF_YEAR_NUMERIC;
+ s->month = DTF_MONTH_NUMERIC;
+ } else if (p_pmd && !has_date) {
+ s->month = DTF_MONTH_NUMERIC;
+ s->day = DTF_DAY_NUMERIC;
+ } else if (p_pt && !has_time) {
+ s->hour = DTF_HOUR_NUMERIC;
+ s->minute = DTF_MINUTE_NUMERIC;
+ s->second = DTF_SECOND_NUMERIC;
+ } else if ((p_pdt || p_inst) && !has_time) {
+ if (!has_date ||
+ (s->weekday == DTF_WEEKDAY_UNSET && s->dateStyle == DTF_STYLE_UNSET &&
+ !s->has_year_option && !s->has_month_option && !s->has_day_option)) {
+ s->hour = DTF_HOUR_NUMERIC;
+ s->minute = DTF_MINUTE_NUMERIC;
+ s->second = DTF_SECOND_NUMERIC;
+ }
+ if (!has_date) {
+ s->year = DTF_YEAR_NUMERIC;
+ s->month = DTF_MONTH_NUMERIC;
+ s->day = DTF_DAY_NUMERIC;
+ }
+ }
+
+ if (!s->has_hourCycle && (s->hour != DTF_HOUR_UNSET || s->timeStyle != DTF_STYLE_UNSET)) {
+ const char *p;
+ if (strstart(s->locale, "ja", &p) && (*p == '-' || *p == '\0'))
+ s->hourCycle = 2; /* h23 */
+ else if (strstart(s->locale, "de", &p) && (*p == '-' || *p == '\0'))
+ s->hourCycle = 2; /* h23 */
+ else
+ s->hourCycle = 1; /* h12 */
+ s->has_hourCycle = 1;
+ }
+ }
+}
+
+static int dtf_append_number_part(JSContext *ctx, DynBuf *db, DTFPartInfo **parts, int *n_parts, int *max_parts,
+ const char *type, int n, int width, int numberingSystem)
+{
+ int off = (int)db->size;
+ dtf_append_number(db, n, width, numberingSystem);
+ if (parts)
+ return dtf_record_part(ctx, db, parts, n_parts, max_parts, type, off, (int)db->size - off);
+ return 0;
+}
+
+static JSValue dtf_format_result(JSContext *ctx, DynBuf *db, DTFPartInfo *parts, int n_parts,
+ int want_parts)
+{
+ if (dbuf_error(db)) {
+ dbuf_free(db);
+ js_free(ctx, parts);
+ return JS_EXCEPTION;
+ }
+ if (want_parts) {
+ JSValue arr = JS_NewArray(ctx);
+ int i;
+ if (JS_IsException(arr))
+ goto fail;
+ for (i = 0; i < n_parts; i++) {
+ JSValue obj = JS_NewObject(ctx);
+ if (JS_IsException(obj))
+ goto fail;
+ if (JS_DefinePropertyValueStr(ctx, obj, "type",
+ JS_NewString(ctx, parts[i].type), JS_PROP_C_W_E) < 0) {
+ JS_FreeValue(ctx, obj);
+ goto fail;
+ }
+ if (JS_DefinePropertyValueStr(ctx, obj, "value",
+ JS_NewStringLen(ctx, (char *)db->buf + parts[i].off,
+ (size_t)parts[i].len), JS_PROP_C_W_E) < 0) {
+ JS_FreeValue(ctx, obj);
+ goto fail;
+ }
+ if (JS_DefinePropertyValueUint32(ctx, arr, (uint32_t)i, obj, JS_PROP_C_W_E) < 0)
+ goto fail;
+ }
+ dbuf_free(db);
+ js_free(ctx, parts);
+ return arr;
+ fail:
+ JS_FreeValue(ctx, arr);
+ dbuf_free(db);
+ js_free(ctx, parts);
+ return JS_EXCEPTION;
+ } else {
+ JSValue ret = JS_NewStringLen(ctx, (char *)db->buf, db->size);
+ dbuf_free(db);
+ js_free(ctx, parts);
+ return ret;
+ }
+}
+
+/* Format a date/time using a CLDR pattern string.
+ Handles: y, M, d, E, G, h, H, m, s, a, z and quoted literals.
+ Returns 0 on success, -1 on error. */
+static int dtf_display_hour(int hour, int hourCycle)
+{
+ switch (hourCycle) {
+ case DTF_HOURCYCLE_H11:
+ return hour % 12;
+ case DTF_HOURCYCLE_H12:
+ {
+ int dh = hour % 12;
+ return dh == 0 ? 12 : dh;
+ }
+ case DTF_HOURCYCLE_H23:
+ return hour;
+ case DTF_HOURCYCLE_H24:
+ return hour == 0 ? 24 : hour;
+ default:
+ return hour;
+ }
+}
+
+static const char *dtf_sec_to_offset_str(int offset_sec);
+static const char *dtf_format_offset_timezone(const char *tz, int is_long);
+
+/* Hardcoded long timezone names for embedded zones used by tests */
+static const char *dtf_get_embedded_tz_long_name(const char *tz, int offset_sec)
+{
+ if (!strcmp(tz, "Europe/Vienna")) {
+ if (offset_sec == 3600)
+ return "Central European Standard Time";
+ if (offset_sec == 7200)
+ return "Central European Summer Time";
+ }
+ return NULL;
+}
+
+static int dtf_format_from_pattern(JSContext *ctx, DynBuf *db,
+ const char *pattern, JSDateTimeFormatData *s,
+ const LocaleData *ldata, DTFDateFields *fields,
+ int want_parts, DTFPartInfo **parts, int *n_parts, int *max_parts)
+{
+ const char *p = pattern;
+ int cal_year = fields->year;
+ int cal_month = fields->month + 1;
+ int cal_day = fields->day;
+ ti_iso_to_calendar_date(s->calendar, fields->year, fields->month + 1, fields->day, &cal_year, &cal_month, &cal_day);
+
+ TIEra era = TI_ERA_UNKNOWN;
+ int era_year = cal_year;
+ ti_calendar_era_and_era_year(s->calendar, fields->year, fields->month + 1, fields->day, cal_year, &era, &era_year);
+
+ int relatedYear = fields->year;
+ int lmonth = cal_month;
+ int lday = cal_day;
+ int is_leap_month = 0;
+ if (s->calendar == CAL_CHINESE || s->calendar == CAL_DANGI) {
+ relatedYear = ti_chinese_related_year(s->calendar, fields->year, fields->month + 1, fields->day);
+ ti_calendar_month_to_month_code(s->calendar, cal_year, cal_month, &lmonth, &is_leap_month);
+ lday = cal_day;
+ }
+
+ while (*p) {
+ if (*p == '\'') {
+ /* Quoted literal */
+ p++;
+ if (*p == '\'') {
+ /* '' → single ' */
+ if (dtf_add_literal(ctx, db, want_parts ? parts : NULL, n_parts, max_parts, "'") < 0)
+ return -1;
+ p++;
+ } else {
+ int off = (int)db->size;
+ while (*p && *p != '\'') {
+ dbuf_putc(db, (uint8_t)*p++);
+ }
+ if (want_parts && parts)
+ if (dtf_record_part(ctx, db, parts, n_parts, max_parts, "literal", off, (int)db->size - off) < 0)
+ return -1;
+ if (*p == '\'') p++;
+ }
+ } else if (isalpha((unsigned char)*p)) {
+ char c = *p;
+ int width = 0;
+ while (*p == c) {
+ width++;
+ p++;
+ }
+ switch (c) {
+ case 'y': {
+ int yr = (s->calendar == CAL_CHINESE || s->calendar == CAL_DANGI) ? relatedYear : era_year;
+ int has_era = 0;
+ const char *era_str = NULL;
+ if (width == 2)
+ yr = yr % 100;
+ if (dtf_append_number_part(ctx, db, want_parts ? parts : NULL, n_parts, max_parts,
+ "year", yr, width == 2 ? 2 : 0, s->numberingSystem) < 0)
+ return -1;
+ if (s->era != DTF_ERA_UNSET && s->calendar != CAL_CHINESE && s->calendar != CAL_DANGI) {
+ has_era = get_calendar_era(s->calendar, era,
+ s->era == DTF_ERA_LONG ? 0 :
+ s->era == DTF_ERA_SHORT ? 1 : 2,
+ ldata, &era_str);
+ if (has_era && era_str) {
+ if (dtf_add_literal(ctx, db, want_parts ? parts : NULL, n_parts, max_parts, " ") < 0)
+ return -1;
+ if (dtf_record_part(ctx, db, want_parts ? parts : NULL, n_parts, max_parts,
+ "era", (int)db->size, (int)strlen(era_str)) < 0)
+ return -1;
+ dbuf_putstr(db, era_str);
+ }
+ }
+ break;
+ }
+ case 'M': {
+ int month_val = (s->calendar == CAL_CHINESE || s->calendar == CAL_DANGI) ? lmonth : cal_month;
+ const char *cal_name = get_calendar_month_name(s->calendar, s->locale, cal_year, cal_month, width);
+ if (cal_name) {
+ if (dtf_record_part(ctx, db, want_parts ? parts : NULL, n_parts, max_parts,
+ "month", (int)db->size, (int)strlen(cal_name)) < 0)
+ return -1;
+ dbuf_putstr(db, cal_name);
+ } else if (width <= 2) {
+ if (dtf_append_number_part(ctx, db, want_parts ? parts : NULL, n_parts, max_parts,
+ "month", month_val, width == 2 ? 2 : 0, s->numberingSystem) < 0)
+ return -1;
+ if ((s->calendar == CAL_CHINESE || s->calendar == CAL_DANGI) && is_leap_month) {
+ dbuf_putc(db, 'L');
+ if (want_parts && parts && *n_parts > 0)
+ (*parts)[*n_parts - 1].len++;
+ }
+ } else if (width == 3) {
+ const char *name = LD_MONTH_SHORT(ldata, fields->month);
+ if (dtf_record_part(ctx, db, want_parts ? parts : NULL, n_parts, max_parts,
+ "month", (int)db->size, (int)strlen(name)) < 0)
+ return -1;
+ dbuf_putstr(db, name);
+ } else {
+ const char *name = LD_MONTH_LONG(ldata, fields->month);
+ if (dtf_record_part(ctx, db, want_parts ? parts : NULL, n_parts, max_parts,
+ "month", (int)db->size, (int)strlen(name)) < 0)
+ return -1;
+ dbuf_putstr(db, name);
+ }
+ break;
+ }
+ case 'd': {
+ int day_val = (s->calendar == CAL_CHINESE || s->calendar == CAL_DANGI) ? lday : cal_day;
+ if (dtf_append_number_part(ctx, db, want_parts ? parts : NULL, n_parts, max_parts,
+ "day", day_val, width == 2 ? 2 : 0, s->numberingSystem) < 0)
+ return -1;
+ break;
+ }
+ case 'E': {
+ const char *name;
+ if (width <= 3) {
+ /* Short weekday not in our data; fall back to long */
+ name = LD_WEEKDAY_LONG(ldata, fields->weekday);
+ } else if (width == 4) {
+ name = LD_WEEKDAY_LONG(ldata, fields->weekday);
+ } else {
+ name = LD_WEEKDAY_NARROW(ldata, fields->weekday);
+ }
+ if (dtf_record_part(ctx, db, want_parts ? parts : NULL, n_parts, max_parts,
+ "weekday", (int)db->size, (int)strlen(name)) < 0)
+ return -1;
+ dbuf_putstr(db, name);
+ break;
+ }
+ case 'G': {
+ const char *era_str = NULL;
+ int has_era = get_calendar_era(s->calendar, era,
+ width <= 3 ? 1 :
+ width == 4 ? 0 : 2,
+ ldata, &era_str);
+ if (has_era && era_str) {
+ if (dtf_record_part(ctx, db, want_parts ? parts : NULL, n_parts, max_parts,
+ "era", (int)db->size, (int)strlen(era_str)) < 0)
+ return -1;
+ dbuf_putstr(db, era_str);
+ }
+ break;
+ }
+ case 'h':
+ case 'K':
+ case 'H':
+ case 'k': {
+ int dh = dtf_display_hour(fields->hour, s->hourCycle);
+ if (dtf_append_number_part(ctx, db, want_parts ? parts : NULL, n_parts, max_parts,
+ "hour", dh, width == 2 ? 2 : 0, s->numberingSystem) < 0)
+ return -1;
+ break;
+ }
+ case 'm': {
+ if (dtf_append_number_part(ctx, db, want_parts ? parts : NULL, n_parts, max_parts,
+ "minute", fields->minute, width == 2 ? 2 : 0, s->numberingSystem) < 0)
+ return -1;
+ break;
+ }
+ case 's': {
+ if (dtf_append_number_part(ctx, db, want_parts ? parts : NULL, n_parts, max_parts,
+ "second", fields->second, width == 2 ? 2 : 0, s->numberingSystem) < 0)
+ return -1;
+ break;
+ }
+ case 'a':
+ case 'b':
+ case 'B': {
+ int is_12h = (s->hourCycle == DTF_HOURCYCLE_H11 || s->hourCycle == DTF_HOURCYCLE_H12);
+ if (is_12h) {
+ const char *dp;
+ if (c == 'B') {
+ int dp_idx = get_en_dayperiod_idx(fields->hour);
+ dp = LD_DAYPERIOD(ldata, dp_idx);
+ } else {
+ dp = LD_AMPM(ldata, fields->hour < 12 ? 0 : 1);
+ }
+ if (dtf_record_part(ctx, db, want_parts ? parts : NULL, n_parts, max_parts,
+ "dayPeriod", (int)db->size, (int)strlen(dp)) < 0)
+ return -1;
+ dbuf_putstr(db, dp);
+ } else {
+ /* Suppress dayPeriod and remove preceding space/U+202F if present */
+ if (db->size >= 1 && db->buf[db->size - 1] == ' ') {
+ db->size -= 1;
+ if (want_parts && parts && *n_parts > 0) {
+ if ((size_t)((*parts)[*n_parts - 1].off + (*parts)[*n_parts - 1].len) == db->size + 1)
+ (*n_parts)--;
+ }
+ } else if (db->size >= 3 &&
+ db->buf[db->size - 3] == 0xE2 &&
+ db->buf[db->size - 2] == 0x80 &&
+ db->buf[db->size - 1] == 0xAF) {
+ db->size -= 3;
+ if (want_parts && parts && *n_parts > 0) {
+ if ((size_t)((*parts)[*n_parts - 1].off + (*parts)[*n_parts - 1].len) == db->size + 3)
+ (*n_parts)--;
+ }
+ }
+ }
+ break;
+ }
+ case 'z':
+ case 'Z':
+ case 'v':
+ case 'V': {
+ /* Timezone formatting */
+ const char *tz_name = NULL;
+ const char *tz_type = "timeZoneName";
+ if (!strcmp(s->timeZone, "UTC") || !strcmp(s->timeZone, "GMT") ||
+ !strcmp(s->timeZone, "Etc/UTC") || !strcmp(s->timeZone, "Etc/GMT")) {
+ if (width >= 4)
+ tz_name = "Coordinated Universal Time";
+ else
+ tz_name = "UTC";
+ } else if (s->timeZone[0] == '+' || s->timeZone[0] == '-') {
+ tz_name = s->timeZone;
+ } else {
+ int tz_id = ti_tz_find_id(s->timeZone);
+ if (tz_id >= 0) {
+ int offset_sec = ti_tz_offset_at_sec(tz_id, fields->epoch_sec);
+ if (width >= 4) {
+ tz_name = dtf_get_embedded_tz_long_name(s->timeZone, offset_sec);
+ if (!tz_name) {
+ const char *offset_str = dtf_sec_to_offset_str(offset_sec);
+ tz_name = dtf_format_offset_timezone(offset_str, 1);
+ }
+ } else {
+ const char *offset_str = dtf_sec_to_offset_str(offset_sec);
+ tz_name = dtf_format_offset_timezone(offset_str, 0);
+ }
+ } else {
+ tz_name = s->timeZone;
+ }
+ }
+ if (tz_name) {
+ if (dtf_record_part(ctx, db, want_parts ? parts : NULL, n_parts, max_parts,
+ tz_type, (int)db->size, (int)strlen(tz_name)) < 0)
+ return -1;
+ dbuf_putstr(db, tz_name);
+ }
+ break;
+ }
+ default:
+ /* Unknown field symbol: treat as literal */
+ {
+ int off = (int)db->size;
+ int i;
+ for (i = 0; i < width; i++)
+ dbuf_putc(db, (uint8_t)c);
+ if (want_parts && parts)
+ if (dtf_record_part(ctx, db, parts, n_parts, max_parts, "literal", off, (int)db->size - off) < 0)
+ return -1;
+ }
+ break;
+ }
+ } else {
+ /* Literal character - handle multi-byte UTF-8 sequences */
+ const char *start = p;
+ unsigned char c = (unsigned char)*p++;
+ if (c >= 0x80) {
+ int nextra;
+ if (c < 0xC0)
+ nextra = 0;
+ else if (c < 0xE0)
+ nextra = 1;
+ else if (c < 0xF0)
+ nextra = 2;
+ else
+ nextra = 3;
+ while (nextra-- > 0 && (*p & 0xC0) == 0x80)
+ p++;
+ }
+ {
+ int off = (int)db->size;
+ int len = (int)(p - start);
+ dbuf_put(db, (uint8_t *)start, (size_t)len);
+ if (want_parts && parts)
+ if (dtf_record_part(ctx, db, parts, n_parts, max_parts, "literal", off, len) < 0)
+ return -1;
+ }
+ }
+ }
+ return 0;
+}
+
+/* Sub-format helper for combined date+time formatting */
+typedef struct {
+ DynBuf db;
+ DTFPartInfo *parts;
+ int n_parts;
+ int max_parts;
+} DTFSubFormat;
+
+static void dtf_subformat_init(JSContext *ctx, DTFSubFormat *sub)
+{
+ js_intl_dbuf_init(ctx, &sub->db);
+ sub->parts = NULL;
+ sub->n_parts = 0;
+ sub->max_parts = 0;
+}
+
+static void dtf_subformat_free(JSContext *ctx, DTFSubFormat *sub)
+{
+ dbuf_free(&sub->db);
+ js_free(ctx, sub->parts);
+}
+
+static int dtf_merge_subformat(JSContext *ctx, DynBuf *db, DTFPartInfo **parts, int *n_parts, int *max_parts,
+ DTFSubFormat *sub)
+{
+ int base_off = (int)db->size;
+ int i;
+ dbuf_put(db, sub->db.buf, sub->db.size);
+ if (dbuf_error(db)) return -1;
+ for (i = 0; i < sub->n_parts; i++) {
+ if (dtf_record_part(ctx, db, parts, n_parts, max_parts,
+ sub->parts[i].type, base_off + sub->parts[i].off, sub->parts[i].len) < 0)
+ return -1;
+ }
+ return 0;
+}
+
+/* Format date and time using a combined CLDR pattern like "{1}, {0}".
+ {1} is replaced by the date sub-format, {0} by the time sub-format. */
+static int dtf_format_combined(JSContext *ctx, DynBuf *db,
+ const char *pattern, JSDateTimeFormatData *s,
+ const LocaleData *ldata, DTFDateFields *fields,
+ int want_parts, DTFPartInfo **parts, int *n_parts, int *max_parts,
+ DTFSubFormat *date_sub, DTFSubFormat *time_sub)
+{
+ const char *p = pattern;
+ while (*p) {
+ if (*p == '\'') {
+ p++;
+ if (*p == '\'') {
+ if (dtf_add_literal(ctx, db, want_parts ? parts : NULL, n_parts, max_parts, "'") < 0)
+ return -1;
+ p++;
+ } else {
+ int off = (int)db->size;
+ while (*p && *p != '\'') {
+ dbuf_putc(db, (uint8_t)*p++);
+ }
+ if (want_parts && parts)
+ if (dtf_record_part(ctx, db, parts, n_parts, max_parts, "literal", off, (int)db->size - off) < 0)
+ return -1;
+ if (*p == '\'') p++;
+ }
+ } else if (p[0] == '{' && (p[1] == '0' || p[1] == '1') && p[2] == '}') {
+ if (p[1] == '0') {
+ if (dtf_merge_subformat(ctx, db, want_parts ? parts : NULL, n_parts, max_parts, time_sub) < 0)
+ return -1;
+ } else {
+ if (dtf_merge_subformat(ctx, db, want_parts ? parts : NULL, n_parts, max_parts, date_sub) < 0)
+ return -1;
+ }
+ p += 3;
+ } else {
+ /* Literal - handle multi-byte UTF-8 sequences */
+ const char *start = p;
+ unsigned char c = (unsigned char)*p++;
+ if (c >= 0x80) {
+ int nextra;
+ if (c < 0xC0)
+ nextra = 0;
+ else if (c < 0xE0)
+ nextra = 1;
+ else if (c < 0xF0)
+ nextra = 2;
+ else
+ nextra = 3;
+ while (nextra-- > 0 && (*p & 0xC0) == 0x80)
+ p++;
+ }
+ {
+ int off = (int)db->size;
+ int len = (int)(p - start);
+ dbuf_put(db, (uint8_t *)start, (size_t)len);
+ if (want_parts && parts)
+ if (dtf_record_part(ctx, db, parts, n_parts, max_parts, "literal", off, len) < 0)
+ return -1;
+ }
+ }
+ }
+ return 0;
+}
+
+/* Convert an offset in seconds to a string like +HH:MM */
+static const char *dtf_sec_to_offset_str(int offset_sec)
+{
+ static char buf[16];
+ int abs_sec = offset_sec < 0 ? -offset_sec : offset_sec;
+ int hour = abs_sec / 3600;
+ int minute = (abs_sec % 3600) / 60;
+ char sign = offset_sec < 0 ? '-' : '+';
+ snprintf(buf, sizeof(buf), "%c%02d:%02d", sign, hour, minute);
+ return buf;
+}
+
+/* Format an offset time zone (e.g. +01:00) into a display string.
+ For short names, zero offset becomes "GMT", non-zero becomes "GMT±H" or "GMT±H:MM".
+ Returns a pointer to a static buffer. */
+static const char *dtf_format_offset_timezone(const char *tz, int is_long)
+{
+ static char buf[32];
+ int hour, minute;
+ char sign;
+ if (tz[0] != '+' && tz[0] != '-')
+ return tz;
+ if (tz[1] < '0' || tz[1] > '9' || tz[2] < '0' || tz[2] > '9' ||
+ tz[3] != ':' || tz[4] < '0' || tz[4] > '9' || tz[5] < '0' || tz[5] > '9' || tz[6] != '\0')
+ return tz;
+ sign = tz[0];
+ hour = (tz[1] - '0') * 10 + (tz[2] - '0');
+ minute = (tz[4] - '0') * 10 + (tz[5] - '0');
+ if (hour == 0 && minute == 0) {
+ snprintf(buf, sizeof(buf), "GMT");
+ } else if (is_long) {
+ snprintf(buf, sizeof(buf), "GMT%c%02d:%02d", sign, hour, minute);
+ } else if (minute == 0) {
+ snprintf(buf, sizeof(buf), "GMT%c%d", sign, hour);
+ } else {
+ snprintf(buf, sizeof(buf), "GMT%c%d:%02d", sign, hour, minute);
+ }
+ return buf;
+}
+
+static JSValue dtf_format_date(JSContext *ctx, JSDateTimeFormatData *s, double ms, int want_parts)
+{
+ DTFDateFields fields;
+ DynBuf db;
+ DTFPartInfo *parts = NULL;
+ int n_parts = 0, max_parts = 0;
+ int has_date, has_time;
+ int weekday_opt, year_opt, month_opt, day_opt;
+ int hour_opt, minute_opt, second_opt, tzname_opt;
+ int display_hour, dayperiod_idx;
+ int hour_width, minute_width, second_width;
+ int has_hour, has_minute, has_second;
+ int has_dayperiod;
+ int time_field_count;
+ const char *dayperiod_str = NULL;
+
+ const LocaleData *ldata = js_intl_find_locale_data(s->locale);
+
+ js_intl_dbuf_init(ctx, &db);
+
+ dtf_extract_fields(ms, s->timeZone, &fields);
+
+ dtf_expand_styles(s, &weekday_opt, &year_opt, &month_opt, &day_opt,
+ &hour_opt, &minute_opt, &second_opt, &tzname_opt);
+
+ has_date = (weekday_opt != DTF_WEEKDAY_UNSET || year_opt != DTF_YEAR_UNSET ||
+ month_opt != DTF_MONTH_UNSET || day_opt != DTF_DAY_UNSET);
+ has_time = (hour_opt != DTF_HOUR_UNSET || minute_opt != DTF_MINUTE_UNSET ||
+ second_opt != DTF_SECOND_UNSET);
+ has_hour = (hour_opt != DTF_HOUR_UNSET);
+ has_minute = (minute_opt != DTF_MINUTE_UNSET);
+ has_second = (second_opt != DTF_SECOND_UNSET);
+ has_dayperiod = (s->dayPeriod != DTF_DAYPERIOD_UNSET);
+
+ {
+ int is_24h = (s->hourCycle == DTF_HOURCYCLE_H23 || s->hourCycle == DTF_HOURCYCLE_H24);
+ hour_width = (hour_opt == DTF_HOUR_2DIGIT || (is_24h && (has_minute || has_second))) ? 2 : 0;
+ }
+ minute_width = (has_minute && (has_hour || has_second)) ? 2 : ((minute_opt == DTF_MINUTE_2DIGIT) ? 2 : 0);
+ second_width = (has_second && has_minute) ? 2 : ((second_opt == DTF_SECOND_2DIGIT) ? 2 : 0);
+
+ display_hour = fields.hour;
+ dayperiod_idx = -1;
+ if (has_hour && (s->hourCycle == DTF_HOURCYCLE_H11 || s->hourCycle == DTF_HOURCYCLE_H12)) {
+ if (fields.hour < 12)
+ dayperiod_idx = 0;
+ else
+ dayperiod_idx = 1;
+ if (s->hourCycle == DTF_HOURCYCLE_H11) {
+ display_hour = fields.hour % 12;
+ } else {
+ display_hour = fields.hour % 12;
+ if (display_hour == 0)
+ display_hour = 12;
+ }
+ } else if (s->hourCycle == DTF_HOURCYCLE_H24) {
+ if (display_hour == 0)
+ display_hour = 24;
+ }
+
+ int cal_year2 = fields.year;
+ int cal_month2 = fields.month + 1;
+ int cal_day2 = fields.day;
+ ti_iso_to_calendar_date(s->calendar, fields.year, fields.month + 1, fields.day, &cal_year2, &cal_month2, &cal_day2);
+
+ TIEra era2 = TI_ERA_UNKNOWN;
+ int era_year2 = cal_year2;
+ ti_calendar_era_and_era_year(s->calendar, fields.year, fields.month + 1, fields.day, cal_year2, &era2, &era_year2);
+
+ if (has_dayperiod) {
+ int dp_idx = get_en_dayperiod_idx(fields.hour);
+ if (s->dayPeriod == DTF_DAYPERIOD_NARROW)
+ dayperiod_str = LD_DAYPERIOD_NARROW(ldata, dp_idx);
+ else
+ dayperiod_str = LD_DAYPERIOD(ldata, dp_idx);
+ }
+
+ /* Date part */
+ if (has_date) {
+ int relatedYear2 = fields.year;
+ int lmonth2 = cal_month2;
+ int lday2 = cal_day2;
+ int is_leap_month2 = 0;
+ if (s->calendar == CAL_CHINESE || s->calendar == CAL_DANGI) {
+ relatedYear2 = ti_chinese_related_year(s->calendar, fields.year, fields.month + 1, fields.day);
+ ti_calendar_month_to_month_code(s->calendar, cal_year2, cal_month2, &lmonth2, &is_leap_month2);
+ lday2 = cal_day2;
+ }
+
+ /* Use locale-specific date pattern when dateStyle is set */
+ if (s->dateStyle != DTF_STYLE_UNSET && s->timeStyle != DTF_STYLE_UNSET) {
+ /* Combined date+time formatting */
+ DTFSubFormat date_sub, time_sub;
+ const char *date_pattern = NULL;
+ const char *time_pattern = NULL;
+ const char *combined_pattern = NULL;
+ switch (s->dateStyle) {
+ case DTF_STYLE_SHORT:
+ date_pattern = date_pattern_tab[ldata->datePatternShort_idx];
+ combined_pattern = combined_pattern_tab[ldata->combinedPatternShort_idx];
+ break;
+ case DTF_STYLE_MEDIUM:
+ date_pattern = date_pattern_tab[ldata->datePatternMedium_idx];
+ combined_pattern = combined_pattern_tab[ldata->combinedPatternMedium_idx];
+ break;
+ case DTF_STYLE_LONG:
+ date_pattern = date_pattern_tab[ldata->datePatternLong_idx];
+ combined_pattern = combined_pattern_tab[ldata->combinedPatternLong_idx];
+ break;
+ case DTF_STYLE_FULL:
+ date_pattern = date_pattern_tab[ldata->datePatternFull_idx];
+ combined_pattern = combined_pattern_tab[ldata->combinedPatternFull_idx];
+ break;
+ }
+ switch (s->timeStyle) {
+ case DTF_STYLE_SHORT:
+ time_pattern = time_pattern_tab[ldata->timePatternShort_idx];
+ break;
+ case DTF_STYLE_MEDIUM:
+ time_pattern = time_pattern_tab[ldata->timePatternMedium_idx];
+ break;
+ case DTF_STYLE_LONG:
+ time_pattern = time_pattern_tab[ldata->timePatternLong_idx];
+ break;
+ case DTF_STYLE_FULL:
+ time_pattern = time_pattern_tab[ldata->timePatternFull_idx];
+ break;
+ }
+ dtf_subformat_init(ctx, &date_sub);
+ if (date_pattern && *date_pattern) {
+ if (dtf_format_from_pattern(ctx, &date_sub.db, date_pattern, s, ldata, &fields,
+ want_parts, want_parts ? &date_sub.parts : NULL, &date_sub.n_parts, &date_sub.max_parts) < 0) {
+ dtf_subformat_free(ctx, &date_sub);
+ goto fail;
+ }
+ }
+ dtf_subformat_init(ctx, &time_sub);
+ if (time_pattern && *time_pattern) {
+ if (dtf_format_from_pattern(ctx, &time_sub.db, time_pattern, s, ldata, &fields,
+ want_parts, want_parts ? &time_sub.parts : NULL, &time_sub.n_parts, &time_sub.max_parts) < 0) {
+ dtf_subformat_free(ctx, &date_sub);
+ dtf_subformat_free(ctx, &time_sub);
+ goto fail;
+ }
+ }
+ if (combined_pattern && *combined_pattern) {
+ if (dtf_format_combined(ctx, &db, combined_pattern, s, ldata, &fields,
+ want_parts, want_parts ? &parts : NULL, &n_parts, &max_parts,
+ &date_sub, &time_sub) < 0) {
+ dtf_subformat_free(ctx, &date_sub);
+ dtf_subformat_free(ctx, &time_sub);
+ goto fail;
+ }
+ }
+ dtf_subformat_free(ctx, &date_sub);
+ dtf_subformat_free(ctx, &time_sub);
+ } else if (s->dateStyle != DTF_STYLE_UNSET) {
+ const char *pattern = NULL;
+ switch (s->dateStyle) {
+ case DTF_STYLE_SHORT:
+ pattern = date_pattern_tab[ldata->datePatternShort_idx];
+ break;
+ case DTF_STYLE_MEDIUM:
+ pattern = date_pattern_tab[ldata->datePatternMedium_idx];
+ break;
+ case DTF_STYLE_LONG:
+ pattern = date_pattern_tab[ldata->datePatternLong_idx];
+ break;
+ case DTF_STYLE_FULL:
+ pattern = date_pattern_tab[ldata->datePatternFull_idx];
+ break;
+ }
+ if (pattern && *pattern) {
+ if (dtf_format_from_pattern(ctx, &db, pattern, s, ldata, &fields,
+ want_parts, want_parts ? &parts : NULL, &n_parts, &max_parts) < 0)
+ goto fail;
+ }
+ } else {
+ if (weekday_opt == DTF_WEEKDAY_LONG) {
+ const char *name = LD_WEEKDAY_LONG(ldata, fields.weekday);
+ if (dtf_record_part(ctx, &db, want_parts ? &parts : NULL, &n_parts, &max_parts,
+ "weekday", (int)db.size, (int)strlen(name)) < 0)
+ goto fail;
+ dbuf_putstr(&db, name);
+ if (month_opt != DTF_MONTH_UNSET || day_opt != DTF_DAY_UNSET || year_opt != DTF_YEAR_UNSET) {
+ if (dtf_add_literal(ctx, &db, want_parts ? &parts : NULL, &n_parts, &max_parts, ", ") < 0)
+ goto fail;
+ }
+ } else if (weekday_opt == DTF_WEEKDAY_SHORT) {
+ const char *name = LD_WEEKDAY_LONG(ldata, fields.weekday);
+ int name_len = (int)strlen(name);
+ if (name_len > 3)
+ name_len = 3;
+ if (dtf_record_part(ctx, &db, want_parts ? &parts : NULL, &n_parts, &max_parts,
+ "weekday", (int)db.size, name_len) < 0)
+ goto fail;
+ dbuf_put(&db, (uint8_t *)name, (size_t)name_len);
+ if (month_opt != DTF_MONTH_UNSET || day_opt != DTF_DAY_UNSET || year_opt != DTF_YEAR_UNSET) {
+ if (dtf_add_literal(ctx, &db, want_parts ? &parts : NULL, &n_parts, &max_parts, ", ") < 0)
+ goto fail;
+ }
+ } else if (weekday_opt == DTF_WEEKDAY_NARROW) {
+ const char *name = LD_WEEKDAY_NARROW(ldata, fields.weekday);
+ if (dtf_record_part(ctx, &db, want_parts ? &parts : NULL, &n_parts, &max_parts,
+ "weekday", (int)db.size, (int)strlen(name)) < 0)
+ goto fail;
+ dbuf_putstr(&db, name);
+ if (month_opt != DTF_MONTH_UNSET || day_opt != DTF_DAY_UNSET || year_opt != DTF_YEAR_UNSET) {
+ if (dtf_add_literal(ctx, &db, want_parts ? &parts : NULL, &n_parts, &max_parts, ", ") < 0)
+ goto fail;
+ }
+ }
+
+ if (month_opt != DTF_MONTH_UNSET) {
+ int month_width = (month_opt == DTF_MONTH_LONG) ? 4 :
+ (month_opt == DTF_MONTH_SHORT) ? 3 :
+ (month_opt == DTF_MONTH_NARROW) ? 5 : 1;
+ const char *cal_name = get_calendar_month_name(s->calendar, s->locale, cal_year2, cal_month2, month_width);
+ if (cal_name) {
+ if (dtf_record_part(ctx, &db, want_parts ? &parts : NULL, &n_parts, &max_parts,
+ "month", (int)db.size, (int)strlen(cal_name)) < 0)
+ goto fail;
+ dbuf_putstr(&db, cal_name);
+ } else if (month_opt == DTF_MONTH_LONG) {
+ const char *name = LD_MONTH_LONG(ldata, fields.month);
+ if (dtf_record_part(ctx, &db, want_parts ? &parts : NULL, &n_parts, &max_parts,
+ "month", (int)db.size, (int)strlen(name)) < 0)
+ goto fail;
+ dbuf_putstr(&db, name);
+ } else if (month_opt == DTF_MONTH_SHORT) {
+ const char *name = LD_MONTH_SHORT(ldata, fields.month);
+ if (dtf_record_part(ctx, &db, want_parts ? &parts : NULL, &n_parts, &max_parts,
+ "month", (int)db.size, (int)strlen(name)) < 0)
+ goto fail;
+ dbuf_putstr(&db, name);
+ } else if (month_opt == DTF_MONTH_NARROW) {
+ const char *name = LD_MONTH_NARROW(ldata, fields.month);
+ if (dtf_record_part(ctx, &db, want_parts ? &parts : NULL, &n_parts, &max_parts,
+ "month", (int)db.size, (int)strlen(name)) < 0)
+ goto fail;
+ dbuf_putstr(&db, name);
+ } else {
+ int width = (month_opt == DTF_MONTH_2DIGIT) ? 2 : 0;
+ int month_val = (s->calendar == CAL_CHINESE || s->calendar == CAL_DANGI) ? lmonth2 : cal_month2;
+ if (dtf_append_number_part(ctx, &db, want_parts ? &parts : NULL, &n_parts, &max_parts,
+ "month", month_val, width, s->numberingSystem) < 0)
+ goto fail;
+ if ((s->calendar == CAL_CHINESE || s->calendar == CAL_DANGI) && is_leap_month2) {
+ dbuf_putc(&db, 'L');
+ if (want_parts && parts && n_parts > 0)
+ parts[n_parts - 1].len++;
+ }
+ }
+
+ int is_en_numeric_month = (strstart(s->locale, "en", NULL) &&
+ month_opt != DTF_MONTH_UNSET &&
+ month_opt != DTF_MONTH_LONG &&
+ month_opt != DTF_MONTH_SHORT);
+ if (day_opt != DTF_DAY_UNSET) {
+ if (s->dateStyle == DTF_STYLE_SHORT || is_en_numeric_month) {
+ if (dtf_add_literal(ctx, &db, want_parts ? &parts : NULL, &n_parts, &max_parts, "/") < 0)
+ goto fail;
+ } else {
+ if (dtf_add_literal(ctx, &db, want_parts ? &parts : NULL, &n_parts, &max_parts, " ") < 0)
+ goto fail;
+ }
+ } else if (year_opt != DTF_YEAR_UNSET) {
+ if (is_en_numeric_month) {
+ if (dtf_add_literal(ctx, &db, want_parts ? &parts : NULL, &n_parts, &max_parts, "/") < 0)
+ goto fail;
+ } else {
+ if (dtf_add_literal(ctx, &db, want_parts ? &parts : NULL, &n_parts, &max_parts, " ") < 0)
+ goto fail;
+ }
+ }
+ }
+
+ if (day_opt != DTF_DAY_UNSET) {
+ int width = (day_opt == DTF_DAY_2DIGIT) ? 2 : 0;
+ int day_val = (s->calendar == CAL_CHINESE || s->calendar == CAL_DANGI) ? lday2 : cal_day2;
+ if (dtf_append_number_part(ctx, &db, want_parts ? &parts : NULL, &n_parts, &max_parts,
+ "day", day_val, width, s->numberingSystem) < 0)
+ goto fail;
+
+ if (year_opt != DTF_YEAR_UNSET) {
+ int is_en_slashed_date = (strstart(s->locale, "en", NULL) &&
+ month_opt != DTF_MONTH_UNSET &&
+ month_opt != DTF_MONTH_LONG &&
+ month_opt != DTF_MONTH_SHORT &&
+ day_opt != DTF_DAY_UNSET);
+ const char *day_year_sep = (s->dateStyle == DTF_STYLE_SHORT || is_en_slashed_date) ? "/" : ", ";
+ if (dtf_add_literal(ctx, &db, want_parts ? &parts : NULL, &n_parts, &max_parts, day_year_sep) < 0)
+ goto fail;
+ }
+ }
+
+ if (year_opt != DTF_YEAR_UNSET) {
+ int width = (year_opt == DTF_YEAR_2DIGIT) ? 2 : 0;
+ int yr = (s->calendar == CAL_CHINESE || s->calendar == CAL_DANGI) ? relatedYear2 : era_year2;
+ int has_era = 0;
+ const char *era_str = NULL;
+
+ if (s->era != DTF_ERA_UNSET && s->calendar != CAL_CHINESE && s->calendar != CAL_DANGI) {
+ has_era = get_calendar_era(s->calendar, era2,
+ s->era == DTF_ERA_LONG ? 0 :
+ s->era == DTF_ERA_SHORT ? 1 : 2,
+ ldata, &era_str);
+ }
+ if (width == 2)
+ yr = yr % 100;
+
+ if (s->calendar != CAL_CHINESE && s->calendar != CAL_DANGI) {
+ if (dtf_append_number_part(ctx, &db, want_parts ? &parts : NULL, &n_parts, &max_parts,
+ "year", yr, width, s->numberingSystem) < 0)
+ goto fail;
+
+ if (has_era && era_str) {
+ if (dtf_add_literal(ctx, &db, want_parts ? &parts : NULL, &n_parts, &max_parts, " ") < 0)
+ goto fail;
+ if (dtf_record_part(ctx, &db, want_parts ? &parts : NULL, &n_parts, &max_parts,
+ "era", (int)db.size, (int)strlen(era_str)) < 0)
+ goto fail;
+ dbuf_putstr(&db, era_str);
+ }
+ }
+ }
+
+ /* Chinese and Dangi calendar stubs: add relatedYear and yearName */
+ if ((s->calendar == CAL_CHINESE || s->calendar == CAL_DANGI) && year_opt != DTF_YEAR_UNSET) {
+ if (strstart(s->locale, "zh", NULL)) {
+ /* zh locale: yearName + literal("年") */
+ const char *year_name = NULL;
+ if (relatedYear2 == 2019)
+ year_name = "\u5df1\u4ea5"; /* 己亥 */
+ else
+ year_name = "Year";
+ if (dtf_record_part(ctx, &db, want_parts ? &parts : NULL, &n_parts, &max_parts,
+ "yearName", (int)db.size, (int)strlen(year_name)) < 0)
+ goto fail;
+ dbuf_putstr(&db, year_name);
+ if (dtf_add_literal(ctx, &db, want_parts ? &parts : NULL, &n_parts, &max_parts, "\u5e74") < 0)
+ goto fail;
+ } else {
+ if (dtf_append_number_part(ctx, &db, want_parts ? &parts : NULL, &n_parts, &max_parts,
+ "relatedYear", relatedYear2, 0, s->numberingSystem) < 0)
+ goto fail;
+ {
+ const char *year_name = "Year";
+ if (dtf_record_part(ctx, &db, want_parts ? &parts : NULL, &n_parts, &max_parts,
+ "yearName", (int)db.size, (int)strlen(year_name)) < 0)
+ goto fail;
+ dbuf_putstr(&db, year_name);
+ }
+ }
+ }
+ }
+ }
+
+ /* Connector between date and time */
+ if (has_date && has_time) {
+ if (s->dateStyle == DTF_STYLE_UNSET || s->timeStyle == DTF_STYLE_UNSET) {
+ if (dtf_add_literal(ctx, &db, want_parts ? &parts : NULL, &n_parts, &max_parts, ", ") < 0)
+ goto fail;
+ }
+ }
+
+ /* Time part */
+ if (has_time && (s->dateStyle == DTF_STYLE_UNSET || s->timeStyle == DTF_STYLE_UNSET)) {
+ if (s->timeStyle != DTF_STYLE_UNSET) {
+ const char *pattern = NULL;
+ switch (s->timeStyle) {
+ case DTF_STYLE_SHORT:
+ pattern = time_pattern_tab[ldata->timePatternShort_idx];
+ break;
+ case DTF_STYLE_MEDIUM:
+ pattern = time_pattern_tab[ldata->timePatternMedium_idx];
+ break;
+ case DTF_STYLE_LONG:
+ pattern = time_pattern_tab[ldata->timePatternLong_idx];
+ break;
+ case DTF_STYLE_FULL:
+ pattern = time_pattern_tab[ldata->timePatternFull_idx];
+ break;
+ }
+ if (pattern && *pattern) {
+ if (dtf_format_from_pattern(ctx, &db, pattern, s, ldata, &fields,
+ want_parts, want_parts ? &parts : NULL, &n_parts, &max_parts) < 0)
+ goto fail;
+ }
+ } else {
+ time_field_count = 0;
+
+ if (has_hour) {
+ if (dtf_append_number_part(ctx, &db, want_parts ? &parts : NULL, &n_parts, &max_parts,
+ "hour", display_hour, hour_width, s->numberingSystem) < 0)
+ goto fail;
+ time_field_count++;
+ }
+
+ if (has_minute) {
+ if (time_field_count > 0) {
+ if (dtf_add_literal(ctx, &db, want_parts ? &parts : NULL, &n_parts, &max_parts, ":") < 0)
+ goto fail;
+ }
+ if (dtf_append_number_part(ctx, &db, want_parts ? &parts : NULL, &n_parts, &max_parts,
+ "minute", fields.minute, minute_width, s->numberingSystem) < 0)
+ goto fail;
+ time_field_count++;
+ }
+
+ if (has_second) {
+ if (time_field_count > 0) {
+ if (dtf_add_literal(ctx, &db, want_parts ? &parts : NULL, &n_parts, &max_parts, ":") < 0)
+ goto fail;
+ }
+ if (dtf_append_number_part(ctx, &db, want_parts ? &parts : NULL, &n_parts, &max_parts,
+ "second", fields.second, second_width, s->numberingSystem) < 0)
+ goto fail;
+ time_field_count++;
+
+ if (s->has_fractionalSecondDigits && s->fractionalSecondDigits > 0) {
+ const char *sep = ".";
+ if (s->numberingSystem == NS_ARAB)
+ sep = "\xD9\xAB";
+ if (dtf_add_literal(ctx, &db, want_parts ? &parts : NULL, &n_parts, &max_parts, sep) < 0)
+ goto fail;
+ {
+ int fsd = s->fractionalSecondDigits;
+ int frac_val = fields.ms;
+ if (fsd == 1)
+ frac_val = frac_val / 100;
+ else if (fsd == 2)
+ frac_val = frac_val / 10;
+ if (dtf_append_number_part(ctx, &db, want_parts ? &parts : NULL, &n_parts, &max_parts,
+ "fractionalSecond", frac_val, fsd, s->numberingSystem) < 0)
+ goto fail;
+ }
+ }
+ }
+
+ if (has_dayperiod) {
+ if (time_field_count > 0) {
+ const char *dp_sep = dtf_get_dayperiod_separator(s->locale);
+ if (dtf_add_literal(ctx, &db, want_parts ? &parts : NULL, &n_parts, &max_parts, dp_sep) < 0)
+ goto fail;
+ }
+ if (dtf_record_part(ctx, &db, want_parts ? &parts : NULL, &n_parts, &max_parts,
+ "dayPeriod", (int)db.size, (int)strlen(dayperiod_str)) < 0)
+ goto fail;
+ dbuf_putstr(&db, dayperiod_str);
+ } else if (dayperiod_idx >= 0) {
+ const char *dp_sep = dtf_get_dayperiod_separator(s->locale);
+ if (dtf_add_literal(ctx, &db, want_parts ? &parts : NULL, &n_parts, &max_parts, dp_sep) < 0)
+ goto fail;
+ {
+ const char *dp = LD_AMPM(ldata, dayperiod_idx);
+ if (dtf_record_part(ctx, &db, want_parts ? &parts : NULL, &n_parts, &max_parts,
+ "dayPeriod", (int)db.size, (int)strlen(dp)) < 0)
+ goto fail;
+ dbuf_putstr(&db, dp);
+ }
+ }
+
+ if (tzname_opt != DTF_TIMEZONE_UNSET) {
+ if (time_field_count > 0 || dayperiod_idx >= 0 || has_dayperiod) {
+ if (dtf_add_literal(ctx, &db, want_parts ? &parts : NULL, &n_parts, &max_parts, " ") < 0)
+ goto fail;
+ }
+ {
+ const char *tz_name = NULL;
+ const char *tz_type = "timeZoneName";
+ if (!strcmp(s->timeZone, "UTC") || !strcmp(s->timeZone, "GMT") ||
+ !strcmp(s->timeZone, "Etc/UTC") || !strcmp(s->timeZone, "Etc/GMT")) {
+ if (tzname_opt == DTF_TIMEZONE_LONG)
+ tz_name = en_tz_utc_long;
+ else
+ tz_name = en_tz_utc_short;
+ } else {
+ int tz_id = ti_tz_find_id(s->timeZone);
+ if (tz_id >= 0) {
+ int offset_sec = ti_tz_offset_at_sec(tz_id, fields.epoch_sec);
+ if (tzname_opt == DTF_TIMEZONE_LONG) {
+ tz_name = dtf_get_embedded_tz_long_name(s->timeZone, offset_sec);
+ if (!tz_name) {
+ const char *offset_str = dtf_sec_to_offset_str(offset_sec);
+ tz_name = dtf_format_offset_timezone(offset_str, 1);
+ }
+ } else {
+ const char *offset_str = dtf_sec_to_offset_str(offset_sec);
+ tz_name = dtf_format_offset_timezone(offset_str, 0);
+ }
+ } else {
+ tz_name = dtf_format_offset_timezone(s->timeZone, tzname_opt == DTF_TIMEZONE_LONG);
+ }
+ }
+ if (tz_name) {
+ if (dtf_record_part(ctx, &db, want_parts ? &parts : NULL, &n_parts, &max_parts,
+ tz_type, (int)db.size, (int)strlen(tz_name)) < 0)
+ goto fail;
+ dbuf_putstr(&db, tz_name);
+ }
+ }
+ }
+ }
+ }
+
+ /* Time zone name for date-only or standalone */
+ if (!has_time && tzname_opt != DTF_TIMEZONE_UNSET) {
+ if (has_date) {
+ if (dtf_add_literal(ctx, &db, want_parts ? &parts : NULL, &n_parts, &max_parts, ", ") < 0)
+ goto fail;
+ }
+ {
+ const char *tz_name = NULL;
+ const char *tz_type = "timeZoneName";
+ if (!strcmp(s->timeZone, "UTC") || !strcmp(s->timeZone, "GMT") ||
+ !strcmp(s->timeZone, "Etc/UTC") || !strcmp(s->timeZone, "Etc/GMT")) {
+ if (tzname_opt == DTF_TIMEZONE_LONG)
+ tz_name = en_tz_utc_long;
+ else
+ tz_name = en_tz_utc_short;
+ } else {
+ int tz_id = ti_tz_find_id(s->timeZone);
+ if (tz_id >= 0) {
+ int offset_sec = ti_tz_offset_at_sec(tz_id, fields.epoch_sec);
+ if (tzname_opt == DTF_TIMEZONE_LONG) {
+ tz_name = dtf_get_embedded_tz_long_name(s->timeZone, offset_sec);
+ if (!tz_name) {
+ const char *offset_str = dtf_sec_to_offset_str(offset_sec);
+ tz_name = dtf_format_offset_timezone(offset_str, 1);
+ }
+ } else {
+ const char *offset_str = dtf_sec_to_offset_str(offset_sec);
+ tz_name = dtf_format_offset_timezone(offset_str, 0);
+ }
+ } else {
+ tz_name = dtf_format_offset_timezone(s->timeZone, tzname_opt == DTF_TIMEZONE_LONG);
+ }
+ }
+ if (tz_name) {
+ if (dtf_record_part(ctx, &db, want_parts ? &parts : NULL, &n_parts, &max_parts,
+ tz_type, (int)db.size, (int)strlen(tz_name)) < 0)
+ goto fail;
+ dbuf_putstr(&db, tz_name);
+ }
+ }
+ }
+
+ /* Day period only formatting (no date or time fields) */
+ if (has_dayperiod && !has_date && !has_time) {
+ if (dtf_record_part(ctx, &db, want_parts ? &parts : NULL, &n_parts, &max_parts,
+ "dayPeriod", (int)db.size, (int)strlen(dayperiod_str)) < 0)
+ goto fail;
+ dbuf_putstr(&db, dayperiod_str);
+ }
+
+ return dtf_format_result(ctx, &db, parts, n_parts, want_parts);
+
+ fail:
+ dbuf_free(&db);
+ js_free(ctx, parts);
+ return JS_EXCEPTION;
+}
+
+static void js_datetimeformat_finalizer(JSRuntime *rt, JSValue val)
+{
+ JSDateTimeFormatData *s = JS_GetOpaque(val, js_datetimeformat_class_id);
+ if (s) {
+ js_free_rt(rt, s->locale);
+ js_free_rt(rt, s->locale_canonical);
+ js_free_rt(rt, s->timeZone);
+ js_free_rt(rt, s);
+ }
+}
+
+static JSClassDef js_datetimeformat_class = {
+ "DateTimeFormat",
+ .finalizer = js_datetimeformat_finalizer,
+};
+
+/* UnwrapDateTimeFormat: handle fallback symbol for cross-realm objects */
+static JSValue js_datetimeformat_unwrap(JSContext *ctx, JSValueConst this_val)
+{
+ JSDateTimeFormatData *s;
+ JSValue ctor, sym, unwrapped;
+ int is_instance;
+
+ if (!JS_IsObject(this_val))
+ return JS_ThrowTypeError(ctx, "DateTimeFormat object expected");
+
+ s = JS_GetOpaque(this_val, js_datetimeformat_class_id);
+ if (s)
+ return JS_DupValue(ctx, this_val);
+
+ /* No internal slot; check if it's an instance of DateTimeFormat */
+ ctor = JS_GetContextValue(ctx, JS_INTL_CTOR_DATETIMEFORMAT);
+ is_instance = JS_OrdinaryIsInstanceOf(ctx, this_val, ctor);
+ JS_FreeValue(ctx, ctor);
+ if (is_instance < 0)
+ return JS_EXCEPTION;
+ if (!is_instance)
+ return JS_ThrowTypeError(ctx, "DateTimeFormat object expected");
+
+ /* Return the fallback symbol value */
+ sym = JS_GetContextValue(ctx, JS_INTL_FALLBACK_SYMBOL);
+ if (JS_IsException(sym))
+ return sym;
+ {
+ JSAtom sym_atom = JS_ValueToAtom(ctx, sym);
+ unwrapped = JS_GetProperty(ctx, this_val, sym_atom);
+ JS_FreeAtom(ctx, sym_atom);
+ }
+ JS_FreeValue(ctx, sym);
+ return unwrapped;
+}
+
+static JSValue js_datetimeformat_constructor(JSContext *ctx,
+ JSValueConst func_obj,
+ JSValueConst this_val,
+ int argc, JSValueConst *argv,
+ int flags)
+{
+ JSDateTimeFormatData *s;
+ JSValue obj = JS_UNDEFINED;
+ JSValue options = JS_UNDEFINED;
+ JSValueConst new_target;
+ int ret;
+ int is_new;
+
+ is_new = (flags & JS_CALL_FLAG_CONSTRUCTOR) != 0;
+
+ if (is_new) {
+ new_target = this_val;
+ } else {
+ new_target = func_obj;
+ }
+
+ s = js_mallocz(ctx, sizeof(*s));
+ if (!s)
+ return JS_EXCEPTION;
+
+ s->calendar = CAL_GREGORY;
+ s->numberingSystem = NS_LATN;
+ {
+ char tz[TI_TIMEZONE_BUF_SIZE];
+ ti_get_default_timezone(tz, sizeof(tz));
+ s->timeZone = js_strdup(ctx, tz);
+ }
+ s->dateStyle = DTF_STYLE_UNSET;
+ s->timeStyle = DTF_STYLE_UNSET;
+ s->weekday = DTF_WEEKDAY_UNSET;
+ s->era = DTF_ERA_UNSET;
+ s->year = DTF_YEAR_UNSET;
+ s->has_year_option = 0;
+ s->month = DTF_MONTH_UNSET;
+ s->has_month_option = 0;
+ s->day = DTF_DAY_UNSET;
+ s->has_day_option = 0;
+ s->dayPeriod = DTF_DAYPERIOD_UNSET;
+ s->hour = DTF_HOUR_UNSET;
+ s->minute = DTF_MINUTE_UNSET;
+ s->second = DTF_SECOND_UNSET;
+ s->timeZoneName = DTF_TIMEZONE_UNSET;
+ s->formatMatcher = DTF_FORMATMATCHER_UNSET;
+ s->required = 0;
+ s->defaults = 0;
+
+ {
+ char *loc = js_intl_extract_locale(ctx, argc, argv);
+ if (!loc)
+ goto fail;
+ js_free(ctx, s->locale);
+ s->locale = loc;
+ }
+
+ /* Save canonical locale with extensions for resolvedOptions, and extract
+ numberingSystem and calendar from the Unicode extension. */
+ {
+ char *canonical = NULL;
+ if (js_canonicalizeLocaleList_first(ctx, argc > 0 ? argv[0] : JS_UNDEFINED, &canonical) < 0)
+ goto fail;
+ s->locale_canonical = canonical;
+ if (canonical) {
+ char *ns_str = js_intl_locale_get_numbering_system(ctx, canonical);
+ if (ns_str) {
+ int ns = js_intl_string_to_numbering_system(ns_str);
+ if (ns != NS_UNKNOWN)
+ s->numberingSystem = ns;
+ js_free(ctx, ns_str);
+ } else {
+ s->numberingSystem = dtf_default_numbering_system(s->locale);
+ }
+ {
+ char *cal = js_intl_locale_get_unicode_key(ctx, canonical, "ca");
+ if (cal) {
+ if (!strcasecmp(cal, "islamicc")) {
+ js_free(ctx, cal);
+ cal = js_strdup(ctx, "islamic-civil");
+ } else if (!strcasecmp(cal, "ethiopic-amete-alem")) {
+ js_free(ctx, cal);
+ cal = js_strdup(ctx, "ethioaa");
+ }
+ if (cal) {
+ int cal_enum = ti_calendar_string_to_enum(cal);
+ if (cal_enum == CAL_UNKNOWN) {
+ js_free(ctx, cal);
+ s->calendar = CAL_GREGORY;
+ } else {
+ js_free(ctx, cal);
+ s->calendar = cal_enum;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* Extract hourCycle from unicode extension if present in raw input */
+ {
+ int hc_from_ext = -1;
+ if (argc > 0 && !JS_IsUndefined(argv[0])) {
+ const char *raw = NULL;
+ if (JS_IsString(argv[0])) {
+ raw = JS_ToCString(ctx, argv[0]);
+ } else {
+ JSValue arr = JS_ToObject(ctx, argv[0]);
+ if (!JS_IsException(arr)) {
+ JSValue item = JS_GetPropertyUint32(ctx, arr, (uint32_t)0);
+ if (!JS_IsException(item) && JS_IsString(item)) {
+ raw = JS_ToCString(ctx, item);
+ }
+ JS_FreeValue(ctx, item);
+ }
+ JS_FreeValue(ctx, arr);
+ }
+ if (raw) {
+ const char *hc_ext = strstr(raw, "-u-hc-");
+ if (hc_ext) {
+ hc_ext += 6;
+ if (!strncmp(hc_ext, "h11", 3) && (hc_ext[3] == '-' || hc_ext[3] == '\0'))
+ hc_from_ext = 0;
+ else if (!strncmp(hc_ext, "h12", 3) && (hc_ext[3] == '-' || hc_ext[3] == '\0'))
+ hc_from_ext = 1;
+ else if (!strncmp(hc_ext, "h23", 3) && (hc_ext[3] == '-' || hc_ext[3] == '\0'))
+ hc_from_ext = 2;
+ else if (!strncmp(hc_ext, "h24", 3) && (hc_ext[3] == '-' || hc_ext[3] == '\0'))
+ hc_from_ext = 3;
+ }
+ JS_FreeCString(ctx, raw);
+ }
+ }
+ s->hourCycle = hc_from_ext >= 0 ? hc_from_ext : 1;
+ s->has_hourCycle = hc_from_ext >= 0;
+ }
+
+ /* parse options */
+ if (argc > 1 && !JS_IsUndefined(argv[1])) {
+ options = JS_ToObject(ctx, argv[1]);
+ if (JS_IsException(options))
+ goto fail;
+
+ /* Step 5: localeMatcher (read for spec order, ignore value) */
+ {
+ int lm = js_intl_get_string_option(ctx, options, "localeMatcher",
+ intl_localeMatcher_names, 2,
+ INTL_LOCALEMATCHER_BESTFIT);
+ if (lm < 0)
+ goto fail;
+ }
+
+ /* Step 8: calendar */
+ {
+ JSValue v = JS_GetPropertyStr(ctx, options, "calendar");
+ if (JS_IsException(v))
+ goto fail;
+ if (!JS_IsUndefined(v)) {
+ const char *str = JS_ToCString(ctx, v);
+ JS_FreeValue(ctx, v);
+ if (!str)
+ goto fail;
+ if (!is_valid_locale_type(str)) {
+ JS_ThrowRangeError(ctx, "invalid calendar option");
+ JS_FreeCString(ctx, str);
+ goto fail;
+ }
+ {
+ char cal_buf[64];
+ const char *cal_str = str;
+ if (!strcasecmp(str, "islamicc")) cal_str = "islamic-civil";
+ else if (!strcasecmp(str, "ethiopic-amete-alem")) cal_str = "ethioaa";
+ else {
+ int i;
+ pstrcpy(cal_buf, sizeof(cal_buf), str);
+ for (i = 0; cal_buf[i]; i++)
+ cal_buf[i] = (char)tolower((unsigned char)cal_buf[i]);
+ cal_str = cal_buf;
+ }
+ {
+ int cal_enum = ti_calendar_string_to_enum(cal_str);
+ if (cal_enum != CAL_UNKNOWN) {
+ s->has_calendar_option = 1;
+ s->calendar = cal_enum;
+ }
+ }
+ }
+ JS_FreeCString(ctx, str);
+ } else {
+ JS_FreeValue(ctx, v);
+ }
+ }
+
+ /* Step 9: numberingSystem */
+ {
+ JSValue v = JS_GetPropertyStr(ctx, options, "numberingSystem");
+ if (JS_IsException(v))
+ goto fail;
+ if (!JS_IsUndefined(v)) {
+ const char *str = JS_ToCString(ctx, v);
+ JS_FreeValue(ctx, v);
+ if (!str)
+ goto fail;
+ if (!is_valid_locale_type(str)) {
+ JS_ThrowRangeError(ctx, "invalid numberingSystem option");
+ JS_FreeCString(ctx, str);
+ goto fail;
+ }
+ {
+ int ns = js_intl_string_to_numbering_system(str);
+ if (ns != NS_UNKNOWN) {
+ s->has_numberingSystem_option = 1;
+ s->numberingSystem = ns;
+ }
+ }
+ JS_FreeCString(ctx, str);
+ } else {
+ JS_FreeValue(ctx, v);
+ }
+ }
+
+ /* Step 12: hour12 */
+ {
+ JSValue v = JS_GetPropertyStr(ctx, options, "hour12");
+ if (JS_IsException(v))
+ goto fail;
+ if (!JS_IsUndefined(v)) {
+ const char *p;
+ int is_ja;
+ s->has_hour12 = 1;
+ s->hour12 = JS_ToBool(ctx, v);
+ is_ja = strstart(s->locale, "ja", &p) && (*p == '-' || *p == '\0');
+ /* hour12 overrides hourCycle */
+ if (s->hour12) {
+ s->hourCycle = is_ja ? 0 : 1; /* h11 for ja, h12 otherwise */
+ s->has_hourCycle = 1;
+ } else {
+ s->hourCycle = 2; /* h23 */
+ s->has_hourCycle = 1;
+ }
+ }
+ JS_FreeValue(ctx, v);
+ }
+
+ /* Step 13: hourCycle */
+ {
+ int hc = js_intl_get_string_option(ctx, options, "hourCycle",
+ dtf_hourcycle_names, 4, 4);
+ if (hc < 0)
+ goto fail;
+ if (hc < 4) {
+ s->has_hourCycle_option = 1;
+ s->hourCycle = hc;
+ s->has_hourCycle = 1;
+ /* hour12 takes precedence if both are present */
+ if (s->has_hour12) {
+ if (s->hour12)
+ s->hourCycle = 1; /* h12 */
+ else
+ s->hourCycle = 2; /* h23 */
+ }
+ }
+ }
+
+ /* Step 29: timeZone */
+ {
+ JSValue v = JS_GetPropertyStr(ctx, options, "timeZone");
+ if (JS_IsException(v))
+ goto fail;
+ if (!JS_IsUndefined(v)) {
+ size_t slen;
+ const char *str = JS_ToCStringLen(ctx, &slen, v);
+ JS_FreeValue(ctx, v);
+ if (!str)
+ goto fail;
+ if (strlen(str) != slen || !is_valid_time_zone(str)) {
+ JS_ThrowRangeError(ctx, "invalid timeZone option");
+ JS_FreeCString(ctx, str);
+ goto fail;
+ }
+ {
+ char *tz;
+ if (str[0] == '+' || str[0] == '-') {
+ tz = canonicalize_offset_time_zone(ctx, str);
+ } else if (!strcasecmp(str, "UTC")) {
+ tz = js_strdup(ctx, "UTC");
+ } else {
+ tz = js_strdup(ctx, str);
+ }
+ js_free(ctx, s->timeZone);
+ s->timeZone = tz;
+ }
+ JS_FreeCString(ctx, str);
+ if (!s->timeZone)
+ goto fail;
+ } else {
+ JS_FreeValue(ctx, v);
+ }
+ }
+
+ /* Step 37: Table 7 options in table order */
+ s->weekday = js_intl_get_string_option(ctx, options, "weekday",
+ dtf_weekday_names, 3,
+ DTF_WEEKDAY_UNSET);
+ if (s->weekday < 0) goto fail;
+ s->era = js_intl_get_string_option(ctx, options, "era",
+ dtf_era_names, 3,
+ DTF_ERA_UNSET);
+ if (s->era < 0) goto fail;
+ s->year = js_intl_get_string_option(ctx, options, "year",
+ dtf_year_names, 2,
+ DTF_YEAR_UNSET);
+ if (s->year < 0) goto fail;
+ s->has_year_option = (s->year != DTF_YEAR_UNSET);
+ s->month = js_intl_get_string_option(ctx, options, "month",
+ dtf_month_names, 5,
+ DTF_MONTH_UNSET);
+ if (s->month < 0) goto fail;
+ s->has_month_option = (s->month != DTF_MONTH_UNSET);
+ s->day = js_intl_get_string_option(ctx, options, "day",
+ dtf_day_names, 2,
+ DTF_DAY_UNSET);
+ if (s->day < 0) goto fail;
+ s->has_day_option = (s->day != DTF_DAY_UNSET);
+ s->dayPeriod = js_intl_get_string_option(ctx, options, "dayPeriod",
+ dtf_dayperiod_names, 3,
+ DTF_DAYPERIOD_UNSET);
+ if (s->dayPeriod < 0) goto fail;
+ s->hour = js_intl_get_string_option(ctx, options, "hour",
+ dtf_hour_names, 2,
+ DTF_HOUR_UNSET);
+ if (s->hour < 0) goto fail;
+ s->minute = js_intl_get_string_option(ctx, options, "minute",
+ dtf_minute_names, 2,
+ DTF_MINUTE_UNSET);
+ if (s->minute < 0) goto fail;
+ s->second = js_intl_get_string_option(ctx, options, "second",
+ dtf_second_names, 2,
+ DTF_SECOND_UNSET);
+ if (s->second < 0) goto fail;
+
+ /* fractionalSecondDigits: GetNumberOption(options, prop, 1, 3, undefined) */
+ {
+ int fsd;
+ ret = js_intl_get_number_option(ctx, options, "fractionalSecondDigits", &fsd, 1, 3);
+ if (ret < 0) goto fail;
+ if (ret > 0) {
+ s->fractionalSecondDigits = fsd;
+ s->has_fractionalSecondDigits = 1;
+ }
+ }
+
+ s->timeZoneName = js_intl_get_string_option(ctx, options, "timeZoneName",
+ dtf_timezonename_names, 6,
+ DTF_TIMEZONE_UNSET);
+ if (s->timeZoneName < 0) goto fail;
+
+ /* Step 37 (continued): formatMatcher */
+ s->formatMatcher = js_intl_get_string_option(ctx, options, "formatMatcher",
+ dtf_formatmatcher_names, 2,
+ DTF_FORMATMATCHER_UNSET);
+ if (s->formatMatcher < 0) goto fail;
+
+ /* Step 38: dateStyle */
+ {
+ int ds_idx = js_intl_get_string_option(ctx, options, "dateStyle",
+ dtf_style_names, 4,
+ DTF_STYLE_UNSET);
+ if (ds_idx < 0)
+ goto fail;
+
+ /* Step 40: timeStyle */
+ int ts_idx = js_intl_get_string_option(ctx, options, "timeStyle",
+ dtf_style_names, 4,
+ DTF_STYLE_UNSET);
+ if (ts_idx < 0)
+ goto fail;
+
+ int has_style = (ds_idx != DTF_STYLE_UNSET || ts_idx != DTF_STYLE_UNSET);
+
+ if (has_style) {
+ static const char *conflicting[] = {
+ "weekday", "era", "year", "month", "day",
+ "dayPeriod", "hour", "minute", "second",
+ "fractionalSecondDigits", "timeZoneName"
+ };
+ int i;
+ for (i = 0; i < 11; i++) {
+ JSValue v = JS_GetPropertyStr(ctx, options, conflicting[i]);
+ if (JS_IsException(v))
+ goto fail;
+ int is_undef = JS_IsUndefined(v);
+ JS_FreeValue(ctx, v);
+ if (!is_undef) {
+ JS_ThrowTypeError(ctx, "conflicting formatting option");
+ goto fail;
+ }
+ }
+ if (ds_idx != DTF_STYLE_UNSET) {
+ s->year = DTF_YEAR_UNSET;
+ s->month = DTF_MONTH_UNSET;
+ s->day = DTF_DAY_UNSET;
+ s->dateStyle = ds_idx;
+ }
+ if (ts_idx != DTF_STYLE_UNSET) {
+ s->hour = DTF_HOUR_UNSET;
+ s->minute = DTF_MINUTE_UNSET;
+ s->second = DTF_SECOND_UNSET;
+ s->timeStyle = ts_idx;
+ }
+ }
+ }
+
+ /* Default hourCycle when hour-related formatting is used but
+ neither hour12 nor hourCycle was explicitly set. */
+ if (!s->has_hourCycle && (s->hour != DTF_HOUR_UNSET || s->timeStyle != DTF_STYLE_UNSET)) {
+ const char *p;
+ /* Check for -u-hc- extension in the original locale string */
+ const char *hc_ext = strstr(s->locale, "-u-hc-");
+ if (hc_ext) {
+ hc_ext += 6;
+ if (!strncmp(hc_ext, "h11", 3) && (hc_ext[3] == '-' || hc_ext[3] == '\0'))
+ s->hourCycle = 0;
+ else if (!strncmp(hc_ext, "h12", 3) && (hc_ext[3] == '-' || hc_ext[3] == '\0'))
+ s->hourCycle = 1;
+ else if (!strncmp(hc_ext, "h23", 3) && (hc_ext[3] == '-' || hc_ext[3] == '\0'))
+ s->hourCycle = 2;
+ else if (!strncmp(hc_ext, "h24", 3) && (hc_ext[3] == '-' || hc_ext[3] == '\0'))
+ s->hourCycle = 3;
+ else
+ goto default_hc;
+ s->has_hourCycle = 1;
+ } else {
+ default_hc:
+ if (strstart(s->locale, "ja", &p) && (*p == '-' || *p == '\0'))
+ s->hourCycle = 2; /* h23 */
+ else if (strstart(s->locale, "de", &p) && (*p == '-' || *p == '\0'))
+ s->hourCycle = 2; /* h23 */
+ else
+ s->hourCycle = 1; /* h12 */
+ s->has_hourCycle = 1;
+ }
+ }
+
+ JS_FreeValue(ctx, options);
+ options = JS_UNDEFINED;
+ }
+
+ /* Rebuild locale with preserved Unicode extensions */
+ if (s->locale_canonical) {
+ int preserve_ca = 0, preserve_nu = 0, preserve_hc = 0;
+
+ if (js_intl_locale_has_key(s->locale_canonical, "ca")) {
+ char *ext_val = js_intl_locale_get_unicode_key(ctx, s->locale_canonical, "ca");
+ if (ext_val && is_supported_calendar(ext_val)) {
+ int ext_cal = ti_calendar_string_to_enum(ext_val);
+ if (!s->has_calendar_option || ext_cal == s->calendar)
+ preserve_ca = 1;
+ }
+ js_free(ctx, ext_val);
+ }
+ if (js_intl_locale_has_key(s->locale_canonical, "nu")) {
+ char *ext_val = js_intl_locale_get_unicode_key(ctx, s->locale_canonical, "nu");
+ if (ext_val) {
+ int ext_ns = js_intl_string_to_numbering_system(ext_val);
+ if (!s->has_numberingSystem_option || ext_ns == s->numberingSystem)
+ preserve_nu = 1;
+ js_free(ctx, ext_val);
+ }
+ }
+ if (js_intl_locale_has_key(s->locale_canonical, "hc")) {
+ char *ext_val = js_intl_locale_get_unicode_key(ctx, s->locale_canonical, "hc");
+ if (ext_val) {
+ int hc_valid = 0;
+ if (!strcmp(ext_val, "h11") || !strcmp(ext_val, "h12") ||
+ !strcmp(ext_val, "h23") || !strcmp(ext_val, "h24"))
+ hc_valid = 1;
+ if (hc_valid && !s->has_hour12 &&
+ (!s->has_hourCycle_option || !strcmp(ext_val, dtf_hourcycle_names[s->hourCycle])))
+ preserve_hc = 1;
+ js_free(ctx, ext_val);
+ }
+ }
+
+ if (preserve_ca || preserve_nu || preserve_hc) {
+ DynBuf db;
+ js_intl_dbuf_init(ctx, &db);
+ dbuf_putstr(&db, s->locale);
+ dbuf_put(&db, (uint8_t *)"-u", (size_t)2);
+ if (preserve_ca) {
+ char *v = js_intl_locale_get_unicode_key(ctx, s->locale_canonical, "ca");
+ if (v) {
+ dbuf_put(&db, (uint8_t *)"-ca-", (size_t)4);
+ dbuf_putstr(&db, v);
+ js_free(ctx, v);
+ }
+ }
+ if (preserve_nu) {
+ char *v = js_intl_locale_get_unicode_key(ctx, s->locale_canonical, "nu");
+ if (v) {
+ dbuf_put(&db, (uint8_t *)"-nu-", (size_t)4);
+ dbuf_putstr(&db, v);
+ js_free(ctx, v);
+ }
+ }
+ if (preserve_hc) {
+ char *v = js_intl_locale_get_unicode_key(ctx, s->locale_canonical, "hc");
+ if (v) {
+ dbuf_put(&db, (uint8_t *)"-hc-", (size_t)4);
+ dbuf_putstr(&db, v);
+ js_free(ctx, v);
+ }
+ }
+ dbuf_put(&db, (uint8_t *)"", (size_t)1);
+ if (dbuf_error(&db)) {
+ dbuf_free(&db);
+ return JS_EXCEPTION;
+ }
+ js_free(ctx, s->locale);
+ s->locale = js_strdup(ctx, (char *)db.buf);
+ dbuf_free(&db);
+ }
+ }
+
+ /* Default date/time fields based on required and defaults */
+ if (s->dateStyle == DTF_STYLE_UNSET && s->timeStyle == DTF_STYLE_UNSET) {
+ int needDefaults = 1;
+ if (s->required == 0 || s->required == 1) {
+ if (s->weekday != DTF_WEEKDAY_UNSET || s->year != DTF_YEAR_UNSET ||
+ s->month != DTF_MONTH_UNSET || s->day != DTF_DAY_UNSET)
+ needDefaults = 0;
+ }
+ if (needDefaults && (s->required == 0 || s->required == 2)) {
+ if (s->dayPeriod != DTF_DAYPERIOD_UNSET || s->hour != DTF_HOUR_UNSET ||
+ s->minute != DTF_MINUTE_UNSET || s->second != DTF_SECOND_UNSET ||
+ s->has_fractionalSecondDigits)
+ needDefaults = 0;
+ }
+ if (needDefaults) {
+ if (s->defaults == 0 || s->defaults == 2) {
+ s->year = DTF_YEAR_NUMERIC;
+ s->month = DTF_MONTH_NUMERIC;
+ s->day = DTF_DAY_NUMERIC;
+ }
+ if (s->defaults == 1 || s->defaults == 2) {
+ s->hour = DTF_HOUR_NUMERIC;
+ s->minute = DTF_MINUTE_NUMERIC;
+ s->second = DTF_SECOND_NUMERIC;
+ }
+ }
+ }
+
+ obj = JS_CreateFromConstructor(ctx, new_target, js_datetimeformat_class_id);
+ if (JS_IsException(obj))
+ goto fail;
+ JS_SetOpaque(obj, s);
+
+ if (!is_new) {
+ /* ChainDateTimeFormat: if this is a DateTimeFormat instance, define fallback symbol */
+ JSValue ctor = JS_GetContextValue(ctx, JS_INTL_CTOR_DATETIMEFORMAT);
+ int is_instance = JS_OrdinaryIsInstanceOf(ctx, this_val, ctor);
+ JS_FreeValue(ctx, ctor);
+ if (is_instance < 0) {
+ JS_FreeValue(ctx, obj);
+ return JS_EXCEPTION;
+ }
+ if (is_instance) {
+ JSValue sym = JS_GetContextValue(ctx, JS_INTL_FALLBACK_SYMBOL);
+ if (JS_IsException(sym)) {
+ JS_FreeValue(ctx, obj);
+ return JS_EXCEPTION;
+ }
+ if (!JS_IsUndefined(sym)) {
+ JSAtom sym_atom = JS_ValueToAtom(ctx, sym);
+ JS_DefinePropertyValue(ctx, this_val, sym_atom, JS_DupValue(ctx, obj), 0);
+ JS_FreeAtom(ctx, sym_atom);
+ }
+ JS_FreeValue(ctx, sym);
+ JS_FreeValue(ctx, obj);
+ return JS_DupValue(ctx, this_val);
+ }
+ }
+ return obj;
+ fail:
+ JS_FreeValue(ctx, options);
+ js_free(ctx, s->locale);
+ js_free(ctx, s->locale_canonical);
+ js_free(ctx, s->timeZone);
+ js_free(ctx, s);
+ JS_FreeValue(ctx, obj);
+ return JS_EXCEPTION;
+}
+
+/* TimeClip as defined in ECMA-262 */
+static double time_clip(double x)
+{
+ if (!isfinite(x))
+ return NAN;
+ if (fabs(x) > 8.64e15)
+ return NAN;
+ return trunc(x);
+}
+
+static int64_t datetime_now(void)
+{
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return (int64_t)tv.tv_sec * 1000 + (tv.tv_usec / 1000);
+}
+
+static double dtf_iso_to_epoch_ms(int year, int month, int day,
+ int hour, int minute, int second, int ms)
+{
+ static const int mdays[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+ int64_t y = year - 1;
+ int64_t days = y * 365;
+ int64_t q = y / 4;
+ if ((y ^ 4) < 0 && (y % 4)) q--;
+ days += q;
+ q = y / 100;
+ if ((y ^ 100) < 0 && (y % 100)) q--;
+ days -= q;
+ q = y / 400;
+ if ((y ^ 400) < 0 && (y % 400)) q--;
+ days += q;
+ int i;
+ for (i = 1; i < month; i++)
+ days += mdays[i];
+ if (month > 2 && ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)))
+ days++;
+ days += day - 1;
+ return (double)((days - 719162) * 86400000LL + hour * 3600000LL + minute * 60000LL + second * 1000LL + ms);
+}
+
+static int datetimeformat_validate_date(JSContext *ctx, JSValueConst arg, double *pd, int *is_plain)
+{
+ if (is_plain)
+ *is_plain = 0;
+
+ if (JS_IsUndefined(arg)) {
+ JS_ThrowTypeError(ctx, "date argument is undefined");
+ return -1;
+ }
+
+ /* Handle Temporal objects */
+ if (JS_IsObject(arg)) {
+ JSInstantData *instant = JS_GetOpaque(arg, js_instant_class_id);
+ if (instant) {
+ *pd = timespec_to_ms(&instant->ts);
+ if (is_plain)
+ *is_plain = 1;
+ goto do_clip;
+ }
+
+ JSZonedDateTimeData *zdt = JS_GetOpaque(arg, js_zoneddatetime_class_id);
+ if (zdt) {
+ *pd = timespec_to_ms(&zdt->ts);
+ goto do_clip;
+ }
+
+ JSPlainDateTimeData *pdt = JS_GetOpaque(arg, js_plaindatetime_class_id);
+ if (pdt) {
+ *pd = dtf_iso_to_epoch_ms(pdt->year, pdt->month, pdt->day,
+ pdt->hour, pdt->minute, pdt->second, pdt->millisecond);
+ if (is_plain)
+ *is_plain = 1;
+ return 0;
+ }
+
+ JSPlainDateData *pdate = JS_GetOpaque(arg, js_plaindate_class_id);
+ if (pdate) {
+ *pd = dtf_iso_to_epoch_ms(pdate->year, pdate->month, pdate->day, 12, 0, 0, 0);
+ if (is_plain)
+ *is_plain = 1;
+ return 0;
+ }
+
+ JSPlainTimeData *pt = JS_GetOpaque(arg, js_plaintime_class_id);
+ if (pt) {
+ *pd = dtf_iso_to_epoch_ms(1970, 1, 1, pt->hour, pt->minute, pt->second, pt->millisecond);
+ if (is_plain)
+ *is_plain = 1;
+ return 0;
+ }
+
+ JSPlainYearMonthData *pym = JS_GetOpaque(arg, js_plainyearmonth_class_id);
+ if (pym) {
+ *pd = dtf_iso_to_epoch_ms(pym->iso_year, pym->iso_month, pym->iso_day, 12, 0, 0, 0);
+ if (is_plain)
+ *is_plain = 1;
+ return 0;
+ }
+
+ JSPlainMonthDayData *pmd = JS_GetOpaque(arg, js_plainmonthday_class_id);
+ if (pmd) {
+ *pd = dtf_iso_to_epoch_ms(pmd->iso_year, pmd->iso_month, pmd->iso_day, 12, 0, 0, 0);
+ if (is_plain)
+ *is_plain = 1;
+ return 0;
+ }
+ }
+
+ {
+ int ret = JS_ToFloat64(ctx, pd, arg);
+ if (ret < 0)
+ return -1;
+ }
+do_clip:
+ *pd = time_clip(*pd);
+ if (isnan(*pd)) {
+ JS_ThrowRangeError(ctx, "Invalid time value");
+ return -1;
+ }
+ return 0;
+}
+
+/* bound format function */
+static JSValue js_datetimeformat_bound_format(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv,
+ int magic, JSValue *func_data)
+{
+ JSDateTimeFormatData *s = JS_GetOpaque(func_data[0], js_datetimeformat_class_id);
+ double d;
+ int is_plain = 0;
+
+ if (!s)
+ return JS_ThrowTypeError(ctx, "DateTimeFormat object expected");
+
+ if (argc == 0 || JS_IsUndefined(argv[0])) {
+ d = time_clip((double)datetime_now());
+ } else {
+ if (JS_IsObject(argv[0])) {
+ if (dtf_check_temporal_overlap(ctx, s, argv[0]) < 0)
+ return JS_EXCEPTION;
+ }
+ if (datetimeformat_validate_date(ctx, argv[0], &d, &is_plain) < 0)
+ return JS_EXCEPTION;
+ }
+ if (is_plain) {
+ JSDateTimeFormatData s_copy = *s;
+ if (JS_GetOpaque(argv[0], js_plaindate_class_id) ||
+ JS_GetOpaque(argv[0], js_plaintime_class_id) ||
+ JS_GetOpaque(argv[0], js_plainyearmonth_class_id) ||
+ JS_GetOpaque(argv[0], js_plainmonthday_class_id) ||
+ JS_GetOpaque(argv[0], js_plaindatetime_class_id)) {
+ s_copy.timeZone = "+00:00";
+ s_copy.timeZoneName = DTF_TIMEZONE_UNSET;
+ }
+ dtf_resolve_style_for_temporal(&s_copy, argv[0]);
+ return dtf_format_date(ctx, &s_copy, d, 0);
+ }
+ return dtf_format_date(ctx, s, d, 0);
+}
+
+/* getter for Intl.DateTimeFormat.prototype.format */
+static JSValue js_datetimeformat_get_format(JSContext *ctx, JSValueConst this_val)
+{
+ JSValue func_data[1];
+ JSValue unwrapped = js_datetimeformat_unwrap(ctx, this_val);
+ if (JS_IsException(unwrapped))
+ return unwrapped;
+ JSDateTimeFormatData *s = JS_GetOpaque2(ctx, unwrapped, js_datetimeformat_class_id);
+ if (!s) {
+ JS_FreeValue(ctx, unwrapped);
+ return JS_EXCEPTION;
+ }
+
+ func_data[0] = unwrapped;
+ JSValue ret = JS_NewCFunctionData(ctx, (JSCFunctionData *)js_datetimeformat_bound_format,
+ 1, 0, 1, func_data);
+ JS_FreeValue(ctx, unwrapped);
+ return ret;
+}
+
+static JSValue js_datetimeformat_formatToParts(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSValue unwrapped = js_datetimeformat_unwrap(ctx, this_val);
+ if (JS_IsException(unwrapped))
+ return unwrapped;
+ JSDateTimeFormatData *s = JS_GetOpaque2(ctx, unwrapped, js_datetimeformat_class_id);
+ double d;
+ int is_plain = 0;
+ if (!s) {
+ JS_FreeValue(ctx, unwrapped);
+ return JS_EXCEPTION;
+ }
+ if (argc == 0 || JS_IsUndefined(argv[0])) {
+ d = time_clip((double)datetime_now());
+ } else {
+ if (JS_IsObject(argv[0])) {
+ if (dtf_check_temporal_overlap(ctx, s, argv[0]) < 0) {
+ JS_FreeValue(ctx, unwrapped);
+ return JS_EXCEPTION;
+ }
+ }
+ if (datetimeformat_validate_date(ctx, argv[0], &d, &is_plain) < 0) {
+ JS_FreeValue(ctx, unwrapped);
+ return JS_EXCEPTION;
+ }
+ }
+ if (is_plain) {
+ JSDateTimeFormatData s_copy = *s;
+ if (JS_GetOpaque(argv[0], js_plaindate_class_id) ||
+ JS_GetOpaque(argv[0], js_plaintime_class_id) ||
+ JS_GetOpaque(argv[0], js_plainyearmonth_class_id) ||
+ JS_GetOpaque(argv[0], js_plainmonthday_class_id) ||
+ JS_GetOpaque(argv[0], js_plaindatetime_class_id)) {
+ s_copy.timeZone = "+00:00";
+ s_copy.timeZoneName = DTF_TIMEZONE_UNSET;
+ }
+ dtf_resolve_style_for_temporal(&s_copy, argv[0]);
+ JSValue ret = dtf_format_date(ctx, &s_copy, d, 1);
+ JS_FreeValue(ctx, unwrapped);
+ return ret;
+ }
+ JSValue ret = dtf_format_date(ctx, s, d, 1);
+ JS_FreeValue(ctx, unwrapped);
+ return ret;
+}
+
+/* Compare two part objects by type and value */
+static int dtf_part_equal(JSContext *ctx, JSValue a, JSValue b)
+{
+ JSValue ta = JS_GetPropertyStr(ctx, a, "type");
+ JSValue tb = JS_GetPropertyStr(ctx, b, "type");
+ JSValue va = JS_GetPropertyStr(ctx, a, "value");
+ JSValue vb = JS_GetPropertyStr(ctx, b, "value");
+ int res = 0;
+ const char *ca, *cb, *cva, *cvb;
+
+ if (JS_IsException(ta) || JS_IsException(tb) || JS_IsException(va) || JS_IsException(vb))
+ goto done;
+
+ ca = JS_ToCString(ctx, ta);
+ cb = JS_ToCString(ctx, tb);
+ cva = JS_ToCString(ctx, va);
+ cvb = JS_ToCString(ctx, vb);
+
+ if (ca && cb && cva && cvb)
+ res = !strcmp(ca, cb) && !strcmp(cva, cvb);
+
+ JS_FreeCString(ctx, ca);
+ JS_FreeCString(ctx, cb);
+ JS_FreeCString(ctx, cva);
+ JS_FreeCString(ctx, cvb);
+
+done:
+ JS_FreeValue(ctx, ta);
+ JS_FreeValue(ctx, tb);
+ JS_FreeValue(ctx, va);
+ JS_FreeValue(ctx, vb);
+ return res;
+}
+
+/* Append string values of parts[start] to parts[end-1] into db */
+static int dtf_append_parts_string(JSContext *ctx, JSValue arr, int start, int end, DynBuf *db)
+{
+ int i;
+ for (i = start; i < end; i++) {
+ JSValue item = JS_GetPropertyUint32(ctx, arr, (uint32_t)i);
+ if (JS_IsException(item))
+ return -1;
+ {
+ JSValue val = JS_GetPropertyStr(ctx, item, "value");
+ const char *str = JS_ToCString(ctx, val);
+ if (str)
+ dbuf_putstr(db, str);
+ JS_FreeCString(ctx, str);
+ JS_FreeValue(ctx, val);
+ }
+ JS_FreeValue(ctx, item);
+ }
+ return 0;
+}
+
+static JSValue js_datetimeformat_formatRange(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSValue unwrapped = js_datetimeformat_unwrap(ctx, this_val);
+ if (JS_IsException(unwrapped))
+ return unwrapped;
+ JSDateTimeFormatData *s = JS_GetOpaque2(ctx, unwrapped, js_datetimeformat_class_id);
+ JSDateTimeFormatData *s_use = s;
+ JSDateTimeFormatData s_copy;
+ JSValue start, end, ret;
+ DynBuf db;
+ double x, y;
+ if (!s) {
+ JS_FreeValue(ctx, unwrapped);
+ return JS_EXCEPTION;
+ }
+ if (JS_IsUndefined(argv[0]) || JS_IsUndefined(argv[1])) {
+ JS_FreeValue(ctx, unwrapped);
+ return JS_ThrowTypeError(ctx, "date argument is undefined");
+ }
+ {
+ BOOL t0, t1, c0, c1;
+ if (dtf_to_datetimeformattable(ctx, argv[0], &x, &t0, &c0) < 0) {
+ JS_FreeValue(ctx, unwrapped);
+ return JS_EXCEPTION;
+ }
+ if (dtf_to_datetimeformattable(ctx, argv[1], &y, &t1, &c1) < 0) {
+ JS_FreeValue(ctx, unwrapped);
+ return JS_EXCEPTION;
+ }
+ if (t0 != t1 || (t0 && !dtf_same_temporal_type(ctx, argv[0], argv[1]))) {
+ JS_FreeValue(ctx, unwrapped);
+ return JS_ThrowTypeError(ctx, "cannot format range between different types");
+ }
+ if (t0) {
+ int cal0 = dtf_get_temporal_calendar(ctx, argv[0]);
+ int cal1 = dtf_get_temporal_calendar(ctx, argv[1]);
+ if (cal0 != cal1) {
+ JS_FreeValue(ctx, unwrapped);
+ return JS_ThrowRangeError(ctx, "cannot format range between different calendars");
+ }
+ if (dtf_check_temporal_overlap(ctx, s, argv[0]) < 0) {
+ JS_FreeValue(ctx, unwrapped);
+ return JS_EXCEPTION;
+ }
+ if (dtf_check_temporal_overlap(ctx, s, argv[1]) < 0) {
+ JS_FreeValue(ctx, unwrapped);
+ return JS_EXCEPTION;
+ }
+ if (JS_GetOpaque(argv[0], js_plaindate_class_id) ||
+ JS_GetOpaque(argv[0], js_plaintime_class_id) ||
+ JS_GetOpaque(argv[0], js_plainyearmonth_class_id) ||
+ JS_GetOpaque(argv[0], js_plainmonthday_class_id) ||
+ JS_GetOpaque(argv[0], js_plaindatetime_class_id)) {
+ s_copy = *s;
+ s_copy.timeZone = "+00:00";
+ s_copy.timeZoneName = DTF_TIMEZONE_UNSET;
+ s_use = &s_copy;
+ }
+ }
+ if (c0) {
+ x = time_clip(x);
+ if (isnan(x)) {
+ JS_FreeValue(ctx, unwrapped);
+ JS_ThrowRangeError(ctx, "Invalid time value");
+ return JS_EXCEPTION;
+ }
+ }
+ if (c1) {
+ y = time_clip(y);
+ if (isnan(y)) {
+ JS_FreeValue(ctx, unwrapped);
+ JS_ThrowRangeError(ctx, "Invalid time value");
+ return JS_EXCEPTION;
+ }
+ }
+ }
+
+ dtf_resolve_style_for_temporal(s_use, argv[0]);
+
+ start = dtf_format_date(ctx, s_use, x, 0);
+ if (JS_IsException(start)) {
+ JS_FreeValue(ctx, unwrapped);
+ return start;
+ }
+ end = dtf_format_date(ctx, s_use, y, 0);
+ if (JS_IsException(end)) {
+ JS_FreeValue(ctx, unwrapped);
+ JS_FreeValue(ctx, start);
+ return end;
+ }
+
+ {
+ const char *start_c = JS_ToCString(ctx, start);
+ const char *end_c = JS_ToCString(ctx, end);
+ int same = start_c && end_c && strcmp(start_c, end_c) == 0;
+ JS_FreeCString(ctx, start_c);
+ JS_FreeCString(ctx, end_c);
+ if (same) {
+ JS_FreeValue(ctx, end);
+ JS_FreeValue(ctx, unwrapped);
+ return start;
+ }
+ }
+
+ {
+ int weekday_opt, year_opt, month_opt, day_opt;
+ int hour_opt, minute_opt, second_opt, tzname_opt;
+ int can_share = 0;
+ DTFDateFields fx, fy;
+ dtf_expand_styles(s_use, &weekday_opt, &year_opt, &month_opt, &day_opt,
+ &hour_opt, &minute_opt, &second_opt, &tzname_opt);
+ dtf_extract_fields(x, s_use->timeZone, &fx);
+ dtf_extract_fields(y, s_use->timeZone, &fy);
+ {
+ int has_date = (year_opt != DTF_YEAR_UNSET || month_opt != DTF_MONTH_UNSET || day_opt != DTF_DAY_UNSET);
+ if (fx.year == fy.year && fx.month == fy.month && fx.day == fy.day && has_date) {
+ can_share = 1;
+ } else if (month_opt == DTF_MONTH_SHORT || month_opt == DTF_MONTH_LONG) {
+ can_share = 1;
+ }
+ }
+
+ if (can_share) {
+ JSValue start_arr, end_arr;
+ int start_len = 0, end_len = 0;
+ int prefix_len = 0, suffix_len = 0;
+ int first_diff = 0, last_diff = -1, i;
+ int largest_diff = -1; /* 0=day, 1=month, 2=year */
+
+ start_arr = dtf_format_date(ctx, s_use, x, 1);
+ if (JS_IsException(start_arr))
+ goto range_fail;
+ end_arr = dtf_format_date(ctx, s_use, y, 1);
+ if (JS_IsException(end_arr)) {
+ JS_FreeValue(ctx, start_arr);
+ goto range_fail;
+ }
+
+ {
+ JSValue len_val = JS_GetPropertyStr(ctx, start_arr, "length");
+ if (!JS_IsException(len_val)) {
+ JS_ToInt32(ctx, &start_len, len_val);
+ JS_FreeValue(ctx, len_val);
+ }
+ }
+ {
+ JSValue len_val = JS_GetPropertyStr(ctx, end_arr, "length");
+ if (!JS_IsException(len_val)) {
+ JS_ToInt32(ctx, &end_len, len_val);
+ JS_FreeValue(ctx, len_val);
+ }
+ }
+
+ /* find first and last differing part */
+ for (i = 0; i < start_len && i < end_len; i++) {
+ JSValue a = JS_GetPropertyUint32(ctx, start_arr, (uint32_t)i);
+ JSValue b = JS_GetPropertyUint32(ctx, end_arr, (uint32_t)i);
+ int eq = dtf_part_equal(ctx, a, b);
+ JS_FreeValue(ctx, a);
+ JS_FreeValue(ctx, b);
+ if (!eq) {
+ if (last_diff == -1)
+ first_diff = i;
+ last_diff = i;
+ }
+ }
+ if (last_diff == -1) {
+ /* no differences found, check if index 0 differs */
+ JSValue a = JS_GetPropertyUint32(ctx, start_arr, (uint32_t)0);
+ JSValue b = JS_GetPropertyUint32(ctx, end_arr, (uint32_t)0);
+ if (!dtf_part_equal(ctx, a, b)) {
+ first_diff = 0;
+ last_diff = 0;
+ }
+ JS_FreeValue(ctx, a);
+ JS_FreeValue(ctx, b);
+ }
+
+ if (fx.year != fy.year)
+ largest_diff = 2;
+ else if (fx.month != fy.month)
+ largest_diff = 1;
+ else if (fx.day != fy.day)
+ largest_diff = 0;
+ else
+ largest_diff = -1;
+ if (largest_diff == 2) {
+ prefix_len = 0;
+ suffix_len = 0;
+ } else if (largest_diff == 1) {
+ prefix_len = 0;
+ /* suffix = matching parts after last_diff */
+ suffix_len = 0;
+ for (i = last_diff + 1; i < start_len && i < end_len; i++) {
+ JSValue a = JS_GetPropertyUint32(ctx, start_arr, (uint32_t)i);
+ JSValue b = JS_GetPropertyUint32(ctx, end_arr, (uint32_t)i);
+ int eq = dtf_part_equal(ctx, a, b);
+ JS_FreeValue(ctx, a);
+ JS_FreeValue(ctx, b);
+ if (eq)
+ suffix_len++;
+ else
+ break;
+ }
+ } else {
+ /* day differs: prefix up to first_diff, suffix after last_diff */
+ prefix_len = first_diff;
+ suffix_len = 0;
+ for (i = last_diff + 1; i < start_len && i < end_len; i++) {
+ JSValue a = JS_GetPropertyUint32(ctx, start_arr, (uint32_t)i);
+ JSValue b = JS_GetPropertyUint32(ctx, end_arr, (uint32_t)i);
+ int eq = dtf_part_equal(ctx, a, b);
+ JS_FreeValue(ctx, a);
+ JS_FreeValue(ctx, b);
+ if (eq)
+ suffix_len++;
+ else
+ break;
+ }
+ }
+
+ js_intl_dbuf_init(ctx, &db);
+ if (dtf_append_parts_string(ctx, start_arr, 0, prefix_len, &db) < 0)
+ goto parts_fail;
+ if (dtf_append_parts_string(ctx, start_arr, prefix_len, start_len - suffix_len, &db) < 0)
+ goto parts_fail;
+ dbuf_put(&db, (uint8_t *)" \xE2\x80\x93 ", (size_t)5); /* " – " */
+ if (dtf_append_parts_string(ctx, end_arr, prefix_len, end_len - suffix_len, &db) < 0)
+ goto parts_fail;
+ if (dtf_append_parts_string(ctx, end_arr, end_len - suffix_len, end_len, &db) < 0)
+ goto parts_fail;
+
+ if (dbuf_error(&db))
+ goto parts_fail;
+ ret = JS_NewStringLen(ctx, (char *)db.buf, db.size);
+ dbuf_free(&db);
+ JS_FreeValue(ctx, start_arr);
+ JS_FreeValue(ctx, end_arr);
+ JS_FreeValue(ctx, start);
+ JS_FreeValue(ctx, end);
+ JS_FreeValue(ctx, unwrapped);
+ return ret;
+
+ parts_fail:
+ dbuf_free(&db);
+ JS_FreeValue(ctx, start_arr);
+ JS_FreeValue(ctx, end_arr);
+ range_fail:
+ JS_FreeValue(ctx, start);
+ JS_FreeValue(ctx, end);
+ JS_FreeValue(ctx, unwrapped);
+ return JS_EXCEPTION;
+ }
+ }
+
+ js_intl_dbuf_init(ctx, &db);
+ {
+ const char *p = JS_ToCString(ctx, start);
+ if (p)
+ dbuf_putstr(&db, p);
+ JS_FreeCString(ctx, p);
+ }
+ dbuf_put(&db, (uint8_t *)" \xE2\x80\x93 ", (size_t)5); /* " – " */
+ {
+ const char *p = JS_ToCString(ctx, end);
+ if (p)
+ dbuf_putstr(&db, p);
+ JS_FreeCString(ctx, p);
+ }
+ if (dbuf_error(&db)) {
+ dbuf_free(&db);
+ JS_FreeValue(ctx, start);
+ JS_FreeValue(ctx, end);
+ JS_FreeValue(ctx, unwrapped);
+ return JS_EXCEPTION;
+ }
+ ret = JS_NewStringLen(ctx, (char *)db.buf, db.size);
+ dbuf_free(&db);
+ JS_FreeValue(ctx, start);
+ JS_FreeValue(ctx, end);
+ JS_FreeValue(ctx, unwrapped);
+ return ret;
+}
+
+static JSValue js_datetimeformat_formatRangeToParts(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSValue unwrapped = js_datetimeformat_unwrap(ctx, this_val);
+ if (JS_IsException(unwrapped))
+ return unwrapped;
+ JSDateTimeFormatData *s = JS_GetOpaque2(ctx, unwrapped, js_datetimeformat_class_id);
+ JSDateTimeFormatData *s_use = s;
+ JSDateTimeFormatData s_copy;
+ JSValue start_arr, end_arr, ret;
+ double x, y;
+ int i, start_len, end_len;
+ uint32_t idx;
+ if (!s) {
+ JS_FreeValue(ctx, unwrapped);
+ return JS_EXCEPTION;
+ }
+ if (JS_IsUndefined(argv[0]) || JS_IsUndefined(argv[1])) {
+ JS_FreeValue(ctx, unwrapped);
+ return JS_ThrowTypeError(ctx, "date argument is undefined");
+ }
+ {
+ BOOL t0, t1, c0, c1;
+ if (dtf_to_datetimeformattable(ctx, argv[0], &x, &t0, &c0) < 0) {
+ JS_FreeValue(ctx, unwrapped);
+ return JS_EXCEPTION;
+ }
+ if (dtf_to_datetimeformattable(ctx, argv[1], &y, &t1, &c1) < 0) {
+ JS_FreeValue(ctx, unwrapped);
+ return JS_EXCEPTION;
+ }
+ if (t0 != t1 || (t0 && !dtf_same_temporal_type(ctx, argv[0], argv[1]))) {
+ JS_FreeValue(ctx, unwrapped);
+ return JS_ThrowTypeError(ctx, "cannot format range between different types");
+ }
+ if (t0) {
+ int cal0 = dtf_get_temporal_calendar(ctx, argv[0]);
+ int cal1 = dtf_get_temporal_calendar(ctx, argv[1]);
+ if (cal0 != cal1) {
+ JS_FreeValue(ctx, unwrapped);
+ return JS_ThrowRangeError(ctx, "cannot format range between different calendars");
+ }
+ if (dtf_check_temporal_overlap(ctx, s, argv[0]) < 0) {
+ JS_FreeValue(ctx, unwrapped);
+ return JS_EXCEPTION;
+ }
+ if (dtf_check_temporal_overlap(ctx, s, argv[1]) < 0) {
+ JS_FreeValue(ctx, unwrapped);
+ return JS_EXCEPTION;
+ }
+ if (JS_GetOpaque(argv[0], js_plaindate_class_id) ||
+ JS_GetOpaque(argv[0], js_plaintime_class_id) ||
+ JS_GetOpaque(argv[0], js_plainyearmonth_class_id) ||
+ JS_GetOpaque(argv[0], js_plainmonthday_class_id) ||
+ JS_GetOpaque(argv[0], js_plaindatetime_class_id)) {
+ s_copy = *s;
+ s_copy.timeZone = "+00:00";
+ s_copy.timeZoneName = DTF_TIMEZONE_UNSET;
+ s_use = &s_copy;
+ }
+ }
+ if (c0) {
+ x = time_clip(x);
+ if (isnan(x)) {
+ JS_FreeValue(ctx, unwrapped);
+ JS_ThrowRangeError(ctx, "Invalid time value");
+ return JS_EXCEPTION;
+ }
+ }
+ if (c1) {
+ y = time_clip(y);
+ if (isnan(y)) {
+ JS_FreeValue(ctx, unwrapped);
+ JS_ThrowRangeError(ctx, "Invalid time value");
+ return JS_EXCEPTION;
+ }
+ }
+ }
+
+ dtf_resolve_style_for_temporal(s_use, argv[0]);
+
+ {
+ JSValue start_str, end_str;
+ start_arr = dtf_format_date(ctx, s_use, x, 1);
+ if (JS_IsException(start_arr))
+ return start_arr;
+ end_arr = dtf_format_date(ctx, s_use, y, 1);
+ if (JS_IsException(end_arr)) {
+ JS_FreeValue(ctx, start_arr);
+ return end_arr;
+ }
+ start_str = dtf_format_date(ctx, s_use, x, 0);
+ if (JS_IsException(start_str)) {
+ JS_FreeValue(ctx, start_arr);
+ JS_FreeValue(ctx, end_arr);
+ return start_str;
+ }
+ end_str = dtf_format_date(ctx, s_use, y, 0);
+ if (JS_IsException(end_str)) {
+ JS_FreeValue(ctx, start_str);
+ JS_FreeValue(ctx, start_arr);
+ JS_FreeValue(ctx, end_arr);
+ return end_str;
+ }
+ {
+ const char *start_c = JS_ToCString(ctx, start_str);
+ const char *end_c = JS_ToCString(ctx, end_str);
+ int same = start_c && end_c && strcmp(start_c, end_c) == 0;
+ JS_FreeCString(ctx, start_c);
+ JS_FreeCString(ctx, end_c);
+ JS_FreeValue(ctx, start_str);
+ JS_FreeValue(ctx, end_str);
+ if (same) {
+ JSValue len_val = JS_GetPropertyStr(ctx, start_arr, "length");
+ int j, n = 0;
+ if (!JS_IsException(len_val) && JS_ToInt32(ctx, &n, len_val) >= 0) {
+ for (j = 0; j < n; j++) {
+ JSValue item = JS_GetPropertyUint32(ctx, start_arr, (uint32_t)j);
+ if (!JS_IsException(item)) {
+ JS_DefinePropertyValueStr(ctx, item, "source",
+ JS_NewString(ctx, "shared"), JS_PROP_C_W_E);
+ }
+ JS_FreeValue(ctx, item);
+ }
+ }
+ JS_FreeValue(ctx, len_val);
+ JS_FreeValue(ctx, end_arr);
+ JS_FreeValue(ctx, unwrapped);
+ return start_arr;
+ }
+ }
+ }
+
+ {
+ int weekday_opt, year_opt, month_opt, day_opt;
+ int hour_opt, minute_opt, second_opt, tzname_opt;
+ int can_share = 0;
+ DTFDateFields fx, fy;
+ dtf_expand_styles(s_use, &weekday_opt, &year_opt, &month_opt, &day_opt,
+ &hour_opt, &minute_opt, &second_opt, &tzname_opt);
+ dtf_extract_fields(x, s_use->timeZone, &fx);
+ dtf_extract_fields(y, s_use->timeZone, &fy);
+ {
+ int has_date = (year_opt != DTF_YEAR_UNSET || month_opt != DTF_MONTH_UNSET || day_opt != DTF_DAY_UNSET);
+ if (fx.year == fy.year && fx.month == fy.month && fx.day == fy.day && has_date) {
+ can_share = 1;
+ } else if (month_opt == DTF_MONTH_SHORT || month_opt == DTF_MONTH_LONG) {
+ can_share = 1;
+ }
+ }
+
+ if (can_share) {
+ int largest_diff = -1;
+ int first_diff = 0, last_diff = -1, j;
+ int prefix_len = 0, suffix_len = 0;
+
+ if (fx.year != fy.year)
+ largest_diff = 2;
+ else if (fx.month != fy.month)
+ largest_diff = 1;
+ else if (fx.day != fy.day)
+ largest_diff = 0;
+ else
+ largest_diff = -1;
+
+ {
+ JSValue len_val = JS_GetPropertyStr(ctx, start_arr, "length");
+ if (!JS_IsException(len_val)) {
+ JS_ToInt32(ctx, &start_len, len_val);
+ JS_FreeValue(ctx, len_val);
+ }
+ }
+ {
+ JSValue len_val = JS_GetPropertyStr(ctx, end_arr, "length");
+ if (!JS_IsException(len_val)) {
+ JS_ToInt32(ctx, &end_len, len_val);
+ JS_FreeValue(ctx, len_val);
+ }
+ }
+
+ for (j = 0; j < start_len && j < end_len; j++) {
+ JSValue a = JS_GetPropertyUint32(ctx, start_arr, (uint32_t)j);
+ JSValue b = JS_GetPropertyUint32(ctx, end_arr, (uint32_t)j);
+ int eq = dtf_part_equal(ctx, a, b);
+ JS_FreeValue(ctx, a);
+ JS_FreeValue(ctx, b);
+ if (!eq) {
+ if (last_diff == -1)
+ first_diff = j;
+ last_diff = j;
+ }
+ }
+ if (last_diff == -1) {
+ JSValue a = JS_GetPropertyUint32(ctx, start_arr, (uint32_t)0);
+ JSValue b = JS_GetPropertyUint32(ctx, end_arr, (uint32_t)0);
+ if (!dtf_part_equal(ctx, a, b)) {
+ first_diff = 0;
+ last_diff = 0;
+ }
+ JS_FreeValue(ctx, a);
+ JS_FreeValue(ctx, b);
+ }
+
+ if (largest_diff == 2) {
+ prefix_len = 0;
+ suffix_len = 0;
+ } else if (largest_diff == 1) {
+ prefix_len = 0;
+ for (j = last_diff + 1; j < start_len && j < end_len; j++) {
+ JSValue a = JS_GetPropertyUint32(ctx, start_arr, (uint32_t)j);
+ JSValue b = JS_GetPropertyUint32(ctx, end_arr, (uint32_t)j);
+ int eq = dtf_part_equal(ctx, a, b);
+ JS_FreeValue(ctx, a);
+ JS_FreeValue(ctx, b);
+ if (eq)
+ suffix_len++;
+ else
+ break;
+ }
+ } else {
+ prefix_len = first_diff;
+ for (j = last_diff + 1; j < start_len && j < end_len; j++) {
+ JSValue a = JS_GetPropertyUint32(ctx, start_arr, (uint32_t)j);
+ JSValue b = JS_GetPropertyUint32(ctx, end_arr, (uint32_t)j);
+ int eq = dtf_part_equal(ctx, a, b);
+ JS_FreeValue(ctx, a);
+ JS_FreeValue(ctx, b);
+ if (eq)
+ suffix_len++;
+ else
+ break;
+ }
+ }
+
+ ret = JS_NewArray(ctx);
+ if (JS_IsException(ret))
+ goto fail;
+ idx = 0;
+
+ /* shared prefix from start */
+ for (j = 0; j < prefix_len; j++) {
+ JSValue item = JS_GetPropertyUint32(ctx, start_arr, (uint32_t)j);
+ if (JS_IsException(item))
+ goto fail;
+ if (JS_DefinePropertyValueStr(ctx, item, "source",
+ JS_NewString(ctx, "shared"), JS_PROP_C_W_E) < 0) {
+ JS_FreeValue(ctx, item);
+ goto fail;
+ }
+ if (JS_DefinePropertyValueUint32(ctx, ret, idx++, item, JS_PROP_C_W_E) < 0)
+ goto fail;
+ }
+
+ /* startRange non-shared */
+ for (j = prefix_len; j < start_len - suffix_len; j++) {
+ JSValue item = JS_GetPropertyUint32(ctx, start_arr, (uint32_t)j);
+ if (JS_IsException(item))
+ goto fail;
+ if (JS_DefinePropertyValueStr(ctx, item, "source",
+ JS_NewString(ctx, "startRange"), JS_PROP_C_W_E) < 0) {
+ JS_FreeValue(ctx, item);
+ goto fail;
+ }
+ if (JS_DefinePropertyValueUint32(ctx, ret, idx++, item, JS_PROP_C_W_E) < 0)
+ goto fail;
+ }
+
+ /* separator */
+ {
+ JSValue sep = JS_NewObject(ctx);
+ if (JS_IsException(sep))
+ goto fail;
+ if (JS_DefinePropertyValueStr(ctx, sep, "type",
+ JS_NewString(ctx, "literal"), JS_PROP_C_W_E) < 0) {
+ JS_FreeValue(ctx, sep);
+ goto fail;
+ }
+ if (JS_DefinePropertyValueStr(ctx, sep, "value",
+ JS_NewString(ctx, " \xE2\x80\x93 "), JS_PROP_C_W_E) < 0) {
+ JS_FreeValue(ctx, sep);
+ goto fail;
+ }
+ if (JS_DefinePropertyValueStr(ctx, sep, "source",
+ JS_NewString(ctx, "shared"), JS_PROP_C_W_E) < 0) {
+ JS_FreeValue(ctx, sep);
+ goto fail;
+ }
+ if (JS_DefinePropertyValueUint32(ctx, ret, idx++, sep, JS_PROP_C_W_E) < 0)
+ goto fail;
+ }
+
+ /* endRange non-shared */
+ for (j = prefix_len; j < end_len - suffix_len; j++) {
+ JSValue item = JS_GetPropertyUint32(ctx, end_arr, (uint32_t)j);
+ if (JS_IsException(item))
+ goto fail;
+ if (JS_DefinePropertyValueStr(ctx, item, "source",
+ JS_NewString(ctx, "endRange"), JS_PROP_C_W_E) < 0) {
+ JS_FreeValue(ctx, item);
+ goto fail;
+ }
+ if (JS_DefinePropertyValueUint32(ctx, ret, idx++, item, JS_PROP_C_W_E) < 0)
+ goto fail;
+ }
+
+ /* shared suffix from end */
+ for (j = end_len - suffix_len; j < end_len; j++) {
+ JSValue item = JS_GetPropertyUint32(ctx, end_arr, (uint32_t)j);
+ if (JS_IsException(item))
+ goto fail;
+ if (JS_DefinePropertyValueStr(ctx, item, "source",
+ JS_NewString(ctx, "shared"), JS_PROP_C_W_E) < 0) {
+ JS_FreeValue(ctx, item);
+ goto fail;
+ }
+ if (JS_DefinePropertyValueUint32(ctx, ret, idx++, item, JS_PROP_C_W_E) < 0)
+ goto fail;
+ }
+
+ JS_FreeValue(ctx, start_arr);
+ JS_FreeValue(ctx, end_arr);
+ JS_FreeValue(ctx, unwrapped);
+ return ret;
+ }
+ }
+
+ ret = JS_NewArray(ctx);
+ if (JS_IsException(ret))
+ goto fail;
+
+ {
+ JSValue len_val = JS_GetPropertyStr(ctx, start_arr, "length");
+ if (JS_IsException(len_val))
+ goto fail;
+ if (JS_ToInt32(ctx, &start_len, len_val) < 0) {
+ JS_FreeValue(ctx, len_val);
+ goto fail;
+ }
+ JS_FreeValue(ctx, len_val);
+ }
+ {
+ JSValue len_val = JS_GetPropertyStr(ctx, end_arr, "length");
+ if (JS_IsException(len_val))
+ goto fail;
+ if (JS_ToInt32(ctx, &end_len, len_val) < 0) {
+ JS_FreeValue(ctx, len_val);
+ goto fail;
+ }
+ JS_FreeValue(ctx, len_val);
+ }
+ idx = 0;
+
+ for (i = 0; i < start_len; i++) {
+ JSValue item = JS_GetPropertyUint32(ctx, start_arr, (uint32_t)i);
+ if (JS_IsException(item))
+ goto fail;
+ if (JS_DefinePropertyValueStr(ctx, item, "source",
+ JS_NewString(ctx, "startRange"), JS_PROP_C_W_E) < 0) {
+ JS_FreeValue(ctx, item);
+ goto fail;
+ }
+ if (JS_DefinePropertyValueUint32(ctx, ret, idx++, item, JS_PROP_C_W_E) < 0)
+ goto fail;
+ }
+
+ {
+ JSValue sep = JS_NewObject(ctx);
+ if (JS_IsException(sep))
+ goto fail;
+ if (JS_DefinePropertyValueStr(ctx, sep, "type",
+ JS_NewString(ctx, "literal"), JS_PROP_C_W_E) < 0) {
+ JS_FreeValue(ctx, sep);
+ goto fail;
+ }
+ if (JS_DefinePropertyValueStr(ctx, sep, "value",
+ JS_NewString(ctx, " \xE2\x80\x93 "), JS_PROP_C_W_E) < 0) {
+ JS_FreeValue(ctx, sep);
+ goto fail;
+ }
+ if (JS_DefinePropertyValueStr(ctx, sep, "source",
+ JS_NewString(ctx, "shared"), JS_PROP_C_W_E) < 0) {
+ JS_FreeValue(ctx, sep);
+ goto fail;
+ }
+ if (JS_DefinePropertyValueUint32(ctx, ret, idx++, sep, JS_PROP_C_W_E) < 0)
+ goto fail;
+ }
+
+ for (i = 0; i < end_len; i++) {
+ JSValue item = JS_GetPropertyUint32(ctx, end_arr, (uint32_t)i);
+ if (JS_IsException(item))
+ goto fail;
+ if (JS_DefinePropertyValueStr(ctx, item, "source",
+ JS_NewString(ctx, "endRange"), JS_PROP_C_W_E) < 0) {
+ JS_FreeValue(ctx, item);
+ goto fail;
+ }
+ if (JS_DefinePropertyValueUint32(ctx, ret, idx++, item, JS_PROP_C_W_E) < 0)
+ goto fail;
+ }
+
+ JS_FreeValue(ctx, start_arr);
+ JS_FreeValue(ctx, end_arr);
+ JS_FreeValue(ctx, unwrapped);
+ return ret;
+
+ fail:
+ JS_FreeValue(ctx, ret);
+ JS_FreeValue(ctx, start_arr);
+ JS_FreeValue(ctx, end_arr);
+ JS_FreeValue(ctx, unwrapped);
+ return JS_EXCEPTION;
+}
+
+static JSValue js_datetimeformat_resolvedOptions(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSValue obj;
+ JSValue unwrapped = js_datetimeformat_unwrap(ctx, this_val);
+ if (JS_IsException(unwrapped))
+ return unwrapped;
+ JSDateTimeFormatData *s = JS_GetOpaque2(ctx, unwrapped, js_datetimeformat_class_id);
+ if (!s) {
+ JS_FreeValue(ctx, unwrapped);
+ return JS_EXCEPTION;
+ }
+
+ obj = JS_NewObject(ctx);
+ if (JS_IsException(obj))
+ return JS_EXCEPTION;
+
+ JS_DefinePropertyValueStr(ctx, obj, "locale",
+ JS_NewString(ctx, s->locale), JS_PROP_C_W_E);
+ JS_DefinePropertyValueStr(ctx, obj, "calendar",
+ JS_NewString(ctx, ti_calendar_enum_to_string(s->calendar)), JS_PROP_C_W_E);
+ JS_DefinePropertyValueStr(ctx, obj, "numberingSystem",
+ JS_NewString(ctx, js_intl_numbering_system_to_string(s->numberingSystem)), JS_PROP_C_W_E);
+ JS_DefinePropertyValueStr(ctx, obj, "timeZone",
+ JS_NewString(ctx, s->timeZone), JS_PROP_C_W_E);
+ /* hourCycle only if hour-related formatting is used */
+ if (s->has_hourCycle && (s->hour != DTF_HOUR_UNSET || s->timeStyle != DTF_STYLE_UNSET)) {
+ JS_DefinePropertyValueStr(ctx, obj, "hourCycle",
+ JS_NewString(ctx, dtf_hourcycle_names[s->hourCycle]), JS_PROP_C_W_E);
+ }
+ /* hour12 if hour-related formatting is used */
+ if (s->hour != DTF_HOUR_UNSET || s->timeStyle != DTF_STYLE_UNSET) {
+ int hour12_val = (s->hourCycle == 0 || s->hourCycle == 1);
+ JS_DefinePropertyValueStr(ctx, obj, "hour12",
+ JS_NewBool(ctx, hour12_val), JS_PROP_C_W_E);
+ }
+ if (s->weekday != DTF_WEEKDAY_UNSET)
+ JS_DefinePropertyValueStr(ctx, obj, "weekday",
+ JS_NewString(ctx, dtf_weekday_names[s->weekday]), JS_PROP_C_W_E);
+ if (s->era != DTF_ERA_UNSET)
+ JS_DefinePropertyValueStr(ctx, obj, "era",
+ JS_NewString(ctx, dtf_era_names[s->era]), JS_PROP_C_W_E);
+ if (s->year != DTF_YEAR_UNSET)
+ JS_DefinePropertyValueStr(ctx, obj, "year",
+ JS_NewString(ctx, dtf_year_names[s->year]), JS_PROP_C_W_E);
+ if (s->month != DTF_MONTH_UNSET)
+ JS_DefinePropertyValueStr(ctx, obj, "month",
+ JS_NewString(ctx, dtf_month_names[s->month]), JS_PROP_C_W_E);
+ if (s->day != DTF_DAY_UNSET)
+ JS_DefinePropertyValueStr(ctx, obj, "day",
+ JS_NewString(ctx, dtf_day_names[s->day]), JS_PROP_C_W_E);
+ if (s->dayPeriod != DTF_DAYPERIOD_UNSET)
+ JS_DefinePropertyValueStr(ctx, obj, "dayPeriod",
+ JS_NewString(ctx, dtf_dayperiod_names[s->dayPeriod]), JS_PROP_C_W_E);
+ if (s->hour != DTF_HOUR_UNSET)
+ JS_DefinePropertyValueStr(ctx, obj, "hour",
+ JS_NewString(ctx, dtf_hour_names[s->hour]), JS_PROP_C_W_E);
+ if (s->minute != DTF_MINUTE_UNSET)
+ JS_DefinePropertyValueStr(ctx, obj, "minute",
+ JS_NewString(ctx, dtf_minute_names[s->minute]), JS_PROP_C_W_E);
+ if (s->second != DTF_SECOND_UNSET)
+ JS_DefinePropertyValueStr(ctx, obj, "second",
+ JS_NewString(ctx, dtf_second_names[s->second]), JS_PROP_C_W_E);
+ if (s->has_fractionalSecondDigits) {
+ JS_DefinePropertyValueStr(ctx, obj, "fractionalSecondDigits",
+ JS_NewInt32(ctx, s->fractionalSecondDigits), JS_PROP_C_W_E);
+ }
+ if (s->timeZoneName != DTF_TIMEZONE_UNSET)
+ JS_DefinePropertyValueStr(ctx, obj, "timeZoneName",
+ JS_NewString(ctx, dtf_timezonename_names[s->timeZoneName]), JS_PROP_C_W_E);
+ if (s->dateStyle != DTF_STYLE_UNSET)
+ JS_DefinePropertyValueStr(ctx, obj, "dateStyle",
+ JS_NewString(ctx, dtf_style_names[s->dateStyle]), JS_PROP_C_W_E);
+ if (s->timeStyle != DTF_STYLE_UNSET)
+ JS_DefinePropertyValueStr(ctx, obj, "timeStyle",
+ JS_NewString(ctx, dtf_style_names[s->timeStyle]), JS_PROP_C_W_E);
+
+ JS_FreeValue(ctx, unwrapped);
+ return obj;
+}
+
+static JSValue js_datetimeformat_supportedLocalesOf(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ return js_intl_supportedLocalesOf(ctx, this_val, argc, argv);
+}
+
+static const JSCFunctionListEntry js_datetimeformat_proto_funcs[] = {
+ JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Intl.DateTimeFormat", JS_PROP_CONFIGURABLE),
+ JS_CGETSET_DEF("format", js_datetimeformat_get_format, NULL),
+ JS_CFUNC_DEF("formatToParts", 1, js_datetimeformat_formatToParts),
+ JS_CFUNC_DEF("formatRange", 2, js_datetimeformat_formatRange),
+ JS_CFUNC_DEF("formatRangeToParts", 2, js_datetimeformat_formatRangeToParts),
+ JS_CFUNC_DEF("resolvedOptions", 0, js_datetimeformat_resolvedOptions),
+};
+
+static const JSCFunctionListEntry js_datetimeformat_static_funcs[] = {
+ JS_CFUNC_DEF("supportedLocalesOf", 1, js_datetimeformat_supportedLocalesOf),
+};
+
+int js_add_datetimeformat(JSContext *ctx, JSValue intl_obj)
+{
+ JS_NewClassID(&js_datetimeformat_class_id);
+ JS_NewClass(JS_GetRuntime(ctx), js_datetimeformat_class_id, &js_datetimeformat_class);
+
+ if (JS_IsException(js_intl_new_constructor(ctx, intl_obj,
+ JS_INTL_CTOR_DATETIMEFORMAT,
+ js_datetimeformat_class_id, "DateTimeFormat",
+ (JSCFunction *)js_datetimeformat_constructor, 0,
+ JS_CFUNC_constructor_or_func_flags, 0,
+ js_datetimeformat_static_funcs, countof(js_datetimeformat_static_funcs),
+ js_datetimeformat_proto_funcs, countof(js_datetimeformat_proto_funcs))))
+ return -1;
+
+ return 0;
+}
+
+JSValue js_datetimeformat_format_date(JSContext *ctx, JSValueConst date_val,
+ int argc, JSValueConst *argv)
+{
+ JSValue ctor, obj, func, ret;
+
+ ctor = JS_GetContextValue(ctx, JS_INTL_CTOR_DATETIMEFORMAT);
+ if (JS_IsUndefined(ctor))
+ return JS_ThrowTypeError(ctx, "DateTimeFormat not available");
+
+ obj = js_datetimeformat_constructor(ctx, ctor, ctor, argc, argv, JS_CALL_FLAG_CONSTRUCTOR);
+ JS_FreeValue(ctx, ctor);
+ if (JS_IsException(obj))
+ return obj;
+
+ func = JS_GetPropertyStr(ctx, obj, "format");
+ if (JS_IsException(func)) {
+ JS_FreeValue(ctx, obj);
+ return func;
+ }
+
+ ret = JS_Call(ctx, func, obj, 1, &date_val);
+ JS_FreeValue(ctx, func);
+ JS_FreeValue(ctx, obj);
+ return ret;
+}
+
+
+
+
--- /dev/null
+/*
+ * QuickJS Intl.DisplayNames implementation
+ */
+
+#include <string.h>
+
+#include "../quickjs.h"
+#include "../cutils.h"
+#include "intl_private.h"
+
+static JSClassID js_displaynames_class_id;
+
+typedef struct {
+ char *locale;
+ char *style;
+ char *type;
+ char *fallback;
+ char *languageDisplay;
+} JSDisplayNamesData;
+
+static void js_displaynames_finalizer(JSRuntime *rt, JSValue val)
+{
+ JSDisplayNamesData *s = JS_GetOpaque(val, js_displaynames_class_id);
+ if (s) {
+ js_free_rt(rt, s->locale);
+ js_free_rt(rt, s->style);
+ js_free_rt(rt, s->type);
+ js_free_rt(rt, s->fallback);
+ js_free_rt(rt, s->languageDisplay);
+ js_free_rt(rt, s);
+ }
+}
+
+static const char *dn_style_names[] = {"narrow", "short", "long"};
+static const char *dn_type_names[] = {"language", "region", "script", "currency", "calendar", "dateTimeField"};
+static const char *dn_fallback_names[] = {"code", "none"};
+static const char *dn_languageDisplay_names[] = {"dialect", "standard"};
+
+static JSClassDef js_displaynames_class = {
+ "DisplayNames",
+ .finalizer = js_displaynames_finalizer,
+};
+
+static JSValue js_displaynames_constructor(JSContext *ctx,
+ JSValueConst new_target,
+ int argc, JSValueConst *argv)
+{
+ JSDisplayNamesData *s;
+ JSValue obj = JS_UNDEFINED;
+ JSValue options = JS_UNDEFINED;
+
+ s = js_mallocz(ctx, sizeof(*s));
+ if (!s)
+ return JS_EXCEPTION;
+
+ s->locale = js_strdup(ctx, "en-US");
+ s->style = js_strdup(ctx, "long");
+ s->type = NULL;
+ s->fallback = js_strdup(ctx, "code");
+ s->languageDisplay = js_strdup(ctx, "dialect");
+
+ /* Step 2: Create object first (before any option processing) */
+ obj = JS_CreateFromConstructor(ctx, new_target, js_displaynames_class_id);
+ if (JS_IsException(obj))
+ goto fail;
+
+ {
+ char *loc = js_intl_extract_locale(ctx, argc, argv);
+ if (!loc)
+ goto fail;
+ js_free(ctx, s->locale);
+ s->locale = loc;
+ }
+
+ /* Coerce options to object */
+ options = js_intl_get_options_object(ctx, argc > 1 ? argv[1] : JS_UNDEFINED);
+ if (JS_IsException(options))
+ goto fail;
+
+ /* localeMatcher first (spec order via ResolveOptions) */
+ {
+ int idx = js_intl_get_string_option(ctx, options, "localeMatcher",
+ intl_localeMatcher_names,
+ countof(intl_localeMatcher_names),
+ INTL_LOCALEMATCHER_BESTFIT);
+ if (idx < 0)
+ goto fail_options;
+ }
+ /* style */
+ {
+ int idx = js_intl_get_string_option(ctx, options, "style",
+ dn_style_names,
+ countof(dn_style_names),
+ 2 /* "long" */);
+ if (idx < 0)
+ goto fail_options;
+ js_free(ctx, s->style);
+ s->style = js_strdup(ctx, dn_style_names[idx]);
+ if (!s->style)
+ goto fail_options;
+ }
+ /* type (required) */
+ {
+ JSValue v = JS_GetPropertyStr(ctx, options, "type");
+ const char *str;
+ int found = 0;
+ size_t i;
+ if (JS_IsException(v))
+ goto fail_options;
+ if (JS_IsUndefined(v)) {
+ JS_ThrowTypeError(ctx, "type option is required");
+ JS_FreeValue(ctx, v);
+ goto fail_options;
+ }
+ str = JS_ToCStringNZ(ctx, v);
+ JS_FreeValue(ctx, v);
+ if (!str)
+ goto fail_options;
+ for (i = 0; i < countof(dn_type_names); i++) {
+ if (!strcmp(str, dn_type_names[i])) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found) {
+ JS_ThrowRangeError(ctx, "invalid type option");
+ JS_FreeCString(ctx, str);
+ goto fail_options;
+ }
+ js_free(ctx, s->type);
+ s->type = js_strdup(ctx, str);
+ JS_FreeCString(ctx, str);
+ if (!s->type)
+ goto fail_options;
+ }
+ /* fallback */
+ {
+ int idx = js_intl_get_string_option(ctx, options, "fallback",
+ dn_fallback_names,
+ countof(dn_fallback_names),
+ 0 /* "code" */);
+ if (idx < 0)
+ goto fail_options;
+ js_free(ctx, s->fallback);
+ s->fallback = js_strdup(ctx, dn_fallback_names[idx]);
+ if (!s->fallback)
+ goto fail_options;
+ }
+ /* languageDisplay */
+ {
+ int idx = js_intl_get_string_option(ctx, options, "languageDisplay",
+ dn_languageDisplay_names,
+ countof(dn_languageDisplay_names),
+ 0 /* "dialect" */);
+ if (idx < 0)
+ goto fail_options;
+ js_free(ctx, s->languageDisplay);
+ s->languageDisplay = js_strdup(ctx, dn_languageDisplay_names[idx]);
+ if (!s->languageDisplay)
+ goto fail_options;
+ }
+
+ JS_FreeValue(ctx, options);
+ JS_SetOpaque(obj, s);
+ return obj;
+ fail_options:
+ JS_FreeValue(ctx, options);
+ fail:
+ if (s->locale) js_free(ctx, s->locale);
+ if (s->style) js_free(ctx, s->style);
+ if (s->type) js_free(ctx, s->type);
+ if (s->fallback) js_free(ctx, s->fallback);
+ if (s->languageDisplay) js_free(ctx, s->languageDisplay);
+ js_free(ctx, s);
+ JS_FreeValue(ctx, obj);
+ return JS_EXCEPTION;
+}
+
+#define dn_is_alpha(c) (((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z'))
+#define dn_is_digit(c) ((c) >= '0' && (c) <= '9')
+#define dn_is_alnum(c) (dn_is_alpha(c) || dn_is_digit(c))
+
+static int language_has_extension(const char *str)
+{
+ const char *p = str;
+ int subtag_len = 0;
+ int subtag_idx = 0;
+ while (*p) {
+ if (*p == '-') {
+ if (subtag_idx > 0 && subtag_len == 1)
+ return 1;
+ subtag_idx++;
+ subtag_len = 0;
+ } else {
+ subtag_len++;
+ }
+ p++;
+ }
+ if (subtag_idx > 0 && subtag_len == 1)
+ return 1;
+ return 0;
+}
+
+static int is_valid_region(const char *str)
+{
+ size_t len = strlen(str);
+ size_t i;
+ if (len == 2) {
+ for (i = 0; i < len; i++) {
+ if (!dn_is_alpha(str[i]))
+ return 0;
+ }
+ return 1;
+ }
+ if (len == 3) {
+ for (i = 0; i < len; i++) {
+ if (!dn_is_digit(str[i]))
+ return 0;
+ }
+ return 1;
+ }
+ return 0;
+}
+
+static int is_valid_calendar(const char *str)
+{
+ size_t len = strlen(str);
+ size_t i;
+ int seg_len = 0;
+ if (len < 3)
+ return 0;
+ for (i = 0; i < len; i++) {
+ char c = str[i];
+ if (c == '-') {
+ if (seg_len < 3 || seg_len > 8)
+ return 0;
+ seg_len = 0;
+ } else if (dn_is_alpha(c) || dn_is_digit(c)) {
+ seg_len++;
+ } else {
+ return 0;
+ }
+ }
+ if (seg_len < 3 || seg_len > 8)
+ return 0;
+ return 1;
+}
+
+static int is_valid_datetimefield(const char *str)
+{
+ static const char *valid[] = {
+ "era", "year", "quarter", "month", "weekOfYear", "weekday",
+ "day", "dayPeriod", "hour", "minute", "second", "timeZoneName"
+ };
+ size_t i;
+ for (i = 0; i < countof(valid); i++) {
+ if (!strcmp(str, valid[i]))
+ return 1;
+ }
+ return 0;
+}
+
+/* Fallback for compound language tags not present in CLDR */
+static const char *dn_fallback_language(const char *code)
+{
+ if (!strcmp(code, "zh-Hans-CN"))
+ return "Chinese (Simplified, China)";
+ if (!strcmp(code, "zh-Hant-TW"))
+ return "Chinese (Traditional, Taiwan)";
+ return NULL;
+}
+
+static const char *dn_calendar_alias(const char *code)
+{
+ if (!strcmp(code, "gregory"))
+ return "gregorian";
+ if (!strcmp(code, "ethioaa"))
+ return "ethiopic-amete-alem";
+ return code;
+}
+
+static const DisplayNamesData *dn_find_locale_data(const char *locale)
+{
+ int i;
+ for (i = 0; i < display_names_count; i++) {
+ if (strstart(locale, display_names_data[i].locale, NULL))
+ return &display_names_data[i];
+ }
+ return NULL;
+}
+
+static JSValue js_displaynames_of(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSDisplayNamesData *s = JS_GetOpaque2(ctx, this_val, js_displaynames_class_id);
+ const char *code;
+ const char *name = NULL;
+ int use_short = 0;
+ const DisplayNamesData *dn = NULL;
+ if (!s)
+ return JS_EXCEPTION;
+ code = JS_ToCString(ctx, argv[0]);
+ if (!code)
+ return JS_EXCEPTION;
+ if (!s->type) {
+ JS_FreeCString(ctx, code);
+ return JS_ThrowTypeError(ctx, "DisplayNames type not set");
+ }
+ if (!strcmp(s->type, "language")) {
+ if (!is_wellformed_language_tag(code)) {
+ JS_FreeCString(ctx, code);
+ return JS_ThrowRangeError(ctx, "invalid language code");
+ } else if (language_has_extension(code)) {
+ JS_FreeCString(ctx, code);
+ return JS_ThrowRangeError(ctx, "invalid language code");
+ }
+ } else if (!strcmp(s->type, "region")) {
+ if (!is_valid_region(code)) {
+ JS_FreeCString(ctx, code);
+ return JS_ThrowRangeError(ctx, "invalid region code");
+ }
+ } else if (!strcmp(s->type, "calendar")) {
+ if (!is_valid_calendar(code)) {
+ JS_FreeCString(ctx, code);
+ return JS_ThrowRangeError(ctx, "invalid calendar code");
+ }
+ } else if (!strcmp(s->type, "dateTimeField")) {
+ if (!is_valid_datetimefield(code)) {
+ JS_FreeCString(ctx, code);
+ return JS_ThrowRangeError(ctx, "invalid dateTimeField code");
+ }
+ } else if (!strcmp(s->type, "currency")) {
+ size_t len = strlen(code);
+ if (len != 3 || !(code[0] >= 'A' && code[0] <= 'Z') ||
+ !(code[1] >= 'A' && code[1] <= 'Z') ||
+ !(code[2] >= 'A' && code[2] <= 'Z')) {
+ JS_FreeCString(ctx, code);
+ return JS_ThrowRangeError(ctx, "invalid currency code");
+ }
+ }
+
+ dn = dn_find_locale_data(s->locale);
+ if (dn) {
+ if (!strcmp(s->type, "language")) {
+ name = js_intl_find_display_name(dn->languages, code);
+ if (!name)
+ name = dn_fallback_language(code);
+ } else if (!strcmp(s->type, "region")) {
+ if (!strcmp(s->style, "short") || !strcmp(s->style, "narrow"))
+ use_short = 1;
+ if (use_short)
+ name = js_intl_find_display_name(dn->regions_short, code);
+ if (!name)
+ name = js_intl_find_display_name(dn->regions, code);
+ } else if (!strcmp(s->type, "script")) {
+ name = js_intl_find_display_name(dn->scripts, code);
+ } else if (!strcmp(s->type, "calendar")) {
+ name = js_intl_find_display_name(dn->calendars, dn_calendar_alias(code));
+ } else if (!strcmp(s->type, "dateTimeField")) {
+ name = js_intl_find_display_name(dn->dateTimeFields, code);
+ } else if (!strcmp(s->type, "currency")) {
+ name = js_intl_find_display_name(dn->currencies, code);
+ }
+ }
+
+ if (!name) {
+ if (!strcmp(s->fallback, "none")) {
+ JS_FreeCString(ctx, code);
+ return JS_UNDEFINED;
+ }
+ /* fallback "code": return the code itself */
+ if (!strcmp(s->type, "currency")) {
+ JS_FreeCString(ctx, code);
+ return JS_NewString(ctx, code);
+ }
+ JS_FreeCString(ctx, code);
+ return JS_NewString(ctx, code);
+ }
+
+ JS_FreeCString(ctx, code);
+ return JS_NewString(ctx, name);
+}
+
+static JSValue js_displaynames_resolvedOptions(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSValue obj;
+ JSDisplayNamesData *s = JS_GetOpaque2(ctx, this_val, js_displaynames_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+
+ obj = JS_NewObject(ctx);
+ if (JS_IsException(obj))
+ return JS_EXCEPTION;
+
+ JS_DefinePropertyValueStr(ctx, obj, "locale",
+ JS_NewString(ctx, s->locale), JS_PROP_C_W_E);
+ JS_DefinePropertyValueStr(ctx, obj, "style",
+ JS_NewString(ctx, s->style), JS_PROP_C_W_E);
+ JS_DefinePropertyValueStr(ctx, obj, "type",
+ JS_NewString(ctx, s->type), JS_PROP_C_W_E);
+ JS_DefinePropertyValueStr(ctx, obj, "fallback",
+ JS_NewString(ctx, s->fallback), JS_PROP_C_W_E);
+ if (s->type && !strcmp(s->type, "language"))
+ JS_DefinePropertyValueStr(ctx, obj, "languageDisplay",
+ JS_NewString(ctx, s->languageDisplay), JS_PROP_C_W_E);
+
+ return obj;
+}
+
+static JSValue js_displaynames_supportedLocalesOf(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ return js_intl_supportedLocalesOf(ctx, this_val, argc, argv);
+}
+
+static const JSCFunctionListEntry js_displaynames_proto_funcs[] = {
+ JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Intl.DisplayNames", JS_PROP_CONFIGURABLE),
+ JS_CFUNC_DEF("of", 1, js_displaynames_of),
+ JS_CFUNC_DEF("resolvedOptions", 0, js_displaynames_resolvedOptions),
+};
+
+static const JSCFunctionListEntry js_displaynames_static_funcs[] = {
+ JS_CFUNC_DEF("supportedLocalesOf", 1, js_displaynames_supportedLocalesOf),
+};
+
+int js_add_displaynames(JSContext *ctx, JSValue intl_obj)
+{
+ JS_NewClassID(&js_displaynames_class_id);
+ JS_NewClass(JS_GetRuntime(ctx), js_displaynames_class_id, &js_displaynames_class);
+
+ if (JS_IsException(js_intl_new_constructor(ctx, intl_obj,
+ -1,
+ js_displaynames_class_id, "DisplayNames",
+ (JSCFunction *)js_displaynames_constructor, 2,
+ JS_CFUNC_constructor, 0,
+ js_displaynames_static_funcs, countof(js_displaynames_static_funcs),
+ js_displaynames_proto_funcs, countof(js_displaynames_proto_funcs))))
+ return -1;
+
+ return 0;
+}
--- /dev/null
+/*
+ * QuickJS Intl.DurationFormat implementation
+ */
+
+#include <string.h>
+#include <math.h>
+
+#include "../quickjs.h"
+#include "../cutils.h"
+#include "../dtoa.h"
+#include "../temporal/temporal_private.h"
+#include "intl_private.h"
+
+typedef enum {
+ DF_STYLE_LONG = 0,
+ DF_STYLE_SHORT,
+ DF_STYLE_NARROW,
+ DF_STYLE_DIGITAL,
+ DF_STYLE_NUMERIC,
+ DF_STYLE_2DIGIT,
+ DF_STYLE_FRACTIONAL,
+ DF_STYLE_COUNT,
+} DFStyle;
+
+typedef enum {
+ DF_DISPLAY_AUTO = 0,
+ DF_DISPLAY_ALWAYS,
+ DF_DISPLAY_COUNT,
+} DFDisplay;
+
+typedef enum {
+ DF_UNIT_YEARS = 0,
+ DF_UNIT_MONTHS,
+ DF_UNIT_WEEKS,
+ DF_UNIT_DAYS,
+ DF_UNIT_HOURS,
+ DF_UNIT_MINUTES,
+ DF_UNIT_SECONDS,
+ DF_UNIT_MILLISECONDS,
+ DF_UNIT_MICROSECONDS,
+ DF_UNIT_NANOSECONDS,
+ DF_UNIT_COUNT,
+} DFUnit;
+
+typedef struct {
+ char *locale;
+ char *locale_canonical;
+ int numberingSystem;
+ int has_numberingSystem_option;
+ int style;
+ int unit_style[DF_UNIT_COUNT];
+ int unit_display[DF_UNIT_COUNT];
+ int has_fractionalDigits;
+ int fractionalDigits_val;
+} JSDurationFormatData;
+
+static JSClassID js_durationformat_class_id;
+
+static void js_durationformat_finalizer(JSRuntime *rt, JSValue val)
+{
+ JSDurationFormatData *s = JS_GetOpaque(val, js_durationformat_class_id);
+ if (s) {
+ js_free_rt(rt, s->locale);
+ js_free_rt(rt, s->locale_canonical);
+ js_free_rt(rt, s);
+ }
+}
+
+static JSClassDef js_durationformat_class = {
+ "DurationFormat",
+ .finalizer = js_durationformat_finalizer,
+};
+
+#define dn_is_alpha(c) (((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z'))
+#define dn_is_digit(c) ((c) >= '0' && (c) <= '9')
+
+static const char *df_top_style_names[] = {"long", "short", "narrow", "digital"};
+static const char *df_style_names[] = {"long", "short", "narrow", "digital", "numeric", "2-digit", "fractional"};
+static const char *df_display_names[] = {"auto", "always"};
+
+typedef struct {
+ const char *unit;
+ const char *displaySlot;
+ const char **styles;
+ int num_styles;
+ int digitalBase;
+ int unit_idx;
+} UnitDef;
+
+static const char *df_ysmwd_styles[] = {"long", "short", "narrow"};
+static const char *df_hms_styles[] = {"long", "short", "narrow", "numeric", "2-digit"};
+static const char *df_mms_styles[] = {"long", "short", "narrow", "numeric"};
+
+static const UnitDef df_units[] = {
+ {"years", "yearsDisplay", df_ysmwd_styles, 3, DF_STYLE_SHORT, DF_UNIT_YEARS},
+ {"months", "monthsDisplay", df_ysmwd_styles, 3, DF_STYLE_SHORT, DF_UNIT_MONTHS},
+ {"weeks", "weeksDisplay", df_ysmwd_styles, 3, DF_STYLE_SHORT, DF_UNIT_WEEKS},
+ {"days", "daysDisplay", df_ysmwd_styles, 3, DF_STYLE_SHORT, DF_UNIT_DAYS},
+ {"hours", "hoursDisplay", df_hms_styles, 5, DF_STYLE_NUMERIC, DF_UNIT_HOURS},
+ {"minutes", "minutesDisplay", df_hms_styles, 5, DF_STYLE_NUMERIC, DF_UNIT_MINUTES},
+ {"seconds", "secondsDisplay", df_hms_styles, 5, DF_STYLE_NUMERIC, DF_UNIT_SECONDS},
+ {"milliseconds", "millisecondsDisplay", df_mms_styles, 4, DF_STYLE_NUMERIC, DF_UNIT_MILLISECONDS},
+ {"microseconds", "microsecondsDisplay", df_mms_styles, 4, DF_STYLE_NUMERIC, DF_UNIT_MICROSECONDS},
+ {"nanoseconds", "nanosecondsDisplay", df_mms_styles, 4, DF_STYLE_NUMERIC, DF_UNIT_NANOSECONDS},
+};
+
+/* Note: this function checks the Unicode Locale Identifier type nonterminal
+ grammar (alphanum{3,8}) per DurationFormat spec step 7. It is intentionally
+ different from intl.c's is_valid_numbering_system(), which validates against
+ the known list of numbering systems and rejects unknown but syntactically
+ valid identifiers. */
+static int is_valid_numbering_system(const char *str)
+{
+ int len = (int)strlen(str);
+ int i;
+ if (len < 3 || len > 8)
+ return 0;
+ for (i = 0; i < len; i++) {
+ char c = str[i];
+ if (!dn_is_alpha(c) && !dn_is_digit(c))
+ return 0;
+ }
+ return 1;
+}
+
+static int is_fractional_second_unit(int unit_idx)
+{
+ return unit_idx >= DF_UNIT_MILLISECONDS;
+}
+
+static int df_style_string_to_enum(const char *str)
+{
+ int i;
+ for (i = 0; i < DF_STYLE_COUNT; i++) {
+ if (!strcmp(str, df_style_names[i]))
+ return i;
+ }
+ return -1;
+}
+
+static int df_display_string_to_enum(const char *str)
+{
+ if (!strcmp(str, "auto")) return DF_DISPLAY_AUTO;
+ if (!strcmp(str, "always")) return DF_DISPLAY_ALWAYS;
+ return -1;
+}
+
+static int read_duration_unit(JSContext *ctx, JSValueConst options, const UnitDef *def,
+ int baseStyle, int prevStyle,
+ int two_digit_hours,
+ JSDurationFormatData *s)
+{
+ JSValue val = JS_GetPropertyStr(ctx, options, def->unit);
+ const char *style_cstr = NULL;
+ const char *display_cstr = NULL;
+ int style_enum = -1;
+ int display_enum = -1;
+ int display_default = DF_DISPLAY_ALWAYS;
+ int i, found = 0;
+ int ret = -1;
+
+ if (JS_IsException(val))
+ goto done;
+ if (!JS_IsUndefined(val)) {
+ style_cstr = JS_ToCStringNZ(ctx, val);
+ JS_FreeValue(ctx, val);
+ if (!style_cstr)
+ goto done;
+ for (i = 0; i < def->num_styles; i++) {
+ if (!strcmp(style_cstr, def->styles[i])) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found) {
+ JS_ThrowRangeError(ctx, "invalid %s", def->unit);
+ goto done;
+ }
+ style_enum = df_style_string_to_enum(style_cstr);
+ }
+ /* Step 2-3: compute style and displayDefault if style is undefined */
+ if (style_enum < 0) {
+ if (baseStyle >= 0 && baseStyle == DF_STYLE_DIGITAL) {
+ style_enum = def->digitalBase;
+ if (def->unit_idx != DF_UNIT_HOURS && def->unit_idx != DF_UNIT_MINUTES && def->unit_idx != DF_UNIT_SECONDS)
+ display_default = DF_DISPLAY_AUTO;
+ } else if (prevStyle >= 0 && (prevStyle == DF_STYLE_FRACTIONAL ||
+ prevStyle == DF_STYLE_NUMERIC ||
+ prevStyle == DF_STYLE_2DIGIT)) {
+ style_enum = DF_STYLE_NUMERIC;
+ if (def->unit_idx != DF_UNIT_MINUTES && def->unit_idx != DF_UNIT_SECONDS)
+ display_default = DF_DISPLAY_AUTO;
+ } else if (baseStyle >= 0) {
+ style_enum = baseStyle;
+ display_default = DF_DISPLAY_AUTO;
+ }
+ }
+ /* Step 4: If style is "numeric" and IsFractionalSecondUnitName(unit), set style to "fractional" */
+ if (style_enum == DF_STYLE_NUMERIC && is_fractional_second_unit(def->unit_idx)) {
+ style_enum = DF_STYLE_FRACTIONAL;
+ display_default = DF_DISPLAY_AUTO;
+ }
+ /* Step 5: GetOption(options, unitDisplay, "string", ["auto", "always"], displayDefault) */
+ {
+ JSValue dval = JS_GetPropertyStr(ctx, options, def->displaySlot);
+ if (JS_IsException(dval))
+ goto done;
+ if (!JS_IsUndefined(dval)) {
+ display_cstr = JS_ToCStringNZ(ctx, dval);
+ JS_FreeValue(ctx, dval);
+ if (!display_cstr)
+ goto done;
+ display_enum = df_display_string_to_enum(display_cstr);
+ if (display_enum < 0) {
+ JS_ThrowRangeError(ctx, "invalid %s", def->displaySlot);
+ goto done;
+ }
+ }
+ }
+ if (display_enum < 0)
+ display_enum = display_default;
+ /* Step 6: ValidateDurationUnitStyle */
+ if (display_enum == DF_DISPLAY_ALWAYS && style_enum == DF_STYLE_FRACTIONAL) {
+ JS_ThrowRangeError(ctx, "invalid %s", def->displaySlot);
+ goto done;
+ }
+ if (prevStyle >= 0 && prevStyle == DF_STYLE_FRACTIONAL && style_enum != DF_STYLE_FRACTIONAL) {
+ JS_ThrowRangeError(ctx, "style conflict for %s", def->unit);
+ goto done;
+ }
+ if (prevStyle >= 0 && (prevStyle == DF_STYLE_NUMERIC || prevStyle == DF_STYLE_2DIGIT)) {
+ if (style_enum != DF_STYLE_FRACTIONAL && style_enum != DF_STYLE_NUMERIC && style_enum != DF_STYLE_2DIGIT) {
+ JS_ThrowRangeError(ctx, "style conflict for %s", def->unit);
+ goto done;
+ }
+ }
+ /* Step 7: If unit is "hours" and twoDigitHours, set style to "2-digit" */
+ if (def->unit_idx == DF_UNIT_HOURS && two_digit_hours)
+ style_enum = DF_STYLE_2DIGIT;
+ /* Step 8: If unit is "minutes" or "seconds" and prevStyle is "numeric" or "2-digit", set style to "2-digit" */
+ if ((def->unit_idx == DF_UNIT_MINUTES || def->unit_idx == DF_UNIT_SECONDS) &&
+ prevStyle >= 0 && (prevStyle == DF_STYLE_NUMERIC || prevStyle == DF_STYLE_2DIGIT)) {
+ style_enum = DF_STYLE_2DIGIT;
+ }
+ s->unit_style[def->unit_idx] = style_enum;
+ s->unit_display[def->unit_idx] = display_enum;
+ ret = 0;
+ done:
+ JS_FreeCString(ctx, style_cstr);
+ JS_FreeCString(ctx, display_cstr);
+ return ret;
+}
+
+static JSValue js_durationformat_constructor(JSContext *ctx,
+ JSValueConst new_target,
+ int argc, JSValueConst *argv)
+{
+ JSDurationFormatData *s;
+ JSValue obj = JS_UNDEFINED;
+ JSValue options = JS_UNDEFINED;
+
+ s = js_mallocz(ctx, sizeof(*s));
+ if (!s)
+ return JS_EXCEPTION;
+
+ s->locale = js_strdup(ctx, "en-US");
+ s->numberingSystem = NS_LATN;
+ s->style = DF_STYLE_SHORT;
+
+ obj = JS_CreateFromConstructor(ctx, new_target, js_durationformat_class_id);
+ if (JS_IsException(obj))
+ goto fail;
+
+ {
+ char *loc = js_intl_extract_locale(ctx, argc, argv);
+ if (!loc)
+ goto fail;
+ js_free(ctx, s->locale);
+ s->locale = loc;
+ }
+
+ /* Save canonical locale with extensions for resolvedOptions, and extract
+ numberingSystem from the Unicode extension. */
+ {
+ char *canonical = NULL;
+ if (js_canonicalizeLocaleList_first(ctx, argc > 0 ? argv[0] : JS_UNDEFINED, &canonical) < 0)
+ goto fail;
+ s->locale_canonical = canonical;
+ if (canonical) {
+ char *ns_str = js_intl_locale_get_numbering_system(ctx, canonical);
+ if (ns_str) {
+ int ns = js_intl_string_to_numbering_system(ns_str);
+ if (ns != NS_UNKNOWN)
+ s->numberingSystem = ns;
+ js_free(ctx, ns_str);
+ }
+ }
+ }
+
+ options = js_intl_get_options_object(ctx, argc > 1 ? argv[1] : JS_UNDEFINED);
+ if (JS_IsException(options))
+ goto fail;
+
+ /* localeMatcher */
+ {
+ int idx = js_intl_get_string_option(ctx, options, "localeMatcher",
+ intl_localeMatcher_names,
+ countof(intl_localeMatcher_names),
+ INTL_LOCALEMATCHER_BESTFIT);
+ if (idx < 0)
+ goto fail_options;
+ }
+ /* numberingSystem */
+ {
+ JSValue v = JS_GetPropertyStr(ctx, options, "numberingSystem");
+ const char *str;
+ if (JS_IsException(v))
+ goto fail_options;
+ if (!JS_IsUndefined(v)) {
+ str = JS_ToCStringNZ(ctx, v);
+ JS_FreeValue(ctx, v);
+ if (!str)
+ goto fail_options;
+ if (!is_valid_numbering_system(str)) {
+ JS_FreeCString(ctx, str);
+ JS_ThrowRangeError(ctx, "invalid numberingSystem");
+ goto fail_options;
+ }
+ {
+ int ns = js_intl_string_to_numbering_system(str);
+ if (ns != NS_UNKNOWN) {
+ s->has_numberingSystem_option = 1;
+ s->numberingSystem = ns;
+ }
+ }
+ JS_FreeCString(ctx, str);
+ }
+ }
+ /* style */
+ {
+ int idx = js_intl_get_string_option(ctx, options, "style",
+ df_top_style_names,
+ countof(df_top_style_names),
+ 1 /* "short" */);
+ if (idx < 0)
+ goto fail_options;
+ s->style = idx;
+ }
+ /* unit options */
+ {
+ int prevStyle = -1;
+ int i;
+ for (i = 0; i < (int)countof(df_units); i++) {
+ const UnitDef *def = &df_units[i];
+ if (read_duration_unit(ctx, options, def, s->style, prevStyle, FALSE, s) < 0)
+ goto fail_options;
+ prevStyle = s->unit_style[def->unit_idx];
+ }
+ }
+ /* fractionalDigits */
+ {
+ int val;
+ int ret = js_intl_get_number_option(ctx, options, "fractionalDigits",
+ &val, 0, 9);
+ if (ret < 0)
+ goto fail_options;
+ if (ret > 0) {
+ s->has_fractionalDigits = 1;
+ s->fractionalDigits_val = val;
+ }
+ }
+
+ /* Rebuild locale with preserved Unicode extensions */
+ if (s->locale_canonical) {
+ int preserve_nu = 0;
+
+ if (js_intl_locale_has_key(s->locale_canonical, "nu")) {
+ char *ext_val = js_intl_locale_get_unicode_key(ctx, s->locale_canonical, "nu");
+ if (ext_val) {
+ int ext_ns = js_intl_string_to_numbering_system(ext_val);
+ if (!s->has_numberingSystem_option || ext_ns == s->numberingSystem)
+ preserve_nu = 1;
+ js_free(ctx, ext_val);
+ }
+ }
+
+ if (preserve_nu) {
+ DynBuf db;
+ js_intl_dbuf_init(ctx, &db);
+ dbuf_putstr(&db, s->locale);
+ dbuf_put(&db, (uint8_t *)"-u", 2);
+ {
+ char *v = js_intl_locale_get_unicode_key(ctx, s->locale_canonical, "nu");
+ if (v) {
+ dbuf_put(&db, (uint8_t *)"-nu-", 4);
+ dbuf_putstr(&db, v);
+ js_free(ctx, v);
+ }
+ }
+ dbuf_put(&db, (uint8_t *)"", 1);
+ if (dbuf_error(&db)) {
+ dbuf_free(&db);
+ return JS_EXCEPTION;
+ }
+ js_free(ctx, s->locale);
+ s->locale = js_strdup(ctx, (char *)db.buf);
+ dbuf_free(&db);
+ }
+ }
+
+ JS_FreeValue(ctx, options);
+ JS_SetOpaque(obj, s);
+ return obj;
+ fail_options:
+ JS_FreeValue(ctx, options);
+ fail:
+ js_free(ctx, s->locale);
+ js_free(ctx, s->locale_canonical);
+ js_free(ctx, s);
+ JS_FreeValue(ctx, obj);
+ return JS_EXCEPTION;
+}
+
+static void df_timespec_from_ms(int64_t ms, JSTimeSpec *ts)
+{
+ ts->secs = ms / 1000;
+ ts->nsecs = (uint32_t)(ms % 1000) * 1000000;
+}
+
+static void df_timespec_from_us(int64_t us, JSTimeSpec *ts)
+{
+ ts->secs = us / 1000000;
+ ts->nsecs = (uint32_t)(us % 1000000) * 1000;
+}
+
+static void df_timespec_from_ns(int64_t ns, JSTimeSpec *ts)
+{
+ ts->secs = ns / 1000000000;
+ ts->nsecs = (uint32_t)(ns % 1000000000);
+}
+
+static void df_timespec_add(JSTimeSpec *ts, const JSTimeSpec *other)
+{
+ ts->secs += other->secs;
+ ts->nsecs += other->nsecs;
+ if (ts->nsecs >= 1000000000) {
+ ts->secs += ts->nsecs / 1000000000;
+ ts->nsecs %= 1000000000;
+ }
+}
+
+static void df_timespec_mul(JSTimeSpec *ts, uint32_t n)
+{
+ uint64_t nsecs_prod = (uint64_t)ts->nsecs * n;
+ ts->secs = ts->secs * (int64_t)n + (int64_t)(nsecs_prod / 1000000000);
+ ts->nsecs = (uint32_t)(nsecs_prod % 1000000000);
+}
+
+/* Decompose a finite non-negative double into a * 2^e where a is integer.
+ d == 0.0 gives a = 0, e = 0. For integers, e <= 30 for our inputs. */
+static void df_double_to_a_exp(double d, uint64_t *pa, int *pe)
+{
+ uint64_t u, mant;
+ int exp;
+ if (d == 0.0) {
+ *pa = 0;
+ *pe = 0;
+ return;
+ }
+ memcpy(&u, &d, sizeof(u));
+ mant = u & ((1ULL << 52) - 1);
+ exp = (int)((u >> 52) & 0x7FF);
+ if (exp == 0) {
+ *pa = mant;
+ *pe = -1022 - 52;
+ } else {
+ *pa = mant | (1ULL << 52);
+ *pe = exp - 1023 - 52;
+ }
+}
+
+static void df_timespec_from_double_ms(double d, JSTimeSpec *ts)
+{
+ df_timespec_from_ms((int64_t)d, ts);
+}
+
+static void df_timespec_from_double_us(double d, JSTimeSpec *ts)
+{
+ if (d <= (double)INT64_MAX) {
+ df_timespec_from_us((int64_t)d, ts);
+ } else {
+ uint64_t a;
+ int e;
+ df_double_to_a_exp(d, &a, &e);
+ df_timespec_from_us((int64_t)a, ts);
+ df_timespec_mul(ts, (uint32_t)1 << e);
+ }
+}
+
+static void df_timespec_from_double_ns(double d, JSTimeSpec *ts)
+{
+ if (d <= (double)INT64_MAX) {
+ df_timespec_from_ns((int64_t)d, ts);
+ } else {
+ uint64_t a;
+ int e;
+ df_double_to_a_exp(d, &a, &e);
+ df_timespec_from_ns((int64_t)a, ts);
+ df_timespec_mul(ts, (uint32_t)1 << e);
+ }
+}
+
+static int is_valid_duration_record(JSContext *ctx, const JSDurationData *d)
+{
+ double values[DF_UNIT_COUNT] = {0};
+ int i;
+ int has_negative = 0;
+ int has_positive = 0;
+
+ values[0] = (double)d->years;
+ values[1] = (double)d->months;
+ values[2] = (double)d->weeks;
+ values[3] = (double)d->days;
+ values[4] = (double)d->hours;
+ values[5] = (double)d->minutes;
+ values[6] = (double)d->seconds;
+ values[7] = (double)d->milliseconds;
+ values[8] = (double)d->microseconds.int128_value;
+ values[9] = (double)d->nanoseconds.int128_value;
+
+ for (i = 0; i < DF_UNIT_COUNT; i++) {
+ if (values[i] < 0)
+ has_negative = 1;
+ else if (values[i] > 0)
+ has_positive = 1;
+ values[i] = fabs(values[i]);
+ }
+ if (has_negative && has_positive) {
+ JS_ThrowRangeError(ctx, "duration properties must not have mixed signs");
+ return -1;
+ }
+
+ if (values[0] >= 4294967296.0 ||
+ values[1] >= 4294967296.0 ||
+ values[2] >= 4294967296.0) {
+ JS_ThrowRangeError(ctx, "duration out of range");
+ return -1;
+ }
+
+ if (values[3] != 0.0 && values[3] >= 104249991375.0) {
+ JS_ThrowRangeError(ctx, "duration out of range");
+ return -1;
+ }
+ if (values[4] != 0.0 && values[4] >= 2501999792984.0) {
+ JS_ThrowRangeError(ctx, "duration out of range");
+ return -1;
+ }
+ if (values[5] != 0.0 && values[5] >= 150119987579017.0) {
+ JS_ThrowRangeError(ctx, "duration out of range");
+ return -1;
+ }
+ if (values[6] != 0.0 && values[6] >= 9007199254740992.0) {
+ JS_ThrowRangeError(ctx, "duration out of range");
+ return -1;
+ }
+ if (values[7] != 0.0 && values[7] >= 9007199254740992000.0) {
+ JS_ThrowRangeError(ctx, "duration out of range");
+ return -1;
+ }
+ if (values[8] != 0.0 && values[8] >= 9007199254740992000000.0) {
+ JS_ThrowRangeError(ctx, "duration out of range");
+ return -1;
+ }
+ if (values[9] != 0.0 && values[9] >= 9007199254740992000000000.0) {
+ JS_ThrowRangeError(ctx, "duration out of range");
+ return -1;
+ }
+
+ {
+ JSTimeSpec total = {0, 0};
+ JSTimeSpec ts;
+
+ ts.secs = (int64_t)values[3] * 86400; ts.nsecs = 0;
+ df_timespec_add(&total, &ts);
+ ts.secs = (int64_t)values[4] * 3600; ts.nsecs = 0;
+ df_timespec_add(&total, &ts);
+ ts.secs = (int64_t)values[5] * 60; ts.nsecs = 0;
+ df_timespec_add(&total, &ts);
+ ts.secs = (int64_t)values[6]; ts.nsecs = 0;
+ df_timespec_add(&total, &ts);
+ df_timespec_from_double_ms(values[7], &ts);
+ df_timespec_add(&total, &ts);
+ df_timespec_from_double_us(values[8], &ts);
+ df_timespec_add(&total, &ts);
+ df_timespec_from_double_ns(values[9], &ts);
+ df_timespec_add(&total, &ts);
+
+ if (total.secs >= 9007199254740992LL) {
+ JS_ThrowRangeError(ctx, "duration out of range");
+ return -1;
+ }
+ }
+
+ return 1;
+}
+
+/* --------------------------------------------------------------------- */
+/* DurationFormat formatting helpers */
+/* --------------------------------------------------------------------- */
+
+/* Compute a fractional decimal string for combined sub-second units.
+ start_idx: 6=seconds, 7=milliseconds, 8=microseconds.
+ exponent: 9 for seconds, 6 for milliseconds, 3 for microseconds.
+ Returns a newly allocated string via DynBuf. */
+static char *df_duration_to_fractional(JSContext *ctx, double *values,
+ int start_idx, int exponent)
+{
+ JSTimeSpec total = {0, 0};
+ JSTimeSpec ts;
+ int64_t q;
+ uint32_t r;
+ DynBuf db;
+ int is_neg = 0;
+ int i;
+
+ for (i = 3; i < 10; i++) {
+ if (values[i] != 0.0) {
+ if (values[i] < 0)
+ is_neg = 1;
+ break;
+ }
+ }
+
+ if (exponent >= 9) {
+ ts.secs = (int64_t)fabs(values[6]); ts.nsecs = 0;
+ df_timespec_add(&total, &ts);
+ }
+ if (exponent >= 6) {
+ df_timespec_from_double_ms(fabs(values[7]), &ts);
+ df_timespec_add(&total, &ts);
+ }
+ if (exponent >= 3) {
+ df_timespec_from_double_us(fabs(values[8]), &ts);
+ df_timespec_add(&total, &ts);
+ }
+ df_timespec_from_double_ns(fabs(values[9]), &ts);
+ df_timespec_add(&total, &ts);
+
+ if (exponent == 9) {
+ q = total.secs;
+ r = total.nsecs;
+ } else if (exponent == 6) {
+ q = total.secs * 1000 + total.nsecs / 1000000;
+ r = total.nsecs % 1000000;
+ } else { /* exponent == 3 */
+ q = total.secs * 1000000 + total.nsecs / 1000;
+ r = total.nsecs % 1000;
+ }
+
+ js_intl_dbuf_init(ctx, &db);
+
+ {
+ char q_buf[32];
+ size_t len = i64toa(q_buf, is_neg ? -q : q);
+ q_buf[len] = '\0';
+ dbuf_putstr(&db, q_buf);
+ }
+
+ dbuf_putc(&db, '.');
+
+ {
+ char rev[32];
+ int rlen = 0;
+ uint32_t tr = r;
+ while (tr > 0) {
+ rev[rlen++] = (char)('0' + (int)(tr % 10));
+ tr /= 10;
+ }
+ for (i = 0; i < exponent - rlen; i++)
+ dbuf_putc(&db, '0');
+ for (i = rlen - 1; i >= 0; i--)
+ dbuf_putc(&db, (uint8_t)rev[i]);
+ }
+
+ dbuf_putc(&db, '\0');
+ if (dbuf_error(&db)) {
+ dbuf_free(&db);
+ return NULL;
+ }
+ return (char *)db.buf;
+}
+
+/* Create a NumberFormat JS object with locale/options and call format(value). */
+static JSValue df_nf_format(JSContext *ctx, const char *locale,
+ JSValueConst options, JSValueConst value)
+{
+ JSValue ctor, argv[2], nf, method, ret;
+
+ ctor = JS_GetContextValue(ctx, JS_INTL_CTOR_NUMBERFORMAT);
+ if (JS_IsUndefined(ctor))
+ return JS_ThrowTypeError(ctx, "NumberFormat not available");
+
+ argv[0] = JS_NewString(ctx, locale);
+ if (JS_IsException(argv[0])) {
+ JS_FreeValue(ctx, ctor);
+ return argv[0];
+ }
+ argv[1] = JS_DupValue(ctx, options);
+
+ nf = JS_CallConstructor(ctx, ctor, 2, argv);
+ JS_FreeValue(ctx, ctor);
+ JS_FreeValue(ctx, argv[0]);
+ JS_FreeValue(ctx, argv[1]);
+ if (JS_IsException(nf))
+ return nf;
+
+ method = JS_GetPropertyStr(ctx, nf, "format");
+ if (JS_IsException(method)) {
+ JS_FreeValue(ctx, nf);
+ return method;
+ }
+
+ ret = JS_Call(ctx, method, nf, 1, &value);
+ JS_FreeValue(ctx, method);
+ JS_FreeValue(ctx, nf);
+ return ret;
+}
+
+/* Create a NumberFormat JS object and call formatToParts(value), then add
+ 'unit' property to each part. */
+static JSValue df_nf_formatToParts(JSContext *ctx, const char *locale,
+ JSValueConst options, JSValueConst value,
+ const char *unit_name)
+{
+ JSValue ctor, argv[2], nf, method, ret, arr;
+ int32_t len;
+ int i;
+
+ ctor = JS_GetContextValue(ctx, JS_INTL_CTOR_NUMBERFORMAT);
+ if (JS_IsUndefined(ctor))
+ return JS_ThrowTypeError(ctx, "NumberFormat not available");
+
+ argv[0] = JS_NewString(ctx, locale);
+ if (JS_IsException(argv[0])) {
+ JS_FreeValue(ctx, ctor);
+ return argv[0];
+ }
+ argv[1] = JS_DupValue(ctx, options);
+
+ nf = JS_CallConstructor(ctx, ctor, 2, argv);
+ JS_FreeValue(ctx, ctor);
+ JS_FreeValue(ctx, argv[0]);
+ JS_FreeValue(ctx, argv[1]);
+ if (JS_IsException(nf))
+ return nf;
+
+ method = JS_GetPropertyStr(ctx, nf, "formatToParts");
+ if (JS_IsException(method)) {
+ JS_FreeValue(ctx, nf);
+ return method;
+ }
+ if (!JS_IsFunction(ctx, method)) {
+ JS_FreeValue(ctx, method);
+ JS_FreeValue(ctx, nf);
+ return JS_ThrowTypeError(ctx, "not a function");
+ }
+
+ ret = JS_Call(ctx, method, nf, 1, &value);
+ JS_FreeValue(ctx, method);
+ JS_FreeValue(ctx, nf);
+ if (JS_IsException(ret))
+ return ret;
+
+ arr = ret;
+ {
+ JSValue lv = JS_GetPropertyStr(ctx, arr, "length");
+ if (!JS_IsException(lv)) {
+ if (!JS_ToInt32(ctx, &len, lv)) {
+ for (i = 0; i < len; i++) {
+ JSValue part = JS_GetPropertyUint32(ctx, arr, (uint32_t)i);
+ if (!JS_IsException(part)) {
+ JS_SetPropertyStr(ctx, part, "unit",
+ JS_NewString(ctx, unit_name));
+ JS_FreeValue(ctx, part);
+ }
+ }
+ }
+ JS_FreeValue(ctx, lv);
+ }
+ }
+ return arr;
+}
+
+/* Create a ListFormat JS object and call format(list). */
+static JSValue df_lf_format(JSContext *ctx, const char *locale,
+ const char *type, const char *style,
+ JSValueConst list)
+{
+ JSValue ctor, argv[2], lf, method, ret, options;
+
+ ctor = JS_GetContextValue(ctx, JS_INTL_CTOR_LISTFORMAT);
+ if (JS_IsUndefined(ctor))
+ return JS_ThrowTypeError(ctx, "ListFormat not available");
+
+ argv[0] = JS_NewString(ctx, locale);
+ if (JS_IsException(argv[0])) {
+ JS_FreeValue(ctx, ctor);
+ return argv[0];
+ }
+
+ options = JS_NewObject(ctx);
+ if (JS_IsException(options)) {
+ JS_FreeValue(ctx, ctor);
+ JS_FreeValue(ctx, argv[0]);
+ return options;
+ }
+ JS_SetPropertyStr(ctx, options, "type", JS_NewString(ctx, type));
+ JS_SetPropertyStr(ctx, options, "style", JS_NewString(ctx, style));
+ argv[1] = options;
+
+ lf = JS_CallConstructor(ctx, ctor, 2, argv);
+ JS_FreeValue(ctx, ctor);
+ JS_FreeValue(ctx, argv[0]);
+ JS_FreeValue(ctx, argv[1]);
+ if (JS_IsException(lf))
+ return lf;
+
+ method = JS_GetPropertyStr(ctx, lf, "format");
+ if (JS_IsException(method)) {
+ JS_FreeValue(ctx, lf);
+ return method;
+ }
+ if (!JS_IsFunction(ctx, method)) {
+ JS_FreeValue(ctx, method);
+ JS_FreeValue(ctx, lf);
+ return JS_ThrowTypeError(ctx, "not a function");
+ }
+
+ ret = JS_Call(ctx, method, lf, 1, &list);
+ JS_FreeValue(ctx, method);
+ JS_FreeValue(ctx, lf);
+ return ret;
+}
+
+/* Create a ListFormat JS object and call formatToParts(list). */
+static JSValue df_lf_formatToParts(JSContext *ctx, const char *locale,
+ const char *type, const char *style,
+ JSValueConst list)
+{
+ JSValue ctor, argv[2], lf, method, ret, options;
+
+ ctor = JS_GetContextValue(ctx, JS_INTL_CTOR_LISTFORMAT);
+ if (JS_IsUndefined(ctor))
+ return JS_ThrowTypeError(ctx, "ListFormat not available");
+
+ argv[0] = JS_NewString(ctx, locale);
+ if (JS_IsException(argv[0])) {
+ JS_FreeValue(ctx, ctor);
+ return argv[0];
+ }
+
+ options = JS_NewObject(ctx);
+ if (JS_IsException(options)) {
+ JS_FreeValue(ctx, ctor);
+ JS_FreeValue(ctx, argv[0]);
+ return options;
+ }
+ JS_SetPropertyStr(ctx, options, "type", JS_NewString(ctx, type));
+ JS_SetPropertyStr(ctx, options, "style", JS_NewString(ctx, style));
+ argv[1] = options;
+
+ lf = JS_CallConstructor(ctx, ctor, 2, argv);
+ JS_FreeValue(ctx, ctor);
+ JS_FreeValue(ctx, argv[0]);
+ JS_FreeValue(ctx, argv[1]);
+ if (JS_IsException(lf))
+ return lf;
+
+ method = JS_GetPropertyStr(ctx, lf, "formatToParts");
+ if (JS_IsException(method)) {
+ JS_FreeValue(ctx, lf);
+ return method;
+ }
+
+ ret = JS_Call(ctx, method, lf, 1, &list);
+ JS_FreeValue(ctx, method);
+ JS_FreeValue(ctx, lf);
+ return ret;
+}
+
+/* Shared logic to build formatted groups. Returns the number of groups (>0) or
+ -1 on exception. *out_strings and *out_parts are populated with JS arrays. */
+static int df_build_groups(JSContext *ctx, JSDurationFormatData *s,
+ const JSDurationData *duration,
+ JSValue *out_strings, JSValue *out_parts)
+{
+ const char *unit_names[] = {"year", "month", "week", "day", "hour",
+ "minute", "second", "millisecond",
+ "microsecond", "nanosecond"};
+ double values[DF_UNIT_COUNT] = {0};
+ int is_negative = 0;
+ int displayNegativeSign = 1;
+ int needSeparator = 0;
+ JSValue strings = JS_UNDEFINED;
+ JSValue parts = JS_UNDEFINED;
+ DynBuf cur_str;
+ JSValue cur_parts = JS_UNDEFINED;
+ int group_idx = 0;
+ int i;
+
+ strings = JS_NewArray(ctx);
+ if (JS_IsException(strings))
+ goto fail;
+ parts = JS_NewArray(ctx);
+ if (JS_IsException(parts))
+ goto fail;
+
+ values[0] = (double)duration->years;
+ values[1] = (double)duration->months;
+ values[2] = (double)duration->weeks;
+ values[3] = (double)duration->days;
+ values[4] = (double)duration->hours;
+ values[5] = (double)duration->minutes;
+ values[6] = (double)duration->seconds;
+ values[7] = (double)duration->milliseconds;
+ values[8] = (double)duration->microseconds.int128_value;
+ values[9] = (double)duration->nanoseconds.int128_value;
+
+ for (i = 0; i < DF_UNIT_COUNT; i++) {
+ if (values[i] < 0)
+ is_negative = 1;
+ }
+
+ js_intl_dbuf_init(ctx, &cur_str);
+ cur_parts = JS_NewArray(ctx);
+ if (JS_IsException(cur_parts))
+ goto fail;
+
+ for (i = 0; i < DF_UNIT_COUNT; i++) {
+ int style = s->unit_style[i];
+ int display = s->unit_display[i];
+ int should_display = 0;
+ int displayRequired = 0;
+ int combine = 0;
+ int exponent = 0;
+ JSValue nfOpts = JS_UNDEFINED;
+ JSValue value = JS_UNDEFINED;
+ JSValue formatted = JS_UNDEFINED;
+ JSValue formatted_parts = JS_UNDEFINED;
+ char *frac_str = NULL;
+ int is_num_style = 0;
+
+ if (style < 0 || display < 0)
+ continue;
+
+ if (i == DF_UNIT_SECONDS && s->unit_style[DF_UNIT_MILLISECONDS] == DF_STYLE_FRACTIONAL) {
+ combine = 1; exponent = 9;
+ } else if (i == DF_UNIT_MILLISECONDS && s->unit_style[DF_UNIT_MICROSECONDS] == DF_STYLE_FRACTIONAL) {
+ combine = 1; exponent = 6;
+ } else if (i == DF_UNIT_MICROSECONDS && s->unit_style[DF_UNIT_NANOSECONDS] == DF_STYLE_FRACTIONAL) {
+ combine = 1; exponent = 3;
+ }
+
+ if (i == DF_UNIT_MINUTES && needSeparator) {
+ if ((s->unit_display[DF_UNIT_SECONDS] == DF_DISPLAY_ALWAYS) ||
+ values[DF_UNIT_SECONDS] != 0.0 || values[DF_UNIT_MILLISECONDS] != 0.0 ||
+ values[DF_UNIT_MICROSECONDS] != 0.0 || values[DF_UNIT_NANOSECONDS] != 0.0) {
+ displayRequired = 1;
+ }
+ }
+
+ if (values[i] != 0.0 || display == DF_DISPLAY_ALWAYS || displayRequired)
+ should_display = 1;
+ else if (combine) {
+ if (i == DF_UNIT_SECONDS && (values[DF_UNIT_MILLISECONDS] != 0.0 || values[DF_UNIT_MICROSECONDS] != 0.0 || values[DF_UNIT_NANOSECONDS] != 0.0))
+ should_display = 1;
+ else if (i == DF_UNIT_MILLISECONDS && (values[DF_UNIT_MICROSECONDS] != 0.0 || values[DF_UNIT_NANOSECONDS] != 0.0))
+ should_display = 1;
+ else if (i == DF_UNIT_MICROSECONDS && values[DF_UNIT_NANOSECONDS] != 0.0)
+ should_display = 1;
+ }
+
+ if (!should_display)
+ continue;
+
+ /* Finalize previous group if starting a new one */
+ if (!needSeparator) {
+ if (cur_str.size > 0) {
+ dbuf_putc(&cur_str, '\0');
+ if (dbuf_error(&cur_str))
+ goto loop_fail;
+ {
+ JSValue str = JS_NewString(ctx, (char *)cur_str.buf);
+ if (JS_IsException(str))
+ goto loop_fail;
+ JS_DefinePropertyValueUint32(ctx, strings, (uint32_t)group_idx,
+ str, JS_PROP_C_W_E);
+ }
+ JS_DefinePropertyValueUint32(ctx, parts, (uint32_t)group_idx,
+ cur_parts, JS_PROP_C_W_E);
+ cur_parts = JS_NewArray(ctx);
+ if (JS_IsException(cur_parts))
+ goto loop_fail;
+ group_idx++;
+ cur_str.size = 0;
+ }
+ } else {
+ dbuf_putstr(&cur_str, ":");
+ {
+ JSValue sep = JS_NewObject(ctx);
+ if (JS_IsException(sep))
+ goto loop_fail;
+ JS_SetPropertyStr(ctx, sep, "type",
+ JS_NewString(ctx, "literal"));
+ JS_SetPropertyStr(ctx, sep, "value",
+ JS_NewString(ctx, ":"));
+ {
+ int32_t plen = 0;
+ JSValue lv = JS_GetPropertyStr(ctx, cur_parts, "length");
+ if (!JS_IsException(lv)) {
+ JS_ToInt32(ctx, &plen, lv);
+ JS_FreeValue(ctx, lv);
+ }
+ JS_DefinePropertyValueUint32(ctx, cur_parts, (uint32_t)plen, sep,
+ JS_PROP_C_W_E);
+ }
+ }
+ }
+
+ nfOpts = JS_NewObject(ctx);
+ if (JS_IsException(nfOpts))
+ goto loop_fail;
+
+ JS_SetPropertyStr(ctx, nfOpts, "numberingSystem",
+ JS_NewString(ctx, js_intl_numbering_system_to_string(s->numberingSystem)));
+
+ if (displayNegativeSign) {
+ displayNegativeSign = 0;
+ if (values[i] == 0.0) {
+ if (is_negative)
+ value = __JS_NewFloat64(ctx, -0.0);
+ else
+ value = __JS_NewFloat64(ctx, 0.0);
+ } else {
+ value = __JS_NewFloat64(ctx, values[i]);
+ }
+ } else {
+ JS_SetPropertyStr(ctx, nfOpts, "signDisplay",
+ JS_NewString(ctx, "never"));
+ value = __JS_NewFloat64(ctx, values[i]);
+ }
+ if (JS_IsException(value))
+ goto loop_fail;
+
+ if (combine) {
+ JS_FreeValue(ctx, value);
+ frac_str = df_duration_to_fractional(ctx, values, i, exponent);
+ if (!frac_str)
+ goto loop_fail;
+ value = JS_NewString(ctx, frac_str);
+ js_free(ctx, frac_str);
+ if (JS_IsException(value))
+ goto loop_fail;
+ if (!s->has_fractionalDigits) {
+ JS_SetPropertyStr(ctx, nfOpts, "maximumFractionDigits",
+ JS_NewInt32(ctx, 9));
+ JS_SetPropertyStr(ctx, nfOpts, "minimumFractionDigits",
+ JS_NewInt32(ctx, 0));
+ } else {
+ JS_SetPropertyStr(ctx, nfOpts, "maximumFractionDigits",
+ JS_NewInt32(ctx, s->fractionalDigits_val));
+ JS_SetPropertyStr(ctx, nfOpts, "minimumFractionDigits",
+ JS_NewInt32(ctx, s->fractionalDigits_val));
+ }
+ JS_SetPropertyStr(ctx, nfOpts, "roundingMode",
+ JS_NewString(ctx, "trunc"));
+ }
+
+ if (style == DF_STYLE_2DIGIT) {
+ JS_SetPropertyStr(ctx, nfOpts, "minimumIntegerDigits",
+ JS_NewInt32(ctx, 2));
+ }
+
+ if (style != DF_STYLE_NUMERIC && style != DF_STYLE_2DIGIT &&
+ style != DF_STYLE_FRACTIONAL) {
+ JS_SetPropertyStr(ctx, nfOpts, "style",
+ JS_NewString(ctx, "unit"));
+ JS_SetPropertyStr(ctx, nfOpts, "unit",
+ JS_NewString(ctx, unit_names[i]));
+ JS_SetPropertyStr(ctx, nfOpts, "unitDisplay",
+ JS_NewString(ctx, df_style_names[style]));
+ } else {
+ JS_SetPropertyStr(ctx, nfOpts, "useGrouping",
+ JS_NewBool(ctx, 0));
+ }
+
+ formatted = df_nf_format(ctx, s->locale, nfOpts, value);
+ if (JS_IsException(formatted))
+ goto loop_fail;
+
+ formatted_parts = df_nf_formatToParts(ctx, s->locale, nfOpts, value,
+ unit_names[i]);
+ if (JS_IsException(formatted_parts))
+ goto loop_fail;
+
+ {
+ const char *fstr = JS_ToCString(ctx, formatted);
+ if (!fstr)
+ goto loop_fail;
+ dbuf_putstr(&cur_str, fstr);
+ JS_FreeCString(ctx, fstr);
+ }
+
+ {
+ int32_t fp_len = 0;
+ int j;
+ JSValue lv = JS_GetPropertyStr(ctx, formatted_parts, "length");
+ if (!JS_IsException(lv)) {
+ JS_ToInt32(ctx, &fp_len, lv);
+ JS_FreeValue(ctx, lv);
+ }
+ for (j = 0; j < fp_len; j++) {
+ JSValue part = JS_GetPropertyUint32(ctx, formatted_parts, (uint32_t)j);
+ int32_t cp_len = 0;
+ JSValue lv2 = JS_GetPropertyStr(ctx, cur_parts, "length");
+ if (!JS_IsException(lv2)) {
+ JS_ToInt32(ctx, &cp_len, lv2);
+ JS_FreeValue(ctx, lv2);
+ }
+ JS_DefinePropertyValueUint32(ctx, cur_parts, (uint32_t)cp_len, part,
+ JS_PROP_C_W_E);
+ }
+ }
+
+ is_num_style = (style == DF_STYLE_NUMERIC || style == DF_STYLE_2DIGIT);
+ if (!needSeparator) {
+ if (is_num_style)
+ needSeparator = 1;
+ }
+
+ JS_FreeValue(ctx, nfOpts);
+ JS_FreeValue(ctx, value);
+ JS_FreeValue(ctx, formatted);
+ JS_FreeValue(ctx, formatted_parts);
+
+ if (combine)
+ break;
+ continue;
+
+ loop_fail:
+ JS_FreeValue(ctx, nfOpts);
+ JS_FreeValue(ctx, value);
+ JS_FreeValue(ctx, formatted);
+ JS_FreeValue(ctx, formatted_parts);
+ goto fail;
+ }
+
+ if (cur_str.size > 0) {
+ dbuf_putc(&cur_str, '\0');
+ if (dbuf_error(&cur_str))
+ goto fail;
+ {
+ JSValue str = JS_NewString(ctx, (char *)cur_str.buf);
+ if (JS_IsException(str))
+ goto fail;
+ JS_DefinePropertyValueUint32(ctx, strings, (uint32_t)group_idx,
+ str, JS_PROP_C_W_E);
+ }
+ JS_DefinePropertyValueUint32(ctx, parts, (uint32_t)group_idx,
+ cur_parts, JS_PROP_C_W_E);
+ group_idx++;
+ } else {
+ JS_FreeValue(ctx, cur_parts);
+ }
+
+ dbuf_free(&cur_str);
+ *out_strings = strings;
+ *out_parts = parts;
+ return group_idx;
+
+fail:
+ dbuf_free(&cur_str);
+ JS_FreeValue(ctx, strings);
+ JS_FreeValue(ctx, parts);
+ JS_FreeValue(ctx, cur_parts);
+ *out_strings = JS_UNDEFINED;
+ *out_parts = JS_UNDEFINED;
+ return -1;
+}
+
+static JSValue js_durationformat_format(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSDurationFormatData *s = JS_GetOpaque2(ctx, this_val, js_durationformat_class_id);
+ JSDurationData d = {0};
+ JSValue strings = JS_UNDEFINED;
+ JSValue parts = JS_UNDEFINED;
+ JSValue list = JS_UNDEFINED;
+ JSValue ret = JS_UNDEFINED;
+ int group_count;
+ int i;
+ const char *list_style_str;
+
+ if (!s)
+ return JS_EXCEPTION;
+
+ if (JS_IsUndefined(argv[0]) || JS_IsNull(argv[0]) ||
+ JS_IsBool(argv[0]) || JS_IsSymbol(argv[0]) || JS_IsNumber(argv[0]) ||
+ JS_IsBigInt(ctx, argv[0]))
+ return JS_ThrowTypeError(ctx, "format requires a duration argument");
+
+ if (js_to_temporal_duration(ctx, argv[0], &d) < 0)
+ return JS_EXCEPTION;
+
+ if (is_valid_duration_record(ctx, &d) < 0)
+ return JS_EXCEPTION;
+
+ group_count = df_build_groups(ctx, s, &d, &strings, &parts);
+ if (group_count < 0)
+ return JS_EXCEPTION;
+
+ list = JS_NewArray(ctx);
+ if (JS_IsException(list))
+ goto fail;
+
+ for (i = 0; i < group_count; i++) {
+ JSValue str = JS_GetPropertyUint32(ctx, strings, (uint32_t)i);
+ if (JS_IsException(str))
+ goto fail;
+ JS_DefinePropertyValueUint32(ctx, list, (uint32_t)i, str, JS_PROP_C_W_E);
+ }
+
+ list_style_str = df_style_names[s->style == DF_STYLE_DIGITAL ? DF_STYLE_SHORT : s->style];
+
+ ret = df_lf_format(ctx, s->locale, "unit", list_style_str, list);
+ JS_FreeValue(ctx, list);
+ JS_FreeValue(ctx, strings);
+ JS_FreeValue(ctx, parts);
+ return ret;
+
+fail:
+ JS_FreeValue(ctx, list);
+ JS_FreeValue(ctx, strings);
+ JS_FreeValue(ctx, parts);
+ return JS_EXCEPTION;
+}
+
+static JSValue js_durationformat_formatToParts(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSDurationFormatData *s = JS_GetOpaque2(ctx, this_val, js_durationformat_class_id);
+ JSDurationData d = {0};
+ JSValue strings = JS_UNDEFINED;
+ JSValue parts = JS_UNDEFINED;
+ JSValue list = JS_UNDEFINED;
+ JSValue lf_parts = JS_UNDEFINED;
+ JSValue result = JS_UNDEFINED;
+ int group_count;
+ int i;
+ int32_t lf_len;
+ const char *list_style_str;
+
+ if (!s)
+ return JS_EXCEPTION;
+
+ if (JS_IsUndefined(argv[0]) || JS_IsNull(argv[0]) ||
+ JS_IsBool(argv[0]) || JS_IsSymbol(argv[0]) || JS_IsNumber(argv[0]) ||
+ JS_IsBigInt(ctx, argv[0]))
+ return JS_ThrowTypeError(ctx, "formatToParts requires a duration argument");
+
+ if (js_to_temporal_duration(ctx, argv[0], &d) < 0)
+ return JS_EXCEPTION;
+
+ if (is_valid_duration_record(ctx, &d) < 0)
+ return JS_EXCEPTION;
+
+ group_count = df_build_groups(ctx, s, &d, &strings, &parts);
+ if (group_count < 0)
+ return JS_EXCEPTION;
+
+ list = JS_NewArray(ctx);
+ if (JS_IsException(list))
+ goto fail;
+
+ for (i = 0; i < group_count; i++) {
+ JSValue str = JS_GetPropertyUint32(ctx, strings, (uint32_t)i);
+ if (JS_IsException(str))
+ goto fail;
+ JS_DefinePropertyValueUint32(ctx, list, (uint32_t)i, str, JS_PROP_C_W_E);
+ }
+
+ list_style_str = df_style_names[s->style == DF_STYLE_DIGITAL ? DF_STYLE_SHORT : s->style];
+
+ lf_parts = df_lf_formatToParts(ctx, s->locale, "unit", list_style_str, list);
+ if (JS_IsException(lf_parts))
+ goto fail;
+
+ result = JS_NewArray(ctx);
+ if (JS_IsException(result))
+ goto fail;
+
+ {
+ JSValue lv = JS_GetPropertyStr(ctx, lf_parts, "length");
+ lf_len = 0;
+ if (!JS_IsException(lv)) {
+ JS_ToInt32(ctx, &lf_len, lv);
+ JS_FreeValue(ctx, lv);
+ }
+ }
+
+ {
+ int group_offset = 0;
+ for (i = 0; i < lf_len; i++) {
+ JSValue item = JS_GetPropertyUint32(ctx, lf_parts, (uint32_t)i);
+ if (JS_IsException(item))
+ goto fail;
+ {
+ JSValue type_val = JS_GetPropertyStr(ctx, item, "type");
+ if (!JS_IsException(type_val)) {
+ const char *type_str = JS_ToCString(ctx, type_val);
+ if (type_str) {
+ if (!strcmp(type_str, "element")) {
+ JSValue group = JS_GetPropertyUint32(ctx, parts, (uint32_t)group_offset);
+ group_offset++;
+ if (!JS_IsException(group)) {
+ int32_t g_len = 0;
+ int j;
+ JSValue glv = JS_GetPropertyStr(ctx, group, "length");
+ if (!JS_IsException(glv)) {
+ JS_ToInt32(ctx, &g_len, glv);
+ JS_FreeValue(ctx, glv);
+ }
+ for (j = 0; j < g_len; j++) {
+ JSValue p = JS_GetPropertyUint32(ctx, group, (uint32_t)j);
+ int32_t rlen = 0;
+ JSValue rlv = JS_GetPropertyStr(ctx, result, "length");
+ if (!JS_IsException(rlv)) {
+ JS_ToInt32(ctx, &rlen, rlv);
+ JS_FreeValue(ctx, rlv);
+ }
+ JS_DefinePropertyValueUint32(ctx, result, (uint32_t)rlen,
+ p, JS_PROP_C_W_E);
+ }
+ JS_FreeValue(ctx, group);
+ }
+ } else {
+ JSValue rlv = JS_GetPropertyStr(ctx, result, "length");
+ int32_t rlen = 0;
+ if (!JS_IsException(rlv)) {
+ JS_ToInt32(ctx, &rlen, rlv);
+ JS_FreeValue(ctx, rlv);
+ }
+ JS_DefinePropertyValueUint32(ctx, result, (uint32_t)rlen,
+ JS_DupValue(ctx, item),
+ JS_PROP_C_W_E);
+ }
+ JS_FreeCString(ctx, type_str);
+ }
+ JS_FreeValue(ctx, type_val);
+ }
+ }
+ JS_FreeValue(ctx, item);
+ }
+ }
+
+ JS_FreeValue(ctx, list);
+ JS_FreeValue(ctx, strings);
+ JS_FreeValue(ctx, parts);
+ JS_FreeValue(ctx, lf_parts);
+ return result;
+
+fail:
+ JS_FreeValue(ctx, list);
+ JS_FreeValue(ctx, strings);
+ JS_FreeValue(ctx, parts);
+ JS_FreeValue(ctx, lf_parts);
+ JS_FreeValue(ctx, result);
+ return JS_EXCEPTION;
+}
+
+static JSValue js_durationformat_resolvedOptions(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSValue obj;
+ JSDurationFormatData *s = JS_GetOpaque2(ctx, this_val, js_durationformat_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+
+ obj = JS_NewObject(ctx);
+ if (JS_IsException(obj))
+ return JS_EXCEPTION;
+
+ JS_DefinePropertyValueStr(ctx, obj, "locale",
+ JS_NewString(ctx, s->locale), JS_PROP_C_W_E);
+ JS_DefinePropertyValueStr(ctx, obj, "numberingSystem",
+ JS_NewString(ctx, js_intl_numbering_system_to_string(s->numberingSystem)), JS_PROP_C_W_E);
+ JS_DefinePropertyValueStr(ctx, obj, "style",
+ JS_NewString(ctx, df_style_names[s->style]), JS_PROP_C_W_E);
+ {
+ int i;
+ for (i = 0; i < (int)countof(df_units); i++) {
+ const UnitDef *def = &df_units[i];
+ int style_val = s->unit_style[def->unit_idx];
+ int display_val = s->unit_display[def->unit_idx];
+ if (style_val >= 0) {
+ const char *out_style = df_style_names[style_val];
+ if (style_val == DF_STYLE_FRACTIONAL)
+ out_style = "numeric";
+ JS_DefinePropertyValueStr(ctx, obj, def->unit,
+ JS_NewString(ctx, out_style), JS_PROP_C_W_E);
+ }
+ if (display_val >= 0)
+ JS_DefinePropertyValueStr(ctx, obj, def->displaySlot,
+ JS_NewString(ctx, df_display_names[display_val]), JS_PROP_C_W_E);
+ }
+ }
+ if (s->has_fractionalDigits)
+ JS_DefinePropertyValueStr(ctx, obj, "fractionalDigits",
+ JS_NewInt32(ctx, s->fractionalDigits_val), JS_PROP_C_W_E);
+ return obj;
+}
+
+static JSValue js_durationformat_supportedLocalesOf(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ return js_intl_supportedLocalesOf(ctx, this_val, argc, argv);
+}
+
+static const JSCFunctionListEntry js_durationformat_proto_funcs[] = {
+ JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Intl.DurationFormat", JS_PROP_CONFIGURABLE),
+ JS_CFUNC_DEF("format", 1, js_durationformat_format),
+ JS_CFUNC_DEF("formatToParts", 1, js_durationformat_formatToParts),
+ JS_CFUNC_DEF("resolvedOptions", 0, js_durationformat_resolvedOptions),
+};
+
+static const JSCFunctionListEntry js_durationformat_static_funcs[] = {
+ JS_CFUNC_DEF("supportedLocalesOf", 1, js_durationformat_supportedLocalesOf),
+};
+
+int js_add_durationformat(JSContext *ctx, JSValue intl_obj)
+{
+ JS_NewClassID(&js_durationformat_class_id);
+ JS_NewClass(JS_GetRuntime(ctx), js_durationformat_class_id, &js_durationformat_class);
+
+ if (JS_IsException(js_intl_new_constructor(ctx, intl_obj,
+ JS_INTL_CTOR_DURATIONFORMAT,
+ js_durationformat_class_id, "DurationFormat",
+ (JSCFunction *)js_durationformat_constructor, 0,
+ JS_CFUNC_constructor, 0,
+ js_durationformat_static_funcs, countof(js_durationformat_static_funcs),
+ js_durationformat_proto_funcs, countof(js_durationformat_proto_funcs))))
+ return -1;
+
+ return 0;
+}
--- /dev/null
+/*
+ * QuickJS Intl implementation (ECMA-402)
+ */
+
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include "../quickjs.h"
+#include "../cutils.h"
+#include "intl_private.h"
+#include "../temporal/calendar.h"
+#include "../temporal/timezone.h"
+
+const char *intl_localeMatcher_names[] = {"lookup", "best fit"};
+
+JSValue js_canonicalizeLocaleList(JSContext *ctx, JSValueConst locales);
+static void js_intl_set_locale_callbacks(JSContext *ctx);
+
+/* --------------------------------------------------------------------- */
+/* Shared option helpers */
+/* --------------------------------------------------------------------- */
+
+JSValue js_intl_get_options_object(JSContext *ctx, JSValueConst options)
+{
+ if (JS_IsUndefined(options))
+ return JS_NewObjectProto(ctx, JS_NULL);
+ if (!JS_IsObject(options))
+ return JS_ThrowTypeError(ctx, "options must be an object");
+ return JS_DupValue(ctx, options);
+}
+
+int js_intl_get_string_option(JSContext *ctx, JSValueConst options, const char *prop,
+ const char **valid_values, int num_values, int default_index)
+{
+ JSValue val = JS_GetPropertyStr(ctx, options, prop);
+ size_t slen;
+ const char *str;
+ int i;
+
+ if (JS_IsException(val))
+ return -1;
+ if (JS_IsUndefined(val))
+ return default_index;
+
+ str = JS_ToCStringLen(ctx, &slen, val);
+ JS_FreeValue(ctx, val);
+ if (!str)
+ return -1;
+
+ for (i = 0; i < num_values; i++) {
+ size_t vlen = strlen(valid_values[i]);
+ if (slen == vlen && memcmp(str, valid_values[i], vlen) == 0) {
+ JS_FreeCString(ctx, str);
+ return i;
+ }
+ }
+
+ JS_ThrowRangeError(ctx, "invalid %s", prop);
+ JS_FreeCString(ctx, str);
+ return -1;
+}
+
+int js_intl_get_number_option(JSContext *ctx, JSValueConst options, const char *prop,
+ int *pval, int val_min, int val_max)
+{
+ JSValue val = JS_GetPropertyStr(ctx, options, prop);
+ double d;
+ int ret;
+
+ if (JS_IsException(val))
+ return -1;
+ if (JS_IsUndefined(val)) {
+ JS_FreeValue(ctx, val);
+ return 0;
+ }
+
+ ret = JS_ToFloat64(ctx, &d, val);
+ JS_FreeValue(ctx, val);
+ if (ret < 0)
+ return -1;
+
+ if (isnan(d) || isinf(d) || d < val_min || d > val_max) {
+ JS_ThrowRangeError(ctx, "%s out of range", prop);
+ return -1;
+ }
+ *pval = (int)d;
+ return 1;
+}
+
+/* --------------------------------------------------------------------- */
+/* Shared supportedLocalesOf helper */
+/* --------------------------------------------------------------------- */
+
+/* Strip Unicode extensions (-u-...) from locale string */
+char *js_intl_strip_unicode_extensions(JSContext *ctx, const char *locale)
+{
+ const char *p = strstr(locale, "-u-");
+ if (!p) {
+ /* also check uppercase, though unlikely */
+ p = strstr(locale, "-U-");
+ }
+ if (p) {
+ size_t len = (size_t)(p - locale);
+ char *res = js_malloc(ctx, len + 1);
+ if (res) {
+ memcpy(res, locale, len);
+ res[len] = '\0';
+ }
+ return res;
+ }
+ return js_strdup(ctx, locale);
+}
+
+/* Extract locale from Intl constructor first argument.
+ Uses CanonicalizeLocaleList then returns the first locale with
+ Unicode extensions stripped, or "en-US" if list is empty.
+ Returns a newly allocated string, or NULL on error/exception.
+ Caller must js_free the result. */
+const char *intl_all_numbering_systems[] = {
+ "adlm", "ahom", "arab", "arabext", "armn", "armnlow", "bali", "beng", "bhks",
+ "brah", "cakm", "cham", "cyrl", "deva", "diak", "ethi", "finance", "fullwide",
+ "gara", "geor", "gong", "gonm", "grek", "greklow", "gujr", "gukh", "guru",
+ "hanidays", "hanidec", "hans", "hansfin", "hant", "hantfin", "hebr", "hmng",
+ "hmnp", "java", "jpan", "jpanfin", "jpanyear", "kali", "kawi", "khmr", "knda",
+ "krai", "lana", "lanatham", "laoo", "latn", "lepc", "limb", "mathbold", "mathdbl",
+ "mathmono", "mathsanb", "mathsans", "mlym", "modi", "mong", "mroo", "mtei",
+ "mymr", "mymrepka", "mymrpao", "mymrshan", "mymrtlng", "nagm", "native", "newa",
+ "nkoo", "olck", "onao", "orya", "osma", "outlined", "rohg", "roman", "romanlow",
+ "saur", "segment", "shrd", "sind", "sinh", "sora", "sund", "sunu", "takr",
+ "talu", "taml", "tamldec", "telu", "thai", "tibt", "tirh", "tnsa", "tols",
+ "traditio", "vaii", "wara", "wcho"
+};
+const int intl_all_numbering_systems_count = countof(intl_all_numbering_systems);
+
+const char *intl_supported_collations[] = {
+ "eor", "phonebk"
+};
+const int intl_supported_collations_count = countof(intl_supported_collations);
+
+static int cmp_str(const void *a, const void *b)
+{
+ return strcmp(*(const char **)a, *(const char **)b);
+}
+
+static int is_valid_numbering_system(const char *name)
+{
+ if (!strcmp(name, "native") || !strcmp(name, "traditio") || !strcmp(name, "finance"))
+ return 0;
+ return bsearch(&name, intl_all_numbering_systems,
+ (size_t)intl_all_numbering_systems_count, sizeof(char *),
+ cmp_str) != NULL;
+}
+
+int js_intl_string_to_numbering_system(const char *str)
+{
+ const char **p;
+ if (!str)
+ return NS_UNKNOWN;
+ p = bsearch(&str, intl_all_numbering_systems,
+ (size_t)intl_all_numbering_systems_count, sizeof(char *),
+ cmp_str);
+ if (p)
+ return (int)(p - intl_all_numbering_systems);
+ return NS_UNKNOWN;
+}
+
+const char *js_intl_numbering_system_to_string(int ns)
+{
+ if (ns >= 0 && ns < intl_all_numbering_systems_count)
+ return intl_all_numbering_systems[ns];
+ return NULL;
+}
+
+/* Extract a Unicode extension keyword value from a canonicalized locale string.
+ key must be exactly 2 characters. Returns a newly allocated string, or NULL.
+ For 'nu', validates against known numbering systems. */
+const char *js_intl_find_u_extension(const char *locale)
+{
+ const char *u = strstr(locale, "-u-");
+ const char *x = strstr(locale, "-x-");
+ if (u && x && u > x)
+ return NULL;
+ return u;
+}
+
+int js_intl_locale_has_key(const char *locale, const char *key)
+{
+ const char *u = js_intl_find_u_extension(locale);
+ if (!u)
+ return 0;
+ u += 3;
+ while (*u) {
+ const char *next = u;
+ while (*next && *next != '-')
+ next++;
+ int len = (int)(next - u);
+ if (len == 2 && u[0] == key[0] && u[1] == key[1])
+ return 1;
+ if (*next == '-')
+ next++;
+ u = next;
+ }
+ return 0;
+}
+
+char *js_intl_locale_get_unicode_key(JSContext *ctx, const char *locale, const char *key)
+{
+ const char *u_ext = js_intl_find_u_extension(locale);
+ if (!u_ext)
+ return NULL;
+ u_ext += 3;
+ while (*u_ext) {
+ const char *next = u_ext;
+ while (*next && *next != '-')
+ next++;
+ int key_len = (int)(next - u_ext);
+ if (key_len == 2 && u_ext[0] == key[0] && u_ext[1] == key[1]) {
+ const char *val = next;
+ if (*val == '-')
+ val++;
+ const char *val_end = val;
+ /* read all subtags until end, singleton, or another key */
+ while (*val_end) {
+ const char *sub_end = val_end;
+ while (*sub_end && *sub_end != '-')
+ sub_end++;
+ int sub_len = (int)(sub_end - val_end);
+ /* singleton (1 char) ends this extension block */
+ if (sub_len == 1)
+ break;
+ /* another key (2 chars) means our key's value ends here */
+ if (sub_len == 2)
+ break;
+ val_end = sub_end;
+ if (*val_end == '-')
+ val_end++;
+ }
+ size_t val_len = (size_t)(val_end - val);
+ /* trim trailing hyphen if any */
+ if (val_len > 0 && val[val_len - 1] == '-')
+ val_len--;
+ if (val_len == 0)
+ return NULL;
+ char *res = js_malloc(ctx, val_len + 1);
+ if (res) {
+ memcpy(res, val, val_len);
+ res[val_len] = '\0';
+ if (key[0] == 'n' && key[1] == 'u' && !is_valid_numbering_system(res)) {
+ js_free(ctx, res);
+ return NULL;
+ }
+ }
+ return res;
+ }
+ /* skip this subtag and continue */
+ if (*next == '-')
+ next++;
+ u_ext = next;
+ }
+ return NULL;
+}
+
+char *js_intl_locale_get_numbering_system(JSContext *ctx, const char *locale)
+{
+ return js_intl_locale_get_unicode_key(ctx, locale, "nu");
+}
+
+char *js_intl_extract_locale(JSContext *ctx, int argc, JSValueConst *argv)
+{
+ char *canonical;
+ char *res = NULL;
+
+ if (argc == 0 || JS_IsUndefined(argv[0]))
+ return js_strdup(ctx, "en-US");
+
+ if (js_canonicalizeLocaleList_first(ctx, argv[0], &canonical) < 0)
+ return NULL;
+ if (!canonical)
+ return js_strdup(ctx, "en-US");
+ res = js_intl_strip_unicode_extensions(ctx, canonical);
+ js_free(ctx, canonical);
+ if (!res)
+ res = js_strdup(ctx, "en-US");
+ return res;
+}
+
+JSValue js_intl_supportedLocalesOf(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSValue arr;
+ int i;
+
+ (void)this_val;
+
+ if (argc > 0 && JS_IsNull(argv[0])) {
+ JS_ThrowTypeError(ctx, "null is not a valid locale list");
+ return JS_EXCEPTION;
+ }
+
+ if (argc == 0 || JS_IsUndefined(argv[0])) {
+ return JS_NewArray(ctx);
+ }
+
+ /* SupportedLocales: if options is not undefined, let options be ? ToObject(options) */
+ if (argc > 1 && !JS_IsUndefined(argv[1])) {
+ JSValue options = JS_ToObject(ctx, argv[1]);
+ if (JS_IsException(options))
+ return JS_EXCEPTION;
+ {
+ int lm = js_intl_get_string_option(ctx, options, "localeMatcher",
+ intl_localeMatcher_names, 2,
+ INTL_LOCALEMATCHER_BESTFIT);
+ if (lm < 0) {
+ JS_FreeValue(ctx, options);
+ return JS_EXCEPTION;
+ }
+ }
+ JS_FreeValue(ctx, options);
+ }
+
+ {
+ char **clocales = NULL;
+ int clen = 0;
+ if (js_canonicalizeLocaleList_c(ctx, argv[0], &clocales, &clen) < 0)
+ return JS_EXCEPTION;
+
+ arr = JS_NewArray(ctx);
+ if (JS_IsException(arr)) {
+ js_canonicalizeLocaleList_free_c(ctx, clocales, clen);
+ return JS_EXCEPTION;
+ }
+
+ {
+ uint32_t out_idx = 0;
+ for (i = 0; i < clen; i++) {
+ const char *str = clocales[i];
+ if (str[0] != '\0' && strcmp(str, "zxx") != 0 && strncmp(str, "zxx-", 4) != 0) {
+ uint32_t j;
+ int dup = 0;
+ for (j = 0; j < out_idx; j++) {
+ JSValue existing = JS_GetPropertyUint32(ctx, arr, j);
+ if (!JS_IsUndefined(existing)) {
+ const char *estr = JS_ToCString(ctx, existing);
+ if (estr) {
+ if (!strcmp(estr, str))
+ dup = 1;
+ JS_FreeCString(ctx, estr);
+ }
+ }
+ JS_FreeValue(ctx, existing);
+ }
+ if (!dup) {
+ JSValue str_val = JS_NewString(ctx, str);
+ if (JS_IsException(str_val)) {
+ js_canonicalizeLocaleList_free_c(ctx, clocales, clen);
+ JS_FreeValue(ctx, arr);
+ return JS_EXCEPTION;
+ }
+ if (JS_DefinePropertyValueUint32(ctx, arr, (uint32_t)out_idx++,
+ str_val, JS_PROP_C_W_E) < 0) {
+ js_canonicalizeLocaleList_free_c(ctx, clocales, clen);
+ JS_FreeValue(ctx, arr);
+ return JS_EXCEPTION;
+ }
+ }
+ }
+ }
+ }
+
+ js_canonicalizeLocaleList_free_c(ctx, clocales, clen);
+ return arr;
+ }
+}
+
+/* --------------------------------------------------------------------- */
+/* Locale helpers */
+/* --------------------------------------------------------------------- */
+
+static int is_alpha(const char *s, int len)
+{
+ int i;
+ for (i = 0; i < len; i++) {
+ char c = s[i];
+ if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')))
+ return 0;
+ }
+ return 1;
+}
+
+static int is_digit(const char *s, int len)
+{
+ int i;
+ for (i = 0; i < len; i++) {
+ char c = s[i];
+ if (!(c >= '0' && c <= '9'))
+ return 0;
+ }
+ return 1;
+}
+
+static int is_alphanum(const char *s, int len)
+{
+ int i;
+ for (i = 0; i < len; i++) {
+ char c = s[i];
+ if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9')))
+ return 0;
+ }
+ return 1;
+}
+
+static void strtolower(char *s)
+{
+ while (*s) {
+ if (*s >= 'A' && *s <= 'Z')
+ *s += 32;
+ s++;
+ }
+}
+
+static void strntolower(char *s, int len)
+{
+ int i;
+ for (i = 0; i < len; i++) {
+ if (s[i] >= 'A' && s[i] <= 'Z')
+ s[i] += 32;
+ }
+}
+
+static void strntoupper(char *s, int len)
+{
+ int i;
+ for (i = 0; i < len; i++) {
+ if (s[i] >= 'a' && s[i] <= 'z')
+ s[i] -= 32;
+ }
+}
+
+/* Check if a language tag is well-formed per UTS35.
+ This operates on the ASCII-lowercase form. */
+static int is_grandfathered_irregular(const char *tag)
+{
+ static const char *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"
+ };
+ static const char *regular_non_uts35[] = {
+ "no-bok", "no-nyn", "zh-min", "zh-min-nan"
+ };
+ int i;
+ for (i = 0; i < (int)countof(irregular); i++)
+ if (!strcasecmp(tag, irregular[i]))
+ return 1;
+ for (i = 0; i < (int)countof(regular_non_uts35); i++)
+ if (!strcasecmp(tag, regular_non_uts35[i]))
+ return 1;
+ return 0;
+}
+
+int is_wellformed_language_tag(const char *tag)
+{
+ char buf[512];
+ char *subtags[64];
+ int n = 0, i, j;
+ int state; /* 0=base, 1=extension, 2=privateuse */
+ int seen_singletons[256] = {0};
+ int has_script = 0, has_region = 0;
+ char ext_singleton = 0;
+ int ext_has_subtag = 0;
+ int tlang_state = 0; /* 0=not in tlang, 1=in tlang language, 2=in tlang script, 3=in tlang region, 4=in tlang variant */
+ int u_attr_done = 0; /* 0=may see u attributes, 1=seen u key */
+
+ if (!tag || !*tag)
+ return 0;
+ if (strlen(tag) >= sizeof(buf))
+ return 0;
+ if (tag[0] == '-')
+ return 0;
+ if (is_grandfathered_irregular(tag))
+ return 0;
+
+ pstrcpy(buf, sizeof(buf), tag);
+ strtolower(buf);
+
+ /* split on '-' */
+ {
+ char *p = buf;
+ subtags[n++] = p;
+ for (i = 0; buf[i]; i++) {
+ if (buf[i] == '-') {
+ buf[i] = '\0';
+ subtags[n++] = &buf[i + 1];
+ if (n >= 64) return 0;
+ }
+ }
+ }
+
+ if (n == 0) return 0;
+ if (subtags[0][0] == '\0') return 0;
+
+ /* first subtag: language */
+ {
+ int llen = (int)strlen(subtags[0]);
+ if (!((llen >= 2 && llen <= 3) || (llen >= 5 && llen <= 8)))
+ return 0;
+ if (!is_alpha(subtags[0], llen))
+ return 0;
+ }
+
+ state = 0;
+ for (i = 1; i < n; i++) {
+ int len = (int)strlen(subtags[i]);
+ if (len == 0) return 0;
+
+ if (state == 2) {
+ /* private use: 1-8 alphanum */
+ if (len < 1 || len > 8 || !is_alphanum(subtags[i], len))
+ return 0;
+ continue;
+ }
+
+ if (state == 1) {
+ if (len == 1) {
+ /* new extension or privateuse */
+ /* Empty extension (singleton immediately followed by another singleton) is invalid */
+ if (!ext_has_subtag)
+ return 0;
+ /* If t extension ended with a key expecting a value, it's invalid */
+ if (ext_singleton == 't' && tlang_state == 5)
+ return 0;
+ state = 0;
+ ext_singleton = 0;
+ tlang_state = 0;
+ u_attr_done = 0;
+ i--; /* reprocess this singleton */
+ continue;
+ }
+ ext_has_subtag = 1;
+ if (ext_singleton == 't') {
+ /* transformed extension: tlang or tfield */
+ /* tfield key is alpha+digit, must be followed by at least one value (3-8 alphanum) */
+ if (tlang_state == 0) {
+ /* could be tlang language or tfield key */
+ if (((len >= 2 && len <= 3) || (len >= 5 && len <= 8)) && is_alpha(subtags[i], len)) {
+ /* tlang language */
+ tlang_state = 1;
+ } else if (len == 2 && is_alpha(subtags[i], 1) && is_digit(subtags[i] + 1, 1)) {
+ /* tfield key */
+ tlang_state = 5;
+ } else {
+ return 0;
+ }
+ } else if (tlang_state == 1) {
+ /* after tlang language: script, region, variant, or tfield key */
+ if (len == 4 && is_alpha(subtags[i], 4)) {
+ tlang_state = 2;
+ } else if ((len == 2 && is_alpha(subtags[i], 2)) ||
+ (len == 3 && is_digit(subtags[i], 3))) {
+ tlang_state = 3;
+ } else if ((len >= 5 && len <= 8 && is_alphanum(subtags[i], len)) ||
+ (len == 4 && isdigit((unsigned char)subtags[i][0]) && is_alphanum(subtags[i] + 1, 3))) {
+ for (j = 2; j < i; j++) {
+ int jlen = (int)strlen(subtags[j]);
+ if (jlen == len && !memcmp(subtags[j], subtags[i], (size_t)len))
+ return 0;
+ }
+ tlang_state = 4;
+ } else if (len == 2 && is_alpha(subtags[i], 1) && is_digit(subtags[i] + 1, 1)) {
+ tlang_state = 5;
+ } else {
+ return 0;
+ }
+ } else if (tlang_state == 2) {
+ /* after tlang script: region, variant, or tfield key */
+ if ((len == 2 && is_alpha(subtags[i], 2)) ||
+ (len == 3 && is_digit(subtags[i], 3))) {
+ tlang_state = 3;
+ } else if ((len >= 5 && len <= 8 && is_alphanum(subtags[i], len)) ||
+ (len == 4 && isdigit((unsigned char)subtags[i][0]) && is_alphanum(subtags[i] + 1, 3))) {
+ for (j = 2; j < i; j++) {
+ int jlen = (int)strlen(subtags[j]);
+ if (jlen == len && !memcmp(subtags[j], subtags[i], (size_t)len))
+ return 0;
+ }
+ tlang_state = 4;
+ } else if (len == 2 && is_alpha(subtags[i], 1) && is_digit(subtags[i] + 1, 1)) {
+ tlang_state = 5;
+ } else {
+ return 0;
+ }
+ } else if (tlang_state == 3) {
+ /* after tlang region: variant or tfield key */
+ if ((len >= 5 && len <= 8 && is_alphanum(subtags[i], len)) ||
+ (len == 4 && isdigit((unsigned char)subtags[i][0]) && is_alphanum(subtags[i] + 1, 3))) {
+ for (j = 2; j < i; j++) {
+ int jlen = (int)strlen(subtags[j]);
+ if (jlen == len && !memcmp(subtags[j], subtags[i], (size_t)len))
+ return 0;
+ }
+ tlang_state = 4;
+ } else if (len == 2 && is_alpha(subtags[i], 1) && is_digit(subtags[i] + 1, 1)) {
+ tlang_state = 5;
+ } else {
+ return 0;
+ }
+ } else if (tlang_state == 4) {
+ /* after tlang variant: more variant or tfield key */
+ if ((len >= 5 && len <= 8 && is_alphanum(subtags[i], len)) ||
+ (len == 4 && isdigit((unsigned char)subtags[i][0]) && is_alphanum(subtags[i] + 1, 3))) {
+ for (j = 2; j < i; j++) {
+ int jlen = (int)strlen(subtags[j]);
+ if (jlen == len && !memcmp(subtags[j], subtags[i], (size_t)len))
+ return 0;
+ }
+ } else if (len == 2 && is_alpha(subtags[i], 1) && is_digit(subtags[i] + 1, 1)) {
+ tlang_state = 5;
+ } else {
+ return 0;
+ }
+ } else if (tlang_state == 5) {
+ /* in tfield, expecting value (3-8 alphanum) */
+ if (len >= 3 && len <= 8 && is_alphanum(subtags[i], len)) {
+ tlang_state = 6;
+ } else {
+ return 0;
+ }
+ } else if (tlang_state == 6) {
+ /* after tfield value: more values or new key */
+ if (len >= 3 && len <= 8 && is_alphanum(subtags[i], len)) {
+ /* another value */
+ } else if (len == 2 && is_alpha(subtags[i], 1) && is_digit(subtags[i] + 1, 1)) {
+ /* new key */
+ tlang_state = 5;
+ } else {
+ return 0;
+ }
+ }
+ } else if (ext_singleton == 'u') {
+ /* unicode extension: attributes or key-value pairs */
+ if (!u_attr_done) {
+ if (len == 2 && is_alphanum(subtags[i], 2) && is_alpha(subtags[i] + 1, 1)) {
+ u_attr_done = 1; /* first key */
+ } else if (len >= 3 && len <= 8 && is_alphanum(subtags[i], len)) {
+ /* attribute */
+ } else {
+ return 0;
+ }
+ } else {
+ /* after first key: values (3-8) or next key (2 with alpha second) */
+ if (len == 2 && is_alphanum(subtags[i], 2) && is_alpha(subtags[i] + 1, 1)) {
+ /* next key */
+ } else if (len >= 3 && len <= 8 && is_alphanum(subtags[i], len)) {
+ /* value */
+ } else {
+ return 0;
+ }
+ }
+ } else {
+ /* other extensions: subtags 2-8 alphanum */
+ if (len < 2 || len > 8 || !is_alphanum(subtags[i], len))
+ return 0;
+ }
+ continue;
+ }
+
+ /* state == 0: base or singleton */
+ if (len == 1) {
+ char c = subtags[i][0];
+ if (!isalnum((unsigned char)c))
+ return 0;
+ if (c == 'x') {
+ /* privateuse must have at least one following subtag */
+ if (i + 1 >= n)
+ return 0;
+ state = 2;
+ continue;
+ }
+ /* extension singleton */
+ if (seen_singletons[(unsigned char)c])
+ return 0;
+ seen_singletons[(unsigned char)c] = 1;
+ /* extension must have at least one following subtag */
+ if (i + 1 >= n)
+ return 0;
+ ext_singleton = c;
+ tlang_state = 0;
+ u_attr_done = 0;
+ ext_has_subtag = 0;
+ state = 1;
+ continue;
+ }
+
+ if (!has_script && !has_region && len == 4 && is_alpha(subtags[i], 4)) {
+ has_script = 1;
+ continue;
+ }
+
+ if (!has_region && ((len == 2 && is_alpha(subtags[i], 2)) ||
+ (len == 3 && is_digit(subtags[i], 3)))) {
+ has_region = 1;
+ continue;
+ }
+
+ /* variant: 5-8 alphanum, or digit + 3 alphanum */
+ if ((len >= 5 && len <= 8 && is_alphanum(subtags[i], len)) ||
+ (len == 4 && isdigit((unsigned char)subtags[i][0]) && is_alphanum(subtags[i] + 1, 3))) {
+ /* check duplicate variants */
+ for (j = 1; j < i; j++) {
+ int jlen = (int)strlen(subtags[j]);
+ if (jlen == len && !memcmp(subtags[j], subtags[i], (size_t)len))
+ return 0;
+ }
+ continue;
+ }
+
+ return 0;
+ }
+
+ /* If we ended inside a t extension expecting a tfield value, it's invalid */
+ if (state == 1 && ext_singleton == 't' && tlang_state == 5)
+ return 0;
+
+ return 1;
+}
+
+/* Canonicalize a well-formed language tag.
+ Returns a newly allocated string in ctx. */
+typedef struct {
+ int start;
+ int len;
+ char singleton;
+} ExtBlock;
+
+static int ext_block_cmp(const void *a, const void *b)
+{
+ const ExtBlock *ea = a;
+ const ExtBlock *eb = b;
+ return (int)ea->singleton - (int)eb->singleton;
+}
+
+char *canonicalize_locale(JSContext *ctx, const char *locale)
+{
+ char buf[512];
+ char *subtags[64];
+ int n = 0, i;
+ char *result;
+ int in_extension = 0;
+ int has_script = 0, has_region = 0;
+ DynBuf dbuf;
+ ExtBlock ext_blocks[16];
+ int ext_count = 0;
+ int base_end = 0;
+
+ if (strlen(locale) >= sizeof(buf))
+ return NULL;
+ pstrcpy(buf, sizeof(buf), locale);
+
+ /* split */
+ {
+ char *p = buf;
+ subtags[n++] = p;
+ for (i = 0; buf[i]; i++) {
+ if (buf[i] == '-') {
+ buf[i] = '\0';
+ subtags[n++] = &buf[i + 1];
+ if (n >= 64) return NULL;
+ }
+ }
+ }
+
+ /* apply alias mappings for grandfathered/deprecated tags */
+ if (!strcasecmp(subtags[0], "cmn")) {
+ pstrcpy(subtags[0], sizeof(buf), "zh");
+ } else if (n == 1 && !strcasecmp(subtags[0], "ji")) {
+ pstrcpy(subtags[0], sizeof(buf), "yi");
+ } else if (n == 1 && !strcasecmp(subtags[0], "in")) {
+ pstrcpy(subtags[0], sizeof(buf), "id");
+ } else if (n == 2 && !strcasecmp(subtags[0], "sgn") && !strcasecmp(subtags[1], "GR")) {
+ pstrcpy(subtags[0], sizeof(buf), "gss");
+ subtags[1][0] = '\0';
+ n = 1;
+ } else if (n == 2 && !strcasecmp(subtags[0], "de") && !strcasecmp(subtags[1], "DD")) {
+ pstrcpy(subtags[1], sizeof(buf), "DE");
+ } else if (!strcasecmp(subtags[0], "mo")) {
+ pstrcpy(subtags[0], sizeof(buf), "ro");
+ } else if (!strcasecmp(subtags[0], "aar")) {
+ pstrcpy(subtags[0], sizeof(buf), "aa");
+ } else if (!strcasecmp(subtags[0], "heb")) {
+ pstrcpy(subtags[0], sizeof(buf), "he");
+ } else if (!strcasecmp(subtags[0], "ces")) {
+ pstrcpy(subtags[0], sizeof(buf), "cs");
+ } else if (!strcasecmp(subtags[0], "sh")) {
+ int found_script = 0, si;
+ for (si = 1; si < n; si++) {
+ if (strlen(subtags[si]) == 4 && is_alpha(subtags[si], 4)) {
+ found_script = 1;
+ break;
+ }
+ }
+ subtags[0] = "sr";
+ if (!found_script) {
+ if (n > 1)
+ memmove(&subtags[2], &subtags[1], (size_t)(n - 1) * sizeof(char *));
+ subtags[1] = "Latn";
+ n++;
+ }
+ } else if (!strcasecmp(subtags[0], "cnr")) {
+ int found_region = 0, insert_pos = 1, ri;
+ for (ri = 1; ri < n; ri++) {
+ int rlen = (int)strlen(subtags[ri]);
+ if (rlen == 4 && is_alpha(subtags[ri], 4)) {
+ insert_pos = ri + 1;
+ } else if ((rlen == 2 && is_alpha(subtags[ri], 2)) ||
+ (rlen == 3 && is_digit(subtags[ri], 3))) {
+ found_region = 1;
+ break;
+ }
+ }
+ subtags[0] = "sr";
+ if (!found_region) {
+ if (insert_pos < n)
+ memmove(&subtags[insert_pos + 1], &subtags[insert_pos], (size_t)(n - insert_pos) * sizeof(char *));
+ subtags[insert_pos] = "ME";
+ n++;
+ }
+ } else if (n == 2 && !strcasecmp(subtags[0], "hy") && !strcasecmp(subtags[1], "arevela")) {
+ pstrcpy(buf, sizeof(buf), "hy");
+ subtags[0] = buf;
+ n = 1;
+ } else if (n == 2 && !strcasecmp(subtags[0], "hy") && !strcasecmp(subtags[1], "arevmda")) {
+ pstrcpy(buf, sizeof(buf), "hyw");
+ subtags[0] = buf;
+ n = 1;
+ } else if (n == 2 && !strcasecmp(subtags[0], "art") && !strcasecmp(subtags[1], "lojban")) {
+ pstrcpy(buf, sizeof(buf), "jbo");
+ subtags[0] = buf;
+ n = 1;
+ } else if (n == 2 && !strcasecmp(subtags[0], "cel") && !strcasecmp(subtags[1], "gaulish")) {
+ pstrcpy(buf, sizeof(buf), "xtg");
+ subtags[0] = buf;
+ n = 1;
+ } else if (n == 2 && !strcasecmp(subtags[0], "zh") && !strcasecmp(subtags[1], "guoyu")) {
+ pstrcpy(buf, sizeof(buf), "zh");
+ subtags[0] = buf;
+ n = 1;
+ } else if (n == 2 && !strcasecmp(subtags[0], "zh") && !strcasecmp(subtags[1], "hakka")) {
+ pstrcpy(buf, sizeof(buf), "hak");
+ subtags[0] = buf;
+ n = 1;
+ } else if (n == 2 && !strcasecmp(subtags[0], "zh") && !strcasecmp(subtags[1], "xiang")) {
+ pstrcpy(buf, sizeof(buf), "hsn");
+ subtags[0] = buf;
+ n = 1;
+ }
+
+ /* identify extension blocks for reordering */
+ base_end = n;
+ for (i = 1; i < n; i++) {
+ if (strlen(subtags[i]) == 1) {
+ char c = (char)tolower((unsigned char)subtags[i][0]);
+ /* found a singleton, this starts an extension block */
+ if (ext_count < 16) {
+ ext_blocks[ext_count].start = i;
+ ext_blocks[ext_count].singleton = c;
+ /* find the end of this extension block */
+ int j;
+ for (j = i + 1; j < n; j++) {
+ if (strlen(subtags[j]) == 1)
+ break;
+ }
+ ext_blocks[ext_count].len = j - i;
+ ext_count++;
+ i = j - 1; /* skip to end of this block */
+ }
+ base_end = i; /* base ends before first extension */
+ if (c == 'x') {
+ /* private use: everything after is part of this block */
+ if (ext_count > 0) {
+ ext_blocks[ext_count - 1].len = n - ext_blocks[ext_count - 1].start;
+ }
+ break;
+ }
+ }
+ }
+ /* base_end should be the index of the first singleton */
+ if (ext_count > 0)
+ base_end = ext_blocks[0].start;
+
+ /* sort extension blocks by singleton */
+ if (ext_count > 1)
+ qsort(ext_blocks, (size_t)ext_count, sizeof(ExtBlock), ext_block_cmp);
+
+ /* apply case rules to all subtags */
+ for (i = 0; i < n; i++) {
+ int len = (int)strlen(subtags[i]);
+
+ if (in_extension) {
+ if (len == 1) {
+ in_extension = 0;
+ /* reprocess below */
+ } else {
+ strntolower(subtags[i], len);
+ continue;
+ }
+ }
+
+ if (len == 1) {
+ /* singleton */
+ if (subtags[i][0] == 'x' || subtags[i][0] == 'X') {
+ /* private use, lowercase it */
+ strntolower(subtags[i], len);
+ /* everything after is lowercase too */
+ for (i = i + 1; i < n; i++)
+ strntolower(subtags[i], (int)strlen(subtags[i]));
+ break;
+ }
+ strntolower(subtags[i], len);
+ in_extension = 1;
+ continue;
+ }
+
+ if (i == 0) {
+ /* language: lowercase */
+ strntolower(subtags[i], len);
+ continue;
+ }
+
+ if (!has_script && !has_region && len == 4 && is_alpha(subtags[i], 4)) {
+ /* script: Titlecase */
+ if (subtags[i][0] >= 'a' && subtags[i][0] <= 'z')
+ subtags[i][0] -= 32;
+ {
+ int j;
+ for (j = 1; j < 4; j++) {
+ if (subtags[i][j] >= 'A' && subtags[i][j] <= 'Z')
+ subtags[i][j] += 32;
+ }
+ }
+ has_script = 1;
+ continue;
+ }
+
+ if (!has_region && ((len == 2 && is_alpha(subtags[i], 2)) ||
+ (len == 3 && is_digit(subtags[i], 3)))) {
+ /* region: UPPERCASE */
+ strntoupper(subtags[i], len);
+ /* Map numeric UN M.49 region codes to ISO 3166-1 alpha-2 */
+ if (len == 3) {
+ if (!strcmp(subtags[i], "554"))
+ pstrcpy(subtags[i], sizeof(buf), "NZ");
+ }
+ /* Region alias replacements */
+ if (!strcmp(subtags[i], "SU") || !strcmp(subtags[i], "810")) {
+ int has_armn = 0;
+ if (!strcmp(subtags[0], "hy"))
+ has_armn = 1;
+ else if (has_script) {
+ int j;
+ for (j = i - 1; j > 0; j--) {
+ if (strlen(subtags[j]) == 4 && is_alpha(subtags[j], 4)) {
+ if (!strcmp(subtags[j], "Armn"))
+ has_armn = 1;
+ break;
+ }
+ }
+ }
+ pstrcpy(subtags[i], sizeof(buf), has_armn ? "AM" : "RU");
+ } else if (!strcmp(subtags[i], "CS")) {
+ pstrcpy(subtags[i], sizeof(buf), "RS");
+ } else if (!strcmp(subtags[i], "NT")) {
+ pstrcpy(subtags[i], sizeof(buf), "SA");
+ }
+ has_region = 1;
+ continue;
+ }
+
+ /* variant or other: lowercase */
+ strntolower(subtags[i], len);
+ /* variant alias mappings */
+ if (!strcmp(subtags[i], "heploc"))
+ pstrcpy(subtags[i], sizeof(buf), "alalc97");
+ }
+ {
+ /* Special case: hepburn + heploc -> alalc97 (remove hepburn) */
+ int has_alalc97 = 0, has_hepburn = 0;
+ for (i = 0; i < base_end; i++) {
+ if (!strcmp(subtags[i], "alalc97")) has_alalc97 = 1;
+ if (!strcmp(subtags[i], "hepburn")) has_hepburn = 1;
+ }
+ if (has_alalc97 && has_hepburn) {
+ for (i = 0; i < base_end; i++) {
+ if (!strcmp(subtags[i], "hepburn")) {
+ subtags[i] = "";
+ }
+ }
+ }
+ }
+
+ /* Sort base tag variants alphabetically */
+ {
+ int var_start = 0;
+ if (base_end > 1) {
+ if (base_end > 2 && strlen(subtags[1]) == 4 && is_alpha(subtags[1], 4))
+ var_start = 2;
+ else
+ var_start = 1;
+ if (var_start < base_end && ((strlen(subtags[var_start]) == 2 && is_alpha(subtags[var_start], 2)) ||
+ (strlen(subtags[var_start]) == 3 && is_digit(subtags[var_start], 3))))
+ var_start++;
+ }
+ if (var_start < base_end && base_end - var_start > 1) {
+ qsort(&subtags[var_start], (size_t)(base_end - var_start), sizeof(char *), cmp_str);
+ }
+ }
+
+ /* After sorting, apply grandfathered alias replacements for regular grandfathered tags
+ when combined with extra subtags (e.g., art-lojban-fonipa -> jbo-fonipa) */
+ {
+ int gf_variant = -1;
+ if (!strcasecmp(subtags[0], "art")) {
+ for (i = 1; i < base_end; i++) {
+ if (!strcasecmp(subtags[i], "lojban")) { gf_variant = i; break; }
+ }
+ } else if (!strcasecmp(subtags[0], "cel")) {
+ for (i = 1; i < base_end; i++) {
+ if (!strcasecmp(subtags[i], "gaulish")) { gf_variant = i; break; }
+ }
+ } else if (!strcasecmp(subtags[0], "zh")) {
+ for (i = 1; i < base_end; i++) {
+ if (!strcasecmp(subtags[i], "guoyu")) { gf_variant = i; break; }
+ if (!strcasecmp(subtags[i], "hakka")) { gf_variant = i; break; }
+ if (!strcasecmp(subtags[i], "xiang")) { gf_variant = i; break; }
+ }
+ }
+ if (gf_variant >= 0) {
+ if (!strcasecmp(subtags[0], "art")) {
+ subtags[0] = "jbo";
+ } else if (!strcasecmp(subtags[0], "cel")) {
+ subtags[0] = "xtg";
+ } else if (!strcasecmp(subtags[0], "zh")) {
+ if (!strcasecmp(subtags[gf_variant], "guoyu"))
+ subtags[0] = "zh";
+ else if (!strcasecmp(subtags[gf_variant], "hakka"))
+ subtags[0] = "hak";
+ else if (!strcasecmp(subtags[gf_variant], "xiang"))
+ subtags[0] = "hsn";
+ }
+ subtags[gf_variant] = "";
+ /* compact empty slots */
+ {
+ int j, k = 0;
+ for (j = 0; j < base_end; j++) {
+ if (strlen(subtags[j]) > 0) {
+ if (j != k)
+ subtags[k] = subtags[j];
+ k++;
+ }
+ }
+ base_end = k;
+ }
+ }
+ }
+
+ /* reconstruct using DynBuf: base subtags + sorted extensions */
+ js_intl_dbuf_init(ctx, &dbuf);
+ for (i = 0; i < base_end; i++) {
+ if (strlen(subtags[i]) == 0)
+ continue;
+ if (dbuf.size > 0)
+ dbuf_putc(&dbuf, '-');
+ dbuf_putstr(&dbuf, subtags[i]);
+ }
+ {
+ int e;
+ for (e = 0; e < ext_count; e++) {
+ int j;
+ char singleton = subtags[ext_blocks[e].start][0];
+ /* t-extension canonicalization */
+ if (singleton == 't') {
+ int t_start = ext_blocks[e].start + 1;
+ int t_len = ext_blocks[e].len - 1;
+ int has_tlang = 0;
+ int tlang_end = 0;
+ if (t_len > 0) {
+ const char *first = subtags[t_start];
+ int flen = (int)strlen(first);
+ if ((flen == 2 || flen == 3 || (flen >= 5 && flen <= 8)) && is_alpha(first, flen)) {
+ has_tlang = 1;
+ tlang_end = 1;
+ if (tlang_end < t_len && strlen(subtags[t_start + tlang_end]) == 4 &&
+ is_alpha(subtags[t_start + tlang_end], 4))
+ tlang_end++;
+ if (tlang_end < t_len &&
+ ((strlen(subtags[t_start + tlang_end]) == 2 && is_alpha(subtags[t_start + tlang_end], 2)) ||
+ (strlen(subtags[t_start + tlang_end]) == 3 && is_digit(subtags[t_start + tlang_end], 3))))
+ tlang_end++;
+ while (tlang_end < t_len) {
+ const char *sub = subtags[t_start + tlang_end];
+ int sublen = (int)strlen(sub);
+ if (sublen == 2 &&
+ ((is_alpha(sub, 1) && is_digit(sub + 1, 1)) ||
+ (is_digit(sub, 1) && is_alpha(sub + 1, 1))))
+ break;
+ tlang_end++;
+ }
+ }
+ }
+ if (has_tlang) {
+ int var_start = 1;
+ if (var_start < tlang_end && strlen(subtags[t_start + var_start]) == 4 &&
+ is_alpha(subtags[t_start + var_start], 4))
+ var_start++;
+ if (var_start < tlang_end &&
+ ((strlen(subtags[t_start + var_start]) == 2 && is_alpha(subtags[t_start + var_start], 2)) ||
+ (strlen(subtags[t_start + var_start]) == 3 && is_digit(subtags[t_start + var_start], 3))))
+ var_start++;
+ if (var_start < tlang_end && tlang_end - var_start > 1)
+ qsort(&subtags[t_start + var_start], (size_t)(tlang_end - var_start), sizeof(char *), cmp_str);
+ if (!strcmp(subtags[t_start], "iw"))
+ subtags[t_start] = "he";
+ }
+ {
+ typedef struct { const char *key; int nvalues; const char *values[4]; } TFieldEntry;
+ TFieldEntry tfields[16];
+ int ntfields = 0;
+ int pos = has_tlang ? tlang_end : 0;
+ while (pos < t_len) {
+ const char *key = subtags[t_start + pos];
+ pos++;
+ int nvalues = 0;
+ const char *values[4];
+ while (pos < t_len) {
+ const char *sub = subtags[t_start + pos];
+ int sublen = (int)strlen(sub);
+ if (sublen == 2 &&
+ ((is_alpha(sub, 1) && is_digit(sub + 1, 1)) ||
+ (is_digit(sub, 1) && is_alpha(sub + 1, 1))))
+ break;
+ if (nvalues < 4) {
+ if (!strcmp(sub, "names"))
+ values[nvalues] = "prprname";
+ else
+ values[nvalues] = sub;
+ nvalues++;
+ }
+ pos++;
+ }
+ if (ntfields < 16) {
+ int v;
+ tfields[ntfields].key = key;
+ tfields[ntfields].nvalues = nvalues;
+ for (v = 0; v < nvalues; v++)
+ tfields[ntfields].values[v] = values[v];
+ ntfields++;
+ }
+ }
+ if (ntfields > 1) {
+ int a, b;
+ for (a = 0; a < ntfields - 1; a++) {
+ for (b = a + 1; b < ntfields; b++) {
+ if (strcmp(tfields[a].key, tfields[b].key) > 0) {
+ TFieldEntry tmp = tfields[a];
+ tfields[a] = tfields[b];
+ tfields[b] = tmp;
+ }
+ }
+ }
+ }
+ dbuf_putc(&dbuf, '-');
+ dbuf_putstr(&dbuf, "t");
+ if (has_tlang) {
+ for (j = 0; j < tlang_end; j++) {
+ dbuf_putc(&dbuf, '-');
+ dbuf_putstr(&dbuf, subtags[t_start + j]);
+ }
+ }
+ for (j = 0; j < ntfields; j++) {
+ int v;
+ dbuf_putc(&dbuf, '-');
+ dbuf_putstr(&dbuf, tfields[j].key);
+ for (v = 0; v < tfields[j].nvalues; v++) {
+ dbuf_putc(&dbuf, '-');
+ dbuf_putstr(&dbuf, tfields[j].values[v]);
+ }
+ }
+ }
+ continue;
+ }
+ for (j = 0; j < ext_blocks[e].len; j++) {
+ const char *sub = subtags[ext_blocks[e].start + j];
+ int slen = (int)strlen(sub);
+ /* u-extension: canonicalize yes -> true for specific keys, then strip true */
+ if (singleton == 'u' && slen == 2 && is_alpha(sub, 1) &&
+ (is_alpha(sub + 1, 1) || is_digit(sub + 1, 1))) {
+ int skip_value = 0;
+ const char *value = NULL;
+ if (j + 1 < ext_blocks[e].len) {
+ const char *next = subtags[ext_blocks[e].start + j + 1];
+ int nlen = (int)strlen(next);
+ if (nlen != 1 || (is_alpha(next, 1) && is_digit(next, 1))) {
+ /* next is a value segment, not a key or singleton */
+ value = next;
+ if (!strcmp(next, "yes") &&
+ (!strcmp(sub, "kb") || !strcmp(sub, "kc") ||
+ !strcmp(sub, "kh") || !strcmp(sub, "kk") ||
+ !strcmp(sub, "kn"))) {
+ skip_value = 1;
+ } else if (!strcmp(next, "true")) {
+ skip_value = 1;
+ } else if (!strcmp(sub, "ca")) {
+ if (!strcmp(next, "ethiopic-amete-alem"))
+ value = "ethioaa";
+ else if (!strcmp(next, "islamicc"))
+ value = "islamic-civil";
+ else if (!strcmp(next, "ethiopic") && j + 3 < ext_blocks[e].len &&
+ !strcmp(subtags[ext_blocks[e].start + j + 2], "amete") &&
+ !strcmp(subtags[ext_blocks[e].start + j + 3], "alem")) {
+ value = "ethioaa";
+ j += 2; /* skip the extra segments */
+ }
+ } else if (!strcmp(sub, "ms")) {
+ if (!strcmp(next, "imperial"))
+ value = "uksystem";
+ } else if (!strcmp(sub, "ks")) {
+ if (!strcmp(next, "primary"))
+ value = "level1";
+ else if (!strcmp(next, "tertiary"))
+ value = "level3";
+ } else if (!strcmp(sub, "tz")) {
+ if (!strcmp(next, "cnckg"))
+ value = "cnsha";
+ else if (!strcmp(next, "eire"))
+ value = "iedub";
+ else if (!strcmp(next, "est"))
+ value = "papty";
+ else if (!strcmp(next, "gmt0"))
+ value = "gmt";
+ else if (!strcmp(next, "uct"))
+ value = "utc";
+ else if (!strcmp(next, "zulu"))
+ value = "utc";
+ } else if (!strcmp(sub, "rg") || !strcmp(sub, "sd")) {
+ if (!strcmp(next, "no23"))
+ value = "no50";
+ else if (!strcmp(next, "cn11"))
+ value = "cnbj";
+ else if (!strcmp(next, "cz10a"))
+ value = "cz110";
+ else if (!strcmp(next, "fra"))
+ value = "frges";
+ else if (!strcmp(next, "frg"))
+ value = "frges";
+ else if (!strcmp(next, "lud"))
+ value = "lucl";
+ }
+ }
+ }
+ dbuf_putc(&dbuf, '-');
+ dbuf_putstr(&dbuf, sub);
+ if (value && !skip_value) {
+ dbuf_putc(&dbuf, '-');
+ dbuf_putstr(&dbuf, value);
+ j++;
+ } else if (skip_value) {
+ j++;
+ }
+ continue;
+ }
+ dbuf_putc(&dbuf, '-');
+ dbuf_putstr(&dbuf, sub);
+ }
+ }
+ }
+ dbuf_putc(&dbuf, '\0');
+ if (dbuf_error(&dbuf)) {
+ dbuf_free(&dbuf);
+ return NULL;
+ }
+ result = (char *)dbuf.buf;
+ return result;
+}
+
+void js_intl_dbuf_init(JSContext *ctx, DynBuf *s)
+{
+ dbuf_init2(s, ctx, (DynBufReallocFunc *)js_realloc);
+}
+
+/* Helper to create an Intl constructor and register it on the Intl object */
+JSValue js_intl_new_constructor(JSContext *ctx, JSValue intl_obj,
+ int intl_idx,
+ JSClassID class_id,
+ const char *name,
+ JSCFunction *func, int length,
+ JSCFunctionEnum cproto, int magic,
+ const JSCFunctionListEntry *static_funcs, int n_static,
+ const JSCFunctionListEntry *proto_funcs, int n_proto)
+{
+ JSValue ctor = JS_NewCConstructor(ctx, (int)class_id, name, func, length, cproto, magic,
+ JS_UNDEFINED,
+ static_funcs, n_static,
+ proto_funcs, n_proto,
+ JS_NEW_CTOR_NO_GLOBAL);
+ if (JS_IsException(ctor))
+ return JS_EXCEPTION;
+ if (intl_idx >= 0)
+ JS_SetContextValue(ctx, intl_idx, JS_DupValue(ctx, ctor));
+ if (JS_DefinePropertyValueStr(ctx, intl_obj, name, ctor,
+ JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE) < 0)
+ return JS_EXCEPTION;
+ return JS_UNDEFINED;
+}
+
+/* --------------------------------------------------------------------- */
+/* CanonicalizeLocaleList (locales) */
+/* --------------------------------------------------------------------- */
+
+/* Internal core: canonicalize locales into a C array of strings.
+ Returns 0 on success, -1 on exception.
+ On success, *plocales is an array of canonical strings (allocated with
+ js_strdup / js_realloc) and *pcount is the number of strings.
+ Caller must free with js_canonicalizeLocaleList_free_c(). */
+static int js_canonicalizeLocaleList_core(JSContext *ctx, JSValueConst locales,
+ char ***plocales, int *pcount)
+{
+ JSValue O = JS_UNDEFINED;
+ int64_t len, k;
+ int ret;
+ char **arr = NULL;
+ int arr_count = 0;
+ int arr_size = 0;
+
+ *plocales = NULL;
+ *pcount = 0;
+
+ if (JS_IsUndefined(locales))
+ return 0;
+
+ {
+ JSValue locale_str = JS_UNDEFINED;
+ int is_locale = 0;
+ if (JS_IsObject(locales)) {
+ locale_str = js_locale_get_locale_string(ctx, locales);
+ if (JS_IsException(locale_str))
+ goto fail;
+ is_locale = !JS_IsUndefined(locale_str);
+ if (!is_locale)
+ JS_FreeValue(ctx, locale_str);
+ }
+ if (JS_IsString(locales) || is_locale) {
+ O = JS_NewArray(ctx);
+ if (JS_IsException(O))
+ goto fail;
+ ret = JS_DefinePropertyValueUint32(ctx, O, 0, JS_DupValue(ctx, locales),
+ JS_PROP_C_W_E);
+ if (ret < 0)
+ goto fail;
+ ret = JS_DefinePropertyValueStr(ctx, O, "length", JS_NewInt32(ctx, 1),
+ JS_PROP_C_W_E);
+ if (ret < 0)
+ goto fail;
+ if (is_locale)
+ JS_FreeValue(ctx, locale_str);
+ } else {
+ O = JS_ToObject(ctx, locales);
+ if (JS_IsException(O))
+ goto fail;
+ }
+ }
+
+ {
+ JSValue len_val = JS_GetPropertyStr(ctx, O, "length");
+ if (JS_IsException(len_val))
+ goto fail;
+ ret = JS_ToInt64(ctx, &len, len_val);
+ JS_FreeValue(ctx, len_val);
+ if (ret < 0)
+ goto fail;
+ }
+
+ for (k = 0; k < len; k++) {
+ JSValue val;
+ int has_prop;
+ const char *tag;
+ char *canonical;
+ int i;
+
+ {
+ JSAtom prop = JS_NewAtomUInt32(ctx, (uint32_t)k);
+ has_prop = JS_HasProperty(ctx, O, prop);
+ JS_FreeAtom(ctx, prop);
+ }
+ if (has_prop < 0)
+ goto fail;
+ if (!has_prop)
+ continue;
+
+ val = JS_GetPropertyUint32(ctx, O, (uint32_t)k);
+ if (JS_IsException(val))
+ goto fail;
+
+ if (!JS_IsString(val) && !JS_IsObject(val)) {
+ JS_FreeValue(ctx, val);
+ JS_ThrowTypeError(ctx, "locale must be a string or object");
+ goto fail;
+ }
+
+ if (JS_IsObject(val)) {
+ JSValue loc_str = js_locale_get_locale_string(ctx, val);
+ if (JS_IsException(loc_str)) {
+ JS_FreeValue(ctx, val);
+ goto fail;
+ }
+ if (!JS_IsUndefined(loc_str)) {
+ tag = JS_ToCStringNZ(ctx, loc_str);
+ JS_FreeValue(ctx, loc_str);
+ if (!tag) {
+ JS_FreeValue(ctx, val);
+ goto fail;
+ }
+ } else {
+ tag = JS_ToCStringNZ(ctx, val);
+ if (!tag) {
+ JS_FreeValue(ctx, val);
+ goto fail;
+ }
+ }
+ JS_FreeValue(ctx, val);
+ } else {
+ tag = JS_ToCStringNZ(ctx, val);
+ JS_FreeValue(ctx, val);
+ if (!tag)
+ goto fail;
+ }
+
+ if (!is_wellformed_language_tag(tag)) {
+ JS_FreeCString(ctx, tag);
+ JS_ThrowRangeError(ctx, "invalid language tag");
+ goto fail;
+ }
+
+ canonical = canonicalize_locale(ctx, tag);
+ JS_FreeCString(ctx, tag);
+
+ if (!canonical)
+ goto fail;
+
+ /* check for duplicates against C array */
+ for (i = 0; i < arr_count; i++) {
+ if (!strcmp(arr[i], canonical)) {
+ js_free(ctx, canonical);
+ canonical = NULL;
+ break;
+ }
+ }
+ if (!canonical)
+ continue;
+
+ if (arr_count >= arr_size) {
+ int new_size = arr_size ? arr_size * 2 : 4;
+ char **new_arr = js_realloc(ctx, arr, (size_t)new_size * sizeof(*arr));
+ if (!new_arr) {
+ js_free(ctx, canonical);
+ goto fail;
+ }
+ arr = new_arr;
+ arr_size = new_size;
+ }
+ arr[arr_count++] = canonical;
+ }
+
+ JS_FreeValue(ctx, O);
+ *plocales = arr;
+ *pcount = arr_count;
+ return 0;
+
+fail:
+ JS_FreeValue(ctx, O);
+ if (arr) {
+ for (k = 0; k < arr_count; k++)
+ js_free(ctx, arr[k]);
+ js_free(ctx, arr);
+ }
+ return -1;
+}
+
+int js_canonicalizeLocaleList_c(JSContext *ctx, JSValueConst locales,
+ char ***plocales, int *pcount)
+{
+ return js_canonicalizeLocaleList_core(ctx, locales, plocales, pcount);
+}
+
+void js_canonicalizeLocaleList_free_c(JSContext *ctx, char **locales, int count)
+{
+ int i;
+ if (locales) {
+ for (i = 0; i < count; i++)
+ js_free(ctx, locales[i]);
+ js_free(ctx, locales);
+ }
+}
+
+/* Convenience: return the first canonical locale string via *plocale.
+ Returns 0 on success (empty list yields *plocale = NULL), -1 on exception.
+ Caller must free with js_free. */
+int js_canonicalizeLocaleList_first(JSContext *ctx, JSValueConst locales, char **plocale)
+{
+ char **arr = NULL;
+ int count = 0;
+
+ *plocale = NULL;
+ if (js_canonicalizeLocaleList_core(ctx, locales, &arr, &count) < 0)
+ return -1;
+ if (count > 0) {
+ *plocale = arr[0];
+ /* Shift remaining down and free the array container */
+ if (count > 1) {
+ int i;
+ for (i = 1; i < count; i++)
+ js_free(ctx, arr[i]);
+ }
+ js_free(ctx, arr);
+ }
+ return 0;
+}
+
+JSValue js_canonicalizeLocaleList(JSContext *ctx, JSValueConst locales)
+{
+ char **arr = NULL;
+ int count = 0;
+ int i;
+ JSValue result;
+
+ if (js_canonicalizeLocaleList_core(ctx, locales, &arr, &count) < 0)
+ return JS_EXCEPTION;
+
+ result = JS_NewArray(ctx);
+ if (JS_IsException(result))
+ goto fail;
+
+ for (i = 0; i < count; i++) {
+ JSValue str = JS_NewString(ctx, arr[i]);
+ if (JS_IsException(str))
+ goto fail;
+ if (JS_DefinePropertyValueUint32(ctx, result, (uint32_t)i, str,
+ JS_PROP_C_W_E) < 0)
+ goto fail;
+ }
+
+ js_canonicalizeLocaleList_free_c(ctx, arr, count);
+ return result;
+ fail:
+ js_canonicalizeLocaleList_free_c(ctx, arr, count);
+ JS_FreeValue(ctx, result);
+ return JS_EXCEPTION;
+}
+
+/* --------------------------------------------------------------------- */
+/* Intl.getCanonicalLocales (locales) */
+/* --------------------------------------------------------------------- */
+
+static JSValue js_intl_getCanonicalLocales(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ return js_canonicalizeLocaleList(ctx, argv[0]);
+}
+
+/* --------------------------------------------------------------------- */
+/* Intl.supportedValuesOf (key) */
+/* --------------------------------------------------------------------- */
+
+static JSValue js_intl_supportedValuesOf(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ const char *key;
+ JSValue result;
+
+ key = JS_ToCStringNZ(ctx, argc > 0 ? argv[0] : JS_UNDEFINED);
+ if (!key)
+ return JS_EXCEPTION;
+
+ result = JS_NewArray(ctx);
+ if (!strcmp(key, "calendar")) {
+ int i;
+ for (i = 0; i < CAL_COUNT; i++) {
+ JS_DefinePropertyValueUint32(ctx, result, (uint32_t)i,
+ JS_NewString(ctx, ti_calendar_enum_to_string(i)),
+ JS_PROP_C_W_E);
+ }
+ } else if (!strcmp(key, "collation")) {
+ int i;
+ for (i = 0; i < intl_supported_collations_count; i++) {
+ JS_DefinePropertyValueUint32(ctx, result, (uint32_t)i,
+ JS_NewString(ctx, intl_supported_collations[i]),
+ JS_PROP_C_W_E);
+ }
+ } else if (!strcmp(key, "currency")) {
+ int i;
+ for (i = 0; i < intl_supported_currencies_count; i++) {
+ JS_DefinePropertyValueUint32(ctx, result, (uint32_t)i,
+ JS_NewString(ctx, intl_supported_currencies[i]),
+ JS_PROP_C_W_E);
+ }
+ } else if (!strcmp(key, "numberingSystem")) {
+ int i;
+ for (i = 0; i < intl_all_numbering_systems_count; i++) {
+ JS_DefinePropertyValueUint32(ctx, result, (uint32_t)i,
+ JS_NewString(ctx, intl_all_numbering_systems[i]),
+ JS_PROP_C_W_E);
+ }
+ } else if (!strcmp(key, "timeZone")) {
+ int i;
+ for (i = 0; i < ti_tz_zone_count; i++) {
+ JS_DefinePropertyValueUint32(ctx, result, (uint32_t)i,
+ JS_NewString(ctx, ti_tz_zone_data[i].canonical_name),
+ JS_PROP_C_W_E);
+ }
+ } else if (!strcmp(key, "unit")) {
+ int i;
+ for (i = 0; i < sanctioned_simple_units_count; i++) {
+ JS_DefinePropertyValueUint32(ctx, result, (uint32_t)i,
+ JS_NewString(ctx, sanctioned_simple_units[i]),
+ JS_PROP_C_W_E);
+ }
+ } else {
+ JS_FreeValue(ctx, result);
+ JS_ThrowRangeError(ctx, "invalid key: %s", key);
+ JS_FreeCString(ctx, key);
+ return JS_EXCEPTION;
+ }
+
+ JS_FreeCString(ctx, key);
+ return result;
+}
+
+/* --------------------------------------------------------------------- */
+/* Intl object definition */
+/* --------------------------------------------------------------------- */
+
+static const JSCFunctionListEntry js_intl_funcs[] = {
+ JS_CFUNC_DEF("getCanonicalLocales", 1, js_intl_getCanonicalLocales),
+ JS_CFUNC_DEF("supportedValuesOf", 1, js_intl_supportedValuesOf),
+ JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Intl", JS_PROP_CONFIGURABLE),
+};
+
+int JS_AddIntrinsicIntl(JSContext *ctx)
+{
+ JSValue global_obj, intl_obj;
+ int ret;
+
+ global_obj = JS_GetGlobalObject(ctx);
+ intl_obj = JS_NewObject(ctx);
+ if (JS_IsException(intl_obj))
+ goto fail;
+
+ /* add functions and Symbol.toStringTag */
+ ret = JS_SetPropertyFunctionList(ctx, intl_obj, js_intl_funcs,
+ countof(js_intl_funcs));
+ if (ret < 0)
+ goto fail;
+
+ /* add Locale constructor */
+ ret = js_add_locale(ctx, intl_obj);
+ if (ret < 0)
+ goto fail;
+
+ /* add NumberFormat constructor */
+ ret = js_add_numberformat(ctx, intl_obj);
+ if (ret < 0)
+ goto fail;
+
+ /* add Collator constructor */
+ ret = js_add_collator(ctx, intl_obj);
+ if (ret < 0)
+ goto fail;
+
+ /* add DateTimeFormat constructor */
+ ret = js_add_datetimeformat(ctx, intl_obj);
+ if (ret < 0)
+ goto fail;
+
+ /* add PluralRules constructor */
+ ret = js_add_pluralrules(ctx, intl_obj);
+ if (ret < 0)
+ goto fail;
+
+ /* add ListFormat constructor */
+ ret = js_add_listformat(ctx, intl_obj);
+ if (ret < 0)
+ goto fail;
+
+ /* add RelativeTimeFormat constructor */
+ ret = js_add_relativetimeformat(ctx, intl_obj);
+ if (ret < 0)
+ goto fail;
+
+ /* add DisplayNames constructor */
+ ret = js_add_displaynames(ctx, intl_obj);
+ if (ret < 0)
+ goto fail;
+
+ /* add Segmenter constructor */
+ ret = js_add_segmenter(ctx, intl_obj);
+ if (ret < 0)
+ goto fail;
+
+ /* add DurationFormat constructor */
+ ret = js_add_durationformat(ctx, intl_obj);
+ if (ret < 0)
+ goto fail;
+
+ /* Create [[FallbackSymbol]] for legacy constructor chaining */
+ {
+ JSValue sym = JS_NewSymbol(ctx, "IntlLegacyConstructedSymbol", FALSE);
+ if (JS_IsException(sym))
+ goto fail;
+ JS_SetContextValue(ctx, JS_INTL_FALLBACK_SYMBOL, sym);
+ }
+
+ /* set Intl on global object */
+ ret = JS_SetPropertyStr(ctx, global_obj, "Intl", intl_obj);
+ JS_FreeValue(ctx, global_obj);
+ if (ret < 0)
+ return -1;
+
+ js_intl_set_locale_callbacks(ctx);
+
+ return 0;
+fail:
+ JS_FreeValue(ctx, intl_obj);
+ JS_FreeValue(ctx, global_obj);
+ return -1;
+}
+
+/* --------------------------------------------------------------------- */
+/* Date locale callbacks */
+/* --------------------------------------------------------------------- */
+
+int js_intl_options_has_date_fields(JSContext *ctx, JSValueConst options)
+{
+ static const char *date_fields[] = {"weekday", "year", "month", "day", "dateStyle"};
+ int i;
+ if (JS_IsUndefined(options) || JS_IsNull(options))
+ return 0;
+ for (i = 0; i < 5; i++) {
+ JSValue v = JS_GetPropertyStr(ctx, options, date_fields[i]);
+ if (JS_IsException(v)) {
+ JS_FreeValue(ctx, v);
+ return -1;
+ }
+ if (!JS_IsUndefined(v)) {
+ JS_FreeValue(ctx, v);
+ return 1;
+ }
+ JS_FreeValue(ctx, v);
+ }
+ return 0;
+}
+
+int js_intl_options_has_time_fields(JSContext *ctx, JSValueConst options)
+{
+ static const char *time_fields[] = {"hour", "minute", "second", "timeStyle"};
+ int i;
+ if (JS_IsUndefined(options) || JS_IsNull(options))
+ return 0;
+ for (i = 0; i < 4; i++) {
+ JSValue v = JS_GetPropertyStr(ctx, options, time_fields[i]);
+ if (JS_IsException(v)) {
+ JS_FreeValue(ctx, v);
+ return -1;
+ }
+ if (!JS_IsUndefined(v)) {
+ JS_FreeValue(ctx, v);
+ return 1;
+ }
+ JS_FreeValue(ctx, v);
+ }
+ return 0;
+}
+
+static JSValue js_intl_date_toLocaleString(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv, int part)
+{
+ double dval;
+ JSValue ctor, obj, format_func, result;
+ JSValue new_argv[2];
+ int has_options = (argc > 1 && !JS_IsUndefined(argv[1]));
+
+ if (JS_ThisDateValue(ctx, &dval, this_val) < 0)
+ return JS_EXCEPTION;
+ if (isnan(dval))
+ return JS_NewString(ctx, "Invalid Date");
+
+ ctor = JS_GetContextValue(ctx, JS_INTL_CTOR_DATETIMEFORMAT);
+ if (JS_IsUndefined(ctor))
+ return JS_UNDEFINED;
+
+ new_argv[0] = argc > 0 ? JS_DupValue(ctx, argv[0]) : JS_UNDEFINED;
+ if (has_options) {
+ new_argv[1] = JS_DupValue(ctx, argv[1]);
+ } else {
+ new_argv[1] = JS_NewObject(ctx);
+ if (JS_IsException(new_argv[1])) {
+ JS_FreeValue(ctx, ctor);
+ JS_FreeValue(ctx, new_argv[0]);
+ return JS_EXCEPTION;
+ }
+ }
+
+ if (!JS_IsException(new_argv[1])) {
+ if (part == 3) { /* toLocaleString */
+ if (!has_options ||
+ (!js_intl_options_has_date_fields(ctx, new_argv[1]) &&
+ !js_intl_options_has_time_fields(ctx, new_argv[1]))) {
+ JS_DefinePropertyValueStr(ctx, new_argv[1], "year",
+ JS_NewString(ctx, "numeric"), JS_PROP_C_W_E);
+ JS_DefinePropertyValueStr(ctx, new_argv[1], "month",
+ JS_NewString(ctx, "numeric"), JS_PROP_C_W_E);
+ JS_DefinePropertyValueStr(ctx, new_argv[1], "day",
+ JS_NewString(ctx, "numeric"), JS_PROP_C_W_E);
+ JS_DefinePropertyValueStr(ctx, new_argv[1], "hour",
+ JS_NewString(ctx, "numeric"), JS_PROP_C_W_E);
+ JS_DefinePropertyValueStr(ctx, new_argv[1], "minute",
+ JS_NewString(ctx, "numeric"), JS_PROP_C_W_E);
+ JS_DefinePropertyValueStr(ctx, new_argv[1], "second",
+ JS_NewString(ctx, "numeric"), JS_PROP_C_W_E);
+ }
+ } else if (part == 1) { /* toLocaleDateString */
+ if (!has_options || !js_intl_options_has_date_fields(ctx, new_argv[1])) {
+ JS_DefinePropertyValueStr(ctx, new_argv[1], "year",
+ JS_NewString(ctx, "numeric"), JS_PROP_C_W_E);
+ JS_DefinePropertyValueStr(ctx, new_argv[1], "month",
+ JS_NewString(ctx, "numeric"), JS_PROP_C_W_E);
+ JS_DefinePropertyValueStr(ctx, new_argv[1], "day",
+ JS_NewString(ctx, "numeric"), JS_PROP_C_W_E);
+ }
+ } else if (part == 2) { /* toLocaleTimeString */
+ if (!has_options || !js_intl_options_has_time_fields(ctx, new_argv[1])) {
+ JS_DefinePropertyValueStr(ctx, new_argv[1], "hour",
+ JS_NewString(ctx, "numeric"), JS_PROP_C_W_E);
+ JS_DefinePropertyValueStr(ctx, new_argv[1], "minute",
+ JS_NewString(ctx, "numeric"), JS_PROP_C_W_E);
+ JS_DefinePropertyValueStr(ctx, new_argv[1], "second",
+ JS_NewString(ctx, "numeric"), JS_PROP_C_W_E);
+ }
+ }
+ }
+
+ obj = JS_CallConstructor(ctx, ctor, 2, new_argv);
+ JS_FreeValue(ctx, ctor);
+ JS_FreeValue(ctx, new_argv[0]);
+ JS_FreeValue(ctx, new_argv[1]);
+ if (JS_IsException(obj))
+ return JS_EXCEPTION;
+ format_func = JS_GetPropertyStr(ctx, obj, "format");
+ if (JS_IsException(format_func)) {
+ JS_FreeValue(ctx, obj);
+ return JS_EXCEPTION;
+ }
+ result = JS_Call(ctx, format_func, obj, 1, &this_val);
+ JS_FreeValue(ctx, format_func);
+ JS_FreeValue(ctx, obj);
+ return result;
+}
+
+static JSValue js_intl_string_localeCompare(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSValue ctor, collator, compare, ret, str_a, str_b;
+ JSValueConst collator_argv[2];
+ int collator_argc = 0;
+
+ ctor = JS_GetContextValue(ctx, JS_INTL_CTOR_COLLATOR);
+ if (JS_IsException(ctor))
+ return JS_EXCEPTION;
+
+ if (argc > 1)
+ collator_argv[collator_argc++] = argv[1];
+ if (argc > 2)
+ collator_argv[collator_argc++] = argv[2];
+
+ collator = JS_CallConstructor(ctx, ctor, collator_argc, collator_argv);
+ JS_FreeValue(ctx, ctor);
+ if (JS_IsException(collator))
+ return JS_EXCEPTION;
+
+ compare = JS_GetPropertyStr(ctx, collator, "compare");
+ if (JS_IsException(compare)) {
+ JS_FreeValue(ctx, collator);
+ return JS_EXCEPTION;
+ }
+
+ if (JS_IsNull(this_val) || JS_IsUndefined(this_val)) {
+ JS_FreeValue(ctx, compare);
+ JS_FreeValue(ctx, collator);
+ return JS_ThrowTypeError(ctx, "null or undefined are forbidden");
+ }
+
+ str_a = JS_ToString(ctx, this_val);
+ if (JS_IsException(str_a)) {
+ JS_FreeValue(ctx, compare);
+ JS_FreeValue(ctx, collator);
+ return JS_EXCEPTION;
+ }
+
+ str_b = JS_ToString(ctx, argc > 0 ? argv[0] : JS_UNDEFINED);
+ if (JS_IsException(str_b)) {
+ JS_FreeValue(ctx, str_a);
+ JS_FreeValue(ctx, compare);
+ JS_FreeValue(ctx, collator);
+ return JS_EXCEPTION;
+ }
+
+ {
+ JSValueConst compare_argv[2] = { str_a, str_b };
+ ret = JS_Call(ctx, compare, JS_UNDEFINED, 2, compare_argv);
+ }
+
+ JS_FreeValue(ctx, str_a);
+ JS_FreeValue(ctx, str_b);
+ JS_FreeValue(ctx, compare);
+ JS_FreeValue(ctx, collator);
+ return ret;
+}
+
+/* --------------------------------------------------------------------- */
+/* Numbering-system digit helpers */
+/* --------------------------------------------------------------------- */
+
+static const uint32_t nf_digit_base[NS_COUNT] = {
+ [NS_ADLM] = 0x1E950,
+ [NS_AHOM] = 0x11730,
+ [NS_ARAB] = 0x0660,
+ [NS_ARABEXT] = 0x06F0,
+ [NS_BALI] = 0x1B50,
+ [NS_BENG] = 0x09E6,
+ [NS_BHKS] = 0x11C50,
+ [NS_BRAH] = 0x11066,
+ [NS_CAKM] = 0x11136,
+ [NS_CHAM] = 0xAA50,
+ [NS_DEVA] = 0x0966,
+ [NS_DIAK] = 0x11950,
+ [NS_FULLWIDE]= 0xFF10,
+ [NS_GARA] = 0x10D40,
+ [NS_GONG] = 0x11DA0,
+ [NS_GONM] = 0x11D50,
+ [NS_GUJR] = 0x0AE6,
+ [NS_GUKH] = 0x16130,
+ [NS_GURU] = 0x0A66,
+ [NS_HMNG] = 0x16B50,
+ [NS_HMNP] = 0x1E140,
+ [NS_JAVA] = 0xA9D0,
+ [NS_KALI] = 0xA900,
+ [NS_KAWI] = 0x11F50,
+ [NS_KHMR] = 0x17E0,
+ [NS_KNDA] = 0x0CE6,
+ [NS_KRAI] = 0x16D70,
+ [NS_LANA] = 0x1A80,
+ [NS_LANATHAM]= 0x1A90,
+ [NS_LAOO] = 0x0ED0,
+ [NS_LATN] = 0x0030,
+ [NS_LEPC] = 0x1C40,
+ [NS_LIMB] = 0x1946,
+ [NS_MATHBOLD]= 0x1D7CE,
+ [NS_MATHDBL] = 0x1D7D8,
+ [NS_MATHMONO]= 0x1D7F6,
+ [NS_MATHSANB]= 0x1D7EC,
+ [NS_MATHSANS]= 0x1D7E2,
+ [NS_MLYM] = 0x0D66,
+ [NS_MODI] = 0x11650,
+ [NS_MONG] = 0x1810,
+ [NS_MROO] = 0x16A60,
+ [NS_MTEI] = 0xABF0,
+ [NS_MYMR] = 0x1040,
+ [NS_MYMREPKA]= 0x116DA,
+ [NS_MYMRPAO] = 0x116D0,
+ [NS_MYMRSHAN] = 0x1090,
+ [NS_MYMRTLNG]= 0xA9F0,
+ [NS_NAGM] = 0x1E4F0,
+ [NS_NEWA] = 0x11450,
+ [NS_NKOO] = 0x07C0,
+ [NS_OLCK] = 0x1C50,
+ [NS_ONAO] = 0x1E5F1,
+ [NS_ORYA] = 0x0B66,
+ [NS_OSMA] = 0x104A0,
+ [NS_OUTLINED]= 0x1CCF0,
+ [NS_ROHG] = 0x10D30,
+ [NS_SAUR] = 0xA8D0,
+ [NS_SEGMENT] = 0x1FBF0,
+ [NS_SHRD] = 0x111D0,
+ [NS_SIND] = 0x112F0,
+ [NS_SINH] = 0x0DE6,
+ [NS_SORA] = 0x110F0,
+ [NS_SUND] = 0x1BB0,
+ [NS_SUNU] = 0x11BF0,
+ [NS_TAKR] = 0x116C0,
+ [NS_TALU] = 0x19D0,
+ [NS_TAMLDEC] = 0x0BE6,
+ [NS_TELU] = 0x0C66,
+ [NS_THAI] = 0x0E50,
+ [NS_TIBT] = 0x0F20,
+ [NS_TIRH] = 0x114D0,
+ [NS_TNSA] = 0x16AC0,
+ [NS_TOLS] = 0x11DE0,
+ [NS_VAII] = 0xA620,
+ [NS_WARA] = 0x118E0,
+ [NS_WCHO] = 0x1E2F0,
+};
+
+static const uint32_t hanidec_cps[10] = {
+ 0x3007, 0x4E00, 0x4E8C, 0x4E09, 0x56DB,
+ 0x4E94, 0x516D, 0x4E03, 0x516B, 0x4E5D
+};
+
+uint32_t nf_get_digit(int ns, int d)
+{
+ if (ns == NS_HANIDEC)
+ return hanidec_cps[d];
+ if (ns >= 0 && ns < NS_COUNT && nf_digit_base[ns] != 0)
+ return nf_digit_base[ns] + (uint32_t)d;
+ return 0;
+}
+
+void nf_put_digit(DynBuf *db, int ns, int d)
+{
+ uint8_t buf[4];
+ uint32_t cp = nf_get_digit(ns, d);
+ int len;
+ if (cp != 0) {
+ len = unicode_to_utf8(buf, cp);
+ dbuf_put(db, buf, (size_t)len);
+ } else {
+ dbuf_putc(db, (uint8_t)('0' + d));
+ }
+}
+
+/* --------------------------------------------------------------------- */
+/* Locale data lookup */
+/* --------------------------------------------------------------------- */
+
+const LocaleData *js_intl_find_locale_data(const char *locale)
+{
+ int i;
+ for (i = 0; i < locale_data_count; i++) {
+ if (!strcmp(locale_data_table[i].locale, locale))
+ return &locale_data_table[i];
+ }
+ for (i = 0; i < locale_data_count; i++) {
+ const char *p = locale_data_table[i].locale;
+ int len = (int)strlen(p);
+ if (!strncmp(locale, p, (size_t)len) && (locale[len] == '\0' || locale[len] == '-'))
+ return &locale_data_table[i];
+ }
+ return &locale_data_table[0];
+}
+
+int js_intl_get_currency_digits(const char *currency)
+{
+ if (!strcmp(currency, "JPY") || !strcmp(currency, "KRW") ||
+ !strcmp(currency, "VND") || !strcmp(currency, "ISK"))
+ return 0;
+ if (!strcmp(currency, "CLF") || !strcmp(currency, "BHD") ||
+ !strcmp(currency, "JOD") || !strcmp(currency, "KWD") ||
+ !strcmp(currency, "OMR") || !strcmp(currency, "TND"))
+ return 3;
+ if (!strcmp(currency, "CLP") || !strcmp(currency, "KMF") ||
+ !strcmp(currency, "GNF") || !strcmp(currency, "PYG") ||
+ !strcmp(currency, "RWF"))
+ return 0;
+ return 2;
+}
+
+static int decode_leb128(const uint8_t **pp)
+{
+ const uint8_t *p = *pp;
+ int val = 0;
+ int shift = 0;
+ uint8_t b;
+ do {
+ b = *p++;
+ val |= (b & 0x7f) << shift;
+ shift += 7;
+ } while (b & 0x80);
+ *pp = p;
+ return val;
+}
+
+const char *js_intl_get_currency_symbol(const char *currency, const char *locale)
+{
+ const LocaleData *ld = js_intl_find_locale_data(locale);
+ const uint8_t *p = locale_currency_data + ld->currency_offset;
+ int i;
+ for (i = 0; i < ld->num_currencies; i++) {
+ int code_idx = decode_leb128(&p);
+ int sym_idx = decode_leb128(&p);
+ if (!strcmp(currency_code_tab[code_idx], currency))
+ return currency_sym_tab[sym_idx];
+ }
+ return currency;
+}
+
+/* --------------------------------------------------------------------- */
+/* Locale callbacks registration */
+static int js_intl_get_string_locale_lang(JSContext *ctx, int argc, JSValueConst *argv)
+{
+ char *canonical;
+ int lang = 0;
+ if (js_canonicalizeLocaleList_first(ctx, argc > 0 ? argv[0] : JS_UNDEFINED, &canonical) < 0)
+ return -1;
+ if (!canonical)
+ return 0;
+ if (!strncasecmp(canonical, "tr", 2) || !strncasecmp(canonical, "az", 2))
+ lang = 1; /* Turkish / Azeri */
+ else if (!strncasecmp(canonical, "lt", 2))
+ lang = 2; /* Lithuanian */
+ js_free(ctx, canonical);
+ return lang;
+}
+
+/* --------------------------------------------------------------------- */
+
+/* DisplayNames lookup in a zero-separated key\0value\0key\0value... pool */
+const char *js_intl_find_display_name(const char *pool, const char *code)
+{
+ const char *p = pool;
+ while (*p) {
+ if (!strcmp(p, code))
+ return p + strlen(p) + 1;
+ p += strlen(p) + 1;
+ p += strlen(p) + 1;
+ }
+ return NULL;
+}
+
+static void js_intl_set_locale_callbacks(JSContext *ctx)
+{
+ static JSLocaleCallbacks callbacks;
+ memset(&callbacks, 0, sizeof(callbacks));
+ callbacks.number_toLocaleString = js_intl_number_toLocaleString;
+ callbacks.bigint_toLocaleString = js_intl_bigint_toLocaleString;
+ callbacks.date_toLocaleString = js_intl_date_toLocaleString;
+ callbacks.string_localeCompare = js_intl_string_localeCompare;
+ callbacks.get_string_locale_lang = js_intl_get_string_locale_lang;
+ JS_SetLocaleCallbacks(ctx, &callbacks);
+}
--- /dev/null
+/*
+ * QuickJS Intl internal definitions
+ */
+
+#ifndef QUICKJS_INTL_PRIVATE_H
+#define QUICKJS_INTL_PRIVATE_H
+
+#include "../quickjs.h"
+
+JSValue js_canonicalizeLocaleList(JSContext *ctx, JSValueConst locales);
+int js_canonicalizeLocaleList_c(JSContext *ctx, JSValueConst locales,
+ char ***plocales, int *pcount);
+void js_canonicalizeLocaleList_free_c(JSContext *ctx, char **locales, int count);
+int js_canonicalizeLocaleList_first(JSContext *ctx, JSValueConst locales, char **plocale);
+int js_add_locale(JSContext *ctx, JSValue intl_obj);
+JSValue js_locale_get_locale_string(JSContext *ctx, JSValueConst val);
+extern JSClassID js_numberformat_class_id;
+JSValue js_numberformat_constructor(JSContext *ctx, JSValueConst func_obj,
+ JSValueConst this_val, int argc, JSValueConst *argv, int flags);
+JSValue js_numberformat_format_number(JSContext *ctx, double d, int argc, JSValueConst *argv);
+JSValue js_intl_number_toLocaleString(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv);
+JSValue js_intl_bigint_toLocaleString(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv);
+int js_add_numberformat(JSContext *ctx, JSValue intl_obj);
+
+
+int js_add_collator(JSContext *ctx, JSValue intl_obj);
+int js_add_datetimeformat(JSContext *ctx, JSValue intl_obj);
+int js_add_pluralrules(JSContext *ctx, JSValue intl_obj);
+int js_add_listformat(JSContext *ctx, JSValue intl_obj);
+int js_add_relativetimeformat(JSContext *ctx, JSValue intl_obj);
+int js_add_displaynames(JSContext *ctx, JSValue intl_obj);
+int js_add_segmenter(JSContext *ctx, JSValue intl_obj);
+int js_add_durationformat(JSContext *ctx, JSValue intl_obj);
+
+/* Read a string option. Returns index in valid_values[], or -1 on error.
+ If property is undefined, returns default_index. */
+int js_intl_get_string_option(JSContext *ctx, JSValueConst options, const char *prop,
+ const char **valid_values, int num_values, int default_index);
+
+/* Read a numeric option. Returns 1 if present and valid, 0 if undefined, -1 on error.
+ Value is stored in *pval. Throws RangeError if out of range or NaN. */
+int js_intl_get_number_option(JSContext *ctx, JSValueConst options, const char *prop,
+ int *pval, int val_min, int val_max);
+
+JSValue js_intl_get_options_object(JSContext *ctx, JSValueConst options);
+JSValue js_intl_supportedLocalesOf(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv);
+int js_intl_options_has_date_fields(JSContext *ctx, JSValueConst options);
+int js_intl_options_has_time_fields(JSContext *ctx, JSValueConst options);
+
+
+char *js_intl_strip_unicode_extensions(JSContext *ctx, const char *locale);
+char *js_intl_locale_get_numbering_system(JSContext *ctx, const char *locale);
+char *js_intl_locale_get_unicode_key(JSContext *ctx, const char *locale, const char *key);
+const char *js_intl_find_u_extension(const char *locale);
+int js_intl_locale_has_key(const char *locale, const char *key);
+
+extern const char *intl_all_numbering_systems[];
+extern const int intl_all_numbering_systems_count;
+
+enum {
+ NS_UNKNOWN = -1,
+ NS_ADLM = 0,
+ NS_AHOM,
+ NS_ARAB,
+ NS_ARABEXT,
+ NS_ARMN,
+ NS_ARMNLOW,
+ NS_BALI,
+ NS_BENG,
+ NS_BHKS,
+ NS_BRAH,
+ NS_CAKM,
+ NS_CHAM,
+ NS_CYRL,
+ NS_DEVA,
+ NS_DIAK,
+ NS_ETHI,
+ NS_FINANCE,
+ NS_FULLWIDE,
+ NS_GARA,
+ NS_GEOR,
+ NS_GONG,
+ NS_GONM,
+ NS_GREK,
+ NS_GREKLOW,
+ NS_GUJR,
+ NS_GUKH,
+ NS_GURU,
+ NS_HANIDAYS,
+ NS_HANIDEC,
+ NS_HANS,
+ NS_HANSFIN,
+ NS_HANT,
+ NS_HANTFIN,
+ NS_HEBR,
+ NS_HMNG,
+ NS_HMNP,
+ NS_JAVA,
+ NS_JPAN,
+ NS_JPANFIN,
+ NS_JPANYEAR,
+ NS_KALI,
+ NS_KAWI,
+ NS_KHMR,
+ NS_KNDA,
+ NS_KRAI,
+ NS_LANA,
+ NS_LANATHAM,
+ NS_LAOO,
+ NS_LATN,
+ NS_LEPC,
+ NS_LIMB,
+ NS_MATHBOLD,
+ NS_MATHDBL,
+ NS_MATHMONO,
+ NS_MATHSANB,
+ NS_MATHSANS,
+ NS_MLYM,
+ NS_MODI,
+ NS_MONG,
+ NS_MROO,
+ NS_MTEI,
+ NS_MYMR,
+ NS_MYMREPKA,
+ NS_MYMRPAO,
+ NS_MYMRSHAN,
+ NS_MYMRTLNG,
+ NS_NAGM,
+ NS_NATIVE,
+ NS_NEWA,
+ NS_NKOO,
+ NS_OLCK,
+ NS_ONAO,
+ NS_ORYA,
+ NS_OSMA,
+ NS_OUTLINED,
+ NS_ROHG,
+ NS_ROMAN,
+ NS_ROMANLOW,
+ NS_SAUR,
+ NS_SEGMENT,
+ NS_SHRD,
+ NS_SIND,
+ NS_SINH,
+ NS_SORA,
+ NS_SUND,
+ NS_SUNU,
+ NS_TAKR,
+ NS_TALU,
+ NS_TAML,
+ NS_TAMLDEC,
+ NS_TELU,
+ NS_THAI,
+ NS_TIBT,
+ NS_TIRH,
+ NS_TNSA,
+ NS_TOLS,
+ NS_TRADITIO,
+ NS_VAII,
+ NS_WARA,
+ NS_WCHO,
+ NS_COUNT
+};
+
+int js_intl_string_to_numbering_system(const char *str);
+const char *js_intl_numbering_system_to_string(int ns);
+uint32_t nf_get_digit(int ns, int d);
+void nf_put_digit(DynBuf *db, int ns, int d);
+
+
+extern const char *intl_supported_collations[];
+extern const int intl_supported_collations_count;
+extern const char *sanctioned_simple_units[];
+extern const int sanctioned_simple_units_count;
+
+enum {
+ PLURAL_ZERO = 0,
+ PLURAL_ONE,
+ PLURAL_TWO,
+ PLURAL_FEW,
+ PLURAL_MANY,
+ PLURAL_OTHER,
+ PLURAL_COUNT
+};
+extern const char *plural_category_names[PLURAL_COUNT];
+char *js_intl_extract_locale(JSContext *ctx, int argc, JSValueConst *argv);
+void js_intl_dbuf_init(JSContext *ctx, DynBuf *s);
+JSValue js_intl_new_constructor(JSContext *ctx, JSValue intl_obj,
+ int intl_idx,
+ JSClassID class_id,
+ const char *name,
+ JSCFunction *func, int length,
+ JSCFunctionEnum cproto, int magic,
+ const JSCFunctionListEntry *static_funcs, int n_static,
+ const JSCFunctionListEntry *proto_funcs, int n_proto);
+int is_wellformed_language_tag(const char *tag);
+char *canonicalize_locale(JSContext *ctx, const char *locale);
+
+enum {
+ INTL_LOCALEMATCHER_LOOKUP = 0,
+ INTL_LOCALEMATCHER_BESTFIT = 1,
+};
+extern const char *intl_localeMatcher_names[2];
+
+/* Locale data structures */
+typedef struct {
+ unsigned decimal_idx : 2;
+ unsigned group_idx : 3;
+ unsigned plusSign_idx : 3;
+ unsigned minusSign_idx : 3;
+ unsigned percentSign_idx : 2;
+ unsigned infinity_idx : 1;
+ unsigned nan_idx : 5;
+} NumberSymbols;
+
+typedef struct {
+ unsigned dec_pos : 6;
+ unsigned dec_neg : 6;
+ unsigned cur_pos : 6;
+ unsigned cur_neg : 6;
+ unsigned acc_pos : 6;
+ unsigned acc_neg : 6;
+ unsigned pct_pos : 6;
+ unsigned pct_neg : 6;
+} NumberPatterns;
+
+typedef struct {
+ int scale_exp; /* e.g. 3 for 10^3, 6 for 10^6, 4 for 10^4 */
+ const char *shortPattern;
+ const char *longPattern;
+} CompactDecimalPattern;
+
+typedef struct {
+ const char *locale;
+ const CompactDecimalPattern *compactPatterns;
+ NumberSymbols symbols;
+ NumberPatterns patterns;
+ uint16_t month_long_idx;
+ uint16_t month_short_idx;
+ uint16_t month_narrow_idx;
+ uint16_t weekday_long_idx;
+ uint16_t weekday_narrow_idx;
+ uint16_t era_idx;
+ uint16_t ampm_idx;
+ uint16_t dayperiod_idx;
+ uint16_t dayperiod_narrow_idx;
+ uint16_t datePatternShort_idx;
+ uint16_t datePatternMedium_idx;
+ uint16_t datePatternLong_idx;
+ uint16_t datePatternFull_idx;
+ uint8_t timePatternShort_idx;
+ uint8_t timePatternMedium_idx;
+ uint8_t timePatternLong_idx;
+ uint8_t timePatternFull_idx;
+ uint8_t combinedPatternShort_idx;
+ uint8_t combinedPatternMedium_idx;
+ uint8_t combinedPatternLong_idx;
+ uint8_t combinedPatternFull_idx;
+ unsigned numCompactPatterns : 4;
+ unsigned groupSize1 : 2;
+ unsigned groupSize2 : 2;
+ unsigned currency_offset : 16;
+ unsigned num_currencies : 8;
+} LocaleData;
+
+extern const LocaleData locale_data_table[];
+extern const int locale_data_count;
+extern const char *currency_code_tab[];
+extern const char *currency_sym_tab[];
+extern const uint8_t locale_currency_data[];
+
+extern const char *decimal_tab[];
+extern const char *group_tab[];
+extern const char *plusSign_tab[];
+extern const char *minusSign_tab[];
+extern const char *percentSign_tab[];
+extern const char *infinity_tab[];
+extern const char *nan_tab[];
+extern const char *pattern_tab[];
+
+extern const char *month_long_tab[];
+extern const char *month_short_tab[];
+extern const char *month_narrow_tab[];
+extern const char *weekday_long_tab[];
+extern const char *weekday_narrow_tab[];
+extern const char *era_tab[];
+extern const char *ampm_tab[];
+extern const char *dayperiod_tab[];
+extern const char *dayperiod_narrow_tab[];
+extern const char *date_pattern_tab[];
+extern const char *time_pattern_tab[];
+extern const char *combined_pattern_tab[];
+
+#define NS_DECIMAL(ns) decimal_tab[(ns).decimal_idx]
+#define NS_GROUP(ns) group_tab[(ns).group_idx]
+#define NS_PLUS(ns) plusSign_tab[(ns).plusSign_idx]
+#define NS_MINUS(ns) minusSign_tab[(ns).minusSign_idx]
+#define NS_PERCENT(ns) percentSign_tab[(ns).percentSign_idx]
+#define NS_INFINITY(ns) infinity_tab[(ns).infinity_idx]
+#define NS_NAN(ns) nan_tab[(ns).nan_idx]
+
+#define NP_DEC_POS(np) pattern_tab[(np).dec_pos]
+#define NP_DEC_NEG(np) pattern_tab[(np).dec_neg]
+#define NP_CUR_POS(np) pattern_tab[(np).cur_pos]
+#define NP_CUR_NEG(np) pattern_tab[(np).cur_neg]
+#define NP_ACC_POS(np) pattern_tab[(np).acc_pos]
+#define NP_ACC_NEG(np) pattern_tab[(np).acc_neg]
+#define NP_PCT_POS(np) pattern_tab[(np).pct_pos]
+#define NP_PCT_NEG(np) pattern_tab[(np).pct_neg]
+
+static inline const char *strpool_get(const char *pool, int n) {
+ const char *p = pool;
+ while (n-- > 0) {
+ while (*p) p++;
+ p++;
+ }
+ return p;
+}
+
+#define LD_MONTH_LONG(ld, i) strpool_get(month_long_tab[(ld)->month_long_idx], (i))
+#define LD_MONTH_SHORT(ld, i) strpool_get(month_short_tab[(ld)->month_short_idx], (i))
+#define LD_MONTH_NARROW(ld, i) strpool_get(month_narrow_tab[(ld)->month_narrow_idx], (i))
+#define LD_WEEKDAY_LONG(ld, i) strpool_get(weekday_long_tab[(ld)->weekday_long_idx], (i))
+#define LD_WEEKDAY_NARROW(ld, i) strpool_get(weekday_narrow_tab[(ld)->weekday_narrow_idx], (i))
+#define LD_ERA(ld, style, era) strpool_get(era_tab[(ld)->era_idx], (style) * 2 + (era))
+#define LD_AMPM(ld, i) strpool_get(ampm_tab[(ld)->ampm_idx], (i))
+#define LD_DAYPERIOD(ld, i) strpool_get(dayperiod_tab[(ld)->dayperiod_idx], (i))
+#define LD_DAYPERIOD_NARROW(ld, i) strpool_get(dayperiod_narrow_tab[(ld)->dayperiod_narrow_idx], (i))
+
+const LocaleData *js_intl_find_locale_data(const char *locale);
+int js_intl_get_currency_digits(const char *currency);
+const char *js_intl_get_currency_symbol(const char *currency, const char *locale);
+
+/* DisplayNames data */
+typedef struct {
+ const char *locale;
+ const char *languages;
+ const char *regions;
+ const char *regions_short;
+ const char *scripts;
+ const char *calendars;
+ const char *dateTimeFields;
+ const char *currencies;
+} DisplayNamesData;
+
+extern const DisplayNamesData display_names_data[];
+extern const int display_names_count;
+const char *js_intl_find_display_name(const char *pool, const char *code);
+
+extern const char *intl_supported_currencies[];
+extern const int intl_supported_currencies_count;
+
+#endif /* QUICKJS_INTL_PRIVATE_H */
--- /dev/null
+/*
+ * QuickJS Intl.ListFormat implementation
+ */
+
+#include <string.h>
+
+#include "../quickjs.h"
+#include "../cutils.h"
+#include "intl_private.h"
+
+static JSClassID js_listformat_class_id;
+
+typedef enum {
+ LF_TYPE_CONJUNCTION = 0,
+ LF_TYPE_DISJUNCTION,
+ LF_TYPE_UNIT,
+} LFType;
+
+typedef enum {
+ LF_STYLE_LONG = 0,
+ LF_STYLE_SHORT,
+ LF_STYLE_NARROW,
+} LFStyle;
+
+typedef struct {
+ char *locale;
+ char *type;
+ char *style;
+} JSListFormatData;
+
+static const char *lf_type_names[] = {"conjunction", "disjunction", "unit"};
+static const char *lf_style_names[] = {"long", "short", "narrow"};
+
+static void js_listformat_finalizer(JSRuntime *rt, JSValue val)
+{
+ JSListFormatData *s = JS_GetOpaque(val, js_listformat_class_id);
+ if (s) {
+ js_free_rt(rt, s->locale);
+ js_free_rt(rt, s->type);
+ js_free_rt(rt, s->style);
+ js_free_rt(rt, s);
+ }
+}
+
+static JSClassDef js_listformat_class = {
+ "ListFormat",
+ .finalizer = js_listformat_finalizer,
+};
+
+static JSValue js_listformat_constructor(JSContext *ctx,
+ JSValueConst new_target,
+ int argc, JSValueConst *argv)
+{
+ JSListFormatData *s;
+ JSValue obj = JS_UNDEFINED;
+ JSValue options = JS_UNDEFINED;
+
+ s = js_mallocz(ctx, sizeof(*s));
+ if (!s)
+ return JS_EXCEPTION;
+
+ s->locale = js_strdup(ctx, "en-US");
+ s->type = js_strdup(ctx, "conjunction");
+ s->style = js_strdup(ctx, "long");
+
+ {
+ char *loc = js_intl_extract_locale(ctx, argc, argv);
+ if (!loc)
+ goto fail;
+ js_free(ctx, s->locale);
+ s->locale = loc;
+ }
+
+ if (argc > 1) {
+ options = js_intl_get_options_object(ctx, argv[1]);
+ if (JS_IsException(options))
+ goto fail;
+ /* localeMatcher first (spec order) */
+ {
+ int idx = js_intl_get_string_option(ctx, options, "localeMatcher",
+ intl_localeMatcher_names,
+ countof(intl_localeMatcher_names),
+ INTL_LOCALEMATCHER_BESTFIT);
+ if (idx < 0)
+ goto fail_options;
+ }
+ /* type */
+ {
+ int idx = js_intl_get_string_option(ctx, options, "type",
+ lf_type_names,
+ countof(lf_type_names),
+ LF_TYPE_CONJUNCTION);
+ if (idx < 0)
+ goto fail_options;
+ js_free(ctx, s->type);
+ s->type = js_strdup(ctx, lf_type_names[idx]);
+ if (!s->type)
+ goto fail_options;
+ }
+ /* style */
+ {
+ int idx = js_intl_get_string_option(ctx, options, "style",
+ lf_style_names,
+ countof(lf_style_names),
+ LF_STYLE_LONG);
+ if (idx < 0)
+ goto fail_options;
+ js_free(ctx, s->style);
+ s->style = js_strdup(ctx, lf_style_names[idx]);
+ if (!s->style)
+ goto fail_options;
+ }
+ JS_FreeValue(ctx, options);
+ }
+
+ obj = JS_CreateFromConstructor(ctx, new_target, js_listformat_class_id);
+ if (JS_IsException(obj))
+ goto fail;
+ JS_SetOpaque(obj, s);
+ return obj;
+ fail_options:
+ JS_FreeValue(ctx, options);
+ fail:
+ if (s->locale) js_free(ctx, s->locale);
+ if (s->type) js_free(ctx, s->type);
+ if (s->style) js_free(ctx, s->style);
+ js_free(ctx, s);
+ JS_FreeValue(ctx, obj);
+ return JS_EXCEPTION;
+}
+
+/* StringListFromIterable abstract operation.
+ Returns a JSValue array of strings, or JS_EXCEPTION on error.
+ Uses JS_GetIterator / JS_IteratorNext / JS_IteratorClose. */
+static JSValue string_list_from_iterable(JSContext *ctx, JSValueConst iterable)
+{
+ JSValue iter = JS_UNDEFINED;
+ JSValue next_method = JS_UNDEFINED;
+ JSValue r = JS_UNDEFINED;
+ JSValue v = JS_UNDEFINED;
+ BOOL done;
+ int64_t k;
+
+ if (JS_IsUndefined(iterable))
+ return JS_NewArray(ctx);
+
+ iter = JS_GetIterator(ctx, iterable, FALSE);
+ if (JS_IsException(iter))
+ goto exception;
+ next_method = JS_GetPropertyStr(ctx, iter, "next");
+ if (JS_IsException(next_method))
+ goto exception;
+ r = JS_NewArray(ctx);
+ if (JS_IsException(r))
+ goto exception;
+
+ for (k = 0;; k++) {
+ v = JS_IteratorNext(ctx, iter, next_method, &done);
+ if (JS_IsException(v))
+ goto exception_close;
+ if (done)
+ break;
+ if (!JS_IsString(v)) {
+ JS_FreeValue(ctx, v);
+ JS_ThrowTypeError(ctx, "iterable yielded non-string value");
+ goto exception_close;
+ }
+ if (JS_DefinePropertyValueUint32(ctx, r, (uint32_t)k, v,
+ JS_PROP_C_W_E | JS_PROP_THROW) < 0)
+ goto exception_close;
+ }
+ done:
+ JS_FreeValue(ctx, next_method);
+ JS_FreeValue(ctx, iter);
+ return r;
+ exception_close:
+ JS_IteratorClose(ctx, iter, TRUE);
+ exception:
+ JS_FreeValue(ctx, r);
+ r = JS_EXCEPTION;
+ JS_FreeValue(ctx, v);
+ goto done;
+}
+
+/* Helpers for list formatting */
+
+typedef struct {
+ const char **items;
+ int count;
+} StringList;
+
+static int is_locale_spanish(const char *locale)
+{
+ return strstart(locale, "es", NULL);
+}
+
+static int is_locale_british(const char *locale)
+{
+ return strstart(locale, "en-GB", NULL);
+}
+
+static int js_listformat_get_separators(JSContext *ctx, JSListFormatData *s,
+ const char **p_start_sep,
+ const char **p_middle_sep,
+ const char **p_end_sep,
+ const char **p_pair_sep)
+{
+ int is_es = is_locale_spanish(s->locale);
+ int is_en_gb = is_locale_british(s->locale);
+ int is_conjunction = !strcmp(s->type, "conjunction");
+ int is_disjunction = !strcmp(s->type, "disjunction");
+ int is_short = !strcmp(s->style, "short");
+ int is_narrow = !strcmp(s->style, "narrow");
+
+ if (is_narrow) {
+ *p_start_sep = "";
+ *p_middle_sep = " ";
+ *p_end_sep = " ";
+ *p_pair_sep = " ";
+ return 0;
+ }
+
+ if (is_es) {
+ if (is_conjunction || is_disjunction) {
+ /* Spanish conjunction/disjunction not explicitly tested,
+ default to English-like with 'y' for conjunction */
+ if (is_short) {
+ *p_start_sep = "";
+ *p_middle_sep = ", ";
+ *p_end_sep = ", ";
+ *p_pair_sep = " y ";
+ } else {
+ *p_start_sep = "";
+ *p_middle_sep = ", ";
+ *p_end_sep = " y ";
+ *p_pair_sep = " y ";
+ }
+ } else { /* unit */
+ if (is_short) {
+ *p_start_sep = "";
+ *p_middle_sep = ", ";
+ *p_end_sep = ", ";
+ *p_pair_sep = " y ";
+ } else {
+ *p_start_sep = "";
+ *p_middle_sep = ", ";
+ *p_end_sep = " y ";
+ *p_pair_sep = " y ";
+ }
+ }
+ return 0;
+ }
+
+ /* English / default */
+ if (is_conjunction) {
+ if (is_short) {
+ *p_start_sep = "";
+ *p_middle_sep = ", ";
+ *p_end_sep = ", & ";
+ *p_pair_sep = " & ";
+ } else if (is_en_gb) {
+ *p_start_sep = "";
+ *p_middle_sep = ", ";
+ *p_end_sep = " and ";
+ *p_pair_sep = " and ";
+ } else {
+ *p_start_sep = "";
+ *p_middle_sep = ", ";
+ *p_end_sep = ", and ";
+ *p_pair_sep = " and ";
+ }
+ } else if (is_disjunction) {
+ if (is_short) {
+ *p_start_sep = "";
+ *p_middle_sep = ", ";
+ *p_end_sep = ", or ";
+ *p_pair_sep = " or ";
+ } else {
+ *p_start_sep = "";
+ *p_middle_sep = ", ";
+ *p_end_sep = ", or ";
+ *p_pair_sep = " or ";
+ }
+ } else { /* unit */
+ if (is_short) {
+ *p_start_sep = "";
+ *p_middle_sep = ", ";
+ *p_end_sep = ", ";
+ *p_pair_sep = ", ";
+ } else {
+ *p_start_sep = "";
+ *p_middle_sep = ", ";
+ *p_end_sep = ", ";
+ *p_pair_sep = ", ";
+ }
+ }
+ return 0;
+}
+
+/* Format a list into a DynBuf string.
+ Does NOT null-terminate. */
+static void js_listformat_format_to_dbuf(JSContext *ctx, JSListFormatData *s,
+ StringList *list, DynBuf *db)
+{
+ const char *start_sep, *middle_sep, *end_sep, *pair_sep;
+ int i;
+
+ js_listformat_get_separators(ctx, s, &start_sep, &middle_sep, &end_sep, &pair_sep);
+
+ if (list->count == 0)
+ return;
+ if (list->count == 1) {
+ dbuf_putstr(db, list->items[0]);
+ return;
+ }
+ if (list->count == 2) {
+ dbuf_putstr(db, list->items[0]);
+ dbuf_putstr(db, pair_sep);
+ dbuf_putstr(db, list->items[1]);
+ return;
+ }
+ /* 3+ items */
+ for (i = 0; i < list->count; i++) {
+ if (i > 0) {
+ if (i == list->count - 1)
+ dbuf_putstr(db, end_sep);
+ else
+ dbuf_putstr(db, middle_sep);
+ }
+ dbuf_putstr(db, list->items[i]);
+ }
+}
+
+/* Format a list into a JS array of parts.
+ Each part is {type: "element"|"literal", value: string}. */
+static JSValue js_listformat_format_to_parts(JSContext *ctx, JSListFormatData *s,
+ StringList *list)
+{
+ const char *start_sep, *middle_sep, *end_sep, *pair_sep;
+ JSValue arr = JS_UNDEFINED;
+ int i;
+ uint32_t idx = 0;
+
+ js_listformat_get_separators(ctx, s, &start_sep, &middle_sep, &end_sep, &pair_sep);
+
+ arr = JS_NewArray(ctx);
+ if (JS_IsException(arr))
+ return arr;
+
+ if (list->count == 0)
+ return arr;
+ if (list->count == 1) {
+ JSValue part = JS_NewObject(ctx);
+ if (JS_IsException(part)) goto fail;
+ JS_SetPropertyStr(ctx, part, "type", JS_NewString(ctx, "element"));
+ JS_SetPropertyStr(ctx, part, "value", JS_NewString(ctx, list->items[0]));
+ JS_DefinePropertyValueUint32(ctx, arr, idx++, part, JS_PROP_C_W_E);
+ return arr;
+ }
+ if (list->count == 2) {
+ JSValue part;
+ part = JS_NewObject(ctx);
+ if (JS_IsException(part)) goto fail;
+ JS_SetPropertyStr(ctx, part, "type", JS_NewString(ctx, "element"));
+ JS_SetPropertyStr(ctx, part, "value", JS_NewString(ctx, list->items[0]));
+ JS_DefinePropertyValueUint32(ctx, arr, idx++, part, JS_PROP_C_W_E);
+
+ part = JS_NewObject(ctx);
+ if (JS_IsException(part)) goto fail;
+ JS_SetPropertyStr(ctx, part, "type", JS_NewString(ctx, "literal"));
+ JS_SetPropertyStr(ctx, part, "value", JS_NewString(ctx, pair_sep));
+ JS_DefinePropertyValueUint32(ctx, arr, idx++, part, JS_PROP_C_W_E);
+
+ part = JS_NewObject(ctx);
+ if (JS_IsException(part)) goto fail;
+ JS_SetPropertyStr(ctx, part, "type", JS_NewString(ctx, "element"));
+ JS_SetPropertyStr(ctx, part, "value", JS_NewString(ctx, list->items[1]));
+ JS_DefinePropertyValueUint32(ctx, arr, idx++, part, JS_PROP_C_W_E);
+ return arr;
+ }
+ /* 3+ items */
+ for (i = 0; i < list->count; i++) {
+ JSValue part;
+ part = JS_NewObject(ctx);
+ if (JS_IsException(part)) goto fail;
+ JS_SetPropertyStr(ctx, part, "type", JS_NewString(ctx, "element"));
+ JS_SetPropertyStr(ctx, part, "value", JS_NewString(ctx, list->items[i]));
+ JS_DefinePropertyValueUint32(ctx, arr, idx++, part, JS_PROP_C_W_E);
+
+ if (i < list->count - 1) {
+ const char *sep = (i == list->count - 2) ? end_sep : middle_sep;
+ part = JS_NewObject(ctx);
+ if (JS_IsException(part)) goto fail;
+ JS_SetPropertyStr(ctx, part, "type", JS_NewString(ctx, "literal"));
+ JS_SetPropertyStr(ctx, part, "value", JS_NewString(ctx, sep));
+ JS_DefinePropertyValueUint32(ctx, arr, idx++, part, JS_PROP_C_W_E);
+ }
+ }
+ return arr;
+ fail:
+ JS_FreeValue(ctx, arr);
+ return JS_EXCEPTION;
+}
+
+static JSValue js_listformat_format(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSListFormatData *s = JS_GetOpaque2(ctx, this_val, js_listformat_class_id);
+ JSValue arr = JS_UNDEFINED;
+ JSValue ret = JS_UNDEFINED;
+ StringList list;
+ int64_t len = 0, i;
+ const char **items = NULL;
+ DynBuf db;
+
+ if (!s)
+ return JS_EXCEPTION;
+
+ arr = string_list_from_iterable(ctx, argc > 0 ? argv[0] : JS_UNDEFINED);
+ if (JS_IsException(arr))
+ return JS_EXCEPTION;
+
+ {
+ JSValue len_val = JS_GetPropertyStr(ctx, arr, "length");
+ if (JS_IsException(len_val))
+ goto fail;
+ if (JS_ToInt64(ctx, &len, len_val) < 0) {
+ JS_FreeValue(ctx, len_val);
+ goto fail;
+ }
+ JS_FreeValue(ctx, len_val);
+ }
+
+ {
+ size_t alloc_count = (len > 0) ? (size_t)len : 1;
+ items = js_malloc(ctx, sizeof(*items) * alloc_count);
+ }
+ if (!items)
+ goto fail;
+
+ for (i = 0; i < len; i++) {
+ JSValue val;
+ const char *str;
+ val = JS_GetPropertyUint32(ctx, arr, (uint32_t)i);
+ if (JS_IsException(val)) {
+ JS_FreeValue(ctx, val);
+ goto fail;
+ }
+ str = JS_ToCString(ctx, val);
+ JS_FreeValue(ctx, val);
+ if (!str)
+ goto fail;
+ items[i] = str;
+ }
+
+ list.items = items;
+ list.count = (int)len;
+
+ js_intl_dbuf_init(ctx, &db);
+ js_listformat_format_to_dbuf(ctx, s, &list, &db);
+ dbuf_putc(&db, '\0');
+
+ if (dbuf_error(&db)) {
+ dbuf_free(&db);
+ ret = JS_EXCEPTION;
+ goto fail;
+ }
+ ret = JS_NewString(ctx, (char *)db.buf);
+ dbuf_free(&db);
+
+ fail:
+ if (items) {
+ for (i = 0; i < len; i++) {
+ if (items[i])
+ JS_FreeCString(ctx, items[i]);
+ }
+ js_free(ctx, items);
+ }
+ JS_FreeValue(ctx, arr);
+ return ret;
+}
+
+static JSValue js_listformat_formatToParts(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSListFormatData *s = JS_GetOpaque2(ctx, this_val, js_listformat_class_id);
+ JSValue arr = JS_UNDEFINED;
+ JSValue ret = JS_UNDEFINED;
+ StringList list;
+ int64_t len = 0, i;
+ const char **items = NULL;
+
+ if (!s)
+ return JS_EXCEPTION;
+
+ arr = string_list_from_iterable(ctx, argc > 0 ? argv[0] : JS_UNDEFINED);
+ if (JS_IsException(arr))
+ return JS_EXCEPTION;
+
+ {
+ JSValue len_val = JS_GetPropertyStr(ctx, arr, "length");
+ if (JS_IsException(len_val))
+ goto fail;
+ if (JS_ToInt64(ctx, &len, len_val) < 0) {
+ JS_FreeValue(ctx, len_val);
+ goto fail;
+ }
+ JS_FreeValue(ctx, len_val);
+ }
+
+ {
+ size_t alloc_count = (len > 0) ? (size_t)len : 1;
+ items = js_malloc(ctx, sizeof(*items) * alloc_count);
+ }
+ if (!items)
+ goto fail;
+
+ for (i = 0; i < len; i++) {
+ JSValue val;
+ const char *str;
+ val = JS_GetPropertyUint32(ctx, arr, (uint32_t)i);
+ if (JS_IsException(val)) {
+ JS_FreeValue(ctx, val);
+ goto fail;
+ }
+ str = JS_ToCString(ctx, val);
+ JS_FreeValue(ctx, val);
+ if (!str)
+ goto fail;
+ items[i] = str;
+ }
+
+ list.items = items;
+ list.count = (int)len;
+
+ ret = js_listformat_format_to_parts(ctx, s, &list);
+
+ fail:
+ if (items) {
+ for (i = 0; i < len; i++) {
+ if (items[i])
+ JS_FreeCString(ctx, items[i]);
+ }
+ js_free(ctx, items);
+ }
+ JS_FreeValue(ctx, arr);
+ return ret;
+}
+
+static JSValue js_listformat_resolvedOptions(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSValue obj;
+ JSListFormatData *s = JS_GetOpaque2(ctx, this_val, js_listformat_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+
+ obj = JS_NewObject(ctx);
+ if (JS_IsException(obj))
+ return JS_EXCEPTION;
+
+ JS_DefinePropertyValueStr(ctx, obj, "locale",
+ JS_NewString(ctx, s->locale), JS_PROP_C_W_E);
+ JS_DefinePropertyValueStr(ctx, obj, "type",
+ JS_NewString(ctx, s->type), JS_PROP_C_W_E);
+ JS_DefinePropertyValueStr(ctx, obj, "style",
+ JS_NewString(ctx, s->style), JS_PROP_C_W_E);
+
+ return obj;
+}
+
+static JSValue js_listformat_supportedLocalesOf(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ return js_intl_supportedLocalesOf(ctx, this_val, argc, argv);
+}
+
+static const JSCFunctionListEntry js_listformat_proto_funcs[] = {
+ JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Intl.ListFormat", JS_PROP_CONFIGURABLE),
+ JS_CFUNC_DEF("format", 1, js_listformat_format),
+ JS_CFUNC_DEF("formatToParts", 1, js_listformat_formatToParts),
+ JS_CFUNC_DEF("resolvedOptions", 0, js_listformat_resolvedOptions),
+};
+
+static const JSCFunctionListEntry js_listformat_static_funcs[] = {
+ JS_CFUNC_DEF("supportedLocalesOf", 1, js_listformat_supportedLocalesOf),
+};
+
+int js_add_listformat(JSContext *ctx, JSValue intl_obj)
+{
+ JS_NewClassID(&js_listformat_class_id);
+ JS_NewClass(JS_GetRuntime(ctx), js_listformat_class_id, &js_listformat_class);
+
+ if (JS_IsException(js_intl_new_constructor(ctx, intl_obj,
+ JS_INTL_CTOR_LISTFORMAT,
+ js_listformat_class_id, "ListFormat",
+ (JSCFunction *)js_listformat_constructor, 0,
+ JS_CFUNC_constructor, 0,
+ js_listformat_static_funcs, countof(js_listformat_static_funcs),
+ js_listformat_proto_funcs, countof(js_listformat_proto_funcs))))
+ return -1;
+
+ return 0;
+}
--- /dev/null
+/* Auto-generated locale data from CLDR */
+#include "../quickjs.h"
+#include "../cutils.h"
+#include "intl_private.h"
+
+const char *currency_code_tab[] = {
+ "XCG",
+ "XPF",
+ "EUR",
+ "XOF",
+ "XAF",
+ "USD",
+ "GBP",
+ "ILS",
+ "XXX",
+ "INR",
+ "VND",
+ "BRL",
+ "CAD",
+ "MXN",
+ "AUD",
+ "NZD",
+ "KRW",
+ "JPY",
+ "XCD",
+ "HKD",
+ "TWD",
+ "CNY",
+ "PHP",
+ "THB",
+ "LBP",
+ "FJD",
+ "SBD",
+ "BMD",
+ "BZD",
+ "SGD",
+ "COP",
+ "NAD",
+ "GIP",
+ "TTD",
+ "ARS",
+ "BND",
+ "SRD",
+ "UYU",
+ "IEP",
+ "CLP",
+ "FKP",
+ "WST",
+ "ILP",
+ "RHD",
+ "FRF",
+ "BEF",
+ "CYP",
+ "ITL",
+ "MTP",
+ "IRR",
+ "IQD",
+ "EGP",
+ "MRU",
+ "ESP",
+ "SYP",
+ "DZD",
+ "TND",
+ "NGN",
+ "JOD",
+ "LYD",
+ "MAD",
+ "AED",
+ "BHD",
+ "KWD",
+ "OMR",
+ "QAR",
+ "SAR",
+ "SDG",
+ "YER",
+ "SDD",
+ "RUB",
+ "KES",
+ "ZAR",
+ "TZS",
+ "BAM",
+ "DKK",
+ "PTE",
+ "ETB",
+ "BBD",
+ "NOK",
+ "PGK",
+ "AFN",
+ "AFA",
+ "ERN",
+ "GHS",
+ "MYR",
+ "TRY",
+ "UGX",
+ "ATS",
+ "CDF",
+ "LRD",
+ "SEK",
+ "UAH",
+ "SCR",
+ "SOS",
+ "BOB",
+ "HRK",
+ "IDR",
+ "KZT",
+ "LSL",
+ "PKR",
+ "PLN",
+ "TMT",
+ "ZWG",
+ "DJF",
+ "ANG",
+ "BSD",
+ "DOP",
+ "GNF",
+ "ISK",
+ "JMD",
+ "MOP",
+ "VES",
+ "BGM",
+ "BGO",
+ "DEM",
+ "SSP",
+ "AZN",
+ "RUR",
+ "ALL",
+ "BDT",
+ "BIF",
+ "BYN",
+ "GEL",
+ "GMD",
+ "GTQ",
+ "HTG",
+ "MDL",
+ "MGA",
+ "MUR",
+ "MZN",
+ "RSD",
+ "SLE",
+ "SZL",
+ "UZS",
+ "ILR",
+ "KMF",
+ "AOA",
+ "AWG",
+ "BWP",
+ "CVE",
+ "CZK",
+ "KGS",
+ "MKD",
+ "MNT",
+ "PAB",
+ "PEN",
+ "PYG",
+ "RON",
+ "RWF",
+ "AMD",
+ "BGN",
+ "CNH",
+ "CRC",
+ "CUP",
+ "HNL",
+ "HUF",
+ "KYD",
+ "LKR",
+ "MVR",
+ "MWK",
+ "NIO",
+ "NPR",
+ "SHP",
+ "STN",
+ "ZMW",
+ "EEK",
+ "BTN",
+ "CHF",
+ "CUC",
+ "KHR",
+ "KPW",
+ "LAK",
+ "MMK",
+ "SLL",
+ "GYD",
+ "TJS",
+ "LUF",
+ "GRD",
+ "TOP",
+ "VUV",
+ "MRO",
+ "ZMK",
+ "CSK",
+ "XEU",
+ "UYW",
+ "VEF",
+ "FIM",
+ "NLG",
+ "LVL",
+ "AON",
+ "AOR",
+ "GNS",
+ "GQE",
+ "GWE",
+ "GWP",
+ "MAF",
+ "MGF",
+ "MLF",
+ "MZE",
+ "MZM",
+ "SDP",
+ "STD",
+ "UGS",
+ "ZRN",
+ "ZRZ",
+ "ZWD",
+ "ZWL",
+ "ZWR",
+ "XDR",
+ "UAK",
+};
+#define CURRENCY_CODE_COUNT 211
+
+const char *currency_sym_tab[] = {
+ "Cg.",
+ "€",
+ "FCFA",
+ "₪",
+ "F CFA",
+ "₹",
+ "¤",
+ "₫",
+ "R$",
+ "CFPF",
+ "₩",
+ "HK$",
+ "NT$",
+ "EC$",
+ "MX$",
+ "CN¥",
+ "NZ$",
+ "£",
+ "CA$",
+ "JP¥",
+ "A$",
+ "US$",
+ "₱",
+ "$",
+ "฿",
+ "¥",
+ "AU$",
+ "$CA",
+ "F",
+ "$MX",
+ "$NZ",
+ "$US",
+ "FB",
+ "£CY",
+ "£IE",
+ "£IL",
+ "₤IT",
+ "£MT",
+ "$RH",
+ "$AR",
+ "$AU",
+ "$BM",
+ "$BN",
+ "$BZ",
+ "$CL",
+ "$CO",
+ "$FJ",
+ "£FK",
+ "£GB",
+ "£GI",
+ "£LB",
+ "$NA",
+ "$SB",
+ "$SG",
+ "$SR",
+ "$TT",
+ "$UY",
+ "$WS",
+ "FCFP",
+ "₧",
+ "د.ع.",
+ "ل.س.",
+ "د.أ.",
+ "د.إ.",
+ "د.ب.",
+ "د.ج.",
+ "ج.م.",
+ "ر.إ.",
+ "د.ك.",
+ "ل.ل.",
+ "د.ل.",
+ "د.م.",
+ "أ.م.",
+ "ر.ع.",
+ "ر.ق.",
+ "ر.س.",
+ "د.س.",
+ "د.ت.",
+ "ر.ي.",
+ "UK£",
+ "ج.س.",
+ "₽",
+ "Ksh",
+ "R",
+ "₦",
+ "TSh",
+ "kr",
+ "Br",
+ "𞤀𞤊𞤀",
+ "𞤑𞤆𞤘",
+ "𞤆𞤆𞤖",
+ "𞤊𞤅𞤊𞤀",
+ "𞤅𞤊𞤀",
+ "",
+ "öS",
+ "𞤐𞤐𞤘",
+ "؋",
+ "Rs",
+ "Cg",
+ "RM",
+ "C$",
+ "Nfk",
+ "USh",
+ "FJ$",
+ "SI$",
+ "₩",
+ "GH₵",
+ "GB£",
+ "ریال",
+ "KM",
+ "BGK",
+ "BGJ",
+ "DM",
+ "FC",
+ "₺",
+ "ZiG",
+ "₴",
+ "р.",
+ "КМ",
+ "kr.",
+ "Rp",
+ "ТМТ",
+ "XXXX",
+ "Dkr",
+ "ILS",
+ "S",
+ "Cf",
+ "₸",
+ "Fdj",
+ "K",
+ "৳",
+ "kn",
+ "zł",
+ "CFP",
+ "MOP$",
+ "RD$",
+ "UM",
+ "Bs.S",
+ "FG",
+ "𞅎",
+ "CFA",
+ "Esc.",
+ "Nkr",
+ "DBB",
+ "₼",
+ "Δρχ",
+ "FBu",
+ "₾",
+ "D",
+ "Ar",
+ "RF",
+ "Le",
+ "NAf.",
+ "E",
+ "L",
+ "G",
+ "¥",
+ "ЛСЛ",
+ "MTn",
+ "BBG",
+ "DBM",
+ "DBZ",
+ "Lekë",
+ "ANG",
+ "Bds$",
+ "BM$",
+ "BR$",
+ "BS$",
+ "BZ$",
+ "Ekr",
+ "EG£",
+ "IE£",
+ "Ikr",
+ "JM$",
+ "BUB",
+ "SCRu",
+ "FCF",
+ "CF",
+ "din.",
+ "P",
+ "SR",
+ "T$",
+ "VT",
+ "Bs",
+ "Q",
+ "B/.",
+ "S/",
+ "¥CN",
+ "$HK",
+ "$EC",
+ "فرانک CFA",
+ "DA",
+ "ƒ",
+ "元",
+ "रॉन",
+ "сом",
+ "Kz",
+ "₮",
+ "नेरू",
+ "Skr",
+ "soʻm",
+ "Irak dinaa",
+ "AAS",
+ "ብር",
+ "F CFA",
+ "AWGA",
+ "ALBL",
+ "ARMD",
+ "NLAG",
+ "ANGK",
+ "ARJP",
+ "ARBF",
+ "AZRM",
+ "BHBM",
+ "BRBD",
+ "BGDT",
+ "BLGL",
+ "BRDF",
+ "BRMD",
+ "BRND",
+ "BLWB",
+ "BHMD",
+ "BTNN",
+ "BTSP",
+ "BLRR",
+ "BLZD",
+ "KN$",
+ "KNGF",
+ "SWZF",
+ "CNYÁ",
+ "CHNY",
+ "KLBP",
+ "KRK",
+ "KBKP",
+ "CBAP",
+ "KWRE",
+ "CHKK",
+ "DJBF",
+ "DNMK",
+ "DOMP",
+ "ALJD",
+ "MSRP",
+ "ERTN",
+ "ETPB",
+ "BRTP",
+ "JRJL",
+ "GNAS",
+ "GBRP",
+ "GMBD",
+ "GWNF",
+ "GTMK",
+ "HGKD",
+ "HNDL",
+ "KRSK",
+ "HTNG",
+ "HGRF",
+ "ENDR",
+ "HNDR",
+ "ERNR",
+ "ISLK",
+ "JMKD",
+ "KINS",
+ "KGSS",
+ "KMBR",
+ "KMRF",
+ "SHKW",
+ "ZBKW",
+ "KMID",
+ "KZKT",
+ "LTKK",
+ "LBNP",
+ "SRLR",
+ "LBRD",
+ "LSTL",
+ "LBYD",
+ "MRKD",
+ "MLDL",
+ "MLGA",
+ "MKDD",
+ "MNMK",
+ "MNGT",
+ "MKNP",
+ "MRTU",
+ "MURR",
+ "MLDR",
+ "MLWK",
+ "MKS$",
+ "MLRG",
+ "MZBM",
+ "NMBD",
+ "NJRN",
+ "NKGC",
+ "NRWK",
+ "NPLR",
+ "PNMB",
+ "PRSL",
+ "PLPP",
+ "PKRS",
+ "PLNZ",
+ "PRGG",
+ "RMNL",
+ "SRBD",
+ "RUSR",
+ "RWDF",
+ "SCLR",
+ "SDNP",
+ "SWDK",
+ "SGPD",
+ "SHLP",
+ "SLNL",
+ "SRLL",
+ "SÓMS",
+ "SRND",
+ "ZRSP",
+ "STPD",
+ "SURP",
+ "SWZL",
+ "TÁIB",
+ "TNSD",
+ "TRKL",
+ "TDTD",
+ "NTWD",
+ "TNZS",
+ "YKNH",
+ "YUGS",
+ "YRGP",
+ "OZBS",
+ "WNZB",
+ "WTND",
+ "DARF",
+ "RKB$",
+ "RACF",
+ "ZAPR",
+ "ZMBK",
+ "лв.",
+ "щ.д.",
+ "$A",
+ "£ RU",
+ "$ HK",
+ "$ ZN",
+ "$ SU",
+ "ए.इ.दि",
+ "अल",
+ "ए.एम.दि",
+ "ए.एन.जि",
+ "ए.अ.ए",
+ "ए.आर.एस",
+ "ए.दब्ल्यु.जि",
+ "ए.जेत.एन",
+ "बि.ए.एम",
+ "बि.बि.दि",
+ "बि.जि.एन",
+ "बि.ऐत्स.दि",
+ "बि.आइ.एफ",
+ "बि.एम.डि",
+ "बि.अ.बि",
+ "बि.एस.दि",
+ "बि.दब्ल्यु.पि",
+ "बि.वाई.एन",
+ "बि.जेद.डि",
+ "सि.ए $",
+ "सि.दि.एफ",
+ "सि.ऐत्स.एफ",
+ "सि.एल.पि",
+ "सि.एन.ऐत्स",
+ "सिएन¥",
+ "सि.अ.पि",
+ "सि.आर.सि",
+ "सि.इउ.सि",
+ "सि.इउ.पि",
+ "सि.भि.इ",
+ "सि.जेद.के",
+ "दि.जे.एफ",
+ "दि.के.के",
+ "डि.अ.पि",
+ "दि.जेत.दि",
+ "ई.जि.पि",
+ "इ.आर.एन",
+ "इ.ति.बि",
+ "एफ.के.पि",
+ "जि.इ.एल",
+ "जि.ऐत्स.एस",
+ "जि.आइ.पि",
+ "जि.एम.दि",
+ "जि.एन.एफ",
+ "जि.ति.किउ",
+ "जि.वाई.दि",
+ "ऐत्स.के$",
+ "ऐत्स.एन.एल",
+ "ऐत्स.आर.के",
+ "ऐत्स.ति.जि",
+ "ऐत्स.इउ.एफ",
+ "आइ.किउ.दि",
+ "आई.एस.के",
+ "जे.एम.दि",
+ "जे.अ.दि",
+ "के.इ.एस",
+ "के.जि.एस",
+ "के.एम.एफ",
+ "के.पि.दब्ल्यु",
+ "के.दब्ल्यु.दि",
+ "के.वाई.दि",
+ "के.जेत.ति",
+ "एल.बि.पि",
+ "एल.आर.दि",
+ "एल.एस.एल",
+ "एल.वाई.दि",
+ "एम.ए.दि",
+ "एम.डि.एल",
+ "एम.जि.ए",
+ "एम.के.दि",
+ "एम.एन.ति",
+ "एम.अ.पि",
+ "एम.आर.इउ",
+ "एम.इउ.आर",
+ "एम.दब्ल्यु.के",
+ "एम.एक्स $",
+ "एम.जेत.एन",
+ "एन.ए.दि",
+ "एन.जि.एन",
+ "एन.आई.अ",
+ "एन.अ.के",
+ "अ.एम.आर",
+ "पि.ए.बि",
+ "पि.इ.एन",
+ "पि.एल.एन",
+ "पि.आई.जि",
+ "किउ.ए.आर",
+ "आर.अ.एन",
+ "आर.एस.दि",
+ "रूब",
+ "एस.ए.आर",
+ "एस.सि.आर",
+ "एस.दि.जि",
+ "एस.इ.के",
+ "एस.ऐत्स.पि",
+ "एस.एल.इ",
+ "एस.एल.एल",
+ "एस.अ.एस",
+ "एस.आर.डि",
+ "एस.एस.पि",
+ "एस.ति.एन",
+ "एस.वाई.पि",
+ "एस.जेत.एल",
+ "ति.जे.एस",
+ "ति.एम.ति",
+ "ति.एन.दि",
+ "ति.आर.वाई",
+ "ति.ति.डि",
+ "एन.ति$",
+ "ति.जेत.एस",
+ "इउ.ए.ऐत्स",
+ "इउ.जि.एक्स",
+ "इउ.वाई.इउ",
+ "इउ.जेत.एस",
+ "भि.इ.एस",
+ "इ.सि $",
+ "वाई.इ.आर",
+ "जेत.ए.आर",
+ "Кч",
+ "зл",
+ "дин.",
+ "Тл",
+ "US $",
+ "Kčs",
+ "Kč",
+ "ECU",
+ "ރ.",
+ "Nu.",
+ "KR₩",
+ "TH฿",
+ "Rf",
+ "MK",
+ "WS$",
+ "₡",
+ "MRU",
+ "Gs.",
+ "UP",
+ "Bs.",
+ "mk",
+ "$ AU",
+ "$ HK",
+ "$ NZ",
+ "$ SG",
+ "$ US",
+ "LS",
+ "DT",
+ "₲",
+ "CN¥",
+ "ל״י",
+ "Ft",
+ "֏",
+ "FJC",
+ "Vẽj.",
+ "SMK",
+ "៛",
+ "ឡូទី",
+ "₭",
+ "Ls",
+ "ден.",
+ "NAf",
+ "Afl",
+ "TT$",
+ "Afl.",
+ "ߊߐߘ",
+ "ߊߝߊ",
+ "ߊߟߟ",
+ "ߊߡߘ",
+ "ߊ߲ߕߝ",
+ "ߊ߲ߜ߭ߎ",
+ "ߊߜ߭ߞ",
+ "ߊߜ߭ߝ",
+ "ߊߖ߭ߔ",
+ "$ߐ",
+ "ߊߥߖ߭",
+ "ߊߖߣ",
+ "ߓߍߡ",
+ "ߓߓߘ",
+ "ߓߘߕ",
+ "ߓߜ߭ߟ",
+ "ߓߤߘ",
+ "ߓߙߝ",
+ "ߓߡߘ",
+ "ߓߣߘ",
+ "ߓߏߓ",
+ "ߓߛߘ",
+ "ߓߕߒ",
+ "ߓߥߔ",
+ "ߓߌߙ",
+ "ߞߝ",
+ "ߛߥߝ",
+ "ߛߟߔ",
+ "ߛߦߤ",
+ "ߛߣߦ",
+ "ߞߐߔ",
+ "ߞߙߞ",
+ "ߞߎ߳ߞ",
+ "ߞߎ߳ߔ",
+ "ߍߛߞ",
+ "ߗߞߞ",
+ "ߖߓߝ",
+ "ߘߞߞ",
+ "ߘߏߔ",
+ "ߊߟߘ",
+ "ߡߛߔ",
+ "ߋߙߝ",
+ "ߋߗߓ",
+ "$ ߝߖ",
+ "ߝߞߔ",
+ "ߖ߭ߐߟ",
+ "ߜ߭ߛߘ",
+ "ߖ߭ߓߔ£",
+ "ߜ߭ߓߘ",
+ "߿",
+ "ߖߛ߾",
+ "ߕߖߋ",
+ "ߜ߭ߕߞ",
+ "ߖߓߍ",
+ "ߖߓߔ",
+ "ߜ߭ߎ߳ߘ",
+ "ߤߞߘ",
+ "ߤߘߟ",
+ "ߞߛߞ",
+ "ߤߕߜ߭",
+ "ߤߜ߭ߝ",
+ "ߍ߲ߘߙ",
+ "ߌߞߘ",
+ "ߌߙߙ",
+ "ߌߛߞ",
+ "ߖߡߘ",
+ "ߖߐߘ",
+ "ߗ߭ߔߦ",
+ "ߞߋߛ",
+ "ߞߜ߭ߛ",
+ "ߞߓߙ",
+ "ߞߡߝ",
+ "ߞߞߥ",
+ "ߞߥߘ",
+ "ߞߌߘ",
+ "ߞߗ߭ߕ",
+ "ߟߊߞ",
+ "ߟߓ£",
+ "ߟߞߙ",
+ "ߟ߾",
+ "ߟߛߟ",
+ "ߟߓߘ",
+ "ߡߘߤ",
+ "ߡߙߝ",
+ "ߡߘߟ",
+ "ߡߘߙ",
+ "ߡߘߝ",
+ "ߡߞߘ",
+ "ߡߝ",
+ "ߡߡߞ",
+ "ߡߣߕ",
+ "ߡߏߔ",
+ "ߡߙߏ",
+ "ߡߎߜ߭",
+ "ߡߙߔ",
+ "ߡߝ߭ߙ",
+ "ߡߟߞ",
+ "ߡߞ$",
+ "ߡߦߙ",
+ "ߡߖ߭ߋ",
+ "ߡߖߡ",
+ "ߡߖ߭ߡ",
+ "ߣߡߘ",
+ "ߖߣ",
+ "ߣߌߏ",
+ "ߣߐߞ",
+ "ߣߔߙ",
+ "$ߣߖ߭",
+ "ߏߡߙ",
+ "ߔߊߓ",
+ "ߔߋߛ",
+ "ߔߖߞ",
+ "ߔߞߙ",
+ "ߔߟߗ߭",
+ "ߔߙߜ߭",
+ "ߞߊߙ",
+ "ߖ߭ߓߘ",
+ "ߙߎߟ",
+ "ߙߛߘ",
+ "ߌߎߙ",
+ "ߙߥߝ",
+ "ߛߊߙ",
+ "ߛߓߘ",
+ "ߛߛߥ",
+ "ߛߘߘ",
+ "ߛߘߜ߭",
+ "ߛߘߔ",
+ "ߛߥߞ",
+ "ߛߜ߭ߘ",
+ "ߛߤߔ",
+ "ߛߙߔ",
+ "ߛߟߟ",
+ "ߛߡߛ",
+ "ߛߎߘ",
+ "ߛߛߔ",
+ "ߛߕߘ",
+ "ߛߔߘ",
+ "ߛߌߔ",
+ "ߛߖ߭ߟ",
+ "ߕߘߓ",
+ "ߕߖߛ",
+ "ߕߡߕ",
+ "ߕߣߘ",
+ "ߕߏߔ",
+ "ߕߎߟ",
+ "ߕߕߘ",
+ "ߕߥߘ",
+ "ߕߖ߭ߛ",
+ "ߌߞߤ",
+ "ߎߜ߭ߥ",
+ "ߎߜ߭ߛ",
+ "ߊߞߘ$",
+ "ߎ߳ߔ",
+ "ߎߗ߭ߛ",
+ "ߝ߭ߋߓ",
+ "ߝ߭ߕߝ߭",
+ "$ߥߛ",
+ "ߝߛߝ",
+ "ߛߟߘ",
+ "߾",
+ "߾ ߝߛߝ",
+ "ߦߡߙ",
+ "ߥߝߙ",
+ "ߖ߭ߓߞ",
+ "ߖ߭ߓߥ",
+ "ߖ߭ߙ",
+ "ߖ߭ߙߖ߭",
+ "ߖ߭ߥߘ",
+ "ߖ߭ߥߟ",
+ "ߖ߭ߥߙ",
+ "ر",
+ "KA$",
+ "Db",
+ "DIP",
+ "රු.",
+ "සිෆ්එ",
+ "NIS",
+ "den",
+ "M",
+ "Rs.",
+ "S$",
+ "сом.",
+ "Kg.",
+ "AUD$",
+ "NZD$",
+ "крб.",
+ "сўм",
+ "EGPP",
+ "GHS.",
+ "GIIP",
+ "GT Q",
+ "HRKS",
+ "Vote MDL",
+ "NGN.",
+ "I-CNH",
+ "ICg.",
+ "IZWG",
+};
+#define CURRENCY_SYM_COUNT 701
+
+const uint8_t locale_currency_data[] = {
+ /* aa */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x4d, 0x57, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b,
+0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* aa-DJ */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x68, 0x80, 0x01, 0x4d, 0x57, 0x02, 0x01, 0x06,
+0x11, 0x13, 0x0b, 0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16,
+0x16, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01,
+0x09, 0x08, 0x06,
+ /* aa-ER */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x53, 0x65, 0x4d, 0x57, 0x02, 0x01, 0x06, 0x11,
+0x13, 0x0b, 0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16,
+0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+0x08, 0x06,
+ /* ab */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* af */
+0x0e, 0x14, 0x0b, 0x08, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03, 0x09, 0x05,
+0x11, 0x13, 0x10, 0x0a, 0x0f, 0x10, 0x17, 0x18, 0x14, 0x0c, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d,
+0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06, 0x48, 0x53,
+ /* af-NA */
+0x0e, 0x14, 0x0b, 0x08, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03, 0x09, 0x05,
+0x11, 0x13, 0x10, 0x0a, 0x1f, 0x17, 0x0f, 0x10, 0x17, 0x18, 0x14, 0x0c, 0x0a, 0x07, 0x04, 0x02,
+0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06, 0x48, 0x53,
+ /* agq */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ak */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x54, 0x6a, 0x13, 0x0b,
+0x07, 0x03, 0x09, 0x05, 0x32, 0xc9, 0x01, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16,
+0x16, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0xca, 0x01,
+0x01, 0x09, 0x08, 0x06,
+ /* am */
+0x0e, 0x1a, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x4d, 0xcb, 0x01, 0x02, 0x01, 0x06, 0x11, 0x13,
+0x0b, 0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x17, 0x18, 0x14,
+0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08,
+0x06,
+ /* an */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ann */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x39, 0x54, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* apc */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x3a, 0x3e, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ar */
+0x3d, 0x3f, 0x0e, 0x1a, 0x3e, 0x40, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x37, 0x41, 0x33, 0x42,
+0x02, 0x01, 0x06, 0x4f, 0x13, 0x0b, 0x07, 0x03, 0x09, 0x05, 0x32, 0x3c, 0x31, 0x43, 0x3a, 0x3e,
+0x11, 0x13, 0x10, 0x0a, 0x3f, 0x44, 0x18, 0x45, 0x3b, 0x46, 0x3c, 0x47, 0x34, 0x48, 0x0d, 0x0e,
+0x0f, 0x10, 0x40, 0x49, 0x41, 0x4a, 0x42, 0x4b, 0x45, 0x4c, 0x43, 0x50, 0x36, 0x3d, 0x17, 0x18,
+0x38, 0x4d, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04,
+0x01, 0x09, 0x08, 0x06, 0x44, 0x4e,
+ /* ar-AE */
+0x3d, 0x3f, 0x0e, 0x1a, 0x3e, 0x40, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x37, 0x41, 0x33, 0x42,
+0x02, 0x01, 0x06, 0x4f, 0x13, 0x0b, 0x07, 0x03, 0x09, 0x05, 0x32, 0x3c, 0x31, 0x43, 0x3a, 0x3e,
+0x11, 0x13, 0x10, 0x0a, 0x3f, 0x44, 0x18, 0x45, 0x3b, 0x46, 0x3c, 0x47, 0x34, 0x48, 0x0d, 0x0e,
+0x0f, 0x10, 0x40, 0x49, 0x41, 0x4a, 0x42, 0x4b, 0x45, 0x4c, 0x43, 0x50, 0x36, 0x3d, 0x17, 0x18,
+0x38, 0x4d, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04,
+0x01, 0x09, 0x08, 0x06, 0x44, 0x4e,
+ /* ar-BH */
+0x3d, 0x3f, 0x0e, 0x1a, 0x3e, 0x40, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x37, 0x41, 0x33, 0x42,
+0x02, 0x01, 0x06, 0x4f, 0x13, 0x0b, 0x07, 0x03, 0x09, 0x05, 0x32, 0x3c, 0x31, 0x43, 0x3a, 0x3e,
+0x11, 0x13, 0x10, 0x0a, 0x3f, 0x44, 0x18, 0x45, 0x3b, 0x46, 0x3c, 0x47, 0x34, 0x48, 0x0d, 0x0e,
+0x0f, 0x10, 0x40, 0x49, 0x41, 0x4a, 0x42, 0x4b, 0x45, 0x4c, 0x43, 0x50, 0x36, 0x3d, 0x17, 0x18,
+0x38, 0x4d, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04,
+0x01, 0x09, 0x08, 0x06, 0x44, 0x4e,
+ /* ar-DJ */
+0x3d, 0x3f, 0x0e, 0x1a, 0x3e, 0x40, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x68, 0x80, 0x01, 0x37,
+0x41, 0x33, 0x42, 0x02, 0x01, 0x06, 0x4f, 0x13, 0x0b, 0x07, 0x03, 0x09, 0x05, 0x32, 0x3c, 0x31,
+0x43, 0x3a, 0x3e, 0x11, 0x13, 0x10, 0x0a, 0x3f, 0x44, 0x18, 0x45, 0x3b, 0x46, 0x3c, 0x47, 0x34,
+0x48, 0x0d, 0x0e, 0x0f, 0x10, 0x40, 0x49, 0x41, 0x4a, 0x42, 0x4b, 0x45, 0x4c, 0x43, 0x50, 0x36,
+0x3d, 0x17, 0x18, 0x38, 0x4d, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00,
+0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06, 0x44, 0x4e,
+ /* ar-DZ */
+0x3d, 0x3f, 0x0e, 0x1a, 0x3e, 0x40, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x37, 0x41, 0x33, 0x42,
+0x02, 0x01, 0x06, 0x4f, 0x13, 0x0b, 0x07, 0x03, 0x09, 0x05, 0x32, 0x3c, 0x31, 0x43, 0x3a, 0x3e,
+0x11, 0x13, 0x10, 0x0a, 0x3f, 0x44, 0x18, 0x45, 0x3b, 0x46, 0x3c, 0x47, 0x34, 0x48, 0x0d, 0x0e,
+0x0f, 0x10, 0x40, 0x49, 0x41, 0x4a, 0x42, 0x4b, 0x45, 0x4c, 0x43, 0x50, 0x36, 0x3d, 0x17, 0x18,
+0x38, 0x4d, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04,
+0x01, 0x09, 0x08, 0x06, 0x44, 0x4e,
+ /* ar-EG */
+0x3d, 0x3f, 0x0e, 0x1a, 0x3e, 0x40, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x37, 0x41, 0x33, 0x42,
+0x02, 0x01, 0x06, 0x4f, 0x13, 0x0b, 0x07, 0x03, 0x09, 0x05, 0x32, 0x3c, 0x31, 0x43, 0x3a, 0x3e,
+0x11, 0x13, 0x10, 0x0a, 0x3f, 0x44, 0x18, 0x45, 0x3b, 0x46, 0x3c, 0x47, 0x34, 0x48, 0x0d, 0x0e,
+0x0f, 0x10, 0x40, 0x49, 0x41, 0x4a, 0x42, 0x4b, 0x45, 0x4c, 0x43, 0x50, 0x36, 0x3d, 0x17, 0x18,
+0x38, 0x4d, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04,
+0x01, 0x09, 0x08, 0x06, 0x44, 0x4e,
+ /* ar-EH */
+0x3d, 0x3f, 0x0e, 0x1a, 0x3e, 0x40, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x37, 0x41, 0x33, 0x42,
+0x02, 0x01, 0x06, 0x4f, 0x13, 0x0b, 0x07, 0x03, 0x09, 0x05, 0x32, 0x3c, 0x31, 0x43, 0x3a, 0x3e,
+0x11, 0x13, 0x10, 0x0a, 0x3f, 0x44, 0x18, 0x45, 0x3b, 0x46, 0x3c, 0x47, 0x34, 0x48, 0x0d, 0x0e,
+0x0f, 0x10, 0x40, 0x49, 0x41, 0x4a, 0x42, 0x4b, 0x45, 0x4c, 0x43, 0x50, 0x36, 0x3d, 0x17, 0x18,
+0x38, 0x4d, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04,
+0x01, 0x09, 0x08, 0x06, 0x44, 0x4e,
+ /* ar-ER */
+0x3d, 0x3f, 0x0e, 0x1a, 0x3e, 0x40, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x37, 0x41, 0x33, 0x42,
+0x53, 0x65, 0x02, 0x01, 0x06, 0x4f, 0x13, 0x0b, 0x07, 0x03, 0x09, 0x05, 0x32, 0x3c, 0x31, 0x43,
+0x3a, 0x3e, 0x11, 0x13, 0x10, 0x0a, 0x3f, 0x44, 0x18, 0x45, 0x3b, 0x46, 0x3c, 0x47, 0x34, 0x48,
+0x0d, 0x0e, 0x0f, 0x10, 0x40, 0x49, 0x41, 0x4a, 0x42, 0x4b, 0x45, 0x4c, 0x43, 0x50, 0x36, 0x3d,
+0x17, 0x18, 0x38, 0x4d, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00,
+0x03, 0x04, 0x01, 0x09, 0x08, 0x06, 0x44, 0x4e,
+ /* ar-IL */
+0x3d, 0x3f, 0x0e, 0x1a, 0x3e, 0x40, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x37, 0x41, 0x33, 0x42,
+0x02, 0x01, 0x06, 0x4f, 0x13, 0x0b, 0x07, 0x03, 0x09, 0x05, 0x32, 0x3c, 0x31, 0x43, 0x3a, 0x3e,
+0x11, 0x13, 0x10, 0x0a, 0x3f, 0x44, 0x18, 0x45, 0x3b, 0x46, 0x3c, 0x47, 0x34, 0x48, 0x0d, 0x0e,
+0x0f, 0x10, 0x40, 0x49, 0x41, 0x4a, 0x42, 0x4b, 0x45, 0x4c, 0x43, 0x50, 0x36, 0x3d, 0x17, 0x18,
+0x38, 0x4d, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04,
+0x01, 0x09, 0x08, 0x06, 0x44, 0x4e,
+ /* ar-IQ */
+0x3d, 0x3f, 0x0e, 0x1a, 0x3e, 0x40, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x37, 0x41, 0x33, 0x42,
+0x02, 0x01, 0x06, 0x4f, 0x13, 0x0b, 0x07, 0x03, 0x09, 0x05, 0x32, 0x3c, 0x31, 0x43, 0x3a, 0x3e,
+0x11, 0x13, 0x10, 0x0a, 0x3f, 0x44, 0x18, 0x45, 0x3b, 0x46, 0x3c, 0x47, 0x34, 0x48, 0x0d, 0x0e,
+0x0f, 0x10, 0x40, 0x49, 0x41, 0x4a, 0x42, 0x4b, 0x45, 0x4c, 0x43, 0x50, 0x36, 0x3d, 0x17, 0x18,
+0x38, 0x4d, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04,
+0x01, 0x09, 0x08, 0x06, 0x44, 0x4e,
+ /* ar-JO */
+0x3d, 0x3f, 0x0e, 0x1a, 0x3e, 0x40, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x37, 0x41, 0x33, 0x42,
+0x02, 0x01, 0x06, 0x4f, 0x13, 0x0b, 0x07, 0x03, 0x09, 0x05, 0x32, 0x3c, 0x31, 0x43, 0x3a, 0x3e,
+0x11, 0x13, 0x10, 0x0a, 0x3f, 0x44, 0x18, 0x45, 0x3b, 0x46, 0x3c, 0x47, 0x34, 0x48, 0x0d, 0x0e,
+0x0f, 0x10, 0x40, 0x49, 0x41, 0x4a, 0x42, 0x4b, 0x45, 0x4c, 0x43, 0x50, 0x36, 0x3d, 0x17, 0x18,
+0x38, 0x4d, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04,
+0x01, 0x09, 0x08, 0x06, 0x44, 0x4e,
+ /* ar-KM */
+0x3d, 0x3f, 0x0e, 0x1a, 0x3e, 0x40, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x37, 0x41, 0x33, 0x42,
+0x02, 0x01, 0x06, 0x4f, 0x13, 0x0b, 0x07, 0x03, 0x09, 0x05, 0x32, 0x3c, 0x31, 0x43, 0x3a, 0x3e,
+0x11, 0x13, 0x88, 0x01, 0xb1, 0x01, 0x10, 0x0a, 0x3f, 0x44, 0x18, 0x45, 0x3b, 0x46, 0x3c, 0x47,
+0x34, 0x48, 0x0d, 0x0e, 0x0f, 0x10, 0x40, 0x49, 0x41, 0x4a, 0x42, 0x4b, 0x45, 0x4c, 0x43, 0x50,
+0x36, 0x3d, 0x17, 0x18, 0x38, 0x4d, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d,
+0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06, 0x44, 0x4e,
+ /* ar-KW */
+0x3d, 0x3f, 0x0e, 0x1a, 0x3e, 0x40, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x37, 0x41, 0x33, 0x42,
+0x02, 0x01, 0x06, 0x4f, 0x13, 0x0b, 0x07, 0x03, 0x09, 0x05, 0x32, 0x3c, 0x31, 0x43, 0x3a, 0x3e,
+0x11, 0x13, 0x10, 0x0a, 0x3f, 0x44, 0x18, 0x45, 0x3b, 0x46, 0x3c, 0x47, 0x34, 0x48, 0x0d, 0x0e,
+0x0f, 0x10, 0x40, 0x49, 0x41, 0x4a, 0x42, 0x4b, 0x45, 0x4c, 0x43, 0x50, 0x36, 0x3d, 0x17, 0x18,
+0x38, 0x4d, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04,
+0x01, 0x09, 0x08, 0x06, 0x44, 0x4e,
+ /* ar-LB */
+0x3d, 0x3f, 0x0e, 0x1a, 0x3e, 0x40, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x37, 0x41, 0x33, 0x42,
+0x02, 0x01, 0x06, 0x4f, 0x13, 0x0b, 0x07, 0x03, 0x09, 0x05, 0x32, 0x3c, 0x31, 0x43, 0x3a, 0x3e,
+0x11, 0x13, 0x10, 0x0a, 0x3f, 0x44, 0x18, 0x45, 0x3b, 0x46, 0x3c, 0x47, 0x34, 0x48, 0x0d, 0x0e,
+0x0f, 0x10, 0x40, 0x49, 0x41, 0x4a, 0x42, 0x4b, 0x45, 0x4c, 0x36, 0x3d, 0x17, 0x18, 0x38, 0x4d,
+0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+0x08, 0x06, 0x44, 0x4e,
+ /* ar-LY */
+0x3d, 0x3f, 0x0e, 0x1a, 0x3e, 0x40, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x37, 0x41, 0x33, 0x42,
+0x02, 0x01, 0x06, 0x4f, 0x13, 0x0b, 0x07, 0x03, 0x09, 0x05, 0x32, 0x3c, 0x31, 0x43, 0x3a, 0x3e,
+0x11, 0x13, 0x10, 0x0a, 0x3f, 0x44, 0x18, 0x45, 0x3b, 0x46, 0x3c, 0x47, 0x34, 0x48, 0x0d, 0x0e,
+0x0f, 0x10, 0x40, 0x49, 0x41, 0x4a, 0x42, 0x4b, 0x45, 0x4c, 0x43, 0x50, 0x36, 0x3d, 0x17, 0x18,
+0x38, 0x4d, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04,
+0x01, 0x09, 0x08, 0x06, 0x44, 0x4e,
+ /* ar-MA */
+0x3d, 0x3f, 0x0e, 0x1a, 0x3e, 0x40, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x37, 0x41, 0x33, 0x42,
+0x02, 0x01, 0x06, 0x4f, 0x13, 0x0b, 0x07, 0x03, 0x09, 0x05, 0x32, 0x3c, 0x31, 0x43, 0x3a, 0x3e,
+0x11, 0x13, 0x10, 0x0a, 0x3f, 0x44, 0x18, 0x45, 0x3b, 0x46, 0x3c, 0x47, 0x34, 0x48, 0x0d, 0x0e,
+0x0f, 0x10, 0x40, 0x49, 0x41, 0x4a, 0x42, 0x4b, 0x45, 0x4c, 0x43, 0x50, 0x36, 0x3d, 0x17, 0x18,
+0x38, 0x4d, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04,
+0x01, 0x09, 0x08, 0x06, 0x44, 0x4e,
+ /* ar-MR */
+0x3d, 0x3f, 0x0e, 0x1a, 0x3e, 0x40, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x37, 0x41, 0x33, 0x42,
+0x02, 0x01, 0x06, 0x4f, 0x13, 0x0b, 0x07, 0x03, 0x09, 0x05, 0x32, 0x3c, 0x31, 0x43, 0x3a, 0x3e,
+0x11, 0x13, 0x10, 0x0a, 0x3f, 0x44, 0x18, 0x45, 0x3b, 0x46, 0x3c, 0x47, 0x34, 0x48, 0x0d, 0x0e,
+0x0f, 0x10, 0x40, 0x49, 0x41, 0x4a, 0x42, 0x4b, 0x45, 0x4c, 0x43, 0x50, 0x36, 0x3d, 0x17, 0x18,
+0x38, 0x4d, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04,
+0x01, 0x09, 0x08, 0x06, 0x44, 0x4e,
+ /* ar-OM */
+0x3d, 0x3f, 0x0e, 0x1a, 0x3e, 0x40, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x37, 0x41, 0x33, 0x42,
+0x02, 0x01, 0x06, 0x4f, 0x13, 0x0b, 0x07, 0x03, 0x09, 0x05, 0x32, 0x3c, 0x31, 0x43, 0x3a, 0x3e,
+0x11, 0x13, 0x10, 0x0a, 0x3f, 0x44, 0x18, 0x45, 0x3b, 0x46, 0x3c, 0x47, 0x34, 0x48, 0x0d, 0x0e,
+0x0f, 0x10, 0x40, 0x49, 0x41, 0x4a, 0x42, 0x4b, 0x45, 0x4c, 0x43, 0x50, 0x36, 0x3d, 0x17, 0x18,
+0x38, 0x4d, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04,
+0x01, 0x09, 0x08, 0x06, 0x44, 0x4e,
+ /* ar-PS */
+0x3d, 0x3f, 0x0e, 0x1a, 0x3e, 0x40, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x37, 0x41, 0x33, 0x42,
+0x02, 0x01, 0x06, 0x4f, 0x13, 0x0b, 0x07, 0x03, 0x09, 0x05, 0x32, 0x3c, 0x31, 0x43, 0x3a, 0x3e,
+0x11, 0x13, 0x10, 0x0a, 0x3f, 0x44, 0x18, 0x45, 0x3b, 0x46, 0x3c, 0x47, 0x34, 0x48, 0x0d, 0x0e,
+0x0f, 0x10, 0x40, 0x49, 0x41, 0x4a, 0x42, 0x4b, 0x45, 0x4c, 0x43, 0x50, 0x36, 0x3d, 0x17, 0x18,
+0x38, 0x4d, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04,
+0x01, 0x09, 0x08, 0x06, 0x44, 0x4e,
+ /* ar-QA */
+0x3d, 0x3f, 0x0e, 0x1a, 0x3e, 0x40, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x37, 0x41, 0x33, 0x42,
+0x02, 0x01, 0x06, 0x4f, 0x13, 0x0b, 0x07, 0x03, 0x09, 0x05, 0x32, 0x3c, 0x31, 0x43, 0x3a, 0x3e,
+0x11, 0x13, 0x10, 0x0a, 0x3f, 0x44, 0x18, 0x45, 0x3b, 0x46, 0x3c, 0x47, 0x34, 0x48, 0x0d, 0x0e,
+0x0f, 0x10, 0x40, 0x49, 0x41, 0x4a, 0x42, 0x4b, 0x45, 0x4c, 0x43, 0x50, 0x36, 0x3d, 0x17, 0x18,
+0x38, 0x4d, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04,
+0x01, 0x09, 0x08, 0x06, 0x44, 0x4e,
+ /* ar-SA */
+0x3d, 0x3f, 0x0e, 0x1a, 0x3e, 0x40, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x37, 0x41, 0x33, 0x42,
+0x02, 0x01, 0x06, 0x4f, 0x13, 0x0b, 0x07, 0x03, 0x09, 0x05, 0x32, 0x3c, 0x31, 0x43, 0x3a, 0x3e,
+0x11, 0x13, 0x10, 0x0a, 0x3f, 0x44, 0x18, 0x45, 0x3b, 0x46, 0x3c, 0x47, 0x34, 0x48, 0x0d, 0x0e,
+0x0f, 0x10, 0x40, 0x49, 0x41, 0x4a, 0x42, 0x4b, 0x45, 0x4c, 0x43, 0x50, 0x36, 0x3d, 0x17, 0x18,
+0x38, 0x4d, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04,
+0x01, 0x09, 0x08, 0x06, 0x44, 0x4e,
+ /* ar-SD */
+0x3d, 0x3f, 0x0e, 0x1a, 0x3e, 0x40, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x37, 0x41, 0x33, 0x42,
+0x02, 0x01, 0x06, 0x4f, 0x13, 0x0b, 0x07, 0x03, 0x09, 0x05, 0x32, 0x3c, 0x31, 0x43, 0x3a, 0x3e,
+0x11, 0x13, 0x10, 0x0a, 0x3f, 0x44, 0x18, 0x45, 0x3b, 0x46, 0x3c, 0x47, 0x34, 0x48, 0x0d, 0x0e,
+0x0f, 0x10, 0x40, 0x49, 0x41, 0x4a, 0x42, 0x4b, 0x45, 0x4c, 0x43, 0x50, 0x36, 0x3d, 0x17, 0x18,
+0x38, 0x4d, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04,
+0x01, 0x09, 0x08, 0x06, 0x44, 0x4e,
+ /* ar-SO */
+0x3d, 0x3f, 0x0e, 0x1a, 0x3e, 0x40, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x37, 0x41, 0x33, 0x42,
+0x02, 0x01, 0x06, 0x4f, 0x13, 0x0b, 0x07, 0x03, 0x09, 0x05, 0x32, 0x3c, 0x31, 0x43, 0x3a, 0x3e,
+0x11, 0x13, 0x10, 0x0a, 0x3f, 0x44, 0x18, 0x45, 0x3b, 0x46, 0x3c, 0x47, 0x34, 0x48, 0x0d, 0x0e,
+0x0f, 0x10, 0x40, 0x49, 0x41, 0x4a, 0x42, 0x4b, 0x45, 0x4c, 0x43, 0x50, 0x5e, 0x7d, 0x36, 0x3d,
+0x17, 0x18, 0x38, 0x4d, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00,
+0x03, 0x04, 0x01, 0x09, 0x08, 0x06, 0x44, 0x4e,
+ /* ar-SS */
+0x3d, 0x3f, 0x0e, 0x1a, 0x3e, 0x40, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x37, 0x41, 0x33, 0x42,
+0x02, 0x01, 0x06, 0x6b, 0x13, 0x0b, 0x07, 0x03, 0x09, 0x05, 0x32, 0x3c, 0x31, 0x43, 0x3a, 0x3e,
+0x11, 0x13, 0x10, 0x0a, 0x3f, 0x44, 0x18, 0x45, 0x3b, 0x46, 0x3c, 0x47, 0x34, 0x48, 0x0d, 0x0e,
+0x0f, 0x10, 0x40, 0x49, 0x41, 0x4a, 0x42, 0x4b, 0x45, 0x4c, 0x43, 0x50, 0x74, 0x11, 0x36, 0x3d,
+0x17, 0x18, 0x38, 0x4d, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00,
+0x03, 0x04, 0x01, 0x09, 0x08, 0x06, 0x44, 0x4e,
+ /* ar-SY */
+0x3d, 0x3f, 0x0e, 0x1a, 0x3e, 0x40, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x37, 0x41, 0x33, 0x42,
+0x02, 0x01, 0x06, 0x4f, 0x13, 0x0b, 0x07, 0x03, 0x09, 0x05, 0x32, 0x3c, 0x31, 0x43, 0x3a, 0x3e,
+0x11, 0x13, 0x10, 0x0a, 0x3f, 0x44, 0x18, 0x45, 0x3b, 0x46, 0x3c, 0x47, 0x34, 0x48, 0x0d, 0x0e,
+0x0f, 0x10, 0x40, 0x49, 0x41, 0x4a, 0x42, 0x4b, 0x45, 0x4c, 0x43, 0x50, 0x36, 0x3d, 0x17, 0x18,
+0x38, 0x4d, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04,
+0x01, 0x09, 0x08, 0x06, 0x44, 0x4e,
+ /* ar-TD */
+0x3d, 0x3f, 0x0e, 0x1a, 0x3e, 0x40, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x37, 0x41, 0x33, 0x42,
+0x02, 0x01, 0x06, 0x4f, 0x13, 0x0b, 0x07, 0x03, 0x09, 0x05, 0x32, 0x3c, 0x31, 0x43, 0x3a, 0x3e,
+0x11, 0x13, 0x10, 0x0a, 0x3f, 0x44, 0x18, 0x45, 0x3b, 0x46, 0x3c, 0x47, 0x34, 0x48, 0x0d, 0x0e,
+0x0f, 0x10, 0x40, 0x49, 0x41, 0x4a, 0x42, 0x4b, 0x45, 0x4c, 0x43, 0x50, 0x36, 0x3d, 0x17, 0x18,
+0x38, 0x4d, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04,
+0x01, 0x09, 0x08, 0x06, 0x44, 0x4e,
+ /* ar-TN */
+0x3d, 0x3f, 0x0e, 0x1a, 0x3e, 0x40, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x37, 0x41, 0x33, 0x42,
+0x02, 0x01, 0x06, 0x4f, 0x13, 0x0b, 0x07, 0x03, 0x09, 0x05, 0x32, 0x3c, 0x31, 0x43, 0x3a, 0x3e,
+0x11, 0x13, 0x10, 0x0a, 0x3f, 0x44, 0x18, 0x45, 0x3b, 0x46, 0x3c, 0x47, 0x34, 0x48, 0x0d, 0x0e,
+0x0f, 0x10, 0x40, 0x49, 0x41, 0x4a, 0x42, 0x4b, 0x45, 0x4c, 0x43, 0x50, 0x36, 0x3d, 0x17, 0x18,
+0x38, 0x4d, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04,
+0x01, 0x09, 0x08, 0x06, 0x44, 0x4e,
+ /* ar-YE */
+0x3d, 0x3f, 0x0e, 0x1a, 0x3e, 0x40, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x37, 0x41, 0x33, 0x42,
+0x02, 0x01, 0x06, 0x4f, 0x13, 0x0b, 0x07, 0x03, 0x09, 0x05, 0x32, 0x3c, 0x31, 0x43, 0x3a, 0x3e,
+0x11, 0x13, 0x10, 0x0a, 0x3f, 0x44, 0x18, 0x45, 0x3b, 0x46, 0x3c, 0x47, 0x34, 0x48, 0x0d, 0x0e,
+0x0f, 0x10, 0x40, 0x49, 0x41, 0x4a, 0x42, 0x4b, 0x45, 0x4c, 0x43, 0x50, 0x36, 0x3d, 0x17, 0x18,
+0x38, 0x4d, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04,
+0x01, 0x09, 0x08, 0x06, 0x44, 0x4e,
+ /* arn */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* as */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07,
+0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* asa */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x49, 0x55,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ast */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x19, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x17, 0x18, 0x14, 0x0c, 0x05, 0x17,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+ /* az */
+0x0e, 0x14, 0x75, 0x90, 0x01, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13,
+0x0b, 0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x17, 0x18, 0x14,
+0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08,
+0x06,
+ /* az-Arab */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* az-Arab-IQ */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* az-Arab-TR */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* az-Cyrl */
+0x0e, 0x14, 0x75, 0x90, 0x01, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13,
+0x0b, 0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14,
+0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08,
+0x06,
+ /* az-Latn */
+0x0e, 0x14, 0x75, 0x90, 0x01, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13,
+0x0b, 0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x17, 0x18, 0x14,
+0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08,
+0x06,
+ /* ba */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x76, 0x75, 0x14, 0x0c,
+0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0xcc, 0x01, 0x01, 0x09, 0x08,
+0x06,
+ /* bal */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* bal-Arab */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* bal-Latn */
+0x51, 0xcd, 0x01, 0x77, 0xce, 0x01, 0x96, 0x01, 0xcf, 0x01, 0x69, 0xd0, 0x01, 0x89, 0x01, 0xd1,
+0x01, 0x22, 0xd2, 0x01, 0x0e, 0x14, 0x8a, 0x01, 0xd3, 0x01, 0x75, 0xd4, 0x01, 0x4a, 0xd5, 0x01,
+0x4e, 0xd6, 0x01, 0x78, 0xd7, 0x01, 0x97, 0x01, 0xd8, 0x01, 0x79, 0xd9, 0x01, 0x1b, 0xda, 0x01,
+0x23, 0xdb, 0x01, 0x5f, 0xdc, 0x01, 0x0b, 0x08, 0x6a, 0xdd, 0x01, 0xa7, 0x01, 0xde, 0x01, 0x8b,
+0x01, 0xdf, 0x01, 0x7a, 0xe0, 0x01, 0x1c, 0xe1, 0x01, 0x0c, 0xe2, 0x01, 0x59, 0xe3, 0x01, 0xa8,
+0x01, 0xe4, 0x01, 0x98, 0x01, 0xe5, 0x01, 0x15, 0xe6, 0x01, 0x1e, 0xe7, 0x01, 0x99, 0x01, 0xe8,
+0x01, 0xa9, 0x01, 0xe9, 0x01, 0x9a, 0x01, 0xea, 0x01, 0x8c, 0x01, 0xeb, 0x01, 0x8d, 0x01, 0xec,
+0x01, 0x68, 0xed, 0x01, 0x4b, 0xee, 0x01, 0x6b, 0xef, 0x01, 0x37, 0xf0, 0x01, 0x33, 0xf1, 0x01,
+0x53, 0xf2, 0x01, 0x4d, 0xf3, 0x01, 0x02, 0x01, 0x06, 0xf4, 0x01, 0x7b, 0xf5, 0x01, 0x54, 0xf6,
+0x01, 0x20, 0xf7, 0x01, 0x7c, 0xf8, 0x01, 0x6c, 0xf9, 0x01, 0x7d, 0xfa, 0x01, 0x13, 0xfb, 0x01,
+0x9b, 0x01, 0xfc, 0x01, 0x60, 0xfd, 0x01, 0x7e, 0xfe, 0x01, 0x9c, 0x01, 0xff, 0x01, 0x61, 0x80,
+0x02, 0x07, 0x03, 0x09, 0x81, 0x02, 0x31, 0x82, 0x02, 0x6d, 0x83, 0x02, 0x6e, 0x84, 0x02, 0x11,
+0x19, 0x47, 0x85, 0x02, 0x8e, 0x01, 0x86, 0x02, 0xaa, 0x01, 0x87, 0x02, 0x88, 0x01, 0x88, 0x02,
+0xab, 0x01, 0x89, 0x02, 0x10, 0x8a, 0x02, 0x9d, 0x01, 0x8b, 0x02, 0x62, 0x8c, 0x02, 0xac, 0x01,
+0x8d, 0x02, 0x18, 0x8e, 0x02, 0x9e, 0x01, 0x8f, 0x02, 0x5a, 0x90, 0x02, 0x63, 0x91, 0x02, 0x3b,
+0x92, 0x02, 0x3c, 0x93, 0x02, 0x7f, 0x94, 0x02, 0x80, 0x01, 0x95, 0x02, 0x8f, 0x01, 0x96, 0x02,
+0xad, 0x01, 0x97, 0x02, 0x90, 0x01, 0x98, 0x02, 0x6f, 0x99, 0x02, 0x34, 0x9a, 0x02, 0x81, 0x01,
+0x9b, 0x02, 0x9f, 0x01, 0x9c, 0x02, 0xa0, 0x01, 0x9d, 0x02, 0x0d, 0x9e, 0x02, 0x55, 0x9f, 0x02,
+0x82, 0x01, 0xa0, 0x02, 0x1f, 0xa1, 0x02, 0x39, 0xa2, 0x02, 0xa1, 0x01, 0xa3, 0x02, 0x4f, 0xa4,
+0x02, 0xa2, 0x01, 0xa5, 0x02, 0x0f, 0x10, 0x91, 0x01, 0xa6, 0x02, 0x92, 0x01, 0xa7, 0x02, 0x16,
+0xa8, 0x02, 0x64, 0xa9, 0x02, 0x65, 0xaa, 0x02, 0x93, 0x01, 0xab, 0x02, 0x94, 0x01, 0xac, 0x02,
+0x83, 0x01, 0xad, 0x02, 0x46, 0xae, 0x02, 0x95, 0x01, 0xaf, 0x02, 0x5d, 0xb0, 0x02, 0x43, 0xb1,
+0x02, 0x5b, 0xb2, 0x02, 0x1d, 0xb3, 0x02, 0xa3, 0x01, 0xb4, 0x02, 0x84, 0x01, 0xb5, 0x02, 0xae,
+0x01, 0xb6, 0x02, 0x5e, 0xb7, 0x02, 0x24, 0xb8, 0x02, 0x74, 0xb9, 0x02, 0xa4, 0x01, 0xba, 0x02,
+0x36, 0xbb, 0x02, 0x85, 0x01, 0xbc, 0x02, 0x17, 0xbd, 0x02, 0x38, 0xbe, 0x02, 0x56, 0xbf, 0x02,
+0x21, 0xc0, 0x02, 0x14, 0xc1, 0x02, 0x49, 0xc2, 0x02, 0x5c, 0xc3, 0x02, 0x57, 0xc4, 0x02, 0x05,
+0x17, 0x25, 0xc5, 0x02, 0x86, 0x01, 0xc6, 0x02, 0x70, 0xc7, 0x02, 0x0a, 0xc8, 0x02, 0x04, 0xc9,
+0x02, 0x12, 0xca, 0x02, 0x00, 0x00, 0x03, 0xcb, 0x02, 0x01, 0x09, 0x08, 0x06, 0x48, 0xcc, 0x02,
+0xa5, 0x01, 0xcd, 0x02,
+ /* bas */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* be */
+0x0e, 0x14, 0x7a, 0x57, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03, 0x09, 0x05,
+0x11, 0x19, 0x10, 0x0a, 0x0d, 0x0e, 0x46, 0x51, 0x14, 0x0c, 0x05, 0x17, 0x0a, 0x07, 0x04, 0x02,
+0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* be-tarask */
+0x0e, 0x14, 0x7a, 0x57, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03, 0x09, 0x05,
+0x11, 0x19, 0x10, 0x0a, 0x0d, 0x0e, 0x46, 0x51, 0x14, 0x0c, 0x05, 0x17, 0x0a, 0x07, 0x04, 0x02,
+0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* bem */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06, 0xa5, 0x01,
+0x81, 0x01,
+ /* bew */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* bez */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x49, 0x55,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* bg */
+0x97, 0x01, 0xce, 0x02, 0x02, 0x01, 0x05, 0xcf, 0x02, 0x04, 0x02, 0x00, 0x00, 0x03, 0x04, 0x01,
+0x09, 0x08, 0x06,
+ /* bgc */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* bgn */
+0x51, 0x60, 0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b,
+0x07, 0x03, 0x09, 0x05, 0x31, 0x6c, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16,
+0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+0x08, 0x06,
+ /* bgn-AE */
+0x51, 0x60, 0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b,
+0x07, 0x03, 0x09, 0x05, 0x31, 0x6c, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16,
+0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+0x08, 0x06,
+ /* bgn-AF */
+0x51, 0x60, 0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b,
+0x07, 0x03, 0x09, 0x05, 0x31, 0x6c, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16,
+0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+0x08, 0x06,
+ /* bgn-IR */
+0x51, 0x60, 0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b,
+0x07, 0x03, 0x09, 0x05, 0x31, 0x6c, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16,
+0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+0x08, 0x06,
+ /* bgn-OM */
+0x51, 0x60, 0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b,
+0x07, 0x03, 0x09, 0x05, 0x31, 0x6c, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16,
+0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+0x08, 0x06,
+ /* bho */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* blo */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* blt */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* bm */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* bm-Nkoo */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* bn */
+0x0e, 0x14, 0x78, 0x82, 0x01, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13,
+0x0b, 0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x17, 0x18, 0x14,
+0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08,
+0x06,
+ /* bn-IN */
+0x0e, 0x14, 0x78, 0x82, 0x01, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13,
+0x0b, 0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x17, 0x18, 0x14,
+0x0c, 0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08,
+0x06,
+ /* bo */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x19, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* bo-IN */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* bqi */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* br */
+0x0e, 0xd0, 0x02, 0x0c, 0x1b, 0x02, 0x01, 0x06, 0xd1, 0x02, 0x13, 0xd2, 0x02, 0x09, 0x05, 0x0d,
+0x0e, 0x0f, 0xd3, 0x02, 0x05, 0xd4, 0x02, 0x04, 0x02, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+ /* brx */
+0x3d, 0xd5, 0x02, 0x77, 0xd6, 0x02, 0x96, 0x01, 0xd7, 0x02, 0x69, 0xd8, 0x02, 0x89, 0x01, 0xd9,
+0x02, 0x22, 0xda, 0x02, 0x0e, 0x14, 0x8a, 0x01, 0xdb, 0x02, 0x75, 0xdc, 0x02, 0x4a, 0xdd, 0x02,
+0x4e, 0xde, 0x02, 0x97, 0x01, 0xdf, 0x02, 0x3e, 0xe0, 0x02, 0x79, 0xe1, 0x02, 0x1b, 0xe2, 0x02,
+0x5f, 0xe3, 0x02, 0x0b, 0x08, 0x6a, 0xe4, 0x02, 0x8b, 0x01, 0xe5, 0x02, 0x7a, 0xe6, 0x02, 0x1c,
+0xe7, 0x02, 0x0c, 0xe8, 0x02, 0x59, 0xe9, 0x02, 0xa8, 0x01, 0xea, 0x02, 0x27, 0xeb, 0x02, 0x98,
+0x01, 0xec, 0x02, 0x15, 0xed, 0x02, 0x1e, 0xee, 0x02, 0x99, 0x01, 0xef, 0x02, 0xa9, 0x01, 0xf0,
+0x02, 0x9a, 0x01, 0xf1, 0x02, 0x8c, 0x01, 0xf2, 0x02, 0x8d, 0x01, 0xf3, 0x02, 0x68, 0xf4, 0x02,
+0x4b, 0xf5, 0x02, 0x6b, 0xf6, 0x02, 0x37, 0xf7, 0x02, 0x33, 0xf8, 0x02, 0x53, 0xf9, 0x02, 0x4d,
+0xfa, 0x02, 0x02, 0x01, 0x28, 0xfb, 0x02, 0x06, 0x11, 0x7b, 0xfc, 0x02, 0x54, 0xfd, 0x02, 0x20,
+0xfe, 0x02, 0x7c, 0xff, 0x02, 0x6c, 0x80, 0x03, 0x7d, 0x81, 0x03, 0xaf, 0x01, 0x82, 0x03, 0x13,
+0x83, 0x03, 0x9b, 0x01, 0x84, 0x03, 0x60, 0x85, 0x03, 0x7e, 0x86, 0x03, 0x9c, 0x01, 0x87, 0x03,
+0x07, 0x03, 0x09, 0x05, 0x32, 0x88, 0x03, 0x6d, 0x89, 0x03, 0x6e, 0x8a, 0x03, 0x3a, 0x8b, 0x03,
+0x11, 0x13, 0x47, 0x8c, 0x03, 0x8e, 0x01, 0x8d, 0x03, 0x88, 0x01, 0x8e, 0x03, 0xab, 0x01, 0x8f,
+0x03, 0x10, 0x0a, 0x3f, 0x90, 0x03, 0x9d, 0x01, 0x91, 0x03, 0x62, 0x92, 0x03, 0x18, 0x93, 0x03,
+0x5a, 0x94, 0x03, 0x63, 0x95, 0x03, 0x3b, 0x96, 0x03, 0x3c, 0x97, 0x03, 0x7f, 0x98, 0x03, 0x80,
+0x01, 0x99, 0x03, 0x8f, 0x01, 0x9a, 0x03, 0x90, 0x01, 0x9b, 0x03, 0x6f, 0x9c, 0x03, 0x34, 0x9d,
+0x03, 0x81, 0x01, 0x9e, 0x03, 0xa0, 0x01, 0x9f, 0x03, 0x0d, 0xa0, 0x03, 0x82, 0x01, 0xa1, 0x03,
+0x1f, 0xa2, 0x03, 0x39, 0xa3, 0x03, 0xa1, 0x01, 0xa4, 0x03, 0x4f, 0xa5, 0x03, 0x0f, 0x10, 0x40,
+0xa6, 0x03, 0x91, 0x01, 0xa7, 0x03, 0x92, 0x01, 0xa8, 0x03, 0x16, 0x16, 0x65, 0xa9, 0x03, 0x93,
+0x01, 0xaa, 0x03, 0x41, 0xab, 0x03, 0x94, 0x01, 0xac, 0x03, 0x83, 0x01, 0xad, 0x03, 0x46, 0xae,
+0x03, 0x42, 0xaf, 0x03, 0x5d, 0xb0, 0x03, 0x43, 0xb1, 0x03, 0x5b, 0xb2, 0x03, 0xa3, 0x01, 0xb3,
+0x03, 0x84, 0x01, 0xb4, 0x03, 0xae, 0x01, 0xb5, 0x03, 0x5e, 0xb6, 0x03, 0x24, 0xb7, 0x03, 0x74,
+0xb8, 0x03, 0xa4, 0x01, 0xb9, 0x03, 0x36, 0xba, 0x03, 0x85, 0x01, 0xbb, 0x03, 0xb0, 0x01, 0xbc,
+0x03, 0x66, 0xbd, 0x03, 0x38, 0xbe, 0x03, 0x56, 0xbf, 0x03, 0x21, 0xc0, 0x03, 0x14, 0xc1, 0x03,
+0x49, 0xc2, 0x03, 0x5c, 0xc3, 0x03, 0x57, 0xc4, 0x03, 0x05, 0x17, 0x25, 0xc5, 0x03, 0x86, 0x01,
+0xc6, 0x03, 0x70, 0xc7, 0x03, 0x0a, 0x07, 0x04, 0x02, 0x12, 0xc8, 0x03, 0x00, 0x00, 0x03, 0x04,
+0x01, 0x09, 0x08, 0x06, 0x44, 0xc9, 0x03, 0x48, 0xca, 0x03,
+ /* bs */
+0x4a, 0x6d, 0x02, 0x01, 0x60, 0x83, 0x01, 0x09, 0x05, 0x11, 0x19, 0x10, 0x0a, 0x83, 0x01, 0xb2,
+0x01, 0x17, 0x18, 0x14, 0x0c, 0x0a, 0x07, 0x04, 0x02, 0x00, 0x00, 0x03, 0x04, 0x08, 0x06,
+ /* bs-Cyrl */
+0x0e, 0x14, 0x4a, 0x76, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x8d, 0x01, 0xcb, 0x03, 0x02, 0x01,
+0x06, 0x11, 0x13, 0x0b, 0x07, 0x03, 0x09, 0x05, 0x11, 0x19, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10,
+0x16, 0x16, 0x65, 0xcc, 0x03, 0x83, 0x01, 0xcd, 0x03, 0x56, 0xce, 0x03, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* bs-Latn */
+0x4a, 0x6d, 0x02, 0x01, 0x60, 0x83, 0x01, 0x09, 0x05, 0x11, 0x19, 0x10, 0x0a, 0x83, 0x01, 0xb2,
+0x01, 0x17, 0x18, 0x14, 0x0c, 0x0a, 0x07, 0x04, 0x02, 0x00, 0x00, 0x03, 0x04, 0x08, 0x06,
+ /* bss */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* bua */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* byn */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x53, 0x65, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b,
+0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ca */
+0x0e, 0x1a, 0x35, 0x3b, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03, 0x09, 0x05, 0x11, 0x19,
+0x10, 0x0a, 0x0f, 0x10, 0x17, 0x18, 0x14, 0x0c, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x04, 0x01, 0x09,
+ /* ca-AD */
+0x0e, 0x1a, 0x35, 0x3b, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03, 0x09, 0x05, 0x11, 0x19,
+0x10, 0x0a, 0x0f, 0x10, 0x17, 0x18, 0x14, 0x0c, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x04, 0x01, 0x09,
+ /* ca-ES-valencia */
+0x0e, 0x1a, 0x35, 0x3b, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03, 0x09, 0x05, 0x11, 0x19,
+0x10, 0x0a, 0x0f, 0x10, 0x17, 0x18, 0x14, 0x0c, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x04, 0x01, 0x09,
+ /* ca-FR */
+0x0e, 0x1a, 0x35, 0x3b, 0x02, 0x01, 0x2c, 0x1c, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03, 0x09, 0x05,
+0x11, 0x19, 0x10, 0x0a, 0x0f, 0x10, 0x17, 0x18, 0x14, 0x0c, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x04,
+0x01, 0x09,
+ /* ca-IT */
+0x0e, 0x1a, 0x35, 0x3b, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03, 0x09, 0x05, 0x11, 0x19,
+0x10, 0x0a, 0x0f, 0x10, 0x17, 0x18, 0x14, 0x0c, 0x0a, 0x07, 0x04, 0x02, 0x03, 0x04, 0x01, 0x09,
+ /* cad */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x17,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* cch */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x39, 0x54, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ccp */
+0x0e, 0x14, 0x78, 0x82, 0x01, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13,
+0x0b, 0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x17, 0x18, 0x14,
+0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08,
+0x06,
+ /* ccp-IN */
+0x0e, 0x14, 0x78, 0x82, 0x01, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13,
+0x0b, 0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x17, 0x18, 0x14,
+0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08,
+0x06,
+ /* ce */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x46, 0x51, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ceb */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0xcf,
+0x03, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* cgg */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x57, 0x66,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* cho */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* chr */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x14, 0x0c, 0x05, 0x17, 0x0a, 0x07,
+0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* cic */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x17,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ckb */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x32, 0x3c, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ckb-IR */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x32, 0x3c, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* co */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* cop */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* cs */
+0x0e, 0x1a, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0xb7, 0x01, 0xd0, 0x03, 0x8d, 0x01, 0xd1, 0x03,
+0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x14, 0x0c,
+0x05, 0x15, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0xb8, 0x01, 0xd2, 0x03, 0x03, 0x04, 0x01, 0x09,
+ /* csw */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* cu */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x46, 0x51, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* cv */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x46, 0x51, 0x14, 0x0c,
+0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* cy */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x0d, 0x0e, 0x0f, 0x10, 0x17, 0x18, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07,
+0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+ /* da */
+0x0e, 0x1a, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x4b, 0x77, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b,
+0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x17, 0x18, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* da-GL */
+0x0e, 0x1a, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x4b, 0x77, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b,
+0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x17, 0x18, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* dav */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x47, 0x52, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* de */
+0x58, 0x5e, 0x0e, 0x1a, 0x71, 0x6e, 0x72, 0x6f, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x73, 0x70,
+0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03, 0x09, 0x05, 0x11, 0x19, 0x10, 0x0a, 0x0d, 0x0e,
+0x0f, 0x10, 0x17, 0x18, 0x14, 0x0c, 0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00,
+0x03, 0x04, 0x01, 0x09,
+ /* de-AT */
+0x58, 0x5e, 0x0e, 0x1a, 0x71, 0x6e, 0x72, 0x6f, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x73, 0x70,
+0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03, 0x09, 0x05, 0x11, 0x19, 0x10, 0x0a, 0x0d, 0x0e,
+0x0f, 0x10, 0x17, 0x18, 0x14, 0x0c, 0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00,
+0x03, 0x04, 0x01, 0x09,
+ /* de-BE */
+0x58, 0x5e, 0x0e, 0x1a, 0x71, 0x6e, 0x72, 0x6f, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x73, 0x70,
+0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03, 0x09, 0x05, 0x11, 0x19, 0x10, 0x0a, 0x0d, 0x0e,
+0x0f, 0x10, 0x17, 0x18, 0x14, 0x0c, 0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00,
+0x03, 0x04, 0x01, 0x09,
+ /* de-CH */
+0x58, 0x5e, 0x0e, 0x1a, 0x71, 0x6e, 0x72, 0x6f, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x73, 0x70,
+0x06, 0x11, 0x13, 0x0b, 0x07, 0x03, 0x09, 0x05, 0x11, 0x19, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10,
+0x17, 0x18, 0x14, 0x0c, 0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04,
+0x01, 0x09,
+ /* de-IT */
+0x58, 0x5e, 0x0e, 0x1a, 0x71, 0x6e, 0x72, 0x6f, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x73, 0x70,
+0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03, 0x09, 0x05, 0x11, 0x19, 0x10, 0x0a, 0x0d, 0x0e,
+0x0f, 0x10, 0x17, 0x18, 0x14, 0x0c, 0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00,
+0x03, 0x04, 0x01, 0x09,
+ /* de-LI */
+0x58, 0x5e, 0x0e, 0x1a, 0x71, 0x6e, 0x72, 0x6f, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x73, 0x70,
+0x06, 0x11, 0x13, 0x0b, 0x07, 0x03, 0x09, 0x05, 0x11, 0x19, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10,
+0x17, 0x18, 0x14, 0x0c, 0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04,
+0x01, 0x09,
+ /* de-LU */
+0x58, 0x5e, 0x0e, 0x1a, 0x71, 0x6e, 0x72, 0x6f, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x73, 0x70,
+0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03, 0x09, 0x05, 0x11, 0x19, 0x10, 0x0a, 0xb1, 0x01,
+0x1c, 0x0d, 0x0e, 0x0f, 0x10, 0x17, 0x18, 0x14, 0x0c, 0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x12,
+0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+ /* dje */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* doi */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x19, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x17,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* dsb */
+0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03, 0x09, 0x05,
+0x11, 0x19, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x65, 0x84, 0x01, 0x17, 0x18, 0x14,
+0x0c, 0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08,
+0x06,
+ /* dua */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* dv */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x9f, 0x01, 0xd3, 0x03, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16,
+0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+0x08, 0x06,
+ /* dyo */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* dz */
+0x0e, 0x1a, 0x0b, 0x08, 0xa7, 0x01, 0xd4, 0x03, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11,
+0x13, 0x0b, 0x09, 0x05, 0x11, 0x13, 0x10, 0xd5, 0x03, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x17,
+0xd6, 0x03, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+0x08, 0x06,
+ /* ebu */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x47, 0x52, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ee */
+0x0e, 0x1a, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x54, 0x6a, 0x13, 0x0b,
+0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x17, 0x18,
+0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+0x08, 0x06,
+ /* ee-TG */
+0x0e, 0x1a, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x54, 0x6a, 0x13, 0x0b,
+0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x17, 0x18,
+0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+0x08, 0x06,
+ /* el */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0xb2, 0x01, 0x91, 0x01,
+0x13, 0x0b, 0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x17, 0x18,
+0x14, 0x0c, 0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+0x08, 0x06,
+ /* el-CY */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0xb2, 0x01, 0x91, 0x01,
+0x13, 0x0b, 0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x17, 0x18,
+0x14, 0x0c, 0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+0x08, 0x06,
+ /* el-polyton */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0xb2, 0x01, 0x91, 0x01,
+0x13, 0x0b, 0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x17, 0x18,
+0x14, 0x0c, 0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+0x08, 0x06,
+ /* en */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x19, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x17,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-001 */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-150 */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-AE */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x19, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x17,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-AG */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x17, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-AI */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x17, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-AS */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x19, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x17,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-AT */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-AU */
+0x0e, 0x17, 0x5d, 0x61, 0x00, 0x00, 0x01, 0x85, 0x01, 0x08, 0x06,
+ /* en-BB */
+0x0e, 0x14, 0x4e, 0x17, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b,
+0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-BE */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-BI */
+0x0e, 0x14, 0x79, 0x92, 0x01, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13,
+0x0b, 0x07, 0x03, 0x09, 0x05, 0x11, 0x19, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14,
+0x0c, 0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08,
+0x06,
+ /* en-BM */
+0x0e, 0x14, 0x1b, 0x17, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b,
+0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-BS */
+0x0e, 0x14, 0x0b, 0x08, 0x6a, 0x17, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b,
+0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-BW */
+0x0e, 0x14, 0x0b, 0x08, 0x8b, 0x01, 0xb3, 0x01, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11,
+0x13, 0x0b, 0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16,
+0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+0x08, 0x06,
+ /* en-BZ */
+0x0e, 0x14, 0x0b, 0x08, 0x1c, 0x17, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b,
+0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-CA */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x17, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x62, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-CC */
+0x0e, 0x17, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-CH */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-CK */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x17, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-CM */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-CX */
+0x0e, 0x17, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-CY */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-CZ */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-DE */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-DG */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-DK */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x4b, 0x77, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b,
+0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-DM */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x17, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-Dsrt */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x17,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-EE */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-ER */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x53, 0x65, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b,
+0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-ES */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-FI */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-FJ */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x19, 0x17, 0x06, 0x11, 0x13, 0x0b,
+0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-FK */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x28, 0x11, 0x06, 0x6b, 0x13, 0x0b,
+0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-FM */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-FR */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-GB */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-GD */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x17, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-GE */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x7b, 0x93, 0x01, 0x13,
+0x0b, 0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14,
+0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08,
+0x06,
+ /* en-GG */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-GH */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x54, 0x6a, 0x13, 0x0b,
+0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-GI */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x6b, 0x20, 0x11, 0x13, 0x0b,
+0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-GM */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x7c, 0x94, 0x01, 0x13,
+0x0b, 0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14,
+0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08,
+0x06,
+ /* en-GS */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-GU */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x19, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x17,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-GY */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0xaf, 0x01, 0x17, 0x13,
+0x0b, 0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14,
+0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08,
+0x06,
+ /* en-HK */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-HU */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-ID */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x61, 0x78,
+0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-IE */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-IL */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-IM */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-IN */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x17,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-IO */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-IT */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-JE */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-JM */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x6e, 0x17, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-JP */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x19, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x17,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-KE */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x47, 0x52, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-KI */
+0x0e, 0x17, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-KN */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x17, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-KY */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x9d, 0x01, 0x17, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14,
+0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08,
+0x06,
+ /* en-LC */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x17, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-LR */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x5a, 0x17, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-LS */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06, 0x48, 0x53,
+ /* en-LT */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-LV */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-MG */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x80, 0x01, 0x95, 0x01, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16,
+0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+0x08, 0x06,
+ /* en-MH */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x19, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x17,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-MO */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x6f, 0x86, 0x01, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14,
+0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08,
+0x06,
+ /* en-MP */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x19, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x17,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-MS */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x17, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-MT */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x6b, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-MU */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x81, 0x01, 0x61, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14,
+0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08,
+0x06,
+ /* en-MV */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x9f, 0x01, 0xd7, 0x03, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16,
+0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+0x08, 0x06,
+ /* en-MW */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0xa0, 0x01, 0xd8, 0x03, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16,
+0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+0x08, 0x06,
+ /* en-MY */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x55, 0x63, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-NA */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x1f, 0x17, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-NF */
+0x0e, 0x17, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-NG */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x39, 0x54, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-NL */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-NO */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x4f, 0x56, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-NR */
+0x0e, 0x17, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-NU */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x17, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-NZ */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x17, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-PG */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x50, 0x81, 0x01, 0x16, 0x16, 0x14,
+0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08,
+0x06,
+ /* en-PH */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x19, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x17,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-PK */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x64, 0x61, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-PL */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-PN */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x17, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-PR */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x19, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x17,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-PT */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-PW */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-RO */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-RW */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x95, 0x01, 0x96, 0x01,
+0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+0x08, 0x06,
+ /* en-SB */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x1a, 0x17, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-SC */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x5d, 0xb4, 0x01, 0x14,
+0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08,
+0x06,
+ /* en-SD */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-SE */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x5b, 0x56, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-SG */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x1d, 0x17, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-SH */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x6b, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0xa3, 0x01, 0x11, 0x14,
+0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08,
+0x06,
+ /* en-Shaw */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-SI */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-SK */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-SL */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x84, 0x01, 0x97, 0x01,
+0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+0x08, 0x06,
+ /* en-SS */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x6b, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x74, 0x11, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-SX */
+0x69, 0x98, 0x01, 0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13,
+0x0b, 0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14,
+0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08,
+0x06,
+ /* en-SZ */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x85, 0x01, 0x99, 0x01,
+0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+0x08, 0x06,
+ /* en-TC */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-TK */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x17, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-TO */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0xb3, 0x01, 0xb5, 0x01,
+0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+0x08, 0x06,
+ /* en-TT */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x21, 0x17, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-TV */
+0x0e, 0x17, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-TZ */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x49, 0x55,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-UA */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-UG */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x57, 0x66,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-UM */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x19, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x17,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-VC */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x17, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-VG */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-VI */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x19, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x17,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* en-VU */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0xb4, 0x01, 0xb6, 0x01, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+0x08, 0x06,
+ /* en-WS */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x29, 0xd9, 0x03, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08,
+0x06,
+ /* en-ZA */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06, 0x48, 0x53,
+ /* en-ZM */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06, 0xa5, 0x01,
+0x81, 0x01,
+ /* en-ZW */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* eo */
+0x02, 0x01, 0x08, 0x06,
+ /* es */
+0x35, 0x3b, 0x02, 0x01, 0x17, 0x18, 0x05, 0x15, 0x0a, 0x07, 0x00, 0x00, 0x01, 0x09, 0x08, 0x06,
+ /* es-419 */
+0x35, 0x3b, 0x00, 0x00, 0x01, 0x09, 0x08, 0x06,
+ /* es-AR */
+0x22, 0x17, 0x35, 0x3b, 0x05, 0x15, 0x00, 0x00, 0x01, 0x09, 0x08, 0x06,
+ /* es-BO */
+0x5f, 0xb7, 0x01, 0x35, 0x3b, 0x00, 0x00, 0x01, 0x09, 0x08, 0x06,
+ /* es-BR */
+0x0b, 0x08, 0x35, 0x3b, 0x00, 0x00, 0x01, 0x09, 0x08, 0x06,
+ /* es-BZ */
+0x1c, 0x17, 0x35, 0x3b, 0x00, 0x00, 0x01, 0x09, 0x08, 0x06,
+ /* es-CL */
+0x27, 0x17, 0x35, 0x3b, 0x05, 0x15, 0x00, 0x00, 0x01, 0x09, 0x08, 0x06,
+ /* es-CO */
+0x1e, 0x17, 0x35, 0x3b, 0x05, 0x15, 0x00, 0x00, 0x01, 0x09, 0x08, 0x06,
+ /* es-CR */
+0x99, 0x01, 0xda, 0x03, 0x35, 0x3b, 0x00, 0x00, 0x01, 0x09, 0x08, 0x06,
+ /* es-CU */
+0x9a, 0x01, 0x17, 0x35, 0x3b, 0x05, 0x15, 0x00, 0x00, 0x01, 0x09, 0x08, 0x06,
+ /* es-DO */
+0x6b, 0x87, 0x01, 0x35, 0x3b, 0x05, 0x15, 0x00, 0x00, 0x01, 0x09, 0x08, 0x06,
+ /* es-EA */
+0x35, 0x3b, 0x02, 0x01, 0x17, 0x18, 0x05, 0x15, 0x0a, 0x07, 0x00, 0x00, 0x01, 0x09, 0x08, 0x06,
+ /* es-EC */
+0x35, 0x3b, 0x05, 0x17, 0x00, 0x00, 0x01, 0x09, 0x08, 0x06,
+ /* es-GQ */
+0x35, 0x3b, 0x02, 0x01, 0x17, 0x18, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x00, 0x00, 0x01, 0x09,
+0x08, 0x06,
+ /* es-GT */
+0x35, 0x3b, 0x7d, 0xb8, 0x01, 0x00, 0x00, 0x01, 0x09, 0x08, 0x06,
+ /* es-HN */
+0x35, 0x3b, 0x9b, 0x01, 0x9a, 0x01, 0x00, 0x00, 0x01, 0x09, 0x08, 0x06,
+ /* es-IC */
+0x35, 0x3b, 0x02, 0x01, 0x17, 0x18, 0x05, 0x15, 0x0a, 0x07, 0x00, 0x00, 0x01, 0x09, 0x08, 0x06,
+ /* es-MX */
+0x35, 0x3b, 0xb5, 0x01, 0xdb, 0x03, 0x34, 0x88, 0x01, 0x0d, 0x17, 0x00, 0x00, 0x01, 0x09, 0x08,
+0x06,
+ /* es-NI */
+0x35, 0x3b, 0xa1, 0x01, 0x64, 0x00, 0x00, 0x01, 0x09, 0x08, 0x06,
+ /* es-PA */
+0x35, 0x3b, 0x91, 0x01, 0xb9, 0x01, 0x00, 0x00, 0x01, 0x09, 0x08, 0x06,
+ /* es-PE */
+0x35, 0x3b, 0x92, 0x01, 0xba, 0x01, 0x00, 0x00, 0x01, 0x09, 0x08, 0x06,
+ /* es-PH */
+0x35, 0x3b, 0x02, 0x01, 0x16, 0x16, 0x17, 0x18, 0x05, 0x15, 0x0a, 0x07, 0x00, 0x00, 0x01, 0x09,
+0x08, 0x06,
+ /* es-PR */
+0x35, 0x3b, 0x05, 0x17, 0x00, 0x00, 0x01, 0x09, 0x08, 0x06,
+ /* es-PY */
+0x35, 0x3b, 0x93, 0x01, 0xdc, 0x03, 0x00, 0x00, 0x01, 0x09, 0x08, 0x06,
+ /* es-SV */
+0x35, 0x3b, 0x05, 0x17, 0x00, 0x00, 0x01, 0x09, 0x08, 0x06,
+ /* es-US */
+0x35, 0x3b, 0x11, 0x19, 0x05, 0x17, 0x00, 0x00, 0x01, 0x09, 0x08, 0x06,
+ /* es-UY */
+0x35, 0x3b, 0x05, 0x15, 0x25, 0x17, 0xb9, 0x01, 0xdd, 0x03, 0x00, 0x00, 0x01, 0x09, 0x08, 0x06,
+ /* es-VE */
+0x35, 0x3b, 0xba, 0x01, 0xde, 0x03, 0x70, 0x89, 0x01, 0x00, 0x00, 0x01, 0x09, 0x08, 0x06,
+ /* et */
+0x0e, 0x1a, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0xa6, 0x01, 0x56, 0x02, 0x01, 0x06, 0x11, 0x13,
+0x0b, 0x07, 0x03, 0x09, 0x05, 0x11, 0x19, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x17, 0x18, 0x14,
+0x0c, 0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08,
+0x06,
+ /* eu */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x35, 0x3b, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b,
+0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x17, 0x18, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ewo */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* fa */
+0x51, 0x60, 0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x1b, 0x15, 0xbb, 0x01, 0x02, 0x01, 0x06, 0x11, 0x13,
+0xbc, 0x01, 0x07, 0x03, 0x09, 0x05, 0x31, 0x6c, 0x11, 0x19, 0x10, 0x0a, 0x0d, 0x1d, 0x0f, 0x1e,
+0x17, 0x18, 0x14, 0x0c, 0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x12, 0xbd, 0x01, 0x00, 0x00, 0x03,
+0xbe, 0x01, 0x01, 0x09, 0x08, 0x06,
+ /* fa-AF */
+0x51, 0x60, 0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x1b, 0x15, 0xbb, 0x01, 0x02, 0x01, 0x06, 0x11, 0x13,
+0xbc, 0x01, 0x07, 0x03, 0x09, 0x05, 0x31, 0x6c, 0x11, 0x19, 0x10, 0x0a, 0x0d, 0x1d, 0x0f, 0x1e,
+0x17, 0x18, 0x14, 0x0c, 0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x12, 0xbd, 0x01, 0x00, 0x00, 0x03,
+0xbe, 0x01, 0x01, 0x09, 0x08, 0x06,
+ /* ff */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ff-Adlm */
+0x52, 0x58, 0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x6c, 0x8a,
+0x01, 0x13, 0x0b, 0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x39, 0x5f, 0x0f,
+0x10, 0x50, 0x59, 0x16, 0x5a, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x5b, 0x12, 0x0d, 0x00,
+0x00, 0x03, 0x5c, 0x01, 0x09, 0x08, 0x06,
+ /* ff-Adlm-BF */
+0x52, 0x58, 0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b,
+0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x39, 0x5f, 0x0f, 0x10, 0x50, 0x59,
+0x16, 0x5a, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x5b, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x5c,
+0x01, 0x09, 0x08, 0x06,
+ /* ff-Adlm-CM */
+0x52, 0x58, 0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b,
+0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x39, 0x5f, 0x0f, 0x10, 0x50, 0x59,
+0x16, 0x5a, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x5b, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x5c,
+0x01, 0x09, 0x08, 0x06,
+ /* ff-Adlm-GH */
+0x52, 0x58, 0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x54, 0x6a,
+0x13, 0x0b, 0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x39, 0x5f, 0x0f, 0x10,
+0x50, 0x59, 0x16, 0x5a, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x5b, 0x12, 0x0d, 0x00, 0x00,
+0x03, 0x5c, 0x01, 0x09, 0x08, 0x06,
+ /* ff-Adlm-GM */
+0x52, 0x58, 0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x7c, 0x94,
+0x01, 0x13, 0x0b, 0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x39, 0x5f, 0x0f,
+0x10, 0x50, 0x59, 0x16, 0x5a, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x5b, 0x12, 0x0d, 0x00,
+0x00, 0x03, 0x5c, 0x01, 0x09, 0x08, 0x06,
+ /* ff-Adlm-GW */
+0x52, 0x58, 0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b,
+0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x39, 0x5f, 0x0f, 0x10, 0x50, 0x59,
+0x16, 0x5a, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x5b, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x5c,
+0x01, 0x09, 0x08, 0x06,
+ /* ff-Adlm-LR */
+0x52, 0x58, 0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b,
+0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x5a, 0x17, 0x0d, 0x0e, 0x39, 0x5f, 0x0f, 0x10,
+0x50, 0x59, 0x16, 0x5a, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x5b, 0x12, 0x0d, 0x00, 0x00,
+0x03, 0x5c, 0x01, 0x09, 0x08, 0x06,
+ /* ff-Adlm-MR */
+0x52, 0x58, 0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b,
+0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x34, 0x88, 0x01, 0x0d, 0x0e, 0x39, 0x5f, 0x0f,
+0x10, 0x50, 0x59, 0x16, 0x5a, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x5b, 0x12, 0x0d, 0x00,
+0x00, 0x03, 0x5c, 0x01, 0x09, 0x08, 0x06,
+ /* ff-Adlm-NE */
+0x52, 0x58, 0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b,
+0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x39, 0x5f, 0x0f, 0x10, 0x50, 0x59,
+0x16, 0x5a, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x5b, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x5c,
+0x01, 0x09, 0x08, 0x06,
+ /* ff-Adlm-NG */
+0x52, 0x58, 0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b,
+0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x39, 0x54, 0x0f, 0x10, 0x50, 0x59,
+0x16, 0x5a, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x5b, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x5c,
+0x01, 0x09, 0x08, 0x06,
+ /* ff-Adlm-SL */
+0x52, 0x58, 0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b,
+0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x39, 0x5f, 0x0f, 0x10, 0x50, 0x59,
+0x16, 0x5a, 0x84, 0x01, 0x97, 0x01, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x5b, 0x12, 0x0d,
+0x00, 0x00, 0x03, 0x5c, 0x01, 0x09, 0x08, 0x06,
+ /* ff-Adlm-SN */
+0x52, 0x58, 0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b,
+0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x39, 0x5f, 0x0f, 0x10, 0x50, 0x59,
+0x16, 0x5a, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x5b, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x5c,
+0x01, 0x09, 0x08, 0x06,
+ /* ff-Latn */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ff-Latn-BF */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ff-Latn-CM */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ff-Latn-GH */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x54, 0x6a, 0x13, 0x0b,
+0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ff-Latn-GM */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x7c, 0x94, 0x01, 0x13,
+0x0b, 0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14,
+0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08,
+0x06,
+ /* ff-Latn-GN */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x6c, 0x8a, 0x01, 0x13,
+0x0b, 0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14,
+0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08,
+0x06,
+ /* ff-Latn-GW */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ff-Latn-LR */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x5a, 0x17, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ff-Latn-MR */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x34, 0x88, 0x01, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14,
+0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08,
+0x06,
+ /* ff-Latn-NE */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ff-Latn-NG */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x39, 0x54, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ff-Latn-SL */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x84, 0x01, 0x97, 0x01,
+0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+0x08, 0x06,
+ /* fi */
+0x02, 0x01, 0xbb, 0x01, 0xdf, 0x03, 0x06, 0x11, 0x11, 0x19, 0x05, 0x17, 0x04, 0x02, 0x00, 0x00,
+0x03, 0x04,
+ /* fil */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x19, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x17, 0x18, 0x14, 0x0c,
+0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* fo */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x4b, 0x56, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b,
+0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* fo-DK */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x4b, 0x77, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b,
+0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* fr */
+0x22, 0x27, 0x0e, 0x28, 0x2d, 0x20, 0x1b, 0x29, 0x23, 0x2a, 0x0b, 0x08, 0x1c, 0x2b, 0x0c, 0x1b,
+0x27, 0x2c, 0x1e, 0x2d, 0x2e, 0x21, 0x02, 0x01, 0x19, 0x2e, 0x28, 0x2f, 0x2c, 0x1c, 0x06, 0x30,
+0x20, 0x31, 0x26, 0x22, 0x2a, 0x23, 0x07, 0x03, 0x09, 0x05, 0x2f, 0x24, 0x10, 0x0a, 0x18, 0x32,
+0x30, 0x25, 0x0d, 0x1d, 0x1f, 0x33, 0x0f, 0x1e, 0x2b, 0x26, 0x1a, 0x34, 0x1d, 0x35, 0x24, 0x36,
+0x21, 0x37, 0x05, 0x1f, 0x25, 0x38, 0x0a, 0x07, 0x29, 0x39, 0x04, 0x02, 0x00, 0x00, 0x03, 0x04,
+0x01, 0x3a, 0x08, 0x06,
+ /* fr-BE */
+0x22, 0x27, 0x0e, 0x28, 0x2d, 0x20, 0x1b, 0x29, 0x23, 0x2a, 0x0b, 0x08, 0x1c, 0x2b, 0x0c, 0x1b,
+0x27, 0x2c, 0x1e, 0x2d, 0x2e, 0x21, 0x02, 0x01, 0x19, 0x2e, 0x28, 0x2f, 0x2c, 0x1c, 0x06, 0x30,
+0x20, 0x31, 0x26, 0x22, 0x2a, 0x23, 0x07, 0x03, 0x09, 0x05, 0x2f, 0x24, 0x10, 0x0a, 0x18, 0x32,
+0x30, 0x25, 0x0d, 0x1d, 0x1f, 0x33, 0x0f, 0x1e, 0x2b, 0x26, 0x1a, 0x34, 0x1d, 0x35, 0x24, 0x36,
+0x21, 0x37, 0x05, 0x1f, 0x25, 0x38, 0x0a, 0x07, 0x29, 0x39, 0x04, 0x02, 0x00, 0x00, 0x03, 0x04,
+0x01, 0x3a, 0x08, 0x06,
+ /* fr-BF */
+0x22, 0x27, 0x0e, 0x28, 0x2d, 0x20, 0x1b, 0x29, 0x23, 0x2a, 0x0b, 0x08, 0x1c, 0x2b, 0x0c, 0x1b,
+0x27, 0x2c, 0x1e, 0x2d, 0x2e, 0x21, 0x02, 0x01, 0x19, 0x2e, 0x28, 0x2f, 0x2c, 0x1c, 0x06, 0x30,
+0x20, 0x31, 0x26, 0x22, 0x2a, 0x23, 0x07, 0x03, 0x09, 0x05, 0x2f, 0x24, 0x10, 0x0a, 0x18, 0x32,
+0x30, 0x25, 0x0d, 0x1d, 0x1f, 0x33, 0x0f, 0x1e, 0x2b, 0x26, 0x1a, 0x34, 0x1d, 0x35, 0x24, 0x36,
+0x21, 0x37, 0x05, 0x1f, 0x25, 0x38, 0x0a, 0x07, 0x29, 0x39, 0x04, 0x02, 0x00, 0x00, 0x03, 0x04,
+0x01, 0x3a, 0x08, 0x06,
+ /* fr-BI */
+0x22, 0x27, 0x0e, 0x28, 0x2d, 0x20, 0x79, 0x92, 0x01, 0x1b, 0x29, 0x23, 0x2a, 0x0b, 0x08, 0x1c,
+0x2b, 0x0c, 0x1b, 0x27, 0x2c, 0x1e, 0x2d, 0x2e, 0x21, 0x02, 0x01, 0x19, 0x2e, 0x28, 0x2f, 0x2c,
+0x1c, 0x06, 0x30, 0x20, 0x31, 0x26, 0x22, 0x2a, 0x23, 0x07, 0x03, 0x09, 0x05, 0x2f, 0x24, 0x10,
+0x0a, 0x18, 0x32, 0x30, 0x25, 0x0d, 0x1d, 0x1f, 0x33, 0x0f, 0x1e, 0x2b, 0x26, 0x1a, 0x34, 0x1d,
+0x35, 0x24, 0x36, 0x21, 0x37, 0x05, 0x1f, 0x25, 0x38, 0x0a, 0x07, 0x29, 0x39, 0x04, 0x02, 0x00,
+0x00, 0x03, 0x04, 0x01, 0x3a, 0x08, 0x06,
+ /* fr-BJ */
+0x22, 0x27, 0x0e, 0x28, 0x2d, 0x20, 0x1b, 0x29, 0x23, 0x2a, 0x0b, 0x08, 0x1c, 0x2b, 0x0c, 0x1b,
+0x27, 0x2c, 0x1e, 0x2d, 0x2e, 0x21, 0x02, 0x01, 0x19, 0x2e, 0x28, 0x2f, 0x2c, 0x1c, 0x06, 0x30,
+0x20, 0x31, 0x26, 0x22, 0x2a, 0x23, 0x07, 0x03, 0x09, 0x05, 0x2f, 0x24, 0x10, 0x0a, 0x18, 0x32,
+0x30, 0x25, 0x0d, 0x1d, 0x1f, 0x33, 0x0f, 0x1e, 0x2b, 0x26, 0x1a, 0x34, 0x1d, 0x35, 0x24, 0x36,
+0x21, 0x37, 0x05, 0x1f, 0x25, 0x38, 0x0a, 0x07, 0x29, 0x39, 0x04, 0x02, 0x00, 0x00, 0x03, 0x04,
+0x01, 0x3a, 0x08, 0x06,
+ /* fr-BL */
+0x22, 0x27, 0x0e, 0x28, 0x2d, 0x20, 0x1b, 0x29, 0x23, 0x2a, 0x0b, 0x08, 0x1c, 0x2b, 0x0c, 0x1b,
+0x27, 0x2c, 0x1e, 0x2d, 0x2e, 0x21, 0x02, 0x01, 0x19, 0x2e, 0x28, 0x2f, 0x2c, 0x1c, 0x06, 0x30,
+0x20, 0x31, 0x26, 0x22, 0x2a, 0x23, 0x07, 0x03, 0x09, 0x05, 0x2f, 0x24, 0x10, 0x0a, 0x18, 0x32,
+0x30, 0x25, 0x0d, 0x1d, 0x1f, 0x33, 0x0f, 0x1e, 0x2b, 0x26, 0x1a, 0x34, 0x1d, 0x35, 0x24, 0x36,
+0x21, 0x37, 0x05, 0x1f, 0x25, 0x38, 0x0a, 0x07, 0x29, 0x39, 0x04, 0x02, 0x00, 0x00, 0x03, 0x04,
+0x01, 0x3a, 0x08, 0x06,
+ /* fr-CA */
+0x0e, 0xe0, 0x03, 0x2d, 0x20, 0x0b, 0x08, 0x0c, 0x17, 0x15, 0x0f, 0x2e, 0x21, 0x02, 0x01, 0x2c,
+0x1c, 0x06, 0x11, 0x13, 0xe1, 0x03, 0x26, 0x22, 0x2a, 0x23, 0x2f, 0x24, 0x11, 0x19, 0x30, 0x25,
+0x0f, 0xe2, 0x03, 0x2b, 0x26, 0x1d, 0xe3, 0x03, 0x05, 0xe4, 0x03, 0x00, 0x00, 0x08, 0x06,
+ /* fr-CD */
+0x22, 0x27, 0x0e, 0x28, 0x2d, 0x20, 0x1b, 0x29, 0x23, 0x2a, 0x0b, 0x08, 0x1c, 0x2b, 0x0c, 0x1b,
+0x59, 0x71, 0x27, 0x2c, 0x1e, 0x2d, 0x2e, 0x21, 0x02, 0x01, 0x19, 0x2e, 0x28, 0x2f, 0x2c, 0x1c,
+0x06, 0x30, 0x20, 0x31, 0x26, 0x22, 0x2a, 0x23, 0x07, 0x03, 0x09, 0x05, 0x2f, 0x24, 0x10, 0x0a,
+0x18, 0x32, 0x30, 0x25, 0x0d, 0x1d, 0x1f, 0x33, 0x0f, 0x1e, 0x2b, 0x26, 0x1a, 0x34, 0x1d, 0x35,
+0x24, 0x36, 0x21, 0x37, 0x05, 0x1f, 0x25, 0x38, 0x0a, 0x07, 0x29, 0x39, 0x04, 0x02, 0x00, 0x00,
+0x03, 0x04, 0x01, 0x3a, 0x08, 0x06,
+ /* fr-CF */
+0x22, 0x27, 0x0e, 0x28, 0x2d, 0x20, 0x1b, 0x29, 0x23, 0x2a, 0x0b, 0x08, 0x1c, 0x2b, 0x0c, 0x1b,
+0x27, 0x2c, 0x1e, 0x2d, 0x2e, 0x21, 0x02, 0x01, 0x19, 0x2e, 0x28, 0x2f, 0x2c, 0x1c, 0x06, 0x30,
+0x20, 0x31, 0x26, 0x22, 0x2a, 0x23, 0x07, 0x03, 0x09, 0x05, 0x2f, 0x24, 0x10, 0x0a, 0x18, 0x32,
+0x30, 0x25, 0x0d, 0x1d, 0x1f, 0x33, 0x0f, 0x1e, 0x2b, 0x26, 0x1a, 0x34, 0x1d, 0x35, 0x24, 0x36,
+0x21, 0x37, 0x05, 0x1f, 0x25, 0x38, 0x0a, 0x07, 0x29, 0x39, 0x04, 0x02, 0x00, 0x00, 0x03, 0x04,
+0x01, 0x3a, 0x08, 0x06,
+ /* fr-CG */
+0x22, 0x27, 0x0e, 0x28, 0x2d, 0x20, 0x1b, 0x29, 0x23, 0x2a, 0x0b, 0x08, 0x1c, 0x2b, 0x0c, 0x1b,
+0x27, 0x2c, 0x1e, 0x2d, 0x2e, 0x21, 0x02, 0x01, 0x19, 0x2e, 0x28, 0x2f, 0x2c, 0x1c, 0x06, 0x30,
+0x20, 0x31, 0x26, 0x22, 0x2a, 0x23, 0x07, 0x03, 0x09, 0x05, 0x2f, 0x24, 0x10, 0x0a, 0x18, 0x32,
+0x30, 0x25, 0x0d, 0x1d, 0x1f, 0x33, 0x0f, 0x1e, 0x2b, 0x26, 0x1a, 0x34, 0x1d, 0x35, 0x24, 0x36,
+0x21, 0x37, 0x05, 0x1f, 0x25, 0x38, 0x0a, 0x07, 0x29, 0x39, 0x04, 0x02, 0x00, 0x00, 0x03, 0x04,
+0x01, 0x3a, 0x08, 0x06,
+ /* fr-CH */
+0x22, 0x27, 0x0e, 0x28, 0x2d, 0x20, 0x1b, 0x29, 0x23, 0x2a, 0x0b, 0x08, 0x1c, 0x2b, 0x0c, 0x1b,
+0x27, 0x2c, 0x1e, 0x2d, 0x2e, 0x21, 0x02, 0x01, 0x19, 0x2e, 0x28, 0x2f, 0x2c, 0x1c, 0x06, 0x30,
+0x20, 0x31, 0x26, 0x22, 0x2a, 0x23, 0x07, 0x03, 0x09, 0x05, 0x2f, 0x24, 0x10, 0x0a, 0x18, 0x32,
+0x30, 0x25, 0x0d, 0x1d, 0x1f, 0x33, 0x0f, 0x1e, 0x2b, 0x26, 0x1a, 0x34, 0x1d, 0x35, 0x24, 0x36,
+0x21, 0x37, 0x05, 0x1f, 0x25, 0x38, 0x0a, 0x07, 0x29, 0x39, 0x04, 0x02, 0x00, 0x00, 0x03, 0x04,
+0x01, 0x3a, 0x08, 0x06,
+ /* fr-CI */
+0x22, 0x27, 0x0e, 0x28, 0x2d, 0x20, 0x1b, 0x29, 0x23, 0x2a, 0x0b, 0x08, 0x1c, 0x2b, 0x0c, 0x1b,
+0x27, 0x2c, 0x1e, 0x2d, 0x2e, 0x21, 0x02, 0x01, 0x19, 0x2e, 0x28, 0x2f, 0x2c, 0x1c, 0x06, 0x30,
+0x20, 0x31, 0x26, 0x22, 0x2a, 0x23, 0x07, 0x03, 0x09, 0x05, 0x2f, 0x24, 0x10, 0x0a, 0x18, 0x32,
+0x30, 0x25, 0x0d, 0x1d, 0x1f, 0x33, 0x0f, 0x1e, 0x2b, 0x26, 0x1a, 0x34, 0x1d, 0x35, 0x24, 0x36,
+0x21, 0x37, 0x05, 0x1f, 0x25, 0x38, 0x0a, 0x07, 0x29, 0x39, 0x04, 0x02, 0x00, 0x00, 0x03, 0x04,
+0x01, 0x3a, 0x08, 0x06,
+ /* fr-CM */
+0x22, 0x27, 0x0e, 0x28, 0x2d, 0x20, 0x1b, 0x29, 0x23, 0x2a, 0x0b, 0x08, 0x1c, 0x2b, 0x0c, 0x1b,
+0x27, 0x2c, 0x1e, 0x2d, 0x2e, 0x21, 0x02, 0x01, 0x19, 0x2e, 0x28, 0x2f, 0x2c, 0x1c, 0x06, 0x30,
+0x20, 0x31, 0x26, 0x22, 0x2a, 0x23, 0x07, 0x03, 0x09, 0x05, 0x2f, 0x24, 0x10, 0x0a, 0x18, 0x32,
+0x30, 0x25, 0x0d, 0x1d, 0x1f, 0x33, 0x0f, 0x1e, 0x2b, 0x26, 0x1a, 0x34, 0x1d, 0x35, 0x24, 0x36,
+0x21, 0x37, 0x05, 0x1f, 0x25, 0x38, 0x0a, 0x07, 0x29, 0x39, 0x04, 0x02, 0x00, 0x00, 0x03, 0x04,
+0x01, 0x3a, 0x08, 0x06,
+ /* fr-DJ */
+0x22, 0x27, 0x0e, 0x28, 0x2d, 0x20, 0x1b, 0x29, 0x23, 0x2a, 0x0b, 0x08, 0x1c, 0x2b, 0x0c, 0x1b,
+0x27, 0x2c, 0x1e, 0x2d, 0x2e, 0x21, 0x68, 0x80, 0x01, 0x02, 0x01, 0x19, 0x2e, 0x28, 0x2f, 0x2c,
+0x1c, 0x06, 0x30, 0x20, 0x31, 0x26, 0x22, 0x2a, 0x23, 0x07, 0x03, 0x09, 0x05, 0x2f, 0x24, 0x10,
+0x0a, 0x18, 0x32, 0x30, 0x25, 0x0d, 0x1d, 0x1f, 0x33, 0x0f, 0x1e, 0x2b, 0x26, 0x1a, 0x34, 0x1d,
+0x35, 0x24, 0x36, 0x21, 0x37, 0x05, 0x1f, 0x25, 0x38, 0x0a, 0x07, 0x29, 0x39, 0x04, 0x02, 0x00,
+0x00, 0x03, 0x04, 0x01, 0x3a, 0x08, 0x06,
+ /* fr-DZ */
+0x22, 0x27, 0x0e, 0x28, 0x2d, 0x20, 0x1b, 0x29, 0x23, 0x2a, 0x0b, 0x08, 0x1c, 0x2b, 0x0c, 0x1b,
+0x27, 0x2c, 0x1e, 0x2d, 0x2e, 0x21, 0x37, 0xbf, 0x01, 0x02, 0x01, 0x19, 0x2e, 0x28, 0x2f, 0x2c,
+0x1c, 0x06, 0x30, 0x20, 0x31, 0x26, 0x22, 0x2a, 0x23, 0x07, 0x03, 0x09, 0x05, 0x2f, 0x24, 0x10,
+0x0a, 0x18, 0x32, 0x30, 0x25, 0x0d, 0x1d, 0x1f, 0x33, 0x0f, 0x1e, 0x2b, 0x26, 0x1a, 0x34, 0x1d,
+0x35, 0x24, 0x36, 0x21, 0x37, 0x05, 0x1f, 0x25, 0x38, 0x0a, 0x07, 0x29, 0x39, 0x04, 0x02, 0x00,
+0x00, 0x03, 0x04, 0x01, 0x3a, 0x08, 0x06,
+ /* fr-GA */
+0x22, 0x27, 0x0e, 0x28, 0x2d, 0x20, 0x1b, 0x29, 0x23, 0x2a, 0x0b, 0x08, 0x1c, 0x2b, 0x0c, 0x1b,
+0x27, 0x2c, 0x1e, 0x2d, 0x2e, 0x21, 0x02, 0x01, 0x19, 0x2e, 0x28, 0x2f, 0x2c, 0x1c, 0x06, 0x30,
+0x20, 0x31, 0x26, 0x22, 0x2a, 0x23, 0x07, 0x03, 0x09, 0x05, 0x2f, 0x24, 0x10, 0x0a, 0x18, 0x32,
+0x30, 0x25, 0x0d, 0x1d, 0x1f, 0x33, 0x0f, 0x1e, 0x2b, 0x26, 0x1a, 0x34, 0x1d, 0x35, 0x24, 0x36,
+0x21, 0x37, 0x05, 0x1f, 0x25, 0x38, 0x0a, 0x07, 0x29, 0x39, 0x04, 0x02, 0x00, 0x00, 0x03, 0x04,
+0x01, 0x3a, 0x08, 0x06,
+ /* fr-GF */
+0x22, 0x27, 0x0e, 0x28, 0x2d, 0x20, 0x1b, 0x29, 0x23, 0x2a, 0x0b, 0x08, 0x1c, 0x2b, 0x0c, 0x1b,
+0x27, 0x2c, 0x1e, 0x2d, 0x2e, 0x21, 0x02, 0x01, 0x19, 0x2e, 0x28, 0x2f, 0x2c, 0x1c, 0x06, 0x30,
+0x20, 0x31, 0x26, 0x22, 0x2a, 0x23, 0x07, 0x03, 0x09, 0x05, 0x2f, 0x24, 0x10, 0x0a, 0x18, 0x32,
+0x30, 0x25, 0x0d, 0x1d, 0x1f, 0x33, 0x0f, 0x1e, 0x2b, 0x26, 0x1a, 0x34, 0x1d, 0x35, 0x24, 0x36,
+0x21, 0x37, 0x05, 0x1f, 0x25, 0x38, 0x0a, 0x07, 0x29, 0x39, 0x04, 0x02, 0x00, 0x00, 0x03, 0x04,
+0x01, 0x3a, 0x08, 0x06,
+ /* fr-GN */
+0x22, 0x27, 0x0e, 0x28, 0x2d, 0x20, 0x1b, 0x29, 0x23, 0x2a, 0x0b, 0x08, 0x1c, 0x2b, 0x0c, 0x1b,
+0x27, 0x2c, 0x1e, 0x2d, 0x2e, 0x21, 0x02, 0x01, 0x19, 0x2e, 0x28, 0x2f, 0x2c, 0x1c, 0x06, 0x30,
+0x20, 0x31, 0x6c, 0x8a, 0x01, 0x26, 0x22, 0x2a, 0x23, 0x07, 0x03, 0x09, 0x05, 0x2f, 0x24, 0x10,
+0x0a, 0x18, 0x32, 0x30, 0x25, 0x0d, 0x1d, 0x1f, 0x33, 0x0f, 0x1e, 0x2b, 0x26, 0x1a, 0x34, 0x1d,
+0x35, 0x24, 0x36, 0x21, 0x37, 0x05, 0x1f, 0x25, 0x38, 0x0a, 0x07, 0x29, 0x39, 0x04, 0x02, 0x00,
+0x00, 0x03, 0x04, 0x01, 0x3a, 0x08, 0x06,
+ /* fr-GP */
+0x22, 0x27, 0x0e, 0x28, 0x2d, 0x20, 0x1b, 0x29, 0x23, 0x2a, 0x0b, 0x08, 0x1c, 0x2b, 0x0c, 0x1b,
+0x27, 0x2c, 0x1e, 0x2d, 0x2e, 0x21, 0x02, 0x01, 0x19, 0x2e, 0x28, 0x2f, 0x2c, 0x1c, 0x06, 0x30,
+0x20, 0x31, 0x26, 0x22, 0x2a, 0x23, 0x07, 0x03, 0x09, 0x05, 0x2f, 0x24, 0x10, 0x0a, 0x18, 0x32,
+0x30, 0x25, 0x0d, 0x1d, 0x1f, 0x33, 0x0f, 0x1e, 0x2b, 0x26, 0x1a, 0x34, 0x1d, 0x35, 0x24, 0x36,
+0x21, 0x37, 0x05, 0x1f, 0x25, 0x38, 0x0a, 0x07, 0x29, 0x39, 0x04, 0x02, 0x00, 0x00, 0x03, 0x04,
+0x01, 0x3a, 0x08, 0x06,
+ /* fr-GQ */
+0x22, 0x27, 0x0e, 0x28, 0x2d, 0x20, 0x1b, 0x29, 0x23, 0x2a, 0x0b, 0x08, 0x1c, 0x2b, 0x0c, 0x1b,
+0x27, 0x2c, 0x1e, 0x2d, 0x2e, 0x21, 0x02, 0x01, 0x19, 0x2e, 0x28, 0x2f, 0x2c, 0x1c, 0x06, 0x30,
+0x20, 0x31, 0x26, 0x22, 0x2a, 0x23, 0x07, 0x03, 0x09, 0x05, 0x2f, 0x24, 0x10, 0x0a, 0x18, 0x32,
+0x30, 0x25, 0x0d, 0x1d, 0x1f, 0x33, 0x0f, 0x1e, 0x2b, 0x26, 0x1a, 0x34, 0x1d, 0x35, 0x24, 0x36,
+0x21, 0x37, 0x05, 0x1f, 0x25, 0x38, 0x0a, 0x07, 0x29, 0x39, 0x04, 0x02, 0x00, 0x00, 0x03, 0x04,
+0x01, 0x3a, 0x08, 0x06,
+ /* fr-HT */
+0x22, 0x27, 0x0e, 0x28, 0x2d, 0x20, 0x1b, 0x29, 0x23, 0x2a, 0x0b, 0x08, 0x1c, 0x2b, 0x0c, 0x1b,
+0x27, 0x2c, 0x1e, 0x2d, 0x2e, 0x21, 0x02, 0x01, 0x19, 0x2e, 0x28, 0x2f, 0x2c, 0x1c, 0x06, 0x30,
+0x20, 0x31, 0x7e, 0x9b, 0x01, 0x26, 0x22, 0x2a, 0x23, 0x07, 0x03, 0x09, 0x05, 0x2f, 0x24, 0x10,
+0x0a, 0x18, 0x32, 0x30, 0x25, 0x0d, 0x1d, 0x1f, 0x33, 0x0f, 0x1e, 0x2b, 0x26, 0x1a, 0x34, 0x1d,
+0x35, 0x24, 0x36, 0x21, 0x37, 0x05, 0x1f, 0x25, 0x38, 0x0a, 0x07, 0x29, 0x39, 0x04, 0x02, 0x00,
+0x00, 0x03, 0x04, 0x01, 0x3a, 0x08, 0x06,
+ /* fr-KM */
+0x22, 0x27, 0x0e, 0x28, 0x2d, 0x20, 0x1b, 0x29, 0x23, 0x2a, 0x0b, 0x08, 0x1c, 0x2b, 0x0c, 0x1b,
+0x27, 0x2c, 0x1e, 0x2d, 0x2e, 0x21, 0x02, 0x01, 0x19, 0x2e, 0x28, 0x2f, 0x2c, 0x1c, 0x06, 0x30,
+0x20, 0x31, 0x26, 0x22, 0x2a, 0x23, 0x07, 0x03, 0x09, 0x05, 0x2f, 0x24, 0x88, 0x01, 0xb1, 0x01,
+0x10, 0x0a, 0x18, 0x32, 0x30, 0x25, 0x0d, 0x1d, 0x1f, 0x33, 0x0f, 0x1e, 0x2b, 0x26, 0x1a, 0x34,
+0x1d, 0x35, 0x24, 0x36, 0x21, 0x37, 0x05, 0x1f, 0x25, 0x38, 0x0a, 0x07, 0x29, 0x39, 0x04, 0x02,
+0x00, 0x00, 0x03, 0x04, 0x01, 0x3a, 0x08, 0x06,
+ /* fr-LU */
+0x22, 0x27, 0x0e, 0x28, 0x2d, 0x20, 0x1b, 0x29, 0x23, 0x2a, 0x0b, 0x08, 0x1c, 0x2b, 0x0c, 0x1b,
+0x27, 0x2c, 0x1e, 0x2d, 0x2e, 0x21, 0x02, 0x01, 0x19, 0x2e, 0x28, 0x2f, 0x06, 0x30, 0x20, 0x31,
+0x26, 0x22, 0x2a, 0x23, 0x07, 0x03, 0x09, 0x05, 0x2f, 0x24, 0x10, 0x0a, 0x18, 0x32, 0xb1, 0x01,
+0x1c, 0x30, 0x25, 0x0d, 0x1d, 0x1f, 0x33, 0x0f, 0x1e, 0x2b, 0x26, 0x1a, 0x34, 0x1d, 0x35, 0x24,
+0x36, 0x21, 0x37, 0x05, 0x1f, 0x25, 0x38, 0x0a, 0x07, 0x29, 0x39, 0x04, 0x02, 0x00, 0x00, 0x03,
+0x04, 0x01, 0x3a, 0x08, 0x06,
+ /* fr-MA */
+0x22, 0x27, 0x0e, 0x28, 0x2d, 0x20, 0x1b, 0x29, 0x23, 0x2a, 0x0b, 0x08, 0x1c, 0x2b, 0x0c, 0x1b,
+0x27, 0x2c, 0x1e, 0x2d, 0x2e, 0x21, 0x02, 0x01, 0x19, 0x2e, 0x28, 0x2f, 0x2c, 0x1c, 0x06, 0x30,
+0x20, 0x31, 0x26, 0x22, 0x2a, 0x23, 0x07, 0x03, 0x09, 0x05, 0x2f, 0x24, 0x10, 0x0a, 0x18, 0x32,
+0x30, 0x25, 0x0d, 0x1d, 0x1f, 0x33, 0x0f, 0x1e, 0x2b, 0x26, 0x1a, 0x34, 0x1d, 0x35, 0x24, 0x36,
+0x21, 0x37, 0x05, 0x1f, 0x25, 0x38, 0x0a, 0x07, 0x29, 0x39, 0x04, 0x02, 0x00, 0x00, 0x03, 0x04,
+0x01, 0x3a, 0x08, 0x06,
+ /* fr-MC */
+0x22, 0x27, 0x0e, 0x28, 0x2d, 0x20, 0x1b, 0x29, 0x23, 0x2a, 0x0b, 0x08, 0x1c, 0x2b, 0x0c, 0x1b,
+0x27, 0x2c, 0x1e, 0x2d, 0x2e, 0x21, 0x02, 0x01, 0x19, 0x2e, 0x28, 0x2f, 0x2c, 0x1c, 0x06, 0x30,
+0x20, 0x31, 0x26, 0x22, 0x2a, 0x23, 0x07, 0x03, 0x09, 0x05, 0x2f, 0x24, 0x10, 0x0a, 0x18, 0x32,
+0x30, 0x25, 0x0d, 0x1d, 0x1f, 0x33, 0x0f, 0x1e, 0x2b, 0x26, 0x1a, 0x34, 0x1d, 0x35, 0x24, 0x36,
+0x21, 0x37, 0x05, 0x1f, 0x25, 0x38, 0x0a, 0x07, 0x29, 0x39, 0x04, 0x02, 0x00, 0x00, 0x03, 0x04,
+0x01, 0x3a, 0x08, 0x06,
+ /* fr-MF */
+0x22, 0x27, 0x0e, 0x28, 0x2d, 0x20, 0x1b, 0x29, 0x23, 0x2a, 0x0b, 0x08, 0x1c, 0x2b, 0x0c, 0x1b,
+0x27, 0x2c, 0x1e, 0x2d, 0x2e, 0x21, 0x02, 0x01, 0x19, 0x2e, 0x28, 0x2f, 0x2c, 0x1c, 0x06, 0x30,
+0x20, 0x31, 0x26, 0x22, 0x2a, 0x23, 0x07, 0x03, 0x09, 0x05, 0x2f, 0x24, 0x10, 0x0a, 0x18, 0x32,
+0x30, 0x25, 0x0d, 0x1d, 0x1f, 0x33, 0x0f, 0x1e, 0x2b, 0x26, 0x1a, 0x34, 0x1d, 0x35, 0x24, 0x36,
+0x21, 0x37, 0x05, 0x1f, 0x25, 0x38, 0x0a, 0x07, 0x29, 0x39, 0x04, 0x02, 0x00, 0x00, 0x03, 0x04,
+0x01, 0x3a, 0x08, 0x06,
+ /* fr-MG */
+0x22, 0x27, 0x0e, 0x28, 0x2d, 0x20, 0x1b, 0x29, 0x23, 0x2a, 0x0b, 0x08, 0x1c, 0x2b, 0x0c, 0x1b,
+0x27, 0x2c, 0x1e, 0x2d, 0x2e, 0x21, 0x02, 0x01, 0x19, 0x2e, 0x28, 0x2f, 0x2c, 0x1c, 0x06, 0x30,
+0x20, 0x31, 0x26, 0x22, 0x2a, 0x23, 0x07, 0x03, 0x09, 0x05, 0x2f, 0x24, 0x10, 0x0a, 0x18, 0x32,
+0x80, 0x01, 0x95, 0x01, 0x30, 0x25, 0x0d, 0x1d, 0x1f, 0x33, 0x0f, 0x1e, 0x2b, 0x26, 0x1a, 0x34,
+0x1d, 0x35, 0x24, 0x36, 0x21, 0x37, 0x05, 0x1f, 0x25, 0x38, 0x0a, 0x07, 0x29, 0x39, 0x04, 0x02,
+0x00, 0x00, 0x03, 0x04, 0x01, 0x3a, 0x08, 0x06,
+ /* fr-ML */
+0x22, 0x27, 0x0e, 0x28, 0x2d, 0x20, 0x1b, 0x29, 0x23, 0x2a, 0x0b, 0x08, 0x1c, 0x2b, 0x0c, 0x1b,
+0x27, 0x2c, 0x1e, 0x2d, 0x2e, 0x21, 0x02, 0x01, 0x19, 0x2e, 0x28, 0x2f, 0x2c, 0x1c, 0x06, 0x30,
+0x20, 0x31, 0x26, 0x22, 0x2a, 0x23, 0x07, 0x03, 0x09, 0x05, 0x2f, 0x24, 0x10, 0x0a, 0x18, 0x32,
+0x30, 0x25, 0x0d, 0x1d, 0x1f, 0x33, 0x0f, 0x1e, 0x2b, 0x26, 0x1a, 0x34, 0x1d, 0x35, 0x24, 0x36,
+0x21, 0x37, 0x05, 0x1f, 0x25, 0x38, 0x0a, 0x07, 0x29, 0x39, 0x04, 0x02, 0x00, 0x00, 0x03, 0x04,
+0x01, 0x3a, 0x08, 0x06,
+ /* fr-MQ */
+0x22, 0x27, 0x0e, 0x28, 0x2d, 0x20, 0x1b, 0x29, 0x23, 0x2a, 0x0b, 0x08, 0x1c, 0x2b, 0x0c, 0x1b,
+0x27, 0x2c, 0x1e, 0x2d, 0x2e, 0x21, 0x02, 0x01, 0x19, 0x2e, 0x28, 0x2f, 0x2c, 0x1c, 0x06, 0x30,
+0x20, 0x31, 0x26, 0x22, 0x2a, 0x23, 0x07, 0x03, 0x09, 0x05, 0x2f, 0x24, 0x10, 0x0a, 0x18, 0x32,
+0x30, 0x25, 0x0d, 0x1d, 0x1f, 0x33, 0x0f, 0x1e, 0x2b, 0x26, 0x1a, 0x34, 0x1d, 0x35, 0x24, 0x36,
+0x21, 0x37, 0x05, 0x1f, 0x25, 0x38, 0x0a, 0x07, 0x29, 0x39, 0x04, 0x02, 0x00, 0x00, 0x03, 0x04,
+0x01, 0x3a, 0x08, 0x06,
+ /* fr-MR */
+0x22, 0x27, 0x0e, 0x28, 0x2d, 0x20, 0x1b, 0x29, 0x23, 0x2a, 0x0b, 0x08, 0x1c, 0x2b, 0x0c, 0x1b,
+0x27, 0x2c, 0x1e, 0x2d, 0x2e, 0x21, 0x02, 0x01, 0x19, 0x2e, 0x28, 0x2f, 0x2c, 0x1c, 0x06, 0x30,
+0x20, 0x31, 0x26, 0x22, 0x2a, 0x23, 0x07, 0x03, 0x09, 0x05, 0x2f, 0x24, 0x10, 0x0a, 0x18, 0x32,
+0x34, 0x88, 0x01, 0x30, 0x25, 0x0d, 0x1d, 0x1f, 0x33, 0x0f, 0x1e, 0x2b, 0x26, 0x1a, 0x34, 0x1d,
+0x35, 0x24, 0x36, 0x21, 0x37, 0x05, 0x1f, 0x25, 0x38, 0x0a, 0x07, 0x29, 0x39, 0x04, 0x02, 0x00,
+0x00, 0x03, 0x04, 0x01, 0x3a, 0x08, 0x06,
+ /* fr-MU */
+0x22, 0x27, 0x0e, 0x28, 0x2d, 0x20, 0x1b, 0x29, 0x23, 0x2a, 0x0b, 0x08, 0x1c, 0x2b, 0x0c, 0x1b,
+0x27, 0x2c, 0x1e, 0x2d, 0x2e, 0x21, 0x02, 0x01, 0x19, 0x2e, 0x28, 0x2f, 0x2c, 0x1c, 0x06, 0x30,
+0x20, 0x31, 0x26, 0x22, 0x2a, 0x23, 0x07, 0x03, 0x09, 0x05, 0x2f, 0x24, 0x10, 0x0a, 0x18, 0x32,
+0x30, 0x25, 0x81, 0x01, 0x61, 0x0d, 0x1d, 0x1f, 0x33, 0x0f, 0x1e, 0x2b, 0x26, 0x1a, 0x34, 0x1d,
+0x35, 0x24, 0x36, 0x21, 0x37, 0x05, 0x1f, 0x25, 0x38, 0x0a, 0x07, 0x29, 0x39, 0x04, 0x02, 0x00,
+0x00, 0x03, 0x04, 0x01, 0x3a, 0x08, 0x06,
+ /* fr-NC */
+0x22, 0x27, 0x0e, 0x28, 0x2d, 0x20, 0x1b, 0x29, 0x23, 0x2a, 0x0b, 0x08, 0x1c, 0x2b, 0x0c, 0x1b,
+0x27, 0x2c, 0x1e, 0x2d, 0x2e, 0x21, 0x02, 0x01, 0x19, 0x2e, 0x28, 0x2f, 0x2c, 0x1c, 0x06, 0x30,
+0x20, 0x31, 0x26, 0x22, 0x2a, 0x23, 0x07, 0x03, 0x09, 0x05, 0x2f, 0x24, 0x10, 0x0a, 0x18, 0x32,
+0x30, 0x25, 0x0d, 0x1d, 0x1f, 0x33, 0x0f, 0x1e, 0x2b, 0x26, 0x1a, 0x34, 0x1d, 0x35, 0x24, 0x36,
+0x21, 0x37, 0x05, 0x1f, 0x25, 0x38, 0x0a, 0x07, 0x29, 0x39, 0x04, 0x02, 0x00, 0x00, 0x03, 0x04,
+0x01, 0x3a, 0x08, 0x06,
+ /* fr-NE */
+0x22, 0x27, 0x0e, 0x28, 0x2d, 0x20, 0x1b, 0x29, 0x23, 0x2a, 0x0b, 0x08, 0x1c, 0x2b, 0x0c, 0x1b,
+0x27, 0x2c, 0x1e, 0x2d, 0x2e, 0x21, 0x02, 0x01, 0x19, 0x2e, 0x28, 0x2f, 0x2c, 0x1c, 0x06, 0x30,
+0x20, 0x31, 0x26, 0x22, 0x2a, 0x23, 0x07, 0x03, 0x09, 0x05, 0x2f, 0x24, 0x10, 0x0a, 0x18, 0x32,
+0x30, 0x25, 0x0d, 0x1d, 0x1f, 0x33, 0x0f, 0x1e, 0x2b, 0x26, 0x1a, 0x34, 0x1d, 0x35, 0x24, 0x36,
+0x21, 0x37, 0x05, 0x1f, 0x25, 0x38, 0x0a, 0x07, 0x29, 0x39, 0x04, 0x02, 0x00, 0x00, 0x03, 0x04,
+0x01, 0x3a, 0x08, 0x06,
+ /* fr-PF */
+0x22, 0x27, 0x0e, 0x28, 0x2d, 0x20, 0x1b, 0x29, 0x23, 0x2a, 0x0b, 0x08, 0x1c, 0x2b, 0x0c, 0x1b,
+0x27, 0x2c, 0x1e, 0x2d, 0x2e, 0x21, 0x02, 0x01, 0x19, 0x2e, 0x28, 0x2f, 0x2c, 0x1c, 0x06, 0x30,
+0x20, 0x31, 0x26, 0x22, 0x2a, 0x23, 0x07, 0x03, 0x09, 0x05, 0x2f, 0x24, 0x10, 0x0a, 0x18, 0x32,
+0x30, 0x25, 0x0d, 0x1d, 0x1f, 0x33, 0x0f, 0x1e, 0x2b, 0x26, 0x1a, 0x34, 0x1d, 0x35, 0x24, 0x36,
+0x21, 0x37, 0x05, 0x1f, 0x25, 0x38, 0x0a, 0x07, 0x29, 0x39, 0x04, 0x02, 0x00, 0x00, 0x03, 0x04,
+0x01, 0x3a, 0x08, 0x06,
+ /* fr-PM */
+0x22, 0x27, 0x0e, 0x28, 0x2d, 0x20, 0x1b, 0x29, 0x23, 0x2a, 0x0b, 0x08, 0x1c, 0x2b, 0x0c, 0x1b,
+0x27, 0x2c, 0x1e, 0x2d, 0x2e, 0x21, 0x02, 0x01, 0x19, 0x2e, 0x28, 0x2f, 0x2c, 0x1c, 0x06, 0x30,
+0x20, 0x31, 0x26, 0x22, 0x2a, 0x23, 0x07, 0x03, 0x09, 0x05, 0x2f, 0x24, 0x10, 0x0a, 0x18, 0x32,
+0x30, 0x25, 0x0d, 0x1d, 0x1f, 0x33, 0x0f, 0x1e, 0x2b, 0x26, 0x1a, 0x34, 0x1d, 0x35, 0x24, 0x36,
+0x21, 0x37, 0x05, 0x1f, 0x25, 0x38, 0x0a, 0x07, 0x29, 0x39, 0x04, 0x02, 0x00, 0x00, 0x03, 0x04,
+0x01, 0x3a, 0x08, 0x06,
+ /* fr-RE */
+0x22, 0x27, 0x0e, 0x28, 0x2d, 0x20, 0x1b, 0x29, 0x23, 0x2a, 0x0b, 0x08, 0x1c, 0x2b, 0x0c, 0x1b,
+0x27, 0x2c, 0x1e, 0x2d, 0x2e, 0x21, 0x02, 0x01, 0x19, 0x2e, 0x28, 0x2f, 0x2c, 0x1c, 0x06, 0x30,
+0x20, 0x31, 0x26, 0x22, 0x2a, 0x23, 0x07, 0x03, 0x09, 0x05, 0x2f, 0x24, 0x10, 0x0a, 0x18, 0x32,
+0x30, 0x25, 0x0d, 0x1d, 0x1f, 0x33, 0x0f, 0x1e, 0x2b, 0x26, 0x1a, 0x34, 0x1d, 0x35, 0x24, 0x36,
+0x21, 0x37, 0x05, 0x1f, 0x25, 0x38, 0x0a, 0x07, 0x29, 0x39, 0x04, 0x02, 0x00, 0x00, 0x03, 0x04,
+0x01, 0x3a, 0x08, 0x06,
+ /* fr-RW */
+0x22, 0x27, 0x0e, 0x28, 0x2d, 0x20, 0x1b, 0x29, 0x23, 0x2a, 0x0b, 0x08, 0x1c, 0x2b, 0x0c, 0x1b,
+0x27, 0x2c, 0x1e, 0x2d, 0x2e, 0x21, 0x02, 0x01, 0x19, 0x2e, 0x28, 0x2f, 0x2c, 0x1c, 0x06, 0x30,
+0x20, 0x31, 0x26, 0x22, 0x2a, 0x23, 0x07, 0x03, 0x09, 0x05, 0x2f, 0x24, 0x10, 0x0a, 0x18, 0x32,
+0x30, 0x25, 0x0d, 0x1d, 0x1f, 0x33, 0x0f, 0x1e, 0x2b, 0x26, 0x95, 0x01, 0x96, 0x01, 0x1a, 0x34,
+0x1d, 0x35, 0x24, 0x36, 0x21, 0x37, 0x05, 0x1f, 0x25, 0x38, 0x0a, 0x07, 0x29, 0x39, 0x04, 0x02,
+0x00, 0x00, 0x03, 0x04, 0x01, 0x3a, 0x08, 0x06,
+ /* fr-SC */
+0x22, 0x27, 0x0e, 0x28, 0x2d, 0x20, 0x1b, 0x29, 0x23, 0x2a, 0x0b, 0x08, 0x1c, 0x2b, 0x0c, 0x1b,
+0x27, 0x2c, 0x1e, 0x2d, 0x2e, 0x21, 0x02, 0x01, 0x19, 0x2e, 0x28, 0x2f, 0x2c, 0x1c, 0x06, 0x30,
+0x20, 0x31, 0x26, 0x22, 0x2a, 0x23, 0x07, 0x03, 0x09, 0x05, 0x2f, 0x24, 0x10, 0x0a, 0x18, 0x32,
+0x30, 0x25, 0x0d, 0x1d, 0x1f, 0x33, 0x0f, 0x1e, 0x2b, 0x26, 0x1a, 0x34, 0x5d, 0xb4, 0x01, 0x1d,
+0x35, 0x24, 0x36, 0x21, 0x37, 0x05, 0x1f, 0x25, 0x38, 0x0a, 0x07, 0x29, 0x39, 0x04, 0x02, 0x00,
+0x00, 0x03, 0x04, 0x01, 0x3a, 0x08, 0x06,
+ /* fr-SN */
+0x22, 0x27, 0x0e, 0x28, 0x2d, 0x20, 0x1b, 0x29, 0x23, 0x2a, 0x0b, 0x08, 0x1c, 0x2b, 0x0c, 0x1b,
+0x27, 0x2c, 0x1e, 0x2d, 0x2e, 0x21, 0x02, 0x01, 0x19, 0x2e, 0x28, 0x2f, 0x2c, 0x1c, 0x06, 0x30,
+0x20, 0x31, 0x26, 0x22, 0x2a, 0x23, 0x07, 0x03, 0x09, 0x05, 0x2f, 0x24, 0x10, 0x0a, 0x18, 0x32,
+0x30, 0x25, 0x0d, 0x1d, 0x1f, 0x33, 0x0f, 0x1e, 0x2b, 0x26, 0x1a, 0x34, 0x1d, 0x35, 0x24, 0x36,
+0x21, 0x37, 0x05, 0x1f, 0x25, 0x38, 0x0a, 0x07, 0x29, 0x39, 0x04, 0x02, 0x00, 0x00, 0x03, 0x04,
+0x01, 0x3a, 0x08, 0x06,
+ /* fr-SY */
+0x22, 0x27, 0x0e, 0x28, 0x2d, 0x20, 0x1b, 0x29, 0x23, 0x2a, 0x0b, 0x08, 0x1c, 0x2b, 0x0c, 0x1b,
+0x27, 0x2c, 0x1e, 0x2d, 0x2e, 0x21, 0x02, 0x01, 0x19, 0x2e, 0x28, 0x2f, 0x2c, 0x1c, 0x06, 0x30,
+0x20, 0x31, 0x26, 0x22, 0x2a, 0x23, 0x07, 0x03, 0x09, 0x05, 0x2f, 0x24, 0x10, 0x0a, 0x18, 0x32,
+0x30, 0x25, 0x0d, 0x1d, 0x1f, 0x33, 0x0f, 0x1e, 0x2b, 0x26, 0x1a, 0x34, 0x1d, 0x35, 0x24, 0x36,
+0x36, 0xe5, 0x03, 0x21, 0x37, 0x05, 0x1f, 0x25, 0x38, 0x0a, 0x07, 0x29, 0x39, 0x04, 0x02, 0x00,
+0x00, 0x03, 0x04, 0x01, 0x3a, 0x08, 0x06,
+ /* fr-TD */
+0x22, 0x27, 0x0e, 0x28, 0x2d, 0x20, 0x1b, 0x29, 0x23, 0x2a, 0x0b, 0x08, 0x1c, 0x2b, 0x0c, 0x1b,
+0x27, 0x2c, 0x1e, 0x2d, 0x2e, 0x21, 0x02, 0x01, 0x19, 0x2e, 0x28, 0x2f, 0x2c, 0x1c, 0x06, 0x30,
+0x20, 0x31, 0x26, 0x22, 0x2a, 0x23, 0x07, 0x03, 0x09, 0x05, 0x2f, 0x24, 0x10, 0x0a, 0x18, 0x32,
+0x30, 0x25, 0x0d, 0x1d, 0x1f, 0x33, 0x0f, 0x1e, 0x2b, 0x26, 0x1a, 0x34, 0x1d, 0x35, 0x24, 0x36,
+0x21, 0x37, 0x05, 0x1f, 0x25, 0x38, 0x0a, 0x07, 0x29, 0x39, 0x04, 0x02, 0x00, 0x00, 0x03, 0x04,
+0x01, 0x3a, 0x08, 0x06,
+ /* fr-TG */
+0x22, 0x27, 0x0e, 0x28, 0x2d, 0x20, 0x1b, 0x29, 0x23, 0x2a, 0x0b, 0x08, 0x1c, 0x2b, 0x0c, 0x1b,
+0x27, 0x2c, 0x1e, 0x2d, 0x2e, 0x21, 0x02, 0x01, 0x19, 0x2e, 0x28, 0x2f, 0x2c, 0x1c, 0x06, 0x30,
+0x20, 0x31, 0x26, 0x22, 0x2a, 0x23, 0x07, 0x03, 0x09, 0x05, 0x2f, 0x24, 0x10, 0x0a, 0x18, 0x32,
+0x30, 0x25, 0x0d, 0x1d, 0x1f, 0x33, 0x0f, 0x1e, 0x2b, 0x26, 0x1a, 0x34, 0x1d, 0x35, 0x24, 0x36,
+0x21, 0x37, 0x05, 0x1f, 0x25, 0x38, 0x0a, 0x07, 0x29, 0x39, 0x04, 0x02, 0x00, 0x00, 0x03, 0x04,
+0x01, 0x3a, 0x08, 0x06,
+ /* fr-TN */
+0x22, 0x27, 0x0e, 0x28, 0x2d, 0x20, 0x1b, 0x29, 0x23, 0x2a, 0x0b, 0x08, 0x1c, 0x2b, 0x0c, 0x1b,
+0x27, 0x2c, 0x1e, 0x2d, 0x2e, 0x21, 0x02, 0x01, 0x19, 0x2e, 0x28, 0x2f, 0x2c, 0x1c, 0x06, 0x30,
+0x20, 0x31, 0x26, 0x22, 0x2a, 0x23, 0x07, 0x03, 0x09, 0x05, 0x2f, 0x24, 0x10, 0x0a, 0x18, 0x32,
+0x30, 0x25, 0x0d, 0x1d, 0x1f, 0x33, 0x0f, 0x1e, 0x2b, 0x26, 0x1a, 0x34, 0x1d, 0x35, 0x24, 0x36,
+0x38, 0xe6, 0x03, 0x21, 0x37, 0x05, 0x1f, 0x25, 0x38, 0x0a, 0x07, 0x29, 0x39, 0x04, 0x02, 0x00,
+0x00, 0x03, 0x04, 0x01, 0x3a, 0x08, 0x06,
+ /* fr-VU */
+0x22, 0x27, 0x0e, 0x28, 0x2d, 0x20, 0x1b, 0x29, 0x23, 0x2a, 0x0b, 0x08, 0x1c, 0x2b, 0x0c, 0x1b,
+0x27, 0x2c, 0x1e, 0x2d, 0x2e, 0x21, 0x02, 0x01, 0x19, 0x2e, 0x28, 0x2f, 0x2c, 0x1c, 0x06, 0x30,
+0x20, 0x31, 0x26, 0x22, 0x2a, 0x23, 0x07, 0x03, 0x09, 0x05, 0x2f, 0x24, 0x10, 0x0a, 0x18, 0x32,
+0x30, 0x25, 0x0d, 0x1d, 0x1f, 0x33, 0x0f, 0x1e, 0x2b, 0x26, 0x1a, 0x34, 0x1d, 0x35, 0x24, 0x36,
+0x21, 0x37, 0x05, 0x1f, 0x25, 0x38, 0x0a, 0x07, 0xb4, 0x01, 0xb6, 0x01, 0x29, 0x39, 0x04, 0x02,
+0x00, 0x00, 0x03, 0x04, 0x01, 0x3a, 0x08, 0x06,
+ /* fr-WF */
+0x22, 0x27, 0x0e, 0x28, 0x2d, 0x20, 0x1b, 0x29, 0x23, 0x2a, 0x0b, 0x08, 0x1c, 0x2b, 0x0c, 0x1b,
+0x27, 0x2c, 0x1e, 0x2d, 0x2e, 0x21, 0x02, 0x01, 0x19, 0x2e, 0x28, 0x2f, 0x2c, 0x1c, 0x06, 0x30,
+0x20, 0x31, 0x26, 0x22, 0x2a, 0x23, 0x07, 0x03, 0x09, 0x05, 0x2f, 0x24, 0x10, 0x0a, 0x18, 0x32,
+0x30, 0x25, 0x0d, 0x1d, 0x1f, 0x33, 0x0f, 0x1e, 0x2b, 0x26, 0x1a, 0x34, 0x1d, 0x35, 0x24, 0x36,
+0x21, 0x37, 0x05, 0x1f, 0x25, 0x38, 0x0a, 0x07, 0x29, 0x39, 0x04, 0x02, 0x00, 0x00, 0x03, 0x04,
+0x01, 0x3a, 0x08, 0x06,
+ /* fr-YT */
+0x22, 0x27, 0x0e, 0x28, 0x2d, 0x20, 0x1b, 0x29, 0x23, 0x2a, 0x0b, 0x08, 0x1c, 0x2b, 0x0c, 0x1b,
+0x27, 0x2c, 0x1e, 0x2d, 0x2e, 0x21, 0x02, 0x01, 0x19, 0x2e, 0x28, 0x2f, 0x2c, 0x1c, 0x06, 0x30,
+0x20, 0x31, 0x26, 0x22, 0x2a, 0x23, 0x07, 0x03, 0x09, 0x05, 0x2f, 0x24, 0x10, 0x0a, 0x18, 0x32,
+0x30, 0x25, 0x0d, 0x1d, 0x1f, 0x33, 0x0f, 0x1e, 0x2b, 0x26, 0x1a, 0x34, 0x1d, 0x35, 0x24, 0x36,
+0x21, 0x37, 0x05, 0x1f, 0x25, 0x38, 0x0a, 0x07, 0x29, 0x39, 0x04, 0x02, 0x00, 0x00, 0x03, 0x04,
+0x01, 0x3a, 0x08, 0x06,
+ /* frr */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* fur */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* fy */
+0x0e, 0x1a, 0x0b, 0x08, 0x0c, 0x64, 0x15, 0x0f, 0x02, 0x01, 0x19, 0x67, 0x06, 0x11, 0x13, 0x0b,
+0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x1a, 0x68,
+0x17, 0x18, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04,
+0x08, 0x06,
+ /* ga */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x19, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x17, 0x18, 0x14, 0x0c,
+0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+ /* ga-GB */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x19, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x17, 0x18, 0x14, 0x0c,
+0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+ /* gaa */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* gd */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x17, 0x18, 0x14, 0x0c, 0x05, 0x17,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+ /* gez */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* gez-ER */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x53, 0x65, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b,
+0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* gl */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x35, 0x3b, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b,
+0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x1d, 0x0f, 0x10, 0x17, 0x18, 0x14, 0x0c,
+0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x00, 0xc0, 0x01, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* gn */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x93, 0x01, 0xe7, 0x03,
+0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+0x08, 0x06,
+ /* gsw */
+0x58, 0x5e, 0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b,
+0x07, 0x03, 0x09, 0x05, 0x11, 0x19, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* gsw-FR */
+0x58, 0x5e, 0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b,
+0x07, 0x03, 0x09, 0x05, 0x11, 0x19, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* gsw-LI */
+0x58, 0x5e, 0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b,
+0x07, 0x03, 0x09, 0x05, 0x11, 0x19, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* gu */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x17, 0x18, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* guz */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x47, 0x52, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* gv */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ha */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x19, 0x10, 0x0a, 0x0d, 0x0e, 0x39, 0x54, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ha-Arab */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x39, 0x54, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ha-Arab-SD */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x39, 0x54, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ha-GH */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x54, 0x6a, 0x13, 0x0b,
+0x07, 0x03, 0x09, 0x05, 0x11, 0x19, 0x10, 0x0a, 0x0d, 0x0e, 0x39, 0x54, 0x0f, 0x10, 0x16, 0x16,
+0x14, 0x0c, 0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+0x08, 0x06,
+ /* ha-NE */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x19, 0x10, 0x0a, 0x0d, 0x0e, 0x39, 0x54, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* haw */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x17,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* he */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0xe8, 0x03, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x2a,
+0xe9, 0x03, 0x07, 0x03, 0x09, 0x05, 0x11, 0x19, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x17, 0x18,
+0x14, 0x0c, 0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+0x08, 0x06,
+ /* hi */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x17, 0x18, 0x14, 0x0c, 0x05, 0x17,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* hi-Latn */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x17,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* hnj */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x8b,
+0x01, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* hnj-Hmnp */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x8b,
+0x01, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* hr */
+0x02, 0x01, 0x60, 0x83, 0x01, 0x04, 0x02, 0x00, 0x00, 0x03, 0x04,
+ /* hr-BA */
+0x4a, 0x6d, 0x02, 0x01, 0x60, 0x83, 0x01, 0x04, 0x02, 0x00, 0x00, 0x03, 0x04,
+ /* hsb */
+0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03, 0x09, 0x05,
+0x11, 0x19, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x65, 0x84, 0x01, 0x17, 0x18, 0x14,
+0x0c, 0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08,
+0x06,
+ /* ht */
+0x22, 0x27, 0x0e, 0x28, 0x2d, 0x20, 0x1b, 0x29, 0x23, 0x2a, 0x0b, 0x08, 0x1c, 0x2b, 0x0c, 0x1b,
+0x27, 0x2c, 0x1e, 0x2d, 0x2e, 0x21, 0x02, 0x01, 0x19, 0x2e, 0x28, 0x2f, 0x2c, 0x1c, 0x06, 0x30,
+0x20, 0x31, 0x7e, 0x9b, 0x01, 0x26, 0x22, 0x2a, 0x23, 0x07, 0x03, 0x09, 0x05, 0x2f, 0x24, 0x10,
+0x0a, 0x18, 0x32, 0x30, 0x25, 0x0d, 0x1d, 0x1f, 0x33, 0x0f, 0x1e, 0x2b, 0x26, 0x1a, 0x34, 0x1d,
+0x35, 0x24, 0x36, 0x21, 0x37, 0x05, 0x1f, 0x25, 0x38, 0x0a, 0x07, 0x29, 0x39, 0x04, 0x02, 0x00,
+0x00, 0x03, 0x04, 0x01, 0x3a, 0x08, 0x06,
+ /* hu */
+0x9c, 0x01, 0xea, 0x03, 0x11, 0x19, 0x04, 0x02, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* hy */
+0x96, 0x01, 0xeb, 0x03, 0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11,
+0x13, 0x0b, 0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x17, 0x18,
+0x14, 0x0c, 0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+0x08, 0x06,
+ /* ia */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0xbc, 0x01, 0xc0, 0x01, 0x0f, 0x10, 0x16, 0x16,
+0x46, 0x51, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04,
+0x01, 0x09, 0x08, 0x06,
+ /* id */
+0x0e, 0x1a, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x61, 0x78,
+0x07, 0x03, 0x09, 0x61, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x17, 0x18, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+ /* ie */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ig */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x19, 0x10, 0x0a, 0x0d, 0x0e, 0x39, 0x54, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ii */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x19, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* io */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* is */
+0x15, 0x0f, 0x13, 0x0b, 0x07, 0x03, 0x6d, 0x77, 0x11, 0x13, 0x04, 0x02, 0x12, 0x0d, 0x03, 0x04,
+0x01, 0x09, 0x08, 0x06,
+ /* it */
+0x0e, 0x14, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x07, 0x03, 0x0f, 0x10, 0x16, 0x16,
+0x17, 0x18, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x7e, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* it-CH */
+0x0e, 0x14, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x07, 0x03, 0x0f, 0x10, 0x16, 0x16,
+0x17, 0x18, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x7e, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* it-SM */
+0x0e, 0x14, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x07, 0x03, 0x0f, 0x10, 0x16, 0x16,
+0x17, 0x18, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x7e, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* it-VA */
+0x0e, 0x14, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x07, 0x03, 0x0f, 0x10, 0x16, 0x16,
+0x17, 0x18, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x7e, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* iu */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* iu-Latn */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ja */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0xc1, 0x01, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07,
+0x03, 0x09, 0x05, 0x11, 0x9c, 0x01, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x14, 0x0c, 0x05, 0x17,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x62, 0x03, 0x04, 0x01, 0x09,
+ /* ja-JP */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0xc1, 0x01, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07,
+0x03, 0x09, 0x05, 0x11, 0x9c, 0x01, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x14, 0x0c, 0x05, 0x17,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x62, 0x03, 0x04, 0x01, 0x09,
+ /* jbo */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* jgo */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* jmc */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x49, 0x55,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* jv */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x61, 0x78,
+0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ka */
+0x0b, 0x08, 0x0c, 0x12, 0x02, 0x01, 0x06, 0x11, 0x7b, 0x93, 0x01, 0x0d, 0x0e, 0x14, 0x0c, 0x05,
+0x15, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* kaa */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* kaa-Cyrl */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* kaa-Latn */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* kab */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x37, 0xbf, 0x01, 0x02, 0x01, 0x06, 0x11, 0x13,
+0x0b, 0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14,
+0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08,
+0x06,
+ /* kaj */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x39, 0x54, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* kam */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x47, 0x52, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* kcg */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x39, 0x54, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* kde */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x49, 0x55,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* kea */
+0x0e, 0x1a, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x8c, 0x01, 0x5d, 0x02, 0x01, 0x06, 0x11, 0x13,
+0x0b, 0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x17,
+0x18, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01,
+0x09, 0x08, 0x06,
+ /* kek */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ken */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* kgp */
+0x0e, 0x1a, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x19, 0xec, 0x03, 0x06, 0x11, 0x13,
+0x0b, 0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x4c, 0xed, 0x03,
+0x17, 0x18, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x8c,
+0x01, 0x01, 0x09, 0x08, 0x06, 0xb6, 0x01, 0xee, 0x03,
+ /* khq */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ki */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x47, 0x52, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* kk */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x62, 0x7f, 0x63, 0x9d, 0x01, 0x0d, 0x0e, 0x0f, 0x10, 0x46,
+0x51, 0x17, 0x18, 0x14, 0x0c, 0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03,
+0x04, 0x01, 0x09, 0x08, 0x06,
+ /* kk-Arab */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x62, 0x7f, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* kk-Cyrl */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x62, 0x7f, 0x63, 0x9d, 0x01, 0x0d, 0x0e, 0x0f, 0x10, 0x46,
+0x51, 0x17, 0x18, 0x14, 0x0c, 0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03,
+0x04, 0x01, 0x09, 0x08, 0x06,
+ /* kk-KZ */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x62, 0x7f, 0x63, 0x9d, 0x01, 0x0d, 0x0e, 0x0f, 0x10, 0x46,
+0x51, 0x17, 0x18, 0x14, 0x0c, 0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03,
+0x04, 0x01, 0x09, 0x08, 0x06,
+ /* kkj */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* kl */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x4b, 0x77, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b,
+0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* kln */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x47, 0x52, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* km */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0xaa, 0x01, 0xef, 0x03, 0x10, 0x0a, 0x63, 0xf0, 0x03, 0x0d, 0x0e, 0x0f,
+0x10, 0x17, 0x18, 0x14, 0x0c, 0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03,
+0x04, 0x01, 0x09, 0x08, 0x06,
+ /* kn */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x17, 0x18, 0x14, 0x0c, 0x05, 0x17,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ko */
+0x0e, 0x1a, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07,
+0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ko-CN */
+0x0e, 0x1a, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07,
+0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ko-KP */
+0x0e, 0x1a, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07,
+0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ko-KR */
+0x0e, 0x1a, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07,
+0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* kok */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x94, 0x01, 0xc2, 0x01, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* kok-Deva */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x94, 0x01, 0xc2, 0x01, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* kok-Latn */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* kpe */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x5a, 0x17, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* kpe-GN */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x6c, 0x8a, 0x01, 0x13,
+0x0b, 0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14,
+0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08,
+0x06,
+ /* ks */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x19, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x17,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ks-Arab */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x19, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x17,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ks-Deva */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x17,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ksb */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x49, 0x55,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ksf */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ksh */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ku */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x56, 0x72, 0x14, 0x0c,
+0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ku-Arab */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ku-Arab-IR */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ku-Latn */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x56, 0x72, 0x14, 0x0c,
+0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ku-Latn-IQ */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x56, 0x72, 0x14, 0x0c,
+0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ku-Latn-SY */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x56, 0x72, 0x14, 0x0c,
+0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ku-TR */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x56, 0x72, 0x14, 0x0c,
+0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* kw */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* kxv */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* kxv-Deva */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* kxv-Latn */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* kxv-Orya */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* kxv-Telu */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ky */
+0x15, 0x0f, 0x02, 0x01, 0x11, 0x13, 0x8e, 0x01, 0xc3, 0x01, 0x17, 0x18, 0x0a, 0x07, 0x04, 0x02,
+0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* la */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* lag */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x49, 0x55,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* lb */
+0x58, 0x5e, 0x0e, 0x1a, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b,
+0x07, 0x03, 0x09, 0x05, 0x11, 0x19, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x17, 0x18, 0x14, 0x0c,
+0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* lg */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x57, 0x66,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* lij */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* lkt */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x17,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* lld */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* lmo */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ln */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x59, 0x71, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b,
+0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ln-AO */
+0x89, 0x01, 0xc4, 0x01, 0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x59, 0x71, 0x15, 0x0f, 0x02, 0x01,
+0x06, 0x11, 0x13, 0x0b, 0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10,
+0x16, 0x16, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04,
+0x01, 0x09, 0x08, 0x06,
+ /* ln-CF */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x59, 0x71, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b,
+0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ln-CG */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x59, 0x71, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b,
+0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* lo */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0xac, 0x01, 0xf1, 0x03, 0x0d, 0x0e, 0x0f, 0x10, 0x17, 0x18,
+0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+0x08, 0x06,
+ /* lrc */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x32, 0x3c, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* lrc-IQ */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x32, 0x3c, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* lt */
+0x02, 0x01, 0x00, 0x00, 0x08, 0x06,
+ /* ltg */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* lu */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x59, 0x71, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b,
+0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* luo */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x47, 0x52, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* luy */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x47, 0x52, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* lv */
+0x0e, 0x1a, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x19, 0x10, 0x0a, 0xbd, 0x01, 0xf2, 0x03, 0x0d, 0x0e, 0x0f, 0x10, 0x17, 0x18,
+0x14, 0x0c, 0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+0x08, 0x06,
+ /* lzz */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* mai */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x17,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* mas */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x47, 0x52, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* mas-TZ */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x47, 0x52, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x49, 0x55, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+0x08, 0x06,
+ /* mdf */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x46, 0x51, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* mer */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x47, 0x52, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* mfe */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x81, 0x01, 0x61, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14,
+0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08,
+0x06,
+ /* mg */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x80, 0x01, 0x95, 0x01, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16,
+0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+0x08, 0x06,
+ /* mgh */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x82, 0x01, 0x9e, 0x01, 0x0f, 0x10, 0x16, 0x16,
+0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+0x08, 0x06,
+ /* mgo */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* mhn */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* mi */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x19, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x17, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* mic */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* mk */
+0x0b, 0x08, 0x0c, 0x12, 0x02, 0x01, 0x8f, 0x01, 0xf3, 0x03, 0x0d, 0x0e, 0x05, 0x15, 0x04, 0x02,
+0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ml */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x19, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x17, 0x18, 0x14, 0x0c, 0x05, 0x17,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* mn */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x90, 0x01, 0xc5, 0x01, 0x0d, 0x0e, 0x0f, 0x10, 0x17, 0x18,
+0x14, 0x0c, 0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+0x08, 0x06,
+ /* mn-Mong */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x17,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* mn-Mong-MN */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x90, 0x01, 0xc5, 0x01, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16,
+0x14, 0x0c, 0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+0x08, 0x06,
+ /* mni */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x17,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* mni-Beng */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x17,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* mni-Mtei */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* moh */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* mr */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x17, 0x18, 0x14, 0x0c, 0x05, 0x17,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ms */
+0x0e, 0x14, 0x0b, 0x08, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03, 0x09, 0x05,
+0x11, 0x13, 0x10, 0x0a, 0x55, 0x63, 0x0f, 0x10, 0x14, 0x0c, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d,
+0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ms-Arab */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x55, 0x63, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ms-Arab-BN */
+0x0e, 0x14, 0x23, 0x17, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b,
+0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x55, 0x63, 0x0f, 0x10, 0x16, 0x16,
+0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+0x08, 0x06,
+ /* ms-BN */
+0x0e, 0x14, 0x23, 0x17, 0x0b, 0x08, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x55, 0x63, 0x0f, 0x10, 0x14, 0x0c, 0x0a, 0x07, 0x04, 0x02,
+0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ms-ID */
+0x0e, 0x14, 0x0b, 0x08, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x61, 0x78, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x55, 0x63, 0x0f, 0x10, 0x14, 0x0c, 0x0a, 0x07, 0x04, 0x02,
+0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ms-SG */
+0x0e, 0x14, 0x0b, 0x08, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03, 0x09, 0x05,
+0x11, 0x13, 0x10, 0x0a, 0x55, 0x63, 0x0f, 0x10, 0x1d, 0x17, 0x14, 0x0c, 0x0a, 0x07, 0x04, 0x02,
+0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* mt */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07,
+0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* mua */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* mus */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x17,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* mww */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x8b,
+0x01, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* mww-Hmnp */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x8b,
+0x01, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* my */
+0x69, 0xf4, 0x03, 0x0e, 0x14, 0x8a, 0x01, 0xf5, 0x03, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02,
+0x01, 0x06, 0x11, 0x13, 0x0b, 0x7e, 0x9b, 0x01, 0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a,
+0xad, 0x01, 0x81, 0x01, 0x0d, 0x0e, 0x0f, 0x10, 0x91, 0x01, 0xb9, 0x01, 0x16, 0x16, 0x17, 0x18,
+0x21, 0xf6, 0x03, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03,
+0x04, 0x01, 0x09, 0x08, 0x06,
+ /* myv */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* mzn */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x14, 0x0c, 0x05, 0x17, 0x0a, 0x07,
+0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* naq */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x1f, 0x17, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* nb */
+0x02, 0x01, 0x06, 0x11, 0x4f, 0x56, 0x00, 0x00, 0x03, 0x04,
+ /* nb-SJ */
+0x02, 0x01, 0x06, 0x11, 0x4f, 0x56, 0x00, 0x00, 0x03, 0x04,
+ /* nd */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* nds */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* nds-NL */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ne */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0xa2, 0x01, 0xc6, 0x01, 0x0f, 0x10, 0x17, 0x18,
+0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+0x08, 0x06,
+ /* ne-IN */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0xa2, 0x01, 0xc6, 0x01, 0x0f, 0x10, 0x17, 0x18,
+0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+0x08, 0x06,
+ /* nl */
+0x0e, 0x1a, 0x0b, 0x08, 0x0c, 0x64, 0x15, 0x0f, 0x02, 0x01, 0x19, 0x67, 0x06, 0x11, 0x13, 0x0b,
+0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x1a, 0x68, 0x17, 0x18,
+0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x67, 0x73,
+ /* nl-AW */
+0x0e, 0x1a, 0x8a, 0x01, 0xf7, 0x03, 0x0b, 0x08, 0x0c, 0x64, 0x15, 0x0f, 0x02, 0x01, 0x19, 0x67,
+0x06, 0x11, 0x13, 0x0b, 0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10,
+0x1a, 0x68, 0x17, 0x18, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00,
+0x03, 0x04, 0x67, 0x73,
+ /* nl-BE */
+0x0e, 0x1a, 0x0b, 0x08, 0x0c, 0x64, 0x15, 0x0f, 0x02, 0x01, 0x19, 0x67, 0x06, 0x11, 0x13, 0x0b,
+0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x1a, 0x68, 0x17, 0x18,
+0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x67, 0x73,
+ /* nl-BQ */
+0x0e, 0x1a, 0x0b, 0x08, 0x0c, 0x64, 0x15, 0x0f, 0x02, 0x01, 0x19, 0x67, 0x06, 0x11, 0x13, 0x0b,
+0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x1a, 0x68, 0x17, 0x18,
+0x14, 0x0c, 0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x67, 0x73,
+ /* nl-CW */
+0x69, 0x98, 0x01, 0x0e, 0x1a, 0x0b, 0x08, 0x0c, 0x64, 0x15, 0x0f, 0x02, 0x01, 0x19, 0x67, 0x06,
+0x11, 0x13, 0x0b, 0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x1a,
+0x68, 0x17, 0x18, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03,
+0x04, 0x67, 0x73,
+ /* nl-SR */
+0x0e, 0x1a, 0x0b, 0x08, 0x0c, 0x64, 0x15, 0x0f, 0x02, 0x01, 0x19, 0x67, 0x06, 0x11, 0x13, 0x0b,
+0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x1a, 0x68, 0x24, 0x17,
+0x17, 0x18, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04,
+0x67, 0x73,
+ /* nl-SX */
+0x69, 0x98, 0x01, 0x0e, 0x1a, 0x0b, 0x08, 0x0c, 0x64, 0x15, 0x0f, 0x02, 0x01, 0x19, 0x67, 0x06,
+0x11, 0x13, 0x0b, 0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x1a,
+0x68, 0x17, 0x18, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03,
+0x04, 0x67, 0x73,
+ /* nmg */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* nn */
+0x02, 0x01, 0x4f, 0x56, 0x00, 0x00, 0x03, 0x04,
+ /* nnh */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* no */
+0x02, 0x01, 0x06, 0x11, 0x4f, 0x56, 0x00, 0x00, 0x03, 0x04,
+ /* nqo */
+0x3d, 0xf8, 0x03, 0x51, 0xf9, 0x03, 0x77, 0xfa, 0x03, 0x96, 0x01, 0xfb, 0x03, 0x69, 0xfc, 0x03,
+0x89, 0x01, 0xfd, 0x03, 0xbe, 0x01, 0xfe, 0x03, 0xbf, 0x01, 0xff, 0x03, 0x22, 0x80, 0x04, 0x0e,
+0x81, 0x04, 0x8a, 0x01, 0x82, 0x04, 0x75, 0x83, 0x04, 0x4a, 0x84, 0x04, 0x4e, 0x85, 0x04, 0x78,
+0x86, 0x04, 0x97, 0x01, 0x87, 0x04, 0x3e, 0x88, 0x04, 0x79, 0x89, 0x04, 0x1b, 0x8a, 0x04, 0x23,
+0x8b, 0x04, 0x5f, 0x8c, 0x04, 0x0b, 0x08, 0x6a, 0x8d, 0x04, 0xa7, 0x01, 0x8e, 0x04, 0x8b, 0x01,
+0x8f, 0x04, 0x7a, 0x90, 0x04, 0x0c, 0x12, 0x59, 0x91, 0x04, 0xa8, 0x01, 0x92, 0x04, 0x27, 0x93,
+0x04, 0x98, 0x01, 0x94, 0x04, 0x15, 0x95, 0x04, 0x1e, 0x96, 0x04, 0x99, 0x01, 0x97, 0x04, 0xa9,
+0x01, 0x98, 0x04, 0x9a, 0x01, 0x99, 0x04, 0x8c, 0x01, 0x9a, 0x04, 0x8d, 0x01, 0x9b, 0x04, 0x68,
+0x9c, 0x04, 0x4b, 0x9d, 0x04, 0x6b, 0x9e, 0x04, 0x37, 0x9f, 0x04, 0x33, 0xa0, 0x04, 0x53, 0xa1,
+0x04, 0x4d, 0xa2, 0x04, 0x02, 0x01, 0x19, 0xa3, 0x04, 0x28, 0xa4, 0x04, 0x06, 0x11, 0x7b, 0xa5,
+0x04, 0x54, 0xa6, 0x04, 0x20, 0xa7, 0x04, 0x7c, 0xa8, 0x04, 0x6c, 0xa9, 0x04, 0xc0, 0x01, 0xaa,
+0x04, 0xc1, 0x01, 0xab, 0x04, 0x7d, 0xac, 0x04, 0xc2, 0x01, 0xad, 0x04, 0xc3, 0x01, 0xae, 0x04,
+0xaf, 0x01, 0xaf, 0x04, 0x13, 0xb0, 0x04, 0x9b, 0x01, 0xb1, 0x04, 0x60, 0xb2, 0x04, 0x7e, 0xb3,
+0x04, 0x9c, 0x01, 0xb4, 0x04, 0x61, 0xb5, 0x04, 0x07, 0x03, 0x09, 0x05, 0x32, 0xb6, 0x04, 0x31,
+0xb7, 0x04, 0x6d, 0xb8, 0x04, 0x6e, 0xb9, 0x04, 0x3a, 0xba, 0x04, 0x11, 0xbb, 0x04, 0x47, 0xbc,
+0x04, 0x8e, 0x01, 0xbd, 0x04, 0xaa, 0x01, 0xbe, 0x04, 0x88, 0x01, 0xbf, 0x04, 0xab, 0x01, 0xc0,
+0x04, 0x10, 0x0a, 0x3f, 0xc1, 0x04, 0x9d, 0x01, 0xc2, 0x04, 0x62, 0xc3, 0x04, 0xac, 0x01, 0xc4,
+0x04, 0x18, 0xc5, 0x04, 0x9e, 0x01, 0xc6, 0x04, 0x5a, 0xc7, 0x04, 0x63, 0xc8, 0x04, 0x3b, 0xc9,
+0x04, 0x3c, 0xca, 0x04, 0xc4, 0x01, 0xcb, 0x04, 0x7f, 0xcc, 0x04, 0x80, 0x01, 0xcd, 0x04, 0xc5,
+0x01, 0xce, 0x04, 0x8f, 0x01, 0xcf, 0x04, 0xc6, 0x01, 0xd0, 0x04, 0xad, 0x01, 0xd1, 0x04, 0x90,
+0x01, 0xd2, 0x04, 0x6f, 0xd3, 0x04, 0xb5, 0x01, 0xd4, 0x04, 0x34, 0xd5, 0x04, 0x81, 0x01, 0xd6,
+0x04, 0x9f, 0x01, 0xd7, 0x04, 0xa0, 0x01, 0xd8, 0x04, 0x0d, 0xd9, 0x04, 0x55, 0xda, 0x04, 0xc7,
+0x01, 0xdb, 0x04, 0xc8, 0x01, 0xdc, 0x04, 0x82, 0x01, 0xdd, 0x04, 0x1f, 0xde, 0x04, 0x39, 0xdf,
+0x04, 0xa1, 0x01, 0xe0, 0x04, 0x4f, 0xe1, 0x04, 0xa2, 0x01, 0xe2, 0x04, 0x0f, 0xe3, 0x04, 0x40,
+0xe4, 0x04, 0x91, 0x01, 0xe5, 0x04, 0x92, 0x01, 0xe6, 0x04, 0x50, 0xe7, 0x04, 0x16, 0x16, 0x64,
+0xe8, 0x04, 0x65, 0xe9, 0x04, 0x93, 0x01, 0xea, 0x04, 0x41, 0xeb, 0x04, 0x2b, 0xec, 0x04, 0x94,
+0x01, 0xed, 0x04, 0x83, 0x01, 0xee, 0x04, 0x46, 0xef, 0x04, 0x95, 0x01, 0xf0, 0x04, 0x42, 0xf1,
+0x04, 0x1a, 0xf2, 0x04, 0x5d, 0xf3, 0x04, 0x45, 0xf4, 0x04, 0x43, 0xf5, 0x04, 0xc9, 0x01, 0xf6,
+0x04, 0x5b, 0xf7, 0x04, 0x1d, 0xf8, 0x04, 0xa3, 0x01, 0xf9, 0x04, 0x84, 0x01, 0xfa, 0x04, 0xae,
+0x01, 0xfb, 0x04, 0x5e, 0xfc, 0x04, 0x24, 0xfd, 0x04, 0x74, 0xfe, 0x04, 0xca, 0x01, 0xff, 0x04,
+0xa4, 0x01, 0x80, 0x05, 0x36, 0x81, 0x05, 0x85, 0x01, 0x82, 0x05, 0x17, 0x83, 0x05, 0xb0, 0x01,
+0x84, 0x05, 0x66, 0x85, 0x05, 0x38, 0x86, 0x05, 0xb3, 0x01, 0x87, 0x05, 0x56, 0x88, 0x05, 0x21,
+0x89, 0x05, 0x14, 0x8a, 0x05, 0x49, 0x8b, 0x05, 0x5c, 0x8c, 0x05, 0xcb, 0x01, 0x8d, 0x05, 0x57,
+0x8e, 0x05, 0x05, 0x8f, 0x05, 0x25, 0x90, 0x05, 0x86, 0x01, 0x91, 0x05, 0x70, 0x92, 0x05, 0x0a,
+0x07, 0xb4, 0x01, 0x93, 0x05, 0x29, 0x94, 0x05, 0x04, 0x95, 0x05, 0x12, 0x96, 0x05, 0x00, 0x00,
+0x03, 0x97, 0x05, 0x01, 0x98, 0x05, 0x08, 0x06, 0x44, 0x99, 0x05, 0x48, 0x9a, 0x05, 0xb6, 0x01,
+0x9b, 0x05, 0xa5, 0x01, 0x9c, 0x05, 0xcc, 0x01, 0x9d, 0x05, 0xcd, 0x01, 0x9e, 0x05, 0xce, 0x01,
+0x9f, 0x05, 0xcf, 0x01, 0xa0, 0x05, 0xd0, 0x01, 0xa1, 0x05,
+ /* nr */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06, 0x48, 0x53,
+ /* nso */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06, 0x48, 0x53,
+ /* nus */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x6b, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x74, 0x11, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* nv */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ny */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* nyn */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x57, 0x66,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* oc */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* oc-ES */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* oka */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* oka-US */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* om */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x4d, 0x57, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b,
+0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* om-KE */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x4d, 0x57, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b,
+0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x47, 0x52, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16,
+0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+0x08, 0x06,
+ /* or */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x19, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x14, 0x0c, 0x05, 0x17, 0x0a, 0x07,
+0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* os */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x7b, 0x93, 0x01, 0x13,
+0x0b, 0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14,
+0x0c, 0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08,
+0x06,
+ /* os-RU */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x46, 0x51, 0x14, 0x0c,
+0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* osa */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x17,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* pa */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x17, 0x18, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+ /* pa-Arab */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x64, 0xa2, 0x05, 0x14,
+0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08,
+0x06,
+ /* pa-Guru */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x17, 0x18, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+ /* pap */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* pap-AW */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* pcm */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0xa3, 0x05, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07,
+0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x39, 0x54, 0x0f, 0x10, 0x14, 0x0c, 0x05,
+0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* pi */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* pi-Latn */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* pis */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x1a, 0x17, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* pl */
+0x0b, 0x08, 0x02, 0x01, 0x65, 0x84, 0x01, 0x04, 0x02, 0x12, 0x0d, 0x03, 0x04, 0x01, 0x09, 0x08,
+0x06,
+ /* pms */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* prg */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ps */
+0x51, 0x60, 0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b,
+0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ps-PK */
+0x51, 0x60, 0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b,
+0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x64, 0x61,
+0x14, 0x0c, 0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+0x08, 0x06,
+ /* pt */
+0x0e, 0x1a, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x4c, 0x8d, 0x01, 0x17, 0x18, 0x14,
+0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08,
+0x06,
+ /* pt-AO */
+0x89, 0x01, 0xc4, 0x01, 0x0e, 0x1a, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11,
+0x13, 0x0b, 0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x4c, 0x5d,
+0x17, 0x18, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04,
+0x01, 0x09, 0x08, 0x06,
+ /* pt-CH */
+0x0e, 0x1a, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x4c, 0x5d, 0x17, 0x18, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* pt-CV */
+0x0e, 0x1a, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x8c, 0x01, 0x5d, 0x02, 0x01, 0x06, 0x11, 0x13,
+0x0b, 0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x17, 0x18, 0x14,
+0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08,
+0x06,
+ /* pt-GQ */
+0x0e, 0x1a, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x4c, 0x5d, 0x17, 0x18, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* pt-GW */
+0x0e, 0x1a, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x4c, 0x5d, 0x17, 0x18, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* pt-LU */
+0x0e, 0x1a, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0xb1, 0x01, 0x1c, 0x0d, 0x0e, 0x0f, 0x10, 0x4c, 0x5d, 0x17,
+0x18, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01,
+0x09, 0x08, 0x06,
+ /* pt-MO */
+0x0e, 0x1a, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x6f, 0x86, 0x01, 0x0d, 0x0e, 0x0f, 0x10, 0x4c, 0x5d, 0x17,
+0x18, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01,
+0x09, 0x08, 0x06,
+ /* pt-MZ */
+0x0e, 0x1a, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x82, 0x01, 0x9e, 0x01, 0x0f, 0x10, 0x4c, 0x5d,
+0x17, 0x18, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04,
+0x01, 0x09, 0x08, 0x06,
+ /* pt-PT */
+0x0e, 0x1a, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x4c, 0x5d, 0x17, 0x18, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* pt-ST */
+0x0e, 0x1a, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x4c, 0x5d, 0xa4, 0x01, 0xa4, 0x05,
+0x17, 0x18, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04,
+0x01, 0x09, 0x08, 0x06,
+ /* pt-TL */
+0x0e, 0x1a, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x4c, 0x5d, 0x17, 0x18, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* qu */
+0x0e, 0x14, 0x4e, 0x9f, 0x01, 0x1b, 0xa0, 0x01, 0x0b, 0x08, 0x1c, 0xa1, 0x01, 0x0c, 0x1b, 0x15,
+0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d,
+0x0e, 0x0f, 0x10, 0x92, 0x01, 0xba, 0x01, 0x14, 0x0c, 0x05, 0x1f, 0x0a, 0x07, 0x04, 0x02, 0x12,
+0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* qu-BO */
+0x0e, 0x14, 0x4e, 0x9f, 0x01, 0x1b, 0xa0, 0x01, 0x5f, 0xb7, 0x01, 0x0b, 0x08, 0x1c, 0xa1, 0x01,
+0x0c, 0x1b, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03, 0x09, 0x05, 0x11, 0x13,
+0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x14, 0x0c, 0x05, 0x1f, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d,
+0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* qu-EC */
+0x0e, 0x14, 0x4e, 0x9f, 0x01, 0x1b, 0xa0, 0x01, 0x0b, 0x08, 0x1c, 0xa1, 0x01, 0x0c, 0x1b, 0x15,
+0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d,
+0x0e, 0x0f, 0x10, 0x14, 0x0c, 0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03,
+0x04, 0x01, 0x09, 0x08, 0x06,
+ /* quc */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x7d, 0xb8, 0x01, 0x13,
+0x0b, 0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14,
+0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08,
+0x06,
+ /* raj */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* rhg */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* rhg-Rohg */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* rhg-Rohg-BD */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* rif */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* rm */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x17,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* rn */
+0x0e, 0x14, 0x79, 0x92, 0x01, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13,
+0x0b, 0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14,
+0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08,
+0x06,
+ /* ro */
+0x04, 0x02, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ro-MD */
+0x7f, 0x9a, 0x01, 0x04, 0x02, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* rof */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x49, 0x55,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ru */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x19, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x46, 0x51, 0x76, 0x75, 0x17, 0x18,
+0x66, 0x79, 0x14, 0x0c, 0x5c, 0x74, 0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x62,
+0x03, 0x04, 0x01, 0x09, 0x08, 0x7a,
+ /* ru-BY */
+0x0e, 0x14, 0x0b, 0x08, 0x7a, 0x57, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b,
+0x07, 0x03, 0x09, 0x05, 0x11, 0x19, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x46, 0x51, 0x17, 0x18,
+0x66, 0x79, 0x14, 0x0c, 0x5c, 0x74, 0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x62,
+0x03, 0x04, 0x01, 0x09, 0x08, 0x7a,
+ /* ru-KG */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x19, 0x8e, 0x01, 0xc3, 0x01, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x46, 0x51,
+0x76, 0x75, 0x17, 0x18, 0x66, 0x79, 0x14, 0x0c, 0x5c, 0x74, 0x05, 0x17, 0x0a, 0x07, 0x04, 0x02,
+0x12, 0x0d, 0x00, 0x62, 0x03, 0x04, 0x01, 0x09, 0x08, 0x7a,
+ /* ru-KZ */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x19, 0x10, 0x0a, 0x62, 0x7f, 0x0d, 0x0e, 0x0f, 0x10, 0x46, 0x51, 0x76, 0x75,
+0x17, 0x18, 0x66, 0x79, 0x14, 0x0c, 0x5c, 0x74, 0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d,
+0x00, 0x62, 0x03, 0x04, 0x01, 0x09, 0x08, 0x7a,
+ /* ru-MD */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x19, 0x10, 0x0a, 0x7f, 0x9a, 0x01, 0x0d, 0x0e, 0x0f, 0x10, 0x46, 0x51, 0x76,
+0x75, 0x17, 0x18, 0x66, 0x79, 0x14, 0x0c, 0x5c, 0x74, 0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x12,
+0x0d, 0x00, 0x62, 0x03, 0x04, 0x01, 0x09, 0x08, 0x7a,
+ /* ru-UA */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x19, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x46, 0x51, 0x76, 0x75, 0x17, 0x18,
+0x66, 0x79, 0x14, 0x0c, 0x5c, 0x74, 0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x62,
+0x03, 0x04, 0x01, 0x09, 0x08, 0x7a,
+ /* rw */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x95, 0x01, 0x96, 0x01,
+0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+0x08, 0x06,
+ /* rwk */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x49, 0x55,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* sa */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* sah */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x46, 0x51, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* saq */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x47, 0x52, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* sat */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* sat-Deva */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* sat-Olck */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* sbp */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x49, 0x55,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* sc */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0xd1, 0x01, 0xa5, 0x05, 0x03, 0x04, 0x01, 0x09,
+0x08, 0x06,
+ /* scn */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* sd */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x64, 0x61, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* sd-Arab */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x64, 0x61, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* sd-Deva */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x19, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x17,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* sdh */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* sdh-IQ */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* se */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x4b, 0x7b, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b,
+0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x4f, 0x56, 0x0f, 0x10, 0x16, 0x16,
+0x5b, 0xc7, 0x01, 0x17, 0x18, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00,
+0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* se-FI */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x4b, 0x7b, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b,
+0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x4f, 0x56, 0x0f, 0x10, 0x16, 0x16,
+0x5b, 0xc7, 0x01, 0x17, 0x18, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00,
+0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* se-SE */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x4b, 0x7b, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b,
+0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x4f, 0x8e, 0x01, 0x0f, 0x10, 0x16,
+0x16, 0x5b, 0x56, 0x17, 0x18, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00,
+0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* seh */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x82, 0x01, 0x9e, 0x01, 0x0f, 0x10, 0x16, 0x16,
+0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+0x08, 0x06,
+ /* ses */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* sg */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* sgs */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* shi */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* shi-Latn */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* shi-Tfng */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* shn */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* shn-TH */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* si */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x9e, 0x01, 0xa6, 0x05, 0x0d, 0x0e, 0x0f, 0x10, 0x17, 0x18,
+0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0xa7, 0x05, 0x01,
+0x09, 0x08, 0x06,
+ /* sid */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x4d, 0x57, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b,
+0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* sk */
+0x02, 0x01, 0x07, 0xa8, 0x05, 0x0d, 0x0e, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x62, 0x03, 0x04, 0x01,
+0x09,
+ /* skr */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* sl */
+0x15, 0x0f, 0x02, 0x01, 0x13, 0x0b, 0x07, 0x03, 0x09, 0x05, 0x11, 0x19, 0x10, 0x0a, 0x05, 0x17,
+0x0a, 0x07, 0x04, 0x02, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* sma */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* sma-NO */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* smj */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* smj-NO */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* smn */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* sms */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* sn */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* so */
+0x0e, 0x14, 0x4e, 0x8f, 0x01, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13,
+0x0b, 0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x5e,
+0x7d, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01,
+0x09, 0x08, 0x06,
+ /* so-DJ */
+0x0e, 0x14, 0x4e, 0x8f, 0x01, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x68, 0x80, 0x01, 0x02, 0x01,
+0x06, 0x11, 0x13, 0x0b, 0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10,
+0x16, 0x16, 0x5e, 0x7d, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00,
+0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* so-ET */
+0x0e, 0x14, 0x4e, 0x8f, 0x01, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x4d, 0x57, 0x02, 0x01, 0x06,
+0x11, 0x13, 0x0b, 0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16,
+0x16, 0x5e, 0x7d, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03,
+0x04, 0x01, 0x09, 0x08, 0x06,
+ /* so-KE */
+0x0e, 0x14, 0x4e, 0x8f, 0x01, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13,
+0x0b, 0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x47, 0x52, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16,
+0x16, 0x5e, 0x7d, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03,
+0x04, 0x01, 0x09, 0x08, 0x06,
+ /* sq */
+0x77, 0xa2, 0x01, 0x0e, 0x14, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07,
+0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x17, 0x18, 0x14, 0x0c, 0x05,
+0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0xa3, 0x01, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* sq-MK */
+0x77, 0xa2, 0x01, 0x0e, 0x14, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07,
+0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x8f, 0x01, 0xa9, 0x05, 0x0d, 0x0e, 0x0f, 0x10, 0x17,
+0x18, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0xa3, 0x01, 0x03, 0x04,
+0x01, 0x09, 0x08, 0x06,
+ /* sq-XK */
+0x77, 0xa2, 0x01, 0x0e, 0x14, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07,
+0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x17, 0x18, 0x14, 0x0c, 0x05,
+0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0xa3, 0x01, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* sr */
+0x4a, 0x76, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x19, 0x0d, 0x0e, 0x14, 0x0c, 0x05, 0x15, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00,
+0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* sr-Cyrl */
+0x4a, 0x76, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x19, 0x0d, 0x0e, 0x14, 0x0c, 0x05, 0x15, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00,
+0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* sr-Cyrl-BA */
+0x4a, 0x76, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x19, 0x0d, 0x0e, 0x14, 0x0c, 0x05, 0x15, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00,
+0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* sr-Cyrl-ME */
+0x4a, 0x76, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x19, 0x0d, 0x0e, 0x14, 0x0c, 0x05, 0x15, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00,
+0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* sr-Cyrl-XK */
+0x4a, 0x76, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x19, 0x0d, 0x0e, 0x14, 0x0c, 0x05, 0x15, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00,
+0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* sr-Latn */
+0x4a, 0x6d, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x19, 0x0d, 0x0e, 0x14, 0x0c, 0x05, 0x15, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00,
+0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* sr-Latn-BA */
+0x4a, 0x6d, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x19, 0x0d, 0x0e, 0x14, 0x0c, 0x05, 0x15, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00,
+0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* sr-Latn-ME */
+0x4a, 0x6d, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x19, 0x0d, 0x0e, 0x14, 0x0c, 0x05, 0x15, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00,
+0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* sr-Latn-XK */
+0x4a, 0x6d, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x19, 0x0d, 0x0e, 0x14, 0x0c, 0x05, 0x15, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00,
+0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ss */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x85, 0x01, 0x99, 0x01,
+0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+0x08, 0x06, 0x48, 0x53,
+ /* ss-SZ */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x85, 0x01, 0x99, 0x01,
+0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+0x08, 0x06, 0x48, 0x53,
+ /* ssy */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x53, 0x65, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b,
+0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* st */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06, 0x48, 0x53,
+ /* st-LS */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x63, 0xaa, 0x05, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14,
+0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08,
+0x06, 0x48, 0x53,
+ /* su */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x61, 0x78,
+0x07, 0x03, 0x09, 0x05, 0x11, 0x19, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* su-Latn */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x61, 0x78,
+0x07, 0x03, 0x09, 0x05, 0x11, 0x19, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* suz */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* suz-Deva */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* suz-Sunu */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* sv */
+0x4e, 0xa4, 0x01, 0x1b, 0xa5, 0x01, 0x0b, 0xa6, 0x01, 0x6a, 0xa7, 0x01, 0x1c, 0xa8, 0x01, 0x0c,
+0x12, 0x4b, 0x7b, 0x6b, 0x87, 0x01, 0xa6, 0x01, 0xa9, 0x01, 0x33, 0xaa, 0x01, 0x02, 0x01, 0x26,
+0xab, 0x01, 0x07, 0x03, 0x6d, 0xac, 0x01, 0x6e, 0xad, 0x01, 0x0d, 0x0e, 0x4f, 0x8e, 0x01, 0x5b,
+0x56, 0x05, 0x15, 0x04, 0x02, 0x12, 0x0d, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* sv-AX */
+0x4e, 0xa4, 0x01, 0x1b, 0xa5, 0x01, 0x0b, 0xa6, 0x01, 0x6a, 0xa7, 0x01, 0x1c, 0xa8, 0x01, 0x0c,
+0x12, 0x4b, 0x7b, 0x6b, 0x87, 0x01, 0xa6, 0x01, 0xa9, 0x01, 0x33, 0xaa, 0x01, 0x02, 0x01, 0x26,
+0xab, 0x01, 0x07, 0x03, 0x6d, 0xac, 0x01, 0x6e, 0xad, 0x01, 0x0d, 0x0e, 0x4f, 0x8e, 0x01, 0x5b,
+0x56, 0x05, 0x15, 0x04, 0x02, 0x12, 0x0d, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* sv-FI */
+0x4e, 0xa4, 0x01, 0x1b, 0xa5, 0x01, 0x0b, 0xa6, 0x01, 0x6a, 0xa7, 0x01, 0x1c, 0xa8, 0x01, 0x0c,
+0x12, 0x4b, 0x7b, 0x6b, 0x87, 0x01, 0xa6, 0x01, 0xa9, 0x01, 0x33, 0xaa, 0x01, 0x02, 0x01, 0x26,
+0xab, 0x01, 0x07, 0x03, 0x6d, 0xac, 0x01, 0x6e, 0xad, 0x01, 0x0d, 0x0e, 0x4f, 0x8e, 0x01, 0x5b,
+0x56, 0x05, 0x15, 0x04, 0x02, 0x12, 0x0d, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* sw */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x47, 0x52, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x17, 0x18, 0x14, 0x0c,
+0x49, 0x55, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+0x08, 0x06,
+ /* sw-CD */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x59, 0x71, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b,
+0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x47, 0x52, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x17, 0x18,
+0x14, 0x0c, 0x49, 0x55, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04,
+0x01, 0x09, 0x08, 0x06,
+ /* sw-KE */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x47, 0x52, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x17, 0x18, 0x14, 0x0c,
+0x49, 0x55, 0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+0x08, 0x06,
+ /* sw-UG */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x47, 0x52, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x17, 0x18, 0x14, 0x0c,
+0x49, 0x55, 0x57, 0x66, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04,
+0x01, 0x09, 0x08, 0x06,
+ /* syr */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x36, 0x3d, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* syr-SY */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x36, 0x3d, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* szl */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x65, 0x84, 0x01, 0x14,
+0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08,
+0x06,
+ /* ta */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x19, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x17, 0x18, 0x14, 0x0c, 0x05, 0x17,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ta-LK */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x19, 0x10, 0x0a, 0x9e, 0x01, 0xab, 0x05, 0x0d, 0x0e, 0x0f, 0x10, 0x17, 0x18,
+0x14, 0x0c, 0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+0x08, 0x06,
+ /* ta-MY */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x19, 0x10, 0x0a, 0x0d, 0x0e, 0x55, 0x63, 0x0f, 0x10, 0x1d, 0xac, 0x05, 0x17,
+0x18, 0x14, 0x0c, 0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01,
+0x09, 0x08, 0x06,
+ /* ta-SG */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x19, 0x10, 0x0a, 0x0d, 0x0e, 0x55, 0x63, 0x0f, 0x10, 0x1d, 0x17, 0x17, 0x18,
+0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+0x08, 0x06,
+ /* te */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x17, 0x18, 0x14, 0x0c, 0x05, 0x17,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* teo */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x57, 0x66,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* teo-KE */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x47, 0x52, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x57, 0x66, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+0x08, 0x06,
+ /* tg */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0xb0, 0x01, 0xad, 0x05,
+0x14, 0x0c, 0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+0x08, 0x06,
+ /* th */
+0x0e, 0x1a, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x19, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x17, 0x18, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+ /* ti */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x4d, 0x57, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07,
+0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ti-ER */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x53, 0x65, 0x4d, 0x57, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b,
+0x07, 0x03, 0x09, 0x05, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* tig */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x53, 0x65, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b,
+0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* tk */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x13, 0x0b, 0x07, 0x03, 0x09, 0x05, 0x11, 0x13,
+0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d,
+0x00, 0xae, 0x05, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* tn */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06, 0x48, 0x53,
+ /* tn-BW */
+0x0e, 0x14, 0x0b, 0x08, 0x8b, 0x01, 0xb3, 0x01, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11,
+0x13, 0x0b, 0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16,
+0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+0x08, 0x06, 0x48, 0x53,
+ /* to */
+0x0e, 0xaf, 0x05, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07,
+0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0xb0, 0x05, 0x16, 0x16, 0xb3, 0x01,
+0xb5, 0x01, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04,
+0x01, 0x09, 0x08, 0x06,
+ /* tok */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* tpi */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* tr */
+0x0e, 0x1a, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x19, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x17, 0x18, 0x56, 0x72, 0x14, 0x0c,
+0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* tr-CY */
+0x0e, 0x1a, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x19, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x17, 0x18, 0x56, 0x72, 0x14, 0x0c,
+0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* trv */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* trw */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ts */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06, 0x48, 0x53,
+ /* tt */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x46, 0x51, 0x14, 0x0c,
+0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* twq */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* tyv */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* tzm */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ug */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x9c, 0x01, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07,
+0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05,
+0x17, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* uk */
+0x11, 0x19, 0x5c, 0x74, 0xd2, 0x01, 0xb1, 0x05, 0x04, 0x02, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+0x08, 0x06,
+ /* und */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ur */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x64, 0x61, 0x17, 0x18, 0x14, 0x0c,
+0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ur-IN */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x17, 0x18, 0x14, 0x0c, 0x05, 0x17,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* uz */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x14, 0x0c, 0x05, 0x15, 0x86, 0x01,
+0xc8, 0x01, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* uz-Arab */
+0x51, 0x60, 0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b,
+0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* uz-Cyrl */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x17, 0x18, 0x14, 0x0c,
+0x05, 0x15, 0x86, 0x01, 0xb2, 0x05, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04,
+0x01, 0x09, 0x08, 0x06,
+ /* uz-Latn */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x14, 0x0c, 0x05, 0x15, 0x86, 0x01,
+0xc8, 0x01, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* vai */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x5a, 0x17, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* vai-Latn */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x5a, 0x17, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* vai-Vaii */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x5a, 0x17, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* ve */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06, 0x48, 0x53,
+ /* vec */
+0x00, 0x7e, 0x08, 0x06,
+ /* vi */
+0x0e, 0x1a, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x19, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x17, 0x18, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+ /* vmw */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* vo */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* vun */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x49, 0x55,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* wa */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* wae */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x19, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x17,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* wal */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x4d, 0x57, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b,
+0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* wbp */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* wo */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x33, 0xb3, 0x05, 0x02, 0x01, 0x06, 0x11, 0x54,
+0xb4, 0x05, 0x20, 0xb5, 0x05, 0x7d, 0xb6, 0x05, 0x13, 0x0b, 0x60, 0xb7, 0x05, 0x07, 0x03, 0x09,
+0x05, 0x11, 0x13, 0x10, 0x0a, 0x7f, 0xb8, 0x05, 0x0d, 0x0e, 0x39, 0xb9, 0x05, 0x0f, 0x10, 0x16,
+0x16, 0x14, 0x0c, 0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01,
+0x09, 0x08, 0x06,
+ /* xh */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x98, 0x01, 0xba, 0x05, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11,
+0x13, 0x0b, 0x07, 0x03, 0x09, 0x05, 0x11, 0x19, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16,
+0x14, 0x0c, 0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0xbb, 0x05, 0x03, 0x04, 0x01,
+0x09, 0x08, 0x06, 0x48, 0x53, 0x67, 0xbc, 0x05,
+ /* xnr */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* xog */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x57, 0x66,
+0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* yav */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* yi */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* yo */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x39, 0x54, 0x0f, 0x10, 0x16, 0x16, 0x46, 0x51,
+0x14, 0x0c, 0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+0x08, 0x06,
+ /* yo-BJ */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x39, 0x54, 0x0f, 0x10, 0x16, 0x16, 0x46, 0x51,
+0x14, 0x0c, 0x05, 0x17, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+0x08, 0x06,
+ /* yrl */
+0x0e, 0x1a, 0x5f, 0xae, 0x01, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x1e, 0x17, 0x02, 0x01, 0x06,
+0x11, 0x13, 0x0b, 0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x4c,
+0x8d, 0x01, 0x5d, 0xaf, 0x01, 0x17, 0x18, 0x14, 0x0c, 0x05, 0x15, 0x70, 0x89, 0x01, 0x0a, 0x07,
+0x04, 0xb0, 0x01, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x8c, 0x01, 0x01, 0x85, 0x01, 0x08, 0x06,
+ /* yrl-CO */
+0x0e, 0x1a, 0x5f, 0xae, 0x01, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x1e, 0x17, 0x02, 0x01, 0x06,
+0x11, 0x13, 0x0b, 0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x4c,
+0x8d, 0x01, 0x5d, 0xaf, 0x01, 0x17, 0x18, 0x14, 0x0c, 0x05, 0x15, 0x70, 0x89, 0x01, 0x0a, 0x07,
+0x04, 0xb0, 0x01, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x8c, 0x01, 0x01, 0x85, 0x01, 0x08, 0x06,
+ /* yrl-VE */
+0x0e, 0x1a, 0x5f, 0xae, 0x01, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x1e, 0x17, 0x02, 0x01, 0x06,
+0x11, 0x13, 0x0b, 0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x4c,
+0x8d, 0x01, 0x5d, 0xaf, 0x01, 0x17, 0x18, 0x14, 0x0c, 0x05, 0x15, 0x70, 0x89, 0x01, 0x0a, 0x07,
+0x04, 0xb0, 0x01, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x8c, 0x01, 0x01, 0x85, 0x01, 0x08, 0x06,
+ /* yue */
+0x0e, 0x1a, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x19, 0x10, 0x69, 0x0d, 0x0e, 0x0f, 0x10, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07,
+0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+ /* yue-Hans */
+0x0e, 0x1a, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x19, 0x10, 0x69, 0x0d, 0x0e, 0x0f, 0x10, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07,
+0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+ /* yue-Hant */
+0x0e, 0x1a, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x19, 0x10, 0x69, 0x0d, 0x0e, 0x0f, 0x10, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07,
+0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+ /* yue-Hant-CN */
+0x0e, 0x1a, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x19, 0x10, 0x69, 0x0d, 0x0e, 0x0f, 0x10, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07,
+0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+ /* yue-Hant-MO */
+0x0e, 0x1a, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x19, 0x10, 0x69, 0x0d, 0x0e, 0x0f, 0x10, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07,
+0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+ /* za */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* zgh */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* zh */
+0x0e, 0x1a, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x19, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x87, 0x01,
+0x7c, 0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x14, 0x0c, 0x05,
+0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+ /* zh-Hans */
+0x0e, 0x1a, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x19, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x87, 0x01,
+0x7c, 0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x14, 0x0c, 0x05,
+0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+ /* zh-Hans-HK */
+0x0e, 0x1a, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x87, 0x01,
+0x7c, 0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x14, 0x0c, 0x05,
+0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+ /* zh-Hans-MO */
+0x0e, 0x1a, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x87, 0x01,
+0x7c, 0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x6f, 0x86, 0x01, 0x0d, 0x0e, 0x0f, 0x10,
+0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+ /* zh-Hans-MY */
+0x0e, 0x1a, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x19, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x87, 0x01,
+0x7c, 0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x14, 0x0c, 0x05,
+0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+ /* zh-Hans-SG */
+0x0e, 0x1a, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x87, 0x01,
+0x7c, 0x07, 0x03, 0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x1d, 0x17, 0x14,
+0x0c, 0x05, 0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+ /* zh-Hant */
+0x0e, 0x1a, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x19, 0x10, 0x69, 0x0d, 0x0e, 0x0f, 0x10, 0x14, 0x17, 0x05, 0x15, 0x0a, 0x07,
+0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+ /* zh-Hant-HK */
+0x0e, 0x1a, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x19, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x14, 0x0c, 0x05, 0x15, 0x0a, 0x07,
+0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+ /* zh-Hant-MO */
+0x0e, 0x1a, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x19, 0x10, 0x0a, 0x6f, 0x86, 0x01, 0x0d, 0x0e, 0x0f, 0x10, 0x14, 0x0c, 0x05,
+0x15, 0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+ /* zh-Hant-MY */
+0x0e, 0x1a, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x19, 0x10, 0x69, 0x0d, 0x0e, 0x0f, 0x10, 0x14, 0x17, 0x05, 0x15, 0x0a, 0x07,
+0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+ /* zh-Latn */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x16, 0x16, 0x14, 0x0c, 0x05, 0x15,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06,
+ /* zh-TW */
+0x0e, 0x1a, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x19, 0x10, 0x69, 0x0d, 0x0e, 0x0f, 0x10, 0x14, 0x17, 0x05, 0x15, 0x0a, 0x07,
+0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09,
+ /* zu */
+0x0e, 0x14, 0x0b, 0x08, 0x0c, 0x12, 0x15, 0x0f, 0x02, 0x01, 0x06, 0x11, 0x13, 0x0b, 0x07, 0x03,
+0x09, 0x05, 0x11, 0x13, 0x10, 0x0a, 0x0d, 0x0e, 0x0f, 0x10, 0x17, 0x18, 0x14, 0x0c, 0x05, 0x17,
+0x0a, 0x07, 0x04, 0x02, 0x12, 0x0d, 0x00, 0x00, 0x03, 0x04, 0x01, 0x09, 0x08, 0x06, 0x48, 0x53,
+};
+
+static const CompactDecimalPattern locale_compact_arr_0[] = {
+ { 3, "{0}K", "{0}K" },
+ { 4, "{0}K", "{0}K" },
+ { 5, "{0}K", "{0}K" },
+ { 6, "{0}M", "{0}M" },
+ { 7, "{0}M", "{0}M" },
+ { 8, "{0}M", "{0}M" },
+ { 9, "{0}G", "{0}G" },
+ { 10, "{0}G", "{0}G" },
+ { 11, "{0}G", "{0}G" },
+ { 12, "{0}T", "{0}T" },
+ { 13, "{0}T", "{0}T" },
+ { 14, "{0}T", "{0}T" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_1[] = {
+ { 3, "{0} k", "{0} duisend" },
+ { 4, "{0} k", "{0} duisend" },
+ { 5, "{0} k", "{0} duisend" },
+ { 6, "{0} m", "{0} miljoen" },
+ { 7, "{0} m", "{0} miljoen" },
+ { 8, "{0} m", "{0} miljoen" },
+ { 9, "{0} mjd", "{0} miljard" },
+ { 10, "{0} mjd", "{0} miljard" },
+ { 11, "{0} mjd", "{0} miljard" },
+ { 12, "{0} bn", "{0} biljoen" },
+ { 13, "{0} bn", "{0} biljoen" },
+ { 14, "{0} bn", "{0} biljoen" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_2[] = {
+ { 3, "{0}K", "apem {0}" },
+ { 4, "{0}K", "mpem {0}" },
+ { 5, "{0}K", "mpem {0}" },
+ { 6, "{0}M", "ɔpepem {0}" },
+ { 7, "{0}M", "ɔpepem {0}" },
+ { 8, "{0}M", "ɔpepem {0}" },
+ { 9, "{0}G", "ɔpepepem {0}" },
+ { 10, "{0}G", "ɔpepepem {0}" },
+ { 11, "{0}G", "ɔpepepem {0}" },
+ { 12, "{0}T", "ɔpepepepem {0}" },
+ { 13, "{0}T", "ɔpepepepem {0}" },
+ { 14, "{0}T", "ɔpepepepem {0}" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_3[] = {
+ { 3, "{0} ሺ", "{0} ሺ" },
+ { 4, "{0} ሺ", "{0} ሺ" },
+ { 5, "{0} ሺ", "{0} ሺ" },
+ { 6, "{0} ሚ", "{0} ሚሊዮን" },
+ { 7, "{0} ሚ", "{0} ሚሊዮን" },
+ { 8, "{0} ሚ", "{0} ሚሊዮን" },
+ { 9, "{0} ቢ", "{0} ቢሊዮን" },
+ { 10, "{0} ቢ", "{0} ቢሊዮን" },
+ { 11, "{0} ቢ", "{0} ቢሊዮን" },
+ { 12, "{0} ት", "{0} ትሪሊዮን" },
+ { 13, "{0} ት", "{0} ትሪሊዮን" },
+ { 14, "{0} ት", "{0} ትሪሊዮን" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_4[] = {
+ { 3, "{0} ألف", "{0} ألف" },
+ { 4, "{0} ألف", "{0} ألف" },
+ { 5, "{0} ألف", "{0} ألف" },
+ { 6, "{0} مليون", "{0} مليون" },
+ { 7, "{0} مليون", "{0} مليون" },
+ { 8, "{0} مليون", "{0} مليون" },
+ { 9, "{0} مليار", "{0} مليار" },
+ { 10, "{0} مليار", "{0} مليار" },
+ { 11, "{0} مليار", "{0} مليار" },
+ { 12, "{0} ترليون", "{0} ترليون" },
+ { 13, "{0} ترليون", "{0} ترليون" },
+ { 14, "{0} ترليون", "{0} ترليون" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_5[] = {
+ { 3, "{0} হাজাৰ", "{0} হাজাৰ" },
+ { 4, "{0} হাজাৰ", "{0} হাজাৰ" },
+ { 5, "{0} লাখ", "{0} লাখ" },
+ { 6, "{0} নিযুত", "{0} নিযুত" },
+ { 7, "{0} নিযুত", "{0} নিযুত" },
+ { 8, "{0} নিঃ", "{0} নিযুত" },
+ { 9, "{0} শঃ কোঃ", "{0} শত কোটি" },
+ { 10, "{0} শঃ কোঃ", "{0} শত কোটি" },
+ { 11, "{0} শঃ কঃ", "{0} শত কোটি" },
+ { 12, "{0} শঃ পঃ", "{0} শত পৰাৰ্দ্ধ" },
+ { 13, "{0} শঃ পঃ", "{0} শত পৰাৰ্দ্ধ" },
+ { 14, "{0} শঃ পঃ", "{0} শত পৰাৰ্দ্ধ" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_6[] = {
+ { 3, "{0}K", "{0} millares" },
+ { 4, "{0}K", "{0} millares" },
+ { 5, "{0}K", "{0} millares" },
+ { 6, "{0}M", "{0} millones" },
+ { 7, "{0}M", "{0} millones" },
+ { 8, "{0}M", "{0} millones" },
+ { 9, "{0}G", "{0}G" },
+ { 10, "{0}G", "{0}G" },
+ { 11, "{0}G", "{0}G" },
+ { 12, "{0}T", "{0}T" },
+ { 13, "{0}T", "{0}T" },
+ { 14, "{0}T", "{0}T" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_7[] = {
+ { 3, "{0}K", "{0} min" },
+ { 4, "{0}K", "{0} min" },
+ { 5, "{0}K", "{0} min" },
+ { 6, "{0} mln", "{0} milyon" },
+ { 7, "{0} mln", "{0} milyon" },
+ { 8, "{0} mln", "{0} milyon" },
+ { 9, "{0} mlrd", "{0} milyard" },
+ { 10, "{0} mlrd", "{0} milyard" },
+ { 11, "{0} mlrd", "{0} milyard" },
+ { 12, "{0} trln", "{0} trilyon" },
+ { 13, "{0} trln", "{0} trilyon" },
+ { 14, "{0} trln", "{0} trilyon" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_8[] = {
+ { 3, "{0} мең", "{0} мең" },
+ { 4, "{0} мең", "{0} мең" },
+ { 5, "{0} мең", "{0} мең" },
+ { 6, "{0} млн", "{0} миллион" },
+ { 7, "{0} млн", "{0} миллион" },
+ { 8, "{0} млн", "{0} миллион" },
+ { 9, "{0} млрд", "{0} миллиард" },
+ { 10, "{0} млрд", "{0} миллиард" },
+ { 11, "{0} млрд", "{0} миллиард" },
+ { 12, "{0} трлн", "{0} триллион" },
+ { 13, "{0} трлн", "{0} триллион" },
+ { 14, "{0} трлн", "{0} триллион" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_9[] = {
+ { 3, "{0}H", "{0}H" },
+ { 4, "{0}H", "{0}H" },
+ { 5, "{0}H", "{0}H" },
+ { 6, "{0}M", "{0}M" },
+ { 7, "{0}M", "{0}M" },
+ { 8, "{0}M", "{0}M" },
+ { 9, "{0}Kr", "{0}Kr" },
+ { 10, "{0}Kr", "{0}Kr" },
+ { 11, "{0}Kr", "{0}Kr" },
+ { 12, "{0}T", "{0}T" },
+ { 13, "{0}T", "{0}T" },
+ { 14, "{0}T", "{0}T" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_10[] = {
+ { 3, "{0} тыс'.'", "{0} тысячы" },
+ { 4, "{0} тыс'.'", "{0} тысячы" },
+ { 5, "{0} тыс'.'", "{0} тысячы" },
+ { 6, "{0} млн", "{0} мільёна" },
+ { 7, "{0} млн", "{0} мільёна" },
+ { 8, "{0} млн", "{0} мільёна" },
+ { 9, "{0} млрд", "{0} мільярда" },
+ { 10, "{0} млрд", "{0} мільярда" },
+ { 11, "{0} млрд", "{0} мільярда" },
+ { 12, "{0} трлн", "{0} трыльёна" },
+ { 13, "{0} трлн", "{0} трыльёна" },
+ { 14, "{0} трлн", "{0} трыльёна" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_11[] = {
+ { 3, "{0} хил'.'", "{0} хиляди" },
+ { 4, "{0} хил'.'", "{0} хиляди" },
+ { 5, "{0} хил'.'", "{0} хиляди" },
+ { 6, "{0} млн'.'", "{0} милиона" },
+ { 7, "{0} млн'.'", "{0} милиона" },
+ { 8, "{0} млн'.'", "{0} милиона" },
+ { 9, "{0} млрд'.'", "{0} милиарда" },
+ { 10, "{0} млрд'.'", "{0} милиарда" },
+ { 11, "{0} млрд'.'", "{0} милиарда" },
+ { 12, "{0} трлн'.'", "{0} трилиона" },
+ { 13, "{0} трлн'.'", "{0} трилиона" },
+ { 14, "{0} трлн'.'", "{0} трилиона" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_12[] = {
+ { 3, "ɩkt {0}", "ɩkotoku {0}" },
+ { 4, "ɩkt {0}", "ɩkotoku {0}" },
+ { 5, "ɩkt {0}", "ɩkotoku {0}" },
+ { 6, "bkl {0}", "bʊkuli {0}" },
+ { 7, "bkl {0}", "bʊkuli {0}" },
+ { 8, "bkl {0}", "bʊkuli {0}" },
+ { 9, "akl {0}", "akulo {0}" },
+ { 10, "akl {0}", "akulo {0}" },
+ { 11, "akl {0}", "akulo {0}" },
+ { 12, "akr {0}", "akrǝ {0}" },
+ { 13, "akr {0}", "akrǝ {0}" },
+ { 14, "akr {0}", "akrǝ {0}" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_13[] = {
+ { 3, "{0} হা", "{0} হাজার" },
+ { 4, "{0} হা", "{0} হাজার" },
+ { 5, "{0} লা", "{0} লাখ" },
+ { 6, "{0} লা", "{0} লাখ" },
+ { 7, "{0} কো", "{0} কোটি" },
+ { 8, "{0} কো", "{0} কোটি" },
+ { 9, "{0} কো", "{0} কোটি" },
+ { 10, "{0}শত কো", "{0} কোটি" },
+ { 11, "{0}কো", "{0} কোটি" },
+ { 12, "{0} লা'.'কো'.'", "{0} লাখ কোটি" },
+ { 13, "{0} লা'.'কো'.'", "{0} লাখ কোটি" },
+ { 14, "{0} লা'.'কো'.'", "{0} লাখ কোটি" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_14[] = {
+ { 3, "{0}k", "{0} miliad" },
+ { 4, "{0}k", "{0} miliad" },
+ { 5, "{0}k", "{0} miliad" },
+ { 6, "{0}M", "{0} milion" },
+ { 7, "{0}M", "{0} milion" },
+ { 8, "{0}M", "{0} milion" },
+ { 9, "{0}G", "{0} miliard" },
+ { 10, "{0}G", "{0} miliard" },
+ { 11, "{0}G", "{0} miliard" },
+ { 12, "{0}T", "{0} bilion" },
+ { 13, "{0}T", "{0} bilion" },
+ { 14, "{0}T", "{0} bilion" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_15[] = {
+ { 3, "{0}के", "{0} रोजा" },
+ { 4, "{0}के", "{0} रोजा" },
+ { 5, "{0}के", "{0} रोजा" },
+ { 6, "{0}एम", "{0} निजुत" },
+ { 7, "{0}एम", "{0} निजुत" },
+ { 8, "{0}एम", "{0} निजुत" },
+ { 9, "{0}बि", "{0} बिलियन" },
+ { 10, "{0}बि", "{0} बिलियन" },
+ { 11, "{0}बि", "{0} बिलियन" },
+ { 12, "{0}ति", "{0} त्रिलियन" },
+ { 13, "{0}ति", "{0} त्रिलियन" },
+ { 14, "{0}ति", "{0} त्रिलियन" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_16[] = {
+ { 3, "{0} hilj'.'", "{0} hiljada" },
+ { 4, "{0} hilj'.'", "{0} hiljada" },
+ { 5, "{0} hilj'.'", "{0} hiljada" },
+ { 6, "{0} mil'.'", "{0} miliona" },
+ { 7, "{0} mil'.'", "{0} miliona" },
+ { 8, "{0} mil'.'", "{0} miliona" },
+ { 9, "{0} mlrd'.'", "{0} milijardi" },
+ { 10, "{0} mlrd'.'", "{0} milijardi" },
+ { 11, "{0} mlrd'.'", "{0} milijardi" },
+ { 12, "{0} bil'.'", "{0} biliona" },
+ { 13, "{0} bil'.'", "{0} biliona" },
+ { 14, "{0} bil'.'", "{0} biliona" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_17[] = {
+ { 3, "{0}", "{0}" },
+ { 4, "{0} хиљ", "{0} хиљ" },
+ { 5, "{0} хиљ", "{0} хиљ" },
+ { 6, "{0} мил", "{0} мил" },
+ { 7, "{0} мил", "{0} мил" },
+ { 8, "{0} мил", "{0} мил" },
+ { 9, "{0} млрд", "{0} млрд" },
+ { 10, "{0} млрд", "{0} млрд" },
+ { 11, "{0} млрд", "{0} млрд" },
+ { 12, "{0} бил", "{0} бил" },
+ { 13, "{0} бил", "{0} бил" },
+ { 14, "{0} бил", "{0} бил" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_18[] = {
+ { 3, "{0} k", "{0} milers" },
+ { 4, "{0} k", "{0} milers" },
+ { 5, "{0} k", "{0} milers" },
+ { 6, "{0} M", "{0} milions" },
+ { 7, "{0} M", "{0} milions" },
+ { 8, "{0} M", "{0} milions" },
+ { 9, "{0} M", "{0} milers de milions" },
+ { 10, "{0} kM", "{0} milers de milions" },
+ { 11, "{0} kM", "{0} milers de milions" },
+ { 12, "{0} B", "{0} bilions" },
+ { 13, "{0} B", "{0} bilions" },
+ { 14, "{0} B", "{0} bilions" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_19[] = {
+ { 3, "{0} эзар", "{0} эзар" },
+ { 4, "{0} эзар", "{0} эзар" },
+ { 5, "{0} эзар", "{0} эзар" },
+ { 6, "{0} млн", "{0} миллион" },
+ { 7, "{0} млн", "{0} миллион" },
+ { 8, "{0} млн", "{0} миллион" },
+ { 9, "{0} млрд", "{0} миллиард" },
+ { 10, "{0} млрд", "{0} миллиард" },
+ { 11, "{0} млрд", "{0} миллиард" },
+ { 12, "{0} трлн", "{0} триллион" },
+ { 13, "{0} трлн", "{0} триллион" },
+ { 14, "{0} трлн", "{0} триллион" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_20[] = {
+ { 3, "{0}K", "{0} ka libo" },
+ { 4, "{0}K", "{0} ka libo" },
+ { 5, "{0}K", "{0} ka libo" },
+ { 6, "{0}M", "{0} ka milyon" },
+ { 7, "{0}M", "{0} ka milyon" },
+ { 8, "{0}M", "{0} ka milyon" },
+ { 9, "{0}B", "{0} ka bilyon" },
+ { 10, "{0}B", "{0} ka bilyon" },
+ { 11, "{0}B", "{0} ka bilyon" },
+ { 12, "{0}T", "{0} ka trilyon" },
+ { 13, "{0}T", "{0} ka trilyon" },
+ { 14, "{0}T", "{0} ka trilyon" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_21[] = {
+ { 3, "{0}K", "{0} ᎢᏯᎦᏴᎵ" },
+ { 4, "{0}K", "{0} ᎢᏯᎦᏴᎵ" },
+ { 5, "{0}K", "{0} ᎢᏯᎦᏴᎵ" },
+ { 6, "{0}M", "{0} ᎢᏳᏆᏗᏅᏛ" },
+ { 7, "{0}M", "{0} ᎢᏳᏆᏗᏅᏛ" },
+ { 8, "{0}M", "{0} ᎢᏳᏆᏗᏅᏛ" },
+ { 9, "{0}B", "{0} ᎢᏯᏔᎳᏗᏅᏛ" },
+ { 10, "{0}B", "{0} ᎢᏯᏔᎳᏗᏅᏛ" },
+ { 11, "{0}B", "{0} ᎢᏯᏔᎳᏗᏅᏛ" },
+ { 12, "{0}T", "{0} ᎢᏯᏦᎠᏗᏅᏛ" },
+ { 13, "{0}T", "{0} ᎢᏯᏦᎠᏗᏅᏛ" },
+ { 14, "{0}T", "{0} ᎢᏯᏦᎠᏗᏅᏛ" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_22[] = {
+ { 3, "{0} tis'.'", "{0} tisíc" },
+ { 4, "{0} tis'.'", "{0} tisíc" },
+ { 5, "{0} tis'.'", "{0} tisíc" },
+ { 6, "{0} mil'.'", "{0} milionů" },
+ { 7, "{0} mil'.'", "{0} milionů" },
+ { 8, "{0} mil'.'", "{0} milionů" },
+ { 9, "{0} mld'.'", "{0} miliard" },
+ { 10, "{0} mld'.'", "{0} miliard" },
+ { 11, "{0} mld'.'", "{0} miliard" },
+ { 12, "{0} bil'.'", "{0} bilionů" },
+ { 13, "{0} bil'.'", "{0} bilionů" },
+ { 14, "{0} bil'.'", "{0} bilionů" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_23[] = {
+ { 3, "{0} пин", "{0} пин" },
+ { 4, "{0} пин", "{0} пин" },
+ { 5, "{0} пин", "{0} пин" },
+ { 6, "{0} млн", "{0} млн" },
+ { 7, "{0} млн", "{0} млн" },
+ { 8, "{0} млн", "{0} млн" },
+ { 9, "{0} млрд", "{0} млрд" },
+ { 10, "{0} млрд", "{0} млрд" },
+ { 11, "{0} млрд", "{0} млрд" },
+ { 12, "{0} трлн", "{0} трлн" },
+ { 13, "{0} трлн", "{0} трлн" },
+ { 14, "{0} трлн", "{0} трлн" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_24[] = {
+ { 3, "{0}K", "{0} mil" },
+ { 4, "{0}K", "{0} mil" },
+ { 5, "{0}K", "{0} mil" },
+ { 6, "{0}M", "{0} miliwn" },
+ { 7, "{0}M", "{0} miliwn" },
+ { 8, "{0}M", "{0} miliwn" },
+ { 9, "{0}B", "{0} biliwn" },
+ { 10, "{0}B", "{0} biliwn" },
+ { 11, "{0}B", "{0} biliwn" },
+ { 12, "{0}T", "{0} triliwn" },
+ { 13, "{0}T", "{0} triliwn" },
+ { 14, "{0}T", "{0} triliwn" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_25[] = {
+ { 3, "{0} t", "{0} tusind" },
+ { 4, "{0} t", "{0} tusind" },
+ { 5, "{0} t", "{0} tusind" },
+ { 6, "{0} mio'.'", "{0} millioner" },
+ { 7, "{0} mio'.'", "{0} millioner" },
+ { 8, "{0} mio'.'", "{0} millioner" },
+ { 9, "{0} mia'.'", "{0} milliarder" },
+ { 10, "{0} mia'.'", "{0} milliarder" },
+ { 11, "{0} mia'.'", "{0} milliarder" },
+ { 12, "{0} bio'.'", "{0} billioner" },
+ { 13, "{0} bio'.'", "{0} billioner" },
+ { 14, "{0} bio'.'", "{0} billioner" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_26[] = {
+ { 3, NULL, "{0} Tausend" },
+ { 6, "{0} Mio.", "{0} Millionen" },
+ { 9, "{0} Mrd.", "{0} Milliarden" },
+ { 12, "{0} Bio.", "{0} Billionen" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_27[] = {
+ { 3, "{0}", "{0} Tausend" },
+ { 4, "{0}", "{0} Tausend" },
+ { 5, "{0}", "{0} Tausend" },
+ { 6, "{0} Mio'.'", "{0} Millionen" },
+ { 7, "{0} Mio'.'", "{0} Millionen" },
+ { 8, "{0} Mio'.'", "{0} Millionen" },
+ { 9, "{0} Mrd'.'", "{0} Milliarden" },
+ { 10, "{0} Mrd'.'", "{0} Milliarden" },
+ { 11, "{0} Mrd'.'", "{0} Milliarden" },
+ { 12, "{0} Bio'.'", "{0} Billionen" },
+ { 13, "{0} Bio'.'", "{0} Billionen" },
+ { 14, "{0} Bio'.'", "{0} Billionen" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_28[] = {
+ { 3, "{0} tys'.'", "{0} tysac" },
+ { 4, "{0} tys'.'", "{0} tysac" },
+ { 5, "{0} tys'.'", "{0} tysac" },
+ { 6, "{0} mio'.'", "{0} milionow" },
+ { 7, "{0} mio'.'", "{0} milionow" },
+ { 8, "{0} mio'.'", "{0} milionow" },
+ { 9, "{0} mrd'.'", "{0} miliardow" },
+ { 10, "{0} mrd'.'", "{0} miliardow" },
+ { 11, "{0} mrd'.'", "{0} miliardow" },
+ { 12, "{0} bil'.'", "{0} bilionow" },
+ { 13, "{0} bil'.'", "{0} bilionow" },
+ { 14, "{0} bil'.'", "{0} bilionow" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_29[] = {
+ { 3, "{0}K", "སྟོང་ཕྲག {0}" },
+ { 4, "{0}K", "ཁྲི་ཕྲག {0}" },
+ { 5, "{0}K", "འབུམ་ཕྲག {0}" },
+ { 6, "{0}M", "ས་ཡ་ {0}" },
+ { 7, "{0}M", "བྱེ་བ་ {0}" },
+ { 8, "{0}M", "དུང་ཕྱུར་ {0}" },
+ { 9, "{0}G", "དུང་ཕྱུར་ {0}" },
+ { 10, "{0}G", "དུང་ཕྱུར་བརྒྱ་ {0}" },
+ { 11, "{0}G", "དུང་ཕྱུར་སྟོང {0}" },
+ { 12, "{0}T", "དུང་ཕྱུར་ཁྲི་ {0}" },
+ { 13, "{0}T", "དུང་ཕྱུར་འབུམ་ {0}" },
+ { 14, "{0}T", "དུང་ཕྱུར་ས་ཡ་ {0}" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_30[] = {
+ { 3, "{0}K", "akpe {0}" },
+ { 4, "{0}K", "akpe {0}" },
+ { 5, "{0}K", "akpe {0}" },
+ { 6, "{0}M", "miliɔn {0}" },
+ { 7, "{0}M", "miliɔn {0}" },
+ { 8, "{0}M", "miliɔn {0}" },
+ { 9, "{0}B", "biliɔn {0}" },
+ { 10, "{0}B", "biliɔn {0}" },
+ { 11, "{0}B", "biliɔn {0}" },
+ { 12, "{0}T", "{0} triliɔn" },
+ { 13, "{0}T", "triliɔn {0}" },
+ { 14, "{0}T", "triliɔn {0}" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_31[] = {
+ { 3, "{0} χιλ'.'", "{0} χιλιάδες" },
+ { 4, "{0} χιλ'.'", "{0} χιλιάδες" },
+ { 5, "{0} χιλ'.'", "{0} χιλιάδες" },
+ { 6, "{0} εκ'.'", "{0} εκατομμύρια" },
+ { 7, "{0} εκ'.'", "{0} εκατομμύρια" },
+ { 8, "{0} εκ'.'", "{0} εκατομμύρια" },
+ { 9, "{0} δισ'.'", "{0} δισεκατομμύρια" },
+ { 10, "{0} δισ'.'", "{0} δισεκατομμύρια" },
+ { 11, "{0} δισ'.'", "{0} δισεκατομμύρια" },
+ { 12, "{0} τρισ'.'", "{0} τρισεκατομμύρια" },
+ { 13, "{0} τρισ'.'", "{0} τρισεκατομμύρια" },
+ { 14, "{0} τρισ'.'", "{0} τρισεκατομμύρια" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_32[] = {
+ { 3, "{0}K", "{0} thousand" },
+ { 6, "{0}M", "{0} million" },
+ { 9, "{0}B", "{0} billion" },
+ { 12, "{0}T", "{0} trillion" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_33[] = {
+ { 3, "{0}K", "{0} thousand" },
+ { 4, "{0}K", "{0} thousand" },
+ { 5, "{0}K", "{0} thousand" },
+ { 6, "{0}M", "{0} million" },
+ { 7, "{0}M", "{0} million" },
+ { 8, "{0}M", "{0} million" },
+ { 9, "{0}B", "{0} billion" },
+ { 10, "{0}B", "{0} billion" },
+ { 11, "{0}B", "{0} billion" },
+ { 12, "{0}T", "{0} trillion" },
+ { 13, "{0}T", "{0} trillion" },
+ { 14, "{0}T", "{0} trillion" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_34[] = {
+ { 3, "{0}k", "{0} thousand" },
+ { 4, "{0}k", "{0} thousand" },
+ { 5, "{0}k", "{0} thousand" },
+ { 6, "{0}m", "{0} million" },
+ { 7, "{0}m", "{0} million" },
+ { 8, "{0}m", "{0} million" },
+ { 9, "{0}bn", "{0} billion" },
+ { 10, "{0}bn", "{0} billion" },
+ { 11, "{0}bn", "{0} billion" },
+ { 12, "{0}tn", "{0} trillion" },
+ { 13, "{0}tn", "{0} trillion" },
+ { 14, "{0}tn", "{0} trillion" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_35[] = {
+ { 3, "{0}K", NULL },
+ { 5, "{0}L", NULL },
+ { 7, "{0}Cr", NULL },
+};
+
+static const CompactDecimalPattern locale_compact_arr_36[] = {
+ { 3, "{0}k", "{0} mil" },
+ { 4, "{0}k", "{0} mil" },
+ { 5, "{0}k", "{0} mil" },
+ { 6, "{0}M", "{0} miliono" },
+ { 7, "{0}M", "{0} milionoj" },
+ { 8, "{0}M", "{0} milionoj" },
+ { 9, "{0}G", "{0} miliardoj" },
+ { 10, "{0}G", "{0} miliardoj" },
+ { 11, "{0}G", "{0} miliardoj" },
+ { 12, "{0}T", "{0} duilionoj" },
+ { 13, "{0}T", "{0} duilionoj" },
+ { 14, "{0}T", "{0} duilionoj" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_37[] = {
+ { 3, "{0} mil", "{0} mil" },
+ { 4, "{0} mil", "{0} mil" },
+ { 5, "{0} mil", "{0} mil" },
+ { 6, "{0} M", "{0} millones" },
+ { 7, "{0} M", "{0} millones" },
+ { 8, "{0} M", "{0} millones" },
+ { 9, "{0} M", "{0} mil millones" },
+ { 10, "{0} mil M", "{0} mil millones" },
+ { 11, "{0} mil M", "{0} mil millones" },
+ { 12, "{0} B", "{0} billones" },
+ { 13, "{0} B", "{0} billones" },
+ { 14, "{0} B", "{0} billones" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_38[] = {
+ { 3, "{0} K", "{0} mil" },
+ { 4, "{0} k", "{0} mil" },
+ { 5, "{0} k", "{0} mil" },
+ { 6, "{0} M", "{0} millones" },
+ { 7, "{0} M", "{0} millones" },
+ { 8, "{0} M", "{0} millones" },
+ { 9, "{0} M", "{0} mil millones" },
+ { 10, "{0} mil M", "{0} mil millones" },
+ { 11, "{0} mil M", "{0} mil millones" },
+ { 12, "{0} B", "{0} billones" },
+ { 13, "{0} B", "{0} billones" },
+ { 14, "{0} B", "{0} billones" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_39[] = {
+ { 3, "{0} k", "{0} mil" },
+ { 4, "{0} k", "{0} mil" },
+ { 5, "{0} k", "{0} mil" },
+ { 6, "{0} M", "{0} millones" },
+ { 7, "{0} M", "{0} millones" },
+ { 8, "{0} M", "{0} millones" },
+ { 9, "{0} M", "{0} mil millones" },
+ { 10, "{0} mil M", "{0} mil millones" },
+ { 11, "{0} mil M", "{0} mil millones" },
+ { 12, "{0} B", "{0} billones" },
+ { 13, "{0} B", "{0} billones" },
+ { 14, "{0} B", "{0} billones" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_40[] = {
+ { 3, "{0} K", "{0} mil" },
+ { 4, "{0} K", "{0} mil" },
+ { 5, "{0} K", "{0} mil" },
+ { 6, "{0} M", "{0} millones" },
+ { 7, "{0} M", "{0} millones" },
+ { 8, "{0} M", "{0} millones" },
+ { 9, "{0} M", "{0} mil millones" },
+ { 10, "{0} mil M", "{0} mil millones" },
+ { 11, "{0} mil M", "{0} mil millones" },
+ { 12, "{0} B", "{0} billones" },
+ { 13, "{0} B", "{0} billones" },
+ { 14, "{0} B", "{0} billones" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_41[] = {
+ { 3, "{0} tuh", "{0} tuhat" },
+ { 4, "{0} tuh", "{0} tuhat" },
+ { 5, "{0} tuh", "{0} tuhat" },
+ { 6, "{0} mln", "{0} miljonit" },
+ { 7, "{0} mln", "{0} miljonit" },
+ { 8, "{0} mln", "{0} miljonit" },
+ { 9, "{0} mld", "{0} miljardit" },
+ { 10, "{0} mld", "{0} miljardit" },
+ { 11, "{0} mld", "{0} miljardit" },
+ { 12, "{0} trln", "{0} triljonit" },
+ { 13, "{0} trln", "{0} triljonit" },
+ { 14, "{0} trln", "{0} triljonit" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_42[] = {
+ { 3, "{0}", "{0}" },
+ { 4, "{0}", "{0}" },
+ { 5, "{0}", "{0}" },
+ { 6, "{0} M", "{0} milioi" },
+ { 7, "{0} M", "{0} milioi" },
+ { 8, "{0} M", "{0} milioi" },
+ { 9, "{0} M", "{0} milioi" },
+ { 10, "{0} M", "{0} milioi" },
+ { 11, "{0} M", "{0} milioi" },
+ { 12, "{0} B", "{0} bilioi" },
+ { 13, "{0} B", "{0} bilioi" },
+ { 14, "{0} B", "{0} bilioi" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_43[] = {
+ { 3, "{0} هزار", "{0} هزار" },
+ { 4, "{0} هزار", "{0} هزار" },
+ { 5, "{0} هزار", "{0} هزار" },
+ { 6, "{0} میلیون", "{0} میلیون" },
+ { 7, "{0} میلیون", "{0} میلیون" },
+ { 8, "{0} میلیون", "{0} میلیون" },
+ { 9, "{0} میلیارد", "{0} میلیارد" },
+ { 10, "{0} میلیارد", "{0} میلیارد" },
+ { 11, "{0} میلیارد", "{0} میلیارد" },
+ { 12, "{0} تریلیون", "{0} هزارمیلیارد" },
+ { 13, "{0} تریلیون", "{0} هزارمیلیارد" },
+ { 14, "{0} تریلیون", "{0} هزارمیلیارد" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_44[] = {
+ { 3, "{0}𞤓", "{0} 𞤵𞤶𞤵𞤲𞤫𞤪𞤫" },
+ { 4, "{0}𞤓", "{0} 𞤵𞤶𞤵𞤲𞤫𞤪𞤫" },
+ { 5, "{0}𞤓", "{0} 𞤵𞤶𞤵𞤲𞤫𞤪𞤫" },
+ { 6, "{0}𞤁", "{0} 𞤣𞤵𞤦𞤵𞤲𞤫𞤪𞤫" },
+ { 7, "{0}𞤁", "{0} 𞤣𞤵𞤦𞤵𞤲𞤫𞤪𞤫" },
+ { 8, "{0}𞤁", "{0} 𞤣𞤵𞤦𞤵𞤲𞤫𞤪𞤫" },
+ { 9, "{0}𞤁𞤶", "{0} 𞤣𞤵𞤶𞤵𞤲𞤫𞤪𞤫" },
+ { 10, "{0}𞤁𞤶", "{0} 𞤣𞤵𞤶𞤵𞤲𞤫𞤪𞤫" },
+ { 11, "{0}𞤁𞤶", "{0} 𞤣𞤵𞤶𞤵𞤲𞤫𞤪𞤫" },
+ { 12, "{0}𞤚", "{0} 𞤼𞤵𞤶𞤵𞤲𞤫𞤪𞤫" },
+ { 13, "{0}𞤚", "{0} 𞤼𞤵𞤶𞤵𞤲𞤫𞤪𞤫" },
+ { 14, "{0}𞤚", "{0} 𞤼𞤵𞤶𞤵𞤲𞤫𞤪𞤫" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_45[] = {
+ { 3, "{0} t'.'", "{0} tuhatta" },
+ { 4, "{0} t'.'", "{0} tuhatta" },
+ { 5, "{0} t'.'", "{0} tuhatta" },
+ { 6, "{0} milj'.'", "{0} miljoonaa" },
+ { 7, "{0} milj'.'", "{0} miljoonaa" },
+ { 8, "{0} milj'.'", "{0} miljoonaa" },
+ { 9, "{0} mrd'.'", "{0} miljardia" },
+ { 10, "{0} mrd'.'", "{0} miljardia" },
+ { 11, "{0} mrd'.'", "{0} miljardia" },
+ { 12, "{0} bilj'.'", "{0} biljoonaa" },
+ { 13, "{0} bilj'.'", "{0} biljoonaa" },
+ { 14, "{0} bilj'.'", "{0} biljoonaa" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_46[] = {
+ { 3, "{0}K", "{0} na libo" },
+ { 4, "{0}K", "{0} na libo" },
+ { 5, "{0}K", "{0} na libo" },
+ { 6, "{0}M", "{0} na milyon" },
+ { 7, "{0}M", "{0} na milyon" },
+ { 8, "{0}M", "{0} na milyon" },
+ { 9, "{0}B", "{0} na bilyon" },
+ { 10, "{0}B", "{0} na bilyon" },
+ { 11, "{0}B", "{0} na bilyon" },
+ { 12, "{0}T", "{0} na trilyon" },
+ { 13, "{0}T", "{0} na trilyon" },
+ { 14, "{0}T", "{0} na trilyon" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_47[] = {
+ { 3, "{0} tús'.'", "{0} túsund" },
+ { 4, "{0} tús'.'", "{0} túsund" },
+ { 5, "{0} tús'.'", "{0} túsund" },
+ { 6, "{0} mió'.'", "{0} milliónir" },
+ { 7, "{0} mió'.'", "{0} milliónir" },
+ { 8, "{0} mió'.'", "{0} milliónir" },
+ { 9, "{0} mia'.'", "{0} milliardir" },
+ { 10, "{0} mia'.'", "{0} milliardir" },
+ { 11, "{0} mia'.'", "{0} milliardir" },
+ { 12, "{0} bió'.'", "{0} billiónir" },
+ { 13, "{0} bió'.'", "{0} billiónir" },
+ { 14, "{0} bió'.'", "{0} billiónir" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_48[] = {
+ { 3, "{0} k", "{0} mille" },
+ { 6, "{0} M", "{0} millions" },
+ { 9, "{0} Md", "{0} milliards" },
+ { 12, "{0} B", "{0} billions" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_49[] = {
+ { 3, "{0} k", "{0} mille" },
+ { 4, "{0} k", "{0} mille" },
+ { 5, "{0} k", "{0} mille" },
+ { 6, "{0} M", "{0} millions" },
+ { 7, "{0} M", "{0} millions" },
+ { 8, "{0} M", "{0} millions" },
+ { 9, "{0} Md", "{0} milliards" },
+ { 10, "{0} Md", "{0} milliards" },
+ { 11, "{0} Md", "{0} milliards" },
+ { 12, "{0} Bn", "{0} billions" },
+ { 13, "{0} Bn", "{0} billions" },
+ { 14, "{0} Bn", "{0} billions" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_50[] = {
+ { 3, "{0} k", "{0} mille" },
+ { 4, "{0} k", "{0} mille" },
+ { 5, "{0} k", "{0} mille" },
+ { 6, "{0} M", "{0} millions" },
+ { 7, "{0} M", "{0} millions" },
+ { 8, "{0} M", "{0} millions" },
+ { 9, "{0} G", "{0} milliards" },
+ { 10, "{0} G", "{0} milliards" },
+ { 11, "{0} G", "{0} milliards" },
+ { 12, "{0} T", "{0} billions" },
+ { 13, "{0} T", "{0} billions" },
+ { 14, "{0} T", "{0} billions" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_51[] = {
+ { 3, "{0}K", "{0} tûzen" },
+ { 4, "{0}K", "{0} tûzen" },
+ { 5, "{0}K", "{0} tûzen" },
+ { 6, "{0} mln'.'", "{0} miljoen" },
+ { 7, "{0} mln'.'", "{0} miljoen" },
+ { 8, "{0} mln'.'", "{0} miljoen" },
+ { 9, "{0} mld'.'", "{0} miljard" },
+ { 10, "{0} mld'.'", "{0} miljard" },
+ { 11, "{0} mld'.'", "{0} miljard" },
+ { 12, "{0} bln'.'", "{0} biljoen" },
+ { 13, "{0} bln'.'", "{0} biljoen" },
+ { 14, "{0} bln'.'", "{0} biljoen" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_52[] = {
+ { 3, "{0}k", "{0} míle" },
+ { 4, "{0}k", "{0} míle" },
+ { 5, "{0}k", "{0} míle" },
+ { 6, "{0}M", "{0} milliún" },
+ { 7, "{0}M", "{0} milliún" },
+ { 8, "{0}M", "{0} milliún" },
+ { 9, "{0}B", "{0} billiún" },
+ { 10, "{0}B", "{0} billiún" },
+ { 11, "{0}B", "{0} billiún" },
+ { 12, "{0}T", "{0} trilliún" },
+ { 13, "{0}T", "{0} trilliún" },
+ { 14, "{0}T", "{0} trilliún" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_53[] = {
+ { 3, "{0}K", "{0} mìle" },
+ { 4, "{0}K", "{0} mìle" },
+ { 5, "{0}K", "{0} mìle" },
+ { 6, "{0}M", "{0} millean" },
+ { 7, "{0}M", "{0} millean" },
+ { 8, "{0}M", "{0} millean" },
+ { 9, "{0}B", "{0} billean" },
+ { 10, "{0}B", "{0} billean" },
+ { 11, "{0}B", "{0} billean" },
+ { 12, "{0}T", "{0} trillean" },
+ { 13, "{0}T", "{0} trillean" },
+ { 14, "{0}T", "{0} trillean" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_54[] = {
+ { 3, "{0}", "{0}" },
+ { 4, "{0}", "{0}" },
+ { 5, "{0}", "{0}" },
+ { 6, "{0} M", "{0} millóns" },
+ { 7, "{0} M", "{0} millóns" },
+ { 8, "{0} M", "{0} millóns" },
+ { 9, "{0} M", "{0} millóns" },
+ { 10, "{0} M", "{0} millóns" },
+ { 11, "{0} M", "{0} millóns" },
+ { 12, "{0} B", "{0} billóns" },
+ { 13, "{0} B", "{0} billóns" },
+ { 14, "{0} B", "{0} billóns" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_55[] = {
+ { 3, "{0} Tsg'.'", "{0} Tuusig" },
+ { 4, "{0} Tsg'.'", "{0} Tuusig" },
+ { 5, "{0} Tsg'.'", "{0} Tuusig" },
+ { 6, "{0} Mio'.'", "{0} Millioone" },
+ { 7, "{0} Mio'.'", "{0} Millioone" },
+ { 8, "{0} Mio'.'", "{0} Millioone" },
+ { 9, "{0} Mrd'.'", "{0} Milliarde" },
+ { 10, "{0} Mrd'.'", "{0} Milliarde" },
+ { 11, "{0} Mrd'.'", "{0} Milliarde" },
+ { 12, "{0} Bio'.'", "{0} Billioone" },
+ { 13, "{0} Bio'.'", "{0} Billioone" },
+ { 14, "{0} Bio'.'", "{0} Billioone" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_56[] = {
+ { 3, "{0} હજાર", "{0} હજાર" },
+ { 4, "{0} હજાર", "{0} હજાર" },
+ { 5, "{0} લાખ", "{0} લાખ" },
+ { 6, "{0} લાખ", "{0} લાખ" },
+ { 7, "{0} કરોડ", "{0} કરોડ" },
+ { 8, "{0} કરોડ", "{0} કરોડ" },
+ { 9, "{0} અબજ", "{0} અબજ" },
+ { 10, "{0} અબજ", "{0} અબજ" },
+ { 11, "{0} નિખર્વ", "{0} નિખર્વ" },
+ { 12, "{0} મહાપદ્મ", "{0} મહાપદ્મ" },
+ { 13, "{0} શંકુ", "{0} શંકુ" },
+ { 14, "{0} જલધિ", "{0} જલધિ" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_57[] = {
+ { 3, "{0}K", "Dubu {0}" },
+ { 4, "{0}D", "Dubu {0}" },
+ { 5, "{0}D", "Dubu {0}" },
+ { 6, "{0}M", "Miliyan {0}" },
+ { 7, "{0}M", "Miliyan {0}" },
+ { 8, "{0}M", "Miliyan {0}" },
+ { 9, "{0}B", "Biliyan {0}" },
+ { 10, "{0}B", "Biliyan {0}" },
+ { 11, "{0}B", "Biliyan {0}" },
+ { 12, "{0}T", "Triliyan {0}" },
+ { 13, "{0}T", "Triliyan {0}" },
+ { 14, "{0}T", "Triliyan {0}" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_58[] = {
+ { 3, "{0}K", "{0} אלף" },
+ { 4, "{0}K", "{0} אלף" },
+ { 5, "{0}K", "{0} אלף" },
+ { 6, "{0}M", "{0} מיליון" },
+ { 7, "{0}M", "{0} מיליון" },
+ { 8, "{0}M", "{0} מיליון" },
+ { 9, "{0}B", "{0} מיליארד" },
+ { 10, "{0}B", "{0} מיליארד" },
+ { 11, "{0}B", "{0} מיליארד" },
+ { 12, "{0}T", "{0} טריליון" },
+ { 13, "{0}T", "{0} טריליון" },
+ { 14, "{0}T", "{0} טריליון" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_59[] = {
+ { 3, "{0} हज़ार", "{0} हज़ार" },
+ { 4, "{0} हज़ार", "{0} हज़ार" },
+ { 5, "{0} लाख", "{0} लाख" },
+ { 6, "{0} लाख", "{0} लाख" },
+ { 7, "{0} क॰", "{0} करोड़" },
+ { 8, "{0} क॰", "{0} करोड़" },
+ { 9, "{0} अ॰", "{0} अरब" },
+ { 10, "{0} अ॰", "{0} अरब" },
+ { 11, "{0} ख॰", "{0} खरब" },
+ { 12, "{0} ख॰", "{0} खरब" },
+ { 13, "{0} नील", "{0} खरब" },
+ { 14, "{0} नील", "{0} खरब" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_60[] = {
+ { 3, "{0}K", "{0} thousand" },
+ { 4, "{0}K", "{0} thousand" },
+ { 5, "{0}L", "{0} lakh" },
+ { 6, "{0}L", "{0} lakh" },
+ { 7, "{0}Cr", "{0} crore" },
+ { 8, "{0}Cr", "{0} crore" },
+ { 9, "{0}Cr", "{0} crore" },
+ { 10, "{0}KCr", "{0} crore" },
+ { 11, "{0}KCr", "{0} crore" },
+ { 12, "{0}LCr", "{0} lakh crore" },
+ { 13, "{0}LCr", "{0} lakh crore" },
+ { 14, "{0}LCr", "{0} lakh crore" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_61[] = {
+ { 3, "{0} tis'.'", "{0} tisuća" },
+ { 4, "{0} tis'.'", "{0} tisuća" },
+ { 5, "{0} tis'.'", "{0} tisuća" },
+ { 6, "{0} mil'.'", "{0} milijuna" },
+ { 7, "{0} mil'.'", "{0} milijuna" },
+ { 8, "{0} mil'.'", "{0} milijuna" },
+ { 9, "{0} mlr'.'", "{0} milijardi" },
+ { 10, "{0} mlr'.'", "{0} milijardi" },
+ { 11, "{0} mlr'.'", "{0} milijardi" },
+ { 12, "{0} bil'.'", "{0} bilijuna" },
+ { 13, "{0} bil'.'", "{0} bilijuna" },
+ { 14, "{0} bil'.'", "{0} bilijuna" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_62[] = {
+ { 3, "{0} E", "{0} ezer" },
+ { 4, "{0} E", "{0} ezer" },
+ { 5, "{0} E", "{0} ezer" },
+ { 6, "{0} M", "{0} millió" },
+ { 7, "{0} M", "{0} millió" },
+ { 8, "{0} M", "{0} millió" },
+ { 9, "{0} Mrd", "{0} milliárd" },
+ { 10, "{0} Mrd", "{0} milliárd" },
+ { 11, "{0} Mrd", "{0} milliárd" },
+ { 12, "{0} B", "{0} billió" },
+ { 13, "{0} B", "{0} billió" },
+ { 14, "{0} B", "{0} billió" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_63[] = {
+ { 3, "{0} հզր", "{0} հազար" },
+ { 4, "{0} հզր", "{0} հազար" },
+ { 5, "{0} հզր", "{0} հազար" },
+ { 6, "{0} մլն", "{0} միլիոն" },
+ { 7, "{0} մլն", "{0} միլիոն" },
+ { 8, "{0} մլն", "{0} միլիոն" },
+ { 9, "{0} մլրդ", "{0} միլիարդ" },
+ { 10, "{0} մլրդ", "{0} միլիարդ" },
+ { 11, "{0} մլրդ", "{0} միլիարդ" },
+ { 12, "{0} տրլն", "{0} տրիլիոն" },
+ { 13, "{0} տրլն", "{0} տրիլիոն" },
+ { 14, "{0} տրլն", "{0} տրիլիոն" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_64[] = {
+ { 3, "{0} mil", "{0} milles" },
+ { 4, "{0} mil", "{0} milles" },
+ { 5, "{0} mil", "{0} milles" },
+ { 6, "{0} mln", "{0} milliones" },
+ { 7, "{0} mln", "{0} milliones" },
+ { 8, "{0} mln", "{0} milliones" },
+ { 9, "{0} mld", "{0} milliardos" },
+ { 10, "{0} mld", "{0} milliardos" },
+ { 11, "{0} mld", "{0} milliardos" },
+ { 12, "{0} bln", "{0} billiones" },
+ { 13, "{0} bln", "{0} billiones" },
+ { 14, "{0} bln", "{0} billiones" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_65[] = {
+ { 3, "{0} rb", "{0} ribu" },
+ { 4, "{0} rb", "{0} ribu" },
+ { 5, "{0} rb", "{0} ribu" },
+ { 6, "{0} jt", "{0} juta" },
+ { 7, "{0} jt", "{0} juta" },
+ { 8, "{0} jt", "{0} juta" },
+ { 9, "{0} M", "{0} miliar" },
+ { 10, "{0} M", "{0} miliar" },
+ { 11, "{0} M", "{0} miliar" },
+ { 12, "{0} T", "{0} triliun" },
+ { 13, "{0} T", "{0} triliun" },
+ { 14, "{0} T", "{0} triliun" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_66[] = {
+ { 3, "{0} þ'.'", "{0} þúsund" },
+ { 4, "{0} þ'.'", "{0} þúsund" },
+ { 5, "{0} þ'.'", "{0} þúsund" },
+ { 6, "{0} m'.'", "{0} milljónir" },
+ { 7, "{0} m'.'", "{0} milljónir" },
+ { 8, "{0} m'.'", "{0} milljónir" },
+ { 9, "{0} ma'.'", "{0} milljarðar" },
+ { 10, "{0} ma'.'", "{0} milljarðar" },
+ { 11, "{0} ma'.'", "{0} milljarðar" },
+ { 12, "{0} bn", "{0} billjónir" },
+ { 13, "{0} bn", "{0} billjónir" },
+ { 14, "{0} bn", "{0} billjónir" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_67[] = {
+ { 3, "{0}K", "{0} mila" },
+ { 4, "{0}K", "{0} mila" },
+ { 5, "{0}K", "{0} mila" },
+ { 6, "{0} Mln", "{0} milioni" },
+ { 7, "{0} Mln", "{0} milioni" },
+ { 8, "{0} Mln", "{0} milioni" },
+ { 9, "{0} Mld", "{0} miliardi" },
+ { 10, "{0} Mld", "{0} miliardi" },
+ { 11, "{0} Mld", "{0} miliardi" },
+ { 12, "{0} Bln", "{0} mila miliardi" },
+ { 13, "{0} Bln", "{0} mila miliardi" },
+ { 14, "{0} Bln", "{0} mila miliardi" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_68[] = {
+ { 4, "{0}万", "{0}万" },
+ { 8, "{0}億", "{0}億" },
+ { 12, "{0}兆", "{0}兆" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_69[] = {
+ { 3, "{0}È", "{0} èwu" },
+ { 4, "{0}È", "{0} èwu" },
+ { 5, "{0}È", "{0} èwu" },
+ { 6, "{0}Y", "{0} yuta" },
+ { 7, "{0}Y", "{0} yuta" },
+ { 8, "{0}Y", "{0} yuta" },
+ { 9, "{0}M", "{0} milyar" },
+ { 10, "{0}M", "{0} milyar" },
+ { 11, "{0}M", "{0} milyar" },
+ { 12, "{0}T", "{0} trilyun" },
+ { 13, "{0}T", "{0} trilyun" },
+ { 14, "{0}T", "{0} trilyun" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_70[] = {
+ { 3, "{0} ათ'.'", "{0} ათასი" },
+ { 4, "{0} ათ'.'", "{0} ათასი" },
+ { 5, "{0} ათ'.'", "{0} ათასი" },
+ { 6, "{0} მლნ'.'", "{0} მილიონი" },
+ { 7, "{0} მლნ'.'", "{0} მილიონი" },
+ { 8, "{0} მლნ'.'", "{0} მილიონი" },
+ { 9, "{0} მლრდ'.'", "{0} მილიარდი" },
+ { 10, "{0} მლრდ'.'", "{0} მილიარდი" },
+ { 11, "{0} მლრ'.'", "{0} მილიარდი" },
+ { 12, "{0} ტრლ'.'", "{0} ტრილიონი" },
+ { 13, "{0} ტრლ'.'", "{0} ტრილიონი" },
+ { 14, "{0} ტრლ'.'", "{0} ტრილიონი" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_71[] = {
+ { 3, "{0} mil", "{0} mil" },
+ { 4, "{0} mil", "{0} mil" },
+ { 5, "{0} mil", "{0} mil" },
+ { 6, "{0} M", "{0} milhãu" },
+ { 7, "{0} M", "{0} milhãu" },
+ { 8, "{0} M", "{0} milhãu" },
+ { 9, "{0} MM", "{0} mil milhãu" },
+ { 10, "{0} MM", "{0} mil milhãu" },
+ { 11, "{0} MM", "{0} mil milhãu" },
+ { 12, "{0} Bi", "{0} bilhãu" },
+ { 13, "{0} Bi", "{0} bilhãu" },
+ { 14, "{0} Bi", "{0} bilhãu" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_72[] = {
+ { 3, "{0} mil", "{0} mil" },
+ { 4, "{0} mil", "{0} mil" },
+ { 5, "{0} mil", "{0} mil" },
+ { 6, "{0} mi", "{0} milhão ag" },
+ { 7, "{0} mi", "{0} milhão ag" },
+ { 8, "{0} mi", "{0} milhão ag" },
+ { 9, "{0} bi", "{0} bilhão ag" },
+ { 10, "{0} bi", "{0} bilhão ag" },
+ { 11, "{0} bi", "{0} bilhão ag" },
+ { 12, "{0} tri", "{0} trilhão ag" },
+ { 13, "{0} tri", "{0} trilhão ag" },
+ { 14, "{0} tri", "{0} trilhão ag" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_73[] = {
+ { 3, "{0} мың", "{0} мың" },
+ { 4, "{0} мың", "{0} мың" },
+ { 5, "{0} м'.'", "{0} мың" },
+ { 6, "{0} млн", "{0} миллион" },
+ { 7, "{0} млн", "{0} миллион" },
+ { 8, "{0} млн", "{0} миллион" },
+ { 9, "{0} млрд", "{0} миллиард" },
+ { 10, "{0} млрд", "{0} миллиард" },
+ { 11, "{0} млрд", "{0} миллиард" },
+ { 12, "{0} трлн", "{0} триллион" },
+ { 13, "{0} трлн", "{0} триллион" },
+ { 14, "{0} трлн", "{0} триллион" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_74[] = {
+ { 3, "{0} مىڭ", "{0} مىڭ" },
+ { 4, "{0} مىڭ", "{0} مىڭ" },
+ { 5, "{0} مىڭ", "{0} مىڭ" },
+ { 6, "{0} ميلليون", "{0} ميلليون" },
+ { 7, "{0} ميلليون", "{0} ميلليون" },
+ { 8, "{0} ملن", "{0} ميلليون" },
+ { 9, "{0} ميلليارد", "{0} ميلليارد" },
+ { 10, "{0} ملرد", "{0} ميلليارد" },
+ { 11, "{0} ملرد", "{0} ميلليارد" },
+ { 12, "{0} تريلليون", "{0} تريلليون" },
+ { 13, "{0} ترلن", "{0} تريلليون" },
+ { 14, "{0} ترلن", "{0} تريلليون" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_75[] = {
+ { 3, "{0}ពាន់", "{0} ពាន់" },
+ { 4, "{0} ពាន់", "{0} ពាន់" },
+ { 5, "{0} ពាន់", "{0}ពាន់" },
+ { 6, "{0} លាន", "{0} លាន" },
+ { 7, "{0} លាន", "{0} លាន" },
+ { 8, "{0} លាន", "{0} លាន" },
+ { 9, "{0} ប៊ីលាន", "{0} ប៊ីលាន" },
+ { 10, "{0} ប៊ីលាន", "{0} ប៊ីលាន" },
+ { 11, "{0} ប៊ីលាន", "{0} ប៊ីលាន" },
+ { 12, "{0} ទ្រីលាន", "{0} ទ្រីលាន" },
+ { 13, "{0} ទ្រីលាន", "{0} ទ្រីលាន" },
+ { 14, "{0} ទ្រីលាន", "{0} ទ្រីលាន" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_76[] = {
+ { 3, "{0}ಸಾ", "{0} ಸಾವಿರ" },
+ { 4, "{0}ಸಾ", "{0} ಸಾವಿರ" },
+ { 5, "{0}ಸಾ", "{0} ಸಾವಿರ" },
+ { 6, "{0}ಮಿ", "{0} ಮಿಲಿಯನ್" },
+ { 7, "{0}ಮಿ", "{0} ಮಿಲಿಯನ್" },
+ { 8, "{0}ಮಿ", "{0} ಮಿಲಿಯನ್" },
+ { 9, "{0}ಬಿ", "{0} ಬಿಲಿಯನ್" },
+ { 10, "{0}ಬಿ", "{0} ಬಿಲಿಯನ್" },
+ { 11, "{0}ಬಿ", "{0} ಬಿಲಿಯನ್" },
+ { 12, "{0}ಟ್ರಿ", "{0} ಟ್ರಿಲಿಯನ್" },
+ { 13, "{0}ಟ್ರಿ", "{0} ಟ್ರಿಲಿಯನ್" },
+ { 14, "{0}ಟ್ರಿ", "{0} ಟ್ರಿಲಿಯನ್" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_77[] = {
+ { 3, "{0}천", "{0}천" },
+ { 4, "{0}만", "{0}만" },
+ { 8, "{0}억", "{0}억" },
+ { 12, "{0}조", "{0}조" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_78[] = {
+ { 3, "{0}천", "{0}천" },
+ { 4, "{0}만", "{0}만" },
+ { 5, "{0}만", "{0}만" },
+ { 6, "{0}만", "{0}만" },
+ { 7, "{0}만", "{0}만" },
+ { 8, "{0}억", "{0}억" },
+ { 9, "{0}억", "{0}억" },
+ { 10, "{0}억", "{0}억" },
+ { 11, "{0}억", "{0}억" },
+ { 12, "{0}조", "{0}조" },
+ { 13, "{0}조", "{0}조" },
+ { 14, "{0}조", "{0}조" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_79[] = {
+ { 3, "{0}हज", "{0} हजार" },
+ { 4, "{0}हज", "{0} हजार" },
+ { 5, "{0}लाख", "{0} लाख" },
+ { 6, "{0}लाख", "{0} लाख" },
+ { 7, "{0}कोटी", "{0} कोटी" },
+ { 8, "{0}कोटी", "{0} कोटी" },
+ { 9, "{0}अब्ज", "{0} अब्ज" },
+ { 10, "{0}अब्ज", "{0} अब्ज" },
+ { 11, "{0}निख", "{0} निखर्व" },
+ { 12, "{0}निख", "{0} निखर्व" },
+ { 13, "{0}निख", "{0} निखर्व" },
+ { 14, "{0}हज'.'निख'.'", "{0} हजार निखर्व" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_80[] = {
+ { 3, "{0}hoz", "{0} hozar" },
+ { 4, "{0}hoz", "{0} hozar" },
+ { 5, "{0}lak", "{0} lakh" },
+ { 6, "{0}lak", "{0} lakh" },
+ { 7, "{0}ko", "{0} kotti" },
+ { 8, "{0}ko", "{0} kotti" },
+ { 9, "{0}obz", "{0} obz" },
+ { 10, "{0}obz", "{0} obz" },
+ { 11, "{0}nikh", "{0} nikhorv" },
+ { 12, "{0}nikh", "{0} nikhorv" },
+ { 13, "{0}nikh", "{0} nikhorv" },
+ { 14, "{0}hoz'.'nikh'.'", "{0} hozar nikhorv" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_81[] = {
+ { 3, "{0} tsd", "{0} Dousend" },
+ { 4, "{0} tsd", "{0} Dousend" },
+ { 5, "{0} tsd", "{0} Dousend" },
+ { 6, "{0} Mio", "{0} Milljuhne" },
+ { 7, "{0} Mio", "{0} Millionen" },
+ { 8, "{0} Mio", "{0} Millionen" },
+ { 9, "{0} Mrd", "{0} Milljarde" },
+ { 10, "{0} Mrd", "{0} Milliarden" },
+ { 11, "{0} Mrd", "{0} Milliarden" },
+ { 12, "{0} Bio", "{0} Billjuhn" },
+ { 13, "{0} Bio", "{0} Billionen" },
+ { 14, "{0} Bio", "{0} Billionen" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_82[] = {
+ { 3, "{0}H", "{0} hezar" },
+ { 4, "{0}H", "{0} hezar" },
+ { 5, "{0}H", "{0} hezar" },
+ { 6, "{0}MN", "{0} milyon" },
+ { 7, "{0}MN", "{0} milyon" },
+ { 8, "{0}MN", "{0} milyon" },
+ { 9, "{0}MR", "{0} milyar" },
+ { 10, "{0}MR", "{0} milyar" },
+ { 11, "{0}MR", "{0} milyar" },
+ { 12, "{0}TN", "{0} trilyon" },
+ { 13, "{0}TN", "{0} trilyon" },
+ { 14, "{0}TN", "{0} trilyon" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_83[] = {
+ { 3, "{0} h", "{0} hjar" },
+ { 4, "{0} h", "{0} hjar" },
+ { 5, "{0} h", "{0} hjar" },
+ { 6, "{0} mi", "{0} million" },
+ { 7, "{0} mi", "{0} million" },
+ { 8, "{0} mi", "{0} million" },
+ { 9, "{0} bi", "{0} billion" },
+ { 10, "{0} bi", "{0} billion" },
+ { 11, "{0} bi", "{0} billion" },
+ { 12, "{0} tri", "{0} trillion" },
+ { 13, "{0} tri", "{0} trillion" },
+ { 14, "{0} tri", "{0} trillion" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_84[] = {
+ { 3, "{0} миң", "{0} миң" },
+ { 4, "{0} миң", "{0} миң" },
+ { 5, "{0} миң", "{0} миң" },
+ { 6, "{0} млн", "{0} миллион" },
+ { 7, "{0} млн", "{0} миллион" },
+ { 8, "{0} млн", "{0} миллион" },
+ { 9, "{0} млд", "{0} миллиард" },
+ { 10, "{0} млд", "{0} миллиард" },
+ { 11, "{0} млд", "{0} миллиард" },
+ { 12, "{0} трлн", "{0} триллион" },
+ { 13, "{0} трлн", "{0} триллион" },
+ { 14, "{0} трлн", "{0} триллион" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_85[] = {
+ { 3, "{0} Dsd'.'", "{0} Dausend" },
+ { 4, "{0} Dsd'.'", "{0} Dausend" },
+ { 5, "{0} Dsd'.'", "{0} Dausend" },
+ { 6, "{0} Mio'.'", "{0} Milliounen" },
+ { 7, "{0} Mio'.'", "{0} Milliounen" },
+ { 8, "{0} Mio'.'", "{0} Milliounen" },
+ { 9, "{0} Mrd'.'", "{0} Milliarden" },
+ { 10, "{0} Mrd'.'", "{0} Milliarden" },
+ { 11, "{0} Mrd'.'", "{0} Milliarden" },
+ { 12, "{0} Bio'.'", "{0} Billiounen" },
+ { 13, "{0} Bio'.'", "{0} Billiounen" },
+ { 14, "{0} Bio'.'", "{0} Billiounen" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_86[] = {
+ { 3, "{0}m", "{0} mile" },
+ { 4, "{0}m", "{0} mile" },
+ { 5, "{0}m", "{0} mile" },
+ { 6, "{0} Mln", "{0} miliuns" },
+ { 7, "{0} Mln", "{0} miliuns" },
+ { 8, "{0} Mln", "{0} miliuns" },
+ { 9, "{0} Mlg", "{0} miliarg" },
+ { 10, "{0} Mlg", "{0} miliarg" },
+ { 11, "{0} Mlg", "{0} miliarg" },
+ { 12, "{0} Bln", "{0} biliuns" },
+ { 13, "{0} Bln", "{0} biliuns" },
+ { 14, "{0} Bln", "{0} biliuns" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_87[] = {
+ { 3, "{0} ພັນ", "{0} ພັນ" },
+ { 4, "{0} ພັນ", "{0} ພັນ" },
+ { 5, "{0} ພັນ", "{0} ແສນ" },
+ { 6, "{0} ລ້ານ", "{0} ລ້ານ" },
+ { 7, "{0} ລ້ານ", "{0} ລ້ານ" },
+ { 8, "{0} ລ້ານ", "{0} ລ້ານ" },
+ { 9, "{0} ຕື້", "{0} ຕື້" },
+ { 10, "{0} ຕື້", "{0} ຕື້" },
+ { 11, "{0} ຕື້", "{0} ຕື້" },
+ { 12, "{0} ລ້ານລ້ານ", "{0} ລ້ານລ້ານ" },
+ { 13, "{0}ລລ", "{0} ລ້ານລ້ານ" },
+ { 14, "{0}ລລ", "{0} ລ້ານລ້ານ" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_88[] = {
+ { 3, "{0} tūkst'.'", "{0} tūkstančių" },
+ { 4, "{0} tūkst'.'", "{0} tūkstančių" },
+ { 5, "{0} tūkst'.'", "{0} tūkstančių" },
+ { 6, "{0} mln'.'", "{0} milijonų" },
+ { 7, "{0} mln'.'", "{0} milijonų" },
+ { 8, "{0} mln'.'", "{0} milijonų" },
+ { 9, "{0} mlrd'.'", "{0} milijardų" },
+ { 10, "{0} mlrd'.'", "{0} milijardų" },
+ { 11, "{0} mlrd'.'", "{0} milijardų" },
+ { 12, "{0} trln'.'", "{0} trilijonų" },
+ { 13, "{0} trln'.'", "{0} trilijonų" },
+ { 14, "{0} trln'.'", "{0} trilijonų" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_89[] = {
+ { 3, "{0} tūkst'.'", "{0} tūkstoši" },
+ { 4, "{0} tūkst'.'", "{0} tūkstoši" },
+ { 5, "{0} tūkst'.'", "{0} tūkstoši" },
+ { 6, "{0} milj'.'", "{0} miljoni" },
+ { 7, "{0} milj'.'", "{0} miljoni" },
+ { 8, "{0} milj'.'", "{0} miljoni" },
+ { 9, "{0} mljrd'.'", "{0} miljardi" },
+ { 10, "{0} mljrd'.'", "{0} miljardi" },
+ { 11, "{0} mljrd'.'", "{0} miljardi" },
+ { 12, "{0} trilj'.'", "{0} triljoni" },
+ { 13, "{0} trilj'.'", "{0} triljoni" },
+ { 14, "{0} trilj'.'", "{0} triljoni" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_90[] = {
+ { 3, "{0} илј'.'", "{0} илјади" },
+ { 4, "{0} илј'.'", "{0} илјади" },
+ { 5, "{0} илј'.'", "{0} илјади" },
+ { 6, "{0} мил'.'", "{0} милиони" },
+ { 7, "{0} мил'.'", "{0} милиони" },
+ { 8, "{0} М", "{0} милиони" },
+ { 9, "{0} милј'.'", "{0} милијарди" },
+ { 10, "{0} милј'.'", "{0} милијарди" },
+ { 11, "{0} ми'.'", "{0} милијарди" },
+ { 12, "{0} бил'.'", "{0} билиони" },
+ { 13, "{0} бил'.'", "{0} билиони" },
+ { 14, "{0} бил'.'", "{0} билиони" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_91[] = {
+ { 3, "{0}K", "{0} ആയിരം" },
+ { 4, "{0}K", "{0} ആയിരം" },
+ { 5, "{0}K", "{0} ആയിരം" },
+ { 6, "{0}M", "{0} ദശലക്ഷം" },
+ { 7, "{0}M", "{0} ദശലക്ഷം" },
+ { 8, "{0}M", "{0} ദശലക്ഷം" },
+ { 9, "{0}B", "{0} ബില്യൺ" },
+ { 10, "{0}B", "{0} ബില്യൺ" },
+ { 11, "{0}B", "{0} ബില്യൺ" },
+ { 12, "{0}T", "{0} ട്രില്യൺ" },
+ { 13, "{0}T", "{0} ട്രില്യൺ" },
+ { 14, "{0}T", "{0} ട്രില്യൺ" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_92[] = {
+ { 3, "{0} мян", "{0} мянга" },
+ { 4, "{0} мян", "{0} мянга" },
+ { 5, "{0} мян", "{0} мянга" },
+ { 6, "{0} сая", "{0} сая" },
+ { 7, "{0} сая", "{0} сая" },
+ { 8, "{0} сая", "{0} сая" },
+ { 9, "{0} тэрбум", "{0} тэрбум" },
+ { 10, "{0} тэрбум", "{0} тэрбум" },
+ { 11, "{0}Т", "{0} тэрбум" },
+ { 12, "{0}ИН", "{0} их наяд" },
+ { 13, "{0}ИН", "{0} их наяд" },
+ { 14, "{0}ИН", "{0} их наяд" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_93[] = {
+ { 3, "{0} ह", "{0} हजार" },
+ { 4, "{0} ह", "{0} हजार" },
+ { 5, "{0} लाख", "{0} लाख" },
+ { 6, "{0} लाख", "{0} लाख" },
+ { 7, "{0} कोटी", "{0} कोटी" },
+ { 8, "{0} कोटी", "{0} कोटी" },
+ { 9, "{0} अब्ज", "{0} अब्ज" },
+ { 10, "{0} अब्ज", "{0} अब्ज" },
+ { 11, "{0} खर्व", "{0} खर्व" },
+ { 12, "{0} खर्व", "{0} खर्व" },
+ { 13, "{0} पद्म", "{0} पद्म" },
+ { 14, "{0} पद्म", "{0} पद्म" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_94[] = {
+ { 3, "{0}K", "{0} ribu" },
+ { 4, "{0}K", "{0} ribu" },
+ { 5, "{0}K", "{0} ribu" },
+ { 6, "{0}J", "{0} juta" },
+ { 7, "{0}J", "{0} juta" },
+ { 8, "{0}J", "{0} juta" },
+ { 9, "{0}B", "{0} bilion" },
+ { 10, "{0}B", "{0} bilion" },
+ { 11, "{0}B", "{0} bilion" },
+ { 12, "{0}T", "{0} trilion" },
+ { 13, "{0}T", "{0} trilion" },
+ { 14, "{0}T", "{0} trilion" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_95[] = {
+ { 3, "{0} ထောင်", "{0} ထောင်" },
+ { 4, "{0} သောင်း", "{0} သောင်း" },
+ { 5, "{0} သိန်း", "{0} သိန်း" },
+ { 6, "{0} သန်း", "{0} သန်း" },
+ { 7, "{0} ကုဋေ", "{0} ကုဋေ" },
+ { 8, "{0} ကုဋေ", "{0} ကုဋေ" },
+ { 9, "{0} ဋေ", "{0} ကုဋေ" },
+ { 10, "ဋေ {0} ထ", "{0} ကုဋေ" },
+ { 11, "ဋေ {0} သ", "ကုဋေ {0} သောင်း" },
+ { 12, "ဋေ {0} သိန်း", "ကုဋေ {0} သိန်း" },
+ { 13, "ဋေ {0} သန်း", "ကုဋေ {0} သန်း" },
+ { 14, "{0} ကောဋိ", "{0} ကောဋိ" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_96[] = {
+ { 3, "{0}k", "{0} tusen" },
+ { 4, "{0}k", "{0} tusen" },
+ { 5, "{0}k", "{0} tusen" },
+ { 6, "{0} mill'.'", "{0} millioner" },
+ { 7, "{0} mill'.'", "{0} millioner" },
+ { 8, "{0} mill'.'", "{0} millioner" },
+ { 9, "{0} mrd'.'", "{0} milliarder" },
+ { 10, "{0} mrd'.'", "{0} milliarder" },
+ { 11, "{0} mrd'.'", "{0} milliarder" },
+ { 12, "{0} bill'.'", "{0} billioner" },
+ { 13, "{0} bill'.'", "{0} billioner" },
+ { 14, "{0} bill'.'", "{0} billioner" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_97[] = {
+ { 3, "{0} हजार", "{0} हजार" },
+ { 4, "{0} हजार", "{0} हजार" },
+ { 5, "{0} लाख", "{0} लाख" },
+ { 6, "{0} लाख", "{0} करोड" },
+ { 7, "{0} करोड", "{0} करोड" },
+ { 8, "{0} करोड", "{0} करोड" },
+ { 9, "{0} अरब", "{0} अरब" },
+ { 10, "{0} अरब", "{0} अरब" },
+ { 11, "{0} खरब", "{0} अरब" },
+ { 12, "{0} खरब", "{0} खरब" },
+ { 13, "{0} शंख", "{0} शंख" },
+ { 14, "{0} शंख", "{0} शंख" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_98[] = {
+ { 3, "{0}K", "{0} duizend" },
+ { 4, "{0}K", "{0} duizend" },
+ { 5, "{0}K", "{0} duizend" },
+ { 6, "{0} mln'.'", "{0} miljoen" },
+ { 7, "{0} mln'.'", "{0} miljoen" },
+ { 8, "{0} mln'.'", "{0} miljoen" },
+ { 9, "{0} mld'.'", "{0} miljard" },
+ { 10, "{0} mld'.'", "{0} miljard" },
+ { 11, "{0} mld'.'", "{0} miljard" },
+ { 12, "{0} bln'.'", "{0} biljoen" },
+ { 13, "{0} bln'.'", "{0} biljoen" },
+ { 14, "{0} bln'.'", "{0} biljoen" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_99[] = {
+ { 3, "{0}k", "{0} tusen" },
+ { 4, "{0}k", "{0} tusen" },
+ { 5, "{0}k", "{0} tusen" },
+ { 6, "{0} mill'.'", "{0} millionar" },
+ { 7, "{0} mill'.'", "{0} millionar" },
+ { 8, "{0} mill'.'", "{0} millionar" },
+ { 9, "{0} mrd'.'", "{0} milliardar" },
+ { 10, "{0} mrd'.'", "{0} milliardar" },
+ { 11, "{0} mrd'.'", "{0} milliardar" },
+ { 12, "{0} bill'.'", "{0} billionar" },
+ { 13, "{0} bill'.'", "{0} billionar" },
+ { 14, "{0} bill'.'", "{0} billionar" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_100[] = {
+ { 3, "{0}K", "kuma {0}" },
+ { 4, "{0}K", "kuma {0}" },
+ { 5, "{0}K", "kuma {0}" },
+ { 6, "{0}M", "miiliyoona {0}" },
+ { 7, "{0}M", "miiliyoona {0}" },
+ { 8, "{0}M", "miiliyoona {0}" },
+ { 9, "{0}G", "biiliyoona {0}" },
+ { 10, "{0}G", "biiliyoona {0}" },
+ { 11, "{0}G", "biiliyoona {0}" },
+ { 12, "{0}T", "tiriiliyoona {0}" },
+ { 13, "{0}T", "tiriiliyoona {0}" },
+ { 14, "{0}T", "tiriiliyoona {0}" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_101[] = {
+ { 3, "{0}ହ", "{0} ହଜାର" },
+ { 4, "{0}ହ", "{0} ହଜାର" },
+ { 5, "{0}ହ", "{0} ହଜାର" },
+ { 6, "{0}ନି", "{0} ନିୟୁତ" },
+ { 7, "{0}ନି", "{0} ନିୟୁତ" },
+ { 8, "{0}ନି", "{0} ନିୟୁତ" },
+ { 9, "{0}ବି", "{0} ଶହକୋଟି" },
+ { 10, "{0}ବି", "{0} ଶହକୋଟି" },
+ { 11, "{0}ବି", "{0} ଶହକୋଟି" },
+ { 12, "{0}ଟ୍ରି", "{0} ଲକ୍ଷକୋଟି" },
+ { 13, "{0}ଟ୍ରି", "{0} ଲକ୍ଷକୋଟି" },
+ { 14, "{0}ଟ୍ରି", "{0} ଲକ୍ଷକୋଟି" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_102[] = {
+ { 3, "{0} ਹਜ਼ਾਰ", "{0} ਹਜ਼ਾਰ" },
+ { 4, "{0} ਹਜ਼ਾਰ", "{0} ਹਜ਼ਾਰ" },
+ { 5, "{0} ਲੱਖ", "{0} ਲੱਖ" },
+ { 6, "{0} ਲੱਖ", "{0} ਲੱਖ" },
+ { 7, "{0} ਕਰੋੜ", "{0} ਕਰੋੜ" },
+ { 8, "{0} ਕਰੋੜ", "{0} ਕਰੋੜ" },
+ { 9, "{0} ਅਰਬ", "{0} ਅਰਬ" },
+ { 10, "{0} ਅਰਬ", "{0} ਅਰਬ" },
+ { 11, "{0} ਖਰਬ", "{0} ਖਰਬ" },
+ { 12, "{0} ਖਰਬ", "{0} ਖਰਬ" },
+ { 13, "{0} ਨੀਲ", "{0} ਨੀਲ" },
+ { 14, "{0} ਨੀਲ", "{0} ਨੀਲ" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_103[] = {
+ { 3, "{0}K", "{0} Taúzan" },
+ { 4, "{0}K", "{0} Taúzan" },
+ { 5, "{0}K", "{0} Taúzan" },
+ { 6, "{0}M", "{0} Míliọn" },
+ { 7, "{0}M", "{0} Míliọn" },
+ { 8, "{0}M", "{0} Míliọn" },
+ { 9, "{0}B", "{0} Bíliọn" },
+ { 10, "{0}B", "{0} Bíliọn" },
+ { 11, "{0}B", "{0} Bíliọn" },
+ { 12, "{0}T", "{0} Tríliọn" },
+ { 13, "{0}T", "{0} Tríliọn" },
+ { 14, "{0}T", "{0} Tríliọn" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_104[] = {
+ { 3, "{0} tys.", "{0} tysiąca" },
+ { 6, "{0} mln", "{0} miliony" },
+ { 9, "{0} mld", "{0} miliardy" },
+ { 12, "{0} bln", "{0} biliony" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_105[] = {
+ { 3, "{0}K", "{0}K" },
+ { 4, "{0}K", "{0}K" },
+ { 5, "{0}K", "{0}K" },
+ { 6, "{0}M", "{0}M" },
+ { 7, "{0}M", "{0}M" },
+ { 8, "{0}M", "{0}M" },
+ { 9, "{0}B", "{0}G" },
+ { 10, "{0}B", "{0}G" },
+ { 11, "{0}B", "{0}G" },
+ { 12, "{0}T", "{0}T" },
+ { 13, "{0}T", "{0}T" },
+ { 14, "{0}T", "{0}T" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_106[] = {
+ { 3, "{0} mil", "{0} mil" },
+ { 4, "{0} mil", "{0} mil" },
+ { 5, "{0} mil", "{0} mil" },
+ { 6, "{0} mi", "{0} milhões" },
+ { 7, "{0} mi", "{0} milhões" },
+ { 8, "{0} mi", "{0} milhões" },
+ { 9, "{0} bi", "{0} bilhões" },
+ { 10, "{0} bi", "{0} bilhões" },
+ { 11, "{0} bi", "{0} bilhões" },
+ { 12, "{0} tri", "{0} trilhões" },
+ { 13, "{0} tri", "{0} trilhões" },
+ { 14, "{0} tri", "{0} trilhões" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_107[] = {
+ { 3, "{0} mil", "{0} mil" },
+ { 4, "{0} mil", "{0} mil" },
+ { 5, "{0} mil", "{0} mil" },
+ { 6, "{0} M", "{0} milhões" },
+ { 7, "{0} M", "{0} milhões" },
+ { 8, "{0} M", "{0} milhões" },
+ { 9, "{0} mM", "{0} mil milhões" },
+ { 10, "{0} mM", "{0} mil milhões" },
+ { 11, "{0} mM", "{0} mil milhões" },
+ { 12, "{0} Bi", "{0} biliões" },
+ { 13, "{0} Bi", "{0} biliões" },
+ { 14, "{0} Bi", "{0} biliões" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_108[] = {
+ { 3, "{0}", "{0}" },
+ { 4, "{0}", "{0}" },
+ { 5, "{0}", "{0}" },
+ { 6, "{0} miu'.'", "{0} milliuns" },
+ { 7, "{0} miu'.'", "{0} milliuns" },
+ { 8, "{0} miu'.'", "{0} milliuns" },
+ { 9, "{0} mia'.'", "{0} milliardas" },
+ { 10, "{0} mia'.'", "{0} milliardas" },
+ { 11, "{0} mia'.'", "{0} milliardas" },
+ { 12, "{0} biu'.'", "{0} billiuns" },
+ { 13, "{0} biu'.'", "{0} billiuns" },
+ { 14, "{0} biu'.'", "{0} billiuns" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_109[] = {
+ { 3, "{0} K", "{0} de mii" },
+ { 4, "{0} K", "{0} de mii" },
+ { 5, "{0} K", "{0} de mii" },
+ { 6, "{0} mil'.'", "{0} de milioane" },
+ { 7, "{0} mil'.'", "{0} de milioane" },
+ { 8, "{0} mil'.'", "{0} de milioane" },
+ { 9, "{0} mld'.'", "{0} de miliarde" },
+ { 10, "{0} mld'.'", "{0} de miliarde" },
+ { 11, "{0} mld'.'", "{0} de miliarde" },
+ { 12, "{0} tril'.'", "{0} de trilioane" },
+ { 13, "{0} tril'.'", "{0} de trilioane" },
+ { 14, "{0} tril'.'", "{0} de trilioane" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_110[] = {
+ { 3, "{0} тыс'.'", "{0} тысячи" },
+ { 4, "{0} тыс'.'", "{0} тысячи" },
+ { 5, "{0} тыс'.'", "{0} тысячи" },
+ { 6, "{0} млн", "{0} миллиона" },
+ { 7, "{0} млн", "{0} миллиона" },
+ { 8, "{0} млн", "{0} миллиона" },
+ { 9, "{0} млрд", "{0} миллиарда" },
+ { 10, "{0} млрд", "{0} миллиарда" },
+ { 11, "{0} млрд", "{0} миллиарда" },
+ { 12, "{0} трлн", "{0} триллиона" },
+ { 13, "{0} трлн", "{0} триллиона" },
+ { 14, "{0} трлн", "{0} триллиона" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_111[] = {
+ { 3, "{0} тыһ'.'", "{0} тыһыынча" },
+ { 4, "{0} тыһ'.'", "{0} тыһыынча" },
+ { 5, "{0} тыһ'.'", "{0} тыһыынча" },
+ { 6, "{0} мөл", "{0} мөлүйүөн" },
+ { 7, "{0} мөл", "{0} мөлүйүөн" },
+ { 8, "{0} мөл", "{0} мөлүйүөн" },
+ { 9, "{0} млрд", "{0} миллиард" },
+ { 10, "{0} млрд", "{0} миллиард" },
+ { 11, "{0} млрд", "{0} миллиард" },
+ { 12, "{0} трлн", "{0} триллион" },
+ { 13, "{0} трлн", "{0} триллион" },
+ { 14, "{0} трлн", "{0} триллион" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_112[] = {
+ { 3, "{0} mìg", "{0} mìgia" },
+ { 4, "{0} mìg", "{0} mìgia" },
+ { 5, "{0} mìg", "{0} mìgia" },
+ { 6, "{0} Mln", "{0} milliones" },
+ { 7, "{0} Mln", "{0} milliones" },
+ { 8, "{0} Mln", "{0} milliones" },
+ { 9, "{0} Mrd", "{0} milliardos" },
+ { 10, "{0} Mrd", "{0} milliardos" },
+ { 11, "{0} Mrd", "{0} milliardos" },
+ { 12, "{0} Bln", "{0} mìgia milliardos" },
+ { 13, "{0} Bln", "{0} mìgia milliardos" },
+ { 14, "{0} Bln", "{0} mìgia milliardos" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_113[] = {
+ { 3, "{0}K", "{0} mila" },
+ { 4, "{0}K", "{0} mila" },
+ { 5, "{0}K", "{0} mila" },
+ { 6, "{0}M", "{0} miliuna" },
+ { 7, "{0}M", "{0} miliuna" },
+ { 8, "{0}M", "{0} miliuna" },
+ { 9, "{0}G", "{0} miliardi" },
+ { 10, "{0}G", "{0} miliardi" },
+ { 11, "{0}G", "{0} miliardi" },
+ { 12, "{0}T", "{0} biliuna" },
+ { 13, "{0}T", "{0} biliuna" },
+ { 14, "{0}T", "{0} biliuna" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_114[] = {
+ { 3, "{0} هزار", "{0} ھزار" },
+ { 4, "{0} هزار", "{0} هزار" },
+ { 5, "{0} هزار", "{0} هزار" },
+ { 6, "{0} ملين", "{0} ملين" },
+ { 7, "{0} ملين", "{0} ملين" },
+ { 8, "{0} ملين", "{0} ملين" },
+ { 9, "{0} بلين", "{0} بلين" },
+ { 10, "{0} بلين", "{0} بلين" },
+ { 11, "{0} بلين", "{0} بلين" },
+ { 12, "{0} ٽرلين", "{0} ٽرلين" },
+ { 13, "{0} ٽرلين", "{0} ٽرلين" },
+ { 14, "{0} ٽرلين", "{0} ٽرلين" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_115[] = {
+ { 3, "{0} dt", "{0} duháhat" },
+ { 4, "{0} dt", "{0} duháhat" },
+ { 5, "{0} dt", "{0} duháhat" },
+ { 6, "{0} mn", "{0} miljonat" },
+ { 7, "{0} mn", "{0} miljonat" },
+ { 8, "{0} mn", "{0} miljonat" },
+ { 9, "{0} md", "{0} miljardit" },
+ { 10, "{0} md", "{0} miljardit" },
+ { 11, "{0} md", "{0} miljardit" },
+ { 12, "{0} bn", "{0} biljonat" },
+ { 13, "{0} bn", "{0} biljonat" },
+ { 14, "{0} bn", "{0} biljonat" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_116[] = {
+ { 3, "{0} dt", "{0} duháhat" },
+ { 4, "{0} dt", "{0} duháhat" },
+ { 5, "{0} dt", "{0} duháhat" },
+ { 6, "{0} mn", "{0} miljonat" },
+ { 7, "{0} mn", "{0} miljonat" },
+ { 8, "{0} mn", "{0} miljonat" },
+ { 9, "{0} md", "{0} miljárdat" },
+ { 10, "{0} md", "{0} miljárdat" },
+ { 11, "{0} md", "{0} miljárdat" },
+ { 12, "{0} bn", "{0} biljovdnat" },
+ { 13, "{0} bn", "{0} biljovdnat" },
+ { 14, "{0} bn", "{0} biljovdnat" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_117[] = {
+ { 3, "{0}K", "{0} ႁဵင်" },
+ { 4, "{0}K", "{0} မိုၼ်ႇ" },
+ { 5, "{0}K", "{0} သႅၼ်" },
+ { 6, "{0}M", "{0} လၢၼ်ႉ" },
+ { 7, "{0}M", "{0} လၢၼ်ႉ" },
+ { 8, "{0}M", "{0} လၢၼ်ႉ" },
+ { 9, "{0}G", "{0} ႁဵင်လၢၼ်ႉ" },
+ { 10, "{0}G", "{0} မိုၼ်ႇလၢၼ်ႉ" },
+ { 11, "{0}G", "{0} သႅၼ်လၢၼ်ႉ" },
+ { 12, "{0}T", "{0} လၢၼ်ႉလၢၼ်ႉ" },
+ { 13, "{0}T", "{0} လၢၼ်ႉလၢၼ်ႉ" },
+ { 14, "{0}T", "{0} လၢၼ်ႉလၢၼ်ႉ" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_118[] = {
+ { 3, "ද{0}", "දහස {0}" },
+ { 4, "ද{0}", "දහස {0}" },
+ { 5, "ද{0}", "දහස {0}" },
+ { 6, "මි{0}", "මිලියන {0}" },
+ { 7, "මි{0}", "මිලියන {0}" },
+ { 8, "මි{0}", "මිලියන {0}" },
+ { 9, "බි{0}", "බිලියන {0}" },
+ { 10, "බි{0}", "බිලියන {0}" },
+ { 11, "බි{0}", "බිලියන {0}" },
+ { 12, "ට්රි{0}", "ට්රිලියන {0}" },
+ { 13, "ට්රි{0}", "ට්රිලියන {0}" },
+ { 14, "ට්රි{0}", "ට්රිලියන {0}" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_119[] = {
+ { 3, "{0} tis'.'", "{0} tisíc" },
+ { 4, "{0} tis'.'", "{0} tisíc" },
+ { 5, "{0} tis'.'", "{0} tisíc" },
+ { 6, "{0} mil'.'", "{0} miliónov" },
+ { 7, "{0} mil'.'", "{0} miliónov" },
+ { 8, "{0} mil'.'", "{0} miliónov" },
+ { 9, "{0} mld'.'", "{0} miliárd" },
+ { 10, "{0} mld'.'", "{0} miliárd" },
+ { 11, "{0} mld'.'", "{0} miliárd" },
+ { 12, "{0} bil'.'", "{0} biliónov" },
+ { 13, "{0} bil'.'", "{0} biliónov" },
+ { 14, "{0} bil'.'", "{0} biliónov" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_120[] = {
+ { 3, "{0} tis'.'", "{0} tisoč" },
+ { 4, "{0} tis'.'", "{0} tisoč" },
+ { 5, "{0} tis'.'", "{0} tisoč" },
+ { 6, "{0} mio'.'", "{0} milijonov" },
+ { 7, "{0} mio'.'", "{0} milijonov" },
+ { 8, "{0} mio'.'", "{0} milijonov" },
+ { 9, "{0} mrd'.'", "{0} milijard" },
+ { 10, "{0} mrd'.'", "{0} milijard" },
+ { 11, "{0} mrd'.'", "{0} milijard" },
+ { 12, "{0} bil'.'", "{0} bilijonov" },
+ { 13, "{0} bil'.'", "{0} bilijonov" },
+ { 14, "{0} bil'.'", "{0} bilijonov" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_121[] = {
+ { 3, "{0}K", "{0} tuhháát" },
+ { 4, "{0}K", "{0} tuhháát" },
+ { 5, "{0}K", "{0} tuhháát" },
+ { 6, "{0}M", "{0} miljovn" },
+ { 7, "{0}M", "{0} miljovn" },
+ { 8, "{0}M", "{0} miljovn" },
+ { 9, "{0}G", "{0} miljard" },
+ { 10, "{0}G", "{0} miljard" },
+ { 11, "{0}G", "{0} miljard" },
+ { 12, "{0}T", "{0} biljovn" },
+ { 13, "{0}T", "{0} biljovn" },
+ { 14, "{0}T", "{0} biljovn" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_122[] = {
+ { 3, "{0}K", "{0} Kun" },
+ { 4, "{0}K", "{0} Kun" },
+ { 5, "{0}K", "{0} Kun" },
+ { 6, "{0}M", "{0} Milyan" },
+ { 7, "{0}M", "{0} Milyan" },
+ { 8, "{0}M", "{0} Milyan" },
+ { 9, "{0}B", "{0} Bilyan" },
+ { 10, "{0}B", "{0} Bilyan" },
+ { 11, "{0}B", "{0} Bilyan" },
+ { 12, "{0}T", "{0} Tirilyan" },
+ { 13, "{0}T", "{0} Tirilyan" },
+ { 14, "{0}T", "{0} Tirilyan" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_123[] = {
+ { 3, "{0} mijë", "{0} mijë" },
+ { 4, "{0} mijë", "{0} mijë" },
+ { 5, "{0} mijë", "{0} mijë" },
+ { 6, "{0} mln", "{0} milion" },
+ { 7, "{0} mln", "{0} milion" },
+ { 8, "{0} mln", "{0} milion" },
+ { 9, "{0} mld", "{0} miliard" },
+ { 10, "{0} mld", "{0} miliard" },
+ { 11, "{0} mld", "{0} miliard" },
+ { 12, "{0} bln", "{0} bilion" },
+ { 13, "{0} bln", "{0} bilion" },
+ { 14, "{0} bln", "{0} bilion" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_124[] = {
+ { 3, "{0} хиљ'.'", "{0} хиљада" },
+ { 4, "{0} хиљ'.'", "{0} хиљада" },
+ { 5, "{0} хиљ'.'", "{0} хиљада" },
+ { 6, "{0} мил'.'", "{0} милиона" },
+ { 7, "{0} мил'.'", "{0} милиона" },
+ { 8, "{0} мил'.'", "{0} милиона" },
+ { 9, "{0} млрд'.'", "{0} милијарди" },
+ { 10, "{0} млрд'.'", "{0} милијарди" },
+ { 11, "{0} млрд'.'", "{0} милијарди" },
+ { 12, "{0} бил'.'", "{0} билиона" },
+ { 13, "{0} бил'.'", "{0} билиона" },
+ { 14, "{0} бил'.'", "{0} билиона" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_125[] = {
+ { 3, "{0} tn", "{0} tusen" },
+ { 4, "{0} tn", "{0} tusen" },
+ { 5, "{0} tn", "{0} tusen" },
+ { 6, "{0} mn", "{0} miljoner" },
+ { 7, "{0} mn", "{0} miljoner" },
+ { 8, "{0} mn", "{0} miljoner" },
+ { 9, "{0} md", "{0} miljarder" },
+ { 10, "{0} md", "{0} miljarder" },
+ { 11, "{0} md", "{0} miljarder" },
+ { 12, "{0} bn", "{0} biljoner" },
+ { 13, "{0} bn", "{0} biljoner" },
+ { 14, "{0} bn", "{0} biljoner" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_126[] = {
+ { 3, "elfu {0};elfu -{0}", "elfu {0};elfu -{0}" },
+ { 4, "elfu {0};elfu -{0}", "elfu {0};elfu -{0}" },
+ { 5, "elfu {0};elfu -{0}", "elfu {0};elfu -{0}" },
+ { 6, "{0}M", "milioni {0};milioni -{0}" },
+ { 7, "{0}M", "milioni {0};milioni -{0}" },
+ { 8, "{0}M", "milioni {0};milioni -{0}" },
+ { 9, "{0}B;-{0}B", "bilioni {0};bilioni -{0}" },
+ { 10, "{0}B;-{0}B", "bilioni {0};bilioni -{0}" },
+ { 11, "{0}B;-{0}B", "bilioni {0};bilioni -{0}" },
+ { 12, "{0}T", "trilioni {0};trilioni -{0}" },
+ { 13, "{0}T", "trilioni {0};trilioni -{0}" },
+ { 14, "{0}T", "trilioni {0};trilioni -{0}" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_127[] = {
+ { 3, "elfu {0}", "elfu {0};elfu -{0}" },
+ { 4, "elfu {0}", "elfu {0}" },
+ { 5, "elfu {0}", "elfu {0}" },
+ { 6, "M{0}", "milioni {0}" },
+ { 7, "M{0}", "milioni {0}" },
+ { 8, "M{0}", "milioni {0}" },
+ { 9, "B{0}", "bilioni {0}" },
+ { 10, "B{0}", "bilioni {0}" },
+ { 11, "B{0}", "bilioni {0}" },
+ { 12, "T{0}", "trilioni {0}" },
+ { 13, "T{0}", "trilioni {0}" },
+ { 14, "T{0}", "trilioni {0}" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_128[] = {
+ { 3, "{0}ஆ", "{0} ஆயிரம்" },
+ { 4, "{0}ஆ", "{0} ஆயிரம்" },
+ { 5, "{0}ஆ", "{0} ஆயிரம்" },
+ { 6, "{0}மி", "{0} மில்லியன்" },
+ { 7, "{0}மி", "{0} மில்லியன்" },
+ { 8, "{0}மி", "{0} மில்லியன்" },
+ { 9, "{0}பி", "{0} பில்லியன்" },
+ { 10, "{0}பி", "{0} பில்லியன்" },
+ { 11, "{0}பி", "{0} பில்லியன்" },
+ { 12, "{0}டி", "{0} டிரில்லியன்" },
+ { 13, "{0}டி", "{0} டிரில்லியன்" },
+ { 14, "{0}டி", "{0} டிரில்லியன்" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_129[] = {
+ { 3, "{0}వే", "{0} వేలు" },
+ { 4, "{0}వే", "{0} వేలు" },
+ { 5, "{0}వే", "{0} వేలు" },
+ { 6, "{0}మి", "{0} మిలియన్లు" },
+ { 7, "{0}మి", "{0} మిలియన్లు" },
+ { 8, "{0}మి", "{0} మిలియన్లు" },
+ { 9, "{0}బి", "{0} బిలియన్లు" },
+ { 10, "{0}బి", "{0} బిలియన్లు" },
+ { 11, "{0}బి", "{0} బిలియన్లు" },
+ { 12, "{0}ట్రి", "{0} ట్రిలియన్లు" },
+ { 13, "{0}ట్రి", "{0} ట్రిలియన్లు" },
+ { 14, "{0}ట్రి", "{0} ట్రిలియన్లు" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_130[] = {
+ { 3, "{0} ҳзр'.'", "{0} ҳазор" },
+ { 4, "{0} ҳзр'.'", "{0} ҳазор" },
+ { 5, "{0} ҳзр'.'", "{0} ҳазор" },
+ { 6, "{0} млн'.'", "{0} миллион" },
+ { 7, "{0} млн'.'", "{0} миллион" },
+ { 8, "{0} млн'.'", "{0} миллион" },
+ { 9, "{0} млрд'.'", "{0} миллиард" },
+ { 10, "{0} млрд'.'", "{0} миллиард" },
+ { 11, "{0} млрд'.'", "{0} миллиард" },
+ { 12, "{0} трлн'.'", "{0} триллион" },
+ { 13, "{0} трлн'.'", "{0} триллион" },
+ { 14, "{0} трлн'.'", "{0} триллион" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_131[] = {
+ { 3, "{0}K", "{0} พัน" },
+ { 4, "{0}K", "{0} หมื่น" },
+ { 5, "{0}K", "{0} แสน" },
+ { 6, "{0}M", "{0} ล้าน" },
+ { 7, "{0}M", "{0} ล้าน" },
+ { 8, "{0}M", "{0} ล้าน" },
+ { 9, "{0}B", "{0} พันล้าน" },
+ { 10, "{0}B", "{0} หมื่นล้าน" },
+ { 11, "{0}B", "{0} แสนล้าน" },
+ { 12, "{0}T", "{0} ล้านล้าน" },
+ { 13, "{0}T", "{0} ล้านล้าน" },
+ { 14, "{0}T", "{0} ล้านล้าน" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_132[] = {
+ { 3, "{0} ሽ", "{0} ሽሕ" },
+ { 4, "{0} ሽ", "{0} ሽሕ" },
+ { 5, "{0} ሽ", "{0} ሽሕ" },
+ { 6, "{0} ሚ", "{0} ሚልዮን" },
+ { 7, "{0} ሚ", "{0} ሚልዮን" },
+ { 8, "{0} ሚ", "{0} ሚልዮን" },
+ { 9, "{0} ቢ", "{0} ቢልዮን" },
+ { 10, "{0} ቢ", "{0} ቢልዮን" },
+ { 11, "{0} ቢ", "{0} ቢልዮን" },
+ { 12, "{0} ት", "{0} ትሪልዮን" },
+ { 13, "{0} ት", "{0} ትሪልዮን" },
+ { 14, "{0} ት", "{0} ትሪልዮን" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_133[] = {
+ { 3, "{0} müň", "{0} müň" },
+ { 4, "{0} müň", "{0} müň" },
+ { 5, "{0} müň", "{0} müň" },
+ { 6, "{0} mln", "{0} million" },
+ { 7, "{0} mln", "{0} million" },
+ { 8, "{0} mln", "{0} million" },
+ { 9, "{0} mlrd", "{0} milliard" },
+ { 10, "{0} mlrd", "{0} milliard" },
+ { 11, "{0} mlrd", "{0} milliard" },
+ { 12, "{0} trln", "{0} trillion" },
+ { 13, "{0} trln", "{0} trillion" },
+ { 14, "{0} trln", "{0} trillion" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_134[] = {
+ { 3, "{0}a", "{0} afe" },
+ { 4, "{0}m", "{0} mano" },
+ { 5, "{0}k", "{0} kilu" },
+ { 6, "{0}M", "{0} miliona" },
+ { 7, "{0}M", "{0} miliona" },
+ { 8, "{0}M", "{0} miliona" },
+ { 9, "{0}P", "{0} piliona" },
+ { 10, "{0}P", "{0} piliona" },
+ { 11, "{0}P", "{0} piliona" },
+ { 12, "{0}T", "{0} tiliona" },
+ { 13, "{0}T", "{0} tiliona" },
+ { 14, "{0}T", "{0} tiliona" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_135[] = {
+ { 3, "{0} B", "{0} bin" },
+ { 4, "{0} B", "{0} bin" },
+ { 5, "{0} B", "{0} bin" },
+ { 6, "{0} Mn", "{0} milyon" },
+ { 7, "{0} Mn", "{0} milyon" },
+ { 8, "{0} Mn", "{0} milyon" },
+ { 9, "{0} Mr", "{0} milyar" },
+ { 10, "{0} Mr", "{0} milyar" },
+ { 11, "{0} Mr", "{0} milyar" },
+ { 12, "{0} Tn", "{0} trilyon" },
+ { 13, "{0} Tn", "{0} trilyon" },
+ { 14, "{0} Tn", "{0} trilyon" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_136[] = {
+ { 3, "{0} мең", "{0} мең" },
+ { 4, "{0} мең", "{0} мең" },
+ { 5, "{0} мең", "{0} мең" },
+ { 6, "{0} млн", "{0} миллион" },
+ { 7, "{0} млн", "{0} миллион" },
+ { 8, "{0} млн", "{0} миллион" },
+ { 9, "{0} млрд", "{0} миллиард" },
+ { 10, "{0} млрд", "{0} миллиард" },
+ { 11, "{0}млрд", "{0} миллиард" },
+ { 12, "{0} трлн", "{0} триллион" },
+ { 13, "{0} трлн", "{0} триллион" },
+ { 14, "{0} трлн", "{0} триллион" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_137[] = {
+ { 3, "{0}مىڭ", "{0} مىڭ" },
+ { 4, "{0}مىڭ", "{0} مىڭ" },
+ { 5, "{0}مىڭ", "{0} مىڭ" },
+ { 6, "{0}مىليون", "{0} مىليون" },
+ { 7, "{0}مىليون", "{0} مىليون" },
+ { 8, "{0}مىليون", "{0} مىليون" },
+ { 9, "{0}مىليارد", "{0} مىليارد" },
+ { 10, "{0}مىليارد", "{0} مىليارد" },
+ { 11, "{0}مىليارد", "{0} مىليارد" },
+ { 12, "{0}T", "{0} تىرىليون" },
+ { 13, "{0}T", "{0} تىرىليون" },
+ { 14, "{0}T", "{0} تىرىليون" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_138[] = {
+ { 3, "{0} тис'.'", "{0} тисячі" },
+ { 4, "{0} тис'.'", "{0} тисячі" },
+ { 5, "{0} тис'.'", "{0} тисячі" },
+ { 6, "{0} млн", "{0} мільйона" },
+ { 7, "{0} млн", "{0} мільйона" },
+ { 8, "{0} млн", "{0} мільйона" },
+ { 9, "{0} млрд", "{0} мільярда" },
+ { 10, "{0} млрд", "{0} мільярда" },
+ { 11, "{0} млрд", "{0} мільярда" },
+ { 12, "{0} трлн", "{0} трильйона" },
+ { 13, "{0} трлн", "{0} трильйона" },
+ { 14, "{0} трлн", "{0} трильйона" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_139[] = {
+ { 3, "{0} ہزار", "{0} ہزار" },
+ { 4, "{0} ہزار", "{0} ہزار" },
+ { 5, "{0} لاکھ", "{0} لاکھ" },
+ { 6, "{0} لاکھ", "{0} لاکھ" },
+ { 7, "{0} کروڑ", "{0} کروڑ" },
+ { 8, "{0} کروڑ", "{0} کروڑ" },
+ { 9, "{0} ارب", "{0} ارب" },
+ { 10, "{0} ارب", "{0} ارب" },
+ { 11, "{0} کھرب", "{0} کھرب" },
+ { 12, "{0} کھرب", "{0} کھرب" },
+ { 13, "{0} ٹریلین", "{0} ٹریلین" },
+ { 14, "{0} ٹریلین", "{0} ٹریلین" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_140[] = {
+ { 3, "{0} ming", "{0} ming" },
+ { 4, "{0} ming", "{0} ming" },
+ { 5, "{0} ming", "{0} ming" },
+ { 6, "{0} mln", "{0} million" },
+ { 7, "{0} mln", "{0} million" },
+ { 8, "{0} mln", "{0} million" },
+ { 9, "{0} mlrd", "{0} milliard" },
+ { 10, "{0} mlrd", "{0} milliard" },
+ { 11, "{0} mlrd", "{0} milliard" },
+ { 12, "{0} trln", "{0} trillion" },
+ { 13, "{0} trln", "{0} trillion" },
+ { 14, "{0} trln", "{0} trillion" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_141[] = {
+ { 3, "{0}минг", "{0} минг" },
+ { 4, "{0}минг", "{0} минг" },
+ { 5, "{0}минг", "{0} минг" },
+ { 6, "{0}млн", "{0} миллион" },
+ { 7, "{0}млн", "{0} миллион" },
+ { 8, "{0}млн", "{0} миллион" },
+ { 9, "{0}млрд", "{0} миллиард" },
+ { 10, "{0}млрд", "{0} миллиард" },
+ { 11, "{0}млрд", "{0} миллиард" },
+ { 12, "{0}трлн", "{0} трилион" },
+ { 13, "{0}трлн", "{0} трилион" },
+ { 14, "{0}трлн", "{0} трилион" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_142[] = {
+ { 3, "{0} mila", "{0} mila" },
+ { 4, "{0} mila", "{0} mila" },
+ { 5, "{0} mila", "{0} mila" },
+ { 6, "{0} mln", "{0} milioni" },
+ { 7, "{0} mln", "{0} milioni" },
+ { 8, "{0} mln", "{0} milioni" },
+ { 9, "{0} mld", "{0} miliardi" },
+ { 10, "{0} mld", "{0} miliardi" },
+ { 11, "{0} mld", "{0} miliardi" },
+ { 12, "{0} bln", "{0} bilioni" },
+ { 13, "{0} bln", "{0} bilioni" },
+ { 14, "{0} bln", "{0} bilioni" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_143[] = {
+ { 3, "{0} N", "{0} nghìn" },
+ { 4, "{0} N", "{0} nghìn" },
+ { 5, "{0} N", "{0} nghìn" },
+ { 6, "{0} Tr", "{0} triệu" },
+ { 7, "{0} Tr", "{0} triệu" },
+ { 8, "{0} Tr", "{0} triệu" },
+ { 9, "{0} T", "{0} tỷ" },
+ { 10, "{0} T", "{0} tỷ" },
+ { 11, "{0} T", "{0} tỷ" },
+ { 12, "{0} NT", "{0} nghìn tỷ" },
+ { 13, "{0} NT", "{0} nghìn tỷ" },
+ { 14, "{0} NT", "{0} nghìn tỷ" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_144[] = {
+ { 3, "{0}K", "{0} thousand" },
+ { 4, "{0}K", "{0} thousand" },
+ { 5, "{0}K", "{0} thousand" },
+ { 6, "{0}M", "{0}M" },
+ { 7, "{0}M", "Vote {0}M" },
+ { 8, "{0}M", "Vote {0}M" },
+ { 9, "{0}B", "{0}B" },
+ { 10, "{0}B", "{0}B" },
+ { 11, "{0}B", "Vote {0}G" },
+ { 12, "{0}T", "{0}T" },
+ { 13, "{0}T", "{0}T" },
+ { 14, "{0}T", "{0}T" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_145[] = {
+ { 3, "{0} हजार", "{0} हजार" },
+ { 4, "{0} हजार", "{0} हजार" },
+ { 5, "{0} लख", "{0} लख" },
+ { 6, "{0} लख", "{0} लख" },
+ { 7, "{0} क॰", "{0} करोड़" },
+ { 8, "{0} क॰", "{0} करोड़" },
+ { 9, "{0} अ॰", "{0} अरब" },
+ { 10, "{0} अ॰", "{0} अरब" },
+ { 11, "{0} ख॰", "{0} खरब" },
+ { 12, "{0} ख॰", "{0} खरब" },
+ { 13, "{0} नील", "{0} खरब" },
+ { 14, "{0} नील", "{0} खरब" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_146[] = {
+ { 3, "{0}K", "{0} ẹgbẹ̀rún" },
+ { 4, "{0}K", "{0} ẹgbẹ̀rún" },
+ { 5, "{0}K", "{0} ẹgbẹ̀rún" },
+ { 6, "{0}M", "{0} mílíọ̀nù" },
+ { 7, "{0}M", "{0} mílíọ̀nù" },
+ { 8, "{0}M", "{0} mílíọ̀nù" },
+ { 9, "{0}G", "{0} bilíọ̀nù" },
+ { 10, "{0}G", "{0} bilíọ̀nù" },
+ { 11, "{0}G", "{0} bilíọ̀nù" },
+ { 12, "{0}T", "{0} tiriliọ̀nù" },
+ { 13, "{0}T", "{0} tiriliọ̀nù" },
+ { 14, "{0}T", "{0} tiriliọ̀nù" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_147[] = {
+ { 3, "{0}K", "{0} ɛgbɛ̀rún" },
+ { 4, "{0}K", "{0} ɛgbɛ̀rún" },
+ { 5, "{0}K", "{0} ɛgbɛ̀rún" },
+ { 6, "{0}M", "{0} mílíɔ̀nù" },
+ { 7, "{0}M", "{0} mílíɔ̀nù" },
+ { 8, "{0}M", "{0} mílíɔ̀nù" },
+ { 9, "{0}G", "{0} bilíɔ̀nù" },
+ { 10, "{0}G", "{0} bilíɔ̀nù" },
+ { 11, "{0}G", "{0} bilíɔ̀nù" },
+ { 12, "{0}T", "{0} tiriliɔ̀nù" },
+ { 13, "{0}T", "{0} tiriliɔ̀nù" },
+ { 14, "{0}T", "{0} tiriliɔ̀nù" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_148[] = {
+ { 3, "{0} miu", "{0} miu" },
+ { 4, "{0} miu", "{0} miu" },
+ { 5, "{0} miu", "{0} miu" },
+ { 6, "{0} mi", "{0} miliãu-ita" },
+ { 7, "{0} mi", "{0} miliãu-ita" },
+ { 8, "{0} mi", "{0} miliãu-ita" },
+ { 9, "{0} bi", "{0} biliãu-ita" },
+ { 10, "{0} bi", "{0} biliãu-ita" },
+ { 11, "{0} bi", "{0} biliãu-ita" },
+ { 12, "{0} tiri", "{0} tiriliãu-ita" },
+ { 13, "{0} tiri", "{0} tiriliãu-ita" },
+ { 14, "{0} tiri", "{0} tiriliãu-ita" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_149[] = {
+ { 3, "{0} miu", "{0} miu" },
+ { 4, "{0} miu", "{0} miu" },
+ { 5, "{0} miu", "{0} miu" },
+ { 6, "{0} mi", "{0} millón-ita" },
+ { 7, "{0} mi", "{0} millón-ita" },
+ { 8, "{0} mi", "{0} millón-ita" },
+ { 9, "{0} bi", "{0} billón-ita" },
+ { 10, "{0} bi", "{0} billón-ita" },
+ { 11, "{0} bi", "{0} billón-ita" },
+ { 12, "{0} tiri", "{0} tirillón-ita" },
+ { 13, "{0} tiri", "{0} tirillón-ita" },
+ { 14, "{0} tiri", "{0} tirillón-ita" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_150[] = {
+ { 3, "{0}千", "{0}千" },
+ { 4, "{0}萬", "{0}萬" },
+ { 5, "{0}萬", "{0}萬" },
+ { 6, "{0}萬", "{0}萬" },
+ { 7, "{0}萬", "{0}萬" },
+ { 8, "{0}億", "{0}億" },
+ { 9, "{0}億", "{0}億" },
+ { 10, "{0}億", "{0}億" },
+ { 11, "{0}億", "{0}億" },
+ { 12, "{0}兆", "{0}兆" },
+ { 13, "{0}兆", "{0}兆" },
+ { 14, "{0}兆", "{0}兆" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_151[] = {
+ { 3, "{0}千", "{0}千" },
+ { 4, "{0}万", "{0}万" },
+ { 5, "{0}万", "{0}万" },
+ { 6, "{0}万", "{0}万" },
+ { 7, "{0}万", "{0}万" },
+ { 8, "{0}亿", "{0}亿" },
+ { 9, "{0}亿", "{0}亿" },
+ { 10, "{0}亿", "{0}亿" },
+ { 11, "{0}亿", "{0}亿" },
+ { 12, "{0}兆", "{0}兆" },
+ { 13, "{0}兆", "{0}兆" },
+ { 14, "{0}兆", "{0}兆" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_152[] = {
+ { 4, "{0}萬", "{0}萬" },
+ { 8, "{0}億", "{0}億" },
+ { 12, "{0}兆", "{0}兆" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_153[] = {
+ { 3, "{0}", "{0}" },
+ { 4, "{0}万", "{0}万" },
+ { 5, "{0}万", "{0}万" },
+ { 6, "{0}万", "{0}万" },
+ { 7, "{0}万", "{0}万" },
+ { 8, "{0}亿", "{0}亿" },
+ { 9, "{0}亿", "{0}亿" },
+ { 10, "{0}亿", "{0}亿" },
+ { 11, "{0}亿", "{0}亿" },
+ { 12, "{0}万亿", "{0}万亿" },
+ { 13, "{0}万亿", "{0}万亿" },
+ { 14, "{0}万亿", "{0}万亿" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_154[] = {
+ { 3, "{0}K", "{0}K" },
+ { 4, "{0}K", "{0}K" },
+ { 5, "{0}K", "{0}K" },
+ { 6, "{0}M", "{0}M" },
+ { 7, "{0}M", "{0}M" },
+ { 8, "{0}M", "{0}M" },
+ { 9, "{0}B", "{0}B" },
+ { 10, "{0}B", "{0}B" },
+ { 11, "{0}B", "{0}B" },
+ { 12, "{0}T", "{0}T" },
+ { 13, "{0}T", "{0}T" },
+ { 14, "{0}T", "{0}T" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_155[] = {
+ { 3, "{0}", "{0}" },
+ { 4, "{0}萬", "{0}萬" },
+ { 5, "{0}萬", "{0}萬" },
+ { 6, "{0}萬", "{0}萬" },
+ { 7, "{0}萬", "{0}萬" },
+ { 8, "{0}億", "{0}億" },
+ { 9, "{0}億", "{0}億" },
+ { 10, "{0}億", "{0}億" },
+ { 11, "{0}億", "{0}億" },
+ { 12, "{0}兆", "{0}兆" },
+ { 13, "{0}兆", "{0}兆" },
+ { 14, "{0}兆", "{0}兆" },
+};
+
+static const CompactDecimalPattern locale_compact_arr_156[] = {
+ { 3, "{0}K", "{0} inkulungwane" },
+ { 4, "{0}K", "{0} inkulungwane" },
+ { 5, "{0}K", "{0} inkulungwane" },
+ { 6, "{0}M", "{0} isigidi" },
+ { 7, "{0}M", "{0} isigidi" },
+ { 8, "{0}M", "{0} isigidi" },
+ { 9, "{0}B", "{0} isigidi sezigidi" },
+ { 10, "{0}B", "{0} isigidi sezigidi" },
+ { 11, "{0}B", "{0} isigidi sezigidi" },
+ { 12, "{0}T", "{0} isigidintathu" },
+ { 13, "{0}T", "{0} isigidintathu" },
+ { 14, "{0}T", "{0} isigidintathu" },
+};
+
+const char *decimal_tab[] = {
+ ".",
+ ",",
+ "٫",
+};
+
+const char *group_tab[] = {
+ ",",
+ " ",
+ "٬",
+ ".",
+ "'",
+ " ",
+ "⹁",
+ "،",
+};
+
+const char *plusSign_tab[] = {
+ "+",
+ "+",
+ "+",
+ "+",
+ "+",
+};
+
+const char *minusSign_tab[] = {
+ "-",
+ "-",
+ "-",
+ "-",
+ "-",
+ "−",
+ "−",
+};
+
+const char *percentSign_tab[] = {
+ "%",
+ "%",
+ "٪",
+ "٪",
+};
+
+const char *infinity_tab[] = {
+ "∞",
+ "གྲངས་མེད",
+};
+
+const char *nan_tab[] = {
+ "NaN",
+ "በቁጥር ሊገለጽ የማይችል",
+ "ليس رقمًا",
+ "ND",
+ "Терхьаш дац",
+ "хисеп мар",
+ "ཨང་མད",
+ "mnn",
+ "ناعدد",
+ "epäluku",
+ "Nuimh",
+ "ՈչԹ",
+ "არ არის რიცხვი",
+ "сан емес",
+ "سان ەمەس",
+ "сан эмес",
+ "ບໍ່ແມ່ນໂຕເລກ",
+ "NS",
+ "ဂဏန်းမဟုတ်သော",
+ "НН",
+ "не число",
+ "чыыһыла буотах",
+ "epiloho",
+ "MaL",
+ "ܠܝܬ ܡܢܝܢܐ",
+ "san däl",
+ "TF",
+ "son emas",
+ "ҳақиқий сон эмас",
+ "非數值",
+ "非数值",
+};
+
+const char *pattern_tab[] = {
+ "{number}",
+ "{minusSign}{number}",
+ "{currency} {number}",
+ "{minusSign}{currency} {number}",
+ "{number}{percentSign}",
+ "{minusSign}{number}{percentSign}",
+ "{currency}{number}",
+ "{minusSign}{currency}{number}",
+ "({currency}{number})",
+ "{number}{currency}",
+ "{minusSign}{number}{currency}",
+ "{number} {currency}",
+ "-{number} {currency}",
+ "{number}{currency}",
+ "({number}{currency})",
+ "{minusSign}{number} {currency}",
+ "{number} {currency}",
+ "{minusSign}{number} {currency}",
+ "{number} {percentSign}",
+ "{minusSign}{number} {percentSign}",
+ "({number} {currency})",
+ "{currency} -{number}",
+ "{percentSign} {number}",
+ "{percentSign} -{number}",
+ "({number}{currency})",
+ "{currency}-{number}",
+ "({currency} {number})",
+ "{number} {currency}",
+ "{minusSign}{number} {currency}",
+ "({number} {currency})",
+ "{minusSign}{percentSign} {number}",
+ "{currency}{number}",
+ "{minusSign}{currency}{number}",
+ "{currency} {number}",
+ "({currency} {number})",
+ "{currency} {number}-",
+ "{number} {currency}",
+ "-{number} {currency}",
+ "{percentSign}{number}",
+ "{minusSign}{percentSign}{number}",
+ "{currency}- {number}",
+ "{number} {percentSign}",
+ "{minusSign}{number} {percentSign}",
+};
+
+const char *month_long_tab[] = {
+ "M01\000M02\000M03\000M04\000M05\000M06\000M07\000M08\000M09\000M10\000M11\000M12",
+ "Januarie\000Februarie\000Maart\000April\000Mei\000Junie\000Julie\000Augustus\000September\000Oktober\000November\000Desember",
+ "ndzɔ̀ŋɔ̀nùm\000ndzɔ̀ŋɔ̀kƗ̀zùʔ\000ndzɔ̀ŋɔ̀tƗ̀dʉ̀ghà\000ndzɔ̀ŋɔ̀tǎafʉ̄ghā\000ndzɔ̀ŋèsèe\000ndzɔ̀ŋɔ̀nzùghò\000ndzɔ̀ŋɔ̀dùmlo\000ndzɔ̀ŋɔ̀kwîfɔ̀e\000ndzɔ̀ŋɔ̀tƗ̀fʉ̀ghàdzughù\000ndzɔ̀ŋɔ̀ghǔuwelɔ̀m\000ndzɔ̀ŋɔ̀chwaʔàkaa wo\000ndzɔ̀ŋèfwòo",
+ "Ɔpɛpɔn\000Ɔgyefoɔ\000Ɔbɛnem\000Oforisuo\000Kɔtɔnimma\000Ayɛwohomumu\000Kutawonsa\000Ɔsanaa\000Ɛbɔ\000Ahinime\000Obubuo\000Ɔpɛnimma",
+ "ጃንዋሪ\000ፌብሩዋሪ\000ማርች\000ኤፕሪል\000ሜይ\000ጁን\000ጁላይ\000ኦገስት\000ሴፕቴምበር\000ኦክቶበር\000ኖቬምበር\000ዲሴምበር",
+ "يناير\000فبراير\000مارس\000أبريل\000مايو\000يونيو\000يوليو\000أغسطس\000سبتمبر\000أكتوبر\000نوفمبر\000ديسمبر",
+ "جانفي\000فيفري\000مارس\000أفريل\000ماي\000جوان\000جويلية\000أوت\000سبتمبر\000أكتوبر\000نوفمبر\000ديسمبر",
+ "كانون الثاني\000شباط\000آذار\000نيسان\000أيار\000حزيران\000تموز\000آب\000أيلول\000تشرين الأول\000تشرين الثاني\000كانون الأول",
+ "يناير\000فبراير\000مارس\000أبريل\000ماي\000يونيو\000يوليوز\000غشت\000شتنبر\000أكتوبر\000نونبر\000دجنبر",
+ "يناير\000فبراير\000مارس\000إبريل\000مايو\000يونيو\000يوليو\000أغشت\000شتمبر\000أكتوبر\000نوفمبر\000دجمبر",
+ "জানুৱাৰী\000ফেব্ৰুৱাৰী\000মাৰ্চ\000এপ্ৰিল\000মে’\000জুন\000জুলাই\000আগষ্ট\000ছেপ্তেম্বৰ\000অক্টোবৰ\000নৱেম্বৰ\000ডিচেম্বৰ",
+ "Januari\000Februari\000Machi\000Aprili\000Mei\000Juni\000Julai\000Agosti\000Septemba\000Oktoba\000Novemba\000Desemba",
+ "de xineru\000de febreru\000de marzu\000d’abril\000de mayu\000de xunu\000de xunetu\000d’agostu\000de setiembre\000d’ochobre\000de payares\000d’avientu",
+ "yanvar\000fevral\000mart\000aprel\000may\000iyun\000iyul\000avqust\000sentyabr\000oktyabr\000noyabr\000dekabr",
+ "јанвар\000феврал\000март\000апрел\000май\000ијун\000ијул\000август\000сентјабр\000октјабр\000нојабр\000декабр",
+ "ғинуар\000февраль\000март\000апрель\000май\000июнь\000июль\000август\000сентябрь\000октябрь\000ноябрь\000декабрь",
+ "Janwari\000Parwari\000Márch\000Aprél\000Mai\000Jun\000Jólái\000Agast\000Satambar\000Aktubar\000Nawambar\000Dasambar",
+ "Kɔndɔŋ\000Màcɛ̂l\000Màtùmb\000Màtop\000M̀puyɛ\000Hìlòndɛ̀\000Njèbà\000Hìkaŋ\000Dìpɔ̀s\000Bìòôm\000Màyɛsèp\000Lìbuy li ńyèe",
+ "студзеня\000лютага\000сакавіка\000красавіка\000мая\000чэрвеня\000ліпеня\000жніўня\000верасня\000кастрычніка\000лістапада\000снежня",
+ "Januari\000Februari\000Machi\000Epreo\000Mei\000Juni\000Julai\000Ogasti\000Septemba\000Oktoba\000Novemba\000Disemba",
+ "pa mwedzi gwa hutala\000pa mwedzi gwa wuvili\000pa mwedzi gwa wudatu\000pa mwedzi gwa wutai\000pa mwedzi gwa wuhanu\000pa mwedzi gwa sita\000pa mwedzi gwa saba\000pa mwedzi gwa nane\000pa mwedzi gwa tisa\000pa mwedzi gwa kumi\000pa mwedzi gwa kumi na moja\000pa mwedzi gwa kumi na mbili",
+ "януари\000февруари\000март\000април\000май\000юни\000юли\000август\000септември\000октомври\000ноември\000декември",
+ "जनवरी\000फरवरी\000मार्च\000अप्रैल\000मई\000जून\000जुलाई\000अगस्त\000सितम्बर\000अक्टूबर\000नवम्बर\000दिसंबर",
+ "जनवरी\000फरवरी\000मार्च\000अप्रैल\000मई\000जून\000जुलाई\000अगस्त\000सितम्बर\000अक्टूबर\000नवंबर\000दिसंबर",
+ "ɩjikawǝrka kaŋɔrɔ\000ɩjikpaka kaŋɔrɔ\000arɛ́cika kaŋɔrɔ\000njɩbɔ nɖʊka kaŋɔrɔ\000acafʊnɖuka kaŋɔrɔ\000anɔɔɖuka kaŋɔrɔ\000alàlaka kaŋɔrɔ\000ɩjikǝuka kaŋɔrɔ\000abofʊmka kaŋɔrɔ\000ɩjicimka kaŋɔrɔ\000acapomka kaŋɔrɔ\000anɔɔbʊnka kaŋɔrɔ",
+ "zanwuye\000feburuye\000marisi\000awirili\000mɛ\000zuwɛn\000zuluye\000uti\000sɛtanburu\000ɔkutɔburu\000nowanburu\000desanburu",
+ "জানুয়ারি\000ফেব্রুয়ারি\000মার্চ\000এপ্রিল\000মে\000জুন\000জুলাই\000আগস্ট\000সেপ্টেম্বর\000অক্টোবর\000নভেম্বর\000ডিসেম্বর",
+ "ཟླ་བ་དང་པོ\000ཟླ་བ་གཉིས་པ\000ཟླ་བ་གསུམ་པ\000ཟླ་བ་བཞི་པ\000ཟླ་བ་ལྔ་པ\000ཟླ་བ་དྲུག་པ\000ཟླ་བ་བདུན་པ\000ཟླ་བ་བརྒྱད་པ\000ཟླ་བ་དགུ་པ\000ཟླ་བ་བཅུ་པ\000ཟླ་བ་བཅུ་གཅིག་པ\000ཟླ་བ་བཅུ་གཉིས་པ",
+ "Genver\000Cʼhwevrer\000Meurzh\000Ebrel\000Mae\000Mezheven\000Gouere\000Eost\000Gwengolo\000Here\000Du\000Kerzu",
+ "जानुवारी\000फेब्रूवारी\000मार्च\000एप्रिल\000मे\000जुन\000जुलाई\000आगष्ट\000सेप्थेम्बर\000अक्ट’बर\000नवेम्बर\000डिसेम्बर",
+ "januar\000februar\000mart\000april\000maj\000juni\000juli\000august\000septembar\000oktobar\000novembar\000decembar",
+ "јануар\000фебруар\000март\000април\000мај\000јуни\000јули\000аугуст\000септембар\000октобар\000новембар\000децембар",
+ "нэгэдүгээр һара\000хоёрдугаар һара\000гурбадугаар һара\000дүрбэдүгээр һара\000табадугаар һара\000зургадугаар һара\000долодугаар һара\000наймадугаар һара\000юһэдүгээр һара\000арбадугаар һара\000арбан нэгэдүгээр һара\000арбан хоёрдугаар һара",
+ "de gener\000de febrer\000de març\000d’abril\000de maig\000de juny\000de juliol\000d’agost\000de setembre\000d’octubre\000de novembre\000de desembre",
+ "Cháykáhday Haˀimay\000Tsahkápbiˀ\000Wánit\000Háshnihtiˀtiˀ\000Háshnih Haˀimay\000Háshnihtsiˀ\000Násˀahˀatsus\000Dahósikah nish\000Híisikah nish\000Nípbaatiˀtiˀ\000Nípbaa Haˀimay\000Cháykáhdaytiˀtiˀ",
+ "𑄎𑄚𑄪𑄠𑄢𑄨\000𑄜𑄬𑄛𑄴𑄝𑄳𑄢𑄪𑄠𑄢𑄨\000𑄟𑄢𑄴𑄌𑄧\000𑄃𑄬𑄛𑄳𑄢𑄨𑄣𑄴\000𑄟𑄬\000𑄎𑄪𑄚𑄴\000𑄎𑄪𑄣𑄭\000𑄃𑄉𑄧𑄌𑄴𑄑𑄴\000𑄥𑄬𑄛𑄴𑄑𑄬𑄟𑄴𑄝𑄧𑄢𑄴\000𑄃𑄧𑄇𑄴𑄑𑄬𑄝𑄧𑄢𑄴\000𑄚𑄧𑄞𑄬𑄟𑄴𑄝𑄧𑄢𑄴\000𑄓𑄨𑄥𑄬𑄟𑄴𑄝𑄧𑄢𑄴",
+ "январь\000февраль\000март\000апрель\000май\000июнь\000июль\000август\000сентябрь\000октябрь\000ноябрь\000декабрь",
+ "Enero\000Pebrero\000Marso\000Abril\000Mayo\000Hunyo\000Hulyo\000Agosto\000Septiyembre\000Oktubre\000Nobyembre\000Disyembre",
+ "Okwokubanza\000Okwakabiri\000Okwakashatu\000Okwakana\000Okwakataana\000Okwamukaaga\000Okwamushanju\000Okwamunaana\000Okwamwenda\000Okwaikumi\000Okwaikumi na kumwe\000Okwaikumi na ibiri",
+ "ᎤᏃᎸᏔᏅ\000ᎧᎦᎵ\000ᎠᏅᏱ\000ᎧᏬᏂ\000ᎠᏂᏍᎬᏘ\000ᏕᎭᎷᏱ\000ᎫᏰᏉᏂ\000ᎦᎶᏂ\000ᏚᎵᏍᏗ\000ᏚᏂᏅᏗ\000ᏅᏓᏕᏆ\000ᎥᏍᎩᏱ",
+ "Hashiʼ Ammoʼnaʼ\000Hashiʼ Atokloʼ\000Hashiʼ Atochchíʼnaʼ\000Iiplal\000Mih\000Choon\000Choola\000Akaas\000Siptimpaʼ\000Aaktopaʼ\000Nofimpaʼ\000Tiisimpaʼ",
+ "کانوونی دووەم\000شوبات\000ئازار\000نیسان\000ئایار\000حوزەیران\000تەمووز\000ئاب\000ئەیلوول\000تشرینی یەکەم\000تشرینی دووەم\000کانونی یەکەم",
+ "ledna\000února\000března\000dubna\000května\000června\000července\000srpna\000září\000října\000listopadu\000prosince",
+ "ᐅᒉᒥᑮᓯᑳᐏᐲᓯᒼ\000ᐸᐚᐦᒐᑭᓇᓰᐢ\000ᒥᑭᓯᐏᐲᓯᒼ\000ᓂᐢᑭᐲᓯᒼ\000ᐊᓃᑭᐲᓯᒼ\000ᐚᐏᐲᓯᒼ\000ᐹᐢᑲᐦᐋᐏᐲᓯᒼ\000ᐅᐸᐦᐅᐏᐲᓯᒼ\000ᓄᒌᑐᐏᐲᓯᒼ\000ᐱᓈᐢᑯᐏᐲᓯᒼ\000ᐋᕽᐘᑎᓄᐏᐲᓯᒼ\000ᒪᑯᓭᑮᓭᑳᐏᐲᓯᒼ",
+ "кӑрлач\000нарӑс\000пуш\000ака\000ҫу\000ҫӗртме\000утӑ\000ҫурла\000авӑн\000юпа\000чӳк\000раштав",
+ "Ionawr\000Chwefror\000Mawrth\000Ebrill\000Mai\000Mehefin\000Gorffennaf\000Awst\000Medi\000Hydref\000Tachwedd\000Rhagfyr",
+ "januar\000februar\000marts\000april\000maj\000juni\000juli\000august\000september\000oktober\000november\000december",
+ "Mori ghwa imbiri\000Mori ghwa kawi\000Mori ghwa kadadu\000Mori ghwa kana\000Mori ghwa kasanu\000Mori ghwa karandadu\000Mori ghwa mfungade\000Mori ghwa wunyanya\000Mori ghwa ikenda\000Mori ghwa ikumi\000Mori ghwa ikumi na imweri\000Mori ghwa ikumi na iwi",
+ "Januar\000Februar\000März\000April\000Mai\000Juni\000Juli\000August\000September\000Oktober\000November\000Dezember",
+ "Jänner\000Februar\000März\000April\000Mai\000Juni\000Juli\000August\000September\000Oktober\000November\000Dezember",
+ "Žanwiye\000Feewiriye\000Marsi\000Awiril\000Me\000Žuweŋ\000Žuyye\000Ut\000Sektanbur\000Oktoobur\000Noowanbur\000Deesanbur",
+ "जनवरी\000फरवरी\000मार्च\000अप्रैल\000मेई\000जून\000जुलाई\000अगस्त\000सितंबर\000अक्तूबर\000नवंबर\000दिसंबर",
+ "januara\000februara\000měrca\000apryla\000maja\000junija\000julija\000awgusta\000septembra\000oktobra\000nowembra\000decembra",
+ "dimɔ́di\000ŋgɔndɛ\000sɔŋɛ\000diɓáɓá\000emiasele\000esɔpɛsɔpɛ\000madiɓɛ́díɓɛ́\000diŋgindi\000nyɛtɛki\000mayésɛ́\000tiníní\000eláŋgɛ́",
+ "Sanvie\000Fébirie\000Mars\000Aburil\000Mee\000Sueŋ\000Súuyee\000Ut\000Settembar\000Oktobar\000Novembar\000Disambar",
+ "ཟླ་དངཔ་\000ཟླ་གཉིས་པ་\000ཟླ་གསུམ་པ་\000ཟླ་བཞི་པ་\000ཟླ་ལྔ་པ་\000ཟླ་དྲུག་པ\000ཟླ་བདུན་པ་\000ཟླ་བརྒྱད་པ་\000ཟླ་དགུ་པ་\000ཟླ་བཅུ་པ་\000ཟླ་བཅུ་གཅིག་པ་\000ཟླ་བཅུ་གཉིས་པ་",
+ "Mweri wa mbere\000Mweri wa kaĩri\000Mweri wa kathatũ\000Mweri wa kana\000Mweri wa gatano\000Mweri wa gatantatũ\000Mweri wa mũgwanja\000Mweri wa kanana\000Mweri wa kenda\000Mweri wa ikũmi\000Mweri wa ikũmi na ũmwe\000Mweri wa ikũmi na Kaĩrĩ",
+ "dzove\000dzodze\000tedoxe\000afɔfĩe\000dame\000masa\000siamlɔm\000deasiamime\000anyɔnyɔ\000kele\000adeɛmekpɔxe\000dzome",
+ "Ιανουαρίου\000Φεβρουαρίου\000Μαρτίου\000Απριλίου\000Μαΐου\000Ιουνίου\000Ιουλίου\000Αυγούστου\000Σεπτεμβρίου\000Οκτωβρίου\000Νοεμβρίου\000Δεκεμβρίου",
+ "Ιανουαρίου\000Φεβρουαρίου\000Μαρτίου\000Απριλίου\000Μαΐου\000Ιουνίου\000Ιουλίου\000Αὐγούστου\000Σεπτεμβρίου\000Ὀκτωβρίου\000Νοεμβρίου\000Δεκεμβρίου",
+ "January\000February\000March\000April\000May\000June\000July\000August\000September\000October\000November\000December",
+ "𐐖𐐰𐑌𐐷𐐭𐐯𐑉𐐨\000𐐙𐐯𐐺𐑉𐐭𐐯𐑉𐐨\000𐐣𐐪𐑉𐐽\000𐐁𐐹𐑉𐐮𐑊\000𐐣𐐩\000𐐖𐐭𐑌\000𐐖𐐭𐑊𐐴\000𐐂𐑀𐐲𐑅𐐻\000𐐝𐐯𐐹𐐻𐐯𐑋𐐺𐐲𐑉\000𐐉𐐿𐐻𐐬𐐺𐐲𐑉\000𐐤𐐬𐑂𐐯𐑋𐐺𐐲𐑉\000𐐔𐐨𐑅𐐯𐑋𐐺𐐲𐑉",
+ "·𐑡𐑨𐑙𐑘𐑭𐑢𐑺𐑰\000·𐑓𐑧𐑚𐑘𐑵𐑢𐑺𐑰\000·𐑥𐑸𐑗\000·𐑱𐑐𐑮𐑭𐑤\000·𐑥𐑱\000·𐑡𐑵𐑯\000·𐑡𐑫𐑤𐑲\000·𐑪𐑜𐑭𐑕𐑑\000·𐑕𐑧𐑐𐑑𐑧𐑥𐑚𐑸\000·𐑷𐑒𐑑𐑴𐑚𐑸\000·𐑯𐑴𐑝𐑧𐑥𐑚𐑸\000·𐑛𐑭𐑕𐑧𐑥𐑚𐑸",
+ "Januaro\000Februaro\000Marto\000Aprilo\000Majo\000Junio\000Julio\000Aŭgusto\000Septembro\000Oktobro\000Novembro\000Decembro",
+ "enero\000febrero\000marzo\000abril\000mayo\000junio\000julio\000agosto\000septiembre\000octubre\000noviembre\000diciembre",
+ "enero\000febrero\000marzo\000abril\000mayo\000junio\000julio\000agosto\000setiembre\000octubre\000noviembre\000diciembre",
+ "jaanuar\000veebruar\000märts\000aprill\000mai\000juuni\000juuli\000august\000september\000oktoober\000november\000detsember",
+ "urtarrila\000otsaila\000martxoa\000apirila\000maiatza\000ekaina\000uztaila\000abuztua\000iraila\000urria\000azaroa\000abendua",
+ "ngɔn osú\000ngɔn bɛ̌\000ngɔn lála\000ngɔn nyina\000ngɔn tána\000ngɔn saməna\000ngɔn zamgbála\000ngɔn mwom\000ngɔn ebulú\000ngɔn awóm\000ngɔn awóm ai dziá\000ngɔn awóm ai bɛ̌",
+ "ژانویهٔ\000فوریهٔ\000مارس\000آوریل\000مهٔ\000ژوئن\000ژوئیهٔ\000اوت\000سپتامبر\000اکتبر\000نوامبر\000دسامبر",
+ "جنوری\000فبروری\000مارچ\000اپریل\000می\000جون\000جولای\000اگست\000سپتمبر\000اکتوبر\000نومبر\000دسمبر",
+ "siilo\000colte\000mbooy\000seeɗto\000duujal\000korse\000morso\000juko\000siilto\000yarkomaa\000jolal\000bowte",
+ "𞤅𞤭𞥅𞤤𞤮\000𞤕𞤮𞤤𞤼𞤮\000𞤐𞤦𞤮𞥅𞤴𞤮\000𞤅𞤫𞥅𞤼𞤮\000𞤁𞤵𞥅𞤶𞤮\000𞤑𞤮𞤪𞤧𞤮\000𞤃𞤮𞤪𞤧𞤮\000𞤔𞤵𞤳𞤮\000𞤅𞤭𞤤𞤼𞤮\000𞤒𞤢𞤪𞤳𞤮\000𞤔𞤮𞤤𞤮\000𞤄𞤮𞤱𞤼𞤮",
+ "tammikuuta\000helmikuuta\000maaliskuuta\000huhtikuuta\000toukokuuta\000kesäkuuta\000heinäkuuta\000elokuuta\000syyskuuta\000lokakuuta\000marraskuuta\000joulukuuta",
+ "Enero\000Pebrero\000Marso\000Abril\000Mayo\000Hunyo\000Hulyo\000Agosto\000Setyembre\000Oktubre\000Nobyembre\000Disyembre",
+ "januar\000februar\000mars\000apríl\000mai\000juni\000juli\000august\000september\000oktober\000november\000desember",
+ "janvier\000février\000mars\000avril\000mai\000juin\000juillet\000août\000septembre\000octobre\000novembre\000décembre",
+ "Zenâr\000Fevrâr\000Març\000Avrîl\000Mai\000Jugn\000Lui\000Avost\000Setembar\000Otubar\000Novembar\000Dicembar",
+ "Jannewaris\000Febrewaris\000Maart\000April\000Maaie\000Juny\000July\000Augustus\000Septimber\000Oktober\000Novimber\000Desimber",
+ "Eanáir\000Feabhra\000Márta\000Aibreán\000Bealtaine\000Meitheamh\000Iúil\000Lúnasa\000Meán Fómhair\000Deireadh Fómhair\000Samhain\000Nollaig",
+ "Aharabata\000Oflɔ\000Otsokrikri\000Abɛibe\000Agbiɛnaa\000Otukwajaŋ\000Maawɛ\000Manyawale\000Gbo\000Antɔŋ\000Alemle\000Afuabe",
+ "dhen Fhaoilleach\000dhen Ghearran\000dhen Mhàrt\000dhen Ghiblean\000dhen Chèitean\000dhen Ògmhios\000dhen Iuchar\000dhen Lùnastal\000dhen t-Sultain\000dhen Dàmhair\000dhen t-Samhain\000dhen Dùbhlachd",
+ "xaneiro\000febreiro\000marzo\000abril\000maio\000xuño\000xullo\000agosto\000setembro\000outubro\000novembro\000decembro",
+ "Jasyteĩ\000Jasykõi\000Jasyapy\000Jasyrundy\000Jasypo\000Jasypoteĩ\000Jasypokõi\000Jasypoapy\000Jasyporundy\000Jasypa\000Jasypateĩ\000Jasypakõi",
+ "Januar\000Februar\000März\000April\000Mai\000Juni\000Juli\000Auguscht\000Septämber\000Oktoober\000Novämber\000Dezämber",
+ "જાન્યુઆરી\000ફેબ્રુઆરી\000માર્ચ\000એપ્રિલ\000મે\000જૂન\000જુલાઈ\000ઑગસ્ટ\000સપ્ટેમ્બર\000ઑક્ટોબર\000નવેમ્બર\000ડિસેમ્બર",
+ "Chanuari\000Feburari\000Machi\000Apiriri\000Mei\000Juni\000Chulai\000Agosti\000Septemba\000Okitoba\000Nobemba\000Disemba",
+ "Jerrey-geuree\000Toshiaght-arree\000Mayrnt\000Averil\000Boaldyn\000Mean-souree\000Jerrey-souree\000Luanistyn\000Mean-fouyir\000Jerrey-fouyir\000Mee Houney\000Mee ny Nollick",
+ "Janairu\000Faburairu\000Maris\000Afirilu\000Mayu\000Yuni\000Yuli\000Agusta\000Satumba\000Oktoba\000Nuwamba\000Disamba",
+ "Ianuali\000Pepeluali\000Malaki\000ʻApelila\000Mei\000Iune\000Iulai\000ʻAukake\000Kepakemapa\000ʻOkakopa\000Nowemapa\000Kekemapa",
+ "ינואר\000פברואר\000מרץ\000אפריל\000מאי\000יוני\000יולי\000אוגוסט\000ספטמבר\000אוקטובר\000נובמבר\000דצמבר",
+ "जनवरी\000फ़रवरी\000मार्च\000अप्रैल\000मई\000जून\000जुलाई\000अगस्त\000सितंबर\000अक्टूबर\000नवंबर\000दिसंबर",
+ "𞄆𞄬\000𞄛𞄨𞄱𞄄𞄤𞄲𞄨\000𞄒𞄫𞄰𞄒𞄪𞄱\000𞄤𞄨𞄱\000𞄀𞄪𞄴\000𞄛𞄤𞄱𞄞𞄤𞄦\000𞄔𞄩𞄴𞄆𞄨𞄰\000𞄕𞄩𞄲𞄔𞄄𞄰𞄤\000𞄛𞄤𞄱𞄒𞄤𞄰\000𞄪𞄱𞄀𞄤𞄴\000𞄚𞄦𞄲𞄤𞄚𞄄𞄰𞄫\000𞄒𞄩𞄱𞄔𞄬𞄴",
+ "siječnja\000veljače\000ožujka\000travnja\000svibnja\000lipnja\000srpnja\000kolovoza\000rujna\000listopada\000studenoga\000prosinca",
+ "januara\000februara\000měrca\000apryla\000meje\000junija\000julija\000awgusta\000septembra\000oktobra\000nowembra\000decembra",
+ "január\000február\000március\000április\000május\000június\000július\000augusztus\000szeptember\000október\000november\000december",
+ "հունվարի\000փետրվարի\000մարտի\000ապրիլի\000մայիսի\000հունիսի\000հուլիսի\000օգոստոսի\000սեպտեմբերի\000հոկտեմբերի\000նոյեմբերի\000դեկտեմբերի",
+ "januario\000februario\000martio\000april\000maio\000junio\000julio\000augusto\000septembre\000octobre\000novembre\000decembre",
+ "Januari\000Februari\000Maret\000April\000Mei\000Juni\000Juli\000Agustus\000September\000Oktober\000November\000Desember",
+ "januar\000februar\000marte\000april\000may\000junio\000julí\000august\000septembre\000octobre\000novembre\000decembre",
+ "Jenụwarị\000Febrụwarị\000Maachị\000Epreel\000Mee\000Jun\000Julaị\000Ọgọọst\000Septemba\000Ọktoba\000Novemba\000Disemba",
+ "ꋍꆪ\000ꑍꆪ\000ꌕꆪ\000ꇖꆪ\000ꉬꆪ\000ꃘꆪ\000ꏃꆪ\000ꉆꆪ\000ꈬꆪ\000ꊰꆪ\000ꊯꊪꆪ\000ꊰꑋꆪ",
+ "janúar\000febrúar\000mars\000apríl\000maí\000júní\000júlí\000ágúst\000september\000október\000nóvember\000desember",
+ "gennaio\000febbraio\000marzo\000aprile\000maggio\000giugno\000luglio\000agosto\000settembre\000ottobre\000novembre\000dicembre",
+ "1月\0002月\0003月\0004月\0005月\0006月\0007月\0008月\0009月\00010月\00011月\00012月",
+ "Nduŋmbi Saŋ\000Pɛsaŋ Pɛ́pá\000Pɛsaŋ Pɛ́tát\000Pɛsaŋ Pɛ́nɛ́kwa\000Pɛsaŋ Pataa\000Pɛsaŋ Pɛ́nɛ́ntúkú\000Pɛsaŋ Saambá\000Pɛsaŋ Pɛ́nɛ́fɔm\000Pɛsaŋ Pɛ́nɛ́pfúꞋú\000Pɛsaŋ Nɛgɛ́m\000Pɛsaŋ Ntsɔ̌pmɔ́\000Pɛsaŋ Ntsɔ̌ppá",
+ "Januari\000Februari\000Machi\000Aprilyi\000Mei\000Junyi\000Julyai\000Agusti\000Septemba\000Oktoba\000Novemba\000Desemba",
+ "იანვარი\000თებერვალი\000მარტი\000აპრილი\000მაისი\000ივნისი\000ივლისი\000აგვისტო\000სექტემბერი\000ოქტომბერი\000ნოემბერი\000დეკემბერი",
+ "Yennayer\000Fuṛar\000Meɣres\000Yebrir\000Mayyu\000Yunyu\000Yulyu\000Ɣuct\000Ctembeṛ\000Tubeṛ\000Nunembeṛ\000Duǧembeṛ",
+ "Mwai wa mbee\000Mwai wa kelĩ\000Mwai wa katatũ\000Mwai wa kana\000Mwai wa katano\000Mwai wa thanthatũ\000Mwai wa muonza\000Mwai wa nyaanya\000Mwai wa kenda\000Mwai wa ĩkumi\000Mwai wa ĩkumi na ĩmwe\000Mwai wa ĩkumi na ilĩ",
+ "Mwedi Ntandi\000Mwedi wa Pili\000Mwedi wa Tatu\000Mwedi wa Nchechi\000Mwedi wa Nnyano\000Mwedi wa Nnyano na Umo\000Mwedi wa Nnyano na Mivili\000Mwedi wa Nnyano na Mitatu\000Mwedi wa Nnyano na Nchechi\000Mwedi wa Nnyano na Nnyano\000Mwedi wa Nnyano na Nnyano na U\000Mwedi wa Nnyano na Nnyano na M",
+ "Janeru\000Febreru\000Marsu\000Abril\000Maiu\000Junhu\000Julhu\000Agostu\000Setenbru\000Otubru\000Nuvenbru\000Dizenbru",
+ "Xbʼeen Po\000Xkabʼ Po\000Rox Po\000Xkaa Po\000Roʼ Po\000Xwaq Po\000Xwuuq Po\000Xwaqxaq Po\000Xbʼelee Po\000Xlajee Po\000Xjunlaj Po\000Xkabʼlaj Po",
+ "1-Kysã\0002-Kysã\0003-Kysã\0004-Kysã\0005-Kysã\0006-Kysã\0007-Kysã\0008-Kysã\0009-Kysã\00010-Kysã\00011-Kysã\00012-Kysã",
+ "Njenuarĩ\000Mwere wa kerĩ\000Mwere wa gatatũ\000Mwere wa kana\000Mwere wa gatano\000Mwere wa gatandatũ\000Mwere wa mũgwanja\000Mwere wa kanana\000Mwere wa kenda\000Mwere wa ikũmi\000Mwere wa ikũmi na ũmwe\000Ndithemba",
+ "қаңтар\000ақпан\000наурыз\000сәуір\000мамыр\000маусым\000шілде\000тамыз\000қыркүйек\000қазан\000қараша\000желтоқсан",
+ "قاڭتار\000اقپان\000ناۋرىز\000ءساۋىر\000مامىر\000ماۋسىم\000شىلدە\000تامىز\000قىركۇيەك\000قازان\000قاراشا\000جەلتوقسان",
+ "pamba\000wanja\000mbiyɔ mɛndoŋgɔ\000Nyɔlɔmbɔŋgɔ\000Mɔnɔ ŋgbanja\000Nyaŋgwɛ ŋgbanja\000kuŋgwɛ\000fɛ\000njapi\000nyukul\000M11\000ɓulɓusɛ",
+ "januaarip\000februaarip\000marsip\000apriilip\000maajip\000juunip\000juulip\000aggustip\000septembarip\000oktobarip\000novembarip\000decembarip",
+ "Mulgul\000Ng’atyaato\000Kiptaamo\000Iwootkuut\000Mamuut\000Paagi\000Ng’eiyeet\000Rooptui\000Bureet\000Epeeso\000Kipsuunde ne taai\000Kipsuunde nebo aeng’",
+ "មករា\000កុម្ភៈ\000មីនា\000មេសា\000ឧសភា\000មិថុនា\000កក្កដា\000សីហា\000កញ្ញា\000តុលា\000វិច្ឆិកា\000ធ្នូ",
+ "ಜನವರಿ\000ಫೆಬ್ರವರಿ\000ಮಾರ್ಚ್\000ಏಪ್ರಿಲ್\000ಮೇ\000ಜೂನ್\000ಜುಲೈ\000ಆಗಸ್ಟ್\000ಸೆಪ್ಟೆಂಬರ್\000ಅಕ್ಟೋಬರ್\000ನವೆಂಬರ್\000ಡಿಸೆಂಬರ್",
+ "1월\0002월\0003월\0004월\0005월\0006월\0007월\0008월\0009월\00010월\00011월\00012월",
+ "जानेवारी\000फेब्रुवारी\000मार्च\000एप्रील\000मे\000जून\000जुलय\000ऑगस्ट\000सप्टेंबर\000ऑक्टोबर\000नोव्हेंबर\000डिसेंबर",
+ "Janer\000Febrer\000Mars\000Abril\000Mai\000Jun\000Julai\000Agost\000Setembr\000Otubr\000Novembr\000Dezembr",
+ "جنؤری\000فرؤری\000مارٕچ\000اپریل\000مئی\000جوٗن\000جُلَے\000اگست\000ستمبر\000اکتوٗبر\000نومبر\000دَسَمبَر",
+ "जनवरी\000फ़रवरी\000मार्च\000अप्रैल\000मई\000जून\000जुलाई\000अगस्त\000सतमबर\000अक्तूबर\000नवमबर\000दसमबर",
+ "Januali\000Febluali\000Machi\000Aplili\000Mei\000Juni\000Julai\000Agosti\000Septemba\000Oktoba\000Novemba\000Desemba",
+ "ŋwíí a ntɔ́ntɔ\000ŋwíí akǝ bɛ́ɛ\000ŋwíí akǝ ráá\000ŋwíí akǝ nin\000ŋwíí akǝ táan\000ŋwíí akǝ táafɔk\000ŋwíí akǝ táabɛɛ\000ŋwíí akǝ táaraa\000ŋwíí akǝ táanin\000ŋwíí akǝ ntɛk\000ŋwíí akǝ ntɛk di bɔ́k\000ŋwíí akǝ ntɛk di bɛ́ɛ",
+ "Jannewa\000Fäbrowa\000Määz\000Aprell\000Mai\000Juuni\000Juuli\000Oujoß\000Septämber\000Oktohber\000Novämber\000Dezämber",
+ "rêbendan\000sibat\000adar\000nîsan\000gulan\000hezîran\000tîrmeh\000tebax\000îlon\000cotmeh\000mijdar\000berfanbar",
+ "mis Genver\000mis Hwevrer\000mis Meurth\000mis Ebrel\000mis Me\000mis Metheven\000mis Gortheren\000mis Est\000mis Gwynngala\000mis Hedra\000mis Du\000mis Kevardhu",
+ "pusu lenju\000maha lenju\000pagu lenju\000hire lenju\000bese lenju\000jaṭṭa lenju\000aasaḍi lenju\000srabĩ lenju\000bado lenju\000dasara lenju\000divi lenju\000pande lenju",
+ "पुसु लेञ्जु\000माहाका लेञ्जु\000पागुणी लेञ्जु\000हिरे लेञ्जु\000बेसे लेञ्जु\000जाटा लेञ्जु\000आसाड़ी लेञ्जु\000स्राबाँ लेञ्जु\000बोदो लेञ्जु\000दसारा लेञ्जु\000दिवी लेञ्जु\000पान्डे लेञ्जु",
+ "ପୁସୁ ଲେଞ୍ଜୁ\000ମାହାକା ଲେଞ୍ଜୁ\000ପାଗୁଣି ଲେଞ୍ଜୁ\000ହିରେ ଲେଞ୍ଜୁ\000ବେସେ ଲେଞ୍ଜୁ\000ଜାଟା ଲେଞ୍ଜୁ\000ଆସାଡ଼ି ଲେଞ୍ଜୁ\000ସ୍ରାବାଁ ଲେଞ୍ଜୁ\000ବଦ ଲେଞ୍ଜୁ\000ଦାସାରା ଲେଞ୍ଜୁ\000ଦିୱିଡ଼ି ଲେଞ୍ଜୁ\000ପାଣ୍ଡେ ଲେଞ୍ଜୁ",
+ "మాగ\000గుండు\000హిరెఇ\000బెసెకి\000లండి\000రాత\000బాన్దపాణా\000బార్సి\000అస్ర\000దివెడి\000పాండు\000పుసు",
+ "Kʉfúngatɨ\000Kʉnaanɨ\000Kʉkeenda\000Kwiikumi\000Kwiinyambála\000Kwiidwaata\000Kʉmʉʉnchɨ\000Kʉvɨɨrɨ\000Kʉsaatʉ\000Kwiinyi\000Kʉsaano\000Kʉsasatʉ",
+ "Januar\000Februar\000Mäerz\000Abrëll\000Mee\000Juni\000Juli\000August\000September\000Oktober\000November\000Dezember",
+ "Janwaliyo\000Febwaliyo\000Marisi\000Apuli\000Maayi\000Juuni\000Julaayi\000Agusito\000Sebuttemba\000Okitobba\000Novemba\000Desemba",
+ "de zenâ\000de frevâ\000de marso\000d’arvî\000de mazzo\000de zugno\000de luggio\000d’agosto\000de settembre\000d’ottobre\000de novembre\000de dexembre",
+ "Wiótheȟika Wí\000Thiyóȟeyuŋka Wí\000Ištáwičhayazaŋ Wí\000Pȟežítȟo Wí\000Čhaŋwápetȟo Wí\000Wípazukȟa-wašté Wí\000Čhaŋpȟásapa Wí\000Wasútȟuŋ Wí\000Čhaŋwápeǧi Wí\000Čhaŋwápe-kasná Wí\000Waníyetu Wí\000Tȟahékapšuŋ Wí",
+ "de jená\000de forá\000de merz\000d’aurí\000de ma\000de jügn\000de messé\000d’aost\000de setëmber\000d’otober\000de novëmber\000de dezëmber",
+ "sginer\000fevrer\000marz\000avril\000masg\000sgiugn\000luj\000avost\000setember\000otover\000november\000dicember",
+ "sánzá ya yambo\000sánzá ya míbalé\000sánzá ya mísáto\000sánzá ya mínei\000sánzá ya mítáno\000sánzá ya motóbá\000sánzá ya nsambo\000sánzá ya mwambe\000sánzá ya libwa\000sánzá ya zómi\000sánzá ya zómi na mɔ̌kɔ́\000sánzá ya zómi na míbalé",
+ "ມັງກອນ\000ກຸມພາ\000ມີນາ\000ເມສາ\000ພຶດສະພາ\000ມິຖຸນາ\000ກໍລະກົດ\000ສິງຫາ\000ກັນຍາ\000ຕຸລາ\000ພະຈິກ\000ທັນວາ",
+ "جانڤیە\000فئڤریە\000مارس\000آڤریل\000مئی\000جوٙأن\000جوٙلا\000آگوست\000سئپتامر\000ئوکتوڤر\000نوڤامر\000دئسامر",
+ "sausio\000vasario\000kovo\000balandžio\000gegužės\000birželio\000liepos\000rugpjūčio\000rugsėjo\000spalio\000lapkričio\000gruodžio",
+ "Ciongo\000Lùishi\000Lusòlo\000Mùuyà\000Lumùngùlù\000Lufuimi\000Kabàlàshìpù\000Lùshìkà\000Lutongolo\000Lungùdi\000Kaswèkèsè\000Ciswà",
+ "Dwe mar Achiel\000Dwe mar Ariyo\000Dwe mar Adek\000Dwe mar Ang’wen\000Dwe mar Abich\000Dwe mar Auchiel\000Dwe mar Abiriyo\000Dwe mar Aboro\000Dwe mar Ochiko\000Dwe mar Apar\000Dwe mar gi achiel\000Dwe mar Apar gi ariyo",
+ "janvāris\000februāris\000marts\000aprīlis\000maijs\000jūnijs\000jūlijs\000augusts\000septembris\000oktobris\000novembris\000decembris",
+ "जनवरी\000फरवरी\000मार्च\000अप्रैल\000मई\000जून\000जुलाई\000अगस्त\000सितंबर\000अक्तूबर\000नवंबर\000दिसंबर",
+ "Oladalʉ́\000Arát\000Ɔɛnɨ́ɔɨŋɔk\000Olodoyíóríê inkókúâ\000Oloilépūnyīē inkókúâ\000Kújúɔrɔk\000Mórusásin\000Ɔlɔ́ɨ́bɔ́rárɛ\000Kúshîn\000Olgísan\000Pʉshʉ́ka\000Ntʉ́ŋʉ́s",
+ "Januarĩ\000Feburuarĩ\000Machi\000Ĩpurũ\000Mĩĩ\000Njuni\000Njuraĩ\000Agasti\000Septemba\000Oktũba\000Novemba\000Dicemba",
+ "zanvie\000fevriye\000mars\000avril\000me\000zin\000zilye\000out\000septam\000oktob\000novam\000desam",
+ "Janoary\000Febroary\000Martsa\000Aprily\000Mey\000Jona\000Jolay\000Aogositra\000Septambra\000Oktobra\000Novambra\000Desambra",
+ "Mweri wo kwanza\000Mweri wo unayeli\000Mweri wo uneraru\000Mweri wo unecheshe\000Mweri wo unethanu\000Mweri wo thanu na mocha\000Mweri wo saba\000Mweri wo nane\000Mweri wo tisa\000Mweri wo kumi\000Mweri wo kumi na moja\000Mweri wo kumi na yel’li",
+ "iməg mbegtug\000imeg àbùbì\000imeg mbəŋchubi\000iməg ngwə̀t\000iməg fog\000iməg ichiibɔd\000iməg àdùmbə̀ŋ\000iməg ichika\000iməg kud\000iməg tèsiʼe\000iməg zò\000iməg krizmed",
+ "Hānuere\000Pēpuere\000Māehe\000Āpereira\000Mei\000Hune\000Hūrae\000Ākuhata\000Hepetema\000Oketopa\000Noema\000Tīhema",
+ "јануари\000февруари\000март\000април\000мај\000јуни\000јули\000август\000септември\000октомври\000ноември\000декември",
+ "ജനുവരി\000ഫെബ്രുവരി\000മാർച്ച്\000ഏപ്രിൽ\000മേയ്\000ജൂൺ\000ജൂലൈ\000ഓഗസ്റ്റ്\000സെപ്റ്റംബർ\000ഒക്ടോബർ\000നവംബർ\000ഡിസംബർ",
+ "нэгдүгээр сар\000хоёрдугаар сар\000гуравдугаар сар\000дөрөвдүгээр сар\000тавдугаар сар\000зургаадугаар сар\000долоодугаар сар\000наймдугаар сар\000есдүгээр сар\000аравдугаар сар\000арван нэгдүгээр сар\000арван хоёрдугаар сар",
+ "ᠨᠢᠭᠡᠳᠥᠭᠡᠷ ᠰᠠᠷᠠ\000ᠬᠣᠶᠠᠳᠣᠭᠠᠷ ᠰᠠᠷ ᠠ\000ᠭᠣᠷᠪᠡᠳᠣᠭᠠᠷ ᠰᠠᠷ ᠠ\000ᠳᠥᠷᠪᠡᠳᠥᠭᠡᠷ ᠰᠠᠷᠠ\000ᠲᠠᠪᠣᠳᠣᠭᠠᠷ ᠰᠠᠷ ᠠ\000ᠵᠢᠷᠭᠣᠭᠠᠳᠣᠭᠠᠷ ᠰᠠᠷᠠ\000ᠲᠣᠯᠣᠭᠠᠳᠣᠭᠠᠷ ᠰᠠᠷᠠ\000ᠨᠠᠢᠮᠠᠳᠥᠭᠠᠷ ᠰᠠᠷᠠ\000ᠶᠢᠰᠥᠳᠥᠭᠡᠷ ᠰᠠᠷᠠ\000ᠠᠷᠪᠠᠳᠣᠭᠠᠷ ᠰᠠᠷᠠ\000ᠠᠷᠪᠠᠨ ᠨᠢᠭᠡᠳᠥᠭᠡᠷ ᠰᠠᠷᠠ\000ᠠᠷᠪᠠᠨ ᠬᠣᠶᠠᠳᠣᠭᠠᠷ ᠰᠠᠷᠠ",
+ "জনুৱারী\000ফেব্রুৱারি\000মার্চ\000এপ্রিল\000মে\000জুন\000জুলাই\000ওগষ্ট\000সেপ্টেম্বর\000ওক্টোবর\000নভেম্বর\000ডিসেম্বর",
+ "जानेवारी\000फेब्रुवारी\000मार्च\000एप्रिल\000मे\000जून\000जुलै\000ऑगस्ट\000सप्टेंबर\000ऑक्टोबर\000नोव्हेंबर\000डिसेंबर",
+ "Januari\000Februari\000Mac\000April\000Mei\000Jun\000Julai\000Ogos\000September\000Oktober\000November\000Disember",
+ "Jannar\000Frar\000Marzu\000April\000Mejju\000Ġunju\000Lulju\000Awwissu\000Settembru\000Ottubru\000Novembru\000Diċembru",
+ "Fĩi Loo\000Cokcwaklaŋne\000Cokcwaklii\000Fĩi Marfoo\000Madǝǝuutǝbijaŋ\000Mamǝŋgwãafahbii\000Mamǝŋgwãalii\000Madǝmbii\000Fĩi Dǝɓlii\000Fĩi Mundaŋ\000Fĩi Gwahlle\000Fĩi Yuru",
+ "Rvfo Cuse\000Hotvle Hvse\000Tasahcuce\000Tasahce Rakko\000Ke Hvse\000Kvco Hvse\000Hiyuce\000Hiyo Rakko\000Otowoskuce\000Otowoskv Rakko\000Ehole\000Rvfo Rakko",
+ "ဇန်နဝါရီ\000ဖေဖော်ဝါရီ\000မတ်\000ဧပြီ\000မေ\000ဇွန်\000ဇူလိုင်\000ဩဂုတ်\000စက်တင်ဘာ\000အောက်တိုဘာ\000နိုဝင်ဘာ\000ဒီဇင်ဘာ",
+ "ژانویه\000فوریه\000مارس\000آوریل\000مه\000ژوئن\000ژوئیه\000اوت\000سپتامبر\000اکتبر\000نوامبر\000دسامبر",
+ "ǃKhanni\000ǃKhanǀgôab\000ǀKhuuǁkhâb\000ǃHôaǂkhaib\000ǃKhaitsâb\000Gamaǀaeb\000ǂKhoesaob\000Aoǁkhuumûǁkhâb\000Taraǀkhuumûǁkhâb\000ǂNûǁnâiseb\000ǀHooǂgaeb\000Hôasoreǁkhâb",
+ "januar\000februar\000mars\000april\000mai\000juni\000juli\000august\000september\000oktober\000november\000desember",
+ "Zibandlela\000Nhlolanja\000Mbimbitho\000Mabasa\000Nkwenkwezi\000Nhlangula\000Ntulikazi\000Ncwabakazi\000Mpandula\000Mfumfu\000Lwezi\000Mpalakazi",
+ "Januaar\000Februaar\000März\000April\000Mai\000Juni\000Juli\000August\000September\000Oktover\000November\000Dezember",
+ "जनवरी\000फेब्रुअरी\000मार्च\000अप्रिल\000मे\000जुन\000जुलाई\000अगस्ट\000सेप्टेम्बर\000अक्टोबर\000नोभेम्बर\000डिसेम्बर",
+ "januari\000februari\000maart\000april\000mei\000juni\000juli\000augustus\000september\000oktober\000november\000december",
+ "ngwɛn matáhra\000ngwɛn ńmba\000ngwɛn ńlal\000ngwɛn ńna\000ngwɛn ńtan\000ngwɛn ńtuó\000ngwɛn hɛmbuɛrí\000ngwɛn lɔmbi\000ngwɛn rɛbvuâ\000ngwɛn wum\000ngwɛn wum navǔr\000krísimin",
+ "saŋ tsetsɛ̀ɛ lùm\000saŋ kàg ngwóŋ\000saŋ lepyè shúm\000saŋ cÿó\000saŋ tsɛ̀ɛ cÿó\000saŋ njÿoláʼ\000saŋ tyɛ̀b tyɛ̀b mbʉ̀ŋ\000saŋ mbʉ̀ŋ\000saŋ ngwɔ̀ʼ mbÿɛ\000saŋ tàŋa tsetsáʼ\000saŋ mejwoŋó\000saŋ lùm",
+ "ߓߌ߲ߠߊߥߎߟߋ߲\000ߞߏ߲ߞߏߜߍ\000ߕߙߊߓߊ\000ߞߏ߲ߞߏߘߌ߬ߓߌ\000ߘߓߊ߬ߕߊ\000ߥߊ߬ߛߌ߬ߥߙߊ\000ߞߊ߬ߙߌߝߐ߭\000ߘߓߊ߬ߓߌߟߊ\000ߕߎߟߊߝߌ߲\000ߞߏ߲ߓߌߕߌ߮\000ߣߍߣߍߓߊ\000ߞߏߟߌ߲ߞߏߟߌ߲",
+ "Janeware\000Febereware\000Matšhe\000Aporele\000Mei\000June\000Julae\000Agosetose\000Setemere\000Oktobore\000Nofemere\000Disemere",
+ "Tiop thar pɛt\000Pɛt\000Duɔ̱ɔ̱ŋ\000Guak\000Duät\000Kornyoot\000Pay yie̱tni\000Tho̱o̱r\000Tɛɛr\000Laath\000Kur\000Tio̱p in di̱i̱t",
+ "de genièr\000de febrièr\000de març\000d’abril\000de mai\000de junh\000de julhet\000d’agost\000de setembre\000d’octòbre\000de novembre\000de decembre",
+ "Amajjii\000Guraandhala\000Bitootessa\000Eebila\000Caamsaa\000Waxabajjii\000Adoolessa\000Hagayya\000Fulbaana\000Onkoloolessa\000Sadaasa\000Mudde",
+ "ଜାନୁଆରୀ\000ଫେବୃଆରୀ\000ମାର୍ଚ୍ଚ\000ଅପ୍ରେଲ\000ମଇ\000ଜୁନ\000ଜୁଲାଇ\000ଅଗଷ୍ଟ\000ସେପ୍ଟେମ୍ବର\000ଅକ୍ଟୋବର\000ନଭେମ୍ବର\000ଡିସେମ୍ବର",
+ "январы\000февралы\000мартъийы\000апрелы\000майы\000июны\000июлы\000августы\000сентябры\000октябры\000ноябры\000декабры",
+ "𐓀𐓣͘𐓪͘𐓬𐓘 𐓄𐓘𐓡𐓛͘𐓧𐓟\000𐓀𐓣͘𐓪͘𐓬𐓘 𐓏𐓟𐓵𐓪͘𐓬𐓘\000𐓀𐓣͘𐓪͘𐓬𐓘 𐓏𐓟𐓵𐓘𐓜𐓣\000𐓀𐓣͘𐓪͘𐓬𐓘 𐓏𐓟𐓰𐓪𐓬𐓘\000𐓀𐓣͘𐓪͘𐓬𐓘 𐓏𐓟𐓮𐓘𐓰𐓘\000𐓀𐓣͘𐓪͘𐓬𐓘 𐓏𐓟𐓯𐓘𐓬𐓟\000𐓀𐓣͘𐓪͘𐓬𐓘 𐓄𐓟𐓵𐓪͘𐓬𐓘\000𐓀𐓣͘𐓪͘𐓬𐓘 𐒼𐓣𐓟𐓰𐓪𐓬𐓘\000𐓀𐓣͘𐓪͘𐓬𐓘 𐒿𐓟𐓜𐓛𐓲𐓟𐓷𐓣͘𐓤𐓟\000𐓀𐓣͘𐓪͘𐓬𐓘 𐒿𐓟𐓜𐓛\000𐓀𐓣͘𐓪͘𐓬𐓘 𐒰𐓧𐓣 𐓏𐓣͘𐓸𐓲𐓣\000𐓀𐓣͘𐓪͘𐓬𐓘 𐒰𐓧𐓣 𐓍𐓪͘𐓬𐓘",
+ "ਜਨਵਰੀ\000ਫ਼ਰਵਰੀ\000ਮਾਰਚ\000ਅਪ੍ਰੈਲ\000ਮਈ\000ਜੂਨ\000ਜੁਲਾਈ\000ਅਗਸਤ\000ਸਤੰਬਰ\000ਅਕਤੂਬਰ\000ਨਵੰਬਰ\000ਦਸੰਬਰ",
+ "جنوری\000فروری\000مارچ\000اپریل\000مئ\000جون\000جولائی\000اگست\000ستمبر\000اکتوبر\000نومبر\000دسمبر",
+ "Yanüari\000Febrüari\000Mart\000Aprel\000Mei\000Yüni\000Yüli\000Ougùstùs\000Sèptèmber\000Òktober\000Novèmber\000Desèmber",
+ "Jénúári\000Fẹ́búári\000Mach\000Éprel\000Mee\000Jun\000Julai\000Ọgọst\000Sẹptẹ́mba\000Ọktóba\000Nọvẹ́mba\000Disẹ́mba",
+ "Januare\000Febuare\000Mas\000Eprel\000Mei\000Jun\000Julae\000Ogus\000Septemba\000Oktoba\000Novemba\000Disemba",
+ "stycznia\000lutego\000marca\000kwietnia\000maja\000czerwca\000lipca\000sierpnia\000września\000października\000listopada\000grudnia",
+ "gené\000fërvé\000mars\000avril\000magg\000giugn\000lugn\000agost\000stèmber\000utuber\000novèmber\000dzèmber",
+ "rags\000wassarins\000pūlis\000sakkis\000zallaws\000sīmenis\000līpa\000daggis\000sillins\000spallins\000lapkrūtis\000sallaws",
+ "جنوري\000فبروري\000مارچ\000اپریل\000مۍ\000جون\000جولای\000اګست\000سېپتمبر\000اکتوبر\000نومبر\000دسمبر",
+ "janeiro\000fevereiro\000março\000abril\000maio\000junho\000julho\000agosto\000setembro\000outubro\000novembro\000dezembro",
+ "Enero\000Febrero\000Marzo\000Abril\000Mayo\000Junio\000Julio\000Agosto\000Setiembre\000Octubre\000Noviembre\000Diciembre",
+ "da schaner\000da favrer\000da mars\000d’avrigl\000da matg\000da zercladur\000da fanadur\000d’avust\000da settember\000d’october\000da november\000da december",
+ "Nzero\000Ruhuhuma\000Ntwarante\000Ndamukiza\000Rusama\000Ruheshi\000Mukakaro\000Nyandagaro\000Nyakanga\000Gitugutu\000Munyonyo\000Kigarama",
+ "ianuarie\000februarie\000martie\000aprilie\000mai\000iunie\000iulie\000august\000septembrie\000octombrie\000noiembrie\000decembrie",
+ "Mweri wa kwanza\000Mweri wa kaili\000Mweri wa katatu\000Mweri wa kaana\000Mweri wa tanu\000Mweri wa sita\000Mweri wa saba\000Mweri wa nane\000Mweri wa tisa\000Mweri wa ikumi\000Mweri wa ikumi na moja\000Mweri wa ikumi na mbili",
+ "января\000февраля\000марта\000апреля\000мая\000июня\000июля\000августа\000сентября\000октября\000ноября\000декабря",
+ "Mutarama\000Gashyantare\000Werurwe\000Mata\000Gicurasi\000Kamena\000Nyakanga\000Kanama\000Nzeri\000Ukwakira\000Ugushyingo\000Ukuboza",
+ "जनवरीमासः\000फरवरीमासः\000मार्चमासः\000अप्रैलमासः\000मईमासः\000जूनमासः\000जुलाईमासः\000अगस्तमासः\000सितंबरमासः\000अक्तूबरमासः\000नवंबरमासः\000दिसंबरमासः",
+ "Тохсунньу\000Олунньу\000Кулун тутар\000Муус устар\000Ыам ыйын\000Бэс ыйын\000От ыйын\000Атырдьых ыйын\000Балаҕан ыйын\000Алтынньы\000Сэтинньи\000ахсынньы",
+ "Lapa le obo\000Lapa le waare\000Lapa le okuni\000Lapa le ong’wan\000Lapa le imet\000Lapa le ile\000Lapa le sapa\000Lapa le isiet\000Lapa le saal\000Lapa le tomon\000Lapa le tomon obo\000Lapa le tomon waare",
+ "ᱡᱟᱱᱣᱟᱨᱤ\000ᱯᱷᱟᱨᱣᱟᱨᱤ\000ᱢᱟᱨᱪ\000ᱟᱯᱨᱮᱞ\000ᱢᱮ\000ᱡᱩᱱ\000ᱡᱩᱞᱟᱭ\000ᱟᱜᱟᱥᱛ\000ᱥᱮᱯᱴᱮᱢᱵᱟᱨ\000ᱚᱠᱴᱚᱵᱟᱨ\000ᱱᱟᱣᱟᱢᱵᱟᱨ\000ᱫᱤᱥᱟᱢᱵᱟᱨ",
+ "Mupalangulwa\000Mwitope\000Mushende\000Munyi\000Mushende Magali\000Mujimbi\000Mushipepo\000Mupuguto\000Munyense\000Mokhu\000Musongandembwe\000Muhaano",
+ "ghennàrgiu\000freàrgiu\000martzu\000abrile\000maju\000làmpadas\000trìulas\000austu\000cabudanni\000santugaine\000santandria\000nadale",
+ "jinnaru\000frivaru\000marzu\000aprili\000maju\000giugnu\000giugnettu\000agustu\000sittèmmiru\000uttùviru\000nuvèmmiru\000dicèmmiru",
+ "جنوري\000فيبروري\000مارچ\000اپريل\000مئي\000جون\000جولاءِ\000آگسٽ\000سيپٽمبر\000آڪٽوبر\000نومبر\000ڊسمبر",
+ "जनवरी\000फेबरवरी\000मार्चु\000अप्रेल\000मई\000जून\000जुलाई\000आगस्ट\000सप्टेंबर\000आक्टोबर\000नवंबर\000डिसंबर",
+ "ođđajagemánnu\000guovvamánnu\000njukčamánnu\000cuoŋománnu\000miessemánnu\000geassemánnu\000suoidnemánnu\000borgemánnu\000čakčamánnu\000golggotmánnu\000skábmamánnu\000juovlamánnu",
+ "Janeiro\000Fevreiro\000Marco\000Abril\000Maio\000Junho\000Julho\000Augusto\000Setembro\000Otubro\000Novembro\000Decembro",
+ "Nyenye\000Fulundïgi\000Mbängü\000Ngubùe\000Bêläwü\000Föndo\000Lengua\000Kükürü\000Mvuka\000Ngberere\000Nabändüru\000Kakauka",
+ "ⵉⵏⵏⴰⵢⵔ\000ⴱⵕⴰⵢⵕ\000ⵎⴰⵕⵚ\000ⵉⴱⵔⵉⵔ\000ⵎⴰⵢⵢⵓ\000ⵢⵓⵏⵢⵓ\000ⵢⵓⵍⵢⵓⵣ\000ⵖⵓⵛⵜ\000ⵛⵓⵜⴰⵏⴱⵉⵔ\000ⴽⵜⵓⴱⵔ\000ⵏⵓⵡⴰⵏⴱⵉⵔ\000ⴷⵓⵊⴰⵏⴱⵉⵔ",
+ "innayr\000bṛayṛ\000maṛṣ\000ibrir\000mayyu\000yunyu\000yulyuz\000ɣuct\000cutanbir\000ktubr\000nuwanbir\000dujanbir",
+ "ၸၼ်ႇဝႃႇရီႇ\000ၾႅပ်ႇဝႃႇရီႇ\000မၢတ်ႉၶ်ျ\000ဢေႇပရႄႇ\000မေႇ\000ၸုၼ်ႇ\000ၸူႇလၢႆႇ\000ဢေႃးၵၢတ်ႉ\000သႅပ်ႇထႅမ်ႇပႃႇ\000ဢွၵ်ႇထူဝ်ႇပႃႇ\000ၼူဝ်ႇဝႅမ်ႇပႃႇ\000တီႇသႅမ်ႇပႃႇ",
+ "දුරුතු\000නවම්\000මැදින්\000බක්\000වෙසක්\000පොසොන්\000ඇසළ\000නිකිණි\000බිනර\000වප්\000ඉල්\000උඳුවප්",
+ "januára\000februára\000marca\000apríla\000mája\000júna\000júla\000augusta\000septembra\000októbra\000novembra\000decembra",
+ "januar\000februar\000marec\000april\000maj\000junij\000julij\000avgust\000september\000oktober\000november\000december",
+ "uđđâivemáánu\000kuovâmáánu\000njuhčâmáánu\000cuáŋuimáánu\000vyesimáánu\000kesimáánu\000syeinimáánu\000porgemáánu\000čohčâmáánu\000roovvâdmáánu\000skammâmáánu\000juovlâmáánu",
+ "Ndira\000Kukadzi\000Kurume\000Kubvumbi\000Chivabvu\000Chikumi\000Chikunguru\000Nyamavhuvhu\000Gunyana\000Gumiguru\000Mbudzi\000Zvita",
+ "Janaayo\000Febraayo\000Maarso\000Abriil\000Maayo\000Juun\000Luulyo\000Agosto\000Sebtembar\000Oktoobar\000Noofeembar\000Diseembar",
+ "janar\000shkurt\000mars\000prill\000maj\000qershor\000korrik\000gusht\000shtator\000tetor\000nëntor\000dhjetor",
+ "јануар\000фебруар\000март\000април\000мај\000јун\000јул\000август\000септембар\000октобар\000новембар\000децембар",
+ "januar\000februar\000mart\000april\000maj\000jun\000jul\000avgust\000septembar\000oktobar\000novembar\000decembar",
+ "Pherekgong\000Hlakola\000Hlakubele\000Mmesa\000Motsheanong\000Phupjane\000Phupu\000Phato\000Lwetse\000Mphalane\000Pudungwana\000Tshitwe",
+ "Januari\000Pébruari\000Maret\000April\000Méi\000Juni\000Juli\000Agustus\000Séptémber\000Oktober\000Nopémber\000Désémber",
+ "januari\000februari\000mars\000april\000maj\000juni\000juli\000augusti\000september\000oktober\000november\000december",
+ "ܟܢܘܢ ܐܚܪܝܐ\000ܫܒܛ\000ܐܕܪ\000ܢܝܣܢ\000ܐܝܪ\000ܚܙܝܪܢ\000ܬܡܘܙ\000ܐܒ\000ܐܝܠܘܠ\000ܬܫܪܝܢ ܩܕܡܝܐ\000ܬܫܪܝܢ ܐܚܪܝܐ\000ܟܢܘܢ ܩܕܡܝܐ",
+ "stycznia\000lutego\000marca\000kwietnia\000moja\000czyrwca\000lipca\000siyrpnia\000września\000października\000listopada\000grudnia",
+ "ஜனவரி\000பிப்ரவரி\000மார்ச்\000ஏப்ரல்\000மே\000ஜூன்\000ஜூலை\000ஆகஸ்ட்\000செப்டம்பர்\000அக்டோபர்\000நவம்பர்\000டிசம்பர்",
+ "జనవరి\000ఫిబ్రవరి\000మార్చి\000ఏప్రిల్\000మే\000జూన్\000జులై\000ఆగస్టు\000సెప్టెంబర్\000అక్టోబర్\000నవంబర్\000డిసెంబర్",
+ "Orara\000Omuk\000Okwamg’\000Odung’el\000Omaruk\000Omodok’king’ol\000Ojola\000Opedel\000Osokosokoma\000Otibar\000Olabor\000Opoo",
+ "Январ\000Феврал\000Март\000Апрел\000Май\000Июн\000Июл\000Август\000Сентябр\000Октябр\000Ноябр\000Декабр",
+ "มกราคม\000กุมภาพันธ์\000มีนาคม\000เมษายน\000พฤษภาคม\000มิถุนายน\000กรกฎาคม\000สิงหาคม\000กันยายน\000ตุลาคม\000พฤศจิกายน\000ธันวาคม",
+ "ጥሪ\000ለካቲት\000መጋቢት\000ሚያዝያ\000ጉንበት\000ሰነ\000ሓምለ\000ነሓሰ\000መስከረም\000ጥቅምቲ\000ሕዳር\000ታሕሳስ",
+ "ýanwar\000fewral\000mart\000aprel\000maý\000iýun\000iýul\000awgust\000sentýabr\000oktýabr\000noýabr\000dekabr",
+ "Ferikgong\000Tlhakole\000Mopitlo\000Moranang\000Motsheganang\000Seetebosigo\000Phukwi\000Phatwe\000Lwetse\000Diphalane\000Ngwanatsele\000Sedimonthole",
+ "Sānuali\000Fēpueli\000Maʻasi\000ʻEpeleli\000Mē\000Sune\000Siulai\000ʻAokosi\000Sēpitema\000ʻOkatopa\000Nōvema\000Tīsema",
+ "tenpo mun #1\000tenpo mun #2\000tenpo mun #3\000tenpo mun #4\000tenpo mun #5\000tenpo mun #6\000tenpo mun #7\000tenpo mun #8\000tenpo mun #9\000tenpo mun #10\000tenpo mun #11\000tenpo mun #12",
+ "Janueri\000Februeri\000Mas\000Epril\000Me\000Jun\000Julai\000Ogas\000Septemba\000Oktoba\000Novemba\000Desemba",
+ "Ocak\000Şubat\000Mart\000Nisan\000Mayıs\000Haziran\000Temmuz\000Ağustos\000Eylül\000Ekim\000Kasım\000Aralık",
+ "Sunguti\000Nyenyenyani\000Nyenyankulu\000Dzivamisoko\000Mudyaxihi\000Khotavuxika\000Mawuwani\000Mhawuri\000Ndzhati\000Nhlangula\000Hukuri\000N’wendzamhala",
+ "гыйнвар\000февраль\000март\000апрель\000май\000июнь\000июль\000август\000сентябрь\000октябрь\000ноябрь\000декабрь",
+ "Январь\000Февраль\000Март\000Апрель\000Май\000Июнь\000Июль\000Август\000Сентябрь\000Октябрь\000Ноябрь\000Декабрь",
+ "Yennayer\000Yebrayer\000Mars\000Ibrir\000Mayyu\000Yunyu\000Yulyuz\000Ɣuct\000Cutanbir\000Kṭuber\000Nwanbir\000Dujanbir",
+ "يانۋار\000فېۋرال\000مارت\000ئاپرېل\000ماي\000ئىيۇن\000ئىيۇل\000ئاۋغۇست\000سېنتەبىر\000ئۆكتەبىر\000نويابىر\000دېكابىر",
+ "січня\000лютого\000березня\000квітня\000травня\000червня\000липня\000серпня\000вересня\000жовтня\000листопада\000грудня",
+ "جنوری\000فروری\000مارچ\000اپریل\000مئی\000جون\000جولائی\000اگست\000ستمبر\000اکتوبر\000نومبر\000دسمبر",
+ "yanvar\000fevral\000mart\000aprel\000may\000iyun\000iyul\000avgust\000sentabr\000oktabr\000noyabr\000dekabr",
+ "январ\000феврал\000март\000апрел\000май\000июн\000июл\000август\000сентябр\000октябр\000ноябр\000декабр",
+ "ꖨꖕ ꕪꕴ ꔞꔀꕮꕊ\000ꕒꕡꖝꖕ\000ꕾꖺ\000ꖢꖕ\000ꖑꕱ\000ꖱꘋ\000ꖱꕞꔤ\000ꗛꔕ\000ꕢꕌ\000ꕭꖃ\000ꔞꘋꕔꕿ ꕸꖃꗏ\000ꖨꖕ ꕪꕴ ꗏꖺꕮꕊ",
+ "jenaro\000febraro\000marso\000aprile\000majo\000jugno\000lujo\000agosto\000setenbre\000otobre\000novenbre\000dezenbre",
+ "tháng 1\000tháng 2\000tháng 3\000tháng 4\000tháng 5\000tháng 6\000tháng 7\000tháng 8\000tháng 9\000tháng 10\000tháng 11\000tháng 12",
+ "janeiru\000fevereiru\000marsu\000abril\000maiu\000junyu\000julyu\000agostu\000setembru\000outubru\000novembru\000dezembru",
+ "Jenner\000Hornig\000Märze\000Abrille\000Meije\000Bráčet\000Heiwet\000Öigšte\000Herbštmánet\000Wímánet\000Wintermánet\000Chrištmánet",
+ "Samwiyee\000Fewriyee\000Mars\000Awril\000Mee\000Suwe\000Sulet\000Ut\000Sàttumbar\000Oktoobar\000Nowàmbar\000Desàmbar",
+ "Janyuwari\000Februwari\000Matshi\000Epreli\000Meyi\000Juni\000Julayi\000Agasti\000Septemba\000Okthobha\000Novemba\000Disemba",
+ "जनवरी\000फ़रवरी\000मार्च\000अप्रैल\000मई\000जून\000जुलाई\000अगस्त\000सितंबर\000अक्तूबर\000नवंबर\000दिसंबर",
+ "pikítíkítie, oólí ú kutúan\000siɛyɛ́, oóli ú kándíɛ\000ɔnsúmbɔl, oóli ú kátátúɛ\000mesiŋ, oóli ú kénie\000ensil, oóli ú kátánuɛ\000ɔsɔn\000efute\000pisuyú\000imɛŋ i puɔs\000imɛŋ i putúk,oóli ú kátíɛ\000makandikɛ\000pilɔndɔ́",
+ "יאַנואַר\000פֿעברואַר\000מערץ\000אַפּריל\000מיי\000יוני\000יולי\000אויגוסט\000סעפּטעמבער\000אקטאבער\000נאוועמבער\000דעצעמבער",
+ "Oṣù Ṣẹ́rẹ́\000Oṣù Èrèlè\000Oṣù Ẹrẹ̀nà\000Oṣù Ìgbé\000Oṣù Ẹ̀bibi\000Oṣù Òkúdu\000Oṣù Agẹmọ\000Oṣù Ògún\000Oṣù Owewe\000Oṣù Ọ̀wàrà\000Oṣù Bélú\000Oṣù Ọ̀pẹ̀",
+ "Oshù Shɛ́rɛ́\000Oshù Èrèlè\000Oshù Ɛrɛ̀nà\000Oshù Ìgbé\000Oshù Ɛ̀bibi\000Oshù Òkúdu\000Oshù Agɛmɔ\000Oshù Ògún\000Oshù Owewe\000Oshù Ɔ̀wàrà\000Oshù Bélú\000Oshù Ɔ̀pɛ̀",
+ "yepé\000mukũi\000musapíri\000irũdí\000pú\000pú-yepé\000pú-mukũi\000pú-musapíri\000pú-irũdí\000yepé-putimaã\000yepé-yepé\000yepé-mukũi",
+ "ndwenit\000ndwenngeih\000ndwensam\000ndwenseiq\000ndwenngux\000ndwenloeg\000ndwencaet\000ndwenbet\000ndwengouj\000ndwencib\000ndwencib’it\000ndwencibngeih",
+ "一月\000二月\000三月\000四月\000五月\000六月\000七月\000八月\000九月\000十月\000十一月\000十二月",
+ "Januwari\000Februwari\000Mashi\000Ephreli\000Meyi\000Juni\000Julayi\000Agasti\000Septhemba\000Okthoba\000Novemba\000Disemba",
+};
+
+const char *month_short_tab[] = {
+ "M01\000M02\000M03\000M04\000M05\000M06\000M07\000M08\000M09\000M10\000M11\000M12",
+ "Jan.\000Feb.\000Mrt.\000Apr.\000Mei\000Jun.\000Jul.\000Aug.\000Sep.\000Okt.\000Nov.\000Des.",
+ "nùm\000kɨz\000tɨd\000taa\000see\000nzu\000dum\000fɔe\000dzu\000lɔm\000kaa\000fwo",
+ "Ɔpɛpɔn\000Ɔgyefoɔ\000Ɔbɛnem\000Oforisuo\000Kɔtɔnimma\000Ayɛwohomumu\000Kutawonsa\000Ɔsanaa\000Ɛbɔ\000Ahinime\000Obubuo\000Ɔpɛnimma",
+ "ጃን\000ፌብ\000ማርች\000ኤፕሪ\000ሜይ\000ጁን\000ጁላይ\000ኦገስ\000ሴፕቴ\000ኦክቶ\000ኖቬም\000ዲሴም",
+ "يناير\000فبراير\000مارس\000أبريل\000مايو\000يونيو\000يوليو\000أغسطس\000سبتمبر\000أكتوبر\000نوفمبر\000ديسمبر",
+ "جانفي\000فيفري\000مارس\000أفريل\000ماي\000جوان\000جويلية\000أوت\000سبتمبر\000أكتوبر\000نوفمبر\000ديسمبر",
+ "كانون الثاني\000شباط\000آذار\000نيسان\000أيار\000حزيران\000تموز\000آب\000أيلول\000تشرين الأول\000تشرين الثاني\000كانون الأول",
+ "كانون الثاني\000شباط\000آذار\000نيسان\000أيار\000حزيران\000تموز\000آب\000أيلول\000تشرين الأول\000تشرين الثاني\000كانون الأول",
+ "يناير\000فبراير\000مارس\000أبريل\000ماي\000يونيو\000يوليوز\000غشت\000شتنبر\000أكتوبر\000نونبر\000دجنبر",
+ "يناير\000فبراير\000مارس\000إبريل\000مايو\000يونيو\000يوليو\000أغشت\000شتمبر\000أكتوبر\000نوفمبر\000دجمبر",
+ "জানু\000ফেব্ৰু\000মাৰ্চ\000এপ্ৰিল\000মে’\000জুন\000জুলাই\000আগ\000ছেপ্তে\000অক্টো\000নৱে\000ডিচে",
+ "Jan\000Feb\000Mac\000Apr\000Mei\000Jun\000Jul\000Ago\000Sep\000Okt\000Nov\000Dec",
+ "xin\000feb\000mar\000abr\000may\000xun\000xnt\000ago\000set\000och\000pay\000avi",
+ "yan\000fev\000mar\000apr\000may\000iyn\000iyl\000avq\000sen\000okt\000noy\000dek",
+ "јан\000фев\000мар\000апр\000май\000ијн\000ијл\000авг\000сен\000окт\000ној\000дек",
+ "ғин.\000фев.\000мар.\000апр.\000май\000июн.\000июл.\000авг.\000сент.\000окт.\000нояб.\000дек.",
+ "Jan\000Par\000Már\000Apr\000Mai\000Jun\000Jól\000Aga\000Sat\000Akt\000Naw\000Das",
+ "kɔn\000mac\000mat\000mto\000mpu\000hil\000nje\000hik\000dip\000bio\000may\000liɓ",
+ "сту\000лют\000сак\000кра\000мая\000чэр\000ліп\000жні\000вер\000кас\000ліс\000сне",
+ "Jan\000Feb\000Mac\000Epr\000Mei\000Jun\000Jul\000Oga\000Sep\000Okt\000Nov\000Dis",
+ "Hut\000Vil\000Dat\000Tai\000Han\000Sit\000Sab\000Nan\000Tis\000Kum\000Kmj\000Kmb",
+ "яну\000фев\000март\000апр\000май\000юни\000юли\000авг\000сеп\000окт\000ное\000дек",
+ "जनवरी\000फरवरी\000मार्च\000अप्रैल\000मई\000जून\000जुलाई\000अगस्त\000सितम्बर\000अक्टूबर\000नवम्बर\000दिसंबर",
+ "जनवरी\000फरवरी\000मार्च\000अप्रैल\000मई\000जून\000जुलाई\000अगस्त\000सितम्बर\000अक्टूबर\000नवंबर\000दिसंबर",
+ "kaw\000kpa\000ci\000ɖʊ\000ɖu5\000ɖu6\000la\000kǝu\000fʊm\000cim\000pom\000bʊn",
+ "zan\000feb\000mar\000awi\000mɛ\000zuw\000zul\000uti\000sɛt\000ɔku\000now\000des",
+ "জানু\000ফেব\000মার্চ\000এপ্রি\000মে\000জুন\000জুল\000আগ\000সেপ\000অক্টো\000নভে\000ডিসে",
+ "জানু\000ফেব\000মার্চ\000এপ্রি\000মে\000জুন\000জুল\000আগ\000সেপ্টেঃ\000অক্টোঃ\000নভেঃ\000ডিসেঃ",
+ "ཟླ་༡\000ཟླ་༢\000ཟླ་༣\000ཟླ་༤\000ཟླ་༥\000ཟླ་༦\000ཟླ་༧\000ཟླ་༨\000ཟླ་༩\000ཟླ་༡༠\000ཟླ་༡༡\000ཟླ་༡༢",
+ "Gen.\000Cʼhwe.\000Meur.\000Ebr.\000Mae\000Mezh.\000Goue.\000Eost\000Gwen.\000Here\000Du\000Kzu.",
+ "जान\000फेब\000मार्च\000एप्रि\000मे\000जुन\000जुल\000आग\000सेप\000अक्ट’\000नवे\000डिसे",
+ "jan\000feb\000mar\000apr\000maj\000jun\000jul\000aug\000sep\000okt\000nov\000dec",
+ "јан\000феб\000мар\000апр\000мај\000јун\000јул\000ауг\000сеп\000окт\000нов\000дец",
+ "нэгэдүгээр һара\000хоёрдугаар һара\000гурбадугаар һара\000дүрбэдүгээр һара\000табадугаар һара\000зургадугаар һара\000долодугаар һара\000наймадугаар һара\000юһэдүгээр һара\000арбадугаар һара\000арбан нэгэдүгээр һара\000арбан хоёрдугаар һара",
+ "de gen.\000de febr.\000de març\000d’abr.\000de maig\000de juny\000de jul.\000d’ag.\000de set.\000d’oct.\000de nov.\000de des.",
+ "Cháykáhday Haˀimay\000Tsahkápbiˀ\000Wánit\000Háshnihtiˀtiˀ\000Háshnih Haˀimay\000Háshnihtsiˀ\000Násˀahˀatsus\000Dahósikah nish\000Híisikah nish\000Nípbaatiˀtiˀ\000Nípbaa Haˀimay\000Cháykáhdaytiˀtiˀ",
+ "𑄎𑄚𑄪\000𑄜𑄬𑄛𑄴\000𑄟𑄢𑄴𑄌𑄧\000𑄃𑄬𑄛𑄳𑄢𑄨𑄣𑄴\000𑄟𑄬\000𑄎𑄪𑄚𑄴\000𑄎𑄪𑄣𑄭\000𑄃𑄉𑄧𑄌𑄴𑄑𑄴\000𑄥𑄬𑄛𑄴𑄑𑄬𑄟𑄴𑄝𑄧𑄢𑄴\000𑄃𑄧𑄇𑄴𑄑𑄮𑄝𑄧𑄢𑄴\000𑄚𑄧𑄞𑄬𑄟𑄴𑄝𑄧𑄢𑄴\000𑄓𑄨𑄥𑄬𑄟𑄴𑄝𑄢𑄴",
+ "янв\000фев\000мар\000апр\000май\000июн\000июл\000авг\000сен\000окт\000ноя\000дек",
+ "Ene\000Peb\000Mar\000Abr\000May\000Hun\000Hul\000Ago\000Sep\000Okt\000Nob\000Dis",
+ "KBZ\000KBR\000KST\000KKN\000KTN\000KMK\000KMS\000KMN\000KMW\000KKM\000KNK\000KNB",
+ "ᎤᏃ\000ᎧᎦ\000ᎠᏅ\000ᎧᏬ\000ᎠᏂ\000ᏕᎭ\000ᎫᏰ\000ᎦᎶ\000ᏚᎵ\000ᏚᏂ\000ᏅᏓ\000ᎥᏍ",
+ "Hashiʼ Ammoʼnaʼ\000Hashiʼ Atokloʼ\000Hashiʼ Atochchíʼnaʼ\000Iiplal\000Mih\000Choon\000Choola\000Akaas\000Siptimpaʼ\000Aaktopaʼ\000Nofimpaʼ\000Tiisimpaʼ",
+ "کانوونی دووەم\000شوبات\000ئازار\000نیسان\000ئایار\000حوزەیران\000تەمووز\000ئاب\000ئەیلوول\000تشرینی یەکەم\000تشرینی دووەم\000کانونی یەکەم",
+ "led\000úno\000bře\000dub\000kvě\000čvn\000čvc\000srp\000zář\000říj\000lis\000pro",
+ "ᐅᒉᒥᑮᓯᑳᐏᐲᓯᒼ\000ᐸᐚᐦᒐᑭᓇᓰᐢ\000ᒥᑭᓯᐏᐲᓯᒼ\000ᓂᐢᑭᐲᓯᒼ\000ᐊᓃᑭᐲᓯᒼ\000ᐚᐏᐲᓯᒼ\000ᐹᐢᑲᐦᐋᐏᐲᓯᒼ\000ᐅᐸᐦᐅᐏᐲᓯᒼ\000ᓄᒌᑐᐏᐲᓯᒼ\000ᐱᓈᐢᑯᐏᐲᓯᒼ\000ᐋᕽᐘᑎᓄᐏᐲᓯᒼ\000ᒪᑯᓭᑮᓭᑳᐏᐲᓯᒼ",
+ "кӑр.\000нар.\000пуш\000ака\000ҫу\000ҫӗрт.\000утӑ\000ҫур.\000авӑн\000юпа\000чӳк\000раш.",
+ "Ion\000Chwef\000Maw\000Ebr\000Mai\000Meh\000Gorff\000Awst\000Medi\000Hyd\000Tach\000Rhag",
+ "jan.\000feb.\000mar.\000apr.\000maj\000jun.\000jul.\000aug.\000sep.\000okt.\000nov.\000dec.",
+ "Imb\000Kaw\000Kad\000Kan\000Kas\000Kar\000Mfu\000Wun\000Ike\000Iku\000Imw\000Iwi",
+ "Jan.\000Feb.\000März\000Apr.\000Mai\000Juni\000Juli\000Aug.\000Sept.\000Okt.\000Nov.\000Dez.",
+ "Jän.\000Feb.\000März\000Apr.\000Mai\000Juni\000Juli\000Aug.\000Sep.\000Okt.\000Nov.\000Dez.",
+ "Žan\000Fee\000Mar\000Awi\000Me\000Žuw\000Žuy\000Ut\000Sek\000Okt\000Noo\000Dee",
+ "जन.\000फर.\000मार्च\000अप्रैल\000मेई\000जून\000जुलाई\000अग.\000सित.\000अक्तू.\000नव.\000दिस.",
+ "jan.\000feb.\000měr.\000apr.\000maj.\000jun.\000jul.\000awg.\000sep.\000okt.\000now.\000dec.",
+ "di\000ŋgɔn\000sɔŋ\000diɓ\000emi\000esɔ\000mad\000diŋ\000nyɛt\000may\000tin\000elá",
+ "Sa\000Fe\000Ma\000Ab\000Me\000Su\000Sú\000Ut\000Se\000Ok\000No\000De",
+ "༡\000༢\000༣\000༤\000༥\000༦\000༧\000༨\000༩\000༡༠\000༡༡\00012",
+ "Mbe\000Kai\000Kat\000Kan\000Gat\000Gan\000Mug\000Knn\000Ken\000Iku\000Imw\000Igi",
+ "dzv\000dzd\000ted\000afɔ\000dam\000mas\000sia\000dea\000any\000kel\000ade\000dzm",
+ "Ιαν\000Φεβ\000Μαρ\000Απρ\000Μαΐ\000Ιουν\000Ιουλ\000Αυγ\000Σεπ\000Οκτ\000Νοε\000Δεκ",
+ "Ιαν\000Φεβ\000Μαρ\000Απρ\000Μαΐ\000Ιουν\000Ιουλ\000Αὐγ\000Σεπ\000Ὀκτ\000Νοε\000Δεκ",
+ "Jan\000Feb\000Mar\000Apr\000May\000Jun\000Jul\000Aug\000Sep\000Oct\000Nov\000Dec",
+ "Jan\000Feb\000Mar\000Apr\000May\000Jun\000Jul\000Aug\000Sept\000Oct\000Nov\000Dec",
+ "Jan\000Feb\000Mar\000Apr\000May\000June\000July\000Aug\000Sept\000Oct\000Nov\000Dec",
+ "𐐖𐐰𐑌\000𐐙𐐯𐐺\000𐐣𐐪𐑉\000𐐁𐐹𐑉\000𐐣𐐩\000𐐖𐐭𐑌\000𐐖𐐭𐑊\000𐐂𐑀\000𐐝𐐯𐐹\000𐐉𐐿𐐻\000𐐤𐐬𐑂\000𐐔𐐨𐑅",
+ "·𐑡𐑨\000·𐑓𐑧\000·𐑥𐑸\000·𐑱𐑐\000·𐑥𐑱\000·𐑡𐑵\000·𐑡𐑫\000·𐑪𐑜\000·𐑕𐑧\000·𐑷𐑒\000·𐑯𐑴\000·𐑛𐑭",
+ "Jan\000Feb\000Mar\000Apr\000Maj\000Jun\000Jul\000Aŭg\000Sep\000Okt\000Nov\000Dec",
+ "ene\000feb\000mar\000abr\000may\000jun\000jul\000ago\000sept\000oct\000nov\000dic",
+ "ene\000feb\000mar\000abr\000may\000jun\000jul\000ago\000sep\000oct\000nov\000dic",
+ "ene.\000feb.\000mar.\000abr.\000may.\000jun.\000jul.\000ago.\000set.\000oct.\000nov.\000dic.",
+ "ene.\000feb.\000mar.\000abr.\000may.\000jun.\000jul.\000ago.\000sept.\000oct.\000nov.\000dic.",
+ "jaan\000veebr\000märts\000apr\000mai\000juuni\000juuli\000aug\000sept\000okt\000nov\000dets",
+ "urt.\000ots.\000mar.\000api.\000mai.\000eka.\000uzt.\000abu.\000ira.\000urr.\000aza.\000abe.",
+ "ngo\000ngb\000ngl\000ngn\000ngt\000ngs\000ngz\000ngm\000nge\000nga\000ngad\000ngab",
+ "ژانویه\000فوریه\000مارس\000آوریل\000مه\000ژوئن\000ژوئیه\000اوت\000سپتامبر\000اکتبر\000نوامبر\000دسامبر",
+ "جنو\000فبروری\000مارچ\000اپریل\000می\000جون\000جول\000اگست\000سپتمبر\000اکتوبر\000نومبر\000دسم",
+ "sii\000col\000mbo\000see\000duu\000kor\000mor\000juk\000slt\000yar\000jol\000bow",
+ "𞤅𞤭𞥅𞤤𞤮\000𞤕𞤮𞤤𞤼𞤮\000𞤐𞤦𞤮𞥅𞤴𞤮\000𞤅𞤫𞥅𞤼𞤮\000𞤁𞤵𞥅𞤶𞤮\000𞤑𞤮𞤪𞤧𞤮\000𞤃𞤮𞤪𞤧𞤮\000𞤔𞤵𞤳𞤮\000𞤅𞤭𞤤𞤼𞤮\000𞤒𞤢𞤪𞤳𞤮\000𞤔𞤮𞤤𞤮\000𞤄𞤮𞤱𞤼𞤮",
+ "tammi\000helmi\000maalis\000huhti\000touko\000kesä\000heinä\000elo\000syys\000loka\000marras\000joulu",
+ "Ene\000Peb\000Mar\000Abr\000May\000Hun\000Hul\000Ago\000Set\000Okt\000Nob\000Dis",
+ "jan.\000feb.\000mar.\000apr.\000mai\000jun.\000jul.\000aug.\000sep.\000okt.\000nov.\000des.",
+ "janv.\000févr.\000mars\000avr.\000mai\000juin\000juil.\000août\000sept.\000oct.\000nov.\000déc.",
+ "janv.\000févr.\000mars\000avr.\000mai\000juin\000juill.\000août\000sept.\000oct.\000nov.\000déc.",
+ "jan.\000fév.\000mar.\000avr.\000mai\000jui.\000juil.\000août\000sept.\000oct.\000nov.\000déc.",
+ "Zen\000Fev\000Mar\000Avr\000Mai\000Jug\000Lui\000Avo\000Set\000Otu\000Nov\000Dic",
+ "Jan\000Feb\000Mrt\000Apr\000Mai\000Jun\000Jul\000Aug\000Sep\000Okt\000Nov\000Des",
+ "Ean\000Feabh\000Márta\000Aib\000Beal\000Meith\000Iúil\000Lún\000MFómh\000DFómh\000Samh\000Noll",
+ "Aharabata\000Oflɔ\000Otsokrikri\000Abɛibe\000Agbiɛnaa\000Otukwajaŋ\000Maawɛ\000Manyawale\000Gbo\000Antɔŋ\000Alemle\000Afuabe",
+ "Faoi\000Gearr\000Màrt\000Gibl\000Cèit\000Ògmh\000Iuch\000Lùna\000Sult\000Dàmh\000Samh\000Dùbh",
+ "xan.\000feb.\000mar.\000abr.\000maio\000xuño\000xul.\000ago.\000set.\000out.\000nov.\000dec.",
+ "Jasyteĩ\000Jasykõi\000Jasyapy\000Jasyrundy\000Jasypo\000Jasypoteĩ\000Jasypokõi\000Jasypoapy\000Jasyporundy\000Jasypa\000Jasypateĩ\000Jasypakõi",
+ "Jan\000Feb\000Mär\000Apr\000Mai\000Jun\000Jul\000Aug\000Sep\000Okt\000Nov\000Dez",
+ "જાન્યુ\000ફેબ્રુ\000માર્ચ\000એપ્રિલ\000મે\000જૂન\000જુલાઈ\000ઑગસ્ટ\000સપ્ટે\000ઑક્ટો\000નવે\000ડિસે",
+ "Can\000Feb\000Mac\000Apr\000Mei\000Jun\000Cul\000Agt\000Sep\000Okt\000Nob\000Dis",
+ "J-guer\000T-arree\000Mayrnt\000Avrril\000Boaldyn\000M-souree\000J-souree\000Luanistyn\000M-fouyir\000J-fouyir\000M-Houney\000M-Nollick",
+ "Jan\000Fab\000Mar\000Afi\000May\000Yun\000Yul\000Agu\000Sat\000Okt\000Nuw\000Dis",
+ "Ian.\000Pep.\000Mal.\000ʻAp.\000Mei\000Iun.\000Iul.\000ʻAu.\000Kep.\000ʻOk.\000Now.\000Kek.",
+ "ינו׳\000פבר׳\000מרץ\000אפר׳\000מאי\000יוני\000יולי\000אוג׳\000ספט׳\000אוק׳\000נוב׳\000דצמ׳",
+ "जन॰\000फ़र॰\000मार्च\000अप्रैल\000मई\000जून\000जुल॰\000अग॰\000सित॰\000अक्टू॰\000नव॰\000दिस॰",
+ "𞄆𞄬\000𞄛𞄨𞄱𞄄𞄤𞄲𞄨\000𞄒𞄫𞄰𞄒𞄪𞄱\000𞄤𞄨𞄱\000𞄀𞄪𞄴\000𞄛𞄤𞄱𞄞𞄤𞄦\000𞄔𞄩𞄴𞄆𞄨𞄰\000𞄕𞄩𞄲𞄔𞄄𞄰𞄤\000𞄛𞄤𞄱𞄒𞄤𞄰\000𞄪𞄱𞄀𞄤𞄴\000𞄚𞄦𞄲𞄤𞄚𞄄𞄰𞄫\000𞄒𞄩𞄱𞄔𞄬𞄴",
+ "sij\000velj\000ožu\000tra\000svi\000lip\000srp\000kol\000ruj\000lis\000stu\000pro",
+ "jan.\000feb.\000měr.\000apr.\000mej.\000jun.\000jul.\000awg.\000sep.\000okt.\000now.\000dec.",
+ "jan.\000febr.\000márc.\000ápr.\000máj.\000jún.\000júl.\000aug.\000szept.\000okt.\000nov.\000dec.",
+ "հնվ\000փտվ\000մրտ\000ապր\000մյս\000հնս\000հլս\000օգս\000սեպ\000հոկ\000նոյ\000դեկ",
+ "jan\000feb\000mar\000apr\000mai\000jun\000jul\000aug\000sep\000oct\000nov\000dec",
+ "Jan\000Feb\000Mar\000Apr\000Mei\000Jun\000Jul\000Agu\000Sep\000Okt\000Nov\000Des",
+ "jan.\000febr.\000mar.\000apr.\000may\000jun.\000julí\000aug.\000sept.\000oct.\000nov.\000dec.",
+ "Jen\000Feb\000Maa\000Epr\000Mee\000Juu\000Jul\000Ọgọ\000Sep\000Ọkt\000Nov\000Dis",
+ "ꋍꆪ\000ꑍꆪ\000ꌕꆪ\000ꇖꆪ\000ꉬꆪ\000ꃘꆪ\000ꏃꆪ\000ꉆꆪ\000ꈬꆪ\000ꊰꆪ\000ꊯꊪꆪ\000ꊰꑋꆪ",
+ "jan.\000feb.\000mar.\000apr.\000maí\000jún.\000júl.\000ágú.\000sep.\000okt.\000nóv.\000des.",
+ "gen\000feb\000mar\000apr\000mag\000giu\000lug\000ago\000set\000ott\000nov\000dic",
+ "1月\0002月\0003月\0004月\0005月\0006月\0007月\0008月\0009月\00010月\00011月\00012月",
+ "Nduŋmbi Saŋ\000Pɛsaŋ Pɛ́pá\000Pɛsaŋ Pɛ́tát\000Pɛsaŋ Pɛ́nɛ́kwa\000Pɛsaŋ Pataa\000Pɛsaŋ Pɛ́nɛ́ntúkú\000Pɛsaŋ Saambá\000Pɛsaŋ Pɛ́nɛ́fɔm\000Pɛsaŋ Pɛ́nɛ́pfúꞋú\000Pɛsaŋ Nɛgɛ́m\000Pɛsaŋ Ntsɔ̌pmɔ́\000Pɛsaŋ Ntsɔ̌ppá",
+ "Jan\000Feb\000Mac\000Apr\000Mei\000Jun\000Jul\000Ago\000Sep\000Okt\000Nov\000Des",
+ "Jan\000Feb\000Mar\000Apr\000Mei\000Jun\000Jul\000Agt\000Sep\000Okt\000Nov\000Des",
+ "იან\000თებ\000მარ\000აპრ\000მაი\000ივნ\000ივლ\000აგვ\000სექ\000ოქტ\000ნოე\000დეკ",
+ "Yen\000Fur\000Meɣ\000Yeb\000May\000Yun\000Yul\000Ɣuc\000Cte\000Tub\000Nun\000Duǧ",
+ "Mbe\000Kel\000Ktũ\000Kan\000Ktn\000Tha\000Moo\000Nya\000Knd\000Ĩku\000Ĩkm\000Ĩkl",
+ "Jan\000Feb\000Mar\000Abr\000Mai\000Jun\000Jul\000Ago\000Set\000Otu\000Nuv\000Diz",
+ "Xbʼeen Po\000Xkabʼ Po\000Rox Po\000Xkaa Po\000Roʼ Po\000Xwaq Po\000Xwuuq Po\000Xwaqxaq Po\000Xbʼelee Po\000Xlajee Po\000Xjunlaj Po\000Xkabʼlaj Po",
+ "1Ky.\0002Ky.\0003Ky.\0004Ky.\0005Ky.\0006Ky.\0007Ky.\0008Ky.\0009Ky.\00010Ky.\00011Ky.\00012Ky.",
+ "JEN\000WKR\000WGT\000WKN\000WTN\000WTD\000WMJ\000WNN\000WKD\000WIK\000WMW\000DIT",
+ "қаң.\000ақп.\000нау.\000сәу.\000мам.\000мау.\000шіл.\000там.\000қыр.\000қаз.\000қар.\000жел.",
+ "قاڭتار\000اقپان\000ناۋرىز\000ءساۋىر\000مامىر\000ماۋسىم\000شىلدە\000تامىز\000قىركۇيەك\000قازان\000قاراشا\000جەلتوقسان",
+ "pamba\000wanja\000mbiyɔ mɛndoŋgɔ\000Nyɔlɔmbɔŋgɔ\000Mɔnɔ ŋgbanja\000Nyaŋgwɛ ŋgbanja\000kuŋgwɛ\000fɛ\000njapi\000nyukul\000M11\000ɓulɓusɛ",
+ "jan\000febr\000mar\000apr\000maj\000jun\000jul\000aug\000sept\000okt\000nov\000dec",
+ "Mul\000Ngat\000Taa\000Iwo\000Mam\000Paa\000Nge\000Roo\000Bur\000Epe\000Kpt\000Kpa",
+ "មករា\000កុម្ភៈ\000មីនា\000មេសា\000ឧសភា\000មិថុនា\000កក្កដា\000សីហា\000កញ្ញា\000តុលា\000វិច្ឆិកា\000ធ្នូ",
+ "ಜನ\000ಫೆಬ್ರ\000ಮಾರ್ಚ್\000ಏಪ್ರಿ\000ಮೇ\000ಜೂನ್\000ಜುಲೈ\000ಆಗ\000ಸೆಪ್ಟೆಂ\000ಅಕ್ಟೋ\000ನವೆಂ\000ಡಿಸೆಂ",
+ "1월\0002월\0003월\0004월\0005월\0006월\0007월\0008월\0009월\00010월\00011월\00012월",
+ "जाने\000फेब्रु\000मार्च\000एप्री\000मे\000जून\000जुल\000ऑग\000सप्टें\000ऑक्टो\000नोव्हें\000डिसें",
+ "Jan\000Feb\000Mar\000Abr\000Mai\000Jun\000Jul\000Ago\000Set\000Otu\000Nov\000Dez",
+ "جنؤری\000فرؤری\000مارٕچ\000اپریل\000مئی\000جوٗن\000جُلَے\000اگست\000ستمبر\000اکتوٗبر\000نومبر\000دسمبر",
+ "जनवरी\000फ़रवरी\000मार्च\000अप्रैल\000मई\000जून\000जुलाई\000अगस्त\000सतुंबर\000अक्तूबर\000नवूमबर\000दसमबर",
+ "ŋ1\000ŋ2\000ŋ3\000ŋ4\000ŋ5\000ŋ6\000ŋ7\000ŋ8\000ŋ9\000ŋ10\000ŋ11\000ŋ12",
+ "Jan\000Fäb\000Mäz\000Apr\000Mai\000Jun\000Jul\000Ouj\000Säp\000Okt\000Nov\000Dez",
+ "rbn\000sbt\000adr\000nsn\000gln\000hzr\000trm\000tbx\000îln\000cot\000mjd\000brf",
+ "Gen\000Hwe\000Meu\000Ebr\000Me\000Met\000Gor\000Est\000Gwn\000Hed\000Du\000Kev",
+ "pusu\000maha\000pagu\000hire\000bese\000jaṭṭa\000aasaḍi\000srabĩ\000bado\000dasara\000divi\000pande",
+ "पुसु\000माहा\000पागु\000हिर्रे\000बेसे\000जाट्टा\000आसाड़ी\000स्राबाँ\000बाॅदो\000दासारा\000दिवी\000पान्डे",
+ "ପୁସୁ\000ମାହା\000ପାଗୁ\000ହିରେ\000ବେସେ\000ଜାଟା\000ଆସାଡ଼ି\000ସ୍ରାବାଁ\000ବଦ\000ଦାସାରା\000ଦିୱି\000ପାଣ୍ଡେ",
+ "మాగ\000గుండు\000హిరెఇ\000బెసెకి\000లండి\000రాత\000బాన్దపాణా\000బార్సి\000అస్ర\000దివెడి\000పాండు\000పుసు",
+ "янв.\000фев.\000мар.\000апр.\000май\000июн.\000июл.\000авг.\000сен.\000окт.\000ноя.\000дек.",
+ "Fúngatɨ\000Naanɨ\000Keenda\000Ikúmi\000Inyambala\000Idwaata\000Mʉʉnchɨ\000Vɨɨrɨ\000Saatʉ\000Inyi\000Saano\000Sasatʉ",
+ "Jan.\000Feb.\000Mäe.\000Abr.\000Mee\000Juni\000Juli\000Aug.\000Sep.\000Okt.\000Nov.\000Dez.",
+ "Jan\000Feb\000Mar\000Apu\000Maa\000Juu\000Jul\000Agu\000Seb\000Oki\000Nov\000Des",
+ "de zenâ\000de frevâ\000de marso\000d’arvî\000de mazzo\000de zugno\000de luggio\000d’agosto\000de settembre\000d’ottobre\000de novembre\000de dexembre",
+ "Wiótheȟika Wí\000Thiyóȟeyuŋka Wí\000Ištáwičhayazaŋ Wí\000Pȟežítȟo Wí\000Čhaŋwápetȟo Wí\000Wípazukȟa-wašté Wí\000Čhaŋpȟásapa Wí\000Wasútȟuŋ Wí\000Čhaŋwápeǧi Wí\000Čhaŋwápe-kasná Wí\000Waníyetu Wí\000Tȟahékapšuŋ Wí",
+ "de jená\000de forá\000de merz\000d’aurí\000de ma\000de jügn\000de messé\000d’aost\000de setëmber\000d’otober\000de novëmber\000de dezëmber",
+ "sginer\000fevrer\000marz\000avril\000masg\000sgiugn\000luj\000avost\000setember\000otover\000november\000dicember",
+ "yan\000fbl\000msi\000apl\000mai\000yun\000yul\000agt\000stb\000ɔtb\000nvb\000dsb",
+ "ມ.ກ.\000ກ.ພ.\000ມ.ນ.\000ມ.ສ.\000ພ.ພ.\000ມິ.ຖ.\000ກ.ລ.\000ສ.ຫ.\000ກ.ຍ.\000ຕ.ລ.\000ພ.ຈ.\000ທ.ວ.",
+ "جانڤیە\000فئڤریە\000مارس\000آڤریل\000مئی\000جوٙأن\000جوٙلا\000آگوست\000سئپتامر\000ئوکتوڤر\000نوڤامر\000دئسامر",
+ "saus.\000vas.\000kov.\000bal.\000geg.\000birž.\000liep.\000rugp.\000rugs.\000spal.\000lapkr.\000gruod.",
+ "Cio\000Lui\000Lus\000Muu\000Lum\000Luf\000Kab\000Lush\000Lut\000Lun\000Kas\000Cis",
+ "DAC\000DAR\000DAD\000DAN\000DAH\000DAU\000DAO\000DAB\000DOC\000DAP\000DGI\000DAG",
+ "Jan\000Feb\000Mar\000Apr\000Mei\000Jun\000Jul\000Ago\000Sep\000Okt\000Nov\000Des",
+ "janv.\000febr.\000marts\000apr.\000maijs\000jūn.\000jūl.\000aug.\000sept.\000okt.\000nov.\000dec.",
+ "जन॰\000फ़र॰\000मार्च\000अप्रैल\000मई\000जून\000जुल॰\000अग॰\000सित॰\000अक्तू॰\000नव॰\000दिस॰",
+ "Dal\000Ará\000Ɔɛn\000Doy\000Lép\000Rok\000Sás\000Bɔ́r\000Kús\000Gís\000Shʉ́\000Ntʉ́",
+ "JAN\000FEB\000MAC\000ĨPU\000MĨĨ\000NJU\000NJR\000AGA\000SPT\000OKT\000NOV\000DEC",
+ "zan\000fev\000mar\000avr\000me\000zin\000zil\000out\000sep\000okt\000nov\000des",
+ "Jan\000Feb\000Mar\000Apr\000Mey\000Jon\000Jol\000Aog\000Sep\000Okt\000Nov\000Des",
+ "Kwa\000Una\000Rar\000Che\000Tha\000Moc\000Sab\000Nan\000Tis\000Kum\000Moj\000Yel",
+ "mbegtug\000imeg àbùbì\000imeg mbəŋchubi\000iməg ngwə̀t\000iməg fog\000iməg ichiibɔd\000iməg àdùmbə̀ŋ\000iməg ichika\000iməg kud\000iməg tèsiʼe\000iməg zò\000iməg krizmed",
+ "Hān\000Pēp\000Māe\000Āpe\000Mei\000Hun\000Hūr\000Āku\000Hep\000Oke\000Noe\000Tīh",
+ "јан.\000фев.\000мар.\000апр.\000мај\000јун.\000јул.\000авг.\000сеп.\000окт.\000ное.\000дек.",
+ "ജനു\000ഫെബ്രു\000മാർ\000ഏപ്രി\000മേയ്\000ജൂൺ\000ജൂലൈ\000ഓഗ\000സെപ്റ്റം\000ഒക്ടോ\000നവം\000ഡിസം",
+ "1-р сар\0002-р сар\0003-р сар\0004-р сар\0005-р сар\0006-р сар\0007-р сар\0008-р сар\0009-р сар\00010-р сар\00011-р сар\00012-р сар",
+ "1 ᠊ᠷ ᠰᠠᠷᠠ\0002 ᠊ᠷ ᠰᠠᠷᠠ\0003᠊ᠷ ᠰᠠᠷᠠ\0004 ᠊ᠷ ᠰᠠᠷᠠ\0005 ᠊ᠷ ᠰᠠᠷᠠ\0006 ᠊ᠷ ᠰᠠᠷᠠ\0007 ᠊ᠷ ᠰᠠᠷᠠ\0008᠊ᠷ ᠰᠠᠷᠠ\0009 ᠊ᠷ ᠰᠠᠷᠠ\00010 ᠊ᠷ ᠰᠠᠷᠠ\00011 ᠊ᠷ ᠰᠠᠷᠠ\00012 ᠊ᠷ ᠰᠠᠷᠠ",
+ "জন\000ফেব্রুৱারি\000মার্চ\000এপ্রিল\000মে\000জুন\000জুলাই\000ওগ\000সেপ্টেম্বর\000ওক্টোবর\000নভেম্বর\000ডিসেম্বর",
+ "जाने\000फेब्रु\000मार्च\000एप्रि\000मे\000जून\000जुलै\000ऑग\000सप्टें\000ऑक्टो\000नोव्हें\000डिसें",
+ "Jan\000Feb\000Mac\000Apr\000Mei\000Jun\000Jul\000Ogo\000Sep\000Okt\000Nov\000Dis",
+ "Jan\000Fra\000Mar\000Apr\000Mej\000Ġun\000Lul\000Aww\000Set\000Ott\000Nov\000Diċ",
+ "FLO\000CLA\000CKI\000FMF\000MAD\000MBI\000MLI\000MAM\000FDE\000FMU\000FGW\000FYU",
+ "Rvfo Cuse\000Hotvle Hvse\000Tasahcuce\000Tasahce Rakko\000Ke Hvse\000Kvco Hvse\000Hiyuce\000Hiyo Rakko\000Otowoskuce\000Otowoskv Rakko\000Ehole\000Rvfo Rakko",
+ "ဇန်\000ဖေ\000မတ်\000ဧ\000မေ\000ဇွန်\000ဇူ\000ဩ\000စက်\000အောက်\000နို\000ဒီ",
+ "jan.\000feb.\000mars\000apr.\000mai\000juni\000juli\000aug.\000sep.\000okt.\000nov.\000des.",
+ "Zib\000Nhlo\000Mbi\000Mab\000Nkw\000Nhla\000Ntu\000Ncw\000Mpan\000Mfu\000Lwe\000Mpal",
+ "Januaar\000Februaar\000März\000April\000Mai\000Juni\000Juli\000August\000September\000Oktover\000November\000Dezember",
+ "जनवरी\000फेब्रुअरी\000मार्च\000अप्रिल\000मे\000जुन\000जुलाई\000अगस्ट\000सेप्टेम्बर\000अक्टोबर\000नोभेम्बर\000डिसेम्बर",
+ "jan\000feb\000mrt\000apr\000mei\000jun\000jul\000aug\000sep\000okt\000nov\000dec",
+ "ng1\000ng2\000ng3\000ng4\000ng5\000ng6\000ng7\000ng8\000ng9\000ng10\000ng11\000kris",
+ "saŋ tsetsɛ̀ɛ lùm\000saŋ kàg ngwóŋ\000saŋ lepyè shúm\000saŋ cÿó\000saŋ tsɛ̀ɛ cÿó\000saŋ njÿoláʼ\000saŋ tyɛ̀b tyɛ̀b mbʉ̀ŋ\000saŋ mbʉ̀ŋ\000saŋ ngwɔ̀ʼ mbÿɛ\000saŋ tàŋa tsetsáʼ\000saŋ mejwoŋó\000saŋ lùm",
+ "ߓߌ߲ߠ\000ߞߏ߲ߞ\000ߕߙߊ\000ߞߏ߲ߘ\000ߘߓߊ߬ߕ\000ߥߊ߬ߛ\000ߞߊ߬ߙ\000ߘߓߊ߬ߓ\000ߕߎߟߊߝߌ߲\000ߞߏ߲ߓ\000ߣߍߣ\000ߞߏߟ",
+ "Jan\000Feb\000Mat\000Apo\000Mei\000Jun\000Jul\000Ago\000Sep\000Okt\000Nof\000Dis",
+ "Tiop\000Pɛt\000Duɔ̱ɔ̱\000Guak\000Duä\000Kor\000Pay\000Thoo\000Tɛɛ\000Laa\000Kur\000Tid",
+ "de genièr\000de febrièr\000de març\000d’abril\000de mai\000de junh\000de julhet\000d’agost\000de setembre\000d’octòbre\000de novembre\000de decembre",
+ "Ama\000Gur\000Bitootessa\000Elb\000Cam\000Wax\000Ado\000Hag\000Ful\000Onk\000Sadaasa\000Mud",
+ "ଜାନୁଆରୀ\000ଫେବୃଆରୀ\000ମାର୍ଚ୍ଚ\000ଅପ୍ରେଲ\000ମଇ\000ଜୁନ\000ଜୁଲାଇ\000ଅଗଷ୍ଟ\000ସେପ୍ଟେମ୍ବର\000ଅକ୍ଟୋବର\000ନଭେମ୍ବର\000ଡିସେମ୍ବର",
+ "янв.\000фев.\000мар.\000апр.\000майы\000июны\000июлы\000авг.\000сен.\000окт.\000ноя.\000дек.",
+ "𐓄𐓘𐓡𐓛͘𐓧𐓟\000𐓵𐓪͘𐓬𐓘\000𐓵𐓘𐓜𐓣\000𐓰𐓪𐓬𐓘\000𐓮𐓘𐓰𐓘\000𐓯𐓘𐓬𐓟\000𐓄𐓟𐓵𐓪͘𐓬𐓘\000𐒼𐓣𐓟𐓰𐓪𐓬𐓘\000𐒿𐓟𐓜𐓛𐓲𐓟𐓷𐓣͘𐓤𐓟\000𐒿𐓟𐓜𐓛\000𐒰𐓧𐓣 𐓏𐓣͘𐓸𐓲𐓣\000𐒰𐓧𐓣 𐓍𐓪͘𐓬𐓘",
+ "ਜਨ\000ਫ਼ਰ\000ਮਾਰਚ\000ਅਪ੍ਰੈ\000ਮਈ\000ਜੂਨ\000ਜੁਲਾ\000ਅਗ\000ਸਤੰ\000ਅਕਤੂ\000ਨਵੰ\000ਦਸੰ",
+ "جنوری\000فروری\000مارچ\000اپریل\000مئ\000جون\000جولائی\000اگست\000ستمبر\000اکتوبر\000نومبر\000دسمبر",
+ "Yanüari\000Febrüari\000Mart\000Aprel\000Mei\000Yüni\000Yüli\000Ougùstùs\000Sèptèmber\000Òktober\000Novèmber\000Desèmber",
+ "Jén\000Fẹ́b\000Mach\000Épr\000Mee\000Jun\000Jul\000Ọgọ\000Sẹp\000Ọkt\000Nọv\000Dis",
+ "Januare\000Febuare\000Mas\000Eprel\000Mei\000Jun\000Julae\000Ogus\000Septemba\000Oktoba\000Novemba\000Disemba",
+ "sty\000lut\000mar\000kwi\000maj\000cze\000lip\000sie\000wrz\000paź\000lis\000gru",
+ "gené\000fërvé\000mars\000avril\000magg\000giugn\000lugn\000agost\000stèmber\000utuber\000novèmber\000dzèmber",
+ "rags\000wassarins\000pūlis\000sakkis\000zallaws\000sīmenis\000līpa\000daggis\000sillins\000spallins\000lapkrūtis\000sallaws",
+ "جنوري\000فبروري\000مارچ\000اپریل\000مۍ\000جون\000جولای\000اګست\000سېپتمبر\000اکتوبر\000نومبر\000دسمبر",
+ "jan.\000fev.\000mar.\000abr.\000mai.\000jun.\000jul.\000ago.\000set.\000out.\000nov.\000dez.",
+ "Ene\000Feb\000Mar\000Abr\000May\000Jun\000Jul\000Ago\000Set\000Oct\000Nov\000Dic",
+ "schan.\000favr.\000mars\000avr.\000matg\000zercl.\000fan.\000avust\000sett.\000oct.\000nov.\000dec.",
+ "Mut.\000Gas.\000Wer.\000Mat.\000Gic.\000Kam.\000Nya.\000Kan.\000Nze.\000Ukw.\000Ugu.\000Uku.",
+ "ian.\000feb.\000mar.\000apr.\000mai\000iun.\000iul.\000aug.\000sept.\000oct.\000nov.\000dec.",
+ "M1\000M2\000M3\000M4\000M5\000M6\000M7\000M8\000M9\000M10\000M11\000M12",
+ "янв.\000февр.\000мар.\000апр.\000мая\000июн.\000июл.\000авг.\000сент.\000окт.\000нояб.\000дек.",
+ "जनवरी:\000फरवरी:\000मार्च:\000अप्रैल:\000मई\000जून:\000जुलाई:\000अगस्त:\000सितंबर:\000अक्तूबर:\000नवंबर:\000दिसंबर:",
+ "Тохс\000Олун\000Клн\000Мсу\000Ыам\000Бэс\000Отй\000Атр\000Блҕ\000Алт\000Сэт\000Ахс",
+ "Obo\000Waa\000Oku\000Ong\000Ime\000Ile\000Sap\000Isi\000Saa\000Tom\000Tob\000Tow",
+ "ᱡᱟᱱ\000ᱯᱷᱟ\000ᱢᱟᱨ\000ᱟᱯᱨ\000ᱢᱮ\000ᱡᱩᱱ\000ᱡᱩᱞ\000ᱟᱜᱟ\000ᱥᱮᱯ\000ᱚᱠᱴ\000ᱱᱟᱣ\000ᱫᱤᱥ",
+ "Mup\000Mwi\000Msh\000Mun\000Mag\000Muj\000Msp\000Mpg\000Mye\000Mok\000Mus\000Muh",
+ "ghe\000fre\000mar\000abr\000maj\000làm\000trì\000aus\000cab\000stG\000stA\000nad",
+ "jin\000fri\000mar\000apr\000maj\000giu\000gnt\000agu\000sit\000utt\000nuv\000dic",
+ "جنوري\000فيبروري\000مارچ\000اپريل\000مئي\000جون\000جولاءِ\000آگسٽ\000سيپٽمبر\000آڪٽوبر\000نومبر\000ڊسمبر",
+ "जन\000फर\000मार्च\000अप्रै\000मई\000जून\000जु\000अग\000सप्टे\000ऑक्टो\000नवं\000डिसं",
+ "ođđj\000guov\000njuk\000cuo\000mies\000geas\000suoi\000borg\000čakč\000golg\000skáb\000juov",
+ "ođđj\000guov\000njuk\000cuoŋ\000mies\000geas\000suoi\000borg\000čakč\000golg\000skáb\000juov",
+ "Jan\000Fev\000Mar\000Abr\000Mai\000Jun\000Jul\000Aug\000Set\000Otu\000Nov\000Dec",
+ "Nye\000Ful\000Mbä\000Ngu\000Bêl\000Fön\000Len\000Kük\000Mvu\000Ngb\000Nab\000Kak",
+ "ⵉⵏⵏ\000ⴱⵕⴰ\000ⵎⴰⵕ\000ⵉⴱⵔ\000ⵎⴰⵢ\000ⵢⵓⵏ\000ⵢⵓⵍ\000ⵖⵓⵛ\000ⵛⵓⵜ\000ⴽⵜⵓ\000ⵏⵓⵡ\000ⴷⵓⵊ",
+ "inn\000bṛa\000maṛ\000ibr\000may\000yun\000yul\000ɣuc\000cut\000ktu\000nuw\000duj",
+ "ၸၼ်ႇ\000ၾႅပ်ႇ\000မၢတ်ႉၶ်ျ\000ဢေႇ\000မေႇ\000ၸုၼ်ႇ\000ၸူႇ\000ဢေႃး\000သႅပ်ႇ\000ဢွၵ်ႇ\000ၼူဝ်ႇ\000တီႇ",
+ "දුරුතු\000නවම්\000මැදින්\000බක්\000වෙසක්\000පොසොන්\000ඇසළ\000නිකිණි\000බිනර\000වප්\000ඉල්\000උඳුවප්",
+ "jan\000feb\000mar\000apr\000máj\000jún\000júl\000aug\000sep\000okt\000nov\000dec",
+ "jan.\000feb.\000mar.\000apr.\000maj\000jun.\000jul.\000avg.\000sep.\000okt.\000nov.\000dec.",
+ "uđiv\000kuovâ\000njuhčâ\000cuáŋui\000vyesi\000kesi\000syeini\000porge\000čohčâ\000roovvâd\000skammâ\000juovlâ",
+ "Ndi\000Kuk\000Kur\000Kub\000Chv\000Chk\000Chg\000Nya\000Gun\000Gum\000Mbu\000Zvi",
+ "Jan\000Feb\000Mar\000Abr\000May\000Jun\000Lul\000Ogs\000Seb\000Okt\000Nof\000Dis",
+ "jan\000shk\000mar\000pri\000maj\000qer\000korr\000gush\000sht\000tet\000nën\000dhj",
+ "јан\000феб\000мар\000апр\000мај\000јун\000јул\000авг\000сеп\000окт\000нов\000дец",
+ "јан\000феб\000март\000апр\000мај\000јун\000јул\000авг\000септ\000окт\000нов\000дец",
+ "jan\000feb\000mar\000apr\000maj\000jun\000jul\000avg\000sep\000okt\000nov\000dec",
+ "jan\000feb\000mart\000apr\000maj\000jun\000jul\000avg\000sept\000okt\000nov\000dec",
+ "Phe\000Kol\000Hlb\000Mme\000Mot\000Jan\000Upu\000Pha\000Leo\000Mph\000Pun\000Tsh",
+ "Jan\000Péb\000Mar\000Apr\000Méi\000Jun\000Jul\000Ags\000Sép\000Okt\000Nop\000Dés",
+ "jan.\000feb.\000mars\000apr.\000maj\000juni\000juli\000aug.\000sep.\000okt.\000nov.\000dec.",
+ "ܟܢܘܢ ܒ\000ܫܒܛ\000ܐܕܪ\000ܢܝܣܢ\000ܐܝܪ\000ܚܙܝܪܢ\000ܬܡܘܙ\000ܐܒ\000ܐܝܠܘܠ\000ܬܫܪܝܢ ܐ\000ܬܫܪܝܢ ܒ\000ܟܢܘܢ ܐ",
+ "stycznia\000lutego\000marca\000kwietnia\000moja\000czyrwca\000lipca\000siyrpnia\000września\000października\000listopada\000grudnia",
+ "ஜன.\000பிப்.\000மார்.\000ஏப்.\000மே\000ஜூன்\000ஜூலை\000ஆக.\000செப்.\000அக்.\000நவ.\000டிச.",
+ "జన\000ఫిబ్ర\000మార్చి\000ఏప్రి\000మే\000జూన్\000జులై\000ఆగ\000సెప్టెం\000అక్టో\000నవం\000డిసెం",
+ "Rar\000Muk\000Kwa\000Dun\000Mar\000Mod\000Jol\000Ped\000Sok\000Tib\000Lab\000Poo",
+ "Янв\000Фев\000Мар\000Апр\000Май\000Июн\000Июл\000Авг\000Сен\000Окт\000Ноя\000Дек",
+ "ม.ค.\000ก.พ.\000มี.ค.\000เม.ย.\000พ.ค.\000มิ.ย.\000ก.ค.\000ส.ค.\000ก.ย.\000ต.ค.\000พ.ย.\000ธ.ค.",
+ "ጥሪ\000ለካ\000መጋ\000ሚያ\000ግን\000ሰነ\000ሓም\000ነሓ\000መስ\000ጥቅ\000ሕዳ\000ታሕ",
+ "ýan\000few\000mart\000apr\000maý\000iýun\000iýul\000awg\000sen\000okt\000noý\000dek",
+ "Fer\000Tlh\000Mop\000Mor\000Mot\000See\000Phu\000Pha\000Lwe\000Dip\000Ngw\000Sed",
+ "Sān\000Fēp\000Maʻa\000ʻEpe\000Mē\000Sun\000Siu\000ʻAok\000Sēp\000ʻOka\000Nōv\000Tīs",
+ "tenpo mun #1\000tenpo mun #2\000tenpo mun #3\000tenpo mun #4\000tenpo mun #5\000tenpo mun #6\000tenpo mun #7\000tenpo mun #8\000tenpo mun #9\000tenpo mun #10\000tenpo mun #11\000tenpo mun #12",
+ "Janueri\000Februeri\000Mas\000Epril\000Me\000Jun\000Julai\000Ogas\000Septemba\000Oktoba\000Novemba\000Desemba",
+ "Oca\000Şub\000Mar\000Nis\000May\000Haz\000Tem\000Ağu\000Eyl\000Eki\000Kas\000Ara",
+ "Sun\000Yan\000Kul\000Dzi\000Mud\000Kho\000Maw\000Mha\000Ndz\000Nhl\000Huk\000N’w",
+ "гыйн.\000фев.\000мар.\000апр.\000май\000июнь\000июль\000авг.\000сент.\000окт.\000нояб.\000дек.",
+ "Янв.\000Февр.\000Мар.\000Апр.\000Май\000Июн.\000Июл.\000Авг.\000Сент.\000Окт.\000Нояб.\000Дек.",
+ "Yen\000Yeb\000Mar\000Ibr\000May\000Yun\000Yul\000Ɣuc\000Cut\000Kṭu\000Nwa\000Duj",
+ "يانۋار\000فېۋرال\000مارت\000ئاپرېل\000ماي\000ئىيۇن\000ئىيۇل\000ئاۋغۇست\000سېنتەبىر\000ئۆكتەبىر\000نويابىر\000دېكابىر",
+ "січ.\000лют.\000бер.\000квіт.\000трав.\000черв.\000лип.\000серп.\000вер.\000жовт.\000лист.\000груд.",
+ "جنوری\000فروری\000مارچ\000اپریل\000مئی\000جون\000جولائی\000اگست\000ستمبر\000اکتوبر\000نومبر\000دسمبر",
+ "yan\000fev\000mar\000apr\000may\000iyn\000iyl\000avg\000sen\000okt\000noy\000dek",
+ "جنو\000فبر\000مار\000اپر\000می\000جون\000جول\000اگس\000سپت\000اکت\000نوم\000دسم",
+ "ꖨꖕꔞ\000ꕒꕡ\000ꕾꖺ\000ꖢꖕ\000ꖑꕱ\000ꖱꘋ\000ꖱꕞ\000ꗛꔕ\000ꕢꕌ\000ꕭꖃ\000ꔞꘋ\000ꖨꖕꗏ",
+ "jen\000feb\000mar\000apr\000maj\000jug\000luj\000ago\000set\000oto\000nov\000dez",
+ "thg 1\000thg 2\000thg 3\000thg 4\000thg 5\000thg 6\000thg 7\000thg 8\000thg 9\000thg 10\000thg 11\000thg 12",
+ "janeiru\000fevereiru\000marsu\000abril\000maiu\000junyu\000julyu\000agostu\000setembru\000outubru\000novembru\000dezembru",
+ "Jen\000Hor\000Mär\000Abr\000Mei\000Brá\000Hei\000Öig\000Her\000Wím\000Win\000Chr",
+ "Sam\000Few\000Mar\000Awr\000Mee\000Suw\000Sul\000Ut\000Sàt\000Okt\000Now\000Des",
+ "Jan\000Feb\000Mat\000Epr\000Mey\000Jun\000Jul\000Aga\000Sept\000Okt\000Nov\000Dis",
+ "o.1\000o.2\000o.3\000o.4\000o.5\000o.6\000o.7\000o.8\000o.9\000o.10\000o.11\000o.12",
+ "יאַנואַר\000פֿעברואַר\000מערץ\000אַפּריל\000מיי\000יוני\000יולי\000אויגוסט\000סעפּטעמבער\000אקטאבער\000נאוועמבער\000דעצעמבער",
+ "Oṣù Ṣẹ́rẹ́\000Oṣù Èrèlè\000Oṣù Ẹrẹ̀nà\000Oṣù Ìgbé\000Oṣù Ẹ̀bibi\000Oṣù Òkúdu\000Oṣù Agẹmọ\000Oṣù Ògún\000Oṣù Owewe\000Oṣù Ọ̀wàrà\000Oṣù Bélú\000Oṣù Ọ̀pẹ̀",
+ "Oshù Shɛ́rɛ́\000Oshù Èrèlè\000Oshù Ɛrɛ̀nà\000Oshù Ìgbé\000Oshù Ɛ̀bibi\000Oshù Òkúdu\000Oshù Agɛmɔ\000Oshù Ògún\000Oshù Owewe\000Oshù Ɔ̀wàrà\000Oshù Bélú\000Oshù Ɔ̀pɛ̀",
+ "ye\000mk\000ms\000id\000pu\000py\000pm\000ps\000pi\000yp\000yy\000ym",
+ "ndwenit\000ndwenngeih\000ndwensam\000ndwenseiq\000ndwenngux\000ndwenloeg\000ndwencaet\000ndwenbet\000ndwengouj\000ndwencib\000ndwencib’it\000ndwencibngeih",
+ "Jan\000Feb\000Mas\000Eph\000Mey\000Jun\000Jul\000Aga\000Sep\000Okt\000Nov\000Dis",
+};
+
+const char *month_narrow_tab[] = {
+ "1\0002\0003\0004\0005\0006\0007\0008\0009\00010\00011\00012",
+ "J\000F\000M\000A\000M\000J\000J\000A\000S\000O\000N\000D",
+ "n\000k\000t\000t\000s\000z\000k\000f\000d\000l\000c\000f",
+ "Ɔp\000Ɔg\000Ɔb\000O\000K\000A\000Ku\000A\000S\000O\000N\000D",
+ "ጃ\000ፌ\000ማ\000ኤ\000ሜ\000ጁ\000ጁ\000ኦ\000ሴ\000ኦ\000ኖ\000ዲ",
+ "ي\000ف\000م\000أ\000و\000ن\000ل\000غ\000س\000ك\000ب\000د",
+ "ج\000ف\000م\000أ\000م\000ج\000ج\000أ\000س\000أ\000ن\000د",
+ "ك\000ش\000آ\000ن\000أ\000ح\000ت\000آ\000أ\000ت\000ت\000ك",
+ "ي\000ف\000م\000أ\000م\000ن\000ل\000غ\000ش\000ك\000ب\000د",
+ "ي\000ف\000م\000إ\000و\000ن\000ل\000غ\000ش\000ك\000ب\000د",
+ "জ\000ফ\000ম\000এ\000ম\000জ\000জ\000আ\000ছ\000অ\000ন\000ড",
+ "X\000F\000M\000A\000M\000X\000X\000A\000S\000O\000P\000A",
+ "Ғ\000Ф\000М\000А\000М\000И\000И\000А\000С\000О\000Н\000Д",
+ "k\000m\000m\000m\000m\000h\000n\000h\000d\000b\000m\000l",
+ "с\000л\000с\000к\000м\000ч\000л\000ж\000в\000к\000л\000с",
+ "J\000F\000M\000E\000M\000J\000J\000O\000S\000O\000N\000D",
+ "H\000V\000D\000T\000H\000S\000S\000N\000T\000K\000K\000K",
+ "я\000ф\000м\000а\000м\000ю\000ю\000а\000с\000о\000н\000д",
+ "Z\000F\000M\000A\000M\000Z\000Z\000U\000S\000Ɔ\000N\000D",
+ "জা\000ফে\000মা\000এ\000মে\000জুন\000জু\000আ\000সে\000অ\000ন\000ডি",
+ "জা\000ফে\000মা\000এ\000মে\000জুন\000জুল\000আ\000সে\000অ\000ন\000ডি",
+ "01\00002\00003\00004\00005\00006\00007\00008\00009\00010\00011\00012",
+ "ज\000फ\000म\000ए\000म\000ज\000ज\000आ\000स\000अ\000न\000ड",
+ "jan\000feb\000mar\000apr\000may\000jun\000jul\000aug\000sep\000okt\000nov\000dec",
+ "ј\000ф\000м\000а\000м\000ј\000ј\000а\000с\000о\000н\000д",
+ "GN\000FB\000MÇ\000AB\000MG\000JN\000JL\000AG\000ST\000OC\000NV\000DS",
+ "𑄎\000𑄜𑄬\000𑄟\000𑄃𑄬\000𑄟𑄬\000𑄎𑄪𑄚𑄴\000𑄎𑄪\000𑄃\000𑄥𑄬\000𑄃𑄧\000𑄚𑄧\000𑄓𑄨",
+ "Я\000Ф\000М\000А\000М\000И\000И\000А\000С\000О\000Н\000Д",
+ "E\000P\000M\000A\000M\000H\000H\000A\000S\000O\000N\000D",
+ "Ꭴ\000Ꭷ\000Ꭰ\000Ꭷ\000Ꭰ\000Ꮥ\000Ꭻ\000Ꭶ\000Ꮪ\000Ꮪ\000Ꮕ\000Ꭵ",
+ "ک\000ش\000ئ\000ن\000ئ\000ح\000ت\000ئ\000ئ\000ت\000ت\000ک",
+ "К\000Н\000П\000А\000Ҫ\000Ҫ\000У\000Ҫ\000А\000Ю\000Ч\000Р",
+ "I\000Ch\000M\000E\000M\000M\000G\000A\000M\000H\000T\000Rh",
+ "I\000K\000K\000K\000K\000K\000M\000W\000I\000I\000I\000I",
+ "Ž\000F\000M\000A\000M\000Ž\000Ž\000U\000S\000O\000N\000D",
+ "ज\000फ\000मा\000अ\000मे\000जू\000जु\000अ\000सि\000अ\000न\000दि",
+ "j\000f\000m\000a\000m\000j\000j\000a\000s\000o\000n\000d",
+ "d\000ŋ\000s\000d\000e\000e\000m\000d\000n\000m\000t\000e",
+ "S\000F\000M\000A\000M\000S\000S\000U\000S\000O\000N\000D",
+ "༡\000༢\000༣\0004\000༥\000༦\000༧\000༨\0009\000༡༠\000༡༡\000༡༢",
+ "M\000K\000K\000K\000G\000G\000M\000K\000K\000I\000I\000I",
+ "d\000d\000t\000a\000d\000m\000s\000d\000a\000k\000a\000d",
+ "Ι\000Φ\000Μ\000Α\000Μ\000Ι\000Ι\000Α\000Σ\000Ο\000Ν\000Δ",
+ "𐐖\000𐐙\000𐐣\000𐐁\000𐐣\000𐐖\000𐐖\000𐐂\000𐐝\000𐐉\000𐐤\000𐐔",
+ "𐑡\000𐑓\000𐑥\000𐑱\000𐑥\000𐑡\000𐑡\000𐑪\000𐑕\000𐑷\000𐑯\000𐑛",
+ "E\000F\000M\000A\000M\000J\000J\000A\000S\000O\000N\000D",
+ "J\000V\000M\000A\000M\000J\000J\000A\000S\000O\000N\000D",
+ "U\000O\000M\000A\000M\000E\000U\000A\000I\000U\000A\000A",
+ "o\000b\000l\000n\000t\000s\000z\000m\000e\000a\000d\000b",
+ "ژ\000ف\000م\000آ\000م\000ژ\000ژ\000ا\000س\000ا\000ن\000د",
+ "ج\000ف\000م\000ا\000م\000ج\000ج\000ا\000س\000ا\000ن\000د",
+ "s\000c\000m\000s\000d\000k\000m\000j\000s\000y\000j\000b",
+ "𞤅\000𞤕\000𞤄\000𞤅\000𞤁\000𞤑\000𞤃\000𞤔\000𞤅\000𞤒\000𞤔\000𞤄",
+ "T\000H\000M\000H\000T\000K\000H\000E\000S\000L\000M\000J",
+ "Ene\000Peb\000Mar\000Abr\000May\000Hun\000Hul\000Ago\000Set\000Okt\000Nob\000Dis",
+ "Z\000F\000M\000A\000M\000J\000L\000A\000S\000O\000N\000D",
+ "E\000F\000M\000A\000B\000M\000I\000L\000M\000D\000S\000N",
+ "F\000G\000M\000G\000C\000Ò\000I\000L\000S\000D\000S\000D",
+ "x.\000f.\000m.\000a.\000m.\000x.\000x.\000a.\000s.\000o.\000n.\000d.",
+ "જા\000ફે\000મા\000એ\000મે\000જૂ\000જુ\000ઑ\000સ\000ઑ\000ન\000ડિ",
+ "C\000F\000M\000A\000M\000J\000C\000A\000S\000O\000N\000D",
+ "J\000F\000M\000A\000M\000Y\000Y\000A\000S\000O\000N\000D",
+ "ज\000फ़\000मा\000अ\000म\000जू\000जु\000अ\000सि\000अ\000न\000दि",
+ "1.\0002.\0003.\0004.\0005.\0006.\0007.\0008.\0009.\00010.\00011.\00012.",
+ "J\000F\000M\000Á\000M\000J\000J\000A\000Sz\000O\000N\000D",
+ "Հ\000Փ\000Մ\000Ա\000Մ\000Հ\000Հ\000Օ\000Ս\000Հ\000Ն\000Դ",
+ "J\000F\000M\000E\000M\000J\000J\000Ọ\000S\000Ọ\000N\000D",
+ "J\000F\000M\000A\000M\000J\000J\000Á\000S\000O\000N\000D",
+ "G\000F\000M\000A\000M\000G\000L\000A\000S\000O\000N\000D",
+ "ი\000თ\000მ\000ა\000მ\000ი\000ი\000ა\000ს\000ო\000ნ\000დ",
+ "Y\000F\000M\000Y\000M\000Y\000Y\000Ɣ\000C\000T\000N\000D",
+ "M\000K\000K\000K\000K\000T\000M\000N\000K\000Ĩ\000Ĩ\000Ĩ",
+ "1K\0002K\0003K\0004K\0005K\0006K\0007K\0008K\0009K\00010K\00011K\00012K",
+ "J\000K\000G\000K\000G\000G\000M\000K\000K\000I\000I\000D",
+ "Қ\000А\000Н\000С\000М\000М\000Ш\000Т\000Қ\000Қ\000Қ\000Ж",
+ "M\000N\000T\000I\000M\000P\000N\000R\000B\000E\000K\000K",
+ "ម\000ក\000ម\000ម\000ឧ\000ម\000ក\000ស\000ក\000ត\000វ\000ធ",
+ "ಜ\000ಫೆ\000ಮಾ\000ಏ\000ಮೇ\000ಜೂ\000ಜು\000ಆ\000ಸೆ\000ಅ\000ನ\000ಡಿ",
+ "1월\0002월\0003월\0004월\0005월\0006월\0007월\0008월\0009월\00010월\00011월\00012월",
+ "जा\000फे\000मा\000ए\000मे\000जू\000जु\000ऑ\000स\000ऑ\000नो\000डि",
+ "ج\000ف\000م\000ا\000م\000ج\000ج\000ا\000س\000س\000ا\000ن",
+ "ज\000फ़\000म\000अ\000म\000ज\000ज\000अ\000स\000ओ\000न\000द",
+ "J\000F\000M\000A\000M\000J\000J\000O\000S\000O\000N\000D",
+ "R\000S\000A\000N\000G\000H\000T\000T\000Î\000C\000M\000B",
+ "pu\000ma\000pa\000hi\000be\000ja\000aa\000sra\000b\000da\000di\000pa",
+ "पु\000मा\000पा\000हि\000बे\000जा\000आ\000स्रा\000बाॅ\000दा\000दि\000पा",
+ "ପୁ\000ମା\000ପା\000ହି\000ବେ\000ଜା\000ଆ\000ସ୍ରା\000ବ\000ଦା\000ଦି\000ପା",
+ "మా\000గు\000హి\000బె\000ల\000రా\000బా\000బా\000అ\000ది\000పా\000పు",
+ "F\000N\000K\000I\000I\000I\000M\000V\000S\000I\000S\000S",
+ "J\000F\000M\000A\000M\000J\000M\000A\000S\000O\000N\000D",
+ "y\000f\000m\000a\000m\000y\000y\000a\000s\000ɔ\000n\000d",
+ "S\000V\000K\000B\000G\000B\000L\000R\000R\000S\000L\000G",
+ "C\000L\000L\000M\000L\000L\000K\000L\000L\000L\000K\000C",
+ "C\000R\000D\000N\000B\000U\000B\000B\000C\000P\000C\000P",
+ "ज\000फ\000मा\000अ\000म\000जू\000जु\000अ\000सि\000अ\000न\000दि",
+ "J\000F\000M\000Ĩ\000M\000N\000N\000A\000S\000O\000N\000D",
+ "z\000f\000m\000a\000m\000z\000z\000o\000s\000o\000n\000d",
+ "K\000U\000R\000C\000T\000M\000S\000N\000T\000K\000M\000Y",
+ "M1\000A2\000M3\000N4\000F5\000I6\000A7\000I8\000K9\00010\00011\00012",
+ "H\000P\000M\000Ā\000M\000H\000H\000Ā\000H\000O\000N\000T",
+ "ജ\000ഫെ\000മാ\000ഏ\000മെ\000ജൂൺ\000ജൂ\000ഓ\000സെ\000ഒ\000ന\000ഡി",
+ "I\000II\000III\000IV\000V\000VI\000VII\000VIII\000IX\000X\000XI\000XII",
+ "জা\000ফে\000মার\000এপ\000মে\000জুন\000জুল\000আ\000সে\000ওক\000নব\000ডি",
+ "J\000F\000M\000A\000M\000Ġ\000L\000A\000S\000O\000N\000D",
+ "O\000A\000I\000F\000D\000B\000L\000M\000E\000U\000W\000Y",
+ "ဇ\000ဖ\000မ\000ဧ\000မ\000ဇ\000ဇ\000ဩ\000စ\000အ\000န\000ဒ",
+ "Z\000N\000M\000M\000N\000N\000N\000N\000M\000M\000L\000M",
+ "जन\000फेब\000मार्च\000अप्र\000मे\000जुन\000जुल\000अग\000सेप\000अक्टो\000नोभे\000डिसे",
+ "ߓ\000ߞ\000ߕ\000ߞ\000ߘ\000ߥ\000ߞ\000ߘ\000ߕ\000ߞ\000ߣ\000ߞ",
+ "P\000D\000H\000M\000M\000P\000M\000P\000L\000D\000D\000M",
+ "T\000P\000D\000G\000D\000K\000P\000T\000T\000L\000K\000T",
+ "A\000G\000B\000E\000C\000W\000A\000H\000F\000O\000S\000M",
+ "ଜା\000ଫେ\000ମା\000ଅ\000ମଇ\000ଜୁ\000ଜୁ\000ଅ\000ସେ\000ଅ\000ନ\000ଡି",
+ "ਜ\000ਫ਼\000ਮਾ\000ਅ\000ਮ\000ਜੂ\000ਜੁ\000ਅ\000ਸ\000ਅ\000ਨ\000ਦ",
+ "s\000l\000m\000k\000m\000c\000l\000s\000w\000p\000l\000g",
+ "S\000F\000M\000A\000M\000Z\000F\000A\000S\000O\000N\000D",
+ "I\000F\000M\000A\000M\000I\000I\000A\000S\000O\000N\000D",
+ "K\000K\000K\000K\000T\000S\000S\000N\000T\000I\000I\000I",
+ "Т\000О\000К\000М\000Ы\000Б\000О\000А\000Б\000А\000С\000А",
+ "O\000W\000O\000O\000I\000I\000S\000I\000S\000T\000T\000T",
+ "ᱡ\000ᱯ\000ᱢ\000ᱟ\000ᱢ\000ᱡ\000ᱡ\000ᱟ\000ᱥ\000ᱚ\000ᱱ\000ᱫ",
+ "G\000F\000M\000A\000M\000L\000T\000A\000C\000S\000S\000N",
+ "J\000F\000M\000A\000M\000G\000G\000A\000S\000U\000N\000D",
+ "ज\000फ़\000मा\000अ\000मा\000जू\000जु\000अग\000स\000ऑ\000न\000डि",
+ "O\000G\000N\000C\000M\000G\000S\000B\000Č\000G\000S\000J",
+ "N\000F\000M\000N\000B\000F\000L\000K\000M\000N\000N\000K",
+ "ⵉ\000ⴱ\000ⵎ\000ⵉ\000ⵎ\000ⵢ\000ⵢ\000ⵖ\000ⵛ\000ⴽ\000ⵏ\000ⴷ",
+ "i\000b\000m\000i\000m\000y\000y\000ɣ\000c\000k\000n\000d",
+ "ၸ.\000ၾ.\000မ.\000ဢ.\000မ.\000ၸ.\000ၸ.\000ဢ.\000သ.\000ဢ.\000ၼ.\000တ.",
+ "දු\000න\000මැ\000බ\000වෙ\000පො\000ඇ\000නි\000බි\000ව\000ඉ\000උ",
+ "U\000K\000NJ\000C\000V\000K\000S\000P\000Č\000R\000S\000J",
+ "N\000K\000K\000K\000C\000C\000C\000N\000G\000G\000M\000Z",
+ "J\000F\000M\000A\000M\000J\000L\000O\000S\000O\000N\000D",
+ "j\000sh\000m\000p\000m\000q\000k\000g\000sh\000t\000n\000dh",
+ "J\000P\000M\000A\000M\000J\000J\000A\000S\000O\000N\000D",
+ "ܟ\000ܫ\000ܐ\000ܢ\000ܐ\000ܚ\000ܬ\000ܐ\000ܐ\000ܬ\000ܬ\000ܟ",
+ "ஜ\000பி\000மா\000ஏ\000மே\000ஜூ\000ஜூ\000ஆ\000செ\000அ\000ந\000டி",
+ "జ\000ఫి\000మా\000ఏ\000మే\000జూ\000జు\000ఆ\000సె\000అ\000న\000డి",
+ "R\000M\000K\000D\000M\000M\000J\000P\000S\000T\000L\000P",
+ "ม.ค.\000ก.พ.\000มี.ค.\000เม.ย.\000พ.ค.\000มิ.ย.\000ก.ค.\000ส.ค.\000ก.ย.\000ต.ค.\000พ.ย.\000ธ.ค.",
+ "ጥ\000ለ\000መ\000ሚ\000ግ\000ሰ\000ሓ\000ነ\000መ\000ጥ\000ሕ\000ታ",
+ "Ý\000F\000M\000A\000M\000I\000I\000A\000S\000O\000N\000D",
+ "S\000F\000M\000ʻE\000M\000S\000S\000ʻA\000S\000ʻO\000N\000T",
+ "O\000Ş\000M\000N\000M\000H\000T\000A\000E\000E\000K\000A",
+ "Y\000Y\000M\000I\000M\000Y\000Y\000Ɣ\000C\000K\000N\000D",
+ "с\000л\000б\000к\000т\000ч\000л\000с\000в\000ж\000л\000г",
+ "Y\000F\000M\000A\000M\000I\000I\000A\000S\000O\000N\000D",
+ "J\000F\000M\000A\000M\000J\000L\000A\000S\000O\000N\000D",
+ "J\000H\000M\000A\000M\000B\000H\000Ö\000H\000W\000W\000C",
+ "S\000È\000Ẹ\000Ì\000Ẹ̀\000Ò\000A\000Ò\000O\000Ọ̀\000B\000Ọ̀",
+ "S\000È\000Ɛ\000Ì\000Ɛ̀\000Ò\000A\000Ò\000O\000Ɔ̀\000B\000Ɔ̀",
+ "Y\000M\000M\000I\000P\000P\000P\000P\000P\000Y\000Y\000Y",
+ "J\000F\000M\000E\000M\000J\000J\000A\000S\000O\000N\000D",
+};
+
+const char *weekday_long_tab[] = {
+ "Sun\000Mon\000Tue\000Wed\000Thu\000Fri\000Sat",
+ "Sondag\000Maandag\000Dinsdag\000Woensdag\000Donderdag\000Vrydag\000Saterdag",
+ "tsuʔntsɨ\000tsuʔukpà\000tsuʔughɔe\000tsuʔutɔ̀mlò\000tsuʔumè\000tsuʔughɨ̂m\000tsuʔndzɨkɔʔɔ",
+ "Sun\000Dwoada\000Benada\000Wukuada\000Yawoada\000Fiada\000Memeneda",
+ "እሑድ\000ሰኞ\000ማክሰኞ\000ረቡዕ\000ሐሙስ\000ዓርብ\000ቅዳሜ",
+ "الأحد\000الاثنين\000الثلاثاء\000الأربعاء\000الخميس\000الجمعة\000السبت",
+ "দেওবাৰ\000সোমবাৰ\000মঙ্গলবাৰ\000বুধবাৰ\000বৃহস্পতিবাৰ\000শুক্ৰবাৰ\000শনিবাৰ",
+ "Jumapili\000Jumatatu\000Jumanne\000Jumatano\000Alhamisi\000Ijumaa\000Jumamosi",
+ "domingu\000llunes\000martes\000miércoles\000xueves\000vienres\000sábadu",
+ "bazar\000bazar ertəsi\000çərşənbə axşamı\000çərşənbə\000cümə axşamı\000cümə\000şənbə",
+ "базар\000базар ертәси\000чәршәнбә ахшамы\000чәршәнбә\000ҹүмә ахшамы\000ҹүмә\000шәнбә",
+ "йәкшәмбе\000дүшәмбе\000шишәмбе\000шаршамбы\000кесаҙна\000йома\000шәмбе",
+ "Yakshambeh\000Doshambeh\000Sayshambeh\000Chárshambeh\000Panchshambeh\000Jomah\000Shambeh",
+ "ŋgwà nɔ̂y\000ŋgwà njaŋgumba\000ŋgwà ûm\000ŋgwà ŋgê\000ŋgwà mbɔk\000ŋgwà kɔɔ\000ŋgwà jôn",
+ "нядзеля\000панядзелак\000аўторак\000серада\000чацвер\000пятніца\000субота",
+ "Pa Mulungu\000Palichimo\000Palichibuli\000Palichitatu\000Palichine\000Palichisano\000Pachibelushi",
+ "pa mulungu\000pa shahuviluha\000pa hivili\000pa hidatu\000pa hitayi\000pa hihanu\000pa shahulembela",
+ "неделя\000понеделник\000вторник\000сряда\000четвъртък\000петък\000събота",
+ "ऐतवार\000सोमवार\000मंगलवार\000बुधवार\000बृहस्पतवार\000शुक्रवार\000शनिवार",
+ "रबीबार\000सोमबार\000मंगलबार\000बुधबार\000बृहस्पतिबार\000शुक्रबार\000सनीचर",
+ "alahaɖɩ\000aɖɩtɛnɛɛ\000atalaata\000alaarba\000alaamɩshɩ\000arɩsǝma\000asiibi",
+ "kari\000ntɛnɛ\000tarata\000araba\000alamisa\000juma\000sibiri",
+ "রবিবার\000সোমবার\000মঙ্গলবার\000বুধবার\000বৃহস্পতিবার\000শুক্রবার\000শনিবার",
+ "གཟའ་ཉི་མ་\000གཟའ་ཟླ་བ་\000གཟའ་མིག་དམར་\000གཟའ་ལྷག་པ་\000གཟའ་ཕུར་བུ་\000གཟའ་པ་སངས་\000གཟའ་སྤེན་པ་",
+ "Sul\000Lun\000Meurzh\000Mercʼher\000Yaou\000Gwener\000Sadorn",
+ "रबिबार\000समबार\000मंगलबार\000बुधबार\000बिस्थिबार\000सुखुरबार\000सनिबार",
+ "nedjelja\000ponedjeljak\000utorak\000srijeda\000četvrtak\000petak\000subota",
+ "недјеља\000понедјељак\000уторак\000сриједа\000четвртак\000петак\000субота",
+ "нима\000дабаа\000мигмар\000һарба\000пүрбэ\000баасан\000бимба",
+ "diumenge\000dilluns\000dimarts\000dimecres\000dijous\000divendres\000dissabte",
+ "Inikuˀ\000Wísts’i hayashuh\000Bít hayashuh\000Dahó hayashuh\000Hiwí hayashuh\000Dissik’an hayashuh\000Inikuˀtiˀtiˀ",
+ "𑄢𑄧𑄝𑄨𑄝𑄢𑄴\000𑄥𑄧𑄟𑄴𑄝𑄢𑄴\000𑄟𑄧𑄁𑄉𑄧𑄣𑄴𑄝𑄢𑄴\000𑄝𑄪𑄖𑄴𑄝𑄢𑄴\000𑄝𑄳𑄢𑄨𑄥𑄪𑄛𑄴𑄝𑄢𑄴\000𑄥𑄪𑄇𑄴𑄇𑄮𑄢𑄴𑄝𑄢𑄴\000𑄥𑄧𑄚𑄨𑄝𑄢𑄴",
+ "кӀира\000оршот\000шинара\000кхаара\000еара\000пӀераска\000шуот",
+ "Domingo\000Lunes\000Martes\000Miyerkules\000Huwebes\000Biyernes\000Sabado",
+ "Sande\000Orwokubanza\000Orwakabiri\000Orwakashatu\000Orwakana\000Orwakataano\000Orwamukaaga",
+ "ᎤᎾᏙᏓᏆᏍᎬ\000ᎤᎾᏙᏓᏉᏅᎯ\000ᏔᎵᏁᎢᎦ\000ᏦᎢᏁᎢᎦ\000ᏅᎩᏁᎢᎦ\000ᏧᎾᎩᎶᏍᏗ\000ᎤᎾᏙᏓᏈᏕᎾ",
+ "Nittak Holloʼ\000Mantiʼ\000Chostiʼ\000Winstiʼ\000Soistiʼ\000Nannalhchifaʼ Nittak\000Nittak Holloʼ Nakfish",
+ "یەکشەممە\000دووشەممە\000سێشەممە\000چوارشەممە\000پێنجشەممە\000ھەینی\000شەممە",
+ "neděle\000pondělí\000úterý\000středa\000čtvrtek\000pátek\000sobota",
+ "ᐊᔭᒥᐦᐁᑮᓯᑳᐤ\000ᐴᓂ ᐊᔭᒥᐦᐁᑮᓯᑳᐤ\000ᓃᓱᑮᓯᑳᐤ\000ᐋᐱᐦᑕᐘᐣ\000ᐴᓂᐋᐱᐦᑕᐘᐣ\000ᑫᑳᐨ ᒫᑎᓇᐍᑮᓯᑳᐤ\000ᒫᑎᓇᐍᑮᓯᑳᐤ",
+ "вырсарни кун\000тунти кун\000ытлари кун\000юн кун\000кӗҫнерни кун\000эрне кун\000шӑмат кун",
+ "Dydd Sul\000Dydd Llun\000Dydd Mawrth\000Dydd Mercher\000Dydd Iau\000Dydd Gwener\000Dydd Sadwrn",
+ "søndag\000mandag\000tirsdag\000onsdag\000torsdag\000fredag\000lørdag",
+ "Ituku ja jumwa\000Kuramuka jimweri\000Kuramuka kawi\000Kuramuka kadadu\000Kuramuka kana\000Kuramuka kasanu\000Kifula nguwo",
+ "Sonntag\000Montag\000Dienstag\000Mittwoch\000Donnerstag\000Freitag\000Samstag",
+ "Alhadi\000Atinni\000Atalaata\000Alarba\000Alhamisi\000Alzuma\000Asibti",
+ "ऐतबार\000सोमबार\000मंगलबार\000बुधबार\000बीरबार\000शुक्रबार\000शनिबार",
+ "njeźela\000pónjeźele\000wałtora\000srjoda\000stwórtk\000pětk\000sobota",
+ "éti\000mɔ́sú\000kwasú\000mukɔ́sú\000ŋgisú\000ɗónɛsú\000esaɓasú",
+ "Dimas\000Teneŋ\000Talata\000Alarbay\000Aramisay\000Arjuma\000Sibiti",
+ "གཟའ་ཟླ་བ་\000གཟའ་མིག་དམར་\000གཟའ་ལྷག་པ་\000གཟའ་ཕུར་བུ་\000གཟའ་པ་སངས་\000གཟའ་སྤེན་པ་\000གཟའ་ཉི་མ་",
+ "Kiumia\000Njumatatu\000Njumaine\000Njumatano\000Aramithi\000Njumaa\000NJumamothii",
+ "kɔsiɖa\000dzoɖa\000blaɖa\000kuɖa\000yawoɖa\000fiɖa\000memleɖa",
+ "Κυριακή\000Δευτέρα\000Τρίτη\000Τετάρτη\000Πέμπτη\000Παρασκευή\000Σάββατο",
+ "Sunday\000Monday\000Tuesday\000Wednesday\000Thursday\000Friday\000Saturday",
+ "𐐝𐐲𐑌𐐼𐐩\000𐐣𐐲𐑌𐐼𐐩\000𐐓𐐭𐑆𐐼𐐩\000𐐎𐐯𐑌𐑆𐐼𐐩\000𐐛𐐲𐑉𐑆𐐼𐐩\000𐐙𐑉𐐴𐐼𐐩\000𐐝𐐰𐐻𐐲𐑉𐐼𐐩",
+ "·𐑕𐑭𐑙𐑛𐑱\000·𐑥𐑭𐑙𐑛𐑱\000·𐑑𐑵𐑟𐑛𐑱\000·𐑢𐑧𐑙𐑟𐑛𐑱\000·𐑔𐑻𐑟𐑛𐑱\000·𐑓𐑮𐑲𐑛𐑱\000·𐑕𐑨𐑛𐑻𐑛𐑱",
+ "dimanĉo\000lundo\000mardo\000merkredo\000ĵaŭdo\000vendredo\000sabato",
+ "domingo\000lunes\000martes\000miércoles\000jueves\000viernes\000sábado",
+ "pühapäev\000esmaspäev\000teisipäev\000kolmapäev\000neljapäev\000reede\000laupäev",
+ "igandea\000astelehena\000asteartea\000asteazkena\000osteguna\000ostirala\000larunbata",
+ "sɔ́ndɔ\000mɔ́ndi\000sɔ́ndɔ məlú mə́bɛ̌\000sɔ́ndɔ məlú mə́lɛ́\000sɔ́ndɔ məlú mə́nyi\000fúladé\000séradé",
+ "یکشنبه\000دوشنبه\000سهشنبه\000چهارشنبه\000پنجشنبه\000جمعه\000شنبه",
+ "dewo\000aaɓnde\000mawbaare\000njeslaare\000naasaande\000mawnde\000hoore-biir",
+ "𞤈𞤫𞤬𞤦𞤭𞤪𞥆𞤫\000𞤀𞥄𞤩𞤵𞤲𞥋𞤣𞤫\000𞤃𞤢𞤱𞤦𞤢𞥄𞤪𞤫\000𞤐𞤶𞤫𞤧𞤤𞤢𞥄𞤪𞤫\000𞤐𞤢𞥄𞤧𞤢𞥄𞤲𞤣𞤫\000𞤃𞤢𞤱𞤲𞤣𞤫\000𞤖𞤮𞤪𞤦𞤭𞤪𞥆𞤫",
+ "sunnuntaina\000maanantaina\000tiistaina\000keskiviikkona\000torstaina\000perjantaina\000lauantaina",
+ "Linggo\000Lunes\000Martes\000Miyerkules\000Huwebes\000Biyernes\000Sabado",
+ "sunnudagur\000mánadagur\000týsdagur\000mikudagur\000hósdagur\000fríggjadagur\000leygardagur",
+ "dimanche\000lundi\000mardi\000mercredi\000jeudi\000vendredi\000samedi",
+ "domenie\000lunis\000martars\000miercus\000joibe\000vinars\000sabide",
+ "snein\000moandei\000tiisdei\000woansdei\000tongersdei\000freed\000sneon",
+ "Dé Domhnaigh\000Dé Luain\000Dé Máirt\000Dé Céadaoin\000Déardaoin\000Dé hAoine\000Dé Sathairn",
+ "Hɔgbaa\000Ju\000Jufɔ\000Shɔ\000Soo\000Sohaa\000Hɔɔ",
+ "DiDòmhnaich\000DiLuain\000DiMàirt\000DiCiadain\000DiarDaoin\000DihAoine\000DiSathairne",
+ "domingo\000luns\000martes\000mércores\000xoves\000venres\000sábado",
+ "Arateĩ\000Arakõi\000Araapy\000Ararundy\000Arapo\000Arapoteĩ\000Arapokõi",
+ "Sunntig\000Määntig\000Ziischtig\000Mittwuch\000Dunschtig\000Friitig\000Samschtig",
+ "રવિવાર\000સોમવાર\000મંગળવાર\000બુધવાર\000ગુરુવાર\000શુક્રવાર\000શનિવાર",
+ "Chumapiri\000Chumatato\000Chumaine\000Chumatano\000Aramisi\000Ichuma\000Esabato",
+ "Jedoonee\000Jelhein\000Jemayrt\000Jercean\000Jerdein\000Jeheiney\000Jesarn",
+ "Lahadi\000Litinin\000Talata\000Laraba\000Alhamis\000Jummaʼa\000Asabar",
+ "Lāpule\000Poʻakahi\000Poʻalua\000Poʻakolu\000Poʻahā\000Poʻalima\000Poʻaono",
+ "יום ראשון\000יום שני\000יום שלישי\000יום רביעי\000יום חמישי\000יום שישי\000יום שבת",
+ "रविवार\000सोमवार\000मंगलवार\000बुधवार\000गुरुवार\000शुक्रवार\000शनिवार",
+ "Raviwaar\000Somwaar\000Mangalwaar\000Budhwaar\000Guruwaar\000Shukrawaar\000Shaniwaar",
+ "njedźela\000póndźela\000wutora\000srjeda\000štwórtk\000pjatk\000sobota",
+ "vasárnap\000hétfő\000kedd\000szerda\000csütörtök\000péntek\000szombat",
+ "կիրակի\000երկուշաբթի\000երեքշաբթի\000չորեքշաբթի\000հինգշաբթի\000ուրբաթ\000շաբաթ",
+ "dominica\000lunedi\000martedi\000mercuridi\000jovedi\000venerdi\000sabbato",
+ "Minggu\000Senin\000Selasa\000Rabu\000Kamis\000Jumat\000Sabtu",
+ "soledí\000lunedí\000mardí\000mercurdí\000jovedí\000venerdí\000saturdí",
+ "Sọndee\000Mọnde\000Tiuzdee\000Wenezdee\000Tọọzdee\000Fraịdee\000Satọdee",
+ "ꑬꆏꑍ\000ꆏꊂꋍ\000ꆏꊂꑍ\000ꆏꊂꌕ\000ꆏꊂꇖ\000ꆏꊂꉬ\000ꆏꊂꃘ",
+ "sunnudagur\000mánudagur\000þriðjudagur\000miðvikudagur\000fimmtudagur\000föstudagur\000laugardagur",
+ "domenica\000lunedì\000martedì\000mercoledì\000giovedì\000venerdì\000sabato",
+ "日曜日\000月曜日\000火曜日\000水曜日\000木曜日\000金曜日\000土曜日",
+ "Sɔ́ndi\000Mɔ́ndi\000Ápta Mɔ́ndi\000Wɛ́nɛsɛdɛ\000Tɔ́sɛdɛ\000Fɛlâyɛdɛ\000Sásidɛ",
+ "Jumapilyi\000Jumatatuu\000Jumanne\000Jumatanu\000Alhamisi\000Ijumaa\000Jumamosi",
+ "Ahad\000Senin\000Selasa\000Rabu\000Kamis\000Jumat\000Sabtu",
+ "კვირა\000ორშაბათი\000სამშაბათი\000ოთხშაბათი\000ხუთშაბათი\000პარასკევი\000შაბათი",
+ "екшемби\000дүйшемби\000сийшемби\000сәршемби\000пийшемби\000жума\000шемби",
+ "Acer\000Arim\000Aram\000Ahad\000Amhad\000Sem\000Sed",
+ "Wa kyumwa\000Wa kwambĩlĩlya\000Wa kelĩ\000Wa katatũ\000Wa kana\000Wa katano\000Wa thanthatũ",
+ "Liduva lyapili\000Liduva lyatatu\000Liduva lyanchechi\000Liduva lyannyano\000Liduva lyannyano na linji\000Liduva lyannyano na mavili\000Liduva litandi",
+ "dumingu\000sigunda-fera\000tersa-fera\000kuarta-fera\000kinta-fera\000sesta-fera\000sábadu",
+ "Doʼkutan\000LuʼKutan\000MarʼKutan\000MerʼKutan\000JueʼKutan\000VierʼKutan\000SabʼKutan",
+ "numĩggu\000pir-kurã-há\000régre-kurã-há\000tẽgtũ-kurã-há\000vẽnhkãgra-kurã-há\000pénkar-kurã-há\000savnu",
+ "Alhadi\000Atini\000Atalata\000Alarba\000Alhamiisa\000Aljuma\000Assabdu",
+ "Kiumia\000Njumatatũ\000Njumaine\000Njumatana\000Aramithi\000Njumaa\000Njumamothi",
+ "жексенбі\000дүйсенбі\000сейсенбі\000сәрсенбі\000бейсенбі\000жұма\000сенбі",
+ "جەكسەنبى\000دۇيسەنبى\000سەيسەنبى\000سارسەنبى\000بەيسەنبى\000جۇما\000سەنبى",
+ "sɔndi\000lundi\000mardi\000mɛrkɛrɛdi\000yedi\000vaŋdɛrɛdi\000mɔnɔ sɔndi",
+ "sapaat\000ataasinngorneq\000marlunngorneq\000pingasunngorneq\000sisamanngorneq\000tallimanngorneq\000arfininngorneq",
+ "Kotisap\000Kotaai\000Koaeng’\000Kosomok\000Koang’wan\000Komuut\000Kolo",
+ "អាទិត្យ\000ច័ន្ទ\000អង្គារ\000ពុធ\000ព្រហស្បតិ៍\000សុក្រ\000សៅរ៍",
+ "ಭಾನುವಾರ\000ಸೋಮವಾರ\000ಮಂಗಳವಾರ\000ಬುಧವಾರ\000ಗುರುವಾರ\000ಶುಕ್ರವಾರ\000ಶನಿವಾರ",
+ "일요일\000월요일\000화요일\000수요일\000목요일\000금요일\000토요일",
+ "आयतार\000सोमार\000मंगळार\000बुधवार\000बिरेस्तार\000शुक्रार\000शेनवार",
+ "Aitar\000Somar\000Mongllar\000Budhvar\000Birestar\000Sukrar\000Sonvar",
+ "اَتھوار\000ژٔندرٕروار\000بۆموار\000بودوار\000برؠسوار\000جُمہ\000بٹوار",
+ "आथवार\000च़ंदिरवार\000बोमवार\000बोदवार\000ब्रेसवार\000जुमा\000बटवार",
+ "Jumaapii\000Jumaatatu\000Jumaane\000Jumaatano\000Alhamisi\000Ijumaa\000Jumaamosi",
+ "sɔ́ndǝ\000lǝndí\000maadí\000mɛkrɛdí\000jǝǝdí\000júmbá\000samdí",
+ "Sunndaach\000Mohndaach\000Dinnsdaach\000Metwoch\000Dunnersdaach\000Friidaach\000Samsdaach",
+ "yekşem\000duşem\000sêşem\000çarşem\000pêncşem\000înî\000şemî",
+ "dy Sul\000dy Lun\000dy Meurth\000dy Merher\000dy Yow\000dy Gwener\000dy Sadorn",
+ "aadi vara\000smbara\000mangaḍa\000pudara\000laki vara\000sukru vara\000sani vara",
+ "आदि वारा\000साॅम्वारा\000मंगाड़ा\000पुद्दारा\000लाक्कि वारा\000सुकुरु वारा\000सान्नि वारा",
+ "ଆଦି ୱାରା\000ସମ୍ବାରା\000ମାଙ୍ଗାଡ଼ା\000ପୁଦାରା\000ଲାକି ୱାରା\000ସୁକ୍ରୁ ୱାରା\000ସାନି ୱାରା",
+ "వారమి\000నమారా\000మాంగాడా\000వుదారా\000లాకివరా\000నుక్ వరా\000సానివరా",
+ "жекшемби\000дүйшөмбү\000шейшемби\000шаршемби\000бейшемби\000жума\000ишемби",
+ "Jumapíiri\000Jumatátu\000Jumaíne\000Jumatáano\000Alamíisi\000Ijumáa\000Jumamóosi",
+ "Sonndeg\000Méindeg\000Dënschdeg\000Mëttwoch\000Donneschdeg\000Freideg\000Samschdeg",
+ "Sabbiiti\000Balaza\000Lwakubiri\000Lwakusatu\000Lwakuna\000Lwakutaano\000Lwamukaaga",
+ "domenega\000lunesdì\000mätesdì\000mäcordì\000zeuggia\000venardì\000sabbo",
+ "Aŋpétuwakȟaŋ\000Aŋpétuwaŋži\000Aŋpétunuŋpa\000Aŋpétuyamni\000Aŋpétutopa\000Aŋpétuzaptaŋ\000Owáŋgyužažapi",
+ "domënia\000lönesc\000mertesc\000mercui\000jöbia\000vëndres\000sabeda",
+ "domenega\000lundì\000mardì\000mercoldì\000sgiovedì\000venerdì\000sabet",
+ "eyenga\000mokɔlɔ mwa yambo\000mokɔlɔ mwa míbalé\000mokɔlɔ mwa mísáto\000mokɔlɔ ya mínéi\000mokɔlɔ ya mítáno\000mpɔ́sɔ",
+ "ວັນອາທິດ\000ວັນຈັນ\000ວັນອັງຄານ\000ວັນພຸດ\000ວັນພະຫັດ\000ວັນສຸກ\000ວັນເສົາ",
+ "sekmadienis\000pirmadienis\000antradienis\000trečiadienis\000ketvirtadienis\000penktadienis\000šeštadienis",
+ "Lumingu\000Nkodya\000Ndàayà\000Ndangù\000Njòwa\000Ngòvya\000Lubingu",
+ "Jumapil\000Wuok Tich\000Tich Ariyo\000Tich Adek\000Tich Ang’wen\000Tich Abich\000Ngeso",
+ "Jumapiri\000Jumatatu\000Jumanne\000Jumatano\000Murwa wa Kanne\000Murwa wa Katano\000Jumamosi",
+ "svētdiena\000pirmdiena\000otrdiena\000trešdiena\000ceturtdiena\000piektdiena\000sestdiena",
+ "रवि दिन\000सोम दिन\000मंगल दिन\000बुध दिन\000बृहस्पति दिन\000शुक्र दिन\000शनि दिन",
+ "Jumapílí\000Jumatátu\000Jumane\000Jumatánɔ\000Alaámisi\000Jumáa\000Jumamósi",
+ "Kiumia\000Muramuko\000Wairi\000Wethatu\000Wena\000Wetano\000Jumamosi",
+ "dimans\000lindi\000mardi\000merkredi\000zedi\000vandredi\000samdi",
+ "Alahady\000Alatsinainy\000Talata\000Alarobia\000Alakamisy\000Zoma\000Asabotsy",
+ "Sabato\000Jumatatu\000Jumanne\000Jumatano\000Arahamisi\000Ijumaa\000Jumamosi",
+ "Aneg 1\000Aneg 2\000Aneg 3\000Aneg 4\000Aneg 5\000Aneg 6\000Aneg 7",
+ "Rātapu\000Mane\000Tūrei\000Wenerei\000Tāite\000Paraire\000Rāhoroi",
+ "недела\000понеделник\000вторник\000среда\000четврток\000петок\000сабота",
+ "ഞായറാഴ്ച\000തിങ്കളാഴ്ച\000ചൊവ്വാഴ്ച\000ബുധനാഴ്ച\000വ്യാഴാഴ്ച\000വെള്ളിയാഴ്ച\000ശനിയാഴ്ച",
+ "ням\000даваа\000мягмар\000лхагва\000пүрэв\000баасан\000бямба",
+ "ᠨᠢᠮᠠ\000ᠳᠠᠸᠠ\000ᠮᠢᠠᠠᠮᠠᠷ\000ᡀᠠᠭᠪᠠ\000ᠫᠦᠷᠪᠦ\000ᠪᠠᠰᠠᠩ\000ᠪᠢᠮᠪᠠ",
+ "নোংমাইজিং\000নিংথৌকাবা\000লৈবাকপোকপা\000য়ুমশকৈশা\000শগোলশেন\000ইরাই\000থাংজ",
+ "रविवार\000सोमवार\000मंगळवार\000बुधवार\000गुरुवार\000शुक्रवार\000शनिवार",
+ "Ahad\000Isnin\000Selasa\000Rabu\000Khamis\000Jumaat\000Sabtu",
+ "Il-Ħadd\000It-Tnejn\000It-Tlieta\000L-Erbgħa\000Il-Ħamis\000Il-Ġimgħa\000Is-Sibt",
+ "Com’yakke\000Comlaaɗii\000Comzyiiɗii\000Comkolle\000Comkaldǝɓlii\000Comgaisuu\000Comzyeɓsuu",
+ "Nettvʼcako\000Enhvteceskv\000Enhvteceskv Enhvyvtke\000Ennvrkvpv\000Ennvrkvpv Enhvyvtke\000Nak Okkoskv Nettv\000Nettv Cakʼcuse",
+ "တနင်္ဂနွေ\000တနင်္လာ\000အင်္ဂါ\000ဗုဒ္ဓဟူး\000ကြာသပတေး\000သောကြာ\000စနေ",
+ "Sontaxtsees\000Mantaxtsees\000Denstaxtsees\000Wunstaxtsees\000Dondertaxtsees\000Fraitaxtsees\000Satertaxtsees",
+ "Sonto\000Mvulo\000Sibili\000Sithathu\000Sine\000Sihlanu\000Mgqibelo",
+ "Sünndag\000Maandag\000Dingsdag\000Middeweken\000Dunnersdag\000Freedag\000Sünnavend",
+ "आइतबार\000सोमबार\000मङ्गलबार\000बुधबार\000बिहिबार\000शुक्रबार\000शनिबार",
+ "zondag\000maandag\000dinsdag\000woensdag\000donderdag\000vrijdag\000zaterdag",
+ "sɔ́ndɔ\000mɔ́ndɔ\000sɔ́ndɔ mafú mába\000sɔ́ndɔ mafú málal\000sɔ́ndɔ mafú mána\000mabágá má sukul\000sásadi",
+ "søndag\000måndag\000tysdag\000onsdag\000torsdag\000fredag\000laurdag",
+ "lyɛʼɛ́ sẅíŋtè\000mvfò lyɛ̌ʼ\000mbɔ́ɔntè mvfò lyɛ̌ʼ\000tsètsɛ̀ɛ lyɛ̌ʼ\000mbɔ́ɔntè tsetsɛ̀ɛ lyɛ̌ʼ\000mvfò màga lyɛ̌ʼ\000màga lyɛ̌ʼ",
+ "ߞߊ߯ߙߌߟߏ߲\000ߞߐ߬ߓߊ߬ߟߏ߲\000ߞߐ߬ߟߏ߲\000ߞߎߣߎ߲ߟߏ߲\000ߓߌߟߏ߲\000ߛߌ߬ߣߌ߲߬ߟߏ߲\000ߞߍ߲ߘߍߟߏ߲",
+ "Lamorena\000Mošupologo\000Labobedi\000Laboraro\000Labone\000Labohlano\000Mokibelo",
+ "Cäŋ kuɔth\000Jiec la̱t\000Rɛw lätni\000Diɔ̱k lätni\000Ŋuaan lätni\000Dhieec lätni\000Bäkɛl lätni",
+ "dimenge\000diluns\000dimars\000dimècres\000dijòus\000divendres\000dissabte",
+ "Dilbata\000Wiixata\000Kibxata\000Roobii\000Kamisa\000Jimaata\000Sanbata",
+ "ରବିବାର\000ସୋମବାର\000ମଙ୍ଗଳବାର\000ବୁଧବାର\000ଗୁରୁବାର\000ଶୁକ୍ରବାର\000ଶନିବାର",
+ "хуыцаубон\000къуырисӕр\000дыццӕг\000ӕртыццӕг\000цыппӕрӕм\000майрӕмбон\000сабат",
+ "𐒹𐓘͘𐓬𐓘 𐓏𐓘𐓤𐓘͘𐓰𐓘𐓤𐓣\000𐒹𐓘͘𐓬𐓘 𐓄𐓘𐓡𐓛͘𐓧𐓣\000𐒹𐓘͘𐓬𐓘 𐓏𐓟𐓵𐓪͘𐓬𐓘\000𐒹𐓘͘𐓬𐓘 𐓏𐓟𐓵𐓘𐓜𐓣\000𐒹𐓘͘𐓬𐓘 𐓏𐓟𐓰𐓪𐓬𐓘\000𐒹𐓘͘𐓬𐓘 𐓈𐓘 𐓵𐓘𐓲𐓘 𐓻𐓣͘\000𐒹𐓘͘𐓬𐓘 𐓂𐓤𐓘𐓸𐓟 𐓣͘𐓤𐓟",
+ "ਐਤਵਾਰ\000ਸੋਮਵਾਰ\000ਮੰਗਲਵਾਰ\000ਬੁੱਧਵਾਰ\000ਵੀਰਵਾਰ\000ਸ਼ੁੱਕਰਵਾਰ\000ਸ਼ਨੀਵਾਰ",
+ "اتوار\000پیر\000منگل\000بُدھ\000جمعرات\000جمعہ\000ہفتہ",
+ "djadumingu\000djaluna\000djamars\000djarason\000djaweps\000djabièrnè\000djasabra",
+ "Sọ́ndè\000Mọ́ndè\000Tiúzdè\000Wẹ́nẹ́zdè\000Tọ́zdè\000Fraídè\000Sátọdè",
+ "Sande\000Mande\000Tiusde\000Wenesde\000Tosde\000Fraede\000Satade",
+ "niedziela\000poniedziałek\000wtorek\000środa\000czwartek\000piątek\000sobota",
+ "dumìnica\000lun-es\000màrtes\000merco\000giòbia\000vënner\000saba",
+ "nadīli\000panadīli\000wisasīdis\000pussisawaiti\000ketwirtiks\000pēntniks\000sabattika",
+ "يونۍ\000دونۍ\000درېنۍ\000څلرنۍ\000پينځنۍ\000جمعه\000اونۍ",
+ "domingo\000segunda-feira\000terça-feira\000quarta-feira\000quinta-feira\000sexta-feira\000sábado",
+ "Domingo\000Lunes\000Martes\000Miércoles\000Jueves\000Viernes\000Sábado",
+ "dumengia\000glindesdi\000mardi\000mesemna\000gievgia\000venderdi\000sonda",
+ "Ku w’indwi\000Ku wa mbere\000Ku wa kabiri\000Ku wa gatatu\000Ku wa kane\000Ku wa gatanu\000Ku wa gatandatu",
+ "duminică\000luni\000marți\000miercuri\000joi\000vineri\000sâmbătă",
+ "Ijumapili\000Ijumatatu\000Ijumanne\000Ijumatano\000Alhamisi\000Ijumaa\000Ijumamosi",
+ "воскресенье\000понедельник\000вторник\000среда\000четверг\000пятница\000суббота",
+ "Ku cyumweru\000Kuwa mbere\000Kuwa kabiri\000Kuwa gatatu\000Kuwa kane\000Kuwa gatanu\000Kuwa gatandatu",
+ "रविवासरः\000सोमवासरः\000मंगलवासरः\000बुधवासरः\000गुरुवासर:\000शुक्रवासरः\000शनिवासरः",
+ "баскыһыанньа\000бэнидиэнньик\000оптуорунньук\000сэрэдэ\000чэппиэр\000Бээтиҥсэ\000субуота",
+ "Mderot ee are\000Mderot ee kuni\000Mderot ee ong’wan\000Mderot ee inet\000Mderot ee ile\000Mderot ee sapa\000Mderot ee kwe",
+ "ᱥᱤᱸᱜᱮ\000ᱚᱛᱮ\000ᱵᱟᱞᱮ\000ᱥᱟᱹᱜᱩᱱ\000ᱥᱟᱹᱨᱫᱤ\000ᱡᱟᱹᱨᱩᱢ\000ᱧᱩᱦᱩᱢ",
+ "Mulungu\000Jumatatu\000Jumanne\000Jumatano\000Alahamisi\000Ijumaa\000Jumamosi",
+ "domìniga\000lunis\000martis\000mèrcuris\000giòbia\000chenàbura\000sàbadu",
+ "dumìnica\000lunnidìa\000martidìa\000mercuridìa\000jovidìa\000venniridìa\000sàbbatu",
+ "آچر\000سومر\000اڱارو\000اربع\000خميس\000جمعو\000ڇنڇر",
+ "आर्तवार\000सूमर\000मंगलु\000ॿुधर\000विस्पत\000जुमो\000छंछर",
+ "sotnabeaivi\000vuossárga\000maŋŋebárga\000gaskavahkku\000duorasdat\000bearjadat\000lávvardat",
+ "sotnabeaivi\000mánnodat\000disdat\000gaskavahkku\000duorastat\000bearjadat\000lávvordat",
+ "Dimingu\000Chiposi\000Chipiri\000Chitatu\000Chinai\000Chishanu\000Sabudu",
+ "Alhadi\000Atinni\000Atalaata\000Alarba\000Alhamiisa\000Alzuma\000Asibti",
+ "Bikua-ôko\000Bïkua-ûse\000Bïkua-ptâ\000Bïkua-usïö\000Bïkua-okü\000Lâpôsö\000Lâyenga",
+ "ⴰⵙⴰⵎⴰⵙ\000ⴰⵢⵏⴰⵙ\000ⴰⵙⵉⵏⴰⵙ\000ⴰⴽⵕⴰⵙ\000ⴰⴽⵡⴰⵙ\000ⵙⵉⵎⵡⴰⵙ\000ⴰⵙⵉⴹⵢⴰⵙ",
+ "asamas\000aynas\000asinas\000akṛas\000akwas\000asimwas\000asiḍyas",
+ "ဝၼ်းဢႃးတိတ်ႉ\000ဝၼ်းၸၼ်\000ဝၼ်းဢင်းၵၢၼ်း\000ဝၼ်းပုတ်ႉ\000ဝၼ်းၽတ်း\000ဝၼ်းသုၵ်း\000ဝၼ်းသဝ်",
+ "ඉරිදා\000සඳුදා\000අඟහරුවාදා\000බදාදා\000බ්රහස්පතින්දා\000සිකුරාදා\000සෙනසුරාදා",
+ "nedeľa\000pondelok\000utorok\000streda\000štvrtok\000piatok\000sobota",
+ "nedelja\000ponedeljek\000torek\000sreda\000četrtek\000petek\000sobota",
+ "pasepeeivi\000vuossaargâ\000majebaargâ\000koskoho\000tuorâstuv\000vástuppeeivi\000lávurduv",
+ "Svondo\000Muvhuro\000Chipiri\000Chitatu\000China\000Chishanu\000Mugovera",
+ "Axad\000Isniin\000Talaado\000Arbaco\000Khamiis\000Jimco\000Sabti",
+ "e diel\000e hënë\000e martë\000e mërkurë\000e enjte\000e premte\000e shtunë",
+ "недеља\000понедељак\000уторак\000среда\000четвртак\000петак\000субота",
+ "недјеља\000понедељак\000уторак\000сриједа\000четвртак\000петак\000субота",
+ "nedelja\000ponedeljak\000utorak\000sreda\000četvrtak\000petak\000subota",
+ "nedjelja\000ponedeljak\000utorak\000srijeda\000četvrtak\000petak\000subota",
+ "Sontaha\000Mantaha\000Labobedi\000Laboraro\000Labone\000Labohlano\000Moqebelo",
+ "Minggu\000Senén\000Salasa\000Rebo\000Kemis\000Jumaah\000Saptu",
+ "söndag\000måndag\000tisdag\000onsdag\000torsdag\000fredag\000lördag",
+ "ܚܕܒܫܒܐ\000ܬܪܝܢܒܫܒܐ\000ܬܠܬܒܫܒܐ\000ܐܪܒܥܒܫܒܐ\000ܚܡܫܒܫܒܐ\000ܥܪܘܒܬܐ\000ܫܒܬܐ",
+ "niydziela\000pyńdziałek\000wtorek\000strzoda\000sztwortek\000piōntek\000sobota",
+ "ஞாயிறு\000திங்கள்\000செவ்வாய்\000புதன்\000வியாழன்\000வெள்ளி\000சனி",
+ "ఆదివారం\000సోమవారం\000మంగళవారం\000బుధవారం\000గురువారం\000శుక్రవారం\000శనివారం",
+ "Nakaejuma\000Nakaebarasa\000Nakaare\000Nakauni\000Nakaung’on\000Nakakany\000Nakasabiti",
+ "Якшанбе\000Душанбе\000Сешанбе\000Чоршанбе\000Панҷшанбе\000Ҷумъа\000Шанбе",
+ "วันอาทิตย์\000วันจันทร์\000วันอังคาร\000วันพุธ\000วันพฤหัสบดี\000วันศุกร์\000วันเสาร์",
+ "ሰንበት\000ሰኑይ\000ሰሉስ\000ረቡዕ\000ሓሙስ\000ዓርቢ\000ቀዳም",
+ "ýekşenbe\000duşenbe\000sişenbe\000çarşenbe\000penşenbe\000anna\000şenbe",
+ "Tshipi\000Mosupologo\000Labobedi\000Laboraro\000Labone\000Labotlhano\000Matlhatso",
+ "Sāpate\000Mōnite\000Tūsite\000Pulelulu\000Tuʻapulelulu\000Falaite\000Tokonaki",
+ "suno esun #7\000suno esun #1\000suno esun #2\000suno esun #3\000suno esun #4\000suno esun #5\000suno esun #6",
+ "Sande\000Mande\000Tunde\000Trinde\000Fonde\000Fraide\000Sarere",
+ "Pazar\000Pazartesi\000Salı\000Çarşamba\000Perşembe\000Cuma\000Cumartesi",
+ "Sonta\000Musumbhunuku\000Ravumbirhi\000Ravunharhu\000Ravumune\000Ravuntlhanu\000Mugqivela",
+ "якшәмбе\000дүшәмбе\000сишәмбе\000чәршәмбе\000пәнҗешәмбе\000җомга\000шимбә",
+ "Улуг-хүн\000Понедельник\000Вторник\000Среда\000Четверг\000Пятница\000Суббота",
+ "Asamas\000Aynas\000Asinas\000Akras\000Akwas\000Asimwas\000Asiḍyas",
+ "يەكشەنبە\000دۈشەنبە\000سەيشەنبە\000چارشەنبە\000پەيشەنبە\000جۈمە\000شەنبە",
+ "неділя\000понеділок\000вівторок\000середа\000четвер\000пʼятниця\000субота",
+ "اتوار\000پیر\000منگل\000بدھ\000جمعرات\000جمعہ\000ہفتہ",
+ "yakshanba\000dushanba\000seshanba\000chorshanba\000payshanba\000juma\000shanba",
+ "якшанба\000душанба\000сешанба\000чоршанба\000пайшанба\000жума\000шанба",
+ "ꕞꕌꔵ\000ꗳꗡꘉ\000ꕚꕞꕚ\000ꕉꕞꕒ\000ꕉꔤꕆꕢ\000ꕉꔤꕀꕮ\000ꔻꔬꔳ",
+ "lahadi\000tɛɛnɛɛ\000talata\000alaba\000aimisa\000aijima\000siɓiti",
+ "doménega\000luni\000marti\000mèrcore\000zoba\000vènare\000sabo",
+ "Chủ Nhật\000Thứ Hai\000Thứ Ba\000Thứ Tư\000Thứ Năm\000Thứ Sáu\000Thứ Bảy",
+ "ettiminku\000nihiku noolempwa\000namaanli\000namararu\000namaxexe\000namathanu\000esaabadu",
+ "Sunntag\000Mäntag\000Zištag\000Mittwuč\000Fróntag\000Fritag\000Samštag",
+ "Dibéer\000Altine\000Talaata\000Àlarba\000Alxamis\000Àjjuma\000Aseer",
+ "Cawe\000Mvulo\000Lwesibini\000Lwesithathu\000Lwesine\000Lwesihlanu\000Mgqibelo",
+ "तोआर\000सोआर\000मंगलवार\000बुधवार\000वीरवार\000शुक्करवार\000शनिच्चरवार",
+ "Sabiiti\000Balaza\000Owokubili\000Owokusatu\000Olokuna\000Olokutaanu\000Olomukaaga",
+ "sɔ́ndiɛ\000móndie\000muányáŋmóndie\000metúkpíápɛ\000kúpélimetúkpiapɛ\000feléte\000séselé",
+ "זונטיק\000מאָנטיק\000דינסטיק\000מיטוואך\000דאנערשטיק\000פֿרײַטיק\000שבת",
+ "Ọjọ́ Àìkú\000Ọjọ́ Ajé\000Ọjọ́ Ìsẹ́gun\000Ọjọ́rú\000Ọjọ́bọ\000Ọjọ́ Ẹtì\000Ọjọ́ Àbámẹ́ta",
+ "Ɔjɔ́ Àìkú\000Ɔjɔ́ Ajé\000Ɔjɔ́ Ìsɛ́gun\000Ɔjɔ́rú\000Ɔjɔ́bɔ\000Ɔjɔ́ Ɛtì\000Ɔjɔ́ Àbámɛ́ta",
+ "mituú\000murakipí\000murakí-mukũi\000murakí-musapíri\000supapá\000yukuakú\000saurú",
+ "星期日\000星期一\000星期二\000星期三\000星期四\000星期五\000星期六",
+ "ngoenzsinghgiz\000singhgizit\000singhgizngeih\000singhgizsam\000singhgizseiq\000singhgizhaj\000singhgizroek",
+ "ⴰⵙⴰⵎⴰⵙ\000ⴰⵢⵏⴰⵙ\000ⴰⵙⵉⵏⴰⵙ\000ⴰⴽⵕⴰⵙ\000ⴰⴽⵡⴰⵙ\000ⴰⵙⵉⵎⵡⴰⵙ\000ⴰⵙⵉⴹⵢⴰⵙ",
+ "ISonto\000UMsombuluko\000ULwesibili\000ULwesithathu\000ULwesine\000ULwesihlanu\000UMgqibelo",
+};
+
+const char *weekday_narrow_tab[] = {
+ "S\000M\000T\000W\000T\000F\000S",
+ "S\000M\000D\000W\000D\000V\000S",
+ "n\000k\000g\000t\000u\000g\000d",
+ "K\000D\000B\000W\000Y\000F\000M",
+ "እ\000ሰ\000ማ\000ረ\000ሐ\000ዓ\000ቅ",
+ "ح\000ن\000ث\000ر\000خ\000ج\000س",
+ "দ\000স\000ম\000ব\000ব\000শ\000শ",
+ "J\000J\000J\000J\000A\000I\000J",
+ "D\000L\000M\000M\000X\000V\000S",
+ "7\0001\0002\0003\0004\0005\0006",
+ "Й\000Д\000Ш\000Ш\000К\000Й\000Ш",
+ "Y\000D\000S\000Ch\000P\000J\000Sh",
+ "n\000n\000u\000ŋ\000m\000k\000j",
+ "н\000п\000а\000с\000ч\000п\000с",
+ "M\000J\000H\000H\000H\000W\000J",
+ "н\000п\000в\000с\000ч\000п\000с",
+ "lh\000ɖt\000tl\000lr\000lm\000rs\000sb",
+ "K\000N\000T\000A\000A\000J\000S",
+ "র\000সো\000ম\000বু\000বৃ\000শু\000শ",
+ "ཉི\000ཟླ\000མིག\000ལྷག\000ཕུར\000སངས\000སྤེན",
+ "Su\000L\000Mz\000Mc\000Y\000G\000Sa",
+ "र\000स\000मं\000बु\000बि\000सु\000स",
+ "N\000P\000U\000S\000Č\000P\000S",
+ "н\000п\000у\000с\000ч\000п\000с",
+ "Ни\000Да\000Ми\000Һа\000Пү\000Ба\000Би",
+ "dg.\000dl.\000dt.\000dc.\000dj.\000dv.\000ds.",
+ "𑄢𑄧\000𑄥𑄧\000𑄟𑄧\000𑄝𑄪\000𑄝𑄳𑄢𑄨\000𑄥𑄪\000𑄥𑄧",
+ "кӀи\000ор\000ши\000кха\000еа\000пӀе\000шуо",
+ "D\000L\000M\000M\000H\000B\000S",
+ "S\000K\000R\000S\000N\000T\000M",
+ "Ꮖ\000Ꮙ\000Ꮤ\000Ꮶ\000Ꮕ\000Ꮷ\000Ꭴ",
+ "ی\000د\000س\000چ\000پ\000ھ\000ش",
+ "N\000P\000Ú\000S\000Č\000P\000S",
+ "ᐊ\000ᐴ\000ᓃ\000ᐋ\000ᐴ\000ᑫ\000ᒫ",
+ "В\000Т\000Ы\000Ю\000К\000Э\000Ш",
+ "S\000Ll\000M\000M\000I\000G\000S",
+ "S\000M\000T\000O\000T\000F\000L",
+ "J\000J\000K\000K\000K\000K\000N",
+ "S\000M\000D\000M\000D\000F\000S",
+ "H\000T\000T\000L\000M\000Z\000S",
+ "ऐ.\000सो.\000म.\000बु.\000बी.\000शु.\000श.",
+ "n\000p\000w\000s\000s\000p\000s",
+ "e\000m\000k\000m\000ŋ\000ɗ\000e",
+ "D\000T\000T\000A\000A\000A\000S",
+ "ཟླ\000མིར\000ལྷག\000ཕུར\000སངྶ\000སྤེན\000ཉི",
+ "K\000N\000N\000N\000A\000M\000N",
+ "k\000d\000b\000k\000y\000f\000m",
+ "Κ\000Δ\000Τ\000Τ\000Π\000Π\000Σ",
+ "Su.\000M.\000Tu.\000W.\000Th.\000F.\000Sa.",
+ "𐐝\000𐐣\000𐐓\000𐐎\000𐐛\000𐐙\000𐐝",
+ "𐑕\000𐑥\000𐑑\000𐑢\000𐑔\000𐑓\000𐑕",
+ "d\000l\000m\000m\000ĵ\000v\000s",
+ "D\000L\000M\000X\000J\000V\000S",
+ "D\000L\000M\000M\000J\000V\000S",
+ "D\000L\000M\000m\000J\000V\000S",
+ "P\000E\000T\000K\000N\000R\000L",
+ "I\000A\000A\000A\000O\000O\000L",
+ "s\000m\000s\000s\000s\000f\000s",
+ "ی\000د\000س\000چ\000پ\000ج\000ش",
+ "d\000a\000m\000n\000n\000m\000h",
+ "𞤈\000𞤀𞥄\000𞤃\000𞤔\000𞤐\000𞤃\000𞤖",
+ "S\000M\000T\000K\000T\000P\000L",
+ "Lin\000Lun\000Mar\000Miy\000Huw\000Biy\000Sab",
+ "S\000M\000T\000M\000H\000F\000L",
+ "D\000L\000M\000C\000D\000A\000S",
+ "D\000L\000M\000C\000A\000H\000S",
+ "d.\000l.\000m.\000m.\000x.\000v.\000s.",
+ "ર\000સો\000મં\000બુ\000ગુ\000શુ\000શ",
+ "C\000C\000C\000C\000A\000I\000E",
+ "L\000L\000T\000L\000A\000J\000A",
+ "א׳\000ב׳\000ג׳\000ד׳\000ה׳\000ו׳\000ש׳",
+ "र\000सो\000मं\000बु\000गु\000शु\000श",
+ "Ra\000So\000Ma\000Bu\000Gu\000Sh\000Sha",
+ "n\000p\000w\000s\000š\000p\000s",
+ "V\000H\000K\000Sz\000Cs\000P\000Sz",
+ "Կ\000Ե\000Ե\000Չ\000Հ\000Ո\000Շ",
+ "d\000l\000m\000m\000j\000v\000s",
+ "M\000S\000S\000R\000K\000J\000S",
+ "S\000L\000M\000M\000J\000V\000S",
+ "ꆏ\000ꋍ\000ꑍ\000ꌕ\000ꇖ\000ꉬ\000ꃘ",
+ "S\000M\000Þ\000M\000F\000F\000L",
+ "D\000L\000M\000M\000G\000V\000S",
+ "日\000月\000火\000水\000木\000金\000土",
+ "Sɔ́\000Mɔ́\000ÁM\000Wɛ́\000Tɔ́\000Fɛ\000Sá",
+ "A\000S\000S\000R\000K\000J\000S",
+ "კ\000ო\000ს\000ო\000ხ\000პ\000შ",
+ "Е\000Д\000С\000С\000П\000Ж\000Ш",
+ "C\000R\000R\000H\000M\000S\000S",
+ "Y\000W\000E\000A\000A\000A\000A",
+ "2\0003\0004\0005\0006\0007\0001",
+ "D\000S\000T\000K\000K\000S\000S",
+ "N.\000P.\000R.\000T.\000V.\000P.\000S.",
+ "H\000T\000T\000L\000L\000L\000S",
+ "K\000N\000N\000N\000A\000N\000N",
+ "Ж\000Д\000С\000С\000Б\000Ж\000С",
+ "ج\000د\000س\000س\000ب\000ج\000س",
+ "so\000lu\000ma\000mɛ\000ye\000va\000ms",
+ "T\000T\000O\000S\000A\000M\000L",
+ "អ\000ច\000អ\000ព\000ព\000ស\000ស",
+ "ಭಾ\000ಸೋ\000ಮಂ\000ಬು\000ಗು\000ಶು\000ಶ",
+ "일\000월\000화\000수\000목\000금\000토",
+ "आ\000सो\000मं\000बु\000बि\000शु\000शे",
+ "A\000S\000M\000B\000B\000S\000S",
+ "ا\000ژ\000ب\000ب\000ب\000ج\000ب",
+ "अ\000च\000ब\000ब\000ब\000ज\000ब",
+ "2\0003\0004\0005\000A\000I\0001",
+ "s\000l\000m\000m\000j\000j\000s",
+ "Y\000D\000S\000Ç\000P\000Î\000Ş",
+ "aa\000s\000ma\000pu\000la\000su\000sa",
+ "आ\000साॅ\000मा\000पू\000ला\000सु\000सा",
+ "ଆ\000ସ\000ମା\000ପୁ\000ଲା\000ସୁ\000ସା",
+ "వా\000న\000మా\000వు\000ల\000ను\000సా",
+ "Ж\000Д\000Ш\000Ш\000Б\000Ж\000И",
+ "P\000T\000E\000O\000A\000I\000M",
+ "S\000B\000L\000L\000L\000L\000L",
+ "A\000W\000N\000Y\000T\000Z\000O",
+ "e\000y\000m\000m\000m\000m\000p",
+ "ອາ\000ຈ\000ອ\000ພ\000ພຫ\000ສຸ\000ສ",
+ "S\000P\000A\000T\000K\000P\000Š",
+ "L\000N\000N\000N\000N\000N\000L",
+ "J\000W\000T\000T\000T\000T\000N",
+ "S\000P\000O\000T\000C\000P\000S",
+ "K\000M\000W\000W\000W\000W\000J",
+ "d\000l\000m\000m\000z\000v\000s",
+ "A\000A\000T\000A\000A\000Z\000A",
+ "S\000J\000J\000J\000A\000I\000J",
+ "1\0002\0003\0004\0005\0006\0007",
+ "Rt\000M\000T\000W\000T\000P\000Rh",
+ "ഞ\000തി\000ചൊ\000ബു\000വ്യാ\000വെ\000ശ",
+ "Ня\000Да\000Мя\000Лх\000Пү\000Ба\000Бя",
+ "ᠨᠢ\000ᠳᠠ\000ᠮᠢᠭ\000ᡀᠠ\000ᠫᠥᠷ\000ᠪᠠ\000ᠪᠢ",
+ "নোং\000নিং\000লৈবা\000য়ুম\000শগো\000ইরা\000থাং",
+ "A\000I\000S\000R\000K\000J\000S",
+ "Ħd\000T\000Tl\000Er\000Ħm\000Ġm\000Sb",
+ "Y\000L\000Z\000O\000A\000G\000E",
+ "တ\000တ\000အ\000ဗ\000က\000သ\000စ",
+ "S\000M\000E\000W\000D\000F\000A",
+ "S\000M\000S\000S\000S\000S\000M",
+ "आ\000सो\000म\000बु\000बि\000शु\000श",
+ "Z\000M\000D\000W\000D\000V\000Z",
+ "s\000m\000s\000s\000s\000m\000s",
+ "ߞ\000ߞ\000ߞ\000ߞ\000ߓ\000ߛ\000ߞ",
+ "L\000M\000B\000R\000N\000H\000M",
+ "C\000J\000R\000D\000Ŋ\000D\000B",
+ "D\000W\000K\000R\000K\000J\000S",
+ "D\000W\000Q\000R\000K\000J\000S",
+ "ର\000ସୋ\000ମ\000ବୁ\000ଗୁ\000ଶୁ\000ଶ",
+ "Х\000К\000Д\000Ӕ\000Ц\000М\000С",
+ "𐓏\000𐓄\000𐓍\000𐒴\000𐓈\000𐓊\000𐓸",
+ "ਐ\000ਸੋ\000ਮੰ\000ਬੁੱ\000ਵੀ\000ਸ਼ੁੱ\000ਸ਼",
+ "n\000p\000w\000ś\000c\000p\000s",
+ "D\000S\000T\000Q\000Q\000S\000S",
+ "D\000G\000M\000M\000G\000V\000S",
+ "D\000L\000Ma\000Mi\000J\000V\000S",
+ "В\000П\000В\000С\000Ч\000П\000С",
+ "Б\000Б\000О\000С\000Ч\000Б\000С",
+ "A\000K\000O\000I\000I\000S\000K",
+ "ᱥ\000ᱚ\000ᱵ\000ᱥ\000ᱥ\000ᱡ\000ᱧ",
+ "M\000J\000J\000J\000A\000I\000J",
+ "D\000L\000M\000M\000G\000C\000S",
+ "آچر\000سو\000اڱ\000اربع\000خم\000جم\000ڇن",
+ "आ\000सू\000मं\000ॿु\000वि\000जु\000छं",
+ "S\000V\000M\000G\000D\000B\000L",
+ "S\000M\000D\000G\000D\000B\000L",
+ "D\000P\000C\000T\000N\000S\000S",
+ "K\000S\000T\000S\000K\000P\000Y",
+ "တိ.\000ၸ.\000ၵ.\000ပု.\000ၽ.\000သု.\000သ.",
+ "ඉ\000ස\000අ\000බ\000බ්ර\000සි\000සෙ",
+ "n\000p\000u\000s\000š\000p\000s",
+ "n\000p\000t\000s\000č\000p\000s",
+ "p\000V\000M\000K\000T\000V\000L",
+ "S\000M\000C\000C\000C\000C\000M",
+ "A\000I\000T\000A\000Kh\000J\000S",
+ "d\000h\000m\000m\000e\000p\000sh",
+ "n\000p\000u\000s\000č\000p\000s",
+ "ܚ\000ܬ\000ܬ\000ܐ\000ܚ\000ܥ\000ܫ",
+ "ஞா\000தி\000செ\000பு\000வி\000வெ\000ச",
+ "ఆ\000సో\000మ\000బు\000గు\000శు\000శ",
+ "J\000B\000A\000U\000U\000K\000S",
+ "Я\000Д\000С\000Ч\000П\000Ҷ\000Ш",
+ "อา\000จ\000อ\000พ\000พฤ\000ศ\000ส",
+ "ሰ\000ሰ\000ሰ\000ረ\000ሓ\000ዓ\000ቀ",
+ "Ý\000D\000S\000Ç\000P\000A\000Ş",
+ "S\000M\000T\000P\000T\000F\000T",
+ "P\000P\000S\000Ç\000P\000C\000C",
+ "Я\000Д\000С\000Ч\000П\000Җ\000Ш",
+ "У\000П\000В\000С\000Ч\000П\000С",
+ "A\000A\000A\000A\000A\000A\000A",
+ "ي\000د\000س\000چ\000پ\000ج\000ش",
+ "Н\000П\000В\000С\000Ч\000П\000С",
+ "Y\000D\000S\000C\000P\000J\000S",
+ "Я\000Д\000С\000Ч\000П\000Ж\000Ш",
+ "D\000L\000M\000M\000Z\000V\000S",
+ "CN\000T2\000T3\000T4\000T5\000T6\000T7",
+ "S\000M\000Z\000M\000F\000F\000S",
+ "Dib\000Alt\000Tal\000Àla\000Alx\000Àjj\000Ase",
+ "C\000Mv\000Sb\000Tht\000Sin\000Hl\000Mg",
+ "त\000सो\000मं\000बु\000वी\000शु\000श",
+ "S\000B\000B\000S\000K\000K\000M",
+ "s\000m\000m\000e\000k\000f\000s",
+ "À\000A\000Ì\000Ọ\000Ọ\000Ẹ\000À",
+ "À\000A\000Ì\000Ɔ\000Ɔ\000Ɛ\000À",
+ "M\000M\000M\000M\000S\000Y\000S",
+ "日\000一\000二\000三\000四\000五\000六",
+ "S\000M\000B\000T\000S\000H\000M",
+};
+
+const char *era_tab[] = {
+ "BCE\000CE\000BCE\000CE\000BCE\000CE",
+ "voor Christus\000ná Christus\000v.C.\000n.C.\000v.C.\000n.C.",
+ "Sěe Kɨ̀lesto\000Bǎa Kɨ̀lesto\000SK\000BK\000SK\000BK",
+ "Ansa Kristo\000Kristo Akyi\000AK\000KE\000AK\000KE",
+ "ዓመተ ዓለም\000ዓመተ ምሕረት\000ዓ/ዓ\000ዓ/ም\000ዓ/ዓ\000ዓ/ም",
+ "قبل الميلاد\000ميلادي\000ق.م\000م\000ق.م\000م",
+ "খ্ৰীষ্টপূৰ্ব\000খ্ৰীষ্টাব্দ\000খ্ৰীঃ পূঃ\000খ্ৰীঃ\000খ্ৰীঃ পূঃ\000খ্ৰীঃ",
+ "Kabla yakwe Yethu\000Baada yakwe Yethu\000KM\000BM\000KM\000BM",
+ "enantes de Cristu\000después de Cristu\000e.C.\000d.C.\000e.C.\000d.C.",
+ "eramızdan əvvəl\000yeni era\000e.ə.\000y.e.\000e.ə.\000y.e.",
+ "ерамыздан әввәл\000јени ера\000е.ә.\000ј.е.\000е.ә.\000ј.е.",
+ "беҙҙең эраға тиклем\000беҙҙең эра\000б.э.т.\000б.э.\000б.э.т.\000б.э.",
+ "Péshmilád\000Annó Domini\000PM\000AD\000PM\000AD",
+ "bisū bi Yesù Krǐstò\000i mbūs Yesù Krǐstò\000b.Y.K\000m.Y.K\000b.Y.K\000m.Y.K",
+ "да нараджэння Хрыстова\000ад нараджэння Хрыстова\000да н.э.\000н.э.\000да н.э.\000н.э.",
+ "Before Yesu\000After Yesu\000BC\000AD\000BC\000AD",
+ "Kabla ya Mtwaa\000Baada ya Mtwaa\000KM\000BM\000KM\000BM",
+ "преди Христа\000след Христа\000пр.Хр.\000сл.Хр.\000пр.Хр.\000сл.Хр.",
+ "naa Ba Ye Ŋʊm Annabi Ɩsa\000Annabi Ɩsa Abʊŋʊma Kaŋkǝm\000naaBYŊAƖ\000AƖAK\000naaBYŊAƖ\000AƖAK",
+ "jezu krisiti ɲɛ\000jezu krisiti minkɛ\000J.-C. ɲɛ\000ni J.-C.\000J.-C. ɲɛ\000ni J.-C.",
+ "খ্রিস্টপূর্ব\000খ্রিস্টাব্দ\000খ্রিস্টপূর্ব\000খৃষ্টাব্দ\000খ্রিস্টপূর্ব\000খৃষ্টাব্দ",
+ "খ্রিঃপূঃ\000খ্রিষ্টাব্দ\000খ্রিঃপূঃ\000খ্রিঃ\000খ্রিঃপূঃ\000খ্রিঃ",
+ "སྤྱི་ལོ་སྔོན་\000སྤྱི་ལོ་\000སྤྱི་ལོ་སྔོན་\000སྤྱི་ལོ་\000སྤྱི་ལོ་སྔོན་\000སྤྱི་ལོ་",
+ "a-raok Jezuz-Krist\000goude Jezuz-Krist\000a-raok J.K.\000goude J.K.\000a-raok J.K.\000goude J.K.",
+ "ख्राइष्तनि सिगां\000आन्न’ दामिनि\000बि.सि.\000ए.दि\000बि.सि.\000ए.दि",
+ "prije nove ere\000nove ere\000p. n. e.\000n. e.\000p.n.e.\000n. e.",
+ "прије нове ере\000нове ере\000п. н. е.\000н. е.\000п.н.е.\000н.е.",
+ "abans de Crist\000després de Crist\000aC\000dC\000aC\000dC",
+ "𑄈𑄳𑄢𑄨𑄌𑄴𑄑𑄴𑄛𑄫𑄢𑄴𑄝𑄧\000𑄈𑄳𑄢𑄨𑄌𑄴𑄑𑄛𑄴𑄘𑄧\000𑄈𑄳𑄢𑄨𑄌𑄴𑄑𑄴𑄛𑄫𑄢𑄴𑄝𑄧\000𑄈𑄳𑄢𑄨𑄌𑄴𑄑𑄛𑄴𑄘𑄧\000𑄈𑄳𑄢𑄨𑄌𑄴𑄑𑄴𑄛𑄫𑄢𑄴𑄝𑄧\000𑄈𑄳𑄢𑄨𑄌𑄴𑄑𑄛𑄴𑄘𑄧",
+ "Ӏийса пайхамар вина де кхачале\000Ӏийса пайхамар вина дийнахь дуьйна\000в. э. тӀ. я\000в. э\000в. э. тӀ. я\000в. э",
+ "Sa Wala Pa Si Kristo\000Anno Domini\000BC\000AD\000BC\000AD",
+ "Kurisito Atakaijire\000Kurisito Yaijire\000BC\000AD\000BC\000AD",
+ "ᏧᏓᎷᎸ ᎤᎷᎯᏍᏗ ᎦᎶᏁᏛ\000ᎠᏃ ᏙᎻᏂ\000BC\000AD\000BC\000AD",
+ "پێش زایین\000زایینی\000پێش زایین\000زایینی\000پێش زایین\000زایینی",
+ "před naším letopočtem\000našeho letopočtu\000př. n. l.\000n. l.\000př.n.l.\000n.l.",
+ "хальхи саманачченхи\000хальхи саманари\000х. с-ч.\000х. с.\000х. с-ч.\000х. с.",
+ "Cyn Crist\000Oed Crist\000CC\000OC\000C\000O",
+ "før Kristus\000efter Kristus\000f.Kr.\000e.Kr.\000fKr\000eKr",
+ "Kabla ya Kristo\000Baada ya Kristo\000KK\000BK\000KK\000BK",
+ "v. Chr.\000n. Chr.\000v. Chr.\000n. Chr.\000v. Chr.\000n. Chr.",
+ "Isaa jine\000Isaa zamanoo\000IJ\000IZ\000IJ\000IZ",
+ "ई.पू.\000ई. सन्\000ई.पू.\000ईसवी\000ई.पू.\000ईसवी",
+ "pśed Kristusowym naroźenim\000pó Kristusowem naroźenju\000pś.Chr.n.\000pó Chr.n.\000pś.Chr.n.\000pó Chr.n.",
+ "ɓoso ɓwá yáɓe lá\000mbúsa kwédi a Yés\000ɓ.Ys\000mb.Ys\000ɓ.Ys\000mb.Ys",
+ "Ariŋuu Yeesu\000Atooŋe Yeesu\000ArY\000AtY\000ArY\000AtY",
+ "Mbere ya Kristo\000Thutha wa Kristo\000MK\000TK\000MK\000TK",
+ "Hafi Yesu Va\000Yesu ŋɔli\000HYV\000Yŋ\000HYV\000Yŋ",
+ "προ Χριστού\000μετά Χριστόν\000π.Χ.\000μ.Χ.\000π.Χ.\000μ.Χ.",
+ "Before Christ\000Anno Domini\000BC\000AD\000B\000A",
+ "𐐒𐐲𐑁𐐬𐑉 𐐗𐑉𐐴𐑅𐐻\000𐐈𐑌𐐬 𐐔𐐱𐑋𐐮𐑌𐐨\000𐐒𐐗\000𐐈𐐔\000𐐒\000𐐈",
+ "𐑚𐑰𐑓𐑪𐑮 ·𐑒𐑮𐑲𐑕𐑑\000𐑨𐑙𐑴 𐑛𐑪𐑥𐑦𐑙𐑰\000𐑚·𐑒\000𐑨𐑛\000𐑚\000𐑨",
+ "antaŭ nia erao\000de nia erao\000a.n.e.\000n.e.\000a.n.e.\000n.e.",
+ "antes de Cristo\000después de Cristo\000a. C.\000d. C.\000a. C.\000d. C.",
+ "antes de Cristo\000después de Cristo\000a.C.\000d.C.\000a.C.\000d.C.",
+ "enne Kristust\000pärast Kristust\000eKr\000pKr\000eKr\000pKr",
+ "Kristo aurretik\000Kristo ondoren\000K.a.\000K.o.\000a\000o",
+ "osúsúa Yésus kiri\000ámvus Yésus Kirís\000oyk\000ayk\000oyk\000ayk",
+ "قبل از میلاد\000میلادی\000ق.م.\000م.\000ق\000م",
+ "Hade Iisa\000Caggal Iisa\000H-I\000C-I\000H-I\000C-I",
+ "𞤀𞤣𞤮 𞤀𞤲𞥆𞤢𞤦𞤭 𞤋𞥅𞤧𞤢𞥄\000𞤇𞤢𞥄𞤱𞤮 𞤀𞤲𞥆𞤢𞤦𞤭 𞤋𞥅𞤧𞤢𞥄\000𞤀𞤀𞤋\000𞤇𞤀𞤋\000𞤀𞤀𞤋\000𞤇𞤀𞤋",
+ "ennen Kristuksen syntymää\000jälkeen Kristuksen syntymän\000eKr.\000jKr.\000eKr\000jKr",
+ "Before Christ\000Anno Domini\000BC\000AD\000BC\000AD",
+ "fyri Krist\000eftir Krist\000f.Kr.\000e.Kr.\000fKr\000eKr",
+ "avant Jésus-Christ\000après Jésus-Christ\000av. J.-C.\000ap. J.-C.\000av. J.-C.\000ap. J.-C.",
+ "pdC\000ddC\000pdC\000ddC\000pdC\000ddC",
+ "Foar Kristus\000nei Kristus\000f.Kr.\000n.Kr.\000f.K.\000n.K.",
+ "Roimh Chríost\000Anno Domini\000RC\000AD\000RC\000AD",
+ "Ro Chrìosta\000An dèidh Chrìosta\000RC\000AD\000R\000A",
+ "antes de Cristo\000despois de Cristo\000a.C.\000d.C.\000a.C.\000d.C.",
+ "ઈસવીસન પૂર્વે\000ઇસવીસન\000ઈ.સ.પૂર્વે\000ઈ.સ.\000ઇ સ પુ\000ઇસ",
+ "Yeso ataiborwa\000Yeso kaiboirwe\000YA\000YK\000YA\000YK",
+ "RC\000AD\000RC\000AD\000RC\000AD",
+ "Kafin haihuwar annab\000Bayan haihuwar annab\000K.H\000BHAI\000K.H\000BHAI",
+ "לפני הספירה\000לספירה\000לפנה״ס\000לספירה\000לפני\000אחריי",
+ "ईसा-पूर्व\000ईसवी सन\000ईसा-पूर्व\000ईस्वी\000ईसा-पूर्व\000ईस्वी",
+ "𞄜𞄆𞄪\000CE\000𞄜𞄆𞄪\000CE\000𞄜𞄆𞄪\000CE",
+ "prije Krista\000poslije Krista\000pr. Kr.\000po. Kr.\000pr.n.e.\000AD",
+ "před Chrystowym narodźenjom\000po Chrystowym narodźenju\000př.Chr.n.\000po Chr.n.\000př.Chr.n.\000po Chr.n.",
+ "Krisztus előtt\000időszámításunk szerint\000i. e.\000i. sz.\000ie.\000isz.",
+ "Քրիստոսից առաջ\000Քրիստոսից հետո\000մ.թ.ա.\000մ.թ.\000մ.թ.ա.\000մ.թ.",
+ "ante Christo\000post Christo\000a.Chr.\000p.Chr.\000a.Chr.\000p.Chr.",
+ "Sebelum Masehi\000Masehi\000SM\000M\000SM\000M",
+ "ante Crist\000era Cristan\000a.C.\000e.C.\000a.C.\000e.C.",
+ "Tupu Kraist\000Afọ Kraịst\000BC\000AD\000BC\000AD",
+ "ꃅꋊꂿ\000ꃅꋊꊂ\000ꃅꋊꂿ\000ꃅꋊꊂ\000ꃅꋊꂿ\000ꃅꋊꊂ",
+ "fyrir Krist\000eftir Krist\000f.Kr.\000e.Kr.\000f.k.\000e.k.",
+ "avanti Cristo\000dopo Cristo\000a.C.\000d.C.\000aC\000dC",
+ "紀元前\000西暦\000紀元前\000西暦\000BC\000AD",
+ "tsɛttsɛt mɛŋguꞌ mi ɛ́ lɛɛnɛ Kɛlísɛtɔ gɔ ńɔ́\000tsɛttsɛt mɛŋguꞌ mi ɛ́ fúnɛ Kɛlísɛtɔ tɔ́ mɔ́\000BCE\000CE\000BCE\000CE",
+ "Kabla ya Kristu\000Baada ya Kristu\000KK\000BK\000KK\000BK",
+ "Sakdurunge Masehi\000Masehi\000SM\000M\000SM\000M",
+ "ძველი წელთაღრიცხვით\000ახალი წელთაღრიცხვით\000ძვ. წ.\000ახ. წ.\000ძვ. წ.\000ახ. წ.",
+ "бизиӊ эрамызға шекемги\000бизиӊ эрамыздыӊ\000б. э. ш.\000б. э.\000б. э. ш.\000б. э.",
+ "send talalit n Ɛisa\000seld talalit n Ɛisa\000snd. T.Ɛ\000sld. T.Ɛ\000snd. T.Ɛ\000sld. T.Ɛ",
+ "Mbee wa Yesũ\000Ĩtina wa Yesũ\000MY\000IY\000MY\000IY",
+ "Akanapawa Yesu\000Nankuida Yesu\000AY\000NY\000AY\000NY",
+ "antis di Kristu\000dispos di Kristu\000AK\000DK\000AK\000DK",
+ "Cristo jo\000Cristo kar kỹ\000C.j.\000C.kk.\000C.j.\000C.kk.",
+ "Isaa jine\000Isaa jamanoo\000IJ\000IZ\000IJ\000IZ",
+ "Біздің заманымызға дейін\000біздің заманымыз\000б.з.д.\000б.з.\000б.з.д.\000б.з.",
+ "ءبىزدىڭ زامانىمىزعا دەيىن\000ءبىزدىڭ زامانىمىز\000ب ز د\000ب ز\000ب ز د\000ب ز",
+ "Amait kesich Jesu\000Kokakesich Jesu\000AM\000KO\000AM\000KO",
+ "មុនគ្រិស្តសករាជ\000គ្រិស្តសករាជ\000មុន គ.ស.\000គ.ស.\000មុន គ.ស.\000គ.ស.",
+ "ಕ್ರಿಸ್ತ ಪೂರ್ವ\000ಕ್ರಿಸ್ತ ಶಕ\000ಕ್ರಿ.ಪೂ\000ಕ್ರಿ.ಶ\000ಕ್ರಿ.ಪೂ\000ಕ್ರಿ.ಶ",
+ "기원전\000서기\000BC\000AD\000BC\000AD",
+ "क्रिस्ता आदीं\000क्रि.श.\000क्रिस्तपूर्व\000क्रि.श.\000क्रि.आ.\000क्रि.श.",
+ "Krista Adim\000Anno Domini\000KA\000AD\000K\000A",
+ "قبٕل مسیٖح\000اینو ڈومنی\000بی سی\000اے ڈی\000بی سی\000اے ڈی",
+ "ईसा ब्रोंठ\000ईस्वी\000BC\000AD\000BC\000AD",
+ "Kabla ya Klisto\000Baada ya Klisto\000KK\000BK\000KK\000BK",
+ "di Yɛ́sus aká yálɛ\000cámɛɛn kǝ kǝbɔpka Y\000d.Y.\000k.Y.\000d.Y.\000k.Y.",
+ "vür Krestos\000noh Krestos\000v. Chr.\000n. Chr.\000vC\000nC",
+ "Berî Mîladê\000Piştî Mîladê\000BM\000PM\000BM\000PM",
+ "krisṭ purb nki\000krisṭabd\000bc\000ad\000bc\000ad",
+ "बिफोर क्राइस्ट\000अन्नो डोमिनी\000बिसि\000ए-डि\000बिसि\000ए-डि",
+ "ବିଫୋର କ୍ରାଇଷ୍ଟ\000ଆନ୍ନା ଡୋମିନି\000ବିସି\000ଏଡି\000ବିସି\000ଏଡି",
+ "క్రీన్తు వూర్వం\000క్రీస్తు సకం\000క్రీపూ\000క్రీశ\000క్రీపూ\000క్రీశ",
+ "биздин заманга чейин\000биздин заман\000б.з.ч.\000б.з.\000б.з.ч.\000б.з.",
+ "Kɨrɨsitʉ sɨ anavyaal\000Kɨrɨsitʉ akavyaalwe\000KSA\000KA\000KSA\000KA",
+ "Kulisito nga tannaza\000Bukya Kulisito Azaal\000BC\000AD\000BC\000AD",
+ "dan Gejú Crist\000AD\000dan G.C.\000AD\000dan G.C.\000AD",
+ "Yambo ya Yézu Krís\000Nsima ya Yézu Krís\000libóso ya\000nsima ya Y\000libóso ya\000nsima ya Y",
+ "ກ່ອນຄຣິດສັກກະລາດ\000ຄຣິດສັກກະລາດ\000ກ່ອນ ຄ.ສ.\000ຄ.ສ.\000ກ່ອນ ຄ.ສ.\000ຄ.ສ.",
+ "prieš Kristų\000po Kristaus\000pr. Kr.\000po Kr.\000pr. Kr.\000po Kr.",
+ "Kumpala kwa Yezu Kli\000Kunyima kwa Yezu Kli\000kmp. Y.K.\000kny. Y. K.\000kmp. Y.K.\000kny. Y. K.",
+ "Kapok Kristo obiro\000Ka Kristo osebiro\000BC\000AD\000BC\000AD",
+ "Imberi ya Kuuza Kwa\000Muhiga Kuvita Kuuza\000BC\000AD\000BC\000AD",
+ "pirms mūsu ēras\000mūsu ērā\000p.m.ē.\000m.ē.\000p.m.ē.\000m.ē.",
+ "ईसा-पूर्व\000ईसवी\000ईसा-पूर्व\000ईसवी\000ईसा-पूर्व\000ईसवी",
+ "Meínō Yɛ́sʉ\000Eínō Yɛ́sʉ\000MY\000EY\000MY\000EY",
+ "Mbere ya Kristũ\000Nyuma ya Kristũ\000MK\000NK\000MK\000NK",
+ "avan Zezi-Krist\000apre Zezi-Krist\000av. Z-K\000ap. Z-K\000av. Z-K\000ap. Z-K",
+ "Alohan’i JK\000Aorian’i JK\000BC\000AD\000BC\000AD",
+ "Hinapiya yesu\000Yopia yesu\000HY\000YY\000HY\000YY",
+ "пред нашата ера\000од нашата ера\000пр. н. е.\000н. е.\000пр. н. е.\000н. е.",
+ "ക്രിസ്തുവിന് മുമ്പ്\000ആന്നോ ഡൊമിനി\000ബിസി\000എഡി\000ബിസി\000എഡി",
+ "манай эриний өмнөх\000манай эриний\000МЭӨ\000МЭ\000МЭӨ\000МЭ",
+ "ᠮ᠂ ᠡᠡ᠂ ᠦ\000ᠮ᠂ ᠡ\000ᠮ᠂ ᠡᠡ᠂ ᠦ\000ᠮ᠂ ᠡ\000ᠮ᠂ ᠡᠡ᠂ ᠦ\000ᠮ᠂ ᠡ",
+ "খৃ: মমাং\000খৃ: মতুং\000খৃ: মমাং\000খৃ: মতুং\000খৃ: মমাং\000খৃ: মতুং",
+ "ईसवीसनपूर्व\000ईसवीसन\000ई. स. पू.\000इ. स.\000ई. स. पू.\000इ. स.",
+ "S.M.\000TM\000S.M.\000TM\000S.M.\000TM",
+ "Qabel Kristu\000Wara Kristu\000QK\000WK\000QK\000WK",
+ "KǝPel Kristu\000Pel Kristu\000KK\000PK\000KK\000PK",
+ "ခရစ်တော် မပေါ်မီနှစ်\000ခရစ်နှစ်\000ဘီစီ\000အဒေီ\000ဘီစီ\000အဒေီ",
+ "قبل میلاد\000بعد میلاد\000پ.م\000م.\000پ.م\000م.",
+ "Xristub aiǃâ\000Xristub khaoǃgâ\000BC\000AD\000BC\000AD",
+ "før Kristus\000etter Kristus\000f.Kr.\000e.Kr.\000f.Kr.\000e.Kr.",
+ "UKristo angakabuyi\000Ukristo ebuyile\000BC\000AD\000BC\000AD",
+ "ईसा पूर्व\000सन्\000ईसा पूर्व\000सन्\000ईसा पूर्व\000सन्",
+ "voor Christus\000na Christus\000v.Chr.\000n.Chr.\000v.C.\000n.C.",
+ "Bó Lahlɛ̄\000Pfiɛ Burī\000BL\000PB\000BL\000PB",
+ "mé zyé Yěsô\000mé gÿo ńzyé Yěsô\000m.z.Y.\000m.g.n.Y.\000m.z.Y.\000m.g.n.Y.",
+ "ߌߛߊ߫ ߡߏߦߌ ߢߍ߫\000ߌߛߊ߫ ߡߏߦߌ ߞߐ߫\000ߌߛ. ߡ. ߢߍ߫\000ߌߛ. ߡ. ߞߐ߫\000ߌߛ. ߢߍ߫\000ߌߛ. ߞߐ߫",
+ "A ka̱n Yecu ni dap\000Ɛ ca Yecu dap\000AY\000ƐY\000AY\000ƐY",
+ "BCE\000CE\000BCE\000CE\000a. C.\000d. C.",
+ "Dhaloota Kiristoos Dura\000Bara Araaraa\000DhKD\000BA\000Dh\000B",
+ "Dhaloota Kiristoos Dura\000Bara Araaraa\000KD\000BA\000Dh\000B",
+ "ଖ୍ରୀଷ୍ଟପୂର୍ବ\000ଖ୍ରୀଷ୍ଟାବ୍ଦ\000BC\000AD\000BC\000AD",
+ "н.д.а.\000н.д.\000н.д.а.\000н.д.\000н.д.а.\000н.д.",
+ "ਈਸਵੀ ਪੂਰਵ\000ਈਸਵੀ ਸੰਨ\000ਈ. ਪੂ.\000ਸੰਨ\000ਈ.ਪੂ.\000ਸੰਨ",
+ "ايساپورو\000سں\000ايساپورو\000سں\000ايساپورو\000سں",
+ "Bifọ́ Kraist\000Kraist Im Yiẹ\000BK\000KIY\000BK\000KIY",
+ "przed naszą erą\000naszej ery\000p.n.e.\000n.e.\000p.n.e.\000n.e.",
+ "له میلاد څخه وړاندې\000له میلاد څخه وروسته\000له میلاد وړاندې\000م.\000له میلاد وړاندې\000م.",
+ "antes de Cristo\000depois de Cristo\000a.C.\000d.C.\000a.C.\000d.C.",
+ "ñawpa cristu\000chanta cristu\000a.d.\000d.C.\000a.d.\000dC",
+ "avant Cristus\000suenter Cristus\000a.Cr.\000s.C.\000a.Cr.\000s.C.",
+ "Mbere ya Yezu\000Nyuma ya Yezu\000Mb.Y.\000Ny.Y\000Mb.Y.\000Ny.Y",
+ "înainte de Hristos\000după Hristos\000î.Hr.\000d.Hr.\000î.Hr.\000d.Hr.",
+ "Kabla ya Mayesu\000Baada ya Mayesu\000KM\000BM\000KM\000BM",
+ "до Рождества Христова\000от Рождества Христова\000до н. э.\000н. э.\000до н.э.\000н.э.",
+ "б. э. и.\000б. э\000б. э. и.\000б. э\000б. э. и.\000б. э",
+ "Kabla ya Christo\000Baada ya Christo\000KK\000BK\000KK\000BK",
+ "ᱵᱤ ᱥᱤ\000ᱤᱥᱣᱤ\000ᱵᱤ ᱥᱤ\000ᱤᱥᱣᱤ\000ᱵᱤ ᱥᱤ\000ᱤᱥᱣᱤ",
+ "Ashanali uKilisito\000Pamwandi ya Kilisto\000AK\000PK\000AK\000PK",
+ "in antis de Cristu\000a pustis de Cristu\000a.C.\000p.C.\000a.C.\000p.C.",
+ "prima di Cristu\000doppu di Cristu\000p.C.\000d.C.\000pC\000dC",
+ "قبل مسيح\000عيسوي کان پهرين\000ق م\000ع\000ق م\000ع",
+ "बीसी\000एडी\000बीसी\000एडी\000बीसी\000एडी",
+ "ovdal Kristtusa\000maŋŋel Kristtusa\000o.Kr.\000m.Kr.\000o.Kr.\000m.Kr.",
+ "ovdal Kristusa\000maŋŋel Kristusa\000oKr.\000mKr.\000oKr.\000mKr.",
+ "Antes de Cristo\000Anno Domini\000AC\000AD\000AC\000AD",
+ "Kôzo na Krîstu\000Na pekô tî Krîstu\000KnK\000NpK\000KnK\000NpK",
+ "ⴷⴰⵜ ⵏ ⵄⵉⵙⴰ\000ⴷⴼⴼⵉⵔ ⵏ ⵄⵉⵙⴰ\000ⴷⴰⵄ\000ⴷⴼⵄ\000ⴷⴰⵄ\000ⴷⴼⵄ",
+ "dat n ɛisa\000dffir n ɛisa\000daɛ\000dfɛ\000daɛ\000dfɛ",
+ "ဢွၼ်ၼႃႈၸဝ်ႈၶရိတ်ႉ\000ပီၶရိတ်ႉ\000ပီႇၸီႇ\000ဢေႇတီႇ\000ပီႇၸီႇ\000ဢေႇတီႇ",
+ "ක්රිස්තු පූර්ව\000ක්රිස්තු වර්ෂ\000ක්රි.පූ.\000ක්රි.ව.\000ක්රි.පූ.\000ක්රි.ව.",
+ "pred Kristom\000po Kristovi\000pred Kr.\000po Kr.\000pred Kr.\000po Kr.",
+ "pred Kristusom\000po Kristusu\000pr. Kr.\000po Kr.\000pr. Kr.\000po Kr.",
+ "Ovdil Kristus šoddâm\000maŋa Kristus šoddâm\000oKr.\000mKr.\000oKr.\000mKr.",
+ "Kristo asati auya\000mugore ramambo vedu\000BC\000AD\000BC\000AD",
+ "Ciise Hortii\000Ciise Dabadii\000BC\000AD\000B\000A",
+ "para Krishtit\000mbas Krishtit\000p.K.\000mb.K.\000p.K.\000mb.K.",
+ "пре нове ере\000нове ере\000п. н. е.\000н. е.\000п.н.е.\000н.е.",
+ "pre nove ere\000nove ere\000p. n. e.\000n. e.\000p.n.e.\000n.e.",
+ "prije nove ere\000nove ere\000p. n. e.\000n. e.\000p.n.e.\000n.e.",
+ "SM\000M\000SM\000M\000SM\000M",
+ "före Kristus\000efter Kristus\000f.Kr.\000e.Kr.\000f.Kr.\000e.Kr.",
+ "ܩܕܡ ܡܫܝܚܐ\000ܫܢܬܐ ܡܪܢܝܬܐ\000ܩܡ\000ܫܡ\000ܩܡ\000ܫܡ",
+ "கிறிஸ்துவுக்கு முன்\000அன்னோ டோமினி\000கி.மு.\000கி.பி.\000கி.மு.\000கி.பி.",
+ "క్రీస్తు పూర్వం\000క్రీస్తు శకం\000క్రీపూ\000క్రీశ\000క్రీపూ\000క్రీశ",
+ "Пеш аз милод\000Пас аз милод\000ПеМ\000ПаМ\000ПеМ\000ПаМ",
+ "ปีก่อนคริสตกาล\000คริสต์ศักราช\000ก่อน ค.ศ.\000ค.ศ.\000ก่อน ค.ศ.\000ค.ศ.",
+ "ቅድመ ክርስቶስ\000ዓመተ ምሕረት\000ዓ/ዓ\000ዓ/ም\000ዓ/ዓ\000ዓ/ም",
+ "Isadan öň\000Isadan soň\000B.e.öň\000B.e.\000B.e.öň\000B.e.",
+ "Pele ga tsalo ya Morena Jeso\000Morago ga Leso la Morena Jeso\000BC\000AD\000BC\000AD",
+ "ki muʻa\000taʻu ʻo Sīsū\000KM\000TS\000KM\000TS",
+ "Milattan Önce\000Milattan Sonra\000MÖ\000MS\000MÖ\000MS",
+ "BC\000CE\000BC\000CE\000BC\000CE",
+ "безнең эрага кадәр\000милади\000б.э.к.\000милади\000б.э.к.\000милади",
+ "Христос бертинде\000Христос төрүмелинден\000БЭЧ\000БЭ\000БЭЧ\000БЭ",
+ "Zdat Ɛisa (TAƔ)\000Ḍeffir Ɛisa (TAƔ)\000ZƐ\000ḌƐ\000ZƐ\000ḌƐ",
+ "مىلادىيەدىن بۇرۇن\000مىلادىيە\000BCE\000مىلادىيە\000BCE\000مىلادىيە",
+ "до нашої ери\000нашої ери\000до н. е.\000н. е.\000до н.е.\000н.е.",
+ "قبل مسیح\000عیسوی\000قبل مسیح\000عیسوی\000قبل مسیح\000عیسوی",
+ "miloddan avvalgi\000milodiy\000m.a.\000milodiy\000m.a.\000milodiy",
+ "милоддан аввалги\000милодий\000м.а.\000милодий\000м.а.\000милодий",
+ "vanti Cristo\000daspò Cristo\000v.C.\000d.C.\000v.C.\000d.C.",
+ "Trước Chúa Giáng Sinh\000Sau Công Nguyên\000TCN\000SCN\000TCN\000CN",
+ "v. Chr.\000n. Chr\000v. Chr.\000n. Chr\000v. Chr.\000n. Chr",
+ "av. JC\000AD\000JC\000AD\000JC\000AD",
+ "Phambi KoKristu\000Anno Domino\000BC\000AD\000BC\000AD",
+ "ईसा-पैले\000ईसवी सन\000ईसा-पैले\000ईस्वी\000ईसा-पैले\000ईस्वी",
+ "Kulisto nga azilawo\000Kulisto nga affile\000AZ\000AF\000AZ\000AF",
+ "katikupíen Yésuse\000ékélémkúnupíén n\000k.Y.\000+J.C.\000k.Y.\000+J.C.",
+ "Saju Kristi\000Lehin Kristi\000BCE\000AD\000BCE\000AD",
+ "Kiristu senũdé\000Kiristu ariré\000K.s.\000K.a.\000K.s.\000K.a.",
+ "西元前\000西元\000西元前\000西元\000西元前\000西元",
+ "公元前\000公元\000公元前\000公元\000公元前\000公元",
+ "BC\000AD\000BC\000AD\000BC\000AD",
+};
+
+const char *ampm_tab[] = {
+ "AM\000PM",
+ "vm.\000nm.",
+ "a.g\000a.k",
+ "AN\000ANW",
+ "ጥዋት\000ከሰዓት",
+ "ص\000م",
+ "পূৰ্বাহ্ন\000অপৰাহ্ন",
+ "icheheavo\000ichamthi",
+ "АМ\000ПМ",
+ "am\000pm",
+ "I bikɛ̂glà\000I ɓugajɔp",
+ "uluchelo\000akasuba",
+ "pamilau\000pamunyi",
+ "1ka\0002ja",
+ "སྔ་དྲོ་\000ཕྱི་དྲོ་",
+ "A.M.\000G.M.",
+ "फुं\000बेलासे",
+ "a. m.\000p. m.",
+ "пре подне\000поподне",
+ "ᏌᎾᎴ\000ᏒᎯᏱᎢ",
+ "ب.ن\000د.ن",
+ "dop.\000odp.",
+ "ᐊᒼ\000ᐲᒼ",
+ "к. у.\000к. х.",
+ "Luma lwa K\000luma lwa p",
+ "Subbaahi\000Zaarikay b",
+ "सवेर\000स’ञ",
+ "dop.\000wótp.",
+ "idiɓa\000ebyámu",
+ "སྔ་ཆ་\000ཕྱི་ཆ་",
+ "KI\000UT",
+ "ŋdi\000ɣetrɔ",
+ "π.μ.\000μ.μ.",
+ "a.m.\000p.m.",
+ "𐐈𐐣\000𐐑𐐣",
+ "𐑨𐑥\000𐑐𐑥",
+ "atm\000ptm",
+ "kíkíríg\000ngəgógəle",
+ "ق.ظ.\000ب.ظ.",
+ "subaka\000kikiiɗe",
+ "𞤀𞤎\000𞤇𞤎",
+ "ap.\000ip.",
+ "mat.\000soir",
+ "a.\000p.",
+ "r.n.\000i.n.",
+ "m\000f",
+ "vorm.\000nam.",
+ "Ma\000Mo",
+ "SF\000YM",
+ "dop.\000pop.",
+ "de.\000du.",
+ "N’ụtụtụ\000N’abalị",
+ "ꎸꄑ\000ꁯꋒ",
+ "f.h.\000e.h.",
+ "午前\000午後",
+ "mbaꞌmbaꞌ\000ŋka mbɔ́t nji",
+ "utuko\000kyiukonyi",
+ "Isuk\000Wengi",
+ "n tufat\000n tmeddit",
+ "Ĩyakwakya\000Ĩyawĩoo",
+ "Muhi\000Chilo",
+ "Adduha\000Aluula",
+ "Kiroko\000Hwaĩ-inĩ",
+ "ت د\000ت ك",
+ "krn\000koosk",
+ "오전\000오후",
+ "makeo\000nyiaghuo",
+ "sárúwá\000cɛɛ́nko",
+ "v.M.\000n.M.",
+ "BN\000PN",
+ "ए एम\000पी एम",
+ "ଏ ଏମ\000ପି ଏମ",
+ "ఎ ఎమ్\000పి ఎమ్",
+ "тң\000тк",
+ "TOO\000MUU",
+ "moies\000nomëttes",
+ "ntɔ́ngɔ́\000mpókwa",
+ "ກ່ອນທ່ຽງ\000ຫຼັງທ່ຽງ",
+ "priešpiet\000popiet",
+ "Dinda\000Dilolo",
+ "OD\000OT",
+ "priekšp.\000pēcp.",
+ "भोर\000सांझ",
+ "Ɛnkakɛnyá\000Ɛndámâ",
+ "RŨ\000ŨG",
+ "wichishu\000mchochil’l",
+ "претпл.\000попл.",
+ "ү.ө.\000ү.х.",
+ "নুমাং\000PM",
+ "PG\000PTG",
+ "comme\000lilli",
+ "နံနက်\000ညနေ",
+ "ǁgoagas\000ǃuias",
+ "पूर्वाह्न\000अपराह्न",
+ "maná\000kugú",
+ "f.m.\000e.m.",
+ "mbaʼámbaʼ\000ncwònzém",
+ "ߛ\000ߥ",
+ "RW\000TŊ",
+ "WD\000WB",
+ "FM\000FI",
+ "غ.م.\000غ.و.",
+ "Z.MU.\000Z.MW.",
+ "kang’ama\000kingoto",
+ "ЭИ\000ЭК",
+ "Tesiran\000Teipa",
+ "Lwamilawu\000Pashamihe",
+ "صبح\000شام",
+ "i.b.\000e.b.",
+ "ib\000eb",
+ "ND\000LK",
+ "ⵜⵉⴼⴰⵡⵜ\000ⵜⴰⴷⴳⴳⵯⴰⵜ",
+ "tifawt\000tadggʷat",
+ "တၸ.\000တလ.",
+ "පෙ.ව.\000ප.ව.",
+ "ip.\000ep.",
+ "GH\000GD",
+ "p.d.\000m.d.",
+ "прије подне\000по подне",
+ "prije podne\000po podne",
+ "fm\000em",
+ "ܩܛ\000ܒܛ",
+ "do połedniŏ\000po połedniu",
+ "Taparachu\000Ebongi",
+ "ቅ.ቀ.\000ድ.ቀ.",
+ "go.öň\000go.soň",
+ "HH\000EA",
+ "ÖÖ\000ÖS",
+ "Zdat azal\000Ḍeffir aza",
+ "چ.ب\000چ.ك",
+ "дп\000пп",
+ "TO\000TK",
+ "ТО\000ТК",
+ "SA\000CH",
+ "Sub\000Ngo",
+ "भ्यागा\000दपेहरा/संजा",
+ "Munkyo\000Eigulo",
+ "kiɛmɛ́ɛm\000kisɛ́ndɛ",
+ "פֿאַרמיטאָג\000נאָכמיטאָג",
+ "Àárọ̀\000Ọ̀sán",
+ "Àárɔ̀\000Ɔ̀sán",
+ "上晝\000下晝",
+ "上昼\000下昼",
+ "上午\000下午",
+};
+
+const char *dayperiod_tab[] = {
+ "\000\000\000\000",
+ "die oggend\000\000die middag\000die aand\000die nag",
+ "ጥዋት\000ቀትር\000ከሰዓት\000በምሽት\000በሌሊት",
+ "في الصباح\000\000ظهرًا\000مساءً\000في المساء",
+ "sübh\000günorta\000gündüz\000axşamüstü\000axşam",
+ "сүбһ\000ҝүнорта\000ҝүндүз\000ахшамүстү\000ахшам",
+ "сутринта\000\000следобед\000вечерта\000през нощта",
+ "asʊbaa\000\000gɩshilikɔnɔ\000gɩjibɔŋɔ\000gajanɩ",
+ "ভোরবেলায়\000\000দুপুরবেলায়\000সন্ধ্যাবেলায়\000রাত্রিবেলায়",
+ "ভোরবেলায়\000\000দুপুরবেলায়\000সন্ধ্যাবেলায়\000রাত্রি",
+ "ujutro\000podne\000poslijepodne\000navečer\000po noći",
+ "ујутру\000подне\000у подне\000увече\000ноћу",
+ "matinada\000\000migdia\000vespre\000nit",
+ "𑄛𑄧𑄖𑄳𑄠𑄃𑄟𑄧𑄣𑄳𑄠𑄬\000\000𑄘𑄨𑄝𑄪𑄎𑄳𑄠\000𑄥𑄎𑄧𑄚𑄳𑄠\000𑄢𑄬𑄖𑄴",
+ "ᏌᎾᎴ\000ᎢᎦ\000ᏒᎯᏱᎢᏗᏢ\000\000",
+ "ráno\000poledne\000odpoledne\000večer\000v noci",
+ "y bore\000canol dydd\000y prynhawn\000yr hwyr\000",
+ "om morgenen\000\000om eftermiddagen\000om aftenen\000om natten",
+ "morgens\000\000mittags\000abends\000nachts",
+ "fɔŋli\000\000ŋdɔ\000fiẽ\000zã",
+ "το πρωί\000\000το μεσημέρι\000το απόγευμα\000το βράδυ",
+ "in the morning\000noon\000in the afternoon\000in the evening\000at night",
+ "in the morning\000midday\000in the afternoon\000in the evening\000at night",
+ "de la madrugada\000del mediodía\000\000de la tarde\000de la noche",
+ "madrugada\000mediodía\000\000tarde\000noche",
+ "de la madrugada\000m.\000\000de la tarde\000de la noche",
+ "de la madrugada\000mediodía\000\000de la tarde\000de la noche",
+ "hommikul\000keskpäeval\000pärastlõunal\000õhtul\000öösel",
+ "goizaldeko\000\000eguerdiko\000iluntzeko\000gaueko",
+ "بامداد\000\000بعدازظهر\000\000شب",
+ "بامداد\000\000ظهر\000\000شب",
+ "aamulla\000keskipäivällä\000iltapäivällä\000illalla\000yöllä",
+ "ng umaga\000tanghaling-tapat\000ng hapon\000ng gabi\000ng gabi",
+ "du matin\000midi\000de l’après-midi\000du soir\000du matin",
+ "du matin\000midi\000de l’après-midi\000du soir\000de la nuit",
+ "da madrugada\000\000do mediodía\000da tarde\000da noite",
+ "am Morge\000\000zmittag\000zaabig\000znacht",
+ "સવારે\000\000બપોરે\000સાંજે\000રાત્રે",
+ "בבוקר\000\000בצהריים\000בערב\000בלילה",
+ "सुबह\000\000दोपहर\000शाम\000रात",
+ "subah\000Madhyanh\000dopahar\000shaam\000raat",
+ "ujutro\000podne\000poslije podne\000navečer\000noću",
+ "reggel\000dél\000délután\000este\000éjjel",
+ "առավոտյան\000կեսօրին\000ցերեկվա\000երեկոյան\000գիշերվա",
+ "pagi\000tengah hari\000siang\000sore\000malam",
+ "að morgni\000hádegi\000síðdegis\000að kvöldi\000að nóttu",
+ "di mattina\000mezzogiorno\000del pomeriggio\000di sera\000di notte",
+ "朝\000正午\000昼\000夕方\000夜",
+ "დილით\000შუადღეს\000ნაშუადღევს\000საღამოს\000ღამით",
+ "kusãg ki\000kurã-kuju\000rãkãnh kỹ\000kuty kỹ\000kurã ge",
+ "таңғы\000түскі\000түстен кейінгі\000кешкі\000түнгі",
+ "تاڭعى\000تۇسكى\000تۇستەن كەيىنگى\000كەشى\000تۇنگى",
+ "នៅពេលព្រឹក\000ថ្ងៃត្រង់\000នៅពេលរសៀល\000នៅពេលល្ងាច\000នៅពេលយប់",
+ "ಬೆಳಗ್ಗೆ\000\000ಮಧ್ಯಾಹ್ನ\000ಸಂಜೆ\000ರಾತ್ರಿ",
+ "아침\000정오\000오후\000저녁\000밤",
+ "सकाळीं\000\000दनपारां\000सांजे\000राती",
+ "sokallim\000\000donparam\000sanje\000rati",
+ "эртең менен\000чак түш\000түштөн кийин\000кечинде\000түн ичинде",
+ "ຕອນເຊົ້າ\000ຕອນທ່ຽງ\000ຕອນບ່າຍ\000ຕອນແລງ\000ຕອນກາງຄືນ",
+ "rytas\000perpiet\000popietė\000vakaras\000naktis",
+ "no rīta\000pusdienlaikā\000pēcpusdienā\000vakarā\000naktī",
+ "наутро\000напладне\000попладне\000навечер\000ноќе",
+ "പുലർച്ചെ\000ഉച്ച\000ഉച്ചയ്ക്ക്\000വൈകുന്നേരം\000രാത്രി",
+ "өглөө\000үд дунд\000өдөр\000орой\000шөнө",
+ "पहाट\000मध्यान्ह\000दुपार\000संध्याकाळ\000रात्र",
+ "tengah malam\000\000tengah hari\000petang\000malam",
+ "နံနက်\000မွန်းတည့်\000နေ့လယ်\000ညနေ\000ည",
+ "på morgenen\000\000på ettermiddagen\000på kvelden\000på natten",
+ "बिहान\000मध्यान्ह\000अपरान्ह\000बेलुकी\000रात",
+ "’s ochtends\000\000’s middags\000’s avonds\000’s nachts",
+ "på morgonen\000\000på ettermiddagen\000på kvelden\000på natta",
+ "ਸਵੇਰੇ\000\000ਦੁਪਹਿਰੇ\000ਸ਼ਾਮੀਂ\000ਰਾਤੀਂ",
+ "rano\000w południe\000po południu\000wieczorem\000w nocy",
+ "da manhã\000meio-dia\000da tarde\000da noite\000da madrugada",
+ "dimineața\000la amiază\000după-amiaza\000seara\000noaptea",
+ "dimineața\000amiază\000după-amiaza\000seara\000noaptea",
+ "утра\000полдень\000дня\000вечера\000ночи",
+ "පාන්දර\000මධ්යාහ්නය\000දවල්\000හවස\000රෑ",
+ "ráno\000napoludnie\000popoludní\000večer\000v noci",
+ "zjutraj\000opoldne\000popoldan\000zvečer\000ponoči",
+ "e mëngjesit\000e mesditës\000e pasdites\000e mbrëmjes\000e natës",
+ "ујутру\000подне\000по подне\000увече\000ноћу",
+ "јутро\000подне\000по под.\000вече\000ноћу",
+ "јутро\000подне\000по под.\000увече\000ноћу",
+ "ujutru\000podne\000po podne\000uveče\000noću",
+ "jutro\000podne\000po pod.\000veče\000noću",
+ "jutro\000podne\000po pod.\000uveče\000noću",
+ "på morgonen\000\000på eftermiddagen\000på kvällen\000på natten",
+ "alfajiri\000saa sita za mchana\000mchana\000jioni\000usiku",
+ "அதிகாலை\000நண்பகல்\000மதியம்\000மாலை\000இரவு",
+ "ఉదయం\000\000మధ్యాహ్నం\000సాయంత్రం\000రాత్రి",
+ "ในตอนเช้า\000เที่ยง\000ในตอนบ่าย\000ในตอนเย็น\000กลางคืน",
+ "sabah\000öğle\000öğleden sonra\000akşam\000gece",
+ "ранку\000дня\000дня\000вечора\000ночі",
+ "صبح میں\000\000دوپہر میں\000شام میں\000رات میں",
+ "ertalab\000tush payti\000kunduzi\000kechqurun\000kechasi",
+ "эрталаб\000туш пайти\000кундузи\000кечқурун\000кечаси",
+ "sáng\000trưa\000chiều\000tối\000đêm",
+ "kuêma ramẽ\000iandé-ara-pyturepé\000karuka ramẽ\000pituna ramẽ\000pitunaeté ramẽ",
+ "清晨\000\000中午\000夜晚\000凌晨",
+ "清晨\000\000中午\000晚上\000凌晨",
+ "早上\000\000中午\000晚上\000凌晨",
+ "entathakusa\000\000emini\000ntambama\000ebusuku",
+};
+
+const char *dayperiod_narrow_tab[] = {
+ "\000\000\000\000",
+ "die oggend\000\000in die middag\000in die aand\000in die nag",
+ "ጥዋት\000ቀ\000ከሰዓት\000በምሽት\000በሌሊት",
+ "فجرًا\000\000ظهرًا\000مساءً\000منتصف الليل",
+ "sübh\000g\000gündüz\000axşamüstü\000axşam",
+ "сүбһ\000ҝ\000ҝүндүз\000ахшамүстү\000ахшам",
+ "сутринта\000\000следобед\000вечерта\000през нощта",
+ "asb\000\000gshk\000gjb\000gjn",
+ "ভোর\000\000দুপুর\000সন্ধ্যা\000রাত্রি",
+ "ujutro\000podne\000poslijepodne\000navečer\000po noći",
+ "ујутру\000подне\000у подне\000увече\000ноћу",
+ "matinada\000\000migdia\000vespre\000nit",
+ "𑄛𑄧𑄖𑄳𑄠𑄃𑄟𑄧𑄣𑄳𑄠𑄬\000\000𑄘𑄨𑄝𑄪𑄎𑄳𑄠\000𑄥𑄎𑄧𑄚𑄳𑄠\000𑄢𑄬𑄖𑄴",
+ "ᏌᎾᎴ\000Ꭲ\000ᏒᎯᏱᎢᏗᏢ\000\000",
+ "r.\000pol.\000o.\000v.\000n.",
+ "yn y bore\000canol dydd\000yn y prynhawn\000min nos\000",
+ "om morgenen\000\000om eftermiddagen\000om aftenen\000om natten",
+ "morgens\000\000mittags\000abends\000nachts",
+ "fɔŋli\000\000ŋdɔ\000fiẽ\000zã",
+ "πρωί\000\000μεσημ.\000απόγ.\000βράδυ",
+ "in the morning\000n\000in the afternoon\000in the evening\000at night",
+ "in the morning\000midday\000in the afternoon\000in the evening\000at night",
+ "mor\000n\000aft\000eve\000night",
+ "de la madrugada\000del mediodía\000\000de la tarde\000de la noche",
+ "madrugada\000mediodía\000\000tarde\000noche",
+ "de la madrugada\000m.\000\000de la tarde\000de la noche",
+ "día\000mediodía\000\000tarde\000noche",
+ "de la madrugada\000mediodía\000\000de la tarde\000de la noche",
+ "hommikul\000keskpäeval\000pärastlõunal\000õhtul\000öösel",
+ "goizald.\000\000eguerd.\000iluntz.\000gaueko",
+ "بامداد\000\000ظهر\000\000شب",
+ "aamulla\000kp.\000ip.\000illalla\000yöllä",
+ "ng umaga\000tanghaling-tapat\000ng hapon\000ng gabi\000ng gabi",
+ "mat.\000midi\000ap.m.\000soir\000matin",
+ "mat.\000midi\000après-midi\000du soir\000mat.",
+ "du mat.\000midi\000de l’ap.m.\000du soir\000du mat.",
+ "da madrugada\000\000do mediodía\000da tarde\000da noite",
+ "am Morge\000\000zmittag\000zaabig\000znacht",
+ "સવારે\000\000બપોરે\000સાંજે\000રાત્રે",
+ "בבוקר\000\000בצהריים\000בערב\000בלילה",
+ "सुबह\000\000दोपहर\000शाम\000रात",
+ "subah\000n\000dopahar\000shaam\000raat",
+ "ujutro\000podne\000popodne\000navečer\000noću",
+ "reggel\000dél\000délután\000este\000éjjel",
+ "առվ\000կօ․\000ցրկ\000երկ\000գշր",
+ "pagi\000tengah hari\000siang\000sore\000malam",
+ "mrg.\000h.\000sd.\000kv.\000n.",
+ "di mattina\000mezzogiorno\000di pomeriggio\000di sera\000di notte",
+ "朝\000正午\000昼\000夕方\000夜",
+ "დილ.\000შუადღ.\000ნაშუადღ.\000საღ.\000ღამ.",
+ "kusãg ki\000kurã-kuju\000rãkãnh kỹ\000kuty kỹ\000kurã ge",
+ "таңғы\000түскі\000түстен кейінгі\000кешкі\000түнгі",
+ "تاڭعى\000تۇسكى\000تۇستەن كەيىنگى\000كەش\000تۇنگى",
+ "នៅពេលព្រឹក\000ថ្ងៃត្រង់\000នៅពេលរសៀល\000នៅពេលល្ងាច\000នៅពេលយប់",
+ "ಬೆಳಗ್ಗೆ\000\000ಮಧ್ಯಾಹ್ನ\000ಸಂಜೆ\000ರಾತ್ರಿ",
+ "아침\000정오\000오후\000저녁\000밤",
+ "सकाळ\000\000दनपार\000सांज\000रात",
+ "sk\000\000dp\000sj\000rt",
+ "эртң мн\000чт\000түшт кйн\000кечк\000түн",
+ "ຕອນເຊົ້າ\000ຕອນທ່ຽງ\000ຕອນທ່ຽງ\000ຕອນແລງ\000ກາງຄືນ",
+ "rytas\000perpiet\000popietė\000vakaras\000naktis",
+ "no rīta\000pusd.\000pēcpusd.\000vakarā\000naktī",
+ "наутро\000напл.\000попл.\000навечер\000ноќе",
+ "പുലർച്ചെ\000ഉച്ച\000ഉച്ചയ്ക്ക്\000വൈകുന്നേരം\000രാത്രി",
+ "өглөө\000үд дунд\000өдөр\000орой\000шөнө",
+ "प\000दु\000दु\000सं\000रा",
+ "pagi\000\000tengah hari\000petang\000malam",
+ "နံနက်\000မွန်းတည့်\000နေ့လယ်\000ညနေ\000ည",
+ "mg.\000\000em.\000kv.\000nt.",
+ "बिहान\000मध्यान्ह\000अपरान्ह\000बेलुकी\000रात",
+ "’s ochtends\000\000’s middags\000’s avonds\000’s nachts",
+ "ਸਵੇਰੇ\000\000ਦੁਪਹਿਰੇ\000ਸ਼ਾਮੀਂ\000ਰਾਤੀਂ",
+ "rano\000w poł.\000po poł.\000wiecz.\000w nocy",
+ "da manhã\000meio-dia\000da tarde\000da noite\000da madrugada",
+ "manhã\000meio-dia\000tarde\000noite\000madrugada",
+ "dimineața\000amiază\000după-amiaza\000seara\000noaptea",
+ "dimineață\000amiază\000după-amiază\000seară\000noapte",
+ "утра\000полд.\000дня\000веч.\000ночи",
+ "පා\000ම\000ද\000හ\000රෑ",
+ "ráno\000nap.\000pop.\000več.\000v n.",
+ "zj\00012.00\000p\000zv\000po",
+ "e mëngjesit\000e mesditës\000e pasdites\000e mbrëmjes\000e natës",
+ "ујутру\000подне\000по подне\000увече\000ноћу",
+ "ујутро\000подне\000по подне\000увече\000ноћу",
+ "јутро\000подне\000по под.\000вече\000ноћ",
+ "ujutru\000podne\000po podne\000uveče\000noću",
+ "ujutro\000podne\000po podne\000uveče\000noću",
+ "jutro\000podne\000po pod.\000veče\000noć",
+ "på morg.\000\000på efterm.\000på kvällen\000på natten",
+ "alfajiri\000mchana\000mchana\000jioni\000usiku",
+ "காலை\000நண்.\000மதி.\000மா.\000இர.",
+ "ఉదయం\000\000మధ్యాహ్నం\000సాయంత్రం\000రాత్రి",
+ "เช้า\000เที่ยง\000เที่ยง\000เย็น\000กลางคืน",
+ "sabah\000ö\000öğleden sonra\000akşam\000gece",
+ "ранку\000дня\000дня\000вечора\000ночі",
+ "صبح\000\000دوپہر\000شام\000رات",
+ "ertalab\000tush payti\000kunduzi\000kechqurun\000kechasi",
+ "эрталаб\000туш пайти\000кундузи\000кечқурун\000кечаси",
+ "sáng\000tr\000chiều\000tối\000đêm",
+ "kuêma ramẽ\000iandé-ara-pyturepé\000karuka ramẽ\000pituna ramẽ\000pitunaeté ramẽ",
+ "清晨\000\000中午\000夜晚\000凌晨",
+ "早上\000\000中午\000晚上\000凌晨",
+ "清晨\000\000中午\000晚上\000凌晨",
+ "entathakusa\000\000emini\000ntambama\000ebusuku",
+};
+
+const char *date_pattern_tab[] = {
+ "y-MM-dd",
+ "y MMM d",
+ "y MMMM d",
+ "y MMMM d, EEEE",
+ "dd MMM y",
+ "dd MMMM y",
+ "EEEE dd MMMM y",
+ "d/M/y",
+ "d MMM, y",
+ "d MMMM y",
+ "EEEE d MMMM y",
+ "d/M/yy",
+ "d, MMM, y",
+ "d, MMMM, y",
+ "EEE, d, MMMM, y",
+ "dd/MM/y",
+ "d MMM y",
+ "d/M/y",
+ "dd/MM/y",
+ "EEEE، d MMMM y",
+ "d-M-y",
+ "dd-MM-y",
+ "d MMMM, y",
+ "EEEE, d MMMM, y",
+ "EEEE, d MMMM y",
+ "d MMMM 'de' y",
+ "EEEE, d MMMM 'de' y",
+ "dd.MM.yy",
+ "d MMMM y, EEEE",
+ "dd.MM.y",
+ "d MMM, y 'й'.",
+ "d MMMM, y 'й'.",
+ "d MMMM, EEEE, y 'й'.",
+ "dd,MM,y",
+ "d.MM.yy",
+ "d MMM y 'г'.",
+ "d MMMM y 'г'.",
+ "EEEE, d MMMM y 'г'.",
+ "d.MM.yy 'г'.",
+ "d.MM.y 'г'.",
+ "M/d/y",
+ "MMM d/y",
+ "EEEE, MMMM d/y",
+ "y ལོའི་MMMཚེས་d",
+ "སྤྱི་ལོ་y MMMMའི་ཚེས་d",
+ "y MMMMའི་ཚེས་d, EEEE",
+ "d. M. y.",
+ "d. MMM y.",
+ "d. MMMM y.",
+ "EEEE, d. MMMM y.",
+ "d.M.yy.",
+ "dd.MM.y.",
+ "dd. MMMM y.",
+ "EEEE, dd. MMMM y.",
+ "d MMMM 'del' y",
+ "EEEE, d MMMM 'del' y",
+ "M/d/yy",
+ "MMM d, y",
+ "MMMM d, y",
+ "EEEE, MMMM d, y",
+ "dی MMMMی y",
+ "d. M. y",
+ "d. MMMM y",
+ "EEEE d. MMMM y",
+ "y.MM.dd",
+ "y, MMM, d",
+ "y, MMMM, d",
+ "y, MMMM, d, EEEE",
+ "dd/MM/yy",
+ "d. MMM y",
+ "EEEE 'den' d. MMMM y",
+ "EEEE, d. MMMM y",
+ "d, MMM y",
+ "d, MMMM y",
+ "EEEE, d, MMMM y",
+ "d.M.yy",
+ "d.M.y",
+ "སྤྱི་ལོ་y ཟླ་MMM ཚེས་dd",
+ "སྤྱི་ལོ་y MMMM ཚེས་ dd",
+ "EEEE, སྤྱི་ལོ་y MMMM ཚེས་dd",
+ "MMM d 'lia', y",
+ "MMMM d 'lia' y",
+ "EEEE, MMMM d 'lia' y",
+ "EEEE, dd MMMM y",
+ "dd-MMM-y",
+ "y/MM/dd",
+ "d-M-yy",
+ "dd MMM,y",
+ "yy-MM-dd",
+ "y-MMM-dd",
+ "y-MMMM-dd",
+ "EEEE, 'la' d-'a' 'de' MMMM y",
+ "d 'de' MMMM 'de' y",
+ "EEEE, d 'de' MMMM 'de' y",
+ "d MMM 'de' y",
+ "dd-MM-yy",
+ "d/MM/yy",
+ "d/MM/y",
+ "dd 'de' MMMM 'de' y",
+ "EEEE dd 'de' MMMM 'de' y",
+ "MM/dd/yy",
+ "MM/dd/y",
+ "yy/M/d",
+ "y('e')'ko' MMM d('a')",
+ "y('e')'ko' MMMM'ren' d('a')",
+ "y('e')'ko' MMMM'ren' d('a'), EEEE",
+ "y/M/d",
+ "d MMM⹁ y",
+ "d MMMM⹁ y",
+ "EEEE d MMMM⹁ y",
+ "cccc d. MMMM y",
+ "d 'di' MMMM 'dal' y",
+ "EEEE d 'di' MMMM 'dal' y",
+ "d'mh' MMM y",
+ "d'mh' MMMM y",
+ "EEEE, d'mh' MMMM y",
+ "d 'de' MMM 'de' y",
+ "EEEE d MMMM, y",
+ "[object Object]",
+ "d בMMM y",
+ "d בMMMM y",
+ "EEEE, d בMMMM y",
+ "dd MMM, y",
+ "dd. MM. y.",
+ "d. M. yy.",
+ "y. MM. dd.",
+ "y. MMM d.",
+ "y. MMMM d.",
+ "y. MMMM d., EEEE",
+ "dd MMM, y թ.",
+ "dd MMMM, y թ.",
+ "y թ. MMMM d, EEEE",
+ "d 'de' MMMM y",
+ "EEEE 'le' d 'de' MMMM y",
+ "y年M月d日",
+ "y年M月d日EEEE",
+ "EEEE, y MMMM dd",
+ "d MMM. y",
+ "EEEE, dd MMMM, y",
+ "d 'di' MMMM 'di' y",
+ "EEEE, d 'di' MMMM 'di' y",
+ "d 'ne' MMM, y",
+ "d 'ne' MMMM, y",
+ "EEEE, d 'ne' MMMM, y",
+ "y 'ж'. dd MMM",
+ "y 'ж'. d MMMM",
+ "y 'ж'. d MMMM, EEEE",
+ "y، d- MMM",
+ "y، d- MMMM",
+ "y، d- MMMM، EEEE",
+ "dd/MM y",
+ "yy. M. d.",
+ "y. M. d.",
+ "y년 MMMM d일",
+ "y년 MMMM d일 EEEE",
+ "d-MMM-y",
+ "d. MMM. y",
+ "EEEE, 'dä' d. MMMM y",
+ "d'ê' MMMM'a' y'an'",
+ "EEEE, d'ê' MMMM'a' y'an'",
+ "y-'ж'., d-MMM",
+ "y-'ж'., d-MMMM",
+ "y-'ж'., d-MMMM, EEEE",
+ "EEEE, d MMMM 'dl' y",
+ "y 'm'. MMMM d 'd'.",
+ "y 'm'. MMMM d 'd'., EEEE",
+ "y. 'gada' d. MMM",
+ "y. 'gada' d. MMMM",
+ "EEEE, y. 'gada' d. MMMM",
+ "d.M.y 'г'.",
+ "y 'оны' MMM'ын' d",
+ "y 'оны' MMMM'ын' d",
+ "y 'оны' MMMM'ын' d, EEEE 'гараг'",
+ "y ᠋ᠣᠨ ᠤMMMM ᠤᠩ d",
+ "y ᠣᠨ ᠤ MMMMᠢᠢᠨd. EEEE ᠋ᠭᠠᠷᠠᠭ",
+ "MMMM d, y, EEEE",
+ "d 'ta'’ MMMM y",
+ "EEEE, d 'ta'’ MMMM y",
+ "y MMMM d EEEE",
+ "'lyɛ'̌ʼ d 'na' MMMM, y",
+ "EEEE , 'lyɛ'̌ʼ d 'na' MMMM, y",
+ "dd MMM y 'аз'",
+ "d MMMM, y 'аз'",
+ "EEEE, d MMMM, y 'аз'",
+ "d.MM.y",
+ "EEEE د y د MMMM d",
+ "EEEE, 'ils' d MMMM y",
+ "y, MMM d",
+ "y, MMMM d",
+ "y 'сыл' MMMM d 'күнэ', EEEE",
+ "d 'de' MMM y",
+ "d 'de' MMMM 'de' 'su' y",
+ "EEEE d 'de' MMMM 'de' 'su' y",
+ "y MMMM d - EEEE",
+ "MMM d. y",
+ "MMMM d. y",
+ "cccc, MMMM d. y",
+ "d-MM-y",
+ "d ܒMMM y",
+ "d ܒMMMM y",
+ "EEEE، d ܒMMMM y",
+ "d, MMMM y, EEEE",
+ "d MMMM G y",
+ "EEEEที่ d MMMM G y",
+ "EEEE፣ d MMMM y",
+ "d MMMM y EEEE",
+ "'sike' #y 'la' MMM 'la' 'suno' #d",
+ "'tenpo' 'sike' #y 'la' 'tenpo' MMMM 'la' 'tenpo' 'suno' #d",
+ "d MMM, y 'ел'",
+ "d MMMM, y 'ел'",
+ "d MMMM, y 'ел', EEEE",
+ "y'ч' MMM d",
+ "y'ч' MMMM d",
+ "y'ч' MMMM d, EEEE",
+ "d-MMM، y",
+ "d-MMMM، y",
+ "y d-MMMM، EEEE",
+ "d MMM y 'р'.",
+ "d MMMM y 'р'.",
+ "EEEE, d MMMM y 'р'.",
+ "d MMM، y",
+ "d MMMM، y",
+ "EEEE، d MMMM، y",
+ "d-MMM, y",
+ "d-MMMM, y",
+ "EEEE, d-MMMM, y",
+ "EEEE, d MMM, y",
+ "dטן MMM y",
+ "dטן MMMM y",
+ "EEEE, dטן MMMM y",
+ "d MM y",
+ "EEEE, d MMM y",
+ "y年M月d日 EEEE",
+};
+
+const char *time_pattern_tab[] = {
+ "h:mm a",
+ "h:mm:ss a",
+ "h:mm:ss a z",
+ "h:mm:ss a zzzz",
+ "HH:mm",
+ "HH:mm:ss",
+ "HH:mm:ss z",
+ "HH:mm:ss zzzz",
+ "h:mm a",
+ "h:mm:ss a",
+ "h:mm:ss a z",
+ "h:mm:ss a zzzz",
+ "H:mm",
+ "H:mm:ss",
+ "H:mm:ss z",
+ "H:mm:ss zzzz",
+ "a h.mm",
+ "a h.mm.ss",
+ "a h.mm.ss z",
+ "a h.mm.ss zzzz",
+ "hh:mm a",
+ "hh:mm:ss a",
+ "hh:mm:ss a zzz",
+ "hh:mm:ss a zzzz",
+ "HH:mm:ss, zzzz",
+ "H:mm:ss 'ч'. z",
+ "H:mm:ss 'ч'. zzzz",
+ "a नि h:mm",
+ "a h:mm:ss",
+ "a h:mm:ss z",
+ "a h:mm:ss zzzz",
+ "H:mm:ss (zzzz)",
+ "H:mm:ss, zzzz",
+ "HH:mm:ss (z)",
+ "HH:mm:ss (zzzz)",
+ "HH.mm",
+ "HH.mm.ss",
+ "HH.mm.ss z",
+ "HH.mm.ss zzzz",
+ "ཆུ་ཚོད་ h སྐར་མ་ mm a",
+ "ཆུ་ཚོད་h:mm:ss a",
+ "ཆུ་ཚོད་ h སྐར་མ་ mm:ss a z",
+ "ཆུ་ཚོད་ h སྐར་མ་ mm:ss a zzzz",
+ "a 'ga' h:mm",
+ "a 'ga' h:mm:ss",
+ "a 'ga' h:mm:ss z",
+ "a 'ga' h:mm:ss zzzz",
+ "H.mm",
+ "H.mm.ss",
+ "H.mm.ss z",
+ "H.mm.ss zzzz",
+ "H:mm:ss (z)",
+ "H 'h' mm 'min' ss 's' zzzz",
+ "HH 'h' mm",
+ "HH 'h' mm 'min' ss 's'",
+ "HH 'h' mm 'min' ss 's' z",
+ "HH 'h' mm 'min' ss 's' zzzz",
+ "HH.mm:ss 'h' zzzz",
+ "hh:mm a",
+ "hh:mm:ss a",
+ "hh:mm:ss a z",
+ "hh:mm:ss a zzzz",
+ "H:mm 'hodź'.",
+ "H時mm分ss秒 zzzz",
+ "a h:mm",
+ "a h시 m분 s초 z",
+ "a h시 m분 s초 zzzz",
+ "z HH:mm:ss",
+ "zzzz HH:mm:ss",
+ "a h:mm",
+ "a h:mm:ss",
+ "a h:mm:ss z",
+ "a h:mm:ss zzzz",
+ "H ໂມງ m ນາທີ ss ວິນາທີ z",
+ "H ໂມງ m ນາທີ ss ວິນາທີ zzzz",
+ "z h:mm:ss a",
+ "zzzz h:mm:ss a",
+ "z h:mm:ss a",
+ "zzzz h:mm:ss a",
+ "h:mm:ss a, z",
+ "h:mm:ss a, zzzz",
+ "H นาฬิกา mm นาที ss วินาที z",
+ "H นาฬิกา mm นาที ss วินาที zzzz",
+ "z 'la' HH:mm:ss",
+ "zzzz 'la' HH:mm:ss",
+ "H:m",
+ "H:m:s",
+ "ah:mm",
+ "ah:mm:ss",
+ "ah:mm:ss [z]",
+ "ah:mm:ss [zzzz]",
+ "HH:mm:ss [z]",
+ "HH:mm:ss [zzzz]",
+ "z ah:mm:ss",
+ "zzzz ah:mm:ss",
+ "Bh:mm",
+ "Bh:mm:ss",
+ "Bh:mm:ss [z]",
+ "Bh:mm:ss [zzzz]",
+};
+
+const char *combined_pattern_tab[] = {
+ "{1} {0}",
+ "{1}, {0}",
+ "{1}، {0}",
+ "{0} {1}",
+ "{1} - {0}",
+ "{1} ({0})",
+ "{1}، {0}",
+ "{1}، ساعت {0}",
+ "{1} आँ {0}",
+ "{1} ଆଁ {0}",
+ "{1} త {0}",
+ "{1} 'kl'. {0}",
+ "{1},{0}",
+ "{1} 'ka' {0}",
+ "{1} {0}",
+};
+
+const LocaleData locale_data_table[] = {
+ {
+ "aa",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 0, 1,
+ 2, 3,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 0, 24,
+ },
+ {
+ "aa-DJ",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 0, 1,
+ 2, 3,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 48, 25,
+ },
+ {
+ "aa-ER",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 0, 1,
+ 2, 3,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 99, 25,
+ },
+ {
+ "ab",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 149, 23,
+ },
+ {
+ "af",
+ locale_compact_arr_1,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 1, 1,
+ 1, 1,
+ 1, 1,
+ 1, 1,
+ 1,
+ 0, 4,
+ 5, 6,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 195, 21,
+ },
+ {
+ "af-NA",
+ locale_compact_arr_1,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 1, 1,
+ 1, 1,
+ 1, 1,
+ 1, 1,
+ 1,
+ 0, 4,
+ 5, 6,
+ 0, 1,
+ 2, 3,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 237, 22,
+ },
+ {
+ "agq",
+ locale_compact_arr_0,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 9, 10, 9, 10, 4, 5 },
+ 2, 2,
+ 2, 2,
+ 2, 2,
+ 2, 0,
+ 0,
+ 7, 8,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 281, 23,
+ },
+ {
+ "ak",
+ locale_compact_arr_2,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 3, 3,
+ 3, 3,
+ 3, 3,
+ 3, 0,
+ 0,
+ 11, 12,
+ 13, 14,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 327, 25,
+ },
+ {
+ "am",
+ locale_compact_arr_3,
+ { 0, 0, 0, 0, 0, 0, 1 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 4, 4,
+ 4, 4,
+ 4, 4,
+ 4, 2,
+ 2,
+ 15, 16,
+ 9, 10,
+ 8, 9,
+ 10, 11,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 379, 24,
+ },
+ {
+ "an",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 428, 23,
+ },
+ {
+ "ann",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 474, 24,
+ },
+ {
+ "apc",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 522, 24,
+ },
+ {
+ "ar",
+ locale_compact_arr_4,
+ { 0, 0, 1, 1, 1, 0, 2 },
+ { 0, 1, 11, 12, 13, 14, 4, 5 },
+ 5, 5,
+ 5, 5,
+ 5, 5,
+ 5, 3,
+ 3,
+ 17, 18,
+ 9, 19,
+ 8, 9,
+ 10, 11,
+ 2, 2,
+ 2, 2,
+ 12, 3, 0,
+ 570, 43,
+ },
+ {
+ "ar-AE",
+ locale_compact_arr_4,
+ { 0, 0, 1, 1, 1, 0, 2 },
+ { 0, 1, 11, 12, 13, 14, 4, 5 },
+ 5, 5,
+ 5, 5,
+ 5, 5,
+ 5, 3,
+ 3,
+ 17, 18,
+ 9, 19,
+ 8, 9,
+ 10, 11,
+ 2, 2,
+ 2, 2,
+ 12, 3, 0,
+ 656, 43,
+ },
+ {
+ "ar-BH",
+ locale_compact_arr_4,
+ { 2, 2, 2, 2, 2, 0, 2 },
+ { 0, 1, 11, 15, 11, 15, 4, 5 },
+ 5, 5,
+ 5, 5,
+ 5, 5,
+ 5, 3,
+ 3,
+ 17, 18,
+ 9, 19,
+ 8, 9,
+ 10, 11,
+ 2, 2,
+ 2, 2,
+ 12, 3, 0,
+ 742, 43,
+ },
+ {
+ "ar-DJ",
+ locale_compact_arr_4,
+ { 2, 2, 2, 2, 2, 0, 2 },
+ { 0, 1, 11, 15, 11, 15, 4, 5 },
+ 5, 5,
+ 5, 5,
+ 5, 5,
+ 5, 3,
+ 3,
+ 17, 18,
+ 9, 19,
+ 8, 9,
+ 10, 11,
+ 2, 2,
+ 2, 2,
+ 12, 3, 0,
+ 828, 44,
+ },
+ {
+ "ar-DZ",
+ locale_compact_arr_4,
+ { 1, 3, 1, 1, 1, 0, 2 },
+ { 0, 1, 11, 12, 13, 14, 4, 5 },
+ 6, 6,
+ 6, 5,
+ 5, 5,
+ 5, 3,
+ 3,
+ 17, 18,
+ 9, 19,
+ 8, 9,
+ 10, 11,
+ 2, 2,
+ 2, 2,
+ 12, 3, 0,
+ 917, 43,
+ },
+ {
+ "ar-EG",
+ locale_compact_arr_4,
+ { 2, 2, 2, 2, 2, 0, 2 },
+ { 0, 1, 11, 15, 11, 15, 4, 5 },
+ 5, 5,
+ 5, 5,
+ 5, 5,
+ 5, 3,
+ 3,
+ 17, 18,
+ 9, 19,
+ 8, 9,
+ 10, 11,
+ 2, 2,
+ 2, 2,
+ 12, 3, 0,
+ 1003, 43,
+ },
+ {
+ "ar-EH",
+ locale_compact_arr_4,
+ { 0, 0, 1, 1, 1, 0, 2 },
+ { 0, 1, 11, 12, 13, 14, 4, 5 },
+ 5, 5,
+ 5, 5,
+ 5, 5,
+ 5, 3,
+ 3,
+ 17, 18,
+ 9, 19,
+ 8, 9,
+ 10, 11,
+ 2, 2,
+ 2, 2,
+ 12, 3, 0,
+ 1089, 43,
+ },
+ {
+ "ar-ER",
+ locale_compact_arr_4,
+ { 2, 2, 2, 2, 2, 0, 2 },
+ { 0, 1, 11, 15, 11, 15, 4, 5 },
+ 5, 5,
+ 5, 5,
+ 5, 5,
+ 5, 3,
+ 3,
+ 17, 18,
+ 9, 19,
+ 8, 9,
+ 10, 11,
+ 2, 2,
+ 2, 2,
+ 12, 3, 0,
+ 1175, 44,
+ },
+ {
+ "ar-IL",
+ locale_compact_arr_4,
+ { 2, 2, 2, 2, 2, 0, 2 },
+ { 0, 1, 11, 15, 11, 15, 4, 5 },
+ 5, 5,
+ 5, 5,
+ 5, 5,
+ 5, 3,
+ 3,
+ 17, 18,
+ 9, 19,
+ 12, 13,
+ 14, 15,
+ 2, 2,
+ 2, 2,
+ 12, 3, 0,
+ 1263, 43,
+ },
+ {
+ "ar-IQ",
+ locale_compact_arr_4,
+ { 2, 2, 2, 2, 2, 0, 2 },
+ { 0, 1, 11, 15, 11, 15, 4, 5 },
+ 7, 7,
+ 7, 5,
+ 5, 5,
+ 5, 3,
+ 3,
+ 17, 18,
+ 9, 19,
+ 8, 9,
+ 10, 11,
+ 2, 2,
+ 2, 2,
+ 12, 3, 0,
+ 1349, 43,
+ },
+ {
+ "ar-JO",
+ locale_compact_arr_4,
+ { 2, 2, 2, 2, 2, 0, 2 },
+ { 0, 1, 11, 15, 11, 15, 4, 5 },
+ 7, 8,
+ 7, 5,
+ 5, 5,
+ 5, 3,
+ 3,
+ 17, 18,
+ 9, 19,
+ 8, 9,
+ 10, 11,
+ 2, 2,
+ 2, 2,
+ 12, 3, 0,
+ 1435, 43,
+ },
+ {
+ "ar-KM",
+ locale_compact_arr_4,
+ { 2, 2, 2, 2, 2, 0, 2 },
+ { 0, 1, 11, 15, 11, 15, 4, 5 },
+ 5, 5,
+ 5, 5,
+ 5, 5,
+ 5, 3,
+ 3,
+ 17, 18,
+ 9, 19,
+ 4, 5,
+ 6, 7,
+ 2, 2,
+ 2, 2,
+ 12, 3, 0,
+ 1521, 44,
+ },
+ {
+ "ar-KW",
+ locale_compact_arr_4,
+ { 2, 2, 2, 2, 2, 0, 2 },
+ { 0, 1, 11, 15, 11, 15, 4, 5 },
+ 5, 5,
+ 5, 5,
+ 5, 5,
+ 5, 3,
+ 3,
+ 17, 18,
+ 9, 19,
+ 8, 9,
+ 10, 11,
+ 2, 2,
+ 2, 2,
+ 12, 3, 0,
+ 1611, 43,
+ },
+ {
+ "ar-LB",
+ locale_compact_arr_4,
+ { 2, 2, 2, 2, 2, 0, 2 },
+ { 0, 1, 11, 15, 11, 15, 4, 5 },
+ 7, 8,
+ 7, 5,
+ 5, 5,
+ 5, 3,
+ 3,
+ 17, 18,
+ 9, 19,
+ 8, 9,
+ 10, 11,
+ 2, 2,
+ 2, 2,
+ 12, 3, 0,
+ 1697, 42,
+ },
+ {
+ "ar-LY",
+ locale_compact_arr_4,
+ { 1, 3, 1, 1, 1, 0, 2 },
+ { 0, 1, 11, 12, 13, 14, 4, 5 },
+ 5, 5,
+ 5, 5,
+ 5, 5,
+ 5, 3,
+ 3,
+ 17, 18,
+ 9, 19,
+ 8, 9,
+ 10, 11,
+ 2, 2,
+ 2, 2,
+ 12, 3, 0,
+ 1781, 43,
+ },
+ {
+ "ar-MA",
+ locale_compact_arr_4,
+ { 1, 3, 1, 1, 1, 0, 2 },
+ { 0, 1, 11, 12, 13, 14, 4, 5 },
+ 8, 9,
+ 8, 5,
+ 5, 5,
+ 5, 3,
+ 3,
+ 17, 18,
+ 9, 19,
+ 4, 5,
+ 6, 7,
+ 2, 2,
+ 2, 2,
+ 12, 3, 0,
+ 1867, 43,
+ },
+ {
+ "ar-MR",
+ locale_compact_arr_4,
+ { 2, 2, 2, 2, 2, 0, 2 },
+ { 0, 1, 11, 15, 11, 15, 4, 5 },
+ 9, 10,
+ 9, 5,
+ 5, 5,
+ 5, 3,
+ 3,
+ 17, 18,
+ 9, 19,
+ 8, 9,
+ 10, 11,
+ 2, 2,
+ 2, 2,
+ 12, 3, 0,
+ 1953, 43,
+ },
+ {
+ "ar-OM",
+ locale_compact_arr_4,
+ { 2, 2, 2, 2, 2, 0, 2 },
+ { 0, 1, 11, 15, 11, 15, 4, 5 },
+ 5, 5,
+ 5, 5,
+ 5, 5,
+ 5, 3,
+ 3,
+ 17, 18,
+ 9, 19,
+ 8, 9,
+ 10, 11,
+ 2, 2,
+ 2, 2,
+ 12, 3, 0,
+ 2039, 43,
+ },
+ {
+ "ar-PS",
+ locale_compact_arr_4,
+ { 2, 2, 2, 2, 2, 0, 2 },
+ { 0, 1, 11, 15, 11, 15, 4, 5 },
+ 7, 8,
+ 7, 5,
+ 5, 5,
+ 5, 3,
+ 3,
+ 17, 18,
+ 9, 19,
+ 8, 9,
+ 10, 11,
+ 2, 2,
+ 2, 2,
+ 12, 3, 0,
+ 2125, 43,
+ },
+ {
+ "ar-QA",
+ locale_compact_arr_4,
+ { 2, 2, 2, 2, 2, 0, 2 },
+ { 0, 1, 11, 15, 11, 15, 4, 5 },
+ 5, 5,
+ 5, 5,
+ 5, 5,
+ 5, 3,
+ 3,
+ 17, 18,
+ 9, 19,
+ 8, 9,
+ 10, 11,
+ 2, 2,
+ 2, 2,
+ 12, 3, 0,
+ 2211, 43,
+ },
+ {
+ "ar-SA",
+ locale_compact_arr_4,
+ { 2, 2, 2, 2, 2, 0, 2 },
+ { 0, 1, 11, 15, 11, 15, 4, 5 },
+ 5, 5,
+ 5, 5,
+ 5, 5,
+ 5, 3,
+ 3,
+ 17, 18,
+ 9, 19,
+ 8, 9,
+ 10, 11,
+ 2, 2,
+ 2, 2,
+ 12, 3, 0,
+ 2297, 43,
+ },
+ {
+ "ar-SD",
+ locale_compact_arr_4,
+ { 2, 2, 2, 2, 2, 0, 2 },
+ { 0, 1, 11, 15, 11, 15, 4, 5 },
+ 5, 5,
+ 5, 5,
+ 5, 5,
+ 5, 3,
+ 3,
+ 17, 18,
+ 9, 19,
+ 8, 9,
+ 10, 11,
+ 2, 2,
+ 2, 2,
+ 12, 3, 0,
+ 2383, 43,
+ },
+ {
+ "ar-SO",
+ locale_compact_arr_4,
+ { 2, 2, 2, 2, 2, 0, 2 },
+ { 0, 1, 11, 15, 11, 15, 4, 5 },
+ 5, 5,
+ 5, 5,
+ 5, 5,
+ 5, 3,
+ 3,
+ 17, 18,
+ 9, 19,
+ 8, 9,
+ 10, 11,
+ 2, 2,
+ 2, 2,
+ 12, 3, 0,
+ 2469, 44,
+ },
+ {
+ "ar-SS",
+ locale_compact_arr_4,
+ { 2, 2, 2, 2, 2, 0, 2 },
+ { 0, 1, 11, 15, 11, 15, 4, 5 },
+ 5, 5,
+ 5, 5,
+ 5, 5,
+ 5, 3,
+ 3,
+ 17, 18,
+ 9, 19,
+ 8, 9,
+ 10, 11,
+ 2, 2,
+ 2, 2,
+ 12, 3, 0,
+ 2557, 44,
+ },
+ {
+ "ar-SY",
+ locale_compact_arr_4,
+ { 2, 2, 2, 2, 2, 0, 2 },
+ { 0, 1, 11, 15, 11, 15, 4, 5 },
+ 7, 8,
+ 7, 5,
+ 5, 5,
+ 5, 3,
+ 3,
+ 17, 18,
+ 9, 19,
+ 8, 9,
+ 10, 11,
+ 2, 2,
+ 2, 2,
+ 12, 3, 0,
+ 2645, 43,
+ },
+ {
+ "ar-TD",
+ locale_compact_arr_4,
+ { 2, 2, 2, 2, 2, 0, 2 },
+ { 0, 1, 11, 15, 11, 15, 4, 5 },
+ 5, 5,
+ 5, 5,
+ 5, 5,
+ 5, 3,
+ 3,
+ 17, 18,
+ 9, 19,
+ 8, 9,
+ 10, 11,
+ 2, 2,
+ 2, 2,
+ 12, 3, 0,
+ 2731, 43,
+ },
+ {
+ "ar-TN",
+ locale_compact_arr_4,
+ { 1, 3, 1, 1, 1, 0, 2 },
+ { 0, 1, 11, 12, 13, 14, 4, 5 },
+ 6, 6,
+ 6, 5,
+ 5, 5,
+ 5, 3,
+ 3,
+ 17, 18,
+ 9, 19,
+ 8, 9,
+ 10, 11,
+ 2, 2,
+ 2, 2,
+ 12, 3, 0,
+ 2817, 43,
+ },
+ {
+ "ar-YE",
+ locale_compact_arr_4,
+ { 2, 2, 2, 2, 2, 0, 2 },
+ { 0, 1, 11, 15, 11, 15, 4, 5 },
+ 5, 5,
+ 5, 5,
+ 5, 5,
+ 5, 3,
+ 3,
+ 17, 18,
+ 9, 19,
+ 8, 9,
+ 10, 11,
+ 2, 2,
+ 2, 2,
+ 12, 3, 0,
+ 2903, 43,
+ },
+ {
+ "arn",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 2989, 23,
+ },
+ {
+ "as",
+ locale_compact_arr_5,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 6, 8, 4, 5 },
+ 10, 11,
+ 10, 6,
+ 6, 6,
+ 6, 0,
+ 0,
+ 20, 21,
+ 22, 23,
+ 16, 17,
+ 18, 19,
+ 0, 0,
+ 0, 0,
+ 12, 3, 2,
+ 3035, 22,
+ },
+ {
+ "asa",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 11, 12,
+ 1, 7,
+ 7, 7,
+ 7, 0,
+ 0,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 3079, 24,
+ },
+ {
+ "ast",
+ locale_compact_arr_6,
+ { 1, 3, 0, 0, 0, 0, 3 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 12, 13,
+ 11, 8,
+ 8, 8,
+ 0, 0,
+ 0,
+ 11, 16,
+ 25, 26,
+ 4, 5,
+ 6, 7,
+ 0, 1,
+ 1, 1,
+ 12, 3, 0,
+ 3127, 22,
+ },
+ {
+ "az",
+ locale_compact_arr_7,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 13, 14,
+ 0, 9,
+ 9, 9,
+ 0, 4,
+ 4,
+ 27, 16,
+ 9, 28,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 3171, 24,
+ },
+ {
+ "az-Arab",
+ locale_compact_arr_0,
+ { 2, 2, 3, 3, 3, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 3220, 23,
+ },
+ {
+ "az-Arab-IQ",
+ locale_compact_arr_0,
+ { 2, 2, 3, 3, 3, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 3266, 23,
+ },
+ {
+ "az-Arab-TR",
+ locale_compact_arr_0,
+ { 2, 2, 3, 3, 3, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 3312, 23,
+ },
+ {
+ "az-Cyrl",
+ locale_compact_arr_0,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 14, 15,
+ 0, 10,
+ 9, 10,
+ 8, 5,
+ 5,
+ 27, 16,
+ 9, 28,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 3358, 24,
+ },
+ {
+ "az-Latn",
+ locale_compact_arr_7,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 13, 14,
+ 0, 9,
+ 9, 9,
+ 0, 4,
+ 4,
+ 27, 16,
+ 9, 28,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 3407, 24,
+ },
+ {
+ "ba",
+ locale_compact_arr_8,
+ { 0, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 15, 16,
+ 12, 11,
+ 10, 11,
+ 0, 0,
+ 0,
+ 29, 30,
+ 31, 32,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 3456, 24,
+ },
+ {
+ "bal",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 3505, 23,
+ },
+ {
+ "bal-Arab",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 3551, 23,
+ },
+ {
+ "bal-Latn",
+ locale_compact_arr_9,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 16, 17,
+ 0, 12,
+ 11, 12,
+ 9, 0,
+ 0,
+ 11, 8,
+ 22, 33,
+ 20, 21,
+ 22, 23,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 3597, 139,
+ },
+ {
+ "bas",
+ locale_compact_arr_0,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 18, 19 },
+ 17, 18,
+ 13, 13,
+ 12, 13,
+ 10, 0,
+ 0,
+ 7, 8,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 4049, 23,
+ },
+ {
+ "be",
+ locale_compact_arr_10,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 18, 19 },
+ 18, 19,
+ 14, 14,
+ 13, 14,
+ 0, 0,
+ 0,
+ 34, 35,
+ 36, 37,
+ 4, 5,
+ 6, 24,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 4095, 21,
+ },
+ {
+ "be-tarask",
+ locale_compact_arr_10,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 18, 19 },
+ 18, 19,
+ 14, 14,
+ 13, 14,
+ 0, 0,
+ 0,
+ 34, 35,
+ 36, 37,
+ 4, 5,
+ 6, 24,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 4137, 21,
+ },
+ {
+ "bem",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 19, 20,
+ 15, 15,
+ 0, 15,
+ 11, 0,
+ 0,
+ 15, 16,
+ 9, 24,
+ 0, 1,
+ 2, 3,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 4179, 24,
+ },
+ {
+ "bew",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 4229, 23,
+ },
+ {
+ "bez",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 9, 10, 9, 10, 4, 5 },
+ 20, 21,
+ 16, 16,
+ 14, 16,
+ 12, 0,
+ 0,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 4275, 24,
+ },
+ {
+ "bg",
+ locale_compact_arr_11,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 4, 5 },
+ 21, 22,
+ 17, 17,
+ 15, 17,
+ 9, 6,
+ 6,
+ 38, 39,
+ 36, 37,
+ 12, 13,
+ 25, 26,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 4323, 8,
+ },
+ {
+ "bgc",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 22, 23,
+ 0, 18,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 8, 9,
+ 10, 11,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 4342, 23,
+ },
+ {
+ "bgn",
+ locale_compact_arr_0,
+ { 2, 2, 3, 3, 3, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 4388, 25,
+ },
+ {
+ "bgn-AE",
+ locale_compact_arr_0,
+ { 2, 2, 3, 3, 3, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 4438, 25,
+ },
+ {
+ "bgn-AF",
+ locale_compact_arr_0,
+ { 2, 2, 3, 3, 3, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 4488, 25,
+ },
+ {
+ "bgn-IR",
+ locale_compact_arr_0,
+ { 2, 2, 3, 3, 3, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 4538, 25,
+ },
+ {
+ "bgn-OM",
+ locale_compact_arr_0,
+ { 2, 2, 3, 3, 3, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 4588, 25,
+ },
+ {
+ "bho",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 7, 4, 5 },
+ 23, 24,
+ 0, 19,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 8, 9,
+ 10, 11,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 4638, 23,
+ },
+ {
+ "blo",
+ locale_compact_arr_12,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 21, 2, 21, 22, 23 },
+ 24, 25,
+ 0, 20,
+ 16, 18,
+ 13, 7,
+ 7,
+ 40, 41,
+ 2, 42,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 4684, 23,
+ },
+ {
+ "blt",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 4730, 23,
+ },
+ {
+ "bm",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 25, 26,
+ 18, 21,
+ 17, 19,
+ 0, 0,
+ 0,
+ 7, 8,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 4776, 23,
+ },
+ {
+ "bm-Nkoo",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 4822, 23,
+ },
+ {
+ "bn",
+ locale_compact_arr_13,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 9, 10, 9, 24, 4, 5 },
+ 26, 27,
+ 19, 22,
+ 18, 20,
+ 0, 8,
+ 8,
+ 11, 8,
+ 22, 23,
+ 8, 9,
+ 10, 11,
+ 0, 0,
+ 0, 0,
+ 12, 3, 2,
+ 4868, 24,
+ },
+ {
+ "bn-IN",
+ locale_compact_arr_13,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 26, 28,
+ 20, 22,
+ 18, 21,
+ 0, 9,
+ 8,
+ 11, 8,
+ 22, 23,
+ 8, 9,
+ 10, 11,
+ 0, 0,
+ 0, 0,
+ 12, 3, 2,
+ 4917, 24,
+ },
+ {
+ "bo",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 27, 29,
+ 0, 23,
+ 19, 22,
+ 14, 0,
+ 0,
+ 0, 43,
+ 44, 45,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 4966, 23,
+ },
+ {
+ "bo-IN",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 27, 29,
+ 0, 23,
+ 19, 22,
+ 14, 0,
+ 0,
+ 0, 43,
+ 44, 45,
+ 8, 9,
+ 10, 11,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 5012, 23,
+ },
+ {
+ "bqi",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 5058, 23,
+ },
+ {
+ "br",
+ locale_compact_arr_14,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 18, 19 },
+ 28, 30,
+ 21, 24,
+ 20, 23,
+ 15, 0,
+ 0,
+ 15, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 1,
+ 1, 1,
+ 12, 3, 0,
+ 5104, 13,
+ },
+ {
+ "brx",
+ locale_compact_arr_15,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 6, 8, 4, 5 },
+ 29, 31,
+ 22, 25,
+ 21, 24,
+ 16, 0,
+ 0,
+ 21, 8,
+ 22, 28,
+ 27, 28,
+ 29, 30,
+ 1, 1,
+ 1, 1,
+ 12, 3, 2,
+ 5135, 135,
+ },
+ {
+ "bs",
+ locale_compact_arr_16,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 30, 32,
+ 23, 26,
+ 22, 25,
+ 17, 10,
+ 9,
+ 46, 47,
+ 48, 49,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 1, 1,
+ 12, 3, 0,
+ 5561, 14,
+ },
+ {
+ "bs-Cyrl",
+ locale_compact_arr_17,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 31, 33,
+ 24, 27,
+ 23, 26,
+ 18, 11,
+ 10,
+ 50, 51,
+ 52, 53,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 5592, 28,
+ },
+ {
+ "bs-Latn",
+ locale_compact_arr_16,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 30, 32,
+ 23, 26,
+ 22, 25,
+ 17, 10,
+ 9,
+ 46, 47,
+ 48, 49,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 1, 1,
+ 12, 3, 0,
+ 5654, 14,
+ },
+ {
+ "bss",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 5685, 23,
+ },
+ {
+ "bua",
+ locale_compact_arr_0,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 18, 19 },
+ 32, 34,
+ 0, 28,
+ 24, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 5731, 23,
+ },
+ {
+ "byn",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 11,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 5777, 24,
+ },
+ {
+ "ca",
+ locale_compact_arr_18,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 18, 19 },
+ 33, 35,
+ 25, 29,
+ 25, 27,
+ 17, 12,
+ 11,
+ 11, 16,
+ 54, 55,
+ 12, 13,
+ 14, 31,
+ 0, 1,
+ 1, 1,
+ 12, 3, 0,
+ 5825, 16,
+ },
+ {
+ "ca-AD",
+ locale_compact_arr_18,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 18, 19 },
+ 33, 35,
+ 25, 29,
+ 25, 27,
+ 17, 12,
+ 11,
+ 11, 16,
+ 54, 55,
+ 12, 13,
+ 14, 31,
+ 0, 1,
+ 1, 1,
+ 12, 3, 0,
+ 5857, 16,
+ },
+ {
+ "ca-ES-valencia",
+ locale_compact_arr_18,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 18, 19 },
+ 33, 35,
+ 25, 29,
+ 25, 27,
+ 17, 12,
+ 11,
+ 11, 16,
+ 54, 55,
+ 12, 13,
+ 14, 31,
+ 0, 1,
+ 1, 1,
+ 12, 3, 0,
+ 5889, 16,
+ },
+ {
+ "ca-FR",
+ locale_compact_arr_18,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 18, 19 },
+ 33, 35,
+ 25, 29,
+ 25, 27,
+ 17, 12,
+ 11,
+ 11, 16,
+ 54, 55,
+ 12, 13,
+ 14, 31,
+ 0, 1,
+ 1, 1,
+ 12, 3, 0,
+ 5921, 17,
+ },
+ {
+ "ca-IT",
+ locale_compact_arr_18,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 18, 19 },
+ 33, 35,
+ 25, 29,
+ 25, 27,
+ 17, 12,
+ 11,
+ 11, 16,
+ 54, 55,
+ 12, 13,
+ 14, 31,
+ 0, 1,
+ 1, 1,
+ 12, 3, 0,
+ 5955, 16,
+ },
+ {
+ "cad",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 34, 36,
+ 0, 30,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 5987, 23,
+ },
+ {
+ "cch",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 6033, 24,
+ },
+ {
+ "ccp",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 9, 10, 9, 24, 4, 5 },
+ 35, 37,
+ 26, 31,
+ 26, 28,
+ 0, 13,
+ 12,
+ 11, 8,
+ 22, 23,
+ 8, 9,
+ 10, 11,
+ 0, 0,
+ 0, 0,
+ 12, 3, 2,
+ 6081, 24,
+ },
+ {
+ "ccp-IN",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 9, 10, 9, 24, 4, 5 },
+ 35, 37,
+ 26, 31,
+ 26, 28,
+ 0, 13,
+ 12,
+ 11, 8,
+ 22, 23,
+ 8, 9,
+ 10, 11,
+ 0, 0,
+ 0, 0,
+ 12, 3, 2,
+ 6130, 24,
+ },
+ {
+ "ce",
+ locale_compact_arr_19,
+ { 0, 0, 0, 0, 0, 0, 4 },
+ { 0, 1, 16, 17, 16, 17, 18, 19 },
+ 36, 38,
+ 27, 32,
+ 27, 29,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 6179, 23,
+ },
+ {
+ "ceb",
+ locale_compact_arr_20,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 37, 39,
+ 28, 33,
+ 28, 30,
+ 0, 0,
+ 0,
+ 56, 57,
+ 58, 59,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 6225, 23,
+ },
+ {
+ "cgg",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 7, 4, 5 },
+ 38, 40,
+ 1, 34,
+ 29, 31,
+ 0, 0,
+ 0,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 6272, 24,
+ },
+ {
+ "cho",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 6320, 23,
+ },
+ {
+ "chr",
+ locale_compact_arr_21,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 39, 41,
+ 29, 35,
+ 30, 32,
+ 19, 14,
+ 13,
+ 56, 57,
+ 58, 59,
+ 8, 9,
+ 10, 11,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 6366, 22,
+ },
+ {
+ "cic",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 40, 42,
+ 0, 36,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 6410, 23,
+ },
+ {
+ "ckb",
+ locale_compact_arr_0,
+ { 2, 2, 4, 4, 3, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 18, 19 },
+ 41, 43,
+ 30, 37,
+ 31, 33,
+ 20, 0,
+ 0,
+ 0, 1,
+ 60, 3,
+ 8, 9,
+ 10, 11,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 6456, 24,
+ },
+ {
+ "ckb-IR",
+ locale_compact_arr_0,
+ { 2, 2, 4, 4, 3, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 18, 19 },
+ 41, 43,
+ 30, 37,
+ 31, 33,
+ 20, 0,
+ 0,
+ 0, 1,
+ 60, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 6504, 24,
+ },
+ {
+ "co",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 6552, 23,
+ },
+ {
+ "cop",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 6598, 23,
+ },
+ {
+ "cs",
+ locale_compact_arr_22,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 18, 19 },
+ 42, 44,
+ 0, 38,
+ 32, 34,
+ 21, 15,
+ 14,
+ 27, 61,
+ 62, 63,
+ 12, 13,
+ 14, 32,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 6644, 21,
+ },
+ {
+ "csw",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 43, 45,
+ 0, 39,
+ 33, 0,
+ 22, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 0, 1,
+ 2, 3,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 6692, 23,
+ },
+ {
+ "cu",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 6738, 24,
+ },
+ {
+ "cv",
+ locale_compact_arr_23,
+ { 1, 1, 0, 0, 0, 0, 5 },
+ { 0, 1, 16, 17, 16, 20, 18, 19 },
+ 44, 46,
+ 31, 40,
+ 34, 35,
+ 23, 0,
+ 0,
+ 64, 65,
+ 66, 67,
+ 4, 5,
+ 33, 34,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 6786, 24,
+ },
+ {
+ "cy",
+ locale_compact_arr_24,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 45, 47,
+ 32, 41,
+ 35, 36,
+ 0, 16,
+ 15,
+ 68, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 1, 1,
+ 12, 3, 0,
+ 6834, 21,
+ },
+ {
+ "da",
+ locale_compact_arr_25,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 18, 19 },
+ 46, 48,
+ 1, 42,
+ 36, 37,
+ 0, 17,
+ 16,
+ 29, 69,
+ 62, 70,
+ 35, 36,
+ 37, 38,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 6876, 24,
+ },
+ {
+ "da-GL",
+ locale_compact_arr_25,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 18, 19 },
+ 46, 48,
+ 1, 42,
+ 36, 37,
+ 0, 17,
+ 16,
+ 29, 69,
+ 62, 70,
+ 35, 36,
+ 37, 38,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 6924, 24,
+ },
+ {
+ "dav",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 47, 49,
+ 33, 43,
+ 37, 38,
+ 24, 0,
+ 0,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 6972, 24,
+ },
+ {
+ "de",
+ locale_compact_arr_26,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 18, 19 },
+ 48, 50,
+ 1, 44,
+ 38, 39,
+ 0, 18,
+ 17,
+ 27, 29,
+ 62, 71,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 4, 3, 0,
+ 7020, 26,
+ },
+ {
+ "de-AT",
+ locale_compact_arr_27,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 18, 19 },
+ 49, 51,
+ 1, 44,
+ 38, 39,
+ 0, 18,
+ 17,
+ 27, 29,
+ 62, 71,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 7072, 26,
+ },
+ {
+ "de-BE",
+ locale_compact_arr_27,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 18, 19 },
+ 48, 50,
+ 1, 44,
+ 38, 39,
+ 0, 18,
+ 17,
+ 27, 29,
+ 62, 71,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 7124, 26,
+ },
+ {
+ "de-CH",
+ locale_compact_arr_27,
+ { 0, 4, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 25, 2, 25, 4, 5 },
+ 48, 50,
+ 1, 44,
+ 38, 39,
+ 0, 18,
+ 17,
+ 27, 29,
+ 62, 71,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 7176, 25,
+ },
+ {
+ "de-IT",
+ locale_compact_arr_27,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 18, 19 },
+ 49, 51,
+ 1, 44,
+ 38, 39,
+ 0, 18,
+ 17,
+ 27, 29,
+ 62, 71,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 7226, 26,
+ },
+ {
+ "de-LI",
+ locale_compact_arr_27,
+ { 0, 4, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 48, 50,
+ 1, 44,
+ 38, 39,
+ 0, 18,
+ 17,
+ 27, 29,
+ 62, 71,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 7278, 25,
+ },
+ {
+ "de-LU",
+ locale_compact_arr_27,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 18, 19 },
+ 48, 50,
+ 1, 44,
+ 38, 39,
+ 0, 18,
+ 17,
+ 27, 29,
+ 62, 71,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 7328, 27,
+ },
+ {
+ "dje",
+ locale_compact_arr_0,
+ { 0, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 9, 10, 9, 10, 4, 5 },
+ 50, 52,
+ 34, 45,
+ 39, 40,
+ 25, 0,
+ 0,
+ 7, 8,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 7383, 23,
+ },
+ {
+ "doi",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 7, 4, 5 },
+ 51, 53,
+ 35, 46,
+ 40, 41,
+ 26, 0,
+ 0,
+ 11, 72,
+ 73, 74,
+ 8, 9,
+ 10, 11,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 7429, 23,
+ },
+ {
+ "dsb",
+ locale_compact_arr_28,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 18, 19 },
+ 52, 54,
+ 36, 47,
+ 41, 42,
+ 27, 0,
+ 0,
+ 75, 76,
+ 62, 71,
+ 12, 13,
+ 14, 15,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 7475, 24,
+ },
+ {
+ "dua",
+ locale_compact_arr_0,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 18, 19 },
+ 53, 55,
+ 37, 48,
+ 42, 43,
+ 28, 0,
+ 0,
+ 7, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 7524, 23,
+ },
+ {
+ "dv",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 7570, 24,
+ },
+ {
+ "dyo",
+ locale_compact_arr_0,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 54, 56,
+ 38, 49,
+ 43, 44,
+ 0, 0,
+ 0,
+ 7, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 7620, 23,
+ },
+ {
+ "dz",
+ locale_compact_arr_29,
+ { 0, 0, 0, 0, 0, 1, 6 },
+ { 0, 1, 6, 7, 6, 7, 18, 19 },
+ 55, 57,
+ 39, 50,
+ 44, 0,
+ 29, 0,
+ 0,
+ 0, 77,
+ 78, 79,
+ 39, 40,
+ 41, 42,
+ 0, 0,
+ 0, 0,
+ 12, 3, 2,
+ 7666, 23,
+ },
+ {
+ "ebu",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 56, 58,
+ 40, 51,
+ 45, 45,
+ 30, 0,
+ 0,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 7716, 24,
+ },
+ {
+ "ee",
+ locale_compact_arr_30,
+ { 0, 0, 0, 0, 0, 0, 7 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 57, 59,
+ 41, 52,
+ 46, 46,
+ 31, 19,
+ 18,
+ 56, 80,
+ 81, 82,
+ 43, 44,
+ 45, 46,
+ 3, 3,
+ 3, 3,
+ 12, 3, 0,
+ 7764, 25,
+ },
+ {
+ "ee-TG",
+ locale_compact_arr_30,
+ { 0, 0, 0, 0, 0, 0, 7 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 57, 59,
+ 41, 52,
+ 46, 46,
+ 31, 19,
+ 18,
+ 56, 80,
+ 81, 82,
+ 4, 5,
+ 6, 7,
+ 3, 3,
+ 3, 3,
+ 12, 3, 0,
+ 7814, 25,
+ },
+ {
+ "el",
+ locale_compact_arr_31,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 58, 60,
+ 42, 53,
+ 47, 47,
+ 32, 20,
+ 19,
+ 11, 16,
+ 9, 10,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 4, 4,
+ 12, 3, 0,
+ 7864, 24,
+ },
+ {
+ "el-CY",
+ locale_compact_arr_31,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 58, 60,
+ 42, 53,
+ 47, 47,
+ 32, 20,
+ 19,
+ 11, 16,
+ 9, 10,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 4, 4,
+ 12, 3, 0,
+ 7914, 24,
+ },
+ {
+ "el-polyton",
+ locale_compact_arr_31,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 59, 61,
+ 42, 53,
+ 47, 47,
+ 32, 20,
+ 19,
+ 11, 16,
+ 9, 10,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 4, 4,
+ 12, 3, 0,
+ 7964, 24,
+ },
+ {
+ "en",
+ locale_compact_arr_32,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 62,
+ 1, 54,
+ 0, 48,
+ 0, 21,
+ 20,
+ 56, 57,
+ 58, 59,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 4, 3, 0,
+ 8014, 23,
+ },
+ {
+ "en-001",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 8060, 23,
+ },
+ {
+ "en-150",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 8106, 23,
+ },
+ {
+ "en-AE",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 62,
+ 1, 54,
+ 0, 48,
+ 0, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 8152, 23,
+ },
+ {
+ "en-AG",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 8198, 23,
+ },
+ {
+ "en-AI",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 8244, 23,
+ },
+ {
+ "en-AS",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 62,
+ 1, 54,
+ 0, 48,
+ 0, 21,
+ 20,
+ 56, 57,
+ 58, 59,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 8290, 23,
+ },
+ {
+ "en-AT",
+ locale_compact_arr_33,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 18, 19 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 8336, 23,
+ },
+ {
+ "en-AU",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 64,
+ 1, 54,
+ 48, 48,
+ 9, 22,
+ 21,
+ 11, 16,
+ 9, 24,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 8382, 5,
+ },
+ {
+ "en-BB",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 8393, 24,
+ },
+ {
+ "en-BE",
+ locale_compact_arr_33,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 68, 4,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 8441, 23,
+ },
+ {
+ "en-BI",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 62,
+ 1, 54,
+ 0, 48,
+ 0, 21,
+ 20,
+ 56, 57,
+ 58, 59,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 8487, 24,
+ },
+ {
+ "en-BM",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 8536, 24,
+ },
+ {
+ "en-BS",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 8584, 24,
+ },
+ {
+ "en-BW",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 68, 4,
+ 5, 83,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 8632, 24,
+ },
+ {
+ "en-BZ",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 68, 84,
+ 5, 83,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 8682, 24,
+ },
+ {
+ "en-CA",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 62,
+ 1, 54,
+ 0, 48,
+ 33, 21,
+ 22,
+ 0, 57,
+ 58, 59,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 8730, 23,
+ },
+ {
+ "en-CC",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 8776, 23,
+ },
+ {
+ "en-CH",
+ locale_compact_arr_33,
+ { 0, 4, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 25, 2, 25, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 29, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 8822, 23,
+ },
+ {
+ "en-CK",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 8868, 23,
+ },
+ {
+ "en-CM",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 8914, 23,
+ },
+ {
+ "en-CX",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 8960, 23,
+ },
+ {
+ "en-CY",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 9006, 23,
+ },
+ {
+ "en-CZ",
+ locale_compact_arr_33,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 9052, 23,
+ },
+ {
+ "en-DE",
+ locale_compact_arr_33,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 18, 19 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 9098, 23,
+ },
+ {
+ "en-DG",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 9144, 23,
+ },
+ {
+ "en-DK",
+ locale_compact_arr_33,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 18, 19 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 35, 36,
+ 37, 38,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 9190, 24,
+ },
+ {
+ "en-DM",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 9238, 23,
+ },
+ {
+ "en-Dsrt",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 61, 65,
+ 43, 55,
+ 49, 49,
+ 34, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 9284, 23,
+ },
+ {
+ "en-EE",
+ locale_compact_arr_33,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 9330, 23,
+ },
+ {
+ "en-ER",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 9376, 24,
+ },
+ {
+ "en-ES",
+ locale_compact_arr_33,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 9424, 23,
+ },
+ {
+ "en-FI",
+ locale_compact_arr_33,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 18, 19 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 47, 48,
+ 49, 50,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 9470, 23,
+ },
+ {
+ "en-FJ",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 9516, 24,
+ },
+ {
+ "en-FK",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 9564, 24,
+ },
+ {
+ "en-FM",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 9612, 23,
+ },
+ {
+ "en-FR",
+ locale_compact_arr_33,
+ { 1, 5, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 9658, 23,
+ },
+ {
+ "en-GB",
+ locale_compact_arr_34,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 9704, 23,
+ },
+ {
+ "en-GD",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 9750, 23,
+ },
+ {
+ "en-GE",
+ locale_compact_arr_33,
+ { 1, 5, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 9796, 24,
+ },
+ {
+ "en-GG",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 9845, 23,
+ },
+ {
+ "en-GH",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 9891, 24,
+ },
+ {
+ "en-GI",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 9939, 24,
+ },
+ {
+ "en-GM",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 9987, 24,
+ },
+ {
+ "en-GS",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 10036, 23,
+ },
+ {
+ "en-GU",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 62,
+ 1, 54,
+ 0, 48,
+ 0, 21,
+ 20,
+ 56, 57,
+ 58, 59,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 10082, 23,
+ },
+ {
+ "en-GY",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 10128, 24,
+ },
+ {
+ "en-HK",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 7, 16,
+ 9, 24,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 10177, 23,
+ },
+ {
+ "en-HU",
+ locale_compact_arr_33,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 10223, 23,
+ },
+ {
+ "en-ID",
+ locale_compact_arr_33,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 35, 36,
+ 37, 38,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 10269, 24,
+ },
+ {
+ "en-IE",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 10317, 23,
+ },
+ {
+ "en-IL",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 12, 13,
+ 14, 15,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 10363, 23,
+ },
+ {
+ "en-IM",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 10409, 23,
+ },
+ {
+ "en-IN",
+ locale_compact_arr_35,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 68, 16,
+ 9, 24,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 3, 3, 2,
+ 10455, 23,
+ },
+ {
+ "en-IO",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 10501, 23,
+ },
+ {
+ "en-IT",
+ locale_compact_arr_33,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 10547, 23,
+ },
+ {
+ "en-JE",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 10593, 23,
+ },
+ {
+ "en-JM",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 10639, 24,
+ },
+ {
+ "en-JP",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 62,
+ 1, 54,
+ 0, 48,
+ 0, 21,
+ 20,
+ 85, 57,
+ 58, 59,
+ 12, 13,
+ 14, 15,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 10687, 23,
+ },
+ {
+ "en-KE",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 10733, 24,
+ },
+ {
+ "en-KI",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 10781, 23,
+ },
+ {
+ "en-KN",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 10827, 23,
+ },
+ {
+ "en-KY",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 10873, 24,
+ },
+ {
+ "en-LC",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 10922, 23,
+ },
+ {
+ "en-LR",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 10968, 24,
+ },
+ {
+ "en-LS",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 11016, 24,
+ },
+ {
+ "en-LT",
+ locale_compact_arr_33,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 11064, 23,
+ },
+ {
+ "en-LV",
+ locale_compact_arr_33,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 11110, 23,
+ },
+ {
+ "en-MG",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 11156, 24,
+ },
+ {
+ "en-MH",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 62,
+ 1, 54,
+ 0, 48,
+ 0, 21,
+ 20,
+ 56, 57,
+ 58, 59,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 11206, 23,
+ },
+ {
+ "en-MO",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 11252, 24,
+ },
+ {
+ "en-MP",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 62,
+ 1, 54,
+ 0, 48,
+ 0, 21,
+ 20,
+ 56, 57,
+ 58, 59,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 11301, 23,
+ },
+ {
+ "en-MS",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 11347, 23,
+ },
+ {
+ "en-MT",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 4,
+ 5, 24,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 11393, 23,
+ },
+ {
+ "en-MU",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 11439, 24,
+ },
+ {
+ "en-MV",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 86, 21,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 11488, 24,
+ },
+ {
+ "en-MW",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 11538, 24,
+ },
+ {
+ "en-MY",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 11588, 24,
+ },
+ {
+ "en-NA",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 11636, 24,
+ },
+ {
+ "en-NF",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 11684, 23,
+ },
+ {
+ "en-NG",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 11730, 24,
+ },
+ {
+ "en-NL",
+ locale_compact_arr_33,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 21, 2, 26, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 11778, 23,
+ },
+ {
+ "en-NO",
+ locale_compact_arr_33,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 18, 19 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 11824, 24,
+ },
+ {
+ "en-NR",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 11872, 23,
+ },
+ {
+ "en-NU",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 11918, 23,
+ },
+ {
+ "en-NZ",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 11964, 23,
+ },
+ {
+ "en-PG",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 12010, 24,
+ },
+ {
+ "en-PH",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 62,
+ 1, 54,
+ 0, 48,
+ 0, 21,
+ 20,
+ 56, 57,
+ 58, 59,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 12059, 23,
+ },
+ {
+ "en-PK",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 84,
+ 9, 24,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 12105, 24,
+ },
+ {
+ "en-PL",
+ locale_compact_arr_33,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 12153, 23,
+ },
+ {
+ "en-PN",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 12199, 23,
+ },
+ {
+ "en-PR",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 62,
+ 1, 54,
+ 0, 48,
+ 0, 21,
+ 20,
+ 56, 57,
+ 58, 59,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 12245, 23,
+ },
+ {
+ "en-PT",
+ locale_compact_arr_33,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 12291, 23,
+ },
+ {
+ "en-PW",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 12337, 23,
+ },
+ {
+ "en-RO",
+ locale_compact_arr_33,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 12383, 23,
+ },
+ {
+ "en-RW",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 12429, 24,
+ },
+ {
+ "en-SB",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 12479, 24,
+ },
+ {
+ "en-SC",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 12527, 24,
+ },
+ {
+ "en-SD",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 12576, 23,
+ },
+ {
+ "en-SE",
+ locale_compact_arr_33,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 18, 19 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 0, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 12622, 24,
+ },
+ {
+ "en-SG",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 11, 16,
+ 9, 24,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 12670, 24,
+ },
+ {
+ "en-SH",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 12718, 24,
+ },
+ {
+ "en-Shaw",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 62, 66,
+ 44, 56,
+ 50, 50,
+ 35, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 12767, 23,
+ },
+ {
+ "en-SI",
+ locale_compact_arr_33,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 12813, 23,
+ },
+ {
+ "en-SK",
+ locale_compact_arr_33,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 12859, 23,
+ },
+ {
+ "en-SL",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 12905, 24,
+ },
+ {
+ "en-SS",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 12955, 24,
+ },
+ {
+ "en-SX",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 13003, 24,
+ },
+ {
+ "en-SZ",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 13052, 24,
+ },
+ {
+ "en-TC",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 13102, 23,
+ },
+ {
+ "en-TK",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 13148, 23,
+ },
+ {
+ "en-TO",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 13194, 24,
+ },
+ {
+ "en-TT",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 13244, 24,
+ },
+ {
+ "en-TV",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 13292, 23,
+ },
+ {
+ "en-TZ",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 13338, 24,
+ },
+ {
+ "en-UA",
+ locale_compact_arr_33,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 13386, 23,
+ },
+ {
+ "en-UG",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 13432, 24,
+ },
+ {
+ "en-UM",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 62,
+ 1, 54,
+ 0, 48,
+ 0, 21,
+ 20,
+ 56, 57,
+ 58, 59,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 13480, 23,
+ },
+ {
+ "en-VC",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 13526, 23,
+ },
+ {
+ "en-VG",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 13572, 23,
+ },
+ {
+ "en-VI",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 62,
+ 1, 54,
+ 0, 48,
+ 0, 21,
+ 20,
+ 56, 57,
+ 58, 59,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 13618, 23,
+ },
+ {
+ "en-VU",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 13664, 24,
+ },
+ {
+ "en-WS",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 13714, 24,
+ },
+ {
+ "en-ZA",
+ locale_compact_arr_33,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 85, 4,
+ 5, 83,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 13763, 24,
+ },
+ {
+ "en-ZM",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 15, 16,
+ 9, 24,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 13811, 24,
+ },
+ {
+ "en-ZW",
+ locale_compact_arr_33,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 60, 63,
+ 1, 54,
+ 0, 48,
+ 9, 21,
+ 20,
+ 7, 87,
+ 5, 83,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 13861, 23,
+ },
+ {
+ "eo",
+ locale_compact_arr_36,
+ { 1, 5, 0, 0, 0, 0, 0 },
+ { 0, 1, 27, 28, 27, 29, 4, 5 },
+ 63, 67,
+ 1, 57,
+ 51, 51,
+ 36, 0,
+ 0,
+ 88, 89,
+ 90, 91,
+ 4, 5,
+ 6, 7,
+ 0, 1,
+ 0, 0,
+ 12, 3, 0,
+ 13907, 2,
+ },
+ {
+ "es",
+ locale_compact_arr_37,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 18, 19 },
+ 64, 68,
+ 45, 58,
+ 52, 52,
+ 17, 23,
+ 23,
+ 11, 16,
+ 92, 93,
+ 12, 13,
+ 14, 31,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 13911, 8,
+ },
+ {
+ "es-419",
+ locale_compact_arr_38,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 7, 4, 5 },
+ 64, 68,
+ 45, 58,
+ 53, 53,
+ 33, 23,
+ 23,
+ 11, 16,
+ 92, 93,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 13927, 4,
+ },
+ {
+ "es-AR",
+ locale_compact_arr_38,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 26, 4, 5 },
+ 64, 68,
+ 45, 58,
+ 53, 53,
+ 17, 24,
+ 24,
+ 11, 16,
+ 92, 93,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 13935, 6,
+ },
+ {
+ "es-BO",
+ locale_compact_arr_38,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 7, 4, 5 },
+ 64, 68,
+ 45, 58,
+ 53, 53,
+ 17, 23,
+ 23,
+ 11, 94,
+ 92, 93,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 13947, 5,
+ },
+ {
+ "es-BR",
+ locale_compact_arr_38,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 7, 4, 5 },
+ 64, 68,
+ 45, 58,
+ 53, 53,
+ 33, 23,
+ 23,
+ 11, 16,
+ 92, 93,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 13958, 5,
+ },
+ {
+ "es-BZ",
+ locale_compact_arr_38,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 7, 4, 5 },
+ 64, 68,
+ 45, 58,
+ 53, 53,
+ 33, 23,
+ 23,
+ 11, 16,
+ 92, 93,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 13968, 5,
+ },
+ {
+ "es-CL",
+ locale_compact_arr_38,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 25, 6, 25, 4, 5 },
+ 64, 68,
+ 45, 58,
+ 53, 53,
+ 17, 23,
+ 23,
+ 95, 21,
+ 92, 93,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 13978, 6,
+ },
+ {
+ "es-CO",
+ locale_compact_arr_38,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 64, 68,
+ 45, 58,
+ 54, 53,
+ 17, 25,
+ 25,
+ 96, 97,
+ 92, 93,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 13990, 6,
+ },
+ {
+ "es-CR",
+ locale_compact_arr_38,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 7, 4, 5 },
+ 64, 68,
+ 45, 58,
+ 53, 53,
+ 17, 23,
+ 23,
+ 11, 16,
+ 92, 93,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 14002, 5,
+ },
+ {
+ "es-CU",
+ locale_compact_arr_38,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 7, 4, 5 },
+ 64, 68,
+ 45, 58,
+ 53, 53,
+ 33, 23,
+ 23,
+ 11, 16,
+ 92, 93,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 14014, 6,
+ },
+ {
+ "es-DO",
+ locale_compact_arr_38,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 64, 68,
+ 45, 58,
+ 53, 53,
+ 17, 23,
+ 26,
+ 11, 16,
+ 92, 93,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 14027, 6,
+ },
+ {
+ "es-EA",
+ locale_compact_arr_37,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 18, 19 },
+ 64, 68,
+ 45, 58,
+ 52, 52,
+ 17, 23,
+ 23,
+ 11, 16,
+ 92, 93,
+ 12, 13,
+ 14, 31,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 14040, 8,
+ },
+ {
+ "es-EC",
+ locale_compact_arr_38,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 25, 6, 25, 4, 5 },
+ 64, 68,
+ 45, 58,
+ 53, 53,
+ 17, 23,
+ 23,
+ 11, 16,
+ 92, 93,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 14056, 5,
+ },
+ {
+ "es-GQ",
+ locale_compact_arr_37,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 7, 18, 19 },
+ 64, 68,
+ 45, 58,
+ 52, 52,
+ 17, 23,
+ 23,
+ 11, 16,
+ 92, 93,
+ 12, 13,
+ 14, 31,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 14066, 9,
+ },
+ {
+ "es-GT",
+ locale_compact_arr_38,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 7, 4, 5 },
+ 64, 68,
+ 45, 58,
+ 53, 53,
+ 17, 23,
+ 23,
+ 96, 97,
+ 92, 93,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 14084, 5,
+ },
+ {
+ "es-HN",
+ locale_compact_arr_38,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 7, 4, 5 },
+ 64, 68,
+ 45, 58,
+ 53, 53,
+ 17, 23,
+ 23,
+ 11, 16,
+ 98, 99,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 14095, 5,
+ },
+ {
+ "es-IC",
+ locale_compact_arr_37,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 18, 19 },
+ 64, 68,
+ 45, 58,
+ 52, 52,
+ 17, 23,
+ 23,
+ 11, 16,
+ 92, 93,
+ 12, 13,
+ 14, 31,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 14107, 8,
+ },
+ {
+ "es-MX",
+ locale_compact_arr_39,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 7, 4, 5 },
+ 64, 69,
+ 45, 58,
+ 53, 53,
+ 33, 23,
+ 23,
+ 68, 16,
+ 92, 93,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 14123, 7,
+ },
+ {
+ "es-NI",
+ locale_compact_arr_38,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 7, 4, 5 },
+ 64, 68,
+ 45, 58,
+ 53, 53,
+ 17, 23,
+ 23,
+ 11, 16,
+ 92, 93,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 14140, 5,
+ },
+ {
+ "es-PA",
+ locale_compact_arr_38,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 7, 4, 5 },
+ 64, 68,
+ 45, 58,
+ 53, 53,
+ 17, 26,
+ 27,
+ 100, 101,
+ 92, 93,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 14151, 5,
+ },
+ {
+ "es-PE",
+ locale_compact_arr_38,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 65, 70,
+ 45, 58,
+ 53, 53,
+ 17, 23,
+ 23,
+ 96, 16,
+ 92, 93,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 14163, 5,
+ },
+ {
+ "es-PH",
+ locale_compact_arr_37,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 18, 19 },
+ 64, 68,
+ 45, 58,
+ 52, 52,
+ 17, 23,
+ 23,
+ 11, 16,
+ 92, 93,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 14175, 9,
+ },
+ {
+ "es-PR",
+ locale_compact_arr_38,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 7, 4, 5 },
+ 64, 68,
+ 45, 58,
+ 53, 53,
+ 17, 23,
+ 23,
+ 100, 101,
+ 92, 93,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 14193, 5,
+ },
+ {
+ "es-PY",
+ locale_compact_arr_38,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 21, 2, 21, 4, 5 },
+ 64, 71,
+ 45, 58,
+ 53, 53,
+ 17, 23,
+ 23,
+ 11, 16,
+ 92, 93,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 14203, 5,
+ },
+ {
+ "es-SV",
+ locale_compact_arr_38,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 7, 4, 5 },
+ 64, 68,
+ 45, 58,
+ 53, 53,
+ 17, 23,
+ 23,
+ 11, 16,
+ 92, 93,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 14215, 5,
+ },
+ {
+ "es-US",
+ locale_compact_arr_40,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 7, 4, 5 },
+ 64, 68,
+ 45, 58,
+ 53, 53,
+ 33, 23,
+ 23,
+ 7, 16,
+ 92, 93,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 14225, 6,
+ },
+ {
+ "es-UY",
+ locale_compact_arr_38,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 26, 4, 5 },
+ 65, 70,
+ 45, 58,
+ 53, 53,
+ 17, 23,
+ 23,
+ 11, 16,
+ 92, 93,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 14237, 7,
+ },
+ {
+ "es-VE",
+ locale_compact_arr_38,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 25, 6, 25, 4, 5 },
+ 64, 71,
+ 45, 58,
+ 53, 53,
+ 17, 23,
+ 23,
+ 11, 16,
+ 92, 93,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 14253, 6,
+ },
+ {
+ "et",
+ locale_compact_arr_41,
+ { 1, 1, 0, 5, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 4, 5 },
+ 66, 72,
+ 46, 59,
+ 55, 54,
+ 0, 27,
+ 28,
+ 27, 69,
+ 62, 71,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 14268, 24,
+ },
+ {
+ "eu",
+ locale_compact_arr_42,
+ { 1, 3, 0, 5, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 22, 30 },
+ 67, 73,
+ 47, 60,
+ 56, 55,
+ 0, 28,
+ 29,
+ 102, 103,
+ 104, 105,
+ 4, 5,
+ 33, 34,
+ 5, 5,
+ 5, 5,
+ 12, 3, 0,
+ 14317, 24,
+ },
+ {
+ "ewo",
+ locale_compact_arr_0,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 68, 74,
+ 48, 61,
+ 57, 56,
+ 37, 0,
+ 0,
+ 7, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 14365, 23,
+ },
+ {
+ "fa",
+ locale_compact_arr_43,
+ { 2, 2, 1, 6, 3, 0, 8 },
+ { 0, 1, 31, 32, 33, 34, 4, 5 },
+ 69, 75,
+ 49, 62,
+ 58, 57,
+ 38, 29,
+ 30,
+ 106, 16,
+ 9, 10,
+ 12, 13,
+ 51, 31,
+ 6, 6,
+ 7, 7,
+ 12, 3, 0,
+ 14411, 25,
+ },
+ {
+ "fa-AF",
+ locale_compact_arr_43,
+ { 2, 2, 1, 6, 3, 0, 8 },
+ { 0, 1, 2, 3, 2, 34, 4, 5 },
+ 70, 76,
+ 50, 62,
+ 58, 57,
+ 38, 30,
+ 30,
+ 106, 16,
+ 9, 10,
+ 12, 13,
+ 51, 31,
+ 6, 6,
+ 7, 7,
+ 12, 3, 0,
+ 14465, 25,
+ },
+ {
+ "ff",
+ locale_compact_arr_0,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 71, 77,
+ 51, 63,
+ 59, 58,
+ 39, 0,
+ 0,
+ 7, 8,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 14519, 23,
+ },
+ {
+ "ff-Adlm",
+ locale_compact_arr_44,
+ { 0, 6, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 72, 78,
+ 52, 64,
+ 60, 59,
+ 40, 0,
+ 0,
+ 20, 107,
+ 108, 109,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 14565, 27,
+ },
+ {
+ "ff-Adlm-BF",
+ locale_compact_arr_44,
+ { 0, 6, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 72, 78,
+ 52, 64,
+ 60, 59,
+ 40, 0,
+ 0,
+ 20, 107,
+ 108, 109,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 14620, 26,
+ },
+ {
+ "ff-Adlm-CM",
+ locale_compact_arr_44,
+ { 0, 6, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 72, 78,
+ 52, 64,
+ 60, 59,
+ 40, 0,
+ 0,
+ 20, 107,
+ 108, 109,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 14672, 26,
+ },
+ {
+ "ff-Adlm-GH",
+ locale_compact_arr_44,
+ { 0, 6, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 72, 78,
+ 52, 64,
+ 60, 59,
+ 40, 0,
+ 0,
+ 20, 107,
+ 108, 109,
+ 8, 9,
+ 10, 11,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 14724, 27,
+ },
+ {
+ "ff-Adlm-GM",
+ locale_compact_arr_44,
+ { 0, 6, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 72, 78,
+ 52, 64,
+ 60, 59,
+ 40, 0,
+ 0,
+ 20, 107,
+ 108, 109,
+ 8, 9,
+ 10, 11,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 14778, 27,
+ },
+ {
+ "ff-Adlm-GW",
+ locale_compact_arr_44,
+ { 0, 6, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 72, 78,
+ 52, 64,
+ 60, 59,
+ 40, 0,
+ 0,
+ 20, 107,
+ 108, 109,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 14833, 26,
+ },
+ {
+ "ff-Adlm-LR",
+ locale_compact_arr_44,
+ { 0, 6, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 72, 78,
+ 52, 64,
+ 60, 59,
+ 40, 0,
+ 0,
+ 20, 107,
+ 108, 109,
+ 8, 9,
+ 10, 11,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 14885, 27,
+ },
+ {
+ "ff-Adlm-MR",
+ locale_compact_arr_44,
+ { 0, 6, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 72, 78,
+ 52, 64,
+ 60, 59,
+ 40, 0,
+ 0,
+ 20, 107,
+ 108, 109,
+ 8, 9,
+ 10, 11,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 14939, 27,
+ },
+ {
+ "ff-Adlm-NE",
+ locale_compact_arr_44,
+ { 0, 6, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 72, 78,
+ 52, 64,
+ 60, 59,
+ 40, 0,
+ 0,
+ 20, 107,
+ 108, 109,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 14994, 26,
+ },
+ {
+ "ff-Adlm-NG",
+ locale_compact_arr_44,
+ { 0, 6, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 72, 78,
+ 52, 64,
+ 60, 59,
+ 40, 0,
+ 0,
+ 20, 107,
+ 108, 109,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 15046, 26,
+ },
+ {
+ "ff-Adlm-SL",
+ locale_compact_arr_44,
+ { 0, 6, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 72, 78,
+ 52, 64,
+ 60, 59,
+ 40, 0,
+ 0,
+ 20, 107,
+ 108, 109,
+ 8, 9,
+ 10, 11,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 15098, 27,
+ },
+ {
+ "ff-Adlm-SN",
+ locale_compact_arr_44,
+ { 0, 6, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 72, 78,
+ 52, 64,
+ 60, 59,
+ 40, 0,
+ 0,
+ 20, 107,
+ 108, 109,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 15154, 26,
+ },
+ {
+ "ff-Latn",
+ locale_compact_arr_0,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 71, 77,
+ 51, 63,
+ 59, 58,
+ 39, 0,
+ 0,
+ 7, 8,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 15206, 23,
+ },
+ {
+ "ff-Latn-BF",
+ locale_compact_arr_0,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 71, 77,
+ 51, 63,
+ 59, 58,
+ 39, 0,
+ 0,
+ 7, 8,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 15252, 23,
+ },
+ {
+ "ff-Latn-CM",
+ locale_compact_arr_0,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 71, 77,
+ 51, 63,
+ 59, 58,
+ 39, 0,
+ 0,
+ 7, 8,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 15298, 23,
+ },
+ {
+ "ff-Latn-GH",
+ locale_compact_arr_0,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 71, 77,
+ 51, 63,
+ 59, 58,
+ 39, 0,
+ 0,
+ 7, 8,
+ 9, 10,
+ 0, 1,
+ 2, 3,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 15344, 24,
+ },
+ {
+ "ff-Latn-GM",
+ locale_compact_arr_0,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 71, 77,
+ 51, 63,
+ 59, 58,
+ 39, 0,
+ 0,
+ 7, 8,
+ 9, 10,
+ 0, 1,
+ 2, 3,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 15392, 24,
+ },
+ {
+ "ff-Latn-GN",
+ locale_compact_arr_0,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 71, 77,
+ 51, 63,
+ 59, 58,
+ 39, 0,
+ 0,
+ 7, 8,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 15441, 24,
+ },
+ {
+ "ff-Latn-GW",
+ locale_compact_arr_0,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 71, 77,
+ 51, 63,
+ 59, 58,
+ 39, 0,
+ 0,
+ 7, 8,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 15490, 23,
+ },
+ {
+ "ff-Latn-LR",
+ locale_compact_arr_0,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 71, 77,
+ 51, 63,
+ 59, 58,
+ 39, 0,
+ 0,
+ 7, 8,
+ 9, 10,
+ 0, 1,
+ 2, 3,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 15536, 24,
+ },
+ {
+ "ff-Latn-MR",
+ locale_compact_arr_0,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 71, 77,
+ 51, 63,
+ 59, 58,
+ 39, 0,
+ 0,
+ 7, 8,
+ 9, 10,
+ 0, 1,
+ 2, 3,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 15584, 24,
+ },
+ {
+ "ff-Latn-NE",
+ locale_compact_arr_0,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 71, 77,
+ 51, 63,
+ 59, 58,
+ 39, 0,
+ 0,
+ 7, 8,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 15633, 23,
+ },
+ {
+ "ff-Latn-NG",
+ locale_compact_arr_0,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 71, 77,
+ 51, 63,
+ 59, 58,
+ 39, 0,
+ 0,
+ 7, 8,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 15679, 24,
+ },
+ {
+ "ff-Latn-SL",
+ locale_compact_arr_0,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 71, 77,
+ 51, 63,
+ 59, 58,
+ 39, 0,
+ 0,
+ 7, 8,
+ 9, 10,
+ 0, 1,
+ 2, 3,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 15727, 24,
+ },
+ {
+ "fi",
+ locale_compact_arr_45,
+ { 1, 1, 0, 5, 0, 0, 9 },
+ { 0, 1, 16, 17, 16, 17, 18, 19 },
+ 73, 79,
+ 53, 65,
+ 61, 60,
+ 41, 31,
+ 31,
+ 76, 76,
+ 62, 110,
+ 47, 48,
+ 49, 50,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 15777, 8,
+ },
+ {
+ "fil",
+ locale_compact_arr_46,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 74, 80,
+ 54, 66,
+ 62, 61,
+ 0, 32,
+ 32,
+ 56, 57,
+ 58, 59,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 15795, 24,
+ },
+ {
+ "fo",
+ locale_compact_arr_47,
+ { 1, 3, 0, 5, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 18, 19 },
+ 75, 81,
+ 1, 67,
+ 63, 62,
+ 0, 0,
+ 0,
+ 27, 29,
+ 62, 71,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 15843, 23,
+ },
+ {
+ "fo-DK",
+ locale_compact_arr_47,
+ { 1, 3, 0, 5, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 18, 19 },
+ 75, 81,
+ 1, 67,
+ 63, 62,
+ 0, 0,
+ 0,
+ 27, 29,
+ 62, 71,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 15889, 23,
+ },
+ {
+ "fr",
+ locale_compact_arr_48,
+ { 1, 5, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 18, 19 },
+ 76, 82,
+ 1, 68,
+ 53, 63,
+ 0, 33,
+ 33,
+ 15, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 1,
+ 1, 1,
+ 4, 3, 0,
+ 15935, 42,
+ },
+ {
+ "fr-BE",
+ locale_compact_arr_49,
+ { 1, 5, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 18, 19 },
+ 76, 82,
+ 1, 68,
+ 53, 63,
+ 0, 33,
+ 33,
+ 96, 16,
+ 9, 10,
+ 4, 5,
+ 6, 52,
+ 0, 1,
+ 1, 1,
+ 12, 3, 0,
+ 16019, 42,
+ },
+ {
+ "fr-BF",
+ locale_compact_arr_49,
+ { 1, 5, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 18, 19 },
+ 76, 82,
+ 1, 68,
+ 53, 63,
+ 0, 33,
+ 33,
+ 15, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 1,
+ 1, 1,
+ 12, 3, 0,
+ 16103, 42,
+ },
+ {
+ "fr-BI",
+ locale_compact_arr_49,
+ { 1, 5, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 18, 19 },
+ 76, 82,
+ 1, 68,
+ 53, 63,
+ 0, 33,
+ 33,
+ 15, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 1,
+ 1, 1,
+ 12, 3, 0,
+ 16187, 43,
+ },
+ {
+ "fr-BJ",
+ locale_compact_arr_49,
+ { 1, 5, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 18, 19 },
+ 76, 82,
+ 1, 68,
+ 53, 63,
+ 0, 33,
+ 33,
+ 15, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 1,
+ 1, 1,
+ 12, 3, 0,
+ 16274, 42,
+ },
+ {
+ "fr-BL",
+ locale_compact_arr_49,
+ { 1, 5, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 18, 19 },
+ 76, 82,
+ 1, 68,
+ 53, 63,
+ 0, 33,
+ 33,
+ 15, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 1,
+ 1, 1,
+ 12, 3, 0,
+ 16358, 42,
+ },
+ {
+ "fr-CA",
+ locale_compact_arr_50,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 18, 19 },
+ 76, 83,
+ 1, 68,
+ 53, 63,
+ 33, 33,
+ 34,
+ 0, 16,
+ 9, 10,
+ 53, 54,
+ 55, 56,
+ 0, 1,
+ 1, 1,
+ 12, 3, 0,
+ 16442, 21,
+ },
+ {
+ "fr-CD",
+ locale_compact_arr_49,
+ { 1, 5, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 18, 19 },
+ 76, 82,
+ 1, 68,
+ 53, 63,
+ 0, 33,
+ 33,
+ 15, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 1,
+ 1, 1,
+ 12, 3, 0,
+ 16489, 43,
+ },
+ {
+ "fr-CF",
+ locale_compact_arr_49,
+ { 1, 5, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 18, 19 },
+ 76, 82,
+ 1, 68,
+ 53, 63,
+ 0, 33,
+ 33,
+ 15, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 1,
+ 1, 1,
+ 12, 3, 0,
+ 16575, 42,
+ },
+ {
+ "fr-CG",
+ locale_compact_arr_49,
+ { 1, 5, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 18, 19 },
+ 76, 82,
+ 1, 68,
+ 53, 63,
+ 0, 33,
+ 33,
+ 15, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 1,
+ 1, 1,
+ 12, 3, 0,
+ 16659, 42,
+ },
+ {
+ "fr-CH",
+ locale_compact_arr_49,
+ { 1, 4, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 4, 5 },
+ 76, 82,
+ 1, 68,
+ 53, 63,
+ 0, 33,
+ 35,
+ 27, 16,
+ 9, 24,
+ 4, 5,
+ 6, 57,
+ 0, 1,
+ 1, 1,
+ 12, 3, 0,
+ 16743, 42,
+ },
+ {
+ "fr-CI",
+ locale_compact_arr_49,
+ { 1, 5, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 18, 19 },
+ 76, 82,
+ 1, 68,
+ 53, 63,
+ 0, 33,
+ 33,
+ 15, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 1,
+ 1, 1,
+ 12, 3, 0,
+ 16827, 42,
+ },
+ {
+ "fr-CM",
+ locale_compact_arr_49,
+ { 1, 5, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 18, 19 },
+ 76, 82,
+ 1, 68,
+ 53, 63,
+ 42, 33,
+ 33,
+ 15, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 1,
+ 1, 1,
+ 12, 3, 0,
+ 16911, 42,
+ },
+ {
+ "fr-DJ",
+ locale_compact_arr_49,
+ { 1, 5, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 18, 19 },
+ 76, 82,
+ 1, 68,
+ 53, 63,
+ 0, 33,
+ 33,
+ 15, 16,
+ 9, 10,
+ 0, 1,
+ 2, 3,
+ 0, 1,
+ 1, 1,
+ 12, 3, 0,
+ 16995, 43,
+ },
+ {
+ "fr-DZ",
+ locale_compact_arr_49,
+ { 1, 5, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 18, 19 },
+ 76, 82,
+ 1, 68,
+ 53, 63,
+ 0, 33,
+ 33,
+ 15, 16,
+ 9, 10,
+ 0, 1,
+ 2, 3,
+ 0, 1,
+ 1, 1,
+ 12, 3, 0,
+ 17082, 43,
+ },
+ {
+ "fr-GA",
+ locale_compact_arr_49,
+ { 1, 5, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 18, 19 },
+ 76, 82,
+ 1, 68,
+ 53, 63,
+ 0, 33,
+ 33,
+ 15, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 1,
+ 1, 1,
+ 12, 3, 0,
+ 17169, 42,
+ },
+ {
+ "fr-GF",
+ locale_compact_arr_49,
+ { 1, 5, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 18, 19 },
+ 76, 82,
+ 1, 68,
+ 53, 63,
+ 0, 33,
+ 33,
+ 15, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 1,
+ 1, 1,
+ 12, 3, 0,
+ 17253, 42,
+ },
+ {
+ "fr-GN",
+ locale_compact_arr_49,
+ { 1, 5, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 18, 19 },
+ 76, 82,
+ 1, 68,
+ 53, 63,
+ 0, 33,
+ 33,
+ 15, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 1,
+ 1, 1,
+ 12, 3, 0,
+ 17337, 43,
+ },
+ {
+ "fr-GP",
+ locale_compact_arr_49,
+ { 1, 5, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 18, 19 },
+ 76, 82,
+ 1, 68,
+ 53, 63,
+ 0, 33,
+ 33,
+ 15, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 1,
+ 1, 1,
+ 12, 3, 0,
+ 17424, 42,
+ },
+ {
+ "fr-GQ",
+ locale_compact_arr_49,
+ { 1, 5, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 18, 19 },
+ 76, 82,
+ 1, 68,
+ 53, 63,
+ 0, 33,
+ 33,
+ 15, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 1,
+ 1, 1,
+ 12, 3, 0,
+ 17508, 42,
+ },
+ {
+ "fr-HT",
+ locale_compact_arr_49,
+ { 1, 5, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 18, 19 },
+ 76, 82,
+ 1, 68,
+ 53, 63,
+ 0, 34,
+ 33,
+ 15, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 1,
+ 1, 1,
+ 12, 3, 0,
+ 17592, 43,
+ },
+ {
+ "fr-KM",
+ locale_compact_arr_49,
+ { 1, 5, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 18, 19 },
+ 76, 82,
+ 1, 68,
+ 53, 63,
+ 0, 33,
+ 33,
+ 15, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 1,
+ 1, 1,
+ 12, 3, 0,
+ 17679, 43,
+ },
+ {
+ "fr-LU",
+ locale_compact_arr_49,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 18, 19 },
+ 76, 82,
+ 1, 68,
+ 53, 63,
+ 0, 33,
+ 33,
+ 15, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 1,
+ 1, 1,
+ 12, 3, 0,
+ 17767, 42,
+ },
+ {
+ "fr-MA",
+ locale_compact_arr_49,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 18, 19 },
+ 76, 84,
+ 1, 68,
+ 53, 63,
+ 0, 33,
+ 33,
+ 15, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 1,
+ 1, 1,
+ 12, 3, 0,
+ 17852, 42,
+ },
+ {
+ "fr-MC",
+ locale_compact_arr_49,
+ { 1, 5, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 18, 19 },
+ 76, 82,
+ 1, 68,
+ 53, 63,
+ 0, 33,
+ 33,
+ 15, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 1,
+ 1, 1,
+ 12, 3, 0,
+ 17936, 42,
+ },
+ {
+ "fr-MF",
+ locale_compact_arr_49,
+ { 1, 5, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 18, 19 },
+ 76, 82,
+ 1, 68,
+ 53, 63,
+ 0, 33,
+ 33,
+ 15, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 1,
+ 1, 1,
+ 12, 3, 0,
+ 18020, 42,
+ },
+ {
+ "fr-MG",
+ locale_compact_arr_49,
+ { 1, 5, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 18, 19 },
+ 76, 82,
+ 1, 68,
+ 53, 63,
+ 0, 33,
+ 33,
+ 15, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 1,
+ 1, 1,
+ 12, 3, 0,
+ 18104, 43,
+ },
+ {
+ "fr-ML",
+ locale_compact_arr_49,
+ { 1, 5, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 18, 19 },
+ 76, 82,
+ 1, 68,
+ 53, 63,
+ 0, 33,
+ 33,
+ 15, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 18192, 42,
+ },
+ {
+ "fr-MQ",
+ locale_compact_arr_49,
+ { 1, 5, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 18, 19 },
+ 76, 82,
+ 1, 68,
+ 53, 63,
+ 0, 33,
+ 33,
+ 15, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 1,
+ 1, 1,
+ 12, 3, 0,
+ 18276, 42,
+ },
+ {
+ "fr-MR",
+ locale_compact_arr_49,
+ { 1, 5, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 18, 19 },
+ 76, 82,
+ 1, 68,
+ 53, 63,
+ 0, 33,
+ 33,
+ 15, 16,
+ 9, 10,
+ 0, 1,
+ 2, 3,
+ 0, 1,
+ 1, 1,
+ 12, 3, 0,
+ 18360, 43,
+ },
+ {
+ "fr-MU",
+ locale_compact_arr_49,
+ { 1, 5, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 18, 19 },
+ 76, 82,
+ 1, 68,
+ 53, 63,
+ 0, 33,
+ 33,
+ 15, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 1,
+ 1, 1,
+ 12, 3, 0,
+ 18447, 43,
+ },
+ {
+ "fr-NC",
+ locale_compact_arr_49,
+ { 1, 5, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 18, 19 },
+ 76, 82,
+ 1, 68,
+ 53, 63,
+ 0, 33,
+ 33,
+ 15, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 1,
+ 1, 1,
+ 12, 3, 0,
+ 18534, 42,
+ },
+ {
+ "fr-NE",
+ locale_compact_arr_49,
+ { 1, 5, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 18, 19 },
+ 76, 82,
+ 1, 68,
+ 53, 63,
+ 0, 33,
+ 33,
+ 15, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 1,
+ 1, 1,
+ 12, 3, 0,
+ 18618, 42,
+ },
+ {
+ "fr-PF",
+ locale_compact_arr_49,
+ { 1, 5, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 18, 19 },
+ 76, 82,
+ 1, 68,
+ 53, 63,
+ 0, 33,
+ 33,
+ 15, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 1,
+ 1, 1,
+ 12, 3, 0,
+ 18702, 42,
+ },
+ {
+ "fr-PM",
+ locale_compact_arr_49,
+ { 1, 5, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 18, 19 },
+ 76, 82,
+ 1, 68,
+ 53, 63,
+ 0, 33,
+ 33,
+ 15, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 1,
+ 1, 1,
+ 12, 3, 0,
+ 18786, 42,
+ },
+ {
+ "fr-RE",
+ locale_compact_arr_49,
+ { 1, 5, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 18, 19 },
+ 76, 82,
+ 1, 68,
+ 53, 63,
+ 0, 33,
+ 33,
+ 15, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 1,
+ 1, 1,
+ 12, 3, 0,
+ 18870, 42,
+ },
+ {
+ "fr-RW",
+ locale_compact_arr_49,
+ { 1, 5, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 18, 19 },
+ 76, 82,
+ 1, 68,
+ 53, 63,
+ 0, 33,
+ 33,
+ 15, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 1,
+ 1, 1,
+ 12, 3, 0,
+ 18954, 43,
+ },
+ {
+ "fr-SC",
+ locale_compact_arr_49,
+ { 1, 5, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 18, 19 },
+ 76, 82,
+ 1, 68,
+ 53, 63,
+ 0, 33,
+ 33,
+ 15, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 1,
+ 1, 1,
+ 12, 3, 0,
+ 19042, 43,
+ },
+ {
+ "fr-SN",
+ locale_compact_arr_49,
+ { 1, 5, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 18, 19 },
+ 76, 82,
+ 1, 68,
+ 53, 63,
+ 0, 33,
+ 33,
+ 15, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 1,
+ 1, 1,
+ 12, 3, 0,
+ 19129, 42,
+ },
+ {
+ "fr-SY",
+ locale_compact_arr_49,
+ { 1, 5, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 18, 19 },
+ 76, 82,
+ 1, 68,
+ 53, 63,
+ 0, 33,
+ 33,
+ 15, 16,
+ 9, 10,
+ 0, 1,
+ 2, 3,
+ 0, 1,
+ 1, 1,
+ 12, 3, 0,
+ 19213, 43,
+ },
+ {
+ "fr-TD",
+ locale_compact_arr_49,
+ { 1, 5, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 18, 19 },
+ 76, 82,
+ 1, 68,
+ 53, 63,
+ 0, 33,
+ 33,
+ 15, 16,
+ 9, 10,
+ 0, 1,
+ 2, 3,
+ 0, 1,
+ 1, 1,
+ 12, 3, 0,
+ 19300, 42,
+ },
+ {
+ "fr-TG",
+ locale_compact_arr_49,
+ { 1, 5, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 18, 19 },
+ 76, 82,
+ 1, 68,
+ 53, 63,
+ 0, 33,
+ 33,
+ 15, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 1,
+ 1, 1,
+ 12, 3, 0,
+ 19384, 42,
+ },
+ {
+ "fr-TN",
+ locale_compact_arr_49,
+ { 1, 5, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 18, 19 },
+ 76, 82,
+ 1, 68,
+ 53, 63,
+ 0, 33,
+ 33,
+ 15, 16,
+ 9, 10,
+ 0, 1,
+ 2, 3,
+ 0, 1,
+ 1, 1,
+ 12, 3, 0,
+ 19468, 43,
+ },
+ {
+ "fr-VU",
+ locale_compact_arr_49,
+ { 1, 5, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 18, 19 },
+ 76, 82,
+ 1, 68,
+ 53, 63,
+ 0, 33,
+ 33,
+ 15, 16,
+ 9, 10,
+ 0, 1,
+ 2, 3,
+ 0, 1,
+ 1, 1,
+ 12, 3, 0,
+ 19555, 43,
+ },
+ {
+ "fr-WF",
+ locale_compact_arr_49,
+ { 1, 5, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 18, 19 },
+ 76, 82,
+ 1, 68,
+ 53, 63,
+ 0, 33,
+ 33,
+ 15, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 1,
+ 1, 1,
+ 12, 3, 0,
+ 19643, 42,
+ },
+ {
+ "fr-YT",
+ locale_compact_arr_49,
+ { 1, 5, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 18, 19 },
+ 76, 82,
+ 1, 68,
+ 53, 63,
+ 0, 33,
+ 33,
+ 15, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 1,
+ 1, 1,
+ 12, 3, 0,
+ 19727, 42,
+ },
+ {
+ "frr",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 19811, 23,
+ },
+ {
+ "fur",
+ locale_compact_arr_0,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 77, 85,
+ 55, 69,
+ 53, 64,
+ 43, 0,
+ 0,
+ 68, 15,
+ 111, 112,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 19857, 23,
+ },
+ {
+ "fy",
+ locale_compact_arr_51,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 35, 2, 26, 4, 5 },
+ 78, 86,
+ 1, 70,
+ 0, 65,
+ 0, 0,
+ 0,
+ 95, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 19903, 25,
+ },
+ {
+ "ga",
+ locale_compact_arr_52,
+ { 0, 0, 0, 0, 0, 0, 10 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 79, 87,
+ 56, 71,
+ 64, 66,
+ 44, 0,
+ 0,
+ 11, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 19953, 23,
+ },
+ {
+ "ga-GB",
+ locale_compact_arr_52,
+ { 0, 0, 0, 0, 0, 0, 10 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 79, 87,
+ 56, 71,
+ 64, 66,
+ 44, 0,
+ 0,
+ 11, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 19999, 23,
+ },
+ {
+ "gaa",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 80, 88,
+ 0, 72,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 0, 1,
+ 2, 3,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 20045, 23,
+ },
+ {
+ "gd",
+ locale_compact_arr_53,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 81, 89,
+ 57, 73,
+ 65, 67,
+ 45, 0,
+ 0,
+ 15, 113,
+ 114, 115,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 20091, 22,
+ },
+ {
+ "gez",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 20135, 23,
+ },
+ {
+ "gez-ER",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 20181, 24,
+ },
+ {
+ "gl",
+ locale_compact_arr_54,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 18, 19 },
+ 82, 90,
+ 58, 74,
+ 66, 68,
+ 33, 35,
+ 36,
+ 68, 116,
+ 92, 93,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 20229, 23,
+ },
+ {
+ "gn",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 83, 91,
+ 0, 75,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 20276, 24,
+ },
+ {
+ "gsw",
+ locale_compact_arr_55,
+ { 0, 4, 0, 5, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 18, 19 },
+ 84, 92,
+ 1, 76,
+ 38, 39,
+ 46, 36,
+ 37,
+ 27, 29,
+ 62, 71,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 20326, 24,
+ },
+ {
+ "gsw-FR",
+ locale_compact_arr_55,
+ { 0, 4, 0, 5, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 18, 19 },
+ 84, 92,
+ 1, 76,
+ 38, 39,
+ 46, 36,
+ 37,
+ 27, 29,
+ 62, 71,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 20374, 24,
+ },
+ {
+ "gsw-LI",
+ locale_compact_arr_55,
+ { 0, 4, 0, 5, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 18, 19 },
+ 84, 92,
+ 1, 76,
+ 38, 39,
+ 46, 36,
+ 37,
+ 27, 29,
+ 62, 71,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 20422, 24,
+ },
+ {
+ "gu",
+ locale_compact_arr_56,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 85, 93,
+ 59, 77,
+ 67, 69,
+ 0, 37,
+ 38,
+ 11, 8,
+ 22, 23,
+ 58, 59,
+ 60, 61,
+ 0, 0,
+ 0, 0,
+ 12, 3, 2,
+ 20470, 23,
+ },
+ {
+ "guz",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 86, 94,
+ 60, 78,
+ 68, 70,
+ 47, 0,
+ 0,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 20516, 24,
+ },
+ {
+ "gv",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 7, 4, 5 },
+ 87, 95,
+ 0, 79,
+ 0, 71,
+ 33, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 20564, 23,
+ },
+ {
+ "ha",
+ locale_compact_arr_57,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 88, 96,
+ 61, 80,
+ 69, 72,
+ 48, 0,
+ 0,
+ 11, 8,
+ 22, 117,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 0,
+ 12, 3, 0,
+ 20610, 24,
+ },
+ {
+ "ha-Arab",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 20658, 24,
+ },
+ {
+ "ha-Arab-SD",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 20706, 24,
+ },
+ {
+ "ha-GH",
+ locale_compact_arr_57,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 88, 96,
+ 61, 80,
+ 69, 72,
+ 48, 0,
+ 0,
+ 11, 8,
+ 22, 117,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 0,
+ 12, 3, 0,
+ 20754, 25,
+ },
+ {
+ "ha-NE",
+ locale_compact_arr_57,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 88, 96,
+ 61, 80,
+ 69, 72,
+ 48, 0,
+ 0,
+ 11, 8,
+ 22, 117,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 0,
+ 12, 3, 0,
+ 20804, 24,
+ },
+ {
+ "haw",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 89, 97,
+ 0, 81,
+ 0, 0,
+ 0, 0,
+ 0,
+ 118, 16,
+ 9, 24,
+ 0, 1,
+ 2, 3,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 20852, 23,
+ },
+ {
+ "he",
+ locale_compact_arr_58,
+ { 0, 0, 1, 1, 0, 0, 0 },
+ { 0, 1, 36, 37, 36, 37, 4, 5 },
+ 90, 98,
+ 0, 82,
+ 70, 73,
+ 0, 38,
+ 39,
+ 76, 119,
+ 120, 121,
+ 12, 13,
+ 14, 15,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 20898, 24,
+ },
+ {
+ "hi",
+ locale_compact_arr_59,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 7, 4, 5 },
+ 91, 99,
+ 62, 83,
+ 71, 74,
+ 9, 39,
+ 40,
+ 11, 16,
+ 9, 24,
+ 8, 9,
+ 10, 11,
+ 1, 1,
+ 1, 1,
+ 12, 3, 2,
+ 20948, 23,
+ },
+ {
+ "hi-Latn",
+ locale_compact_arr_60,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 7, 4, 5 },
+ 60, 62,
+ 1, 84,
+ 72, 48,
+ 0, 40,
+ 41,
+ 15, 122,
+ 22, 24,
+ 0, 1,
+ 2, 3,
+ 0, 0,
+ 1, 1,
+ 12, 3, 2,
+ 20994, 23,
+ },
+ {
+ "hnj",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 92, 100,
+ 0, 0,
+ 0, 75,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 21040, 23,
+ },
+ {
+ "hnj-Hmnp",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 92, 100,
+ 0, 0,
+ 0, 75,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 21087, 23,
+ },
+ {
+ "hr",
+ locale_compact_arr_61,
+ { 1, 3, 0, 5, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 18, 19 },
+ 93, 101,
+ 63, 26,
+ 22, 76,
+ 0, 41,
+ 42,
+ 123, 47,
+ 48, 49,
+ 4, 5,
+ 6, 34,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 21134, 5,
+ },
+ {
+ "hr-BA",
+ locale_compact_arr_61,
+ { 1, 3, 0, 5, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 18, 19 },
+ 93, 101,
+ 63, 26,
+ 22, 76,
+ 0, 41,
+ 42,
+ 124, 47,
+ 48, 49,
+ 4, 5,
+ 6, 34,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 21145, 6,
+ },
+ {
+ "hsb",
+ locale_compact_arr_28,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 18, 19 },
+ 94, 102,
+ 36, 85,
+ 73, 77,
+ 49, 0,
+ 0,
+ 75, 76,
+ 62, 71,
+ 62, 13,
+ 14, 15,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 21158, 24,
+ },
+ {
+ "ht",
+ locale_compact_arr_49,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 18, 19 },
+ 76, 82,
+ 1, 68,
+ 53, 63,
+ 0, 34,
+ 33,
+ 15, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 1,
+ 1, 1,
+ 12, 3, 0,
+ 21207, 43,
+ },
+ {
+ "hu",
+ locale_compact_arr_62,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 95, 103,
+ 64, 86,
+ 74, 78,
+ 50, 42,
+ 43,
+ 125, 126,
+ 127, 128,
+ 12, 13,
+ 14, 15,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 21294, 7,
+ },
+ {
+ "hy",
+ locale_compact_arr_63,
+ { 1, 1, 0, 0, 0, 0, 11 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 96, 104,
+ 65, 87,
+ 75, 79,
+ 0, 43,
+ 44,
+ 27, 129,
+ 130, 131,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 21310, 24,
+ },
+ {
+ "ia",
+ locale_compact_arr_64,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 26, 4, 5 },
+ 97, 105,
+ 36, 88,
+ 76, 80,
+ 0, 0,
+ 0,
+ 21, 16,
+ 132, 133,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 21360, 25,
+ },
+ {
+ "id",
+ locale_compact_arr_65,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 7, 4, 5 },
+ 98, 106,
+ 1, 89,
+ 77, 81,
+ 0, 44,
+ 45,
+ 68, 16,
+ 9, 83,
+ 35, 36,
+ 37, 38,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 21412, 23,
+ },
+ {
+ "ie",
+ locale_compact_arr_0,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 21, 2, 21, 4, 5 },
+ 99, 107,
+ 1, 90,
+ 78, 82,
+ 33, 0,
+ 0,
+ 75, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 21458, 23,
+ },
+ {
+ "ig",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 100, 108,
+ 66, 91,
+ 0, 83,
+ 51, 0,
+ 0,
+ 11, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 21504, 24,
+ },
+ {
+ "ii",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 101, 109,
+ 0, 92,
+ 79, 84,
+ 52, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 21552, 23,
+ },
+ {
+ "io",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 21598, 23,
+ },
+ {
+ "is",
+ locale_compact_arr_66,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 102, 110,
+ 67, 93,
+ 80, 85,
+ 53, 45,
+ 46,
+ 76, 69,
+ 62, 71,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 21644, 10,
+ },
+ {
+ "it",
+ locale_compact_arr_67,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 103, 111,
+ 68, 94,
+ 81, 86,
+ 0, 46,
+ 47,
+ 68, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 0, 0,
+ 12, 3, 0,
+ 21664, 15,
+ },
+ {
+ "it-CH",
+ locale_compact_arr_67,
+ { 0, 4, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 25, 2, 25, 4, 5 },
+ 103, 111,
+ 68, 94,
+ 81, 86,
+ 0, 46,
+ 47,
+ 27, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 0, 0,
+ 12, 3, 0,
+ 21694, 15,
+ },
+ {
+ "it-SM",
+ locale_compact_arr_67,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 103, 111,
+ 68, 94,
+ 81, 86,
+ 0, 46,
+ 47,
+ 68, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 0, 0,
+ 12, 3, 0,
+ 21724, 15,
+ },
+ {
+ "it-VA",
+ locale_compact_arr_67,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 103, 111,
+ 68, 94,
+ 81, 86,
+ 0, 46,
+ 47,
+ 68, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 0, 0,
+ 12, 3, 0,
+ 21754, 15,
+ },
+ {
+ "iu",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 101, 57,
+ 58, 59,
+ 8, 9,
+ 10, 11,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 21784, 23,
+ },
+ {
+ "iu-Latn",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 21830, 23,
+ },
+ {
+ "ja",
+ locale_compact_arr_68,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 104, 112,
+ 0, 95,
+ 82, 87,
+ 54, 47,
+ 48,
+ 85, 85,
+ 134, 135,
+ 12, 13,
+ 14, 63,
+ 0, 0,
+ 0, 0,
+ 3, 3, 0,
+ 21876, 21,
+ },
+ {
+ "ja-JP",
+ locale_compact_arr_68,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 104, 112,
+ 0, 95,
+ 82, 87,
+ 54, 47,
+ 48,
+ 85, 85,
+ 134, 135,
+ 12, 13,
+ 14, 63,
+ 0, 0,
+ 0, 0,
+ 3, 3, 0,
+ 21920, 21,
+ },
+ {
+ "jbo",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 21964, 23,
+ },
+ {
+ "jgo",
+ locale_compact_arr_0,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 105, 113,
+ 0, 96,
+ 83, 88,
+ 55, 0,
+ 0,
+ 0, 1,
+ 2, 136,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 22010, 23,
+ },
+ {
+ "jmc",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 7, 4, 5 },
+ 106, 114,
+ 1, 97,
+ 7, 89,
+ 56, 0,
+ 0,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 22056, 24,
+ },
+ {
+ "jv",
+ locale_compact_arr_69,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 98, 115,
+ 1, 98,
+ 84, 90,
+ 57, 0,
+ 0,
+ 21, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 0, 0,
+ 12, 3, 0,
+ 22104, 24,
+ },
+ {
+ "ka",
+ locale_compact_arr_70,
+ { 1, 1, 0, 0, 0, 0, 12 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 107, 116,
+ 69, 99,
+ 85, 91,
+ 0, 48,
+ 49,
+ 27, 137,
+ 22, 138,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 22152, 14,
+ },
+ {
+ "kaa",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 36, 38,
+ 27, 100,
+ 86, 92,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 22181, 23,
+ },
+ {
+ "kaa-Cyrl",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 36, 38,
+ 27, 100,
+ 86, 92,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 22227, 23,
+ },
+ {
+ "kaa-Latn",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 22273, 23,
+ },
+ {
+ "kab",
+ locale_compact_arr_0,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 9, 10, 9, 10, 4, 5 },
+ 108, 117,
+ 70, 101,
+ 87, 93,
+ 58, 0,
+ 0,
+ 7, 8,
+ 9, 10,
+ 0, 1,
+ 2, 3,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 22319, 24,
+ },
+ {
+ "kaj",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 22368, 24,
+ },
+ {
+ "kam",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 109, 118,
+ 71, 102,
+ 88, 94,
+ 59, 0,
+ 0,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 22416, 24,
+ },
+ {
+ "kcg",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 22464, 24,
+ },
+ {
+ "kde",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 110, 114,
+ 1, 103,
+ 89, 95,
+ 60, 0,
+ 0,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 22512, 24,
+ },
+ {
+ "kea",
+ locale_compact_arr_71,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 4, 5 },
+ 111, 119,
+ 1, 104,
+ 90, 96,
+ 9, 0,
+ 0,
+ 15, 16,
+ 139, 140,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 22560, 25,
+ },
+ {
+ "kek",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 112, 120,
+ 0, 105,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 22611, 23,
+ },
+ {
+ "ken",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 22657, 23,
+ },
+ {
+ "kgp",
+ locale_compact_arr_72,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 113, 121,
+ 72, 106,
+ 91, 97,
+ 0, 49,
+ 50,
+ 15, 141,
+ 142, 143,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 22703, 26,
+ },
+ {
+ "khq",
+ locale_compact_arr_0,
+ { 0, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 9, 10, 9, 10, 4, 5 },
+ 50, 52,
+ 34, 107,
+ 92, 98,
+ 61, 0,
+ 0,
+ 7, 8,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 22760, 23,
+ },
+ {
+ "ki",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 114, 122,
+ 73, 108,
+ 93, 45,
+ 62, 0,
+ 0,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 22806, 24,
+ },
+ {
+ "kk",
+ locale_compact_arr_73,
+ { 1, 1, 0, 0, 0, 0, 13 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 115, 123,
+ 74, 109,
+ 94, 99,
+ 0, 50,
+ 51,
+ 27, 144,
+ 145, 146,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 22854, 26,
+ },
+ {
+ "kk-Arab",
+ locale_compact_arr_74,
+ { 0, 0, 0, 0, 0, 0, 14 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 116, 124,
+ 0, 110,
+ 95, 100,
+ 63, 51,
+ 52,
+ 21, 147,
+ 148, 149,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 2, 2,
+ 12, 3, 0,
+ 22907, 24,
+ },
+ {
+ "kk-Cyrl",
+ locale_compact_arr_73,
+ { 1, 1, 0, 0, 0, 0, 13 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 115, 123,
+ 74, 109,
+ 94, 99,
+ 0, 50,
+ 51,
+ 27, 144,
+ 145, 146,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 22955, 26,
+ },
+ {
+ "kk-KZ",
+ locale_compact_arr_73,
+ { 1, 1, 0, 0, 0, 0, 13 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 115, 123,
+ 74, 109,
+ 94, 99,
+ 0, 50,
+ 51,
+ 27, 144,
+ 145, 146,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 23008, 26,
+ },
+ {
+ "kkj",
+ locale_compact_arr_0,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 117, 125,
+ 0, 111,
+ 96, 0,
+ 0, 0,
+ 0,
+ 150, 16,
+ 9, 6,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 23061, 23,
+ },
+ {
+ "kl",
+ locale_compact_arr_0,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 25, 6, 25, 18, 19 },
+ 118, 126,
+ 0, 112,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 35, 36,
+ 37, 38,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 23107, 24,
+ },
+ {
+ "kln",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 119, 127,
+ 75, 113,
+ 97, 101,
+ 64, 0,
+ 0,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 23155, 24,
+ },
+ {
+ "km",
+ locale_compact_arr_75,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 9, 10, 9, 24, 4, 5 },
+ 120, 128,
+ 76, 114,
+ 98, 102,
+ 0, 52,
+ 53,
+ 11, 16,
+ 9, 10,
+ 8, 9,
+ 10, 11,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 23203, 25,
+ },
+ {
+ "kn",
+ locale_compact_arr_76,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 121, 129,
+ 77, 115,
+ 99, 103,
+ 0, 53,
+ 54,
+ 11, 57,
+ 58, 59,
+ 58, 59,
+ 60, 61,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 23256, 23,
+ },
+ {
+ "ko",
+ locale_compact_arr_77,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 122, 130,
+ 78, 116,
+ 100, 104,
+ 65, 54,
+ 55,
+ 151, 152,
+ 153, 154,
+ 64, 28,
+ 65, 66,
+ 0, 0,
+ 0, 0,
+ 4, 3, 0,
+ 23302, 22,
+ },
+ {
+ "ko-CN",
+ locale_compact_arr_78,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 122, 130,
+ 78, 116,
+ 100, 104,
+ 65, 54,
+ 55,
+ 151, 152,
+ 153, 154,
+ 4, 5,
+ 67, 68,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 23346, 22,
+ },
+ {
+ "ko-KP",
+ locale_compact_arr_78,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 122, 130,
+ 78, 116,
+ 100, 104,
+ 65, 54,
+ 55,
+ 151, 152,
+ 153, 154,
+ 64, 28,
+ 65, 66,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 23390, 22,
+ },
+ {
+ "ko-KR",
+ locale_compact_arr_77,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 122, 130,
+ 78, 116,
+ 100, 104,
+ 65, 54,
+ 55,
+ 151, 152,
+ 153, 154,
+ 64, 28,
+ 65, 66,
+ 0, 0,
+ 0, 0,
+ 4, 3, 0,
+ 23434, 22,
+ },
+ {
+ "kok",
+ locale_compact_arr_79,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 7, 4, 5 },
+ 123, 131,
+ 79, 117,
+ 101, 105,
+ 0, 55,
+ 56,
+ 86, 155,
+ 9, 10,
+ 8, 9,
+ 10, 11,
+ 0, 0,
+ 0, 0,
+ 12, 3, 2,
+ 23478, 23,
+ },
+ {
+ "kok-Deva",
+ locale_compact_arr_79,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 7, 4, 5 },
+ 123, 131,
+ 79, 117,
+ 101, 105,
+ 0, 55,
+ 56,
+ 86, 155,
+ 9, 10,
+ 8, 9,
+ 10, 11,
+ 0, 0,
+ 0, 0,
+ 12, 3, 2,
+ 23526, 23,
+ },
+ {
+ "kok-Latn",
+ locale_compact_arr_80,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 7, 4, 5 },
+ 124, 132,
+ 1, 118,
+ 102, 106,
+ 0, 56,
+ 57,
+ 86, 8,
+ 22, 23,
+ 69, 70,
+ 71, 72,
+ 1, 1,
+ 1, 1,
+ 12, 3, 2,
+ 23574, 23,
+ },
+ {
+ "kpe",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 0, 1,
+ 2, 3,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 23620, 24,
+ },
+ {
+ "kpe-GN",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 23668, 24,
+ },
+ {
+ "ks",
+ locale_compact_arr_0,
+ { 2, 2, 3, 3, 3, 0, 0 },
+ { 0, 1, 6, 7, 6, 7, 4, 5 },
+ 125, 133,
+ 80, 119,
+ 103, 107,
+ 0, 0,
+ 0,
+ 56, 57,
+ 58, 59,
+ 8, 9,
+ 10, 11,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 23717, 23,
+ },
+ {
+ "ks-Arab",
+ locale_compact_arr_0,
+ { 2, 2, 3, 3, 3, 0, 0 },
+ { 0, 1, 6, 7, 6, 7, 4, 5 },
+ 125, 133,
+ 80, 119,
+ 103, 107,
+ 0, 0,
+ 0,
+ 56, 57,
+ 58, 59,
+ 8, 9,
+ 10, 11,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 23763, 23,
+ },
+ {
+ "ks-Deva",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 126, 134,
+ 81, 120,
+ 104, 108,
+ 0, 0,
+ 0,
+ 11, 16,
+ 9, 24,
+ 64, 28,
+ 29, 30,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 23809, 23,
+ },
+ {
+ "ksb",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 9, 10, 9, 10, 4, 5 },
+ 127, 114,
+ 1, 121,
+ 105, 109,
+ 66, 0,
+ 0,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 23855, 24,
+ },
+ {
+ "ksf",
+ locale_compact_arr_0,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 128, 135,
+ 0, 122,
+ 106, 110,
+ 67, 0,
+ 0,
+ 7, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 23903, 23,
+ },
+ {
+ "ksh",
+ locale_compact_arr_81,
+ { 1, 1, 0, 5, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 18, 19 },
+ 129, 136,
+ 82, 123,
+ 38, 111,
+ 68, 0,
+ 0,
+ 61, 156,
+ 62, 157,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 23949, 23,
+ },
+ {
+ "ku",
+ locale_compact_arr_82,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 38, 39 },
+ 130, 137,
+ 83, 124,
+ 107, 112,
+ 69, 0,
+ 0,
+ 29, 8,
+ 158, 159,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 23995, 24,
+ },
+ {
+ "ku-Arab",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 24043, 23,
+ },
+ {
+ "ku-Arab-IR",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 24089, 23,
+ },
+ {
+ "ku-Latn",
+ locale_compact_arr_82,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 38, 39 },
+ 130, 137,
+ 83, 124,
+ 107, 112,
+ 69, 0,
+ 0,
+ 29, 8,
+ 158, 159,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 24135, 24,
+ },
+ {
+ "ku-Latn-IQ",
+ locale_compact_arr_82,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 38, 39 },
+ 130, 137,
+ 83, 124,
+ 107, 112,
+ 69, 0,
+ 0,
+ 29, 8,
+ 158, 159,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 24183, 24,
+ },
+ {
+ "ku-Latn-SY",
+ locale_compact_arr_82,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 38, 39 },
+ 130, 137,
+ 83, 124,
+ 107, 112,
+ 69, 0,
+ 0,
+ 29, 8,
+ 158, 159,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 24231, 24,
+ },
+ {
+ "ku-TR",
+ locale_compact_arr_82,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 38, 39 },
+ 130, 137,
+ 83, 124,
+ 107, 112,
+ 69, 0,
+ 0,
+ 29, 8,
+ 158, 159,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 24279, 24,
+ },
+ {
+ "kw",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 7, 4, 5 },
+ 131, 138,
+ 0, 125,
+ 0, 71,
+ 33, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 24327, 23,
+ },
+ {
+ "kxv",
+ locale_compact_arr_83,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 132, 139,
+ 84, 126,
+ 108, 113,
+ 9, 0,
+ 0,
+ 11, 16,
+ 9, 24,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 2,
+ 24373, 23,
+ },
+ {
+ "kxv-Deva",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 7, 4, 5 },
+ 133, 140,
+ 85, 127,
+ 109, 114,
+ 70, 0,
+ 0,
+ 11, 16,
+ 9, 24,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 8, 8,
+ 12, 3, 2,
+ 24419, 23,
+ },
+ {
+ "kxv-Latn",
+ locale_compact_arr_83,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 132, 139,
+ 84, 126,
+ 108, 113,
+ 9, 0,
+ 0,
+ 11, 16,
+ 9, 24,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 2,
+ 24465, 23,
+ },
+ {
+ "kxv-Orya",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 7, 4, 5 },
+ 134, 141,
+ 86, 128,
+ 110, 115,
+ 71, 0,
+ 0,
+ 11, 16,
+ 9, 24,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 9, 9,
+ 12, 3, 2,
+ 24511, 23,
+ },
+ {
+ "kxv-Telu",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 7, 4, 5 },
+ 135, 142,
+ 87, 129,
+ 111, 116,
+ 72, 0,
+ 0,
+ 11, 16,
+ 9, 24,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 10, 10,
+ 12, 3, 2,
+ 24557, 23,
+ },
+ {
+ "ky",
+ locale_compact_arr_84,
+ { 1, 1, 0, 0, 0, 0, 15 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 36, 143,
+ 27, 130,
+ 112, 117,
+ 73, 57,
+ 58,
+ 11, 160,
+ 161, 162,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 24603, 11,
+ },
+ {
+ "la",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 24627, 23,
+ },
+ {
+ "lag",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 136, 144,
+ 88, 131,
+ 113, 118,
+ 74, 0,
+ 0,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 24673, 24,
+ },
+ {
+ "lb",
+ locale_compact_arr_85,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 18, 19 },
+ 137, 145,
+ 1, 132,
+ 38, 39,
+ 75, 0,
+ 0,
+ 27, 69,
+ 62, 71,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 24721, 24,
+ },
+ {
+ "lg",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 9, 10, 9, 10, 4, 5 },
+ 138, 146,
+ 1, 133,
+ 114, 119,
+ 0, 0,
+ 0,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 24769, 24,
+ },
+ {
+ "lij",
+ locale_compact_arr_0,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 139, 147,
+ 0, 134,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 24817, 23,
+ },
+ {
+ "lkt",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 140, 148,
+ 0, 135,
+ 115, 0,
+ 0, 0,
+ 0,
+ 56, 57,
+ 58, 59,
+ 0, 1,
+ 2, 3,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 24863, 23,
+ },
+ {
+ "lld",
+ locale_compact_arr_86,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 141, 149,
+ 89, 136,
+ 53, 120,
+ 0, 0,
+ 0,
+ 27, 16,
+ 9, 163,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 0, 0,
+ 12, 3, 0,
+ 24909, 23,
+ },
+ {
+ "lmo",
+ locale_compact_arr_0,
+ { 1, 4, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 142, 150,
+ 0, 137,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 24955, 23,
+ },
+ {
+ "ln",
+ locale_compact_arr_0,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 143, 151,
+ 90, 138,
+ 116, 121,
+ 76, 0,
+ 0,
+ 7, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 25001, 24,
+ },
+ {
+ "ln-AO",
+ locale_compact_arr_0,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 143, 151,
+ 90, 138,
+ 116, 121,
+ 76, 0,
+ 0,
+ 7, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 25049, 25,
+ },
+ {
+ "ln-CF",
+ locale_compact_arr_0,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 143, 151,
+ 90, 138,
+ 116, 121,
+ 76, 0,
+ 0,
+ 7, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 25101, 24,
+ },
+ {
+ "ln-CG",
+ locale_compact_arr_0,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 143, 151,
+ 90, 138,
+ 116, 121,
+ 76, 0,
+ 0,
+ 7, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 25149, 24,
+ },
+ {
+ "lo",
+ locale_compact_arr_87,
+ { 1, 3, 0, 0, 0, 0, 16 },
+ { 0, 1, 6, 25, 6, 25, 4, 5 },
+ 144, 152,
+ 0, 139,
+ 117, 122,
+ 77, 58,
+ 59,
+ 7, 16,
+ 9, 24,
+ 12, 13,
+ 73, 74,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 25197, 24,
+ },
+ {
+ "lrc",
+ locale_compact_arr_0,
+ { 2, 2, 3, 3, 3, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 145, 153,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 25247, 24,
+ },
+ {
+ "lrc-IQ",
+ locale_compact_arr_0,
+ { 2, 2, 3, 3, 3, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 145, 153,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 8, 9,
+ 10, 11,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 25295, 24,
+ },
+ {
+ "lt",
+ locale_compact_arr_88,
+ { 1, 1, 0, 5, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 18, 19 },
+ 146, 154,
+ 91, 140,
+ 118, 123,
+ 78, 59,
+ 60,
+ 0, 0,
+ 164, 165,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 25343, 3,
+ },
+ {
+ "ltg",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 25349, 23,
+ },
+ {
+ "lu",
+ locale_compact_arr_0,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 9, 10, 9, 10, 4, 5 },
+ 147, 155,
+ 92, 141,
+ 119, 124,
+ 79, 0,
+ 0,
+ 7, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 25395, 24,
+ },
+ {
+ "luo",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 9, 10, 9, 10, 4, 5 },
+ 148, 156,
+ 93, 142,
+ 120, 125,
+ 80, 0,
+ 0,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 25443, 24,
+ },
+ {
+ "luy",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 40, 6, 40, 4, 5 },
+ 11, 157,
+ 1, 143,
+ 0, 126,
+ 33, 0,
+ 0,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 25491, 24,
+ },
+ {
+ "lv",
+ locale_compact_arr_89,
+ { 1, 1, 0, 0, 0, 0, 17 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 149, 158,
+ 1, 144,
+ 121, 127,
+ 81, 60,
+ 61,
+ 27, 166,
+ 167, 168,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 25539, 24,
+ },
+ {
+ "lzz",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 25589, 23,
+ },
+ {
+ "mai",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 150, 159,
+ 94, 145,
+ 71, 128,
+ 82, 0,
+ 0,
+ 11, 16,
+ 9, 24,
+ 8, 9,
+ 10, 11,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 25635, 23,
+ },
+ {
+ "mas",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 151, 160,
+ 0, 146,
+ 89, 129,
+ 83, 0,
+ 0,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 25681, 24,
+ },
+ {
+ "mas-TZ",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 151, 160,
+ 0, 146,
+ 89, 129,
+ 83, 0,
+ 0,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 25729, 25,
+ },
+ {
+ "mdf",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 25779, 24,
+ },
+ {
+ "mer",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 152, 161,
+ 95, 147,
+ 122, 130,
+ 84, 0,
+ 0,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 25827, 24,
+ },
+ {
+ "mfe",
+ locale_compact_arr_0,
+ { 0, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 153, 162,
+ 96, 148,
+ 123, 131,
+ 0, 0,
+ 0,
+ 7, 8,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 25875, 24,
+ },
+ {
+ "mg",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 6, 7, 4, 5 },
+ 154, 163,
+ 1, 149,
+ 124, 132,
+ 0, 0,
+ 0,
+ 0, 1,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 25924, 24,
+ },
+ {
+ "mgh",
+ locale_compact_arr_0,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 155, 164,
+ 97, 150,
+ 125, 133,
+ 85, 0,
+ 0,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 25974, 24,
+ },
+ {
+ "mgo",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 156, 165,
+ 98, 151,
+ 126, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 136,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 26024, 23,
+ },
+ {
+ "mhn",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 26070, 23,
+ },
+ {
+ "mi",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 157, 166,
+ 99, 152,
+ 127, 0,
+ 0, 0,
+ 0,
+ 21, 16,
+ 9, 24,
+ 0, 1,
+ 2, 3,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 26116, 23,
+ },
+ {
+ "mic",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 26162, 23,
+ },
+ {
+ "mk",
+ locale_compact_arr_90,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 18, 19 },
+ 158, 167,
+ 24, 153,
+ 15, 134,
+ 86, 61,
+ 62,
+ 169, 35,
+ 36, 37,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 26208, 12,
+ },
+ {
+ "ml",
+ locale_compact_arr_91,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 159, 168,
+ 100, 154,
+ 128, 135,
+ 0, 62,
+ 63,
+ 11, 1,
+ 2, 3,
+ 8, 9,
+ 75, 76,
+ 1, 1,
+ 1, 1,
+ 12, 3, 2,
+ 26234, 23,
+ },
+ {
+ "mn",
+ locale_compact_arr_92,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 160, 169,
+ 101, 155,
+ 129, 136,
+ 87, 63,
+ 64,
+ 64, 170,
+ 171, 172,
+ 4, 5,
+ 33, 34,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 26280, 24,
+ },
+ {
+ "mn-Mong",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 26330, 23,
+ },
+ {
+ "mn-Mong-MN",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 7, 4, 5 },
+ 161, 170,
+ 101, 156,
+ 130, 137,
+ 0, 0,
+ 0,
+ 64, 64,
+ 173, 174,
+ 4, 5,
+ 33, 34,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 26376, 24,
+ },
+ {
+ "mni",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 162, 171,
+ 102, 157,
+ 131, 138,
+ 88, 0,
+ 0,
+ 11, 57,
+ 58, 175,
+ 8, 9,
+ 10, 11,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 26426, 23,
+ },
+ {
+ "mni-Beng",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 162, 171,
+ 102, 157,
+ 131, 138,
+ 88, 0,
+ 0,
+ 11, 57,
+ 58, 175,
+ 8, 9,
+ 10, 11,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 26472, 23,
+ },
+ {
+ "mni-Mtei",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 26518, 23,
+ },
+ {
+ "moh",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 0, 1,
+ 2, 3,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 26564, 23,
+ },
+ {
+ "mr",
+ locale_compact_arr_93,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 163, 172,
+ 79, 158,
+ 71, 139,
+ 0, 64,
+ 65,
+ 11, 8,
+ 22, 23,
+ 8, 9,
+ 10, 11,
+ 1, 1,
+ 1, 1,
+ 12, 3, 2,
+ 26610, 23,
+ },
+ {
+ "ms",
+ locale_compact_arr_94,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 164, 173,
+ 82, 159,
+ 132, 140,
+ 89, 65,
+ 66,
+ 96, 16,
+ 9, 24,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 0, 0,
+ 12, 3, 0,
+ 26656, 20,
+ },
+ {
+ "ms-Arab",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 96, 15,
+ 9, 19,
+ 8, 9,
+ 10, 11,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 26696, 24,
+ },
+ {
+ "ms-Arab-BN",
+ locale_compact_arr_0,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 6, 8, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 96, 15,
+ 9, 5,
+ 8, 9,
+ 10, 11,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 26744, 25,
+ },
+ {
+ "ms-BN",
+ locale_compact_arr_94,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 6, 8, 4, 5 },
+ 164, 173,
+ 82, 159,
+ 132, 140,
+ 89, 65,
+ 66,
+ 96, 16,
+ 9, 5,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 0, 0,
+ 12, 3, 0,
+ 26794, 21,
+ },
+ {
+ "ms-ID",
+ locale_compact_arr_94,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 7, 4, 5 },
+ 164, 173,
+ 82, 159,
+ 132, 140,
+ 89, 65,
+ 66,
+ 68, 16,
+ 9, 83,
+ 35, 36,
+ 37, 38,
+ 1, 1,
+ 0, 0,
+ 12, 3, 0,
+ 26836, 21,
+ },
+ {
+ "ms-SG",
+ locale_compact_arr_94,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 164, 173,
+ 82, 159,
+ 132, 140,
+ 89, 65,
+ 66,
+ 96, 16,
+ 9, 24,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 0, 0,
+ 12, 3, 0,
+ 26878, 21,
+ },
+ {
+ "mt",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 7, 4, 5 },
+ 165, 174,
+ 103, 160,
+ 133, 141,
+ 0, 0,
+ 0,
+ 15, 4,
+ 176, 177,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 26920, 22,
+ },
+ {
+ "mua",
+ locale_compact_arr_0,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 166, 175,
+ 104, 161,
+ 134, 142,
+ 90, 0,
+ 0,
+ 7, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 26964, 23,
+ },
+ {
+ "mus",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 167, 176,
+ 0, 162,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 27010, 23,
+ },
+ {
+ "mww",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 27056, 23,
+ },
+ {
+ "mww-Hmnp",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 27103, 23,
+ },
+ {
+ "my",
+ locale_compact_arr_95,
+ { 0, 0, 0, 0, 0, 0, 18 },
+ { 0, 1, 16, 17, 2, 3, 4, 5 },
+ 168, 177,
+ 105, 163,
+ 135, 143,
+ 91, 66,
+ 67,
+ 11, 1,
+ 2, 178,
+ 12, 13,
+ 67, 68,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 27150, 30,
+ },
+ {
+ "myv",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 27219, 23,
+ },
+ {
+ "mzn",
+ locale_compact_arr_0,
+ { 2, 2, 3, 3, 3, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 169, 75,
+ 0, 0,
+ 0, 144,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 27265, 22,
+ },
+ {
+ "naq",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 7, 4, 5 },
+ 170, 62,
+ 1, 164,
+ 136, 145,
+ 92, 0,
+ 0,
+ 15, 16,
+ 9, 24,
+ 0, 1,
+ 2, 3,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 27309, 24,
+ },
+ {
+ "nb",
+ locale_compact_arr_96,
+ { 1, 1, 0, 5, 0, 0, 0 },
+ { 0, 1, 16, 17, 2, 26, 18, 19 },
+ 171, 178,
+ 1, 42,
+ 36, 146,
+ 33, 67,
+ 68,
+ 29, 69,
+ 62, 63,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 27357, 5,
+ },
+ {
+ "nb-SJ",
+ locale_compact_arr_96,
+ { 1, 1, 0, 5, 0, 0, 0 },
+ { 0, 1, 16, 17, 2, 26, 18, 19 },
+ 171, 178,
+ 1, 42,
+ 36, 146,
+ 33, 67,
+ 68,
+ 29, 69,
+ 62, 63,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 27367, 5,
+ },
+ {
+ "nd",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 172, 179,
+ 106, 165,
+ 137, 147,
+ 0, 0,
+ 0,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 27377, 23,
+ },
+ {
+ "nds",
+ locale_compact_arr_0,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 18, 19 },
+ 173, 180,
+ 0, 166,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 27423, 23,
+ },
+ {
+ "nds-NL",
+ locale_compact_arr_0,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 18, 19 },
+ 173, 180,
+ 0, 166,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 27469, 23,
+ },
+ {
+ "ne",
+ locale_compact_arr_97,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 174, 181,
+ 107, 167,
+ 138, 148,
+ 93, 68,
+ 69,
+ 102, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 0, 0,
+ 12, 3, 2,
+ 27515, 24,
+ },
+ {
+ "ne-IN",
+ locale_compact_arr_97,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 174, 181,
+ 107, 167,
+ 138, 148,
+ 93, 68,
+ 69,
+ 102, 1,
+ 2, 3,
+ 8, 9,
+ 10, 11,
+ 1, 1,
+ 0, 0,
+ 12, 3, 2,
+ 27565, 24,
+ },
+ {
+ "nl",
+ locale_compact_arr_98,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 21, 2, 26, 4, 5 },
+ 175, 182,
+ 1, 168,
+ 139, 149,
+ 33, 69,
+ 70,
+ 21, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 27615, 24,
+ },
+ {
+ "nl-AW",
+ locale_compact_arr_98,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 21, 2, 26, 4, 5 },
+ 175, 182,
+ 1, 168,
+ 139, 149,
+ 33, 69,
+ 70,
+ 21, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 27663, 25,
+ },
+ {
+ "nl-BE",
+ locale_compact_arr_98,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 21, 2, 26, 4, 5 },
+ 175, 182,
+ 1, 168,
+ 139, 149,
+ 33, 69,
+ 70,
+ 97, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 27715, 24,
+ },
+ {
+ "nl-BQ",
+ locale_compact_arr_98,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 21, 2, 26, 4, 5 },
+ 175, 182,
+ 1, 168,
+ 139, 149,
+ 33, 69,
+ 70,
+ 21, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 27763, 24,
+ },
+ {
+ "nl-CW",
+ locale_compact_arr_98,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 21, 2, 26, 4, 5 },
+ 175, 182,
+ 1, 168,
+ 139, 149,
+ 33, 69,
+ 70,
+ 21, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 27811, 25,
+ },
+ {
+ "nl-SR",
+ locale_compact_arr_98,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 21, 2, 26, 4, 5 },
+ 175, 182,
+ 1, 168,
+ 139, 149,
+ 33, 69,
+ 70,
+ 21, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 27862, 25,
+ },
+ {
+ "nl-SX",
+ locale_compact_arr_98,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 21, 2, 26, 4, 5 },
+ 175, 182,
+ 1, 168,
+ 139, 149,
+ 33, 69,
+ 70,
+ 21, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 27912, 25,
+ },
+ {
+ "nmg",
+ locale_compact_arr_0,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 176, 183,
+ 0, 169,
+ 140, 150,
+ 94, 0,
+ 0,
+ 7, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 27963, 23,
+ },
+ {
+ "nn",
+ locale_compact_arr_99,
+ { 1, 1, 0, 5, 0, 0, 0 },
+ { 0, 1, 16, 17, 2, 26, 18, 19 },
+ 171, 178,
+ 1, 170,
+ 36, 146,
+ 95, 70,
+ 68,
+ 29, 69,
+ 62, 63,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 11, 0,
+ 12, 3, 0,
+ 28009, 4,
+ },
+ {
+ "nnh",
+ locale_compact_arr_0,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 177, 184,
+ 0, 171,
+ 0, 151,
+ 96, 0,
+ 0,
+ 68, 8,
+ 179, 180,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 1, 12,
+ 12, 3, 0,
+ 28017, 23,
+ },
+ {
+ "no",
+ locale_compact_arr_96,
+ { 1, 1, 0, 5, 0, 0, 0 },
+ { 0, 1, 16, 17, 2, 26, 18, 19 },
+ 171, 178,
+ 1, 42,
+ 36, 146,
+ 33, 67,
+ 68,
+ 29, 69,
+ 62, 63,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 28063, 5,
+ },
+ {
+ "nqo",
+ locale_compact_arr_0,
+ { 0, 7, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 178, 185,
+ 108, 172,
+ 141, 152,
+ 97, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 28073, 181,
+ },
+ {
+ "nr",
+ locale_compact_arr_0,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 7, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 28675, 24,
+ },
+ {
+ "nso",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 6, 7, 4, 5 },
+ 179, 186,
+ 109, 173,
+ 142, 61,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 13, 13,
+ 12, 3, 0,
+ 28723, 24,
+ },
+ {
+ "nus",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 180, 187,
+ 110, 174,
+ 143, 153,
+ 98, 0,
+ 0,
+ 97, 16,
+ 9, 10,
+ 0, 1,
+ 77, 78,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 28771, 24,
+ },
+ {
+ "nv",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 28819, 23,
+ },
+ {
+ "ny",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 0, 1,
+ 2, 3,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 28865, 23,
+ },
+ {
+ "nyn",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 7, 4, 5 },
+ 38, 40,
+ 1, 34,
+ 29, 31,
+ 0, 0,
+ 0,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 28911, 24,
+ },
+ {
+ "oc",
+ locale_compact_arr_0,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 9, 10, 9, 10, 41, 42 },
+ 181, 188,
+ 0, 175,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 28959, 23,
+ },
+ {
+ "oc-ES",
+ locale_compact_arr_0,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 9, 10, 9, 10, 41, 42 },
+ 181, 188,
+ 0, 175,
+ 0, 154,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 29005, 23,
+ },
+ {
+ "oka",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 29051, 23,
+ },
+ {
+ "oka-US",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 29097, 23,
+ },
+ {
+ "om",
+ locale_compact_arr_100,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 7, 4, 5 },
+ 182, 189,
+ 111, 176,
+ 144, 155,
+ 99, 0,
+ 0,
+ 56, 57,
+ 58, 59,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 29143, 24,
+ },
+ {
+ "om-KE",
+ locale_compact_arr_100,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 7, 4, 5 },
+ 182, 189,
+ 111, 176,
+ 145, 156,
+ 99, 0,
+ 0,
+ 56, 57,
+ 58, 59,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 29191, 25,
+ },
+ {
+ "or",
+ locale_compact_arr_101,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 183, 190,
+ 112, 177,
+ 146, 157,
+ 0, 0,
+ 0,
+ 56, 57,
+ 58, 59,
+ 8, 9,
+ 10, 11,
+ 1, 1,
+ 1, 1,
+ 12, 3, 2,
+ 29241, 22,
+ },
+ {
+ "os",
+ locale_compact_arr_0,
+ { 1, 1, 0, 0, 0, 0, 19 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 184, 191,
+ 27, 178,
+ 147, 158,
+ 0, 0,
+ 0,
+ 27, 181,
+ 182, 183,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 29285, 24,
+ },
+ {
+ "os-RU",
+ locale_compact_arr_0,
+ { 1, 1, 0, 0, 0, 0, 19 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 184, 191,
+ 27, 178,
+ 147, 158,
+ 0, 0,
+ 0,
+ 27, 181,
+ 182, 183,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 29334, 24,
+ },
+ {
+ "osa",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 185, 192,
+ 0, 179,
+ 148, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 29382, 23,
+ },
+ {
+ "pa",
+ locale_compact_arr_102,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 2, 3, 4, 5 },
+ 186, 193,
+ 113, 180,
+ 149, 159,
+ 0, 71,
+ 71,
+ 11, 16,
+ 9, 24,
+ 8, 9,
+ 10, 11,
+ 1, 1,
+ 0, 0,
+ 12, 3, 2,
+ 29428, 22,
+ },
+ {
+ "pa-Arab",
+ locale_compact_arr_0,
+ { 2, 2, 3, 3, 3, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 187, 194,
+ 0, 181,
+ 0, 160,
+ 0, 0,
+ 0,
+ 15, 16,
+ 9, 83,
+ 8, 9,
+ 10, 11,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 29472, 24,
+ },
+ {
+ "pa-Guru",
+ locale_compact_arr_102,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 2, 3, 4, 5 },
+ 186, 193,
+ 113, 180,
+ 149, 159,
+ 0, 71,
+ 71,
+ 11, 16,
+ 9, 24,
+ 8, 9,
+ 10, 11,
+ 1, 1,
+ 0, 0,
+ 12, 3, 2,
+ 29521, 22,
+ },
+ {
+ "pap",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 188, 195,
+ 0, 182,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 29565, 23,
+ },
+ {
+ "pap-AW",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 188, 195,
+ 0, 182,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 29611, 23,
+ },
+ {
+ "pcm",
+ locale_compact_arr_103,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 7, 4, 5 },
+ 189, 196,
+ 1, 183,
+ 0, 161,
+ 100, 0,
+ 0,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 14, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 29657, 23,
+ },
+ {
+ "pi",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 29704, 23,
+ },
+ {
+ "pi-Latn",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 29750, 23,
+ },
+ {
+ "pis",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 190, 197,
+ 0, 184,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 29796, 24,
+ },
+ {
+ "pl",
+ locale_compact_arr_104,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 4, 5 },
+ 191, 198,
+ 114, 185,
+ 150, 162,
+ 0, 72,
+ 72,
+ 184, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 0, 0,
+ 4, 3, 0,
+ 29844, 8,
+ },
+ {
+ "pms",
+ locale_compact_arr_0,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 192, 199,
+ 0, 186,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 29861, 23,
+ },
+ {
+ "prg",
+ locale_compact_arr_0,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 193, 200,
+ 0, 187,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 29907, 23,
+ },
+ {
+ "ps",
+ locale_compact_arr_105,
+ { 2, 2, 3, 3, 3, 0, 0 },
+ { 0, 1, 2, 3, 6, 8, 4, 5 },
+ 194, 201,
+ 50, 188,
+ 0, 163,
+ 101, 0,
+ 0,
+ 106, 1,
+ 2, 185,
+ 12, 13,
+ 51, 31,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 29953, 24,
+ },
+ {
+ "ps-PK",
+ locale_compact_arr_105,
+ { 2, 2, 3, 3, 3, 0, 0 },
+ { 0, 1, 2, 3, 6, 8, 4, 5 },
+ 194, 201,
+ 50, 188,
+ 0, 163,
+ 101, 0,
+ 0,
+ 106, 1,
+ 2, 185,
+ 8, 9,
+ 10, 11,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 30001, 25,
+ },
+ {
+ "pt",
+ locale_compact_arr_106,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 195, 202,
+ 1, 189,
+ 151, 164,
+ 0, 73,
+ 73,
+ 15, 116,
+ 92, 93,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 30051, 24,
+ },
+ {
+ "pt-AO",
+ locale_compact_arr_107,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 4, 5 },
+ 195, 202,
+ 1, 189,
+ 151, 164,
+ 33, 73,
+ 74,
+ 68, 15,
+ 92, 93,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 30100, 25,
+ },
+ {
+ "pt-CH",
+ locale_compact_arr_107,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 4, 5 },
+ 195, 202,
+ 1, 189,
+ 151, 164,
+ 33, 73,
+ 74,
+ 68, 15,
+ 92, 93,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 30152, 24,
+ },
+ {
+ "pt-CV",
+ locale_compact_arr_107,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 4, 5 },
+ 195, 202,
+ 1, 189,
+ 151, 164,
+ 33, 73,
+ 74,
+ 68, 15,
+ 92, 93,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 30200, 24,
+ },
+ {
+ "pt-GQ",
+ locale_compact_arr_107,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 4, 5 },
+ 195, 202,
+ 1, 189,
+ 151, 164,
+ 33, 73,
+ 74,
+ 68, 15,
+ 92, 93,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 30249, 24,
+ },
+ {
+ "pt-GW",
+ locale_compact_arr_107,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 4, 5 },
+ 195, 202,
+ 1, 189,
+ 151, 164,
+ 33, 73,
+ 74,
+ 68, 15,
+ 92, 93,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 30297, 24,
+ },
+ {
+ "pt-LU",
+ locale_compact_arr_107,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 4, 5 },
+ 195, 202,
+ 1, 189,
+ 151, 164,
+ 33, 73,
+ 74,
+ 68, 15,
+ 92, 93,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 30345, 25,
+ },
+ {
+ "pt-MO",
+ locale_compact_arr_107,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 4, 5 },
+ 195, 202,
+ 1, 189,
+ 151, 164,
+ 33, 73,
+ 74,
+ 68, 15,
+ 92, 93,
+ 0, 1,
+ 2, 3,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 30396, 25,
+ },
+ {
+ "pt-MZ",
+ locale_compact_arr_107,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 4, 5 },
+ 195, 202,
+ 1, 189,
+ 151, 164,
+ 33, 73,
+ 74,
+ 68, 15,
+ 92, 93,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 30447, 25,
+ },
+ {
+ "pt-PT",
+ locale_compact_arr_107,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 4, 5 },
+ 195, 202,
+ 1, 189,
+ 151, 164,
+ 33, 73,
+ 74,
+ 68, 15,
+ 92, 93,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 30499, 24,
+ },
+ {
+ "pt-ST",
+ locale_compact_arr_107,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 4, 5 },
+ 195, 202,
+ 1, 189,
+ 151, 164,
+ 33, 73,
+ 74,
+ 68, 15,
+ 92, 93,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 30547, 25,
+ },
+ {
+ "pt-TL",
+ locale_compact_arr_107,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 4, 5 },
+ 195, 202,
+ 1, 189,
+ 151, 164,
+ 33, 73,
+ 74,
+ 68, 15,
+ 92, 93,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 30599, 24,
+ },
+ {
+ "qu",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 18, 19 },
+ 196, 203,
+ 0, 190,
+ 52, 165,
+ 33, 0,
+ 0,
+ 11, 16,
+ 9, 23,
+ 0, 1,
+ 2, 3,
+ 0, 0,
+ 3, 0,
+ 12, 3, 0,
+ 30647, 26,
+ },
+ {
+ "qu-BO",
+ locale_compact_arr_0,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 18, 19 },
+ 196, 203,
+ 0, 190,
+ 52, 165,
+ 33, 0,
+ 0,
+ 11, 16,
+ 9, 23,
+ 0, 1,
+ 2, 3,
+ 0, 0,
+ 3, 0,
+ 12, 3, 0,
+ 30704, 26,
+ },
+ {
+ "qu-EC",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 18, 19 },
+ 196, 203,
+ 0, 190,
+ 52, 165,
+ 33, 0,
+ 0,
+ 11, 16,
+ 9, 23,
+ 0, 1,
+ 2, 3,
+ 0, 0,
+ 3, 0,
+ 12, 3, 0,
+ 30760, 25,
+ },
+ {
+ "quc",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 30813, 24,
+ },
+ {
+ "raj",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 23, 24,
+ 0, 83,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 8, 9,
+ 10, 11,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 30862, 23,
+ },
+ {
+ "rhg",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 12, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 30908, 23,
+ },
+ {
+ "rhg-Rohg",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 12, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 30954, 23,
+ },
+ {
+ "rhg-Rohg-BD",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 8, 9,
+ 10, 11,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 31000, 23,
+ },
+ {
+ "rif",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 31046, 23,
+ },
+ {
+ "rm",
+ locale_compact_arr_108,
+ { 1, 5, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 197, 204,
+ 115, 191,
+ 152, 166,
+ 0, 0,
+ 0,
+ 95, 21,
+ 9, 186,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 31092, 23,
+ },
+ {
+ "rn",
+ locale_compact_arr_0,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 9, 10, 9, 10, 18, 19 },
+ 198, 205,
+ 0, 192,
+ 0, 167,
+ 102, 0,
+ 0,
+ 7, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 31138, 24,
+ },
+ {
+ "ro",
+ locale_compact_arr_109,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 18, 19 },
+ 199, 206,
+ 116, 193,
+ 53, 168,
+ 33, 74,
+ 75,
+ 29, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 31187, 5,
+ },
+ {
+ "ro-MD",
+ locale_compact_arr_109,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 18, 19 },
+ 199, 206,
+ 116, 193,
+ 153, 168,
+ 33, 75,
+ 76,
+ 29, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 31197, 6,
+ },
+ {
+ "rof",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 7, 4, 5 },
+ 200, 207,
+ 117, 194,
+ 89, 169,
+ 103, 0,
+ 0,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 31210, 24,
+ },
+ {
+ "ru",
+ locale_compact_arr_110,
+ { 1, 1, 0, 0, 0, 0, 20 },
+ { 0, 1, 16, 17, 16, 17, 18, 19 },
+ 201, 208,
+ 27, 195,
+ 154, 170,
+ 0, 76,
+ 77,
+ 29, 35,
+ 36, 37,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 31258, 27,
+ },
+ {
+ "ru-BY",
+ locale_compact_arr_110,
+ { 1, 1, 0, 0, 0, 0, 20 },
+ { 0, 1, 16, 17, 16, 17, 18, 19 },
+ 201, 208,
+ 27, 195,
+ 154, 170,
+ 0, 76,
+ 77,
+ 29, 35,
+ 36, 37,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 31312, 27,
+ },
+ {
+ "ru-KG",
+ locale_compact_arr_110,
+ { 1, 1, 0, 0, 0, 0, 20 },
+ { 0, 1, 16, 17, 16, 17, 18, 19 },
+ 201, 208,
+ 27, 195,
+ 154, 170,
+ 0, 76,
+ 77,
+ 29, 35,
+ 36, 37,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 31366, 28,
+ },
+ {
+ "ru-KZ",
+ locale_compact_arr_110,
+ { 1, 1, 0, 0, 0, 0, 20 },
+ { 0, 1, 16, 17, 16, 17, 18, 19 },
+ 201, 208,
+ 27, 195,
+ 154, 170,
+ 0, 76,
+ 77,
+ 29, 35,
+ 36, 37,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 31424, 28,
+ },
+ {
+ "ru-MD",
+ locale_compact_arr_110,
+ { 1, 1, 0, 0, 0, 0, 20 },
+ { 0, 1, 16, 17, 16, 17, 18, 19 },
+ 201, 208,
+ 27, 195,
+ 154, 170,
+ 0, 76,
+ 77,
+ 29, 35,
+ 36, 37,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 31480, 28,
+ },
+ {
+ "ru-UA",
+ locale_compact_arr_110,
+ { 1, 1, 0, 0, 0, 0, 20 },
+ { 0, 1, 16, 17, 16, 17, 18, 19 },
+ 201, 208,
+ 27, 195,
+ 154, 170,
+ 0, 76,
+ 77,
+ 29, 35,
+ 36, 37,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 31537, 27,
+ },
+ {
+ "rw",
+ locale_compact_arr_0,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 202, 205,
+ 0, 196,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 31591, 24,
+ },
+ {
+ "rwk",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 9, 10, 9, 10, 4, 5 },
+ 106, 114,
+ 1, 97,
+ 7, 89,
+ 56, 0,
+ 0,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 31641, 24,
+ },
+ {
+ "sa",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 2, 3, 4, 5 },
+ 203, 209,
+ 94, 197,
+ 71, 0,
+ 0, 0,
+ 0,
+ 11, 16,
+ 9, 24,
+ 8, 9,
+ 10, 11,
+ 1, 1,
+ 1, 1,
+ 12, 3, 2,
+ 31689, 23,
+ },
+ {
+ "sah",
+ locale_compact_arr_111,
+ { 1, 1, 0, 0, 0, 0, 21 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 204, 210,
+ 118, 198,
+ 155, 171,
+ 104, 0,
+ 0,
+ 102, 187,
+ 188, 189,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 31735, 24,
+ },
+ {
+ "saq",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 205, 211,
+ 119, 199,
+ 156, 172,
+ 105, 0,
+ 0,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 31783, 24,
+ },
+ {
+ "sat",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 206, 212,
+ 120, 200,
+ 157, 173,
+ 0, 0,
+ 0,
+ 11, 16,
+ 9, 24,
+ 8, 9,
+ 10, 11,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 31831, 23,
+ },
+ {
+ "sat-Deva",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 31877, 23,
+ },
+ {
+ "sat-Olck",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 206, 212,
+ 120, 200,
+ 157, 173,
+ 0, 0,
+ 0,
+ 11, 16,
+ 9, 24,
+ 8, 9,
+ 10, 11,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 31923, 23,
+ },
+ {
+ "sbp",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 9, 10, 9, 10, 4, 5 },
+ 207, 213,
+ 0, 201,
+ 158, 174,
+ 106, 0,
+ 0,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 31969, 24,
+ },
+ {
+ "sc",
+ locale_compact_arr_112,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 4, 5 },
+ 208, 214,
+ 121, 202,
+ 159, 175,
+ 0, 0,
+ 0,
+ 15, 190,
+ 191, 192,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 32017, 24,
+ },
+ {
+ "scn",
+ locale_compact_arr_113,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 209, 215,
+ 122, 203,
+ 76, 176,
+ 0, 0,
+ 0,
+ 11, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 32067, 23,
+ },
+ {
+ "sd",
+ locale_compact_arr_114,
+ { 0, 2, 2, 2, 2, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 210, 216,
+ 1, 204,
+ 160, 177,
+ 107, 0,
+ 0,
+ 0, 1,
+ 2, 59,
+ 8, 9,
+ 10, 11,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 32113, 23,
+ },
+ {
+ "sd-Arab",
+ locale_compact_arr_114,
+ { 0, 2, 2, 2, 2, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 210, 216,
+ 1, 204,
+ 160, 177,
+ 107, 0,
+ 0,
+ 0, 1,
+ 2, 59,
+ 8, 9,
+ 10, 11,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 32159, 23,
+ },
+ {
+ "sd-Deva",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 211, 217,
+ 123, 205,
+ 161, 178,
+ 0, 0,
+ 0,
+ 56, 57,
+ 58, 59,
+ 8, 9,
+ 10, 11,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 32205, 23,
+ },
+ {
+ "sdh",
+ locale_compact_arr_0,
+ { 2, 2, 2, 2, 2, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 32251, 23,
+ },
+ {
+ "sdh-IQ",
+ locale_compact_arr_0,
+ { 2, 2, 2, 2, 2, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 32297, 23,
+ },
+ {
+ "se",
+ locale_compact_arr_115,
+ { 1, 1, 0, 5, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 18, 19 },
+ 212, 218,
+ 124, 206,
+ 162, 179,
+ 108, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 32343, 27,
+ },
+ {
+ "se-FI",
+ locale_compact_arr_116,
+ { 1, 1, 0, 5, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 18, 19 },
+ 212, 219,
+ 124, 207,
+ 163, 180,
+ 109, 0,
+ 0,
+ 29, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 32398, 27,
+ },
+ {
+ "se-SE",
+ locale_compact_arr_115,
+ { 1, 1, 0, 5, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 18, 19 },
+ 212, 218,
+ 124, 206,
+ 162, 179,
+ 108, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 32453, 27,
+ },
+ {
+ "seh",
+ locale_compact_arr_0,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 9, 10, 9, 10, 4, 5 },
+ 213, 220,
+ 1, 208,
+ 164, 181,
+ 0, 0,
+ 0,
+ 7, 116,
+ 92, 93,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 32508, 24,
+ },
+ {
+ "ses",
+ locale_compact_arr_0,
+ { 0, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 9, 10, 9, 10, 4, 5 },
+ 50, 52,
+ 34, 209,
+ 92, 40,
+ 61, 0,
+ 0,
+ 7, 8,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 32558, 23,
+ },
+ {
+ "sg",
+ locale_compact_arr_0,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 25, 6, 25, 4, 5 },
+ 214, 221,
+ 125, 210,
+ 165, 182,
+ 110, 0,
+ 0,
+ 7, 8,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 32604, 23,
+ },
+ {
+ "sgs",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 32650, 23,
+ },
+ {
+ "shi",
+ locale_compact_arr_0,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 9, 10, 9, 10, 4, 5 },
+ 215, 222,
+ 126, 211,
+ 0, 183,
+ 111, 0,
+ 0,
+ 7, 8,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 32696, 23,
+ },
+ {
+ "shi-Latn",
+ locale_compact_arr_0,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 9, 10, 9, 10, 4, 5 },
+ 216, 223,
+ 127, 212,
+ 0, 184,
+ 112, 0,
+ 0,
+ 7, 8,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 32742, 23,
+ },
+ {
+ "shi-Tfng",
+ locale_compact_arr_0,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 9, 10, 9, 10, 4, 5 },
+ 215, 222,
+ 126, 211,
+ 0, 183,
+ 111, 0,
+ 0,
+ 7, 8,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 32788, 23,
+ },
+ {
+ "shn",
+ locale_compact_arr_117,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 217, 224,
+ 128, 213,
+ 166, 185,
+ 113, 0,
+ 0,
+ 0, 1,
+ 2, 193,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 32834, 23,
+ },
+ {
+ "shn-TH",
+ locale_compact_arr_117,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 217, 224,
+ 128, 213,
+ 166, 185,
+ 113, 0,
+ 0,
+ 0, 1,
+ 2, 193,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 32880, 23,
+ },
+ {
+ "si",
+ locale_compact_arr_118,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 218, 225,
+ 129, 214,
+ 167, 186,
+ 114, 77,
+ 78,
+ 0, 1,
+ 2, 3,
+ 35, 36,
+ 37, 38,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 32926, 24,
+ },
+ {
+ "sid",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 32977, 24,
+ },
+ {
+ "sk",
+ locale_compact_arr_119,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 18, 19 },
+ 219, 226,
+ 36, 215,
+ 168, 187,
+ 0, 78,
+ 79,
+ 61, 61,
+ 62, 63,
+ 12, 13,
+ 14, 15,
+ 0, 1,
+ 1, 1,
+ 12, 3, 0,
+ 33025, 8,
+ },
+ {
+ "skr",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 33042, 23,
+ },
+ {
+ "sl",
+ locale_compact_arr_120,
+ { 1, 3, 0, 5, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 18, 19 },
+ 220, 227,
+ 36, 216,
+ 169, 188,
+ 49, 79,
+ 80,
+ 61, 69,
+ 62, 71,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 0, 0,
+ 12, 3, 0,
+ 33088, 14,
+ },
+ {
+ "sma",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 33116, 23,
+ },
+ {
+ "sma-NO",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 33162, 23,
+ },
+ {
+ "smj",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 33208, 23,
+ },
+ {
+ "smj-NO",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 33254, 23,
+ },
+ {
+ "smn",
+ locale_compact_arr_121,
+ { 1, 1, 0, 0, 0, 0, 22 },
+ { 0, 1, 16, 17, 16, 17, 18, 19 },
+ 221, 228,
+ 130, 217,
+ 170, 189,
+ 115, 0,
+ 0,
+ 76, 194,
+ 195, 196,
+ 47, 48,
+ 49, 50,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 33300, 23,
+ },
+ {
+ "sms",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 33346, 23,
+ },
+ {
+ "sn",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 222, 229,
+ 131, 218,
+ 171, 190,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 33392, 23,
+ },
+ {
+ "so",
+ locale_compact_arr_122,
+ { 0, 0, 0, 0, 0, 0, 23 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 223, 230,
+ 132, 219,
+ 172, 191,
+ 116, 0,
+ 0,
+ 68, 84,
+ 58, 59,
+ 0, 1,
+ 2, 3,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 33438, 25,
+ },
+ {
+ "so-DJ",
+ locale_compact_arr_122,
+ { 0, 0, 0, 0, 0, 0, 23 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 223, 230,
+ 132, 219,
+ 172, 191,
+ 116, 0,
+ 0,
+ 68, 84,
+ 58, 59,
+ 0, 1,
+ 2, 3,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 33489, 26,
+ },
+ {
+ "so-ET",
+ locale_compact_arr_122,
+ { 0, 0, 0, 0, 0, 0, 23 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 223, 230,
+ 132, 219,
+ 172, 191,
+ 116, 0,
+ 0,
+ 68, 84,
+ 58, 59,
+ 0, 1,
+ 2, 3,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 33543, 26,
+ },
+ {
+ "so-KE",
+ locale_compact_arr_122,
+ { 0, 0, 0, 0, 0, 0, 23 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 223, 230,
+ 132, 219,
+ 172, 191,
+ 116, 0,
+ 0,
+ 68, 84,
+ 58, 59,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 33596, 26,
+ },
+ {
+ "sq",
+ locale_compact_arr_123,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 4, 5 },
+ 224, 231,
+ 133, 220,
+ 173, 192,
+ 117, 80,
+ 81,
+ 75, 16,
+ 9, 24,
+ 0, 1,
+ 79, 80,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 33649, 23,
+ },
+ {
+ "sq-MK",
+ locale_compact_arr_123,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 4, 5 },
+ 224, 231,
+ 133, 220,
+ 173, 192,
+ 117, 80,
+ 81,
+ 75, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 33697, 24,
+ },
+ {
+ "sq-XK",
+ locale_compact_arr_123,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 4, 5 },
+ 224, 231,
+ 133, 220,
+ 173, 192,
+ 117, 80,
+ 81,
+ 75, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 33749, 23,
+ },
+ {
+ "sr",
+ locale_compact_arr_124,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 4, 5 },
+ 225, 232,
+ 24, 221,
+ 23, 193,
+ 0, 81,
+ 82,
+ 46, 46,
+ 48, 49,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 33797, 19,
+ },
+ {
+ "sr-Cyrl",
+ locale_compact_arr_124,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 4, 5 },
+ 225, 232,
+ 24, 221,
+ 23, 193,
+ 0, 81,
+ 82,
+ 46, 46,
+ 48, 49,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 33835, 19,
+ },
+ {
+ "sr-Cyrl-BA",
+ locale_compact_arr_124,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 4, 5 },
+ 225, 232,
+ 24, 27,
+ 23, 26,
+ 118, 81,
+ 83,
+ 46, 46,
+ 48, 49,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 33873, 19,
+ },
+ {
+ "sr-Cyrl-ME",
+ locale_compact_arr_124,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 4, 5 },
+ 225, 233,
+ 24, 222,
+ 23, 26,
+ 118, 82,
+ 84,
+ 46, 46,
+ 48, 49,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 33911, 19,
+ },
+ {
+ "sr-Cyrl-XK",
+ locale_compact_arr_124,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 4, 5 },
+ 225, 233,
+ 24, 221,
+ 23, 193,
+ 0, 83,
+ 84,
+ 46, 46,
+ 48, 49,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 33949, 19,
+ },
+ {
+ "sr-Latn",
+ locale_compact_arr_16,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 4, 5 },
+ 226, 234,
+ 36, 223,
+ 174, 194,
+ 0, 84,
+ 85,
+ 46, 46,
+ 48, 49,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 33987, 19,
+ },
+ {
+ "sr-Latn-BA",
+ locale_compact_arr_16,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 4, 5 },
+ 226, 234,
+ 36, 26,
+ 174, 195,
+ 119, 84,
+ 86,
+ 46, 46,
+ 48, 49,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 34025, 19,
+ },
+ {
+ "sr-Latn-ME",
+ locale_compact_arr_16,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 4, 5 },
+ 226, 235,
+ 36, 224,
+ 174, 195,
+ 119, 85,
+ 87,
+ 46, 46,
+ 48, 49,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 34063, 19,
+ },
+ {
+ "sr-Latn-XK",
+ locale_compact_arr_16,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 4, 5 },
+ 226, 235,
+ 36, 223,
+ 174, 194,
+ 0, 86,
+ 87,
+ 46, 46,
+ 48, 49,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 34101, 19,
+ },
+ {
+ "ss",
+ locale_compact_arr_0,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 7, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 34139, 25,
+ },
+ {
+ "ss-SZ",
+ locale_compact_arr_0,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 7, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 0, 1,
+ 2, 3,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 34191, 25,
+ },
+ {
+ "ssy",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 2, 3,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 34243, 24,
+ },
+ {
+ "st",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 7, 4, 5 },
+ 227, 236,
+ 0, 225,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 34291, 24,
+ },
+ {
+ "st-LS",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 7, 4, 5 },
+ 227, 236,
+ 0, 225,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 0, 1,
+ 2, 3,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 34339, 25,
+ },
+ {
+ "su",
+ locale_compact_arr_0,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 7, 4, 5 },
+ 228, 237,
+ 134, 226,
+ 77, 196,
+ 0, 0,
+ 0,
+ 11, 16,
+ 9, 24,
+ 47, 48,
+ 49, 50,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 34390, 24,
+ },
+ {
+ "su-Latn",
+ locale_compact_arr_0,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 7, 4, 5 },
+ 228, 237,
+ 134, 226,
+ 77, 196,
+ 0, 0,
+ 0,
+ 11, 16,
+ 9, 24,
+ 47, 48,
+ 49, 50,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 34438, 24,
+ },
+ {
+ "suz",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 34486, 23,
+ },
+ {
+ "suz-Deva",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 34532, 23,
+ },
+ {
+ "suz-Sunu",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 34578, 23,
+ },
+ {
+ "sv",
+ locale_compact_arr_125,
+ { 1, 1, 0, 5, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 18, 19 },
+ 229, 238,
+ 1, 227,
+ 36, 197,
+ 120, 87,
+ 88,
+ 0, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 34624, 24,
+ },
+ {
+ "sv-AX",
+ locale_compact_arr_125,
+ { 1, 1, 0, 5, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 18, 19 },
+ 229, 238,
+ 1, 227,
+ 36, 197,
+ 120, 87,
+ 88,
+ 76, 76,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 34685, 24,
+ },
+ {
+ "sv-FI",
+ locale_compact_arr_125,
+ { 1, 1, 0, 5, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 18, 19 },
+ 229, 238,
+ 1, 227,
+ 36, 197,
+ 120, 87,
+ 88,
+ 76, 16,
+ 9, 10,
+ 47, 48,
+ 49, 38,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 34746, 24,
+ },
+ {
+ "sw",
+ locale_compact_arr_126,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 11, 114,
+ 1, 7,
+ 0, 38,
+ 0, 88,
+ 89,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 34807, 25,
+ },
+ {
+ "sw-CD",
+ locale_compact_arr_126,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 11, 114,
+ 1, 7,
+ 0, 38,
+ 0, 88,
+ 89,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 34857, 26,
+ },
+ {
+ "sw-KE",
+ locale_compact_arr_127,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 11, 114,
+ 1, 7,
+ 0, 38,
+ 0, 88,
+ 89,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 34909, 25,
+ },
+ {
+ "sw-UG",
+ locale_compact_arr_126,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 11, 114,
+ 1, 7,
+ 0, 38,
+ 0, 88,
+ 89,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 34959, 26,
+ },
+ {
+ "syr",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 24 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 230, 239,
+ 135, 228,
+ 175, 198,
+ 121, 0,
+ 0,
+ 197, 198,
+ 199, 200,
+ 8, 9,
+ 10, 11,
+ 2, 2,
+ 2, 2,
+ 12, 3, 0,
+ 35011, 24,
+ },
+ {
+ "syr-SY",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 24 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 230, 239,
+ 135, 228,
+ 175, 198,
+ 121, 0,
+ 0,
+ 197, 198,
+ 199, 200,
+ 8, 9,
+ 10, 11,
+ 2, 2,
+ 2, 2,
+ 12, 3, 0,
+ 35059, 24,
+ },
+ {
+ "szl",
+ locale_compact_arr_0,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 231, 240,
+ 0, 229,
+ 0, 0,
+ 122, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 35107, 24,
+ },
+ {
+ "ta",
+ locale_compact_arr_128,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 232, 241,
+ 136, 230,
+ 176, 199,
+ 0, 89,
+ 90,
+ 11, 8,
+ 22, 23,
+ 8, 9,
+ 10, 11,
+ 1, 1,
+ 1, 1,
+ 12, 3, 2,
+ 35156, 23,
+ },
+ {
+ "ta-LK",
+ locale_compact_arr_128,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 232, 241,
+ 136, 230,
+ 176, 199,
+ 0, 89,
+ 90,
+ 11, 8,
+ 22, 23,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 2,
+ 35202, 24,
+ },
+ {
+ "ta-MY",
+ locale_compact_arr_128,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 6, 8, 4, 5 },
+ 232, 241,
+ 136, 230,
+ 176, 199,
+ 0, 89,
+ 90,
+ 11, 8,
+ 22, 23,
+ 8, 9,
+ 10, 11,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 35252, 25,
+ },
+ {
+ "ta-SG",
+ locale_compact_arr_128,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 6, 8, 4, 5 },
+ 232, 241,
+ 136, 230,
+ 176, 199,
+ 0, 89,
+ 90,
+ 11, 8,
+ 22, 23,
+ 8, 9,
+ 10, 11,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 35303, 25,
+ },
+ {
+ "te",
+ locale_compact_arr_129,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 233, 242,
+ 137, 231,
+ 177, 200,
+ 0, 90,
+ 91,
+ 95, 8,
+ 22, 201,
+ 8, 9,
+ 10, 11,
+ 0, 0,
+ 0, 0,
+ 12, 3, 2,
+ 35353, 23,
+ },
+ {
+ "teo",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 234, 243,
+ 138, 232,
+ 178, 172,
+ 123, 0,
+ 0,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 35399, 24,
+ },
+ {
+ "teo-KE",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 234, 243,
+ 138, 232,
+ 178, 172,
+ 123, 0,
+ 0,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 35447, 25,
+ },
+ {
+ "tg",
+ locale_compact_arr_130,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 235, 244,
+ 27, 233,
+ 179, 201,
+ 0, 0,
+ 0,
+ 68, 4,
+ 5, 83,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 35497, 24,
+ },
+ {
+ "th",
+ locale_compact_arr_131,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 236, 245,
+ 139, 234,
+ 180, 202,
+ 0, 91,
+ 92,
+ 11, 16,
+ 202, 203,
+ 4, 5,
+ 81, 82,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 35547, 22,
+ },
+ {
+ "ti",
+ locale_compact_arr_132,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 7, 4, 5 },
+ 237, 246,
+ 140, 235,
+ 181, 203,
+ 124, 0,
+ 0,
+ 56, 57,
+ 58, 204,
+ 8, 9,
+ 10, 11,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 35591, 22,
+ },
+ {
+ "ti-ER",
+ locale_compact_arr_132,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 7, 4, 5 },
+ 237, 246,
+ 140, 235,
+ 181, 4,
+ 124, 0,
+ 0,
+ 56, 57,
+ 58, 204,
+ 8, 9,
+ 10, 11,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 35635, 23,
+ },
+ {
+ "tig",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 35681, 24,
+ },
+ {
+ "tk",
+ locale_compact_arr_133,
+ { 1, 1, 0, 0, 0, 0, 25 },
+ { 0, 1, 16, 17, 16, 17, 18, 19 },
+ 238, 247,
+ 141, 236,
+ 182, 204,
+ 125, 0,
+ 0,
+ 29, 16,
+ 9, 205,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 35729, 20,
+ },
+ {
+ "tn",
+ locale_compact_arr_0,
+ { 0, 4, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 7, 4, 5 },
+ 239, 248,
+ 0, 237,
+ 0, 205,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 13, 13,
+ 12, 3, 0,
+ 35770, 24,
+ },
+ {
+ "tn-BW",
+ locale_compact_arr_0,
+ { 0, 4, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 7, 4, 5 },
+ 239, 248,
+ 0, 237,
+ 0, 205,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 13, 13,
+ 12, 3, 0,
+ 35818, 25,
+ },
+ {
+ "to",
+ locale_compact_arr_134,
+ { 0, 0, 0, 0, 0, 0, 26 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 240, 249,
+ 142, 238,
+ 183, 206,
+ 126, 0,
+ 0,
+ 11, 16,
+ 9, 10,
+ 0, 1,
+ 2, 3,
+ 0, 1,
+ 1, 1,
+ 12, 3, 0,
+ 35870, 24,
+ },
+ {
+ "tok",
+ locale_compact_arr_0,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 7, 4, 5 },
+ 241, 250,
+ 0, 239,
+ 9, 0,
+ 0, 0,
+ 0,
+ 0, 206,
+ 207, 206,
+ 4, 5,
+ 83, 84,
+ 0, 0,
+ 0, 0,
+ 12, 2, 0,
+ 35922, 23,
+ },
+ {
+ "tpi",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 242, 251,
+ 0, 240,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 35968, 23,
+ },
+ {
+ "tr",
+ locale_compact_arr_135,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 38, 39 },
+ 243, 252,
+ 143, 241,
+ 184, 207,
+ 127, 92,
+ 93,
+ 184, 16,
+ 9, 205,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 36014, 24,
+ },
+ {
+ "tr-CY",
+ locale_compact_arr_135,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 38, 39 },
+ 243, 252,
+ 143, 241,
+ 184, 207,
+ 127, 92,
+ 93,
+ 184, 16,
+ 9, 205,
+ 0, 1,
+ 2, 3,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 36062, 24,
+ },
+ {
+ "trv",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 36110, 23,
+ },
+ {
+ "trw",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 36156, 23,
+ },
+ {
+ "ts",
+ locale_compact_arr_0,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 244, 253,
+ 0, 242,
+ 0, 208,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 36202, 24,
+ },
+ {
+ "tt",
+ locale_compact_arr_136,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 18, 19 },
+ 245, 254,
+ 0, 243,
+ 185, 209,
+ 0, 0,
+ 0,
+ 29, 208,
+ 209, 210,
+ 12, 13,
+ 14, 15,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 36250, 24,
+ },
+ {
+ "twq",
+ locale_compact_arr_0,
+ { 0, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 9, 10, 9, 10, 4, 5 },
+ 50, 52,
+ 34, 209,
+ 92, 40,
+ 25, 0,
+ 0,
+ 7, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 36298, 23,
+ },
+ {
+ "tyv",
+ locale_compact_arr_0,
+ { 0, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 246, 255,
+ 27, 244,
+ 186, 210,
+ 0, 0,
+ 0,
+ 0, 211,
+ 212, 213,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 36344, 23,
+ },
+ {
+ "tzm",
+ locale_compact_arr_0,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 247, 256,
+ 144, 245,
+ 187, 211,
+ 128, 0,
+ 0,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 36390, 23,
+ },
+ {
+ "ug",
+ locale_compact_arr_137,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 248, 257,
+ 0, 246,
+ 188, 212,
+ 129, 0,
+ 0,
+ 0, 214,
+ 215, 216,
+ 4, 5,
+ 6, 7,
+ 2, 2,
+ 0, 0,
+ 12, 3, 0,
+ 36436, 23,
+ },
+ {
+ "uk",
+ locale_compact_arr_138,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 249, 258,
+ 145, 247,
+ 189, 213,
+ 130, 93,
+ 94,
+ 27, 217,
+ 218, 219,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 36483, 8,
+ },
+ {
+ "und",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 36501, 23,
+ },
+ {
+ "ur",
+ locale_compact_arr_139,
+ { 0, 0, 1, 1, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 250, 259,
+ 1, 248,
+ 0, 214,
+ 0, 94,
+ 95,
+ 11, 220,
+ 221, 222,
+ 8, 9,
+ 10, 11,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 36547, 24,
+ },
+ {
+ "ur-IN",
+ locale_compact_arr_139,
+ { 2, 2, 3, 3, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 250, 259,
+ 1, 248,
+ 0, 214,
+ 0, 94,
+ 95,
+ 11, 220,
+ 221, 222,
+ 8, 9,
+ 10, 11,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 36595, 23,
+ },
+ {
+ "uz",
+ locale_compact_arr_140,
+ { 1, 1, 0, 0, 0, 0, 27 },
+ { 0, 1, 16, 17, 6, 8, 4, 5 },
+ 251, 260,
+ 146, 249,
+ 190, 215,
+ 131, 95,
+ 96,
+ 68, 223,
+ 224, 225,
+ 4, 5,
+ 51, 31,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 36641, 23,
+ },
+ {
+ "uz-Arab",
+ locale_compact_arr_0,
+ { 2, 2, 3, 3, 3, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 70, 261,
+ 0, 62,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 36689, 24,
+ },
+ {
+ "uz-Cyrl",
+ locale_compact_arr_141,
+ { 1, 1, 0, 0, 0, 0, 28 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 252, 38,
+ 27, 250,
+ 191, 216,
+ 132, 96,
+ 97,
+ 68, 8,
+ 22, 138,
+ 4, 5,
+ 33, 34,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 36737, 25,
+ },
+ {
+ "uz-Latn",
+ locale_compact_arr_140,
+ { 1, 1, 0, 0, 0, 0, 27 },
+ { 0, 1, 16, 17, 6, 8, 4, 5 },
+ 251, 260,
+ 146, 249,
+ 190, 215,
+ 131, 95,
+ 96,
+ 68, 223,
+ 224, 225,
+ 4, 5,
+ 51, 31,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 36789, 23,
+ },
+ {
+ "vai",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 253, 262,
+ 0, 251,
+ 0, 0,
+ 0, 0,
+ 0,
+ 15, 16,
+ 9, 24,
+ 8, 9,
+ 10, 11,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 36837, 24,
+ },
+ {
+ "vai-Latn",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 0, 0,
+ 0, 252,
+ 0, 0,
+ 0, 0,
+ 0,
+ 15, 16,
+ 9, 24,
+ 0, 1,
+ 2, 3,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 36885, 24,
+ },
+ {
+ "vai-Vaii",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 253, 262,
+ 0, 251,
+ 0, 0,
+ 0, 0,
+ 0,
+ 15, 16,
+ 9, 24,
+ 8, 9,
+ 10, 11,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 36933, 24,
+ },
+ {
+ "ve",
+ locale_compact_arr_0,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 7, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 36981, 24,
+ },
+ {
+ "vec",
+ locale_compact_arr_142,
+ { 1, 5, 0, 0, 0, 0, 0 },
+ { 0, 1, 27, 28, 27, 28, 4, 5 },
+ 254, 263,
+ 147, 253,
+ 192, 217,
+ 0, 0,
+ 0,
+ 68, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 1, 1,
+ 1, 1,
+ 12, 3, 0,
+ 37029, 2,
+ },
+ {
+ "vi",
+ locale_compact_arr_143,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 255, 264,
+ 0, 254,
+ 193, 218,
+ 133, 97,
+ 98,
+ 11, 8,
+ 22, 23,
+ 4, 5,
+ 6, 7,
+ 3, 3,
+ 3, 3,
+ 12, 3, 0,
+ 37033, 22,
+ },
+ {
+ "vmw",
+ locale_compact_arr_0,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 256, 265,
+ 0, 255,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 37077, 23,
+ },
+ {
+ "vo",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 37123, 23,
+ },
+ {
+ "vun",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 7, 4, 5 },
+ 106, 114,
+ 1, 97,
+ 7, 89,
+ 56, 0,
+ 0,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 37169, 24,
+ },
+ {
+ "wa",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 37217, 23,
+ },
+ {
+ "wae",
+ locale_compact_arr_0,
+ { 1, 4, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 257, 266,
+ 148, 256,
+ 194, 219,
+ 0, 0,
+ 0,
+ 0, 69,
+ 62, 71,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 37263, 23,
+ },
+ {
+ "wal",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 37309, 24,
+ },
+ {
+ "wbp",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 37357, 23,
+ },
+ {
+ "wo",
+ locale_compact_arr_144,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 258, 267,
+ 0, 257,
+ 195, 220,
+ 134, 0,
+ 0,
+ 21, 8,
+ 22, 226,
+ 4, 5,
+ 6, 7,
+ 4, 4,
+ 4, 4,
+ 12, 3, 0,
+ 37403, 30,
+ },
+ {
+ "xh",
+ locale_compact_arr_0,
+ { 0, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 7, 4, 5 },
+ 259, 268,
+ 1, 258,
+ 196, 221,
+ 0, 0,
+ 0,
+ 56, 57,
+ 58, 59,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 37470, 26,
+ },
+ {
+ "xnr",
+ locale_compact_arr_145,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 7, 4, 5 },
+ 260, 159,
+ 62, 259,
+ 197, 222,
+ 135, 0,
+ 0,
+ 11, 16,
+ 9, 24,
+ 8, 9,
+ 10, 11,
+ 1, 1,
+ 1, 1,
+ 12, 3, 2,
+ 37526, 23,
+ },
+ {
+ "xog",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 17, 4, 5 },
+ 138, 146,
+ 1, 260,
+ 198, 223,
+ 136, 0,
+ 0,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 37572, 24,
+ },
+ {
+ "yav",
+ locale_compact_arr_0,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 16, 17, 16, 20, 4, 5 },
+ 261, 269,
+ 0, 261,
+ 199, 224,
+ 137, 0,
+ 0,
+ 7, 16,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 37620, 23,
+ },
+ {
+ "yi",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 262, 270,
+ 0, 262,
+ 0, 0,
+ 138, 0,
+ 0,
+ 68, 227,
+ 228, 229,
+ 4, 5,
+ 6, 7,
+ 0, 1,
+ 0, 0,
+ 12, 3, 0,
+ 37666, 23,
+ },
+ {
+ "yo",
+ locale_compact_arr_146,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 263, 271,
+ 149, 263,
+ 200, 225,
+ 139, 0,
+ 0,
+ 7, 230,
+ 16, 231,
+ 85, 86,
+ 14, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 37712, 25,
+ },
+ {
+ "yo-BJ",
+ locale_compact_arr_147,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 264, 272,
+ 150, 264,
+ 201, 225,
+ 140, 0,
+ 0,
+ 7, 230,
+ 16, 231,
+ 85, 86,
+ 14, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 37762, 25,
+ },
+ {
+ "yrl",
+ locale_compact_arr_148,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 265, 273,
+ 151, 265,
+ 202, 226,
+ 0, 98,
+ 99,
+ 15, 16,
+ 9, 24,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 37812, 28,
+ },
+ {
+ "yrl-CO",
+ locale_compact_arr_149,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 265, 273,
+ 151, 265,
+ 202, 226,
+ 17, 98,
+ 99,
+ 15, 16,
+ 9, 24,
+ 0, 1,
+ 2, 3,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 37875, 28,
+ },
+ {
+ "yrl-VE",
+ locale_compact_arr_149,
+ { 1, 3, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 265, 273,
+ 151, 265,
+ 202, 226,
+ 17, 98,
+ 99,
+ 15, 16,
+ 9, 24,
+ 0, 1,
+ 2, 3,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 37938, 28,
+ },
+ {
+ "yue",
+ locale_compact_arr_150,
+ { 0, 0, 0, 0, 0, 0, 29 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 104, 112,
+ 0, 266,
+ 203, 227,
+ 141, 99,
+ 100,
+ 106, 134,
+ 134, 232,
+ 87, 88,
+ 89, 90,
+ 14, 0,
+ 0, 0,
+ 12, 3, 0,
+ 38001, 21,
+ },
+ {
+ "yue-Hans",
+ locale_compact_arr_151,
+ { 0, 0, 0, 0, 0, 0, 30 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 104, 112,
+ 0, 266,
+ 203, 227,
+ 142, 99,
+ 100,
+ 106, 134,
+ 134, 232,
+ 4, 5,
+ 91, 92,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 38043, 21,
+ },
+ {
+ "yue-Hant",
+ locale_compact_arr_150,
+ { 0, 0, 0, 0, 0, 0, 29 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 104, 112,
+ 0, 266,
+ 203, 227,
+ 141, 99,
+ 100,
+ 106, 134,
+ 134, 232,
+ 87, 88,
+ 89, 90,
+ 14, 0,
+ 0, 0,
+ 12, 3, 0,
+ 38085, 21,
+ },
+ {
+ "yue-Hant-CN",
+ locale_compact_arr_150,
+ { 0, 0, 0, 0, 0, 0, 29 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 104, 112,
+ 0, 266,
+ 203, 227,
+ 141, 99,
+ 100,
+ 106, 134,
+ 134, 232,
+ 4, 5,
+ 91, 92,
+ 14, 0,
+ 0, 0,
+ 12, 3, 0,
+ 38127, 21,
+ },
+ {
+ "yue-Hant-MO",
+ locale_compact_arr_150,
+ { 0, 0, 0, 0, 0, 0, 29 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 104, 112,
+ 0, 266,
+ 203, 227,
+ 141, 99,
+ 100,
+ 106, 134,
+ 134, 232,
+ 87, 88,
+ 89, 90,
+ 14, 0,
+ 0, 0,
+ 12, 3, 0,
+ 38169, 21,
+ },
+ {
+ "za",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 266, 274,
+ 0, 267,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 38211, 23,
+ },
+ {
+ "zgh",
+ locale_compact_arr_0,
+ { 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 9, 10, 9, 10, 18, 19 },
+ 215, 222,
+ 126, 268,
+ 0, 183,
+ 111, 0,
+ 0,
+ 7, 8,
+ 9, 10,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 38257, 23,
+ },
+ {
+ "zh",
+ locale_compact_arr_152,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 267, 112,
+ 0, 266,
+ 203, 228,
+ 143, 100,
+ 101,
+ 106, 134,
+ 134, 135,
+ 4, 5,
+ 67, 68,
+ 0, 0,
+ 0, 0,
+ 3, 3, 0,
+ 38303, 22,
+ },
+ {
+ "zh-Hans",
+ locale_compact_arr_153,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 267, 112,
+ 0, 266,
+ 203, 228,
+ 143, 100,
+ 101,
+ 106, 134,
+ 134, 135,
+ 4, 5,
+ 67, 68,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 38348, 22,
+ },
+ {
+ "zh-Hans-HK",
+ locale_compact_arr_153,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 267, 112,
+ 0, 266,
+ 203, 228,
+ 143, 100,
+ 101,
+ 11, 134,
+ 134, 135,
+ 87, 88,
+ 93, 94,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 38393, 22,
+ },
+ {
+ "zh-Hans-MO",
+ locale_compact_arr_153,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 267, 112,
+ 0, 266,
+ 203, 228,
+ 143, 100,
+ 101,
+ 11, 134,
+ 134, 135,
+ 87, 88,
+ 93, 94,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 38438, 23,
+ },
+ {
+ "zh-Hans-MY",
+ locale_compact_arr_153,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 267, 112,
+ 0, 266,
+ 203, 228,
+ 143, 100,
+ 101,
+ 106, 134,
+ 134, 135,
+ 87, 88,
+ 93, 94,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 38486, 22,
+ },
+ {
+ "zh-Hans-SG",
+ locale_compact_arr_153,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 267, 112,
+ 0, 266,
+ 203, 228,
+ 143, 100,
+ 101,
+ 68, 134,
+ 134, 135,
+ 87, 88,
+ 93, 94,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 38531, 23,
+ },
+ {
+ "zh-Hant",
+ locale_compact_arr_152,
+ { 0, 0, 0, 0, 0, 0, 29 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 104, 112,
+ 0, 266,
+ 203, 227,
+ 143, 100,
+ 102,
+ 106, 134,
+ 134, 232,
+ 95, 96,
+ 97, 98,
+ 14, 0,
+ 0, 0,
+ 3, 3, 0,
+ 38578, 21,
+ },
+ {
+ "zh-Hant-HK",
+ locale_compact_arr_154,
+ { 0, 0, 0, 0, 0, 0, 29 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 104, 112,
+ 0, 266,
+ 203, 228,
+ 143, 101,
+ 101,
+ 7, 134,
+ 134, 135,
+ 87, 88,
+ 89, 90,
+ 14, 0,
+ 0, 0,
+ 12, 3, 0,
+ 38620, 21,
+ },
+ {
+ "zh-Hant-MO",
+ locale_compact_arr_154,
+ { 0, 0, 0, 0, 0, 0, 29 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 104, 112,
+ 0, 266,
+ 203, 228,
+ 143, 101,
+ 101,
+ 7, 134,
+ 134, 135,
+ 87, 88,
+ 89, 90,
+ 14, 0,
+ 0, 0,
+ 12, 3, 0,
+ 38662, 22,
+ },
+ {
+ "zh-Hant-MY",
+ locale_compact_arr_155,
+ { 0, 0, 0, 0, 0, 0, 29 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 104, 112,
+ 0, 266,
+ 203, 227,
+ 143, 100,
+ 102,
+ 106, 134,
+ 134, 232,
+ 87, 88,
+ 93, 94,
+ 14, 0,
+ 0, 0,
+ 12, 3, 0,
+ 38707, 21,
+ },
+ {
+ "zh-Latn",
+ locale_compact_arr_0,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 3, 2, 3, 4, 5 },
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0,
+ 0, 1,
+ 2, 3,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 38749, 23,
+ },
+ {
+ "zh-TW",
+ locale_compact_arr_152,
+ { 0, 0, 0, 0, 0, 0, 29 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 104, 112,
+ 0, 266,
+ 203, 227,
+ 143, 100,
+ 102,
+ 106, 134,
+ 134, 232,
+ 95, 96,
+ 97, 98,
+ 14, 0,
+ 0, 0,
+ 3, 3, 0,
+ 38795, 21,
+ },
+ {
+ "zu",
+ locale_compact_arr_156,
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 6, 7, 6, 8, 4, 5 },
+ 268, 275,
+ 152, 269,
+ 204, 229,
+ 0, 102,
+ 103,
+ 56, 57,
+ 58, 59,
+ 4, 5,
+ 6, 7,
+ 0, 0,
+ 0, 0,
+ 12, 3, 0,
+ 38837, 24,
+ },
+};
+
+const int locale_data_count = sizeof(locale_data_table) / sizeof(locale_data_table[0]);
+
+/* DisplayNames data for en */
+static const char dn_en_languages[] = "aa\000Afar\000ab\000Abkhazian\000ace\000Acehnese\000ach\000Acoli\000ada\000Adangme\000ady\000Adyghe\000ae\000Avestan\000aeb\000Tunisian Arabic\000af\000Afrikaans\000afh\000Afrihili\000agq\000Aghem\000ain\000Ainu\000ak\000Akan\000akk\000Akkadian\000akz\000Alabama\000ale\000Aleut\000aln\000Gheg Albanian\000alt\000Southern Altai\000am\000Amharic\000an\000Aragonese\000ang\000Old English\000ann\000Obolo\000anp\000Angika\000ar\000Arabic\000ar-001\000Modern Standard Arabic\000arc\000Aramaic\000arn\000Mapuche\000aro\000Araona\000arp\000Arapaho\000arq\000Algerian Arabic\000ars\000Najdi Arabic\000ars-alt-menu\000Arabic, Najdi\000arw\000Arawak\000ary\000Moroccan Arabic\000arz\000Egyptian Arabic\000as\000Assamese\000asa\000Asu\000ase\000American Sign Language\000ast\000Asturian\000atj\000Atikamekw\000av\000Avaric\000avk\000Kotava\000awa\000Awadhi\000ay\000Aymara\000az\000Azerbaijani\000az-alt-short\000Azeri\000ba\000Bashkir\000bal\000Baluchi\000ban\000Balinese\000bar\000Bavarian\000bas\000Basaa\000bax\000Bamun\000bbc\000Batak Toba\000bbj\000Ghomala\000be\000Belarusian\000bej\000Beja\000bem\000Bemba\000bew\000Betawi\000bez\000Bena\000bfd\000Bafut\000bfq\000Badaga\000bg\000Bulgarian\000bgc\000Haryanvi\000bgn\000Western Balochi\000bho\000Bhojpuri\000bi\000Bislama\000bik\000Bikol\000bin\000Bini\000bjn\000Banjar\000bkm\000Kom\000bla\000Siksiká\000blo\000Anii\000blt\000Tai Dam\000bm\000Bambara\000bn\000Bangla\000bo\000Tibetan\000bpy\000Bishnupriya\000bqi\000Bakhtiari\000bqi-alt-variant\000Luri Bakhtiari\000br\000Breton\000bra\000Braj\000brh\000Brahui\000brx\000Bodo\000bs\000Bosnian\000bss\000Akoose\000bua\000Buriat\000bug\000Buginese\000bum\000Bulu\000byn\000Blin\000byv\000Medumba\000ca\000Catalan\000cad\000Caddo\000car\000Carib\000cay\000Cayuga\000cch\000Atsam\000ccp\000Chakma\000ce\000Chechen\000ceb\000Cebuano\000cgg\000Chiga\000ch\000Chamorro\000chb\000Chibcha\000chg\000Chagatai\000chk\000Chuukese\000chm\000Mari\000chn\000Chinook Jargon\000cho\000Choctaw\000chp\000Chipewyan\000chr\000Cherokee\000chy\000Cheyenne\000cic\000Chickasaw\000ckb\000Central Kurdish\000ckb-alt-menu\000Kurdish, Central\000ckb-alt-variant\000Kurdish, Sorani\000ckb-menu-core\000Kurdish\000ckb-menu-extension\000Central\000clc\000Chilcotin\000co\000Corsican\000cop\000Coptic\000cps\000Capiznon\000cr\000Cree\000cr-alt-long\000Woods Cree\000crg\000Michif\000crh\000Crimean Tatar\000crj\000Southern East Cree\000crk\000Plains Cree\000crl\000Northern East Cree\000crm\000Moose Cree\000crr\000Carolina Algonquian\000crs\000Seselwa Creole French\000cs\000Czech\000csb\000Kashubian\000csw\000Swampy Cree\000cu\000Church Slavic\000cv\000Chuvash\000cy\000Welsh\000da\000Danish\000dak\000Dakota\000dar\000Dargwa\000dav\000Taita\000de\000German\000de-AT\000Austrian German\000de-CH\000Swiss High German\000del\000Delaware\000den\000Slave\000dgr\000Dogrib\000din\000Dinka\000dje\000Zarma\000doi\000Dogri\000dsb\000Lower Sorbian\000dtp\000Central Dusun\000dua\000Duala\000dum\000Middle Dutch\000dv\000Divehi\000dyo\000Jola-Fonyi\000dyu\000Dyula\000dz\000Dzongkha\000dzg\000Dazaga\000ebu\000Embu\000ee\000Ewe\000efi\000Efik\000egl\000Emilian\000egy\000Ancient Egyptian\000eka\000Ekajuk\000el\000Greek\000elx\000Elamite\000en\000English\000en-AU\000Australian English\000en-CA\000Canadian English\000en-GB\000British English\000en-GB-alt-short\000UK English\000en-US\000American English\000en-US-alt-short\000US English\000enm\000Middle English\000eo\000Esperanto\000es\000Spanish\000es-419\000Latin American Spanish\000es-ES\000European Spanish\000es-MX\000Mexican Spanish\000esu\000Central Yupik\000et\000Estonian\000eu\000Basque\000ewo\000Ewondo\000ext\000Extremaduran\000fa\000Persian\000fa-AF\000Dari\000fan\000Fang\000fat\000Fanti\000ff\000Fula\000fi\000Finnish\000fil\000Filipino\000fit\000Tornedalen Finnish\000fj\000Fijian\000fo\000Faroese\000fon\000Fon\000fr\000French\000fr-CA\000Canadian French\000fr-CH\000Swiss French\000frc\000Cajun French\000frm\000Middle French\000fro\000Old French\000frp\000Arpitan\000frr\000Northern Frisian\000frs\000Eastern Frisian\000fur\000Friulian\000fy\000Western Frisian\000ga\000Irish\000gaa\000Ga\000gag\000Gagauz\000gan\000Gan Chinese\000gay\000Gayo\000gba\000Gbaya\000gbz\000Zoroastrian Dari\000gd\000Scottish Gaelic\000gez\000Geez\000gil\000Gilbertese\000gl\000Galician\000glk\000Gilaki\000gmh\000Middle High German\000gn\000Guarani\000goh\000Old High German\000gon\000Gondi\000gor\000Gorontalo\000got\000Gothic\000grb\000Grebo\000grc\000Ancient Greek\000gsw\000Swiss German\000gu\000Gujarati\000guc\000Wayuu\000gur\000Frafra\000guz\000Gusii\000gv\000Manx\000gwi\000Gwichʼin\000ha\000Hausa\000hai\000Haida\000hak\000Hakka Chinese\000haw\000Hawaiian\000hax\000Southern Haida\000he\000Hebrew\000hi\000Hindi\000hi-Latn\000Hindi (Latin)\000hi-Latn-alt-variant\000Hinglish\000hif\000Fiji Hindi\000hil\000Hiligaynon\000hit\000Hittite\000hmn\000Hmong\000hnj\000Hmong Njua\000ho\000Hiri Motu\000hr\000Croatian\000hsb\000Upper Sorbian\000hsn\000Xiang Chinese\000ht\000Haitian Creole\000hu\000Hungarian\000hup\000Hupa\000hur\000Halkomelem\000hy\000Armenian\000hz\000Herero\000ia\000Interlingua\000iba\000Iban\000ibb\000Ibibio\000id\000Indonesian\000ie\000Interlingue\000ig\000Igbo\000ii\000Sichuan Yi\000ik\000Inupiaq\000ikt\000Western Canadian Inuktitut\000ilo\000Iloko\000inh\000Ingush\000io\000Ido\000is\000Icelandic\000it\000Italian\000iu\000Inuktitut\000izh\000Ingrian\000ja\000Japanese\000jam\000Jamaican Creole English\000jbo\000Lojban\000jgo\000Ngomba\000jmc\000Machame\000jpr\000Judeo-Persian\000jrb\000Judeo-Arabic\000jut\000Jutish\000jv\000Javanese\000ka\000Georgian\000kaa\000Kara-Kalpak\000kab\000Kabyle\000kac\000Kachin\000kaj\000Jju\000kam\000Kamba\000kaw\000Kawi\000kbd\000Kabardian\000kbl\000Kanembu\000kcg\000Tyap\000kde\000Makonde\000kea\000Kabuverdianu\000kek\000Qʼeqchiʼ\000ken\000Kenyang\000kfo\000Koro\000kg\000Kongo\000kgp\000Kaingang\000kha\000Khasi\000kho\000Khotanese\000khq\000Koyra Chiini\000khw\000Khowar\000ki\000Kikuyu\000kiu\000Kirmanjki\000kj\000Kuanyama\000kk\000Kazakh\000kkj\000Kako\000kl\000Kalaallisut\000kln\000Kalenjin\000km\000Khmer\000kmb\000Kimbundu\000kn\000Kannada\000ko\000Korean\000koi\000Komi-Permyak\000kok\000Konkani\000kos\000Kosraean\000kpe\000Kpelle\000kr\000Kanuri\000krc\000Karachay-Balkar\000kri\000Krio\000krj\000Kinaray-a\000krl\000Karelian\000kru\000Kurukh\000ks\000Kashmiri\000ksb\000Shambala\000ksf\000Bafia\000ksh\000Colognian\000ku\000Kurdish\000ku-menu-core\000Kurdish\000ku-menu-extension\000Kurmanji\000kum\000Kumyk\000kut\000Kutenai\000kv\000Komi\000kw\000Cornish\000kwk\000Kwakʼwala\000kxv\000Kuvi\000ky\000Kyrgyz\000ky-alt-variant\000Kirghiz\000la\000Latin\000lad\000Ladino\000lag\000Langi\000lah\000Western Panjabi\000lam\000Lamba\000lb\000Luxembourgish\000lez\000Lezghian\000lfn\000Lingua Franca Nova\000lg\000Ganda\000li\000Limburgish\000lij\000Ligurian\000lil\000Lillooet\000liv\000Livonian\000lkt\000Lakota\000lmo\000Lombard\000ln\000Lingala\000lo\000Lao\000lol\000Mongo\000lou\000Louisiana Creole\000loz\000Lozi\000lrc\000Northern Luri\000lsm\000Saamia\000lt\000Lithuanian\000ltg\000Latgalian\000lu\000Luba-Katanga\000lua\000Luba-Lulua\000lui\000Luiseno\000lun\000Lunda\000luo\000Luo\000lus\000Mizo\000luy\000Luyia\000lv\000Latvian\000lzh\000Literary Chinese\000lzz\000Laz\000mad\000Madurese\000maf\000Mafa\000mag\000Magahi\000mai\000Maithili\000mak\000Makasar\000man\000Mandingo\000mas\000Masai\000mde\000Maba\000mdf\000Moksha\000mdr\000Mandar\000men\000Mende\000mer\000Meru\000mfe\000Morisyen\000mg\000Malagasy\000mga\000Middle Irish\000mgh\000Makhuwa-Meetto\000mgo\000Metaʼ\000mh\000Marshallese\000mi\000Māori\000mic\000Mi'kmaw\000min\000Minangkabau\000mk\000Macedonian\000ml\000Malayalam\000mn\000Mongolian\000mnc\000Manchu\000mni\000Manipuri\000moe\000Innu-aimun\000moh\000Mohawk\000mos\000Mossi\000mr\000Marathi\000mrj\000Western Mari\000ms\000Malay\000mt\000Maltese\000mua\000Mundang\000mul\000Multiple languages\000mus\000Muscogee\000mus-alt-official\000Mvskoke\000mwl\000Mirandese\000mwr\000Marwari\000mwv\000Mentawai\000my\000Burmese\000my-alt-variant\000Myanmar Language\000mye\000Myene\000myv\000Erzya\000mzn\000Mazanderani\000na\000Nauru\000nan\000Min Nan Chinese\000nap\000Neapolitan\000naq\000Nama\000nb\000Norwegian Bokmål\000nd\000North Ndebele\000nds\000Low German\000nds-NL\000Low Saxon\000ne\000Nepali\000new\000Newari\000ng\000Ndonga\000nia\000Nias\000niu\000Niuean\000njo\000Ao Naga\000nl\000Dutch\000nl-BE\000Flemish\000nmg\000Kwasio\000nn\000Norwegian Nynorsk\000nnh\000Ngiemboon\000no\000Norwegian\000nog\000Nogai\000non\000Old Norse\000nov\000Novial\000nqo\000N’Ko\000nr\000South Ndebele\000nso\000Northern Sotho\000nus\000Nuer\000nv\000Navajo\000nwc\000Classical Newari\000ny\000Nyanja\000nym\000Nyamwezi\000nyn\000Nyankole\000nyo\000Nyoro\000nzi\000Nzima\000oc\000Occitan\000oj\000Ojibwa\000ojb\000Northwestern Ojibwa\000ojc\000Central Ojibwa\000ojs\000Oji-Cree\000ojw\000Western Ojibwa\000oka\000Okanagan\000oka-alt-variant\000Colville Salish\000om\000Oromo\000or\000Odia\000os\000Ossetic\000osa\000Osage\000ota\000Ottoman Turkish\000pa\000Punjabi\000pag\000Pangasinan\000pal\000Pahlavi\000pam\000Pampanga\000pap\000Papiamento\000pau\000Palauan\000pcd\000Picard\000pcm\000Nigerian Pidgin\000pdc\000Pennsylvania German\000pdt\000Plautdietsch\000peo\000Old Persian\000pfl\000Palatine German\000phn\000Phoenician\000pi\000Pali\000pi-alt-variant\000Pāli\000pis\000Pijin\000pl\000Polish\000pms\000Piedmontese\000pnt\000Pontic\000pon\000Pohnpeian\000pqm\000Maliseet-Passamaquoddy\000prg\000Prussian\000pro\000Old Provençal\000ps\000Pashto\000ps-alt-variant\000Pushto\000pt\000Portuguese\000pt-BR\000Brazilian Portuguese\000pt-PT\000European Portuguese\000qu\000Quechua\000quc\000Kʼicheʼ\000qug\000Chimborazo Highland Quichua\000raj\000Rajasthani\000rap\000Rapanui\000rar\000Rarotongan\000rgn\000Romagnol\000rhg\000Rohingya\000rif\000Riffian\000rm\000Romansh\000rn\000Rundi\000ro\000Romanian\000ro-MD\000Moldavian\000rof\000Rombo\000rom\000Romany\000rtm\000Rotuman\000ru\000Russian\000rue\000Rusyn\000rug\000Roviana\000rup\000Aromanian\000rw\000Kinyarwanda\000rwk\000Rwa\000sa\000Sanskrit\000sad\000Sandawe\000sah\000Yakut\000sam\000Samaritan Aramaic\000saq\000Samburu\000sas\000Sasak\000sat\000Santali\000saz\000Sourashtra\000saz-alt-variant\000Saurashtra\000sba\000Ngambay\000sbp\000Sangu\000sc\000Sardinian\000scn\000Sicilian\000sco\000Scots\000sd\000Sindhi\000sdc\000Sassarese Sardinian\000sdh\000Southern Kurdish\000sdh-menu-core\000Kurdish\000sdh-menu-extension\000Southern\000se\000Northern Sami\000se-alt-menu\000Sami, Northern\000see\000Seneca\000seh\000Sena\000sei\000Seri\000sel\000Selkup\000ses\000Koyraboro Senni\000sg\000Sango\000sga\000Old Irish\000sgs\000Samogitian\000sh\000Serbo-Croatian\000shi\000Tachelhit\000shn\000Shan\000shu\000Chadian Arabic\000si\000Sinhala\000sid\000Sidamo\000sk\000Slovak\000sl\000Slovenian\000slh\000Southern Lushootseed\000sli\000Lower Silesian\000sly\000Selayar\000sm\000Samoan\000sma\000Southern Sami\000sma-alt-menu\000Sami, Southern\000smj\000Lule Sami\000smj-alt-menu\000Sami, Lule\000smn\000Inari Sami\000smn-alt-menu\000Sami, Inari\000sms\000Skolt Sami\000sms-alt-menu\000Sami, Skolt\000sn\000Shona\000snk\000Soninke\000so\000Somali\000sog\000Sogdien\000sq\000Albanian\000sr\000Serbian\000sr-ME\000Montenegrin\000srn\000Sranan Tongo\000srr\000Serer\000ss\000Swati\000ssy\000Saho\000st\000Southern Sotho\000stq\000Saterland Frisian\000str\000Straits Salish\000su\000Sundanese\000suk\000Sukuma\000sus\000Susu\000sux\000Sumerian\000sv\000Swedish\000sw\000Swahili\000sw-CD\000Congo Swahili\000swb\000Comorian\000syc\000Classical Syriac\000syr\000Syriac\000szl\000Silesian\000ta\000Tamil\000tce\000Southern Tutchone\000tcy\000Tulu\000te\000Telugu\000tem\000Timne\000teo\000Teso\000ter\000Tereno\000tet\000Tetum\000tg\000Tajik\000tgx\000Tagish\000th\000Thai\000tht\000Tahltan\000ti\000Tigrinya\000tig\000Tigre\000tiv\000Tiv\000tk\000Turkmen\000tkl\000Tokelauan\000tkr\000Tsakhur\000tl\000Tagalog\000tlh\000Klingon\000tli\000Tlingit\000tly\000Talysh\000tmh\000Tamashek\000tn\000Tswana\000to\000Tongan\000tog\000Nyasa Tonga\000tok\000Toki Pona\000tpi\000Tok Pisin\000tr\000Turkish\000tru\000Turoyo\000trv\000Taroko\000trw\000Torwali\000ts\000Tsonga\000tsd\000Tsakonian\000tsi\000Tsimshian\000tt\000Tatar\000ttm\000Northern Tutchone\000ttt\000Muslim Tat\000tum\000Tumbuka\000tvl\000Tuvalu\000tw\000Twi\000twq\000Tasawaq\000ty\000Tahitian\000tyv\000Tuvinian\000tzm\000Central Atlas Tamazight\000udm\000Udmurt\000ug\000Uyghur\000ug-alt-variant\000Uighur\000uga\000Ugaritic\000uk\000Ukrainian\000umb\000Umbundu\000und\000Unknown language\000ur\000Urdu\000uz\000Uzbek\000vai\000Vai\000ve\000Venda\000vec\000Venetian\000vep\000Veps\000vi\000Vietnamese\000vls\000West Flemish\000vmf\000Main-Franconian\000vmw\000Makhuwa\000vo\000Volapük\000vot\000Votic\000vro\000Võro\000vun\000Vunjo\000wa\000Walloon\000wae\000Walser\000wal\000Wolaytta\000war\000Waray\000was\000Washo\000wbp\000Warlpiri\000wo\000Wolof\000wuu\000Wu Chinese\000xal\000Kalmyk\000xh\000Xhosa\000xmf\000Mingrelian\000xnr\000Kangri\000xog\000Soga\000yao\000Yao\000yap\000Yapese\000yav\000Yangben\000ybb\000Yemba\000yi\000Yiddish\000yo\000Yoruba\000yrl\000Nheengatu\000yue\000Cantonese\000yue-alt-menu\000Chinese, Cantonese\000za\000Zhuang\000zap\000Zapotec\000zbl\000Blissymbols\000zea\000Zeelandic\000zen\000Zenaga\000zgh\000Standard Moroccan Tamazight\000zh\000Chinese\000zh-Hans\000Simplified Chinese\000zh-Hans-alt-long\000Simplified Mandarin Chinese\000zh-Hant\000Traditional Chinese\000zh-Hant-alt-long\000Traditional Mandarin Chinese\000zh-alt-long\000Mandarin Chinese\000zh-alt-menu\000Chinese, Mandarin\000zu\000Zulu\000zun\000Zuni\000zxx\000No linguistic content\000zza\000Zaza\000";
+static const char dn_en_regions[] = "001\000world\000002\000Africa\000003\000North America\000005\000South America\000009\000Oceania\000011\000Western Africa\000013\000Central America\000014\000Eastern Africa\000015\000Northern Africa\000017\000Middle Africa\000018\000Southern Africa\000019\000Americas\000021\000Northern America\000029\000Caribbean\000030\000Eastern Asia\000034\000Southern Asia\000035\000Southeast Asia\000039\000Southern Europe\000053\000Australasia\000054\000Melanesia\000057\000Micronesian Region\000061\000Polynesia\000142\000Asia\000143\000Central Asia\000145\000Western Asia\000150\000Europe\000151\000Eastern Europe\000154\000Northern Europe\000155\000Western Europe\000202\000Sub-Saharan Africa\000419\000Latin America\000AC\000Ascension Island\000AD\000Andorra\000AE\000United Arab Emirates\000AF\000Afghanistan\000AG\000Antigua & Barbuda\000AI\000Anguilla\000AL\000Albania\000AM\000Armenia\000AO\000Angola\000AQ\000Antarctica\000AR\000Argentina\000AS\000American Samoa\000AT\000Austria\000AU\000Australia\000AW\000Aruba\000AX\000Åland Islands\000AZ\000Azerbaijan\000BA\000Bosnia & Herzegovina\000BB\000Barbados\000BD\000Bangladesh\000BE\000Belgium\000BF\000Burkina Faso\000BG\000Bulgaria\000BH\000Bahrain\000BI\000Burundi\000BJ\000Benin\000BL\000St. Barthélemy\000BM\000Bermuda\000BN\000Brunei\000BO\000Bolivia\000BQ\000Caribbean Netherlands\000BR\000Brazil\000BS\000Bahamas\000BT\000Bhutan\000BV\000Bouvet Island\000BW\000Botswana\000BY\000Belarus\000BZ\000Belize\000CA\000Canada\000CC\000Cocos (Keeling) Islands\000CD\000Congo - Kinshasa\000CF\000Central African Republic\000CG\000Congo - Brazzaville\000CH\000Switzerland\000CI\000Côte d’Ivoire\000CK\000Cook Islands\000CL\000Chile\000CM\000Cameroon\000CN\000China\000CO\000Colombia\000CP\000Clipperton Island\000CQ\000Sark\000CR\000Costa Rica\000CU\000Cuba\000CV\000Cape Verde\000CW\000Curaçao\000CX\000Christmas Island\000CY\000Cyprus\000CZ\000Czechia\000DE\000Germany\000DG\000Diego Garcia\000DJ\000Djibouti\000DK\000Denmark\000DM\000Dominica\000DO\000Dominican Republic\000DZ\000Algeria\000EA\000Ceuta & Melilla\000EC\000Ecuador\000EE\000Estonia\000EG\000Egypt\000EH\000Western Sahara\000ER\000Eritrea\000ES\000Spain\000ET\000Ethiopia\000EU\000European Union\000EZ\000Eurozone\000FI\000Finland\000FJ\000Fiji\000FK\000Falkland Islands\000FM\000Micronesia\000FO\000Faroe Islands\000FR\000France\000GA\000Gabon\000GB\000United Kingdom\000GD\000Grenada\000GE\000Georgia\000GF\000French Guiana\000GG\000Guernsey\000GH\000Ghana\000GI\000Gibraltar\000GL\000Greenland\000GM\000Gambia\000GN\000Guinea\000GP\000Guadeloupe\000GQ\000Equatorial Guinea\000GR\000Greece\000GS\000South Georgia & South Sandwich Islands\000GT\000Guatemala\000GU\000Guam\000GW\000Guinea-Bissau\000GY\000Guyana\000HK\000Hong Kong SAR China\000HM\000Heard & McDonald Islands\000HN\000Honduras\000HR\000Croatia\000HT\000Haiti\000HU\000Hungary\000IC\000Canary Islands\000ID\000Indonesia\000IE\000Ireland\000IL\000Israel\000IM\000Isle of Man\000IN\000India\000IO\000British Indian Ocean Territory\000IQ\000Iraq\000IR\000Iran\000IS\000Iceland\000IT\000Italy\000JE\000Jersey\000JM\000Jamaica\000JO\000Jordan\000JP\000Japan\000KE\000Kenya\000KG\000Kyrgyzstan\000KH\000Cambodia\000KI\000Kiribati\000KM\000Comoros\000KN\000St. Kitts & Nevis\000KP\000North Korea\000KR\000South Korea\000KW\000Kuwait\000KY\000Cayman Islands\000KZ\000Kazakhstan\000LA\000Laos\000LB\000Lebanon\000LC\000St. Lucia\000LI\000Liechtenstein\000LK\000Sri Lanka\000LR\000Liberia\000LS\000Lesotho\000LT\000Lithuania\000LU\000Luxembourg\000LV\000Latvia\000LY\000Libya\000MA\000Morocco\000MC\000Monaco\000MD\000Moldova\000ME\000Montenegro\000MF\000St. Martin\000MG\000Madagascar\000MH\000Marshall Islands\000MK\000North Macedonia\000ML\000Mali\000MM\000Myanmar (Burma)\000MN\000Mongolia\000MO\000Macao SAR China\000MP\000Northern Mariana Islands\000MQ\000Martinique\000MR\000Mauritania\000MS\000Montserrat\000MT\000Malta\000MU\000Mauritius\000MV\000Maldives\000MW\000Malawi\000MX\000Mexico\000MY\000Malaysia\000MZ\000Mozambique\000NA\000Namibia\000NC\000New Caledonia\000NE\000Niger\000NF\000Norfolk Island\000NG\000Nigeria\000NI\000Nicaragua\000NL\000Netherlands\000NO\000Norway\000NP\000Nepal\000NR\000Nauru\000NU\000Niue\000NZ\000New Zealand\000OM\000Oman\000PA\000Panama\000PE\000Peru\000PF\000French Polynesia\000PG\000Papua New Guinea\000PH\000Philippines\000PK\000Pakistan\000PL\000Poland\000PM\000St. Pierre & Miquelon\000PN\000Pitcairn Islands\000PR\000Puerto Rico\000PS\000Palestinian Territories\000PT\000Portugal\000PW\000Palau\000PY\000Paraguay\000QA\000Qatar\000QO\000Outlying Oceania\000RE\000Réunion\000RO\000Romania\000RS\000Serbia\000RU\000Russia\000RW\000Rwanda\000SA\000Saudi Arabia\000SB\000Solomon Islands\000SC\000Seychelles\000SD\000Sudan\000SE\000Sweden\000SG\000Singapore\000SH\000St. Helena\000SI\000Slovenia\000SJ\000Svalbard & Jan Mayen\000SK\000Slovakia\000SL\000Sierra Leone\000SM\000San Marino\000SN\000Senegal\000SO\000Somalia\000SR\000Suriname\000SS\000South Sudan\000ST\000São Tomé & Príncipe\000SV\000El Salvador\000SX\000Sint Maarten\000SY\000Syria\000SZ\000Eswatini\000TA\000Tristan da Cunha\000TC\000Turks & Caicos Islands\000TD\000Chad\000TF\000French Southern Territories\000TG\000Togo\000TH\000Thailand\000TJ\000Tajikistan\000TK\000Tokelau\000TL\000Timor-Leste\000TM\000Turkmenistan\000TN\000Tunisia\000TO\000Tonga\000TR\000Türkiye\000TT\000Trinidad & Tobago\000TV\000Tuvalu\000TW\000Taiwan\000TZ\000Tanzania\000UA\000Ukraine\000UG\000Uganda\000UM\000U.S. Outlying Islands\000UN\000United Nations\000US\000United States\000UY\000Uruguay\000UZ\000Uzbekistan\000VA\000Vatican City\000VC\000St. Vincent & Grenadines\000VE\000Venezuela\000VG\000British Virgin Islands\000VI\000U.S. Virgin Islands\000VN\000Vietnam\000VU\000Vanuatu\000WF\000Wallis & Futuna\000WS\000Samoa\000XA\000Pseudo-Accents\000XB\000Pseudo-Bidi\000XK\000Kosovo\000YE\000Yemen\000YT\000Mayotte\000ZA\000South Africa\000ZM\000Zambia\000ZW\000Zimbabwe\000ZZ\000Unknown Region\000";
+static const char dn_en_regions_short[] = "BA\000Bosnia\000CC\000Cocos Islands\000GB\000UK\000HK\000Hong Kong\000MM\000Myanmar\000MO\000Macao\000PN\000Pitcairn\000PS\000Palestine\000UN\000UN\000US\000US\000";
+static const char dn_en_scripts[] = "Adlm\000Adlam\000Afak\000Afaka\000Aghb\000Caucasian Albanian\000Ahom\000Ahom\000Arab\000Arabic\000Arab-alt-variant\000Perso-Arabic\000Aran\000Nastaliq\000Armi\000Imperial Aramaic\000Armn\000Armenian\000Avst\000Avestan\000Bali\000Balinese\000Bamu\000Bamum\000Bass\000Bassa Vah\000Batk\000Batak\000Beng\000Bangla\000Berf\000Beria Erfe\000Bhks\000Bhaiksuki\000Blis\000Blissymbols\000Bopo\000Bopomofo\000Brah\000Brahmi\000Brai\000Braille\000Bugi\000Buginese\000Buhd\000Buhid\000Cakm\000Chakma\000Cans\000Unified Canadian Aboriginal Syllabics\000Cans-alt-short\000UCAS\000Cari\000Carian\000Cham\000Cham\000Cher\000Cherokee\000Chrs\000Chorasmian\000Cirt\000Cirth\000Copt\000Coptic\000Cpmn\000Cypro-Minoan\000Cprt\000Cypriot\000Cyrl\000Cyrillic\000Cyrs\000Old Church Slavonic Cyrillic\000Deva\000Devanagari\000Diak\000Dives Akuru\000Dogr\000Dogra\000Dsrt\000Deseret\000Dupl\000Duployan shorthand\000Egyd\000Egyptian demotic\000Egyh\000Egyptian hieratic\000Egyp\000Egyptian hieroglyphs\000Elba\000Elbasan\000Elym\000Elymaic\000Ethi\000Ethiopic\000Gara\000Garay\000Geok\000Georgian Khutsuri\000Geor\000Georgian\000Glag\000Glagolitic\000Gong\000Gunjala Gondi\000Gonm\000Masaram Gondi\000Goth\000Gothic\000Gran\000Grantha\000Grek\000Greek\000Gujr\000Gujarati\000Gukh\000Gurung Khema\000Guru\000Gurmukhi\000Hanb\000Han with Bopomofo\000Hang\000Hangul\000Hani\000Han\000Hano\000Hanunoo\000Hans\000Simplified\000Hans-alt-stand-alone\000Simplified Han\000Hant\000Traditional\000Hant-alt-stand-alone\000Traditional Han\000Hatr\000Hatran\000Hebr\000Hebrew\000Hira\000Hiragana\000Hluw\000Anatolian Hieroglyphs\000Hmng\000Pahawh Hmong\000Hmnp\000Nyiakeng Puachue Hmong\000Hrkt\000Japanese syllabaries\000Hung\000Old Hungarian\000Inds\000Indus\000Ital\000Old Italic\000Jamo\000Jamo\000Java\000Javanese\000Jpan\000Japanese\000Jurc\000Jurchen\000Kali\000Kayah Li\000Kana\000Katakana\000Kawi\000Kawi\000Khar\000Kharoshthi\000Khmr\000Khmer\000Khoj\000Khojki\000Kits\000Khitan small script\000Knda\000Kannada\000Kore\000Korean\000Kpel\000Kpelle\000Krai\000Kirat Rai\000Kthi\000Kaithi\000Lana\000Lanna\000Laoo\000Lao\000Latf\000Fraktur Latin\000Latg\000Gaelic Latin\000Latn\000Latin\000Lepc\000Lepcha\000Limb\000Limbu\000Lina\000Linear A\000Linb\000Linear B\000Lisu\000Fraser\000Loma\000Loma\000Lyci\000Lycian\000Lydi\000Lydian\000Mahj\000Mahajani\000Maka\000Makasar\000Mand\000Mandaean\000Mani\000Manichaean\000Marc\000Marchen\000Maya\000Mayan hieroglyphs\000Medf\000Medefaidrin\000Mend\000Mende\000Merc\000Meroitic Cursive\000Mero\000Meroitic\000Mlym\000Malayalam\000Modi\000Modi\000Mong\000Mongolian\000Moon\000Moon\000Mroo\000Mro\000Mtei\000Meitei Mayek\000Mult\000Multani\000Mymr\000Myanmar\000Nagm\000Nag Mundari\000Nand\000Nandinagari\000Narb\000Old North Arabian\000Nbat\000Nabataean\000Newa\000Newa\000Nkgb\000Naxi Geba\000Nkoo\000N’Ko\000Nshu\000Nüshu\000Ogam\000Ogham\000Olck\000Ol Chiki\000Onao\000Ol Onal\000Orkh\000Orkhon\000Orya\000Odia\000Osge\000Osage\000Osma\000Osmanya\000Ougr\000Old Uyghur\000Palm\000Palmyrene\000Pauc\000Pau Cin Hau\000Perm\000Old Permic\000Phag\000Phags-pa\000Phli\000Inscriptional Pahlavi\000Phlp\000Psalter Pahlavi\000Phlv\000Book Pahlavi\000Phnx\000Phoenician\000Plrd\000Pollard Phonetic\000Prti\000Inscriptional Parthian\000Qaag\000Zawgyi\000Rjng\000Rejang\000Rohg\000Hanifi\000Rohg-alt-stand-alone\000Hanifi Rohingya\000Roro\000Rongorongo\000Runr\000Runic\000Samr\000Samaritan\000Sara\000Sarati\000Sarb\000Old South Arabian\000Saur\000Sourashtra\000Saur-alt-variant\000Saurashtra\000Sgnw\000SignWriting\000Shaw\000Shavian\000Shrd\000Sharada\000Sidd\000Siddham\000Sidt\000Sidetic\000Sind\000Khudawadi\000Sinh\000Sinhala\000Sogd\000Sogdian\000Sogo\000Old Sogdian\000Sora\000Sora Sompeng\000Soyo\000Soyombo\000Sund\000Sundanese\000Sunu\000Sunuwar\000Sylo\000Syloti Nagri\000Syrc\000Syriac\000Syre\000Estrangelo Syriac\000Syrj\000Western Syriac\000Syrn\000Eastern Syriac\000Tagb\000Tagbanwa\000Takr\000Takri\000Tale\000Tai Le\000Talu\000New Tai Lue\000Taml\000Tamil\000Tang\000Tangut\000Tavt\000Tai Viet\000Tayo\000Tai Yo\000Telu\000Telugu\000Teng\000Tengwar\000Tfng\000Tifinagh\000Tglg\000Tagalog\000Thaa\000Thaana\000Thai\000Thai\000Tibt\000Tibetan\000Tirh\000Tirhuta\000Tnsa\000Tangsa\000Todr\000Todhri\000Tols\000Tolong Siki\000Toto\000Toto\000Tutg\000Tulu-Tigalari\000Ugar\000Ugaritic\000Vaii\000Vai\000Visp\000Visible Speech\000Vith\000Vithkuqi\000Wara\000Varang Kshiti\000Wcho\000Wancho\000Wole\000Woleai\000Xpeo\000Old Persian\000Xsux\000Sumero-Akkadian Cuneiform\000Xsux-alt-short\000S-A Cuneiform\000Yezi\000Yezidi\000Yiii\000Yi\000Zanb\000Zanabazar Square\000Zinh\000Inherited\000Zmth\000Mathematical Notation\000Zsye\000Emoji\000Zsym\000Symbols\000Zxxx\000Unwritten\000Zyyy\000Common\000Zzzz\000Unknown Script\000";
+static const char dn_en_calendars[] = "buddhist\000Buddhist Calendar\000chinese\000Chinese Calendar\000coptic\000Coptic Calendar\000core\000Minguo\000dangi\000Dangi Calendar\000ethiopic\000Ethiopic Calendar\000ethiopic-amete-alem\000Ethiopic Amete Alem Calendar\000gregorian\000Gregorian Calendar\000hebrew\000Hebrew Calendar\000indian\000Indian National Calendar\000islamic\000Hijri Calendar\000islamic-civil\000Hijri Calendar (tabular, civil epoch)\000islamic-rgsa\000Hijri Calendar (Saudi Arabia, sighting)\000islamic-tbla\000Hijri Calendar (tabular, astronomical epoch)\000islamic-umalqura\000Hijri Calendar (Umm al-Qura)\000iso8601\000Gregorian Calendar (ISO 8601 Weeks)\000japanese\000Japanese Calendar\000persian\000Persian Calendar\000roc\000Minguo Calendar\000";
+static const char dn_en_dateTimeFields[] = "day\000day\000dayPeriod\000AM/PM\000era\000era\000hour\000hour\000minute\000minute\000month\000month\000quarter\000quarter\000second\000second\000timeZoneName\000time zone\000weekOfYear\000week\000weekday\000day of the week\000year\000year\000";
+static const char dn_en_currencies[] = "ADP\000Andorran Peseta\000AED\000United Arab Emirates Dirham\000AFA\000Afghan Afghani (1927–2002)\000AFN\000Afghan Afghani\000ALK\000Albanian Lek (1946–1965)\000ALL\000Albanian Lek\000AMD\000Armenian Dram\000ANG\000Netherlands Antillean Guilder\000AOA\000Angolan Kwanza\000AOK\000Angolan Kwanza (1977–1991)\000AON\000Angolan New Kwanza (1990–2000)\000AOR\000Angolan Readjusted Kwanza (1995–1999)\000ARA\000Argentine Austral\000ARL\000Argentine Peso Ley (1970–1983)\000ARM\000Argentine Peso (1881–1970)\000ARP\000Argentine Peso (1983–1985)\000ARS\000Argentine Peso\000ATS\000Austrian Schilling\000AUD\000Australian Dollar\000AWG\000Aruban Florin\000AZM\000Azerbaijani Manat (1993–2006)\000AZN\000Azerbaijani Manat\000BAD\000Bosnia-Herzegovina Dinar (1992–1994)\000BAM\000Bosnia-Herzegovina Convertible Mark\000BAN\000Bosnia-Herzegovina New Dinar (1994–1997)\000BBD\000Barbadian Dollar\000BDT\000Bangladeshi Taka\000BEC\000Belgian Franc (convertible)\000BEF\000Belgian Franc\000BEL\000Belgian Franc (financial)\000BGL\000Bulgarian Hard Lev\000BGM\000Bulgarian Socialist Lev\000BGN\000Bulgarian Lev\000BGO\000Bulgarian Lev (1879–1952)\000BHD\000Bahraini Dinar\000BIF\000Burundian Franc\000BMD\000Bermudan Dollar\000BND\000Brunei Dollar\000BOB\000Bolivian Boliviano\000BOL\000Bolivian Boliviano (1863–1963)\000BOP\000Bolivian Peso\000BOV\000Bolivian Mvdol\000BRB\000Brazilian New Cruzeiro (1967–1986)\000BRC\000Brazilian Cruzado (1986–1989)\000BRE\000Brazilian Cruzeiro (1990–1993)\000BRL\000Brazilian Real\000BRN\000Brazilian New Cruzado (1989–1990)\000BRR\000Brazilian Cruzeiro (1993–1994)\000BRZ\000Brazilian Cruzeiro (1942–1967)\000BSD\000Bahamian Dollar\000BTN\000Bhutanese Ngultrum\000BUK\000Burmese Kyat\000BWP\000Botswanan Pula\000BYB\000Belarusian Ruble (1994–1999)\000BYN\000Belarusian Ruble\000BYR\000Belarusian Ruble (2000–2016)\000BZD\000Belize Dollar\000CAD\000Canadian Dollar\000CDF\000Congolese Franc\000CHE\000WIR Euro\000CHF\000Swiss Franc\000CHW\000WIR Franc\000CLE\000Chilean Escudo\000CLF\000Chilean Unit of Account (UF)\000CLP\000Chilean Peso\000CNH\000Chinese Yuan (offshore)\000CNX\000Chinese People’s Bank Dollar\000CNY\000Chinese Yuan\000COP\000Colombian Peso\000COU\000Colombian Real Value Unit\000CRC\000Costa Rican Colón\000CSD\000Serbian Dinar (2002–2006)\000CSK\000Czechoslovak Hard Koruna\000CUC\000Cuban Convertible Peso\000CUP\000Cuban Peso\000CVE\000Cape Verdean Escudo\000CYP\000Cypriot Pound\000CZK\000Czech Koruna\000DDM\000East German Mark\000DEM\000German Mark\000DJF\000Djiboutian Franc\000DKK\000Danish Krone\000DOP\000Dominican Peso\000DZD\000Algerian Dinar\000ECS\000Ecuadorian Sucre\000ECV\000Ecuadorian Unit of Constant Value\000EEK\000Estonian Kroon\000EGP\000Egyptian Pound\000ERN\000Eritrean Nakfa\000ESA\000Spanish Peseta (A account)\000ESB\000Spanish Peseta (convertible account)\000ESP\000Spanish Peseta\000ETB\000Ethiopian Birr\000EUR\000Euro\000FIM\000Finnish Markka\000FJD\000Fijian Dollar\000FKP\000Falkland Islands Pound\000FRF\000French Franc\000GBP\000British Pound\000GEK\000Georgian Kupon Larit\000GEL\000Georgian Lari\000GHC\000Ghanaian Cedi (1979–2007)\000GHS\000Ghanaian Cedi\000GIP\000Gibraltar Pound\000GMD\000Gambian Dalasi\000GNF\000Guinean Franc\000GNS\000Guinean Syli\000GQE\000Equatorial Guinean Ekwele\000GRD\000Greek Drachma\000GTQ\000Guatemalan Quetzal\000GWE\000Portuguese Guinea Escudo\000GWP\000Guinea-Bissau Peso\000GYD\000Guyanaese Dollar\000HKD\000Hong Kong Dollar\000HNL\000Honduran Lempira\000HRD\000Croatian Dinar\000HRK\000Croatian Kuna\000HTG\000Haitian Gourde\000HUF\000Hungarian Forint\000IDR\000Indonesian Rupiah\000IEP\000Irish Pound\000ILP\000Israeli Pound\000ILR\000Israeli Shekel (1980–1985)\000ILS\000Israeli New Shekel\000INR\000Indian Rupee\000IQD\000Iraqi Dinar\000IRR\000Iranian Rial\000ISJ\000Icelandic Króna (1918–1981)\000ISK\000Icelandic Króna\000ITL\000Italian Lira\000JMD\000Jamaican Dollar\000JOD\000Jordanian Dinar\000JPY\000Japanese Yen\000KES\000Kenyan Shilling\000KGS\000Kyrgyz Som\000KHR\000Cambodian Riel\000KMF\000Comorian Franc\000KPW\000North Korean Won\000KRH\000South Korean Hwan (1953–1962)\000KRO\000South Korean Won (1945–1953)\000KRW\000South Korean Won\000KWD\000Kuwaiti Dinar\000KYD\000Cayman Islands Dollar\000KZT\000Kazakhstani Tenge\000LAK\000Laotian Kip\000LBP\000Lebanese Pound\000LKR\000Sri Lankan Rupee\000LRD\000Liberian Dollar\000LSL\000Lesotho Loti\000LTL\000Lithuanian Litas\000LTT\000Lithuanian Talonas\000LUC\000Luxembourgian Convertible Franc\000LUF\000Luxembourgian Franc\000LUL\000Luxembourg Financial Franc\000LVL\000Latvian Lats\000LVR\000Latvian Ruble\000LYD\000Libyan Dinar\000MAD\000Moroccan Dirham\000MAF\000Moroccan Franc\000MCF\000Monegasque Franc\000MDC\000Moldovan Cupon\000MDL\000Moldovan Leu\000MGA\000Malagasy Ariary\000MGF\000Malagasy Franc\000MKD\000Macedonian Denar\000MKN\000Macedonian Denar (1992–1993)\000MLF\000Malian Franc\000MMK\000Myanmar Kyat\000MNT\000Mongolian Tugrik\000MOP\000Macanese Pataca\000MRO\000Mauritanian Ouguiya (1973–2017)\000MRU\000Mauritanian Ouguiya\000MTL\000Maltese Lira\000MTP\000Maltese Pound\000MUR\000Mauritian Rupee\000MVP\000Maldivian Rupee (1947–1981)\000MVR\000Maldivian Rufiyaa\000MWK\000Malawian Kwacha\000MXN\000Mexican Peso\000MXP\000Mexican Silver Peso (1861–1992)\000MXV\000Mexican Investment Unit\000MYR\000Malaysian Ringgit\000MZE\000Mozambican Escudo\000MZM\000Mozambican Metical (1980–2006)\000MZN\000Mozambican Metical\000NAD\000Namibian Dollar\000NGN\000Nigerian Naira\000NIC\000Nicaraguan Córdoba (1988–1991)\000NIO\000Nicaraguan Córdoba\000NLG\000Dutch Guilder\000NOK\000Norwegian Krone\000NPR\000Nepalese Rupee\000NZD\000New Zealand Dollar\000OMR\000Omani Rial\000PAB\000Panamanian Balboa\000PEI\000Peruvian Inti\000PEN\000Peruvian Sol\000PES\000Peruvian Sol (1863–1965)\000PGK\000Papua New Guinean Kina\000PHP\000Philippine Peso\000PKR\000Pakistani Rupee\000PLN\000Polish Zloty\000PLZ\000Polish Zloty (1950–1995)\000PTE\000Portuguese Escudo\000PYG\000Paraguayan Guarani\000QAR\000Qatari Riyal\000RHD\000Rhodesian Dollar\000ROL\000Romanian Leu (1952–2006)\000RON\000Romanian Leu\000RSD\000Serbian Dinar\000RUB\000Russian Ruble\000RUR\000Russian Ruble (1991–1998)\000RWF\000Rwandan Franc\000SAR\000Saudi Riyal\000SBD\000Solomon Islands Dollar\000SCR\000Seychellois Rupee\000SDD\000Sudanese Dinar (1992–2007)\000SDG\000Sudanese Pound\000SDP\000Sudanese Pound (1957–1998)\000SEK\000Swedish Krona\000SGD\000Singapore Dollar\000SHP\000St. Helena Pound\000SIT\000Slovenian Tolar\000SKK\000Slovak Koruna\000SLE\000Sierra Leonean Leone\000SLL\000Sierra Leonean Leone (1964—2022)\000SOS\000Somali Shilling\000SRD\000Surinamese Dollar\000SRG\000Surinamese Guilder\000SSP\000South Sudanese Pound\000STD\000São Tomé & Príncipe Dobra (1977–2017)\000STN\000São Tomé & Príncipe Dobra\000SUR\000Soviet Rouble\000SVC\000Salvadoran Colón\000SYP\000Syrian Pound\000SZL\000Swazi Lilangeni\000THB\000Thai Baht\000TJR\000Tajikistani Ruble\000TJS\000Tajikistani Somoni\000TMM\000Turkmenistani Manat (1993–2009)\000TMT\000Turkmenistani Manat\000TND\000Tunisian Dinar\000TOP\000Tongan Paʻanga\000TPE\000Timorese Escudo\000TRL\000Turkish Lira (1922–2005)\000TRY\000Turkish Lira\000TTD\000Trinidad & Tobago Dollar\000TWD\000New Taiwan Dollar\000TZS\000Tanzanian Shilling\000UAH\000Ukrainian Hryvnia\000UAK\000Ukrainian Karbovanets\000UGS\000Ugandan Shilling (1966–1987)\000UGX\000Ugandan Shilling\000USD\000US Dollar\000USN\000US Dollar (Next day)\000USS\000US Dollar (Same day)\000UYI\000Uruguayan Peso (Indexed Units)\000UYP\000Uruguayan Peso (1975–1993)\000UYU\000Uruguayan Peso\000UYW\000Uruguayan Nominal Wage Index Unit\000UZS\000Uzbekistani Som\000VEB\000Venezuelan Bolívar (1871–2008)\000VED\000Bolívar Soberano\000VEF\000Venezuelan Bolívar (2008–2018)\000VES\000Venezuelan Bolívar\000VND\000Vietnamese Dong\000VNN\000Vietnamese Dong (1978–1985)\000VUV\000Vanuatu Vatu\000WST\000Samoan Tala\000XAF\000Central African CFA Franc\000XAG\000Silver\000XAU\000Gold\000XBA\000European Composite Unit\000XBB\000European Monetary Unit\000XBC\000European Unit of Account (XBC)\000XBD\000European Unit of Account (XBD)\000XCD\000East Caribbean Dollar\000XCG\000Caribbean guilder\000XDR\000Special Drawing Rights\000XEU\000European Currency Unit\000XFO\000French Gold Franc\000XFU\000French UIC-Franc\000XOF\000West African CFA Franc\000XPD\000Palladium\000XPF\000CFP Franc\000XPT\000Platinum\000XRE\000RINET Funds\000XSU\000Sucre\000XTS\000Testing Currency Code\000XUA\000ADB Unit of Account\000XXX\000Unknown Currency\000YDD\000Yemeni Dinar\000YER\000Yemeni Rial\000YUD\000Yugoslavian Hard Dinar (1966–1990)\000YUM\000Yugoslavian New Dinar (1994–2002)\000YUN\000Yugoslavian Convertible Dinar (1990–1992)\000YUR\000Yugoslavian Reformed Dinar (1992–1993)\000ZAL\000South African Rand (financial)\000ZAR\000South African Rand\000ZMK\000Zambian Kwacha (1968–2012)\000ZMW\000Zambian Kwacha\000ZRN\000Zairean New Zaire (1993–1998)\000ZRZ\000Zairean Zaire (1971–1993)\000ZWD\000Zimbabwean Dollar (1980–2008)\000ZWG\000Zimbabwean Gold\000ZWL\000Zimbabwean Dollar (2009–2024)\000ZWR\000Zimbabwean Dollar (2008)\000";
+
+/* DisplayNames data for fr */
+static const char dn_fr_languages[] = "aa\000afar\000ab\000abkhaze\000ace\000aceh\000ach\000acoli\000ada\000adangme\000ady\000adyguéen\000ae\000avestique\000aeb\000arabe tunisien\000af\000afrikaans\000afh\000afrihili\000agq\000aghem\000ain\000aïnou\000ak\000akan\000akk\000akkadien\000akz\000alabama\000ale\000aléoute\000aln\000guègue\000alt\000altaï du Sud\000am\000amharique\000an\000aragonais\000ang\000ancien anglais\000ann\000obolo\000anp\000angika\000ar\000arabe\000ar-001\000arabe standard moderne\000arc\000araméen\000arn\000mapuche\000aro\000araona\000arp\000arapaho\000arq\000arabe algérien\000ars\000arabe najdi\000arw\000arawak\000ary\000arabe marocain\000arz\000arabe égyptien\000as\000assamais\000asa\000asu\000ase\000langue des signes américaine\000ast\000asturien\000atj\000atikamekw\000av\000avar\000avk\000kotava\000awa\000awadhi\000ay\000aymara\000az\000azerbaïdjanais\000az-alt-short\000azéri\000ba\000bachkir\000bal\000baloutchi\000ban\000balinais\000bar\000bavarois\000bas\000bassa\000bax\000bamoun\000bbc\000batak toba\000bbj\000ghomalaʼ\000be\000biélorusse\000bej\000bedja\000bem\000bemba\000bew\000betawi\000bez\000bena\000bfd\000bafut\000bfq\000badaga\000bg\000bulgare\000bgc\000haryanvi\000bgn\000baloutchi occidental\000bho\000bhodjpouri\000bi\000bichelamar\000bik\000bikol\000bin\000bini\000bjn\000banjar\000bkm\000kom\000bla\000siksika\000blo\000anii\000bm\000bambara\000bn\000bengali\000bo\000tibétain\000bpy\000bishnupriya\000bqi\000bakhtiari\000br\000breton\000bra\000braj\000brh\000brahoui\000brx\000bodo\000bs\000bosniaque\000bss\000akoose\000bua\000bouriate\000bug\000bugi\000bum\000boulou\000byn\000blin\000byv\000médumba\000ca\000catalan\000cad\000caddo\000car\000caribe\000cay\000cayuga\000cch\000atsam\000ccp\000changma kodha\000ce\000tchétchène\000ceb\000cebuano\000cgg\000kiga\000ch\000chamorro\000chb\000chibcha\000chg\000tchaghataï\000chk\000chuuk\000chm\000mari\000chn\000jargon chinook\000cho\000choctaw\000chp\000chipewyan\000chr\000cherokee\000chy\000cheyenne\000ckb\000sorani\000ckb-alt-menu\000kurde sorani\000clc\000chilcotin\000co\000corse\000cop\000copte\000cps\000capiznon\000cr\000cree\000crg\000mitchif\000crh\000tatar de Crimée\000crj\000cri de l’Est (dialecte du Sud)\000crk\000cri des plaines\000crl\000cri de l’Est (dialecte du Nord)\000crm\000cri de Moose\000crr\000algonquin de Caroline\000crs\000créole seychellois\000cs\000tchèque\000csb\000kachoube\000csw\000cri des marais\000cu\000slavon d’église\000cv\000tchouvache\000cy\000gallois\000da\000danois\000dak\000dakota\000dar\000dargwa\000dav\000taita\000de\000allemand\000de-AT\000allemand autrichien\000de-CH\000allemand suisse\000del\000delaware\000den\000esclave\000dgr\000dogrib\000din\000dinka\000dje\000zarma\000doi\000dogri\000dsb\000bas-sorabe\000dtp\000dusun central\000dua\000douala\000dum\000moyen néerlandais\000dv\000maldivien\000dyo\000diola-fogny\000dyu\000dioula\000dz\000dzongkha\000dzg\000dazaga\000ebu\000embu\000ee\000éwé\000efi\000éfik\000egl\000émilien\000egy\000égyptien ancien\000eka\000ékadjouk\000el\000grec\000elx\000élamite\000en\000anglais\000en-AU\000anglais australien\000en-CA\000anglais canadien\000en-GB\000anglais britannique\000en-US\000anglais américain\000enm\000moyen anglais\000eo\000espéranto\000es\000espagnol\000es-419\000espagnol d’Amérique latine\000es-ES\000espagnol d’Espagne\000es-MX\000espagnol du Mexique\000esu\000youpik central\000et\000estonien\000eu\000basque\000ewo\000éwondo\000ext\000estrémègne\000fa\000persan\000fa-AF\000dari\000fan\000fang\000fat\000fanti\000ff\000peul\000fi\000finnois\000fil\000filipino\000fit\000finnois tornédalien\000fj\000fidjien\000fo\000féroïen\000fon\000fon\000fr\000français\000fr-CA\000français canadien\000fr-CH\000français suisse\000frc\000français cadien\000frm\000moyen français\000fro\000ancien français\000frp\000francoprovençal\000frr\000frison septentrional\000frs\000frison oriental\000fur\000frioulan\000fy\000frison occidental\000ga\000irlandais\000gaa\000ga\000gag\000gagaouze\000gan\000gan\000gay\000gayo\000gba\000gbaya\000gbz\000dari zoroastrien\000gd\000gaélique écossais\000gez\000guèze\000gil\000gilbertin\000gl\000galicien\000glk\000gilaki\000gmh\000moyen haut-allemand\000gn\000guarani\000goh\000ancien haut allemand\000gon\000gondi\000gor\000gorontalo\000got\000gotique\000grb\000grebo\000grc\000grec ancien\000gsw\000suisse allemand\000gu\000goudjarati\000guc\000wayuu\000gur\000gurenne\000guz\000gusii\000gv\000mannois\000gwi\000gwichʼin\000ha\000haoussa\000hai\000haïda\000hak\000hakka\000haw\000hawaïen\000hax\000haïda du Sud\000he\000hébreu\000hi\000hindi\000hi-Latn-alt-variant\000hinglish\000hif\000hindi fidjien\000hil\000hiligaynon\000hit\000hittite\000hmn\000hmong\000ho\000hiri motu\000hr\000croate\000hsb\000haut-sorabe\000hsn\000xiang\000ht\000créole haïtien\000hu\000hongrois\000hup\000hupa\000hur\000halkomelem\000hy\000arménien\000hz\000héréro\000ia\000interlingua\000iba\000iban\000ibb\000ibibio\000id\000indonésien\000ie\000interlingue\000ig\000igbo\000ii\000yi du Sichuan\000ik\000inupiaq\000ikt\000inuktitut de l’Ouest canadien\000ilo\000ilocano\000inh\000ingouche\000io\000ido\000is\000islandais\000it\000italien\000iu\000inuktitut\000izh\000ingrien\000ja\000japonais\000jam\000créole jamaïcain\000jbo\000lojban\000jgo\000ngomba\000jmc\000matchamé\000jpr\000judéo-persan\000jrb\000judéo-arabe\000jut\000jute\000jv\000javanais\000ka\000géorgien\000kaa\000karakalpak\000kab\000kabyle\000kac\000kachin\000kaj\000jju\000kam\000kamba\000kaw\000kawi\000kbd\000kabarde\000kbl\000kanembou\000kcg\000tyap\000kde\000makondé\000kea\000capverdien\000ken\000kényang\000kfo\000koro\000kg\000kikongo\000kgp\000caingangue\000kha\000khasi\000kho\000khotanais\000khq\000koyra chiini\000khw\000khowar\000ki\000kikuyu\000kiu\000kirmanjki\000kj\000kuanyama\000kk\000kazakh\000kkj\000kako\000kl\000groenlandais\000kln\000kalendjin\000km\000khmer\000kmb\000kimboundou\000kn\000kannada\000ko\000coréen\000koi\000komi-permiak\000kok\000konkani\000kos\000kosraéen\000kpe\000kpellé\000kr\000kanouri\000krc\000karatchaï balkar\000kri\000krio\000krj\000kinaray-a\000krl\000carélien\000kru\000kouroukh\000ks\000cachemiri\000ksb\000shambala\000ksf\000bafia\000ksh\000kölsch\000ku\000kurde\000ku-menu-core\000kurde\000ku-menu-extension\000kurmandji\000kum\000koumyk\000kut\000kutenai\000kv\000komi\000kw\000cornique\000kwk\000kwak’wala\000kxv\000kuvi\000ky\000kirghize\000la\000latin\000lad\000ladino\000lag\000langi\000lah\000lahnda\000lam\000lamba\000lb\000luxembourgeois\000lez\000lezghien\000lfn\000lingua franca nova\000lg\000ganda\000li\000limbourgeois\000lij\000ligure\000lil\000lillooet\000liv\000livonien\000lkt\000lakota\000lmo\000lombard\000ln\000lingala\000lo\000lao\000lol\000mongo\000lou\000créole louisianais\000loz\000lozi\000lrc\000lori du Nord\000lsm\000samia\000lt\000lituanien\000ltg\000latgalien\000lu\000luba-katanga (kiluba)\000lua\000luba-kasaï (ciluba)\000lui\000luiseño\000lun\000lunda\000lus\000lushaï\000luy\000luyia\000lv\000letton\000lzh\000chinois littéraire\000lzz\000laze\000mad\000madurais\000maf\000mafa\000mag\000magahi\000mai\000maïthili\000mak\000makassar\000man\000mandingue\000mas\000maasaï\000mde\000maba\000mdf\000mokcha\000mdr\000mandar\000men\000mendé\000mer\000meru\000mfe\000créole mauricien\000mg\000malgache\000mga\000moyen irlandais\000mgh\000makua\000mgo\000metaʼ\000mh\000marshallais\000mi\000maori\000mic\000micmac\000min\000minangkabau\000mk\000macédonien\000ml\000malayalam\000mn\000mongol\000mnc\000mandchou\000mni\000manipuri\000moe\000innu-aimun\000moh\000mohawk\000mos\000moré\000mr\000marathi\000mrj\000mari occidental\000ms\000malais\000mt\000maltais\000mua\000moundang\000mul\000multilingue\000mus\000creek\000mwl\000mirandais\000mwr\000marwarî\000mwv\000mentawaï\000my\000birman\000mye\000myènè\000myv\000erzya\000mzn\000mazandérani\000na\000nauruan\000nan\000minnan\000nap\000napolitain\000naq\000nama\000nb\000norvégien bokmål\000nd\000ndébélé du Nord\000nds\000bas-allemand\000nds-NL\000bas-saxon néerlandais\000ne\000népalais\000new\000newari\000ng\000ndonga\000nia\000niha\000niu\000niuéen\000njo\000ao\000nl\000néerlandais\000nl-BE\000flamand\000nmg\000ngoumba\000nn\000norvégien nynorsk\000nnh\000ngiemboon\000no\000norvégien\000nog\000nogaï\000non\000vieux norrois\000nov\000novial\000nqo\000n’ko\000nr\000ndébélé du Sud\000nso\000sotho du Nord\000nus\000nuer\000nv\000navajo\000nwc\000newarî classique\000ny\000chewa\000nym\000nyamwezi\000nyn\000nyankolé\000nyo\000nyoro\000nzi\000nzema\000oc\000occitan\000oj\000ojibwa\000ojb\000ojibwé du Nord-Ouest\000ojc\000ojibwé central\000ojs\000oji-cri\000ojw\000ojibwé occidental\000oka\000colville-okanagan\000om\000oromo\000or\000odia\000os\000ossète\000osa\000osage\000ota\000turc ottoman\000pa\000pendjabi\000pag\000pangasinan\000pal\000pahlavi\000pam\000pampangan\000pap\000papiamento\000pau\000palau\000pcd\000picard\000pcm\000pidgin nigérian\000pdc\000pennsilfaanisch\000pdt\000bas-prussien\000peo\000persan ancien\000pfl\000allemand palatin\000phn\000phénicien\000pi\000pali\000pis\000pijin\000pl\000polonais\000pms\000piémontais\000pnt\000pontique\000pon\000pohnpei\000pqm\000malécite-passamaquoddy\000prg\000prussien\000pro\000provençal ancien\000ps\000pachto\000ps-alt-variant\000pashto\000pt\000portugais\000pt-BR\000portugais brésilien\000pt-PT\000portugais européen\000qu\000quechua\000quc\000quiché\000qug\000quichua du Haut-Chimborazo\000raj\000rajasthani\000rap\000rapanui\000rar\000rarotongien\000rgn\000romagnol\000rhg\000rohingya\000rif\000rifain\000rm\000romanche\000rn\000roundi\000ro\000roumain\000ro-MD\000moldave\000rof\000rombo\000rom\000romani\000rtm\000rotuman\000ru\000russe\000rue\000ruthène\000rug\000roviana\000rup\000aroumain\000rw\000kinyarwanda\000rwk\000rwa\000sa\000sanskrit\000sad\000sandawe\000sah\000iakoute\000sam\000araméen samaritain\000saq\000samburu\000sas\000sasak\000sat\000santali\000saz\000saurashtra\000sba\000ngambay\000sbp\000isangu\000sc\000sarde\000scn\000sicilien\000sco\000écossais\000sd\000sindhi\000sdc\000sarde sassarais\000sdh\000kurde du Sud\000se\000same du Nord\000see\000seneca\000seh\000cisena\000sei\000séri\000sel\000selkoupe\000ses\000koyraboro senni\000sg\000sango\000sga\000ancien irlandais\000sgs\000samogitien\000sh\000serbo-croate\000shi\000chleuh\000shn\000shan\000shu\000arabe tchadien\000si\000cingalais\000sid\000sidamo\000sk\000slovaque\000sl\000slovène\000slh\000lushootseed du Sud\000sli\000bas-silésien\000sly\000sélayar\000sm\000samoan\000sma\000same du Sud\000smj\000same de Lule\000smn\000same d’Inari\000sms\000same skolt\000sn\000shona\000snk\000soninké\000so\000somali\000sog\000sogdien\000sq\000albanais\000sr\000serbe\000srn\000sranan tongo\000srr\000sérère\000ss\000swati\000ssy\000saho\000st\000sotho du Sud\000stq\000saterlandais\000str\000salish des détroits\000su\000soundanais\000suk\000soukouma\000sus\000soussou\000sux\000sumérien\000sv\000suédois\000sw\000swahili\000sw-CD\000swahili du Congo\000swb\000comorien\000syc\000syriaque classique\000syr\000syriaque\000szl\000silésien\000ta\000tamoul\000tce\000tutchone du Sud\000tcy\000toulou\000te\000télougou\000tem\000timné\000teo\000teso\000ter\000tereno\000tet\000tétoum\000tg\000tadjik\000tgx\000tagish\000th\000thaï\000tht\000tahltan\000ti\000tigrigna\000tig\000tigré\000tiv\000tiv\000tk\000turkmène\000tkl\000tokelau\000tkr\000tsakhour\000tl\000tagalog\000tlh\000klingon\000tli\000tlingit\000tly\000talysh\000tmh\000tamacheq\000tn\000tswana\000to\000tongien\000tog\000tonga nyasa\000tok\000toki pona\000tpi\000tok pisin\000tr\000turc\000tru\000touroyo\000trv\000taroko\000ts\000tsonga\000tsd\000tsakonien\000tsi\000tsimshian\000tt\000tatar\000ttm\000tutchone du Nord\000ttt\000tati caucasien\000tum\000tumbuka\000tvl\000tuvalu\000tw\000twi\000twq\000tasawaq\000ty\000tahitien\000tyv\000touvain\000tzm\000amazighe de l’Atlas central\000udm\000oudmourte\000ug\000ouïghour\000ug-alt-variant\000ouïgour\000uga\000ougaritique\000uk\000ukrainien\000umb\000umbundu\000und\000langue indéterminée\000ur\000ourdou\000uz\000ouzbek\000vai\000vaï\000ve\000venda\000vec\000vénitien\000vep\000vepse\000vi\000vietnamien\000vls\000flamand occidental\000vmf\000franconien du Main\000vmw\000macua\000vo\000volapük\000vot\000vote\000vro\000võro\000vun\000vunjo\000wa\000wallon\000wae\000walser\000wal\000walamo\000war\000waray\000was\000washo\000wbp\000warlpiri\000wo\000wolof\000wuu\000wu\000xal\000kalmouk\000xh\000xhosa\000xmf\000mingrélien\000xnr\000kangri\000xog\000soga\000yao\000yao\000yap\000yapois\000yav\000yangben\000ybb\000yemba\000yi\000yiddish\000yo\000yoruba\000yrl\000nheengatou\000yue\000cantonais\000yue-alt-menu\000chinois cantonais\000za\000zhuang\000zap\000zapotèque\000zbl\000symboles Bliss\000zea\000zélandais\000zen\000zenaga\000zgh\000amazighe standard marocain\000zh\000chinois\000zh-Hans\000chinois simplifié\000zh-Hans-alt-long\000mandarin simplifié\000zh-Hant\000chinois traditionnel\000zh-Hant-alt-long\000mandarin traditionnel\000zh-alt-menu\000chinois mandarin\000zu\000zoulou\000zun\000zuñi\000zxx\000sans contenu linguistique\000zza\000zazaki\000";
+static const char dn_fr_regions[] = "001\000Monde\000002\000Afrique\000003\000Amérique du Nord\000005\000Amérique du Sud\000009\000Océanie\000011\000Afrique occidentale\000013\000Amérique centrale\000014\000Afrique orientale\000015\000Afrique septentrionale\000017\000Afrique centrale\000018\000Afrique australe\000019\000Amériques\000021\000Amérique septentrionale\000029\000Caraïbes\000030\000Asie de l’Est\000034\000Asie du Sud\000035\000Asie du Sud-Est\000039\000Europe du Sud\000053\000Australasie\000054\000Mélanésie\000057\000région micronésienne\000061\000Polynésie\000142\000Asie\000143\000Asie centrale\000145\000Asie de l’Ouest\000150\000Europe\000151\000Europe de l’Est\000154\000Europe du Nord\000155\000Europe de l’Ouest\000202\000Afrique subsaharienne\000419\000Amérique latine\000AC\000Île de l’Ascension\000AD\000Andorre\000AE\000Émirats arabes unis\000AF\000Afghanistan\000AG\000Antigua-et-Barbuda\000AI\000Anguilla\000AL\000Albanie\000AM\000Arménie\000AO\000Angola\000AQ\000Antarctique\000AR\000Argentine\000AS\000Samoa américaines\000AT\000Autriche\000AU\000Australie\000AW\000Aruba\000AX\000Îles Åland\000AZ\000Azerbaïdjan\000BA\000Bosnie-Herzégovine\000BB\000Barbade\000BD\000Bangladesh\000BE\000Belgique\000BF\000Burkina Faso\000BG\000Bulgarie\000BH\000Bahreïn\000BI\000Burundi\000BJ\000Bénin\000BL\000Saint-Barthélemy\000BM\000Bermudes\000BN\000Brunei\000BO\000Bolivie\000BQ\000Pays-Bas caribéens\000BR\000Brésil\000BS\000Bahamas\000BT\000Bhoutan\000BV\000Île Bouvet\000BW\000Botswana\000BY\000Biélorussie\000BZ\000Belize\000CA\000Canada\000CC\000Îles Cocos\000CD\000Congo-Kinshasa\000CF\000République centrafricaine\000CG\000Congo-Brazzaville\000CH\000Suisse\000CI\000Côte d’Ivoire\000CK\000Îles Cook\000CL\000Chili\000CM\000Cameroun\000CN\000Chine\000CO\000Colombie\000CP\000Île Clipperton\000CQ\000Sercq\000CR\000Costa Rica\000CU\000Cuba\000CV\000Cap-Vert\000CW\000Curaçao\000CX\000Île Christmas\000CY\000Chypre\000CZ\000Tchéquie\000DE\000Allemagne\000DG\000Diego Garcia\000DJ\000Djibouti\000DK\000Danemark\000DM\000Dominique\000DO\000République dominicaine\000DZ\000Algérie\000EA\000Ceuta et Melilla\000EC\000Équateur\000EE\000Estonie\000EG\000Égypte\000EH\000Sahara occidental\000ER\000Érythrée\000ES\000Espagne\000ET\000Éthiopie\000EU\000Union européenne\000EZ\000zone euro\000FI\000Finlande\000FJ\000Fidji\000FK\000Îles Malouines\000FM\000Micronésie\000FO\000Îles Féroé\000FR\000France\000GA\000Gabon\000GB\000Royaume-Uni\000GD\000Grenade\000GE\000Géorgie\000GF\000Guyane française\000GG\000Guernesey\000GH\000Ghana\000GI\000Gibraltar\000GL\000Groenland\000GM\000Gambie\000GN\000Guinée\000GP\000Guadeloupe\000GQ\000Guinée équatoriale\000GR\000Grèce\000GS\000Géorgie du Sud-et-les Îles Sandwich du Sud\000GT\000Guatemala\000GU\000Guam\000GW\000Guinée-Bissau\000GY\000Guyana\000HK\000R.A.S. chinoise de Hong Kong\000HM\000Îles Heard-et-MacDonald\000HN\000Honduras\000HR\000Croatie\000HT\000Haïti\000HU\000Hongrie\000IC\000Îles Canaries\000ID\000Indonésie\000IE\000Irlande\000IL\000Israël\000IM\000Île de Man\000IN\000Inde\000IO\000Territoire britannique de l’océan Indien\000IQ\000Irak\000IR\000Iran\000IS\000Islande\000IT\000Italie\000JE\000Jersey\000JM\000Jamaïque\000JO\000Jordanie\000JP\000Japon\000KE\000Kenya\000KG\000Kirghizstan\000KH\000Cambodge\000KI\000Kiribati\000KM\000Comores\000KN\000Saint-Christophe-et-Niévès\000KP\000Corée du Nord\000KR\000Corée du Sud\000KW\000Koweït\000KY\000Îles Caïmans\000KZ\000Kazakhstan\000LA\000Laos\000LB\000Liban\000LC\000Sainte-Lucie\000LI\000Liechtenstein\000LK\000Sri Lanka\000LR\000Liberia\000LS\000Lesotho\000LT\000Lituanie\000LU\000Luxembourg\000LV\000Lettonie\000LY\000Libye\000MA\000Maroc\000MC\000Monaco\000MD\000Moldavie\000ME\000Monténégro\000MF\000Saint-Martin\000MG\000Madagascar\000MH\000Îles Marshall\000MK\000Macédoine du Nord\000ML\000Mali\000MM\000Myanmar (Birmanie)\000MN\000Mongolie\000MO\000R.A.S. chinoise de Macao\000MP\000Îles Mariannes du Nord\000MQ\000Martinique\000MR\000Mauritanie\000MS\000Montserrat\000MT\000Malte\000MU\000Maurice\000MV\000Maldives\000MW\000Malawi\000MX\000Mexique\000MY\000Malaisie\000MZ\000Mozambique\000NA\000Namibie\000NC\000Nouvelle-Calédonie\000NE\000Niger\000NF\000Île Norfolk\000NG\000Nigeria\000NI\000Nicaragua\000NL\000Pays-Bas\000NO\000Norvège\000NP\000Népal\000NR\000Nauru\000NU\000Niue\000NZ\000Nouvelle-Zélande\000OM\000Oman\000PA\000Panama\000PE\000Pérou\000PF\000Polynésie française\000PG\000Papouasie-Nouvelle-Guinée\000PH\000Philippines\000PK\000Pakistan\000PL\000Pologne\000PM\000Saint-Pierre-et-Miquelon\000PN\000Îles Pitcairn\000PR\000Porto Rico\000PS\000Territoires palestiniens\000PT\000Portugal\000PW\000Palaos\000PY\000Paraguay\000QA\000Qatar\000QO\000régions éloignées de l’Océanie\000RE\000La Réunion\000RO\000Roumanie\000RS\000Serbie\000RU\000Russie\000RW\000Rwanda\000SA\000Arabie saoudite\000SB\000Îles Salomon\000SC\000Seychelles\000SD\000Soudan\000SE\000Suède\000SG\000Singapour\000SH\000Sainte-Hélène\000SI\000Slovénie\000SJ\000Svalbard et Jan Mayen\000SK\000Slovaquie\000SL\000Sierra Leone\000SM\000Saint-Marin\000SN\000Sénégal\000SO\000Somalie\000SR\000Suriname\000SS\000Soudan du Sud\000ST\000Sao Tomé-et-Principe\000SV\000Salvador\000SX\000Saint-Martin (partie néerlandaise)\000SY\000Syrie\000SZ\000Eswatini\000TA\000Tristan da Cunha\000TC\000Îles Turques-et-Caïques\000TD\000Tchad\000TF\000Terres australes françaises\000TG\000Togo\000TH\000Thaïlande\000TJ\000Tadjikistan\000TK\000Tokelau\000TL\000Timor oriental\000TM\000Turkménistan\000TN\000Tunisie\000TO\000Tonga\000TR\000Turquie\000TT\000Trinité-et-Tobago\000TV\000Tuvalu\000TW\000Taïwan\000TZ\000Tanzanie\000UA\000Ukraine\000UG\000Ouganda\000UM\000Îles mineures éloignées des États-Unis\000UN\000Nations Unies\000US\000États-Unis\000UY\000Uruguay\000UZ\000Ouzbékistan\000VA\000État de la Cité du Vatican\000VC\000Saint-Vincent-et-les Grenadines\000VE\000Venezuela\000VG\000Îles Vierges britanniques\000VI\000Îles Vierges des États-Unis\000VN\000Viêt Nam\000VU\000Vanuatu\000WF\000Wallis-et-Futuna\000WS\000Samoa\000XA\000pseudo-accents\000XB\000pseudo-bidi\000XK\000Kosovo\000YE\000Yémen\000YT\000Mayotte\000ZA\000Afrique du Sud\000ZM\000Zambie\000ZW\000Zimbabwe\000ZZ\000région inconnue\000";
+static const char dn_fr_regions_short[] = "GB\000R.-U.\000HK\000Hong Kong\000MO\000Macao\000PS\000Palestine\000UN\000ONU\000US\000É.-U.\000";
+static const char dn_fr_scripts[] = "Adlm\000adlam\000Arab\000arabe\000Arab-alt-variant\000arabo-persan\000Aran\000nastaliq\000Armi\000araméen impérial\000Armn\000arménien\000Avst\000avestique\000Bali\000balinais\000Batk\000batak\000Beng\000bengali\000Blis\000symboles Bliss\000Bopo\000bopomofo\000Brah\000brâhmî\000Brai\000braille\000Bugi\000bouguis\000Buhd\000bouhide\000Cakm\000chakma\000Cans\000syllabaire autochtone canadien unifié\000Cari\000carien\000Cham\000cham\000Cher\000cherokee\000Cirt\000cirth\000Copt\000copte\000Cprt\000syllabaire chypriote\000Cyrl\000cyrillique\000Cyrs\000cyrillique (variante slavonne)\000Deva\000dévanagari\000Dsrt\000déséret\000Egyd\000démotique égyptien\000Egyh\000hiératique égyptien\000Egyp\000hiéroglyphes égyptiens\000Elym\000élymaïque\000Ethi\000éthiopique\000Geok\000géorgien khoutsouri\000Geor\000géorgien\000Glag\000glagolitique\000Goth\000gotique\000Grek\000grec\000Gujr\000goudjarâtî\000Guru\000gourmoukhî\000Hanb\000han avec bopomofo\000Hang\000hangûl\000Hani\000sinogrammes\000Hano\000hanounóo\000Hans\000simplifié\000Hans-alt-stand-alone\000sinogrammes simplifiés\000Hant\000traditionnel\000Hant-alt-stand-alone\000sinogrammes traditionnels\000Hebr\000hébreu\000Hira\000hiragana\000Hmng\000pahawh hmong\000Hmnp\000nyiakeng puachue hmong\000Hrkt\000katakana ou hiragana\000Hung\000ancien hongrois\000Inds\000indus\000Ital\000ancien italique\000Jamo\000jamo\000Java\000javanais\000Jpan\000japonais\000Kali\000kayah li\000Kana\000katakana\000Khar\000kharochthî\000Khmr\000khmer\000Knda\000kannara\000Kore\000coréen\000Kthi\000kaithî\000Lana\000lanna\000Laoo\000lao\000Latf\000latin (variante brisée)\000Latg\000latin (variante gaélique)\000Latn\000latin\000Lepc\000lepcha\000Limb\000limbou\000Lina\000linéaire A\000Linb\000linéaire B\000Lyci\000lycien\000Lydi\000lydien\000Mand\000mandéen\000Mani\000manichéen\000Maya\000hiéroglyphes mayas\000Mero\000méroïtique\000Mlym\000malayalam\000Mong\000mongol\000Moon\000moon\000Mtei\000meitei mayek\000Mymr\000birman\000Nand\000nandinagari\000Nkoo\000n’ko\000Ogam\000ogam\000Olck\000ol-chiki\000Orkh\000orkhon\000Orya\000odia\000Osma\000osmanais\000Perm\000ancien permien\000Phag\000phags pa\000Phli\000pehlevi des inscriptions\000Phlp\000pehlevi des psautiers\000Phlv\000pehlevi des livres\000Phnx\000phénicien\000Plrd\000phonétique de Pollard\000Prti\000parthe des inscriptions\000Qaag\000zawgyi\000Rjng\000rejang\000Rohg\000hanifi\000Roro\000rongorongo\000Runr\000runique\000Samr\000samaritain\000Sara\000sarati\000Saur\000saurashtra\000Sgnw\000écriture des signes\000Shaw\000shavien\000Sinh\000cingalais\000Sund\000sundanais\000Sylo\000sylotî nâgrî\000Syrc\000syriaque\000Syre\000syriaque estranghélo\000Syrj\000syriaque occidental\000Syrn\000syriaque oriental\000Tagb\000tagbanoua\000Tale\000taï-le\000Talu\000nouveau taï-lue\000Taml\000tamoul\000Tavt\000taï viêt\000Telu\000télougou\000Teng\000tengwar\000Tfng\000tifinagh\000Tglg\000tagal\000Thaa\000thâna\000Thai\000thaï\000Tibt\000tibétain\000Ugar\000ougaritique\000Vaii\000vaï\000Visp\000parole visible\000Wcho\000wantcho\000Xpeo\000cunéiforme persépolitain\000Xsux\000cunéiforme suméro-akkadien\000Yiii\000yi\000Zinh\000hérité\000Zmth\000notation mathématique\000Zsye\000emoji\000Zsym\000symboles\000Zxxx\000non écrit\000Zyyy\000commun\000Zzzz\000écriture inconnue\000";
+static const char dn_fr_calendars[] = "buddhist\000calendrier bouddhiste\000chinese\000calendrier chinois\000coptic\000calendrier copte\000core\000républicain chinois\000dangi\000calendrier dangi\000ethiopic\000calendrier éthiopien\000ethiopic-amete-alem\000calendrier éthiopien Amete Alem\000gregorian\000calendrier grégorien\000hebrew\000calendrier hébraïque\000indian\000calendrier indien\000islamic\000calendrier hégirien\000islamic-civil\000calendrier hégirien (tabulaire, époque civile)\000islamic-tbla\000calendrier hégirien (tabulaire, époque astronomique)\000islamic-umalqura\000calendrier hégirien (Umm al-Qura)\000iso8601\000calendrier ISO 8601\000japanese\000calendrier japonais\000persian\000calendrier persan\000roc\000calendrier républicain chinois\000";
+static const char dn_fr_dateTimeFields[] = "day\000jour\000dayPeriod\000cadran\000era\000ère\000hour\000heure\000minute\000minute\000month\000mois\000quarter\000trimestre\000second\000seconde\000timeZoneName\000fuseau horaire\000weekOfYear\000semaine\000weekday\000jour de la semaine\000year\000année\000";
+static const char dn_fr_currencies[] = "ADP\000peseta andorrane\000AED\000dirham des Émirats arabes unis\000AFA\000afghani (1927–2002)\000AFN\000afghani afghan\000ALK\000lek albanais (1947–1961)\000ALL\000lek albanais\000AMD\000dram arménien\000ANG\000florin antillais\000AOA\000kwanza angolais\000AOK\000kwanza angolais (1977–1990)\000AON\000nouveau kwanza angolais (1990–2000)\000AOR\000kwanza angolais réajusté (1995–1999)\000ARA\000austral argentin\000ARP\000peso argentin (1983–1985)\000ARS\000peso argentin\000ATS\000schilling autrichien\000AUD\000dollar australien\000AWG\000florin arubais\000AZM\000manat azéri (1993–2006)\000AZN\000manat azéri\000BAD\000dinar bosniaque\000BAM\000mark convertible bosniaque\000BBD\000dollar barbadien\000BDT\000taka bangladeshi\000BEC\000franc belge (convertible)\000BEF\000franc belge\000BEL\000franc belge (financier)\000BGL\000lev bulgare (1962–1999)\000BGN\000lev bulgare\000BHD\000dinar bahreïni\000BIF\000franc burundais\000BMD\000dollar bermudien\000BND\000dollar brunéien\000BOB\000boliviano bolivien\000BOP\000peso bolivien\000BOV\000mvdol bolivien\000BRB\000nouveau cruzeiro brésilien (1967–1986)\000BRC\000cruzado brésilien (1986–1989)\000BRE\000cruzeiro brésilien (1990–1993)\000BRL\000réal brésilien\000BRN\000nouveau cruzado\000BRR\000cruzeiro\000BSD\000dollar bahaméen\000BTN\000ngultrum bouthanais\000BUK\000kyat birman\000BWP\000pula botswanais\000BYB\000nouveau rouble biélorusse (1994–1999)\000BYN\000rouble biélorusse\000BYR\000rouble biélorusse (2000–2016)\000BZD\000dollar bélizéen\000CAD\000dollar canadien\000CDF\000franc congolais\000CHE\000euro WIR\000CHF\000franc suisse\000CHW\000franc WIR\000CLF\000unité d’investissement chilienne\000CLP\000peso chilien\000CNH\000yuan chinois (zone extracôtière)\000CNY\000yuan renminbi chinois\000COP\000peso colombien\000COU\000unité de valeur réelle colombienne\000CRC\000colón costaricain\000CSD\000dinar serbo-monténégrin\000CSK\000couronne forte tchécoslovaque\000CUC\000peso cubain convertible\000CUP\000peso cubain\000CVE\000escudo capverdien\000CYP\000livre chypriote\000CZK\000couronne tchèque\000DDM\000mark est-allemand\000DEM\000mark allemand\000DJF\000franc djiboutien\000DKK\000couronne danoise\000DOP\000peso dominicain\000DZD\000dinar algérien\000ECS\000sucre équatorien\000ECV\000unité de valeur constante équatoriale (UVC)\000EEK\000couronne estonienne\000EGP\000livre égyptienne\000ERN\000nafka érythréen\000ESA\000peseta espagnole (compte A)\000ESB\000peseta espagnole (compte convertible)\000ESP\000peseta espagnole\000ETB\000birr éthiopien\000EUR\000euro\000FIM\000mark finlandais\000FJD\000dollar fidjien\000FKP\000livre des îles Malouines\000FRF\000franc français\000GBP\000livre sterling\000GEK\000coupon de lari géorgien\000GEL\000lari géorgien\000GHC\000cédi\000GHS\000cédi ghanéen\000GIP\000livre de Gibraltar\000GMD\000dalasi gambien\000GNF\000franc guinéen\000GNS\000syli guinéen\000GQE\000ekwélé équatoguinéen\000GRD\000drachme grecque\000GTQ\000quetzal guatémaltèque\000GWE\000escudo de Guinée portugaise\000GWP\000peso bissau-guinéen\000GYD\000dollar du Guyana\000HKD\000dollar de Hong Kong\000HNL\000lempira hondurien\000HRD\000dinar croate\000HRK\000kuna croate\000HTG\000gourde haïtienne\000HUF\000forint hongrois\000IDR\000roupie indonésienne\000IEP\000livre irlandaise\000ILP\000livre israélienne\000ILS\000nouveau shekel israélien\000INR\000roupie indienne\000IQD\000dinar irakien\000IRR\000riyal iranien\000ISK\000couronne islandaise\000ITL\000lire italienne\000JMD\000dollar jamaïcain\000JOD\000dinar jordanien\000JPY\000yen japonais\000KES\000shilling kényan\000KGS\000som kirghize\000KHR\000riel cambodgien\000KMF\000franc comorien\000KPW\000won nord-coréen\000KRW\000won sud-coréen\000KWD\000dinar koweïtien\000KYD\000dollar des îles Caïmans\000KZT\000tenge kazakh\000LAK\000kip laotien\000LBP\000livre libanaise\000LKR\000roupie srilankaise\000LRD\000dollar libérien\000LSL\000loti lesothan\000LTL\000litas lituanien\000LTT\000talonas lituanien\000LUC\000franc convertible luxembourgeois\000LUF\000franc luxembourgeois\000LUL\000franc financier luxembourgeois\000LVL\000lats letton\000LVR\000rouble letton\000LYD\000dinar libyen\000MAD\000dirham marocain\000MAF\000franc marocain\000MDL\000leu moldave\000MGA\000ariary malgache\000MGF\000franc malgache\000MKD\000denar macédonien\000MLF\000franc malien\000MMK\000kyat myanmarais\000MNT\000tugrik mongol\000MOP\000pataca macanaise\000MRO\000ouguiya mauritanien (1973–2017)\000MRU\000ouguiya mauritanien\000MTL\000lire maltaise\000MTP\000livre maltaise\000MUR\000roupie mauricienne\000MVR\000rufiyaa maldivienne\000MWK\000kwacha malawite\000MXN\000peso mexicain\000MXP\000peso d’argent mexicain (1861–1992)\000MXV\000unité de conversion mexicaine (UDI)\000MYR\000ringgit malais\000MZE\000escudo mozambicain\000MZM\000métical\000MZN\000metical mozambicain\000NAD\000dollar namibien\000NGN\000naira nigérian\000NIC\000cordoba\000NIO\000córdoba oro nicaraguayen\000NLG\000florin néerlandais\000NOK\000couronne norvégienne\000NPR\000roupie népalaise\000NZD\000dollar néo-zélandais\000OMR\000riyal omanais\000PAB\000balboa panaméen\000PEI\000inti péruvien\000PEN\000sol péruvien\000PES\000sol péruvien (1863–1985)\000PGK\000kina papouan-néo-guinéen\000PHP\000peso philippin\000PKR\000roupie pakistanaise\000PLN\000zloty polonais\000PLZ\000zloty (1950–1995)\000PTE\000escudo portugais\000PYG\000guaraní paraguayen\000QAR\000riyal qatari\000RHD\000dollar rhodésien\000ROL\000ancien leu roumain\000RON\000leu roumain\000RSD\000dinar serbe\000RUB\000rouble russe\000RUR\000rouble russe (1991–1998)\000RWF\000franc rwandais\000SAR\000riyal saoudien\000SBD\000dollar des îles Salomon\000SCR\000roupie des Seychelles\000SDD\000dinar soudanais\000SDG\000livre soudanaise\000SDP\000livre soudanaise (1956–2007)\000SEK\000couronne suédoise\000SGD\000dollar de Singapour\000SHP\000livre de Sainte-Hélène\000SIT\000tolar slovène\000SKK\000couronne slovaque\000SLE\000leone sierra-léonais\000SLL\000leone sierra-léonais (1964—2022)\000SOS\000shilling somalien\000SRD\000dollar surinamais\000SRG\000florin surinamais\000SSP\000livre sud-soudanaise\000STD\000dobra santoméen (1977–2017)\000STN\000dobra santoméen\000SUR\000rouble soviétique\000SVC\000colón salvadorien\000SYP\000livre syrienne\000SZL\000lilangeni swazi\000THB\000baht thaïlandais\000TJR\000rouble tadjik\000TJS\000somoni tadjik\000TMM\000manat turkmène\000TMT\000nouveau manat turkmène\000TND\000dinar tunisien\000TOP\000pa’anga tongan\000TPE\000escudo timorais\000TRL\000livre turque (1844–2005)\000TRY\000livre turque\000TTD\000dollar de Trinité-et-Tobago\000TWD\000nouveau dollar taïwanais\000TZS\000shilling tanzanien\000UAH\000hryvnia ukrainienne\000UAK\000karbovanetz\000UGS\000shilling ougandais (1966–1987)\000UGX\000shilling ougandais\000USD\000dollar des États-Unis\000USN\000dollar des Etats-Unis (jour suivant)\000USS\000dollar des Etats-Unis (jour même)\000UYI\000peso uruguayen (unités indexées)\000UYP\000peso uruguayen (1975–1993)\000UYU\000peso uruguayen\000UZS\000sum ouzbek\000VEB\000bolivar vénézuélien (1871–2008)\000VEF\000bolivar vénézuélien (2008–2018)\000VES\000bolivar vénézuélien\000VND\000dông vietnamien\000VUV\000vatu vanuatuan\000WST\000tala samoan\000XAF\000franc CFA (BEAC)\000XAG\000argent\000XAU\000or\000XBA\000unité européenne composée\000XBB\000unité monétaire européenne\000XBC\000unité de compte européenne (XBC)\000XBD\000unité de compte européenne (XBD)\000XCD\000dollar des Caraïbes orientales\000XCG\000florin caribéen\000XDR\000droit de tirage spécial\000XEU\000unité de compte européenne (ECU)\000XFO\000franc or\000XFU\000franc UIC\000XOF\000franc CFA (BCEAO)\000XPD\000palladium\000XPF\000franc CFP\000XPT\000platine\000XRE\000type de fonds RINET\000XTS\000(devise de test)\000XXX\000devise inconnue ou non valide\000YDD\000dinar du Yémen\000YER\000riyal yéménite\000YUD\000nouveau dinar yougoslave\000YUM\000dinar yougoslave Noviy\000YUN\000dinar yougoslave convertible\000ZAL\000rand sud-africain (financier)\000ZAR\000rand sud-africain\000ZMK\000kwacha zambien (1968–2012)\000ZMW\000kwacha zambien\000ZRN\000nouveau zaïre zaïrien\000ZRZ\000zaïre zaïrois\000ZWD\000dollar zimbabwéen\000ZWG\000or du Zimbabwe\000ZWL\000dollar zimbabwéen (2009)\000ZWR\000dollar zimbabwéen (2008)\000";
+
+const DisplayNamesData display_names_data[] = {
+ { "en", dn_en_languages, dn_en_regions, dn_en_regions_short, dn_en_scripts, dn_en_calendars, dn_en_dateTimeFields, dn_en_currencies },
+ { "fr", dn_fr_languages, dn_fr_regions, dn_fr_regions_short, dn_fr_scripts, dn_fr_calendars, dn_fr_dateTimeFields, dn_fr_currencies },
+};
+const int display_names_count = sizeof(display_names_data) / sizeof(display_names_data[0]);
+
+const char *intl_supported_currencies[] = {
+ "ADP",
+ "AED",
+ "AFA",
+ "AFN",
+ "ALK",
+ "ALL",
+ "AMD",
+ "ANG",
+ "AOA",
+ "AOK",
+ "AON",
+ "AOR",
+ "ARA",
+ "ARL",
+ "ARM",
+ "ARP",
+ "ARS",
+ "ATS",
+ "AUD",
+ "AWG",
+ "AZM",
+ "AZN",
+ "BAD",
+ "BAM",
+ "BAN",
+ "BBD",
+ "BDT",
+ "BEC",
+ "BEF",
+ "BEL",
+ "BGL",
+ "BGM",
+ "BGN",
+ "BGO",
+ "BHD",
+ "BIF",
+ "BMD",
+ "BND",
+ "BOB",
+ "BOL",
+ "BOP",
+ "BOV",
+ "BRB",
+ "BRC",
+ "BRE",
+ "BRL",
+ "BRN",
+ "BRR",
+ "BRZ",
+ "BSD",
+ "BTN",
+ "BUK",
+ "BWP",
+ "BYB",
+ "BYN",
+ "BYR",
+ "BZD",
+ "CAD",
+ "CDF",
+ "CHE",
+ "CHF",
+ "CHW",
+ "CLE",
+ "CLF",
+ "CLP",
+ "CNH",
+ "CNX",
+ "CNY",
+ "COP",
+ "COU",
+ "CRC",
+ "CSD",
+ "CSK",
+ "CUC",
+ "CUP",
+ "CVE",
+ "CYP",
+ "CZK",
+ "DDM",
+ "DEM",
+ "DJF",
+ "DKK",
+ "DOP",
+ "DZD",
+ "ECS",
+ "ECV",
+ "EEK",
+ "EGP",
+ "ERN",
+ "ESA",
+ "ESB",
+ "ESP",
+ "ETB",
+ "EUR",
+ "FIM",
+ "FJD",
+ "FKP",
+ "FRF",
+ "GBP",
+ "GEK",
+ "GEL",
+ "GHC",
+ "GHS",
+ "GIP",
+ "GMD",
+ "GNF",
+ "GNS",
+ "GQE",
+ "GRD",
+ "GTQ",
+ "GWE",
+ "GWP",
+ "GYD",
+ "HKD",
+ "HNL",
+ "HRD",
+ "HRK",
+ "HTG",
+ "HUF",
+ "IDR",
+ "IEP",
+ "ILP",
+ "ILR",
+ "ILS",
+ "INR",
+ "IQD",
+ "IRR",
+ "ISJ",
+ "ISK",
+ "ITL",
+ "JMD",
+ "JOD",
+ "JPY",
+ "KES",
+ "KGS",
+ "KHR",
+ "KMF",
+ "KPW",
+ "KRH",
+ "KRO",
+ "KRW",
+ "KWD",
+ "KYD",
+ "KZT",
+ "LAK",
+ "LBP",
+ "LKR",
+ "LRD",
+ "LSL",
+ "LTL",
+ "LTT",
+ "LUC",
+ "LUF",
+ "LUL",
+ "LVL",
+ "LVR",
+ "LYD",
+ "MAD",
+ "MAF",
+ "MCF",
+ "MDC",
+ "MDL",
+ "MGA",
+ "MGF",
+ "MKD",
+ "MKN",
+ "MLF",
+ "MMK",
+ "MNT",
+ "MOP",
+ "MRO",
+ "MRU",
+ "MTL",
+ "MTP",
+ "MUR",
+ "MVP",
+ "MVR",
+ "MWK",
+ "MXN",
+ "MXP",
+ "MXV",
+ "MYR",
+ "MZE",
+ "MZM",
+ "MZN",
+ "NAD",
+ "NGN",
+ "NIC",
+ "NIO",
+ "NLG",
+ "NOK",
+ "NPR",
+ "NZD",
+ "OMR",
+ "PAB",
+ "PEI",
+ "PEN",
+ "PES",
+ "PGK",
+ "PHP",
+ "PKR",
+ "PLN",
+ "PLZ",
+ "PTE",
+ "PYG",
+ "QAR",
+ "RHD",
+ "ROL",
+ "RON",
+ "RSD",
+ "RUB",
+ "RUR",
+ "RWF",
+ "SAR",
+ "SBD",
+ "SCR",
+ "SDD",
+ "SDG",
+ "SDP",
+ "SEK",
+ "SGD",
+ "SHP",
+ "SIT",
+ "SKK",
+ "SLE",
+ "SLL",
+ "SOS",
+ "SRD",
+ "SRG",
+ "SSP",
+ "STD",
+ "STN",
+ "SUR",
+ "SVC",
+ "SYP",
+ "SZL",
+ "THB",
+ "TJR",
+ "TJS",
+ "TMM",
+ "TMT",
+ "TND",
+ "TOP",
+ "TPE",
+ "TRL",
+ "TRY",
+ "TTD",
+ "TWD",
+ "TZS",
+ "UAH",
+ "UAK",
+ "UGS",
+ "UGX",
+ "USD",
+ "USN",
+ "USS",
+ "UYI",
+ "UYP",
+ "UYU",
+ "UYW",
+ "UZS",
+ "VEB",
+ "VED",
+ "VEF",
+ "VES",
+ "VND",
+ "VNN",
+ "VUV",
+ "WST",
+ "XAF",
+ "XAG",
+ "XAU",
+ "XBA",
+ "XBB",
+ "XBC",
+ "XBD",
+ "XCD",
+ "XCG",
+ "XDR",
+ "XEU",
+ "XFO",
+ "XFU",
+ "XOF",
+ "XPD",
+ "XPF",
+ "XPT",
+ "XRE",
+ "XSU",
+ "XTS",
+ "XUA",
+ "XXX",
+ "YDD",
+ "YER",
+ "YUD",
+ "YUM",
+ "YUN",
+ "YUR",
+ "ZAL",
+ "ZAR",
+ "ZMK",
+ "ZMW",
+ "ZRN",
+ "ZRZ",
+ "ZWD",
+ "ZWG",
+ "ZWL",
+ "ZWR",
+};
+const int intl_supported_currencies_count = sizeof(intl_supported_currencies) / sizeof(intl_supported_currencies[0]);
--- /dev/null
+/*
+ * QuickJS Intl.Locale implementation (ECMA-402)
+ */
+
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+
+#include "../quickjs.h"
+#include "../cutils.h"
+#include "intl_private.h"
+
+static JSClassID js_locale_class_id;
+
+typedef struct {
+ char *locale;
+ char *baseName;
+ char *language;
+ char *script;
+ char *region;
+ char *variants;
+ char *calendar;
+ char *collation;
+ char *hourCycle;
+ char *numberingSystem;
+ char *caseFirst;
+ char *firstDayOfWeek;
+ int numeric; /* -1 = undefined, 0 = false, 1 = true */
+} JSLocaleData;
+
+static void js_locale_finalizer(JSRuntime *rt, JSValue val)
+{
+ JSLocaleData *s = JS_GetOpaque(val, js_locale_class_id);
+ if (s) {
+# define FREE_FIELD(f) if (s->f) js_free_rt(rt, s->f)
+ FREE_FIELD(locale);
+ FREE_FIELD(baseName);
+ FREE_FIELD(language);
+ FREE_FIELD(script);
+ FREE_FIELD(region);
+ FREE_FIELD(variants);
+ FREE_FIELD(calendar);
+ FREE_FIELD(collation);
+ FREE_FIELD(hourCycle);
+ FREE_FIELD(numberingSystem);
+ FREE_FIELD(caseFirst);
+ FREE_FIELD(firstDayOfWeek);
+#undef FREE_FIELD
+ js_free_rt(rt, s);
+ }
+}
+
+static JSClassDef js_locale_class = {
+ "Locale",
+ .finalizer = js_locale_finalizer,
+};
+
+/* --------------------------------------------------------------------- */
+/* Locale subtag validation helpers */
+/* --------------------------------------------------------------------- */
+
+static int is_valid_language_subtag(const char *s)
+{
+ int len = (int)strlen(s);
+ int i;
+ if (len < 2 || len > 8) return 0;
+ if (len == 4) return 0; /* 4-letter is script, not language */
+ for (i = 0; i < len; i++)
+ if (!isalpha((unsigned char)s[i])) return 0;
+ return 1;
+}
+
+static int is_valid_script_subtag(const char *s)
+{
+ int len = (int)strlen(s);
+ int i;
+ if (len != 4) return 0;
+ for (i = 0; i < len; i++)
+ if (!isalpha((unsigned char)s[i])) return 0;
+ return 1;
+}
+
+static int is_valid_region_subtag(const char *s)
+{
+ int len = (int)strlen(s);
+ int i;
+ if (len == 2) {
+ for (i = 0; i < len; i++)
+ if (!isalpha((unsigned char)s[i])) return 0;
+ return 1;
+ }
+ if (len == 3) {
+ for (i = 0; i < len; i++)
+ if (!isdigit((unsigned char)s[i])) return 0;
+ return 1;
+ }
+ return 0;
+}
+
+static int is_valid_variant_subtag(const char *s)
+{
+ int len = (int)strlen(s);
+ int i;
+ if (len >= 5 && len <= 8) {
+ for (i = 0; i < len; i++)
+ if (!isalnum((unsigned char)s[i])) return 0;
+ return 1;
+ }
+ if (len == 4) {
+ if (!isdigit((unsigned char)s[0])) return 0;
+ for (i = 1; i < 4; i++)
+ if (!isalnum((unsigned char)s[i])) return 0;
+ return 1;
+ }
+ return 0;
+}
+
+static void to_title_case(char *s)
+{
+ if (s && s[0])
+ s[0] = (char)toupper((unsigned char)s[0]);
+ if (s) {
+ int i;
+ for (i = 1; s[i]; i++)
+ s[i] = (char)tolower((unsigned char)s[i]);
+ }
+}
+
+static void to_upper_case(char *s)
+{
+ int i;
+ if (s) {
+ for (i = 0; s[i]; i++)
+ s[i] = (char)toupper((unsigned char)s[i]);
+ }
+}
+
+static void to_lower_case(char *s)
+{
+ int i;
+ if (s) {
+ for (i = 0; s[i]; i++)
+ s[i] = (char)tolower((unsigned char)s[i]);
+ }
+}
+
+static int cmp_str(const void *a, const void *b)
+{
+ return strcmp(*(const char **)a, *(const char **)b);
+}
+
+/* Validate a Unicode locale "type" nonterminal: one or more 3-8 alphanum segments */
+static int is_valid_type(const char *s)
+{
+ int len = (int)strlen(s);
+ int i = 0;
+ if (len == 0) return 0;
+ while (i < len) {
+ int seg_len = 0;
+ while (i < len && s[i] != '-') {
+ if (!isalnum((unsigned char)s[i])) return 0;
+ seg_len++;
+ i++;
+ }
+ if (seg_len < 3 || seg_len > 8) return 0;
+ if (s[i] == '-') {
+ i++;
+ if (i >= len) return 0;
+ }
+ }
+ return 1;
+}
+
+static int is_valid_hour_cycle(const char *s)
+{
+ return !strcmp(s, "h11") || !strcmp(s, "h12") ||
+ !strcmp(s, "h23") || !strcmp(s, "h24");
+}
+
+static int is_valid_case_first(const char *s)
+{
+ return !strcmp(s, "upper") || !strcmp(s, "lower") || !strcmp(s, "false");
+}
+
+static const char *weekday_to_u_value(const char *s)
+{
+ if (!strcasecmp(s, "0") || !strcasecmp(s, "7")) return "sun";
+ if (!strcasecmp(s, "1")) return "mon";
+ if (!strcasecmp(s, "2")) return "tue";
+ if (!strcasecmp(s, "3")) return "wed";
+ if (!strcasecmp(s, "4")) return "thu";
+ if (!strcasecmp(s, "5")) return "fri";
+ if (!strcasecmp(s, "6")) return "sat";
+ return NULL;
+}
+
+/* --------------------------------------------------------------------- */
+/* Locale option application */
+/* --------------------------------------------------------------------- */
+
+typedef struct {
+ char *key;
+ char *value;
+} UKeyword;
+
+static int cmp_ukeyword(const void *a, const void *b)
+{
+ const UKeyword *ka = a;
+ const UKeyword *kb = b;
+ return strcmp(ka->key, kb->key);
+}
+
+static int locale_find_u_extension(const char *tag, int *u_start, int *u_end)
+{
+ int i = 0, len = (int)strlen(tag);
+ int in_ext = 0;
+ char ext_char = 0;
+ int saw_other_ext = 0;
+ *u_start = -1;
+ *u_end = -1;
+ while (i < len) {
+ int j = i;
+ while (j < len && tag[j] != '-') j++;
+ int slen = j - i;
+ if (slen == 1 && isalpha((unsigned char)tag[i])) {
+ if (in_ext && ext_char == 'u' && *u_start >= 0) {
+ *u_end = i - 1;
+ return 1;
+ }
+ ext_char = tag[i];
+ in_ext = 1;
+ if (ext_char == 'u' && !saw_other_ext)
+ *u_start = i;
+ else
+ saw_other_ext = 1;
+ }
+ i = j + 1;
+ }
+ if (in_ext && ext_char == 'u' && *u_start >= 0) {
+ *u_end = len;
+ return 1;
+ }
+ return 0;
+}
+
+static const char *canonicalize_keyword_value(const char *key, const char *value)
+{
+ if (!strcasecmp(key, "ca")) {
+ if (!strcasecmp(value, "islamicc")) return "islamic-civil";
+ if (!strcasecmp(value, "ethiopic-amete-alem")) return "ethioaa";
+ }
+ return value;
+}
+
+static int locale_parse_u_keywords(JSContext *ctx, const char *u_ext, int u_len,
+ UKeyword *keywords, int max_kw,
+ char **attributes)
+{
+ int i = 2; /* skip "u-" */
+ int num_kw = 0;
+ *attributes = NULL;
+ while (i < u_len) {
+ int j = i;
+ while (j < u_len && u_ext[j] != '-') j++;
+ int slen = j - i;
+ if (slen == 2 && isalpha((unsigned char)u_ext[i]) &&
+ (isalpha((unsigned char)u_ext[i+1]) || isdigit((unsigned char)u_ext[i+1]))) {
+ /* keyword key */
+ char key[3] = {u_ext[i], u_ext[i+1], '\0'};
+ i = j + 1;
+ /* read value(s) */
+ int vstart = i;
+ while (i < u_len) {
+ int k = i;
+ while (k < u_len && u_ext[k] != '-') k++;
+ int vlen = k - i;
+ if (vlen == 2 && isalpha((unsigned char)u_ext[i]) &&
+ (isalpha((unsigned char)u_ext[i+1]) || isdigit((unsigned char)u_ext[i+1])))
+ break; /* next keyword key */
+ i = k + 1;
+ }
+ {
+ int k;
+ int already_seen = 0;
+ for (k = 0; k < num_kw; k++) {
+ if (!strcmp(keywords[k].key, key)) {
+ already_seen = 1;
+ break;
+ }
+ }
+ if (!already_seen && num_kw < max_kw) {
+ keywords[num_kw].key = js_strdup(ctx, key);
+ {
+ int vlen = i - vstart - (i < u_len ? 1 : 0);
+ if (vlen < 0) vlen = 0;
+ if (vlen > 0 && u_ext[vstart + vlen - 1] == '-') vlen--;
+ keywords[num_kw].value = js_malloc(ctx, (size_t)vlen + 1);
+ if (keywords[num_kw].value) {
+ const char *cval;
+ memcpy(keywords[num_kw].value, u_ext + vstart, (size_t)vlen);
+ keywords[num_kw].value[vlen] = '\0';
+ cval = canonicalize_keyword_value(key, keywords[num_kw].value);
+ if (cval != keywords[num_kw].value) {
+ js_free(ctx, keywords[num_kw].value);
+ keywords[num_kw].value = js_strdup(ctx, cval);
+ }
+ }
+ }
+ num_kw++;
+ }
+ }
+ } else if (slen >= 3 && slen <= 8) {
+ /* attribute */
+ int alen = j - i;
+ if (!*attributes) {
+ *attributes = js_malloc(ctx, (size_t)alen + 1);
+ if (*attributes) {
+ memcpy(*attributes, u_ext + i, (size_t)alen);
+ (*attributes)[alen] = '\0';
+ }
+ } else {
+ int old_len = (int)strlen(*attributes);
+ char *new_attr = js_malloc(ctx, (size_t)old_len + 1 + (size_t)alen + 1);
+ if (new_attr) {
+ memcpy(new_attr, *attributes, (size_t)old_len);
+ new_attr[old_len] = '-';
+ memcpy(new_attr + old_len + 1, u_ext + i, (size_t)alen);
+ new_attr[old_len + 1 + alen] = '\0';
+ js_free(ctx, *attributes);
+ *attributes = new_attr;
+ }
+ }
+ i = j + 1;
+ } else {
+ i = j + 1;
+ }
+ }
+ return num_kw;
+}
+
+/* Manual split of base name by '-' without strtok */
+static int locale_split_subtags(char *buf, char **subtags, int max_subtags)
+{
+ int n = 0;
+ char *p = buf;
+ while (*p && n < max_subtags) {
+ char *start = p;
+ while (*p && *p != '-') p++;
+ subtags[n] = start;
+ n++;
+ if (*p == '-') {
+ *p = '\0';
+ p++;
+ }
+ }
+ return n;
+}
+
+static char *locale_build_locale_from_options(JSContext *ctx, const char *canonical,
+ JSValueConst options, JSLocaleData *out)
+{
+ DynBuf db;
+ char *baseName = NULL;
+ char *result = NULL;
+ char *language = NULL, *script = NULL, *region = NULL, *variants = NULL;
+ char *u_ext_str = NULL;
+ char *u_attributes = NULL;
+ char *ext_suffix = NULL;
+ char *subtags[16];
+ int n_subtags = 0;
+ UKeyword u_keywords[16];
+ int num_u_keywords = 0;
+ int u_start = -1, u_end = -1;
+ int i, has_u = 0;
+ JSValue val;
+ const char *str;
+
+ js_intl_dbuf_init(ctx, &db);
+
+ memset(out, 0, sizeof(*out));
+ out->numeric = -1;
+ memset(u_keywords, 0, sizeof(u_keywords));
+
+ /* 1. Extract base name and existing u-extension */
+ has_u = locale_find_u_extension(canonical, &u_start, &u_end);
+ if (has_u) {
+ baseName = js_malloc(ctx, (size_t)u_start);
+ if (baseName) {
+ memcpy(baseName, canonical, (size_t)u_start - 1);
+ baseName[u_start - 1] = '\0';
+ }
+ u_ext_str = js_malloc(ctx, (size_t)(u_end - u_start) + 1);
+ if (u_ext_str) {
+ memcpy(u_ext_str, canonical + u_start, (size_t)(u_end - u_start));
+ u_ext_str[u_end - u_start] = '\0';
+ }
+ if (u_ext_str)
+ num_u_keywords = locale_parse_u_keywords(ctx, u_ext_str, (int)strlen(u_ext_str),
+ u_keywords, 16, &u_attributes);
+ } else {
+ baseName = js_strdup(ctx, canonical);
+ }
+
+ if (!baseName)
+ goto fail;
+
+ /* 2. Parse baseName into components and set defaults */
+ {
+ char buf[256];
+ int idx;
+ int ext_start = -1;
+ pstrcpy(buf, sizeof(buf), baseName);
+ n_subtags = locale_split_subtags(buf, subtags, 16);
+ for (i = 0; i < n_subtags; i++)
+ subtags[i] = js_strdup(ctx, subtags[i]);
+ /* find first extension singleton (length 1 alpha) */
+ for (i = 1; i < n_subtags; i++) {
+ if (strlen(subtags[i]) == 1 && isalpha((unsigned char)subtags[i][0])) {
+ ext_start = i;
+ break;
+ }
+ }
+ /* Save extension suffix from canonical */
+ if (ext_start >= 0 && !has_u) {
+ /* find position of first extension in canonical */
+ int canon_len = (int)strlen(canonical);
+ int pos = 0, subtag_idx = 0;
+ while (pos < canon_len && subtag_idx < ext_start) {
+ int dash = pos;
+ while (dash < canon_len && canonical[dash] != '-') dash++;
+ subtag_idx++;
+ pos = dash + 1;
+ }
+ if (pos <= canon_len) {
+ ext_suffix = js_strdup(ctx, canonical + pos - 1); /* include leading dash */
+ }
+ }
+ if (n_subtags > 0) language = js_strdup(ctx, subtags[0]);
+ idx = 1;
+ if (idx < n_subtags && (ext_start < 0 || idx < ext_start) && strlen(subtags[idx]) == 4 &&
+ isalpha((unsigned char)subtags[idx][0]) &&
+ isalpha((unsigned char)subtags[idx][1]) &&
+ isalpha((unsigned char)subtags[idx][2]) &&
+ isalpha((unsigned char)subtags[idx][3])) {
+ script = js_strdup(ctx, subtags[idx]);
+ to_title_case(script);
+ idx++;
+ }
+ if (idx < n_subtags && (ext_start < 0 || idx < ext_start) && (strlen(subtags[idx]) == 2 || strlen(subtags[idx]) == 3)) {
+ int is_region = 1;
+ int j;
+ for (j = 0; j < (int)strlen(subtags[idx]); j++) {
+ if (strlen(subtags[idx]) == 2 && !isalpha((unsigned char)subtags[idx][j])) is_region = 0;
+ if (strlen(subtags[idx]) == 3 && !isdigit((unsigned char)subtags[idx][j])) is_region = 0;
+ }
+ if (is_region) {
+ region = js_strdup(ctx, subtags[idx]);
+ to_upper_case(region);
+ idx++;
+ }
+ }
+ if (idx < n_subtags && (ext_start < 0 || idx < ext_start)) {
+ int vlen = 0;
+ int j;
+ int num_variants = ext_start < 0 ? n_subtags - idx : ext_start - idx;
+ /* sort variants lexicographically */
+ if (num_variants > 1)
+ qsort(&subtags[idx], (size_t)num_variants, sizeof(char *), cmp_str);
+ for (j = idx; j < idx + num_variants; j++) vlen += (int)strlen(subtags[j]) + 1;
+ variants = js_malloc(ctx, (size_t)vlen);
+ if (variants) {
+ variants[0] = '\0';
+ for (j = idx; j < idx + num_variants; j++) {
+ if (j > idx) pstrcat(variants, vlen, "-");
+ pstrcat(variants, vlen, subtags[j]);
+ }
+ to_lower_case(variants);
+ }
+ }
+ for (i = 0; i < n_subtags; i++)
+ js_free(ctx, subtags[i]);
+ n_subtags = 0;
+ }
+
+ /* 3. Read language option */
+ val = JS_GetPropertyStr(ctx, options, "language");
+ if (JS_IsException(val)) goto fail;
+ if (!JS_IsUndefined(val)) {
+ str = JS_ToCStringNZ(ctx, val);
+ JS_FreeValue(ctx, val);
+ if (!str) goto fail;
+ if (!is_valid_language_subtag(str)) {
+ JS_FreeCString(ctx, str);
+ JS_ThrowRangeError(ctx, "invalid language subtag");
+ goto fail;
+ }
+ js_free(ctx, language);
+ language = js_strdup(ctx, str);
+ JS_FreeCString(ctx, str);
+ }
+
+ /* 4. Read script option */
+ val = JS_GetPropertyStr(ctx, options, "script");
+ if (JS_IsException(val)) goto fail;
+ if (!JS_IsUndefined(val)) {
+ str = JS_ToCStringNZ(ctx, val);
+ JS_FreeValue(ctx, val);
+ if (!str) goto fail;
+ if (!is_valid_script_subtag(str)) {
+ JS_FreeCString(ctx, str);
+ JS_ThrowRangeError(ctx, "invalid script subtag");
+ goto fail;
+ }
+ js_free(ctx, script);
+ script = js_strdup(ctx, str);
+ to_title_case(script);
+ JS_FreeCString(ctx, str);
+ }
+
+ /* 5. Read region option */
+ val = JS_GetPropertyStr(ctx, options, "region");
+ if (JS_IsException(val)) goto fail;
+ if (!JS_IsUndefined(val)) {
+ str = JS_ToCStringNZ(ctx, val);
+ JS_FreeValue(ctx, val);
+ if (!str) goto fail;
+ if (!is_valid_region_subtag(str)) {
+ JS_FreeCString(ctx, str);
+ JS_ThrowRangeError(ctx, "invalid region subtag");
+ goto fail;
+ }
+ js_free(ctx, region);
+ region = js_strdup(ctx, str);
+ to_upper_case(region);
+ JS_FreeCString(ctx, str);
+ }
+
+ /* 6. Read variants option */
+ val = JS_GetPropertyStr(ctx, options, "variants");
+ if (JS_IsException(val)) goto fail;
+ if (!JS_IsUndefined(val)) {
+ str = JS_ToCStringNZ(ctx, val);
+ JS_FreeValue(ctx, val);
+ if (!str) goto fail;
+ if (strlen(str) == 0) {
+ JS_FreeCString(ctx, str);
+ JS_ThrowRangeError(ctx, "invalid variants");
+ goto fail;
+ }
+ {
+ char vbuf[256];
+ char *vsubtags[16];
+ int vn;
+ pstrcpy(vbuf, sizeof(vbuf), str);
+ vn = locale_split_subtags(vbuf, vsubtags, 16);
+ {
+ int dash_count = 0;
+ for (i = 0; str[i]; i++) if (str[i] == '-') dash_count++;
+ if ((vn == 0 && dash_count > 0) || (vn > 0 && dash_count != vn - 1)) {
+ JS_FreeCString(ctx, str);
+ JS_ThrowRangeError(ctx, "invalid variant subtag");
+ goto fail;
+ }
+ }
+ for (i = 0; i < vn; i++) {
+ if (!is_valid_variant_subtag(vsubtags[i])) {
+ JS_FreeCString(ctx, str);
+ JS_ThrowRangeError(ctx, "invalid variant subtag");
+ goto fail;
+ }
+ }
+ /* check duplicates (case-insensitive) */
+ for (i = 0; i < vn; i++) {
+ int j;
+ for (j = i + 1; j < vn; j++) {
+ if (!strcasecmp(vsubtags[i], vsubtags[j])) {
+ JS_FreeCString(ctx, str);
+ JS_ThrowRangeError(ctx, "duplicate variant subtag");
+ goto fail;
+ }
+ }
+ }
+ /* sort variants lexicographically */
+ qsort(vsubtags, (size_t)vn, sizeof(char *), cmp_str);
+ {
+ int j, vlen = 0;
+ for (j = 0; j < vn; j++) vlen += (int)strlen(vsubtags[j]) + 1;
+ js_free(ctx, variants);
+ variants = js_malloc(ctx, (size_t)vlen);
+ if (variants) {
+ variants[0] = '\0';
+ for (j = 0; j < vn; j++) {
+ if (j > 0) pstrcat(variants, vlen, "-");
+ pstrcat(variants, vlen, vsubtags[j]);
+ }
+ to_lower_case(variants);
+ }
+ }
+ }
+ JS_FreeCString(ctx, str);
+ }
+
+ /* 7. Rebuild baseName */
+ if (language) dbuf_putstr(&db, language);
+ if (script) {
+ dbuf_putc(&db, (uint8_t)'-');
+ dbuf_putstr(&db, script);
+ }
+ if (region) {
+ dbuf_putc(&db, (uint8_t)'-');
+ dbuf_putstr(&db, region);
+ }
+ if (variants) {
+ dbuf_putc(&db, (uint8_t)'-');
+ dbuf_putstr(&db, variants);
+ }
+ dbuf_putc(&db, '\0');
+ {
+ char *new_base = js_strdup(ctx, (const char *)db.buf);
+ js_free(ctx, baseName);
+ baseName = new_base;
+ }
+ db.size = 0;
+
+ /* 8. Read and validate unicode extension options */
+ {
+ /* calendar */
+ val = JS_GetPropertyStr(ctx, options, "calendar");
+ if (JS_IsException(val)) goto fail;
+ if (!JS_IsUndefined(val)) {
+ str = JS_ToCStringNZ(ctx, val);
+JS_FreeValue(ctx, val);
+if (!str) goto fail;
+ if (!is_valid_type(str)) {
+ JS_FreeCString(ctx, str);
+ JS_ThrowRangeError(ctx, "invalid calendar");
+ goto fail;
+ }
+ {
+ const char *cal_val = canonicalize_keyword_value("ca", str);
+ /* replace or add keyword */
+ for (i = 0; i < num_u_keywords; i++) {
+ if (!strcmp(u_keywords[i].key, "ca")) {
+ js_free(ctx, u_keywords[i].value);
+ u_keywords[i].value = js_strdup(ctx, cal_val);
+ break;
+ }
+ }
+ if (i == num_u_keywords && num_u_keywords < 16) {
+ u_keywords[num_u_keywords].key = js_strdup(ctx, "ca");
+ u_keywords[num_u_keywords].value = js_strdup(ctx, cal_val);
+ num_u_keywords++;
+ }
+ out->calendar = js_strdup(ctx, cal_val);
+ JS_FreeCString(ctx, str);
+ }
+ }
+
+ /* collation */
+ val = JS_GetPropertyStr(ctx, options, "collation");
+ if (JS_IsException(val)) goto fail;
+ if (!JS_IsUndefined(val)) {
+ str = JS_ToCStringNZ(ctx, val);
+JS_FreeValue(ctx, val);
+if (!str) goto fail;
+ if (!is_valid_type(str)) {
+ JS_FreeCString(ctx, str);
+ JS_ThrowRangeError(ctx, "invalid collation");
+ goto fail;
+ }
+ for (i = 0; i < num_u_keywords; i++) {
+ if (!strcmp(u_keywords[i].key, "co")) {
+ js_free(ctx, u_keywords[i].value);
+ u_keywords[i].value = js_strdup(ctx, str);
+ break;
+ }
+ }
+ if (i == num_u_keywords && num_u_keywords < 16) {
+ u_keywords[num_u_keywords].key = js_strdup(ctx, "co");
+ u_keywords[num_u_keywords].value = js_strdup(ctx, str);
+ num_u_keywords++;
+ }
+ out->collation = js_strdup(ctx, str);
+ JS_FreeCString(ctx, str);
+ }
+
+ /* firstDayOfWeek */
+ val = JS_GetPropertyStr(ctx, options, "firstDayOfWeek");
+ if (JS_IsException(val)) goto fail;
+ if (!JS_IsUndefined(val)) {
+ str = JS_ToCStringNZ(ctx, val);
+JS_FreeValue(ctx, val);
+if (!str) goto fail;
+ {
+ const char *fw_val = weekday_to_u_value(str);
+ if (!fw_val) {
+ /* not a weekday name, validate as type */
+ if (!is_valid_type(str)) {
+ JS_FreeCString(ctx, str);
+ JS_ThrowRangeError(ctx, "invalid firstDayOfWeek");
+ goto fail;
+ }
+ fw_val = str;
+ }
+ for (i = 0; i < num_u_keywords; i++) {
+ if (!strcmp(u_keywords[i].key, "fw")) {
+ js_free(ctx, u_keywords[i].value);
+ u_keywords[i].value = js_strdup(ctx, fw_val);
+ break;
+ }
+ }
+ if (i == num_u_keywords && num_u_keywords < 16) {
+ u_keywords[num_u_keywords].key = js_strdup(ctx, "fw");
+ u_keywords[num_u_keywords].value = js_strdup(ctx, fw_val);
+ num_u_keywords++;
+ }
+ out->firstDayOfWeek = js_strdup(ctx, fw_val);
+ }
+ JS_FreeCString(ctx, str);
+ }
+
+ /* hourCycle */
+ val = JS_GetPropertyStr(ctx, options, "hourCycle");
+ if (JS_IsException(val)) goto fail;
+ if (!JS_IsUndefined(val)) {
+ str = JS_ToCStringNZ(ctx, val);
+JS_FreeValue(ctx, val);
+if (!str) goto fail;
+ if (!is_valid_hour_cycle(str)) {
+ JS_FreeCString(ctx, str);
+ JS_ThrowRangeError(ctx, "invalid hourCycle");
+ goto fail;
+ }
+ for (i = 0; i < num_u_keywords; i++) {
+ if (!strcmp(u_keywords[i].key, "hc")) {
+ js_free(ctx, u_keywords[i].value);
+ u_keywords[i].value = js_strdup(ctx, str);
+ break;
+ }
+ }
+ if (i == num_u_keywords && num_u_keywords < 16) {
+ u_keywords[num_u_keywords].key = js_strdup(ctx, "hc");
+ u_keywords[num_u_keywords].value = js_strdup(ctx, str);
+ num_u_keywords++;
+ }
+ out->hourCycle = js_strdup(ctx, str);
+ JS_FreeCString(ctx, str);
+ }
+
+ /* caseFirst */
+ val = JS_GetPropertyStr(ctx, options, "caseFirst");
+ if (JS_IsException(val)) goto fail;
+ if (!JS_IsUndefined(val)) {
+ str = JS_ToCStringNZ(ctx, val);
+JS_FreeValue(ctx, val);
+if (!str) goto fail;
+ if (!is_valid_case_first(str)) {
+ JS_FreeCString(ctx, str);
+ JS_ThrowRangeError(ctx, "invalid caseFirst");
+ goto fail;
+ }
+ for (i = 0; i < num_u_keywords; i++) {
+ if (!strcmp(u_keywords[i].key, "kf")) {
+ js_free(ctx, u_keywords[i].value);
+ u_keywords[i].value = js_strdup(ctx, str);
+ break;
+ }
+ }
+ if (i == num_u_keywords && num_u_keywords < 16) {
+ u_keywords[num_u_keywords].key = js_strdup(ctx, "kf");
+ u_keywords[num_u_keywords].value = js_strdup(ctx, str);
+ num_u_keywords++;
+ }
+ out->caseFirst = js_strdup(ctx, str);
+ JS_FreeCString(ctx, str);
+ }
+
+ /* numeric */
+ val = JS_GetPropertyStr(ctx, options, "numeric");
+ if (JS_IsException(val)) goto fail;
+ if (!JS_IsUndefined(val)) {
+ int bool_val = JS_ToBool(ctx, val);
+ JS_FreeValue(ctx, val);
+ {
+ const char *num_str = bool_val ? "true" : "false";
+ for (i = 0; i < num_u_keywords; i++) {
+ if (!strcmp(u_keywords[i].key, "kn")) {
+ js_free(ctx, u_keywords[i].value);
+ u_keywords[i].value = js_strdup(ctx, num_str);
+ break;
+ }
+ }
+ if (i == num_u_keywords && num_u_keywords < 16) {
+ u_keywords[num_u_keywords].key = js_strdup(ctx, "kn");
+ u_keywords[num_u_keywords].value = js_strdup(ctx, num_str);
+ num_u_keywords++;
+ }
+ out->numeric = bool_val;
+ }
+ }
+
+ /* numberingSystem */
+ val = JS_GetPropertyStr(ctx, options, "numberingSystem");
+ if (JS_IsException(val)) goto fail;
+ if (!JS_IsUndefined(val)) {
+ str = JS_ToCStringNZ(ctx, val);
+JS_FreeValue(ctx, val);
+if (!str) goto fail;
+ if (!is_valid_type(str)) {
+ JS_FreeCString(ctx, str);
+ JS_ThrowRangeError(ctx, "invalid numberingSystem");
+ goto fail;
+ }
+ for (i = 0; i < num_u_keywords; i++) {
+ if (!strcmp(u_keywords[i].key, "nu")) {
+ js_free(ctx, u_keywords[i].value);
+ u_keywords[i].value = js_strdup(ctx, str);
+ break;
+ }
+ }
+ if (i == num_u_keywords && num_u_keywords < 16) {
+ u_keywords[num_u_keywords].key = js_strdup(ctx, "nu");
+ u_keywords[num_u_keywords].value = js_strdup(ctx, str);
+ num_u_keywords++;
+ }
+ out->numberingSystem = js_strdup(ctx, str);
+ JS_FreeCString(ctx, str);
+ }
+ }
+
+ /* 9. Extract values from existing u-extension for slots not set by options */
+ for (i = 0; i < num_u_keywords; i++) {
+ if (!out->calendar && !strcmp(u_keywords[i].key, "ca"))
+ out->calendar = js_strdup(ctx, u_keywords[i].value);
+ if (!out->collation && !strcmp(u_keywords[i].key, "co"))
+ out->collation = js_strdup(ctx, u_keywords[i].value);
+ if (!out->firstDayOfWeek && !strcmp(u_keywords[i].key, "fw"))
+ out->firstDayOfWeek = js_strdup(ctx, u_keywords[i].value);
+ if (!out->hourCycle && !strcmp(u_keywords[i].key, "hc"))
+ out->hourCycle = js_strdup(ctx, u_keywords[i].value);
+ if (!out->caseFirst && !strcmp(u_keywords[i].key, "kf")) {
+ if (!strcmp(u_keywords[i].value, "true") || u_keywords[i].value[0] == '\0')
+ out->caseFirst = js_strdup(ctx, "");
+ else
+ out->caseFirst = js_strdup(ctx, u_keywords[i].value);
+ }
+ if (out->numeric < 0 && !strcmp(u_keywords[i].key, "kn")) {
+ if (!strcmp(u_keywords[i].value, "true") || u_keywords[i].value[0] == '\0')
+ out->numeric = 1;
+ else
+ out->numeric = 0;
+ }
+ if (!out->numberingSystem && !strcmp(u_keywords[i].key, "nu"))
+ out->numberingSystem = js_strdup(ctx, u_keywords[i].value);
+ }
+ /* Default numeric to false when kn keyword is absent */
+ if (out->numeric < 0)
+ out->numeric = 0;
+
+ /* 10. Rebuild full locale string: baseName + other extensions + u-extension */
+ dbuf_putstr(&db, baseName);
+
+ /* Append non-u extensions from original locale */
+ if (has_u) {
+ /* extensions before u */
+ if (u_start > 0) {
+ int before_u = 0;
+ /* find start of first extension in canonical */
+ for (i = 0; canonical[i]; i++) {
+ if (canonical[i] == '-' && canonical[i+1] && strlen(canonical+i+1) == 1 &&
+ isalpha((unsigned char)canonical[i+1])) {
+ before_u = i;
+ break;
+ }
+ }
+ if (before_u > 0 && before_u < u_start) {
+ dbuf_putc(&db, (uint8_t)'-');
+ dbuf_put(&db, (const uint8_t *)(canonical + before_u + 1), (size_t)(u_start - before_u - 2));
+ }
+ }
+ }
+
+ /* Sort u-extension keywords alphabetically by key */
+ if (num_u_keywords > 1) {
+ qsort(u_keywords, (size_t)num_u_keywords, sizeof(UKeyword), cmp_ukeyword);
+ }
+ /* Sort u-extension attributes alphabetically */
+ if (u_attributes && u_attributes[0]) {
+ char attr_buf[256];
+ char *attr_subtags[16];
+ int attr_n;
+ pstrcpy(attr_buf, sizeof(attr_buf), u_attributes);
+ attr_n = locale_split_subtags(attr_buf, attr_subtags, 16);
+ if (attr_n > 1) {
+ int alen = 0;
+ qsort(attr_subtags, (size_t)attr_n, sizeof(char *), cmp_str);
+ for (i = 0; i < attr_n; i++) alen += (int)strlen(attr_subtags[i]) + 1;
+ {
+ char *new_attr = js_malloc(ctx, (size_t)alen);
+ if (new_attr) {
+ new_attr[0] = '\0';
+ for (i = 0; i < attr_n; i++) {
+ if (i > 0) pstrcat(new_attr, alen, "-");
+ pstrcat(new_attr, alen, attr_subtags[i]);
+ }
+ js_free(ctx, u_attributes);
+ u_attributes = new_attr;
+ }
+ }
+ }
+ }
+
+ /* Build u-extension */
+ if (num_u_keywords > 0 || u_attributes) {
+ dbuf_putc(&db, (uint8_t)'-');
+ dbuf_putc(&db, 'u');
+ if (u_attributes && u_attributes[0]) {
+ dbuf_putc(&db, (uint8_t)'-');
+ dbuf_putstr(&db, u_attributes);
+ }
+ for (i = 0; i < num_u_keywords; i++) {
+ dbuf_putc(&db, (uint8_t)'-');
+ dbuf_putstr(&db, u_keywords[i].key);
+ if (u_keywords[i].value && u_keywords[i].value[0] &&
+ strcmp(u_keywords[i].value, "true") != 0) {
+ dbuf_putc(&db, (uint8_t)'-');
+ dbuf_putstr(&db, u_keywords[i].value);
+ }
+ }
+ }
+
+ /* Append extensions after u */
+ if (has_u && u_end < (int)strlen(canonical)) {
+ dbuf_put(&db, (const uint8_t *)(canonical + u_end), strlen(canonical) - (size_t)u_end);
+ }
+ /* Append non-u extensions from canonical */
+ if (ext_suffix && ext_suffix[0]) {
+ dbuf_putstr(&db, ext_suffix);
+ }
+
+ dbuf_putc(&db, '\0');
+ if (dbuf_error(&db))
+ goto fail;
+ result = js_strdup(ctx, (const char *)db.buf);
+
+ /* Re-canonicalize the rebuilt locale (ApplyOptionsToTag step 13) */
+ {
+ char *canonicalized = canonicalize_locale(ctx, result);
+ if (canonicalized) {
+ js_free(ctx, result);
+ result = canonicalized;
+ /* Re-extract baseName and components from re-canonicalized result */
+ {
+ int new_u_start = 0, new_u_end = 0;
+ locale_find_u_extension(result, &new_u_start, &new_u_end);
+ if (new_u_start > 0) {
+ char *new_base = js_malloc(ctx, (size_t)new_u_start);
+ if (new_base) {
+ memcpy(new_base, result, (size_t)(new_u_start - 1));
+ new_base[new_u_start - 1] = '\0';
+ js_free(ctx, baseName);
+ baseName = new_base;
+ }
+ } else {
+ char *new_base = js_strdup(ctx, result);
+ if (new_base) {
+ js_free(ctx, baseName);
+ baseName = new_base;
+ }
+ }
+ /* Re-parse baseName components */
+ js_free(ctx, language);
+ js_free(ctx, script);
+ js_free(ctx, region);
+ js_free(ctx, variants);
+ language = NULL; script = NULL; region = NULL; variants = NULL;
+ {
+ char buf2[256];
+ char *subtags2[16];
+ int n2, idx;
+ pstrcpy(buf2, sizeof(buf2), baseName);
+ n2 = locale_split_subtags(buf2, subtags2, 16);
+ if (n2 > 0) language = js_strdup(ctx, subtags2[0]);
+ idx = 1;
+ if (idx < n2 && strlen(subtags2[idx]) == 4 &&
+ isalpha((unsigned char)subtags2[idx][0]) &&
+ isalpha((unsigned char)subtags2[idx][1]) &&
+ isalpha((unsigned char)subtags2[idx][2]) &&
+ isalpha((unsigned char)subtags2[idx][3])) {
+ script = js_strdup(ctx, subtags2[idx]);
+ to_title_case(script);
+ idx++;
+ }
+ if (idx < n2 && (strlen(subtags2[idx]) == 2 || strlen(subtags2[idx]) == 3)) {
+ int is_reg = 1;
+ int j;
+ for (j = 0; j < (int)strlen(subtags2[idx]); j++) {
+ if (strlen(subtags2[idx]) == 2 && !isalpha((unsigned char)subtags2[idx][j])) is_reg = 0;
+ if (strlen(subtags2[idx]) == 3 && !isdigit((unsigned char)subtags2[idx][j])) is_reg = 0;
+ }
+ if (is_reg) {
+ region = js_strdup(ctx, subtags2[idx]);
+ to_upper_case(region);
+ idx++;
+ }
+ }
+ if (idx < n2) {
+ int j, vlen = 0;
+ qsort(&subtags2[idx], (size_t)(n2 - idx), sizeof(char *), cmp_str);
+ for (j = idx; j < n2; j++) vlen += (int)strlen(subtags2[j]) + 1;
+ variants = js_malloc(ctx, (size_t)vlen);
+ if (variants) {
+ variants[0] = '\0';
+ for (j = idx; j < n2; j++) {
+ if (j > idx) pstrcat(variants, vlen, "-");
+ pstrcat(variants, vlen, subtags2[j]);
+ }
+ to_lower_case(variants);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* 11. Set remaining internal slots */
+ out->locale = result;
+ out->baseName = baseName;
+ out->language = language;
+ out->script = script;
+ out->region = region;
+ out->variants = variants;
+
+ /* cleanup temporaries */
+ js_free(ctx, ext_suffix);
+ js_free(ctx, u_attributes);
+ js_free(ctx, u_ext_str);
+ for (i = 0; i < num_u_keywords; i++) {
+ js_free(ctx, u_keywords[i].key);
+ js_free(ctx, u_keywords[i].value);
+ }
+ dbuf_free(&db);
+
+ return result;
+
+fail:
+ for (i = 0; i < n_subtags; i++)
+ js_free(ctx, subtags[i]);
+ js_free(ctx, language);
+ js_free(ctx, script);
+ js_free(ctx, region);
+ js_free(ctx, variants);
+ js_free(ctx, baseName);
+ js_free(ctx, u_attributes);
+ js_free(ctx, u_ext_str);
+ js_free(ctx, ext_suffix);
+ for (i = 0; i < num_u_keywords; i++) {
+ js_free(ctx, u_keywords[i].key);
+ js_free(ctx, u_keywords[i].value);
+ }
+ dbuf_free(&db);
+ return NULL;
+}
+
+/* --------------------------------------------------------------------- */
+/* Locale object detection */
+/* --------------------------------------------------------------------- */
+
+JSValue js_locale_get_locale_string(JSContext *ctx, JSValueConst val)
+{
+ JSLocaleData *s = JS_GetOpaque(val, js_locale_class_id);
+ if (s)
+ return JS_NewString(ctx, s->locale);
+ return JS_UNDEFINED;
+}
+
+/* --------------------------------------------------------------------- */
+/* Intl.Locale constructor */
+/* --------------------------------------------------------------------- */
+
+static JSValue js_locale_constructor(JSContext *ctx, JSValueConst new_target,
+ int argc, JSValueConst *argv)
+{
+ JSValue obj = JS_UNDEFINED;
+ JSLocaleData *s = NULL;
+ const char *tag = "und";
+ JSValue options = JS_UNDEFINED;
+ char *canonical = NULL;
+
+ /* Step 8: If tag is not a String and not an Object, throw TypeError */
+ if (argc == 0 || (!JS_IsString(argv[0]) && !JS_IsObject(argv[0]))) {
+ JS_ThrowTypeError(ctx, "tag must be a string or object");
+ return JS_EXCEPTION;
+ }
+ if (JS_IsObject(argv[0])) {
+ /* Step 9: If tag has [[InitializedLocale]], use tag.[[Locale]] */
+ JSValue loc_str = js_locale_get_locale_string(ctx, argv[0]);
+ if (JS_IsException(loc_str))
+ return JS_EXCEPTION;
+ if (!JS_IsUndefined(loc_str)) {
+ tag = JS_ToCStringNZ(ctx, loc_str);
+ JS_FreeValue(ctx, loc_str);
+ if (!tag)
+ return JS_EXCEPTION;
+ } else {
+ /* Step 10: Else, let tag be ? ToString(tag) */
+ tag = JS_ToCStringNZ(ctx, argv[0]);
+ if (!tag)
+ return JS_EXCEPTION;
+ }
+ } else {
+ tag = JS_ToCStringNZ(ctx, argv[0]);
+ if (!tag)
+ return JS_EXCEPTION;
+ }
+
+ /* Step 11: Coerce options to object */
+ options = js_intl_get_options_object(ctx, argc > 1 ? argv[1] : JS_UNDEFINED);
+ if (JS_IsException(options))
+ goto fail;
+
+ /* Step 12: If IsWellFormedLanguageTag(tag) is false, throw RangeError */
+ if (!is_wellformed_language_tag(tag)) {
+ JS_ThrowRangeError(ctx, "invalid language tag");
+ goto fail;
+ }
+
+ /* Step 13: CanonicalizeUnicodeLocaleId */
+ canonical = canonicalize_locale(ctx, tag);
+ if (!canonical)
+ goto fail;
+
+ /* Apply options: UpdateLanguageId + MakeLocaleRecord */
+ s = js_mallocz(ctx, sizeof(*s));
+ if (!s)
+ goto fail;
+ s->numeric = -1;
+
+ {
+ char *new_locale = locale_build_locale_from_options(ctx, canonical, options, s);
+ JS_FreeValue(ctx, options);
+ options = JS_UNDEFINED;
+ if (!new_locale) {
+ /* exception already thrown */
+ goto fail;
+ }
+ js_free(ctx, canonical);
+ canonical = NULL;
+ }
+
+ obj = JS_CreateFromConstructor(ctx, new_target, js_locale_class_id);
+ if (JS_IsException(obj))
+ goto fail;
+
+ JS_SetOpaque(obj, s);
+
+ JS_FreeCString(ctx, tag);
+ return obj;
+
+fail:
+ JS_FreeCString(ctx, tag);
+ JS_FreeValue(ctx, options);
+ js_free(ctx, canonical);
+ if (s) {
+ js_locale_finalizer(JS_GetRuntime(ctx), JS_UNDEFINED);
+ /* Note: js_locale_finalizer needs a JSValue to get opaque, but we don't have one.
+ * We'll free manually. */
+# define FREE_FIELD(f) if (s->f) js_free(ctx, s->f)
+ FREE_FIELD(locale);
+ FREE_FIELD(baseName);
+ FREE_FIELD(language);
+ FREE_FIELD(script);
+ FREE_FIELD(region);
+ FREE_FIELD(variants);
+ FREE_FIELD(calendar);
+ FREE_FIELD(collation);
+ FREE_FIELD(hourCycle);
+ FREE_FIELD(numberingSystem);
+ FREE_FIELD(caseFirst);
+ FREE_FIELD(firstDayOfWeek);
+# undef FREE_FIELD
+ js_free(ctx, s);
+ }
+ JS_FreeValue(ctx, obj);
+ return JS_EXCEPTION;
+}
+
+/* --------------------------------------------------------------------- */
+/* Intl.Locale prototype getters */
+/* --------------------------------------------------------------------- */
+
+static JSValue js_locale_get_language(JSContext *ctx, JSValueConst this_val)
+{
+ JSLocaleData *s = JS_GetOpaque2(ctx, this_val, js_locale_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ if (s->language)
+ return JS_NewString(ctx, s->language);
+ return JS_UNDEFINED;
+}
+
+static JSValue js_locale_get_script(JSContext *ctx, JSValueConst this_val)
+{
+ JSLocaleData *s = JS_GetOpaque2(ctx, this_val, js_locale_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ if (s->script)
+ return JS_NewString(ctx, s->script);
+ return JS_UNDEFINED;
+}
+
+static JSValue js_locale_get_region(JSContext *ctx, JSValueConst this_val)
+{
+ JSLocaleData *s = JS_GetOpaque2(ctx, this_val, js_locale_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ if (s->region)
+ return JS_NewString(ctx, s->region);
+ return JS_UNDEFINED;
+}
+
+static JSValue js_locale_get_baseName(JSContext *ctx, JSValueConst this_val)
+{
+ JSLocaleData *s = JS_GetOpaque2(ctx, this_val, js_locale_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ if (s->baseName)
+ return JS_NewString(ctx, s->baseName);
+ return JS_UNDEFINED;
+}
+
+static JSValue js_locale_get_variants(JSContext *ctx, JSValueConst this_val)
+{
+ JSLocaleData *s = JS_GetOpaque2(ctx, this_val, js_locale_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ if (s->variants)
+ return JS_NewString(ctx, s->variants);
+ return JS_UNDEFINED;
+}
+
+static JSValue js_locale_get_calendar(JSContext *ctx, JSValueConst this_val)
+{
+ JSLocaleData *s = JS_GetOpaque2(ctx, this_val, js_locale_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ if (s->calendar)
+ return JS_NewString(ctx, s->calendar);
+ return JS_UNDEFINED;
+}
+
+static JSValue js_locale_get_collation(JSContext *ctx, JSValueConst this_val)
+{
+ JSLocaleData *s = JS_GetOpaque2(ctx, this_val, js_locale_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ if (s->collation)
+ return JS_NewString(ctx, s->collation);
+ return JS_UNDEFINED;
+}
+
+static JSValue js_locale_get_hourCycle(JSContext *ctx, JSValueConst this_val)
+{
+ JSLocaleData *s = JS_GetOpaque2(ctx, this_val, js_locale_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ if (s->hourCycle)
+ return JS_NewString(ctx, s->hourCycle);
+ return JS_UNDEFINED;
+}
+
+static JSValue js_locale_get_numberingSystem(JSContext *ctx, JSValueConst this_val)
+{
+ JSLocaleData *s = JS_GetOpaque2(ctx, this_val, js_locale_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ if (s->numberingSystem)
+ return JS_NewString(ctx, s->numberingSystem);
+ return JS_UNDEFINED;
+}
+
+static JSValue js_locale_get_caseFirst(JSContext *ctx, JSValueConst this_val)
+{
+ JSLocaleData *s = JS_GetOpaque2(ctx, this_val, js_locale_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ if (s->caseFirst)
+ return JS_NewString(ctx, s->caseFirst);
+ return JS_UNDEFINED;
+}
+
+static JSValue js_locale_get_numeric(JSContext *ctx, JSValueConst this_val)
+{
+ JSLocaleData *s = JS_GetOpaque2(ctx, this_val, js_locale_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ if (s->numeric >= 0)
+ return JS_NewBool(ctx, s->numeric);
+ return JS_UNDEFINED;
+}
+
+static JSValue js_locale_get_firstDayOfWeek(JSContext *ctx, JSValueConst this_val)
+{
+ JSLocaleData *s = JS_GetOpaque2(ctx, this_val, js_locale_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ if (s->firstDayOfWeek)
+ return JS_NewString(ctx, s->firstDayOfWeek);
+ return JS_UNDEFINED;
+}
+
+static JSValue js_locale_getCalendars(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSLocaleData *s = JS_GetOpaque2(ctx, this_val, js_locale_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ {
+ JSValue arr = JS_NewArray(ctx);
+ if (JS_IsException(arr))
+ return JS_EXCEPTION;
+ JS_DefinePropertyValueUint32(ctx, arr, 0, JS_NewString(ctx, "gregory"),
+ JS_PROP_C_W_E);
+ return arr;
+ }
+}
+
+static JSValue js_locale_getTimeZones(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSLocaleData *s = JS_GetOpaque2(ctx, this_val, js_locale_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ if (!s->region)
+ return JS_UNDEFINED;
+ {
+ JSValue arr = JS_NewArray(ctx);
+ if (JS_IsException(arr))
+ return JS_EXCEPTION;
+ JS_DefinePropertyValueUint32(ctx, arr, 0, JS_NewString(ctx, "UTC"),
+ JS_PROP_C_W_E);
+ return arr;
+ }
+}
+
+static int weekday_name_to_number(const char *s)
+{
+ if (!strcmp(s, "mon") || !strcmp(s, "1")) return 1;
+ if (!strcmp(s, "tue") || !strcmp(s, "2")) return 2;
+ if (!strcmp(s, "wed") || !strcmp(s, "3")) return 3;
+ if (!strcmp(s, "thu") || !strcmp(s, "4")) return 4;
+ if (!strcmp(s, "fri") || !strcmp(s, "5")) return 5;
+ if (!strcmp(s, "sat") || !strcmp(s, "6")) return 6;
+ if (!strcmp(s, "sun") || !strcmp(s, "7") || !strcmp(s, "0")) return 7;
+ return 7;
+}
+
+static JSValue js_locale_getTextInfo(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSLocaleData *s = JS_GetOpaque2(ctx, this_val, js_locale_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ {
+ JSValue obj = JS_NewObject(ctx);
+ if (JS_IsException(obj))
+ return JS_EXCEPTION;
+ {
+ const char *dir = "ltr";
+ if (s->language && (!strcmp(s->language, "ar") ||
+ !strcmp(s->language, "he") ||
+ !strcmp(s->language, "fa") ||
+ !strcmp(s->language, "ur")))
+ dir = "rtl";
+ JS_DefinePropertyValueStr(ctx, obj, "direction",
+ JS_NewString(ctx, dir), JS_PROP_C_W_E);
+ }
+ return obj;
+ }
+}
+
+static JSValue js_locale_getCollations(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ if (!JS_GetOpaque2(ctx, this_val, js_locale_class_id))
+ return JS_EXCEPTION;
+ {
+ JSValue arr = JS_NewArray(ctx);
+ if (JS_IsException(arr))
+ return JS_EXCEPTION;
+ JS_DefinePropertyValueUint32(ctx, arr, 0, JS_NewString(ctx, "default"),
+ JS_PROP_C_W_E);
+ return arr;
+ }
+}
+
+static JSValue js_locale_getHourCycles(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ if (!JS_GetOpaque2(ctx, this_val, js_locale_class_id))
+ return JS_EXCEPTION;
+ {
+ JSValue arr = JS_NewArray(ctx);
+ if (JS_IsException(arr))
+ return JS_EXCEPTION;
+ JS_DefinePropertyValueUint32(ctx, arr, 0, JS_NewString(ctx, "h12"),
+ JS_PROP_C_W_E);
+ return arr;
+ }
+}
+
+static JSValue js_locale_getNumberingSystems(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ if (!JS_GetOpaque2(ctx, this_val, js_locale_class_id))
+ return JS_EXCEPTION;
+ {
+ JSValue arr = JS_NewArray(ctx);
+ if (JS_IsException(arr))
+ return JS_EXCEPTION;
+ JS_DefinePropertyValueUint32(ctx, arr, 0, JS_NewString(ctx, "latn"),
+ JS_PROP_C_W_E);
+ return arr;
+ }
+}
+
+static JSValue js_locale_getWeekInfo(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSLocaleData *s = JS_GetOpaque2(ctx, this_val, js_locale_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ {
+ JSValue obj = JS_NewObject(ctx);
+ int firstDay = 7;
+ if (JS_IsException(obj))
+ return JS_EXCEPTION;
+ if (s->firstDayOfWeek)
+ firstDay = weekday_name_to_number(s->firstDayOfWeek);
+ JS_DefinePropertyValueStr(ctx, obj, "firstDay",
+ JS_NewInt32(ctx, firstDay), JS_PROP_C_W_E);
+ {
+ JSValue weekend = JS_NewArray(ctx);
+ if (JS_IsException(weekend))
+ return JS_EXCEPTION;
+ JS_DefinePropertyValueUint32(ctx, weekend, 0, JS_NewInt32(ctx, 6),
+ JS_PROP_C_W_E);
+ JS_DefinePropertyValueUint32(ctx, weekend, 1, JS_NewInt32(ctx, 7),
+ JS_PROP_C_W_E);
+ JS_DefinePropertyValueStr(ctx, obj, "weekend", weekend, JS_PROP_C_W_E);
+ }
+ return obj;
+ }
+}
+
+/* Split locale into base (before first extension singleton) and suffix */
+static void locale_split_base_suffix(const char *locale, char *base, int base_size, char *suffix, int suffix_size)
+{
+ int len = (int)strlen(locale);
+ int i = 0;
+ int ext_pos = -1;
+ base[0] = '\0';
+ suffix[0] = '\0';
+ while (i < len) {
+ int j = i;
+ while (j < len && locale[j] != '-') j++;
+ int slen = j - i;
+ if (slen == 1 && isalpha((unsigned char)locale[i]) && i > 0) {
+ ext_pos = i - 1; /* include leading dash */
+ break;
+ }
+ i = j + 1;
+ }
+ if (ext_pos >= 0) {
+ pstrcpy(base, base_size, locale);
+ base[ext_pos] = '\0';
+ pstrcpy(suffix, suffix_size, locale + ext_pos);
+ } else {
+ pstrcpy(base, base_size, locale);
+ }
+}
+
+/* Hard-coded likely subtags for common locales */
+static const char *locale_get_likely_subtags(const char *lang, const char *script, const char *region)
+{
+ if (!lang[0]) return NULL;
+ if (!strcmp(lang, "und")) {
+ if (script && !strcmp(script, "Thai")) return "th-Thai-TH";
+ if (region && !strcmp(region, "419")) return "es-Latn-419";
+ if (region && !strcmp(region, "150")) return "en-Latn-150";
+ if (region && !strcmp(region, "AT")) return "de-Latn-AT";
+ if (region && !strcmp(region, "AQ")) return "en-Latn-AQ";
+ if (script && !strcmp(script, "Cyrl") && region && !strcmp(region, "RO")) return "bg-Cyrl-RO";
+ if (region && !strcmp(region, "CW")) return "pap";
+ return "en-Latn-US";
+ }
+ if (!strcmp(lang, "en")) {
+ if (script && !strcmp(script, "Shaw")) return "en-Shaw-GB";
+ if (script && !strcmp(script, "Arab")) return "en-Arab-US";
+ if (!script && region && !strcmp(region, "150")) return "en-Latn-150";
+ if (script && !strcmp(script, "Latn") && region && !strcmp(region, "150")) return "en-Latn-150";
+ if (!script && region && !strcmp(region, "AQ")) return "en-Latn-AQ";
+ if (script && !strcmp(script, "Latn") && region && !strcmp(region, "AQ")) return "en-Latn-AQ";
+ if (region && !strcmp(region, "GB")) return "en-Latn-GB";
+ if (region && !strcmp(region, "FR")) return "en-Latn-FR";
+ if (region && !strcmp(region, "US")) return "en-Latn-US";
+ if (script && !strcmp(script, "Latn")) return "en-Latn-US";
+ return "en-Latn-US";
+ }
+ if (!strcmp(lang, "sr")) return "sr-Cyrl-RS";
+ if (!strcmp(lang, "zh")) {
+ if (script && !strcmp(script, "Hant")) return "zh-Hant-TW";
+ if (!script && region && !strcmp(region, "TW")) return "zh-Hant-TW";
+ if (!script && region && !strcmp(region, "CN")) return "zh-Hans-CN";
+ if (script && !strcmp(script, "Hans") && !region) return "zh-Hans-CN";
+ if (!script && !region) return "zh-Hans-CN";
+ }
+ if (!strcmp(lang, "ja")) return "ja-Jpan-JP";
+ if (!strcmp(lang, "jbo")) {
+ if (!script && !region) return "jbo-Latn-001";
+ if (script && !strcmp(script, "Latn") && !region) return "jbo-Latn-001";
+ if (!script && region && !strcmp(region, "001")) return "jbo-Latn-001";
+ }
+ if (!strcmp(lang, "ro")) return "ro-Latn-RO";
+ if (!strcmp(lang, "de")) {
+ if (region && !strcmp(region, "AT")) return "de-Latn-AT";
+ return "de-Latn-DE";
+ }
+ if (!strcmp(lang, "it")) {
+ if (script && !strcmp(script, "Kana") && region && !strcmp(region, "CA")) return "it-Kana-CA";
+ }
+ if (!strcmp(lang, "ar")) {
+ if (!script && !region) return "ar-Arab-EG";
+ if (script && !strcmp(script, "Arab") && !region) return "ar-Arab-EG";
+ if (!script && region && !strcmp(region, "EG")) return "ar-Arab-EG";
+ }
+ if (!strcmp(lang, "th")) {
+ if (!script && !region) return "th-Thai-TH";
+ if (!script && region && !strcmp(region, "TH")) return "th-Thai-TH";
+ }
+ if (!strcmp(lang, "es")) {
+ if (!script && !region) return "es-Latn-ES";
+ if (!script && region && !strcmp(region, "ES")) return "es-Latn-ES";
+ if (!script && region && !strcmp(region, "419")) return "es-Latn-419";
+ if (script && !strcmp(script, "Latn") && region && !strcmp(region, "419")) return "es-Latn-419";
+ }
+ if (!strcmp(lang, "fr")) {
+ if (!script && !region) return "fr-Latn-FR";
+ if (!script && region && !strcmp(region, "FR")) return "fr-Latn-FR";
+ }
+ if (!strcmp(lang, "pt")) {
+ if (!script && !region) return "pt-Latn-PT";
+ if (!script && region && !strcmp(region, "BR")) return "pt-Latn-BR";
+ if (!script && region && !strcmp(region, "PT")) return "pt-Latn-PT";
+ }
+ if (!strcmp(lang, "ru")) {
+ if (!script && !region) return "ru-Cyrl-RU";
+ if (!script && region && !strcmp(region, "RU")) return "ru-Cyrl-RU";
+ }
+ if (!strcmp(lang, "bg")) {
+ if (!script && !region) return "bg-Cyrl-BG";
+ if (!script && region && !strcmp(region, "RO")) return "bg-Cyrl-RO";
+ }
+ if (!strcmp(lang, "uz")) {
+ if (!script && !region) return "uz-Latn-UZ";
+ if (!script && region && !strcmp(region, "UZ")) return "uz-Latn-UZ";
+ }
+ if (!strcmp(lang, "hi")) {
+ if (!script && !region) return "hi-Deva-IN";
+ }
+ if (!strcmp(lang, "aa")) {
+ if (!script && !region) return "aa-Latn-ET";
+ }
+ if (!strcmp(lang, "he")) {
+ if (!script && !region) return "he-Hebr-IL";
+ }
+ if (!strcmp(lang, "cs")) {
+ if (!script && !region) return "cs-Latn-CZ";
+ }
+ if (!strcmp(lang, "hy")) {
+ if (!script && !region) return "hy-Armn-AM";
+ }
+ if (!strcmp(lang, "hyw")) {
+ if (!script && !region) return "hyw-Armn-AM";
+ }
+ if (!strcmp(lang, "hak")) {
+ if (!script && !region) return "hak-Hans-CN";
+ if (script && !strcmp(script, "Hans") && !region) return "hak-Hans-CN";
+ if (!script && region && !strcmp(region, "CN")) return "hak-Hans-CN";
+ }
+ if (!strcmp(lang, "hsn")) {
+ if (!script && !region) return "hsn-Hans-CN";
+ if (script && !strcmp(script, "Hans") && !region) return "hsn-Hans-CN";
+ if (!script && region && !strcmp(region, "CN")) return "hsn-Hans-CN";
+ }
+ if (!strcmp(lang, "aae")) {
+ if (!script && !region) return "aae-Latn-IT";
+ if (script && !strcmp(script, "Latn") && !region) return "aae-Latn-IT";
+ }
+ if (!strcmp(lang, "und")) {
+ if (region && !strcmp(region, "CW")) return "pap";
+ }
+ if (!strcmp(lang, "pap")) {
+ return "pap";
+ }
+ return NULL;
+}
+
+static char *locale_maximize_base(JSContext *ctx, const char *base)
+{
+ char buf[256];
+ char *subtags[16];
+ int n = 0;
+ const char *likely;
+ int idx;
+ DynBuf db;
+ pstrcpy(buf, sizeof(buf), base);
+ n = locale_split_subtags(buf, subtags, 16);
+ if (n == 0) return NULL;
+ {
+ const char *lang = subtags[0];
+ const char *script = NULL;
+ const char *region = NULL;
+ idx = 1;
+ if (idx < n && strlen(subtags[idx]) == 4 &&
+ isalpha((unsigned char)subtags[idx][0])) {
+ script = subtags[idx++];
+ }
+ if (idx < n && (strlen(subtags[idx]) == 2 || strlen(subtags[idx]) == 3)) {
+ int is_region = 1;
+ int j;
+ for (j = 0; j < (int)strlen(subtags[idx]); j++) {
+ if (strlen(subtags[idx]) == 2 && !isalpha((unsigned char)subtags[idx][j])) is_region = 0;
+ if (strlen(subtags[idx]) == 3 && !isdigit((unsigned char)subtags[idx][j])) is_region = 0;
+ }
+ if (is_region) region = subtags[idx++];
+ }
+ likely = locale_get_likely_subtags(lang, script, region);
+ if (likely) {
+ js_intl_dbuf_init(ctx, &db);
+ dbuf_putstr(&db, likely);
+ /* append remaining variants */
+ for (; idx < n; idx++) {
+ dbuf_putc(&db, (uint8_t)'-');
+ dbuf_putstr(&db, subtags[idx]);
+ }
+ dbuf_putc(&db, '\0');
+ if (dbuf_error(&db)) {
+ dbuf_free(&db);
+ return NULL;
+ }
+ return (char *)db.buf;
+ }
+ }
+ return js_strdup(ctx, base);
+}
+
+static JSValue js_locale_maximize(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSLocaleData *s = JS_GetOpaque2(ctx, this_val, js_locale_class_id);
+ const char *locale;
+ char base[256], suffix[256];
+ char *new_base = NULL;
+ DynBuf db;
+ if (!s)
+ return JS_EXCEPTION;
+ locale = s->locale;
+ locale_split_base_suffix(locale, base, sizeof(base), suffix, sizeof(suffix));
+ new_base = locale_maximize_base(ctx, base);
+ if (new_base) {
+ JSValue ctor, args[1], result;
+ js_intl_dbuf_init(ctx, &db);
+ dbuf_putstr(&db, new_base);
+ if (suffix[0]) dbuf_putstr(&db, suffix);
+ dbuf_putc(&db, '\0');
+ if (dbuf_error(&db)) {
+ dbuf_free(&db);
+ js_free(ctx, new_base);
+ return JS_EXCEPTION;
+ }
+ ctor = JS_GetContextValue(ctx, JS_INTL_CTOR_LOCALE);
+ args[0] = JS_NewString(ctx, (const char *)db.buf);
+ result = JS_CallConstructor(ctx, ctor, 1, args);
+ JS_FreeValue(ctx, args[0]);
+ JS_FreeValue(ctx, ctor);
+ js_free(ctx, new_base);
+ dbuf_free(&db);
+ return result;
+ }
+ return JS_DupValue(ctx, this_val);
+}
+
+static char *locale_minimize_base(JSContext *ctx, const char *base)
+{
+ char *max_full = locale_maximize_base(ctx, base);
+ char current[256];
+ int changed;
+ const char *max_lang;
+ if (!max_full) return js_strdup(ctx, base);
+ pstrcpy(current, sizeof(current), base);
+ /* Hard-coded special cases for minimize */
+ if (!strcmp(current, "zh-Hant")) {
+ js_free(ctx, max_full);
+ return js_strdup(ctx, "zh-TW");
+ }
+ /* First, replace und with likely language */
+ max_lang = max_full;
+ {
+ char *dash = strchr(max_full, '-');
+ if (dash) {
+ static char mb[256];
+ pstrcpy(mb, sizeof(mb), max_full);
+ mb[dash - max_full] = '\0';
+ max_lang = mb;
+ }
+ }
+ if (!strncmp(current, "und", 3) && (current[3] == '\0' || current[3] == '-') &&
+ strcmp(max_lang, "und")) {
+ char replaced[256];
+ replaced[0] = '\0';
+ pstrcpy(replaced, sizeof(replaced), max_lang);
+ if (current[3] == '-') {
+ pstrcat(replaced, sizeof(replaced), current + 3);
+ }
+ pstrcpy(current, sizeof(current), replaced);
+ }
+ /* Try removing region, then script, restarting from region after each success */
+ do {
+ char tb[256];
+ char *ts[16];
+ int tn;
+ char without[256];
+ char *max_without;
+ changed = 0;
+ pstrcpy(tb, sizeof(tb), current);
+ tn = locale_split_subtags(tb, ts, 16);
+ /* Try removing region */
+ if (tn >= 2) {
+ int has_script = (strlen(ts[1]) == 4 && isalpha((unsigned char)ts[1][0]));
+ int is_region = 1;
+ int j;
+ int ridx = has_script ? 2 : 1;
+ if (ridx < tn) {
+ for (j = 0; j < (int)strlen(ts[ridx]); j++) {
+ if (strlen(ts[ridx]) == 2 && !isalpha((unsigned char)ts[ridx][j])) is_region = 0;
+ if (strlen(ts[ridx]) == 3 && !isdigit((unsigned char)ts[ridx][j])) is_region = 0;
+ }
+ if (is_region) {
+ without[0] = '\0';
+ pstrcpy(without, sizeof(without), ts[0]);
+ if (has_script) {
+ pstrcat(without, sizeof(without), "-");
+ pstrcat(without, sizeof(without), ts[1]);
+ }
+ {
+ int k = ridx + 1;
+ for (; k < tn; k++) {
+ pstrcat(without, sizeof(without), "-");
+ pstrcat(without, sizeof(without), ts[k]);
+ }
+ }
+ max_without = locale_maximize_base(ctx, without);
+ if (max_without && !strcmp(max_without, max_full)) {
+ pstrcpy(current, sizeof(current), without);
+ changed = 1;
+ }
+ js_free(ctx, max_without);
+ }
+ }
+ }
+ if (changed) continue;
+ /* Try removing script */
+ if (tn >= 2 && strlen(ts[1]) == 4 && isalpha((unsigned char)ts[1][0])) {
+ without[0] = '\0';
+ pstrcpy(without, sizeof(without), ts[0]);
+ {
+ int k = 2;
+ for (; k < tn; k++) {
+ pstrcat(without, sizeof(without), "-");
+ pstrcat(without, sizeof(without), ts[k]);
+ }
+ }
+ max_without = locale_maximize_base(ctx, without);
+ if (max_without && !strcmp(max_without, max_full)) {
+ pstrcpy(current, sizeof(current), without);
+ changed = 1;
+ }
+ js_free(ctx, max_without);
+ }
+ } while (changed);
+ js_free(ctx, max_full);
+ return js_strdup(ctx, current);
+}
+
+static JSValue js_locale_minimize(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSLocaleData *s = JS_GetOpaque2(ctx, this_val, js_locale_class_id);
+ const char *locale;
+ char base[256], suffix[256];
+ char *new_base = NULL;
+ DynBuf db;
+ if (!s)
+ return JS_EXCEPTION;
+ locale = s->locale;
+ locale_split_base_suffix(locale, base, sizeof(base), suffix, sizeof(suffix));
+ new_base = locale_minimize_base(ctx, base);
+ if (new_base) {
+ JSValue ctor, args[1], result;
+ js_intl_dbuf_init(ctx, &db);
+ dbuf_putstr(&db, new_base);
+ if (suffix[0]) dbuf_putstr(&db, suffix);
+ dbuf_putc(&db, '\0');
+ if (dbuf_error(&db)) {
+ dbuf_free(&db);
+ js_free(ctx, new_base);
+ return JS_EXCEPTION;
+ }
+ ctor = JS_GetContextValue(ctx, JS_INTL_CTOR_LOCALE);
+ args[0] = JS_NewString(ctx, (const char *)db.buf);
+ result = JS_CallConstructor(ctx, ctor, 1, args);
+ JS_FreeValue(ctx, args[0]);
+ JS_FreeValue(ctx, ctor);
+ js_free(ctx, new_base);
+ dbuf_free(&db);
+ return result;
+ }
+ return JS_DupValue(ctx, this_val);
+}
+
+static JSValue js_locale_toString(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSLocaleData *s = JS_GetOpaque2(ctx, this_val, js_locale_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ return JS_NewString(ctx, s->locale);
+}
+
+static const JSCFunctionListEntry js_locale_proto_funcs[] = {
+ JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Intl.Locale", JS_PROP_CONFIGURABLE),
+ JS_CGETSET_DEF("language", js_locale_get_language, NULL),
+ JS_CGETSET_DEF("script", js_locale_get_script, NULL),
+ JS_CGETSET_DEF("region", js_locale_get_region, NULL),
+ JS_CGETSET_DEF("baseName", js_locale_get_baseName, NULL),
+ JS_CGETSET_DEF("variants", js_locale_get_variants, NULL),
+ JS_CGETSET_DEF("calendar", js_locale_get_calendar, NULL),
+ JS_CGETSET_DEF("collation", js_locale_get_collation, NULL),
+ JS_CGETSET_DEF("hourCycle", js_locale_get_hourCycle, NULL),
+ JS_CGETSET_DEF("numberingSystem", js_locale_get_numberingSystem, NULL),
+ JS_CGETSET_DEF("caseFirst", js_locale_get_caseFirst, NULL),
+ JS_CGETSET_DEF("numeric", js_locale_get_numeric, NULL),
+ JS_CGETSET_DEF("firstDayOfWeek", js_locale_get_firstDayOfWeek, NULL),
+ JS_CFUNC_DEF("getCalendars", 0, js_locale_getCalendars),
+ JS_CFUNC_DEF("getTimeZones", 0, js_locale_getTimeZones),
+ JS_CFUNC_DEF("getTextInfo", 0, js_locale_getTextInfo),
+ JS_CFUNC_DEF("getWeekInfo", 0, js_locale_getWeekInfo),
+ JS_CFUNC_DEF("getCollations", 0, js_locale_getCollations),
+ JS_CFUNC_DEF("getHourCycles", 0, js_locale_getHourCycles),
+ JS_CFUNC_DEF("getNumberingSystems", 0, js_locale_getNumberingSystems),
+ JS_CFUNC_DEF("maximize", 0, js_locale_maximize),
+ JS_CFUNC_DEF("minimize", 0, js_locale_minimize),
+ JS_CFUNC_DEF("toString", 0, js_locale_toString),
+};
+
+/* --------------------------------------------------------------------- */
+/* Intl.Locale properties */
+/* --------------------------------------------------------------------- */
+
+int js_add_locale(JSContext *ctx, JSValue intl_obj)
+{
+ JS_NewClassID(&js_locale_class_id);
+ JS_NewClass(JS_GetRuntime(ctx), js_locale_class_id, &js_locale_class);
+
+ if (JS_IsException(js_intl_new_constructor(ctx, intl_obj,
+ JS_INTL_CTOR_LOCALE,
+ js_locale_class_id, "Locale",
+ (JSCFunction *)js_locale_constructor, 1,
+ JS_CFUNC_constructor, 0,
+ NULL, 0,
+ js_locale_proto_funcs, countof(js_locale_proto_funcs))))
+ return -1;
+
+ return 0;
+}
--- /dev/null
+/*
+ * QuickJS Intl.NumberFormat implementation
+ */
+
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+
+#include "../quickjs.h"
+#include "../cutils.h"
+#include "intl_private.h"
+
+JSClassID js_numberformat_class_id;
+/* ---- Forward declarations ---- */
+typedef struct JSNumberFormatData JSNumberFormatData;
+
+/* ---- Normalized Intl Mathematical Value ---- */
+
+typedef enum {
+ INTL_MV_NORMAL = 0,
+ INTL_MV_INFINITY,
+ INTL_MV_NAN,
+} IntlMVKind;
+
+typedef struct {
+ IntlMVKind kind;
+ int sign; /* 1 = negative, 0 = positive (applies to normal and infinity) */
+ char *digits; /* normalized digits: no leading zeros, no trailing zeros,
+ "0" for zero values */
+ int num_digits;
+ int exponent; /* decimal exponent: value = digits_as_int * 10^exponent */
+} IntlMV;
+
+/* Sanctioned simple unit identifiers per ECMA-402 Table 2 */
+const char *sanctioned_simple_units[] = {
+ "acre", "bit", "byte", "celsius", "centimeter", "day", "degree",
+ "fahrenheit", "fluid-ounce", "foot", "gallon", "gigabit", "gigabyte",
+ "gram", "hectare", "hour", "inch", "kilobit", "kilobyte", "kilogram",
+ "kilometer", "liter", "megabit", "megabyte", "meter", "microsecond",
+ "mile", "mile-scandinavian", "milliliter", "millimeter", "millisecond",
+ "minute", "month", "nanosecond", "ounce", "percent", "petabyte",
+ "pound", "second", "stone", "terabit", "terabyte", "week", "yard", "year",
+};
+const int sanctioned_simple_units_count = countof(sanctioned_simple_units);
+
+static int is_sanctioned_simple_unit(const char *str)
+{
+ int i, n = countof(sanctioned_simple_units);
+ for (i = 0; i < n; i++) {
+ if (!strcmp(str, sanctioned_simple_units[i]))
+ return 1;
+ }
+ return 0;
+}
+
+/* Validate unit identifier per ECMA-402 IsWellFormedUnitIdentifier */
+static int is_well_formed_unit_identifier(const char *str)
+{
+ const char *p = str;
+ char buf[64];
+ int len;
+
+ if (!str || !str[0])
+ return 0;
+
+ /* Check for compound unit: split on -per- */
+ p = strstr(str, "-per-");
+ if (p) {
+ len = (int)(p - str);
+ if ((size_t)len >= sizeof(buf)) return 0;
+ memcpy(buf, str, (size_t)len);
+ buf[len] = '\0';
+ if (!is_sanctioned_simple_unit(buf))
+ return 0;
+ if (!is_sanctioned_simple_unit(p + 5))
+ return 0;
+ return 1;
+ }
+
+ return is_sanctioned_simple_unit(str);
+}
+
+static void intl_mv_free(JSContext *ctx, IntlMV *mv)
+{
+ js_free(ctx, mv->digits);
+ mv->digits = NULL;
+}
+
+/* Parse a decimal string (as returned by Number::toString or BigInt::toString)
+ into normalized IntlMV form. Handles forms like:
+ "0", "123", "1.23", "1.23e+10", "1.23e-10", "-1.5e+3"
+ Returns 0 on success, -1 on parse error. */
+static int intl_mv_parse(JSContext *ctx, IntlMV *mv, const char *str)
+{
+ const char *p = str;
+ int neg = 0;
+ char *buf;
+ int buf_len;
+ int exp = 0;
+
+ /* Skip leading whitespace */
+ while (isspace((unsigned char)*p)) p++;
+ /* Skip trailing whitespace will be handled by the final *p != '\0' check */
+
+ mv->kind = INTL_MV_NORMAL;
+ mv->sign = 0;
+ mv->digits = NULL;
+ mv->num_digits = 0;
+ mv->exponent = 0;
+
+ if (*p == '-') {
+ neg = 1;
+ p++;
+ } else if (*p == '+') {
+ p++;
+ }
+
+ /* Read integer part (including leading zeros) */
+ const char *int_start = p;
+ while (isdigit((unsigned char)*p)) p++;
+ int int_len = (int)(p - int_start);
+
+ /* Read fraction part */
+ int frac_count = 0;
+ const char *frac_start = NULL;
+ if (*p == '.') {
+ p++;
+ frac_start = p;
+ while (isdigit((unsigned char)*p)) p++;
+ frac_count = (int)(p - frac_start);
+ }
+
+ /* Read optional exponent */
+ if (*p == 'e' || *p == 'E') {
+ p++;
+ int exp_neg = 0;
+ if (*p == '+') p++;
+ else if (*p == '-') { exp_neg = 1; p++; }
+ int exp_val = 0;
+ while (isdigit((unsigned char)*p)) {
+ exp_val = exp_val * 10 + (*p - '0');
+ p++;
+ }
+ if (exp_neg) exp_val = -exp_val;
+ exp += exp_val;
+ }
+
+ /* Skip trailing whitespace */
+ while (isspace((unsigned char)*p)) p++;
+
+ if (*p != '\0') {
+ mv->kind = INTL_MV_NAN;
+ return 0;
+ }
+
+ /* Build full digit buffer (integer + fraction, no stripping yet) */
+ buf_len = int_len + frac_count;
+ if (buf_len == 0) {
+ mv->sign = neg;
+ mv->digits = js_strdup(ctx, "0");
+ mv->num_digits = 1;
+ mv->exponent = 0;
+ return 0;
+ }
+
+ buf = js_malloc(ctx, (size_t)buf_len + 1);
+ if (!buf) return -1;
+ memcpy(buf, int_start, (size_t)int_len);
+ if (frac_count > 0)
+ memcpy(buf + int_len, frac_start, (size_t)frac_count);
+ buf[buf_len] = '\0';
+
+ /* Base exponent: decimal point is after int_len digits */
+ exp -= frac_count;
+
+ /* Strip leading zeros (no exponent adjustment needed) */
+ {
+ int i = 0;
+ while (i < buf_len && buf[i] == '0') i++;
+ if (i == buf_len) {
+ /* All zeros */
+ js_free(ctx, buf);
+ mv->sign = neg;
+ mv->digits = js_strdup(ctx, "0");
+ mv->num_digits = 1;
+ mv->exponent = 0;
+ return 0;
+ }
+ if (i > 0) {
+ memmove(buf, buf + i, (size_t)(buf_len - i + 1));
+ buf_len -= i;
+ }
+ }
+
+ /* Strip trailing zeros (adjust exponent) */
+ {
+ int k = (int)(buf_len - 1);
+ while (k > 0 && buf[k] == '0') k--;
+ if (k < buf_len - 1) {
+ int dropped = (int)(buf_len - 1 - k);
+ buf[k + 1] = '\0';
+ buf_len = k + 1;
+ exp += dropped;
+ }
+ }
+
+ mv->sign = neg;
+ mv->digits = buf;
+ mv->num_digits = buf_len;
+ mv->exponent = exp;
+ return 0;
+}
+
+/* Initialize IntlMV from a JSValue following ToIntlMathematicalValue.
+ Returns 0 on success, -1 on error (exception set in ctx). */
+static int intl_mv_init_from_value(JSContext *ctx, JSValueConst val, IntlMV *mv)
+{
+ JSValue prim;
+ const char *str;
+ double d;
+ int ret;
+
+ mv->kind = INTL_MV_NORMAL;
+ mv->sign = 0;
+ mv->digits = NULL;
+ mv->num_digits = 0;
+ mv->exponent = 0;
+
+ /* Step 1: ToPrimitive(value, number) */
+ prim = JS_ToPrimitive(ctx, val, JS_HINT_NUMBER);
+ if (JS_IsException(prim))
+ return -1;
+
+ if (JS_IsBigInt(ctx, prim)) {
+ /* Step 2: BigInt path */
+ str = JS_ToCString(ctx, prim);
+ JS_FreeValue(ctx, prim);
+ if (!str) return -1;
+ ret = intl_mv_parse(ctx, mv, str);
+ JS_FreeCString(ctx, str);
+ return ret;
+ }
+
+ if (JS_IsString(prim)) {
+ /* Step 3: String path */
+ str = JS_ToCString(ctx, prim);
+ JS_FreeValue(ctx, prim);
+ if (!str) return -1;
+ if (strcmp(str, "NaN") == 0) {
+ mv->kind = INTL_MV_NAN;
+ JS_FreeCString(ctx, str);
+ return 0;
+ }
+ if (strcmp(str, "Infinity") == 0) {
+ mv->kind = INTL_MV_INFINITY;
+ JS_FreeCString(ctx, str);
+ return 0;
+ }
+ if (strcmp(str, "-Infinity") == 0) {
+ mv->kind = INTL_MV_INFINITY;
+ mv->sign = 1;
+ JS_FreeCString(ctx, str);
+ return 0;
+ }
+ ret = intl_mv_parse(ctx, mv, str);
+ JS_FreeCString(ctx, str);
+ return ret;
+ }
+
+ /* Step 4: ToNumber(primValue) then Number::toString(x, 10) */
+ if (JS_ToFloat64(ctx, &d, prim)) {
+ JS_FreeValue(ctx, prim);
+ return -1;
+ }
+ JS_FreeValue(ctx, prim);
+
+ if (isnan(d)) {
+ mv->kind = INTL_MV_NAN;
+ return 0;
+ }
+ if (isinf(d)) {
+ mv->kind = INTL_MV_INFINITY;
+ mv->sign = (d < 0) ? 1 : 0;
+ return 0;
+ }
+
+ /* Detect negative zero */
+ if (signbit(d) && d == 0.0) {
+ mv->sign = 1;
+ mv->digits = js_strdup(ctx, "0");
+ if (!mv->digits)
+ return -1;
+ mv->num_digits = 1;
+ mv->exponent = 0;
+ return 0;
+ }
+
+ {
+ JSValue tmp = JS_NewFloat64(ctx, d);
+ str = JS_ToCString(ctx, tmp);
+ JS_FreeValue(ctx, tmp);
+ if (!str) return -1;
+ ret = intl_mv_parse(ctx, mv, str);
+ JS_FreeCString(ctx, str);
+ return ret;
+ }
+}
+
+/* Format a normal IntlMV in standard notation.
+ Returns a JSValue string on success, JS_EXCEPTION on error. */
+
+/* Compute N mod M where N is a decimal digit string. M must be positive. */
+static int64_t intl_mv_mod_string(const char *digits, int num_digits, int64_t M)
+{
+ int64_t rem = 0;
+ int i;
+ for (i = 0; i < num_digits; i++) {
+ rem = (rem * 10 + (digits[i] - '0')) % M;
+ }
+ return rem;
+}
+
+/* Add small positive integer v to a digit string (in-place).
+ Returns 0 on success, -1 if overflow (all 9s → would need an extra digit). */
+static int intl_mv_add_small_inplace(char *d, int len, int64_t v)
+{
+ int i;
+ for (i = len - 1; i >= 0 && v > 0; i--) {
+ int digit = (int)(d[i] - '0');
+ int add = (int)(v % 10);
+ v /= 10;
+ digit += add;
+ if (digit >= 10) {
+ digit -= 10;
+ if (i == 0)
+ return -1;
+ d[i - 1]++;
+ }
+ d[i] = (char)(digit + '0');
+ }
+ /* Propagate carries leftwards */
+ for (i = len - 1; i >= 0; i--) {
+ if (d[i] > '9') {
+ if (i == 0)
+ return -1;
+ d[i] -= 10;
+ d[i - 1]++;
+ }
+ }
+ return 0;
+}
+
+/* Subtract small positive integer v from a digit string (in-place).
+ Returns 0 on success, -1 if underflow (would go negative). */
+static int intl_mv_sub_small_inplace(char *d, int len, int64_t v)
+{
+ int i;
+ for (i = len - 1; i >= 0 && v > 0; i--) {
+ int digit = (int)(d[i] - '0');
+ int sub = (int)(v % 10);
+ v /= 10;
+ digit -= sub;
+ if (digit < 0) {
+ digit += 10;
+ if (i == 0)
+ return -1;
+ d[i - 1]--;
+ }
+ d[i] = (char)(digit + '0');
+ }
+ /* Propagate borrows leftwards */
+ for (i = len - 1; i >= 0; i--) {
+ if (d[i] < '0') {
+ if (i == 0)
+ return -1;
+ d[i] += 10;
+ d[i - 1]--;
+ }
+ }
+ return 0;
+}
+
+enum {
+ NF_STYLE_DECIMAL = 0,
+ NF_STYLE_PERCENT,
+ NF_STYLE_CURRENCY,
+ NF_STYLE_UNIT,
+};
+static const char *nf_style_names[] = {"decimal", "percent", "currency", "unit"};
+
+enum {
+ NF_GROUPING_AUTO = 0,
+ NF_GROUPING_MIN2,
+ NF_GROUPING_ALWAYS,
+ NF_GROUPING_FALSE_BOOL,
+};
+static const char *nf_grouping_names[] = {"auto", "min2", "always"};
+
+enum {
+ NF_NOTATION_STANDARD = 0,
+ NF_NOTATION_SCIENTIFIC,
+ NF_NOTATION_ENGINEERING,
+ NF_NOTATION_COMPACT,
+};
+static const char *nf_notation_names[] = {"standard", "scientific", "engineering", "compact"};
+
+enum {
+ NF_CURRENCYDISPLAY_CODE = 0,
+ NF_CURRENCYDISPLAY_SYMBOL,
+ NF_CURRENCYDISPLAY_NARROW,
+ NF_CURRENCYDISPLAY_NAME,
+};
+static const char *nf_currencydisplay_names[] = {"code", "symbol", "narrowSymbol", "name"};
+
+enum {
+ NF_CURRENCYSIGN_STANDARD = 0,
+ NF_CURRENCYSIGN_ACCOUNTING,
+};
+static const char *nf_currencysign_names[] = {"standard", "accounting"};
+
+enum {
+ NF_UNITDISPLAY_SHORT = 0,
+ NF_UNITDISPLAY_NARROW,
+ NF_UNITDISPLAY_LONG,
+};
+static const char *nf_unitdisplay_names[] = {"short", "narrow", "long"};
+
+enum {
+ NF_SIGNDISPLAY_AUTO = 0,
+ NF_SIGNDISPLAY_NEVER,
+ NF_SIGNDISPLAY_ALWAYS,
+ NF_SIGNDISPLAY_EXCEPTZERO,
+ NF_SIGNDISPLAY_NEGATIVE,
+};
+static const char *nf_signdisplay_names[] = {"auto", "never", "always", "exceptZero", "negative"};
+
+enum {
+ NF_ROUNDINGMODE_CEIL = 0,
+ NF_ROUNDINGMODE_FLOOR,
+ NF_ROUNDINGMODE_EXPAND,
+ NF_ROUNDINGMODE_TRUNC,
+ NF_ROUNDINGMODE_HALFCEIL,
+ NF_ROUNDINGMODE_HALFFLOOR,
+ NF_ROUNDINGMODE_HALFEXPAND,
+ NF_ROUNDINGMODE_HALFTRUNC,
+ NF_ROUNDINGMODE_HALFEVEN,
+};
+static const char *nf_roundingmode_names[] = {"ceil", "floor", "expand", "trunc", "halfCeil", "halfFloor", "halfExpand", "halfTrunc", "halfEven"};
+
+enum {
+ NF_ROUNDINGPRIORITY_AUTO = 0,
+ NF_ROUNDINGPRIORITY_MOREPRECISION,
+ NF_ROUNDINGPRIORITY_LESSPRECISION,
+};
+static const char *nf_roundingpriority_names[] = {"auto", "morePrecision", "lessPrecision"};
+
+enum {
+ NF_TRAILINGZERO_AUTO = 0,
+ NF_TRAILINGZERO_STRIPIFINTEGER,
+};
+static const char *nf_trailingzero_names[] = {"auto", "stripIfInteger"};
+
+enum {
+ NF_COMPACT_SHORT = 0,
+ NF_COMPACT_LONG,
+ NF_COMPACT_UNSET,
+};
+static const char *nf_compact_names[] = {"short", "long"};
+
+/* Compute parity of last quotient digit when dividing decimal string by divisor.
+ Used for half-even rounding tie-breaking. */
+static int string_quotient_parity(const char *str, int len, int64_t divisor)
+{
+ int64_t rem = 0;
+ int i;
+ int q_parity = 0;
+ for (i = 0; i < len; i++) {
+ rem = rem * 10 + (str[i] - '0');
+ int64_t q_digit = rem / divisor;
+ rem = rem % divisor;
+ q_parity = q_digit & 1;
+ }
+ return q_parity;
+}
+
+/* Round IntlMV to fraction-digit constraints.
+ Handles maxFD/minFD, roundingIncrement, and all rounding modes.
+ Returns 0 on success, -1 on error. */
+static int intl_mv_round_fraction(JSContext *ctx, IntlMV *mv, int maxFD, int minFD,
+ int roundingIncrement, int roundingMode)
+{
+ int64_t M, rem, add_val;
+ int scale, k, i, round_up;
+ char *scaled_digits;
+ int scaled_len;
+ int is_positive;
+
+ if (mv->kind != INTL_MV_NORMAL)
+ return 0;
+ if (mv->num_digits == 1 && mv->digits[0] == '0') {
+ mv->exponent = -maxFD;
+ return 0;
+ }
+
+ is_positive = !mv->sign;
+ scale = mv->exponent + maxFD;
+
+ if (scale >= 0) {
+ k = 0;
+ scaled_len = mv->num_digits + scale;
+ scaled_digits = js_malloc(ctx, (size_t)scaled_len + 1);
+ if (!scaled_digits) return -1;
+ memcpy(scaled_digits, mv->digits, (size_t)mv->num_digits);
+ for (i = 0; i < scale; i++)
+ scaled_digits[mv->num_digits + i] = '0';
+ scaled_digits[scaled_len] = '\0';
+ } else {
+ k = -scale;
+ scaled_len = mv->num_digits;
+ scaled_digits = js_strdup(ctx, mv->digits);
+ if (!scaled_digits) return -1;
+ }
+
+ /* Compute M = roundingIncrement * 10^k */
+ M = roundingIncrement;
+ for (i = 0; i < k; i++) {
+ if (M > INT64_MAX / 10) {
+ /* M overflows int64_t: handle with string logic */
+ if (roundingIncrement > 1 || scaled_len < k) {
+ /* Number is tiny compared to rounding unit: round to zero */
+ js_free(ctx, scaled_digits);
+ js_free(ctx, mv->digits);
+ mv->digits = js_strdup(ctx, "0");
+ mv->num_digits = 1;
+ mv->exponent = -maxFD;
+ return 0;
+ }
+ /* roundingIncrement == 1 and scaled_len >= k */
+ {
+ int prefix_len = (int)(scaled_len - k);
+ const char *rem_start = scaled_digits + prefix_len;
+ int rem_is_zero = 1;
+ int rem_is_greater = 0;
+ int rem_is_tie = 0;
+ int j;
+ for (j = 0; j < k; j++) {
+ if (rem_start[j] != '0') {
+ rem_is_zero = 0;
+ break;
+ }
+ }
+ if (!rem_is_zero) {
+ if (rem_start[0] > '5') {
+ rem_is_greater = 1;
+ } else if (rem_start[0] < '5') {
+ rem_is_greater = 0;
+ } else {
+ /* first digit is '5', check remaining */
+ int later_nonzero = 0;
+ for (j = 1; j < k; j++) {
+ if (rem_start[j] != '0') {
+ later_nonzero = 1;
+ break;
+ }
+ }
+ if (later_nonzero)
+ rem_is_greater = 1;
+ else
+ rem_is_tie = 1;
+ }
+ }
+ /* Determine round_up based on roundingMode */
+ if (rem_is_zero) {
+ round_up = 0;
+ } else {
+ switch (roundingMode) {
+ case NF_ROUNDINGMODE_CEIL:
+ round_up = is_positive;
+ break;
+ case NF_ROUNDINGMODE_FLOOR:
+ round_up = !is_positive;
+ break;
+ case NF_ROUNDINGMODE_EXPAND:
+ round_up = 1;
+ break;
+ case NF_ROUNDINGMODE_TRUNC:
+ round_up = 0;
+ break;
+ case NF_ROUNDINGMODE_HALFCEIL:
+ if (rem_is_greater) round_up = 1;
+ else if (rem_is_tie) round_up = is_positive;
+ else round_up = 0;
+ break;
+ case NF_ROUNDINGMODE_HALFFLOOR:
+ if (rem_is_greater) round_up = 1;
+ else if (rem_is_tie) round_up = !is_positive;
+ else round_up = 0;
+ break;
+ case NF_ROUNDINGMODE_HALFEXPAND:
+ if (rem_is_greater || rem_is_tie) round_up = 1;
+ else round_up = 0;
+ break;
+ case NF_ROUNDINGMODE_HALFTRUNC:
+ if (rem_is_greater) round_up = 1;
+ else round_up = 0;
+ break;
+ case NF_ROUNDINGMODE_HALFEVEN:
+ if (rem_is_greater) round_up = 1;
+ else if (rem_is_tie) {
+ /* q = floor(scaled_value / M). M = 10^k, q = prefix as integer. */
+ /* Check if prefix is odd */
+ int prefix_odd = 0;
+ if (prefix_len > 0) {
+ /* check last digit of prefix */
+ prefix_odd = (scaled_digits[prefix_len - 1] - '0') & 1;
+ }
+ round_up = prefix_odd;
+ } else {
+ round_up = 0;
+ }
+ break;
+ default:
+ round_up = 0;
+ }
+ }
+ if (round_up) {
+ /* Add 10^k - rem: zero out suffix, increment prefix */
+ char *new_digits;
+ int j2;
+ if (prefix_len == 0) {
+ new_digits = js_malloc(ctx, 2);
+ if (!new_digits) { js_free(ctx, scaled_digits); return -1; }
+ new_digits[0] = '1';
+ new_digits[1] = '\0';
+ } else {
+ new_digits = js_malloc(ctx, (size_t)prefix_len + 1);
+ if (!new_digits) { js_free(ctx, scaled_digits); return -1; }
+ memcpy(new_digits, scaled_digits, (size_t)prefix_len);
+ new_digits[prefix_len] = '\0';
+ for (j2 = prefix_len - 1; j2 >= 0; j2--) {
+ if (new_digits[j2] == '9') {
+ new_digits[j2] = '0';
+ } else {
+ new_digits[j2]++;
+ break;
+ }
+ }
+ if (j2 < 0) {
+ js_free(ctx, new_digits);
+ new_digits = js_malloc(ctx, (size_t)prefix_len + 2);
+ if (!new_digits) { js_free(ctx, scaled_digits); return -1; }
+ new_digits[0] = '1';
+ for (j2 = 0; j2 < prefix_len; j2++)
+ new_digits[j2 + 1] = '0';
+ new_digits[prefix_len + 1] = '\0';
+ }
+ }
+ js_free(ctx, scaled_digits);
+ js_free(ctx, mv->digits);
+ mv->digits = new_digits;
+ mv->num_digits = (int)strlen(new_digits);
+ mv->exponent = -maxFD;
+ } else {
+ char *new_digits;
+ if (prefix_len == 0) {
+ new_digits = js_strdup(ctx, "0");
+ } else {
+ new_digits = js_malloc(ctx, (size_t)prefix_len + 1);
+ if (!new_digits) { js_free(ctx, scaled_digits); return -1; }
+ memcpy(new_digits, scaled_digits, (size_t)prefix_len);
+ new_digits[prefix_len] = '\0';
+ }
+ js_free(ctx, scaled_digits);
+ js_free(ctx, mv->digits);
+ mv->digits = new_digits;
+ mv->num_digits = (int)strlen(new_digits);
+ if (mv->num_digits == 1 && mv->digits[0] == '0')
+ mv->exponent = 0;
+ else
+ mv->exponent = -maxFD;
+ }
+ }
+ return 0;
+ }
+ M *= 10;
+ }
+
+ rem = intl_mv_mod_string(scaled_digits, scaled_len, M);
+
+ if (rem == 0) {
+ round_up = 0;
+ } else {
+ int is_greater, is_tie;
+ /* Safe comparison without overflow */
+ if (M % 2 == 1) {
+ /* M is odd: tie is impossible */
+ is_tie = 0;
+ is_greater = (rem > M / 2);
+ } else {
+ is_tie = (rem == M / 2);
+ is_greater = (rem > M / 2);
+ }
+ switch (roundingMode) {
+ case NF_ROUNDINGMODE_CEIL:
+ round_up = is_positive;
+ break;
+ case NF_ROUNDINGMODE_FLOOR:
+ round_up = !is_positive;
+ break;
+ case NF_ROUNDINGMODE_EXPAND:
+ round_up = 1;
+ break;
+ case NF_ROUNDINGMODE_TRUNC:
+ round_up = 0;
+ break;
+ case NF_ROUNDINGMODE_HALFCEIL:
+ if (is_greater) round_up = 1;
+ else if (is_tie) round_up = is_positive;
+ else round_up = 0;
+ break;
+ case NF_ROUNDINGMODE_HALFFLOOR:
+ if (is_greater) round_up = 1;
+ else if (is_tie) round_up = !is_positive;
+ else round_up = 0;
+ break;
+ case NF_ROUNDINGMODE_HALFEXPAND:
+ if (is_greater || is_tie) round_up = 1;
+ else round_up = 0;
+ break;
+ case NF_ROUNDINGMODE_HALFTRUNC:
+ if (is_greater) round_up = 1;
+ else round_up = 0;
+ break;
+ case NF_ROUNDINGMODE_HALFEVEN:
+ if (is_greater) {
+ round_up = 1;
+ } else if (is_tie) {
+ int q_parity = string_quotient_parity(scaled_digits, scaled_len, M);
+ round_up = q_parity;
+ } else {
+ round_up = 0;
+ }
+ break;
+ default:
+ round_up = 0;
+ }
+ }
+
+ if (round_up) {
+ add_val = M - rem;
+ if (intl_mv_add_small_inplace(scaled_digits, scaled_len, add_val) < 0) {
+ js_free(ctx, scaled_digits);
+ scaled_len++;
+ scaled_digits = js_malloc(ctx, (size_t)scaled_len + 1);
+ if (!scaled_digits) return -1;
+ scaled_digits[0] = '1';
+ for (i = 1; i < scaled_len; i++)
+ scaled_digits[i] = '0';
+ scaled_digits[scaled_len] = '\0';
+ }
+ } else {
+ if (rem > 0) {
+ if (intl_mv_sub_small_inplace(scaled_digits, scaled_len, rem) < 0) {
+ js_free(ctx, scaled_digits);
+ return -1;
+ }
+ }
+ }
+
+ /* Strip leading zeros */
+ i = 0;
+ while (i < scaled_len && scaled_digits[i] == '0') i++;
+ if (i == scaled_len) {
+ js_free(ctx, scaled_digits);
+ js_free(ctx, mv->digits);
+ mv->digits = js_strdup(ctx, "0");
+ mv->num_digits = 1;
+ mv->exponent = -maxFD;
+ return 0;
+ }
+ if (i > 0) {
+ memmove(scaled_digits, scaled_digits + i, (size_t)(scaled_len - i + 1));
+ scaled_len -= i;
+ }
+
+ /* For scale < 0, drop last k zeros (result is multiple of 10^k) */
+ if (k > 0) {
+ scaled_len -= k;
+ scaled_digits[scaled_len] = '\0';
+ }
+
+ js_free(ctx, mv->digits);
+ mv->digits = scaled_digits;
+ mv->num_digits = scaled_len;
+ mv->exponent = -maxFD;
+
+ /* Pad to minimumFractionDigits */
+ {
+ int current_frac = (mv->exponent < 0) ? -mv->exponent : 0;
+ if (current_frac < minFD) {
+ int pad = (int)(minFD - current_frac);
+ int new_len = mv->num_digits + pad;
+ char *new_d = js_malloc(ctx, (size_t)new_len + 1);
+ if (!new_d) return -1;
+ memcpy(new_d, mv->digits, (size_t)mv->num_digits);
+ for (i = 0; i < pad; i++)
+ new_d[mv->num_digits + i] = '0';
+ new_d[new_len] = '\0';
+ js_free(ctx, mv->digits);
+ mv->digits = new_d;
+ mv->num_digits = new_len;
+ mv->exponent = -minFD;
+ }
+ }
+
+ return 0;
+}
+
+/* Round IntlMV to significant-digit constraints.
+ Handles maxSD/minSD and all rounding modes.
+ Returns 0 on success, -1 on error. */
+static int intl_mv_round_significant(JSContext *ctx, IntlMV *mv, int maxSD, int minSD,
+ int roundingMode)
+{
+ int64_t M, rem, add_val;
+ int drop, i, round_up;
+ char *scaled_digits;
+ int scaled_len;
+ int is_positive;
+
+ if (mv->kind != INTL_MV_NORMAL)
+ return 0;
+ if (mv->num_digits == 1 && mv->digits[0] == '0') {
+ /* Zero: pad to minSD if needed */
+ if (minSD > 1) {
+ int pad = (int)(minSD - 1);
+ int new_len = 1 + pad;
+ char *new_d = js_malloc(ctx, (size_t)new_len + 1);
+ if (!new_d) return -1;
+ new_d[0] = '0';
+ for (i = 0; i < pad; i++)
+ new_d[1 + i] = '0';
+ new_d[new_len] = '\0';
+ js_free(ctx, mv->digits);
+ mv->digits = new_d;
+ mv->num_digits = new_len;
+ mv->exponent = -(minSD - 1);
+ }
+ return 0;
+ }
+
+ is_positive = !mv->sign;
+ drop = mv->num_digits - maxSD;
+
+ if (drop <= 0) {
+ /* No rounding needed, but may need to pad for minSD */
+ if (mv->num_digits < minSD) {
+ int pad = (int)(minSD - mv->num_digits);
+ int new_len = mv->num_digits + pad;
+ char *new_d = js_malloc(ctx, (size_t)new_len + 1);
+ if (!new_d) return -1;
+ memcpy(new_d, mv->digits, (size_t)mv->num_digits);
+ for (i = 0; i < pad; i++)
+ new_d[mv->num_digits + i] = '0';
+ new_d[new_len] = '\0';
+ js_free(ctx, mv->digits);
+ mv->digits = new_d;
+ mv->num_digits = new_len;
+ mv->exponent = mv->exponent - pad;
+ }
+ return 0;
+ }
+
+ /* Round the coefficient to nearest multiple of 10^drop */
+ scaled_len = mv->num_digits;
+ scaled_digits = js_strdup(ctx, mv->digits);
+ if (!scaled_digits) return -1;
+
+ M = 1;
+ for (i = 0; i < drop; i++) {
+ if (M > INT64_MAX / 10) {
+ /* M overflows int64_t */
+ int prefix_len = (int)(scaled_len - drop);
+ if (prefix_len <= 0) {
+ js_free(ctx, scaled_digits);
+ js_free(ctx, mv->digits);
+ mv->digits = js_strdup(ctx, "0");
+ mv->num_digits = 1;
+ mv->exponent = 0;
+ return 0;
+ }
+ {
+ const char *rem_start = scaled_digits + prefix_len;
+ int rem_is_zero = 1;
+ int rem_is_greater = 0;
+ int rem_is_tie = 0;
+ int j;
+ for (j = 0; j < drop; j++) {
+ if (rem_start[j] != '0') {
+ rem_is_zero = 0;
+ break;
+ }
+ }
+ if (!rem_is_zero) {
+ if (rem_start[0] > '5') {
+ rem_is_greater = 1;
+ } else if (rem_start[0] < '5') {
+ rem_is_greater = 0;
+ } else {
+ int later_nonzero = 0;
+ for (j = 1; j < drop; j++) {
+ if (rem_start[j] != '0') {
+ later_nonzero = 1;
+ break;
+ }
+ }
+ if (later_nonzero)
+ rem_is_greater = 1;
+ else
+ rem_is_tie = 1;
+ }
+ }
+ if (rem_is_zero) {
+ round_up = 0;
+ } else {
+ switch (roundingMode) {
+ case NF_ROUNDINGMODE_CEIL:
+ round_up = is_positive;
+ break;
+ case NF_ROUNDINGMODE_FLOOR:
+ round_up = !is_positive;
+ break;
+ case NF_ROUNDINGMODE_EXPAND:
+ round_up = 1;
+ break;
+ case NF_ROUNDINGMODE_TRUNC:
+ round_up = 0;
+ break;
+ case NF_ROUNDINGMODE_HALFCEIL:
+ if (rem_is_greater) round_up = 1;
+ else if (rem_is_tie) round_up = is_positive;
+ else round_up = 0;
+ break;
+ case NF_ROUNDINGMODE_HALFFLOOR:
+ if (rem_is_greater) round_up = 1;
+ else if (rem_is_tie) round_up = !is_positive;
+ else round_up = 0;
+ break;
+ case NF_ROUNDINGMODE_HALFEXPAND:
+ if (rem_is_greater || rem_is_tie) round_up = 1;
+ else round_up = 0;
+ break;
+ case NF_ROUNDINGMODE_HALFTRUNC:
+ if (rem_is_greater) round_up = 1;
+ else round_up = 0;
+ break;
+ case NF_ROUNDINGMODE_HALFEVEN:
+ if (rem_is_greater) {
+ round_up = 1;
+ } else if (rem_is_tie) {
+ int prefix_odd = 0;
+ if (prefix_len > 0)
+ prefix_odd = (scaled_digits[prefix_len - 1] - '0') & 1;
+ round_up = prefix_odd;
+ } else {
+ round_up = 0;
+ }
+ break;
+ default:
+ round_up = 0;
+ }
+ }
+ if (round_up) {
+ char *new_digits;
+ int j2;
+ if (prefix_len == 0) {
+ new_digits = js_malloc(ctx, 2);
+ if (!new_digits) { js_free(ctx, scaled_digits); return -1; }
+ new_digits[0] = '1';
+ new_digits[1] = '\0';
+ } else {
+ new_digits = js_malloc(ctx, (size_t)prefix_len + 1);
+ if (!new_digits) { js_free(ctx, scaled_digits); return -1; }
+ memcpy(new_digits, scaled_digits, (size_t)prefix_len);
+ new_digits[prefix_len] = '\0';
+ for (j2 = prefix_len - 1; j2 >= 0; j2--) {
+ if (new_digits[j2] == '9') {
+ new_digits[j2] = '0';
+ } else {
+ new_digits[j2]++;
+ break;
+ }
+ }
+ if (j2 < 0) {
+ js_free(ctx, new_digits);
+ new_digits = js_malloc(ctx, (size_t)prefix_len + 2);
+ if (!new_digits) { js_free(ctx, scaled_digits); return -1; }
+ new_digits[0] = '1';
+ for (j2 = 0; j2 < prefix_len; j2++)
+ new_digits[j2 + 1] = '0';
+ new_digits[prefix_len + 1] = '\0';
+ }
+ }
+ js_free(ctx, scaled_digits);
+ js_free(ctx, mv->digits);
+ mv->digits = new_digits;
+ mv->num_digits = (int)strlen(new_digits);
+ mv->exponent = mv->exponent + drop;
+ } else {
+ char *new_digits;
+ if (prefix_len == 0) {
+ new_digits = js_strdup(ctx, "0");
+ } else {
+ new_digits = js_malloc(ctx, (size_t)prefix_len + 1);
+ if (!new_digits) { js_free(ctx, scaled_digits); return -1; }
+ memcpy(new_digits, scaled_digits, (size_t)prefix_len);
+ new_digits[prefix_len] = '\0';
+ }
+ js_free(ctx, scaled_digits);
+ js_free(ctx, mv->digits);
+ mv->digits = new_digits;
+ mv->num_digits = (int)strlen(new_digits);
+ if (mv->num_digits == 1 && mv->digits[0] == '0')
+ mv->exponent = 0;
+ else
+ mv->exponent = mv->exponent + drop;
+ }
+ }
+ return 0;
+ }
+ M *= 10;
+ }
+
+ rem = intl_mv_mod_string(scaled_digits, scaled_len, M);
+
+ if (rem == 0) {
+ round_up = 0;
+ } else {
+ int is_greater, is_tie;
+ if (M % 2 == 1) {
+ is_tie = 0;
+ is_greater = (rem > M / 2);
+ } else {
+ is_tie = (rem == M / 2);
+ is_greater = (rem > M / 2);
+ }
+ switch (roundingMode) {
+ case NF_ROUNDINGMODE_CEIL:
+ round_up = is_positive;
+ break;
+ case NF_ROUNDINGMODE_FLOOR:
+ round_up = !is_positive;
+ break;
+ case NF_ROUNDINGMODE_EXPAND:
+ round_up = 1;
+ break;
+ case NF_ROUNDINGMODE_TRUNC:
+ round_up = 0;
+ break;
+ case NF_ROUNDINGMODE_HALFCEIL:
+ if (is_greater) round_up = 1;
+ else if (is_tie) round_up = is_positive;
+ else round_up = 0;
+ break;
+ case NF_ROUNDINGMODE_HALFFLOOR:
+ if (is_greater) round_up = 1;
+ else if (is_tie) round_up = !is_positive;
+ else round_up = 0;
+ break;
+ case NF_ROUNDINGMODE_HALFEXPAND:
+ if (is_greater || is_tie) round_up = 1;
+ else round_up = 0;
+ break;
+ case NF_ROUNDINGMODE_HALFTRUNC:
+ if (is_greater) round_up = 1;
+ else round_up = 0;
+ break;
+ case NF_ROUNDINGMODE_HALFEVEN:
+ if (is_greater) {
+ round_up = 1;
+ } else if (is_tie) {
+ int q_parity = string_quotient_parity(scaled_digits, scaled_len, M);
+ round_up = q_parity;
+ } else {
+ round_up = 0;
+ }
+ break;
+ default:
+ round_up = 0;
+ }
+ }
+
+ if (round_up) {
+ add_val = M - rem;
+ if (intl_mv_add_small_inplace(scaled_digits, scaled_len, add_val) < 0) {
+ js_free(ctx, scaled_digits);
+ scaled_len++;
+ scaled_digits = js_malloc(ctx, (size_t)scaled_len + 1);
+ if (!scaled_digits) return -1;
+ scaled_digits[0] = '1';
+ for (i = 1; i < scaled_len; i++)
+ scaled_digits[i] = '0';
+ scaled_digits[scaled_len] = '\0';
+ }
+ } else {
+ if (rem > 0) {
+ if (intl_mv_sub_small_inplace(scaled_digits, scaled_len, rem) < 0) {
+ js_free(ctx, scaled_digits);
+ return -1;
+ }
+ }
+ }
+
+ /* Strip leading zeros */
+ i = 0;
+ while (i < scaled_len && scaled_digits[i] == '0') i++;
+ if (i == scaled_len) {
+ js_free(ctx, scaled_digits);
+ js_free(ctx, mv->digits);
+ mv->digits = js_strdup(ctx, "0");
+ mv->num_digits = 1;
+ mv->exponent = 0;
+ return 0;
+ }
+ if (i > 0) {
+ memmove(scaled_digits, scaled_digits + i, (size_t)(scaled_len - i + 1));
+ scaled_len -= i;
+ }
+
+ /* Drop the last 'drop' zeros */
+ scaled_len -= drop;
+ scaled_digits[scaled_len] = '\0';
+
+ js_free(ctx, mv->digits);
+ mv->digits = scaled_digits;
+ mv->num_digits = scaled_len;
+ mv->exponent = mv->exponent + drop;
+
+ /* Pad to minimumSignificantDigits */
+ if (mv->num_digits < minSD) {
+ int pad = (int)(minSD - mv->num_digits);
+ int new_len = mv->num_digits + pad;
+ char *new_d = js_malloc(ctx, (size_t)new_len + 1);
+ if (!new_d) return -1;
+ memcpy(new_d, mv->digits, (size_t)mv->num_digits);
+ for (i = 0; i < pad; i++)
+ new_d[mv->num_digits + i] = '0';
+ new_d[new_len] = '\0';
+ js_free(ctx, mv->digits);
+ mv->digits = new_d;
+ mv->num_digits = new_len;
+ }
+
+ return 0;
+}
+
+/* ---- data struct ---- */
+
+typedef struct JSNumberFormatData {
+ char *locale;
+ char *locale_canonical;
+ int numberingSystem;
+ int has_numberingSystem_option;
+ int style;
+ char *currency;
+ int currencyDisplay;
+ int currencySign;
+ char *unit;
+ int unitDisplay;
+ int minimumIntegerDigits;
+ int minimumFractionDigits;
+ int maximumFractionDigits;
+ int minimumSignificantDigits;
+ int maximumSignificantDigits;
+ int hasMinimumSignificantDigits;
+ int hasMaximumSignificantDigits;
+ int useGrouping;
+ int notation;
+ int compactDisplay; /* -1 = unset */
+ int signDisplay;
+ int roundingMode;
+ int roundingPriority;
+ int roundingIncrement;
+ int trailingZeroDisplay;
+} JSNumberFormatData;
+
+static void js_numberformat_finalizer(JSRuntime *rt, JSValue val)
+{
+ JSNumberFormatData *s = JS_GetOpaque(val, js_numberformat_class_id);
+ if (s) {
+ js_free_rt(rt, s->locale);
+ js_free_rt(rt, s->locale_canonical);
+ js_free_rt(rt, s->currency);
+ js_free_rt(rt, s->unit);
+ js_free_rt(rt, s);
+ }
+}
+
+static JSClassDef js_numberformat_class = {
+ "NumberFormat",
+ .finalizer = js_numberformat_finalizer,
+};
+
+/* UnwrapNumberFormat: handle fallback symbol for cross-realm objects */
+static JSValue js_numberformat_unwrap(JSContext *ctx, JSValueConst this_val)
+{
+ JSNumberFormatData *s;
+ JSValue ctor, sym, unwrapped;
+ int is_instance;
+
+ if (!JS_IsObject(this_val))
+ return JS_ThrowTypeError(ctx, "NumberFormat object expected");
+
+ s = JS_GetOpaque(this_val, js_numberformat_class_id);
+ if (s)
+ return JS_DupValue(ctx, this_val);
+
+ /* No internal slot; check if it's an instance of NumberFormat */
+ ctor = JS_GetContextValue(ctx, JS_INTL_CTOR_NUMBERFORMAT);
+ is_instance = JS_OrdinaryIsInstanceOf(ctx, this_val, ctor);
+ JS_FreeValue(ctx, ctor);
+ if (is_instance < 0)
+ return JS_EXCEPTION;
+ if (!is_instance)
+ return JS_ThrowTypeError(ctx, "NumberFormat object expected");
+
+ /* Return the fallback symbol value */
+ sym = JS_GetContextValue(ctx, JS_INTL_FALLBACK_SYMBOL);
+ if (JS_IsException(sym))
+ return sym;
+ {
+ JSAtom sym_atom = JS_ValueToAtom(ctx, sym);
+ unwrapped = JS_GetProperty(ctx, this_val, sym_atom);
+ JS_FreeAtom(ctx, sym_atom);
+ }
+ JS_FreeValue(ctx, sym);
+ return unwrapped;
+}
+
+/* Helper: read number option with range validation */
+JSValue js_numberformat_constructor(JSContext *ctx,
+ JSValueConst func_obj,
+ JSValueConst this_val,
+ int argc, JSValueConst *argv,
+ int flags)
+{
+
+ JSNumberFormatData *s;
+ JSValue obj = JS_UNDEFINED;
+ JSValue options = JS_UNDEFINED;
+ JSValueConst new_target;
+ int is_new;
+
+ is_new = (flags & JS_CALL_FLAG_CONSTRUCTOR) != 0;
+
+ if (is_new) {
+ new_target = this_val;
+ } else {
+ /* Function call: implement ChainNumberFormat */
+ new_target = func_obj;
+ }
+
+ s = js_mallocz(ctx, sizeof(*s));
+ if (!s)
+ return JS_EXCEPTION;
+
+ /* defaults */
+ s->locale = js_strdup(ctx, "en-US");
+ s->numberingSystem = NS_LATN;
+ s->style = NF_STYLE_DECIMAL;
+ s->currencyDisplay = NF_CURRENCYDISPLAY_SYMBOL;
+ s->currencySign = NF_CURRENCYSIGN_STANDARD;
+ s->unitDisplay = NF_UNITDISPLAY_SHORT;
+ s->minimumIntegerDigits = 1;
+ s->minimumFractionDigits = 0;
+ s->maximumFractionDigits = 3;
+ s->minimumSignificantDigits = 1;
+ s->maximumSignificantDigits = 21;
+ s->hasMinimumSignificantDigits = 0;
+ s->hasMaximumSignificantDigits = 0;
+ s->useGrouping = NF_GROUPING_AUTO;
+ s->notation = NF_NOTATION_STANDARD;
+ s->signDisplay = NF_SIGNDISPLAY_AUTO;
+ s->roundingMode = NF_ROUNDINGMODE_HALFEXPAND;
+ s->roundingPriority = NF_ROUNDINGPRIORITY_AUTO;
+ s->roundingIncrement = 1;
+ s->trailingZeroDisplay = NF_TRAILINGZERO_AUTO;
+ s->compactDisplay = NF_COMPACT_UNSET;
+
+ {
+ char *canonical = NULL;
+ if (js_canonicalizeLocaleList_first(ctx, argc > 0 ? argv[0] : JS_UNDEFINED, &canonical) < 0)
+ goto fail;
+ s->locale_canonical = canonical;
+ if (canonical) {
+ char *ns_str = js_intl_locale_get_numbering_system(ctx, canonical);
+ if (ns_str) {
+ int ns = js_intl_string_to_numbering_system(ns_str);
+ if (ns != NS_UNKNOWN)
+ s->numberingSystem = ns;
+ js_free(ctx, ns_str);
+ }
+ {
+ char *stripped = js_intl_strip_unicode_extensions(ctx, canonical);
+ if (stripped) {
+ js_free(ctx, s->locale);
+ s->locale = stripped;
+ }
+ }
+ }
+ }
+
+ /* parse options */
+ if (argc > 1 && !JS_IsUndefined(argv[1])) {
+ options = JS_ToObject(ctx, argv[1]);
+ if (JS_IsException(options))
+ goto fail;
+
+ /* ResolveOptions reads: localeMatcher, numberingSystem */
+ {
+ int idx = js_intl_get_string_option(ctx, options, "localeMatcher",
+ intl_localeMatcher_names,
+ countof(intl_localeMatcher_names),
+ INTL_LOCALEMATCHER_BESTFIT);
+ if (idx < 0)
+ goto fail;
+ }
+
+ {
+ JSValue ns_val = JS_GetPropertyStr(ctx, options, "numberingSystem");
+ if (JS_IsException(ns_val))
+ goto fail;
+ if (!JS_IsUndefined(ns_val)) {
+ const char *ns_str = JS_ToCString(ctx, ns_val);
+ JS_FreeValue(ctx, ns_val);
+ if (ns_str) {
+ int valid = 1;
+ int len = (int)strlen(ns_str);
+ int i = 0;
+ if (len == 0) valid = 0;
+ while (i < len && valid) {
+ int seg_len = 0;
+ while (i < len && ns_str[i] != '-') {
+ if (!isalnum((unsigned char)ns_str[i])) {
+ valid = 0;
+ break;
+ }
+ seg_len++;
+ i++;
+ }
+ if (seg_len < 3 || seg_len > 8) valid = 0;
+ if (i < len && ns_str[i] == '-') {
+ i++;
+ if (i >= len) valid = 0;
+ }
+ }
+ if (!valid) {
+ JS_FreeCString(ctx, ns_str);
+ JS_ThrowRangeError(ctx, "invalid numberingSystem option");
+ goto fail;
+ }
+ {
+ int ns = js_intl_string_to_numbering_system(ns_str);
+ if (ns != NS_UNKNOWN) {
+ s->has_numberingSystem_option = 1;
+ s->numberingSystem = ns;
+ }
+ }
+ JS_FreeCString(ctx, ns_str);
+ }
+ }
+ }
+
+ /* SetNumberFormatUnitOptions order: style, currency, currencyDisplay, currencySign, unit, unitDisplay */
+ {
+ int idx = js_intl_get_string_option(ctx, options, "style",
+ nf_style_names,
+ countof(nf_style_names),
+ NF_STYLE_DECIMAL);
+ if (idx < 0)
+ goto fail;
+ s->style = idx;
+ }
+
+ {
+ JSValue currency_val = JS_GetPropertyStr(ctx, options, "currency");
+ if (JS_IsException(currency_val))
+ goto fail;
+ if (!JS_IsUndefined(currency_val)) {
+ size_t slen;
+ const char *currency_str = JS_ToCStringLen(ctx, &slen, currency_val);
+ JS_FreeValue(ctx, currency_val);
+ if (currency_str) {
+ if (slen == 3 && strlen(currency_str) == slen &&
+ isalpha((unsigned char)currency_str[0]) &&
+ isalpha((unsigned char)currency_str[1]) &&
+ isalpha((unsigned char)currency_str[2])) {
+ char upper_currency[4];
+ upper_currency[0] = (char)toupper((unsigned char)currency_str[0]);
+ upper_currency[1] = (char)toupper((unsigned char)currency_str[1]);
+ upper_currency[2] = (char)toupper((unsigned char)currency_str[2]);
+ upper_currency[3] = '\0';
+ js_free(ctx, s->currency);
+ s->currency = js_strdup(ctx, upper_currency);
+ JS_FreeCString(ctx, currency_str);
+ } else {
+ JS_FreeCString(ctx, currency_str);
+ JS_ThrowRangeError(ctx, "invalid currency code");
+ goto fail;
+ }
+ }
+ }
+ }
+
+ {
+ int idx = js_intl_get_string_option(ctx, options, "currencyDisplay",
+ nf_currencydisplay_names,
+ countof(nf_currencydisplay_names),
+ NF_CURRENCYDISPLAY_SYMBOL);
+ if (idx < 0)
+ goto fail;
+ s->currencyDisplay = idx;
+ }
+
+ {
+ int idx = js_intl_get_string_option(ctx, options, "currencySign",
+ nf_currencysign_names,
+ countof(nf_currencysign_names),
+ NF_CURRENCYSIGN_STANDARD);
+ if (idx < 0)
+ goto fail;
+ s->currencySign = idx;
+ }
+
+ /* Validate currency is present when style is currency */
+ if (s->style == NF_STYLE_CURRENCY && !s->currency) {
+ JS_ThrowTypeError(ctx, "currency option is required when style is currency");
+ goto fail;
+ }
+
+ /* Only store currency when style is currency */
+ if (s->style != NF_STYLE_CURRENCY) {
+ js_free(ctx, s->currency);
+ s->currency = NULL;
+ }
+
+ {
+ JSValue unit_val = JS_GetPropertyStr(ctx, options, "unit");
+ if (JS_IsException(unit_val))
+ goto fail;
+ if (!JS_IsUndefined(unit_val)) {
+ const char *unit_str = JS_ToCString(ctx, unit_val);
+ JS_FreeValue(ctx, unit_val);
+ if (unit_str) {
+ js_free(ctx, s->unit);
+ s->unit = js_strdup(ctx, unit_str);
+ JS_FreeCString(ctx, unit_str);
+ }
+ }
+ }
+
+ /* Validate unit is present when style is unit, and well-formed */
+ if (s->style == NF_STYLE_UNIT && !s->unit) {
+ JS_ThrowTypeError(ctx, "unit option is required when style is unit");
+ goto fail;
+ }
+ if (s->unit && !is_well_formed_unit_identifier(s->unit)) {
+ JS_ThrowRangeError(ctx, "invalid unit identifier");
+ goto fail;
+ }
+
+ {
+ int idx = js_intl_get_string_option(ctx, options, "unitDisplay",
+ nf_unitdisplay_names,
+ countof(nf_unitdisplay_names),
+ NF_UNITDISPLAY_SHORT);
+ if (idx < 0)
+ goto fail;
+ s->unitDisplay = idx;
+ }
+
+ /* notation */
+ {
+ int idx = js_intl_get_string_option(ctx, options, "notation",
+ nf_notation_names,
+ countof(nf_notation_names),
+ NF_NOTATION_STANDARD);
+ if (idx < 0)
+ goto fail;
+ s->notation = idx;
+ }
+
+ /* Default fraction digits for currency and percent styles */
+ int default_mnfd = s->minimumFractionDigits;
+ int default_mxfd = s->maximumFractionDigits;
+
+ if (s->style == NF_STYLE_CURRENCY && s->currency) {
+ if (s->notation == NF_NOTATION_STANDARD) {
+ int digits = js_intl_get_currency_digits(s->currency);
+ default_mnfd = digits;
+ default_mxfd = digits;
+ } else {
+ default_mnfd = 0;
+ if (s->notation == NF_NOTATION_COMPACT)
+ default_mxfd = 0;
+ else
+ default_mxfd = 3;
+ }
+ } else if (s->style == NF_STYLE_PERCENT) {
+ default_mnfd = 0;
+ default_mxfd = 0;
+ }
+
+ s->minimumFractionDigits = default_mnfd;
+ s->maximumFractionDigits = default_mxfd;
+
+ /* SetNumberFormatDigitOptions order: mnid, mnfd, mxfd, mnsd, mxsd, roundingIncrement, roundingMode, roundingPriority, trailingZeroDisplay */
+ {
+ int v, ret;
+ int has_mnfd = 0, has_mxfd = 0;
+ ret = js_intl_get_number_option(ctx, options, "minimumIntegerDigits", &v, 1, 21);
+ if (ret < 0) goto fail;
+ if (ret > 0) s->minimumIntegerDigits = v;
+
+ ret = js_intl_get_number_option(ctx, options, "minimumFractionDigits", &v, 0, 100);
+ if (ret < 0) goto fail;
+ if (ret > 0) {
+ s->minimumFractionDigits = v;
+ has_mnfd = 1;
+ }
+
+ ret = js_intl_get_number_option(ctx, options, "maximumFractionDigits", &v, 0, 100);
+ if (ret < 0) goto fail;
+ if (ret > 0) {
+ s->maximumFractionDigits = v;
+ has_mxfd = 1;
+ }
+
+ /* Apply spec adjustment when only one of mnfd/mxfd is provided */
+ if (has_mxfd && !has_mnfd) {
+ s->minimumFractionDigits = s->maximumFractionDigits < default_mnfd ? s->maximumFractionDigits : default_mnfd;
+ } else if (has_mnfd && !has_mxfd) {
+ s->maximumFractionDigits = s->minimumFractionDigits > default_mxfd ? s->minimumFractionDigits : default_mxfd;
+ }
+
+ ret = js_intl_get_number_option(ctx, options, "minimumSignificantDigits", &v, 1, 21);
+ if (ret < 0) goto fail;
+ if (ret > 0) {
+ s->minimumSignificantDigits = v;
+ s->hasMinimumSignificantDigits = 1;
+ }
+
+ ret = js_intl_get_number_option(ctx, options, "maximumSignificantDigits", &v, 1, 21);
+ if (ret < 0) goto fail;
+ if (ret > 0) {
+ s->maximumSignificantDigits = v;
+ s->hasMaximumSignificantDigits = 1;
+ }
+
+ /* If either significant digits option is set, apply defaults and validate */
+ if (s->hasMinimumSignificantDigits || s->hasMaximumSignificantDigits) {
+ int mnsd = s->hasMinimumSignificantDigits ? s->minimumSignificantDigits : 1;
+ int mxsd = s->hasMaximumSignificantDigits ? s->maximumSignificantDigits : 21;
+ if (mxsd < mnsd) {
+ JS_ThrowRangeError(ctx, "maximumSignificantDigits must be >= minimumSignificantDigits");
+ goto fail;
+ }
+ s->minimumSignificantDigits = mnsd;
+ s->maximumSignificantDigits = mxsd;
+ }
+
+ ret = js_intl_get_number_option(ctx, options, "roundingIncrement", &v, 1, 5000);
+ if (ret < 0) goto fail;
+ if (ret > 0) {
+ static const int valid_increments[] = {1, 2, 5, 10, 20, 25, 50, 100, 200, 250, 500, 1000, 2000, 2500, 5000};
+ int valid = 0;
+ int j;
+ for (j = 0; j < 15; j++) {
+ if (valid_increments[j] == v) {
+ valid = 1;
+ break;
+ }
+ }
+ if (!valid) {
+ JS_ThrowRangeError(ctx, "roundingIncrement out of range");
+ goto fail;
+ }
+ s->roundingIncrement = v;
+ }
+
+ ret = js_intl_get_string_option(ctx, options, "roundingMode",
+ nf_roundingmode_names,
+ countof(nf_roundingmode_names),
+ NF_ROUNDINGMODE_HALFEXPAND);
+ if (ret < 0) goto fail;
+ s->roundingMode = ret;
+
+ ret = js_intl_get_string_option(ctx, options, "roundingPriority",
+ nf_roundingpriority_names,
+ countof(nf_roundingpriority_names),
+ NF_ROUNDINGPRIORITY_AUTO);
+ if (ret < 0) goto fail;
+ s->roundingPriority = ret;
+
+ /* Validate roundingIncrement constraints */
+ if (s->roundingIncrement > 1) {
+ if (s->roundingPriority != NF_ROUNDINGPRIORITY_AUTO) {
+ JS_ThrowTypeError(ctx, "roundingIncrement cannot be used with morePrecision or lessPrecision");
+ goto fail;
+ }
+ if (s->hasMinimumSignificantDigits || s->hasMaximumSignificantDigits) {
+ JS_ThrowTypeError(ctx, "roundingIncrement cannot be used with significant digits");
+ goto fail;
+ }
+ if (s->maximumFractionDigits != s->minimumFractionDigits) {
+ JS_ThrowRangeError(ctx, "maximumFractionDigits must equal minimumFractionDigits when roundingIncrement is used");
+ goto fail;
+ }
+ }
+
+ ret = js_intl_get_string_option(ctx, options, "trailingZeroDisplay",
+ nf_trailingzero_names,
+ countof(nf_trailingzero_names),
+ NF_TRAILINGZERO_AUTO);
+ if (ret < 0) goto fail;
+ s->trailingZeroDisplay = ret;
+
+ /* Compact notation default digit options per SetNumberFormatDigitOptions */
+ if (s->notation == NF_NOTATION_COMPACT &&
+ s->roundingPriority == NF_ROUNDINGPRIORITY_AUTO &&
+ !s->hasMinimumSignificantDigits && !s->hasMaximumSignificantDigits &&
+ !has_mnfd && !has_mxfd) {
+ s->minimumFractionDigits = 0;
+ s->maximumFractionDigits = 0;
+ s->minimumSignificantDigits = 1;
+ s->maximumSignificantDigits = 2;
+ s->roundingPriority = NF_ROUNDINGPRIORITY_MOREPRECISION;
+ }
+ }
+
+ /* Back to constructor: compactDisplay, useGrouping, signDisplay */
+ {
+ int idx = js_intl_get_string_option(ctx, options, "compactDisplay",
+ nf_compact_names,
+ countof(nf_compact_names),
+ NF_COMPACT_UNSET);
+ if (idx < 0)
+ goto fail;
+ s->compactDisplay = idx;
+ }
+
+ /* useGrouping: GetBooleanOrStringNumberFormatOption */
+ {
+ static const char *ug_string_values[] = {"min2", "auto", "always", "true", "false"};
+ JSValue v = JS_GetPropertyStr(ctx, options, "useGrouping");
+ if (JS_IsException(v))
+ goto fail;
+ if (JS_IsUndefined(v)) {
+ JS_FreeValue(ctx, v);
+ s->useGrouping = (s->notation == NF_NOTATION_COMPACT) ? NF_GROUPING_MIN2 : NF_GROUPING_AUTO;
+ } else if (JS_IsBool(v) && JS_ToBool(ctx, v)) {
+ JS_FreeValue(ctx, v);
+ s->useGrouping = NF_GROUPING_ALWAYS;
+ } else if (JS_ToBool(ctx, v) == 0) {
+ JS_FreeValue(ctx, v);
+ s->useGrouping = NF_GROUPING_FALSE_BOOL;
+ } else {
+ {
+ int i, found = 0;
+ const char *str = JS_ToCString(ctx, v);
+ JS_FreeValue(ctx, v);
+ if (!str)
+ goto fail;
+ for (i = 0; i < 5; i++) {
+ if (!strcmp(str, ug_string_values[i])) {
+ found = 1;
+ break;
+ }
+ }
+ JS_FreeCString(ctx, str);
+ if (!found) {
+ JS_ThrowRangeError(ctx, "invalid useGrouping option");
+ goto fail;
+ }
+ if (i == 3 || i == 4) { /* "true" or "false" -> fallback */
+ s->useGrouping = (s->notation == NF_NOTATION_COMPACT) ? NF_GROUPING_MIN2 : NF_GROUPING_AUTO;
+ } else if (i == 0) {
+ s->useGrouping = NF_GROUPING_MIN2;
+ } else if (i == 1) {
+ s->useGrouping = NF_GROUPING_AUTO;
+ } else {
+ s->useGrouping = NF_GROUPING_ALWAYS;
+ }
+ }
+ }
+ }
+
+ {
+ int idx = js_intl_get_string_option(ctx, options, "signDisplay",
+ nf_signdisplay_names,
+ countof(nf_signdisplay_names),
+ NF_SIGNDISPLAY_AUTO);
+ if (idx < 0)
+ goto fail;
+ s->signDisplay = idx;
+ }
+
+ JS_FreeValue(ctx, options);
+ options = JS_UNDEFINED;
+ }
+
+ /* compactDisplay defaults to "short" when notation is compact */
+ if (s->notation == NF_NOTATION_COMPACT && s->compactDisplay == NF_COMPACT_UNSET)
+ s->compactDisplay = NF_COMPACT_SHORT;
+
+ /* currency style must have currency option */
+ if (s->style == NF_STYLE_CURRENCY && !s->currency) {
+ JS_ThrowTypeError(ctx, "currency code is required with currency style");
+ goto fail;
+ }
+
+ /* Rebuild locale with preserved Unicode extensions */
+ if (s->locale_canonical) {
+ int preserve_nu = 0;
+
+ if (js_intl_locale_has_key(s->locale_canonical, "nu")) {
+ char *ext_val = js_intl_locale_get_unicode_key(ctx, s->locale_canonical, "nu");
+ if (ext_val) {
+ int ext_ns = js_intl_string_to_numbering_system(ext_val);
+ if (!s->has_numberingSystem_option || ext_ns == s->numberingSystem)
+ preserve_nu = 1;
+ js_free(ctx, ext_val);
+ }
+ }
+
+ if (preserve_nu) {
+ DynBuf db;
+ js_intl_dbuf_init(ctx, &db);
+ dbuf_putstr(&db, s->locale);
+ dbuf_put(&db, (uint8_t *)"-u", (size_t)2);
+ {
+ char *v = js_intl_locale_get_unicode_key(ctx, s->locale_canonical, "nu");
+ if (v) {
+ dbuf_put(&db, (uint8_t *)"-nu-", (size_t)4);
+ dbuf_putstr(&db, v);
+ js_free(ctx, v);
+ }
+ }
+ dbuf_put(&db, (uint8_t *)"", (size_t)1);
+ if (dbuf_error(&db)) {
+ dbuf_free(&db);
+ return JS_EXCEPTION;
+ }
+ js_free(ctx, s->locale);
+ s->locale = js_strdup(ctx, (char *)db.buf);
+ dbuf_free(&db);
+ }
+ }
+
+ obj = JS_CreateFromConstructor(ctx, new_target, js_numberformat_class_id);
+ if (JS_IsException(obj))
+ goto fail;
+ JS_SetOpaque(obj, s);
+
+ if (!is_new) {
+ /* ChainNumberFormat: if this is a NumberFormat instance, define fallback symbol */
+ JSValue ctor = JS_GetContextValue(ctx, JS_INTL_CTOR_NUMBERFORMAT);
+ int is_instance = JS_OrdinaryIsInstanceOf(ctx, this_val, ctor);
+ JS_FreeValue(ctx, ctor);
+ if (is_instance < 0) {
+ JS_FreeValue(ctx, obj);
+ return JS_EXCEPTION;
+ }
+ if (is_instance) {
+ JSValue sym = JS_GetContextValue(ctx, JS_INTL_FALLBACK_SYMBOL);
+ if (JS_IsException(sym)) {
+ JS_FreeValue(ctx, obj);
+ return JS_EXCEPTION;
+ }
+ if (!JS_IsUndefined(sym)) {
+ JSAtom sym_atom = JS_ValueToAtom(ctx, sym);
+ JS_DefinePropertyValue(ctx, this_val, sym_atom, JS_DupValue(ctx, obj), 0);
+ JS_FreeAtom(ctx, sym_atom);
+ }
+ JS_FreeValue(ctx, sym);
+ JS_FreeValue(ctx, obj);
+ return JS_DupValue(ctx, this_val);
+ }
+ }
+ return obj;
+ fail:
+ JS_FreeValue(ctx, options);
+ if (s->locale) js_free(ctx, s->locale);
+ if (s->locale_canonical) js_free(ctx, s->locale_canonical);
+ if (s->currency) js_free(ctx, s->currency);
+ if (s->unit) js_free(ctx, s->unit);
+ js_free(ctx, s);
+ JS_FreeValue(ctx, obj);
+ return JS_EXCEPTION;
+}
+
+/* Helper: format integer part with grouping */
+
+typedef struct {
+ const char *locale_prefix;
+ const char *unit;
+ const char *short_pattern;
+ const char *short_singular;
+ const char *narrow_pattern;
+ const char *narrow_singular;
+ const char *long_pattern;
+ const char *long_singular;
+} UnitPatternEntry;
+
+static const UnitPatternEntry unit_patterns[] = {
+ {"en", "percent", "{number}%", NULL, "{number}%", NULL, "{number} percent", NULL},
+ {"en", "kilometer-per-hour", "{number} km/h", NULL, "{number}km/h", NULL, "{number} kilometers per hour", NULL},
+ {"en", "day", "{number} days", "{number} day", "{number}d", NULL, "{number} days", "{number} day"},
+ {"en", "hour", "{number} hr", NULL, "{number}h", NULL, "{number} hours", "{number} hour"},
+ {"en", "minute", "{number} min", NULL, "{number}m", NULL, "{number} minutes", "{number} minute"},
+ {"en", "second", "{number} sec", NULL, "{number}s", NULL, "{number} seconds", "{number} second"},
+ {"en", "week", "{number} wks", "{number} wk", "{number}w", NULL, "{number} weeks", "{number} week"},
+ {"en", "month", "{number} mths", "{number} mth", "{number}m", NULL, "{number} months", "{number} month"},
+ {"en", "year", "{number} yrs", "{number} yr", "{number}y", NULL, "{number} years", "{number} year"},
+ {"en-GB", "hour", "{number} hr", NULL, "{number}h", NULL, "{number} hours", "{number} hour"},
+ {"en-GB", "minute", "{number} mins", "{number} min", "{number}m", NULL, "{number} minutes", "{number} minute"},
+ {"en-GB", "second", "{number} secs", "{number} sec", "{number}s", NULL, "{number} seconds", "{number} second"},
+ {"de", "kilometer-per-hour", "{number} km/h", NULL, "{number} km/h", NULL, "{number} Kilometer pro Stunde", NULL},
+ {"de", "hour", "{number} Std.", NULL, "{number}h", NULL, "{number} Stunden", "{number} Stunde"},
+ {"de", "minute", "{number} Min.", NULL, "{number} Min.", NULL, "{number} Minuten", "{number} Minute"},
+ {"de", "second", "{number} Sek.", NULL, "{number} Sek.", NULL, "{number} Sekunden", "{number} Sekunde"},
+ {"ja", "kilometer-per-hour", "{number} km/h", NULL, "{number}km/h", NULL, "時速 {number} キロメートル", NULL},
+ {"ja", "hour", "{number} 時間", NULL, "{number}h", NULL, "{number} 時間", NULL},
+ {"ja", "minute", "{number} 分", NULL, "{number}m", NULL, "{number} 分", NULL},
+ {"ja", "second", "{number} 秒", NULL, "{number}s", NULL, "{number} 秒", NULL},
+ {"ko", "kilometer-per-hour", "{number}km/h", NULL, "{number}km/h", NULL, "시속 {number}킬로미터", NULL},
+ {"zh", "kilometer-per-hour", "{number} 公里/小時", NULL, "{number}公里/小時", NULL, "每小時 {number} 公里", NULL},
+ {"zh", "hour", "{number}小时", NULL, "{number}h", NULL, "{number}小时", NULL},
+ {"zh", "minute", "{number}分钟", NULL, "{number}m", NULL, "{number}分钟", NULL},
+ {"zh", "second", "{number}秒", NULL, "{number}s", NULL, "{number}秒", NULL},
+ {"zh-Hant", "hour", "{number} 小時", NULL, "{number}h", NULL, "{number} 小時", NULL},
+ {"zh-Hant", "minute", "{number} 分鐘", NULL, "{number}m", NULL, "{number} 分鐘", NULL},
+ {"zh-Hant", "second", "{number} 秒", NULL, "{number}s", NULL, "{number} 秒", NULL},
+};
+
+static int unit_value_is_one(const IntlMV *mv)
+{
+ int i;
+ if (mv->num_digits == 0)
+ return 0;
+ if (mv->digits[0] != '1')
+ return 0;
+ for (i = 1; i < mv->num_digits; i++) {
+ if (mv->digits[i] != '0')
+ return 0;
+ }
+ return mv->exponent + mv->num_digits - 1 == 0;
+}
+
+static const char *get_unit_pattern(const UnitPatternEntry *e, int unitDisplay, int is_one)
+{
+ const char *pat;
+ if (unitDisplay == NF_UNITDISPLAY_NARROW) {
+ pat = is_one && e->narrow_singular ? e->narrow_singular : e->narrow_pattern;
+ } else if (unitDisplay == NF_UNITDISPLAY_LONG) {
+ pat = is_one && e->long_singular ? e->long_singular : e->long_pattern;
+ } else {
+ pat = is_one && e->short_singular ? e->short_singular : e->short_pattern;
+ }
+ return pat;
+}
+
+static const UnitPatternEntry *find_unit_pattern(const char *locale, const char *unit)
+{
+ int i;
+ int locale_len = (int)strlen(locale);
+ /* First pass: exact match */
+ for (i = 0; i < (int)countof(unit_patterns); i++) {
+ const UnitPatternEntry *e = &unit_patterns[i];
+ if (!strcmp(locale, e->locale_prefix) && !strcmp(unit, e->unit))
+ return e;
+ }
+ /* Second pass: prefix match (only if remainder is '\0' or '-') */
+ for (i = 0; i < (int)countof(unit_patterns); i++) {
+ const UnitPatternEntry *e = &unit_patterns[i];
+ int prefix_len = (int)strlen(e->locale_prefix);
+ if (locale_len >= prefix_len && !memcmp(locale, e->locale_prefix, (size_t)prefix_len) &&
+ !strcmp(unit, e->unit)) {
+ char next = locale[prefix_len];
+ if (next == '\0' || next == '-')
+ return e;
+ }
+ }
+ return NULL;
+}
+
+static JSValue nf_finish_with_digits(JSContext *ctx, DynBuf *db, int numberingSystem)
+{
+ char *new_buf;
+ int i, j;
+ int len;
+ JSValue ret;
+
+ if (dbuf_error(db)) {
+ dbuf_free(db);
+ return JS_EXCEPTION;
+ }
+
+ if (numberingSystem == NS_LATN) {
+ ret = JS_NewString(ctx, (char *)db->buf);
+ dbuf_free(db);
+ return ret;
+ }
+
+ len = (int)db->size - 1; /* exclude '\0' */
+ new_buf = js_malloc(ctx, (size_t)(len * 4 + 1));
+ if (!new_buf) {
+ dbuf_free(db);
+ return JS_EXCEPTION;
+ }
+
+ j = 0;
+ for (i = 0; i < len; i++) {
+ unsigned char c = db->buf[i];
+ if (c >= '0' && c <= '9') {
+ uint32_t cp = nf_get_digit(numberingSystem, c - '0');
+ if (cp != 0) {
+ j += unicode_to_utf8((uint8_t *)new_buf + j, cp);
+ } else {
+ new_buf[j++] = (char)c;
+ }
+ } else {
+ new_buf[j++] = (char)c;
+ }
+ }
+ new_buf[j] = '\0';
+ dbuf_free(db);
+ ret = JS_NewString(ctx, new_buf);
+ js_free(ctx, new_buf);
+ return ret;
+}
+
+static void add_grouping(DynBuf *db, const char *digits, int len, const char *group_sep, int min2,
+ int group_size1, int group_size2)
+{
+ int first_group;
+ int i;
+ int remaining = len;
+ int groups[20];
+ int num_groups = 0;
+ int gi;
+
+ /* Determine group boundaries from right to left */
+ if (remaining > 0) {
+ int gs1 = group_size1 > 0 ? group_size1 : 3;
+ int gs2 = group_size2 > 0 ? group_size2 : gs1;
+ int first = remaining > gs1 ? gs1 : remaining;
+ groups[num_groups++] = first;
+ remaining -= first;
+ while (remaining > 0) {
+ int g = remaining > gs2 ? gs2 : remaining;
+ groups[num_groups++] = g;
+ remaining -= g;
+ }
+ }
+
+ if (num_groups == 0) {
+ dbuf_put(db, (const uint8_t *)digits, (size_t)len);
+ return;
+ }
+
+ /* The most significant group is at the end of groups[] */
+ first_group = groups[num_groups - 1];
+
+ if (min2 && num_groups == 2 && first_group < 2) {
+ /* min2: don't group if there are exactly 2 groups and the most significant group has < 2 digits */
+ dbuf_put(db, (const uint8_t *)digits, (size_t)len);
+ return;
+ }
+
+ /* Output groups from left to right */
+ i = 0;
+ for (gi = num_groups - 1; gi >= 0; gi--) {
+ if (gi < num_groups - 1)
+ dbuf_putstr(db, group_sep);
+ dbuf_put(db, (const uint8_t *)digits + i, (size_t)groups[gi]);
+ i += groups[gi];
+ }
+}
+
+static void nf_add_part(JSContext *ctx, JSValue parts, const char *type, const char *value)
+{
+ JSValue part;
+ int32_t len = 0;
+ JSValue lv;
+
+ if (JS_IsUndefined(parts))
+ return;
+
+ part = JS_NewObject(ctx);
+ if (JS_IsException(part))
+ return;
+ JS_SetPropertyStr(ctx, part, "type", JS_NewString(ctx, type));
+ JS_SetPropertyStr(ctx, part, "value", JS_NewString(ctx, value));
+
+ lv = JS_GetPropertyStr(ctx, parts, "length");
+ if (!JS_IsException(lv)) {
+ JS_ToInt32(ctx, &len, lv);
+ JS_FreeValue(ctx, lv);
+ }
+ JS_DefinePropertyValueUint32(ctx, parts, (uint32_t)len, part, JS_PROP_C_W_E);
+}
+
+static void nf_add_grouped_integer_parts(JSContext *ctx, JSValue parts, const char *digits, int len,
+ const char *group_sep, int min2,
+ int group_size1, int group_size2)
+{
+ int remaining = len;
+ int groups[20];
+ int num_groups = 0;
+ int gi;
+ int first_group;
+ char *tmp;
+ int i;
+
+ if (remaining > 0) {
+ int gs1 = group_size1 > 0 ? group_size1 : 3;
+ int gs2 = group_size2 > 0 ? group_size2 : gs1;
+ int first = remaining > gs1 ? gs1 : remaining;
+ groups[num_groups++] = first;
+ remaining -= first;
+ while (remaining > 0) {
+ int g = remaining > gs2 ? gs2 : remaining;
+ groups[num_groups++] = g;
+ remaining -= g;
+ }
+ }
+
+ if (num_groups == 0) {
+ tmp = js_malloc(ctx, (size_t)len + 1);
+ if (!tmp) return;
+ memcpy(tmp, digits, (size_t)len);
+ tmp[len] = '\0';
+ nf_add_part(ctx, parts, "integer", tmp);
+ js_free(ctx, tmp);
+ return;
+ }
+
+ first_group = groups[num_groups - 1];
+
+ if (min2 && num_groups == 2 && first_group < 2) {
+ tmp = js_malloc(ctx, (size_t)len + 1);
+ if (!tmp) return;
+ memcpy(tmp, digits, (size_t)len);
+ tmp[len] = '\0';
+ nf_add_part(ctx, parts, "integer", tmp);
+ js_free(ctx, tmp);
+ return;
+ }
+
+ i = 0;
+ for (gi = num_groups - 1; gi >= 0; gi--) {
+ if (gi < num_groups - 1)
+ nf_add_part(ctx, parts, "group", group_sep);
+ tmp = js_malloc(ctx, (size_t)(groups[gi] + 1));
+ if (!tmp) continue;
+ memcpy(tmp, digits + i, (size_t)groups[gi]);
+ tmp[groups[gi]] = '\0';
+ nf_add_part(ctx, parts, "integer", tmp);
+ js_free(ctx, tmp);
+ i += groups[gi];
+ }
+}
+
+static JSValue intl_mv_format_standard(JSContext *ctx, IntlMV *mv, JSNumberFormatData *s,
+ const LocaleData *ldata, int strip_trailing_zeros,
+ JSValue parts)
+{
+ DynBuf db;
+ JSValue ret;
+ const char *pattern;
+ int is_negative = mv->sign;
+ int is_zero = (mv->num_digits == 1 && mv->digits[0] == '0');
+ char *int_str = NULL;
+ char *frac_str = NULL;
+ int int_len = 0;
+ int frac_len = 0;
+ int i;
+
+ js_intl_dbuf_init(ctx, &db);
+
+ /* Build integer and fraction strings */
+ if (mv->exponent >= 0) {
+ /* Pure integer: digits followed by exponent zeros */
+ int_len = mv->num_digits + mv->exponent;
+ int_str = js_malloc(ctx, (size_t)int_len + 1);
+ if (!int_str) goto fail;
+ memcpy(int_str, mv->digits, (size_t)mv->num_digits);
+ for (i = 0; i < mv->exponent; i++)
+ int_str[mv->num_digits + i] = '0';
+ int_str[int_len] = '\0';
+ frac_len = 0;
+ } else {
+ int int_part = mv->num_digits + mv->exponent; /* may be <= 0 */
+ if (int_part > 0) {
+ int_len = int_part;
+ int_str = js_malloc(ctx, (size_t)int_len + 1);
+ if (!int_str) goto fail;
+ memcpy(int_str, mv->digits, (size_t)int_len);
+ int_str[int_len] = '\0';
+ frac_len = -mv->exponent;
+ frac_str = js_malloc(ctx, (size_t)frac_len + 1);
+ if (!frac_str) goto fail;
+ memcpy(frac_str, mv->digits + int_part, (size_t)frac_len);
+ frac_str[frac_len] = '\0';
+ } else if (int_part == 0) {
+ int_len = 1;
+ int_str = js_strdup(ctx, "0");
+ if (!int_str) goto fail;
+ frac_len = mv->num_digits;
+ frac_str = js_malloc(ctx, (size_t)frac_len + 1);
+ if (!frac_str) goto fail;
+ memcpy(frac_str, mv->digits, (size_t)frac_len);
+ frac_str[frac_len] = '\0';
+ } else {
+ /* int_part < 0: leading zeros in fraction */
+ int leading_zeros = (int)(-mv->exponent - mv->num_digits);
+ int_len = 1;
+ int_str = js_strdup(ctx, "0");
+ if (!int_str) goto fail;
+ frac_len = -mv->exponent;
+ frac_str = js_malloc(ctx, (size_t)frac_len + 1);
+ if (!frac_str) goto fail;
+ for (i = 0; i < leading_zeros; i++)
+ frac_str[i] = '0';
+ memcpy(frac_str + leading_zeros, mv->digits, (size_t)mv->num_digits);
+ frac_str[frac_len] = '\0';
+ }
+ }
+
+ /* Strip trailing zeros down to minimumFractionDigits */
+ if (frac_len > 0 && strip_trailing_zeros) {
+ while (frac_len > s->minimumFractionDigits && frac_str[frac_len - 1] == '0')
+ frac_len--;
+ if (frac_len == 0) {
+ js_free(ctx, frac_str);
+ frac_str = NULL;
+ } else {
+ frac_str[frac_len] = '\0';
+ }
+ }
+
+ /* Pad integer part to minimumIntegerDigits */
+ if (int_len < s->minimumIntegerDigits) {
+ int pad = (int)(s->minimumIntegerDigits - int_len);
+ char *padded = js_malloc(ctx, (size_t)(s->minimumIntegerDigits + 1));
+ if (!padded) goto fail;
+ memset(padded, '0', (size_t)pad);
+ memcpy(padded + pad, int_str, (size_t)int_len);
+ padded[s->minimumIntegerDigits] = '\0';
+ js_free(ctx, int_str);
+ int_str = padded;
+ int_len = s->minimumIntegerDigits;
+ }
+
+ /* Select pattern based on signDisplay */
+ {
+ int use_negative_pattern = 0;
+ int prepend_plus = 0;
+ if (s->signDisplay == NF_SIGNDISPLAY_NEVER) {
+ use_negative_pattern = 0;
+ } else if (s->signDisplay == NF_SIGNDISPLAY_NEGATIVE) {
+ use_negative_pattern = is_negative && !is_zero;
+ } else if (s->signDisplay == NF_SIGNDISPLAY_EXCEPTZERO) {
+ use_negative_pattern = is_negative && !is_zero;
+ prepend_plus = !is_negative && !is_zero;
+ } else if (s->signDisplay == NF_SIGNDISPLAY_ALWAYS) {
+ use_negative_pattern = is_negative;
+ prepend_plus = !is_negative;
+ } else {
+ /* auto */
+ use_negative_pattern = is_negative;
+ }
+ if (prepend_plus) {
+ dbuf_putstr(&db, NS_PLUS(ldata->symbols));
+ if (!JS_IsUndefined(parts))
+ nf_add_part(ctx, parts, "plusSign", NS_PLUS(ldata->symbols));
+ }
+ if (s->style == NF_STYLE_PERCENT) {
+ pattern = use_negative_pattern ? NP_PCT_NEG(ldata->patterns) : NP_PCT_POS(ldata->patterns);
+ } else if (s->style == NF_STYLE_CURRENCY) {
+ if (s->currencySign == NF_CURRENCYSIGN_ACCOUNTING) {
+ pattern = use_negative_pattern ? NP_ACC_NEG(ldata->patterns) : NP_ACC_POS(ldata->patterns);
+ } else {
+ pattern = use_negative_pattern ? NP_CUR_NEG(ldata->patterns) : NP_CUR_POS(ldata->patterns);
+ }
+ } else {
+ pattern = use_negative_pattern ? NP_DEC_NEG(ldata->patterns) : NP_DEC_POS(ldata->patterns);
+ }
+ }
+
+ /* Build grouped integer string */
+ {
+ char *ungrouped_int_str = int_str;
+ int ungrouped_int_len = int_len;
+ DynBuf group_db;
+ js_intl_dbuf_init(ctx, &group_db);
+ if (s->useGrouping != NF_GROUPING_FALSE_BOOL) {
+ int min2 = (s->useGrouping == NF_GROUPING_MIN2);
+ add_grouping(&group_db, int_str, int_len, NS_GROUP(ldata->symbols), min2,
+ ldata->groupSize1, ldata->groupSize2);
+ } else {
+ dbuf_putstr(&group_db, int_str);
+ }
+ dbuf_putc(&group_db, '\0');
+ /* Don't free int_str; keep ungrouped copy for parts */
+ int_str = (char *)group_db.buf;
+ int_len = (int)group_db.size - 1;
+ /* group_db.buf is now owned by int_str, don't free group_db separately */
+ group_db.buf = NULL;
+ group_db.size = 0;
+
+ /* Apply pattern */
+ {
+ const char *p = pattern;
+ const char *next;
+ while (*p) {
+ if (strstart(p, "{number}", &next)) {
+ dbuf_putstr(&db, int_str);
+ if (!JS_IsUndefined(parts)) {
+ if (s->useGrouping != NF_GROUPING_FALSE_BOOL) {
+ int min2 = (s->useGrouping == NF_GROUPING_MIN2);
+ nf_add_grouped_integer_parts(ctx, parts, ungrouped_int_str, ungrouped_int_len, NS_GROUP(ldata->symbols), min2,
+ ldata->groupSize1, ldata->groupSize2);
+ } else {
+ nf_add_part(ctx, parts, "integer", ungrouped_int_str);
+ }
+ }
+ if (frac_len > 0) {
+ dbuf_putstr(&db, NS_DECIMAL(ldata->symbols));
+ dbuf_putstr(&db, frac_str);
+ if (!JS_IsUndefined(parts)) {
+ nf_add_part(ctx, parts, "decimal", NS_DECIMAL(ldata->symbols));
+ nf_add_part(ctx, parts, "fraction", frac_str);
+ }
+ }
+ p = next;
+ } else if (strstart(p, "{plusSign}", &next)) {
+ if (!is_negative) {
+ if (s->signDisplay == NF_SIGNDISPLAY_ALWAYS ||
+ (s->signDisplay == NF_SIGNDISPLAY_EXCEPTZERO && !is_zero)) {
+ dbuf_putstr(&db, NS_PLUS(ldata->symbols));
+ if (!JS_IsUndefined(parts))
+ nf_add_part(ctx, parts, "plusSign", NS_PLUS(ldata->symbols));
+ }
+ }
+ p = next;
+ } else if (strstart(p, "{minusSign}", &next)) {
+ if (is_negative) {
+ int show = 0;
+ if (s->signDisplay == NF_SIGNDISPLAY_ALWAYS) show = 1;
+ else if (s->signDisplay == NF_SIGNDISPLAY_AUTO) show = 1;
+ else if (s->signDisplay == NF_SIGNDISPLAY_EXCEPTZERO && !is_zero) show = 1;
+ else if (s->signDisplay == NF_SIGNDISPLAY_NEGATIVE && !is_zero) show = 1;
+ if (show) {
+ dbuf_putstr(&db, NS_MINUS(ldata->symbols));
+ if (!JS_IsUndefined(parts))
+ nf_add_part(ctx, parts, "minusSign", NS_MINUS(ldata->symbols));
+ }
+ }
+ p = next;
+ } else if (strstart(p, "{percentSign}", &next)) {
+ dbuf_putstr(&db, NS_PERCENT(ldata->symbols));
+ if (!JS_IsUndefined(parts))
+ nf_add_part(ctx, parts, "percentSign", NS_PERCENT(ldata->symbols));
+ p = next;
+ } else if (strstart(p, "{currency}", &next)) {
+ if (s->currency) {
+ const char *currency_str;
+ if (s->currencyDisplay == NF_CURRENCYDISPLAY_CODE)
+ currency_str = s->currency;
+ else
+ currency_str = js_intl_get_currency_symbol(s->currency, s->locale);
+ dbuf_putstr(&db, currency_str);
+ if (!JS_IsUndefined(parts))
+ nf_add_part(ctx, parts, "currency", currency_str);
+ }
+ p = next;
+ } else {
+ const char *lit_start = p;
+ while (*p && !strstart(p, "{", &next)) {
+ p++;
+ }
+ if (*p) {
+ dbuf_put(&db, (const uint8_t *)lit_start, (size_t)(p - lit_start));
+ } else {
+ dbuf_putstr(&db, lit_start);
+ }
+ if (!JS_IsUndefined(parts)) {
+ int lit_len = (int)(p - lit_start);
+ if (lit_len > 0) {
+ char *lit = js_malloc(ctx, (size_t)lit_len + 1);
+ if (lit) {
+ memcpy(lit, lit_start, (size_t)lit_len);
+ lit[lit_len] = '\0';
+ nf_add_part(ctx, parts, "literal", lit);
+ js_free(ctx, lit);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ dbuf_putc(&db, '\0');
+ ret = nf_finish_with_digits(ctx, &db, s->numberingSystem);
+ js_free(ctx, ungrouped_int_str);
+ goto cleanup;
+ }
+
+fail:
+ ret = JS_EXCEPTION;
+cleanup:
+ dbuf_free(&db);
+ js_free(ctx, frac_str);
+ js_free(ctx, int_str);
+ return ret;
+}
+
+/* Format scientific or engineering notation */
+static JSValue intl_mv_format_scientific(JSContext *ctx, IntlMV *mv, JSNumberFormatData *s,
+ const LocaleData *ldata, int is_engineering,
+ JSValue parts)
+{
+ DynBuf db;
+ JSValue ret;
+ int total_exp = (int)(mv->exponent + mv->num_digits - 1);
+ int eng_exp;
+ int digits_before;
+ int is_negative = mv->sign;
+ int is_zero = (mv->num_digits == 1 && mv->digits[0] == '0');
+ const char *sign_str = "";
+ int i;
+
+ js_intl_dbuf_init(ctx, &db);
+
+ if (is_engineering) {
+ if (total_exp >= 0) {
+ eng_exp = (total_exp / 3) * 3;
+ } else {
+ eng_exp = ((total_exp - 2) / 3) * 3;
+ }
+ digits_before = total_exp - eng_exp + 1;
+ } else {
+ eng_exp = total_exp;
+ digits_before = 1;
+ }
+
+ /* Determine sign */
+ if (s->signDisplay == NF_SIGNDISPLAY_NEVER) {
+ sign_str = "";
+ } else if (s->signDisplay == NF_SIGNDISPLAY_ALWAYS) {
+ sign_str = is_negative ? NS_MINUS(ldata->symbols) : NS_PLUS(ldata->symbols);
+ } else if (s->signDisplay == NF_SIGNDISPLAY_EXCEPTZERO) {
+ if (!is_zero)
+ sign_str = is_negative ? NS_MINUS(ldata->symbols) : NS_PLUS(ldata->symbols);
+ } else if (s->signDisplay == NF_SIGNDISPLAY_NEGATIVE) {
+ if (is_negative && !is_zero)
+ sign_str = NS_MINUS(ldata->symbols);
+ } else {
+ /* auto */
+ if (is_negative)
+ sign_str = NS_MINUS(ldata->symbols);
+ }
+
+ if (sign_str[0]) {
+ dbuf_putstr(&db, sign_str);
+ if (!JS_IsUndefined(parts))
+ nf_add_part(ctx, parts, is_negative ? "minusSign" : "plusSign", sign_str);
+ }
+
+ /* Integer part of mantissa */
+ {
+ char *int_buf = js_malloc(ctx, (size_t)digits_before + 1);
+ if (!int_buf) goto sci_fail;
+ memcpy(int_buf, mv->digits, (size_t)digits_before);
+ int_buf[digits_before] = '\0';
+ dbuf_putstr(&db, int_buf);
+ if (!JS_IsUndefined(parts))
+ nf_add_part(ctx, parts, "integer", int_buf);
+ js_free(ctx, int_buf);
+ }
+
+ /* Fraction part */
+ if (mv->num_digits > digits_before) {
+ int frac_len = (int)(mv->num_digits - digits_before);
+ char *frac_buf = js_malloc(ctx, (size_t)frac_len + 1);
+ if (!frac_buf) goto sci_fail;
+ memcpy(frac_buf, mv->digits + digits_before, (size_t)frac_len);
+ frac_buf[frac_len] = '\0';
+
+ /* Strip trailing zeros down to minimumFractionDigits */
+ if (frac_len > s->minimumFractionDigits) {
+ while (frac_len > s->minimumFractionDigits && frac_buf[frac_len - 1] == '0')
+ frac_len--;
+ frac_buf[frac_len] = '\0';
+ }
+
+ if (frac_len > 0) {
+ dbuf_putstr(&db, NS_DECIMAL(ldata->symbols));
+ dbuf_putstr(&db, frac_buf);
+ if (!JS_IsUndefined(parts)) {
+ nf_add_part(ctx, parts, "decimal", NS_DECIMAL(ldata->symbols));
+ nf_add_part(ctx, parts, "fraction", frac_buf);
+ }
+ }
+ js_free(ctx, frac_buf);
+ }
+
+ /* Exponent */
+ dbuf_putstr(&db, "E");
+ if (!JS_IsUndefined(parts))
+ nf_add_part(ctx, parts, "exponentSeparator", "E");
+
+ if (eng_exp < 0) {
+ dbuf_putstr(&db, "-");
+ if (!JS_IsUndefined(parts))
+ nf_add_part(ctx, parts, "exponentMinusSign", "-");
+ eng_exp = -eng_exp;
+ }
+
+ {
+ char exp_buf[32];
+ int n = eng_exp;
+ int exp_len = 0;
+ if (n == 0) {
+ exp_buf[0] = '0';
+ exp_len = 1;
+ } else {
+ while (n > 0) {
+ exp_buf[exp_len++] = (char)('0' + (n % 10));
+ n /= 10;
+ }
+ for (i = 0; i < exp_len / 2; i++) {
+ char t = exp_buf[i];
+ exp_buf[i] = exp_buf[exp_len - 1 - i];
+ exp_buf[exp_len - 1 - i] = t;
+ }
+ }
+ exp_buf[exp_len] = '\0';
+ dbuf_putstr(&db, exp_buf);
+ if (!JS_IsUndefined(parts))
+ nf_add_part(ctx, parts, "exponentInteger", exp_buf);
+ }
+
+ dbuf_putc(&db, '\0');
+ ret = nf_finish_with_digits(ctx, &db, s->numberingSystem);
+ goto sci_cleanup;
+
+sci_fail:
+ ret = JS_EXCEPTION;
+sci_cleanup:
+ dbuf_free(&db);
+ return ret;
+}
+
+static int intl_mv_is_at_least_scale(IntlMV *mv, int scale_exp)
+{
+ int exp_diff = (int)(mv->exponent - scale_exp);
+ if (exp_diff >= 0)
+ return 1;
+ int threshold_digit_count = -exp_diff + 1; /* number of digits in 10^(-exp_diff) */
+ if (mv->num_digits > threshold_digit_count)
+ return 1;
+ if (mv->num_digits < threshold_digit_count)
+ return 0;
+ return 1;
+}
+
+static JSValue intl_mv_format_compact(JSContext *ctx, IntlMV *mv, JSNumberFormatData *s,
+ const LocaleData *ldata, JSValue parts)
+{
+ const CompactDecimalPattern *cp = NULL;
+ const char *pat_str = NULL;
+ int scale_exp = 0;
+ int i;
+ JSNumberFormatData s2;
+ IntlMV scaled_mv = {0};
+ JSValue num_str = JS_UNDEFINED;
+ const char *num_cstr = NULL;
+ const char *suffix_start = NULL;
+ JSValue ret = JS_EXCEPTION;
+ DynBuf db;
+
+ for (i = ldata->numCompactPatterns - 1; i >= 0; i--) {
+ const CompactDecimalPattern *p = &ldata->compactPatterns[i];
+ int use = 0;
+ if (s->compactDisplay == NF_COMPACT_LONG) {
+ if (p->longPattern) use = 1;
+ } else {
+ if (p->shortPattern) use = 1;
+ }
+ if (use && intl_mv_is_at_least_scale(mv, p->scale_exp)) {
+ cp = p;
+ scale_exp = p->scale_exp;
+ pat_str = (s->compactDisplay == NF_COMPACT_LONG) ? p->longPattern : p->shortPattern;
+ break;
+ }
+ }
+
+ if (!cp) {
+ return intl_mv_format_standard(ctx, mv, s, ldata, 1, parts);
+ }
+
+ scaled_mv.kind = mv->kind;
+ scaled_mv.sign = mv->sign;
+ scaled_mv.digits = js_strdup(ctx, mv->digits);
+ if (!scaled_mv.digits)
+ return JS_EXCEPTION;
+ scaled_mv.num_digits = mv->num_digits;
+ scaled_mv.exponent = mv->exponent - scale_exp;
+
+ {
+ int int_digits = scaled_mv.num_digits + scaled_mv.exponent;
+ int compact_maxFD, compact_minFD;
+ if (int_digits <= 0) int_digits = 0;
+ if (int_digits == 1) {
+ compact_maxFD = 1;
+ compact_minFD = 0;
+ } else {
+ compact_maxFD = 0;
+ compact_minFD = 0;
+ }
+
+ s2 = *s;
+ s2.style = NF_STYLE_DECIMAL;
+ s2.currency = NULL;
+ s2.unit = NULL;
+ s2.maximumFractionDigits = compact_maxFD;
+ s2.minimumFractionDigits = compact_minFD;
+
+ if (intl_mv_round_fraction(ctx, &scaled_mv, compact_maxFD, compact_minFD, 1, s->roundingMode)) {
+ intl_mv_free(ctx, &scaled_mv);
+ return JS_EXCEPTION;
+ }
+ }
+
+ if (scaled_mv.num_digits == 1 && scaled_mv.digits[0] == '0') {
+ intl_mv_free(ctx, &scaled_mv);
+ return intl_mv_format_standard(ctx, mv, s, ldata, 1, parts);
+ }
+
+ num_str = intl_mv_format_standard(ctx, &scaled_mv, &s2, ldata, 1, parts);
+ if (JS_IsException(num_str)) {
+ intl_mv_free(ctx, &scaled_mv);
+ return num_str;
+ }
+ num_cstr = JS_ToCString(ctx, num_str);
+ if (!num_cstr) {
+ intl_mv_free(ctx, &scaled_mv);
+ JS_FreeValue(ctx, num_str);
+ return JS_EXCEPTION;
+ }
+
+ js_intl_dbuf_init(ctx, &db);
+
+ {
+ const char *p = pat_str;
+ while (*p) {
+ if (p[0] == '{' && p[1] == '0' && p[2] == '}') {
+ suffix_start = p + 3;
+ break;
+ }
+ p++;
+ }
+ if (suffix_start) {
+ dbuf_put(&db, (const uint8_t *)pat_str, (size_t)(suffix_start - pat_str - 3));
+ dbuf_putstr(&db, num_cstr);
+ dbuf_putstr(&db, suffix_start);
+ } else {
+ dbuf_putstr(&db, pat_str);
+ dbuf_putstr(&db, num_cstr);
+ }
+ }
+
+ dbuf_putc(&db, '\0');
+ ret = nf_finish_with_digits(ctx, &db, s->numberingSystem);
+
+ if (!JS_IsUndefined(parts) && suffix_start) {
+ const char *p = suffix_start;
+ while (*p) {
+ if (*p == ' ') {
+ nf_add_part(ctx, parts, "literal", " ");
+ p++;
+ } else if ((unsigned char)p[0] == 0xC2 && (unsigned char)p[1] == 0xA0) {
+ nf_add_part(ctx, parts, "literal", "\xC2\xA0");
+ p += 2;
+ } else {
+ break;
+ }
+ }
+ if (*p) {
+ nf_add_part(ctx, parts, "compact", p);
+ }
+ }
+
+ JS_FreeCString(ctx, num_cstr);
+ JS_FreeValue(ctx, num_str);
+ intl_mv_free(ctx, &scaled_mv);
+ return ret;
+}
+
+static JSValue intl_mv_format_unit(JSContext *ctx, IntlMV *mv, JSNumberFormatData *s,
+ const LocaleData *ldata, JSValue parts)
+{
+ const UnitPatternEntry *entry = find_unit_pattern(s->locale, s->unit);
+ const char *unit_pattern;
+ const char *num_pos;
+ const char *prefix;
+ int prefix_len;
+ const char *suffix;
+ JSValue num_str = JS_UNDEFINED;
+ DynBuf db;
+ JSValue ret = JS_UNDEFINED;
+ int has_parts = !JS_IsUndefined(parts);
+
+ if (entry)
+ unit_pattern = get_unit_pattern(entry, s->unitDisplay, unit_value_is_one(mv));
+ else
+ unit_pattern = NULL;
+
+ if (!unit_pattern) {
+ /* Fallback: decimal + " " + unit identifier */
+ JSNumberFormatData s2 = *s;
+ s2.style = NF_STYLE_DECIMAL;
+ num_str = intl_mv_format_standard(ctx, mv, &s2, ldata, 1, parts);
+ if (JS_IsException(num_str))
+ return num_str;
+
+ js_intl_dbuf_init(ctx, &db);
+ {
+ const char *str = JS_ToCString(ctx, num_str);
+ if (str) {
+ dbuf_putstr(&db, str);
+ dbuf_putstr(&db, " ");
+ dbuf_putstr(&db, s->unit);
+ JS_FreeCString(ctx, str);
+ }
+ }
+ dbuf_putc(&db, '\0');
+ if (dbuf_error(&db)) {
+ dbuf_free(&db);
+ JS_FreeValue(ctx, num_str);
+ return JS_EXCEPTION;
+ }
+ ret = JS_NewString(ctx, (char *)db.buf);
+ dbuf_free(&db);
+ JS_FreeValue(ctx, num_str);
+
+ if (has_parts) {
+ nf_add_part(ctx, parts, "literal", " ");
+ nf_add_part(ctx, parts, "unit", s->unit);
+ }
+ return ret;
+ }
+
+ num_pos = strstr(unit_pattern, "{number}");
+ if (!num_pos) {
+ JSNumberFormatData s2 = *s;
+ s2.style = NF_STYLE_DECIMAL;
+ return intl_mv_format_standard(ctx, mv, &s2, ldata, 1, parts);
+ }
+
+ prefix = unit_pattern;
+ prefix_len = (int)(num_pos - unit_pattern);
+ suffix = num_pos + strlen("{number}");
+
+ js_intl_dbuf_init(ctx, &db);
+
+ /* Prefix */
+ if (prefix_len > 0)
+ dbuf_put(&db, (const uint8_t *)prefix, (size_t)prefix_len);
+
+ if (has_parts && prefix_len > 0) {
+ const char *prefix_unit = prefix + prefix_len;
+ while (prefix_unit > prefix && prefix_unit[-1] == ' ') prefix_unit--;
+ int prefix_space_len = (int)(prefix_len - (prefix_unit - prefix));
+ if (prefix_unit > prefix) {
+ char *unit_str = js_strndup(ctx, prefix, (size_t)(prefix_unit - prefix));
+ if (unit_str) {
+ nf_add_part(ctx, parts, "unit", unit_str);
+ js_free(ctx, unit_str);
+ }
+ }
+ if (prefix_space_len > 0) {
+ char *space_str = js_strndup(ctx, prefix_unit, (size_t)prefix_space_len);
+ if (space_str) {
+ nf_add_part(ctx, parts, "literal", space_str);
+ js_free(ctx, space_str);
+ }
+ }
+ }
+
+ /* Number (formatted as decimal) */
+ {
+ JSNumberFormatData s2 = *s;
+ s2.style = NF_STYLE_DECIMAL;
+ num_str = intl_mv_format_standard(ctx, mv, &s2, ldata, 1, has_parts ? parts : JS_UNDEFINED);
+ if (JS_IsException(num_str)) {
+ dbuf_free(&db);
+ return num_str;
+ }
+ {
+ const char *str = JS_ToCString(ctx, num_str);
+ if (str) {
+ dbuf_putstr(&db, str);
+ JS_FreeCString(ctx, str);
+ }
+ }
+ JS_FreeValue(ctx, num_str);
+ }
+
+ /* Suffix */
+ if (*suffix)
+ dbuf_putstr(&db, suffix);
+ dbuf_putc(&db, '\0');
+ if (dbuf_error(&db)) {
+ dbuf_free(&db);
+ return JS_EXCEPTION;
+ }
+ ret = JS_NewString(ctx, (char *)db.buf);
+ dbuf_free(&db);
+
+ if (has_parts && *suffix) {
+ const char *unit_text = suffix;
+ while (*unit_text == ' ') unit_text++;
+ int space_len = (int)(unit_text - suffix);
+ if (space_len > 0) {
+ char *space_str = js_strndup(ctx, suffix, (size_t)space_len);
+ if (space_str) {
+ nf_add_part(ctx, parts, "literal", space_str);
+ js_free(ctx, space_str);
+ }
+ }
+ if (*unit_text) {
+ nf_add_part(ctx, parts, "unit", unit_text);
+ }
+ }
+
+ return ret;
+}
+
+/* Internal format helper: returns JSValue string.
+ If out_parts is non-NULL, also fills the parts array. */
+static JSValue js_numberformat_format_internal2(JSContext *ctx, JSNumberFormatData *s,
+ int argc, JSValueConst *argv,
+ JSValue *out_parts)
+{
+ const LocaleData *ldata;
+ IntlMV mv = {0};
+ JSValue ret;
+ DynBuf db;
+ const char *sign_str = "";
+ int is_negative, is_zero;
+ int strip_trailing_zeros = 1;
+
+ if (!s)
+ return JS_EXCEPTION;
+
+ ldata = js_intl_find_locale_data(s->locale);
+
+ if (argc == 0) {
+ mv.kind = INTL_MV_NAN;
+ } else {
+ if (intl_mv_init_from_value(ctx, argv[0], &mv))
+ return JS_EXCEPTION;
+ }
+
+ JSValue parts = JS_UNDEFINED;
+ if (out_parts) {
+ parts = *out_parts;
+ }
+
+ /* Handle NaN and Infinity */
+ if (mv.kind == INTL_MV_NAN || mv.kind == INTL_MV_INFINITY) {
+ js_intl_dbuf_init(ctx, &db);
+ is_negative = mv.sign;
+ if (s->signDisplay == NF_SIGNDISPLAY_ALWAYS) {
+ sign_str = is_negative ? NS_MINUS(ldata->symbols) : NS_PLUS(ldata->symbols);
+ } else if (s->signDisplay == NF_SIGNDISPLAY_EXCEPTZERO) {
+ if (mv.kind != INTL_MV_NAN)
+ sign_str = is_negative ? NS_MINUS(ldata->symbols) : NS_PLUS(ldata->symbols);
+ } else if (s->signDisplay == NF_SIGNDISPLAY_NEGATIVE) {
+ if (is_negative)
+ sign_str = NS_MINUS(ldata->symbols);
+ } else if (s->signDisplay == NF_SIGNDISPLAY_NEVER) {
+ sign_str = "";
+ } else {
+ if (is_negative)
+ sign_str = NS_MINUS(ldata->symbols);
+ }
+ if (sign_str[0]) {
+ dbuf_putstr(&db, sign_str);
+ if (!JS_IsUndefined(parts))
+ nf_add_part(ctx, parts, is_negative ? "minusSign" : "plusSign", sign_str);
+ }
+ {
+ const char *sym = (mv.kind == INTL_MV_NAN) ?
+ (NS_NAN(ldata->symbols) ? NS_NAN(ldata->symbols) : "NaN") :
+ (NS_INFINITY(ldata->symbols) ? NS_INFINITY(ldata->symbols) : "∞");
+ dbuf_putstr(&db, sym);
+ if (!JS_IsUndefined(parts))
+ nf_add_part(ctx, parts, mv.kind == INTL_MV_NAN ? "nan" : "infinity", sym);
+ }
+ dbuf_putc(&db, '\0');
+ ret = nf_finish_with_digits(ctx, &db, s->numberingSystem);
+ intl_mv_free(ctx, &mv);
+ return ret;
+ }
+
+ is_negative = mv.sign;
+ is_zero = (mv.num_digits == 1 && mv.digits[0] == '0');
+
+ /* For percent style, multiply by 100 via exponent adjustment */
+ if (s->style == NF_STYLE_PERCENT && !is_zero) {
+ mv.exponent += 2;
+ }
+
+ /* Apply rounding based on roundingPriority and significant digits options */
+ if (s->roundingPriority == NF_ROUNDINGPRIORITY_AUTO &&
+ (s->hasMinimumSignificantDigits || s->hasMaximumSignificantDigits)) {
+ /* auto with significant digits: ignore fraction digits */
+ strip_trailing_zeros = 0;
+ if (intl_mv_round_significant(ctx, &mv, s->maximumSignificantDigits,
+ s->minimumSignificantDigits,
+ s->roundingMode)) {
+ intl_mv_free(ctx, &mv);
+ return JS_EXCEPTION;
+ }
+ } else if (s->roundingPriority == NF_ROUNDINGPRIORITY_MOREPRECISION ||
+ s->roundingPriority == NF_ROUNDINGPRIORITY_LESSPRECISION) {
+ /* Compute both and pick based on RoundingMagnitude */
+ IntlMV mv_sig = {0}, mv_frac = {0};
+ int rm_sig, rm_frac;
+ int fixed_is_more_precise;
+ int use_frac;
+
+ /* Copy mv for significant-digit rounding */
+ mv_sig.kind = mv.kind;
+ mv_sig.sign = mv.sign;
+ mv_sig.digits = js_strdup(ctx, mv.digits);
+ if (!mv_sig.digits) goto precision_fail;
+ mv_sig.num_digits = mv.num_digits;
+ mv_sig.exponent = mv.exponent;
+
+ if (intl_mv_round_significant(ctx, &mv_sig, s->maximumSignificantDigits,
+ s->minimumSignificantDigits,
+ s->roundingMode)) {
+ intl_mv_free(ctx, &mv_sig);
+ goto precision_fail;
+ }
+
+ /* Copy mv for fraction-digit rounding */
+ mv_frac.kind = mv.kind;
+ mv_frac.sign = mv.sign;
+ mv_frac.digits = js_strdup(ctx, mv.digits);
+ if (!mv_frac.digits) {
+ intl_mv_free(ctx, &mv_sig);
+ goto precision_fail;
+ }
+ mv_frac.num_digits = mv.num_digits;
+ mv_frac.exponent = mv.exponent;
+
+ if (intl_mv_round_fraction(ctx, &mv_frac, s->maximumFractionDigits,
+ s->minimumFractionDigits, s->roundingIncrement,
+ s->roundingMode)) {
+ intl_mv_free(ctx, &mv_sig);
+ intl_mv_free(ctx, &mv_frac);
+ goto precision_fail;
+ }
+
+ /* RoundingMagnitude for ToRawPrecision: e - p + 1 = exponent + num_digits - maxSD */
+ rm_sig = mv_sig.exponent + mv_sig.num_digits - s->maximumSignificantDigits;
+ /* RoundingMagnitude for ToRawFixed: -maxFD */
+ rm_frac = -s->maximumFractionDigits;
+
+ fixed_is_more_precise = (rm_frac < rm_sig);
+
+ if (s->roundingPriority == NF_ROUNDINGPRIORITY_MOREPRECISION)
+ use_frac = fixed_is_more_precise;
+ else
+ use_frac = !fixed_is_more_precise;
+
+ if (use_frac) {
+ intl_mv_free(ctx, &mv_sig);
+ intl_mv_free(ctx, &mv);
+ mv = mv_frac;
+ strip_trailing_zeros = 1;
+ } else {
+ intl_mv_free(ctx, &mv_frac);
+ intl_mv_free(ctx, &mv);
+ mv = mv_sig;
+ strip_trailing_zeros = 0;
+ }
+ goto precision_done;
+ precision_fail:
+ intl_mv_free(ctx, &mv);
+ return JS_EXCEPTION;
+ precision_done:
+ ;
+ } else {
+ /* fraction digits only */
+ if (s->notation != NF_NOTATION_SCIENTIFIC && s->notation != NF_NOTATION_ENGINEERING) {
+ if (intl_mv_round_fraction(ctx, &mv, s->maximumFractionDigits,
+ s->minimumFractionDigits, s->roundingIncrement,
+ s->roundingMode)) {
+ intl_mv_free(ctx, &mv);
+ return JS_EXCEPTION;
+ }
+ }
+ }
+
+ /* Re-check zero after rounding */
+ is_zero = (mv.num_digits == 1 && mv.digits[0] == '0');
+
+ /* For scientific/engineering notation, round mantissa to desired significant digits */
+ if (s->notation == NF_NOTATION_SCIENTIFIC || s->notation == NF_NOTATION_ENGINEERING) {
+ int total_exp = (int)(mv.exponent + mv.num_digits - 1);
+ int eng_exp;
+ int digits_before;
+ int desired_sig_digits;
+
+ if (s->notation == NF_NOTATION_ENGINEERING) {
+ if (total_exp >= 0) {
+ eng_exp = (total_exp / 3) * 3;
+ } else {
+ eng_exp = ((total_exp - 2) / 3) * 3;
+ }
+ digits_before = total_exp - eng_exp + 1;
+ } else {
+ digits_before = 1;
+ }
+
+ if (s->hasMaximumSignificantDigits || s->hasMinimumSignificantDigits) {
+ desired_sig_digits = s->maximumSignificantDigits;
+ } else {
+ desired_sig_digits = digits_before + s->maximumFractionDigits;
+ }
+
+ if (desired_sig_digits > 0 && desired_sig_digits < 100) {
+ if (intl_mv_round_significant(ctx, &mv, desired_sig_digits,
+ s->minimumSignificantDigits,
+ s->roundingMode)) {
+ intl_mv_free(ctx, &mv);
+ return JS_EXCEPTION;
+ }
+ }
+ /* Re-check zero after re-rounding */
+ is_zero = (mv.num_digits == 1 && mv.digits[0] == '0');
+ ret = intl_mv_format_scientific(ctx, &mv, s, ldata,
+ s->notation == NF_NOTATION_ENGINEERING,
+ parts);
+ intl_mv_free(ctx, &mv);
+ return ret;
+ }
+
+ if (s->notation == NF_NOTATION_COMPACT) {
+ ret = intl_mv_format_compact(ctx, &mv, s, ldata, parts);
+ intl_mv_free(ctx, &mv);
+ return ret;
+ }
+
+ if (s->style == NF_STYLE_UNIT && s->unit) {
+ ret = intl_mv_format_unit(ctx, &mv, s, ldata, parts);
+ intl_mv_free(ctx, &mv);
+ return ret;
+ }
+
+ /* Format using intl_mv_format_standard */
+ ret = intl_mv_format_standard(ctx, &mv, s, ldata, strip_trailing_zeros, parts);
+ intl_mv_free(ctx, &mv);
+ return ret;
+}
+
+static JSValue js_numberformat_format_internal(JSContext *ctx, JSNumberFormatData *s,
+ int argc, JSValueConst *argv)
+{
+ return js_numberformat_format_internal2(ctx, s, argc, argv, NULL);
+}
+
+/* Number format function - called via JS_NewCFunctionData */
+static JSValue js_numberformat_bound_format(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv,
+ int magic, JSValue *func_data)
+{
+ (void)this_val;
+ (void)magic;
+ JSNumberFormatData *s = JS_GetOpaque2(ctx, func_data[0], js_numberformat_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ return js_numberformat_format_internal(ctx, s, argc, argv);
+}
+
+/* getter for Intl.NumberFormat.prototype.format */
+static JSValue js_numberformat_get_format(JSContext *ctx, JSValueConst this_val)
+{
+ JSValue bound;
+ JSNumberFormatData *s;
+ JSValue unwrapped = js_numberformat_unwrap(ctx, this_val);
+ if (JS_IsException(unwrapped))
+ return unwrapped;
+ s = JS_GetOpaque2(ctx, unwrapped, js_numberformat_class_id);
+ if (!s) {
+ JS_FreeValue(ctx, unwrapped);
+ return JS_EXCEPTION;
+ }
+
+ /* Check cached bound function */
+ bound = JS_GetPropertyStr(ctx, unwrapped, "__boundFormat__");
+ if (!JS_IsUndefined(bound) && JS_IsFunction(ctx, bound)) {
+ JS_FreeValue(ctx, unwrapped);
+ return bound;
+ }
+ JS_FreeValue(ctx, bound);
+
+ /* Create bound function using func_data to store the instance */
+ {
+ JSValue data[1];
+ JSValue ret;
+ data[0] = unwrapped;
+ bound = JS_NewCFunctionData(ctx, js_numberformat_bound_format, 1, 0, 1, data);
+ if (JS_IsException(bound)) {
+ JS_FreeValue(ctx, unwrapped);
+ return bound;
+ }
+ /* Cache it */
+ JS_SetPropertyStr(ctx, unwrapped, "__boundFormat__",
+ JS_DupValue(ctx, bound));
+ ret = JS_DupValue(ctx, bound);
+ JS_FreeValue(ctx, bound);
+ JS_FreeValue(ctx, unwrapped);
+ return ret;
+ }
+}
+
+/* prototype method: formatToParts */
+static JSValue js_numberformat_formatToParts(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSValue parts, str;
+ JSNumberFormatData *s;
+ JSValue unwrapped = js_numberformat_unwrap(ctx, this_val);
+ if (JS_IsException(unwrapped))
+ return unwrapped;
+ s = JS_GetOpaque2(ctx, unwrapped, js_numberformat_class_id);
+ if (!s) {
+ JS_FreeValue(ctx, unwrapped);
+ return JS_EXCEPTION;
+ }
+
+ parts = JS_NewArray(ctx);
+ if (JS_IsException(parts)) {
+ JS_FreeValue(ctx, unwrapped);
+ return parts;
+ }
+
+ str = js_numberformat_format_internal2(ctx, s, argc, argv, &parts);
+ if (JS_IsException(str)) {
+ JS_FreeValue(ctx, parts);
+ JS_FreeValue(ctx, unwrapped);
+ return str;
+ }
+ JS_FreeValue(ctx, str);
+ JS_FreeValue(ctx, unwrapped);
+ return parts;
+}
+
+/* prototype method: formatRange */
+static int js_numberformat_formatRange_validate(JSContext *ctx, int argc, JSValueConst *argv)
+{
+ int i;
+ IntlMV mv;
+
+ if (JS_IsUndefined(argv[0]) || JS_IsUndefined(argv[1]))
+ return JS_ThrowTypeError(ctx, "start and end must be defined"), -1;
+
+ for (i = 0; i < 2; i++) {
+ JSValue prim = JS_ToPrimitive(ctx, argv[i], JS_HINT_NUMBER);
+ if (JS_IsException(prim))
+ return -1;
+ if (JS_IsSymbol(prim)) {
+ JS_FreeValue(ctx, prim);
+ return JS_ThrowTypeError(ctx, "cannot convert symbol to number"), -1;
+ }
+ JS_FreeValue(ctx, prim);
+ }
+
+ /* Check for NaN per PartitionNumberRangePattern */
+ for (i = 0; i < 2; i++) {
+ if (intl_mv_init_from_value(ctx, argv[i], &mv))
+ return -1;
+ if (mv.kind == INTL_MV_NAN) {
+ intl_mv_free(ctx, &mv);
+ return JS_ThrowRangeError(ctx, "cannot format range with NaN"), -1;
+ }
+ intl_mv_free(ctx, &mv);
+ }
+
+ return 0;
+}
+
+static JSValue js_numberformat_formatRangeToParts(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv);
+
+static JSValue js_numberformat_formatRange(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSNumberFormatData *s;
+ JSValue unwrapped = js_numberformat_unwrap(ctx, this_val);
+ JSValue start_parts = JS_UNDEFINED, end_parts = JS_UNDEFINED;
+ JSValue start_str_val = JS_UNDEFINED, end_str_val = JS_UNDEFINED;
+ DynBuf db;
+ int start_len = 0, end_len = 0;
+ int i;
+ int prefix_len = 0, suffix_len = 0;
+ int share_prefix = 0, share_suffix = 0;
+ const char *start_cstr = NULL, *end_cstr = NULL;
+ const char *sep;
+
+ if (JS_IsException(unwrapped))
+ return unwrapped;
+ s = JS_GetOpaque2(ctx, unwrapped, js_numberformat_class_id);
+ if (!s) {
+ JS_FreeValue(ctx, unwrapped);
+ return JS_EXCEPTION;
+ }
+ if (js_numberformat_formatRange_validate(ctx, argc, argv) < 0) {
+ JS_FreeValue(ctx, unwrapped);
+ return JS_EXCEPTION;
+ }
+
+ start_parts = JS_NewArray(ctx);
+ if (JS_IsException(start_parts))
+ goto fail_range;
+ end_parts = JS_NewArray(ctx);
+ if (JS_IsException(end_parts))
+ goto fail_range;
+
+ start_str_val = js_numberformat_format_internal2(ctx, s, 1, &argv[0], &start_parts);
+ if (JS_IsException(start_str_val))
+ goto fail_range;
+ end_str_val = js_numberformat_format_internal2(ctx, s, 1, &argv[1], &end_parts);
+ if (JS_IsException(end_str_val))
+ goto fail_range;
+
+ start_cstr = JS_ToCString(ctx, start_str_val);
+ end_cstr = JS_ToCString(ctx, end_str_val);
+ if (!start_cstr || !end_cstr)
+ goto fail_range;
+
+ if (strcmp(start_cstr, end_cstr) == 0) {
+ js_intl_dbuf_init(ctx, &db);
+ dbuf_putstr(&db, "~");
+ dbuf_putstr(&db, start_cstr);
+ dbuf_putc(&db, '\0');
+ if (dbuf_error(&db))
+ goto fail_range;
+ {
+ JSValue ret = JS_NewString(ctx, (char *)db.buf);
+ dbuf_free(&db);
+ JS_FreeCString(ctx, start_cstr);
+ JS_FreeCString(ctx, end_cstr);
+ JS_FreeValue(ctx, start_str_val);
+ JS_FreeValue(ctx, end_str_val);
+ JS_FreeValue(ctx, start_parts);
+ JS_FreeValue(ctx, end_parts);
+ JS_FreeValue(ctx, unwrapped);
+ return ret;
+ }
+ }
+
+ {
+ JSValue len_val = JS_GetPropertyStr(ctx, start_parts, "length");
+ if (!JS_IsException(len_val)) {
+ int64_t v;
+ if (JS_ToInt64(ctx, &v, len_val) == 0)
+ start_len = (int)v;
+ JS_FreeValue(ctx, len_val);
+ }
+ }
+ {
+ JSValue len_val = JS_GetPropertyStr(ctx, end_parts, "length");
+ if (!JS_IsException(len_val)) {
+ int64_t v;
+ if (JS_ToInt64(ctx, &v, len_val) == 0)
+ end_len = (int)v;
+ JS_FreeValue(ctx, len_val);
+ }
+ }
+
+ for (i = 0; i < start_len && i < end_len; i++) {
+ JSValue sp = JS_GetPropertyUint32(ctx, start_parts, (uint32_t)i);
+ JSValue ep = JS_GetPropertyUint32(ctx, end_parts, (uint32_t)i);
+ int eq = 0;
+ if (!JS_IsException(sp) && !JS_IsException(ep)) {
+ JSValue st = JS_GetPropertyStr(ctx, sp, "type");
+ JSValue et = JS_GetPropertyStr(ctx, ep, "type");
+ JSValue sv = JS_GetPropertyStr(ctx, sp, "value");
+ JSValue ev = JS_GetPropertyStr(ctx, ep, "value");
+ if (!JS_IsException(st) && !JS_IsException(et) &&
+ !JS_IsException(sv) && !JS_IsException(ev)) {
+ const char *sct = JS_ToCString(ctx, st);
+ const char *ect = JS_ToCString(ctx, et);
+ const char *scv = JS_ToCString(ctx, sv);
+ const char *ecv = JS_ToCString(ctx, ev);
+ if (sct && ect && scv && ecv) {
+ if (!strcmp(sct, ect) && !strcmp(scv, ecv))
+ eq = 1;
+ }
+ JS_FreeCString(ctx, sct);
+ JS_FreeCString(ctx, ect);
+ JS_FreeCString(ctx, scv);
+ JS_FreeCString(ctx, ecv);
+ }
+ JS_FreeValue(ctx, st);
+ JS_FreeValue(ctx, et);
+ JS_FreeValue(ctx, sv);
+ JS_FreeValue(ctx, ev);
+ }
+ JS_FreeValue(ctx, sp);
+ JS_FreeValue(ctx, ep);
+ if (!eq)
+ break;
+ prefix_len++;
+ }
+
+ for (i = 0; i < start_len - prefix_len && i < end_len - prefix_len; i++) {
+ JSValue sp = JS_GetPropertyUint32(ctx, start_parts, (uint32_t)(start_len - 1 - i));
+ JSValue ep = JS_GetPropertyUint32(ctx, end_parts, (uint32_t)(end_len - 1 - i));
+ int eq = 0;
+ if (!JS_IsException(sp) && !JS_IsException(ep)) {
+ JSValue st = JS_GetPropertyStr(ctx, sp, "type");
+ JSValue et = JS_GetPropertyStr(ctx, ep, "type");
+ JSValue sv = JS_GetPropertyStr(ctx, sp, "value");
+ JSValue ev = JS_GetPropertyStr(ctx, ep, "value");
+ if (!JS_IsException(st) && !JS_IsException(et) &&
+ !JS_IsException(sv) && !JS_IsException(ev)) {
+ const char *sct = JS_ToCString(ctx, st);
+ const char *ect = JS_ToCString(ctx, et);
+ const char *scv = JS_ToCString(ctx, sv);
+ const char *ecv = JS_ToCString(ctx, ev);
+ if (sct && ect && scv && ecv) {
+ if (!strcmp(sct, ect) && !strcmp(scv, ecv))
+ eq = 1;
+ }
+ JS_FreeCString(ctx, sct);
+ JS_FreeCString(ctx, ect);
+ JS_FreeCString(ctx, scv);
+ JS_FreeCString(ctx, ecv);
+ }
+ JS_FreeValue(ctx, st);
+ JS_FreeValue(ctx, et);
+ JS_FreeValue(ctx, sv);
+ JS_FreeValue(ctx, ev);
+ }
+ JS_FreeValue(ctx, sp);
+ JS_FreeValue(ctx, ep);
+ if (!eq)
+ break;
+ suffix_len++;
+ }
+
+ for (i = 0; i < prefix_len; i++) {
+ JSValue sp = JS_GetPropertyUint32(ctx, start_parts, (uint32_t)i);
+ if (!JS_IsException(sp)) {
+ JSValue st = JS_GetPropertyStr(ctx, sp, "type");
+ if (!JS_IsException(st)) {
+ const char *sct = JS_ToCString(ctx, st);
+ if (sct) {
+ if (!strcmp(sct, "plusSign") || !strcmp(sct, "minusSign"))
+ share_prefix = 1;
+ }
+ JS_FreeCString(ctx, sct);
+ }
+ JS_FreeValue(ctx, st);
+ }
+ JS_FreeValue(ctx, sp);
+ }
+
+ for (i = 0; i < suffix_len; i++) {
+ JSValue sp = JS_GetPropertyUint32(ctx, start_parts, (uint32_t)(start_len - suffix_len + i));
+ if (!JS_IsException(sp)) {
+ JSValue st = JS_GetPropertyStr(ctx, sp, "type");
+ if (!JS_IsException(st)) {
+ const char *sct = JS_ToCString(ctx, st);
+ if (sct) {
+ if (!strcmp(sct, "currency") || !strcmp(sct, "percentSign") || !strcmp(sct, "unit"))
+ share_suffix = 1;
+ }
+ JS_FreeCString(ctx, sct);
+ }
+ JS_FreeValue(ctx, st);
+ }
+ JS_FreeValue(ctx, sp);
+ }
+
+ if (strstart(s->locale, "pt", NULL) || strstart(s->locale, "pt-", NULL)) {
+ sep = " - ";
+ } else {
+ if (share_prefix || share_suffix) {
+ sep = "\u2013";
+ } else {
+ if (s->style == NF_STYLE_CURRENCY || s->style == NF_STYLE_UNIT || s->style == NF_STYLE_PERCENT) {
+ sep = " \u2013 ";
+ } else {
+ sep = "\u2013";
+ }
+ }
+ }
+
+ js_intl_dbuf_init(ctx, &db);
+
+ for (i = 0; i < prefix_len; i++) {
+ if (share_prefix) {
+ JSValue sp = JS_GetPropertyUint32(ctx, start_parts, (uint32_t)i);
+ if (!JS_IsException(sp)) {
+ JSValue sv = JS_GetPropertyStr(ctx, sp, "value");
+ if (!JS_IsException(sv)) {
+ const char *scv = JS_ToCString(ctx, sv);
+ if (scv)
+ dbuf_putstr(&db, scv);
+ JS_FreeCString(ctx, scv);
+ }
+ JS_FreeValue(ctx, sv);
+ }
+ JS_FreeValue(ctx, sp);
+ }
+ }
+
+ for (i = share_prefix ? prefix_len : 0; i < start_len - (share_suffix ? suffix_len : 0); i++) {
+ JSValue sp = JS_GetPropertyUint32(ctx, start_parts, (uint32_t)i);
+ if (!JS_IsException(sp)) {
+ JSValue sv = JS_GetPropertyStr(ctx, sp, "value");
+ if (!JS_IsException(sv)) {
+ const char *scv = JS_ToCString(ctx, sv);
+ if (scv)
+ dbuf_putstr(&db, scv);
+ JS_FreeCString(ctx, scv);
+ }
+ JS_FreeValue(ctx, sv);
+ }
+ JS_FreeValue(ctx, sp);
+ }
+
+ dbuf_putstr(&db, sep);
+
+ for (i = share_prefix ? prefix_len : 0; i < end_len - (share_suffix ? suffix_len : 0); i++) {
+ JSValue ep = JS_GetPropertyUint32(ctx, end_parts, (uint32_t)i);
+ if (!JS_IsException(ep)) {
+ JSValue ev = JS_GetPropertyStr(ctx, ep, "value");
+ if (!JS_IsException(ev)) {
+ const char *ecv = JS_ToCString(ctx, ev);
+ if (ecv)
+ dbuf_putstr(&db, ecv);
+ JS_FreeCString(ctx, ecv);
+ }
+ JS_FreeValue(ctx, ev);
+ }
+ JS_FreeValue(ctx, ep);
+ }
+
+ for (i = 0; i < suffix_len; i++) {
+ if (share_suffix) {
+ JSValue sp = JS_GetPropertyUint32(ctx, start_parts, (uint32_t)(start_len - suffix_len + i));
+ if (!JS_IsException(sp)) {
+ JSValue sv = JS_GetPropertyStr(ctx, sp, "value");
+ if (!JS_IsException(sv)) {
+ const char *scv = JS_ToCString(ctx, sv);
+ if (scv)
+ dbuf_putstr(&db, scv);
+ JS_FreeCString(ctx, scv);
+ }
+ JS_FreeValue(ctx, sv);
+ }
+ JS_FreeValue(ctx, sp);
+ }
+ }
+
+ dbuf_putc(&db, '\0');
+ if (dbuf_error(&db)) {
+ dbuf_free(&db);
+ goto fail_range;
+ }
+ {
+ JSValue ret = JS_NewString(ctx, (char *)db.buf);
+ dbuf_free(&db);
+ JS_FreeCString(ctx, start_cstr);
+ JS_FreeCString(ctx, end_cstr);
+ JS_FreeValue(ctx, start_str_val);
+ JS_FreeValue(ctx, end_str_val);
+ JS_FreeValue(ctx, start_parts);
+ JS_FreeValue(ctx, end_parts);
+ JS_FreeValue(ctx, unwrapped);
+ return ret;
+ }
+
+fail_range:
+ JS_FreeCString(ctx, start_cstr);
+ JS_FreeCString(ctx, end_cstr);
+ JS_FreeValue(ctx, start_str_val);
+ JS_FreeValue(ctx, end_str_val);
+ JS_FreeValue(ctx, start_parts);
+ JS_FreeValue(ctx, end_parts);
+ JS_FreeValue(ctx, unwrapped);
+ return JS_EXCEPTION;
+}
+
+/* prototype method: formatRangeToParts */
+static JSValue js_numberformat_formatRangeToParts(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSNumberFormatData *s;
+ JSValue unwrapped = js_numberformat_unwrap(ctx, this_val);
+ JSValue start_parts = JS_UNDEFINED, end_parts = JS_UNDEFINED, result = JS_EXCEPTION;
+ int start_len = 0, end_len = 0;
+ int i;
+ int all_equal = 1;
+
+ if (JS_IsException(unwrapped))
+ return unwrapped;
+ s = JS_GetOpaque2(ctx, unwrapped, js_numberformat_class_id);
+ if (!s) {
+ JS_FreeValue(ctx, unwrapped);
+ return JS_EXCEPTION;
+ }
+ if (js_numberformat_formatRange_validate(ctx, argc, argv) < 0) {
+ JS_FreeValue(ctx, unwrapped);
+ return JS_EXCEPTION;
+ }
+
+ start_parts = JS_NewArray(ctx);
+ if (JS_IsException(start_parts))
+ goto fail_parts;
+ end_parts = JS_NewArray(ctx);
+ if (JS_IsException(end_parts))
+ goto fail_parts;
+
+ {
+ JSValue str1 = js_numberformat_format_internal2(ctx, s, 1, &argv[0], &start_parts);
+ if (JS_IsException(str1))
+ goto fail_parts;
+ JS_FreeValue(ctx, str1);
+ }
+ {
+ JSValue str2 = js_numberformat_format_internal2(ctx, s, 1, &argv[1], &end_parts);
+ if (JS_IsException(str2))
+ goto fail_parts;
+ JS_FreeValue(ctx, str2);
+ }
+
+ {
+ JSValue len_val = JS_GetPropertyStr(ctx, start_parts, "length");
+ if (!JS_IsException(len_val)) {
+ int64_t v;
+ if (JS_ToInt64(ctx, &v, len_val) == 0)
+ start_len = (int)v;
+ JS_FreeValue(ctx, len_val);
+ }
+ }
+ {
+ JSValue len_val = JS_GetPropertyStr(ctx, end_parts, "length");
+ if (!JS_IsException(len_val)) {
+ int64_t v;
+ if (JS_ToInt64(ctx, &v, len_val) == 0)
+ end_len = (int)v;
+ JS_FreeValue(ctx, len_val);
+ }
+ }
+
+ if (start_len != end_len)
+ all_equal = 0;
+ else {
+ for (i = 0; i < start_len; i++) {
+ JSValue sp = JS_GetPropertyUint32(ctx, start_parts, (uint32_t)i);
+ JSValue ep = JS_GetPropertyUint32(ctx, end_parts, (uint32_t)i);
+ int eq = 0;
+ if (!JS_IsException(sp) && !JS_IsException(ep)) {
+ JSValue st = JS_GetPropertyStr(ctx, sp, "type");
+ JSValue et = JS_GetPropertyStr(ctx, ep, "type");
+ JSValue sv = JS_GetPropertyStr(ctx, sp, "value");
+ JSValue ev = JS_GetPropertyStr(ctx, ep, "value");
+ if (!JS_IsException(st) && !JS_IsException(et) &&
+ !JS_IsException(sv) && !JS_IsException(ev)) {
+ const char *sct = JS_ToCString(ctx, st);
+ const char *ect = JS_ToCString(ctx, et);
+ const char *scv = JS_ToCString(ctx, sv);
+ const char *ecv = JS_ToCString(ctx, ev);
+ if (sct && ect && scv && ecv) {
+ if (!strcmp(sct, ect) && !strcmp(scv, ecv))
+ eq = 1;
+ }
+ JS_FreeCString(ctx, sct);
+ JS_FreeCString(ctx, ect);
+ JS_FreeCString(ctx, scv);
+ JS_FreeCString(ctx, ecv);
+ }
+ JS_FreeValue(ctx, st);
+ JS_FreeValue(ctx, et);
+ JS_FreeValue(ctx, sv);
+ JS_FreeValue(ctx, ev);
+ }
+ JS_FreeValue(ctx, sp);
+ JS_FreeValue(ctx, ep);
+ if (!eq) {
+ all_equal = 0;
+ break;
+ }
+ }
+ }
+
+ result = JS_NewArray(ctx);
+ if (JS_IsException(result))
+ goto fail_parts;
+
+ if (all_equal && start_len > 0) {
+ JSValue part = JS_NewObject(ctx);
+ if (JS_IsException(part))
+ goto fail_parts;
+ JS_DefinePropertyValueStr(ctx, part, "type", JS_NewString(ctx, "approximatelySign"), JS_PROP_C_W_E);
+ JS_DefinePropertyValueStr(ctx, part, "value", JS_NewString(ctx, "~"), JS_PROP_C_W_E);
+ JS_DefinePropertyValueStr(ctx, part, "source", JS_NewString(ctx, "shared"), JS_PROP_C_W_E);
+ JS_DefinePropertyValueUint32(ctx, result, (uint32_t)0, part, JS_PROP_C_W_E);
+
+ for (i = 0; i < start_len; i++) {
+ JSValue sp = JS_GetPropertyUint32(ctx, start_parts, (uint32_t)i);
+ JSValue type_val = JS_GetPropertyStr(ctx, sp, "type");
+ JSValue value_val = JS_GetPropertyStr(ctx, sp, "value");
+ JSValue part2 = JS_NewObject(ctx);
+ if (JS_IsException(part2)) {
+ JS_FreeValue(ctx, type_val);
+ JS_FreeValue(ctx, value_val);
+ JS_FreeValue(ctx, sp);
+ goto fail_parts;
+ }
+ JS_DefinePropertyValueStr(ctx, part2, "type", type_val, JS_PROP_C_W_E);
+ JS_DefinePropertyValueStr(ctx, part2, "value", value_val, JS_PROP_C_W_E);
+ JS_DefinePropertyValueStr(ctx, part2, "source", JS_NewString(ctx, "shared"), JS_PROP_C_W_E);
+ JS_DefinePropertyValueUint32(ctx, result, (uint32_t)(i + 1), part2, JS_PROP_C_W_E);
+ JS_FreeValue(ctx, sp);
+ }
+ } else {
+ for (i = 0; i < start_len; i++) {
+ JSValue sp = JS_GetPropertyUint32(ctx, start_parts, (uint32_t)i);
+ JSValue type_val = JS_GetPropertyStr(ctx, sp, "type");
+ JSValue value_val = JS_GetPropertyStr(ctx, sp, "value");
+ JSValue part2 = JS_NewObject(ctx);
+ if (JS_IsException(part2)) {
+ JS_FreeValue(ctx, type_val);
+ JS_FreeValue(ctx, value_val);
+ JS_FreeValue(ctx, sp);
+ goto fail_parts;
+ }
+ JS_DefinePropertyValueStr(ctx, part2, "type", type_val, JS_PROP_C_W_E);
+ JS_DefinePropertyValueStr(ctx, part2, "value", value_val, JS_PROP_C_W_E);
+ JS_DefinePropertyValueStr(ctx, part2, "source", JS_NewString(ctx, "startRange"), JS_PROP_C_W_E);
+ JS_DefinePropertyValueUint32(ctx, result, (uint32_t)i, part2, JS_PROP_C_W_E);
+ JS_FreeValue(ctx, sp);
+ }
+
+ {
+ JSValue sep_part = JS_NewObject(ctx);
+ const char *sep = (strstart(s->locale, "pt", NULL) || strstart(s->locale, "pt-", NULL)) ? " - " : " \u2013 ";
+ if (JS_IsException(sep_part))
+ goto fail_parts;
+ JS_DefinePropertyValueStr(ctx, sep_part, "type", JS_NewString(ctx, "literal"), JS_PROP_C_W_E);
+ JS_DefinePropertyValueStr(ctx, sep_part, "value", JS_NewString(ctx, sep), JS_PROP_C_W_E);
+ JS_DefinePropertyValueStr(ctx, sep_part, "source", JS_NewString(ctx, "shared"), JS_PROP_C_W_E);
+ JS_DefinePropertyValueUint32(ctx, result, (uint32_t)start_len, sep_part, JS_PROP_C_W_E);
+ }
+
+ for (i = 0; i < end_len; i++) {
+ JSValue ep = JS_GetPropertyUint32(ctx, end_parts, (uint32_t)i);
+ JSValue type_val = JS_GetPropertyStr(ctx, ep, "type");
+ JSValue value_val = JS_GetPropertyStr(ctx, ep, "value");
+ JSValue part2 = JS_NewObject(ctx);
+ if (JS_IsException(part2)) {
+ JS_FreeValue(ctx, type_val);
+ JS_FreeValue(ctx, value_val);
+ JS_FreeValue(ctx, ep);
+ goto fail_parts;
+ }
+ JS_DefinePropertyValueStr(ctx, part2, "type", type_val, JS_PROP_C_W_E);
+ JS_DefinePropertyValueStr(ctx, part2, "value", value_val, JS_PROP_C_W_E);
+ JS_DefinePropertyValueStr(ctx, part2, "source", JS_NewString(ctx, "endRange"), JS_PROP_C_W_E);
+ JS_DefinePropertyValueUint32(ctx, result, (uint32_t)(start_len + 1 + i), part2, JS_PROP_C_W_E);
+ JS_FreeValue(ctx, ep);
+ }
+ }
+
+ JS_FreeValue(ctx, start_parts);
+ JS_FreeValue(ctx, end_parts);
+ JS_FreeValue(ctx, unwrapped);
+ return result;
+
+fail_parts:
+ JS_FreeValue(ctx, start_parts);
+ JS_FreeValue(ctx, end_parts);
+ JS_FreeValue(ctx, result);
+ JS_FreeValue(ctx, unwrapped);
+ return JS_EXCEPTION;
+}
+
+/* prototype method: resolvedOptions */
+static JSValue js_numberformat_resolvedOptions(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSValue obj;
+ JSNumberFormatData *s;
+ JSValue unwrapped = js_numberformat_unwrap(ctx, this_val);
+ if (JS_IsException(unwrapped))
+ return unwrapped;
+ s = JS_GetOpaque2(ctx, unwrapped, js_numberformat_class_id);
+ if (!s) {
+ JS_FreeValue(ctx, unwrapped);
+ return JS_EXCEPTION;
+ }
+
+ obj = JS_NewObject(ctx);
+ if (JS_IsException(obj)) {
+ JS_FreeValue(ctx, unwrapped);
+ return JS_EXCEPTION;
+ }
+
+ JS_DefinePropertyValueStr(ctx, obj, "locale",
+ JS_NewString(ctx, s->locale), JS_PROP_C_W_E);
+ JS_DefinePropertyValueStr(ctx, obj, "numberingSystem",
+ JS_NewString(ctx, js_intl_numbering_system_to_string(s->numberingSystem)), JS_PROP_C_W_E);
+ JS_DefinePropertyValueStr(ctx, obj, "style",
+ JS_NewString(ctx, nf_style_names[s->style]), JS_PROP_C_W_E);
+
+ if (s->style == NF_STYLE_CURRENCY && s->currency) {
+ JS_DefinePropertyValueStr(ctx, obj, "currency",
+ JS_NewString(ctx, s->currency), JS_PROP_C_W_E);
+ JS_DefinePropertyValueStr(ctx, obj, "currencyDisplay",
+ JS_NewString(ctx, nf_currencydisplay_names[s->currencyDisplay]), JS_PROP_C_W_E);
+ JS_DefinePropertyValueStr(ctx, obj, "currencySign",
+ JS_NewString(ctx, nf_currencysign_names[s->currencySign]), JS_PROP_C_W_E);
+ }
+ if (s->style == NF_STYLE_UNIT && s->unit) {
+ JS_DefinePropertyValueStr(ctx, obj, "unit",
+ JS_NewString(ctx, s->unit), JS_PROP_C_W_E);
+ JS_DefinePropertyValueStr(ctx, obj, "unitDisplay",
+ JS_NewString(ctx, nf_unitdisplay_names[s->unitDisplay]), JS_PROP_C_W_E);
+ }
+
+ JS_DefinePropertyValueStr(ctx, obj, "minimumIntegerDigits",
+ JS_NewInt32(ctx, s->minimumIntegerDigits), JS_PROP_C_W_E);
+ JS_DefinePropertyValueStr(ctx, obj, "minimumFractionDigits",
+ JS_NewInt32(ctx, s->minimumFractionDigits), JS_PROP_C_W_E);
+ JS_DefinePropertyValueStr(ctx, obj, "maximumFractionDigits",
+ JS_NewInt32(ctx, s->maximumFractionDigits), JS_PROP_C_W_E);
+
+ if (s->hasMinimumSignificantDigits || s->hasMaximumSignificantDigits) {
+ JS_DefinePropertyValueStr(ctx, obj, "minimumSignificantDigits",
+ JS_NewInt32(ctx, s->minimumSignificantDigits), JS_PROP_C_W_E);
+ JS_DefinePropertyValueStr(ctx, obj, "maximumSignificantDigits",
+ JS_NewInt32(ctx, s->maximumSignificantDigits), JS_PROP_C_W_E);
+ }
+
+ if (s->useGrouping == NF_GROUPING_FALSE_BOOL) {
+ JS_DefinePropertyValueStr(ctx, obj, "useGrouping",
+ JS_NewBool(ctx, 0), JS_PROP_C_W_E);
+ } else {
+ JS_DefinePropertyValueStr(ctx, obj, "useGrouping",
+ JS_NewString(ctx, nf_grouping_names[s->useGrouping]), JS_PROP_C_W_E);
+ }
+ JS_DefinePropertyValueStr(ctx, obj, "notation",
+ JS_NewString(ctx, nf_notation_names[s->notation]), JS_PROP_C_W_E);
+
+ if (s->notation == NF_NOTATION_COMPACT) {
+ JS_DefinePropertyValueStr(ctx, obj, "compactDisplay",
+ JS_NewString(ctx, nf_compact_names[s->compactDisplay]), JS_PROP_C_W_E);
+ }
+
+ JS_DefinePropertyValueStr(ctx, obj, "signDisplay",
+ JS_NewString(ctx, nf_signdisplay_names[s->signDisplay]), JS_PROP_C_W_E);
+ JS_DefinePropertyValueStr(ctx, obj, "roundingIncrement",
+ JS_NewInt32(ctx, s->roundingIncrement), JS_PROP_C_W_E);
+ JS_DefinePropertyValueStr(ctx, obj, "roundingMode",
+ JS_NewString(ctx, nf_roundingmode_names[s->roundingMode]), JS_PROP_C_W_E);
+ JS_DefinePropertyValueStr(ctx, obj, "roundingPriority",
+ JS_NewString(ctx, nf_roundingpriority_names[s->roundingPriority]), JS_PROP_C_W_E);
+ JS_DefinePropertyValueStr(ctx, obj, "trailingZeroDisplay",
+ JS_NewString(ctx, nf_trailingzero_names[s->trailingZeroDisplay]), JS_PROP_C_W_E);
+
+ JS_FreeValue(ctx, unwrapped);
+ return obj;
+}
+
+/* static method: supportedLocalesOf */
+static JSValue js_numberformat_supportedLocalesOf(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ return js_intl_supportedLocalesOf(ctx, this_val, argc, argv);
+}
+
+static const JSCFunctionListEntry js_numberformat_proto_funcs[] = {
+ JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Intl.NumberFormat", JS_PROP_CONFIGURABLE),
+ JS_CGETSET_DEF("format", js_numberformat_get_format, NULL),
+ JS_CFUNC_DEF("formatToParts", 1, js_numberformat_formatToParts),
+ JS_CFUNC_DEF("formatRange", 2, js_numberformat_formatRange),
+ JS_CFUNC_DEF("formatRangeToParts", 2, js_numberformat_formatRangeToParts),
+ JS_CFUNC_DEF("resolvedOptions", 0, js_numberformat_resolvedOptions),
+};
+
+static const JSCFunctionListEntry js_numberformat_static_funcs[] = {
+ JS_CFUNC_DEF("supportedLocalesOf", 1, js_numberformat_supportedLocalesOf),
+};
+
+int js_add_numberformat(JSContext *ctx, JSValue intl_obj)
+{
+ JS_NewClassID(&js_numberformat_class_id);
+ JS_NewClass(JS_GetRuntime(ctx), js_numberformat_class_id, &js_numberformat_class);
+
+ if (JS_IsException(js_intl_new_constructor(ctx, intl_obj,
+ JS_INTL_CTOR_NUMBERFORMAT,
+ js_numberformat_class_id, "NumberFormat",
+ (JSCFunction *)js_numberformat_constructor, 0,
+ JS_CFUNC_constructor_or_func_flags, 0,
+ js_numberformat_static_funcs, countof(js_numberformat_static_funcs),
+ js_numberformat_proto_funcs, countof(js_numberformat_proto_funcs))))
+ return -1;
+
+ return 0;
+}
+
+JSValue js_numberformat_format_number(JSContext *ctx, double d, int argc, JSValueConst *argv)
+{
+ JSValue ctor, obj, val, ret;
+
+ ctor = JS_GetContextValue(ctx, JS_INTL_CTOR_NUMBERFORMAT);
+ if (JS_IsUndefined(ctor))
+ return JS_ThrowTypeError(ctx, "NumberFormat not available");
+
+ obj = JS_CallConstructor(ctx, ctor, argc, argv);
+ JS_FreeValue(ctx, ctor);
+ if (JS_IsException(obj))
+ return obj;
+
+ {
+ JSNumberFormatData *s = JS_GetOpaque(obj, js_numberformat_class_id);
+ if (!s) {
+ JS_FreeValue(ctx, obj);
+ return JS_EXCEPTION;
+ }
+ val = __JS_NewFloat64(ctx, d);
+ ret = js_numberformat_format_internal(ctx, s, 1, &val);
+ JS_FreeValue(ctx, val);
+ }
+ JS_FreeValue(ctx, obj);
+ return ret;
+}
+
+JSValue js_intl_number_toLocaleString(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ double d;
+ if (JS_ToFloat64(ctx, &d, this_val))
+ return JS_EXCEPTION;
+ return js_numberformat_format_number(ctx, d, argc, argv);
+}
+
+JSValue js_intl_bigint_toLocaleString(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSValue ctor, obj, func, ret;
+
+ ctor = JS_GetContextValue(ctx, JS_INTL_CTOR_NUMBERFORMAT);
+ if (JS_IsUndefined(ctor))
+ return JS_ThrowTypeError(ctx, "NumberFormat not available");
+
+ obj = JS_CallConstructor(ctx, ctor, argc, argv);
+ JS_FreeValue(ctx, ctor);
+ if (JS_IsException(obj))
+ return obj;
+
+ func = JS_GetPropertyStr(ctx, obj, "format");
+ if (JS_IsException(func)) {
+ JS_FreeValue(ctx, obj);
+ return func;
+ }
+
+ ret = JS_Call(ctx, func, obj, 1, &this_val);
+ JS_FreeValue(ctx, func);
+ JS_FreeValue(ctx, obj);
+ return ret;
+}
--- /dev/null
+/*
+ * QuickJS Intl.PluralRules implementation
+ */
+
+#include <string.h>
+#include <math.h>
+
+#include "../quickjs.h"
+#include "../cutils.h"
+#include "intl_private.h"
+
+static JSClassID js_pluralrules_class_id;
+
+enum {
+ PR_TYPE_CARDINAL = 0,
+ PR_TYPE_ORDINAL,
+};
+static const char *pr_type_names[] = {"cardinal", "ordinal"};
+
+enum {
+ PR_NOTATION_STANDARD = 0,
+ PR_NOTATION_SCIENTIFIC,
+ PR_NOTATION_ENGINEERING,
+ PR_NOTATION_COMPACT,
+};
+static const char *pr_notation_names[] = {"standard", "scientific", "engineering", "compact"};
+
+enum {
+ PR_COMPACT_SHORT = 0,
+ PR_COMPACT_LONG,
+};
+static const char *pr_compactdisplay_names[] = {"short", "long"};
+
+enum {
+ PR_ROUNDINGMODE_CEIL = 0,
+ PR_ROUNDINGMODE_FLOOR,
+ PR_ROUNDINGMODE_EXPAND,
+ PR_ROUNDINGMODE_TRUNC,
+ PR_ROUNDINGMODE_HALFCEIL,
+ PR_ROUNDINGMODE_HALFFLOOR,
+ PR_ROUNDINGMODE_HALFEXPAND,
+ PR_ROUNDINGMODE_HALFTRUNC,
+ PR_ROUNDINGMODE_HALFEVEN,
+};
+static const char *pr_roundingmode_names[] = {"ceil", "floor", "expand", "trunc", "halfCeil", "halfFloor", "halfExpand", "halfTrunc", "halfEven"};
+
+enum {
+ PR_ROUNDINGPRIORITY_AUTO = 0,
+ PR_ROUNDINGPRIORITY_MOREPRECISION,
+ PR_ROUNDINGPRIORITY_LESSPRECISION,
+};
+static const char *pr_roundingpriority_names[] = {"auto", "morePrecision", "lessPrecision"};
+
+enum {
+ PR_TRAILINGZERO_AUTO = 0,
+ PR_TRAILINGZERO_STRIPIFINTEGER,
+};
+static const char *pr_trailingzero_names[] = {"auto", "stripIfInteger"};
+
+typedef struct {
+ char *locale;
+ int type;
+ int notation;
+ int compactDisplay; /* only meaningful when notation == compact */
+ int minimumIntegerDigits;
+ int minimumFractionDigits;
+ int maximumFractionDigits;
+ int minimumSignificantDigits;
+ int maximumSignificantDigits;
+ int hasSignificantDigits;
+ int roundingIncrement;
+ int roundingMode;
+ int roundingPriority;
+ int trailingZeroDisplay;
+} JSPluralRulesData;
+
+static void js_pluralrules_finalizer(JSRuntime *rt, JSValue val)
+{
+ JSPluralRulesData *s = JS_GetOpaque(val, js_pluralrules_class_id);
+ if (s) {
+ js_free_rt(rt, s->locale);
+ js_free_rt(rt, s);
+ }
+}
+
+static JSClassDef js_pluralrules_class = {
+ "PluralRules",
+ .finalizer = js_pluralrules_finalizer,
+};
+
+const char *plural_category_names[PLURAL_COUNT] = {
+ "zero", "one", "two", "few", "many", "other"
+};
+
+/* Return plural categories array for locale and type.
+ bitmap: bit i set => include PLURAL_* category i.
+ For cardinal: returns categories in canonical order. */
+static JSValue js_pluralrules_get_categories(JSContext *ctx, const char *locale, int type)
+{
+ JSValue arr;
+ int bitmap;
+ int i;
+ uint32_t idx;
+
+ if (type == PR_TYPE_ORDINAL) {
+ bitmap = (1 << PLURAL_ONE) | (1 << PLURAL_TWO) | (1 << PLURAL_FEW) | (1 << PLURAL_OTHER);
+ } else if (!strcmp(locale, "ar")) {
+ bitmap = (1 << PLURAL_ZERO) | (1 << PLURAL_ONE) | (1 << PLURAL_TWO) |
+ (1 << PLURAL_FEW) | (1 << PLURAL_MANY) | (1 << PLURAL_OTHER);
+ } else if (!strcmp(locale, "fa")) {
+ bitmap = (1 << PLURAL_ONE) | (1 << PLURAL_OTHER);
+ } else if (!strcmp(locale, "fr")) {
+ bitmap = (1 << PLURAL_ONE) | (1 << PLURAL_MANY) | (1 << PLURAL_OTHER);
+ } else if (!strcmp(locale, "gv")) {
+ bitmap = (1 << PLURAL_ONE) | (1 << PLURAL_TWO) | (1 << PLURAL_FEW) |
+ (1 << PLURAL_MANY) | (1 << PLURAL_OTHER);
+ } else if (!strcmp(locale, "ko") || !strcmp(locale, "ja") ||
+ strstart(locale, "zh", NULL)) {
+ bitmap = (1 << PLURAL_OTHER);
+ } else if (!strcmp(locale, "sl")) {
+ bitmap = (1 << PLURAL_ONE) | (1 << PLURAL_TWO) | (1 << PLURAL_FEW) | (1 << PLURAL_OTHER);
+ } else if (strstart(locale, "ru", NULL)) {
+ bitmap = (1 << PLURAL_ONE) | (1 << PLURAL_FEW) | (1 << PLURAL_MANY) | (1 << PLURAL_OTHER);
+ } else {
+ /* Default: en, etc. */
+ bitmap = (1 << PLURAL_ONE) | (1 << PLURAL_OTHER);
+ }
+
+ arr = JS_NewArray(ctx);
+ if (JS_IsException(arr))
+ return JS_EXCEPTION;
+
+ idx = 0;
+ for (i = 0; i < PLURAL_COUNT; i++) {
+ if (bitmap & (1 << i)) {
+ JSValue val = JS_NewString(ctx, plural_category_names[i]);
+ if (JS_IsException(val)) {
+ JS_FreeValue(ctx, arr);
+ return JS_EXCEPTION;
+ }
+ if (JS_DefinePropertyValueUint32(ctx, arr, idx++, val, JS_PROP_C_W_E) < 0) {
+ JS_FreeValue(ctx, arr);
+ return JS_EXCEPTION;
+ }
+ }
+ }
+ return arr;
+}
+
+static JSValue js_pluralrules_constructor(JSContext *ctx,
+ JSValueConst new_target,
+ int argc, JSValueConst *argv)
+{
+ JSPluralRulesData *s;
+ JSValue obj = JS_UNDEFINED;
+ JSValue options = JS_UNDEFINED;
+ int v;
+ int ret;
+
+ s = js_mallocz(ctx, sizeof(*s));
+ if (!s)
+ return JS_EXCEPTION;
+
+ s->locale = js_strdup(ctx, "en-US");
+ s->type = PR_TYPE_CARDINAL;
+ s->notation = PR_NOTATION_STANDARD;
+ s->minimumIntegerDigits = 1;
+ s->minimumFractionDigits = 0;
+ s->maximumFractionDigits = 3;
+ s->roundingIncrement = 1;
+ s->roundingMode = PR_ROUNDINGMODE_HALFEVEN;
+ s->roundingPriority = PR_ROUNDINGPRIORITY_AUTO;
+ s->trailingZeroDisplay = PR_TRAILINGZERO_AUTO;
+
+ {
+ char *loc = js_intl_extract_locale(ctx, argc, argv);
+ if (!loc)
+ goto fail;
+ js_free(ctx, s->locale);
+ s->locale = loc;
+ }
+
+ /* Handle options */
+ if (argc > 1 && !JS_IsUndefined(argv[1])) {
+ options = JS_ToObject(ctx, argv[1]);
+ if (JS_IsException(options))
+ goto fail;
+ } else {
+ options = JS_NewObjectProto(ctx, JS_NULL);
+ if (JS_IsException(options))
+ goto fail;
+ }
+
+ /* Read localeMatcher (from ResolveOptions) */
+ {
+ int idx = js_intl_get_string_option(ctx, options, "localeMatcher",
+ intl_localeMatcher_names,
+ countof(intl_localeMatcher_names),
+ INTL_LOCALEMATCHER_BESTFIT);
+ if (idx < 0)
+ goto fail;
+ }
+
+ /* Read type */
+ {
+ int idx = js_intl_get_string_option(ctx, options, "type",
+ pr_type_names,
+ countof(pr_type_names),
+ PR_TYPE_CARDINAL);
+ if (idx < 0)
+ goto fail;
+ s->type = idx;
+ }
+
+ /* Read notation */
+ {
+ int idx = js_intl_get_string_option(ctx, options, "notation",
+ pr_notation_names,
+ countof(pr_notation_names),
+ PR_NOTATION_STANDARD);
+ if (idx < 0)
+ goto fail;
+ s->notation = idx;
+ }
+
+ /* Read compactDisplay */
+ {
+ int idx = js_intl_get_string_option(ctx, options, "compactDisplay",
+ pr_compactdisplay_names,
+ countof(pr_compactdisplay_names),
+ PR_COMPACT_SHORT);
+ if (idx < 0)
+ goto fail;
+ if (s->notation == PR_NOTATION_COMPACT)
+ s->compactDisplay = idx;
+ }
+
+ /* SetNumberFormatDigitOptions */
+ ret = js_intl_get_number_option(ctx, options, "minimumIntegerDigits", &v, 1, 21);
+ if (ret < 0) goto fail;
+ if (ret > 0) s->minimumIntegerDigits = v;
+
+ ret = js_intl_get_number_option(ctx, options, "minimumFractionDigits", &v, 0, 100);
+ if (ret < 0) goto fail;
+ if (ret > 0) s->minimumFractionDigits = v;
+
+ ret = js_intl_get_number_option(ctx, options, "maximumFractionDigits", &v, 0, 100);
+ if (ret < 0) goto fail;
+ if (ret > 0) s->maximumFractionDigits = v;
+
+ {
+ int has_mnsd = 0, has_mxsd = 0;
+ int mnsd = 0, mxsd = 0;
+
+ ret = js_intl_get_number_option(ctx, options, "minimumSignificantDigits", &mnsd, 1, 21);
+ if (ret < 0) goto fail;
+ has_mnsd = ret;
+
+ ret = js_intl_get_number_option(ctx, options, "maximumSignificantDigits", &mxsd, 1, 21);
+ if (ret < 0) goto fail;
+ has_mxsd = ret;
+
+ if (has_mnsd && has_mxsd) {
+ s->minimumSignificantDigits = mnsd;
+ s->maximumSignificantDigits = mxsd;
+ s->hasSignificantDigits = 1;
+ }
+ }
+
+ ret = js_intl_get_number_option(ctx, options, "roundingIncrement", &v, 1, 5000);
+ if (ret < 0) goto fail;
+ if (ret > 0) s->roundingIncrement = v;
+
+ {
+ int idx = js_intl_get_string_option(ctx, options, "roundingMode",
+ pr_roundingmode_names,
+ countof(pr_roundingmode_names),
+ PR_ROUNDINGMODE_HALFEVEN);
+ if (idx < 0)
+ goto fail;
+ s->roundingMode = idx;
+ }
+
+ {
+ int idx = js_intl_get_string_option(ctx, options, "roundingPriority",
+ pr_roundingpriority_names,
+ countof(pr_roundingpriority_names),
+ PR_ROUNDINGPRIORITY_AUTO);
+ if (idx < 0)
+ goto fail;
+ s->roundingPriority = idx;
+ }
+
+ {
+ int idx = js_intl_get_string_option(ctx, options, "trailingZeroDisplay",
+ pr_trailingzero_names,
+ countof(pr_trailingzero_names),
+ PR_TRAILINGZERO_AUTO);
+ if (idx < 0)
+ goto fail;
+ s->trailingZeroDisplay = idx;
+ }
+
+ JS_FreeValue(ctx, options);
+ options = JS_UNDEFINED;
+
+ obj = JS_CreateFromConstructor(ctx, new_target, js_pluralrules_class_id);
+ if (JS_IsException(obj))
+ goto fail;
+ JS_SetOpaque(obj, s);
+ return obj;
+ fail:
+ JS_FreeValue(ctx, options);
+ if (s->locale) js_free(ctx, s->locale);
+ js_free(ctx, s);
+ JS_FreeValue(ctx, obj);
+ return JS_EXCEPTION;
+}
+
+static int is_power_of_10(double n)
+{
+ if (n <= 0 || floor(n) != n)
+ return 0;
+ while (n > 1) {
+ if (fmod(n, 10.0) != 0)
+ return 0;
+ n /= 10.0;
+ }
+ return n == 1.0;
+}
+
+static JSValue js_pluralrules_select(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSPluralRulesData *s = JS_GetOpaque2(ctx, this_val, js_pluralrules_class_id);
+ double n, abs_n;
+ int ret;
+ if (!s)
+ return JS_EXCEPTION;
+ if (JS_IsUndefined(argv[0]))
+ return JS_ThrowTypeError(ctx, "select requires a value");
+ ret = JS_ToFloat64(ctx, &n, argv[0]);
+ if (ret < 0)
+ return JS_EXCEPTION;
+ if (isnan(n) || isinf(n))
+ return JS_NewString(ctx, "other");
+
+ abs_n = fabs(n);
+
+ if (!strcmp(s->locale, "ko") || !strcmp(s->locale, "ja") ||
+ strstart(s->locale, "zh", NULL)) {
+ return JS_NewString(ctx, plural_category_names[PLURAL_OTHER]);
+ }
+
+ if (strstart(s->locale, "fr", NULL)) {
+ if (abs_n < 2.0)
+ return JS_NewString(ctx, plural_category_names[PLURAL_ONE]);
+ if (s->notation == PR_NOTATION_COMPACT && abs_n >= 1000000.0)
+ return JS_NewString(ctx, plural_category_names[PLURAL_MANY]);
+ if (is_power_of_10(abs_n))
+ return JS_NewString(ctx, plural_category_names[PLURAL_MANY]);
+ return JS_NewString(ctx, plural_category_names[PLURAL_OTHER]);
+ }
+
+ if (strstart(s->locale, "ru", NULL)) {
+ int iv = (int)abs_n;
+ int mod10 = iv % 10;
+ int mod100 = iv % 100;
+ if (mod10 == 1 && mod100 != 11)
+ return JS_NewString(ctx, plural_category_names[PLURAL_ONE]);
+ if (mod10 >= 2 && mod10 <= 4 && (mod100 < 10 || mod100 >= 20))
+ return JS_NewString(ctx, plural_category_names[PLURAL_FEW]);
+ return JS_NewString(ctx, plural_category_names[PLURAL_MANY]);
+ }
+
+ /* Default English-like rule */
+ if (abs_n == 1.0)
+ return JS_NewString(ctx, plural_category_names[PLURAL_ONE]);
+ return JS_NewString(ctx, plural_category_names[PLURAL_OTHER]);
+}
+
+static JSValue js_pluralrules_selectRange(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSPluralRulesData *s = JS_GetOpaque2(ctx, this_val, js_pluralrules_class_id);
+ double start, end;
+ int ret;
+ if (!s)
+ return JS_EXCEPTION;
+ if (JS_IsUndefined(argv[0]) || JS_IsUndefined(argv[1]))
+ return JS_ThrowTypeError(ctx, "selectRange requires two arguments");
+ ret = JS_ToFloat64(ctx, &start, argv[0]);
+ if (ret < 0)
+ return JS_EXCEPTION;
+ ret = JS_ToFloat64(ctx, &end, argv[1]);
+ if (ret < 0)
+ return JS_EXCEPTION;
+ if (isnan(start) || isnan(end))
+ return JS_ThrowRangeError(ctx, "selectRange argument is NaN");
+ return JS_NewString(ctx, "other");
+}
+
+static int js_add_prop_str(JSContext *ctx, JSValue obj, const char *name, const char *val)
+{
+ JSValue v = JS_NewString(ctx, val);
+ if (JS_IsException(v))
+ return -1;
+ return JS_DefinePropertyValueStr(ctx, obj, name, v, JS_PROP_C_W_E);
+}
+
+static int js_add_prop_int32(JSContext *ctx, JSValue obj, const char *name, int32_t val)
+{
+ return JS_DefinePropertyValueStr(ctx, obj, name, JS_NewInt32(ctx, val), JS_PROP_C_W_E);
+}
+
+static JSValue js_pluralrules_resolvedOptions(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSValue obj;
+ JSPluralRulesData *s = JS_GetOpaque2(ctx, this_val, js_pluralrules_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+
+ obj = JS_NewObject(ctx);
+ if (JS_IsException(obj))
+ return JS_EXCEPTION;
+
+ if (js_add_prop_str(ctx, obj, "locale", s->locale) < 0 ||
+ js_add_prop_str(ctx, obj, "type", pr_type_names[s->type]) < 0 ||
+ js_add_prop_str(ctx, obj, "notation", pr_notation_names[s->notation]) < 0)
+ goto fail;
+ if (s->notation == PR_NOTATION_COMPACT) {
+ if (js_add_prop_str(ctx, obj, "compactDisplay", pr_compactdisplay_names[s->compactDisplay]) < 0)
+ goto fail;
+ }
+ if (js_add_prop_int32(ctx, obj, "minimumIntegerDigits", s->minimumIntegerDigits) < 0 ||
+ js_add_prop_int32(ctx, obj, "minimumFractionDigits", s->minimumFractionDigits) < 0 ||
+ js_add_prop_int32(ctx, obj, "maximumFractionDigits", s->maximumFractionDigits) < 0)
+ goto fail;
+ if (s->hasSignificantDigits) {
+ if (js_add_prop_int32(ctx, obj, "minimumSignificantDigits", s->minimumSignificantDigits) < 0 ||
+ js_add_prop_int32(ctx, obj, "maximumSignificantDigits", s->maximumSignificantDigits) < 0)
+ goto fail;
+ }
+ {
+ JSValue cats = js_pluralrules_get_categories(ctx, s->locale, s->type);
+ if (JS_IsException(cats)) {
+ JS_FreeValue(ctx, obj);
+ return JS_EXCEPTION;
+ }
+ if (JS_DefinePropertyValueStr(ctx, obj, "pluralCategories", cats, JS_PROP_C_W_E) < 0)
+ goto fail;
+ }
+ if (js_add_prop_int32(ctx, obj, "roundingIncrement", s->roundingIncrement) < 0 ||
+ js_add_prop_str(ctx, obj, "roundingMode", pr_roundingmode_names[s->roundingMode]) < 0 ||
+ js_add_prop_str(ctx, obj, "roundingPriority", pr_roundingpriority_names[s->roundingPriority]) < 0 ||
+ js_add_prop_str(ctx, obj, "trailingZeroDisplay", pr_trailingzero_names[s->trailingZeroDisplay]) < 0)
+ goto fail;
+
+ return obj;
+fail:
+ JS_FreeValue(ctx, obj);
+ return JS_EXCEPTION;
+}
+
+static JSValue js_pluralrules_supportedLocalesOf(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ return js_intl_supportedLocalesOf(ctx, this_val, argc, argv);
+}
+
+static const JSCFunctionListEntry js_pluralrules_proto_funcs[] = {
+ JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Intl.PluralRules", JS_PROP_CONFIGURABLE),
+ JS_CFUNC_DEF("select", 1, js_pluralrules_select),
+ JS_CFUNC_DEF("selectRange", 2, js_pluralrules_selectRange),
+ JS_CFUNC_DEF("resolvedOptions", 0, js_pluralrules_resolvedOptions),
+};
+
+static const JSCFunctionListEntry js_pluralrules_static_funcs[] = {
+ JS_CFUNC_DEF("supportedLocalesOf", 1, js_pluralrules_supportedLocalesOf),
+};
+
+int js_add_pluralrules(JSContext *ctx, JSValue intl_obj)
+{
+ JS_NewClassID(&js_pluralrules_class_id);
+ JS_NewClass(JS_GetRuntime(ctx), js_pluralrules_class_id, &js_pluralrules_class);
+
+ if (JS_IsException(js_intl_new_constructor(ctx, intl_obj,
+ -1,
+ js_pluralrules_class_id, "PluralRules",
+ (JSCFunction *)js_pluralrules_constructor, 0,
+ JS_CFUNC_constructor, 0,
+ js_pluralrules_static_funcs, countof(js_pluralrules_static_funcs),
+ js_pluralrules_proto_funcs, countof(js_pluralrules_proto_funcs))))
+ return -1;
+
+ return 0;
+}
--- /dev/null
+/*
+ * QuickJS Intl.RelativeTimeFormat implementation
+ */
+
+#include <string.h>
+#include <math.h>
+
+#include "../quickjs.h"
+#include "../cutils.h"
+#include "intl_private.h"
+
+static int is_valid_locale_type(const char *str)
+{
+ int seg_len = 0;
+ const char *p = str;
+ while (*p) {
+ if ((*p >= '0' && *p <= '9') || (*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z')) {
+ seg_len++;
+ if (seg_len > 8)
+ return 0;
+ p++;
+ } else if (*p == '-') {
+ if (seg_len < 3 || seg_len > 8)
+ return 0;
+ seg_len = 0;
+ p++;
+ } else {
+ return 0;
+ }
+ }
+ if (seg_len < 3 || seg_len > 8)
+ return 0;
+ return 1;
+}
+
+static JSClassID js_relativetimeformat_class_id;
+
+typedef struct {
+ char *locale;
+ char *locale_canonical;
+ int numberingSystem;
+ int has_numberingSystem_option;
+ char *style;
+ char *numeric;
+} JSRelativeTimeFormatData;
+
+static void js_relativetimeformat_finalizer(JSRuntime *rt, JSValue val)
+{
+ JSRelativeTimeFormatData *s = JS_GetOpaque(val, js_relativetimeformat_class_id);
+ if (s) {
+ js_free_rt(rt, s->locale);
+ js_free_rt(rt, s->locale_canonical);
+ js_free_rt(rt, s->style);
+ js_free_rt(rt, s->numeric);
+ js_free_rt(rt, s);
+ }
+}
+
+static JSClassDef js_relativetimeformat_class = {
+ "RelativeTimeFormat",
+ .finalizer = js_relativetimeformat_finalizer,
+};
+
+static JSValue js_relativetimeformat_constructor(JSContext *ctx,
+ JSValueConst new_target,
+ int argc, JSValueConst *argv)
+{
+ JSRelativeTimeFormatData *s;
+ JSValue obj = JS_UNDEFINED;
+
+ s = js_mallocz(ctx, sizeof(*s));
+ if (!s)
+ return JS_EXCEPTION;
+
+ s->locale = js_strdup(ctx, "en-US");
+ s->numberingSystem = NS_LATN;
+ s->style = js_strdup(ctx, "long");
+ s->numeric = js_strdup(ctx, "always");
+
+ {
+ char *loc = js_intl_extract_locale(ctx, argc, argv);
+ if (!loc)
+ goto fail;
+ js_free(ctx, s->locale);
+ s->locale = loc;
+ }
+
+ /* Save canonical locale with extensions for resolvedOptions, and extract
+ numberingSystem from the Unicode extension. */
+ {
+ char *canonical = NULL;
+ if (js_canonicalizeLocaleList_first(ctx, argc > 0 ? argv[0] : JS_UNDEFINED, &canonical) < 0)
+ goto fail;
+ s->locale_canonical = canonical;
+ if (canonical) {
+ char *ns_str = js_intl_locale_get_numbering_system(ctx, canonical);
+ if (ns_str) {
+ int ns = js_intl_string_to_numbering_system(ns_str);
+ if (ns != NS_UNKNOWN)
+ s->numberingSystem = ns;
+ js_free(ctx, ns_str);
+ }
+ }
+ }
+
+ if (argc > 1 && !JS_IsUndefined(argv[1])) {
+ JSValue options = JS_ToObject(ctx, argv[1]);
+ if (JS_IsException(options))
+ goto fail;
+ /* localeMatcher (read for spec order) */
+ {
+ JSValue v = JS_GetPropertyStr(ctx, options, "localeMatcher");
+ if (JS_IsException(v)) {
+ JS_FreeValue(ctx, options);
+ goto fail;
+ }
+ if (!JS_IsUndefined(v)) {
+ const char *str = JS_ToCStringNZ(ctx, v);
+ JS_FreeValue(ctx, v);
+ if (!str) {
+ JS_FreeValue(ctx, options);
+ goto fail;
+ }
+ if (strcmp(str, "lookup") && strcmp(str, "best fit")) {
+ JS_ThrowRangeError(ctx, "invalid localeMatcher option");
+ JS_FreeCString(ctx, str);
+ JS_FreeValue(ctx, options);
+ goto fail;
+ }
+ JS_FreeCString(ctx, str);
+ } else {
+ JS_FreeValue(ctx, v);
+ }
+ }
+ /* numberingSystem (read for spec order) */
+ {
+ JSValue v = JS_GetPropertyStr(ctx, options, "numberingSystem");
+ if (JS_IsException(v)) {
+ JS_FreeValue(ctx, options);
+ goto fail;
+ }
+ if (!JS_IsUndefined(v)) {
+ const char *str = JS_ToCStringNZ(ctx, v);
+ JS_FreeValue(ctx, v);
+ if (!str) {
+ JS_FreeValue(ctx, options);
+ goto fail;
+ }
+ if (!is_valid_locale_type(str)) {
+ JS_ThrowRangeError(ctx, "invalid numberingSystem option");
+ JS_FreeCString(ctx, str);
+ JS_FreeValue(ctx, options);
+ goto fail;
+ }
+ {
+ int ns = js_intl_string_to_numbering_system(str);
+ if (ns != NS_UNKNOWN) {
+ s->has_numberingSystem_option = 1;
+ s->numberingSystem = ns;
+ }
+ }
+ JS_FreeCString(ctx, str);
+ } else {
+ JS_FreeValue(ctx, v);
+ }
+ }
+ {
+ JSValue v = JS_GetPropertyStr(ctx, options, "style");
+ if (JS_IsException(v)) {
+ JS_FreeValue(ctx, options);
+ goto fail;
+ }
+ if (!JS_IsUndefined(v)) {
+ const char *str = JS_ToCStringNZ(ctx, v);
+ JS_FreeValue(ctx, v);
+ if (!str) {
+ JS_FreeValue(ctx, options);
+ goto fail;
+ }
+ if (strcmp(str, "long") && strcmp(str, "short") && strcmp(str, "narrow")) {
+ JS_ThrowRangeError(ctx, "invalid style option");
+ JS_FreeCString(ctx, str);
+ JS_FreeValue(ctx, options);
+ goto fail;
+ }
+ js_free(ctx, s->style);
+ s->style = js_strdup(ctx, str);
+ JS_FreeCString(ctx, str);
+ if (!s->style) {
+ JS_FreeValue(ctx, options);
+ goto fail;
+ }
+ } else {
+ JS_FreeValue(ctx, v);
+ }
+ }
+ {
+ JSValue v = JS_GetPropertyStr(ctx, options, "numeric");
+ if (JS_IsException(v)) {
+ JS_FreeValue(ctx, options);
+ goto fail;
+ }
+ if (!JS_IsUndefined(v)) {
+ const char *str = JS_ToCStringNZ(ctx, v);
+ JS_FreeValue(ctx, v);
+ if (!str) {
+ JS_FreeValue(ctx, options);
+ goto fail;
+ }
+ if (strcmp(str, "always") && strcmp(str, "auto")) {
+ JS_ThrowRangeError(ctx, "invalid numeric option");
+ JS_FreeCString(ctx, str);
+ JS_FreeValue(ctx, options);
+ goto fail;
+ }
+ js_free(ctx, s->numeric);
+ s->numeric = js_strdup(ctx, str);
+ JS_FreeCString(ctx, str);
+ if (!s->numeric) {
+ JS_FreeValue(ctx, options);
+ goto fail;
+ }
+ } else {
+ JS_FreeValue(ctx, v);
+ }
+ }
+ JS_FreeValue(ctx, options);
+ }
+
+ /* Rebuild locale with preserved Unicode extensions */
+ if (s->locale_canonical) {
+ int preserve_nu = 0;
+
+ if (js_intl_locale_has_key(s->locale_canonical, "nu")) {
+ char *ext_val = js_intl_locale_get_unicode_key(ctx, s->locale_canonical, "nu");
+ if (ext_val) {
+ int ext_ns = js_intl_string_to_numbering_system(ext_val);
+ if (!s->has_numberingSystem_option || ext_ns == s->numberingSystem)
+ preserve_nu = 1;
+ js_free(ctx, ext_val);
+ }
+ }
+
+ if (preserve_nu) {
+ DynBuf db;
+ js_intl_dbuf_init(ctx, &db);
+ dbuf_putstr(&db, s->locale);
+ dbuf_put(&db, (uint8_t *)"-u", 2);
+ {
+ char *v = js_intl_locale_get_unicode_key(ctx, s->locale_canonical, "nu");
+ if (v) {
+ dbuf_put(&db, (uint8_t *)"-nu-", 4);
+ dbuf_putstr(&db, v);
+ js_free(ctx, v);
+ }
+ }
+ dbuf_put(&db, (uint8_t *)"", 1);
+ if (dbuf_error(&db)) {
+ dbuf_free(&db);
+ return JS_EXCEPTION;
+ }
+ js_free(ctx, s->locale);
+ s->locale = js_strdup(ctx, (char *)db.buf);
+ dbuf_free(&db);
+ }
+ }
+
+ obj = JS_CreateFromConstructor(ctx, new_target, js_relativetimeformat_class_id);
+ if (JS_IsException(obj))
+ goto fail;
+ JS_SetOpaque(obj, s);
+ return obj;
+ fail:
+ if (s->locale) js_free(ctx, s->locale);
+ if (s->locale_canonical) js_free(ctx, s->locale_canonical);
+ if (s->style) js_free(ctx, s->style);
+ if (s->numeric) js_free(ctx, s->numeric);
+ js_free(ctx, s);
+ JS_FreeValue(ctx, obj);
+ return JS_EXCEPTION;
+}
+
+static const char *relativetimeformat_units[] = {
+ "second", "minute", "hour", "day", "week", "month", "quarter", "year"
+};
+
+static int js_relativetimeformat_validate(JSContext *ctx, int argc, JSValueConst *argv,
+ double *pvalue, char *unit_buf, int unit_buf_size)
+{
+ double d;
+ int valid = 0;
+ int i;
+ const char *str;
+
+ /* ToNumber(value) */
+ if (JS_ToFloat64(ctx, &d, argv[0]) < 0)
+ return -1;
+ if (!isfinite(d))
+ return JS_ThrowRangeError(ctx, "invalid value"), -1;
+ *pvalue = d;
+
+ /* Validate unit */
+ {
+ size_t slen;
+ str = JS_ToCStringLen(ctx, &slen, argv[1]);
+ if (!str)
+ return -1;
+ if (strlen(str) != slen) {
+ JS_FreeCString(ctx, str);
+ goto invalid_unit;
+ }
+ pstrcpy(unit_buf, unit_buf_size, str);
+ JS_FreeCString(ctx, str);
+ }
+
+ /* normalize plural forms to singular by stripping trailing 's' */
+ {
+ int len = (int)strlen(unit_buf);
+ if (len > 0 && unit_buf[len - 1] == 's') {
+ unit_buf[len - 1] = '\0';
+ len--;
+ }
+ }
+
+ for (i = 0; i < (int)countof(relativetimeformat_units); i++) {
+ if (!strcmp(unit_buf, relativetimeformat_units[i])) {
+ valid = 1;
+ break;
+ }
+ }
+ if (!valid)
+ goto invalid_unit;
+ return 0;
+
+invalid_unit:
+ return JS_ThrowRangeError(ctx, "invalid unit"), -1;
+}
+
+/* --- Relative time formatting helpers --- */
+
+static int rtf_unit_idx(const char *unit)
+{
+ int i;
+ for (i = 0; i < (int)countof(relativetimeformat_units); i++) {
+ if (!strcmp(unit, relativetimeformat_units[i]))
+ return i;
+ }
+ return -1;
+}
+
+static int rtf_plural_en(double n)
+{
+ double abs_n = n < 0 ? -n : n;
+ if (abs_n == 1.0) return PLURAL_ONE;
+ return PLURAL_OTHER;
+}
+
+static int rtf_plural_pl(double n)
+{
+ double abs_n = n < 0 ? -n : n;
+ int int_n = (int)abs_n;
+ if (abs_n != int_n) return PLURAL_OTHER;
+ if (int_n == 1) return PLURAL_ONE;
+ if (int_n % 10 >= 2 && int_n % 10 <= 4 && (int_n % 100 < 12 || int_n % 100 > 14))
+ return PLURAL_FEW;
+ return PLURAL_MANY;
+}
+
+/* --- Locale-specific unit tables for RelativeTimeFormat --- */
+/* Unit order: second, minute, hour, day, week, month, quarter, year */
+/* Each entry: { one, other } */
+
+typedef struct {
+ const char *locale;
+ const char *long_one[8];
+ const char *long_other[8];
+ const char *short_one[8];
+ const char *short_other[8];
+ const char *future_prefix;
+ const char *future_suffix;
+ const char *past_prefix;
+ const char *past_suffix;
+} RTFLocaleUnits;
+
+static const RTFLocaleUnits rtf_en = {
+ "en",
+ {"second","minute","hour","day","week","month","quarter","year"},
+ {"seconds","minutes","hours","days","weeks","months","quarters","years"},
+ {"sec.","min.","hr.","day","wk.","mo.","qtr.","yr."},
+ {"sec.","min.","hr.","days","wk.","mo.","qtrs.","yr."},
+ "in ", "", "", " ago"
+};
+
+static const RTFLocaleUnits rtf_de = {
+ "de",
+ {"Sekunde","Minute","Stunde","Tag","Woche","Monat","Quartal","Jahr"},
+ {"Sekunden","Minuten","Stunden","Tagen","Wochen","Monaten","Quartalen","Jahren"},
+ {"Sek.","Min.","Std.","Tag","Wo.","Mon.","Quart.","J."},
+ {"Sek.","Min.","Std.","Tagen","Wo.","Mon.","Quart.","J."},
+ "in ", "", "vor ", ""
+};
+
+static const RTFLocaleUnits rtf_fr = {
+ "fr",
+ {"seconde","minute","heure","jour","semaine","mois","trimestre","an"},
+ {"secondes","minutes","heures","jours","semaines","mois","trimestres","ans"},
+ {"s","min","h","j","sem.","mois","trim.","an"},
+ {"s","min","h","j","sem.","mois","trim.","ans"},
+ "dans ", "", "il y a ", ""
+};
+
+static const RTFLocaleUnits rtf_es = {
+ "es",
+ {"segundo","minuto","hora","día","semana","mes","trimestre","año"},
+ {"segundos","minutos","horas","días","semanas","meses","trimestres","años"},
+ {"sg","min","h","d","sem.","m.","trim.","a."},
+ {"sg","min","h","d","sem.","m.","trim.","a."},
+ "dentro de ", "", "hace ", ""
+};
+
+static const RTFLocaleUnits rtf_ja = {
+ "ja",
+ {"秒","分","時間","日","週間","か月","四半期","年"},
+ {"秒","分","時間","日","週間","か月","四半期","年"},
+ {"秒","分","時間","日","週間","か月","四半期","年"},
+ {"秒","分","時間","日","週間","か月","四半期","年"},
+ "", "後", "", "前"
+};
+
+static const RTFLocaleUnits rtf_zh = {
+ "zh",
+ {"秒","分钟","小时","天","周","个月","个季度","年"},
+ {"秒","分钟","小时","天","周","个月","个季度","年"},
+ {"秒","分钟","小时","天","周","个月","个季度","年"},
+ {"秒","分钟","小时","天","周","个月","个季度","年"},
+ "", "后", "", "前"
+};
+
+static const RTFLocaleUnits rtf_pl = {
+ "pl",
+ {"sekunda","minuta","godzina","dzień","tydzień","miesiąc","kwartał","rok"},
+ {"sekundy","minuty","godziny","dni","tygodnie","miesiące","kwartały","lata"},
+ {"sek.","min.","godz.","dzień","tydz.","mies.","kw.","r."},
+ {"sek.","min.","godz.","dni","tydz.","mies.","kw.","r."},
+ "za ", "", "", " temu"
+};
+
+static const RTFLocaleUnits rtf_ru = {
+ "ru",
+ {"секунда","минута","час","день","неделя","месяц","квартал","год"},
+ {"секунды","минуты","часа","дня","недели","месяца","квартала","года"},
+ {"с","мин","ч","д","нед.","мес.","кв.","г."},
+ {"с","мин","ч","д","нед.","мес.","кв.","г."},
+ "через ", "", "", " назад"
+};
+
+static const RTFLocaleUnits rtf_pt = {
+ "pt",
+ {"segundo","minuto","hora","dia","semana","mês","trimestre","ano"},
+ {"segundos","minutos","horas","dias","semanas","meses","trimestres","anos"},
+ {"seg.","min.","h.","dia","sem.","mês","trim.","a."},
+ {"seg.","min.","h.","dias","sem.","meses","trim.","a."},
+ "em ", "", "há ", ""
+};
+
+static const RTFLocaleUnits rtf_ko = {
+ "ko",
+ {"초","분","시간","일","주","개월","분기","년"},
+ {"초","분","시간","일","주","개월","분기","년"},
+ {"초","분","시간","일","주","개월","분기","년"},
+ {"초","분","시간","일","주","개월","분기","년"},
+ "", " 후", "", " 전"
+};
+
+static const RTFLocaleUnits rtf_it = {
+ "it",
+ {"secondo","minuto","ora","giorno","settimana","mese","trimestre","anno"},
+ {"secondi","minuti","ore","giorni","settimane","mesi","trimestri","anni"},
+ {"s","min","h","g","sett.","mese","trim.","a."},
+ {"s","min","h","g","sett.","mesi","trim.","a."},
+ "tra ", "", "", " fa"
+};
+
+static const RTFLocaleUnits *rtf_all_locales[] = {
+ &rtf_en, &rtf_de, &rtf_fr, &rtf_es, &rtf_ja, &rtf_zh, &rtf_pl, &rtf_ru, &rtf_pt, &rtf_ko, &rtf_it
+};
+
+static const RTFLocaleUnits *rtf_find_locale(const char *locale)
+{
+ int i;
+ for (i = 0; i < (int)countof(rtf_all_locales); i++) {
+ if (strstart(locale, rtf_all_locales[i]->locale, NULL))
+ return rtf_all_locales[i];
+ }
+ return &rtf_en;
+}
+
+static const char *rtf_auto_exception(const char *locale, int unit_idx, int ivalue)
+{
+ if (strstart(locale, "pl", NULL)) return NULL;
+
+ if (strstart(locale, "de", NULL)) {
+ if (ivalue == -1) {
+ switch (unit_idx) {
+ case 3: return "gestern";
+ case 4: return "letzte Woche";
+ case 5: return "letzten Monat";
+ case 7: return "letztes Jahr";
+ }
+ } else if (ivalue == 1) {
+ switch (unit_idx) {
+ case 3: return "morgen";
+ case 4: return "nächste Woche";
+ case 5: return "nächsten Monat";
+ case 7: return "nächstes Jahr";
+ }
+ }
+ return NULL;
+ }
+
+ if (strstart(locale, "fr", NULL)) {
+ if (ivalue == -1) {
+ switch (unit_idx) {
+ case 3: return "hier";
+ case 4: return "la semaine dernière";
+ case 5: return "le mois dernier";
+ case 7: return "l’année dernière";
+ }
+ } else if (ivalue == 1) {
+ switch (unit_idx) {
+ case 3: return "demain";
+ case 4: return "la semaine prochaine";
+ case 5: return "le mois prochain";
+ case 7: return "l’année prochaine";
+ }
+ }
+ return NULL;
+ }
+
+ if (strstart(locale, "es", NULL)) {
+ if (ivalue == -1) {
+ switch (unit_idx) {
+ case 3: return "ayer";
+ case 4: return "la semana pasada";
+ case 5: return "el mes pasado";
+ case 7: return "el año pasado";
+ }
+ } else if (ivalue == 1) {
+ switch (unit_idx) {
+ case 3: return "mañana";
+ case 4: return "la próxima semana";
+ case 5: return "el próximo mes";
+ case 7: return "el próximo año";
+ }
+ }
+ return NULL;
+ }
+
+ if (strstart(locale, "ja", NULL)) {
+ if (ivalue == -1) {
+ switch (unit_idx) {
+ case 3: return "昨日";
+ case 4: return "先週";
+ case 5: return "先月";
+ case 7: return "昨年";
+ }
+ } else if (ivalue == 1) {
+ switch (unit_idx) {
+ case 3: return "明日";
+ case 4: return "来週";
+ case 5: return "来月";
+ case 7: return "来年";
+ }
+ }
+ return NULL;
+ }
+
+ /* English auto exceptions */
+ if (ivalue == 0) {
+ switch (unit_idx) {
+ case 0: return "now";
+ case 1: return "this minute";
+ case 2: return "this hour";
+ case 3: return "today";
+ case 4: return "this week";
+ case 5: return "this month";
+ case 6: return "this quarter";
+ case 7: return "this year";
+ }
+ } else if (ivalue == 1) {
+ switch (unit_idx) {
+ case 3: return "tomorrow";
+ case 4: return "next week";
+ case 5: return "next month";
+ case 6: return "next quarter";
+ case 7: return "next year";
+ }
+ } else if (ivalue == -1) {
+ switch (unit_idx) {
+ case 3: return "yesterday";
+ case 4: return "last week";
+ case 5: return "last month";
+ case 6: return "last quarter";
+ case 7: return "last year";
+ }
+ }
+ return NULL;
+}
+
+static const char *rtf_unit_form(const char *locale, const char *style, int unit_idx, int plural)
+{
+ const RTFLocaleUnits *lu = rtf_find_locale(locale);
+ int is_short = !strcmp(style, "short");
+ int is_narrow = !strcmp(style, "narrow");
+ int is_one = (plural == PLURAL_ONE);
+
+ if (strstart(locale, "pl", NULL) && !is_short && !is_narrow) {
+ /* Polish has few/many forms not in the simple table */
+ switch (unit_idx) {
+ case 0:
+ if (is_one) return "sekundę";
+ if (plural == PLURAL_FEW) return "sekundy";
+ if (plural == PLURAL_MANY) return "sekund";
+ return "sekundy";
+ case 1:
+ if (is_one) return "minutę";
+ if (plural == PLURAL_FEW) return "minuty";
+ if (plural == PLURAL_MANY) return "minut";
+ return "minuty";
+ case 2:
+ if (is_one) return "godzinę";
+ if (plural == PLURAL_FEW) return "godziny";
+ if (plural == PLURAL_MANY) return "godzin";
+ return "godziny";
+ case 3:
+ if (is_one) return "dzień";
+ if (plural == PLURAL_FEW) return "dni";
+ if (plural == PLURAL_MANY) return "dni";
+ return "dnia";
+ case 4:
+ if (is_one) return "tydzień";
+ if (plural == PLURAL_FEW) return "tygodnie";
+ if (plural == PLURAL_MANY) return "tygodni";
+ return "tygodnia";
+ case 5:
+ if (is_one) return "miesiąc";
+ if (plural == PLURAL_FEW) return "miesiące";
+ if (plural == PLURAL_MANY) return "miesięcy";
+ return "miesiąca";
+ case 6:
+ if (is_one) return "kwartał";
+ if (plural == PLURAL_FEW) return "kwartały";
+ if (plural == PLURAL_MANY) return "kwartałów";
+ return "kwartału";
+ case 7:
+ if (is_one) return "rok";
+ if (plural == PLURAL_FEW) return "lata";
+ if (plural == PLURAL_MANY) return "lat";
+ return "roku";
+ }
+ return "";
+ }
+
+ if (is_narrow && strstart(locale, "en", NULL)) {
+ static const char *en_narrow[8] = {"s","m","h","d","w","mo","q","y"};
+ return en_narrow[unit_idx];
+ }
+
+ if (is_short || is_narrow) {
+ if (strstart(locale, "pl", NULL)) {
+ if (unit_idx == 3) {
+ if (is_one) return "dzień";
+ if (plural == PLURAL_FEW || plural == PLURAL_MANY) return "dni";
+ return "dnia";
+ }
+ if (unit_idx == 4) {
+ if (is_one) return is_narrow ? "tydz." : "tydz.";
+ return "tyg.";
+ }
+ if (unit_idx == 7) {
+ if (is_one) return "rok";
+ if (plural == PLURAL_FEW) return "lata";
+ if (plural == PLURAL_MANY) return "lat";
+ return "roku";
+ }
+ if (is_narrow) {
+ static const char *pl_narrow[8] = {"s","min","g.","d","tyg.","mies.","kw.","lat"};
+ return pl_narrow[unit_idx];
+ } else {
+ static const char *pl_short[8] = {"sek.","min","godz.","dni","tyg.","mies.","kw.","lat"};
+ return pl_short[unit_idx];
+ }
+ }
+ return is_one ? lu->short_one[unit_idx] : lu->short_other[unit_idx];
+ }
+
+ return is_one ? lu->long_one[unit_idx] : lu->long_other[unit_idx];
+}
+
+static JSValue rtf_format_number_value(JSContext *ctx, JSRelativeTimeFormatData *s, double value)
+{
+ JSValue argv[2];
+ JSValue ret;
+
+ argv[0] = JS_NewString(ctx, s->locale);
+ if (JS_IsException(argv[0]))
+ return argv[0];
+
+ argv[1] = JS_NewObject(ctx);
+ if (JS_IsException(argv[1])) {
+ JS_FreeValue(ctx, argv[0]);
+ return argv[1];
+ }
+
+ JS_SetPropertyStr(ctx, argv[1], "numberingSystem", JS_NewString(ctx, js_intl_numbering_system_to_string(s->numberingSystem)));
+ /* Some locales use min2 grouping by default (e.g. Polish) */
+ if (strstart(s->locale, "pl", NULL)) {
+ JS_SetPropertyStr(ctx, argv[1], "useGrouping", JS_NewString(ctx, "min2"));
+ }
+
+ ret = js_numberformat_format_number(ctx, value, 2, argv);
+ JS_FreeValue(ctx, argv[0]);
+ JS_FreeValue(ctx, argv[1]);
+ return ret;
+}
+
+static int rtf_add_number_parts(JSContext *ctx, JSValue arr, int *pidx, const char *num_str,
+ const char *unit_name, const char *decimal_sep, const char *group_sep)
+{
+ const char *p = num_str;
+ int decimal_len = decimal_sep ? (int)strlen(decimal_sep) : 0;
+ int group_len = group_sep ? (int)strlen(group_sep) : 0;
+ int in_fraction = 0;
+
+ while (*p) {
+ if (group_len > 0 && !memcmp(p, group_sep, (size_t)group_len)) {
+ JSValue part = JS_NewObject(ctx);
+ if (JS_IsException(part)) return -1;
+ JS_SetPropertyStr(ctx, part, "type", JS_NewString(ctx, "group"));
+ JS_SetPropertyStr(ctx, part, "value", JS_NewStringLen(ctx, p, (size_t)group_len));
+ JS_SetPropertyStr(ctx, part, "unit", JS_NewString(ctx, unit_name));
+ JS_DefinePropertyValueUint32(ctx, arr, (uint32_t)(*pidx)++, part, JS_PROP_C_W_E);
+ p += group_len;
+ } else if (decimal_len > 0 && !memcmp(p, decimal_sep, (size_t)decimal_len)) {
+ JSValue part = JS_NewObject(ctx);
+ if (JS_IsException(part)) return -1;
+ JS_SetPropertyStr(ctx, part, "type", JS_NewString(ctx, "decimal"));
+ JS_SetPropertyStr(ctx, part, "value", JS_NewStringLen(ctx, p, (size_t)decimal_len));
+ JS_SetPropertyStr(ctx, part, "unit", JS_NewString(ctx, unit_name));
+ JS_DefinePropertyValueUint32(ctx, arr, (uint32_t)(*pidx)++, part, JS_PROP_C_W_E);
+ p += decimal_len;
+ in_fraction = 1;
+ } else if (*p >= '0' && *p <= '9') {
+ const char *start = p;
+ while (*p >= '0' && *p <= '9') p++;
+ {
+ JSValue part = JS_NewObject(ctx);
+ if (JS_IsException(part)) return -1;
+ JS_SetPropertyStr(ctx, part, "type", JS_NewString(ctx, in_fraction ? "fraction" : "integer"));
+ JS_SetPropertyStr(ctx, part, "value", JS_NewStringLen(ctx, start, (size_t)(p - start)));
+ JS_SetPropertyStr(ctx, part, "unit", JS_NewString(ctx, unit_name));
+ JS_DefinePropertyValueUint32(ctx, arr, (uint32_t)(*pidx)++, part, JS_PROP_C_W_E);
+ }
+ } else {
+ p++;
+ }
+ }
+ return 0;
+}
+
+static JSValue js_relativetimeformat_format(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSRelativeTimeFormatData *s = JS_GetOpaque2(ctx, this_val, js_relativetimeformat_class_id);
+ double value;
+ char unit_buf[16];
+ JSValue num_val;
+ const char *num_str;
+ const char *unit_str;
+ const char *auto_exc;
+ const char *fut_pre, *fut_suf, *past_pre, *past_suf;
+ int plural;
+ int unit_idx;
+ int ivalue;
+ DynBuf db;
+
+ if (!s)
+ return JS_EXCEPTION;
+ if (js_relativetimeformat_validate(ctx, argc, argv, &value, unit_buf, sizeof(unit_buf)) < 0)
+ return JS_EXCEPTION;
+
+ unit_idx = rtf_unit_idx(unit_buf);
+ if (unit_idx < 0)
+ return JS_ThrowRangeError(ctx, "invalid unit"), JS_EXCEPTION;
+
+ ivalue = 999;
+ if (value == 1.0) ivalue = 1;
+ else if (value == -1.0) ivalue = -1;
+ else if (value == 0.0) ivalue = 0;
+
+ /* Check auto exceptions */
+ if (!strcmp(s->numeric, "auto") && (ivalue == -1 || ivalue == 0 || ivalue == 1)) {
+ auto_exc = rtf_auto_exception(s->locale, unit_idx, ivalue);
+ if (auto_exc)
+ return JS_NewString(ctx, auto_exc);
+ }
+
+ /* Determine plural */
+ if (strstart(s->locale, "pl", NULL))
+ plural = rtf_plural_pl(value);
+ else
+ plural = rtf_plural_en(value);
+
+ unit_str = rtf_unit_form(s->locale, s->style, unit_idx, plural);
+
+ {
+ const RTFLocaleUnits *lu = rtf_find_locale(s->locale);
+ fut_pre = lu->future_prefix;
+ fut_suf = lu->future_suffix;
+ past_pre = lu->past_prefix;
+ past_suf = lu->past_suffix;
+ }
+
+ /* Format the absolute number */
+ {
+ double abs_val = value < 0 ? -value : value;
+ if (value == 0.0) abs_val = 0.0;
+ num_val = rtf_format_number_value(ctx, s, abs_val);
+ if (JS_IsException(num_val))
+ return num_val;
+ }
+
+ num_str = JS_ToCString(ctx, num_val);
+ if (!num_str) {
+ JS_FreeValue(ctx, num_val);
+ return JS_EXCEPTION;
+ }
+
+ js_intl_dbuf_init(ctx, &db);
+ if (value > 0 || (value == 0.0 && !signbit(value))) {
+ dbuf_putstr(&db, fut_pre);
+ dbuf_putstr(&db, num_str);
+ dbuf_putc(&db, ' ');
+ dbuf_putstr(&db, unit_str);
+ dbuf_putstr(&db, fut_suf);
+ } else {
+ dbuf_putstr(&db, past_pre);
+ dbuf_putstr(&db, num_str);
+ dbuf_putc(&db, ' ');
+ dbuf_putstr(&db, unit_str);
+ dbuf_putstr(&db, past_suf);
+ }
+ dbuf_putc(&db, '\0');
+ if (dbuf_error(&db)) {
+ dbuf_free(&db);
+ JS_FreeCString(ctx, num_str);
+ JS_FreeValue(ctx, num_val);
+ return JS_EXCEPTION;
+ }
+
+ JS_FreeCString(ctx, num_str);
+ JS_FreeValue(ctx, num_val);
+
+ {
+ JSValue ret = JS_NewString(ctx, (char *)db.buf);
+ dbuf_free(&db);
+ return ret;
+ }
+}
+
+static JSValue js_relativetimeformat_formatToParts(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSRelativeTimeFormatData *s = JS_GetOpaque2(ctx, this_val, js_relativetimeformat_class_id);
+ double value;
+ char unit_buf[16];
+ JSValue arr, num_val;
+ const char *num_str;
+ const char *unit_str;
+ const char *auto_exc;
+ const char *fut_pre, *fut_suf, *past_pre, *past_suf;
+ int plural;
+ const LocaleData *ldata;
+ int unit_idx;
+ int ivalue;
+ int idx = 0;
+
+ if (!s)
+ return JS_EXCEPTION;
+ if (js_relativetimeformat_validate(ctx, argc, argv, &value, unit_buf, sizeof(unit_buf)) < 0)
+ return JS_EXCEPTION;
+
+ arr = JS_NewArray(ctx);
+ if (JS_IsException(arr))
+ return arr;
+
+ unit_idx = rtf_unit_idx(unit_buf);
+ if (unit_idx < 0) {
+ JS_FreeValue(ctx, arr);
+ return JS_ThrowRangeError(ctx, "invalid unit"), JS_EXCEPTION;
+ }
+
+ ivalue = 999;
+ if (value == 1.0) ivalue = 1;
+ else if (value == -1.0) ivalue = -1;
+ else if (value == 0.0) ivalue = 0;
+
+ /* Check auto exceptions */
+ if (!strcmp(s->numeric, "auto") && (ivalue == -1 || ivalue == 0 || ivalue == 1)) {
+ auto_exc = rtf_auto_exception(s->locale, unit_idx, ivalue);
+ if (auto_exc) {
+ JSValue part = JS_NewObject(ctx);
+ if (JS_IsException(part)) {
+ JS_FreeValue(ctx, arr);
+ return part;
+ }
+ JS_SetPropertyStr(ctx, part, "type", JS_NewString(ctx, "literal"));
+ JS_SetPropertyStr(ctx, part, "value", JS_NewString(ctx, auto_exc));
+ JS_DefinePropertyValueUint32(ctx, arr, (uint32_t)idx++, part, JS_PROP_C_W_E);
+ return arr;
+ }
+ }
+
+ /* Determine plural */
+ if (strstart(s->locale, "pl", NULL))
+ plural = rtf_plural_pl(value);
+ else
+ plural = rtf_plural_en(value);
+
+ unit_str = rtf_unit_form(s->locale, s->style, unit_idx, plural);
+ ldata = js_intl_find_locale_data(s->locale);
+
+ {
+ const RTFLocaleUnits *lu = rtf_find_locale(s->locale);
+ fut_pre = lu->future_prefix;
+ fut_suf = lu->future_suffix;
+ past_pre = lu->past_prefix;
+ past_suf = lu->past_suffix;
+ }
+
+ /* Format the absolute number */
+ {
+ double abs_val = value < 0 ? -value : value;
+ if (value == 0.0) abs_val = 0.0;
+ num_val = rtf_format_number_value(ctx, s, abs_val);
+ if (JS_IsException(num_val)) {
+ JS_FreeValue(ctx, arr);
+ return num_val;
+ }
+ }
+
+ num_str = JS_ToCString(ctx, num_val);
+ if (!num_str) {
+ JS_FreeValue(ctx, num_val);
+ JS_FreeValue(ctx, arr);
+ return JS_EXCEPTION;
+ }
+
+ if (value > 0 || (value == 0.0 && !signbit(value))) {
+ if (fut_pre[0]) {
+ JSValue part = JS_NewObject(ctx);
+ if (!JS_IsException(part)) {
+ JS_SetPropertyStr(ctx, part, "type", JS_NewString(ctx, "literal"));
+ JS_SetPropertyStr(ctx, part, "value", JS_NewString(ctx, fut_pre));
+ JS_DefinePropertyValueUint32(ctx, arr, (uint32_t)idx++, part, JS_PROP_C_W_E);
+ }
+ }
+ if (rtf_add_number_parts(ctx, arr, &idx, num_str, unit_buf,
+ NS_DECIMAL(ldata->symbols), NS_GROUP(ldata->symbols)) < 0) {
+ JS_FreeCString(ctx, num_str);
+ JS_FreeValue(ctx, num_val);
+ JS_FreeValue(ctx, arr);
+ return JS_EXCEPTION;
+ }
+ {
+ char lit_buf[64];
+ snprintf(lit_buf, sizeof(lit_buf), " %s%s", unit_str, fut_suf);
+ {
+ JSValue part = JS_NewObject(ctx);
+ if (!JS_IsException(part)) {
+ JS_SetPropertyStr(ctx, part, "type", JS_NewString(ctx, "literal"));
+ JS_SetPropertyStr(ctx, part, "value", JS_NewString(ctx, lit_buf));
+ JS_DefinePropertyValueUint32(ctx, arr, (uint32_t)idx++, part, JS_PROP_C_W_E);
+ }
+ }
+ }
+ } else {
+ if (past_pre[0]) {
+ JSValue part = JS_NewObject(ctx);
+ if (!JS_IsException(part)) {
+ JS_SetPropertyStr(ctx, part, "type", JS_NewString(ctx, "literal"));
+ JS_SetPropertyStr(ctx, part, "value", JS_NewString(ctx, past_pre));
+ JS_DefinePropertyValueUint32(ctx, arr, (uint32_t)idx++, part, JS_PROP_C_W_E);
+ }
+ }
+ if (rtf_add_number_parts(ctx, arr, &idx, num_str, unit_buf,
+ NS_DECIMAL(ldata->symbols), NS_GROUP(ldata->symbols)) < 0) {
+ JS_FreeCString(ctx, num_str);
+ JS_FreeValue(ctx, num_val);
+ JS_FreeValue(ctx, arr);
+ return JS_EXCEPTION;
+ }
+ {
+ char lit_buf[64];
+ snprintf(lit_buf, sizeof(lit_buf), " %s%s", unit_str, past_suf);
+ {
+ JSValue part = JS_NewObject(ctx);
+ if (!JS_IsException(part)) {
+ JS_SetPropertyStr(ctx, part, "type", JS_NewString(ctx, "literal"));
+ JS_SetPropertyStr(ctx, part, "value", JS_NewString(ctx, lit_buf));
+ JS_DefinePropertyValueUint32(ctx, arr, (uint32_t)idx++, part, JS_PROP_C_W_E);
+ }
+ }
+ }
+ }
+
+ JS_FreeCString(ctx, num_str);
+ JS_FreeValue(ctx, num_val);
+ return arr;
+}
+
+static JSValue js_relativetimeformat_resolvedOptions(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSValue obj;
+ JSRelativeTimeFormatData *s = JS_GetOpaque2(ctx, this_val, js_relativetimeformat_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+
+ obj = JS_NewObject(ctx);
+ if (JS_IsException(obj))
+ return JS_EXCEPTION;
+
+ JS_DefinePropertyValueStr(ctx, obj, "locale",
+ JS_NewString(ctx, s->locale), JS_PROP_C_W_E);
+ JS_DefinePropertyValueStr(ctx, obj, "style",
+ JS_NewString(ctx, s->style), JS_PROP_C_W_E);
+ JS_DefinePropertyValueStr(ctx, obj, "numeric",
+ JS_NewString(ctx, s->numeric), JS_PROP_C_W_E);
+ JS_DefinePropertyValueStr(ctx, obj, "numberingSystem",
+ JS_NewString(ctx, js_intl_numbering_system_to_string(s->numberingSystem)), JS_PROP_C_W_E);
+
+ return obj;
+}
+
+static JSValue js_relativetimeformat_supportedLocalesOf(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ return js_intl_supportedLocalesOf(ctx, this_val, argc, argv);
+}
+
+static const JSCFunctionListEntry js_relativetimeformat_proto_funcs[] = {
+ JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Intl.RelativeTimeFormat", JS_PROP_CONFIGURABLE),
+ JS_CFUNC_DEF("format", 2, js_relativetimeformat_format),
+ JS_CFUNC_DEF("formatToParts", 2, js_relativetimeformat_formatToParts),
+ JS_CFUNC_DEF("resolvedOptions", 0, js_relativetimeformat_resolvedOptions),
+};
+
+static const JSCFunctionListEntry js_relativetimeformat_static_funcs[] = {
+ JS_CFUNC_DEF("supportedLocalesOf", 1, js_relativetimeformat_supportedLocalesOf),
+};
+
+int js_add_relativetimeformat(JSContext *ctx, JSValue intl_obj)
+{
+ JS_NewClassID(&js_relativetimeformat_class_id);
+ JS_NewClass(JS_GetRuntime(ctx), js_relativetimeformat_class_id, &js_relativetimeformat_class);
+
+ if (JS_IsException(js_intl_new_constructor(ctx, intl_obj,
+ -1,
+ js_relativetimeformat_class_id, "RelativeTimeFormat",
+ (JSCFunction *)js_relativetimeformat_constructor, 0,
+ JS_CFUNC_constructor, 0,
+ js_relativetimeformat_static_funcs, countof(js_relativetimeformat_static_funcs),
+ js_relativetimeformat_proto_funcs, countof(js_relativetimeformat_proto_funcs))))
+ return -1;
+
+ return 0;
+}
--- /dev/null
+/*
+ * QuickJS Intl.Segmenter implementation
+ */
+
+#include <string.h>
+#include <ctype.h>
+
+#include "../quickjs.h"
+#include "../cutils.h"
+#include "../libunicode.h"
+#include "intl_private.h"
+
+static JSClassID js_segmenter_class_id;
+static JSClassID js_segments_class_id;
+static JSClassID js_segment_iterator_class_id;
+
+enum {
+ GRANULARITY_GRAPHEME = 0,
+ GRANULARITY_WORD,
+ GRANULARITY_SENTENCE,
+};
+
+static const char *granularity_names[] = {
+ "grapheme", "word", "sentence"
+};
+
+typedef struct {
+ char *locale;
+ int granularity;
+} JSSegmenterData;
+
+typedef struct {
+ JSValue segmenter; /* strong ref */
+ JSValue string; /* strong ref */
+} JSSegmentsData;
+
+typedef struct {
+ JSValue segmenter; /* strong ref */
+ JSValue string; /* strong ref */
+ int next_index; /* next code unit index */
+} JSSegmentIteratorData;
+
+static void js_segmenter_finalizer(JSRuntime *rt, JSValue val)
+{
+ JSSegmenterData *s = JS_GetOpaque(val, js_segmenter_class_id);
+ if (s) {
+ js_free_rt(rt, s->locale);
+ js_free_rt(rt, s);
+ }
+}
+
+static void js_segments_finalizer(JSRuntime *rt, JSValue val)
+{
+ JSSegmentsData *s = JS_GetOpaque(val, js_segments_class_id);
+ if (s) {
+ JS_FreeValueRT(rt, s->segmenter);
+ JS_FreeValueRT(rt, s->string);
+ js_free_rt(rt, s);
+ }
+}
+
+static void js_segments_mark(JSRuntime *rt, JSValueConst val,
+ JS_MarkFunc *mark_func)
+{
+ JSSegmentsData *s = JS_GetOpaque(val, js_segments_class_id);
+ if (s) {
+ JS_MarkValue(rt, s->segmenter, mark_func);
+ JS_MarkValue(rt, s->string, mark_func);
+ }
+}
+
+static void js_segment_iterator_finalizer(JSRuntime *rt, JSValue val)
+{
+ JSSegmentIteratorData *s = JS_GetOpaque(val, js_segment_iterator_class_id);
+ if (s) {
+ JS_FreeValueRT(rt, s->segmenter);
+ JS_FreeValueRT(rt, s->string);
+ js_free_rt(rt, s);
+ }
+}
+
+static void js_segment_iterator_mark(JSRuntime *rt, JSValueConst val,
+ JS_MarkFunc *mark_func)
+{
+ JSSegmentIteratorData *s = JS_GetOpaque(val, js_segment_iterator_class_id);
+ if (s) {
+ JS_MarkValue(rt, s->segmenter, mark_func);
+ JS_MarkValue(rt, s->string, mark_func);
+ }
+}
+
+static JSClassDef js_segmenter_class = {
+ "Segmenter",
+ .finalizer = js_segmenter_finalizer,
+};
+
+static JSClassDef js_segments_class = {
+ "Segments",
+ .finalizer = js_segments_finalizer,
+ .gc_mark = js_segments_mark,
+};
+
+static JSClassDef js_segment_iterator_class = {
+ "SegmentIterator",
+ .finalizer = js_segment_iterator_finalizer,
+ .gc_mark = js_segment_iterator_mark,
+};
+
+/* --------------------------------------------------------------------- */
+/* Segmenter constructor */
+/* --------------------------------------------------------------------- */
+
+static JSValue js_segmenter_constructor(JSContext *ctx,
+ JSValueConst new_target,
+ int argc, JSValueConst *argv)
+{
+ JSSegmenterData *s;
+ JSValue obj = JS_UNDEFINED;
+ JSValue options = JS_UNDEFINED;
+ int granularity_idx;
+ s = js_mallocz(ctx, sizeof(*s));
+ if (!s)
+ return JS_EXCEPTION;
+
+ s->locale = js_strdup(ctx, "en-US");
+
+ {
+ static const char *available[] = {
+ "ar", "de", "en", "fr", "hi", "it", "ja", "ko", "sr", "zh"
+ };
+ char **locales = NULL;
+ int count = 0;
+ int k;
+ if (js_canonicalizeLocaleList_c(ctx, argc > 0 ? argv[0] : JS_UNDEFINED,
+ &locales, &count) < 0)
+ goto fail;
+ for (k = 0; k < count; k++) {
+ const char *str = locales[k];
+ size_t i;
+ for (i = 0; i < countof(available); i++) {
+ size_t alen = strlen(available[i]);
+ if (!strncmp(str, available[i], alen) &&
+ (str[alen] == '\0' || str[alen] == '-')) {
+ js_free(ctx, s->locale);
+ s->locale = js_strdup(ctx, str);
+ break;
+ }
+ }
+ if (i < countof(available))
+ break;
+ }
+ js_canonicalizeLocaleList_free_c(ctx, locales, count);
+ }
+
+ if (argc > 1 && !JS_IsUndefined(argv[1]))
+ options = JS_ToObject(ctx, argv[1]);
+ else
+ options = JS_NewObjectProto(ctx, JS_NULL);
+ if (JS_IsException(options))
+ goto fail;
+
+ /* Read localeMatcher first (spec order) */
+ {
+ int idx = js_intl_get_string_option(ctx, options, "localeMatcher",
+ intl_localeMatcher_names,
+ countof(intl_localeMatcher_names),
+ INTL_LOCALEMATCHER_BESTFIT);
+ if (idx < 0)
+ goto fail;
+ }
+
+ granularity_idx = js_intl_get_string_option(ctx, options, "granularity",
+ granularity_names,
+ countof(granularity_names),
+ GRANULARITY_GRAPHEME);
+ if (granularity_idx < 0)
+ goto fail;
+
+ JS_FreeValue(ctx, options);
+ options = JS_UNDEFINED;
+
+ s->granularity = granularity_idx;
+
+ obj = JS_CreateFromConstructor(ctx, new_target, js_segmenter_class_id);
+ if (JS_IsException(obj))
+ goto fail;
+ JS_SetOpaque(obj, s);
+ return obj;
+ fail:
+ JS_FreeValue(ctx, options);
+ if (s->locale) js_free(ctx, s->locale);
+ js_free(ctx, s);
+ JS_FreeValue(ctx, obj);
+ return JS_EXCEPTION;
+}
+
+/* --------------------------------------------------------------------- */
+/* Helper: create a segment data object */
+/* --------------------------------------------------------------------- */
+
+static JSValue create_segment_data(JSContext *ctx, JSValueConst str_val,
+ int index, int segment_len, int is_word_like,
+ int include_is_word_like)
+{
+ JSValue obj = JS_NewObject(ctx);
+ JSValue seg_str;
+ if (JS_IsException(obj))
+ return JS_EXCEPTION;
+
+ seg_str = js_sub_string_val(ctx, str_val, index, index + segment_len);
+ if (JS_IsException(seg_str)) {
+ JS_FreeValue(ctx, obj);
+ return JS_EXCEPTION;
+ }
+ JS_DefinePropertyValueStr(ctx, obj, "segment", seg_str, JS_PROP_C_W_E);
+ JS_DefinePropertyValueStr(ctx, obj, "index",
+ JS_NewInt32(ctx, index), JS_PROP_C_W_E);
+ {
+ JSValue input_str = JS_DupValue(ctx, str_val);
+ JS_DefinePropertyValueStr(ctx, obj, "input", input_str, JS_PROP_C_W_E);
+ }
+ if (include_is_word_like) {
+ JS_DefinePropertyValueStr(ctx, obj, "isWordLike",
+ JS_NewBool(ctx, is_word_like), JS_PROP_C_W_E);
+ }
+ return obj;
+}
+
+/* --------------------------------------------------------------------- */
+/* Segments helper: find segment boundaries */
+/* --------------------------------------------------------------------- */
+
+/* Returns 1 if c is "word-like" (letter, digit, non-ASCII, or some punct) */
+static int is_word_char(int c)
+{
+ return isalnum(c) || c > 127 ||
+ c == '.' || c == '-' || c == '+' ||
+ c == '%' || c == '$' || c == '_' || c == '\'';
+}
+
+/* Determine if a code point should be part of the current grapheme cluster.
+ Returns 1 if c combines with the preceding base or extender. */
+static int is_grapheme_extender(int prev_c, int c)
+{
+ if (unicode_get_cc((uint32_t)c) > 0)
+ return 1;
+ /* Thai vowels and marks with combining class 0 */
+ if ((c >= 0x0E31 && c <= 0x0E3A) || (c >= 0x0E47 && c <= 0x0E4E))
+ return 1;
+ /* Emoji skin tone modifiers */
+ if (c >= 0x1F3FB && c <= 0x1F3FF)
+ return 1;
+ /* Variation selectors */
+ if (c >= 0xFE00 && c <= 0xFE0F)
+ return 1;
+ /* ZWJ - combines to form emoji sequences */
+ if (c == 0x200D)
+ return 1;
+ /* After ZWJ, consume the next char (emoji sequence continuation) */
+ if (prev_c == 0x200D)
+ return 1;
+ /* Regional indicators form flag pairs */
+ if (prev_c >= 0x1F1E6 && prev_c <= 0x1F1FF &&
+ c >= 0x1F1E6 && c <= 0x1F1FF)
+ return 1;
+ return 0;
+}
+
+/* Get Hangul Jamo type: 0=none, 1=L, 2=V, 3=LV, 4=LVT, 5=T */
+static int hangul_jamo_type(int c)
+{
+ if (c >= 0x1100 && c <= 0x115F)
+ return 1; /* L */
+ if (c >= 0x1160 && c <= 0x11A7)
+ return 2; /* V */
+ if (c >= 0x11A8 && c <= 0x11FF)
+ return 5; /* T */
+ if (c >= 0xAC00 && c <= 0xD7A3) {
+ int t = (c - 0xAC00) % 28;
+ return t == 0 ? 3 : 4; /* LV or LVT */
+ }
+ return 0;
+}
+
+/* Check if two Hangul characters should be in the same cluster */
+static int hangul_combine(int prev_type, int type)
+{
+ if (prev_type == 1 && (type == 1 || type == 2 || type == 3 || type == 4)) /* L × (L|V|LV|LVT) */
+ return 1;
+ if (prev_type == 2 && (type == 2 || type == 5)) /* V × (V|T) */
+ return 1;
+ if (prev_type == 3 && (type == 2 || type == 5)) /* LV × (V|T) */
+ return 1;
+ if (prev_type == 4 && type == 5) /* LVT × T */
+ return 1;
+ if (prev_type == 5 && type == 5) /* T × T */
+ return 1;
+ return 0;
+}
+
+/* --------------------------------------------------------------------- */
+/* Segments prototype */
+/* --------------------------------------------------------------------- */
+
+static JSValue js_segments_containing(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSSegmentsData *seg = JS_GetOpaque2(ctx, this_val, js_segments_class_id);
+ JSSegmenterData *s;
+ JSValue str_val;
+ int len, pos, start, segment_len, is_word_like;
+
+ if (!seg)
+ return JS_EXCEPTION;
+
+ s = JS_GetOpaque(seg->segmenter, js_segmenter_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+
+ str_val = JS_DupValue(ctx, seg->string);
+ len = js_string_get_len(str_val);
+
+ /* ToInteger(index) */
+ if (JS_ToInt32Sat(ctx, &pos, argv[0]) < 0) {
+ JS_FreeValue(ctx, str_val);
+ return JS_EXCEPTION;
+ }
+
+ if (pos < 0 || pos >= len) {
+ JS_FreeValue(ctx, str_val);
+ return JS_UNDEFINED;
+ }
+
+ if (s->granularity == GRANULARITY_SENTENCE) {
+ JS_FreeValue(ctx, str_val);
+ return create_segment_data(ctx, str_val, 0, len, 0, 0);
+ }
+
+ /* For grapheme and word, find the segment containing pos */
+ {
+ int idx = 0;
+ start = 0;
+ segment_len = 0;
+ is_word_like = 0;
+
+ if (s->granularity == GRANULARITY_GRAPHEME) {
+ while (idx < len) {
+ int seg_start = idx;
+ int c = js_string_getc(str_val, &idx);
+ int prev_c = c;
+ int prev_type = hangul_jamo_type(c);
+ while (idx < len) {
+ int next_idx = idx;
+ int c2 = js_string_getc(str_val, &next_idx);
+ int type2 = hangul_jamo_type(c2);
+ if (hangul_combine(prev_type, type2) ||
+ is_grapheme_extender(prev_c, c2)) {
+ prev_c = c2;
+ prev_type = type2;
+ idx = next_idx;
+ } else {
+ break;
+ }
+ }
+ if (seg_start <= pos && pos < idx) {
+ start = seg_start;
+ segment_len = idx - seg_start;
+ break;
+ }
+ }
+ } else { /* word */
+ int first_word = -1;
+ idx = 0;
+ start = 0;
+ while (idx < len) {
+ int c = js_string_getc(str_val, &idx);
+ int w = is_word_char(c);
+ if (first_word < 0)
+ first_word = w;
+ if (idx < len) {
+ int idx_after_c = idx;
+ int next_c = js_string_getc(str_val, &idx);
+ int next_w = is_word_char(next_c);
+ int is_lone_surrogate = (c >= 0xD800 && c <= 0xDFFF) || (next_c >= 0xD800 && next_c <= 0xDFFF);
+ idx = idx_after_c; /* restore after peek */
+ if (w != next_w || is_lone_surrogate) {
+ if (start <= pos && pos < idx) {
+ segment_len = idx - start;
+ is_word_like = first_word;
+ break;
+ }
+ start = idx;
+ first_word = next_w;
+ }
+ } else {
+ segment_len = idx - start;
+ is_word_like = first_word;
+ break;
+ }
+ }
+ }
+ {
+ JSValue res = create_segment_data(ctx, str_val, start, segment_len,
+ is_word_like,
+ s->granularity == GRANULARITY_WORD);
+ JS_FreeValue(ctx, str_val);
+ return res;
+ }
+ }
+}
+
+static JSValue js_segments_iterator(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSSegmentsData *seg = JS_GetOpaque2(ctx, this_val, js_segments_class_id);
+ JSValue obj = JS_UNDEFINED;
+ JSValue proto;
+ JSSegmentIteratorData *it;
+
+ if (!seg)
+ return JS_EXCEPTION;
+
+ it = js_mallocz(ctx, sizeof(*it));
+ if (!it)
+ return JS_EXCEPTION;
+
+ it->segmenter = JS_DupValue(ctx, seg->segmenter);
+ it->string = JS_DupValue(ctx, seg->string);
+ it->next_index = 0;
+
+ proto = JS_GetClassProto(ctx, js_segment_iterator_class_id);
+ obj = JS_NewObjectProtoClass(ctx, proto, js_segment_iterator_class_id);
+ JS_FreeValue(ctx, proto);
+ if (JS_IsException(obj))
+ goto fail;
+ JS_SetOpaque(obj, it);
+ return obj;
+ fail:
+ JS_FreeValue(ctx, it->segmenter);
+ JS_FreeValue(ctx, it->string);
+ js_free(ctx, it);
+ JS_FreeValue(ctx, obj);
+ return JS_EXCEPTION;
+}
+
+static const JSCFunctionListEntry js_segments_proto_funcs[] = {
+ JS_CFUNC_DEF("containing", 1, js_segments_containing),
+ JS_CFUNC_DEF("[Symbol.iterator]", 0, js_segments_iterator),
+};
+
+/* --------------------------------------------------------------------- */
+/* SegmentIterator prototype */
+/* --------------------------------------------------------------------- */
+
+static JSValue js_segment_iterator_next(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv,
+ int *pdone, int magic)
+{
+ JSSegmentIteratorData *it = JS_GetOpaque2(ctx, this_val, js_segment_iterator_class_id);
+ JSSegmenterData *s;
+ JSValue str_val;
+ int len, start, segment_len, is_word_like;
+ JSValue value;
+
+ if (!it)
+ return JS_EXCEPTION;
+
+ s = JS_GetOpaque(it->segmenter, js_segmenter_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+
+ str_val = JS_DupValue(ctx, it->string);
+ len = js_string_get_len(str_val);
+
+ if (it->next_index >= len) {
+ JS_FreeValue(ctx, str_val);
+ *pdone = 1;
+ return JS_UNDEFINED;
+ }
+
+ if (s->granularity == GRANULARITY_SENTENCE) {
+ start = 0;
+ segment_len = len;
+ is_word_like = 0;
+ } else if (s->granularity == GRANULARITY_GRAPHEME) {
+ int idx = it->next_index;
+ start = idx;
+ int c = js_string_getc(str_val, &idx);
+ int prev_c = c;
+ int prev_type = hangul_jamo_type(c);
+ while (idx < len) {
+ int next_idx = idx;
+ int c2 = js_string_getc(str_val, &next_idx);
+ int type2 = hangul_jamo_type(c2);
+ if (hangul_combine(prev_type, type2) ||
+ is_grapheme_extender(prev_c, c2)) {
+ prev_c = c2;
+ prev_type = type2;
+ idx = next_idx;
+ } else {
+ break;
+ }
+ }
+ segment_len = idx - start;
+ is_word_like = 0;
+ } else { /* word */
+ int idx = it->next_index;
+ int c = js_string_getc(str_val, &idx);
+ int first_word = is_word_char(c);
+ start = it->next_index;
+ while (idx < len) {
+ int prev_idx = idx;
+ int c2 = js_string_getc(str_val, &idx);
+ if (is_word_char(c2) != first_word) {
+ idx = prev_idx;
+ break;
+ }
+ }
+ segment_len = idx - start;
+ is_word_like = first_word;
+ }
+
+ it->next_index = start + segment_len;
+
+ value = create_segment_data(ctx, str_val, start, segment_len, is_word_like,
+ s->granularity == GRANULARITY_WORD);
+ JS_FreeValue(ctx, str_val);
+
+ if (JS_IsException(value))
+ return JS_EXCEPTION;
+
+ *pdone = 0;
+ return value;
+}
+
+static const JSCFunctionListEntry js_segment_iterator_proto_funcs[] = {
+ JS_ITERATOR_NEXT_DEF("next", 0, js_segment_iterator_next, 0),
+};
+
+/* --------------------------------------------------------------------- */
+/* Segmenter prototype methods */
+/* --------------------------------------------------------------------- */
+
+static JSValue js_segmenter_segment(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSSegmenterData *s = JS_GetOpaque2(ctx, this_val, js_segmenter_class_id);
+ JSValue str_val, obj = JS_UNDEFINED, proto;
+ JSSegmentsData *seg;
+
+ if (!s)
+ return JS_EXCEPTION;
+
+ /* 3. Let string be ? ToString(string). */
+ str_val = JS_ToString(ctx, argc > 0 ? argv[0] : JS_UNDEFINED);
+ if (JS_IsException(str_val))
+ return JS_EXCEPTION;
+
+ seg = js_mallocz(ctx, sizeof(*seg));
+ if (!seg) {
+ JS_FreeValue(ctx, str_val);
+ return JS_EXCEPTION;
+ }
+
+ seg->segmenter = JS_DupValue(ctx, this_val);
+ seg->string = str_val;
+
+ proto = JS_GetClassProto(ctx, js_segments_class_id);
+ obj = JS_NewObjectProtoClass(ctx, proto, js_segments_class_id);
+ JS_FreeValue(ctx, proto);
+ if (JS_IsException(obj))
+ goto fail;
+ JS_SetOpaque(obj, seg);
+ return obj;
+ fail:
+ JS_FreeValue(ctx, seg->segmenter);
+ JS_FreeValue(ctx, seg->string);
+ js_free(ctx, seg);
+ JS_FreeValue(ctx, obj);
+ return JS_EXCEPTION;
+}
+
+static JSValue js_segmenter_resolvedOptions(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSValue obj;
+ JSSegmenterData *s = JS_GetOpaque2(ctx, this_val, js_segmenter_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+
+ obj = JS_NewObject(ctx);
+ if (JS_IsException(obj))
+ return JS_EXCEPTION;
+
+ JS_DefinePropertyValueStr(ctx, obj, "locale",
+ JS_NewString(ctx, s->locale), JS_PROP_C_W_E);
+ JS_DefinePropertyValueStr(ctx, obj, "granularity",
+ JS_NewString(ctx, granularity_names[s->granularity]), JS_PROP_C_W_E);
+
+ return obj;
+}
+
+static JSValue js_segmenter_supportedLocalesOf(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ return js_intl_supportedLocalesOf(ctx, this_val, argc, argv);
+}
+
+static const JSCFunctionListEntry js_segmenter_proto_funcs[] = {
+ JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Intl.Segmenter", JS_PROP_CONFIGURABLE),
+ JS_CFUNC_DEF("segment", 1, js_segmenter_segment),
+ JS_CFUNC_DEF("resolvedOptions", 0, js_segmenter_resolvedOptions),
+};
+
+static const JSCFunctionListEntry js_segmenter_static_funcs[] = {
+ JS_CFUNC_DEF("supportedLocalesOf", 1, js_segmenter_supportedLocalesOf),
+};
+
+int js_add_segmenter(JSContext *ctx, JSValue intl_obj)
+{
+ JSValue segments_proto, segiter_proto;
+
+ JS_NewClassID(&js_segmenter_class_id);
+ JS_NewClassID(&js_segments_class_id);
+ JS_NewClassID(&js_segment_iterator_class_id);
+
+ JS_NewClass(JS_GetRuntime(ctx), js_segmenter_class_id, &js_segmenter_class);
+ JS_NewClass(JS_GetRuntime(ctx), js_segments_class_id, &js_segments_class);
+ JS_NewClass(JS_GetRuntime(ctx), js_segment_iterator_class_id, &js_segment_iterator_class);
+
+ /* Segments prototype */
+ segments_proto = JS_NewObject(ctx);
+ if (JS_IsException(segments_proto))
+ return -1;
+ JS_SetPropertyFunctionList(ctx, segments_proto, js_segments_proto_funcs,
+ countof(js_segments_proto_funcs));
+ JS_SetClassProto(ctx, js_segments_class_id, segments_proto);
+
+ /* SegmentIterator prototype */
+ segiter_proto = JS_NewObject(ctx);
+ if (JS_IsException(segiter_proto)) {
+ JS_FreeValue(ctx, segments_proto);
+ return -1;
+ }
+ JS_SetPropertyFunctionList(ctx, segiter_proto, js_segment_iterator_proto_funcs,
+ countof(js_segment_iterator_proto_funcs));
+ JS_SetClassProto(ctx, js_segment_iterator_class_id, segiter_proto);
+
+ if (JS_IsException(js_intl_new_constructor(ctx, intl_obj,
+ -1,
+ js_segmenter_class_id, "Segmenter",
+ (JSCFunction *)js_segmenter_constructor, 0,
+ JS_CFUNC_constructor, 0,
+ js_segmenter_static_funcs, countof(js_segmenter_static_funcs),
+ js_segmenter_proto_funcs, countof(js_segmenter_proto_funcs)))) {
+ return -1;
+ }
+
+ return 0;
+}
extern const uint8_t qjsc_repl[];
extern const uint32_t qjsc_repl_size;
+#ifdef CONFIG_TEMPORAL_INTL
+static int enable_experimental = 0;
+#endif
+
static int eval_buf(JSContext *ctx, const void *buf, int buf_len,
const char *filename, int eval_flags)
{
/* system modules */
js_init_module_std(ctx, "std");
js_init_module_os(ctx, "os");
+#ifdef CONFIG_TEMPORAL_INTL
+ if (enable_experimental) {
+ JS_AddIntrinsicTemporal(ctx);
+ JS_AddIntrinsicIntl(ctx);
+ }
+#endif
return ctx;
}
" --no-unhandled-rejection ignore unhandled promise rejections\n"
"-s strip all the debug info\n"
" --strip-source strip the source code\n"
+#ifdef CONFIG_TEMPORAL_INTL
+ " --experimental enable experimental Temporal and Intl support\n"
+#endif
"-q --quit just instantiate the interpreter and quit\n");
exit(1);
}
dump_unhandled_promise_rejection = 0;
continue;
}
+#ifdef CONFIG_TEMPORAL_INTL
+ if (!strcmp(longopt, "experimental")) {
+ enable_experimental = TRUE;
+ continue;
+ }
+#endif
if (opt == 'q' || !strcmp(longopt, "quit")) {
empty_run++;
continue;
static FILE *outfile;
static BOOL byte_swap;
static BOOL dynamic_export;
+#ifdef CONFIG_TEMPORAL_INTL
+static BOOL enable_experimental;
+#endif
static const char *c_ident_prefix = "qjsc_";
#define FE_ALL (-1)
"-x byte swapped output\n"
"-p prefix set the prefix of the generated C names\n"
"-S n set the maximum stack size to 'n' bytes (default=%d)\n"
- "-s strip all the debug info\n"
- "--keep-source keep the source code\n",
- JS_DEFAULT_STACK_SIZE);
+ "-s strip all the debug info\n"
+ "--keep-source keep the source code\n"
+#ifdef CONFIG_TEMPORAL_INTL
+ "--experimental enable experimental Temporal and Intl support\n"
+#endif
+ , JS_DEFAULT_STACK_SIZE);
#ifdef CONFIG_LTO
{
int i;
libraries */
*arg++ = "-D";
*arg++ = "_GNU_SOURCE";
+#ifdef CONFIG_TEMPORAL_INTL
+ if (enable_experimental) {
+ *arg++ = "-D";
+ *arg++ = "CONFIG_TEMPORAL_INTL";
+ }
+#endif
*arg++ = "-I";
*arg++ = inc_dir;
*arg++ = "-o";
strip_flags = 0;
continue;
}
+#ifdef CONFIG_TEMPORAL_INTL
+ if (!strcmp(longopt, "experimental")) {
+ enable_experimental = TRUE;
+ continue;
+ }
+#endif
if (opt) {
fprintf(stderr, "qjsc: unknown option '-%c'\n", opt);
} else {
feature_list[i].init_name);
}
}
+
+#ifdef CONFIG_TEMPORAL_INTL
+ if (enable_experimental) {
+ fprintf(fo, " JS_AddIntrinsicTemporal(ctx);\n");
+ fprintf(fo, " JS_AddIntrinsicIntl(ctx);\n");
+ }
+#endif
/* add the precompiled modules (XXX: could modify the module
loader instead) */
for(i = 0; i < init_module_list.count; i++) {
JSValue array_proto_values;
JSValue throw_type_error;
JSValue eval_obj;
+ JSValue user_values[JS_CONTEXT_VALUE_COUNT];
JSValue global_obj; /* global object */
JSValue global_var_obj; /* contains the global let/const definitions */
JSValue (*eval_internal)(JSContext *ctx, JSValueConst this_obj,
const char *input, size_t input_len,
const char *filename, int flags, int scope_idx);
+ const JSLocaleCallbacks *locale_callbacks;
void *user_opaque;
};
rt->interrupt_opaque = opaque;
}
+void JS_SetLocaleCallbacks(JSContext *ctx, const JSLocaleCallbacks *callbacks)
+{
+ ctx->locale_callbacks = callbacks;
+}
+
+void JS_SetContextValue(JSContext *ctx, int idx, JSValue val)
+{
+ if (idx >= 0 && idx < JS_CONTEXT_VALUE_COUNT) {
+ JS_FreeValue(ctx, ctx->user_values[idx]);
+ ctx->user_values[idx] = val;
+ } else {
+ JS_FreeValue(ctx, val);
+ }
+}
+
+JSValue JS_GetContextValue(JSContext *ctx, int idx)
+{
+ if (idx >= 0 && idx < JS_CONTEXT_VALUE_COUNT)
+ return JS_DupValue(ctx, ctx->user_values[idx]);
+ return JS_UNDEFINED;
+}
+
void JS_SetCanBlock(JSRuntime *rt, BOOL can_block)
{
rt->can_block = can_block;
ctx->iterator_ctor = JS_NULL;
ctx->regexp_ctor = JS_NULL;
ctx->promise_ctor = JS_NULL;
+ for(i = 0; i < JS_CONTEXT_VALUE_COUNT; i++)
+ ctx->user_values[i] = JS_NULL;
init_list_head(&ctx->loaded_modules);
if (JS_AddIntrinsicBasicObjects(ctx)) {
JS_MarkValue(rt, ctx->eval_obj, mark_func);
JS_MarkValue(rt, ctx->array_proto_values, mark_func);
+ for(i = 0; i < JS_CONTEXT_VALUE_COUNT; i++) {
+ JS_MarkValue(rt, ctx->user_values[i], mark_func);
+ }
for(i = 0; i < JS_NATIVE_ERROR_COUNT; i++) {
JS_MarkValue(rt, ctx->native_error_proto[i], mark_func);
}
JS_FreeValue(ctx, ctx->eval_obj);
JS_FreeValue(ctx, ctx->array_proto_values);
+ for(i = 0; i < JS_CONTEXT_VALUE_COUNT; i++) {
+ JS_FreeValue(ctx, ctx->user_values[i]);
+ }
for(i = 0; i < JS_NATIVE_ERROR_COUNT; i++) {
JS_FreeValue(ctx, ctx->native_error_proto[i]);
}
return c;
}
+/* exported string helpers: caller must ensure val is a string */
+int js_string_get_len(JSValueConst val)
+{
+ return JS_VALUE_GET_STRING(val)->len;
+}
+
+int js_string_getc(JSValueConst val, int *pidx)
+{
+ return string_getc(JS_VALUE_GET_STRING(val), pidx);
+}
+
+JSValue js_sub_string_val(JSContext *ctx, JSValueConst val, int start, int end)
+{
+ return js_sub_string(ctx, JS_VALUE_GET_STRING(val), start, end);
+}
+
static int string_buffer_write8(StringBuffer *s, const uint8_t *p, int len)
{
int i;
return ret;
}
-static JSValue JS_ToLocaleStringFree(JSContext *ctx, JSValue val)
+static JSValue JS_ToLocaleStringFree(JSContext *ctx, JSValue val,
+ int argc, JSValueConst *argv)
{
if (JS_IsUndefined(val) || JS_IsNull(val))
return JS_ToStringFree(ctx, val);
- return JS_InvokeFree(ctx, val, JS_ATOM_toLocaleString, 0, NULL);
+ return JS_InvokeFree(ctx, val, JS_ATOM_toLocaleString, argc, argv);
}
JSValue JS_ToPropertyKey(JSContext *ctx, JSValueConst val)
goto fail;
if (!JS_IsNull(el) && !JS_IsUndefined(el)) {
if (toLocaleString) {
- el = JS_ToLocaleStringFree(ctx, el);
+ JSValueConst locale_argv[2];
+ locale_argv[0] = (argc > 0) ? argv[0] : JS_UNDEFINED;
+ locale_argv[1] = (argc > 1) ? argv[1] : JS_UNDEFINED;
+ el = JS_ToLocaleStringFree(ctx, el, 2, locale_argv);
}
if (string_buffer_concat_value_free(b, el))
goto fail;
val = js_thisNumberValue(ctx, this_val);
if (JS_IsException(val))
return val;
- if (magic || JS_IsUndefined(argv[0])) {
+ if (magic && ctx->locale_callbacks && ctx->locale_callbacks->number_toLocaleString) {
+ JSValue ret;
+ ret = ctx->locale_callbacks->number_toLocaleString(ctx, val, argc, argv);
+ JS_FreeValue(ctx, val);
+ return ret;
+ } else if (magic || JS_IsUndefined(argv[0])) {
base = 10;
} else {
base = js_get_radix(ctx, argv[0]);
return !lre_is_cased(c1);
}
+static int js_get_locale_lang(JSContext *ctx, int argc, JSValueConst *argv)
+{
+ const JSLocaleCallbacks *lc = ctx->locale_callbacks;
+ if (lc && lc->get_string_locale_lang)
+ return lc->get_string_locale_lang(ctx, argc, argv);
+ return 0;
+}
+
static JSValue js_string_toLowerCase(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv, int to_lower)
{
StringBuffer b_s, *b = &b_s;
JSString *p;
int i, c, j, l;
+ int is_locale = to_lower >= 2;
+ int case_dir = to_lower & 1;
+ int locale_lang = 0;
uint32_t res[LRE_CC_RES_LEN_MAX];
+ if (is_locale) {
+ locale_lang = js_get_locale_lang(ctx, argc, argv);
+ if (locale_lang < 0)
+ return JS_EXCEPTION;
+ }
+
val = JS_ToStringCheckObject(ctx, this_val);
if (JS_IsException(val))
return val;
goto fail;
for(i = 0; i < p->len;) {
c = string_getc(p, &i);
- if (c == 0x3a3 && to_lower && test_final_sigma(p, i - 1)) {
+ if (c == 0x3a3 && case_dir && test_final_sigma(p, i - 1)) {
res[0] = 0x3c2; /* final sigma */
l = 1;
+ } else if (locale_lang == 1 && case_dir) {
+ /* Turkish/Azeri lowercase */
+ if (c == 0x0130) { /* İ → i */
+ res[0] = 'i'; l = 1;
+ } else if (c == 'I') {
+ /* I → i if followed by COMBINING DOT ABOVE (U+0307) that can be removed */
+ int k = i, has_dot = 0, blocked = 0;
+ while (k < p->len) {
+ int c2 = string_getc(p, &k);
+ if (!lre_is_case_ignorable(c2))
+ break;
+ if (c2 == 0x0307) {
+ has_dot = 1;
+ break;
+ }
+ if (unicode_get_cc(c2) == 230)
+ blocked = 1;
+ }
+ if (has_dot && !blocked) {
+ /* output 'i' first, then intermediate case-ignorable chars, skip U+0307 */
+ string_buffer_putc(b, 'i');
+ l = 0;
+ while (i < p->len) {
+ int k2 = i;
+ int c2 = string_getc(p, &k2);
+ if (c2 == 0x0307) {
+ i = k2;
+ break;
+ }
+ if (!lre_is_case_ignorable(c2))
+ break;
+ string_buffer_putc(b, c2);
+ i = k2;
+ }
+ } else {
+ res[0] = 0x0131; l = 1; /* I → ı */
+ }
+ } else {
+ l = lre_case_conv(res, c, case_dir);
+ }
+ } else if (locale_lang == 1 && !case_dir) {
+ /* Turkish/Azeri uppercase */
+ if (c == 'i') { /* i → İ */
+ res[0] = 0x0130; l = 1;
+ } else if (c == 0x0131) { /* ı → I */
+ res[0] = 'I'; l = 1;
+ } else {
+ l = lre_case_conv(res, c, case_dir);
+ }
+ } else if (locale_lang == 2 && case_dir) {
+ /* Lithuanian lowercase */
+ if (c == 'I' || c == 'J' || c == 0x012E) {
+ /* Check if followed by class-230 combining mark */
+ int k = i, has_cc230 = 0;
+ while (k < p->len) {
+ int c2 = string_getc(p, &k);
+ if (!lre_is_case_ignorable(c2)) {
+ break;
+ }
+ if (unicode_get_cc(c2) == 230) {
+ has_cc230 = 1;
+ break;
+ }
+ }
+ if (has_cc230) {
+ l = lre_case_conv(res, c, case_dir);
+ for(j = 0; j < l; j++) {
+ if (string_buffer_putc(b, res[j]))
+ goto fail;
+ }
+ if (string_buffer_putc(b, 0x0307))
+ goto fail;
+ l = 0;
+ } else {
+ l = lre_case_conv(res, c, case_dir);
+ }
+ } else if (c == 0x00CC) {
+ /* I with grave → i + dot_above + grave */
+ if (string_buffer_putc(b, 'i')) goto fail;
+ if (string_buffer_putc(b, 0x0307)) goto fail;
+ if (string_buffer_putc(b, 0x0300)) goto fail;
+ l = 0;
+ } else if (c == 0x00CD) {
+ /* I with acute → i + dot_above + acute */
+ if (string_buffer_putc(b, 'i')) goto fail;
+ if (string_buffer_putc(b, 0x0307)) goto fail;
+ if (string_buffer_putc(b, 0x0301)) goto fail;
+ l = 0;
+ } else if (c == 0x0128) {
+ /* I with tilde → i + dot_above + tilde */
+ if (string_buffer_putc(b, 'i')) goto fail;
+ if (string_buffer_putc(b, 0x0307)) goto fail;
+ if (string_buffer_putc(b, 0x0303)) goto fail;
+ l = 0;
+ } else {
+ l = lre_case_conv(res, c, case_dir);
+ }
+ } else if (locale_lang == 2 && !case_dir) {
+ /* Lithuanian uppercase */
+ if (lre_is_soft_dotted(c)) {
+ l = lre_case_conv(res, c, case_dir);
+ for(j = 0; j < l; j++) {
+ if (string_buffer_putc(b, res[j]))
+ goto fail;
+ }
+ /* Look ahead for dot_above to consume */
+ while (i < p->len) {
+ int k = i;
+ int c2 = string_getc(p, &k);
+ if (c2 == 0x0307) {
+ i = k; /* skip dot_above */
+ break;
+ }
+ if (!lre_is_case_ignorable(c2))
+ break;
+ if (string_buffer_putc(b, c2))
+ goto fail;
+ i = k;
+ }
+ l = 0;
+ } else {
+ l = lre_case_conv(res, c, case_dir);
+ }
} else {
- l = lre_case_conv(res, c, to_lower);
+ l = lre_case_conv(res, c, case_dir);
}
for(j = 0; j < l; j++) {
if (string_buffer_putc(b, res[j]))
int cmp, a_len, b_len;
uint32_t *a_buf, *b_buf;
+ if (ctx->locale_callbacks && ctx->locale_callbacks->string_localeCompare)
+ return ctx->locale_callbacks->string_localeCompare(ctx, this_val, argc, argv);
+
a = JS_ToStringCheckObject(ctx, this_val);
if (JS_IsException(a))
return JS_EXCEPTION;
JSValue a, b;
int cmp;
+ if (ctx->locale_callbacks && ctx->locale_callbacks->string_localeCompare)
+ return ctx->locale_callbacks->string_localeCompare(ctx, this_val, argc, argv);
+
a = JS_ToStringCheckObject(ctx, this_val);
if (JS_IsException(a))
return JS_EXCEPTION;
JS_CFUNC_DEF("valueOf", 0, js_string_toString ),
JS_CFUNC_MAGIC_DEF("toLowerCase", 0, js_string_toLowerCase, 1 ),
JS_CFUNC_MAGIC_DEF("toUpperCase", 0, js_string_toLowerCase, 0 ),
- JS_CFUNC_MAGIC_DEF("toLocaleLowerCase", 0, js_string_toLowerCase, 1 ),
- JS_CFUNC_MAGIC_DEF("toLocaleUpperCase", 0, js_string_toLowerCase, 0 ),
+ JS_CFUNC_MAGIC_DEF("toLocaleLowerCase", 0, js_string_toLowerCase, 3 ),
+ JS_CFUNC_MAGIC_DEF("toLocaleUpperCase", 0, js_string_toLowerCase, 2 ),
JS_CFUNC_MAGIC_DEF("[Symbol.iterator]", 0, js_create_array_iterator, JS_ITERATOR_KIND_VALUE | 4 ),
/* ES6 Annex B 2.3.2 etc. */
JS_CFUNC_MAGIC_DEF("anchor", 1, js_string_CreateHTML, magic_string_anchor ),
fmt = (magic >> 4) & 0x0F;
part = magic & 0x0F;
+ if (fmt == 3) {
+ const JSLocaleCallbacks *lc = ctx->locale_callbacks;
+ if (lc && lc->date_toLocaleString)
+ return lc->date_toLocaleString(ctx, this_val, argc, argv, part);
+ }
+
res = get_date_fields(ctx, this_val, fields, fmt & 1, 0);
if (res < 0)
return JS_EXCEPTION;
return JS_EXCEPTION;
}
+static JSValue js_bigint_toLocaleString(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ if (ctx->locale_callbacks && ctx->locale_callbacks->bigint_toLocaleString) {
+ JSValue val, ret;
+
+ val = js_thisBigIntValue(ctx, this_val);
+ if (JS_IsException(val))
+ return val;
+ ret = ctx->locale_callbacks->bigint_toLocaleString(ctx, val, argc, argv);
+ JS_FreeValue(ctx, val);
+ return ret;
+ }
+
+ return js_bigint_toString(ctx, this_val, argc, argv);
+}
+
static JSValue js_bigint_valueOf(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
static const JSCFunctionListEntry js_bigint_proto_funcs[] = {
JS_CFUNC_DEF("toString", 0, js_bigint_toString ),
+ JS_CFUNC_DEF("toLocaleString", 0, js_bigint_toLocaleString ),
JS_CFUNC_DEF("valueOf", 0, js_bigint_valueOf ),
JS_PROP_STRING_DEF("[Symbol.toStringTag]", "BigInt", JS_PROP_CONFIGURABLE ),
};
if (JS_IsException(el))
goto fail;
if (toLocaleString) {
- el = JS_ToLocaleStringFree(ctx, el);
+ JSValueConst locale_argv[2];
+ locale_argv[0] = (argc > 0) ? argv[0] : JS_UNDEFINED;
+ locale_argv[1] = (argc > 1) ? argv[1] : JS_UNDEFINED;
+ el = JS_ToLocaleStringFree(ctx, el, 2, locale_argv);
}
if (string_buffer_concat_value_free(b, el))
goto fail;
void JS_SetClassProto(JSContext *ctx, JSClassID class_id, JSValue obj);
JSValue JS_GetClassProto(JSContext *ctx, JSClassID class_id);
+enum {
+ JS_INTL_CTOR_NUMBERFORMAT = 0,
+ JS_INTL_CTOR_DATETIMEFORMAT,
+ JS_INTL_CTOR_COLLATOR,
+ JS_INTL_CTOR_LISTFORMAT,
+ JS_INTL_CTOR_LOCALE,
+ JS_INTL_CTOR_DURATIONFORMAT,
+ JS_INTL_FALLBACK_SYMBOL,
+ JS_CONTEXT_VALUE_COUNT,
+};
+
+void JS_SetContextValue(JSContext *ctx, int idx, JSValue val);
+JSValue JS_GetContextValue(JSContext *ctx, int idx);
+
/* the following functions are used to select the intrinsic object to
save memory */
JSContext *JS_NewContextRaw(JSRuntime *rt);
int JS_AddIntrinsicTypedArrays(JSContext *ctx);
int JS_AddIntrinsicPromise(JSContext *ctx);
int JS_AddIntrinsicWeakRef(JSContext *ctx);
+#ifdef CONFIG_TEMPORAL_INTL
+int JS_AddIntrinsicTemporal(JSContext *ctx);
+int JS_AddIntrinsicIntl(JSContext *ctx);
+#endif
JSValue js_string_codePointRange(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv);
int JS_IteratorClose(JSContext *ctx, JSValueConst enum_obj,
JS_BOOL is_exception_pending);
+#ifdef CONFIG_TEMPORAL_INTL
+/*
+ * Internal string helpers: caller must ensure 'val' is a JS_TAG_STRING
+ * (use JS_ToString() which never returns a rope). We may later export
+ * an opaque struct JSString and use it as parameter instead.
+ */
+int js_string_get_len(JSValueConst val);
+int js_string_getc(JSValueConst val, int *pidx);
+JSValue js_sub_string_val(JSContext *ctx, JSValueConst val, int start, int end);
+#endif /* CONFIG_TEMPORAL_INTL */
+
/* C module definition */
typedef int JSModuleInitFunc(JSContext *ctx, JSModuleDef *m);
int JS_SetModulePrivateValue(JSContext *ctx, JSModuleDef *m, JSValue val);
JSValue JS_GetModulePrivateValue(JSContext *ctx, JSModuleDef *m);
+/* locale specific callbacks to override the default functions */
+typedef struct JSLocaleCallbacks {
+ JSValue (*number_toLocaleString)(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv);
+ JSValue (*date_toLocaleString)(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv, int part);
+ JSValue (*string_localeCompare)(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv);
+ JSValue (*bigint_toLocaleString)(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv);
+ int (*get_string_locale_lang)(JSContext *ctx, int argc, JSValueConst *argv);
+} JSLocaleCallbacks;
+
+void JS_SetLocaleCallbacks(JSContext *ctx, const JSLocaleCallbacks *callbacks);
+
/* debug value output */
typedef struct {
JS_SetPropertyStr(ctx, global_obj, "$262", JS_DupValue(ctx, obj262));
+#ifdef CONFIG_TEMPORAL_INTL
+ JS_AddIntrinsicTemporal(ctx);
+ JS_AddIntrinsicIntl(ctx);
+#endif
+
JS_FreeValue(ctx, global_obj);
return obj262;
}
--- /dev/null
+/*
+ * QuickJS Temporal calendar arithmetic and properties
+ */
+
+#include <string.h>
+#include "../cutils.h"
+#include "calendar.h"
+#include "temporal_private.h"
+
+const int ti_iso_month_days[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+
+/* List of built-in calendar identifiers per spec AvailableCalendars().
+ Order matches the CalendarType enum. */
+const char *ti_calendar_names[] = {
+ "buddhist", "chinese", "coptic", "dangi", "ethioaa", "ethiopic",
+ "gregory", "hebrew", "indian", "islamic-civil", "islamic-tbla",
+ "islamic-umalqura", "iso8601", "japanese", "persian", "roc"
+};
+
+CalendarType ti_calendar_string_to_enum(const char *str)
+{
+ int i;
+ for (i = 0; i < CAL_COUNT; i++) {
+ if (!strcmp(str, ti_calendar_names[i]))
+ return i;
+ }
+ if (!strcmp(str, "ethiopic-amete-alem"))
+ return CAL_ETHIOAA;
+ if (!strcmp(str, "islamicc"))
+ return CAL_ISLAMIC_CIVIL;
+ return CAL_UNKNOWN;
+}
+
+const char *ti_calendar_enum_to_string(CalendarType cal)
+{
+ if (cal >= 0 && cal < CAL_COUNT)
+ return ti_calendar_names[cal];
+ return NULL;
+}
+
+/* Compressed Chinese/Dangi calendar data (3 bytes per entry) */
+typedef struct {
+ uint8_t data[3];
+} ChineseCalendarEntry;
+
+static inline int cce_cny_month(const ChineseCalendarEntry *e) {
+ return (e->data[0] & 1) + 1;
+}
+static inline int cce_cny_day(const ChineseCalendarEntry *e) {
+ return ((e->data[0] >> 1) & 0x1F) + 1;
+}
+static inline int cce_leap_month(const ChineseCalendarEntry *e) {
+ return ((e->data[0] >> 6) & 3) | ((e->data[1] & 3) << 2);
+}
+static inline int cce_num_months(const ChineseCalendarEntry *e) {
+ return cce_leap_month(e) ? 13 : 12;
+}
+static inline uint32_t cce_month_bitmap(const ChineseCalendarEntry *e) {
+ return ((e->data[1] >> 2) & 0x3F) | ((uint32_t)(e->data[2] & 0x7F) << 6);
+}
+static inline int cce_month_length(const ChineseCalendarEntry *e, int month_idx) {
+ return (cce_month_bitmap(e) & (1U << month_idx)) ? 30 : 29;
+}
+
+/* ============================================================================
+ Chinese calendar data
+ ============================================================================ */
+
+static const ChineseCalendarEntry chinese_calendar_data[] = {
+ {{48, 181, 42}}, {{25, 88, 43}}, {{5, 80, 23}}, {{172, 164, 54}}, {{21, 36, 59}},
+ {{252, 41, 58}}, {{35, 44, 26}}, {{13, 156, 52}}, {{118, 89, 37}}, {{27, 108, 37}},
+ {{7, 104, 43}}, {{240, 80, 91}}, {{25, 80, 29}}, {{1, 36, 29}}, {{168, 44, 90}},
+ {{17, 76, 42}}, {{184, 173, 84}}, {{31, 180, 20}}, {{9, 180, 37}}, {{50, 169, 45}},
+ {{27, 168, 54}}, {{5, 144, 46}}, {{236, 20, 109}}, {{21, 36, 53}}, {{252, 85, 106}},
+ {{35, 84, 42}}, {{13, 180, 20}}, {{116, 181, 42}}, {{29, 212, 42}}, {{7, 168, 54}},
+ {{48, 145, 118}}, {{25, 144, 58}}, {{67, 42, 117}}, {{39, 40, 53}}, {{17, 88, 42}},
+ {{184, 217, 84}}, {{33, 104, 21}}, {{9, 84, 43}}, {{50, 41, 91}}, {{27, 72, 29}},
+ {{5, 148, 58}}, {{236, 40, 53}}, {{19, 44, 25}}, {{250, 93, 42}}, {{35, 172, 42}},
+ {{13, 104, 21}}, {{116, 85, 45}}, {{29, 164, 46}}, {{9, 72, 29}}, {{46, 149, 108}},
+ {{23, 148, 44}}, {{1, 46, 105}}, {{39, 52, 37}}, {{15, 180, 42}}, {{248, 169, 85}},
+ {{33, 208, 22}}, {{11, 164, 54}}, {{114, 73, 117}}, {{27, 72, 54}}, {{5, 148, 52}},
+ {{236, 52, 105}}, {{19, 88, 41}}, {{58, 214, 74}}, {{35, 88, 43}}, {{15, 80, 27}},
+ {{116, 165, 54}}, {{29, 36, 59}}, {{9, 72, 58}}, {{48, 153, 52}}, {{21, 172, 20}},
+ {{188, 94, 41}}, {{37, 108, 37}}, {{17, 104, 45}}, {{184, 81, 91}}, {{33, 80, 29}},
+ {{11, 36, 29}}, {{114, 77, 90}}, {{25, 76, 42}}, {{3, 172, 20}}, {{234, 108, 41}},
+ {{19, 180, 41}}, {{250, 169, 45}}, {{35, 168, 54}}, {{15, 144, 46}}, {{118, 37, 109}},
+ {{29, 36, 53}}, {{7, 84, 42}}, {{46, 181, 84}}, {{23, 180, 20}}, {{60, 180, 42}},
+ {{168, 168, 85}}, {{17, 168, 54}}, {{186, 145, 118}}, {{33, 144, 58}}, {{11, 40, 53}},
+ {{114, 85, 42}}, {{25, 92, 42}}, {{3, 88, 21}}, {{234, 212, 42}}, {{19, 84, 43}},
+ {{60, 74, 91}}, {{37, 72, 29}}, {{15, 148, 58}}, {{120, 41, 89}}, {{31, 44, 25}},
+ {{7, 108, 42}}, {{48, 105, 85}}, {{25, 168, 21}}, {{3, 100, 45}}, {{170, 72, 93}},
+ {{19, 72, 29}}, {{186, 149, 108}}, {{35, 148, 44}}, {{11, 44, 41}}, {{114, 173, 82}},
+ {{27, 180, 10}}, {{5, 172, 21}}, {{172, 164, 45}}, {{21, 164, 54}}, {{193, 73, 118}},
+ {{39, 72, 58}}, {{15, 148, 52}}, {{118, 53, 105}}, {{31, 88, 41}}, {{9, 216, 10}},
+ {{46, 213, 86}}, {{25, 80, 27}}, {{3, 164, 58}}, {{172, 72, 122}}, {{19, 72, 58}},
+ {{186, 153, 52}}, {{33, 172, 20}}, {{11, 92, 41}}, {{114, 217, 74}}, {{27, 104, 45}},
+ {{7, 80, 27}}, {{238, 36, 59}}, {{21, 36, 29}}, {{252, 77, 90}}, {{37, 76, 42}},
+ {{15, 172, 20}}, {{180, 109, 41}}, {{29, 180, 42}}, {{9, 168, 21}}, {{48, 85, 109}},
+ {{25, 144, 46}}, {{3, 36, 45}}, {{170, 76, 106}}, {{19, 84, 42}}, {{248, 181, 84}},
+ {{33, 216, 20}}, {{11, 180, 42}}, {{116, 169, 86}}, {{27, 200, 22}}, {{5, 148, 54}},
+ {{238, 40, 117}}, {{23, 40, 53}}, {{60, 86, 42}}, {{35, 92, 42}}, {{15, 88, 21}},
+ {{182, 213, 42}}, {{29, 84, 43}}, {{9, 72, 27}}, {{48, 149, 58}}, {{25, 148, 58}},
+ {{3, 40, 25}}, {{232, 92, 50}}, {{17, 108, 42}}, {{250, 105, 85}}, {{33, 168, 21}},
+ {{11, 164, 45}}, {{116, 73, 93}}, {{29, 72, 45}}, {{5, 148, 44}}, {{44, 45, 89}},
+ {{21, 44, 41}}, {{60, 174, 82}}, {{35, 180, 10}}, {{13, 180, 21}}, {{182, 165, 45}},
+ {{31, 164, 54}}, {{9, 72, 54}}, {{48, 149, 116}}, {{25, 148, 52}}, {{131, 54, 105}},
+ {{39, 88, 41}}, {{17, 216, 10}}, {{184, 213, 22}}, {{33, 84, 27}}, {{11, 164, 58}},
+ {{116, 73, 122}}, {{29, 72, 58}}, {{7, 152, 52}}, {{236, 88, 41}}, {{19, 92, 41}},
+ {{60, 90, 83}}, {{37, 104, 13}}, {{13, 84, 27}}, {{118, 37, 91}}, {{31, 36, 29}},
+ {{9, 76, 26}}, {{46, 173, 84}}, {{23, 172, 20}}, {{1, 108, 41}}, {{170, 104, 85}},
+ {{17, 168, 21}}, {{248, 85, 109}}, {{35, 144, 46}}, {{13, 36, 45}}, {{114, 77, 106}},
+ {{27, 84, 42}}, {{5, 180, 20}}, {{44, 181, 42}}, {{19, 212, 42}}, {{124, 170, 86}},
+ {{37, 72, 23}}, {{15, 148, 54}}, {{182, 41, 117}}, {{31, 40, 53}}, {{9, 84, 50}},
+ {{48, 185, 84}}, {{23, 88, 21}}, {{1, 212, 42}}, {{170, 200, 86}}, {{19, 72, 27}},
+ {{184, 149, 58}}, {{33, 148, 28}}, {{11, 44, 25}}, {{114, 93, 50}}, {{25, 172, 50}},
+ {{5, 104, 21}}, {{236, 88, 43}}, {{21, 164, 45}}, {{252, 74, 93}}, {{37, 72, 45}},
+ {{15, 148, 44}}, {{182, 45, 105}}, {{29, 44, 41}}, {{7, 172, 18}}, {{110, 109, 21}},
+ {{23, 180, 22}}, {{1, 168, 45}}, {{170, 72, 109}}, {{19, 72, 54}}, {{250, 149, 116}},
+ {{33, 148, 52}}, {{11, 84, 41}}, {{114, 181, 82}}, {{27, 216, 18}}, {{3, 212, 22}},
+ {{236, 168, 54}}, {{21, 36, 59}}, {{1, 74, 122}}, {{37, 72, 58}}, {{15, 152, 52}},
+ {{182, 89, 41}}, {{29, 92, 41}}, {{7, 88, 21}}, {{46, 85, 27}}, {{23, 84, 29}}, {{3, 36, 29}},
+ {{232, 76, 58}}, {{17, 76, 26}}, {{248, 173, 84}}, {{33, 172, 20}}, {{9, 108, 41}},
+ {{114, 105, 85}}, {{27, 168, 21}}, {{5, 148, 45}}, {{44, 41, 93}}, {{21, 40, 45}},
+ {{60, 86, 106}}, {{37, 84, 42}}, {{13, 180, 20}}, {{180, 181, 42}}, {{29, 212, 42}},
+ {{9, 168, 22}}, {{46, 149, 46}}, {{23, 148, 54}}, {{3, 40, 53}}, {{234, 84, 114}},
+ {{17, 88, 50}}, {{248, 57, 101}}, {{33, 88, 21}}, {{11, 212, 42}}, {{114, 201, 86}},
+ {{27, 72, 27}}, {{5, 148, 58}}, {{46, 41, 57}}, {{19, 44, 26}}, {{58, 94, 50}},
+ {{35, 172, 18}}, {{13, 108, 21}}, {{180, 89, 43}}, {{29, 168, 45}}, {{9, 72, 29}},
+ {{48, 149, 92}}, {{23, 20, 45}}, {{1, 44, 42}}, {{168, 108, 82}}, {{17, 172, 18}},
+ {{248, 109, 37}}, {{33, 180, 22}}, {{13, 168, 46}}, {{118, 73, 109}}, {{29, 72, 54}},
+ {{7, 148, 52}}, {{46, 45, 105}}, {{23, 84, 41}}, {{124, 182, 82}}, {{37, 216, 18}},
+ {{15, 212, 26}}, {{184, 169, 54}}, {{31, 36, 59}}, {{11, 72, 58}}, {{50, 153, 116}},
+ {{27, 168, 52}}, {{3, 88, 41}}, {{234, 216, 82}}, {{19, 88, 21}}, {{250, 85, 43}},
+ {{33, 84, 45}}, {{13, 40, 29}}, {{116, 77, 58}}, {{29, 84, 26}}, {{5, 172, 20}},
+ {{44, 93, 41}}, {{21, 108, 42}}, {{193, 106, 101}}, {{37, 168, 21}}, {{15, 148, 45}},
+ {{184, 41, 93}}, {{33, 40, 45}}, {{9, 84, 44}}, {{112, 173, 84}}, {{25, 52, 21}},
+ {{3, 180, 42}}, {{170, 168, 85}}, {{19, 168, 22}}, {{250, 149, 46}}, {{35, 148, 54}},
+ {{13, 40, 53}}, {{116, 85, 116}}, {{29, 88, 52}}, {{7, 56, 37}}, {{44, 181, 42}},
+ {{21, 88, 43}}, {{193, 210, 102}}, {{39, 72, 27}}, {{15, 148, 58}}, {{184, 41, 58}},
+ {{31, 44, 26}}, {{9, 92, 52}}, {{112, 89, 37}}, {{23, 108, 37}}, {{3, 104, 43}},
+ {{236, 80, 91}}, {{19, 80, 29}}, {{250, 21, 93}}, {{35, 20, 45}}, {{13, 44, 42}},
+ {{178, 173, 84}}, {{27, 180, 18}}, {{5, 172, 37}}, {{46, 105, 45}}, {{21, 168, 54}},
+ {{129, 82, 109}}, {{39, 136, 54}}, {{17, 20, 53}}, {{182, 85, 106}}, {{31, 84, 42}},
+ {{9, 180, 20}}, {{112, 181, 42}}, {{23, 212, 42}}, {{3, 168, 54}}, {{236, 144, 118}},
+ {{21, 136, 58}}, {{250, 25, 117}}, {{35, 40, 53}}, {{13, 88, 42}}, {{180, 217, 84}},
+ {{27, 104, 21}}, {{5, 84, 43}}, {{46, 41, 91}}, {{23, 72, 29}}, {{60, 148, 58}},
+ {{168, 40, 53}}, {{15, 44, 21}}, {{182, 93, 42}}, {{29, 172, 42}}, {{9, 104, 21}},
+ {{112, 85, 43}}, {{25, 148, 45}}, {{3, 72, 29}}, {{234, 148, 106}}, {{19, 148, 44}},
+ {{250, 45, 105}}, {{33, 52, 37}}, {{11, 180, 42}}, {{180, 169, 85}}, {{29, 208, 22}}
+};
+
+/* Look up Chinese calendar data for a given Gregorian year (which contains CNY).
+ Returns NULL if out of range. */
+static const ChineseCalendarEntry *lookup_chinese_year(int year)
+{
+ int idx = year - 1800;
+ if (idx < 0 || idx >= (int)(sizeof(chinese_calendar_data) / sizeof(chinese_calendar_data[0])))
+ return NULL;
+ return &chinese_calendar_data[idx];
+}
+
+/* ============================================================================
+ Dangi (Korean lunisolar) calendar data
+ ============================================================================ */
+
+static const ChineseCalendarEntry dangi_calendar_data[] = {
+ {{112, 181, 42}}, {{25, 88, 43}}, {{5, 80, 23}}, {{172, 164, 54}}, {{21, 148, 58}},
+ {{252, 41, 58}}, {{35, 44, 26}}, {{13, 156, 20}}, {{116, 93, 37}}, {{27, 108, 37}},
+ {{7, 104, 43}}, {{240, 80, 91}}, {{25, 80, 29}}, {{193, 22, 93}}, {{39, 20, 45}},
+ {{17, 44, 42}}, {{184, 173, 84}}, {{31, 180, 18}}, {{9, 180, 37}}, {{50, 169, 45}},
+ {{27, 168, 46}}, {{5, 80, 46}}, {{236, 20, 109}}, {{21, 20, 53}}, {{252, 85, 106}},
+ {{35, 84, 42}}, {{13, 180, 20}}, {{180, 181, 42}}, {{29, 212, 42}}, {{7, 168, 54}},
+ {{48, 145, 118}}, {{25, 136, 58}}, {{67, 42, 117}}, {{39, 40, 53}}, {{17, 88, 42}},
+ {{184, 217, 84}}, {{33, 104, 21}}, {{9, 84, 43}}, {{50, 41, 91}}, {{27, 72, 29}},
+ {{5, 148, 58}}, {{236, 40, 85}}, {{19, 44, 21}}, {{250, 93, 42}}, {{35, 172, 42}},
+ {{13, 104, 21}}, {{116, 85, 45}}, {{29, 164, 46}}, {{9, 72, 29}}, {{46, 149, 106}},
+ {{23, 148, 44}}, {{1, 46, 105}}, {{39, 52, 37}}, {{15, 180, 42}}, {{248, 169, 85}},
+ {{33, 208, 22}}, {{11, 164, 46}}, {{114, 73, 117}}, {{27, 72, 54}}, {{5, 148, 52}},
+ {{236, 52, 105}}, {{19, 88, 37}}, {{58, 214, 74}}, {{35, 88, 43}}, {{15, 80, 27}},
+ {{116, 165, 54}}, {{29, 36, 59}}, {{9, 72, 58}}, {{48, 153, 52}}, {{21, 156, 20}},
+ {{188, 94, 41}}, {{37, 108, 37}}, {{17, 104, 45}}, {{184, 81, 91}}, {{33, 80, 29}},
+ {{11, 36, 29}}, {{114, 77, 90}}, {{25, 76, 42}}, {{3, 172, 20}}, {{234, 108, 41}},
+ {{19, 180, 37}}, {{250, 169, 45}}, {{35, 168, 54}}, {{15, 144, 46}}, {{118, 37, 109}},
+ {{29, 36, 53}}, {{7, 84, 42}}, {{46, 173, 84}}, {{23, 180, 20}}, {{60, 183, 42}},
+ {{37, 212, 42}}, {{17, 168, 54}}, {{186, 145, 118}}, {{33, 144, 58}}, {{11, 40, 53}},
+ {{114, 85, 106}}, {{27, 88, 42}}, {{3, 88, 21}}, {{234, 212, 42}}, {{19, 84, 43}},
+ {{60, 74, 91}}, {{37, 72, 29}}, {{15, 148, 58}}, {{120, 41, 89}}, {{31, 44, 25}},
+ {{7, 108, 42}}, {{48, 89, 85}}, {{25, 168, 21}}, {{3, 100, 45}}, {{170, 72, 93}},
+ {{19, 72, 29}}, {{186, 149, 108}}, {{35, 148, 44}}, {{11, 44, 41}}, {{114, 109, 74}},
+ {{27, 180, 42}}, {{7, 168, 21}}, {{172, 164, 45}}, {{21, 164, 46}}, {{193, 73, 109}},
+ {{39, 72, 54}}, {{15, 148, 52}}, {{118, 53, 105}}, {{31, 88, 37}}, {{9, 212, 10}},
+ {{46, 181, 86}}, {{25, 80, 27}}, {{3, 164, 54}}, {{172, 72, 118}}, {{19, 72, 58}},
+ {{186, 153, 52}}, {{33, 156, 20}}, {{11, 92, 41}}, {{114, 217, 74}}, {{27, 104, 43}},
+ {{7, 80, 27}}, {{238, 164, 58}}, {{21, 36, 29}}, {{252, 77, 90}}, {{37, 76, 42}},
+ {{15, 172, 20}}, {{180, 109, 41}}, {{29, 180, 37}}, {{9, 168, 45}}, {{50, 81, 109}},
+ {{25, 144, 46}}, {{3, 36, 45}}, {{170, 76, 106}}, {{19, 84, 42}}, {{248, 173, 84}},
+ {{33, 180, 20}}, {{11, 180, 42}}, {{116, 169, 85}}, {{27, 200, 54}}, {{7, 144, 54}},
+ {{238, 36, 117}}, {{23, 40, 53}}, {{60, 86, 106}}, {{37, 88, 42}}, {{15, 88, 21}},
+ {{182, 213, 42}}, {{29, 84, 43}}, {{9, 72, 27}}, {{48, 149, 58}}, {{25, 148, 58}},
+ {{3, 40, 57}}, {{234, 88, 50}}, {{17, 108, 42}}, {{250, 89, 85}}, {{33, 168, 21}},
+ {{11, 100, 45}}, {{116, 73, 93}}, {{29, 72, 29}}, {{5, 148, 28}}, {{44, 45, 89}},
+ {{21, 44, 41}}, {{60, 174, 74}}, {{35, 180, 10}}, {{13, 172, 21}}, {{182, 165, 45}},
+ {{31, 164, 54}}, {{9, 72, 54}}, {{48, 149, 108}}, {{25, 148, 52}}, {{131, 54, 105}},
+ {{39, 88, 41}}, {{17, 216, 10}}, {{184, 181, 86}}, {{35, 80, 27}}, {{11, 164, 54}},
+ {{116, 73, 118}}, {{29, 72, 58}}, {{7, 152, 52}}, {{236, 88, 41}}, {{19, 92, 41}},
+ {{60, 218, 74}}, {{37, 104, 45}}, {{15, 80, 27}}, {{118, 37, 59}}, {{31, 36, 29}},
+ {{9, 76, 26}}, {{46, 157, 84}}, {{23, 172, 20}}, {{1, 108, 41}}, {{170, 104, 85}},
+ {{17, 168, 13}}, {{248, 85, 109}}, {{35, 144, 46}}, {{13, 36, 45}}, {{114, 77, 106}},
+ {{27, 84, 42}}, {{5, 180, 20}}, {{236, 116, 41}}, {{19, 180, 42}}, {{124, 170, 86}},
+ {{37, 72, 23}}, {{15, 148, 54}}, {{118, 37, 117}}, {{31, 40, 53}}, {{9, 84, 42}},
+ {{48, 181, 84}}, {{23, 88, 21}}, {{1, 212, 42}}, {{170, 168, 86}}, {{19, 72, 27}},
+ {{184, 149, 58}}, {{33, 148, 58}}, {{13, 40, 57}}, {{116, 89, 50}}, {{25, 108, 50}},
+ {{5, 104, 21}}, {{236, 84, 43}}, {{21, 164, 45}}, {{252, 74, 93}}, {{37, 72, 29}},
+ {{15, 148, 44}}, {{182, 45, 89}}, {{29, 44, 41}}, {{7, 172, 18}}, {{110, 109, 21}},
+ {{23, 180, 21}}, {{1, 164, 45}}, {{170, 72, 109}}, {{19, 72, 54}}, {{250, 149, 116}},
+ {{33, 148, 52}}, {{11, 52, 41}}, {{114, 181, 82}}, {{27, 216, 10}}, {{3, 212, 22}},
+ {{236, 164, 54}}, {{21, 36, 55}}, {{1, 74, 118}}, {{37, 72, 58}}, {{15, 152, 52}},
+ {{182, 89, 41}}, {{29, 92, 41}}, {{7, 88, 19}}, {{46, 213, 26}}, {{23, 84, 27}}, {{3, 36, 59}},
+ {{234, 72, 58}}, {{17, 76, 26}}, {{248, 173, 84}}, {{33, 172, 20}}, {{9, 108, 41}},
+ {{114, 105, 85}}, {{27, 168, 21}}, {{5, 84, 45}}, {{44, 37, 93}}, {{21, 36, 45}},
+ {{60, 78, 106}}, {{37, 84, 42}}, {{13, 180, 20}}, {{180, 181, 42}}, {{29, 212, 42}},
+ {{9, 168, 22}}, {{46, 149, 46}}, {{23, 148, 54}}, {{3, 40, 53}}, {{234, 84, 106}},
+ {{17, 84, 50}}, {{248, 185, 84}}, {{33, 88, 21}}, {{11, 212, 42}}, {{114, 201, 86}},
+ {{27, 72, 27}}, {{5, 148, 58}}, {{46, 41, 121}}, {{21, 40, 25}}, {{58, 94, 50}},
+ {{35, 172, 50}}, {{15, 104, 21}}, {{180, 85, 43}}, {{29, 164, 45}}, {{9, 72, 29}},
+ {{48, 149, 58}}, {{23, 148, 44}}, {{1, 44, 25}}, {{232, 92, 82}}, {{17, 172, 18}},
+ {{248, 109, 21}}, {{33, 180, 22}}, {{13, 164, 45}}, {{118, 73, 109}}, {{29, 72, 54}},
+ {{7, 148, 52}}, {{46, 45, 105}}, {{23, 84, 41}}, {{124, 182, 82}}, {{37, 216, 18}},
+ {{15, 212, 22}}, {{184, 169, 54}}, {{31, 36, 59}}, {{11, 72, 58}}, {{50, 149, 116}},
+ {{27, 152, 52}}, {{3, 88, 41}}, {{234, 184, 82}}, {{19, 88, 19}}, {{250, 85, 27}},
+ {{33, 84, 27}}, {{13, 36, 59}}, {{118, 73, 58}}, {{29, 76, 26}}, {{5, 172, 20}},
+ {{44, 93, 41}}, {{21, 108, 41}}, {{193, 106, 85}}, {{37, 168, 21}}, {{15, 148, 45}},
+ {{184, 41, 93}}, {{33, 36, 45}}, {{9, 84, 42}}, {{112, 173, 84}}, {{25, 180, 20}},
+ {{3, 180, 42}}, {{170, 168, 85}}, {{19, 168, 22}}, {{250, 149, 46}}, {{35, 148, 54}},
+ {{13, 40, 53}}, {{116, 85, 114}}, {{29, 88, 50}}, {{7, 56, 37}}, {{44, 181, 42}},
+ {{21, 212, 42}}, {{1, 200, 22}}, {{104, 148, 54}}, {{15, 148, 58}}, {{184, 41, 121}},
+ {{33, 40, 26}}, {{9, 92, 50}}, {{112, 89, 37}}, {{23, 108, 21}}, {{3, 88, 43}},
+ {{236, 80, 91}}, {{19, 72, 29}}, {{250, 149, 92}}, {{35, 20, 45}}, {{13, 44, 26}},
+ {{178, 109, 82}}, {{27, 172, 18}}, {{5, 108, 37}}, {{46, 105, 45}}, {{21, 168, 46}},
+ {{129, 74, 109}}, {{39, 136, 54}}, {{17, 20, 53}}, {{182, 45, 106}}, {{31, 84, 41}},
+ {{9, 180, 18}}, {{48, 181, 37}}, {{23, 212, 22}}, {{3, 168, 54}}, {{236, 72, 118}},
+ {{21, 136, 58}}, {{250, 21, 117}}, {{35, 168, 52}}, {{13, 88, 41}}, {{180, 217, 82}},
+ {{27, 88, 21}}, {{5, 84, 43}}, {{46, 169, 54}}, {{23, 40, 29}}, {{60, 140, 58}},
+ {{168, 24, 53}}, {{15, 172, 20}}, {{246, 93, 41}}, {{29, 108, 42}}, {{9, 104, 21}},
+ {{112, 85, 43}}, {{25, 148, 45}}, {{3, 40, 29}}, {{234, 148, 90}}, {{19, 84, 42}},
+ {{250, 173, 84}}, {{33, 52, 21}}, {{11, 180, 42}}, {{116, 169, 85}}, {{29, 168, 22}}
+};
+
+static const ChineseCalendarEntry *lookup_dangi_year(int year)
+{
+ int idx = year - 1800;
+ if (idx < 0 || idx >= (int)(sizeof(dangi_calendar_data) / sizeof(dangi_calendar_data[0])))
+ return NULL;
+ return &dangi_calendar_data[idx];
+}
+
+/* Return the related Gregorian year for a Chinese/Dangi date.
+ Returns iso_year if on/after Chinese New Year, iso_year - 1 otherwise.
+ Falls back to iso_year if the year is not in the calendar data. */
+int ti_chinese_related_year(CalendarType cal, int iso_year, int iso_month, int iso_day)
+{
+ const ChineseCalendarEntry *e;
+ if (cal == CAL_DANGI)
+ e = lookup_dangi_year(iso_year);
+ else
+ e = lookup_chinese_year(iso_year);
+ if (e && (iso_month < cce_cny_month(e) ||
+ (iso_month == cce_cny_month(e) && iso_day < cce_cny_day(e)))) {
+ return iso_year - 1;
+ }
+ return iso_year;
+}
+
+/* ===== Chinese/Dangi calendar properties ===== */
+
+int64_t pdt_to_ordinal_days(int year, int month, int day)
+{
+ int64_t y = (int64_t)year - 1;
+ int64_t days = y * 365 + floor_div64(y, 4) - floor_div64(y, 100) + floor_div64(y, 400);
+ int i;
+ for (i = 1; i < month; i++)
+ days += ti_iso_month_days[i];
+ if (month > 2 && ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)))
+ days++;
+ days += day - 1;
+ return days;
+}
+
+/* Inverse of pdt_to_ordinal_days: convert ordinal day count (from 0001-01-01 = 0)
+ back to year, month, day. Uses 400/100/4/1 year cycles for direct computation. */
+void pdt_from_ordinal_days(int64_t ordinal, int *year, int *month, int *day)
+{
+ int64_t r400, r100, r4, r1;
+ int64_t n400 = floor_divrem64(&r400, ordinal, 146097);
+ int64_t n100 = floor_divrem64(&r100, r400, 36524);
+ int64_t n4, n1;
+ int64_t y;
+ int doy, i;
+
+ if (n100 == 4) { n100 = 3; r100 = 36524; }
+ y = 1 + n400 * 400 + n100 * 100;
+
+ n4 = floor_divrem64(&r4, r100, 1461);
+ y += n4 * 4;
+
+ n1 = floor_divrem64(&r1, r4, 365);
+ if (n1 == 4) { n1 = 3; r1 = 365; }
+ y += n1;
+
+ doy = (int)r1;
+ for (i = 1; i <= 12; i++) {
+ int dim = ti_iso_month_days[i];
+ if (i == 2 && ((y % 4 == 0 && y % 100 != 0) || (y % 400 == 0)))
+ dim = 29;
+ if (doy < dim) {
+ *year = (int)y;
+ *month = i;
+ *day = doy + 1;
+ return;
+ }
+ doy -= dim;
+ }
+ /* Should not reach here for valid ordinal */
+ *year = (int)y;
+ *month = 12;
+ *day = 31;
+}
+
+
+
+static int ti_calendar_is_leap_year_chinese(int year)
+{
+ const ChineseCalendarEntry *entry = lookup_chinese_year(year);
+ if (!entry)
+ return 0;
+ return cce_num_months(entry) == 13;
+}
+
+static int ti_calendar_days_in_year_chinese(int year)
+{
+ const ChineseCalendarEntry *entry = lookup_chinese_year(year);
+ int i, days = 0;
+ if (!entry)
+ return 365;
+ for (i = 0; i < cce_num_months(entry); i++)
+ days += cce_month_length(entry, i);
+ return days;
+}
+
+static int ti_calendar_months_in_year_chinese(int year)
+{
+ const ChineseCalendarEntry *entry = lookup_chinese_year(year);
+ if (!entry)
+ return 12;
+ return cce_num_months(entry);
+}
+
+static int ti_calendar_days_in_month_chinese(int year, int month)
+{
+ const ChineseCalendarEntry *entry = lookup_chinese_year(year);
+ if (!entry || month < 1 || month > cce_num_months(entry))
+ return 30;
+ return cce_month_length(entry, month - 1);
+}
+
+static int ti_calendar_is_leap_year_dangi(int year)
+{
+ const ChineseCalendarEntry *entry = lookup_dangi_year(year);
+ if (!entry)
+ return 0;
+ return cce_num_months(entry) == 13;
+}
+
+static int ti_calendar_days_in_year_dangi(int year)
+{
+ const ChineseCalendarEntry *entry = lookup_dangi_year(year);
+ int i, days = 0;
+ if (!entry)
+ return 365;
+ for (i = 0; i < cce_num_months(entry); i++)
+ days += cce_month_length(entry, i);
+ return days;
+}
+
+static int ti_calendar_months_in_year_dangi(int year)
+{
+ const ChineseCalendarEntry *entry = lookup_dangi_year(year);
+ if (!entry)
+ return 12;
+ return cce_num_months(entry);
+}
+
+static int ti_calendar_days_in_month_dangi(int year, int month)
+{
+ const ChineseCalendarEntry *entry = lookup_dangi_year(year);
+ if (!entry || month < 1 || month > cce_num_months(entry))
+ return 30;
+ return cce_month_length(entry, month - 1);
+}
+
+/* ===== Coptic / Ethiopic / Ethioaa ===== */
+
+static int coptic_ethiopic_is_leap(int year)
+{
+ int mod = year % 4;
+ if (mod < 0) mod += 4;
+ return mod == 3;
+}
+
+static int coptic_ethiopic_days_in_year(int year)
+{
+ return coptic_ethiopic_is_leap(year) ? 366 : 365;
+}
+
+static int coptic_ethiopic_months_in_year(int year)
+{
+ (void)year;
+ return 13;
+}
+
+static int coptic_ethiopic_days_in_month(int year, int month)
+{
+ if (month < 1 || month > 13)
+ return 30;
+ if (month < 13)
+ return 30;
+ return coptic_ethiopic_is_leap(year) ? 6 : 5;
+}
+
+/* ===== Persian ===== */
+
+static int persian_is_leap(int year)
+{
+ int64_t rem = (25LL * year + 11) % 33;
+ if (rem < 0)
+ rem += 33;
+ return rem < 8;
+}
+
+static int persian_days_in_year(int year)
+{
+ return persian_is_leap(year) ? 366 : 365;
+}
+
+static int persian_months_in_year(int year)
+{
+ (void)year;
+ return 12;
+}
+
+static int persian_days_in_month(int year, int month)
+{
+ static const int days[] = {31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 29};
+ if (month < 1 || month > 12)
+ return 30;
+ if (month == 12 && persian_is_leap(year))
+ return 30;
+ return days[month - 1];
+}
+
+/* ===== Islamic civil / tbla ===== */
+
+static int islamic_civil_is_leap(int year)
+{
+ int rem = year % 30;
+ if (rem < 0)
+ rem += 30;
+ return rem == 2 || rem == 5 || rem == 7 || rem == 10 || rem == 13 ||
+ rem == 16 || rem == 18 || rem == 21 || rem == 24 || rem == 26 ||
+ rem == 29;
+}
+
+static int islamic_civil_days_in_year(int year)
+{
+ return islamic_civil_is_leap(year) ? 355 : 354;
+}
+
+static int islamic_civil_months_in_year(int year)
+{
+ (void)year;
+ return 12;
+}
+
+static int islamic_civil_days_in_month(int year, int month)
+{
+ if (month < 1 || month > 12)
+ return 30;
+ if (month == 12)
+ return islamic_civil_is_leap(year) ? 30 : 29;
+ return (month % 2 == 1) ? 30 : 29;
+}
+
+/* ===== Indian ===== */
+
+static int indian_is_leap(int year)
+{
+ int mod = year % 4;
+ if (mod < 0) mod += 4;
+ return mod == 2;
+}
+
+static int indian_days_in_year(int year)
+{
+ return indian_is_leap(year) ? 366 : 365;
+}
+
+static int indian_months_in_year(int year)
+{
+ (void)year;
+ return 12;
+}
+
+static int indian_days_in_month(int year, int month)
+{
+ if (month < 1 || month > 12)
+ return 30;
+ if (month == 1)
+ return indian_is_leap(year) ? 31 : 30;
+ if (month <= 6)
+ return 31;
+ return 30;
+}
+
+static int ti_indian_to_iso(int indian_year, int indian_month, int indian_day,
+ int *iso_y, int *iso_m, int *iso_d)
+{
+ int gyear = indian_year + 78;
+ int doy = indian_day - 1;
+ int ml[12] = {30, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 30};
+ int64_t base_ord;
+
+ if (indian_month < 1 || indian_month > 12)
+ return -1;
+ if (indian_is_leap(indian_year))
+ ml[0] = 31;
+ if (indian_day < 1 || indian_day > ml[indian_month - 1])
+ return -1;
+
+ for (int i = 0; i < indian_month - 1; i++)
+ doy += ml[i];
+
+ base_ord = pdt_to_ordinal_days(gyear, 3, indian_is_leap(indian_year) ? 21 : 22);
+ pdt_from_ordinal_days(base_ord + doy, iso_y, iso_m, iso_d);
+ return 0;
+}
+
+static int ti_iso_to_indian(int iso_y, int iso_m, int iso_d,
+ int *indian_y, int *indian_m, int *indian_d)
+{
+ int64_t iso_ord = pdt_to_ordinal_days(iso_y, iso_m, iso_d);
+ int candidate_y;
+
+ for (candidate_y = iso_y - 79; candidate_y <= iso_y - 77; candidate_y++) {
+ int gyear = candidate_y + 78;
+ int base_d = indian_is_leap(candidate_y) ? 21 : 22;
+ int64_t base_ord = pdt_to_ordinal_days(gyear, 3, base_d);
+ int year_len = indian_days_in_year(candidate_y);
+
+ if (iso_ord >= base_ord && iso_ord < base_ord + year_len) {
+ int doy = (int)(iso_ord - base_ord);
+ int ml[12] = {30, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 30};
+ int m;
+ if (indian_is_leap(candidate_y))
+ ml[0] = 31;
+ for (m = 0; m < 12; m++) {
+ if (doy < ml[m])
+ break;
+ doy -= ml[m];
+ }
+ *indian_y = candidate_y;
+ *indian_m = m + 1;
+ *indian_d = doy + 1;
+ return 0;
+ }
+ }
+ return -1;
+}
+
+/* ===== Hebrew ===== */
+
+static int hebrew_is_leap(int year)
+{
+ int mod = (7 * year + 1) % 19;
+ if (mod < 0) mod += 19;
+ return mod < 7;
+}
+
+static int hebrew_months_in_year(int year)
+{
+ return hebrew_is_leap(year) ? 13 : 12;
+}
+
+/* Year type determines Heshvan and Kislev lengths:
+ * Deficient: Heshvan 29, Kislev 29
+ * Regular: Heshvan 29, Kislev 30
+ * Complete: Heshvan 30, Kislev 30
+ */
+
+static int64_t hebrew_start_of_year(int year);
+
+static int hebrew_days_in_year(int year)
+{
+ static const int hebrew_year_lengths[80] = {
+ 383, 354, 355, 383, 355, 354, 385, 353, 384, 355,
+ 355, 383, 354, 355, 385, 354, 383, 355, 354, 383,
+ 355, 354, 385, 353, 355, 384, 355, 383, 354, 355,
+ 385, 353, 354, 385, 355, 383, 354, 355, 383, 354,
+ 355, 385, 354, 353, 385, 354, 385, 353, 354, 385,
+ 355, 353, 384, 355, 383, 355, 354, 385, 355, 354,
+ 383, 355, 354, 383, 355, 385, 354, 353, 385, 354,
+ 355, 383, 354, 385, 353, 355, 384, 355, 353, 384
+ };
+ static const int hebrew_year_lengths_epoch[11] = {
+ 384, 355, 355, 383, 354, 355, 385, 354, 383, 355, 354
+ };
+ if (year >= 0 && year <= 10)
+ return hebrew_year_lengths_epoch[year];
+ if (year >= 5730 && year <= 5809)
+ return hebrew_year_lengths[year - 5730];
+ /* Fallback: compute actual length from start-of-year algorithm */
+ return (int)(hebrew_start_of_year(year + 1) - hebrew_start_of_year(year));
+}
+
+static int hebrew_days_in_month(int year, int month)
+{
+ int leap = hebrew_is_leap(year);
+ int months = leap ? 13 : 12;
+ int days_in_year = hebrew_days_in_year(year);
+ int is_deficient, is_complete;
+
+ if (month < 1 || month > months)
+ return 30;
+
+ if (leap) {
+ is_deficient = (days_in_year == 383);
+ is_complete = (days_in_year == 385);
+ } else {
+ is_deficient = (days_in_year == 353);
+ is_complete = (days_in_year == 355);
+ }
+
+ if (month == 1) /* Tishri */
+ return 30;
+ if (month == 2) /* Heshvan */
+ return is_complete ? 30 : 29;
+ if (month == 3) /* Kislev */
+ return is_deficient ? 29 : 30;
+ if (month == 4) /* Tevet */
+ return 29;
+ if (month == 5) /* Shevat */
+ return 30;
+
+ if (!leap) {
+ /* Common year */
+ if (month == 6) return 29; /* Adar */
+ if (month == 7) return 30; /* Nisan */
+ if (month == 8) return 29; /* Iyar */
+ if (month == 9) return 30; /* Sivan */
+ if (month == 10) return 29; /* Tammuz */
+ if (month == 11) return 30; /* Av */
+ if (month == 12) return 29; /* Elul */
+ } else {
+ /* Leap year */
+ if (month == 6) return 30; /* Adar I */
+ if (month == 7) return 29; /* Adar II */
+ if (month == 8) return 30; /* Nisan */
+ if (month == 9) return 29; /* Iyar */
+ if (month == 10) return 30; /* Sivan */
+ if (month == 11) return 29; /* Tammuz */
+ if (month == 12) return 30; /* Av */
+ if (month == 13) return 29; /* Elul */
+ }
+ return 30;
+}
+
+/* ===== Hebrew ISO conversion (based on ICU) ===== */
+
+/* Cumulative days to end of each month. Index 0 is placeholder. */
+static const int16_t hebrew_month_start[][3] = {
+ /* Deficient Normal Complete */
+ { 0, 0, 0 },
+ { 30, 30, 30 },
+ { 59, 59, 60 },
+ { 88, 89, 90 },
+ { 117, 118, 119 },
+ { 147, 148, 149 },
+ { 176, 177, 178 },
+ { 206, 207, 208 },
+ { 235, 236, 237 },
+ { 265, 266, 267 },
+ { 294, 295, 296 },
+ { 324, 325, 326 },
+ { 353, 354, 355 },
+ { 353, 354, 355 },
+};
+
+static const int16_t hebrew_leap_month_start[][3] = {
+ /* Deficient Normal Complete */
+ { 0, 0, 0 },
+ { 30, 30, 30 },
+ { 59, 59, 60 },
+ { 88, 89, 90 },
+ { 117, 118, 119 },
+ { 147, 148, 149 },
+ { 177, 178, 179 },
+ { 206, 207, 208 },
+ { 236, 237, 238 },
+ { 265, 266, 267 },
+ { 295, 296, 297 },
+ { 324, 325, 326 },
+ { 354, 355, 356 },
+ { 383, 384, 385 },
+};
+
+#define HEBREW_HOUR_PARTS 1080
+#define HEBREW_DAY_PARTS (24 * HEBREW_HOUR_PARTS)
+#define HEBREW_MONTH_FRACT (12 * HEBREW_HOUR_PARTS + 793)
+#define HEBREW_MONTH_PARTS (29 * HEBREW_DAY_PARTS + HEBREW_MONTH_FRACT)
+#define HEBREW_BAHARAD (11 * HEBREW_HOUR_PARTS + 204)
+
+/* Hebrew epoch offset for pdt_to_ordinal_days:
+ * ICU startOfYear(1)=0 corresponds to 1 Tishri 1.
+ * Mapping verified: d=1 -> ordinal=-1373427 (ISO -3760-09-08).
+ * offset = 1 - (-1373427) = 1373428.
+ */
+#define HEBREW_EPOCH_OFFSET 1373428
+
+static int64_t hebrew_start_of_year(int year)
+{
+ int64_t months = floor_div64(235LL * year - 234, 19);
+ int64_t frac = months * HEBREW_MONTH_FRACT + HEBREW_BAHARAD;
+ int64_t frac_div = floor_div64(frac, HEBREW_DAY_PARTS);
+ int64_t day = months * 29 + frac_div;
+ int wd;
+ frac = frac - frac_div * HEBREW_DAY_PARTS;
+ wd = (int)((day % 7 + 7) % 7);
+ if (wd == 2 || wd == 4 || wd == 6) {
+ day += 1;
+ wd = (int)((day % 7 + 7) % 7);
+ } else if (wd == 1 && frac >= 15 * HEBREW_HOUR_PARTS + 204 && !hebrew_is_leap(year)) {
+ day += 2;
+ } else if (wd == 0 && frac >= 21 * HEBREW_HOUR_PARTS + 589 && hebrew_is_leap(year - 1)) {
+ day += 1;
+ }
+ return day;
+}
+
+static int hebrew_year_type(int year)
+{
+ int len = (int)(hebrew_start_of_year(year + 1) - hebrew_start_of_year(year));
+ if (hebrew_is_leap(year))
+ len -= 30;
+ if (len == 353) return 0;
+ if (len == 355) return 2;
+ return 1;
+}
+
+static void ti_hebrew_date_to_iso(int cal_year, int cal_month, int cal_day,
+ int *iso_year, int *iso_month, int *iso_day)
+{
+ int64_t d = hebrew_start_of_year(cal_year) + cal_day - 1;
+ int i;
+ int type = hebrew_year_type(cal_year);
+ for (i = 1; i < cal_month; i++)
+ d += hebrew_is_leap(cal_year) ? hebrew_leap_month_start[i][type] - hebrew_leap_month_start[i - 1][type]
+ : hebrew_month_start[i][type] - hebrew_month_start[i - 1][type];
+ pdt_from_ordinal_days(d - HEBREW_EPOCH_OFFSET, iso_year, iso_month, iso_day);
+}
+
+static void ti_iso_to_hebrew_date(int iso_year, int iso_month, int iso_day,
+ int *cal_year, int *cal_month, int *cal_day)
+{
+ int64_t ordinal = pdt_to_ordinal_days(iso_year, iso_month, iso_day);
+ int64_t d = ordinal + HEBREW_EPOCH_OFFSET;
+ /* Estimate year using the same formula as ICU:
+ * months ≈ floor(d * DAY_PARTS / MONTH_PARTS)
+ * year ≈ floor((19 * months + 234) / 235) + 1
+ */
+ int64_t est_months = floor_div64(d * HEBREW_DAY_PARTS, HEBREW_MONTH_PARTS);
+ int year = (int)floor_div64(19 * est_months + 234, 235) + 1;
+ if (year < 1) year = 1;
+ while (d < hebrew_start_of_year(year)) year--;
+ while (d > hebrew_start_of_year(year + 1)) year++;
+ {
+ int day_of_year = (int)(d - hebrew_start_of_year(year)) + 1;
+ int type = hebrew_year_type(year);
+ int is_leap = hebrew_is_leap(year);
+ const int16_t (*table)[3] = is_leap ? hebrew_leap_month_start : hebrew_month_start;
+ int month = 0;
+ while (month < 13 && day_of_year > table[month + 1][type]) month++;
+ *cal_year = year;
+ *cal_month = month + 1;
+ *cal_day = day_of_year - table[month][type];
+ }
+}
+
+/* ===== Islamic umalqura ===== */
+/* Table-based observational calendar for years 1300-1600.
+ Outside this range, falls back to Islamic civil rules. */
+
+#define UMALQURA_YEAR_START 1300
+#define UMALQURA_YEAR_END 1600
+
+static const int16_t umalqura_year_lengths[301] = {
+ 0x0AAA, 0x0D54, 0x0EC9, 0x06D4, 0x06EA, 0x036C, 0x0AAD, 0x0555,
+ 0x06A9, 0x0792, 0x0BA9, 0x05D4, 0x0ADA, 0x055C, 0x0D2D, 0x0695,
+ 0x074A, 0x0B54, 0x0B6A, 0x05AD, 0x04AE, 0x0A4F, 0x0517, 0x068B,
+ 0x06A5, 0x0AD5, 0x02D6, 0x095B, 0x049D, 0x0A4D, 0x0D26, 0x0D95,
+ 0x05AC, 0x09B6, 0x02BA, 0x0A5B, 0x052B, 0x0A95, 0x06CA, 0x0AE9,
+ 0x02F4, 0x0976, 0x02B6, 0x0956, 0x0ACA, 0x0BA4, 0x0BD2, 0x05D9,
+ 0x02DC, 0x096D, 0x054D, 0x0AA5, 0x0B52, 0x0BA5, 0x05B4, 0x09B6,
+ 0x0557, 0x0297, 0x054B, 0x06A3, 0x0752, 0x0B65, 0x056A, 0x0AAB,
+ 0x052B, 0x0C95, 0x0D4A, 0x0DA5, 0x05CA, 0x0AD6, 0x0957, 0x04AB,
+ 0x094B, 0x0AA5, 0x0B52, 0x0B6A, 0x0575, 0x0276, 0x08B7, 0x045B,
+ 0x0555, 0x05A9, 0x05B4, 0x09DA, 0x04DD, 0x026E, 0x0936, 0x0AAA,
+ 0x0D54, 0x0DB2, 0x05D5, 0x02DA, 0x095B, 0x04AB, 0x0A55, 0x0B49,
+ 0x0B64, 0x0B71, 0x05B4, 0x0AB5, 0x0A55, 0x0D25, 0x0E92, 0x0EC9,
+ 0x06D4, 0x0AE9, 0x096B, 0x04AB, 0x0A93, 0x0D49, 0x0DA4, 0x0DB2,
+ 0x0AB9, 0x04BA, 0x0A5B, 0x052B, 0x0A95, 0x0B2A, 0x0B55, 0x055C,
+ 0x04BD, 0x023D, 0x091D, 0x0A95, 0x0B4A, 0x0B5A, 0x056D, 0x02B6,
+ 0x093B, 0x049B, 0x0655, 0x06A9, 0x0754, 0x0B6A, 0x056C, 0x0AAD,
+ 0x0555, 0x0B29, 0x0B92, 0x0BA9, 0x05D4, 0x0ADA, 0x055A, 0x0AAB,
+ 0x0595, 0x0749, 0x0764, 0x0BAA, 0x05B5, 0x02B6, 0x0A56, 0x0E4D,
+ 0x0B25, 0x0B52, 0x0B6A, 0x05AD, 0x02AE, 0x092F, 0x0497, 0x064B,
+ 0x06A5, 0x06AC, 0x0AD6, 0x055D, 0x049D, 0x0A4D, 0x0D16, 0x0D95,
+ 0x05AA, 0x05B5, 0x02DA, 0x095B, 0x04AD, 0x0595, 0x06CA, 0x06E4,
+ 0x0AEA, 0x04F5, 0x02B6, 0x0956, 0x0AAA, 0x0B54, 0x0BD2, 0x05D9,
+ 0x02EA, 0x096D, 0x04AD, 0x0A95, 0x0B4A, 0x0BA5, 0x05B2, 0x09B5,
+ 0x04D6, 0x0A97, 0x0547, 0x0693, 0x0749, 0x0B55, 0x056A, 0x0A6B,
+ 0x052B, 0x0A8B, 0x0D46, 0x0DA3, 0x05CA, 0x0AD6, 0x04DB, 0x026B,
+ 0x094B, 0x0AA5, 0x0B52, 0x0B69, 0x0575, 0x0176, 0x08B7, 0x025B,
+ 0x052B, 0x0565, 0x05B4, 0x09DA, 0x04ED, 0x016D, 0x08B6, 0x0AA6,
+ 0x0D52, 0x0DA9, 0x05D4, 0x0ADA, 0x095B, 0x04AB, 0x0653, 0x0729,
+ 0x0762, 0x0BA9, 0x05B2, 0x0AB5, 0x0555, 0x0B25, 0x0D92, 0x0EC9,
+ 0x06D2, 0x0AE9, 0x056B, 0x04AB, 0x0A55, 0x0D29, 0x0D54, 0x0DAA,
+ 0x09B5, 0x04BA, 0x0A3B, 0x049B, 0x0A4D, 0x0AAA, 0x0AD5, 0x02DA,
+ 0x095D, 0x045E, 0x0A2E, 0x0C9A, 0x0D55, 0x06B2, 0x06B9, 0x04BA,
+ 0x0A5D, 0x052D, 0x0A95, 0x0B52, 0x0BA8, 0x0BB4, 0x05B9, 0x02DA,
+ 0x095A, 0x0B4A, 0x0DA4, 0x0ED1, 0x06E8, 0x0B6A, 0x056D, 0x0535,
+ 0x0695, 0x0D4A, 0x0DA8, 0x0DD4, 0x06DA, 0x055B, 0x029D, 0x062B,
+ 0x0B15, 0x0B4A, 0x0B95, 0x05AA, 0x0AAE, 0x092E, 0x0C8F, 0x0527,
+ 0x0695, 0x06AA, 0x0AD6, 0x055D, 0x029D,
+};
+
+static const int32_t umalqura_year_starts[302] = {
+ 460322, 460676, 461030, 461385, 461739, 462094, 462448, 462803,
+ 463157, 463511, 463865, 464220, 464574, 464929, 465283, 465638,
+ 465992, 466346, 466700, 467055, 467410, 467764, 468119, 468473,
+ 468827, 469181, 469536, 469890, 470245, 470599, 470953, 471307,
+ 471662, 472016, 472371, 472725, 473080, 473434, 473788, 474142,
+ 474497, 474851, 475206, 475560, 475914, 476268, 476622, 476977,
+ 477332, 477686, 478041, 478395, 478749, 479103, 479458, 479812,
+ 480167, 480522, 480876, 481230, 481584, 481938, 482293, 482647,
+ 483002, 483356, 483710, 484064, 484419, 484773, 485128, 485483,
+ 485837, 486191, 486545, 486899, 487254, 487609, 487963, 488318,
+ 488672, 489026, 489380, 489734, 490089, 490444, 490798, 491152,
+ 491506, 491860, 492215, 492570, 492924, 493279, 493633, 493987,
+ 494341, 494695, 495050, 495404, 495759, 496113, 496467, 496821,
+ 497176, 497530, 497885, 498240, 498594, 498948, 499302, 499656,
+ 500011, 500366, 500720, 501075, 501429, 501783, 502137, 502492,
+ 502846, 503201, 503555, 503909, 504263, 504617, 504972, 505327,
+ 505681, 506036, 506390, 506744, 507098, 507452, 507807, 508161,
+ 508516, 508870, 509224, 509578, 509933, 510287, 510642, 510996,
+ 511351, 511705, 512059, 512413, 512768, 513123, 513477, 513831,
+ 514186, 514540, 514894, 515249, 515604, 515958, 516313, 516667,
+ 517021, 517375, 517729, 518084, 518439, 518793, 519147, 519501,
+ 519856, 520210, 520565, 520919, 521274, 521628, 521982, 522336,
+ 522690, 523045, 523400, 523754, 524108, 524462, 524816, 525171,
+ 525526, 525880, 526235, 526589, 526943, 527297, 527652, 528006,
+ 528361, 528715, 529070, 529424, 529778, 530132, 530487, 530841,
+ 531196, 531550, 531904, 532258, 532613, 532967, 533322, 533677,
+ 534031, 534385, 534739, 535093, 535448, 535803, 536157, 536512,
+ 536866, 537220, 537574, 537928, 538283, 538638, 538992, 539346,
+ 539700, 540054, 540409, 540763, 541118, 541473, 541827, 542181,
+ 542535, 542889, 543244, 543598, 543953, 544307, 544661, 545015,
+ 545370, 545724, 546079, 546434, 546788, 547142, 547496, 547850,
+ 548205, 548560, 548914, 549269, 549623, 549977, 550331, 550686,
+ 551040, 551395, 551749, 552103, 552457, 552812, 553166, 553521,
+ 553875, 554230, 554584, 554938, 555292, 555646, 556001, 556356,
+ 556710, 557064, 557418, 557772, 558127, 558481, 558836, 559191,
+ 559545, 559899, 560253, 560607, 560962, 561317, 561672, 562026,
+ 562380, 562734, 563088, 563443, 563797, 564152, 564506, 564861,
+ 565215, 565569, 565923, 566278, 566633, 566987
+};
+
+static int umalqura_in_range(int year)
+{
+ return year >= UMALQURA_YEAR_START && year <= UMALQURA_YEAR_END;
+}
+
+static int umalqura_month_length(int year_idx, int month)
+{
+ int val = umalqura_year_lengths[year_idx];
+ int bit = (val >> (11 - (month - 1))) & 1;
+ return bit ? 30 : 29;
+}
+
+static int islamic_umalqura_is_leap(int year)
+{
+ int idx;
+ if (!umalqura_in_range(year))
+ return islamic_civil_is_leap(year);
+ idx = year - UMALQURA_YEAR_START;
+ return umalqura_month_length(idx, 1) + umalqura_month_length(idx, 2) +
+ umalqura_month_length(idx, 3) + umalqura_month_length(idx, 4) +
+ umalqura_month_length(idx, 5) + umalqura_month_length(idx, 6) +
+ umalqura_month_length(idx, 7) + umalqura_month_length(idx, 8) +
+ umalqura_month_length(idx, 9) + umalqura_month_length(idx, 10) +
+ umalqura_month_length(idx, 11) + umalqura_month_length(idx, 12) == 355;
+}
+
+static int islamic_umalqura_days_in_year(int year)
+{
+ int idx;
+ if (!umalqura_in_range(year))
+ return islamic_civil_days_in_year(year);
+ idx = year - UMALQURA_YEAR_START;
+ return umalqura_month_length(idx, 1) + umalqura_month_length(idx, 2) +
+ umalqura_month_length(idx, 3) + umalqura_month_length(idx, 4) +
+ umalqura_month_length(idx, 5) + umalqura_month_length(idx, 6) +
+ umalqura_month_length(idx, 7) + umalqura_month_length(idx, 8) +
+ umalqura_month_length(idx, 9) + umalqura_month_length(idx, 10) +
+ umalqura_month_length(idx, 11) + umalqura_month_length(idx, 12);
+}
+
+static int islamic_umalqura_months_in_year(int year)
+{
+ (void)year;
+ return 12;
+}
+
+static int islamic_umalqura_days_in_month(int year, int month)
+{
+ int idx;
+ if (!umalqura_in_range(year))
+ return islamic_civil_days_in_month(year, month);
+ if (month < 1 || month > 12)
+ return 29;
+ idx = year - UMALQURA_YEAR_START;
+ return umalqura_month_length(idx, month);
+}
+
+/* ===== Islamic civil <-> ISO conversion ===== */
+#define ISLAMIC_CIVIL_EPOCH_ORDINAL 227014
+
+static int64_t islamic_civil_month_start(int year, int month)
+{
+ return (59LL * month + 1) / 2 + 354LL * (year - 1) + floor_div64(11LL * year + 3, 30);
+}
+
+static void ti_islamic_civil_to_iso(int year, int month, int day, int *iso_year, int *iso_month, int *iso_day)
+{
+ int64_t days_from_epoch = islamic_civil_month_start(year, month - 1) + (day - 1);
+ pdt_from_ordinal_days(ISLAMIC_CIVIL_EPOCH_ORDINAL + days_from_epoch, iso_year, iso_month, iso_day);
+}
+
+static void ti_iso_to_islamic_civil(int iso_year, int iso_month, int iso_day, int *year, int *month, int *day)
+{
+ int64_t ordinal = pdt_to_ordinal_days(iso_year, iso_month, iso_day);
+ int64_t days = ordinal - ISLAMIC_CIVIL_EPOCH_ORDINAL;
+ int y = (int)floor_div64(30 * days + 10646, 10631);
+ int64_t yd = islamic_civil_month_start(y, 0);
+ while (yd > days) {
+ y--;
+ yd = islamic_civil_month_start(y, 0);
+ }
+ while (yd + (islamic_civil_is_leap(y) ? 355 : 354) <= days) {
+ y++;
+ yd = islamic_civil_month_start(y, 0);
+ }
+ int doy = (int)(days - yd);
+ int m = 0;
+ while (m < 11 && doy >= islamic_civil_days_in_month(y, m + 1)) {
+ doy -= islamic_civil_days_in_month(y, m + 1);
+ m++;
+ }
+ *year = y;
+ *month = m + 1;
+ *day = doy + 1;
+}
+
+/* ===== Islamic tbla <-> ISO conversion ===== */
+#define ISLAMIC_TBLA_EPOCH_ORDINAL 227013
+
+static void ti_islamic_tbla_to_iso(int year, int month, int day, int *iso_year, int *iso_month, int *iso_day)
+{
+ int64_t days_from_epoch = islamic_civil_month_start(year, month - 1) + (day - 1);
+ pdt_from_ordinal_days(ISLAMIC_TBLA_EPOCH_ORDINAL + days_from_epoch, iso_year, iso_month, iso_day);
+}
+
+static void ti_iso_to_islamic_tbla(int iso_year, int iso_month, int iso_day, int *year, int *month, int *day)
+{
+ int64_t ordinal = pdt_to_ordinal_days(iso_year, iso_month, iso_day);
+ int64_t days = ordinal - ISLAMIC_TBLA_EPOCH_ORDINAL;
+ int y = (int)floor_div64(30 * days + 10646, 10631);
+ int64_t yd = islamic_civil_month_start(y, 0);
+ while (yd > days) {
+ y--;
+ yd = islamic_civil_month_start(y, 0);
+ }
+ while (yd + (islamic_civil_is_leap(y) ? 355 : 354) <= days) {
+ y++;
+ yd = islamic_civil_month_start(y, 0);
+ }
+ int doy = (int)(days - yd);
+ int m = 0;
+ while (m < 11 && doy >= islamic_civil_days_in_month(y, m + 1)) {
+ doy -= islamic_civil_days_in_month(y, m + 1);
+ m++;
+ }
+ *year = y;
+ *month = m + 1;
+ *day = doy + 1;
+}
+
+static void ti_islamic_umalqura_to_iso(int year, int month, int day, int *iso_year, int *iso_month, int *iso_day)
+{
+ if (umalqura_in_range(year)) {
+ int idx = year - UMALQURA_YEAR_START;
+ int64_t days_from_epoch = umalqura_year_starts[idx];
+ int m;
+ for (m = 1; m < month; m++)
+ days_from_epoch += umalqura_month_length(idx, m);
+ days_from_epoch += (day - 1);
+ pdt_from_ordinal_days(ISLAMIC_CIVIL_EPOCH_ORDINAL + days_from_epoch, iso_year, iso_month, iso_day);
+ } else {
+ /* Fallback to civil outside table range */
+ ti_islamic_civil_to_iso(year, month, day, iso_year, iso_month, iso_day);
+ }
+}
+
+static void ti_iso_to_islamic_umalqura(int iso_year, int iso_month, int iso_day, int *year, int *month, int *day)
+{
+ int64_t ordinal = pdt_to_ordinal_days(iso_year, iso_month, iso_day);
+ int64_t days = ordinal - ISLAMIC_CIVIL_EPOCH_ORDINAL;
+ int y, idx;
+ /* Check if within table range */
+ if (days >= umalqura_year_starts[0] && days < umalqura_year_starts[301]) {
+ /* Binary search for year */
+ int lo = 0, hi = 300;
+ while (lo < hi) {
+ int mid = lo + (hi - lo + 1) / 2;
+ if (umalqura_year_starts[mid] <= days)
+ lo = mid;
+ else
+ hi = mid - 1;
+ }
+ y = UMALQURA_YEAR_START + lo;
+ idx = lo;
+ } else {
+ /* Fallback to civil */
+ ti_iso_to_islamic_civil(iso_year, iso_month, iso_day, year, month, day);
+ return;
+ }
+ {
+ int64_t yd = umalqura_year_starts[idx];
+ int doy = (int)(days - yd);
+ int m = 0;
+ while (m < 11) {
+ int mlen = umalqura_month_length(idx, m + 1);
+ if (doy < mlen)
+ break;
+ doy -= mlen;
+ m++;
+ }
+ *year = y;
+ *month = m + 1;
+ *day = doy + 1;
+ }
+}
+
+/* ===== Calendar <-> ISO conversion functions ===== */
+
+/* Coptic epoch: Thout 1, year 1 = August 29, 284 CE = ordinal 103604 */
+#define COPTIC_EPOCH_ORDINAL 103604
+
+static void ti_coptic_to_iso(int year, int month, int day, int *iso_year, int *iso_month, int *iso_day)
+{
+ int64_t ordinal = COPTIC_EPOCH_ORDINAL + 365 * (int64_t)(year - 1) + floor_div64(year, 4) + 30 * (month - 1) + (day - 1);
+ pdt_from_ordinal_days(ordinal, iso_year, iso_month, iso_day);
+}
+
+static void ti_iso_to_coptic(int iso_year, int iso_month, int iso_day, int *year, int *month, int *day)
+{
+ int64_t ordinal = pdt_to_ordinal_days(iso_year, iso_month, iso_day);
+ int64_t coptic_ordinal = ordinal - COPTIC_EPOCH_ORDINAL;
+ int64_t q = floor_div64(coptic_ordinal, 1461);
+ int64_t r = coptic_ordinal - q * 1461;
+ int n;
+ if (r < 365) n = 0;
+ else if (r < 730) n = 1;
+ else if (r < 1096) n = 2;
+ else n = 3;
+ *year = (int)(4 * q + n + 1);
+ {
+ int64_t rd_year_start = 365 * (*year - 1) + floor_div64(*year, 4);
+ int64_t remaining = coptic_ordinal - rd_year_start;
+ if (month)
+ *month = (int)(remaining / 30 + 1);
+ if (day)
+ *day = (int)(remaining % 30 + 1);
+ }
+}
+
+/* Ethiopic epoch: Maskaram 1, year 1 = August 27, 8 CE = ordinal 2795 */
+#define ETHIOPIC_EPOCH_ORDINAL 2795
+
+static void ti_ethiopic_to_iso(int year, int month, int day, int *iso_year, int *iso_month, int *iso_day)
+{
+ int64_t ordinal = ETHIOPIC_EPOCH_ORDINAL + 365 * (int64_t)(year - 1) + floor_div64(year, 4) + 30 * (month - 1) + (day - 1);
+ pdt_from_ordinal_days(ordinal, iso_year, iso_month, iso_day);
+}
+
+static void ti_iso_to_ethiopic(int iso_year, int iso_month, int iso_day, int *year, int *month, int *day)
+{
+ int64_t ordinal = pdt_to_ordinal_days(iso_year, iso_month, iso_day);
+ int64_t ethiopic_ordinal = ordinal - ETHIOPIC_EPOCH_ORDINAL;
+ int64_t q = floor_div64(ethiopic_ordinal, 1461);
+ int64_t r = ethiopic_ordinal - q * 1461;
+ int n;
+ if (r < 365) n = 0;
+ else if (r < 730) n = 1;
+ else if (r < 1096) n = 2;
+ else n = 3;
+ *year = (int)(4 * q + n + 1);
+ {
+ int64_t rd_year_start = 365 * (*year - 1) + floor_div64(*year, 4);
+ int64_t remaining = ethiopic_ordinal - rd_year_start;
+ if (month)
+ *month = (int)(remaining / 30 + 1);
+ if (day)
+ *day = (int)(remaining % 30 + 1);
+ }
+}
+
+static void ti_ethioaa_to_iso(int year, int month, int day, int *iso_year, int *iso_month, int *iso_day)
+{
+ ti_ethiopic_to_iso(year - 5500, month, day, iso_year, iso_month, iso_day);
+}
+
+static void ti_iso_to_ethioaa(int iso_year, int iso_month, int iso_day, int *year, int *month, int *day)
+{
+ ti_iso_to_ethiopic(iso_year, iso_month, iso_day, year, month, day);
+ *year += 5500;
+}
+
+/* Persian epoch: 1 Farvardin 1 AP = March 21, 622 CE = ordinal 226894 */
+#define PERSIAN_EPOCH_ORDINAL 226894
+
+static void ti_persian_to_iso(int year, int month, int day, int *iso_year, int *iso_month, int *iso_day)
+{
+ static const int num_days[12] = {0, 31, 62, 93, 124, 155, 186, 216, 246, 276, 306, 336};
+ int64_t days_from_epoch = 365LL * (year - 1) + floor_div64(8LL * year + 21, 33);
+ if (month > 1)
+ days_from_epoch += num_days[month - 1];
+ days_from_epoch += day - 1;
+ pdt_from_ordinal_days(PERSIAN_EPOCH_ORDINAL + days_from_epoch, iso_year, iso_month, iso_day);
+}
+
+static void ti_iso_to_persian(int iso_year, int iso_month, int iso_day, int *year, int *month, int *day)
+{
+ static const int num_days[12] = {0, 31, 62, 93, 124, 155, 186, 216, 246, 276, 306, 336};
+ int64_t ordinal = pdt_to_ordinal_days(iso_year, iso_month, iso_day);
+ int64_t days = ordinal - PERSIAN_EPOCH_ORDINAL;
+ int64_t y = floor_div64(33LL * days + 3, 12053) + 1;
+ int64_t farvardin1 = 365LL * (y - 1) + floor_div64(8LL * y + 21, 33);
+ int64_t day_of_year = days - farvardin1;
+ if (day_of_year == 365 && !persian_is_leap((int)y)) {
+ y++;
+ farvardin1 = 365LL * (y - 1) + floor_div64(8LL * y + 21, 33);
+ day_of_year = days - farvardin1;
+ }
+ int64_t m;
+ if (day_of_year < 216) {
+ m = day_of_year / 31;
+ } else {
+ m = (day_of_year - 6) / 30;
+ }
+ *year = (int)y;
+ *month = (int)(m + 1);
+ *day = (int)(day_of_year - num_days[m] + 1);
+}
+
+/* Chinese/Dangi date <-> ISO conversion using precomputed tables */
+static int ti_chinese_date_to_iso(int cal_year, int cal_month, int cal_day,
+ int *iso_year, int *iso_month, int *iso_day,
+ const ChineseCalendarEntry *data, int count)
+{
+ const ChineseCalendarEntry *e;
+ int64_t ny_ordinal, target_ordinal;
+ int doy = cal_day;
+ int i;
+ int idx = cal_year - 1800;
+ if (idx < 0 || idx >= count)
+ return -1;
+ e = &data[idx];
+ if (cal_month < 1 || cal_month > cce_num_months(e) || cal_day < 1 || cal_day > cce_month_length(e, cal_month - 1))
+ return -1;
+ ny_ordinal = pdt_to_ordinal_days(cal_year, cce_cny_month(e), cce_cny_day(e));
+ for (i = 0; i < cal_month - 1; i++)
+ doy += cce_month_length(e, i);
+ target_ordinal = ny_ordinal + doy - 1;
+ pdt_from_ordinal_days(target_ordinal, iso_year, iso_month, iso_day);
+ return 0;
+}
+
+static int ti_iso_to_chinese_date(int iso_year, int iso_month, int iso_day,
+ int *cal_year, int *cal_month, int *cal_day,
+ const ChineseCalendarEntry *data, int count)
+{
+ int64_t target_ordinal = pdt_to_ordinal_days(iso_year, iso_month, iso_day);
+ int i;
+ for (i = 0; i < count; i++) {
+ const ChineseCalendarEntry *e = &data[i];
+ int64_t ny_ordinal = pdt_to_ordinal_days(1800 + i, cce_cny_month(e), cce_cny_day(e));
+ int days_in_year = 0;
+ int j;
+ for (j = 0; j < cce_num_months(e); j++)
+ days_in_year += cce_month_length(e, j);
+ if (target_ordinal >= ny_ordinal && target_ordinal < ny_ordinal + days_in_year) {
+ int doy = (int)(target_ordinal - ny_ordinal) + 1;
+ int month = 1;
+ while (month <= cce_num_months(e) && doy > cce_month_length(e, month - 1)) {
+ doy -= cce_month_length(e, month - 1);
+ month++;
+ }
+ *cal_year = 1800 + i;
+ *cal_month = month;
+ *cal_day = doy;
+ return 0;
+ }
+ }
+ return -1;
+}
+
+/* CalendarDateToISO: convert calendar year/month/day to ISO year/month/day */
+int ti_calendar_date_to_iso(CalendarType cal, int cal_year, int cal_month, int cal_day,
+ int *iso_year, int *iso_month, int *iso_day)
+{
+ switch (cal) {
+ case CAL_ISO8601:
+ case CAL_GREGORY:
+ case CAL_JAPANESE:
+ *iso_year = cal_year;
+ *iso_month = cal_month;
+ *iso_day = cal_day;
+ return 0;
+ case CAL_BUDDHIST:
+ *iso_year = cal_year - 543;
+ *iso_month = cal_month;
+ *iso_day = cal_day;
+ return 0;
+ case CAL_ROC:
+ *iso_year = cal_year + 1911;
+ *iso_month = cal_month;
+ *iso_day = cal_day;
+ return 0;
+ case CAL_COPTIC:
+ ti_coptic_to_iso(cal_year, cal_month, cal_day, iso_year, iso_month, iso_day);
+ return 0;
+ case CAL_ETHIOPIC:
+ ti_ethiopic_to_iso(cal_year, cal_month, cal_day, iso_year, iso_month, iso_day);
+ return 0;
+ case CAL_ETHIOAA:
+ ti_ethioaa_to_iso(cal_year, cal_month, cal_day, iso_year, iso_month, iso_day);
+ return 0;
+ case CAL_HEBREW:
+ ti_hebrew_date_to_iso(cal_year, cal_month, cal_day, iso_year, iso_month, iso_day);
+ return 0;
+ case CAL_PERSIAN:
+ ti_persian_to_iso(cal_year, cal_month, cal_day, iso_year, iso_month, iso_day);
+ return 0;
+ case CAL_ISLAMIC_CIVIL:
+ ti_islamic_civil_to_iso(cal_year, cal_month, cal_day, iso_year, iso_month, iso_day);
+ return 0;
+ case CAL_ISLAMIC_TBLA:
+ ti_islamic_tbla_to_iso(cal_year, cal_month, cal_day, iso_year, iso_month, iso_day);
+ return 0;
+ case CAL_ISLAMIC_UMALQURA:
+ ti_islamic_umalqura_to_iso(cal_year, cal_month, cal_day, iso_year, iso_month, iso_day);
+ return 0;
+ case CAL_INDIAN:
+ return ti_indian_to_iso(cal_year, cal_month, cal_day, iso_year, iso_month, iso_day);
+ case CAL_CHINESE:
+ if (ti_chinese_date_to_iso(cal_year, cal_month, cal_day, iso_year, iso_month, iso_day,
+ chinese_calendar_data,
+ sizeof(chinese_calendar_data) / sizeof(chinese_calendar_data[0])) == 0)
+ return 0;
+ break;
+ case CAL_DANGI:
+ if (ti_chinese_date_to_iso(cal_year, cal_month, cal_day, iso_year, iso_month, iso_day,
+ dangi_calendar_data,
+ sizeof(dangi_calendar_data) / sizeof(dangi_calendar_data[0])) == 0)
+ return 0;
+ break;
+ default:
+ break;
+ }
+ /* Fallback: treat calendar date as ISO date (old behavior) */
+ *iso_year = cal_year;
+ *iso_month = cal_month;
+ *iso_day = cal_day;
+ return 0;
+}
+
+/* ISOToCalendarDate: convert ISO year/month/day to calendar year/month/day */
+int ti_iso_to_calendar_date(CalendarType cal, int iso_year, int iso_month, int iso_day,
+ int *cal_year, int *cal_month, int *cal_day)
+{
+ switch (cal) {
+ case CAL_ISO8601:
+ case CAL_GREGORY:
+ case CAL_JAPANESE:
+ *cal_year = iso_year;
+ *cal_month = iso_month;
+ *cal_day = iso_day;
+ return 0;
+ case CAL_BUDDHIST:
+ *cal_year = iso_year + 543;
+ *cal_month = iso_month;
+ *cal_day = iso_day;
+ return 0;
+ case CAL_ROC:
+ *cal_year = iso_year - 1911;
+ *cal_month = iso_month;
+ *cal_day = iso_day;
+ return 0;
+ case CAL_COPTIC:
+ ti_iso_to_coptic(iso_year, iso_month, iso_day, cal_year, cal_month, cal_day);
+ return 0;
+ case CAL_ETHIOPIC:
+ ti_iso_to_ethiopic(iso_year, iso_month, iso_day, cal_year, cal_month, cal_day);
+ return 0;
+ case CAL_ETHIOAA:
+ ti_iso_to_ethioaa(iso_year, iso_month, iso_day, cal_year, cal_month, cal_day);
+ return 0;
+ case CAL_HEBREW:
+ ti_iso_to_hebrew_date(iso_year, iso_month, iso_day, cal_year, cal_month, cal_day);
+ return 0;
+ case CAL_PERSIAN:
+ ti_iso_to_persian(iso_year, iso_month, iso_day, cal_year, cal_month, cal_day);
+ return 0;
+ case CAL_ISLAMIC_CIVIL:
+ ti_iso_to_islamic_civil(iso_year, iso_month, iso_day, cal_year, cal_month, cal_day);
+ return 0;
+ case CAL_ISLAMIC_TBLA:
+ ti_iso_to_islamic_tbla(iso_year, iso_month, iso_day, cal_year, cal_month, cal_day);
+ return 0;
+ case CAL_ISLAMIC_UMALQURA:
+ ti_iso_to_islamic_umalqura(iso_year, iso_month, iso_day, cal_year, cal_month, cal_day);
+ return 0;
+ case CAL_INDIAN:
+ return ti_iso_to_indian(iso_year, iso_month, iso_day, cal_year, cal_month, cal_day);
+ case CAL_CHINESE:
+ if (ti_iso_to_chinese_date(iso_year, iso_month, iso_day, cal_year, cal_month, cal_day,
+ chinese_calendar_data,
+ sizeof(chinese_calendar_data) / sizeof(chinese_calendar_data[0])) == 0)
+ return 0;
+ break;
+ case CAL_DANGI:
+ if (ti_iso_to_chinese_date(iso_year, iso_month, iso_day, cal_year, cal_month, cal_day,
+ dangi_calendar_data,
+ sizeof(dangi_calendar_data) / sizeof(dangi_calendar_data[0])) == 0)
+ return 0;
+ break;
+ default:
+ break;
+ }
+ /* Fallback: treat ISO date as calendar date (old behavior) */
+ *cal_year = iso_year;
+ *cal_month = iso_month;
+ *cal_day = iso_day;
+ return 0;
+}
+
+/* ===== Public dispatch functions ===== */
+
+int ti_calendar_is_leap_year(CalendarType cal, int year)
+{
+ switch (cal) {
+ case CAL_COPTIC:
+ case CAL_ETHIOPIC:
+ case CAL_ETHIOAA:
+ return coptic_ethiopic_is_leap(year);
+ case CAL_PERSIAN:
+ return persian_is_leap(year);
+ case CAL_ISLAMIC_CIVIL:
+ case CAL_ISLAMIC_TBLA:
+ return islamic_civil_is_leap(year);
+ case CAL_INDIAN:
+ return indian_is_leap(year);
+ case CAL_CHINESE:
+ return ti_calendar_is_leap_year_chinese(year);
+ case CAL_DANGI:
+ return ti_calendar_is_leap_year_dangi(year);
+ case CAL_HEBREW:
+ return hebrew_is_leap(year);
+ case CAL_ISLAMIC_UMALQURA:
+ return islamic_umalqura_is_leap(year);
+ case CAL_BUDDHIST:
+ return pd_is_leap_year(year - 543);
+ case CAL_ROC:
+ return pd_is_leap_year(year + 1911);
+ case CAL_GREGORY:
+ case CAL_JAPANESE:
+ case CAL_ISO8601:
+ default:
+ return pd_is_leap_year(year);
+ }
+}
+
+int ti_calendar_days_in_year(CalendarType cal, int year)
+{
+ switch (cal) {
+ case CAL_COPTIC:
+ case CAL_ETHIOPIC:
+ case CAL_ETHIOAA:
+ return coptic_ethiopic_days_in_year(year);
+ case CAL_PERSIAN:
+ return persian_days_in_year(year);
+ case CAL_ISLAMIC_CIVIL:
+ case CAL_ISLAMIC_TBLA:
+ return islamic_civil_days_in_year(year);
+ case CAL_INDIAN:
+ return indian_days_in_year(year);
+ case CAL_CHINESE:
+ return ti_calendar_days_in_year_chinese(year);
+ case CAL_DANGI:
+ return ti_calendar_days_in_year_dangi(year);
+ case CAL_HEBREW:
+ return hebrew_days_in_year(year);
+ case CAL_ISLAMIC_UMALQURA:
+ return islamic_umalqura_days_in_year(year);
+ case CAL_BUDDHIST:
+ return pd_is_leap_year(year - 543) ? 366 : 365;
+ case CAL_ROC:
+ return pd_is_leap_year(year + 1911) ? 366 : 365;
+ case CAL_GREGORY:
+ case CAL_JAPANESE:
+ case CAL_ISO8601:
+ default:
+ return pd_is_leap_year(year) ? 366 : 365;
+ }
+}
+
+int ti_calendar_months_in_year(CalendarType cal, int year)
+{
+ switch (cal) {
+ case CAL_COPTIC:
+ case CAL_ETHIOPIC:
+ case CAL_ETHIOAA:
+ return coptic_ethiopic_months_in_year(year);
+ case CAL_PERSIAN:
+ return persian_months_in_year(year);
+ case CAL_ISLAMIC_CIVIL:
+ case CAL_ISLAMIC_TBLA:
+ return islamic_civil_months_in_year(year);
+ case CAL_INDIAN:
+ return indian_months_in_year(year);
+ case CAL_CHINESE:
+ return ti_calendar_months_in_year_chinese(year);
+ case CAL_DANGI:
+ return ti_calendar_months_in_year_dangi(year);
+ case CAL_HEBREW:
+ return hebrew_months_in_year(year);
+ case CAL_ISLAMIC_UMALQURA:
+ return islamic_umalqura_months_in_year(year);
+ case CAL_BUDDHIST:
+ case CAL_GREGORY:
+ case CAL_JAPANESE:
+ case CAL_ROC:
+ case CAL_ISO8601:
+ default:
+ return 12;
+ }
+}
+
+int ti_calendar_days_in_month(CalendarType cal, int year, int month)
+{
+ switch (cal) {
+ case CAL_COPTIC:
+ case CAL_ETHIOPIC:
+ case CAL_ETHIOAA:
+ return coptic_ethiopic_days_in_month(year, month);
+ case CAL_PERSIAN:
+ return persian_days_in_month(year, month);
+ case CAL_ISLAMIC_CIVIL:
+ case CAL_ISLAMIC_TBLA:
+ return islamic_civil_days_in_month(year, month);
+ case CAL_INDIAN:
+ return indian_days_in_month(year, month);
+ case CAL_CHINESE:
+ return ti_calendar_days_in_month_chinese(year, month);
+ case CAL_DANGI:
+ return ti_calendar_days_in_month_dangi(year, month);
+ case CAL_HEBREW:
+ return hebrew_days_in_month(year, month);
+ case CAL_ISLAMIC_UMALQURA:
+ return islamic_umalqura_days_in_month(year, month);
+ case CAL_BUDDHIST:
+ return pd_days_in_month(year - 543, month);
+ case CAL_ROC:
+ return pd_days_in_month(year + 1911, month);
+ case CAL_GREGORY:
+ case CAL_JAPANESE:
+ case CAL_ISO8601:
+ default:
+ return pd_days_in_month(year, month);
+ }
+}
+
+int ti_calendar_day_of_year(CalendarType cal, int year, int month, int day)
+{
+ int doy = 0;
+ int i;
+ int dim = ti_calendar_days_in_month(cal, year, month);
+ if (day > dim) day = dim;
+ else if (day < 1) day = 1;
+ switch (cal) {
+ case CAL_COPTIC:
+ case CAL_ETHIOPIC:
+ case CAL_ETHIOAA:
+ if (month > 13)
+ month = 13;
+ doy = (month - 1) * 30 + day;
+ return doy;
+ case CAL_PERSIAN: {
+ int pl[12] = {31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 29};
+ if (persian_is_leap(year))
+ pl[11] = 30;
+ for (i = 0; i < month - 1; i++)
+ doy += pl[i];
+ return doy + day;
+ }
+ case CAL_ISLAMIC_CIVIL:
+ case CAL_ISLAMIC_TBLA: {
+ int il[12] = {30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29};
+ if (islamic_civil_is_leap(year))
+ il[11] = 30;
+ for (i = 0; i < month - 1; i++)
+ doy += il[i];
+ return doy + day;
+ }
+ case CAL_INDIAN: {
+ int il2[12] = {30, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 30};
+ if (indian_is_leap(year))
+ il2[0] = 31;
+ for (i = 0; i < month - 1; i++)
+ doy += il2[i];
+ return doy + day;
+ }
+ case CAL_HEBREW: {
+ for (i = 1; i < month; i++)
+ doy += hebrew_days_in_month(year, i);
+ return doy + day;
+ }
+ case CAL_CHINESE: {
+ const ChineseCalendarEntry *entry = lookup_chinese_year(year);
+ if (!entry || month < 1 || month > cce_num_months(entry))
+ return (month - 1) * 29 + day;
+ for (i = 0; i < month - 1; i++)
+ doy += cce_month_length(entry, i);
+ return doy + day;
+ }
+ case CAL_DANGI: {
+ const ChineseCalendarEntry *entry = lookup_dangi_year(year);
+ if (!entry || month < 1 || month > cce_num_months(entry))
+ return (month - 1) * 29 + day;
+ for (i = 0; i < month - 1; i++)
+ doy += cce_month_length(entry, i);
+ return doy + day;
+ }
+ case CAL_ISLAMIC_UMALQURA: {
+ if (umalqura_in_range(year)) {
+ int idx = year - UMALQURA_YEAR_START;
+ for (i = 1; i < month; i++)
+ doy += umalqura_month_length(idx, i);
+ } else {
+ for (i = 1; i < month; i++)
+ doy += islamic_civil_days_in_month(year, i);
+ }
+ return doy + day;
+ }
+ case CAL_BUDDHIST:
+ return pd_day_of_year(year - 543, month, day);
+ case CAL_ROC:
+ return pd_day_of_year(year + 1911, month, day);
+ case CAL_GREGORY:
+ case CAL_JAPANESE:
+ case CAL_ISO8601:
+ default:
+ return pd_day_of_year(year, month, day);
+ }
+}
+
+/* ------------------------------------------------------------------ */
+/* Calendar-aware date arithmetic for non-ISO calendars */
+/* ------------------------------------------------------------------ */
+
+static int compare_calendar_dates(CalendarType cal, int y1, int m1, int d1,
+ int y2, int m2, int d2)
+{
+ (void)cal;
+ if (y1 != y2) return (y1 < y2) ? -1 : 1;
+ if (m1 != m2) return (m1 < m2) ? -1 : 1;
+ if (d1 != d2) return (d1 < d2) ? -1 : 1;
+ return 0;
+}
+
+static int64_t calendar_days_between(CalendarType cal, int y1, int m1, int d1,
+ int y2, int m2, int d2)
+{
+ int cmp = compare_calendar_dates(cal, y1, m1, d1, y2, m2, d2);
+ if (cmp == 0) return 0;
+
+ int sy = y1, sm = m1, sd = d1;
+ int ey = y2, em = m2, ed = d2;
+ int sign = 1;
+
+ if (cmp > 0) {
+ sy = y2; sm = m2; sd = d2;
+ ey = y1; em = m1; ed = d1;
+ sign = -1;
+ }
+
+ int64_t doy_s = ti_calendar_day_of_year(cal, sy, sm, sd);
+ int64_t doy_e = ti_calendar_day_of_year(cal, ey, em, ed);
+ int64_t total = 0;
+
+ if (sy == ey) {
+ total = doy_e - doy_s;
+ } else {
+ total = ti_calendar_days_in_year(cal, sy) - doy_s;
+ for (int y = sy + 1; y < ey; y++)
+ total += ti_calendar_days_in_year(cal, y);
+ total += doy_e;
+ }
+
+ return total * sign;
+}
+
+static void ti_balance_month(int *year, int *month, CalendarType cal)
+{
+ int max_month;
+ while (1) {
+ max_month = (cal == CAL_ISO8601 || cal == CAL_GREGORY) ? 12 : ti_calendar_months_in_year(cal, *year);
+ if (*month <= max_month && *month >= 1)
+ break;
+ if (*month > max_month) {
+ *month -= max_month;
+ (*year)++;
+ } else {
+ (*year)--;
+ max_month = (cal == CAL_ISO8601 || cal == CAL_GREGORY) ? 12 : ti_calendar_months_in_year(cal, *year);
+ *month += max_month;
+ }
+ }
+}
+
+void ti_calendar_date_until(CalendarType cal, int one_year, int one_month, int one_day,
+ int two_year, int two_month, int two_day,
+ int largestUnit,
+ int64_t *out_years, int64_t *out_months,
+ int64_t *out_weeks, int64_t *out_days)
+{
+ if (cal == CAL_ISO8601 || cal == CAL_GREGORY ||
+ cal == CAL_BUDDHIST || cal == CAL_ROC || cal == CAL_JAPANESE) {
+ ti_iso_calendar_date_until(one_year, one_month, one_day,
+ two_year, two_month, two_day, largestUnit,
+ out_years, out_months, out_weeks, out_days);
+ return;
+ }
+
+ if (out_years) *out_years = 0;
+ if (out_months) *out_months = 0;
+ if (out_weeks) *out_weeks = 0;
+ if (out_days) *out_days = 0;
+
+ int cmp = compare_calendar_dates(cal, one_year, one_month, one_day,
+ two_year, two_month, two_day);
+ if (cmp == 0)
+ return;
+
+ int sign = (cmp > 0) ? -1 : 1;
+ int64_t years = 0, months = 0, weeks = 0, days = 0;
+ int cy = one_year, cm = one_month, cd = one_day;
+
+ if (largestUnit == TI_UNIT_YEAR) {
+ while (1) {
+ int ny = cy + sign;
+ int nm = cm;
+ int nd = cd;
+
+ int c = compare_calendar_dates(cal, ny, nm, nd,
+ two_year, two_month, two_day);
+ if (sign > 0 && c > 0) break;
+ if (sign < 0 && c < 0) break;
+ cy = ny; cm = nm; cd = nd;
+ years += sign;
+ }
+ }
+
+ if (largestUnit == TI_UNIT_YEAR || largestUnit == TI_UNIT_MONTH) {
+ while (1) {
+ int ny = cy;
+ int nm = cm + sign;
+ int nd = cd;
+ if (nm > ti_calendar_months_in_year(cal, ny)) {
+ nm = 1;
+ ny++;
+ } else if (nm < 1) {
+ ny--;
+ nm = ti_calendar_months_in_year(cal, ny);
+ }
+
+ int c = compare_calendar_dates(cal, ny, nm, nd,
+ two_year, two_month, two_day);
+ if (sign > 0 && c > 0) break;
+ if (sign < 0 && c < 0) break;
+ cy = ny; cm = nm; cd = nd;
+ months += sign;
+ }
+ }
+
+ days = calendar_days_between(cal, cy, cm, cd, two_year, two_month, two_day);
+
+ if (largestUnit == TI_UNIT_WEEK) {
+ weeks = days / 7;
+ days = days % 7;
+ }
+
+ if (out_years) *out_years = years;
+ if (out_months) *out_months = months;
+ if (out_weeks) *out_weeks = weeks;
+ if (out_days) *out_days = days;
+}
+
+void ti_calendar_date_until_with_monthcode(CalendarType cal,
+ int one_year, int one_month, int one_day,
+ int one_mc, BOOL one_has_mc, BOOL one_has_l,
+ int two_year, int two_month, int two_day,
+ int two_mc, BOOL two_has_mc, BOOL two_has_l,
+ int largestUnit,
+ int64_t *out_years, int64_t *out_months,
+ int64_t *out_weeks, int64_t *out_days)
+{
+ /* non-ISO calendar date until with monthCode */
+ if (cal == CAL_ISO8601 || cal == CAL_GREGORY ||
+ cal == CAL_BUDDHIST || cal == CAL_ROC || cal == CAL_JAPANESE) {
+ ti_iso_calendar_date_until(one_year, one_month, one_day,
+ two_year, two_month, two_day, largestUnit,
+ out_years, out_months, out_weeks, out_days);
+ return;
+ }
+
+ if (out_years) *out_years = 0;
+ if (out_months) *out_months = 0;
+ if (out_weeks) *out_weeks = 0;
+ if (out_days) *out_days = 0;
+
+ int use_mc = one_has_mc && two_has_mc;
+ int cmp;
+ if (use_mc) {
+ if (one_year != two_year)
+ cmp = (one_year < two_year) ? -1 : 1;
+ else if (one_mc != two_mc)
+ cmp = (one_mc < two_mc) ? -1 : 1;
+ else if (one_has_l != two_has_l)
+ cmp = one_has_l ? 1 : -1;
+ else if (one_day != two_day)
+ cmp = (one_day < two_day) ? -1 : 1;
+ else
+ cmp = 0;
+ } else {
+ cmp = compare_calendar_dates(cal, one_year, one_month, one_day,
+ two_year, two_month, two_day);
+ }
+ if (cmp == 0)
+ return;
+
+ int sign = (cmp > 0) ? -1 : 1;
+ int64_t years = 0, months = 0, weeks = 0, days = 0;
+ int cy = one_year, cm = one_month, cd = one_day;
+
+ if (largestUnit == TI_UNIT_YEAR) {
+ years = (int64_t)two_year - (int64_t)one_year;
+ if (use_mc) {
+ /* Compute monthCode comparison: sign of (target monthCode - source monthCode) */
+ int monthCode_cmp = 0;
+ if (two_mc > one_mc)
+ monthCode_cmp = 1;
+ else if (two_mc < one_mc)
+ monthCode_cmp = -1;
+ else {
+ if (two_has_l > one_has_l)
+ monthCode_cmp = 1;
+ else if (two_has_l < one_has_l)
+ monthCode_cmp = -1;
+ else
+ monthCode_cmp = (two_day > one_day) ? 1 : (two_day < one_day) ? -1 : 0;
+ }
+ /* If monthCode ordering disagrees with overall ordering, adjust years */
+ if (monthCode_cmp * sign < 0)
+ years -= sign;
+
+ /* Verify: add years to source and check if it overshoots target */
+ if (years != 0) {
+ int vy = one_year + (int)years;
+ int vm = ti_calendar_month_code_to_month(cal, vy, one_mc, one_has_l);
+ if (vm < 0)
+ vm = ti_calendar_month_code_to_month(cal, vy, one_mc, 0);
+ int vd = one_day;
+ int c = compare_calendar_dates(cal, vy, vm, vd, two_year, two_month, two_day);
+ if (sign == 1 && c > 0)
+ years -= 1;
+ else if (sign == -1 && c < 0)
+ years += 1;
+ }
+ } else {
+ if (sign == 1 && (two_month < one_month || (two_month == one_month && two_day < one_day)))
+ years -= 1;
+ else if (sign == -1 && (two_month > one_month || (two_month == one_month && two_day > one_day)))
+ years += 1;
+ }
+ cy = one_year + (int)years;
+ if (use_mc) {
+ cm = ti_calendar_month_code_to_month(cal, cy, one_mc, one_has_l);
+ if (cm < 0)
+ cm = ti_calendar_month_code_to_month(cal, cy, one_mc, 0);
+ } else {
+ cm = one_month;
+ }
+ cd = one_day;
+ }
+
+ if (largestUnit == TI_UNIT_YEAR || largestUnit == TI_UNIT_MONTH) {
+ int64_t m = 0;
+ int base_year = cy, base_month = cm, base_day = cd;
+ while (1) {
+ int candidate_year = base_year;
+ int candidate_month = base_month + (int)((m + 1) * sign);
+ int candidate_day = base_day;
+ ti_balance_month(&candidate_year, &candidate_month, cal);
+
+ int c, mc = 0, has_l = 0;
+ if (use_mc) {
+ ti_calendar_month_to_month_code(cal, candidate_year, candidate_month, &mc, &has_l);
+ if (candidate_year != two_year)
+ c = (candidate_year < two_year) ? -1 : 1;
+ else if (mc != two_mc)
+ c = (mc < two_mc) ? -1 : 1;
+ else if (has_l != two_has_l)
+ c = has_l ? 1 : -1;
+ else if (candidate_day != two_day)
+ c = (candidate_day < two_day) ? -1 : 1;
+ else
+ c = 0;
+ } else {
+ c = compare_calendar_dates(cal, candidate_year, candidate_month, candidate_day,
+ two_year, two_month, two_day);
+ }
+ if (sign > 0 && c > 0) break;
+ if (sign < 0 && c < 0) break;
+ m++;
+ }
+ months = m * sign;
+
+ cy = base_year;
+ cm = base_month + (int)months;
+ cd = base_day;
+ ti_balance_month(&cy, &cm, cal);
+ }
+
+ days = calendar_days_between(cal, cy, cm, cd, two_year, two_month, two_day);
+
+ if (largestUnit == TI_UNIT_WEEK) {
+ weeks = days / 7;
+ days = days % 7;
+ }
+
+ if (out_years) *out_years = years;
+ if (out_months) *out_months = months;
+ if (out_weeks) *out_weeks = weeks;
+ if (out_days) *out_days = days;
+}
+
+int ti_calendar_month_code_to_month(CalendarType cal, int year, int month_code, int has_l)
+{
+ if (cal == CAL_HEBREW) {
+ if (ti_calendar_is_leap_year(cal, year)) {
+ if (month_code == 5 && has_l)
+ return 6;
+ if (month_code <= 5)
+ return month_code;
+ return month_code + 1;
+ }
+ if (month_code == 5 && has_l)
+ return 6;
+ return month_code;
+ }
+ if (cal == CAL_CHINESE) {
+ const ChineseCalendarEntry *e = lookup_chinese_year(year);
+ if (!e || cce_leap_month(e) == 0) {
+ if (has_l) return -1;
+ return month_code;
+ }
+ int leapPos = cce_leap_month(e);
+ if (month_code == leapPos && has_l)
+ return leapPos + 1;
+ if (month_code < leapPos) {
+ if (has_l) return -1;
+ return month_code;
+ }
+ if (month_code == leapPos && !has_l)
+ return month_code;
+ if (has_l) return -1;
+ return month_code + 1;
+ }
+ if (cal == CAL_DANGI) {
+ const ChineseCalendarEntry *e = lookup_dangi_year(year);
+ if (!e || cce_leap_month(e) == 0) {
+ if (has_l) return -1;
+ return month_code;
+ }
+ int leapPos = cce_leap_month(e);
+ if (month_code == leapPos && has_l)
+ return leapPos + 1;
+ if (month_code < leapPos) {
+ if (has_l) return -1;
+ return month_code;
+ }
+ if (month_code == leapPos && !has_l)
+ return month_code;
+ if (has_l) return -1;
+ return month_code + 1;
+ }
+ return month_code;
+}
+
+static void month_to_month_code_with_leap(int month, int leapPos, int *out_month_code, int *out_has_l)
+{
+ if (month <= leapPos) {
+ *out_month_code = month;
+ } else if (month == leapPos + 1) {
+ *out_month_code = leapPos;
+ *out_has_l = 1;
+ } else {
+ *out_month_code = month - 1;
+ }
+}
+
+void ti_calendar_month_to_month_code(CalendarType cal, int year, int month,
+ int *out_month_code, int *out_has_l)
+{
+ *out_has_l = 0;
+ switch (cal) {
+ case CAL_HEBREW:
+ if (ti_calendar_is_leap_year(cal, year))
+ month_to_month_code_with_leap(month, 5, out_month_code, out_has_l);
+ else
+ *out_month_code = month;
+ break;
+ case CAL_CHINESE: {
+ const ChineseCalendarEntry *e = lookup_chinese_year(year);
+ if (!e || cce_leap_month(e) == 0)
+ *out_month_code = month;
+ else
+ month_to_month_code_with_leap(month, cce_leap_month(e), out_month_code, out_has_l);
+ break;
+ }
+ case CAL_DANGI: {
+ const ChineseCalendarEntry *e = lookup_dangi_year(year);
+ if (!e || cce_leap_month(e) == 0)
+ *out_month_code = month;
+ else
+ month_to_month_code_with_leap(month, cce_leap_month(e), out_month_code, out_has_l);
+ break;
+ }
+ default:
+ *out_month_code = month;
+ break;
+ }
+}
+static TIEra ti_calendar_era(CalendarType cal, int iso_year)
+{
+ if (cal == CAL_GREGORY)
+ return iso_year >= 1 ? TI_ERA_CE : TI_ERA_BCE;
+ if (cal == CAL_BUDDHIST)
+ return TI_ERA_BE;
+ if (cal == CAL_COPTIC)
+ return TI_ERA_AM;
+ if (cal == CAL_ETHIOAA)
+ return TI_ERA_AA;
+ if (cal == CAL_ETHIOPIC)
+ return iso_year >= 1 ? TI_ERA_AM : TI_ERA_AA;
+ if (cal == CAL_HEBREW)
+ return TI_ERA_AM;
+ if (cal == CAL_INDIAN)
+ return TI_ERA_SHAKA;
+ if (cal == CAL_ISLAMIC_CIVIL || cal == CAL_ISLAMIC_TBLA || cal == CAL_ISLAMIC_UMALQURA)
+ return iso_year >= 1 ? TI_ERA_AH : TI_ERA_BH;
+ if (cal == CAL_PERSIAN)
+ return TI_ERA_AP;
+ if (cal == CAL_ROC)
+ return iso_year >= 1912 ? TI_ERA_ROC : TI_ERA_BROC;
+ if (cal == CAL_JAPANESE) {
+ if (iso_year <= 0)
+ return TI_ERA_BCE;
+ if (iso_year < 1868)
+ return TI_ERA_CE;
+ if (iso_year < 1912)
+ return TI_ERA_MEIJI;
+ if (iso_year < 1926)
+ return TI_ERA_TAISHO;
+ if (iso_year < 1989)
+ return TI_ERA_SHOWA;
+ if (iso_year < 2019)
+ return TI_ERA_HEISEI;
+ return TI_ERA_REIWA;
+ }
+ return TI_ERA_UNKNOWN;
+}
+
+int ti_calendar_requires_era(CalendarType cal)
+{
+ return ti_calendar_era(cal, 0) != TI_ERA_UNKNOWN;
+}
+static int ti_calendar_era_year(CalendarType cal, int iso_year)
+{
+ if (cal == CAL_GREGORY)
+ return iso_year >= 1 ? iso_year : 1 - iso_year;
+ if (cal == CAL_ETHIOPIC)
+ return iso_year >= 1 ? iso_year : iso_year + 5500;
+ if (cal == CAL_ISLAMIC_CIVIL || cal == CAL_ISLAMIC_TBLA || cal == CAL_ISLAMIC_UMALQURA)
+ return iso_year >= 1 ? iso_year : 1 - iso_year;
+ if (cal == CAL_ROC) {
+ int cal_year = iso_year - 1911;
+ return cal_year >= 1 ? cal_year : 1 - cal_year;
+ }
+ if (cal == CAL_BUDDHIST)
+ return iso_year + 543;
+ if (cal == CAL_JAPANESE) {
+ if (iso_year <= 0)
+ return 1 - iso_year;
+ if (iso_year < 1868)
+ return iso_year;
+ if (iso_year < 1912)
+ return iso_year - 1867;
+ if (iso_year < 1926)
+ return iso_year - 1911;
+ if (iso_year < 1989)
+ return iso_year - 1925;
+ if (iso_year < 2019)
+ return iso_year - 1988;
+ return iso_year - 2018;
+ }
+ /* For single-era calendars, eraYear equals ISO year */
+ if (cal == CAL_BUDDHIST || cal == CAL_COPTIC || cal == CAL_ETHIOAA ||
+ cal == CAL_HEBREW || cal == CAL_INDIAN ||
+ cal == CAL_PERSIAN)
+ return iso_year;
+ return iso_year;
+}
+static const char *ti_japanese_era_from_date(int year, int month, int day)
+{
+ if (year <= 0)
+ return "bce";
+ if (year < 1873)
+ return "ce";
+ if (year < 1912)
+ return "meiji";
+ if (year == 1912 && (month < 7 || (month == 7 && day < 30)))
+ return "meiji";
+ if (year < 1926)
+ return "taisho";
+ if (year == 1926 && (month < 12 || (month == 12 && day < 25)))
+ return "taisho";
+ if (year < 1989)
+ return "showa";
+ if (year == 1989 && (month < 1 || (month == 1 && day < 8)))
+ return "showa";
+ if (year < 2019)
+ return "heisei";
+ if (year == 2019 && (month < 5 || (month == 5 && day < 1)))
+ return "heisei";
+ return "reiwa";
+}
+static int ti_japanese_era_year_from_date(int year, int month, int day)
+{
+ const char *era = ti_japanese_era_from_date(year, month, day);
+ if (!strcmp(era, "bce")) return 1 - year;
+ if (!strcmp(era, "meiji")) return year - 1867;
+ if (!strcmp(era, "taisho")) return year - 1911;
+ if (!strcmp(era, "showa")) return year - 1925;
+ if (!strcmp(era, "heisei")) return year - 1988;
+ if (!strcmp(era, "reiwa")) return year - 2018;
+ return year;
+}
+void ti_calendar_era_and_era_year(CalendarType cal, int iso_year, int iso_month, int iso_day,
+ int cal_year, TIEra *era, int *era_year)
+{
+ if (cal == CAL_JAPANESE) {
+ *era = ti_string_to_era(ti_japanese_era_from_date(iso_year, iso_month, iso_day));
+ *era_year = ti_japanese_era_year_from_date(iso_year, iso_month, iso_day);
+ } else if (cal == CAL_ETHIOPIC) {
+ if (cal_year >= 1) {
+ *era = TI_ERA_AM;
+ *era_year = cal_year;
+ } else {
+ *era = TI_ERA_AA;
+ *era_year = cal_year + 5500;
+ }
+ } else if (cal == CAL_ISLAMIC_CIVIL || cal == CAL_ISLAMIC_TBLA || cal == CAL_ISLAMIC_UMALQURA) {
+ *era = cal_year >= 1 ? TI_ERA_AH : TI_ERA_BH;
+ *era_year = cal_year >= 1 ? cal_year : 1 - cal_year;
+ } else {
+ *era = ti_calendar_era(cal, iso_year);
+ if (*era != TI_ERA_UNKNOWN) {
+ if (cal == CAL_GREGORY || cal == CAL_ROC)
+ *era_year = ti_calendar_era_year(cal, iso_year);
+ else
+ *era_year = cal_year;
+ } else {
+ *era_year = cal_year;
+ }
+ }
+}
+/* Find the ISO reference date for a PlainMonthDay with the given monthCode and day.
+ Returns 0 on success, -1 on failure (with exception already thrown if applicable).
+ On success, sets *iso_y, *iso_m, *iso_d.
+ overflow_year: user-provided year for overflow validation (0 if not provided). */
+int ti_calendar_monthday_iso_reference_date(CalendarType cal, int month, int has_l, int day,
+ int overflow_constrain, int overflow_year,
+ int *iso_y, int *iso_m, int *iso_d)
+{
+ int ref_iso_year = 1972;
+ int max_day = -1;
+ int dim;
+
+ /* ISO/Gregorian-based calendars (including Buddhist, ROC, Japanese) always
+ use referenceISOYear = 1972. Overflow uses overflow_year if provided,
+ otherwise 1972. */
+ if (cal == CAL_ISO8601 || cal == CAL_GREGORY || cal == CAL_JAPANESE ||
+ cal == CAL_BUDDHIST || cal == CAL_ROC) {
+ int y = overflow_year ? overflow_year : 1972;
+ if (month > 12) {
+ if (!overflow_constrain)
+ return -1;
+ month = 12;
+ }
+ dim = pd_days_in_month(y, month);
+ if (day > dim) {
+ if (!overflow_constrain)
+ return -1;
+ day = dim;
+ } else if (day < 1) {
+ return -1;
+ }
+ *iso_y = 1972;
+ *iso_m = month;
+ *iso_d = day;
+ return 0;
+ }
+
+ /* For non-ISO calendars, if overflow_year is provided, validate against that year */
+ if (overflow_year != 0) {
+ int resolved_month = ti_calendar_month_code_to_month(cal, overflow_year, month, has_l);
+ if (resolved_month < 0) {
+ /* monthCode doesn't exist in the specified year */
+ if (!overflow_constrain)
+ return -1;
+ if (has_l) {
+ /* Fall back to non-leap month */
+ has_l = 0;
+ resolved_month = ti_calendar_month_code_to_month(cal, overflow_year, month, 0);
+ }
+ if (resolved_month < 0) {
+ /* Still doesn't exist, constrain to month 1 */
+ month = 1;
+ has_l = 0;
+ resolved_month = ti_calendar_month_code_to_month(cal, overflow_year, 1, 0);
+ if (resolved_month < 0) resolved_month = 1;
+ }
+ }
+ dim = ti_calendar_days_in_month(cal, overflow_year, resolved_month);
+ if (day > dim) {
+ if (!overflow_constrain)
+ return -1;
+ day = dim;
+ } else if (day < 1) {
+ return -1;
+ }
+ /* After overflow, proceed with monthCode-based reference year search */
+ } else {
+ /* No overflow_year: use maxLengthOfAdjustedMonthCodeInAnyYear logic */
+ if (cal == CAL_CHINESE || cal == CAL_DANGI) {
+ if (has_l) {
+ /* Search for leap month reference year per spec Table 6:
+ 1. Latest year in [1900, 1972] with enough days
+ 2. Earliest year >= 1973 with enough days
+ 3. Latest year < 1900 with enough days */
+ int search_year;
+ int leap_found = 0;
+ int leap_year = -1;
+ int leap_max_dim = 0;
+ int leap_max_dim_year = 1972;
+
+ /* M01L and M12L are not known to have occurred in the calculable range */
+ if (month == 1 || month == 12) {
+ if (!overflow_constrain)
+ return -1;
+ has_l = 0;
+ } else if (day >= 30 && (month == 2 || month == 8 || month == 9 || month == 10 || month == 11)) {
+ /* M02L, M08L-M11L are not known to commonly have 30 days */
+ if (!overflow_constrain)
+ return -1;
+ has_l = 0;
+ } else {
+ for (search_year = 1972; search_year >= 1900; search_year--) {
+ const ChineseCalendarEntry *e = (cal == CAL_CHINESE) ?
+ lookup_chinese_year(search_year) : lookup_dangi_year(search_year);
+ if (e && cce_leap_month(e) == month) {
+ int ordinal_month = month + 1;
+ int month_days = ti_calendar_days_in_month(cal, search_year, ordinal_month);
+ if (month_days >= day) {
+ leap_found = 1;
+ leap_year = search_year;
+ break;
+ }
+ if (month_days > leap_max_dim) {
+ leap_max_dim = month_days;
+ leap_max_dim_year = search_year;
+ }
+ }
+ }
+ if (!leap_found) {
+ for (search_year = 1973; ; search_year++) {
+ const ChineseCalendarEntry *e = (cal == CAL_CHINESE) ?
+ lookup_chinese_year(search_year) : lookup_dangi_year(search_year);
+ if (!e)
+ break;
+ if (cce_leap_month(e) == month) {
+ int ordinal_month = month + 1;
+ int month_days = ti_calendar_days_in_month(cal, search_year, ordinal_month);
+ if (month_days >= day) {
+ leap_found = 1;
+ leap_year = search_year;
+ break;
+ }
+ if (month_days > leap_max_dim) {
+ leap_max_dim = month_days;
+ leap_max_dim_year = search_year;
+ }
+ }
+ }
+ }
+ if (!leap_found) {
+ for (search_year = 1899; search_year >= 1800; search_year--) {
+ const ChineseCalendarEntry *e = (cal == CAL_CHINESE) ?
+ lookup_chinese_year(search_year) : lookup_dangi_year(search_year);
+ if (e && cce_leap_month(e) == month) {
+ int ordinal_month = month + 1;
+ int month_days = ti_calendar_days_in_month(cal, search_year, ordinal_month);
+ if (month_days >= day) {
+ leap_found = 1;
+ leap_year = search_year;
+ break;
+ }
+ if (month_days > leap_max_dim) {
+ leap_max_dim = month_days;
+ leap_max_dim_year = search_year;
+ }
+ }
+ }
+ }
+ if (leap_found) {
+ int ordinal_month = month + 1;
+ if (ti_calendar_date_to_iso(cal, leap_year, ordinal_month, day, iso_y, iso_m, iso_d) < 0)
+ return -1;
+ return 0;
+ } else if (leap_max_dim >= 30 && overflow_constrain) {
+ int ordinal_month = month + 1;
+ if (ti_calendar_date_to_iso(cal, leap_max_dim_year, ordinal_month, leap_max_dim, iso_y, iso_m, iso_d) < 0)
+ return -1;
+ return 0;
+ } else if (leap_max_dim > 0 && overflow_constrain) {
+ has_l = 0;
+ } else {
+ if (!overflow_constrain)
+ return -1;
+ has_l = 0;
+ }
+ }
+ }
+ max_day = 30;
+ } else if (cal == CAL_HEBREW) {
+ if (has_l) {
+ max_day = (month == 5) ? 30 : -1;
+ } else {
+ switch (month) {
+ case 1: case 2: case 3: case 5: case 7: case 9: case 11: max_day = 30; break;
+ case 4: case 6: case 8: case 10: case 12: max_day = 29; break;
+ default: max_day = -1; break;
+ }
+ }
+ } else if (cal == CAL_ISLAMIC_CIVIL || cal == CAL_ISLAMIC_TBLA) {
+ if (has_l) {
+ max_day = -1;
+ } else {
+ max_day = (month == 12) ? 30 : ((month % 2 == 1) ? 30 : 29);
+ }
+ } else if (cal == CAL_ISLAMIC_UMALQURA) {
+ if (has_l) max_day = -1;
+ else max_day = 30;
+ } else if (cal == CAL_PERSIAN) {
+ if (has_l) max_day = -1;
+ else max_day = (month <= 6) ? 31 : 30;
+ } else if (cal == CAL_INDIAN) {
+ if (has_l) max_day = -1;
+ else max_day = (month >= 1 && month <= 6) ? 31 : 30;
+ } else if (cal == CAL_COPTIC || cal == CAL_ETHIOPIC || cal == CAL_ETHIOAA) {
+ if (has_l) max_day = -1;
+ else max_day = (month == 13) ? 6 : 30;
+ }
+ if (max_day < 0) {
+ if (!overflow_constrain)
+ return -1;
+ month = 1;
+ has_l = 0;
+ max_day = 30;
+ }
+ if (day > max_day) {
+ if (!overflow_constrain)
+ return -1;
+ day = max_day;
+ }
+ if (day < 1)
+ return -1;
+ }
+
+ /* Determine reference ISO year based on calendar */
+ if (cal == CAL_HEBREW) {
+ if (month == 5 && has_l)
+ ref_iso_year = 1970;
+ else if ((month == 2 || month == 3) && day == 30)
+ ref_iso_year = 1971;
+ } else if ((cal == CAL_ISLAMIC_CIVIL || cal == CAL_ISLAMIC_TBLA) && month == 12 && day == 30) {
+ ref_iso_year = 1971;
+ }
+
+ {
+ int cal_y, cal_m, cal_d;
+ int cal_mc, cal_has_l;
+ int calendar_year;
+ int test_y, test_m, test_d;
+ int rt_y, rt_m, rt_d;
+ int rt_mc, rt_has_l;
+
+ /* Convert ISO (ref_iso_year, 12, 31) to calendar */
+ ti_iso_to_calendar_date(cal, ref_iso_year, 12, 31, &cal_y, &cal_m, &cal_d);
+ ti_calendar_month_to_month_code(cal, cal_y, cal_m, &cal_mc, &cal_has_l);
+
+ /* Determine calendarYear based on monthCode comparison */
+ if (cal_mc > month || (cal_mc == month && cal_has_l > has_l) ||
+ (cal_mc == month && cal_has_l == has_l && cal_d >= day)) {
+ calendar_year = cal_y;
+ } else {
+ calendar_year = cal_y - 1;
+ }
+
+ /* Search backwards from calendar_year until a valid reference year is found */
+ {
+ int ty;
+ for (ty = calendar_year; ty >= calendar_year - 5000 && ty >= 1; ty--) {
+ int tm = ti_calendar_month_code_to_month(cal, ty, month, has_l);
+ if (tm < 0)
+ continue;
+ if (ti_calendar_date_to_iso(cal, ty, tm, day, &test_y, &test_m, &test_d) < 0)
+ continue;
+ ti_iso_to_calendar_date(cal, test_y, test_m, test_d, &rt_y, &rt_m, &rt_d);
+ ti_calendar_month_to_month_code(cal, rt_y, rt_m, &rt_mc, &rt_has_l);
+ if (rt_mc == month && rt_has_l == has_l && rt_d == day) {
+ *iso_y = test_y;
+ *iso_m = test_m;
+ *iso_d = test_d;
+ return 0;
+ }
+ }
+ }
+ }
+
+ return -1;
+}
+
+static const char *era_strings[] = {
+ NULL, "ce", "bce", "be", "am", "aa", "shaka", "ap", "ah", "bh",
+ "roc", "broc", "meiji", "taisho", "showa", "heisei", "reiwa"
+};
+
+TIEra ti_string_to_era(const char *era)
+{
+ int i;
+ for (i = TI_ERA_CE; i <= TI_ERA_REIWA; i++) {
+ if (!strcmp(era, era_strings[i]))
+ return i;
+ }
+ if (!strcmp(era, "ad"))
+ return TI_ERA_CE;
+ if (!strcmp(era, "bc"))
+ return TI_ERA_BCE;
+ return TI_ERA_UNKNOWN;
+}
+
+const char *ti_era_to_string(TIEra era)
+{
+ if (era >= TI_ERA_CE && era <= TI_ERA_REIWA)
+ return era_strings[era];
+ return NULL;
+}
+int ti_calendar_validate_month_code(CalendarType cal, int month_from_code, int has_l)
+{
+ int max_numeric;
+ switch (cal) {
+ case CAL_COPTIC:
+ case CAL_ETHIOAA:
+ case CAL_ETHIOPIC:
+ max_numeric = 13;
+ break;
+ default:
+ max_numeric = 12;
+ break;
+ }
+ if (month_from_code < 1 || month_from_code > max_numeric)
+ return 0;
+ if (!has_l)
+ return 1;
+ /* Leap month codes: only certain calendars support them */
+ if (cal == CAL_CHINESE || cal == CAL_DANGI) {
+ /* Chinese/Dangi support M01L-M12L */
+ return month_from_code >= 1 && month_from_code <= 12;
+ }
+ if (cal == CAL_HEBREW) {
+ /* Hebrew only supports M05L (Adar I in leap years) */
+ return month_from_code == 5;
+ }
+ /* No other calendars support leap month codes */
+ return 0;
+}
+int ti_calendar_era_to_iso_year(CalendarType cal, TIEra era, int eraYear, int *iso_year)
+{
+ if (cal == CAL_GREGORY) {
+ if (era == TI_ERA_CE) {
+ *iso_year = eraYear;
+ return 0;
+ } else if (era == TI_ERA_BCE) {
+ *iso_year = 1 - eraYear;
+ return 0;
+ }
+ return -1;
+ }
+ if (cal == CAL_JAPANESE) {
+ if (era == TI_ERA_CE) {
+ *iso_year = eraYear;
+ return 0;
+ } else if (era == TI_ERA_BCE) {
+ *iso_year = 1 - eraYear;
+ return 0;
+ } else if (era == TI_ERA_MEIJI) {
+ *iso_year = 1867 + eraYear;
+ return 0;
+ } else if (era == TI_ERA_TAISHO) {
+ *iso_year = 1911 + eraYear;
+ return 0;
+ } else if (era == TI_ERA_SHOWA) {
+ *iso_year = 1925 + eraYear;
+ return 0;
+ } else if (era == TI_ERA_HEISEI) {
+ *iso_year = 1988 + eraYear;
+ return 0;
+ } else if (era == TI_ERA_REIWA) {
+ *iso_year = 2018 + eraYear;
+ return 0;
+ }
+ return -1;
+ }
+ if (cal == CAL_ISLAMIC_CIVIL || cal == CAL_ISLAMIC_TBLA || cal == CAL_ISLAMIC_UMALQURA) {
+ if (era == TI_ERA_AH) {
+ *iso_year = eraYear;
+ return 0;
+ } else if (era == TI_ERA_BH) {
+ *iso_year = 1 - eraYear;
+ return 0;
+ }
+ return -1;
+ }
+ if (cal == CAL_ROC) {
+ if (era == TI_ERA_ROC) {
+ *iso_year = eraYear + 1911;
+ return 0;
+ } else if (era == TI_ERA_BROC) {
+ *iso_year = 1912 - eraYear;
+ return 0;
+ }
+ return -1;
+ }
+ if (cal == CAL_ETHIOPIC) {
+ if (era == TI_ERA_AM) {
+ *iso_year = eraYear;
+ return 0;
+ } else if (era == TI_ERA_AA) {
+ *iso_year = eraYear - 5500;
+ return 0;
+ }
+ return -1;
+ }
+ /* Single-era calendars */
+ if (cal == CAL_BUDDHIST && era == TI_ERA_BE) {
+ *iso_year = eraYear - 543;
+ return 0;
+ } else if (cal == CAL_COPTIC && era == TI_ERA_AM) {
+ *iso_year = eraYear;
+ return 0;
+ } else if (cal == CAL_ETHIOAA && era == TI_ERA_AA) {
+ *iso_year = eraYear;
+ return 0;
+ } else if (cal == CAL_HEBREW && era == TI_ERA_AM) {
+ *iso_year = eraYear;
+ return 0;
+ } else if (cal == CAL_INDIAN && era == TI_ERA_SHAKA) {
+ *iso_year = eraYear;
+ return 0;
+ } else if (cal == CAL_PERSIAN && era == TI_ERA_AP) {
+ *iso_year = eraYear;
+ return 0;
+ }
+ return -1;
+}
+int ti_calendar_era_to_calendar_year(CalendarType cal, TIEra era, int eraYear, int *cal_year)
+{
+ if (cal == CAL_GREGORY) {
+ if (era == TI_ERA_CE) { *cal_year = eraYear; return 0; }
+ if (era == TI_ERA_BCE) { *cal_year = 1 - eraYear; return 0; }
+ return -1;
+ }
+ if (cal == CAL_JAPANESE) {
+ if (era == TI_ERA_CE) { *cal_year = eraYear; return 0; }
+ if (era == TI_ERA_BCE) { *cal_year = 1 - eraYear; return 0; }
+ if (era == TI_ERA_MEIJI) { *cal_year = 1867 + eraYear; return 0; }
+ if (era == TI_ERA_TAISHO) { *cal_year = 1911 + eraYear; return 0; }
+ if (era == TI_ERA_SHOWA) { *cal_year = 1925 + eraYear; return 0; }
+ if (era == TI_ERA_HEISEI) { *cal_year = 1988 + eraYear; return 0; }
+ if (era == TI_ERA_REIWA) { *cal_year = 2018 + eraYear; return 0; }
+ return -1;
+ }
+ if (cal == CAL_ISLAMIC_CIVIL || cal == CAL_ISLAMIC_TBLA || cal == CAL_ISLAMIC_UMALQURA) {
+ if (era == TI_ERA_AH) { *cal_year = eraYear; return 0; }
+ if (era == TI_ERA_BH) { *cal_year = 1 - eraYear; return 0; }
+ return -1;
+ }
+ if (cal == CAL_ROC) {
+ if (era == TI_ERA_ROC) { *cal_year = eraYear; return 0; }
+ if (era == TI_ERA_BROC) { *cal_year = 1 - eraYear; return 0; }
+ return -1;
+ }
+ if (cal == CAL_ETHIOPIC) {
+ if (era == TI_ERA_AM) { *cal_year = eraYear; return 0; }
+ if (era == TI_ERA_AA) { *cal_year = eraYear - 5500; return 0; }
+ return -1;
+ }
+ /* Single-era calendars: eraYear is the calendar year */
+ if ((cal == CAL_BUDDHIST && era == TI_ERA_BE) ||
+ (cal == CAL_COPTIC && era == TI_ERA_AM) ||
+ (cal == CAL_ETHIOAA && era == TI_ERA_AA) ||
+ (cal == CAL_HEBREW && era == TI_ERA_AM) ||
+ (cal == CAL_INDIAN && era == TI_ERA_SHAKA) ||
+ (cal == CAL_PERSIAN && era == TI_ERA_AP)) {
+ *cal_year = eraYear;
+ return 0;
+ }
+ return -1;
+}
+void pdt_balance_month_calendar(int *year, int *month, CalendarType cal)
+{
+ int max_month;
+ while (1) {
+ max_month = ti_calendar_months_in_year(cal, *year);
+ if (*month <= max_month && *month >= 1)
+ break;
+ if (*month > max_month) {
+ *month -= max_month;
+ (*year)++;
+ } else {
+ (*year)--;
+ max_month = ti_calendar_months_in_year(cal, *year);
+ *month += max_month;
+ }
+ }
+}
+void pdt_balance_date_calendar(int *year, int *month, int *day, CalendarType cal)
+{
+ int dim;
+ pdt_balance_month_calendar(year, month, cal);
+ while (*day > (dim = ti_calendar_days_in_month(cal, *year, *month))) {
+ *day -= dim;
+ (*month)++;
+ if (*month > ti_calendar_months_in_year(cal, *year)) {
+ *month = 1;
+ (*year)++;
+ }
+ }
+ while (*day < 1) {
+ (*month)--;
+ if (*month < 1) {
+ (*year)--;
+ *month = ti_calendar_months_in_year(cal, *year);
+ }
+ dim = ti_calendar_days_in_month(cal, *year, *month);
+ *day += dim;
+ }
+}
--- /dev/null
+/*
+ * QuickJS Temporal calendar implementation - private header
+ */
+
+#ifndef TEMPORAL_CALENDAR_H
+#define TEMPORAL_CALENDAR_H
+
+#include "../cutils.h"
+
+#define TI_TIMEZONE_BUF_SIZE 128
+
+/* Calendar type enum */
+typedef enum {
+ CAL_UNKNOWN = -1,
+ CAL_BUDDHIST = 0,
+ CAL_CHINESE,
+ CAL_COPTIC,
+ CAL_DANGI,
+ CAL_ETHIOAA,
+ CAL_ETHIOPIC,
+ CAL_GREGORY,
+ CAL_HEBREW,
+ CAL_INDIAN,
+ CAL_ISLAMIC_CIVIL,
+ CAL_ISLAMIC_TBLA,
+ CAL_ISLAMIC_UMALQURA,
+ CAL_ISO8601,
+ CAL_JAPANESE,
+ CAL_PERSIAN,
+ CAL_ROC,
+ CAL_COUNT,
+} CalendarType;
+
+/* Era enum */
+typedef enum {
+ TI_ERA_UNKNOWN = 0,
+ TI_ERA_CE,
+ TI_ERA_BCE,
+ TI_ERA_BE,
+ TI_ERA_AM,
+ TI_ERA_AA,
+ TI_ERA_SHAKA,
+ TI_ERA_AP,
+ TI_ERA_AH,
+ TI_ERA_BH,
+ TI_ERA_ROC,
+ TI_ERA_BROC,
+ TI_ERA_MEIJI,
+ TI_ERA_TAISHO,
+ TI_ERA_SHOWA,
+ TI_ERA_HEISEI,
+ TI_ERA_REIWA,
+} TIEra;
+
+/* Calendar names array (order matches CalendarType enum) */
+extern const char *ti_calendar_names[];
+
+/* Calendar string <-> enum conversions */
+CalendarType ti_calendar_string_to_enum(const char *str);
+const char *ti_calendar_enum_to_string(CalendarType cal);
+
+/* ISO month days table */
+extern const int ti_iso_month_days[];
+
+/* Related Gregorian year for Chinese/Dangi dates */
+int ti_chinese_related_year(CalendarType cal, int iso_year, int iso_month, int iso_day);
+
+/* Calendar date conversion */
+int ti_calendar_date_to_iso(CalendarType cal, int cal_year, int cal_month, int cal_day,
+ int *iso_year, int *iso_month, int *iso_day);
+int ti_iso_to_calendar_date(CalendarType cal, int iso_year, int iso_month, int iso_day,
+ int *cal_year, int *cal_month, int *cal_day);
+
+/* Era functions */
+int ti_calendar_requires_era(CalendarType cal);
+void ti_calendar_era_and_era_year(CalendarType cal, int iso_year, int iso_month, int iso_day,
+ int cal_year, TIEra *era, int *era_year);
+TIEra ti_string_to_era(const char *era);
+const char *ti_era_to_string(TIEra era);
+int ti_calendar_validate_month_code(CalendarType cal, int month_from_code, int has_l);
+int ti_calendar_era_to_iso_year(CalendarType cal, TIEra era, int eraYear, int *iso_year);
+int ti_calendar_era_to_calendar_year(CalendarType cal, TIEra era, int eraYear, int *cal_year);
+int ti_calendar_monthday_iso_reference_date(CalendarType cal, int month, int has_l, int day,
+ int overflow_constrain, int overflow_year,
+ int *iso_year, int *iso_month, int *iso_day);
+
+/* Calendar property functions */
+int ti_calendar_is_leap_year(CalendarType cal, int year);
+int ti_calendar_days_in_year(CalendarType cal, int year);
+int ti_calendar_months_in_year(CalendarType cal, int year);
+int ti_calendar_days_in_month(CalendarType cal, int year, int month);
+int ti_calendar_day_of_year(CalendarType cal, int year, int month, int day);
+int ti_calendar_month_code_to_month(CalendarType cal, int year, int month_code, int has_l);
+void ti_calendar_month_to_month_code(CalendarType cal, int year, int month,
+ int *out_month_code, int *out_has_l);
+
+/* Calendar date arithmetic */
+void ti_calendar_date_until(CalendarType cal, int one_year, int one_month, int one_day,
+ int two_year, int two_month, int two_day,
+ int largestUnit,
+ int64_t *out_years, int64_t *out_months,
+ int64_t *out_weeks, int64_t *out_days);
+void ti_calendar_date_until_with_monthcode(CalendarType cal,
+ int one_year, int one_month, int one_day,
+ int one_mc, int one_has_mc, int one_has_l,
+ int two_year, int two_month, int two_day,
+ int two_mc, int two_has_mc, int two_has_l,
+ int largestUnit,
+ int64_t *out_years, int64_t *out_months,
+ int64_t *out_weeks, int64_t *out_days);
+/* Calendar balancing helpers */
+void pdt_balance_month_calendar(int *year, int *month, CalendarType cal);
+void pdt_balance_date_calendar(int *year, int *month, int *day, CalendarType cal);
+
+#endif /* TEMPORAL_CALENDAR_H */
--- /dev/null
+/*
+ * QuickJS Temporal.Duration implementation (minimal)
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <math.h>
+
+#include "../quickjs.h"
+#include "../cutils.h"
+#include "temporal_private.h"
+
+static JSClassID js_duration_class_id;
+
+static void js_duration_finalizer(JSRuntime *rt, JSValue val)
+{
+ JSDurationData *s = JS_GetOpaque(val, js_duration_class_id);
+ if (s) {
+ js_free_rt(rt, s);
+ }
+}
+
+static const JSClassDef js_duration_class = {
+ "Temporal.Duration",
+ .finalizer = js_duration_finalizer,
+};
+
+static void duration_round_fields_to_float64(JSDurationData *d)
+{
+ d->milliseconds = (int64_t)(double)d->milliseconds;
+ d->microseconds.int128_value = (js_int128_t)(double)d->microseconds.int128_value;
+ d->nanoseconds.int128_value = (js_int128_t)(double)d->nanoseconds.int128_value;
+}
+
+static TIUnit duration_get_largest_unit(const JSDurationData *d)
+{
+ if (d->years != 0) return TI_UNIT_YEAR;
+ if (d->months != 0) return TI_UNIT_MONTH;
+ if (d->weeks != 0) return TI_UNIT_WEEK;
+ if (d->days != 0) return TI_UNIT_DAY;
+ if (d->hours != 0) return TI_UNIT_HOUR;
+ if (d->minutes != 0) return TI_UNIT_MINUTE;
+ if (d->seconds != 0) return TI_UNIT_SECOND;
+ if (d->milliseconds != 0) return TI_UNIT_MILLISECOND;
+ if (d->microseconds.int128_value != 0) return TI_UNIT_MICROSECOND;
+ if (d->nanoseconds.int128_value != 0) return TI_UNIT_NANOSECOND;
+ return TI_UNIT_NANOSECOND;
+}
+
+static TIUnit ti_larger_of_two_units(TIUnit a, TIUnit b)
+{
+ return a < b ? a : b;
+}
+
+JSValue js_create_duration(JSContext *ctx, const JSDurationData *d)
+{
+ JSDurationData *s;
+ JSValue obj;
+ s = js_mallocz(ctx, sizeof(*s));
+ if (!s)
+ return JS_EXCEPTION;
+ *s = *d;
+ /* Round fields to float64-representable integers to match spec behavior */
+ duration_round_fields_to_float64(s);
+ obj = JS_NewObjectClass(ctx, (int)js_duration_class_id);
+ if (JS_IsException(obj)) {
+ js_free(ctx, s);
+ return JS_EXCEPTION;
+ }
+ JS_SetOpaque(obj, s);
+ return obj;
+}
+
+static int to_integer_if_integral(JSContext *ctx, JSValueConst val, int64_t *pres)
+{
+ double d;
+ if (JS_IsUndefined(val)) {
+ *pres = 0;
+ return 0;
+ }
+ if (JS_ToFloat64(ctx, &d, val))
+ return -1;
+ if (!isfinite(d) || floor(d) != d) {
+ JS_ThrowRangeError(ctx, "value must be an integer");
+ return -1;
+ }
+ if (d > (double)INT64_MAX || d < (double)INT64_MIN) {
+ JS_ThrowRangeError(ctx, "value out of range");
+ return -1;
+ }
+ *pres = (int64_t)d;
+ return 0;
+}
+
+static int to_integer_if_integral128(JSContext *ctx, JSValueConst val, js_int128_t *pres)
+{
+ double d;
+ if (JS_IsUndefined(val)) {
+ *pres = 0;
+ return 0;
+ }
+ if (JS_ToFloat64(ctx, &d, val))
+ return -1;
+ if (!isfinite(d) || floor(d) != d) {
+ JS_ThrowRangeError(ctx, "value must be an integer");
+ return -1;
+ }
+ *pres = (js_int128_t)d;
+ if (d != 0 && *pres == 0) {
+ JS_ThrowRangeError(ctx, "value out of range");
+ return -1;
+ }
+ return 0;
+}
+
+#define DURATION_MAX_SECONDS 9007199254740991LL
+
+int duration_has_mixed_signs(const JSDurationData *d)
+{
+ int sign = 0;
+ int64_t vals[] = { d->years, d->months, d->weeks, d->days, d->hours,
+ d->minutes, d->seconds, d->milliseconds };
+ int i;
+ for (i = 0; i < 8; i++) {
+ if (vals[i] != 0) {
+ if (sign == 0)
+ sign = vals[i] > 0 ? 1 : -1;
+ else if ((vals[i] > 0 ? 1 : -1) != sign)
+ return 1;
+ }
+ }
+ if (d->microseconds.int128_value != 0) {
+ if (sign == 0)
+ sign = d->microseconds.int128_value > 0 ? 1 : -1;
+ else if ((d->microseconds.int128_value > 0 ? 1 : -1) != sign)
+ return 1;
+ }
+ if (d->nanoseconds.int128_value != 0) {
+ if (sign == 0)
+ sign = d->nanoseconds.int128_value > 0 ? 1 : -1;
+ else if ((d->nanoseconds.int128_value > 0 ? 1 : -1) != sign)
+ return 1;
+ }
+ return 0;
+}
+
+int duration_is_out_of_range(const JSDurationData *d)
+{
+ const int64_t MAX_YEARS = 4294967295LL;
+ const int64_t MAX_MONTHS = 4294967295LL;
+ const int64_t MAX_WEEKS = 4294967295LL;
+ /* These limits prevent overflow in multiplication and are derived from
+ the total nanoseconds limit 10^9 * 2^53. */
+ const int64_t MAX_DAYS_ALONE = 104249991374LL;
+ const int64_t MAX_HOURS_ALONE = 2501999792983LL;
+ const int64_t MAX_MINUTES_ALONE = 150119987579016LL;
+ const int64_t MAX_SECONDS_ALONE = 9007199254740991LL;
+ int64_t abs_days, abs_hours, abs_minutes, abs_seconds;
+ int64_t abs_ms;
+ js_int128_t abs_us, abs_ns;
+ JSTimeSpec total = {0, 0};
+ JSTimeSpec ts;
+
+ if (d->years < -MAX_YEARS || d->years > MAX_YEARS)
+ return 1;
+ if (d->months < -MAX_MONTHS || d->months > MAX_MONTHS)
+ return 1;
+ if (d->weeks < -MAX_WEEKS || d->weeks > MAX_WEEKS)
+ return 1;
+
+ /* Quick reject for individual fields that are too large, preventing
+ overflow in the subsequent total computation. */
+ if (d->days < -MAX_DAYS_ALONE || d->days > MAX_DAYS_ALONE)
+ return 1;
+ if (d->hours < -MAX_HOURS_ALONE || d->hours > MAX_HOURS_ALONE)
+ return 1;
+ if (d->minutes < -MAX_MINUTES_ALONE || d->minutes > MAX_MINUTES_ALONE)
+ return 1;
+ if (d->seconds < -MAX_SECONDS_ALONE || d->seconds > MAX_SECONDS_ALONE)
+ return 1;
+
+ /* Since duration_has_mixed_signs() is already checked, all non-zero
+ fields have the same sign. Use absolute values for safe addition. */
+ abs_days = d->days < 0 ? -d->days : d->days;
+ abs_hours = d->hours < 0 ? -d->hours : d->hours;
+ abs_minutes = d->minutes < 0 ? -d->minutes : d->minutes;
+ abs_seconds = d->seconds < 0 ? -d->seconds : d->seconds;
+ abs_ms = d->milliseconds < 0 ? -d->milliseconds : d->milliseconds;
+ abs_us = d->microseconds.int128_value < 0 ? -d->microseconds.int128_value : d->microseconds.int128_value;
+ abs_ns = d->nanoseconds.int128_value < 0 ? -d->nanoseconds.int128_value : d->nanoseconds.int128_value;
+
+ /* Accumulate total nanoseconds as (seconds, nanoseconds) using
+ non-negative arithmetic to avoid signed overflow. */
+ ts.secs = abs_days * 86400LL;
+ ts.nsecs = 0;
+ total.secs += ts.secs;
+
+ ts.secs = abs_hours * 3600LL;
+ ts.nsecs = 0;
+ total.secs += ts.secs;
+
+ ts.secs = abs_minutes * 60LL;
+ ts.nsecs = 0;
+ total.secs += ts.secs;
+
+ ts.secs = abs_seconds;
+ ts.nsecs = 0;
+ total.secs += ts.secs;
+
+ {
+ uint64_t n = (uint64_t)total.nsecs + (uint64_t)(abs_ms % 1000) * 1000000;
+ total.secs += abs_ms / 1000 + (int64_t)(n / 1000000000);
+ total.nsecs = (uint32_t)(n % 1000000000);
+ }
+
+ {
+ uint64_t n = (uint64_t)total.nsecs + (uint64_t)(abs_us % 1000000) * 1000;
+ total.secs += (int64_t)(abs_us / 1000000) + (int64_t)(n / 1000000000);
+ total.nsecs = (uint32_t)(n % 1000000000);
+ }
+
+ {
+ uint64_t n = (uint64_t)total.nsecs + (uint64_t)(abs_ns % 1000000000);
+ total.secs += (int64_t)(abs_ns / 1000000000) + (int64_t)(n / 1000000000);
+ total.nsecs = (uint32_t)(n % 1000000000);
+ }
+
+ if (total.secs >= 9007199254740992LL)
+ return 1;
+ return 0;
+}
+
+static int64_t round_half_away_from_zero(double x)
+{
+ if (x >= 0)
+ return (int64_t)floor(x + 0.5);
+ else
+ return (int64_t)ceil(x - 0.5);
+}
+
+static void distribute_fractional_time(double hours, double minutes, double seconds,
+ double milliseconds, double microseconds, double nanoseconds,
+ JSDurationData *out)
+{
+ /* Distribute fractional parts downward only. Integer components in each
+ unit are preserved as-is per ParseTemporalDurationString. */
+ double frac;
+ out->hours = (int64_t)floor(hours);
+ frac = (hours - (double)out->hours) * 60;
+ minutes += frac;
+
+ out->minutes = (int64_t)floor(minutes);
+ frac = (minutes - (double)out->minutes) * 60;
+ seconds += frac;
+
+ out->seconds = (int64_t)floor(seconds);
+ frac = (seconds - (double)out->seconds) * 1000;
+ milliseconds += frac;
+
+ out->milliseconds = (int64_t)floor(milliseconds);
+ frac = (milliseconds - (double)out->milliseconds) * 1000;
+ microseconds += frac;
+
+ out->microseconds.int128_value = (int64_t)floor(microseconds);
+ frac = (microseconds - (double)out->microseconds.int128_value) * 1000;
+ nanoseconds += frac;
+
+ /* Final nanoseconds rounded with halfExpand */
+ out->nanoseconds.int128_value = round_half_away_from_zero(nanoseconds);
+ /* Normalize subseconds only (they all came from fractional seconds) */
+ if (out->nanoseconds.int128_value >= 1000) {
+ out->microseconds.int128_value += out->nanoseconds.int128_value / 1000;
+ out->nanoseconds.int128_value %= 1000;
+ } else if (out->nanoseconds.int128_value < 0) {
+ out->microseconds.int128_value += (out->nanoseconds.int128_value - 999) / 1000;
+ out->nanoseconds.int128_value = 1000 + (out->nanoseconds.int128_value % 1000);
+ if (out->nanoseconds.int128_value == 1000) {
+ out->nanoseconds.int128_value = 0;
+ out->microseconds.int128_value += 1;
+ }
+ }
+ if (out->microseconds.int128_value >= 1000) {
+ out->milliseconds += (int64_t)(out->microseconds.int128_value / 1000);
+ out->microseconds.int128_value %= 1000;
+ } else if (out->microseconds.int128_value < 0) {
+ out->milliseconds += (int64_t)((out->microseconds.int128_value - 999) / 1000);
+ out->microseconds.int128_value = 1000 + (out->microseconds.int128_value % 1000);
+ if (out->microseconds.int128_value == 1000) {
+ out->microseconds.int128_value = 0;
+ out->milliseconds += 1;
+ }
+ }
+ if (out->milliseconds >= 1000) {
+ out->seconds += out->milliseconds / 1000;
+ out->milliseconds %= 1000;
+ } else if (out->milliseconds < 0) {
+ out->seconds += (out->milliseconds - 999) / 1000;
+ out->milliseconds = 1000 + (out->milliseconds % 1000);
+ if (out->milliseconds == 1000) {
+ out->milliseconds = 0;
+ out->seconds += 1;
+ }
+ }
+}
+
+int js_parse_duration_string(JSContext *ctx, const char *str, JSDurationData *out)
+{
+ const char *p;
+ int negative = 0;
+ int has_t = 0;
+ double num = 0;
+ int in_time = 0;
+ int has_value = 0;
+ double hours = 0, minutes = 0, seconds = 0;
+ double milliseconds = 0, microseconds = 0, nanoseconds = 0;
+ int has_minutes = 0, has_seconds = 0;
+ int frac_hours = 0, frac_minutes = 0;
+ memset(out, 0, sizeof(*out));
+ p = str;
+ if (*p == '-') {
+ negative = 1;
+ p++;
+ } else if (*p == '+') {
+ p++;
+ }
+ if (*p != 'P' && *p != 'p') {
+ JS_ThrowRangeError(ctx, "invalid duration string");
+ return -1;
+ }
+ p++;
+ while (*p) {
+ char c;
+ char *end;
+ char num_buf[64];
+ int num_len;
+ if (*p == 'T' || *p == 't') {
+ if (has_t) {
+ JS_ThrowRangeError(ctx, "invalid duration string");
+ return -1;
+ }
+ has_t = 1;
+ in_time = 1;
+ p++;
+ continue;
+ }
+ if (*p < '0' || *p > '9') {
+ JS_ThrowRangeError(ctx, "invalid duration string");
+ return -1;
+ }
+ /* Copy number to buffer, replacing comma with dot for strtod */
+ num_len = 0;
+ while ((*p >= '0' && *p <= '9') || *p == '.' || *p == ',') {
+ if (num_len < (int)(sizeof(num_buf) - 1)) {
+ num_buf[num_len] = (*p == ',') ? '.' : *p;
+ num_len++;
+ }
+ p++;
+ }
+ if (num_len >= (int)(sizeof(num_buf) - 1)) {
+ JS_ThrowRangeError(ctx, "invalid duration string");
+ return -1;
+ }
+ /* Reject trailing decimal point (e.g. "2.") or leading decimal (".1") */
+ if (num_buf[0] == '.' || (num_len > 0 && num_buf[num_len - 1] == '.')) {
+ JS_ThrowRangeError(ctx, "invalid duration string");
+ return -1;
+ }
+ /* Reject multiple decimal points */
+ {
+ int dot_count = 0, i;
+ for (i = 0; i < num_len; i++)
+ if (num_buf[i] == '.')
+ dot_count++;
+ if (dot_count > 1) {
+ JS_ThrowRangeError(ctx, "invalid duration string");
+ return -1;
+ }
+ }
+ num_buf[num_len] = '\0';
+ num = strtod(num_buf, &end);
+ if (end == num_buf || !isfinite(num)) {
+ JS_ThrowRangeError(ctx, "invalid duration string");
+ return -1;
+ }
+ c = *p;
+ if (!c) {
+ JS_ThrowRangeError(ctx, "invalid duration string");
+ return -1;
+ }
+ has_value = 1;
+ if (in_time) {
+ switch (c) {
+ case 'H': case 'h':
+ if (floor(num) != num) frac_hours = 1;
+ hours += num;
+ break;
+ case 'M': case 'm':
+ has_minutes = 1;
+ if (floor(num) != num) frac_minutes = 1;
+ minutes += num;
+ break;
+ case 'S': case 's':
+ has_seconds = 1;
+ {
+ int dot_pos = -1, i;
+ for (i = 0; i < num_len; i++) {
+ if (num_buf[i] == '.') {
+ dot_pos = i;
+ break;
+ }
+ }
+ if (dot_pos >= 0) {
+ int frac_digits = num_len - dot_pos - 1;
+ char int_buf[32];
+ int64_t int_sec;
+ if (frac_digits > 9) {
+ JS_ThrowRangeError(ctx, "invalid duration string");
+ return -1;
+ }
+ /* Parse integer part separately to avoid double rounding */
+ if (dot_pos >= (int)sizeof(int_buf))
+ dot_pos = sizeof(int_buf) - 1;
+ memcpy(int_buf, num_buf, (size_t)dot_pos);
+ int_buf[dot_pos] = '\0';
+ int_sec = strtoll(int_buf, NULL, 10);
+ if (int_sec > DURATION_MAX_SECONDS || int_sec < -DURATION_MAX_SECONDS) {
+ JS_ThrowRangeError(ctx, "duration out of range");
+ return -1;
+ }
+ seconds += (double)int_sec;
+ /* Distribute fractional part to ms/us/ns */
+ {
+ char frac_buf[16];
+ int64_t frac_val;
+ int j;
+ for (j = 0; j < frac_digits && j < 9; j++)
+ frac_buf[j] = num_buf[dot_pos + 1 + j];
+ for (; j < 9; j++)
+ frac_buf[j] = '0';
+ frac_buf[9] = '\0';
+ frac_val = strtoll(frac_buf, NULL, 10);
+ milliseconds += (double)(frac_val / 1000000);
+ microseconds += (double)((frac_val / 1000) % 1000);
+ nanoseconds += (double)(frac_val % 1000);
+ }
+ } else {
+ int64_t int_sec = strtoll(num_buf, NULL, 10);
+ if (int_sec > DURATION_MAX_SECONDS || int_sec < -DURATION_MAX_SECONDS) {
+ JS_ThrowRangeError(ctx, "duration out of range");
+ return -1;
+ }
+ seconds += (double)int_sec;
+ }
+ }
+ break;
+ default:
+ JS_ThrowRangeError(ctx, "invalid duration string");
+ return -1;
+ }
+ } else {
+ switch (c) {
+ case 'Y': case 'y':
+ if (floor(num) != num) {
+ JS_ThrowRangeError(ctx, "invalid duration string");
+ return -1;
+ }
+ out->years = (int64_t)num;
+ break;
+ case 'M': case 'm':
+ if (floor(num) != num) {
+ JS_ThrowRangeError(ctx, "invalid duration string");
+ return -1;
+ }
+ out->months = (int64_t)num;
+ break;
+ case 'W': case 'w':
+ if (floor(num) != num) {
+ JS_ThrowRangeError(ctx, "invalid duration string");
+ return -1;
+ }
+ out->weeks = (int64_t)num;
+ break;
+ case 'D': case 'd':
+ if (floor(num) != num) {
+ JS_ThrowRangeError(ctx, "invalid duration string");
+ return -1;
+ }
+ out->days = (int64_t)num;
+ break;
+ default:
+ JS_ThrowRangeError(ctx, "invalid duration string");
+ return -1;
+ }
+ }
+ p++;
+ }
+ if (!has_value) {
+ JS_ThrowRangeError(ctx, "invalid duration string");
+ return -1;
+ }
+ if (*p) {
+ JS_ThrowRangeError(ctx, "invalid duration string");
+ return -1;
+ }
+ /* If a unit is fractional, no lower time unit may be present */
+ if ((frac_hours && (has_minutes || has_seconds)) ||
+ (frac_minutes && has_seconds)) {
+ JS_ThrowRangeError(ctx, "invalid duration string");
+ return -1;
+ }
+ /* Distribute fractional time units */
+ distribute_fractional_time(hours, minutes, seconds, milliseconds, microseconds, nanoseconds, out);
+ if (negative) {
+ out->years = -out->years;
+ out->months = -out->months;
+ out->weeks = -out->weeks;
+ out->days = -out->days;
+ out->hours = -out->hours;
+ out->minutes = -out->minutes;
+ out->seconds = -out->seconds;
+ out->milliseconds = -out->milliseconds;
+ out->microseconds.int128_value = -out->microseconds.int128_value;
+ out->nanoseconds.int128_value = -out->nanoseconds.int128_value;
+ }
+ return 0;
+}
+
+/* Convert an arbitrary value to a JSDurationData */
+/* Read a single duration property. Returns 1 if found, 0 if undefined, -1 on error. */
+static int read_duration_property(JSContext *ctx, JSValueConst obj, const char *name,
+ int use_128, int64_t *out_i64, js_int128_t *out_i128)
+{
+ JSValue v = JS_GetPropertyStr(ctx, obj, name);
+ if (JS_IsUndefined(v))
+ return 0;
+ if (use_128) {
+ if (to_integer_if_integral128(ctx, v, out_i128) < 0) {
+ JS_FreeValue(ctx, v);
+ return -1;
+ }
+ } else {
+ if (to_integer_if_integral(ctx, v, out_i64) < 0) {
+ JS_FreeValue(ctx, v);
+ return -1;
+ }
+ }
+ JS_FreeValue(ctx, v);
+ return 1;
+}
+
+int js_to_temporal_duration(JSContext *ctx, JSValueConst item, JSDurationData *out)
+{
+ JSDurationData *s;
+ int has_any = 0;
+ js_int128_t tmp_microseconds = 0, tmp_nanoseconds = 0;
+ int ret;
+ memset(out, 0, sizeof(*out));
+ if (JS_IsObject(item)) {
+ /* If it's already a Duration, extract its data */
+ s = JS_GetOpaque(item, js_duration_class_id);
+ if (s) {
+ *out = *s;
+ return 0;
+ }
+ /* Read duration-like properties in alphabetical order per spec */
+ ret = read_duration_property(ctx, item, "days", 0, &out->days, NULL);
+ if (ret < 0) return -1;
+ has_any |= ret;
+ ret = read_duration_property(ctx, item, "hours", 0, &out->hours, NULL);
+ if (ret < 0) return -1;
+ has_any |= ret;
+ ret = read_duration_property(ctx, item, "microseconds", 1, NULL, &tmp_microseconds);
+ if (ret < 0) return -1;
+ has_any |= ret;
+ ret = read_duration_property(ctx, item, "milliseconds", 0, &out->milliseconds, NULL);
+ if (ret < 0) return -1;
+ has_any |= ret;
+ ret = read_duration_property(ctx, item, "minutes", 0, &out->minutes, NULL);
+ if (ret < 0) return -1;
+ has_any |= ret;
+ ret = read_duration_property(ctx, item, "months", 0, &out->months, NULL);
+ if (ret < 0) return -1;
+ has_any |= ret;
+ ret = read_duration_property(ctx, item, "nanoseconds", 1, NULL, &tmp_nanoseconds);
+ if (ret < 0) return -1;
+ has_any |= ret;
+ ret = read_duration_property(ctx, item, "seconds", 0, &out->seconds, NULL);
+ if (ret < 0) return -1;
+ has_any |= ret;
+ ret = read_duration_property(ctx, item, "weeks", 0, &out->weeks, NULL);
+ if (ret < 0) return -1;
+ has_any |= ret;
+ ret = read_duration_property(ctx, item, "years", 0, &out->years, NULL);
+ if (ret < 0) return -1;
+ has_any |= ret;
+ out->microseconds.int128_value = tmp_microseconds;
+ out->nanoseconds.int128_value = tmp_nanoseconds;
+ if (!has_any) {
+ JS_ThrowTypeError(ctx, "no duration properties found");
+ return -1;
+ }
+ if (duration_has_mixed_signs(out)) {
+ JS_ThrowRangeError(ctx, "mixed-sign duration not allowed");
+ return -1;
+ }
+ return 0;
+ }
+ if (JS_IsString(item)) {
+ const char *str = JS_ToCString(ctx, item);
+ if (!str)
+ return -1;
+ ret = js_parse_duration_string(ctx, str, out);
+ JS_FreeCString(ctx, str);
+ return ret;
+ }
+ JS_ThrowTypeError(ctx, "cannot convert argument to Temporal.Duration");
+ return -1;
+}
+
+/* Temporal.Duration constructor */
+static JSValue js_duration_constructor(JSContext *ctx, JSValueConst new_target,
+ int argc, JSValueConst *argv)
+{
+ JSDurationData d = {0};
+ js_int128_t tmp_microseconds = 0, tmp_nanoseconds = 0;
+ JSValue obj;
+ if (JS_IsUndefined(new_target)) {
+ return JS_ThrowTypeError(ctx, "Temporal.Duration constructor cannot be called as a function");
+ }
+ if (argc > 0 && to_integer_if_integral(ctx, argv[0], &d.years) < 0)
+ return JS_EXCEPTION;
+ if (argc > 1 && to_integer_if_integral(ctx, argv[1], &d.months) < 0)
+ return JS_EXCEPTION;
+ if (argc > 2 && to_integer_if_integral(ctx, argv[2], &d.weeks) < 0)
+ return JS_EXCEPTION;
+ if (argc > 3 && to_integer_if_integral(ctx, argv[3], &d.days) < 0)
+ return JS_EXCEPTION;
+ if (argc > 4 && to_integer_if_integral(ctx, argv[4], &d.hours) < 0)
+ return JS_EXCEPTION;
+ if (argc > 5 && to_integer_if_integral(ctx, argv[5], &d.minutes) < 0)
+ return JS_EXCEPTION;
+ if (argc > 6 && to_integer_if_integral(ctx, argv[6], &d.seconds) < 0)
+ return JS_EXCEPTION;
+ if (argc > 7 && to_integer_if_integral(ctx, argv[7], &d.milliseconds) < 0)
+ return JS_EXCEPTION;
+ if (argc > 8 && to_integer_if_integral128(ctx, argv[8], &tmp_microseconds) < 0)
+ return JS_EXCEPTION;
+ if (argc > 9 && to_integer_if_integral128(ctx, argv[9], &tmp_nanoseconds) < 0)
+ return JS_EXCEPTION;
+ d.microseconds.int128_value = tmp_microseconds;
+ d.nanoseconds.int128_value = tmp_nanoseconds;
+ if (duration_has_mixed_signs(&d))
+ return JS_ThrowRangeError(ctx, "duration out of range");
+ if (duration_is_out_of_range(&d))
+ return JS_ThrowRangeError(ctx, "duration out of range");
+ {
+ JSDurationData *s = js_mallocz(ctx, sizeof(*s));
+ if (!s)
+ return JS_EXCEPTION;
+ *s = d;
+ obj = js_create_temporal_object(ctx, new_target, js_duration_class_id, s);
+ if (JS_IsException(obj)) {
+ js_free(ctx, s);
+ return JS_EXCEPTION;
+ }
+ return obj;
+ }
+}
+
+/* Temporal.Duration.from */
+static JSValue js_duration_from(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSDurationData d = {0};
+ JSValue val;
+ (void)this_val;
+ if (argc >= 2 && ti_validate_options_object(ctx, argv[1]) < 0)
+ return JS_EXCEPTION;
+ val = argv[0];
+ if (JS_IsObject(val)) {
+ if (js_to_temporal_duration(ctx, val, &d) < 0)
+ return JS_EXCEPTION;
+ if (duration_has_mixed_signs(&d))
+ return JS_ThrowRangeError(ctx, "duration out of range");
+ if (duration_is_out_of_range(&d))
+ return JS_ThrowRangeError(ctx, "duration out of range");
+ return js_create_duration(ctx, &d);
+ }
+ if (JS_IsString(val)) {
+ const char *str = JS_ToCString(ctx, val);
+ int ret;
+ if (!str)
+ return JS_EXCEPTION;
+ ret = js_parse_duration_string(ctx, str, &d);
+ JS_FreeCString(ctx, str);
+ if (ret < 0)
+ return JS_EXCEPTION;
+ if (duration_has_mixed_signs(&d))
+ return JS_ThrowRangeError(ctx, "duration out of range");
+ if (duration_is_out_of_range(&d))
+ return JS_ThrowRangeError(ctx, "duration out of range");
+ return js_create_duration(ctx, &d);
+ }
+ return JS_ThrowTypeError(ctx, "unsupported argument type for Temporal.Duration.from");
+}
+
+#define DURATION_GETTER(name) \
+static JSValue js_duration_get_##name(JSContext *ctx, JSValueConst this_val) \
+{ \
+ JSDurationData *s = JS_GetOpaque2(ctx, this_val, js_duration_class_id); \
+ if (!s) \
+ return JS_EXCEPTION; \
+ return JS_NewFloat64(ctx, (double)s->name); \
+}
+
+DURATION_GETTER(years)
+DURATION_GETTER(months)
+DURATION_GETTER(weeks)
+DURATION_GETTER(days)
+DURATION_GETTER(hours)
+DURATION_GETTER(minutes)
+DURATION_GETTER(seconds)
+DURATION_GETTER(milliseconds)
+
+static JSValue js_duration_get_microseconds(JSContext *ctx, JSValueConst this_val)
+{
+ JSDurationData *s = JS_GetOpaque2(ctx, this_val, js_duration_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ return JS_NewFloat64(ctx, (double)s->microseconds.int128_value);
+}
+
+static JSValue js_duration_get_nanoseconds(JSContext *ctx, JSValueConst this_val)
+{
+ JSDurationData *s = JS_GetOpaque2(ctx, this_val, js_duration_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ return JS_NewFloat64(ctx, (double)s->nanoseconds.int128_value);
+}
+
+static JSValue js_duration_get_blank(JSContext *ctx, JSValueConst this_val)
+{
+ JSDurationData *s = JS_GetOpaque2(ctx, this_val, js_duration_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ return JS_NewBool(ctx, s->years == 0 && s->months == 0 && s->weeks == 0 &&
+ s->days == 0 && s->hours == 0 && s->minutes == 0 &&
+ s->seconds == 0 && s->milliseconds == 0 &&
+ s->microseconds.int128_value == 0 && s->nanoseconds.int128_value == 0);
+}
+
+static JSValue js_duration_negated(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSDurationData *s = JS_GetOpaque2(ctx, this_val, js_duration_class_id);
+ (void)argc;
+ (void)argv;
+ JSDurationData d;
+ if (!s)
+ return JS_EXCEPTION;
+ d.years = -s->years;
+ d.months = -s->months;
+ d.weeks = -s->weeks;
+ d.days = -s->days;
+ d.hours = -s->hours;
+ d.minutes = -s->minutes;
+ d.seconds = -s->seconds;
+ d.milliseconds = -s->milliseconds;
+ d.microseconds.int128_value = -s->microseconds.int128_value;
+ d.nanoseconds.int128_value = -s->nanoseconds.int128_value;
+ return js_create_duration(ctx, &d);
+}
+
+static JSValue js_duration_abs(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSDurationData *s = JS_GetOpaque2(ctx, this_val, js_duration_class_id);
+ (void)argc;
+ (void)argv;
+ JSDurationData d;
+ if (!s)
+ return JS_EXCEPTION;
+ d.years = s->years < 0 ? -s->years : s->years;
+ d.months = s->months < 0 ? -s->months : s->months;
+ d.weeks = s->weeks < 0 ? -s->weeks : s->weeks;
+ d.days = s->days < 0 ? -s->days : s->days;
+ d.hours = s->hours < 0 ? -s->hours : s->hours;
+ d.minutes = s->minutes < 0 ? -s->minutes : s->minutes;
+ d.seconds = s->seconds < 0 ? -s->seconds : s->seconds;
+ d.milliseconds = s->milliseconds < 0 ? -s->milliseconds : s->milliseconds;
+ d.microseconds.int128_value = s->microseconds.int128_value < 0 ? -s->microseconds.int128_value : s->microseconds.int128_value;
+ d.nanoseconds.int128_value = s->nanoseconds.int128_value < 0 ? -s->nanoseconds.int128_value : s->nanoseconds.int128_value;
+ return js_create_duration(ctx, &d);
+}
+
+static JSValue js_duration_get_sign(JSContext *ctx, JSValueConst this_val)
+{
+ JSDurationData *s = JS_GetOpaque2(ctx, this_val, js_duration_class_id);
+ int sign = 0;
+ if (!s)
+ return JS_EXCEPTION;
+ if (s->years > 0 || s->months > 0 || s->weeks > 0 || s->days > 0 || s->hours > 0 ||
+ s->minutes > 0 || s->seconds > 0 || s->milliseconds > 0 || s->microseconds.int128_value > 0 ||
+ s->nanoseconds.int128_value > 0)
+ sign = 1;
+ else if (s->years < 0 || s->months < 0 || s->weeks < 0 || s->days < 0 || s->hours < 0 ||
+ s->minutes < 0 || s->seconds < 0 || s->milliseconds < 0 || s->microseconds.int128_value < 0 ||
+ s->nanoseconds.int128_value < 0)
+ sign = -1;
+ return JS_NewInt32(ctx, sign);
+}
+
+static JSValue js_duration_with(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ (void)argc;
+ JSDurationData *s;
+ JSDurationData d;
+ JSValue val;
+ int has_any = 0;
+ js_int128_t tmp_microseconds, tmp_nanoseconds;
+ s = JS_GetOpaque2(ctx, this_val, js_duration_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ d = *s;
+ tmp_microseconds = d.microseconds.int128_value;
+ tmp_nanoseconds = d.nanoseconds.int128_value;
+ val = argv[0];
+ if (!JS_IsObject(val))
+ return JS_ThrowTypeError(ctx, "with argument must be an object");
+ {
+ int ret;
+ /* Read in alphabetical order per spec */
+ ret = read_duration_property(ctx, val, "days", 0, &d.days, NULL);
+ if (ret < 0) return JS_EXCEPTION;
+ has_any |= ret;
+ ret = read_duration_property(ctx, val, "hours", 0, &d.hours, NULL);
+ if (ret < 0) return JS_EXCEPTION;
+ has_any |= ret;
+ ret = read_duration_property(ctx, val, "microseconds", 1, NULL, &tmp_microseconds);
+ if (ret < 0) return JS_EXCEPTION;
+ has_any |= ret;
+ ret = read_duration_property(ctx, val, "milliseconds", 0, &d.milliseconds, NULL);
+ if (ret < 0) return JS_EXCEPTION;
+ has_any |= ret;
+ ret = read_duration_property(ctx, val, "minutes", 0, &d.minutes, NULL);
+ if (ret < 0) return JS_EXCEPTION;
+ has_any |= ret;
+ ret = read_duration_property(ctx, val, "months", 0, &d.months, NULL);
+ if (ret < 0) return JS_EXCEPTION;
+ has_any |= ret;
+ ret = read_duration_property(ctx, val, "nanoseconds", 1, NULL, &tmp_nanoseconds);
+ if (ret < 0) return JS_EXCEPTION;
+ has_any |= ret;
+ ret = read_duration_property(ctx, val, "seconds", 0, &d.seconds, NULL);
+ if (ret < 0) return JS_EXCEPTION;
+ has_any |= ret;
+ ret = read_duration_property(ctx, val, "weeks", 0, &d.weeks, NULL);
+ if (ret < 0) return JS_EXCEPTION;
+ has_any |= ret;
+ ret = read_duration_property(ctx, val, "years", 0, &d.years, NULL);
+ if (ret < 0) return JS_EXCEPTION;
+ has_any |= ret;
+ }
+ d.microseconds.int128_value = tmp_microseconds;
+ d.nanoseconds.int128_value = tmp_nanoseconds;
+ if (!has_any)
+ return JS_ThrowTypeError(ctx, "no duration properties found");
+ if (duration_has_mixed_signs(&d))
+ return JS_ThrowRangeError(ctx, "duration out of range");
+ if (duration_is_out_of_range(&d))
+ return JS_ThrowRangeError(ctx, "duration out of range");
+ return js_create_duration(ctx, &d);
+}
+
+static js_int128_t duration_to_total_ns(const JSDurationData *d)
+{
+ int64_t total_seconds = d->years * 31536000LL +
+ d->months * 2592000LL +
+ d->weeks * 604800LL +
+ d->days * 86400LL +
+ d->hours * 3600LL +
+ d->minutes * 60LL +
+ d->seconds;
+ js_int128_t total_ns = (js_int128_t)total_seconds * 1000000000LL;
+ total_ns += (js_int128_t)d->milliseconds * 1000000LL;
+ total_ns += d->microseconds.int128_value * 1000LL;
+ total_ns += d->nanoseconds.int128_value;
+ return total_ns;
+}
+
+static int int128_fits_in_int64(js_int128_t v)
+{
+ return v >= INT64_MIN && v <= INT64_MAX;
+}
+
+static int duration_from_total_ns(js_int128_t total_ns, TIUnit largestUnit, JSDurationData *d)
+{
+ int negative = total_ns < 0;
+ js_int128_t abs_ns = negative ? -total_ns : total_ns;
+
+ memset(d, 0, sizeof(*d));
+
+ if (largestUnit <= TI_UNIT_SECOND) {
+ int64_t total_seconds = (int64_t)(abs_ns / 1000000000LL);
+ int32_t rem_ns = (int32_t)(abs_ns % 1000000000LL);
+
+ if (largestUnit <= TI_UNIT_YEAR) {
+ d->years = total_seconds / 31536000;
+ total_seconds %= 31536000;
+ }
+ if (largestUnit <= TI_UNIT_MONTH) {
+ d->months = total_seconds / 2592000;
+ total_seconds %= 2592000;
+ }
+ if (largestUnit <= TI_UNIT_WEEK) {
+ d->weeks = total_seconds / 604800;
+ total_seconds %= 604800;
+ }
+ if (largestUnit <= TI_UNIT_DAY) {
+ d->days = total_seconds / 86400;
+ total_seconds %= 86400;
+ }
+ if (largestUnit <= TI_UNIT_HOUR) {
+ d->hours = total_seconds / 3600;
+ total_seconds %= 3600;
+ }
+ if (largestUnit <= TI_UNIT_MINUTE) {
+ d->minutes = total_seconds / 60;
+ total_seconds %= 60;
+ }
+ d->seconds = total_seconds;
+
+ if (largestUnit <= TI_UNIT_MILLISECOND) {
+ d->milliseconds = rem_ns / 1000000;
+ rem_ns %= 1000000;
+ }
+ if (largestUnit <= TI_UNIT_MICROSECOND) {
+ d->microseconds.int128_value = rem_ns / 1000;
+ rem_ns %= 1000;
+ }
+ d->nanoseconds.int128_value = rem_ns;
+ } else {
+ if (largestUnit <= TI_UNIT_MILLISECOND) {
+ js_int128_t v = abs_ns / 1000000LL;
+ if (!int128_fits_in_int64(v)) return -1;
+ d->milliseconds = (int64_t)v;
+ abs_ns %= 1000000LL;
+ }
+ if (largestUnit <= TI_UNIT_MICROSECOND) {
+ d->microseconds.int128_value = abs_ns / 1000LL;
+ abs_ns %= 1000LL;
+ }
+ d->nanoseconds.int128_value = abs_ns;
+ }
+
+ if (negative) {
+ d->years = -d->years;
+ d->months = -d->months;
+ d->weeks = -d->weeks;
+ d->days = -d->days;
+ d->hours = -d->hours;
+ d->minutes = -d->minutes;
+ d->seconds = -d->seconds;
+ d->milliseconds = -d->milliseconds;
+ d->microseconds.int128_value = -d->microseconds.int128_value;
+ d->nanoseconds.int128_value = -d->nanoseconds.int128_value;
+ }
+ return 0;
+}
+
+static JSValue js_duration_add_subtract(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv, int sign)
+{
+ (void)argc;
+ JSDurationData *s;
+ JSDurationData d;
+ JSDurationData result;
+ s = JS_GetOpaque2(ctx, this_val, js_duration_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ if (js_to_temporal_duration(ctx, argv[0], &d) < 0)
+ return JS_EXCEPTION;
+ if (s->years != 0 || s->months != 0 || s->weeks != 0 || d.years != 0 || d.months != 0 || d.weeks != 0)
+ return JS_ThrowRangeError(ctx, "duration contains calendar units");
+ {
+ TIUnit largestUnit = ti_larger_of_two_units(duration_get_largest_unit(s), duration_get_largest_unit(&d));
+ js_int128_t total1 = duration_to_total_ns(s);
+ js_int128_t total2 = duration_to_total_ns(&d);
+ js_int128_t sum = total1 + sign * total2;
+ if (duration_from_total_ns(sum, largestUnit, &result) < 0)
+ return JS_ThrowRangeError(ctx, "duration out of range");
+ }
+ duration_round_fields_to_float64(&result);
+ if (duration_is_out_of_range(&result))
+ return JS_ThrowRangeError(ctx, "duration out of range");
+ return js_create_duration(ctx, &result);
+}
+
+static JSValue js_duration_add(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ return js_duration_add_subtract(ctx, this_val, argc, argv, 1);
+}
+
+static JSValue js_duration_subtract(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ return js_duration_add_subtract(ctx, this_val, argc, argv, -1);
+}
+
+static void duration_round_fields_to_float64(JSDurationData *d);
+static JSValue ti_to_temporal_relative_to_string(JSContext *ctx, const char *str);
+static JSValue ti_convert_relative_to_property_bag(JSContext *ctx, JSValueConst obj);
+static double ti_iso_total_in_unit(int rel_year, int rel_month, int rel_day,
+ int target_year, int target_month, int target_day,
+ TIUnit unit, int64_t rel_time_ns, int64_t target_time_ns);
+
+/* Temporal.Duration.compare */
+static JSValue js_duration_compare(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ (void)this_val;
+ JSDurationData d1, d2;
+ JSValue relativeTo = JS_UNDEFINED;
+ if (js_to_temporal_duration(ctx, argv[0], &d1) < 0)
+ return JS_EXCEPTION;
+ if (js_to_temporal_duration(ctx, argv[1], &d2) < 0)
+ return JS_EXCEPTION;
+ /* Round to float64 to match spec observable behavior */
+ duration_round_fields_to_float64(&d1);
+ duration_round_fields_to_float64(&d2);
+ if (duration_is_out_of_range(&d1))
+ return JS_ThrowRangeError(ctx, "duration out of range");
+ if (duration_is_out_of_range(&d2))
+ return JS_ThrowRangeError(ctx, "duration out of range");
+ /* Validate options object (spec step 3: GetOptionsObject) */
+ if (ti_validate_options_object(ctx, argc >= 3 ? argv[2] : JS_UNDEFINED) < 0)
+ return JS_EXCEPTION;
+ /* Read relativeTo from options (spec step 4: GetTemporalRelativeToOption) */
+ if (argc >= 3 && !JS_IsUndefined(argv[2])) {
+ relativeTo = JS_GetPropertyStr(ctx, argv[2], "relativeTo");
+ if (JS_IsException(relativeTo))
+ return JS_EXCEPTION;
+ if (!JS_IsUndefined(relativeTo)) {
+ if (JS_IsObject(relativeTo)) {
+ JSPlainDateTimeData *pdt = JS_GetOpaque(relativeTo, js_plaindatetime_class_id);
+ if (pdt && (pdt->calendar == CAL_ISO8601 || pdt->calendar == CAL_GREGORY)) {
+ JSValue plainDate = js_create_plaindate(ctx, pdt->year, pdt->month, pdt->day);
+ JS_FreeValue(ctx, relativeTo);
+ relativeTo = plainDate;
+ if (JS_IsException(relativeTo))
+ return JS_EXCEPTION;
+ }
+ if (!JS_GetOpaque(relativeTo, js_plaindate_class_id) &&
+ !JS_GetOpaque(relativeTo, js_plaindatetime_class_id) &&
+ !JS_GetOpaque(relativeTo, js_zoneddatetime_class_id)) {
+ JSValue converted = ti_convert_relative_to_property_bag(ctx, relativeTo);
+ JS_FreeValue(ctx, relativeTo);
+ relativeTo = converted;
+ if (JS_IsException(relativeTo))
+ return JS_EXCEPTION;
+ }
+ } else if (JS_IsString(relativeTo)) {
+ const char *rt_str = JS_ToCString(ctx, relativeTo);
+ if (!rt_str) {
+ JS_FreeValue(ctx, relativeTo);
+ return JS_EXCEPTION;
+ }
+ JS_FreeValue(ctx, relativeTo);
+ relativeTo = ti_to_temporal_relative_to_string(ctx, rt_str);
+ JS_FreeCString(ctx, rt_str);
+ if (JS_IsException(relativeTo))
+ return JS_EXCEPTION;
+ }
+ }
+ }
+ /* Early exit if all fields are equal (spec step 5) */
+ if (d1.years == d2.years && d1.months == d2.months && d1.weeks == d2.weeks &&
+ d1.days == d2.days && d1.hours == d2.hours && d1.minutes == d2.minutes &&
+ d1.seconds == d2.seconds && d1.milliseconds == d2.milliseconds &&
+ d1.microseconds.int128_value == d2.microseconds.int128_value && d1.nanoseconds.int128_value == d2.nanoseconds.int128_value) {
+ JS_FreeValue(ctx, relativeTo);
+ return JS_NewInt32(ctx, 0);
+ }
+ /* If calendar units are present, relativeTo is required */
+ if (d1.years != 0 || d1.months != 0 || d1.weeks != 0 ||
+ d2.years != 0 || d2.months != 0 || d2.weeks != 0) {
+ if (JS_IsUndefined(relativeTo))
+ return JS_ThrowRangeError(ctx, "relativeTo is required");
+ }
+ /* If relativeTo is ISO PlainDate/PlainDateTime, use actual calendar
+ arithmetic instead of approximate total nanoseconds. */
+ if (!JS_IsUndefined(relativeTo)) {
+ JSPlainDateData *pd = JS_GetOpaque(relativeTo, js_plaindate_class_id);
+ JSPlainDateTimeData *pdt = JS_GetOpaque(relativeTo, js_plaindatetime_class_id);
+ if (pd && (pd->calendar == CAL_ISO8601 || pd->calendar == CAL_GREGORY)) {
+ /* For time-only durations, skip calendar arithmetic and compare directly */
+ if (d1.years == 0 && d1.months == 0 && d1.weeks == 0 && d1.days == 0 &&
+ d2.years == 0 && d2.months == 0 && d2.weeks == 0 && d2.days == 0) {
+ JS_FreeValue(ctx, relativeTo);
+ goto compare_total_ns;
+ }
+ int y1, m1, d1d, h1, min1, s1, ms1, us1, ns1;
+ int y2, m2, d2d, h2, min2, s2, ms2, us2, ns2;
+ js_int128_t us_val = d1.microseconds.int128_value;
+ js_int128_t ns_val = d1.nanoseconds.int128_value;
+ if (ti_iso_datetime_add_duration(
+ pd->year, pd->month, pd->day, 0, 0, 0, 0, 0, 0,
+ d1.years, d1.months, d1.weeks, d1.days,
+ d1.hours, d1.minutes, d1.seconds, d1.milliseconds, us_val, ns_val,
+ &y1, &m1, &d1d, &h1, &min1, &s1, &ms1, &us1, &ns1) < 0) {
+ JS_FreeValue(ctx, relativeTo);
+ return JS_ThrowRangeError(ctx, "duration out of range");
+ }
+ if (!ti_is_date_within_iso_limits(y1, m1, d1d)) {
+ JS_FreeValue(ctx, relativeTo);
+ return JS_ThrowRangeError(ctx, "duration out of range");
+ }
+ us_val = d2.microseconds.int128_value;
+ ns_val = d2.nanoseconds.int128_value;
+ if (ti_iso_datetime_add_duration(
+ pd->year, pd->month, pd->day, 0, 0, 0, 0, 0, 0,
+ d2.years, d2.months, d2.weeks, d2.days,
+ d2.hours, d2.minutes, d2.seconds, d2.milliseconds, us_val, ns_val,
+ &y2, &m2, &d2d, &h2, &min2, &s2, &ms2, &us2, &ns2) < 0) {
+ JS_FreeValue(ctx, relativeTo);
+ return JS_ThrowRangeError(ctx, "duration out of range");
+ }
+ if (!ti_is_date_within_iso_limits(y2, m2, d2d)) {
+ JS_FreeValue(ctx, relativeTo);
+ return JS_ThrowRangeError(ctx, "duration out of range");
+ }
+ {
+ int64_t sec1 = pdt_to_ordinal_days(y1, m1, d1d) * 86400LL + h1 * 3600LL + min1 * 60LL + s1;
+ int64_t sec2 = pdt_to_ordinal_days(y2, m2, d2d) * 86400LL + h2 * 3600LL + min2 * 60LL + s2;
+ js_int128_t epoch1 = (js_int128_t)sec1 * 1000000000LL + (js_int128_t)ms1 * 1000000LL + (js_int128_t)us1 * 1000LL + (js_int128_t)ns1;
+ js_int128_t epoch2 = (js_int128_t)sec2 * 1000000000LL + (js_int128_t)ms2 * 1000000LL + (js_int128_t)us2 * 1000LL + (js_int128_t)ns2;
+ JS_FreeValue(ctx, relativeTo);
+ if (epoch1 < epoch2) return JS_NewInt32(ctx, -1);
+ if (epoch1 > epoch2) return JS_NewInt32(ctx, 1);
+ return JS_NewInt32(ctx, 0);
+ }
+ } else if (pdt && (pdt->calendar == CAL_ISO8601 || pdt->calendar == CAL_GREGORY)) {
+ /* For time-only durations, skip calendar arithmetic and compare directly */
+ if (d1.years == 0 && d1.months == 0 && d1.weeks == 0 && d1.days == 0 &&
+ d2.years == 0 && d2.months == 0 && d2.weeks == 0 && d2.days == 0) {
+ JS_FreeValue(ctx, relativeTo);
+ goto compare_total_ns;
+ }
+ int y1, m1, d1d, h1, min1, s1, ms1, us1, ns1;
+ int y2, m2, d2d, h2, min2, s2, ms2, us2, ns2;
+ js_int128_t us_val = d1.microseconds.int128_value;
+ js_int128_t ns_val = d1.nanoseconds.int128_value;
+ if (ti_iso_datetime_add_duration(
+ pdt->year, pdt->month, pdt->day, pdt->hour, pdt->minute, pdt->second,
+ pdt->millisecond, pdt->microsecond, pdt->nanosecond,
+ d1.years, d1.months, d1.weeks, d1.days,
+ d1.hours, d1.minutes, d1.seconds, d1.milliseconds, us_val, ns_val,
+ &y1, &m1, &d1d, &h1, &min1, &s1, &ms1, &us1, &ns1) < 0) {
+ JS_FreeValue(ctx, relativeTo);
+ return JS_ThrowRangeError(ctx, "duration out of range");
+ }
+ if (!ti_is_date_within_iso_limits(y1, m1, d1d)) {
+ JS_FreeValue(ctx, relativeTo);
+ return JS_ThrowRangeError(ctx, "duration out of range");
+ }
+ us_val = d2.microseconds.int128_value;
+ ns_val = d2.nanoseconds.int128_value;
+ if (ti_iso_datetime_add_duration(
+ pdt->year, pdt->month, pdt->day, pdt->hour, pdt->minute, pdt->second,
+ pdt->millisecond, pdt->microsecond, pdt->nanosecond,
+ d2.years, d2.months, d2.weeks, d2.days,
+ d2.hours, d2.minutes, d2.seconds, d2.milliseconds, us_val, ns_val,
+ &y2, &m2, &d2d, &h2, &min2, &s2, &ms2, &us2, &ns2) < 0) {
+ JS_FreeValue(ctx, relativeTo);
+ return JS_ThrowRangeError(ctx, "duration out of range");
+ }
+ if (!ti_is_date_within_iso_limits(y2, m2, d2d)) {
+ JS_FreeValue(ctx, relativeTo);
+ return JS_ThrowRangeError(ctx, "duration out of range");
+ }
+ {
+ int64_t sec1 = pdt_to_ordinal_days(y1, m1, d1d) * 86400LL + h1 * 3600LL + min1 * 60LL + s1;
+ int64_t sec2 = pdt_to_ordinal_days(y2, m2, d2d) * 86400LL + h2 * 3600LL + min2 * 60LL + s2;
+ js_int128_t epoch1 = (js_int128_t)sec1 * 1000000000LL + (js_int128_t)ms1 * 1000000LL + (js_int128_t)us1 * 1000LL + (js_int128_t)ns1;
+ js_int128_t epoch2 = (js_int128_t)sec2 * 1000000000LL + (js_int128_t)ms2 * 1000000LL + (js_int128_t)us2 * 1000LL + (js_int128_t)ns2;
+ JS_FreeValue(ctx, relativeTo);
+ if (epoch1 < epoch2) return JS_NewInt32(ctx, -1);
+ if (epoch1 > epoch2) return JS_NewInt32(ctx, 1);
+ return JS_NewInt32(ctx, 0);
+ }
+ } else {
+ JSZonedDateTimeData *zdt = JS_GetOpaque(relativeTo, js_zoneddatetime_class_id);
+ if (zdt) {
+ /* Only use ZonedDateTime arithmetic if date units are present.
+ For time-only durations, fall through to plain nanosecond comparison
+ to avoid spurious out-of-range errors from adding to boundary instants. */
+ if (d1.years == 0 && d1.months == 0 && d1.weeks == 0 && d1.days == 0 &&
+ d2.years == 0 && d2.months == 0 && d2.weeks == 0 && d2.days == 0) {
+ JS_FreeValue(ctx, relativeTo);
+ goto compare_total_ns;
+ }
+ JSValue d1_obj = js_create_duration(ctx, &d1);
+ if (JS_IsException(d1_obj)) {
+ JS_FreeValue(ctx, relativeTo);
+ return JS_EXCEPTION;
+ }
+ JSValue after1 = js_zoneddatetime_add(ctx, relativeTo, 1, &d1_obj);
+ JS_FreeValue(ctx, d1_obj);
+ if (JS_IsException(after1)) {
+ JS_FreeValue(ctx, relativeTo);
+ return JS_EXCEPTION;
+ }
+ JSValue d2_obj = js_create_duration(ctx, &d2);
+ if (JS_IsException(d2_obj)) {
+ JS_FreeValue(ctx, after1);
+ JS_FreeValue(ctx, relativeTo);
+ return JS_EXCEPTION;
+ }
+ JSValue after2 = js_zoneddatetime_add(ctx, relativeTo, 1, &d2_obj);
+ JS_FreeValue(ctx, d2_obj);
+ JS_FreeValue(ctx, relativeTo);
+ if (JS_IsException(after2)) {
+ JS_FreeValue(ctx, after1);
+ return JS_EXCEPTION;
+ }
+ JSZonedDateTimeData *a1 = JS_GetOpaque(after1, js_zoneddatetime_class_id);
+ JSZonedDateTimeData *a2 = JS_GetOpaque(after2, js_zoneddatetime_class_id);
+ js_int128_t ns1 = ti_timespec_to_ns(&a1->ts);
+ js_int128_t ns2 = ti_timespec_to_ns(&a2->ts);
+ JS_FreeValue(ctx, after1);
+ JS_FreeValue(ctx, after2);
+ if (ns1 < ns2) return JS_NewInt32(ctx, -1);
+ if (ns1 > ns2) return JS_NewInt32(ctx, 1);
+ return JS_NewInt32(ctx, 0);
+ }
+ }
+ }
+ JS_FreeValue(ctx, relativeTo);
+compare_total_ns:
+ /* Compare using exact js_int128_t arithmetic */
+ {
+ js_int128_t total1 = duration_to_total_ns(&d1);
+ js_int128_t total2 = duration_to_total_ns(&d2);
+ if (total1 < total2)
+ return JS_NewInt32(ctx, -1);
+ if (total1 > total2)
+ return JS_NewInt32(ctx, 1);
+ return JS_NewInt32(ctx, 0);
+ }
+}
+
+static int duration_has_calendar_units(const JSDurationData *s)
+{
+ return s->years != 0 || s->months != 0 || s->weeks != 0;
+}
+
+/* Format an instant difference (in nanoseconds) as a JSDurationData time
+ duration, capping fields according to largestUnit (a time unit:
+ hour..nanosecond). All date fields in out are zeroed. */
+static void duration_format_time_ns(js_int128_t total_ns, TIUnit largestUnit, JSDurationData *out)
+{
+ memset(out, 0, sizeof(*out));
+ int sign = (total_ns < 0) ? -1 : 1;
+ js_int128_t abs_ns = total_ns >= 0 ? total_ns : -total_ns;
+ int64_t total_seconds = (int64_t)(abs_ns / 1000000000LL);
+ int32_t rem_ns = (int32_t)(abs_ns % 1000000000LL);
+
+ if (largestUnit == TI_UNIT_HOUR) {
+ out->hours = sign * (total_seconds / 3600);
+ total_seconds %= 3600;
+ out->minutes = sign * (total_seconds / 60);
+ total_seconds %= 60;
+ out->seconds = sign * total_seconds;
+ out->milliseconds = sign * (rem_ns / 1000000);
+ rem_ns %= 1000000;
+ out->microseconds.int128_value = sign * (rem_ns / 1000);
+ out->nanoseconds.int128_value = sign * (rem_ns % 1000);
+ } else if (largestUnit == TI_UNIT_MINUTE) {
+ out->minutes = sign * (total_seconds / 60);
+ total_seconds %= 60;
+ out->seconds = sign * total_seconds;
+ out->milliseconds = sign * (rem_ns / 1000000);
+ rem_ns %= 1000000;
+ out->microseconds.int128_value = sign * (rem_ns / 1000);
+ out->nanoseconds.int128_value = sign * (rem_ns % 1000);
+ } else if (largestUnit == TI_UNIT_SECOND) {
+ out->seconds = sign * total_seconds;
+ out->milliseconds = sign * (rem_ns / 1000000);
+ rem_ns %= 1000000;
+ out->microseconds.int128_value = sign * (rem_ns / 1000);
+ out->nanoseconds.int128_value = sign * (rem_ns % 1000);
+ } else if (largestUnit == TI_UNIT_MILLISECOND) {
+ out->milliseconds = sign * (total_seconds * 1000 + rem_ns / 1000000);
+ rem_ns %= 1000000;
+ out->microseconds.int128_value = sign * (rem_ns / 1000);
+ out->nanoseconds.int128_value = sign * (rem_ns % 1000);
+ } else if (largestUnit == TI_UNIT_MICROSECOND) {
+ out->microseconds.int128_value = sign * (total_seconds * 1000000LL + rem_ns / 1000);
+ out->nanoseconds.int128_value = sign * (rem_ns % 1000);
+ } else {
+ /* TI_UNIT_NANOSECOND: everything in nanoseconds */
+ out->nanoseconds.int128_value = sign * total_ns;
+ }
+}
+
+/* Divide total_ns by divisor as a correctly-rounded double.
+ |total_ns| < ~2^86 (from DURATION_MAX_SECONDS * 1e9 + subsecond parts).
+ divisor is a uint64_t unit in nanoseconds, always < 2^53.
+ The simplest correct method uses __float128 division. */
+static double duration_total_div(js_int128_t total_ns, uint64_t divisor)
+{
+ /* Fast path: both total_ns and divisor are exactly representable as doubles,
+ and IEEE 754 division is correctly rounded. */
+ if (total_ns < (1LL << 53) && total_ns > -(1LL << 53)) {
+ return (double)total_ns / (double)divisor;
+ }
+#ifdef __SIZEOF_FLOAT128__
+ return (double)((__float128)total_ns / (__float128)divisor);
+#else
+ {
+ js_int128_t q = total_ns / (js_int128_t)divisor;
+ js_int128_t r = total_ns % (js_int128_t)divisor;
+ return (double)q + (double)r / (double)divisor;
+ }
+#endif
+}
+
+/* NudgeToCalendarUnit-style total for ZonedDateTime relativeTo.
+ Computes total = (r1 * denominator + sign * numerator) / denominator
+ where numerator = dest - start, denominator = end - start. */
+static int duration_total_nudge(const char *timeZone, CalendarType calendar,
+ JSTimeSpec origin, JSTimeSpec dest, JSDurationData *diff,
+ TIUnit unit, double *out)
+{
+ /* Determine sign from the first non-zero field (same as InternalDurationSign) */
+ int sign = 1;
+ if (diff->years < 0) sign = -1;
+ else if (diff->months < 0) sign = -1;
+ else if (diff->weeks < 0) sign = -1;
+ else if (diff->days < 0) sign = -1;
+ else if (diff->hours < 0) sign = -1;
+ else if (diff->minutes < 0) sign = -1;
+ else if (diff->seconds < 0) sign = -1;
+ else if (diff->milliseconds < 0) sign = -1;
+ else if (diff->microseconds.int128_value < 0) sign = -1;
+ else if (diff->nanoseconds.int128_value < 0) sign = -1;
+
+ int64_t r1 = 0;
+ JSDurationData start_d = {0};
+ JSDurationData end_d = {0};
+
+ switch (unit) {
+ case TI_UNIT_YEAR:
+ r1 = diff->years;
+ start_d.years = r1;
+ start_d.months = 0;
+ start_d.weeks = 0;
+ start_d.days = 0;
+ end_d.years = r1 + sign;
+ end_d.months = 0;
+ end_d.weeks = 0;
+ end_d.days = 0;
+ break;
+ case TI_UNIT_MONTH:
+ r1 = diff->months;
+ start_d.years = diff->years;
+ start_d.months = r1;
+ start_d.weeks = 0;
+ start_d.days = 0;
+ end_d.years = diff->years;
+ end_d.months = r1 + sign;
+ end_d.weeks = 0;
+ end_d.days = 0;
+ break;
+ case TI_UNIT_WEEK: {
+ /* Balance days into weeks like CalendarDateUntil(..., 'week') */
+ int64_t wsy, wsm, wsd, wey, wem, wed;
+ if (ti_iso_calendar_date_add(0, 1, 1, diff->years, diff->months, 0, 0, (int*)&wsy, (int*)&wsm, (int*)&wsd) < 0)
+ return -1;
+ if (ti_iso_calendar_date_add((int)wsy, (int)wsm, (int)wsd, 0, 0, 0, diff->days, (int*)&wey, (int*)&wem, (int*)&wed) < 0)
+ return -1;
+ int64_t wweeks = 0, wdays = 0;
+ ti_iso_calendar_date_until((int)wsy, (int)wsm, (int)wsd, (int)wey, (int)wem, (int)wed, TI_UNIT_WEEK,
+ &wweeks, &wdays, NULL, NULL);
+ r1 = diff->weeks + wweeks;
+ start_d.years = diff->years;
+ start_d.months = diff->months;
+ start_d.weeks = r1;
+ start_d.days = 0;
+ end_d.years = diff->years;
+ end_d.months = diff->months;
+ end_d.weeks = r1 + sign;
+ end_d.days = 0;
+ break;
+ }
+ case TI_UNIT_DAY:
+ r1 = diff->days;
+ start_d.years = diff->years;
+ start_d.months = diff->months;
+ start_d.weeks = diff->weeks;
+ start_d.days = r1;
+ end_d.years = diff->years;
+ end_d.months = diff->months;
+ end_d.weeks = diff->weeks;
+ end_d.days = r1 + sign;
+ break;
+ default:
+ return -1;
+ }
+
+ JSTimeSpec start_ts, end_ts;
+ if (ti_zoneddatetime_add_duration_iso(timeZone, calendar, origin, &start_d, 1, &start_ts) < 0)
+ return -1;
+ if (ti_zoneddatetime_add_duration_iso(timeZone, calendar, origin, &end_d, 1, &end_ts) < 0)
+ return -1;
+
+ js_int128_t start_ns = ti_timespec_to_ns(&start_ts);
+ js_int128_t end_ns = ti_timespec_to_ns(&end_ts);
+ js_int128_t dest_ns = ti_timespec_to_ns(&dest);
+
+ /* Expand window if dest is outside */
+ if (sign == 1) {
+ if (!(start_ns <= dest_ns && dest_ns <= end_ns)) {
+ r1 += sign;
+ start_d = end_d;
+ end_d.years = start_d.years;
+ end_d.months = start_d.months;
+ end_d.weeks = start_d.weeks;
+ end_d.days = start_d.days;
+ switch (unit) {
+ case TI_UNIT_YEAR: end_d.years += sign; end_d.months = 0; end_d.weeks = 0; end_d.days = 0; break;
+ case TI_UNIT_MONTH: end_d.months += sign; end_d.weeks = 0; end_d.days = 0; break;
+ case TI_UNIT_WEEK: end_d.weeks += sign; end_d.days = 0; break;
+ case TI_UNIT_DAY: end_d.days += sign; break;
+ default: break;
+ }
+ if (ti_zoneddatetime_add_duration_iso(timeZone, calendar, origin, &start_d, 1, &start_ts) < 0)
+ return -1;
+ if (ti_zoneddatetime_add_duration_iso(timeZone, calendar, origin, &end_d, 1, &end_ts) < 0)
+ return -1;
+ start_ns = ti_timespec_to_ns(&start_ts);
+ end_ns = ti_timespec_to_ns(&end_ts);
+ }
+ } else {
+ if (!(end_ns <= dest_ns && dest_ns <= start_ns)) {
+ r1 += sign;
+ start_d = end_d;
+ end_d.years = start_d.years;
+ end_d.months = start_d.months;
+ end_d.weeks = start_d.weeks;
+ end_d.days = start_d.days;
+ switch (unit) {
+ case TI_UNIT_YEAR: end_d.years += sign; end_d.months = 0; end_d.weeks = 0; end_d.days = 0; break;
+ case TI_UNIT_MONTH: end_d.months += sign; end_d.weeks = 0; end_d.days = 0; break;
+ case TI_UNIT_WEEK: end_d.weeks += sign; end_d.days = 0; break;
+ case TI_UNIT_DAY: end_d.days += sign; break;
+ default: break;
+ }
+ if (ti_zoneddatetime_add_duration_iso(timeZone, calendar, origin, &start_d, 1, &start_ts) < 0)
+ return -1;
+ if (ti_zoneddatetime_add_duration_iso(timeZone, calendar, origin, &end_d, 1, &end_ts) < 0)
+ return -1;
+ start_ns = ti_timespec_to_ns(&start_ts);
+ end_ns = ti_timespec_to_ns(&end_ts);
+ }
+ }
+
+ js_int128_t numerator = dest_ns - start_ns;
+ js_int128_t denominator = end_ns - start_ns;
+
+ if (denominator == 0) {
+ *out = (double)r1;
+ return 0;
+ }
+
+ *out = (double)((long double)(r1 * denominator + sign * numerator) / (long double)denominator);
+ return 0;
+}
+
+/* Check if adding sign days to a ZonedDateTime would stay within instant limits.
+ For now, only supports UTC. Returns TRUE if in range or cannot determine. */
+static BOOL ti_zoneddatetime_day_boundary_in_range(JSZonedDateTimeData *zdt, int sign)
+{
+ if (strcmp(zdt->timeZone, "UTC") != 0)
+ return TRUE;
+ {
+ js_int128_t epoch_ns = ti_timespec_to_ns(&zdt->ts);
+ int64_t ordinal = (int64_t)(epoch_ns / 86400000000000LL);
+ int64_t time_ns = (int64_t)(epoch_ns % 86400000000000LL);
+ if (time_ns < 0) {
+ time_ns += 86400000000000LL;
+ ordinal -= 1;
+ }
+ ordinal += sign;
+ {
+ js_int128_t new_epoch_ns = (js_int128_t)ordinal * 86400000000000LL + time_ns;
+ js_int128_t limit = (js_int128_t)INSTANT_MAX_SECS * 1000000000LL;
+ return (new_epoch_ns >= -limit && new_epoch_ns <= limit);
+ }
+ }
+}
+
+/* Convert a relativeTo string to a Temporal object (PlainDate, PlainDateTime,
+ or ZonedDateTime). Returns the object or JS_EXCEPTION on error. */
+static JSValue ti_to_temporal_relative_to_string(JSContext *ctx, const char *str)
+{
+ TISODateTimeParseResult r;
+ memset(&r, 0, sizeof(r));
+ if (ti_parse_iso_datetime_string(ctx, str, &r, TI_PARSE_DEFAULT) < 0)
+ return JS_ThrowRangeError(ctx, "invalid relativeTo string");
+ if (!r.has_date)
+ return JS_ThrowRangeError(ctx, "invalid relativeTo string");
+ if (r.has_utc && !r.has_tz_annotation)
+ return JS_ThrowRangeError(ctx, "invalid relativeTo string");
+
+ if (r.has_tz_annotation) {
+ /* ZonedDateTime: call ZonedDateTime.from directly for proper
+ offset/timezone validation */
+ JSValue str_val = JS_NewString(ctx, str);
+ JSValue result = js_zoneddatetime_from(ctx, JS_UNDEFINED, 1, &str_val);
+ JS_FreeValue(ctx, str_val);
+ return result;
+ } else {
+ /* GetTemporalRelativeToOption returns PlainDate for all strings
+ without time zone, discarding any time component. */
+ if (r.has_calendar && r.calendar != CAL_ISO8601)
+ return JS_ThrowRangeError(ctx, "invalid calendar ID");
+ return js_create_plaindate(ctx, r.year, r.month, r.day);
+ }
+}
+
+static JSValue ti_convert_relative_to_property_bag(JSContext *ctx, JSValueConst obj)
+{
+ TIPreparedFields fields;
+ JSValue result;
+ CalendarType cal = CAL_ISO8601;
+ uint32_t field_mask = TI_FIELD_YEAR | TI_FIELD_MONTH | TI_FIELD_MONTH_CODE |
+ TI_FIELD_DAY | TI_FIELD_HOUR | TI_FIELD_MINUTE |
+ TI_FIELD_SECOND | TI_FIELD_MILLISECOND | TI_FIELD_MICROSECOND |
+ TI_FIELD_NANOSECOND | TI_FIELD_OFFSET | TI_FIELD_TIMEZONE;
+
+ if (ti_resolve_calendar_from_object(ctx, obj, &cal) < 0)
+ return JS_EXCEPTION;
+
+ if (ti_prepare_calendar_fields(ctx, obj, field_mask, 0, 0, &fields, cal) < 0)
+ return JS_EXCEPTION;
+
+ if (fields.present_mask & TI_FIELD_TIMEZONE) {
+ result = ti_create_zoneddatetime_from_fields(ctx, &fields, 1, JS_UNDEFINED);
+ } else {
+ /* GetTemporalRelativeToOption returns PlainDate for all objects
+ without time zone, discarding any time component. */
+ result = ti_create_plaindate_from_fields(ctx, &fields, 1);
+ }
+
+ return result;
+}
+
+/* Compute exact total for ISO calendar total() with years/months/weeks unit.
+ This implements NudgeToCalendarUnit behavior for the ISO calendar.
+ rel_time_ns and target_time_ns are the time-of-day nanosecond offsets
+ (hour*3600*1e9 + minute*60*1e9 + second*1e9 + ms*1e6 + us*1e3 + ns). */
+static double ti_iso_total_in_unit(int rel_year, int rel_month, int rel_day,
+ int target_year, int target_month, int target_day,
+ TIUnit unit, int64_t rel_time_ns, int64_t target_time_ns)
+{
+ int64_t years = 0, months = 0, weeks = 0, days = 0;
+ int64_t start_ord, end_ord, target_ord;
+ int sy, sm, sd, ey, em, ed;
+ int sign;
+ const int64_t DAY_NS = 86400000000000LL;
+
+ target_ord = pdt_to_ordinal_days(target_year, target_month, target_day);
+
+ if (unit == TI_UNIT_YEAR) {
+ ti_iso_calendar_date_until(rel_year, rel_month, rel_day,
+ target_year, target_month, target_day,
+ TI_UNIT_YEAR, &years, &months, &weeks, &days);
+ sign = (years < 0 || (years == 0 && months < 0) ||
+ (years == 0 && months == 0 && weeks < 0) ||
+ (years == 0 && months == 0 && weeks == 0 && days < 0)) ? -1 : 1;
+ ti_iso_calendar_date_add(rel_year, rel_month, rel_day, years, 0, 0, 0, &sy, &sm, &sd);
+ start_ord = pdt_to_ordinal_days(sy, sm, sd);
+ ti_iso_calendar_date_add(rel_year, rel_month, rel_day, years + sign, 0, 0, 0, &ey, &em, &ed);
+ end_ord = pdt_to_ordinal_days(ey, em, ed);
+ if (end_ord == start_ord) end_ord = start_ord + sign; /* shouldn't happen */
+ js_int128_t num = (js_int128_t)years * (end_ord - start_ord) * DAY_NS
+ + ((js_int128_t)(target_ord - start_ord) * DAY_NS + (target_time_ns - rel_time_ns)) * sign;
+ js_int128_t den = (js_int128_t)(end_ord - start_ord) * DAY_NS;
+ js_int128_t q = num / den;
+ js_int128_t r = num % den;
+ if (q <= 1 && q >= -1)
+ return (double)num / (double)den;
+ else
+ return (double)q + (double)r / (double)den;
+ } else if (unit == TI_UNIT_MONTH) {
+ ti_iso_calendar_date_until(rel_year, rel_month, rel_day,
+ target_year, target_month, target_day,
+ TI_UNIT_MONTH, &years, &months, &weeks, &days);
+ int64_t total_months = years * 12 + months;
+ sign = (total_months < 0 || (total_months == 0 && weeks < 0) ||
+ (total_months == 0 && weeks == 0 && days < 0)) ? -1 : 1;
+ int64_t r1 = total_months;
+ int64_t r2 = r1 + sign;
+
+ ti_iso_calendar_date_add(rel_year, rel_month, rel_day, 0, r1, 0, 0, &sy, &sm, &sd);
+ start_ord = pdt_to_ordinal_days(sy, sm, sd);
+ ti_iso_calendar_date_add(rel_year, rel_month, rel_day, 0, r2, 0, 0, &ey, &em, &ed);
+ end_ord = pdt_to_ordinal_days(ey, em, ed);
+
+ js_int128_t startEpochNs = (js_int128_t)start_ord * DAY_NS + rel_time_ns;
+ js_int128_t endEpochNs = (js_int128_t)end_ord * DAY_NS + rel_time_ns;
+ js_int128_t destEpochNs = (js_int128_t)target_ord * DAY_NS + target_time_ns;
+
+ BOOL in_bounds = (sign == 1) ? (startEpochNs <= destEpochNs && destEpochNs <= endEpochNs)
+ : (endEpochNs <= destEpochNs && destEpochNs <= startEpochNs);
+ if (!in_bounds) {
+ r1 += sign;
+ r2 += sign;
+ ti_iso_calendar_date_add(rel_year, rel_month, rel_day, 0, r1, 0, 0, &sy, &sm, &sd);
+ start_ord = pdt_to_ordinal_days(sy, sm, sd);
+ ti_iso_calendar_date_add(rel_year, rel_month, rel_day, 0, r2, 0, 0, &ey, &em, &ed);
+ end_ord = pdt_to_ordinal_days(ey, em, ed);
+ }
+
+ if (end_ord == start_ord) end_ord = start_ord + sign; /* shouldn't happen */
+
+ js_int128_t num = (js_int128_t)r1 * (end_ord - start_ord) * DAY_NS
+ + ((js_int128_t)(target_ord - start_ord) * DAY_NS + (target_time_ns - rel_time_ns)) * sign;
+ js_int128_t den = (js_int128_t)(end_ord - start_ord) * DAY_NS;
+ js_int128_t q = num / den;
+ js_int128_t r = num % den;
+ if (q <= 1 && q >= -1)
+ return (double)num / (double)den;
+ else
+ return (double)q + (double)r / (double)den;
+ } else if (unit == TI_UNIT_WEEK) {
+ ti_iso_calendar_date_until(rel_year, rel_month, rel_day,
+ target_year, target_month, target_day,
+ TI_UNIT_WEEK, &years, &months, &weeks, &days);
+ sign = (weeks < 0 || (weeks == 0 && days < 0)) ? -1 : 1;
+ ti_iso_calendar_date_add(rel_year, rel_month, rel_day, 0, 0, weeks, 0, &sy, &sm, &sd);
+ start_ord = pdt_to_ordinal_days(sy, sm, sd);
+ ti_iso_calendar_date_add(rel_year, rel_month, rel_day, 0, 0, weeks + sign, 0, &ey, &em, &ed);
+ end_ord = pdt_to_ordinal_days(ey, em, ed);
+ if (end_ord == start_ord) end_ord = start_ord + sign; /* shouldn't happen */
+ js_int128_t num = (js_int128_t)weeks * (end_ord - start_ord) * DAY_NS
+ + ((js_int128_t)(target_ord - start_ord) * DAY_NS + (target_time_ns - rel_time_ns)) * sign;
+ js_int128_t den = (js_int128_t)(end_ord - start_ord) * DAY_NS;
+ js_int128_t q = num / den;
+ js_int128_t r = num % den;
+ if (q <= 1 && q >= -1)
+ return (double)num / (double)den;
+ else
+ return (double)q + (double)r / (double)den;
+ }
+ return 0.0;
+}
+
+static JSValue js_duration_total(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ (void)argc;
+ JSDurationData *s;
+ TIUnit unit_enum = TI_UNIT_INVALID;
+ JSValue relativeTo_val = JS_UNDEFINED;
+ double total;
+ int has_relativeTo = 0;
+ int is_calendar_unit;
+ int has_calendar_units;
+
+ if (JS_IsUndefined(argv[0]))
+ return JS_ThrowTypeError(ctx, "total requires a unit argument");
+
+ if (!JS_IsString(argv[0]) && !JS_IsObject(argv[0]))
+ return JS_ThrowTypeError(ctx, "total requires a unit argument");
+
+ s = JS_GetOpaque2(ctx, this_val, js_duration_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+
+ if (JS_IsString(argv[0])) {
+ /* String shorthand: unit is the argument, relativeTo is undefined */
+ const char *unit_str = JS_ToCString(ctx, argv[0]);
+ if (!unit_str)
+ return JS_EXCEPTION;
+ unit_enum = ti_string_to_unit(unit_str, strlen(unit_str));
+ JS_FreeCString(ctx, unit_str);
+ if (unit_enum == TI_UNIT_INVALID)
+ return JS_ThrowRangeError(ctx, "invalid unit");
+ } else {
+ /* Object argument: read relativeTo first, then unit */
+ JSValue options = JS_ToObject(ctx, argv[0]);
+ if (JS_IsException(options))
+ return JS_EXCEPTION;
+
+ relativeTo_val = JS_GetPropertyStr(ctx, options, "relativeTo");
+ if (JS_IsException(relativeTo_val)) {
+ JS_FreeValue(ctx, options);
+ return JS_EXCEPTION;
+ }
+ if (!JS_IsUndefined(relativeTo_val)) {
+ if (!JS_IsString(relativeTo_val) && !JS_IsObject(relativeTo_val)) {
+ JS_FreeValue(ctx, options);
+ JS_FreeValue(ctx, relativeTo_val);
+ return JS_ThrowTypeError(ctx, "invalid relativeTo");
+ }
+ has_relativeTo = 1;
+ }
+
+ /* Convert relativeTo string to Temporal object */
+ if (has_relativeTo && JS_IsString(relativeTo_val)) {
+ const char *rt_str = JS_ToCString(ctx, relativeTo_val);
+ if (!rt_str) {
+ JS_FreeValue(ctx, options);
+ goto fail;
+ }
+ JS_FreeValue(ctx, relativeTo_val);
+ relativeTo_val = ti_to_temporal_relative_to_string(ctx, rt_str);
+ JS_FreeCString(ctx, rt_str);
+ if (JS_IsException(relativeTo_val)) {
+ JS_FreeValue(ctx, options);
+ goto fail;
+ }
+ }
+ /* Convert PlainDateTime objects to PlainDate per GetTemporalRelativeToOption */
+ if (has_relativeTo && JS_IsObject(relativeTo_val)) {
+ JSPlainDateTimeData *pdt = JS_GetOpaque(relativeTo_val, js_plaindatetime_class_id);
+ if (pdt && (pdt->calendar == CAL_ISO8601 || pdt->calendar == CAL_GREGORY)) {
+ JSValue plainDate = js_create_plaindate(ctx, pdt->year, pdt->month, pdt->day);
+ JS_FreeValue(ctx, relativeTo_val);
+ relativeTo_val = plainDate;
+ if (JS_IsException(relativeTo_val)) {
+ JS_FreeValue(ctx, options);
+ goto fail;
+ }
+ }
+ }
+ /* Validate and convert relativeTo property bag before reading unit */
+ if (has_relativeTo && JS_IsObject(relativeTo_val)) {
+ if (!JS_GetOpaque(relativeTo_val, js_zoneddatetime_class_id) &&
+ !JS_GetOpaque(relativeTo_val, js_plaindate_class_id) &&
+ !JS_GetOpaque(relativeTo_val, js_plaindatetime_class_id)) {
+ JSValue converted = ti_convert_relative_to_property_bag(ctx, relativeTo_val);
+ JS_FreeValue(ctx, relativeTo_val);
+ relativeTo_val = converted;
+ if (JS_IsException(relativeTo_val)) {
+ JS_FreeValue(ctx, options);
+ goto fail;
+ }
+ }
+ }
+
+ if (ti_parse_unit_option(ctx, options, "unit", &unit_enum, 0, 0) < 0) {
+ JS_FreeValue(ctx, options);
+ goto fail;
+ }
+ JS_FreeValue(ctx, options);
+ }
+
+ is_calendar_unit = (unit_enum >= TI_UNIT_YEAR && unit_enum <= TI_UNIT_WEEK);
+ has_calendar_units = duration_has_calendar_units(s);
+
+ /* Extract ISO date fields from relativeTo object */
+ int rel_year = 0, rel_month = 0, rel_day = 0;
+ int rel_hour = 0, rel_minute = 0, rel_second = 0, rel_ms = 0, rel_us = 0, rel_ns = 0;
+ int use_iso = 0;
+ if (has_relativeTo && JS_IsObject(relativeTo_val)) {
+ JSPlainDateData *pd = JS_GetOpaque(relativeTo_val, js_plaindate_class_id);
+ if (pd && (pd->calendar == CAL_ISO8601 || pd->calendar == CAL_GREGORY)) {
+ rel_year = pd->year; rel_month = pd->month; rel_day = pd->day;
+ use_iso = 1;
+ } else {
+ JSPlainDateTimeData *pdt = JS_GetOpaque(relativeTo_val, js_plaindatetime_class_id);
+ if (pdt && (pdt->calendar == CAL_ISO8601 || pdt->calendar == CAL_GREGORY)) {
+ rel_year = pdt->year; rel_month = pdt->month; rel_day = pdt->day;
+ rel_hour = pdt->hour; rel_minute = pdt->minute; rel_second = pdt->second;
+ rel_ms = pdt->millisecond; rel_us = pdt->microsecond; rel_ns = pdt->nanosecond;
+ use_iso = 1;
+ } else {
+ JSZonedDateTimeData *zdt = JS_GetOpaque(relativeTo_val, js_zoneddatetime_class_id);
+ if (zdt && (zdt->calendar == CAL_ISO8601 || zdt->calendar == CAL_GREGORY)) {
+ int64_t offset_sec = 0;
+ int tz_id = ti_tz_find_id(zdt->timeZone);
+ if (tz_id >= 0) {
+ offset_sec = ti_tz_offset_at_sec(tz_id, zdt->ts.secs);
+ } else {
+ int64_t offset_ns = 0;
+ int ret = ti_parse_temporal_timezone_string(zdt->timeZone, &offset_ns);
+ if (ret >= 0)
+ offset_sec = offset_ns / 1000000000LL;
+ }
+ int64_t local_sec = zdt->ts.secs + offset_sec;
+ int local_nsec = (int)zdt->ts.nsecs;
+ if (local_nsec >= 1000000000) {
+ local_sec += 1;
+ local_nsec -= 1000000000;
+ } else if (local_nsec < 0) {
+ local_sec -= 1;
+ local_nsec += 1000000000;
+ }
+ {
+ int64_t year64;
+ ti_epoch_sec_to_date(local_sec, &year64, &rel_month, &rel_day, &rel_hour, &rel_minute, &rel_second);
+ rel_year = (int)year64;
+ }
+ rel_ms = local_nsec / 1000000;
+ rel_us = (local_nsec / 1000) % 1000;
+ rel_ns = local_nsec % 1000;
+ use_iso = 1;
+ }
+ }
+ }
+ }
+
+ /* If no relativeTo and either the duration or the unit involves calendar units, throw */
+ if (!has_relativeTo && (has_calendar_units || is_calendar_unit)) {
+ JS_FreeValue(ctx, relativeTo_val);
+ return JS_ThrowRangeError(ctx, "a starting point is required for durations with calendar units");
+ }
+
+ js_int128_t total_ns;
+ int ty, tm, td, th, tmin, ts, tms, tus, tns;
+
+ /* Zero duration always totals to 0, unless ZonedDateTime relativeTo
+ requires NudgeToCalendarUnit validation for days. */
+ if (s->years == 0 && s->months == 0 && s->weeks == 0 && s->days == 0 &&
+ s->hours == 0 && s->minutes == 0 && s->seconds == 0 &&
+ s->milliseconds == 0 && s->microseconds.int128_value == 0 && s->nanoseconds.int128_value == 0) {
+ JSZonedDateTimeData *zdt = JS_GetOpaque(relativeTo_val, js_zoneddatetime_class_id);
+ if (zdt && unit_enum == TI_UNIT_DAY) {
+ if (!ti_zoneddatetime_day_boundary_in_range(zdt, 1)) {
+ JS_FreeValue(ctx, relativeTo_val);
+ return JS_ThrowRangeError(ctx, "relativeTo outside valid instant range");
+ }
+ }
+ JS_FreeValue(ctx, relativeTo_val);
+ return JS_NewFloat64(ctx, 0);
+ }
+
+ /* ZonedDateTime relativeTo with ISO-like calendar: use AddZonedDateTime
+ + DifferenceZonedDateTime per spec. */
+ {
+ JSZonedDateTimeData *zdt = NULL;
+ if (has_relativeTo && JS_IsObject(relativeTo_val))
+ zdt = JS_GetOpaque(relativeTo_val, js_zoneddatetime_class_id);
+ if (zdt && (zdt->calendar == CAL_ISO8601 || zdt->calendar == CAL_GREGORY)) {
+ JSTimeSpec origin = zdt->ts;
+ JSTimeSpec target;
+ JSDurationData add_d = *s;
+ if (ti_zoneddatetime_add_duration_iso(zdt->timeZone, zdt->calendar, origin, &add_d, 1, &target) < 0) {
+ JS_FreeValue(ctx, relativeTo_val);
+ return JS_ThrowRangeError(ctx, "total result outside valid ISO range");
+ }
+ js_int128_t zdt_total_ns = ti_timespec_to_ns(&target)
+ - (ti_timespec_to_ns(&origin));
+
+ if (unit_enum == TI_UNIT_DAY) {
+ JSDurationData diff;
+ if (ti_zoneddatetime_difference_iso(zdt->timeZone, zdt->calendar, origin, target, TI_UNIT_DAY, &diff) < 0) {
+ JS_FreeValue(ctx, relativeTo_val);
+ return JS_ThrowRangeError(ctx, "total result outside valid ISO range");
+ }
+ if (duration_total_nudge(zdt->timeZone, zdt->calendar, origin, target, &diff, TI_UNIT_DAY, &total) < 0) {
+ JS_FreeValue(ctx, relativeTo_val);
+ return JS_ThrowRangeError(ctx, "total result outside valid ISO range");
+ }
+ JS_FreeValue(ctx, relativeTo_val);
+ return JS_NewFloat64(ctx, total);
+ } else if (unit_enum == TI_UNIT_YEAR) {
+ JSDurationData diff;
+ if (ti_zoneddatetime_difference_iso(zdt->timeZone, zdt->calendar, origin, target, TI_UNIT_YEAR, &diff) < 0) {
+ JS_FreeValue(ctx, relativeTo_val);
+ return JS_ThrowRangeError(ctx, "total result outside valid ISO range");
+ }
+ if (duration_total_nudge(zdt->timeZone, zdt->calendar, origin, target, &diff, TI_UNIT_YEAR, &total) < 0) {
+ JS_FreeValue(ctx, relativeTo_val);
+ return JS_ThrowRangeError(ctx, "total result outside valid ISO range");
+ }
+ JS_FreeValue(ctx, relativeTo_val);
+ return JS_NewFloat64(ctx, total);
+ } else if (unit_enum == TI_UNIT_MONTH) {
+ JSDurationData diff;
+ if (ti_zoneddatetime_difference_iso(zdt->timeZone, zdt->calendar, origin, target, TI_UNIT_MONTH, &diff) < 0) {
+ JS_FreeValue(ctx, relativeTo_val);
+ return JS_ThrowRangeError(ctx, "total result outside valid ISO range");
+ }
+ if (duration_total_nudge(zdt->timeZone, zdt->calendar, origin, target, &diff, TI_UNIT_MONTH, &total) < 0) {
+ JS_FreeValue(ctx, relativeTo_val);
+ return JS_ThrowRangeError(ctx, "total result outside valid ISO range");
+ }
+ JS_FreeValue(ctx, relativeTo_val);
+ return JS_NewFloat64(ctx, total);
+ } else if (unit_enum == TI_UNIT_WEEK) {
+ JSDurationData diff;
+ if (ti_zoneddatetime_difference_iso(zdt->timeZone, zdt->calendar, origin, target, TI_UNIT_WEEK, &diff) < 0) {
+ JS_FreeValue(ctx, relativeTo_val);
+ return JS_ThrowRangeError(ctx, "total result outside valid ISO range");
+ }
+ if (duration_total_nudge(zdt->timeZone, zdt->calendar, origin, target, &diff, TI_UNIT_WEEK, &total) < 0) {
+ JS_FreeValue(ctx, relativeTo_val);
+ return JS_ThrowRangeError(ctx, "total result outside valid ISO range");
+ }
+ JS_FreeValue(ctx, relativeTo_val);
+ return JS_NewFloat64(ctx, total);
+ } else if (unit_enum == TI_UNIT_HOUR) {
+ total = duration_total_div(zdt_total_ns, 3600000000000ULL);
+ } else if (unit_enum == TI_UNIT_MINUTE) {
+ total = duration_total_div(zdt_total_ns, 60000000000ULL);
+ } else if (unit_enum == TI_UNIT_SECOND) {
+ total = duration_total_div(zdt_total_ns, 1000000000ULL);
+ } else if (unit_enum == TI_UNIT_MILLISECOND) {
+ total = duration_total_div(zdt_total_ns, 1000000ULL);
+ } else if (unit_enum == TI_UNIT_MICROSECOND) {
+ total = duration_total_div(zdt_total_ns, 1000ULL);
+ } else if (unit_enum == TI_UNIT_NANOSECOND) {
+ total = (double)zdt_total_ns;
+ } else {
+ JS_FreeValue(ctx, relativeTo_val);
+ return JS_ThrowRangeError(ctx, "unit out of range");
+ }
+ JS_FreeValue(ctx, relativeTo_val);
+ return JS_NewFloat64(ctx, total);
+ }
+ }
+
+ /* Compute total nanoseconds as exact integer, then divide to avoid
+ floating-point rounding order differences. For ISO calendar relativeTo
+ with calendar-unit durations, compute the actual difference between
+ relativeTo and relativeTo + duration. */
+ if (has_relativeTo && (has_calendar_units || s->days != 0 || is_calendar_unit) && use_iso) {
+ js_int128_t us_val = s->microseconds.int128_value;
+ js_int128_t ns_val = s->nanoseconds.int128_value;
+ if (ti_iso_datetime_add_duration(
+ rel_year, rel_month, rel_day, rel_hour, rel_minute, rel_second, rel_ms, rel_us, rel_ns,
+ s->years, s->months, s->weeks, s->days,
+ s->hours, s->minutes, s->seconds, s->milliseconds, us_val, ns_val,
+ &ty, &tm, &td, &th, &tmin, &ts, &tms, &tus, &tns) < 0) {
+ JS_FreeValue(ctx, relativeTo_val);
+ return JS_ThrowRangeError(ctx, "total result outside valid ISO range");
+ }
+ if (!ti_is_date_within_iso_limits(ty, tm, td)) {
+ JS_FreeValue(ctx, relativeTo_val);
+ return JS_ThrowRangeError(ctx, "total result outside valid ISO range");
+ }
+ if (JS_GetOpaque(relativeTo_val, js_plaindate_class_id)) {
+ if (!pdt_is_within_limits(rel_year, rel_month, rel_day, rel_hour, rel_minute, rel_second, rel_ms, rel_us, rel_ns) ||
+ !pdt_is_within_limits(ty, tm, td, th, tmin, ts, tms, tus, tns)) {
+ JS_FreeValue(ctx, relativeTo_val);
+ return JS_ThrowRangeError(ctx, "relativeTo outside valid ISO range");
+ }
+ }
+ {
+ int64_t rel_sec = pdt_to_ordinal_days(rel_year, rel_month, rel_day) * 86400LL + rel_hour * 3600LL + rel_minute * 60LL + rel_second;
+ int64_t target_sec = pdt_to_ordinal_days(ty, tm, td) * 86400LL + th * 3600LL + tmin * 60LL + ts;
+ js_int128_t rel_epoch_ns = (js_int128_t)rel_sec * 1000000000LL + (js_int128_t)rel_ms * 1000000LL + (js_int128_t)rel_us * 1000LL + (js_int128_t)rel_ns;
+ js_int128_t target_epoch_ns = (js_int128_t)target_sec * 1000000000LL + (js_int128_t)tms * 1000000LL + (js_int128_t)tus * 1000LL + (js_int128_t)tns;
+ total_ns = target_epoch_ns - rel_epoch_ns;
+ }
+ /* NudgeToCalendarUnit validation: for calendar units with PlainDate
+ or ZonedDateTime, ensure relativeTo + {unit: sign} is within ISO limits. */
+ if (is_calendar_unit && (JS_GetOpaque(relativeTo_val, js_plaindate_class_id) ||
+ (js_zoneddatetime_class_id && JS_GetOpaque(relativeTo_val, js_zoneddatetime_class_id)))) {
+ int sign = (total_ns > 0) ? 1 : (total_ns < 0) ? -1 : 0;
+ if (sign != 0) {
+ int ny, nm, nd;
+ int64_t add_y = 0, add_m = 0, add_w = 0, add_d = 0;
+ if (unit_enum == TI_UNIT_YEAR) add_y = sign;
+ else if (unit_enum == TI_UNIT_MONTH) add_m = sign;
+ else if (unit_enum == TI_UNIT_WEEK) add_w = sign;
+ else if (unit_enum == TI_UNIT_DAY) add_d = sign;
+ if (ti_iso_calendar_date_add(rel_year, rel_month, rel_day, add_y, add_m, add_w, add_d, &ny, &nm, &nd) < 0 ||
+ !ti_is_date_within_iso_limits(ny, nm, nd)) {
+ JS_FreeValue(ctx, relativeTo_val);
+ return JS_ThrowRangeError(ctx, "total result outside valid ISO range");
+ }
+ }
+ }
+ } else {
+ if (has_relativeTo && use_iso && JS_GetOpaque(relativeTo_val, js_plaindate_class_id)) {
+ int ety, etm, etd, eth, etmin, ets, etms, etus, etns;
+ if (ti_iso_datetime_add_duration(
+ rel_year, rel_month, rel_day, rel_hour, rel_minute, rel_second, rel_ms, rel_us, rel_ns,
+ 0, 0, 0, 0,
+ s->hours, s->minutes, s->seconds, s->milliseconds,
+ s->microseconds.int128_value, s->nanoseconds.int128_value,
+ &ety, &etm, &etd, ð, &etmin, &ets, &etms, &etus, &etns) < 0) {
+ JS_FreeValue(ctx, relativeTo_val);
+ return JS_ThrowRangeError(ctx, "relativeTo outside valid ISO range");
+ }
+ if (!pdt_is_within_limits(rel_year, rel_month, rel_day, rel_hour, rel_minute, rel_second, rel_ms, rel_us, rel_ns) ||
+ !pdt_is_within_limits(ety, etm, etd, eth, etmin, ets, etms, etus, etns)) {
+ JS_FreeValue(ctx, relativeTo_val);
+ return JS_ThrowRangeError(ctx, "relativeTo outside valid ISO range");
+ }
+ }
+ {
+ int64_t total_seconds = s->days * 86400LL +
+ s->hours * 3600LL +
+ s->minutes * 60LL +
+ s->seconds;
+ total_ns = (js_int128_t)total_seconds * 1000000000LL +
+ (js_int128_t)s->milliseconds * 1000000LL +
+ s->microseconds.int128_value * 1000LL +
+ s->nanoseconds.int128_value;
+ }
+ }
+
+ /* For ZonedDateTime relativeTo with time-only durations, validate
+ that the result epoch nanoseconds are within Instant limits. */
+ if (has_relativeTo && JS_IsObject(relativeTo_val)) {
+ JSZonedDateTimeData *zdt = JS_GetOpaque(relativeTo_val, js_zoneddatetime_class_id);
+ if (zdt && s->years == 0 && s->months == 0 && s->weeks == 0 && s->days == 0) {
+ js_int128_t zdt_epoch_ns = ti_timespec_to_ns(&zdt->ts);
+ js_int128_t target_epoch_ns = zdt_epoch_ns + total_ns;
+ js_int128_t limit = (js_int128_t)INSTANT_MAX_SECS * 1000000000LL;
+ if (target_epoch_ns < -limit || target_epoch_ns > limit) {
+ JS_FreeValue(ctx, relativeTo_val);
+ return JS_ThrowRangeError(ctx, "epoch nanoseconds outside valid limits");
+ }
+ }
+ }
+
+ if (unit_enum == TI_UNIT_DAY) {
+ total = duration_total_div(total_ns, 86400000000000ULL);
+ } else if (unit_enum == TI_UNIT_HOUR) {
+ total = duration_total_div(total_ns, 3600000000000ULL);
+ } else if (unit_enum == TI_UNIT_MINUTE) {
+ total = duration_total_div(total_ns, 60000000000ULL);
+ } else if (unit_enum == TI_UNIT_SECOND) {
+ total = duration_total_div(total_ns, 1000000000ULL);
+ } else if (unit_enum == TI_UNIT_MILLISECOND) {
+ total = duration_total_div(total_ns, 1000000ULL);
+ } else if (unit_enum == TI_UNIT_MICROSECOND) {
+ total = duration_total_div(total_ns, 1000ULL);
+ } else if (unit_enum == TI_UNIT_NANOSECOND) {
+ total = (double)total_ns;
+ } else {
+ /* Not a fixed-length time unit, fall through to calendar unit checks */
+ goto calendar_units;
+ }
+
+ JS_FreeValue(ctx, relativeTo_val);
+ return JS_NewFloat64(ctx, total);
+
+calendar_units:
+ if (has_relativeTo && use_iso) {
+ int64_t rel_time_ns = (int64_t)rel_hour * 3600000000000LL
+ + (int64_t)rel_minute * 60000000000LL
+ + (int64_t)rel_second * 1000000000LL
+ + (int64_t)rel_ms * 1000000LL
+ + (int64_t)rel_us * 1000LL
+ + (int64_t)rel_ns;
+ int64_t target_time_ns = (int64_t)th * 3600000000000LL
+ + (int64_t)tmin * 60000000000LL
+ + (int64_t)ts * 1000000000LL
+ + (int64_t)tms * 1000000LL
+ + (int64_t)tus * 1000LL
+ + (int64_t)tns;
+ total = ti_iso_total_in_unit(rel_year, rel_month, rel_day, ty, tm, td, unit_enum, rel_time_ns, target_time_ns);
+ JS_FreeValue(ctx, relativeTo_val);
+ return JS_NewFloat64(ctx, total);
+ }
+
+ goto fail_range;
+
+fail_range:
+ JS_FreeValue(ctx, relativeTo_val);
+ return JS_ThrowRangeError(ctx, "unit out of range");
+fail:
+ JS_FreeValue(ctx, relativeTo_val);
+ return JS_EXCEPTION;
+}
+
+static void duration_balance_subseconds(JSDurationData *d)
+{
+ js_int128_t total_ns;
+ /* Balance nanoseconds -> microseconds -> milliseconds -> seconds only */
+ total_ns = d->nanoseconds.int128_value;
+ d->nanoseconds.int128_value = total_ns % 1000;
+ d->microseconds.int128_value += total_ns / 1000;
+
+ total_ns = d->microseconds.int128_value;
+ d->microseconds.int128_value = total_ns % 1000;
+ d->milliseconds += (int64_t)(total_ns / 1000);
+
+ total_ns = d->milliseconds;
+ d->milliseconds = (int64_t)(total_ns % 1000);
+ d->seconds += (int64_t)(total_ns / 1000);
+}
+
+/* Temporal.Duration.prototype.toString */
+static int duration_sign(const JSDurationData *d)
+{
+ if (d->years < 0) return -1;
+ if (d->years > 0) return 1;
+ if (d->months < 0) return -1;
+ if (d->months > 0) return 1;
+ if (d->weeks < 0) return -1;
+ if (d->weeks > 0) return 1;
+ if (d->days < 0) return -1;
+ if (d->days > 0) return 1;
+ if (d->hours < 0) return -1;
+ if (d->hours > 0) return 1;
+ if (d->minutes < 0) return -1;
+ if (d->minutes > 0) return 1;
+ if (d->seconds < 0) return -1;
+ if (d->seconds > 0) return 1;
+ if (d->milliseconds < 0) return -1;
+ if (d->milliseconds > 0) return 1;
+ if (d->microseconds.int128_value < 0) return -1;
+ if (d->microseconds.int128_value > 0) return 1;
+ if (d->nanoseconds.int128_value < 0) return -1;
+ if (d->nanoseconds.int128_value > 0) return 1;
+ return 0;
+}
+
+static js_int128_t round_int128_to_increment(js_int128_t x, js_int128_t increment, TIRoundingMode mode)
+{
+ js_int128_t q, r, q_euclid, r_euclid, result;
+
+ if (increment == 1)
+ return x;
+
+ q = x / increment;
+ r = x % increment;
+
+ if (r < 0) {
+ q_euclid = q - 1;
+ r_euclid = r + increment;
+ } else {
+ q_euclid = q;
+ r_euclid = r;
+ }
+
+ if (r_euclid == 0)
+ return x;
+
+ switch (mode) {
+ case ROUND_CEIL:
+ result = (q_euclid + 1) * increment;
+ break;
+ case ROUND_FLOOR:
+ result = q_euclid * increment;
+ break;
+ case ROUND_TRUNC:
+ result = (x >= 0 ? q_euclid : (q_euclid + 1)) * increment;
+ break;
+ case ROUND_EXPAND:
+ result = (x >= 0 ? (q_euclid + 1) : q_euclid) * increment;
+ break;
+ case ROUND_HALF_EVEN:
+ if (r_euclid * 2 < increment)
+ result = q_euclid * increment;
+ else if (r_euclid * 2 > increment)
+ result = (q_euclid + 1) * increment;
+ else
+ result = ((q_euclid % 2) == 0) ? q_euclid * increment : (q_euclid + 1) * increment;
+ break;
+ case ROUND_HALF_CEIL:
+ result = (r_euclid * 2 < increment) ? q_euclid * increment : (q_euclid + 1) * increment;
+ break;
+ case ROUND_HALF_FLOOR:
+ result = (r_euclid * 2 <= increment) ? q_euclid * increment : (q_euclid + 1) * increment;
+ break;
+ case ROUND_HALF_EXPAND:
+ result = (r_euclid * 2 < increment) ? q_euclid * increment : (q_euclid + 1) * increment;
+ break;
+ case ROUND_HALF_TRUNC:
+ if (r_euclid * 2 < increment)
+ result = q_euclid * increment;
+ else if (r_euclid * 2 > increment)
+ result = (q_euclid + 1) * increment;
+ else
+ result = (x >= 0 ? q_euclid : (q_euclid + 1)) * increment;
+ break;
+ default:
+ result = x;
+ break;
+ }
+ return result;
+}
+
+static JSValue js_duration_toString(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSDurationData *s;
+ JSDurationData d;
+ DynBuf dbuf;
+ JSValue options = JS_UNDEFINED;
+ int precision = -1; /* -1 = auto, 0-9 = digits */
+ TIRoundingMode roundingMode = ROUND_TRUNC;
+ int has_smallestUnit = 0;
+ TIUnit smallestUnit = TI_UNIT_INVALID;
+ int64_t increment_ns = 1;
+ int needs_rounding = 0;
+ js_int128_t total_ns, rounded_ns;
+
+ s = JS_GetOpaque2(ctx, this_val, js_duration_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+
+ /* Step 3: GetOptionsObject */
+ if (argc >= 1 && !JS_IsUndefined(argv[0])) {
+ if (!JS_IsObject(argv[0]))
+ return JS_ThrowTypeError(ctx, "options must be an object");
+ options = JS_DupValue(ctx, argv[0]);
+ }
+
+ /* Read fractionalSecondDigits */
+ if (!JS_IsUndefined(options)) {
+ if (ti_get_fractional_second_digits_option(ctx, options, &precision) < 0) {
+ JS_FreeValue(ctx, options);
+ return JS_EXCEPTION;
+ }
+ }
+
+ /* Read roundingMode */
+ if (!JS_IsUndefined(options)) {
+ if (ti_get_rounding_mode_option_default(ctx, options, &roundingMode, ROUND_TRUNC) < 0) {
+ JS_FreeValue(ctx, options);
+ return JS_EXCEPTION;
+ }
+ }
+
+ /* Read smallestUnit */
+ if (!JS_IsUndefined(options)) {
+ TIUnit unit;
+ if (ti_parse_unit_option(ctx, options, "smallestUnit", &unit, TI_UNIT_OPT_ALLOW_UNDEFINED, TI_UNIT_INVALID) < 0) {
+ JS_FreeValue(ctx, options);
+ return JS_EXCEPTION;
+ }
+ if (unit != TI_UNIT_INVALID) {
+ smallestUnit = unit;
+ has_smallestUnit = 1;
+ }
+ }
+
+ JS_FreeValue(ctx, options);
+
+ /* Validate smallestUnit */
+ if (has_smallestUnit) {
+ if (smallestUnit == TI_UNIT_INVALID) {
+ return JS_ThrowRangeError(ctx, "invalid smallestUnit");
+ }
+ /* Duration toString: hour and minute are invalid */
+ if (smallestUnit == TI_UNIT_HOUR || smallestUnit == TI_UNIT_MINUTE) {
+ return JS_ThrowRangeError(ctx, "invalid smallestUnit");
+ }
+ /* Must be a time unit (second, ms, us, ns) */
+ if (smallestUnit < TI_UNIT_SECOND || smallestUnit > TI_UNIT_NANOSECOND) {
+ return JS_ThrowRangeError(ctx, "invalid smallestUnit");
+ }
+ /* smallestUnit overrides fractionalSecondDigits */
+ switch (smallestUnit) {
+ case TI_UNIT_SECOND: precision = 0; break;
+ case TI_UNIT_MILLISECOND: precision = 3; break;
+ case TI_UNIT_MICROSECOND: precision = 6; break;
+ case TI_UNIT_NANOSECOND: precision = 9; break;
+ default: break;
+ }
+ }
+
+ /* Compute increment in nanoseconds */
+ if (precision == -1) {
+ increment_ns = 1;
+ } else {
+ static const int64_t inc_table[10] = {
+ 1000000000LL, 100000000LL, 10000000LL, 1000000LL,
+ 100000LL, 10000LL, 1000LL, 100LL, 10LL, 1LL
+ };
+ increment_ns = inc_table[precision];
+ }
+
+ /* Determine if rounding is needed */
+ if (increment_ns == 1) {
+ needs_rounding = 0;
+ } else {
+ needs_rounding = 1;
+ }
+
+ d = *s;
+ duration_round_fields_to_float64(&d);
+ duration_balance_subseconds(&d);
+
+ if (needs_rounding) {
+ /* Convert time components to total nanoseconds */
+ {
+ int64_t total_seconds = d.hours * 3600LL + d.minutes * 60LL + d.seconds;
+ total_ns = (js_int128_t)total_seconds * 1000000000LL;
+ total_ns += (js_int128_t)d.milliseconds * 1000000LL;
+ total_ns += d.microseconds.int128_value * 1000LL;
+ total_ns += d.nanoseconds.int128_value;
+ }
+
+ /* Round to increment */
+ rounded_ns = round_int128_to_increment(total_ns, increment_ns, roundingMode);
+
+ /* Check maxTimeDuration */
+ {
+ const js_int128_t MAX_TIME_DURATION = (((js_int128_t)9007199254740992LL) * 1000000000LL) - 1;
+ if (rounded_ns < 0) {
+ if (-rounded_ns > MAX_TIME_DURATION)
+ return JS_ThrowRangeError(ctx, "rounded duration out of range");
+ } else {
+ if (rounded_ns > MAX_TIME_DURATION)
+ return JS_ThrowRangeError(ctx, "rounded duration out of range");
+ }
+ }
+
+ /* Determine roundedLargestUnit */
+ TIUnit largestUnit = duration_get_largest_unit(&d);
+ TIUnit roundedLargestUnit;
+ if (largestUnit == TI_UNIT_YEAR || largestUnit == TI_UNIT_MONTH ||
+ largestUnit == TI_UNIT_WEEK || largestUnit == TI_UNIT_DAY) {
+ roundedLargestUnit = largestUnit;
+ } else if (largestUnit == TI_UNIT_HOUR) {
+ roundedLargestUnit = TI_UNIT_HOUR;
+ } else if (largestUnit == TI_UNIT_MINUTE) {
+ roundedLargestUnit = TI_UNIT_MINUTE;
+ } else {
+ roundedLargestUnit = TI_UNIT_SECOND;
+ }
+
+ /* Zero out time components and set nanoseconds to rounded value */
+ d.hours = 0;
+ d.minutes = 0;
+ d.seconds = 0;
+ d.milliseconds = 0;
+ d.microseconds.int128_value = 0;
+ d.nanoseconds.int128_value = rounded_ns;
+
+ /* Balance time components up to roundedLargestUnit */
+ ti_balance_time_duration(&d, roundedLargestUnit);
+
+ /* Check if result is out of range */
+ if (duration_is_out_of_range(&d))
+ return JS_ThrowRangeError(ctx, "rounded duration out of range");
+ }
+
+ /* Format using TemporalDurationToString */
+ dbuf_init2(&dbuf, ctx, (DynBufReallocFunc *)js_realloc);
+ if (dbuf_error(&dbuf))
+ return JS_EXCEPTION;
+
+ {
+ int sign = duration_sign(&d);
+ int has_time = 0;
+ char time_buf[256];
+ int time_len = 0;
+
+ /* Compute time part first */
+ if (d.hours != 0) {
+ has_time = 1;
+ time_len += snprintf(time_buf + time_len, sizeof(time_buf) - (size_t)time_len,
+ "%"PRIi64"H", d.hours < 0 ? -d.hours : d.hours);
+ }
+ if (d.minutes != 0) {
+ has_time = 1;
+ time_len += snprintf(time_buf + time_len, sizeof(time_buf) - (size_t)time_len,
+ "%"PRIi64"M", d.minutes < 0 ? -d.minutes : d.minutes);
+ }
+
+ /* Determine zeroMinutesAndHigher */
+ int zeroMinutesAndHigher = 0;
+ TIUnit defaultLargestUnit = duration_get_largest_unit(&d);
+ if (defaultLargestUnit == TI_UNIT_SECOND || defaultLargestUnit == TI_UNIT_MILLISECOND ||
+ defaultLargestUnit == TI_UNIT_MICROSECOND || defaultLargestUnit == TI_UNIT_NANOSECOND) {
+ zeroMinutesAndHigher = 1;
+ }
+
+ /* secondsDuration = time components from seconds down */
+ js_int128_t secondsDuration = (js_int128_t)d.seconds * 1000000000LL +
+ (js_int128_t)d.milliseconds * 1000000LL +
+ d.microseconds.int128_value * 1000LL +
+ d.nanoseconds.int128_value;
+
+ if (secondsDuration != 0 || zeroMinutesAndHigher || precision != -1) {
+ has_time = 1;
+ js_int128_t sec128 = secondsDuration / 1000000000LL;
+ if (sec128 < 0) sec128 = -sec128;
+ int64_t sec = (int64_t)sec128;
+
+ js_int128_t subsec128 = secondsDuration % 1000000000LL;
+ if (subsec128 < 0) subsec128 = -subsec128;
+ int64_t subsec_ns = (int64_t)subsec128;
+
+ time_len += snprintf(time_buf + time_len, sizeof(time_buf) - (size_t)time_len,
+ "%"PRIi64, sec);
+
+ /* FormatFractionalSeconds */
+ if (precision == -1) {
+ /* auto */
+ if (subsec_ns != 0) {
+ char frac[16];
+ snprintf(frac, sizeof(frac), "%09"PRIi64, subsec_ns);
+ int frac_len = 9;
+ while (frac_len > 0 && frac[frac_len - 1] == '0')
+ frac_len--;
+ frac[frac_len] = '\0';
+ time_len += snprintf(time_buf + time_len, sizeof(time_buf) - (size_t)time_len,
+ ".%s", frac);
+ }
+ } else if (precision > 0) {
+ char frac[16];
+ snprintf(frac, sizeof(frac), "%09"PRIi64, subsec_ns);
+ frac[precision] = '\0';
+ time_len += snprintf(time_buf + time_len, sizeof(time_buf) - (size_t)time_len,
+ ".%s", frac);
+ }
+ time_len += snprintf(time_buf + time_len, sizeof(time_buf) - (size_t)time_len, "S");
+ }
+
+ /* Output sign and date part */
+ if (sign < 0)
+ dbuf_putstr(&dbuf, "-");
+ dbuf_putstr(&dbuf, "P");
+
+ if (d.years != 0)
+ dbuf_printf(&dbuf, "%"PRIi64"Y", d.years < 0 ? -d.years : d.years);
+ if (d.months != 0)
+ dbuf_printf(&dbuf, "%"PRIi64"M", d.months < 0 ? -d.months : d.months);
+ if (d.weeks != 0)
+ dbuf_printf(&dbuf, "%"PRIi64"W", d.weeks < 0 ? -d.weeks : d.weeks);
+ if (d.days != 0)
+ dbuf_printf(&dbuf, "%"PRIi64"D", d.days < 0 ? -d.days : d.days);
+
+ if (has_time) {
+ dbuf_putstr(&dbuf, "T");
+ dbuf_putstr(&dbuf, time_buf);
+ }
+ }
+
+ dbuf_putc(&dbuf, '\0');
+ if (dbuf_error(&dbuf)) {
+ dbuf_free(&dbuf);
+ return JS_ThrowOutOfMemory(ctx);
+ }
+ {
+ JSValue ret = JS_NewString(ctx, (const char *)dbuf.buf);
+ dbuf_free(&dbuf);
+ return ret;
+ }
+}
+static JSValue js_duration_toJSON(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ (void)argc;
+ (void)argv;
+ return js_duration_toString(ctx, this_val, 0, NULL);
+}
+
+static JSValue js_duration_toLocaleString(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSDurationData *s;
+ JSValue df_ctor, df_obj, result;
+ JSValue args[2];
+ int i;
+
+ s = JS_GetOpaque2(ctx, this_val, js_duration_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+
+ df_ctor = JS_GetContextValue(ctx, JS_INTL_CTOR_DURATIONFORMAT);
+
+ for (i = 0; i < argc && i < 2; i++)
+ args[i] = argv[i];
+ for (; i < 2; i++)
+ args[i] = JS_UNDEFINED;
+
+ df_obj = JS_CallConstructor(ctx, df_ctor, argc, args);
+ JS_FreeValue(ctx, df_ctor);
+ if (JS_IsException(df_obj))
+ return JS_EXCEPTION;
+
+ {
+ JSValue format_fn = JS_GetPropertyStr(ctx, df_obj, "format");
+ if (JS_IsException(format_fn)) {
+ JS_FreeValue(ctx, format_fn);
+ JS_FreeValue(ctx, df_obj);
+ return JS_EXCEPTION;
+ }
+ JSValue dur = JS_DupValue(ctx, this_val);
+ result = JS_Call(ctx, format_fn, df_obj, 1, &dur);
+ JS_FreeValue(ctx, format_fn);
+ JS_FreeValue(ctx, dur);
+ }
+ JS_FreeValue(ctx, df_obj);
+ return result;
+}
+
+static int64_t ti_unit_to_nanoseconds(TIUnit unit)
+{
+ switch (unit) {
+ case TI_UNIT_DAY: return 86400000000000LL;
+ case TI_UNIT_HOUR: return 3600000000000LL;
+ case TI_UNIT_MINUTE: return 60000000000LL;
+ case TI_UNIT_SECOND: return 1000000000LL;
+ case TI_UNIT_MILLISECOND: return 1000000LL;
+ case TI_UNIT_MICROSECOND: return 1000LL;
+ case TI_UNIT_NANOSECOND: return 1LL;
+ default: return 0;
+ }
+}
+
+static JSValue js_duration_round(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ (void)argc;
+ JSDurationData *s;
+ JSValue options, relativeTo_val = JS_UNDEFINED;
+ const char *smallestUnit = NULL;
+ TIRoundingMode mode = ROUND_HALF_EXPAND;
+ int64_t roundingIncrement = 1;
+ TIUnit unit = TI_UNIT_INVALID;
+ js_int128_t total_ns, rounded_ns, unit_ns, inc_ns, day_time_ns;
+ int64_t time_ns;
+ JSDurationData result = {0};
+ int has_relativeTo = 0;
+ TIUnit largestUnit = TI_UNIT_INVALID;
+
+ s = JS_GetOpaque2(ctx, this_val, js_duration_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+
+ if (JS_IsUndefined(argv[0]))
+ return JS_ThrowTypeError(ctx, "roundTo is required");
+
+ if (JS_IsString(argv[0])) {
+ /* If argument is a string, use it as smallestUnit */
+ size_t su_len;
+ smallestUnit = JS_ToCStringLen(ctx, &su_len, argv[0]);
+ if (!smallestUnit)
+ return JS_EXCEPTION;
+ options = JS_NewObjectProto(ctx, JS_NULL);
+ if (JS_IsException(options)) {
+ JS_FreeCString(ctx, smallestUnit);
+ return JS_EXCEPTION;
+ }
+ {
+ JSValue su_str = JS_NewStringLen(ctx, smallestUnit, su_len);
+ JS_FreeCString(ctx, smallestUnit);
+ if (JS_IsException(su_str)) {
+ JS_FreeValue(ctx, options);
+ return JS_EXCEPTION;
+ }
+ if (JS_SetPropertyStr(ctx, options, "smallestUnit", su_str) < 0) {
+ JS_FreeValue(ctx, options);
+ return JS_EXCEPTION;
+ }
+ }
+ } else if (JS_IsObject(argv[0])) {
+ options = JS_ToObject(ctx, argv[0]);
+ if (JS_IsException(options))
+ return JS_EXCEPTION;
+ } else {
+ return JS_ThrowTypeError(ctx, "roundTo must be a string or object");
+ }
+
+ {
+ int has_smallest_unit = 0, has_largest_unit = 0;
+ if (ti_parse_unit_option(ctx, options, "largestUnit", &largestUnit, TI_UNIT_OPT_ALLOW_UNDEFINED | TI_UNIT_OPT_ALLOW_AUTO, TI_UNIT_INVALID) < 0) {
+ JS_FreeValue(ctx, options);
+ JS_FreeValue(ctx, relativeTo_val);
+ return JS_EXCEPTION;
+ }
+ has_largest_unit = (largestUnit != TI_UNIT_INVALID);
+
+ /* Read and validate relativeTo */
+ {
+ JSValue rt = JS_GetPropertyStr(ctx, options, "relativeTo");
+ if (JS_IsException(rt)) {
+ JS_FreeValue(ctx, options);
+ JS_FreeValue(ctx, relativeTo_val);
+ return JS_EXCEPTION;
+ }
+ if (!JS_IsUndefined(rt)) {
+ has_relativeTo = 1;
+ if (JS_IsString(rt)) {
+ const char *rt_str = JS_ToCString(ctx, rt);
+ if (!rt_str) {
+ JS_FreeValue(ctx, rt);
+ JS_FreeValue(ctx, options);
+ JS_FreeValue(ctx, relativeTo_val);
+ return JS_EXCEPTION;
+ }
+ if (ti_is_minus_zero_year(rt_str)) {
+ JS_FreeCString(ctx, rt_str);
+ JS_FreeValue(ctx, rt);
+ JS_FreeValue(ctx, options);
+ JS_FreeValue(ctx, relativeTo_val);
+ return JS_ThrowRangeError(ctx, "minus zero year is not allowed");
+ }
+ JS_FreeValue(ctx, rt);
+ rt = ti_to_temporal_relative_to_string(ctx, rt_str);
+ JS_FreeCString(ctx, rt_str);
+ if (JS_IsException(rt)) {
+ JS_FreeValue(ctx, options);
+ JS_FreeValue(ctx, relativeTo_val);
+ return JS_EXCEPTION;
+ }
+ relativeTo_val = rt;
+ } else if (JS_IsObject(rt)) {
+ JSPlainDateTimeData *pdt = JS_GetOpaque(rt, js_plaindatetime_class_id);
+ if (pdt && (pdt->calendar == CAL_ISO8601 || pdt->calendar == CAL_GREGORY)) {
+ JSValue plainDate = js_create_plaindate(ctx, pdt->year, pdt->month, pdt->day);
+ JS_FreeValue(ctx, rt);
+ rt = plainDate;
+ if (JS_IsException(rt)) {
+ JS_FreeValue(ctx, options);
+ JS_FreeValue(ctx, relativeTo_val);
+ return JS_EXCEPTION;
+ }
+ }
+ if (!JS_GetOpaque(rt, js_zoneddatetime_class_id) &&
+ !JS_GetOpaque(rt, js_plaindate_class_id) &&
+ !JS_GetOpaque(rt, js_plaindatetime_class_id)) {
+ JSValue converted = ti_convert_relative_to_property_bag(ctx, rt);
+ JS_FreeValue(ctx, rt);
+ rt = converted;
+ if (JS_IsException(rt)) {
+ JS_FreeValue(ctx, options);
+ JS_FreeValue(ctx, relativeTo_val);
+ return JS_EXCEPTION;
+ }
+ }
+ relativeTo_val = rt;
+ } else {
+ JS_FreeValue(ctx, rt);
+ JS_FreeValue(ctx, options);
+ JS_FreeValue(ctx, relativeTo_val);
+ return JS_ThrowTypeError(ctx, "invalid relativeTo");
+ }
+ } else {
+ JS_FreeValue(ctx, rt);
+ }
+ }
+
+ if (ti_get_rounding_increment_option(ctx, options, &roundingIncrement) < 0) {
+ JS_FreeValue(ctx, options);
+ JS_FreeValue(ctx, relativeTo_val);
+ return JS_EXCEPTION;
+ }
+
+ /* Read roundingMode */
+ if (ti_get_rounding_mode_option(ctx, options, &mode) < 0) {
+ JS_FreeValue(ctx, options);
+ JS_FreeValue(ctx, relativeTo_val);
+ return JS_EXCEPTION;
+ }
+
+ if (ti_parse_unit_option(ctx, options, "smallestUnit", &unit, TI_UNIT_OPT_ALLOW_UNDEFINED, TI_UNIT_INVALID) < 0) {
+ JS_FreeValue(ctx, options);
+ JS_FreeValue(ctx, relativeTo_val);
+ return JS_EXCEPTION;
+ }
+ if (unit != TI_UNIT_INVALID)
+ has_smallest_unit = 1;
+
+ if (!has_smallest_unit && !has_largest_unit) {
+ JS_FreeValue(ctx, options);
+ JS_FreeValue(ctx, relativeTo_val);
+ return JS_ThrowRangeError(ctx, "smallestUnit or largestUnit is required");
+ }
+ if (!has_smallest_unit) {
+ unit = TI_UNIT_NANOSECOND;
+ }
+ }
+
+ JS_FreeValue(ctx, options);
+
+ /* Compute existing largest unit and default largestUnit if not provided */
+ {
+ TIUnit existingLargestUnit = duration_get_largest_unit(s);
+ if (largestUnit == TI_UNIT_INVALID || largestUnit == TI_UNIT_AUTO) {
+ largestUnit = (existingLargestUnit < unit) ? existingLargestUnit : unit;
+ }
+ if (!has_relativeTo) {
+ if (existingLargestUnit <= TI_UNIT_WEEK || largestUnit <= TI_UNIT_WEEK) {
+ JS_FreeValue(ctx, relativeTo_val);
+ return JS_ThrowRangeError(ctx, "a starting point is required for durations with calendar units");
+ }
+ }
+ }
+ /* Validate largestUnit >= smallestUnit (smallestUnit must not be larger than largestUnit) */
+ if (unit < largestUnit) {
+ JS_FreeValue(ctx, relativeTo_val);
+ return JS_ThrowRangeError(ctx, "smallestUnit must not be larger than largestUnit");
+ }
+ /* Validate roundingIncrement */
+ {
+ int64_t maximum = 0;
+ if (unit == TI_UNIT_HOUR) {
+ maximum = 24;
+ } else if (unit == TI_UNIT_MINUTE || unit == TI_UNIT_SECOND) {
+ maximum = 60;
+ } else if (unit == TI_UNIT_MILLISECOND || unit == TI_UNIT_MICROSECOND || unit == TI_UNIT_NANOSECOND) {
+ maximum = 1000;
+ }
+ if (maximum > 0 && (roundingIncrement >= maximum || maximum % roundingIncrement != 0)) {
+ JS_FreeValue(ctx, relativeTo_val);
+ return JS_ThrowRangeError(ctx, "invalid roundingIncrement");
+ }
+ /* Calendar units with roundingIncrement > 1 require largestUnit == smallestUnit */
+ if (roundingIncrement > 1 && unit <= TI_UNIT_DAY && unit != largestUnit) {
+ JS_FreeValue(ctx, relativeTo_val);
+ return JS_ThrowRangeError(ctx, "invalid roundingIncrement");
+ }
+ }
+
+ {
+ int use_iso_rounding = 0;
+ int has_timeZone = 0;
+ int has_calendar_units = duration_has_calendar_units(s) || s->days != 0;
+ int is_calendar_unit = (largestUnit >= TI_UNIT_YEAR && largestUnit <= TI_UNIT_DAY);
+ int rel_year = 0, rel_month = 0, rel_day = 0;
+ int rel_hour = 0, rel_minute = 0, rel_second = 0;
+ int rel_ms = 0, rel_us = 0, rel_ns = 0;
+
+ if (JS_IsObject(relativeTo_val)) {
+ JSPlainDateData *pd = JS_GetOpaque(relativeTo_val, js_plaindate_class_id);
+ if (pd && (pd->calendar == CAL_ISO8601 || pd->calendar == CAL_GREGORY)) {
+ rel_year = pd->year;
+ rel_month = pd->month;
+ rel_day = pd->day;
+ use_iso_rounding = 1;
+ } else {
+ JSPlainDateTimeData *pdt = JS_GetOpaque(relativeTo_val, js_plaindatetime_class_id);
+ if (pdt && (pdt->calendar == CAL_ISO8601 || pdt->calendar == CAL_GREGORY)) {
+ rel_year = pdt->year;
+ rel_month = pdt->month;
+ rel_day = pdt->day;
+ rel_hour = pdt->hour;
+ rel_minute = pdt->minute;
+ rel_second = pdt->second;
+ rel_ms = pdt->millisecond;
+ rel_us = pdt->microsecond;
+ rel_ns = pdt->nanosecond;
+ use_iso_rounding = 1;
+ } else {
+ JSZonedDateTimeData *zdt = JS_GetOpaque(relativeTo_val, js_zoneddatetime_class_id);
+ if (zdt && (zdt->calendar == CAL_ISO8601 || zdt->calendar == CAL_GREGORY)) {
+ int64_t offset_sec = 0;
+ int tz_id = ti_tz_find_id(zdt->timeZone);
+ if (tz_id >= 0) {
+ offset_sec = ti_tz_offset_at_sec(tz_id, zdt->ts.secs);
+ } else {
+ int64_t offset_ns = 0;
+ int ret = ti_parse_temporal_timezone_string(zdt->timeZone, &offset_ns);
+ if (ret >= 0)
+ offset_sec = offset_ns / 1000000000LL;
+ }
+ int64_t local_sec = zdt->ts.secs + offset_sec;
+ int local_nsec = (int)zdt->ts.nsecs;
+ if (local_nsec >= 1000000000) {
+ local_sec += 1;
+ local_nsec -= 1000000000;
+ } else if (local_nsec < 0) {
+ local_sec -= 1;
+ local_nsec += 1000000000;
+ }
+ {
+ int64_t year64;
+ ti_epoch_sec_to_date(local_sec, &year64, &rel_month, &rel_day, &rel_hour, &rel_minute, &rel_second);
+ rel_year = (int)year64;
+ }
+ rel_ms = local_nsec / 1000000;
+ rel_us = (local_nsec / 1000) % 1000;
+ rel_ns = local_nsec % 1000;
+ use_iso_rounding = 1;
+ has_timeZone = 1;
+ }
+ }
+ }
+ }
+
+ if (use_iso_rounding) {
+ /* Zero duration with ISO relativeTo: return zero immediately.
+ This matches the spec's early return in
+ DifferencePlainDateTimeWithRounding/DifferencePlainDateTimeWithTotal.
+ For ZonedDateTime, NudgeToZonedTime always runs and may throw
+ when the next day boundary is out of range. */
+ if (s->years == 0 && s->months == 0 && s->weeks == 0 && s->days == 0 &&
+ s->hours == 0 && s->minutes == 0 && s->seconds == 0 &&
+ s->milliseconds == 0 && s->microseconds.int128_value == 0 && s->nanoseconds.int128_value == 0) {
+ /* Only check day boundary for ZonedDateTime when RoundRelativeDuration
+ would be called (largestUnit is date and smallestUnit is not the
+ default nanosecond/1 early-return case). */
+ if (has_timeZone && is_calendar_unit && (unit != TI_UNIT_NANOSECOND || roundingIncrement != 1)) {
+ JSZonedDateTimeData *zdt = JS_GetOpaque(relativeTo_val, js_zoneddatetime_class_id);
+ if (zdt && !ti_zoneddatetime_day_boundary_in_range(zdt, 1)) {
+ JS_FreeValue(ctx, relativeTo_val);
+ return JS_ThrowRangeError(ctx, "relativeTo outside valid instant range");
+ }
+ }
+ JS_FreeValue(ctx, relativeTo_val);
+ return js_create_duration(ctx, s);
+ }
+
+ /* ZonedDateTime-specific path for ISO-like calendars */
+ if (has_timeZone) {
+ JSZonedDateTimeData *zdt = JS_GetOpaque(relativeTo_val, js_zoneddatetime_class_id);
+ if (zdt) {
+ JSTimeSpec origin = zdt->ts;
+ JSTimeSpec target;
+ JSDurationData add_d = *s;
+ if (ti_zoneddatetime_add_duration_iso(zdt->timeZone, zdt->calendar, origin, &add_d, 1, &target) < 0) {
+ JS_FreeValue(ctx, relativeTo_val);
+ return JS_ThrowRangeError(ctx, "round result outside valid range");
+ }
+
+ TIUnit effective_largest = largestUnit;
+ if (effective_largest == TI_UNIT_INVALID) {
+ if (s->years != 0) effective_largest = TI_UNIT_YEAR;
+ else if (s->months != 0) effective_largest = TI_UNIT_MONTH;
+ else if (s->weeks != 0) effective_largest = TI_UNIT_WEEK;
+ else if (s->days != 0) effective_largest = TI_UNIT_DAY;
+ else if (s->hours != 0) effective_largest = TI_UNIT_HOUR;
+ else if (s->minutes != 0) effective_largest = TI_UNIT_MINUTE;
+ else if (s->seconds != 0) effective_largest = TI_UNIT_SECOND;
+ else if (s->milliseconds != 0) effective_largest = TI_UNIT_MILLISECOND;
+ else if (s->microseconds.int128_value != 0) effective_largest = TI_UNIT_MICROSECOND;
+ else effective_largest = TI_UNIT_NANOSECOND;
+ }
+
+ /* No rounding requested: return exact difference */
+ if (unit == TI_UNIT_NANOSECOND && roundingIncrement == 1) {
+ if (effective_largest >= TI_UNIT_YEAR && effective_largest <= TI_UNIT_DAY) {
+ JSDurationData diff;
+ if (ti_zoneddatetime_difference_iso(zdt->timeZone, zdt->calendar, origin, target, effective_largest, &diff) < 0) {
+ JS_FreeValue(ctx, relativeTo_val);
+ return JS_ThrowRangeError(ctx, "round result outside valid range");
+ }
+ JS_FreeValue(ctx, relativeTo_val);
+ return js_create_duration(ctx, &diff);
+ } else {
+ js_int128_t pdt_total_ns = ti_timespec_to_ns(&target)
+ - (ti_timespec_to_ns(&origin));
+ JSDurationData pdt_diff;
+ duration_format_time_ns(pdt_total_ns, effective_largest, &pdt_diff);
+ JS_FreeValue(ctx, relativeTo_val);
+ return js_create_duration(ctx, &pdt_diff);
+ }
+ }
+
+ if (effective_largest >= TI_UNIT_YEAR && effective_largest <= TI_UNIT_DAY) {
+ /* Date largestUnit */
+ JSDurationData diff;
+ if (ti_zoneddatetime_difference_iso(zdt->timeZone, zdt->calendar, origin, target, effective_largest, &diff) < 0) {
+ JS_FreeValue(ctx, relativeTo_val);
+ return JS_ThrowRangeError(ctx, "round result outside valid range");
+ }
+ if (unit >= TI_UNIT_YEAR && unit <= TI_UNIT_DAY) {
+ /* Calendar unit rounding using NudgeToCalendarUnit */
+ double total;
+ if (duration_total_nudge(zdt->timeZone, zdt->calendar, origin, target, &diff, unit, &total) < 0) {
+ JS_FreeValue(ctx, relativeTo_val);
+ return JS_ThrowRangeError(ctx, "round result outside valid range");
+ }
+ double q = total / (double)roundingIncrement;
+ double rounded_q;
+ switch (mode) {
+ case ROUND_CEIL: rounded_q = ceil(q); break;
+ case ROUND_FLOOR: rounded_q = floor(q); break;
+ case ROUND_EXPAND: rounded_q = (q >= 0) ? ceil(q) : floor(q); break;
+ case ROUND_TRUNC: rounded_q = (q >= 0) ? floor(q) : ceil(q); break;
+ case ROUND_HALF_CEIL: rounded_q = floor(q + 0.5); break;
+ case ROUND_HALF_FLOOR: rounded_q = ceil(q - 0.5); break;
+ case ROUND_HALF_TRUNC: rounded_q = (q >= 0) ? ceil(q - 0.5) : floor(q + 0.5); break;
+ case ROUND_HALF_EXPAND: default: rounded_q = (q >= 0) ? floor(q + 0.5) : ceil(q - 0.5); break;
+ }
+ int rounded_units = (int)(rounded_q * (double)roundingIncrement);
+ JSDurationData new_d = diff;
+ switch (unit) {
+ case TI_UNIT_YEAR:
+ new_d.years = rounded_units;
+ new_d.months = 0;
+ new_d.weeks = 0;
+ new_d.days = 0;
+ break;
+ case TI_UNIT_MONTH:
+ new_d.months = rounded_units;
+ new_d.weeks = 0;
+ new_d.days = 0;
+ break;
+ case TI_UNIT_WEEK:
+ new_d.weeks = rounded_units;
+ new_d.days = 0;
+ break;
+ case TI_UNIT_DAY:
+ new_d.days = rounded_units;
+ break;
+ default:
+ break;
+ }
+ new_d.hours = 0;
+ new_d.minutes = 0;
+ new_d.seconds = 0;
+ new_d.milliseconds = 0;
+ new_d.microseconds.int128_value = 0;
+ new_d.nanoseconds.int128_value = 0;
+ JS_FreeValue(ctx, relativeTo_val);
+ return js_create_duration(ctx, &new_d);
+ } else {
+ /* Time unit rounding using NudgeToZonedTime */
+ JSDurationData zdt_time_diff;
+ if (ti_zoneddatetime_difference_iso(zdt->timeZone, zdt->calendar, origin, target, effective_largest, &zdt_time_diff) < 0) {
+ JS_FreeValue(ctx, relativeTo_val);
+ return JS_ThrowRangeError(ctx, "round result outside valid range");
+ }
+ {
+ int64_t total_seconds = zdt_time_diff.hours * 3600LL + zdt_time_diff.minutes * 60LL + zdt_time_diff.seconds;
+ time_ns = total_seconds * 1000000000LL
+ + diff.milliseconds * 1000000LL
+ + (int64_t)diff.microseconds.int128_value * 1000LL
+ + (int64_t)diff.nanoseconds.int128_value;
+ }
+ if (time_ns == 0) {
+ JS_FreeValue(ctx, relativeTo_val);
+ return js_create_duration(ctx, &diff);
+ }
+ int sign = duration_sign(&diff);
+ if (sign == 0) sign = 1;
+ /* Get origin local time */
+ int tz_id = ti_tz_find_id(zdt->timeZone);
+ int64_t origin_local_sec;
+ if (tz_id >= 0) {
+ int offset_sec = ti_tz_offset_at_sec(tz_id, origin.secs);
+ origin_local_sec = origin.secs + offset_sec;
+ } else {
+ int64_t offset_ns = 0;
+ ti_parse_temporal_timezone_string(zdt->timeZone, &offset_ns);
+ origin_local_sec = origin.secs + offset_ns / 1000000000LL;
+ }
+ int64_t origin_y64;
+ int origin_m, origin_d, origin_h, origin_min, origin_sec;
+ ti_epoch_sec_to_date(origin_local_sec, &origin_y64, &origin_m, &origin_d, &origin_h, &origin_min, &origin_sec);
+ /* startDate = originLocalDate + diff.date */
+ int start_y, start_m, start_d;
+ ti_iso_calendar_date_add((int)origin_y64, origin_m, origin_d,
+ diff.years, diff.months, diff.weeks, diff.days,
+ &start_y, &start_m, &start_d);
+ int64_t start_days = pdt_to_ordinal_days(start_y, start_m, start_d);
+ int64_t end_days = start_days + sign;
+ int64_t start_local_sec = (start_days - 719162) * 86400LL
+ + origin_h * 3600LL + origin_min * 60LL + origin_sec;
+ int64_t end_local_sec = (end_days - 719162) * 86400LL
+ + origin_h * 3600LL + origin_min * 60LL + origin_sec;
+ int64_t start_epoch_sec, end_epoch_sec;
+ if (tz_id >= 0) {
+ int offset_sec;
+ ti_tz_local_to_utc(tz_id, start_local_sec, 2, &start_epoch_sec, &offset_sec);
+ ti_tz_local_to_utc(tz_id, end_local_sec, 2, &end_epoch_sec, &offset_sec);
+ } else {
+ int64_t offset_ns = 0;
+ ti_parse_temporal_timezone_string(zdt->timeZone, &offset_ns);
+ int64_t offset_sec = offset_ns / 1000000000LL;
+ start_epoch_sec = start_local_sec - offset_sec;
+ end_epoch_sec = end_local_sec - offset_sec;
+ }
+ int64_t daySpan = (end_epoch_sec - start_epoch_sec) * 1000000000LL;
+ js_int128_t round_unit_ns = ti_unit_to_nanoseconds(unit);
+ js_int128_t round_inc_ns = round_unit_ns * roundingIncrement;
+ js_int128_t rounded_time_ns = ti_round_to_increment128(time_ns, round_inc_ns, mode);
+ js_int128_t beyond_day_span = rounded_time_ns - daySpan;
+ int beyond_sign = (beyond_day_span < 0) ? -1 : (beyond_day_span > 0) ? 1 : 0;
+ int didRoundBeyondDay = (beyond_sign != -sign);
+ JSDurationData round_result = diff;
+ if (didRoundBeyondDay) {
+ js_int128_t remainder_ns = ti_round_to_increment128(beyond_day_span, round_inc_ns, mode);
+ round_result.days += sign;
+ int rsign = (remainder_ns < 0) ? -1 : 1;
+ int64_t abs_ns = (int64_t)(remainder_ns >= 0 ? remainder_ns : -remainder_ns);
+ int64_t total_seconds = abs_ns / 1000000000LL;
+ int64_t ns = abs_ns % 1000000000LL;
+ int64_t total_minutes = total_seconds / 60;
+ int64_t seconds = total_seconds % 60;
+ int64_t total_hours = total_minutes / 60;
+ int64_t minutes = total_minutes % 60;
+ int64_t hours = total_hours;
+ round_result.hours = rsign * hours;
+ round_result.minutes = rsign * minutes;
+ round_result.seconds = rsign * seconds;
+ round_result.milliseconds = rsign * (ns / 1000000LL);
+ ns %= 1000000LL;
+ round_result.microseconds.int128_value = rsign * (ns / 1000LL);
+ round_result.nanoseconds.int128_value = rsign * (ns % 1000LL);
+ } else {
+ int rsign = (rounded_time_ns < 0) ? -1 : 1;
+ int64_t abs_ns = (int64_t)(rounded_time_ns >= 0 ? rounded_time_ns : -rounded_time_ns);
+ int64_t total_seconds = abs_ns / 1000000000LL;
+ int64_t ns = abs_ns % 1000000000LL;
+ int64_t total_minutes = total_seconds / 60;
+ int64_t seconds = total_seconds % 60;
+ int64_t total_hours = total_minutes / 60;
+ int64_t minutes = total_minutes % 60;
+ int64_t hours = total_hours;
+ round_result.hours = rsign * hours;
+ round_result.minutes = rsign * minutes;
+ round_result.seconds = rsign * seconds;
+ round_result.milliseconds = rsign * (ns / 1000000LL);
+ ns %= 1000000LL;
+ round_result.microseconds.int128_value = rsign * (ns / 1000LL);
+ round_result.nanoseconds.int128_value = rsign * (ns % 1000LL);
+ }
+ JS_FreeValue(ctx, relativeTo_val);
+ return js_create_duration(ctx, &round_result);
+ }
+ } else {
+ /* Time largestUnit: use DifferenceInstant-style rounding */
+ js_int128_t inst_total_ns = ti_timespec_to_ns(&target)
+ - (ti_timespec_to_ns(&origin));
+ js_int128_t inst_unit_ns = ti_unit_to_nanoseconds(unit);
+ js_int128_t inst_inc_ns = inst_unit_ns * roundingIncrement;
+ js_int128_t inst_rounded_ns = ti_round_to_increment128(inst_total_ns, inst_inc_ns, mode);
+ JSDurationData inst_diff;
+ duration_format_time_ns(inst_rounded_ns, effective_largest, &inst_diff);
+ JS_FreeValue(ctx, relativeTo_val);
+ return js_create_duration(ctx, &inst_diff);
+ }
+ }
+ }
+
+ if (has_calendar_units || is_calendar_unit) {
+ /* Calendar unit rounding with ISO relativeTo.
+ Compute diff = (relativeTo + duration) - relativeTo,
+ then round diff using RoundRelativeDuration. */
+ int ty, tm, td, th, tmin, ts, tms, tus, tns;
+ js_int128_t us_val = s->microseconds.int128_value;
+ js_int128_t ns_val = s->nanoseconds.int128_value;
+ if (ti_iso_datetime_add_duration(
+ rel_year, rel_month, rel_day, rel_hour, rel_minute, rel_second, rel_ms, rel_us, rel_ns,
+ s->years, s->months, s->weeks, s->days,
+ s->hours, s->minutes, s->seconds, s->milliseconds, us_val, ns_val,
+ &ty, &tm, &td, &th, &tmin, &ts, &tms, &tus, &tns) < 0) {
+ JS_FreeValue(ctx, relativeTo_val);
+ return JS_ThrowRangeError(ctx, "rounded date outside valid ISO range");
+ }
+ if (!ti_is_date_within_iso_limits(ty, tm, td)) {
+ JS_FreeValue(ctx, relativeTo_val);
+ return JS_ThrowRangeError(ctx, "rounded date outside valid ISO range");
+ }
+ if (!has_timeZone) {
+ if (!pdt_is_within_limits(rel_year, rel_month, rel_day, rel_hour, rel_minute, rel_second, rel_ms, rel_us, rel_ns) ||
+ !pdt_is_within_limits(ty, tm, td, th, tmin, ts, tms, tus, tns)) {
+ JS_FreeValue(ctx, relativeTo_val);
+ return JS_ThrowRangeError(ctx, "relativeTo outside valid ISO range");
+ }
+ }
+
+ JSDurationData diff;
+ memset(&diff, 0, sizeof(diff));
+ if (ti_iso_datetime_difference(
+ rel_year, rel_month, rel_day, rel_hour, rel_minute, rel_second, rel_ms, rel_us, rel_ns,
+ ty, tm, td, th, tmin, ts, tms, tus, tns,
+ largestUnit,
+ &diff) < 0) {
+ JS_FreeValue(ctx, relativeTo_val);
+ return JS_EXCEPTION;
+ }
+
+ JSDurationData out;
+ memset(&out, 0, sizeof(out));
+ if (ti_round_relative_duration_iso(ctx,
+ rel_year, rel_month, rel_day,
+ rel_hour, rel_minute, rel_second, rel_ms, rel_us, rel_ns,
+ &diff, largestUnit, unit,
+ roundingIncrement, mode,
+ has_timeZone, &out) < 0) {
+ JS_FreeValue(ctx, relativeTo_val);
+ return JS_EXCEPTION;
+ }
+ memset(&result, 0, sizeof(result));
+ result.years = out.years;
+ result.months = out.months;
+ result.weeks = out.weeks;
+ result.days = out.days;
+ result.hours = out.hours;
+ result.minutes = out.minutes;
+ result.seconds = out.seconds;
+ result.milliseconds = out.milliseconds;
+ result.microseconds.int128_value = out.microseconds.int128_value;
+ result.nanoseconds.int128_value = out.nanoseconds.int128_value;
+ } else {
+ if (!has_timeZone) {
+ int ty, tm, td, th, tmin, ts, tms, tus, tns;
+ if (ti_iso_datetime_add_duration(
+ rel_year, rel_month, rel_day, rel_hour, rel_minute, rel_second, rel_ms, rel_us, rel_ns,
+ 0, 0, 0, 0,
+ s->hours, s->minutes, s->seconds, s->milliseconds,
+ s->microseconds.int128_value, s->nanoseconds.int128_value,
+ &ty, &tm, &td, &th, &tmin, &ts, &tms, &tus, &tns) < 0) {
+ JS_FreeValue(ctx, relativeTo_val);
+ return JS_ThrowRangeError(ctx, "relativeTo outside valid ISO range");
+ }
+ if (!pdt_is_within_limits(rel_year, rel_month, rel_day, rel_hour, rel_minute, rel_second, rel_ms, rel_us, rel_ns) ||
+ !pdt_is_within_limits(ty, tm, td, th, tmin, ts, tms, tus, tns)) {
+ JS_FreeValue(ctx, relativeTo_val);
+ return JS_ThrowRangeError(ctx, "relativeTo outside valid ISO range");
+ }
+ } else {
+ JSZonedDateTimeData *zdt = JS_GetOpaque(relativeTo_val, js_zoneddatetime_class_id);
+ if (zdt) {
+ js_int128_t zdt_epoch_ns = ti_timespec_to_ns(&zdt->ts);
+ {
+ int64_t total_seconds = s->days * 86400LL +
+ s->hours * 3600LL +
+ s->minutes * 60LL +
+ s->seconds;
+ js_int128_t duration_ns = (js_int128_t)total_seconds * 1000000000LL +
+ (js_int128_t)s->milliseconds * 1000000LL +
+ s->microseconds.int128_value * 1000LL +
+ s->nanoseconds.int128_value;
+ js_int128_t target_epoch_ns = zdt_epoch_ns + duration_ns;
+ js_int128_t limit = (js_int128_t)INSTANT_MAX_SECS * 1000000000LL;
+ if (target_epoch_ns < -limit || target_epoch_ns > limit) {
+ JS_FreeValue(ctx, relativeTo_val);
+ JS_FreeValue(ctx, relativeTo_val);
+ return JS_ThrowRangeError(ctx, "relativeTo outside valid instant range");
+ }
+ }
+ }
+ }
+ /* Time unit rounding with ISO relativeTo.
+ Place the rounded value in the smallestUnit field only,
+ preserving the original calendar fields (years/months/weeks)
+ and extracting days only when largestUnit is a date unit. */
+ {
+ int64_t total_seconds = s->days * 86400LL +
+ s->hours * 3600LL +
+ s->minutes * 60LL +
+ s->seconds;
+ day_time_ns = (js_int128_t)total_seconds * 1000000000LL;
+ day_time_ns += (js_int128_t)s->milliseconds * 1000000LL;
+ day_time_ns += s->microseconds.int128_value * 1000LL;
+ day_time_ns += s->nanoseconds.int128_value;
+ }
+
+ js_int128_t plain_unit_ns;
+ switch (unit) {
+ case TI_UNIT_DAY: plain_unit_ns = 86400000000000LL; break;
+ case TI_UNIT_HOUR: plain_unit_ns = 3600000000000LL; break;
+ case TI_UNIT_MINUTE: plain_unit_ns = 60000000000LL; break;
+ case TI_UNIT_SECOND: plain_unit_ns = 1000000000LL; break;
+ case TI_UNIT_MILLISECOND: plain_unit_ns = 1000000LL; break;
+ case TI_UNIT_MICROSECOND: plain_unit_ns = 1000LL; break;
+ case TI_UNIT_NANOSECOND: plain_unit_ns = 1LL; break;
+ default: plain_unit_ns = 1LL; break;
+ }
+
+ js_int128_t plain_rounded_ns = ti_round_to_increment128(day_time_ns, plain_unit_ns * roundingIncrement, mode);
+
+ int64_t extra_days = 0;
+ js_int128_t remainder_ns = plain_rounded_ns;
+ if (largestUnit <= TI_UNIT_DAY) {
+ extra_days = (int64_t)(plain_rounded_ns / 86400000000000LL);
+ remainder_ns = plain_rounded_ns % 86400000000000LL;
+ }
+
+ memset(&result, 0, sizeof(result));
+ result.years = s->years;
+ result.months = s->months;
+ result.weeks = s->weeks;
+ if (largestUnit <= TI_UNIT_DAY) {
+ result.days = extra_days;
+ } else {
+ result.days = s->days;
+ }
+
+ {
+ int sign = (remainder_ns < 0) ? -1 : 1;
+ js_int128_t abs_ns = remainder_ns >= 0 ? remainder_ns : -remainder_ns;
+ int64_t sec = (int64_t)(abs_ns / 1000000000LL);
+ int64_t ns = (int64_t)(abs_ns % 1000000000LL);
+ int64_t us = ns / 1000; ns %= 1000;
+ int64_t ms = us / 1000; us %= 1000;
+ sec += ms / 1000; ms %= 1000;
+ int64_t min = 0, hr = 0;
+
+ switch (largestUnit) {
+ case TI_UNIT_NANOSECOND:
+ ns = sec * 1000000000LL + ns;
+ sec = 0;
+ ms = 0;
+ us = 0;
+ break;
+ case TI_UNIT_MICROSECOND:
+ us = sec * 1000000LL + us;
+ sec = 0;
+ ms = 0;
+ ns = 0;
+ break;
+ case TI_UNIT_MILLISECOND:
+ ms = sec * 1000LL + ms;
+ sec = 0;
+ us = 0;
+ ns = 0;
+ break;
+ case TI_UNIT_SECOND:
+ break;
+ case TI_UNIT_MINUTE:
+ min = sec / 60; sec %= 60;
+ break;
+ case TI_UNIT_HOUR:
+ min = sec / 60; sec %= 60;
+ hr = min / 60; min %= 60;
+ break;
+ default:
+ /* day/week/month/year: normalize all the way to hours */
+ min = sec / 60; sec %= 60;
+ hr = min / 60; min %= 60;
+ break;
+ }
+
+ result.hours = hr * sign;
+ result.minutes = min * sign;
+ result.seconds = sec * sign;
+ result.milliseconds = ms * sign;
+ result.microseconds.int128_value = (js_int128_t)(us * sign);
+ result.nanoseconds.int128_value = (js_int128_t)(ns * sign);
+ }
+ }
+ } else if (unit >= TI_UNIT_YEAR && unit <= TI_UNIT_WEEK) {
+ (void)rel_year; (void)rel_month; (void)rel_day;
+ (void)rel_hour; (void)rel_minute; (void)rel_second;
+ (void)rel_ms; (void)rel_us; (void)rel_ns;
+ /* For date units without ISO relativeTo, approximate using total days */
+ int64_t total_days = s->years * 365LL + s->months * 30LL + s->weeks * 7LL + s->days;
+ total_days += (int64_t)(duration_to_total_ns(s) / 86400000000000LL);
+ if (unit == TI_UNIT_DAY) {
+ unit_ns = 86400000000000LL;
+ inc_ns = unit_ns * roundingIncrement;
+ rounded_ns = ti_round_to_increment128((js_int128_t)total_days * 86400000000000LL, inc_ns, mode);
+ total_days = (int64_t)(rounded_ns / 86400000000000LL);
+ result.days = total_days;
+ } else {
+ /* week/month/year: just return days for now */
+ result.days = total_days;
+ }
+ } else {
+ total_ns = duration_to_total_ns(s);
+ unit_ns = ti_unit_to_nanoseconds(unit);
+ if (unit_ns <= 0) {
+ JS_FreeValue(ctx, relativeTo_val);
+ return JS_ThrowRangeError(ctx, "invalid unit");
+ }
+ inc_ns = unit_ns * roundingIncrement;
+ rounded_ns = ti_round_to_increment128(total_ns, inc_ns, mode);
+ if (duration_from_total_ns(rounded_ns, largestUnit, &result) < 0) {
+ JS_FreeValue(ctx, relativeTo_val);
+ return JS_ThrowRangeError(ctx, "result out of range");
+ }
+ }
+ }
+
+ JS_FreeValue(ctx, relativeTo_val);
+ duration_round_fields_to_float64(&result);
+ if (duration_is_out_of_range(&result))
+ return JS_ThrowRangeError(ctx, "duration out of range");
+ return js_create_duration(ctx, &result);
+}
+
+static JSValue js_duration_valueOf(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ (void)this_val;
+ (void)argc;
+ (void)argv;
+ return JS_ThrowTypeError(ctx, "cannot compare Temporal.Duration with < or >");
+}
+
+static const JSCFunctionListEntry js_duration_proto_funcs[] = {
+ JS_CGETSET_DEF("years", js_duration_get_years, NULL),
+ JS_CGETSET_DEF("months", js_duration_get_months, NULL),
+ JS_CGETSET_DEF("weeks", js_duration_get_weeks, NULL),
+ JS_CGETSET_DEF("days", js_duration_get_days, NULL),
+ JS_CGETSET_DEF("hours", js_duration_get_hours, NULL),
+ JS_CGETSET_DEF("minutes", js_duration_get_minutes, NULL),
+ JS_CGETSET_DEF("seconds", js_duration_get_seconds, NULL),
+ JS_CGETSET_DEF("milliseconds", js_duration_get_milliseconds, NULL),
+ JS_CGETSET_DEF("microseconds", js_duration_get_microseconds, NULL),
+ JS_CGETSET_DEF("nanoseconds", js_duration_get_nanoseconds, NULL),
+ JS_CGETSET_DEF("blank", js_duration_get_blank, NULL),
+ JS_CFUNC_DEF("negated", 0, js_duration_negated),
+ JS_CFUNC_DEF("abs", 0, js_duration_abs),
+ JS_CGETSET_DEF("sign", js_duration_get_sign, NULL),
+ JS_CFUNC_DEF("with", 1, js_duration_with),
+ JS_CFUNC_DEF("add", 1, js_duration_add),
+ JS_CFUNC_DEF("subtract", 1, js_duration_subtract),
+ JS_CFUNC_DEF("total", 1, js_duration_total),
+ JS_CFUNC_DEF("round", 1, js_duration_round),
+ JS_CFUNC_DEF("toString", 0, js_duration_toString),
+ JS_CFUNC_DEF("toJSON", 0, js_duration_toJSON),
+ JS_CFUNC_DEF("toLocaleString", 0, js_duration_toLocaleString),
+ JS_CFUNC_DEF("valueOf", 0, js_duration_valueOf),
+ JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Temporal.Duration", JS_PROP_CONFIGURABLE),
+};
+
+static const JSCFunctionListEntry js_duration_static_funcs[] = {
+ JS_CFUNC_DEF("from", 1, js_duration_from),
+ JS_CFUNC_DEF("compare", 2, js_duration_compare),
+};
+
+int js_add_duration(JSContext *ctx, JSValue temporal_obj)
+{
+ JSValue ctor;
+
+ JS_NewClassID(&js_duration_class_id);
+ JS_NewClass(JS_GetRuntime(ctx), js_duration_class_id, &js_duration_class);
+
+ ctor = JS_NewCConstructor(ctx, (int)js_duration_class_id, "Duration",
+ (JSCFunction *)js_duration_constructor, 0,
+ JS_CFUNC_constructor, 0,
+ JS_UNDEFINED,
+ js_duration_static_funcs, countof(js_duration_static_funcs),
+ js_duration_proto_funcs, countof(js_duration_proto_funcs),
+ JS_NEW_CTOR_NO_GLOBAL);
+ if (JS_IsException(ctor))
+ return -1;
+ if (JS_DefinePropertyValueStr(ctx, temporal_obj, "Duration", ctor,
+ JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE) < 0)
+ return -1;
+ return 0;
+}
--- /dev/null
+/*
+ * QuickJS Temporal.Instant implementation
+ */
+
+#include <string.h>
+#include <math.h>
+
+#include "../quickjs.h"
+#include "../cutils.h"
+#include "temporal_private.h"
+#include "timezone.h"
+
+JSClassID js_instant_class_id;
+
+static void js_instant_finalizer(JSRuntime *rt, JSValue val)
+{
+ JSInstantData *s = JS_GetOpaque(val, js_instant_class_id);
+ if (s) {
+ js_free_rt(rt, s);
+ }
+}
+
+static const JSClassDef js_instant_class = {
+ "Temporal.Instant",
+ .finalizer = js_instant_finalizer,
+};
+
+JSValue js_create_instant(JSContext *ctx, const JSTimeSpec *ts)
+{
+ JSInstantData *s;
+ JSValue obj;
+ s = js_mallocz(ctx, sizeof(*s));
+ if (!s)
+ return JS_EXCEPTION;
+ s->ts = *ts;
+ obj = JS_NewObjectClass(ctx, (int)js_instant_class_id);
+ if (JS_IsException(obj)) {
+ js_free(ctx, s);
+ return JS_EXCEPTION;
+ }
+ JS_SetOpaque(obj, s);
+ return obj;
+}
+
+/* --- Date math helpers --- */
+
+static int ti_is_leap_year(int64_t y)
+{
+ return !(y % 4) - !(y % 100) + !(y % 400);
+}
+
+static int ti_days_in_month(int m, int is_leap)
+{
+ if (m == 2 && is_leap)
+ return 29;
+ return ti_iso_month_days[m];
+}
+
+static int64_t ti_days_from_year(int64_t y)
+{
+ return 365 * (y - 1970) + floor_div64(y - 1969, 4) -
+ floor_div64(y - 1901, 100) + floor_div64(y - 1601, 400);
+}
+
+static int ti_is_valid_date(int64_t y, int m, int d)
+{
+ if (m < 1 || m > 12 || d < 1)
+ return 0;
+ return d <= ti_days_in_month(m, ti_is_leap_year(y));
+}
+
+/* Convert parsed ISO date/time to epoch nanoseconds.
+ tz_offset_ns is the offset from the string (positive = east of UTC).
+ UTC = local - offset, so we subtract the offset. */
+static int ti_iso_to_epoch_ns(JSContext *ctx, int64_t year, int month, int day,
+ int hour, int minute, int second,
+ int ms, int us, int ns,
+ int64_t tz_offset_ns, JSTimeSpec *ts)
+{
+ int64_t doy = day - 1;
+ int i, is_leap = ti_is_leap_year(year);
+ int64_t epoch_sec, frac_ns;
+
+ for (i = 1; i < month; i++)
+ doy += ti_days_in_month(i, is_leap);
+
+ epoch_sec = (ti_days_from_year(year) + doy) * 86400LL;
+ epoch_sec += hour * 3600LL + minute * 60LL + second;
+
+ /* Apply timezone offset: UTC = local - offset */
+ epoch_sec -= tz_offset_ns / 1000000000LL;
+ frac_ns = (int64_t)ms * 1000000 + (int64_t)us * 1000 + ns
+ - (tz_offset_ns % 1000000000LL);
+
+ /* Normalize */
+ ts->secs = epoch_sec + frac_ns / 1000000000LL;
+ ts->nsecs = (uint32_t)(frac_ns % 1000000000LL);
+ if (frac_ns < 0 && ts->nsecs != 0) {
+ ts->nsecs = (uint32_t)(ts->nsecs + 1000000000LL);
+ ts->secs -= 1;
+ }
+
+ if (!is_valid_epoch_timespec(ts)) {
+ JS_ThrowRangeError(ctx, "epochNanoseconds out of range");
+ return -1;
+ }
+ return 0;
+}
+
+/* --- Main ISO instant string parser --- */
+
+static int ti_parse_instant_string(JSContext *ctx, const char *str, JSTimeSpec *ts)
+{
+ TISODateTimeParseResult r;
+ int64_t tz_offset_ns = 0;
+
+ if (ti_parse_iso_datetime_string(ctx, str, &r, TI_PARSE_DEFAULT) < 0)
+ goto fail;
+
+ /* Instant strings must have a timezone indicator (Z or offset) */
+ if (!r.has_utc && !r.has_tz_offset)
+ goto fail;
+
+ /* Instant strings must have a date and time */
+ if (!r.has_date || !r.has_time)
+ goto fail;
+
+ /* Reject year-month only or month-day only strings */
+ if (r.has_yearmonth || r.has_monthday)
+ goto fail;
+
+ if (r.has_utc) {
+ tz_offset_ns = 0;
+ } else if (r.has_tz_offset) {
+ tz_offset_ns = (int64_t)r.tz_offset_seconds * 1000000000LL + r.tz_offset_nanoseconds;
+ }
+
+ if (!ti_is_valid_date(r.year, r.month, r.day))
+ goto fail;
+
+ return ti_iso_to_epoch_ns(ctx, r.year, r.month, r.day,
+ r.hour, r.minute, r.second,
+ r.millisecond, r.microsecond, r.nanosecond,
+ tz_offset_ns, ts);
+
+fail:
+ JS_ThrowRangeError(ctx, "invalid ISO string for Temporal.Instant");
+ return -1;
+}
+
+/* JSValue wrapper for ti_parse_temporal_timezone_string.
+ Returns JS_UNDEFINED on success, or throws JS_EXCEPTION on error. */
+static JSValue ti_parse_temporal_timezone_string_value(JSContext *ctx, JSValue val, int64_t *offset_ns)
+{
+ const char *str;
+ int ret;
+
+ if (!JS_IsString(val))
+ return JS_ThrowTypeError(ctx, "timeZone is not a valid string");
+ str = JS_ToCString(ctx, val);
+ if (!str)
+ return JS_EXCEPTION;
+ ret = ti_parse_temporal_timezone_string(str, offset_ns);
+ JS_FreeCString(ctx, str);
+ if (ret == -1)
+ return JS_ThrowRangeError(ctx, "invalid time zone");
+ return JS_UNDEFINED;
+}
+
+/* Return a canonical time zone identifier string for a time zone value.
+ Returns a JSValue string on success, JS_EXCEPTION on error.
+ This handles strings like "UTC", "utc", "+01:00", "2021-08-19T17:30-07:00",
+ "2021-08-19T17:30Z", "2021-08-19T17:30[UTC]", etc.
+ Bracket annotation takes precedence over prefix offset. */
+static JSValue ti_canonicalize_timezone_string(JSContext *ctx, JSValue val)
+{
+ const char *str;
+ size_t len;
+ JSValue result = JS_UNDEFINED;
+
+ if (!JS_IsString(val))
+ return JS_UNDEFINED;
+
+ str = JS_ToCStringLen(ctx, &len, val);
+ if (!str)
+ return JS_EXCEPTION;
+
+ /* Bracket annotation takes precedence */
+ const char *bracket = strchr(str, '[');
+ if (bracket) {
+ const char *close = strchr(bracket, ']');
+ if (close) {
+ int inner_len = (int)(close - bracket - 1);
+ if (inner_len == 3 && (bracket[1] == 'U' || bracket[1] == 'u') &&
+ (bracket[2] == 'T' || bracket[2] == 't') &&
+ (bracket[3] == 'C' || bracket[3] == 'c')) {
+ result = JS_NewString(ctx, "UTC");
+ } else if (inner_len == 6 && (bracket[1] == '+' || bracket[1] == '-')) {
+ char buf[8];
+ memcpy(buf, bracket + 1, 6);
+ buf[6] = '\0';
+ result = JS_NewString(ctx, buf);
+ } else if (inner_len > 0) {
+ /* IANA name */
+ result = JS_NewStringLen(ctx, bracket + 1, (size_t)inner_len);
+ }
+ }
+ } else if (len == 3 && (str[0] == 'U' || str[0] == 'u') &&
+ (str[1] == 'T' || str[1] == 't') &&
+ (str[2] == 'C' || str[2] == 'c')) {
+ result = JS_NewString(ctx, "UTC");
+ } else if (len == 6 && (str[0] == '+' || str[0] == '-')) {
+ result = JS_NewString(ctx, str);
+ } else if (len == 5 && (str[0] == '+' || str[0] == '-')) {
+ /* ±HHMM format - convert to ±HH:MM */
+ char buf[7];
+ buf[0] = str[0];
+ buf[1] = str[1];
+ buf[2] = str[2];
+ buf[3] = ':';
+ buf[4] = str[3];
+ buf[5] = str[4];
+ buf[6] = '\0';
+ result = JS_NewString(ctx, buf);
+ } else if (len > 1 && str[len - 1] == 'Z') {
+ result = JS_NewString(ctx, "UTC");
+ } else {
+ /* Plain IANA name */
+ int valid_iana = 1;
+ size_t i;
+ for (i = 0; i < len; i++) {
+ char c = str[i];
+ if (!((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') ||
+ (c >= '0' && c <= '9') || c == '/' || c == '_' || c == '-')) {
+ valid_iana = 0;
+ break;
+ }
+ }
+ if (valid_iana && len > 0) {
+ result = JS_NewString(ctx, str);
+ } else {
+ /* Find offset at end: ±HH:MM */
+ int j;
+ for (j = (int)len - 6; j >= 0; j--) {
+ if ((str[j] == '+' || str[j] == '-') && str[j + 3] == ':') {
+ int h1 = str[j + 1] - '0';
+ int h2 = str[j + 2] - '0';
+ int m1 = str[j + 4] - '0';
+ int m2 = str[j + 5] - '0';
+ if (h1 >= 0 && h1 <= 9 && h2 >= 0 && h2 <= 9 &&
+ m1 >= 0 && m1 <= 5 && m2 >= 0 && m2 <= 9) {
+ char buf[7];
+ memcpy(buf, str + j, 6);
+ buf[6] = '\0';
+ result = JS_NewString(ctx, buf);
+ break;
+ }
+ }
+ }
+ if (JS_IsUndefined(result)) {
+ /* Find offset at end: ±HHMM */
+ int k;
+ for (k = (int)len - 5; k >= 0; k--) {
+ if (str[k] == '+' || str[k] == '-') {
+ int h1 = str[k + 1] - '0';
+ int h2 = str[k + 2] - '0';
+ int m1 = str[k + 3] - '0';
+ int m2 = str[k + 4] - '0';
+ if (h1 >= 0 && h1 <= 9 && h2 >= 0 && h2 <= 9 &&
+ m1 >= 0 && m1 <= 5 && m2 >= 0 && m2 <= 9) {
+ char buf[7];
+ buf[0] = str[k];
+ buf[1] = str[k + 1];
+ buf[2] = str[k + 2];
+ buf[3] = ':';
+ buf[4] = str[k + 3];
+ buf[5] = str[k + 4];
+ buf[6] = '\0';
+ result = JS_NewString(ctx, buf);
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ JS_FreeCString(ctx, str);
+ return result;
+}
+
+/* ToTemporalInstant(item): converts item to Temporal.Instant */
+static JSValue ti_to_temporal_instant(JSContext *ctx, JSValueConst item)
+{
+ JSInstantData *s;
+ const char *str;
+ JSTimeSpec ts;
+ JSValue prim, r;
+
+ if (JS_IsObject(item)) {
+ s = JS_GetOpaque(item, js_instant_class_id);
+ if (s)
+ return js_create_instant(ctx, &s->ts);
+ /* Fast path for ZonedDateTime */
+ if (js_zoneddatetime_get_timespec(ctx, item, &ts) == 0)
+ return js_create_instant(ctx, &ts);
+ /* Convert to primitive string */
+ prim = JS_ToPrimitive(ctx, item, JS_HINT_STRING);
+ if (JS_IsException(prim))
+ return JS_EXCEPTION;
+ if (!JS_IsString(prim)) {
+ JS_FreeValue(ctx, prim);
+ return JS_ThrowTypeError(ctx, "cannot convert to Temporal.Instant");
+ }
+ str = JS_ToCString(ctx, prim);
+ if (!str) {
+ JS_FreeValue(ctx, prim);
+ return JS_EXCEPTION;
+ }
+ r = (ti_parse_instant_string(ctx, str, &ts) == 0)
+ ? js_create_instant(ctx, &ts)
+ : JS_EXCEPTION;
+ JS_FreeCString(ctx, str);
+ JS_FreeValue(ctx, prim);
+ return r;
+ }
+ if (!JS_IsString(item))
+ return JS_ThrowTypeError(ctx, "cannot convert to Temporal.Instant");
+ str = JS_ToCString(ctx, item);
+ if (!str)
+ return JS_EXCEPTION;
+ r = (ti_parse_instant_string(ctx, str, &ts) == 0)
+ ? js_create_instant(ctx, &ts)
+ : JS_EXCEPTION;
+ JS_FreeCString(ctx, str);
+ return r;
+}
+
+/* --- Instant methods --- */
+
+/* Temporal.Instant constructor */
+static JSValue js_instant_constructor(JSContext *ctx, JSValueConst new_target,
+ int argc, JSValueConst *argv)
+{
+ (void)argc;
+ JSValue obj = JS_UNDEFINED;
+ JSTimeSpec ts;
+ if (JS_IsUndefined(new_target)) {
+ return JS_ThrowTypeError(ctx, "Temporal.Instant constructor cannot be called as a function");
+ }
+ if (JS_IsUndefined(argv[0])) {
+ return JS_ThrowTypeError(ctx, "Temporal.Instant requires an epochNanoseconds argument");
+ }
+ if (ti_bigint_to_timespec(ctx, argv[0], &ts) < 0)
+ return JS_EXCEPTION;
+ if (!is_valid_epoch_timespec(&ts)) {
+ return JS_ThrowRangeError(ctx, "epochNanoseconds out of range");
+ }
+ {
+ JSInstantData *s = js_mallocz(ctx, sizeof(*s));
+ if (!s)
+ return JS_EXCEPTION;
+ s->ts = ts;
+ obj = js_create_temporal_object(ctx, new_target, js_instant_class_id, s);
+ if (JS_IsException(obj)) {
+ js_free(ctx, s);
+ return JS_EXCEPTION;
+ }
+ return obj;
+ }
+}
+
+/* Temporal.Instant.fromEpochMilliseconds */
+/* NumberToBigInt semantics: throws RangeError for non-integral, NaN, Infinity, undefined */
+static int js_number_to_int64(JSContext *ctx, JSValueConst val, int64_t *pres)
+{
+ double d;
+ if (JS_ToFloat64(ctx, &d, val))
+ return -1;
+ if (!isfinite(d) || floor(d) != d) {
+ JS_ThrowRangeError(ctx, "number cannot be converted to BigInt");
+ return -1;
+ }
+ *pres = (int64_t)d;
+ return 0;
+}
+
+static void ms_to_timespec(int64_t ms, JSTimeSpec *ts)
+{
+ ts->secs = ms / 1000;
+ int64_t rem = (ms % 1000) * 1000000;
+ if (rem < 0) {
+ rem += 1000000000;
+ ts->secs -= 1;
+ }
+ ts->nsecs = (uint32_t)rem;
+}
+
+static JSValue js_instant_fromEpochMilliseconds(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ (void)argc;
+ (void)this_val;
+ (void)this_val;
+ int64_t ms;
+ JSTimeSpec ts;
+ JSValueConst val = argc > 0 ? argv[0] : JS_UNDEFINED;
+ if (js_number_to_int64(ctx, val, &ms) < 0)
+ return JS_EXCEPTION;
+ ms_to_timespec(ms, &ts);
+ if (!is_valid_epoch_timespec(&ts))
+ return JS_ThrowRangeError(ctx, "epochMilliseconds out of range");
+ return js_create_instant(ctx, &ts);
+}
+
+/* Temporal.Instant.fromEpochNanoseconds */
+static JSValue js_instant_fromEpochNanoseconds(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ (void)this_val;
+ (void)argc;
+ JSTimeSpec ts;
+ if (ti_bigint_to_timespec(ctx, argv[0], &ts) < 0)
+ return JS_EXCEPTION;
+ if (!is_valid_epoch_timespec(&ts))
+ return JS_ThrowRangeError(ctx, "epochNanoseconds out of range");
+ return js_create_instant(ctx, &ts);
+}
+
+/* Temporal.Instant.compare */
+static JSValue js_instant_compare(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ (void)this_val;
+ (void)argc;
+ JSValue a, b;
+ JSInstantData *s1, *s2;
+ int cmp;
+ a = ti_to_temporal_instant(ctx, argv[0]);
+ if (JS_IsException(a))
+ return JS_EXCEPTION;
+ b = ti_to_temporal_instant(ctx, argv[1]);
+ if (JS_IsException(b)) {
+ JS_FreeValue(ctx, a);
+ return JS_EXCEPTION;
+ }
+ s1 = JS_GetOpaque(a, js_instant_class_id);
+ s2 = JS_GetOpaque(b, js_instant_class_id);
+ if (s1->ts.secs < s2->ts.secs)
+ cmp = -1;
+ else if (s1->ts.secs > s2->ts.secs)
+ cmp = 1;
+ else if (s1->ts.nsecs < s2->ts.nsecs)
+ cmp = -1;
+ else if (s1->ts.nsecs > s2->ts.nsecs)
+ cmp = 1;
+ else
+ cmp = 0;
+ JS_FreeValue(ctx, a);
+ JS_FreeValue(ctx, b);
+ return JS_NewInt32(ctx, cmp);
+}
+
+/* Temporal.Instant.from */
+static JSValue js_instant_from(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ (void)this_val;
+ (void)argc;
+ return ti_to_temporal_instant(ctx, argv[0]);
+}
+
+/* get epochMilliseconds */
+static JSValue js_instant_get_epochMilliseconds(JSContext *ctx, JSValueConst this_val)
+{
+ JSInstantData *s = JS_GetOpaque2(ctx, this_val, js_instant_class_id);
+ int64_t ms;
+ if (!s)
+ return JS_EXCEPTION;
+ ms = s->ts.secs * 1000 + (int64_t)(s->ts.nsecs / 1000000);
+ return JS_NewFloat64(ctx, (double)ms);
+}
+
+/* get epochNanoseconds */
+static JSValue js_instant_get_epochNanoseconds(JSContext *ctx, JSValueConst this_val)
+{
+ JSInstantData *s = JS_GetOpaque2(ctx, this_val, js_instant_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ return ti_timespec_to_bigint(ctx, &s->ts);
+}
+
+/* Temporal.Instant.prototype.equals */
+static JSValue js_instant_equals(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ (void)argc;
+ (void)argc;
+ JSInstantData *s, *other;
+ JSValue other_val;
+ s = JS_GetOpaque2(ctx, this_val, js_instant_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ other_val = ti_to_temporal_instant(ctx, argv[0]);
+ if (JS_IsException(other_val))
+ return JS_EXCEPTION;
+ other = JS_GetOpaque(other_val, js_instant_class_id);
+ if (!other) {
+ JS_FreeValue(ctx, other_val);
+ return JS_ThrowTypeError(ctx, "not an Instant");
+ }
+ {
+ JSTimeSpec s_ts = s->ts;
+ int64_t other_secs = other->ts.secs;
+ uint32_t other_nsecs = other->ts.nsecs;
+ JS_FreeValue(ctx, other_val);
+ return JS_NewBool(ctx, s_ts.secs == other_secs && s_ts.nsecs == other_nsecs);
+ }
+}
+
+/* Temporal.Instant.prototype.valueOf */
+static JSValue js_instant_valueOf(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ (void)argc;
+ (void)argv;
+ (void)this_val;
+ return JS_ThrowTypeError(ctx, "cannot compare Temporal.Instant with < or >");
+}
+
+/* Forward declarations */
+static JSValue js_instant_toString(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv);
+
+/* --- Rounding helpers --- */
+
+int ti_parse_rounding_mode(JSContext *ctx, JSValueConst val, TIRoundingMode *out)
+{
+ const char *str;
+ if (JS_IsUndefined(val)) {
+ *out = ROUND_HALF_EXPAND;
+ return 0;
+ }
+ str = JS_ToCStringNZ(ctx, val);
+ if (!str)
+ return -1;
+ if (!strcmp(str, "ceil"))
+ *out = ROUND_CEIL;
+ else if (!strcmp(str, "floor"))
+ *out = ROUND_FLOOR;
+ else if (!strcmp(str, "expand"))
+ *out = ROUND_EXPAND;
+ else if (!strcmp(str, "trunc"))
+ *out = ROUND_TRUNC;
+ else if (!strcmp(str, "halfCeil"))
+ *out = ROUND_HALF_CEIL;
+ else if (!strcmp(str, "halfFloor"))
+ *out = ROUND_HALF_FLOOR;
+ else if (!strcmp(str, "halfExpand"))
+ *out = ROUND_HALF_EXPAND;
+ else if (!strcmp(str, "halfTrunc"))
+ *out = ROUND_HALF_TRUNC;
+ else if (!strcmp(str, "halfEven"))
+ *out = ROUND_HALF_EVEN;
+ else {
+ JS_ThrowRangeError(ctx, "invalid rounding mode");
+ JS_FreeCString(ctx, str);
+ return -1;
+ }
+ JS_FreeCString(ctx, str);
+ return 0;
+}
+
+/* Standard rounding using Euclidean division.
+ ceil/floor are mathematical (toward ±∞).
+ expand rounds away from zero, trunc rounds toward zero. */
+int64_t ti_round_to_increment(int64_t x, int64_t increment, TIRoundingMode mode)
+{
+ int64_t q, r, q_euclid, r_euclid, floor_q, ceil_q, trunc_q, result;
+
+ if (increment == 1)
+ return x;
+
+ q = x / increment;
+ r = x % increment;
+
+ /* Convert to Euclidean division: x = q_euclid * inc + r_euclid, 0 <= r_euclid < inc */
+ if (r < 0) {
+ q_euclid = q - 1;
+ r_euclid = r + increment;
+ } else {
+ q_euclid = q;
+ r_euclid = r;
+ }
+
+ floor_q = q_euclid;
+ ceil_q = (r_euclid == 0) ? q_euclid : q_euclid + 1;
+ trunc_q = (x >= 0) ? q_euclid : ((r_euclid == 0) ? q_euclid : q_euclid + 1);
+
+ if (r_euclid == 0)
+ return x;
+
+ switch (mode) {
+ case ROUND_CEIL:
+ result = ceil_q * increment;
+ break;
+ case ROUND_FLOOR:
+ result = floor_q * increment;
+ break;
+ case ROUND_EXPAND:
+ result = (x > 0 ? ceil_q : floor_q) * increment;
+ break;
+ case ROUND_TRUNC:
+ result = trunc_q * increment;
+ break;
+ case ROUND_HALF_CEIL:
+ case ROUND_HALF_FLOOR:
+ case ROUND_HALF_EXPAND:
+ case ROUND_HALF_TRUNC:
+ case ROUND_HALF_EVEN: {
+ int64_t dist_floor = r_euclid;
+ int64_t dist_ceil = increment - r_euclid;
+ int up; /* 1 = ceil, 0 = floor */
+ if (dist_floor < dist_ceil) {
+ up = 0;
+ } else if (dist_floor > dist_ceil) {
+ up = 1;
+ } else {
+ switch (mode) {
+ case ROUND_HALF_CEIL:
+ up = 1;
+ break;
+ case ROUND_HALF_FLOOR:
+ up = 0;
+ break;
+ case ROUND_HALF_EXPAND:
+ up = (x > 0) ? 1 : 0; /* away from zero: positive→ceil, negative→floor */
+ break;
+ case ROUND_HALF_TRUNC:
+ up = (x > 0) ? 0 : 1; /* toward zero: positive→floor, negative→ceil */
+ break;
+ case ROUND_HALF_EVEN:
+ up = (floor_q % 2 == 0) ? 0 : 1;
+ break;
+ default:
+ up = 0;
+ break;
+ }
+ }
+ result = up ? (ceil_q * increment) : (floor_q * increment);
+ break;
+ }
+ default:
+ result = x;
+ break;
+ }
+ return result;
+}
+
+js_int128_t ti_round_to_increment128(js_int128_t x, js_int128_t increment, TIRoundingMode mode)
+{
+ js_int128_t q, r, q_euclid, r_euclid, floor_q, ceil_q, trunc_q, result;
+
+ if (increment == 1)
+ return x;
+
+ q = x / increment;
+ r = x % increment;
+
+ /* Convert to Euclidean division */
+ if (r < 0) {
+ q_euclid = q - 1;
+ r_euclid = r + increment;
+ } else {
+ q_euclid = q;
+ r_euclid = r;
+ }
+
+ floor_q = q_euclid;
+ ceil_q = (r_euclid == 0) ? q_euclid : q_euclid + 1;
+ trunc_q = (x >= 0) ? q_euclid : ((r_euclid == 0) ? q_euclid : q_euclid + 1);
+
+ if (r_euclid == 0)
+ return x;
+
+ switch (mode) {
+ case ROUND_CEIL:
+ result = ceil_q * increment;
+ break;
+ case ROUND_FLOOR:
+ result = floor_q * increment;
+ break;
+ case ROUND_EXPAND:
+ result = (x > 0 ? ceil_q : floor_q) * increment;
+ break;
+ case ROUND_TRUNC:
+ result = trunc_q * increment;
+ break;
+ case ROUND_HALF_CEIL:
+ case ROUND_HALF_FLOOR:
+ case ROUND_HALF_EXPAND:
+ case ROUND_HALF_TRUNC:
+ case ROUND_HALF_EVEN: {
+ js_int128_t dist_floor = r_euclid;
+ js_int128_t dist_ceil = increment - r_euclid;
+ int up;
+ if (dist_floor < dist_ceil) {
+ up = 0;
+ } else if (dist_floor > dist_ceil) {
+ up = 1;
+ } else {
+ switch (mode) {
+ case ROUND_HALF_CEIL:
+ up = 1;
+ break;
+ case ROUND_HALF_FLOOR:
+ up = 0;
+ break;
+ case ROUND_HALF_EXPAND:
+ up = (x > 0) ? 1 : 0;
+ break;
+ case ROUND_HALF_TRUNC:
+ up = (x > 0) ? 0 : 1;
+ break;
+ case ROUND_HALF_EVEN:
+ up = (floor_q % 2 == 0) ? 0 : 1;
+ break;
+ default:
+ up = 0;
+ break;
+ }
+ }
+ result = up ? (ceil_q * increment) : (floor_q * increment);
+ break;
+ }
+ default:
+ result = x;
+ break;
+ }
+ return result;
+}
+
+/* As-if-positive rounding used by toString: treat negative as positive then negate */
+int64_t ti_round_to_increment_as_if_positive(int64_t x, int64_t increment, TIRoundingMode mode)
+{
+ int64_t q, r, floor_q, ceil_q, result;
+ int has_remainder;
+
+ if (increment == 1)
+ return x;
+
+ q = x / increment;
+ r = x % increment;
+ has_remainder = (r != 0);
+
+ if (x >= 0) {
+ floor_q = q;
+ ceil_q = has_remainder ? q + 1 : q;
+ } else {
+ floor_q = has_remainder ? q - 1 : q;
+ ceil_q = q;
+ }
+
+ if (!has_remainder)
+ return x;
+
+ switch (mode) {
+ case ROUND_CEIL:
+ case ROUND_EXPAND:
+ result = ceil_q * increment;
+ break;
+ case ROUND_FLOOR:
+ case ROUND_TRUNC:
+ result = floor_q * increment;
+ break;
+ case ROUND_HALF_CEIL:
+ case ROUND_HALF_FLOOR:
+ case ROUND_HALF_EXPAND:
+ case ROUND_HALF_TRUNC:
+ case ROUND_HALF_EVEN: {
+ int64_t abs_r = r >= 0 ? r : -r;
+ int64_t r_euclid = (x >= 0) ? abs_r : (increment - abs_r);
+ int64_t dist_floor = r_euclid;
+ int64_t dist_ceil = increment - r_euclid;
+ int up;
+ if (dist_floor < dist_ceil) {
+ up = 0;
+ } else if (dist_floor > dist_ceil) {
+ up = 1;
+ } else {
+ /* Tie: round as if positive, then negate */
+ switch (mode) {
+ case ROUND_HALF_CEIL:
+ up = 1; /* ceil for positive → negate → ceil for negative */
+ break;
+ case ROUND_HALF_FLOOR:
+ up = 0; /* floor for positive → negate → floor for negative */
+ break;
+ case ROUND_HALF_EXPAND:
+ up = 1; /* away from zero for positive → negate → away from zero for negative */
+ break;
+ case ROUND_HALF_TRUNC:
+ up = 0; /* toward zero for positive → negate → toward zero for negative */
+ break;
+ case ROUND_HALF_EVEN:
+ /* For positive: if floor is even, floor; else ceil.
+ For negative x, floor(|x|/inc) = -ceil_q.
+ If -ceil_q is even (i.e., ceil_q is even), choose ceil_q.
+ Otherwise choose floor_q. */
+ up = (ceil_q % 2 == 0) ? 1 : 0;
+ break;
+ default:
+ up = 0;
+ break;
+ }
+ }
+ result = up ? (ceil_q * increment) : (floor_q * increment);
+ break;
+ }
+ default:
+ result = x;
+ break;
+ }
+ return result;
+}
+
+/* js_int128_t variant of AsIfPositive rounding, used to avoid overflow for large epoch nanoseconds */
+js_int128_t ti_round_to_increment_as_if_positive128(js_int128_t x, js_int128_t increment, TIRoundingMode mode)
+{
+ js_int128_t q, r, floor_q, ceil_q, result;
+ int has_remainder;
+
+ if (increment == 1)
+ return x;
+
+ q = x / increment;
+ r = x % increment;
+ has_remainder = (r != 0);
+
+ if (x >= 0) {
+ floor_q = q;
+ ceil_q = has_remainder ? q + 1 : q;
+ } else {
+ floor_q = has_remainder ? q - 1 : q;
+ ceil_q = q;
+ }
+
+ if (!has_remainder)
+ return x;
+
+ switch (mode) {
+ case ROUND_CEIL:
+ case ROUND_EXPAND:
+ result = ceil_q * increment;
+ break;
+ case ROUND_FLOOR:
+ case ROUND_TRUNC:
+ result = floor_q * increment;
+ break;
+ case ROUND_HALF_CEIL:
+ case ROUND_HALF_FLOOR:
+ case ROUND_HALF_EXPAND:
+ case ROUND_HALF_TRUNC:
+ case ROUND_HALF_EVEN: {
+ js_int128_t abs_r = r >= 0 ? r : -r;
+ js_int128_t r_euclid = (x >= 0) ? abs_r : (increment - abs_r);
+ js_int128_t dist_floor = r_euclid;
+ js_int128_t dist_ceil = increment - r_euclid;
+ int up;
+ if (dist_floor < dist_ceil) {
+ up = 0;
+ } else if (dist_floor > dist_ceil) {
+ up = 1;
+ } else {
+ switch (mode) {
+ case ROUND_HALF_CEIL:
+ up = 1;
+ break;
+ case ROUND_HALF_FLOOR:
+ up = 0;
+ break;
+ case ROUND_HALF_EXPAND:
+ up = 1;
+ break;
+ case ROUND_HALF_TRUNC:
+ up = 0;
+ break;
+ case ROUND_HALF_EVEN:
+ up = (ceil_q % 2 == 0) ? 1 : 0;
+ break;
+ default:
+ up = 0;
+ break;
+ }
+ }
+ result = up ? (ceil_q * increment) : (floor_q * increment);
+ break;
+ }
+ default:
+ result = x;
+ break;
+ }
+ return result;
+}
+
+static int ti_unit_is_time_unit(TIUnit unit)
+{
+ return unit >= TI_UNIT_HOUR;
+}
+
+/* Convert nanosecond count to Duration with given largestUnit */
+static void ti_ns_to_duration(js_int128_t total_ns, TIUnit largestUnit, JSDurationData *d)
+{
+ js_int128_t abs_ns = total_ns >= 0 ? total_ns : -total_ns;
+ int negative = total_ns < 0;
+
+ memset(d, 0, sizeof(*d));
+
+ if (largestUnit <= TI_UNIT_SECOND) {
+ int64_t total_seconds = (int64_t)(abs_ns / 1000000000LL);
+ int64_t rem_ns = (int64_t)(abs_ns % 1000000000LL);
+
+ if (largestUnit <= TI_UNIT_HOUR) {
+ d->hours = total_seconds / 3600;
+ total_seconds %= 3600;
+ }
+ if (largestUnit <= TI_UNIT_MINUTE) {
+ d->minutes = total_seconds / 60;
+ total_seconds %= 60;
+ }
+ d->seconds = total_seconds;
+
+ d->milliseconds = rem_ns / 1000000LL;
+ rem_ns %= 1000000LL;
+ d->microseconds.int128_value = rem_ns / 1000LL;
+ d->nanoseconds.int128_value = rem_ns % 1000LL;
+ } else {
+ if (largestUnit <= TI_UNIT_MILLISECOND) {
+ d->milliseconds = (int64_t)(abs_ns / 1000000LL);
+ abs_ns %= 1000000LL;
+ }
+ if (largestUnit <= TI_UNIT_MICROSECOND) {
+ d->microseconds.int128_value = (int64_t)(abs_ns / 1000LL);
+ abs_ns %= 1000LL;
+ }
+ if (largestUnit <= TI_UNIT_NANOSECOND) {
+ d->nanoseconds.int128_value = (int64_t)abs_ns;
+ }
+ }
+
+ if (negative) {
+ d->hours = -d->hours;
+ d->minutes = -d->minutes;
+ d->seconds = -d->seconds;
+ d->milliseconds = -d->milliseconds;
+ d->microseconds.int128_value = -d->microseconds.int128_value;
+ d->nanoseconds.int128_value = -d->nanoseconds.int128_value;
+ }
+}
+
+/* Temporal.Instant.prototype.round */
+static JSValue js_instant_round(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ (void)argc;
+ JSInstantData *s;
+ JSValue options;
+ const char *unit_str;
+ int64_t unit_ns, increment = 1;
+ TIRoundingMode mode = ROUND_TRUNC;
+ js_int128_t total_ns, rounded_ns;
+ JSTimeSpec result;
+
+ s = JS_GetOpaque2(ctx, this_val, js_instant_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ if (JS_IsUndefined(argv[0]))
+ return JS_ThrowTypeError(ctx, "round requires an options object");
+
+ /* Accept string as smallestUnit shorthand */
+ if (JS_IsString(argv[0])) {
+ unit_str = JS_ToCStringNZ(ctx, argv[0]);
+ if (!unit_str)
+ return JS_EXCEPTION;
+ {
+ TIUnit u = ti_string_to_unit(unit_str, strlen(unit_str));
+ unit_ns = ti_unit_to_ns(u);
+ }
+ JS_FreeCString(ctx, unit_str);
+ if (unit_ns == 0)
+ return JS_ThrowRangeError(ctx, "invalid smallestUnit");
+ options = JS_NULL;
+ mode = ROUND_HALF_EXPAND;
+ } else if (JS_IsObject(argv[0])) {
+ options = JS_DupValue(ctx, argv[0]);
+
+ if (ti_get_rounding_increment_option(ctx, options, &increment) < 0) {
+ JS_FreeValue(ctx, options);
+ return JS_EXCEPTION;
+ }
+ /* roundingMode */
+ if (ti_get_rounding_mode_option(ctx, options, &mode) < 0) {
+ JS_FreeValue(ctx, options);
+ return JS_EXCEPTION;
+ }
+
+ /* smallestUnit */
+ {
+ TIUnit smallestUnit;
+ if (ti_parse_unit_option(ctx, options, "smallestUnit", &smallestUnit, TI_UNIT_OPT_ALLOW_UNDEFINED, TI_UNIT_INVALID) < 0) {
+ JS_FreeValue(ctx, options);
+ return JS_EXCEPTION;
+ }
+ unit_ns = ti_unit_to_ns(smallestUnit);
+ }
+
+ JS_FreeValue(ctx, options);
+ } else {
+ return JS_ThrowTypeError(ctx, "round requires an options object");
+ }
+
+ /* Validate smallestUnit */
+ if (unit_ns == 0)
+ return JS_ThrowRangeError(ctx, "invalid smallestUnit");
+
+ /* Validate roundingIncrement against maximum for smallestUnit */
+ {
+ int64_t maximum;
+ switch (unit_ns) {
+ case 3600000000000LL: maximum = 24; break;
+ case 60000000000LL: maximum = 1440; break;
+ case 1000000000LL: maximum = 86400; break;
+ case 1000000LL: maximum = 86400000; break;
+ case 1000LL: maximum = 86400000000LL; break;
+ case 1LL: maximum = 86400000000000LL; break;
+ default: maximum = 0; break;
+ }
+ if (increment > maximum || maximum % increment != 0) {
+ return JS_ThrowRangeError(ctx, "roundingIncrement does not divide evenly into the unit");
+ }
+ }
+
+ /* Convert instant to total nanoseconds using js_int128_t to avoid overflow */
+ total_ns = ti_timespec_to_ns(&s->ts);
+
+ /* Round */
+ {
+ js_int128_t inc_ns = unit_ns * increment;
+ rounded_ns = ti_round_to_increment_as_if_positive128(total_ns, inc_ns, mode);
+ }
+
+ /* Convert back to JSTimeSpec */
+ ti_ns_to_timespec(rounded_ns, &result);
+ if (!is_valid_epoch_timespec(&result))
+ return JS_ThrowRangeError(ctx, "rounded value out of range");
+ return js_create_instant(ctx, &result);
+}
+
+/* Temporal.Instant.prototype.toJSON */
+static JSValue js_instant_toJSON(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ (void)argc;
+ (void)argv;
+ return js_instant_toString(ctx, this_val, 0, NULL);
+}
+
+/* Temporal.Instant.prototype.toLocaleString */
+static JSValue js_instant_toLocaleString(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSInstantData *s = JS_GetOpaque2(ctx, this_val, js_instant_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ return ti_temporal_toLocaleString(ctx, this_val, argc, argv, 0, js_instant_toString);
+}
+
+/* Convert a JSValue (number or bigint) to js_int128_t. Returns 0 on success, -1 on exception. */
+static int js_value_to_int128(JSContext *ctx, JSValueConst val, js_int128_t *res)
+{
+ if (JS_IsBigInt(ctx, val)) {
+ JSValue str = JS_ToString(ctx, val);
+ if (JS_IsException(str))
+ return -1;
+ const char *s = JS_ToCString(ctx, str);
+ if (!s) {
+ JS_FreeValue(ctx, str);
+ return -1;
+ }
+ js_int128_t v = 0;
+ int sign = 1;
+ const char *p = s;
+ if (*p == '-') {
+ sign = -1;
+ p++;
+ }
+ while (*p >= '0' && *p <= '9') {
+ v = v * 10 + (*p - '0');
+ p++;
+ }
+ *res = sign * v;
+ JS_FreeCString(ctx, s);
+ JS_FreeValue(ctx, str);
+ return 0;
+ } else {
+ double d;
+ if (JS_ToFloat64(ctx, &d, val))
+ return -1;
+ if (!isfinite(d) || floor(d) != d) {
+ JS_ThrowRangeError(ctx, "value must be an integer");
+ return -1;
+ }
+ *res = (js_int128_t)d;
+ return 0;
+ }
+}
+
+/* Read duration-like properties from an object and return total nanoseconds as js_int128_t.
+ Also validates no date units and no mixed signs. */
+static int ti_read_instant_duration_ns(JSContext *ctx, JSValueConst item, js_int128_t *total_ns)
+{
+ JSValue val;
+ js_int128_t ns = 0;
+ int has_positive = 0, has_negative = 0;
+ int has_any = 0;
+
+ *total_ns = 0;
+ if (JS_IsString(item)) {
+ const char *str = JS_ToCString(ctx, item);
+ JSDurationData d;
+ int ret;
+ if (!str)
+ return -1;
+ ret = js_parse_duration_string(ctx, str, &d);
+ JS_FreeCString(ctx, str);
+ if (ret < 0)
+ return -1;
+ if (duration_has_mixed_signs(&d)) {
+ JS_ThrowRangeError(ctx, "mixed signs in duration fields");
+ return -1;
+ }
+ if (d.years != 0 || d.months != 0 || d.weeks != 0 || d.days != 0) {
+ JS_ThrowRangeError(ctx, "date units not allowed for Instant arithmetic");
+ return -1;
+ }
+ ns += (js_int128_t)d.hours * 3600 * 1000000000;
+ ns += (js_int128_t)d.minutes * 60 * 1000000000;
+ ns += (js_int128_t)d.seconds * 1000000000;
+ ns += (js_int128_t)d.milliseconds * 1000000;
+ ns += (js_int128_t)d.microseconds.int128_value * 1000;
+ ns += (js_int128_t)d.nanoseconds.int128_value;
+ *total_ns = ns;
+ return 0;
+ }
+ if (!JS_IsObject(item)) {
+ JS_ThrowTypeError(ctx, "expected object");
+ return -1;
+ }
+
+ /* days */
+ val = JS_GetPropertyStr(ctx, item, "days");
+ if (!JS_IsUndefined(val)) {
+ js_int128_t v;
+ if (js_value_to_int128(ctx, val, &v) < 0) {
+ JS_FreeValue(ctx, val);
+ return -1;
+ }
+ if (v != 0) {
+ JS_ThrowRangeError(ctx, "date units not allowed for Instant arithmetic");
+ JS_FreeValue(ctx, val);
+ return -1;
+ }
+ JS_FreeValue(ctx, val);
+ }
+ /* hours */
+ val = JS_GetPropertyStr(ctx, item, "hours");
+ if (!JS_IsUndefined(val)) {
+ js_int128_t v;
+ if (js_value_to_int128(ctx, val, &v) < 0) {
+ JS_FreeValue(ctx, val);
+ return -1;
+ }
+ if (v > 0) has_positive = 1;
+ if (v < 0) has_negative = 1;
+ ns += v * 3600 * 1000000000;
+ has_any = 1;
+ JS_FreeValue(ctx, val);
+ }
+ /* microseconds */
+ val = JS_GetPropertyStr(ctx, item, "microseconds");
+ if (!JS_IsUndefined(val)) {
+ js_int128_t v;
+ if (js_value_to_int128(ctx, val, &v) < 0) {
+ JS_FreeValue(ctx, val);
+ return -1;
+ }
+ if (v > 0) has_positive = 1;
+ if (v < 0) has_negative = 1;
+ ns += v * 1000;
+ has_any = 1;
+ JS_FreeValue(ctx, val);
+ }
+ /* milliseconds */
+ val = JS_GetPropertyStr(ctx, item, "milliseconds");
+ if (!JS_IsUndefined(val)) {
+ js_int128_t v;
+ if (js_value_to_int128(ctx, val, &v) < 0) {
+ JS_FreeValue(ctx, val);
+ return -1;
+ }
+ if (v > 0) has_positive = 1;
+ if (v < 0) has_negative = 1;
+ ns += v * 1000000;
+ has_any = 1;
+ JS_FreeValue(ctx, val);
+ }
+ /* minutes */
+ val = JS_GetPropertyStr(ctx, item, "minutes");
+ if (!JS_IsUndefined(val)) {
+ js_int128_t v;
+ if (js_value_to_int128(ctx, val, &v) < 0) {
+ JS_FreeValue(ctx, val);
+ return -1;
+ }
+ if (v > 0) has_positive = 1;
+ if (v < 0) has_negative = 1;
+ ns += v * 60 * 1000000000;
+ has_any = 1;
+ JS_FreeValue(ctx, val);
+ }
+ /* months */
+ val = JS_GetPropertyStr(ctx, item, "months");
+ if (!JS_IsUndefined(val)) {
+ js_int128_t v;
+ if (js_value_to_int128(ctx, val, &v) < 0) {
+ JS_FreeValue(ctx, val);
+ return -1;
+ }
+ if (v != 0) {
+ JS_ThrowRangeError(ctx, "date units not allowed for Instant arithmetic");
+ JS_FreeValue(ctx, val);
+ return -1;
+ }
+ JS_FreeValue(ctx, val);
+ }
+ /* nanoseconds */
+ val = JS_GetPropertyStr(ctx, item, "nanoseconds");
+ if (!JS_IsUndefined(val)) {
+ js_int128_t v;
+ if (js_value_to_int128(ctx, val, &v) < 0) {
+ JS_FreeValue(ctx, val);
+ return -1;
+ }
+ if (v > 0) has_positive = 1;
+ if (v < 0) has_negative = 1;
+ ns += v;
+ has_any = 1;
+ JS_FreeValue(ctx, val);
+ }
+ /* seconds */
+ val = JS_GetPropertyStr(ctx, item, "seconds");
+ if (!JS_IsUndefined(val)) {
+ js_int128_t v;
+ if (js_value_to_int128(ctx, val, &v) < 0) {
+ JS_FreeValue(ctx, val);
+ return -1;
+ }
+ if (v > 0) has_positive = 1;
+ if (v < 0) has_negative = 1;
+ ns += v * 1000000000;
+ has_any = 1;
+ JS_FreeValue(ctx, val);
+ }
+ /* weeks */
+ val = JS_GetPropertyStr(ctx, item, "weeks");
+ if (!JS_IsUndefined(val)) {
+ js_int128_t v;
+ if (js_value_to_int128(ctx, val, &v) < 0) {
+ JS_FreeValue(ctx, val);
+ return -1;
+ }
+ if (v != 0) {
+ JS_ThrowRangeError(ctx, "date units not allowed for Instant arithmetic");
+ JS_FreeValue(ctx, val);
+ return -1;
+ }
+ JS_FreeValue(ctx, val);
+ }
+ /* years */
+ val = JS_GetPropertyStr(ctx, item, "years");
+ if (!JS_IsUndefined(val)) {
+ js_int128_t v;
+ if (js_value_to_int128(ctx, val, &v) < 0) {
+ JS_FreeValue(ctx, val);
+ return -1;
+ }
+ if (v != 0) {
+ JS_ThrowRangeError(ctx, "date units not allowed for Instant arithmetic");
+ JS_FreeValue(ctx, val);
+ return -1;
+ }
+ JS_FreeValue(ctx, val);
+ }
+
+ if (has_positive && has_negative) {
+ JS_ThrowRangeError(ctx, "mixed signs in duration fields");
+ return -1;
+ }
+ if (!has_any) {
+ JS_ThrowTypeError(ctx, "no duration properties found");
+ return -1;
+ }
+
+ *total_ns = ns;
+ return 0;
+}
+
+/* Temporal.Instant.prototype.toZonedDateTimeISO */
+static JSValue js_instant_toZonedDateTimeISO(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ (void)argc;
+ JSInstantData *s;
+ JSValue result;
+
+ s = JS_GetOpaque2(ctx, this_val, js_instant_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ /* Validate timeZone */
+ {
+ int64_t offset_ns;
+ JSValue r = ti_parse_temporal_timezone_string_value(ctx, argv[0], &offset_ns);
+ if (JS_IsException(r))
+ return JS_EXCEPTION;
+ JS_FreeValue(ctx, r);
+ }
+
+ /* Get canonical time zone identifier */
+ {
+ JSValue canon = ti_canonicalize_timezone_string(ctx, argv[0]);
+ const char *timeZone;
+ if (JS_IsException(canon))
+ return JS_EXCEPTION;
+ if (JS_IsUndefined(canon))
+ return JS_ThrowRangeError(ctx, "invalid time zone");
+ timeZone = JS_ToCString(ctx, canon);
+ if (!timeZone) {
+ JS_FreeValue(ctx, canon);
+ return JS_EXCEPTION;
+ }
+ result = js_create_zoneddatetime(ctx, &s->ts, timeZone, CAL_ISO8601);
+ JS_FreeCString(ctx, timeZone);
+ JS_FreeValue(ctx, canon);
+ return result;
+ }
+}
+
+/* Temporal.Instant.prototype.add */
+/* Shared implementation for Instant.prototype.add and subtract.
+ is_add: 1 for add, 0 for subtract. */
+static JSValue js_instant_add_subtract(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv, int is_add)
+{
+ (void)argc;
+ (void)ctx;
+ JSInstantData *s;
+ js_int128_t total_ns;
+ JSTimeSpec result;
+
+ s = JS_GetOpaque2(ctx, this_val, js_instant_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ if (ti_read_instant_duration_ns(ctx, argv[0], &total_ns) < 0)
+ return JS_EXCEPTION;
+
+ if (!is_add)
+ total_ns = -total_ns;
+
+ total_ns += ti_timespec_to_ns(&s->ts);
+
+ if (total_ns < (js_int128_t)(-INSTANT_MAX_SECS) * 1000000000 ||
+ total_ns > (js_int128_t)INSTANT_MAX_SECS * 1000000000)
+ return JS_ThrowRangeError(ctx, "instant arithmetic overflow");
+
+ ti_ns_to_timespec(total_ns, &result);
+ return js_create_instant(ctx, &result);
+}
+
+/* Shared implementation for Instant.prototype.until and since.
+ is_since: 0 for until (diff = other - this), 1 for since (diff = this - other) */
+static JSValue js_instant_difference(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv, int is_since)
+{
+ JSInstantData *s, *other;
+ JSValue other_val = JS_UNDEFINED;
+ JSValue options = JS_UNDEFINED;
+ JSValue v = JS_UNDEFINED;
+ JSDurationData d;
+ TIUnit smallestUnit = TI_UNIT_INVALID, largestUnit = TI_UNIT_INVALID;
+ TIRoundingMode mode = ROUND_TRUNC;
+ int64_t increment = 1;
+ js_int128_t total_ns, rounded_ns;
+
+ s = JS_GetOpaque2(ctx, this_val, js_instant_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ /* Convert other first */
+ other_val = ti_to_temporal_instant(ctx, argv[0]);
+ if (JS_IsException(other_val))
+ return JS_EXCEPTION;
+ other = JS_GetOpaque(other_val, js_instant_class_id);
+ if (!other) {
+ JS_FreeValue(ctx, other_val);
+ return JS_EXCEPTION;
+ }
+
+ /* Parse options: GetOptionsObject semantics */
+ if (argc >= 2 && !JS_IsUndefined(argv[1])) {
+ if (!JS_IsObject(argv[1])) {
+ JS_FreeValue(ctx, other_val);
+ return JS_ThrowTypeError(ctx, "options must be an object");
+ }
+ options = JS_DupValue(ctx, argv[1]);
+
+ if (ti_parse_unit_option(ctx, options, "largestUnit", &largestUnit, TI_UNIT_OPT_ALLOW_UNDEFINED, TI_UNIT_INVALID) < 0)
+ goto fail;
+ if (ti_get_rounding_increment_option(ctx, options, &increment) < 0)
+ goto fail;
+ if (ti_get_rounding_mode_option_default(ctx, options, &mode, ROUND_TRUNC) < 0)
+ goto fail;
+ if (ti_parse_unit_option(ctx, options, "smallestUnit", &smallestUnit, TI_UNIT_OPT_ALLOW_UNDEFINED, TI_UNIT_INVALID) < 0)
+ goto fail;
+
+ JS_FreeValue(ctx, options);
+ }
+
+ /* Apply defaults */
+ if (smallestUnit == TI_UNIT_INVALID) {
+ smallestUnit = TI_UNIT_NANOSECOND;
+ if (largestUnit == TI_UNIT_INVALID)
+ largestUnit = TI_UNIT_SECOND;
+ } else {
+ if (largestUnit == TI_UNIT_INVALID) {
+ if (smallestUnit < TI_UNIT_SECOND)
+ largestUnit = smallestUnit;
+ else
+ largestUnit = TI_UNIT_SECOND;
+ }
+ }
+
+ /* Validate units are time units (not date units) */
+ if (largestUnit != TI_UNIT_INVALID && !ti_unit_is_time_unit(largestUnit)) {
+ JS_FreeValue(ctx, other_val);
+ return JS_ThrowRangeError(ctx, "invalid largestUnit");
+ }
+ if (smallestUnit != TI_UNIT_INVALID && !ti_unit_is_time_unit(smallestUnit)) {
+ JS_FreeValue(ctx, other_val);
+ return JS_ThrowRangeError(ctx, "invalid smallestUnit");
+ }
+
+ /* Validate smallestUnit <= largestUnit (fineness) */
+ if (smallestUnit < largestUnit) {
+ JS_FreeValue(ctx, other_val);
+ return JS_ThrowRangeError(ctx, "smallestUnit must not be larger than largestUnit");
+ }
+
+ /* Validate roundingIncrement against maximum for smallestUnit */
+ if (smallestUnit != TI_UNIT_INVALID && increment > 1) {
+ int64_t maximum;
+ switch (smallestUnit) {
+ case TI_UNIT_HOUR: maximum = 24; break;
+ case TI_UNIT_MINUTE: maximum = 60; break;
+ case TI_UNIT_SECOND: maximum = 60; break;
+ case TI_UNIT_MILLISECOND: maximum = 1000; break;
+ case TI_UNIT_MICROSECOND: maximum = 1000; break;
+ case TI_UNIT_NANOSECOND: maximum = 1000; break;
+ default: maximum = 0; break;
+ }
+ if (maximum > 0) {
+ int64_t max_allowed = maximum - 1; /* inclusive = false */
+ if (increment > max_allowed || maximum % increment != 0) {
+ JS_FreeValue(ctx, other_val);
+ return JS_ThrowRangeError(ctx, "roundingIncrement does not divide evenly into the unit");
+ }
+ }
+ }
+
+ /* Compute diff in nanoseconds using js_int128_t to avoid overflow */
+ if (is_since) {
+ total_ns = ti_timespec_to_ns(&s->ts);
+ total_ns -= ti_timespec_to_ns(&other->ts);
+ } else {
+ total_ns = ti_timespec_to_ns(&other->ts);
+ total_ns -= ti_timespec_to_ns(&s->ts);
+ }
+
+ /* Round to smallestUnit */
+ {
+ int64_t unit_ns = ti_unit_to_ns(smallestUnit);
+ int64_t inc_ns = unit_ns * increment;
+ rounded_ns = ti_round_to_increment128(total_ns, inc_ns, mode);
+ }
+
+ /* Convert to Duration */
+ ti_ns_to_duration(rounded_ns, largestUnit, &d);
+
+ JS_FreeValue(ctx, other_val);
+ return js_create_duration(ctx, &d);
+
+fail:
+ JS_FreeValue(ctx, v);
+ JS_FreeValue(ctx, options);
+ JS_FreeValue(ctx, other_val);
+ return JS_EXCEPTION;
+}
+
+/* Temporal.Instant.prototype.until */
+/* Temporal.Instant.prototype.subtract */
+/* Convert epoch seconds to ISO date components */
+void ti_epoch_sec_to_date(int64_t epoch_sec, int64_t *year, int *month, int *day,
+ int *hour, int *minute, int *second)
+{
+ int64_t days, doy, y, m, d = 1, rem;
+ int is_leap;
+ static const int mdays_cum[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
+
+ days = floor_div64(epoch_sec, 86400ULL);
+ rem = epoch_sec - days * 86400LL;
+
+ if (hour) {
+ *hour = (int)(rem / 3600);
+ rem %= 3600;
+ }
+ if (minute) {
+ *minute = (int)(rem / 60);
+ rem %= 60;
+ }
+ if (second)
+ *second = (int)(rem % 60);
+
+ /* Find year from days since 1970-01-01 */
+ y = 1970;
+ if (days >= 0) {
+ while (days >= 365 + ti_is_leap_year(y)) {
+ days -= 365 + ti_is_leap_year(y);
+ y++;
+ }
+ } else {
+ while (days < 0) {
+ y--;
+ days += 365 + ti_is_leap_year(y);
+ }
+ }
+ is_leap = ti_is_leap_year(y);
+ doy = days;
+
+ /* Find month from day-of-year */
+ for (m = 11; m >= 0; m--) {
+ int start = mdays_cum[(int)m];
+ if (m >= 2)
+ start += is_leap;
+ if (doy >= start) {
+ d = doy - start + 1;
+ break;
+ }
+ }
+
+ if (year)
+ *year = y;
+ if (month)
+ *month = (int)m + 1;
+ if (day)
+ *day = (int)d;
+}
+
+/* Format Instant as ISO string */
+static JSValue js_instant_toString(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSInstantData *s = JS_GetOpaque2(ctx, this_val, js_instant_class_id);
+ char buf[64];
+ int64_t year;
+ int month, day, hour, minute, second;
+ int64_t epoch_sec;
+ uint32_t nsec;
+ int n;
+ int64_t unit_ns = 1; /* default nanosecond */
+ int show_seconds = 1; /* 1 = show seconds field */
+ int frac_digits = -1; /* -1 = auto, 0-9 = explicit */
+ int has_smallestUnit = 0;
+ int has_timezone = 0;
+ int64_t offset_sec = 0;
+ char tz_name[64] = "";
+ TIRoundingMode mode = ROUND_TRUNC;
+ JSValue options = JS_UNDEFINED;
+
+ if (!s)
+ return JS_EXCEPTION;
+
+ /* Parse options if provided */
+ if (argc > 0 && !JS_IsUndefined(argv[0])) {
+ int fsd_is_auto = 0, fsd_num = 0;
+ JSValue v_tz;
+ int su_valid = 0;
+
+ if (!JS_IsObject(argv[0]))
+ return JS_ThrowTypeError(ctx, "options must be an object");
+ options = JS_DupValue(ctx, argv[0]);
+
+ /* Read all options in spec order before any algorithmic validation */
+ /* fractionalSecondDigits */
+ {
+ int fsd = ti_get_fractional_second_digits_option(ctx, options, &fsd_num);
+ if (fsd < 0) {
+ JS_FreeValue(ctx, options);
+ return JS_EXCEPTION;
+ }
+ if (fsd_num == -1)
+ fsd_is_auto = 1;
+ else
+ fsd_is_auto = 0;
+ }
+
+ /* roundingMode */
+ if (ti_get_rounding_mode_option_default(ctx, options, &mode, ROUND_TRUNC) < 0) {
+ JS_FreeValue(ctx, options);
+ return JS_EXCEPTION;
+ }
+
+ /* smallestUnit */
+ {
+ TIUnit su = TI_UNIT_INVALID;
+ if (ti_parse_unit_option(ctx, options, "smallestUnit", &su, TI_UNIT_OPT_ALLOW_UNDEFINED, TI_UNIT_INVALID) < 0) {
+ JS_FreeValue(ctx, options);
+ return JS_EXCEPTION;
+ }
+ if (su != TI_UNIT_INVALID) {
+ has_smallestUnit = 1;
+ switch (su) {
+ case TI_UNIT_MINUTE:
+ unit_ns = 60000000000LL; show_seconds = 0; frac_digits = 0; su_valid = 1; break;
+ case TI_UNIT_SECOND:
+ unit_ns = 1000000000LL; show_seconds = 1; frac_digits = 0; su_valid = 1; break;
+ case TI_UNIT_MILLISECOND:
+ unit_ns = 1000000LL; show_seconds = 1; frac_digits = 3; su_valid = 1; break;
+ case TI_UNIT_MICROSECOND:
+ unit_ns = 1000LL; show_seconds = 1; frac_digits = 6; su_valid = 1; break;
+ case TI_UNIT_NANOSECOND:
+ unit_ns = 1LL; show_seconds = 1; frac_digits = 9; su_valid = 1; break;
+ default:
+ break;
+ }
+ }
+ }
+
+ /* timeZone */
+ v_tz = JS_GetPropertyStr(ctx, options, "timeZone");
+ if (JS_IsException(v_tz)) {
+ JS_FreeValue(ctx, options);
+ return JS_EXCEPTION;
+ }
+ if (!JS_IsUndefined(v_tz)) {
+ int64_t offset_ns;
+ const char *tz_str;
+ int ret;
+ if (!JS_IsString(v_tz)) {
+ JS_FreeValue(ctx, v_tz);
+ JS_FreeValue(ctx, options);
+ return JS_ThrowTypeError(ctx, "timeZone must be a string");
+ }
+ tz_str = JS_ToCString(ctx, v_tz);
+ ret = ti_parse_temporal_timezone_string(tz_str, &offset_ns);
+ if (ret < 0) {
+ JS_FreeCString(ctx, tz_str);
+ JS_FreeValue(ctx, v_tz);
+ JS_FreeValue(ctx, options);
+ return JS_ThrowRangeError(ctx, "invalid time zone");
+ }
+ if (offset_ns == 0) {
+ /* Named timezone - try full string first, then extract from brackets */
+ if (ti_tz_find_id(tz_str) >= 0) {
+ pstrcpy(tz_name, sizeof(tz_name), tz_str);
+ } else {
+ const char *bo = strchr(tz_str, '[');
+ const char *bc = bo ? strchr(bo, ']') : NULL;
+ if (bo && bc && bc[1] == '\0' && bc > bo + 1) {
+ int inner_len = (int)(bc - bo - 1);
+ if (inner_len < (int)sizeof(tz_name)) {
+ memcpy(tz_name, bo + 1, (size_t)inner_len);
+ tz_name[inner_len] = '\0';
+ }
+ }
+ }
+ } else {
+ offset_sec = offset_ns / 1000000000;
+ }
+ has_timezone = 1;
+ JS_FreeCString(ctx, tz_str);
+ JS_FreeValue(ctx, v_tz);
+ } else {
+ JS_FreeValue(ctx, v_tz);
+ }
+
+ JS_FreeValue(ctx, options);
+
+ /* Validate smallestUnit after all reads */
+ if (has_smallestUnit && !su_valid)
+ return JS_ThrowRangeError(ctx, "invalid smallestUnit");
+
+ /* Apply fractionalSecondDigits only if smallestUnit is not present */
+ if (!has_smallestUnit && !fsd_is_auto) {
+ frac_digits = fsd_num;
+ }
+ }
+
+ epoch_sec = s->ts.secs;
+ nsec = s->ts.nsecs;
+
+ /* Apply rounding/truncation based on smallestUnit */
+ if (unit_ns > 1 || frac_digits >= 0) {
+ js_int128_t total_ns;
+ js_int128_t rounded_ns;
+
+ /* Use js_int128_t to avoid overflow for large negative epoch seconds */
+ total_ns = ti_sec_nsec_to_ns(epoch_sec, nsec);
+
+ if (unit_ns > 1) {
+ rounded_ns = ti_round_to_increment_as_if_positive128(total_ns, unit_ns, mode);
+ } else if (frac_digits >= 0) {
+ js_int128_t inc = 1;
+ int i;
+ for (i = 0; i < (9 - frac_digits); i++)
+ inc *= 10;
+ rounded_ns = ti_round_to_increment_as_if_positive128(total_ns, inc, mode);
+ } else {
+ rounded_ns = total_ns;
+ }
+
+ epoch_sec = (int64_t)(rounded_ns / 1000000000);
+ nsec = (uint32_t)(rounded_ns % 1000000000);
+ if (rounded_ns < 0 && nsec != 0) {
+ nsec += 1000000000;
+ epoch_sec -= 1;
+ }
+ }
+
+ /* Apply time zone offset for display */
+ if (has_timezone && tz_name[0] != '\0') {
+ int tz_id = ti_tz_find_id(tz_name);
+ if (tz_id >= 0)
+ offset_sec = ti_tz_offset_at_sec(tz_id, epoch_sec);
+ }
+ if (has_timezone)
+ epoch_sec += offset_sec;
+
+ /* Round offset to nearest minute for display (half-expand away from zero) */
+ if (has_timezone) {
+ if (offset_sec >= 0)
+ offset_sec = (offset_sec + 30) / 60 * 60;
+ else
+ offset_sec = (offset_sec - 30) / 60 * 60;
+ }
+
+ ti_epoch_sec_to_date(epoch_sec, &year, &month, &day, &hour, &minute, &second);
+
+ if (year < 0) {
+ n = snprintf(buf, sizeof(buf), "-%06" PRId64 "-%02d-%02dT%02d:%02d",
+ -year, month, day, hour, minute);
+ } else if (year >= 10000) {
+ n = snprintf(buf, sizeof(buf), "+%06" PRId64 "-%02d-%02dT%02d:%02d",
+ year, month, day, hour, minute);
+ } else {
+ n = snprintf(buf, sizeof(buf), "%04" PRId64 "-%02d-%02dT%02d:%02d",
+ year, month, day, hour, minute);
+ }
+
+ if (show_seconds) {
+ int m = snprintf(buf + n, sizeof(buf) - (size_t)n, ":%02d", second);
+ n += m;
+
+ if (frac_digits == 0) {
+ if (has_timezone) {
+ int off_sec = (int)(offset_sec >= 0 ? offset_sec : -offset_sec);
+ snprintf(buf + n, sizeof(buf) - (size_t)n, "%c%02d:%02d",
+ offset_sec >= 0 ? '+' : '-', off_sec / 3600, (off_sec % 3600) / 60);
+ } else {
+ snprintf(buf + n, sizeof(buf) - (size_t)n, "Z");
+ }
+ } else if (frac_digits > 0) {
+ char frac[16];
+ snprintf(frac, sizeof(frac), "%09u", nsec);
+ frac[frac_digits] = '\0';
+ if (has_timezone) {
+ int off_sec = (int)(offset_sec >= 0 ? offset_sec : -offset_sec);
+ snprintf(buf + n, sizeof(buf) - (size_t)n, ".%s%c%02d:%02d", frac,
+ offset_sec >= 0 ? '+' : '-', off_sec / 3600, (off_sec % 3600) / 60);
+ } else {
+ snprintf(buf + n, sizeof(buf) - (size_t)n, ".%sZ", frac);
+ }
+ } else {
+ /* Auto: show only non-zero fraction digits */
+ if (nsec > 0) {
+ char frac[16];
+ int frac_n;
+ frac_n = snprintf(frac, sizeof(frac), "%09u", nsec);
+ while (frac_n > 0 && frac[frac_n - 1] == '0')
+ frac_n--;
+ frac[frac_n] = '\0';
+ if (has_timezone) {
+ int off_sec = (int)(offset_sec >= 0 ? offset_sec : -offset_sec);
+ snprintf(buf + n, sizeof(buf) - (size_t)n, ".%s%c%02d:%02d", frac,
+ offset_sec >= 0 ? '+' : '-', off_sec / 3600, (off_sec % 3600) / 60);
+ } else {
+ snprintf(buf + n, sizeof(buf) - (size_t)n, ".%sZ", frac);
+ }
+ } else {
+ if (has_timezone) {
+ int off_sec = (int)(offset_sec >= 0 ? offset_sec : -offset_sec);
+ snprintf(buf + n, sizeof(buf) - (size_t)n, "%c%02d:%02d",
+ offset_sec >= 0 ? '+' : '-', off_sec / 3600, (off_sec % 3600) / 60);
+ } else {
+ snprintf(buf + n, sizeof(buf) - (size_t)n, "Z");
+ }
+ }
+ }
+ } else {
+ if (has_timezone) {
+ int off_sec = (int)(offset_sec >= 0 ? offset_sec : -offset_sec);
+ snprintf(buf + n, sizeof(buf) - (size_t)n, "%c%02d:%02d",
+ offset_sec >= 0 ? '+' : '-', off_sec / 3600, (off_sec % 3600) / 60);
+ } else {
+ snprintf(buf + n, sizeof(buf) - (size_t)n, "Z");
+ }
+ }
+
+ return JS_NewString(ctx, buf);
+}
+
+static const JSCFunctionListEntry js_instant_proto_funcs[] = {
+ JS_CGETSET_DEF("epochMilliseconds", js_instant_get_epochMilliseconds, NULL),
+ JS_CGETSET_DEF("epochNanoseconds", js_instant_get_epochNanoseconds, NULL),
+ JS_CFUNC_DEF("equals", 1, js_instant_equals),
+ JS_CFUNC_DEF("toString", 0, js_instant_toString),
+ JS_CFUNC_DEF("toJSON", 0, js_instant_toJSON),
+ JS_CFUNC_DEF("toLocaleString", 0, js_instant_toLocaleString),
+ JS_CFUNC_DEF("toZonedDateTimeISO", 1, js_instant_toZonedDateTimeISO),
+ JS_CFUNC_MAGIC_DEF("add", 1, js_instant_add_subtract, 1),
+ JS_CFUNC_MAGIC_DEF("subtract", 1, js_instant_add_subtract, 0),
+ JS_CFUNC_MAGIC_DEF("until", 1, js_instant_difference, 0),
+ JS_CFUNC_MAGIC_DEF("since", 1, js_instant_difference, 1),
+ JS_CFUNC_DEF("round", 1, js_instant_round),
+ JS_CFUNC_DEF("valueOf", 0, js_instant_valueOf),
+ JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Temporal.Instant", JS_PROP_CONFIGURABLE),
+};
+
+static const JSCFunctionListEntry js_instant_static_funcs[] = {
+ JS_CFUNC_DEF("from", 1, js_instant_from),
+ JS_CFUNC_DEF("fromEpochMilliseconds", 1, js_instant_fromEpochMilliseconds),
+ JS_CFUNC_DEF("fromEpochNanoseconds", 1, js_instant_fromEpochNanoseconds),
+ JS_CFUNC_DEF("compare", 2, js_instant_compare),
+};
+
+int js_add_instant(JSContext *ctx, JSValue temporal_obj)
+{
+ JSValue ctor;
+
+ JS_NewClassID(&js_instant_class_id);
+ JS_NewClass(JS_GetRuntime(ctx), js_instant_class_id, &js_instant_class);
+
+ ctor = JS_NewCConstructor(ctx, (int)js_instant_class_id, "Instant",
+ (JSCFunction *)js_instant_constructor, 1,
+ JS_CFUNC_constructor, 0,
+ JS_UNDEFINED,
+ js_instant_static_funcs, countof(js_instant_static_funcs),
+ js_instant_proto_funcs, countof(js_instant_proto_funcs),
+ JS_NEW_CTOR_NO_GLOBAL);
+ if (JS_IsException(ctor))
+ return -1;
+ if (JS_DefinePropertyValueStr(ctx, temporal_obj, "Instant", ctor,
+ JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE) < 0)
+ return -1;
+ return 0;
+}
--- /dev/null
+/*
+ * QuickJS Temporal.Now implementation (minimal)
+ */
+
+#include <time.h>
+
+#include "../quickjs.h"
+#include "../cutils.h"
+#include "temporal_private.h"
+
+static int now_get_system_time(JSTimeSpec *ts)
+{
+ struct timespec t;
+ if (clock_gettime(CLOCK_REALTIME, &t) != 0)
+ return -1;
+ ts->secs = t.tv_sec;
+ ts->nsecs = (uint32_t)t.tv_nsec;
+ return 0;
+}
+
+/* Temporal.Now.instant() */
+static JSValue js_now_instant(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ (void)argc;
+ (void)argv;
+ (void)this_val;
+ JSTimeSpec ts;
+ if (now_get_system_time(&ts) < 0)
+ return JS_ThrowInternalError(ctx, "cannot get system time");
+ return js_create_instant(ctx, &ts);
+}
+
+/* Get canonical timezone string. Returns a newly allocated C string
+ that must be freed with js_free, or NULL on error/exception. */
+static char *now_get_canonical_timezone(JSContext *ctx, JSValueConst val)
+{
+ const char *str;
+ char buf[64];
+ int64_t offset_ns;
+ int ret;
+
+ if (JS_IsUndefined(val)) {
+ char tz[TI_TIMEZONE_BUF_SIZE];
+ ti_get_default_timezone(tz, sizeof(tz));
+ return js_strdup(ctx, tz);
+ }
+
+ if (!JS_IsString(val)) {
+ JS_ThrowTypeError(ctx, "invalid time zone");
+ return NULL;
+ }
+
+ str = JS_ToCString(ctx, val);
+ if (!str)
+ return NULL;
+
+ ret = ti_parse_temporal_timezone_string(str, &offset_ns);
+ if (ret < 0) {
+ JS_FreeCString(ctx, str);
+ JS_ThrowRangeError(ctx, "invalid time zone");
+ return NULL;
+ }
+
+ if (ti_canonicalize_timezone_identifier(str, offset_ns, buf, sizeof(buf)) < 0) {
+ JS_FreeCString(ctx, str);
+ JS_ThrowRangeError(ctx, "invalid time zone");
+ return NULL;
+ }
+
+ JS_FreeCString(ctx, str);
+ return js_strdup(ctx, buf);
+}
+
+/* Temporal.Now.plainDateISO(timeZone) */
+static JSValue js_now_plainDateISO(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ (void)this_val;
+ JSTimeSpec ts;
+ int64_t year;
+ int month, day;
+ char *tz_str;
+
+ tz_str = now_get_canonical_timezone(ctx, argc > 0 ? argv[0] : JS_UNDEFINED);
+ if (!tz_str)
+ return JS_EXCEPTION;
+
+ if (now_get_system_time(&ts) < 0) {
+ js_free(ctx, tz_str);
+ return JS_ThrowInternalError(ctx, "cannot get system time");
+ }
+
+ ti_zoneddatetime_to_local(tz_str, ts.secs, (int)ts.nsecs,
+ &year, &month, &day, NULL, NULL, NULL, NULL, NULL, NULL);
+ js_free(ctx, tz_str);
+ return js_create_plaindate(ctx, (int)year, month, day);
+}
+
+/* Temporal.Now.plainTimeISO(timeZone) */
+static JSValue js_now_plainTimeISO(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ (void)this_val;
+ JSTimeSpec ts;
+ JSPlainTimeData pt = {0};
+ char *tz_str;
+
+ tz_str = now_get_canonical_timezone(ctx, argc > 0 ? argv[0] : JS_UNDEFINED);
+ if (!tz_str)
+ return JS_EXCEPTION;
+
+ if (now_get_system_time(&ts) < 0) {
+ js_free(ctx, tz_str);
+ return JS_ThrowInternalError(ctx, "cannot get system time");
+ }
+
+ ti_zoneddatetime_to_local(tz_str, ts.secs, (int)ts.nsecs,
+ NULL, NULL, NULL,
+ &pt.hour, &pt.minute, &pt.second,
+ &pt.millisecond, &pt.microsecond, &pt.nanosecond);
+ js_free(ctx, tz_str);
+ return js_create_plaintime(ctx, &pt);
+}
+
+/* Temporal.Now.plainDateTimeISO(timeZone) */
+static JSValue js_now_plainDateTimeISO(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ (void)this_val;
+ JSTimeSpec ts;
+ int64_t year;
+ int month, day, hour, minute, second, ms, us, ns;
+ char *tz_str;
+
+ tz_str = now_get_canonical_timezone(ctx, argc > 0 ? argv[0] : JS_UNDEFINED);
+ if (!tz_str)
+ return JS_EXCEPTION;
+
+ if (now_get_system_time(&ts) < 0) {
+ js_free(ctx, tz_str);
+ return JS_ThrowInternalError(ctx, "cannot get system time");
+ }
+
+ ti_zoneddatetime_to_local(tz_str, ts.secs, (int)ts.nsecs,
+ &year, &month, &day,
+ &hour, &minute, &second,
+ &ms, &us, &ns);
+ js_free(ctx, tz_str);
+ return js_create_plaindatetime(ctx, (int)year, month, day,
+ hour, minute, second, ms, us, ns);
+}
+
+/* Temporal.Now.zonedDateTimeISO([timeZone]) */
+static JSValue js_now_zonedDateTimeISO(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ (void)this_val;
+ JSTimeSpec ts;
+ JSValue result;
+ char *tz_str;
+
+ tz_str = now_get_canonical_timezone(ctx, argc > 0 ? argv[0] : JS_UNDEFINED);
+ if (!tz_str)
+ return JS_EXCEPTION;
+
+ if (now_get_system_time(&ts) < 0) {
+ js_free(ctx, tz_str);
+ return JS_ThrowInternalError(ctx, "cannot get system time");
+ }
+
+ result = js_create_zoneddatetime(ctx, &ts, tz_str, CAL_ISO8601);
+ js_free(ctx, tz_str);
+ return result;
+}
+
+/* Temporal.Now.timeZoneId() */
+static JSValue js_now_timeZoneId(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ (void)ctx;
+ (void)this_val;
+ JSValue r;
+ char tz[TI_TIMEZONE_BUF_SIZE];
+ (void)argc; (void)argv;
+ ti_get_default_timezone(tz, sizeof(tz));
+ r = JS_NewString(ctx, tz);
+ return r;
+}
+
+static const JSCFunctionListEntry js_now_funcs[] = {
+ JS_CFUNC_DEF("instant", 0, js_now_instant),
+ JS_CFUNC_DEF("plainDateISO", 0, js_now_plainDateISO),
+ JS_CFUNC_DEF("plainDateTimeISO", 0, js_now_plainDateTimeISO),
+ JS_CFUNC_DEF("plainTimeISO", 0, js_now_plainTimeISO),
+ JS_CFUNC_DEF("zonedDateTimeISO", 0, js_now_zonedDateTimeISO),
+ JS_CFUNC_DEF("timeZoneId", 0, js_now_timeZoneId),
+ JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Temporal.Now", JS_PROP_CONFIGURABLE),
+};
+
+int js_add_now(JSContext *ctx, JSValue temporal_obj)
+{
+ JSValue now_obj;
+ now_obj = JS_NewObject(ctx);
+ if (JS_IsException(now_obj))
+ return -1;
+ if (JS_SetPropertyFunctionList(ctx, now_obj, js_now_funcs,
+ countof(js_now_funcs)) < 0) {
+ JS_FreeValue(ctx, now_obj);
+ return -1;
+ }
+ if (JS_DefinePropertyValueStr(ctx, temporal_obj, "Now", now_obj,
+ JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE) < 0) {
+ JS_FreeValue(ctx, now_obj);
+ return -1;
+ }
+ return 0;
+}
--- /dev/null
+/*
+ * QuickJS Temporal.PlainDate implementation (minimal)
+ */
+
+#include <string.h>
+#include <math.h>
+
+#include "../quickjs.h"
+#include "../cutils.h"
+#include "temporal_private.h"
+
+JSClassID js_plaindate_class_id;
+
+static void js_plaindate_finalizer(JSRuntime *rt, JSValue val)
+{
+ JSPlainDateData *s = JS_GetOpaque(val, js_plaindate_class_id);
+ if (s)
+ js_free_rt(rt, s);
+}
+
+static const JSClassDef js_plaindate_class = {
+ "Temporal.PlainDate",
+ .finalizer = js_plaindate_finalizer,
+};
+
+JSValue js_create_plaindate_with_calendar(JSContext *ctx, int year, int month, int day, CalendarType calendar)
+{
+ if (calendar == CAL_ISO8601 || calendar == CAL_GREGORY) {
+ /* ISO date range: -271821-04-19 to +275760-09-13 */
+ if (year < -271821 || year > 275760 ||
+ (year == -271821 && (month < 4 || (month == 4 && day < 19))) ||
+ (year == 275760 && (month > 9 || (month == 9 && day > 13))))
+ return JS_ThrowRangeError(ctx, "PlainDate out of range");
+ }
+ {
+ JSPlainDateData *s;
+ JSValue obj;
+ s = js_mallocz(ctx, sizeof(*s));
+ if (!s)
+ return JS_EXCEPTION;
+ s->year = year;
+ s->month = month;
+ s->day = day;
+ s->calendar = calendar;
+ obj = JS_NewObjectClass(ctx, (int)js_plaindate_class_id);
+ if (JS_IsException(obj)) {
+ js_free(ctx, s);
+ return JS_EXCEPTION;
+ }
+ JS_SetOpaque(obj, s);
+ return obj;
+ }
+}
+
+JSValue js_create_plaindate(JSContext *ctx, int year, int month, int day)
+{
+ return js_create_plaindate_with_calendar(ctx, year, month, day, CAL_ISO8601);
+}
+
+JSValue ti_create_plaindate_from_fields(JSContext *ctx, TIPreparedFields *fields,
+ int overflow_constrain)
+{
+ int year, month, day;
+ JSValue obj;
+
+ if (ti_resolve_date_from_fields(ctx, fields, overflow_constrain, &year, &month, &day, 1) < 0)
+ return JS_EXCEPTION;
+
+ {
+ int iso_y = year, iso_m = month, iso_d = day;
+ if (fields->calendar != CAL_ISO8601 && fields->calendar != CAL_GREGORY) {
+ ti_calendar_date_to_iso(fields->calendar, year, month, day, &iso_y, &iso_m, &iso_d);
+ }
+ obj = js_create_plaindate_with_calendar(ctx, iso_y, iso_m, iso_d, fields->calendar);
+ }
+ return obj;
+}
+
+int pd_is_leap_year(int year)
+{
+ return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
+}
+
+int pd_days_in_month(int year, int month)
+{
+ static const int days[] = {31,28,31,30,31,30,31,31,30,31,30,31};
+ if (month == 2 && pd_is_leap_year(year))
+ return 29;
+ return days[month - 1];
+}
+
+int pd_is_valid_date(int year, int month, int day)
+{
+ if (month < 1 || month > 12)
+ return 0;
+ if (day < 1 || day > pd_days_in_month(year, month))
+ return 0;
+ return 1;
+}
+
+/* Convert stored ISO date to calendar date for the object's calendar */
+static void pd_get_calendar_date(JSPlainDateData *s, int *cal_year, int *cal_month, int *cal_day)
+{
+ ti_iso_to_calendar_date(s->calendar, s->year, s->month, s->day, cal_year, cal_month, cal_day);
+}
+
+static int pd_is_valid_date_for_calendar(int year, int month, int day, CalendarType cal)
+{
+ int max_month = ti_calendar_months_in_year(cal, year);
+ if (month < 1 || month > max_month)
+ return 0;
+ {
+ int dim = ti_calendar_days_in_month(cal, year, month);
+ if (day < 1 || day > dim)
+ return 0;
+ }
+ return 1;
+}
+
+static int pd_to_integer_with_truncation(JSContext *ctx, JSValueConst val, int *pres)
+{
+ double d;
+ if (JS_ToFloat64(ctx, &d, val))
+ return -1;
+ if (!isfinite(d)) {
+ JS_ThrowRangeError(ctx, "value must be an integer");
+ return -1;
+ }
+ if (d < INT32_MIN || d > INT32_MAX) {
+ JS_ThrowRangeError(ctx, "value out of range");
+ return -1;
+ }
+ *pres = (int)(d < 0 ? ceil(d) : floor(d));
+ return 0;
+}
+
+/* Temporal.PlainDate constructor */
+static JSValue js_plaindate_constructor(JSContext *ctx, JSValueConst new_target,
+ int argc, JSValueConst *argv)
+{
+ int year, month, day;
+ if (JS_IsUndefined(new_target)) {
+ return JS_ThrowTypeError(ctx, "Temporal.PlainDate constructor cannot be called as a function");
+ }
+ if (pd_to_integer_with_truncation(ctx, argv[0], &year) < 0)
+ return JS_EXCEPTION;
+ if (pd_to_integer_with_truncation(ctx, argv[1], &month) < 0)
+ return JS_EXCEPTION;
+ if (pd_to_integer_with_truncation(ctx, argv[2], &day) < 0)
+ return JS_EXCEPTION;
+ if (!pd_is_valid_date(year, month, day))
+ return JS_ThrowRangeError(ctx, "invalid PlainDate");
+ if (year < -271821 || year > 275760 ||
+ (year == -271821 && (month < 4 || (month == 4 && day < 19))) ||
+ (year == 275760 && (month > 9 || (month == 9 && day > 13))))
+ return JS_ThrowRangeError(ctx, "PlainDate out of range");
+ {
+ JSPlainDateData *s = js_mallocz(ctx, sizeof(*s));
+ JSValue obj;
+ if (!s)
+ return JS_EXCEPTION;
+ s->year = year;
+ s->month = month;
+ s->day = day;
+ s->calendar = CAL_ISO8601;
+ if (argc > 3) {
+ int cal_res = ti_validate_constructor_calendar(ctx, argv[3], &s->calendar);
+ if (cal_res < 0) {
+ js_free(ctx, s);
+ return JS_EXCEPTION;
+ }
+ }
+ obj = js_create_temporal_object(ctx, new_target, js_plaindate_class_id, s);
+ if (JS_IsException(obj)) {
+ js_free(ctx, s);
+ return JS_EXCEPTION;
+ }
+ return obj;
+ }
+}
+
+/* Getters */
+/* Getters */
+enum {
+ PLAINDATE_YEAR = 0,
+ PLAINDATE_MONTH,
+ PLAINDATE_DAY,
+};
+
+static JSValue js_plaindate_get_field(JSContext *ctx, JSValueConst this_val, int magic)
+{
+ JSPlainDateData *s = JS_GetOpaque2(ctx, this_val, js_plaindate_class_id);
+ int cal_year, cal_month, cal_day;
+ if (!s)
+ return JS_EXCEPTION;
+ pd_get_calendar_date(s, &cal_year, &cal_month, &cal_day);
+ switch (magic) {
+ case PLAINDATE_YEAR: return JS_NewInt32(ctx, cal_year);
+ case PLAINDATE_MONTH: return JS_NewInt32(ctx, cal_month);
+ case PLAINDATE_DAY: return JS_NewInt32(ctx, cal_day);
+ default: return JS_UNDEFINED;
+ }
+}
+
+static JSValue js_plaindate_get_monthCode(JSContext *ctx, JSValueConst this_val)
+{
+ JSPlainDateData *s = JS_GetOpaque2(ctx, this_val, js_plaindate_class_id);
+ int cal_year, cal_month, cal_day;
+ if (!s)
+ return JS_EXCEPTION;
+ pd_get_calendar_date(s, &cal_year, &cal_month, &cal_day);
+ return ti_get_month_code(ctx, s->calendar, cal_year, cal_month);
+}
+
+static JSValue js_plaindate_get_calendarId(JSContext *ctx, JSValueConst this_val)
+{
+ JSPlainDateData *s = JS_GetOpaque2(ctx, this_val, js_plaindate_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ return JS_NewString(ctx, ti_calendar_enum_to_string(s->calendar));
+}
+
+static JSValue js_plaindate_get_era(JSContext *ctx, JSValueConst this_val)
+{
+ JSPlainDateData *s = JS_GetOpaque2(ctx, this_val, js_plaindate_class_id);
+ int era_year;
+ TIEra era;
+ int cal_y, cal_m, cal_d;
+ if (!s)
+ return JS_EXCEPTION;
+ pd_get_calendar_date(s, &cal_y, &cal_m, &cal_d);
+ ti_calendar_era_and_era_year(s->calendar, s->year, s->month, s->day, cal_y, &era, &era_year);
+ if (era != TI_ERA_UNKNOWN)
+ return JS_NewString(ctx, ti_era_to_string(era));
+ return JS_UNDEFINED;
+}
+
+static JSValue js_plaindate_get_eraYear(JSContext *ctx, JSValueConst this_val)
+{
+ JSPlainDateData *s = JS_GetOpaque2(ctx, this_val, js_plaindate_class_id);
+ int era_year;
+ TIEra era;
+ int cal_y, cal_m, cal_d;
+ if (!s)
+ return JS_EXCEPTION;
+ pd_get_calendar_date(s, &cal_y, &cal_m, &cal_d);
+ ti_calendar_era_and_era_year(s->calendar, s->year, s->month, s->day, cal_y, &era, &era_year);
+ if (era != TI_ERA_UNKNOWN)
+ return JS_NewInt32(ctx, era_year);
+ return JS_UNDEFINED;
+}
+
+static int pd_day_of_week(int year, int month, int day)
+{
+ int a = (14 - month) / 12;
+ int y = year - a;
+ int m = month + 12 * a - 2;
+ int d = (day + y + floor_div32(y, 4) - floor_div32(y, 100) + floor_div32(y, 400) + (31 * m) / 12) % 7;
+ if (d <= 0)
+ d += 7;
+ return d;
+}
+
+int pd_day_of_year(int year, int month, int day)
+{
+ int doy = day;
+ int i;
+ for (i = 1; i < month; i++)
+ doy += ti_iso_month_days[i];
+ if (month > 2 && pd_is_leap_year(year))
+ doy++;
+ return doy;
+}
+
+static void pd_iso_week(int year, int month, int day, int *weekYear, int *weekNumber)
+{
+ int dow = pd_day_of_week(year, month, day);
+ int ordinal = pd_day_of_year(year, month, day);
+ int thursdayOrdinal = ordinal + (4 - dow);
+ int y = year;
+ int daysInY = pd_is_leap_year(y) ? 366 : 365;
+ if (thursdayOrdinal <= 0) {
+ y = year - 1;
+ daysInY = pd_is_leap_year(y) ? 366 : 365;
+ thursdayOrdinal += daysInY;
+ } else if (thursdayOrdinal > daysInY) {
+ thursdayOrdinal -= daysInY;
+ y = year + 1;
+ }
+ *weekYear = y;
+ *weekNumber = (thursdayOrdinal - 1) / 7 + 1;
+}
+
+static JSValue js_plaindate_get_inLeapYear(JSContext *ctx, JSValueConst this_val)
+{
+ JSPlainDateData *s = JS_GetOpaque2(ctx, this_val, js_plaindate_class_id);
+ int cal_y, cal_m, cal_d;
+ if (!s)
+ return JS_EXCEPTION;
+ pd_get_calendar_date(s, &cal_y, &cal_m, &cal_d);
+ return JS_NewBool(ctx, ti_calendar_is_leap_year(s->calendar, cal_y));
+}
+
+static JSValue js_plaindate_get_daysInMonth(JSContext *ctx, JSValueConst this_val)
+{
+ JSPlainDateData *s = JS_GetOpaque2(ctx, this_val, js_plaindate_class_id);
+ int cal_y, cal_m, cal_d;
+ if (!s)
+ return JS_EXCEPTION;
+ pd_get_calendar_date(s, &cal_y, &cal_m, &cal_d);
+ return JS_NewInt32(ctx, ti_calendar_days_in_month(s->calendar, cal_y, cal_m));
+}
+
+static JSValue js_plaindate_get_daysInYear(JSContext *ctx, JSValueConst this_val)
+{
+ JSPlainDateData *s = JS_GetOpaque2(ctx, this_val, js_plaindate_class_id);
+ int cal_y, cal_m, cal_d;
+ if (!s)
+ return JS_EXCEPTION;
+ pd_get_calendar_date(s, &cal_y, &cal_m, &cal_d);
+ return JS_NewInt32(ctx, ti_calendar_days_in_year(s->calendar, cal_y));
+}
+
+static JSValue js_plaindate_get_daysInWeek(JSContext *ctx, JSValueConst this_val)
+{
+ JSPlainDateData *s = JS_GetOpaque2(ctx, this_val, js_plaindate_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ return JS_NewInt32(ctx, 7);
+}
+
+static JSValue js_plaindate_get_monthsInYear(JSContext *ctx, JSValueConst this_val)
+{
+ JSPlainDateData *s = JS_GetOpaque2(ctx, this_val, js_plaindate_class_id);
+ int cal_y, cal_m, cal_d;
+ if (!s)
+ return JS_EXCEPTION;
+ pd_get_calendar_date(s, &cal_y, &cal_m, &cal_d);
+ return JS_NewInt32(ctx, ti_calendar_months_in_year(s->calendar, cal_y));
+}
+
+static JSValue js_plaindate_get_dayOfYear(JSContext *ctx, JSValueConst this_val)
+{
+ JSPlainDateData *s = JS_GetOpaque2(ctx, this_val, js_plaindate_class_id);
+ int cal_y, cal_m, cal_d;
+ if (!s)
+ return JS_EXCEPTION;
+ pd_get_calendar_date(s, &cal_y, &cal_m, &cal_d);
+ return JS_NewInt32(ctx, ti_calendar_day_of_year(s->calendar, cal_y, cal_m, cal_d));
+}
+
+static JSValue js_plaindate_get_dayOfWeek(JSContext *ctx, JSValueConst this_val)
+{
+ JSPlainDateData *s = JS_GetOpaque2(ctx, this_val, js_plaindate_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ return JS_NewInt32(ctx, pd_day_of_week(s->year, s->month, s->day));
+}
+
+static JSValue js_plaindate_get_weekOfYear(JSContext *ctx, JSValueConst this_val)
+{
+ JSPlainDateData *s = JS_GetOpaque2(ctx, this_val, js_plaindate_class_id);
+ int weekYear, weekNumber;
+ if (!s)
+ return JS_EXCEPTION;
+ if (s->calendar != CAL_ISO8601)
+ return JS_UNDEFINED;
+ pd_iso_week(s->year, s->month, s->day, &weekYear, &weekNumber);
+ return JS_NewInt32(ctx, weekNumber);
+}
+
+static JSValue js_plaindate_get_yearOfWeek(JSContext *ctx, JSValueConst this_val)
+{
+ JSPlainDateData *s = JS_GetOpaque2(ctx, this_val, js_plaindate_class_id);
+ int weekYear, weekNumber;
+ if (!s)
+ return JS_EXCEPTION;
+ if (s->calendar != CAL_ISO8601)
+ return JS_UNDEFINED;
+ pd_iso_week(s->year, s->month, s->day, &weekYear, &weekNumber);
+ return JS_NewInt64(ctx, weekYear);
+}
+
+static JSValue js_plaindate_from(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv);
+
+/* Temporal.PlainDate.prototype.equals */
+static JSValue js_plaindate_equals(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ (void)this_val;
+ (void)argc;
+ JSPlainDateData *s, *other;
+ JSValue other_val;
+ s = JS_GetOpaque2(ctx, this_val, js_plaindate_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ if (JS_IsNumber(argv[0]) || JS_IsUndefined(argv[0]) || JS_IsNull(argv[0]) ||
+ JS_IsBool(argv[0]) || JS_IsBigInt(ctx, argv[0]))
+ return JS_ThrowTypeError(ctx, "invalid PlainDate");
+ other_val = js_plaindate_from(ctx, JS_UNDEFINED, 1, argv);
+ if (JS_IsException(other_val))
+ return JS_EXCEPTION;
+ other = JS_GetOpaque(other_val, js_plaindate_class_id);
+ if (!other) {
+ JS_FreeValue(ctx, other_val);
+ return JS_NewBool(ctx, 0);
+ }
+ {
+ int res = s->year == other->year && s->month == other->month && s->day == other->day &&
+ s->calendar == other->calendar;
+ JS_FreeValue(ctx, other_val);
+ return JS_NewBool(ctx, res);
+ }
+}
+
+/* Temporal.PlainDate.compare */
+static JSValue js_plaindate_compare(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ (void)argc;
+ (void)this_val;
+ JSPlainDateData *s1, *s2;
+ JSValue v1, v2;
+ int cmp;
+ v1 = js_plaindate_from(ctx, JS_UNDEFINED, 1, argv);
+ if (JS_IsException(v1))
+ return JS_EXCEPTION;
+ v2 = js_plaindate_from(ctx, JS_UNDEFINED, 1, argv + 1);
+ if (JS_IsException(v2)) {
+ JS_FreeValue(ctx, v1);
+ return JS_EXCEPTION;
+ }
+ s1 = JS_GetOpaque(v1, js_plaindate_class_id);
+ s2 = JS_GetOpaque(v2, js_plaindate_class_id);
+ if (!s1 || !s2) {
+ JS_FreeValue(ctx, v1);
+ JS_FreeValue(ctx, v2);
+ return JS_ThrowTypeError(ctx, "compare arguments must be PlainDate objects");
+ }
+ if (s1->year != s2->year)
+ cmp = s1->year < s2->year ? -1 : 1;
+ else if (s1->month != s2->month)
+ cmp = s1->month < s2->month ? -1 : 1;
+ else if (s1->day != s2->day)
+ cmp = s1->day < s2->day ? -1 : 1;
+ else
+ cmp = 0;
+ JS_FreeValue(ctx, v1);
+ JS_FreeValue(ctx, v2);
+ return JS_NewInt32(ctx, cmp);
+}
+
+/* Format PlainDate as ISO string */
+static JSValue js_plaindate_toString(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSPlainDateData *s;
+ char buf[64];
+ int calendarName = 0; /* 0=auto, 1=always, 2=critical, 3=never */
+ if (argc >= 1 && ti_validate_options_object(ctx, argv[0]) < 0)
+ return JS_EXCEPTION;
+ s = JS_GetOpaque2(ctx, this_val, js_plaindate_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ if (argc >= 1 && JS_IsObject(argv[0])) {
+ if (ti_get_calendar_name_option(ctx, argv[0], &calendarName) < 0)
+ return JS_EXCEPTION;
+ }
+ {
+ int fy = s->year, fm = s->month, fd = s->day;
+ if (fy < 0)
+ snprintf(buf, sizeof(buf), "-%06d-%02d-%02d", -fy, fm, fd);
+ else if (fy >= 10000)
+ snprintf(buf, sizeof(buf), "+%06d-%02d-%02d", fy, fm, fd);
+ else
+ snprintf(buf, sizeof(buf), "%04d-%02d-%02d", fy, fm, fd);
+ }
+ ti_append_calendar_annotation(buf, sizeof(buf), s->calendar, calendarName);
+ return JS_NewString(ctx, buf);
+}
+
+static JSValue js_plaindate_toJSON(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ (void)argc;
+ (void)argv;
+ return js_plaindate_toString(ctx, this_val, 0, NULL);
+}
+
+static JSValue js_plaindate_toLocaleString(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSPlainDateData *s = JS_GetOpaque2(ctx, this_val, js_plaindate_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ return ti_temporal_toLocaleString(ctx, this_val, argc, argv, 1, js_plaindate_toString);
+}
+
+static JSValue js_plaindate_valueOf(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ (void)argc;
+ (void)argv;
+ (void)this_val;
+ return JS_ThrowTypeError(ctx, "cannot compare Temporal.PlainDate with < or >");
+}
+
+/* Temporal.PlainDate.prototype.with */
+static JSValue js_plaindate_with(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSPlainDateData *s;
+ int year, month, day;
+ int orig_cal_year, orig_cal_month, orig_cal_day;
+ JSValue val;
+ int overflow_constrain = 1; /* default is constrain */
+ int month_code_iso_err = 0;
+ int month_conflict_err = 0;
+ int has_month = 0;
+ int has_year_prop = 0;
+ int with_month_code = 0;
+ int with_has_month_code = 0;
+ int with_has_l = 0;
+ TIPreparedFields fields;
+ s = JS_GetOpaque2(ctx, this_val, js_plaindate_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ ti_iso_to_calendar_date(s->calendar, s->year, s->month, s->day, &orig_cal_year, &orig_cal_month, &orig_cal_day);
+ year = orig_cal_year;
+ month = orig_cal_month;
+ day = orig_cal_day;
+ val = argv[0];
+ if (ti_is_partial_temporal_object(ctx, val) < 0)
+ return JS_EXCEPTION;
+ if (ti_prepare_calendar_fields(ctx, val,
+ TI_FIELD_DAY | TI_FIELD_MONTH | TI_FIELD_MONTH_CODE |
+ TI_FIELD_YEAR,
+ 0, 1, &fields, s->calendar) < 0)
+ return JS_EXCEPTION;
+ /* Merge fields with existing object */
+ if (fields.present_mask & TI_FIELD_DAY) {
+ day = fields.day;
+ }
+ if (fields.present_mask & TI_FIELD_MONTH) {
+ has_month = 1;
+ month = fields.month;
+ }
+ if (fields.present_mask & TI_FIELD_YEAR) {
+ has_year_prop = 1;
+ year = (int)fields.year;
+ if (s->calendar == CAL_ISO8601 && (year < -271821 || year > 275760))
+ return JS_ThrowRangeError(ctx, "year out of range");
+ }
+ /* era/eraYear processing */
+ if (fields.present_mask & (TI_FIELD_ERA | TI_FIELD_ERA_YEAR)) {
+ if (!ti_calendar_requires_era(s->calendar))
+ return JS_ThrowTypeError(ctx, "era and eraYear are invalid for this calendar");
+ if (!(fields.present_mask & TI_FIELD_ERA) || !(fields.present_mask & TI_FIELD_ERA_YEAR))
+ return JS_ThrowTypeError(ctx, "era and eraYear must both be present");
+ {
+ int cal_year_from_era;
+ if (fields.era == TI_ERA_UNKNOWN || ti_calendar_era_to_calendar_year(s->calendar, fields.era, (int)fields.era_year, &cal_year_from_era) < 0)
+ return JS_ThrowRangeError(ctx, "invalid era");
+ if (has_year_prop) {
+ if (year != cal_year_from_era)
+ return JS_ThrowRangeError(ctx, "year and era/eraYear must agree");
+ }
+ year = cal_year_from_era;
+ }
+ }
+ /* monthCode processing */
+ if (fields.present_mask & TI_FIELD_MONTH_CODE) {
+ with_has_month_code = 1;
+ with_month_code = fields.month_from_code;
+ with_has_l = fields.month_code_has_l;
+ if (s->calendar == CAL_ISO8601 || s->calendar == CAL_GREGORY) {
+ if (with_month_code < 1 || with_month_code > 12 || with_has_l)
+ month_code_iso_err = 1;
+ else if (has_month && month != with_month_code)
+ month_conflict_err = 1;
+ else
+ month = with_month_code;
+ } else {
+ int resolved_month = ti_calendar_month_code_to_month(s->calendar, year, with_month_code, with_has_l);
+ if (resolved_month < 0)
+ return JS_ThrowRangeError(ctx, "monthCode is not valid for this calendar");
+ if (has_month && month != resolved_month)
+ month_conflict_err = 1;
+ else
+ month = resolved_month;
+ }
+ }
+ /* Validate options object type */
+ if (argc >= 2 && !JS_IsUndefined(argv[1])) {
+ if (ti_validate_options_object(ctx, argv[1]) < 0)
+ return JS_EXCEPTION;
+ if (ti_get_overflow_option(ctx, argv[1], &overflow_constrain) < 0)
+ return JS_EXCEPTION;
+ }
+ if (month_code_iso_err)
+ return JS_ThrowRangeError(ctx, "monthCode is not valid for ISO 8601 calendar");
+ if (month_conflict_err)
+ return JS_ThrowRangeError(ctx, "month and monthCode conflict");
+ /* If monthCode was preserved from source but year changed, re-resolve */
+ if (!with_has_month_code && !has_month && year != orig_cal_year) {
+ int orig_mc, orig_has_l;
+ int result_mc, result_has_l;
+ ti_calendar_month_to_month_code(s->calendar, orig_cal_year, orig_cal_month, &orig_mc, &orig_has_l);
+ {
+ int resolved_month = ti_calendar_month_code_to_month(s->calendar, year, orig_mc, orig_has_l);
+ if (resolved_month < 0) {
+ if (!overflow_constrain)
+ return JS_ThrowRangeError(ctx, "invalid PlainDate");
+ resolved_month = ti_calendar_month_code_to_month(s->calendar, year, orig_mc, 0);
+ }
+ month = resolved_month;
+ }
+ ti_calendar_month_to_month_code(s->calendar, year, month, &result_mc, &result_has_l);
+ if (!overflow_constrain && (result_mc != orig_mc || result_has_l != orig_has_l))
+ return JS_ThrowRangeError(ctx, "invalid PlainDate");
+ }
+ if (!pd_is_valid_date_for_calendar(year, month, day, s->calendar)) {
+ if (!overflow_constrain)
+ return JS_ThrowRangeError(ctx, "invalid PlainDate");
+ /* Constrain month and day */
+ {
+ int max_month = ti_calendar_months_in_year(s->calendar, year);
+ if (month < 1)
+ month = 1;
+ else if (month > max_month)
+ month = max_month;
+ }
+ {
+ int dim = ti_calendar_days_in_month(s->calendar, year, month);
+ if (day > dim)
+ day = dim;
+ else if (day < 1)
+ day = 1;
+ }
+ }
+ {
+ int iso_y, iso_m, iso_d;
+ ti_calendar_date_to_iso(s->calendar, year, month, day, &iso_y, &iso_m, &iso_d);
+ year = iso_y; month = iso_m; day = iso_d;
+ }
+ {
+ JSValue obj = js_create_plaindate_with_calendar(ctx, year, month, day, s->calendar);
+ return obj;
+ }
+}
+
+static int pd_balance_month(int *year, int *month, CalendarType cal)
+{
+ int max_month;
+ while (1) {
+ max_month = ti_calendar_months_in_year(cal, *year);
+ if (*month <= max_month && *month >= 1)
+ break;
+ if (*month > max_month) {
+ *month -= max_month;
+ (*year)++;
+ } else {
+ (*year)--;
+ max_month = ti_calendar_months_in_year(cal, *year);
+ *month += max_month;
+ }
+ }
+ return 0;
+}
+
+static int pd_balance_date(int *year, int *month, int *day, CalendarType cal)
+{
+ int dim;
+ pd_balance_month(year, month, cal);
+ while (*day > (dim = ti_calendar_days_in_month(cal, *year, *month))) {
+ *day -= dim;
+ (*month)++;
+ if (*month > ti_calendar_months_in_year(cal, *year)) {
+ *month = 1;
+ (*year)++;
+ }
+ }
+ while (*day < 1) {
+ (*month)--;
+ if (*month < 1) {
+ (*year)--;
+ *month = ti_calendar_months_in_year(cal, *year);
+ }
+ dim = ti_calendar_days_in_month(cal, *year, *month);
+ *day += dim;
+ }
+ return 0;
+}
+
+static JSValue js_plaindate_add_subtract(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv, int is_add)
+{
+ JSPlainDateData *s = JS_GetOpaque2(ctx, this_val, js_plaindate_class_id);
+ JSDurationData d = {0};
+ int year, month, day;
+ int overflow_constrain = 1;
+ js_int128_t total_ns;
+ int64_t day_delta;
+ int sign = is_add ? 1 : -1;
+ if (!s)
+ return JS_EXCEPTION;
+ if (js_to_temporal_duration(ctx, argv[0], &d))
+ return JS_EXCEPTION;
+ if (duration_has_mixed_signs(&d))
+ return JS_ThrowRangeError(ctx, "mixed-sign duration not allowed");
+ if (duration_is_out_of_range(&d))
+ return JS_ThrowRangeError(ctx, "duration out of range");
+ if (argc >= 2 && ti_validate_options_object(ctx, argv[1]) < 0)
+ return JS_EXCEPTION;
+ if (argc >= 2 && !JS_IsUndefined(argv[1])) {
+ if (ti_get_overflow_option(ctx, argv[1], &overflow_constrain) < 0)
+ return JS_EXCEPTION;
+ }
+ year = s->year;
+ month = s->month;
+ day = s->day;
+ {
+ int orig_mc = 0, orig_has_l = 0;
+ ti_iso_to_calendar_date(s->calendar, s->year, s->month, s->day, &year, &month, &day);
+ ti_calendar_month_to_month_code(s->calendar, year, month, &orig_mc, &orig_has_l);
+ year = year + sign * (int)d.years;
+ month = ti_calendar_month_code_to_month(s->calendar, year, orig_mc, orig_has_l);
+ if (month < 0) {
+ if (!overflow_constrain)
+ return JS_ThrowRangeError(ctx, "invalid PlainDate");
+ month = ti_calendar_month_code_to_month(s->calendar, year, orig_mc, 0);
+ } else if (!overflow_constrain) {
+ int result_mc, result_has_l;
+ ti_calendar_month_to_month_code(s->calendar, year, month, &result_mc, &result_has_l);
+ if (result_mc != orig_mc || result_has_l != orig_has_l)
+ return JS_ThrowRangeError(ctx, "invalid PlainDate");
+ }
+ }
+ month += sign * (int)d.months;
+ pd_balance_month(&year, &month, s->calendar);
+ {
+ int dim = ti_calendar_days_in_month(s->calendar, year, month);
+ if (day > dim) {
+ if (!overflow_constrain)
+ return JS_ThrowRangeError(ctx, "invalid PlainDate");
+ day = dim;
+ }
+ }
+ day += sign * (int)(d.weeks * 7 + d.days);
+ /* Balance smaller time units into days */
+ total_ns = ti_duration_time_fields_to_ns(&d);
+ day_delta = (int64_t)(total_ns / 86400000000000LL);
+ day += sign * (int)day_delta;
+ pd_balance_date(&year, &month, &day, s->calendar);
+ {
+ int iso_y, iso_m, iso_d;
+ ti_calendar_date_to_iso(s->calendar, year, month, day, &iso_y, &iso_m, &iso_d);
+ year = iso_y; month = iso_m; day = iso_d;
+ }
+ if (year < -271821 || year > 275760)
+ return JS_ThrowRangeError(ctx, "invalid PlainDate");
+ /* Check against ISO date bounds */
+ if (year == -271821 && (month < 4 || (month == 4 && day < 19)))
+ return JS_ThrowRangeError(ctx, "invalid PlainDate");
+ if (year == 275760 && (month > 9 || (month == 9 && day > 13)))
+ return JS_ThrowRangeError(ctx, "invalid PlainDate");
+ {
+ JSValue obj = js_create_plaindate_with_calendar(ctx, year, month, day, s->calendar);
+ return obj;
+ }
+}
+
+static JSValue js_plaindate_difference(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv, int is_until)
+{
+ JSPlainDateData *s = JS_GetOpaque2(ctx, this_val, js_plaindate_class_id);
+ JSValue other_val;
+ JSPlainDateData *other;
+ int other_year, other_month, other_day;
+ JSDurationData d = {0};
+ TIUnit largestUnit = TI_UNIT_INVALID;
+ TIUnit smallestUnit = TI_UNIT_INVALID;
+ int64_t roundingIncrement = 1;
+ TIRoundingMode roundingMode = ROUND_TRUNC;
+ if (!s)
+ return JS_EXCEPTION;
+ other_val = js_plaindate_from(ctx, JS_UNDEFINED, 1, argv);
+ if (JS_IsException(other_val))
+ return JS_EXCEPTION;
+ other = JS_GetOpaque(other_val, js_plaindate_class_id);
+ if (!other) {
+ JS_FreeValue(ctx, other_val);
+ return JS_ThrowTypeError(ctx, "invalid PlainDate");
+ }
+ if (s->calendar != other->calendar) {
+ JS_FreeValue(ctx, other_val);
+ return JS_ThrowRangeError(ctx, "calendars must be the same");
+ }
+ other_year = other->year;
+ other_month = other->month;
+ other_day = other->day;
+ if (argc >= 2 && ti_validate_options_object(ctx, argv[1]) < 0) {
+ JS_FreeValue(ctx, other_val);
+ return JS_EXCEPTION;
+ }
+ if (argc >= 2 && !JS_IsUndefined(argv[1])) {
+ if (ti_parse_unit_option(ctx, argv[1], "largestUnit", &largestUnit, TI_UNIT_OPT_ALLOW_UNDEFINED | TI_UNIT_OPT_ALLOW_AUTO, TI_UNIT_INVALID) < 0) {
+ JS_FreeValue(ctx, other_val);
+ return JS_EXCEPTION;
+ }
+ if (ti_get_rounding_increment_option(ctx, argv[1], &roundingIncrement) < 0) {
+ JS_FreeValue(ctx, other_val);
+ return JS_EXCEPTION;
+ }
+ if (ti_get_rounding_mode_option_default(ctx, argv[1], &roundingMode, ROUND_TRUNC) < 0) {
+ JS_FreeValue(ctx, other_val);
+ return JS_EXCEPTION;
+ }
+ if (ti_parse_unit_option(ctx, argv[1], "smallestUnit", &smallestUnit, TI_UNIT_OPT_ALLOW_UNDEFINED, TI_UNIT_INVALID) < 0) {
+ JS_FreeValue(ctx, other_val);
+ return JS_EXCEPTION;
+ }
+ /* Validate unit restrictions */
+ if (largestUnit != TI_UNIT_INVALID && largestUnit != TI_UNIT_AUTO &&
+ largestUnit != TI_UNIT_YEAR && largestUnit != TI_UNIT_MONTH &&
+ largestUnit != TI_UNIT_WEEK && largestUnit != TI_UNIT_DAY) {
+ JS_FreeValue(ctx, other_val);
+ return JS_ThrowRangeError(ctx, "invalid largestUnit");
+ }
+ if (smallestUnit != TI_UNIT_INVALID && smallestUnit != TI_UNIT_YEAR &&
+ smallestUnit != TI_UNIT_MONTH && smallestUnit != TI_UNIT_WEEK &&
+ smallestUnit != TI_UNIT_DAY) {
+ JS_FreeValue(ctx, other_val);
+ return JS_ThrowRangeError(ctx, "invalid smallestUnit");
+ }
+ }
+ JS_FreeValue(ctx, other_val);
+ if (smallestUnit == TI_UNIT_INVALID)
+ smallestUnit = TI_UNIT_DAY;
+ if (largestUnit == TI_UNIT_INVALID || largestUnit == TI_UNIT_AUTO)
+ largestUnit = (smallestUnit < TI_UNIT_DAY) ? smallestUnit : TI_UNIT_DAY;
+
+ if (largestUnit > smallestUnit) {
+ return JS_ThrowRangeError(ctx, "invalid unit combination");
+ }
+
+ /* Compute monthCode for Chinese/Dangi/Hebrew */
+ int s_mc = 0, s_has_l = 0, s_has_mc = 0;
+ int o_mc = 0, o_has_l = 0, o_has_mc = 0;
+ int s_cal_y = s->year, s_cal_m = s->month, s_cal_d = s->day;
+ int o_cal_y = other_year, o_cal_m = other_month, o_cal_d = other_day;
+ if (s->calendar == CAL_CHINESE || s->calendar == CAL_DANGI || s->calendar == CAL_HEBREW) {
+ ti_iso_to_calendar_date(s->calendar, s->year, s->month, s->day, &s_cal_y, &s_cal_m, &s_cal_d);
+ ti_iso_to_calendar_date(s->calendar, other_year, other_month, other_day, &o_cal_y, &o_cal_m, &o_cal_d);
+ ti_calendar_month_to_month_code(s->calendar, s_cal_y, s_cal_m, &s_mc, &s_has_l);
+ s_has_mc = 1;
+ ti_calendar_month_to_month_code(s->calendar, o_cal_y, o_cal_m, &o_mc, &o_has_l);
+ o_has_mc = 1;
+ }
+
+ if ((largestUnit == TI_UNIT_YEAR || largestUnit == TI_UNIT_MONTH) &&
+ (s->calendar == CAL_CHINESE || s->calendar == CAL_DANGI || s->calendar == CAL_HEBREW) &&
+ s_has_mc && o_has_mc) {
+ ti_calendar_date_until_with_monthcode(s->calendar,
+ s_cal_y, s_cal_m, s_cal_d, s_mc, s_has_mc, s_has_l,
+ o_cal_y, o_cal_m, o_cal_d, o_mc, o_has_mc, o_has_l,
+ largestUnit,
+ &d.years, &d.months, &d.weeks, &d.days);
+ } else if ((largestUnit == TI_UNIT_YEAR || largestUnit == TI_UNIT_MONTH) &&
+ s->calendar != CAL_ISO8601 && s->calendar != CAL_GREGORY &&
+ s->calendar != CAL_BUDDHIST && s->calendar != CAL_ROC && s->calendar != CAL_JAPANESE) {
+ if (s->calendar != CAL_CHINESE && s->calendar != CAL_DANGI && s->calendar != CAL_HEBREW) {
+ ti_iso_to_calendar_date(s->calendar, s->year, s->month, s->day, &s_cal_y, &s_cal_m, &s_cal_d);
+ ti_iso_to_calendar_date(s->calendar, other_year, other_month, other_day, &o_cal_y, &o_cal_m, &o_cal_d);
+ }
+ ti_calendar_date_until(s->calendar,
+ s_cal_y, s_cal_m, s_cal_d,
+ o_cal_y, o_cal_m, o_cal_d,
+ largestUnit,
+ &d.years, &d.months, &d.weeks, &d.days);
+ } else if ((largestUnit == TI_UNIT_WEEK || largestUnit == TI_UNIT_DAY) &&
+ s->calendar != CAL_ISO8601 && s->calendar != CAL_GREGORY &&
+ s->calendar != CAL_CHINESE && s->calendar != CAL_DANGI && s->calendar != CAL_HEBREW &&
+ s->calendar != CAL_BUDDHIST && s->calendar != CAL_ROC && s->calendar != CAL_JAPANESE) {
+ ti_iso_to_calendar_date(s->calendar, s->year, s->month, s->day, &s_cal_y, &s_cal_m, &s_cal_d);
+ ti_iso_to_calendar_date(s->calendar, other_year, other_month, other_day, &o_cal_y, &o_cal_m, &o_cal_d);
+ ti_calendar_date_until(s->calendar,
+ s_cal_y, s_cal_m, s_cal_d,
+ o_cal_y, o_cal_m, o_cal_d,
+ largestUnit,
+ &d.years, &d.months, &d.weeks, &d.days);
+ } else {
+ ti_iso_calendar_date_until(s->year, s->month, s->day,
+ other_year, other_month, other_day,
+ largestUnit,
+ &d.years, &d.months, &d.weeks, &d.days);
+ }
+ if (smallestUnit != TI_UNIT_DAY || roundingIncrement != 1) {
+ TIRoundingMode rm = is_until ? roundingMode : ti_negate_rounding_mode(roundingMode);
+ if (smallestUnit == TI_UNIT_DAY) {
+ /* For PlainDate, day is not a calendar unit; just round the day count */
+ d.days = ti_round_to_increment(d.days, roundingIncrement, rm);
+ } else {
+ if (ti_round_iso_date_duration(ctx,
+ s->year, s->month, s->day,
+ other_year, other_month, other_day,
+ 0, 0,
+ d.years, d.months, d.weeks, d.days,
+ largestUnit, smallestUnit,
+ roundingIncrement, rm,
+ 1,
+ FALSE,
+ &d.years, &d.months, &d.weeks, &d.days) < 0)
+ return JS_EXCEPTION;
+ }
+ }
+ if (!is_until) {
+ d.years = -d.years;
+ d.months = -d.months;
+ d.weeks = -d.weeks;
+ d.days = -d.days;
+ }
+ return js_create_duration(ctx, &d);
+}
+
+static JSValue js_plaindate_toZonedDateTime(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ (void)argc;
+ JSPlainDateData *s = JS_GetOpaque2(ctx, this_val, js_plaindate_class_id);
+ JSTimeSpec ts;
+ const char *timeZone = "UTC";
+ char tz_buf[64] = "UTC";
+ int64_t tz_offset_ns = 0;
+ int hour = 0, minute = 0, second = 0, ms = 0, us = 0, ns = 0;
+ if (!s)
+ return JS_EXCEPTION;
+ int has_plainTime = 0;
+ if (JS_IsString(argv[0])) {
+ const char *str = JS_ToCString(ctx, argv[0]);
+ if (!str)
+ return JS_EXCEPTION;
+ {
+ int64_t offset_ns = 0;
+ int ret = ti_parse_temporal_timezone_string(str, &offset_ns);
+ if (ret < 0) {
+ JS_FreeCString(ctx, str);
+ return JS_ThrowRangeError(ctx, "invalid time zone");
+ }
+ if (ti_canonicalize_timezone_identifier(str, offset_ns, tz_buf, sizeof(tz_buf)) < 0) {
+ JS_FreeCString(ctx, str);
+ return JS_ThrowRangeError(ctx, "unsupported time zone");
+ }
+ tz_offset_ns = offset_ns;
+ }
+ timeZone = tz_buf;
+ JS_FreeCString(ctx, str);
+ } else if (JS_IsObject(argv[0])) {
+ JSValue v = JS_GetPropertyStr(ctx, argv[0], "timeZone");
+ if (JS_IsException(v))
+ return JS_EXCEPTION;
+ if (JS_IsUndefined(v)) {
+ JS_FreeValue(ctx, v);
+ return JS_ThrowTypeError(ctx, "missing timeZone");
+ }
+ if (!JS_IsString(v) && !JS_IsObject(v)) {
+ JS_FreeValue(ctx, v);
+ return JS_ThrowTypeError(ctx, "timeZone must be a string or object");
+ }
+ if (JS_IsString(v)) {
+ const char *str = JS_ToCString(ctx, v);
+ if (!str) {
+ JS_FreeValue(ctx, v);
+ return JS_EXCEPTION;
+ }
+ {
+ int64_t offset_ns = 0;
+ int ret = ti_parse_temporal_timezone_string(str, &offset_ns);
+ if (ret < 0) {
+ JS_FreeCString(ctx, str);
+ JS_FreeValue(ctx, v);
+ return JS_ThrowRangeError(ctx, "invalid time zone");
+ }
+ if (ti_canonicalize_timezone_identifier(str, offset_ns, tz_buf, sizeof(tz_buf)) < 0) {
+ JS_FreeCString(ctx, str);
+ JS_FreeValue(ctx, v);
+ return JS_ThrowRangeError(ctx, "unsupported time zone");
+ }
+ tz_offset_ns = offset_ns;
+ }
+ timeZone = tz_buf;
+ JS_FreeCString(ctx, str);
+ } else {
+ /* Object timezone: not supported yet */
+ JS_FreeValue(ctx, v);
+ return JS_ThrowTypeError(ctx, "unsupported time zone argument");
+ }
+ JS_FreeValue(ctx, v);
+ v = JS_GetPropertyStr(ctx, argv[0], "plainTime");
+ if (JS_IsException(v))
+ return JS_EXCEPTION;
+ if (!JS_IsUndefined(v)) {
+ has_plainTime = 1;
+ JSPlainTimeData *pt = JS_GetOpaque(v, js_plaintime_class_id);
+ if (pt) {
+ hour = pt->hour;
+ minute = pt->minute;
+ second = pt->second;
+ ms = pt->millisecond;
+ us = pt->microsecond;
+ ns = pt->nanosecond;
+ } else {
+ JSValue pt_val = js_plaintime_from(ctx, JS_UNDEFINED, 1, &v);
+ if (JS_IsException(pt_val)) {
+ JS_FreeValue(ctx, v);
+ return JS_EXCEPTION;
+ }
+ pt = JS_GetOpaque(pt_val, js_plaintime_class_id);
+ if (pt) {
+ hour = pt->hour;
+ minute = pt->minute;
+ second = pt->second;
+ ms = pt->millisecond;
+ us = pt->microsecond;
+ ns = pt->nanosecond;
+ }
+ JS_FreeValue(ctx, pt_val);
+ }
+ JS_FreeValue(ctx, v);
+ }
+ } else {
+ return JS_ThrowTypeError(ctx, "unsupported time zone argument");
+ }
+ {
+ int64_t days = pdt_to_ordinal_days(s->year, s->month, s->day);
+ int64_t epoch_days = days - 719162; /* days before 1970 */
+ int64_t epoch_sec = epoch_days * 86400LL;
+ epoch_sec += hour * 3600LL + minute * 60LL + second;
+ ts.secs = epoch_sec;
+ ts.nsecs = (uint32_t)(ms * 1000000 + us * 1000 + ns);
+ }
+ {
+ int tz_id = ti_tz_find_id(timeZone);
+ if (tz_id >= 0) {
+ if (has_plainTime) {
+ /* Object with plainTime: use compatible disambiguation */
+ int64_t utc_sec;
+ int offset_sec;
+ if (ti_tz_local_to_utc(tz_id, ts.secs, 2, &utc_sec, &offset_sec) < 0)
+ return JS_ThrowRangeError(ctx, "multiple instants found");
+ ts.secs = utc_sec;
+ } else {
+ /* String or object without plainTime: use startOfDay semantics */
+ int64_t utc_sec;
+ int offset_sec;
+ if (ti_tz_local_to_utc(tz_id, ts.secs, 0, &utc_sec, &offset_sec) < 0)
+ return JS_ThrowRangeError(ctx, "multiple instants found");
+ if (utc_sec + ti_tz_offset_at_sec(tz_id, utc_sec) == ts.secs) {
+ ts.secs = utc_sec;
+ } else {
+ /* Gap at midnight: return next transition after (midnight - 1 day) */
+ int64_t next_trans = ti_tz_next_transition_sec(tz_id, ts.secs - 86400LL);
+ if (next_trans != INT64_MIN) {
+ ts.secs = next_trans;
+ } else {
+ ts.secs = utc_sec;
+ }
+ }
+ }
+ } else {
+ int64_t offset_sec = tz_offset_ns / 1000000000LL;
+ int offset_nsec = (int)(tz_offset_ns % 1000000000LL);
+ ts.secs -= offset_sec;
+ {
+ int64_t new_nsec = (int64_t)ts.nsecs - offset_nsec;
+ if (new_nsec < 0) {
+ new_nsec += 1000000000;
+ ts.secs -= 1;
+ } else if (new_nsec >= 1000000000) {
+ new_nsec -= 1000000000;
+ ts.secs += 1;
+ }
+ ts.nsecs = (uint32_t)new_nsec;
+ }
+ }
+ }
+ if (!is_valid_epoch_timespec(&ts))
+ return JS_ThrowRangeError(ctx, "epoch nanoseconds outside valid limits");
+ return js_create_zoneddatetime(ctx, &ts, timeZone, s->calendar);
+}
+
+static JSValue js_plaindate_toPlainDateTime(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSPlainDateData *s = JS_GetOpaque2(ctx, this_val, js_plaindate_class_id);
+ int hour = 0, minute = 0, second = 0, ms = 0, us = 0, ns = 0;
+ if (!s)
+ return JS_EXCEPTION;
+ if (argc >= 1 && !JS_IsUndefined(argv[0])) {
+ JSPlainTimeData *pt = JS_GetOpaque(argv[0], js_plaintime_class_id);
+ if (pt) {
+ hour = pt->hour;
+ minute = pt->minute;
+ second = pt->second;
+ ms = pt->millisecond;
+ us = pt->microsecond;
+ ns = pt->nanosecond;
+ } else if (JS_GetOpaque(argv[0], js_plaindatetime_class_id)) {
+ JSPlainDateTimeData *pdt = JS_GetOpaque(argv[0], js_plaindatetime_class_id);
+ hour = pdt->hour;
+ minute = pdt->minute;
+ second = pdt->second;
+ ms = pdt->millisecond;
+ us = pdt->microsecond;
+ ns = pdt->nanosecond;
+ } else if (JS_GetOpaque(argv[0], js_zoneddatetime_class_id)) {
+ JSZonedDateTimeData *zdt = JS_GetOpaque(argv[0], js_zoneddatetime_class_id);
+ int64_t epoch_sec = zdt->ts.secs;
+ int epoch_nsec = (int)zdt->ts.nsecs;
+ {
+ int64_t offset_ns = 0;
+ int ret = ti_parse_temporal_timezone_string(zdt->timeZone, &offset_ns);
+ if (ret == 0) {
+ int64_t offset_sec = offset_ns / 1000000000LL;
+ int offset_nsec = (int)(offset_ns % 1000000000LL);
+ epoch_sec += offset_sec;
+ epoch_nsec += offset_nsec;
+ if (epoch_nsec >= 1000000000) {
+ epoch_nsec -= 1000000000;
+ epoch_sec += 1;
+ } else if (epoch_nsec < 0) {
+ epoch_nsec += 1000000000;
+ epoch_sec -= 1;
+ }
+ }
+ }
+ {
+ int64_t y;
+ int mo, d;
+ ti_epoch_sec_to_date(epoch_sec, &y, &mo, &d, &hour, &minute, &second);
+ ms = epoch_nsec / 1000000;
+ us = (epoch_nsec % 1000000) / 1000;
+ ns = epoch_nsec % 1000;
+ }
+ } else {
+ JSValue pt_val = js_plaintime_from(ctx, JS_UNDEFINED, 1, argv);
+ if (JS_IsException(pt_val))
+ return pt_val;
+ {
+ JSPlainTimeData *pt2 = JS_GetOpaque(pt_val, js_plaintime_class_id);
+ if (pt2) {
+ hour = pt2->hour;
+ minute = pt2->minute;
+ second = pt2->second;
+ ms = pt2->millisecond;
+ us = pt2->microsecond;
+ ns = pt2->nanosecond;
+ }
+ }
+ JS_FreeValue(ctx, pt_val);
+ }
+ }
+ return js_create_plaindatetime_with_calendar(ctx, s->year, s->month, s->day,
+ hour, minute, second, ms, us, ns, s->calendar);
+}
+
+static JSValue js_plaindate_toPlainYearMonth(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ (void)argc;
+ (void)argv;
+ JSPlainDateData *s = JS_GetOpaque2(ctx, this_val, js_plaindate_class_id);
+ int ref_day;
+ if (!s)
+ return JS_EXCEPTION;
+ ref_day = (s->calendar == CAL_ISO8601 || s->calendar == CAL_GREGORY) ? 1 : s->day;
+ return js_create_plainyearmonth_with_calendar(ctx, s->year, s->month, ref_day, s->calendar);
+}
+
+static JSValue js_plaindate_toPlainMonthDay(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ (void)argc;
+ (void)argv;
+ JSPlainDateData *s = JS_GetOpaque2(ctx, this_val, js_plaindate_class_id);
+ int ref_year;
+ if (!s)
+ return JS_EXCEPTION;
+ ref_year = (s->calendar == CAL_ISO8601 || s->calendar == CAL_GREGORY) ? 1972 : s->year;
+ return js_create_plainmonthday_with_calendar(ctx, ref_year, s->month, s->day, s->calendar);
+}
+
+static JSValue js_plaindate_withCalendar(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ (void)argc;
+ JSPlainDateData *s = JS_GetOpaque2(ctx, this_val, js_plaindate_class_id);
+ JSPlainDateData *t;
+ JSValue obj;
+ CalendarType cal;
+ if (!s)
+ return JS_EXCEPTION;
+ if (ti_resolve_calendar_value(ctx, argv[0], &cal) < 0)
+ return JS_EXCEPTION;
+ t = js_mallocz(ctx, sizeof(*t));
+ if (!t)
+ return JS_EXCEPTION;
+ *t = *s;
+ t->calendar = cal;
+ obj = JS_NewObjectClass(ctx, (int)js_plaindate_class_id);
+ if (JS_IsException(obj)) {
+ js_free(ctx, t);
+ return JS_EXCEPTION;
+ }
+ JS_SetOpaque(obj, t);
+ return obj;
+}
+
+static JSValue js_plaindate_from(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ (void)this_val;
+ JSValue val;
+ int overflow_constrain = 1;
+ val = argv[0];
+ if (JS_IsObject(val)) {
+ JSPlainDateData *s = JS_GetOpaque(val, js_plaindate_class_id);
+ if (s) {
+ if (argc >= 2 && ti_validate_options_object(ctx, argv[1]) < 0)
+ return JS_EXCEPTION;
+ if (argc >= 2 && ti_get_overflow_option(ctx, argv[1], &overflow_constrain) < 0)
+ return JS_EXCEPTION;
+ return js_create_plaindate_with_calendar(ctx, s->year, s->month, s->day, s->calendar);
+ }
+ {
+ JSPlainDateTimeData *pdt = JS_GetOpaque(val, js_plaindatetime_class_id);
+ if (pdt) {
+ int year = pdt->year, month = pdt->month, day = pdt->day;
+ if (argc >= 2 && ti_validate_options_object(ctx, argv[1]) < 0)
+ return JS_EXCEPTION;
+ if (argc >= 2 && ti_get_overflow_option(ctx, argv[1], &overflow_constrain) < 0)
+ return JS_EXCEPTION;
+ if (pdt->calendar != CAL_ISO8601 && pdt->calendar != CAL_GREGORY)
+ ti_calendar_date_to_iso(pdt->calendar, pdt->year, pdt->month, pdt->day, &year, &month, &day);
+ return js_create_plaindate_with_calendar(ctx, year, month, day, pdt->calendar);
+ }
+ }
+ {
+ JSZonedDateTimeData *zdt = JS_GetOpaque(val, js_zoneddatetime_class_id);
+ if (zdt) {
+ int64_t year;
+ int month, day, hour, minute, second;
+ if (argc >= 2 && ti_validate_options_object(ctx, argv[1]) < 0)
+ return JS_EXCEPTION;
+ if (argc >= 2 && ti_get_overflow_option(ctx, argv[1], &overflow_constrain) < 0)
+ return JS_EXCEPTION;
+ ti_epoch_sec_to_date(zdt->ts.secs, &year, &month, &day, &hour, &minute, &second);
+ return js_create_plaindate_with_calendar(ctx, (int)year, month, day, zdt->calendar);
+ }
+ }
+ {
+ TIPreparedFields fields;
+ uint32_t field_mask = TI_FIELD_YEAR | TI_FIELD_MONTH | TI_FIELD_MONTH_CODE |
+ TI_FIELD_DAY;
+ CalendarType cal = CAL_ISO8601;
+ if (ti_resolve_calendar_from_object(ctx, val, &cal) < 0)
+ return JS_EXCEPTION;
+ if (ti_prepare_calendar_fields(ctx, val, field_mask, 0, 0, &fields, cal) < 0)
+ return JS_EXCEPTION;
+ if (argc >= 2 && ti_validate_options_object(ctx, argv[1]) < 0)
+ return JS_EXCEPTION;
+ if (argc >= 2 && ti_get_overflow_option(ctx, argv[1], &overflow_constrain) < 0)
+ return JS_EXCEPTION;
+ return ti_create_plaindate_from_fields(ctx, &fields, overflow_constrain);
+ }
+ }
+ if (JS_IsString(val)) {
+ const char *str = JS_ToCString(ctx, val);
+ TISODateTimeParseResult r;
+ if (!str)
+ return JS_EXCEPTION;
+ if (ti_parse_iso_datetime_string(ctx, str, &r, TI_PARSE_DEFAULT) < 0) {
+ JS_FreeCString(ctx, str);
+ return JS_ThrowRangeError(ctx, "invalid PlainDate string");
+ }
+ JS_FreeCString(ctx, str);
+ if (!r.has_date)
+ return JS_ThrowRangeError(ctx, "invalid PlainDate string");
+ if (r.has_utc)
+ return JS_ThrowRangeError(ctx, "invalid PlainDate string");
+ if (r.has_tz_offset && !r.has_time)
+ return JS_ThrowRangeError(ctx, "invalid PlainDate string");
+ {
+ CalendarType cal = r.has_calendar ? r.calendar : CAL_ISO8601;
+ if (cal == CAL_UNKNOWN)
+ return JS_ThrowRangeError(ctx, "invalid calendar ID");
+ /* String contains ISO fields; store them directly */
+ if (!pd_is_valid_date(r.year, r.month, r.day))
+ return JS_ThrowRangeError(ctx, "invalid PlainDate");
+ /* Validate options AFTER successful string parse */
+ if (argc >= 2 && ti_validate_options_object(ctx, argv[1]) < 0)
+ return JS_EXCEPTION;
+ if (argc >= 2 && ti_get_overflow_option(ctx, argv[1], &overflow_constrain) < 0)
+ return JS_EXCEPTION;
+ if (!overflow_constrain && !pd_is_valid_date(r.year, r.month, r.day))
+ return JS_ThrowRangeError(ctx, "invalid PlainDate");
+ return js_create_plaindate_with_calendar(ctx, r.year, r.month, r.day, cal);
+ }
+ }
+ return JS_ThrowTypeError(ctx, "unsupported argument type for Temporal.PlainDate.from");
+}
+
+static const JSCFunctionListEntry js_plaindate_proto_funcs[] = {
+ JS_CGETSET_MAGIC_DEF("year", js_plaindate_get_field, NULL, PLAINDATE_YEAR),
+ JS_CGETSET_MAGIC_DEF("month", js_plaindate_get_field, NULL, PLAINDATE_MONTH),
+ JS_CGETSET_DEF("monthCode", js_plaindate_get_monthCode, NULL),
+ JS_CGETSET_MAGIC_DEF("day", js_plaindate_get_field, NULL, PLAINDATE_DAY),
+ JS_CGETSET_DEF("calendarId", js_plaindate_get_calendarId, NULL),
+ JS_CGETSET_DEF("era", js_plaindate_get_era, NULL),
+ JS_CGETSET_DEF("eraYear", js_plaindate_get_eraYear, NULL),
+ JS_CGETSET_DEF("inLeapYear", js_plaindate_get_inLeapYear, NULL),
+ JS_CGETSET_DEF("daysInMonth", js_plaindate_get_daysInMonth, NULL),
+ JS_CGETSET_DEF("daysInYear", js_plaindate_get_daysInYear, NULL),
+ JS_CGETSET_DEF("daysInWeek", js_plaindate_get_daysInWeek, NULL),
+ JS_CGETSET_DEF("monthsInYear", js_plaindate_get_monthsInYear, NULL),
+ JS_CGETSET_DEF("dayOfYear", js_plaindate_get_dayOfYear, NULL),
+ JS_CGETSET_DEF("dayOfWeek", js_plaindate_get_dayOfWeek, NULL),
+ JS_CGETSET_DEF("weekOfYear", js_plaindate_get_weekOfYear, NULL),
+ JS_CGETSET_DEF("yearOfWeek", js_plaindate_get_yearOfWeek, NULL),
+ JS_CFUNC_DEF("equals", 1, js_plaindate_equals),
+ JS_CFUNC_DEF("toString", 0, js_plaindate_toString),
+ JS_CFUNC_DEF("toJSON", 0, js_plaindate_toJSON),
+ JS_CFUNC_DEF("toLocaleString", 0, js_plaindate_toLocaleString),
+ JS_CFUNC_MAGIC_DEF("add", 1, js_plaindate_add_subtract, 1),
+ JS_CFUNC_MAGIC_DEF("subtract", 1, js_plaindate_add_subtract, 0),
+ JS_CFUNC_MAGIC_DEF("until", 1, js_plaindate_difference, 1),
+ JS_CFUNC_MAGIC_DEF("since", 1, js_plaindate_difference, 0),
+ JS_CFUNC_DEF("toZonedDateTime", 1, js_plaindate_toZonedDateTime),
+ JS_CFUNC_DEF("toPlainDateTime", 0, js_plaindate_toPlainDateTime),
+
+ JS_CFUNC_DEF("toPlainYearMonth", 0, js_plaindate_toPlainYearMonth),
+ JS_CFUNC_DEF("toPlainMonthDay", 0, js_plaindate_toPlainMonthDay),
+ JS_CFUNC_DEF("with", 1, js_plaindate_with),
+ JS_CFUNC_DEF("withCalendar", 1, js_plaindate_withCalendar),
+ JS_CFUNC_DEF("valueOf", 0, js_plaindate_valueOf),
+ JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Temporal.PlainDate", JS_PROP_CONFIGURABLE),
+};
+
+static const JSCFunctionListEntry js_plaindate_static_funcs[] = {
+ JS_CFUNC_DEF("from", 1, js_plaindate_from),
+ JS_CFUNC_DEF("compare", 2, js_plaindate_compare),
+};
+
+int js_add_plaindate(JSContext *ctx, JSValue temporal_obj)
+{
+ JSValue ctor;
+
+ JS_NewClassID(&js_plaindate_class_id);
+ JS_NewClass(JS_GetRuntime(ctx), js_plaindate_class_id, &js_plaindate_class);
+
+ ctor = JS_NewCConstructor(ctx, (int)js_plaindate_class_id, "PlainDate",
+ (JSCFunction *)js_plaindate_constructor, 3,
+ JS_CFUNC_constructor, 0,
+ JS_UNDEFINED,
+ js_plaindate_static_funcs, countof(js_plaindate_static_funcs),
+ js_plaindate_proto_funcs, countof(js_plaindate_proto_funcs),
+ JS_NEW_CTOR_NO_GLOBAL);
+ if (JS_IsException(ctor))
+ return -1;
+ if (JS_DefinePropertyValueStr(ctx, temporal_obj, "PlainDate", ctor,
+ JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE) < 0)
+ return -1;
+ return 0;
+}
--- /dev/null
+/*
+ * QuickJS Temporal.PlainDateTime implementation (minimal)
+ */
+
+#include <string.h>
+#include <math.h>
+
+#include "../quickjs.h"
+#include "../cutils.h"
+#include "temporal_private.h"
+
+JSClassID js_plaindatetime_class_id;
+
+static void js_plaindatetime_finalizer(JSRuntime *rt, JSValue val)
+{
+ JSPlainDateTimeData *s = JS_GetOpaque(val, js_plaindatetime_class_id);
+ if (s)
+ js_free_rt(rt, s);
+}
+
+static const JSClassDef js_plaindatetime_class = {
+ "Temporal.PlainDateTime",
+ .finalizer = js_plaindatetime_finalizer,
+};
+
+static void pdt_get_calendar_date(JSPlainDateTimeData *s, int *cal_year, int *cal_month, int *cal_day)
+{
+ ti_iso_to_calendar_date(s->calendar, s->year, s->month, s->day, cal_year, cal_month, cal_day);
+}
+
+int pdt_is_within_limits(int year, int month, int day,
+ int hour, int minute, int second,
+ int millisecond, int microsecond, int nanosecond);
+
+JSValue js_create_plaindatetime(JSContext *ctx, int year, int month, int day,
+ int hour, int minute, int second,
+ int millisecond, int microsecond, int nanosecond)
+{
+ return js_create_plaindatetime_with_calendar(ctx, year, month, day, hour, minute, second,
+ millisecond, microsecond, nanosecond, CAL_ISO8601);
+}
+
+JSValue js_create_plaindatetime_with_calendar(JSContext *ctx, int year, int month, int day,
+ int hour, int minute, int second,
+ int millisecond, int microsecond, int nanosecond,
+ CalendarType calendar)
+{
+ JSPlainDateTimeData *s;
+ JSValue obj;
+ if ((calendar == CAL_ISO8601 || calendar == CAL_GREGORY) &&
+ !pdt_is_within_limits(year, month, day, hour, minute, second,
+ millisecond, microsecond, nanosecond))
+ return JS_ThrowRangeError(ctx, "PlainDateTime outside valid ISO range");
+ s = js_mallocz(ctx, sizeof(*s));
+ if (!s)
+ return JS_EXCEPTION;
+ s->year = year;
+ s->month = month;
+ s->day = day;
+ s->hour = hour;
+ s->minute = minute;
+ s->second = second;
+ s->millisecond = millisecond;
+ s->microsecond = microsecond;
+ s->nanosecond = nanosecond;
+ s->calendar = calendar;
+ obj = JS_NewObjectClass(ctx, (int)js_plaindatetime_class_id);
+ if (JS_IsException(obj)) {
+ js_free(ctx, s);
+ return JS_EXCEPTION;
+ }
+ JS_SetOpaque(obj, s);
+ return obj;
+}
+
+static JSValue ti_create_plaindatetime_from_fields(JSContext *ctx, TIPreparedFields *fields,
+ int overflow_constrain)
+{
+ int year, month, day, hour, minute, second, ms, us, ns;
+
+ if (ti_resolve_date_from_fields(ctx, fields, overflow_constrain, &year, &month, &day, 1) < 0)
+ return JS_EXCEPTION;
+
+ hour = (fields->present_mask & TI_FIELD_HOUR) ? fields->hour : 0;
+ minute = (fields->present_mask & TI_FIELD_MINUTE) ? fields->minute : 0;
+ second = (fields->present_mask & TI_FIELD_SECOND) ? fields->second : 0;
+ ms = (fields->present_mask & TI_FIELD_MILLISECOND) ? fields->millisecond : 0;
+ us = (fields->present_mask & TI_FIELD_MICROSECOND) ? fields->microsecond : 0;
+ ns = (fields->present_mask & TI_FIELD_NANOSECOND) ? fields->nanosecond : 0;
+
+ if (!overflow_constrain) {
+ if (hour < 0 || hour > 23)
+ return JS_ThrowRangeError(ctx, "invalid hour");
+ if (minute < 0 || minute > 59)
+ return JS_ThrowRangeError(ctx, "invalid minute");
+ if (second < 0 || second > 59)
+ return JS_ThrowRangeError(ctx, "invalid second");
+ if (ms < 0 || ms > 999)
+ return JS_ThrowRangeError(ctx, "invalid millisecond");
+ if (us < 0 || us > 999)
+ return JS_ThrowRangeError(ctx, "invalid microsecond");
+ if (ns < 0 || ns > 999)
+ return JS_ThrowRangeError(ctx, "invalid nanosecond");
+ } else {
+ if (hour > 23) hour = 23; else if (hour < 0) hour = 0;
+ if (minute > 59) minute = 59; else if (minute < 0) minute = 0;
+ if (second > 59) second = 59; else if (second < 0) second = 0;
+ if (ms > 999) ms = 999; else if (ms < 0) ms = 0;
+ if (us > 999) us = 999; else if (us < 0) us = 0;
+ if (ns > 999) ns = 999; else if (ns < 0) ns = 0;
+ }
+
+ if (fields->calendar != CAL_ISO8601 && fields->calendar != CAL_GREGORY) {
+ int iso_y, iso_m, iso_d;
+ ti_calendar_date_to_iso(fields->calendar, year, month, day, &iso_y, &iso_m, &iso_d);
+ year = iso_y; month = iso_m; day = iso_d;
+ }
+ return js_create_plaindatetime_with_calendar(ctx, year, month, day, hour, minute, second, ms, us, ns, fields->calendar);
+}
+
+static void pdt_balance_date(int *year, int *month, int *day);
+
+static int pdt_is_valid_date(int year, int month, int day)
+{
+ if (month < 1 || month > 12)
+ return 0;
+ if (day < 1 || day > pd_days_in_month(year, month))
+ return 0;
+ return 1;
+}
+
+static int pdt_is_valid_date_for_calendar(int year, int month, int day, CalendarType cal)
+{
+ int max_month = (cal == CAL_ISO8601 || cal == CAL_GREGORY) ? 12 : ti_calendar_months_in_year(cal, year);
+ if (month < 1 || month > max_month)
+ return 0;
+ {
+ int dim = (cal == CAL_ISO8601 || cal == CAL_GREGORY) ? pd_days_in_month(year, month) : ti_calendar_days_in_month(cal, year, month);
+ if (day < 1 || day > dim)
+ return 0;
+ }
+ return 1;
+}
+
+static int pdt_is_valid_time(int hour, int minute, int second,
+ int millisecond, int microsecond, int nanosecond)
+{
+ if (hour < 0 || hour > 23)
+ return 0;
+ if (minute < 0 || minute > 59)
+ return 0;
+ if (second < 0 || second > 59)
+ return 0;
+ if (millisecond < 0 || millisecond > 999)
+ return 0;
+ if (microsecond < 0 || microsecond > 999)
+ return 0;
+ if (nanosecond < 0 || nanosecond > 999)
+ return 0;
+ return 1;
+}
+
+/* PlainDateTime limits: -271821-04-19T00:00:00.000000001 to +275760-09-13T23:59:59.999999999 */
+int pdt_is_within_limits(int year, int month, int day,
+ int hour, int minute, int second,
+ int millisecond, int microsecond, int nanosecond)
+{
+ if (year < -271821 || year > 275760)
+ return 0;
+ if (year == -271821) {
+ if (month < 4) return 0;
+ if (month == 4 && day < 19) return 0;
+ if (month == 4 && day == 19) {
+ if (hour < 0 || minute < 0 || second < 0 ||
+ millisecond < 0 || microsecond < 0 || nanosecond < 0)
+ return 0;
+ /* Minimum is 00:00:00.000000001; 00:00:00.000000000 is out of range */
+ if (hour == 0 && minute == 0 && second == 0 &&
+ millisecond == 0 && microsecond == 0 && nanosecond == 0)
+ return 0;
+ }
+ }
+ if (year == 275760) {
+ if (month > 9) return 0;
+ if (month == 9 && day > 13) return 0;
+ if (month == 9 && day == 13) {
+ if (hour > 23 || minute > 59 || second > 59 ||
+ millisecond > 999 || microsecond > 999 || nanosecond > 999)
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static int pdt_to_integer_with_truncation(JSContext *ctx, JSValueConst val, int *pres)
+{
+ double d;
+ if (JS_IsUndefined(val)) {
+ *pres = 0;
+ return 0;
+ }
+ if (JS_ToFloat64(ctx, &d, val))
+ return -1;
+ if (!isfinite(d)) {
+ JS_ThrowRangeError(ctx, "value must be an integer");
+ return -1;
+ }
+ if (d < INT32_MIN || d > INT32_MAX) {
+ JS_ThrowRangeError(ctx, "value out of range");
+ return -1;
+ }
+ *pres = (int)(d < 0 ? ceil(d) : floor(d));
+ return 0;
+}
+
+/* Temporal.PlainDateTime constructor */
+static JSValue js_plaindatetime_constructor(JSContext *ctx, JSValueConst new_target,
+ int argc, JSValueConst *argv)
+{
+ int year, month, day, hour = 0, minute = 0, second = 0;
+ int millisecond = 0, microsecond = 0, nanosecond = 0;
+ if (JS_IsUndefined(new_target)) {
+ return JS_ThrowTypeError(ctx, "Temporal.PlainDateTime constructor cannot be called as a function");
+ }
+ if (JS_IsUndefined(argv[0])) {
+ JS_ThrowRangeError(ctx, "value must be an integer");
+ return JS_EXCEPTION;
+ }
+ if (pdt_to_integer_with_truncation(ctx, argv[0], &year) < 0)
+ return JS_EXCEPTION;
+ if (JS_IsUndefined(argv[1])) {
+ JS_ThrowRangeError(ctx, "value must be an integer");
+ return JS_EXCEPTION;
+ }
+ if (pdt_to_integer_with_truncation(ctx, argv[1], &month) < 0)
+ return JS_EXCEPTION;
+ if (JS_IsUndefined(argv[2])) {
+ JS_ThrowRangeError(ctx, "value must be an integer");
+ return JS_EXCEPTION;
+ }
+ if (pdt_to_integer_with_truncation(ctx, argv[2], &day) < 0)
+ return JS_EXCEPTION;
+ if (argc > 3 && pdt_to_integer_with_truncation(ctx, argv[3], &hour) < 0)
+ return JS_EXCEPTION;
+ if (argc > 4 && pdt_to_integer_with_truncation(ctx, argv[4], &minute) < 0)
+ return JS_EXCEPTION;
+ if (argc > 5 && pdt_to_integer_with_truncation(ctx, argv[5], &second) < 0)
+ return JS_EXCEPTION;
+ if (argc > 6 && pdt_to_integer_with_truncation(ctx, argv[6], &millisecond) < 0)
+ return JS_EXCEPTION;
+ if (argc > 7 && pdt_to_integer_with_truncation(ctx, argv[7], µsecond) < 0)
+ return JS_EXCEPTION;
+ if (argc > 8 && pdt_to_integer_with_truncation(ctx, argv[8], &nanosecond) < 0)
+ return JS_EXCEPTION;
+ if (!pdt_is_valid_date(year, month, day))
+ return JS_ThrowRangeError(ctx, "invalid PlainDateTime date");
+ if (!pdt_is_valid_time(hour, minute, second, millisecond, microsecond, nanosecond))
+ return JS_ThrowRangeError(ctx, "invalid PlainDateTime time");
+ {
+ CalendarType calendar = CAL_ISO8601;
+ if (argc > 9) {
+ int cal_res = ti_validate_constructor_calendar(ctx, argv[9], &calendar);
+ if (cal_res < 0)
+ return JS_EXCEPTION;
+ }
+ if ((calendar == CAL_ISO8601 || calendar == CAL_GREGORY) &&
+ !pdt_is_within_limits(year, month, day, hour, minute, second,
+ millisecond, microsecond, nanosecond))
+ return JS_ThrowRangeError(ctx, "PlainDateTime outside valid range");
+ {
+ JSPlainDateTimeData *s = js_mallocz(ctx, sizeof(*s));
+ JSValue obj;
+ if (!s)
+ return JS_EXCEPTION;
+ s->year = year;
+ s->month = month;
+ s->day = day;
+ s->hour = hour;
+ s->minute = minute;
+ s->second = second;
+ s->millisecond = millisecond;
+ s->microsecond = microsecond;
+ s->nanosecond = nanosecond;
+ s->calendar = calendar;
+ obj = js_create_temporal_object(ctx, new_target, js_plaindatetime_class_id, s);
+ if (JS_IsException(obj)) {
+ js_free(ctx, s);
+ return JS_EXCEPTION;
+ }
+ return obj;
+ }
+ }
+}
+
+/* Getters */
+enum {
+ PLAINDATETIME_YEAR = 0,
+ PLAINDATETIME_MONTH,
+ PLAINDATETIME_DAY,
+ PLAINDATETIME_HOUR,
+ PLAINDATETIME_MINUTE,
+ PLAINDATETIME_SECOND,
+ PLAINDATETIME_MILLISECOND,
+ PLAINDATETIME_MICROSECOND,
+ PLAINDATETIME_NANOSECOND,
+};
+
+static JSValue js_plaindatetime_get_field(JSContext *ctx, JSValueConst this_val, int magic)
+{
+ JSPlainDateTimeData *s = JS_GetOpaque2(ctx, this_val, js_plaindatetime_class_id);
+ int cal_y, cal_m, cal_d;
+ if (!s)
+ return JS_EXCEPTION;
+ pdt_get_calendar_date(s, &cal_y, &cal_m, &cal_d);
+ switch (magic) {
+ case PLAINDATETIME_YEAR: return JS_NewInt32(ctx, cal_y);
+ case PLAINDATETIME_MONTH: return JS_NewInt32(ctx, cal_m);
+ case PLAINDATETIME_DAY: return JS_NewInt32(ctx, cal_d);
+ case PLAINDATETIME_HOUR: return JS_NewInt32(ctx, s->hour);
+ case PLAINDATETIME_MINUTE: return JS_NewInt32(ctx, s->minute);
+ case PLAINDATETIME_SECOND: return JS_NewInt32(ctx, s->second);
+ case PLAINDATETIME_MILLISECOND: return JS_NewInt32(ctx, s->millisecond);
+ case PLAINDATETIME_MICROSECOND: return JS_NewInt32(ctx, s->microsecond);
+ case PLAINDATETIME_NANOSECOND: return JS_NewInt32(ctx, s->nanosecond);
+ default: return JS_UNDEFINED;
+ }
+}
+
+static JSValue js_plaindatetime_get_monthCode(JSContext *ctx, JSValueConst this_val)
+{
+ JSPlainDateTimeData *s = JS_GetOpaque2(ctx, this_val, js_plaindatetime_class_id);
+ int cal_y, cal_m, cal_d;
+ if (!s)
+ return JS_EXCEPTION;
+ pdt_get_calendar_date(s, &cal_y, &cal_m, &cal_d);
+ return ti_get_month_code(ctx, s->calendar, cal_y, cal_m);
+}
+
+static JSValue js_plaindatetime_get_calendarId(JSContext *ctx, JSValueConst this_val)
+{
+ JSPlainDateTimeData *s = JS_GetOpaque2(ctx, this_val, js_plaindatetime_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ return JS_NewString(ctx, ti_calendar_enum_to_string(s->calendar));
+}
+
+static int pdt_day_of_week(int year, int month, int day)
+{
+ int a = (14 - month) / 12;
+ int y = year - a;
+ int m = month + 12 * a - 2;
+ int d = (day + y + y / 4 - y / 100 + y / 400 + (31 * m) / 12) % 7;
+ return (d == 0) ? 7 : d;
+}
+
+static void pdt_iso_week(int year, int month, int day, int *weekYear, int *weekNumber)
+{
+ int dow = pdt_day_of_week(year, month, day);
+ int ordinal = pd_day_of_year(year, month, day);
+ int thursdayOrdinal = ordinal + (4 - dow);
+ int y = year;
+ int daysInY = pd_is_leap_year(y) ? 366 : 365;
+ if (thursdayOrdinal <= 0) {
+ y = year - 1;
+ daysInY = pd_is_leap_year(y) ? 366 : 365;
+ thursdayOrdinal += daysInY;
+ } else if (thursdayOrdinal > daysInY) {
+ thursdayOrdinal -= daysInY;
+ y = year + 1;
+ }
+ *weekYear = y;
+ *weekNumber = (thursdayOrdinal - 1) / 7 + 1;
+}
+
+static JSValue js_plaindatetime_get_era(JSContext *ctx, JSValueConst this_val)
+{
+ JSPlainDateTimeData *s = JS_GetOpaque2(ctx, this_val, js_plaindatetime_class_id);
+ TIEra era;
+ int dummy_era_year;
+ int cal_y, cal_m, cal_d;
+ if (!s)
+ return JS_EXCEPTION;
+ if (s->calendar == CAL_ISO8601)
+ return JS_UNDEFINED;
+ pdt_get_calendar_date(s, &cal_y, &cal_m, &cal_d);
+ ti_calendar_era_and_era_year(s->calendar, s->year, s->month, s->day, cal_y, &era, &dummy_era_year);
+ if (era != TI_ERA_UNKNOWN)
+ return JS_NewString(ctx, ti_era_to_string(era));
+ return JS_UNDEFINED;
+}
+
+static JSValue js_plaindatetime_get_eraYear(JSContext *ctx, JSValueConst this_val)
+{
+ JSPlainDateTimeData *s = JS_GetOpaque2(ctx, this_val, js_plaindatetime_class_id);
+ int era_year;
+ TIEra era;
+ int cal_y, cal_m, cal_d;
+ if (!s)
+ return JS_EXCEPTION;
+ if (s->calendar == CAL_ISO8601)
+ return JS_UNDEFINED;
+ pdt_get_calendar_date(s, &cal_y, &cal_m, &cal_d);
+ ti_calendar_era_and_era_year(s->calendar, s->year, s->month, s->day, cal_y, &era, &era_year);
+ if (era != TI_ERA_UNKNOWN)
+ return JS_NewInt32(ctx, era_year);
+ return JS_UNDEFINED;
+}
+
+static JSValue js_plaindatetime_get_inLeapYear(JSContext *ctx, JSValueConst this_val)
+{
+ JSPlainDateTimeData *s = JS_GetOpaque2(ctx, this_val, js_plaindatetime_class_id);
+ int cal_y, cal_m, cal_d;
+ if (!s)
+ return JS_EXCEPTION;
+ pdt_get_calendar_date(s, &cal_y, &cal_m, &cal_d);
+ return JS_NewBool(ctx, ti_calendar_is_leap_year(s->calendar, cal_y));
+}
+
+static JSValue js_plaindatetime_get_daysInMonth(JSContext *ctx, JSValueConst this_val)
+{
+ JSPlainDateTimeData *s = JS_GetOpaque2(ctx, this_val, js_plaindatetime_class_id);
+ int cal_y, cal_m, cal_d;
+ if (!s)
+ return JS_EXCEPTION;
+ pdt_get_calendar_date(s, &cal_y, &cal_m, &cal_d);
+ return JS_NewInt32(ctx, ti_calendar_days_in_month(s->calendar, cal_y, cal_m));
+}
+
+static JSValue js_plaindatetime_get_daysInYear(JSContext *ctx, JSValueConst this_val)
+{
+ JSPlainDateTimeData *s = JS_GetOpaque2(ctx, this_val, js_plaindatetime_class_id);
+ int cal_y, cal_m, cal_d;
+ if (!s)
+ return JS_EXCEPTION;
+ pdt_get_calendar_date(s, &cal_y, &cal_m, &cal_d);
+ return JS_NewInt32(ctx, ti_calendar_days_in_year(s->calendar, cal_y));
+}
+
+static JSValue js_plaindatetime_get_daysInWeek(JSContext *ctx, JSValueConst this_val)
+{
+ JSPlainDateTimeData *s = JS_GetOpaque2(ctx, this_val, js_plaindatetime_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ return JS_NewInt32(ctx, 7);
+}
+
+static JSValue js_plaindatetime_get_monthsInYear(JSContext *ctx, JSValueConst this_val)
+{
+ JSPlainDateTimeData *s = JS_GetOpaque2(ctx, this_val, js_plaindatetime_class_id);
+ int cal_y, cal_m, cal_d;
+ if (!s)
+ return JS_EXCEPTION;
+ pdt_get_calendar_date(s, &cal_y, &cal_m, &cal_d);
+ return JS_NewInt32(ctx, ti_calendar_months_in_year(s->calendar, cal_y));
+}
+
+static JSValue js_plaindatetime_get_dayOfYear(JSContext *ctx, JSValueConst this_val)
+{
+ JSPlainDateTimeData *s = JS_GetOpaque2(ctx, this_val, js_plaindatetime_class_id);
+ int cal_y, cal_m, cal_d;
+ if (!s)
+ return JS_EXCEPTION;
+ pdt_get_calendar_date(s, &cal_y, &cal_m, &cal_d);
+ return JS_NewInt32(ctx, ti_calendar_day_of_year(s->calendar, cal_y, cal_m, cal_d));
+}
+
+static JSValue js_plaindatetime_get_dayOfWeek(JSContext *ctx, JSValueConst this_val)
+{
+ JSPlainDateTimeData *s = JS_GetOpaque2(ctx, this_val, js_plaindatetime_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ return JS_NewInt32(ctx, pdt_day_of_week(s->year, s->month, s->day));
+}
+
+static JSValue js_plaindatetime_get_weekOfYear(JSContext *ctx, JSValueConst this_val)
+{
+ JSPlainDateTimeData *s = JS_GetOpaque2(ctx, this_val, js_plaindatetime_class_id);
+ int weekYear, weekNumber;
+ if (!s)
+ return JS_EXCEPTION;
+ if (s->calendar != CAL_ISO8601)
+ return JS_UNDEFINED;
+ pdt_iso_week(s->year, s->month, s->day, &weekYear, &weekNumber);
+ return JS_NewInt32(ctx, weekNumber);
+}
+
+static JSValue js_plaindatetime_get_yearOfWeek(JSContext *ctx, JSValueConst this_val)
+{
+ JSPlainDateTimeData *s = JS_GetOpaque2(ctx, this_val, js_plaindatetime_class_id);
+ int weekYear, weekNumber;
+ if (!s)
+ return JS_EXCEPTION;
+ if (s->calendar != CAL_ISO8601)
+ return JS_UNDEFINED;
+ pdt_iso_week(s->year, s->month, s->day, &weekYear, &weekNumber);
+ return JS_NewInt64(ctx, weekYear);
+}
+
+/* Temporal.PlainDateTime.prototype.equals */
+static JSValue js_plaindatetime_from(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv);
+
+static JSValue js_plaindatetime_equals(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ (void)this_val;
+ (void)argc;
+ JSPlainDateTimeData *s, *other;
+ JSValue other_val;
+ s = JS_GetOpaque2(ctx, this_val, js_plaindatetime_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ if (JS_IsNumber(argv[0]) || JS_IsUndefined(argv[0]) || JS_IsNull(argv[0]) ||
+ JS_IsBool(argv[0]) || JS_IsBigInt(ctx, argv[0]))
+ return JS_ThrowTypeError(ctx, "invalid PlainDateTime");
+ other_val = js_plaindatetime_from(ctx, JS_UNDEFINED, 1, argv);
+ if (JS_IsException(other_val))
+ return JS_EXCEPTION;
+ other = JS_GetOpaque(other_val, js_plaindatetime_class_id);
+ if (!other) {
+ JS_FreeValue(ctx, other_val);
+ return JS_NewBool(ctx, 0);
+ }
+ {
+ int res = s->year == other->year && s->month == other->month &&
+ s->day == other->day && s->hour == other->hour &&
+ s->minute == other->minute && s->second == other->second &&
+ s->millisecond == other->millisecond &&
+ s->microsecond == other->microsecond &&
+ s->nanosecond == other->nanosecond &&
+ s->calendar == other->calendar;
+ JS_FreeValue(ctx, other_val);
+ return JS_NewBool(ctx, res);
+ }
+}
+
+/* Temporal.PlainDateTime.compare */
+static JSValue js_plaindatetime_compare(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ (void)argc;
+ (void)this_val;
+ JSPlainDateTimeData *s1, *s2;
+ JSValue v1, v2;
+ int cmp;
+ v1 = js_plaindatetime_from(ctx, JS_UNDEFINED, 1, argv);
+ if (JS_IsException(v1))
+ return JS_EXCEPTION;
+ v2 = js_plaindatetime_from(ctx, JS_UNDEFINED, 1, argv + 1);
+ if (JS_IsException(v2)) {
+ JS_FreeValue(ctx, v1);
+ return JS_EXCEPTION;
+ }
+ s1 = JS_GetOpaque(v1, js_plaindatetime_class_id);
+ s2 = JS_GetOpaque(v2, js_plaindatetime_class_id);
+ if (!s1 || !s2) {
+ JS_FreeValue(ctx, v1);
+ JS_FreeValue(ctx, v2);
+ return JS_ThrowTypeError(ctx, "compare arguments must be PlainDateTime objects");
+ }
+ if (s1->year != s2->year)
+ cmp = s1->year < s2->year ? -1 : 1;
+ else if (s1->month != s2->month)
+ cmp = s1->month < s2->month ? -1 : 1;
+ else if (s1->day != s2->day)
+ cmp = s1->day < s2->day ? -1 : 1;
+ else if (s1->hour != s2->hour)
+ cmp = s1->hour < s2->hour ? -1 : 1;
+ else if (s1->minute != s2->minute)
+ cmp = s1->minute < s2->minute ? -1 : 1;
+ else if (s1->second != s2->second)
+ cmp = s1->second < s2->second ? -1 : 1;
+ else if (s1->millisecond != s2->millisecond)
+ cmp = s1->millisecond < s2->millisecond ? -1 : 1;
+ else if (s1->microsecond != s2->microsecond)
+ cmp = s1->microsecond < s2->microsecond ? -1 : 1;
+ else if (s1->nanosecond != s2->nanosecond)
+ cmp = s1->nanosecond < s2->nanosecond ? -1 : 1;
+ else
+ cmp = 0;
+ JS_FreeValue(ctx, v1);
+ JS_FreeValue(ctx, v2);
+ return JS_NewInt32(ctx, cmp);
+}
+
+/* Format PlainDateTime as ISO string */
+static JSValue js_plaindatetime_toString(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSPlainDateTimeData *s;
+ JSPlainTimeData rounded = {0};
+ char buf[128];
+ int n;
+ int calendarName = 0; /* 0=auto (no annotation for ISO), 1=always, 2=critical */
+ int precision_type = -1; /* -1=auto, 0=second, 1-9=digits, 10=minute, 11=second, 12=ms, 13=us, 14=ns */
+ int fsd_is_auto = 1;
+ int fsd_value = 0;
+ TIUnit smallestUnit = TI_UNIT_INVALID;
+ int has_smallestUnit = 0;
+ TIRoundingMode rounding_mode = ROUND_TRUNC;
+ if (argc >= 1 && ti_validate_options_object(ctx, argv[0]) < 0)
+ return JS_EXCEPTION;
+ s = JS_GetOpaque2(ctx, this_val, js_plaindatetime_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ if (argc >= 1 && JS_IsObject(argv[0])) {
+ /* Step 1: calendarName */
+ if (ti_get_calendar_name_option(ctx, argv[0], &calendarName) < 0)
+ return JS_EXCEPTION;
+ /* Step 2: fractionalSecondDigits */
+ {
+ int fsd = ti_get_fractional_second_digits_option(ctx, argv[0], &fsd_value);
+ if (fsd < 0)
+ return JS_EXCEPTION;
+ if (fsd_value != -1)
+ fsd_is_auto = 0;
+ }
+ /* Step 3: roundingMode */
+ {
+ TIRoundingMode mode;
+ if (ti_get_rounding_mode_option_default(ctx, argv[0], &mode, ROUND_TRUNC) < 0)
+ return JS_EXCEPTION;
+ rounding_mode = mode;
+ }
+ /* Step 4: smallestUnit */
+ {
+ TIUnit unit;
+ if (ti_parse_unit_option(ctx, argv[0], "smallestUnit", &unit, TI_UNIT_OPT_ALLOW_UNDEFINED, TI_UNIT_INVALID) < 0)
+ return JS_EXCEPTION;
+ if (unit != TI_UNIT_INVALID) {
+ smallestUnit = unit;
+ has_smallestUnit = 1;
+ }
+ }
+ }
+ /* Validation */
+ if (has_smallestUnit && (smallestUnit == TI_UNIT_INVALID || smallestUnit < TI_UNIT_MINUTE || smallestUnit > TI_UNIT_NANOSECOND))
+ return JS_ThrowRangeError(ctx, "invalid smallestUnit");
+ /* Determine precision */
+ if (has_smallestUnit && smallestUnit >= TI_UNIT_MINUTE && smallestUnit <= TI_UNIT_NANOSECOND) {
+ precision_type = ti_precision_from_smallest_unit(smallestUnit);
+ } else if (!fsd_is_auto) {
+ precision_type = fsd_value;
+ } else {
+ precision_type = -1; /* auto */
+ }
+ /* Apply rounding */
+ {
+ int fmt_year = s->year;
+ int fmt_month = s->month;
+ int fmt_day = s->day;
+ rounded.hour = s->hour;
+ rounded.minute = s->minute;
+ rounded.second = s->second;
+ rounded.millisecond = s->millisecond;
+ rounded.microsecond = s->microsecond;
+ rounded.nanosecond = s->nanosecond;
+ if (precision_type >= 0 && precision_type != 14) {
+ int64_t total_ns = ((int64_t)s->hour * 3600 + s->minute * 60 + s->second) * 1000000000LL
+ + s->millisecond * 1000000LL + s->microsecond * 1000LL + s->nanosecond;
+ int64_t increment_ns;
+ switch (precision_type) {
+ case 0:
+ case 11:
+ increment_ns = 1000000000LL;
+ break;
+ case 10:
+ increment_ns = 60000000000LL;
+ break;
+ case 12:
+ increment_ns = 1000000LL;
+ break;
+ case 13:
+ increment_ns = 1000LL;
+ break;
+ default: /* 1-9 digits */
+ increment_ns = 1;
+ {
+ int i;
+ for (i = 0; i < 9 - precision_type; i++) increment_ns *= 10;
+ }
+ break;
+ }
+ int64_t rounded_ns = ti_round_to_increment_as_if_positive(total_ns, increment_ns, rounding_mode);
+ if (rounded_ns >= 86400000000000LL) {
+ rounded_ns -= 86400000000000LL;
+ fmt_day++;
+ pdt_balance_date(&fmt_year, &fmt_month, &fmt_day);
+ }
+ rounded.hour = (int)(rounded_ns / 3600000000000LL);
+ rounded_ns %= 3600000000000LL;
+ rounded.minute = (int)(rounded_ns / 60000000000LL);
+ rounded_ns %= 60000000000LL;
+ rounded.second = (int)(rounded_ns / 1000000000LL);
+ rounded_ns %= 1000000000LL;
+ rounded.millisecond = (int)(rounded_ns / 1000000LL);
+ rounded_ns %= 1000000LL;
+ rounded.microsecond = (int)(rounded_ns / 1000LL);
+ rounded.nanosecond = (int)(rounded_ns % 1000LL);
+ if ((s->calendar == CAL_ISO8601 || s->calendar == CAL_GREGORY) &&
+ !pdt_is_within_limits(fmt_year, fmt_month, fmt_day,
+ rounded.hour, rounded.minute, rounded.second,
+ rounded.millisecond, rounded.microsecond, rounded.nanosecond))
+ return JS_ThrowRangeError(ctx, "PlainDateTime outside valid range");
+ }
+ /* Format date */
+ if (fmt_year < 0)
+ n = snprintf(buf, sizeof(buf), "-%06d-%02d-%02dT",
+ -fmt_year, fmt_month, fmt_day);
+ else if (fmt_year >= 10000)
+ n = snprintf(buf, sizeof(buf), "+%06d-%02d-%02dT",
+ fmt_year, fmt_month, fmt_day);
+ else
+ n = snprintf(buf, sizeof(buf), "%04d-%02d-%02dT",
+ fmt_year, fmt_month, fmt_day);
+ }
+ /* Format time */
+ if (precision_type == 10) { /* minute */
+ n += snprintf(buf + n, sizeof(buf) - (size_t)n, "%02d:%02d",
+ rounded.hour, rounded.minute);
+ } else {
+ n += snprintf(buf + n, sizeof(buf) - (size_t)n, "%02d:%02d:%02d",
+ rounded.hour, rounded.minute, rounded.second);
+ if (precision_type != 0 && precision_type != 11) {
+ int digits = 9;
+ if (precision_type >= 1 && precision_type <= 9)
+ digits = precision_type;
+ else if (precision_type == 12)
+ digits = 3;
+ else if (precision_type == 13)
+ digits = 6;
+ else if (precision_type == 14)
+ digits = 9;
+ char frac[16];
+ snprintf(frac, sizeof(frac), "%03d%03d%03d",
+ rounded.millisecond, rounded.microsecond, rounded.nanosecond);
+ if (precision_type == -1) {
+ while (digits > 0 && frac[digits - 1] == '0')
+ digits--;
+ }
+ if (digits > 0) {
+ frac[digits] = '\0';
+ n += snprintf(buf + n, sizeof(buf) - (size_t)n, ".%s", frac);
+ }
+ }
+ }
+ ti_append_calendar_annotation(buf, sizeof(buf), s->calendar, calendarName);
+ return JS_NewString(ctx, buf);
+}
+
+static JSValue js_plaindatetime_toJSON(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ (void)argc;
+ (void)argv;
+ return js_plaindatetime_toString(ctx, this_val, 0, NULL);
+}
+
+static JSValue js_plaindatetime_toLocaleString(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSPlainDateTimeData *s = JS_GetOpaque2(ctx, this_val, js_plaindatetime_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ return ti_temporal_toLocaleString(ctx, this_val, argc, argv, 0, js_plaindatetime_toString);
+}
+
+static JSValue js_plaindatetime_valueOf(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ (void)argc;
+ (void)argv;
+ (void)this_val;
+ return JS_ThrowTypeError(ctx, "cannot compare Temporal.PlainDateTime with < or >");
+}
+
+/* Temporal.PlainDateTime.prototype.with */
+static JSValue js_plaindatetime_with(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSPlainDateTimeData *s;
+ int year, month, day, hour, minute, second;
+ int millisecond, microsecond, nanosecond;
+ int orig_cal_year, orig_cal_month;
+ JSValue val;
+ int has_month_prop = 0;
+ int has_year_prop = 0;
+ int has_month_code = 0;
+ int month_code_val = 0;
+ int has_month_code_l = 0;
+ int overflow_constrain = 1;
+ TIPreparedFields fields;
+ s = JS_GetOpaque2(ctx, this_val, js_plaindatetime_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ ti_iso_to_calendar_date(s->calendar, s->year, s->month, s->day, &orig_cal_year, &orig_cal_month, &day);
+ year = orig_cal_year; month = orig_cal_month;
+ hour = s->hour; minute = s->minute; second = s->second;
+ millisecond = s->millisecond; microsecond = s->microsecond; nanosecond = s->nanosecond;
+ val = argv[0];
+ if (ti_is_partial_temporal_object(ctx, val) < 0)
+ return JS_EXCEPTION;
+ if (ti_prepare_calendar_fields(ctx, val,
+ TI_FIELD_DAY | TI_FIELD_MONTH | TI_FIELD_MONTH_CODE |
+ TI_FIELD_YEAR | TI_FIELD_HOUR | TI_FIELD_MINUTE |
+ TI_FIELD_SECOND | TI_FIELD_MILLISECOND | TI_FIELD_MICROSECOND |
+ TI_FIELD_NANOSECOND,
+ 0, 1, &fields, s->calendar) < 0)
+ return JS_EXCEPTION;
+ /* Merge fields with existing object */
+ if (fields.present_mask & TI_FIELD_DAY) {
+ day = fields.day;
+ }
+ if (fields.present_mask & TI_FIELD_HOUR) {
+ hour = fields.hour;
+ }
+ if (fields.present_mask & TI_FIELD_MICROSECOND) {
+ microsecond = fields.microsecond;
+ }
+ if (fields.present_mask & TI_FIELD_MILLISECOND) {
+ millisecond = fields.millisecond;
+ }
+ if (fields.present_mask & TI_FIELD_MINUTE) {
+ minute = fields.minute;
+ }
+ if (fields.present_mask & TI_FIELD_MONTH) {
+ has_month_prop = 1;
+ month = fields.month;
+ }
+ if (fields.present_mask & TI_FIELD_MONTH_CODE) {
+ has_month_code = 1;
+ month_code_val = fields.month_from_code;
+ has_month_code_l = fields.month_code_has_l;
+ }
+ if (fields.present_mask & TI_FIELD_NANOSECOND) {
+ nanosecond = fields.nanosecond;
+ }
+ if (fields.present_mask & TI_FIELD_SECOND) {
+ second = fields.second;
+ }
+ if (fields.present_mask & TI_FIELD_YEAR) {
+ has_year_prop = 1;
+ year = (int)fields.year;
+ }
+ /* Validate options type */
+ if (argc >= 2 && ti_validate_options_object(ctx, argv[1]) < 0)
+ return JS_EXCEPTION;
+ if (argc >= 2 && !JS_IsUndefined(argv[1])) {
+ if (ti_get_overflow_option(ctx, argv[1], &overflow_constrain) < 0)
+ return JS_EXCEPTION;
+ }
+ /* era/eraYear processing */
+ if (fields.present_mask & (TI_FIELD_ERA | TI_FIELD_ERA_YEAR)) {
+ if (!ti_calendar_requires_era(s->calendar))
+ return JS_ThrowTypeError(ctx, "era and eraYear are invalid for this calendar");
+ if (!(fields.present_mask & TI_FIELD_ERA) || !(fields.present_mask & TI_FIELD_ERA_YEAR))
+ return JS_ThrowTypeError(ctx, "era and eraYear must both be present");
+ {
+ int cal_year_from_era;
+ if (fields.era == TI_ERA_UNKNOWN || ti_calendar_era_to_calendar_year(s->calendar, fields.era, (int)fields.era_year, &cal_year_from_era) < 0)
+ return JS_ThrowRangeError(ctx, "invalid era");
+ if (has_year_prop && year != cal_year_from_era)
+ return JS_ThrowRangeError(ctx, "year and era/eraYear must agree");
+ year = cal_year_from_era;
+ }
+ }
+
+ /* monthCode processing */
+ if (has_month_code) {
+ if (s->calendar == CAL_ISO8601 || s->calendar == CAL_GREGORY) {
+ if (month_code_val < 1 || month_code_val > 12 || has_month_code_l)
+ return JS_ThrowRangeError(ctx, "monthCode is not valid for ISO 8601 calendar");
+ } else {
+ if (!ti_calendar_validate_month_code(s->calendar, month_code_val, has_month_code_l))
+ return JS_ThrowRangeError(ctx, "monthCode is not valid for this calendar");
+ }
+ }
+ if (has_month_code && has_month_prop) {
+ int resolved_month = ti_calendar_month_code_to_month(s->calendar, year, month_code_val, has_month_code_l);
+ if (resolved_month >= 0 && resolved_month != month)
+ return JS_ThrowRangeError(ctx, "month and monthCode must agree");
+ }
+ if (has_month_code) {
+ if (!(s->calendar == CAL_ISO8601 || s->calendar == CAL_GREGORY)) {
+ int resolved_month = ti_calendar_month_code_to_month(s->calendar, year, month_code_val, has_month_code_l);
+ if (resolved_month < 0)
+ return JS_ThrowRangeError(ctx, "monthCode is not valid for this calendar");
+ month = resolved_month;
+ } else {
+ month = month_code_val;
+ }
+ }
+ /* If monthCode was preserved from source but year changed, re-resolve */
+ if (!has_month_code && !has_month_prop && year != orig_cal_year) {
+ int orig_mc, orig_has_l;
+ int result_mc, result_has_l;
+ int resolved_month;
+ ti_calendar_month_to_month_code(s->calendar, orig_cal_year, orig_cal_month, &orig_mc, &orig_has_l);
+ resolved_month = ti_calendar_month_code_to_month(s->calendar, year, orig_mc, orig_has_l);
+ if (resolved_month < 0) {
+ if (!overflow_constrain)
+ return JS_ThrowRangeError(ctx, "invalid PlainDateTime date");
+ resolved_month = ti_calendar_month_code_to_month(s->calendar, year, orig_mc, 0);
+ }
+ month = resolved_month;
+ ti_calendar_month_to_month_code(s->calendar, year, month, &result_mc, &result_has_l);
+ if (!overflow_constrain && (result_mc != orig_mc || result_has_l != orig_has_l))
+ return JS_ThrowRangeError(ctx, "invalid PlainDateTime date");
+ }
+ {
+ int is_valid = pdt_is_valid_date_for_calendar(year, month, day, s->calendar);
+ if (!is_valid) {
+ if (!overflow_constrain)
+ return JS_ThrowRangeError(ctx, "invalid PlainDateTime date");
+ {
+ int max_month = ti_calendar_months_in_year(s->calendar, year);
+ if (month > max_month)
+ month = max_month;
+ else if (month < 1)
+ month = 1;
+ }
+ {
+ int dim = ti_calendar_days_in_month(s->calendar, year, month);
+ if (day > dim)
+ day = dim;
+ else if (day < 1)
+ day = 1;
+ }
+ }
+ }
+ if (!pdt_is_valid_time(hour, minute, second, millisecond, microsecond, nanosecond)) {
+ if (!overflow_constrain)
+ return JS_ThrowRangeError(ctx, "invalid PlainDateTime time");
+ /* Clamp each field independently to valid range */
+ if (nanosecond > 999) nanosecond = 999;
+ else if (nanosecond < 0) nanosecond = 0;
+ if (microsecond > 999) microsecond = 999;
+ else if (microsecond < 0) microsecond = 0;
+ if (millisecond > 999) millisecond = 999;
+ else if (millisecond < 0) millisecond = 0;
+ if (second > 59) second = 59;
+ else if (second < 0) second = 0;
+ if (minute > 59) minute = 59;
+ else if (minute < 0) minute = 0;
+ if (hour > 23) {
+ hour = 23;
+ minute = 59;
+ second = 59;
+ millisecond = 999;
+ microsecond = 999;
+ nanosecond = 999;
+ } else if (hour < 0) {
+ hour = 0;
+ minute = 0;
+ second = 0;
+ millisecond = 0;
+ microsecond = 0;
+ nanosecond = 0;
+ }
+ }
+ {
+ int iso_y, iso_m, iso_d;
+ ti_calendar_date_to_iso(s->calendar, year, month, day, &iso_y, &iso_m, &iso_d);
+ year = iso_y; month = iso_m; day = iso_d;
+ }
+ if (!pdt_is_within_limits(year, month, day, hour, minute, second,
+ millisecond, microsecond, nanosecond))
+ return JS_ThrowRangeError(ctx, "PlainDateTime outside valid range");
+ return js_create_plaindatetime_with_calendar(ctx, year, month, day, hour, minute, second,
+ millisecond, microsecond, nanosecond, s->calendar);
+}
+
+static void pdt_balance_month(int *year, int *month)
+{
+ while (*month > 12) { *month -= 12; (*year)++; }
+ while (*month < 1) { *month += 12; (*year)--; }
+}
+
+static void pdt_balance_date(int *year, int *month, int *day)
+{
+ int dim;
+ pdt_balance_month(year, month);
+ while (*day > (dim = pd_days_in_month(*year, *month))) {
+ *day -= dim;
+ (*month)++;
+ if (*month > 12) { *month = 1; (*year)++; }
+ }
+ while (*day < 1) {
+ (*month)--;
+ if (*month < 1) { *month = 12; (*year)--; }
+ dim = pd_days_in_month(*year, *month);
+ *day += dim;
+ }
+}
+
+
+
+static JSValue js_plaindatetime_add_subtract(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv,
+ int is_add)
+{
+ JSPlainDateTimeData *s = JS_GetOpaque2(ctx, this_val, js_plaindatetime_class_id);
+ JSDurationData d = {0};
+ int year, month, day, hour, minute, second, ms, us, ns;
+ int overflow_constrain = 1;
+ js_int128_t total_ns, time_ns, dur_ns;
+ int64_t day_delta;
+ int sign = is_add ? 1 : -1;
+ if (!s)
+ return JS_EXCEPTION;
+ if (js_to_temporal_duration(ctx, argv[0], &d))
+ return JS_EXCEPTION;
+ if (duration_has_mixed_signs(&d))
+ return JS_ThrowRangeError(ctx, "mixed-sign duration not allowed");
+ if (duration_is_out_of_range(&d))
+ return JS_ThrowRangeError(ctx, "duration out of range");
+ if (argc >= 2 && ti_validate_options_object(ctx, argv[1]) < 0)
+ return JS_EXCEPTION;
+ if (argc >= 2 && !JS_IsUndefined(argv[1])) {
+ if (ti_get_overflow_option(ctx, argv[1], &overflow_constrain) < 0)
+ return JS_EXCEPTION;
+ }
+ /* Date part */
+ year = s->year; month = s->month; day = s->day;
+ ti_iso_to_calendar_date(s->calendar, s->year, s->month, s->day, &year, &month, &day);
+ {
+ int orig_mc = 0, orig_has_l = 0;
+ ti_calendar_month_to_month_code(s->calendar, year, month, &orig_mc, &orig_has_l);
+ year += sign * (int)d.years;
+ month = ti_calendar_month_code_to_month(s->calendar, year, orig_mc, orig_has_l);
+ if (month < 0) {
+ if (!overflow_constrain)
+ return JS_ThrowRangeError(ctx, "invalid PlainDateTime");
+ month = ti_calendar_month_code_to_month(s->calendar, year, orig_mc, 0);
+ } else if (!overflow_constrain) {
+ int result_mc, result_has_l;
+ ti_calendar_month_to_month_code(s->calendar, year, month, &result_mc, &result_has_l);
+ if (result_mc != orig_mc || result_has_l != orig_has_l)
+ return JS_ThrowRangeError(ctx, "invalid PlainDateTime");
+ }
+ }
+ month += sign * (int)d.months;
+ pdt_balance_month_calendar(&year, &month, s->calendar);
+ {
+ int dim = ti_calendar_days_in_month(s->calendar, year, month);
+ if (day > dim) {
+ if (!overflow_constrain)
+ return JS_ThrowRangeError(ctx, "invalid PlainDateTime");
+ day = dim;
+ }
+ }
+ day += sign * (int)(d.weeks * 7 + d.days);
+ pdt_balance_date_calendar(&year, &month, &day, s->calendar);
+ /* Time part */
+ hour = s->hour;
+ minute = s->minute;
+ second = s->second;
+ ms = s->millisecond;
+ us = (int)s->microsecond;
+ ns = (int)s->nanosecond;
+ {
+ int64_t time_sec = hour * 3600LL + minute * 60LL + second;
+ time_ns = (js_int128_t)time_sec * 1000000000LL + (js_int128_t)ms * 1000000LL + (js_int128_t)us * 1000LL + ns;
+ }
+ dur_ns = ti_duration_time_fields_to_ns(&d);
+ total_ns = time_ns + sign * dur_ns;
+ day_delta = (int64_t)(total_ns / 86400000000000LL);
+ total_ns = total_ns % 86400000000000LL;
+ if (total_ns < 0) {
+ day_delta--;
+ total_ns += 86400000000000LL;
+ }
+ day += (int)day_delta;
+ pdt_balance_date_calendar(&year, &month, &day, s->calendar);
+ hour = (int)(total_ns / 3600000000000LL);
+ total_ns %= 3600000000000LL;
+ minute = (int)(total_ns / 60000000000LL);
+ total_ns %= 60000000000LL;
+ second = (int)(total_ns / 1000000000LL);
+ total_ns %= 1000000000LL;
+ ms = (int)(total_ns / 1000000LL);
+ total_ns %= 1000000LL;
+ us = (int)(total_ns / 1000LL);
+ ns = (int)(total_ns % 1000LL);
+ {
+ int iso_y, iso_m, iso_d;
+ ti_calendar_date_to_iso(s->calendar, year, month, day, &iso_y, &iso_m, &iso_d);
+ year = iso_y; month = iso_m; day = iso_d;
+ }
+ if (!pdt_is_within_limits(year, month, day, hour, minute, second, ms, us, ns))
+ return JS_ThrowRangeError(ctx, "invalid PlainDateTime");
+ {
+ JSValue obj = js_create_plaindatetime(ctx, year, month, day, hour, minute, second, ms, us, ns);
+ if (!JS_IsException(obj)) {
+ JSPlainDateTimeData *res = JS_GetOpaque(obj, js_plaindatetime_class_id);
+ if (res)
+ res->calendar = s->calendar;
+ }
+ return obj;
+ }
+}
+
+static JSValue js_plaindatetime_withPlainTime(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSPlainDateTimeData *s = JS_GetOpaque2(ctx, this_val, js_plaindatetime_class_id);
+ JSPlainTimeData *pt;
+ JSValue pt_val;
+ if (!s)
+ return JS_EXCEPTION;
+ if (argc >= 1 && !JS_IsUndefined(argv[0])) {
+ pt_val = js_plaintime_from(ctx, JS_UNDEFINED, 1, argv);
+ } else {
+ JSPlainTimeData tmp = {0};
+ pt_val = js_create_plaintime(ctx, &tmp);
+ }
+ if (JS_IsException(pt_val))
+ return pt_val;
+ pt = JS_GetOpaque(pt_val, js_plaintime_class_id);
+ if (!pt) {
+ JS_FreeValue(ctx, pt_val);
+ return JS_ThrowTypeError(ctx, "invalid PlainTime");
+ }
+ {
+ JSValue result = js_create_plaindatetime(ctx, s->year, s->month, s->day,
+ pt->hour, pt->minute, pt->second,
+ pt->millisecond, pt->microsecond, pt->nanosecond);
+ JSPlainDateTimeData *res = JS_GetOpaque(result, js_plaindatetime_class_id);
+ if (res)
+ res->calendar = s->calendar;
+ JS_FreeValue(ctx, pt_val);
+ return result;
+ }
+}
+
+static JSValue plaindatetime_difference(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv,
+ int is_until)
+{
+ JSPlainDateTimeData *s = JS_GetOpaque2(ctx, this_val, js_plaindatetime_class_id);
+ JSValue other_val;
+ JSPlainDateTimeData *other;
+ JSDurationData diff = {0};
+ TIUnit largestUnit = TI_UNIT_INVALID;
+ TIUnit smallestUnit = TI_UNIT_INVALID;
+ int64_t roundingIncrement = 1;
+ TIRoundingMode roundingMode = ROUND_TRUNC;
+ int other_year, other_month, other_day;
+ int other_hour, other_minute, other_second;
+ int other_ms, other_us, other_ns;
+
+ if (!s)
+ return JS_EXCEPTION;
+ other_val = js_plaindatetime_from(ctx, JS_UNDEFINED, 1, argv);
+ if (JS_IsException(other_val))
+ return JS_EXCEPTION;
+ other = JS_GetOpaque(other_val, js_plaindatetime_class_id);
+ if (!other) {
+ JS_FreeValue(ctx, other_val);
+ return JS_ThrowTypeError(ctx, "invalid PlainDateTime");
+ }
+ if (s->calendar != other->calendar) {
+ JS_FreeValue(ctx, other_val);
+ return JS_ThrowRangeError(ctx, "calendars must be the same");
+ }
+
+ other_year = other->year;
+ other_month = other->month;
+ other_day = other->day;
+ other_hour = other->hour;
+ other_minute = other->minute;
+ other_second = other->second;
+ other_ms = other->millisecond;
+ other_us = other->microsecond;
+ other_ns = other->nanosecond;
+
+ if (argc >= 2 && ti_validate_options_object(ctx, argv[1]) < 0) {
+ JS_FreeValue(ctx, other_val);
+ return JS_EXCEPTION;
+ }
+
+ if (argc >= 2 && !JS_IsUndefined(argv[1])) {
+ if (ti_parse_unit_option(ctx, argv[1], "largestUnit", &largestUnit, TI_UNIT_OPT_ALLOW_UNDEFINED | TI_UNIT_OPT_ALLOW_AUTO, TI_UNIT_INVALID) < 0) {
+ JS_FreeValue(ctx, other_val);
+ return JS_EXCEPTION;
+ }
+
+ if (ti_get_rounding_increment_option(ctx, argv[1], &roundingIncrement) < 0) {
+ JS_FreeValue(ctx, other_val);
+ return JS_EXCEPTION;
+ }
+
+ if (ti_get_rounding_mode_option_default(ctx, argv[1], &roundingMode, ROUND_TRUNC) < 0) {
+ JS_FreeValue(ctx, other_val);
+ return JS_EXCEPTION;
+ }
+
+ TIUnit su = TI_UNIT_INVALID;
+ if (ti_parse_unit_option(ctx, argv[1], "smallestUnit", &su, TI_UNIT_OPT_ALLOW_UNDEFINED, TI_UNIT_INVALID) < 0) {
+ JS_FreeValue(ctx, other_val);
+ return JS_EXCEPTION;
+ }
+
+ if (su != TI_UNIT_INVALID) {
+ smallestUnit = su;
+ }
+ }
+
+ JS_FreeValue(ctx, other_val);
+
+ if (smallestUnit == TI_UNIT_INVALID)
+ smallestUnit = TI_UNIT_NANOSECOND;
+ if (largestUnit == TI_UNIT_INVALID || largestUnit == TI_UNIT_AUTO)
+ largestUnit = (smallestUnit < TI_UNIT_DAY) ? smallestUnit : TI_UNIT_DAY;
+
+ if (largestUnit > smallestUnit) {
+ return JS_ThrowRangeError(ctx, "largestUnit must be larger than smallestUnit");
+ }
+
+ {
+ int64_t maximum = 0;
+ switch (smallestUnit) {
+ case TI_UNIT_HOUR: maximum = 24; break;
+ case TI_UNIT_MINUTE: maximum = 60; break;
+ case TI_UNIT_SECOND: maximum = 60; break;
+ case TI_UNIT_MILLISECOND: maximum = 1000; break;
+ case TI_UNIT_MICROSECOND: maximum = 1000; break;
+ case TI_UNIT_NANOSECOND: maximum = 1000; break;
+ default: maximum = 0; break;
+ }
+ if (maximum > 0 && (roundingIncrement >= maximum || maximum % roundingIncrement != 0)) {
+ return JS_ThrowRangeError(ctx, "roundingIncrement does not divide evenly into the unit");
+ }
+ }
+
+ if (s->calendar != CAL_ISO8601 && s->calendar != CAL_GREGORY &&
+ s->calendar != CAL_BUDDHIST && s->calendar != CAL_ROC && s->calendar != CAL_JAPANESE &&
+ (largestUnit == TI_UNIT_YEAR || largestUnit == TI_UNIT_MONTH)) {
+ int s_cal_y, s_cal_m, s_cal_d;
+ int o_cal_y, o_cal_m, o_cal_d;
+ ti_iso_to_calendar_date(s->calendar, s->year, s->month, s->day, &s_cal_y, &s_cal_m, &s_cal_d);
+ ti_iso_to_calendar_date(s->calendar, other_year, other_month, other_day, &o_cal_y, &o_cal_m, &o_cal_d);
+ ti_calendar_datetime_difference(s->calendar,
+ s_cal_y, s_cal_m, s_cal_d, s->hour, s->minute, s->second, s->millisecond, s->microsecond, s->nanosecond,
+ o_cal_y, o_cal_m, o_cal_d, other_hour, other_minute, other_second, other_ms, other_us, other_ns,
+ largestUnit, &diff);
+ } else {
+ ti_iso_datetime_difference(s->year, s->month, s->day, s->hour, s->minute, s->second, s->millisecond, s->microsecond, s->nanosecond,
+ other_year, other_month, other_day, other_hour, other_minute, other_second, other_ms, other_us, other_ns,
+ largestUnit, &diff);
+ }
+ if (smallestUnit != TI_UNIT_NANOSECOND || roundingIncrement != 1) {
+ if (ti_round_relative_duration_iso(ctx,
+ s->year, s->month, s->day, s->hour, s->minute, s->second, s->millisecond, s->microsecond, s->nanosecond,
+ &diff, largestUnit, smallestUnit, roundingIncrement,
+ is_until ? roundingMode : ti_negate_rounding_mode(roundingMode), FALSE, &diff) < 0)
+ return JS_EXCEPTION;
+ }
+ ti_balance_time_duration(&diff, largestUnit);
+
+ if (!is_until) {
+ diff.years = -diff.years;
+ diff.months = -diff.months;
+ diff.weeks = -diff.weeks;
+ diff.days = -diff.days;
+ diff.hours = -diff.hours;
+ diff.minutes = -diff.minutes;
+ diff.seconds = -diff.seconds;
+ diff.milliseconds = -diff.milliseconds;
+ js_int128_t us = diff.microseconds.int128_value;
+ diff.microseconds.int128_value = -us;
+ js_int128_t ns = diff.nanoseconds.int128_value;
+ diff.nanoseconds.int128_value = -ns;
+ }
+
+ return js_create_duration(ctx, &diff);
+}
+
+
+
+static JSValue js_plaindatetime_toPlainDate(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ (void)argc;
+ (void)argv;
+ JSPlainDateTimeData *s = JS_GetOpaque2(ctx, this_val, js_plaindatetime_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ return js_create_plaindate(ctx, s->year, s->month, s->day);
+}
+
+static JSValue js_plaindatetime_toPlainTime(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ (void)argc;
+ (void)argv;
+ JSPlainDateTimeData *s = JS_GetOpaque2(ctx, this_val, js_plaindatetime_class_id);
+ JSPlainTimeData pt;
+ if (!s)
+ return JS_EXCEPTION;
+ pt.hour = s->hour;
+ pt.minute = s->minute;
+ pt.second = s->second;
+ pt.millisecond = s->millisecond;
+ pt.microsecond = s->microsecond;
+ pt.nanosecond = s->nanosecond;
+ return js_create_plaintime(ctx, &pt);
+}
+
+static int64_t pdt_unit_to_nanoseconds(TIUnit unit)
+{
+ switch (unit) {
+ case TI_UNIT_DAY: return 86400000000000LL;
+ case TI_UNIT_HOUR: return 3600000000000LL;
+ case TI_UNIT_MINUTE: return 60000000000LL;
+ case TI_UNIT_SECOND: return 1000000000LL;
+ case TI_UNIT_MILLISECOND: return 1000000LL;
+ case TI_UNIT_MICROSECOND: return 1000LL;
+ case TI_UNIT_NANOSECOND: return 1LL;
+ default: return 0;
+ }
+}
+
+static JSValue js_plaindatetime_round(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ (void)argc;
+ JSPlainDateTimeData *s = JS_GetOpaque2(ctx, this_val, js_plaindatetime_class_id);
+ JSValue options;
+ const char *smallestUnit = NULL;
+ TIRoundingMode mode = ROUND_HALF_EXPAND;
+ int64_t roundingIncrement = 1;
+ TIUnit unit = TI_UNIT_INVALID;
+ js_int128_t total_ns, rounded_ns, unit_ns, inc_ns;
+ int64_t days;
+ int64_t year;
+ int month, day, hour, minute, second, ms, us, ns;
+ if (!s)
+ return JS_EXCEPTION;
+ if (JS_IsUndefined(argv[0]))
+ return JS_ThrowTypeError(ctx, "roundTo is required");
+ if (!JS_IsString(argv[0]) && !JS_IsObject(argv[0]))
+ return JS_ThrowTypeError(ctx, "roundTo must be an object or string");
+ if (JS_IsString(argv[0])) {
+ size_t su_len;
+ smallestUnit = JS_ToCStringLen(ctx, &su_len, argv[0]);
+ if (!smallestUnit)
+ return JS_EXCEPTION;
+ unit = ti_string_to_unit(smallestUnit, su_len);
+ JS_FreeCString(ctx, smallestUnit);
+ if (unit == TI_UNIT_INVALID)
+ return JS_ThrowRangeError(ctx, "invalid smallestUnit");
+ options = JS_NewObjectProto(ctx, JS_NULL);
+ if (JS_IsException(options))
+ return JS_EXCEPTION;
+ } else {
+ options = JS_ToObject(ctx, argv[0]);
+ if (JS_IsException(options))
+ return JS_EXCEPTION;
+ }
+ if (ti_get_rounding_increment_option(ctx, options, &roundingIncrement) < 0) {
+ JS_FreeValue(ctx, options);
+ return JS_EXCEPTION;
+ }
+ if (ti_get_rounding_mode_option_default(ctx, options, &mode, ROUND_HALF_EXPAND) < 0) {
+ JS_FreeValue(ctx, options);
+ return JS_EXCEPTION;
+ }
+ /* Read smallestUnit last */
+ if (!JS_IsString(argv[0])) {
+ if (ti_parse_unit_option(ctx, options, "smallestUnit", &unit, TI_UNIT_OPT_ALLOW_UNDEFINED, TI_UNIT_INVALID) < 0) {
+ JS_FreeValue(ctx, options);
+ return JS_EXCEPTION;
+ }
+ }
+ if (unit == TI_UNIT_INVALID) {
+ JS_FreeValue(ctx, options);
+ return JS_ThrowRangeError(ctx, "smallestUnit is required");
+ }
+ /* PlainDateTime.round only supports day and time units */
+ if (unit < TI_UNIT_DAY || unit > TI_UNIT_NANOSECOND) {
+ JS_FreeValue(ctx, options);
+ return JS_ThrowRangeError(ctx, "invalid smallestUnit");
+ }
+ JS_FreeValue(ctx, options);
+ /* Validate roundingIncrement against per-unit maximum */
+ {
+ int64_t maximum;
+ int inclusive;
+ switch (unit) {
+ case TI_UNIT_DAY: maximum = 1; inclusive = 1; break;
+ case TI_UNIT_HOUR: maximum = 24; inclusive = 0; break;
+ case TI_UNIT_MINUTE: maximum = 60; inclusive = 0; break;
+ case TI_UNIT_SECOND: maximum = 60; inclusive = 0; break;
+ case TI_UNIT_MILLISECOND: maximum = 1000; inclusive = 0; break;
+ case TI_UNIT_MICROSECOND: maximum = 1000; inclusive = 0; break;
+ case TI_UNIT_NANOSECOND: maximum = 1000; inclusive = 0; break;
+ default: maximum = 0; inclusive = 0; break;
+ }
+ if ((inclusive ? roundingIncrement > maximum : roundingIncrement >= maximum) || maximum % roundingIncrement != 0) {
+ return JS_ThrowRangeError(ctx, "roundingIncrement does not divide evenly into the unit");
+ }
+ }
+ /* Compute total nanoseconds from date-time */
+ days = pdt_to_ordinal_days(s->year, s->month, s->day);
+ total_ns = (js_int128_t)days * 86400000000000LL +
+ (js_int128_t)s->hour * 3600000000000LL +
+ (js_int128_t)s->minute * 60000000000LL +
+ (js_int128_t)s->second * 1000000000LL +
+ (js_int128_t)s->millisecond * 1000000LL +
+ (js_int128_t)s->microsecond * 1000LL +
+ (js_int128_t)s->nanosecond;
+ unit_ns = pdt_unit_to_nanoseconds(unit);
+ if (unit_ns <= 0)
+ return JS_ThrowRangeError(ctx, "invalid unit");
+ inc_ns = unit_ns * roundingIncrement;
+ rounded_ns = ti_round_to_increment_as_if_positive128(total_ns, inc_ns, mode);
+ /* Convert back to date-time */
+ days = (int64_t)(rounded_ns / 86400000000000LL);
+ rounded_ns %= 86400000000000LL;
+ if (rounded_ns < 0) {
+ days--;
+ rounded_ns += 86400000000000LL;
+ }
+ ti_epoch_sec_to_date((days - 719162) * 86400LL, &year, &month, &day, NULL, NULL, NULL);
+ hour = (int)(rounded_ns / 3600000000000LL);
+ rounded_ns %= 3600000000000LL;
+ minute = (int)(rounded_ns / 60000000000LL);
+ rounded_ns %= 60000000000LL;
+ second = (int)(rounded_ns / 1000000000LL);
+ rounded_ns %= 1000000000LL;
+ ms = (int)(rounded_ns / 1000000LL);
+ rounded_ns %= 1000000LL;
+ us = (int)(rounded_ns / 1000LL);
+ ns = (int)(rounded_ns % 1000LL);
+ return js_create_plaindatetime(ctx, (int)year, month, day, hour, minute, second, ms, us, ns);
+}
+
+static JSValue js_plaindatetime_withCalendar(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ (void)argc;
+ JSPlainDateTimeData *s = JS_GetOpaque2(ctx, this_val, js_plaindatetime_class_id);
+ JSPlainDateTimeData *t;
+ JSValue obj;
+ CalendarType cal;
+ if (!s)
+ return JS_EXCEPTION;
+ if (ti_resolve_calendar_value(ctx, argv[0], &cal) < 0)
+ return JS_EXCEPTION;
+ t = js_mallocz(ctx, sizeof(*t));
+ if (!t)
+ return JS_EXCEPTION;
+ *t = *s;
+ t->calendar = cal;
+ obj = JS_NewObjectClass(ctx, (int)js_plaindatetime_class_id);
+ if (JS_IsException(obj)) {
+ js_free(ctx, t);
+ return JS_EXCEPTION;
+ }
+ JS_SetOpaque(obj, t);
+ return obj;
+}
+
+static JSValue js_plaindatetime_toZonedDateTime(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSPlainDateTimeData *s = JS_GetOpaque2(ctx, this_val, js_plaindatetime_class_id);
+ JSTimeSpec ts;
+ char tz_buf[64] = "UTC";
+ const char *timeZone = "UTC";
+ int64_t tz_offset_ns = 0;
+ int has_tz = 0;
+ int unsupported_tz = 0;
+ if (!s)
+ return JS_EXCEPTION;
+ if (JS_IsString(argv[0])) {
+ const char *str = JS_ToCString(ctx, argv[0]);
+ if (!str)
+ return JS_EXCEPTION;
+ {
+ int64_t offset_ns = 0;
+ int ret = ti_parse_temporal_timezone_string(str, &offset_ns);
+ if (ret < 0) {
+ JS_FreeCString(ctx, str);
+ return JS_ThrowRangeError(ctx, "invalid time zone");
+ }
+ if (ti_canonicalize_timezone_identifier(str, offset_ns, tz_buf, sizeof(tz_buf)) < 0) {
+ unsupported_tz = 1;
+ } else {
+ tz_offset_ns = offset_ns;
+ timeZone = tz_buf;
+ }
+ }
+ JS_FreeCString(ctx, str);
+ has_tz = 1;
+ } else if (JS_IsObject(argv[0])) {
+ JSValue v = JS_GetPropertyStr(ctx, argv[0], "timeZone");
+ if (JS_IsException(v)) {
+ JS_FreeValue(ctx, v);
+ return JS_EXCEPTION;
+ }
+ if (JS_IsUndefined(v)) {
+ JS_FreeValue(ctx, v);
+ return JS_ThrowTypeError(ctx, "unsupported time zone argument");
+ }
+ if (JS_IsString(v)) {
+ const char *str = JS_ToCString(ctx, v);
+ if (!str) {
+ JS_FreeValue(ctx, v);
+ return JS_EXCEPTION;
+ }
+ {
+ int64_t offset_ns = 0;
+ int ret = ti_parse_temporal_timezone_string(str, &offset_ns);
+ if (ret < 0) {
+ JS_FreeCString(ctx, str);
+ JS_FreeValue(ctx, v);
+ return JS_ThrowRangeError(ctx, "invalid time zone");
+ }
+ if (ti_canonicalize_timezone_identifier(str, offset_ns, tz_buf, sizeof(tz_buf)) < 0) {
+ unsupported_tz = 1;
+ } else {
+ tz_offset_ns = offset_ns;
+ timeZone = tz_buf;
+ }
+ }
+ JS_FreeCString(ctx, str);
+ has_tz = 1;
+ }
+ JS_FreeValue(ctx, v);
+ if (!has_tz)
+ return JS_ThrowTypeError(ctx, "unsupported time zone argument");
+ } else {
+ return JS_ThrowTypeError(ctx, "unsupported time zone argument");
+ }
+ {
+ int dis_idx = 2; /* default compatible */
+ if (argc >= 2 && ti_validate_options_object(ctx, argv[1]) < 0)
+ return JS_EXCEPTION;
+ if (argc >= 2 && JS_IsObject(argv[1])) {
+ static const char *dis_values[] = { "earlier", "later", "compatible", "reject" };
+ dis_idx = ti_get_string_option(ctx, argv[1], "disambiguation", dis_values, 4, 2);
+ if (dis_idx < 0)
+ return JS_EXCEPTION;
+ }
+ if (unsupported_tz)
+ return JS_ThrowRangeError(ctx, "unsupported time zone");
+ {
+ int64_t days = pdt_to_ordinal_days(s->year, s->month, s->day);
+ int64_t epoch_days = days - 719162;
+ int64_t epoch_sec = epoch_days * 86400LL;
+ epoch_sec += s->hour * 3600LL + s->minute * 60LL + s->second;
+ ts.secs = epoch_sec;
+ ts.nsecs = (uint32_t)(s->millisecond * 1000000 + s->microsecond * 1000 + s->nanosecond);
+ }
+ {
+ int tz_id = ti_tz_find_id(timeZone);
+ if (tz_id >= 0) {
+ int64_t utc_sec;
+ int offset_sec;
+ if (ti_tz_local_to_utc(tz_id, ts.secs, dis_idx, &utc_sec, &offset_sec) < 0)
+ return JS_ThrowRangeError(ctx, "multiple instants found");
+ ts.secs = utc_sec;
+ } else {
+ int64_t offset_sec = tz_offset_ns / 1000000000LL;
+ int offset_nsec = (int)(tz_offset_ns % 1000000000LL);
+ ts.secs -= offset_sec;
+ {
+ int64_t new_nsec = (int64_t)ts.nsecs - offset_nsec;
+ if (new_nsec < 0) {
+ new_nsec += 1000000000;
+ ts.secs -= 1;
+ } else if (new_nsec >= 1000000000) {
+ new_nsec -= 1000000000;
+ ts.secs += 1;
+ }
+ ts.nsecs = (uint32_t)new_nsec;
+ }
+ }
+ }
+ if (!is_valid_epoch_timespec(&ts))
+ return JS_ThrowRangeError(ctx, "epoch nanoseconds outside valid limits");
+ return js_create_zoneddatetime(ctx, &ts, timeZone, s->calendar);
+ }
+}
+
+/* Temporal.PlainDateTime.from */
+static JSValue js_plaindatetime_from(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ (void)this_val;
+ int year = 0, month = 0, day = 0, hour = 0, minute = 0, second = 0;
+ int millisecond = 0, microsecond = 0, nanosecond = 0;
+ JSValue val;
+ int overflow_constrain = 1; /* default is constrain */
+ val = argv[0];
+ if (JS_IsObject(val)) {
+ JSPlainDateTimeData *s = JS_GetOpaque(val, js_plaindatetime_class_id);
+ if (s) {
+ if (argc >= 2 && ti_validate_options_object(ctx, argv[1]) < 0)
+ return JS_EXCEPTION;
+ if (argc >= 2 && ti_get_overflow_option(ctx, argv[1], &overflow_constrain) < 0)
+ return JS_EXCEPTION;
+ return js_create_plaindatetime_with_calendar(ctx, s->year, s->month, s->day,
+ s->hour, s->minute, s->second,
+ s->millisecond, s->microsecond, s->nanosecond, s->calendar);
+ }
+ {
+ JSPlainDateData *pd = JS_GetOpaque(val, js_plaindate_class_id);
+ if (pd) {
+ if (argc >= 2 && ti_validate_options_object(ctx, argv[1]) < 0)
+ return JS_EXCEPTION;
+ if (argc >= 2 && ti_get_overflow_option(ctx, argv[1], &overflow_constrain) < 0)
+ return JS_EXCEPTION;
+ return js_create_plaindatetime_with_calendar(ctx, pd->year, pd->month, pd->day,
+ 0, 0, 0, 0, 0, 0, pd->calendar);
+ }
+ }
+ {
+ JSZonedDateTimeData *zdt = JS_GetOpaque(val, js_zoneddatetime_class_id);
+ if (zdt) {
+ int64_t epoch_sec = zdt->ts.secs;
+ int epoch_nsec = (int)zdt->ts.nsecs;
+ {
+ int64_t offset_ns = 0;
+ int ret = ti_parse_temporal_timezone_string(zdt->timeZone, &offset_ns);
+ if (ret == 0) {
+ int64_t offset_sec = offset_ns / 1000000000LL;
+ int offset_nsec = (int)(offset_ns % 1000000000LL);
+ epoch_sec += offset_sec;
+ epoch_nsec += offset_nsec;
+ if (epoch_nsec >= 1000000000) {
+ epoch_nsec -= 1000000000;
+ epoch_sec += 1;
+ } else if (epoch_nsec < 0) {
+ epoch_nsec += 1000000000;
+ epoch_sec -= 1;
+ }
+ }
+ }
+ {
+ int64_t y;
+ int mo, d, h, mi, se;
+ ti_epoch_sec_to_date(epoch_sec, &y, &mo, &d, &h, &mi, &se);
+ int ms = epoch_nsec / 1000000;
+ int us = (epoch_nsec % 1000000) / 1000;
+ int ns = epoch_nsec % 1000;
+ if (argc >= 2 && ti_validate_options_object(ctx, argv[1]) < 0)
+ return JS_EXCEPTION;
+ if (argc >= 2 && ti_get_overflow_option(ctx, argv[1], &overflow_constrain) < 0)
+ return JS_EXCEPTION;
+ return js_create_plaindatetime(ctx, (int)y, mo, d, h, mi, se, ms, us, ns);
+ }
+ }
+ }
+ {
+ TIPreparedFields fields;
+ uint32_t field_mask = TI_FIELD_YEAR | TI_FIELD_MONTH | TI_FIELD_MONTH_CODE |
+ TI_FIELD_DAY | TI_FIELD_HOUR | TI_FIELD_MINUTE |
+ TI_FIELD_SECOND | TI_FIELD_MILLISECOND | TI_FIELD_MICROSECOND |
+ TI_FIELD_NANOSECOND;
+ CalendarType cal = CAL_ISO8601;
+ if (ti_resolve_calendar_from_object(ctx, val, &cal) < 0)
+ return JS_EXCEPTION;
+ if (ti_prepare_calendar_fields(ctx, val, field_mask, 0, 0, &fields, cal) < 0)
+ return JS_EXCEPTION;
+ if (argc >= 2 && ti_validate_options_object(ctx, argv[1]) < 0)
+ return JS_EXCEPTION;
+ if (argc >= 2 && ti_get_overflow_option(ctx, argv[1], &overflow_constrain) < 0)
+ return JS_EXCEPTION;
+ return ti_create_plaindatetime_from_fields(ctx, &fields, overflow_constrain);
+ }
+ }
+ if (JS_IsString(val)) {
+ const char *str = JS_ToCString(ctx, val);
+ TISODateTimeParseResult r;
+ if (!str)
+ return JS_EXCEPTION;
+ if (ti_parse_iso_datetime_string(ctx, str, &r, TI_PARSE_DEFAULT) < 0) {
+ JS_FreeCString(ctx, str);
+ return JS_ThrowRangeError(ctx, "invalid PlainDateTime string");
+ }
+ JS_FreeCString(ctx, str);
+ if (!r.has_date)
+ return JS_ThrowRangeError(ctx, "invalid PlainDateTime string");
+ if (r.has_utc)
+ return JS_ThrowRangeError(ctx, "invalid PlainDateTime string");
+ if (r.has_tz_offset && !r.has_time)
+ return JS_ThrowRangeError(ctx, "invalid PlainDateTime string");
+ {
+ CalendarType cal = r.has_calendar ? r.calendar : CAL_ISO8601;
+ if (cal == CAL_UNKNOWN)
+ return JS_ThrowRangeError(ctx, "invalid calendar ID");
+ year = r.year;
+ month = r.month;
+ day = r.day;
+ hour = r.hour;
+ minute = r.minute;
+ second = r.second;
+ millisecond = r.millisecond;
+ microsecond = r.microsecond;
+ nanosecond = r.nanosecond;
+ if (!pdt_is_valid_date(year, month, day))
+ return JS_ThrowRangeError(ctx, "invalid PlainDateTime");
+ if (!pdt_is_valid_time(hour, minute, second, millisecond, microsecond, nanosecond))
+ return JS_ThrowRangeError(ctx, "invalid PlainDateTime");
+ /* Validate options AFTER string parsing */
+ if (argc >= 2 && ti_validate_options_object(ctx, argv[1]) < 0)
+ return JS_EXCEPTION;
+ if (argc >= 2 && ti_get_overflow_option(ctx, argv[1], &overflow_constrain) < 0)
+ return JS_EXCEPTION;
+ return js_create_plaindatetime_with_calendar(ctx, year, month, day, hour, minute, second,
+ millisecond, microsecond, nanosecond, cal);
+ }
+ }
+ return JS_ThrowTypeError(ctx, "unsupported argument type for Temporal.PlainDateTime.from");
+}
+
+static const JSCFunctionListEntry js_plaindatetime_proto_funcs[] = {
+ JS_CGETSET_MAGIC_DEF("year", js_plaindatetime_get_field, NULL, PLAINDATETIME_YEAR),
+ JS_CGETSET_MAGIC_DEF("month", js_plaindatetime_get_field, NULL, PLAINDATETIME_MONTH),
+ JS_CGETSET_DEF("monthCode", js_plaindatetime_get_monthCode, NULL),
+ JS_CGETSET_MAGIC_DEF("day", js_plaindatetime_get_field, NULL, PLAINDATETIME_DAY),
+ JS_CGETSET_MAGIC_DEF("hour", js_plaindatetime_get_field, NULL, PLAINDATETIME_HOUR),
+ JS_CGETSET_MAGIC_DEF("minute", js_plaindatetime_get_field, NULL, PLAINDATETIME_MINUTE),
+ JS_CGETSET_MAGIC_DEF("second", js_plaindatetime_get_field, NULL, PLAINDATETIME_SECOND),
+ JS_CGETSET_MAGIC_DEF("millisecond", js_plaindatetime_get_field, NULL, PLAINDATETIME_MILLISECOND),
+ JS_CGETSET_MAGIC_DEF("microsecond", js_plaindatetime_get_field, NULL, PLAINDATETIME_MICROSECOND),
+ JS_CGETSET_MAGIC_DEF("nanosecond", js_plaindatetime_get_field, NULL, PLAINDATETIME_NANOSECOND),
+ JS_CGETSET_DEF("calendarId", js_plaindatetime_get_calendarId, NULL),
+ JS_CGETSET_DEF("era", js_plaindatetime_get_era, NULL),
+ JS_CGETSET_DEF("eraYear", js_plaindatetime_get_eraYear, NULL),
+ JS_CGETSET_DEF("inLeapYear", js_plaindatetime_get_inLeapYear, NULL),
+ JS_CGETSET_DEF("daysInMonth", js_plaindatetime_get_daysInMonth, NULL),
+ JS_CGETSET_DEF("daysInYear", js_plaindatetime_get_daysInYear, NULL),
+ JS_CGETSET_DEF("daysInWeek", js_plaindatetime_get_daysInWeek, NULL),
+ JS_CGETSET_DEF("monthsInYear", js_plaindatetime_get_monthsInYear, NULL),
+ JS_CGETSET_DEF("dayOfYear", js_plaindatetime_get_dayOfYear, NULL),
+ JS_CGETSET_DEF("dayOfWeek", js_plaindatetime_get_dayOfWeek, NULL),
+ JS_CGETSET_DEF("weekOfYear", js_plaindatetime_get_weekOfYear, NULL),
+ JS_CGETSET_DEF("yearOfWeek", js_plaindatetime_get_yearOfWeek, NULL),
+ JS_CFUNC_DEF("equals", 1, js_plaindatetime_equals),
+ JS_CFUNC_DEF("toString", 0, js_plaindatetime_toString),
+ JS_CFUNC_DEF("toJSON", 0, js_plaindatetime_toJSON),
+ JS_CFUNC_DEF("toLocaleString", 0, js_plaindatetime_toLocaleString),
+ JS_CFUNC_MAGIC_DEF("add", 1, js_plaindatetime_add_subtract, 1),
+ JS_CFUNC_MAGIC_DEF("subtract", 1, js_plaindatetime_add_subtract, 0),
+ JS_CFUNC_MAGIC_DEF("until", 1, plaindatetime_difference, 1),
+ JS_CFUNC_MAGIC_DEF("since", 1, plaindatetime_difference, 0),
+ JS_CFUNC_DEF("round", 1, js_plaindatetime_round),
+ JS_CFUNC_DEF("toPlainDate", 0, js_plaindatetime_toPlainDate),
+ JS_CFUNC_DEF("toPlainTime", 0, js_plaindatetime_toPlainTime),
+ JS_CFUNC_DEF("toZonedDateTime", 1, js_plaindatetime_toZonedDateTime),
+ JS_CFUNC_DEF("with", 1, js_plaindatetime_with),
+ JS_CFUNC_DEF("withCalendar", 1, js_plaindatetime_withCalendar),
+ JS_CFUNC_DEF("withPlainTime", 0, js_plaindatetime_withPlainTime),
+ JS_CFUNC_DEF("valueOf", 0, js_plaindatetime_valueOf),
+ JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Temporal.PlainDateTime", JS_PROP_CONFIGURABLE),
+};
+
+static const JSCFunctionListEntry js_plaindatetime_static_funcs[] = {
+ JS_CFUNC_DEF("from", 1, js_plaindatetime_from),
+ JS_CFUNC_DEF("compare", 2, js_plaindatetime_compare),
+};
+
+int js_add_plaindatetime(JSContext *ctx, JSValue temporal_obj)
+{
+ JSValue ctor;
+
+ JS_NewClassID(&js_plaindatetime_class_id);
+ JS_NewClass(JS_GetRuntime(ctx), js_plaindatetime_class_id, &js_plaindatetime_class);
+
+ ctor = JS_NewCConstructor(ctx, (int)js_plaindatetime_class_id, "PlainDateTime",
+ (JSCFunction *)js_plaindatetime_constructor, 3,
+ JS_CFUNC_constructor, 0,
+ JS_UNDEFINED,
+ js_plaindatetime_static_funcs, countof(js_plaindatetime_static_funcs),
+ js_plaindatetime_proto_funcs, countof(js_plaindatetime_proto_funcs),
+ JS_NEW_CTOR_NO_GLOBAL);
+ if (JS_IsException(ctor))
+ return -1;
+ if (JS_DefinePropertyValueStr(ctx, temporal_obj, "PlainDateTime", ctor,
+ JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE) < 0)
+ return -1;
+ return 0;
+}
--- /dev/null
+/*
+ * QuickJS Temporal.PlainMonthDay implementation (minimal)
+ */
+
+#include <string.h>
+#include <math.h>
+
+#include "../quickjs.h"
+#include "../cutils.h"
+#include "temporal_private.h"
+
+JSClassID js_plainmonthday_class_id;
+
+
+static void js_plainmonthday_finalizer(JSRuntime *rt, JSValue val)
+{
+ JSPlainMonthDayData *s = JS_GetOpaque(val, js_plainmonthday_class_id);
+ if (s)
+ js_free_rt(rt, s);
+}
+
+static const JSClassDef js_plainmonthday_class = {
+ "Temporal.PlainMonthDay",
+ .finalizer = js_plainmonthday_finalizer,
+};
+
+JSValue js_create_plainmonthday_with_calendar(JSContext *ctx, int iso_year, int iso_month, int iso_day, CalendarType calendar)
+{
+ JSPlainMonthDayData *s;
+ JSValue obj;
+ /* Validate ISO year range (ISO date limits: -271821 to 275760) */
+ if (iso_year < -271821 || iso_year > 275760)
+ return JS_ThrowRangeError(ctx, "PlainMonthDay out of range");
+ s = js_mallocz(ctx, sizeof(*s));
+ if (!s)
+ return JS_EXCEPTION;
+ s->iso_year = iso_year;
+ s->iso_month = iso_month;
+ s->iso_day = iso_day;
+ s->calendar = calendar;
+ obj = JS_NewObjectClass(ctx, (int)js_plainmonthday_class_id);
+ if (JS_IsException(obj)) {
+ js_free(ctx, s);
+ return JS_EXCEPTION;
+ }
+ JS_SetOpaque(obj, s);
+ return obj;
+}
+
+static int pmd_to_integer_with_truncation(JSContext *ctx, JSValueConst val, int *pres)
+{
+ double d;
+ if (JS_IsUndefined(val)) {
+ *pres = 0;
+ return 0;
+ }
+ if (JS_ToFloat64(ctx, &d, val))
+ return -1;
+ if (!isfinite(d)) {
+ JS_ThrowRangeError(ctx, "value must be an integer");
+ return -1;
+ }
+ if (d < INT32_MIN || d > INT32_MAX) {
+ JS_ThrowRangeError(ctx, "value out of range");
+ return -1;
+ }
+ *pres = (int)(d < 0 ? ceil(d) : floor(d));
+ return 0;
+}
+
+/* Temporal.PlainMonthDay constructor */
+static JSValue js_plainmonthday_constructor(JSContext *ctx, JSValueConst new_target,
+ int argc, JSValueConst *argv)
+{
+ int month, day, year = 1972;
+ if (JS_IsUndefined(new_target)) {
+ return JS_ThrowTypeError(ctx, "Temporal.PlainMonthDay constructor cannot be called as a function");
+ }
+ if (pmd_to_integer_with_truncation(ctx, argv[0], &month) < 0)
+ return JS_EXCEPTION;
+ if (pmd_to_integer_with_truncation(ctx, argv[1], &day) < 0)
+ return JS_EXCEPTION;
+ {
+ CalendarType calendar = CAL_ISO8601;
+ if (argc > 2) {
+ int cal_res = ti_validate_constructor_calendar(ctx, argv[2], &calendar);
+ if (cal_res < 0)
+ return JS_EXCEPTION;
+ }
+ if (argc > 3 && !JS_IsUndefined(argv[3])) {
+ if (pmd_to_integer_with_truncation(ctx, argv[3], &year) < 0)
+ return JS_EXCEPTION;
+ if (ti_is_minus_zero(argv[3]))
+ return JS_ThrowRangeError(ctx, "minus zero year is not allowed");
+ }
+ if (month < 1 || month > 12 || day < 1 || day > pd_days_in_month(year, month))
+ return JS_ThrowRangeError(ctx, "invalid PlainMonthDay");
+ /* ISODateWithinLimits check for CreateTemporalMonthDay */
+ if (year < -271821 || (year == -271821 && (month < 4 || (month == 4 && day < 19))))
+ return JS_ThrowRangeError(ctx, "date outside supported range");
+ if (year > 275760 || (year == 275760 && (month > 9 || (month == 9 && day > 13))))
+ return JS_ThrowRangeError(ctx, "date outside supported range");
+ {
+ JSPlainMonthDayData *s = js_mallocz(ctx, sizeof(*s));
+ JSValue obj;
+ if (!s)
+ return JS_EXCEPTION;
+ s->iso_year = year;
+ s->iso_month = month;
+ s->iso_day = day;
+ s->calendar = calendar;
+ obj = js_create_temporal_object(ctx, new_target, js_plainmonthday_class_id, s);
+ if (JS_IsException(obj)) {
+ js_free(ctx, s);
+ return JS_EXCEPTION;
+ }
+ return obj;
+ }
+ }
+}
+
+/* Getters */
+static JSValue js_plainmonthday_get_monthCode(JSContext *ctx, JSValueConst this_val)
+{
+ JSPlainMonthDayData *s = JS_GetOpaque2(ctx, this_val, js_plainmonthday_class_id);
+ int cal_y, cal_m, cal_d;
+ if (!s)
+ return JS_EXCEPTION;
+ pmd_get_calendar_date(s, &cal_y, &cal_m, &cal_d);
+ return ti_get_month_code(ctx, s->calendar, cal_y, cal_m);
+}
+
+static JSValue js_plainmonthday_get_day(JSContext *ctx, JSValueConst this_val)
+{
+ JSPlainMonthDayData *s = JS_GetOpaque2(ctx, this_val, js_plainmonthday_class_id);
+ int cal_y, cal_m, cal_d;
+ if (!s)
+ return JS_EXCEPTION;
+ pmd_get_calendar_date(s, &cal_y, &cal_m, &cal_d);
+ return JS_NewInt32(ctx, cal_d);
+}
+
+static JSValue js_plainmonthday_get_referenceISOYear(JSContext *ctx, JSValueConst this_val)
+{
+ JSPlainMonthDayData *s = JS_GetOpaque2(ctx, this_val, js_plainmonthday_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ return JS_NewInt32(ctx, s->iso_year);
+}
+
+static JSValue js_plainmonthday_get_calendarId(JSContext *ctx, JSValueConst this_val)
+{
+ JSPlainMonthDayData *s = JS_GetOpaque2(ctx, this_val, js_plainmonthday_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ return JS_NewString(ctx, ti_calendar_enum_to_string(s->calendar));
+}
+
+static int pmd_day_of_week(int year, int month, int day)
+{
+ int a = (14 - month) / 12;
+ int y = year - a;
+ int m = month + 12 * a - 2;
+ int d = (day + y + y / 4 - y / 100 + y / 400 + (31 * m) / 12) % 7;
+ return (d == 0) ? 7 : d;
+}
+
+static void pmd_iso_week(int year, int month, int day, int *weekYear, int *weekNumber)
+{
+ int dow = pmd_day_of_week(year, month, day);
+ int ordinal = pd_day_of_year(year, month, day);
+ int thursdayOrdinal = ordinal + (4 - dow);
+ int y = year;
+ int daysInY = pd_is_leap_year(y) ? 366 : 365;
+ if (thursdayOrdinal <= 0) {
+ y = year - 1;
+ daysInY = pd_is_leap_year(y) ? 366 : 365;
+ thursdayOrdinal += daysInY;
+ } else if (thursdayOrdinal > daysInY) {
+ thursdayOrdinal -= daysInY;
+ y = year + 1;
+ }
+ *weekYear = y;
+ *weekNumber = (thursdayOrdinal - 1) / 7 + 1;
+}
+
+static JSValue js_plainmonthday_get_era(JSContext *ctx, JSValueConst this_val)
+{
+ JSPlainMonthDayData *s = JS_GetOpaque2(ctx, this_val, js_plainmonthday_class_id);
+ int cal_y, cal_m, cal_d;
+ TIEra era;
+ int dummy_era_year;
+ if (!s)
+ return JS_EXCEPTION;
+ if (s->calendar == CAL_ISO8601)
+ return JS_UNDEFINED;
+ pmd_get_calendar_date(s, &cal_y, &cal_m, &cal_d);
+ ti_calendar_era_and_era_year(s->calendar, s->iso_year, s->iso_month, s->iso_day,
+ cal_y, &era, &dummy_era_year);
+ if (era != TI_ERA_UNKNOWN)
+ return JS_NewString(ctx, ti_era_to_string(era));
+ return JS_UNDEFINED;
+}
+
+static JSValue js_plainmonthday_get_eraYear(JSContext *ctx, JSValueConst this_val)
+{
+ JSPlainMonthDayData *s = JS_GetOpaque2(ctx, this_val, js_plainmonthday_class_id);
+ int cal_y, cal_m, cal_d;
+ TIEra era;
+ int era_year;
+ if (!s)
+ return JS_EXCEPTION;
+ if (s->calendar == CAL_ISO8601)
+ return JS_UNDEFINED;
+ pmd_get_calendar_date(s, &cal_y, &cal_m, &cal_d);
+ ti_calendar_era_and_era_year(s->calendar, s->iso_year, s->iso_month, s->iso_day,
+ cal_y, &era, &era_year);
+ if (era != TI_ERA_UNKNOWN)
+ return JS_NewInt32(ctx, era_year);
+ return JS_UNDEFINED;
+}
+
+static JSValue js_plainmonthday_get_inLeapYear(JSContext *ctx, JSValueConst this_val)
+{
+ JSPlainMonthDayData *s = JS_GetOpaque2(ctx, this_val, js_plainmonthday_class_id);
+ int cal_y, cal_m, cal_d;
+ if (!s)
+ return JS_EXCEPTION;
+ pmd_get_calendar_date(s, &cal_y, &cal_m, &cal_d);
+ return JS_NewBool(ctx, ti_calendar_is_leap_year(s->calendar, cal_y));
+}
+
+static JSValue js_plainmonthday_get_daysInMonth(JSContext *ctx, JSValueConst this_val)
+{
+ JSPlainMonthDayData *s = JS_GetOpaque2(ctx, this_val, js_plainmonthday_class_id);
+ int cal_y, cal_m, cal_d;
+ if (!s)
+ return JS_EXCEPTION;
+ pmd_get_calendar_date(s, &cal_y, &cal_m, &cal_d);
+ return JS_NewInt32(ctx, ti_calendar_days_in_month(s->calendar, cal_y, cal_m));
+}
+
+static JSValue js_plainmonthday_get_daysInYear(JSContext *ctx, JSValueConst this_val)
+{
+ JSPlainMonthDayData *s = JS_GetOpaque2(ctx, this_val, js_plainmonthday_class_id);
+ int cal_y, cal_m, cal_d;
+ if (!s)
+ return JS_EXCEPTION;
+ pmd_get_calendar_date(s, &cal_y, &cal_m, &cal_d);
+ return JS_NewInt32(ctx, ti_calendar_days_in_year(s->calendar, cal_y));
+}
+
+static JSValue js_plainmonthday_get_daysInWeek(JSContext *ctx, JSValueConst this_val)
+{
+ JSPlainMonthDayData *s = JS_GetOpaque2(ctx, this_val, js_plainmonthday_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ return JS_NewInt32(ctx, 7);
+}
+
+static JSValue js_plainmonthday_get_monthsInYear(JSContext *ctx, JSValueConst this_val)
+{
+ JSPlainMonthDayData *s = JS_GetOpaque2(ctx, this_val, js_plainmonthday_class_id);
+ int cal_y, cal_m, cal_d;
+ if (!s)
+ return JS_EXCEPTION;
+ pmd_get_calendar_date(s, &cal_y, &cal_m, &cal_d);
+ return JS_NewInt32(ctx, ti_calendar_months_in_year(s->calendar, cal_y));
+}
+
+static JSValue js_plainmonthday_get_dayOfYear(JSContext *ctx, JSValueConst this_val)
+{
+ JSPlainMonthDayData *s = JS_GetOpaque2(ctx, this_val, js_plainmonthday_class_id);
+ int cal_y, cal_m, cal_d;
+ if (!s)
+ return JS_EXCEPTION;
+ pmd_get_calendar_date(s, &cal_y, &cal_m, &cal_d);
+ return JS_NewInt32(ctx, ti_calendar_day_of_year(s->calendar, cal_y, cal_m, cal_d));
+}
+
+static JSValue js_plainmonthday_get_dayOfWeek(JSContext *ctx, JSValueConst this_val)
+{
+ JSPlainMonthDayData *s = JS_GetOpaque2(ctx, this_val, js_plainmonthday_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ return JS_NewInt32(ctx, pmd_day_of_week(s->iso_year, s->iso_month, s->iso_day));
+}
+
+static JSValue js_plainmonthday_get_weekOfYear(JSContext *ctx, JSValueConst this_val)
+{
+ JSPlainMonthDayData *s = JS_GetOpaque2(ctx, this_val, js_plainmonthday_class_id);
+ int weekYear, weekNumber;
+ if (!s)
+ return JS_EXCEPTION;
+ pmd_iso_week(s->iso_year, s->iso_month, s->iso_day, &weekYear, &weekNumber);
+ return JS_NewInt32(ctx, weekNumber);
+}
+
+static JSValue js_plainmonthday_get_yearOfWeek(JSContext *ctx, JSValueConst this_val)
+{
+ JSPlainMonthDayData *s = JS_GetOpaque2(ctx, this_val, js_plainmonthday_class_id);
+ int weekYear, weekNumber;
+ if (!s)
+ return JS_EXCEPTION;
+ pmd_iso_week(s->iso_year, s->iso_month, s->iso_day, &weekYear, &weekNumber);
+ return JS_NewInt64(ctx, weekYear);
+}
+
+static JSValue js_plainmonthday_from(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv);
+
+/* Temporal.PlainMonthDay.prototype.equals */
+static JSValue js_plainmonthday_equals(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ (void)this_val;
+ (void)argc;
+ JSPlainMonthDayData *s, *other;
+ JSValue other_val;
+ s = JS_GetOpaque2(ctx, this_val, js_plainmonthday_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ other_val = js_plainmonthday_from(ctx, JS_UNDEFINED, 1, &argv[0]);
+ if (JS_IsException(other_val))
+ return JS_EXCEPTION;
+ other = JS_GetOpaque(other_val, js_plainmonthday_class_id);
+ if (!other) {
+ JS_FreeValue(ctx, other_val);
+ return JS_NewBool(ctx, 0);
+ }
+ {
+ int res = s->iso_year == other->iso_year && s->iso_month == other->iso_month &&
+ s->iso_day == other->iso_day &&
+ s->calendar == other->calendar;
+ JS_FreeValue(ctx, other_val);
+ return JS_NewBool(ctx, res);
+ }
+}
+
+/* Temporal.PlainMonthDay.prototype.with */
+static JSValue js_plainmonthday_with(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSPlainMonthDayData *s;
+ int month, day;
+ int year_for_overflow = 0;
+ int has_year = 0;
+ JSValue val;
+ int has_month_code = 0;
+ int month_code_val = 0;
+ int has_month_code_l = 0;
+ int has_month_prop = 0;
+ int month_prop_val = 0;
+ TIPreparedFields fields;
+ int orig_cal_y, orig_cal_m, orig_cal_d;
+ int iso_y, iso_m, iso_d;
+ s = JS_GetOpaque2(ctx, this_val, js_plainmonthday_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ pmd_get_calendar_date(s, &orig_cal_y, &orig_cal_m, &orig_cal_d);
+ month = orig_cal_m;
+ day = orig_cal_d;
+ val = argv[0];
+ if (ti_is_partial_temporal_object(ctx, val) < 0)
+ return JS_EXCEPTION;
+ if (ti_prepare_calendar_fields(ctx, val,
+ TI_FIELD_DAY | TI_FIELD_MONTH | TI_FIELD_MONTH_CODE |
+ TI_FIELD_YEAR,
+ 0, 1, &fields, CAL_ISO8601) < 0)
+ return JS_EXCEPTION;
+ /* Merge fields with existing object */
+ if (fields.present_mask & TI_FIELD_DAY) {
+ day = fields.day;
+ }
+ if (fields.present_mask & TI_FIELD_MONTH) {
+ has_month_prop = 1;
+ month_prop_val = fields.month;
+ month = fields.month;
+ }
+ if (fields.present_mask & TI_FIELD_MONTH_CODE) {
+ has_month_code = 1;
+ month_code_val = fields.month_from_code;
+ has_month_code_l = fields.month_code_has_l;
+ }
+ if (fields.present_mask & TI_FIELD_YEAR) {
+ has_year = 1;
+ year_for_overflow = (int)fields.year;
+ }
+ /* Validate options type */
+ if (argc >= 2 && ti_validate_options_object(ctx, argv[1]) < 0)
+ return JS_EXCEPTION;
+ {
+ int overflow_constrain = 1;
+ if (argc >= 2 && !JS_IsUndefined(argv[1])) {
+ if (ti_get_overflow_option(ctx, argv[1], &overflow_constrain) < 0)
+ return JS_EXCEPTION;
+ }
+ if (s->calendar != CAL_ISO8601 && has_month_prop && !has_month_code)
+ return JS_ThrowTypeError(ctx, "monthCode is required");
+ if (has_month_code) {
+ if (!ti_calendar_validate_month_code(s->calendar, month_code_val, has_month_code_l))
+ return JS_ThrowRangeError(ctx, "monthCode is not valid for this calendar");
+ month = month_code_val;
+ } else if (has_month_prop) {
+ month = month_prop_val;
+ }
+ if (has_month_code && has_month_prop && month_code_val != month_prop_val &&
+ ti_calendar_enforces_month_monthcode_agreement(s->calendar))
+ return JS_ThrowRangeError(ctx, "month and monthCode must agree");
+ {
+ int ref_year = has_year ? year_for_overflow : orig_cal_y;
+ int dim = ti_calendar_days_in_month(s->calendar, ref_year, month);
+ if (day > dim || day < 1) {
+ if (!overflow_constrain)
+ return JS_ThrowRangeError(ctx, "invalid PlainMonthDay");
+ if (day > dim)
+ day = dim;
+ else if (day < 1)
+ day = 1;
+ }
+ }
+ if (ti_calendar_monthday_iso_reference_date(s->calendar, month,
+ has_month_code ? has_month_code_l : 0,
+ day, overflow_constrain, 0,
+ &iso_y, &iso_m, &iso_d) < 0)
+ return JS_ThrowRangeError(ctx, "invalid PlainMonthDay");
+ return js_create_plainmonthday_with_calendar(ctx, iso_y, iso_m, iso_d, s->calendar);
+ }
+}
+
+/* Format PlainMonthDay as ISO string */
+static JSValue js_plainmonthday_toString(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSPlainMonthDayData *s;
+ char buf[64];
+ int calendar_name = 0; /* 0 = auto/never, 1 = always, 2 = critical */
+ if (argc >= 1 && ti_validate_options_object(ctx, argv[0]) < 0)
+ return JS_EXCEPTION;
+ if (argc >= 1 && !JS_IsUndefined(argv[0])) {
+ if (ti_get_calendar_name_option(ctx, argv[0], &calendar_name) < 0)
+ return JS_EXCEPTION;
+ }
+ s = JS_GetOpaque2(ctx, this_val, js_plainmonthday_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ if (calendar_name == 1 || calendar_name == 2 || (calendar_name == 0 && s->calendar != CAL_ISO8601) || (calendar_name == 3 && s->calendar != CAL_ISO8601)) {
+ if (s->iso_year < 0)
+ snprintf(buf, sizeof(buf), "-%06d-%02d-%02d", -s->iso_year, s->iso_month, s->iso_day);
+ else if (s->iso_year >= 10000)
+ snprintf(buf, sizeof(buf), "+%06d-%02d-%02d", s->iso_year, s->iso_month, s->iso_day);
+ else
+ snprintf(buf, sizeof(buf), "%04d-%02d-%02d", s->iso_year, s->iso_month, s->iso_day);
+ } else {
+ snprintf(buf, sizeof(buf), "%02d-%02d", s->iso_month, s->iso_day);
+ }
+ ti_append_calendar_annotation(buf, sizeof(buf), s->calendar, calendar_name);
+ return JS_NewString(ctx, buf);
+}
+
+static JSValue js_plainmonthday_toJSON(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ (void)argc;
+ (void)argv;
+ return js_plainmonthday_toString(ctx, this_val, 0, NULL);
+}
+
+static JSValue js_plainmonthday_toLocaleString(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSPlainMonthDayData *s = JS_GetOpaque2(ctx, this_val, js_plainmonthday_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ return ti_temporal_toLocaleString(ctx, this_val, argc, argv, 1, js_plainmonthday_toString);
+}
+
+static JSValue js_plainmonthday_valueOf(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ (void)argc;
+ (void)argv;
+ (void)this_val;
+ return JS_ThrowTypeError(ctx, "cannot compare Temporal.PlainMonthDay with < or >");
+}
+
+/* Temporal.PlainMonthDay.from */
+static JSValue js_plainmonthday_from(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ (void)this_val;
+ int overflow_constrain = 1;
+ int ref_year = 1972;
+ int month = 0;
+ int day = 0;
+ int has_year = 0;
+ JSValue val;
+ CalendarType calendar = CAL_ISO8601;
+ int month_code_has_l = 0;
+ int parsed_month = 0;
+ int has_month_code = 0;
+ val = argv[0];
+ if (JS_IsObject(val)) {
+ JSPlainMonthDayData *s = JS_GetOpaque(val, js_plainmonthday_class_id);
+ if (s) {
+ if (argc >= 2 && ti_validate_options_object(ctx, argv[1]) < 0)
+ return JS_EXCEPTION;
+ if (argc >= 2 && ti_get_overflow_option(ctx, argv[1], &overflow_constrain) < 0)
+ return JS_EXCEPTION;
+ return js_create_plainmonthday_with_calendar(ctx, s->iso_year, s->iso_month, s->iso_day, s->calendar);
+ }
+ {
+ TIPreparedFields fields;
+ int has_month = 0;
+ int has_numeric_month = 0;
+ int has_day = 0;
+ int has_any = 0;
+ JSValue cal_v = JS_GetPropertyStr(ctx, val, "calendar");
+ if (JS_IsException(cal_v))
+ return JS_EXCEPTION;
+ if (!JS_IsUndefined(cal_v)) {
+ has_any = 1;
+ if (ti_resolve_calendar_value(ctx, cal_v, &calendar) < 0) {
+ JS_FreeValue(ctx, cal_v);
+ return JS_EXCEPTION;
+ }
+ }
+ JS_FreeValue(ctx, cal_v);
+ if (ti_prepare_calendar_fields(ctx, val,
+ TI_FIELD_DAY | TI_FIELD_MONTH | TI_FIELD_MONTH_CODE |
+ TI_FIELD_YEAR,
+ 0, 0, &fields, calendar) < 0)
+ return JS_EXCEPTION;
+ if (fields.present_mask)
+ has_any = 1;
+ /* Extract fields from prepared structure */
+ if (fields.present_mask & TI_FIELD_DAY) {
+ has_day = 1;
+ day = fields.day;
+ }
+ if (fields.present_mask & TI_FIELD_MONTH) {
+ has_month = 1;
+ has_numeric_month = 1;
+ month = fields.month;
+ }
+ if (fields.present_mask & TI_FIELD_MONTH_CODE) {
+ has_month = 1;
+ has_month_code = 1;
+ parsed_month = fields.month_from_code;
+ month_code_has_l = fields.month_code_has_l;
+ }
+ if (fields.present_mask & TI_FIELD_YEAR) {
+ has_year = 1;
+ ref_year = (int)fields.year;
+ }
+ /* era/eraYear processing */
+ if (ti_calendar_requires_era(calendar) &&
+ (fields.present_mask & (TI_FIELD_ERA | TI_FIELD_ERA_YEAR))) {
+ if (!(fields.present_mask & TI_FIELD_ERA) || !(fields.present_mask & TI_FIELD_ERA_YEAR))
+ return JS_ThrowTypeError(ctx, "era and eraYear must both be present");
+ {
+ int iso_year;
+ if (fields.era == TI_ERA_UNKNOWN || ti_calendar_era_to_iso_year(calendar, fields.era, (int)fields.era_year, &iso_year) < 0)
+ return JS_ThrowRangeError(ctx, "invalid era");
+ if (has_year && ref_year != iso_year)
+ return JS_ThrowRangeError(ctx, "year and era/eraYear must agree");
+ ref_year = iso_year;
+ has_year = 1;
+ }
+ }
+ if (!has_any)
+ return JS_ThrowTypeError(ctx, "plain object is not a valid property bag and does not convert to a string");
+ /* Validate options AFTER reading fields */
+ if (argc >= 2 && ti_validate_options_object(ctx, argv[1]) < 0)
+ return JS_EXCEPTION;
+ if (argc >= 2 && ti_get_overflow_option(ctx, argv[1], &overflow_constrain) < 0)
+ return JS_EXCEPTION;
+ /* Missing property check before algorithmic validation */
+ if (!has_month || !has_day)
+ return JS_ThrowTypeError(ctx, "invalid PlainMonthDay");
+ /* Non-ISO calendars require monthCode or year */
+ if (calendar != CAL_ISO8601 && !has_month_code && !has_year) {
+ return JS_ThrowTypeError(ctx, "invalid PlainMonthDay");
+ }
+ /* Non-ISO calendars require year when numeric month is present */
+ if (calendar != CAL_ISO8601 && has_numeric_month && !has_year) {
+ return JS_ThrowTypeError(ctx, "invalid PlainMonthDay");
+ }
+ /* Validate monthCode */
+ if (fields.present_mask & TI_FIELD_MONTH_CODE) {
+ if (!ti_calendar_validate_month_code(calendar, parsed_month, fields.month_code_has_l))
+ return JS_ThrowRangeError(ctx, "invalid PlainMonthDay");
+ month = parsed_month;
+ }
+ /* Check month/monthCode agreement */
+ if (has_numeric_month && (fields.present_mask & TI_FIELD_MONTH_CODE)) {
+ int resolved = ti_calendar_month_code_to_month(calendar, ref_year, parsed_month, fields.month_code_has_l);
+ if (resolved >= 0 && fields.month != resolved)
+ return JS_ThrowRangeError(ctx, "month and monthCode must agree");
+ }
+ /* Bail out early if year is out of supported range for non-ISO calendars */
+ if (has_year && calendar != CAL_ISO8601) {
+ if (ref_year < -271821 || ref_year > 275760)
+ return JS_ThrowRangeError(ctx, "invalid PlainMonthDay");
+ }
+ /* When only numeric month is provided, convert to monthCode */
+ if (has_month && !has_month_code && calendar != CAL_ISO8601 && calendar != CAL_GREGORY) {
+ int user_year = has_year ? ref_year : 1972;
+ int computed_mc, computed_has_l;
+ int max_m = ti_calendar_months_in_year(calendar, user_year);
+ if (month < 1 || month > max_m) {
+ if (!overflow_constrain)
+ return JS_ThrowRangeError(ctx, "invalid PlainMonthDay");
+ if (month < 1) month = 1;
+ else month = max_m;
+ }
+ ti_calendar_month_to_month_code(calendar, user_year, month, &computed_mc, &computed_has_l);
+ month = computed_mc;
+ month_code_has_l = computed_has_l;
+ has_month_code = 1;
+ }
+ }
+ if (month < 1)
+ return JS_ThrowRangeError(ctx, "invalid PlainMonthDay");
+ {
+ int iso_y, iso_m, iso_d;
+ {
+ int overflow_year = has_year ? ref_year : 0;
+ if (ti_calendar_monthday_iso_reference_date(calendar, month,
+ has_month_code ? month_code_has_l : 0,
+ day, overflow_constrain, overflow_year,
+ &iso_y, &iso_m, &iso_d) < 0)
+ return JS_ThrowRangeError(ctx, "invalid PlainMonthDay");
+ return js_create_plainmonthday_with_calendar(ctx, iso_y, iso_m, iso_d, calendar);
+ }
+ }
+ }
+ if (JS_IsString(val)) {
+ const char *str = JS_ToCString(ctx, val);
+ TISODateTimeParseResult result;
+ int pm_month, pm_day, pm_year;
+ CalendarType str_calendar;
+ if (!str)
+ return JS_EXCEPTION;
+ if (ti_is_minus_zero_year(str)) {
+ JS_FreeCString(ctx, str);
+ return JS_ThrowRangeError(ctx, "invalid PlainMonthDay string");
+ }
+ memset(&result, 0, sizeof(result));
+ if (ti_parse_iso_datetime_string(ctx, str, &result, TI_PARSE_PLAIN_MONTHDAY) < 0) {
+ JS_FreeCString(ctx, str);
+ return JS_ThrowRangeError(ctx, "invalid PlainMonthDay string");
+ }
+ JS_FreeCString(ctx, str);
+ if (result.has_date) {
+ pm_month = result.month;
+ pm_day = result.day;
+ pm_year = result.year;
+ } else {
+ pm_month = result.month;
+ pm_day = result.day;
+ pm_year = 0;
+ }
+ str_calendar = result.has_calendar ? result.calendar : CAL_ISO8601;
+ if (str_calendar == CAL_UNKNOWN)
+ return JS_ThrowRangeError(ctx, "invalid PlainMonthDay string");
+ /* For month-day strings without a year, only iso8601 calendar is allowed */
+ if (!result.has_date && str_calendar != CAL_ISO8601)
+ return JS_ThrowRangeError(ctx, "invalid PlainMonthDay string");
+ /* Validate options AFTER string parsing */
+ if (argc >= 2 && ti_validate_options_object(ctx, argv[1]) < 0)
+ return JS_EXCEPTION;
+ if (argc >= 2 && ti_get_overflow_option(ctx, argv[1], &overflow_constrain) < 0)
+ return JS_EXCEPTION;
+ {
+ int str_ref_year = 1972;
+ if (str_calendar != CAL_ISO8601) {
+ str_ref_year = pm_year;
+ if (!ti_is_date_within_iso_limits(str_ref_year, pm_month, pm_day))
+ return JS_ThrowRangeError(ctx, "invalid PlainMonthDay string");
+ }
+ return js_create_plainmonthday_with_calendar(ctx, str_ref_year, pm_month, pm_day, str_calendar);
+ }
+ }
+ return JS_ThrowTypeError(ctx, "unsupported argument type for Temporal.PlainMonthDay.from");
+}
+
+static JSValue js_plainmonthday_toPlainDate(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSPlainMonthDayData *s;
+ JSValue val;
+ int year;
+ s = JS_GetOpaque2(ctx, this_val, js_plainmonthday_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ val = argv[0];
+ if (!JS_IsObject(val))
+ return JS_ThrowTypeError(ctx, "toPlainDate argument must be an object");
+ {
+ JSValue v = JS_GetPropertyStr(ctx, val, "year");
+ double d;
+ int has_year = 0;
+ if (!JS_IsUndefined(v)) {
+ if (JS_ToFloat64(ctx, &d, v) < 0) {
+ JS_FreeValue(ctx, v);
+ return JS_EXCEPTION;
+ }
+ if (ti_is_minus_zero(v)) {
+ JS_FreeValue(ctx, v);
+ return JS_ThrowRangeError(ctx, "minus zero year is not allowed");
+ }
+ JS_FreeValue(ctx, v);
+ if (!isfinite(d)) {
+ JS_ThrowRangeError(ctx, "year must be an integer");
+ return JS_EXCEPTION;
+ }
+ if (d < INT32_MIN || d > INT32_MAX) {
+ JS_ThrowRangeError(ctx, "year out of range");
+ return JS_EXCEPTION;
+ }
+ year = (int)(d < 0 ? ceil(d) : floor(d));
+ has_year = 1;
+ } else {
+ JS_FreeValue(ctx, v);
+ }
+ /* era/eraYear fallback for calendars that support eras */
+ if (!has_year && ti_calendar_requires_era(s->calendar)) {
+ JSValue era_v = JS_GetPropertyStr(ctx, val, "era");
+ JSValue eraYear_v = JS_GetPropertyStr(ctx, val, "eraYear");
+ if (!JS_IsUndefined(era_v) || !JS_IsUndefined(eraYear_v)) {
+ if (JS_IsUndefined(era_v) || JS_IsUndefined(eraYear_v)) {
+ JS_FreeValue(ctx, era_v);
+ JS_FreeValue(ctx, eraYear_v);
+ return JS_ThrowTypeError(ctx, "era and eraYear must both be present");
+ }
+ const char *era_str = JS_ToCString(ctx, era_v);
+ if (!era_str) {
+ JS_FreeValue(ctx, era_v);
+ JS_FreeValue(ctx, eraYear_v);
+ return JS_EXCEPTION;
+ }
+ TIEra era = ti_string_to_era(era_str);
+ JS_FreeCString(ctx, era_str);
+ JS_FreeValue(ctx, era_v);
+ if (era == TI_ERA_UNKNOWN) {
+ JS_FreeValue(ctx, eraYear_v);
+ return JS_ThrowRangeError(ctx, "invalid era");
+ }
+ if (JS_ToFloat64(ctx, &d, eraYear_v) < 0) {
+ JS_FreeValue(ctx, eraYear_v);
+ return JS_EXCEPTION;
+ }
+ JS_FreeValue(ctx, eraYear_v);
+ if (!isfinite(d)) {
+ JS_ThrowRangeError(ctx, "eraYear must be an integer");
+ return JS_EXCEPTION;
+ }
+ int iso_year;
+ if (ti_calendar_era_to_iso_year(s->calendar, era, (int)d, &iso_year) < 0)
+ return JS_ThrowRangeError(ctx, "invalid era");
+ year = iso_year;
+ has_year = 1;
+ } else {
+ JS_FreeValue(ctx, era_v);
+ JS_FreeValue(ctx, eraYear_v);
+ }
+ }
+ if (!has_year)
+ return JS_ThrowTypeError(ctx, "missing year property");
+ }
+ {
+ int cal_y, cal_m, cal_d;
+ int iso_y, iso_m, iso_d;
+ int day;
+ int dim;
+ pmd_get_calendar_date(s, &cal_y, &cal_m, &cal_d);
+ day = cal_d;
+ dim = ti_calendar_days_in_month(s->calendar, year, cal_m);
+ if (day > dim || day < 1) {
+ int overflow_constrain = 1;
+ if (argc >= 2 && ti_validate_options_object(ctx, argv[1]) < 0)
+ return JS_EXCEPTION;
+ if (argc >= 2 && !JS_IsUndefined(argv[1])) {
+ if (ti_get_overflow_option(ctx, argv[1], &overflow_constrain) < 0)
+ return JS_EXCEPTION;
+ }
+ if (!overflow_constrain)
+ return JS_ThrowRangeError(ctx, "invalid PlainDate");
+ if (day > dim)
+ day = dim;
+ else if (day < 1)
+ day = 1;
+ }
+ if (ti_calendar_date_to_iso(s->calendar, year, cal_m, day, &iso_y, &iso_m, &iso_d) < 0)
+ return JS_ThrowRangeError(ctx, "invalid PlainDate");
+ return js_create_plaindate_with_calendar(ctx, iso_y, iso_m, iso_d, s->calendar);
+ }
+}
+
+static const JSCFunctionListEntry js_plainmonthday_proto_funcs[] = {
+ JS_CGETSET_DEF("monthCode", js_plainmonthday_get_monthCode, NULL),
+ JS_CGETSET_DEF("day", js_plainmonthday_get_day, NULL),
+ JS_CGETSET_DEF("referenceISOYear", js_plainmonthday_get_referenceISOYear, NULL),
+ JS_CGETSET_DEF("calendarId", js_plainmonthday_get_calendarId, NULL),
+ JS_CGETSET_DEF("era", js_plainmonthday_get_era, NULL),
+ JS_CGETSET_DEF("eraYear", js_plainmonthday_get_eraYear, NULL),
+ JS_CGETSET_DEF("inLeapYear", js_plainmonthday_get_inLeapYear, NULL),
+ JS_CGETSET_DEF("daysInMonth", js_plainmonthday_get_daysInMonth, NULL),
+ JS_CGETSET_DEF("daysInYear", js_plainmonthday_get_daysInYear, NULL),
+ JS_CGETSET_DEF("daysInWeek", js_plainmonthday_get_daysInWeek, NULL),
+ JS_CGETSET_DEF("monthsInYear", js_plainmonthday_get_monthsInYear, NULL),
+ JS_CGETSET_DEF("dayOfYear", js_plainmonthday_get_dayOfYear, NULL),
+ JS_CGETSET_DEF("dayOfWeek", js_plainmonthday_get_dayOfWeek, NULL),
+ JS_CGETSET_DEF("weekOfYear", js_plainmonthday_get_weekOfYear, NULL),
+ JS_CGETSET_DEF("yearOfWeek", js_plainmonthday_get_yearOfWeek, NULL),
+ JS_CFUNC_DEF("equals", 1, js_plainmonthday_equals),
+ JS_CFUNC_DEF("toString", 0, js_plainmonthday_toString),
+ JS_CFUNC_DEF("toJSON", 0, js_plainmonthday_toJSON),
+ JS_CFUNC_DEF("toLocaleString", 0, js_plainmonthday_toLocaleString),
+ JS_CFUNC_DEF("with", 1, js_plainmonthday_with),
+ JS_CFUNC_DEF("toPlainDate", 1, js_plainmonthday_toPlainDate),
+ JS_CFUNC_DEF("valueOf", 0, js_plainmonthday_valueOf),
+ JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Temporal.PlainMonthDay", JS_PROP_CONFIGURABLE),
+};
+
+static const JSCFunctionListEntry js_plainmonthday_static_funcs[] = {
+ JS_CFUNC_DEF("from", 1, js_plainmonthday_from),
+};
+
+int js_add_plainmonthday(JSContext *ctx, JSValue temporal_obj)
+{
+ JSValue ctor;
+
+ JS_NewClassID(&js_plainmonthday_class_id);
+ JS_NewClass(JS_GetRuntime(ctx), js_plainmonthday_class_id, &js_plainmonthday_class);
+
+ ctor = JS_NewCConstructor(ctx, (int)js_plainmonthday_class_id, "PlainMonthDay",
+ (JSCFunction *)js_plainmonthday_constructor, 2,
+ JS_CFUNC_constructor, 0,
+ JS_UNDEFINED,
+ js_plainmonthday_static_funcs, countof(js_plainmonthday_static_funcs),
+ js_plainmonthday_proto_funcs, countof(js_plainmonthday_proto_funcs),
+ JS_NEW_CTOR_NO_GLOBAL);
+ if (JS_IsException(ctor))
+ return -1;
+ if (JS_DefinePropertyValueStr(ctx, temporal_obj, "PlainMonthDay", ctor,
+ JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE) < 0)
+ return -1;
+ return 0;
+}
--- /dev/null
+/*
+ * QuickJS Temporal.PlainTime implementation
+ */
+
+#include <string.h>
+#include <math.h>
+
+#include "../quickjs.h"
+#include "../cutils.h"
+#include "temporal_private.h"
+
+JSClassID js_plaintime_class_id;
+
+static void js_plaintime_finalizer(JSRuntime *rt, JSValue val)
+{
+ JSPlainTimeData *s = JS_GetOpaque(val, js_plaintime_class_id);
+ if (s)
+ js_free_rt(rt, s);
+}
+
+static const JSClassDef js_plaintime_class = {
+ "Temporal.PlainTime",
+ .finalizer = js_plaintime_finalizer,
+};
+
+JSValue js_create_plaintime(JSContext *ctx, const JSPlainTimeData *t)
+{
+ JSPlainTimeData *s;
+ JSValue obj;
+ s = js_mallocz(ctx, sizeof(*s));
+ if (!s)
+ return JS_EXCEPTION;
+ *s = *t;
+ obj = JS_NewObjectClass(ctx, (int)js_plaintime_class_id);
+ if (JS_IsException(obj)) {
+ js_free(ctx, s);
+ return JS_EXCEPTION;
+ }
+ JS_SetOpaque(obj, s);
+ return obj;
+}
+
+/* Forward declaration */
+JSValue js_plaintime_from(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv);
+
+static int pt_to_integer_with_truncation(JSContext *ctx, JSValueConst val, int *pres)
+{
+ double d;
+ if (JS_IsUndefined(val)) {
+ *pres = 0;
+ return 0;
+ }
+ if (JS_ToFloat64(ctx, &d, val))
+ return -1;
+ if (!isfinite(d)) {
+ JS_ThrowRangeError(ctx, "value must be an integer");
+ return -1;
+ }
+ if (d < INT32_MIN || d > INT32_MAX) {
+ JS_ThrowRangeError(ctx, "value out of range");
+ return -1;
+ }
+ *pres = (int)(d < 0 ? ceil(d) : floor(d));
+ return 0;
+}
+
+/* Validate time fields */
+static int pt_is_valid_time(int hour, int minute, int second,
+ int millisecond, int microsecond, int nanosecond)
+{
+ if (hour < 0 || hour > 23)
+ return 0;
+ if (minute < 0 || minute > 59)
+ return 0;
+ if (second < 0 || second > 59)
+ return 0;
+ if (millisecond < 0 || millisecond > 999)
+ return 0;
+ if (microsecond < 0 || microsecond > 999)
+ return 0;
+ if (nanosecond < 0 || nanosecond > 999)
+ return 0;
+ return 1;
+}
+
+/* Temporal.PlainTime constructor */
+static JSValue js_plaintime_constructor(JSContext *ctx, JSValueConst new_target,
+ int argc, JSValueConst *argv)
+{
+ JSPlainTimeData t = {0};
+ JSValue obj;
+ if (JS_IsUndefined(new_target)) {
+ return JS_ThrowTypeError(ctx, "Temporal.PlainTime constructor cannot be called as a function");
+ }
+ if (argc > 0 && pt_to_integer_with_truncation(ctx, argv[0], &t.hour) < 0)
+ return JS_EXCEPTION;
+ if (argc > 1 && pt_to_integer_with_truncation(ctx, argv[1], &t.minute) < 0)
+ return JS_EXCEPTION;
+ if (argc > 2 && pt_to_integer_with_truncation(ctx, argv[2], &t.second) < 0)
+ return JS_EXCEPTION;
+ if (argc > 3 && pt_to_integer_with_truncation(ctx, argv[3], &t.millisecond) < 0)
+ return JS_EXCEPTION;
+ if (argc > 4 && pt_to_integer_with_truncation(ctx, argv[4], &t.microsecond) < 0)
+ return JS_EXCEPTION;
+ if (argc > 5 && pt_to_integer_with_truncation(ctx, argv[5], &t.nanosecond) < 0)
+ return JS_EXCEPTION;
+ if (!pt_is_valid_time(t.hour, t.minute, t.second, t.millisecond, t.microsecond, t.nanosecond))
+ return JS_ThrowRangeError(ctx, "invalid PlainTime");
+ {
+ JSPlainTimeData *s = js_mallocz(ctx, sizeof(*s));
+ if (!s)
+ return JS_EXCEPTION;
+ *s = t;
+ obj = js_create_temporal_object(ctx, new_target, js_plaintime_class_id, s);
+ if (JS_IsException(obj)) {
+ js_free(ctx, s);
+ return JS_EXCEPTION;
+ }
+ return obj;
+ }
+}
+
+/* Getters */
+enum {
+ PLAINTIME_HOUR = 0,
+ PLAINTIME_MINUTE,
+ PLAINTIME_SECOND,
+ PLAINTIME_MILLISECOND,
+ PLAINTIME_MICROSECOND,
+ PLAINTIME_NANOSECOND,
+};
+
+static JSValue js_plaintime_get_field(JSContext *ctx, JSValueConst this_val, int magic)
+{
+ JSPlainTimeData *s = JS_GetOpaque2(ctx, this_val, js_plaintime_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ switch (magic) {
+ case PLAINTIME_HOUR: return JS_NewInt32(ctx, s->hour);
+ case PLAINTIME_MINUTE: return JS_NewInt32(ctx, s->minute);
+ case PLAINTIME_SECOND: return JS_NewInt32(ctx, s->second);
+ case PLAINTIME_MILLISECOND: return JS_NewInt32(ctx, s->millisecond);
+ case PLAINTIME_MICROSECOND: return JS_NewInt32(ctx, s->microsecond);
+ case PLAINTIME_NANOSECOND: return JS_NewInt32(ctx, s->nanosecond);
+ default: return JS_UNDEFINED;
+ }
+}
+
+/* Temporal.PlainTime.prototype.equals */
+static JSValue js_plaintime_equals(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ (void)argc;
+ JSPlainTimeData *s, *other;
+ JSValue other_val;
+ int ret;
+ s = JS_GetOpaque2(ctx, this_val, js_plaintime_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ other_val = js_plaintime_from(ctx, JS_UNDEFINED, 1, argv);
+ if (JS_IsException(other_val))
+ return JS_EXCEPTION;
+ other = JS_GetOpaque(other_val, js_plaintime_class_id);
+ if (!other) {
+ JS_FreeValue(ctx, other_val);
+ return JS_NewBool(ctx, 0);
+ }
+ ret = s->hour == other->hour && s->minute == other->minute &&
+ s->second == other->second && s->millisecond == other->millisecond &&
+ s->microsecond == other->microsecond && s->nanosecond == other->nanosecond;
+ JS_FreeValue(ctx, other_val);
+ return JS_NewBool(ctx, ret);
+}
+
+/* Format PlainTime as ISO string */
+static JSValue js_plaintime_toString(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSPlainTimeData *s;
+ JSPlainTimeData rounded = {0};
+ char buf[64];
+ int n;
+ int precision_type = -1; /* -1 = auto, 0 = second, 1-9 = digits, 10 = minute, 11 = second, 12 = ms, 13 = us, 14 = ns */
+ int fsd_is_auto = 1;
+ int fsd_value = 0;
+ TIUnit smallestUnit = TI_UNIT_INVALID;
+ TIRoundingMode rounding_mode = ROUND_TRUNC;
+ int has_smallestUnit = 0;
+ s = JS_GetOpaque2(ctx, this_val, js_plaintime_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+
+ if (argc >= 1 && !JS_IsUndefined(argv[0])) {
+ if (!JS_IsObject(argv[0]))
+ return JS_ThrowTypeError(ctx, "options must be an object");
+
+ /* Step 1: Read fractionalSecondDigits */
+ {
+ int fsd = ti_get_fractional_second_digits_option(ctx, argv[0], &fsd_value);
+ if (fsd < 0)
+ return JS_EXCEPTION;
+ if (fsd_value != -1)
+ fsd_is_auto = 0;
+ }
+
+ /* Step 2: Read roundingMode */
+ {
+ TIRoundingMode mode;
+ if (ti_get_rounding_mode_option_default(ctx, argv[0], &mode, ROUND_TRUNC) < 0)
+ return JS_EXCEPTION;
+ rounding_mode = mode;
+ }
+
+ /* Step 3: Read smallestUnit */
+ {
+ TIUnit unit;
+ if (ti_parse_unit_option(ctx, argv[0], "smallestUnit", &unit, TI_UNIT_OPT_ALLOW_UNDEFINED, TI_UNIT_INVALID) < 0)
+ return JS_EXCEPTION;
+ if (unit != TI_UNIT_INVALID) {
+ smallestUnit = unit;
+ has_smallestUnit = 1;
+ }
+ }
+ }
+
+ /* Validation */
+ if (has_smallestUnit && (smallestUnit == TI_UNIT_INVALID || smallestUnit < TI_UNIT_MINUTE || smallestUnit > TI_UNIT_NANOSECOND))
+ return JS_ThrowRangeError(ctx, "invalid smallestUnit");
+
+ /* Determine precision: smallestUnit overrides fractionalSecondDigits */
+ if (has_smallestUnit && smallestUnit >= TI_UNIT_MINUTE && smallestUnit <= TI_UNIT_NANOSECOND) {
+ precision_type = ti_precision_from_smallest_unit(smallestUnit);
+ } else if (!fsd_is_auto) {
+ precision_type = fsd_value;
+ } else {
+ precision_type = -1; /* auto */
+ }
+
+ /* Apply rounding if precision is not auto and not nanosecond (increment > 1) */
+ rounded = *s;
+ if (precision_type >= 0 && precision_type != 14) {
+ int64_t total_ns = ((int64_t)s->hour * 3600 + s->minute * 60 + s->second) * 1000000000LL
+ + s->millisecond * 1000000LL + s->microsecond * 1000LL + s->nanosecond;
+ int64_t increment_ns;
+
+ switch (precision_type) {
+ case 0:
+ case 11:
+ increment_ns = 1000000000LL;
+ break;
+ case 10:
+ increment_ns = 60000000000LL;
+ break;
+ case 12:
+ increment_ns = 1000000LL;
+ break;
+ case 13:
+ increment_ns = 1000LL;
+ break;
+ default: /* 1-9 digits */
+ increment_ns = 1;
+ {
+ int i;
+ for (i = 0; i < 9 - precision_type; i++) increment_ns *= 10;
+ }
+ break;
+ }
+
+ int64_t rounded_ns = ti_round_to_increment_as_if_positive(total_ns, increment_ns, rounding_mode);
+ rounded_ns %= 86400000000000LL;
+
+ rounded.hour = (int)(rounded_ns / 3600000000000LL);
+ rounded_ns %= 3600000000000LL;
+ rounded.minute = (int)(rounded_ns / 60000000000LL);
+ rounded_ns %= 60000000000LL;
+ rounded.second = (int)(rounded_ns / 1000000000LL);
+ rounded_ns %= 1000000000LL;
+ rounded.millisecond = (int)(rounded_ns / 1000000LL);
+ rounded_ns %= 1000000LL;
+ rounded.microsecond = (int)(rounded_ns / 1000LL);
+ rounded.nanosecond = (int)(rounded_ns % 1000LL);
+ }
+
+ /* Format */
+ if (precision_type == 10) { /* minute */
+ n = snprintf(buf, sizeof(buf), "%02d:%02d", rounded.hour, rounded.minute);
+ } else {
+ n = snprintf(buf, sizeof(buf), "%02d:%02d:%02d",
+ rounded.hour, rounded.minute, rounded.second);
+
+ if (precision_type != 0 && precision_type != 11) {
+ /* Add fractional part */
+ int digits = 9;
+ if (precision_type >= 1 && precision_type <= 9)
+ digits = precision_type;
+ else if (precision_type == 12)
+ digits = 3;
+ else if (precision_type == 13)
+ digits = 6;
+ else if (precision_type == 14)
+ digits = 9;
+
+ char frac[16];
+ snprintf(frac, sizeof(frac), "%03d%03d%03d",
+ rounded.millisecond, rounded.microsecond, rounded.nanosecond);
+
+ if (precision_type == -1) {
+ /* auto: drop trailing zeros */
+ while (digits > 0 && frac[digits - 1] == '0')
+ digits--;
+ }
+
+ if (digits > 0) {
+ frac[digits] = '\0';
+ snprintf(buf + n, sizeof(buf) - (size_t)n, ".%s", frac);
+ }
+ }
+ }
+
+ return JS_NewString(ctx, buf);
+}
+
+
+static JSValue js_plaintime_toJSON(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ (void)argc;
+ (void)argv;
+ return js_plaintime_toString(ctx, this_val, 0, NULL);
+}
+
+static JSValue js_plaintime_toLocaleString(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSPlainTimeData *s = JS_GetOpaque2(ctx, this_val, js_plaintime_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ return ti_temporal_toLocaleString(ctx, this_val, argc, argv, 2, js_plaintime_toString);
+}
+
+static JSValue js_plaintime_valueOf(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ (void)argc;
+ (void)argv;
+ (void)this_val;
+ return JS_ThrowTypeError(ctx, "cannot compare Temporal.PlainTime with < or >");
+}
+
+/* Temporal.PlainTime.compare */
+static JSValue js_plaintime_compare(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ (void)argc;
+ (void)this_val;
+ JSPlainTimeData *s1, *s2;
+ JSValue a, b;
+ int cmp;
+ a = js_plaintime_from(ctx, JS_UNDEFINED, 1, &argv[0]);
+ if (JS_IsException(a))
+ return JS_EXCEPTION;
+ b = js_plaintime_from(ctx, JS_UNDEFINED, 1, &argv[1]);
+ if (JS_IsException(b)) {
+ JS_FreeValue(ctx, a);
+ return JS_EXCEPTION;
+ }
+ s1 = JS_GetOpaque(a, js_plaintime_class_id);
+ s2 = JS_GetOpaque(b, js_plaintime_class_id);
+ if (!s1 || !s2) {
+ JS_FreeValue(ctx, a);
+ JS_FreeValue(ctx, b);
+ return JS_ThrowTypeError(ctx, "compare arguments must be PlainTime objects");
+ }
+ if (s1->hour != s2->hour) {
+ cmp = s1->hour < s2->hour ? -1 : 1;
+ } else if (s1->minute != s2->minute) {
+ cmp = s1->minute < s2->minute ? -1 : 1;
+ } else if (s1->second != s2->second) {
+ cmp = s1->second < s2->second ? -1 : 1;
+ } else if (s1->millisecond != s2->millisecond) {
+ cmp = s1->millisecond < s2->millisecond ? -1 : 1;
+ } else if (s1->microsecond != s2->microsecond) {
+ cmp = s1->microsecond < s2->microsecond ? -1 : 1;
+ } else if (s1->nanosecond != s2->nanosecond) {
+ cmp = s1->nanosecond < s2->nanosecond ? -1 : 1;
+ } else {
+ cmp = 0;
+ }
+ JS_FreeValue(ctx, a);
+ JS_FreeValue(ctx, b);
+ return JS_NewInt32(ctx, cmp);
+}
+
+/* Helper: convert PlainTime to total nanoseconds from midnight */
+static int64_t pt_to_nanoseconds(const JSPlainTimeData *t)
+{
+ return ((int64_t)t->hour * 3600000000000LL +
+ (int64_t)t->minute * 60000000000LL +
+ (int64_t)t->second * 1000000000LL +
+ (int64_t)t->millisecond * 1000000LL +
+ (int64_t)t->microsecond * 1000LL +
+ (int64_t)t->nanosecond);
+}
+
+/* Helper: convert nanoseconds from midnight to PlainTime */
+static void pt_from_nanoseconds(int64_t ns, JSPlainTimeData *t)
+{
+ int64_t rem;
+ t->hour = (int)(ns / 3600000000000LL);
+ rem = ns % 3600000000000LL;
+ if (rem < 0) {
+ t->hour -= 1;
+ rem += 3600000000000LL;
+ }
+ t->minute = (int)(rem / 60000000000LL);
+ rem = rem % 60000000000LL;
+ t->second = (int)(rem / 1000000000LL);
+ rem = rem % 1000000000LL;
+ t->millisecond = (int)(rem / 1000000LL);
+ rem = rem % 1000000LL;
+ t->microsecond = (int)(rem / 1000LL);
+ t->nanosecond = (int)(rem % 1000LL);
+}
+
+/* Temporal.PlainTime.prototype.add */
+static JSValue js_plaintime_add_subtract(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv,
+ int is_add)
+{
+ (void)argc;
+ JSPlainTimeData *s;
+ JSDurationData d;
+ int64_t result_ns;
+ JSPlainTimeData result;
+ int sign = is_add ? 1 : -1;
+ s = JS_GetOpaque2(ctx, this_val, js_plaintime_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ if (js_to_temporal_duration(ctx, argv[0], &d) < 0)
+ return JS_EXCEPTION;
+ if (duration_has_mixed_signs(&d))
+ return JS_ThrowRangeError(ctx, "mixed signs in duration fields");
+ if (duration_is_out_of_range(&d))
+ return JS_ThrowRangeError(ctx, "duration out of range");
+ {
+ js_int128_t total = (js_int128_t)pt_to_nanoseconds(s) +
+ sign * ti_duration_time_fields_to_ns(&d);
+ /* Wrap around 24 hours */
+ total = ((total % 86400000000000LL) + 86400000000000LL) % 86400000000000LL;
+ result_ns = (int64_t)total;
+ }
+ pt_from_nanoseconds(result_ns, &result);
+ return js_create_plaintime(ctx, &result);
+}
+
+/* Temporal.PlainTime.prototype.round */
+static JSValue js_plaintime_round(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ (void)argc;
+ JSPlainTimeData *s;
+ JSValue options = JS_UNDEFINED;
+ JSValue v = JS_UNDEFINED;
+ TIUnit smallestUnit = TI_UNIT_INVALID;
+ TIRoundingMode mode = ROUND_HALF_EXPAND;
+ int64_t increment = 1;
+ int64_t total_ns, rounded_ns, unit_ns;
+ JSPlainTimeData result;
+
+ s = JS_GetOpaque2(ctx, this_val, js_plaintime_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ if (JS_IsString(argv[0])) {
+ size_t len;
+ const char *str = JS_ToCStringLen(ctx, &len, argv[0]);
+ if (!str)
+ return JS_EXCEPTION;
+ options = JS_NewObjectProto(ctx, JS_NULL);
+ JS_SetPropertyStr(ctx, options, "smallestUnit", JS_NewStringLen(ctx, str, len));
+ JS_FreeCString(ctx, str);
+ } else if (!JS_IsObject(argv[0])) {
+ return JS_ThrowTypeError(ctx, "round options must be an object or string");
+ } else {
+ options = JS_DupValue(ctx, argv[0]);
+ }
+
+ if (ti_get_rounding_increment_option(ctx, options, &increment) < 0) {
+ JS_FreeValue(ctx, options);
+ return JS_EXCEPTION;
+ }
+ if (ti_get_rounding_mode_option(ctx, options, &mode) < 0) {
+ JS_FreeValue(ctx, options);
+ return JS_EXCEPTION;
+ }
+ if (ti_parse_unit_option(ctx, options, "smallestUnit", &smallestUnit, 0, 0) < 0) {
+ JS_FreeValue(ctx, options);
+ return JS_EXCEPTION;
+ }
+ if (smallestUnit < TI_UNIT_HOUR || smallestUnit > TI_UNIT_NANOSECOND) {
+ JS_ThrowRangeError(ctx, "invalid smallestUnit");
+ JS_FreeValue(ctx, options);
+ return JS_EXCEPTION;
+ }
+ /* Validate roundingIncrement against per-unit maximum (inclusive = false) */
+ {
+ int64_t maximum;
+ switch (smallestUnit) {
+ case TI_UNIT_HOUR: maximum = 24; break;
+ case TI_UNIT_MINUTE: maximum = 60; break;
+ case TI_UNIT_SECOND: maximum = 60; break;
+ case TI_UNIT_MILLISECOND: maximum = 1000; break;
+ case TI_UNIT_MICROSECOND: maximum = 1000; break;
+ case TI_UNIT_NANOSECOND: maximum = 1000; break;
+ default: maximum = 0; break;
+ }
+ if (increment >= maximum || maximum % increment != 0) {
+ JS_ThrowRangeError(ctx, "roundingIncrement does not divide evenly into the unit");
+ goto round_fail;
+ }
+ }
+
+
+
+ total_ns = pt_to_nanoseconds(s);
+
+ switch (smallestUnit) {
+ case TI_UNIT_HOUR: unit_ns = 3600000000000LL; break;
+ case TI_UNIT_MINUTE: unit_ns = 60000000000LL; break;
+ case TI_UNIT_SECOND: unit_ns = 1000000000LL; break;
+ case TI_UNIT_MILLISECOND: unit_ns = 1000000LL; break;
+ case TI_UNIT_MICROSECOND: unit_ns = 1000LL; break;
+ case TI_UNIT_NANOSECOND: unit_ns = 1LL; break;
+ default: unit_ns = 1LL; break;
+ }
+
+ rounded_ns = ti_round_to_increment(total_ns, unit_ns * increment, mode);
+ /* Wrap around midnight for PlainTime */
+ rounded_ns = rounded_ns % 86400000000000LL;
+ if (rounded_ns < 0)
+ rounded_ns += 86400000000000LL;
+ pt_from_nanoseconds(rounded_ns, &result);
+ JS_FreeValue(ctx, options);
+ return js_create_plaintime(ctx, &result);
+
+round_fail:
+ JS_FreeValue(ctx, v);
+ JS_FreeValue(ctx, options);
+ return JS_EXCEPTION;
+}
+
+/* Helper: convert nanoseconds to JSDurationData for PlainTime difference */
+static void pt_ns_to_duration(int64_t ns, TIUnit largestUnit, JSDurationData *d)
+{
+ int64_t rem;
+ int sign = (ns < 0) ? -1 : 1;
+ memset(d, 0, sizeof(*d));
+ if (ns < 0)
+ ns = -ns;
+
+ if (largestUnit == TI_UNIT_HOUR) {
+ d->hours = sign * (ns / 3600000000000LL);
+ rem = ns % 3600000000000LL;
+ } else {
+ d->hours = 0;
+ rem = ns;
+ }
+
+ if (largestUnit == TI_UNIT_MINUTE) {
+ d->minutes = sign * (rem / 60000000000LL);
+ rem = rem % 60000000000LL;
+ } else if (largestUnit == TI_UNIT_HOUR) {
+ d->minutes = sign * (rem / 60000000000LL);
+ rem = rem % 60000000000LL;
+ } else {
+ d->minutes = 0;
+ }
+
+ if (largestUnit == TI_UNIT_SECOND) {
+ d->seconds = sign * (rem / 1000000000LL);
+ rem = rem % 1000000000LL;
+ } else if (largestUnit == TI_UNIT_HOUR || largestUnit == TI_UNIT_MINUTE) {
+ d->seconds = sign * (rem / 1000000000LL);
+ rem = rem % 1000000000LL;
+ } else {
+ d->seconds = 0;
+ }
+
+ if (largestUnit == TI_UNIT_MILLISECOND) {
+ d->milliseconds = sign * (rem / 1000000LL);
+ rem = rem % 1000000LL;
+ } else if (largestUnit < TI_UNIT_MILLISECOND) {
+ d->milliseconds = sign * (rem / 1000000LL);
+ rem = rem % 1000000LL;
+ } else {
+ d->milliseconds = 0;
+ }
+
+ if (largestUnit == TI_UNIT_MICROSECOND) {
+ d->microseconds.int128_value = sign * (rem / 1000LL);
+ rem = rem % 1000LL;
+ } else if (largestUnit < TI_UNIT_MICROSECOND) {
+ d->microseconds.int128_value = sign * (rem / 1000LL);
+ rem = rem % 1000LL;
+ } else {
+ d->microseconds.int128_value = 0;
+ }
+
+ if (largestUnit == TI_UNIT_NANOSECOND) {
+ d->nanoseconds.int128_value = sign * rem;
+ } else if (largestUnit < TI_UNIT_NANOSECOND) {
+ d->nanoseconds.int128_value = sign * rem;
+ } else {
+ d->nanoseconds.int128_value = 0;
+ }
+}
+
+/* Temporal.PlainTime.prototype.until */
+static JSValue js_plaintime_difference(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv, int is_since)
+{
+ JSPlainTimeData *s, *other;
+ JSValue other_val = JS_UNDEFINED;
+ JSValue options = JS_UNDEFINED;
+ JSDurationData d;
+ TIUnit smallestUnit = TI_UNIT_INVALID, largestUnit = TI_UNIT_INVALID;
+ TIRoundingMode mode = ROUND_TRUNC;
+ int64_t increment = 1;
+ int64_t this_ns, other_ns, diff_ns;
+
+ s = JS_GetOpaque2(ctx, this_val, js_plaintime_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ other_val = js_plaintime_from(ctx, JS_UNDEFINED, 1, argv);
+ if (JS_IsException(other_val))
+ return JS_EXCEPTION;
+ other = JS_GetOpaque(other_val, js_plaintime_class_id);
+ if (!other) {
+ JS_FreeValue(ctx, other_val);
+ return JS_EXCEPTION;
+ }
+
+ if (argc >= 2 && !JS_IsUndefined(argv[1])) {
+ if (!JS_IsObject(argv[1])) {
+ JS_FreeValue(ctx, other_val);
+ return JS_ThrowTypeError(ctx, "options must be an object");
+ }
+ options = JS_DupValue(ctx, argv[1]);
+
+ if (ti_parse_unit_option(ctx, options, "largestUnit", &largestUnit, TI_UNIT_OPT_ALLOW_UNDEFINED | TI_UNIT_OPT_ALLOW_AUTO, TI_UNIT_INVALID) < 0)
+ goto fail;
+ if (ti_get_rounding_increment_option(ctx, options, &increment) < 0)
+ goto fail;
+ if (ti_get_rounding_mode_option_default(ctx, options, &mode, ROUND_TRUNC) < 0)
+ goto fail;
+ if (ti_parse_unit_option(ctx, options, "smallestUnit", &smallestUnit, TI_UNIT_OPT_ALLOW_UNDEFINED, TI_UNIT_INVALID) < 0)
+ goto fail;
+
+ /* Validate unit restrictions */
+ if (largestUnit != TI_UNIT_INVALID && largestUnit != TI_UNIT_AUTO && largestUnit < TI_UNIT_HOUR) {
+ JS_ThrowRangeError(ctx, "invalid largestUnit");
+ goto fail;
+ }
+ if (smallestUnit != TI_UNIT_INVALID && smallestUnit < TI_UNIT_HOUR) {
+ JS_ThrowRangeError(ctx, "invalid smallestUnit");
+ goto fail;
+ }
+ /* Validate roundingIncrement against per-unit maximum (inclusive = false) */
+ {
+ int64_t maximum;
+ TIUnit eff_su = (smallestUnit == TI_UNIT_INVALID) ? TI_UNIT_NANOSECOND : smallestUnit;
+ switch (eff_su) {
+ case TI_UNIT_HOUR: maximum = 24; break;
+ case TI_UNIT_MINUTE: maximum = 60; break;
+ case TI_UNIT_SECOND: maximum = 60; break;
+ case TI_UNIT_MILLISECOND: maximum = 1000; break;
+ case TI_UNIT_MICROSECOND: maximum = 1000; break;
+ case TI_UNIT_NANOSECOND: maximum = 1000; break;
+ default: maximum = 0; break;
+ }
+ if (increment >= maximum || maximum % increment != 0) {
+ JS_ThrowRangeError(ctx, "roundingIncrement does not divide evenly into the unit");
+ goto fail;
+ }
+ }
+ /* Validate largestUnit >= smallestUnit in magnitude */
+ {
+ TIUnit eff_lu = (largestUnit == TI_UNIT_INVALID || largestUnit == TI_UNIT_AUTO) ? TI_UNIT_HOUR : largestUnit;
+ TIUnit eff_su = (smallestUnit == TI_UNIT_INVALID) ? TI_UNIT_NANOSECOND : smallestUnit;
+ if (eff_lu > eff_su) {
+ JS_ThrowRangeError(ctx, "largestUnit must be larger than smallestUnit");
+ goto fail;
+ }
+ }
+ JS_FreeValue(ctx, options);
+ options = JS_UNDEFINED;
+ }
+
+ this_ns = pt_to_nanoseconds(s);
+ other_ns = pt_to_nanoseconds(other);
+ diff_ns = is_since ? (this_ns - other_ns) : (other_ns - this_ns);
+
+ {
+ int64_t unit_ns;
+ TIUnit su = smallestUnit;
+ if (su == -1)
+ su = TI_UNIT_NANOSECOND;
+ switch (su) {
+ case TI_UNIT_HOUR: unit_ns = 3600000000000LL; break;
+ case TI_UNIT_MINUTE: unit_ns = 60000000000LL; break;
+ case TI_UNIT_SECOND: unit_ns = 1000000000LL; break;
+ case TI_UNIT_MILLISECOND: unit_ns = 1000000LL; break;
+ case TI_UNIT_MICROSECOND: unit_ns = 1000LL; break;
+ case TI_UNIT_NANOSECOND: unit_ns = 1LL; break;
+ default: unit_ns = 1LL; break;
+ }
+ diff_ns = ti_round_to_increment(diff_ns, unit_ns * increment, mode);
+ }
+
+ if (largestUnit == TI_UNIT_INVALID || largestUnit == TI_UNIT_AUTO)
+ largestUnit = TI_UNIT_HOUR;
+ pt_ns_to_duration(diff_ns, largestUnit, &d);
+ JS_FreeValue(ctx, other_val);
+ return js_create_duration(ctx, &d);
+
+fail:
+ JS_FreeValue(ctx, options);
+ JS_FreeValue(ctx, other_val);
+ return JS_EXCEPTION;
+}
+
+/* Temporal.PlainTime.from */
+JSValue js_plaintime_from(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ (void)this_val;
+ JSPlainTimeData t = {0};
+ JSValue val, result = JS_UNDEFINED;
+ val = argv[0];
+ if (JS_IsObject(val)) {
+ JSPlainTimeData *s = JS_GetOpaque(val, js_plaintime_class_id);
+ if (s) {
+ result = js_create_plaintime(ctx, s);
+ }
+ if (JS_IsUndefined(result)) {
+ JSPlainDateTimeData *pdt = JS_GetOpaque(val, js_plaindatetime_class_id);
+ if (pdt) {
+ JSPlainTimeData pt;
+ pt.hour = pdt->hour;
+ pt.minute = pdt->minute;
+ pt.second = pdt->second;
+ pt.millisecond = pdt->millisecond;
+ pt.microsecond = pdt->microsecond;
+ pt.nanosecond = pdt->nanosecond;
+ result = js_create_plaintime(ctx, &pt);
+ }
+ }
+ if (JS_IsUndefined(result)) {
+ JSZonedDateTimeData *zdt = JS_GetOpaque(val, js_zoneddatetime_class_id);
+ if (zdt) {
+ JSPlainTimeData pt;
+ /* Convert epoch nanoseconds to time of day, applying timezone offset */
+ js_int128_t ns = ti_timespec_to_ns(&zdt->ts);
+ {
+ int64_t offset_ns = 0;
+ int ret = ti_parse_temporal_timezone_string(zdt->timeZone, &offset_ns);
+ if (ret == 0) {
+ ns += offset_ns;
+ }
+ }
+ {
+ int64_t day_ns = 86400000000000LL;
+ int64_t rem = (int64_t)(ns % day_ns);
+ if (rem < 0) rem += day_ns;
+ pt_from_nanoseconds(rem, &pt);
+ }
+ result = js_create_plaintime(ctx, &pt);
+ }
+ }
+ if (!JS_IsUndefined(result)) {
+ /* Read options for PlainTime/PlainDateTime/ZonedDateTime instances */
+ if (argc >= 2) {
+ if (JS_IsNull(argv[1])) {
+ JS_FreeValue(ctx, result);
+ return JS_ThrowTypeError(ctx, "options must be an object");
+ }
+ if (!JS_IsUndefined(argv[1])) {
+ if (!JS_IsObject(argv[1])) {
+ JS_FreeValue(ctx, result);
+ return JS_ThrowTypeError(ctx, "options must be an object");
+ }
+ {
+ int oc = 1;
+ if (ti_get_overflow_option(ctx, argv[1], &oc) < 0) {
+ JS_FreeValue(ctx, result);
+ return JS_EXCEPTION;
+ }
+ }
+ }
+ }
+ return result;
+ }
+ /* Property bag */
+ {
+ TIPreparedFields fields;
+ if (ti_prepare_calendar_fields(ctx, val,
+ TI_FIELD_HOUR | TI_FIELD_MINUTE | TI_FIELD_SECOND |
+ TI_FIELD_MILLISECOND | TI_FIELD_MICROSECOND | TI_FIELD_NANOSECOND,
+ 0, 0, &fields, CAL_ISO8601) < 0)
+ return JS_EXCEPTION;
+ if (!fields.present_mask)
+ return JS_ThrowTypeError(ctx, "invalid PlainTime");
+ if (fields.present_mask & TI_FIELD_HOUR) t.hour = fields.hour;
+ if (fields.present_mask & TI_FIELD_MINUTE) t.minute = fields.minute;
+ if (fields.present_mask & TI_FIELD_SECOND) t.second = fields.second;
+ if (fields.present_mask & TI_FIELD_MILLISECOND) t.millisecond = fields.millisecond;
+ if (fields.present_mask & TI_FIELD_MICROSECOND) t.microsecond = fields.microsecond;
+ if (fields.present_mask & TI_FIELD_NANOSECOND) t.nanosecond = fields.nanosecond;
+ }
+ /* Now read options */
+ {
+ int overflow_reject = 0;
+ if (argc >= 2) {
+ if (JS_IsNull(argv[1]))
+ return JS_ThrowTypeError(ctx, "options must be an object");
+ if (!JS_IsUndefined(argv[1])) {
+ if (!JS_IsObject(argv[1]))
+ return JS_ThrowTypeError(ctx, "options must be an object");
+ {
+ int oc = 1;
+ if (ti_get_overflow_option(ctx, argv[1], &oc) < 0)
+ return JS_EXCEPTION;
+ if (!oc)
+ overflow_reject = 1;
+ }
+ }
+ }
+ /* Handle leap second: second 60 is normalized to 59 with constrain, rejected with reject */
+ if (t.second == 60) {
+ if (overflow_reject)
+ return JS_ThrowRangeError(ctx, "invalid PlainTime");
+ t.second = 59;
+ }
+ if (!overflow_reject) {
+ if (t.hour < 0) t.hour = 0;
+ if (t.hour > 23) t.hour = 23;
+ if (t.minute < 0) t.minute = 0;
+ if (t.minute > 59) t.minute = 59;
+ if (t.second < 0) t.second = 0;
+ if (t.second > 59) t.second = 59;
+ if (t.millisecond < 0) t.millisecond = 0;
+ if (t.millisecond > 999) t.millisecond = 999;
+ if (t.microsecond < 0) t.microsecond = 0;
+ if (t.microsecond > 999) t.microsecond = 999;
+ if (t.nanosecond < 0) t.nanosecond = 0;
+ if (t.nanosecond > 999) t.nanosecond = 999;
+ }
+ }
+ if (!pt_is_valid_time(t.hour, t.minute, t.second, t.millisecond, t.microsecond, t.nanosecond))
+ return JS_ThrowRangeError(ctx, "invalid PlainTime");
+ return js_create_plaintime(ctx, &t);
+ }
+ if (JS_IsString(val)) {
+ const char *str = JS_ToCString(ctx, val);
+ TISODateTimeParseResult r = {0};
+ if (!str)
+ return JS_EXCEPTION;
+ if (ti_parse_iso_datetime_string(ctx, str, &r, TI_PARSE_PLAIN_TIME) < 0) {
+ JS_FreeCString(ctx, str);
+ return JS_ThrowRangeError(ctx, "invalid PlainTime string");
+ }
+ JS_FreeCString(ctx, str);
+ if (r.second == 60) r.second = 59;
+ if (!pt_is_valid_time(r.hour, r.minute, r.second, r.millisecond, r.microsecond, r.nanosecond))
+ return JS_ThrowRangeError(ctx, "invalid PlainTime");
+ if (argc >= 2) {
+ if (JS_IsNull(argv[1]))
+ return JS_ThrowTypeError(ctx, "options must be an object");
+ if (!JS_IsUndefined(argv[1])) {
+ if (!JS_IsObject(argv[1]))
+ return JS_ThrowTypeError(ctx, "options must be an object");
+ {
+ int oc = 1;
+ if (ti_get_overflow_option(ctx, argv[1], &oc) < 0)
+ return JS_EXCEPTION;
+ }
+ }
+ }
+ t.hour = r.hour;
+ t.minute = r.minute;
+ t.second = r.second;
+ t.millisecond = r.millisecond;
+ t.microsecond = r.microsecond;
+ t.nanosecond = r.nanosecond;
+ return js_create_plaintime(ctx, &t);
+ }
+ return JS_ThrowTypeError(ctx, "unsupported argument type for Temporal.PlainTime.from");
+}
+
+/* Temporal.PlainTime.prototype.with */
+static JSValue js_plaintime_with(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSPlainTimeData *s;
+ JSPlainTimeData t;
+ TIPreparedFields fields;
+ int overflow_reject = 0;
+ s = JS_GetOpaque2(ctx, this_val, js_plaintime_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ t = *s;
+ if (ti_is_partial_temporal_object(ctx, argv[0]) < 0)
+ return JS_EXCEPTION;
+ if (ti_prepare_calendar_fields(ctx, argv[0],
+ TI_FIELD_HOUR | TI_FIELD_MINUTE | TI_FIELD_SECOND |
+ TI_FIELD_MILLISECOND | TI_FIELD_MICROSECOND | TI_FIELD_NANOSECOND,
+ 0, 1, &fields, CAL_ISO8601) < 0)
+ return JS_EXCEPTION;
+ /* Merge fields */
+ if (fields.present_mask & TI_FIELD_HOUR) t.hour = fields.hour;
+ if (fields.present_mask & TI_FIELD_MINUTE) t.minute = fields.minute;
+ if (fields.present_mask & TI_FIELD_SECOND) t.second = fields.second;
+ if (fields.present_mask & TI_FIELD_MILLISECOND) t.millisecond = fields.millisecond;
+ if (fields.present_mask & TI_FIELD_MICROSECOND) t.microsecond = fields.microsecond;
+ if (fields.present_mask & TI_FIELD_NANOSECOND) t.nanosecond = fields.nanosecond;
+ /* Read and validate overflow option */
+ if (argc >= 2 && !JS_IsUndefined(argv[1])) {
+ if (!JS_IsObject(argv[1]))
+ return JS_ThrowTypeError(ctx, "options must be an object");
+ {
+ int oc = 1;
+ if (ti_get_overflow_option(ctx, argv[1], &oc) < 0)
+ return JS_EXCEPTION;
+ if (!oc)
+ overflow_reject = 1;
+ }
+ }
+ /* Handle leap second */
+ if (t.second == 60) {
+ if (overflow_reject)
+ return JS_ThrowRangeError(ctx, "invalid PlainTime");
+ t.second = 59;
+ }
+ if (overflow_reject) {
+ if (!pt_is_valid_time(t.hour, t.minute, t.second, t.millisecond, t.microsecond, t.nanosecond))
+ return JS_ThrowRangeError(ctx, "invalid PlainTime");
+ } else {
+ /* constrain */
+ if (t.hour < 0) t.hour = 0;
+ if (t.hour > 23) t.hour = 23;
+ if (t.minute < 0) t.minute = 0;
+ if (t.minute > 59) t.minute = 59;
+ if (t.second < 0) t.second = 0;
+ if (t.second > 59) t.second = 59;
+ if (t.millisecond < 0) t.millisecond = 0;
+ if (t.millisecond > 999) t.millisecond = 999;
+ if (t.microsecond < 0) t.microsecond = 0;
+ if (t.microsecond > 999) t.microsecond = 999;
+ if (t.nanosecond < 0) t.nanosecond = 0;
+ if (t.nanosecond > 999) t.nanosecond = 999;
+ }
+ return js_create_plaintime(ctx, &t);
+}
+
+static const JSCFunctionListEntry js_plaintime_proto_funcs[] = {
+ JS_CGETSET_MAGIC_DEF("hour", js_plaintime_get_field, NULL, PLAINTIME_HOUR),
+ JS_CGETSET_MAGIC_DEF("minute", js_plaintime_get_field, NULL, PLAINTIME_MINUTE),
+ JS_CGETSET_MAGIC_DEF("second", js_plaintime_get_field, NULL, PLAINTIME_SECOND),
+ JS_CGETSET_MAGIC_DEF("millisecond", js_plaintime_get_field, NULL, PLAINTIME_MILLISECOND),
+ JS_CGETSET_MAGIC_DEF("microsecond", js_plaintime_get_field, NULL, PLAINTIME_MICROSECOND),
+ JS_CGETSET_MAGIC_DEF("nanosecond", js_plaintime_get_field, NULL, PLAINTIME_NANOSECOND),
+ JS_CFUNC_DEF("equals", 1, js_plaintime_equals),
+ JS_CFUNC_DEF("toString", 0, js_plaintime_toString),
+ JS_CFUNC_DEF("toJSON", 0, js_plaintime_toJSON),
+ JS_CFUNC_DEF("toLocaleString", 0, js_plaintime_toLocaleString),
+ JS_CFUNC_DEF("with", 1, js_plaintime_with),
+ JS_CFUNC_MAGIC_DEF("add", 1, js_plaintime_add_subtract, 1),
+ JS_CFUNC_MAGIC_DEF("subtract", 1, js_plaintime_add_subtract, 0),
+ JS_CFUNC_DEF("round", 1, js_plaintime_round),
+ JS_CFUNC_MAGIC_DEF("until", 1, js_plaintime_difference, 0),
+ JS_CFUNC_MAGIC_DEF("since", 1, js_plaintime_difference, 1),
+ JS_CFUNC_DEF("valueOf", 0, js_plaintime_valueOf),
+ JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Temporal.PlainTime", JS_PROP_CONFIGURABLE),
+};
+
+static const JSCFunctionListEntry js_plaintime_static_funcs[] = {
+ JS_CFUNC_DEF("from", 1, js_plaintime_from),
+ JS_CFUNC_DEF("compare", 2, js_plaintime_compare),
+};
+
+int js_add_plaintime(JSContext *ctx, JSValue temporal_obj)
+{
+ JSValue ctor;
+
+ JS_NewClassID(&js_plaintime_class_id);
+ JS_NewClass(JS_GetRuntime(ctx), js_plaintime_class_id, &js_plaintime_class);
+
+ ctor = JS_NewCConstructor(ctx, (int)js_plaintime_class_id, "PlainTime",
+ (JSCFunction *)js_plaintime_constructor, 0,
+ JS_CFUNC_constructor, 0,
+ JS_UNDEFINED,
+ js_plaintime_static_funcs, countof(js_plaintime_static_funcs),
+ js_plaintime_proto_funcs, countof(js_plaintime_proto_funcs),
+ JS_NEW_CTOR_NO_GLOBAL);
+ if (JS_IsException(ctor))
+ return -1;
+ if (JS_DefinePropertyValueStr(ctx, temporal_obj, "PlainTime", ctor,
+ JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE) < 0)
+ return -1;
+ return 0;
+}
--- /dev/null
+/*
+ * QuickJS Temporal.PlainYearMonth implementation (minimal)
+ */
+
+#include <string.h>
+#include <math.h>
+
+#include "../quickjs.h"
+#include "../cutils.h"
+#include "temporal_private.h"
+
+JSClassID js_plainyearmonth_class_id;
+
+static void js_plainyearmonth_finalizer(JSRuntime *rt, JSValue val)
+{
+ JSPlainYearMonthData *s = JS_GetOpaque(val, js_plainyearmonth_class_id);
+ if (s)
+ js_free_rt(rt, s);
+}
+
+static const JSClassDef js_plainyearmonth_class = {
+ "Temporal.PlainYearMonth",
+ .finalizer = js_plainyearmonth_finalizer,
+};
+
+static JSValue js_create_plainyearmonth(JSContext *ctx, int year, int month, int referenceISODay)
+{
+ return js_create_plainyearmonth_with_calendar(ctx, year, month, referenceISODay, CAL_ISO8601);
+}
+
+JSValue js_create_plainyearmonth_with_calendar(JSContext *ctx, int year, int month, int referenceISODay, CalendarType calendar)
+{
+ JSPlainYearMonthData *s;
+ JSValue obj;
+ s = js_mallocz(ctx, sizeof(*s));
+ if (!s)
+ return JS_EXCEPTION;
+ s->iso_year = year;
+ s->iso_month = month;
+ s->iso_day = referenceISODay;
+ s->calendar = calendar;
+ obj = JS_NewObjectClass(ctx, (int)js_plainyearmonth_class_id);
+ if (JS_IsException(obj)) {
+ js_free(ctx, s);
+ return JS_EXCEPTION;
+ }
+ JS_SetOpaque(obj, s);
+ return obj;
+}
+
+static JSValue ti_create_plainyearmonth_from_fields(JSContext *ctx, TIPreparedFields *fields,
+ int overflow_constrain)
+{
+ int year, month, dummy_day = 1;
+ JSValue obj;
+ JSPlainYearMonthData *s;
+
+ if (ti_resolve_date_from_fields(ctx, fields, overflow_constrain, &year, &month, &dummy_day, 0) < 0)
+ return JS_EXCEPTION;
+
+ /* Constrain/reject leap monthCode if year doesn't have the leap month */
+ if (fields->calendar != CAL_ISO8601 && fields->calendar != CAL_GREGORY &&
+ (fields->present_mask & TI_FIELD_MONTH_CODE) && fields->month_code_has_l) {
+ int result_mc, result_has_l;
+ ti_calendar_month_to_month_code(fields->calendar, year, month, &result_mc, &result_has_l);
+ if (result_has_l != fields->month_code_has_l) {
+ if (!overflow_constrain)
+ return JS_ThrowRangeError(ctx, "invalid PlainYearMonth");
+ /* For Chinese/Dangi, fall back to regular month; Hebrew already resolved correctly */
+ if (fields->calendar == CAL_CHINESE || fields->calendar == CAL_DANGI)
+ month = fields->month_from_code;
+ }
+ }
+
+ if (fields->calendar == CAL_ISO8601 || fields->calendar == CAL_GREGORY) {
+ int is_valid = month >= 1 && month <= 12 &&
+ ((year > -271821 || (year == -271821 && month >= 4)) &&
+ (year < 275760 || (year == 275760 && month <= 9)));
+ if (!is_valid)
+ return JS_ThrowRangeError(ctx, "invalid PlainYearMonth");
+ }
+
+ {
+ int iso_d = 1;
+ /* Convert calendar date to ISO for all non-ISO/non-Gregory calendars */
+ if (fields->calendar != CAL_ISO8601 && fields->calendar != CAL_GREGORY) {
+ int iso_y, iso_m;
+ ti_calendar_date_to_iso(fields->calendar, year, month, 1, &iso_y, &iso_m, &iso_d);
+ year = iso_y;
+ month = iso_m;
+ }
+ {
+ int is_valid = month >= 1 && month <= 12 &&
+ ((year > -271821 || (year == -271821 && month >= 4)) &&
+ (year < 275760 || (year == 275760 && month <= 9)));
+ if (!is_valid)
+ return JS_ThrowRangeError(ctx, "invalid PlainYearMonth");
+ }
+ obj = js_create_plainyearmonth(ctx, year, month, iso_d);
+ }
+ if (!JS_IsException(obj)) {
+ s = JS_GetOpaque(obj, js_plainyearmonth_class_id);
+ if (s) {
+ s->calendar = fields->calendar;
+ }
+ }
+ return obj;
+}
+
+static int pym_is_valid_year_month(int year, int month)
+{
+ return month >= 1 && month <= 12 &&
+ ((year > -271821 || (year == -271821 && month >= 4)) &&
+ (year < 275760 || (year == 275760 && month <= 9)));
+}
+
+static int pym_to_integer_with_truncation(JSContext *ctx, JSValueConst val, int *pres)
+{
+ double d;
+ if (JS_ToFloat64(ctx, &d, val))
+ return -1;
+ if (!isfinite(d)) {
+ JS_ThrowRangeError(ctx, "value must be an integer");
+ return -1;
+ }
+ if (d < INT32_MIN || d > INT32_MAX) {
+ JS_ThrowRangeError(ctx, "value out of range");
+ return -1;
+ }
+ *pres = (int)(d < 0 ? ceil(d) : floor(d));
+ return 0;
+}
+
+/* Temporal.PlainYearMonth constructor */
+static JSValue js_plainyearmonth_constructor(JSContext *ctx, JSValueConst new_target,
+ int argc, JSValueConst *argv)
+{
+ int year, month, day = 1;
+ if (JS_IsUndefined(new_target)) {
+ return JS_ThrowTypeError(ctx, "Temporal.PlainYearMonth constructor cannot be called as a function");
+ }
+ if (pym_to_integer_with_truncation(ctx, argv[0], &year) < 0)
+ return JS_EXCEPTION;
+ if (pym_to_integer_with_truncation(ctx, argv[1], &month) < 0)
+ return JS_EXCEPTION;
+ if (!pym_is_valid_year_month(year, month))
+ return JS_ThrowRangeError(ctx, "invalid PlainYearMonth");
+ if (year < -271821 || (year == -271821 && month < 4))
+ return JS_ThrowRangeError(ctx, "invalid PlainYearMonth");
+ if (year > 275760 || (year == 275760 && month > 9))
+ return JS_ThrowRangeError(ctx, "invalid PlainYearMonth");
+ {
+ CalendarType calendar = CAL_ISO8601;
+ if (argc > 2) {
+ int cal_res = ti_validate_constructor_calendar(ctx, argv[2], &calendar);
+ if (cal_res < 0)
+ return JS_EXCEPTION;
+ }
+ if (argc > 3 && !JS_IsUndefined(argv[3])) {
+ if (pym_to_integer_with_truncation(ctx, argv[3], &day) < 0)
+ return JS_EXCEPTION;
+ }
+ if (day < 1 || day > pd_days_in_month(year, month))
+ return JS_ThrowRangeError(ctx, "invalid PlainYearMonth");
+ if (argc <= 3 || JS_IsUndefined(argv[3]))
+ day = 1;
+ {
+ JSPlainYearMonthData *s = js_mallocz(ctx, sizeof(*s));
+ JSValue obj;
+ if (!s)
+ return JS_EXCEPTION;
+ s->iso_year = year;
+ s->iso_month = month;
+ s->iso_day = day;
+ s->calendar = calendar;
+ obj = js_create_temporal_object(ctx, new_target, js_plainyearmonth_class_id, s);
+ if (JS_IsException(obj)) {
+ js_free(ctx, s);
+ return JS_EXCEPTION;
+ }
+ return obj;
+ }
+ }
+}
+
+/* Getters */
+static JSValue js_plainyearmonth_get_year(JSContext *ctx, JSValueConst this_val)
+{
+ JSPlainYearMonthData *s = JS_GetOpaque2(ctx, this_val, js_plainyearmonth_class_id);
+ int cal_y, cal_m, cal_d;
+ if (!s)
+ return JS_EXCEPTION;
+ pym_get_calendar_date(s, &cal_y, &cal_m, &cal_d);
+ return JS_NewInt32(ctx, cal_y);
+}
+
+static JSValue js_plainyearmonth_get_month(JSContext *ctx, JSValueConst this_val)
+{
+ JSPlainYearMonthData *s = JS_GetOpaque2(ctx, this_val, js_plainyearmonth_class_id);
+ int cal_y, cal_m, cal_d;
+ if (!s)
+ return JS_EXCEPTION;
+ pym_get_calendar_date(s, &cal_y, &cal_m, &cal_d);
+ return JS_NewInt32(ctx, cal_m);
+}
+
+static JSValue js_plainyearmonth_get_monthCode(JSContext *ctx, JSValueConst this_val)
+{
+ JSPlainYearMonthData *s = JS_GetOpaque2(ctx, this_val, js_plainyearmonth_class_id);
+ int cal_y, cal_m, cal_d;
+ if (!s)
+ return JS_EXCEPTION;
+ pym_get_calendar_date(s, &cal_y, &cal_m, &cal_d);
+ return ti_get_month_code(ctx, s->calendar, cal_y, cal_m);
+}
+
+static JSValue js_plainyearmonth_get_calendarId(JSContext *ctx, JSValueConst this_val)
+{
+ JSPlainYearMonthData *s = JS_GetOpaque2(ctx, this_val, js_plainyearmonth_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ return JS_NewString(ctx, ti_calendar_enum_to_string(s->calendar));
+}
+
+static JSValue js_plainyearmonth_get_daysInMonth(JSContext *ctx, JSValueConst this_val)
+{
+ JSPlainYearMonthData *s = JS_GetOpaque2(ctx, this_val, js_plainyearmonth_class_id);
+ int cal_y, cal_m, cal_d;
+ if (!s)
+ return JS_EXCEPTION;
+ pym_get_calendar_date(s, &cal_y, &cal_m, &cal_d);
+ return JS_NewInt32(ctx, ti_calendar_days_in_month(s->calendar, cal_y, cal_m));
+}
+
+static JSValue js_plainyearmonth_get_daysInYear(JSContext *ctx, JSValueConst this_val)
+{
+ JSPlainYearMonthData *s = JS_GetOpaque2(ctx, this_val, js_plainyearmonth_class_id);
+ int cal_y, cal_m, cal_d;
+ if (!s)
+ return JS_EXCEPTION;
+ pym_get_calendar_date(s, &cal_y, &cal_m, &cal_d);
+ return JS_NewInt32(ctx, ti_calendar_days_in_year(s->calendar, cal_y));
+}
+
+static JSValue js_plainyearmonth_get_inLeapYear(JSContext *ctx, JSValueConst this_val)
+{
+ JSPlainYearMonthData *s = JS_GetOpaque2(ctx, this_val, js_plainyearmonth_class_id);
+ int cal_y, cal_m, cal_d;
+ if (!s)
+ return JS_EXCEPTION;
+ pym_get_calendar_date(s, &cal_y, &cal_m, &cal_d);
+ return JS_NewBool(ctx, ti_calendar_is_leap_year(s->calendar, cal_y));
+}
+
+static JSValue js_plainyearmonth_get_monthsInYear(JSContext *ctx, JSValueConst this_val)
+{
+ JSPlainYearMonthData *s = JS_GetOpaque2(ctx, this_val, js_plainyearmonth_class_id);
+ int cal_y, cal_m, cal_d;
+ if (!s)
+ return JS_EXCEPTION;
+ pym_get_calendar_date(s, &cal_y, &cal_m, &cal_d);
+ return JS_NewInt32(ctx, ti_calendar_months_in_year(s->calendar, cal_y));
+ return JS_NewInt32(ctx, 12);
+}
+
+static JSValue js_plainyearmonth_get_referenceISODay(JSContext *ctx, JSValueConst this_val)
+{
+ JSPlainYearMonthData *s = JS_GetOpaque2(ctx, this_val, js_plainyearmonth_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ return JS_NewInt32(ctx, s->iso_day);
+}
+
+static int pym_day_of_week(int year, int month, int day)
+{
+ int a = (14 - month) / 12;
+ int y = year - a;
+ int m = month + 12 * a - 2;
+ int d = (day + y + y / 4 - y / 100 + y / 400 + (31 * m) / 12) % 7;
+ return (d == 0) ? 7 : d;
+}
+
+static void pym_iso_week(int year, int month, int day, int *weekYear, int *weekNumber)
+{
+ int dow = pym_day_of_week(year, month, day);
+ int ordinal = pd_day_of_year(year, month, day);
+ int thursdayOrdinal = ordinal + (4 - dow);
+ int y = year;
+ int daysInY = pd_is_leap_year(y) ? 366 : 365;
+ if (thursdayOrdinal <= 0) {
+ y = year - 1;
+ daysInY = pd_is_leap_year(y) ? 366 : 365;
+ thursdayOrdinal += daysInY;
+ } else if (thursdayOrdinal > daysInY) {
+ thursdayOrdinal -= daysInY;
+ y = year + 1;
+ }
+ *weekYear = y;
+ *weekNumber = (thursdayOrdinal - 1) / 7 + 1;
+}
+
+static JSValue js_plainyearmonth_get_era(JSContext *ctx, JSValueConst this_val)
+{
+ JSPlainYearMonthData *s = JS_GetOpaque2(ctx, this_val, js_plainyearmonth_class_id);
+ int cal_y, cal_m, cal_d;
+ TIEra era;
+ if (!s)
+ return JS_EXCEPTION;
+ if (s->calendar == CAL_ISO8601)
+ return JS_UNDEFINED;
+ int dummy_era_year;
+ pym_get_calendar_date(s, &cal_y, &cal_m, &cal_d);
+ ti_calendar_era_and_era_year(s->calendar, s->iso_year, s->iso_month, s->iso_day,
+ cal_y, &era, &dummy_era_year);
+ if (era != TI_ERA_UNKNOWN)
+ return JS_NewString(ctx, ti_era_to_string(era));
+ return JS_UNDEFINED;
+}
+
+static JSValue js_plainyearmonth_get_eraYear(JSContext *ctx, JSValueConst this_val)
+{
+ JSPlainYearMonthData *s = JS_GetOpaque2(ctx, this_val, js_plainyearmonth_class_id);
+ int cal_y, cal_m, cal_d;
+ TIEra era;
+ int era_year;
+ if (!s)
+ return JS_EXCEPTION;
+ if (s->calendar == CAL_ISO8601)
+ return JS_UNDEFINED;
+ pym_get_calendar_date(s, &cal_y, &cal_m, &cal_d);
+ ti_calendar_era_and_era_year(s->calendar, s->iso_year, s->iso_month, s->iso_day,
+ cal_y, &era, &era_year);
+ if (era != TI_ERA_UNKNOWN)
+ return JS_NewInt32(ctx, era_year);
+ return JS_UNDEFINED;
+}
+
+static JSValue js_plainyearmonth_get_daysInWeek(JSContext *ctx, JSValueConst this_val)
+{
+ JSPlainYearMonthData *s = JS_GetOpaque2(ctx, this_val, js_plainyearmonth_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ return JS_NewInt32(ctx, 7);
+}
+
+static JSValue js_plainyearmonth_get_dayOfWeek(JSContext *ctx, JSValueConst this_val)
+{
+ JSPlainYearMonthData *s = JS_GetOpaque2(ctx, this_val, js_plainyearmonth_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ return JS_NewInt32(ctx, pym_day_of_week(s->iso_year, s->iso_month, s->iso_day));
+}
+
+static JSValue js_plainyearmonth_get_dayOfYear(JSContext *ctx, JSValueConst this_val)
+{
+ JSPlainYearMonthData *s = JS_GetOpaque2(ctx, this_val, js_plainyearmonth_class_id);
+ int cal_y, cal_m, cal_d;
+ if (!s)
+ return JS_EXCEPTION;
+ pym_get_calendar_date(s, &cal_y, &cal_m, &cal_d);
+ return JS_NewInt32(ctx, ti_calendar_day_of_year(s->calendar, cal_y, cal_m, cal_d));
+}
+
+static JSValue js_plainyearmonth_get_weekOfYear(JSContext *ctx, JSValueConst this_val)
+{
+ JSPlainYearMonthData *s = JS_GetOpaque2(ctx, this_val, js_plainyearmonth_class_id);
+ int weekYear, weekNumber;
+ if (!s)
+ return JS_EXCEPTION;
+ if (s->calendar != CAL_ISO8601)
+ return JS_UNDEFINED;
+ pym_iso_week(s->iso_year, s->iso_month, s->iso_day, &weekYear, &weekNumber);
+ return JS_NewInt32(ctx, weekNumber);
+}
+
+static JSValue js_plainyearmonth_get_yearOfWeek(JSContext *ctx, JSValueConst this_val)
+{
+ JSPlainYearMonthData *s = JS_GetOpaque2(ctx, this_val, js_plainyearmonth_class_id);
+ int weekYear, weekNumber;
+ if (!s)
+ return JS_EXCEPTION;
+ if (s->calendar != CAL_ISO8601)
+ return JS_UNDEFINED;
+ pym_iso_week(s->iso_year, s->iso_month, s->iso_day, &weekYear, &weekNumber);
+ return JS_NewInt64(ctx, weekYear);
+}
+
+static JSValue js_plainyearmonth_from(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv);
+
+/* Temporal.PlainYearMonth.prototype.equals */
+static JSValue js_plainyearmonth_equals(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ (void)this_val;
+ (void)argc;
+ JSPlainYearMonthData *s, *other;
+ JSValue other_val;
+ s = JS_GetOpaque2(ctx, this_val, js_plainyearmonth_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ other_val = js_plainyearmonth_from(ctx, JS_UNDEFINED, 1, argv);
+ if (JS_IsException(other_val))
+ return JS_EXCEPTION;
+ other = JS_GetOpaque(other_val, js_plainyearmonth_class_id);
+ if (!other) {
+ JS_FreeValue(ctx, other_val);
+ return JS_NewBool(ctx, 0);
+ }
+ int eq = s->iso_year == other->iso_year && s->iso_month == other->iso_month && s->iso_day == other->iso_day &&
+ s->calendar == other->calendar;
+ JS_FreeValue(ctx, other_val);
+ return JS_NewBool(ctx, eq);
+}
+
+/* Temporal.PlainYearMonth.compare */
+static JSValue js_plainyearmonth_compare(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ (void)argc;
+ (void)this_val;
+ JSPlainYearMonthData *s1, *s2;
+ JSValue v1, v2;
+ int cmp;
+ v1 = js_plainyearmonth_from(ctx, JS_UNDEFINED, 1, argv);
+ if (JS_IsException(v1))
+ return JS_EXCEPTION;
+ v2 = js_plainyearmonth_from(ctx, JS_UNDEFINED, 1, argv + 1);
+ if (JS_IsException(v2)) {
+ JS_FreeValue(ctx, v1);
+ return JS_EXCEPTION;
+ }
+ s1 = JS_GetOpaque(v1, js_plainyearmonth_class_id);
+ s2 = JS_GetOpaque(v2, js_plainyearmonth_class_id);
+ if (!s1 || !s2) {
+ JS_FreeValue(ctx, v1);
+ JS_FreeValue(ctx, v2);
+ return JS_ThrowTypeError(ctx, "compare arguments must be PlainYearMonth objects");
+ }
+ if (s1->iso_year != s2->iso_year)
+ cmp = s1->iso_year < s2->iso_year ? -1 : 1;
+ else if (s1->iso_month != s2->iso_month)
+ cmp = s1->iso_month < s2->iso_month ? -1 : 1;
+ else if (s1->iso_day != s2->iso_day)
+ cmp = s1->iso_day < s2->iso_day ? -1 : 1;
+ else
+ cmp = 0;
+ JS_FreeValue(ctx, v1);
+ JS_FreeValue(ctx, v2);
+ return JS_NewInt32(ctx, cmp);
+}
+
+/* Format PlainYearMonth as ISO string */
+static JSValue js_plainyearmonth_toString(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSPlainYearMonthData *s;
+ char buf[64];
+ int calendarName = 0; /* 0=auto/never, 1=always, 2=critical */
+ if (argc >= 1 && ti_validate_options_object(ctx, argv[0]) < 0)
+ return JS_EXCEPTION;
+ s = JS_GetOpaque2(ctx, this_val, js_plainyearmonth_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ if (argc > 0 && !JS_IsUndefined(argv[0]) && !JS_IsNull(argv[0])) {
+ if (ti_get_calendar_name_option(ctx, argv[0], &calendarName) < 0)
+ return JS_EXCEPTION;
+ }
+ if (s->iso_year < 0)
+ snprintf(buf, sizeof(buf), "-%06d-%02d", -s->iso_year, s->iso_month);
+ else if (s->iso_year >= 10000)
+ snprintf(buf, sizeof(buf), "+%06d-%02d", s->iso_year, s->iso_month);
+ else
+ snprintf(buf, sizeof(buf), "%04d-%02d", s->iso_year, s->iso_month);
+ if (calendarName == 1 || calendarName == 2 || s->calendar != CAL_ISO8601) {
+ char daybuf[16];
+ snprintf(daybuf, sizeof(daybuf), "-%02d", s->iso_day);
+ pstrcat(buf, sizeof(buf), daybuf);
+ }
+ ti_append_calendar_annotation(buf, sizeof(buf), s->calendar, calendarName);
+ return JS_NewString(ctx, buf);
+}
+
+static JSValue js_plainyearmonth_toJSON(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ (void)argc;
+ (void)argv;
+ return js_plainyearmonth_toString(ctx, this_val, 0, NULL);
+}
+
+static JSValue js_plainyearmonth_toLocaleString(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSPlainYearMonthData *s = JS_GetOpaque2(ctx, this_val, js_plainyearmonth_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ return ti_temporal_toLocaleString(ctx, this_val, argc, argv, 1, js_plainyearmonth_toString);
+}
+
+static JSValue js_plainyearmonth_valueOf(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ (void)argc;
+ (void)argv;
+ (void)this_val;
+ return JS_ThrowTypeError(ctx, "cannot compare Temporal.PlainYearMonth with < or >");
+}
+
+/* Temporal.PlainYearMonth.prototype.with */
+static JSValue js_plainyearmonth_with(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSPlainYearMonthData *s;
+ int cal_year, cal_month;
+ int orig_cal_year, orig_cal_month, orig_cal_day;
+ int has_year_prop = 0;
+ int has_month_code = 0;
+ int month_code_val = 0;
+ int has_month_code_l = 0;
+ int has_month_prop = 0;
+ int overflow_constrain = 1;
+ TIPreparedFields fields;
+ s = JS_GetOpaque2(ctx, this_val, js_plainyearmonth_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ pym_get_calendar_date(s, &orig_cal_year, &orig_cal_month, &orig_cal_day);
+ cal_year = orig_cal_year;
+ cal_month = orig_cal_month;
+ if (ti_is_partial_temporal_object(ctx, argv[0]) < 0)
+ return JS_EXCEPTION;
+ if (ti_prepare_calendar_fields(ctx, argv[0],
+ TI_FIELD_MONTH | TI_FIELD_MONTH_CODE |
+ TI_FIELD_YEAR,
+ 0, 1, &fields, s->calendar) < 0)
+ return JS_EXCEPTION;
+ /* Merge fields with existing object in calendar space */
+ if (fields.present_mask & TI_FIELD_MONTH) {
+ has_month_prop = 1;
+ cal_month = fields.month;
+ }
+ if (fields.present_mask & TI_FIELD_MONTH_CODE) {
+ has_month_code = 1;
+ month_code_val = fields.month_from_code;
+ has_month_code_l = fields.month_code_has_l;
+ }
+ if (fields.present_mask & TI_FIELD_YEAR) {
+ has_year_prop = 1;
+ cal_year = (int)fields.year;
+ }
+ /* Validate options type */
+ if (argc >= 2 && ti_validate_options_object(ctx, argv[1]) < 0)
+ return JS_EXCEPTION;
+ if (argc >= 2 && !JS_IsUndefined(argv[1])) {
+ if (ti_get_overflow_option(ctx, argv[1], &overflow_constrain) < 0)
+ return JS_EXCEPTION;
+ }
+ /* era/eraYear processing */
+ if (fields.present_mask & (TI_FIELD_ERA | TI_FIELD_ERA_YEAR)) {
+ if (!ti_calendar_requires_era(s->calendar))
+ return JS_ThrowTypeError(ctx, "era and eraYear are invalid for this calendar");
+ if (!(fields.present_mask & TI_FIELD_ERA) || !(fields.present_mask & TI_FIELD_ERA_YEAR))
+ return JS_ThrowTypeError(ctx, "era and eraYear must both be present");
+ {
+ int era_cal_year;
+ if (fields.era == TI_ERA_UNKNOWN || ti_calendar_era_to_calendar_year(s->calendar, fields.era, (int)fields.era_year, &era_cal_year) < 0)
+ return JS_ThrowRangeError(ctx, "invalid era");
+ if (has_year_prop && cal_year != era_cal_year)
+ return JS_ThrowRangeError(ctx, "year and era/eraYear must agree");
+ cal_year = era_cal_year;
+ }
+ }
+ /* monthCode processing */
+ if (has_month_code) {
+ if (!ti_calendar_validate_month_code(s->calendar, month_code_val, has_month_code_l))
+ return JS_ThrowRangeError(ctx, "monthCode is not valid for this calendar");
+ }
+ if (has_month_code && has_month_prop) {
+ int resolved_month = ti_calendar_month_code_to_month(s->calendar, cal_year, month_code_val, has_month_code_l);
+ if (resolved_month >= 0 && resolved_month != cal_month)
+ return JS_ThrowRangeError(ctx, "month and monthCode must agree");
+ }
+ if (has_month_code) {
+ int resolved_month = ti_calendar_month_code_to_month(s->calendar, cal_year, month_code_val, has_month_code_l);
+ if (resolved_month < 0)
+ return JS_ThrowRangeError(ctx, "monthCode is not valid for this calendar");
+ cal_month = resolved_month;
+ }
+ /* If year changed but month not specified, recompute original monthCode */
+ if (!has_month_code && !has_month_prop && cal_year != orig_cal_year) {
+ int orig_mc, orig_has_l;
+ int result_mc, result_has_l;
+ ti_calendar_month_to_month_code(s->calendar, orig_cal_year, orig_cal_month, &orig_mc, &orig_has_l);
+ int resolved_month = ti_calendar_month_code_to_month(s->calendar, cal_year, orig_mc, orig_has_l);
+ if (resolved_month < 0) {
+ if (!overflow_constrain)
+ return JS_ThrowRangeError(ctx, "invalid PlainYearMonth");
+ resolved_month = ti_calendar_month_code_to_month(s->calendar, cal_year, orig_mc, 0);
+ }
+ cal_month = resolved_month;
+ ti_calendar_month_to_month_code(s->calendar, cal_year, cal_month, &result_mc, &result_has_l);
+ if (!overflow_constrain && (result_mc != orig_mc || result_has_l != orig_has_l))
+ return JS_ThrowRangeError(ctx, "invalid PlainYearMonth");
+ }
+ /* Validate month */
+ {
+ int max_month = ti_calendar_months_in_year(s->calendar, cal_year);
+ if (cal_month < 1 || cal_month > max_month) {
+ if (!overflow_constrain)
+ return JS_ThrowRangeError(ctx, "invalid PlainYearMonth");
+ if (cal_month > max_month)
+ cal_month = max_month;
+ else if (cal_month < 1)
+ cal_month = 1;
+ }
+ }
+ {
+ int iso_y, iso_m, iso_d;
+ ti_calendar_date_to_iso(s->calendar, cal_year, cal_month, 1, &iso_y, &iso_m, &iso_d);
+ return js_create_plainyearmonth_with_calendar(ctx, iso_y, iso_m, iso_d, s->calendar);
+ }
+}
+
+static void pym_balance_month(int *year, int *month, CalendarType cal)
+{
+ int max_month;
+ while (1) {
+ max_month = ti_calendar_months_in_year(cal, *year);
+ if (*month <= max_month && *month >= 1)
+ break;
+ if (*month > max_month) {
+ *month -= max_month;
+ (*year)++;
+ } else {
+ (*year)--;
+ max_month = ti_calendar_months_in_year(cal, *year);
+ *month += max_month;
+ }
+ }
+}
+
+static int pym_duration_has_lower_units(const JSDurationData *d)
+{
+ return d->weeks != 0 || d->days != 0 || d->hours != 0 || d->minutes != 0 ||
+ d->seconds != 0 || d->milliseconds != 0 || d->microseconds.int128_value != 0 || d->nanoseconds.int128_value != 0;
+}
+
+static JSValue js_plainyearmonth_add_subtract(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv, int is_add)
+{
+ JSPlainYearMonthData *s = JS_GetOpaque2(ctx, this_val, js_plainyearmonth_class_id);
+ JSDurationData d = {0};
+ int cal_year, cal_month, cal_day;
+ int overflow_constrain = 1;
+ int sign = is_add ? 1 : -1;
+ if (!s)
+ return JS_EXCEPTION;
+ if (js_to_temporal_duration(ctx, argv[0], &d))
+ return JS_EXCEPTION;
+ if (argc >= 2 && ti_validate_options_object(ctx, argv[1]) < 0)
+ return JS_EXCEPTION;
+ if (argc >= 2 && !JS_IsUndefined(argv[1])) {
+ if (ti_get_overflow_option(ctx, argv[1], &overflow_constrain) < 0)
+ return JS_EXCEPTION;
+ }
+ if (duration_has_mixed_signs(&d))
+ return JS_ThrowRangeError(ctx, "mixed-sign duration not allowed");
+ if (duration_is_out_of_range(&d))
+ return JS_ThrowRangeError(ctx, "duration out of range");
+ if (pym_duration_has_lower_units(&d))
+ return JS_ThrowRangeError(ctx, "duration contains units smaller than months");
+ /* Convert ISO to calendar space for arithmetic */
+ pym_get_calendar_date(s, &cal_year, &cal_month, &cal_day);
+ /* Check that base date is within ISO limits */
+ if (s->iso_year < -271821 || (s->iso_year == -271821 && (s->iso_month < 4 || (s->iso_month == 4 && s->iso_day < 19))))
+ return JS_ThrowRangeError(ctx, "invalid PlainYearMonth");
+ if (s->iso_year > 275760 || (s->iso_year == 275760 && (s->iso_month > 9 || (s->iso_month == 9 && s->iso_day > 13))))
+ return JS_ThrowRangeError(ctx, "invalid PlainYearMonth");
+ {
+ int orig_mc = 0, orig_has_l = 0;
+ ti_calendar_month_to_month_code(s->calendar, cal_year, cal_month, &orig_mc, &orig_has_l);
+ cal_year += sign * (int)d.years;
+ cal_month = ti_calendar_month_code_to_month(s->calendar, cal_year, orig_mc, orig_has_l);
+ if (cal_month < 0) {
+ if (!overflow_constrain)
+ return JS_ThrowRangeError(ctx, "invalid PlainYearMonth");
+ cal_month = ti_calendar_month_code_to_month(s->calendar, cal_year, orig_mc, 0);
+ } else if (!overflow_constrain) {
+ int result_mc, result_has_l;
+ ti_calendar_month_to_month_code(s->calendar, cal_year, cal_month, &result_mc, &result_has_l);
+ if (result_mc != orig_mc || result_has_l != orig_has_l)
+ return JS_ThrowRangeError(ctx, "invalid PlainYearMonth");
+ }
+ }
+ cal_month += sign * (int)d.months;
+ pym_balance_month(&cal_year, &cal_month, s->calendar);
+ {
+ int dim = ti_calendar_days_in_month(s->calendar, cal_year, cal_month);
+ if (cal_day > dim) {
+ if (!overflow_constrain)
+ return JS_ThrowRangeError(ctx, "invalid PlainYearMonth");
+ cal_day = dim;
+ }
+ }
+ {
+ int iso_y, iso_m, iso_d;
+ ti_calendar_date_to_iso(s->calendar, cal_year, cal_month, cal_day, &iso_y, &iso_m, &iso_d);
+ if (iso_y < -271821 || (iso_y == -271821 && iso_m < 4))
+ return JS_ThrowRangeError(ctx, "invalid PlainYearMonth");
+ if (iso_y > 275760 || (iso_y == 275760 && iso_m > 9))
+ return JS_ThrowRangeError(ctx, "invalid PlainYearMonth");
+ return js_create_plainyearmonth_with_calendar(ctx, iso_y, iso_m, iso_d, s->calendar);
+ }
+}
+
+static JSValue js_plainyearmonth_difference(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv, int is_until)
+{
+ JSPlainYearMonthData *s = JS_GetOpaque2(ctx, this_val, js_plainyearmonth_class_id);
+ JSValue other_val;
+ JSPlainYearMonthData *other;
+ int64_t total_months;
+ JSDurationData d = {0};
+ TIUnit largestUnit = TI_UNIT_INVALID;
+ TIUnit smallestUnit = TI_UNIT_INVALID;
+ int64_t roundingIncrement = 1;
+ TIRoundingMode roundingMode = ROUND_TRUNC;
+ if (!s)
+ return JS_EXCEPTION;
+ other_val = js_plainyearmonth_from(ctx, JS_UNDEFINED, 1, argv);
+ if (JS_IsException(other_val))
+ return JS_EXCEPTION;
+ other = JS_GetOpaque(other_val, js_plainyearmonth_class_id);
+ if (!other) {
+ JS_FreeValue(ctx, other_val);
+ return JS_ThrowTypeError(ctx, "invalid PlainYearMonth");
+ }
+ if (s->calendar != other->calendar) {
+ JS_FreeValue(ctx, other_val);
+ return JS_ThrowRangeError(ctx, "calendars must be the same");
+ }
+ int other_iso_year = other->iso_year;
+ int other_iso_month = other->iso_month;
+ int other_iso_day = other->iso_day;
+ JS_FreeValue(ctx, other_val);
+ {
+ int s_cal_y, s_cal_m, s_cal_d;
+ int o_cal_y, o_cal_m, o_cal_d;
+ pym_get_calendar_date(s, &s_cal_y, &s_cal_m, &s_cal_d);
+ ti_iso_to_calendar_date(s->calendar, other_iso_year, other_iso_month, other_iso_day, &o_cal_y, &o_cal_m, &o_cal_d);
+ total_months = (int64_t)((js_int128_t)(o_cal_y - s_cal_y) * 12 + (o_cal_m - s_cal_m));
+ if (total_months != 0) {
+ int64_t days1 = pdt_to_ordinal_days(s->iso_year, s->iso_month, 1);
+ int64_t days2 = pdt_to_ordinal_days(other_iso_year, other_iso_month, 1);
+ int64_t epoch_days1 = days1 - 719162;
+ int64_t epoch_days2 = days2 - 719162;
+ if (epoch_days1 < -100000001LL || epoch_days1 > 100000001LL ||
+ epoch_days2 < -100000001LL || epoch_days2 > 100000001LL)
+ return JS_ThrowRangeError(ctx, "outside representable range");
+ }
+ }
+ if (argc >= 2 && ti_validate_options_object(ctx, argv[1]) < 0)
+ return JS_EXCEPTION;
+ if (argc >= 2 && !JS_IsUndefined(argv[1])) {
+ if (ti_parse_unit_option(ctx, argv[1], "largestUnit", &largestUnit, TI_UNIT_OPT_ALLOW_UNDEFINED | TI_UNIT_OPT_ALLOW_AUTO, TI_UNIT_INVALID) < 0)
+ return JS_EXCEPTION;
+ if (ti_get_rounding_increment_option(ctx, argv[1], &roundingIncrement) < 0)
+ return JS_EXCEPTION;
+ if (ti_get_rounding_mode_option_default(ctx, argv[1], &roundingMode, ROUND_TRUNC) < 0)
+ return JS_EXCEPTION;
+ if (ti_parse_unit_option(ctx, argv[1], "smallestUnit", &smallestUnit, TI_UNIT_OPT_ALLOW_UNDEFINED, TI_UNIT_INVALID) < 0)
+ return JS_EXCEPTION;
+ /* Validate unit restrictions */
+ if (largestUnit != TI_UNIT_INVALID && largestUnit != TI_UNIT_AUTO &&
+ largestUnit != TI_UNIT_YEAR && largestUnit != TI_UNIT_MONTH) {
+ return JS_ThrowRangeError(ctx, "invalid largestUnit");
+ }
+ if (smallestUnit != TI_UNIT_INVALID && smallestUnit != TI_UNIT_YEAR &&
+ smallestUnit != TI_UNIT_MONTH) {
+ return JS_ThrowRangeError(ctx, "invalid smallestUnit");
+ }
+ }
+ if (largestUnit == TI_UNIT_INVALID || largestUnit == TI_UNIT_AUTO)
+ largestUnit = TI_UNIT_YEAR;
+ if (smallestUnit == TI_UNIT_INVALID)
+ smallestUnit = TI_UNIT_MONTH;
+ if (smallestUnit < largestUnit) {
+ return JS_ThrowRangeError(ctx, "invalid unit combination");
+ }
+ {
+ int s_cal_y, s_cal_m, s_cal_d;
+ int o_cal_y, o_cal_m, o_cal_d;
+ int s_mc, s_has_l, o_mc, o_has_l;
+ pym_get_calendar_date(s, &s_cal_y, &s_cal_m, &s_cal_d);
+ ti_iso_to_calendar_date(s->calendar, other_iso_year, other_iso_month, other_iso_day, &o_cal_y, &o_cal_m, &o_cal_d);
+ ti_calendar_month_to_month_code(s->calendar, s_cal_y, s_cal_m, &s_mc, &s_has_l);
+ ti_calendar_month_to_month_code(s->calendar, o_cal_y, o_cal_m, &o_mc, &o_has_l);
+ if ((largestUnit == TI_UNIT_YEAR || largestUnit == TI_UNIT_MONTH) &&
+ (s->calendar == CAL_CHINESE || s->calendar == CAL_DANGI || s->calendar == CAL_HEBREW)) {
+ ti_calendar_date_until_with_monthcode(s->calendar,
+ s_cal_y, s_cal_m, 1, s_mc, 1, s_has_l,
+ o_cal_y, o_cal_m, 1, o_mc, 1, o_has_l,
+ largestUnit,
+ &d.years, &d.months, NULL, NULL);
+ } else if (s->calendar != CAL_ISO8601 && s->calendar != CAL_GREGORY) {
+ ti_calendar_date_until(s->calendar,
+ s_cal_y, s_cal_m, 1,
+ o_cal_y, o_cal_m, 1,
+ largestUnit,
+ &d.years, &d.months, NULL, NULL);
+ } else {
+ ti_iso_calendar_date_until(s->iso_year, s->iso_month, 1,
+ other_iso_year, other_iso_month, 1,
+ largestUnit,
+ &d.years, &d.months, NULL, NULL);
+ }
+ if (smallestUnit != TI_UNIT_MONTH || roundingIncrement != 1) {
+ TIRoundingMode rm = is_until ? roundingMode : ti_negate_rounding_mode(roundingMode);
+ if (ti_round_iso_date_duration(ctx,
+ s->iso_year, s->iso_month, 1,
+ other_iso_year, other_iso_month, 1,
+ 0, 0,
+ d.years, d.months, 0, 0,
+ largestUnit, smallestUnit,
+ roundingIncrement, rm,
+ 1,
+ FALSE,
+ &d.years, &d.months, &d.weeks, &d.days) < 0)
+ return JS_EXCEPTION;
+ }
+ }
+ if (!is_until) {
+ d.years = -d.years;
+ d.months = -d.months;
+ }
+ return js_create_duration(ctx, &d);
+}
+
+static JSValue js_plainyearmonth_toPlainDate(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSPlainYearMonthData *s = JS_GetOpaque2(ctx, this_val, js_plainyearmonth_class_id);
+ int day;
+ int overflow_constrain = 1;
+ if (!s)
+ return JS_EXCEPTION;
+ if (!JS_IsObject(argv[0]))
+ return JS_ThrowTypeError(ctx, "toPlainDate argument must be an object");
+ /* Read options if provided */
+ if (argc >= 2 && ti_validate_options_object(ctx, argv[1]) < 0)
+ return JS_EXCEPTION;
+ if (argc >= 2 && !JS_IsUndefined(argv[1])) {
+ if (ti_get_overflow_option(ctx, argv[1], &overflow_constrain) < 0)
+ return JS_EXCEPTION;
+ }
+ {
+ JSValue v = JS_GetPropertyStr(ctx, argv[0], "day");
+ if (JS_IsUndefined(v)) {
+ return JS_ThrowTypeError(ctx, "missing required property day");
+ }
+ {
+ double d;
+ if (JS_ToFloat64(ctx, &d, v) < 0) {
+ JS_FreeValue(ctx, v);
+ return JS_EXCEPTION;
+ }
+ JS_FreeValue(ctx, v);
+ if (!isfinite(d))
+ return JS_ThrowRangeError(ctx, "invalid day");
+ day = (int)d;
+ }
+ }
+ {
+ int cal_y, cal_m, cal_d;
+ int iso_y, iso_m, iso_d;
+ pym_get_calendar_date(s, &cal_y, &cal_m, &cal_d);
+ {
+ int dim = ti_calendar_days_in_month(s->calendar, cal_y, cal_m);
+ if (day < 1 || day > dim) {
+ if (!overflow_constrain)
+ return JS_ThrowRangeError(ctx, "invalid PlainDate");
+ if (day > dim)
+ day = dim;
+ else if (day < 1)
+ day = 1;
+ }
+ }
+ ti_calendar_date_to_iso(s->calendar, cal_y, cal_m, day, &iso_y, &iso_m, &iso_d);
+ return js_create_plaindate_with_calendar(ctx, iso_y, iso_m, iso_d, s->calendar);
+ }
+}
+
+/* Temporal.PlainYearMonth.from */
+static JSValue js_plainyearmonth_from(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ (void)this_val;
+ JSValue val;
+ int overflow_constrain = 1; /* default is constrain */
+ val = argv[0];
+ if (JS_IsObject(val)) {
+ JSPlainYearMonthData *s = JS_GetOpaque(val, js_plainyearmonth_class_id);
+ if (s) {
+ if (argc >= 2 && ti_validate_options_object(ctx, argv[1]) < 0)
+ return JS_EXCEPTION;
+ if (argc >= 2 && ti_get_overflow_option(ctx, argv[1], &overflow_constrain) < 0)
+ return JS_EXCEPTION;
+ return js_create_plainyearmonth_with_calendar(ctx, s->iso_year, s->iso_month, s->iso_day, s->calendar);
+ }
+ {
+ TIPreparedFields fields;
+ uint32_t field_mask = TI_FIELD_YEAR | TI_FIELD_MONTH | TI_FIELD_MONTH_CODE;
+ CalendarType cal = CAL_ISO8601;
+ if (ti_resolve_calendar_from_object(ctx, val, &cal) < 0)
+ return JS_EXCEPTION;
+ if (ti_prepare_calendar_fields(ctx, val, field_mask, 0, 0, &fields, cal) < 0)
+ return JS_EXCEPTION;
+ if (argc >= 2 && ti_validate_options_object(ctx, argv[1]) < 0)
+ return JS_EXCEPTION;
+ if (argc >= 2 && ti_get_overflow_option(ctx, argv[1], &overflow_constrain) < 0)
+ return JS_EXCEPTION;
+ return ti_create_plainyearmonth_from_fields(ctx, &fields, overflow_constrain);
+ }
+ }
+ if (JS_IsString(val)) {
+ const char *str = JS_ToCString(ctx, val);
+ TISODateTimeParseResult r;
+ if (!str)
+ return JS_EXCEPTION;
+ if (ti_parse_iso_datetime_string(ctx, str, &r, TI_PARSE_DEFAULT) < 0) {
+ JS_FreeCString(ctx, str);
+ return JS_ThrowRangeError(ctx, "invalid PlainYearMonth string");
+ }
+ JS_FreeCString(ctx, str);
+ if (!r.has_date && !r.has_yearmonth)
+ return JS_ThrowRangeError(ctx, "invalid PlainYearMonth string");
+ if (r.has_utc)
+ return JS_ThrowRangeError(ctx, "invalid PlainYearMonth string");
+ if (r.has_tz_offset && !r.has_time)
+ return JS_ThrowRangeError(ctx, "invalid PlainYearMonth string");
+ {
+ CalendarType cal = r.has_calendar ? r.calendar : CAL_ISO8601;
+ if (cal == CAL_UNKNOWN)
+ return JS_ThrowRangeError(ctx, "invalid calendar ID");
+ if (!pym_is_valid_year_month(r.year, r.month))
+ return JS_ThrowRangeError(ctx, "invalid PlainYearMonth");
+ /* YYYY-MM format is only valid with iso8601 calendar */
+ if (!r.has_date && cal != CAL_ISO8601)
+ return JS_ThrowRangeError(ctx, "invalid PlainYearMonth string");
+ /* Validate options AFTER string parsing */
+ if (argc >= 2 && ti_validate_options_object(ctx, argv[1]) < 0)
+ return JS_EXCEPTION;
+ if (argc >= 2 && ti_get_overflow_option(ctx, argv[1], &overflow_constrain) < 0)
+ return JS_EXCEPTION;
+ if (cal == CAL_ISO8601 || cal == CAL_GREGORY) {
+ return js_create_plainyearmonth_with_calendar(ctx, r.year, r.month, 1, cal);
+ } else {
+ /* For non-ISO calendars, perform ISO->calendar->ISO with day=1
+ to determine referenceISODay */
+ int cal_y, cal_m, cal_d, iso_y, iso_m, iso_d;
+ ti_iso_to_calendar_date(cal, r.year, r.month, r.has_date ? r.day : 1, &cal_y, &cal_m, &cal_d);
+ /* Override day to 1 for year-month */
+ cal_d = 1;
+ if (ti_calendar_date_to_iso(cal, cal_y, cal_m, cal_d, &iso_y, &iso_m, &iso_d) < 0)
+ return JS_ThrowRangeError(ctx, "invalid PlainYearMonth");
+ return js_create_plainyearmonth_with_calendar(ctx, iso_y, iso_m, iso_d, cal);
+ }
+ }
+ }
+ return JS_ThrowTypeError(ctx, "unsupported argument type for Temporal.PlainYearMonth.from");
+}
+
+static const JSCFunctionListEntry js_plainyearmonth_proto_funcs[] = {
+ JS_CGETSET_DEF("year", js_plainyearmonth_get_year, NULL),
+ JS_CGETSET_DEF("month", js_plainyearmonth_get_month, NULL),
+ JS_CGETSET_DEF("monthCode", js_plainyearmonth_get_monthCode, NULL),
+ JS_CGETSET_DEF("calendarId", js_plainyearmonth_get_calendarId, NULL),
+ JS_CGETSET_DEF("daysInMonth", js_plainyearmonth_get_daysInMonth, NULL),
+ JS_CGETSET_DEF("daysInYear", js_plainyearmonth_get_daysInYear, NULL),
+ JS_CGETSET_DEF("inLeapYear", js_plainyearmonth_get_inLeapYear, NULL),
+ JS_CGETSET_DEF("monthsInYear", js_plainyearmonth_get_monthsInYear, NULL),
+ JS_CGETSET_DEF("referenceISODay", js_plainyearmonth_get_referenceISODay, NULL),
+ JS_CGETSET_DEF("era", js_plainyearmonth_get_era, NULL),
+ JS_CGETSET_DEF("eraYear", js_plainyearmonth_get_eraYear, NULL),
+ JS_CGETSET_DEF("daysInWeek", js_plainyearmonth_get_daysInWeek, NULL),
+ JS_CGETSET_DEF("dayOfWeek", js_plainyearmonth_get_dayOfWeek, NULL),
+ JS_CGETSET_DEF("dayOfYear", js_plainyearmonth_get_dayOfYear, NULL),
+ JS_CGETSET_DEF("weekOfYear", js_plainyearmonth_get_weekOfYear, NULL),
+ JS_CGETSET_DEF("yearOfWeek", js_plainyearmonth_get_yearOfWeek, NULL),
+ JS_CFUNC_MAGIC_DEF("add", 1, js_plainyearmonth_add_subtract, 1),
+ JS_CFUNC_MAGIC_DEF("subtract", 1, js_plainyearmonth_add_subtract, 0),
+ JS_CFUNC_MAGIC_DEF("until", 1, js_plainyearmonth_difference, 1),
+ JS_CFUNC_MAGIC_DEF("since", 1, js_plainyearmonth_difference, 0),
+ JS_CFUNC_DEF("equals", 1, js_plainyearmonth_equals),
+ JS_CFUNC_DEF("toString", 0, js_plainyearmonth_toString),
+ JS_CFUNC_DEF("toJSON", 0, js_plainyearmonth_toJSON),
+ JS_CFUNC_DEF("toLocaleString", 0, js_plainyearmonth_toLocaleString),
+ JS_CFUNC_DEF("toPlainDate", 1, js_plainyearmonth_toPlainDate),
+ JS_CFUNC_DEF("with", 1, js_plainyearmonth_with),
+ JS_CFUNC_DEF("valueOf", 0, js_plainyearmonth_valueOf),
+ JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Temporal.PlainYearMonth", JS_PROP_CONFIGURABLE),
+};
+
+static const JSCFunctionListEntry js_plainyearmonth_static_funcs[] = {
+ JS_CFUNC_DEF("from", 1, js_plainyearmonth_from),
+ JS_CFUNC_DEF("compare", 2, js_plainyearmonth_compare),
+};
+
+int js_add_plainyearmonth(JSContext *ctx, JSValue temporal_obj)
+{
+ JSValue ctor;
+
+ JS_NewClassID(&js_plainyearmonth_class_id);
+ JS_NewClass(JS_GetRuntime(ctx), js_plainyearmonth_class_id, &js_plainyearmonth_class);
+
+ ctor = JS_NewCConstructor(ctx, (int)js_plainyearmonth_class_id, "PlainYearMonth",
+ (JSCFunction *)js_plainyearmonth_constructor, 2,
+ JS_CFUNC_constructor, 0,
+ JS_UNDEFINED,
+ js_plainyearmonth_static_funcs, countof(js_plainyearmonth_static_funcs),
+ js_plainyearmonth_proto_funcs, countof(js_plainyearmonth_proto_funcs),
+ JS_NEW_CTOR_NO_GLOBAL);
+ if (JS_IsException(ctor))
+ return -1;
+ if (JS_DefinePropertyValueStr(ctx, temporal_obj, "PlainYearMonth", ctor,
+ JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE) < 0)
+ return -1;
+ return 0;
+}
--- /dev/null
+/*
+ * QuickJS Temporal implementation
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <math.h>
+#include <ctype.h>
+#include <limits.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <time.h>
+
+#include "../quickjs.h"
+#include "../cutils.h"
+#include "temporal_private.h"
+#include "../intl/intl_private.h"
+
+static int ti_is_valid_plain_offset_string(const char *str);
+
+/* Parse a Temporal time zone string and return the fixed offset in nanoseconds.
+ Returns 0 on success, -1 on RangeError, -2 on TypeError.
+ Handles: "UTC", "±HH:MM", ISO date-time strings with Z/offset/bracket annotation.
+ This is a partial implementation of ToTemporalTimeZone for fixed-offset time zones. */
+int ti_parse_temporal_timezone_string(const char *str, int64_t *offset_ns)
+{
+ int has_bracket = 0;
+ const char *bracket_open, *bracket_close;
+ size_t len;
+
+ if (!str || !str[0])
+ return -1;
+ len = strlen(str);
+
+ /* Look for bracket annotation [name] at the end */
+ bracket_open = strchr(str, '[');
+ if (bracket_open) {
+ bracket_close = strchr(bracket_open, ']');
+ if (!bracket_close || bracket_close[1] != '\0')
+ return -1;
+ has_bracket = 1;
+ /* Extract bracket content */
+ if (bracket_close == bracket_open + 1)
+ return -1;
+ int inner_len = (int)(bracket_close - bracket_open - 1);
+ if (inner_len == 3 && (bracket_open[1] == 'U' || bracket_open[1] == 'u') &&
+ (bracket_open[2] == 'T' || bracket_open[2] == 't') &&
+ (bracket_open[3] == 'C' || bracket_open[3] == 'c')) {
+ *offset_ns = 0;
+ } else if (inner_len == 6 && (bracket_open[1] == '+' || bracket_open[1] == '-')) {
+ /* Offset in brackets like [+01:46] */
+ int sign = (bracket_open[1] == '+') ? 1 : -1;
+ int h1 = bracket_open[2] - '0';
+ int h2 = bracket_open[3] - '0';
+ if (bracket_open[4] != ':' || h1 < 0 || h1 > 9 || h2 < 0 || h2 > 9)
+ return -1;
+ int m1 = bracket_open[5] - '0';
+ int m2 = bracket_open[6] - '0';
+ if (m1 < 0 || m1 > 5 || m2 < 0 || m2 > 9)
+ return -1;
+ int hours = h1 * 10 + h2;
+ int mins = m1 * 10 + m2;
+ if (hours > 23 || mins > 59)
+ return -1;
+ *offset_ns = sign * ((int64_t)hours * 3600 + mins * 60) * 1000000000LL;
+ } else {
+ /* Accept IANA-like names in brackets: letters, slashes, underscores, hyphens, plus */
+ int i;
+ int valid_iana = 1;
+ for (i = 1; i <= inner_len; i++) {
+ char c = bracket_open[i];
+ if (!((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') ||
+ (c >= '0' && c <= '9') || c == '/' || c == '_' || c == '-' || c == '+')) {
+ valid_iana = 0;
+ break;
+ }
+ }
+ if (valid_iana && inner_len > 0) {
+ *offset_ns = 0;
+ } else {
+ return -1;
+ }
+ }
+ }
+
+ /* If there's a bracket, validate the prefix is a valid date-time or time string */
+ if (has_bracket) {
+ int prefix_len = (int)(bracket_open - str);
+ if (prefix_len == 0)
+ return -1;
+ if (prefix_len >= 7 && !memcmp(str, "-000000", 7))
+ return -1;
+ if (prefix_len > 0 && str[prefix_len - 1] == 'Z') {
+ /* OK */
+ } else {
+ if (prefix_len >= 6 && (str[prefix_len - 6] == '+' || str[prefix_len - 6] == '-')
+ && str[prefix_len - 3] == ':') {
+ /* OK - regular offset */
+ } else if (prefix_len == 8 && str[2] == ':' && str[5] == ':') {
+ /* Time-only like HH:MM:SS */
+ /* OK */
+ } else if (memchr(str, 'T', (size_t)prefix_len) != NULL) {
+ /* Date-time prefix */
+ /* OK */
+ } else {
+ return -1;
+ }
+ }
+ return 0;
+ }
+
+ /* No bracket - plain identifiers */
+ if (len == 3 && (str[0] == 'U' || str[0] == 'u') &&
+ (str[1] == 'T' || str[1] == 't') &&
+ (str[2] == 'C' || str[2] == 'c')) {
+ *offset_ns = 0;
+ return 0;
+ }
+
+ /* Plain offset string ±HH */
+ if (len == 3 && (str[0] == '+' || str[0] == '-')) {
+ int sign = (str[0] == '+') ? 1 : -1;
+ int h1 = str[1] - '0';
+ int h2 = str[2] - '0';
+ if (h1 < 0 || h1 > 9 || h2 < 0 || h2 > 9)
+ return -1;
+ int hours = h1 * 10 + h2;
+ if (hours > 23)
+ return -1;
+ *offset_ns = sign * (int64_t)hours * 3600 * 1000000000LL;
+ return 0;
+ }
+
+ /* Plain offset string ±HH:MM */
+ if (len == 6 && (str[0] == '+' || str[0] == '-')) {
+ int sign = (str[0] == '+') ? 1 : -1;
+ int h1 = str[1] - '0';
+ int h2 = str[2] - '0';
+ int m1 = str[4] - '0';
+ int m2 = str[5] - '0';
+ if (str[3] != ':' || h1 < 0 || h1 > 9 || h2 < 0 || h2 > 9 ||
+ m1 < 0 || m1 > 5 || m2 < 0 || m2 > 9)
+ return -1;
+ int hours = h1 * 10 + h2;
+ int mins = m1 * 10 + m2;
+ if (hours > 23 || mins > 59)
+ return -1;
+ *offset_ns = sign * ((int64_t)hours * 3600 + mins * 60) * 1000000000LL;
+ return 0;
+ }
+
+ /* Plain offset string ±HHMM */
+ if (len == 5 && (str[0] == '+' || str[0] == '-')) {
+ int sign = (str[0] == '+') ? 1 : -1;
+ int h1 = str[1] - '0';
+ int h2 = str[2] - '0';
+ int m1 = str[3] - '0';
+ int m2 = str[4] - '0';
+ if (h1 < 0 || h1 > 9 || h2 < 0 || h2 > 9 ||
+ m1 < 0 || m1 > 5 || m2 < 0 || m2 > 9)
+ return -1;
+ int hours = h1 * 10 + h2;
+ int mins = m1 * 10 + m2;
+ if (hours > 23 || mins > 59)
+ return -1;
+ *offset_ns = sign * ((int64_t)hours * 3600 + mins * 60) * 1000000000LL;
+ return 0;
+ }
+
+ /* ISO date-time string ending with Z */
+ if (len > 1 && str[len - 1] == 'Z') {
+ if (len >= 7 && !memcmp(str, "-000000", 7))
+ return -1;
+ *offset_ns = 0;
+ return 0;
+ }
+
+ /* ISO date-time string with ±HHMM or ±HH:MM offset at end */
+ if (len >= 5) {
+ const char *offset_start = NULL;
+ int offset_len = 0;
+ int i;
+ for (i = (int)(len - 6); i >= 0; i--) {
+ if ((str[i] == '+' || str[i] == '-') && str[i + 3] == ':') {
+ offset_start = str + i;
+ offset_len = 6;
+ break;
+ }
+ }
+ if (!offset_start) {
+ for (i = (int)(len - 5); i >= 0; i--) {
+ if ((str[i] == '+' || str[i] == '-') &&
+ str[i + 1] >= '0' && str[i + 1] <= '9' &&
+ str[i + 2] >= '0' && str[i + 2] <= '9' &&
+ str[i + 3] >= '0' && str[i + 3] <= '5' &&
+ str[i + 4] >= '0' && str[i + 4] <= '9') {
+ offset_start = str + i;
+ offset_len = 5;
+ break;
+ }
+ }
+ }
+ if (offset_start) {
+ int sign = (offset_start[0] == '+') ? 1 : -1;
+ int h1 = offset_start[1] - '0';
+ int h2 = offset_start[2] - '0';
+ int m1, m2;
+ if (offset_len == 6) {
+ m1 = offset_start[4] - '0';
+ m2 = offset_start[5] - '0';
+ } else {
+ m1 = offset_start[3] - '0';
+ m2 = offset_start[4] - '0';
+ }
+ if (h1 >= 0 && h1 <= 9 && h2 >= 0 && h2 <= 9 &&
+ m1 >= 0 && m1 <= 5 && m2 >= 0 && m2 <= 9) {
+ int hours = h1 * 10 + h2;
+ int mins = m1 * 10 + m2;
+ if (hours <= 23 && mins <= 59) {
+ if ((int)len > (int)(offset_start - str) + offset_len && offset_start[offset_len] == ':')
+ return -1;
+ if ((int)len > (int)(offset_start - str) + offset_len && offset_start[offset_len] == '.')
+ return -1;
+ if (len >= 7 && !memcmp(str, "-000000", 7))
+ return -1;
+ *offset_ns = sign * ((int64_t)hours * 3600 + mins * 60) * 1000000000LL;
+ return 0;
+ }
+ }
+ }
+ }
+
+ /* Plain IANA time zone name */
+ {
+ int valid_iana = 1;
+ size_t i;
+ for (i = 0; i < len; i++) {
+ char c = str[i];
+ if (!((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') ||
+ (c >= '0' && c <= '9') || c == '/' || c == '_' || c == '-' || c == '+')) {
+ valid_iana = 0;
+ break;
+ }
+ }
+ if (valid_iana && len > 0) {
+ *offset_ns = 0;
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+/* Return the default time zone identifier from the TZ environment variable.
+ Returns a newly allocated string, or NULL if not set or empty. */
+void ti_get_default_timezone(char *buf, size_t buf_size)
+{
+ const char *tz = getenv("TZ");
+ if (tz && tz[0]) {
+ pstrcpy(buf, buf_size, tz);
+ return;
+ }
+ {
+ char linkbuf[512];
+ ssize_t len = readlink("/etc/localtime", linkbuf, sizeof(linkbuf) - 1);
+ if (len > 0) {
+ const char *p;
+ linkbuf[len] = '\0';
+ p = strstr(linkbuf, "/zoneinfo/");
+ if (p) {
+ pstrcpy(buf, buf_size, p + 10);
+ return;
+ }
+ }
+ }
+ {
+ FILE *f = fopen("/etc/timezone", "r");
+ if (f) {
+ char line[256];
+ if (fgets(line, sizeof(line), f)) {
+ size_t len = strlen(line);
+ if (len > 0 && line[len - 1] == '\n')
+ line[len - 1] = '\0';
+ fclose(f);
+ if (line[0]) {
+ pstrcpy(buf, buf_size, line);
+ return;
+ }
+ }
+ fclose(f);
+ }
+ }
+ /* fallback: compute offset from localtime */
+ {
+ time_t t = time(NULL);
+ int offset_min = 0;
+#if defined(_WIN32)
+ {
+ struct tm *tm;
+ time_t gm_ti, loc_ti;
+
+ tm = gmtime(&t);
+ if (tm) {
+ gm_ti = mktime(tm);
+ tm = localtime(&t);
+ if (tm) {
+ loc_ti = mktime(tm);
+ offset_min = (int)((gm_ti - loc_ti) / 60);
+ }
+ }
+ }
+#else
+ {
+ struct tm tm;
+ if (localtime_r(&t, &tm))
+ offset_min = (int)(-tm.tm_gmtoff / 60);
+ }
+#endif
+ if (offset_min % 60 == 0) {
+ snprintf(buf, buf_size, "Etc/GMT%+d", offset_min / 60);
+ } else {
+ int abs_min = abs(offset_min);
+ char sign = offset_min <= 0 ? '+' : '-';
+ snprintf(buf, buf_size, "%c%02d:%02d", sign, abs_min / 60, abs_min % 60);
+ }
+ return;
+ }
+}
+
+/* Canonicalize a calendar identifier per spec CanonicalizeCalendar.
+ Returns 0 on success with calendar type in *out, -1 on RangeError, -2 on TypeError. */
+static int ti_canonicalize_calendar(JSContext *ctx, JSValue val, CalendarType *out)
+{
+ const char *str;
+ size_t len, i;
+ char *lower;
+
+ if (!JS_IsString(val))
+ return -2;
+
+ str = JS_ToCStringLen(ctx, &len, val);
+ if (!str)
+ return -2;
+
+ if (len == 0) {
+ JS_FreeCString(ctx, str);
+ return -1;
+ }
+
+ lower = js_malloc(ctx, len + 1);
+ if (!lower) {
+ JS_FreeCString(ctx, str);
+ return -2;
+ }
+
+ for (i = 0; i < len; i++) {
+ char c = str[i];
+ lower[i] = (c >= 'A' && c <= 'Z') ? (c + ('a' - 'A')) : c;
+ }
+ lower[len] = '\0';
+
+ if (!strcmp(lower, "ethiopic-amete-alem"))
+ *out = CAL_ETHIOAA;
+ else if (!strcmp(lower, "islamicc"))
+ *out = CAL_ISLAMIC_CIVIL;
+ else
+ *out = ti_calendar_string_to_enum(lower);
+
+ js_free(ctx, lower);
+ JS_FreeCString(ctx, str);
+
+ if (*out == CAL_UNKNOWN)
+ return -1;
+ return 0;
+}
+
+/* Parse a calendar string per ParseTemporalCalendarString / ToTemporalCalendarIdentifier.
+ Returns 0 on success with calendar type in *out, -1 on RangeError, -2 on TypeError. */
+static int ti_parse_temporal_calendar_string(JSContext *ctx, JSValue val, CalendarType *out)
+{
+ const char *str;
+ size_t len, i;
+ const char *cal = NULL;
+ size_t cal_len = 0;
+ int looks_like_iso = 0;
+ int has_annotation = 0;
+
+ if (!JS_IsString(val))
+ return -2;
+
+ str = JS_ToCStringLen(ctx, &len, val);
+ if (!str)
+ return -2;
+
+ if (len == 0) {
+ JS_FreeCString(ctx, str);
+ return -1;
+ }
+
+ if (ti_is_minus_zero_year(str)) {
+ JS_FreeCString(ctx, str);
+ return -1;
+ }
+
+ {
+ char first = str[0];
+ if (isdigit((unsigned char)first) || first == '+' || first == '-') {
+ looks_like_iso = 1;
+ }
+ }
+
+ for (i = 0; i < len; i++) {
+ char c = str[i];
+ if (c == '-' || c == ':' || c == 'T' || c == 't' ||
+ c == '.' || c == ',' || (c == '+' && i == 0)) {
+ looks_like_iso = 1;
+ }
+ if (c == '[') {
+ const char *end = strchr(str + i, ']');
+ if (!end) {
+ JS_FreeCString(ctx, str);
+ return -1;
+ }
+ has_annotation = 1;
+ {
+ const char *content = str + i + 1;
+ size_t content_len = (size_t)(end - content);
+ int j;
+ int is_bang = 0;
+ if (content_len > 0 && content[0] == '!') {
+ is_bang = 1;
+ content++;
+ content_len--;
+ }
+ if (content_len >= 5 && !memcmp(content, "u-ca=", 5)) {
+ cal = content + 5;
+ cal_len = content_len - 5;
+ } else if (looks_like_iso) {
+ if (is_bang) {
+ JS_FreeCString(ctx, str);
+ return -1;
+ }
+ } else {
+ if (content_len == 0) {
+ JS_FreeCString(ctx, str);
+ return -1;
+ }
+ {
+ char k0 = content[0];
+ if (!(islower((unsigned char)k0) || k0 == '_')) {
+ JS_FreeCString(ctx, str);
+ return -1;
+ }
+ }
+ for (j = 0; j < (int)content_len; j++) {
+ char kc = content[j];
+ if (kc == '=') {
+ break;
+ }
+ if (!(islower((unsigned char)kc) || isdigit((unsigned char)kc) || kc == '_' || kc == '-')) {
+ JS_FreeCString(ctx, str);
+ return -1;
+ }
+ }
+ }
+ }
+ i = (size_t)(end - str);
+ }
+ }
+
+ if (!looks_like_iso) {
+ if (has_annotation) {
+ JS_FreeCString(ctx, str);
+ return -1;
+ }
+ cal = str;
+ cal_len = len;
+ } else {
+ if (cal == NULL) {
+ JS_FreeCString(ctx, str);
+ *out = CAL_ISO8601;
+ return 0;
+ }
+ }
+
+ if (cal == NULL || cal_len == 0) {
+ JS_FreeCString(ctx, str);
+ return -1;
+ }
+
+ {
+ char *lower = js_malloc(ctx, cal_len + 1);
+ if (!lower) {
+ JS_FreeCString(ctx, str);
+ return -1;
+ }
+ for (i = 0; i < cal_len; i++) {
+ char c = cal[i];
+ lower[i] = (c >= 'A' && c <= 'Z') ? (c + ('a' - 'A')) : c;
+ }
+ lower[cal_len] = '\0';
+
+ if (!strcmp(lower, "ethiopic-amete-alem"))
+ *out = CAL_ETHIOAA;
+ else if (!strcmp(lower, "islamicc"))
+ *out = CAL_ISLAMIC_CIVIL;
+ else
+ *out = ti_calendar_string_to_enum(lower);
+
+ js_free(ctx, lower);
+ }
+
+ JS_FreeCString(ctx, str);
+ if (*out == CAL_UNKNOWN)
+ return -1;
+ return 0;
+}
+
+/* Shared ISO date/time string parser for Temporal.
+ Parses date, time, timezone offset/Z, and bracket annotations.
+ Returns 0 on success, -1 on error (RangeError). */
+int ti_parse_iso_datetime_string(JSContext *ctx, const char *str, TISODateTimeParseResult *out, int flags)
+{
+ const char *p = str;
+ int has_sign = 0;
+ int sign = 1;
+ int i;
+
+ memset(out, 0, sizeof(*out));
+
+ /* Reject non-ASCII */
+ for (i = 0; str[i]; i++) {
+ if ((unsigned char)str[i] > 127)
+ goto error;
+ }
+
+ /* Reject empty string */
+ if (*p == '\0')
+ goto error;
+
+ /* Check for sign */
+ if (*p == '+' || *p == '-') {
+ has_sign = 1;
+ sign = (*p == '-') ? -1 : 1;
+ p++;
+ }
+
+ /* Try to parse date part */
+ {
+ const char *date_start = p;
+ int year_len = 0;
+ int month_len = 0;
+ int day_len = 0;
+
+ if ((flags & TI_PARSE_PLAIN_TIME)) {
+ const char *q = str;
+ while (*q && *q != '[') {
+ if (*q == 'T' || *q == 't' || *q == ' ')
+ break;
+ q++;
+ }
+ if (!*q || *q == '[')
+ goto no_date;
+ }
+
+ if ((flags & TI_PARSE_PLAIN_MONTHDAY) && !has_sign) {
+ /* MM-DD or MMDD */
+ if (p[0] >= '0' && p[0] <= '9' && p[1] >= '0' && p[1] <= '9' &&
+ p[2] == '-' &&
+ p[3] >= '0' && p[3] <= '9' && p[4] >= '0' && p[4] <= '9') {
+ const char *q = p + 5;
+ if (*q == '\0' || *q == 'T' || *q == 't' || *q == '[') {
+ out->has_monthday = 1;
+ out->month = (p[0]-'0')*10 + (p[1]-'0');
+ out->day = (p[3]-'0')*10 + (p[4]-'0');
+ p = q;
+ goto no_date;
+ }
+ } else if (p[0] >= '0' && p[0] <= '9' && p[1] >= '0' && p[1] <= '9' &&
+ p[2] >= '0' && p[2] <= '9' && p[3] >= '0' && p[3] <= '9') {
+ const char *q = p + 4;
+ if (*q == '\0' || *q == 'T' || *q == 't' || *q == '[') {
+ out->has_monthday = 1;
+ out->month = (p[0]-'0')*10 + (p[1]-'0');
+ out->day = (p[2]-'0')*10 + (p[3]-'0');
+ p = q;
+ goto no_date;
+ }
+ }
+ }
+
+ if ((flags & TI_PARSE_PLAIN_MONTHDAY) && has_sign && sign == -1 && p[0] == '-') {
+ /* --MM-DD or --MMDD */
+ const char *q = p + 1;
+ if (q[0] >= '0' && q[0] <= '9' && q[1] >= '0' && q[1] <= '9' &&
+ q[2] == '-' &&
+ q[3] >= '0' && q[3] <= '9' && q[4] >= '0' && q[4] <= '9') {
+ const char *r = q + 5;
+ if (*r == '\0' || *r == 'T' || *r == 't' || *r == '[') {
+ out->has_monthday = 1;
+ out->month = (q[0]-'0')*10 + (q[1]-'0');
+ out->day = (q[3]-'0')*10 + (q[4]-'0');
+ p = r;
+ goto no_date;
+ }
+ } else if (q[0] >= '0' && q[0] <= '9' && q[1] >= '0' && q[1] <= '9' &&
+ q[2] >= '0' && q[2] <= '9' && q[3] >= '0' && q[3] <= '9') {
+ const char *r = q + 4;
+ if (*r == '\0' || *r == 'T' || *r == 't' || *r == '[') {
+ out->has_monthday = 1;
+ out->month = (q[0]-'0')*10 + (q[1]-'0');
+ out->day = (q[2]-'0')*10 + (q[3]-'0');
+ p = r;
+ goto no_date;
+ }
+ }
+ /* Not a valid --MM-DD, rewind and continue as normal date parsing */
+ p = date_start - 1;
+ has_sign = 0;
+ }
+
+ /* Count leading digits */
+ while (*p >= '0' && *p <= '9') {
+ year_len++;
+ p++;
+ }
+
+ if (year_len == 4 && !has_sign) {
+ /* Four-digit year without sign */
+ if (*p == '-') {
+ p++;
+ /* Count month digits */
+ while (*p >= '0' && *p <= '9') {
+ month_len++;
+ p++;
+ }
+ if (month_len == 2) {
+ if (*p == '-') {
+ p++;
+ /* Count day digits */
+ while (*p >= '0' && *p <= '9') {
+ day_len++;
+ p++;
+ }
+ if (day_len == 2) {
+ /* YYYY-MM-DD */
+ out->has_date = 1;
+ out->year = ((date_start[0]-'0')*1000 + (date_start[1]-'0')*100 +
+ (date_start[2]-'0')*10 + (date_start[3]-'0'));
+ out->month = ((date_start[5]-'0')*10 + (date_start[6]-'0'));
+ out->day = ((date_start[8]-'0')*10 + (date_start[9]-'0'));
+ } else {
+ goto error;
+ }
+ } else if (*p == '\0' || *p == 'T' || *p == 't' || *p == ' ' || *p == '[') {
+ /* YYYY-MM - yearmonth only, no day */
+ /* Don't consume, rewind to after year-month part */
+ p = date_start + 4 + 1 + 2; /* after YYYY-MM */
+ out->has_yearmonth = 1;
+ out->year = ((date_start[0]-'0')*1000 + (date_start[1]-'0')*100 +
+ (date_start[2]-'0')*10 + (date_start[3]-'0'));
+ out->month = ((date_start[5]-'0')*10 + (date_start[6]-'0'));
+ out->day = 1; /* default */
+ } else {
+ goto error;
+ }
+ } else {
+ goto error;
+ }
+ } else if (year_len == 4) {
+ /* No separator after 4-digit year: check for compact YYYYMMDD */
+ if (*p == '\0' || *p == 'T' || *p == 't' || *p == ' ') {
+ /* Only 4 digits - not enough for compact date */
+ /* This could be just a year, not a date */
+ p = date_start;
+ } else {
+ /* Trailing junk after year */
+ p = date_start;
+ }
+ }
+ } else if (year_len == 6 && has_sign) {
+ /* Signed extended year: ±YYYYYY */
+ if (*p == '-') {
+ p++;
+ while (*p >= '0' && *p <= '9') {
+ month_len++;
+ p++;
+ }
+ if (month_len == 2) {
+ if (*p == '-') {
+ p++;
+ while (*p >= '0' && *p <= '9') {
+ day_len++;
+ p++;
+ }
+ if (day_len == 2) {
+ out->has_date = 1;
+ out->year = sign * ((date_start[0]-'0')*100000 + (date_start[1]-'0')*10000 +
+ (date_start[2]-'0')*1000 + (date_start[3]-'0')*100 +
+ (date_start[4]-'0')*10 + (date_start[5]-'0'));
+ if (out->year == 0 && sign < 0)
+ goto error;
+ out->month = (date_start[7]-'0')*10 + (date_start[8]-'0');
+ out->day = (date_start[10]-'0')*10 + (date_start[11]-'0');
+ } else {
+ goto error;
+ }
+ } else if (*p == '\0' || *p == 'T' || *p == 't' || *p == ' ' || *p == '[') {
+ /* ±YYYYYY-MM - yearmonth only, no day */
+ p = date_start + 6 + 1 + 2; /* after ±YYYYYY-MM */
+ out->has_yearmonth = 1;
+ out->year = sign * ((date_start[0]-'0')*100000 + (date_start[1]-'0')*10000 +
+ (date_start[2]-'0')*1000 + (date_start[3]-'0')*100 +
+ (date_start[4]-'0')*10 + (date_start[5]-'0'));
+ if (out->year == 0 && sign < 0)
+ goto error;
+ out->month = (date_start[7]-'0')*10 + (date_start[8]-'0');
+ out->day = 1; /* default */
+ } else {
+ goto error;
+ }
+ } else {
+ goto error;
+ }
+ } else if (year_len == 6) {
+ /* ±YYYYYY with no separator: check for ±YYYYYYMMDD */
+ if (*p == '\0' || *p == 'T' || *p == 't' || *p == ' ') {
+ /* Only 6 digits - not enough */
+ p = date_start - 1; /* rewind to include sign */
+ } else {
+ p = date_start - 1;
+ }
+ }
+ } else if (year_len == 6 && !has_sign) {
+ /* Compact YYYYMM without sign and without separators */
+ out->has_yearmonth = 1;
+ out->year = ((date_start[0]-'0')*1000 + (date_start[1]-'0')*100 +
+ (date_start[2]-'0')*10 + (date_start[3]-'0'));
+ out->month = (date_start[4]-'0')*10 + (date_start[5]-'0');
+ out->day = 1; /* default */
+ } else if (year_len == 8 && !has_sign) {
+ /* Compact YYYYMMDD without sign and without separators */
+ /* We already consumed 8 digits. Validate positions. */
+ out->has_date = 1;
+ out->year = ((date_start[0]-'0')*1000 + (date_start[1]-'0')*100 +
+ (date_start[2]-'0')*10 + (date_start[3]-'0'));
+ out->month = (date_start[4]-'0')*10 + (date_start[5]-'0');
+ out->day = (date_start[6]-'0')*10 + (date_start[7]-'0');
+ /* Don't rewind - p is already after 8 digits */
+ } else if (year_len == 8 && has_sign) {
+ /* Compact ±YYYYYYMM without separators */
+ out->has_yearmonth = 1;
+ out->year = sign * ((date_start[0]-'0')*100000 + (date_start[1]-'0')*10000 +
+ (date_start[2]-'0')*1000 + (date_start[3]-'0')*100 +
+ (date_start[4]-'0')*10 + (date_start[5]-'0'));
+ if (out->year == 0 && sign < 0)
+ goto error;
+ out->month = (date_start[6]-'0')*10 + (date_start[7]-'0');
+ out->day = 1; /* default */
+ } else if (year_len == 10 && has_sign) {
+ /* Compact ±YYYYYYMMDD */
+ out->has_date = 1;
+ out->year = sign * ((date_start[0]-'0')*100000 + (date_start[1]-'0')*10000 +
+ (date_start[2]-'0')*1000 + (date_start[3]-'0')*100 +
+ (date_start[4]-'0')*10 + (date_start[5]-'0'));
+ if (out->year == 0 && sign < 0)
+ goto error;
+ out->month = (date_start[6]-'0')*10 + (date_start[7]-'0');
+ out->day = (date_start[8]-'0')*10 + (date_start[9]-'0');
+ } else {
+ /* Not a recognizable date prefix */
+ if (has_sign)
+ p = date_start - 1;
+ else
+ p = date_start;
+ }
+
+ no_date:;
+ }
+
+ /* Check for time separator and parse time */
+ if (*p == 'T' || *p == 't' || (*p == ' ' && out->has_date)) {
+ p++;
+ {
+ int h1 = 0, h2 = 0, m1 = 0, m2 = 0, s1 = 0, s2 = 0;
+ int has_explicit_seconds = 0;
+
+ /* Try extended format HH:MM:SS or HH:MM */
+ if (p[0] >= '0' && p[0] <= '9' && p[1] >= '0' && p[1] <= '9') {
+ h1 = p[0]-'0'; h2 = p[1]-'0';
+ p += 2;
+ if (*p == ':') {
+ p++;
+ if (p[0] >= '0' && p[0] <= '9' && p[1] >= '0' && p[1] <= '9') {
+ m1 = p[0]-'0'; m2 = p[1]-'0';
+ p += 2;
+ if (*p == ':') {
+ p++;
+ if (p[0] >= '0' && p[0] <= '9' && p[1] >= '0' && p[1] <= '9') {
+ s1 = p[0]-'0'; s2 = p[1]-'0';
+ p += 2;
+ has_explicit_seconds = 1;
+ out->has_time = 1;
+ out->hour = h1*10 + h2;
+ out->minute = m1*10 + m2;
+ out->second = s1*10 + s2;
+ } else {
+ goto error;
+ }
+ } else {
+ /* HH:MM */
+ out->has_time = 1;
+ out->hour = h1*10 + h2;
+ out->minute = m1*10 + m2;
+ out->second = 0;
+ }
+ } else {
+ goto error;
+ }
+ } else {
+ /* Could be compact HHMMSS or HHMM after T */
+ /* We already consumed HH, now check for MM and SS */
+ if (*p >= '0' && *p <= '9' && p[1] >= '0' && p[1] <= '9') {
+ m1 = p[0]-'0'; m2 = p[1]-'0';
+ p += 2;
+ if (*p >= '0' && *p <= '9' && p[1] >= '0' && p[1] <= '9') {
+ s1 = p[0]-'0'; s2 = p[1]-'0';
+ p += 2;
+ has_explicit_seconds = 1;
+ out->has_time = 1;
+ out->hour = h1*10 + h2;
+ out->minute = m1*10 + m2;
+ out->second = s1*10 + s2;
+ } else {
+ out->has_time = 1;
+ out->hour = h1*10 + h2;
+ out->minute = m1*10 + m2;
+ out->second = 0;
+ }
+ } else {
+ out->has_time = 1;
+ out->hour = h1*10 + h2;
+ out->minute = 0;
+ out->second = 0;
+ }
+ }
+ } else if (p[0] >= '0' && p[0] <= '9') {
+ /* Single digit hour */
+ h1 = p[0]-'0';
+ p += 1;
+ if (*p == ':') {
+ p++;
+ if (p[0] >= '0' && p[0] <= '9' && p[1] >= '0' && p[1] <= '9') {
+ m1 = p[0]-'0'; m2 = p[1]-'0';
+ p += 2;
+ out->has_time = 1;
+ out->hour = h1;
+ out->minute = m1*10 + m2;
+ out->second = 0;
+ } else {
+ goto error;
+ }
+ } else {
+ goto error;
+ }
+ } else {
+ goto error;
+ }
+
+ if (out->has_time) {
+ if (out->hour < 0 || out->hour > 23 || out->minute < 0 || out->minute > 59 || out->second < 0 || out->second > 60)
+ goto error;
+ if (out->second == 60)
+ out->second = 59;
+ }
+
+ /* Fractional seconds */
+ if (*p == '.' || *p == ',') {
+ if (!has_explicit_seconds)
+ goto error;
+ int frac[9] = {0};
+ int frac_len = 0;
+ p++;
+ while (*p >= '0' && *p <= '9' && frac_len < 9) {
+ frac[frac_len++] = *p - '0';
+ p++;
+ }
+ if (frac_len == 0)
+ goto error;
+ for (i = frac_len; i < 9; i++) frac[i] = 0;
+ out->millisecond = frac[0]*100 + frac[1]*10 + frac[2];
+ out->microsecond = frac[3]*100 + frac[4]*10 + frac[5];
+ out->nanosecond = frac[6]*100 + frac[7]*10 + frac[8];
+ }
+ }
+ } else if (!out->has_date) {
+ /* No date - try bare time (unambiguous) */
+ /* This is for PlainTime strings without date prefix */
+ int has_explicit_seconds = 0;
+ if (p[0] >= '0' && p[0] <= '9' && p[1] >= '0' && p[1] <= '9') {
+ int h1 = p[0]-'0', h2 = p[1]-'0';
+ p += 2;
+ if (*p == ':') {
+ p++;
+ if (p[0] >= '0' && p[0] <= '9' && p[1] >= '0' && p[1] <= '9') {
+ int m1 = p[0]-'0', m2 = p[1]-'0';
+ p += 2;
+ if (*p == ':') {
+ p++;
+ if (p[0] >= '0' && p[0] <= '9' && p[1] >= '0' && p[1] <= '9') {
+ int s1 = p[0]-'0', s2 = p[1]-'0';
+ p += 2;
+ has_explicit_seconds = 1;
+ out->has_time = 1;
+ out->hour = h1*10 + h2;
+ out->minute = m1*10 + m2;
+ out->second = s1*10 + s2;
+ } else {
+ goto error;
+ }
+ } else {
+ out->has_time = 1;
+ out->hour = h1*10 + h2;
+ out->minute = m1*10 + m2;
+ out->second = 0;
+ }
+ } else {
+ goto error;
+ }
+ } else {
+ /* Could be compact HHMMSS or HHMM */
+ if (*p >= '0' && *p <= '9' && p[1] >= '0' && p[1] <= '9') {
+ int m1 = p[0]-'0', m2 = p[1]-'0';
+ p += 2;
+ if (*p >= '0' && *p <= '9' && p[1] >= '0' && p[1] <= '9') {
+ int s1 = p[0]-'0', s2 = p[1]-'0';
+ p += 2;
+ has_explicit_seconds = 1;
+ out->has_time = 1;
+ out->hour = h1*10 + h2;
+ out->minute = m1*10 + m2;
+ out->second = s1*10 + s2;
+ } else {
+ out->has_time = 1;
+ out->hour = h1*10 + h2;
+ out->minute = m1*10 + m2;
+ out->second = 0;
+ }
+ } else {
+ out->has_time = 1;
+ out->hour = h1*10 + h2;
+ out->minute = 0;
+ out->second = 0;
+ }
+ }
+
+ if (out->has_time) {
+ if (out->hour < 0 || out->hour > 23 || out->minute < 0 || out->minute > 59 || out->second < 0 || out->second > 60)
+ goto error;
+ if (out->second == 60)
+ out->second = 59;
+ }
+
+ /* Fractional seconds for bare time */
+ if (*p == '.' || *p == ',') {
+ if (!has_explicit_seconds)
+ goto error;
+ int frac[9] = {0};
+ int frac_len = 0;
+ p++;
+ while (*p >= '0' && *p <= '9' && frac_len < 9) {
+ frac[frac_len++] = *p - '0';
+ p++;
+ }
+ if (frac_len == 0)
+ goto error;
+ for (i = frac_len; i < 9; i++) frac[i] = 0;
+ out->millisecond = frac[0]*100 + frac[1]*10 + frac[2];
+ out->microsecond = frac[3]*100 + frac[4]*10 + frac[5];
+ out->nanosecond = frac[6]*100 + frac[7]*10 + frac[8];
+ }
+ } else if (p[0] >= '0' && p[0] <= '9') {
+ /* Single digit hour */
+ int h1 = p[0]-'0';
+ p += 1;
+ if (*p == ':') {
+ p++;
+ if (p[0] >= '0' && p[0] <= '9' && p[1] >= '0' && p[1] <= '9') {
+ int m1 = p[0]-'0', m2 = p[1]-'0';
+ p += 2;
+ out->has_time = 1;
+ out->hour = h1;
+ out->minute = m1*10 + m2;
+ out->second = 0;
+ } else {
+ goto error;
+ }
+ } else {
+ out->has_time = 1;
+ out->hour = h1;
+ out->minute = 0;
+ out->second = 0;
+ }
+
+ if (out->has_time) {
+ if (out->hour < 0 || out->hour > 23 || out->minute < 0 || out->minute > 59 || out->second < 0 || out->second > 60)
+ goto error;
+ if (out->second == 60)
+ out->second = 59;
+ }
+ } else {
+ /* Not a time string either */
+ }
+ }
+
+ /* Timezone offset or Z */
+ if (*p == 'Z' || *p == 'z') {
+ out->has_utc = 1;
+ p++;
+ } else if (*p == '+' || *p == '-') {
+ int tz_sign = (*p == '-') ? -1 : 1;
+ p++;
+ if (p[0] >= '0' && p[0] <= '9' && p[1] >= '0' && p[1] <= '9') {
+ int th = (p[0]-'0')*10 + (p[1]-'0');
+ p += 2;
+ if (*p == ':') {
+ p++;
+ if (p[0] >= '0' && p[0] <= '9' && p[1] >= '0' && p[1] <= '9') {
+ int tm = (p[0]-'0')*10 + (p[1]-'0');
+ p += 2;
+ if (*p == ':') {
+ p++;
+ if (p[0] >= '0' && p[0] <= '9' && p[1] >= '0' && p[1] <= '9') {
+ int ts = (p[0]-'0')*10 + (p[1]-'0');
+ p += 2;
+ if (th > 23 || tm > 59 || ts > 59)
+ goto error;
+ out->has_tz_offset = 1;
+ out->tz_offset_has_seconds = 1;
+ out->tz_offset_seconds = tz_sign * (th * 3600 + tm * 60 + ts);
+ } else {
+ goto error;
+ }
+ } else {
+ if (th > 23 || tm > 59)
+ goto error;
+ out->has_tz_offset = 1;
+ out->tz_offset_seconds = tz_sign * (th * 3600 + tm * 60);
+ }
+ } else {
+ goto error;
+ }
+ } else if (p[0] >= '0' && p[0] <= '9' && p[1] >= '0' && p[1] <= '9') {
+ /* HHMM compact offset */
+ int tm = (p[0]-'0')*10 + (p[1]-'0');
+ p += 2;
+ if (p[0] >= '0' && p[0] <= '9' && p[1] >= '0' && p[1] <= '9') {
+ /* HHMMSS */
+ int ts = (p[0]-'0')*10 + (p[1]-'0');
+ p += 2;
+ if (th > 23 || tm > 59 || ts > 59)
+ goto error;
+ out->has_tz_offset = 1;
+ out->tz_offset_has_seconds = 1;
+ out->tz_offset_seconds = tz_sign * (th * 3600 + tm * 60 + ts);
+ } else {
+ if (th > 23 || tm > 59)
+ goto error;
+ out->has_tz_offset = 1;
+ out->tz_offset_seconds = tz_sign * (th * 3600 + tm * 60);
+ }
+ } else {
+ /* HH offset only */
+ if (th > 23)
+ goto error;
+ out->has_tz_offset = 1;
+ out->tz_offset_seconds = tz_sign * (th * 3600);
+ }
+ } else {
+ goto error;
+ }
+
+ /* Fractional timezone offsets */
+ if (*p == '.' || *p == ',') {
+ int frac_count = 0;
+ int frac_val = 0;
+ p++;
+ while (*p >= '0' && *p <= '9' && frac_count < 9) {
+ frac_val = frac_val * 10 + (*p - '0');
+ frac_count++;
+ p++;
+ }
+ if (frac_count == 0)
+ goto error;
+ for (i = frac_count; i < 9; i++)
+ frac_val *= 10;
+ out->tz_offset_nanoseconds = tz_sign * frac_val;
+ }
+ }
+
+ /* Bracket annotations */
+ {
+ int tz_annotation_count = 0;
+ int cal_annotation_count = 0;
+ int has_critical_calendar = 0;
+
+ while (*p == '[') {
+ int is_critical = 0;
+ const char *key_start;
+ int key_len;
+ const char *val_start;
+ int val_len;
+
+ p++;
+ if (*p == '!') {
+ is_critical = 1;
+ p++;
+ }
+ key_start = p;
+ while (*p && *p != '=' && *p != ']') p++;
+ key_len = (int)(p - key_start);
+ if (*p == '=') {
+ p++;
+ val_start = p;
+ while (*p && *p != ']') p++;
+ if (*p != ']')
+ goto error;
+ val_len = (int)(p - val_start);
+
+ /* Validate key characters */
+ {
+ int valid = 1;
+ for (i = 0; i < key_len; i++) {
+ char c = key_start[i];
+ if (i == 0) {
+ if (!((c >= 'a' && c <= 'z') || c == '_'))
+ valid = 0;
+ } else {
+ if (!((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '-' || c == '_'))
+ valid = 0;
+ }
+ }
+ if (!valid)
+ goto error;
+ }
+
+ if (key_len == 4 && memcmp(key_start, "u-ca", 4) == 0) {
+ cal_annotation_count++;
+ if (is_critical)
+ has_critical_calendar = 1;
+ if (!out->has_calendar && val_len > 0 && val_len < 64) {
+ char cal_buf[64];
+ int j;
+ memcpy(cal_buf, val_start, (size_t)val_len);
+ cal_buf[val_len] = '\0';
+ for (j = 0; j < val_len; j++) {
+ char c = cal_buf[j];
+ cal_buf[j] = (c >= 'A' && c <= 'Z') ? (c + ('a' - 'A')) : c;
+ }
+ out->calendar = ti_calendar_string_to_enum_with_aliases(cal_buf);
+ out->has_calendar = 1;
+ out->calendar_critical = is_critical;
+ }
+ } else {
+ if (is_critical)
+ goto error;
+ }
+ } else if (*p == ']') {
+ tz_annotation_count++;
+ if (!out->has_tz_annotation && key_len > 0 && key_len < 64) {
+ /* Reject sub-minute offsets in timezone annotations */
+ if (key_start[0] == '+' || key_start[0] == '-') {
+ int colon_count = 0;
+ int j;
+ for (j = 0; j < key_len; j++) {
+ if (key_start[j] == ':')
+ colon_count++;
+ }
+ if (colon_count >= 2 || (colon_count == 0 && key_len > 5))
+ goto error;
+ }
+ memcpy(out->tz_annotation, key_start, (size_t)key_len);
+ out->tz_annotation[key_len] = '\0';
+ out->has_tz_annotation = 1;
+ }
+ } else {
+ goto error;
+ }
+ p++;
+ }
+ if (cal_annotation_count > 1 && has_critical_calendar)
+ goto error;
+ if (tz_annotation_count > 1)
+ goto error;
+ }
+
+ /* Trailing junk */
+ if (*p != '\0')
+ goto error;
+
+ if (flags & TI_PARSE_PLAIN_TIME) {
+ if (!out->has_time)
+ goto error;
+ if (out->has_utc)
+ goto error;
+ {
+ const char *q = str;
+ int has_t = 0;
+ while (*q && *q != '[') {
+ if (*q == 'T' || *q == 't') {
+ has_t = 1;
+ break;
+ }
+ q++;
+ }
+ if (!has_t) {
+ const char *q2 = str;
+ while (*q2 && ((*q2 >= '0' && *q2 <= '9') || *q2 == '-')) q2++;
+ int core_len = (int)(q2 - str);
+ if (core_len == 4) {
+ int mm = (str[0]-'0')*10 + (str[1]-'0');
+ int dd = (str[2]-'0')*10 + (str[3]-'0');
+ int max_day[13] = {0,31,29,31,30,31,30,31,31,30,31,30,31};
+ if (mm >= 1 && mm <= 12 && dd >= 1 && dd <= max_day[mm])
+ goto error;
+ } else if (core_len == 6) {
+ int mm = (str[4]-'0')*10 + (str[5]-'0');
+ if (mm >= 1 && mm <= 12)
+ goto error;
+ } else if (core_len == 5 && str[2] == '-') {
+ int mm = (str[0]-'0')*10 + (str[1]-'0');
+ int dd = (str[3]-'0')*10 + (str[4]-'0');
+ int max_day[13] = {0,31,29,31,30,31,30,31,31,30,31,30,31};
+ if (mm >= 1 && mm <= 12 && dd >= 1 && dd <= max_day[mm])
+ goto error;
+ } else if (core_len == 7 && str[4] == '-') {
+ int mm = (str[5]-'0')*10 + (str[6]-'0');
+ if (mm >= 1 && mm <= 12)
+ goto error;
+ }
+ }
+ }
+ }
+
+ if (flags & TI_PARSE_PLAIN_MONTHDAY) {
+ if (!out->has_monthday && !out->has_date)
+ goto error;
+ if (out->has_monthday) {
+ if (out->month < 1 || out->month > 12 || out->day < 1 || out->day > 31)
+ goto error;
+ }
+ /* Time is only allowed with a full date (YYYY-MM-DD) */
+ if (out->has_time && !out->has_date)
+ goto error;
+ /* UTC designator is never allowed for PlainMonthDay */
+ if (out->has_utc)
+ goto error;
+ /* Numeric offsets are only allowed with time */
+ if (out->has_tz_offset && !out->has_time)
+ goto error;
+ }
+
+ return 0;
+
+error:
+ return -1;
+}
+
+/* Get a string option from an options object and validate it against a list of allowed values.
+ Returns the index of the matched value, or default_index if the property is undefined.
+ Returns -1 on error (exception thrown).
+ Uses JS_ToCStringLen for exact length comparison to handle embedded null bytes. */
+int ti_get_string_option(JSContext *ctx, JSValueConst options, const char *prop,
+ const char **valid_values, int num_values, int default_index)
+{
+ JSValue val;
+ size_t slen;
+ const char *str;
+ int i;
+
+ if (JS_IsUndefined(options))
+ return default_index;
+
+ val = JS_GetPropertyStr(ctx, options, prop);
+
+ if (JS_IsException(val))
+ return -1;
+ if (JS_IsUndefined(val))
+ return default_index;
+
+ str = JS_ToCStringLen(ctx, &slen, val);
+ JS_FreeValue(ctx, val);
+ if (!str)
+ return -1;
+
+ for (i = 0; i < num_values; i++) {
+ size_t vlen = strlen(valid_values[i]);
+ if (slen == vlen && memcmp(str, valid_values[i], vlen) == 0) {
+ JS_FreeCString(ctx, str);
+ return i;
+ }
+ }
+
+ JS_ThrowRangeError(ctx, "invalid %s", prop);
+ JS_FreeCString(ctx, str);
+ return -1;
+}
+
+/* Get the "overflow" option from an options object.
+ Returns 1 for "constrain", 0 for "reject".
+ Returns -1 on error (exception thrown).
+ Default is "constrain" (returns 1). */
+int ti_get_overflow_option(JSContext *ctx, JSValueConst options, int *overflow_constrain)
+{
+ static const char *overflow_values[] = { "reject", "constrain" };
+ int idx = ti_get_string_option(ctx, options, "overflow", overflow_values, 2, 1);
+ if (idx < 0)
+ return -1;
+ *overflow_constrain = idx; /* 0 = reject, 1 = constrain */
+ return 0;
+}
+
+TIUnit ti_string_to_unit(const char *str, size_t len)
+{
+ static const char *unit_strings[] = {
+ "year", "month", "week", "day", "hour", "minute", "second",
+ "millisecond", "microsecond", "nanosecond"
+ };
+ int i;
+ for (i = 0; i < (int)(sizeof(unit_strings) / sizeof(unit_strings[0])); i++) {
+ size_t unit_len = strlen(unit_strings[i]);
+ if (len == unit_len && memcmp(str, unit_strings[i], unit_len) == 0)
+ return (TIUnit)(TI_UNIT_YEAR + i);
+ if (len == unit_len + 1 && str[len - 1] == 's' && memcmp(str, unit_strings[i], unit_len) == 0)
+ return (TIUnit)(TI_UNIT_YEAR + i);
+ }
+ return TI_UNIT_INVALID;
+}
+
+/* Parse a unit option (smallestUnit, largestUnit, unit) from an options object.
+ Returns 0 on success, -1 on error (exception thrown).
+ flags: bitwise OR of TI_UNIT_OPT_ALLOW_UNDEFINED and/or TI_UNIT_OPT_ALLOW_AUTO.
+ If ALLOW_UNDEFINED is set and the property is undefined, *out = default_unit.
+ If ALLOW_AUTO is set and the value is "auto", *out = TI_UNIT_AUTO.
+ Otherwise throws RangeError for undefined or invalid strings. */
+int ti_parse_unit_option(JSContext *ctx, JSValueConst options, const char *prop,
+ TIUnit *out, int flags, TIUnit default_unit)
+{
+ JSValue val = JS_GetPropertyStr(ctx, options, prop);
+ size_t len;
+ const char *str;
+ TIUnit unit;
+
+ if (JS_IsException(val))
+ return -1;
+ if (JS_IsUndefined(val)) {
+ JS_FreeValue(ctx, val);
+ if (flags & TI_UNIT_OPT_ALLOW_UNDEFINED) {
+ *out = default_unit;
+ return 0;
+ }
+ JS_ThrowRangeError(ctx, "%s is required", prop);
+ return -1;
+ }
+
+ str = JS_ToCStringLen(ctx, &len, val);
+ JS_FreeValue(ctx, val);
+ if (!str)
+ return -1;
+
+ if ((flags & TI_UNIT_OPT_ALLOW_AUTO) && len == 4 && memcmp(str, "auto", 4) == 0) {
+ JS_FreeCString(ctx, str);
+ *out = TI_UNIT_AUTO;
+ return 0;
+ }
+
+ unit = ti_string_to_unit(str, len);
+ JS_FreeCString(ctx, str);
+ if (unit == TI_UNIT_INVALID) {
+ JS_ThrowRangeError(ctx, "invalid %s", prop);
+ return -1;
+ }
+ *out = unit;
+ return 0;
+}
+
+int64_t ti_unit_to_ns(TIUnit unit)
+{
+ switch (unit) {
+ case TI_UNIT_DAY: return 86400000000000LL;
+ case TI_UNIT_HOUR: return 3600000000000LL;
+ case TI_UNIT_MINUTE: return 60000000000LL;
+ case TI_UNIT_SECOND: return 1000000000LL;
+ case TI_UNIT_MILLISECOND: return 1000000LL;
+ case TI_UNIT_MICROSECOND: return 1000LL;
+ case TI_UNIT_NANOSECOND: return 1LL;
+ default: return 0;
+ }
+}
+
+/* Read the roundingIncrement option from an options object.
+ Returns 0 on success, -1 on error (exception thrown).
+ If the property is undefined, *out is left unchanged. */
+int ti_get_rounding_increment_option(JSContext *ctx, JSValueConst options, int64_t *out)
+{
+ JSValue val = JS_GetPropertyStr(ctx, options, "roundingIncrement");
+ double d;
+ int64_t ri;
+
+ if (JS_IsException(val))
+ return -1;
+ if (JS_IsUndefined(val)) {
+ JS_FreeValue(ctx, val);
+ return 0;
+ }
+ if (JS_ToFloat64(ctx, &d, val) < 0) {
+ JS_FreeValue(ctx, val);
+ return -1;
+ }
+ JS_FreeValue(ctx, val);
+ ri = (int64_t)d;
+ if (!isfinite(d) || ri < 1 || ri > 1000000000LL) {
+ JS_ThrowRangeError(ctx, "invalid roundingIncrement");
+ return -1;
+ }
+ *out = ri;
+ return 0;
+}
+
+/* Read the roundingMode option from an options object.
+ Returns 0 on success, -1 on error (exception thrown).
+ If default_mode is -1, uses ROUND_HALF_EXPAND as default. */
+int ti_get_rounding_mode_option_default(JSContext *ctx, JSValueConst options, TIRoundingMode *out, int default_mode)
+{
+ JSValue val = JS_GetPropertyStr(ctx, options, "roundingMode");
+ int ret;
+
+ if (JS_IsException(val))
+ return -1;
+
+ if (JS_IsUndefined(val)) {
+ *out = (default_mode < 0) ? ROUND_HALF_EXPAND : default_mode;
+ JS_FreeValue(ctx, val);
+ return 0;
+ }
+
+ ret = ti_parse_rounding_mode(ctx, val, out);
+ JS_FreeValue(ctx, val);
+ return ret;
+}
+
+int ti_get_rounding_mode_option(JSContext *ctx, JSValueConst options, TIRoundingMode *out)
+{
+ return ti_get_rounding_mode_option_default(ctx, options, out, -1);
+}
+
+/* Read the "calendarName" option from an options object.
+ Returns 0 on success, -1 on error (exception thrown).
+ *out is set to: 0=auto, 1=always, 2=critical, 3=never.
+ Leaves *out unchanged if property is undefined. */
+int ti_get_calendar_name_option(JSContext *ctx, JSValueConst options, int *out)
+{
+ JSValue v = JS_GetPropertyStr(ctx, options, "calendarName");
+ size_t len;
+ const char *str;
+ if (JS_IsException(v))
+ return -1;
+ if (JS_IsUndefined(v)) {
+ JS_FreeValue(ctx, v);
+ return 0;
+ }
+ str = JS_ToCStringLen(ctx, &len, v);
+ JS_FreeValue(ctx, v);
+ if (!str)
+ return -1;
+ if (len == 6 && memcmp(str, "always", 6) == 0)
+ *out = 1;
+ else if (len == 8 && memcmp(str, "critical", 8) == 0)
+ *out = 2;
+ else if (len == 5 && memcmp(str, "never", 5) == 0)
+ *out = 3;
+ else if (len == 4 && memcmp(str, "auto", 4) == 0)
+ *out = 0;
+ else {
+ JS_FreeCString(ctx, str);
+ JS_ThrowRangeError(ctx, "invalid calendarName");
+ return -1;
+ }
+ JS_FreeCString(ctx, str);
+ return 0;
+}
+
+/* GetTemporalFractionalSecondDigitsOption as specified in Temporal spec.
+ Returns 0 on success, -1 on error (exception thrown).
+ *out is set to -1 for "auto" or 0-9 for a digit count.
+ Leaves *out unchanged if property is undefined. */
+int ti_get_fractional_second_digits_option(JSContext *ctx, JSValueConst options, int *out)
+{
+ JSValue v = JS_GetPropertyStr(ctx, options, "fractionalSecondDigits");
+ if (JS_IsException(v))
+ return -1;
+ if (JS_IsUndefined(v)) {
+ *out = -1;
+ return 0;
+ }
+ if (JS_IsNumber(v)) {
+ double d;
+ if (JS_ToFloat64(ctx, &d, v) < 0)
+ goto fail;
+ JS_FreeValue(ctx, v);
+ if (isnan(d) || isinf(d)) {
+ JS_ThrowRangeError(ctx, "invalid fractionalSecondDigits");
+ return -1;
+ }
+ int digitCount = (int)floor(d);
+ if (digitCount < 0 || digitCount > 9) {
+ JS_ThrowRangeError(ctx, "invalid fractionalSecondDigits");
+ return -1;
+ }
+ *out = digitCount;
+ return 0;
+ } else {
+ JSValue str = JS_ToString(ctx, v);
+ JS_FreeValue(ctx, v);
+ if (JS_IsException(str))
+ return -1;
+ size_t len;
+ const char *p = JS_ToCStringLen(ctx, &len, str);
+ if (!p) {
+ JS_FreeValue(ctx, str);
+ return -1;
+ }
+ int ok = (len == 4 && memcmp(p, "auto", 4) == 0);
+ JS_FreeCString(ctx, p);
+ JS_FreeValue(ctx, str);
+ if (!ok) {
+ JS_ThrowRangeError(ctx, "invalid fractionalSecondDigits");
+ return -1;
+ }
+ *out = -1;
+ return 0;
+ }
+fail:
+ JS_FreeValue(ctx, v);
+ return -1;
+}
+
+/* NegateRoundingMode as specified in GetDifferenceSettings step 6.
+ For since operations, the rounding mode is inverted. */
+TIRoundingMode ti_negate_rounding_mode(TIRoundingMode mode)
+{
+ switch (mode) {
+ case ROUND_CEIL: return ROUND_FLOOR;
+ case ROUND_FLOOR: return ROUND_CEIL;
+ case ROUND_HALF_CEIL: return ROUND_HALF_FLOOR;
+ case ROUND_HALF_FLOOR: return ROUND_HALF_CEIL;
+ default: return mode;
+ }
+}
+
+/* ------------------------------------------------------------------ */
+/* PrepareCalendarFields-like implementation */
+/* ------------------------------------------------------------------ */
+
+static void ti_prepared_fields_init(TIPreparedFields *fields)
+{
+ memset(fields, 0, sizeof(*fields));
+ fields->calendar = CAL_ISO8601;
+}
+
+/* Helper to convert a JSValue to integer with truncation.
+ Returns 0 on success, -1 on exception. */
+static int ti_to_integer_with_truncation(JSContext *ctx, JSValue v, int64_t *out)
+{
+ double d;
+ if (JS_ToFloat64(ctx, &d, v) < 0)
+ return -1;
+ if (!isfinite(d)) {
+ JS_ThrowRangeError(ctx, "value must be finite");
+ return -1;
+ }
+ *out = (int64_t)d;
+ return 0;
+}
+
+/* Helper to convert a JSValue to positive integer with truncation.
+ Returns 0 on success, -1 on exception. */
+static int ti_to_positive_integer_with_truncation(JSContext *ctx, JSValue v, int *out)
+{
+ double d;
+ if (JS_ToFloat64(ctx, &d, v) < 0)
+ return -1;
+ if (!isfinite(d) || d <= 0) {
+ JS_ThrowRangeError(ctx, "value must be a finite positive number");
+ return -1;
+ }
+ *out = (int)d;
+ return 0;
+}
+
+/* Resolve a calendar JSValue to a CalendarType.
+ Returns 0 on success, -1 on exception. */
+int ti_resolve_calendar_value(JSContext *ctx, JSValue cal_v, CalendarType *out)
+{
+ if (JS_IsString(cal_v)) {
+ int cal_res;
+ size_t cal_len;
+ const char *cal_raw = JS_ToCStringLen(ctx, &cal_len, cal_v);
+ if (!cal_raw)
+ return -1;
+ int looks_temporal = 0;
+ if (cal_len > 0) {
+ char first = cal_raw[0];
+ if (isdigit((unsigned char)first) || first == '+' || first == '-')
+ looks_temporal = 1;
+ else if ((first == 'T' || first == 't') && cal_len > 1 && isdigit((unsigned char)cal_raw[1]))
+ looks_temporal = 1;
+ }
+ if (looks_temporal) {
+ cal_res = ti_parse_temporal_calendar_string(ctx, cal_v, out);
+ } else {
+ cal_res = ti_canonicalize_calendar(ctx, cal_v, out);
+ }
+ JS_FreeCString(ctx, cal_raw);
+ if (cal_res == -2) {
+ JS_ThrowTypeError(ctx, "invalid calendar");
+ return -1;
+ }
+ if (cal_res < 0) {
+ JS_ThrowRangeError(ctx, "invalid calendar ID");
+ return -1;
+ }
+ } else if (JS_IsObject(cal_v)) {
+ JSPlainDateData *pd = JS_GetOpaque(cal_v, js_plaindate_class_id);
+ JSPlainDateTimeData *pdt = JS_GetOpaque(cal_v, js_plaindatetime_class_id);
+ JSPlainMonthDayData *pmd = JS_GetOpaque(cal_v, js_plainmonthday_class_id);
+ JSPlainYearMonthData *pym = JS_GetOpaque(cal_v, js_plainyearmonth_class_id);
+ JSZonedDateTimeData *zdt = js_zoneddatetime_class_id ? JS_GetOpaque(cal_v, js_zoneddatetime_class_id) : NULL;
+ if (pd) *out = pd->calendar;
+ else if (pdt) *out = pdt->calendar;
+ else if (pmd) *out = pmd->calendar;
+ else if (pym) *out = pym->calendar;
+ else if (zdt) *out = zdt->calendar;
+ else {
+ JS_ThrowTypeError(ctx, "invalid calendar");
+ return -1;
+ }
+ } else {
+ JS_ThrowTypeError(ctx, "invalid calendar");
+ return -1;
+ }
+ return 0;
+}
+
+/* Read the calendar property from an object and resolve it.
+ Returns 0 on success, -1 on exception. Default is CAL_ISO8601. */
+int ti_resolve_calendar_from_object(JSContext *ctx, JSValueConst obj, CalendarType *out)
+{
+ JSValue cal_v = JS_GetPropertyStr(ctx, obj, "calendar");
+ if (JS_IsException(cal_v))
+ return -1;
+ if (JS_IsUndefined(cal_v)) {
+ *out = CAL_ISO8601;
+ return 0;
+ }
+ int ret = ti_resolve_calendar_value(ctx, cal_v, out);
+ JS_FreeValue(ctx, cal_v);
+ return ret;
+}
+
+/* Check if obj is a partial Temporal object suitable for .with() methods.
+ Returns 0 on success, -1 on exception (TypeError already thrown).
+ Rejects non-objects, Temporal internal slot objects, and objects with
+ calendar or timeZone properties. */
+int ti_is_partial_temporal_object(JSContext *ctx, JSValueConst obj)
+{
+ JSValue v;
+ if (!JS_IsObject(obj))
+ return JS_ThrowTypeError(ctx, "expected an object"), -1;
+ if (JS_GetOpaque(obj, js_plaindate_class_id) ||
+ JS_GetOpaque(obj, js_plaintime_class_id) ||
+ JS_GetOpaque(obj, js_plaindatetime_class_id) ||
+ JS_GetOpaque(obj, js_plainmonthday_class_id) ||
+ JS_GetOpaque(obj, js_plainyearmonth_class_id) ||
+ JS_GetOpaque(obj, js_zoneddatetime_class_id))
+ return JS_ThrowTypeError(ctx, "object must not be a Temporal instance"), -1;
+ v = JS_GetPropertyStr(ctx, obj, "calendar");
+ if (JS_IsException(v)) {
+ JS_FreeValue(ctx, v);
+ return -1;
+ }
+ if (!JS_IsUndefined(v)) {
+ JS_FreeValue(ctx, v);
+ return JS_ThrowTypeError(ctx, "object must not have a calendar property"), -1;
+ }
+ JS_FreeValue(ctx, v);
+ v = JS_GetPropertyStr(ctx, obj, "timeZone");
+ if (JS_IsException(v)) {
+ JS_FreeValue(ctx, v);
+ return -1;
+ }
+ if (!JS_IsUndefined(v)) {
+ JS_FreeValue(ctx, v);
+ return JS_ThrowTypeError(ctx, "object must not have a timeZone property"), -1;
+ }
+ JS_FreeValue(ctx, v);
+ return 0;
+}
+
+/* Month code formatting helper */
+JSValue ti_get_month_code(JSContext *ctx, CalendarType cal, int year, int month)
+{
+ char buf[8];
+ int mc, has_l;
+ ti_calendar_month_to_month_code(cal, year, month, &mc, &has_l);
+ snprintf(buf, sizeof(buf), "M%02d%s", mc, has_l ? "L" : "");
+ return JS_NewString(ctx, buf);
+}
+
+/* Read fields from a property bag according to field_mask.
+ required_mask: fields that MUST be present (throw TypeError if missing).
+ partial: if true, at least one field must be present (like ~partial~ in spec).
+ calendar: the resolved calendar type (used to determine if era/eraYear should be read).
+ Returns 0 on success, -1 on exception. */
+int ti_prepare_calendar_fields(JSContext *ctx, JSValueConst obj,
+ uint32_t field_mask, uint32_t required_mask,
+ int partial, TIPreparedFields *out,
+ CalendarType calendar)
+{
+ JSValue v;
+ ti_prepared_fields_init(out);
+ out->calendar = calendar;
+
+ if (!JS_IsObject(obj)) {
+ JS_ThrowTypeError(ctx, "expected an object");
+ return -1;
+ }
+
+ if (calendar != CAL_ISO8601)
+ field_mask |= TI_FIELD_ERA | TI_FIELD_ERA_YEAR;
+
+ /* Read fields in alphabetical order */
+
+ /* day */
+ if (field_mask & TI_FIELD_DAY) {
+ v = JS_GetPropertyStr(ctx, obj, "day");
+ if (JS_IsException(v))
+ goto fail;
+ if (!JS_IsUndefined(v)) {
+ if (ti_to_positive_integer_with_truncation(ctx, v, &out->day) < 0) {
+ goto fail;
+ }
+ out->present_mask |= TI_FIELD_DAY;
+ }
+ JS_FreeValue(ctx, v);
+ v = JS_UNDEFINED;
+ }
+
+ /* era */
+ if (field_mask & TI_FIELD_ERA) {
+ v = JS_GetPropertyStr(ctx, obj, "era");
+ if (JS_IsException(v))
+ goto fail;
+ if (!JS_IsUndefined(v)) {
+ const char *era_str = JS_ToCString(ctx, v);
+ if (!era_str)
+ goto fail;
+ out->era = ti_string_to_era(era_str);
+ JS_FreeCString(ctx, era_str);
+ out->present_mask |= TI_FIELD_ERA;
+ }
+ }
+
+ /* eraYear */
+ if (field_mask & TI_FIELD_ERA_YEAR) {
+ v = JS_GetPropertyStr(ctx, obj, "eraYear");
+ if (JS_IsException(v))
+ goto fail;
+ if (!JS_IsUndefined(v)) {
+ if (ti_to_integer_with_truncation(ctx, v, &out->era_year) < 0) {
+ goto fail;
+ }
+ out->present_mask |= TI_FIELD_ERA_YEAR;
+ }
+ JS_FreeValue(ctx, v);
+ v = JS_UNDEFINED;
+ }
+
+ /* hour */
+ if (field_mask & TI_FIELD_HOUR) {
+ v = JS_GetPropertyStr(ctx, obj, "hour");
+ if (JS_IsException(v))
+ goto fail;
+ if (!JS_IsUndefined(v)) {
+ int64_t tmp;
+ if (ti_to_integer_with_truncation(ctx, v, &tmp) < 0) {
+ goto fail;
+ }
+ out->hour = (int)tmp;
+ out->present_mask |= TI_FIELD_HOUR;
+ }
+ JS_FreeValue(ctx, v);
+ v = JS_UNDEFINED;
+ }
+
+ /* microsecond */
+ if (field_mask & TI_FIELD_MICROSECOND) {
+ v = JS_GetPropertyStr(ctx, obj, "microsecond");
+ if (JS_IsException(v))
+ goto fail;
+ if (!JS_IsUndefined(v)) {
+ int64_t tmp;
+ if (ti_to_integer_with_truncation(ctx, v, &tmp) < 0) {
+ goto fail;
+ }
+ out->microsecond = (int)tmp;
+ out->present_mask |= TI_FIELD_MICROSECOND;
+ }
+ JS_FreeValue(ctx, v);
+ v = JS_UNDEFINED;
+ }
+
+ /* millisecond */
+ if (field_mask & TI_FIELD_MILLISECOND) {
+ v = JS_GetPropertyStr(ctx, obj, "millisecond");
+ if (JS_IsException(v))
+ goto fail;
+ if (!JS_IsUndefined(v)) {
+ int64_t tmp;
+ if (ti_to_integer_with_truncation(ctx, v, &tmp) < 0) {
+ goto fail;
+ }
+ out->millisecond = (int)tmp;
+ out->present_mask |= TI_FIELD_MILLISECOND;
+ }
+ JS_FreeValue(ctx, v);
+ v = JS_UNDEFINED;
+ }
+
+ /* minute */
+ if (field_mask & TI_FIELD_MINUTE) {
+ v = JS_GetPropertyStr(ctx, obj, "minute");
+ if (JS_IsException(v))
+ goto fail;
+ if (!JS_IsUndefined(v)) {
+ int64_t tmp;
+ if (ti_to_integer_with_truncation(ctx, v, &tmp) < 0) {
+ goto fail;
+ }
+ out->minute = (int)tmp;
+ out->present_mask |= TI_FIELD_MINUTE;
+ }
+ JS_FreeValue(ctx, v);
+ v = JS_UNDEFINED;
+ }
+
+ /* month */
+ if (field_mask & TI_FIELD_MONTH) {
+ v = JS_GetPropertyStr(ctx, obj, "month");
+ if (JS_IsException(v))
+ goto fail;
+ if (!JS_IsUndefined(v)) {
+ if (ti_to_positive_integer_with_truncation(ctx, v, &out->month) < 0) {
+ goto fail;
+ }
+ out->present_mask |= TI_FIELD_MONTH;
+ }
+ JS_FreeValue(ctx, v);
+ v = JS_UNDEFINED;
+ }
+
+ /* monthCode */
+ if (field_mask & TI_FIELD_MONTH_CODE) {
+ v = JS_GetPropertyStr(ctx, obj, "monthCode");
+ if (JS_IsException(v))
+ goto fail;
+ if (!JS_IsUndefined(v)) {
+ JSValue prim = JS_ToPrimitive(ctx, v, JS_HINT_STRING);
+ JS_FreeValue(ctx, v);
+ v = JS_UNDEFINED;
+ if (JS_IsException(prim)) {
+ JS_FreeValue(ctx, prim);
+ goto fail;
+ }
+ if (!JS_IsString(prim)) {
+ JS_FreeValue(ctx, prim);
+ JS_ThrowTypeError(ctx, "monthCode must be a string");
+ goto fail;
+ }
+ {
+ const char *mc = JS_ToCString(ctx, prim);
+ if (!mc) {
+ JS_FreeValue(ctx, prim);
+ goto fail;
+ }
+ /* Validate monthCode format: M## or M##L */
+ if (mc[0] == 'M' && isdigit((unsigned char)mc[1]) && isdigit((unsigned char)mc[2])) {
+ if (mc[3] == '\0') {
+ out->month_from_code = atoi(mc + 1);
+ out->month_code_has_l = 0;
+ } else if (mc[3] == 'L' && mc[4] == '\0') {
+ out->month_from_code = atoi(mc + 1);
+ out->month_code_has_l = 1;
+ } else {
+ JS_FreeCString(ctx, mc);
+ JS_FreeValue(ctx, prim);
+ JS_ThrowRangeError(ctx, "monthCode is not well-formed");
+ goto fail;
+ }
+ } else {
+ JS_FreeCString(ctx, mc);
+ JS_FreeValue(ctx, prim);
+ JS_ThrowRangeError(ctx, "monthCode is not well-formed");
+ goto fail;
+ }
+ JS_FreeCString(ctx, mc);
+ }
+ JS_FreeValue(ctx, prim);
+ out->present_mask |= TI_FIELD_MONTH_CODE;
+ }
+ }
+
+ /* nanosecond */
+ if (field_mask & TI_FIELD_NANOSECOND) {
+ v = JS_GetPropertyStr(ctx, obj, "nanosecond");
+ if (JS_IsException(v))
+ goto fail;
+ if (!JS_IsUndefined(v)) {
+ int64_t tmp;
+ if (ti_to_integer_with_truncation(ctx, v, &tmp) < 0) {
+ goto fail;
+ }
+ out->nanosecond = (int)tmp;
+ out->present_mask |= TI_FIELD_NANOSECOND;
+ }
+ JS_FreeValue(ctx, v);
+ v = JS_UNDEFINED;
+ }
+
+ /* offset */
+ if (field_mask & TI_FIELD_OFFSET) {
+ v = JS_GetPropertyStr(ctx, obj, "offset");
+ if (JS_IsException(v))
+ goto fail;
+ if (!JS_IsUndefined(v)) {
+ JSValue prim = JS_ToPrimitive(ctx, v, JS_HINT_STRING);
+ JS_FreeValue(ctx, v);
+ v = JS_UNDEFINED;
+ if (JS_IsException(prim)) {
+ JS_FreeValue(ctx, prim);
+ goto fail;
+ }
+ if (!JS_IsString(prim)) {
+ JS_FreeValue(ctx, prim);
+ JS_ThrowTypeError(ctx, "offset must be a string");
+ goto fail;
+ }
+ {
+ const char *str = JS_ToCString(ctx, prim);
+ size_t len;
+ int sign;
+ if (!str) {
+ JS_FreeValue(ctx, prim);
+ goto fail;
+ }
+ len = strlen(str);
+ if (len == 1 && (str[0] == 'Z' || str[0] == 'z')) {
+ out->offset_ns = 0;
+ JS_FreeCString(ctx, str);
+ JS_FreeValue(ctx, prim);
+ out->present_mask |= TI_FIELD_OFFSET;
+ goto offset_done;
+ }
+ if (!ti_is_valid_plain_offset_string(str)) {
+ JS_FreeCString(ctx, str);
+ JS_FreeValue(ctx, prim);
+ JS_ThrowRangeError(ctx, "invalid offset string");
+ goto fail;
+ }
+ sign = (str[0] == '-') ? -1 : 1;
+ if (len == 3) {
+ int h = (str[1] - '0') * 10 + (str[2] - '0');
+ out->offset_ns = sign * h * 3600LL * 1000000000LL;
+ } else if (len == 5) {
+ int h = (str[1] - '0') * 10 + (str[2] - '0');
+ int m = (str[3] - '0') * 10 + (str[4] - '0');
+ out->offset_ns = sign * (h * 3600LL + m * 60LL) * 1000000000LL;
+ } else if (len == 6) {
+ int h = (str[1] - '0') * 10 + (str[2] - '0');
+ int m = (str[4] - '0') * 10 + (str[5] - '0');
+ out->offset_ns = sign * (h * 3600LL + m * 60LL) * 1000000000LL;
+ } else if (len >= 9) {
+ int h = (str[1] - '0') * 10 + (str[2] - '0');
+ int m = (str[4] - '0') * 10 + (str[5] - '0');
+ int s = (str[7] - '0') * 10 + (str[8] - '0');
+ int frac = 0, i;
+ out->offset_ns = sign * ((h * 3600LL + m * 60LL + s) * 1000000000LL);
+ if (len > 9) {
+ int frac_count = 0;
+ for (i = 10; i < (int)len; i++) {
+ frac = frac * 10 + (str[i] - '0');
+ frac_count++;
+ }
+ for (i = frac_count; i < 9; i++)
+ frac *= 10;
+ out->offset_ns += sign * frac;
+ }
+ }
+ JS_FreeCString(ctx, str);
+ }
+ JS_FreeValue(ctx, prim);
+ out->present_mask |= TI_FIELD_OFFSET;
+ }
+ }
+offset_done:
+
+ /* second */
+ if (field_mask & TI_FIELD_SECOND) {
+ v = JS_GetPropertyStr(ctx, obj, "second");
+ if (JS_IsException(v))
+ goto fail;
+ if (!JS_IsUndefined(v)) {
+ int64_t tmp;
+ if (ti_to_integer_with_truncation(ctx, v, &tmp) < 0) {
+ goto fail;
+ }
+ out->second = (int)tmp;
+ out->present_mask |= TI_FIELD_SECOND;
+ }
+ JS_FreeValue(ctx, v);
+ v = JS_UNDEFINED;
+ }
+
+ /* timeZone */
+ if (field_mask & TI_FIELD_TIMEZONE) {
+ v = JS_GetPropertyStr(ctx, obj, "timeZone");
+ if (JS_IsException(v))
+ goto fail;
+ if (!JS_IsUndefined(v)) {
+ if (!JS_IsString(v) && !JS_IsObject(v)) {
+ JS_ThrowTypeError(ctx, "timeZone must be a string or object");
+ goto fail;
+ }
+ if (JS_IsString(v)) {
+ const char *tz = JS_ToCString(ctx, v);
+ int64_t tz_offset_ns;
+ if (!tz || *tz == '\0') {
+ JS_FreeCString(ctx, tz);
+ JS_ThrowRangeError(ctx, "invalid timeZone");
+ goto fail;
+ }
+ if (ti_is_minus_zero_year(tz)) {
+ JS_FreeCString(ctx, tz);
+ JS_ThrowRangeError(ctx, "minus zero year is not allowed");
+ goto fail;
+ }
+ if (ti_parse_temporal_timezone_string(tz, &tz_offset_ns) < 0) {
+ JS_FreeCString(ctx, tz);
+ JS_ThrowRangeError(ctx, "invalid timeZone");
+ goto fail;
+ }
+ pstrcpy(out->time_zone, sizeof(out->time_zone), tz);
+ JS_FreeCString(ctx, tz);
+ } else if (JS_IsObject(v)) {
+ JSZonedDateTimeData *zdt = JS_GetOpaque(v, js_zoneddatetime_class_id);
+ if (!zdt) {
+ JS_ThrowTypeError(ctx, "timeZone must be a string or object");
+ goto fail;
+ }
+ pstrcpy(out->time_zone, sizeof(out->time_zone), zdt->timeZone);
+ }
+ JS_FreeValue(ctx, v);
+ v = JS_UNDEFINED;
+ out->present_mask |= TI_FIELD_TIMEZONE;
+ }
+ }
+
+ /* year */
+ if (field_mask & TI_FIELD_YEAR) {
+ v = JS_GetPropertyStr(ctx, obj, "year");
+ if (JS_IsException(v))
+ goto fail;
+ if (!JS_IsUndefined(v)) {
+ if (ti_is_minus_zero(v)) {
+ JS_ThrowRangeError(ctx, "minus zero year is not allowed");
+ goto fail;
+ }
+ if (ti_to_integer_with_truncation(ctx, v, &out->year) < 0) {
+ goto fail;
+ }
+ out->present_mask |= TI_FIELD_YEAR;
+ }
+ JS_FreeValue(ctx, v);
+ v = JS_UNDEFINED;
+ }
+
+ /* Check required fields */
+ {
+ static const char *field_names[] = {
+ "year", "month", "monthCode", "day", "hour", "minute", "second",
+ "millisecond", "microsecond", "nanosecond", "offset", "timeZone",
+ "calendar", "era", "eraYear"
+ };
+ uint32_t missing = required_mask & ~out->present_mask;
+ if (missing) {
+ int i = __builtin_ctz(missing);
+ JS_ThrowTypeError(ctx, "missing %s", field_names[i]);
+ goto fail;
+ }
+ }
+
+ /* Check partial requirement */
+ if (partial && !out->present_mask) {
+ JS_ThrowTypeError(ctx, "object must contain at least one property");
+ goto fail;
+ }
+
+ return 0;
+
+fail:
+ JS_FreeValue(ctx, v);
+ return -1;
+}
+
+/* Create a PlainDate from prepared fields */
+/* Resolve year, month, day from prepared fields.
+ Sets *year, *month, *day. Returns 0 on success, -1 on exception. */
+int ti_resolve_date_from_fields(JSContext *ctx, TIPreparedFields *fields, int overflow_constrain,
+ int *year, int *month, int *day, BOOL require_day)
+{
+ int has_year = (fields->present_mask & TI_FIELD_YEAR) != 0;
+ int has_era = (fields->present_mask & TI_FIELD_ERA) != 0;
+ int has_eraYear = (fields->present_mask & TI_FIELD_ERA_YEAR) != 0;
+
+ *year = (int)fields->year;
+
+ if (fields->calendar != CAL_ISO8601) {
+ if (has_era || has_eraYear) {
+ if (!has_era || !has_eraYear) {
+ JS_ThrowTypeError(ctx, "era and eraYear must both be present");
+ return -1;
+ }
+ if (!ti_calendar_requires_era(fields->calendar)) {
+ if (!has_year) {
+ JS_ThrowTypeError(ctx, "era and eraYear cannot replace year for calendar not using eras");
+ return -1;
+ }
+ /* year is present: ignore era/eraYear */
+ } else {
+ int cal_year_from_era;
+ if (ti_calendar_era_to_calendar_year(fields->calendar, fields->era, (int)fields->era_year, &cal_year_from_era) < 0) {
+ JS_ThrowRangeError(ctx, "invalid era");
+ return -1;
+ }
+ if (has_year && *year != cal_year_from_era) {
+ JS_ThrowRangeError(ctx, "year and era/eraYear must agree");
+ return -1;
+ }
+ *year = cal_year_from_era;
+ has_year = 1;
+ }
+ }
+ }
+
+ if (!has_year) {
+ JS_ThrowTypeError(ctx, "missing required property");
+ return -1;
+ }
+ if (require_day && !(fields->present_mask & TI_FIELD_DAY)) {
+ JS_ThrowTypeError(ctx, "missing required property");
+ return -1;
+ }
+ if (!(fields->present_mask & (TI_FIELD_MONTH | TI_FIELD_MONTH_CODE))) {
+ JS_ThrowTypeError(ctx, "missing required property");
+ return -1;
+ }
+
+ *month = (fields->present_mask & TI_FIELD_MONTH) ? fields->month : 0;
+ if (require_day)
+ *day = fields->day;
+
+ if (fields->present_mask & TI_FIELD_MONTH_CODE) {
+ if (!ti_calendar_validate_month_code(fields->calendar, fields->month_from_code, fields->month_code_has_l)) {
+ JS_ThrowRangeError(ctx, "monthCode is not valid for this calendar");
+ return -1;
+ }
+ {
+ int resolved = ti_calendar_month_code_to_month(fields->calendar, *year, fields->month_from_code, fields->month_code_has_l);
+ if (fields->present_mask & TI_FIELD_MONTH) {
+ if (resolved >= 0 && fields->month != resolved) {
+ JS_ThrowRangeError(ctx, "month and monthCode must agree");
+ return -1;
+ }
+ } else {
+ *month = resolved;
+ }
+ }
+ }
+
+ {
+ int max_month = ti_calendar_months_in_year(fields->calendar, *year);
+ if (*month > max_month) {
+ if (!overflow_constrain) {
+ JS_ThrowRangeError(ctx, "invalid date");
+ return -1;
+ }
+ *month = max_month;
+ } else if (*month < 1) {
+ if (!overflow_constrain) {
+ JS_ThrowRangeError(ctx, "invalid date");
+ return -1;
+ }
+ *month = 1;
+ }
+ if (require_day) {
+ int dim = ti_calendar_days_in_month(fields->calendar, *year, *month);
+ if (*day > dim) {
+ if (!overflow_constrain) {
+ JS_ThrowRangeError(ctx, "invalid date");
+ return -1;
+ }
+ *day = dim;
+ } else if (*day < 1) {
+ if (!overflow_constrain) {
+ JS_ThrowRangeError(ctx, "invalid date");
+ return -1;
+ }
+ *day = 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------ */
+/* ISO calendar date arithmetic helpers for CalendarDateUntil etc. */
+/* ------------------------------------------------------------------ */
+
+/* CalendarDateUntil for ISO8601 calendar as specified in calendar.html.
+ This uses direct arithmetic instead of loops for performance. */
+void ti_iso_calendar_date_until(int one_year, int one_month, int one_day,
+ int two_year, int two_month, int two_day,
+ TIUnit largestUnit,
+ int64_t *out_years, int64_t *out_months,
+ int64_t *out_weeks, int64_t *out_days)
+{
+ int sign;
+ int64_t years = 0, months = 0, weeks = 0, days = 0;
+ int iy, im, id;
+ int64_t remaining_days;
+
+ /* CompareISODate */
+ if (one_year < two_year) sign = -1;
+ else if (one_year > two_year) sign = 1;
+ else if (one_month < two_month) sign = -1;
+ else if (one_month > two_month) sign = 1;
+ else if (one_day < two_day) sign = -1;
+ else if (one_day > two_day) sign = 1;
+ else sign = 0;
+
+ if (out_years) *out_years = 0;
+ if (out_months) *out_months = 0;
+ if (out_weeks) *out_weeks = 0;
+ if (out_days) *out_days = 0;
+ if (sign == 0)
+ return;
+
+ sign = -sign;
+
+ if (largestUnit == TI_UNIT_YEAR) {
+ years = (int64_t)two_year - (int64_t)one_year;
+ if (sign == 1 && (two_month < one_month || (two_month == one_month && two_day < one_day)))
+ years -= 1;
+ else if (sign == -1 && (two_month > one_month || (two_month == one_month && two_day > one_day)))
+ years += 1;
+ }
+
+ if (largestUnit == TI_UNIT_YEAR || largestUnit == TI_UNIT_MONTH) {
+ int64_t iy64 = (int64_t)one_year + years;
+ int64_t im64 = (int64_t)one_month;
+ im64 = ((im64 - 1) % 12) + 1;
+ /* Balance year if months went out of range */
+ iy64 += (int64_t)floor_div64((int)(im64 - 1), 12);
+ im64 = ((im64 - 1) - floor_div64((int)(im64 - 1), 12) * 12) + 1;
+ months = ((int64_t)two_year - iy64) * 12 + ((int64_t)two_month - im64);
+ if (sign == 1 && two_day < one_day)
+ months -= 1;
+ else if (sign == -1 && two_day > one_day)
+ months += 1;
+ }
+
+ /* Compute intermediate date after adding years and months */
+ iy = one_year + (int)years;
+ im = one_month + (int)months;
+ /* BalanceISOYearMonth */
+ iy += (int)floor_div64(im - 1, 12);
+ im = (im - 1) - (int)floor_div64(im - 1, 12) * 12 + 1;
+ /* RegulateISODate with constrain */
+ id = one_day;
+ if (id < 1) id = 1;
+ if (id > pd_days_in_month(iy, im)) id = pd_days_in_month(iy, im);
+
+ remaining_days = pdt_to_ordinal_days(two_year, two_month, two_day) -
+ pdt_to_ordinal_days(iy, im, id);
+
+ if (largestUnit == TI_UNIT_WEEK) {
+ weeks = remaining_days / 7;
+ days = remaining_days % 7;
+ } else {
+ days = remaining_days;
+ }
+
+ if (out_years) *out_years = years;
+ if (out_months) *out_months = months;
+ if (out_weeks) *out_weeks = weeks;
+ if (out_days) *out_days = days;
+}
+
+int ti_iso_calendar_date_add(int year, int month, int day,
+ int64_t years, int64_t months, int64_t weeks, int64_t days,
+ int *out_year, int *out_month, int *out_day)
+{
+ int64_t y = (int64_t)year + years;
+ int64_t m = (int64_t)month + months;
+ int64_t d = (int64_t)day;
+
+ /* BalanceISOYearMonth */
+ y += floor_div64(m - 1, 12);
+ m = (m - 1) - floor_div64(m - 1, 12) * 12 + 1;
+
+ /* RegulateISODate (constrain): clamp day to month length */
+ int dim = pd_days_in_month((int)y, (int)m);
+ if (d > dim) d = dim;
+ if (d < 1) d = 1;
+
+ /* Add weeks and days, then BalanceISODate */
+ {
+ js_int128_t delta = (js_int128_t)weeks * 7 + days;
+ if (y < INT_MIN || y > INT_MAX)
+ return -1;
+ js_int128_t ordinal = pdt_to_ordinal_days((int)y, (int)m, 1);
+ ordinal += (d - 1) + delta;
+ if (ordinal < INT64_MIN || ordinal > INT64_MAX)
+ return -1;
+ {
+ int fy, fm, fd;
+ pdt_from_ordinal_days((int64_t)ordinal, &fy, &fm, &fd);
+ y = fy;
+ m = fm;
+ d = fd;
+ }
+ }
+
+ *out_year = (int)y;
+ *out_month = (int)m;
+ *out_day = (int)d;
+ return 0;
+}
+
+/* Add a duration to an ISO datetime, handling time overflow into days */
+int ti_iso_datetime_add_duration(
+ int year, int month, int day,
+ int hour, int minute, int second, int ms, int us, int ns,
+ int64_t dyears, int64_t dmonths, int64_t dweeks, int64_t ddays,
+ int64_t dhours, int64_t dminutes, int64_t dseconds,
+ int64_t dms, js_int128_t dus, js_int128_t dns,
+ int *out_year, int *out_month, int *out_day,
+ int *out_hour, int *out_minute, int *out_second,
+ int *out_ms, int *out_us, int *out_ns)
+{
+ int64_t base_sec = hour * 3600LL + minute * 60LL + second;
+ js_int128_t total_ns = (js_int128_t)base_sec * 1000000000LL + (js_int128_t)ms * 1000000LL + (js_int128_t)us * 1000LL + ns;
+ int64_t dur_sec = dhours * 3600LL + dminutes * 60LL + dseconds;
+ js_int128_t dur_ns = (js_int128_t)dur_sec * 1000000000LL + (js_int128_t)dms * 1000000LL + dus * 1000LL + dns;
+ total_ns += dur_ns;
+
+ int64_t delta_days = (int64_t)(total_ns / 86400000000000LL);
+ js_int128_t rem_ns = total_ns % 86400000000000LL;
+ if (rem_ns < 0) {
+ delta_days--;
+ rem_ns += 86400000000000LL;
+ }
+
+ *out_hour = (int)(rem_ns / 3600000000000LL);
+ rem_ns %= 3600000000000LL;
+ *out_minute = (int)(rem_ns / 60000000000LL);
+ rem_ns %= 60000000000LL;
+ *out_second = (int)(rem_ns / 1000000000LL);
+ rem_ns %= 1000000000LL;
+ *out_ms = (int)(rem_ns / 1000000LL);
+ rem_ns %= 1000000LL;
+ *out_us = (int)(rem_ns / 1000LL);
+ *out_ns = (int)(rem_ns % 1000LL);
+
+ return ti_iso_calendar_date_add(year, month, day, dyears, dmonths, dweeks, ddays + delta_days,
+ out_year, out_month, out_day);
+}
+
+/* DifferenceISODateTime for ISO calendar (no timezone) */
+int ti_iso_datetime_difference(
+ int y1, int m1, int d1, int h1, int min1, int s1, int ms1, int us1, int ns1,
+ int y2, int m2, int d2, int h2, int min2, int s2, int ms2, int us2, int ns2,
+ TIUnit largestUnit,
+ JSDurationData *out)
+{
+ int64_t time1_sec = h1 * 3600LL + min1 * 60LL + s1;
+ int64_t time2_sec = h2 * 3600LL + min2 * 60LL + s2;
+ js_int128_t time1_ns = (js_int128_t)time1_sec * 1000000000LL + (js_int128_t)ms1 * 1000000LL + (js_int128_t)us1 * 1000LL + ns1;
+ js_int128_t time2_ns = (js_int128_t)time2_sec * 1000000000LL + (js_int128_t)ms2 * 1000000LL + (js_int128_t)us2 * 1000LL + ns2;
+ js_int128_t time_diff = time2_ns - time1_ns;
+ int time_sign = (time_diff > 0) ? 1 : (time_diff < 0) ? -1 : 0;
+
+ int64_t ord1 = pdt_to_ordinal_days(y1, m1, d1);
+ int64_t ord2 = pdt_to_ordinal_days(y2, m2, d2);
+ int date_sign = (ord1 < ord2) ? -1 : (ord1 > ord2) ? 1 : 0;
+
+ int ay = y2, am = m2, ad = d2;
+
+ if (date_sign != 0 && date_sign == time_sign) {
+ /* AddDaysToISODate: use BalanceISODate, not constrain */
+ ad = d2 + time_sign;
+ am = m2;
+ ay = y2;
+ while (ad < 1) {
+ am--;
+ if (am < 1) { am = 12; ay--; }
+ ad += pd_days_in_month(ay, am);
+ }
+ while (ad > pd_days_in_month(ay, am)) {
+ ad -= pd_days_in_month(ay, am);
+ am++;
+ if (am > 12) { am = 1; ay++; }
+ }
+ time_diff -= (js_int128_t)time_sign * 86400000000000LL;
+ }
+
+ TIUnit dateLargestUnit = (largestUnit <= TI_UNIT_DAY) ? largestUnit : TI_UNIT_DAY;
+
+ int64_t years = 0, months = 0, weeks = 0, days = 0;
+ ti_iso_calendar_date_until(y1, m1, d1, ay, am, ad, dateLargestUnit,
+ &years, &months, &weeks, &days);
+
+ if (largestUnit != dateLargestUnit) {
+ /* For time-unit largestUnit, convert all calendar units to nanoseconds.
+ Use the ordinal day difference for exact conversion. */
+ int64_t total_days = pdt_to_ordinal_days(ay, am, ad) - ord1;
+ time_diff += (js_int128_t)total_days * 86400000000000LL;
+ years = months = weeks = days = 0;
+ }
+
+ memset(out, 0, sizeof(*out));
+ out->years = years;
+ out->months = months;
+ out->weeks = weeks;
+ out->days = days;
+
+ if (time_diff < 0) {
+ js_int128_t abs_time = -time_diff;
+ out->hours = -(int64_t)(abs_time / 3600000000000LL);
+ abs_time %= 3600000000000LL;
+ out->minutes = -(int64_t)(abs_time / 60000000000LL);
+ abs_time %= 60000000000LL;
+ out->seconds = -(int64_t)(abs_time / 1000000000LL);
+ abs_time %= 1000000000LL;
+ out->milliseconds = -(int64_t)(abs_time / 1000000LL);
+ abs_time %= 1000000LL;
+ out->microseconds.int128_value = -(abs_time / 1000LL);
+ out->nanoseconds.int128_value = -(abs_time % 1000LL);
+ } else {
+ out->hours = (int64_t)(time_diff / 3600000000000LL);
+ time_diff %= 3600000000000LL;
+ out->minutes = (int64_t)(time_diff / 60000000000LL);
+ time_diff %= 60000000000LL;
+ out->seconds = (int64_t)(time_diff / 1000000000LL);
+ time_diff %= 1000000000LL;
+ out->milliseconds = (int64_t)(time_diff / 1000000LL);
+ time_diff %= 1000000LL;
+ out->microseconds.int128_value = time_diff / 1000LL;
+ out->nanoseconds.int128_value = time_diff % 1000LL;
+ }
+
+ return 0;
+}
+
+/* Balance time fields in a JSDurationData based on largestUnit, matching
+ TemporalDurationFromInternal behavior. */
+void ti_balance_time_duration(JSDurationData *d, TIUnit largestUnit)
+{
+ js_int128_t total_ns = ti_duration_time_fields_to_ns(d);
+ if (largestUnit > TI_UNIT_DAY)
+ total_ns += (js_int128_t)d->days * 86400000000000LL;
+ int sign = (total_ns < 0) ? -1 : (total_ns > 0) ? 1 : 0;
+ js_int128_t abs_ns = total_ns >= 0 ? total_ns : -total_ns;
+
+ d->hours = 0;
+ d->minutes = 0;
+ d->seconds = 0;
+ d->milliseconds = 0;
+ d->microseconds.int128_value = 0;
+ d->nanoseconds.int128_value = 0;
+
+ if (sign == 0) return;
+
+ if (largestUnit <= TI_UNIT_DAY) {
+ /* Date category: balance up to days */
+ js_int128_t total_seconds = abs_ns / 1000000000LL;
+ js_int128_t ns = abs_ns % 1000000000LL;
+ js_int128_t total_minutes = total_seconds / 60;
+ js_int128_t seconds = total_seconds % 60;
+ js_int128_t total_hours = total_minutes / 60;
+ js_int128_t minutes = total_minutes % 60;
+ js_int128_t days = total_hours / 24;
+ js_int128_t hours = total_hours % 24;
+ d->days += sign * (int64_t)days;
+ d->hours = sign * (int64_t)hours;
+ d->minutes = sign * (int64_t)minutes;
+ d->seconds = sign * (int64_t)seconds;
+ d->milliseconds = sign * (int64_t)(ns / 1000000LL);
+ ns %= 1000000LL;
+ d->microseconds.int128_value = sign * (ns / 1000LL);
+ d->nanoseconds.int128_value = sign * (ns % 1000LL);
+ } else if (largestUnit == TI_UNIT_HOUR) {
+ js_int128_t total_seconds = abs_ns / 1000000000LL;
+ js_int128_t ns = abs_ns % 1000000000LL;
+ js_int128_t total_minutes = total_seconds / 60;
+ js_int128_t seconds = total_seconds % 60;
+ js_int128_t hours = total_minutes / 60;
+ js_int128_t minutes = total_minutes % 60;
+ d->hours = sign * (int64_t)hours;
+ d->minutes = sign * (int64_t)minutes;
+ d->seconds = sign * (int64_t)seconds;
+ d->milliseconds = sign * (int64_t)(ns / 1000000LL);
+ ns %= 1000000LL;
+ d->microseconds.int128_value = sign * (ns / 1000LL);
+ d->nanoseconds.int128_value = sign * (ns % 1000LL);
+ } else if (largestUnit == TI_UNIT_MINUTE) {
+ js_int128_t total_seconds = abs_ns / 1000000000LL;
+ js_int128_t ns = abs_ns % 1000000000LL;
+ js_int128_t minutes = total_seconds / 60;
+ js_int128_t seconds = total_seconds % 60;
+ d->minutes = sign * (int64_t)minutes;
+ d->seconds = sign * (int64_t)seconds;
+ d->milliseconds = sign * (int64_t)(ns / 1000000LL);
+ ns %= 1000000LL;
+ d->microseconds.int128_value = sign * (ns / 1000LL);
+ d->nanoseconds.int128_value = sign * (ns % 1000LL);
+ } else if (largestUnit == TI_UNIT_SECOND) {
+ js_int128_t total_ms = abs_ns / 1000000LL;
+ js_int128_t ns = abs_ns % 1000000LL;
+ js_int128_t seconds = total_ms / 1000;
+ js_int128_t ms = total_ms % 1000;
+ d->seconds = sign * (int64_t)seconds;
+ d->milliseconds = sign * (int64_t)ms;
+ d->microseconds.int128_value = sign * (ns / 1000LL);
+ d->nanoseconds.int128_value = sign * (ns % 1000LL);
+ } else if (largestUnit == TI_UNIT_MILLISECOND) {
+ js_int128_t total_us = abs_ns / 1000LL;
+ js_int128_t ns = abs_ns % 1000LL;
+ js_int128_t ms = total_us / 1000;
+ js_int128_t us = total_us % 1000;
+ d->milliseconds = sign * (int64_t)ms;
+ d->microseconds.int128_value = sign * us;
+ d->nanoseconds.int128_value = sign * ns;
+ } else if (largestUnit == TI_UNIT_MICROSECOND) {
+ js_int128_t us = abs_ns / 1000LL;
+ js_int128_t ns = abs_ns % 1000LL;
+ d->microseconds.int128_value = sign * us;
+ d->nanoseconds.int128_value = sign * ns;
+ } else {
+ /* Nanosecond largestUnit: keep total in nanoseconds */
+ d->nanoseconds.int128_value = sign * abs_ns;
+ }
+}
+
+/* Calendar-aware datetime difference for non-ISO calendars.
+ The date fields are interpreted as calendar fields. */
+int ti_calendar_datetime_difference(
+ CalendarType cal,
+ int y1, int m1, int d1, int h1, int min1, int s1, int ms1, int us1, int ns1,
+ int y2, int m2, int d2, int h2, int min2, int s2, int ms2, int us2, int ns2,
+ TIUnit largestUnit,
+ JSDurationData *out)
+{
+ int64_t time1_sec = h1 * 3600LL + min1 * 60LL + s1;
+ int64_t time2_sec = h2 * 3600LL + min2 * 60LL + s2;
+ js_int128_t time1_ns = (js_int128_t)time1_sec * 1000000000LL + (js_int128_t)ms1 * 1000000LL + (js_int128_t)us1 * 1000LL + ns1;
+ js_int128_t time2_ns = (js_int128_t)time2_sec * 1000000000LL + (js_int128_t)ms2 * 1000000LL + (js_int128_t)us2 * 1000LL + ns2;
+ js_int128_t time_diff = time2_ns - time1_ns;
+ int time_sign = (time_diff > 0) ? 1 : (time_diff < 0) ? -1 : 0;
+
+ int date_sign;
+ if (y1 != y2) date_sign = (y1 < y2) ? -1 : 1;
+ else if (m1 != m2) date_sign = (m1 < m2) ? -1 : 1;
+ else if (d1 != d2) date_sign = (d1 < d2) ? -1 : 1;
+ else date_sign = 0;
+
+ int ay = y2, am = m2, ad = d2;
+
+ if (date_sign != 0 && date_sign == time_sign) {
+ ad = d2 + time_sign;
+ if (time_sign > 0) {
+ int dim = ti_calendar_days_in_month(cal, y2, m2);
+ if (ad > dim) {
+ ad = 1;
+ am = m2 + 1;
+ if (am > ti_calendar_months_in_year(cal, y2)) {
+ am = 1;
+ ay = y2 + 1;
+ }
+ }
+ } else {
+ if (ad < 1) {
+ am = m2 - 1;
+ if (am < 1) {
+ ay = y2 - 1;
+ am = ti_calendar_months_in_year(cal, ay);
+ }
+ ad = ti_calendar_days_in_month(cal, ay, am);
+ }
+ }
+ time_diff -= (js_int128_t)time_sign * 86400000000000LL;
+ }
+
+ TIUnit dateLargestUnit = (largestUnit <= TI_UNIT_DAY) ? largestUnit : TI_UNIT_DAY;
+
+ int64_t years = 0, months = 0, weeks = 0, days = 0;
+
+ if ((cal == CAL_CHINESE || cal == CAL_DANGI || cal == CAL_HEBREW) &&
+ (largestUnit == TI_UNIT_YEAR || largestUnit == TI_UNIT_MONTH)) {
+ int mc1, has_l1, mc2, has_l2;
+ ti_calendar_month_to_month_code(cal, y1, m1, &mc1, &has_l1);
+ ti_calendar_month_to_month_code(cal, ay, am, &mc2, &has_l2);
+ ti_calendar_date_until_with_monthcode(cal,
+ y1, m1, d1, mc1, 1, has_l1,
+ ay, am, ad, mc2, 1, has_l2, dateLargestUnit,
+ &years, &months, &weeks, &days);
+ } else if (cal != CAL_ISO8601 && cal != CAL_GREGORY) {
+ ti_calendar_date_until(cal, y1, m1, d1, ay, am, ad, dateLargestUnit,
+ &years, &months, &weeks, &days);
+ } else {
+ ti_iso_calendar_date_until(y1, m1, d1, ay, am, ad, dateLargestUnit,
+ &years, &months, &weeks, &days);
+ }
+
+ if (largestUnit != dateLargestUnit) {
+ int64_t total_days = 0;
+ int64_t dummy_y = 0, dummy_m = 0, dummy_w = 0;
+ if (cal == CAL_CHINESE || cal == CAL_DANGI || cal == CAL_HEBREW) {
+ int mc1, has_l1, mc2, has_l2;
+ ti_calendar_month_to_month_code(cal, y1, m1, &mc1, &has_l1);
+ ti_calendar_month_to_month_code(cal, ay, am, &mc2, &has_l2);
+ ti_calendar_date_until_with_monthcode(cal,
+ y1, m1, d1, mc1, 1, has_l1,
+ ay, am, ad, mc2, 1, has_l2, TI_UNIT_DAY,
+ &dummy_y, &dummy_m, &dummy_w, &total_days);
+ } else {
+ ti_calendar_date_until(cal, y1, m1, d1, ay, am, ad, TI_UNIT_DAY,
+ &dummy_y, &dummy_m, &dummy_w, &total_days);
+ }
+ time_diff += (js_int128_t)total_days * 86400000000000LL;
+ years = months = weeks = days = 0;
+ }
+
+ memset(out, 0, sizeof(*out));
+ out->years = years;
+ out->months = months;
+ out->weeks = weeks;
+ out->days = days;
+
+ if (time_diff < 0) {
+ js_int128_t abs_time = -time_diff;
+ out->hours = -(int64_t)(abs_time / 3600000000000LL);
+ abs_time %= 3600000000000LL;
+ out->minutes = -(int64_t)(abs_time / 60000000000LL);
+ abs_time %= 60000000000LL;
+ out->seconds = -(int64_t)(abs_time / 1000000000LL);
+ abs_time %= 1000000000LL;
+ out->milliseconds = -(int64_t)(abs_time / 1000000LL);
+ abs_time %= 1000000LL;
+ out->microseconds.int128_value = -(abs_time / 1000LL);
+ out->nanoseconds.int128_value = -(abs_time % 1000LL);
+ } else {
+ out->hours = (int64_t)(time_diff / 3600000000000LL);
+ time_diff %= 3600000000000LL;
+ out->minutes = (int64_t)(time_diff / 60000000000LL);
+ time_diff %= 60000000000LL;
+ out->seconds = (int64_t)(time_diff / 1000000000LL);
+ time_diff %= 1000000000LL;
+ out->milliseconds = (int64_t)(time_diff / 1000000LL);
+ time_diff %= 1000000LL;
+ out->microseconds.int128_value = time_diff / 1000LL;
+ out->nanoseconds.int128_value = time_diff % 1000LL;
+ }
+
+ return 0;
+}
+
+/* Round a duration relative to an ISO datetime. For ISO calendar only. */
+int ti_round_relative_duration_iso(
+ JSContext *ctx,
+ int rel_year, int rel_month, int rel_day,
+ int rel_hour, int rel_minute, int rel_second,
+ int rel_ms, int rel_us, int rel_ns,
+ const JSDurationData *duration,
+ TIUnit largestUnit, TIUnit smallestUnit,
+ int64_t increment, TIRoundingMode roundingMode,
+ BOOL has_timeZone,
+ JSDurationData *out)
+{
+ int end_year, end_month, end_day, end_hour, end_minute, end_second, end_ms, end_us, end_ns;
+ js_int128_t us_val = duration->microseconds.int128_value;
+ js_int128_t ns_val = duration->nanoseconds.int128_value;
+ JSDurationData rounded = {0};
+
+ /* Compute end = relativeTo + duration */
+ if (ti_iso_datetime_add_duration(
+ rel_year, rel_month, rel_day, rel_hour, rel_minute, rel_second, rel_ms, rel_us, rel_ns,
+ duration->years, duration->months, duration->weeks, duration->days,
+ duration->hours, duration->minutes, duration->seconds,
+ duration->milliseconds, us_val, ns_val,
+ &end_year, &end_month, &end_day, &end_hour, &end_minute, &end_second, &end_ms, &end_us, &end_ns) < 0) {
+ JS_ThrowRangeError(ctx, "rounded date outside valid ISO range");
+ return -1;
+ }
+
+ if (!ti_is_date_within_iso_limits(end_year, end_month, end_day)) {
+ JS_ThrowRangeError(ctx, "rounded date outside valid ISO range");
+ return -1;
+ }
+
+ if (smallestUnit == TI_UNIT_YEAR || smallestUnit == TI_UNIT_MONTH ||
+ smallestUnit == TI_UNIT_WEEK || (has_timeZone && smallestUnit == TI_UNIT_DAY)) {
+ /* Calendar unit rounding (day is only a calendar unit for ZonedDateTime) */
+ int64_t ry, rm, rw, rd;
+ int64_t rel_time_ns = (rel_hour * 3600LL + rel_minute * 60LL + rel_second) * 1000000000LL
+ + rel_ms * 1000000LL + rel_us * 1000LL + rel_ns;
+ int64_t dest_time_ns = (end_hour * 3600LL + end_minute * 60LL + end_second) * 1000000000LL
+ + end_ms * 1000000LL + end_us * 1000LL + end_ns;
+
+ /* Compute the normalized difference between rel and end, then round
+ that. This is necessary because the input duration may not be in
+ normalized form (e.g. P5Y6M7W8D from Duration.prototype.round). */
+ JSDurationData diff = {0};
+ ti_iso_datetime_difference(rel_year, rel_month, rel_day, rel_hour, rel_minute, rel_second, rel_ms, rel_us, rel_ns,
+ end_year, end_month, end_day, end_hour, end_minute, end_second, end_ms, end_us, end_ns,
+ largestUnit, &diff);
+
+ if (ti_round_iso_date_duration(ctx, rel_year, rel_month, rel_day,
+ end_year, end_month, end_day,
+ rel_time_ns, dest_time_ns,
+ diff.years, diff.months, diff.weeks, diff.days,
+ largestUnit, smallestUnit, increment, roundingMode,
+ 0,
+ has_timeZone,
+ &ry, &rm, &rw, &rd) < 0)
+ return -1;
+
+ memset(&rounded, 0, sizeof(rounded));
+ rounded.years = ry;
+ rounded.months = rm;
+ rounded.weeks = rw;
+ rounded.days = rd;
+ } else {
+ /* Time unit rounding */
+ js_int128_t day_time_ns;
+ if (has_timeZone) {
+ /* For ZonedDateTime, days are kept separate because day length
+ varies due to timezone offsets. Only round the time part. */
+ day_time_ns = ti_duration_time_fields_to_ns(duration);
+ } else {
+ day_time_ns = (js_int128_t)duration->days * 86400000000000LL;
+ day_time_ns += ti_duration_time_fields_to_ns(duration);
+ }
+
+ js_int128_t unit_ns;
+ switch (smallestUnit) {
+ case TI_UNIT_DAY: unit_ns = 86400000000000LL; break;
+ case TI_UNIT_HOUR: unit_ns = 3600000000000LL; break;
+ case TI_UNIT_MINUTE: unit_ns = 60000000000LL; break;
+ case TI_UNIT_SECOND: unit_ns = 1000000000LL; break;
+ case TI_UNIT_MILLISECOND: unit_ns = 1000000LL; break;
+ case TI_UNIT_MICROSECOND: unit_ns = 1000LL; break;
+ case TI_UNIT_NANOSECOND: unit_ns = 1LL; break;
+ default: unit_ns = 1LL; break;
+ }
+
+ js_int128_t rounded_ns = ti_round_to_increment128(day_time_ns, unit_ns * increment, roundingMode);
+
+ int64_t new_days;
+ js_int128_t new_time_ns;
+ if (largestUnit <= TI_UNIT_DAY) {
+ /* Date category: split into days and time using truncate toward zero */
+ new_days = (int64_t)(rounded_ns / 86400000000000LL);
+ new_time_ns = rounded_ns % 86400000000000LL;
+ } else {
+ /* Time category: keep everything in time */
+ new_days = 0;
+ new_time_ns = rounded_ns;
+ }
+
+ memset(&rounded, 0, sizeof(rounded));
+ rounded.years = duration->years;
+ rounded.months = duration->months;
+ rounded.weeks = duration->weeks;
+ if (has_timeZone) {
+ rounded.days = duration->days + new_days;
+ } else {
+ rounded.days = new_days;
+ }
+
+ if (new_time_ns < 0) {
+ js_int128_t abs_time = -new_time_ns;
+ if (TI_UNIT_HOUR >= largestUnit) {
+ rounded.hours = -(int64_t)(abs_time / 3600000000000LL);
+ abs_time %= 3600000000000LL;
+ }
+ if (TI_UNIT_MINUTE >= largestUnit) {
+ rounded.minutes = -(int64_t)(abs_time / 60000000000LL);
+ abs_time %= 60000000000LL;
+ }
+ if (TI_UNIT_SECOND >= largestUnit) {
+ rounded.seconds = -(int64_t)(abs_time / 1000000000LL);
+ abs_time %= 1000000000LL;
+ }
+ if (TI_UNIT_MILLISECOND >= largestUnit) {
+ rounded.milliseconds = -(int64_t)(abs_time / 1000000LL);
+ abs_time %= 1000000LL;
+ }
+ if (TI_UNIT_MICROSECOND >= largestUnit) {
+ rounded.microseconds.int128_value = -(abs_time / 1000LL);
+ }
+ if (TI_UNIT_NANOSECOND >= largestUnit) {
+ if (largestUnit == TI_UNIT_NANOSECOND && smallestUnit == TI_UNIT_NANOSECOND)
+ rounded.nanoseconds.int128_value = -abs_time;
+ else
+ rounded.nanoseconds.int128_value = -(abs_time % 1000LL);
+ }
+ } else {
+ if (TI_UNIT_HOUR >= largestUnit) {
+ rounded.hours = (int64_t)(new_time_ns / 3600000000000LL);
+ new_time_ns %= 3600000000000LL;
+ }
+ if (TI_UNIT_MINUTE >= largestUnit) {
+ rounded.minutes = (int64_t)(new_time_ns / 60000000000LL);
+ new_time_ns %= 60000000000LL;
+ }
+ if (TI_UNIT_SECOND >= largestUnit) {
+ rounded.seconds = (int64_t)(new_time_ns / 1000000000LL);
+ new_time_ns %= 1000000000LL;
+ }
+ if (TI_UNIT_MILLISECOND >= largestUnit) {
+ rounded.milliseconds = (int64_t)(new_time_ns / 1000000LL);
+ new_time_ns %= 1000000LL;
+ }
+ if (TI_UNIT_MICROSECOND >= largestUnit) {
+ rounded.microseconds.int128_value = new_time_ns / 1000LL;
+ }
+ if (TI_UNIT_NANOSECOND >= largestUnit) {
+ if (largestUnit == TI_UNIT_NANOSECOND && smallestUnit == TI_UNIT_NANOSECOND)
+ rounded.nanoseconds.int128_value = new_time_ns;
+ else
+ rounded.nanoseconds.int128_value = new_time_ns % 1000LL;
+ }
+ }
+ }
+
+ if (largestUnit <= TI_UNIT_DAY) {
+ /* Date category largestUnit: recompute by adding rounded duration back
+ to relativeTo so that calendar constraints and unit conversions are
+ applied correctly (e.g., days -> years). */
+ /* For calendar-unit rounding (year/month/week), return the rounded
+ duration directly. Recomputing via CalendarDateUntil can collapse
+ the rounded unit due to calendar constraints (e.g. Feb 29 + 1 year
+ becomes Feb 28, and diffing gives 11 months 30 days instead of 1
+ year). The spec's NudgeToCalendarUnit returns the nudged duration
+ directly, not via a diff recomputation. */
+ if (smallestUnit == TI_UNIT_YEAR || smallestUnit == TI_UNIT_MONTH ||
+ smallestUnit == TI_UNIT_WEEK) {
+ /* ISO calendar balancing: bubble months into years when
+ largestUnit permits. */
+ if (largestUnit == TI_UNIT_YEAR && rounded.months != 0) {
+ int64_t years_from_months = rounded.months / 12;
+ rounded.years += years_from_months;
+ rounded.months -= years_from_months * 12;
+ }
+ *out = rounded;
+ return 0;
+ }
+ int ny, nm, nd, nh, nmin, ns, nms, nus, nns;
+ js_int128_t r_us = rounded.microseconds.int128_value;
+ js_int128_t r_ns = rounded.nanoseconds.int128_value;
+ if (ti_iso_datetime_add_duration(
+ rel_year, rel_month, rel_day, rel_hour, rel_minute, rel_second, rel_ms, rel_us, rel_ns,
+ rounded.years, rounded.months, rounded.weeks, rounded.days,
+ rounded.hours, rounded.minutes, rounded.seconds,
+ rounded.milliseconds, r_us, r_ns,
+ &ny, &nm, &nd, &nh, &nmin, &ns, &nms, &nus, &nns) < 0) {
+ JS_ThrowRangeError(ctx, "rounded date outside valid ISO range");
+ return -1;
+ }
+
+ return ti_iso_datetime_difference(
+ rel_year, rel_month, rel_day, rel_hour, rel_minute, rel_second, rel_ms, rel_us, rel_ns,
+ ny, nm, nd, nh, nmin, ns, nms, nus, nns,
+ largestUnit, out);
+ } else {
+ /* Time category largestUnit: return directly */
+ *out = rounded;
+ return 0;
+ }
+}
+
+int ti_is_date_within_iso_limits(int year, int month, int day)
+{
+ if (year < -271821 || year > 275760) return 0;
+ if (year == -271821 && (month < 4 || (month == 4 && day < 19))) return 0;
+ if (year == 275760 && (month > 9 || (month == 9 && day > 13))) return 0;
+ return 1;
+}
+
+int ti_round_iso_date_duration(JSContext *ctx,
+ int oy, int om, int od,
+ int dy, int dm, int dd,
+ int64_t rel_time_ns, int64_t dest_time_ns,
+ int64_t years, int64_t months, int64_t weeks, int64_t days,
+ TIUnit largestUnit, TIUnit smallestUnit,
+ int64_t increment, TIRoundingMode rounding_mode,
+ int do_bubble,
+ BOOL has_timeZone,
+ int64_t *out_years, int64_t *out_months,
+ int64_t *out_weeks, int64_t *out_days)
+{
+ int sign;
+ int64_t r1, r2;
+ int64_t start_years, start_months, start_weeks, start_days;
+ int64_t end_years, end_months, end_weeks, end_days;
+ int sy, sm, sd, ey, em, ed;
+ int64_t start_ord, end_ord, dest_ord;
+ js_int128_t numerator, denominator;
+ int cmp;
+ int even;
+ int64_t ry, rm, rw, rd;
+ int choice;
+
+ /* Determine sign from the relationship between rel and dest.
+ Per spec RoundRelativeDuration step 2, if duration sign is 0, set sign to 1. */
+ {
+ int64_t rel_ord = pdt_to_ordinal_days(oy, om, od);
+ int64_t inner_dest_ord = pdt_to_ordinal_days(dy, dm, dd);
+ if (rel_ord < inner_dest_ord || (rel_ord == inner_dest_ord && rel_time_ns < dest_time_ns))
+ sign = 1;
+ else if (rel_ord > inner_dest_ord || (rel_ord == inner_dest_ord && rel_time_ns > dest_time_ns))
+ sign = -1;
+ else
+ sign = 1;
+ }
+
+ /* Compute r1 (truncated toward zero) and r2 (next multiple in sign direction) */
+ switch (smallestUnit) {
+ case TI_UNIT_YEAR: {
+ r1 = (years / increment) * increment;
+ r2 = r1 + increment * sign;
+ start_years = r1; start_months = 0; start_weeks = 0; start_days = 0;
+ end_years = r2; end_months = 0; end_weeks = 0; end_days = 0;
+ break;
+ }
+ case TI_UNIT_MONTH: {
+ r1 = (months / increment) * increment;
+ r2 = r1 + increment * sign;
+ start_years = years; start_months = r1; start_weeks = 0; start_days = 0;
+ end_years = years; end_months = r2; end_weeks = 0; end_days = 0;
+ break;
+ }
+ case TI_UNIT_WEEK: {
+ int wsy, wsm, wsd, wey, wem, wed;
+ int64_t wweeks, wdays;
+ /* weeksStart = origin + years + months */
+ if (ti_iso_calendar_date_add(oy, om, od, years, months, 0, 0, &wsy, &wsm, &wsd) < 0 ||
+ ti_iso_calendar_date_add(wsy, wsm, wsd, 0, 0, 0, days, &wey, &wem, &wed) < 0) {
+ JS_ThrowRangeError(ctx, "rounded date outside valid ISO range");
+ return -1;
+ }
+ /* CalendarDateUntil(weeksStart, weeksEnd, week) */
+ ti_iso_calendar_date_until(wsy, wsm, wsd, wey, wem, wed, TI_UNIT_WEEK,
+ &wweeks, &wdays, NULL, NULL);
+ r1 = ((weeks + wweeks) / increment) * increment;
+ r2 = r1 + increment * sign;
+ start_years = years; start_months = months; start_weeks = r1; start_days = 0;
+ end_years = years; end_months = months; end_weeks = r2; end_days = 0;
+ break;
+ }
+ case TI_UNIT_DAY: {
+ r1 = (days / increment) * increment;
+ r2 = r1 + increment * sign;
+ start_years = years; start_months = months; start_weeks = weeks; start_days = r1;
+ end_years = years; end_months = months; end_weeks = weeks; end_days = r2;
+ break;
+ }
+ default:
+ *out_years = years; *out_months = months; *out_weeks = weeks; *out_days = days;
+ return 0;
+ }
+
+ /* Convert startDuration and endDuration to ordinal days */
+ if (ti_iso_calendar_date_add(oy, om, od, start_years, start_months, start_weeks, start_days, &sy, &sm, &sd) < 0 ||
+ ti_iso_calendar_date_add(oy, om, od, end_years, end_months, end_weeks, end_days, &ey, &em, &ed) < 0) {
+ JS_ThrowRangeError(ctx, "rounded date outside valid ISO range");
+ return -1;
+ }
+ if (has_timeZone) {
+ int64_t start_epoch_days = pdt_to_ordinal_days(sy, sm, sd) - 719162;
+ int64_t end_epoch_days = pdt_to_ordinal_days(ey, em, ed) - 719162;
+ int64_t time_sec = rel_time_ns / 1000000000LL;
+ int time_nsec = (int)(rel_time_ns % 1000000000LL);
+ if (time_nsec < 0) {
+ time_nsec += 1000000000;
+ time_sec--;
+ }
+ JSTimeSpec start_ts = { start_epoch_days * 86400LL + time_sec, (uint32_t)time_nsec };
+ JSTimeSpec end_ts = { end_epoch_days * 86400LL + time_sec, (uint32_t)time_nsec };
+ if (!is_valid_epoch_timespec(&start_ts) || !is_valid_epoch_timespec(&end_ts)) {
+ JS_ThrowRangeError(ctx, "rounded date outside valid instant range");
+ return -1;
+ }
+ } else {
+ if (!ti_is_date_within_iso_limits(sy, sm, sd) || !ti_is_date_within_iso_limits(ey, em, ed)) {
+ JS_ThrowRangeError(ctx, "rounded date outside valid ISO range");
+ return -1;
+ }
+ }
+ start_ord = pdt_to_ordinal_days(sy, sm, sd);
+ end_ord = pdt_to_ordinal_days(ey, em, ed);
+ dest_ord = pdt_to_ordinal_days(dy, dm, dd);
+
+ /* Check if dest is within [start, end] (for sign=1) or [end, start] (for sign=-1).
+ Loop until dest is bracketed, shifting r1/r2 by increment each time. */
+ {
+ int iter = 0;
+ if (sign == 1) {
+ while (1) {
+ int start_le_dest = (start_ord < dest_ord) || (start_ord == dest_ord && rel_time_ns <= dest_time_ns);
+ int dest_le_end = (dest_ord < end_ord) || (dest_ord == end_ord && dest_time_ns <= rel_time_ns);
+ if (start_le_dest && dest_le_end)
+ break;
+ if (++iter > 10000) {
+ JS_ThrowRangeError(ctx, "rounded date outside valid ISO range");
+ return -1;
+ }
+ r1 = r2;
+ r2 = r1 + increment * sign;
+ switch (smallestUnit) {
+ case TI_UNIT_YEAR: start_years = r1; end_years = r2; break;
+ case TI_UNIT_MONTH: start_months = r1; end_months = r2; break;
+ case TI_UNIT_WEEK: start_weeks = r1; end_weeks = r2; break;
+ case TI_UNIT_DAY: start_days = r1; end_days = r2; break;
+ default: break;
+ }
+ if (ti_iso_calendar_date_add(oy, om, od, start_years, start_months, start_weeks, start_days, &sy, &sm, &sd) < 0 ||
+ ti_iso_calendar_date_add(oy, om, od, end_years, end_months, end_weeks, end_days, &ey, &em, &ed) < 0) {
+ JS_ThrowRangeError(ctx, "rounded date outside valid ISO range");
+ return -1;
+ }
+ if (has_timeZone) {
+ int64_t start_epoch_days = pdt_to_ordinal_days(sy, sm, sd) - 719162;
+ int64_t end_epoch_days = pdt_to_ordinal_days(ey, em, ed) - 719162;
+ int64_t time_sec = rel_time_ns / 1000000000LL;
+ int time_nsec = (int)(rel_time_ns % 1000000000LL);
+ if (time_nsec < 0) {
+ time_nsec += 1000000000;
+ time_sec--;
+ }
+ JSTimeSpec start_ts = { start_epoch_days * 86400LL + time_sec, (uint32_t)time_nsec };
+ JSTimeSpec end_ts = { end_epoch_days * 86400LL + time_sec, (uint32_t)time_nsec };
+ if (!is_valid_epoch_timespec(&start_ts) || !is_valid_epoch_timespec(&end_ts)) {
+ JS_ThrowRangeError(ctx, "rounded date outside valid instant range");
+ return -1;
+ }
+ } else {
+ if (!ti_is_date_within_iso_limits(sy, sm, sd) || !ti_is_date_within_iso_limits(ey, em, ed)) {
+ JS_ThrowRangeError(ctx, "rounded date outside valid ISO range");
+ return -1;
+ }
+ }
+ start_ord = pdt_to_ordinal_days(sy, sm, sd);
+ end_ord = pdt_to_ordinal_days(ey, em, ed);
+ }
+ } else {
+ while (1) {
+ int end_le_dest = (end_ord < dest_ord) || (end_ord == dest_ord && rel_time_ns <= dest_time_ns);
+ int dest_le_start = (dest_ord < start_ord) || (dest_ord == start_ord && dest_time_ns <= rel_time_ns);
+ if (end_le_dest && dest_le_start)
+ break;
+ if (++iter > 10000) {
+ JS_ThrowRangeError(ctx, "rounded date outside valid ISO range");
+ return -1;
+ }
+ r1 = r2;
+ r2 = r1 + increment * sign;
+ switch (smallestUnit) {
+ case TI_UNIT_YEAR: start_years = r1; end_years = r2; break;
+ case TI_UNIT_MONTH: start_months = r1; end_months = r2; break;
+ case TI_UNIT_WEEK: start_weeks = r1; end_weeks = r2; break;
+ case TI_UNIT_DAY: start_days = r1; end_days = r2; break;
+ default: break;
+ }
+ if (ti_iso_calendar_date_add(oy, om, od, start_years, start_months, start_weeks, start_days, &sy, &sm, &sd) < 0 ||
+ ti_iso_calendar_date_add(oy, om, od, end_years, end_months, end_weeks, end_days, &ey, &em, &ed) < 0) {
+ JS_ThrowRangeError(ctx, "rounded date outside valid ISO range");
+ return -1;
+ }
+ if (has_timeZone) {
+ int64_t start_epoch_days = pdt_to_ordinal_days(sy, sm, sd) - 719162;
+ int64_t end_epoch_days = pdt_to_ordinal_days(ey, em, ed) - 719162;
+ int64_t time_sec = rel_time_ns / 1000000000LL;
+ int time_nsec = (int)(rel_time_ns % 1000000000LL);
+ if (time_nsec < 0) {
+ time_nsec += 1000000000;
+ time_sec--;
+ }
+ JSTimeSpec start_ts = { start_epoch_days * 86400LL + time_sec, (uint32_t)time_nsec };
+ JSTimeSpec end_ts = { end_epoch_days * 86400LL + time_sec, (uint32_t)time_nsec };
+ if (!is_valid_epoch_timespec(&start_ts) || !is_valid_epoch_timespec(&end_ts)) {
+ JS_ThrowRangeError(ctx, "rounded date outside valid instant range");
+ return -1;
+ }
+ } else {
+ if (!ti_is_date_within_iso_limits(sy, sm, sd) || !ti_is_date_within_iso_limits(ey, em, ed)) {
+ JS_ThrowRangeError(ctx, "rounded date outside valid ISO range");
+ return -1;
+ }
+ }
+ start_ord = pdt_to_ordinal_days(sy, sm, sd);
+ end_ord = pdt_to_ordinal_days(ey, em, ed);
+ }
+ }
+ }
+
+ if (start_ord == end_ord) {
+ *out_years = start_years; *out_months = start_months; *out_weeks = start_weeks; *out_days = start_days;
+ return 0;
+ }
+
+ /* Compute numerator and denominator in nanoseconds */
+ {
+ js_int128_t day_ns = 86400000000000LL;
+ if (sign == 1) {
+ numerator = (js_int128_t)(dest_ord - start_ord) * day_ns + (dest_time_ns - rel_time_ns);
+ denominator = (js_int128_t)(end_ord - start_ord) * day_ns;
+ } else {
+ numerator = (js_int128_t)(start_ord - dest_ord) * day_ns + (rel_time_ns - dest_time_ns);
+ denominator = (js_int128_t)(start_ord - end_ord) * day_ns;
+ }
+ }
+
+ /* cmp = sign( abs(2*numerator) - abs(denominator) ) */
+ {
+ js_int128_t twice_num = numerator >= 0 ? numerator * 2 : -numerator * 2;
+ js_int128_t abs_den = denominator >= 0 ? denominator : -denominator;
+ if (twice_num < abs_den) cmp = -1;
+ else if (twice_num > abs_den) cmp = 1;
+ else cmp = 0;
+ }
+
+ /* even = (abs(r1) / increment) % 2 == 0 */
+ {
+ int64_t abs_r1 = r1 >= 0 ? r1 : -r1;
+ even = (abs_r1 / increment) % 2 == 0;
+ }
+
+ /* Apply unsigned rounding mode */
+ {
+ int unsigned_mode;
+ switch (rounding_mode) {
+ case ROUND_CEIL: unsigned_mode = (sign < 0) ? 0 : 1; break;
+ case ROUND_FLOOR: unsigned_mode = (sign < 0) ? 1 : 0; break;
+ case ROUND_EXPAND: unsigned_mode = 1; break;
+ case ROUND_TRUNC: unsigned_mode = 0; break;
+ case ROUND_HALF_CEIL: unsigned_mode = (sign < 0) ? 2 : 3; break;
+ case ROUND_HALF_FLOOR: unsigned_mode = (sign < 0) ? 3 : 2; break;
+ case ROUND_HALF_EXPAND: unsigned_mode = 3; break;
+ case ROUND_HALF_TRUNC: unsigned_mode = 2; break;
+ case ROUND_HALF_EVEN: unsigned_mode = 4; break;
+ default: unsigned_mode = 3; break;
+ }
+
+ if (numerator == 0) {
+ choice = 0;
+ } else if (numerator == denominator) {
+ choice = 1;
+ } else {
+ switch (unsigned_mode) {
+ case 0: /* zero */ choice = 0; break;
+ case 1: /* infinity */ choice = 1; break;
+ case 2: /* halfZero */
+ if (cmp < 0) choice = 0;
+ else if (cmp > 0) choice = 1;
+ else choice = 0;
+ break;
+ case 3: /* halfInfinity */
+ if (cmp < 0) choice = 0;
+ else if (cmp > 0) choice = 1;
+ else choice = 1;
+ break;
+ case 4: /* halfEven */
+ if (cmp < 0) choice = 0;
+ else if (cmp > 0) choice = 1;
+ else choice = even ? 0 : 1;
+ break;
+ default: choice = 1; break;
+ }
+ }
+ }
+
+ if (choice == 0) {
+ ry = start_years; rm = start_months; rw = start_weeks; rd = start_days;
+ } else {
+ ry = end_years; rm = end_months; rw = end_weeks; rd = end_days;
+ }
+
+ if (do_bubble && choice == 1 && smallestUnit != TI_UNIT_WEEK && smallestUnit != TI_UNIT_DAY) {
+ int by, bm, bd;
+ if (ti_iso_calendar_date_add(oy, om, od, ry, rm, rw, rd, &by, &bm, &bd) < 0 ||
+ !ti_is_date_within_iso_limits(by, bm, bd)) {
+ JS_ThrowRangeError(ctx, "rounded date outside valid ISO range");
+ return -1;
+ }
+ ti_iso_calendar_date_until(oy, om, od, by, bm, bd, largestUnit,
+ out_years, out_months, out_weeks, out_days);
+ } else {
+ *out_years = ry;
+ *out_months = rm;
+ *out_weeks = rw;
+ *out_days = rd;
+ }
+ return 0;
+}
+
+static const JSCFunctionListEntry js_temporal_funcs[] = {
+ JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Temporal", JS_PROP_CONFIGURABLE),
+};
+
+static JSValue js_date_toTemporalInstant(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ (void)argc;
+ (void)argv;
+ double v;
+ int64_t secs;
+ int32_t nsecs;
+ js_int128_t total_ns;
+ JSTimeSpec ts;
+
+ if (JS_ThisDateValue(ctx, &v, this_val))
+ return JS_EXCEPTION;
+ if (isnan(v))
+ return JS_ThrowRangeError(ctx, "invalid Date");
+
+ total_ns = (js_int128_t)(int64_t)v * 1000000LL;
+ secs = (int64_t)(total_ns / 1000000000LL);
+ nsecs = (int32_t)(total_ns % 1000000000LL);
+ if (nsecs < 0) {
+ secs--;
+ nsecs += 1000000000;
+ }
+ ts.secs = secs;
+ ts.nsecs = (uint32_t)nsecs;
+ return js_create_instant(ctx, &ts);
+}
+
+/* Helper for Temporal.prototype.toLocaleString using Intl.DateTimeFormat.
+ Falls back to toString_func if Intl is not available. */
+JSValue ti_temporal_toLocaleString(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv,
+ int default_mode,
+ JSValue (*toString_func)(JSContext *, JSValueConst, int, JSValueConst *))
+{
+ JSValue ctor = JS_GetContextValue(ctx, JS_INTL_CTOR_DATETIMEFORMAT);
+ JSValue new_argv[2];
+ JSValue dtf, method, ret;
+
+ if (JS_IsNull(ctor) || JS_IsUndefined(ctor)) {
+ JS_FreeValue(ctx, ctor);
+ return toString_func(ctx, this_val, 0, NULL);
+ }
+
+ new_argv[0] = argc > 0 ? JS_DupValue(ctx, argv[0]) : JS_UNDEFINED;
+ new_argv[1] = argc > 1 ? JS_DupValue(ctx, argv[1]) : JS_UNDEFINED;
+
+ if (JS_IsUndefined(new_argv[1]) || JS_IsNull(new_argv[1])) {
+ JS_FreeValue(ctx, new_argv[1]);
+ new_argv[1] = JS_NewObject(ctx);
+ if (JS_IsException(new_argv[1])) {
+ JS_FreeValue(ctx, new_argv[0]);
+ JS_FreeValue(ctx, ctor);
+ return JS_EXCEPTION;
+ }
+ }
+
+ if (JS_IsObject(new_argv[1])) {
+ int has_date = js_intl_options_has_date_fields(ctx, new_argv[1]);
+ int has_time = js_intl_options_has_time_fields(ctx, new_argv[1]);
+ if (has_date < 0 || has_time < 0) {
+ JS_FreeValue(ctx, new_argv[0]);
+ JS_FreeValue(ctx, new_argv[1]);
+ JS_FreeValue(ctx, ctor);
+ return JS_EXCEPTION;
+ }
+ JSValue ds_val = JS_GetPropertyStr(ctx, new_argv[1], "dateStyle");
+ if (JS_IsException(ds_val)) {
+ JS_FreeValue(ctx, ds_val);
+ JS_FreeValue(ctx, new_argv[0]);
+ JS_FreeValue(ctx, new_argv[1]);
+ JS_FreeValue(ctx, ctor);
+ return JS_EXCEPTION;
+ }
+ JSValue ts_val = JS_GetPropertyStr(ctx, new_argv[1], "timeStyle");
+ if (JS_IsException(ts_val)) {
+ JS_FreeValue(ctx, ds_val);
+ JS_FreeValue(ctx, ts_val);
+ JS_FreeValue(ctx, new_argv[0]);
+ JS_FreeValue(ctx, new_argv[1]);
+ JS_FreeValue(ctx, ctor);
+ return JS_EXCEPTION;
+ }
+ BOOL has_ds = !JS_IsUndefined(ds_val);
+ BOOL has_ts = !JS_IsUndefined(ts_val);
+ JS_FreeValue(ctx, ds_val);
+ JS_FreeValue(ctx, ts_val);
+
+ /* Reject incompatible style options based on Temporal type */
+ if (default_mode == 1 && has_ts) { /* date types */
+ JS_FreeValue(ctx, new_argv[0]);
+ JS_FreeValue(ctx, new_argv[1]);
+ JS_FreeValue(ctx, ctor);
+ return JS_ThrowTypeError(ctx, "timeStyle option is not allowed for this Temporal type");
+ }
+ if (default_mode == 2 && has_ds) { /* time types */
+ JS_FreeValue(ctx, new_argv[0]);
+ JS_FreeValue(ctx, new_argv[1]);
+ JS_FreeValue(ctx, ctor);
+ return JS_ThrowTypeError(ctx, "dateStyle option is not allowed for this Temporal type");
+ }
+
+ if (!has_ds && !has_ts) {
+ if (default_mode == 0) { /* any: Instant, PlainDateTime */
+ if (!has_date && !has_time) {
+ JS_DefinePropertyValueStr(ctx, new_argv[1], "year",
+ JS_NewString(ctx, "numeric"), JS_PROP_C_W_E);
+ JS_DefinePropertyValueStr(ctx, new_argv[1], "month",
+ JS_NewString(ctx, "numeric"), JS_PROP_C_W_E);
+ JS_DefinePropertyValueStr(ctx, new_argv[1], "day",
+ JS_NewString(ctx, "numeric"), JS_PROP_C_W_E);
+ JS_DefinePropertyValueStr(ctx, new_argv[1], "hour",
+ JS_NewString(ctx, "numeric"), JS_PROP_C_W_E);
+ JS_DefinePropertyValueStr(ctx, new_argv[1], "minute",
+ JS_NewString(ctx, "numeric"), JS_PROP_C_W_E);
+ JS_DefinePropertyValueStr(ctx, new_argv[1], "second",
+ JS_NewString(ctx, "numeric"), JS_PROP_C_W_E);
+ }
+ } else if (default_mode == 1) { /* date: PlainDate, PlainYearMonth, PlainMonthDay */
+ if (!has_date) {
+ JS_DefinePropertyValueStr(ctx, new_argv[1], "year",
+ JS_NewString(ctx, "numeric"), JS_PROP_C_W_E);
+ JS_DefinePropertyValueStr(ctx, new_argv[1], "month",
+ JS_NewString(ctx, "numeric"), JS_PROP_C_W_E);
+ JS_DefinePropertyValueStr(ctx, new_argv[1], "day",
+ JS_NewString(ctx, "numeric"), JS_PROP_C_W_E);
+ }
+ } else if (default_mode == 2) { /* time: PlainTime */
+ if (!has_time) {
+ JS_DefinePropertyValueStr(ctx, new_argv[1], "hour",
+ JS_NewString(ctx, "numeric"), JS_PROP_C_W_E);
+ JS_DefinePropertyValueStr(ctx, new_argv[1], "minute",
+ JS_NewString(ctx, "numeric"), JS_PROP_C_W_E);
+ JS_DefinePropertyValueStr(ctx, new_argv[1], "second",
+ JS_NewString(ctx, "numeric"), JS_PROP_C_W_E);
+ }
+ }
+ }
+ }
+
+ dtf = JS_CallConstructor(ctx, ctor, 2, new_argv);
+ JS_FreeValue(ctx, ctor);
+ if (JS_IsException(dtf)) {
+ JS_FreeValue(ctx, new_argv[0]);
+ JS_FreeValue(ctx, new_argv[1]);
+ return dtf;
+ }
+
+ /* Calendar mismatch check for types with calendars */
+ if (JS_GetOpaque(this_val, js_plaindate_class_id) ||
+ JS_GetOpaque(this_val, js_plaindatetime_class_id) ||
+ JS_GetOpaque(this_val, js_plainyearmonth_class_id) ||
+ JS_GetOpaque(this_val, js_plainmonthday_class_id)) {
+ JSValue resolved = JS_GetPropertyStr(ctx, dtf, "resolvedOptions");
+ if (!JS_IsException(resolved)) {
+ JSValue opts = JS_Call(ctx, resolved, dtf, 0, NULL);
+ JS_FreeValue(ctx, resolved);
+ if (!JS_IsException(opts)) {
+ JSValue dtf_cal_val = JS_GetPropertyStr(ctx, opts, "calendar");
+ JSValue obj_cal_val = JS_GetPropertyStr(ctx, this_val, "calendarId");
+ JS_FreeValue(ctx, opts);
+ if (!JS_IsException(dtf_cal_val) && !JS_IsException(obj_cal_val)) {
+ const char *dtf_cal = JS_ToCString(ctx, dtf_cal_val);
+ const char *obj_cal = JS_ToCString(ctx, obj_cal_val);
+ int mismatch;
+ if (JS_GetOpaque(this_val, js_plainyearmonth_class_id) ||
+ JS_GetOpaque(this_val, js_plainmonthday_class_id)) {
+ /* PlainYearMonth and PlainMonthDay: no ISO exemption */
+ mismatch = (dtf_cal && obj_cal && strcmp(obj_cal, dtf_cal) != 0);
+ } else {
+ /* PlainDate and PlainDateTime: ISO calendar is exempt */
+ mismatch = (dtf_cal && obj_cal && strcmp(obj_cal, "iso8601") != 0 &&
+ strcmp(dtf_cal, "iso8601") != 0 && strcmp(obj_cal, dtf_cal) != 0);
+ }
+ if (mismatch) {
+ JS_FreeCString(ctx, dtf_cal);
+ JS_FreeCString(ctx, obj_cal);
+ JS_FreeValue(ctx, dtf_cal_val);
+ JS_FreeValue(ctx, obj_cal_val);
+ JS_FreeValue(ctx, dtf);
+ JS_FreeValue(ctx, new_argv[0]);
+ JS_FreeValue(ctx, new_argv[1]);
+ return JS_ThrowRangeError(ctx, "calendar mismatch");
+ }
+ JS_FreeCString(ctx, dtf_cal);
+ JS_FreeCString(ctx, obj_cal);
+ }
+ JS_FreeValue(ctx, dtf_cal_val);
+ JS_FreeValue(ctx, obj_cal_val);
+ }
+ }
+ }
+
+ JS_FreeValue(ctx, new_argv[0]);
+ JS_FreeValue(ctx, new_argv[1]);
+
+ method = JS_GetPropertyStr(ctx, dtf, "format");
+ if (JS_IsException(method)) {
+ JS_FreeValue(ctx, dtf);
+ return method;
+ }
+
+ ret = JS_Call(ctx, method, dtf, 1, &this_val);
+ JS_FreeValue(ctx, method);
+ JS_FreeValue(ctx, dtf);
+ return ret;
+}
+
+int JS_AddIntrinsicTemporal(JSContext *ctx)
+{
+ JSValue global_obj, temporal_obj;
+ int ret;
+
+ global_obj = JS_GetGlobalObject(ctx);
+ temporal_obj = JS_NewObject(ctx);
+ if (JS_IsException(temporal_obj))
+ goto fail;
+
+ ret = JS_SetPropertyFunctionList(ctx, temporal_obj, js_temporal_funcs,
+ countof(js_temporal_funcs));
+ if (ret < 0)
+ goto fail;
+
+ ret = js_add_instant(ctx, temporal_obj);
+ if (ret < 0)
+ goto fail;
+
+ ret = js_add_duration(ctx, temporal_obj);
+ if (ret < 0)
+ goto fail;
+
+ ret = js_add_plaintime(ctx, temporal_obj);
+ if (ret < 0)
+ goto fail;
+
+ ret = js_add_now(ctx, temporal_obj);
+ if (ret < 0)
+ goto fail;
+
+ ret = js_add_plaindate(ctx, temporal_obj);
+ if (ret < 0)
+ goto fail;
+
+ ret = js_add_plaindatetime(ctx, temporal_obj);
+ if (ret < 0)
+ goto fail;
+
+ ret = js_add_plainyearmonth(ctx, temporal_obj);
+ if (ret < 0)
+ goto fail;
+
+ ret = js_add_plainmonthday(ctx, temporal_obj);
+ if (ret < 0)
+ goto fail;
+
+ ret = js_add_zoneddatetime(ctx, temporal_obj);
+ if (ret < 0)
+ goto fail;
+
+ ret = JS_DefinePropertyValueStr(ctx, global_obj, "Temporal", temporal_obj,
+ JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
+ if (ret < 0)
+ goto fail;
+
+ {
+ JSValue date_ctor = JS_GetPropertyStr(ctx, global_obj, "Date");
+ if (JS_IsException(date_ctor))
+ goto fail;
+ if (!JS_IsUndefined(date_ctor)) {
+ JSValue date_proto = JS_GetPropertyStr(ctx, date_ctor, "prototype");
+ if (JS_IsException(date_proto)) {
+ JS_FreeValue(ctx, date_ctor);
+ goto fail;
+ }
+ if (!JS_IsUndefined(date_proto)) {
+ JSValue func = JS_NewCFunction(ctx, js_date_toTemporalInstant, "toTemporalInstant", 0);
+ JS_DefinePropertyValueStr(ctx, date_proto, "toTemporalInstant", func,
+ JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
+ JS_FreeValue(ctx, date_proto);
+ }
+ JS_FreeValue(ctx, date_ctor);
+ }
+ }
+
+ JS_FreeValue(ctx, global_obj);
+ return 0;
+
+fail:
+ JS_FreeValue(ctx, temporal_obj);
+ JS_FreeValue(ctx, global_obj);
+ return -1;
+}
+int ti_is_minus_zero_year(const char *str)
+{
+ /* Reject extended year -000000 (minus zero) per ISO 8601 / Temporal spec */
+ if (str[0] == '-' && str[1] == '0' && str[2] == '0' &&
+ str[3] == '0' && str[4] == '0' && str[5] == '0' && str[6] == '0') {
+ char c = str[7];
+ if (c == '\0' || c == '-' || c == 'T')
+ return 1;
+ }
+ return 0;
+}
+static int ti_is_valid_plain_offset_string(const char *str)
+{
+ size_t len = strlen(str);
+ int h1, h2, m1, m2, s1, s2, i;
+
+ if (len < 3 || len > 19)
+ return 0;
+ if (str[0] != '+' && str[0] != '-')
+ return 0;
+
+ if (len == 3) {
+ /* ±HH */
+ h1 = str[1] - '0';
+ h2 = str[2] - '0';
+ if (h1 < 0 || h1 > 9 || h2 < 0 || h2 > 9)
+ return 0;
+ if (h1 * 10 + h2 > 23)
+ return 0;
+ return 1;
+ }
+
+ if (len == 5) {
+ /* ±HHMM */
+ h1 = str[1] - '0';
+ h2 = str[2] - '0';
+ m1 = str[3] - '0';
+ m2 = str[4] - '0';
+ if (h1 < 0 || h1 > 9 || h2 < 0 || h2 > 9 || m1 < 0 || m1 > 5 || m2 < 0 || m2 > 9)
+ return 0;
+ if (h1 * 10 + h2 > 23)
+ return 0;
+ return 1;
+ }
+
+ if (len == 6) {
+ /* ±HH:MM */
+ if (str[3] != ':')
+ return 0;
+ h1 = str[1] - '0';
+ h2 = str[2] - '0';
+ m1 = str[4] - '0';
+ m2 = str[5] - '0';
+ if (h1 < 0 || h1 > 9 || h2 < 0 || h2 > 9 || m1 < 0 || m1 > 5 || m2 < 0 || m2 > 9)
+ return 0;
+ if (h1 * 10 + h2 > 23)
+ return 0;
+ return 1;
+ }
+
+ if (len >= 9) {
+ /* ±HH:MM:SS or ±HH:MM:SS.fraction */
+ if (str[3] != ':' || str[6] != ':')
+ return 0;
+ h1 = str[1] - '0';
+ h2 = str[2] - '0';
+ m1 = str[4] - '0';
+ m2 = str[5] - '0';
+ s1 = str[7] - '0';
+ s2 = str[8] - '0';
+ if (h1 < 0 || h1 > 9 || h2 < 0 || h2 > 9 || m1 < 0 || m1 > 5 || m2 < 0 || m2 > 9 ||
+ s1 < 0 || s1 > 5 || s2 < 0 || s2 > 9)
+ return 0;
+ if (h1 * 10 + h2 > 23 || m1 * 10 + m2 > 59)
+ return 0;
+ if (len == 9)
+ return 1;
+ if (str[9] != '.')
+ return 0;
+ for (i = 10; i < (int)len; i++) {
+ if (str[i] < '0' || str[i] > '9')
+ return 0;
+ }
+ return 1;
+ }
+
+ return 0;
+}
+int ti_is_minus_zero(JSValueConst v)
+{
+ /* Check if JS value is -0 (negative zero float64) */
+ if (JS_VALUE_GET_TAG(v) == JS_TAG_FLOAT64) {
+ double d = JS_VALUE_GET_FLOAT64(v);
+ if (d == 0.0) {
+ union { double d; uint64_t u; } u;
+ u.d = d;
+ if (u.u == 0x8000000000000000ULL)
+ return 1;
+ }
+ }
+ return 0;
+}
+void ti_format_canonical_timezone(int64_t offset_ns, int is_utc, char *out, size_t out_size)
+{
+ if (is_utc) {
+ pstrcpy(out, (int)out_size, "UTC");
+ } else {
+ int64_t abs_ns = llabs(offset_ns);
+ int hours = (int)(abs_ns / (3600LL * 1000000000LL));
+ int minutes = (int)((abs_ns % (3600LL * 1000000000LL)) / (60LL * 1000000000LL));
+ snprintf(out, out_size, "%c%02d:%02d", (offset_ns >= 0) ? '+' : '-', hours, minutes);
+ }
+}
+
+/* Append calendar annotation to a string buffer.
+ calendarName: 0=auto, 1=always, 2=critical, 3=never.
+ Appends when calendarName is always/critical, or when auto and calendar is not ISO8601. */
+void ti_append_calendar_annotation(char *buf, int buf_size, CalendarType cal, int calendarName)
+{
+ const char *cal_str;
+ if (calendarName == 3)
+ return;
+ if (calendarName == 0 && cal == CAL_ISO8601)
+ return;
+ cal_str = ti_calendar_enum_to_string(cal);
+ if (!cal_str)
+ return;
+ if (calendarName == 2)
+ pstrcat(buf, buf_size, "[!u-ca=");
+ else
+ pstrcat(buf, buf_size, "[u-ca=");
+ pstrcat(buf, buf_size, cal_str);
+ pstrcat(buf, buf_size, "]");
+}
+
+int ti_canonicalize_timezone_identifier(const char *str, int64_t offset_ns, char *out, size_t out_size)
+{
+ size_t len = strlen(str);
+ const char *bracket_open = strchr(str, '[');
+ if (bracket_open) {
+ const char *bracket_close = strchr(bracket_open, ']');
+ if (bracket_close && bracket_close[1] == '\0') {
+ int inner_len = (int)(bracket_close - bracket_open - 1);
+ if (inner_len > 0 && inner_len < (int)out_size) {
+ memcpy(out, bracket_open + 1, (size_t)inner_len);
+ out[inner_len] = '\0';
+ if (out[0] == 'u' || out[0] == 'U') {
+ if ((out[1] == 't' || out[1] == 'T') &&
+ (out[2] == 'c' || out[2] == 'C') && out[3] == '\0')
+ pstrcpy(out, (int)out_size, "UTC");
+ }
+ return 0;
+ }
+ }
+ } else {
+ int is_utc = (len == 3 && (str[0] == 'U' || str[0] == 'u') &&
+ (str[1] == 'T' || str[1] == 't') &&
+ (str[2] == 'C' || str[2] == 'c'));
+ if (!is_utc && len > 0 && (str[len - 1] == 'Z' || str[len - 1] == 'z'))
+ is_utc = 1;
+ if (!is_utc && offset_ns == 0 && len > 0 &&
+ str[0] != '+' && str[0] != '-' && str[0] != 'Z' && str[0] != 'z') {
+ /* Accept IANA time zone names */
+ int is_iana = 1;
+ size_t i;
+ for (i = 0; i < len; i++) {
+ char c = str[i];
+ if (!((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') ||
+ (c >= '0' && c <= '9') || c == '/' || c == '_' || c == '-' || c == '+')) {
+ is_iana = 0;
+ break;
+ }
+ }
+ if (is_iana) {
+ pstrcpy(out, (int)out_size, str);
+ return 0;
+ }
+ return -1;
+ }
+ ti_format_canonical_timezone(offset_ns, is_utc, out, out_size);
+ if (out[0] == 'u' || out[0] == 'U') {
+ if ((out[1] == 't' || out[1] == 'T') &&
+ (out[2] == 'c' || out[2] == 'C') && out[3] == '\0')
+ pstrcpy(out, (int)out_size, "UTC");
+ }
+ return 0;
+ }
+ return -1;
+}
+int ti_validate_constructor_calendar(JSContext *ctx, JSValueConst v, CalendarType *out)
+{
+ const char *cal;
+ size_t len;
+ char *lower;
+ int i;
+
+ if (JS_IsUndefined(v)) {
+ *out = CAL_ISO8601;
+ return 0;
+ }
+
+ if (!JS_IsString(v)) {
+ JS_ThrowTypeError(ctx, "calendar must be a string");
+ return -1;
+ }
+
+ cal = JS_ToCString(ctx, v);
+ if (!cal)
+ return -1;
+ len = strlen(cal);
+ if (len == 0) {
+ JS_FreeCString(ctx, cal);
+ return JS_ThrowRangeError(ctx, "invalid calendar ID"), -1;
+ }
+
+ lower = js_malloc(ctx, len + 1);
+ if (!lower) {
+ JS_FreeCString(ctx, cal);
+ return -1;
+ }
+ for (i = 0; i < (int)len; i++) {
+ char c = cal[i];
+ lower[i] = (c >= 'A' && c <= 'Z') ? (c + ('a' - 'A')) : c;
+ }
+ lower[len] = '\0';
+
+ if (!strcmp(lower, "ethiopic-amete-alem"))
+ *out = CAL_ETHIOAA;
+ else if (!strcmp(lower, "islamicc"))
+ *out = CAL_ISLAMIC_CIVIL;
+ else
+ *out = ti_calendar_string_to_enum(lower);
+
+ js_free(ctx, lower);
+ JS_FreeCString(ctx, cal);
+
+ if (*out == CAL_UNKNOWN)
+ return JS_ThrowRangeError(ctx, "invalid calendar ID"), -1;
+ return 0;
+}
+int ti_validate_timezone_identifier(JSContext *ctx, JSValueConst v, const char **out_str)
+{
+ const char *str;
+ size_t len, i;
+
+ if (JS_IsUndefined(v)) {
+ *out_str = NULL;
+ return 0;
+ }
+ if (!JS_IsString(v)) {
+ JS_ThrowTypeError(ctx, "timeZone must be a string");
+ return -1;
+ }
+ str = JS_ToCString(ctx, v);
+ if (!str)
+ return -1;
+ len = strlen(str);
+ if (len == 0) {
+ JS_FreeCString(ctx, str);
+ return JS_ThrowRangeError(ctx, "invalid time zone"), -1;
+ }
+ /* Canonicalize UTC */
+ if (len == 3 &&
+ (str[0] == 'U' || str[0] == 'u') &&
+ (str[1] == 'T' || str[1] == 't') &&
+ (str[2] == 'C' || str[2] == 'c')) {
+ JS_FreeCString(ctx, str);
+ {
+ JSValue utc_val = JS_NewString(ctx, "UTC");
+ *out_str = JS_ToCString(ctx, utc_val);
+ JS_FreeValue(ctx, utc_val);
+ }
+ return 1;
+ }
+ /* Reject strings that look like ISO date-time strings.
+ ISO date-time strings start with a digit and contain 'T' with digits/colons.
+ Plain IANA names like Etc/GMT+1 may contain 't' and digits but don't start with digits. */
+ if (len > 0 && (str[0] >= '0' && str[0] <= '9')) {
+ for (i = 0; i < len; i++) {
+ char c = str[i];
+ if (c == 'T' || c == 't') {
+ int has_digit_or_colon = 0;
+ size_t j;
+ for (j = 0; j < len; j++) {
+ char d = str[j];
+ if ((d >= '0' && d <= '9') || d == ':') {
+ has_digit_or_colon = 1;
+ break;
+ }
+ }
+ if (has_digit_or_colon) {
+ JS_FreeCString(ctx, str);
+ return JS_ThrowRangeError(ctx, "invalid time zone"), -1;
+ }
+ break;
+ }
+ }
+ }
+ /* Reject legacy non-IANA 3-letter abbreviations */
+ if (len == 3 && str[0] >= 'A' && str[0] <= 'Z' &&
+ str[1] >= 'A' && str[1] <= 'Z' && str[2] >= 'A' && str[2] <= 'Z') {
+ static const char *legacy_non_iana[] = {
+ "ACT", "AET", "AGT", "ART", "AST", "BET", "BST", "CAT",
+ "CNT", "CST", "CTT", "EAT", "ECT", "IET", "IST", "JST",
+ "MIT", "NET", "NST", "PLT", "PNT", "PRT", "PST", "SST",
+ "VST"
+ };
+ int is_legacy = 0;
+ size_t j;
+ for (j = 0; j < sizeof(legacy_non_iana) / sizeof(legacy_non_iana[0]); j++) {
+ if (!strcmp(str, legacy_non_iana[j])) {
+ is_legacy = 1;
+ break;
+ }
+ }
+ if (is_legacy) {
+ JS_FreeCString(ctx, str);
+ return JS_ThrowRangeError(ctx, "invalid time zone"), -1;
+ }
+ }
+ *out_str = str;
+ return 1;
+}
+JSValue js_create_temporal_object(JSContext *ctx, JSValueConst new_target,
+ JSClassID class_id, void *opaque)
+{
+
+ JSValue obj = JS_CreateFromConstructor(ctx, new_target, class_id);
+ if (JS_IsException(obj))
+ return JS_EXCEPTION;
+ JS_SetOpaque(obj, opaque);
+ return obj;
+}
+int is_valid_epoch_timespec(const JSTimeSpec *ts)
+{
+ if (ts->secs > INSTANT_MAX_SECS || ts->secs < -INSTANT_MAX_SECS)
+ return 0;
+ if (ts->secs == INSTANT_MAX_SECS && ts->nsecs != 0)
+ return 0;
+ return 1;
+}
+
+JSValue ti_timespec_to_bigint(JSContext *ctx, const JSTimeSpec *ts)
+{
+ js_int128_t total_ns = (js_int128_t)ts->secs * 1000000000LL + ts->nsecs;
+ return JS_NewBigInt128(ctx, (uint64_t)total_ns, (uint64_t)(total_ns >> 64));
+}
+
+int ti_bigint_to_timespec(JSContext *ctx, JSValueConst val, JSTimeSpec *ts)
+{
+ uint64_t low, high;
+ int32_t nsecs;
+ int ret;
+ js_int128_t total_ns;
+
+ ret = JS_ToBigInt128(ctx, &low, &high, val);
+ if (ret < 0)
+ return -1;
+ if (ret > 0) {
+ JS_ThrowRangeError(ctx, "epochNanoseconds out of range");
+ return -1;
+ }
+ total_ns = (js_int128_t)low + ((js_int128_t)(int64_t)high << 64);
+ if (total_ns / 1000000000LL > INT64_MAX ||
+ total_ns / 1000000000LL < INT64_MIN) {
+ JS_ThrowRangeError(ctx, "epochNanoseconds out of range");
+ return -1;
+ }
+ ts->secs = (int64_t)(total_ns / 1000000000LL);
+ nsecs = (int32_t)(total_ns % 1000000000LL);
+ if (nsecs < 0) {
+ ts->secs -= 1;
+ nsecs += 1000000000;
+ }
+ ts->nsecs = (uint32_t)nsecs;
+ return 0;
+}
--- /dev/null
+/*
+ * QuickJS Temporal implementation - private header
+ */
+
+#ifndef TEMPORAL_PRIVATE_H
+#define TEMPORAL_PRIVATE_H
+
+#include "../quickjs.h"
+#include "timezone.h"
+
+/* 128-bit integer type: __int128 on 64-bit, _BitInt(128) on 32-bit */
+#ifdef __SIZEOF_INT128__
+typedef __int128 js_int128_t;
+#else
+typedef _BitInt(128) js_int128_t;
+#endif
+
+/* Temporal limits */
+#define INSTANT_MAX_SECS 8640000000000LL
+
+/* JSTimeSpec is used by Intl.DurationFormat and Temporal */
+typedef struct JSTimeSpec {
+ int64_t secs;
+ uint32_t nsecs;
+} JSTimeSpec;
+
+JSValue ti_timespec_to_bigint(JSContext *ctx, const JSTimeSpec *ts);
+int ti_bigint_to_timespec(JSContext *ctx, JSValueConst val, JSTimeSpec *ts);
+
+int ti_is_partial_temporal_object(JSContext *ctx, JSValueConst obj);
+
+
+
+static inline int ti_validate_options_object(JSContext *ctx, JSValueConst v)
+{
+ if (!JS_IsUndefined(v) && !JS_IsObject(v)) {
+ JS_ThrowTypeError(ctx, "options must be an object");
+ return -1;
+ }
+ return 0;
+}
+
+#include "calendar.h"
+
+/* PlainTime data */
+typedef struct JSPlainTimeData {
+ int hour;
+ int minute;
+ int second;
+ int millisecond;
+ int microsecond;
+ int nanosecond;
+} JSPlainTimeData;
+
+/* PlainDateTime data */
+typedef struct JSPlainDateTimeData {
+ int year;
+ int month;
+ int day;
+ int hour;
+ int minute;
+ int second;
+ int millisecond;
+ int microsecond;
+ int nanosecond;
+ CalendarType calendar;
+} JSPlainDateTimeData;
+
+/* Packed js_int128_t wrapper for use in structs that must be 8-byte aligned */
+typedef struct __attribute__((packed)) JSPackedInt128 {
+ js_int128_t int128_value;
+} JSPackedInt128;
+
+/* Duration data (shared with Instant arithmetic) */
+typedef struct JSDurationData {
+ int64_t years;
+ int64_t months;
+ int64_t weeks;
+ int64_t days;
+ int64_t hours;
+ int64_t minutes;
+ int64_t seconds;
+ int64_t milliseconds;
+ JSPackedInt128 microseconds;
+ JSPackedInt128 nanoseconds;
+} JSDurationData;
+
+typedef enum {
+ TI_UNIT_AUTO = -102,
+ TI_UNIT_INVALID = -100,
+ TI_UNIT_YEAR = -4,
+ TI_UNIT_MONTH = -3,
+ TI_UNIT_WEEK = -2,
+ TI_UNIT_DAY = -1,
+ TI_UNIT_HOUR = 0,
+ TI_UNIT_MINUTE = 1,
+ TI_UNIT_SECOND = 2,
+ TI_UNIT_MILLISECOND = 3,
+ TI_UNIT_MICROSECOND = 4,
+ TI_UNIT_NANOSECOND = 5,
+} TIUnit;
+
+#define TI_UNIT_OPT_ALLOW_UNDEFINED 1
+#define TI_UNIT_OPT_ALLOW_AUTO 2
+
+/* Instant data */
+typedef struct {
+ JSTimeSpec ts;
+} JSInstantData;
+
+/* ZonedDateTime data */
+typedef struct {
+ JSTimeSpec ts;
+ char timeZone[TI_TIMEZONE_BUF_SIZE];
+ CalendarType calendar;
+} JSZonedDateTimeData;
+
+/* PlainDate data */
+typedef struct {
+ int year;
+ int month;
+ int day;
+ CalendarType calendar;
+} JSPlainDateData;
+
+/* PlainMonthDay data (stores ISO date) */
+typedef struct {
+ int iso_year;
+ int iso_month;
+ int iso_day;
+ CalendarType calendar;
+} JSPlainMonthDayData;
+
+static inline void pmd_get_calendar_date(JSPlainMonthDayData *s, int *cal_year, int *cal_month, int *cal_day)
+{
+ ti_iso_to_calendar_date(s->calendar, s->iso_year, s->iso_month, s->iso_day, cal_year, cal_month, cal_day);
+}
+
+/* PlainYearMonth data (stores ISO date) */
+typedef struct {
+ int iso_year;
+ int iso_month;
+ int iso_day;
+ CalendarType calendar;
+} JSPlainYearMonthData;
+
+static inline void pym_get_calendar_date(JSPlainYearMonthData *s, int *cal_year, int *cal_month, int *cal_day)
+{
+ ti_iso_to_calendar_date(s->calendar, s->iso_year, s->iso_month, s->iso_day, cal_year, cal_month, cal_day);
+}
+
+/* Forward declarations */
+extern JSClassID js_plaindate_class_id;
+extern JSClassID js_plaintime_class_id;
+extern JSClassID js_plaindatetime_class_id;
+extern JSClassID js_zoneddatetime_class_id;
+extern JSClassID js_plainmonthday_class_id;
+extern JSClassID js_plainyearmonth_class_id;
+extern JSClassID js_instant_class_id;
+JSValue js_create_zoneddatetime(JSContext *ctx, const JSTimeSpec *ts,
+ const char *timeZone, CalendarType calendar);
+JSValue js_zoneddatetime_from(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv);
+JSValue js_create_instant(JSContext *ctx, const JSTimeSpec *ts);
+JSValue js_create_plaintime(JSContext *ctx, const JSPlainTimeData *t);
+JSValue js_create_plaindate(JSContext *ctx, int year, int month, int day);
+JSValue js_create_plaindate_with_calendar(JSContext *ctx, int year, int month, int day, CalendarType calendar);
+JSValue js_create_plaindatetime(JSContext *ctx, int year, int month, int day,
+ int hour, int minute, int second,
+ int millisecond, int microsecond, int nanosecond);
+JSValue js_create_plaindatetime_with_calendar(JSContext *ctx, int year, int month, int day,
+ int hour, int minute, int second,
+ int millisecond, int microsecond, int nanosecond,
+ CalendarType calendar);
+int pdt_is_within_limits(int year, int month, int day,
+ int hour, int minute, int second,
+ int millisecond, int microsecond, int nanosecond);
+JSValue js_create_plainyearmonth_with_calendar(JSContext *ctx, int year, int month, int referenceISODay, CalendarType calendar);
+JSValue js_create_plainmonthday_with_calendar(JSContext *ctx, int iso_year, int iso_month, int iso_day, CalendarType calendar);
+int js_to_temporal_duration(JSContext *ctx, JSValueConst item, JSDurationData *out);
+int duration_has_mixed_signs(const JSDurationData *d);
+int duration_is_out_of_range(const JSDurationData *d);
+typedef enum {
+ ROUND_CEIL,
+ ROUND_FLOOR,
+ ROUND_EXPAND,
+ ROUND_TRUNC,
+ ROUND_HALF_CEIL,
+ ROUND_HALF_FLOOR,
+ ROUND_HALF_EXPAND,
+ ROUND_HALF_TRUNC,
+ ROUND_HALF_EVEN,
+} TIRoundingMode;
+
+TIUnit ti_string_to_unit(const char *str, size_t len);
+int64_t ti_round_to_increment_as_if_positive(int64_t x, int64_t increment, TIRoundingMode mode);
+int64_t ti_round_to_increment(int64_t x, int64_t increment, TIRoundingMode mode);
+js_int128_t ti_round_to_increment128(js_int128_t x, js_int128_t increment, TIRoundingMode mode);
+js_int128_t ti_round_to_increment_as_if_positive128(js_int128_t x, js_int128_t increment, TIRoundingMode mode);
+int ti_parse_rounding_mode(JSContext *ctx, JSValueConst val, TIRoundingMode *out);
+
+/* Moved from temporal_private.h inline functions */
+int ti_is_minus_zero_year(const char *str);
+int ti_is_minus_zero(JSValueConst v);
+void ti_format_canonical_timezone(int64_t offset_ns, int is_utc, char *out, size_t out_size);
+void ti_append_calendar_annotation(char *buf, int buf_size, CalendarType cal, int calendarName);
+int ti_canonicalize_timezone_identifier(const char *str, int64_t offset_ns, char *out, size_t out_size);
+int ti_validate_constructor_calendar(JSContext *ctx, JSValueConst v, CalendarType *out);
+int ti_validate_timezone_identifier(JSContext *ctx, JSValueConst v, const char **out_str);
+JSValue js_create_temporal_object(JSContext *ctx, JSValueConst new_target, JSClassID class_id, void *opaque);
+int is_valid_epoch_timespec(const JSTimeSpec *ts);
+
+static inline js_int128_t ti_sec_nsec_to_ns(int64_t secs, uint32_t nsecs)
+{
+ return (js_int128_t)secs * 1000000000LL + nsecs;
+}
+
+static inline js_int128_t ti_timespec_to_ns(const JSTimeSpec *ts)
+{
+ return ti_sec_nsec_to_ns(ts->secs, ts->nsecs);
+}
+
+static inline js_int128_t ti_duration_time_fields_to_ns(const JSDurationData *d)
+{
+ return (js_int128_t)d->hours * 3600000000000LL
+ + (js_int128_t)d->minutes * 60000000000LL
+ + (js_int128_t)d->seconds * 1000000000LL
+ + (js_int128_t)d->milliseconds * 1000000LL
+ + d->microseconds.int128_value * 1000LL
+ + d->nanoseconds.int128_value;
+}
+
+static inline void ti_ns_to_timespec(js_int128_t ns, JSTimeSpec *ts)
+{
+ ts->secs = (int64_t)(ns / 1000000000LL);
+ ts->nsecs = (uint32_t)(ns % 1000000000LL);
+ if (ts->nsecs != 0 && ns < 0) {
+ ts->nsecs += 1000000000;
+ ts->secs -= 1;
+ }
+}
+
+
+
+JSValue ti_get_month_code(JSContext *ctx, CalendarType cal, int year, int month);
+static inline CalendarType ti_calendar_string_to_enum_with_aliases(const char *str)
+{
+ return ti_calendar_string_to_enum(str);
+}
+static inline int ti_calendar_enforces_month_monthcode_agreement(CalendarType cal)
+{
+ /* Hebrew, Chinese, and Dangi calendars allow month and monthCode to disagree
+ because month numbers shift in leap years */
+ return cal != CAL_HEBREW && cal != CAL_CHINESE && cal != CAL_DANGI;
+}
+
+int64_t ti_unit_to_ns(TIUnit unit);
+/* Parse a unit option (smallestUnit, largestUnit, unit) from an options object.
+ Returns 0 on success, -1 on error (exception thrown).
+ flags: bitwise OR of TI_UNIT_OPT_ALLOW_UNDEFINED and/or TI_UNIT_OPT_ALLOW_AUTO.
+ If ALLOW_UNDEFINED is set and the property is undefined, *out = default_unit.
+ If ALLOW_AUTO is set and the value is "auto", *out = TI_UNIT_AUTO.
+ Otherwise throws RangeError for undefined or invalid strings. */
+int ti_parse_unit_option(JSContext *ctx, JSValueConst options, const char *prop,
+ TIUnit *out, int flags, TIUnit default_unit);
+int ti_get_rounding_increment_option(JSContext *ctx, JSValueConst options, int64_t *out);
+int ti_get_rounding_mode_option_default(JSContext *ctx, JSValueConst options, TIRoundingMode *out, int default_mode);
+int ti_get_rounding_mode_option(JSContext *ctx, JSValueConst options, TIRoundingMode *out);
+int ti_get_calendar_name_option(JSContext *ctx, JSValueConst options, int *out);
+int ti_get_fractional_second_digits_option(JSContext *ctx, JSValueConst options, int *out);
+TIRoundingMode ti_negate_rounding_mode(TIRoundingMode mode);
+
+/* Map smallestUnit to precision_type used by toString methods.
+ Returns: 10=minute, 11=second, 12=ms, 13=us, 14=ns, -1 for invalid. */
+static inline int ti_precision_from_smallest_unit(TIUnit unit)
+{
+ switch (unit) {
+ case TI_UNIT_MINUTE: return 10;
+ case TI_UNIT_SECOND: return 11;
+ case TI_UNIT_MILLISECOND: return 12;
+ case TI_UNIT_MICROSECOND: return 13;
+ case TI_UNIT_NANOSECOND: return 14;
+ default: return -1;
+ }
+}
+
+/* Create a Temporal object respecting newTarget's prototype per spec */
+
+/* JSTimeSpec helpers for Temporal */
+
+
+static inline double timespec_to_ms(const JSTimeSpec *ts)
+{
+ return (double)ts->secs * 1000.0 + (double)ts->nsecs / 1000000.0;
+}
+
+
+void ti_epoch_sec_to_date(int64_t epoch_sec, int64_t *year, int *month, int *day,
+ int *hour, int *minute, int *second);
+void ti_zoneddatetime_to_local(const char *timeZone, int64_t epoch_sec, int epoch_nsec,
+ int64_t *out_year, int *out_month, int *out_day,
+ int *out_hour, int *out_minute, int *out_second,
+ int *out_ms, int *out_us, int *out_ns);
+
+static inline int64_t floor_div64(int64_t a, uint64_t b)
+{
+ int64_t bi = (int64_t)b;
+ if (a >= 0)
+ return a / bi;
+ else
+ return (a - bi + 1) / bi;
+}
+
+static inline int64_t floor_divrem64(int64_t *pr, int64_t a, uint64_t b)
+{
+ int64_t bi = (int64_t)b;
+ int64_t q = a / bi;
+ int64_t r = a % bi;
+ if (r < 0) {
+ q--;
+ r += bi;
+ }
+ *pr = r;
+ return q;
+}
+
+static inline int32_t floor_div32(int32_t a, uint32_t b)
+{
+ int32_t bi = (int32_t)b;
+ if (a >= 0)
+ return a / bi;
+ else
+ return (a - bi + 1) / bi;
+}
+
+
+
+int64_t pdt_to_ordinal_days(int year, int month, int day);
+int pd_days_in_month(int year, int month);
+int pd_is_valid_date(int year, int month, int day);
+int pd_is_leap_year(int year);
+int pd_day_of_year(int year, int month, int day);
+void pdt_from_ordinal_days(int64_t ordinal, int *year, int *month, int *day);
+int ti_is_date_within_iso_limits(int year, int month, int day);
+void ti_iso_calendar_date_until(int one_year, int one_month, int one_day,
+ int two_year, int two_month, int two_day,
+ TIUnit largestUnit,
+ int64_t *out_years, int64_t *out_months,
+ int64_t *out_weeks, int64_t *out_days);
+int ti_iso_calendar_date_add(int year, int month, int day,
+ int64_t years, int64_t months, int64_t weeks, int64_t days,
+ int *out_year, int *out_month, int *out_day);
+int ti_iso_datetime_add_duration(
+ int year, int month, int day,
+ int hour, int minute, int second, int ms, int us, int ns,
+ int64_t dyears, int64_t dmonths, int64_t dweeks, int64_t ddays,
+ int64_t dhours, int64_t dminutes, int64_t dseconds,
+ int64_t dms, js_int128_t dus, js_int128_t dns,
+ int *out_year, int *out_month, int *out_day,
+ int *out_hour, int *out_minute, int *out_second,
+ int *out_ms, int *out_us, int *out_ns);
+int ti_calendar_datetime_difference(
+ CalendarType cal,
+ int y1, int m1, int d1, int h1, int min1, int s1, int ms1, int us1, int ns1,
+ int y2, int m2, int d2, int h2, int min2, int s2, int ms2, int us2, int ns2,
+ TIUnit largestUnit,
+ JSDurationData *out);
+
+int ti_iso_datetime_difference(
+ int y1, int m1, int d1, int h1, int min1, int s1, int ms1, int us1, int ns1,
+ int y2, int m2, int d2, int h2, int min2, int s2, int ms2, int us2, int ns2,
+ TIUnit largestUnit,
+ JSDurationData *out);
+int ti_round_relative_duration_iso(
+ JSContext *ctx,
+ int rel_year, int rel_month, int rel_day,
+ int rel_hour, int rel_minute, int rel_second,
+ int rel_ms, int rel_us, int rel_ns,
+ const JSDurationData *duration,
+ TIUnit largestUnit, TIUnit smallestUnit,
+ int64_t increment, TIRoundingMode roundingMode,
+ BOOL has_timeZone,
+ JSDurationData *out);
+
+void ti_balance_time_duration(JSDurationData *d, TIUnit largestUnit);
+int ti_round_iso_date_duration(JSContext *ctx,
+ int origin_year, int origin_month, int origin_day,
+ int dest_year, int dest_month, int dest_day,
+ int64_t rel_time_ns, int64_t dest_time_ns,
+ int64_t years, int64_t months, int64_t weeks, int64_t days,
+ TIUnit largestUnit, TIUnit smallestUnit,
+ int64_t increment, TIRoundingMode rounding_mode,
+ int do_bubble,
+ BOOL has_timeZone,
+ int64_t *out_years, int64_t *out_months,
+ int64_t *out_weeks, int64_t *out_days);
+
+/* ZonedDateTime functions */
+JSValue js_zoneddatetime_add(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv);
+int ti_zoneddatetime_add_duration_iso(const char *timeZone, CalendarType calendar,
+ JSTimeSpec origin, JSDurationData *duration,
+ int overflow_constrain, JSTimeSpec *out);
+int ti_zoneddatetime_difference_iso(const char *timeZone, CalendarType calendar,
+ JSTimeSpec start, JSTimeSpec end,
+ TIUnit largestUnit, JSDurationData *out);
+
+/* Instant functions */
+int js_add_instant(JSContext *ctx, JSValue temporal_obj);
+
+/* Duration functions */
+int js_add_duration(JSContext *ctx, JSValue temporal_obj);
+int js_parse_duration_string(JSContext *ctx, const char *str, JSDurationData *out);
+JSValue js_create_duration(JSContext *ctx, const JSDurationData *d);
+
+/* PlainTime functions */
+int js_add_plaintime(JSContext *ctx, JSValue temporal_obj);
+JSValue js_plaintime_from(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv);
+
+/* Now functions */
+int js_add_now(JSContext *ctx, JSValue temporal_obj);
+
+/* PlainDate functions */
+int js_add_plaindate(JSContext *ctx, JSValue temporal_obj);
+
+/* PlainDateTime functions */
+int js_add_plaindatetime(JSContext *ctx, JSValue temporal_obj);
+
+/* PlainYearMonth functions */
+int js_add_plainyearmonth(JSContext *ctx, JSValue temporal_obj);
+
+/* PlainMonthDay functions */
+int js_add_plainmonthday(JSContext *ctx, JSValue temporal_obj);
+
+/* ZonedDateTime functions */
+int js_add_zoneddatetime(JSContext *ctx, JSValue temporal_obj);
+int js_zoneddatetime_get_timespec(JSContext *ctx, JSValueConst val, JSTimeSpec *ts);
+
+/* TimeZone string parsing */
+int ti_parse_temporal_timezone_string(const char *str, int64_t *offset_ns);
+void ti_get_default_timezone(char *buf, size_t buf_size);
+int ti_get_string_option(JSContext *ctx, JSValueConst options, const char *prop,
+ const char **valid_values, int num_values, int default_index);
+int ti_get_overflow_option(JSContext *ctx, JSValueConst options, int *overflow_constrain);
+
+/* Calendar Fields Record - like PrepareCalendarFields from the spec */
+#define TI_FIELD_YEAR (1U << 0)
+#define TI_FIELD_MONTH (1U << 1)
+#define TI_FIELD_MONTH_CODE (1U << 2)
+#define TI_FIELD_DAY (1U << 3)
+#define TI_FIELD_HOUR (1U << 4)
+#define TI_FIELD_MINUTE (1U << 5)
+#define TI_FIELD_SECOND (1U << 6)
+#define TI_FIELD_MILLISECOND (1U << 7)
+#define TI_FIELD_MICROSECOND (1U << 8)
+#define TI_FIELD_NANOSECOND (1U << 9)
+#define TI_FIELD_OFFSET (1U << 10)
+#define TI_FIELD_TIMEZONE (1U << 11)
+#define TI_FIELD_CALENDAR (1U << 12)
+#define TI_FIELD_ERA (1U << 13)
+#define TI_FIELD_ERA_YEAR (1U << 14)
+
+typedef struct {
+ /* Integer fields */
+ int64_t year;
+ int month, day;
+ int hour, minute, second;
+ int millisecond, microsecond, nanosecond;
+ int64_t era_year;
+ /* Derived from monthCode */
+ int month_from_code;
+ int month_code_has_l;
+ /* Parsed offset in nanoseconds */
+ int64_t offset_ns;
+ /* Time zone identifier */
+ char time_zone[TI_TIMEZONE_BUF_SIZE];
+ /* Era enum (for non-ISO calendars) */
+ TIEra era;
+ /* Presence and calendar info */
+ uint32_t present_mask;
+ CalendarType calendar;
+} TIPreparedFields;
+
+int ti_resolve_date_from_fields(JSContext *ctx, TIPreparedFields *fields, int overflow_constrain,
+ int *year, int *month, int *day, BOOL require_day);
+int ti_resolve_calendar_value(JSContext *ctx, JSValue cal_v, CalendarType *out);
+int ti_resolve_calendar_from_object(JSContext *ctx, JSValueConst obj, CalendarType *out);
+int ti_prepare_calendar_fields(JSContext *ctx, JSValueConst obj,
+ uint32_t field_mask, uint32_t required_mask,
+ int partial, TIPreparedFields *out,
+ CalendarType calendar);
+
+/* Helpers to create Temporal objects from prepared fields without JS calls */
+JSValue ti_create_plaindate_from_fields(JSContext *ctx, TIPreparedFields *fields,
+ int overflow_constrain);
+JSValue ti_create_zoneddatetime_from_fields(JSContext *ctx, TIPreparedFields *fields,
+ int overflow_constrain, JSValueConst options);
+
+
+
+typedef struct TISODateTimeParseResult {
+ int has_date;
+ int has_yearmonth;
+ int has_monthday;
+ int year, month, day;
+ int has_time;
+ int hour, minute, second;
+ int millisecond, microsecond, nanosecond;
+ int has_utc;
+ int has_tz_offset;
+ int tz_offset_seconds;
+ int tz_offset_nanoseconds;
+ int tz_offset_has_seconds;
+ int has_calendar;
+ CalendarType calendar;
+ int calendar_critical;
+ int has_unknown_critical;
+ int has_tz_annotation;
+ char tz_annotation[64];
+} TISODateTimeParseResult;
+
+#define TI_PARSE_DEFAULT 0
+#define TI_PARSE_PLAIN_TIME 1 /* Reject Z, require time, reject ambiguous date-like strings without T prefix */
+#define TI_PARSE_PLAIN_MONTHDAY 2 /* Accept --MM-DD, MM-DD, MMDD; reject time/Z/offset without full date */
+
+int ti_parse_iso_datetime_string(JSContext *ctx, const char *str, TISODateTimeParseResult *out, int flags);
+
+/* Helper for Temporal.prototype.toLocaleString using Intl.DateTimeFormat.
+ Falls back to toString_func if Intl is not available. */
+JSValue ti_temporal_toLocaleString(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv,
+ int default_mode,
+ JSValue (*toString_func)(JSContext *, JSValueConst, int, JSValueConst *));
+
+#endif /* TEMPORAL_PRIVATE_H */
--- /dev/null
+#include <string.h>
+#include <stdint.h>
+#include "timezone.h"
+#include "../cutils.h"
+
+static const char * const tz_aliases[][2] = {
+ {"America/Atka", "America/Adak"},
+ {"America/Knox_IN", "America/Indiana/Knox"},
+ {"Asia/Ashkhabad", "Asia/Ashgabat"},
+ {"Asia/Calcutta", "Asia/Kolkata"},
+ {"Asia/Dacca", "Asia/Dhaka"},
+ {"Asia/Istanbul", "Europe/Istanbul"},
+ {"Asia/Macao", "Asia/Macau"},
+ {"Asia/Saigon", "Asia/Ho_Chi_Minh"},
+ {"Asia/Tel_Aviv", "Asia/Jerusalem"},
+ {"Asia/Thimbu", "Asia/Thimphu"},
+ {"Asia/Ujung_Pandang", "Asia/Makassar"},
+ {"Asia/Ulan_Bator", "Asia/Ulaanbaatar"},
+ {"Atlantic/Faeroe", "Atlantic/Faroe"},
+ {"Australia/ACT", "Australia/Sydney"},
+ {"Australia/Canberra", "Australia/Sydney"},
+ {"Australia/LHI", "Australia/Lord_Howe"},
+ {"Australia/North", "Australia/Darwin"},
+ {"Australia/NSW", "Australia/Sydney"},
+ {"Australia/Queensland", "Australia/Brisbane"},
+ {"Australia/South", "Australia/Adelaide"},
+ {"Australia/Tasmania", "Australia/Hobart"},
+ {"Australia/Victoria", "Australia/Melbourne"},
+ {"Australia/West", "Australia/Perth"},
+ {"Australia/Yancowinna", "Australia/Broken_Hill"},
+ {"Brazil/Acre", "America/Rio_Branco"},
+ {"Brazil/DeNoronha", "America/Noronha"},
+ {"Brazil/East", "America/Sao_Paulo"},
+ {"Brazil/West", "America/Manaus"},
+ {"Canada/Atlantic", "America/Halifax"},
+ {"Canada/Central", "America/Winnipeg"},
+ {"Canada/Eastern", "America/Toronto"},
+ {"Canada/Mountain", "America/Edmonton"},
+ {"Canada/Newfoundland", "America/St_Johns"},
+ {"Canada/Pacific", "America/Vancouver"},
+ {"Canada/Saskatchewan", "America/Regina"},
+ {"Canada/Yukon", "America/Whitehorse"},
+ {"Chile/Continental", "America/Santiago"},
+ {"Chile/EasterIsland", "Pacific/Easter"},
+ {"Cuba", "America/Havana"},
+ {"Egypt", "Africa/Cairo"},
+ {"Eire", "Europe/Dublin"},
+ {"Europe/Belfast", "Europe/London"},
+ {"Europe/Tiraspol", "Europe/Chisinau"},
+ {"Hongkong", "Asia/Hong_Kong"},
+ {"Iceland", "Atlantic/Reykjavik"},
+ {"Iran", "Asia/Tehran"},
+ {"Israel", "Asia/Jerusalem"},
+ {"Jamaica", "America/Jamaica"},
+ {"Japan", "Asia/Tokyo"},
+ {"Kwajalein", "Pacific/Kwajalein"},
+ {"Libya", "Africa/Tripoli"},
+ {"Mexico/BajaNorte", "America/Tijuana"},
+ {"Mexico/BajaSur", "America/Mazatlan"},
+ {"Mexico/General", "America/Mexico_City"},
+ {"NZ", "Pacific/Auckland"},
+ {"NZ-CHAT", "Pacific/Chatham"},
+ {"Navajo", "America/Denver"},
+ {"Pacific/Samoa", "Pacific/Pago_Pago"},
+ {"Poland", "Europe/Warsaw"},
+ {"Portugal", "Europe/Lisbon"},
+ {"PRC", "Asia/Shanghai"},
+ {"ROC", "Asia/Taipei"},
+ {"ROK", "Asia/Seoul"},
+ {"Singapore", "Asia/Singapore"},
+ {"Turkey", "Europe/Istanbul"},
+ {"US/Alaska", "America/Anchorage"},
+ {"US/Aleutian", "America/Adak"},
+ {"US/Arizona", "America/Phoenix"},
+ {"US/Central", "America/Chicago"},
+ {"US/East-Indiana", "America/Indiana/Indianapolis"},
+ {"US/Eastern", "America/New_York"},
+ {"US/Hawaii", "Pacific/Honolulu"},
+ {"US/Indiana-Starke", "America/Indiana/Knox"},
+ {"US/Michigan", "America/Detroit"},
+ {"US/Mountain", "America/Denver"},
+ {"US/Pacific", "America/Los_Angeles"},
+ {"US/Samoa", "Pacific/Pago_Pago"},
+ {"W-SU", "Europe/Moscow"},
+};
+
+static const char *ti_tz_canonical_name(int tz_id) {
+ if (tz_id < 0 || tz_id >= ti_tz_zone_count)
+ return NULL;
+ return ti_tz_zone_data[tz_id].canonical_name;
+}
+
+const char *ti_canonicalize_timezone_alias(const char *tz)
+{
+ int i;
+ int n = (int)(sizeof(tz_aliases) / sizeof(tz_aliases[0]));
+ for (i = 0; i < n; i++) {
+ if (strcmp(tz, tz_aliases[i][0]) == 0)
+ return tz_aliases[i][1];
+ if (strcmp(tz, tz_aliases[i][1]) == 0)
+ return tz_aliases[i][1];
+ }
+ int id = ti_tz_find_id(tz);
+ if (id >= 0) {
+ const char *canon = ti_tz_canonical_name(id);
+ if (canon)
+ return canon;
+ }
+ return tz;
+}
+
+BOOL ti_timezones_are_equal(const char *tz1, const char *tz2)
+{
+ if (strcmp(tz1, tz2) == 0)
+ return TRUE;
+ if (strcasecmp(tz1, tz2) == 0)
+ return TRUE;
+ const char *c1 = ti_canonicalize_timezone_alias(tz1);
+ const char *c2 = ti_canonicalize_timezone_alias(tz2);
+ return strcmp(c1, c2) == 0;
+}
+
+int ti_tz_find_id(const char *name) {
+ int i;
+ for (i = 0; i < ti_tz_alias_count; i++) {
+ if (strcasecmp(name, ti_tz_aliases[i].alias) == 0)
+ return ti_tz_aliases[i].canonical_id;
+ }
+ for (i = 0; i < ti_tz_zone_count; i++) {
+ if (strcasecmp(name, ti_tz_zone_data[i].canonical_name) == 0)
+ return i;
+ }
+ return -1;
+}
+
+int ti_tz_offset_at_sec(int tz_id, int64_t epoch_sec) {
+ const TZData *tz;
+ const TZTransition *tr;
+ int n, lo, hi, mid;
+ if (tz_id < 0 || tz_id >= ti_tz_zone_count)
+ return 0;
+ tz = &ti_tz_zone_data[tz_id];
+ tr = tz->transitions;
+ n = tz->transition_count;
+ lo = 0;
+ hi = n;
+ while (lo < hi) {
+ mid = (lo + hi) >> 1;
+ if (tr[mid].start_sec <= epoch_sec)
+ lo = mid + 1;
+ else
+ hi = mid;
+ }
+ if (lo > 0)
+ return tr[lo - 1].offset_sec;
+ return 0;
+}
+
+int64_t ti_tz_next_transition_sec(int tz_id, int64_t epoch_sec) {
+ const TZData *tz;
+ const TZTransition *tr;
+ int n, lo, hi, mid;
+ if (tz_id < 0 || tz_id >= ti_tz_zone_count)
+ return INT64_MIN;
+ tz = &ti_tz_zone_data[tz_id];
+ tr = tz->transitions;
+ n = tz->transition_count;
+ lo = 0;
+ hi = n;
+ while (lo < hi) {
+ mid = (lo + hi) >> 1;
+ if (tr[mid].start_sec <= epoch_sec)
+ lo = mid + 1;
+ else
+ hi = mid;
+ }
+ if (lo < n)
+ return tr[lo].start_sec;
+ return INT64_MIN;
+}
+
+int64_t ti_tz_next_transition_at(int tz_id, int64_t epoch_sec, int epoch_nsec) {
+ const TZData *tz;
+ const TZTransition *tr;
+ int n, lo, hi, mid;
+ if (tz_id < 0 || tz_id >= ti_tz_zone_count)
+ return INT64_MIN;
+ tz = &ti_tz_zone_data[tz_id];
+ tr = tz->transitions;
+ n = tz->transition_count;
+ lo = 0;
+ hi = n;
+ while (lo < hi) {
+ mid = (lo + hi) >> 1;
+ if (tr[mid].start_sec < epoch_sec || (tr[mid].start_sec == epoch_sec && epoch_nsec >= 0))
+ lo = mid + 1;
+ else
+ hi = mid;
+ }
+ /* Skip no-op transitions where the offset doesn't change */
+ while (lo < n && tr[lo].offset_sec == tr[lo - 1].offset_sec)
+ lo++;
+ if (lo < n)
+ return tr[lo].start_sec;
+ return INT64_MIN;
+}
+
+int64_t ti_tz_prev_transition_at(int tz_id, int64_t epoch_sec, int epoch_nsec) {
+ const TZData *tz;
+ const TZTransition *tr;
+ int n, lo, hi, mid;
+ if (tz_id < 0 || tz_id >= ti_tz_zone_count)
+ return INT64_MIN;
+ tz = &ti_tz_zone_data[tz_id];
+ tr = tz->transitions;
+ n = tz->transition_count;
+ lo = 0;
+ hi = n;
+ while (lo < hi) {
+ mid = (lo + hi) >> 1;
+ if (tr[mid].start_sec < epoch_sec || (tr[mid].start_sec == epoch_sec && epoch_nsec > 0))
+ lo = mid + 1;
+ else
+ hi = mid;
+ }
+ /* Skip no-op transitions where the offset doesn't change */
+ {
+ int i = lo - 1;
+ while (i >= 1 && tr[i].offset_sec == tr[i - 1].offset_sec)
+ i--;
+ if (i >= 1)
+ return tr[i].start_sec;
+ }
+ return INT64_MIN;
+}
+
+int ti_tz_prev_offset_at_sec(int tz_id, int64_t epoch_sec) {
+ const TZData *tz;
+ const TZTransition *tr;
+ int n, lo, hi, mid;
+ if (tz_id < 0 || tz_id >= ti_tz_zone_count)
+ return 0;
+ tz = &ti_tz_zone_data[tz_id];
+ tr = tz->transitions;
+ n = tz->transition_count;
+ lo = 0;
+ hi = n;
+ while (lo < hi) {
+ mid = (lo + hi) >> 1;
+ if (tr[mid].start_sec <= epoch_sec)
+ lo = mid + 1;
+ else
+ hi = mid;
+ }
+ /* lo-1 is the active transition, lo-2 is the previous one */
+ if (lo > 1)
+ return tr[lo - 2].offset_sec;
+ return tr[0].offset_sec;
+}
+
+/* Convert local wall-clock time to UTC epoch for a named timezone.
+ dis_idx: 0=earlier, 1=later, 2=compatible, 3=reject.
+ Returns 0 on success, -1 if reject disambiguation throws (caller should throw RangeError).
+ On success, *out_utc_sec and *out_offset_sec are set. */
+int ti_tz_local_to_utc(int tz_id, int64_t local_sec, int dis_idx,
+ int64_t *out_utc_sec, int *out_offset_sec)
+{
+ int64_t guess_sec = local_sec;
+ int iter;
+ int converged = 0;
+ int64_t utc1 = 0;
+ int offset1 = 0;
+
+ for (iter = 0; iter < 4; iter++) {
+ int offset_sec = ti_tz_offset_at_sec(tz_id, guess_sec);
+ int64_t new_sec = local_sec - offset_sec;
+ if (new_sec == guess_sec) {
+ utc1 = guess_sec;
+ offset1 = offset_sec;
+ converged = 1;
+ break;
+ }
+ guess_sec = new_sec;
+ }
+
+ if (converged) {
+ /* Check for ambiguity (overlap): another candidate with prev offset */
+ int prev_offset = ti_tz_prev_offset_at_sec(tz_id, utc1);
+ if (prev_offset != offset1) {
+ int64_t cand2 = local_sec - prev_offset;
+ if (cand2 != utc1 && ti_tz_offset_at_sec(tz_id, cand2) == prev_offset) {
+ /* Two candidates - sort by UTC time */
+ int64_t earlier_utc, later_utc;
+ int earlier_offset, later_offset;
+ if (cand2 < utc1) {
+ earlier_utc = cand2;
+ earlier_offset = prev_offset;
+ later_utc = utc1;
+ later_offset = offset1;
+ } else {
+ earlier_utc = utc1;
+ earlier_offset = offset1;
+ later_utc = cand2;
+ later_offset = prev_offset;
+ }
+ if (dis_idx == 3) /* reject */
+ return -1;
+ if (dis_idx == 1) { /* later */
+ *out_utc_sec = later_utc;
+ *out_offset_sec = later_offset;
+ } else { /* compatible / earlier */
+ *out_utc_sec = earlier_utc;
+ *out_offset_sec = earlier_offset;
+ }
+ return 0;
+ }
+ }
+ /* Single candidate */
+ *out_utc_sec = utc1;
+ *out_offset_sec = offset1;
+ return 0;
+ } else {
+ /* Gap - no converged value */
+ int64_t guess1 = guess_sec;
+ int offset_guess1 = ti_tz_offset_at_sec(tz_id, guess1);
+ int64_t guess2 = local_sec - offset_guess1;
+ int offset_guess2 = ti_tz_offset_at_sec(tz_id, guess2);
+ int64_t mapped_local1 = guess1 + offset_guess1;
+ int64_t mapped_local2 = guess2 + offset_guess2;
+
+ if (dis_idx == 3) /* reject */
+ return -1;
+
+ if (dis_idx == 0) { /* earlier: use candidate mapping to earlier local time */
+ if (mapped_local1 < mapped_local2) {
+ *out_utc_sec = guess1;
+ *out_offset_sec = offset_guess1;
+ } else {
+ *out_utc_sec = guess2;
+ *out_offset_sec = offset_guess2;
+ }
+ } else { /* compatible / later */
+ if (mapped_local1 > mapped_local2) {
+ *out_utc_sec = guess1;
+ *out_offset_sec = offset_guess1;
+ } else {
+ *out_utc_sec = guess2;
+ *out_offset_sec = offset_guess2;
+ }
+ }
+ return 0;
+ }
+}
+
+/* GetStartOfDay: return the UTC epoch for the start of a local day.
+ Uses the spec GetStartOfDay algorithm:
+ - Try earlier disambiguation for midnight local time
+ - If midnight maps back correctly, that's the start of day
+ - Otherwise (gap at midnight), return the next transition after (midnight - 1 day)
+ Returns the UTC epoch, or INT64_MIN on error (should not happen for valid days). */
+int64_t ti_get_start_of_day_sec(int tz_id, int64_t local_day_start_sec)
+{
+ int64_t utc_sec;
+ int out_offset_sec;
+ if (ti_tz_local_to_utc(tz_id, local_day_start_sec, 0, &utc_sec, &out_offset_sec) < 0)
+ return INT64_MIN;
+ if (utc_sec + ti_tz_offset_at_sec(tz_id, utc_sec) == local_day_start_sec)
+ return utc_sec;
+ /* Gap at midnight: return the next transition after (midnight - 1 day) */
+ {
+ int64_t next_trans = ti_tz_next_transition_sec(tz_id, local_day_start_sec - 86400LL);
+ if (next_trans != INT64_MIN)
+ return next_trans;
+ }
+ return utc_sec;
+}
--- /dev/null
+#ifndef TIMEZONE_H
+#define TIMEZONE_H
+
+#include <stdint.h>
+#include "../cutils.h"
+
+typedef struct {
+ int64_t start_sec;
+ int32_t offset_sec;
+} TZTransition;
+
+typedef struct {
+ const char *canonical_name;
+ const TZTransition *transitions;
+ int transition_count;
+} TZData;
+
+typedef struct {
+ const char *alias;
+ int canonical_id;
+} TZAlias;
+
+/* Generated data (in tzdata_generated.c) */
+extern const int ti_tz_zone_count;
+extern const TZData ti_tz_zone_data[];
+extern const TZAlias ti_tz_aliases[];
+extern const int ti_tz_alias_count;
+
+/* Lookup functions */
+int ti_tz_find_id(const char *name);
+int ti_tz_offset_at_sec(int tz_id, int64_t epoch_sec);
+int ti_tz_prev_offset_at_sec(int tz_id, int64_t epoch_sec);
+int64_t ti_tz_next_transition_sec(int tz_id, int64_t epoch_sec);
+int64_t ti_tz_next_transition_at(int tz_id, int64_t epoch_sec, int epoch_nsec);
+int64_t ti_tz_prev_transition_at(int tz_id, int64_t epoch_sec, int epoch_nsec);
+
+
+/* Timezone alias canonicalization and equality */
+const char *ti_canonicalize_timezone_alias(const char *tz);
+int ti_timezones_are_equal(const char *tz1, const char *tz2);
+
+/* Convert local wall-clock time to UTC epoch for a named timezone.
+ dis_idx: 0=earlier, 1=later, 2=compatible, 3=reject.
+ Returns 0 on success, -1 if reject disambiguation throws (caller should throw RangeError).
+ On success, *out_utc_sec and *out_offset_sec are set. */
+int ti_tz_local_to_utc(int tz_id, int64_t local_sec, int dis_idx,
+ int64_t *out_utc_sec, int *out_offset_sec);
+int64_t ti_get_start_of_day_sec(int tz_id, int64_t local_day_start_sec);
+
+#endif
--- /dev/null
+/* Auto-generated by gen_tzdata.py — DO NOT EDIT */
+#include "timezone.h"
+
+static const TZTransition tz_trans_Africa_Monrovia[] = {
+ { INT64_MIN, -2588 }, /* before first transition */
+ { -2776979812LL, -2588 }, /* 1882-01-01T00:43:08Z */
+ { -1604359012LL, -2670 }, /* 1919-03-01T00:43:08Z */
+ { 63593070LL, 0 }, /* 1972-01-07T00:44:30Z */
+};
+
+static const TZTransition tz_trans_Africa_Tunis[] = {
+ { INT64_MIN, 2444 }, /* before first transition */
+ { -2797202444LL, 561 }, /* 1881-05-11T23:19:16Z */
+ { -1855958961LL, 3600 }, /* 1911-03-10T23:50:39Z */
+ { -969242400LL, 7200 }, /* 1939-04-15T22:00:00Z */
+ { -950493600LL, 3600 }, /* 1939-11-18T22:00:00Z */
+ { -941940000LL, 7200 }, /* 1940-02-25T22:00:00Z */
+ { -891136800LL, 3600 }, /* 1941-10-05T22:00:00Z */
+ { -877827600LL, 7200 }, /* 1942-03-08T23:00:00Z */
+ { -857257200LL, 3600 }, /* 1942-11-02T01:00:00Z */
+ { -844556400LL, 7200 }, /* 1943-03-29T01:00:00Z */
+ { -842918400LL, 3600 }, /* 1943-04-17T00:00:00Z */
+ { -842223600LL, 7200 }, /* 1943-04-25T01:00:00Z */
+ { -828230400LL, 3600 }, /* 1943-10-04T00:00:00Z */
+ { -812502000LL, 7200 }, /* 1944-04-03T01:00:00Z */
+ { -796269600LL, 3600 }, /* 1944-10-07T22:00:00Z */
+ { -781052400LL, 7200 }, /* 1945-04-02T01:00:00Z */
+ { -766634400LL, 3600 }, /* 1945-09-15T22:00:00Z */
+ { 231202800LL, 7200 }, /* 1977-04-29T23:00:00Z */
+ { 243903600LL, 3600 }, /* 1977-09-23T23:00:00Z */
+ { 262825200LL, 7200 }, /* 1978-04-30T23:00:00Z */
+ { 276044400LL, 3600 }, /* 1978-09-30T23:00:00Z */
+ { 581122800LL, 7200 }, /* 1988-05-31T23:00:00Z */
+ { 591145200LL, 3600 }, /* 1988-09-24T23:00:00Z */
+ { 606870000LL, 7200 }, /* 1989-03-25T23:00:00Z */
+ { 622594800LL, 3600 }, /* 1989-09-23T23:00:00Z */
+ { 641516400LL, 7200 }, /* 1990-04-30T23:00:00Z */
+ { 654649200LL, 3600 }, /* 1990-09-29T23:00:00Z */
+ { 1114902000LL, 7200 }, /* 2005-04-30T23:00:00Z */
+ { 1128038400LL, 3600 }, /* 2005-09-30T00:00:00Z */
+ { 1143334800LL, 7200 }, /* 2006-03-26T01:00:00Z */
+ { 1162083600LL, 3600 }, /* 2006-10-29T01:00:00Z */
+ { 1174784400LL, 7200 }, /* 2007-03-25T01:00:00Z */
+ { 1193533200LL, 3600 }, /* 2007-10-28T01:00:00Z */
+ { 1206838800LL, 7200 }, /* 2008-03-30T01:00:00Z */
+ { 1224982800LL, 3600 }, /* 2008-10-26T01:00:00Z */
+};
+
+static const TZTransition tz_trans_America_Anchorage[] = {
+ { INT64_MIN, 50424 }, /* before first transition */
+ { -3225223727LL, -35976 }, /* 1867-10-19T00:31:13Z */
+ { -2188951224LL, -36000 }, /* 1900-08-20T21:59:36Z */
+ { -880200000LL, -32400 }, /* 1942-02-09T12:00:00Z */
+ { -769395600LL, -32400 }, /* 1945-08-14T23:00:00Z */
+ { -765378000LL, -36000 }, /* 1945-09-30T11:00:00Z */
+ { -86882400LL, -36000 }, /* 1967-04-01T10:00:00Z */
+ { -21470400LL, -32400 }, /* 1969-04-27T12:00:00Z */
+ { -5749200LL, -36000 }, /* 1969-10-26T11:00:00Z */
+ { 9979200LL, -32400 }, /* 1970-04-26T12:00:00Z */
+ { 25700400LL, -36000 }, /* 1970-10-25T11:00:00Z */
+ { 41428800LL, -32400 }, /* 1971-04-25T12:00:00Z */
+ { 57754800LL, -36000 }, /* 1971-10-31T11:00:00Z */
+ { 73483200LL, -32400 }, /* 1972-04-30T12:00:00Z */
+ { 89204400LL, -36000 }, /* 1972-10-29T11:00:00Z */
+ { 104932800LL, -32400 }, /* 1973-04-29T12:00:00Z */
+ { 120654000LL, -36000 }, /* 1973-10-28T11:00:00Z */
+ { 126705600LL, -32400 }, /* 1974-01-06T12:00:00Z */
+ { 152103600LL, -36000 }, /* 1974-10-27T11:00:00Z */
+ { 162388800LL, -32400 }, /* 1975-02-23T12:00:00Z */
+ { 183553200LL, -36000 }, /* 1975-10-26T11:00:00Z */
+ { 199281600LL, -32400 }, /* 1976-04-25T12:00:00Z */
+ { 215607600LL, -36000 }, /* 1976-10-31T11:00:00Z */
+ { 230731200LL, -32400 }, /* 1977-04-24T12:00:00Z */
+ { 247057200LL, -36000 }, /* 1977-10-30T11:00:00Z */
+ { 262785600LL, -32400 }, /* 1978-04-30T12:00:00Z */
+ { 278506800LL, -36000 }, /* 1978-10-29T11:00:00Z */
+ { 294235200LL, -32400 }, /* 1979-04-29T12:00:00Z */
+ { 309956400LL, -36000 }, /* 1979-10-28T11:00:00Z */
+ { 325684800LL, -32400 }, /* 1980-04-27T12:00:00Z */
+ { 341406000LL, -36000 }, /* 1980-10-26T11:00:00Z */
+ { 357134400LL, -32400 }, /* 1981-04-26T12:00:00Z */
+ { 372855600LL, -36000 }, /* 1981-10-25T11:00:00Z */
+ { 388584000LL, -32400 }, /* 1982-04-25T12:00:00Z */
+ { 404910000LL, -36000 }, /* 1982-10-31T11:00:00Z */
+ { 420033600LL, -32400 }, /* 1983-04-24T12:00:00Z */
+ { 436359600LL, -32400 }, /* 1983-10-30T11:00:00Z */
+ { 439030800LL, -32400 }, /* 1983-11-30T09:00:00Z */
+ { 452084400LL, -28800 }, /* 1984-04-29T11:00:00Z */
+ { 467805600LL, -32400 }, /* 1984-10-28T10:00:00Z */
+ { 483534000LL, -28800 }, /* 1985-04-28T11:00:00Z */
+ { 499255200LL, -32400 }, /* 1985-10-27T10:00:00Z */
+ { 514983600LL, -28800 }, /* 1986-04-27T11:00:00Z */
+ { 530704800LL, -32400 }, /* 1986-10-26T10:00:00Z */
+ { 544618800LL, -28800 }, /* 1987-04-05T11:00:00Z */
+ { 562154400LL, -32400 }, /* 1987-10-25T10:00:00Z */
+ { 576068400LL, -28800 }, /* 1988-04-03T11:00:00Z */
+ { 594208800LL, -32400 }, /* 1988-10-30T10:00:00Z */
+ { 607518000LL, -28800 }, /* 1989-04-02T11:00:00Z */
+ { 625658400LL, -32400 }, /* 1989-10-29T10:00:00Z */
+ { 638967600LL, -28800 }, /* 1990-04-01T11:00:00Z */
+ { 657108000LL, -32400 }, /* 1990-10-28T10:00:00Z */
+ { 671022000LL, -28800 }, /* 1991-04-07T11:00:00Z */
+ { 688557600LL, -32400 }, /* 1991-10-27T10:00:00Z */
+ { 702471600LL, -28800 }, /* 1992-04-05T11:00:00Z */
+ { 720007200LL, -32400 }, /* 1992-10-25T10:00:00Z */
+ { 733921200LL, -28800 }, /* 1993-04-04T11:00:00Z */
+ { 752061600LL, -32400 }, /* 1993-10-31T10:00:00Z */
+ { 765370800LL, -28800 }, /* 1994-04-03T11:00:00Z */
+ { 783511200LL, -32400 }, /* 1994-10-30T10:00:00Z */
+ { 796820400LL, -28800 }, /* 1995-04-02T11:00:00Z */
+ { 814960800LL, -32400 }, /* 1995-10-29T10:00:00Z */
+ { 828874800LL, -28800 }, /* 1996-04-07T11:00:00Z */
+ { 846410400LL, -32400 }, /* 1996-10-27T10:00:00Z */
+ { 860324400LL, -28800 }, /* 1997-04-06T11:00:00Z */
+ { 877860000LL, -32400 }, /* 1997-10-26T10:00:00Z */
+ { 891774000LL, -28800 }, /* 1998-04-05T11:00:00Z */
+ { 909309600LL, -32400 }, /* 1998-10-25T10:00:00Z */
+ { 923223600LL, -28800 }, /* 1999-04-04T11:00:00Z */
+ { 941364000LL, -32400 }, /* 1999-10-31T10:00:00Z */
+ { 954673200LL, -28800 }, /* 2000-04-02T11:00:00Z */
+ { 972813600LL, -32400 }, /* 2000-10-29T10:00:00Z */
+ { 986122800LL, -28800 }, /* 2001-04-01T11:00:00Z */
+ { 1004263200LL, -32400 }, /* 2001-10-28T10:00:00Z */
+ { 1018177200LL, -28800 }, /* 2002-04-07T11:00:00Z */
+ { 1035712800LL, -32400 }, /* 2002-10-27T10:00:00Z */
+ { 1049626800LL, -28800 }, /* 2003-04-06T11:00:00Z */
+ { 1067162400LL, -32400 }, /* 2003-10-26T10:00:00Z */
+ { 1081076400LL, -28800 }, /* 2004-04-04T11:00:00Z */
+ { 1099216800LL, -32400 }, /* 2004-10-31T10:00:00Z */
+ { 1112526000LL, -28800 }, /* 2005-04-03T11:00:00Z */
+ { 1130666400LL, -32400 }, /* 2005-10-30T10:00:00Z */
+ { 1143975600LL, -28800 }, /* 2006-04-02T11:00:00Z */
+ { 1162116000LL, -32400 }, /* 2006-10-29T10:00:00Z */
+ { 1173610800LL, -28800 }, /* 2007-03-11T11:00:00Z */
+ { 1194170400LL, -32400 }, /* 2007-11-04T10:00:00Z */
+ { 1205060400LL, -28800 }, /* 2008-03-09T11:00:00Z */
+ { 1225620000LL, -32400 }, /* 2008-11-02T10:00:00Z */
+ { 1236510000LL, -28800 }, /* 2009-03-08T11:00:00Z */
+ { 1257069600LL, -32400 }, /* 2009-11-01T10:00:00Z */
+ { 1268564400LL, -28800 }, /* 2010-03-14T11:00:00Z */
+ { 1289124000LL, -32400 }, /* 2010-11-07T10:00:00Z */
+ { 1300014000LL, -28800 }, /* 2011-03-13T11:00:00Z */
+ { 1320573600LL, -32400 }, /* 2011-11-06T10:00:00Z */
+ { 1331463600LL, -28800 }, /* 2012-03-11T11:00:00Z */
+ { 1352023200LL, -32400 }, /* 2012-11-04T10:00:00Z */
+ { 1362913200LL, -28800 }, /* 2013-03-10T11:00:00Z */
+ { 1383472800LL, -32400 }, /* 2013-11-03T10:00:00Z */
+ { 1394362800LL, -28800 }, /* 2014-03-09T11:00:00Z */
+ { 1414922400LL, -32400 }, /* 2014-11-02T10:00:00Z */
+ { 1425812400LL, -28800 }, /* 2015-03-08T11:00:00Z */
+ { 1446372000LL, -32400 }, /* 2015-11-01T10:00:00Z */
+ { 1457866800LL, -28800 }, /* 2016-03-13T11:00:00Z */
+ { 1478426400LL, -32400 }, /* 2016-11-06T10:00:00Z */
+ { 1489316400LL, -28800 }, /* 2017-03-12T11:00:00Z */
+ { 1509876000LL, -32400 }, /* 2017-11-05T10:00:00Z */
+ { 1520766000LL, -28800 }, /* 2018-03-11T11:00:00Z */
+ { 1541325600LL, -32400 }, /* 2018-11-04T10:00:00Z */
+ { 1552215600LL, -28800 }, /* 2019-03-10T11:00:00Z */
+ { 1572775200LL, -32400 }, /* 2019-11-03T10:00:00Z */
+ { 1583665200LL, -28800 }, /* 2020-03-08T11:00:00Z */
+ { 1604224800LL, -32400 }, /* 2020-11-01T10:00:00Z */
+ { 1615719600LL, -28800 }, /* 2021-03-14T11:00:00Z */
+ { 1636279200LL, -32400 }, /* 2021-11-07T10:00:00Z */
+ { 1647169200LL, -28800 }, /* 2022-03-13T11:00:00Z */
+ { 1667728800LL, -32400 }, /* 2022-11-06T10:00:00Z */
+ { 1678618800LL, -28800 }, /* 2023-03-12T11:00:00Z */
+ { 1699178400LL, -32400 }, /* 2023-11-05T10:00:00Z */
+ { 1710068400LL, -28800 }, /* 2024-03-10T11:00:00Z */
+ { 1730628000LL, -32400 }, /* 2024-11-03T10:00:00Z */
+ { 1741518000LL, -28800 }, /* 2025-03-09T11:00:00Z */
+ { 1762077600LL, -32400 }, /* 2025-11-02T10:00:00Z */
+ { 1772967600LL, -28800 }, /* 2026-03-08T11:00:00Z */
+ { 1793527200LL, -32400 }, /* 2026-11-01T10:00:00Z */
+ { 1805022000LL, -28800 }, /* 2027-03-14T11:00:00Z */
+ { 1825581600LL, -32400 }, /* 2027-11-07T10:00:00Z */
+ { 1836471600LL, -28800 }, /* 2028-03-12T11:00:00Z */
+ { 1857031200LL, -32400 }, /* 2028-11-05T10:00:00Z */
+ { 1867921200LL, -28800 }, /* 2029-03-11T11:00:00Z */
+ { 1888480800LL, -32400 }, /* 2029-11-04T10:00:00Z */
+ { 1899370800LL, -28800 }, /* 2030-03-10T11:00:00Z */
+ { 1919930400LL, -32400 }, /* 2030-11-03T10:00:00Z */
+ { 1930820400LL, -28800 }, /* 2031-03-09T11:00:00Z */
+ { 1951380000LL, -32400 }, /* 2031-11-02T10:00:00Z */
+ { 1962874800LL, -28800 }, /* 2032-03-14T11:00:00Z */
+ { 1983434400LL, -32400 }, /* 2032-11-07T10:00:00Z */
+ { 1994324400LL, -28800 }, /* 2033-03-13T11:00:00Z */
+ { 2014884000LL, -32400 }, /* 2033-11-06T10:00:00Z */
+ { 2025774000LL, -28800 }, /* 2034-03-12T11:00:00Z */
+ { 2046333600LL, -32400 }, /* 2034-11-05T10:00:00Z */
+ { 2057223600LL, -28800 }, /* 2035-03-11T11:00:00Z */
+ { 2077783200LL, -32400 }, /* 2035-11-04T10:00:00Z */
+ { 2088673200LL, -28800 }, /* 2036-03-09T11:00:00Z */
+ { 2109232800LL, -32400 }, /* 2036-11-02T10:00:00Z */
+ { 2120122800LL, -28800 }, /* 2037-03-08T11:00:00Z */
+ { 2140682400LL, -32400 }, /* 2037-11-01T10:00:00Z */
+};
+
+static const TZTransition tz_trans_America_Argentina_Tucuman[] = {
+ { INT64_MIN, -15652 }, /* before first transition */
+ { -2372096348LL, -15408 }, /* 1894-10-31T04:20:52Z */
+ { -1567453392LL, -14400 }, /* 1920-05-01T04:16:48Z */
+ { -1233432000LL, -10800 }, /* 1930-12-01T04:00:00Z */
+ { -1222981200LL, -14400 }, /* 1931-04-01T03:00:00Z */
+ { -1205956800LL, -10800 }, /* 1931-10-15T04:00:00Z */
+ { -1194037200LL, -14400 }, /* 1932-03-01T03:00:00Z */
+ { -1172865600LL, -10800 }, /* 1932-11-01T04:00:00Z */
+ { -1162501200LL, -14400 }, /* 1933-03-01T03:00:00Z */
+ { -1141329600LL, -10800 }, /* 1933-11-01T04:00:00Z */
+ { -1130965200LL, -14400 }, /* 1934-03-01T03:00:00Z */
+ { -1109793600LL, -10800 }, /* 1934-11-01T04:00:00Z */
+ { -1099429200LL, -14400 }, /* 1935-03-01T03:00:00Z */
+ { -1078257600LL, -10800 }, /* 1935-11-01T04:00:00Z */
+ { -1067806800LL, -14400 }, /* 1936-03-01T03:00:00Z */
+ { -1046635200LL, -10800 }, /* 1936-11-01T04:00:00Z */
+ { -1036270800LL, -14400 }, /* 1937-03-01T03:00:00Z */
+ { -1015099200LL, -10800 }, /* 1937-11-01T04:00:00Z */
+ { -1004734800LL, -14400 }, /* 1938-03-01T03:00:00Z */
+ { -983563200LL, -10800 }, /* 1938-11-01T04:00:00Z */
+ { -973198800LL, -14400 }, /* 1939-03-01T03:00:00Z */
+ { -952027200LL, -10800 }, /* 1939-11-01T04:00:00Z */
+ { -941576400LL, -14400 }, /* 1940-03-01T03:00:00Z */
+ { -931032000LL, -10800 }, /* 1940-07-01T04:00:00Z */
+ { -900882000LL, -14400 }, /* 1941-06-15T03:00:00Z */
+ { -890337600LL, -10800 }, /* 1941-10-15T04:00:00Z */
+ { -833749200LL, -14400 }, /* 1943-08-01T03:00:00Z */
+ { -827265600LL, -10800 }, /* 1943-10-15T04:00:00Z */
+ { -752274000LL, -14400 }, /* 1946-03-01T03:00:00Z */
+ { -733780800LL, -10800 }, /* 1946-10-01T04:00:00Z */
+ { -197326800LL, -14400 }, /* 1963-10-01T03:00:00Z */
+ { -190843200LL, -10800 }, /* 1963-12-15T04:00:00Z */
+ { -184194000LL, -14400 }, /* 1964-03-01T03:00:00Z */
+ { -164491200LL, -10800 }, /* 1964-10-15T04:00:00Z */
+ { -152658000LL, -14400 }, /* 1965-03-01T03:00:00Z */
+ { -132955200LL, -10800 }, /* 1965-10-15T04:00:00Z */
+ { -121122000LL, -14400 }, /* 1966-03-01T03:00:00Z */
+ { -101419200LL, -10800 }, /* 1966-10-15T04:00:00Z */
+ { -86821200LL, -14400 }, /* 1967-04-02T03:00:00Z */
+ { -71092800LL, -10800 }, /* 1967-10-01T04:00:00Z */
+ { -54766800LL, -14400 }, /* 1968-04-07T03:00:00Z */
+ { -39038400LL, -10800 }, /* 1968-10-06T04:00:00Z */
+ { -23317200LL, -14400 }, /* 1969-04-06T03:00:00Z */
+ { -7588800LL, -10800 }, /* 1969-10-05T04:00:00Z */
+ { 128142000LL, -7200 }, /* 1974-01-23T03:00:00Z */
+ { 136605600LL, -10800 }, /* 1974-05-01T02:00:00Z */
+ { 596948400LL, -7200 }, /* 1988-12-01T03:00:00Z */
+ { 605066400LL, -10800 }, /* 1989-03-05T02:00:00Z */
+ { 624423600LL, -7200 }, /* 1989-10-15T03:00:00Z */
+ { 636516000LL, -10800 }, /* 1990-03-04T02:00:00Z */
+ { 656478000LL, -7200 }, /* 1990-10-21T03:00:00Z */
+ { 667965600LL, -14400 }, /* 1991-03-03T02:00:00Z */
+ { 687931200LL, -7200 }, /* 1991-10-20T04:00:00Z */
+ { 699415200LL, -10800 }, /* 1992-03-01T02:00:00Z */
+ { 719377200LL, -7200 }, /* 1992-10-18T03:00:00Z */
+ { 731469600LL, -10800 }, /* 1993-03-07T02:00:00Z */
+ { 938919600LL, -10800 }, /* 1999-10-03T03:00:00Z */
+ { 952052400LL, -10800 }, /* 2000-03-03T03:00:00Z */
+ { 1086058800LL, -14400 }, /* 2004-06-01T03:00:00Z */
+ { 1087099200LL, -10800 }, /* 2004-06-13T04:00:00Z */
+ { 1198983600LL, -7200 }, /* 2007-12-30T03:00:00Z */
+ { 1205632800LL, -10800 }, /* 2008-03-16T02:00:00Z */
+ { 1224385200LL, -7200 }, /* 2008-10-19T03:00:00Z */
+ { 1237082400LL, -10800 }, /* 2009-03-15T02:00:00Z */
+};
+
+static const TZTransition tz_trans_America_Boa_Vista[] = {
+ { INT64_MIN, -14560 }, /* before first transition */
+ { -1767211040LL, -14400 }, /* 1914-01-01T04:02:40Z */
+ { -1206954000LL, -10800 }, /* 1931-10-03T15:00:00Z */
+ { -1191358800LL, -14400 }, /* 1932-04-01T03:00:00Z */
+ { -1175371200LL, -10800 }, /* 1932-10-03T04:00:00Z */
+ { -1159822800LL, -14400 }, /* 1933-04-01T03:00:00Z */
+ { -633816000LL, -10800 }, /* 1949-12-01T04:00:00Z */
+ { -622065600LL, -14400 }, /* 1950-04-16T04:00:00Z */
+ { -602280000LL, -10800 }, /* 1950-12-01T04:00:00Z */
+ { -591829200LL, -14400 }, /* 1951-04-01T03:00:00Z */
+ { -570744000LL, -10800 }, /* 1951-12-01T04:00:00Z */
+ { -560206800LL, -14400 }, /* 1952-04-01T03:00:00Z */
+ { -539121600LL, -10800 }, /* 1952-12-01T04:00:00Z */
+ { -531349200LL, -14400 }, /* 1953-03-01T03:00:00Z */
+ { -191361600LL, -10800 }, /* 1963-12-09T04:00:00Z */
+ { -184194000LL, -14400 }, /* 1964-03-01T03:00:00Z */
+ { -155160000LL, -10800 }, /* 1965-01-31T04:00:00Z */
+ { -150066000LL, -14400 }, /* 1965-03-31T03:00:00Z */
+ { -128894400LL, -10800 }, /* 1965-12-01T04:00:00Z */
+ { -121122000LL, -14400 }, /* 1966-03-01T03:00:00Z */
+ { -99950400LL, -10800 }, /* 1966-11-01T04:00:00Z */
+ { -89586000LL, -14400 }, /* 1967-03-01T03:00:00Z */
+ { -68414400LL, -10800 }, /* 1967-11-01T04:00:00Z */
+ { -57963600LL, -14400 }, /* 1968-03-01T03:00:00Z */
+ { 499752000LL, -10800 }, /* 1985-11-02T04:00:00Z */
+ { 511239600LL, -14400 }, /* 1986-03-15T03:00:00Z */
+ { 530596800LL, -10800 }, /* 1986-10-25T04:00:00Z */
+ { 540270000LL, -14400 }, /* 1987-02-14T03:00:00Z */
+ { 562132800LL, -10800 }, /* 1987-10-25T04:00:00Z */
+ { 571201200LL, -14400 }, /* 1988-02-07T03:00:00Z */
+ { 938923200LL, -10800 }, /* 1999-10-03T04:00:00Z */
+ { 951620400LL, -14400 }, /* 2000-02-27T03:00:00Z */
+ { 970977600LL, -10800 }, /* 2000-10-08T04:00:00Z */
+ { 971578800LL, -14400 }, /* 2000-10-15T03:00:00Z */
+};
+
+static const TZTransition tz_trans_America_Fortaleza[] = {
+ { INT64_MIN, -9240 }, /* before first transition */
+ { -1767216360LL, -10800 }, /* 1914-01-01T02:34:00Z */
+ { -1206957600LL, -7200 }, /* 1931-10-03T14:00:00Z */
+ { -1191362400LL, -10800 }, /* 1932-04-01T02:00:00Z */
+ { -1175374800LL, -7200 }, /* 1932-10-03T03:00:00Z */
+ { -1159826400LL, -10800 }, /* 1933-04-01T02:00:00Z */
+ { -633819600LL, -7200 }, /* 1949-12-01T03:00:00Z */
+ { -622069200LL, -10800 }, /* 1950-04-16T03:00:00Z */
+ { -602283600LL, -7200 }, /* 1950-12-01T03:00:00Z */
+ { -591832800LL, -10800 }, /* 1951-04-01T02:00:00Z */
+ { -570747600LL, -7200 }, /* 1951-12-01T03:00:00Z */
+ { -560210400LL, -10800 }, /* 1952-04-01T02:00:00Z */
+ { -539125200LL, -7200 }, /* 1952-12-01T03:00:00Z */
+ { -531352800LL, -10800 }, /* 1953-03-01T02:00:00Z */
+ { -191365200LL, -7200 }, /* 1963-12-09T03:00:00Z */
+ { -184197600LL, -10800 }, /* 1964-03-01T02:00:00Z */
+ { -155163600LL, -7200 }, /* 1965-01-31T03:00:00Z */
+ { -150069600LL, -10800 }, /* 1965-03-31T02:00:00Z */
+ { -128898000LL, -7200 }, /* 1965-12-01T03:00:00Z */
+ { -121125600LL, -10800 }, /* 1966-03-01T02:00:00Z */
+ { -99954000LL, -7200 }, /* 1966-11-01T03:00:00Z */
+ { -89589600LL, -10800 }, /* 1967-03-01T02:00:00Z */
+ { -68418000LL, -7200 }, /* 1967-11-01T03:00:00Z */
+ { -57967200LL, -10800 }, /* 1968-03-01T02:00:00Z */
+ { 499748400LL, -7200 }, /* 1985-11-02T03:00:00Z */
+ { 511236000LL, -10800 }, /* 1986-03-15T02:00:00Z */
+ { 530593200LL, -7200 }, /* 1986-10-25T03:00:00Z */
+ { 540266400LL, -10800 }, /* 1987-02-14T02:00:00Z */
+ { 562129200LL, -7200 }, /* 1987-10-25T03:00:00Z */
+ { 571197600LL, -10800 }, /* 1988-02-07T02:00:00Z */
+ { 592974000LL, -7200 }, /* 1988-10-16T03:00:00Z */
+ { 602042400LL, -10800 }, /* 1989-01-29T02:00:00Z */
+ { 624423600LL, -7200 }, /* 1989-10-15T03:00:00Z */
+ { 634701600LL, -10800 }, /* 1990-02-11T02:00:00Z */
+ { 938919600LL, -7200 }, /* 1999-10-03T03:00:00Z */
+ { 951616800LL, -10800 }, /* 2000-02-27T02:00:00Z */
+ { 970974000LL, -7200 }, /* 2000-10-08T03:00:00Z */
+ { 972180000LL, -10800 }, /* 2000-10-22T02:00:00Z */
+ { 1003028400LL, -7200 }, /* 2001-10-14T03:00:00Z */
+ { 1013911200LL, -10800 }, /* 2002-02-17T02:00:00Z */
+};
+
+static const TZTransition tz_trans_America_Los_Angeles[] = {
+ { INT64_MIN, -28378 }, /* before first transition */
+ { -2717640000LL, -28800 }, /* 1883-11-18T20:00:00Z */
+ { -1633269600LL, -25200 }, /* 1918-03-31T10:00:00Z */
+ { -1615129200LL, -28800 }, /* 1918-10-27T09:00:00Z */
+ { -1601820000LL, -25200 }, /* 1919-03-30T10:00:00Z */
+ { -1583679600LL, -28800 }, /* 1919-10-26T09:00:00Z */
+ { -880207200LL, -25200 }, /* 1942-02-09T10:00:00Z */
+ { -769395600LL, -25200 }, /* 1945-08-14T23:00:00Z */
+ { -765385200LL, -28800 }, /* 1945-09-30T09:00:00Z */
+ { -687967140LL, -25200 }, /* 1948-03-14T10:01:00Z */
+ { -662655600LL, -28800 }, /* 1949-01-01T09:00:00Z */
+ { -620838000LL, -25200 }, /* 1950-04-30T09:00:00Z */
+ { -608137200LL, -28800 }, /* 1950-09-24T09:00:00Z */
+ { -589388400LL, -25200 }, /* 1951-04-29T09:00:00Z */
+ { -576082800LL, -28800 }, /* 1951-09-30T09:00:00Z */
+ { -557938800LL, -25200 }, /* 1952-04-27T09:00:00Z */
+ { -544633200LL, -28800 }, /* 1952-09-28T09:00:00Z */
+ { -526489200LL, -25200 }, /* 1953-04-26T09:00:00Z */
+ { -513183600LL, -28800 }, /* 1953-09-27T09:00:00Z */
+ { -495039600LL, -25200 }, /* 1954-04-25T09:00:00Z */
+ { -481734000LL, -28800 }, /* 1954-09-26T09:00:00Z */
+ { -463590000LL, -25200 }, /* 1955-04-24T09:00:00Z */
+ { -450284400LL, -28800 }, /* 1955-09-25T09:00:00Z */
+ { -431535600LL, -25200 }, /* 1956-04-29T09:00:00Z */
+ { -418230000LL, -28800 }, /* 1956-09-30T09:00:00Z */
+ { -400086000LL, -25200 }, /* 1957-04-28T09:00:00Z */
+ { -386780400LL, -28800 }, /* 1957-09-29T09:00:00Z */
+ { -368636400LL, -25200 }, /* 1958-04-27T09:00:00Z */
+ { -355330800LL, -28800 }, /* 1958-09-28T09:00:00Z */
+ { -337186800LL, -25200 }, /* 1959-04-26T09:00:00Z */
+ { -323881200LL, -28800 }, /* 1959-09-27T09:00:00Z */
+ { -305737200LL, -25200 }, /* 1960-04-24T09:00:00Z */
+ { -292431600LL, -28800 }, /* 1960-09-25T09:00:00Z */
+ { -273682800LL, -25200 }, /* 1961-04-30T09:00:00Z */
+ { -260982000LL, -28800 }, /* 1961-09-24T09:00:00Z */
+ { -242233200LL, -25200 }, /* 1962-04-29T09:00:00Z */
+ { -226508400LL, -28800 }, /* 1962-10-28T09:00:00Z */
+ { -210783600LL, -25200 }, /* 1963-04-28T09:00:00Z */
+ { -195058800LL, -28800 }, /* 1963-10-27T09:00:00Z */
+ { -179334000LL, -25200 }, /* 1964-04-26T09:00:00Z */
+ { -163609200LL, -28800 }, /* 1964-10-25T09:00:00Z */
+ { -147884400LL, -25200 }, /* 1965-04-25T09:00:00Z */
+ { -131554800LL, -28800 }, /* 1965-10-31T09:00:00Z */
+ { -116434800LL, -25200 }, /* 1966-04-24T09:00:00Z */
+ { -100105200LL, -28800 }, /* 1966-10-30T09:00:00Z */
+ { -84376800LL, -25200 }, /* 1967-04-30T10:00:00Z */
+ { -68655600LL, -28800 }, /* 1967-10-29T09:00:00Z */
+ { -52927200LL, -25200 }, /* 1968-04-28T10:00:00Z */
+ { -37206000LL, -28800 }, /* 1968-10-27T09:00:00Z */
+ { -21477600LL, -25200 }, /* 1969-04-27T10:00:00Z */
+ { -5756400LL, -28800 }, /* 1969-10-26T09:00:00Z */
+ { 9972000LL, -25200 }, /* 1970-04-26T10:00:00Z */
+ { 25693200LL, -28800 }, /* 1970-10-25T09:00:00Z */
+ { 41421600LL, -25200 }, /* 1971-04-25T10:00:00Z */
+ { 57747600LL, -28800 }, /* 1971-10-31T09:00:00Z */
+ { 73476000LL, -25200 }, /* 1972-04-30T10:00:00Z */
+ { 89197200LL, -28800 }, /* 1972-10-29T09:00:00Z */
+ { 104925600LL, -25200 }, /* 1973-04-29T10:00:00Z */
+ { 120646800LL, -28800 }, /* 1973-10-28T09:00:00Z */
+ { 126698400LL, -25200 }, /* 1974-01-06T10:00:00Z */
+ { 152096400LL, -28800 }, /* 1974-10-27T09:00:00Z */
+ { 162381600LL, -25200 }, /* 1975-02-23T10:00:00Z */
+ { 183546000LL, -28800 }, /* 1975-10-26T09:00:00Z */
+ { 199274400LL, -25200 }, /* 1976-04-25T10:00:00Z */
+ { 215600400LL, -28800 }, /* 1976-10-31T09:00:00Z */
+ { 230724000LL, -25200 }, /* 1977-04-24T10:00:00Z */
+ { 247050000LL, -28800 }, /* 1977-10-30T09:00:00Z */
+ { 262778400LL, -25200 }, /* 1978-04-30T10:00:00Z */
+ { 278499600LL, -28800 }, /* 1978-10-29T09:00:00Z */
+ { 294228000LL, -25200 }, /* 1979-04-29T10:00:00Z */
+ { 309949200LL, -28800 }, /* 1979-10-28T09:00:00Z */
+ { 325677600LL, -25200 }, /* 1980-04-27T10:00:00Z */
+ { 341398800LL, -28800 }, /* 1980-10-26T09:00:00Z */
+ { 357127200LL, -25200 }, /* 1981-04-26T10:00:00Z */
+ { 372848400LL, -28800 }, /* 1981-10-25T09:00:00Z */
+ { 388576800LL, -25200 }, /* 1982-04-25T10:00:00Z */
+ { 404902800LL, -28800 }, /* 1982-10-31T09:00:00Z */
+ { 420026400LL, -25200 }, /* 1983-04-24T10:00:00Z */
+ { 436352400LL, -28800 }, /* 1983-10-30T09:00:00Z */
+ { 452080800LL, -25200 }, /* 1984-04-29T10:00:00Z */
+ { 467802000LL, -28800 }, /* 1984-10-28T09:00:00Z */
+ { 483530400LL, -25200 }, /* 1985-04-28T10:00:00Z */
+ { 499251600LL, -28800 }, /* 1985-10-27T09:00:00Z */
+ { 514980000LL, -25200 }, /* 1986-04-27T10:00:00Z */
+ { 530701200LL, -28800 }, /* 1986-10-26T09:00:00Z */
+ { 544615200LL, -25200 }, /* 1987-04-05T10:00:00Z */
+ { 562150800LL, -28800 }, /* 1987-10-25T09:00:00Z */
+ { 576064800LL, -25200 }, /* 1988-04-03T10:00:00Z */
+ { 594205200LL, -28800 }, /* 1988-10-30T09:00:00Z */
+ { 607514400LL, -25200 }, /* 1989-04-02T10:00:00Z */
+ { 625654800LL, -28800 }, /* 1989-10-29T09:00:00Z */
+ { 638964000LL, -25200 }, /* 1990-04-01T10:00:00Z */
+ { 657104400LL, -28800 }, /* 1990-10-28T09:00:00Z */
+ { 671018400LL, -25200 }, /* 1991-04-07T10:00:00Z */
+ { 688554000LL, -28800 }, /* 1991-10-27T09:00:00Z */
+ { 702468000LL, -25200 }, /* 1992-04-05T10:00:00Z */
+ { 720003600LL, -28800 }, /* 1992-10-25T09:00:00Z */
+ { 733917600LL, -25200 }, /* 1993-04-04T10:00:00Z */
+ { 752058000LL, -28800 }, /* 1993-10-31T09:00:00Z */
+ { 765367200LL, -25200 }, /* 1994-04-03T10:00:00Z */
+ { 783507600LL, -28800 }, /* 1994-10-30T09:00:00Z */
+ { 796816800LL, -25200 }, /* 1995-04-02T10:00:00Z */
+ { 814957200LL, -28800 }, /* 1995-10-29T09:00:00Z */
+ { 828871200LL, -25200 }, /* 1996-04-07T10:00:00Z */
+ { 846406800LL, -28800 }, /* 1996-10-27T09:00:00Z */
+ { 860320800LL, -25200 }, /* 1997-04-06T10:00:00Z */
+ { 877856400LL, -28800 }, /* 1997-10-26T09:00:00Z */
+ { 891770400LL, -25200 }, /* 1998-04-05T10:00:00Z */
+ { 909306000LL, -28800 }, /* 1998-10-25T09:00:00Z */
+ { 923220000LL, -25200 }, /* 1999-04-04T10:00:00Z */
+ { 941360400LL, -28800 }, /* 1999-10-31T09:00:00Z */
+ { 954669600LL, -25200 }, /* 2000-04-02T10:00:00Z */
+ { 972810000LL, -28800 }, /* 2000-10-29T09:00:00Z */
+ { 986119200LL, -25200 }, /* 2001-04-01T10:00:00Z */
+ { 1004259600LL, -28800 }, /* 2001-10-28T09:00:00Z */
+ { 1018173600LL, -25200 }, /* 2002-04-07T10:00:00Z */
+ { 1035709200LL, -28800 }, /* 2002-10-27T09:00:00Z */
+ { 1049623200LL, -25200 }, /* 2003-04-06T10:00:00Z */
+ { 1067158800LL, -28800 }, /* 2003-10-26T09:00:00Z */
+ { 1081072800LL, -25200 }, /* 2004-04-04T10:00:00Z */
+ { 1099213200LL, -28800 }, /* 2004-10-31T09:00:00Z */
+ { 1112522400LL, -25200 }, /* 2005-04-03T10:00:00Z */
+ { 1130662800LL, -28800 }, /* 2005-10-30T09:00:00Z */
+ { 1143972000LL, -25200 }, /* 2006-04-02T10:00:00Z */
+ { 1162112400LL, -28800 }, /* 2006-10-29T09:00:00Z */
+ { 1173607200LL, -25200 }, /* 2007-03-11T10:00:00Z */
+ { 1194166800LL, -28800 }, /* 2007-11-04T09:00:00Z */
+ { 1205056800LL, -25200 }, /* 2008-03-09T10:00:00Z */
+ { 1225616400LL, -28800 }, /* 2008-11-02T09:00:00Z */
+ { 1236506400LL, -25200 }, /* 2009-03-08T10:00:00Z */
+ { 1257066000LL, -28800 }, /* 2009-11-01T09:00:00Z */
+ { 1268560800LL, -25200 }, /* 2010-03-14T10:00:00Z */
+ { 1289120400LL, -28800 }, /* 2010-11-07T09:00:00Z */
+ { 1300010400LL, -25200 }, /* 2011-03-13T10:00:00Z */
+ { 1320570000LL, -28800 }, /* 2011-11-06T09:00:00Z */
+ { 1331460000LL, -25200 }, /* 2012-03-11T10:00:00Z */
+ { 1352019600LL, -28800 }, /* 2012-11-04T09:00:00Z */
+ { 1362909600LL, -25200 }, /* 2013-03-10T10:00:00Z */
+ { 1383469200LL, -28800 }, /* 2013-11-03T09:00:00Z */
+ { 1394359200LL, -25200 }, /* 2014-03-09T10:00:00Z */
+ { 1414918800LL, -28800 }, /* 2014-11-02T09:00:00Z */
+ { 1425808800LL, -25200 }, /* 2015-03-08T10:00:00Z */
+ { 1446368400LL, -28800 }, /* 2015-11-01T09:00:00Z */
+ { 1457863200LL, -25200 }, /* 2016-03-13T10:00:00Z */
+ { 1478422800LL, -28800 }, /* 2016-11-06T09:00:00Z */
+ { 1489312800LL, -25200 }, /* 2017-03-12T10:00:00Z */
+ { 1509872400LL, -28800 }, /* 2017-11-05T09:00:00Z */
+ { 1520762400LL, -25200 }, /* 2018-03-11T10:00:00Z */
+ { 1541322000LL, -28800 }, /* 2018-11-04T09:00:00Z */
+ { 1552212000LL, -25200 }, /* 2019-03-10T10:00:00Z */
+ { 1572771600LL, -28800 }, /* 2019-11-03T09:00:00Z */
+ { 1583661600LL, -25200 }, /* 2020-03-08T10:00:00Z */
+ { 1604221200LL, -28800 }, /* 2020-11-01T09:00:00Z */
+ { 1615716000LL, -25200 }, /* 2021-03-14T10:00:00Z */
+ { 1636275600LL, -28800 }, /* 2021-11-07T09:00:00Z */
+ { 1647165600LL, -25200 }, /* 2022-03-13T10:00:00Z */
+ { 1667725200LL, -28800 }, /* 2022-11-06T09:00:00Z */
+ { 1678615200LL, -25200 }, /* 2023-03-12T10:00:00Z */
+ { 1699174800LL, -28800 }, /* 2023-11-05T09:00:00Z */
+ { 1710064800LL, -25200 }, /* 2024-03-10T10:00:00Z */
+ { 1730624400LL, -28800 }, /* 2024-11-03T09:00:00Z */
+ { 1741514400LL, -25200 }, /* 2025-03-09T10:00:00Z */
+ { 1762074000LL, -28800 }, /* 2025-11-02T09:00:00Z */
+ { 1772964000LL, -25200 }, /* 2026-03-08T10:00:00Z */
+ { 1793523600LL, -28800 }, /* 2026-11-01T09:00:00Z */
+ { 1805018400LL, -25200 }, /* 2027-03-14T10:00:00Z */
+ { 1825578000LL, -28800 }, /* 2027-11-07T09:00:00Z */
+ { 1836468000LL, -25200 }, /* 2028-03-12T10:00:00Z */
+ { 1857027600LL, -28800 }, /* 2028-11-05T09:00:00Z */
+ { 1867917600LL, -25200 }, /* 2029-03-11T10:00:00Z */
+ { 1888477200LL, -28800 }, /* 2029-11-04T09:00:00Z */
+ { 1899367200LL, -25200 }, /* 2030-03-10T10:00:00Z */
+ { 1919926800LL, -28800 }, /* 2030-11-03T09:00:00Z */
+ { 1930816800LL, -25200 }, /* 2031-03-09T10:00:00Z */
+ { 1951376400LL, -28800 }, /* 2031-11-02T09:00:00Z */
+ { 1962871200LL, -25200 }, /* 2032-03-14T10:00:00Z */
+ { 1983430800LL, -28800 }, /* 2032-11-07T09:00:00Z */
+ { 1994320800LL, -25200 }, /* 2033-03-13T10:00:00Z */
+ { 2014880400LL, -28800 }, /* 2033-11-06T09:00:00Z */
+ { 2025770400LL, -25200 }, /* 2034-03-12T10:00:00Z */
+ { 2046330000LL, -28800 }, /* 2034-11-05T09:00:00Z */
+ { 2057220000LL, -25200 }, /* 2035-03-11T10:00:00Z */
+ { 2077779600LL, -28800 }, /* 2035-11-04T09:00:00Z */
+ { 2088669600LL, -25200 }, /* 2036-03-09T10:00:00Z */
+ { 2109229200LL, -28800 }, /* 2036-11-02T09:00:00Z */
+ { 2120119200LL, -25200 }, /* 2037-03-08T10:00:00Z */
+ { 2140678800LL, -28800 }, /* 2037-11-01T09:00:00Z */
+};
+
+static const TZTransition tz_trans_America_Maceio[] = {
+ { INT64_MIN, -8572 }, /* before first transition */
+ { -1767217028LL, -10800 }, /* 1914-01-01T02:22:52Z */
+ { -1206957600LL, -7200 }, /* 1931-10-03T14:00:00Z */
+ { -1191362400LL, -10800 }, /* 1932-04-01T02:00:00Z */
+ { -1175374800LL, -7200 }, /* 1932-10-03T03:00:00Z */
+ { -1159826400LL, -10800 }, /* 1933-04-01T02:00:00Z */
+ { -633819600LL, -7200 }, /* 1949-12-01T03:00:00Z */
+ { -622069200LL, -10800 }, /* 1950-04-16T03:00:00Z */
+ { -602283600LL, -7200 }, /* 1950-12-01T03:00:00Z */
+ { -591832800LL, -10800 }, /* 1951-04-01T02:00:00Z */
+ { -570747600LL, -7200 }, /* 1951-12-01T03:00:00Z */
+ { -560210400LL, -10800 }, /* 1952-04-01T02:00:00Z */
+ { -539125200LL, -7200 }, /* 1952-12-01T03:00:00Z */
+ { -531352800LL, -10800 }, /* 1953-03-01T02:00:00Z */
+ { -191365200LL, -7200 }, /* 1963-12-09T03:00:00Z */
+ { -184197600LL, -10800 }, /* 1964-03-01T02:00:00Z */
+ { -155163600LL, -7200 }, /* 1965-01-31T03:00:00Z */
+ { -150069600LL, -10800 }, /* 1965-03-31T02:00:00Z */
+ { -128898000LL, -7200 }, /* 1965-12-01T03:00:00Z */
+ { -121125600LL, -10800 }, /* 1966-03-01T02:00:00Z */
+ { -99954000LL, -7200 }, /* 1966-11-01T03:00:00Z */
+ { -89589600LL, -10800 }, /* 1967-03-01T02:00:00Z */
+ { -68418000LL, -7200 }, /* 1967-11-01T03:00:00Z */
+ { -57967200LL, -10800 }, /* 1968-03-01T02:00:00Z */
+ { 499748400LL, -7200 }, /* 1985-11-02T03:00:00Z */
+ { 511236000LL, -10800 }, /* 1986-03-15T02:00:00Z */
+ { 530593200LL, -7200 }, /* 1986-10-25T03:00:00Z */
+ { 540266400LL, -10800 }, /* 1987-02-14T02:00:00Z */
+ { 562129200LL, -7200 }, /* 1987-10-25T03:00:00Z */
+ { 571197600LL, -10800 }, /* 1988-02-07T02:00:00Z */
+ { 592974000LL, -7200 }, /* 1988-10-16T03:00:00Z */
+ { 602042400LL, -10800 }, /* 1989-01-29T02:00:00Z */
+ { 624423600LL, -7200 }, /* 1989-10-15T03:00:00Z */
+ { 634701600LL, -10800 }, /* 1990-02-11T02:00:00Z */
+ { 813726000LL, -7200 }, /* 1995-10-15T03:00:00Z */
+ { 824004000LL, -10800 }, /* 1996-02-11T02:00:00Z */
+ { 938919600LL, -7200 }, /* 1999-10-03T03:00:00Z */
+ { 951616800LL, -10800 }, /* 2000-02-27T02:00:00Z */
+ { 970974000LL, -7200 }, /* 2000-10-08T03:00:00Z */
+ { 972180000LL, -10800 }, /* 2000-10-22T02:00:00Z */
+ { 1003028400LL, -7200 }, /* 2001-10-14T03:00:00Z */
+ { 1013911200LL, -10800 }, /* 2002-02-17T02:00:00Z */
+};
+
+static const TZTransition tz_trans_America_New_York[] = {
+ { INT64_MIN, -17762 }, /* before first transition */
+ { -2717650800LL, -18000 }, /* 1883-11-18T17:00:00Z */
+ { -1633280400LL, -14400 }, /* 1918-03-31T07:00:00Z */
+ { -1615140000LL, -18000 }, /* 1918-10-27T06:00:00Z */
+ { -1601830800LL, -14400 }, /* 1919-03-30T07:00:00Z */
+ { -1583690400LL, -18000 }, /* 1919-10-26T06:00:00Z */
+ { -1570381200LL, -14400 }, /* 1920-03-28T07:00:00Z */
+ { -1551636000LL, -18000 }, /* 1920-10-31T06:00:00Z */
+ { -1536512400LL, -14400 }, /* 1921-04-24T07:00:00Z */
+ { -1523210400LL, -18000 }, /* 1921-09-25T06:00:00Z */
+ { -1504458000LL, -14400 }, /* 1922-04-30T07:00:00Z */
+ { -1491760800LL, -18000 }, /* 1922-09-24T06:00:00Z */
+ { -1473008400LL, -14400 }, /* 1923-04-29T07:00:00Z */
+ { -1459706400LL, -18000 }, /* 1923-09-30T06:00:00Z */
+ { -1441558800LL, -14400 }, /* 1924-04-27T07:00:00Z */
+ { -1428256800LL, -18000 }, /* 1924-09-28T06:00:00Z */
+ { -1410109200LL, -14400 }, /* 1925-04-26T07:00:00Z */
+ { -1396807200LL, -18000 }, /* 1925-09-27T06:00:00Z */
+ { -1378659600LL, -14400 }, /* 1926-04-25T07:00:00Z */
+ { -1365357600LL, -18000 }, /* 1926-09-26T06:00:00Z */
+ { -1347210000LL, -14400 }, /* 1927-04-24T07:00:00Z */
+ { -1333908000LL, -18000 }, /* 1927-09-25T06:00:00Z */
+ { -1315155600LL, -14400 }, /* 1928-04-29T07:00:00Z */
+ { -1301853600LL, -18000 }, /* 1928-09-30T06:00:00Z */
+ { -1283706000LL, -14400 }, /* 1929-04-28T07:00:00Z */
+ { -1270404000LL, -18000 }, /* 1929-09-29T06:00:00Z */
+ { -1252256400LL, -14400 }, /* 1930-04-27T07:00:00Z */
+ { -1238954400LL, -18000 }, /* 1930-09-28T06:00:00Z */
+ { -1220806800LL, -14400 }, /* 1931-04-26T07:00:00Z */
+ { -1207504800LL, -18000 }, /* 1931-09-27T06:00:00Z */
+ { -1189357200LL, -14400 }, /* 1932-04-24T07:00:00Z */
+ { -1176055200LL, -18000 }, /* 1932-09-25T06:00:00Z */
+ { -1157302800LL, -14400 }, /* 1933-04-30T07:00:00Z */
+ { -1144605600LL, -18000 }, /* 1933-09-24T06:00:00Z */
+ { -1125853200LL, -14400 }, /* 1934-04-29T07:00:00Z */
+ { -1112551200LL, -18000 }, /* 1934-09-30T06:00:00Z */
+ { -1094403600LL, -14400 }, /* 1935-04-28T07:00:00Z */
+ { -1081101600LL, -18000 }, /* 1935-09-29T06:00:00Z */
+ { -1062954000LL, -14400 }, /* 1936-04-26T07:00:00Z */
+ { -1049652000LL, -18000 }, /* 1936-09-27T06:00:00Z */
+ { -1031504400LL, -14400 }, /* 1937-04-25T07:00:00Z */
+ { -1018202400LL, -18000 }, /* 1937-09-26T06:00:00Z */
+ { -1000054800LL, -14400 }, /* 1938-04-24T07:00:00Z */
+ { -986752800LL, -18000 }, /* 1938-09-25T06:00:00Z */
+ { -968000400LL, -14400 }, /* 1939-04-30T07:00:00Z */
+ { -955303200LL, -18000 }, /* 1939-09-24T06:00:00Z */
+ { -936550800LL, -14400 }, /* 1940-04-28T07:00:00Z */
+ { -923248800LL, -18000 }, /* 1940-09-29T06:00:00Z */
+ { -905101200LL, -14400 }, /* 1941-04-27T07:00:00Z */
+ { -891799200LL, -18000 }, /* 1941-09-28T06:00:00Z */
+ { -880218000LL, -14400 }, /* 1942-02-09T07:00:00Z */
+ { -769395600LL, -14400 }, /* 1945-08-14T23:00:00Z */
+ { -765396000LL, -18000 }, /* 1945-09-30T06:00:00Z */
+ { -747248400LL, -14400 }, /* 1946-04-28T07:00:00Z */
+ { -733946400LL, -18000 }, /* 1946-09-29T06:00:00Z */
+ { -715798800LL, -14400 }, /* 1947-04-27T07:00:00Z */
+ { -702496800LL, -18000 }, /* 1947-09-28T06:00:00Z */
+ { -684349200LL, -14400 }, /* 1948-04-25T07:00:00Z */
+ { -671047200LL, -18000 }, /* 1948-09-26T06:00:00Z */
+ { -652899600LL, -14400 }, /* 1949-04-24T07:00:00Z */
+ { -639597600LL, -18000 }, /* 1949-09-25T06:00:00Z */
+ { -620845200LL, -14400 }, /* 1950-04-30T07:00:00Z */
+ { -608148000LL, -18000 }, /* 1950-09-24T06:00:00Z */
+ { -589395600LL, -14400 }, /* 1951-04-29T07:00:00Z */
+ { -576093600LL, -18000 }, /* 1951-09-30T06:00:00Z */
+ { -557946000LL, -14400 }, /* 1952-04-27T07:00:00Z */
+ { -544644000LL, -18000 }, /* 1952-09-28T06:00:00Z */
+ { -526496400LL, -14400 }, /* 1953-04-26T07:00:00Z */
+ { -513194400LL, -18000 }, /* 1953-09-27T06:00:00Z */
+ { -495046800LL, -14400 }, /* 1954-04-25T07:00:00Z */
+ { -481744800LL, -18000 }, /* 1954-09-26T06:00:00Z */
+ { -463597200LL, -14400 }, /* 1955-04-24T07:00:00Z */
+ { -447271200LL, -18000 }, /* 1955-10-30T06:00:00Z */
+ { -431542800LL, -14400 }, /* 1956-04-29T07:00:00Z */
+ { -415821600LL, -18000 }, /* 1956-10-28T06:00:00Z */
+ { -400093200LL, -14400 }, /* 1957-04-28T07:00:00Z */
+ { -384372000LL, -18000 }, /* 1957-10-27T06:00:00Z */
+ { -368643600LL, -14400 }, /* 1958-04-27T07:00:00Z */
+ { -352922400LL, -18000 }, /* 1958-10-26T06:00:00Z */
+ { -337194000LL, -14400 }, /* 1959-04-26T07:00:00Z */
+ { -321472800LL, -18000 }, /* 1959-10-25T06:00:00Z */
+ { -305744400LL, -14400 }, /* 1960-04-24T07:00:00Z */
+ { -289418400LL, -18000 }, /* 1960-10-30T06:00:00Z */
+ { -273690000LL, -14400 }, /* 1961-04-30T07:00:00Z */
+ { -257968800LL, -18000 }, /* 1961-10-29T06:00:00Z */
+ { -242240400LL, -14400 }, /* 1962-04-29T07:00:00Z */
+ { -226519200LL, -18000 }, /* 1962-10-28T06:00:00Z */
+ { -210790800LL, -14400 }, /* 1963-04-28T07:00:00Z */
+ { -195069600LL, -18000 }, /* 1963-10-27T06:00:00Z */
+ { -179341200LL, -14400 }, /* 1964-04-26T07:00:00Z */
+ { -163620000LL, -18000 }, /* 1964-10-25T06:00:00Z */
+ { -147891600LL, -14400 }, /* 1965-04-25T07:00:00Z */
+ { -131565600LL, -18000 }, /* 1965-10-31T06:00:00Z */
+ { -116442000LL, -14400 }, /* 1966-04-24T07:00:00Z */
+ { -100116000LL, -18000 }, /* 1966-10-30T06:00:00Z */
+ { -84387600LL, -14400 }, /* 1967-04-30T07:00:00Z */
+ { -68666400LL, -18000 }, /* 1967-10-29T06:00:00Z */
+ { -52938000LL, -14400 }, /* 1968-04-28T07:00:00Z */
+ { -37216800LL, -18000 }, /* 1968-10-27T06:00:00Z */
+ { -21488400LL, -14400 }, /* 1969-04-27T07:00:00Z */
+ { -5767200LL, -18000 }, /* 1969-10-26T06:00:00Z */
+ { 9961200LL, -14400 }, /* 1970-04-26T07:00:00Z */
+ { 25682400LL, -18000 }, /* 1970-10-25T06:00:00Z */
+ { 41410800LL, -14400 }, /* 1971-04-25T07:00:00Z */
+ { 57736800LL, -18000 }, /* 1971-10-31T06:00:00Z */
+ { 73465200LL, -14400 }, /* 1972-04-30T07:00:00Z */
+ { 89186400LL, -18000 }, /* 1972-10-29T06:00:00Z */
+ { 104914800LL, -14400 }, /* 1973-04-29T07:00:00Z */
+ { 120636000LL, -18000 }, /* 1973-10-28T06:00:00Z */
+ { 126687600LL, -14400 }, /* 1974-01-06T07:00:00Z */
+ { 152085600LL, -18000 }, /* 1974-10-27T06:00:00Z */
+ { 162370800LL, -14400 }, /* 1975-02-23T07:00:00Z */
+ { 183535200LL, -18000 }, /* 1975-10-26T06:00:00Z */
+ { 199263600LL, -14400 }, /* 1976-04-25T07:00:00Z */
+ { 215589600LL, -18000 }, /* 1976-10-31T06:00:00Z */
+ { 230713200LL, -14400 }, /* 1977-04-24T07:00:00Z */
+ { 247039200LL, -18000 }, /* 1977-10-30T06:00:00Z */
+ { 262767600LL, -14400 }, /* 1978-04-30T07:00:00Z */
+ { 278488800LL, -18000 }, /* 1978-10-29T06:00:00Z */
+ { 294217200LL, -14400 }, /* 1979-04-29T07:00:00Z */
+ { 309938400LL, -18000 }, /* 1979-10-28T06:00:00Z */
+ { 325666800LL, -14400 }, /* 1980-04-27T07:00:00Z */
+ { 341388000LL, -18000 }, /* 1980-10-26T06:00:00Z */
+ { 357116400LL, -14400 }, /* 1981-04-26T07:00:00Z */
+ { 372837600LL, -18000 }, /* 1981-10-25T06:00:00Z */
+ { 388566000LL, -14400 }, /* 1982-04-25T07:00:00Z */
+ { 404892000LL, -18000 }, /* 1982-10-31T06:00:00Z */
+ { 420015600LL, -14400 }, /* 1983-04-24T07:00:00Z */
+ { 436341600LL, -18000 }, /* 1983-10-30T06:00:00Z */
+ { 452070000LL, -14400 }, /* 1984-04-29T07:00:00Z */
+ { 467791200LL, -18000 }, /* 1984-10-28T06:00:00Z */
+ { 483519600LL, -14400 }, /* 1985-04-28T07:00:00Z */
+ { 499240800LL, -18000 }, /* 1985-10-27T06:00:00Z */
+ { 514969200LL, -14400 }, /* 1986-04-27T07:00:00Z */
+ { 530690400LL, -18000 }, /* 1986-10-26T06:00:00Z */
+ { 544604400LL, -14400 }, /* 1987-04-05T07:00:00Z */
+ { 562140000LL, -18000 }, /* 1987-10-25T06:00:00Z */
+ { 576054000LL, -14400 }, /* 1988-04-03T07:00:00Z */
+ { 594194400LL, -18000 }, /* 1988-10-30T06:00:00Z */
+ { 607503600LL, -14400 }, /* 1989-04-02T07:00:00Z */
+ { 625644000LL, -18000 }, /* 1989-10-29T06:00:00Z */
+ { 638953200LL, -14400 }, /* 1990-04-01T07:00:00Z */
+ { 657093600LL, -18000 }, /* 1990-10-28T06:00:00Z */
+ { 671007600LL, -14400 }, /* 1991-04-07T07:00:00Z */
+ { 688543200LL, -18000 }, /* 1991-10-27T06:00:00Z */
+ { 702457200LL, -14400 }, /* 1992-04-05T07:00:00Z */
+ { 719992800LL, -18000 }, /* 1992-10-25T06:00:00Z */
+ { 733906800LL, -14400 }, /* 1993-04-04T07:00:00Z */
+ { 752047200LL, -18000 }, /* 1993-10-31T06:00:00Z */
+ { 765356400LL, -14400 }, /* 1994-04-03T07:00:00Z */
+ { 783496800LL, -18000 }, /* 1994-10-30T06:00:00Z */
+ { 796806000LL, -14400 }, /* 1995-04-02T07:00:00Z */
+ { 814946400LL, -18000 }, /* 1995-10-29T06:00:00Z */
+ { 828860400LL, -14400 }, /* 1996-04-07T07:00:00Z */
+ { 846396000LL, -18000 }, /* 1996-10-27T06:00:00Z */
+ { 860310000LL, -14400 }, /* 1997-04-06T07:00:00Z */
+ { 877845600LL, -18000 }, /* 1997-10-26T06:00:00Z */
+ { 891759600LL, -14400 }, /* 1998-04-05T07:00:00Z */
+ { 909295200LL, -18000 }, /* 1998-10-25T06:00:00Z */
+ { 923209200LL, -14400 }, /* 1999-04-04T07:00:00Z */
+ { 941349600LL, -18000 }, /* 1999-10-31T06:00:00Z */
+ { 954658800LL, -14400 }, /* 2000-04-02T07:00:00Z */
+ { 972799200LL, -18000 }, /* 2000-10-29T06:00:00Z */
+ { 986108400LL, -14400 }, /* 2001-04-01T07:00:00Z */
+ { 1004248800LL, -18000 }, /* 2001-10-28T06:00:00Z */
+ { 1018162800LL, -14400 }, /* 2002-04-07T07:00:00Z */
+ { 1035698400LL, -18000 }, /* 2002-10-27T06:00:00Z */
+ { 1049612400LL, -14400 }, /* 2003-04-06T07:00:00Z */
+ { 1067148000LL, -18000 }, /* 2003-10-26T06:00:00Z */
+ { 1081062000LL, -14400 }, /* 2004-04-04T07:00:00Z */
+ { 1099202400LL, -18000 }, /* 2004-10-31T06:00:00Z */
+ { 1112511600LL, -14400 }, /* 2005-04-03T07:00:00Z */
+ { 1130652000LL, -18000 }, /* 2005-10-30T06:00:00Z */
+ { 1143961200LL, -14400 }, /* 2006-04-02T07:00:00Z */
+ { 1162101600LL, -18000 }, /* 2006-10-29T06:00:00Z */
+ { 1173596400LL, -14400 }, /* 2007-03-11T07:00:00Z */
+ { 1194156000LL, -18000 }, /* 2007-11-04T06:00:00Z */
+ { 1205046000LL, -14400 }, /* 2008-03-09T07:00:00Z */
+ { 1225605600LL, -18000 }, /* 2008-11-02T06:00:00Z */
+ { 1236495600LL, -14400 }, /* 2009-03-08T07:00:00Z */
+ { 1257055200LL, -18000 }, /* 2009-11-01T06:00:00Z */
+ { 1268550000LL, -14400 }, /* 2010-03-14T07:00:00Z */
+ { 1289109600LL, -18000 }, /* 2010-11-07T06:00:00Z */
+ { 1299999600LL, -14400 }, /* 2011-03-13T07:00:00Z */
+ { 1320559200LL, -18000 }, /* 2011-11-06T06:00:00Z */
+ { 1331449200LL, -14400 }, /* 2012-03-11T07:00:00Z */
+ { 1352008800LL, -18000 }, /* 2012-11-04T06:00:00Z */
+ { 1362898800LL, -14400 }, /* 2013-03-10T07:00:00Z */
+ { 1383458400LL, -18000 }, /* 2013-11-03T06:00:00Z */
+ { 1394348400LL, -14400 }, /* 2014-03-09T07:00:00Z */
+ { 1414908000LL, -18000 }, /* 2014-11-02T06:00:00Z */
+ { 1425798000LL, -14400 }, /* 2015-03-08T07:00:00Z */
+ { 1446357600LL, -18000 }, /* 2015-11-01T06:00:00Z */
+ { 1457852400LL, -14400 }, /* 2016-03-13T07:00:00Z */
+ { 1478412000LL, -18000 }, /* 2016-11-06T06:00:00Z */
+ { 1489302000LL, -14400 }, /* 2017-03-12T07:00:00Z */
+ { 1509861600LL, -18000 }, /* 2017-11-05T06:00:00Z */
+ { 1520751600LL, -14400 }, /* 2018-03-11T07:00:00Z */
+ { 1541311200LL, -18000 }, /* 2018-11-04T06:00:00Z */
+ { 1552201200LL, -14400 }, /* 2019-03-10T07:00:00Z */
+ { 1572760800LL, -18000 }, /* 2019-11-03T06:00:00Z */
+ { 1583650800LL, -14400 }, /* 2020-03-08T07:00:00Z */
+ { 1604210400LL, -18000 }, /* 2020-11-01T06:00:00Z */
+ { 1615705200LL, -14400 }, /* 2021-03-14T07:00:00Z */
+ { 1636264800LL, -18000 }, /* 2021-11-07T06:00:00Z */
+ { 1647154800LL, -14400 }, /* 2022-03-13T07:00:00Z */
+ { 1667714400LL, -18000 }, /* 2022-11-06T06:00:00Z */
+ { 1678604400LL, -14400 }, /* 2023-03-12T07:00:00Z */
+ { 1699164000LL, -18000 }, /* 2023-11-05T06:00:00Z */
+ { 1710054000LL, -14400 }, /* 2024-03-10T07:00:00Z */
+ { 1730613600LL, -18000 }, /* 2024-11-03T06:00:00Z */
+ { 1741503600LL, -14400 }, /* 2025-03-09T07:00:00Z */
+ { 1762063200LL, -18000 }, /* 2025-11-02T06:00:00Z */
+ { 1772953200LL, -14400 }, /* 2026-03-08T07:00:00Z */
+ { 1793512800LL, -18000 }, /* 2026-11-01T06:00:00Z */
+ { 1805007600LL, -14400 }, /* 2027-03-14T07:00:00Z */
+ { 1825567200LL, -18000 }, /* 2027-11-07T06:00:00Z */
+ { 1836457200LL, -14400 }, /* 2028-03-12T07:00:00Z */
+ { 1857016800LL, -18000 }, /* 2028-11-05T06:00:00Z */
+ { 1867906800LL, -14400 }, /* 2029-03-11T07:00:00Z */
+ { 1888466400LL, -18000 }, /* 2029-11-04T06:00:00Z */
+ { 1899356400LL, -14400 }, /* 2030-03-10T07:00:00Z */
+ { 1919916000LL, -18000 }, /* 2030-11-03T06:00:00Z */
+ { 1930806000LL, -14400 }, /* 2031-03-09T07:00:00Z */
+ { 1951365600LL, -18000 }, /* 2031-11-02T06:00:00Z */
+ { 1962860400LL, -14400 }, /* 2032-03-14T07:00:00Z */
+ { 1983420000LL, -18000 }, /* 2032-11-07T06:00:00Z */
+ { 1994310000LL, -14400 }, /* 2033-03-13T07:00:00Z */
+ { 2014869600LL, -18000 }, /* 2033-11-06T06:00:00Z */
+ { 2025759600LL, -14400 }, /* 2034-03-12T07:00:00Z */
+ { 2046319200LL, -18000 }, /* 2034-11-05T06:00:00Z */
+ { 2057209200LL, -14400 }, /* 2035-03-11T07:00:00Z */
+ { 2077768800LL, -18000 }, /* 2035-11-04T06:00:00Z */
+ { 2088658800LL, -14400 }, /* 2036-03-09T07:00:00Z */
+ { 2109218400LL, -18000 }, /* 2036-11-02T06:00:00Z */
+ { 2120108400LL, -14400 }, /* 2037-03-08T07:00:00Z */
+ { 2140668000LL, -18000 }, /* 2037-11-01T06:00:00Z */
+};
+
+static const TZTransition tz_trans_America_Noronha[] = {
+ { INT64_MIN, -7780 }, /* before first transition */
+ { -1767217820LL, -7200 }, /* 1914-01-01T02:09:40Z */
+ { -1206961200LL, -3600 }, /* 1931-10-03T13:00:00Z */
+ { -1191366000LL, -7200 }, /* 1932-04-01T01:00:00Z */
+ { -1175378400LL, -3600 }, /* 1932-10-03T02:00:00Z */
+ { -1159830000LL, -7200 }, /* 1933-04-01T01:00:00Z */
+ { -633823200LL, -3600 }, /* 1949-12-01T02:00:00Z */
+ { -622072800LL, -7200 }, /* 1950-04-16T02:00:00Z */
+ { -602287200LL, -3600 }, /* 1950-12-01T02:00:00Z */
+ { -591836400LL, -7200 }, /* 1951-04-01T01:00:00Z */
+ { -570751200LL, -3600 }, /* 1951-12-01T02:00:00Z */
+ { -560214000LL, -7200 }, /* 1952-04-01T01:00:00Z */
+ { -539128800LL, -3600 }, /* 1952-12-01T02:00:00Z */
+ { -531356400LL, -7200 }, /* 1953-03-01T01:00:00Z */
+ { -191368800LL, -3600 }, /* 1963-12-09T02:00:00Z */
+ { -184201200LL, -7200 }, /* 1964-03-01T01:00:00Z */
+ { -155167200LL, -3600 }, /* 1965-01-31T02:00:00Z */
+ { -150073200LL, -7200 }, /* 1965-03-31T01:00:00Z */
+ { -128901600LL, -3600 }, /* 1965-12-01T02:00:00Z */
+ { -121129200LL, -7200 }, /* 1966-03-01T01:00:00Z */
+ { -99957600LL, -3600 }, /* 1966-11-01T02:00:00Z */
+ { -89593200LL, -7200 }, /* 1967-03-01T01:00:00Z */
+ { -68421600LL, -3600 }, /* 1967-11-01T02:00:00Z */
+ { -57970800LL, -7200 }, /* 1968-03-01T01:00:00Z */
+ { 499744800LL, -3600 }, /* 1985-11-02T02:00:00Z */
+ { 511232400LL, -7200 }, /* 1986-03-15T01:00:00Z */
+ { 530589600LL, -3600 }, /* 1986-10-25T02:00:00Z */
+ { 540262800LL, -7200 }, /* 1987-02-14T01:00:00Z */
+ { 562125600LL, -3600 }, /* 1987-10-25T02:00:00Z */
+ { 571194000LL, -7200 }, /* 1988-02-07T01:00:00Z */
+ { 592970400LL, -3600 }, /* 1988-10-16T02:00:00Z */
+ { 602038800LL, -7200 }, /* 1989-01-29T01:00:00Z */
+ { 624420000LL, -3600 }, /* 1989-10-15T02:00:00Z */
+ { 634698000LL, -7200 }, /* 1990-02-11T01:00:00Z */
+ { 938916000LL, -3600 }, /* 1999-10-03T02:00:00Z */
+ { 951613200LL, -7200 }, /* 2000-02-27T01:00:00Z */
+ { 970970400LL, -3600 }, /* 2000-10-08T02:00:00Z */
+ { 971571600LL, -7200 }, /* 2000-10-15T01:00:00Z */
+ { 1003024800LL, -3600 }, /* 2001-10-14T02:00:00Z */
+ { 1013907600LL, -7200 }, /* 2002-02-17T01:00:00Z */
+};
+
+static const TZTransition tz_trans_America_Recife[] = {
+ { INT64_MIN, -8376 }, /* before first transition */
+ { -1767217224LL, -10800 }, /* 1914-01-01T02:19:36Z */
+ { -1206957600LL, -7200 }, /* 1931-10-03T14:00:00Z */
+ { -1191362400LL, -10800 }, /* 1932-04-01T02:00:00Z */
+ { -1175374800LL, -7200 }, /* 1932-10-03T03:00:00Z */
+ { -1159826400LL, -10800 }, /* 1933-04-01T02:00:00Z */
+ { -633819600LL, -7200 }, /* 1949-12-01T03:00:00Z */
+ { -622069200LL, -10800 }, /* 1950-04-16T03:00:00Z */
+ { -602283600LL, -7200 }, /* 1950-12-01T03:00:00Z */
+ { -591832800LL, -10800 }, /* 1951-04-01T02:00:00Z */
+ { -570747600LL, -7200 }, /* 1951-12-01T03:00:00Z */
+ { -560210400LL, -10800 }, /* 1952-04-01T02:00:00Z */
+ { -539125200LL, -7200 }, /* 1952-12-01T03:00:00Z */
+ { -531352800LL, -10800 }, /* 1953-03-01T02:00:00Z */
+ { -191365200LL, -7200 }, /* 1963-12-09T03:00:00Z */
+ { -184197600LL, -10800 }, /* 1964-03-01T02:00:00Z */
+ { -155163600LL, -7200 }, /* 1965-01-31T03:00:00Z */
+ { -150069600LL, -10800 }, /* 1965-03-31T02:00:00Z */
+ { -128898000LL, -7200 }, /* 1965-12-01T03:00:00Z */
+ { -121125600LL, -10800 }, /* 1966-03-01T02:00:00Z */
+ { -99954000LL, -7200 }, /* 1966-11-01T03:00:00Z */
+ { -89589600LL, -10800 }, /* 1967-03-01T02:00:00Z */
+ { -68418000LL, -7200 }, /* 1967-11-01T03:00:00Z */
+ { -57967200LL, -10800 }, /* 1968-03-01T02:00:00Z */
+ { 499748400LL, -7200 }, /* 1985-11-02T03:00:00Z */
+ { 511236000LL, -10800 }, /* 1986-03-15T02:00:00Z */
+ { 530593200LL, -7200 }, /* 1986-10-25T03:00:00Z */
+ { 540266400LL, -10800 }, /* 1987-02-14T02:00:00Z */
+ { 562129200LL, -7200 }, /* 1987-10-25T03:00:00Z */
+ { 571197600LL, -10800 }, /* 1988-02-07T02:00:00Z */
+ { 592974000LL, -7200 }, /* 1988-10-16T03:00:00Z */
+ { 602042400LL, -10800 }, /* 1989-01-29T02:00:00Z */
+ { 624423600LL, -7200 }, /* 1989-10-15T03:00:00Z */
+ { 634701600LL, -10800 }, /* 1990-02-11T02:00:00Z */
+ { 938919600LL, -7200 }, /* 1999-10-03T03:00:00Z */
+ { 951616800LL, -10800 }, /* 2000-02-27T02:00:00Z */
+ { 970974000LL, -7200 }, /* 2000-10-08T03:00:00Z */
+ { 971575200LL, -10800 }, /* 2000-10-15T02:00:00Z */
+ { 1003028400LL, -7200 }, /* 2001-10-14T03:00:00Z */
+ { 1013911200LL, -10800 }, /* 2002-02-17T02:00:00Z */
+};
+
+static const TZTransition tz_trans_America_Sao_Paulo[] = {
+ { INT64_MIN, -11188 }, /* before first transition */
+ { -1767214412LL, -10800 }, /* 1914-01-01T03:06:28Z */
+ { -1206957600LL, -7200 }, /* 1931-10-03T14:00:00Z */
+ { -1191362400LL, -10800 }, /* 1932-04-01T02:00:00Z */
+ { -1175374800LL, -7200 }, /* 1932-10-03T03:00:00Z */
+ { -1159826400LL, -10800 }, /* 1933-04-01T02:00:00Z */
+ { -633819600LL, -7200 }, /* 1949-12-01T03:00:00Z */
+ { -622069200LL, -10800 }, /* 1950-04-16T03:00:00Z */
+ { -602283600LL, -7200 }, /* 1950-12-01T03:00:00Z */
+ { -591832800LL, -10800 }, /* 1951-04-01T02:00:00Z */
+ { -570747600LL, -7200 }, /* 1951-12-01T03:00:00Z */
+ { -560210400LL, -10800 }, /* 1952-04-01T02:00:00Z */
+ { -539125200LL, -7200 }, /* 1952-12-01T03:00:00Z */
+ { -531352800LL, -10800 }, /* 1953-03-01T02:00:00Z */
+ { -195426000LL, -7200 }, /* 1963-10-23T03:00:00Z */
+ { -184197600LL, -10800 }, /* 1964-03-01T02:00:00Z */
+ { -155163600LL, -7200 }, /* 1965-01-31T03:00:00Z */
+ { -150069600LL, -10800 }, /* 1965-03-31T02:00:00Z */
+ { -128898000LL, -7200 }, /* 1965-12-01T03:00:00Z */
+ { -121125600LL, -10800 }, /* 1966-03-01T02:00:00Z */
+ { -99954000LL, -7200 }, /* 1966-11-01T03:00:00Z */
+ { -89589600LL, -10800 }, /* 1967-03-01T02:00:00Z */
+ { -68418000LL, -7200 }, /* 1967-11-01T03:00:00Z */
+ { -57967200LL, -10800 }, /* 1968-03-01T02:00:00Z */
+ { 499748400LL, -7200 }, /* 1985-11-02T03:00:00Z */
+ { 511236000LL, -10800 }, /* 1986-03-15T02:00:00Z */
+ { 530593200LL, -7200 }, /* 1986-10-25T03:00:00Z */
+ { 540266400LL, -10800 }, /* 1987-02-14T02:00:00Z */
+ { 562129200LL, -7200 }, /* 1987-10-25T03:00:00Z */
+ { 571197600LL, -10800 }, /* 1988-02-07T02:00:00Z */
+ { 592974000LL, -7200 }, /* 1988-10-16T03:00:00Z */
+ { 602042400LL, -10800 }, /* 1989-01-29T02:00:00Z */
+ { 624423600LL, -7200 }, /* 1989-10-15T03:00:00Z */
+ { 634701600LL, -10800 }, /* 1990-02-11T02:00:00Z */
+ { 656478000LL, -7200 }, /* 1990-10-21T03:00:00Z */
+ { 666756000LL, -10800 }, /* 1991-02-17T02:00:00Z */
+ { 687927600LL, -7200 }, /* 1991-10-20T03:00:00Z */
+ { 697600800LL, -10800 }, /* 1992-02-09T02:00:00Z */
+ { 719982000LL, -7200 }, /* 1992-10-25T03:00:00Z */
+ { 728445600LL, -10800 }, /* 1993-01-31T02:00:00Z */
+ { 750826800LL, -7200 }, /* 1993-10-17T03:00:00Z */
+ { 761709600LL, -10800 }, /* 1994-02-20T02:00:00Z */
+ { 782276400LL, -7200 }, /* 1994-10-16T03:00:00Z */
+ { 793159200LL, -10800 }, /* 1995-02-19T02:00:00Z */
+ { 813726000LL, -7200 }, /* 1995-10-15T03:00:00Z */
+ { 824004000LL, -10800 }, /* 1996-02-11T02:00:00Z */
+ { 844570800LL, -7200 }, /* 1996-10-06T03:00:00Z */
+ { 856058400LL, -10800 }, /* 1997-02-16T02:00:00Z */
+ { 876106800LL, -7200 }, /* 1997-10-06T03:00:00Z */
+ { 888717600LL, -10800 }, /* 1998-03-01T02:00:00Z */
+ { 908074800LL, -7200 }, /* 1998-10-11T03:00:00Z */
+ { 919562400LL, -10800 }, /* 1999-02-21T02:00:00Z */
+ { 938919600LL, -7200 }, /* 1999-10-03T03:00:00Z */
+ { 951616800LL, -10800 }, /* 2000-02-27T02:00:00Z */
+ { 970974000LL, -7200 }, /* 2000-10-08T03:00:00Z */
+ { 982461600LL, -10800 }, /* 2001-02-18T02:00:00Z */
+ { 1003028400LL, -7200 }, /* 2001-10-14T03:00:00Z */
+ { 1013911200LL, -10800 }, /* 2002-02-17T02:00:00Z */
+ { 1036292400LL, -7200 }, /* 2002-11-03T03:00:00Z */
+ { 1045360800LL, -10800 }, /* 2003-02-16T02:00:00Z */
+ { 1066532400LL, -7200 }, /* 2003-10-19T03:00:00Z */
+ { 1076810400LL, -10800 }, /* 2004-02-15T02:00:00Z */
+ { 1099364400LL, -7200 }, /* 2004-11-02T03:00:00Z */
+ { 1108864800LL, -10800 }, /* 2005-02-20T02:00:00Z */
+ { 1129431600LL, -7200 }, /* 2005-10-16T03:00:00Z */
+ { 1140314400LL, -10800 }, /* 2006-02-19T02:00:00Z */
+ { 1162695600LL, -7200 }, /* 2006-11-05T03:00:00Z */
+ { 1172368800LL, -10800 }, /* 2007-02-25T02:00:00Z */
+ { 1192330800LL, -7200 }, /* 2007-10-14T03:00:00Z */
+ { 1203213600LL, -10800 }, /* 2008-02-17T02:00:00Z */
+ { 1224385200LL, -7200 }, /* 2008-10-19T03:00:00Z */
+ { 1234663200LL, -10800 }, /* 2009-02-15T02:00:00Z */
+ { 1255834800LL, -7200 }, /* 2009-10-18T03:00:00Z */
+ { 1266717600LL, -10800 }, /* 2010-02-21T02:00:00Z */
+ { 1287284400LL, -7200 }, /* 2010-10-17T03:00:00Z */
+ { 1298167200LL, -10800 }, /* 2011-02-20T02:00:00Z */
+ { 1318734000LL, -7200 }, /* 2011-10-16T03:00:00Z */
+ { 1330221600LL, -10800 }, /* 2012-02-26T02:00:00Z */
+ { 1350788400LL, -7200 }, /* 2012-10-21T03:00:00Z */
+ { 1361066400LL, -10800 }, /* 2013-02-17T02:00:00Z */
+ { 1382238000LL, -7200 }, /* 2013-10-20T03:00:00Z */
+ { 1392516000LL, -10800 }, /* 2014-02-16T02:00:00Z */
+ { 1413687600LL, -7200 }, /* 2014-10-19T03:00:00Z */
+ { 1424570400LL, -10800 }, /* 2015-02-22T02:00:00Z */
+ { 1445137200LL, -7200 }, /* 2015-10-18T03:00:00Z */
+ { 1456020000LL, -10800 }, /* 2016-02-21T02:00:00Z */
+ { 1476586800LL, -7200 }, /* 2016-10-16T03:00:00Z */
+ { 1487469600LL, -10800 }, /* 2017-02-19T02:00:00Z */
+ { 1508036400LL, -7200 }, /* 2017-10-15T03:00:00Z */
+ { 1518919200LL, -10800 }, /* 2018-02-18T02:00:00Z */
+ { 1541300400LL, -7200 }, /* 2018-11-04T03:00:00Z */
+ { 1550368800LL, -10800 }, /* 2019-02-17T02:00:00Z */
+};
+
+static const TZTransition tz_trans_America_St_Johns[] = {
+ { INT64_MIN, -12652 }, /* before first transition */
+ { -2713897748LL, -12652 }, /* 1884-01-01T03:30:52Z */
+ { -1664130548LL, -9052 }, /* 1917-04-08T05:30:52Z */
+ { -1650137348LL, -12652 }, /* 1917-09-17T04:30:52Z */
+ { -1632076148LL, -9052 }, /* 1918-04-14T05:30:52Z */
+ { -1615145348LL, -12652 }, /* 1918-10-27T04:30:52Z */
+ { -1598650148LL, -9052 }, /* 1919-05-06T02:30:52Z */
+ { -1590100148LL, -12652 }, /* 1919-08-13T01:30:52Z */
+ { -1567286948LL, -9052 }, /* 1920-05-03T02:30:52Z */
+ { -1551565748LL, -12652 }, /* 1920-11-01T01:30:52Z */
+ { -1535837348LL, -9052 }, /* 1921-05-02T02:30:52Z */
+ { -1520116148LL, -12652 }, /* 1921-10-31T01:30:52Z */
+ { -1503782948LL, -9052 }, /* 1922-05-08T02:30:52Z */
+ { -1488666548LL, -12652 }, /* 1922-10-30T01:30:52Z */
+ { -1472333348LL, -9052 }, /* 1923-05-07T02:30:52Z */
+ { -1457216948LL, -12652 }, /* 1923-10-29T01:30:52Z */
+ { -1440883748LL, -9052 }, /* 1924-05-05T02:30:52Z */
+ { -1425767348LL, -12652 }, /* 1924-10-27T01:30:52Z */
+ { -1409434148LL, -9052 }, /* 1925-05-04T02:30:52Z */
+ { -1394317748LL, -12652 }, /* 1925-10-26T01:30:52Z */
+ { -1377984548LL, -9052 }, /* 1926-05-03T02:30:52Z */
+ { -1362263348LL, -12652 }, /* 1926-11-01T01:30:52Z */
+ { -1346534948LL, -9052 }, /* 1927-05-02T02:30:52Z */
+ { -1330813748LL, -12652 }, /* 1927-10-31T01:30:52Z */
+ { -1314480548LL, -9052 }, /* 1928-05-07T02:30:52Z */
+ { -1299364148LL, -12652 }, /* 1928-10-29T01:30:52Z */
+ { -1283030948LL, -9052 }, /* 1929-05-06T02:30:52Z */
+ { -1267914548LL, -12652 }, /* 1929-10-28T01:30:52Z */
+ { -1251581348LL, -9052 }, /* 1930-05-05T02:30:52Z */
+ { -1236464948LL, -12652 }, /* 1930-10-27T01:30:52Z */
+ { -1220131748LL, -9052 }, /* 1931-05-04T02:30:52Z */
+ { -1205015348LL, -12652 }, /* 1931-10-26T01:30:52Z */
+ { -1188682148LL, -9052 }, /* 1932-05-02T02:30:52Z */
+ { -1172960948LL, -12652 }, /* 1932-10-31T01:30:52Z */
+ { -1156627748LL, -9052 }, /* 1933-05-08T02:30:52Z */
+ { -1141511348LL, -12652 }, /* 1933-10-30T01:30:52Z */
+ { -1125178148LL, -9052 }, /* 1934-05-07T02:30:52Z */
+ { -1110061748LL, -12652 }, /* 1934-10-29T01:30:52Z */
+ { -1096921748LL, -12600 }, /* 1935-03-30T03:30:52Z */
+ { -1093728600LL, -9000 }, /* 1935-05-06T02:30:00Z */
+ { -1078612200LL, -12600 }, /* 1935-10-28T01:30:00Z */
+ { -1061670600LL, -9000 }, /* 1936-05-11T03:30:00Z */
+ { -1048973400LL, -12600 }, /* 1936-10-05T02:30:00Z */
+ { -1030221000LL, -9000 }, /* 1937-05-10T03:30:00Z */
+ { -1017523800LL, -12600 }, /* 1937-10-04T02:30:00Z */
+ { -998771400LL, -9000 }, /* 1938-05-09T03:30:00Z */
+ { -986074200LL, -12600 }, /* 1938-10-03T02:30:00Z */
+ { -966717000LL, -9000 }, /* 1939-05-15T03:30:00Z */
+ { -954624600LL, -12600 }, /* 1939-10-02T02:30:00Z */
+ { -935267400LL, -9000 }, /* 1940-05-13T03:30:00Z */
+ { -922570200LL, -12600 }, /* 1940-10-07T02:30:00Z */
+ { -903817800LL, -9000 }, /* 1941-05-12T03:30:00Z */
+ { -891120600LL, -12600 }, /* 1941-10-06T02:30:00Z */
+ { -872368200LL, -9000 }, /* 1942-05-11T03:30:00Z */
+ { -769395600LL, -9000 }, /* 1945-08-14T23:00:00Z */
+ { -765401400LL, -12600 }, /* 1945-09-30T04:30:00Z */
+ { -746044200LL, -9000 }, /* 1946-05-12T05:30:00Z */
+ { -733347000LL, -12600 }, /* 1946-10-06T04:30:00Z */
+ { -714594600LL, -9000 }, /* 1947-05-11T05:30:00Z */
+ { -701897400LL, -12600 }, /* 1947-10-05T04:30:00Z */
+ { -683145000LL, -9000 }, /* 1948-05-09T05:30:00Z */
+ { -670447800LL, -12600 }, /* 1948-10-03T04:30:00Z */
+ { -651695400LL, -9000 }, /* 1949-05-08T05:30:00Z */
+ { -638998200LL, -12600 }, /* 1949-10-02T04:30:00Z */
+ { -619641000LL, -9000 }, /* 1950-05-14T05:30:00Z */
+ { -606943800LL, -12600 }, /* 1950-10-08T04:30:00Z */
+ { -589401000LL, -9000 }, /* 1951-04-29T05:30:00Z */
+ { -576099000LL, -12600 }, /* 1951-09-30T04:30:00Z */
+ { -557951400LL, -9000 }, /* 1952-04-27T05:30:00Z */
+ { -544649400LL, -12600 }, /* 1952-09-28T04:30:00Z */
+ { -526501800LL, -9000 }, /* 1953-04-26T05:30:00Z */
+ { -513199800LL, -12600 }, /* 1953-09-27T04:30:00Z */
+ { -495052200LL, -9000 }, /* 1954-04-25T05:30:00Z */
+ { -481750200LL, -12600 }, /* 1954-09-26T04:30:00Z */
+ { -463602600LL, -9000 }, /* 1955-04-24T05:30:00Z */
+ { -450300600LL, -12600 }, /* 1955-09-25T04:30:00Z */
+ { -431548200LL, -9000 }, /* 1956-04-29T05:30:00Z */
+ { -418246200LL, -12600 }, /* 1956-09-30T04:30:00Z */
+ { -400098600LL, -9000 }, /* 1957-04-28T05:30:00Z */
+ { -386796600LL, -12600 }, /* 1957-09-29T04:30:00Z */
+ { -368649000LL, -9000 }, /* 1958-04-27T05:30:00Z */
+ { -355347000LL, -12600 }, /* 1958-09-28T04:30:00Z */
+ { -337199400LL, -9000 }, /* 1959-04-26T05:30:00Z */
+ { -323897400LL, -12600 }, /* 1959-09-27T04:30:00Z */
+ { -305749800LL, -9000 }, /* 1960-04-24T05:30:00Z */
+ { -289423800LL, -12600 }, /* 1960-10-30T04:30:00Z */
+ { -273695400LL, -9000 }, /* 1961-04-30T05:30:00Z */
+ { -257974200LL, -12600 }, /* 1961-10-29T04:30:00Z */
+ { -242245800LL, -9000 }, /* 1962-04-29T05:30:00Z */
+ { -226524600LL, -12600 }, /* 1962-10-28T04:30:00Z */
+ { -210796200LL, -9000 }, /* 1963-04-28T05:30:00Z */
+ { -195075000LL, -12600 }, /* 1963-10-27T04:30:00Z */
+ { -179346600LL, -9000 }, /* 1964-04-26T05:30:00Z */
+ { -163625400LL, -12600 }, /* 1964-10-25T04:30:00Z */
+ { -147897000LL, -9000 }, /* 1965-04-25T05:30:00Z */
+ { -131571000LL, -12600 }, /* 1965-10-31T04:30:00Z */
+ { -116447400LL, -9000 }, /* 1966-04-24T05:30:00Z */
+ { -100121400LL, -12600 }, /* 1966-10-30T04:30:00Z */
+ { -84393000LL, -9000 }, /* 1967-04-30T05:30:00Z */
+ { -68671800LL, -12600 }, /* 1967-10-29T04:30:00Z */
+ { -52943400LL, -9000 }, /* 1968-04-28T05:30:00Z */
+ { -37222200LL, -12600 }, /* 1968-10-27T04:30:00Z */
+ { -21493800LL, -9000 }, /* 1969-04-27T05:30:00Z */
+ { -5772600LL, -12600 }, /* 1969-10-26T04:30:00Z */
+ { 9955800LL, -9000 }, /* 1970-04-26T05:30:00Z */
+ { 25677000LL, -12600 }, /* 1970-10-25T04:30:00Z */
+ { 41405400LL, -9000 }, /* 1971-04-25T05:30:00Z */
+ { 57731400LL, -12600 }, /* 1971-10-31T04:30:00Z */
+ { 73459800LL, -9000 }, /* 1972-04-30T05:30:00Z */
+ { 89181000LL, -12600 }, /* 1972-10-29T04:30:00Z */
+ { 104909400LL, -9000 }, /* 1973-04-29T05:30:00Z */
+ { 120630600LL, -12600 }, /* 1973-10-28T04:30:00Z */
+ { 136359000LL, -9000 }, /* 1974-04-28T05:30:00Z */
+ { 152080200LL, -12600 }, /* 1974-10-27T04:30:00Z */
+ { 167808600LL, -9000 }, /* 1975-04-27T05:30:00Z */
+ { 183529800LL, -12600 }, /* 1975-10-26T04:30:00Z */
+ { 199258200LL, -9000 }, /* 1976-04-25T05:30:00Z */
+ { 215584200LL, -12600 }, /* 1976-10-31T04:30:00Z */
+ { 230707800LL, -9000 }, /* 1977-04-24T05:30:00Z */
+ { 247033800LL, -12600 }, /* 1977-10-30T04:30:00Z */
+ { 262762200LL, -9000 }, /* 1978-04-30T05:30:00Z */
+ { 278483400LL, -12600 }, /* 1978-10-29T04:30:00Z */
+ { 294211800LL, -9000 }, /* 1979-04-29T05:30:00Z */
+ { 309933000LL, -12600 }, /* 1979-10-28T04:30:00Z */
+ { 325661400LL, -9000 }, /* 1980-04-27T05:30:00Z */
+ { 341382600LL, -12600 }, /* 1980-10-26T04:30:00Z */
+ { 357111000LL, -9000 }, /* 1981-04-26T05:30:00Z */
+ { 372832200LL, -12600 }, /* 1981-10-25T04:30:00Z */
+ { 388560600LL, -9000 }, /* 1982-04-25T05:30:00Z */
+ { 404886600LL, -12600 }, /* 1982-10-31T04:30:00Z */
+ { 420010200LL, -9000 }, /* 1983-04-24T05:30:00Z */
+ { 436336200LL, -12600 }, /* 1983-10-30T04:30:00Z */
+ { 452064600LL, -9000 }, /* 1984-04-29T05:30:00Z */
+ { 467785800LL, -12600 }, /* 1984-10-28T04:30:00Z */
+ { 483514200LL, -9000 }, /* 1985-04-28T05:30:00Z */
+ { 499235400LL, -12600 }, /* 1985-10-27T04:30:00Z */
+ { 514963800LL, -9000 }, /* 1986-04-27T05:30:00Z */
+ { 530685000LL, -12600 }, /* 1986-10-26T04:30:00Z */
+ { 544591860LL, -9000 }, /* 1987-04-05T03:31:00Z */
+ { 562127460LL, -12600 }, /* 1987-10-25T02:31:00Z */
+ { 576041460LL, -5400 }, /* 1988-04-03T03:31:00Z */
+ { 594178260LL, -12600 }, /* 1988-10-30T01:31:00Z */
+ { 607491060LL, -9000 }, /* 1989-04-02T03:31:00Z */
+ { 625631460LL, -12600 }, /* 1989-10-29T02:31:00Z */
+ { 638940660LL, -9000 }, /* 1990-04-01T03:31:00Z */
+ { 657081060LL, -12600 }, /* 1990-10-28T02:31:00Z */
+ { 670995060LL, -9000 }, /* 1991-04-07T03:31:00Z */
+ { 688530660LL, -12600 }, /* 1991-10-27T02:31:00Z */
+ { 702444660LL, -9000 }, /* 1992-04-05T03:31:00Z */
+ { 719980260LL, -12600 }, /* 1992-10-25T02:31:00Z */
+ { 733894260LL, -9000 }, /* 1993-04-04T03:31:00Z */
+ { 752034660LL, -12600 }, /* 1993-10-31T02:31:00Z */
+ { 765343860LL, -9000 }, /* 1994-04-03T03:31:00Z */
+ { 783484260LL, -12600 }, /* 1994-10-30T02:31:00Z */
+ { 796793460LL, -9000 }, /* 1995-04-02T03:31:00Z */
+ { 814933860LL, -12600 }, /* 1995-10-29T02:31:00Z */
+ { 828847860LL, -9000 }, /* 1996-04-07T03:31:00Z */
+ { 846383460LL, -12600 }, /* 1996-10-27T02:31:00Z */
+ { 860297460LL, -9000 }, /* 1997-04-06T03:31:00Z */
+ { 877833060LL, -12600 }, /* 1997-10-26T02:31:00Z */
+ { 891747060LL, -9000 }, /* 1998-04-05T03:31:00Z */
+ { 909282660LL, -12600 }, /* 1998-10-25T02:31:00Z */
+ { 923196660LL, -9000 }, /* 1999-04-04T03:31:00Z */
+ { 941337060LL, -12600 }, /* 1999-10-31T02:31:00Z */
+ { 954646260LL, -9000 }, /* 2000-04-02T03:31:00Z */
+ { 972786660LL, -12600 }, /* 2000-10-29T02:31:00Z */
+ { 986095860LL, -9000 }, /* 2001-04-01T03:31:00Z */
+ { 1004236260LL, -12600 }, /* 2001-10-28T02:31:00Z */
+ { 1018150260LL, -9000 }, /* 2002-04-07T03:31:00Z */
+ { 1035685860LL, -12600 }, /* 2002-10-27T02:31:00Z */
+ { 1049599860LL, -9000 }, /* 2003-04-06T03:31:00Z */
+ { 1067135460LL, -12600 }, /* 2003-10-26T02:31:00Z */
+ { 1081049460LL, -9000 }, /* 2004-04-04T03:31:00Z */
+ { 1099189860LL, -12600 }, /* 2004-10-31T02:31:00Z */
+ { 1112499060LL, -9000 }, /* 2005-04-03T03:31:00Z */
+ { 1130639460LL, -12600 }, /* 2005-10-30T02:31:00Z */
+ { 1143948660LL, -9000 }, /* 2006-04-02T03:31:00Z */
+ { 1162089060LL, -12600 }, /* 2006-10-29T02:31:00Z */
+ { 1173583860LL, -9000 }, /* 2007-03-11T03:31:00Z */
+ { 1194143460LL, -12600 }, /* 2007-11-04T02:31:00Z */
+ { 1205033460LL, -9000 }, /* 2008-03-09T03:31:00Z */
+ { 1225593060LL, -12600 }, /* 2008-11-02T02:31:00Z */
+ { 1236483060LL, -9000 }, /* 2009-03-08T03:31:00Z */
+ { 1257042660LL, -12600 }, /* 2009-11-01T02:31:00Z */
+ { 1268537460LL, -9000 }, /* 2010-03-14T03:31:00Z */
+ { 1289097060LL, -12600 }, /* 2010-11-07T02:31:00Z */
+ { 1299987060LL, -9000 }, /* 2011-03-13T03:31:00Z */
+ { 1320553800LL, -12600 }, /* 2011-11-06T04:30:00Z */
+ { 1331443800LL, -9000 }, /* 2012-03-11T05:30:00Z */
+ { 1352003400LL, -12600 }, /* 2012-11-04T04:30:00Z */
+ { 1362893400LL, -9000 }, /* 2013-03-10T05:30:00Z */
+ { 1383453000LL, -12600 }, /* 2013-11-03T04:30:00Z */
+ { 1394343000LL, -9000 }, /* 2014-03-09T05:30:00Z */
+ { 1414902600LL, -12600 }, /* 2014-11-02T04:30:00Z */
+ { 1425792600LL, -9000 }, /* 2015-03-08T05:30:00Z */
+ { 1446352200LL, -12600 }, /* 2015-11-01T04:30:00Z */
+ { 1457847000LL, -9000 }, /* 2016-03-13T05:30:00Z */
+ { 1478406600LL, -12600 }, /* 2016-11-06T04:30:00Z */
+ { 1489296600LL, -9000 }, /* 2017-03-12T05:30:00Z */
+ { 1509856200LL, -12600 }, /* 2017-11-05T04:30:00Z */
+ { 1520746200LL, -9000 }, /* 2018-03-11T05:30:00Z */
+ { 1541305800LL, -12600 }, /* 2018-11-04T04:30:00Z */
+ { 1552195800LL, -9000 }, /* 2019-03-10T05:30:00Z */
+ { 1572755400LL, -12600 }, /* 2019-11-03T04:30:00Z */
+ { 1583645400LL, -9000 }, /* 2020-03-08T05:30:00Z */
+ { 1604205000LL, -12600 }, /* 2020-11-01T04:30:00Z */
+ { 1615699800LL, -9000 }, /* 2021-03-14T05:30:00Z */
+ { 1636259400LL, -12600 }, /* 2021-11-07T04:30:00Z */
+ { 1647149400LL, -9000 }, /* 2022-03-13T05:30:00Z */
+ { 1667709000LL, -12600 }, /* 2022-11-06T04:30:00Z */
+ { 1678599000LL, -9000 }, /* 2023-03-12T05:30:00Z */
+ { 1699158600LL, -12600 }, /* 2023-11-05T04:30:00Z */
+ { 1710048600LL, -9000 }, /* 2024-03-10T05:30:00Z */
+ { 1730608200LL, -12600 }, /* 2024-11-03T04:30:00Z */
+ { 1741498200LL, -9000 }, /* 2025-03-09T05:30:00Z */
+ { 1762057800LL, -12600 }, /* 2025-11-02T04:30:00Z */
+ { 1772947800LL, -9000 }, /* 2026-03-08T05:30:00Z */
+ { 1793507400LL, -12600 }, /* 2026-11-01T04:30:00Z */
+ { 1805002200LL, -9000 }, /* 2027-03-14T05:30:00Z */
+ { 1825561800LL, -12600 }, /* 2027-11-07T04:30:00Z */
+ { 1836451800LL, -9000 }, /* 2028-03-12T05:30:00Z */
+ { 1857011400LL, -12600 }, /* 2028-11-05T04:30:00Z */
+ { 1867901400LL, -9000 }, /* 2029-03-11T05:30:00Z */
+ { 1888461000LL, -12600 }, /* 2029-11-04T04:30:00Z */
+ { 1899351000LL, -9000 }, /* 2030-03-10T05:30:00Z */
+ { 1919910600LL, -12600 }, /* 2030-11-03T04:30:00Z */
+ { 1930800600LL, -9000 }, /* 2031-03-09T05:30:00Z */
+ { 1951360200LL, -12600 }, /* 2031-11-02T04:30:00Z */
+ { 1962855000LL, -9000 }, /* 2032-03-14T05:30:00Z */
+ { 1983414600LL, -12600 }, /* 2032-11-07T04:30:00Z */
+ { 1994304600LL, -9000 }, /* 2033-03-13T05:30:00Z */
+ { 2014864200LL, -12600 }, /* 2033-11-06T04:30:00Z */
+ { 2025754200LL, -9000 }, /* 2034-03-12T05:30:00Z */
+ { 2046313800LL, -12600 }, /* 2034-11-05T04:30:00Z */
+ { 2057203800LL, -9000 }, /* 2035-03-11T05:30:00Z */
+ { 2077763400LL, -12600 }, /* 2035-11-04T04:30:00Z */
+ { 2088653400LL, -9000 }, /* 2036-03-09T05:30:00Z */
+ { 2109213000LL, -12600 }, /* 2036-11-02T04:30:00Z */
+ { 2120103000LL, -9000 }, /* 2037-03-08T05:30:00Z */
+ { 2140662600LL, -12600 }, /* 2037-11-01T04:30:00Z */
+};
+
+static const TZTransition tz_trans_America_Toronto[] = {
+ { INT64_MIN, -19052 }, /* before first transition */
+ { -2366736148LL, -18000 }, /* 1895-01-01T05:17:32Z */
+ { -1632070800LL, -14400 }, /* 1918-04-14T07:00:00Z */
+ { -1615140000LL, -18000 }, /* 1918-10-27T06:00:00Z */
+ { -1601753400LL, -14400 }, /* 1919-03-31T04:30:00Z */
+ { -1583697600LL, -18000 }, /* 1919-10-26T04:00:00Z */
+ { -1567357200LL, -14400 }, /* 1920-05-02T07:00:00Z */
+ { -1554667200LL, -18000 }, /* 1920-09-26T04:00:00Z */
+ { -1534698000LL, -14400 }, /* 1921-05-15T07:00:00Z */
+ { -1524074400LL, -18000 }, /* 1921-09-15T06:00:00Z */
+ { -1503248400LL, -14400 }, /* 1922-05-14T07:00:00Z */
+ { -1492365600LL, -18000 }, /* 1922-09-17T06:00:00Z */
+ { -1471798800LL, -14400 }, /* 1923-05-13T07:00:00Z */
+ { -1460916000LL, -18000 }, /* 1923-09-16T06:00:00Z */
+ { -1440954000LL, -14400 }, /* 1924-05-04T07:00:00Z */
+ { -1428861600LL, -18000 }, /* 1924-09-21T06:00:00Z */
+ { -1409504400LL, -14400 }, /* 1925-05-03T07:00:00Z */
+ { -1397412000LL, -18000 }, /* 1925-09-20T06:00:00Z */
+ { -1378054800LL, -14400 }, /* 1926-05-02T07:00:00Z */
+ { -1365962400LL, -18000 }, /* 1926-09-19T06:00:00Z */
+ { -1346605200LL, -14400 }, /* 1927-05-01T07:00:00Z */
+ { -1333908000LL, -18000 }, /* 1927-09-25T06:00:00Z */
+ { -1315155600LL, -14400 }, /* 1928-04-29T07:00:00Z */
+ { -1301853600LL, -18000 }, /* 1928-09-30T06:00:00Z */
+ { -1283706000LL, -14400 }, /* 1929-04-28T07:00:00Z */
+ { -1270404000LL, -18000 }, /* 1929-09-29T06:00:00Z */
+ { -1252256400LL, -14400 }, /* 1930-04-27T07:00:00Z */
+ { -1238954400LL, -18000 }, /* 1930-09-28T06:00:00Z */
+ { -1220806800LL, -14400 }, /* 1931-04-26T07:00:00Z */
+ { -1207504800LL, -18000 }, /* 1931-09-27T06:00:00Z */
+ { -1188752400LL, -14400 }, /* 1932-05-01T07:00:00Z */
+ { -1176055200LL, -18000 }, /* 1932-09-25T06:00:00Z */
+ { -1157302800LL, -14400 }, /* 1933-04-30T07:00:00Z */
+ { -1144000800LL, -18000 }, /* 1933-10-01T06:00:00Z */
+ { -1125853200LL, -14400 }, /* 1934-04-29T07:00:00Z */
+ { -1112551200LL, -18000 }, /* 1934-09-30T06:00:00Z */
+ { -1094403600LL, -14400 }, /* 1935-04-28T07:00:00Z */
+ { -1081101600LL, -18000 }, /* 1935-09-29T06:00:00Z */
+ { -1062954000LL, -14400 }, /* 1936-04-26T07:00:00Z */
+ { -1049652000LL, -18000 }, /* 1936-09-27T06:00:00Z */
+ { -1031504400LL, -14400 }, /* 1937-04-25T07:00:00Z */
+ { -1018202400LL, -18000 }, /* 1937-09-26T06:00:00Z */
+ { -1000054800LL, -14400 }, /* 1938-04-24T07:00:00Z */
+ { -986752800LL, -18000 }, /* 1938-09-25T06:00:00Z */
+ { -968000400LL, -14400 }, /* 1939-04-30T07:00:00Z */
+ { -955303200LL, -18000 }, /* 1939-09-24T06:00:00Z */
+ { -936550800LL, -14400 }, /* 1940-04-28T07:00:00Z */
+ { -880218000LL, -14400 }, /* 1942-02-09T07:00:00Z */
+ { -769395600LL, -14400 }, /* 1945-08-14T23:00:00Z */
+ { -765396000LL, -18000 }, /* 1945-09-30T06:00:00Z */
+ { -747248400LL, -14400 }, /* 1946-04-28T07:00:00Z */
+ { -733946400LL, -18000 }, /* 1946-09-29T06:00:00Z */
+ { -715798800LL, -14400 }, /* 1947-04-27T07:00:00Z */
+ { -702496800LL, -18000 }, /* 1947-09-28T06:00:00Z */
+ { -684349200LL, -14400 }, /* 1948-04-25T07:00:00Z */
+ { -671047200LL, -18000 }, /* 1948-09-26T06:00:00Z */
+ { -652899600LL, -14400 }, /* 1949-04-24T07:00:00Z */
+ { -634154400LL, -18000 }, /* 1949-11-27T06:00:00Z */
+ { -620845200LL, -14400 }, /* 1950-04-30T07:00:00Z */
+ { -602704800LL, -18000 }, /* 1950-11-26T06:00:00Z */
+ { -589395600LL, -14400 }, /* 1951-04-29T07:00:00Z */
+ { -576093600LL, -18000 }, /* 1951-09-30T06:00:00Z */
+ { -557946000LL, -14400 }, /* 1952-04-27T07:00:00Z */
+ { -544644000LL, -18000 }, /* 1952-09-28T06:00:00Z */
+ { -526496400LL, -14400 }, /* 1953-04-26T07:00:00Z */
+ { -513194400LL, -18000 }, /* 1953-09-27T06:00:00Z */
+ { -495046800LL, -14400 }, /* 1954-04-25T07:00:00Z */
+ { -481744800LL, -18000 }, /* 1954-09-26T06:00:00Z */
+ { -463597200LL, -14400 }, /* 1955-04-24T07:00:00Z */
+ { -450295200LL, -18000 }, /* 1955-09-25T06:00:00Z */
+ { -431542800LL, -14400 }, /* 1956-04-29T07:00:00Z */
+ { -418240800LL, -18000 }, /* 1956-09-30T06:00:00Z */
+ { -400093200LL, -14400 }, /* 1957-04-28T07:00:00Z */
+ { -384372000LL, -18000 }, /* 1957-10-27T06:00:00Z */
+ { -368643600LL, -14400 }, /* 1958-04-27T07:00:00Z */
+ { -352922400LL, -18000 }, /* 1958-10-26T06:00:00Z */
+ { -337194000LL, -14400 }, /* 1959-04-26T07:00:00Z */
+ { -321472800LL, -18000 }, /* 1959-10-25T06:00:00Z */
+ { -305744400LL, -14400 }, /* 1960-04-24T07:00:00Z */
+ { -289418400LL, -18000 }, /* 1960-10-30T06:00:00Z */
+ { -273690000LL, -14400 }, /* 1961-04-30T07:00:00Z */
+ { -257968800LL, -18000 }, /* 1961-10-29T06:00:00Z */
+ { -242240400LL, -14400 }, /* 1962-04-29T07:00:00Z */
+ { -226519200LL, -18000 }, /* 1962-10-28T06:00:00Z */
+ { -210790800LL, -14400 }, /* 1963-04-28T07:00:00Z */
+ { -195069600LL, -18000 }, /* 1963-10-27T06:00:00Z */
+ { -179341200LL, -14400 }, /* 1964-04-26T07:00:00Z */
+ { -163620000LL, -18000 }, /* 1964-10-25T06:00:00Z */
+ { -147891600LL, -14400 }, /* 1965-04-25T07:00:00Z */
+ { -131565600LL, -18000 }, /* 1965-10-31T06:00:00Z */
+ { -116442000LL, -14400 }, /* 1966-04-24T07:00:00Z */
+ { -100116000LL, -18000 }, /* 1966-10-30T06:00:00Z */
+ { -84387600LL, -14400 }, /* 1967-04-30T07:00:00Z */
+ { -68666400LL, -18000 }, /* 1967-10-29T06:00:00Z */
+ { -52938000LL, -14400 }, /* 1968-04-28T07:00:00Z */
+ { -37216800LL, -18000 }, /* 1968-10-27T06:00:00Z */
+ { -21488400LL, -14400 }, /* 1969-04-27T07:00:00Z */
+ { -5767200LL, -18000 }, /* 1969-10-26T06:00:00Z */
+ { 9961200LL, -14400 }, /* 1970-04-26T07:00:00Z */
+ { 25682400LL, -18000 }, /* 1970-10-25T06:00:00Z */
+ { 41410800LL, -14400 }, /* 1971-04-25T07:00:00Z */
+ { 57736800LL, -18000 }, /* 1971-10-31T06:00:00Z */
+ { 73465200LL, -14400 }, /* 1972-04-30T07:00:00Z */
+ { 89186400LL, -18000 }, /* 1972-10-29T06:00:00Z */
+ { 104914800LL, -14400 }, /* 1973-04-29T07:00:00Z */
+ { 120636000LL, -18000 }, /* 1973-10-28T06:00:00Z */
+ { 136364400LL, -14400 }, /* 1974-04-28T07:00:00Z */
+ { 152085600LL, -18000 }, /* 1974-10-27T06:00:00Z */
+ { 167814000LL, -14400 }, /* 1975-04-27T07:00:00Z */
+ { 183535200LL, -18000 }, /* 1975-10-26T06:00:00Z */
+ { 199263600LL, -14400 }, /* 1976-04-25T07:00:00Z */
+ { 215589600LL, -18000 }, /* 1976-10-31T06:00:00Z */
+ { 230713200LL, -14400 }, /* 1977-04-24T07:00:00Z */
+ { 247039200LL, -18000 }, /* 1977-10-30T06:00:00Z */
+ { 262767600LL, -14400 }, /* 1978-04-30T07:00:00Z */
+ { 278488800LL, -18000 }, /* 1978-10-29T06:00:00Z */
+ { 294217200LL, -14400 }, /* 1979-04-29T07:00:00Z */
+ { 309938400LL, -18000 }, /* 1979-10-28T06:00:00Z */
+ { 325666800LL, -14400 }, /* 1980-04-27T07:00:00Z */
+ { 341388000LL, -18000 }, /* 1980-10-26T06:00:00Z */
+ { 357116400LL, -14400 }, /* 1981-04-26T07:00:00Z */
+ { 372837600LL, -18000 }, /* 1981-10-25T06:00:00Z */
+ { 388566000LL, -14400 }, /* 1982-04-25T07:00:00Z */
+ { 404892000LL, -18000 }, /* 1982-10-31T06:00:00Z */
+ { 420015600LL, -14400 }, /* 1983-04-24T07:00:00Z */
+ { 436341600LL, -18000 }, /* 1983-10-30T06:00:00Z */
+ { 452070000LL, -14400 }, /* 1984-04-29T07:00:00Z */
+ { 467791200LL, -18000 }, /* 1984-10-28T06:00:00Z */
+ { 483519600LL, -14400 }, /* 1985-04-28T07:00:00Z */
+ { 499240800LL, -18000 }, /* 1985-10-27T06:00:00Z */
+ { 514969200LL, -14400 }, /* 1986-04-27T07:00:00Z */
+ { 530690400LL, -18000 }, /* 1986-10-26T06:00:00Z */
+ { 544604400LL, -14400 }, /* 1987-04-05T07:00:00Z */
+ { 562140000LL, -18000 }, /* 1987-10-25T06:00:00Z */
+ { 576054000LL, -14400 }, /* 1988-04-03T07:00:00Z */
+ { 594194400LL, -18000 }, /* 1988-10-30T06:00:00Z */
+ { 607503600LL, -14400 }, /* 1989-04-02T07:00:00Z */
+ { 625644000LL, -18000 }, /* 1989-10-29T06:00:00Z */
+ { 638953200LL, -14400 }, /* 1990-04-01T07:00:00Z */
+ { 657093600LL, -18000 }, /* 1990-10-28T06:00:00Z */
+ { 671007600LL, -14400 }, /* 1991-04-07T07:00:00Z */
+ { 688543200LL, -18000 }, /* 1991-10-27T06:00:00Z */
+ { 702457200LL, -14400 }, /* 1992-04-05T07:00:00Z */
+ { 719992800LL, -18000 }, /* 1992-10-25T06:00:00Z */
+ { 733906800LL, -14400 }, /* 1993-04-04T07:00:00Z */
+ { 752047200LL, -18000 }, /* 1993-10-31T06:00:00Z */
+ { 765356400LL, -14400 }, /* 1994-04-03T07:00:00Z */
+ { 783496800LL, -18000 }, /* 1994-10-30T06:00:00Z */
+ { 796806000LL, -14400 }, /* 1995-04-02T07:00:00Z */
+ { 814946400LL, -18000 }, /* 1995-10-29T06:00:00Z */
+ { 828860400LL, -14400 }, /* 1996-04-07T07:00:00Z */
+ { 846396000LL, -18000 }, /* 1996-10-27T06:00:00Z */
+ { 860310000LL, -14400 }, /* 1997-04-06T07:00:00Z */
+ { 877845600LL, -18000 }, /* 1997-10-26T06:00:00Z */
+ { 891759600LL, -14400 }, /* 1998-04-05T07:00:00Z */
+ { 909295200LL, -18000 }, /* 1998-10-25T06:00:00Z */
+ { 923209200LL, -14400 }, /* 1999-04-04T07:00:00Z */
+ { 941349600LL, -18000 }, /* 1999-10-31T06:00:00Z */
+ { 954658800LL, -14400 }, /* 2000-04-02T07:00:00Z */
+ { 972799200LL, -18000 }, /* 2000-10-29T06:00:00Z */
+ { 986108400LL, -14400 }, /* 2001-04-01T07:00:00Z */
+ { 1004248800LL, -18000 }, /* 2001-10-28T06:00:00Z */
+ { 1018162800LL, -14400 }, /* 2002-04-07T07:00:00Z */
+ { 1035698400LL, -18000 }, /* 2002-10-27T06:00:00Z */
+ { 1049612400LL, -14400 }, /* 2003-04-06T07:00:00Z */
+ { 1067148000LL, -18000 }, /* 2003-10-26T06:00:00Z */
+ { 1081062000LL, -14400 }, /* 2004-04-04T07:00:00Z */
+ { 1099202400LL, -18000 }, /* 2004-10-31T06:00:00Z */
+ { 1112511600LL, -14400 }, /* 2005-04-03T07:00:00Z */
+ { 1130652000LL, -18000 }, /* 2005-10-30T06:00:00Z */
+ { 1143961200LL, -14400 }, /* 2006-04-02T07:00:00Z */
+ { 1162101600LL, -18000 }, /* 2006-10-29T06:00:00Z */
+ { 1173596400LL, -14400 }, /* 2007-03-11T07:00:00Z */
+ { 1194156000LL, -18000 }, /* 2007-11-04T06:00:00Z */
+ { 1205046000LL, -14400 }, /* 2008-03-09T07:00:00Z */
+ { 1225605600LL, -18000 }, /* 2008-11-02T06:00:00Z */
+ { 1236495600LL, -14400 }, /* 2009-03-08T07:00:00Z */
+ { 1257055200LL, -18000 }, /* 2009-11-01T06:00:00Z */
+ { 1268550000LL, -14400 }, /* 2010-03-14T07:00:00Z */
+ { 1289109600LL, -18000 }, /* 2010-11-07T06:00:00Z */
+ { 1299999600LL, -14400 }, /* 2011-03-13T07:00:00Z */
+ { 1320559200LL, -18000 }, /* 2011-11-06T06:00:00Z */
+ { 1331449200LL, -14400 }, /* 2012-03-11T07:00:00Z */
+ { 1352008800LL, -18000 }, /* 2012-11-04T06:00:00Z */
+ { 1362898800LL, -14400 }, /* 2013-03-10T07:00:00Z */
+ { 1383458400LL, -18000 }, /* 2013-11-03T06:00:00Z */
+ { 1394348400LL, -14400 }, /* 2014-03-09T07:00:00Z */
+ { 1414908000LL, -18000 }, /* 2014-11-02T06:00:00Z */
+ { 1425798000LL, -14400 }, /* 2015-03-08T07:00:00Z */
+ { 1446357600LL, -18000 }, /* 2015-11-01T06:00:00Z */
+ { 1457852400LL, -14400 }, /* 2016-03-13T07:00:00Z */
+ { 1478412000LL, -18000 }, /* 2016-11-06T06:00:00Z */
+ { 1489302000LL, -14400 }, /* 2017-03-12T07:00:00Z */
+ { 1509861600LL, -18000 }, /* 2017-11-05T06:00:00Z */
+ { 1520751600LL, -14400 }, /* 2018-03-11T07:00:00Z */
+ { 1541311200LL, -18000 }, /* 2018-11-04T06:00:00Z */
+ { 1552201200LL, -14400 }, /* 2019-03-10T07:00:00Z */
+ { 1572760800LL, -18000 }, /* 2019-11-03T06:00:00Z */
+ { 1583650800LL, -14400 }, /* 2020-03-08T07:00:00Z */
+ { 1604210400LL, -18000 }, /* 2020-11-01T06:00:00Z */
+ { 1615705200LL, -14400 }, /* 2021-03-14T07:00:00Z */
+ { 1636264800LL, -18000 }, /* 2021-11-07T06:00:00Z */
+ { 1647154800LL, -14400 }, /* 2022-03-13T07:00:00Z */
+ { 1667714400LL, -18000 }, /* 2022-11-06T06:00:00Z */
+ { 1678604400LL, -14400 }, /* 2023-03-12T07:00:00Z */
+ { 1699164000LL, -18000 }, /* 2023-11-05T06:00:00Z */
+ { 1710054000LL, -14400 }, /* 2024-03-10T07:00:00Z */
+ { 1730613600LL, -18000 }, /* 2024-11-03T06:00:00Z */
+ { 1741503600LL, -14400 }, /* 2025-03-09T07:00:00Z */
+ { 1762063200LL, -18000 }, /* 2025-11-02T06:00:00Z */
+ { 1772953200LL, -14400 }, /* 2026-03-08T07:00:00Z */
+ { 1793512800LL, -18000 }, /* 2026-11-01T06:00:00Z */
+ { 1805007600LL, -14400 }, /* 2027-03-14T07:00:00Z */
+ { 1825567200LL, -18000 }, /* 2027-11-07T06:00:00Z */
+ { 1836457200LL, -14400 }, /* 2028-03-12T07:00:00Z */
+ { 1857016800LL, -18000 }, /* 2028-11-05T06:00:00Z */
+ { 1867906800LL, -14400 }, /* 2029-03-11T07:00:00Z */
+ { 1888466400LL, -18000 }, /* 2029-11-04T06:00:00Z */
+ { 1899356400LL, -14400 }, /* 2030-03-10T07:00:00Z */
+ { 1919916000LL, -18000 }, /* 2030-11-03T06:00:00Z */
+ { 1930806000LL, -14400 }, /* 2031-03-09T07:00:00Z */
+ { 1951365600LL, -18000 }, /* 2031-11-02T06:00:00Z */
+ { 1962860400LL, -14400 }, /* 2032-03-14T07:00:00Z */
+ { 1983420000LL, -18000 }, /* 2032-11-07T06:00:00Z */
+ { 1994310000LL, -14400 }, /* 2033-03-13T07:00:00Z */
+ { 2014869600LL, -18000 }, /* 2033-11-06T06:00:00Z */
+ { 2025759600LL, -14400 }, /* 2034-03-12T07:00:00Z */
+ { 2046319200LL, -18000 }, /* 2034-11-05T06:00:00Z */
+ { 2057209200LL, -14400 }, /* 2035-03-11T07:00:00Z */
+ { 2077768800LL, -18000 }, /* 2035-11-04T06:00:00Z */
+ { 2088658800LL, -14400 }, /* 2036-03-09T07:00:00Z */
+ { 2109218400LL, -18000 }, /* 2036-11-02T06:00:00Z */
+ { 2120108400LL, -14400 }, /* 2037-03-08T07:00:00Z */
+ { 2140668000LL, -18000 }, /* 2037-11-01T06:00:00Z */
+};
+
+static const TZTransition tz_trans_America_Vancouver[] = {
+ { INT64_MIN, -29548 }, /* before first transition */
+ { -2713880852LL, -28800 }, /* 1884-01-01T08:12:28Z */
+ { -1632060000LL, -25200 }, /* 1918-04-14T10:00:00Z */
+ { -1615129200LL, -28800 }, /* 1918-10-27T09:00:00Z */
+ { -880207200LL, -25200 }, /* 1942-02-09T10:00:00Z */
+ { -769395600LL, -25200 }, /* 1945-08-14T23:00:00Z */
+ { -765385200LL, -28800 }, /* 1945-09-30T09:00:00Z */
+ { -747237600LL, -25200 }, /* 1946-04-28T10:00:00Z */
+ { -733935600LL, -28800 }, /* 1946-09-29T09:00:00Z */
+ { -715788000LL, -25200 }, /* 1947-04-27T10:00:00Z */
+ { -702486000LL, -28800 }, /* 1947-09-28T09:00:00Z */
+ { -684338400LL, -25200 }, /* 1948-04-25T10:00:00Z */
+ { -671036400LL, -28800 }, /* 1948-09-26T09:00:00Z */
+ { -652888800LL, -25200 }, /* 1949-04-24T10:00:00Z */
+ { -639586800LL, -28800 }, /* 1949-09-25T09:00:00Z */
+ { -620834400LL, -25200 }, /* 1950-04-30T10:00:00Z */
+ { -608137200LL, -28800 }, /* 1950-09-24T09:00:00Z */
+ { -589384800LL, -25200 }, /* 1951-04-29T10:00:00Z */
+ { -576082800LL, -28800 }, /* 1951-09-30T09:00:00Z */
+ { -557935200LL, -25200 }, /* 1952-04-27T10:00:00Z */
+ { -544633200LL, -28800 }, /* 1952-09-28T09:00:00Z */
+ { -526485600LL, -25200 }, /* 1953-04-26T10:00:00Z */
+ { -513183600LL, -28800 }, /* 1953-09-27T09:00:00Z */
+ { -495036000LL, -25200 }, /* 1954-04-25T10:00:00Z */
+ { -481734000LL, -28800 }, /* 1954-09-26T09:00:00Z */
+ { -463586400LL, -25200 }, /* 1955-04-24T10:00:00Z */
+ { -450284400LL, -28800 }, /* 1955-09-25T09:00:00Z */
+ { -431532000LL, -25200 }, /* 1956-04-29T10:00:00Z */
+ { -418230000LL, -28800 }, /* 1956-09-30T09:00:00Z */
+ { -400082400LL, -25200 }, /* 1957-04-28T10:00:00Z */
+ { -386780400LL, -28800 }, /* 1957-09-29T09:00:00Z */
+ { -368632800LL, -25200 }, /* 1958-04-27T10:00:00Z */
+ { -355330800LL, -28800 }, /* 1958-09-28T09:00:00Z */
+ { -337183200LL, -25200 }, /* 1959-04-26T10:00:00Z */
+ { -323881200LL, -28800 }, /* 1959-09-27T09:00:00Z */
+ { -305733600LL, -25200 }, /* 1960-04-24T10:00:00Z */
+ { -292431600LL, -28800 }, /* 1960-09-25T09:00:00Z */
+ { -273679200LL, -25200 }, /* 1961-04-30T10:00:00Z */
+ { -260982000LL, -28800 }, /* 1961-09-24T09:00:00Z */
+ { -242229600LL, -25200 }, /* 1962-04-29T10:00:00Z */
+ { -226508400LL, -28800 }, /* 1962-10-28T09:00:00Z */
+ { -210780000LL, -25200 }, /* 1963-04-28T10:00:00Z */
+ { -195058800LL, -28800 }, /* 1963-10-27T09:00:00Z */
+ { -179330400LL, -25200 }, /* 1964-04-26T10:00:00Z */
+ { -163609200LL, -28800 }, /* 1964-10-25T09:00:00Z */
+ { -147880800LL, -25200 }, /* 1965-04-25T10:00:00Z */
+ { -131554800LL, -28800 }, /* 1965-10-31T09:00:00Z */
+ { -116431200LL, -25200 }, /* 1966-04-24T10:00:00Z */
+ { -100105200LL, -28800 }, /* 1966-10-30T09:00:00Z */
+ { -84376800LL, -25200 }, /* 1967-04-30T10:00:00Z */
+ { -68655600LL, -28800 }, /* 1967-10-29T09:00:00Z */
+ { -52927200LL, -25200 }, /* 1968-04-28T10:00:00Z */
+ { -37206000LL, -28800 }, /* 1968-10-27T09:00:00Z */
+ { -21477600LL, -25200 }, /* 1969-04-27T10:00:00Z */
+ { -5756400LL, -28800 }, /* 1969-10-26T09:00:00Z */
+ { 9972000LL, -25200 }, /* 1970-04-26T10:00:00Z */
+ { 25693200LL, -28800 }, /* 1970-10-25T09:00:00Z */
+ { 41421600LL, -25200 }, /* 1971-04-25T10:00:00Z */
+ { 57747600LL, -28800 }, /* 1971-10-31T09:00:00Z */
+ { 73476000LL, -25200 }, /* 1972-04-30T10:00:00Z */
+ { 89197200LL, -28800 }, /* 1972-10-29T09:00:00Z */
+ { 104925600LL, -25200 }, /* 1973-04-29T10:00:00Z */
+ { 120646800LL, -28800 }, /* 1973-10-28T09:00:00Z */
+ { 136375200LL, -25200 }, /* 1974-04-28T10:00:00Z */
+ { 152096400LL, -28800 }, /* 1974-10-27T09:00:00Z */
+ { 167824800LL, -25200 }, /* 1975-04-27T10:00:00Z */
+ { 183546000LL, -28800 }, /* 1975-10-26T09:00:00Z */
+ { 199274400LL, -25200 }, /* 1976-04-25T10:00:00Z */
+ { 215600400LL, -28800 }, /* 1976-10-31T09:00:00Z */
+ { 230724000LL, -25200 }, /* 1977-04-24T10:00:00Z */
+ { 247050000LL, -28800 }, /* 1977-10-30T09:00:00Z */
+ { 262778400LL, -25200 }, /* 1978-04-30T10:00:00Z */
+ { 278499600LL, -28800 }, /* 1978-10-29T09:00:00Z */
+ { 294228000LL, -25200 }, /* 1979-04-29T10:00:00Z */
+ { 309949200LL, -28800 }, /* 1979-10-28T09:00:00Z */
+ { 325677600LL, -25200 }, /* 1980-04-27T10:00:00Z */
+ { 341398800LL, -28800 }, /* 1980-10-26T09:00:00Z */
+ { 357127200LL, -25200 }, /* 1981-04-26T10:00:00Z */
+ { 372848400LL, -28800 }, /* 1981-10-25T09:00:00Z */
+ { 388576800LL, -25200 }, /* 1982-04-25T10:00:00Z */
+ { 404902800LL, -28800 }, /* 1982-10-31T09:00:00Z */
+ { 420026400LL, -25200 }, /* 1983-04-24T10:00:00Z */
+ { 436352400LL, -28800 }, /* 1983-10-30T09:00:00Z */
+ { 452080800LL, -25200 }, /* 1984-04-29T10:00:00Z */
+ { 467802000LL, -28800 }, /* 1984-10-28T09:00:00Z */
+ { 483530400LL, -25200 }, /* 1985-04-28T10:00:00Z */
+ { 499251600LL, -28800 }, /* 1985-10-27T09:00:00Z */
+ { 514980000LL, -25200 }, /* 1986-04-27T10:00:00Z */
+ { 530701200LL, -28800 }, /* 1986-10-26T09:00:00Z */
+ { 544615200LL, -25200 }, /* 1987-04-05T10:00:00Z */
+ { 562150800LL, -28800 }, /* 1987-10-25T09:00:00Z */
+ { 576064800LL, -25200 }, /* 1988-04-03T10:00:00Z */
+ { 594205200LL, -28800 }, /* 1988-10-30T09:00:00Z */
+ { 607514400LL, -25200 }, /* 1989-04-02T10:00:00Z */
+ { 625654800LL, -28800 }, /* 1989-10-29T09:00:00Z */
+ { 638964000LL, -25200 }, /* 1990-04-01T10:00:00Z */
+ { 657104400LL, -28800 }, /* 1990-10-28T09:00:00Z */
+ { 671018400LL, -25200 }, /* 1991-04-07T10:00:00Z */
+ { 688554000LL, -28800 }, /* 1991-10-27T09:00:00Z */
+ { 702468000LL, -25200 }, /* 1992-04-05T10:00:00Z */
+ { 720003600LL, -28800 }, /* 1992-10-25T09:00:00Z */
+ { 733917600LL, -25200 }, /* 1993-04-04T10:00:00Z */
+ { 752058000LL, -28800 }, /* 1993-10-31T09:00:00Z */
+ { 765367200LL, -25200 }, /* 1994-04-03T10:00:00Z */
+ { 783507600LL, -28800 }, /* 1994-10-30T09:00:00Z */
+ { 796816800LL, -25200 }, /* 1995-04-02T10:00:00Z */
+ { 814957200LL, -28800 }, /* 1995-10-29T09:00:00Z */
+ { 828871200LL, -25200 }, /* 1996-04-07T10:00:00Z */
+ { 846406800LL, -28800 }, /* 1996-10-27T09:00:00Z */
+ { 860320800LL, -25200 }, /* 1997-04-06T10:00:00Z */
+ { 877856400LL, -28800 }, /* 1997-10-26T09:00:00Z */
+ { 891770400LL, -25200 }, /* 1998-04-05T10:00:00Z */
+ { 909306000LL, -28800 }, /* 1998-10-25T09:00:00Z */
+ { 923220000LL, -25200 }, /* 1999-04-04T10:00:00Z */
+ { 941360400LL, -28800 }, /* 1999-10-31T09:00:00Z */
+ { 954669600LL, -25200 }, /* 2000-04-02T10:00:00Z */
+ { 972810000LL, -28800 }, /* 2000-10-29T09:00:00Z */
+ { 986119200LL, -25200 }, /* 2001-04-01T10:00:00Z */
+ { 1004259600LL, -28800 }, /* 2001-10-28T09:00:00Z */
+ { 1018173600LL, -25200 }, /* 2002-04-07T10:00:00Z */
+ { 1035709200LL, -28800 }, /* 2002-10-27T09:00:00Z */
+ { 1049623200LL, -25200 }, /* 2003-04-06T10:00:00Z */
+ { 1067158800LL, -28800 }, /* 2003-10-26T09:00:00Z */
+ { 1081072800LL, -25200 }, /* 2004-04-04T10:00:00Z */
+ { 1099213200LL, -28800 }, /* 2004-10-31T09:00:00Z */
+ { 1112522400LL, -25200 }, /* 2005-04-03T10:00:00Z */
+ { 1130662800LL, -28800 }, /* 2005-10-30T09:00:00Z */
+ { 1143972000LL, -25200 }, /* 2006-04-02T10:00:00Z */
+ { 1162112400LL, -28800 }, /* 2006-10-29T09:00:00Z */
+ { 1173607200LL, -25200 }, /* 2007-03-11T10:00:00Z */
+ { 1194166800LL, -28800 }, /* 2007-11-04T09:00:00Z */
+ { 1205056800LL, -25200 }, /* 2008-03-09T10:00:00Z */
+ { 1225616400LL, -28800 }, /* 2008-11-02T09:00:00Z */
+ { 1236506400LL, -25200 }, /* 2009-03-08T10:00:00Z */
+ { 1257066000LL, -28800 }, /* 2009-11-01T09:00:00Z */
+ { 1268560800LL, -25200 }, /* 2010-03-14T10:00:00Z */
+ { 1289120400LL, -28800 }, /* 2010-11-07T09:00:00Z */
+ { 1300010400LL, -25200 }, /* 2011-03-13T10:00:00Z */
+ { 1320570000LL, -28800 }, /* 2011-11-06T09:00:00Z */
+ { 1331460000LL, -25200 }, /* 2012-03-11T10:00:00Z */
+ { 1352019600LL, -28800 }, /* 2012-11-04T09:00:00Z */
+ { 1362909600LL, -25200 }, /* 2013-03-10T10:00:00Z */
+ { 1383469200LL, -28800 }, /* 2013-11-03T09:00:00Z */
+ { 1394359200LL, -25200 }, /* 2014-03-09T10:00:00Z */
+ { 1414918800LL, -28800 }, /* 2014-11-02T09:00:00Z */
+ { 1425808800LL, -25200 }, /* 2015-03-08T10:00:00Z */
+ { 1446368400LL, -28800 }, /* 2015-11-01T09:00:00Z */
+ { 1457863200LL, -25200 }, /* 2016-03-13T10:00:00Z */
+ { 1478422800LL, -28800 }, /* 2016-11-06T09:00:00Z */
+ { 1489312800LL, -25200 }, /* 2017-03-12T10:00:00Z */
+ { 1509872400LL, -28800 }, /* 2017-11-05T09:00:00Z */
+ { 1520762400LL, -25200 }, /* 2018-03-11T10:00:00Z */
+ { 1541322000LL, -28800 }, /* 2018-11-04T09:00:00Z */
+ { 1552212000LL, -25200 }, /* 2019-03-10T10:00:00Z */
+ { 1572771600LL, -28800 }, /* 2019-11-03T09:00:00Z */
+ { 1583661600LL, -25200 }, /* 2020-03-08T10:00:00Z */
+ { 1604221200LL, -28800 }, /* 2020-11-01T09:00:00Z */
+ { 1615716000LL, -25200 }, /* 2021-03-14T10:00:00Z */
+ { 1636275600LL, -28800 }, /* 2021-11-07T09:00:00Z */
+ { 1647165600LL, -25200 }, /* 2022-03-13T10:00:00Z */
+ { 1667725200LL, -28800 }, /* 2022-11-06T09:00:00Z */
+ { 1678615200LL, -25200 }, /* 2023-03-12T10:00:00Z */
+ { 1699174800LL, -28800 }, /* 2023-11-05T09:00:00Z */
+ { 1710064800LL, -25200 }, /* 2024-03-10T10:00:00Z */
+ { 1730624400LL, -28800 }, /* 2024-11-03T09:00:00Z */
+ { 1741514400LL, -25200 }, /* 2025-03-09T10:00:00Z */
+ { 1762074000LL, -28800 }, /* 2025-11-02T09:00:00Z */
+ { 1772964000LL, -25200 }, /* 2026-03-08T10:00:00Z */
+ { 1793523600LL, -25200 }, /* 2026-11-01T09:00:00Z */
+};
+
+static const TZTransition tz_trans_Antarctica_Casey[] = {
+ { INT64_MIN, 0 }, /* before first transition */
+ { -31536000LL, 28800 }, /* 1969-01-01T00:00:00Z */
+ { 1255802400LL, 39600 }, /* 2009-10-17T18:00:00Z */
+ { 1267714800LL, 28800 }, /* 2010-03-04T15:00:00Z */
+ { 1319738400LL, 39600 }, /* 2011-10-27T18:00:00Z */
+ { 1329843600LL, 28800 }, /* 2012-02-21T17:00:00Z */
+ { 1477065600LL, 39600 }, /* 2016-10-21T16:00:00Z */
+ { 1520701200LL, 28800 }, /* 2018-03-10T17:00:00Z */
+ { 1538856000LL, 39600 }, /* 2018-10-06T20:00:00Z */
+ { 1552752000LL, 28800 }, /* 2019-03-16T16:00:00Z */
+ { 1570129200LL, 39600 }, /* 2019-10-03T19:00:00Z */
+ { 1583596800LL, 28800 }, /* 2020-03-07T16:00:00Z */
+ { 1601740860LL, 39600 }, /* 2020-10-03T16:01:00Z */
+ { 1615640400LL, 28800 }, /* 2021-03-13T13:00:00Z */
+ { 1633190460LL, 39600 }, /* 2021-10-02T16:01:00Z */
+ { 1647090000LL, 28800 }, /* 2022-03-12T13:00:00Z */
+ { 1664640060LL, 39600 }, /* 2022-10-01T16:01:00Z */
+ { 1678291200LL, 28800 }, /* 2023-03-08T16:00:00Z */
+};
+
+static const TZTransition tz_trans_Asia_Kolkata[] = {
+ { INT64_MIN, 21208 }, /* before first transition */
+ { -3645237208LL, 21200 }, /* 1854-06-27T18:06:32Z */
+ { -3155694800LL, 19270 }, /* 1869-12-31T18:06:40Z */
+ { -2019705670LL, 19800 }, /* 1905-12-31T18:38:50Z */
+ { -891581400LL, 23400 }, /* 1941-09-30T18:30:00Z */
+ { -872058600LL, 19800 }, /* 1942-05-14T17:30:00Z */
+ { -862637400LL, 23400 }, /* 1942-08-31T18:30:00Z */
+ { -764145000LL, 19800 }, /* 1945-10-14T17:30:00Z */
+};
+
+static const TZTransition tz_trans_Asia_Riyadh[] = {
+ { INT64_MIN, 11212 }, /* before first transition */
+ { -719636812LL, 10800 }, /* 1947-03-13T20:53:08Z */
+};
+
+static const TZTransition tz_trans_Asia_Singapore[] = {
+ { INT64_MIN, 24925 }, /* before first transition */
+ { -2177477725LL, 24925 }, /* 1900-12-31T17:04:35Z */
+ { -2038200925LL, 25200 }, /* 1905-05-31T17:04:35Z */
+ { -1167634800LL, 26400 }, /* 1932-12-31T17:00:00Z */
+ { -1073028000LL, 26400 }, /* 1935-12-31T16:40:00Z */
+ { -894180000LL, 27000 }, /* 1941-08-31T16:40:00Z */
+ { -879665400LL, 32400 }, /* 1942-02-15T16:30:00Z */
+ { -767005200LL, 27000 }, /* 1945-09-11T15:00:00Z */
+ { 378662400LL, 28800 }, /* 1981-12-31T16:00:00Z */
+};
+
+static const TZTransition tz_trans_Asia_Tokyo[] = {
+ { INT64_MIN, 33539 }, /* before first transition */
+ { -2587712400LL, 32400 }, /* 1887-12-31T15:00:00Z */
+ { -683802000LL, 36000 }, /* 1948-05-01T15:00:00Z */
+ { -672310800LL, 32400 }, /* 1948-09-11T15:00:00Z */
+ { -654771600LL, 36000 }, /* 1949-04-02T15:00:00Z */
+ { -640861200LL, 32400 }, /* 1949-09-10T15:00:00Z */
+ { -620298000LL, 36000 }, /* 1950-05-06T15:00:00Z */
+ { -609411600LL, 32400 }, /* 1950-09-09T15:00:00Z */
+ { -588848400LL, 36000 }, /* 1951-05-05T15:00:00Z */
+ { -577962000LL, 32400 }, /* 1951-09-08T15:00:00Z */
+};
+
+static const TZTransition tz_trans_Australia_Lord_Howe[] = {
+ { INT64_MIN, 38180 }, /* before first transition */
+ { -2364114980LL, 36000 }, /* 1895-01-31T13:23:40Z */
+ { 352216800LL, 37800 }, /* 1981-02-28T14:00:00Z */
+ { 372785400LL, 41400 }, /* 1981-10-24T15:30:00Z */
+ { 384273000LL, 37800 }, /* 1982-03-06T14:30:00Z */
+ { 404839800LL, 41400 }, /* 1982-10-30T15:30:00Z */
+ { 415722600LL, 37800 }, /* 1983-03-05T14:30:00Z */
+ { 436289400LL, 41400 }, /* 1983-10-29T15:30:00Z */
+ { 447172200LL, 37800 }, /* 1984-03-03T14:30:00Z */
+ { 467739000LL, 41400 }, /* 1984-10-27T15:30:00Z */
+ { 478621800LL, 37800 }, /* 1985-03-02T14:30:00Z */
+ { 499188600LL, 39600 }, /* 1985-10-26T15:30:00Z */
+ { 511282800LL, 37800 }, /* 1986-03-15T15:00:00Z */
+ { 530033400LL, 39600 }, /* 1986-10-18T15:30:00Z */
+ { 542732400LL, 37800 }, /* 1987-03-14T15:00:00Z */
+ { 562087800LL, 39600 }, /* 1987-10-24T15:30:00Z */
+ { 574786800LL, 37800 }, /* 1988-03-19T15:00:00Z */
+ { 594142200LL, 39600 }, /* 1988-10-29T15:30:00Z */
+ { 606236400LL, 37800 }, /* 1989-03-18T15:00:00Z */
+ { 625591800LL, 39600 }, /* 1989-10-28T15:30:00Z */
+ { 636476400LL, 37800 }, /* 1990-03-03T15:00:00Z */
+ { 657041400LL, 39600 }, /* 1990-10-27T15:30:00Z */
+ { 667926000LL, 37800 }, /* 1991-03-02T15:00:00Z */
+ { 688491000LL, 39600 }, /* 1991-10-26T15:30:00Z */
+ { 699375600LL, 37800 }, /* 1992-02-29T15:00:00Z */
+ { 719940600LL, 39600 }, /* 1992-10-24T15:30:00Z */
+ { 731430000LL, 37800 }, /* 1993-03-06T15:00:00Z */
+ { 751995000LL, 39600 }, /* 1993-10-30T15:30:00Z */
+ { 762879600LL, 37800 }, /* 1994-03-05T15:00:00Z */
+ { 783444600LL, 39600 }, /* 1994-10-29T15:30:00Z */
+ { 794329200LL, 37800 }, /* 1995-03-04T15:00:00Z */
+ { 814894200LL, 39600 }, /* 1995-10-28T15:30:00Z */
+ { 828198000LL, 37800 }, /* 1996-03-30T15:00:00Z */
+ { 846343800LL, 39600 }, /* 1996-10-26T15:30:00Z */
+ { 859647600LL, 37800 }, /* 1997-03-29T15:00:00Z */
+ { 877793400LL, 39600 }, /* 1997-10-25T15:30:00Z */
+ { 891097200LL, 37800 }, /* 1998-03-28T15:00:00Z */
+ { 909243000LL, 39600 }, /* 1998-10-24T15:30:00Z */
+ { 922546800LL, 37800 }, /* 1999-03-27T15:00:00Z */
+ { 941297400LL, 39600 }, /* 1999-10-30T15:30:00Z */
+ { 953996400LL, 37800 }, /* 2000-03-25T15:00:00Z */
+ { 967303800LL, 39600 }, /* 2000-08-26T15:30:00Z */
+ { 985446000LL, 37800 }, /* 2001-03-24T15:00:00Z */
+ { 1004196600LL, 39600 }, /* 2001-10-27T15:30:00Z */
+ { 1017500400LL, 37800 }, /* 2002-03-30T15:00:00Z */
+ { 1035646200LL, 39600 }, /* 2002-10-26T15:30:00Z */
+ { 1048950000LL, 37800 }, /* 2003-03-29T15:00:00Z */
+ { 1067095800LL, 39600 }, /* 2003-10-25T15:30:00Z */
+ { 1080399600LL, 37800 }, /* 2004-03-27T15:00:00Z */
+ { 1099150200LL, 39600 }, /* 2004-10-30T15:30:00Z */
+ { 1111849200LL, 37800 }, /* 2005-03-26T15:00:00Z */
+ { 1130599800LL, 39600 }, /* 2005-10-29T15:30:00Z */
+ { 1143903600LL, 37800 }, /* 2006-04-01T15:00:00Z */
+ { 1162049400LL, 39600 }, /* 2006-10-28T15:30:00Z */
+ { 1174748400LL, 37800 }, /* 2007-03-24T15:00:00Z */
+ { 1193499000LL, 39600 }, /* 2007-10-27T15:30:00Z */
+ { 1207407600LL, 37800 }, /* 2008-04-05T15:00:00Z */
+ { 1223134200LL, 39600 }, /* 2008-10-04T15:30:00Z */
+ { 1238857200LL, 37800 }, /* 2009-04-04T15:00:00Z */
+ { 1254583800LL, 39600 }, /* 2009-10-03T15:30:00Z */
+ { 1270306800LL, 37800 }, /* 2010-04-03T15:00:00Z */
+ { 1286033400LL, 39600 }, /* 2010-10-02T15:30:00Z */
+ { 1301756400LL, 37800 }, /* 2011-04-02T15:00:00Z */
+ { 1317483000LL, 39600 }, /* 2011-10-01T15:30:00Z */
+ { 1333206000LL, 37800 }, /* 2012-03-31T15:00:00Z */
+ { 1349537400LL, 39600 }, /* 2012-10-06T15:30:00Z */
+ { 1365260400LL, 37800 }, /* 2013-04-06T15:00:00Z */
+ { 1380987000LL, 39600 }, /* 2013-10-05T15:30:00Z */
+ { 1396710000LL, 37800 }, /* 2014-04-05T15:00:00Z */
+ { 1412436600LL, 39600 }, /* 2014-10-04T15:30:00Z */
+ { 1428159600LL, 37800 }, /* 2015-04-04T15:00:00Z */
+ { 1443886200LL, 39600 }, /* 2015-10-03T15:30:00Z */
+ { 1459609200LL, 37800 }, /* 2016-04-02T15:00:00Z */
+ { 1475335800LL, 39600 }, /* 2016-10-01T15:30:00Z */
+ { 1491058800LL, 37800 }, /* 2017-04-01T15:00:00Z */
+ { 1506785400LL, 39600 }, /* 2017-09-30T15:30:00Z */
+ { 1522508400LL, 37800 }, /* 2018-03-31T15:00:00Z */
+ { 1538839800LL, 39600 }, /* 2018-10-06T15:30:00Z */
+ { 1554562800LL, 37800 }, /* 2019-04-06T15:00:00Z */
+ { 1570289400LL, 39600 }, /* 2019-10-05T15:30:00Z */
+ { 1586012400LL, 37800 }, /* 2020-04-04T15:00:00Z */
+ { 1601739000LL, 39600 }, /* 2020-10-03T15:30:00Z */
+ { 1617462000LL, 37800 }, /* 2021-04-03T15:00:00Z */
+ { 1633188600LL, 39600 }, /* 2021-10-02T15:30:00Z */
+ { 1648911600LL, 37800 }, /* 2022-04-02T15:00:00Z */
+ { 1664638200LL, 39600 }, /* 2022-10-01T15:30:00Z */
+ { 1680361200LL, 37800 }, /* 2023-04-01T15:00:00Z */
+ { 1696087800LL, 39600 }, /* 2023-09-30T15:30:00Z */
+ { 1712415600LL, 37800 }, /* 2024-04-06T15:00:00Z */
+ { 1728142200LL, 39600 }, /* 2024-10-05T15:30:00Z */
+ { 1743865200LL, 37800 }, /* 2025-04-05T15:00:00Z */
+ { 1759591800LL, 39600 }, /* 2025-10-04T15:30:00Z */
+ { 1775314800LL, 37800 }, /* 2026-04-04T15:00:00Z */
+ { 1791041400LL, 39600 }, /* 2026-10-03T15:30:00Z */
+ { 1806764400LL, 37800 }, /* 2027-04-03T15:00:00Z */
+ { 1822491000LL, 39600 }, /* 2027-10-02T15:30:00Z */
+ { 1838214000LL, 37800 }, /* 2028-04-01T15:00:00Z */
+ { 1853940600LL, 39600 }, /* 2028-09-30T15:30:00Z */
+ { 1869663600LL, 37800 }, /* 2029-03-31T15:00:00Z */
+ { 1885995000LL, 39600 }, /* 2029-10-06T15:30:00Z */
+ { 1901718000LL, 37800 }, /* 2030-04-06T15:00:00Z */
+ { 1917444600LL, 39600 }, /* 2030-10-05T15:30:00Z */
+ { 1933167600LL, 37800 }, /* 2031-04-05T15:00:00Z */
+ { 1948894200LL, 39600 }, /* 2031-10-04T15:30:00Z */
+ { 1964617200LL, 37800 }, /* 2032-04-03T15:00:00Z */
+ { 1980343800LL, 39600 }, /* 2032-10-02T15:30:00Z */
+ { 1996066800LL, 37800 }, /* 2033-04-02T15:00:00Z */
+ { 2011793400LL, 39600 }, /* 2033-10-01T15:30:00Z */
+ { 2027516400LL, 37800 }, /* 2034-04-01T15:00:00Z */
+ { 2043243000LL, 39600 }, /* 2034-09-30T15:30:00Z */
+ { 2058966000LL, 37800 }, /* 2035-03-31T15:00:00Z */
+ { 2075297400LL, 39600 }, /* 2035-10-06T15:30:00Z */
+ { 2091020400LL, 37800 }, /* 2036-04-05T15:00:00Z */
+ { 2106747000LL, 39600 }, /* 2036-10-04T15:30:00Z */
+ { 2122470000LL, 37800 }, /* 2037-04-04T15:00:00Z */
+ { 2138196600LL, 39600 }, /* 2037-10-03T15:30:00Z */
+};
+
+static const TZTransition tz_trans_Etc_GMT_plus_1[] = {
+ { INT64_MIN, -3600 }, /* before first transition */
+};
+
+static const TZTransition tz_trans_Etc_GMT_plus_10[] = {
+ { INT64_MIN, -36000 }, /* before first transition */
+};
+
+static const TZTransition tz_trans_Etc_GMT_plus_11[] = {
+ { INT64_MIN, -39600 }, /* before first transition */
+};
+
+static const TZTransition tz_trans_Etc_GMT_plus_12[] = {
+ { INT64_MIN, -43200 }, /* before first transition */
+};
+
+static const TZTransition tz_trans_Etc_GMT_plus_2[] = {
+ { INT64_MIN, -7200 }, /* before first transition */
+};
+
+static const TZTransition tz_trans_Etc_GMT_plus_3[] = {
+ { INT64_MIN, -10800 }, /* before first transition */
+};
+
+static const TZTransition tz_trans_Etc_GMT_plus_4[] = {
+ { INT64_MIN, -14400 }, /* before first transition */
+};
+
+static const TZTransition tz_trans_Etc_GMT_plus_5[] = {
+ { INT64_MIN, -18000 }, /* before first transition */
+};
+
+static const TZTransition tz_trans_Etc_GMT_plus_6[] = {
+ { INT64_MIN, -21600 }, /* before first transition */
+};
+
+static const TZTransition tz_trans_Etc_GMT_plus_7[] = {
+ { INT64_MIN, -25200 }, /* before first transition */
+};
+
+static const TZTransition tz_trans_Etc_GMT_plus_8[] = {
+ { INT64_MIN, -28800 }, /* before first transition */
+};
+
+static const TZTransition tz_trans_Etc_GMT_plus_9[] = {
+ { INT64_MIN, -32400 }, /* before first transition */
+};
+
+static const TZTransition tz_trans_Etc_GMT_1[] = {
+ { INT64_MIN, 3600 }, /* before first transition */
+};
+
+static const TZTransition tz_trans_Etc_GMT_10[] = {
+ { INT64_MIN, 36000 }, /* before first transition */
+};
+
+static const TZTransition tz_trans_Etc_GMT_11[] = {
+ { INT64_MIN, 39600 }, /* before first transition */
+};
+
+static const TZTransition tz_trans_Etc_GMT_12[] = {
+ { INT64_MIN, 43200 }, /* before first transition */
+};
+
+static const TZTransition tz_trans_Etc_GMT_13[] = {
+ { INT64_MIN, 46800 }, /* before first transition */
+};
+
+static const TZTransition tz_trans_Etc_GMT_14[] = {
+ { INT64_MIN, 50400 }, /* before first transition */
+};
+
+static const TZTransition tz_trans_Etc_GMT_2[] = {
+ { INT64_MIN, 7200 }, /* before first transition */
+};
+
+static const TZTransition tz_trans_Etc_GMT_3[] = {
+ { INT64_MIN, 10800 }, /* before first transition */
+};
+
+static const TZTransition tz_trans_Etc_GMT_4[] = {
+ { INT64_MIN, 14400 }, /* before first transition */
+};
+
+static const TZTransition tz_trans_Etc_GMT_5[] = {
+ { INT64_MIN, 18000 }, /* before first transition */
+};
+
+static const TZTransition tz_trans_Etc_GMT_6[] = {
+ { INT64_MIN, 21600 }, /* before first transition */
+};
+
+static const TZTransition tz_trans_Etc_GMT_7[] = {
+ { INT64_MIN, 25200 }, /* before first transition */
+};
+
+static const TZTransition tz_trans_Etc_GMT_8[] = {
+ { INT64_MIN, 28800 }, /* before first transition */
+};
+
+static const TZTransition tz_trans_Etc_GMT_9[] = {
+ { INT64_MIN, 32400 }, /* before first transition */
+};
+
+static const TZTransition tz_trans_Europe_Berlin[] = {
+ { INT64_MIN, 3208 }, /* before first transition */
+ { -2422054408LL, 3600 }, /* 1893-03-31T23:06:32Z */
+ { -1693706400LL, 7200 }, /* 1916-04-30T22:00:00Z */
+ { -1680483600LL, 3600 }, /* 1916-09-30T23:00:00Z */
+ { -1663455600LL, 7200 }, /* 1917-04-16T01:00:00Z */
+ { -1650150000LL, 3600 }, /* 1917-09-17T01:00:00Z */
+ { -1632006000LL, 7200 }, /* 1918-04-15T01:00:00Z */
+ { -1618700400LL, 3600 }, /* 1918-09-16T01:00:00Z */
+ { -938905200LL, 7200 }, /* 1940-04-01T01:00:00Z */
+ { -857257200LL, 3600 }, /* 1942-11-02T01:00:00Z */
+ { -844556400LL, 7200 }, /* 1943-03-29T01:00:00Z */
+ { -828226800LL, 3600 }, /* 1943-10-04T01:00:00Z */
+ { -812502000LL, 7200 }, /* 1944-04-03T01:00:00Z */
+ { -796777200LL, 3600 }, /* 1944-10-02T01:00:00Z */
+ { -781052400LL, 7200 }, /* 1945-04-02T01:00:00Z */
+ { -776563200LL, 10800 }, /* 1945-05-24T00:00:00Z */
+ { -765936000LL, 7200 }, /* 1945-09-24T00:00:00Z */
+ { -761180400LL, 3600 }, /* 1945-11-18T01:00:00Z */
+ { -748479600LL, 7200 }, /* 1946-04-14T01:00:00Z */
+ { -733273200LL, 3600 }, /* 1946-10-07T01:00:00Z */
+ { -717631200LL, 7200 }, /* 1947-04-06T02:00:00Z */
+ { -714610800LL, 10800 }, /* 1947-05-11T01:00:00Z */
+ { -710380800LL, 7200 }, /* 1947-06-29T00:00:00Z */
+ { -701910000LL, 3600 }, /* 1947-10-05T01:00:00Z */
+ { -684975600LL, 7200 }, /* 1948-04-18T01:00:00Z */
+ { -670460400LL, 3600 }, /* 1948-10-03T01:00:00Z */
+ { -654130800LL, 7200 }, /* 1949-04-10T01:00:00Z */
+ { -639010800LL, 3600 }, /* 1949-10-02T01:00:00Z */
+ { 323830800LL, 7200 }, /* 1980-04-06T01:00:00Z */
+ { 338950800LL, 3600 }, /* 1980-09-28T01:00:00Z */
+ { 354675600LL, 7200 }, /* 1981-03-29T01:00:00Z */
+ { 370400400LL, 3600 }, /* 1981-09-27T01:00:00Z */
+ { 386125200LL, 7200 }, /* 1982-03-28T01:00:00Z */
+ { 401850000LL, 3600 }, /* 1982-09-26T01:00:00Z */
+ { 417574800LL, 7200 }, /* 1983-03-27T01:00:00Z */
+ { 433299600LL, 3600 }, /* 1983-09-25T01:00:00Z */
+ { 449024400LL, 7200 }, /* 1984-03-25T01:00:00Z */
+ { 465354000LL, 3600 }, /* 1984-09-30T01:00:00Z */
+ { 481078800LL, 7200 }, /* 1985-03-31T01:00:00Z */
+ { 496803600LL, 3600 }, /* 1985-09-29T01:00:00Z */
+ { 512528400LL, 7200 }, /* 1986-03-30T01:00:00Z */
+ { 528253200LL, 3600 }, /* 1986-09-28T01:00:00Z */
+ { 543978000LL, 7200 }, /* 1987-03-29T01:00:00Z */
+ { 559702800LL, 3600 }, /* 1987-09-27T01:00:00Z */
+ { 575427600LL, 7200 }, /* 1988-03-27T01:00:00Z */
+ { 591152400LL, 3600 }, /* 1988-09-25T01:00:00Z */
+ { 606877200LL, 7200 }, /* 1989-03-26T01:00:00Z */
+ { 622602000LL, 3600 }, /* 1989-09-24T01:00:00Z */
+ { 638326800LL, 7200 }, /* 1990-03-25T01:00:00Z */
+ { 654656400LL, 3600 }, /* 1990-09-30T01:00:00Z */
+ { 670381200LL, 7200 }, /* 1991-03-31T01:00:00Z */
+ { 686106000LL, 3600 }, /* 1991-09-29T01:00:00Z */
+ { 701830800LL, 7200 }, /* 1992-03-29T01:00:00Z */
+ { 717555600LL, 3600 }, /* 1992-09-27T01:00:00Z */
+ { 733280400LL, 7200 }, /* 1993-03-28T01:00:00Z */
+ { 749005200LL, 3600 }, /* 1993-09-26T01:00:00Z */
+ { 764730000LL, 7200 }, /* 1994-03-27T01:00:00Z */
+ { 780454800LL, 3600 }, /* 1994-09-25T01:00:00Z */
+ { 796179600LL, 7200 }, /* 1995-03-26T01:00:00Z */
+ { 811904400LL, 3600 }, /* 1995-09-24T01:00:00Z */
+ { 828234000LL, 7200 }, /* 1996-03-31T01:00:00Z */
+ { 846378000LL, 3600 }, /* 1996-10-27T01:00:00Z */
+ { 859683600LL, 7200 }, /* 1997-03-30T01:00:00Z */
+ { 877827600LL, 3600 }, /* 1997-10-26T01:00:00Z */
+ { 891133200LL, 7200 }, /* 1998-03-29T01:00:00Z */
+ { 909277200LL, 3600 }, /* 1998-10-25T01:00:00Z */
+ { 922582800LL, 7200 }, /* 1999-03-28T01:00:00Z */
+ { 941331600LL, 3600 }, /* 1999-10-31T01:00:00Z */
+ { 954032400LL, 7200 }, /* 2000-03-26T01:00:00Z */
+ { 972781200LL, 3600 }, /* 2000-10-29T01:00:00Z */
+ { 985482000LL, 7200 }, /* 2001-03-25T01:00:00Z */
+ { 1004230800LL, 3600 }, /* 2001-10-28T01:00:00Z */
+ { 1017536400LL, 7200 }, /* 2002-03-31T01:00:00Z */
+ { 1035680400LL, 3600 }, /* 2002-10-27T01:00:00Z */
+ { 1048986000LL, 7200 }, /* 2003-03-30T01:00:00Z */
+ { 1067130000LL, 3600 }, /* 2003-10-26T01:00:00Z */
+ { 1080435600LL, 7200 }, /* 2004-03-28T01:00:00Z */
+ { 1099184400LL, 3600 }, /* 2004-10-31T01:00:00Z */
+ { 1111885200LL, 7200 }, /* 2005-03-27T01:00:00Z */
+ { 1130634000LL, 3600 }, /* 2005-10-30T01:00:00Z */
+ { 1143334800LL, 7200 }, /* 2006-03-26T01:00:00Z */
+ { 1162083600LL, 3600 }, /* 2006-10-29T01:00:00Z */
+ { 1174784400LL, 7200 }, /* 2007-03-25T01:00:00Z */
+ { 1193533200LL, 3600 }, /* 2007-10-28T01:00:00Z */
+ { 1206838800LL, 7200 }, /* 2008-03-30T01:00:00Z */
+ { 1224982800LL, 3600 }, /* 2008-10-26T01:00:00Z */
+ { 1238288400LL, 7200 }, /* 2009-03-29T01:00:00Z */
+ { 1256432400LL, 3600 }, /* 2009-10-25T01:00:00Z */
+ { 1269738000LL, 7200 }, /* 2010-03-28T01:00:00Z */
+ { 1288486800LL, 3600 }, /* 2010-10-31T01:00:00Z */
+ { 1301187600LL, 7200 }, /* 2011-03-27T01:00:00Z */
+ { 1319936400LL, 3600 }, /* 2011-10-30T01:00:00Z */
+ { 1332637200LL, 7200 }, /* 2012-03-25T01:00:00Z */
+ { 1351386000LL, 3600 }, /* 2012-10-28T01:00:00Z */
+ { 1364691600LL, 7200 }, /* 2013-03-31T01:00:00Z */
+ { 1382835600LL, 3600 }, /* 2013-10-27T01:00:00Z */
+ { 1396141200LL, 7200 }, /* 2014-03-30T01:00:00Z */
+ { 1414285200LL, 3600 }, /* 2014-10-26T01:00:00Z */
+ { 1427590800LL, 7200 }, /* 2015-03-29T01:00:00Z */
+ { 1445734800LL, 3600 }, /* 2015-10-25T01:00:00Z */
+ { 1459040400LL, 7200 }, /* 2016-03-27T01:00:00Z */
+ { 1477789200LL, 3600 }, /* 2016-10-30T01:00:00Z */
+ { 1490490000LL, 7200 }, /* 2017-03-26T01:00:00Z */
+ { 1509238800LL, 3600 }, /* 2017-10-29T01:00:00Z */
+ { 1521939600LL, 7200 }, /* 2018-03-25T01:00:00Z */
+ { 1540688400LL, 3600 }, /* 2018-10-28T01:00:00Z */
+ { 1553994000LL, 7200 }, /* 2019-03-31T01:00:00Z */
+ { 1572138000LL, 3600 }, /* 2019-10-27T01:00:00Z */
+ { 1585443600LL, 7200 }, /* 2020-03-29T01:00:00Z */
+ { 1603587600LL, 3600 }, /* 2020-10-25T01:00:00Z */
+ { 1616893200LL, 7200 }, /* 2021-03-28T01:00:00Z */
+ { 1635642000LL, 3600 }, /* 2021-10-31T01:00:00Z */
+ { 1648342800LL, 7200 }, /* 2022-03-27T01:00:00Z */
+ { 1667091600LL, 3600 }, /* 2022-10-30T01:00:00Z */
+ { 1679792400LL, 7200 }, /* 2023-03-26T01:00:00Z */
+ { 1698541200LL, 3600 }, /* 2023-10-29T01:00:00Z */
+ { 1711846800LL, 7200 }, /* 2024-03-31T01:00:00Z */
+ { 1729990800LL, 3600 }, /* 2024-10-27T01:00:00Z */
+ { 1743296400LL, 7200 }, /* 2025-03-30T01:00:00Z */
+ { 1761440400LL, 3600 }, /* 2025-10-26T01:00:00Z */
+ { 1774746000LL, 7200 }, /* 2026-03-29T01:00:00Z */
+ { 1792890000LL, 3600 }, /* 2026-10-25T01:00:00Z */
+ { 1806195600LL, 7200 }, /* 2027-03-28T01:00:00Z */
+ { 1824944400LL, 3600 }, /* 2027-10-31T01:00:00Z */
+ { 1837645200LL, 7200 }, /* 2028-03-26T01:00:00Z */
+ { 1856394000LL, 3600 }, /* 2028-10-29T01:00:00Z */
+ { 1869094800LL, 7200 }, /* 2029-03-25T01:00:00Z */
+ { 1887843600LL, 3600 }, /* 2029-10-28T01:00:00Z */
+ { 1901149200LL, 7200 }, /* 2030-03-31T01:00:00Z */
+ { 1919293200LL, 3600 }, /* 2030-10-27T01:00:00Z */
+ { 1932598800LL, 7200 }, /* 2031-03-30T01:00:00Z */
+ { 1950742800LL, 3600 }, /* 2031-10-26T01:00:00Z */
+ { 1964048400LL, 7200 }, /* 2032-03-28T01:00:00Z */
+ { 1982797200LL, 3600 }, /* 2032-10-31T01:00:00Z */
+ { 1995498000LL, 7200 }, /* 2033-03-27T01:00:00Z */
+ { 2014246800LL, 3600 }, /* 2033-10-30T01:00:00Z */
+ { 2026947600LL, 7200 }, /* 2034-03-26T01:00:00Z */
+ { 2045696400LL, 3600 }, /* 2034-10-29T01:00:00Z */
+ { 2058397200LL, 7200 }, /* 2035-03-25T01:00:00Z */
+ { 2077146000LL, 3600 }, /* 2035-10-28T01:00:00Z */
+ { 2090451600LL, 7200 }, /* 2036-03-30T01:00:00Z */
+ { 2108595600LL, 3600 }, /* 2036-10-26T01:00:00Z */
+ { 2121901200LL, 7200 }, /* 2037-03-29T01:00:00Z */
+ { 2140045200LL, 3600 }, /* 2037-10-25T01:00:00Z */
+};
+
+static const TZTransition tz_trans_Europe_London[] = {
+ { INT64_MIN, -75 }, /* before first transition */
+ { -3852662325LL, 0 }, /* 1847-12-01T00:01:15Z */
+ { -1691964000LL, 3600 }, /* 1916-05-21T02:00:00Z */
+ { -1680472800LL, 0 }, /* 1916-10-01T02:00:00Z */
+ { -1664143200LL, 3600 }, /* 1917-04-08T02:00:00Z */
+ { -1650146400LL, 0 }, /* 1917-09-17T02:00:00Z */
+ { -1633903200LL, 3600 }, /* 1918-03-24T02:00:00Z */
+ { -1617487200LL, 0 }, /* 1918-09-30T02:00:00Z */
+ { -1601848800LL, 3600 }, /* 1919-03-30T02:00:00Z */
+ { -1586037600LL, 0 }, /* 1919-09-29T02:00:00Z */
+ { -1570399200LL, 3600 }, /* 1920-03-28T02:00:00Z */
+ { -1552168800LL, 0 }, /* 1920-10-25T02:00:00Z */
+ { -1538344800LL, 3600 }, /* 1921-04-03T02:00:00Z */
+ { -1522533600LL, 0 }, /* 1921-10-03T02:00:00Z */
+ { -1507500000LL, 3600 }, /* 1922-03-26T02:00:00Z */
+ { -1490565600LL, 0 }, /* 1922-10-08T02:00:00Z */
+ { -1473631200LL, 3600 }, /* 1923-04-22T02:00:00Z */
+ { -1460930400LL, 0 }, /* 1923-09-16T02:00:00Z */
+ { -1442786400LL, 3600 }, /* 1924-04-13T02:00:00Z */
+ { -1428876000LL, 0 }, /* 1924-09-21T02:00:00Z */
+ { -1410732000LL, 3600 }, /* 1925-04-19T02:00:00Z */
+ { -1396216800LL, 0 }, /* 1925-10-04T02:00:00Z */
+ { -1379282400LL, 3600 }, /* 1926-04-18T02:00:00Z */
+ { -1364767200LL, 0 }, /* 1926-10-03T02:00:00Z */
+ { -1348437600LL, 3600 }, /* 1927-04-10T02:00:00Z */
+ { -1333317600LL, 0 }, /* 1927-10-02T02:00:00Z */
+ { -1315778400LL, 3600 }, /* 1928-04-22T02:00:00Z */
+ { -1301263200LL, 0 }, /* 1928-10-07T02:00:00Z */
+ { -1284328800LL, 3600 }, /* 1929-04-21T02:00:00Z */
+ { -1269813600LL, 0 }, /* 1929-10-06T02:00:00Z */
+ { -1253484000LL, 3600 }, /* 1930-04-13T02:00:00Z */
+ { -1238364000LL, 0 }, /* 1930-10-05T02:00:00Z */
+ { -1221429600LL, 3600 }, /* 1931-04-19T02:00:00Z */
+ { -1206914400LL, 0 }, /* 1931-10-04T02:00:00Z */
+ { -1189980000LL, 3600 }, /* 1932-04-17T02:00:00Z */
+ { -1175464800LL, 0 }, /* 1932-10-02T02:00:00Z */
+ { -1159135200LL, 3600 }, /* 1933-04-09T02:00:00Z */
+ { -1143410400LL, 0 }, /* 1933-10-08T02:00:00Z */
+ { -1126476000LL, 3600 }, /* 1934-04-22T02:00:00Z */
+ { -1111960800LL, 0 }, /* 1934-10-07T02:00:00Z */
+ { -1095631200LL, 3600 }, /* 1935-04-14T02:00:00Z */
+ { -1080511200LL, 0 }, /* 1935-10-06T02:00:00Z */
+ { -1063576800LL, 3600 }, /* 1936-04-19T02:00:00Z */
+ { -1049061600LL, 0 }, /* 1936-10-04T02:00:00Z */
+ { -1032127200LL, 3600 }, /* 1937-04-18T02:00:00Z */
+ { -1017612000LL, 0 }, /* 1937-10-03T02:00:00Z */
+ { -1001282400LL, 3600 }, /* 1938-04-10T02:00:00Z */
+ { -986162400LL, 0 }, /* 1938-10-02T02:00:00Z */
+ { -969228000LL, 3600 }, /* 1939-04-16T02:00:00Z */
+ { -950479200LL, 0 }, /* 1939-11-19T02:00:00Z */
+ { -942012000LL, 3600 }, /* 1940-02-25T02:00:00Z */
+ { -904518000LL, 7200 }, /* 1941-05-04T01:00:00Z */
+ { -896050800LL, 3600 }, /* 1941-08-10T01:00:00Z */
+ { -875487600LL, 7200 }, /* 1942-04-05T01:00:00Z */
+ { -864601200LL, 3600 }, /* 1942-08-09T01:00:00Z */
+ { -844038000LL, 7200 }, /* 1943-04-04T01:00:00Z */
+ { -832546800LL, 3600 }, /* 1943-08-15T01:00:00Z */
+ { -812588400LL, 7200 }, /* 1944-04-02T01:00:00Z */
+ { -798073200LL, 3600 }, /* 1944-09-17T01:00:00Z */
+ { -781052400LL, 7200 }, /* 1945-04-02T01:00:00Z */
+ { -772066800LL, 3600 }, /* 1945-07-15T01:00:00Z */
+ { -764805600LL, 0 }, /* 1945-10-07T02:00:00Z */
+ { -748476000LL, 3600 }, /* 1946-04-14T02:00:00Z */
+ { -733356000LL, 0 }, /* 1946-10-06T02:00:00Z */
+ { -719445600LL, 3600 }, /* 1947-03-16T02:00:00Z */
+ { -717030000LL, 7200 }, /* 1947-04-13T01:00:00Z */
+ { -706748400LL, 3600 }, /* 1947-08-10T01:00:00Z */
+ { -699487200LL, 0 }, /* 1947-11-02T02:00:00Z */
+ { -687996000LL, 3600 }, /* 1948-03-14T02:00:00Z */
+ { -668037600LL, 0 }, /* 1948-10-31T02:00:00Z */
+ { -654732000LL, 3600 }, /* 1949-04-03T02:00:00Z */
+ { -636588000LL, 0 }, /* 1949-10-30T02:00:00Z */
+ { -622072800LL, 3600 }, /* 1950-04-16T02:00:00Z */
+ { -605743200LL, 0 }, /* 1950-10-22T02:00:00Z */
+ { -590623200LL, 3600 }, /* 1951-04-15T02:00:00Z */
+ { -574293600LL, 0 }, /* 1951-10-21T02:00:00Z */
+ { -558568800LL, 3600 }, /* 1952-04-20T02:00:00Z */
+ { -542239200LL, 0 }, /* 1952-10-26T02:00:00Z */
+ { -527119200LL, 3600 }, /* 1953-04-19T02:00:00Z */
+ { -512604000LL, 0 }, /* 1953-10-04T02:00:00Z */
+ { -496274400LL, 3600 }, /* 1954-04-11T02:00:00Z */
+ { -481154400LL, 0 }, /* 1954-10-03T02:00:00Z */
+ { -464220000LL, 3600 }, /* 1955-04-17T02:00:00Z */
+ { -449704800LL, 0 }, /* 1955-10-02T02:00:00Z */
+ { -432165600LL, 3600 }, /* 1956-04-22T02:00:00Z */
+ { -417650400LL, 0 }, /* 1956-10-07T02:00:00Z */
+ { -401320800LL, 3600 }, /* 1957-04-14T02:00:00Z */
+ { -386200800LL, 0 }, /* 1957-10-06T02:00:00Z */
+ { -369266400LL, 3600 }, /* 1958-04-20T02:00:00Z */
+ { -354751200LL, 0 }, /* 1958-10-05T02:00:00Z */
+ { -337816800LL, 3600 }, /* 1959-04-19T02:00:00Z */
+ { -323301600LL, 0 }, /* 1959-10-04T02:00:00Z */
+ { -306972000LL, 3600 }, /* 1960-04-10T02:00:00Z */
+ { -291852000LL, 0 }, /* 1960-10-02T02:00:00Z */
+ { -276732000LL, 3600 }, /* 1961-03-26T02:00:00Z */
+ { -257983200LL, 0 }, /* 1961-10-29T02:00:00Z */
+ { -245282400LL, 3600 }, /* 1962-03-25T02:00:00Z */
+ { -226533600LL, 0 }, /* 1962-10-28T02:00:00Z */
+ { -213228000LL, 3600 }, /* 1963-03-31T02:00:00Z */
+ { -195084000LL, 0 }, /* 1963-10-27T02:00:00Z */
+ { -182383200LL, 3600 }, /* 1964-03-22T02:00:00Z */
+ { -163634400LL, 0 }, /* 1964-10-25T02:00:00Z */
+ { -150933600LL, 3600 }, /* 1965-03-21T02:00:00Z */
+ { -132184800LL, 0 }, /* 1965-10-24T02:00:00Z */
+ { -119484000LL, 3600 }, /* 1966-03-20T02:00:00Z */
+ { -100735200LL, 0 }, /* 1966-10-23T02:00:00Z */
+ { -88034400LL, 3600 }, /* 1967-03-19T02:00:00Z */
+ { -68680800LL, 0 }, /* 1967-10-29T02:00:00Z */
+ { -59004000LL, 3600 }, /* 1968-02-18T02:00:00Z */
+ { -37242000LL, 3600 }, /* 1968-10-26T23:00:00Z */
+ { 57722400LL, 0 }, /* 1971-10-31T02:00:00Z */
+ { 69818400LL, 3600 }, /* 1972-03-19T02:00:00Z */
+ { 89172000LL, 0 }, /* 1972-10-29T02:00:00Z */
+ { 101268000LL, 3600 }, /* 1973-03-18T02:00:00Z */
+ { 120621600LL, 0 }, /* 1973-10-28T02:00:00Z */
+ { 132717600LL, 3600 }, /* 1974-03-17T02:00:00Z */
+ { 152071200LL, 0 }, /* 1974-10-27T02:00:00Z */
+ { 164167200LL, 3600 }, /* 1975-03-16T02:00:00Z */
+ { 183520800LL, 0 }, /* 1975-10-26T02:00:00Z */
+ { 196221600LL, 3600 }, /* 1976-03-21T02:00:00Z */
+ { 214970400LL, 0 }, /* 1976-10-24T02:00:00Z */
+ { 227671200LL, 3600 }, /* 1977-03-20T02:00:00Z */
+ { 246420000LL, 0 }, /* 1977-10-23T02:00:00Z */
+ { 259120800LL, 3600 }, /* 1978-03-19T02:00:00Z */
+ { 278474400LL, 0 }, /* 1978-10-29T02:00:00Z */
+ { 290570400LL, 3600 }, /* 1979-03-18T02:00:00Z */
+ { 309924000LL, 0 }, /* 1979-10-28T02:00:00Z */
+ { 322020000LL, 3600 }, /* 1980-03-16T02:00:00Z */
+ { 341373600LL, 0 }, /* 1980-10-26T02:00:00Z */
+ { 354675600LL, 3600 }, /* 1981-03-29T01:00:00Z */
+ { 372819600LL, 0 }, /* 1981-10-25T01:00:00Z */
+ { 386125200LL, 3600 }, /* 1982-03-28T01:00:00Z */
+ { 404269200LL, 0 }, /* 1982-10-24T01:00:00Z */
+ { 417574800LL, 3600 }, /* 1983-03-27T01:00:00Z */
+ { 435718800LL, 0 }, /* 1983-10-23T01:00:00Z */
+ { 449024400LL, 3600 }, /* 1984-03-25T01:00:00Z */
+ { 467773200LL, 0 }, /* 1984-10-28T01:00:00Z */
+ { 481078800LL, 3600 }, /* 1985-03-31T01:00:00Z */
+ { 499222800LL, 0 }, /* 1985-10-27T01:00:00Z */
+ { 512528400LL, 3600 }, /* 1986-03-30T01:00:00Z */
+ { 530672400LL, 0 }, /* 1986-10-26T01:00:00Z */
+ { 543978000LL, 3600 }, /* 1987-03-29T01:00:00Z */
+ { 562122000LL, 0 }, /* 1987-10-25T01:00:00Z */
+ { 575427600LL, 3600 }, /* 1988-03-27T01:00:00Z */
+ { 593571600LL, 0 }, /* 1988-10-23T01:00:00Z */
+ { 606877200LL, 3600 }, /* 1989-03-26T01:00:00Z */
+ { 625626000LL, 0 }, /* 1989-10-29T01:00:00Z */
+ { 638326800LL, 3600 }, /* 1990-03-25T01:00:00Z */
+ { 657075600LL, 0 }, /* 1990-10-28T01:00:00Z */
+ { 670381200LL, 3600 }, /* 1991-03-31T01:00:00Z */
+ { 688525200LL, 0 }, /* 1991-10-27T01:00:00Z */
+ { 701830800LL, 3600 }, /* 1992-03-29T01:00:00Z */
+ { 719974800LL, 0 }, /* 1992-10-25T01:00:00Z */
+ { 733280400LL, 3600 }, /* 1993-03-28T01:00:00Z */
+ { 751424400LL, 0 }, /* 1993-10-24T01:00:00Z */
+ { 764730000LL, 3600 }, /* 1994-03-27T01:00:00Z */
+ { 782874000LL, 0 }, /* 1994-10-23T01:00:00Z */
+ { 796179600LL, 3600 }, /* 1995-03-26T01:00:00Z */
+ { 814323600LL, 0 }, /* 1995-10-22T01:00:00Z */
+ { 828234000LL, 3600 }, /* 1996-03-31T01:00:00Z */
+ { 846378000LL, 0 }, /* 1996-10-27T01:00:00Z */
+ { 859683600LL, 3600 }, /* 1997-03-30T01:00:00Z */
+ { 877827600LL, 0 }, /* 1997-10-26T01:00:00Z */
+ { 891133200LL, 3600 }, /* 1998-03-29T01:00:00Z */
+ { 909277200LL, 0 }, /* 1998-10-25T01:00:00Z */
+ { 922582800LL, 3600 }, /* 1999-03-28T01:00:00Z */
+ { 941331600LL, 0 }, /* 1999-10-31T01:00:00Z */
+ { 954032400LL, 3600 }, /* 2000-03-26T01:00:00Z */
+ { 972781200LL, 0 }, /* 2000-10-29T01:00:00Z */
+ { 985482000LL, 3600 }, /* 2001-03-25T01:00:00Z */
+ { 1004230800LL, 0 }, /* 2001-10-28T01:00:00Z */
+ { 1017536400LL, 3600 }, /* 2002-03-31T01:00:00Z */
+ { 1035680400LL, 0 }, /* 2002-10-27T01:00:00Z */
+ { 1048986000LL, 3600 }, /* 2003-03-30T01:00:00Z */
+ { 1067130000LL, 0 }, /* 2003-10-26T01:00:00Z */
+ { 1080435600LL, 3600 }, /* 2004-03-28T01:00:00Z */
+ { 1099184400LL, 0 }, /* 2004-10-31T01:00:00Z */
+ { 1111885200LL, 3600 }, /* 2005-03-27T01:00:00Z */
+ { 1130634000LL, 0 }, /* 2005-10-30T01:00:00Z */
+ { 1143334800LL, 3600 }, /* 2006-03-26T01:00:00Z */
+ { 1162083600LL, 0 }, /* 2006-10-29T01:00:00Z */
+ { 1174784400LL, 3600 }, /* 2007-03-25T01:00:00Z */
+ { 1193533200LL, 0 }, /* 2007-10-28T01:00:00Z */
+ { 1206838800LL, 3600 }, /* 2008-03-30T01:00:00Z */
+ { 1224982800LL, 0 }, /* 2008-10-26T01:00:00Z */
+ { 1238288400LL, 3600 }, /* 2009-03-29T01:00:00Z */
+ { 1256432400LL, 0 }, /* 2009-10-25T01:00:00Z */
+ { 1269738000LL, 3600 }, /* 2010-03-28T01:00:00Z */
+ { 1288486800LL, 0 }, /* 2010-10-31T01:00:00Z */
+ { 1301187600LL, 3600 }, /* 2011-03-27T01:00:00Z */
+ { 1319936400LL, 0 }, /* 2011-10-30T01:00:00Z */
+ { 1332637200LL, 3600 }, /* 2012-03-25T01:00:00Z */
+ { 1351386000LL, 0 }, /* 2012-10-28T01:00:00Z */
+ { 1364691600LL, 3600 }, /* 2013-03-31T01:00:00Z */
+ { 1382835600LL, 0 }, /* 2013-10-27T01:00:00Z */
+ { 1396141200LL, 3600 }, /* 2014-03-30T01:00:00Z */
+ { 1414285200LL, 0 }, /* 2014-10-26T01:00:00Z */
+ { 1427590800LL, 3600 }, /* 2015-03-29T01:00:00Z */
+ { 1445734800LL, 0 }, /* 2015-10-25T01:00:00Z */
+ { 1459040400LL, 3600 }, /* 2016-03-27T01:00:00Z */
+ { 1477789200LL, 0 }, /* 2016-10-30T01:00:00Z */
+ { 1490490000LL, 3600 }, /* 2017-03-26T01:00:00Z */
+ { 1509238800LL, 0 }, /* 2017-10-29T01:00:00Z */
+ { 1521939600LL, 3600 }, /* 2018-03-25T01:00:00Z */
+ { 1540688400LL, 0 }, /* 2018-10-28T01:00:00Z */
+ { 1553994000LL, 3600 }, /* 2019-03-31T01:00:00Z */
+ { 1572138000LL, 0 }, /* 2019-10-27T01:00:00Z */
+ { 1585443600LL, 3600 }, /* 2020-03-29T01:00:00Z */
+ { 1603587600LL, 0 }, /* 2020-10-25T01:00:00Z */
+ { 1616893200LL, 3600 }, /* 2021-03-28T01:00:00Z */
+ { 1635642000LL, 0 }, /* 2021-10-31T01:00:00Z */
+ { 1648342800LL, 3600 }, /* 2022-03-27T01:00:00Z */
+ { 1667091600LL, 0 }, /* 2022-10-30T01:00:00Z */
+ { 1679792400LL, 3600 }, /* 2023-03-26T01:00:00Z */
+ { 1698541200LL, 0 }, /* 2023-10-29T01:00:00Z */
+ { 1711846800LL, 3600 }, /* 2024-03-31T01:00:00Z */
+ { 1729990800LL, 0 }, /* 2024-10-27T01:00:00Z */
+ { 1743296400LL, 3600 }, /* 2025-03-30T01:00:00Z */
+ { 1761440400LL, 0 }, /* 2025-10-26T01:00:00Z */
+ { 1774746000LL, 3600 }, /* 2026-03-29T01:00:00Z */
+ { 1792890000LL, 0 }, /* 2026-10-25T01:00:00Z */
+ { 1806195600LL, 3600 }, /* 2027-03-28T01:00:00Z */
+ { 1824944400LL, 0 }, /* 2027-10-31T01:00:00Z */
+ { 1837645200LL, 3600 }, /* 2028-03-26T01:00:00Z */
+ { 1856394000LL, 0 }, /* 2028-10-29T01:00:00Z */
+ { 1869094800LL, 3600 }, /* 2029-03-25T01:00:00Z */
+ { 1887843600LL, 0 }, /* 2029-10-28T01:00:00Z */
+ { 1901149200LL, 3600 }, /* 2030-03-31T01:00:00Z */
+ { 1919293200LL, 0 }, /* 2030-10-27T01:00:00Z */
+ { 1932598800LL, 3600 }, /* 2031-03-30T01:00:00Z */
+ { 1950742800LL, 0 }, /* 2031-10-26T01:00:00Z */
+ { 1964048400LL, 3600 }, /* 2032-03-28T01:00:00Z */
+ { 1982797200LL, 0 }, /* 2032-10-31T01:00:00Z */
+ { 1995498000LL, 3600 }, /* 2033-03-27T01:00:00Z */
+ { 2014246800LL, 0 }, /* 2033-10-30T01:00:00Z */
+ { 2026947600LL, 3600 }, /* 2034-03-26T01:00:00Z */
+ { 2045696400LL, 0 }, /* 2034-10-29T01:00:00Z */
+ { 2058397200LL, 3600 }, /* 2035-03-25T01:00:00Z */
+ { 2077146000LL, 0 }, /* 2035-10-28T01:00:00Z */
+ { 2090451600LL, 3600 }, /* 2036-03-30T01:00:00Z */
+ { 2108595600LL, 0 }, /* 2036-10-26T01:00:00Z */
+ { 2121901200LL, 3600 }, /* 2037-03-29T01:00:00Z */
+ { 2140045200LL, 0 }, /* 2037-10-25T01:00:00Z */
+};
+
+static const TZTransition tz_trans_Europe_Moscow[] = {
+ { INT64_MIN, 9017 }, /* before first transition */
+ { -2840149817LL, 9017 }, /* 1879-12-31T21:29:43Z */
+ { -1688265017LL, 9079 }, /* 1916-07-02T21:29:43Z */
+ { -1656819079LL, 12679 }, /* 1917-07-01T20:28:41Z */
+ { -1641353479LL, 9079 }, /* 1917-12-27T20:28:41Z */
+ { -1627965079LL, 16279 }, /* 1918-05-31T19:28:41Z */
+ { -1618716679LL, 12679 }, /* 1918-09-15T20:28:41Z */
+ { -1596429079LL, 16279 }, /* 1919-05-31T19:28:41Z */
+ { -1593820800LL, 14400 }, /* 1919-07-01T00:00:00Z */
+ { -1589860800LL, 10800 }, /* 1919-08-15T20:00:00Z */
+ { -1542427200LL, 14400 }, /* 1921-02-14T20:00:00Z */
+ { -1539493200LL, 18000 }, /* 1921-03-20T19:00:00Z */
+ { -1525323600LL, 14400 }, /* 1921-08-31T19:00:00Z */
+ { -1522728000LL, 10800 }, /* 1921-09-30T20:00:00Z */
+ { -1491188400LL, 7200 }, /* 1922-09-30T21:00:00Z */
+ { -1247536800LL, 10800 }, /* 1930-06-20T22:00:00Z */
+ { 354920400LL, 14400 }, /* 1981-03-31T21:00:00Z */
+ { 370728000LL, 10800 }, /* 1981-09-30T20:00:00Z */
+ { 386456400LL, 14400 }, /* 1982-03-31T21:00:00Z */
+ { 402264000LL, 10800 }, /* 1982-09-30T20:00:00Z */
+ { 417992400LL, 14400 }, /* 1983-03-31T21:00:00Z */
+ { 433800000LL, 10800 }, /* 1983-09-30T20:00:00Z */
+ { 449614800LL, 14400 }, /* 1984-03-31T21:00:00Z */
+ { 465346800LL, 10800 }, /* 1984-09-29T23:00:00Z */
+ { 481071600LL, 14400 }, /* 1985-03-30T23:00:00Z */
+ { 496796400LL, 10800 }, /* 1985-09-28T23:00:00Z */
+ { 512521200LL, 14400 }, /* 1986-03-29T23:00:00Z */
+ { 528246000LL, 10800 }, /* 1986-09-27T23:00:00Z */
+ { 543970800LL, 14400 }, /* 1987-03-28T23:00:00Z */
+ { 559695600LL, 10800 }, /* 1987-09-26T23:00:00Z */
+ { 575420400LL, 14400 }, /* 1988-03-26T23:00:00Z */
+ { 591145200LL, 10800 }, /* 1988-09-24T23:00:00Z */
+ { 606870000LL, 14400 }, /* 1989-03-25T23:00:00Z */
+ { 622594800LL, 10800 }, /* 1989-09-23T23:00:00Z */
+ { 638319600LL, 14400 }, /* 1990-03-24T23:00:00Z */
+ { 654649200LL, 10800 }, /* 1990-09-29T23:00:00Z */
+ { 670374000LL, 10800 }, /* 1991-03-30T23:00:00Z */
+ { 686102400LL, 7200 }, /* 1991-09-29T00:00:00Z */
+ { 695779200LL, 10800 }, /* 1992-01-19T00:00:00Z */
+ { 701823600LL, 14400 }, /* 1992-03-28T23:00:00Z */
+ { 717548400LL, 10800 }, /* 1992-09-26T23:00:00Z */
+ { 733273200LL, 14400 }, /* 1993-03-27T23:00:00Z */
+ { 748998000LL, 10800 }, /* 1993-09-25T23:00:00Z */
+ { 764722800LL, 14400 }, /* 1994-03-26T23:00:00Z */
+ { 780447600LL, 10800 }, /* 1994-09-24T23:00:00Z */
+ { 796172400LL, 14400 }, /* 1995-03-25T23:00:00Z */
+ { 811897200LL, 10800 }, /* 1995-09-23T23:00:00Z */
+ { 828226800LL, 14400 }, /* 1996-03-30T23:00:00Z */
+ { 846370800LL, 10800 }, /* 1996-10-26T23:00:00Z */
+ { 859676400LL, 14400 }, /* 1997-03-29T23:00:00Z */
+ { 877820400LL, 10800 }, /* 1997-10-25T23:00:00Z */
+ { 891126000LL, 14400 }, /* 1998-03-28T23:00:00Z */
+ { 909270000LL, 10800 }, /* 1998-10-24T23:00:00Z */
+ { 922575600LL, 14400 }, /* 1999-03-27T23:00:00Z */
+ { 941324400LL, 10800 }, /* 1999-10-30T23:00:00Z */
+ { 954025200LL, 14400 }, /* 2000-03-25T23:00:00Z */
+ { 972774000LL, 10800 }, /* 2000-10-28T23:00:00Z */
+ { 985474800LL, 14400 }, /* 2001-03-24T23:00:00Z */
+ { 1004223600LL, 10800 }, /* 2001-10-27T23:00:00Z */
+ { 1017529200LL, 14400 }, /* 2002-03-30T23:00:00Z */
+ { 1035673200LL, 10800 }, /* 2002-10-26T23:00:00Z */
+ { 1048978800LL, 14400 }, /* 2003-03-29T23:00:00Z */
+ { 1067122800LL, 10800 }, /* 2003-10-25T23:00:00Z */
+ { 1080428400LL, 14400 }, /* 2004-03-27T23:00:00Z */
+ { 1099177200LL, 10800 }, /* 2004-10-30T23:00:00Z */
+ { 1111878000LL, 14400 }, /* 2005-03-26T23:00:00Z */
+ { 1130626800LL, 10800 }, /* 2005-10-29T23:00:00Z */
+ { 1143327600LL, 14400 }, /* 2006-03-25T23:00:00Z */
+ { 1162076400LL, 10800 }, /* 2006-10-28T23:00:00Z */
+ { 1174777200LL, 14400 }, /* 2007-03-24T23:00:00Z */
+ { 1193526000LL, 10800 }, /* 2007-10-27T23:00:00Z */
+ { 1206831600LL, 14400 }, /* 2008-03-29T23:00:00Z */
+ { 1224975600LL, 10800 }, /* 2008-10-25T23:00:00Z */
+ { 1238281200LL, 14400 }, /* 2009-03-28T23:00:00Z */
+ { 1256425200LL, 10800 }, /* 2009-10-24T23:00:00Z */
+ { 1269730800LL, 14400 }, /* 2010-03-27T23:00:00Z */
+ { 1288479600LL, 10800 }, /* 2010-10-30T23:00:00Z */
+ { 1301180400LL, 14400 }, /* 2011-03-26T23:00:00Z */
+ { 1414274400LL, 10800 }, /* 2014-10-25T22:00:00Z */
+};
+
+static const TZTransition tz_trans_Europe_Paris[] = {
+ { INT64_MIN, 561 }, /* before first transition */
+ { -2486592561LL, 561 }, /* 1891-03-15T23:50:39Z */
+ { -1855958961LL, 0 }, /* 1911-03-10T23:50:39Z */
+ { -1689814800LL, 3600 }, /* 1916-06-14T23:00:00Z */
+ { -1680397200LL, 0 }, /* 1916-10-01T23:00:00Z */
+ { -1665363600LL, 3600 }, /* 1917-03-24T23:00:00Z */
+ { -1648342800LL, 0 }, /* 1917-10-07T23:00:00Z */
+ { -1635123600LL, 3600 }, /* 1918-03-09T23:00:00Z */
+ { -1616893200LL, 0 }, /* 1918-10-06T23:00:00Z */
+ { -1604278800LL, 3600 }, /* 1919-03-01T23:00:00Z */
+ { -1585443600LL, 0 }, /* 1919-10-05T23:00:00Z */
+ { -1574038800LL, 3600 }, /* 1920-02-14T23:00:00Z */
+ { -1552266000LL, 0 }, /* 1920-10-23T23:00:00Z */
+ { -1539997200LL, 3600 }, /* 1921-03-14T23:00:00Z */
+ { -1520557200LL, 0 }, /* 1921-10-25T23:00:00Z */
+ { -1507510800LL, 3600 }, /* 1922-03-25T23:00:00Z */
+ { -1490576400LL, 0 }, /* 1922-10-07T23:00:00Z */
+ { -1470618000LL, 3600 }, /* 1923-05-26T23:00:00Z */
+ { -1459126800LL, 0 }, /* 1923-10-06T23:00:00Z */
+ { -1444006800LL, 3600 }, /* 1924-03-29T23:00:00Z */
+ { -1427677200LL, 0 }, /* 1924-10-04T23:00:00Z */
+ { -1411952400LL, 3600 }, /* 1925-04-04T23:00:00Z */
+ { -1396227600LL, 0 }, /* 1925-10-03T23:00:00Z */
+ { -1379293200LL, 3600 }, /* 1926-04-17T23:00:00Z */
+ { -1364778000LL, 0 }, /* 1926-10-02T23:00:00Z */
+ { -1348448400LL, 3600 }, /* 1927-04-09T23:00:00Z */
+ { -1333328400LL, 0 }, /* 1927-10-01T23:00:00Z */
+ { -1316394000LL, 3600 }, /* 1928-04-14T23:00:00Z */
+ { -1301274000LL, 0 }, /* 1928-10-06T23:00:00Z */
+ { -1284339600LL, 3600 }, /* 1929-04-20T23:00:00Z */
+ { -1269824400LL, 0 }, /* 1929-10-05T23:00:00Z */
+ { -1253494800LL, 3600 }, /* 1930-04-12T23:00:00Z */
+ { -1238374800LL, 0 }, /* 1930-10-04T23:00:00Z */
+ { -1221440400LL, 3600 }, /* 1931-04-18T23:00:00Z */
+ { -1206925200LL, 0 }, /* 1931-10-03T23:00:00Z */
+ { -1191200400LL, 3600 }, /* 1932-04-02T23:00:00Z */
+ { -1175475600LL, 0 }, /* 1932-10-01T23:00:00Z */
+ { -1160355600LL, 3600 }, /* 1933-03-25T23:00:00Z */
+ { -1143421200LL, 0 }, /* 1933-10-07T23:00:00Z */
+ { -1127696400LL, 3600 }, /* 1934-04-07T23:00:00Z */
+ { -1111971600LL, 0 }, /* 1934-10-06T23:00:00Z */
+ { -1096851600LL, 3600 }, /* 1935-03-30T23:00:00Z */
+ { -1080522000LL, 0 }, /* 1935-10-05T23:00:00Z */
+ { -1063587600LL, 3600 }, /* 1936-04-18T23:00:00Z */
+ { -1049072400LL, 0 }, /* 1936-10-03T23:00:00Z */
+ { -1033347600LL, 3600 }, /* 1937-04-03T23:00:00Z */
+ { -1017622800LL, 0 }, /* 1937-10-02T23:00:00Z */
+ { -1002502800LL, 3600 }, /* 1938-03-26T23:00:00Z */
+ { -986173200LL, 0 }, /* 1938-10-01T23:00:00Z */
+ { -969238800LL, 3600 }, /* 1939-04-15T23:00:00Z */
+ { -950490000LL, 0 }, /* 1939-11-18T23:00:00Z */
+ { -942012000LL, 3600 }, /* 1940-02-25T02:00:00Z */
+ { -932436000LL, 7200 }, /* 1940-06-14T22:00:00Z */
+ { -857257200LL, 3600 }, /* 1942-11-02T01:00:00Z */
+ { -844556400LL, 7200 }, /* 1943-03-29T01:00:00Z */
+ { -828226800LL, 3600 }, /* 1943-10-04T01:00:00Z */
+ { -812502000LL, 7200 }, /* 1944-04-03T01:00:00Z */
+ { -800071200LL, 7200 }, /* 1944-08-24T22:00:00Z */
+ { -796266000LL, 3600 }, /* 1944-10-07T23:00:00Z */
+ { -781052400LL, 7200 }, /* 1945-04-02T01:00:00Z */
+ { -766623600LL, 3600 }, /* 1945-09-16T01:00:00Z */
+ { 196819200LL, 7200 }, /* 1976-03-28T00:00:00Z */
+ { 212540400LL, 3600 }, /* 1976-09-25T23:00:00Z */
+ { 228877200LL, 7200 }, /* 1977-04-03T01:00:00Z */
+ { 243997200LL, 3600 }, /* 1977-09-25T01:00:00Z */
+ { 260326800LL, 7200 }, /* 1978-04-02T01:00:00Z */
+ { 276051600LL, 3600 }, /* 1978-10-01T01:00:00Z */
+ { 291776400LL, 7200 }, /* 1979-04-01T01:00:00Z */
+ { 307501200LL, 3600 }, /* 1979-09-30T01:00:00Z */
+ { 323830800LL, 7200 }, /* 1980-04-06T01:00:00Z */
+ { 338950800LL, 3600 }, /* 1980-09-28T01:00:00Z */
+ { 354675600LL, 7200 }, /* 1981-03-29T01:00:00Z */
+ { 370400400LL, 3600 }, /* 1981-09-27T01:00:00Z */
+ { 386125200LL, 7200 }, /* 1982-03-28T01:00:00Z */
+ { 401850000LL, 3600 }, /* 1982-09-26T01:00:00Z */
+ { 417574800LL, 7200 }, /* 1983-03-27T01:00:00Z */
+ { 433299600LL, 3600 }, /* 1983-09-25T01:00:00Z */
+ { 449024400LL, 7200 }, /* 1984-03-25T01:00:00Z */
+ { 465354000LL, 3600 }, /* 1984-09-30T01:00:00Z */
+ { 481078800LL, 7200 }, /* 1985-03-31T01:00:00Z */
+ { 496803600LL, 3600 }, /* 1985-09-29T01:00:00Z */
+ { 512528400LL, 7200 }, /* 1986-03-30T01:00:00Z */
+ { 528253200LL, 3600 }, /* 1986-09-28T01:00:00Z */
+ { 543978000LL, 7200 }, /* 1987-03-29T01:00:00Z */
+ { 559702800LL, 3600 }, /* 1987-09-27T01:00:00Z */
+ { 575427600LL, 7200 }, /* 1988-03-27T01:00:00Z */
+ { 591152400LL, 3600 }, /* 1988-09-25T01:00:00Z */
+ { 606877200LL, 7200 }, /* 1989-03-26T01:00:00Z */
+ { 622602000LL, 3600 }, /* 1989-09-24T01:00:00Z */
+ { 638326800LL, 7200 }, /* 1990-03-25T01:00:00Z */
+ { 654656400LL, 3600 }, /* 1990-09-30T01:00:00Z */
+ { 670381200LL, 7200 }, /* 1991-03-31T01:00:00Z */
+ { 686106000LL, 3600 }, /* 1991-09-29T01:00:00Z */
+ { 701830800LL, 7200 }, /* 1992-03-29T01:00:00Z */
+ { 717555600LL, 3600 }, /* 1992-09-27T01:00:00Z */
+ { 733280400LL, 7200 }, /* 1993-03-28T01:00:00Z */
+ { 749005200LL, 3600 }, /* 1993-09-26T01:00:00Z */
+ { 764730000LL, 7200 }, /* 1994-03-27T01:00:00Z */
+ { 780454800LL, 3600 }, /* 1994-09-25T01:00:00Z */
+ { 796179600LL, 7200 }, /* 1995-03-26T01:00:00Z */
+ { 811904400LL, 3600 }, /* 1995-09-24T01:00:00Z */
+ { 828234000LL, 7200 }, /* 1996-03-31T01:00:00Z */
+ { 846378000LL, 3600 }, /* 1996-10-27T01:00:00Z */
+ { 859683600LL, 7200 }, /* 1997-03-30T01:00:00Z */
+ { 877827600LL, 3600 }, /* 1997-10-26T01:00:00Z */
+ { 891133200LL, 7200 }, /* 1998-03-29T01:00:00Z */
+ { 909277200LL, 3600 }, /* 1998-10-25T01:00:00Z */
+ { 922582800LL, 7200 }, /* 1999-03-28T01:00:00Z */
+ { 941331600LL, 3600 }, /* 1999-10-31T01:00:00Z */
+ { 954032400LL, 7200 }, /* 2000-03-26T01:00:00Z */
+ { 972781200LL, 3600 }, /* 2000-10-29T01:00:00Z */
+ { 985482000LL, 7200 }, /* 2001-03-25T01:00:00Z */
+ { 1004230800LL, 3600 }, /* 2001-10-28T01:00:00Z */
+ { 1017536400LL, 7200 }, /* 2002-03-31T01:00:00Z */
+ { 1035680400LL, 3600 }, /* 2002-10-27T01:00:00Z */
+ { 1048986000LL, 7200 }, /* 2003-03-30T01:00:00Z */
+ { 1067130000LL, 3600 }, /* 2003-10-26T01:00:00Z */
+ { 1080435600LL, 7200 }, /* 2004-03-28T01:00:00Z */
+ { 1099184400LL, 3600 }, /* 2004-10-31T01:00:00Z */
+ { 1111885200LL, 7200 }, /* 2005-03-27T01:00:00Z */
+ { 1130634000LL, 3600 }, /* 2005-10-30T01:00:00Z */
+ { 1143334800LL, 7200 }, /* 2006-03-26T01:00:00Z */
+ { 1162083600LL, 3600 }, /* 2006-10-29T01:00:00Z */
+ { 1174784400LL, 7200 }, /* 2007-03-25T01:00:00Z */
+ { 1193533200LL, 3600 }, /* 2007-10-28T01:00:00Z */
+ { 1206838800LL, 7200 }, /* 2008-03-30T01:00:00Z */
+ { 1224982800LL, 3600 }, /* 2008-10-26T01:00:00Z */
+ { 1238288400LL, 7200 }, /* 2009-03-29T01:00:00Z */
+ { 1256432400LL, 3600 }, /* 2009-10-25T01:00:00Z */
+ { 1269738000LL, 7200 }, /* 2010-03-28T01:00:00Z */
+ { 1288486800LL, 3600 }, /* 2010-10-31T01:00:00Z */
+ { 1301187600LL, 7200 }, /* 2011-03-27T01:00:00Z */
+ { 1319936400LL, 3600 }, /* 2011-10-30T01:00:00Z */
+ { 1332637200LL, 7200 }, /* 2012-03-25T01:00:00Z */
+ { 1351386000LL, 3600 }, /* 2012-10-28T01:00:00Z */
+ { 1364691600LL, 7200 }, /* 2013-03-31T01:00:00Z */
+ { 1382835600LL, 3600 }, /* 2013-10-27T01:00:00Z */
+ { 1396141200LL, 7200 }, /* 2014-03-30T01:00:00Z */
+ { 1414285200LL, 3600 }, /* 2014-10-26T01:00:00Z */
+ { 1427590800LL, 7200 }, /* 2015-03-29T01:00:00Z */
+ { 1445734800LL, 3600 }, /* 2015-10-25T01:00:00Z */
+ { 1459040400LL, 7200 }, /* 2016-03-27T01:00:00Z */
+ { 1477789200LL, 3600 }, /* 2016-10-30T01:00:00Z */
+ { 1490490000LL, 7200 }, /* 2017-03-26T01:00:00Z */
+ { 1509238800LL, 3600 }, /* 2017-10-29T01:00:00Z */
+ { 1521939600LL, 7200 }, /* 2018-03-25T01:00:00Z */
+ { 1540688400LL, 3600 }, /* 2018-10-28T01:00:00Z */
+ { 1553994000LL, 7200 }, /* 2019-03-31T01:00:00Z */
+ { 1572138000LL, 3600 }, /* 2019-10-27T01:00:00Z */
+ { 1585443600LL, 7200 }, /* 2020-03-29T01:00:00Z */
+ { 1603587600LL, 3600 }, /* 2020-10-25T01:00:00Z */
+ { 1616893200LL, 7200 }, /* 2021-03-28T01:00:00Z */
+ { 1635642000LL, 3600 }, /* 2021-10-31T01:00:00Z */
+ { 1648342800LL, 7200 }, /* 2022-03-27T01:00:00Z */
+ { 1667091600LL, 3600 }, /* 2022-10-30T01:00:00Z */
+ { 1679792400LL, 7200 }, /* 2023-03-26T01:00:00Z */
+ { 1698541200LL, 3600 }, /* 2023-10-29T01:00:00Z */
+ { 1711846800LL, 7200 }, /* 2024-03-31T01:00:00Z */
+ { 1729990800LL, 3600 }, /* 2024-10-27T01:00:00Z */
+ { 1743296400LL, 7200 }, /* 2025-03-30T01:00:00Z */
+ { 1761440400LL, 3600 }, /* 2025-10-26T01:00:00Z */
+ { 1774746000LL, 7200 }, /* 2026-03-29T01:00:00Z */
+ { 1792890000LL, 3600 }, /* 2026-10-25T01:00:00Z */
+ { 1806195600LL, 7200 }, /* 2027-03-28T01:00:00Z */
+ { 1824944400LL, 3600 }, /* 2027-10-31T01:00:00Z */
+ { 1837645200LL, 7200 }, /* 2028-03-26T01:00:00Z */
+ { 1856394000LL, 3600 }, /* 2028-10-29T01:00:00Z */
+ { 1869094800LL, 7200 }, /* 2029-03-25T01:00:00Z */
+ { 1887843600LL, 3600 }, /* 2029-10-28T01:00:00Z */
+ { 1901149200LL, 7200 }, /* 2030-03-31T01:00:00Z */
+ { 1919293200LL, 3600 }, /* 2030-10-27T01:00:00Z */
+ { 1932598800LL, 7200 }, /* 2031-03-30T01:00:00Z */
+ { 1950742800LL, 3600 }, /* 2031-10-26T01:00:00Z */
+ { 1964048400LL, 7200 }, /* 2032-03-28T01:00:00Z */
+ { 1982797200LL, 3600 }, /* 2032-10-31T01:00:00Z */
+ { 1995498000LL, 7200 }, /* 2033-03-27T01:00:00Z */
+ { 2014246800LL, 3600 }, /* 2033-10-30T01:00:00Z */
+ { 2026947600LL, 7200 }, /* 2034-03-26T01:00:00Z */
+ { 2045696400LL, 3600 }, /* 2034-10-29T01:00:00Z */
+ { 2058397200LL, 7200 }, /* 2035-03-25T01:00:00Z */
+ { 2077146000LL, 3600 }, /* 2035-10-28T01:00:00Z */
+ { 2090451600LL, 7200 }, /* 2036-03-30T01:00:00Z */
+ { 2108595600LL, 3600 }, /* 2036-10-26T01:00:00Z */
+ { 2121901200LL, 7200 }, /* 2037-03-29T01:00:00Z */
+ { 2140045200LL, 3600 }, /* 2037-10-25T01:00:00Z */
+};
+
+static const TZTransition tz_trans_Europe_Riga[] = {
+ { INT64_MIN, 5794 }, /* before first transition */
+ { -2840146594LL, 5794 }, /* 1879-12-31T22:23:26Z */
+ { -1632008194LL, 9394 }, /* 1918-04-15T00:23:26Z */
+ { -1618702594LL, 5794 }, /* 1918-09-16T00:23:26Z */
+ { -1601681794LL, 9394 }, /* 1919-04-01T00:23:26Z */
+ { -1597275394LL, 5794 }, /* 1919-05-22T00:23:26Z */
+ { -1377308194LL, 7200 }, /* 1926-05-10T22:23:26Z */
+ { -928029600LL, 10800 }, /* 1940-08-04T22:00:00Z */
+ { -899521200LL, 7200 }, /* 1941-06-30T21:00:00Z */
+ { -857257200LL, 3600 }, /* 1942-11-02T01:00:00Z */
+ { -844556400LL, 7200 }, /* 1943-03-29T01:00:00Z */
+ { -828226800LL, 3600 }, /* 1943-10-04T01:00:00Z */
+ { -812502000LL, 7200 }, /* 1944-04-03T01:00:00Z */
+ { -796777200LL, 3600 }, /* 1944-10-02T01:00:00Z */
+ { -795834000LL, 10800 }, /* 1944-10-12T23:00:00Z */
+ { 354920400LL, 14400 }, /* 1981-03-31T21:00:00Z */
+ { 370728000LL, 10800 }, /* 1981-09-30T20:00:00Z */
+ { 386456400LL, 14400 }, /* 1982-03-31T21:00:00Z */
+ { 402264000LL, 10800 }, /* 1982-09-30T20:00:00Z */
+ { 417992400LL, 14400 }, /* 1983-03-31T21:00:00Z */
+ { 433800000LL, 10800 }, /* 1983-09-30T20:00:00Z */
+ { 449614800LL, 14400 }, /* 1984-03-31T21:00:00Z */
+ { 465346800LL, 10800 }, /* 1984-09-29T23:00:00Z */
+ { 481071600LL, 14400 }, /* 1985-03-30T23:00:00Z */
+ { 496796400LL, 10800 }, /* 1985-09-28T23:00:00Z */
+ { 512521200LL, 14400 }, /* 1986-03-29T23:00:00Z */
+ { 528246000LL, 10800 }, /* 1986-09-27T23:00:00Z */
+ { 543970800LL, 14400 }, /* 1987-03-28T23:00:00Z */
+ { 559695600LL, 10800 }, /* 1987-09-26T23:00:00Z */
+ { 575420400LL, 14400 }, /* 1988-03-26T23:00:00Z */
+ { 591145200LL, 10800 }, /* 1988-09-24T23:00:00Z */
+ { 606870000LL, 10800 }, /* 1989-03-25T23:00:00Z */
+ { 622598400LL, 7200 }, /* 1989-09-24T00:00:00Z */
+ { 638323200LL, 10800 }, /* 1990-03-25T00:00:00Z */
+ { 654652800LL, 7200 }, /* 1990-09-30T00:00:00Z */
+ { 670377600LL, 10800 }, /* 1991-03-31T00:00:00Z */
+ { 686102400LL, 7200 }, /* 1991-09-29T00:00:00Z */
+ { 701827200LL, 10800 }, /* 1992-03-29T00:00:00Z */
+ { 717552000LL, 7200 }, /* 1992-09-27T00:00:00Z */
+ { 733276800LL, 10800 }, /* 1993-03-28T00:00:00Z */
+ { 749001600LL, 7200 }, /* 1993-09-26T00:00:00Z */
+ { 764726400LL, 10800 }, /* 1994-03-27T00:00:00Z */
+ { 780451200LL, 7200 }, /* 1994-09-25T00:00:00Z */
+ { 796176000LL, 10800 }, /* 1995-03-26T00:00:00Z */
+ { 811900800LL, 7200 }, /* 1995-09-24T00:00:00Z */
+ { 828230400LL, 10800 }, /* 1996-03-31T00:00:00Z */
+ { 843955200LL, 7200 }, /* 1996-09-29T00:00:00Z */
+ { 859683600LL, 10800 }, /* 1997-03-30T01:00:00Z */
+ { 877827600LL, 7200 }, /* 1997-10-26T01:00:00Z */
+ { 891133200LL, 10800 }, /* 1998-03-29T01:00:00Z */
+ { 909277200LL, 7200 }, /* 1998-10-25T01:00:00Z */
+ { 922582800LL, 10800 }, /* 1999-03-28T01:00:00Z */
+ { 941331600LL, 7200 }, /* 1999-10-31T01:00:00Z */
+ { 985482000LL, 10800 }, /* 2001-03-25T01:00:00Z */
+ { 1004230800LL, 7200 }, /* 2001-10-28T01:00:00Z */
+ { 1017536400LL, 10800 }, /* 2002-03-31T01:00:00Z */
+ { 1035680400LL, 7200 }, /* 2002-10-27T01:00:00Z */
+ { 1048986000LL, 10800 }, /* 2003-03-30T01:00:00Z */
+ { 1067130000LL, 7200 }, /* 2003-10-26T01:00:00Z */
+ { 1080435600LL, 10800 }, /* 2004-03-28T01:00:00Z */
+ { 1099184400LL, 7200 }, /* 2004-10-31T01:00:00Z */
+ { 1111885200LL, 10800 }, /* 2005-03-27T01:00:00Z */
+ { 1130634000LL, 7200 }, /* 2005-10-30T01:00:00Z */
+ { 1143334800LL, 10800 }, /* 2006-03-26T01:00:00Z */
+ { 1162083600LL, 7200 }, /* 2006-10-29T01:00:00Z */
+ { 1174784400LL, 10800 }, /* 2007-03-25T01:00:00Z */
+ { 1193533200LL, 7200 }, /* 2007-10-28T01:00:00Z */
+ { 1206838800LL, 10800 }, /* 2008-03-30T01:00:00Z */
+ { 1224982800LL, 7200 }, /* 2008-10-26T01:00:00Z */
+ { 1238288400LL, 10800 }, /* 2009-03-29T01:00:00Z */
+ { 1256432400LL, 7200 }, /* 2009-10-25T01:00:00Z */
+ { 1269738000LL, 10800 }, /* 2010-03-28T01:00:00Z */
+ { 1288486800LL, 7200 }, /* 2010-10-31T01:00:00Z */
+ { 1301187600LL, 10800 }, /* 2011-03-27T01:00:00Z */
+ { 1319936400LL, 7200 }, /* 2011-10-30T01:00:00Z */
+ { 1332637200LL, 10800 }, /* 2012-03-25T01:00:00Z */
+ { 1351386000LL, 7200 }, /* 2012-10-28T01:00:00Z */
+ { 1364691600LL, 10800 }, /* 2013-03-31T01:00:00Z */
+ { 1382835600LL, 7200 }, /* 2013-10-27T01:00:00Z */
+ { 1396141200LL, 10800 }, /* 2014-03-30T01:00:00Z */
+ { 1414285200LL, 7200 }, /* 2014-10-26T01:00:00Z */
+ { 1427590800LL, 10800 }, /* 2015-03-29T01:00:00Z */
+ { 1445734800LL, 7200 }, /* 2015-10-25T01:00:00Z */
+ { 1459040400LL, 10800 }, /* 2016-03-27T01:00:00Z */
+ { 1477789200LL, 7200 }, /* 2016-10-30T01:00:00Z */
+ { 1490490000LL, 10800 }, /* 2017-03-26T01:00:00Z */
+ { 1509238800LL, 7200 }, /* 2017-10-29T01:00:00Z */
+ { 1521939600LL, 10800 }, /* 2018-03-25T01:00:00Z */
+ { 1540688400LL, 7200 }, /* 2018-10-28T01:00:00Z */
+ { 1553994000LL, 10800 }, /* 2019-03-31T01:00:00Z */
+ { 1572138000LL, 7200 }, /* 2019-10-27T01:00:00Z */
+ { 1585443600LL, 10800 }, /* 2020-03-29T01:00:00Z */
+ { 1603587600LL, 7200 }, /* 2020-10-25T01:00:00Z */
+ { 1616893200LL, 10800 }, /* 2021-03-28T01:00:00Z */
+ { 1635642000LL, 7200 }, /* 2021-10-31T01:00:00Z */
+ { 1648342800LL, 10800 }, /* 2022-03-27T01:00:00Z */
+ { 1667091600LL, 7200 }, /* 2022-10-30T01:00:00Z */
+ { 1679792400LL, 10800 }, /* 2023-03-26T01:00:00Z */
+ { 1698541200LL, 7200 }, /* 2023-10-29T01:00:00Z */
+ { 1711846800LL, 10800 }, /* 2024-03-31T01:00:00Z */
+ { 1729990800LL, 7200 }, /* 2024-10-27T01:00:00Z */
+ { 1743296400LL, 10800 }, /* 2025-03-30T01:00:00Z */
+ { 1761440400LL, 7200 }, /* 2025-10-26T01:00:00Z */
+ { 1774746000LL, 10800 }, /* 2026-03-29T01:00:00Z */
+ { 1792890000LL, 7200 }, /* 2026-10-25T01:00:00Z */
+ { 1806195600LL, 10800 }, /* 2027-03-28T01:00:00Z */
+ { 1824944400LL, 7200 }, /* 2027-10-31T01:00:00Z */
+ { 1837645200LL, 10800 }, /* 2028-03-26T01:00:00Z */
+ { 1856394000LL, 7200 }, /* 2028-10-29T01:00:00Z */
+ { 1869094800LL, 10800 }, /* 2029-03-25T01:00:00Z */
+ { 1887843600LL, 7200 }, /* 2029-10-28T01:00:00Z */
+ { 1901149200LL, 10800 }, /* 2030-03-31T01:00:00Z */
+ { 1919293200LL, 7200 }, /* 2030-10-27T01:00:00Z */
+ { 1932598800LL, 10800 }, /* 2031-03-30T01:00:00Z */
+ { 1950742800LL, 7200 }, /* 2031-10-26T01:00:00Z */
+ { 1964048400LL, 10800 }, /* 2032-03-28T01:00:00Z */
+ { 1982797200LL, 7200 }, /* 2032-10-31T01:00:00Z */
+ { 1995498000LL, 10800 }, /* 2033-03-27T01:00:00Z */
+ { 2014246800LL, 7200 }, /* 2033-10-30T01:00:00Z */
+ { 2026947600LL, 10800 }, /* 2034-03-26T01:00:00Z */
+ { 2045696400LL, 7200 }, /* 2034-10-29T01:00:00Z */
+ { 2058397200LL, 10800 }, /* 2035-03-25T01:00:00Z */
+ { 2077146000LL, 7200 }, /* 2035-10-28T01:00:00Z */
+ { 2090451600LL, 10800 }, /* 2036-03-30T01:00:00Z */
+ { 2108595600LL, 7200 }, /* 2036-10-26T01:00:00Z */
+ { 2121901200LL, 10800 }, /* 2037-03-29T01:00:00Z */
+ { 2140045200LL, 7200 }, /* 2037-10-25T01:00:00Z */
+};
+
+static const TZTransition tz_trans_Europe_Simferopol[] = {
+ { INT64_MIN, 8184 }, /* before first transition */
+ { -2840148984LL, 8160 }, /* 1879-12-31T21:43:36Z */
+ { -1441160160LL, 7200 }, /* 1924-05-01T21:44:00Z */
+ { -1247536800LL, 10800 }, /* 1930-06-20T22:00:00Z */
+ { -888894000LL, 7200 }, /* 1941-10-31T21:00:00Z */
+ { -857257200LL, 3600 }, /* 1942-11-02T01:00:00Z */
+ { -844556400LL, 7200 }, /* 1943-03-29T01:00:00Z */
+ { -828226800LL, 3600 }, /* 1943-10-04T01:00:00Z */
+ { -812502000LL, 7200 }, /* 1944-04-03T01:00:00Z */
+ { -811648800LL, 10800 }, /* 1944-04-12T22:00:00Z */
+ { 354920400LL, 14400 }, /* 1981-03-31T21:00:00Z */
+ { 370728000LL, 10800 }, /* 1981-09-30T20:00:00Z */
+ { 386456400LL, 14400 }, /* 1982-03-31T21:00:00Z */
+ { 402264000LL, 10800 }, /* 1982-09-30T20:00:00Z */
+ { 417992400LL, 14400 }, /* 1983-03-31T21:00:00Z */
+ { 433800000LL, 10800 }, /* 1983-09-30T20:00:00Z */
+ { 449614800LL, 14400 }, /* 1984-03-31T21:00:00Z */
+ { 465346800LL, 10800 }, /* 1984-09-29T23:00:00Z */
+ { 481071600LL, 14400 }, /* 1985-03-30T23:00:00Z */
+ { 496796400LL, 10800 }, /* 1985-09-28T23:00:00Z */
+ { 512521200LL, 14400 }, /* 1986-03-29T23:00:00Z */
+ { 528246000LL, 10800 }, /* 1986-09-27T23:00:00Z */
+ { 543970800LL, 14400 }, /* 1987-03-28T23:00:00Z */
+ { 559695600LL, 10800 }, /* 1987-09-26T23:00:00Z */
+ { 575420400LL, 14400 }, /* 1988-03-26T23:00:00Z */
+ { 591145200LL, 10800 }, /* 1988-09-24T23:00:00Z */
+ { 606870000LL, 14400 }, /* 1989-03-25T23:00:00Z */
+ { 622594800LL, 10800 }, /* 1989-09-23T23:00:00Z */
+ { 646786800LL, 7200 }, /* 1990-06-30T23:00:00Z */
+ { 701827200LL, 10800 }, /* 1992-03-29T00:00:00Z */
+ { 717552000LL, 7200 }, /* 1992-09-27T00:00:00Z */
+ { 733276800LL, 10800 }, /* 1993-03-28T00:00:00Z */
+ { 749001600LL, 7200 }, /* 1993-09-26T00:00:00Z */
+ { 764726400LL, 10800 }, /* 1994-03-27T00:00:00Z */
+ { 767739600LL, 14400 }, /* 1994-04-30T21:00:00Z */
+ { 780447600LL, 10800 }, /* 1994-09-24T23:00:00Z */
+ { 796172400LL, 14400 }, /* 1995-03-25T23:00:00Z */
+ { 811897200LL, 10800 }, /* 1995-09-23T23:00:00Z */
+ { 828219600LL, 14400 }, /* 1996-03-30T21:00:00Z */
+ { 846374400LL, 10800 }, /* 1996-10-27T00:00:00Z */
+ { 859683600LL, 10800 }, /* 1997-03-30T01:00:00Z */
+ { 877827600LL, 7200 }, /* 1997-10-26T01:00:00Z */
+ { 891133200LL, 10800 }, /* 1998-03-29T01:00:00Z */
+ { 909277200LL, 7200 }, /* 1998-10-25T01:00:00Z */
+ { 922582800LL, 10800 }, /* 1999-03-28T01:00:00Z */
+ { 941331600LL, 7200 }, /* 1999-10-31T01:00:00Z */
+ { 954032400LL, 10800 }, /* 2000-03-26T01:00:00Z */
+ { 972781200LL, 7200 }, /* 2000-10-29T01:00:00Z */
+ { 985482000LL, 10800 }, /* 2001-03-25T01:00:00Z */
+ { 1004230800LL, 7200 }, /* 2001-10-28T01:00:00Z */
+ { 1017536400LL, 10800 }, /* 2002-03-31T01:00:00Z */
+ { 1035680400LL, 7200 }, /* 2002-10-27T01:00:00Z */
+ { 1048986000LL, 10800 }, /* 2003-03-30T01:00:00Z */
+ { 1067130000LL, 7200 }, /* 2003-10-26T01:00:00Z */
+ { 1080435600LL, 10800 }, /* 2004-03-28T01:00:00Z */
+ { 1099184400LL, 7200 }, /* 2004-10-31T01:00:00Z */
+ { 1111885200LL, 10800 }, /* 2005-03-27T01:00:00Z */
+ { 1130634000LL, 7200 }, /* 2005-10-30T01:00:00Z */
+ { 1143334800LL, 10800 }, /* 2006-03-26T01:00:00Z */
+ { 1162083600LL, 7200 }, /* 2006-10-29T01:00:00Z */
+ { 1174784400LL, 10800 }, /* 2007-03-25T01:00:00Z */
+ { 1193533200LL, 7200 }, /* 2007-10-28T01:00:00Z */
+ { 1206838800LL, 10800 }, /* 2008-03-30T01:00:00Z */
+ { 1224982800LL, 7200 }, /* 2008-10-26T01:00:00Z */
+ { 1238288400LL, 10800 }, /* 2009-03-29T01:00:00Z */
+ { 1256432400LL, 7200 }, /* 2009-10-25T01:00:00Z */
+ { 1269738000LL, 10800 }, /* 2010-03-28T01:00:00Z */
+ { 1288486800LL, 7200 }, /* 2010-10-31T01:00:00Z */
+ { 1301187600LL, 10800 }, /* 2011-03-27T01:00:00Z */
+ { 1319936400LL, 7200 }, /* 2011-10-30T01:00:00Z */
+ { 1332637200LL, 10800 }, /* 2012-03-25T01:00:00Z */
+ { 1351386000LL, 7200 }, /* 2012-10-28T01:00:00Z */
+ { 1364691600LL, 10800 }, /* 2013-03-31T01:00:00Z */
+ { 1382835600LL, 7200 }, /* 2013-10-27T01:00:00Z */
+ { 1396137600LL, 14400 }, /* 2014-03-30T00:00:00Z */
+ { 1414274400LL, 10800 }, /* 2014-10-25T22:00:00Z */
+};
+
+static const TZTransition tz_trans_Europe_Tirane[] = {
+ { INT64_MIN, 4760 }, /* before first transition */
+ { -1767230360LL, 3600 }, /* 1913-12-31T22:40:40Z */
+ { -932346000LL, 7200 }, /* 1940-06-15T23:00:00Z */
+ { -857257200LL, 3600 }, /* 1942-11-02T01:00:00Z */
+ { -844556400LL, 7200 }, /* 1943-03-29T01:00:00Z */
+ { -843519600LL, 3600 }, /* 1943-04-10T01:00:00Z */
+ { 136854000LL, 7200 }, /* 1974-05-03T23:00:00Z */
+ { 149896800LL, 3600 }, /* 1974-10-01T22:00:00Z */
+ { 168130800LL, 7200 }, /* 1975-04-30T23:00:00Z */
+ { 181432800LL, 3600 }, /* 1975-10-01T22:00:00Z */
+ { 199839600LL, 7200 }, /* 1976-05-01T23:00:00Z */
+ { 213141600LL, 3600 }, /* 1976-10-02T22:00:00Z */
+ { 231894000LL, 7200 }, /* 1977-05-07T23:00:00Z */
+ { 244591200LL, 3600 }, /* 1977-10-01T22:00:00Z */
+ { 263257200LL, 7200 }, /* 1978-05-05T23:00:00Z */
+ { 276040800LL, 3600 }, /* 1978-09-30T22:00:00Z */
+ { 294706800LL, 7200 }, /* 1979-05-04T23:00:00Z */
+ { 307490400LL, 3600 }, /* 1979-09-29T22:00:00Z */
+ { 326156400LL, 7200 }, /* 1980-05-02T23:00:00Z */
+ { 339458400LL, 3600 }, /* 1980-10-03T22:00:00Z */
+ { 357087600LL, 7200 }, /* 1981-04-25T23:00:00Z */
+ { 370389600LL, 3600 }, /* 1981-09-26T22:00:00Z */
+ { 389142000LL, 7200 }, /* 1982-05-01T23:00:00Z */
+ { 402444000LL, 3600 }, /* 1982-10-02T22:00:00Z */
+ { 419468400LL, 7200 }, /* 1983-04-17T23:00:00Z */
+ { 433807200LL, 3600 }, /* 1983-09-30T22:00:00Z */
+ { 449622000LL, 7200 }, /* 1984-03-31T23:00:00Z */
+ { 465354000LL, 3600 }, /* 1984-09-30T01:00:00Z */
+ { 481078800LL, 7200 }, /* 1985-03-31T01:00:00Z */
+ { 496803600LL, 3600 }, /* 1985-09-29T01:00:00Z */
+ { 512528400LL, 7200 }, /* 1986-03-30T01:00:00Z */
+ { 528253200LL, 3600 }, /* 1986-09-28T01:00:00Z */
+ { 543978000LL, 7200 }, /* 1987-03-29T01:00:00Z */
+ { 559702800LL, 3600 }, /* 1987-09-27T01:00:00Z */
+ { 575427600LL, 7200 }, /* 1988-03-27T01:00:00Z */
+ { 591152400LL, 3600 }, /* 1988-09-25T01:00:00Z */
+ { 606877200LL, 7200 }, /* 1989-03-26T01:00:00Z */
+ { 622602000LL, 3600 }, /* 1989-09-24T01:00:00Z */
+ { 638326800LL, 7200 }, /* 1990-03-25T01:00:00Z */
+ { 654656400LL, 3600 }, /* 1990-09-30T01:00:00Z */
+ { 670381200LL, 7200 }, /* 1991-03-31T01:00:00Z */
+ { 686106000LL, 3600 }, /* 1991-09-29T01:00:00Z */
+ { 701830800LL, 7200 }, /* 1992-03-29T01:00:00Z */
+ { 717555600LL, 3600 }, /* 1992-09-27T01:00:00Z */
+ { 733280400LL, 7200 }, /* 1993-03-28T01:00:00Z */
+ { 749005200LL, 3600 }, /* 1993-09-26T01:00:00Z */
+ { 764730000LL, 7200 }, /* 1994-03-27T01:00:00Z */
+ { 780454800LL, 3600 }, /* 1994-09-25T01:00:00Z */
+ { 796179600LL, 7200 }, /* 1995-03-26T01:00:00Z */
+ { 811904400LL, 3600 }, /* 1995-09-24T01:00:00Z */
+ { 828234000LL, 7200 }, /* 1996-03-31T01:00:00Z */
+ { 846378000LL, 3600 }, /* 1996-10-27T01:00:00Z */
+ { 859683600LL, 7200 }, /* 1997-03-30T01:00:00Z */
+ { 877827600LL, 3600 }, /* 1997-10-26T01:00:00Z */
+ { 891133200LL, 7200 }, /* 1998-03-29T01:00:00Z */
+ { 909277200LL, 3600 }, /* 1998-10-25T01:00:00Z */
+ { 922582800LL, 7200 }, /* 1999-03-28T01:00:00Z */
+ { 941331600LL, 3600 }, /* 1999-10-31T01:00:00Z */
+ { 954032400LL, 7200 }, /* 2000-03-26T01:00:00Z */
+ { 972781200LL, 3600 }, /* 2000-10-29T01:00:00Z */
+ { 985482000LL, 7200 }, /* 2001-03-25T01:00:00Z */
+ { 1004230800LL, 3600 }, /* 2001-10-28T01:00:00Z */
+ { 1017536400LL, 7200 }, /* 2002-03-31T01:00:00Z */
+ { 1035680400LL, 3600 }, /* 2002-10-27T01:00:00Z */
+ { 1048986000LL, 7200 }, /* 2003-03-30T01:00:00Z */
+ { 1067130000LL, 3600 }, /* 2003-10-26T01:00:00Z */
+ { 1080435600LL, 7200 }, /* 2004-03-28T01:00:00Z */
+ { 1099184400LL, 3600 }, /* 2004-10-31T01:00:00Z */
+ { 1111885200LL, 7200 }, /* 2005-03-27T01:00:00Z */
+ { 1130634000LL, 3600 }, /* 2005-10-30T01:00:00Z */
+ { 1143334800LL, 7200 }, /* 2006-03-26T01:00:00Z */
+ { 1162083600LL, 3600 }, /* 2006-10-29T01:00:00Z */
+ { 1174784400LL, 7200 }, /* 2007-03-25T01:00:00Z */
+ { 1193533200LL, 3600 }, /* 2007-10-28T01:00:00Z */
+ { 1206838800LL, 7200 }, /* 2008-03-30T01:00:00Z */
+ { 1224982800LL, 3600 }, /* 2008-10-26T01:00:00Z */
+ { 1238288400LL, 7200 }, /* 2009-03-29T01:00:00Z */
+ { 1256432400LL, 3600 }, /* 2009-10-25T01:00:00Z */
+ { 1269738000LL, 7200 }, /* 2010-03-28T01:00:00Z */
+ { 1288486800LL, 3600 }, /* 2010-10-31T01:00:00Z */
+ { 1301187600LL, 7200 }, /* 2011-03-27T01:00:00Z */
+ { 1319936400LL, 3600 }, /* 2011-10-30T01:00:00Z */
+ { 1332637200LL, 7200 }, /* 2012-03-25T01:00:00Z */
+ { 1351386000LL, 3600 }, /* 2012-10-28T01:00:00Z */
+ { 1364691600LL, 7200 }, /* 2013-03-31T01:00:00Z */
+ { 1382835600LL, 3600 }, /* 2013-10-27T01:00:00Z */
+ { 1396141200LL, 7200 }, /* 2014-03-30T01:00:00Z */
+ { 1414285200LL, 3600 }, /* 2014-10-26T01:00:00Z */
+ { 1427590800LL, 7200 }, /* 2015-03-29T01:00:00Z */
+ { 1445734800LL, 3600 }, /* 2015-10-25T01:00:00Z */
+ { 1459040400LL, 7200 }, /* 2016-03-27T01:00:00Z */
+ { 1477789200LL, 3600 }, /* 2016-10-30T01:00:00Z */
+ { 1490490000LL, 7200 }, /* 2017-03-26T01:00:00Z */
+ { 1509238800LL, 3600 }, /* 2017-10-29T01:00:00Z */
+ { 1521939600LL, 7200 }, /* 2018-03-25T01:00:00Z */
+ { 1540688400LL, 3600 }, /* 2018-10-28T01:00:00Z */
+ { 1553994000LL, 7200 }, /* 2019-03-31T01:00:00Z */
+ { 1572138000LL, 3600 }, /* 2019-10-27T01:00:00Z */
+ { 1585443600LL, 7200 }, /* 2020-03-29T01:00:00Z */
+ { 1603587600LL, 3600 }, /* 2020-10-25T01:00:00Z */
+ { 1616893200LL, 7200 }, /* 2021-03-28T01:00:00Z */
+ { 1635642000LL, 3600 }, /* 2021-10-31T01:00:00Z */
+ { 1648342800LL, 7200 }, /* 2022-03-27T01:00:00Z */
+ { 1667091600LL, 3600 }, /* 2022-10-30T01:00:00Z */
+ { 1679792400LL, 7200 }, /* 2023-03-26T01:00:00Z */
+ { 1698541200LL, 3600 }, /* 2023-10-29T01:00:00Z */
+ { 1711846800LL, 7200 }, /* 2024-03-31T01:00:00Z */
+ { 1729990800LL, 3600 }, /* 2024-10-27T01:00:00Z */
+ { 1743296400LL, 7200 }, /* 2025-03-30T01:00:00Z */
+ { 1761440400LL, 3600 }, /* 2025-10-26T01:00:00Z */
+ { 1774746000LL, 7200 }, /* 2026-03-29T01:00:00Z */
+ { 1792890000LL, 3600 }, /* 2026-10-25T01:00:00Z */
+ { 1806195600LL, 7200 }, /* 2027-03-28T01:00:00Z */
+ { 1824944400LL, 3600 }, /* 2027-10-31T01:00:00Z */
+ { 1837645200LL, 7200 }, /* 2028-03-26T01:00:00Z */
+ { 1856394000LL, 3600 }, /* 2028-10-29T01:00:00Z */
+ { 1869094800LL, 7200 }, /* 2029-03-25T01:00:00Z */
+ { 1887843600LL, 3600 }, /* 2029-10-28T01:00:00Z */
+ { 1901149200LL, 7200 }, /* 2030-03-31T01:00:00Z */
+ { 1919293200LL, 3600 }, /* 2030-10-27T01:00:00Z */
+ { 1932598800LL, 7200 }, /* 2031-03-30T01:00:00Z */
+ { 1950742800LL, 3600 }, /* 2031-10-26T01:00:00Z */
+ { 1964048400LL, 7200 }, /* 2032-03-28T01:00:00Z */
+ { 1982797200LL, 3600 }, /* 2032-10-31T01:00:00Z */
+ { 1995498000LL, 7200 }, /* 2033-03-27T01:00:00Z */
+ { 2014246800LL, 3600 }, /* 2033-10-30T01:00:00Z */
+ { 2026947600LL, 7200 }, /* 2034-03-26T01:00:00Z */
+ { 2045696400LL, 3600 }, /* 2034-10-29T01:00:00Z */
+ { 2058397200LL, 7200 }, /* 2035-03-25T01:00:00Z */
+ { 2077146000LL, 3600 }, /* 2035-10-28T01:00:00Z */
+ { 2090451600LL, 7200 }, /* 2036-03-30T01:00:00Z */
+ { 2108595600LL, 3600 }, /* 2036-10-26T01:00:00Z */
+ { 2121901200LL, 7200 }, /* 2037-03-29T01:00:00Z */
+ { 2140045200LL, 3600 }, /* 2037-10-25T01:00:00Z */
+};
+
+static const TZTransition tz_trans_Europe_Vienna[] = {
+ { INT64_MIN, 3921 }, /* before first transition */
+ { -2422055121LL, 3600 }, /* 1893-03-31T22:54:39Z */
+ { -1693706400LL, 7200 }, /* 1916-04-30T22:00:00Z */
+ { -1680483600LL, 3600 }, /* 1916-09-30T23:00:00Z */
+ { -1663455600LL, 7200 }, /* 1917-04-16T01:00:00Z */
+ { -1650150000LL, 3600 }, /* 1917-09-17T01:00:00Z */
+ { -1632006000LL, 7200 }, /* 1918-04-15T01:00:00Z */
+ { -1618700400LL, 3600 }, /* 1918-09-16T01:00:00Z */
+ { -1569711600LL, 7200 }, /* 1920-04-05T01:00:00Z */
+ { -1555801200LL, 3600 }, /* 1920-09-13T01:00:00Z */
+ { -938905200LL, 7200 }, /* 1940-04-01T01:00:00Z */
+ { -857257200LL, 3600 }, /* 1942-11-02T01:00:00Z */
+ { -844556400LL, 7200 }, /* 1943-03-29T01:00:00Z */
+ { -828226800LL, 3600 }, /* 1943-10-04T01:00:00Z */
+ { -812502000LL, 7200 }, /* 1944-04-03T01:00:00Z */
+ { -796777200LL, 3600 }, /* 1944-10-02T01:00:00Z */
+ { -781052400LL, 7200 }, /* 1945-04-02T01:00:00Z */
+ { -780188400LL, 3600 }, /* 1945-04-12T01:00:00Z */
+ { -748479600LL, 7200 }, /* 1946-04-14T01:00:00Z */
+ { -733273200LL, 3600 }, /* 1946-10-07T01:00:00Z */
+ { -717634800LL, 7200 }, /* 1947-04-06T01:00:00Z */
+ { -701910000LL, 3600 }, /* 1947-10-05T01:00:00Z */
+ { -684975600LL, 7200 }, /* 1948-04-18T01:00:00Z */
+ { -670460400LL, 3600 }, /* 1948-10-03T01:00:00Z */
+ { 323823600LL, 7200 }, /* 1980-04-05T23:00:00Z */
+ { 338940000LL, 3600 }, /* 1980-09-27T22:00:00Z */
+ { 354675600LL, 7200 }, /* 1981-03-29T01:00:00Z */
+ { 370400400LL, 3600 }, /* 1981-09-27T01:00:00Z */
+ { 386125200LL, 7200 }, /* 1982-03-28T01:00:00Z */
+ { 401850000LL, 3600 }, /* 1982-09-26T01:00:00Z */
+ { 417574800LL, 7200 }, /* 1983-03-27T01:00:00Z */
+ { 433299600LL, 3600 }, /* 1983-09-25T01:00:00Z */
+ { 449024400LL, 7200 }, /* 1984-03-25T01:00:00Z */
+ { 465354000LL, 3600 }, /* 1984-09-30T01:00:00Z */
+ { 481078800LL, 7200 }, /* 1985-03-31T01:00:00Z */
+ { 496803600LL, 3600 }, /* 1985-09-29T01:00:00Z */
+ { 512528400LL, 7200 }, /* 1986-03-30T01:00:00Z */
+ { 528253200LL, 3600 }, /* 1986-09-28T01:00:00Z */
+ { 543978000LL, 7200 }, /* 1987-03-29T01:00:00Z */
+ { 559702800LL, 3600 }, /* 1987-09-27T01:00:00Z */
+ { 575427600LL, 7200 }, /* 1988-03-27T01:00:00Z */
+ { 591152400LL, 3600 }, /* 1988-09-25T01:00:00Z */
+ { 606877200LL, 7200 }, /* 1989-03-26T01:00:00Z */
+ { 622602000LL, 3600 }, /* 1989-09-24T01:00:00Z */
+ { 638326800LL, 7200 }, /* 1990-03-25T01:00:00Z */
+ { 654656400LL, 3600 }, /* 1990-09-30T01:00:00Z */
+ { 670381200LL, 7200 }, /* 1991-03-31T01:00:00Z */
+ { 686106000LL, 3600 }, /* 1991-09-29T01:00:00Z */
+ { 701830800LL, 7200 }, /* 1992-03-29T01:00:00Z */
+ { 717555600LL, 3600 }, /* 1992-09-27T01:00:00Z */
+ { 733280400LL, 7200 }, /* 1993-03-28T01:00:00Z */
+ { 749005200LL, 3600 }, /* 1993-09-26T01:00:00Z */
+ { 764730000LL, 7200 }, /* 1994-03-27T01:00:00Z */
+ { 780454800LL, 3600 }, /* 1994-09-25T01:00:00Z */
+ { 796179600LL, 7200 }, /* 1995-03-26T01:00:00Z */
+ { 811904400LL, 3600 }, /* 1995-09-24T01:00:00Z */
+ { 828234000LL, 7200 }, /* 1996-03-31T01:00:00Z */
+ { 846378000LL, 3600 }, /* 1996-10-27T01:00:00Z */
+ { 859683600LL, 7200 }, /* 1997-03-30T01:00:00Z */
+ { 877827600LL, 3600 }, /* 1997-10-26T01:00:00Z */
+ { 891133200LL, 7200 }, /* 1998-03-29T01:00:00Z */
+ { 909277200LL, 3600 }, /* 1998-10-25T01:00:00Z */
+ { 922582800LL, 7200 }, /* 1999-03-28T01:00:00Z */
+ { 941331600LL, 3600 }, /* 1999-10-31T01:00:00Z */
+ { 954032400LL, 7200 }, /* 2000-03-26T01:00:00Z */
+ { 972781200LL, 3600 }, /* 2000-10-29T01:00:00Z */
+ { 985482000LL, 7200 }, /* 2001-03-25T01:00:00Z */
+ { 1004230800LL, 3600 }, /* 2001-10-28T01:00:00Z */
+ { 1017536400LL, 7200 }, /* 2002-03-31T01:00:00Z */
+ { 1035680400LL, 3600 }, /* 2002-10-27T01:00:00Z */
+ { 1048986000LL, 7200 }, /* 2003-03-30T01:00:00Z */
+ { 1067130000LL, 3600 }, /* 2003-10-26T01:00:00Z */
+ { 1080435600LL, 7200 }, /* 2004-03-28T01:00:00Z */
+ { 1099184400LL, 3600 }, /* 2004-10-31T01:00:00Z */
+ { 1111885200LL, 7200 }, /* 2005-03-27T01:00:00Z */
+ { 1130634000LL, 3600 }, /* 2005-10-30T01:00:00Z */
+ { 1143334800LL, 7200 }, /* 2006-03-26T01:00:00Z */
+ { 1162083600LL, 3600 }, /* 2006-10-29T01:00:00Z */
+ { 1174784400LL, 7200 }, /* 2007-03-25T01:00:00Z */
+ { 1193533200LL, 3600 }, /* 2007-10-28T01:00:00Z */
+ { 1206838800LL, 7200 }, /* 2008-03-30T01:00:00Z */
+ { 1224982800LL, 3600 }, /* 2008-10-26T01:00:00Z */
+ { 1238288400LL, 7200 }, /* 2009-03-29T01:00:00Z */
+ { 1256432400LL, 3600 }, /* 2009-10-25T01:00:00Z */
+ { 1269738000LL, 7200 }, /* 2010-03-28T01:00:00Z */
+ { 1288486800LL, 3600 }, /* 2010-10-31T01:00:00Z */
+ { 1301187600LL, 7200 }, /* 2011-03-27T01:00:00Z */
+ { 1319936400LL, 3600 }, /* 2011-10-30T01:00:00Z */
+ { 1332637200LL, 7200 }, /* 2012-03-25T01:00:00Z */
+ { 1351386000LL, 3600 }, /* 2012-10-28T01:00:00Z */
+ { 1364691600LL, 7200 }, /* 2013-03-31T01:00:00Z */
+ { 1382835600LL, 3600 }, /* 2013-10-27T01:00:00Z */
+ { 1396141200LL, 7200 }, /* 2014-03-30T01:00:00Z */
+ { 1414285200LL, 3600 }, /* 2014-10-26T01:00:00Z */
+ { 1427590800LL, 7200 }, /* 2015-03-29T01:00:00Z */
+ { 1445734800LL, 3600 }, /* 2015-10-25T01:00:00Z */
+ { 1459040400LL, 7200 }, /* 2016-03-27T01:00:00Z */
+ { 1477789200LL, 3600 }, /* 2016-10-30T01:00:00Z */
+ { 1490490000LL, 7200 }, /* 2017-03-26T01:00:00Z */
+ { 1509238800LL, 3600 }, /* 2017-10-29T01:00:00Z */
+ { 1521939600LL, 7200 }, /* 2018-03-25T01:00:00Z */
+ { 1540688400LL, 3600 }, /* 2018-10-28T01:00:00Z */
+ { 1553994000LL, 7200 }, /* 2019-03-31T01:00:00Z */
+ { 1572138000LL, 3600 }, /* 2019-10-27T01:00:00Z */
+ { 1585443600LL, 7200 }, /* 2020-03-29T01:00:00Z */
+ { 1603587600LL, 3600 }, /* 2020-10-25T01:00:00Z */
+ { 1616893200LL, 7200 }, /* 2021-03-28T01:00:00Z */
+ { 1635642000LL, 3600 }, /* 2021-10-31T01:00:00Z */
+ { 1648342800LL, 7200 }, /* 2022-03-27T01:00:00Z */
+ { 1667091600LL, 3600 }, /* 2022-10-30T01:00:00Z */
+ { 1679792400LL, 7200 }, /* 2023-03-26T01:00:00Z */
+ { 1698541200LL, 3600 }, /* 2023-10-29T01:00:00Z */
+ { 1711846800LL, 7200 }, /* 2024-03-31T01:00:00Z */
+ { 1729990800LL, 3600 }, /* 2024-10-27T01:00:00Z */
+ { 1743296400LL, 7200 }, /* 2025-03-30T01:00:00Z */
+ { 1761440400LL, 3600 }, /* 2025-10-26T01:00:00Z */
+ { 1774746000LL, 7200 }, /* 2026-03-29T01:00:00Z */
+ { 1792890000LL, 3600 }, /* 2026-10-25T01:00:00Z */
+ { 1806195600LL, 7200 }, /* 2027-03-28T01:00:00Z */
+ { 1824944400LL, 3600 }, /* 2027-10-31T01:00:00Z */
+ { 1837645200LL, 7200 }, /* 2028-03-26T01:00:00Z */
+ { 1856394000LL, 3600 }, /* 2028-10-29T01:00:00Z */
+ { 1869094800LL, 7200 }, /* 2029-03-25T01:00:00Z */
+ { 1887843600LL, 3600 }, /* 2029-10-28T01:00:00Z */
+ { 1901149200LL, 7200 }, /* 2030-03-31T01:00:00Z */
+ { 1919293200LL, 3600 }, /* 2030-10-27T01:00:00Z */
+ { 1932598800LL, 7200 }, /* 2031-03-30T01:00:00Z */
+ { 1950742800LL, 3600 }, /* 2031-10-26T01:00:00Z */
+ { 1964048400LL, 7200 }, /* 2032-03-28T01:00:00Z */
+ { 1982797200LL, 3600 }, /* 2032-10-31T01:00:00Z */
+ { 1995498000LL, 7200 }, /* 2033-03-27T01:00:00Z */
+ { 2014246800LL, 3600 }, /* 2033-10-30T01:00:00Z */
+ { 2026947600LL, 7200 }, /* 2034-03-26T01:00:00Z */
+ { 2045696400LL, 3600 }, /* 2034-10-29T01:00:00Z */
+ { 2058397200LL, 7200 }, /* 2035-03-25T01:00:00Z */
+ { 2077146000LL, 3600 }, /* 2035-10-28T01:00:00Z */
+ { 2090451600LL, 7200 }, /* 2036-03-30T01:00:00Z */
+ { 2108595600LL, 3600 }, /* 2036-10-26T01:00:00Z */
+ { 2121901200LL, 7200 }, /* 2037-03-29T01:00:00Z */
+ { 2140045200LL, 3600 }, /* 2037-10-25T01:00:00Z */
+};
+
+static const TZTransition tz_trans_GMT[] = {
+ { INT64_MIN, 0 }, /* before first transition */
+};
+
+static const TZTransition tz_trans_Pacific_Apia[] = {
+ { INT64_MIN, 45184 }, /* before first transition */
+ { -2445424384LL, -41216 }, /* 1892-07-04T11:26:56Z */
+ { -1861878784LL, -41400 }, /* 1911-01-01T11:26:56Z */
+ { -631110600LL, -39600 }, /* 1950-01-01T11:30:00Z */
+ { 1285498800LL, -36000 }, /* 2010-09-26T11:00:00Z */
+ { 1301752800LL, -39600 }, /* 2011-04-02T14:00:00Z */
+ { 1316872800LL, -36000 }, /* 2011-09-24T14:00:00Z */
+ { 1325239200LL, 50400 }, /* 2011-12-30T10:00:00Z */
+ { 1333202400LL, 46800 }, /* 2012-03-31T14:00:00Z */
+ { 1348927200LL, 50400 }, /* 2012-09-29T14:00:00Z */
+ { 1365256800LL, 46800 }, /* 2013-04-06T14:00:00Z */
+ { 1380376800LL, 50400 }, /* 2013-09-28T14:00:00Z */
+ { 1396706400LL, 46800 }, /* 2014-04-05T14:00:00Z */
+ { 1411826400LL, 50400 }, /* 2014-09-27T14:00:00Z */
+ { 1428156000LL, 46800 }, /* 2015-04-04T14:00:00Z */
+ { 1443276000LL, 50400 }, /* 2015-09-26T14:00:00Z */
+ { 1459605600LL, 46800 }, /* 2016-04-02T14:00:00Z */
+ { 1474725600LL, 50400 }, /* 2016-09-24T14:00:00Z */
+ { 1491055200LL, 46800 }, /* 2017-04-01T14:00:00Z */
+ { 1506175200LL, 50400 }, /* 2017-09-23T14:00:00Z */
+ { 1522504800LL, 46800 }, /* 2018-03-31T14:00:00Z */
+ { 1538229600LL, 50400 }, /* 2018-09-29T14:00:00Z */
+ { 1554559200LL, 46800 }, /* 2019-04-06T14:00:00Z */
+ { 1569679200LL, 50400 }, /* 2019-09-28T14:00:00Z */
+ { 1586008800LL, 46800 }, /* 2020-04-04T14:00:00Z */
+ { 1601128800LL, 50400 }, /* 2020-09-26T14:00:00Z */
+ { 1617458400LL, 46800 }, /* 2021-04-03T14:00:00Z */
+};
+
+static const TZTransition tz_trans_Pacific_Niue[] = {
+ { INT64_MIN, -40780 }, /* before first transition */
+ { -543069620LL, -40800 }, /* 1952-10-16T11:19:40Z */
+ { -173623200LL, -39600 }, /* 1964-07-01T11:20:00Z */
+};
+
+static const TZTransition tz_trans_UTC[] = {
+ { INT64_MIN, 0 }, /* before first transition */
+};
+
+const TZAlias ti_tz_aliases[] = {
+ { "America/Nipigon", 13 },
+ { "Arctic/Longyearbyen", 47 },
+ { "Asia/Calcutta", 16 },
+ { "Atlantic/Jan_Mayen", 47 },
+ { "Australia/LHI", 20 },
+ { "Brazil/DeNoronha", 9 },
+ { "Brazil/East", 11 },
+ { "Canada/Eastern", 13 },
+ { "Canada/Newfoundland", 12 },
+ { "Canada/Pacific", 14 },
+ { "EST5EDT", 8 },
+ { "Etc/GMT", 55 },
+ { "Etc/GMT+0", 55 },
+ { "Etc/GMT-0", 55 },
+ { "Etc/GMT0", 55 },
+ { "Etc/UCT", 58 },
+ { "Etc/UTC", 58 },
+ { "Etc/Universal", 58 },
+ { "Etc/Zulu", 58 },
+ { "GB", 48 },
+ { "GB-Eire", 48 },
+ { "GMT+0", 55 },
+ { "GMT-0", 55 },
+ { "GMT0", 55 },
+ { "Greenwich", 55 },
+ { "Japan", 19 },
+ { "MET", 50 },
+ { "PST8PDT", 6 },
+ { "Singapore", 18 },
+ { "UCT", 58 },
+ { "US/Alaska", 2 },
+ { "US/Eastern", 8 },
+ { "US/Pacific", 6 },
+ { "Universal", 58 },
+ { "W-SU", 49 },
+ { "Zulu", 58 },
+};
+const int ti_tz_alias_count = countof(ti_tz_aliases);
+
+const TZData ti_tz_zone_data[] = {
+ { "Africa/Monrovia", tz_trans_Africa_Monrovia, 4 },
+ { "Africa/Tunis", tz_trans_Africa_Tunis, 35 },
+ { "America/Anchorage", tz_trans_America_Anchorage, 146 },
+ { "America/Argentina/Tucuman", tz_trans_America_Argentina_Tucuman, 64 },
+ { "America/Boa_Vista", tz_trans_America_Boa_Vista, 34 },
+ { "America/Fortaleza", tz_trans_America_Fortaleza, 40 },
+ { "America/Los_Angeles", tz_trans_America_Los_Angeles, 187 },
+ { "America/Maceio", tz_trans_America_Maceio, 42 },
+ { "America/New_York", tz_trans_America_New_York, 237 },
+ { "America/Noronha", tz_trans_America_Noronha, 40 },
+ { "America/Recife", tz_trans_America_Recife, 40 },
+ { "America/Sao_Paulo", tz_trans_America_Sao_Paulo, 92 },
+ { "America/St_Johns", tz_trans_America_St_Johns, 240 },
+ { "America/Toronto", tz_trans_America_Toronto, 234 },
+ { "America/Vancouver", tz_trans_America_Vancouver, 169 },
+ { "Antarctica/Casey", tz_trans_Antarctica_Casey, 18 },
+ { "Asia/Kolkata", tz_trans_Asia_Kolkata, 8 },
+ { "Asia/Riyadh", tz_trans_Asia_Riyadh, 2 },
+ { "Asia/Singapore", tz_trans_Asia_Singapore, 9 },
+ { "Asia/Tokyo", tz_trans_Asia_Tokyo, 10 },
+ { "Australia/Lord_Howe", tz_trans_Australia_Lord_Howe, 116 },
+ { "Etc/GMT+1", tz_trans_Etc_GMT_plus_1, 1 },
+ { "Etc/GMT+10", tz_trans_Etc_GMT_plus_10, 1 },
+ { "Etc/GMT+11", tz_trans_Etc_GMT_plus_11, 1 },
+ { "Etc/GMT+12", tz_trans_Etc_GMT_plus_12, 1 },
+ { "Etc/GMT+2", tz_trans_Etc_GMT_plus_2, 1 },
+ { "Etc/GMT+3", tz_trans_Etc_GMT_plus_3, 1 },
+ { "Etc/GMT+4", tz_trans_Etc_GMT_plus_4, 1 },
+ { "Etc/GMT+5", tz_trans_Etc_GMT_plus_5, 1 },
+ { "Etc/GMT+6", tz_trans_Etc_GMT_plus_6, 1 },
+ { "Etc/GMT+7", tz_trans_Etc_GMT_plus_7, 1 },
+ { "Etc/GMT+8", tz_trans_Etc_GMT_plus_8, 1 },
+ { "Etc/GMT+9", tz_trans_Etc_GMT_plus_9, 1 },
+ { "Etc/GMT-1", tz_trans_Etc_GMT_1, 1 },
+ { "Etc/GMT-10", tz_trans_Etc_GMT_10, 1 },
+ { "Etc/GMT-11", tz_trans_Etc_GMT_11, 1 },
+ { "Etc/GMT-12", tz_trans_Etc_GMT_12, 1 },
+ { "Etc/GMT-13", tz_trans_Etc_GMT_13, 1 },
+ { "Etc/GMT-14", tz_trans_Etc_GMT_14, 1 },
+ { "Etc/GMT-2", tz_trans_Etc_GMT_2, 1 },
+ { "Etc/GMT-3", tz_trans_Etc_GMT_3, 1 },
+ { "Etc/GMT-4", tz_trans_Etc_GMT_4, 1 },
+ { "Etc/GMT-5", tz_trans_Etc_GMT_5, 1 },
+ { "Etc/GMT-6", tz_trans_Etc_GMT_6, 1 },
+ { "Etc/GMT-7", tz_trans_Etc_GMT_7, 1 },
+ { "Etc/GMT-8", tz_trans_Etc_GMT_8, 1 },
+ { "Etc/GMT-9", tz_trans_Etc_GMT_9, 1 },
+ { "Europe/Berlin", tz_trans_Europe_Berlin, 144 },
+ { "Europe/London", tz_trans_Europe_London, 243 },
+ { "Europe/Moscow", tz_trans_Europe_Moscow, 79 },
+ { "Europe/Paris", tz_trans_Europe_Paris, 185 },
+ { "Europe/Riga", tz_trans_Europe_Riga, 127 },
+ { "Europe/Simferopol", tz_trans_Europe_Simferopol, 76 },
+ { "Europe/Tirane", tz_trans_Europe_Tirane, 134 },
+ { "Europe/Vienna", tz_trans_Europe_Vienna, 140 },
+ { "GMT", tz_trans_GMT, 1 },
+ { "Pacific/Apia", tz_trans_Pacific_Apia, 27 },
+ { "Pacific/Niue", tz_trans_Pacific_Niue, 3 },
+ { "UTC", tz_trans_UTC, 1 },
+};
+
+const int ti_tz_zone_count = countof(ti_tz_zone_data);
--- /dev/null
+/*
+ * QuickJS Temporal.ZonedDateTime implementation (minimal)
+ */
+
+#include <string.h>
+#include <math.h>
+#include <ctype.h>
+
+#include "../quickjs.h"
+#include "../cutils.h"
+#include "temporal_private.h"
+#include "../intl/intl_private.h"
+#include "timezone.h"
+
+JSClassID js_zoneddatetime_class_id;
+
+/* Public helper to extract timespec from a ZonedDateTime without toString conversion */
+int js_zoneddatetime_get_timespec(JSContext *ctx, JSValueConst val, JSTimeSpec *ts)
+{
+ JSZonedDateTimeData *s = JS_GetOpaque(val, js_zoneddatetime_class_id);
+ if (!s)
+ return -1;
+ *ts = s->ts;
+ return 0;
+}
+
+static void js_zoneddatetime_finalizer(JSRuntime *rt, JSValue val)
+{
+ JSZonedDateTimeData *s = JS_GetOpaque(val, js_zoneddatetime_class_id);
+ if (s)
+ js_free_rt(rt, s);
+}
+
+static const JSClassDef js_zoneddatetime_class = {
+ "Temporal.ZonedDateTime",
+ .finalizer = js_zoneddatetime_finalizer,
+};
+
+JSValue js_create_zoneddatetime(JSContext *ctx, const JSTimeSpec *ts,
+ const char *timeZone, CalendarType calendar)
+{
+ JSZonedDateTimeData *s;
+ JSValue obj;
+ s = js_mallocz(ctx, sizeof(*s));
+ if (!s)
+ return JS_EXCEPTION;
+ s->ts = *ts;
+ pstrcpy(s->timeZone, sizeof(s->timeZone), timeZone);
+ s->calendar = calendar;
+ obj = JS_NewObjectClass(ctx, (int)js_zoneddatetime_class_id);
+ if (JS_IsException(obj)) {
+ js_free(ctx, s);
+ return JS_EXCEPTION;
+ }
+ JS_SetOpaque(obj, s);
+ return obj;
+}
+
+/* Apply timezone offset to UTC epoch seconds to get local wall-clock time */
+/* Create a ZonedDateTime from prepared fields */
+JSValue ti_create_zoneddatetime_from_fields(JSContext *ctx, TIPreparedFields *fields,
+ int overflow_constrain, JSValueConst options)
+{
+ int year, month, day, hour, minute, second, ms, us, ns;
+ int64_t offset_ns = 0;
+ const char *timeZone = "UTC";
+ JSTimeSpec ts;
+ int has_offset = 0;
+
+ if (fields->calendar == CAL_ISO8601 || fields->calendar == CAL_GREGORY) {
+ if (!(fields->present_mask & TI_FIELD_YEAR))
+ return JS_ThrowTypeError(ctx, "missing required property");
+ if (!(fields->present_mask & TI_FIELD_DAY))
+ return JS_ThrowTypeError(ctx, "missing required property");
+ if (!(fields->present_mask & (TI_FIELD_MONTH | TI_FIELD_MONTH_CODE)))
+ return JS_ThrowTypeError(ctx, "missing required property");
+ }
+
+ year = (int)fields->year;
+ month = (fields->present_mask & TI_FIELD_MONTH) ? fields->month : 0;
+ day = fields->day;
+
+ if (fields->present_mask & TI_FIELD_MONTH_CODE) {
+ if (fields->calendar == CAL_ISO8601) {
+ if (fields->month_from_code < 1 || fields->month_from_code > 12)
+ return JS_ThrowRangeError(ctx, "monthCode is not valid for ISO 8601 calendar");
+ if (fields->month_code_has_l)
+ return JS_ThrowRangeError(ctx, "monthCode is not valid for ISO 8601 calendar");
+ month = fields->month_from_code;
+ } else {
+ if (!ti_calendar_validate_month_code(fields->calendar, fields->month_from_code, fields->month_code_has_l))
+ return JS_ThrowRangeError(ctx, "monthCode is not valid for this calendar");
+ if (!(fields->present_mask & TI_FIELD_MONTH))
+ month = fields->month_from_code;
+ }
+ }
+
+ if ((fields->calendar == CAL_ISO8601 || fields->calendar == CAL_GREGORY) &&
+ (fields->present_mask & TI_FIELD_MONTH_CODE) && (fields->present_mask & TI_FIELD_MONTH) &&
+ fields->month != fields->month_from_code)
+ return JS_ThrowRangeError(ctx, "month and monthCode must agree");
+
+ if (month <= 0)
+ return JS_ThrowRangeError(ctx, "month must be positive");
+ if (day <= 0)
+ return JS_ThrowRangeError(ctx, "day must be positive");
+
+ hour = (fields->present_mask & TI_FIELD_HOUR) ? fields->hour : 0;
+ minute = (fields->present_mask & TI_FIELD_MINUTE) ? fields->minute : 0;
+ second = (fields->present_mask & TI_FIELD_SECOND) ? fields->second : 0;
+ ms = (fields->present_mask & TI_FIELD_MILLISECOND) ? fields->millisecond : 0;
+ us = (fields->present_mask & TI_FIELD_MICROSECOND) ? fields->microsecond : 0;
+ ns = (fields->present_mask & TI_FIELD_NANOSECOND) ? fields->nanosecond : 0;
+
+ if (!overflow_constrain) {
+ if (hour < 0 || hour > 23)
+ return JS_ThrowRangeError(ctx, "invalid hour");
+ if (minute < 0 || minute > 59)
+ return JS_ThrowRangeError(ctx, "invalid minute");
+ if (second < 0 || second > 59)
+ return JS_ThrowRangeError(ctx, "invalid second");
+ if (ms < 0 || ms > 999)
+ return JS_ThrowRangeError(ctx, "invalid millisecond");
+ if (us < 0 || us > 999)
+ return JS_ThrowRangeError(ctx, "invalid microsecond");
+ if (ns < 0 || ns > 999)
+ return JS_ThrowRangeError(ctx, "invalid nanosecond");
+ } else {
+ if (hour > 23) hour = 23; else if (hour < 0) hour = 0;
+ if (minute > 59) minute = 59; else if (minute < 0) minute = 0;
+ if (second > 59) second = 59; else if (second < 0) second = 0;
+ if (ms > 999) ms = 999; else if (ms < 0) ms = 0;
+ if (us > 999) us = 999; else if (us < 0) us = 0;
+ if (ns > 999) ns = 999; else if (ns < 0) ns = 0;
+ }
+
+ if (!pd_is_valid_date(year, month, day)) {
+ if (!overflow_constrain)
+ return JS_ThrowRangeError(ctx, "invalid ZonedDateTime");
+ if (month > 12) month = 12;
+ else if (month < 1) month = 1;
+ {
+ int dim = pd_days_in_month(year, month);
+ if (day > dim) day = dim;
+ else if (day < 1) day = 1;
+ }
+ }
+
+ /* Get timeZone */
+ if (fields->present_mask & TI_FIELD_TIMEZONE) {
+ if (fields->time_zone[0])
+ timeZone = fields->time_zone;
+ }
+
+ /* Use offset if present */
+ if (fields->present_mask & TI_FIELD_OFFSET) {
+ offset_ns = fields->offset_ns;
+ has_offset = 1;
+ }
+
+ /* Compute local seconds */
+ {
+ int64_t days = pdt_to_ordinal_days(year, month, day);
+ int64_t local_sec = (days - 719162) * 86400LL + hour * 3600LL + minute * 60LL + second;
+ int local_nsec = ms * 1000000 + us * 1000 + ns;
+ int64_t tz_offset_ns = 0;
+
+ /* Get timezone offset */
+ {
+ int ret = ti_parse_temporal_timezone_string(timeZone, &tz_offset_ns);
+ if (ret < 0)
+ return JS_ThrowRangeError(ctx, "invalid timeZone");
+ }
+
+ /* For named timezones, look up the exact offset */
+ {
+ int tz_id = ti_tz_find_id(timeZone);
+ if (tz_id >= 0) {
+ int iter;
+ ts.secs = local_sec;
+ for (iter = 0; iter < 4; iter++) {
+ int offset_sec = ti_tz_offset_at_sec(tz_id, ts.secs);
+ int64_t new_sec = local_sec - offset_sec;
+ if (new_sec == ts.secs)
+ break;
+ ts.secs = new_sec;
+ }
+ tz_offset_ns = ti_tz_offset_at_sec(tz_id, ts.secs) * 1000000000LL;
+ }
+ }
+
+ /* Apply offset: UTC = local - offset */
+ if (has_offset) {
+ /* If options say "use", use property offset; otherwise validate */
+ int use_prop_offset = 0;
+ if (!JS_IsUndefined(options) && !JS_IsNull(options)) {
+ JSValue opt_offset = JS_GetPropertyStr(ctx, options, "offset");
+ if (JS_IsException(opt_offset))
+ return JS_EXCEPTION;
+ if (!JS_IsUndefined(opt_offset)) {
+ const char *ostr = JS_ToCString(ctx, opt_offset);
+ if (ostr) {
+ if (strcmp(ostr, "use") == 0)
+ use_prop_offset = 1;
+ JS_FreeCString(ctx, ostr);
+ }
+ }
+ JS_FreeValue(ctx, opt_offset);
+ }
+ if (use_prop_offset) {
+ tz_offset_ns = offset_ns;
+ } else {
+ /* Validate property bag offset against timezone (default = exact reject) */
+ if (offset_ns != tz_offset_ns)
+ return JS_ThrowRangeError(ctx, "offset does not match time zone");
+ }
+ }
+
+ {
+ int64_t offset_sec = tz_offset_ns / 1000000000LL;
+ int offset_nsec = (int)(tz_offset_ns % 1000000000LL);
+ ts.secs = local_sec - offset_sec;
+ {
+ int new_nsec = local_nsec - offset_nsec;
+ if (new_nsec < 0) {
+ new_nsec += 1000000000;
+ ts.secs -= 1;
+ } else if (new_nsec >= 1000000000) {
+ new_nsec -= 1000000000;
+ ts.secs += 1;
+ }
+ ts.nsecs = (uint32_t)new_nsec;
+ }
+ }
+ }
+
+ if (!is_valid_epoch_timespec(&ts))
+ return JS_ThrowRangeError(ctx, "epoch nanoseconds outside valid limits");
+
+ return js_create_zoneddatetime(ctx, &ts, timeZone, fields->calendar);
+}
+static void zdt_apply_timezone_offset(JSContext *ctx, JSZonedDateTimeData *s,
+ int64_t *epoch_sec, int *epoch_nsec)
+{
+ int tz_id = ti_tz_find_id(s->timeZone);
+ if (tz_id >= 0) {
+ int offset_sec = ti_tz_offset_at_sec(tz_id, *epoch_sec);
+ *epoch_sec += offset_sec;
+ } else {
+ int64_t offset_ns = 0;
+ int ret = ti_parse_temporal_timezone_string(s->timeZone, &offset_ns);
+ if (ret == 0) {
+ int64_t offset_sec = offset_ns / 1000000000LL;
+ int offset_nsec = (int)(offset_ns % 1000000000LL);
+ *epoch_sec += offset_sec;
+ *epoch_nsec += offset_nsec;
+ if (*epoch_nsec >= 1000000000) {
+ *epoch_nsec -= 1000000000;
+ *epoch_sec += 1;
+ } else if (*epoch_nsec < 0) {
+ *epoch_nsec += 1000000000;
+ *epoch_sec -= 1;
+ }
+ }
+ }
+}
+
+/* Convert local wall-clock time to UTC epoch by subtracting timezone offset.
+ For named timezones, iterates to find the correct epoch. */
+/* Temporal.ZonedDateTime constructor */
+static JSValue js_zoneddatetime_constructor(JSContext *ctx, JSValueConst new_target,
+ int argc, JSValueConst *argv)
+{
+ JSZonedDateTimeData *s;
+ JSValue obj;
+ JSTimeSpec ts;
+ const char *timeZone = "UTC";
+ CalendarType calendar = CAL_ISO8601;
+ int tz_allocated = 0;
+ if (JS_IsUndefined(new_target)) {
+ return JS_ThrowTypeError(ctx, "Temporal.ZonedDateTime constructor cannot be called as a function");
+ }
+ if (ti_bigint_to_timespec(ctx, argv[0], &ts) < 0)
+ return JS_EXCEPTION;
+ if (!is_valid_epoch_timespec(&ts))
+ return JS_ThrowRangeError(ctx, "epochNanoseconds out of range");
+ {
+ int tz_res = ti_validate_timezone_identifier(ctx, argc > 1 ? argv[1] : JS_UNDEFINED, &timeZone);
+ if (tz_res < 0)
+ return JS_EXCEPTION;
+ if (tz_res == 1)
+ tz_allocated = 1;
+ }
+ if (argc > 2) {
+ int cal_res = ti_validate_constructor_calendar(ctx, argv[2], &calendar);
+ if (cal_res < 0) {
+ if (tz_allocated) JS_FreeCString(ctx, timeZone);
+ return JS_EXCEPTION;
+ }
+ }
+ s = js_mallocz(ctx, sizeof(*s));
+ if (!s) {
+ if (tz_allocated) JS_FreeCString(ctx, timeZone);
+ return JS_EXCEPTION;
+ }
+ s->ts = ts;
+ pstrcpy(s->timeZone, sizeof(s->timeZone), timeZone);
+ s->calendar = calendar;
+ obj = js_create_temporal_object(ctx, new_target, js_zoneddatetime_class_id, s);
+ if (JS_IsException(obj)) {
+ js_free(ctx, s);
+ if (tz_allocated) JS_FreeCString(ctx, timeZone);
+ return JS_EXCEPTION;
+ }
+ if (tz_allocated) JS_FreeCString(ctx, timeZone);
+ return obj;
+}
+
+/* Getters for epoch values */
+static JSValue js_zoneddatetime_get_epochNanoseconds(JSContext *ctx, JSValueConst this_val)
+{
+ JSZonedDateTimeData *s = JS_GetOpaque2(ctx, this_val, js_zoneddatetime_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ return ti_timespec_to_bigint(ctx, &s->ts);
+}
+
+static JSValue js_zoneddatetime_get_epochMilliseconds(JSContext *ctx, JSValueConst this_val)
+{
+ JSZonedDateTimeData *s = JS_GetOpaque2(ctx, this_val, js_zoneddatetime_class_id);
+ js_int128_t total_ns;
+ int64_t ms;
+ if (!s)
+ return JS_EXCEPTION;
+ total_ns = ti_timespec_to_ns(&s->ts);
+ ms = (int64_t)(total_ns / 1000000);
+ if (total_ns < 0 && total_ns % 1000000 != 0)
+ ms -= 1;
+ return JS_NewInt64(ctx, ms);
+}
+
+static JSValue js_zoneddatetime_get_timeZoneId(JSContext *ctx, JSValueConst this_val)
+{
+ JSZonedDateTimeData *s = JS_GetOpaque2(ctx, this_val, js_zoneddatetime_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ return JS_NewString(ctx, s->timeZone);
+}
+
+static JSValue js_zoneddatetime_get_calendarId(JSContext *ctx, JSValueConst this_val)
+{
+ JSZonedDateTimeData *s = JS_GetOpaque2(ctx, this_val, js_zoneddatetime_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ return JS_NewString(ctx, ti_calendar_enum_to_string(s->calendar));
+}
+
+/* Getters for date/time components (apply timezone offset for local wall-clock time) */
+/* Getters for date/time components (apply timezone offset for local wall-clock time) */
+static BOOL zdt_get_local_fields(JSContext *ctx, JSValueConst this_val,
+ int64_t *year, int *month, int *day,
+ int *hour, int *minute, int *second,
+ JSZonedDateTimeData **ps)
+{
+ JSZonedDateTimeData *s = JS_GetOpaque2(ctx, this_val, js_zoneddatetime_class_id);
+ int64_t epoch_sec;
+ int epoch_nsec;
+ if (!s)
+ return FALSE;
+ epoch_sec = s->ts.secs;
+ epoch_nsec = (int)s->ts.nsecs;
+ zdt_apply_timezone_offset(ctx, s, &epoch_sec, &epoch_nsec);
+ ti_epoch_sec_to_date(epoch_sec, year, month, day, hour, minute, second);
+ if (ps)
+ *ps = s;
+ return TRUE;
+}
+
+static JSValue js_zoneddatetime_get_year(JSContext *ctx, JSValueConst this_val)
+{
+ int64_t year;
+ int month, day, hour, minute, second;
+ JSZonedDateTimeData *s;
+ int cal_year, cal_month, cal_day;
+ if (!zdt_get_local_fields(ctx, this_val, &year, &month, &day, &hour, &minute, &second, &s))
+ return JS_EXCEPTION;
+ cal_year = (int)year; cal_month = month; cal_day = day;
+ ti_iso_to_calendar_date(s->calendar, (int)year, month, day, &cal_year, &cal_month, &cal_day);
+ return JS_NewInt64(ctx, cal_year);
+}
+
+
+static JSValue js_zoneddatetime_get_month(JSContext *ctx, JSValueConst this_val)
+{
+ int64_t year;
+ int month, day, hour, minute, second;
+ JSZonedDateTimeData *s;
+ int cal_year, cal_month, cal_day;
+ if (!zdt_get_local_fields(ctx, this_val, &year, &month, &day, &hour, &minute, &second, &s))
+ return JS_EXCEPTION;
+ cal_year = (int)year; cal_month = month; cal_day = day;
+ ti_iso_to_calendar_date(s->calendar, (int)year, month, day, &cal_year, &cal_month, &cal_day);
+ return JS_NewInt32(ctx, cal_month);
+}
+
+
+static JSValue js_zoneddatetime_get_day(JSContext *ctx, JSValueConst this_val)
+{
+ int64_t year;
+ int month, day, hour, minute, second;
+ JSZonedDateTimeData *s;
+ int cal_year, cal_month, cal_day;
+ if (!zdt_get_local_fields(ctx, this_val, &year, &month, &day, &hour, &minute, &second, &s))
+ return JS_EXCEPTION;
+ cal_year = (int)year; cal_month = month; cal_day = day;
+ ti_iso_to_calendar_date(s->calendar, (int)year, month, day, &cal_year, &cal_month, &cal_day);
+ return JS_NewInt32(ctx, cal_day);
+}
+
+
+static JSValue js_zoneddatetime_get_hour(JSContext *ctx, JSValueConst this_val)
+{
+ int64_t year;
+ int month, day, hour, minute, second;
+ if (!zdt_get_local_fields(ctx, this_val, &year, &month, &day, &hour, &minute, &second, NULL))
+ return JS_EXCEPTION;
+ return JS_NewInt32(ctx, hour);
+}
+
+
+static JSValue js_zoneddatetime_get_minute(JSContext *ctx, JSValueConst this_val)
+{
+ int64_t year;
+ int month, day, hour, minute, second;
+ if (!zdt_get_local_fields(ctx, this_val, &year, &month, &day, &hour, &minute, &second, NULL))
+ return JS_EXCEPTION;
+ return JS_NewInt32(ctx, minute);
+}
+
+
+static JSValue js_zoneddatetime_get_second(JSContext *ctx, JSValueConst this_val)
+{
+ int64_t year;
+ int month, day, hour, minute, second;
+ if (!zdt_get_local_fields(ctx, this_val, &year, &month, &day, &hour, &minute, &second, NULL))
+ return JS_EXCEPTION;
+ return JS_NewInt32(ctx, second);
+}
+
+
+static JSValue js_zoneddatetime_get_millisecond(JSContext *ctx, JSValueConst this_val)
+{
+ JSZonedDateTimeData *s = JS_GetOpaque2(ctx, this_val, js_zoneddatetime_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ return JS_NewInt32(ctx, s->ts.nsecs / 1000000);
+}
+
+
+static JSValue js_zoneddatetime_get_microsecond(JSContext *ctx, JSValueConst this_val)
+{
+ JSZonedDateTimeData *s = JS_GetOpaque2(ctx, this_val, js_zoneddatetime_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ return JS_NewInt32(ctx, (s->ts.nsecs / 1000) % 1000);
+}
+
+
+static JSValue js_zoneddatetime_get_nanosecond(JSContext *ctx, JSValueConst this_val)
+{
+ JSZonedDateTimeData *s = JS_GetOpaque2(ctx, this_val, js_zoneddatetime_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ return JS_NewInt32(ctx, s->ts.nsecs % 1000);
+}
+
+
+static JSValue js_zoneddatetime_get_offset(JSContext *ctx, JSValueConst this_val)
+{
+ JSZonedDateTimeData *s = JS_GetOpaque2(ctx, this_val, js_zoneddatetime_class_id);
+ int64_t offset_ns;
+ int tz_id;
+ char buf[16];
+ if (!s)
+ return JS_EXCEPTION;
+ tz_id = ti_tz_find_id(s->timeZone);
+ if (tz_id >= 0) {
+ int offset_sec = ti_tz_offset_at_sec(tz_id, s->ts.secs);
+ offset_ns = (int64_t)offset_sec * 1000000000LL;
+ } else {
+ int ret = ti_parse_temporal_timezone_string(s->timeZone, &offset_ns);
+ if (ret != 0)
+ offset_ns = 0;
+ }
+ {
+ int64_t off_sec = offset_ns / 1000000000LL;
+ int64_t abs_sec = off_sec >= 0 ? off_sec : -off_sec;
+ int hours = (int)(abs_sec / 3600);
+ int mins = (int)((abs_sec % 3600) / 60);
+ int secs = (int)(abs_sec % 60);
+ if (secs)
+ snprintf(buf, sizeof(buf), "%c%02d:%02d:%02d",
+ off_sec >= 0 ? '+' : '-', hours, mins, secs);
+ else
+ snprintf(buf, sizeof(buf), "%c%02d:%02d",
+ off_sec >= 0 ? '+' : '-', hours, mins);
+ return JS_NewString(ctx, buf);
+ }
+}
+
+static JSValue js_zoneddatetime_get_offsetNanoseconds(JSContext *ctx, JSValueConst this_val)
+{
+ JSZonedDateTimeData *s = JS_GetOpaque2(ctx, this_val, js_zoneddatetime_class_id);
+ int64_t offset_ns;
+ int tz_id;
+ if (!s)
+ return JS_EXCEPTION;
+ tz_id = ti_tz_find_id(s->timeZone);
+ if (tz_id >= 0) {
+ int offset_sec = ti_tz_offset_at_sec(tz_id, s->ts.secs);
+ offset_ns = (int64_t)offset_sec * 1000000000LL;
+ } else {
+ int ret = ti_parse_temporal_timezone_string(s->timeZone, &offset_ns);
+ if (ret != 0)
+ offset_ns = 0;
+ }
+ return JS_NewInt64(ctx, offset_ns);
+}
+
+static JSValue js_zoneddatetime_get_era(JSContext *ctx, JSValueConst this_val)
+{
+ int64_t year;
+ int month, day, hour, minute, second;
+ JSZonedDateTimeData *s;
+ int cal_year, cal_m, cal_d;
+ TIEra era;
+ int dummy_era_year;
+ if (!zdt_get_local_fields(ctx, this_val, &year, &month, &day, &hour, &minute, &second, &s))
+ return JS_EXCEPTION;
+ if (s->calendar == CAL_ISO8601)
+ return JS_UNDEFINED;
+ cal_year = (int)year; cal_m = month; cal_d = day;
+ ti_iso_to_calendar_date(s->calendar, (int)year, month, day, &cal_year, &cal_m, &cal_d);
+ ti_calendar_era_and_era_year(s->calendar, (int)year, month, day, cal_year, &era, &dummy_era_year);
+ if (era != TI_ERA_UNKNOWN)
+ return JS_NewString(ctx, ti_era_to_string(era));
+ return JS_UNDEFINED;
+}
+
+
+static JSValue js_zoneddatetime_get_eraYear(JSContext *ctx, JSValueConst this_val)
+{
+ int64_t year;
+ int month, day, hour, minute, second;
+ JSZonedDateTimeData *s;
+ int cal_year, cal_m, cal_d;
+ TIEra era;
+ int era_year;
+ if (!zdt_get_local_fields(ctx, this_val, &year, &month, &day, &hour, &minute, &second, &s))
+ return JS_EXCEPTION;
+ if (s->calendar == CAL_ISO8601)
+ return JS_UNDEFINED;
+ cal_year = (int)year; cal_m = month; cal_d = day;
+ ti_iso_to_calendar_date(s->calendar, (int)year, month, day, &cal_year, &cal_m, &cal_d);
+ ti_calendar_era_and_era_year(s->calendar, (int)year, month, day, cal_year, &era, &era_year);
+ if (era != TI_ERA_UNKNOWN)
+ return JS_NewInt32(ctx, era_year);
+ return JS_UNDEFINED;
+}
+
+
+static JSValue js_zoneddatetime_get_monthCode(JSContext *ctx, JSValueConst this_val)
+{
+ int64_t year;
+ int month, day, hour, minute, second;
+ JSZonedDateTimeData *s;
+ int cal_year, cal_m, cal_d;
+ if (!zdt_get_local_fields(ctx, this_val, &year, &month, &day, &hour, &minute, &second, &s))
+ return JS_EXCEPTION;
+ cal_year = (int)year; cal_m = month; cal_d = day;
+ ti_iso_to_calendar_date(s->calendar, (int)year, month, day, &cal_year, &cal_m, &cal_d);
+ return ti_get_month_code(ctx, s->calendar, cal_year, cal_m);
+}
+
+
+
+static JSValue js_zoneddatetime_get_inLeapYear(JSContext *ctx, JSValueConst this_val)
+{
+ int64_t year;
+ int month, day, hour, minute, second;
+ JSZonedDateTimeData *s;
+ int cal_year, cal_m, cal_d;
+ if (!zdt_get_local_fields(ctx, this_val, &year, &month, &day, &hour, &minute, &second, &s))
+ return JS_EXCEPTION;
+ cal_year = (int)year; cal_m = month; cal_d = day;
+ ti_iso_to_calendar_date(s->calendar, (int)year, month, day, &cal_year, &cal_m, &cal_d);
+ return JS_NewBool(ctx, ti_calendar_is_leap_year(s->calendar, cal_year));
+}
+
+
+static JSValue js_zoneddatetime_get_daysInYear(JSContext *ctx, JSValueConst this_val)
+{
+ int64_t year;
+ int month, day, hour, minute, second;
+ JSZonedDateTimeData *s;
+ int cal_year, cal_m, cal_d;
+ if (!zdt_get_local_fields(ctx, this_val, &year, &month, &day, &hour, &minute, &second, &s))
+ return JS_EXCEPTION;
+ cal_year = (int)year; cal_m = month; cal_d = day;
+ ti_iso_to_calendar_date(s->calendar, (int)year, month, day, &cal_year, &cal_m, &cal_d);
+ return JS_NewInt32(ctx, ti_calendar_days_in_year(s->calendar, cal_year));
+}
+
+
+static JSValue js_zoneddatetime_get_daysInWeek(JSContext *ctx, JSValueConst this_val)
+{
+ JSZonedDateTimeData *s = JS_GetOpaque2(ctx, this_val, js_zoneddatetime_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ return JS_NewInt32(ctx, 7);
+}
+
+static JSValue js_zoneddatetime_get_monthsInYear(JSContext *ctx, JSValueConst this_val)
+{
+ int64_t year;
+ int month, day, hour, minute, second;
+ JSZonedDateTimeData *s;
+ int cal_year, cal_m, cal_d;
+ if (!zdt_get_local_fields(ctx, this_val, &year, &month, &day, &hour, &minute, &second, &s))
+ return JS_EXCEPTION;
+ cal_year = (int)year; cal_m = month; cal_d = day;
+ ti_iso_to_calendar_date(s->calendar, (int)year, month, day, &cal_year, &cal_m, &cal_d);
+ return JS_NewInt32(ctx, ti_calendar_months_in_year(s->calendar, cal_year));
+}
+
+
+static JSValue js_zoneddatetime_get_hoursInDay(JSContext *ctx, JSValueConst this_val)
+{
+ JSZonedDateTimeData *s = JS_GetOpaque2(ctx, this_val, js_zoneddatetime_class_id);
+ int64_t offset_sec;
+ int64_t local_sec, day_number;
+ int64_t start_today_utc, start_tomorrow_utc;
+ JSTimeSpec today_ts, tomorrow_ts;
+ int tz_id;
+
+ if (!s)
+ return JS_EXCEPTION;
+
+ tz_id = ti_tz_find_id(s->timeZone);
+ if (tz_id >= 0) {
+ offset_sec = ti_tz_offset_at_sec(tz_id, s->ts.secs);
+ } else {
+ int64_t offset_ns = 0;
+ int ret = ti_parse_temporal_timezone_string(s->timeZone, &offset_ns);
+ if (ret < 0)
+ return JS_ThrowRangeError(ctx, "invalid time zone");
+ offset_sec = offset_ns / 1000000000LL;
+ }
+
+ local_sec = s->ts.secs + offset_sec;
+ day_number = floor_div64(local_sec, 86400LL);
+
+ if (tz_id >= 0) {
+ start_today_utc = ti_get_start_of_day_sec(tz_id, day_number * 86400LL);
+ if (start_today_utc == INT64_MIN)
+ return JS_ThrowRangeError(ctx, "multiple instants found");
+ start_tomorrow_utc = ti_get_start_of_day_sec(tz_id, (day_number + 1) * 86400LL);
+ if (start_tomorrow_utc == INT64_MIN)
+ return JS_ThrowRangeError(ctx, "multiple instants found");
+ } else {
+ start_today_utc = day_number * 86400LL - offset_sec;
+ start_tomorrow_utc = (day_number + 1) * 86400LL - offset_sec;
+ }
+
+ today_ts.secs = start_today_utc;
+ today_ts.nsecs = 0;
+ tomorrow_ts.secs = start_tomorrow_utc;
+ tomorrow_ts.nsecs = 0;
+
+ if (!is_valid_epoch_timespec(&today_ts) || !is_valid_epoch_timespec(&tomorrow_ts))
+ return JS_ThrowRangeError(ctx, "hoursInDay out of range");
+
+ return JS_NewFloat64(ctx, (double)(start_tomorrow_utc - start_today_utc) / 3600.0);
+}
+
+
+/* ISO day of week: 1=Monday, 7=Sunday */
+static int zdt_iso_day_of_week(int year, int month, int day)
+{
+ /* Using Zeller's congruence variant for Gregorian calendar */
+ int a = (14 - month) / 12;
+ int y = year - a;
+ int m = month + 12 * a - 2;
+ int d = (day + y + y / 4 - y / 100 + y / 400 + (31 * m) / 12) % 7;
+ /* d: 0=Sunday, 1=Monday, ..., 6=Saturday */
+ return (d == 0) ? 7 : d;
+}
+
+/* ISO week computation: week 1 contains the first Thursday */
+static void zdt_iso_week(int year, int month, int day, int *weekYear, int *weekNumber)
+{
+ int dow = zdt_iso_day_of_week(year, month, day);
+ int ordinal = day;
+ int m;
+ for (m = 1; m < month; m++) {
+ ordinal += pd_days_in_month(year, m);
+ }
+ /* Find Thursday of current week */
+ int thursdayOrdinal = ordinal + (4 - dow);
+ /* Year of the Thursday */
+ int y = year;
+ int daysInY = pd_is_leap_year(y) ? 366 : 365;
+ if (thursdayOrdinal <= 0) {
+ y = year - 1;
+ daysInY = pd_is_leap_year(y) ? 366 : 365;
+ thursdayOrdinal += daysInY;
+ } else if (thursdayOrdinal > daysInY) {
+ thursdayOrdinal -= daysInY;
+ y = year + 1;
+ }
+ *weekYear = y;
+ *weekNumber = (thursdayOrdinal - 1) / 7 + 1;
+}
+
+static JSValue js_zoneddatetime_get_weekOfYear(JSContext *ctx, JSValueConst this_val)
+{
+ int64_t year;
+ int month, day, hour, minute, second;
+ int weekYear, weekNumber;
+ JSZonedDateTimeData *s;
+ if (!zdt_get_local_fields(ctx, this_val, &year, &month, &day, &hour, &minute, &second, &s))
+ return JS_EXCEPTION;
+ if (s->calendar != CAL_ISO8601)
+ return JS_UNDEFINED;
+ if (year < 1 || year > 9999)
+ return JS_UNDEFINED;
+ zdt_iso_week((int)year, month, day, &weekYear, &weekNumber);
+ return JS_NewInt32(ctx, weekNumber);
+}
+
+
+static JSValue js_zoneddatetime_get_yearOfWeek(JSContext *ctx, JSValueConst this_val)
+{
+ int64_t year;
+ int month, day, hour, minute, second;
+ int weekYear, weekNumber;
+ JSZonedDateTimeData *s;
+ if (!zdt_get_local_fields(ctx, this_val, &year, &month, &day, &hour, &minute, &second, &s))
+ return JS_EXCEPTION;
+ if (s->calendar != CAL_ISO8601)
+ return JS_UNDEFINED;
+ if (year < 1 || year > 9999)
+ return JS_UNDEFINED;
+ zdt_iso_week((int)year, month, day, &weekYear, &weekNumber);
+ return JS_NewInt64(ctx, weekYear);
+}
+
+
+static JSValue js_zoneddatetime_get_daysInMonth(JSContext *ctx, JSValueConst this_val)
+{
+ int64_t year;
+ int month, day, hour, minute, second;
+ JSZonedDateTimeData *s;
+ int cal_year, cal_m, cal_d;
+ if (!zdt_get_local_fields(ctx, this_val, &year, &month, &day, &hour, &minute, &second, &s))
+ return JS_EXCEPTION;
+ cal_year = (int)year; cal_m = month; cal_d = day;
+ ti_iso_to_calendar_date(s->calendar, (int)year, month, day, &cal_year, &cal_m, &cal_d);
+ return JS_NewInt32(ctx, ti_calendar_days_in_month(s->calendar, cal_year, cal_m));
+}
+
+
+static JSValue js_zoneddatetime_get_dayOfYear(JSContext *ctx, JSValueConst this_val)
+{
+ int64_t year;
+ int month, day, hour, minute, second;
+ JSZonedDateTimeData *s;
+ int cal_year, cal_m, cal_d;
+ if (!zdt_get_local_fields(ctx, this_val, &year, &month, &day, &hour, &minute, &second, &s))
+ return JS_EXCEPTION;
+ cal_year = (int)year; cal_m = month; cal_d = day;
+ ti_iso_to_calendar_date(s->calendar, (int)year, month, day, &cal_year, &cal_m, &cal_d);
+ return JS_NewInt32(ctx, ti_calendar_day_of_year(s->calendar, cal_year, cal_m, cal_d));
+}
+
+
+static JSValue js_zoneddatetime_get_dayOfWeek(JSContext *ctx, JSValueConst this_val)
+{
+ int64_t year;
+ int month, day, hour, minute, second;
+ int a, y, m, d;
+ if (!zdt_get_local_fields(ctx, this_val, &year, &month, &day, &hour, &minute, &second, NULL))
+ return JS_EXCEPTION;
+ a = (14 - month) / 12;
+ y = (int)year - a;
+ m = month + 12 * a - 2;
+ d = (day + y + y / 4 - y / 100 + y / 400 + (31 * m) / 12) % 7;
+ return JS_NewInt32(ctx, (d == 0) ? 7 : d);
+}
+
+
+JSValue js_zoneddatetime_from(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv);
+
+static JSValue js_zoneddatetime_compare(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ (void)argc;
+ (void)this_val;
+ JSValue a_val, b_val;
+ JSZonedDateTimeData *a, *b;
+ js_int128_t ns_a, ns_b;
+ a_val = js_zoneddatetime_from(ctx, JS_UNDEFINED, 1, argv);
+ if (JS_IsException(a_val))
+ return JS_EXCEPTION;
+ b_val = js_zoneddatetime_from(ctx, JS_UNDEFINED, 1, &argv[1]);
+ if (JS_IsException(b_val)) {
+ JS_FreeValue(ctx, a_val);
+ return JS_EXCEPTION;
+ }
+ a = JS_GetOpaque(a_val, js_zoneddatetime_class_id);
+ b = JS_GetOpaque(b_val, js_zoneddatetime_class_id);
+ if (!a || !b) {
+ JS_FreeValue(ctx, a_val);
+ JS_FreeValue(ctx, b_val);
+ return JS_ThrowTypeError(ctx, "invalid ZonedDateTime");
+ }
+ ns_a = ti_timespec_to_ns(&a->ts);
+ ns_b = ti_timespec_to_ns(&b->ts);
+ JS_FreeValue(ctx, a_val);
+ JS_FreeValue(ctx, b_val);
+ if (ns_a < ns_b)
+ return JS_NewInt32(ctx, -1);
+ if (ns_a > ns_b)
+ return JS_NewInt32(ctx, 1);
+ return JS_NewInt32(ctx, 0);
+}
+
+static JSValue js_zoneddatetime_withCalendar(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ (void)argc;
+ JSZonedDateTimeData *s = JS_GetOpaque2(ctx, this_val, js_zoneddatetime_class_id);
+ JSZonedDateTimeData *t;
+ JSValue obj;
+ CalendarType cal;
+ if (!s)
+ return JS_EXCEPTION;
+ if (ti_resolve_calendar_value(ctx, argv[0], &cal) < 0)
+ return JS_EXCEPTION;
+ t = js_mallocz(ctx, sizeof(*t));
+ if (!t)
+ return JS_EXCEPTION;
+ *t = *s;
+ t->calendar = cal;
+ obj = JS_NewObjectClass(ctx, (int)js_zoneddatetime_class_id);
+ if (JS_IsException(obj)) {
+ js_free(ctx, t);
+ return JS_EXCEPTION;
+ }
+ JS_SetOpaque(obj, t);
+ return obj;
+}
+
+static JSValue js_zoneddatetime_startOfDay(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ (void)argc;
+ (void)argv;
+ JSZonedDateTimeData *s = JS_GetOpaque2(ctx, this_val, js_zoneddatetime_class_id);
+ int64_t local_sec;
+ JSTimeSpec ts;
+ int64_t offset_sec = 0;
+ int tz_id;
+ if (!s)
+ return JS_EXCEPTION;
+ /* Apply timezone offset to get local wall-clock time */
+ tz_id = ti_tz_find_id(s->timeZone);
+ if (tz_id >= 0) {
+ offset_sec = ti_tz_offset_at_sec(tz_id, s->ts.secs);
+ } else {
+ int64_t offset_ns = 0;
+ int ret = ti_parse_temporal_timezone_string(s->timeZone, &offset_ns);
+ if (ret == 0)
+ offset_sec = offset_ns / 1000000000LL;
+ }
+ local_sec = s->ts.secs + offset_sec;
+ /* Floor local time to start of local day */
+ {
+ int64_t days = local_sec / 86400LL;
+ if (local_sec < 0 && local_sec % 86400LL != 0)
+ days--;
+ ts.secs = days * 86400LL;
+ ts.nsecs = 0;
+ }
+ /* Convert local day start back to UTC, handling DST transitions at midnight */
+ if (tz_id >= 0) {
+ int64_t utc_sec = ti_get_start_of_day_sec(tz_id, ts.secs);
+ if (utc_sec == INT64_MIN)
+ return JS_ThrowRangeError(ctx, "multiple instants found");
+ ts.secs = utc_sec;
+ } else {
+ ts.secs -= offset_sec;
+ }
+ /* Validate epoch nanoseconds are within Instant limits */
+ {
+ js_int128_t epoch_ns = ti_timespec_to_ns(&ts);
+ js_int128_t limit = (js_int128_t)8640000000000LL * 1000000000LL;
+ if (epoch_ns < -limit || epoch_ns > limit)
+ return JS_ThrowRangeError(ctx, "epoch nanoseconds outside valid limits");
+ }
+ return js_create_zoneddatetime(ctx, &ts, s->timeZone, s->calendar);
+}
+
+static JSValue js_zoneddatetime_getTimeZoneTransition(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ (void)argc;
+ JSZonedDateTimeData *s = JS_GetOpaque2(ctx, this_val, js_zoneddatetime_class_id);
+ JSValue direction_val;
+ const char *str;
+ size_t len;
+ int is_next = -1;
+ int64_t trans_sec;
+ int tz_id;
+ JSTimeSpec ts;
+ if (!s)
+ return JS_EXCEPTION;
+ if (JS_IsUndefined(argv[0]))
+ return JS_ThrowTypeError(ctx, "getTimeZoneTransition requires a direction argument");
+ if (JS_IsString(argv[0])) {
+ str = JS_ToCStringLen(ctx, &len, argv[0]);
+ if (!str)
+ return JS_EXCEPTION;
+ if (len == strlen(str) && strcmp(str, "next") == 0)
+ is_next = 1;
+ else if (len == strlen(str) && strcmp(str, "previous") == 0)
+ is_next = 0;
+ JS_FreeCString(ctx, str);
+ if (is_next < 0)
+ return JS_ThrowRangeError(ctx, "invalid direction");
+ } else if (JS_IsObject(argv[0])) {
+ direction_val = JS_GetPropertyStr(ctx, argv[0], "direction");
+ if (JS_IsException(direction_val))
+ return JS_EXCEPTION;
+ if (JS_IsUndefined(direction_val))
+ return JS_ThrowRangeError(ctx, "invalid direction");
+ str = JS_ToCStringLen(ctx, &len, direction_val);
+ JS_FreeValue(ctx, direction_val);
+ if (!str)
+ return JS_EXCEPTION;
+ if (len == strlen(str) && strcmp(str, "next") == 0)
+ is_next = 1;
+ else if (len == strlen(str) && strcmp(str, "previous") == 0)
+ is_next = 0;
+ JS_FreeCString(ctx, str);
+ if (is_next < 0)
+ return JS_ThrowRangeError(ctx, "invalid direction");
+ } else {
+ return JS_ThrowTypeError(ctx, "options must be an object");
+ }
+ tz_id = ti_tz_find_id(s->timeZone);
+ if (tz_id < 0)
+ return JS_NULL;
+ if (is_next)
+ trans_sec = ti_tz_next_transition_at(tz_id, s->ts.secs, (int)s->ts.nsecs);
+ else
+ trans_sec = ti_tz_prev_transition_at(tz_id, s->ts.secs, (int)s->ts.nsecs);
+ if (trans_sec == INT64_MIN)
+ return JS_NULL;
+ ts.secs = trans_sec;
+ ts.nsecs = 0;
+ return js_create_zoneddatetime(ctx, &ts, s->timeZone, s->calendar);
+}
+
+static void zdt_epoch_to_datetime(int64_t epoch_sec, int epoch_nsec,
+ int *year, int *month, int *day,
+ int *hour, int *minute, int *second,
+ int *ms, int *us, int *ns)
+{
+ int64_t days = epoch_sec / 86400;
+ int64_t sec_of_day = epoch_sec % 86400;
+ if (sec_of_day < 0) {
+ sec_of_day += 86400;
+ days -= 1;
+ }
+ int64_t ordinal_1970 = pdt_to_ordinal_days(1970, 1, 1);
+ int64_t ordinal = ordinal_1970 + days;
+ pdt_from_ordinal_days(ordinal, year, month, day);
+ *hour = (int)(sec_of_day / 3600);
+ sec_of_day %= 3600;
+ *minute = (int)(sec_of_day / 60);
+ *second = (int)(sec_of_day % 60);
+ *ms = epoch_nsec / 1000000;
+ epoch_nsec %= 1000000;
+ *us = epoch_nsec / 1000;
+ *ns = epoch_nsec % 1000;
+}
+
+/* Convert a ZonedDateTime instant to local wall-clock ISO date/time */
+void ti_zoneddatetime_to_local(const char *timeZone, int64_t epoch_sec, int epoch_nsec,
+ int64_t *out_year, int *out_month, int *out_day,
+ int *out_hour, int *out_minute, int *out_second,
+ int *out_ms, int *out_us, int *out_ns)
+{
+ int64_t local_sec = epoch_sec;
+ int local_nsec = epoch_nsec;
+ int tz_id = ti_tz_find_id(timeZone);
+ if (tz_id >= 0) {
+ int offset_sec = ti_tz_offset_at_sec(tz_id, epoch_sec);
+ local_sec += offset_sec;
+ } else {
+ int64_t offset_ns = 0;
+ if (ti_parse_temporal_timezone_string(timeZone, &offset_ns) == 0) {
+ int64_t offset_sec = offset_ns / 1000000000LL;
+ int offset_nsec = (int)(offset_ns % 1000000000LL);
+ local_sec += offset_sec;
+ local_nsec += offset_nsec;
+ if (local_nsec >= 1000000000) {
+ local_nsec -= 1000000000;
+ local_sec += 1;
+ } else if (local_nsec < 0) {
+ local_nsec += 1000000000;
+ local_sec -= 1;
+ }
+ }
+ }
+ ti_epoch_sec_to_date(local_sec, out_year, out_month, out_day, out_hour, out_minute, out_second);
+ if (out_ms)
+ *out_ms = local_nsec / 1000000;
+ if (out_us)
+ *out_us = (local_nsec / 1000) % 1000;
+ if (out_ns)
+ *out_ns = local_nsec % 1000;
+}
+
+/* Spec AddZonedDateTime for ISO-like calendars.
+ Returns 0 on success, -1 on error. */
+int ti_zoneddatetime_add_duration_iso(const char *timeZone, CalendarType calendar,
+ JSTimeSpec origin, JSDurationData *duration,
+ int overflow_constrain, JSTimeSpec *out)
+{
+ /* Time-only path: exact instant arithmetic (AddInstant) */
+ if (duration->years == 0 && duration->months == 0 && duration->weeks == 0 && duration->days == 0) {
+ js_int128_t total_ns = ti_timespec_to_ns(&origin);
+ total_ns += ti_duration_time_fields_to_ns(duration);
+ js_int128_t limit = (js_int128_t)INSTANT_MAX_SECS * 1000000000LL;
+ if (total_ns < -limit || total_ns > limit)
+ return -1;
+ ti_ns_to_timespec(total_ns, out);
+ return 0;
+ }
+
+ /* Extract local wall-clock date/time */
+ int64_t year64;
+ int y, m, d, h, min, sec, ms, us, ns;
+ ti_zoneddatetime_to_local(timeZone, origin.secs, (int)origin.nsecs, &year64, &m, &d, &h, &min, &sec, &ms, &us, &ns);
+ y = (int)year64;
+
+ /* Add date portion in ISO-like calendar space */
+ int ay, am, ad;
+ if (ti_iso_calendar_date_add(y, m, d,
+ duration->years, duration->months, duration->weeks, duration->days,
+ &ay, &am, &ad) < 0) {
+ return -1;
+ }
+ if (!ti_is_date_within_iso_limits(ay, am, ad))
+ return -1;
+
+ /* Combine new date with original local time */
+ int64_t days = pdt_to_ordinal_days(ay, am, ad);
+ int64_t local_sec = (days - 719162) * 86400LL + h * 3600LL + min * 60LL + sec;
+ int local_nsec = ms * 1000000 + us * 1000 + ns;
+
+ /* Convert local back to UTC with compatible disambiguation */
+ int tz_id = ti_tz_find_id(timeZone);
+ int64_t utc_sec;
+ if (tz_id >= 0) {
+ int offset_sec;
+ if (ti_tz_local_to_utc(tz_id, local_sec, 2, &utc_sec, &offset_sec) < 0)
+ return -1;
+ } else {
+ int64_t offset_ns = 0;
+ if (ti_parse_temporal_timezone_string(timeZone, &offset_ns) < 0)
+ return -1;
+ int64_t offset_sec = offset_ns / 1000000000LL;
+ int offset_nsec = (int)(offset_ns % 1000000000LL);
+ utc_sec = local_sec - offset_sec;
+ local_nsec -= offset_nsec;
+ if (local_nsec < 0) {
+ local_nsec += 1000000000;
+ utc_sec -= 1;
+ } else if (local_nsec >= 1000000000) {
+ local_nsec -= 1000000000;
+ utc_sec += 1;
+ }
+ }
+
+ /* Add time portion via instant arithmetic (AddInstant) */
+ js_int128_t total_ns = ti_sec_nsec_to_ns(utc_sec, (uint32_t)local_nsec);
+ total_ns += ti_duration_time_fields_to_ns(duration);
+
+ js_int128_t limit = (js_int128_t)INSTANT_MAX_SECS * 1000000000LL;
+ if (total_ns < -limit || total_ns > limit)
+ return -1;
+
+ ti_ns_to_timespec(total_ns, out);
+ return 0;
+}
+
+/* Spec DifferenceZonedDateTime for ISO-like calendars.
+ Returns 0 on success, -1 on error. */
+int ti_zoneddatetime_difference_iso(const char *timeZone, CalendarType calendar,
+ JSTimeSpec start, JSTimeSpec end,
+ TIUnit largestUnit, JSDurationData *out)
+{
+ memset(out, 0, sizeof(*out));
+
+ /* Convert to wall-clock PlainDateTimes */
+ int64_t y1_64, y2_64;
+ int y1, m1, d1, h1, min1, sec1, ms1, us1, ns1;
+ int y2, m2, d2, h2, min2, sec2, ms2, us2, ns2;
+ ti_zoneddatetime_to_local(timeZone, start.secs, (int)start.nsecs, &y1_64, &m1, &d1, &h1, &min1, &sec1, &ms1, &us1, &ns1);
+ ti_zoneddatetime_to_local(timeZone, end.secs, (int)end.nsecs, &y2_64, &m2, &d2, &h2, &min2, &sec2, &ms2, &us2, &ns2);
+ y1 = (int)y1_64;
+ y2 = (int)y2_64;
+
+ js_int128_t ns1_128 = ti_timespec_to_ns(&start);
+ js_int128_t ns2_128 = ti_timespec_to_ns(&end);
+ js_int128_t nsDiff = ns2_128 - ns1_128;
+
+ if (largestUnit <= TI_UNIT_DAY) {
+ if (nsDiff == 0)
+ return 0;
+
+ int polyfill_sign = (nsDiff < 0) ? 1 : -1;
+
+ if (y1 == y2 && m1 == m2 && d1 == d2) {
+ /* Same wall-clock calendar day: return instant difference */
+ int sign = (nsDiff < 0) ? -1 : 1;
+ int64_t abs_ns = (int64_t)(nsDiff >= 0 ? nsDiff : -nsDiff);
+ int64_t total_seconds = abs_ns / 1000000000LL;
+ int64_t ns = abs_ns % 1000000000LL;
+ int64_t total_minutes = total_seconds / 60;
+ int64_t seconds = total_seconds % 60;
+ int64_t total_hours = total_minutes / 60;
+ int64_t minutes = total_minutes % 60;
+ int64_t hours = total_hours;
+ out->hours = sign * hours;
+ out->minutes = sign * minutes;
+ out->seconds = sign * seconds;
+ out->milliseconds = sign * (ns / 1000000LL);
+ ns %= 1000000LL;
+ out->microseconds.int128_value = sign * (ns / 1000LL);
+ out->nanoseconds.int128_value = sign * (ns % 1000LL);
+ } else {
+ /* dayCorrection algorithm per spec */
+ int dayCorrection = 0;
+ int maxDayCorrection = (polyfill_sign == -1) ? 2 : 1;
+ int64_t timeDiffNs = ((h2 - h1) * 3600LL + (min2 - min1) * 60LL + (sec2 - sec1)) * 1000000000LL
+ + (ms2 - ms1) * 1000000LL + (us2 - us1) * 1000LL + (ns2 - ns1);
+ int timeSign = (timeDiffNs < 0) ? -1 : (timeDiffNs > 0) ? 1 : 0;
+ if (timeSign == polyfill_sign)
+ dayCorrection++;
+
+ int int_y = y2, int_m = m2, int_d = d2;
+ int64_t remNs = 0;
+ int tz_id = ti_tz_find_id(timeZone);
+
+ for (; dayCorrection <= maxDayCorrection; dayCorrection++) {
+ int64_t end_days = pdt_to_ordinal_days(y2, m2, d2);
+ int64_t int_days = end_days + dayCorrection * polyfill_sign;
+ int64_t int_epoch_sec = (int_days - 719162) * 86400LL;
+ int64_t tmp_y64;
+ int tmp_h, tmp_min, tmp_sec;
+ ti_epoch_sec_to_date(int_epoch_sec, &tmp_y64, &int_m, &int_d, &tmp_h, &tmp_min, &tmp_sec);
+ int_y = (int)tmp_y64;
+
+ int64_t local_sec = (int_days - 719162) * 86400LL
+ + h1 * 3600LL + min1 * 60LL + sec1;
+ int local_nsec = ms1 * 1000000 + us1 * 1000 + ns1;
+
+ int64_t utc_sec;
+ if (tz_id >= 0) {
+ int offset_sec;
+ if (ti_tz_local_to_utc(tz_id, local_sec, 2, &utc_sec, &offset_sec) < 0)
+ return -1;
+ } else {
+ int64_t offset_ns = 0;
+ if (ti_parse_temporal_timezone_string(timeZone, &offset_ns) < 0)
+ return -1;
+ int64_t offset_sec = offset_ns / 1000000000LL;
+ utc_sec = local_sec - offset_sec;
+ }
+
+ js_int128_t intermediateNs = ti_sec_nsec_to_ns(utc_sec, (uint32_t)local_nsec);
+ remNs = (int64_t)(ns2_128 - intermediateNs);
+ int remSign = (remNs < 0) ? -1 : (remNs > 0) ? 1 : 0;
+ if (remSign != polyfill_sign) {
+ break;
+ }
+ }
+
+ TIUnit dateLargestUnit = (largestUnit <= TI_UNIT_DAY) ? largestUnit : TI_UNIT_DAY;
+ int64_t date_years = 0, date_months = 0, date_weeks = 0, date_days = 0;
+ ti_iso_calendar_date_until(y1, m1, d1, int_y, int_m, int_d,
+ dateLargestUnit,
+ &date_years, &date_months, &date_weeks, &date_days);
+
+ out->years = date_years;
+ out->months = date_months;
+ out->weeks = date_weeks;
+ out->days = date_days;
+
+ int sign = (remNs < 0) ? -1 : 1;
+ int64_t abs_ns = remNs >= 0 ? remNs : -remNs;
+ int64_t total_seconds = abs_ns / 1000000000LL;
+ int64_t ns = abs_ns % 1000000000LL;
+ int64_t total_minutes = total_seconds / 60;
+ int64_t seconds = total_seconds % 60;
+ int64_t total_hours = total_minutes / 60;
+ int64_t minutes = total_minutes % 60;
+ int64_t hours = total_hours;
+ out->hours = sign * hours;
+ out->minutes = sign * minutes;
+ out->seconds = sign * seconds;
+ out->milliseconds = sign * (ns / 1000000LL);
+ ns %= 1000000LL;
+ out->microseconds.int128_value = sign * (ns / 1000LL);
+ out->nanoseconds.int128_value = sign * (ns % 1000LL);
+ }
+ } else {
+ /* Time units: instant difference */
+ out->nanoseconds.int128_value = nsDiff;
+ ti_balance_time_duration(out, largestUnit);
+ }
+ return 0;
+}
+
+static JSValue js_zoneddatetime_difference(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv, int is_until)
+{
+ JSZonedDateTimeData *s = JS_GetOpaque2(ctx, this_val, js_zoneddatetime_class_id);
+ JSValue other_val;
+ JSZonedDateTimeData *other;
+ JSDurationData d = {0};
+ TIUnit largestUnit = TI_UNIT_INVALID;
+ TIUnit smallestUnit = TI_UNIT_INVALID;
+ int64_t roundingIncrement = 1;
+ TIRoundingMode roundingMode = ROUND_TRUNC;
+ if (!s)
+ return JS_EXCEPTION;
+ other_val = js_zoneddatetime_from(ctx, JS_UNDEFINED, 1, argv);
+ if (JS_IsException(other_val))
+ return JS_EXCEPTION;
+ other = JS_GetOpaque(other_val, js_zoneddatetime_class_id);
+ if (!other) {
+ JS_FreeValue(ctx, other_val);
+ return JS_ThrowTypeError(ctx, "invalid ZonedDateTime");
+ }
+ if (s->calendar != other->calendar) {
+ JS_FreeValue(ctx, other_val);
+ return JS_ThrowRangeError(ctx, "calendars must be the same");
+ }
+ JSTimeSpec other_ts = other->ts;
+ char other_tz[64];
+ pstrcpy(other_tz, sizeof(other_tz), other->timeZone);
+ JS_FreeValue(ctx, other_val);
+ other = NULL;
+ if (argc >= 2 && ti_validate_options_object(ctx, argv[1]) < 0)
+ return JS_EXCEPTION;
+ if (argc >= 2 && !JS_IsUndefined(argv[1])) {
+ if (ti_parse_unit_option(ctx, argv[1], "largestUnit", &largestUnit, TI_UNIT_OPT_ALLOW_UNDEFINED | TI_UNIT_OPT_ALLOW_AUTO, TI_UNIT_INVALID) < 0)
+ return JS_EXCEPTION;
+
+ if (ti_get_rounding_increment_option(ctx, argv[1], &roundingIncrement) < 0)
+ return JS_EXCEPTION;
+
+ if (ti_get_rounding_mode_option_default(ctx, argv[1], &roundingMode, ROUND_TRUNC) < 0)
+ return JS_EXCEPTION;
+
+ if (ti_parse_unit_option(ctx, argv[1], "smallestUnit", &smallestUnit, TI_UNIT_OPT_ALLOW_UNDEFINED, TI_UNIT_INVALID) < 0)
+ return JS_EXCEPTION;
+ }
+ if (smallestUnit == TI_UNIT_INVALID)
+ smallestUnit = TI_UNIT_NANOSECOND;
+ if (largestUnit == TI_UNIT_INVALID || largestUnit == TI_UNIT_AUTO)
+ largestUnit = (smallestUnit < TI_UNIT_HOUR) ? smallestUnit : TI_UNIT_HOUR;
+
+ if (largestUnit > smallestUnit) {
+ return JS_ThrowRangeError(ctx, "invalid unit combination");
+ }
+ if (largestUnit <= TI_UNIT_DAY && (s->ts.secs != other_ts.secs || s->ts.nsecs != other_ts.nsecs) &&
+ !ti_timezones_are_equal(s->timeZone, other_tz)) {
+ return JS_ThrowRangeError(ctx, "cannot compute difference between different time zones");
+ }
+
+ /* roundingIncrement validation for time units */
+ if (smallestUnit >= TI_UNIT_HOUR) {
+ int64_t maximum = 0;
+ switch (smallestUnit) {
+ case TI_UNIT_HOUR: maximum = 24; break;
+ case TI_UNIT_MINUTE: maximum = 60; break;
+ case TI_UNIT_SECOND: maximum = 60; break;
+ case TI_UNIT_MILLISECOND: maximum = 1000; break;
+ case TI_UNIT_MICROSECOND: maximum = 1000; break;
+ case TI_UNIT_NANOSECOND: maximum = 1000; break;
+ default: break;
+ }
+ if (maximum > 0 && (roundingIncrement >= maximum || maximum % roundingIncrement != 0))
+ return JS_ThrowRangeError(ctx, "roundingIncrement does not divide evenly into the unit");
+ }
+
+ /* Convert to wall-clock PlainDateTimes */
+ int64_t epoch_sec1 = s->ts.secs;
+ int epoch_nsec1 = (int)s->ts.nsecs;
+ zdt_apply_timezone_offset(ctx, s, &epoch_sec1, &epoch_nsec1);
+ int y1, m1, d1, h1, min1, sec1, ms1, us1, ns1;
+ zdt_epoch_to_datetime(epoch_sec1, epoch_nsec1, &y1, &m1, &d1, &h1, &min1, &sec1, &ms1, &us1, &ns1);
+
+ int64_t epoch_sec2 = other_ts.secs;
+ int epoch_nsec2 = (int)other_ts.nsecs;
+ JSZonedDateTimeData other_tmp = {0};
+ other_tmp.ts = other_ts;
+ pstrcpy(other_tmp.timeZone, sizeof(other_tmp.timeZone), other_tz);
+ zdt_apply_timezone_offset(ctx, &other_tmp, &epoch_sec2, &epoch_nsec2);
+ int y2, m2, d2, h2, min2, sec2, ms2, us2, ns2;
+ zdt_epoch_to_datetime(epoch_sec2, epoch_nsec2, &y2, &m2, &d2, &h2, &min2, &sec2, &ms2, &us2, &ns2);
+
+ js_int128_t diff_ns = ti_timespec_to_ns(&other_ts)
+ - ti_timespec_to_ns(&s->ts);
+
+ if (largestUnit <= TI_UNIT_DAY) {
+ if (s->calendar == CAL_ISO8601 || s->calendar == CAL_GREGORY ||
+ s->calendar == CAL_BUDDHIST || s->calendar == CAL_ROC || s->calendar == CAL_JAPANESE) {
+ /* Spec DifferenceZonedDateTime algorithm for ISO-like calendars */
+ js_int128_t ns1_128 = ti_timespec_to_ns(&s->ts);
+ js_int128_t ns2_128 = ti_timespec_to_ns(&other_ts);
+ js_int128_t nsDiff = ns2_128 - ns1_128;
+ if (nsDiff == 0) {
+ memset(&d, 0, sizeof(d));
+ } else {
+ int polyfill_sign = (nsDiff < 0) ? 1 : -1;
+ if (y1 == y2 && m1 == m2 && d1 == d2) {
+ /* Same wall-clock calendar day: return instant difference */
+ int sign = (nsDiff < 0) ? -1 : 1;
+ int64_t abs_ns = (int64_t)(nsDiff >= 0 ? nsDiff : -nsDiff);
+ int64_t total_seconds = abs_ns / 1000000000LL;
+ int64_t ns = abs_ns % 1000000000LL;
+ int64_t total_minutes = total_seconds / 60;
+ int64_t seconds = total_seconds % 60;
+ int64_t total_hours = total_minutes / 60;
+ int64_t minutes = total_minutes % 60;
+ int64_t hours = total_hours;
+ memset(&d, 0, sizeof(d));
+ d.hours = sign * hours;
+ d.minutes = sign * minutes;
+ d.seconds = sign * seconds;
+ d.milliseconds = sign * (ns / 1000000LL);
+ ns %= 1000000LL;
+ d.microseconds.int128_value = sign * (ns / 1000LL);
+ d.nanoseconds.int128_value = sign * (ns % 1000LL);
+ } else {
+ /* dayCorrection algorithm */
+ int dayCorrection = 0;
+ int maxDayCorrection = (polyfill_sign == -1) ? 2 : 1;
+ int64_t timeDiffNs = ((h2 - h1) * 3600LL + (min2 - min1) * 60LL + (sec2 - sec1)) * 1000000000LL
+ + (ms2 - ms1) * 1000000LL + (us2 - us1) * 1000LL + (ns2 - ns1);
+ int timeSign = (timeDiffNs < 0) ? -1 : (timeDiffNs > 0) ? 1 : 0;
+ if (timeSign == polyfill_sign) {
+ dayCorrection++;
+ }
+ int int_y = y2, int_m = m2, int_d = d2;
+ int64_t remNs = 0;
+ int found = 0;
+ for (; dayCorrection <= maxDayCorrection; dayCorrection++) {
+ int64_t end_days = pdt_to_ordinal_days(y2, m2, d2);
+ int64_t int_days = end_days + dayCorrection * polyfill_sign;
+ int64_t int_epoch_sec = (int_days - 719162) * 86400LL;
+ int64_t tmp_y64;
+ int tmp_h, tmp_min, tmp_sec;
+ ti_epoch_sec_to_date(int_epoch_sec, &tmp_y64, &int_m, &int_d,
+ &tmp_h, &tmp_min, &tmp_sec);
+ int_y = (int)tmp_y64;
+ int64_t local_sec = (int_days - 719162) * 86400LL
+ + h1 * 3600LL + min1 * 60LL + sec1;
+ int local_nsec = ms1 * 1000000 + us1 * 1000 + ns1;
+ int tz_id = ti_tz_find_id(s->timeZone);
+ int64_t utc_sec;
+ if (tz_id >= 0) {
+ int offset_sec;
+ if (ti_tz_local_to_utc(tz_id, local_sec, 2, &utc_sec, &offset_sec) < 0)
+ return JS_ThrowRangeError(ctx, "multiple instants found");
+ } else {
+ int64_t offset_ns = 0;
+ if (ti_parse_temporal_timezone_string(s->timeZone, &offset_ns) < 0)
+ return JS_ThrowRangeError(ctx, "unsupported time zone for difference");
+ int64_t offset_sec = offset_ns / 1000000000LL;
+ utc_sec = local_sec - offset_sec;
+ }
+ js_int128_t intermediateNs = ti_sec_nsec_to_ns(utc_sec, (uint32_t)local_nsec);
+ remNs = (int64_t)(ns2_128 - intermediateNs);
+ int remSign = (remNs < 0) ? -1 : (remNs > 0) ? 1 : 0;
+ if (remSign != polyfill_sign) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found) {
+ /* Should not happen per spec; use last remNs */
+ }
+ TIUnit dateLargestUnit = (largestUnit <= TI_UNIT_DAY) ? largestUnit : TI_UNIT_DAY;
+ int64_t date_years = 0, date_months = 0, date_weeks = 0, date_days = 0;
+ ti_iso_calendar_date_until(y1, m1, d1, int_y, int_m, int_d,
+ dateLargestUnit,
+ &date_years, &date_months, &date_weeks, &date_days);
+ memset(&d, 0, sizeof(d));
+ d.years = date_years;
+ d.months = date_months;
+ d.weeks = date_weeks;
+ d.days = date_days;
+ int sign = (remNs < 0) ? -1 : 1;
+ int64_t abs_ns = remNs >= 0 ? remNs : -remNs;
+ int64_t total_seconds = abs_ns / 1000000000LL;
+ int64_t ns = abs_ns % 1000000000LL;
+ int64_t total_minutes = total_seconds / 60;
+ int64_t seconds = total_seconds % 60;
+ int64_t total_hours = total_minutes / 60;
+ int64_t minutes = total_minutes % 60;
+ int64_t hours = total_hours;
+ d.hours = sign * hours;
+ d.minutes = sign * minutes;
+ d.seconds = sign * seconds;
+ d.milliseconds = sign * (ns / 1000000LL);
+ ns %= 1000000LL;
+ d.microseconds.int128_value = sign * (ns / 1000LL);
+ d.nanoseconds.int128_value = sign * (ns % 1000LL);
+ }
+ }
+ } else {
+ /* Non-ISO calendar: fallback to wall-clock PlainDateTime difference */
+ if (largestUnit == TI_UNIT_YEAR || largestUnit == TI_UNIT_MONTH) {
+ int s_cal_y, s_cal_m, s_cal_d;
+ int o_cal_y, o_cal_m, o_cal_d;
+ ti_iso_to_calendar_date(s->calendar, y1, m1, d1, &s_cal_y, &s_cal_m, &s_cal_d);
+ ti_iso_to_calendar_date(s->calendar, y2, m2, d2, &o_cal_y, &o_cal_m, &o_cal_d);
+ ti_calendar_datetime_difference(s->calendar,
+ s_cal_y, s_cal_m, s_cal_d, h1, min1, sec1, ms1, us1, ns1,
+ o_cal_y, o_cal_m, o_cal_d, h2, min2, sec2, ms2, us2, ns2,
+ largestUnit, &d);
+ } else {
+ ti_iso_datetime_difference(y1, m1, d1, h1, min1, sec1, ms1, us1, ns1,
+ y2, m2, d2, h2, min2, sec2, ms2, us2, ns2,
+ largestUnit, &d);
+ }
+ }
+ if (smallestUnit != TI_UNIT_NANOSECOND || roundingIncrement != 1) {
+ TIRoundingMode rm = is_until ? roundingMode : ti_negate_rounding_mode(roundingMode);
+ if (ti_round_relative_duration_iso(ctx,
+ y1, m1, d1, h1, min1, sec1, ms1, us1, ns1,
+ &d, largestUnit, smallestUnit, roundingIncrement,
+ rm, TRUE, &d) < 0)
+ return JS_EXCEPTION;
+ }
+ if (s->calendar != CAL_ISO8601 && s->calendar != CAL_GREGORY &&
+ s->calendar != CAL_BUDDHIST && s->calendar != CAL_ROC && s->calendar != CAL_JAPANESE) {
+ ti_balance_time_duration(&d, largestUnit);
+ }
+ } else {
+ /* Time units: use instant difference */
+ if (smallestUnit != TI_UNIT_NANOSECOND || roundingIncrement != 1) {
+ js_int128_t unit_ns = 1;
+ switch (smallestUnit) {
+ case TI_UNIT_HOUR: unit_ns = 3600000000000LL; break;
+ case TI_UNIT_MINUTE: unit_ns = 60000000000LL; break;
+ case TI_UNIT_SECOND: unit_ns = 1000000000LL; break;
+ case TI_UNIT_MILLISECOND: unit_ns = 1000000LL; break;
+ case TI_UNIT_MICROSECOND: unit_ns = 1000LL; break;
+ case TI_UNIT_NANOSECOND: unit_ns = 1LL; break;
+ default: break;
+ }
+ TIRoundingMode rm = is_until ? roundingMode : ti_negate_rounding_mode(roundingMode);
+ diff_ns = ti_round_to_increment128(diff_ns, unit_ns * roundingIncrement, rm);
+ }
+ d.nanoseconds.int128_value = diff_ns;
+ ti_balance_time_duration(&d, largestUnit);
+ }
+
+ if (!is_until) {
+ d.years = -d.years;
+ d.months = -d.months;
+ d.weeks = -d.weeks;
+ d.days = -d.days;
+ d.hours = -d.hours;
+ d.minutes = -d.minutes;
+ d.seconds = -d.seconds;
+ d.milliseconds = -d.milliseconds;
+ js_int128_t us = d.microseconds.int128_value;
+ d.microseconds.int128_value = -us;
+ js_int128_t ns = d.nanoseconds.int128_value;
+ d.nanoseconds.int128_value = -ns;
+ }
+
+ return js_create_duration(ctx, &d);
+}
+
+static JSValue js_zoneddatetime_round(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ (void)argc;
+ JSZonedDateTimeData *s = JS_GetOpaque2(ctx, this_val, js_zoneddatetime_class_id);
+ JSValue options;
+ const char *unit_str;
+ int64_t unit_ns, increment = 1;
+ TIRoundingMode mode = ROUND_TRUNC;
+ js_int128_t total_ns, rounded_ns;
+ JSTimeSpec result;
+
+ if (!s)
+ return JS_EXCEPTION;
+ if (JS_IsUndefined(argv[0]))
+ return JS_ThrowTypeError(ctx, "round requires an options object");
+
+ if (JS_IsString(argv[0])) {
+ TIUnit unit;
+ size_t len;
+ unit_str = JS_ToCStringLen(ctx, &len, argv[0]);
+ if (!unit_str)
+ return JS_EXCEPTION;
+ unit = ti_string_to_unit(unit_str, len);
+ JS_FreeCString(ctx, unit_str);
+ if (unit == TI_UNIT_INVALID)
+ return JS_ThrowRangeError(ctx, "invalid smallestUnit");
+ unit_ns = ti_unit_to_ns(unit);
+ options = JS_NULL;
+ mode = ROUND_HALF_EXPAND;
+ } else if (JS_IsObject(argv[0])) {
+ TIUnit unit;
+ options = JS_DupValue(ctx, argv[0]);
+
+ if (ti_get_rounding_increment_option(ctx, options, &increment) < 0) {
+ JS_FreeValue(ctx, options);
+ return JS_EXCEPTION;
+ }
+ if (ti_get_rounding_mode_option(ctx, options, &mode) < 0) {
+ JS_FreeValue(ctx, options);
+ return JS_EXCEPTION;
+ }
+
+ if (ti_parse_unit_option(ctx, options, "smallestUnit", &unit, 0, 0) < 0) {
+ JS_FreeValue(ctx, options);
+ return JS_EXCEPTION;
+ }
+ unit_ns = ti_unit_to_ns(unit);
+
+ JS_FreeValue(ctx, options);
+ } else {
+ return JS_ThrowTypeError(ctx, "round requires an options object");
+ }
+
+ if (unit_ns == 0)
+ return JS_ThrowRangeError(ctx, "invalid smallestUnit");
+
+ {
+ int64_t maximum;
+ int inclusive;
+ switch (unit_ns) {
+ case 86400000000000LL: maximum = 1; inclusive = 1; break;
+ case 3600000000000LL: maximum = 24; inclusive = 0; break;
+ case 60000000000LL: maximum = 60; inclusive = 0; break;
+ case 1000000000LL: maximum = 60; inclusive = 0; break;
+ case 1000000LL: maximum = 1000; inclusive = 0; break;
+ case 1000LL: maximum = 1000; inclusive = 0; break;
+ case 1LL: maximum = 1000; inclusive = 0; break;
+ default: maximum = 0; inclusive = 0; break;
+ }
+ if ((inclusive ? increment > maximum : increment >= maximum) || maximum % increment != 0) {
+ return JS_ThrowRangeError(ctx, "roundingIncrement does not divide evenly into the unit");
+ }
+ }
+
+ if (unit_ns == 86400000000000LL) {
+ /* Day rounding: use GetStartOfDay for day boundaries */
+ int64_t offset_sec = 0;
+ int64_t local_sec, day_number;
+ int64_t start_today_utc, start_tomorrow_utc;
+ int64_t day_length_ns;
+ int64_t diff_ns;
+ int tz_id = ti_tz_find_id(s->timeZone);
+ if (tz_id >= 0) {
+ offset_sec = ti_tz_offset_at_sec(tz_id, s->ts.secs);
+ } else {
+ int64_t offset_ns = 0;
+ int ret = ti_parse_temporal_timezone_string(s->timeZone, &offset_ns);
+ if (ret != 0)
+ return JS_ThrowRangeError(ctx, "unsupported time zone");
+ offset_sec = (int)(offset_ns / 1000000000LL);
+ }
+ local_sec = s->ts.secs + offset_sec;
+ day_number = floor_div64(local_sec, 86400LL);
+ if (tz_id >= 0) {
+ start_today_utc = ti_get_start_of_day_sec(tz_id, day_number * 86400LL);
+ start_tomorrow_utc = ti_get_start_of_day_sec(tz_id, (day_number + 1) * 86400LL);
+ } else {
+ start_today_utc = day_number * 86400LL - offset_sec;
+ start_tomorrow_utc = (day_number + 1) * 86400LL - offset_sec;
+ }
+ {
+ JSTimeSpec today_ts, tomorrow_ts;
+ today_ts.secs = start_today_utc;
+ today_ts.nsecs = 0;
+ tomorrow_ts.secs = start_tomorrow_utc;
+ tomorrow_ts.nsecs = 0;
+ if (!is_valid_epoch_timespec(&today_ts) || !is_valid_epoch_timespec(&tomorrow_ts))
+ return JS_ThrowRangeError(ctx, "outside representable range");
+ }
+ day_length_ns = (start_tomorrow_utc - start_today_utc) * 1000000000LL;
+ {
+ js_int128_t instant_ns = ti_timespec_to_ns(&s->ts);
+ js_int128_t end_ns = (js_int128_t)start_tomorrow_utc * 1000000000LL;
+ /* Handle the case where a transition starts after midnight and falls back
+ to before midnight, and pieces of two calendar days are interleaved.
+ https://github.com/tc39/proposal-temporal/issues/3312 */
+ if (instant_ns >= end_ns) {
+ instant_ns = end_ns - 1;
+ }
+ diff_ns = (int64_t)(instant_ns - (js_int128_t)start_today_utc * 1000000000LL);
+ }
+ if (day_length_ns > 0) {
+ int64_t rounded_diff = ti_round_to_increment_as_if_positive(diff_ns, day_length_ns, mode);
+ rounded_ns = (js_int128_t)start_today_utc * 1000000000LL + rounded_diff;
+ } else {
+ rounded_ns = ti_timespec_to_ns(&s->ts);
+ }
+ } else {
+ /* Round in local time: apply offset, round, subtract offset */
+ int64_t offset_ns = 0;
+ {
+ int ret = ti_parse_temporal_timezone_string(s->timeZone, &offset_ns);
+ if (ret == 0) {
+ total_ns = ti_timespec_to_ns(&s->ts);
+ total_ns += offset_ns;
+ {
+ js_int128_t inc_ns = unit_ns * increment;
+ rounded_ns = ti_round_to_increment_as_if_positive128(total_ns, inc_ns, mode);
+ }
+ rounded_ns -= offset_ns;
+ } else {
+ total_ns = ti_timespec_to_ns(&s->ts);
+ {
+ js_int128_t inc_ns = unit_ns * increment;
+ rounded_ns = ti_round_to_increment_as_if_positive128(total_ns, inc_ns, mode);
+ }
+ }
+ }
+ }
+
+ ti_ns_to_timespec(rounded_ns, &result);
+
+ if (!is_valid_epoch_timespec(&result))
+ return JS_ThrowRangeError(ctx, "outside representable range");
+ return js_create_zoneddatetime(ctx, &result, s->timeZone, s->calendar);
+}
+
+static JSValue js_zoneddatetime_withTimeZone(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ (void)argc;
+ JSZonedDateTimeData *s = JS_GetOpaque2(ctx, this_val, js_zoneddatetime_class_id);
+ JSZonedDateTimeData *t;
+ JSValue obj;
+ const char *str;
+ int64_t offset_ns;
+ int ret;
+ if (!s)
+ return JS_EXCEPTION;
+ if (!JS_IsString(argv[0]))
+ return JS_ThrowTypeError(ctx, "timeZone must be a string");
+ str = JS_ToCString(ctx, argv[0]);
+ if (!str)
+ return JS_EXCEPTION;
+ /* Validate timezone string */
+ ret = ti_parse_temporal_timezone_string(str, &offset_ns);
+ if (ret < 0) {
+ JS_FreeCString(ctx, str);
+ return JS_ThrowRangeError(ctx, "unsupported time zone");
+ }
+ t = js_mallocz(ctx, sizeof(*t));
+ if (!t) {
+ JS_FreeCString(ctx, str);
+ return JS_EXCEPTION;
+ }
+ *t = *s;
+ {
+ size_t len = strlen(str);
+ const char *bracket_open = strchr(str, '[');
+ if (bracket_open) {
+ const char *bracket_close = strchr(bracket_open, ']');
+ if (bracket_close && bracket_close[1] == '\0') {
+ int inner_len = (int)(bracket_close - bracket_open - 1);
+ if (inner_len > 0 && inner_len < (int)sizeof(t->timeZone)) {
+ memcpy(t->timeZone, bracket_open + 1, (size_t)inner_len);
+ t->timeZone[inner_len] = '\0';
+ }
+ }
+ } else {
+ int is_utc = (len == 3 && (str[0] == 'U' || str[0] == 'u') &&
+ (str[1] == 'T' || str[1] == 't') &&
+ (str[2] == 'C' || str[2] == 'c'));
+ int is_iso = 0;
+ if (strchr(str, ':') != NULL) {
+ is_iso = 1;
+ } else {
+ const char *p = str;
+ while ((p = strchr(p, 'T')) != NULL) {
+ if (p > str && isdigit((unsigned char)p[-1]) && isdigit((unsigned char)p[1])) {
+ is_iso = 1;
+ break;
+ }
+ p++;
+ }
+ }
+ if (!is_utc && is_iso && len > 1 && str[len - 1] == 'Z')
+ is_utc = 1;
+ if (!is_utc && !is_iso && str[0] != '+' && str[0] != '-') {
+ /* IANA name: preserve as-is */
+ pstrcpy(t->timeZone, sizeof(t->timeZone), str);
+ } else {
+ ti_format_canonical_timezone(offset_ns, is_utc, t->timeZone, sizeof(t->timeZone));
+ }
+ }
+ /* Canonicalize UTC */
+ if (t->timeZone[0] == 'u' || t->timeZone[0] == 'U') {
+ if ((t->timeZone[1] == 't' || t->timeZone[1] == 'T') &&
+ (t->timeZone[2] == 'c' || t->timeZone[2] == 'C') && t->timeZone[3] == '\0')
+ pstrcpy(t->timeZone, sizeof(t->timeZone), "UTC");
+ }
+ }
+ JS_FreeCString(ctx, str);
+ obj = JS_NewObjectClass(ctx, (int)js_zoneddatetime_class_id);
+ if (JS_IsException(obj)) {
+ js_free(ctx, t);
+ return JS_EXCEPTION;
+ }
+ JS_SetOpaque(obj, t);
+ return obj;
+}
+
+static JSValue js_zoneddatetime_with(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSZonedDateTimeData *s = JS_GetOpaque2(ctx, this_val, js_zoneddatetime_class_id);
+ int64_t year;
+ int month, day, hour, minute, second, ms, us, ns;
+ int has_year_prop = 0;
+ int has_month_prop = 0;
+ int has_month_code = 0;
+ int month_from_code = 0;
+ int mc_has_l = 0;
+ int overflow_constrain = 1;
+ int64_t parsed_offset_ns = 0;
+ int64_t original_offset_sec = 0;
+ int offset_idx = 3; /* default reject */
+ int dis_idx = 2; /* default compatible */
+ JSTimeSpec ts;
+ TIPreparedFields fields;
+ if (!s)
+ return JS_EXCEPTION;
+ {
+ int64_t offset_sec = 0;
+ int tz_id = ti_tz_find_id(s->timeZone);
+ if (tz_id >= 0) {
+ offset_sec = ti_tz_offset_at_sec(tz_id, s->ts.secs);
+ } else {
+ int64_t offset_ns = 0;
+ int ret = ti_parse_temporal_timezone_string(s->timeZone, &offset_ns);
+ if (ret < 0)
+ return JS_ThrowRangeError(ctx, "invalid timeZone");
+ offset_sec = offset_ns / 1000000000LL;
+ }
+ original_offset_sec = offset_sec;
+ {
+ int64_t local_sec = s->ts.secs + offset_sec;
+ int local_nsec = (int)s->ts.nsecs;
+ if (local_nsec < 0) {
+ local_sec -= 1;
+ local_nsec += 1000000000;
+ }
+ ti_epoch_sec_to_date(local_sec, &year, &month, &day, &hour, &minute, &second);
+ ms = local_nsec / 1000000;
+ us = (local_nsec / 1000) % 1000;
+ ns = local_nsec % 1000;
+ }
+ }
+ if (ti_is_partial_temporal_object(ctx, argv[0]) < 0)
+ return JS_EXCEPTION;
+ if (ti_prepare_calendar_fields(ctx, argv[0],
+ TI_FIELD_DAY | TI_FIELD_MONTH | TI_FIELD_MONTH_CODE |
+ TI_FIELD_YEAR | TI_FIELD_HOUR | TI_FIELD_MINUTE |
+ TI_FIELD_SECOND | TI_FIELD_MILLISECOND | TI_FIELD_MICROSECOND |
+ TI_FIELD_NANOSECOND | TI_FIELD_OFFSET,
+ 0, 1, &fields, s->calendar) < 0)
+ return JS_EXCEPTION;
+ /* Convert current ISO date to calendar space */
+ int cal_year = (int)year, cal_month = month, cal_day = day;
+ int orig_cal_year, orig_cal_month;
+ ti_iso_to_calendar_date(s->calendar, (int)year, month, day, &cal_year, &cal_month, &cal_day);
+ orig_cal_year = cal_year;
+ orig_cal_month = cal_month;
+
+ /* Merge fields in calendar space */
+ if (fields.present_mask & TI_FIELD_DAY) {
+ cal_day = fields.day;
+ }
+ if (fields.present_mask & TI_FIELD_HOUR) {
+ hour = fields.hour;
+ }
+ if (fields.present_mask & TI_FIELD_MICROSECOND) {
+ us = fields.microsecond;
+ }
+ if (fields.present_mask & TI_FIELD_MILLISECOND) {
+ ms = fields.millisecond;
+ }
+ if (fields.present_mask & TI_FIELD_MINUTE) {
+ minute = fields.minute;
+ }
+ if (fields.present_mask & TI_FIELD_MONTH) {
+ has_month_prop = 1;
+ cal_month = fields.month;
+ }
+ if (fields.present_mask & TI_FIELD_MONTH_CODE) {
+ has_month_code = 1;
+ month_from_code = fields.month_from_code;
+ mc_has_l = fields.month_code_has_l;
+ }
+ if (fields.present_mask & TI_FIELD_NANOSECOND) {
+ ns = fields.nanosecond;
+ }
+ if (fields.present_mask & TI_FIELD_OFFSET) {
+ parsed_offset_ns = fields.offset_ns;
+ } else {
+ parsed_offset_ns = original_offset_sec * 1000000000LL;
+ }
+ if (fields.present_mask & TI_FIELD_SECOND) {
+ second = fields.second;
+ }
+ if (fields.present_mask & TI_FIELD_YEAR) {
+ has_year_prop = 1;
+ cal_year = (int)fields.year;
+ }
+ /* era/eraYear processing */
+ if (fields.present_mask & (TI_FIELD_ERA | TI_FIELD_ERA_YEAR)) {
+ if (!ti_calendar_requires_era(s->calendar))
+ return JS_ThrowTypeError(ctx, "era and eraYear are invalid for this calendar");
+ if (!(fields.present_mask & TI_FIELD_ERA) || !(fields.present_mask & TI_FIELD_ERA_YEAR))
+ return JS_ThrowTypeError(ctx, "era and eraYear must both be present");
+ {
+ int cal_year_from_era;
+ if (fields.era == TI_ERA_UNKNOWN || ti_calendar_era_to_calendar_year(s->calendar, fields.era, (int)fields.era_year, &cal_year_from_era) < 0)
+ return JS_ThrowRangeError(ctx, "invalid era");
+ if (has_year_prop) {
+ if (cal_year != cal_year_from_era)
+ return JS_ThrowRangeError(ctx, "year and era/eraYear must agree");
+ } else {
+ cal_year = cal_year_from_era;
+ }
+ }
+ }
+ /* Validate options type */
+ if (argc >= 2 && ti_validate_options_object(ctx, argv[1]) < 0)
+ return JS_EXCEPTION;
+ if (argc >= 2 && !JS_IsUndefined(argv[1])) {
+ static const char *dis_values[] = { "earlier", "later", "compatible", "reject" };
+ static const char *offset_values[] = { "use", "ignore", "prefer", "reject" };
+ dis_idx = ti_get_string_option(ctx, argv[1], "disambiguation", dis_values, 4, 2);
+ if (dis_idx < 0)
+ return JS_EXCEPTION;
+ offset_idx = ti_get_string_option(ctx, argv[1], "offset", offset_values, 4, 3);
+ if (offset_idx < 0)
+ return JS_EXCEPTION;
+ if (ti_get_overflow_option(ctx, argv[1], &overflow_constrain) < 0)
+ return JS_EXCEPTION;
+ }
+ /* monthCode processing */
+ if (has_month_code) {
+ if (s->calendar == CAL_ISO8601 || s->calendar == CAL_GREGORY) {
+ if (month_from_code < 1 || month_from_code > 12 || mc_has_l)
+ return JS_ThrowRangeError(ctx, "monthCode is not valid for ISO 8601 calendar");
+ } else {
+ if (!ti_calendar_validate_month_code(s->calendar, month_from_code, mc_has_l))
+ return JS_ThrowRangeError(ctx, "monthCode is not valid for this calendar");
+ }
+ }
+ {
+ int resolved_month = 0;
+ if (has_month_code)
+ resolved_month = ti_calendar_month_code_to_month(s->calendar, cal_year, month_from_code, mc_has_l);
+ if (has_month_prop && has_month_code) {
+ if (resolved_month >= 0 && cal_month != resolved_month)
+ return JS_ThrowRangeError(ctx, "month and monthCode must agree");
+ }
+ if (has_month_code)
+ cal_month = resolved_month;
+ }
+ /* If monthCode was preserved from source but year changed, re-resolve */
+ if (!has_month_code && !has_month_prop && cal_year != orig_cal_year) {
+ int orig_mc, orig_has_l;
+ int result_mc, result_has_l;
+ int resolved_month;
+ ti_calendar_month_to_month_code(s->calendar, orig_cal_year, orig_cal_month, &orig_mc, &orig_has_l);
+ resolved_month = ti_calendar_month_code_to_month(s->calendar, cal_year, orig_mc, orig_has_l);
+ if (resolved_month < 0) {
+ if (!overflow_constrain)
+ return JS_ThrowRangeError(ctx, "invalid ZonedDateTime date");
+ resolved_month = ti_calendar_month_code_to_month(s->calendar, cal_year, orig_mc, 0);
+ }
+ cal_month = resolved_month;
+ ti_calendar_month_to_month_code(s->calendar, cal_year, cal_month, &result_mc, &result_has_l);
+ if (!overflow_constrain && (result_mc != orig_mc || result_has_l != orig_has_l))
+ return JS_ThrowRangeError(ctx, "invalid ZonedDateTime date");
+ }
+ if (!overflow_constrain) {
+ if (cal_month < 1 || cal_month > ti_calendar_months_in_year(s->calendar, cal_year))
+ return JS_ThrowRangeError(ctx, "invalid month");
+ if (cal_day < 1 || cal_day > ti_calendar_days_in_month(s->calendar, cal_year, cal_month))
+ return JS_ThrowRangeError(ctx, "invalid day");
+ if (hour < 0 || hour > 23)
+ return JS_ThrowRangeError(ctx, "invalid hour");
+ if (minute < 0 || minute > 59)
+ return JS_ThrowRangeError(ctx, "invalid minute");
+ if (second < 0 || second > 59)
+ return JS_ThrowRangeError(ctx, "invalid second");
+ if (ms < 0 || ms > 999)
+ return JS_ThrowRangeError(ctx, "invalid millisecond");
+ if (us < 0 || us > 999)
+ return JS_ThrowRangeError(ctx, "invalid microsecond");
+ if (ns < 0 || ns > 999)
+ return JS_ThrowRangeError(ctx, "invalid nanosecond");
+ } else {
+ if (cal_month > ti_calendar_months_in_year(s->calendar, cal_year))
+ cal_month = ti_calendar_months_in_year(s->calendar, cal_year);
+ else if (cal_month < 1) cal_month = 1;
+ {
+ int dim = ti_calendar_days_in_month(s->calendar, cal_year, cal_month);
+ if (cal_day > dim) cal_day = dim;
+ else if (cal_day < 1) cal_day = 1;
+ }
+ if (hour > 23) hour = 23; else if (hour < 0) hour = 0;
+ if (minute > 59) minute = 59; else if (minute < 0) minute = 0;
+ if (second > 59) second = 59; else if (second < 0) second = 0;
+ if (ms > 999) ms = 999; else if (ms < 0) ms = 0;
+ if (us > 999) us = 999; else if (us < 0) us = 0;
+ if (ns > 999) ns = 999; else if (ns < 0) ns = 0;
+ }
+ {
+ int iso_year, iso_month, iso_day;
+ ti_calendar_date_to_iso(s->calendar, cal_year, cal_month, cal_day, &iso_year, &iso_month, &iso_day);
+ year = iso_year;
+ month = iso_month;
+ day = iso_day;
+ }
+ {
+ int64_t days = pdt_to_ordinal_days((int)year, month, day);
+ int64_t local_sec = (days - 719162) * 86400LL + hour * 3600LL + minute * 60LL + second;
+ int local_nsec = ms * 1000000 + us * 1000 + ns;
+ int tz_id = ti_tz_find_id(s->timeZone);
+ if (tz_id >= 0) {
+ if (offset_idx == 0) { /* use */
+ int64_t offset_sec = parsed_offset_ns / 1000000000LL;
+ int offset_nsec = (int)(parsed_offset_ns % 1000000000LL);
+ ts.secs = local_sec - offset_sec;
+ {
+ int new_nsec = local_nsec - offset_nsec;
+ if (new_nsec < 0) {
+ new_nsec += 1000000000;
+ ts.secs -= 1;
+ } else if (new_nsec >= 1000000000) {
+ new_nsec -= 1000000000;
+ ts.secs += 1;
+ }
+ ts.nsecs = (uint32_t)new_nsec;
+ }
+ } else if (offset_idx == 1) { /* ignore */
+ int64_t utc_sec;
+ int offset_sec;
+ if (ti_tz_local_to_utc(tz_id, local_sec, dis_idx, &utc_sec, &offset_sec) < 0)
+ return JS_ThrowRangeError(ctx, "multiple instants found");
+ ts.secs = utc_sec;
+ ts.nsecs = (uint32_t)local_nsec;
+ } else { /* prefer / reject */
+ int64_t cand1_utc, cand2_utc;
+ int cand1_off, cand2_off;
+ if (ti_tz_local_to_utc(tz_id, local_sec, 0, &cand1_utc, &cand1_off) < 0)
+ return JS_ThrowRangeError(ctx, "multiple instants found");
+ if (ti_tz_local_to_utc(tz_id, local_sec, 1, &cand2_utc, &cand2_off) < 0)
+ return JS_ThrowRangeError(ctx, "multiple instants found");
+ {
+ int64_t cand1_off_ns = (int64_t)cand1_off * 1000000000LL;
+ int64_t cand2_off_ns = (int64_t)cand2_off * 1000000000LL;
+ int64_t utc_sec;
+ int offset_sec;
+ if (parsed_offset_ns == cand1_off_ns) {
+ utc_sec = cand1_utc;
+ offset_sec = cand1_off;
+ } else if (parsed_offset_ns == cand2_off_ns) {
+ utc_sec = cand2_utc;
+ offset_sec = cand2_off;
+ } else if (offset_idx == 3) { /* reject: no match */
+ return JS_ThrowRangeError(ctx, "offset does not match time zone");
+ } else { /* prefer: fallback to disambiguation */
+ if (ti_tz_local_to_utc(tz_id, local_sec, dis_idx, &utc_sec, &offset_sec) < 0)
+ return JS_ThrowRangeError(ctx, "multiple instants found");
+ }
+ ts.secs = utc_sec;
+ ts.nsecs = (uint32_t)local_nsec;
+ }
+ }
+ } else {
+ int64_t offset_ns = 0;
+ int ret = ti_parse_temporal_timezone_string(s->timeZone, &offset_ns);
+ if (ret < 0)
+ return JS_ThrowRangeError(ctx, "invalid timeZone");
+ if (offset_idx == 0)
+ offset_ns = parsed_offset_ns;
+ {
+ int64_t offset_sec = offset_ns / 1000000000LL;
+ int offset_nsec = (int)(offset_ns % 1000000000LL);
+ ts.secs = local_sec - offset_sec;
+ {
+ int new_nsec = local_nsec - offset_nsec;
+ if (new_nsec < 0) {
+ new_nsec += 1000000000;
+ ts.secs -= 1;
+ } else if (new_nsec >= 1000000000) {
+ new_nsec -= 1000000000;
+ ts.secs += 1;
+ }
+ ts.nsecs = (uint32_t)new_nsec;
+ }
+ }
+ }
+ }
+ if (!is_valid_epoch_timespec(&ts))
+ return JS_ThrowRangeError(ctx, "epoch nanoseconds outside valid limits");
+ return js_create_zoneddatetime(ctx, &ts, s->timeZone, s->calendar);
+}
+
+static JSValue js_zoneddatetime_withPlainTime(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSZonedDateTimeData *s = JS_GetOpaque2(ctx, this_val, js_zoneddatetime_class_id);
+ int64_t year;
+ int month, day;
+ JSTimeSpec ts;
+ JSPlainTimeData *pt;
+ JSValue pt_val;
+ int has_plainTime = (argc >= 1 && !JS_IsUndefined(argv[0]));
+ if (!s)
+ return JS_EXCEPTION;
+ /* Extract local ISO date from the ZDT */
+ {
+ int64_t offset_sec = 0;
+ int tz_id = ti_tz_find_id(s->timeZone);
+ if (tz_id >= 0) {
+ offset_sec = ti_tz_offset_at_sec(tz_id, s->ts.secs);
+ } else {
+ int64_t offset_ns = 0;
+ int ret = ti_parse_temporal_timezone_string(s->timeZone, &offset_ns);
+ if (ret < 0)
+ return JS_ThrowRangeError(ctx, "invalid timeZone");
+ offset_sec = offset_ns / 1000000000LL;
+ }
+ {
+ int64_t local_sec = s->ts.secs + offset_sec;
+ int h = 0, m = 0, sec = 0;
+ ti_epoch_sec_to_date(local_sec, &year, &month, &day, &h, &m, &sec);
+ }
+ }
+ /* Get time from argument, default to midnight */
+ if (has_plainTime) {
+ pt_val = js_plaintime_from(ctx, JS_UNDEFINED, 1, argv);
+ } else {
+ JSPlainTimeData tmp = {0};
+ pt_val = js_create_plaintime(ctx, &tmp);
+ }
+ if (JS_IsException(pt_val))
+ return pt_val;
+ pt = JS_GetOpaque(pt_val, js_plaintime_class_id);
+ if (!pt) {
+ JS_FreeValue(ctx, pt_val);
+ return JS_ThrowTypeError(ctx, "invalid PlainTime");
+ }
+ {
+ int64_t days = pdt_to_ordinal_days((int)year, month, day);
+ int64_t local_sec = (days - 719162) * 86400LL + pt->hour * 3600LL + pt->minute * 60LL + pt->second;
+ int local_nsec = pt->millisecond * 1000000 + pt->microsecond * 1000 + pt->nanosecond;
+ int tz_id = ti_tz_find_id(s->timeZone);
+ if (tz_id >= 0) {
+ if (has_plainTime) {
+ /* withPlainTime(plainTime): use compatible disambiguation */
+ int64_t utc_sec;
+ int offset_sec;
+ if (ti_tz_local_to_utc(tz_id, local_sec, 2, &utc_sec, &offset_sec) < 0)
+ return JS_ThrowRangeError(ctx, "multiple instants found");
+ ts.secs = utc_sec;
+ ts.nsecs = (uint32_t)local_nsec;
+ } else {
+ /* withPlainTime(): use GetStartOfDay semantics */
+ int64_t utc_sec = ti_get_start_of_day_sec(tz_id, local_sec);
+ ts.secs = utc_sec;
+ ts.nsecs = (uint32_t)local_nsec;
+ }
+ } else {
+ int64_t offset_ns = 0;
+ int ret = ti_parse_temporal_timezone_string(s->timeZone, &offset_ns);
+ if (ret < 0)
+ return JS_ThrowRangeError(ctx, "invalid timeZone");
+ {
+ int64_t offset_sec = offset_ns / 1000000000LL;
+ int offset_nsec = (int)(offset_ns % 1000000000LL);
+ ts.secs = local_sec - offset_sec;
+ {
+ int new_nsec = local_nsec - offset_nsec;
+ if (new_nsec < 0) {
+ new_nsec += 1000000000;
+ ts.secs -= 1;
+ } else if (new_nsec >= 1000000000) {
+ new_nsec -= 1000000000;
+ ts.secs += 1;
+ }
+ ts.nsecs = (uint32_t)new_nsec;
+ }
+ }
+ }
+ }
+ JS_FreeValue(ctx, pt_val);
+ if (!is_valid_epoch_timespec(&ts))
+ return JS_ThrowRangeError(ctx, "invalid epoch nanoseconds");
+ return js_create_zoneddatetime(ctx, &ts, s->timeZone, s->calendar);
+}
+
+/* equals */
+static JSValue js_zoneddatetime_equals(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ (void)argc;
+ JSZonedDateTimeData *s, *other;
+ JSValue other_val;
+ s = JS_GetOpaque2(ctx, this_val, js_zoneddatetime_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ other_val = js_zoneddatetime_from(ctx, JS_UNDEFINED, 1, argv);
+ if (JS_IsException(other_val))
+ return JS_EXCEPTION;
+ other = JS_GetOpaque(other_val, js_zoneddatetime_class_id);
+ if (!other) {
+ JS_FreeValue(ctx, other_val);
+ return JS_NewBool(ctx, 0);
+ }
+ if (s->ts.secs != other->ts.secs || s->ts.nsecs != other->ts.nsecs ||
+ !ti_timezones_are_equal(s->timeZone, other->timeZone) || s->calendar != other->calendar) {
+ JS_FreeValue(ctx, other_val);
+ return JS_NewBool(ctx, 0);
+ }
+ JS_FreeValue(ctx, other_val);
+ return JS_NewBool(ctx, 1);
+}
+
+/* toString - minimal ISO format */
+static JSValue js_zoneddatetime_toString(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSZonedDateTimeData *s;
+ char buf[256];
+ int pos = 0;
+ int64_t year, local_sec;
+ int month, day, hour, minute, second;
+ int frac_ms, frac_us, frac_ns;
+ int64_t offset_ns = 0;
+ int offset_sec;
+ int calendarName = 0; /* 0=auto (no annotation for ISO), 1=always, 2=critical */
+ int timeZoneName = 0; /* 0=auto, 1=never, 2=critical */
+ int offset_opt = 0; /* 0=auto, 1=never */
+ int precision_type = -1; /* -1=auto, 0=second, 1-9=digits, 10=minute, 11=second, 12=ms, 13=us, 14=ns */
+ int fsd_is_auto = 1;
+ int fsd_value = 0;
+ TIUnit smallestUnit = TI_UNIT_INVALID;
+ int has_smallestUnit = 0;
+ TIRoundingMode rounding_mode = ROUND_TRUNC;
+ if (argc >= 1 && ti_validate_options_object(ctx, argv[0]) < 0)
+ return JS_EXCEPTION;
+ s = JS_GetOpaque2(ctx, this_val, js_zoneddatetime_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ /* Parse options first */
+ if (argc >= 1 && JS_IsObject(argv[0])) {
+ /* Step 1: calendarName */
+ if (ti_get_calendar_name_option(ctx, argv[0], &calendarName) < 0)
+ return JS_EXCEPTION;
+ /* Step 2: fractionalSecondDigits */
+ {
+ int fsd = ti_get_fractional_second_digits_option(ctx, argv[0], &fsd_value);
+ if (fsd < 0)
+ return JS_EXCEPTION;
+ if (fsd_value != -1)
+ fsd_is_auto = 0;
+ }
+ /* Step 3: offset */
+ {
+ JSValue v = JS_GetPropertyStr(ctx, argv[0], "offset");
+ if (!JS_IsUndefined(v)) {
+ size_t len;
+ const char *str = JS_ToCStringLen(ctx, &len, v);
+ if (!str) {
+ JS_FreeValue(ctx, v);
+ return JS_EXCEPTION;
+ }
+ if (len == strlen(str) && !strcmp(str, "never")) {
+ offset_opt = 1;
+ } else if (len == strlen(str) && !strcmp(str, "auto")) {
+ offset_opt = 0;
+ } else {
+ JS_FreeCString(ctx, str);
+ JS_FreeValue(ctx, v);
+ return JS_ThrowRangeError(ctx, "invalid offset");
+ }
+ JS_FreeCString(ctx, str);
+ }
+ JS_FreeValue(ctx, v);
+ }
+ /* Step 4: roundingMode */
+ {
+ TIRoundingMode mode;
+ if (ti_get_rounding_mode_option_default(ctx, argv[0], &mode, ROUND_TRUNC) < 0)
+ return JS_EXCEPTION;
+ rounding_mode = mode;
+ }
+ /* Step 5: smallestUnit */
+ {
+ TIUnit unit;
+ if (ti_parse_unit_option(ctx, argv[0], "smallestUnit", &unit, TI_UNIT_OPT_ALLOW_UNDEFINED, TI_UNIT_INVALID) < 0)
+ return JS_EXCEPTION;
+ if (unit != TI_UNIT_INVALID) {
+ smallestUnit = unit;
+ has_smallestUnit = 1;
+ }
+ }
+ /* Step 6: timeZoneName */
+ {
+ JSValue v = JS_GetPropertyStr(ctx, argv[0], "timeZoneName");
+ if (!JS_IsUndefined(v)) {
+ size_t len;
+ const char *str = JS_ToCStringLen(ctx, &len, v);
+ if (!str) {
+ JS_FreeValue(ctx, v);
+ return JS_EXCEPTION;
+ }
+ if (len == strlen(str) && !strcmp(str, "never")) {
+ timeZoneName = 1;
+ } else if (len == strlen(str) && !strcmp(str, "auto")) {
+ timeZoneName = 0;
+ } else if (len == strlen(str) && !strcmp(str, "critical")) {
+ timeZoneName = 2;
+ } else {
+ JS_FreeCString(ctx, str);
+ JS_FreeValue(ctx, v);
+ return JS_ThrowRangeError(ctx, "invalid timeZoneName");
+ }
+ JS_FreeCString(ctx, str);
+ }
+ JS_FreeValue(ctx, v);
+ }
+ }
+ /* Validation */
+ if (has_smallestUnit && (smallestUnit == TI_UNIT_INVALID || smallestUnit < TI_UNIT_MINUTE || smallestUnit > TI_UNIT_NANOSECOND))
+ return JS_ThrowRangeError(ctx, "invalid smallestUnit");
+ /* Determine precision */
+ if (has_smallestUnit) {
+ precision_type = ti_precision_from_smallest_unit(smallestUnit);
+ } else if (!fsd_is_auto) {
+ precision_type = fsd_value;
+ } else {
+ precision_type = -1; /* auto */
+ }
+ /* Apply rounding to UTC instant, then compute local time */
+ {
+ js_int128_t total_ns = ti_timespec_to_ns(&s->ts);
+ js_int128_t increment_ns = 1;
+ int64_t rounded_sec;
+ int rounded_nsec;
+ if (precision_type == 10)
+ increment_ns = 60000000000LL;
+ else if (precision_type == 11)
+ increment_ns = 1000000000LL;
+ else if (precision_type == 12)
+ increment_ns = 1000000LL;
+ else if (precision_type == 13)
+ increment_ns = 1000LL;
+ else if (precision_type == 14)
+ increment_ns = 1LL;
+ else if (precision_type == 0)
+ increment_ns = 1000000000LL;
+ else if (precision_type >= 1 && precision_type <= 9)
+ increment_ns = (js_int128_t)pow(10, 9 - precision_type);
+ if (increment_ns > 1 || precision_type == 0) {
+ total_ns = ti_round_to_increment_as_if_positive128(total_ns, increment_ns, rounding_mode);
+ }
+ rounded_sec = (int64_t)(total_ns / 1000000000LL);
+ rounded_nsec = (int)(total_ns % 1000000000LL);
+ if (rounded_nsec < 0) {
+ rounded_nsec += 1000000000;
+ rounded_sec--;
+ }
+ /* Compute offset at rounded UTC time */
+ {
+ int tz_id = ti_tz_find_id(s->timeZone);
+ if (tz_id >= 0) {
+ offset_sec = ti_tz_offset_at_sec(tz_id, rounded_sec);
+ } else {
+ int ret = ti_parse_temporal_timezone_string(s->timeZone, &offset_ns);
+ if (ret != 0)
+ return JS_ThrowRangeError(ctx, "unsupported time zone");
+ offset_sec = (int)(offset_ns / 1000000000LL);
+ }
+ }
+ local_sec = rounded_sec + offset_sec;
+ /* Handle nanosecond carry */
+ {
+ int64_t nsec = rounded_nsec;
+ if (nsec < 0) {
+ nsec += 1000000000LL;
+ local_sec--;
+ } else if (nsec >= 1000000000LL) {
+ nsec -= 1000000000LL;
+ local_sec++;
+ }
+ frac_ms = (int)(nsec / 1000000);
+ frac_us = (int)((nsec / 1000) % 1000);
+ frac_ns = (int)(nsec % 1000);
+ }
+ ti_epoch_sec_to_date(local_sec, &year, &month, &day, &hour, &minute, &second);
+ }
+ /* Format date */
+ if (year < 0)
+ pos += snprintf(buf + pos, sizeof(buf) - (size_t)pos, "-%06d-%02d-%02d",
+ (int)(-year), month, day);
+ else if (year >= 10000)
+ pos += snprintf(buf + pos, sizeof(buf) - (size_t)pos, "+%06d-%02d-%02d",
+ (int)year, month, day);
+ else
+ pos += snprintf(buf + pos, sizeof(buf) - (size_t)pos, "%04d-%02d-%02d",
+ (int)year, month, day);
+ /* Format time */
+ if (precision_type == 10)
+ pos += snprintf(buf + pos, sizeof(buf) - (size_t)pos, "T%02d:%02d",
+ hour, minute);
+ else
+ pos += snprintf(buf + pos, sizeof(buf) - (size_t)pos, "T%02d:%02d:%02d",
+ hour, minute, second);
+ /* Format fractional seconds */
+ if (precision_type == 10) {
+ /* minute precision: truncate seconds */
+ } else if (precision_type == 0) {
+ /* second precision: no fractions */
+ } else if (precision_type >= 1 && precision_type <= 9) {
+ char frac[16];
+ (void)snprintf(frac, sizeof(frac), "%09d",
+ frac_ms * 1000000 + frac_us * 1000 + frac_ns);
+ frac[precision_type] = '\0';
+ pos += snprintf(buf + pos, sizeof(buf) - (size_t)pos, ".%s", frac);
+ } else if (precision_type == -1 && (frac_ms != 0 || frac_us != 0 || frac_ns != 0)) {
+ char frac[16];
+ int frac_len = snprintf(frac, sizeof(frac), "%03d%03d%03d", frac_ms, frac_us, frac_ns);
+ while (frac_len > 0 && frac[frac_len - 1] == '0')
+ frac_len--;
+ frac[frac_len] = '\0';
+ if (frac_len > 0)
+ pos += snprintf(buf + pos, sizeof(buf) - (size_t)pos, ".%s", frac);
+ } else if (precision_type >= 11) {
+ int digits = 0;
+ if (precision_type == 11) digits = 0;
+ else if (precision_type == 12) digits = 3;
+ else if (precision_type == 13) digits = 6;
+ else if (precision_type == 14) digits = 9;
+ if (digits > 0) {
+ char fmt[8];
+ snprintf(fmt, sizeof(fmt), "%%0%dd", digits);
+ int frac_val = 0;
+ if (digits == 3) frac_val = frac_ms;
+ else if (digits == 6) frac_val = frac_ms * 1000 + frac_us;
+ else if (digits == 9) frac_val = frac_ms * 1000000 + frac_us * 1000 + frac_ns;
+ pos += snprintf(buf + pos, sizeof(buf) - (size_t)pos, ".");
+ pos += snprintf(buf + pos, sizeof(buf) - (size_t)pos, fmt, frac_val);
+ }
+ }
+ /* Format timezone offset */
+ if (offset_opt == 0) {
+ int offset_min = offset_sec / 60;
+ /* Round to nearest minute (half-expand away from zero) */
+ {
+ int rem = offset_sec % 60;
+ if (offset_sec >= 0) {
+ if (rem >= 30) offset_min++;
+ } else {
+ if (rem <= -30) offset_min--;
+ }
+ }
+ int offset_abs = offset_min >= 0 ? offset_min : -offset_min;
+ int offset_h = offset_abs / 60;
+ int offset_m = offset_abs % 60;
+ pos += snprintf(buf + pos, sizeof(buf) - (size_t)pos, "%c%02d:%02d",
+ offset_min >= 0 ? '+' : '-', offset_h, offset_m);
+ }
+ /* Format timezone name */
+ if (timeZoneName != 1) {
+ if (timeZoneName == 2)
+ pos += snprintf(buf + pos, sizeof(buf) - (size_t)pos, "[!%s]", s->timeZone);
+ else
+ pos += snprintf(buf + pos, sizeof(buf) - (size_t)pos, "[%s]", s->timeZone);
+ }
+ /* Calendar annotation */
+ if (calendarName == 1 || calendarName == 2 || (calendarName == 0 && s->calendar != CAL_ISO8601)) {
+ const char *cal_str = ti_calendar_enum_to_string(s->calendar);
+ if (cal_str) {
+ if (calendarName == 2)
+ pos += snprintf(buf + pos, sizeof(buf) - (size_t)pos, "[!u-ca=%s]", cal_str);
+ else
+ pos += snprintf(buf + pos, sizeof(buf) - (size_t)pos, "[u-ca=%s]", cal_str);
+ }
+ }
+ return JS_NewString(ctx, buf);
+}
+
+static JSValue js_zoneddatetime_toJSON(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ (void)argc;
+ (void)argv;
+ return js_zoneddatetime_toString(ctx, this_val, 0, NULL);
+}
+
+static JSValue js_zoneddatetime_toLocaleString(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSZonedDateTimeData *s = JS_GetOpaque2(ctx, this_val, js_zoneddatetime_class_id);
+ JSValue ctor, dtf, method, ret;
+ JSValue new_argv[2];
+ JSValue date_val;
+ if (!s)
+ return JS_EXCEPTION;
+
+ /* timeZone option is not allowed in toLocaleString for ZonedDateTime */
+ if (argc > 1 && JS_IsObject(argv[1])) {
+ JSAtom tz_atom = JS_NewAtom(ctx, "timeZone");
+ int has_tz = JS_HasProperty(ctx, argv[1], tz_atom);
+ JS_FreeAtom(ctx, tz_atom);
+ if (has_tz > 0)
+ return JS_ThrowTypeError(ctx, "timeZone option disallowed");
+ if (has_tz < 0)
+ return JS_EXCEPTION;
+ }
+
+ ctor = JS_GetContextValue(ctx, JS_INTL_CTOR_DATETIMEFORMAT);
+ if (JS_IsNull(ctor) || JS_IsUndefined(ctor)) {
+ JS_FreeValue(ctx, ctor);
+ return js_zoneddatetime_toString(ctx, this_val, 0, NULL);
+ }
+
+ new_argv[0] = argc >= 1 ? JS_DupValue(ctx, argv[0]) : JS_UNDEFINED;
+ if (argc >= 2 && JS_IsObject(argv[1])) {
+ new_argv[1] = JS_DupValue(ctx, argv[1]);
+ } else if (argc >= 2 && JS_IsUndefined(argv[1])) {
+ new_argv[1] = JS_NewObject(ctx);
+ } else if (argc >= 2) {
+ /* Non-object, non-undefined options - let DateTimeFormat constructor throw */
+ new_argv[1] = JS_DupValue(ctx, argv[1]);
+ } else {
+ new_argv[1] = JS_NewObject(ctx);
+ }
+ if (JS_IsException(new_argv[1])) {
+ JS_FreeValue(ctx, new_argv[0]);
+ JS_FreeValue(ctx, ctor);
+ return new_argv[1];
+ }
+
+ if (JS_IsObject(new_argv[1])) {
+ const char *canon_tz = ti_canonicalize_timezone_alias(s->timeZone);
+ JSValue tz_val = JS_NewString(ctx, canon_tz);
+ int has_date, has_time;
+ if (JS_IsException(tz_val)) {
+ JS_FreeValue(ctx, new_argv[0]);
+ JS_FreeValue(ctx, new_argv[1]);
+ JS_FreeValue(ctx, ctor);
+ return tz_val;
+ }
+ JS_SetPropertyStr(ctx, new_argv[1], "timeZone", tz_val);
+ {
+ JSValue ds_val = JS_GetPropertyStr(ctx, new_argv[1], "dateStyle");
+ if (JS_IsException(ds_val)) {
+ JS_FreeValue(ctx, ds_val);
+ JS_FreeValue(ctx, new_argv[0]);
+ JS_FreeValue(ctx, new_argv[1]);
+ JS_FreeValue(ctx, ctor);
+ return JS_EXCEPTION;
+ }
+ JSValue ts_val = JS_GetPropertyStr(ctx, new_argv[1], "timeStyle");
+ if (JS_IsException(ts_val)) {
+ JS_FreeValue(ctx, ds_val);
+ JS_FreeValue(ctx, ts_val);
+ JS_FreeValue(ctx, new_argv[0]);
+ JS_FreeValue(ctx, new_argv[1]);
+ JS_FreeValue(ctx, ctor);
+ return JS_EXCEPTION;
+ }
+ BOOL has_ds = !JS_IsUndefined(ds_val);
+ BOOL has_ts = !JS_IsUndefined(ts_val);
+ JS_FreeValue(ctx, ds_val);
+ JS_FreeValue(ctx, ts_val);
+ has_date = js_intl_options_has_date_fields(ctx, new_argv[1]);
+ has_time = js_intl_options_has_time_fields(ctx, new_argv[1]);
+ if (has_date < 0 || has_time < 0) {
+ JS_FreeValue(ctx, new_argv[0]);
+ JS_FreeValue(ctx, new_argv[1]);
+ JS_FreeValue(ctx, ctor);
+ return JS_EXCEPTION;
+ }
+ if (!has_ds && !has_ts && !has_date && !has_time) {
+ JS_DefinePropertyValueStr(ctx, new_argv[1], "year",
+ JS_NewString(ctx, "numeric"), JS_PROP_C_W_E);
+ JS_DefinePropertyValueStr(ctx, new_argv[1], "month",
+ JS_NewString(ctx, "numeric"), JS_PROP_C_W_E);
+ JS_DefinePropertyValueStr(ctx, new_argv[1], "day",
+ JS_NewString(ctx, "numeric"), JS_PROP_C_W_E);
+ JS_DefinePropertyValueStr(ctx, new_argv[1], "hour",
+ JS_NewString(ctx, "numeric"), JS_PROP_C_W_E);
+ JS_DefinePropertyValueStr(ctx, new_argv[1], "minute",
+ JS_NewString(ctx, "numeric"), JS_PROP_C_W_E);
+ JS_DefinePropertyValueStr(ctx, new_argv[1], "second",
+ JS_NewString(ctx, "numeric"), JS_PROP_C_W_E);
+ }
+ if (!has_ds && !has_ts) {
+ JSAtom tzn_atom = JS_NewAtom(ctx, "timeZoneName");
+ int has_tzn = JS_HasProperty(ctx, new_argv[1], tzn_atom);
+ JS_FreeAtom(ctx, tzn_atom);
+ if (has_tzn <= 0) {
+ JS_DefinePropertyValueStr(ctx, new_argv[1], "timeZoneName",
+ JS_NewString(ctx, "short"), JS_PROP_C_W_E);
+ }
+ }
+ }
+ }
+
+ dtf = JS_CallConstructor(ctx, ctor, 2, new_argv);
+ JS_FreeValue(ctx, ctor);
+ JS_FreeValue(ctx, new_argv[0]);
+ JS_FreeValue(ctx, new_argv[1]);
+ if (JS_IsException(dtf))
+ return dtf;
+
+ /* Calendar mismatch check */
+ {
+ JSValue resolved = JS_GetPropertyStr(ctx, dtf, "resolvedOptions");
+ if (!JS_IsException(resolved)) {
+ JSValue opts = JS_Call(ctx, resolved, dtf, 0, NULL);
+ JS_FreeValue(ctx, resolved);
+ if (!JS_IsException(opts)) {
+ JSValue dtf_cal_val = JS_GetPropertyStr(ctx, opts, "calendar");
+ JSValue obj_cal_val = JS_GetPropertyStr(ctx, this_val, "calendarId");
+ JS_FreeValue(ctx, opts);
+ if (!JS_IsException(dtf_cal_val) && !JS_IsException(obj_cal_val)) {
+ const char *dtf_cal = JS_ToCString(ctx, dtf_cal_val);
+ const char *obj_cal = JS_ToCString(ctx, obj_cal_val);
+ if (dtf_cal && obj_cal && strcmp(obj_cal, "iso8601") != 0 &&
+ strcmp(dtf_cal, "iso8601") != 0 && strcmp(obj_cal, dtf_cal) != 0) {
+ JS_FreeCString(ctx, dtf_cal);
+ JS_FreeCString(ctx, obj_cal);
+ JS_FreeValue(ctx, dtf_cal_val);
+ JS_FreeValue(ctx, obj_cal_val);
+ JS_FreeValue(ctx, dtf);
+ return JS_ThrowRangeError(ctx, "calendar mismatch");
+ }
+ JS_FreeCString(ctx, dtf_cal);
+ JS_FreeCString(ctx, obj_cal);
+ }
+ JS_FreeValue(ctx, dtf_cal_val);
+ JS_FreeValue(ctx, obj_cal_val);
+ }
+ }
+ }
+
+ /* Format as epoch milliseconds to avoid dtf_check_temporal_overlap rejection */
+ date_val = JS_NewFloat64(ctx, timespec_to_ms(&s->ts));
+ if (JS_IsException(date_val)) {
+ JS_FreeValue(ctx, dtf);
+ return date_val;
+ }
+
+ method = JS_GetPropertyStr(ctx, dtf, "format");
+ if (JS_IsException(method)) {
+ JS_FreeValue(ctx, dtf);
+ JS_FreeValue(ctx, date_val);
+ return method;
+ }
+
+ ret = JS_Call(ctx, method, dtf, 1, &date_val);
+ JS_FreeValue(ctx, method);
+ JS_FreeValue(ctx, dtf);
+ JS_FreeValue(ctx, date_val);
+ return ret;
+}
+
+static JSValue js_zoneddatetime_valueOf(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ (void)argc;
+ (void)argv;
+ (void)this_val;
+ return JS_ThrowTypeError(ctx, "cannot compare Temporal.ZonedDateTime with < or >");
+}
+
+/* toInstant */
+static JSValue js_zoneddatetime_toInstant(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ (void)argc;
+ (void)argv;
+ JSZonedDateTimeData *s = JS_GetOpaque2(ctx, this_val, js_zoneddatetime_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ return js_create_instant(ctx, &s->ts);
+}
+
+static JSValue js_zoneddatetime_add_subtract(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv, int is_add)
+{
+ JSZonedDateTimeData *s = JS_GetOpaque2(ctx, this_val, js_zoneddatetime_class_id);
+ JSDurationData d = {0};
+ int64_t year64;
+ int year;
+ int month, day, hour, minute, second, ms, us, ns;
+ int overflow_constrain = 1;
+ JSTimeSpec ts;
+ int sign = is_add ? 1 : -1;
+ if (!s)
+ return JS_EXCEPTION;
+ if (js_to_temporal_duration(ctx, argv[0], &d))
+ return JS_EXCEPTION;
+ if (argc >= 2 && ti_validate_options_object(ctx, argv[1]) < 0)
+ return JS_EXCEPTION;
+ if (argc >= 2 && !JS_IsUndefined(argv[1])) {
+ if (ti_get_overflow_option(ctx, argv[1], &overflow_constrain) < 0)
+ return JS_EXCEPTION;
+ }
+ /* Validate duration fields fit in int before casting */
+ if ((int64_t)(int)d.years != d.years ||
+ (int64_t)(int)d.months != d.months ||
+ (int64_t)(int)d.weeks != d.weeks ||
+ (int64_t)(int)d.days != d.days)
+ return JS_ThrowRangeError(ctx, "duration out of range");
+ /* Time-only path: exact instant arithmetic (AddInstant) per spec */
+ if (d.years == 0 && d.months == 0 && d.weeks == 0 && d.days == 0) {
+ js_int128_t total_ns = ti_timespec_to_ns(&s->ts);
+ total_ns += sign * ti_duration_time_fields_to_ns(&d);
+ ti_ns_to_timespec(total_ns, &ts);
+ } else {
+ /* Date+time path per spec AddZonedDateTime */
+ /* Get local ISO date/time from the UTC instant */
+ {
+ int64_t local_sec = s->ts.secs;
+ int local_nsec = (int)s->ts.nsecs;
+ zdt_apply_timezone_offset(ctx, s, &local_sec, &local_nsec);
+ ti_epoch_sec_to_date(local_sec, &year64, &month, &day, &hour, &minute, &second);
+ ms = (int)(local_nsec / 1000000);
+ us = (int)((local_nsec / 1000) % 1000);
+ ns = (int)(local_nsec % 1000);
+ }
+ year = (int)year64;
+ /* Add date part in calendar space */
+ {
+ int cal_y = year, cal_m = month, cal_d = day;
+ int orig_mc = 0, orig_has_l = 0;
+ ti_iso_to_calendar_date(s->calendar, year, month, day, &cal_y, &cal_m, &cal_d);
+ year = cal_y; month = cal_m; day = cal_d;
+ ti_calendar_month_to_month_code(s->calendar, year, month, &orig_mc, &orig_has_l);
+ year += sign * (int)d.years;
+ month = ti_calendar_month_code_to_month(s->calendar, year, orig_mc, orig_has_l);
+ if (month < 0) {
+ if (!overflow_constrain)
+ return JS_ThrowRangeError(ctx, "invalid ZonedDateTime");
+ month = ti_calendar_month_code_to_month(s->calendar, year, orig_mc, 0);
+ } else if (!overflow_constrain) {
+ int result_mc, result_has_l;
+ ti_calendar_month_to_month_code(s->calendar, year, month, &result_mc, &result_has_l);
+ if (result_mc != orig_mc || result_has_l != orig_has_l)
+ return JS_ThrowRangeError(ctx, "invalid ZonedDateTime");
+ }
+ month += sign * (int)d.months;
+ pdt_balance_month_calendar(&year, &month, s->calendar);
+ {
+ int dim = ti_calendar_days_in_month(s->calendar, year, month);
+ if (day > dim) {
+ if (!overflow_constrain)
+ return JS_ThrowRangeError(ctx, "invalid ZonedDateTime");
+ day = dim;
+ }
+ }
+ day += sign * (int)(d.weeks * 7 + d.days);
+ pdt_balance_date_calendar(&year, &month, &day, s->calendar);
+ {
+ int iso_y, iso_m, iso_d;
+ ti_calendar_date_to_iso(s->calendar, year, month, day, &iso_y, &iso_m, &iso_d);
+ year = iso_y; month = iso_m; day = iso_d;
+ }
+ }
+ /* Combine new date with original local time */
+ {
+ int64_t days = pdt_to_ordinal_days(year, month, day);
+ ts.secs = (days - 719162) * 86400LL + hour * 3600LL + minute * 60LL + second;
+ ts.nsecs = (uint32_t)(ms * 1000000 + us * 1000 + ns);
+ }
+ /* Convert local back to UTC with compatible disambiguation */
+ {
+ int tz_id = ti_tz_find_id(s->timeZone);
+ if (tz_id >= 0) {
+ int64_t utc_sec;
+ int offset_sec;
+ if (ti_tz_local_to_utc(tz_id, ts.secs, 2, &utc_sec, &offset_sec) < 0)
+ return JS_ThrowRangeError(ctx, "multiple instants found");
+ ts.secs = utc_sec;
+ } else {
+ int64_t offset_ns = 0;
+ int ret2 = ti_parse_temporal_timezone_string(s->timeZone, &offset_ns);
+ if (ret2 == 0) {
+ int64_t offset_sec = offset_ns / 1000000000LL;
+ int offset_nsec = (int)(offset_ns % 1000000000LL);
+ ts.secs -= offset_sec;
+ {
+ int new_nsec = (int)ts.nsecs - offset_nsec;
+ if (new_nsec < 0) {
+ new_nsec += 1000000000;
+ ts.secs -= 1;
+ } else if (new_nsec >= 1000000000) {
+ new_nsec -= 1000000000;
+ ts.secs += 1;
+ }
+ ts.nsecs = (uint32_t)new_nsec;
+ }
+ }
+ }
+ }
+ /* Add time part using exact instant arithmetic (AddInstant) */
+ {
+ js_int128_t total_ns = ti_timespec_to_ns(&ts);
+ total_ns += sign * ti_duration_time_fields_to_ns(&d);
+ ti_ns_to_timespec(total_ns, &ts);
+ }
+ }
+ {
+ js_int128_t epoch_ns = ti_timespec_to_ns(&ts);
+ js_int128_t limit = (js_int128_t)8640000000000LL * 1000000000LL;
+ if (epoch_ns < -limit || epoch_ns > limit)
+ return JS_ThrowRangeError(ctx, "epoch nanoseconds outside valid limits");
+ }
+ return js_create_zoneddatetime(ctx, &ts, s->timeZone, s->calendar);
+}
+
+JSValue js_zoneddatetime_add(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ return js_zoneddatetime_add_subtract(ctx, this_val, argc, argv, 1);
+}
+
+/* toPlainDateTime */
+static JSValue js_zoneddatetime_toPlainDateTime(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ (void)argc;
+ (void)argv;
+ JSZonedDateTimeData *s;
+ int64_t year;
+ int month, day, hour, minute, second;
+ int ms, us, ns;
+ s = JS_GetOpaque2(ctx, this_val, js_zoneddatetime_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ {
+ int64_t epoch_sec = s->ts.secs;
+ int epoch_nsec = (int)s->ts.nsecs;
+ zdt_apply_timezone_offset(ctx, s, &epoch_sec, &epoch_nsec);
+ ti_epoch_sec_to_date(epoch_sec, &year, &month, &day, &hour, &minute, &second);
+ ms = epoch_nsec / 1000000;
+ us = (epoch_nsec % 1000000) / 1000;
+ ns = epoch_nsec % 1000;
+ }
+ return js_create_plaindatetime_with_calendar(ctx, (int)year, month, day, hour, minute, second, ms, us, ns, s->calendar);
+}
+
+/* toPlainDate */
+static JSValue js_zoneddatetime_toPlainDate(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ (void)argc;
+ (void)argv;
+ JSZonedDateTimeData *s;
+ int64_t year;
+ int month, day, hour, minute, second;
+ s = JS_GetOpaque2(ctx, this_val, js_zoneddatetime_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ {
+ int64_t epoch_sec = s->ts.secs;
+ int epoch_nsec = (int)s->ts.nsecs;
+ zdt_apply_timezone_offset(ctx, s, &epoch_sec, &epoch_nsec);
+ ti_epoch_sec_to_date(epoch_sec, &year, &month, &day, &hour, &minute, &second);
+ }
+ return js_create_plaindate_with_calendar(ctx, (int)year, month, day, s->calendar);
+}
+
+/* toPlainTime */
+static JSValue js_zoneddatetime_toPlainTime(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ (void)argc;
+ (void)argv;
+ JSZonedDateTimeData *s;
+ int64_t year;
+ int month, day, hour, minute, second;
+ int ms, us, ns;
+ s = JS_GetOpaque2(ctx, this_val, js_zoneddatetime_class_id);
+ if (!s)
+ return JS_EXCEPTION;
+ {
+ int64_t epoch_sec = s->ts.secs;
+ int epoch_nsec = (int)s->ts.nsecs;
+ zdt_apply_timezone_offset(ctx, s, &epoch_sec, &epoch_nsec);
+ ti_epoch_sec_to_date(epoch_sec, &year, &month, &day, &hour, &minute, &second);
+ ms = epoch_nsec / 1000000;
+ us = (epoch_nsec % 1000000) / 1000;
+ ns = epoch_nsec % 1000;
+ }
+ {
+ JSPlainTimeData t = {hour, minute, second, ms, us, ns};
+ return js_create_plaintime(ctx, &t);
+ }
+}
+
+/* Temporal.ZonedDateTime.from */
+JSValue js_zoneddatetime_from(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ if (JS_IsObject(argv[0])) {
+ JSZonedDateTimeData *s = JS_GetOpaque(argv[0], js_zoneddatetime_class_id);
+ if (s) {
+ int overflow_dummy = 1;
+ if (argc >= 2 && ti_validate_options_object(ctx, argv[1]) < 0)
+ return JS_EXCEPTION;
+ if (argc >= 2) {
+ static const char *dis_values[] = { "earlier", "later", "compatible", "reject" };
+ if (ti_get_string_option(ctx, argv[1], "disambiguation", dis_values, 4, 2) < 0)
+ return JS_EXCEPTION;
+ static const char *offset_values[] = { "use", "ignore", "prefer", "reject" };
+ if (ti_get_string_option(ctx, argv[1], "offset", offset_values, 4, 3) < 0)
+ return JS_EXCEPTION;
+ }
+ if (argc >= 2 && ti_get_overflow_option(ctx, argv[1], &overflow_dummy) < 0)
+ return JS_EXCEPTION;
+ return js_create_zoneddatetime(ctx, &s->ts, s->timeZone, s->calendar);
+ }
+ /* Property bag */
+ {
+ TIPreparedFields fields;
+ int year = 0, month = 0, day = 0;
+ int month_from_code = 0;
+ int mc_has_l = 0;
+ int hour = 0, minute = 0, second = 0, ms = 0, us = 0, ns = 0;
+ int has_year = 0, has_month = 0, has_month_code = 0, has_day = 0;
+ int has_time_zone = 0;
+ int has_offset_prop = 0;
+ int64_t prop_offset_ns = 0;
+ int is_iso_calendar = 1;
+ char timeZone[TI_TIMEZONE_BUF_SIZE] = "UTC";
+ CalendarType calendar = CAL_ISO8601;
+ JSTimeSpec ts;
+
+ if (ti_resolve_calendar_from_object(ctx, argv[0], &calendar) < 0)
+ return JS_EXCEPTION;
+ if (calendar != CAL_ISO8601 && calendar != CAL_GREGORY)
+ is_iso_calendar = 0;
+
+ if (ti_prepare_calendar_fields(ctx, argv[0],
+ TI_FIELD_DAY | TI_FIELD_MONTH | TI_FIELD_MONTH_CODE |
+ TI_FIELD_YEAR | TI_FIELD_HOUR | TI_FIELD_MINUTE |
+ TI_FIELD_SECOND | TI_FIELD_MILLISECOND | TI_FIELD_MICROSECOND |
+ TI_FIELD_NANOSECOND | TI_FIELD_OFFSET | TI_FIELD_TIMEZONE,
+ 0, 0, &fields, calendar) < 0)
+ return JS_EXCEPTION;
+
+ /* Merge fields */
+ if (fields.present_mask & TI_FIELD_DAY) {
+ day = fields.day;
+ has_day = 1;
+ }
+ if (fields.present_mask & TI_FIELD_HOUR) hour = fields.hour;
+ if (fields.present_mask & TI_FIELD_MICROSECOND) us = fields.microsecond;
+ if (fields.present_mask & TI_FIELD_MILLISECOND) ms = fields.millisecond;
+ if (fields.present_mask & TI_FIELD_MINUTE) minute = fields.minute;
+ if (fields.present_mask & TI_FIELD_MONTH) {
+ month = fields.month;
+ has_month = 1;
+ }
+ if (fields.present_mask & TI_FIELD_MONTH_CODE) {
+ month_from_code = fields.month_from_code;
+ mc_has_l = fields.month_code_has_l;
+ has_month_code = 1;
+ }
+ if (fields.present_mask & TI_FIELD_NANOSECOND) ns = fields.nanosecond;
+ if (fields.present_mask & TI_FIELD_OFFSET) {
+ prop_offset_ns = fields.offset_ns;
+ has_offset_prop = 1;
+ }
+ if (fields.present_mask & TI_FIELD_SECOND) second = fields.second;
+ if (fields.present_mask & TI_FIELD_YEAR) {
+ year = (int)fields.year;
+ has_year = 1;
+ }
+
+ /* Handle timezone */
+ if (fields.present_mask & TI_FIELD_TIMEZONE) {
+ if (fields.time_zone[0]) {
+ const char *tz = fields.time_zone;
+ const char *bracket_open = strchr(tz, '[');
+ if (bracket_open) {
+ const char *bracket_close = strchr(bracket_open, ']');
+ if (bracket_close && bracket_close[1] == '\0') {
+ int inner_len = (int)(bracket_close - bracket_open - 1);
+ if (inner_len > 0 && inner_len < (int)sizeof(timeZone)) {
+ memcpy(timeZone, bracket_open + 1, (size_t)inner_len);
+ timeZone[inner_len] = '\0';
+ ;
+ }
+ }
+ } else {
+ size_t tz_len = strlen(tz);
+ int is_utc = (tz_len == 3 && (tz[0] == 'U' || tz[0] == 'u') &&
+ (tz[1] == 'T' || tz[1] == 't') &&
+ (tz[2] == 'C' || tz[2] == 'c'));
+ if (!is_utc && tz_len > 0 && tz[tz_len - 1] == 'Z')
+ is_utc = 1;
+ {
+ int64_t offset_ns = 0;
+ int ret = ti_parse_temporal_timezone_string(tz, &offset_ns);
+ if (ret == 0) {
+ if (ti_tz_find_id(tz) >= 0) {
+ /* Known IANA timezone name - preserve it */
+ pstrcpy(timeZone, sizeof(timeZone), tz);
+ } else {
+ ti_format_canonical_timezone(offset_ns, is_utc, timeZone, sizeof(timeZone));
+ }
+ }
+ }
+ }
+ /* Canonicalize UTC */
+ if (timeZone[0] == 'u' || timeZone[0] == 'U') {
+ if ((timeZone[1] == 't' || timeZone[1] == 'T') &&
+ (timeZone[2] == 'c' || timeZone[2] == 'C') && timeZone[3] == '\0')
+ pstrcpy(timeZone, sizeof(timeZone), "UTC");
+ }
+ has_time_zone = 1;
+ } else {
+ JSValue tz_v = JS_GetPropertyStr(ctx, argv[0], "timeZone");
+ if (JS_IsException(tz_v)) {
+ JS_FreeValue(ctx, tz_v);
+ return JS_EXCEPTION;
+ }
+ if (!JS_IsUndefined(tz_v)) {
+ JSZonedDateTimeData *zdt = JS_GetOpaque(tz_v, js_zoneddatetime_class_id);
+ if (zdt) {
+ pstrcpy(timeZone, sizeof(timeZone), zdt->timeZone);
+ has_time_zone = 1;
+ }
+ JS_FreeValue(ctx, tz_v);
+ }
+ }
+ }
+
+ /* era/eraYear handling */
+ if (ti_calendar_requires_era(calendar) && (fields.present_mask & (TI_FIELD_ERA | TI_FIELD_ERA_YEAR))) {
+ if (!(fields.present_mask & TI_FIELD_ERA) || !(fields.present_mask & TI_FIELD_ERA_YEAR))
+ return JS_ThrowTypeError(ctx, "era and eraYear must both be present");
+ {
+ int cal_year_from_era;
+ if (fields.era == TI_ERA_UNKNOWN || ti_calendar_era_to_calendar_year(calendar, fields.era, (int)fields.era_year, &cal_year_from_era) < 0)
+ return JS_ThrowRangeError(ctx, "invalid era");
+ if (has_year) {
+ if (year != cal_year_from_era)
+ return JS_ThrowRangeError(ctx, "year and era/eraYear must agree");
+ } else {
+ year = cal_year_from_era;
+ has_year = 1;
+ }
+ }
+ }
+
+ if (!has_time_zone)
+ return JS_ThrowTypeError(ctx, "missing timeZone");
+ {
+ int overflow_constrain = 1;
+ int offset_idx = 3; /* default reject */
+ /* Validate options before algorithmic validation */
+ if (argc >= 2 && ti_validate_options_object(ctx, argv[1]) < 0)
+ return JS_EXCEPTION;
+ int dis_idx = 2; /* default compatible */
+ if (argc >= 2) {
+ static const char *dis_values[] = { "earlier", "later", "compatible", "reject" };
+ dis_idx = ti_get_string_option(ctx, argv[1], "disambiguation", dis_values, 4, 2);
+ if (dis_idx < 0)
+ return JS_EXCEPTION;
+ static const char *offset_values[] = { "use", "ignore", "prefer", "reject" };
+ offset_idx = ti_get_string_option(ctx, argv[1], "offset", offset_values, 4, 3);
+ if (offset_idx < 0)
+ return JS_EXCEPTION;
+ }
+ if (argc >= 2 && ti_get_overflow_option(ctx, argv[1], &overflow_constrain) < 0)
+ return JS_EXCEPTION;
+ if (!has_year || !has_day || (!has_month && !has_month_code))
+ return JS_ThrowTypeError(ctx, "missing required property");
+ {
+ int resolved_month = 0;
+ if (has_month_code)
+ resolved_month = ti_calendar_month_code_to_month(calendar, year, month_from_code, mc_has_l);
+ if (has_month && has_month_code && month != resolved_month)
+ return JS_ThrowRangeError(ctx, "monthCode and month conflict");
+ if (has_month_code && !has_month)
+ month = resolved_month;
+ }
+ /* Validate monthCode suitability */
+ if (has_month_code) {
+ if (is_iso_calendar) {
+ if (month < 1 || month > 12 || mc_has_l)
+ return JS_ThrowRangeError(ctx, "invalid monthCode");
+ } else {
+ if (!ti_calendar_validate_month_code(calendar, month_from_code, mc_has_l))
+ return JS_ThrowRangeError(ctx, "invalid monthCode");
+ }
+ }
+ if (day < 1)
+ return JS_ThrowRangeError(ctx, "invalid day");
+ if (month < 1)
+ return JS_ThrowRangeError(ctx, "invalid month");
+ if (hour < 0 || minute < 0 || second < 0 ||
+ ms < 0 || us < 0 || ns < 0)
+ return JS_ThrowRangeError(ctx, "invalid time");
+ /* Apply overflow handling for month and day in calendar space */
+ if (calendar != CAL_ISO8601 && calendar != CAL_GREGORY) {
+ int max_month = ti_calendar_months_in_year(calendar, year);
+ if (month > max_month) {
+ if (!overflow_constrain)
+ return JS_ThrowRangeError(ctx, "invalid ZonedDateTime");
+ month = max_month;
+ }
+ {
+ int dim = ti_calendar_days_in_month(calendar, year, month);
+ if (day > dim) {
+ if (!overflow_constrain)
+ return JS_ThrowRangeError(ctx, "invalid ZonedDateTime");
+ day = dim;
+ }
+ }
+ {
+ int iso_year, iso_month, iso_day;
+ ti_calendar_date_to_iso(calendar, year, month, day, &iso_year, &iso_month, &iso_day);
+ year = iso_year; month = iso_month; day = iso_day;
+ }
+ } else {
+ int dim;
+ if (month > 12) {
+ if (!overflow_constrain)
+ return JS_ThrowRangeError(ctx, "invalid ZonedDateTime");
+ month = 12;
+ }
+ dim = pd_days_in_month(year, month);
+ if (day > dim) {
+ if (!overflow_constrain)
+ return JS_ThrowRangeError(ctx, "invalid ZonedDateTime");
+ day = dim;
+ }
+ }
+ int64_t days = pdt_to_ordinal_days(year, month, day);
+ ts.secs = (days - 719162) * 86400LL + hour * 3600LL + minute * 60LL + second;
+ ts.nsecs = (uint32_t)(ms * 1000000 + us * 1000 + ns);
+ /* Adjust for timezone offset: UTC = local - offset */
+ {
+ int64_t computed_offset_ns = 0;
+ int64_t local_sec = ts.secs;
+ int tz_id = ti_tz_find_id(timeZone);
+ if (tz_id >= 0) {
+ int64_t utc_sec;
+ int offset_sec;
+ if (offset_idx == 2 && has_offset_prop) {
+ /* prefer: check both candidates for matching offset */
+ int64_t cand1_utc, cand2_utc;
+ int cand1_off, cand2_off;
+ if (ti_tz_local_to_utc(tz_id, local_sec, 0, &cand1_utc, &cand1_off) < 0)
+ return JS_ThrowRangeError(ctx, "multiple instants found");
+ if (ti_tz_local_to_utc(tz_id, local_sec, 1, &cand2_utc, &cand2_off) < 0)
+ return JS_ThrowRangeError(ctx, "multiple instants found");
+ {
+ int64_t cand1_off_ns = (int64_t)cand1_off * 1000000000LL;
+ int64_t cand2_off_ns = (int64_t)cand2_off * 1000000000LL;
+ if (prop_offset_ns == cand1_off_ns) {
+ utc_sec = cand1_utc;
+ offset_sec = cand1_off;
+ } else if (prop_offset_ns == cand2_off_ns) {
+ utc_sec = cand2_utc;
+ offset_sec = cand2_off;
+ } else {
+ if (ti_tz_local_to_utc(tz_id, local_sec, dis_idx, &utc_sec, &offset_sec) < 0)
+ return JS_ThrowRangeError(ctx, "multiple instants found");
+ }
+ }
+ } else {
+ if (ti_tz_local_to_utc(tz_id, local_sec, dis_idx, &utc_sec, &offset_sec) < 0)
+ return JS_ThrowRangeError(ctx, "multiple instants found");
+ }
+ ts.secs = utc_sec;
+ computed_offset_ns = (int64_t)offset_sec * 1000000000LL;
+ } else {
+ int64_t offset_ns = 0;
+ int ret2 = ti_parse_temporal_timezone_string(timeZone, &offset_ns);
+ if (ret2 == 0) {
+ int64_t offset_sec = offset_ns / 1000000000LL;
+ int offset_nsec = (int)(offset_ns % 1000000000LL);
+ ts.secs -= offset_sec;
+ {
+ int new_nsec = (int)ts.nsecs - offset_nsec;
+ if (new_nsec < 0) {
+ new_nsec += 1000000000;
+ ts.secs -= 1;
+ } else if (new_nsec >= 1000000000) {
+ new_nsec -= 1000000000;
+ ts.secs += 1;
+ }
+ ts.nsecs = (uint32_t)new_nsec;
+ }
+ computed_offset_ns = offset_ns;
+ }
+ }
+ if (has_offset_prop) {
+ if (offset_idx == 0) { /* use */
+ /* Use the property bag offset, overriding loop result */
+ int64_t offset_sec = prop_offset_ns / 1000000000LL;
+ int offset_nsec = (int)(prop_offset_ns % 1000000000LL);
+ ts.secs = local_sec - offset_sec;
+ {
+ int new_nsec = (int)(ms * 1000000 + us * 1000 + ns) - offset_nsec;
+ if (new_nsec < 0) {
+ new_nsec += 1000000000;
+ ts.secs -= 1;
+ } else if (new_nsec >= 1000000000) {
+ new_nsec -= 1000000000;
+ ts.secs += 1;
+ }
+ ts.nsecs = (uint32_t)new_nsec;
+ }
+ } else if (offset_idx == 3) { /* reject */
+ if (computed_offset_ns != prop_offset_ns)
+ return JS_ThrowRangeError(ctx, "offset does not match time zone");
+ }
+ }
+ }
+ return js_create_zoneddatetime(ctx, &ts, timeZone, calendar);
+ }
+ }
+ }
+ if (JS_IsString(argv[0])) {
+ /* Parse ISO string using shared parser */
+ const char *str = JS_ToCString(ctx, argv[0]);
+ TISODateTimeParseResult r;
+ char timeZone[TI_TIMEZONE_BUF_SIZE] = "UTC";
+ JSTimeSpec ts;
+ int overflow_constrain = 1;
+ int offset_idx = 3; /* default reject */
+ int64_t tz_offset_ns = 0;
+ int has_computed_utc = 0;
+ if (!str)
+ return JS_EXCEPTION;
+ if (ti_parse_iso_datetime_string(ctx, str, &r, TI_PARSE_DEFAULT) < 0) {
+ JS_FreeCString(ctx, str);
+ return JS_ThrowRangeError(ctx, "invalid ZonedDateTime string");
+ }
+ JS_FreeCString(ctx, str);
+ /* ZonedDateTime strings must have a bracket timezone annotation */
+ if (!r.has_tz_annotation)
+ return JS_ThrowRangeError(ctx, "invalid ZonedDateTime string");
+ /* ZonedDateTime must have date */
+ if (!r.has_date)
+ return JS_ThrowRangeError(ctx, "invalid ZonedDateTime string");
+ /* UTC designator or prefix offset requires time component */
+ if ((r.has_utc || r.has_tz_offset) && !r.has_time)
+ return JS_ThrowRangeError(ctx, "invalid ZonedDateTime string");
+ pstrcpy(timeZone, sizeof(timeZone), r.tz_annotation);
+ /* Canonicalize UTC */
+ if (timeZone[0] == 'u' || timeZone[0] == 'U') {
+ if ((timeZone[1] == 't' || timeZone[1] == 'T') &&
+ (timeZone[2] == 'c' || timeZone[2] == 'C') && timeZone[3] == '\0')
+ pstrcpy(timeZone, sizeof(timeZone), "UTC");
+ }
+ /* Read options in spec order: disambiguation, offset, overflow */
+ int dis_idx = 2; /* default compatible */
+ if (argc >= 2 && ti_validate_options_object(ctx, argv[1]) < 0)
+ return JS_EXCEPTION;
+ if (argc >= 2) {
+ static const char *dis_values[] = { "earlier", "later", "compatible", "reject" };
+ dis_idx = ti_get_string_option(ctx, argv[1], "disambiguation", dis_values, 4, 2);
+ if (dis_idx < 0)
+ return JS_EXCEPTION;
+ static const char *offset_values[] = { "use", "ignore", "prefer", "reject" };
+ offset_idx = ti_get_string_option(ctx, argv[1], "offset", offset_values, 4, 3);
+ if (offset_idx < 0)
+ return JS_EXCEPTION;
+ }
+ if (argc >= 2 && ti_get_overflow_option(ctx, argv[1], &overflow_constrain) < 0)
+ return JS_EXCEPTION;
+ /* Compute epoch seconds from parsed fields */
+ {
+ int64_t days = pdt_to_ordinal_days(r.year, r.month, r.day);
+ {
+ /* CheckISODaysRange: validate local date if needed */
+ int check_local = r.has_utc;
+ if (!check_local && (offset_idx == 2 || offset_idx == 3))
+ check_local = 1;
+ if (check_local) {
+ int64_t epoch_days = days - 719162;
+ if (epoch_days < -100000000LL || epoch_days > 100000000LL)
+ return JS_ThrowRangeError(ctx, "invalid ZonedDateTime string");
+ }
+ }
+ ts.secs = (days - 719162) * 86400LL + r.hour * 3600LL + r.minute * 60LL + r.second;
+ ts.nsecs = (uint32_t)(r.millisecond * 1000000 + r.microsecond * 1000 + r.nanosecond);
+ }
+ /* Determine timezone offset to subtract */
+ {
+ int64_t prefix_offset_ns = 0;
+ int64_t timezone_offset_ns = 0;
+ int has_timezone_offset = 0;
+ int tz_id = -1;
+
+ if (r.has_tz_offset) {
+ prefix_offset_ns = (int64_t)r.tz_offset_seconds * 1000000000LL + r.tz_offset_nanoseconds;
+ }
+
+ /* Compute timezone offset from bracket annotation */
+ {
+ size_t tz_len = strlen(timeZone);
+ if ((timeZone[0] == '+' || timeZone[0] == '-') &&
+ (tz_len == 3 || tz_len == 5 || (tz_len == 6 && timeZone[3] == ':'))) {
+ int tz_sign = (timeZone[0] == '-') ? -1 : 1;
+ int tz_hour = (timeZone[1] - '0') * 10 + (timeZone[2] - '0');
+ int tz_minute = 0;
+ if (tz_len == 5)
+ tz_minute = (timeZone[3] - '0') * 10 + (timeZone[4] - '0');
+ else if (tz_len == 6)
+ tz_minute = (timeZone[4] - '0') * 10 + (timeZone[5] - '0');
+ timezone_offset_ns = tz_sign * ((int64_t)tz_hour * 3600 + tz_minute * 60) * 1000000000LL;
+ has_timezone_offset = 1;
+ }
+ }
+
+ tz_id = ti_tz_find_id(timeZone);
+
+ {
+ int is_fixed_or_utc = has_timezone_offset || strcmp(timeZone, "UTC") == 0;
+ if (r.has_utc) {
+ tz_offset_ns = 0;
+ } else if (r.has_tz_offset) {
+ /* Both prefix offset and bracket timezone present */
+ if (tz_id >= 0) {
+ /* For reject and prefer-match-check, compute offset using
+ prefix as a rough guess. For ignore/prefer-mismatch, use
+ ti_tz_local_to_utc with disambiguation. */
+ int64_t guess_sec = ts.secs - prefix_offset_ns / 1000000000LL;
+ int offset_sec = ti_tz_offset_at_sec(tz_id, guess_sec);
+ int64_t computed_offset_ns = (int64_t)offset_sec * 1000000000LL;
+ /* Check for ambiguous local time near transitions (e.g. Pacific/Niue).
+ Only when an earlier candidate has an offset within 60 seconds
+ of the prefix offset (minute-rounded match). */
+ if (!r.tz_offset_has_seconds) {
+ int prev_offset_sec = ti_tz_prev_offset_at_sec(tz_id, guess_sec);
+ int64_t prev_offset_ns = (int64_t)prev_offset_sec * 1000000000LL;
+ int64_t diff = prefix_offset_ns - prev_offset_ns;
+ if (diff < 0) diff = -diff;
+ if (diff < 60 * 1000000000LL) {
+ int64_t cand1 = ts.secs - computed_offset_ns / 1000000000LL;
+ int64_t cand2 = ts.secs - prev_offset_ns / 1000000000LL;
+ if (cand2 < cand1 &&
+ ti_tz_offset_at_sec(tz_id, cand2) == prev_offset_sec &&
+ ti_tz_offset_at_sec(tz_id, cand1) == offset_sec) {
+ computed_offset_ns = prev_offset_ns;
+ }
+ }
+ }
+ if (offset_idx == 3) { /* reject */
+ if (r.tz_offset_has_seconds) {
+ if (prefix_offset_ns != computed_offset_ns)
+ return JS_ThrowRangeError(ctx, "offset does not match time zone");
+ tz_offset_ns = prefix_offset_ns;
+ } else {
+ int64_t diff_ns = prefix_offset_ns - computed_offset_ns;
+ if (diff_ns < 0)
+ diff_ns = -diff_ns;
+ if (diff_ns >= 60 * 1000000000LL)
+ return JS_ThrowRangeError(ctx, "offset does not match time zone");
+ tz_offset_ns = computed_offset_ns;
+ }
+ } else if (offset_idx == 0) { /* use */
+ tz_offset_ns = prefix_offset_ns;
+ } else if (offset_idx == 1) { /* ignore */
+ int64_t utc_sec;
+ int act_offset_sec;
+ if (ti_tz_local_to_utc(tz_id, ts.secs, dis_idx, &utc_sec, &act_offset_sec) < 0)
+ return JS_ThrowRangeError(ctx, "multiple instants found");
+ ts.secs = utc_sec;
+ tz_offset_ns = (int64_t)act_offset_sec * 1000000000LL;
+ has_computed_utc = 1;
+ } else { /* prefer */
+ /* prefer only uses the prefix offset when it exactly
+ matches the computed offset. Minute-rounded offsets
+ that are within 60s but not exact are treated like ignore. */
+ if (prefix_offset_ns == computed_offset_ns) {
+ tz_offset_ns = prefix_offset_ns;
+ } else {
+ int64_t utc_sec;
+ int act_offset_sec;
+ if (ti_tz_local_to_utc(tz_id, ts.secs, dis_idx, &utc_sec, &act_offset_sec) < 0)
+ return JS_ThrowRangeError(ctx, "multiple instants found");
+ ts.secs = utc_sec;
+ tz_offset_ns = (int64_t)act_offset_sec * 1000000000LL;
+ has_computed_utc = 1;
+ }
+ }
+ } else if (!is_fixed_or_utc) {
+ /* Unsupported IANA timezone: can't verify agreement, use prefix offset */
+ tz_offset_ns = prefix_offset_ns;
+ } else if (offset_idx == 3) { /* reject */
+ if (prefix_offset_ns != timezone_offset_ns)
+ return JS_ThrowRangeError(ctx, "offset does not match time zone");
+ tz_offset_ns = prefix_offset_ns;
+ } else if (offset_idx == 0) { /* use */
+ tz_offset_ns = prefix_offset_ns;
+ } else if (offset_idx == 1) { /* ignore */
+ tz_offset_ns = has_timezone_offset ? timezone_offset_ns : 0;
+ } else { /* prefer */
+ if (prefix_offset_ns == timezone_offset_ns)
+ tz_offset_ns = prefix_offset_ns;
+ else
+ tz_offset_ns = has_timezone_offset ? timezone_offset_ns : 0;
+ }
+ } else {
+ /* Only bracket timezone (no prefix offset) */
+ if (tz_id >= 0) {
+ if (!r.has_time) {
+ /* Date-only string: use GetStartOfDay semantics */
+ int64_t utc_sec = ti_get_start_of_day_sec(tz_id, ts.secs);
+ if (utc_sec == INT64_MIN)
+ return JS_ThrowRangeError(ctx, "multiple instants found");
+ ts.secs = utc_sec;
+ tz_offset_ns = (int64_t)ti_tz_offset_at_sec(tz_id, utc_sec) * 1000000000LL;
+ has_computed_utc = 1;
+ } else {
+ int64_t utc_sec;
+ int offset_sec;
+ if (ti_tz_local_to_utc(tz_id, ts.secs, dis_idx, &utc_sec, &offset_sec) < 0)
+ return JS_ThrowRangeError(ctx, "multiple instants found");
+ ts.secs = utc_sec;
+ tz_offset_ns = (int64_t)offset_sec * 1000000000LL;
+ has_computed_utc = 1;
+ }
+ } else {
+ tz_offset_ns = has_timezone_offset ? timezone_offset_ns : 0;
+ }
+ }
+ }
+ }
+ /* Apply offset: UTC = local - offset */
+ if (!has_computed_utc) {
+ int64_t offset_sec = tz_offset_ns / 1000000000LL;
+ int offset_nsec = (int)(tz_offset_ns % 1000000000LL);
+ ts.secs -= offset_sec;
+ {
+ int new_nsec = (int)ts.nsecs - offset_nsec;
+ if (new_nsec < 0) {
+ new_nsec += 1000000000;
+ ts.secs -= 1;
+ } else if (new_nsec >= 1000000000) {
+ new_nsec -= 1000000000;
+ ts.secs += 1;
+ }
+ ts.nsecs = (uint32_t)new_nsec;
+ }
+ }
+ /* Validate epoch nanoseconds are within valid range */
+ if (!is_valid_epoch_timespec(&ts))
+ return JS_ThrowRangeError(ctx, "invalid ZonedDateTime string");
+ {
+ CalendarType cal = r.has_calendar ? r.calendar : CAL_ISO8601;
+ if (cal == CAL_UNKNOWN)
+ return JS_ThrowRangeError(ctx, "invalid calendar ID");
+ return js_create_zoneddatetime(ctx, &ts, timeZone, cal);
+ }
+ }
+ return JS_ThrowTypeError(ctx, "unsupported argument type for Temporal.ZonedDateTime.from");
+}
+
+static const JSCFunctionListEntry js_zoneddatetime_proto_funcs[] = {
+ JS_CGETSET_DEF("epochNanoseconds", js_zoneddatetime_get_epochNanoseconds, NULL),
+ JS_CGETSET_DEF("epochMilliseconds", js_zoneddatetime_get_epochMilliseconds, NULL),
+ JS_CGETSET_DEF("timeZoneId", js_zoneddatetime_get_timeZoneId, NULL),
+ JS_CGETSET_DEF("calendarId", js_zoneddatetime_get_calendarId, NULL),
+ JS_CGETSET_DEF("year", js_zoneddatetime_get_year, NULL),
+ JS_CGETSET_DEF("month", js_zoneddatetime_get_month, NULL),
+ JS_CGETSET_DEF("day", js_zoneddatetime_get_day, NULL),
+ JS_CGETSET_DEF("hour", js_zoneddatetime_get_hour, NULL),
+ JS_CGETSET_DEF("minute", js_zoneddatetime_get_minute, NULL),
+ JS_CGETSET_DEF("second", js_zoneddatetime_get_second, NULL),
+ JS_CGETSET_DEF("millisecond", js_zoneddatetime_get_millisecond, NULL),
+ JS_CGETSET_DEF("microsecond", js_zoneddatetime_get_microsecond, NULL),
+ JS_CGETSET_DEF("nanosecond", js_zoneddatetime_get_nanosecond, NULL),
+ JS_CGETSET_DEF("offset", js_zoneddatetime_get_offset, NULL),
+ JS_CGETSET_DEF("offsetNanoseconds", js_zoneddatetime_get_offsetNanoseconds, NULL),
+ JS_CGETSET_DEF("era", js_zoneddatetime_get_era, NULL),
+ JS_CGETSET_DEF("eraYear", js_zoneddatetime_get_eraYear, NULL),
+ JS_CGETSET_DEF("monthCode", js_zoneddatetime_get_monthCode, NULL),
+ JS_CGETSET_DEF("inLeapYear", js_zoneddatetime_get_inLeapYear, NULL),
+ JS_CGETSET_DEF("daysInYear", js_zoneddatetime_get_daysInYear, NULL),
+ JS_CGETSET_DEF("daysInWeek", js_zoneddatetime_get_daysInWeek, NULL),
+ JS_CGETSET_DEF("monthsInYear", js_zoneddatetime_get_monthsInYear, NULL),
+ JS_CGETSET_DEF("hoursInDay", js_zoneddatetime_get_hoursInDay, NULL),
+ JS_CGETSET_DEF("weekOfYear", js_zoneddatetime_get_weekOfYear, NULL),
+ JS_CGETSET_DEF("yearOfWeek", js_zoneddatetime_get_yearOfWeek, NULL),
+ JS_CGETSET_DEF("daysInMonth", js_zoneddatetime_get_daysInMonth, NULL),
+ JS_CGETSET_DEF("dayOfYear", js_zoneddatetime_get_dayOfYear, NULL),
+ JS_CGETSET_DEF("dayOfWeek", js_zoneddatetime_get_dayOfWeek, NULL),
+ JS_CFUNC_MAGIC_DEF("add", 1, js_zoneddatetime_add_subtract, 1),
+ JS_CFUNC_MAGIC_DEF("subtract", 1, js_zoneddatetime_add_subtract, 0),
+ JS_CFUNC_DEF("round", 1, js_zoneddatetime_round),
+ JS_CFUNC_MAGIC_DEF("until", 1, js_zoneddatetime_difference, 1),
+ JS_CFUNC_MAGIC_DEF("since", 1, js_zoneddatetime_difference, 0),
+ JS_CFUNC_DEF("startOfDay", 0, js_zoneddatetime_startOfDay),
+ JS_CFUNC_DEF("getTimeZoneTransition", 1, js_zoneddatetime_getTimeZoneTransition),
+ JS_CFUNC_DEF("equals", 1, js_zoneddatetime_equals),
+ JS_CFUNC_DEF("with", 1, js_zoneddatetime_with),
+ JS_CFUNC_DEF("withCalendar", 1, js_zoneddatetime_withCalendar),
+ JS_CFUNC_DEF("withPlainTime", 0, js_zoneddatetime_withPlainTime),
+ JS_CFUNC_DEF("withTimeZone", 1, js_zoneddatetime_withTimeZone),
+ JS_CFUNC_DEF("toString", 0, js_zoneddatetime_toString),
+ JS_CFUNC_DEF("toJSON", 0, js_zoneddatetime_toJSON),
+ JS_CFUNC_DEF("toLocaleString", 0, js_zoneddatetime_toLocaleString),
+ JS_CFUNC_DEF("valueOf", 0, js_zoneddatetime_valueOf),
+ JS_CFUNC_DEF("toInstant", 0, js_zoneddatetime_toInstant),
+ JS_CFUNC_DEF("toPlainDateTime", 0, js_zoneddatetime_toPlainDateTime),
+ JS_CFUNC_DEF("toPlainDate", 0, js_zoneddatetime_toPlainDate),
+ JS_CFUNC_DEF("toPlainTime", 0, js_zoneddatetime_toPlainTime),
+ JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Temporal.ZonedDateTime", JS_PROP_CONFIGURABLE),
+};
+
+static const JSCFunctionListEntry js_zoneddatetime_static_funcs[] = {
+ JS_CFUNC_DEF("from", 1, js_zoneddatetime_from),
+ JS_CFUNC_DEF("compare", 2, js_zoneddatetime_compare),
+};
+
+int js_add_zoneddatetime(JSContext *ctx, JSValue temporal_obj)
+{
+ JSValue ctor;
+
+ JS_NewClassID(&js_zoneddatetime_class_id);
+ JS_NewClass(JS_GetRuntime(ctx), js_zoneddatetime_class_id, &js_zoneddatetime_class);
+
+ ctor = JS_NewCConstructor(ctx, (int)js_zoneddatetime_class_id, "ZonedDateTime",
+ (JSCFunction *)js_zoneddatetime_constructor, 2,
+ JS_CFUNC_constructor, 0,
+ JS_UNDEFINED,
+ js_zoneddatetime_static_funcs, countof(js_zoneddatetime_static_funcs),
+ js_zoneddatetime_proto_funcs, countof(js_zoneddatetime_proto_funcs),
+ JS_NEW_CTOR_NO_GLOBAL);
+ if (JS_IsException(ctor))
+ return -1;
+ if (JS_DefinePropertyValueStr(ctx, temporal_obj, "ZonedDateTime", ctor,
+ JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE) < 0)
+ return -1;
+ return 0;
+}
Int16Array
Int32Array
Int8Array
-Intl-enumeration=skip
-intl-normative-optional=skip
-Intl.DateTimeFormat-datetimestyle=skip
-Intl.DateTimeFormat-dayPeriod=skip
-Intl.DateTimeFormat-extend-timezonename=skip
-Intl.DateTimeFormat-formatRange=skip
-Intl.DateTimeFormat-fractionalSecondDigits=skip
-Intl.DisplayNames-v2=skip
-Intl.DisplayNames=skip
-Intl.DurationFormat=skip
-Intl.Era-monthcode=skip
-Intl.ListFormat=skip
-Intl.Locale-info=skip
-Intl.Locale=skip
-Intl.NumberFormat-unified=skip
-Intl.NumberFormat-v3=skip
-Intl.RelativeTimeFormat=skip
-Intl.Segmenter=skip
+Intl-enumeration
+intl-normative-optional
+Intl.DateTimeFormat-datetimestyle
+Intl.DateTimeFormat-dayPeriod
+Intl.DateTimeFormat-extend-timezonename
+Intl.DateTimeFormat-formatRange
+Intl.DateTimeFormat-fractionalSecondDigits
+Intl.DisplayNames-v2
+Intl.DisplayNames
+Intl.DurationFormat
+Intl.Era-monthcode
+Intl.ListFormat
+Intl.Locale-info
+Intl.Locale
+Intl.NumberFormat-unified
+Intl.NumberFormat-v3
+Intl.RelativeTimeFormat
+Intl.Segmenter
IsHTMLDDA
Iterator.prototype.join=skip
iterator-chunking=skip
symbols-as-weakmap-keys
tail-call-optimization=skip
template
-Temporal=skip
+Temporal
top-level-await
TypedArray
TypedArray.prototype.at
[exclude]
# list excluded tests and directories here
-# intl not supported
-test262/test/intl402/
-
# incompatible with the "caller" feature
test262/test/built-ins/Function/prototype/restricted-property-caller.js
test262/test/built-ins/Function/prototype/restricted-property-arguments.js
+test262/test/built-ins/Temporal/Instant/prototype/toString/timezone-string-unknown.js:10: Test262Error: Mars/Olympus_Mons is not an available named time zone Expected a RangeError to be thrown but no exception was thrown at all
+test262/test/built-ins/Temporal/Instant/prototype/toZonedDateTimeISO/timezone-string-unknown.js:10: Test262Error: Mars/Olympus_Mons is not an available named time zone Expected a RangeError to be thrown but no exception was thrown at all
+test262/test/intl402/DateTimeFormat/prototype/format/german-weekday-no-year.js:10: Test262Error: German weekday without year Expected SameValue(«false», «true») to be true
+test262/test/intl402/Locale/constructor-unicode-extension-uvalue-true.js:20: Test262Error: new Intl.Locale("en-u-0a-true").toString() must be "en-u-0a" Expected SameValue(«"en-u-true"», «"en-u-0a"») to be true
+test262/test/intl402/Locale/constructor-unicode-extension-uvalue-yes.js:20: Test262Error: new Intl.Locale("en-u-0a-yes").toString() must be "en-u-0a-yes" Expected SameValue(«"en-u-yes"», «"en-u-0a-yes"») to be true
+test262/test/intl402/Locale/prototype/calendar/canonicalize-case.js:26: Test262Error: new Intl.Locale("de", {calendar: "GREGORY"}).calendar Expected SameValue(«"GREGORY"», «"gregory"») to be true
+test262/test/intl402/Locale/prototype/collation/canonicalize-case.js:26: Test262Error: new Intl.Locale("de", {collation: "PHONEBK"}).collation Expected SameValue(«"PHONEBK"», «"phonebk"») to be true
+test262/test/intl402/Locale/prototype/firstDayOfWeek/valid-options.js:15: Test262Error: new Intl.Locale("en", { firstDayOfWeek: MON }).firstDayOfWeek returns "mon" Expected SameValue(«"MON"», «"mon"») to be true
+test262/test/intl402/Locale/prototype/getCalendars/likely-subtags-region.js:42: Test262Error: No suitable test data found in this implementation. Consider updating the candidate list
+test262/test/intl402/Locale/prototype/getCalendars/region-override.js:41: Test262Error: No suitable test data found in this implementation. Consider updating the candidate list
+test262/test/intl402/Locale/prototype/getCalendars/region-priority.js:60: Test262Error: Inconclusive: the "rg" region override and the region subtag select regions with identical calendars in this implementation. Consider updating the test data
+test262/test/intl402/Locale/prototype/getCalendars/subdivision-region.js:35: Test262Error: No suitable test data found in this implementation. Consider updating the candidate list
+test262/test/intl402/Locale/prototype/getCollations/collation-keyword.js:28: Test262Error: Actual [default] and expected [phonebk] should have the same contents. getCollations() for en-u-co-phonebk returns only phonebk
+test262/test/intl402/Locale/prototype/getCollations/und-language.js:53: Test262Error: Actual [default] and expected [emoji, eor] should have the same contents. getCollations() for und must return the root collations
+test262/test/intl402/Locale/prototype/getHourCycles/language-priority.js:47: Test262Error: Either the feature is not implemented correctly, or no suitable test data found in this implementation. If the latter, consider updating the candidate list
+test262/test/intl402/Locale/prototype/getHourCycles/likely-subtags-region.js:42: Test262Error: No suitable test data found in this implementation. Consider updating the candidate list
+test262/test/intl402/Locale/prototype/getHourCycles/region-override.js:41: Test262Error: No suitable test data found in this implementation. Consider updating the candidate list
+test262/test/intl402/Locale/prototype/getHourCycles/region-priority.js:59: Test262Error: Inconclusive: the "rg" region override and the region subtag select regions with identical hour cycles in this implementation. Consider updating the test data
+test262/test/intl402/Locale/prototype/getHourCycles/subdivision-region.js:35: Test262Error: No suitable test data found in this implementation. Consider updating the candidate list
+test262/test/intl402/Locale/prototype/getWeekInfo/likely-subtags-region.js:46: Test262Error: No suitable test data found in this implementation. Consider updating the candidate list
+test262/test/intl402/Locale/prototype/getWeekInfo/region-override.js:45: Test262Error: No suitable test data found in this implementation. Consider updating the candidate list
+test262/test/intl402/Locale/prototype/getWeekInfo/region-priority.js:59: Test262Error: Inconclusive: the "rg" region override and the region subtag selected regions with identical week info in this implementation. Consider updating the test data
+test262/test/intl402/Locale/prototype/getWeekInfo/subdivision-region.js:39: Test262Error: No suitable test data found in this implementation. Consider updating the candidate list
+test262/test/intl402/Locale/prototype/numberingSystem/canonicalize-case.js:26: Test262Error: new Intl.Locale("de", {numberingSystem: "LATN"}).numberingSystem Expected SameValue(«"LATN"», «"latn"») to be true
+test262/test/intl402/NumberFormat/prototype/format/format-significant-digits-rounding-magnitude.js:93: Test262Error: Formatted value for 0.0009999, en-US-u-nu-latn and options {"useGrouping":false,"minimumSignificantDigits":3,"maximumSignificantDigits":3} is 0.001000; expected 0.00100.
+test262/test/intl402/NumberFormat/prototype/formatToParts/significant-digits-rounding-magnitude-en-US.js:32: Test262Error: Expected [Object {type: "integer", value: "10"}, Object {type: "decimal", value: "."}, Object {type: "fraction", value: "00"}] to be structurally equal to [Object {type: "integer", value: "10"}]. 9.999 with maximumSignificantDigits 3 is '10'
+test262/test/intl402/Temporal/PlainMonthDay/from/reference-date-noniso-calendar.js:16: Test262Error: referenceISOYear result: Expected SameValue(«2023», «1972») to be true
test262/test/staging/sm/Function/arguments-parameter-shadowing.js:14: Test262Error: Expected SameValue(«true», «false») to be true
test262/test/staging/sm/Function/constructor-binding.js:11: Test262Error: Expected SameValue(«"function"», «"undefined"») to be true
test262/test/staging/sm/Function/function-bind.js:24: Test262Error: Conforms to NativeFunction Syntax: "function bound unbound() {\n [native code]\n}"
test262/test/staging/sm/Function/implicit-this-in-parameter-expression.js:12: Test262Error: Expected SameValue(«[object Object]», «undefined») to be true
test262/test/staging/sm/Function/invalid-parameter-list.js:13: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all
+test262/test/staging/sm/String/internalUsage.js:16: Test262Error: Expected SameValue(«false», «true») to be true
test262/test/staging/sm/class/strictExecution.js:13: Test262Error: Expected a TypeError to be thrown but no exception was thrown at all
test262/test/staging/sm/class/superPropOrdering.js:17: Test262Error: Expected a TypeError to be thrown but no exception was thrown at all
test262/test/staging/sm/lexical-environment/block-scoped-functions-annex-b-arguments.js:13: Test262Error: Expected SameValue(«"object"», «"function"») to be true