@sfdxy/mule-lint 1.6.0 → 1.7.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 +2 -0
- package/dist/package.json +70 -0
- package/dist/src/core/YamlParser.d.ts +1 -0
- package/dist/src/core/YamlParser.d.ts.map +1 -1
- package/dist/src/core/YamlParser.js +38 -7
- package/dist/src/core/YamlParser.js.map +1 -1
- package/dist/src/formatters/HtmlFormatter.d.ts.map +1 -1
- package/dist/src/formatters/HtmlFormatter.js +26 -7
- package/dist/src/formatters/HtmlFormatter.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -281,6 +281,8 @@ Generates a modern, interactive single-page report with:
|
|
|
281
281
|
|
|
282
282
|
Built with **Tailwind CSS**, **Chart.js**, and **Tabulator**.
|
|
283
283
|
|
|
284
|
+

|
|
285
|
+
|
|
284
286
|
```bash
|
|
285
287
|
mule-lint src/main/mule -f html -o report.html
|
|
286
288
|
```
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@sfdxy/mule-lint",
|
|
3
|
+
"version": "1.7.0",
|
|
4
|
+
"description": "Static analysis tool for MuleSoft applications - supports humans, AI agents, and CI/CD pipelines",
|
|
5
|
+
"author": "Avinava",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"mulesoft",
|
|
9
|
+
"mule",
|
|
10
|
+
"lint",
|
|
11
|
+
"static-analysis",
|
|
12
|
+
"xml",
|
|
13
|
+
"sarif",
|
|
14
|
+
"cli"
|
|
15
|
+
],
|
|
16
|
+
"bin": {
|
|
17
|
+
"mule-lint": "./dist/bin/mule-lint.js"
|
|
18
|
+
},
|
|
19
|
+
"main": "./dist/index.js",
|
|
20
|
+
"types": "./dist/index.d.ts",
|
|
21
|
+
"files": [
|
|
22
|
+
"dist",
|
|
23
|
+
"README.md",
|
|
24
|
+
"LICENSE"
|
|
25
|
+
],
|
|
26
|
+
"scripts": {
|
|
27
|
+
"build": "tsc",
|
|
28
|
+
"build:watch": "tsc --watch",
|
|
29
|
+
"test": "jest",
|
|
30
|
+
"test:watch": "jest --watch",
|
|
31
|
+
"test:coverage": "jest --coverage",
|
|
32
|
+
"lint": "eslint src/ --ext .ts",
|
|
33
|
+
"lint:fix": "eslint src/ --ext .ts --fix",
|
|
34
|
+
"format": "prettier --write \"src/**/*.{ts,js,json,md}\"",
|
|
35
|
+
"clean": "rm -rf dist",
|
|
36
|
+
"prepublishOnly": "npm run clean && npm run build && npm test",
|
|
37
|
+
"release": "git tag v$(node -p 'require(\"./package.json\").version') && git push origin v$(node -p 'require(\"./package.json\").version')"
|
|
38
|
+
},
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"@xmldom/xmldom": "^0.8.10",
|
|
41
|
+
"chalk": "^4.1.2",
|
|
42
|
+
"commander": "^11.1.0",
|
|
43
|
+
"fast-glob": "^3.3.2",
|
|
44
|
+
"js-yaml": "^4.1.1",
|
|
45
|
+
"xpath": "^0.0.34"
|
|
46
|
+
},
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"@types/jest": "^29.5.11",
|
|
49
|
+
"@types/js-yaml": "^4.0.9",
|
|
50
|
+
"@types/node": "^20.19.27",
|
|
51
|
+
"@typescript-eslint/eslint-plugin": "^6.15.0",
|
|
52
|
+
"@typescript-eslint/parser": "^6.15.0",
|
|
53
|
+
"eslint": "^8.56.0",
|
|
54
|
+
"jest": "^29.7.0",
|
|
55
|
+
"prettier": "^3.7.4",
|
|
56
|
+
"ts-jest": "^29.1.1",
|
|
57
|
+
"typescript": "^5.3.3"
|
|
58
|
+
},
|
|
59
|
+
"engines": {
|
|
60
|
+
"node": ">=18.0.0"
|
|
61
|
+
},
|
|
62
|
+
"repository": {
|
|
63
|
+
"type": "git",
|
|
64
|
+
"url": "https://github.com/Avinava/mule-lint.git"
|
|
65
|
+
},
|
|
66
|
+
"bugs": {
|
|
67
|
+
"url": "https://github.com/Avinava/mule-lint/issues"
|
|
68
|
+
},
|
|
69
|
+
"homepage": "https://github.com/Avinava/mule-lint#readme"
|
|
70
|
+
}
|
|
@@ -24,6 +24,7 @@ export declare class YamlParser {
|
|
|
24
24
|
static isEncryptedValue(value: unknown): boolean;
|
|
25
25
|
/**
|
|
26
26
|
* Check if a key name suggests it contains sensitive data
|
|
27
|
+
* Uses word-boundary matching to avoid false positives
|
|
27
28
|
*/
|
|
28
29
|
static isSensitiveKey(key: string): boolean;
|
|
29
30
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"YamlParser.d.ts","sourceRoot":"","sources":["../../../src/core/YamlParser.ts"],"names":[],"mappings":"AAIA;;GAEG;AACH,qBAAa,UAAU;IACnB;;OAEG;IACH,MAAM,CAAC,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IASlE;;OAEG;IACH,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAQ7D;;OAEG;IACH,MAAM,CAAC,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAK5C;;OAEG;IACH,MAAM,CAAC,UAAU,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,SAAK,GAAG,MAAM,EAAE;IAiBtE;;OAEG;IACH,MAAM,CAAC,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO;IAMhD
|
|
1
|
+
{"version":3,"file":"YamlParser.d.ts","sourceRoot":"","sources":["../../../src/core/YamlParser.ts"],"names":[],"mappings":"AAIA;;GAEG;AACH,qBAAa,UAAU;IACnB;;OAEG;IACH,MAAM,CAAC,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IASlE;;OAEG;IACH,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAQ7D;;OAEG;IACH,MAAM,CAAC,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAK5C;;OAEG;IACH,MAAM,CAAC,UAAU,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,SAAK,GAAG,MAAM,EAAE;IAiBtE;;OAEG;IACH,MAAM,CAAC,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO;IAMhD;;;OAGG;IACH,MAAM,CAAC,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;CAgD9C"}
|
|
@@ -99,21 +99,52 @@ class YamlParser {
|
|
|
99
99
|
}
|
|
100
100
|
/**
|
|
101
101
|
* Check if a key name suggests it contains sensitive data
|
|
102
|
+
* Uses word-boundary matching to avoid false positives
|
|
102
103
|
*/
|
|
103
104
|
static isSensitiveKey(key) {
|
|
104
|
-
const
|
|
105
|
+
const lowerKey = key.toLowerCase();
|
|
106
|
+
// Patterns that indicate a secret - must be at word boundary (end of key or before .)
|
|
107
|
+
const secretKeyEndings = [
|
|
105
108
|
'password',
|
|
109
|
+
'passwd',
|
|
106
110
|
'secret',
|
|
107
111
|
'apikey',
|
|
108
112
|
'api-key',
|
|
109
113
|
'api_key',
|
|
110
|
-
'
|
|
111
|
-
'
|
|
112
|
-
'
|
|
113
|
-
'
|
|
114
|
+
'accesstoken',
|
|
115
|
+
'access-token',
|
|
116
|
+
'access_token',
|
|
117
|
+
'refreshtoken',
|
|
118
|
+
'refresh-token',
|
|
119
|
+
'refresh_token',
|
|
120
|
+
'clientsecret',
|
|
121
|
+
'client-secret',
|
|
122
|
+
'client_secret',
|
|
123
|
+
'privatekey',
|
|
124
|
+
'private-key',
|
|
125
|
+
'private_key',
|
|
126
|
+
'credentials',
|
|
127
|
+
'authtoken',
|
|
128
|
+
'auth-token',
|
|
129
|
+
'auth_token',
|
|
130
|
+
'bearertoken',
|
|
131
|
+
'bearer-token',
|
|
132
|
+
'bearer_token',
|
|
133
|
+
'consumerkey',
|
|
134
|
+
'consumer-key',
|
|
135
|
+
'consumer_key',
|
|
136
|
+
'consumersecret',
|
|
137
|
+
'consumer-secret',
|
|
138
|
+
'consumer_secret',
|
|
139
|
+
'tokensecret',
|
|
140
|
+
'token-secret',
|
|
141
|
+
'token_secret',
|
|
114
142
|
];
|
|
115
|
-
|
|
116
|
-
|
|
143
|
+
// Get the last segment of the key (after the last .)
|
|
144
|
+
const segments = lowerKey.split('.');
|
|
145
|
+
const lastSegment = segments[segments.length - 1];
|
|
146
|
+
// Check if the last segment matches any secret pattern
|
|
147
|
+
return secretKeyEndings.some(pattern => lastSegment === pattern || lastSegment.endsWith(pattern));
|
|
117
148
|
}
|
|
118
149
|
}
|
|
119
150
|
exports.YamlParser = YamlParser;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"YamlParser.js","sourceRoot":"","sources":["../../../src/core/YamlParser.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,8CAAgC;AAChC,uCAAyB;AACzB,2CAA6B;AAE7B;;GAEG;AACH,MAAa,UAAU;IACnB;;OAEG;IACH,MAAM,CAAC,SAAS,CAAC,QAAgB;QAC7B,IAAI,CAAC;YACD,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;YAClD,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAA4B,CAAC;QACzD,CAAC;QAAC,MAAM,CAAC;YACL,OAAO,IAAI,CAAC;QAChB,CAAC;IACL,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,KAAK,CAAC,OAAe;QACxB,IAAI,CAAC;YACD,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAA4B,CAAC;QACzD,CAAC;QAAC,MAAM,CAAC;YACL,OAAO,IAAI,CAAC;QAChB,CAAC;IACL,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,UAAU,CAAC,QAAgB;QAC9B,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC;QACjD,OAAO,GAAG,KAAK,OAAO,IAAI,GAAG,KAAK,MAAM,CAAC;IAC7C,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,UAAU,CAAC,GAA4B,EAAE,MAAM,GAAG,EAAE;QACvD,MAAM,IAAI,GAAa,EAAE,CAAC;QAE1B,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YACjC,MAAM,OAAO,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,IAAI,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC;YAClD,MAAM,KAAK,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC;YAEvB,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;gBACvE,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,KAAgC,EAAE,OAAO,CAAC,CAAC,CAAC;YAC7E,CAAC;iBAAM,CAAC;gBACJ,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACvB,CAAC;QACL,CAAC;QAED,OAAO,IAAI,CAAC;IAChB,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,gBAAgB,CAAC,KAAc;QAClC,IAAI,OAAO,KAAK,KAAK,QAAQ;YAAE,OAAO,KAAK,CAAC;QAC5C,8CAA8C;QAC9C,OAAO,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACnC,CAAC;IAED
|
|
1
|
+
{"version":3,"file":"YamlParser.js","sourceRoot":"","sources":["../../../src/core/YamlParser.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HtmlFormatter.d.ts","sourceRoot":"","sources":["../../../src/formatters/HtmlFormatter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"HtmlFormatter.d.ts","sourceRoot":"","sources":["../../../src/formatters/HtmlFormatter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAI7C;;GAEG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CA6mBrD"}
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
exports.formatHtml = formatHtml;
|
|
4
7
|
const rules_1 = require("../rules");
|
|
8
|
+
const package_json_1 = __importDefault(require("../../package.json"));
|
|
5
9
|
/**
|
|
6
10
|
* Format lint report as a modern, interactive HTML Single Page Application
|
|
7
11
|
*/
|
|
@@ -24,9 +28,9 @@ function formatHtml(report) {
|
|
|
24
28
|
const clientData = {
|
|
25
29
|
metadata: {
|
|
26
30
|
timestamp: report.timestamp,
|
|
27
|
-
version:
|
|
31
|
+
version: package_json_1.default.version,
|
|
28
32
|
filesScanned: report.files.length,
|
|
29
|
-
duration: 0
|
|
33
|
+
duration: report.durationMs || 0
|
|
30
34
|
},
|
|
31
35
|
summary: report.summary,
|
|
32
36
|
files: enrichedFiles,
|
|
@@ -298,7 +302,10 @@ function formatHtml(report) {
|
|
|
298
302
|
<!-- Top Rules -->
|
|
299
303
|
<div class="lg:col-span-2 bg-white rounded-xl shadow-sm border border-gray-100 p-6">
|
|
300
304
|
<div class="flex items-center justify-between mb-6">
|
|
301
|
-
<
|
|
305
|
+
<div>
|
|
306
|
+
<h3 class="text-lg font-semibold text-gray-800">Top 5 Violated Rules</h3>
|
|
307
|
+
<p class="text-sm text-gray-500 mt-1">Most frequently triggered lint rules</p>
|
|
308
|
+
</div>
|
|
302
309
|
</div>
|
|
303
310
|
<div class="chart-container">
|
|
304
311
|
<canvas id="chart-top-rules"></canvas>
|
|
@@ -308,7 +315,10 @@ function formatHtml(report) {
|
|
|
308
315
|
<!-- Severity Distribution -->
|
|
309
316
|
<div class="bg-white rounded-xl shadow-sm border border-gray-100 p-6">
|
|
310
317
|
<div class="flex items-center justify-between mb-6">
|
|
311
|
-
<
|
|
318
|
+
<div>
|
|
319
|
+
<h3 class="text-lg font-semibold text-gray-800">Severity Breakdown</h3>
|
|
320
|
+
<p class="text-sm text-gray-500 mt-1">Distribution by issue type</p>
|
|
321
|
+
</div>
|
|
312
322
|
</div>
|
|
313
323
|
<div class="chart-container flex items-center justify-center">
|
|
314
324
|
<canvas id="chart-severity"></canvas>
|
|
@@ -319,7 +329,10 @@ function formatHtml(report) {
|
|
|
319
329
|
<!-- Categories Section -->
|
|
320
330
|
<div class="bg-white rounded-xl shadow-sm border border-gray-100 p-6">
|
|
321
331
|
<div class="flex items-center justify-between mb-6">
|
|
322
|
-
<
|
|
332
|
+
<div>
|
|
333
|
+
<h3 class="text-lg font-semibold text-gray-800">Issues by Category</h3>
|
|
334
|
+
<p class="text-sm text-gray-500 mt-1">Grouped by rule category</p>
|
|
335
|
+
</div>
|
|
323
336
|
<button onclick="router.navigate('issues')" class="text-sm text-brand-600 hover:text-brand-900 font-medium">View All Issues →</button>
|
|
324
337
|
</div>
|
|
325
338
|
<div class="h-[300px] w-full relative">
|
|
@@ -469,11 +482,17 @@ function formatHtml(report) {
|
|
|
469
482
|
}
|
|
470
483
|
});
|
|
471
484
|
|
|
472
|
-
// Categories (Bar)
|
|
485
|
+
// Categories (Bar) - Colorful
|
|
473
486
|
const catCounts = {};
|
|
474
487
|
allIssues.forEach(i => catCounts[i.category] = (catCounts[i.category] || 0) + 1);
|
|
475
488
|
const sortedCats = Object.entries(catCounts).sort((a,b) => b[1] - a[1]);
|
|
476
489
|
|
|
490
|
+
// Color palette for categories
|
|
491
|
+
const categoryColors = [
|
|
492
|
+
'#0ea5e9', '#8b5cf6', '#10b981', '#f59e0b', '#ef4444',
|
|
493
|
+
'#ec4899', '#06b6d4', '#84cc16', '#f97316', '#6366f1'
|
|
494
|
+
];
|
|
495
|
+
|
|
477
496
|
new Chart(document.getElementById('chart-categories'), {
|
|
478
497
|
type: 'bar',
|
|
479
498
|
data: {
|
|
@@ -481,7 +500,7 @@ function formatHtml(report) {
|
|
|
481
500
|
datasets: [{
|
|
482
501
|
label: 'Issues',
|
|
483
502
|
data: sortedCats.map(x => x[1]),
|
|
484
|
-
backgroundColor:
|
|
503
|
+
backgroundColor: sortedCats.map((_, i) => categoryColors[i % categoryColors.length]),
|
|
485
504
|
borderRadius: 4,
|
|
486
505
|
barThickness: 20
|
|
487
506
|
}]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HtmlFormatter.js","sourceRoot":"","sources":["../../../src/formatters/HtmlFormatter.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"HtmlFormatter.js","sourceRoot":"","sources":["../../../src/formatters/HtmlFormatter.ts"],"names":[],"mappings":";;;;;AAOA,gCA6mBC;AAnnBD,oCAAqC;AACrC,sEAA6C;AAE7C;;GAEG;AACH,SAAgB,UAAU,CAAC,MAAkB;IACzC,iBAAiB;IACjB,MAAM,aAAa,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC5C,GAAG,IAAI;QACP,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE;YAC5B,MAAM,OAAO,GAAG,iBAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,KAAK,CAAC,MAAM,CAAC,CAAC;YAC3D,OAAO;gBACH,GAAG,KAAK;gBACR,QAAQ,EAAE,OAAO,EAAE,QAAQ,IAAI,SAAS;gBACxC,eAAe,EAAE,OAAO,EAAE,WAAW,IAAI,0BAA0B;gBACnE,QAAQ,EAAE,OAAO,EAAE,IAAI,IAAI,KAAK,CAAC,MAAM;gBACvC,IAAI,EAAE,IAAI,CAAC,YAAY;aAC1B,CAAC;QACN,CAAC,CAAC;KACL,CAAC,CAAC,CAAC;IAEJ,yCAAyC;IACzC,MAAM,UAAU,GAAG;QACf,QAAQ,EAAE;YACN,SAAS,EAAE,MAAM,CAAC,SAAS;YAC3B,OAAO,EAAE,sBAAW,CAAC,OAAO;YAC5B,YAAY,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM;YACjC,QAAQ,EAAE,MAAM,CAAC,UAAU,IAAI,CAAC;SACnC;QACD,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,KAAK,EAAE,aAAa;QACpB,KAAK,EAAE,iBAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;KACtG,CAAC;IAEF,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IAExE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAuJD,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAsbb,CAAC;AACT,CAAC"}
|