@conduction/nextcloud-vue 2.82.0 → 2.83.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/dist/esm/components/CnActionsBar/CnActionsBar.vue2.js +2 -2
- package/dist/esm/components/CnActionsBar/CnActionsBar.vue2.js.map +1 -1
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue.js +1 -1
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue2.js +24 -0
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue2.js.map +1 -1
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue3.js +9 -4
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue3.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue.js +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js +9 -0
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +96 -12
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +95 -50
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
- package/dist/esm/components/CnMassActionBar/CnMassActionBar.vue2.js +2 -2
- package/dist/esm/components/CnMassActionBar/CnMassActionBar.vue2.js.map +1 -1
- package/dist/esm/components/CnMassImportDialog/CnMassImportDialog.vue2.js +2 -2
- package/dist/esm/components/CnMassImportDialog/CnMassImportDialog.vue2.js.map +1 -1
- package/dist/esm/components/CnRadioCardsWidget/CnRadioCardsWidget.vue.js +1 -1
- package/dist/esm/components/CnRadioCardsWidget/CnRadioCardsWidget.vue2.js +16 -2
- package/dist/esm/components/CnRadioCardsWidget/CnRadioCardsWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnRadioCardsWidget/CnRadioCardsWidget.vue3.js +3 -3
- package/dist/esm/components/CnRadioCardsWidget/CnRadioCardsWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnReportsPage/CnReportsPage.vue.js +1 -1
- package/dist/esm/components/CnReportsPage/CnReportsPage.vue2.js +43 -0
- package/dist/esm/components/CnReportsPage/CnReportsPage.vue2.js.map +1 -1
- package/dist/esm/components/CnReportsPage/CnReportsPage.vue3.js +130 -53
- package/dist/esm/components/CnReportsPage/CnReportsPage.vue3.js.map +1 -1
- package/dist/esm/components/CnSettingsFormWidget/CnSettingsFormWidget.vue.js +1 -1
- package/dist/esm/components/CnSettingsFormWidget/CnSettingsFormWidget.vue2.js +70 -5
- package/dist/esm/components/CnSettingsFormWidget/CnSettingsFormWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnSettingsFormWidget/CnSettingsFormWidget.vue3.js +61 -35
- package/dist/esm/components/CnSettingsFormWidget/CnSettingsFormWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnStatWidget/CnStatWidget.vue.js +1 -1
- package/dist/esm/components/CnStatWidget/CnStatWidget.vue2.js +3 -1
- package/dist/esm/components/CnStatWidget/CnStatWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnStatWidget/CnStatWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnStatsBlockWidget/CnStatsBlockWidget.vue.js +1 -1
- package/dist/esm/components/CnStatsBlockWidget/CnStatsBlockWidget.vue2.js +55 -3
- package/dist/esm/components/CnStatsBlockWidget/CnStatsBlockWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnStatsBlockWidget/CnStatsBlockWidget.vue3.js +88 -71
- package/dist/esm/components/CnStatsBlockWidget/CnStatsBlockWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnSwitchRowsWidget/CnSwitchRowsWidget.vue.js +1 -1
- package/dist/esm/components/CnSwitchRowsWidget/CnSwitchRowsWidget.vue2.js +18 -4
- package/dist/esm/components/CnSwitchRowsWidget/CnSwitchRowsWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnSwitchRowsWidget/CnSwitchRowsWidget.vue3.js.map +1 -1
- package/dist/esm/l10n/nl.json.js +3 -3
- package/dist/esm/library-style.js +1 -1
- package/dist/esm/nextcloud-vue.css +549 -338
- package/dist/esm/utils/fetchAggregate.js +25 -2
- package/dist/esm/utils/fetchAggregate.js.map +1 -1
- package/dist/esm/utils/switchValues.js +62 -0
- package/dist/esm/utils/switchValues.js.map +1 -0
- package/dist/esm/utils/validateManifestV2.compiled.js +3 -3
- package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
- package/dist/nextcloud-vue.cjs.js +36086 -35536
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +549 -338
- package/l10n/nl.json +3 -3
- package/package.json +1 -1
- package/src/components/CnAdminSettingsShell/CnAdminSettingsShell.vue +31 -2
- package/src/components/CnDashboardPage/CnDashboardPage.vue +9 -0
- package/src/components/CnIndexPage/CnIndexPage.vue +125 -15
- package/src/components/CnRadioCardsWidget/CnRadioCardsWidget.vue +54 -3
- package/src/components/CnReportsPage/CnReportsPage.vue +84 -4
- package/src/components/CnSettingsFormWidget/CnSettingsFormWidget.vue +110 -18
- package/src/components/CnStatWidget/CnStatWidget.vue +3 -1
- package/src/components/CnStatsBlockWidget/CnStatsBlockWidget.vue +92 -5
- package/src/components/CnSwitchRowsWidget/CnSwitchRowsWidget.vue +18 -4
- package/src/css/index-page.css +11 -0
- package/src/css/index.css +1 -0
- package/src/css/look-board-reports.css +117 -0
- package/src/css/look-board.css +32 -1
- package/src/schemas/app-manifest-v2.schema.json +2 -2
- package/src/utils/fetchAggregate.js +24 -1
- package/src/utils/switchValues.js +59 -0
- package/src/utils/validateManifestV2.compiled.js +3 -3
|
@@ -38,11 +38,34 @@ function flattenAggFilter(target, filter, ctx) {
|
|
|
38
38
|
target[`filter[${k}][${op}]`] = ov;
|
|
39
39
|
}
|
|
40
40
|
} else if (v !== '' && v !== null && v !== undefined) {
|
|
41
|
-
target[
|
|
41
|
+
target[aggFilterParam(k)] = v;
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
+
/**
|
|
47
|
+
* Matches a filter key that spells its operator, `field[op]`.
|
|
48
|
+
*
|
|
49
|
+
* @type {RegExp}
|
|
50
|
+
*/
|
|
51
|
+
const OPERATOR_KEY = /^(.+)\[([A-Za-z_]+)\]$/;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* The query parameter of one plain filter key. A key that spells its operator
|
|
55
|
+
* (`scheduledDate[gte]`, the flat form a list page and a lens use) goes out as
|
|
56
|
+
* `filter[scheduledDate][gte]`, the form the aggregation endpoint reads, and
|
|
57
|
+
* not as `filter[scheduledDate[gte]]`, a field it does not have, which counted
|
|
58
|
+
* 0. Any other key goes out as `filter[key]`.
|
|
59
|
+
*
|
|
60
|
+
* @spec openspec/changes/screens-stats-block-operator-keys/specs/stats-block/spec.md#requirement-a-stats-block-filter-can-spell-its-operator-in-the-key
|
|
61
|
+
* @param {string} key The filter key.
|
|
62
|
+
* @return {string} The query parameter name.
|
|
63
|
+
*/
|
|
64
|
+
function aggFilterParam(key) {
|
|
65
|
+
const match = OPERATOR_KEY.exec(key);
|
|
66
|
+
return match ? `filter[${match[1]}][${match[2]}]` : `filter[${key}]`
|
|
67
|
+
}
|
|
68
|
+
|
|
46
69
|
/**
|
|
47
70
|
* Fetch one aggregated scalar from OpenRegister.
|
|
48
71
|
*
|
|
@@ -115,5 +138,5 @@ async function fetchGroupedCounts(source, ctx) {
|
|
|
115
138
|
.map((g) => ({ key: String(g.key), count: Number(g.value) || 0 }))
|
|
116
139
|
}
|
|
117
140
|
|
|
118
|
-
export { fetchAggregateValue, fetchGroupedCounts, flattenAggFilter };
|
|
141
|
+
export { aggFilterParam, fetchAggregateValue, fetchGroupedCounts, flattenAggFilter };
|
|
119
142
|
//# sourceMappingURL=fetchAggregate.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetchAggregate.js","sources":["../../../src/utils/fetchAggregate.js"],"sourcesContent":["/**\n * SPDX-FileCopyrightText: 2026 Conduction B.V.\n * SPDX-License-Identifier: EUPL-1.2\n *\n * Shared helper for the abstract data widgets (CnStatWidget, CnDeltaWidget,\n * CnGaugeWidget, …) — fetches ONE scalar from OpenRegister's ad-hoc aggregation\n * `/value` endpoint given a `{ register, schema, metric, field, filter }`\n * descriptor. Filter values run through `resolveFilterTokens` first, so relative\n * tokens (`@me`, `@monthStart`, `@currentFiscalYear`, …) resolve at fetch time.\n *\n * @module utils/fetchAggregate\n */\n\nimport { resolveFilterTokens } from './resolveFilterTokens.js'\n\n/**\n * Flatten a filter map into operator-aware `filter[key]` / `filter[key][op]`\n * query params (the OpenRegister aggregation filter vocabulary). Resolves\n * relative tokens before writing.\n *\n * @param {object} target The params object to write into.\n * @param {object} filter The filter map.\n * @param {{objectId?: (string|number), object?: object, workspace?: object}} [ctx] Optional\n * token-resolution context forwarded to {@link resolveFilterTokens} so a\n * detail-page aggregate can scope its filter to the current object via\n * `@objectId` / `@object.<field>`.\n * @return {void}\n */\nexport function flattenAggFilter(target, filter, ctx) {\n\tif (!filter || typeof filter !== 'object') {\n\t\treturn\n\t}\n\tfilter = resolveFilterTokens(filter, ctx)\n\tfor (const [k, v] of Object.entries(filter)) {\n\t\tif (v && typeof v === 'object') {\n\t\t\tfor (const [op, ov] of Object.entries(v)) {\n\t\t\t\ttarget[`filter[${k}][${op}]`] = ov\n\t\t\t}\n\t\t} else if (v !== '' && v !== null && v !== undefined) {\n\t\t\ttarget[
|
|
1
|
+
{"version":3,"file":"fetchAggregate.js","sources":["../../../src/utils/fetchAggregate.js"],"sourcesContent":["/**\n * SPDX-FileCopyrightText: 2026 Conduction B.V.\n * SPDX-License-Identifier: EUPL-1.2\n *\n * Shared helper for the abstract data widgets (CnStatWidget, CnDeltaWidget,\n * CnGaugeWidget, …) — fetches ONE scalar from OpenRegister's ad-hoc aggregation\n * `/value` endpoint given a `{ register, schema, metric, field, filter }`\n * descriptor. Filter values run through `resolveFilterTokens` first, so relative\n * tokens (`@me`, `@monthStart`, `@currentFiscalYear`, …) resolve at fetch time.\n *\n * @module utils/fetchAggregate\n */\n\nimport { resolveFilterTokens } from './resolveFilterTokens.js'\n\n/**\n * Flatten a filter map into operator-aware `filter[key]` / `filter[key][op]`\n * query params (the OpenRegister aggregation filter vocabulary). Resolves\n * relative tokens before writing.\n *\n * @param {object} target The params object to write into.\n * @param {object} filter The filter map.\n * @param {{objectId?: (string|number), object?: object, workspace?: object}} [ctx] Optional\n * token-resolution context forwarded to {@link resolveFilterTokens} so a\n * detail-page aggregate can scope its filter to the current object via\n * `@objectId` / `@object.<field>`.\n * @return {void}\n */\nexport function flattenAggFilter(target, filter, ctx) {\n\tif (!filter || typeof filter !== 'object') {\n\t\treturn\n\t}\n\tfilter = resolveFilterTokens(filter, ctx)\n\tfor (const [k, v] of Object.entries(filter)) {\n\t\tif (v && typeof v === 'object') {\n\t\t\tfor (const [op, ov] of Object.entries(v)) {\n\t\t\t\ttarget[`filter[${k}][${op}]`] = ov\n\t\t\t}\n\t\t} else if (v !== '' && v !== null && v !== undefined) {\n\t\t\ttarget[aggFilterParam(k)] = v\n\t\t}\n\t}\n}\n\n/**\n * Matches a filter key that spells its operator, `field[op]`.\n *\n * @type {RegExp}\n */\nconst OPERATOR_KEY = /^(.+)\\[([A-Za-z_]+)\\]$/\n\n/**\n * The query parameter of one plain filter key. A key that spells its operator\n * (`scheduledDate[gte]`, the flat form a list page and a lens use) goes out as\n * `filter[scheduledDate][gte]`, the form the aggregation endpoint reads, and\n * not as `filter[scheduledDate[gte]]`, a field it does not have, which counted\n * 0. Any other key goes out as `filter[key]`.\n *\n * @spec openspec/changes/screens-stats-block-operator-keys/specs/stats-block/spec.md#requirement-a-stats-block-filter-can-spell-its-operator-in-the-key\n * @param {string} key The filter key.\n * @return {string} The query parameter name.\n */\nexport function aggFilterParam(key) {\n\tconst match = OPERATOR_KEY.exec(key)\n\treturn match ? `filter[${match[1]}][${match[2]}]` : `filter[${key}]`\n}\n\n/**\n * Fetch one aggregated scalar from OpenRegister.\n *\n * @param {object} source The aggregate descriptor.\n * @param {string} source.register The register slug.\n * @param {string} source.schema The schema slug.\n * @param {string} [source.metric] count | sum | avg | min | max (default count).\n * @param {string} [source.field] The numeric field (required for non-count metrics).\n * @param {object} [source.filter] The filter map.\n * @param {{objectId?: (string|number), object?: object, workspace?: object}} [ctx] Optional\n * token-resolution context (a detail page's object context) so the filter can\n * scope to the current object via `@objectId` / `@object.<field>`.\n * @return {Promise<number|null>} The aggregated value, or null when unavailable.\n */\nexport async function fetchAggregateValue(source, ctx) {\n\tconst s = source || {}\n\tif (!s.register || !s.schema) {\n\t\treturn null\n\t}\n\tconst [{ default: axios }, { generateUrl }] = await Promise.all([\n\t\timport('@nextcloud/axios'),\n\t\timport('@nextcloud/router'),\n\t])\n\tconst url = generateUrl(\n\t\t'/apps/openregister/api/objects/aggregations/{register}/{schema}/value',\n\t\t{ register: s.register, schema: s.schema },\n\t)\n\tconst params = { metric: s.metric || 'count' }\n\tif (s.field) {\n\t\tparams.field = s.field\n\t}\n\tflattenAggFilter(params, s.filter || {}, ctx)\n\tconst res = await axios.get(url, { params })\n\treturn (res && res.data && res.data.value !== undefined) ? res.data.value : null\n}\n\n/**\n * Fetch the object count per distinct value of one field, in ONE request,\n * from OpenRegister's `/grouped` aggregation endpoint.\n *\n * @param {object} source The grouped descriptor.\n * @param {string} source.register The register slug.\n * @param {string} source.schema The schema slug.\n * @param {string} source.groupBy The field to group on.\n * @param {object} [source.filter] The filter map.\n * @param {{objectId?: (string|number), object?: object, workspace?: object}} [ctx] Optional\n * token-resolution context for the filter.\n * @return {Promise<Array<{key: string, count: number}>>} One entry per group; [] when the source is incomplete.\n * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-stacked-bar-widget\n */\nexport async function fetchGroupedCounts(source, ctx) {\n\tconst s = source || {}\n\tif (!s.register || !s.schema || !s.groupBy) {\n\t\treturn []\n\t}\n\tconst [{ default: axios }, { generateUrl }] = await Promise.all([\n\t\timport('@nextcloud/axios'),\n\t\timport('@nextcloud/router'),\n\t])\n\tconst url = generateUrl(\n\t\t'/apps/openregister/api/objects/aggregations/{register}/{schema}/grouped',\n\t\t{ register: s.register, schema: s.schema },\n\t)\n\tconst params = { groupBy: s.groupBy, metric: 'count' }\n\tflattenAggFilter(params, s.filter || {}, ctx)\n\tconst res = await axios.get(url, { params })\n\tconst groups = (res && res.data && Array.isArray(res.data.groups)) ? res.data.groups : []\n\treturn groups\n\t\t.filter((g) => g && g.key !== null && g.key !== undefined && g.key !== '')\n\t\t.map((g) => ({ key: String(g.key), count: Number(g.value) || 0 }))\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SPDX-FileCopyrightText: 2026 Conduction B.V.
|
|
3
|
+
* SPDX-License-Identifier: EUPL-1.2
|
|
4
|
+
*
|
|
5
|
+
* A switch's value map: what a switch reads as "on" and what it writes for on
|
|
6
|
+
* and off. Without a map a switch is a boolean, as before. With `values:
|
|
7
|
+
* { on, off }` it reads a field stored as `"1"`/`"0"` or `"true"`/`"false"`
|
|
8
|
+
* (an app config flag) and writes those values back.
|
|
9
|
+
*
|
|
10
|
+
* @module utils/switchValues
|
|
11
|
+
* @spec openspec/changes/screens-switch-value-map/specs/switch-rows/spec.md#requirement-a-switch-can-read-and-write-a-value-map
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* The value map of a switch, or null when it has none (a boolean switch).
|
|
16
|
+
*
|
|
17
|
+
* @param {unknown} values The declared `values`.
|
|
18
|
+
* @return {{on: unknown, off: unknown}|null} The map.
|
|
19
|
+
*/
|
|
20
|
+
function switchValueMap(values) {
|
|
21
|
+
if (!values || typeof values !== 'object' || Array.isArray(values) || values.on === undefined) {
|
|
22
|
+
return null
|
|
23
|
+
}
|
|
24
|
+
return { on: values.on, off: values.off === undefined ? null : values.off }
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Whether a stored value reads as "on". Without a map only `true` does; with
|
|
29
|
+
* one, the `on` value does, compared as text so `1` and `"1"` are the same.
|
|
30
|
+
*
|
|
31
|
+
* @param {unknown} stored The stored value.
|
|
32
|
+
* @param {unknown} values The declared `values`.
|
|
33
|
+
* @return {boolean} True when the switch shows on.
|
|
34
|
+
*/
|
|
35
|
+
function switchIsOn(stored, values) {
|
|
36
|
+
const map = switchValueMap(values);
|
|
37
|
+
if (!map) {
|
|
38
|
+
return stored === true
|
|
39
|
+
}
|
|
40
|
+
if (stored === undefined || stored === null) {
|
|
41
|
+
return false
|
|
42
|
+
}
|
|
43
|
+
return stored === map.on || String(stored) === String(map.on)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* The value a switch writes for a state.
|
|
48
|
+
*
|
|
49
|
+
* @param {boolean} on The switch state.
|
|
50
|
+
* @param {unknown} values The declared `values`.
|
|
51
|
+
* @return {unknown} `true`/`false` without a map, else the map's `on` / `off`.
|
|
52
|
+
*/
|
|
53
|
+
function switchStoredValue(on, values) {
|
|
54
|
+
const map = switchValueMap(values);
|
|
55
|
+
if (!map) {
|
|
56
|
+
return on === true
|
|
57
|
+
}
|
|
58
|
+
return on ? map.on : map.off
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export { switchIsOn, switchStoredValue, switchValueMap };
|
|
62
|
+
//# sourceMappingURL=switchValues.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"switchValues.js","sources":["../../../src/utils/switchValues.js"],"sourcesContent":["/**\n * SPDX-FileCopyrightText: 2026 Conduction B.V.\n * SPDX-License-Identifier: EUPL-1.2\n *\n * A switch's value map: what a switch reads as \"on\" and what it writes for on\n * and off. Without a map a switch is a boolean, as before. With `values:\n * { on, off }` it reads a field stored as `\"1\"`/`\"0\"` or `\"true\"`/`\"false\"`\n * (an app config flag) and writes those values back.\n *\n * @module utils/switchValues\n * @spec openspec/changes/screens-switch-value-map/specs/switch-rows/spec.md#requirement-a-switch-can-read-and-write-a-value-map\n */\n\n/**\n * The value map of a switch, or null when it has none (a boolean switch).\n *\n * @param {unknown} values The declared `values`.\n * @return {{on: unknown, off: unknown}|null} The map.\n */\nexport function switchValueMap(values) {\n\tif (!values || typeof values !== 'object' || Array.isArray(values) || values.on === undefined) {\n\t\treturn null\n\t}\n\treturn { on: values.on, off: values.off === undefined ? null : values.off }\n}\n\n/**\n * Whether a stored value reads as \"on\". Without a map only `true` does; with\n * one, the `on` value does, compared as text so `1` and `\"1\"` are the same.\n *\n * @param {unknown} stored The stored value.\n * @param {unknown} values The declared `values`.\n * @return {boolean} True when the switch shows on.\n */\nexport function switchIsOn(stored, values) {\n\tconst map = switchValueMap(values)\n\tif (!map) {\n\t\treturn stored === true\n\t}\n\tif (stored === undefined || stored === null) {\n\t\treturn false\n\t}\n\treturn stored === map.on || String(stored) === String(map.on)\n}\n\n/**\n * The value a switch writes for a state.\n *\n * @param {boolean} on The switch state.\n * @param {unknown} values The declared `values`.\n * @return {unknown} `true`/`false` without a map, else the map's `on` / `off`.\n */\nexport function switchStoredValue(on, values) {\n\tconst map = switchValueMap(values)\n\tif (!map) {\n\t\treturn on === true\n\t}\n\treturn on ? map.on : map.off\n}\n"],"names":[],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,cAAc,CAAC,MAAM,EAAE;AACvC,CAAC,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,EAAE,KAAK,SAAS,EAAE;AAChG,EAAE,OAAO,IAAI;AACb,EAAE;AACF,CAAC,OAAO,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,KAAK,SAAS,GAAG,IAAI,GAAG,MAAM,CAAC,GAAG,EAAE;AAC5E,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE;AAC3C,CAAC,MAAM,GAAG,GAAG,cAAc,CAAC,MAAM,EAAC;AACnC,CAAC,IAAI,CAAC,GAAG,EAAE;AACX,EAAE,OAAO,MAAM,KAAK,IAAI;AACxB,EAAE;AACF,CAAC,IAAI,MAAM,KAAK,SAAS,IAAI,MAAM,KAAK,IAAI,EAAE;AAC9C,EAAE,OAAO,KAAK;AACd,EAAE;AACF,CAAC,OAAO,MAAM,KAAK,GAAG,CAAC,EAAE,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;AAC9D,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,iBAAiB,CAAC,EAAE,EAAE,MAAM,EAAE;AAC9C,CAAC,MAAM,GAAG,GAAG,cAAc,CAAC,MAAM,EAAC;AACnC,CAAC,IAAI,CAAC,GAAG,EAAE;AACX,EAAE,OAAO,EAAE,KAAK,IAAI;AACpB,EAAE;AACF,CAAC,OAAO,EAAE,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,GAAG;AAC7B;;;;"}
|