@venn-lang/data 0.1.0
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/LICENSE +21 -0
- package/README.md +143 -0
- package/dist/index.d.ts +152 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1941 -0
- package/dist/index.js.map +1 -0
- package/package.json +54 -0
- package/src/actions/faker-actions.ts +22 -0
- package/src/actions/index.ts +7 -0
- package/src/actions/parse-actions.ts +31 -0
- package/src/actions/random-actions.ts +51 -0
- package/src/csv/csv.types.ts +2 -0
- package/src/csv/index.ts +2 -0
- package/src/csv/parse-csv.ts +30 -0
- package/src/faker/address.ts +70 -0
- package/src/faker/all-specs.ts +25 -0
- package/src/faker/brazil-documents.ts +46 -0
- package/src/faker/brazil.ts +75 -0
- package/src/faker/check-digits.ts +56 -0
- package/src/faker/commerce.ts +59 -0
- package/src/faker/company.ts +41 -0
- package/src/faker/data/business.ts +80 -0
- package/src/faker/data/commerce.ts +73 -0
- package/src/faker/data/index.ts +36 -0
- package/src/faker/data/names.ts +93 -0
- package/src/faker/data/places.ts +109 -0
- package/src/faker/data/web.ts +45 -0
- package/src/faker/data/words.ts +104 -0
- package/src/faker/datetime.ts +102 -0
- package/src/faker/faker.types.ts +24 -0
- package/src/faker/finance.ts +86 -0
- package/src/faker/ids.ts +80 -0
- package/src/faker/index.ts +8 -0
- package/src/faker/internet.ts +100 -0
- package/src/faker/person.ts +88 -0
- package/src/faker/primitives.ts +77 -0
- package/src/faker/text.ts +56 -0
- package/src/index.ts +8 -0
- package/src/plugin.ts +17 -0
- package/src/rng/index.ts +4 -0
- package/src/rng/mulberry32.ts +18 -0
- package/src/rng/rng.types.ts +2 -0
- package/src/rng/shared-rng.ts +15 -0
- package/src/rng/shuffle.ts +17 -0
- package/src/types.ts +14 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Vinicius Borges
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# @venn-lang/data
|
|
2
|
+
|
|
3
|
+
> The `data` namespace: 96 deterministic faker verbs, plus picking, shuffling and parsing.
|
|
4
|
+
|
|
5
|
+
Test data that changes between runs makes a failure impossible to reproduce. Every value this
|
|
6
|
+
package draws comes from one seeded PRNG (mulberry32, seed 1) held at module level, so the same
|
|
7
|
+
flow replays the same person, the same card number, the same CPF. The plugin declares no
|
|
8
|
+
capability and rides no port: `data` is pure computation, no network and no clock.
|
|
9
|
+
|
|
10
|
+
## Install
|
|
11
|
+
|
|
12
|
+
The package is part of the stdlib the `venn` CLI loads, so nothing to install. Reach it from a
|
|
13
|
+
flow with a `use` line:
|
|
14
|
+
|
|
15
|
+
```ruby
|
|
16
|
+
use "venn/data"
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
|
|
21
|
+
```ruby
|
|
22
|
+
module demo.signup
|
|
23
|
+
|
|
24
|
+
use "venn/assert"
|
|
25
|
+
use "venn/data"
|
|
26
|
+
|
|
27
|
+
flow "A generated Brazilian signup" {
|
|
28
|
+
const name = data.faker.name
|
|
29
|
+
const email = data.faker.email
|
|
30
|
+
const cpf = data.faker.br.cpf
|
|
31
|
+
const card = data.faker.creditCard
|
|
32
|
+
|
|
33
|
+
step "the generated person is plausible" {
|
|
34
|
+
expect name contains " "
|
|
35
|
+
expect email contains "@"
|
|
36
|
+
expect cpf contains "-"
|
|
37
|
+
expect card contains " "
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
step "and the rest of the namespace is there too" {
|
|
41
|
+
const plan = data.oneOf "free" "pro"
|
|
42
|
+
const roll = data.range 1 10
|
|
43
|
+
const rows = data.csv "name,plan\nada,pro\nlinus,free"
|
|
44
|
+
|
|
45
|
+
expect roll >= 1
|
|
46
|
+
expect rows.len == 2
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Verbs
|
|
52
|
+
|
|
53
|
+
Five verbs sit directly on the namespace:
|
|
54
|
+
|
|
55
|
+
| Verb | Gives back | Notes |
|
|
56
|
+
| --- | --- | --- |
|
|
57
|
+
| `data.oneOf a b c…` | `dynamic` | One of the positional arguments. |
|
|
58
|
+
| `data.range min max` | `number` | An integer in the inclusive range. |
|
|
59
|
+
| `data.shuffle values` | `list<dynamic>` | A permutation. The input array is left alone. |
|
|
60
|
+
| `data.csv text` | `list<data.Row>` | Parses inline CSV; the first line names the columns. |
|
|
61
|
+
| `data.json text` | `dynamic` | `JSON.parse`, with the shape left to the caller. |
|
|
62
|
+
|
|
63
|
+
The other 96 are `data.faker.*`, grouped by what a form asks for:
|
|
64
|
+
|
|
65
|
+
| Family | Verbs |
|
|
66
|
+
| --- | --- |
|
|
67
|
+
| Person | `firstName` `lastName` `name` `fullName` `prefix` `suffix` `gender` `jobTitle` `age` `birthDate` `phone` |
|
|
68
|
+
| Internet | `email` `username` `password` `domain` `url` `ipv4` `ipv6` `mac` `port` `userAgent` `slug` `httpMethod` `httpStatus` `mimeType` |
|
|
69
|
+
| Address | `street` `streetAddress` `address` `buildingNumber` `city` `country` `countryCode` `zip` `latitude` `longitude` `timezone` |
|
|
70
|
+
| Company | `company` `department` `catchPhrase` `buzzword` |
|
|
71
|
+
| Commerce | `product` `productName` `sku` `barcode` `category` `material` `color` `hexColor` `price` |
|
|
72
|
+
| Finance | `creditCard` `cardType` `cvv` `expiryDate` `iban` `bic` `accountNumber` `currencyCode` `currencySymbol` `currencyName` `amount` |
|
|
73
|
+
| Date and time | `date` `dateTime` `pastDate` `futureDate` `time` `timestamp` `weekday` `month` `year` |
|
|
74
|
+
| Text | `word` `words` `sentence` `sentences` `paragraph` `paragraphs` `title` |
|
|
75
|
+
| Identifiers | `uuid` `nanoid` `objectId` `hex` `token` `alphanumeric` `digits` `int` `float` `boolean` |
|
|
76
|
+
| Brazil | `br.cpf` `br.cnpj` `br.cep` `br.phone` `br.plate` `br.street` `br.address` `br.city` `br.state` `br.stateCode` |
|
|
77
|
+
|
|
78
|
+
Ten of them read positional bounds; the rest take nothing.
|
|
79
|
+
|
|
80
|
+
```ruby
|
|
81
|
+
const pin = data.faker.digits 4 # four decimal digits
|
|
82
|
+
const quantity = data.faker.int 1 6 # inclusive on both ends
|
|
83
|
+
const blurb = data.faker.words 5
|
|
84
|
+
const born = data.faker.year 1980 2005
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
The full list of verbs that read arguments: `nanoid(length)`, `hex(length)`,
|
|
88
|
+
`alphanumeric(length)`, `digits(length)`, `int(min, max)`, `float(min, max)`, `words(count)`,
|
|
89
|
+
`sentences(count)`, `paragraphs(count)`, `year(from, to)`. All arguments are optional and every
|
|
90
|
+
one has a default.
|
|
91
|
+
|
|
92
|
+
### Check digits are real
|
|
93
|
+
|
|
94
|
+
A value a form rejects before it reaches the server is useless in a test, so the generators that
|
|
95
|
+
carry a checksum compute it: `creditCard` passes Luhn, `barcode` passes the EAN-13 check, `iban`
|
|
96
|
+
passes mod-97, and `br.cpf` and `br.cnpj` carry the digits a Brazilian form validates.
|
|
97
|
+
|
|
98
|
+
## API
|
|
99
|
+
|
|
100
|
+
| Export | What it is |
|
|
101
|
+
| --- | --- |
|
|
102
|
+
| `dataPlugin` (also the default export) | The `PluginDefinition` for the `data` namespace. |
|
|
103
|
+
| `dataActions` | The `ActionDefinition[]` behind it, faker verbs included. |
|
|
104
|
+
| `allFakerSpecs`, `FakerSpec` | The catalogue as data: `name`, `doc`, a `TypeSpec` result, optional `args`, and `make(rng, args)`. |
|
|
105
|
+
| `rng`, `resetRng()` | The shared PRNG and the reset that rewinds it to the seed. |
|
|
106
|
+
| `mulberry32(seed)`, `Rng` | The generator itself, for an independent stream. |
|
|
107
|
+
| `shuffleWith(items, rng)` | Fisher-Yates against a given PRNG. Returns a new array. |
|
|
108
|
+
| `parseCsv(content)`, `CsvRow` | The splitter behind `data.csv`. |
|
|
109
|
+
| `uuid`, `email`, `firstName`, `lastName`, `fullName` | Single generators, each taking an `Rng`. |
|
|
110
|
+
| `cpfDigits`, `cnpjDigits`, `luhnDigit`, `eanDigit`, `ibanCheck` | The check-digit functions on their own. |
|
|
111
|
+
| `ANCHOR` | The fixed instant the date verbs are drawn around, `2025-01-01T00:00:00Z`. |
|
|
112
|
+
|
|
113
|
+
The plugin publishes one named type, `data.Row`: a map of string to string, which is what
|
|
114
|
+
`data.csv` gives back per record.
|
|
115
|
+
|
|
116
|
+
## Determinism
|
|
117
|
+
|
|
118
|
+
`rng` is a module-level mulberry32 seeded with `1`. Draws advance one shared stream, so the
|
|
119
|
+
sequence of calls a flow makes is what determines the values, not the wall clock. `resetRng()`
|
|
120
|
+
rewinds it, which is how the tests here assert that a whole catalogue replays identically:
|
|
121
|
+
|
|
122
|
+
```ts
|
|
123
|
+
import { allFakerSpecs, resetRng, rng } from "@venn-lang/data";
|
|
124
|
+
|
|
125
|
+
resetRng();
|
|
126
|
+
const first = allFakerSpecs.map((spec) => spec.make(rng, []));
|
|
127
|
+
resetRng();
|
|
128
|
+
const again = allFakerSpecs.map((spec) => spec.make(rng, []));
|
|
129
|
+
// `again` equals `first`: the same 96 values, in the same order
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Dates are drawn around `ANCHOR` rather than `Date.now()`, for the same reason.
|
|
133
|
+
|
|
134
|
+
## Limits
|
|
135
|
+
|
|
136
|
+
`parseCsv` is a minimal splitter: it reads inline content only (no file paths yet), splits on
|
|
137
|
+
commas and trims cells, and does not handle quoted commas.
|
|
138
|
+
|
|
139
|
+
## See also
|
|
140
|
+
|
|
141
|
+
- [`@venn-lang/crypto`](../std-crypto) for hashing and signing the values generated here.
|
|
142
|
+
- [`@venn-lang/mock`](../std-mock) for freezing the clock and flipping flags.
|
|
143
|
+
- [`@venn-lang/sdk`](../sdk) for `defineAction` and `definePlugin`.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { ActionDefinition, ArgSpec, PluginDefinition } from "@venn-lang/sdk";
|
|
2
|
+
import { TypeSpec } from "@venn-lang/types";
|
|
3
|
+
//#region src/actions/index.d.ts
|
|
4
|
+
/** Every verb in the `data` namespace. Adding one is a single line here. */
|
|
5
|
+
declare const dataActions: ActionDefinition[];
|
|
6
|
+
//#endregion
|
|
7
|
+
//#region src/csv/csv.types.d.ts
|
|
8
|
+
/** One parsed CSV record: header name → cell value, both strings. */
|
|
9
|
+
type CsvRow = Record<string, string>;
|
|
10
|
+
//#endregion
|
|
11
|
+
//#region src/csv/parse-csv.d.ts
|
|
12
|
+
/**
|
|
13
|
+
* Parse a CSV string into row objects. The first line supplies the headers.
|
|
14
|
+
*
|
|
15
|
+
* A minimal splitter: it takes inline content only (never a path) and does not
|
|
16
|
+
* understand quoting, so a quoted cell containing a comma splits in two.
|
|
17
|
+
*
|
|
18
|
+
* @param content The CSV text. Blank lines are skipped.
|
|
19
|
+
* @returns One object per data line, keyed by header. Empty when there is no header line.
|
|
20
|
+
*/
|
|
21
|
+
declare function parseCsv(content: string): CsvRow[];
|
|
22
|
+
//#endregion
|
|
23
|
+
//#region src/rng/rng.types.d.ts
|
|
24
|
+
/** A deterministic pseudo-random generator: each call yields the next float in [0, 1). */
|
|
25
|
+
type Rng = () => number;
|
|
26
|
+
//#endregion
|
|
27
|
+
//#region src/rng/mulberry32.d.ts
|
|
28
|
+
/**
|
|
29
|
+
* Mulberry32: a tiny, fast, fully deterministic PRNG.
|
|
30
|
+
*
|
|
31
|
+
* @param seed Any number. It is coerced to a uint32, so the same seed always
|
|
32
|
+
* yields the same stream.
|
|
33
|
+
* @returns A generator producing the next float in [0, 1) on each call.
|
|
34
|
+
*/
|
|
35
|
+
declare function mulberry32(seed: number): Rng;
|
|
36
|
+
//#endregion
|
|
37
|
+
//#region src/rng/shared-rng.d.ts
|
|
38
|
+
/** The module-level deterministic PRNG shared by every generator in this package. */
|
|
39
|
+
declare const rng: Rng;
|
|
40
|
+
/** Reset the shared PRNG to its seed so the same stream can be drawn again. Used by tests. */
|
|
41
|
+
declare function resetRng(): void;
|
|
42
|
+
//#endregion
|
|
43
|
+
//#region src/rng/shuffle.d.ts
|
|
44
|
+
/**
|
|
45
|
+
* Fisher-Yates shuffle driven by the given PRNG.
|
|
46
|
+
*
|
|
47
|
+
* @returns A new array holding the same elements in a new order. `items` is untouched.
|
|
48
|
+
*/
|
|
49
|
+
declare function shuffleWith(items: readonly unknown[], rng: Rng): unknown[];
|
|
50
|
+
//#endregion
|
|
51
|
+
//#region src/faker/faker.types.d.ts
|
|
52
|
+
/**
|
|
53
|
+
* One `data.faker.*` verb: what it is called, what it means, and how to draw a
|
|
54
|
+
* value. A spec is plain data, so the action wiring reads the list as it stands
|
|
55
|
+
* and needs no edit when a category grows.
|
|
56
|
+
*/
|
|
57
|
+
interface FakerSpec {
|
|
58
|
+
/** The verb, without the namespace: `email`, `br.cpf`. */
|
|
59
|
+
name: string;
|
|
60
|
+
/** One line, in the user's domain. Shown on hover and in completion. */
|
|
61
|
+
doc: string;
|
|
62
|
+
/** The type it draws. A `TypeSpec`, not a name, so the checker can act on it. */
|
|
63
|
+
result: TypeSpec;
|
|
64
|
+
/**
|
|
65
|
+
* The positional arguments `make` reads, in order. Most verbs read none and
|
|
66
|
+
* leave this out. The action wiring turns it into the signature the checker sees.
|
|
67
|
+
*/
|
|
68
|
+
args?: readonly ArgSpec[];
|
|
69
|
+
/** Draw a value. `args` carries the call's positional arguments, if any. */
|
|
70
|
+
make(rng: Rng, args: readonly unknown[]): unknown;
|
|
71
|
+
}
|
|
72
|
+
//#endregion
|
|
73
|
+
//#region src/faker/all-specs.d.ts
|
|
74
|
+
/** Every `data.faker.*` verb. Adding a whole category is one line here. */
|
|
75
|
+
declare const allFakerSpecs: readonly FakerSpec[];
|
|
76
|
+
//#endregion
|
|
77
|
+
//#region src/faker/brazil-documents.d.ts
|
|
78
|
+
/**
|
|
79
|
+
* The two CPF check digits.
|
|
80
|
+
*
|
|
81
|
+
* @param base The first nine digits, unformatted.
|
|
82
|
+
* @returns Two digits to append.
|
|
83
|
+
*/
|
|
84
|
+
declare function cpfDigits(base: string): string;
|
|
85
|
+
/**
|
|
86
|
+
* The two CNPJ check digits.
|
|
87
|
+
*
|
|
88
|
+
* @param base The first twelve digits, unformatted.
|
|
89
|
+
* @returns Two digits to append.
|
|
90
|
+
*/
|
|
91
|
+
declare function cnpjDigits(base: string): string;
|
|
92
|
+
//#endregion
|
|
93
|
+
//#region src/faker/check-digits.d.ts
|
|
94
|
+
/**
|
|
95
|
+
* The Luhn check digit for a card number.
|
|
96
|
+
*
|
|
97
|
+
* @param base The digits preceding the check digit.
|
|
98
|
+
* @returns One digit. Appending it makes `base` pass the Luhn test.
|
|
99
|
+
*/
|
|
100
|
+
declare function luhnDigit(base: string): string;
|
|
101
|
+
/**
|
|
102
|
+
* The EAN-13 check digit for the leading 12 digits of a barcode.
|
|
103
|
+
*
|
|
104
|
+
* @param base Exactly 12 digits.
|
|
105
|
+
* @returns The thirteenth digit.
|
|
106
|
+
*/
|
|
107
|
+
declare function eanDigit(base: string): string;
|
|
108
|
+
/**
|
|
109
|
+
* The two IBAN check digits: mod-97 over the rearranged, letter-expanded account.
|
|
110
|
+
*
|
|
111
|
+
* @param country The two-letter country code, upper case.
|
|
112
|
+
* @param account The account part, without check digits.
|
|
113
|
+
* @returns Two digits, zero-padded, to be inserted after the country code.
|
|
114
|
+
*/
|
|
115
|
+
declare function ibanCheck(country: string, account: string): string;
|
|
116
|
+
//#endregion
|
|
117
|
+
//#region src/faker/datetime.d.ts
|
|
118
|
+
/**
|
|
119
|
+
* The instant every generated date is measured from.
|
|
120
|
+
*
|
|
121
|
+
* Dates hang off a fixed anchor rather than the wall clock: `Date.now()` would
|
|
122
|
+
* give a different answer on every run and break the seeded replay guarantee.
|
|
123
|
+
*/
|
|
124
|
+
declare const ANCHOR: number;
|
|
125
|
+
//#endregion
|
|
126
|
+
//#region src/faker/ids.d.ts
|
|
127
|
+
/** An RFC 4122 v4 UUID. The version and variant bits are stamped, not drawn. */
|
|
128
|
+
declare function uuid(rng: Rng): string;
|
|
129
|
+
//#endregion
|
|
130
|
+
//#region src/faker/internet.d.ts
|
|
131
|
+
/** An email on a reserved domain, e.g. `"grace.hopper@example.test"`. It reaches nobody. */
|
|
132
|
+
declare function email(rng: Rng): string;
|
|
133
|
+
//#endregion
|
|
134
|
+
//#region src/faker/person.d.ts
|
|
135
|
+
/** A given name, e.g. `"Grace"`. */
|
|
136
|
+
declare function firstName(rng: Rng): string;
|
|
137
|
+
/** A family name, e.g. `"Hopper"`. */
|
|
138
|
+
declare function lastName(rng: Rng): string;
|
|
139
|
+
/** A full name, e.g. `"Grace Hopper"`. */
|
|
140
|
+
declare function fullName(rng: Rng): string;
|
|
141
|
+
//#endregion
|
|
142
|
+
//#region src/plugin.d.ts
|
|
143
|
+
/**
|
|
144
|
+
* The `data` plugin: pure, deterministic test-data generators.
|
|
145
|
+
*
|
|
146
|
+
* Every verb draws from a seeded module-level PRNG, so the same script replays the
|
|
147
|
+
* same values. Nothing here does I/O, so there is no capability and no port to bind.
|
|
148
|
+
*/
|
|
149
|
+
declare const dataPlugin: PluginDefinition;
|
|
150
|
+
//#endregion
|
|
151
|
+
export { ANCHOR, type CsvRow, type FakerSpec, type Rng, allFakerSpecs, cnpjDigits, cpfDigits, dataActions, dataPlugin, dataPlugin as default, eanDigit, email, firstName, fullName, ibanCheck, lastName, luhnDigit, mulberry32, parseCsv, resetRng, rng, shuffleWith, uuid };
|
|
152
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/actions/index.ts","../src/csv/csv.types.ts","../src/csv/parse-csv.ts","../src/rng/rng.types.ts","../src/rng/mulberry32.ts","../src/rng/shared-rng.ts","../src/rng/shuffle.ts","../src/faker/faker.types.ts","../src/faker/all-specs.ts","../src/faker/brazil-documents.ts","../src/faker/check-digits.ts","../src/faker/datetime.ts","../src/faker/ids.ts","../src/faker/internet.ts","../src/faker/person.ts","../src/plugin.ts"],"mappings":";;;;cAMa,aAAa;;;;KCLd,SAAS;;;;;;;;;;;;iBCUL,SAAS,kBAAkB;;;;KCV/B;;;;;;;;;;iBCQI,WAAW,eAAe;;;;cCA7B,KAAK;;iBAGF;;;;;;;;iBCLA,YAAY,2BAA2B,KAAK;;;;;;;;UCE3C;;EAEf;;EAEA;;EAEA,QAAQ;;;;;EAKR,gBAAgB;;EAEhB,KAAK,KAAK,KAAK;;;;;cCTJ,wBAAwB;;;;;;;;;iBCHrB,UAAU;;;;;;;iBAsBV,WAAW;;;;;;;;;iBCpBX,UAAU;;;;;;;iBAiBV,SAAS;;;;;;;;iBAeT,UAAU,iBAAiB;;;;;;;;;cChC9B;;;;iBCLG,KAAK,KAAK;;;;iBCWV,MAAM,KAAK;;;;iBCJX,UAAU,KAAK;;iBAKf,SAAS,KAAK;;iBAKd,SAAS,KAAK;;;;;;;;;cCdjB,YAAY"}
|