@jacraig/woodchuck 1.0.4 → 1.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/README.md +34 -0
- package/lib/Logger.cjs.js +36 -0
- package/lib/Logger.esm.js +35 -1
- package/lib/Logger.umd.js +36 -0
- package/lib/Logger.umd.min.js +1 -1
- package/lib/declarations/BatchedSink.d.ts +13 -0
- package/lib/declarations/BatchedSink.d.ts.map +1 -0
- package/lib/declarations/BatchedSinkOptions.d.ts +6 -0
- package/lib/declarations/BatchedSinkOptions.d.ts.map +1 -0
- package/lib/declarations/Logger.d.ts +3 -1
- package/lib/declarations/Logger.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -7,9 +7,15 @@ WoodChuck is a versatile logging library for TypeScript/JavaScript that simplifi
|
|
|
7
7
|
## Features
|
|
8
8
|
|
|
9
9
|
- **Easy Integration**: Simple setup for quick integration into your projects.
|
|
10
|
+
|
|
10
11
|
- **Customizable Logging Levels**: Define and use different logging levels to categorize and filter messages.
|
|
12
|
+
|
|
11
13
|
- **Extensible Plugins**: Extend functionality with plugins for various output formats and destinations.
|
|
12
14
|
|
|
15
|
+
- **Structured Logging**: Log structured event data to make it easier to analyze and understand.
|
|
16
|
+
|
|
17
|
+
- **Flexible Configuration**: Configure the logger with a fluent interface to customize the logging experience.
|
|
18
|
+
|
|
13
19
|
## Installation
|
|
14
20
|
|
|
15
21
|
```bash
|
|
@@ -48,3 +54,31 @@ Logger.fatal("This is a fatal message: {key}", { "key": "value" }, new Error("Th
|
|
|
48
54
|
|
|
49
55
|
```typescript
|
|
50
56
|
|
|
57
|
+
Logger.configure()
|
|
58
|
+
.enrichWith(new UserAgentEnricher())
|
|
59
|
+
.enrichWith(new UrlEnricher())
|
|
60
|
+
.enrichWith(new CallerEnricher())
|
|
61
|
+
.formatUsing(new DefaultFormatter())
|
|
62
|
+
.minimumLevel("Information")
|
|
63
|
+
.writeTo(new ConsoleSink());
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
4. Or build your own plugins:
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
|
|
70
|
+
import { LogEventEnricher, LogEvent } from '@jacraig/woodchuck';
|
|
71
|
+
|
|
72
|
+
export class MyCustomPlugin implements LogEventEnricher {
|
|
73
|
+
public enrich(logEvent: LogEvent): void {
|
|
74
|
+
logEvent.properties["myProperty"] = "Something, something, something, dark side";
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
# Contributing
|
|
81
|
+
If you'd like to contribute to WoodChuck, please follow our [contribution guidelines](https://github.com/JaCraig/Woodchuck/blob/main/CONTRIBUTING.md).
|
|
82
|
+
|
|
83
|
+
# License
|
|
84
|
+
WoodChuck is licensed under the [Apache 2 License](https://github.com/JaCraig/Woodchuck/blob/main/LICENSE).
|
package/lib/Logger.cjs.js
CHANGED
|
@@ -180,6 +180,40 @@ class UrlEnricher {
|
|
|
180
180
|
}
|
|
181
181
|
}
|
|
182
182
|
|
|
183
|
+
class BatchedSink {
|
|
184
|
+
constructor(sink, options) {
|
|
185
|
+
this.buffer = [];
|
|
186
|
+
this.sink = sink;
|
|
187
|
+
this.options = options;
|
|
188
|
+
this.timer = setInterval(() => this.flush(), this.options.maxWaitTime);
|
|
189
|
+
this.buffer = JSON.parse(this.options.storage.getItem("logBuffer") || "[]");
|
|
190
|
+
}
|
|
191
|
+
flush() {
|
|
192
|
+
if (this.buffer.length == 0) {
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
for (let event of this.buffer) {
|
|
196
|
+
this.sink.write(event);
|
|
197
|
+
}
|
|
198
|
+
this.buffer = [];
|
|
199
|
+
}
|
|
200
|
+
write(event) {
|
|
201
|
+
this.buffer.push(event);
|
|
202
|
+
this.options.storage.setItem("logBuffer", JSON.stringify(this.buffer));
|
|
203
|
+
if (this.buffer.length >= this.options.maxBatchSize) {
|
|
204
|
+
this.flush();
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
class BatchedSinkOptions {
|
|
210
|
+
constructor() {
|
|
211
|
+
this.maxBatchSize = 10;
|
|
212
|
+
this.maxWaitTime = 500;
|
|
213
|
+
this.storage = localStorage;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
183
217
|
class Logger {
|
|
184
218
|
constructor() { }
|
|
185
219
|
static configure() {
|
|
@@ -210,6 +244,8 @@ class Logger {
|
|
|
210
244
|
}
|
|
211
245
|
}
|
|
212
246
|
|
|
247
|
+
exports.BatchedSink = BatchedSink;
|
|
248
|
+
exports.BatchedSinkOptions = BatchedSinkOptions;
|
|
213
249
|
exports.CallerEnricher = CallerEnricher;
|
|
214
250
|
exports.ConsoleSink = ConsoleSink;
|
|
215
251
|
exports.DefaultFormatter = DefaultFormatter;
|
package/lib/Logger.esm.js
CHANGED
|
@@ -178,6 +178,40 @@ class UrlEnricher {
|
|
|
178
178
|
}
|
|
179
179
|
}
|
|
180
180
|
|
|
181
|
+
class BatchedSink {
|
|
182
|
+
constructor(sink, options) {
|
|
183
|
+
this.buffer = [];
|
|
184
|
+
this.sink = sink;
|
|
185
|
+
this.options = options;
|
|
186
|
+
this.timer = setInterval(() => this.flush(), this.options.maxWaitTime);
|
|
187
|
+
this.buffer = JSON.parse(this.options.storage.getItem("logBuffer") || "[]");
|
|
188
|
+
}
|
|
189
|
+
flush() {
|
|
190
|
+
if (this.buffer.length == 0) {
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
for (let event of this.buffer) {
|
|
194
|
+
this.sink.write(event);
|
|
195
|
+
}
|
|
196
|
+
this.buffer = [];
|
|
197
|
+
}
|
|
198
|
+
write(event) {
|
|
199
|
+
this.buffer.push(event);
|
|
200
|
+
this.options.storage.setItem("logBuffer", JSON.stringify(this.buffer));
|
|
201
|
+
if (this.buffer.length >= this.options.maxBatchSize) {
|
|
202
|
+
this.flush();
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
class BatchedSinkOptions {
|
|
208
|
+
constructor() {
|
|
209
|
+
this.maxBatchSize = 10;
|
|
210
|
+
this.maxWaitTime = 500;
|
|
211
|
+
this.storage = localStorage;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
181
215
|
class Logger {
|
|
182
216
|
constructor() { }
|
|
183
217
|
static configure() {
|
|
@@ -208,4 +242,4 @@ class Logger {
|
|
|
208
242
|
}
|
|
209
243
|
}
|
|
210
244
|
|
|
211
|
-
export { CallerEnricher, ConsoleSink, DefaultFormatter, LogSinkPipeline, Logger, LoggerConfiguration, MinimumLevelLogFilter, UrlEnricher, UserAgentEnricher };
|
|
245
|
+
export { BatchedSink, BatchedSinkOptions, CallerEnricher, ConsoleSink, DefaultFormatter, LogSinkPipeline, Logger, LoggerConfiguration, MinimumLevelLogFilter, UrlEnricher, UserAgentEnricher };
|
package/lib/Logger.umd.js
CHANGED
|
@@ -184,6 +184,40 @@
|
|
|
184
184
|
}
|
|
185
185
|
}
|
|
186
186
|
|
|
187
|
+
class BatchedSink {
|
|
188
|
+
constructor(sink, options) {
|
|
189
|
+
this.buffer = [];
|
|
190
|
+
this.sink = sink;
|
|
191
|
+
this.options = options;
|
|
192
|
+
this.timer = setInterval(() => this.flush(), this.options.maxWaitTime);
|
|
193
|
+
this.buffer = JSON.parse(this.options.storage.getItem("logBuffer") || "[]");
|
|
194
|
+
}
|
|
195
|
+
flush() {
|
|
196
|
+
if (this.buffer.length == 0) {
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
for (let event of this.buffer) {
|
|
200
|
+
this.sink.write(event);
|
|
201
|
+
}
|
|
202
|
+
this.buffer = [];
|
|
203
|
+
}
|
|
204
|
+
write(event) {
|
|
205
|
+
this.buffer.push(event);
|
|
206
|
+
this.options.storage.setItem("logBuffer", JSON.stringify(this.buffer));
|
|
207
|
+
if (this.buffer.length >= this.options.maxBatchSize) {
|
|
208
|
+
this.flush();
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
class BatchedSinkOptions {
|
|
214
|
+
constructor() {
|
|
215
|
+
this.maxBatchSize = 10;
|
|
216
|
+
this.maxWaitTime = 500;
|
|
217
|
+
this.storage = localStorage;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
187
221
|
class Logger {
|
|
188
222
|
constructor() { }
|
|
189
223
|
static configure() {
|
|
@@ -214,6 +248,8 @@
|
|
|
214
248
|
}
|
|
215
249
|
}
|
|
216
250
|
|
|
251
|
+
exports.BatchedSink = BatchedSink;
|
|
252
|
+
exports.BatchedSinkOptions = BatchedSinkOptions;
|
|
217
253
|
exports.CallerEnricher = CallerEnricher;
|
|
218
254
|
exports.ConsoleSink = ConsoleSink;
|
|
219
255
|
exports.DefaultFormatter = DefaultFormatter;
|
package/lib/Logger.umd.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).woodchuck={})}(this,(function(e){"use strict";class t{constructor(){this.styles={Verbose:"color: white;",Debug:"color: green",Information:"color: blue",Warning:"color: yellow",Error:"color: red",Fatal:"color: palevioletred"},this.consoleMethods={Verbose:(e,t,
|
|
1
|
+
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).woodchuck={})}(this,(function(e){"use strict";class t{constructor(){this.styles={Verbose:"color: white;",Debug:"color: green",Information:"color: blue",Warning:"color: yellow",Error:"color: red",Fatal:"color: palevioletred"},this.consoleMethods={Verbose:(e,t,i)=>{console.log(e,t,i)},Debug:(e,t,i)=>{console.debug(e,t,i)},Information:(e,t,i)=>{console.info(e,t,i)},Warning:(e,t,i)=>{console.warn(e,t,i)},Error:(e,t,i)=>{console.error(e,t,i)},Fatal:(e,t,i)=>{console.error(e,t,i)}}}write(e){let t=e.args&&"object"!=typeof e.args,i=e.args&&"object"==typeof e.args;this.consoleMethods[e.level]("%c"+e.message,this.styles[e.level],t?e.args:""),i&&console.table(e.args)}}class i{constructor(e){this.outputFormat=e??"[{Timestamp}]\t[{Level}]\t{Message}{Exception}"}format(e){return this.outputFormat.replace(/{(\w+)}/g,((t,i)=>"Timestamp"===i?e.timestamp.toISOString():"Level"===i?e.level:"Message"===i?e.message:"Exception"===i?e.exception?"\n"+e.exception.stack:"":e.properties[i]))}}class s{constructor(e="Debug"){this.allowedLevels=["Verbose","Debug","Information","Warning","Error","Fatal"],this.minimumLevel=e,this.allowedLevels=this.allowedLevels.slice(this.allowedLevels.indexOf(e))}filter(e){return this.allowedLevels.indexOf(e.level)>=0}}class r{constructor(e){this.sink=new t,this.filters=[],this.formatter=new i,this.enrichers=[],this.loggerConfiguration=e}writeTo(e){return this.sink=e,this.loggerConfiguration}minimumLevel(e){return this.filters.push(new s(e)),this}filter(e){return this.filters.push(e),this}formatUsing(e){return this.formatter=e,this}enrichWith(e){return this.enrichers.push(e),this}process(e){this.formatter??=new i,this.sink??=new t;let s=Object.assign({},e);this.filters.some((e=>e.filter(s)))&&(this.enrichers.forEach((e=>e.enrich(s))),s.message=this.formatter.format(s)||s.message,this.sink.write(s))}}class o{constructor(){this.pipelines=[]}writeTo(e){let t=new r(this);return this.pipelines.push(t),t.writeTo(e)}minimumLevel(e){let t=new r(this);return this.pipelines.push(t),t.minimumLevel(e)}filter(e){let t=new r(this);return this.pipelines.push(t),t.filter(e)}formatUsing(e){let t=new r(this);return this.pipelines.push(t),t.formatUsing(e)}enrichWith(e){let t=new r(this);return this.pipelines.push(t),t.enrichWith(e)}write(e,t,i,s){let r={level:e,message:t,properties:{},exception:s,timestamp:new Date,args:i};this.pipelines.forEach((e=>e.process(r)))}}class n{constructor(){}static configure(){return this.loggerConfiguration??=globalThis.LoggerConfiguration||new o,globalThis.LoggerConfiguration=this.loggerConfiguration,this.loggerConfiguration}static write(e,t,i,s){n.configure().write(e,t,i,s)}static verbose(e,t){this.write("Verbose",e,t)}static debug(e,t){this.write("Debug",e,t)}static information(e,t){this.write("Information",e,t)}static warning(e,t){this.write("Warning",e,t)}static error(e,t,i){this.write("Error",e,t,i)}static fatal(e,t,i){this.write("Fatal",e,t,i)}}e.BatchedSink=class{constructor(e,t){this.buffer=[],this.sink=e,this.options=t,this.timer=setInterval((()=>this.flush()),this.options.maxWaitTime),this.buffer=JSON.parse(this.options.storage.getItem("logBuffer")||"[]")}flush(){if(0!=this.buffer.length){for(let e of this.buffer)this.sink.write(e);this.buffer=[]}}write(e){this.buffer.push(e),this.options.storage.setItem("logBuffer",JSON.stringify(this.buffer)),this.buffer.length>=this.options.maxBatchSize&&this.flush()}},e.BatchedSinkOptions=class{constructor(){this.maxBatchSize=10,this.maxWaitTime=500,this.storage=localStorage}},e.CallerEnricher=class{enrich(e){e.properties??={};let t=this.matchAll((new Error).stack?.toString()??"",/at([\s\w\d\.$]+)[\(]?((http|https|ftp)[^\)\n]+)[\)]?/gi).map((e=>e[2].trim()));e.properties.caller=t[t.length-1]}matchAll(e,t){const i=t.global?t.flags:t.flags+"g",s=new RegExp(t,i);let r,o=[];for(;r=s.exec(e);)o.push(r);return o}},e.ConsoleSink=t,e.DefaultFormatter=i,e.LogSinkPipeline=r,e.Logger=n,e.LoggerConfiguration=o,e.MinimumLevelLogFilter=s,e.UrlEnricher=class{enrich(e){e.properties??={},e.properties.url=window.location.href}},e.UserAgentEnricher=class{enrich(e){e.properties??={},e.properties.userAgent=navigator.userAgent}}}));
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { BatchedSinkOptions } from "./BatchedSinkOptions";
|
|
2
|
+
import { LogEvent } from "./LogEvent";
|
|
3
|
+
import { LogSink } from "./LogSink";
|
|
4
|
+
export declare class BatchedSink implements LogSink {
|
|
5
|
+
constructor(sink: LogSink, options: BatchedSinkOptions);
|
|
6
|
+
private buffer;
|
|
7
|
+
private sink;
|
|
8
|
+
private options;
|
|
9
|
+
private timer;
|
|
10
|
+
private flush;
|
|
11
|
+
write(event: LogEvent): void;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=BatchedSink.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BatchedSink.d.ts","sourceRoot":"","sources":["../../src/BatchedSink.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGpC,qBAAa,WAAY,YAAW,OAAO;gBAEpB,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,kBAAkB;IAQ7D,OAAO,CAAC,MAAM,CAAkB;IAGhC,OAAO,CAAC,IAAI,CAAU;IAGtB,OAAO,CAAC,OAAO,CAAqB;IAGpC,OAAO,CAAC,KAAK,CAAS;IAGtB,OAAO,CAAC,KAAK;IAYN,KAAK,CAAC,KAAK,EAAE,QAAQ,GAAG,IAAI;CAOtC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BatchedSinkOptions.d.ts","sourceRoot":"","sources":["../../src/BatchedSinkOptions.ts"],"names":[],"mappings":"AACA,qBAAa,kBAAkB;IAEpB,YAAY,EAAE,MAAM,CAAM;IAG1B,WAAW,EAAE,MAAM,CAAO;IAG1B,OAAO,EAAE,OAAO,CAAgB;CAC1C"}
|
|
@@ -12,6 +12,8 @@ import { MinimumLevelLogFilter } from "./MinimumLevelLogFilter";
|
|
|
12
12
|
import { CallerEnricher } from "./CallerEnricher";
|
|
13
13
|
import { UserAgentEnricher } from "./UserAgentEnricher";
|
|
14
14
|
import { UrlEnricher } from "./UrlEnricher";
|
|
15
|
+
import { BatchedSink } from "./BatchedSink";
|
|
16
|
+
import { BatchedSinkOptions } from "./BatchedSinkOptions";
|
|
15
17
|
declare class Logger {
|
|
16
18
|
private constructor();
|
|
17
19
|
private static loggerConfiguration;
|
|
@@ -38,5 +40,5 @@ declare class Logger {
|
|
|
38
40
|
[key: string]: any;
|
|
39
41
|
}, exception?: Error): void;
|
|
40
42
|
}
|
|
41
|
-
export { Logger, LogLevel, LogEvent, LogEventEnricher, LogFilter, OutputFormatter, DefaultFormatter, LogSink, ConsoleSink, LogSinkPipeline, LoggerConfiguration, UrlEnricher, UserAgentEnricher, CallerEnricher, MinimumLevelLogFilter };
|
|
43
|
+
export { Logger, LogLevel, LogEvent, LogEventEnricher, LogFilter, OutputFormatter, DefaultFormatter, LogSink, ConsoleSink, LogSinkPipeline, LoggerConfiguration, UrlEnricher, UserAgentEnricher, CallerEnricher, MinimumLevelLogFilter, BatchedSink, BatchedSinkOptions };
|
|
42
44
|
//# sourceMappingURL=Logger.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Logger.d.ts","sourceRoot":"","sources":["../../src/Logger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"Logger.d.ts","sourceRoot":"","sources":["../../src/Logger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAQ1D,cAAM,MAAM;IAER,OAAO;IAGP,OAAO,CAAC,MAAM,CAAC,mBAAmB,CAAsB;WAG1C,SAAS,IAAI,mBAAmB;WAWhC,KAAK,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;KAAE,EAAE,SAAS,CAAC,EAAE,KAAK,GAAG,IAAI;WAOrG,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;KAAE,GAAG,IAAI;WAOnE,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;KAAE,GAAG,IAAI;WAOjE,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;KAAE,GAAG,IAAI;WAOvE,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;KAAE,GAAG,IAAI;WAQnE,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;KAAE,EAAE,SAAS,CAAC,EAAE,KAAK,GAAG,IAAI;WAQpF,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;KAAE,EAAE,SAAS,CAAC,EAAE,KAAK,GAAG,IAAI;CAGrG;AAED,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,gBAAgB,EAAE,SAAS,EAAE,eAAe,EAAE,gBAAgB,EAAE,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,mBAAmB,EAAE,WAAW,EAAE,iBAAiB,EAAE,cAAc,EAAE,qBAAqB,EAAE,WAAW,EAAE,kBAAkB,EAAE,CAAC"}
|