rrdir 14.0.0 → 14.0.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/dist/index.d.ts CHANGED
@@ -1,35 +1,49 @@
1
- import type { Stats } from "node:fs";
2
- import type { Matcher } from "picomatch";
3
- export type Encoding = "utf8" | "buffer";
4
- export type Dir = string | Uint8Array;
5
- export type DirNodeCompatible = string | Buffer;
6
- export type RRDirOpts = {
7
- strict?: boolean;
8
- stats?: boolean;
9
- followSymlinks?: boolean;
10
- include?: string[];
11
- exclude?: string[];
12
- insensitive?: boolean;
1
+ import { Stats } from "node:fs";
2
+ import { Matcher } from "picomatch";
3
+
4
+ //#region index.d.ts
5
+ type Encoding = "utf8" | "buffer";
6
+ type Dir = string | Uint8Array;
7
+ type DirNodeCompatible = string | Buffer;
8
+ type RRDirOpts = {
9
+ strict?: boolean;
10
+ stats?: boolean;
11
+ followSymlinks?: boolean;
12
+ include?: string[];
13
+ exclude?: string[];
14
+ insensitive?: boolean;
13
15
  };
14
16
  type InternalOpts = {
15
- includeMatcher?: Matcher;
16
- excludeMatcher?: Matcher;
17
- encoding?: Encoding;
17
+ includeMatcher?: Matcher;
18
+ excludeMatcher?: Matcher;
19
+ encoding?: Encoding;
18
20
  };
19
- export type Entry = {
20
- /** The path to the entry, will be relative if `dir` is given relative. If `dir` is a `Uint8Array`, this will be too. Always present. */
21
- path: Dir;
22
- /** Boolean indicating whether the entry is a directory. `undefined` on error. */
23
- directory?: boolean;
24
- /** Boolean indicating whether the entry is a symbolic link. `undefined` on error. */
25
- symlink?: boolean;
26
- /** A [`fs.stats`](https://nodejs.org/api/fs.html#fs_class_fs_stats) object, present when `options.stats` is set. `undefined` on error. */
27
- stats?: Stats;
28
- /** Any error encountered while reading this entry. `undefined` on success. */
29
- err?: Error;
21
+ type Entry = {
22
+ /** The path to the entry, will be relative if `dir` is given relative. If `dir` is a `Uint8Array`, this will be too. Always present. */
23
+ path: Dir;
24
+ /** Boolean indicating whether the entry is a directory. `undefined` on error. */
25
+ directory?: boolean;
26
+ /** Boolean indicating whether the entry is a symbolic link. `undefined` on error. */
27
+ symlink?: boolean;
28
+ /** A [`fs.stats`](https://nodejs.org/api/fs.html#fs_class_fs_stats) object, present when `options.stats` is set. `undefined` on error. */
29
+ stats?: Stats;
30
+ /** Any error encountered while reading this entry. `undefined` on success. */
31
+ err?: Error;
30
32
  };
31
- export declare function rrdir(dir: Dir, opts?: RRDirOpts, { includeMatcher, excludeMatcher, encoding }?: InternalOpts): AsyncGenerator<Entry>;
32
- export declare function rrdirAsync(dir: Dir, opts?: RRDirOpts, { includeMatcher, excludeMatcher, encoding }?: InternalOpts): Promise<Entry[]>;
33
- export declare function rrdirSync(dir: Dir, opts?: RRDirOpts, { includeMatcher, excludeMatcher, encoding }?: InternalOpts): Entry[];
34
- export {};
35
- //# sourceMappingURL=index.d.ts.map
33
+ declare function rrdir(dir: Dir, opts?: RRDirOpts, {
34
+ includeMatcher,
35
+ excludeMatcher,
36
+ encoding
37
+ }?: InternalOpts): AsyncGenerator<Entry>;
38
+ declare function rrdirAsync(dir: Dir, opts?: RRDirOpts, {
39
+ includeMatcher,
40
+ excludeMatcher,
41
+ encoding
42
+ }?: InternalOpts): Promise<Entry[]>;
43
+ declare function rrdirSync(dir: Dir, opts?: RRDirOpts, {
44
+ includeMatcher,
45
+ excludeMatcher,
46
+ encoding
47
+ }?: InternalOpts): Entry[];
48
+ //#endregion
49
+ export { Dir, DirNodeCompatible, Encoding, Entry, RRDirOpts, rrdir, rrdirAsync, rrdirSync };
package/dist/index.js CHANGED
@@ -1,8 +1,9 @@
1
- import { readdir, stat, lstat } from 'node:fs/promises';
2
- import { readdirSync, statSync, lstatSync } from 'node:fs';
3
- import { sep, resolve } from 'node:path';
4
- import picomatch from 'picomatch';
1
+ import { lstat, readdir, stat } from "node:fs/promises";
2
+ import { lstatSync, readdirSync, statSync } from "node:fs";
3
+ import { resolve, sep } from "node:path";
4
+ import picomatch from "picomatch";
5
5
 
6
+ //#region index.ts
6
7
  const encoder = new TextEncoder();
7
8
  const toUint8Array = encoder.encode.bind(encoder);
8
9
  const decoder = new TextDecoder();
@@ -10,179 +11,214 @@ const toString = decoder.decode.bind(decoder);
10
11
  const sepUint8Array = toUint8Array(sep);
11
12
  const getEncoding = (dir) => dir instanceof Uint8Array ? "buffer" : "utf8";
12
13
  const defaultOpts = {
13
- strict: false,
14
- stats: false,
15
- followSymlinks: false,
16
- exclude: void 0,
17
- include: void 0,
18
- insensitive: false
14
+ strict: false,
15
+ stats: false,
16
+ followSymlinks: false,
17
+ exclude: void 0,
18
+ include: void 0,
19
+ insensitive: false
19
20
  };
20
21
  function makePath({ name }, dir, encoding) {
21
- if (encoding === "buffer") {
22
- return dir === "." ? name : Uint8Array.from([...dir, ...sepUint8Array, ...name]);
23
- } else {
24
- return dir === "." ? name : `${dir}${sep}${name}`;
25
- }
22
+ if (encoding === "buffer") return dir === "." ? name : Uint8Array.from([
23
+ ...dir,
24
+ ...sepUint8Array,
25
+ ...name
26
+ ]);
27
+ else return dir === "." ? name : `${dir}${sep}${name}`;
26
28
  }
27
29
  function build(dirent, path, stats, opts) {
28
- return {
29
- path,
30
- directory: (stats || dirent).isDirectory(),
31
- symlink: (stats || dirent).isSymbolicLink(),
32
- ...opts.stats ? { stats } : {}
33
- };
30
+ return {
31
+ path,
32
+ directory: (stats || dirent).isDirectory(),
33
+ symlink: (stats || dirent).isSymbolicLink(),
34
+ ...opts.stats ? { stats } : {}
35
+ };
34
36
  }
35
37
  function makeMatchers({ include, exclude, insensitive }) {
36
- const opts = {
37
- dot: true,
38
- flags: insensitive ? "i" : void 0
39
- };
40
- return {
41
- includeMatcher: include?.length ? (path) => picomatch(include, opts)(resolve(path)) : null,
42
- excludeMatcher: exclude?.length ? (path) => picomatch(exclude, opts)(resolve(path)) : null
43
- };
38
+ const opts = {
39
+ dot: true,
40
+ flags: insensitive ? "i" : void 0
41
+ };
42
+ return {
43
+ includeMatcher: include?.length ? (path) => picomatch(include, opts)(resolve(path)) : null,
44
+ excludeMatcher: exclude?.length ? (path) => picomatch(exclude, opts)(resolve(path)) : null
45
+ };
44
46
  }
45
47
  async function* rrdir(dir, opts = {}, { includeMatcher, excludeMatcher, encoding } = {}) {
46
- if (includeMatcher === void 0) {
47
- opts = { ...defaultOpts, ...opts };
48
- ({ includeMatcher, excludeMatcher } = makeMatchers(opts));
49
- if (typeof dir === "string" && /[/\\]$/.test(dir)) dir = dir.substring(0, dir.length - 1);
50
- encoding = getEncoding(dir);
51
- }
52
- let dirents = [];
53
- try {
54
- dirents = await readdir(dir, { encoding, withFileTypes: true });
55
- } catch (err) {
56
- if (opts.strict) throw err;
57
- yield { path: dir, err };
58
- }
59
- if (!dirents.length) return;
60
- for (const dirent of dirents) {
61
- const path = makePath(dirent, dir, encoding);
62
- if (excludeMatcher?.(encoding === "buffer" ? toString(path) : path)) continue;
63
- const isSymbolicLink = opts.followSymlinks && dirent.isSymbolicLink();
64
- const encodedPath = encoding === "buffer" ? toString(path) : path;
65
- const isIncluded = !includeMatcher || includeMatcher(encodedPath);
66
- let stats;
67
- if (isIncluded) {
68
- if (opts.stats || isSymbolicLink) {
69
- try {
70
- stats = await (opts.followSymlinks ? stat : lstat)(path);
71
- } catch (err) {
72
- if (opts.strict) throw err;
73
- yield { path, err };
74
- }
75
- }
76
- yield build(dirent, path, stats, opts);
77
- }
78
- let recurse = false;
79
- if (isSymbolicLink) {
80
- if (!stats) try {
81
- stats = await stat(path);
82
- } catch {
83
- }
84
- if (stats && stats.isDirectory()) recurse = true;
85
- } else if (dirent.isDirectory()) {
86
- recurse = true;
87
- }
88
- if (recurse) yield* rrdir(path, opts, { includeMatcher, excludeMatcher, encoding });
89
- }
48
+ if (includeMatcher === void 0) {
49
+ opts = {
50
+ ...defaultOpts,
51
+ ...opts
52
+ };
53
+ ({includeMatcher, excludeMatcher} = makeMatchers(opts));
54
+ if (typeof dir === "string" && /[/\\]$/.test(dir)) dir = dir.substring(0, dir.length - 1);
55
+ encoding = getEncoding(dir);
56
+ }
57
+ let dirents = [];
58
+ try {
59
+ dirents = await readdir(dir, {
60
+ encoding,
61
+ withFileTypes: true
62
+ });
63
+ } catch (err) {
64
+ if (opts.strict) throw err;
65
+ yield {
66
+ path: dir,
67
+ err
68
+ };
69
+ }
70
+ if (!dirents.length) return;
71
+ for (const dirent of dirents) {
72
+ const path = makePath(dirent, dir, encoding);
73
+ if (excludeMatcher?.(encoding === "buffer" ? toString(path) : path)) continue;
74
+ const isSymbolicLink = Boolean(opts.followSymlinks && dirent.isSymbolicLink());
75
+ const encodedPath = encoding === "buffer" ? toString(path) : path;
76
+ const isIncluded = !includeMatcher || includeMatcher(encodedPath);
77
+ let stats;
78
+ if (isIncluded) {
79
+ if (opts.stats || isSymbolicLink) try {
80
+ stats = await (opts.followSymlinks ? stat : lstat)(path);
81
+ } catch (err) {
82
+ if (opts.strict) throw err;
83
+ yield {
84
+ path,
85
+ err
86
+ };
87
+ }
88
+ yield build(dirent, path, stats, opts);
89
+ }
90
+ let recurse = false;
91
+ if (isSymbolicLink) {
92
+ if (!stats) try {
93
+ stats = await stat(path);
94
+ } catch {}
95
+ if (stats?.isDirectory()) recurse = true;
96
+ } else if (dirent.isDirectory()) recurse = true;
97
+ if (recurse) yield* rrdir(path, opts, {
98
+ includeMatcher,
99
+ excludeMatcher,
100
+ encoding
101
+ });
102
+ }
90
103
  }
91
104
  async function rrdirAsync(dir, opts = {}, { includeMatcher, excludeMatcher, encoding } = {}) {
92
- if (includeMatcher === void 0) {
93
- opts = { ...defaultOpts, ...opts };
94
- ({ includeMatcher, excludeMatcher } = makeMatchers(opts));
95
- if (typeof dir === "string" && /[/\\]$/.test(dir)) dir = dir.substring(0, dir.length - 1);
96
- encoding = getEncoding(dir);
97
- }
98
- const results = [];
99
- let dirents = [];
100
- try {
101
- dirents = await readdir(dir, { encoding, withFileTypes: true });
102
- } catch (err) {
103
- if (opts.strict) throw err;
104
- results.push({ path: dir, err });
105
- }
106
- if (!dirents.length) return results;
107
- await Promise.all(dirents.map(async (dirent) => {
108
- const path = makePath(dirent, dir, encoding);
109
- if (excludeMatcher?.(encoding === "buffer" ? toString(path) : path)) return;
110
- const isSymbolicLink = opts.followSymlinks && dirent.isSymbolicLink();
111
- const encodedPath = encoding === "buffer" ? toString(path) : path;
112
- const isIncluded = !includeMatcher || includeMatcher(encodedPath);
113
- let stats;
114
- if (isIncluded) {
115
- if (opts.stats || isSymbolicLink) {
116
- try {
117
- stats = await (opts.followSymlinks ? stat : lstat)(path);
118
- } catch (err) {
119
- if (opts.strict) throw err;
120
- results.push({ path, err });
121
- }
122
- }
123
- results.push(build(dirent, path, stats, opts));
124
- }
125
- let recurse = false;
126
- if (isSymbolicLink) {
127
- if (!stats) try {
128
- stats = await stat(path);
129
- } catch {
130
- }
131
- if (stats && stats.isDirectory()) recurse = true;
132
- } else if (dirent.isDirectory()) {
133
- recurse = true;
134
- }
135
- if (recurse) results.push(...await rrdirAsync(path, opts, { includeMatcher, excludeMatcher, encoding }));
136
- }));
137
- return results;
105
+ if (includeMatcher === void 0) {
106
+ opts = {
107
+ ...defaultOpts,
108
+ ...opts
109
+ };
110
+ ({includeMatcher, excludeMatcher} = makeMatchers(opts));
111
+ if (typeof dir === "string" && /[/\\]$/.test(dir)) dir = dir.substring(0, dir.length - 1);
112
+ encoding = getEncoding(dir);
113
+ }
114
+ const results = [];
115
+ let dirents = [];
116
+ try {
117
+ dirents = await readdir(dir, {
118
+ encoding,
119
+ withFileTypes: true
120
+ });
121
+ } catch (err) {
122
+ if (opts.strict) throw err;
123
+ results.push({
124
+ path: dir,
125
+ err
126
+ });
127
+ }
128
+ if (!dirents.length) return results;
129
+ await Promise.all(dirents.map(async (dirent) => {
130
+ const path = makePath(dirent, dir, encoding);
131
+ if (excludeMatcher?.(encoding === "buffer" ? toString(path) : path)) return;
132
+ const isSymbolicLink = Boolean(opts.followSymlinks && dirent.isSymbolicLink());
133
+ const encodedPath = encoding === "buffer" ? toString(path) : path;
134
+ const isIncluded = !includeMatcher || includeMatcher(encodedPath);
135
+ let stats;
136
+ if (isIncluded) {
137
+ if (opts.stats || isSymbolicLink) try {
138
+ stats = await (opts.followSymlinks ? stat : lstat)(path);
139
+ } catch (err) {
140
+ if (opts.strict) throw err;
141
+ results.push({
142
+ path,
143
+ err
144
+ });
145
+ }
146
+ results.push(build(dirent, path, stats, opts));
147
+ }
148
+ let recurse = false;
149
+ if (isSymbolicLink) {
150
+ if (!stats) try {
151
+ stats = await stat(path);
152
+ } catch {}
153
+ if (stats?.isDirectory()) recurse = true;
154
+ } else if (dirent.isDirectory()) recurse = true;
155
+ if (recurse) results.push(...await rrdirAsync(path, opts, {
156
+ includeMatcher,
157
+ excludeMatcher,
158
+ encoding
159
+ }));
160
+ }));
161
+ return results;
138
162
  }
139
163
  function rrdirSync(dir, opts = {}, { includeMatcher, excludeMatcher, encoding } = {}) {
140
- if (includeMatcher === void 0) {
141
- opts = { ...defaultOpts, ...opts };
142
- ({ includeMatcher, excludeMatcher } = makeMatchers(opts));
143
- if (typeof dir === "string" && /[/\\]$/.test(dir)) dir = dir.substring(0, dir.length - 1);
144
- encoding = getEncoding(dir);
145
- }
146
- const results = [];
147
- let dirents = [];
148
- try {
149
- dirents = readdirSync(dir, { encoding, withFileTypes: true });
150
- } catch (err) {
151
- if (opts.strict) throw err;
152
- results.push({ path: dir, err });
153
- }
154
- if (!dirents.length) return results;
155
- for (const dirent of dirents) {
156
- const path = makePath(dirent, dir, encoding);
157
- if (excludeMatcher?.(encoding === "buffer" ? toString(path) : path)) continue;
158
- const isSymbolicLink = opts.followSymlinks && dirent.isSymbolicLink();
159
- const encodedPath = encoding === "buffer" ? toString(path) : path;
160
- const isIncluded = !includeMatcher || includeMatcher(encodedPath);
161
- let stats;
162
- if (isIncluded) {
163
- if (opts.stats || isSymbolicLink) {
164
- try {
165
- stats = (opts.followSymlinks ? statSync : lstatSync)(path);
166
- } catch (err) {
167
- if (opts.strict) throw err;
168
- results.push({ path, err });
169
- }
170
- }
171
- results.push(build(dirent, path, stats, opts));
172
- }
173
- let recurse = false;
174
- if (isSymbolicLink) {
175
- if (!stats) try {
176
- stats = statSync(path);
177
- } catch {
178
- }
179
- if (stats && stats.isDirectory()) recurse = true;
180
- } else if (dirent.isDirectory()) {
181
- recurse = true;
182
- }
183
- if (recurse) results.push(...rrdirSync(path, opts, { includeMatcher, excludeMatcher, encoding }));
184
- }
185
- return results;
164
+ if (includeMatcher === void 0) {
165
+ opts = {
166
+ ...defaultOpts,
167
+ ...opts
168
+ };
169
+ ({includeMatcher, excludeMatcher} = makeMatchers(opts));
170
+ if (typeof dir === "string" && /[/\\]$/.test(dir)) dir = dir.substring(0, dir.length - 1);
171
+ encoding = getEncoding(dir);
172
+ }
173
+ const results = [];
174
+ let dirents = [];
175
+ try {
176
+ dirents = readdirSync(dir, {
177
+ encoding,
178
+ withFileTypes: true
179
+ });
180
+ } catch (err) {
181
+ if (opts.strict) throw err;
182
+ results.push({
183
+ path: dir,
184
+ err
185
+ });
186
+ }
187
+ if (!dirents.length) return results;
188
+ for (const dirent of dirents) {
189
+ const path = makePath(dirent, dir, encoding);
190
+ if (excludeMatcher?.(encoding === "buffer" ? toString(path) : path)) continue;
191
+ const isSymbolicLink = Boolean(opts.followSymlinks && dirent.isSymbolicLink());
192
+ const encodedPath = encoding === "buffer" ? toString(path) : path;
193
+ const isIncluded = !includeMatcher || includeMatcher(encodedPath);
194
+ let stats;
195
+ if (isIncluded) {
196
+ if (opts.stats || isSymbolicLink) try {
197
+ stats = (opts.followSymlinks ? statSync : lstatSync)(path);
198
+ } catch (err) {
199
+ if (opts.strict) throw err;
200
+ results.push({
201
+ path,
202
+ err
203
+ });
204
+ }
205
+ results.push(build(dirent, path, stats, opts));
206
+ }
207
+ let recurse = false;
208
+ if (isSymbolicLink) {
209
+ if (!stats) try {
210
+ stats = statSync(path);
211
+ } catch {}
212
+ if (stats?.isDirectory()) recurse = true;
213
+ } else if (dirent.isDirectory()) recurse = true;
214
+ if (recurse) results.push(...rrdirSync(path, opts, {
215
+ includeMatcher,
216
+ excludeMatcher,
217
+ encoding
218
+ }));
219
+ }
220
+ return results;
186
221
  }
187
222
 
188
- export { rrdir, rrdirAsync, rrdirSync };
223
+ //#endregion
224
+ export { rrdir, rrdirAsync, rrdirSync };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rrdir",
3
- "version": "14.0.0",
3
+ "version": "14.0.1",
4
4
  "description": "Recursive directory reader with a delightful API",
5
5
  "author": "silverwind <me@silverwind.io>",
6
6
  "repository": "silverwind/rrdir",
@@ -20,16 +20,16 @@
20
20
  "picomatch": "4.0.3"
21
21
  },
22
22
  "devDependencies": {
23
- "@types/node": "24.3.3",
23
+ "@types/node": "24.10.1",
24
24
  "@types/picomatch": "4.0.2",
25
- "eslint": "9.35.0",
26
- "eslint-config-silverwind": "103.0.1",
27
- "typescript-config-silverwind": "10.0.1",
28
- "updates": "16.7.2",
29
- "versions": "13.1.1",
30
- "vite": "7.1.5",
31
- "vite-config-silverwind": "5.4.0",
32
- "vitest": "3.2.4",
33
- "vitest-config-silverwind": "10.2.0"
25
+ "eslint": "9.39.1",
26
+ "eslint-config-silverwind": "111.0.5",
27
+ "tsdown": "0.16.3",
28
+ "tsdown-config-silverwind": "1.5.2",
29
+ "typescript-config-silverwind": "12.0.0",
30
+ "updates": "16.9.1",
31
+ "versions": "14.0.2",
32
+ "vitest": "4.0.8",
33
+ "vitest-config-silverwind": "10.4.2"
34
34
  }
35
35
  }
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAC,KAAK,EAAS,MAAM,SAAS,CAAC;AAC3C,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,WAAW,CAAC;AAQvC,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,QAAQ,CAAC;AACzC,MAAM,MAAM,GAAG,GAAG,MAAM,GAAG,UAAU,CAAC;AACtC,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,MAAM,CAAC;AAEhD,MAAM,MAAM,SAAS,GAAG;IACtB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,CAAC;AAEF,KAAK,YAAY,GAAG;IAClB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,KAAK,GAAG;IAClB,wIAAwI;IACxI,IAAI,EAAE,GAAG,CAAC;IACV,iFAAiF;IACjF,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,qFAAqF;IACrF,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,0IAA0I;IAC1I,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,8EAA8E;IAC9E,GAAG,CAAC,EAAE,KAAK,CAAC;CACb,CAAC;AAgDF,wBAAuB,KAAK,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,GAAE,SAAc,EAAE,EAAC,cAAc,EAAE,cAAc,EAAE,QAAQ,EAAC,GAAE,YAAiB,GAAG,cAAc,CAAC,KAAK,CAAC,CAkDjJ;AAED,wBAAsB,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,GAAE,SAAc,EAAE,EAAC,cAAc,EAAE,cAAc,EAAE,QAAQ,EAAC,GAAE,YAAiB,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC,CAqDhJ;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,GAAE,SAAc,EAAE,EAAC,cAAc,EAAE,cAAc,EAAE,QAAQ,EAAC,GAAE,YAAiB,GAAG,KAAK,EAAE,CAoDhI"}