@lodashventure/medusa-login-provider 4.1.1 → 4.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/.medusa/server/src/providers/line/__tests__/line-api.mock.test.js +472 -0
- package/.medusa/server/src/providers/line/__tests__/service.test.js +438 -0
- package/.medusa/server/src/providers/line/__tests__/utils.test.js +351 -0
- package/.medusa/server/src/providers/line/service.js +201 -51
- package/.medusa/server/src/providers/line/types.js +3 -0
- package/.medusa/server/src/providers/line/utils.js +119 -0
- package/package.json +21 -2
|
@@ -0,0 +1,351 @@
|
|
|
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 crypto_1 = __importDefault(require("crypto"));
|
|
7
|
+
const utils_1 = require("@medusajs/framework/utils");
|
|
8
|
+
const utils_2 = require("../utils");
|
|
9
|
+
// Mock crypto for consistent testing
|
|
10
|
+
jest.mock("crypto");
|
|
11
|
+
const mockCrypto = crypto_1.default;
|
|
12
|
+
describe("LINE Utils", () => {
|
|
13
|
+
beforeEach(() => {
|
|
14
|
+
jest.clearAllMocks();
|
|
15
|
+
// Reset Date.now mock
|
|
16
|
+
jest.spyOn(Date, "now").mockRestore();
|
|
17
|
+
});
|
|
18
|
+
describe("generateState", () => {
|
|
19
|
+
it("should generate a 64-character hex string", () => {
|
|
20
|
+
const mockBuffer = Buffer.from("a".repeat(32));
|
|
21
|
+
mockCrypto.randomBytes.mockReturnValue(mockBuffer);
|
|
22
|
+
const state = (0, utils_2.generateState)();
|
|
23
|
+
expect(mockCrypto.randomBytes).toHaveBeenCalledWith(32);
|
|
24
|
+
expect(state).toBe("a".repeat(64));
|
|
25
|
+
expect(state).toHaveLength(64);
|
|
26
|
+
});
|
|
27
|
+
it("should generate different values on subsequent calls", () => {
|
|
28
|
+
mockCrypto.randomBytes
|
|
29
|
+
.mockReturnValueOnce(Buffer.from("a".repeat(32)))
|
|
30
|
+
.mockReturnValueOnce(Buffer.from("b".repeat(32)));
|
|
31
|
+
const state1 = (0, utils_2.generateState)();
|
|
32
|
+
const state2 = (0, utils_2.generateState)();
|
|
33
|
+
expect(state1).not.toBe(state2);
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
describe("generateNonce", () => {
|
|
37
|
+
it("should generate a 32-character hex string", () => {
|
|
38
|
+
const mockBuffer = Buffer.from("c".repeat(16));
|
|
39
|
+
mockCrypto.randomBytes.mockReturnValue(mockBuffer);
|
|
40
|
+
const nonce = (0, utils_2.generateNonce)();
|
|
41
|
+
expect(mockCrypto.randomBytes).toHaveBeenCalledWith(16);
|
|
42
|
+
expect(nonce).toBe("c".repeat(32));
|
|
43
|
+
expect(nonce).toHaveLength(32);
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
describe("generatePlaceholderEmail", () => {
|
|
47
|
+
it("should generate email with default domain", () => {
|
|
48
|
+
const email = (0, utils_2.generatePlaceholderEmail)("U123456");
|
|
49
|
+
expect(email).toBe("line-U123456@line.local");
|
|
50
|
+
});
|
|
51
|
+
it("should generate email with custom domain", () => {
|
|
52
|
+
const email = (0, utils_2.generatePlaceholderEmail)("U123456", "example.com");
|
|
53
|
+
expect(email).toBe("line-U123456@example.com");
|
|
54
|
+
});
|
|
55
|
+
it("should handle empty LINE user ID", () => {
|
|
56
|
+
const email = (0, utils_2.generatePlaceholderEmail)("");
|
|
57
|
+
expect(email).toBe("line-@line.local");
|
|
58
|
+
});
|
|
59
|
+
it("should handle special characters in LINE user ID", () => {
|
|
60
|
+
const email = (0, utils_2.generatePlaceholderEmail)("U123-456_789");
|
|
61
|
+
expect(email).toBe("line-U123-456_789@line.local");
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
describe("parseDisplayName", () => {
|
|
65
|
+
it("should parse single name", () => {
|
|
66
|
+
const result = (0, utils_2.parseDisplayName)("John");
|
|
67
|
+
expect(result).toEqual({
|
|
68
|
+
firstName: "John",
|
|
69
|
+
lastName: "",
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
it("should parse full name", () => {
|
|
73
|
+
const result = (0, utils_2.parseDisplayName)("John Doe");
|
|
74
|
+
expect(result).toEqual({
|
|
75
|
+
firstName: "John",
|
|
76
|
+
lastName: "Doe",
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
it("should handle multiple middle names", () => {
|
|
80
|
+
const result = (0, utils_2.parseDisplayName)("John William Doe Smith");
|
|
81
|
+
expect(result).toEqual({
|
|
82
|
+
firstName: "John",
|
|
83
|
+
lastName: "William Doe Smith",
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
it("should handle empty display name", () => {
|
|
87
|
+
const result = (0, utils_2.parseDisplayName)("");
|
|
88
|
+
expect(result).toEqual({
|
|
89
|
+
firstName: "",
|
|
90
|
+
lastName: "",
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
it("should handle whitespace-only display name", () => {
|
|
94
|
+
const result = (0, utils_2.parseDisplayName)(" ");
|
|
95
|
+
expect(result).toEqual({
|
|
96
|
+
firstName: "",
|
|
97
|
+
lastName: "",
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
it("should trim whitespace", () => {
|
|
101
|
+
const result = (0, utils_2.parseDisplayName)(" John Doe ");
|
|
102
|
+
expect(result).toEqual({
|
|
103
|
+
firstName: "John",
|
|
104
|
+
lastName: "Doe",
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
it("should handle names with extra spaces", () => {
|
|
108
|
+
const result = (0, utils_2.parseDisplayName)("John Doe Smith");
|
|
109
|
+
expect(result).toEqual({
|
|
110
|
+
firstName: "John",
|
|
111
|
+
lastName: "Doe Smith",
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
describe("validateChannelId", () => {
|
|
116
|
+
it("should validate correct 10-digit channel ID", () => {
|
|
117
|
+
expect((0, utils_2.validateChannelId)("1234567890")).toBe(true);
|
|
118
|
+
expect((0, utils_2.validateChannelId)("0000000000")).toBe(true);
|
|
119
|
+
expect((0, utils_2.validateChannelId)("9999999999")).toBe(true);
|
|
120
|
+
});
|
|
121
|
+
it("should reject channel ID with wrong length", () => {
|
|
122
|
+
expect((0, utils_2.validateChannelId)("123456789")).toBe(false); // 9 digits
|
|
123
|
+
expect((0, utils_2.validateChannelId)("12345678901")).toBe(false); // 11 digits
|
|
124
|
+
expect((0, utils_2.validateChannelId)("")).toBe(false);
|
|
125
|
+
});
|
|
126
|
+
it("should reject channel ID with non-numeric characters", () => {
|
|
127
|
+
expect((0, utils_2.validateChannelId)("123456789a")).toBe(false);
|
|
128
|
+
expect((0, utils_2.validateChannelId)("12345-6789")).toBe(false);
|
|
129
|
+
expect((0, utils_2.validateChannelId)("1234 56789")).toBe(false);
|
|
130
|
+
expect((0, utils_2.validateChannelId)("abcdefghij")).toBe(false);
|
|
131
|
+
});
|
|
132
|
+
it("should reject special characters and symbols", () => {
|
|
133
|
+
expect((0, utils_2.validateChannelId)("123456789@")).toBe(false);
|
|
134
|
+
expect((0, utils_2.validateChannelId)("123456789#")).toBe(false);
|
|
135
|
+
expect((0, utils_2.validateChannelId)("123456789$")).toBe(false);
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
describe("validateCallbackUrl", () => {
|
|
139
|
+
it("should validate HTTPS URLs", () => {
|
|
140
|
+
expect((0, utils_2.validateCallbackUrl)("https://example.com")).toBe(true);
|
|
141
|
+
expect((0, utils_2.validateCallbackUrl)("https://example.com/callback")).toBe(true);
|
|
142
|
+
expect((0, utils_2.validateCallbackUrl)("https://subdomain.example.com/path")).toBe(true);
|
|
143
|
+
});
|
|
144
|
+
it("should validate localhost URLs", () => {
|
|
145
|
+
expect((0, utils_2.validateCallbackUrl)("http://localhost:3000")).toBe(true);
|
|
146
|
+
expect((0, utils_2.validateCallbackUrl)("http://localhost")).toBe(true);
|
|
147
|
+
expect((0, utils_2.validateCallbackUrl)("https://localhost:8080")).toBe(true);
|
|
148
|
+
});
|
|
149
|
+
it("should reject HTTP URLs (non-localhost)", () => {
|
|
150
|
+
expect((0, utils_2.validateCallbackUrl)("http://example.com")).toBe(false);
|
|
151
|
+
expect((0, utils_2.validateCallbackUrl)("http://google.com")).toBe(false);
|
|
152
|
+
});
|
|
153
|
+
it("should reject invalid URLs", () => {
|
|
154
|
+
expect((0, utils_2.validateCallbackUrl)("not-a-url")).toBe(false);
|
|
155
|
+
expect((0, utils_2.validateCallbackUrl)("")).toBe(false);
|
|
156
|
+
expect((0, utils_2.validateCallbackUrl)("ftp://example.com")).toBe(false);
|
|
157
|
+
expect((0, utils_2.validateCallbackUrl)("mailto:test@example.com")).toBe(false);
|
|
158
|
+
});
|
|
159
|
+
it("should handle malformed URLs", () => {
|
|
160
|
+
expect((0, utils_2.validateCallbackUrl)("https://")).toBe(false);
|
|
161
|
+
expect((0, utils_2.validateCallbackUrl)("https:")).toBe(false);
|
|
162
|
+
expect((0, utils_2.validateCallbackUrl)("://example.com")).toBe(false);
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
describe("RateLimiter", () => {
|
|
166
|
+
let rateLimiter;
|
|
167
|
+
let mockDateNow;
|
|
168
|
+
beforeEach(() => {
|
|
169
|
+
mockDateNow = jest.spyOn(Date, "now");
|
|
170
|
+
rateLimiter = new utils_2.RateLimiter(3, 60000); // 3 attempts per minute
|
|
171
|
+
});
|
|
172
|
+
afterEach(() => {
|
|
173
|
+
mockDateNow.mockRestore();
|
|
174
|
+
});
|
|
175
|
+
it("should allow requests under the limit", () => {
|
|
176
|
+
mockDateNow.mockReturnValue(1000);
|
|
177
|
+
expect(rateLimiter.isAllowed("user1")).toBe(true);
|
|
178
|
+
expect(rateLimiter.isAllowed("user1")).toBe(true);
|
|
179
|
+
expect(rateLimiter.isAllowed("user1")).toBe(true);
|
|
180
|
+
});
|
|
181
|
+
it("should reject requests over the limit", () => {
|
|
182
|
+
mockDateNow.mockReturnValue(1000);
|
|
183
|
+
// Fill up the limit
|
|
184
|
+
expect(rateLimiter.isAllowed("user1")).toBe(true);
|
|
185
|
+
expect(rateLimiter.isAllowed("user1")).toBe(true);
|
|
186
|
+
expect(rateLimiter.isAllowed("user1")).toBe(true);
|
|
187
|
+
// This should be rejected
|
|
188
|
+
expect(rateLimiter.isAllowed("user1")).toBe(false);
|
|
189
|
+
});
|
|
190
|
+
it("should reset after time window", () => {
|
|
191
|
+
mockDateNow.mockReturnValue(1000);
|
|
192
|
+
// Fill up the limit
|
|
193
|
+
rateLimiter.isAllowed("user1");
|
|
194
|
+
rateLimiter.isAllowed("user1");
|
|
195
|
+
rateLimiter.isAllowed("user1");
|
|
196
|
+
// Should be rejected
|
|
197
|
+
expect(rateLimiter.isAllowed("user1")).toBe(false);
|
|
198
|
+
// Move time forward past window
|
|
199
|
+
mockDateNow.mockReturnValue(61001);
|
|
200
|
+
// Should be allowed again
|
|
201
|
+
expect(rateLimiter.isAllowed("user1")).toBe(true);
|
|
202
|
+
});
|
|
203
|
+
it("should track different keys separately", () => {
|
|
204
|
+
mockDateNow.mockReturnValue(1000);
|
|
205
|
+
// Fill limit for user1
|
|
206
|
+
rateLimiter.isAllowed("user1");
|
|
207
|
+
rateLimiter.isAllowed("user1");
|
|
208
|
+
rateLimiter.isAllowed("user1");
|
|
209
|
+
// user1 should be blocked, but user2 should be allowed
|
|
210
|
+
expect(rateLimiter.isAllowed("user1")).toBe(false);
|
|
211
|
+
expect(rateLimiter.isAllowed("user2")).toBe(true);
|
|
212
|
+
});
|
|
213
|
+
it("should handle partial window expiration", () => {
|
|
214
|
+
let currentTime = 1000;
|
|
215
|
+
mockDateNow.mockImplementation(() => currentTime);
|
|
216
|
+
// Make 2 requests at time 1000
|
|
217
|
+
rateLimiter.isAllowed("user1");
|
|
218
|
+
rateLimiter.isAllowed("user1");
|
|
219
|
+
// Move time forward 30 seconds and make 1 more request
|
|
220
|
+
currentTime = 31000;
|
|
221
|
+
rateLimiter.isAllowed("user1");
|
|
222
|
+
// Should be at limit now
|
|
223
|
+
expect(rateLimiter.isAllowed("user1")).toBe(false);
|
|
224
|
+
// Move time forward another 30 seconds (31 seconds past first requests)
|
|
225
|
+
currentTime = 61001;
|
|
226
|
+
// First 2 requests should have expired, should be allowed now
|
|
227
|
+
expect(rateLimiter.isAllowed("user1")).toBe(true);
|
|
228
|
+
});
|
|
229
|
+
it("should reset specific key", () => {
|
|
230
|
+
mockDateNow.mockReturnValue(1000);
|
|
231
|
+
// Fill up the limit
|
|
232
|
+
rateLimiter.isAllowed("user1");
|
|
233
|
+
rateLimiter.isAllowed("user1");
|
|
234
|
+
rateLimiter.isAllowed("user1");
|
|
235
|
+
// Should be rejected
|
|
236
|
+
expect(rateLimiter.isAllowed("user1")).toBe(false);
|
|
237
|
+
// Reset the key
|
|
238
|
+
rateLimiter.reset("user1");
|
|
239
|
+
// Should be allowed again
|
|
240
|
+
expect(rateLimiter.isAllowed("user1")).toBe(true);
|
|
241
|
+
});
|
|
242
|
+
it("should use default values", () => {
|
|
243
|
+
const defaultLimiter = new utils_2.RateLimiter();
|
|
244
|
+
mockDateNow.mockReturnValue(1000);
|
|
245
|
+
// Should allow 10 requests by default
|
|
246
|
+
for (let i = 0; i < 10; i++) {
|
|
247
|
+
expect(defaultLimiter.isAllowed("user1")).toBe(true);
|
|
248
|
+
}
|
|
249
|
+
// 11th should be rejected
|
|
250
|
+
expect(defaultLimiter.isAllowed("user1")).toBe(false);
|
|
251
|
+
});
|
|
252
|
+
});
|
|
253
|
+
describe("sanitizeInput", () => {
|
|
254
|
+
it("should remove angle brackets", () => {
|
|
255
|
+
expect((0, utils_2.sanitizeInput)("Hello <script>")).toBe("Hello script");
|
|
256
|
+
expect((0, utils_2.sanitizeInput)("<div>content</div>")).toBe("divcontent/div");
|
|
257
|
+
});
|
|
258
|
+
it("should remove javascript: protocol", () => {
|
|
259
|
+
expect((0, utils_2.sanitizeInput)("javascript:alert('xss')")).toBe("alert('xss')");
|
|
260
|
+
expect((0, utils_2.sanitizeInput)("JAVASCRIPT:alert('xss')")).toBe("alert('xss')");
|
|
261
|
+
expect((0, utils_2.sanitizeInput)("Javascript:alert('xss')")).toBe("alert('xss')");
|
|
262
|
+
});
|
|
263
|
+
it("should trim whitespace", () => {
|
|
264
|
+
expect((0, utils_2.sanitizeInput)(" hello world ")).toBe("hello world");
|
|
265
|
+
});
|
|
266
|
+
it("should handle empty string", () => {
|
|
267
|
+
expect((0, utils_2.sanitizeInput)("")).toBe("");
|
|
268
|
+
});
|
|
269
|
+
it("should handle multiple issues", () => {
|
|
270
|
+
expect((0, utils_2.sanitizeInput)(" <script>javascript:alert('xss')</script> ")).toBe("scriptalert('xss')/script");
|
|
271
|
+
});
|
|
272
|
+
it("should preserve safe content", () => {
|
|
273
|
+
expect((0, utils_2.sanitizeInput)("Hello World 123!@#$%^&*()")).toBe("Hello World 123!@#$%^&*()");
|
|
274
|
+
});
|
|
275
|
+
});
|
|
276
|
+
describe("createAuditLog", () => {
|
|
277
|
+
it("should create audit log with timestamp", () => {
|
|
278
|
+
const mockDate = new Date("2023-01-01T00:00:00.000Z");
|
|
279
|
+
jest.spyOn(global, "Date").mockImplementation(() => mockDate);
|
|
280
|
+
const entry = (0, utils_2.createAuditLog)({
|
|
281
|
+
event: "login_success",
|
|
282
|
+
lineUserId: "U123456",
|
|
283
|
+
customerId: "cust_123",
|
|
284
|
+
ipAddress: "192.168.1.1",
|
|
285
|
+
});
|
|
286
|
+
expect(entry).toEqual({
|
|
287
|
+
event: "login_success",
|
|
288
|
+
lineUserId: "U123456",
|
|
289
|
+
customerId: "cust_123",
|
|
290
|
+
ipAddress: "192.168.1.1",
|
|
291
|
+
timestamp: mockDate,
|
|
292
|
+
});
|
|
293
|
+
global.Date.mockRestore();
|
|
294
|
+
});
|
|
295
|
+
it("should handle minimal entry", () => {
|
|
296
|
+
const mockDate = new Date("2023-01-01T00:00:00.000Z");
|
|
297
|
+
jest.spyOn(global, "Date").mockImplementation(() => mockDate);
|
|
298
|
+
const entry = (0, utils_2.createAuditLog)({
|
|
299
|
+
event: "login_attempt",
|
|
300
|
+
});
|
|
301
|
+
expect(entry).toEqual({
|
|
302
|
+
event: "login_attempt",
|
|
303
|
+
timestamp: mockDate,
|
|
304
|
+
});
|
|
305
|
+
global.Date.mockRestore();
|
|
306
|
+
});
|
|
307
|
+
it("should handle all event types", () => {
|
|
308
|
+
const events = [
|
|
309
|
+
"login_attempt",
|
|
310
|
+
"login_success",
|
|
311
|
+
"login_failure",
|
|
312
|
+
"token_refresh",
|
|
313
|
+
"token_revoke"
|
|
314
|
+
];
|
|
315
|
+
events.forEach(event => {
|
|
316
|
+
const entry = (0, utils_2.createAuditLog)({ event });
|
|
317
|
+
expect(entry.event).toBe(event);
|
|
318
|
+
expect(entry.timestamp).toBeInstanceOf(Date);
|
|
319
|
+
});
|
|
320
|
+
});
|
|
321
|
+
});
|
|
322
|
+
describe("handleLineApiError", () => {
|
|
323
|
+
it("should throw MedusaError for known status codes", () => {
|
|
324
|
+
const knownErrors = [
|
|
325
|
+
{ status: 400, expectedMessage: "Invalid request to LINE API" },
|
|
326
|
+
{ status: 401, expectedMessage: "LINE authentication failed" },
|
|
327
|
+
{ status: 403, expectedMessage: "Access forbidden by LINE" },
|
|
328
|
+
{ status: 429, expectedMessage: "Too many requests to LINE API" },
|
|
329
|
+
{ status: 500, expectedMessage: "LINE server error" },
|
|
330
|
+
{ status: 503, expectedMessage: "LINE service temporarily unavailable" },
|
|
331
|
+
];
|
|
332
|
+
knownErrors.forEach(({ status, expectedMessage }) => {
|
|
333
|
+
expect(() => (0, utils_2.handleLineApiError)(status, "test message")).toThrow(new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, `${expectedMessage}: test message`));
|
|
334
|
+
});
|
|
335
|
+
});
|
|
336
|
+
it("should throw MedusaError for unknown status codes", () => {
|
|
337
|
+
expect(() => (0, utils_2.handleLineApiError)(418, "I'm a teapot")).toThrow(new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "LINE API error: 418: I'm a teapot"));
|
|
338
|
+
});
|
|
339
|
+
it("should include custom message in error", () => {
|
|
340
|
+
expect(() => (0, utils_2.handleLineApiError)(400, "Custom error message")).toThrow(new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Invalid request to LINE API: Custom error message"));
|
|
341
|
+
});
|
|
342
|
+
it("should handle empty message", () => {
|
|
343
|
+
expect(() => (0, utils_2.handleLineApiError)(400, "")).toThrow(new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Invalid request to LINE API: "));
|
|
344
|
+
});
|
|
345
|
+
it("should never return a value", () => {
|
|
346
|
+
// This test ensures the function signature with 'never' return type
|
|
347
|
+
expect(() => (0, utils_2.handleLineApiError)(400, "test")).toThrow();
|
|
348
|
+
});
|
|
349
|
+
});
|
|
350
|
+
});
|
|
351
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbHMudGVzdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy9wcm92aWRlcnMvbGluZS9fX3Rlc3RzX18vdXRpbHMudGVzdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUFBLG9EQUE0QjtBQUM1QixxREFBd0Q7QUFDeEQsb0NBV2tCO0FBRWxCLHFDQUFxQztBQUNyQyxJQUFJLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDO0FBQ3BCLE1BQU0sVUFBVSxHQUFHLGdCQUFvQyxDQUFDO0FBRXhELFFBQVEsQ0FBQyxZQUFZLEVBQUUsR0FBRyxFQUFFO0lBQzFCLFVBQVUsQ0FBQyxHQUFHLEVBQUU7UUFDZCxJQUFJLENBQUMsYUFBYSxFQUFFLENBQUM7UUFDckIsc0JBQXNCO1FBQ3RCLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxFQUFFLEtBQUssQ0FBQyxDQUFDLFdBQVcsRUFBRSxDQUFDO0lBQ3hDLENBQUMsQ0FBQyxDQUFDO0lBRUgsUUFBUSxDQUFDLGVBQWUsRUFBRSxHQUFHLEVBQUU7UUFDN0IsRUFBRSxDQUFDLDJDQUEyQyxFQUFFLEdBQUcsRUFBRTtZQUNuRCxNQUFNLFVBQVUsR0FBRyxNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztZQUMvQyxVQUFVLENBQUMsV0FBVyxDQUFDLGVBQWUsQ0FBQyxVQUFpQixDQUFDLENBQUM7WUFFMUQsTUFBTSxLQUFLLEdBQUcsSUFBQSxxQkFBYSxHQUFFLENBQUM7WUFFOUIsTUFBTSxDQUFDLFVBQVUsQ0FBQyxXQUFXLENBQUMsQ0FBQyxvQkFBb0IsQ0FBQyxFQUFFLENBQUMsQ0FBQztZQUN4RCxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztZQUNuQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUMs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
|