@cutoptim/mcp 0.1.0 → 0.1.2
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/LICENSE +21 -21
- package/README.md +77 -73
- package/dist/core.gen.d.ts +7 -0
- package/dist/core.gen.js +7 -1
- package/dist/tools.gen.js +919 -32
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +61 -61
- package/server.json +49 -45
package/dist/tools.gen.js
CHANGED
|
@@ -101,9 +101,27 @@ export const TOOLS = [
|
|
|
101
101
|
},
|
|
102
102
|
"id": {
|
|
103
103
|
"description": "The row's id, so a `matchedSets` layout can name it. Any JSON value is accepted here. Only an id a set REFERS TO is checked: it must be a non-empty string of printable characters, at most 64 long, or a safe integer (`7` and `\"7\"` are the same id), and it must be on exactly one part. Every other id is ignored, whatever it holds (a float, an object, null, repeated, long, empty): always without a non-empty `matchedSets`, and on the rows no set names with one — so an ERP article number is safe to send."
|
|
104
|
+
},
|
|
105
|
+
"qr": {
|
|
106
|
+
"type": "string",
|
|
107
|
+
"minLength": 1,
|
|
108
|
+
"maxLength": 300,
|
|
109
|
+
"description": "QR payload template for every copy of this row: returned resolved in `labels[].qr` and printed as a QR code (error correction level M) on each of the row's labels in `labelsPdf`. Exactly two tokens are filled in: `{piece}` (the copy, 1-based — the `k` of the `k/n` printed on the label) and `{of}` (the row's `qty`); any other `{…}` stays as sent. At most 300 UTF-8 bytes once filled in, printable characters only (no control characters); not together with `qrs`. A wrong value is a 400 `invalid_request` naming the field, before any quota is used. Metadata only: it never changes the plan or `planHash`. On a small label format a long payload can print below 0.4 mm per module, and `warnings` then says so. 2D only."
|
|
110
|
+
},
|
|
111
|
+
"qrs": {
|
|
112
|
+
"type": "array",
|
|
113
|
+
"minItems": 1,
|
|
114
|
+
"maxItems": 2000,
|
|
115
|
+
"items": {
|
|
116
|
+
"type": "string",
|
|
117
|
+
"minLength": 1,
|
|
118
|
+
"maxLength": 300
|
|
119
|
+
},
|
|
120
|
+
"description": "One QR payload per copy of this row, used verbatim: copy `k` (the `k/n` printed on its label) gets entry `k`, in `labels[].qr` and on `labelsPdf`. Exactly `qty` entries (`qty` defaults to 1), each 1 to 300 UTF-8 bytes of printable characters; not together with `qr`. A wrong value is a 400 `invalid_request` naming the field, before any quota is used. 2D only."
|
|
104
121
|
}
|
|
105
122
|
}
|
|
106
|
-
}
|
|
123
|
+
},
|
|
124
|
+
"description": "The rectangular parts to cut, one row per part type (`w`, `h`, optional `qty`, `name`, grain, edge banding)."
|
|
107
125
|
},
|
|
108
126
|
"stock": {
|
|
109
127
|
"type": "array",
|
|
@@ -159,7 +177,8 @@ export const TOOLS = [
|
|
|
159
177
|
"description": "Opaque JSON object (any keys) echoed back VERBATIM on the matching output (a part's meta on every placed piece of it; a stock row's meta on every sheet/rod cut from it). Attach ERP article numbers, order-line ids, customer refs to reconcile the cut plan with your system. Never parsed, never affects placement. Part meta follows its request row: the meta of each row lands on exactly its qty of placed pieces, even when rows share a name; stock meta by stock-row order."
|
|
160
178
|
}
|
|
161
179
|
}
|
|
162
|
-
}
|
|
180
|
+
},
|
|
181
|
+
"description": "The sheet sizes to cut from, one row per size (`w`, `h`, optional `qty`, `price`)."
|
|
163
182
|
},
|
|
164
183
|
"options": {
|
|
165
184
|
"type": "object",
|
|
@@ -253,8 +272,148 @@ export const TOOLS = [
|
|
|
253
272
|
"setOutlines": {
|
|
254
273
|
"default": true,
|
|
255
274
|
"description": "A boolean. With `matchedSets` and the `svg` export: draw the dashed frame and the \"SET A\" badge of every set instance, in ONE separate group (`<g id=\"matched-sets\" data-role=\"annotation\">`) a laser or CNC import can drop in one move. `false` leaves that group out (the position codes in the part labels stay). Read only in a request with sets — there a value other than `true`, `false` or `null` is a 400; without sets the field is ignored, whatever it holds."
|
|
275
|
+
},
|
|
276
|
+
"labels": {
|
|
277
|
+
"type": "object",
|
|
278
|
+
"additionalProperties": false,
|
|
279
|
+
"description": "Label settings — the same settings as the Label format panel of the CutOptim app, under these names. They shape `labelsPdf` and add `piece`, `of`, `sheetNo`, `stockRow` and `sheetMeta` to every `labels[]` entry. Every field is optional; `{}` is valid and only adds those fields. Absent: the label PDF is the A4 sheet and `labels[]` is exactly as without this object. Validated STRICTLY, unlike the rest of `options`: an unknown key, a wrong type or a value out of range is a 400 `invalid_request` with `details.path`, before any call is counted (also on `/v1/validate/2d`). `null` for a field means the field is absent. Sent without `include` `labels` or `labelsPdf`, it changes nothing and the answer says so in `warnings`. 2D only.",
|
|
280
|
+
"properties": {
|
|
281
|
+
"format": {
|
|
282
|
+
"type": "string",
|
|
283
|
+
"enum": [
|
|
284
|
+
"sheet",
|
|
285
|
+
"roll",
|
|
286
|
+
"apli-03056",
|
|
287
|
+
"brother-dk-11201"
|
|
288
|
+
],
|
|
289
|
+
"default": "sheet",
|
|
290
|
+
"description": "`sheet` = the A4 sheet of labels (3 columns); `roll` = one label per page, `width` × `height` mm, for a label printer; `apli-03056` = APLI 03056 sheets (24 labels of 64.6 × 33.9 mm on A4, 3 × 8); `brother-dk-11201` = Brother DK-11201 roll labels (29 × 90 mm, one per page)."
|
|
291
|
+
},
|
|
292
|
+
"width": {
|
|
293
|
+
"type": "number",
|
|
294
|
+
"minimum": 20,
|
|
295
|
+
"maximum": 300,
|
|
296
|
+
"default": 100,
|
|
297
|
+
"description": "Label width in mm, `roll` only."
|
|
298
|
+
},
|
|
299
|
+
"height": {
|
|
300
|
+
"type": "number",
|
|
301
|
+
"minimum": 15,
|
|
302
|
+
"maximum": 300,
|
|
303
|
+
"default": 40,
|
|
304
|
+
"description": "Label height in mm, `roll` only."
|
|
305
|
+
},
|
|
306
|
+
"offset": {
|
|
307
|
+
"type": "object",
|
|
308
|
+
"additionalProperties": false,
|
|
309
|
+
"description": "Printer offset in mm: moves everything printed on the label right (`x`) and down (`y`); negative values move it back. Applied rounded to 0.1 mm.",
|
|
310
|
+
"properties": {
|
|
311
|
+
"x": {
|
|
312
|
+
"type": "number",
|
|
313
|
+
"minimum": -20,
|
|
314
|
+
"maximum": 20,
|
|
315
|
+
"default": 0,
|
|
316
|
+
"description": "Shift right in mm (negative = left)."
|
|
317
|
+
},
|
|
318
|
+
"y": {
|
|
319
|
+
"type": "number",
|
|
320
|
+
"minimum": -20,
|
|
321
|
+
"maximum": 20,
|
|
322
|
+
"default": 0,
|
|
323
|
+
"description": "Shift down in mm (negative = up)."
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
},
|
|
327
|
+
"dimSize": {
|
|
328
|
+
"type": "string",
|
|
329
|
+
"enum": [
|
|
330
|
+
"normal",
|
|
331
|
+
"large",
|
|
332
|
+
"xl"
|
|
333
|
+
],
|
|
334
|
+
"default": "normal",
|
|
335
|
+
"description": "Size of the dimension text on the label."
|
|
336
|
+
},
|
|
337
|
+
"partNo": {
|
|
338
|
+
"type": "boolean",
|
|
339
|
+
"default": false,
|
|
340
|
+
"description": "Print the part number, top left and largest: the 1-based row of the FIRST `parts` row with that name (rows sharing a name share a number; with unique names it equals `labels[].partNo`)."
|
|
341
|
+
},
|
|
342
|
+
"order": {
|
|
343
|
+
"type": "string",
|
|
344
|
+
"enum": [
|
|
345
|
+
"input",
|
|
346
|
+
"cut"
|
|
347
|
+
],
|
|
348
|
+
"default": "input",
|
|
349
|
+
"description": "`input` = labels in `parts` order; `cut` = sheet by sheet, in the order the saw plan frees the pieces."
|
|
350
|
+
},
|
|
351
|
+
"stages": {
|
|
352
|
+
"type": "array",
|
|
353
|
+
"maxItems": 6,
|
|
354
|
+
"items": {
|
|
355
|
+
"type": "string",
|
|
356
|
+
"minLength": 1,
|
|
357
|
+
"maxLength": 6
|
|
358
|
+
},
|
|
359
|
+
"description": "Work stages printed as a row of circles to tick off by pen; empty or absent = no row. Each entry is a built-in key — `rc` (rough cut), `c2s` (cut to size), `eb` (edge banded, printed only on a banded part), `s` (sanded), `d` (drilled, not printed yet) — or free text of at most 6 characters, printed as sent (keys are lower case: `RC` is free text). Spaces are trimmed; printable characters only."
|
|
360
|
+
},
|
|
361
|
+
"stageWords": {
|
|
362
|
+
"type": "object",
|
|
363
|
+
"additionalProperties": false,
|
|
364
|
+
"description": "Your own word for a built-in stage key, at most 6 characters; empty or absent = the English abbreviation (RC, C2S, EB, S, D).",
|
|
365
|
+
"properties": {
|
|
366
|
+
"rc": {
|
|
367
|
+
"type": "string",
|
|
368
|
+
"maxLength": 6,
|
|
369
|
+
"description": "Your word for `rc` (rough cut); default RC."
|
|
370
|
+
},
|
|
371
|
+
"c2s": {
|
|
372
|
+
"type": "string",
|
|
373
|
+
"maxLength": 6,
|
|
374
|
+
"description": "Your word for `c2s` (cut to size); default C2S."
|
|
375
|
+
},
|
|
376
|
+
"eb": {
|
|
377
|
+
"type": "string",
|
|
378
|
+
"maxLength": 6,
|
|
379
|
+
"description": "Your word for `eb` (edge banded); default EB."
|
|
380
|
+
},
|
|
381
|
+
"s": {
|
|
382
|
+
"type": "string",
|
|
383
|
+
"maxLength": 6,
|
|
384
|
+
"description": "Your word for `s` (sanded); default S."
|
|
385
|
+
},
|
|
386
|
+
"d": {
|
|
387
|
+
"type": "string",
|
|
388
|
+
"maxLength": 6,
|
|
389
|
+
"description": "Your word for `d` (drilled); default D."
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
},
|
|
393
|
+
"factoryEdges": {
|
|
394
|
+
"type": "boolean",
|
|
395
|
+
"default": false,
|
|
396
|
+
"description": "Mark FE on the edges of a piece that lie on a sheet edge with no `trim` on that side (the board's factory edge)."
|
|
397
|
+
},
|
|
398
|
+
"hiddenFaceHint": {
|
|
399
|
+
"type": "boolean",
|
|
400
|
+
"default": false,
|
|
401
|
+
"description": "Print the \"hidden side\" mark."
|
|
402
|
+
},
|
|
403
|
+
"parts": {
|
|
404
|
+
"type": "array",
|
|
405
|
+
"maxItems": 500,
|
|
406
|
+
"items": {
|
|
407
|
+
"type": "integer",
|
|
408
|
+
"minimum": 1,
|
|
409
|
+
"maximum": 999999
|
|
410
|
+
},
|
|
411
|
+
"description": "Print only the labels of these part numbers (the numbers `partNo` prints), e.g. to re-print after sanding. Empty or absent = all."
|
|
412
|
+
}
|
|
413
|
+
}
|
|
256
414
|
}
|
|
257
|
-
}
|
|
415
|
+
},
|
|
416
|
+
"description": "Kerf, trim, first-cut direction, cost and stock rules, effort and label output; every field is optional."
|
|
258
417
|
},
|
|
259
418
|
"engine": {
|
|
260
419
|
"type": "string",
|
|
@@ -627,6 +786,12 @@ export const TOOLS = [
|
|
|
627
786
|
"stage": {
|
|
628
787
|
"type": "integer",
|
|
629
788
|
"minimum": 1
|
|
789
|
+
},
|
|
790
|
+
"angle": {
|
|
791
|
+
"type": "number"
|
|
792
|
+
},
|
|
793
|
+
"bevel": {
|
|
794
|
+
"type": "number"
|
|
630
795
|
}
|
|
631
796
|
}
|
|
632
797
|
}
|
|
@@ -996,6 +1161,28 @@ export const TOOLS = [
|
|
|
996
1161
|
},
|
|
997
1162
|
"meta": {
|
|
998
1163
|
"type": "object"
|
|
1164
|
+
},
|
|
1165
|
+
"piece": {
|
|
1166
|
+
"type": "integer",
|
|
1167
|
+
"minimum": 1
|
|
1168
|
+
},
|
|
1169
|
+
"of": {
|
|
1170
|
+
"type": "integer",
|
|
1171
|
+
"minimum": 1
|
|
1172
|
+
},
|
|
1173
|
+
"sheetNo": {
|
|
1174
|
+
"type": "integer",
|
|
1175
|
+
"minimum": 1
|
|
1176
|
+
},
|
|
1177
|
+
"stockRow": {
|
|
1178
|
+
"type": "integer",
|
|
1179
|
+
"minimum": 0
|
|
1180
|
+
},
|
|
1181
|
+
"sheetMeta": {
|
|
1182
|
+
"type": "object"
|
|
1183
|
+
},
|
|
1184
|
+
"qr": {
|
|
1185
|
+
"type": "string"
|
|
999
1186
|
}
|
|
1000
1187
|
}
|
|
1001
1188
|
}
|
|
@@ -1139,9 +1326,81 @@ export const TOOLS = [
|
|
|
1139
1326
|
"meta": {
|
|
1140
1327
|
"type": "object",
|
|
1141
1328
|
"description": "Opaque JSON object (any keys) echoed back VERBATIM on the matching output (a part's meta on every placed piece of it; a stock row's meta on every sheet/rod cut from it). Attach ERP article numbers, order-line ids, customer refs to reconcile the cut plan with your system. Never parsed, never affects placement. Part meta follows its request row: the meta of each row lands on exactly its qty of placed pieces, even when rows share a name; stock meta by stock-row order."
|
|
1329
|
+
},
|
|
1330
|
+
"ends": {
|
|
1331
|
+
"type": "object",
|
|
1332
|
+
"description": "The angled ends of a part, read only with `options.mitrePairing`. Two parts of one section whose facing ends lie in one plane (after a turn `flip` allows) can be cut with ONE saw cut between them: the triangle between the long and the short point is not wasted. Without `mitrePairing` the ends are not used (a warning says so) and the part packs as its `length`.",
|
|
1333
|
+
"properties": {
|
|
1334
|
+
"start": {
|
|
1335
|
+
"type": "object",
|
|
1336
|
+
"required": [
|
|
1337
|
+
"angle"
|
|
1338
|
+
],
|
|
1339
|
+
"description": "One end cut of a part, in degrees from square (0 = a square end), signed. The part is measured long point to long point (`length` is its overall length). A part whose two end cuts would cross inside its section (shorter than its leads) cannot be made: a 400 `invalid_request` naming `parts[i].ends` says how long it must at least be.",
|
|
1340
|
+
"properties": {
|
|
1341
|
+
"angle": {
|
|
1342
|
+
"type": "number",
|
|
1343
|
+
"exclusiveMinimum": -90,
|
|
1344
|
+
"exclusiveMaximum": 90,
|
|
1345
|
+
"description": "The face angle: the mitre or plumb cut as seen on the `depth` side (wood: on `sh` as entered)."
|
|
1346
|
+
},
|
|
1347
|
+
"bevel": {
|
|
1348
|
+
"type": "number",
|
|
1349
|
+
"exclusiveMinimum": -90,
|
|
1350
|
+
"exclusiveMaximum": 90,
|
|
1351
|
+
"default": 0,
|
|
1352
|
+
"description": "The edge angle: the bevel as seen on the `thickness` side (wood: on `sw` as entered). A compound cut has both."
|
|
1353
|
+
}
|
|
1354
|
+
}
|
|
1355
|
+
},
|
|
1356
|
+
"end": {
|
|
1357
|
+
"type": "object",
|
|
1358
|
+
"required": [
|
|
1359
|
+
"angle"
|
|
1360
|
+
],
|
|
1361
|
+
"description": "One end cut of a part, in degrees from square (0 = a square end), signed. The part is measured long point to long point (`length` is its overall length). A part whose two end cuts would cross inside its section (shorter than its leads) cannot be made: a 400 `invalid_request` naming `parts[i].ends` says how long it must at least be.",
|
|
1362
|
+
"properties": {
|
|
1363
|
+
"angle": {
|
|
1364
|
+
"type": "number",
|
|
1365
|
+
"exclusiveMinimum": -90,
|
|
1366
|
+
"exclusiveMaximum": 90,
|
|
1367
|
+
"description": "The face angle: the mitre or plumb cut as seen on the `depth` side (wood: on `sh` as entered)."
|
|
1368
|
+
},
|
|
1369
|
+
"bevel": {
|
|
1370
|
+
"type": "number",
|
|
1371
|
+
"exclusiveMinimum": -90,
|
|
1372
|
+
"exclusiveMaximum": 90,
|
|
1373
|
+
"default": 0,
|
|
1374
|
+
"description": "The edge angle: the bevel as seen on the `thickness` side (wood: on `sw` as entered). A compound cut has both."
|
|
1375
|
+
}
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1378
|
+
}
|
|
1379
|
+
},
|
|
1380
|
+
"flip": {
|
|
1381
|
+
"type": "string",
|
|
1382
|
+
"enum": [
|
|
1383
|
+
"none",
|
|
1384
|
+
"face",
|
|
1385
|
+
"edge",
|
|
1386
|
+
"any"
|
|
1387
|
+
],
|
|
1388
|
+
"default": "none",
|
|
1389
|
+
"description": "Mitre pairing only: which 180° turns of the part on the bar are allowed, so its angled end can meet a neighbour's. `none` (default — a profiled moulding or one-sided stock), `face` (end for end, the crown or top edge stays up — roof members), `edge` (end for end over the edge — flat stock, frames), `any`."
|
|
1390
|
+
},
|
|
1391
|
+
"depth": {
|
|
1392
|
+
"type": "number",
|
|
1393
|
+
"exclusiveMinimum": 0,
|
|
1394
|
+
"description": "Mitre pairing only: the side of the bar the `angle` of `ends` is seen on. Required with `ends` (a 1D part has no cross-section to take it from). Unit-agnostic: pick one unit (mm, inch, …) for every length in the request and every length in the response is in that same unit. Nothing is converted server-side."
|
|
1395
|
+
},
|
|
1396
|
+
"thickness": {
|
|
1397
|
+
"type": "number",
|
|
1398
|
+
"exclusiveMinimum": 0,
|
|
1399
|
+
"description": "Mitre pairing only: the other side, the one the `bevel` is seen on. Required with `ends`. Unit-agnostic: pick one unit (mm, inch, …) for every length in the request and every length in the response is in that same unit. Nothing is converted server-side."
|
|
1142
1400
|
}
|
|
1143
1401
|
}
|
|
1144
|
-
}
|
|
1402
|
+
},
|
|
1403
|
+
"description": "The lengths to cut, one row per part type (`length`, optional `qty`, `name`, mitred `ends`)."
|
|
1145
1404
|
},
|
|
1146
1405
|
"stock": {
|
|
1147
1406
|
"type": "array",
|
|
@@ -1183,7 +1442,8 @@ export const TOOLS = [
|
|
|
1183
1442
|
"description": "Opaque JSON object (any keys) echoed back VERBATIM on the matching output (a part's meta on every placed piece of it; a stock row's meta on every sheet/rod cut from it). Attach ERP article numbers, order-line ids, customer refs to reconcile the cut plan with your system. Never parsed, never affects placement. Part meta follows its request row: the meta of each row lands on exactly its qty of placed pieces, even when rows share a name; stock meta by stock-row order."
|
|
1184
1443
|
}
|
|
1185
1444
|
}
|
|
1186
|
-
}
|
|
1445
|
+
},
|
|
1446
|
+
"description": "The bar lengths to cut from, one row per length (`length`, optional `qty`, `price`)."
|
|
1187
1447
|
},
|
|
1188
1448
|
"options": {
|
|
1189
1449
|
"type": "object",
|
|
@@ -1232,6 +1492,11 @@ export const TOOLS = [
|
|
|
1232
1492
|
"minimum": 0,
|
|
1233
1493
|
"description": "Output filter: report a leftover only if it is at least this long.",
|
|
1234
1494
|
"default": 0
|
|
1495
|
+
},
|
|
1496
|
+
"mitrePairing": {
|
|
1497
|
+
"type": "boolean",
|
|
1498
|
+
"default": false,
|
|
1499
|
+
"description": "Pair parts of one section whose facing ends (`parts[].ends`) can share ONE saw cut. Off by default: a request without it is solved exactly as before. On, a plan with pairs is returned only when it ranks strictly better than the unpaired plan by the packer's own ranking (parts placed first, then material — or price with `minimizeCost`); otherwise the unpaired plan comes back. Pairs only, no chains of three or more."
|
|
1235
1500
|
}
|
|
1236
1501
|
}
|
|
1237
1502
|
},
|
|
@@ -1339,6 +1604,37 @@ export const TOOLS = [
|
|
|
1339
1604
|
},
|
|
1340
1605
|
"meta": {
|
|
1341
1606
|
"type": "object"
|
|
1607
|
+
},
|
|
1608
|
+
"sharedCut": {
|
|
1609
|
+
"type": "object",
|
|
1610
|
+
"required": [
|
|
1611
|
+
"angle",
|
|
1612
|
+
"bevel",
|
|
1613
|
+
"kerfAlongAxis",
|
|
1614
|
+
"lead"
|
|
1615
|
+
],
|
|
1616
|
+
"properties": {
|
|
1617
|
+
"angle": {
|
|
1618
|
+
"type": "number"
|
|
1619
|
+
},
|
|
1620
|
+
"bevel": {
|
|
1621
|
+
"type": "number"
|
|
1622
|
+
},
|
|
1623
|
+
"kerfAlongAxis": {
|
|
1624
|
+
"type": "number"
|
|
1625
|
+
},
|
|
1626
|
+
"lead": {
|
|
1627
|
+
"type": "number"
|
|
1628
|
+
}
|
|
1629
|
+
}
|
|
1630
|
+
},
|
|
1631
|
+
"flipped": {
|
|
1632
|
+
"type": "string",
|
|
1633
|
+
"enum": [
|
|
1634
|
+
"face",
|
|
1635
|
+
"edge",
|
|
1636
|
+
"roll"
|
|
1637
|
+
]
|
|
1342
1638
|
}
|
|
1343
1639
|
}
|
|
1344
1640
|
}
|
|
@@ -1390,6 +1686,9 @@ export const TOOLS = [
|
|
|
1390
1686
|
},
|
|
1391
1687
|
"toleranceAcceptedCount": {
|
|
1392
1688
|
"type": "integer"
|
|
1689
|
+
},
|
|
1690
|
+
"sharedCuts": {
|
|
1691
|
+
"type": "integer"
|
|
1393
1692
|
}
|
|
1394
1693
|
}
|
|
1395
1694
|
},
|
|
@@ -1434,6 +1733,12 @@ export const TOOLS = [
|
|
|
1434
1733
|
"stage": {
|
|
1435
1734
|
"type": "integer",
|
|
1436
1735
|
"minimum": 1
|
|
1736
|
+
},
|
|
1737
|
+
"angle": {
|
|
1738
|
+
"type": "number"
|
|
1739
|
+
},
|
|
1740
|
+
"bevel": {
|
|
1741
|
+
"type": "number"
|
|
1437
1742
|
}
|
|
1438
1743
|
}
|
|
1439
1744
|
}
|
|
@@ -1632,9 +1937,71 @@ export const TOOLS = [
|
|
|
1632
1937
|
"meta": {
|
|
1633
1938
|
"type": "object",
|
|
1634
1939
|
"description": "Opaque JSON object (any keys) echoed back VERBATIM on the matching output (a part's meta on every placed piece of it; a stock row's meta on every sheet/rod cut from it). Attach ERP article numbers, order-line ids, customer refs to reconcile the cut plan with your system. Never parsed, never affects placement. Part meta follows its request row: the meta of each row lands on exactly its qty of placed pieces, even when rows share a name; stock meta by stock-row order."
|
|
1940
|
+
},
|
|
1941
|
+
"ends": {
|
|
1942
|
+
"type": "object",
|
|
1943
|
+
"description": "Angled ends (mitre pairing). The `angle` is seen on `sh` AS ENTERED and the `bevel` on `sw`, so send the section the way the angles were measured.",
|
|
1944
|
+
"properties": {
|
|
1945
|
+
"start": {
|
|
1946
|
+
"type": "object",
|
|
1947
|
+
"required": [
|
|
1948
|
+
"angle"
|
|
1949
|
+
],
|
|
1950
|
+
"description": "One end cut of a part, in degrees from square (0 = a square end), signed. The part is measured long point to long point (`length` is its overall length). A part whose two end cuts would cross inside its section (shorter than its leads) cannot be made: a 400 `invalid_request` naming `parts[i].ends` says how long it must at least be.",
|
|
1951
|
+
"properties": {
|
|
1952
|
+
"angle": {
|
|
1953
|
+
"type": "number",
|
|
1954
|
+
"exclusiveMinimum": -90,
|
|
1955
|
+
"exclusiveMaximum": 90,
|
|
1956
|
+
"description": "The face angle: the mitre or plumb cut as seen on the `depth` side (wood: on `sh` as entered)."
|
|
1957
|
+
},
|
|
1958
|
+
"bevel": {
|
|
1959
|
+
"type": "number",
|
|
1960
|
+
"exclusiveMinimum": -90,
|
|
1961
|
+
"exclusiveMaximum": 90,
|
|
1962
|
+
"default": 0,
|
|
1963
|
+
"description": "The edge angle: the bevel as seen on the `thickness` side (wood: on `sw` as entered). A compound cut has both."
|
|
1964
|
+
}
|
|
1965
|
+
}
|
|
1966
|
+
},
|
|
1967
|
+
"end": {
|
|
1968
|
+
"type": "object",
|
|
1969
|
+
"required": [
|
|
1970
|
+
"angle"
|
|
1971
|
+
],
|
|
1972
|
+
"description": "One end cut of a part, in degrees from square (0 = a square end), signed. The part is measured long point to long point (`length` is its overall length). A part whose two end cuts would cross inside its section (shorter than its leads) cannot be made: a 400 `invalid_request` naming `parts[i].ends` says how long it must at least be.",
|
|
1973
|
+
"properties": {
|
|
1974
|
+
"angle": {
|
|
1975
|
+
"type": "number",
|
|
1976
|
+
"exclusiveMinimum": -90,
|
|
1977
|
+
"exclusiveMaximum": 90,
|
|
1978
|
+
"description": "The face angle: the mitre or plumb cut as seen on the `depth` side (wood: on `sh` as entered)."
|
|
1979
|
+
},
|
|
1980
|
+
"bevel": {
|
|
1981
|
+
"type": "number",
|
|
1982
|
+
"exclusiveMinimum": -90,
|
|
1983
|
+
"exclusiveMaximum": 90,
|
|
1984
|
+
"default": 0,
|
|
1985
|
+
"description": "The edge angle: the bevel as seen on the `thickness` side (wood: on `sw` as entered). A compound cut has both."
|
|
1986
|
+
}
|
|
1987
|
+
}
|
|
1988
|
+
}
|
|
1989
|
+
}
|
|
1990
|
+
},
|
|
1991
|
+
"flip": {
|
|
1992
|
+
"type": "string",
|
|
1993
|
+
"enum": [
|
|
1994
|
+
"none",
|
|
1995
|
+
"face",
|
|
1996
|
+
"edge",
|
|
1997
|
+
"any"
|
|
1998
|
+
],
|
|
1999
|
+
"default": "none",
|
|
2000
|
+
"description": "Mitre pairing only: which 180° turns of the part on the bar are allowed, so its angled end can meet a neighbour's. `none` (default — a profiled moulding or one-sided stock), `face` (end for end, the crown or top edge stays up — roof members), `edge` (end for end over the edge — flat stock, frames), `any`."
|
|
1635
2001
|
}
|
|
1636
2002
|
}
|
|
1637
|
-
}
|
|
2003
|
+
},
|
|
2004
|
+
"description": "The timber parts to cut, one row per part type: cross-section `sw` × `sh`, `length`, optional `qty`."
|
|
1638
2005
|
},
|
|
1639
2006
|
"stock": {
|
|
1640
2007
|
"type": "array",
|
|
@@ -1743,6 +2110,11 @@ export const TOOLS = [
|
|
|
1743
2110
|
"minimum": 0,
|
|
1744
2111
|
"description": "Output filter: report a leftover only if it is at least this long.",
|
|
1745
2112
|
"default": 0
|
|
2113
|
+
},
|
|
2114
|
+
"mitrePairing": {
|
|
2115
|
+
"type": "boolean",
|
|
2116
|
+
"default": false,
|
|
2117
|
+
"description": "Pair parts of one section whose facing ends (`parts[].ends`) can share ONE saw cut. Off by default: a request without it is solved exactly as before. On, a plan with pairs is returned only when it ranks strictly better than the unpaired plan by the packer's own ranking (parts placed first, then material — or price with `minimizeCost`); otherwise the unpaired plan comes back. Pairs only, no chains of three or more."
|
|
1746
2118
|
}
|
|
1747
2119
|
}
|
|
1748
2120
|
},
|
|
@@ -1883,6 +2255,37 @@ export const TOOLS = [
|
|
|
1883
2255
|
},
|
|
1884
2256
|
"meta": {
|
|
1885
2257
|
"type": "object"
|
|
2258
|
+
},
|
|
2259
|
+
"sharedCut": {
|
|
2260
|
+
"type": "object",
|
|
2261
|
+
"required": [
|
|
2262
|
+
"angle",
|
|
2263
|
+
"bevel",
|
|
2264
|
+
"kerfAlongAxis",
|
|
2265
|
+
"lead"
|
|
2266
|
+
],
|
|
2267
|
+
"properties": {
|
|
2268
|
+
"angle": {
|
|
2269
|
+
"type": "number"
|
|
2270
|
+
},
|
|
2271
|
+
"bevel": {
|
|
2272
|
+
"type": "number"
|
|
2273
|
+
},
|
|
2274
|
+
"kerfAlongAxis": {
|
|
2275
|
+
"type": "number"
|
|
2276
|
+
},
|
|
2277
|
+
"lead": {
|
|
2278
|
+
"type": "number"
|
|
2279
|
+
}
|
|
2280
|
+
}
|
|
2281
|
+
},
|
|
2282
|
+
"flipped": {
|
|
2283
|
+
"type": "string",
|
|
2284
|
+
"enum": [
|
|
2285
|
+
"face",
|
|
2286
|
+
"edge",
|
|
2287
|
+
"roll"
|
|
2288
|
+
]
|
|
1886
2289
|
}
|
|
1887
2290
|
}
|
|
1888
2291
|
}
|
|
@@ -2048,6 +2451,9 @@ export const TOOLS = [
|
|
|
2048
2451
|
},
|
|
2049
2452
|
"toleranceAcceptedCount": {
|
|
2050
2453
|
"type": "integer"
|
|
2454
|
+
},
|
|
2455
|
+
"sharedCuts": {
|
|
2456
|
+
"type": "integer"
|
|
2051
2457
|
}
|
|
2052
2458
|
}
|
|
2053
2459
|
},
|
|
@@ -2094,6 +2500,12 @@ export const TOOLS = [
|
|
|
2094
2500
|
"stage": {
|
|
2095
2501
|
"type": "integer",
|
|
2096
2502
|
"minimum": 1
|
|
2503
|
+
},
|
|
2504
|
+
"angle": {
|
|
2505
|
+
"type": "number"
|
|
2506
|
+
},
|
|
2507
|
+
"bevel": {
|
|
2508
|
+
"type": "number"
|
|
2097
2509
|
}
|
|
2098
2510
|
}
|
|
2099
2511
|
}
|
|
@@ -2404,6 +2816,16 @@ export const TOOLS = [
|
|
|
2404
2816
|
"meta": {
|
|
2405
2817
|
"type": "object",
|
|
2406
2818
|
"description": "Echoed on every sheet cut from this stock row."
|
|
2819
|
+
},
|
|
2820
|
+
"roll": {
|
|
2821
|
+
"type": "boolean",
|
|
2822
|
+
"description": "Marker mode: this row is a ROLL of width `w` and free length (fabric, leather, film, any roll good). Give `w` only — no `h`, `polygon` or `exclusions` — and make it the only stock row. The answer is ONE sheet `w` wide whose `h` is the shortest length found (also `metrics.length`), edge gap included at both ends. Both engines: `lbf` answers synchronously; `max` (async) starts from that marker and spends `options.timeBudgetMs` on a strip search that may shorten it, never lengthen it."
|
|
2823
|
+
},
|
|
2824
|
+
"maxLength": {
|
|
2825
|
+
"type": "number",
|
|
2826
|
+
"exclusiveMinimum": 0,
|
|
2827
|
+
"maximum": 200000,
|
|
2828
|
+
"description": "With `roll` only: the longest the marker may be (at most 200000). Parts that do not fit within it are returned in `unplaced` — a roll never becomes a second sheet. Omit it and the length is unbounded up to 200000."
|
|
2407
2829
|
}
|
|
2408
2830
|
}
|
|
2409
2831
|
},
|
|
@@ -2687,6 +3109,9 @@ export const TOOLS = [
|
|
|
2687
3109
|
},
|
|
2688
3110
|
"pierces": {
|
|
2689
3111
|
"type": "integer"
|
|
3112
|
+
},
|
|
3113
|
+
"length": {
|
|
3114
|
+
"type": "number"
|
|
2690
3115
|
}
|
|
2691
3116
|
}
|
|
2692
3117
|
},
|
|
@@ -2744,6 +3169,32 @@ export const TOOLS = [
|
|
|
2744
3169
|
},
|
|
2745
3170
|
"qty": {
|
|
2746
3171
|
"type": "integer"
|
|
3172
|
+
},
|
|
3173
|
+
"reason": {
|
|
3174
|
+
"type": "string",
|
|
3175
|
+
"enum": [
|
|
3176
|
+
"too_large",
|
|
3177
|
+
"no_room"
|
|
3178
|
+
]
|
|
3179
|
+
},
|
|
3180
|
+
"minSheet": {
|
|
3181
|
+
"type": "object",
|
|
3182
|
+
"required": [
|
|
3183
|
+
"w",
|
|
3184
|
+
"h",
|
|
3185
|
+
"rotation"
|
|
3186
|
+
],
|
|
3187
|
+
"properties": {
|
|
3188
|
+
"w": {
|
|
3189
|
+
"type": "number"
|
|
3190
|
+
},
|
|
3191
|
+
"h": {
|
|
3192
|
+
"type": "number"
|
|
3193
|
+
},
|
|
3194
|
+
"rotation": {
|
|
3195
|
+
"type": "number"
|
|
3196
|
+
}
|
|
3197
|
+
}
|
|
2747
3198
|
}
|
|
2748
3199
|
}
|
|
2749
3200
|
}
|
|
@@ -2814,6 +3265,32 @@ export const TOOLS = [
|
|
|
2814
3265
|
},
|
|
2815
3266
|
"qty": {
|
|
2816
3267
|
"type": "integer"
|
|
3268
|
+
},
|
|
3269
|
+
"reason": {
|
|
3270
|
+
"type": "string",
|
|
3271
|
+
"enum": [
|
|
3272
|
+
"too_large",
|
|
3273
|
+
"no_room"
|
|
3274
|
+
]
|
|
3275
|
+
},
|
|
3276
|
+
"minSheet": {
|
|
3277
|
+
"type": "object",
|
|
3278
|
+
"required": [
|
|
3279
|
+
"w",
|
|
3280
|
+
"h",
|
|
3281
|
+
"rotation"
|
|
3282
|
+
],
|
|
3283
|
+
"properties": {
|
|
3284
|
+
"w": {
|
|
3285
|
+
"type": "number"
|
|
3286
|
+
},
|
|
3287
|
+
"h": {
|
|
3288
|
+
"type": "number"
|
|
3289
|
+
},
|
|
3290
|
+
"rotation": {
|
|
3291
|
+
"type": "number"
|
|
3292
|
+
}
|
|
3293
|
+
}
|
|
2817
3294
|
}
|
|
2818
3295
|
}
|
|
2819
3296
|
}
|
|
@@ -3017,12 +3494,28 @@ export const TOOLS = [
|
|
|
3017
3494
|
"meta": {
|
|
3018
3495
|
"type": "object"
|
|
3019
3496
|
},
|
|
3020
|
-
"id": {}
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
|
|
3497
|
+
"id": {},
|
|
3498
|
+
"qr": {
|
|
3499
|
+
"type": "string",
|
|
3500
|
+
"minLength": 1,
|
|
3501
|
+
"maxLength": 300
|
|
3502
|
+
},
|
|
3503
|
+
"qrs": {
|
|
3504
|
+
"type": "array",
|
|
3505
|
+
"minItems": 1,
|
|
3506
|
+
"maxItems": 2000,
|
|
3507
|
+
"items": {
|
|
3508
|
+
"type": "string",
|
|
3509
|
+
"minLength": 1,
|
|
3510
|
+
"maxLength": 300
|
|
3511
|
+
}
|
|
3512
|
+
}
|
|
3513
|
+
}
|
|
3514
|
+
},
|
|
3515
|
+
"description": "The rectangular parts to cut, one row per part type (`w`, `h`, optional `qty`, `name`, grain, edge banding)."
|
|
3516
|
+
},
|
|
3517
|
+
"stock": {
|
|
3518
|
+
"type": "array",
|
|
3026
3519
|
"minItems": 1,
|
|
3027
3520
|
"maxItems": 50,
|
|
3028
3521
|
"items": {
|
|
@@ -3067,7 +3560,8 @@ export const TOOLS = [
|
|
|
3067
3560
|
"type": "object"
|
|
3068
3561
|
}
|
|
3069
3562
|
}
|
|
3070
|
-
}
|
|
3563
|
+
},
|
|
3564
|
+
"description": "The sheet sizes to cut from, one row per size (`w`, `h`, optional `qty`, `price`)."
|
|
3071
3565
|
},
|
|
3072
3566
|
"options": {
|
|
3073
3567
|
"type": "object",
|
|
@@ -3146,8 +3640,128 @@ export const TOOLS = [
|
|
|
3146
3640
|
},
|
|
3147
3641
|
"setOutlines": {
|
|
3148
3642
|
"default": true
|
|
3643
|
+
},
|
|
3644
|
+
"labels": {
|
|
3645
|
+
"type": "object",
|
|
3646
|
+
"additionalProperties": false,
|
|
3647
|
+
"properties": {
|
|
3648
|
+
"format": {
|
|
3649
|
+
"type": "string",
|
|
3650
|
+
"enum": [
|
|
3651
|
+
"sheet",
|
|
3652
|
+
"roll",
|
|
3653
|
+
"apli-03056",
|
|
3654
|
+
"brother-dk-11201"
|
|
3655
|
+
],
|
|
3656
|
+
"default": "sheet"
|
|
3657
|
+
},
|
|
3658
|
+
"width": {
|
|
3659
|
+
"type": "number",
|
|
3660
|
+
"minimum": 20,
|
|
3661
|
+
"maximum": 300,
|
|
3662
|
+
"default": 100
|
|
3663
|
+
},
|
|
3664
|
+
"height": {
|
|
3665
|
+
"type": "number",
|
|
3666
|
+
"minimum": 15,
|
|
3667
|
+
"maximum": 300,
|
|
3668
|
+
"default": 40
|
|
3669
|
+
},
|
|
3670
|
+
"offset": {
|
|
3671
|
+
"type": "object",
|
|
3672
|
+
"additionalProperties": false,
|
|
3673
|
+
"properties": {
|
|
3674
|
+
"x": {
|
|
3675
|
+
"type": "number",
|
|
3676
|
+
"minimum": -20,
|
|
3677
|
+
"maximum": 20,
|
|
3678
|
+
"default": 0
|
|
3679
|
+
},
|
|
3680
|
+
"y": {
|
|
3681
|
+
"type": "number",
|
|
3682
|
+
"minimum": -20,
|
|
3683
|
+
"maximum": 20,
|
|
3684
|
+
"default": 0
|
|
3685
|
+
}
|
|
3686
|
+
}
|
|
3687
|
+
},
|
|
3688
|
+
"dimSize": {
|
|
3689
|
+
"type": "string",
|
|
3690
|
+
"enum": [
|
|
3691
|
+
"normal",
|
|
3692
|
+
"large",
|
|
3693
|
+
"xl"
|
|
3694
|
+
],
|
|
3695
|
+
"default": "normal"
|
|
3696
|
+
},
|
|
3697
|
+
"partNo": {
|
|
3698
|
+
"type": "boolean",
|
|
3699
|
+
"default": false
|
|
3700
|
+
},
|
|
3701
|
+
"order": {
|
|
3702
|
+
"type": "string",
|
|
3703
|
+
"enum": [
|
|
3704
|
+
"input",
|
|
3705
|
+
"cut"
|
|
3706
|
+
],
|
|
3707
|
+
"default": "input"
|
|
3708
|
+
},
|
|
3709
|
+
"stages": {
|
|
3710
|
+
"type": "array",
|
|
3711
|
+
"maxItems": 6,
|
|
3712
|
+
"items": {
|
|
3713
|
+
"type": "string",
|
|
3714
|
+
"minLength": 1,
|
|
3715
|
+
"maxLength": 6
|
|
3716
|
+
}
|
|
3717
|
+
},
|
|
3718
|
+
"stageWords": {
|
|
3719
|
+
"type": "object",
|
|
3720
|
+
"additionalProperties": false,
|
|
3721
|
+
"properties": {
|
|
3722
|
+
"rc": {
|
|
3723
|
+
"type": "string",
|
|
3724
|
+
"maxLength": 6
|
|
3725
|
+
},
|
|
3726
|
+
"c2s": {
|
|
3727
|
+
"type": "string",
|
|
3728
|
+
"maxLength": 6
|
|
3729
|
+
},
|
|
3730
|
+
"eb": {
|
|
3731
|
+
"type": "string",
|
|
3732
|
+
"maxLength": 6
|
|
3733
|
+
},
|
|
3734
|
+
"s": {
|
|
3735
|
+
"type": "string",
|
|
3736
|
+
"maxLength": 6
|
|
3737
|
+
},
|
|
3738
|
+
"d": {
|
|
3739
|
+
"type": "string",
|
|
3740
|
+
"maxLength": 6
|
|
3741
|
+
}
|
|
3742
|
+
}
|
|
3743
|
+
},
|
|
3744
|
+
"factoryEdges": {
|
|
3745
|
+
"type": "boolean",
|
|
3746
|
+
"default": false
|
|
3747
|
+
},
|
|
3748
|
+
"hiddenFaceHint": {
|
|
3749
|
+
"type": "boolean",
|
|
3750
|
+
"default": false
|
|
3751
|
+
},
|
|
3752
|
+
"parts": {
|
|
3753
|
+
"type": "array",
|
|
3754
|
+
"maxItems": 500,
|
|
3755
|
+
"items": {
|
|
3756
|
+
"type": "integer",
|
|
3757
|
+
"minimum": 1,
|
|
3758
|
+
"maximum": 999999
|
|
3759
|
+
}
|
|
3760
|
+
}
|
|
3761
|
+
}
|
|
3149
3762
|
}
|
|
3150
|
-
}
|
|
3763
|
+
},
|
|
3764
|
+
"description": "Kerf, trim, first-cut direction, cost and stock rules, effort and label output; every field is optional."
|
|
3151
3765
|
},
|
|
3152
3766
|
"engine": {
|
|
3153
3767
|
"type": "string",
|
|
@@ -3156,7 +3770,8 @@ export const TOOLS = [
|
|
|
3156
3770
|
"balanced",
|
|
3157
3771
|
"max"
|
|
3158
3772
|
],
|
|
3159
|
-
"default": "heuristic"
|
|
3773
|
+
"default": "heuristic",
|
|
3774
|
+
"description": "Which optimizer to run. `heuristic` is the guillotine multi-strategy packer: highest yield, every layout edge-to-edge saw-cuttable, always a full `cutPlan`. `balanced` is a MaxRects free-nesting packer: much faster on large jobs for a small yield cost, but its layouts are often not guillotine (`guillotineValid: false`, `cutPlan: null`), and it does not model `tolerance`, `minimizeCost`, `grainGroup`, `maxCutStages` or `minimizeRotations` — set one of those and a string in `warnings` tells you it was ignored. `max` is the ASYNCHRONOUS tree-search tier (2D only): it reaches the proven optimum on far more jobs at the cost of seconds-to-a-minute per solve, so instead of a plan it returns **202** with a `jobId` — poll `GET /v1/jobs/{id}` for the result. Still deterministic and guillotine-valid. Where the tier is not enabled on a deployment, `engine: \"max\"` fails closed with **503**. **What `max` models.** It packs ONE stock format at full sheet size with unlimited supply and a fixed 3-stage guillotine pattern. Anything that would make the returned plan physically WRONG is therefore REFUSED with **400** at submission — before a call is reserved and before you wait for the solve: a second `stock` row, `options.trim`, `options.respectStock`, any `material`, any `grainGroup`, a non-empty `matchedSets` (an empty one is fine). Options that only make the plan less tuned are accepted and listed in `warnings`: `tolerance`, `minimizeCost`, `maxCutStages` (fixed at 3), `minimizeRotations`, `firstCut`, `effort`. A `max` result reports no `offcuts`. Send those jobs to `heuristic`. The default never changes silently."
|
|
3160
3775
|
},
|
|
3161
3776
|
"include": {
|
|
3162
3777
|
"type": "array",
|
|
@@ -3173,7 +3788,8 @@ export const TOOLS = [
|
|
|
3173
3788
|
"pdf",
|
|
3174
3789
|
"labelsPdf"
|
|
3175
3790
|
]
|
|
3176
|
-
}
|
|
3791
|
+
},
|
|
3792
|
+
"description": "Three kinds of token. NARROWING (`cutPlan`, `offcuts`): omit the field entirely to get both; a present array keeps only the narrowing tokens it lists (an empty array drops both). ADDITIVE EXPORT (`svg`, `csv`, `dxf`): each adds an inline export STRING to the response (`svg` a standalone 2D layout — 2D only, a warning is returned for 1D/wood; `dxf` an R12/AC1009 drawing; `csv` a cut list, RFC 4180 quoted (a part name with a comma or a quote stays one field) and formula-injection-guarded (a name beginning with `=`, `+`, `-`, `@`, TAB or CR is prefixed with an apostrophe so a spreadsheet reads it as text, not a formula — CWE-1236). 2D DATA (`labels`, `planHash`, `pdf`, `labelsPdf`): `labels` adds per-piece label data (`labels[]`, see `Label2D`), `planHash` a 64-hex fingerprint of the plan (the same plan always gives the same hash), `pdf` the cutting-plan PDF and `labelsPdf` the label PDF, both base64-encoded and drawn by the same code as the CutOptim app. These four are 2D only: a 1D or wood request returns a `warnings` entry instead. `pdf` renders at most 500 parts (total quantity); a larger 2D request with `pdf` is a 413 `too_large` with `details.path: \"include\"`. Export and data tokens do not affect narrowing, so `[\"svg\"]` adds svg and — listing no narrowing token — drops cutPlan/offcuts; use `[\"cutPlan\",\"offcuts\",\"svg\"]` to keep everything."
|
|
3177
3793
|
},
|
|
3178
3794
|
"matchedSets": {
|
|
3179
3795
|
"maxItems": 50,
|
|
@@ -3254,7 +3870,8 @@ export const TOOLS = [
|
|
|
3254
3870
|
}
|
|
3255
3871
|
}
|
|
3256
3872
|
}
|
|
3257
|
-
}
|
|
3873
|
+
},
|
|
3874
|
+
"description": "Matched sets (grain matching): groups of parts cut side by side from one piece of board. Send a NON-EMPTY ARRAY of sets (at most 50); members are named by `parts[].id`. Only a non-empty array switches the feature on: absent, `null`, `[]` — and any value that is not an array — is a request without sets, answered exactly as before (no error). With sets the response adds `sheets[].parts[].matchedSet` on every member and a `matchedSets` rollup; `csv` gains `Set` and `Position` columns at the end, `svg` the `matched-sets` frame group, `dxf` the position code on LABELS; `pdf` and `labelsPdf` draw the members as ordinary parts for now (a `warnings` line says so; the set marks are in `sheets[].parts[].matchedSet`, `csv` and `svg`). Engine `max` refuses a non-empty array (400 `details.unsupported`); an empty one is fine. 2D only: the 1D, wood and nest endpoints ignore this field and `parts[].id`."
|
|
3258
3875
|
}
|
|
3259
3876
|
}
|
|
3260
3877
|
},
|
|
@@ -3380,9 +3997,71 @@ export const TOOLS = [
|
|
|
3380
3997
|
},
|
|
3381
3998
|
"meta": {
|
|
3382
3999
|
"type": "object"
|
|
4000
|
+
},
|
|
4001
|
+
"ends": {
|
|
4002
|
+
"type": "object",
|
|
4003
|
+
"properties": {
|
|
4004
|
+
"start": {
|
|
4005
|
+
"type": "object",
|
|
4006
|
+
"required": [
|
|
4007
|
+
"angle"
|
|
4008
|
+
],
|
|
4009
|
+
"properties": {
|
|
4010
|
+
"angle": {
|
|
4011
|
+
"type": "number",
|
|
4012
|
+
"exclusiveMinimum": -90,
|
|
4013
|
+
"exclusiveMaximum": 90
|
|
4014
|
+
},
|
|
4015
|
+
"bevel": {
|
|
4016
|
+
"type": "number",
|
|
4017
|
+
"exclusiveMinimum": -90,
|
|
4018
|
+
"exclusiveMaximum": 90,
|
|
4019
|
+
"default": 0
|
|
4020
|
+
}
|
|
4021
|
+
}
|
|
4022
|
+
},
|
|
4023
|
+
"end": {
|
|
4024
|
+
"type": "object",
|
|
4025
|
+
"required": [
|
|
4026
|
+
"angle"
|
|
4027
|
+
],
|
|
4028
|
+
"properties": {
|
|
4029
|
+
"angle": {
|
|
4030
|
+
"type": "number",
|
|
4031
|
+
"exclusiveMinimum": -90,
|
|
4032
|
+
"exclusiveMaximum": 90
|
|
4033
|
+
},
|
|
4034
|
+
"bevel": {
|
|
4035
|
+
"type": "number",
|
|
4036
|
+
"exclusiveMinimum": -90,
|
|
4037
|
+
"exclusiveMaximum": 90,
|
|
4038
|
+
"default": 0
|
|
4039
|
+
}
|
|
4040
|
+
}
|
|
4041
|
+
}
|
|
4042
|
+
}
|
|
4043
|
+
},
|
|
4044
|
+
"flip": {
|
|
4045
|
+
"type": "string",
|
|
4046
|
+
"enum": [
|
|
4047
|
+
"none",
|
|
4048
|
+
"face",
|
|
4049
|
+
"edge",
|
|
4050
|
+
"any"
|
|
4051
|
+
],
|
|
4052
|
+
"default": "none"
|
|
4053
|
+
},
|
|
4054
|
+
"depth": {
|
|
4055
|
+
"type": "number",
|
|
4056
|
+
"exclusiveMinimum": 0
|
|
4057
|
+
},
|
|
4058
|
+
"thickness": {
|
|
4059
|
+
"type": "number",
|
|
4060
|
+
"exclusiveMinimum": 0
|
|
3383
4061
|
}
|
|
3384
4062
|
}
|
|
3385
|
-
}
|
|
4063
|
+
},
|
|
4064
|
+
"description": "The lengths to cut, one row per part type (`length`, optional `qty`, `name`, mitred `ends`)."
|
|
3386
4065
|
},
|
|
3387
4066
|
"stock": {
|
|
3388
4067
|
"type": "array",
|
|
@@ -3418,7 +4097,8 @@ export const TOOLS = [
|
|
|
3418
4097
|
"type": "object"
|
|
3419
4098
|
}
|
|
3420
4099
|
}
|
|
3421
|
-
}
|
|
4100
|
+
},
|
|
4101
|
+
"description": "The bar lengths to cut from, one row per length (`length`, optional `qty`, `price`)."
|
|
3422
4102
|
},
|
|
3423
4103
|
"options": {
|
|
3424
4104
|
"type": "object",
|
|
@@ -3458,8 +4138,13 @@ export const TOOLS = [
|
|
|
3458
4138
|
"type": "number",
|
|
3459
4139
|
"minimum": 0,
|
|
3460
4140
|
"default": 0
|
|
4141
|
+
},
|
|
4142
|
+
"mitrePairing": {
|
|
4143
|
+
"type": "boolean",
|
|
4144
|
+
"default": false
|
|
3461
4145
|
}
|
|
3462
|
-
}
|
|
4146
|
+
},
|
|
4147
|
+
"description": "The 1D option set is deliberately smaller: there is no `firstCut`, `maxCutStages` or `minimizeRotations`, because none of them means anything on a bar."
|
|
3463
4148
|
},
|
|
3464
4149
|
"engine": {
|
|
3465
4150
|
"type": "string",
|
|
@@ -3467,7 +4152,8 @@ export const TOOLS = [
|
|
|
3467
4152
|
"heuristic",
|
|
3468
4153
|
"balanced"
|
|
3469
4154
|
],
|
|
3470
|
-
"default": "heuristic"
|
|
4155
|
+
"default": "heuristic",
|
|
4156
|
+
"description": "`max` is not offered here: it is a 2D (and, separately, nesting) tier, and `engine: \"max\"` on this path is a **400** before a call is charged. In 1D `balanced` resolves to the same packer as `heuristic` — the linear packer is already a best-of-multiple-strategies search, so there is no separate balanced mode. The value is accepted and echoed back so a single client can send one engine id for both endpoints."
|
|
3471
4157
|
},
|
|
3472
4158
|
"include": {
|
|
3473
4159
|
"type": "array",
|
|
@@ -3484,7 +4170,8 @@ export const TOOLS = [
|
|
|
3484
4170
|
"pdf",
|
|
3485
4171
|
"labelsPdf"
|
|
3486
4172
|
]
|
|
3487
|
-
}
|
|
4173
|
+
},
|
|
4174
|
+
"description": "Three kinds of token. NARROWING (`cutPlan`, `offcuts`): omit the field entirely to get both; a present array keeps only the narrowing tokens it lists (an empty array drops both). ADDITIVE EXPORT (`svg`, `csv`, `dxf`): each adds an inline export STRING to the response (`svg` a standalone 2D layout — 2D only, a warning is returned for 1D/wood; `dxf` an R12/AC1009 drawing; `csv` a cut list, RFC 4180 quoted (a part name with a comma or a quote stays one field) and formula-injection-guarded (a name beginning with `=`, `+`, `-`, `@`, TAB or CR is prefixed with an apostrophe so a spreadsheet reads it as text, not a formula — CWE-1236). 2D DATA (`labels`, `planHash`, `pdf`, `labelsPdf`): `labels` adds per-piece label data (`labels[]`, see `Label2D`), `planHash` a 64-hex fingerprint of the plan (the same plan always gives the same hash), `pdf` the cutting-plan PDF and `labelsPdf` the label PDF, both base64-encoded and drawn by the same code as the CutOptim app. These four are 2D only: a 1D or wood request returns a `warnings` entry instead. `pdf` renders at most 500 parts (total quantity); a larger 2D request with `pdf` is a 413 `too_large` with `details.path: \"include\"`. Export and data tokens do not affect narrowing, so `[\"svg\"]` adds svg and — listing no narrowing token — drops cutPlan/offcuts; use `[\"cutPlan\",\"offcuts\",\"svg\"]` to keep everything."
|
|
3488
4175
|
}
|
|
3489
4176
|
}
|
|
3490
4177
|
},
|
|
@@ -3620,9 +4307,63 @@ export const TOOLS = [
|
|
|
3620
4307
|
},
|
|
3621
4308
|
"meta": {
|
|
3622
4309
|
"type": "object"
|
|
4310
|
+
},
|
|
4311
|
+
"ends": {
|
|
4312
|
+
"type": "object",
|
|
4313
|
+
"properties": {
|
|
4314
|
+
"start": {
|
|
4315
|
+
"type": "object",
|
|
4316
|
+
"required": [
|
|
4317
|
+
"angle"
|
|
4318
|
+
],
|
|
4319
|
+
"properties": {
|
|
4320
|
+
"angle": {
|
|
4321
|
+
"type": "number",
|
|
4322
|
+
"exclusiveMinimum": -90,
|
|
4323
|
+
"exclusiveMaximum": 90
|
|
4324
|
+
},
|
|
4325
|
+
"bevel": {
|
|
4326
|
+
"type": "number",
|
|
4327
|
+
"exclusiveMinimum": -90,
|
|
4328
|
+
"exclusiveMaximum": 90,
|
|
4329
|
+
"default": 0
|
|
4330
|
+
}
|
|
4331
|
+
}
|
|
4332
|
+
},
|
|
4333
|
+
"end": {
|
|
4334
|
+
"type": "object",
|
|
4335
|
+
"required": [
|
|
4336
|
+
"angle"
|
|
4337
|
+
],
|
|
4338
|
+
"properties": {
|
|
4339
|
+
"angle": {
|
|
4340
|
+
"type": "number",
|
|
4341
|
+
"exclusiveMinimum": -90,
|
|
4342
|
+
"exclusiveMaximum": 90
|
|
4343
|
+
},
|
|
4344
|
+
"bevel": {
|
|
4345
|
+
"type": "number",
|
|
4346
|
+
"exclusiveMinimum": -90,
|
|
4347
|
+
"exclusiveMaximum": 90,
|
|
4348
|
+
"default": 0
|
|
4349
|
+
}
|
|
4350
|
+
}
|
|
4351
|
+
}
|
|
4352
|
+
}
|
|
4353
|
+
},
|
|
4354
|
+
"flip": {
|
|
4355
|
+
"type": "string",
|
|
4356
|
+
"enum": [
|
|
4357
|
+
"none",
|
|
4358
|
+
"face",
|
|
4359
|
+
"edge",
|
|
4360
|
+
"any"
|
|
4361
|
+
],
|
|
4362
|
+
"default": "none"
|
|
3623
4363
|
}
|
|
3624
4364
|
}
|
|
3625
|
-
}
|
|
4365
|
+
},
|
|
4366
|
+
"description": "The timber parts to cut, one row per part type: cross-section `sw` × `sh`, `length`, optional `qty`."
|
|
3626
4367
|
},
|
|
3627
4368
|
"stock": {
|
|
3628
4369
|
"type": "array",
|
|
@@ -3672,7 +4413,8 @@ export const TOOLS = [
|
|
|
3672
4413
|
"type": "object"
|
|
3673
4414
|
}
|
|
3674
4415
|
}
|
|
3675
|
-
}
|
|
4416
|
+
},
|
|
4417
|
+
"description": "At most 50 rows. Since every cross-section needs at least one stock row, this is also the practical ceiling on cross-sections in a single job; a wider catalogue should be split into several requests."
|
|
3676
4418
|
},
|
|
3677
4419
|
"options": {
|
|
3678
4420
|
"type": "object",
|
|
@@ -3712,8 +4454,13 @@ export const TOOLS = [
|
|
|
3712
4454
|
"type": "number",
|
|
3713
4455
|
"minimum": 0,
|
|
3714
4456
|
"default": 0
|
|
4457
|
+
},
|
|
4458
|
+
"mitrePairing": {
|
|
4459
|
+
"type": "boolean",
|
|
4460
|
+
"default": false
|
|
3715
4461
|
}
|
|
3716
|
-
}
|
|
4462
|
+
},
|
|
4463
|
+
"description": "Identical to `Options1D` — a cross-section changes what fits, not how a bar is cut."
|
|
3717
4464
|
},
|
|
3718
4465
|
"engine": {
|
|
3719
4466
|
"type": "string",
|
|
@@ -3721,7 +4468,8 @@ export const TOOLS = [
|
|
|
3721
4468
|
"heuristic",
|
|
3722
4469
|
"balanced"
|
|
3723
4470
|
],
|
|
3724
|
-
"default": "heuristic"
|
|
4471
|
+
"default": "heuristic",
|
|
4472
|
+
"description": "As in 1D, `max` is not offered here (a **400** before a call is charged). `balanced` resolves to the same packer as `heuristic`: within a section a timber job is a length problem, and free nesting has nothing to offer it. The value is accepted, echoed back, and a warning states which packer actually ran."
|
|
3725
4473
|
},
|
|
3726
4474
|
"include": {
|
|
3727
4475
|
"type": "array",
|
|
@@ -3738,7 +4486,8 @@ export const TOOLS = [
|
|
|
3738
4486
|
"pdf",
|
|
3739
4487
|
"labelsPdf"
|
|
3740
4488
|
]
|
|
3741
|
-
}
|
|
4489
|
+
},
|
|
4490
|
+
"description": "Three kinds of token. NARROWING (`cutPlan`, `offcuts`): omit the field entirely to get both; a present array keeps only the narrowing tokens it lists (an empty array drops both). ADDITIVE EXPORT (`svg`, `csv`, `dxf`): each adds an inline export STRING to the response (`svg` a standalone 2D layout — 2D only, a warning is returned for 1D/wood; `dxf` an R12/AC1009 drawing; `csv` a cut list, RFC 4180 quoted (a part name with a comma or a quote stays one field) and formula-injection-guarded (a name beginning with `=`, `+`, `-`, `@`, TAB or CR is prefixed with an apostrophe so a spreadsheet reads it as text, not a formula — CWE-1236). 2D DATA (`labels`, `planHash`, `pdf`, `labelsPdf`): `labels` adds per-piece label data (`labels[]`, see `Label2D`), `planHash` a 64-hex fingerprint of the plan (the same plan always gives the same hash), `pdf` the cutting-plan PDF and `labelsPdf` the label PDF, both base64-encoded and drawn by the same code as the CutOptim app. These four are 2D only: a 1D or wood request returns a `warnings` entry instead. `pdf` renders at most 500 parts (total quantity); a larger 2D request with `pdf` is a 413 `too_large` with `details.path: \"include\"`. Export and data tokens do not affect narrowing, so `[\"svg\"]` adds svg and — listing no narrowing token — drops cutPlan/offcuts; use `[\"cutPlan\",\"offcuts\",\"svg\"]` to keep everything."
|
|
3742
4491
|
}
|
|
3743
4492
|
}
|
|
3744
4493
|
},
|
|
@@ -3947,7 +4696,8 @@ export const TOOLS = [
|
|
|
3947
4696
|
"type": "object"
|
|
3948
4697
|
}
|
|
3949
4698
|
}
|
|
3950
|
-
}
|
|
4699
|
+
},
|
|
4700
|
+
"description": "One or more parts to nest, one NestPart per row."
|
|
3951
4701
|
},
|
|
3952
4702
|
"stock": {
|
|
3953
4703
|
"type": "array",
|
|
@@ -4022,9 +4772,18 @@ export const TOOLS = [
|
|
|
4022
4772
|
},
|
|
4023
4773
|
"meta": {
|
|
4024
4774
|
"type": "object"
|
|
4775
|
+
},
|
|
4776
|
+
"roll": {
|
|
4777
|
+
"type": "boolean"
|
|
4778
|
+
},
|
|
4779
|
+
"maxLength": {
|
|
4780
|
+
"type": "number",
|
|
4781
|
+
"exclusiveMinimum": 0,
|
|
4782
|
+
"maximum": 200000
|
|
4025
4783
|
}
|
|
4026
4784
|
}
|
|
4027
|
-
}
|
|
4785
|
+
},
|
|
4786
|
+
"description": "One or more sheet types, one NestStock per row."
|
|
4028
4787
|
},
|
|
4029
4788
|
"options": {
|
|
4030
4789
|
"type": "object",
|
|
@@ -4068,7 +4827,8 @@ export const TOOLS = [
|
|
|
4068
4827
|
],
|
|
4069
4828
|
"default": "box"
|
|
4070
4829
|
}
|
|
4071
|
-
}
|
|
4830
|
+
},
|
|
4831
|
+
"description": "Solve options. All optional."
|
|
4072
4832
|
},
|
|
4073
4833
|
"engine": {
|
|
4074
4834
|
"type": "string",
|
|
@@ -4077,7 +4837,8 @@ export const TOOLS = [
|
|
|
4077
4837
|
"max",
|
|
4078
4838
|
"sparrow"
|
|
4079
4839
|
],
|
|
4080
|
-
"default": "lbf"
|
|
4840
|
+
"default": "lbf",
|
|
4841
|
+
"description": "`lbf` (default) is single-pass, synchronous and instant. `max` is ASYNCHRONOUS: 202 + poll `GET /v1/jobs/{id}`; it runs `lbf` first, then a time-budgeted search that fills sheets one at a time looking for FEWER sheets, and never returns more than `lbf`, nor a plan that ranks worse (price with `minimizeCost`, otherwise sheet area). It accepts several sheet sizes per material and `respectStock`; a `polygon` sheet or exclusion zones are served by `lbf` inside the job, with a warning. `sparrow` is a deprecated alias of `max`."
|
|
4081
4842
|
},
|
|
4082
4843
|
"include": {
|
|
4083
4844
|
"type": "array",
|
|
@@ -4087,7 +4848,8 @@ export const TOOLS = [
|
|
|
4087
4848
|
"svg",
|
|
4088
4849
|
"dxf"
|
|
4089
4850
|
]
|
|
4090
|
-
}
|
|
4851
|
+
},
|
|
4852
|
+
"description": "Additive inline export of the achieved layout. `svg` returns a self-contained, styled `<svg>` string (one titled band per sheet, parts drawn as filled polygons with holes, exclusion zones hatched); `dxf` returns an R12 document (closed `POLYLINE`/`VERTEX` outlines on STOCK/PARTS/HOLES/ZONES layers, part names on LABELS). Both are unit-agnostic, exactly like the request coordinates. The geometry in `sheets[]` is returned either way."
|
|
4091
4853
|
}
|
|
4092
4854
|
}
|
|
4093
4855
|
},
|
|
@@ -4472,6 +5234,12 @@ export const TOOLS = [
|
|
|
4472
5234
|
"stage": {
|
|
4473
5235
|
"type": "integer",
|
|
4474
5236
|
"minimum": 1
|
|
5237
|
+
},
|
|
5238
|
+
"angle": {
|
|
5239
|
+
"type": "number"
|
|
5240
|
+
},
|
|
5241
|
+
"bevel": {
|
|
5242
|
+
"type": "number"
|
|
4475
5243
|
}
|
|
4476
5244
|
}
|
|
4477
5245
|
}
|
|
@@ -4841,6 +5609,28 @@ export const TOOLS = [
|
|
|
4841
5609
|
},
|
|
4842
5610
|
"meta": {
|
|
4843
5611
|
"type": "object"
|
|
5612
|
+
},
|
|
5613
|
+
"piece": {
|
|
5614
|
+
"type": "integer",
|
|
5615
|
+
"minimum": 1
|
|
5616
|
+
},
|
|
5617
|
+
"of": {
|
|
5618
|
+
"type": "integer",
|
|
5619
|
+
"minimum": 1
|
|
5620
|
+
},
|
|
5621
|
+
"sheetNo": {
|
|
5622
|
+
"type": "integer",
|
|
5623
|
+
"minimum": 1
|
|
5624
|
+
},
|
|
5625
|
+
"stockRow": {
|
|
5626
|
+
"type": "integer",
|
|
5627
|
+
"minimum": 0
|
|
5628
|
+
},
|
|
5629
|
+
"sheetMeta": {
|
|
5630
|
+
"type": "object"
|
|
5631
|
+
},
|
|
5632
|
+
"qr": {
|
|
5633
|
+
"type": "string"
|
|
4844
5634
|
}
|
|
4845
5635
|
}
|
|
4846
5636
|
}
|
|
@@ -5067,6 +5857,9 @@ export const TOOLS = [
|
|
|
5067
5857
|
},
|
|
5068
5858
|
"pierces": {
|
|
5069
5859
|
"type": "integer"
|
|
5860
|
+
},
|
|
5861
|
+
"length": {
|
|
5862
|
+
"type": "number"
|
|
5070
5863
|
}
|
|
5071
5864
|
}
|
|
5072
5865
|
},
|
|
@@ -5124,6 +5917,32 @@ export const TOOLS = [
|
|
|
5124
5917
|
},
|
|
5125
5918
|
"qty": {
|
|
5126
5919
|
"type": "integer"
|
|
5920
|
+
},
|
|
5921
|
+
"reason": {
|
|
5922
|
+
"type": "string",
|
|
5923
|
+
"enum": [
|
|
5924
|
+
"too_large",
|
|
5925
|
+
"no_room"
|
|
5926
|
+
]
|
|
5927
|
+
},
|
|
5928
|
+
"minSheet": {
|
|
5929
|
+
"type": "object",
|
|
5930
|
+
"required": [
|
|
5931
|
+
"w",
|
|
5932
|
+
"h",
|
|
5933
|
+
"rotation"
|
|
5934
|
+
],
|
|
5935
|
+
"properties": {
|
|
5936
|
+
"w": {
|
|
5937
|
+
"type": "number"
|
|
5938
|
+
},
|
|
5939
|
+
"h": {
|
|
5940
|
+
"type": "number"
|
|
5941
|
+
},
|
|
5942
|
+
"rotation": {
|
|
5943
|
+
"type": "number"
|
|
5944
|
+
}
|
|
5945
|
+
}
|
|
5127
5946
|
}
|
|
5128
5947
|
}
|
|
5129
5948
|
}
|
|
@@ -5194,6 +6013,32 @@ export const TOOLS = [
|
|
|
5194
6013
|
},
|
|
5195
6014
|
"qty": {
|
|
5196
6015
|
"type": "integer"
|
|
6016
|
+
},
|
|
6017
|
+
"reason": {
|
|
6018
|
+
"type": "string",
|
|
6019
|
+
"enum": [
|
|
6020
|
+
"too_large",
|
|
6021
|
+
"no_room"
|
|
6022
|
+
]
|
|
6023
|
+
},
|
|
6024
|
+
"minSheet": {
|
|
6025
|
+
"type": "object",
|
|
6026
|
+
"required": [
|
|
6027
|
+
"w",
|
|
6028
|
+
"h",
|
|
6029
|
+
"rotation"
|
|
6030
|
+
],
|
|
6031
|
+
"properties": {
|
|
6032
|
+
"w": {
|
|
6033
|
+
"type": "number"
|
|
6034
|
+
},
|
|
6035
|
+
"h": {
|
|
6036
|
+
"type": "number"
|
|
6037
|
+
},
|
|
6038
|
+
"rotation": {
|
|
6039
|
+
"type": "number"
|
|
6040
|
+
}
|
|
6041
|
+
}
|
|
5197
6042
|
}
|
|
5198
6043
|
}
|
|
5199
6044
|
}
|
|
@@ -5334,6 +6179,48 @@ export const TOOLS = [
|
|
|
5334
6179
|
"enum": [
|
|
5335
6180
|
"tenant"
|
|
5336
6181
|
]
|
|
6182
|
+
},
|
|
6183
|
+
"trial": {
|
|
6184
|
+
"type": "object",
|
|
6185
|
+
"required": [
|
|
6186
|
+
"endsAt",
|
|
6187
|
+
"callsLimit",
|
|
6188
|
+
"callsUsed",
|
|
6189
|
+
"callsRemaining",
|
|
6190
|
+
"maxJobsLimit",
|
|
6191
|
+
"maxJobsUsed",
|
|
6192
|
+
"maxJobsRemaining"
|
|
6193
|
+
],
|
|
6194
|
+
"properties": {
|
|
6195
|
+
"endsAt": {
|
|
6196
|
+
"type": "string",
|
|
6197
|
+
"format": "date-time"
|
|
6198
|
+
},
|
|
6199
|
+
"callsLimit": {
|
|
6200
|
+
"type": "integer",
|
|
6201
|
+
"minimum": 0
|
|
6202
|
+
},
|
|
6203
|
+
"callsUsed": {
|
|
6204
|
+
"type": "integer",
|
|
6205
|
+
"minimum": 0
|
|
6206
|
+
},
|
|
6207
|
+
"callsRemaining": {
|
|
6208
|
+
"type": "integer",
|
|
6209
|
+
"minimum": 0
|
|
6210
|
+
},
|
|
6211
|
+
"maxJobsLimit": {
|
|
6212
|
+
"type": "integer",
|
|
6213
|
+
"minimum": 0
|
|
6214
|
+
},
|
|
6215
|
+
"maxJobsUsed": {
|
|
6216
|
+
"type": "integer",
|
|
6217
|
+
"minimum": 0
|
|
6218
|
+
},
|
|
6219
|
+
"maxJobsRemaining": {
|
|
6220
|
+
"type": "integer",
|
|
6221
|
+
"minimum": 0
|
|
6222
|
+
}
|
|
6223
|
+
}
|
|
5337
6224
|
}
|
|
5338
6225
|
}
|
|
5339
6226
|
},
|