@jytextiles/medusa-plugin-faire-store-sync 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/.medusa/server/src/__tests__/ingest-faire-order-support.spec.js +74 -0
  2. package/.medusa/server/src/__tests__/webhook.spec.js +77 -0
  3. package/.medusa/server/src/admin/index.js +960 -0
  4. package/.medusa/server/src/admin/index.mjs +959 -0
  5. package/.medusa/server/src/api/admin/faire/auth/authorize/route.js +12 -0
  6. package/.medusa/server/src/api/admin/faire/auth/callback/route.js +25 -0
  7. package/.medusa/server/src/api/admin/faire/auth/disconnect/route.js +12 -0
  8. package/.medusa/server/src/api/admin/faire/brand/route.js +14 -0
  9. package/.medusa/server/src/api/admin/faire/ingest/orders/[batchId]/route.js +27 -0
  10. package/.medusa/server/src/api/admin/faire/ingest/orders/route.js +20 -0
  11. package/.medusa/server/src/api/admin/faire/products/route.js +16 -0
  12. package/.medusa/server/src/api/admin/faire/settings/route.js +19 -0
  13. package/.medusa/server/src/api/admin/faire/status/product/[id]/route.js +30 -0
  14. package/.medusa/server/src/api/admin/faire/status/route.js +46 -0
  15. package/.medusa/server/src/api/admin/faire/sync/bulk/[batchId]/route.js +29 -0
  16. package/.medusa/server/src/api/admin/faire/sync/bulk/route.js +20 -0
  17. package/.medusa/server/src/api/admin/faire/sync/product/[id]/route.js +14 -0
  18. package/.medusa/server/src/api/admin/faire/syncs/[id]/route.js +32 -0
  19. package/.medusa/server/src/api/admin/faire/syncs/route.js +18 -0
  20. package/.medusa/server/src/api/webhooks/faire/route.js +125 -0
  21. package/.medusa/server/src/jobs/pull-faire-orders.js +32 -0
  22. package/.medusa/server/src/jobs/refresh-faire-token.js +25 -0
  23. package/.medusa/server/src/lib/faire-client.js +321 -0
  24. package/.medusa/server/src/lib/types.js +10 -0
  25. package/.medusa/server/src/lib/webhook.js +58 -0
  26. package/.medusa/server/src/links/product-faire-sync-link.js +57 -0
  27. package/.medusa/server/src/modules/faire-sync/index.js +15 -0
  28. package/.medusa/server/src/modules/faire-sync/migrations/Migration20260707211346.js +34 -0
  29. package/.medusa/server/src/modules/faire-sync/models/faire-order.js +21 -0
  30. package/.medusa/server/src/modules/faire-sync/models/faire-sync-account.js +17 -0
  31. package/.medusa/server/src/modules/faire-sync/models/faire-sync-batch.js +18 -0
  32. package/.medusa/server/src/modules/faire-sync/models/faire-sync-record.js +22 -0
  33. package/.medusa/server/src/modules/faire-sync/models/faire-sync-settings.js +26 -0
  34. package/.medusa/server/src/modules/faire-sync/models/faire-webhook-event.js +21 -0
  35. package/.medusa/server/src/modules/faire-sync/service.js +222 -0
  36. package/.medusa/server/src/subscribers/faire-inventory-sync.js +87 -0
  37. package/.medusa/server/src/subscribers/faire-listing-events.js +46 -0
  38. package/.medusa/server/src/subscribers/faire-order-ingest.js +54 -0
  39. package/.medusa/server/src/subscribers/faire-order-lifecycle.js +71 -0
  40. package/.medusa/server/src/subscribers/faire-product-status-sync.js +71 -0
  41. package/.medusa/server/src/workflows/index.js +21 -0
  42. package/.medusa/server/src/workflows/ingest-faire-order-support.js +76 -0
  43. package/.medusa/server/src/workflows/ingest-faire-order.js +148 -0
  44. package/.medusa/server/src/workflows/ingest-faire-orders-bulk.js +124 -0
  45. package/.medusa/server/src/workflows/refresh-faire-token.js +20 -0
  46. package/.medusa/server/src/workflows/sync-product-to-faire.js +262 -0
  47. package/.medusa/server/src/workflows/sync-products-to-faire.js +90 -0
  48. package/LICENSE +21 -0
  49. package/README.md +180 -0
  50. package/package.json +84 -0
  51. package/scripts/postbuild.js +36 -0
  52. package/src/__tests__/ingest-faire-order-support.spec.ts +77 -0
  53. package/src/__tests__/webhook.spec.ts +81 -0
  54. package/src/admin/lib/api.ts +88 -0
  55. package/src/admin/routes/settings/faire/[id]/page.tsx +184 -0
  56. package/src/admin/routes/settings/faire/hooks/use-faire-sync-columns.tsx +80 -0
  57. package/src/admin/routes/settings/faire/page.tsx +445 -0
  58. package/src/admin/routes/settings/faire/settings/page.tsx +286 -0
  59. package/src/admin/routes/settings/oauth/faire/callback/page.tsx +67 -0
  60. package/src/admin/widgets/faire-product-widget.tsx +180 -0
  61. package/src/api/admin/faire/auth/authorize/route.ts +10 -0
  62. package/src/api/admin/faire/auth/callback/route.ts +29 -0
  63. package/src/api/admin/faire/auth/disconnect/route.ts +10 -0
  64. package/src/api/admin/faire/brand/route.ts +12 -0
  65. package/src/api/admin/faire/ingest/orders/[batchId]/route.ts +31 -0
  66. package/src/api/admin/faire/ingest/orders/route.ts +29 -0
  67. package/src/api/admin/faire/products/route.ts +14 -0
  68. package/src/api/admin/faire/settings/route.ts +17 -0
  69. package/src/api/admin/faire/status/product/[id]/route.ts +30 -0
  70. package/src/api/admin/faire/status/route.ts +47 -0
  71. package/src/api/admin/faire/sync/bulk/[batchId]/route.ts +33 -0
  72. package/src/api/admin/faire/sync/bulk/route.ts +27 -0
  73. package/src/api/admin/faire/sync/product/[id]/route.ts +13 -0
  74. package/src/api/admin/faire/syncs/[id]/route.ts +32 -0
  75. package/src/api/admin/faire/syncs/route.ts +17 -0
  76. package/src/api/webhooks/faire/route.ts +133 -0
  77. package/src/jobs/pull-faire-orders.ts +30 -0
  78. package/src/jobs/refresh-faire-token.ts +23 -0
  79. package/src/lib/faire-client.ts +436 -0
  80. package/src/lib/types.ts +117 -0
  81. package/src/lib/webhook.ts +85 -0
  82. package/src/links/product-faire-sync-link.ts +56 -0
  83. package/src/modules/faire-sync/index.ts +11 -0
  84. package/src/modules/faire-sync/migrations/.snapshot-medusa-faire-sync.json +1486 -0
  85. package/src/modules/faire-sync/migrations/Migration20260707211346.ts +43 -0
  86. package/src/modules/faire-sync/models/faire-order.ts +20 -0
  87. package/src/modules/faire-sync/models/faire-sync-account.ts +16 -0
  88. package/src/modules/faire-sync/models/faire-sync-batch.ts +17 -0
  89. package/src/modules/faire-sync/models/faire-sync-record.ts +21 -0
  90. package/src/modules/faire-sync/models/faire-sync-settings.ts +25 -0
  91. package/src/modules/faire-sync/models/faire-webhook-event.ts +20 -0
  92. package/src/modules/faire-sync/service.ts +252 -0
  93. package/src/subscribers/faire-inventory-sync.ts +97 -0
  94. package/src/subscribers/faire-listing-events.ts +48 -0
  95. package/src/subscribers/faire-order-ingest.ts +61 -0
  96. package/src/subscribers/faire-order-lifecycle.ts +81 -0
  97. package/src/subscribers/faire-product-status-sync.ts +76 -0
  98. package/src/workflows/index.ts +4 -0
  99. package/src/workflows/ingest-faire-order-support.ts +96 -0
  100. package/src/workflows/ingest-faire-order.ts +212 -0
  101. package/src/workflows/ingest-faire-orders-bulk.ts +168 -0
  102. package/src/workflows/refresh-faire-token.ts +28 -0
  103. package/src/workflows/sync-product-to-faire.ts +375 -0
  104. package/src/workflows/sync-products-to-faire.ts +133 -0
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const ingest_faire_order_support_1 = require("../workflows/ingest-faire-order-support");
4
+ describe("faireMoney", () => {
5
+ it("converts integer cents to decimal major units", () => {
6
+ expect((0, ingest_faire_order_support_1.faireMoney)(2500)).toBe(25);
7
+ expect((0, ingest_faire_order_support_1.faireMoney)(4999)).toBe(49.99);
8
+ });
9
+ it("coerces undefined/NaN to 0", () => {
10
+ expect((0, ingest_faire_order_support_1.faireMoney)(undefined)).toBe(0);
11
+ expect((0, ingest_faire_order_support_1.faireMoney)(NaN)).toBe(0);
12
+ });
13
+ });
14
+ describe("mapFaireOrderToOrder", () => {
15
+ it("maps items, address and idempotency token", () => {
16
+ const order = {
17
+ order_token: "o_123",
18
+ currency: "USD",
19
+ total_cents: 4999,
20
+ buyer_name: "Ada Lovelace",
21
+ address: {
22
+ first_name: "Ada",
23
+ last_name: "Lovelace",
24
+ street1: "1 Main St",
25
+ city: "London",
26
+ state: "ENG",
27
+ zip: "EC1",
28
+ country: "GB",
29
+ },
30
+ items: [
31
+ {
32
+ id: "i_1",
33
+ product_token: "p_1",
34
+ sku: "SKU-1",
35
+ quantity: 2,
36
+ wholesale_price_cents: 1250,
37
+ name: "Cushion",
38
+ },
39
+ ],
40
+ };
41
+ const mapped = (0, ingest_faire_order_support_1.mapFaireOrderToOrder)(order);
42
+ expect(mapped.order_token).toBe("o_123");
43
+ expect(mapped.currency_code).toBe("usd");
44
+ expect(mapped.total).toBe(49.99);
45
+ expect(mapped.buyer_name).toBe("Ada Lovelace");
46
+ expect(mapped.email).toBe("faire+o_123@marketplace.invalid");
47
+ expect(mapped.shipping_address.country_code).toBe("gb");
48
+ expect(mapped.items).toHaveLength(1);
49
+ expect(mapped.items[0]).toMatchObject({
50
+ title: "Cushion",
51
+ quantity: 2,
52
+ unit_price: 12.5,
53
+ });
54
+ expect(mapped.items[0].metadata).toMatchObject({
55
+ faire_order_token: "o_123",
56
+ faire_product_token: "p_1",
57
+ faire_sku: "SKU-1",
58
+ });
59
+ });
60
+ it("falls back when address fields are missing", () => {
61
+ const mapped = (0, ingest_faire_order_support_1.mapFaireOrderToOrder)({ order_token: "o_1", items: [] });
62
+ expect(mapped.shipping_address.first_name).toBe("Faire");
63
+ expect(mapped.items).toEqual([]);
64
+ });
65
+ it("uses buyer email when provided", () => {
66
+ const mapped = (0, ingest_faire_order_support_1.mapFaireOrderToOrder)({
67
+ order_token: "o_2",
68
+ buyer_email: "retailer@example.com",
69
+ items: [{ quantity: 1, name: "x" }],
70
+ });
71
+ expect(mapped.email).toBe("retailer@example.com");
72
+ });
73
+ });
74
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5nZXN0LWZhaXJlLW9yZGVyLXN1cHBvcnQuc3BlYy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9fX3Rlc3RzX18vaW5nZXN0LWZhaXJlLW9yZGVyLXN1cHBvcnQuc3BlYy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLHdGQUEwRjtBQUUxRixRQUFRLENBQUMsWUFBWSxFQUFFLEdBQUcsRUFBRTtJQUMxQixFQUFFLENBQUMsK0NBQStDLEVBQUUsR0FBRyxFQUFFO1FBQ3ZELE1BQU0sQ0FBQyxJQUFBLHVDQUFVLEVBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUE7UUFDakMsTUFBTSxDQUFDLElBQUEsdUNBQVUsRUFBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQTtJQUN0QyxDQUFDLENBQUMsQ0FBQTtJQUNGLEVBQUUsQ0FBQyw0QkFBNEIsRUFBRSxHQUFHLEVBQUU7UUFDcEMsTUFBTSxDQUFDLElBQUEsdUNBQVUsRUFBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQTtRQUNyQyxNQUFNLENBQUMsSUFBQSx1Q0FBVSxFQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFBO0lBQ2pDLENBQUMsQ0FBQyxDQUFBO0FBQ0osQ0FBQyxDQUFDLENBQUE7QUFFRixRQUFRLENBQUMsc0JBQXNCLEVBQUUsR0FBRyxFQUFFO0lBQ3BDLEVBQUUsQ0FBQywyQ0FBMkMsRUFBRSxHQUFHLEVBQUU7UUFDbkQsTUFBTSxLQUFLLEdBQUc7WUFDWixXQUFXLEVBQUUsT0FBTztZQUNwQixRQUFRLEVBQUUsS0FBSztZQUNmLFdBQVcsRUFBRSxJQUFJO1lBQ2pCLFVBQVUsRUFBRSxjQUFjO1lBQzFCLE9BQU8sRUFBRTtnQkFDUCxVQUFVLEVBQUUsS0FBSztnQkFDakIsU0FBUyxFQUFFLFVBQVU7Z0JBQ3JCLE9BQU8sRUFBRSxXQUFXO2dCQUNwQixJQUFJLEVBQUUsUUFBUTtnQkFDZCxLQUFLLEVBQUUsS0FBSztnQkFDWixHQUFHLEVBQUUsS0FBSztnQkFDVixPQUFPLEVBQUUsSUFBSTthQUNkO1lBQ0QsS0FBSyxFQUFFO2dCQUNMO29CQUNFLEVBQUUsRUFBRSxLQUFLO29CQUNULGFBQWEsRUFBRSxLQUFLO29CQUNwQixHQUFHLEVBQUUsT0FBTztvQkFDWixRQUFRLEVBQUUsQ0FBQztvQkFDWCxxQkFBcUIsRUFBRSxJQUFJO29CQUMzQixJQUFJLEVBQUUsU0FBUztpQkFDaEI7YUFDRjtTQUNGLENBQUE7UUFFRCxNQUFNLE1BQU0sR0FBRyxJQUFBLGlEQUFvQixFQUFDLEtBQUssQ0FBQyxDQUFBO1FBRTFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsV0FBVyxDQUFDLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFBO1FBQ3hDLE1BQU0sQ0FBQyxNQUFNLENBQUMsYUFBYSxDQUFDLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFBO1FBQ3hDLE1BQU0sQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFBO1FBQ2hDLE1BQU0sQ0FBQyxNQUFNLENBQUMsVUFBVSxDQUFDLENBQUMsSUFBSSxDQUFDLGNBQWMsQ0FBQyxDQUFBO1FBQzlDLE1BQU0sQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUMsSUFBSSxDQUFDLGlDQUFpQyxDQUFDLENBQUE7UUFDNUQsTUFBTSxDQUFDLE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQyxZQUFZLENBQUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUE7UUFDdkQsTUFBTSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQyxZQUFZLENBQUMsQ0FBQyxDQUFDLENBQUE7UUFDcEMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxhQUFhLENBQUM7WUFDcEMsS0FBSyxFQUFFLFNBQVM7WUFDaEIsUUFBUSxFQUFFLENBQUM7WUFDWCxVQUFVLEVBQUUsSUFBSTtTQUNqQixDQUFDLENBQUE7UUFDRixNQUFNLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsQ0FBQyxhQUFhLENBQUM7WUFDN0MsaUJBQWlCLEVBQUUsT0FBTztZQUMxQixtQkFBbUIsRUFBRSxLQUFLO1lBQzFCLFNBQVMsRUFBRSxPQUFPO1NBQ25CLENBQUMsQ0FBQTtJQUNKLENBQUMsQ0FBQyxDQUFBO0lBRUYsRUFBRSxDQUFDLDRDQUE0QyxFQUFFLEdBQUcsRUFBRTtRQUNwRCxNQUFNLE1BQU0sR0FBRyxJQUFBLGlEQUFvQixFQUFDLEVBQUUsV0FBVyxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsRUFBRSxFQUFFLENBQUMsQ0FBQTtRQUN0RSxNQUFNLENBQUMsTUFBTSxDQUFDLGdCQUFnQixDQUFDLFVBQVUsQ0FBQyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQTtRQUN4RCxNQUFNLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUMsQ0FBQTtJQUNsQyxDQUFDLENBQUMsQ0FBQTtJQUVGLEVBQUUsQ0FBQyxnQ0FBZ0MsRUFBRSxHQUFHLEVBQUU7UUFDeEMsTUFBTSxNQUFNLEdBQUcsSUFBQSxpREFBb0IsRUFBQztZQUNsQyxXQUFXLEVBQUUsS0FBSztZQUNsQixXQUFXLEVBQUUsc0JBQXNCO1lBQ25DLEtBQUssRUFBRSxDQUFDLEVBQUUsUUFBUSxFQUFFLENBQUMsRUFBRSxJQUFJLEVBQUUsR0FBRyxFQUFFLENBQUM7U0FDcEMsQ0FBQyxDQUFBO1FBQ0YsTUFBTSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQyxJQUFJLENBQUMsc0JBQXNCLENBQUMsQ0FBQTtJQUNuRCxDQUFDLENBQUMsQ0FBQTtBQUNKLENBQUMsQ0FBQyxDQUFBIn0=
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const webhook_1 = require("../lib/webhook");
7
+ const crypto_1 = __importDefault(require("crypto"));
8
+ const secret = "faire-webhook-secret";
9
+ const sign = (body, enc = "hex") => crypto_1.default.createHmac("sha256", Buffer.from(secret, "utf8")).update(body, "utf8").digest(enc);
10
+ describe("verifyFaireWebhook", () => {
11
+ it("accepts a valid hex signature", () => {
12
+ const body = '{"event_type":"ORDER_PLACED"}';
13
+ const res = (0, webhook_1.verifyFaireWebhook)({
14
+ secret,
15
+ headers: { signature: sign(body, "hex") },
16
+ rawBody: body,
17
+ });
18
+ expect(res.valid).toBe(true);
19
+ });
20
+ it("accepts a valid base64 signature", () => {
21
+ const body = '{"event_type":"ORDER_PLACED"}';
22
+ const res = (0, webhook_1.verifyFaireWebhook)({
23
+ secret,
24
+ headers: { signature: sign(body, "base64") },
25
+ rawBody: body,
26
+ });
27
+ expect(res.valid).toBe(true);
28
+ });
29
+ it("accepts svix-style v1,<sig> entries", () => {
30
+ const body = '{"event_type":"ORDER_PLACED"}';
31
+ const res = (0, webhook_1.verifyFaireWebhook)({
32
+ secret,
33
+ headers: { signature: `v1,${sign(body, "hex")}` },
34
+ rawBody: body,
35
+ });
36
+ expect(res.valid).toBe(true);
37
+ });
38
+ it("rejects a tampered body", () => {
39
+ const body = '{"event_type":"ORDER_PLACED"}';
40
+ const res = (0, webhook_1.verifyFaireWebhook)({
41
+ secret,
42
+ headers: { signature: sign(body, "hex") },
43
+ rawBody: body + "tampered",
44
+ });
45
+ expect(res.valid).toBe(false);
46
+ expect(res.reason).toBe("signature mismatch");
47
+ });
48
+ it("rejects when signature header is missing", () => {
49
+ const res = (0, webhook_1.verifyFaireWebhook)({
50
+ secret,
51
+ headers: {},
52
+ rawBody: "{}",
53
+ });
54
+ expect(res.valid).toBe(false);
55
+ expect(res.reason).toMatch(/missing/);
56
+ });
57
+ it("rejects when secret is empty", () => {
58
+ const res = (0, webhook_1.verifyFaireWebhook)({
59
+ secret: "",
60
+ headers: { signature: "abc" },
61
+ rawBody: "{}",
62
+ });
63
+ expect(res.valid).toBe(false);
64
+ expect(res.reason).toMatch(/secret/);
65
+ });
66
+ it("enforces timestamp tolerance when a timestamp is present", () => {
67
+ const body = "{}";
68
+ const res = (0, webhook_1.verifyFaireWebhook)({
69
+ secret,
70
+ headers: { signature: sign(body, "hex"), timestamp: String(Math.floor(Date.now() / 1000) - 600) },
71
+ rawBody: body,
72
+ });
73
+ expect(res.valid).toBe(false);
74
+ expect(res.reason).toMatch(/timestamp/);
75
+ });
76
+ });
77
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid2ViaG9vay5zcGVjLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL19fdGVzdHNfXy93ZWJob29rLnNwZWMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFBQSw0Q0FBbUQ7QUFDbkQsb0RBQTJCO0FBRTNCLE1BQU0sTUFBTSxHQUFHLHNCQUFzQixDQUFBO0FBRXJDLE1BQU0sSUFBSSxHQUFHLENBQUMsSUFBWSxFQUFFLE1BQXdCLEtBQUssRUFBRSxFQUFFLENBQzNELGdCQUFNLENBQUMsVUFBVSxDQUFDLFFBQVEsRUFBRSxNQUFNLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRSxNQUFNLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxJQUFJLEVBQUUsTUFBTSxDQUFDLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFBO0FBRTNGLFFBQVEsQ0FBQyxvQkFBb0IsRUFBRSxHQUFHLEVBQUU7SUFDbEMsRUFBRSxDQUFDLCtCQUErQixFQUFFLEdBQUcsRUFBRTtRQUN2QyxNQUFNLElBQUksR0FBRywrQkFBK0IsQ0FBQTtRQUM1QyxNQUFNLEdBQUcsR0FBRyxJQUFBLDRCQUFrQixFQUFDO1lBQzdCLE1BQU07WUFDTixPQUFPLEVBQUUsRUFBRSxTQUFTLEVBQUUsSUFBSSxDQUFDLElBQUksRUFBRSxLQUFLLENBQUMsRUFBRTtZQUN6QyxPQUFPLEVBQUUsSUFBSTtTQUNkLENBQUMsQ0FBQTtRQUNGLE1BQU0sQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFBO0lBQzlCLENBQUMsQ0FBQyxDQUFBO0lBRUYsRUFBRSxDQUFDLGtDQUFrQyxFQUFFLEdBQUcsRUFBRTtRQUMxQyxNQUFNLElBQUksR0FBRywrQkFBK0IsQ0FBQTtRQUM1QyxNQUFNLEdBQUcsR0FBRyxJQUFBLDRCQUFrQixFQUFDO1lBQzdCLE1BQU07WUFDTixPQUFPLEVBQUUsRUFBRSxTQUFTLEVBQUUsSUFBSSxD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