shopify-webhook-schemas 0.1.7 → 0.1.9

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.
@@ -1,3 +1,5 @@
1
+ import { inferSchemaFromExamplePayload } from "./infer-schema";
2
+ export { inferSchemaFromExamplePayload };
1
3
  export declare function getPackageRootDir(): string;
2
4
  /** Return a metadata blob from Shopify's docs describing a webhook topic */
3
5
  export declare function metadataForWebhook(apiVersion: string, topic: string): any;
package/dist/src/index.js CHANGED
@@ -3,6 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.inferSchemaFromExamplePayload = void 0;
6
7
  exports.getPackageRootDir = getPackageRootDir;
7
8
  exports.metadataForWebhook = metadataForWebhook;
8
9
  exports.schemaForWebhook = schemaForWebhook;
@@ -10,6 +11,8 @@ exports.allTopicsForVersion = allTopicsForVersion;
10
11
  const fs_1 = __importDefault(require("fs"));
11
12
  const path_1 = __importDefault(require("path"));
12
13
  const fast_glob_1 = __importDefault(require("fast-glob"));
14
+ const infer_schema_1 = require("./infer-schema");
15
+ Object.defineProperty(exports, "inferSchemaFromExamplePayload", { enumerable: true, get: function () { return infer_schema_1.inferSchemaFromExamplePayload; } });
13
16
  const loaded = { metadatas: {}, schemas: {} };
14
17
  function getPackageRootDir() {
15
18
  let currentDir = __dirname;
@@ -0,0 +1,18 @@
1
+ export declare const startVersion = "2024-04";
2
+ export type Error = {
3
+ message: string;
4
+ path: string;
5
+ };
6
+ export declare const inferSchemaFromExamplePayload: (examplePayload: Record<string, any>, metadata: {
7
+ name: string;
8
+ }) => {
9
+ schema: any;
10
+ warnings: number;
11
+ errors: Error[];
12
+ };
13
+ export declare const manualExamples: [RegExp, Record<string, any>][];
14
+ export declare const overrides: {
15
+ topics: string[];
16
+ schema: any;
17
+ versions?: string[];
18
+ }[];
@@ -0,0 +1,627 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.overrides = exports.manualExamples = exports.inferSchemaFromExamplePayload = exports.startVersion = void 0;
4
+ const json_schema_walker_1 = require("@cloudflare/json-schema-walker");
5
+ const schema_infer_1 = require("@jsonhero/schema-infer");
6
+ const lodash_1 = require("lodash");
7
+ const safe_stable_stringify_1 = require("safe-stable-stringify");
8
+ const stringify = (0, safe_stable_stringify_1.configure)({ deterministic: true });
9
+ exports.startVersion = "2024-04";
10
+ const inferSchemaFromExamplePayload = (examplePayload, metadata) => {
11
+ const inference = (0, schema_infer_1.inferSchema)(examplePayload);
12
+ // build a copy of the payload and apply overrides based on the webhook name
13
+ for (const [matcher, override] of exports.manualExamples) {
14
+ if (matcher.test(metadata.name)) {
15
+ const overridesPayload = (0, lodash_1.cloneDeep)(examplePayload);
16
+ const maskedOverride = (0, lodash_1.pick)(override, Object.keys(examplePayload));
17
+ (0, lodash_1.merge)(overridesPayload, maskedOverride);
18
+ inference.infer(overridesPayload);
19
+ }
20
+ }
21
+ const schema = {
22
+ $schema: "https://json-schema.org/draft/2020-12/schema",
23
+ ...inference.toJSONSchema(),
24
+ };
25
+ for (const override of exports.overrides) {
26
+ if (override.topics.includes(metadata.name) && (!override.versions || override.versions.includes(exports.startVersion))) {
27
+ for (const [key, schemaOverride] of Object.entries(override.schema)) {
28
+ schema.properties[key] = schemaOverride;
29
+ }
30
+ }
31
+ }
32
+ const sortedSchema = getDeterministicObject(schema);
33
+ let warnings = 0;
34
+ const errors = [];
35
+ (0, json_schema_walker_1.schemaWalk)(sortedSchema, (subschema, path, _parent, parentPath) => {
36
+ if ((0, lodash_1.isEqual)(subschema, { type: "null" })) {
37
+ warnings += 1;
38
+ const fullPath = [...parentPath, ...path].join(".");
39
+ if (unknownPaths.some(([pattern, paths]) => pattern.test(metadata.name) && paths.includes(fullPath))) {
40
+ // we know this path is always null, so don't error
41
+ }
42
+ else {
43
+ errors.push({
44
+ message: "null type found in final schema",
45
+ path: fullPath,
46
+ });
47
+ }
48
+ }
49
+ }, () => { }, (0, json_schema_walker_1.getVocabulary)(sortedSchema));
50
+ return { schema: sortedSchema, warnings, errors };
51
+ };
52
+ exports.inferSchemaFromExamplePayload = inferSchemaFromExamplePayload;
53
+ const getDeterministicObject = (obj) => {
54
+ const stableString = stringify(sortStringArrays(obj));
55
+ return JSON.parse(stableString);
56
+ };
57
+ const sortStringArrays = (obj) => {
58
+ return (0, lodash_1.cloneDeepWith)(obj, (value) => {
59
+ if (Array.isArray(value) && value.every((item) => typeof item === "string")) {
60
+ return value.sort();
61
+ }
62
+ });
63
+ };
64
+ // paths that we can't find any source data for at all, so we don't know what type they should be
65
+ const unknownPaths = [
66
+ [
67
+ /checkouts\/.+/,
68
+ [
69
+ "properties.line_items.items.properties.unit_price_measurement.properties.measured_type",
70
+ "properties.line_items.items.properties.unit_price_measurement.properties.quantity_value",
71
+ "properties.line_items.items.properties.unit_price_measurement.properties.quantity_unit",
72
+ "properties.line_items.items.properties.unit_price_measurement.properties.reference_value",
73
+ "properties.line_items.items.properties.unit_price_measurement.properties.reference_unit",
74
+ "properties.line_items.items.properties.tax_lines.items.properties.reporting_jurisdiction_name",
75
+ "properties.line_items.items.properties.tax_lines.items.properties.reporting_jurisdiction_type",
76
+ "properties.line_items.items.properties.tax_lines.items.properties.reporting_jurisdiction_code",
77
+ "properties.line_items.items.properties.user_id",
78
+ "properties.line_items.items.properties.compare_at_price",
79
+ "properties.gateway",
80
+ "properties.shipping_lines.items.properties.delivery_category",
81
+ "properties.shipping_lines.items.properties.validation_context",
82
+ "properties.shipping_lines.items.properties.requested_fulfillment_service_id",
83
+ "properties.shipping_lines.items.properties.tax_lines.items.properties.identifier",
84
+ "properties.shipping_lines.items.properties.tax_lines.items.properties.reporting_jurisdiction_name",
85
+ "properties.shipping_lines.items.properties.tax_lines.items.properties.tax_api_client_id",
86
+ "properties.shipping_lines.items.properties.tax_lines.items.properties.reporting_exempt_amount",
87
+ "properties.shipping_lines.items.properties.tax_lines.items.properties.jurisdiction_source",
88
+ "properties.shipping_lines.items.properties.tax_lines.items.properties.reporting_jurisdiction_code",
89
+ "properties.shipping_lines.items.properties.tax_lines.items.properties.reporting_jurisdiction_type",
90
+ "properties.shipping_lines.items.properties.tax_lines.items.properties.reporting_taxable_amount",
91
+ "properties.shipping_lines.items.properties.tax_lines.items.properties.jurisdiction_type",
92
+ "properties.shipping_lines.items.properties.tax_lines.items.properties.tax_type",
93
+ "properties.shipping_lines.items.properties.tax_lines.items.properties.jurisdiction_id",
94
+ "properties.shipping_lines.items.properties.tax_lines.items.properties.reporting_non_taxable_amount",
95
+ "properties.shipping_lines.items.properties.custom_tax_lines",
96
+ "properties.shipping_lines.items.properties.estimated_delivery_time_range",
97
+ "properties.line_items.items.properties.tax_lines.items.properties.tax_type",
98
+ "properties.line_items.items.properties.tax_lines.items.properties.identifier",
99
+ "properties.line_items.items.properties.discount_allocations.items.properties.id",
100
+ "properties.line_items.items.properties.discount_allocations.items.properties.created_at",
101
+ ],
102
+ ],
103
+ [
104
+ /collection_listings\/.+/,
105
+ ["properties.collection_listing.properties.default_product_image", "properties.collection_listing.properties.image"],
106
+ ],
107
+ [/domains\/.+/, ["properties.localization.properties.country"]],
108
+ [/orders\/.+/, ["properties.client_details.properties.session_hash"]],
109
+ ];
110
+ // example data we feed the schema infer-er for each topic to allow it to discover real types
111
+ exports.manualExamples = [
112
+ [
113
+ /.+/,
114
+ {
115
+ admin_graphql_api_id: "gid://shopify/Something/1234567890",
116
+ admin_graphql_api_job_id: "gid://shopify/Job/1234567890",
117
+ created_at: "2021-12-30T19:00:00-05:00",
118
+ updated_at: "2021-12-30T19:00:00-05:00",
119
+ address2: "Apt 123",
120
+ latitude: 10.1,
121
+ longitude: 10.1,
122
+ location_id: 111111,
123
+ },
124
+ ],
125
+ [
126
+ /(app|shop)\/.+/,
127
+ {
128
+ domain: "example.com",
129
+ source: "example source",
130
+ myshopify_domain: "example.myshopify.com",
131
+ google_apps_domain: "example.com",
132
+ google_apps_login_enabled: true,
133
+ password_enabled: true,
134
+ taxes_included: true,
135
+ tax_shipping: true,
136
+ iana_timezone: "America/New_York",
137
+ auto_configure_tax_inclusivity: true,
138
+ county_taxes: true,
139
+ },
140
+ ],
141
+ [
142
+ /bulk_operations\/.+/,
143
+ {
144
+ error_code: "SOME_ERROR_ENUM",
145
+ },
146
+ ],
147
+ [
148
+ /carts\/.+/,
149
+ {
150
+ note: "some cart note string",
151
+ },
152
+ ],
153
+ [
154
+ /(checkouts|orders)\/.+/,
155
+ {
156
+ gateway: "shopify_payments",
157
+ landing_site: "https://example.com",
158
+ note: "some order note",
159
+ referring_site: "https://example.com",
160
+ completed_at: "2021-12-30T19:00:00-05:00",
161
+ closed_at: "2021-12-30T19:00:00-05:00",
162
+ user_id: 11111111,
163
+ location_id: 22222222,
164
+ source_identifier: "some_source_identifier",
165
+ source_url: "https://example.com",
166
+ device_id: "some_device_id",
167
+ phone: "+1 (123) 456 7890",
168
+ sms_marketing_phone: "+1 (123) 456 7890",
169
+ customer_locale: "en",
170
+ source: "some_source",
171
+ total_duties: 10.11,
172
+ app_id: 12345,
173
+ browser_ip: "10.0.0.1",
174
+ cart_token: "some_cart_token",
175
+ checkout_id: 12345,
176
+ client_details: {
177
+ accept_language: "en-US,en;q=0.9",
178
+ browser_height: 800,
179
+ },
180
+ confirmation_number: "some_confirmation_number",
181
+ current_total_additional_fees_set: {
182
+ shop_money: {
183
+ amount: "0.00",
184
+ currency_code: "USD",
185
+ },
186
+ presentment_money: {
187
+ amount: "0.00",
188
+ currency_code: "USD",
189
+ },
190
+ },
191
+ current_total_duties_set: {
192
+ shop_money: {
193
+ amount: "0.00",
194
+ currency_code: "USD",
195
+ },
196
+ presentment_money: {
197
+ amount: "0.00",
198
+ currency_code: "USD",
199
+ },
200
+ },
201
+ original_total_additional_fees_set: {
202
+ shop_money: {
203
+ amount: "0.00",
204
+ currency_code: "USD",
205
+ },
206
+ presentment_money: {
207
+ amount: "0.00",
208
+ currency_code: "USD",
209
+ },
210
+ },
211
+ original_total_duties_set: {
212
+ shop_money: {
213
+ amount: "0.00",
214
+ currency_code: "USD",
215
+ },
216
+ presentment_money: {
217
+ amount: "0.00",
218
+ currency_code: "USD",
219
+ },
220
+ },
221
+ checkout_token: "some_checkout_token",
222
+ landing_site_ref: "https://example.com",
223
+ merchant_of_record_app_id: 12345,
224
+ po_number: "some_po_number",
225
+ processed_at: "2021-12-30T19:00:00-05:00",
226
+ reference: "some_reference",
227
+ payment_terms: "some_payment_terms",
228
+ reservation_token: "some_reservation_token",
229
+ billing_address: {
230
+ address2: "suite 101",
231
+ latitude: 34.1,
232
+ longitude: 34.1,
233
+ },
234
+ shipping_address: {
235
+ address2: "suite 101",
236
+ latitude: 34.1,
237
+ longitude: 34.1,
238
+ },
239
+ customer: {
240
+ created_at: "2024-05-05T02:42:32+08:00",
241
+ marketing_opt_in_level: "single_opt_in",
242
+ note: "some string",
243
+ multipass_identifier: "hello",
244
+ },
245
+ },
246
+ ],
247
+ [
248
+ /checkouts\/.+/,
249
+ {
250
+ line_items: [
251
+ {
252
+ presentment_variant_title: "51 x 76 / Blanc / 1",
253
+ taxable: true,
254
+ variant_price: "69.00",
255
+ presentment_title: "Taie d'oreiller Pure Soie de Mûrier",
256
+ requires_shipping: true,
257
+ unit_price_measurement: {
258
+ measured_type: null,
259
+ quantity_unit: null,
260
+ quantity_value: null,
261
+ reference_unit: null,
262
+ reference_value: null,
263
+ },
264
+ variant_title: "51 x 76 / Blanc / 1",
265
+ title: "Taie d'oreiller Pure Soie de Mûrier",
266
+ gift_card: false,
267
+ destination_location_id: 4042942054746,
268
+ compare_at_price: null,
269
+ key: "e0105d4efb1970501cf831566fa79752",
270
+ line_price: "69.00",
271
+ vendor: "Emily's pillow",
272
+ quantity: 1,
273
+ applied_discounts: [],
274
+ grams: 110,
275
+ properties: [
276
+ {
277
+ name: "_isJust",
278
+ value: "true",
279
+ },
280
+ ],
281
+ tax_lines: [
282
+ {
283
+ reporting_jurisdiction_type: null,
284
+ reporting_non_taxable_amount: "0.00",
285
+ zone: null,
286
+ compare_at: 0.2,
287
+ reporting_taxable_amount: "57.50",
288
+ tax_api_client_id: null,
289
+ jurisdiction_source: "ActiveTax",
290
+ title: "FR TVA",
291
+ identifier: null,
292
+ jurisdiction_type: "COUNTRY",
293
+ reporting_jurisdiction_code: null,
294
+ source: "MerchantActiveTax",
295
+ reporting_exempt_amount: "0.00",
296
+ reporting_jurisdiction_name: null,
297
+ jurisdiction_id: "FR",
298
+ tax_type: null,
299
+ channel_liable: false,
300
+ price: "11.50",
301
+ rate: 0.2,
302
+ position: 1,
303
+ tax_calculation_price: "11.50",
304
+ },
305
+ ],
306
+ sku: "EMIL-TO5176-22WH",
307
+ rank: 0,
308
+ user_id: null,
309
+ product_id: 4610455470216,
310
+ discount_allocations: [],
311
+ origin_location_id: 1743669821576,
312
+ fulfillment_service: "manual",
313
+ variant_id: 32516187029640,
314
+ price: "69.00",
315
+ },
316
+ ],
317
+ },
318
+ ],
319
+ [
320
+ /collections\/.+/,
321
+ {
322
+ sort_order: "manual",
323
+ template_suffix: "some_template_suffix",
324
+ },
325
+ ],
326
+ [
327
+ /collection_listings\/.+/,
328
+ {
329
+ collection_listing: {
330
+ updated_at: "2021-12-30T19:00:00-05:00",
331
+ sort_order: 1,
332
+ },
333
+ },
334
+ ],
335
+ [
336
+ /company_locations\/.+/,
337
+ {
338
+ buyer_experience_configuration: { pay_now_only: true },
339
+ billing_address: {
340
+ address2: "suite 101",
341
+ },
342
+ shipping_address: {
343
+ address2: "suite 101",
344
+ },
345
+ },
346
+ ],
347
+ [
348
+ /customers\/.+/,
349
+ {
350
+ last_order_id: 12345,
351
+ multipass_identifier: "some_multipass_identifier",
352
+ last_order_name: "Foobar",
353
+ phone: "+1 (123) 456 7890",
354
+ sms_marketing_consent: false,
355
+ email_marketing_consent: false,
356
+ accepts_marketing_updated_at: "2021-12-30T19:00:00-05:00",
357
+ marketing_opt_in_level: "single_opt_in",
358
+ },
359
+ ],
360
+ [
361
+ /customer_account_settings\/.+/,
362
+ {
363
+ url: "https://example.com",
364
+ },
365
+ ],
366
+ [
367
+ /customer.+consent\/.+/,
368
+ {
369
+ phone: "+1 (123) 456 7890",
370
+ email_address: "test@test.com",
371
+ },
372
+ ],
373
+ [
374
+ /disputes\/.+/,
375
+ {
376
+ evidence_sent_on: "2021-12-30T19:00:00-05:00",
377
+ finalized_on: "2021-12-30T19:00:00-05:00",
378
+ },
379
+ ],
380
+ [
381
+ /draft_orders\/.+/,
382
+ {
383
+ invoice_sent_at: "2021-12-30T19:00:00-05:00",
384
+ order_id: 12345,
385
+ },
386
+ ],
387
+ [
388
+ /fulfillment_events\/.+/,
389
+ {
390
+ city: "Ottawa",
391
+ province: "ON",
392
+ zip: "K1P1J1",
393
+ address1: "150 Elgin St",
394
+ estimated_delivery_at: "2021-12-30T19:00:00-05:00",
395
+ },
396
+ ],
397
+ [
398
+ /fulfillment_orders\/.+/,
399
+ {
400
+ remaining_fulfillment_order: {
401
+ id: 5859333242902,
402
+ shop_id: 20978040854,
403
+ order_id: 4804938989590,
404
+ assigned_location_id: 67794436118,
405
+ request_status: "unsubmitted",
406
+ status: "open",
407
+ supported_actions: ["request_fulfillment", "hold", "move"],
408
+ destination: {
409
+ id: 5479404371990,
410
+ address1: "23 Hassall Street",
411
+ address2: "",
412
+ city: "Parramatta",
413
+ company: null,
414
+ country: "Australia",
415
+ email: "",
416
+ first_name: "Tyler",
417
+ last_name: "Kelleher",
418
+ phone: null,
419
+ province: "New South Wales",
420
+ zip: "2150",
421
+ },
422
+ line_items: [
423
+ {
424
+ id: 12675478814742,
425
+ shop_id: 20978040854,
426
+ fulfillment_order_id: 5859333242902,
427
+ quantity: 1,
428
+ line_item_id: 12553770336278,
429
+ inventory_item_id: 44276125368342,
430
+ fulfillable_quantity: 1,
431
+ variant_id: 42182036422678,
432
+ },
433
+ ],
434
+ fulfill_at: "2022-10-13T13:00:00-04:00",
435
+ fulfill_by: null,
436
+ international_duties: {
437
+ incoterm: "DAP",
438
+ },
439
+ fulfillment_holds: [],
440
+ delivery_method: {
441
+ id: 140816351254,
442
+ method_type: "shipping",
443
+ min_delivery_date_time: null,
444
+ max_delivery_date_time: null,
445
+ },
446
+ assigned_location: {
447
+ address1: null,
448
+ address2: null,
449
+ city: null,
450
+ country_code: "CA",
451
+ location_id: 67794436118,
452
+ name: "test-created-via-api-2",
453
+ phone: null,
454
+ province: null,
455
+ zip: null,
456
+ },
457
+ },
458
+ },
459
+ ],
460
+ [
461
+ /fulfillments\/.+/,
462
+ {
463
+ service: "manual",
464
+ shipment_status: "confirmed",
465
+ origin_address: {
466
+ first_name: "Steve",
467
+ address1: "123 Shipping Street",
468
+ phone: "555-555-SHIP",
469
+ city: "Shippington",
470
+ zip: "40003",
471
+ province: "Kentucky",
472
+ country: "United States",
473
+ last_name: "Shipper",
474
+ address2: null,
475
+ company: "Shipping Company",
476
+ latitude: null,
477
+ longitude: null,
478
+ name: "Steve Shipper",
479
+ country_code: "US",
480
+ province_code: "KY",
481
+ },
482
+ },
483
+ ],
484
+ [
485
+ /inventory_items\/.+/,
486
+ {
487
+ cost: 10.11,
488
+ country_code_of_origin: "CA",
489
+ province_code_of_origin: "CA",
490
+ harmonized_system_code: "1234567890",
491
+ },
492
+ ],
493
+ [
494
+ /inventory_levels\/.+/,
495
+ {
496
+ available: 10,
497
+ },
498
+ ],
499
+ [
500
+ /order_transactions\/.+/,
501
+ {
502
+ message: "some message from the gateway",
503
+ user_id: 12345,
504
+ parent_id: 12345,
505
+ processed_at: "2021-12-30T19:00:00-05:00",
506
+ device_id: "some_device_id",
507
+ error_code: "SOME_ERROR_ENUM",
508
+ },
509
+ ],
510
+ [
511
+ /orders\/risk_assessment.+/,
512
+ {
513
+ provider_id: 12345,
514
+ provider_title: "whatever",
515
+ },
516
+ ],
517
+ [
518
+ /products\/.+/,
519
+ {
520
+ template_suffix: "something",
521
+ image: "gid://shopify/ProductImage/1234567890",
522
+ },
523
+ ],
524
+ [
525
+ /refunds\/.+/,
526
+ {
527
+ return: "unknown",
528
+ },
529
+ ],
530
+ [
531
+ /selling_plan_groups\/.+/,
532
+ {
533
+ app_id: 12345,
534
+ description: "some description",
535
+ position: 1,
536
+ },
537
+ ],
538
+ [
539
+ /subscription_billing_attempts\/.+/,
540
+ {
541
+ id: 12345,
542
+ error_message: "some error message",
543
+ error_code: "some error copde",
544
+ },
545
+ ],
546
+ [
547
+ /subscription_billing_cycle.+/,
548
+ {
549
+ contract_edit: "some contract edit",
550
+ },
551
+ ],
552
+ [
553
+ /tender_transactions\/.+/,
554
+ {
555
+ user_id: 12345,
556
+ processed_at: "2021-12-30T19:00:00-05:00",
557
+ payment_details: { something: "true" },
558
+ },
559
+ ],
560
+ ];
561
+ const shippingAddress = {
562
+ type: "object",
563
+ properties: {
564
+ first_name: {
565
+ type: "string",
566
+ },
567
+ address1: {
568
+ type: "string",
569
+ },
570
+ phone: {
571
+ type: "string",
572
+ },
573
+ city: {
574
+ type: "string",
575
+ },
576
+ zip: {
577
+ type: "string",
578
+ },
579
+ province: {
580
+ type: "string",
581
+ },
582
+ country: {
583
+ type: "string",
584
+ },
585
+ last_name: {
586
+ type: "string",
587
+ },
588
+ address2: {
589
+ type: ["string", "null"],
590
+ },
591
+ company: {
592
+ type: ["string", "null"],
593
+ },
594
+ latitude: {
595
+ type: ["number", "null"],
596
+ },
597
+ longitude: {
598
+ type: ["number", "null"],
599
+ },
600
+ name: {
601
+ type: "string",
602
+ },
603
+ country_code: {
604
+ type: "string",
605
+ },
606
+ province_code: {
607
+ type: "string",
608
+ },
609
+ },
610
+ };
611
+ exports.overrides = [
612
+ {
613
+ topics: ["checkouts/create", "checkouts/update"],
614
+ schema: {
615
+ shipping_address: shippingAddress,
616
+ },
617
+ },
618
+ {
619
+ topics: ["order_transactions/create", "order_transactions/update"],
620
+ schema: {
621
+ receipt: {
622
+ type: "object",
623
+ additionalProperties: true,
624
+ },
625
+ },
626
+ },
627
+ ];