@cyberismo/backend 0.0.19 → 0.0.21

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.
Files changed (44) hide show
  1. package/dist/common/validationSchemas.d.ts +2 -2
  2. package/dist/domain/calculations/index.js +5 -5
  3. package/dist/domain/calculations/index.js.map +1 -1
  4. package/dist/domain/calculations/schema.d.ts +1 -1
  5. package/dist/domain/calculations/schema.js +1 -1
  6. package/dist/domain/calculations/schema.js.map +1 -1
  7. package/dist/domain/calculations/service.d.ts +1 -1
  8. package/dist/domain/calculations/service.js +21 -2
  9. package/dist/domain/calculations/service.js.map +1 -1
  10. package/dist/domain/cardTypes/index.js +62 -1
  11. package/dist/domain/cardTypes/index.js.map +1 -1
  12. package/dist/domain/cardTypes/schema.d.ts +19 -0
  13. package/dist/domain/cardTypes/schema.js +9 -0
  14. package/dist/domain/cardTypes/schema.js.map +1 -1
  15. package/dist/domain/cardTypes/service.d.ts +6 -0
  16. package/dist/domain/cardTypes/service.js +100 -0
  17. package/dist/domain/cardTypes/service.js.map +1 -1
  18. package/dist/domain/project/index.js +5 -0
  19. package/dist/domain/project/index.js.map +1 -1
  20. package/dist/domain/project/service.d.ts +1 -0
  21. package/dist/domain/project/service.js +3 -0
  22. package/dist/domain/project/service.js.map +1 -1
  23. package/dist/domain/resources/schema.d.ts +2 -1
  24. package/dist/domain/resources/schema.js +1 -0
  25. package/dist/domain/resources/schema.js.map +1 -1
  26. package/dist/domain/resources/service.js +24 -5
  27. package/dist/domain/resources/service.js.map +1 -1
  28. package/dist/middleware/zvalidator.d.ts +1 -1
  29. package/dist/public/THIRD-PARTY.txt +848 -745
  30. package/dist/public/assets/index-CRSBseQM.css +1 -0
  31. package/dist/public/assets/{index-BeA3_uli.js → index-Ca10XaMv.js} +102999 -102042
  32. package/dist/public/index.html +2 -2
  33. package/package.json +4 -4
  34. package/src/domain/calculations/index.ts +5 -5
  35. package/src/domain/calculations/schema.ts +1 -1
  36. package/src/domain/calculations/service.ts +26 -2
  37. package/src/domain/cardTypes/index.ts +75 -1
  38. package/src/domain/cardTypes/schema.ts +15 -0
  39. package/src/domain/cardTypes/service.ts +151 -0
  40. package/src/domain/project/index.ts +6 -0
  41. package/src/domain/project/service.ts +4 -0
  42. package/src/domain/resources/schema.ts +1 -0
  43. package/src/domain/resources/service.ts +28 -5
  44. package/dist/public/assets/index-DnK7MBer.css +0 -1
@@ -11,8 +11,8 @@
11
11
  name="msapplication-TileImage"
12
12
  content="/cropped-favicon-270x270.png"
13
13
  />
14
- <script type="module" crossorigin src="/assets/index-BeA3_uli.js"></script>
15
- <link rel="stylesheet" crossorigin href="/assets/index-DnK7MBer.css">
14
+ <script type="module" crossorigin src="/assets/index-Ca10XaMv.js"></script>
15
+ <link rel="stylesheet" crossorigin href="/assets/index-CRSBseQM.css">
16
16
  </head>
17
17
  <body>
18
18
  <div id="root"></div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cyberismo/backend",
3
- "version": "0.0.19",
3
+ "version": "0.0.21",
4
4
  "description": "Express backend for Cyberismo",
5
5
  "main": "dist/index.js",
6
6
  "keywords": [],
@@ -15,13 +15,13 @@
15
15
  "dependencies": {
16
16
  "@asciidoctor/core": "^3.0.4",
17
17
  "@hono/node-server": "^1.19.2",
18
- "@hono/zod-validator": "^0.7.5",
18
+ "@hono/zod-validator": "^0.7.6",
19
19
  "@types/mime-types": "^3.0.1",
20
20
  "dotenv": "^17.2.3",
21
21
  "hono": "^4.10.7",
22
22
  "mime-types": "^3.0.2",
23
- "zod": "^4.1.13",
24
- "@cyberismo/data-handler": "0.0.19"
23
+ "zod": "^4.3.6",
24
+ "@cyberismo/data-handler": "0.0.21"
25
25
  },
26
26
  "devDependencies": {
27
27
  "@cyberismo/app": "0.0.2"
@@ -23,7 +23,7 @@ const router = new Hono();
23
23
  * /api/calculations:
24
24
  * post:
25
25
  * summary: Create a new calculation
26
- * description: Creates a new calculation file with the specified fileName
26
+ * description: Creates a new calculation with the specified identifier
27
27
  * requestBody:
28
28
  * required: true
29
29
  * content:
@@ -31,10 +31,10 @@ const router = new Hono();
31
31
  * schema:
32
32
  * type: object
33
33
  * properties:
34
- * fileName:
34
+ * identifier:
35
35
  * type: string
36
36
  * required:
37
- * - fileName
37
+ * - identifier
38
38
  * responses:
39
39
  * 200:
40
40
  * description: Calculation created successfully
@@ -45,9 +45,9 @@ const router = new Hono();
45
45
  */
46
46
  router.post('/', zValidator('json', createCalculationSchema), async (c) => {
47
47
  const commands = c.get('commands');
48
- const { fileName } = c.req.valid('json');
48
+ const { identifier } = c.req.valid('json');
49
49
 
50
- await calculationService.createCalculation(commands, fileName);
50
+ await calculationService.createCalculation(commands, identifier);
51
51
  return c.json({ message: 'Calculation created successfully' });
52
52
  });
53
53
 
@@ -14,5 +14,5 @@
14
14
  import { z } from 'zod';
15
15
 
16
16
  export const createCalculationSchema = z.object({
17
- fileName: z.string().min(1),
17
+ identifier: z.string().min(1),
18
18
  });
@@ -12,10 +12,34 @@
12
12
  */
13
13
 
14
14
  import type { CommandManager } from '@cyberismo/data-handler';
15
+ import { updateResourceWithOperation } from '../resources/service.js';
16
+
17
+ /**
18
+ * Capitalizes the first letter of a string.
19
+ */
20
+ function capitalize(str: string): string {
21
+ if (!str) return str;
22
+ return str.charAt(0).toUpperCase() + str.slice(1);
23
+ }
15
24
 
16
25
  export async function createCalculation(
17
26
  commands: CommandManager,
18
- fileName: string,
27
+ identifier: string,
19
28
  ) {
20
- await commands.createCmd.createCalculation(fileName);
29
+ await commands.createCmd.createCalculation(identifier);
30
+
31
+ // Set displayName to capitalized version of identifier
32
+ const project = await commands.showCmd.showProject();
33
+ await updateResourceWithOperation(
34
+ commands,
35
+ { prefix: project.prefix, type: 'calculations', identifier },
36
+ {
37
+ updateKey: { key: 'displayName' },
38
+ operation: {
39
+ name: 'change',
40
+ target: '',
41
+ to: capitalize(identifier),
42
+ },
43
+ },
44
+ );
21
45
  }
@@ -13,7 +13,11 @@
13
13
 
14
14
  import { Hono } from 'hono';
15
15
  import * as cardTypeService from './service.js';
16
- import { createCardTypeSchema } from './schema.js';
16
+ import {
17
+ createCardTypeSchema,
18
+ cardTypeNameParamSchema,
19
+ fieldVisibilityBodySchema,
20
+ } from './schema.js';
17
21
  import { zValidator } from '../../middleware/zvalidator.js';
18
22
 
19
23
  const router = new Hono();
@@ -93,4 +97,74 @@ router.post('/', zValidator('json', createCardTypeSchema), async (c) => {
93
97
  }
94
98
  });
95
99
 
100
+ /**
101
+ * @swagger
102
+ * /api/cardTypes/{cardTypeName}/field-visibility:
103
+ * patch:
104
+ * summary: Update field visibility for a card type
105
+ * description: Move a field between visibility groups (always, optional, hidden) and optionally set its position
106
+ * parameters:
107
+ * - in: path
108
+ * name: cardTypeName
109
+ * required: true
110
+ * schema:
111
+ * type: string
112
+ * description: Full name of the card type (e.g., "prefix/cardTypes/identifier")
113
+ * requestBody:
114
+ * required: true
115
+ * content:
116
+ * application/json:
117
+ * schema:
118
+ * type: object
119
+ * properties:
120
+ * fieldName:
121
+ * type: string
122
+ * description: Name of the field to update
123
+ * group:
124
+ * type: string
125
+ * enum: [always, optional, hidden]
126
+ * description: Target visibility group
127
+ * index:
128
+ * type: number
129
+ * description: Optional position within the group
130
+ * required:
131
+ * - fieldName
132
+ * - group
133
+ * responses:
134
+ * 200:
135
+ * description: Field visibility updated successfully
136
+ * 400:
137
+ * description: Invalid request
138
+ * 404:
139
+ * description: Card type not found
140
+ * 500:
141
+ * description: Server error
142
+ */
143
+ router.patch(
144
+ '/:cardTypeName/field-visibility',
145
+ zValidator('param', cardTypeNameParamSchema),
146
+ zValidator('json', fieldVisibilityBodySchema),
147
+ async (c) => {
148
+ const commands = c.get('commands');
149
+ const { cardTypeName } = c.req.valid('param');
150
+ const body = c.req.valid('json');
151
+
152
+ try {
153
+ await cardTypeService.updateFieldVisibility(commands, cardTypeName, body);
154
+ return c.json({ message: 'Field visibility updated successfully' });
155
+ } catch (error) {
156
+ // TODO: Implement NotFoundError etc and handle them globally
157
+ if (error instanceof Error && error.message.includes('does not exist')) {
158
+ return c.json({ error: error.message }, 404);
159
+ }
160
+ return c.json(
161
+ {
162
+ error: `${error instanceof Error ? error.message : 'Unknown error'}`,
163
+ },
164
+ 500,
165
+ );
166
+ }
167
+ },
168
+ );
169
+
96
170
  export default router;
@@ -17,3 +17,18 @@ export const createCardTypeSchema = z.object({
17
17
  identifier: identifierSchema,
18
18
  workflowName: z.string(),
19
19
  });
20
+
21
+ export const visibilityGroup = z.enum(['always', 'optional', 'hidden']);
22
+ export type VisibilityGroup = z.infer<typeof visibilityGroup>;
23
+
24
+ export const fieldVisibilityBodySchema = z.object({
25
+ fieldName: z.string().min(1),
26
+ group: visibilityGroup,
27
+ index: z.number().int().min(0).optional(),
28
+ });
29
+
30
+ export type FieldVisibilityBody = z.infer<typeof fieldVisibilityBodySchema>;
31
+
32
+ export const cardTypeNameParamSchema = z.object({
33
+ cardTypeName: z.string().min(1),
34
+ });
@@ -12,6 +12,7 @@
12
12
  */
13
13
 
14
14
  import type { CommandManager } from '@cyberismo/data-handler';
15
+ import type { VisibilityGroup, FieldVisibilityBody } from './schema.js';
15
16
 
16
17
  export async function getCardTypes(commands: CommandManager) {
17
18
  const cardTypesWithDetails =
@@ -26,3 +27,153 @@ export async function createCardType(
26
27
  ) {
27
28
  await commands.createCmd.createCardType(cardTypeName, workflowName);
28
29
  }
30
+
31
+ const groupToKey: Record<Exclude<VisibilityGroup, 'hidden'>, string> = {
32
+ always: 'alwaysVisibleFields',
33
+ optional: 'optionallyVisibleFields',
34
+ };
35
+
36
+ function getCurrentGroup(
37
+ alwaysVisibleFields: string[],
38
+ optionallyVisibleFields: string[],
39
+ fieldName: string,
40
+ ): VisibilityGroup {
41
+ if (alwaysVisibleFields.includes(fieldName)) return 'always';
42
+ if (optionallyVisibleFields.includes(fieldName)) return 'optional';
43
+ return 'hidden';
44
+ }
45
+
46
+ /**
47
+ * Update field visibility for a card type.
48
+ * Handles moving fields between visibility groups and reordering within groups.
49
+ */
50
+ export async function updateFieldVisibility(
51
+ commands: CommandManager,
52
+ cardTypeName: string,
53
+ body: FieldVisibilityBody,
54
+ ): Promise<void> {
55
+ const { fieldName, group: targetGroup, index: targetIndex } = body;
56
+
57
+ // Get current card type data
58
+ const cardType = await commands.showCmd.showResource(
59
+ cardTypeName,
60
+ 'cardTypes',
61
+ );
62
+ if (!cardType) {
63
+ throw new Error(`Card type '${cardTypeName}' not found`);
64
+ }
65
+
66
+ const customFields = cardType.customFields || [];
67
+ const alwaysVisibleFields = cardType.alwaysVisibleFields || [];
68
+ const optionallyVisibleFields = cardType.optionallyVisibleFields || [];
69
+
70
+ // Validate that the field exists in customFields
71
+ const fieldExists = customFields.some(
72
+ (f: { name: string }) => f.name === fieldName,
73
+ );
74
+ if (!fieldExists) {
75
+ throw new Error(
76
+ `Field '${fieldName}' does not exist in card type '${cardTypeName}'. `,
77
+ );
78
+ }
79
+
80
+ const currentGroup = getCurrentGroup(
81
+ alwaysVisibleFields,
82
+ optionallyVisibleFields,
83
+ fieldName,
84
+ );
85
+
86
+ // If same group, just handle reordering
87
+ if (currentGroup === targetGroup) {
88
+ if (targetGroup === 'hidden') {
89
+ // Nothing to reorder in hidden group
90
+ return;
91
+ }
92
+
93
+ if (targetIndex !== undefined) {
94
+ await commands.updateCmd.applyResourceOperation(
95
+ cardTypeName,
96
+ {
97
+ key: groupToKey[targetGroup],
98
+ },
99
+ {
100
+ name: 'rank',
101
+ target: fieldName,
102
+ newIndex: targetIndex,
103
+ },
104
+ );
105
+ }
106
+ return;
107
+ }
108
+
109
+ // Different group - need to remove from old and add to new
110
+ let removedFromOld = false;
111
+
112
+ try {
113
+ // Remove from current group (if not hidden)
114
+ if (currentGroup !== 'hidden') {
115
+ await commands.updateCmd.applyResourceOperation(
116
+ cardTypeName,
117
+ {
118
+ key: groupToKey[currentGroup],
119
+ },
120
+ {
121
+ name: 'remove',
122
+ target: fieldName,
123
+ },
124
+ );
125
+ removedFromOld = true;
126
+ }
127
+
128
+ // Add to new group (if not hidden)
129
+ if (targetGroup !== 'hidden') {
130
+ await commands.updateCmd.applyResourceOperation(
131
+ cardTypeName,
132
+ {
133
+ key: groupToKey[targetGroup],
134
+ },
135
+ {
136
+ name: 'add',
137
+ target: fieldName,
138
+ },
139
+ );
140
+
141
+ // Reorder if index specified
142
+ if (targetIndex !== undefined) {
143
+ await commands.updateCmd.applyResourceOperation(
144
+ cardTypeName,
145
+ {
146
+ key: groupToKey[targetGroup],
147
+ },
148
+ {
149
+ name: 'rank',
150
+ target: fieldName,
151
+ newIndex: targetIndex,
152
+ },
153
+ );
154
+ }
155
+ }
156
+ } catch (error) {
157
+ // Attempt rollback if we removed from old group but failed to add to new
158
+ if (removedFromOld && currentGroup !== 'hidden') {
159
+ try {
160
+ await commands.updateCmd.applyResourceOperation(
161
+ cardTypeName,
162
+ {
163
+ key: groupToKey[currentGroup],
164
+ },
165
+ {
166
+ name: 'add',
167
+ target: fieldName,
168
+ },
169
+ );
170
+ } catch {
171
+ // Rollback failed - log but throw original error
172
+ console.error(
173
+ `Rollback failed for field '${fieldName}' in card type '${cardTypeName}'`,
174
+ );
175
+ }
176
+ }
177
+ throw error;
178
+ }
179
+ }
@@ -33,6 +33,12 @@ router.patch('/', zValidator('json', updateProjectSchema), async (c) => {
33
33
  return c.json(project);
34
34
  });
35
35
 
36
+ router.post('/modules/update', async (c) => {
37
+ const commands = c.get('commands');
38
+ await projectService.updateAllModules(commands);
39
+ return c.json({ message: 'All modules updated' });
40
+ });
41
+
36
42
  router.post(
37
43
  '/modules/:module/update',
38
44
  zValidator('param', moduleParamSchema),
@@ -83,6 +83,10 @@ export async function updateModule(commands: CommandManager, module: string) {
83
83
  await commands.importCmd.updateModule(module);
84
84
  }
85
85
 
86
+ export async function updateAllModules(commands: CommandManager) {
87
+ await commands.importCmd.updateAllModules();
88
+ }
89
+
86
90
  export async function deleteModule(commands: CommandManager, module: string) {
87
91
  await commands.removeCmd.remove('module', module);
88
92
  }
@@ -51,6 +51,7 @@ export const updateOperationBodySchema = z.object({
51
51
  z.object({
52
52
  name: z.literal('remove'),
53
53
  target: z.unknown(),
54
+ replacementValue: z.unknown().optional(),
54
55
  }),
55
56
  z.object({
56
57
  name: z.literal('rank'),
@@ -48,7 +48,7 @@ async function getModules(commands: CommandManager) {
48
48
  try {
49
49
  const module = await commands.showCmd.showModule(moduleName);
50
50
  return { name: module.name, cardKeyPrefix: module.cardKeyPrefix };
51
- } catch (error) {
51
+ } catch {
52
52
  return { name: moduleName, cardKeyPrefix: moduleName };
53
53
  }
54
54
  }),
@@ -58,6 +58,24 @@ async function getModules(commands: CommandManager) {
58
58
  }
59
59
  }
60
60
 
61
+ function sortTemplateCardsByRank(
62
+ cards: CardWithChildrenCards[],
63
+ ): CardWithChildrenCards[] {
64
+ return [...cards]
65
+ .sort((a, b) => {
66
+ const rankA = a.metadata?.rank ?? '';
67
+ const rankB = b.metadata?.rank ?? '';
68
+ if (rankA === rankB) {
69
+ return a.key.localeCompare(b.key);
70
+ }
71
+ return rankA.localeCompare(rankB);
72
+ })
73
+ .map((card) => ({
74
+ ...card,
75
+ childrenCards: sortTemplateCardsByRank(card.childrenCards ?? []),
76
+ }));
77
+ }
78
+
61
79
  export async function buildResourceTree(commands: CommandManager) {
62
80
  const project = await commands.showCmd.showProject();
63
81
  const tree: unknown[] = [];
@@ -220,7 +238,10 @@ async function createResourceNode(
220
238
  fileName,
221
239
  displayName: fileName,
222
240
  data: {
223
- content,
241
+ content:
242
+ typeof content === 'string'
243
+ ? content
244
+ : JSON.stringify(content, null, 2),
224
245
  },
225
246
  readOnly: resourceName(name).prefix !== projectPrefix,
226
247
  }),
@@ -263,8 +284,9 @@ function createCardNode(
263
284
  };
264
285
 
265
286
  // Recursively process children if they exist
266
- if (childrenCards && childrenCards.length > 0) {
267
- cardNode.children = childrenCards.map((child) =>
287
+ if (childrenCards?.length) {
288
+ const sortedChildren = sortTemplateCardsByRank(childrenCards);
289
+ cardNode.children = sortedChildren.map((child) =>
268
290
  createCardNode(child, module, projectPrefix),
269
291
  );
270
292
  }
@@ -286,7 +308,8 @@ async function processTemplates(
286
308
  } = {};
287
309
 
288
310
  for (const { name, cards } of templateTree) {
289
- for (const card of cards) {
311
+ const sortedCards = sortTemplateCardsByRank(cards);
312
+ for (const card of sortedCards) {
290
313
  const { prefix } = parseResourcePrefix(name);
291
314
  const cardNode = createCardNode(card, prefix, projectPrefix);
292
315
 
@@ -1 +0,0 @@
1
- @media(max-width:800px){.breadcrumbs{display:none}}[role=treeitem][aria-selected=false]:hover{.treenode{background-color:#dedede}}[role=treeitem][aria-selected=true]{outline:none}.resizeHandle{width:2px}.resizeHandle:hover,.resizeHandle:active{background-color:#0b6bcb}.cyberismo-svg-wrapper svg{max-height:100vh}.doc .MuiButton-root{margin-top:12px}.doc table.tableblock{border-collapse:collapse}.doc{color:#333;font-size:inherit;-ms-hyphens:auto;hyphens:auto;line-height:1.6;margin:0;padding:0}@media screen and (min-width:1024px){.doc{-webkit-box-flex:1;-ms-flex:auto;flex:auto;font-size:.94444rem;margin:0;min-width:0}}.doc h1,.doc h2,.doc h3,.doc h4,.doc h5,.doc h6{color:#191919;font-weight:400;-ms-hyphens:none;hyphens:none;line-height:1.3;margin:1rem 0 0}.doc>h1.page:first-child{font-size:2rem;margin:1.5rem 0}@media screen and (min-width:769px){.doc>h1.page:first-child{margin-top:2.5rem}}.doc>h1.page:first-child+aside.toc.embedded{margin-top:-.5rem}.doc>h2#name+.sectionbody{margin-top:1rem}#preamble+.sect1,.doc .sect1+.sect1{margin-top:2rem}.doc h1.sect0{background:#f0f0f0;font-size:1.8em;margin:1.5rem -1rem 0;padding:.5rem 1rem}.doc h2:not(.discrete){border-bottom:1px solid #e1e1e1;margin-left:-1rem;margin-right:-1rem;padding:.4rem 1rem .1rem}.doc h3:not(.discrete),.doc h4:not(.discrete){font-weight:600}.doc h1 .anchor,.doc h2 .anchor,.doc h3 .anchor,.doc h4 .anchor,.doc h5 .anchor,.doc h6 .anchor{position:absolute;text-decoration:none;width:1.75ex;margin-left:-1.5ex;visibility:hidden;font-size:.8em;font-weight:400;padding-top:.05em}.doc h1 .anchor:before,.doc h2 .anchor:before,.doc h3 .anchor:before,.doc h4 .anchor:before,.doc h5 .anchor:before,.doc h6 .anchor:before{content:"§"}.doc h1:hover .anchor,.doc h2:hover .anchor,.doc h3:hover .anchor,.doc h4:hover .anchor,.doc h5:hover .anchor,.doc h6:hover .anchor{visibility:visible}.doc dl,.doc p{margin:0}.doc a{color:#1565c0}.doc a:hover{color:#104d92}.doc a.bare{-ms-hyphens:none;hyphens:none}.doc a.unresolved{color:#d32f2f}.doc i.fa{-ms-hyphens:none;hyphens:none;font-style:normal}.doc .colist>table code,.doc p code,.doc thead code{color:#222;background:#fafafa;border-radius:.25em;font-size:.95em;padding:.125em .25em}.doc code,.doc pre{-ms-hyphens:none;hyphens:none}.doc pre{font-size:.88889rem;line-height:1.5;margin:0}.doc blockquote{margin:0}.doc .paragraph.lead>p{font-size:1rem}.doc .right{float:right}.doc .left{float:left}.doc .float-gap.right{margin:0 1rem 1rem 0}.doc .float-gap.left{margin:0 0 1rem 1rem}.doc .float-group:after{content:"";display:table;clear:both}.doc .text-left{text-align:left}.doc .text-center{text-align:center}.doc .text-right{text-align:right}.doc .text-justify{text-align:justify}.doc .stretch{width:100%}.doc .big{font-size:larger}.doc .small{font-size:smaller}.doc .underline{text-decoration:underline}.doc .line-through{text-decoration:line-through}.doc .dlist,.doc .exampleblock,.doc .hdlist,.doc .imageblock,.doc .listingblock,.doc .literalblock,.doc .olist,.doc .paragraph,.doc .partintro,.doc .quoteblock,.doc .sidebarblock,.doc .tabs,.doc .ulist,.doc .verseblock,.doc .videoblock,.doc details,.doc hr{margin:1rem 0 0}.doc .tablecontainer,.doc .tablecontainer+*,.doc :not(.tablecontainer)>table.tableblock,.doc :not(.tablecontainer)>table.tableblock+*,.doc>table.tableblock,.doc>table.tableblock+*{margin-top:1.5rem}.doc table.tableblock{font-size:.83333rem}.doc p.tableblock+p.tableblock{margin-top:.5rem}.doc table.tableblock pre{font-size:inherit}.doc td.tableblock>.content{word-wrap:anywhere}.doc td.tableblock>.content>:first-child{margin-top:0}.doc table.tableblock td{padding:.5rem}.doc table.tableblock th{padding:.5rem;background:#fbfcfe}.doc table.tableblock,.doc table.tableblock>*>tr>*{border:0 solid #e1e1e1}.doc table.grid-all>*>tr>*{border-width:1px}.doc table.grid-cols>*>tr>*{border-width:0 1px}.doc table.grid-rows>*>tr>*{border-width:1px 0}.doc table.grid-all>thead th,.doc table.grid-rows>thead th{border-bottom-width:2.5px}.doc table.frame-all{border-width:1px}.doc table.frame-ends{border-width:1px 0}.doc table.frame-sides{border-width:0 1px}.doc table.frame-none>colgroup+*>:first-child>*,.doc table.frame-sides>colgroup+*>:first-child>*{border-top-width:0}.doc table.frame-sides>:last-child>:last-child>*{border-bottom-width:0}.doc table.frame-ends>*>tr>:first-child,.doc table.frame-none>*>tr>:first-child{border-left-width:0}.doc table.frame-ends>*>tr>:last-child,.doc table.frame-none>*>tr>:last-child{border-right-width:0}.doc table.stripes-all>tbody>tr,.doc table.stripes-even>tbody>tr:nth-of-type(2n),.doc table.stripes-hover>tbody>tr:hover,.doc table.stripes-odd>tbody>tr:nth-of-type(odd){background:#fafafa}.doc table.tableblock>tfoot{background:-webkit-gradient(linear,left top,left bottom,from(#f0f0f0),to(#fff));background:linear-gradient(180deg,#f0f0f0 0,#fff)}.doc .halign-left{text-align:left}.doc .halign-right{text-align:right}.doc .halign-center{text-align:center}.doc .valign-top{vertical-align:top}.doc .valign-bottom{vertical-align:bottom}.doc .valign-middle{vertical-align:middle}.doc .admonitionblock{margin:1.4rem 0 0}.doc .admonitionblock p,.doc .admonitionblock td.content{font-size:.88889rem}.doc .admonitionblock td.content>.title+*,.doc .admonitionblock td.content>:not(.title):first-child{margin-top:0}.doc .admonitionblock td.content pre{font-size:.83333rem}.doc .admonitionblock>table{table-layout:fixed;position:relative;width:100%}.doc .admonitionblock td.content{padding:1rem 1rem .75rem;background:#fafafa;width:100%;word-wrap:anywhere}.doc .admonitionblock td.icon{font-size:.83333rem;left:0;line-height:1;padding:0;position:absolute;top:0;-webkit-transform:translate(-.5rem,-50%);transform:translate(-.5rem,-50%)}.doc .admonitionblock td.icon i{-webkit-box-align:center;-ms-flex-align:center;align-items:center;border-radius:.45rem;display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-filter:initial;filter:none;height:1.25rem;padding:0 .5rem;vertical-align:initial;width:-webkit-fit-content;width:-moz-fit-content;width:fit-content}.doc .admonitionblock td.icon i:after{content:attr(title);font-weight:600;font-style:normal;text-transform:uppercase}.doc .admonitionblock td.icon i.icon-caution{background-color:#a0439c;color:#fff}.doc .admonitionblock td.icon i.icon-important{background-color:#d32f2f;color:#fff}.doc .admonitionblock td.icon i.icon-note{background-color:#217ee7;color:#fff}.doc .admonitionblock td.icon i.icon-tip{background-color:#41af46;color:#fff}.doc .admonitionblock td.icon i.icon-warning{background-color:#e18114;color:#fff}.doc .imageblock,.doc .videoblock{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.doc .imageblock .content{-ms-flex-item-align:stretch;align-self:stretch;text-align:center}.doc .imageblock.text-left,.doc .videoblock.text-left{-webkit-box-align:start;-ms-flex-align:start;align-items:flex-start}.doc .imageblock.text-left .content{text-align:left}.doc .imageblock.text-right,.doc .videoblock.text-right{-webkit-box-align:end;-ms-flex-align:end;align-items:flex-end}.doc .imageblock.text-right .content{text-align:right}.doc .image>img,.doc .image>object,.doc .image>svg,.doc .imageblock img,.doc .imageblock object,.doc .imageblock svg{display:inline-block;max-height:75vh;max-width:100%;vertical-align:middle}.doc .image:not(.left):not(.right)>img{margin-top:-.2em}.doc .videoblock iframe,.doc .videoblock video{max-width:100%;vertical-align:middle}#preamble .abstract blockquote{background:#f0f0f0;border-left:5px solid #e1e1e1;color:#4a4a4a;font-size:.88889rem;padding:.75em 1em}.doc .quoteblock,.doc .verseblock{background:#fafafa;border-left:5px solid #5d5d5d;color:#5d5d5d}.doc .quoteblock{padding:.25rem 2rem 1.25rem}.doc .quoteblock .attribution{color:#8e8e8e;font-size:.83333rem;margin-top:.75rem}.doc .quoteblock blockquote{margin-top:1rem}.doc .quoteblock .paragraph{font-style:italic}.doc .quoteblock cite{padding-left:1em}.doc .verseblock{font-size:1.15em;padding:1rem 2rem}.doc .verseblock pre{font-family:inherit;font-size:inherit}.doc ol,.doc ul{margin:0;padding:0 0 0 2rem}.doc ol.none,.doc ol.unnumbered,.doc ol.unstyled,.doc ul.checklist,.doc ul.no-bullet,.doc ul.none,.doc ul.unstyled{list-style-type:none}.doc ol.unnumbered,.doc ul.no-bullet{padding-left:1.25rem}.doc ol.unstyled,.doc ul.unstyled{padding-left:0}.doc ul.circle{list-style-type:circle}.doc ul.disc{list-style-type:disc}.doc ul.square{list-style-type:square}.doc ul.circle ul:not([class]),.doc ul.disc ul:not([class]),.doc ul.square ul:not([class]){list-style:inherit}.doc ol.arabic{list-style-type:decimal}.doc ol.decimal{list-style-type:decimal-leading-zero}.doc ol.loweralpha{list-style-type:lower-alpha}.doc ol.upperalpha{list-style-type:upper-alpha}.doc ol.lowerroman{list-style-type:lower-roman}.doc ol.upperroman{list-style-type:upper-roman}.doc ol.lowergreek{list-style-type:lower-greek}.doc ul.checklist{padding-left:1.75rem}.doc ul.checklist p>i.fa-check-square-o:first-child,.doc ul.checklist p>i.fa-square-o:first-child{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;width:1.25rem;margin-left:-1.25rem}.doc ul.checklist i.fa-check-square-o:before{content:"✓"}.doc ul.checklist i.fa-square-o:before{content:"❏"}.doc .dlist .dlist,.doc .dlist .olist,.doc .dlist .ulist,.doc .olist .dlist,.doc .olist .olist,.doc .olist .ulist,.doc .olist li+li,.doc .ulist .dlist,.doc .ulist .olist,.doc .ulist .ulist,.doc .ulist li+li{margin-top:.5rem}.doc .admonitionblock .listingblock,.doc .olist .listingblock,.doc .ulist .listingblock{padding:0}.doc .admonitionblock .title,.doc .exampleblock .title,.doc .imageblock .title,.doc .listingblock .title,.doc .literalblock .title,.doc .openblock .title,.doc .videoblock .title,.doc table.tableblock caption{color:#5d5d5d;font-size:.88889rem;font-style:italic;font-weight:600;-ms-hyphens:none;hyphens:none;letter-spacing:.01em;padding-bottom:.075rem}.doc table.tableblock caption{text-align:left}.doc .olist .title,.doc .ulist .title{font-style:italic;font-weight:600;margin-bottom:.25rem}.doc .imageblock .title,.doc .videoblock .title{margin-top:.5rem;padding-bottom:0}.doc details{margin-left:1rem}.doc details>summary{display:block;position:relative;line-height:1.6;margin-bottom:.5rem}.doc details>summary::-webkit-details-marker{display:none}.doc details>summary:before{content:"";border:solid transparent;border-left:solid;border-width:.3em 0 .3em .5em;position:absolute;top:.5em;left:-1rem;-webkit-transform:translateX(15%);transform:translate(15%)}.doc details[open]>summary:before{border-color:currentColor transparent transparent;border-width:.5rem .3rem 0;-webkit-transform:translateY(15%);transform:translateY(15%)}.doc details>summary:after{content:"";width:1rem;height:1em;position:absolute;top:.3em;left:-1rem}.doc details.result{margin-top:.25rem}.doc details.result>summary{color:#5d5d5d;font-style:italic;margin-bottom:0}.doc details.result>.content{margin-left:-1rem}.doc .exampleblock>.content,.doc details.result>.content{background:#fff;border:.25rem solid #5d5d5d;border-radius:.5rem;padding:.75rem}.doc .exampleblock>.content:after,.doc details.result>.content:after{content:"";display:table;clear:both}.doc .exampleblock>.content>:first-child,.doc details>.content>:first-child{margin-top:0}.doc .sidebarblock{background:#e1e1e1;border-radius:.75rem;padding:.75rem 1.5rem}.doc .sidebarblock>.content>.title{font-size:1.25rem;font-weight:600;line-height:1.3;margin-bottom:.5rem;text-align:center}.doc .sidebarblock>.content>.title+*,.doc .sidebarblock>.content>:not(.title):first-child{margin-top:0}.doc .listingblock.wrap pre,.doc table.tableblock pre{white-space:pre-wrap}.doc .listingblock pre:not(.highlight),.doc .literalblock pre,.doc pre.highlight>code{background:#fafafa;-webkit-box-shadow:inset 0 0 1.75px #e1e1e1;box-shadow:inset 0 0 1.75px #e1e1e1;display:block;overflow-x:auto;padding:.875em}.doc .listingblock>.content{position:relative}.doc .source-toolbox{display:-webkit-box;display:-ms-flexbox;display:flex;visibility:hidden;position:absolute;top:.25rem;right:.5rem;color:gray;font-family:Roboto,sans-serif;font-size:.72222rem;line-height:1;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;white-space:nowrap;z-index:1}.doc .listingblock:hover .source-toolbox{visibility:visible}.doc .source-toolbox .source-lang{text-transform:uppercase;letter-spacing:.075em}.doc .source-toolbox>:not(:last-child):after{content:"|";letter-spacing:0;padding:0 1ch}.doc .source-toolbox .copy-button{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;-webkit-box-align:center;-ms-flex-align:center;align-items:center;background:none;border:none;color:inherit;outline:none;padding:0;font-size:inherit;line-height:inherit;width:1em;height:1em}.doc .source-toolbox .copy-icon{-webkit-box-flex:0;-ms-flex:none;flex:none;width:inherit;height:inherit}.doc .source-toolbox img.copy-icon{-webkit-filter:invert(50.2%);filter:invert(50.2%)}.doc .source-toolbox svg.copy-icon{fill:currentColor}.doc .source-toolbox .copy-toast{-webkit-box-flex:0;-ms-flex:none;flex:none;position:relative;display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;margin-top:1em;background-color:#333;border-radius:.25em;padding:.5em;color:#fff;cursor:auto;opacity:0;-webkit-transition:opacity .5s ease .5s;transition:opacity .5s ease .5s}.doc .source-toolbox .copy-toast:after{content:"";position:absolute;top:0;width:1em;height:1em;border:.55em solid transparent;border-left-color:#333;-webkit-transform:rotate(-90deg) translateX(50%) translateY(50%);transform:rotate(-90deg) translate(50%) translateY(50%);-webkit-transform-origin:left;transform-origin:left}.doc .source-toolbox .copy-button.clicked .copy-toast{opacity:1;-webkit-transition:none;transition:none}.doc .language-console .hljs-meta{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.doc .dlist dt{font-style:italic}.doc .dlist dd{margin:0 0 0 1.5rem}.doc .dlist dd+dt,.doc .dlist dd>p:first-child{margin-top:.5rem}.doc td.hdlist1,.doc td.hdlist2{padding:.5rem 0 0;vertical-align:top}.doc tr:first-child>.hdlist1,.doc tr:first-child>.hdlist2{padding-top:0}.doc td.hdlist1{font-weight:600;padding-right:.25rem}.doc td.hdlist2{padding-left:.25rem}.doc .colist{font-size:.88889rem;margin:.25rem 0 -.25rem}.doc .colist>table>tbody>tr>:first-child,.doc .colist>table>tr>:first-child{padding:.25em .5rem 0;vertical-align:top}.doc .colist>table>tbody>tr>:last-child,.doc .colist>table>tr>:last-child{padding:.25rem 0}.doc .conum[data-value]{border:1px solid;border-radius:100%;display:inline-block;font-family:Roboto,sans-serif;font-size:.75rem;font-style:normal;line-height:1.2;text-align:center;width:1.25em;height:1.25em;letter-spacing:-.25ex;text-indent:-.25ex}.doc .conum[data-value]:after{content:attr(data-value)}.doc .conum[data-value]+b{display:none}.doc hr{border:solid #e1e1e1;border-width:2px 0 0;height:0}.doc b.button{white-space:nowrap}.doc b.button:before{content:"[";padding-right:.25em}.doc b.button:after{content:"]";padding-left:.25em}.doc kbd{display:inline-block;font-size:.66667rem;background:#fafafa;border:1px solid #c1c1c1;border-radius:.25em;-webkit-box-shadow:0 1px 0 #c1c1c1,0 0 0 .1em #fff inset;box-shadow:0 1px #c1c1c1,inset 0 0 0 .1em #fff;padding:.25em .5em;vertical-align:text-bottom;white-space:nowrap}.doc .keyseq,.doc kbd{line-height:1}.doc .keyseq{font-size:.88889rem}.doc .keyseq kbd{margin:0 .125em}.doc .keyseq kbd:first-child{margin-left:0}.doc .keyseq kbd:last-child{margin-right:0}.doc .menuseq,.doc .path{-ms-hyphens:none;hyphens:none}.doc .menuseq i.caret:before{content:"›";font-size:1.1em;font-weight:600;line-height:.90909}.doc :not(pre).nowrap{white-space:nowrap}.doc .nobreak{-ms-hyphens:none;hyphens:none;word-wrap:normal}.doc :not(pre).pre-wrap{white-space:pre-wrap}#footnotes{font-size:.85em;line-height:1.5;margin:2rem -.5rem 0}.doc td.tableblock>.content #footnotes{margin:2rem 0 0}#footnotes hr{border-top-width:1px;margin-top:0;width:20%}#footnotes .footnote{margin:.5em 0 0 1em}#footnotes .footnote+.footnote{margin-top:.25em}#footnotes .footnote>a:first-of-type{display:inline-block;margin-left:-2em;text-align:right;width:1.5em}.toc-menu{color:#5d5d5d}.toc.sidebar .toc-menu{margin-right:.75rem;position:sticky;top:6rem}.toc .toc-menu h3{color:#333;font-size:.88889rem;font-weight:600;line-height:1.3;margin:0 -.5px;padding-bottom:.25rem}.toc.sidebar .toc-menu h3{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;height:2.5rem;-webkit-box-pack:end;-ms-flex-pack:end;justify-content:flex-end}.toc .toc-menu ul{font-size:.83333rem;line-height:1.2;list-style:none;margin:0;padding:0}.toc.sidebar .toc-menu ul{max-height:calc(100vh - 8.5rem);overflow-y:auto;-ms-scroll-chaining:none;overscroll-behavior:none}@supports (scrollbar-width: none){.toc.sidebar .toc-menu ul{scrollbar-width:none}}.toc .toc-menu ul::-webkit-scrollbar{width:0;height:0}@media screen and (min-width:1024px){.toc .toc-menu h3{font-size:.83333rem}.toc .toc-menu ul{font-size:.75rem}}.toc .toc-menu li{margin:0}.toc .toc-menu li[data-level="2"] a{padding-left:1.25rem}.toc .toc-menu li[data-level="3"] a{padding-left:2rem}.toc .toc-menu a{color:inherit;border-left:2px solid #e1e1e1;display:inline-block;padding:.25rem 0 .25rem .5rem;text-decoration:none}.sidebar.toc .toc-menu a{display:block;outline:none}.toc .toc-menu a:hover{color:#1565c0}.toc .toc-menu a.is-active{border-left-color:#2a7ee4;color:#2a7ee4}.sidebar.toc .toc-menu a:focus{background:#fafafa}.toc .toc-menu .is-hidden-toc{display:none!important}.contentSidebar{min-width:160px}.doc .videoblock .content{position:relative;width:100%;max-width:100%}.doc .videoblock .content:before{content:"";display:block;padding-top:56.25%}.doc .videoblock .content>iframe,.doc .videoblock .content>video{position:absolute;inset:0;width:100%!important;height:100%!important;border:0;background:#000;display:block}