tmw-numeric 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AI_BUILD_PLAN.md +127 -0
- package/esm2020/lib/models/tmw-numeric-options.model.mjs +37 -0
- package/esm2020/lib/tmw-numeric-mask.directive.mjs +272 -0
- package/esm2020/public-api.mjs +6 -0
- package/esm2020/tmw-numeric.mjs +5 -0
- package/fesm2015/tmw-numeric.mjs +320 -0
- package/fesm2015/tmw-numeric.mjs.map +1 -0
- package/fesm2020/tmw-numeric.mjs +319 -0
- package/fesm2020/tmw-numeric.mjs.map +1 -0
- package/index.d.ts +5 -0
- package/lib/models/tmw-numeric-options.model.d.ts +47 -0
- package/lib/tmw-numeric-mask.directive.d.ts +90 -0
- package/package.json +36 -0
- package/public-api.d.ts +2 -0
package/AI_BUILD_PLAN.md
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# AI_BUILD_PLAN — tmw-numeric
|
|
2
|
+
|
|
3
|
+
Sostituto di `@eqproject/eqp-numeric`, nato non da un'iniziativa dedicata come tmw-select/tmw-table/
|
|
4
|
+
tmw-attachments, ma come tassello di un'indagine più ampia: rimozione sicura dei pacchetti
|
|
5
|
+
`@eqproject/*` da TMED (v. `Tmed.Web/TmedClient/package.json`), tenendo solo `eqp-filters` e
|
|
6
|
+
`eqp-dynamic-module` (quest'ultimo non rimovibile — è il motore dei form dinamici, non un widget).
|
|
7
|
+
|
|
8
|
+
## Cosa sostituisce
|
|
9
|
+
|
|
10
|
+
`EqpNumericDirective` (selettore `[eqpNumericMask]`) — **non** un componente, una direttiva
|
|
11
|
+
`ControlValueAccessor` su `<input>` per la mascheratura di valori numerici/valuta (separatori
|
|
12
|
+
migliaia/decimali, prefisso/suffisso, precisione, min/max, modalità di digitazione FINANCIAL/
|
|
13
|
+
NATURAL). Documentata in `node_modules/@eqproject/eqp-numeric/README.md` (stessa forma/API di
|
|
14
|
+
`ngx-currency`/`ng2-currency-mask`).
|
|
15
|
+
|
|
16
|
+
## Audit uso reale in TMED (prima di scrivere una riga di codice)
|
|
17
|
+
|
|
18
|
+
5 punti d'uso reali, tutti campi prezzo (fatturazione/ambulatori, **fuori** da `projects/tmed-therapy`
|
|
19
|
+
— nessun impatto clinico/MDR):
|
|
20
|
+
- `invoice-generate.component.html:64`
|
|
21
|
+
- `add-outpatientclinics.component.html:562,1768,1776`
|
|
22
|
+
- `create-invoice-fattureincloud.component.html:136`
|
|
23
|
+
|
|
24
|
+
Tutti e 5 passano **lo stesso** `[options]="{ prefix: '€ ', thousands: '.', decimal: ',' }"` (formato
|
|
25
|
+
euro) — nessuno usa i default nudi del pacchetto (`$`/`,`/`.`) né chiama `EqpNumericModule.forRoot()`.
|
|
26
|
+
Wiring in `src/modules/shared.module.ts` (import + `imports`/`exports` di `SharedModule`).
|
|
27
|
+
|
|
28
|
+
## Decisioni
|
|
29
|
+
|
|
30
|
+
1. **Direttiva standalone**, stesso principio delle altre `tmw-*` (niente `TmwNumericModule`,
|
|
31
|
+
si importa `TmwNumericMaskDirective` direttamente).
|
|
32
|
+
2. **Selettore** `[tmwNumericMask]` (rename `eqpNumericMask`→`tmwNumericMask`, stesso principio
|
|
33
|
+
`eqp-xxx`→`tmw-xxx` delle altre). **`[options]` e i nomi delle sue proprietà (`align`,
|
|
34
|
+
`allowNegative`, `decimal`, `precision`, `prefix`, `suffix`, `thousands`, `nullable`, `min`,
|
|
35
|
+
`max`, `inputMode`) restano INVARIATI** — compatibilità byte-per-byte con i binding esistenti,
|
|
36
|
+
il rename tocca solo l'attributo/selettore.
|
|
37
|
+
3. **Nessun `forRoot()`**: nessun consumer reale lo usava, i default (`TMW_NUMERIC_DEFAULT_OPTIONS`)
|
|
38
|
+
bastano com'erano nell'originale.
|
|
39
|
+
4. **`TmwNumericInputMode`** (rename `EqpNumericInputMode`) con gli stessi due valori
|
|
40
|
+
`FINANCIAL`/`NATURAL` e comportamento identico.
|
|
41
|
+
|
|
42
|
+
## Bug scoperti e corretti durante la verifica funzionale (Playwright, non solo tsc)
|
|
43
|
+
|
|
44
|
+
La prima bozza (formattazione a piena precisione ad ogni tasto anche in modalità NATURAL) si è
|
|
45
|
+
rivelata **rotta digitando davvero** (verificato con `page.type()`, non solo lettura del codice):
|
|
46
|
+
|
|
47
|
+
1. **Cifre perse durante la digitazione (NATURAL)**: arrotondare/paddare a `precision` ad OGNI
|
|
48
|
+
`input` event faceva sì che digitare `"1"` su un campo vuoto producesse subito `"$ 0.00"` —
|
|
49
|
+
la cifra veniva arrotondata via prima ancora di poter comporre un numero. Fix: formattazione
|
|
50
|
+
**live** durante la digitazione (nessun padding/arrotondamento, si preservano le cifre esatte
|
|
51
|
+
digitate, capped a `precision` cifre decimali) e formattazione **piena** (padding/arrotondamento
|
|
52
|
+
`toFixed`) solo a `blur`/`writeValue`/cambio opzioni. La modalità FINANCIAL non soffriva di
|
|
53
|
+
questo bug (si ricalcola sempre da zero dalle sole cifre, insensibile alla formattazione
|
|
54
|
+
precedente) — lì il formato pieno ad ogni tasto è corretto fin da subito.
|
|
55
|
+
2. **Segno negativo mai riconosciuto**: `rawValue.startsWith('-')` non funziona MAI, perché il
|
|
56
|
+
segno digitato dall'utente finisce sempre DOPO un eventuale prefisso (es. `"$ -5"`, non
|
|
57
|
+
`"-$ 5"` nella stringa grezza del campo) — il controllo iniziale falliva sempre silenziosamente.
|
|
58
|
+
Fix: `rawValue.includes('-')`.
|
|
59
|
+
|
|
60
|
+
Entrambi scoperti SOLO grazie a un test funzionale che digita davvero nel campo (Playwright
|
|
61
|
+
`page.locator(...).type(...)`) — una verifica solo statica/tsc non li avrebbe mai presi.
|
|
62
|
+
|
|
63
|
+
## Verifica
|
|
64
|
+
|
|
65
|
+
Playground `test-tmw-numeric` in `tmw-suite` (route `/tmw-numeric`, 3 casi: default TMED — euro,
|
|
66
|
+
virgola decimale, punto migliaia, no `[options]` custom oltre a quello reale —, custom con
|
|
67
|
+
`nullable`+`allowNegative:false`, FINANCIAL). Verificato via Playwright headless (Chromium 1228 già
|
|
68
|
+
installato in TMED, non serve emulazione mobile qui): digitazione carattere per carattere,
|
|
69
|
+
`fill('')`+`type(...)`+`blur()`, controllo sia del valore visualizzato sia del model (`ngModel`)
|
|
70
|
+
sottostante. Tutti i casi passano dopo il fix, incluso il caso reale esatto usato in TMED (prefisso
|
|
71
|
+
`€ `, migliaia `.`, decimale `,`). Zero errori console.
|
|
72
|
+
|
|
73
|
+
## Sync in TMED
|
|
74
|
+
|
|
75
|
+
`tmw-numeric` 0.1.0, build produzione, `npm pack` → tarball locale (non pubblicato su npm reale,
|
|
76
|
+
a differenza di tmw-attachments — l'utente non l'ha richiesto per questo pacchetto, resta per
|
|
77
|
+
quando lo chiederà a parte, stesso principio di tmw-table/tmw-select prima della pubblicazione).
|
|
78
|
+
`TmedClient/package.json`: rimosso `@eqproject/eqp-numeric`, aggiunto `tmw-numeric` (tarball).
|
|
79
|
+
`shared.module.ts`: `EqpNumericModule`→`TmwNumericMaskDirective`. 5 template: `eqpNumericMask`→
|
|
80
|
+
`tmwNumericMask` (`[options]` invariato). `tsc --noEmit --skipLibCheck`: 27 errori pre-esistenti
|
|
81
|
+
invariati, zero nuovi. `ng serve` (heap 16GB, v. `project_ng_serve_perf` in memoria — necessario,
|
|
82
|
+
altrimenti OOM) pulito, `Compiled successfully`.
|
|
83
|
+
|
|
84
|
+
**Non verificato dal vivo in TMED** (stesso limite onesto di altre sincronizzazioni): nessuna
|
|
85
|
+
credenziale e2e reale disponibile in questa sessione (`e2e/.auth/credentials.json` assente) — la
|
|
86
|
+
verifica del comportamento REALE nei 5 campi prezzo si basa su tsc pulito + AOT compile pulito +
|
|
87
|
+
verifica funzionale esaustiva nel playground con la STESSA identica configurazione `[options]`
|
|
88
|
+
usata in produzione (prefisso `€ `, migliaia `.`, decimale `,`), non su un click reale in TMED.
|
|
89
|
+
|
|
90
|
+
## Round mobile/tablet (2026-07-15, stessa giornata) — v0.1.0 → v0.1.1
|
|
91
|
+
|
|
92
|
+
L'utente ha chiesto esplicitamente se il componente fosse pensato per mobile/tablet — risposta
|
|
93
|
+
onesta: non ancora. Analisi e fix:
|
|
94
|
+
|
|
95
|
+
1. **Nessun hint di tastiera numerica**: un `<input>` senza `type`/`inputmode` mostra la tastiera
|
|
96
|
+
alfanumerica completa su mobile/tablet — sbagliato per un campo numerico, e nessuno dei 5 usi
|
|
97
|
+
reali in TMED imposta `type`/`inputmode` proprio. Fix: la direttiva imposta
|
|
98
|
+
`inputmode="decimal"` nel costruttore, MA SOLO se il consumer non ha già messo un proprio
|
|
99
|
+
`type`/`inputmode` nel template (nessun conflitto, nessun binding Angular duplicato sullo
|
|
100
|
+
stesso attributo).
|
|
101
|
+
|
|
102
|
+
2. **Bug reale scoperto testando su viewport mobile con tastiera touch**: le tastiere numeriche
|
|
103
|
+
mobile mostrano quasi sempre "." come tasto decimale, a prescindere dalla configurazione locale
|
|
104
|
+
— un primo fix ("accetta sia il separatore configurato sia `.` come decimale") si è rivelato
|
|
105
|
+
**rotto per la configurazione ESATTA usata in produzione** (`thousands: '.'`, `decimal: ','` —
|
|
106
|
+
formato euro): il punto delle migliaia già inserito dal render "live" veniva confuso con il
|
|
107
|
+
punto decimale appena digitato (entrambi lo stesso carattere), producendo un parsing
|
|
108
|
+
completamente sbagliato (digitare `"1234.5"` risultava in `"€ 1,23"` invece di
|
|
109
|
+
`"€ 1.234,50"`). **Fix corretto**: stato persistente `_hasDecimalState`, impostato SOLO quando
|
|
110
|
+
`event.data` (il carattere/testo appena digitato/incollato, non l'intera stringa già
|
|
111
|
+
formattata) corrisponde al separatore decimale configurato o a `'.'` — una volta noto che un
|
|
112
|
+
separatore decimale esiste, si cerca la sua ULTIMA occorrenza nella stringa (le migliaia, anche
|
|
113
|
+
quando coincidono con `'.'`, possono comparire SOLO prima del separatore decimale reale, mai
|
|
114
|
+
dopo — la formattazione non raggruppa mai le cifre decimali). Gestito anche il caso di
|
|
115
|
+
backspace sul separatore (torna correttamente a "nessun decimale", verificato: cancellare la
|
|
116
|
+
virgola e digitare una cifra la rimette nella parte intera, non in quella decimale).
|
|
117
|
+
|
|
118
|
+
**Cosa NON serviva**: nessun CSS responsive/breakpoint — la direttiva non possiede overlay/modali/
|
|
119
|
+
dropdown propri (a differenza di tmw-attachments/tmw-select/tmw-table), è un attributo su un
|
|
120
|
+
`<input>` che il consumer stila autonomamente; non c'è "chrome" della libreria che possa rompersi
|
|
121
|
+
su schermi piccoli.
|
|
122
|
+
|
|
123
|
+
**Verifica**: Playwright con device emulation (`iPhone 13`, `hasTouch:true`) — confermato
|
|
124
|
+
`inputmode="decimal"` presente, digitazione carattere per carattere del formato euro reale
|
|
125
|
+
(`"1234.5"` e `"1234,5"`) entrambe producono `"€ 1.234,50"` / modello `1234.5`, backspace sul
|
|
126
|
+
separatore verificato, zero errori console. Bump a v0.1.1, tarball rigenerata, risincronizzata in
|
|
127
|
+
TMED (`tsc` pulito, 27 errori pre-esistenti invariati).
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Modalità di digitazione — nomi/valori/comportamento invariati rispetto a
|
|
3
|
+
* `@eqproject/eqp-numeric` (`EqpNumericInputMode`), per parità di comportamento.
|
|
4
|
+
*/
|
|
5
|
+
export var TmwNumericInputMode;
|
|
6
|
+
(function (TmwNumericInputMode) {
|
|
7
|
+
/**
|
|
8
|
+
* I numeri partono dalla precisione più alta (i decimali): digitare uno shifta tutto a
|
|
9
|
+
* sinistra, il carattere decimale digitato viene ignorato. Es. `'12'` → `'0.12'`,
|
|
10
|
+
* `'1234'` → `'12.34'`.
|
|
11
|
+
*/
|
|
12
|
+
TmwNumericInputMode["FINANCIAL"] = "FINANCIAL";
|
|
13
|
+
/**
|
|
14
|
+
* I numeri partono a sinistra del separatore decimale, come un campo di testo qualunque.
|
|
15
|
+
* Es. `'1234'` → `'1234'`, `'12.34'` → `'12.34'`.
|
|
16
|
+
*/
|
|
17
|
+
TmwNumericInputMode["NATURAL"] = "NATURAL";
|
|
18
|
+
})(TmwNumericInputMode || (TmwNumericInputMode = {}));
|
|
19
|
+
/**
|
|
20
|
+
* Default identici a `@eqproject/eqp-numeric` — nessun consumer TMED chiamava
|
|
21
|
+
* `EqpNumericModule.forRoot(...)` né passava `[options]`, quindi questi default SONO il
|
|
22
|
+
* comportamento reale in produzione (v. AI_BUILD_PLAN.md per i 5 punti d'uso reali).
|
|
23
|
+
*/
|
|
24
|
+
export const TMW_NUMERIC_DEFAULT_OPTIONS = {
|
|
25
|
+
align: 'right',
|
|
26
|
+
allowNegative: true,
|
|
27
|
+
decimal: '.',
|
|
28
|
+
precision: 2,
|
|
29
|
+
prefix: '$ ',
|
|
30
|
+
suffix: '',
|
|
31
|
+
thousands: ',',
|
|
32
|
+
nullable: false,
|
|
33
|
+
min: undefined,
|
|
34
|
+
max: undefined,
|
|
35
|
+
inputMode: TmwNumericInputMode.NATURAL,
|
|
36
|
+
};
|
|
37
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidG13LW51bWVyaWMtb3B0aW9ucy5tb2RlbC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL3Rtdy1udW1lcmljL3NyYy9saWIvbW9kZWxzL3Rtdy1udW1lcmljLW9wdGlvbnMubW9kZWwudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7OztHQUdHO0FBQ0gsTUFBTSxDQUFOLElBQVksbUJBWVg7QUFaRCxXQUFZLG1CQUFtQjtJQUM3Qjs7OztPQUlHO0lBQ0gsOENBQXVCLENBQUE7SUFDdkI7OztPQUdHO0lBQ0gsMENBQW1CLENBQUE7QUFDckIsQ0FBQyxFQVpXLG1CQUFtQixLQUFuQixtQkFBbUIsUUFZOUI7QUEyQkQ7Ozs7R0FJRztBQUNILE1BQU0sQ0FBQyxNQUFNLDJCQUEyQixHQUFnQztJQUN0RSxLQUFLLEVBQUUsT0FBTztJQUNkLGFBQWEsRUFBRSxJQUFJO0lBQ25CLE9BQU8sRUFBRSxHQUFHO0lBQ1osU0FBUyxFQUFFLENBQUM7SUFDWixNQUFNLEVBQUUsSUFBSTtJQUNaLE1BQU0sRUFBRSxFQUFFO0lBQ1YsU0FBUyxFQUFFLEdBQUc7SUFDZCxRQUFRLEVBQUUsS0FBSztJQUNmLEdBQUcsRUFBRSxTQUE4QjtJQUNuQyxHQUFHLEVBQUUsU0FBOEI7SUFDbkMsU0FBUyxFQUFFLG1CQUFtQixDQUFDLE9BQU87Q0FDdkMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogTW9kYWxpdMOgIGRpIGRpZ2l0YXppb25lIOKAlCBub21pL3ZhbG9yaS9jb21wb3J0YW1lbnRvIGludmFyaWF0aSByaXNwZXR0byBhXG4gKiBgQGVxcHJvamVjdC9lcXAtbnVtZXJpY2AgKGBFcXBOdW1lcmljSW5wdXRNb2RlYCksIHBlciBwYXJpdMOgIGRpIGNvbXBvcnRhbWVudG8uXG4gKi9cbmV4cG9ydCBlbnVtIFRtd051bWVyaWNJbnB1dE1vZGUge1xuICAvKipcbiAgICogSSBudW1lcmkgcGFydG9ubyBkYWxsYSBwcmVjaXNpb25lIHBpw7kgYWx0YSAoaSBkZWNpbWFsaSk6IGRpZ2l0YXJlIHVubyBzaGlmdGEgdHV0dG8gYVxuICAgKiBzaW5pc3RyYSwgaWwgY2FyYXR0ZXJlIGRlY2ltYWxlIGRpZ2l0YXRvIHZpZW5lIGlnbm9yYXRvLiBFcy4gYCcxMidgIOKGkiBgJzAuMTInYCxcbiAgICogYCcxMjM0J2Ag4oaSIGAnMTIuMzQnYC5cbiAgICovXG4gIEZJTkFOQ0lBTCA9ICdGSU5BTkNJQUwnLFxuICAvKipcbiAgICogSSBudW1lcmkgcGFydG9ubyBhIHNpbmlzdHJhIGRlbCBzZXBhcmF0b3JlIGRlY2ltYWxlLCBjb21lIHVuIGNhbXBvIGRpIHRlc3RvIHF1YWx1bnF1ZS5cbiAgICogRXMuIGAnMTIzNCdgIOKGkiBgJzEyMzQnYCwgYCcxMi4zNCdgIOKGkiBgJzEyLjM0J2AuXG4gICAqL1xuICBOQVRVUkFMID0gJ05BVFVSQUwnLFxufVxuXG5leHBvcnQgaW50ZXJmYWNlIFRtd051bWVyaWNPcHRpb25zIHtcbiAgLyoqIEFsbGluZWFtZW50byB0ZXN0byBuZWxsJ2lucHV0LiBEZWZhdWx0IGAncmlnaHQnYC4gKi9cbiAgYWxpZ24/OiAnbGVmdCcgfCAncmlnaHQnO1xuICAvKiogU2UgYHRydWVgIGNvbnNlbnRlIHZhbG9yaSBuZWdhdGl2aS4gRGVmYXVsdCBgdHJ1ZWAuICovXG4gIGFsbG93TmVnYXRpdmU/OiBib29sZWFuO1xuICAvKiogU2VwYXJhdG9yZSBkZWkgZGVjaW1hbGkuIERlZmF1bHQgYCcuJ2AuICovXG4gIGRlY2ltYWw/OiBzdHJpbmc7XG4gIC8qKiBOdW1lcm8gZGkgY2lmcmUgZGVjaW1hbGkuIERlZmF1bHQgYDJgLiAqL1xuICBwcmVjaXNpb24/OiBudW1iZXI7XG4gIC8qKiBQcmVmaXNzbyAoZXMuIHNpbWJvbG8gdmFsdXRhKS4gRGVmYXVsdCBgJyQgJ2AuICovXG4gIHByZWZpeD86IHN0cmluZztcbiAgLyoqIFN1ZmZpc3NvLiBEZWZhdWx0IGAnJ2AuICovXG4gIHN1ZmZpeD86IHN0cmluZztcbiAgLyoqIFNlcGFyYXRvcmUgZGVsbGUgbWlnbGlhaWEuIERlZmF1bHQgYCcsJ2AuICovXG4gIHRob3VzYW5kcz86IHN0cmluZztcbiAgLyoqIFNlIGB0cnVlYCwgdW4gY2FtcG8gdnVvdG8gcHJvZHVjZSBgbnVsbGAgaW52ZWNlIGRpIGAwYC4gRGVmYXVsdCBgZmFsc2VgLiAqL1xuICBudWxsYWJsZT86IGJvb2xlYW47XG4gIC8qKiBWYWxvcmUgbWluaW1vIGNvbnNlbnRpdG8uIERlZmF1bHQgYHVuZGVmaW5lZGAgKG5lc3N1biBsaW1pdGUpLiAqL1xuICBtaW4/OiBudW1iZXI7XG4gIC8qKiBWYWxvcmUgbWFzc2ltbyBjb25zZW50aXRvLiBEZWZhdWx0IGB1bmRlZmluZWRgIChuZXNzdW4gbGltaXRlKS4gKi9cbiAgbWF4PzogbnVtYmVyO1xuICAvKiogTW9kYWxpdMOgIGRpIGRpZ2l0YXppb25lLiBEZWZhdWx0IGBOQVRVUkFMYC4gKi9cbiAgaW5wdXRNb2RlPzogVG13TnVtZXJpY0lucHV0TW9kZTtcbn1cblxuLyoqXG4gKiBEZWZhdWx0IGlkZW50aWNpIGEgYEBlcXByb2plY3QvZXFwLW51bWVyaWNgIOKAlCBuZXNzdW4gY29uc3VtZXIgVE1FRCBjaGlhbWF2YVxuICogYEVxcE51bWVyaWNNb2R1bGUuZm9yUm9vdCguLi4pYCBuw6kgcGFzc2F2YSBgW29wdGlvbnNdYCwgcXVpbmRpIHF1ZXN0aSBkZWZhdWx0IFNPTk8gaWxcbiAqIGNvbXBvcnRhbWVudG8gcmVhbGUgaW4gcHJvZHV6aW9uZSAodi4gQUlfQlVJTERfUExBTi5tZCBwZXIgaSA1IHB1bnRpIGQndXNvIHJlYWxpKS5cbiAqL1xuZXhwb3J0IGNvbnN0IFRNV19OVU1FUklDX0RFRkFVTFRfT1BUSU9OUzogUmVxdWlyZWQ8VG13TnVtZXJpY09wdGlvbnM+ID0ge1xuICBhbGlnbjogJ3JpZ2h0JyxcbiAgYWxsb3dOZWdhdGl2ZTogdHJ1ZSxcbiAgZGVjaW1hbDogJy4nLFxuICBwcmVjaXNpb246IDIsXG4gIHByZWZpeDogJyQgJyxcbiAgc3VmZml4OiAnJyxcbiAgdGhvdXNhbmRzOiAnLCcsXG4gIG51bGxhYmxlOiBmYWxzZSxcbiAgbWluOiB1bmRlZmluZWQgYXMgdW5rbm93biBhcyBudW1iZXIsXG4gIG1heDogdW5kZWZpbmVkIGFzIHVua25vd24gYXMgbnVtYmVyLFxuICBpbnB1dE1vZGU6IFRtd051bWVyaWNJbnB1dE1vZGUuTkFUVVJBTCxcbn07XG4iXX0=
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
import { Directive, HostListener, Input, forwardRef } from '@angular/core';
|
|
2
|
+
import { NG_VALUE_ACCESSOR } from '@angular/forms';
|
|
3
|
+
import { TMW_NUMERIC_DEFAULT_OPTIONS, TmwNumericInputMode } from './models/tmw-numeric-options.model';
|
|
4
|
+
import * as i0 from "@angular/core";
|
|
5
|
+
/**
|
|
6
|
+
* Sostituto di `[eqpNumericMask]` (`@eqproject/eqp-numeric`) — stesso `[options]`, stessi nomi
|
|
7
|
+
* di opzione, stessi default (v. `TMW_NUMERIC_DEFAULT_OPTIONS`). Nessun `forRoot()`: nessun
|
|
8
|
+
* consumer reale in TMED lo usava, i default del pacchetto originale erano già il comportamento
|
|
9
|
+
* effettivo in produzione.
|
|
10
|
+
*
|
|
11
|
+
* Formatta un `<input>` come numero mascherato (valuta/decimale) mantenendo il model
|
|
12
|
+
* (`ngModel`/`formControlName`) come `number | null` — l'utente vede `'$ 1,234.56'`, il form
|
|
13
|
+
* riceve `1234.56`.
|
|
14
|
+
*
|
|
15
|
+
* In modalità NATURAL la formattazione "live" (durante la digitazione) NON forza il padding a
|
|
16
|
+
* piena precisione: farlo ad ogni tasto arrotonderebbe via le cifre appena digitate (es. digitare
|
|
17
|
+
* "1" su un campo vuoto renderizzerebbe subito "0.00", perdendo la cifra) — il padding/
|
|
18
|
+
* arrotondamento pieno avviene solo al `blur`/`writeValue`. In modalità FINANCIAL questo problema
|
|
19
|
+
* non esiste (il valore si ricalcola sempre da zero dalle sole cifre digitate, insensibile alla
|
|
20
|
+
* formattazione precedente), quindi lì si usa direttamente il formato pieno ad ogni tasto.
|
|
21
|
+
*/
|
|
22
|
+
export class TmwNumericMaskDirective {
|
|
23
|
+
set options(value) {
|
|
24
|
+
this._options = { ...TMW_NUMERIC_DEFAULT_OPTIONS, ...(value ?? {}) };
|
|
25
|
+
this._applyAlignment();
|
|
26
|
+
this._renderFinal(this._value);
|
|
27
|
+
}
|
|
28
|
+
constructor(_elementRef, _renderer) {
|
|
29
|
+
this._elementRef = _elementRef;
|
|
30
|
+
this._renderer = _renderer;
|
|
31
|
+
this._options = { ...TMW_NUMERIC_DEFAULT_OPTIONS };
|
|
32
|
+
this._value = null;
|
|
33
|
+
this._onChange = () => { };
|
|
34
|
+
this._onTouched = () => { };
|
|
35
|
+
this._disabled = false;
|
|
36
|
+
/**
|
|
37
|
+
* Stato PERSISTENTE (non ri-derivato ogni volta dalla stringa già formattata): true dal
|
|
38
|
+
* momento in cui l'utente ha digitato/incollato un carattere decimale, false quando il campo
|
|
39
|
+
* è vuoto o quel carattere viene cancellato. Necessario perché in formato euro `thousands` e
|
|
40
|
+
* l'alternativa mobile-friendly per `decimal` possono coincidere entrambi su `'.'` — v.
|
|
41
|
+
* `_tokenize` per come risolve l'ambiguità usando questo stato invece di ri-cercare "il primo
|
|
42
|
+
* punto" nella stringa (che potrebbe essere un separatore delle migliaia già inserito da noi).
|
|
43
|
+
*/
|
|
44
|
+
this._hasDecimalState = false;
|
|
45
|
+
this._applyAlignment();
|
|
46
|
+
// Senza un hint esplicito, mobile/tablet mostrano la tastiera alfanumerica completa per un
|
|
47
|
+
// <input> senza type/inputmode — sbagliato per un campo numerico. Impostato solo se il
|
|
48
|
+
// consumer non ha già messo il proprio `type`/`inputmode` nel template (es. `type="tel"`,
|
|
49
|
+
// suggerito anche dal README dell'originale `eqp-numeric` per Ionic).
|
|
50
|
+
const el = this._elementRef.nativeElement;
|
|
51
|
+
if (!el.hasAttribute('inputmode') && !el.hasAttribute('type')) {
|
|
52
|
+
this._renderer.setAttribute(el, 'inputmode', 'decimal');
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
//#region ControlValueAccessor
|
|
56
|
+
writeValue(value) {
|
|
57
|
+
this._value = this._roundToPrecision(this._clampRange(value == null ? null : Number(value)));
|
|
58
|
+
this._hasDecimalState = false;
|
|
59
|
+
this._renderFinal(this._value);
|
|
60
|
+
}
|
|
61
|
+
registerOnChange(fn) {
|
|
62
|
+
this._onChange = fn;
|
|
63
|
+
}
|
|
64
|
+
registerOnTouched(fn) {
|
|
65
|
+
this._onTouched = fn;
|
|
66
|
+
}
|
|
67
|
+
setDisabledState(isDisabled) {
|
|
68
|
+
this._disabled = isDisabled;
|
|
69
|
+
this._renderer.setProperty(this._elementRef.nativeElement, 'disabled', isDisabled);
|
|
70
|
+
}
|
|
71
|
+
//#endregion
|
|
72
|
+
onInput(event) {
|
|
73
|
+
if (this._disabled) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
const rawValue = event.target.value;
|
|
77
|
+
const caretFromEnd = this._captureCaretFromEnd();
|
|
78
|
+
if (this._options.inputMode === TmwNumericInputMode.FINANCIAL) {
|
|
79
|
+
this._value = this._clampRange(this._parseFinancial(rawValue));
|
|
80
|
+
this._onChange(this._value);
|
|
81
|
+
this._renderFinal(this._value);
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
const { decimal } = this._options;
|
|
85
|
+
const insertedText = event.data;
|
|
86
|
+
// Il carattere/testo appena digitato o incollato (`event.data`) dice INEQUIVOCABILMENTE se
|
|
87
|
+
// l'utente sta esprimendo l'intento "questo è il separatore decimale" — a differenza di
|
|
88
|
+
// ri-cercare "il primo punto" nell'intera stringa già formattata, che in formato euro
|
|
89
|
+
// (`thousands: '.'`) confonderebbe un punto delle migliaia già inserito da noi con il
|
|
90
|
+
// punto decimale appena digitato (v. commento su `_hasDecimalState`).
|
|
91
|
+
if (insertedText && (insertedText.includes(decimal) || insertedText.includes('.'))) {
|
|
92
|
+
this._hasDecimalState = true;
|
|
93
|
+
}
|
|
94
|
+
if (rawValue.length === 0) {
|
|
95
|
+
this._hasDecimalState = false;
|
|
96
|
+
}
|
|
97
|
+
const { integerDigits, decimalDigits, hasDecimalSeparator, isNegative } = this._tokenize(rawValue, this._hasDecimalState);
|
|
98
|
+
this._hasDecimalState = hasDecimalSeparator;
|
|
99
|
+
this._value = this._clampRange(this._toNumber(integerDigits, decimalDigits, isNegative));
|
|
100
|
+
this._onChange(this._value);
|
|
101
|
+
this._renderLive(integerDigits, decimalDigits, hasDecimalSeparator, isNegative);
|
|
102
|
+
}
|
|
103
|
+
this._restoreCaretFromEnd(caretFromEnd);
|
|
104
|
+
}
|
|
105
|
+
onBlur() {
|
|
106
|
+
this._onTouched();
|
|
107
|
+
this._value = this._roundToPrecision(this._value);
|
|
108
|
+
this._onChange(this._value);
|
|
109
|
+
this._renderFinal(this._value);
|
|
110
|
+
}
|
|
111
|
+
_applyAlignment() {
|
|
112
|
+
this._renderer.setStyle(this._elementRef.nativeElement, 'text-align', this._options.align);
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Modalità FINANCIAL: TUTTE le cifre della stringa (incluse quelle già formattate dal render
|
|
116
|
+
* precedente — prefisso/migliaia/decimali) vengono lette come un unico intero in centesimi
|
|
117
|
+
* (o nella più piccola unità di `precision`) e ridivise per `10^precision` — è quello che dà
|
|
118
|
+
* l'effetto "shift da destra" tipico delle casse, insensibile a qualunque formattazione
|
|
119
|
+
* precedente (a differenza di NATURAL non serve un formato "live" separato).
|
|
120
|
+
*/
|
|
121
|
+
_parseFinancial(rawValue) {
|
|
122
|
+
const { precision, allowNegative, nullable } = this._options;
|
|
123
|
+
const isNegative = allowNegative && this._hasTypedMinus(rawValue);
|
|
124
|
+
const digitsOnly = rawValue.replace(/[^0-9]/g, '');
|
|
125
|
+
if (digitsOnly.length === 0) {
|
|
126
|
+
return nullable ? null : 0;
|
|
127
|
+
}
|
|
128
|
+
const units = parseInt(digitsOnly, 10);
|
|
129
|
+
const value = units / Math.pow(10, precision);
|
|
130
|
+
return isNegative ? -value : value;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* `rawValue.startsWith('-')` non basta: il segno digitato dall'utente finisce SEMPRE dopo un
|
|
134
|
+
* eventuale prefisso (es. `"$ -5"`), mai a inizio stringa assoluto — si cerca quindi il
|
|
135
|
+
* carattere ovunque nella stringa.
|
|
136
|
+
*/
|
|
137
|
+
_hasTypedMinus(rawValue) {
|
|
138
|
+
return rawValue.includes('-');
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Estrae dalla stringa grezza le sole cifre intere/decimali digitate. Usato SOLO in modalità
|
|
142
|
+
* NATURAL. `hasDecimalHint` (stato persistente, v. `_hasDecimalState`) dice se un separatore
|
|
143
|
+
* decimale è già stato digitato in un keystroke precedente:
|
|
144
|
+
*
|
|
145
|
+
* - `false`: nessun separatore ancora — si scartano TUTTI i caratteri non-cifra (incluso un
|
|
146
|
+
* eventuale punto delle migliaia già presente dal render precedente), tutto ciò che resta è
|
|
147
|
+
* parte intera.
|
|
148
|
+
* - `true`: si cerca l'ULTIMA occorrenza di `decimal` o `'.'` nella stringa — mai la prima. Le
|
|
149
|
+
* migliaia (anche quando coincidono con `'.'`, formato euro) possono comparire SOLO PRIMA del
|
|
150
|
+
* separatore decimale reale (la formattazione non raggruppa mai le cifre decimali), quindi
|
|
151
|
+
* l'ultima occorrenza è sempre quella vera, senza ambiguità. Se non se ne trova più nessuna
|
|
152
|
+
* (l'utente ha cancellato il separatore), si ritorna a "nessun decimale".
|
|
153
|
+
*/
|
|
154
|
+
_tokenize(rawValue, hasDecimalHint) {
|
|
155
|
+
const { decimal, allowNegative, precision } = this._options;
|
|
156
|
+
const isNegative = allowNegative && this._hasTypedMinus(rawValue);
|
|
157
|
+
if (!hasDecimalHint) {
|
|
158
|
+
return { integerDigits: rawValue.replace(/[^0-9]/g, ''), decimalDigits: '', hasDecimalSeparator: false, isNegative };
|
|
159
|
+
}
|
|
160
|
+
let splitIndex = -1;
|
|
161
|
+
for (let i = rawValue.length - 1; i >= 0; i--) {
|
|
162
|
+
if (rawValue[i] === decimal || rawValue[i] === '.') {
|
|
163
|
+
splitIndex = i;
|
|
164
|
+
break;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
if (splitIndex === -1) {
|
|
168
|
+
return { integerDigits: rawValue.replace(/[^0-9]/g, ''), decimalDigits: '', hasDecimalSeparator: false, isNegative };
|
|
169
|
+
}
|
|
170
|
+
const integerDigits = rawValue.slice(0, splitIndex).replace(/[^0-9]/g, '');
|
|
171
|
+
const decimalDigits = rawValue.slice(splitIndex + 1).replace(/[^0-9]/g, '').slice(0, precision);
|
|
172
|
+
return { integerDigits, decimalDigits, hasDecimalSeparator: true, isNegative };
|
|
173
|
+
}
|
|
174
|
+
_toNumber(integerDigits, decimalDigits, isNegative) {
|
|
175
|
+
if (integerDigits.length === 0 && decimalDigits.length === 0) {
|
|
176
|
+
return this._options.nullable ? null : 0;
|
|
177
|
+
}
|
|
178
|
+
const value = parseFloat(`${integerDigits || '0'}.${decimalDigits || '0'}`);
|
|
179
|
+
return isNegative ? -value : value;
|
|
180
|
+
}
|
|
181
|
+
/** Applica solo `allowNegative`/`min`/`max` — NON arrotonda a `precision` (v. commento di classe). */
|
|
182
|
+
_clampRange(value) {
|
|
183
|
+
if (value == null) {
|
|
184
|
+
return value;
|
|
185
|
+
}
|
|
186
|
+
const { min, max, allowNegative } = this._options;
|
|
187
|
+
let result = value;
|
|
188
|
+
if (!allowNegative && result < 0) {
|
|
189
|
+
result = -result;
|
|
190
|
+
}
|
|
191
|
+
if (min != null && result < min) {
|
|
192
|
+
result = min;
|
|
193
|
+
}
|
|
194
|
+
if (max != null && result > max) {
|
|
195
|
+
result = max;
|
|
196
|
+
}
|
|
197
|
+
return result;
|
|
198
|
+
}
|
|
199
|
+
_roundToPrecision(value) {
|
|
200
|
+
if (value == null) {
|
|
201
|
+
return value;
|
|
202
|
+
}
|
|
203
|
+
const factor = Math.pow(10, this._options.precision);
|
|
204
|
+
return Math.round(value * factor) / factor;
|
|
205
|
+
}
|
|
206
|
+
/** Formato "live", usato in NATURAL durante la digitazione: nessun padding/arrotondamento. */
|
|
207
|
+
_renderLive(integerDigits, decimalDigits, hasDecimalSeparator, isNegative) {
|
|
208
|
+
const { prefix, suffix, thousands, decimal, precision } = this._options;
|
|
209
|
+
const groupedInteger = integerDigits.replace(/\B(?=(\d{3})+(?!\d))/g, thousands);
|
|
210
|
+
const decimalSegment = precision > 0 && hasDecimalSeparator ? decimal + decimalDigits : '';
|
|
211
|
+
const formatted = `${isNegative ? '-' : ''}${prefix}${groupedInteger}${decimalSegment}${suffix}`;
|
|
212
|
+
this._renderer.setProperty(this._elementRef.nativeElement, 'value', formatted);
|
|
213
|
+
}
|
|
214
|
+
/** Formato pieno (padding a `precision`, arrotondato) — usato a `blur`/`writeValue`/opzioni cambiate. */
|
|
215
|
+
_renderFinal(value) {
|
|
216
|
+
const formatted = value == null ? '' : this._formatFull(value);
|
|
217
|
+
this._renderer.setProperty(this._elementRef.nativeElement, 'value', formatted);
|
|
218
|
+
}
|
|
219
|
+
_formatFull(value) {
|
|
220
|
+
const { prefix, suffix, thousands, decimal, precision } = this._options;
|
|
221
|
+
const isNegative = value < 0;
|
|
222
|
+
const fixed = Math.abs(value).toFixed(precision);
|
|
223
|
+
const [integerPart, decimalPart] = fixed.split('.');
|
|
224
|
+
const groupedInteger = integerPart.replace(/\B(?=(\d{3})+(?!\d))/g, thousands);
|
|
225
|
+
const decimalSegment = precision > 0 ? decimal + decimalPart : '';
|
|
226
|
+
return `${isNegative ? '-' : ''}${prefix}${groupedInteger}${decimalSegment}${suffix}`;
|
|
227
|
+
}
|
|
228
|
+
_captureCaretFromEnd() {
|
|
229
|
+
const el = this._elementRef.nativeElement;
|
|
230
|
+
const caret = el.selectionStart ?? el.value.length;
|
|
231
|
+
return el.value.length - caret;
|
|
232
|
+
}
|
|
233
|
+
_restoreCaretFromEnd(distanceFromEnd) {
|
|
234
|
+
const el = this._elementRef.nativeElement;
|
|
235
|
+
const position = Math.max(0, el.value.length - distanceFromEnd);
|
|
236
|
+
// Il reformat avviene sincronamente nello stesso ciclo dell'evento `input`: il browser
|
|
237
|
+
// applica la posizione del cursore SUBITO dopo, senza bisogno di un setTimeout/microtask.
|
|
238
|
+
el.setSelectionRange(position, position);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
TmwNumericMaskDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: TmwNumericMaskDirective, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Directive });
|
|
242
|
+
TmwNumericMaskDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.9", type: TmwNumericMaskDirective, isStandalone: true, selector: "[tmwNumericMask]", inputs: { options: "options" }, host: { listeners: { "input": "onInput($event)", "blur": "onBlur()" } }, providers: [
|
|
243
|
+
{
|
|
244
|
+
provide: NG_VALUE_ACCESSOR,
|
|
245
|
+
useExisting: forwardRef(() => TmwNumericMaskDirective),
|
|
246
|
+
multi: true,
|
|
247
|
+
},
|
|
248
|
+
], ngImport: i0 });
|
|
249
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: TmwNumericMaskDirective, decorators: [{
|
|
250
|
+
type: Directive,
|
|
251
|
+
args: [{
|
|
252
|
+
selector: '[tmwNumericMask]',
|
|
253
|
+
standalone: true,
|
|
254
|
+
providers: [
|
|
255
|
+
{
|
|
256
|
+
provide: NG_VALUE_ACCESSOR,
|
|
257
|
+
useExisting: forwardRef(() => TmwNumericMaskDirective),
|
|
258
|
+
multi: true,
|
|
259
|
+
},
|
|
260
|
+
],
|
|
261
|
+
}]
|
|
262
|
+
}], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i0.Renderer2 }]; }, propDecorators: { options: [{
|
|
263
|
+
type: Input,
|
|
264
|
+
args: ['options']
|
|
265
|
+
}], onInput: [{
|
|
266
|
+
type: HostListener,
|
|
267
|
+
args: ['input', ['$event']]
|
|
268
|
+
}], onBlur: [{
|
|
269
|
+
type: HostListener,
|
|
270
|
+
args: ['blur']
|
|
271
|
+
}] } });
|
|
272
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidG13LW51bWVyaWMtbWFzay5kaXJlY3RpdmUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9wcm9qZWN0cy90bXctbnVtZXJpYy9zcmMvbGliL3Rtdy1udW1lcmljLW1hc2suZGlyZWN0aXZlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxTQUFTLEVBQWMsWUFBWSxFQUFFLEtBQUssRUFBYSxVQUFVLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDbEcsT0FBTyxFQUFFLGlCQUFpQixFQUF3QixNQUFNLGdCQUFnQixDQUFDO0FBQ3pFLE9BQU8sRUFBRSwyQkFBMkIsRUFBRSxtQkFBbUIsRUFBcUIsTUFBTSxvQ0FBb0MsQ0FBQzs7QUFFekg7Ozs7Ozs7Ozs7Ozs7Ozs7R0FnQkc7QUFZSCxNQUFNLE9BQU8sdUJBQXVCO0lBR2xDLElBQ0ksT0FBTyxDQUFDLEtBQW9DO1FBQzlDLElBQUksQ0FBQyxRQUFRLEdBQUcsRUFBRSxHQUFHLDJCQUEyQixFQUFFLEdBQUcsQ0FBQyxLQUFLLElBQUksRUFBRSxDQUFDLEVBQUUsQ0FBQztRQUNyRSxJQUFJLENBQUMsZUFBZSxFQUFFLENBQUM7UUFDdkIsSUFBSSxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUM7SUFDakMsQ0FBQztJQWdCRCxZQUFvQixXQUF5QyxFQUFVLFNBQW9CO1FBQXZFLGdCQUFXLEdBQVgsV0FBVyxDQUE4QjtRQUFVLGNBQVMsR0FBVCxTQUFTLENBQVc7UUF2Qm5GLGFBQVEsR0FBZ0MsRUFBRSxHQUFHLDJCQUEyQixFQUFFLENBQUM7UUFTM0UsV0FBTSxHQUFrQixJQUFJLENBQUM7UUFDN0IsY0FBUyxHQUFtQyxHQUFHLEVBQUUsR0FBRSxDQUFDLENBQUM7UUFDckQsZUFBVSxHQUFlLEdBQUcsRUFBRSxHQUFFLENBQUMsQ0FBQztRQUNsQyxjQUFTLEdBQUcsS0FBSyxDQUFDO1FBQzFCOzs7Ozs7O1dBT0c7UUFDSyxxQkFBZ0Is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OztvSEF4UFUsdUJBQXVCO3dHQUF2Qix1QkFBdUIsd0tBUnZCO1FBQ1Q7WUFDRSxPQUFPLEVBQUUsaUJBQWlCO1lBQzFCLFdBQVcsRUFBRSxVQUFVLENBQUMsR0FBRyxFQUFFLENBQUMsdUJBQXVCLENBQUM7WUFDdEQsS0FBSyxFQUFFLElBQUk7U0FDWjtLQUNGOzJGQUVVLHVCQUF1QjtrQkFYbkMsU0FBUzttQkFBQztvQkFDVCxRQUFRLEVBQUUsa0JBQWtCO29CQUM1QixVQUFVLEVBQUUsSUFBSTtvQkFDaEIsU0FBUyxFQUFFO3dCQUNUOzRCQUNFLE9BQU8sRUFBRSxpQkFBaUI7NEJBQzFCLFdBQVcsRUFBRSxVQUFVLENBQUMsR0FBRyxFQUFFLHdCQUF3QixDQUFDOzRCQUN0RCxLQUFLLEVBQUUsSUFBSTt5QkFDWjtxQkFDRjtpQkFDRjt5SEFLSyxPQUFPO3NCQURWLEtBQUs7dUJBQUMsU0FBUztnQkF5RGhCLE9BQU87c0JBRE4sWUFBWTt1QkFBQyxPQUFPLEVBQUUsQ0FBQyxRQUFRLENBQUM7Z0JBb0NqQyxNQUFNO3NCQURMLFlBQVk7dUJBQUMsTUFBTSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IERpcmVjdGl2ZSwgRWxlbWVudFJlZiwgSG9zdExpc3RlbmVyLCBJbnB1dCwgUmVuZGVyZXIyLCBmb3J3YXJkUmVmIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBOR19WQUxVRV9BQ0NFU1NPUiwgQ29udHJvbFZhbHVlQWNjZXNzb3IgfSBmcm9tICdAYW5ndWxhci9mb3Jtcyc7XG5pbXBvcnQgeyBUTVdfTlVNRVJJQ19ERUZBVUxUX09QVElPTlMsIFRtd051bWVyaWNJbnB1dE1vZGUsIFRtd051bWVyaWNPcHRpb25zIH0gZnJvbSAnLi9tb2RlbHMvdG13LW51bWVyaWMtb3B0aW9ucy5tb2RlbCc7XG5cbi8qKlxuICogU29zdGl0dXRvIGRpIGBbZXFwTnVtZXJpY01hc2tdYCAoYEBlcXByb2plY3QvZXFwLW51bWVyaWNgKSDigJQgc3Rlc3NvIGBbb3B0aW9uc11gLCBzdGVzc2kgbm9taVxuICogZGkgb3B6aW9uZSwgc3Rlc3NpIGRlZmF1bHQgKHYuIGBUTVdfTlVNRVJJQ19ERUZBVUxUX09QVElPTlNgKS4gTmVzc3VuIGBmb3JSb290KClgOiBuZXNzdW5cbiAqIGNvbnN1bWVyIHJlYWxlIGluIFRNRUQgbG8gdXNhdmEsIGkgZGVmYXVsdCBkZWwgcGFjY2hldHRvIG9yaWdpbmFsZSBlcmFubyBnacOgIGlsIGNvbXBvcnRhbWVudG9cbiAqIGVmZmV0dGl2byBpbiBwcm9kdXppb25lLlxuICpcbiAqIEZvcm1hdHRhIHVuIGA8aW5wdXQ+YCBjb21lIG51bWVybyBtYXNjaGVyYXRvICh2YWx1dGEvZGVjaW1hbGUpIG1hbnRlbmVuZG8gaWwgbW9kZWxcbiAqIChgbmdNb2RlbGAvYGZvcm1Db250cm9sTmFtZWApIGNvbWUgYG51bWJlciB8IG51bGxgIOKAlCBsJ3V0ZW50ZSB2ZWRlIGAnJCAxLDIzNC41NidgLCBpbCBmb3JtXG4gKiByaWNldmUgYDEyMzQuNTZgLlxuICpcbiAqIEluIG1vZGFsaXTDoCBOQVRVUkFMIGxhIGZvcm1hdHRhemlvbmUgXCJsaXZlXCIgKGR1cmFudGUgbGEgZGlnaXRhemlvbmUpIE5PTiBmb3J6YSBpbCBwYWRkaW5nIGFcbiAqIHBpZW5hIHByZWNpc2lvbmU6IGZhcmxvIGFkIG9nbmkgdGFzdG8gYXJyb3RvbmRlcmViYmUgdmlhIGxlIGNpZnJlIGFwcGVuYSBkaWdpdGF0ZSAoZXMuIGRpZ2l0YXJlXG4gKiBcIjFcIiBzdSB1biBjYW1wbyB2dW90byByZW5kZXJpenplcmViYmUgc3ViaXRvIFwiMC4wMFwiLCBwZXJkZW5kbyBsYSBjaWZyYSkg4oCUIGlsIHBhZGRpbmcvXG4gKiBhcnJvdG9uZGFtZW50byBwaWVubyBhdnZpZW5lIHNvbG8gYWwgYGJsdXJgL2B3cml0ZVZhbHVlYC4gSW4gbW9kYWxpdMOgIEZJTkFOQ0lBTCBxdWVzdG8gcHJvYmxlbWFcbiAqIG5vbiBlc2lzdGUgKGlsIHZhbG9yZSBzaSByaWNhbGNvbGEgc2VtcHJlIGRhIHplcm8gZGFsbGUgc29sZSBjaWZyZSBkaWdpdGF0ZSwgaW5zZW5zaWJpbGUgYWxsYVxuICogZm9ybWF0dGF6aW9uZSBwcmVjZWRlbnRlKSwgcXVpbmRpIGzDrCBzaSB1c2EgZGlyZXR0YW1lbnRlIGlsIGZvcm1hdG8gcGllbm8gYWQgb2duaSB0YXN0by5cbiAqL1xuQERpcmVjdGl2ZSh7XG4gIHNlbGVjdG9yOiAnW3Rtd051bWVyaWNNYXNrXScsXG4gIHN0YW5kYWxvbmU6IHRydWUsXG4gIHByb3ZpZGVyczogW1xuICAgIHtcbiAgICAgIHByb3ZpZGU6IE5HX1ZBTFVFX0FDQ0VTU09SLFxuICAgICAgdXNlRXhpc3Rpbmc6IGZvcndhcmRSZWYoKCkgPT4gVG13TnVtZXJpY01hc2tEaXJlY3RpdmUpLFxuICAgICAgbXVsdGk6IHRydWUsXG4gICAgfSxcbiAgXSxcbn0pXG5leHBvcnQgY2xhc3MgVG13TnVtZXJpY01hc2tEaXJlY3RpdmUgaW1wbGVtZW50cyBDb250cm9sVmFsdWVBY2Nlc3NvciB7XG4gIHByaXZhdGUgX29wdGlvbnM6IFJlcXVpcmVkPFRtd051bWVyaWNPcHRpb25zPiA9IHsgLi4uVE1XX05VTUVSSUNfREVGQVVMVF9PUFRJT05TIH07XG5cbiAgQElucHV0KCdvcHRpb25zJylcbiAgc2V0IG9wdGlvbnModmFsdWU6IFRtd051bWVyaWNPcHRpb25zIHwgdW5kZWZpbmVkKSB7XG4gICAgdGhpcy5fb3B0aW9ucyA9IHsgLi4uVE1XX05VTUVSSUNfREVGQVVMVF9PUFRJT05TLCAuLi4odmFsdWUgPz8ge30pIH07XG4gICAgdGhpcy5fYXBwbHlBbGlnbm1lbnQoKTtcbiAgICB0aGlzLl9yZW5kZXJGaW5hbCh0aGlzLl92YWx1ZSk7XG4gIH1cblxuICBwcml2YXRlIF92YWx1ZTogbnVtYmVyIHwgbnVsbCA9IG51bGw7XG4gIHByaXZhdGUgX29uQ2hhbmdlOiAodmFsdWU6IG51bWJlciB8IG51bGwpID0+IHZvaWQgPSAoKSA9PiB7fTtcbiAgcHJpdmF0ZSBfb25Ub3VjaGVkOiAoKSA9PiB2b2lkID0gKCkgPT4ge307XG4gIHByaXZhdGUgX2Rpc2FibGVkID0gZmFsc2U7XG4gIC8qKlxuICAgKiBTdGF0byBQRVJTSVNURU5URSAobm9uIHJpLWRlcml2YXRvIG9nbmkgdm9sdGEgZGFsbGEgc3RyaW5nYSBnacOgIGZvcm1hdHRhdGEpOiB0cnVlIGRhbFxuICAgKiBtb21lbnRvIGluIGN1aSBsJ3V0ZW50ZSBoYSBkaWdpdGF0by9pbmNvbGxhdG8gdW4gY2FyYXR0ZXJlIGRlY2ltYWxlLCBmYWxzZSBxdWFuZG8gaWwgY2FtcG9cbiAgICogw6ggdnVvdG8gbyBxdWVsIGNhcmF0dGVyZSB2aWVuZSBjYW5jZWxsYXRvLiBOZWNlc3NhcmlvIHBlcmNow6kgaW4gZm9ybWF0byBldXJvIGB0aG91c2FuZHNgIGVcbiAgICogbCdhbHRlcm5hdGl2YSBtb2JpbGUtZnJpZW5kbHkgcGVyIGBkZWNpbWFsYCBwb3Nzb25vIGNvaW5jaWRlcmUgZW50cmFtYmkgc3UgYCcuJ2Ag4oCUIHYuXG4gICAqIGBfdG9rZW5pemVgIHBlciBjb21lIHJpc29sdmUgbCdhbWJpZ3VpdMOgIHVzYW5kbyBxdWVzdG8gc3RhdG8gaW52ZWNlIGRpIHJpLWNlcmNhcmUgXCJpbCBwcmltb1xuICAgKiBwdW50b1wiIG5lbGxhIHN0cmluZ2EgKGNoZSBwb3RyZWJiZSBlc3NlcmUgdW4gc2VwYXJhdG9yZSBkZWxsZSBtaWdsaWFpYSBnacOgIGluc2VyaXRvIGRhIG5vaSkuXG4gICAqL1xuICBwcml2YXRlIF9oYXNEZWNpbWFsU3RhdGUgPSBmYWxzZTtcblxuICBjb25zdHJ1Y3Rvcihwcml2YXRlIF9lbGVtZW50UmVmOiBFbGVtZW50UmVmPEhUTUxJbnB1dEVsZW1lbnQ+LCBwcml2YXRlIF9yZW5kZXJlcjogUmVuZGVyZXIyKSB7XG4gICAgdGhpcy5fYXBwbHlBbGlnbm1lbnQoKTtcbiAgICAvLyBTZW56YSB1biBoaW50IGVzcGxpY2l0bywgbW9iaWxlL3RhYmxldCBtb3N0cmFubyBsYSB0YXN0aWVyYSBhbGZhbnVtZXJpY2EgY29tcGxldGEgcGVyIHVuXG4gICAgLy8gPGlucHV0PiBzZW56YSB0eXBlL2lucHV0bW9kZSDigJQgc2JhZ2xpYXRvIHBlciB1biBjYW1wbyBudW1lcmljby4gSW1wb3N0YXRvIHNvbG8gc2UgaWxcbiAgICAvLyBjb25zdW1lciBub24gaGEgZ2nDoCBtZXNzbyBpbCBwcm9wcmlvIGB0eXBlYC9gaW5wdXRtb2RlYCBuZWwgdGVtcGxhdGUgKGVzLiBgdHlwZT1cInRlbFwiYCxcbiAgICAvLyBzdWdnZXJpdG8gYW5jaGUgZGFsIFJFQURNRSBkZWxsJ29yaWdpbmFsZSBgZXFwLW51bWVyaWNgIHBlciBJb25pYykuXG4gICAgY29uc3QgZWwgPSB0aGlzLl9lbGVtZW50UmVmLm5hdGl2ZUVsZW1lbnQ7XG4gICAgaWYgKCFlbC5oYXNBdHRyaWJ1dGUoJ2lucHV0bW9kZScpICYmICFlbC5oYXNBdHRyaWJ1dGUoJ3R5cGUnKSkge1xuICAgICAgdGhpcy5fcmVuZGVyZXIuc2V0QXR0cmlidXRlKGVsLCAnaW5wdXRtb2RlJywgJ2RlY2ltYWwnKTtcbiAgICB9XG4gIH1cblxuICAvLyNyZWdpb24gQ29udHJvbFZhbHVlQWNjZXNzb3JcblxuICB3cml0ZVZhbHVlKHZhbHVlOiBudW1iZXIgfCBudWxsKTogdm9pZCB7XG4gICAgdGhpcy5fdmFsdWUgPSB0aGlzLl9yb3VuZFRvUHJlY2lzaW9uKHRoaXMuX2NsYW1wUmFuZ2UodmFsdWUgPT0gbnVsbCA/IG51bGwgOiBOdW1iZXIodmFsdWUpKSk7XG4gICAgdGhpcy5faGFzRGVjaW1hbFN0YXRlID0gZmFsc2U7XG4gICAgdGhpcy5fcmVuZGVyRmluYWwodGhpcy5fdmFsdWUpO1xuICB9XG5cbiAgcmVnaXN0ZXJPbkNoYW5nZShmbjogKHZhbHVlOiBudW1iZXIgfCBudWxsKSA9PiB2b2lkKTogdm9pZCB7XG4gICAgdGhpcy5fb25DaGFuZ2UgPSBmbjtcbiAgfVxuXG4gIHJlZ2lzdGVyT25Ub3VjaGVkKGZuOiAoKSA9PiB2b2lkKTogdm9pZCB7XG4gICAgdGhpcy5fb25Ub3VjaGVkID0gZm47XG4gIH1cblxuICBzZXREaXNhYmxlZFN0YXRlKGlzRGlzYWJsZWQ6IGJvb2xlYW4pOiB2b2lkIHtcbiAgICB0aGlzLl9kaXNhYmxlZCA9IGlzRGlzYWJsZWQ7XG4gICAgdGhpcy5fcmVuZGVyZXIuc2V0UHJvcGVydHkodGhpcy5fZWxlbWVudFJlZi5uYXRpdmVFbGVtZW50LCAnZGlzYWJsZWQnLCBpc0Rpc2FibGVkKTtcbiAgfVxuXG4gIC8vI2VuZHJlZ2lvblxuXG4gIEBIb3N0TGlzdGVuZXIoJ2lucHV0JywgWyckZXZlbnQnXSlcbiAgb25JbnB1dChldmVudDogSW5wdXRFdmVudCk6IHZvaWQge1xuICAgIGlmICh0aGlzLl9kaXNhYmxlZCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBjb25zdCByYXdWYWx1ZSA9IChldmVudC50YXJnZXQgYXMgSFRNTElucHV0RWxlbWVudCkudmFsdWU7XG4gICAgY29uc3QgY2FyZXRGcm9tRW5kID0gdGhpcy5fY2FwdHVyZUNhcmV0RnJvbUVuZCgpO1xuXG4gICAgaWYgKHRoaXMuX29wdGlvbnMuaW5wdXRNb2RlID09PSBUbXdOdW1lcmljSW5wdXRNb2RlLkZJTkFOQ0lBTCkge1xuICAgICAgdGhpcy5fdmFsdWUgPSB0aGlzLl9jbGFtcFJhbmdlKHRoaXMuX3BhcnNlRmluYW5jaWFsKHJhd1ZhbHVlKSk7XG4gICAgICB0aGlzLl9vbkNoYW5nZSh0aGlzLl92YWx1ZSk7XG4gICAgICB0aGlzLl9yZW5kZXJGaW5hbCh0aGlzLl92YWx1ZSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGNvbnN0IHsgZGVjaW1hbCB9ID0gdGhpcy5fb3B0aW9ucztcbiAgICAgIGNvbnN0IGluc2VydGVkVGV4dCA9IGV2ZW50LmRhdGE7XG4gICAgICAvLyBJbCBjYXJhdHRlcmUvdGVzdG8gYXBwZW5hIGRpZ2l0YXRvIG8gaW5jb2xsYXRvIChgZXZlbnQuZGF0YWApIGRpY2UgSU5FUVVJVk9DQUJJTE1FTlRFIHNlXG4gICAgICAvLyBsJ3V0ZW50ZSBzdGEgZXNwcmltZW5kbyBsJ2ludGVudG8gXCJxdWVzdG8gw6ggaWwgc2VwYXJhdG9yZSBkZWNpbWFsZVwiIOKAlCBhIGRpZmZlcmVuemEgZGlcbiAgICAgIC8vIHJpLWNlcmNhcmUgXCJpbCBwcmltbyBwdW50b1wiIG5lbGwnaW50ZXJhIHN0cmluZ2EgZ2nDoCBmb3JtYXR0YXRhLCBjaGUgaW4gZm9ybWF0byBldXJvXG4gICAgICAvLyAoYHRob3VzYW5kczogJy4nYCkgY29uZm9uZGVyZWJiZSB1biBwdW50byBkZWxsZSBtaWdsaWFpYSBnacOgIGluc2VyaXRvIGRhIG5vaSBjb24gaWxcbiAgICAgIC8vIHB1bnRvIGRlY2ltYWxlIGFwcGVuYSBkaWdpdGF0byAodi4gY29tbWVudG8gc3UgYF9oYXNEZWNpbWFsU3RhdGVgKS5cbiAgICAgIGlmIChpbnNlcnRlZFRleHQgJiYgKGluc2VydGVkVGV4dC5pbmNsdWRlcyhkZWNpbWFsKSB8fCBpbnNlcnRlZFRleHQuaW5jbHVkZXMoJy4nKSkpIHtcbiAgICAgICAgdGhpcy5faGFzRGVjaW1hbFN0YXRlID0gdHJ1ZTtcbiAgICAgIH1cbiAgICAgIGlmIChyYXdWYWx1ZS5sZW5ndGggPT09IDApIHtcbiAgICAgICAgdGhpcy5faGFzRGVjaW1hbFN0YXRlID0gZmFsc2U7XG4gICAgICB9XG4gICAgICBjb25zdCB7IGludGVnZXJEaWdpdHMsIGRlY2ltYWxEaWdpdHMsIGhhc0RlY2ltYWxTZXBhcmF0b3IsIGlzTmVnYXRpdmUgfSA9IHRoaXMuX3Rva2VuaXplKHJhd1ZhbHVlLCB0aGlzLl9oYXNEZWNpbWFsU3RhdGUpO1xuICAgICAgdGhpcy5faGFzRGVjaW1hbFN0YXRlID0gaGFzRGVjaW1hbFNlcGFyYXRvcjtcbiAgICAgIHRoaXMuX3ZhbHVlID0gdGhpcy5fY2xhbXBSYW5nZSh0aGlzLl90b051bWJlcihpbnRlZ2VyRGlnaXRzLCBkZWNpbWFsRGlnaXRzLCBpc05lZ2F0aXZlKSk7XG4gICAgICB0aGlzLl9vbkNoYW5nZSh0aGlzLl92YWx1ZSk7XG4gICAgICB0aGlzLl9yZW5kZXJMaXZlKGludGVnZXJEaWdpdHMsIGRlY2ltYWxEaWdpdHMsIGhhc0RlY2ltYWxTZXBhcmF0b3IsIGlzTmVnYXRpdmUpO1xuICAgIH1cbiAgICB0aGlzLl9yZXN0b3JlQ2FyZXRGcm9tRW5kKGNhcmV0RnJvbUVuZCk7XG4gIH1cblxuICBASG9zdExpc3RlbmVyKCdibHVyJylcbiAgb25CbHVyKCk6IHZvaWQge1xuICAgIHRoaXMuX29uVG91Y2hlZCgpO1xuICAgIHRoaXMuX3ZhbHVlID0gdGhpcy5fcm91bmRUb1ByZWNpc2lvbih0aGlzLl92YWx1ZSk7XG4gICAgdGhpcy5fb25DaGFuZ2UodGhpcy5fdmFsdWUpO1xuICAgIHRoaXMuX3JlbmRlckZpbmFsKHRoaXMuX3ZhbHVlKTtcbiAgfVxuXG4gIHByaXZhdGUgX2FwcGx5QWxpZ25tZW50KCk6IHZvaWQge1xuICAgIHRoaXMuX3JlbmRlcmVyLnNldFN0eWxlKHRoaXMuX2VsZW1lbnRSZWYubmF0aXZlRWxlbWVudCwgJ3RleHQtYWxpZ24nLCB0aGlzLl9vcHRpb25zLmFsaWduKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBNb2RhbGl0w6AgRklOQU5DSUFMOiBUVVRURSBsZSBjaWZyZSBkZWxsYSBzdHJpbmdhIChpbmNsdXNlIHF1ZWxsZSBnacOgIGZvcm1hdHRhdGUgZGFsIHJlbmRlclxuICAgKiBwcmVjZWRlbnRlIOKAlCBwcmVmaXNzby9taWdsaWFpYS9kZWNpbWFsaSkgdmVuZ29ubyBsZXR0ZSBjb21lIHVuIHVuaWNvIGludGVybyBpbiBjZW50ZXNpbWlcbiAgICogKG8gbmVsbGEgcGnDuSBwaWNjb2xhIHVuaXTDoCBkaSBgcHJlY2lzaW9uYCkgZSByaWRpdmlzZSBwZXIgYDEwXnByZWNpc2lvbmAg4oCUIMOoIHF1ZWxsbyBjaGUgZMOgXG4gICAqIGwnZWZmZXR0byBcInNoaWZ0IGRhIGRlc3RyYVwiIHRpcGljbyBkZWxsZSBjYXNzZSwgaW5zZW5zaWJpbGUgYSBxdWFsdW5xdWUgZm9ybWF0dGF6aW9uZVxuICAgKiBwcmVjZWRlbnRlIChhIGRpZmZlcmVuemEgZGkgTkFUVVJBTCBub24gc2VydmUgdW4gZm9ybWF0byBcImxpdmVcIiBzZXBhcmF0bykuXG4gICAqL1xuICBwcml2YXRlIF9wYXJzZUZpbmFuY2lhbChyYXdWYWx1ZTogc3RyaW5nKTogbnVtYmVyIHwgbnVsbCB7XG4gICAgY29uc3QgeyBwcmVjaXNpb24sIGFsbG93TmVnYXRpdmUsIG51bGxhYmxlIH0gPSB0aGlzLl9vcHRpb25zO1xuICAgIGNvbnN0IGlzTmVnYXRpdmUgPSBhbGxvd05lZ2F0aXZlICYmIHRoaXMuX2hhc1R5cGVkTWludXMocmF3VmFsdWUpO1xuICAgIGNvbnN0IGRpZ2l0c09ubHkgPSByYXdWYWx1ZS5yZXBsYWNlKC9bXjAtOV0vZywgJycpO1xuICAgIGlmIChkaWdpdHNPbmx5Lmxlbmd0aCA9PT0gMCkge1xuICAgICAgcmV0dXJuIG51bGxhYmxlID8gbnVsbCA6IDA7XG4gICAgfVxuICAgIGNvbnN0IHVuaXRzID0gcGFyc2VJbnQoZGlnaXRzT25seSwgMTApO1xuICAgIGNvbnN0IHZhbHVlID0gdW5pdHMgLyBNYXRoLnBvdygxMCwgcHJlY2lzaW9uKTtcbiAgICByZXR1cm4gaXNOZWdhdGl2ZSA/IC12YWx1ZSA6IHZhbHVlO1xuICB9XG5cbiAgLyoqXG4gICAqIGByYXdWYWx1ZS5zdGFydHNXaXRoKCctJylgIG5vbiBiYXN0YTogaWwgc2Vnbm8gZGlnaXRhdG8gZGFsbCd1dGVudGUgZmluaXNjZSBTRU1QUkUgZG9wbyB1blxuICAgKiBldmVudHVhbGUgcHJlZmlzc28gKGVzLiBgXCIkIC01XCJgKSwgbWFpIGEgaW5pemlvIHN0cmluZ2EgYXNzb2x1dG8g4oCUIHNpIGNlcmNhIHF1aW5kaSBpbFxuICAgKiBjYXJhdHRlcmUgb3Z1bnF1ZSBuZWxsYSBzdHJpbmdhLlxuICAgKi9cbiAgcHJpdmF0ZSBfaGFzVHlwZWRNaW51cyhyYXdWYWx1ZTogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHJhd1ZhbHVlLmluY2x1ZGVzKCctJyk7XG4gIH1cblxuICAvKipcbiAgICogRXN0cmFlIGRhbGxhIHN0cmluZ2EgZ3JlenphIGxlIHNvbGUgY2lmcmUgaW50ZXJlL2RlY2ltYWxpIGRpZ2l0YXRlLiBVc2F0byBTT0xPIGluIG1vZGFsaXTDoFxuICAgKiBOQVRVUkFMLiBgaGFzRGVjaW1hbEhpbnRgIChzdGF0byBwZXJzaXN0ZW50ZSwgdi4gYF9oYXNEZWNpbWFsU3RhdGVgKSBkaWNlIHNlIHVuIHNlcGFyYXRvcmVcbiAgICogZGVjaW1hbGUgw6ggZ2nDoCBzdGF0byBkaWdpdGF0byBpbiB1biBrZXlzdHJva2UgcHJlY2VkZW50ZTpcbiAgICpcbiAgICogLSBgZmFsc2VgOiBuZXNzdW4gc2VwYXJhdG9yZSBhbmNvcmEg4oCUIHNpIHNjYXJ0YW5vIFRVVFRJIGkgY2FyYXR0ZXJpIG5vbi1jaWZyYSAoaW5jbHVzbyB1blxuICAgKiAgIGV2ZW50dWFsZSBwdW50byBkZWxsZSBtaWdsaWFpYSBnacOgIHByZXNlbnRlIGRhbCByZW5kZXIgcHJlY2VkZW50ZSksIHR1dHRvIGNpw7IgY2hlIHJlc3RhIMOoXG4gICAqICAgcGFydGUgaW50ZXJhLlxuICAgKiAtIGB0cnVlYDogc2kgY2VyY2EgbCdVTFRJTUEgb2Njb3JyZW56YSBkaSBgZGVjaW1hbGAgbyBgJy4nYCBuZWxsYSBzdHJpbmdhIOKAlCBtYWkgbGEgcHJpbWEuIExlXG4gICAqICAgbWlnbGlhaWEgKGFuY2hlIHF1YW5kbyBjb2luY2lkb25vIGNvbiBgJy4nYCwgZm9ybWF0byBldXJvKSBwb3Nzb25vIGNvbXBhcmlyZSBTT0xPIFBSSU1BIGRlbFxuICAgKiAgIHNlcGFyYXRvcmUgZGVjaW1hbGUgcmVhbGUgKGxhIGZvcm1hdHRhemlvbmUgbm9uIHJhZ2dydXBwYSBtYWkgbGUgY2lmcmUgZGVjaW1hbGkpLCBxdWluZGlcbiAgICogICBsJ3VsdGltYSBvY2NvcnJlbnphIMOoIHNlbXByZSBxdWVsbGEgdmVyYSwgc2VuemEgYW1iaWd1aXTDoC4gU2Ugbm9uIHNlIG5lIHRyb3ZhIHBpw7kgbmVzc3VuYVxuICAgKiAgIChsJ3V0ZW50ZSBoYSBjYW5jZWxsYXRvIGlsIHNlcGFyYXRvcmUpLCBzaSByaXRvcm5hIGEgXCJuZXNzdW4gZGVjaW1hbGVcIi5cbiAgICovXG4gIHByaXZhdGUgX3Rva2VuaXplKHJhd1ZhbHVlOiBzdHJpbmcsIGhhc0RlY2ltYWxIaW50OiBib29sZWFuKToge1xuICAgIGludGVnZXJEaWdpdHM6IHN0cmluZztcbiAgICBkZWNpbWFsRGlnaXRzOiBzdHJpbmc7XG4gICAgaGFzRGVjaW1hbFNlcGFyYXRvcjogYm9vbGVhbjtcbiAgICBpc05lZ2F0aXZlOiBib29sZWFuO1xuICB9IHtcbiAgICBjb25zdCB7IGRlY2ltYWwsIGFsbG93TmVnYXRpdmUsIHByZWNpc2lvbiB9ID0gdGhpcy5fb3B0aW9ucztcbiAgICBjb25zdCBpc05lZ2F0aXZlID0gYWxsb3dOZWdhdGl2ZSAmJiB0aGlzLl9oYXNUeXBlZE1pbnVzKHJhd1ZhbHVlKTtcblxuICAgIGlmICghaGFzRGVjaW1hbEhpbnQpIHtcbiAgICAgIHJldHVybiB7IGludGVnZXJEaWdpdHM6IHJhd1ZhbHVlLnJlcGxhY2UoL1teMC05XS9nLCAnJyksIGRlY2ltYWxEaWdpdHM6ICcnLCBoYXNEZWNpbWFsU2VwYXJhdG9yOiBmYWxzZSwgaXNOZWdhdGl2ZSB9O1xuICAgIH1cblxuICAgIGxldCBzcGxpdEluZGV4ID0gLTE7XG4gICAgZm9yIChsZXQgaSA9IHJhd1ZhbHVlLmxlbmd0aCAtIDE7IGkgPj0gMDsgaS0tKSB7XG4gICAgICBpZiAocmF3VmFsdWVbaV0gPT09IGRlY2ltYWwgfHwgcmF3VmFsdWVbaV0gPT09ICcuJykge1xuICAgICAgICBzcGxpdEluZGV4ID0gaTtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgfVxuICAgIGlmIChzcGxpdEluZGV4ID09PSAtMSkge1xuICAgICAgcmV0dXJuIHsgaW50ZWdlckRpZ2l0czogcmF3VmFsdWUucmVwbGFjZSgvW14wLTldL2csICcnKSwgZGVjaW1hbERpZ2l0czogJycsIGhhc0RlY2ltYWxTZXBhcmF0b3I6IGZhbHNlLCBpc05lZ2F0aXZlIH07XG4gICAgfVxuICAgIGNvbnN0IGludGVnZXJEaWdpdHMgPSByYXdWYWx1ZS5zbGljZSgwLCBzcGxpdEluZGV4KS5yZXBsYWNlKC9bXjAtOV0vZywgJycpO1xuICAgIGNvbnN0IGRlY2ltYWxEaWdpdHMgPSByYXdWYWx1ZS5zbGljZShzcGxpdEluZGV4ICsgMSkucmVwbGFjZSgvW14wLTldL2csICcnKS5zbGljZSgwLCBwcmVjaXNpb24pO1xuICAgIHJldHVybiB7IGludGVnZXJEaWdpdHMsIGRlY2ltYWxEaWdpdHMsIGhhc0RlY2ltYWxTZXBhcmF0b3I6IHRydWUsIGlzTmVnYXRpdmUgfTtcbiAgfVxuXG4gIHByaXZhdGUgX3RvTnVtYmVyKGludGVnZXJEaWdpdHM6IHN0cmluZywgZGVjaW1hbERpZ2l0czogc3RyaW5nLCBpc05lZ2F0aXZlOiBib29sZWFuKTogbnVtYmVyIHwgbnVsbCB7XG4gICAgaWYgKGludGVnZXJEaWdpdHMubGVuZ3RoID09PSAwICYmIGRlY2ltYWxEaWdpdHMubGVuZ3RoID09PSAwKSB7XG4gICAgICByZXR1cm4gdGhpcy5fb3B0aW9ucy5udWxsYWJsZSA/IG51bGwgOiAwO1xuICAgIH1cbiAgICBjb25zdCB2YWx1ZSA9IHBhcnNlRmxvYXQoYCR7aW50ZWdlckRpZ2l0cyB8fCAnMCd9LiR7ZGVjaW1hbERpZ2l0cyB8fCAnMCd9YCk7XG4gICAgcmV0dXJuIGlzTmVnYXRpdmUgPyAtdmFsdWUgOiB2YWx1ZTtcbiAgfVxuXG4gIC8qKiBBcHBsaWNhIHNvbG8gYGFsbG93TmVnYXRpdmVgL2BtaW5gL2BtYXhgIOKAlCBOT04gYXJyb3RvbmRhIGEgYHByZWNpc2lvbmAgKHYuIGNvbW1lbnRvIGRpIGNsYXNzZSkuICovXG4gIHByaXZhdGUgX2NsYW1wUmFuZ2UodmFsdWU6IG51bWJlciB8IG51bGwpOiBudW1iZXIgfCBudWxsIHtcbiAgICBpZiAodmFsdWUgPT0gbnVsbCkge1xuICAgICAgcmV0dXJuIHZhbHVlO1xuICAgIH1cbiAgICBjb25zdCB7IG1pbiwgbWF4LCBhbGxvd05lZ2F0aXZlIH0gPSB0aGlzLl9vcHRpb25zO1xuICAgIGxldCByZXN1bHQgPSB2YWx1ZTtcbiAgICBpZiAoIWFsbG93TmVnYXRpdmUgJiYgcmVzdWx0IDwgMCkge1xuICAgICAgcmVzdWx0ID0gLXJlc3VsdDtcbiAgICB9XG4gICAgaWYgKG1pbiAhPSBudWxsICYmIHJlc3VsdCA8IG1pbikge1xuICAgICAgcmVzdWx0ID0gbWluO1xuICAgIH1cbiAgICBpZiAobWF4ICE9IG51bGwgJiYgcmVzdWx0ID4gbWF4KSB7XG4gICAgICByZXN1bHQgPSBtYXg7XG4gICAgfVxuICAgIHJldHVybiByZXN1bHQ7XG4gIH1cblxuICBwcml2YXRlIF9yb3VuZFRvUHJlY2lzaW9uKHZhbHVlOiBudW1iZXIgfCBudWxsKTogbnVtYmVyIHwgbnVsbCB7XG4gICAgaWYgKHZhbHVlID09IG51bGwpIHtcbiAgICAgIHJldHVybiB2YWx1ZTtcbiAgICB9XG4gICAgY29uc3QgZmFjdG9yID0gTWF0aC5wb3coMTAsIHRoaXMuX29wdGlvbnMucHJlY2lzaW9uKTtcbiAgICByZXR1cm4gTWF0aC5yb3VuZCh2YWx1ZSAqIGZhY3RvcikgLyBmYWN0b3I7XG4gIH1cblxuICAvKiogRm9ybWF0byBcImxpdmVcIiwgdXNhdG8gaW4gTkFUVVJBTCBkdXJhbnRlIGxhIGRpZ2l0YXppb25lOiBuZXNzdW4gcGFkZGluZy9hcnJvdG9uZGFtZW50by4gKi9cbiAgcHJpdmF0ZSBfcmVuZGVyTGl2ZShpbnRlZ2VyRGlnaXRzOiBzdHJpbmcsIGRlY2ltYWxEaWdpdHM6IHN0cmluZywgaGFzRGVjaW1hbFNlcGFyYXRvcjogYm9vbGVhbiwgaXNOZWdhdGl2ZTogYm9vbGVhbik6IHZvaWQge1xuICAgIGNvbnN0IHsgcHJlZml4LCBzdWZmaXgsIHRob3VzYW5kcywgZGVjaW1hbCwgcHJlY2lzaW9uIH0gPSB0aGlzLl9vcHRpb25zO1xuICAgIGNvbnN0IGdyb3VwZWRJbnRlZ2VyID0gaW50ZWdlckRpZ2l0cy5yZXBsYWNlKC9cXEIoPz0oXFxkezN9KSsoPyFcXGQpKS9nLCB0aG91c2FuZHMpO1xuICAgIGNvbnN0IGRlY2ltYWxTZWdtZW50ID0gcHJlY2lzaW9uID4gMCAmJiBoYXNEZWNpbWFsU2VwYXJhdG9yID8gZGVjaW1hbCArIGRlY2ltYWxEaWdpdHMgOiAnJztcbiAgICBjb25zdCBmb3JtYXR0ZWQgPSBgJHtpc05lZ2F0aXZlID8gJy0nIDogJyd9JHtwcmVmaXh9JHtncm91cGVkSW50ZWdlcn0ke2RlY2ltYWxTZWdtZW50fSR7c3VmZml4fWA7XG4gICAgdGhpcy5fcmVuZGVyZXIuc2V0UHJvcGVydHkodGhpcy5fZWxlbWVudFJlZi5uYXRpdmVFbGVtZW50LCAndmFsdWUnLCBmb3JtYXR0ZWQpO1xuICB9XG5cbiAgLyoqIEZvcm1hdG8gcGllbm8gKHBhZGRpbmcgYSBgcHJlY2lzaW9uYCwgYXJyb3RvbmRhdG8pIOKAlCB1c2F0byBhIGBibHVyYC9gd3JpdGVWYWx1ZWAvb3B6aW9uaSBjYW1iaWF0ZS4gKi9cbiAgcHJpdmF0ZSBfcmVuZGVyRmluYWwodmFsdWU6IG51bWJlciB8IG51bGwpOiB2b2lkIHtcbiAgICBjb25zdCBmb3JtYXR0ZWQgPSB2YWx1ZSA9PSBudWxsID8gJycgOiB0aGlzLl9mb3JtYXRGdWxsKHZhbHVlKTtcbiAgICB0aGlzLl9yZW5kZXJlci5zZXRQcm9wZXJ0eSh0aGlzLl9lbGVtZW50UmVmLm5hdGl2ZUVsZW1lbnQsICd2YWx1ZScsIGZvcm1hdHRlZCk7XG4gIH1cblxuICBwcml2YXRlIF9mb3JtYXRGdWxsKHZhbHVlOiBudW1iZXIpOiBzdHJpbmcge1xuICAgIGNvbnN0IHsgcHJlZml4LCBzdWZmaXgsIHRob3VzYW5kcywgZGVjaW1hbCwgcHJlY2lzaW9uIH0gPSB0aGlzLl9vcHRpb25zO1xuICAgIGNvbnN0IGlzTmVnYXRpdmUgPSB2YWx1ZSA8IDA7XG4gICAgY29uc3QgZml4ZWQgPSBNYXRoLmFicyh2YWx1ZSkudG9GaXhlZChwcmVjaXNpb24pO1xuICAgIGNvbnN0IFtpbnRlZ2VyUGFydCwgZGVjaW1hbFBhcnRdID0gZml4ZWQuc3BsaXQoJy4nKTtcbiAgICBjb25zdCBncm91cGVkSW50ZWdlciA9IGludGVnZXJQYXJ0LnJlcGxhY2UoL1xcQig/PShcXGR7M30pKyg/IVxcZCkpL2csIHRob3VzYW5kcyk7XG4gICAgY29uc3QgZGVjaW1hbFNlZ21lbnQgPSBwcmVjaXNpb24gPiAwID8gZGVjaW1hbCArIGRlY2ltYWxQYXJ0IDogJyc7XG4gICAgcmV0dXJuIGAke2lzTmVnYXRpdmUgPyAnLScgOiAnJ30ke3ByZWZpeH0ke2dyb3VwZWRJbnRlZ2VyfSR7ZGVjaW1hbFNlZ21lbnR9JHtzdWZmaXh9YDtcbiAgfVxuXG4gIHByaXZhdGUgX2NhcHR1cmVDYXJldEZyb21FbmQoKTogbnVtYmVyIHtcbiAgICBjb25zdCBlbCA9IHRoaXMuX2VsZW1lbnRSZWYubmF0aXZlRWxlbWVudDtcbiAgICBjb25zdCBjYXJldCA9IGVsLnNlbGVjdGlvblN0YXJ0ID8/IGVsLnZhbHVlLmxlbmd0aDtcbiAgICByZXR1cm4gZWwudmFsdWUubGVuZ3RoIC0gY2FyZXQ7XG4gIH1cblxuICBwcml2YXRlIF9yZXN0b3JlQ2FyZXRGcm9tRW5kKGRpc3RhbmNlRnJvbUVuZDogbnVtYmVyKTogdm9pZCB7XG4gICAgY29uc3QgZWwgPSB0aGlzLl9lbGVtZW50UmVmLm5hdGl2ZUVsZW1lbnQ7XG4gICAgY29uc3QgcG9zaXRpb24gPSBNYXRoLm1heCgwLCBlbC52YWx1ZS5sZW5ndGggLSBkaXN0YW5jZUZyb21FbmQpO1xuICAgIC8vIElsIHJlZm9ybWF0IGF2dmllbmUgc2luY3JvbmFtZW50ZSBuZWxsbyBzdGVzc28gY2ljbG8gZGVsbCdldmVudG8gYGlucHV0YDogaWwgYnJvd3NlclxuICAgIC8vIGFwcGxpY2EgbGEgcG9zaXppb25lIGRlbCBjdXJzb3JlIFNVQklUTyBkb3BvLCBzZW56YSBiaXNvZ25vIGRpIHVuIHNldFRpbWVvdXQvbWljcm90YXNrLlxuICAgIGVsLnNldFNlbGVjdGlvblJhbmdlKHBvc2l0aW9uLCBwb3NpdGlvbik7XG4gIH1cbn1cbiJdfQ==
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Public API Surface of tmw-numeric
|
|
3
|
+
*/
|
|
4
|
+
export * from './lib/tmw-numeric-mask.directive';
|
|
5
|
+
export * from './lib/models/tmw-numeric-options.model';
|
|
6
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHVibGljLWFwaS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3Byb2plY3RzL3Rtdy1udW1lcmljL3NyYy9wdWJsaWMtYXBpLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBRUgsY0FBYyxrQ0FBa0MsQ0FBQztBQUNqRCxjQUFjLHdDQUF3QyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLypcbiAqIFB1YmxpYyBBUEkgU3VyZmFjZSBvZiB0bXctbnVtZXJpY1xuICovXG5cbmV4cG9ydCAqIGZyb20gJy4vbGliL3Rtdy1udW1lcmljLW1hc2suZGlyZWN0aXZlJztcbmV4cG9ydCAqIGZyb20gJy4vbGliL21vZGVscy90bXctbnVtZXJpYy1vcHRpb25zLm1vZGVsJztcbiJdfQ==
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generated bundle index. Do not edit.
|
|
3
|
+
*/
|
|
4
|
+
export * from './public-api';
|
|
5
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidG13LW51bWVyaWMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9wcm9qZWN0cy90bXctbnVtZXJpYy9zcmMvdG13LW51bWVyaWMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7O0dBRUc7QUFFSCxjQUFjLGNBQWMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogR2VuZXJhdGVkIGJ1bmRsZSBpbmRleC4gRG8gbm90IGVkaXQuXG4gKi9cblxuZXhwb3J0ICogZnJvbSAnLi9wdWJsaWMtYXBpJztcbiJdfQ==
|