From 37840a3ba3dd98d035ab904555e3d1edd6484ac3 Mon Sep 17 00:00:00 2001 From: cgjgh <160297365+cgjgh@users.noreply.github.com> Date: Thu, 13 Mar 2025 15:39:03 -0500 Subject: [PATCH] Added Dutch, French, Italian and Spanish languages --- .changeset/tricky-streets-accept.md | 5 ++ README.md | 4 ++ src/languages/es.ts | 72 +++++++++++++++++++++++++++++ src/languages/fr.ts | 72 +++++++++++++++++++++++++++++ src/languages/index.ts | 8 +++- src/languages/it.ts | 72 +++++++++++++++++++++++++++++ src/languages/nl.ts | 72 +++++++++++++++++++++++++++++ tests/de.test.ts | 58 +++++++++++++++++++++++ tests/es.test.ts | 56 ++++++++++++++++++++++ tests/fr.test.ts | 56 ++++++++++++++++++++++ tests/it.test.ts | 57 +++++++++++++++++++++++ tests/nl.test.ts | 56 ++++++++++++++++++++++ 12 files changed, 586 insertions(+), 2 deletions(-) create mode 100644 .changeset/tricky-streets-accept.md create mode 100644 src/languages/es.ts create mode 100644 src/languages/fr.ts create mode 100644 src/languages/it.ts create mode 100644 src/languages/nl.ts create mode 100644 tests/de.test.ts create mode 100644 tests/es.test.ts create mode 100644 tests/fr.test.ts create mode 100644 tests/it.test.ts create mode 100644 tests/nl.test.ts diff --git a/.changeset/tricky-streets-accept.md b/.changeset/tricky-streets-accept.md new file mode 100644 index 0000000..225e6b1 --- /dev/null +++ b/.changeset/tricky-streets-accept.md @@ -0,0 +1,5 @@ +--- +"enhanced-ms": minor +--- + +Added language support for Dutch, French, Italian and Spanish diff --git a/README.md b/README.md index df2d581..fdbaf57 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,10 @@ The currently supported languages include: | German | de | | Russian | ru | | Māori | mi | +| Spanish | es | +| Dutch | nl | +| Italian | it | +| French | fr | You can help by adding support for more languages. diff --git a/src/languages/es.ts b/src/languages/es.ts new file mode 100644 index 0000000..179eb2c --- /dev/null +++ b/src/languages/es.ts @@ -0,0 +1,72 @@ +export default { + decimal: ',', + and: 'y', + + units: { + nanosecond: { + name: (c) => (c === 1 ? 'nanosegundo' : 'nanosegundos'), + abbreviation: 'ns', + matches: ['nanosegundo', 'nanosegundos', 'ns'], + }, + microsecond: { + name: (c) => (c === 1 ? 'microsegundo' : 'microsegundos'), + abbreviation: 'μs', + matches: ['microsegundo', 'microsegundos', 'μs'], + }, + millisecond: { + name: (c) => (c === 1 ? 'milisegundo' : 'milisegundos'), + abbreviation: 'ms', + matches: ['milisegundo', 'milisegundos', 'ms'], + }, + second: { + name: (c) => (c === 1 ? 'segundo' : 'segundos'), + abbreviation: 's', + matches: ['segundo', 'segundos', 's'], + }, + minute: { + name: (c) => (c === 1 ? 'minuto' : 'minutos'), + abbreviation: 'min', + matches: ['minuto', 'minutos', 'min'], + }, + hour: { + name: (c) => (c === 1 ? 'hora' : 'horas'), + abbreviation: 'h', + matches: ['hora', 'horas', 'h'], + }, + day: { + name: (c) => (c === 1 ? 'día' : 'días'), + abbreviation: 'd', + matches: ['día', 'días', 'd'], + }, + week: { + name: (c) => (c === 1 ? 'semana' : 'semanas'), + abbreviation: 'sem', + matches: ['semana', 'semanas', 'sem'], + }, + month: { + name: (c) => (c === 1 ? 'mes' : 'meses'), + abbreviation: 'mes', + matches: ['mes', 'meses', 'mes'], + }, + year: { + name: (c) => (c === 1 ? 'año' : 'años'), + abbreviation: 'a', + matches: ['año', 'años', 'a'], + }, + decade: { + name: (c) => (c === 1 ? 'década' : 'décadas'), + abbreviation: 'déc', + matches: ['década', 'décadas', 'déc'], + }, + century: { + name: (c) => (c === 1 ? 'siglo' : 'siglos'), + abbreviation: 'sig', + matches: ['siglo', 'siglos', 'sig'], + }, + millennium: { + name: (c) => (c === 1 ? 'milenio' : 'milenios'), + abbreviation: 'mil', + matches: ['milenio', 'milenios', 'mil'], + }, + }, +} satisfies import('./helpers/definition-types').LanguageDefinition; diff --git a/src/languages/fr.ts b/src/languages/fr.ts new file mode 100644 index 0000000..373b1f9 --- /dev/null +++ b/src/languages/fr.ts @@ -0,0 +1,72 @@ +export default { + decimal: ',', + and: 'et', + + units: { + nanosecond: { + name: (c) => (c === 1 ? 'nanoseconde' : 'nanosecondes'), + abbreviation: 'ns', + matches: ['nanoseconde', 'nanosecondes', 'ns'], + }, + microsecond: { + name: (c) => (c === 1 ? 'microseconde' : 'microsecondes'), + abbreviation: 'μs', + matches: ['microseconde', 'microsecondes', 'μs'], + }, + millisecond: { + name: (c) => (c === 1 ? 'milliseconde' : 'millisecondes'), + abbreviation: 'ms', + matches: ['milliseconde', 'millisecondes', 'ms'], + }, + second: { + name: (c) => (c === 1 ? 'seconde' : 'secondes'), + abbreviation: 's', + matches: ['seconde', 'secondes', 's'], + }, + minute: { + name: (c) => (c === 1 ? 'minute' : 'minutes'), + abbreviation: 'min', + matches: ['minute', 'minutes', 'min'], + }, + hour: { + name: (c) => (c === 1 ? 'heure' : 'heures'), + abbreviation: 'h', + matches: ['heure', 'heures', 'h'], + }, + day: { + name: (c) => (c === 1 ? 'jour' : 'jours'), + abbreviation: 'j', + matches: ['jour', 'jours', 'j'], + }, + week: { + name: (c) => (c === 1 ? 'semaine' : 'semaines'), + abbreviation: 'sem', + matches: ['semaine', 'semaines', 'sem'], + }, + month: { + name: (_c) => 'mois', // In French, the singular and plural form is identical. + abbreviation: 'mo', + matches: ['mois', 'mo'], + }, + year: { + name: (c) => (c === 1 ? 'an' : 'ans'), + abbreviation: 'an', + matches: ['an', 'ans'], + }, + decade: { + name: (c) => (c === 1 ? 'décennie' : 'décennies'), + abbreviation: 'dec', + matches: ['décennie', 'décennies', 'dec'], + }, + century: { + name: (c) => (c === 1 ? 'siècle' : 'siècles'), + abbreviation: 'siè', + matches: ['siècle', 'siècles', 'siè'], + }, + millennium: { + name: (c) => (c === 1 ? 'millénaire' : 'millénaires'), + abbreviation: 'mil', + matches: ['millénaire', 'millénaires', 'mil'], + }, + }, +} satisfies import('./helpers/definition-types').LanguageDefinition; diff --git a/src/languages/index.ts b/src/languages/index.ts index 17390da..3018c0c 100644 --- a/src/languages/index.ts +++ b/src/languages/index.ts @@ -2,10 +2,14 @@ import type { LanguageDefinition } from './helpers/definition-types'; import de from './de'; import en from './en'; +import es from './es'; +import fr from './fr'; +import it from './it'; import mi from './mi'; +import nl from './nl'; import ru from './ru'; // This prevents the whole language definition being included in the dts output -type Locale = 'de' | 'en' | 'mi' | 'ru'; +type Locale = 'de' | 'en' | 'es' | 'fr' | 'it' | 'mi' | 'nl' | 'ru'; type Languages = Record; -export const languages: Languages = { de, en, mi, ru }; +export const languages: Languages = { de, en, es, fr, it, mi, nl, ru }; diff --git a/src/languages/it.ts b/src/languages/it.ts new file mode 100644 index 0000000..91d08c9 --- /dev/null +++ b/src/languages/it.ts @@ -0,0 +1,72 @@ +export default { + decimal: ',', + and: 'e', + + units: { + nanosecond: { + name: (c) => (c === 1 ? 'nanosecondo' : 'nanosecondi'), + abbreviation: 'ns', + matches: ['nanosecondo', 'nanosecondi', 'ns'], + }, + microsecond: { + name: (c) => (c === 1 ? 'microsecondo' : 'microsecondi'), + abbreviation: 'μs', + matches: ['microsecondo', 'microsecondi', 'μs'], + }, + millisecond: { + name: (c) => (c === 1 ? 'millisecondo' : 'millisecondi'), + abbreviation: 'ms', + matches: ['millisecondo', 'millisecondi', 'ms'], + }, + second: { + name: (c) => (c === 1 ? 'secondo' : 'secondi'), + abbreviation: 's', + matches: ['secondo', 'secondi', 's'], + }, + minute: { + name: (c) => (c === 1 ? 'minuto' : 'minuti'), + abbreviation: 'min', + matches: ['minuto', 'minuti', 'min'], + }, + hour: { + name: (c) => (c === 1 ? 'ora' : 'ore'), + abbreviation: 'h', + matches: ['ora', 'ore', 'h'], + }, + day: { + name: (c) => (c === 1 ? 'giorno' : 'giorni'), + abbreviation: 'g', + matches: ['giorno', 'giorni', 'g'], + }, + week: { + name: (c) => (c === 1 ? 'settimana' : 'settimane'), + abbreviation: 'sett', + matches: ['settimana', 'settimane', 'sett'], + }, + month: { + name: (c) => (c === 1 ? 'mese' : 'mesi'), + abbreviation: 'mes', + matches: ['mese', 'mesi', 'mes'], + }, + year: { + name: (c) => (c === 1 ? 'anno' : 'anni'), + abbreviation: 'a', + matches: ['anno', 'anni', 'a'], + }, + decade: { + name: (c) => (c === 1 ? 'decennio' : 'decenni'), + abbreviation: 'dec', + matches: ['decennio', 'decenni', 'dec'], + }, + century: { + name: (c) => (c === 1 ? 'secolo' : 'secoli'), + abbreviation: 'sc', + matches: ['secolo', 'secoli', 'sc'], + }, + millennium: { + name: (c) => (c === 1 ? 'millennio' : 'millenni'), + abbreviation: 'mil', + matches: ['millennio', 'millenni', 'mil'], + }, + }, +} satisfies import('./helpers/definition-types').LanguageDefinition; diff --git a/src/languages/nl.ts b/src/languages/nl.ts new file mode 100644 index 0000000..2d3166e --- /dev/null +++ b/src/languages/nl.ts @@ -0,0 +1,72 @@ +export default { + decimal: ',', + and: 'en', + + units: { + nanosecond: { + name: (c) => (c === 1 ? 'nanoseconde' : 'nanoseconden'), + abbreviation: 'ns', + matches: ['nanoseconde', 'nanoseconden', 'ns'], + }, + microsecond: { + name: (c) => (c === 1 ? 'microseconde' : 'microseconden'), + abbreviation: 'μs', + matches: ['microseconde', 'microseconden', 'μs'], + }, + millisecond: { + name: (c) => (c === 1 ? 'milliseconde' : 'milliseconden'), + abbreviation: 'ms', + matches: ['milliseconde', 'milliseconden', 'ms'], + }, + second: { + name: (c) => (c === 1 ? 'seconde' : 'seconden'), + abbreviation: 's', + matches: ['seconde', 'seconden', 's'], + }, + minute: { + name: (c) => (c === 1 ? 'minuut' : 'minuten'), + abbreviation: 'min', + matches: ['minuut', 'minuten', 'min'], + }, + hour: { + name: (c) => (c === 1 ? 'uur' : 'uren'), + abbreviation: 'h', + matches: ['uur', 'uren', 'h'], + }, + day: { + name: (c) => (c === 1 ? 'dag' : 'dagen'), + abbreviation: 'd', + matches: ['dag', 'dagen', 'd'], + }, + week: { + name: (c) => (c === 1 ? 'week' : 'weken'), + abbreviation: 'w', + matches: ['week', 'weken', 'w'], + }, + month: { + name: (c) => (c === 1 ? 'maand' : 'maanden'), + abbreviation: 'mnd', + matches: ['maand', 'maanden', 'mnd'], + }, + year: { + name: (c) => (c === 1 ? 'jaar' : 'jaren'), + abbreviation: 'jr', + matches: ['jaar', 'jaren', 'jr'], + }, + decade: { + name: (c) => (c === 1 ? 'decennium' : 'decennia'), + abbreviation: 'dec', + matches: ['decennium', 'decennia', 'dec'], + }, + century: { + name: (c) => (c === 1 ? 'eeuw' : 'eeuwen'), + abbreviation: 'eeuw', + matches: ['eeuw', 'eeuwen'], + }, + millennium: { + name: (c) => (c === 1 ? 'millennium' : 'millennia'), + abbreviation: 'mil', + matches: ['millennium', 'millennia', 'mil'], + }, + }, +} satisfies import('./helpers/definition-types').LanguageDefinition; diff --git a/tests/de.test.ts b/tests/de.test.ts new file mode 100644 index 0000000..ce02cb2 --- /dev/null +++ b/tests/de.test.ts @@ -0,0 +1,58 @@ +import { createMs } from 'enhanced-ms'; +import { describe, expect, it } from 'vitest'; + +// Using German locale (de) +const ms = createMs({ language: 'de' }); + +describe('German (Deutsch)', () => { + describe('format milliseconds', () => { + it('formats with default options', () => { + // 90061 ms should format as "1 Minute 30 Sekunden" + expect(ms(90061)).toBe('1 Minute 30 Sekunden'); + // 90061000 ms should format as "1 Tag 1 Stunde 1 Minute 1 Sekunde" + expect(ms(90061000)).toBe('1 Tag 1 Stunde 1 Minute 1 Sekunde'); + }); + + it('returns null for durations below one second with default options', () => { + expect(ms(0)).toBeNull(); + }); + + it('formats with preset short', () => { + // Expected abbreviations based on the German config: + // Minute -> "Min.", Sekunde -> "Sek.", Tag -> "T.", Stunde -> "Std." + expect(ms(90061, 'short')).toBe('1Min. 30Sek.'); + expect(ms(90061000, 'short')).toBe('1T. 1Std.'); + }); + + it('formats with colon notation preset', () => { + expect(ms(90061, 'colonNotation')).toBe('01:30'); + expect(ms(90061000, 'colonNotation')).toBe('25:01:01'); + }); + + it('formats with use abbreviations', () => { + const options = { useAbbreviations: true }; + expect(ms(90061, options)).toBe('1Min. 30Sek.'); + expect(ms(90061000, options)).toBe('1T. 1Std. 1Min. 1Sek.'); + }); + + it('formats with a unit limit', () => { + const options = { unitLimit: 1 }; + expect(ms(90061, options)).toBe('1 Minute'); + expect(ms(90061000, options)).toBe('1 Tag'); + }); + }); + + describe('parse duration', () => { + it('parses durations correctly', () => { + expect(ms('1 Minute 30 Sekunden')).toBe(90000); + expect(ms('1Min. 30Sek.')).toBe(90000); + expect(ms('1 Minute 30 Sekunden 61 Millisekunden')).toBe(90061); + expect(ms('1Min. 30Sek. 61ms')).toBe(90061); + }); + + it('returns zero for invalid duration strings', () => { + expect(ms('nyr9341')).toBe(0); + expect(ms('o4utrc89nyt')).toBe(0); + }); + }); +}); diff --git a/tests/es.test.ts b/tests/es.test.ts new file mode 100644 index 0000000..5e27fa9 --- /dev/null +++ b/tests/es.test.ts @@ -0,0 +1,56 @@ +import { createMs } from 'enhanced-ms'; +import { describe, expect, it } from 'vitest'; + +const ms = createMs({ language: 'es' }); + +describe('Spanish (Español)', () => { + describe('format milliseconds', () => { + it('formats with default options', () => { + // 90061 ms should format as "1 minuto 30 segundos" in Spanish + expect(ms(90061)).toBe('1 minuto 30 segundos'); + // 90061000 ms should format as "1 día 1 hora 1 minuto 1 segundo" in Spanish + expect(ms(90061000)).toBe('1 día 1 hora 1 minuto 1 segundo'); + }); + + it('returns null for durations below one second with default options', () => { + expect(ms(0)).toBeNull(); + }); + + it('formats with preset short', () => { + // Expected abbreviations: "min" for minuto, "s" for segundo, "d" for día, "h" for hora. + expect(ms(90061, 'short')).toBe('1min 30s'); + expect(ms(90061000, 'short')).toBe('1d 1h'); + }); + + it('formats with colon notation preset', () => { + expect(ms(90061, 'colonNotation')).toBe('01:30'); + expect(ms(90061000, 'colonNotation')).toBe('25:01:01'); + }); + + it('formats with use abbreviations', () => { + const options = { useAbbreviations: true }; + expect(ms(90061, options)).toBe('1min 30s'); + expect(ms(90061000, options)).toBe('1d 1h 1min 1s'); + }); + + it('formats with a unit limit', () => { + const options = { unitLimit: 1 }; + expect(ms(90061, options)).toBe('1 minuto'); + expect(ms(90061000, options)).toBe('1 día'); + }); + }); + + describe('parse duration', () => { + it('parses durations correctly', () => { + expect(ms('1 minuto 30 segundos')).toBe(90000); + expect(ms('1min 30s')).toBe(90000); + expect(ms('1 minuto 30 segundos 61 milisegundos')).toBe(90061); + expect(ms('1min 30s 61ms')).toBe(90061); + }); + + it('returns zero for invalid duration strings', () => { + expect(ms('nyr9341')).toBe(0); + expect(ms('o4utrc89nyt')).toBe(0); + }); + }); +}); diff --git a/tests/fr.test.ts b/tests/fr.test.ts new file mode 100644 index 0000000..5b28e25 --- /dev/null +++ b/tests/fr.test.ts @@ -0,0 +1,56 @@ +import { createMs } from 'enhanced-ms'; +import { describe, expect, it } from 'vitest'; + +const ms = createMs({ language: 'fr' }); + +describe('French (Français)', () => { + describe('format milliseconds', () => { + it('formats with default options', () => { + // 90061 ms should format as "1 minute 30 secondes" in French + expect(ms(90061)).toBe('1 minute 30 secondes'); + // 90061000 ms should format as "1 jour 1 heure 1 minute 1 seconde" in French + expect(ms(90061000)).toBe('1 jour 1 heure 1 minute 1 seconde'); + }); + + it('returns null for durations below one second with default options', () => { + expect(ms(0)).toBeNull(); + }); + + it('formats with preset short', () => { + // Expected short format using abbreviations: "min" for minute, "s" for seconde, "j" for jour, "h" for heure. + expect(ms(90061, 'short')).toBe('1min 30s'); + expect(ms(90061000, 'short')).toBe('1j 1h'); + }); + + it('formats with colon notation preset', () => { + expect(ms(90061, 'colonNotation')).toBe('01:30'); + expect(ms(90061000, 'colonNotation')).toBe('25:01:01'); + }); + + it('formats with use abbreviations', () => { + const options = { useAbbreviations: true }; + expect(ms(90061, options)).toBe('1min 30s'); + expect(ms(90061000, options)).toBe('1j 1h 1min 1s'); + }); + + it('formats with a unit limit', () => { + const options = { unitLimit: 1 }; + expect(ms(90061, options)).toBe('1 minute'); + expect(ms(90061000, options)).toBe('1 jour'); + }); + }); + + describe('parse duration', () => { + it('parses durations correctly', () => { + expect(ms('1 minute 30 secondes')).toBe(90000); + expect(ms('1min 30s')).toBe(90000); + expect(ms('1 minute 30 secondes 61 millisecondes')).toBe(90061); + expect(ms('1min 30s 61ms')).toBe(90061); + }); + + it('returns zero for invalid duration strings', () => { + expect(ms('nyr9341')).toBe(0); + expect(ms('o4utrc89nyt')).toBe(0); + }); + }); +}); diff --git a/tests/it.test.ts b/tests/it.test.ts new file mode 100644 index 0000000..44234de --- /dev/null +++ b/tests/it.test.ts @@ -0,0 +1,57 @@ +import { createMs } from 'enhanced-ms'; +import { describe, expect, it } from 'vitest'; + +const ms = createMs({ language: 'it' }); + +describe('Italian (Italiano)', () => { + describe('format milliseconds', () => { + it('formats with default options', () => { + // 90061 ms should format as "1 minuto 30 secondi" in Italian. + expect(ms(90061)).toBe('1 minuto 30 secondi'); + // 90061000 ms should format as "1 giorno 1 ora 1 minuto 1 secondo" in Italian. + expect(ms(90061000)).toBe('1 giorno 1 ora 1 minuto 1 secondo'); + }); + + it('returns null for durations below one second with default options', () => { + expect(ms(0)).toBeNull(); + }); + + it('formats with preset short', () => { + // Expected abbreviations: "min" for minuto, "s" for secondi, + // "g" for giorno, "h" for ora. + expect(ms(90061, 'short')).toBe('1min 30s'); + expect(ms(90061000, 'short')).toBe('1g 1h'); + }); + + it('formats with colon notation preset', () => { + expect(ms(90061, 'colonNotation')).toBe('01:30'); + expect(ms(90061000, 'colonNotation')).toBe('25:01:01'); + }); + + it('formats with use abbreviations', () => { + const options = { useAbbreviations: true }; + expect(ms(90061, options)).toBe('1min 30s'); + expect(ms(90061000, options)).toBe('1g 1h 1min 1s'); + }); + + it('formats with a unit limit', () => { + const options = { unitLimit: 1 }; + expect(ms(90061, options)).toBe('1 minuto'); + expect(ms(90061000, options)).toBe('1 giorno'); + }); + }); + + describe('parse duration', () => { + it('parses durations correctly', () => { + expect(ms('1 minuto 30 secondi')).toBe(90000); + expect(ms('1min 30s')).toBe(90000); + expect(ms('1 minuto 30 secondi 61 millisecondi')).toBe(90061); + expect(ms('1min 30s 61ms')).toBe(90061); + }); + + it('returns zero for invalid duration strings', () => { + expect(ms('nyr9341')).toBe(0); + expect(ms('o4utrc89nyt')).toBe(0); + }); + }); +}); diff --git a/tests/nl.test.ts b/tests/nl.test.ts new file mode 100644 index 0000000..b742818 --- /dev/null +++ b/tests/nl.test.ts @@ -0,0 +1,56 @@ +import { createMs } from 'enhanced-ms'; +import { describe, expect, it } from 'vitest'; + +const ms = createMs({ language: 'nl' }); + +describe('Dutch (Nederlands)', () => { + describe('format milliseconds', () => { + it('formats with default options', () => { + // 90061 ms should format as "1 minuut 30 seconden" in Dutch. + expect(ms(90061)).toBe('1 minuut 30 seconden'); + // 90061000 ms should format as "1 dag 1 uur 1 minuut 1 seconde" in Dutch. + expect(ms(90061000)).toBe('1 dag 1 uur 1 minuut 1 seconde'); + }); + + it('returns null for durations below one second with default options', () => { + expect(ms(0)).toBeNull(); + }); + + it('formats with preset short', () => { + // Expected short format: "min" for minuut, "s" for seconde, "d" for dag, "h" for uur. + expect(ms(90061, 'short')).toBe('1min 30s'); + expect(ms(90061000, 'short')).toBe('1d 1h'); + }); + + it('formats with colon notation preset', () => { + expect(ms(90061, 'colonNotation')).toBe('01:30'); + expect(ms(90061000, 'colonNotation')).toBe('25:01:01'); + }); + + it('formats with use abbreviations', () => { + const options = { useAbbreviations: true }; + expect(ms(90061, options)).toBe('1min 30s'); + expect(ms(90061000, options)).toBe('1d 1h 1min 1s'); + }); + + it('formats with a unit limit', () => { + const options = { unitLimit: 1 }; + expect(ms(90061, options)).toBe('1 minuut'); + expect(ms(90061000, options)).toBe('1 dag'); + }); + }); + + describe('parse duration', () => { + it('parses durations correctly', () => { + expect(ms('1 minuut 30 seconden')).toBe(90000); + expect(ms('1min 30s')).toBe(90000); + expect(ms('1 minuut 30 seconden 61 milliseconden')).toBe(90061); + expect(ms('1min 30s 61ms')).toBe(90061); + }); + + it('returns zero for invalid duration strings', () => { + expect(ms('nyr9341')).toBe(0); + expect(ms('o4utrc89nyt')).toBe(0); + }); + }); +});