bullmq 5.56.8 → 5.56.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.
- package/dist/cjs/classes/scripts.js +3 -3
- package/dist/cjs/classes/scripts.js.map +1 -1
- package/dist/cjs/commands/includes/moveJobToWait.lua +15 -0
- package/dist/cjs/commands/moveStalledJobsToWait-8.lua +3 -11
- package/dist/cjs/commands/{moveToWaitingChildren-8.lua → moveToWaitingChildren-7.lua} +12 -38
- package/dist/cjs/enums/error-code.js +1 -1
- package/dist/cjs/enums/error-code.js.map +1 -1
- package/dist/cjs/scripts/index.js +1 -1
- package/dist/cjs/scripts/moveStalledJobsToWait-8.js +12 -8
- package/dist/cjs/scripts/moveStalledJobsToWait-8.js.map +1 -1
- package/dist/cjs/scripts/moveToWaitingChildren-7.js +107 -0
- package/dist/cjs/scripts/moveToWaitingChildren-7.js.map +1 -0
- package/dist/cjs/tsconfig-cjs.tsbuildinfo +1 -1
- package/dist/cjs/version.js +1 -1
- package/dist/esm/classes/scripts.js +3 -3
- package/dist/esm/classes/scripts.js.map +1 -1
- package/dist/esm/commands/includes/moveJobToWait.lua +15 -0
- package/dist/esm/commands/moveStalledJobsToWait-8.lua +3 -11
- package/dist/esm/commands/{moveToWaitingChildren-8.lua → moveToWaitingChildren-7.lua} +12 -38
- package/dist/esm/enums/error-code.d.ts +1 -1
- package/dist/esm/enums/error-code.js +1 -1
- package/dist/esm/enums/error-code.js.map +1 -1
- package/dist/esm/scripts/index.d.ts +1 -1
- package/dist/esm/scripts/index.js +1 -1
- package/dist/esm/scripts/moveStalledJobsToWait-8.js +12 -8
- package/dist/esm/scripts/moveStalledJobsToWait-8.js.map +1 -1
- package/dist/esm/scripts/moveToWaitingChildren-7.js +104 -0
- package/dist/esm/scripts/moveToWaitingChildren-7.js.map +1 -0
- package/dist/esm/tsconfig.tsbuildinfo +1 -1
- package/dist/esm/version.d.ts +1 -1
- package/dist/esm/version.js +1 -1
- package/package.json +3 -4
- package/dist/cjs/scripts/moveToWaitingChildren-8.js +0 -540
- package/dist/cjs/scripts/moveToWaitingChildren-8.js.map +0 -1
- package/dist/esm/scripts/moveToWaitingChildren-8.js +0 -537
- package/dist/esm/scripts/moveToWaitingChildren-8.js.map +0 -1
- /package/dist/esm/scripts/{moveToWaitingChildren-8.d.ts → moveToWaitingChildren-7.d.ts} +0 -0
|
@@ -25,6 +25,7 @@ local rcall = redis.call
|
|
|
25
25
|
--- @include "includes/addJobInTargetList"
|
|
26
26
|
--- @include "includes/batches"
|
|
27
27
|
--- @include "includes/getTargetQueueList"
|
|
28
|
+
--- @include "includes/moveJobToWait"
|
|
28
29
|
--- @include "includes/trimEvents"
|
|
29
30
|
|
|
30
31
|
local stalledKey = KEYS[1]
|
|
@@ -73,20 +74,11 @@ if (#stalling > 0) then
|
|
|
73
74
|
-- If this job has been stalled too many times, such as if it crashes the worker, then fail it.
|
|
74
75
|
local stalledCount = rcall("HINCRBY", jobKey, "stc", 1)
|
|
75
76
|
if stalledCount > maxStalledJobCount then
|
|
76
|
-
local jobAttributes = rcall("HMGET", jobKey, "opts", "parent")
|
|
77
|
-
local rawOpts = jobAttributes[1]
|
|
78
|
-
local rawParentData = jobAttributes[2]
|
|
79
|
-
local opts = cjson.decode(rawOpts)
|
|
80
|
-
|
|
81
77
|
local failedReason = "job stalled more than allowable limit"
|
|
82
78
|
rcall("HSET", jobKey, "defa", failedReason)
|
|
83
79
|
end
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
-- Move the job back to the wait queue, to immediately be picked up by a waiting worker.
|
|
87
|
-
addJobInTargetList(target, markerKey, "RPUSH", isPausedOrMaxed, jobId)
|
|
88
|
-
|
|
89
|
-
rcall("XADD", eventStreamKey, "*", "event", "waiting", "jobId", jobId, 'prev', 'active')
|
|
80
|
+
moveJobToWait(metaKey, activeKey, waitKey, pausedKey, markerKey, eventStreamKey, jobId,
|
|
81
|
+
"RPUSH")
|
|
90
82
|
|
|
91
83
|
-- Emit the stalled event
|
|
92
84
|
rcall("XADD", eventStreamKey, "*", "event", "stalled", "jobId", jobId)
|
|
@@ -8,8 +8,7 @@
|
|
|
8
8
|
KEYS[4] job dependencies key
|
|
9
9
|
KEYS[5] job unsuccessful key
|
|
10
10
|
KEYS[6] stalled key
|
|
11
|
-
KEYS[7]
|
|
12
|
-
KEYS[8] events key
|
|
11
|
+
KEYS[7] events key
|
|
13
12
|
|
|
14
13
|
ARGV[1] token
|
|
15
14
|
ARGV[2] child key
|
|
@@ -23,6 +22,7 @@
|
|
|
23
22
|
-1 - Missing job.
|
|
24
23
|
-2 - Missing lock
|
|
25
24
|
-3 - Job not in active set
|
|
25
|
+
-9 - Job has failed children
|
|
26
26
|
]]
|
|
27
27
|
local rcall = redis.call
|
|
28
28
|
local activeKey = KEYS[1]
|
|
@@ -31,15 +31,12 @@ local jobKey = KEYS[3]
|
|
|
31
31
|
local jobDependenciesKey = KEYS[4]
|
|
32
32
|
local jobUnsuccessfulKey = KEYS[5]
|
|
33
33
|
local stalledKey = KEYS[6]
|
|
34
|
-
local
|
|
34
|
+
local eventStreamKey = KEYS[7]
|
|
35
35
|
local token = ARGV[1]
|
|
36
36
|
local timestamp = ARGV[3]
|
|
37
37
|
local jobId = ARGV[4]
|
|
38
38
|
|
|
39
39
|
--- Includes
|
|
40
|
-
--- @include "includes/moveChildFromDependenciesIfNeeded"
|
|
41
|
-
--- @include "includes/removeDeduplicationKeyIfNeededOnFinalization"
|
|
42
|
-
--- @include "includes/removeJobsOnFail"
|
|
43
40
|
--- @include "includes/removeLock"
|
|
44
41
|
|
|
45
42
|
local function removeJobFromActive(activeKey, stalledKey, jobKey, jobId,
|
|
@@ -51,15 +48,15 @@ local function removeJobFromActive(activeKey, stalledKey, jobKey, jobId,
|
|
|
51
48
|
|
|
52
49
|
local numRemovedElements = rcall("LREM", activeKey, -1, jobId)
|
|
53
50
|
|
|
54
|
-
if
|
|
51
|
+
if numRemovedElements < 1 then
|
|
55
52
|
return -3
|
|
56
53
|
end
|
|
57
54
|
|
|
58
55
|
return 0
|
|
59
56
|
end
|
|
60
57
|
|
|
61
|
-
local function moveToWaitingChildren(activeKey, waitingChildrenKey, stalledKey,
|
|
62
|
-
timestamp, token)
|
|
58
|
+
local function moveToWaitingChildren(activeKey, waitingChildrenKey, stalledKey, eventStreamKey,
|
|
59
|
+
jobKey, jobId, timestamp, token)
|
|
63
60
|
local errorCode = removeJobFromActive(activeKey, stalledKey, jobKey, jobId, token)
|
|
64
61
|
if errorCode < 0 then
|
|
65
62
|
return errorCode
|
|
@@ -68,49 +65,26 @@ local function moveToWaitingChildren(activeKey, waitingChildrenKey, stalledKey,
|
|
|
68
65
|
local score = tonumber(timestamp)
|
|
69
66
|
|
|
70
67
|
rcall("ZADD", waitingChildrenKey, score, jobId)
|
|
68
|
+
rcall("XADD", eventStreamKey, "*", "event", "waiting-children", "jobId", jobId, 'prev', 'active')
|
|
71
69
|
|
|
72
70
|
return 0
|
|
73
71
|
end
|
|
74
72
|
|
|
75
73
|
if rcall("EXISTS", jobKey) == 1 then
|
|
76
74
|
if rcall("ZCARD", jobUnsuccessfulKey) ~= 0 then
|
|
77
|
-
|
|
78
|
-
if errorCode < 0 then
|
|
79
|
-
return errorCode
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
-- TODO: refactor this logic in an include later
|
|
83
|
-
local jobAttributes = rcall("HMGET", jobKey, "parent", "deid", "opts")
|
|
84
|
-
|
|
85
|
-
removeDeduplicationKeyIfNeededOnFinalization(ARGV[5], jobAttributes[2], jobId)
|
|
86
|
-
|
|
87
|
-
local failedReason = "children are failed"
|
|
88
|
-
rcall("ZADD", failedKey, timestamp, jobId)
|
|
89
|
-
rcall("HSET", jobKey, "finishedOn", timestamp)
|
|
90
|
-
rcall("XADD", KEYS[8], "*", "event", "failed", "jobId", jobId, "failedReason",
|
|
91
|
-
failedReason, "prev", "active")
|
|
92
|
-
|
|
93
|
-
local rawParentData = jobAttributes[1]
|
|
94
|
-
local rawOpts = jobAttributes[3]
|
|
95
|
-
local opts = cjson.decode(rawOpts)
|
|
96
|
-
|
|
97
|
-
moveChildFromDependenciesIfNeeded(rawParentData, jobKey, failedReason, timestamp)
|
|
98
|
-
|
|
99
|
-
removeJobsOnFail(ARGV[5], failedKey, jobId, opts, timestamp)
|
|
100
|
-
|
|
101
|
-
return 0
|
|
75
|
+
return -9
|
|
102
76
|
else
|
|
103
77
|
if ARGV[2] ~= "" then
|
|
104
78
|
if rcall("SISMEMBER", jobDependenciesKey, ARGV[2]) ~= 0 then
|
|
105
|
-
return moveToWaitingChildren(activeKey, waitingChildrenKey, stalledKey,
|
|
106
|
-
timestamp, token)
|
|
79
|
+
return moveToWaitingChildren(activeKey, waitingChildrenKey, stalledKey, eventStreamKey,
|
|
80
|
+
jobKey, jobId, timestamp, token)
|
|
107
81
|
end
|
|
108
82
|
|
|
109
83
|
return 1
|
|
110
84
|
else
|
|
111
85
|
if rcall("SCARD", jobDependenciesKey) ~= 0 then
|
|
112
|
-
return moveToWaitingChildren(activeKey, waitingChildrenKey, stalledKey,
|
|
113
|
-
timestamp, token)
|
|
86
|
+
return moveToWaitingChildren(activeKey, waitingChildrenKey, stalledKey, eventStreamKey,
|
|
87
|
+
jobKey, jobId, timestamp, token)
|
|
114
88
|
end
|
|
115
89
|
|
|
116
90
|
return 1
|
|
@@ -8,6 +8,6 @@ export var ErrorCode;
|
|
|
8
8
|
ErrorCode[ErrorCode["JobLockMismatch"] = -6] = "JobLockMismatch";
|
|
9
9
|
ErrorCode[ErrorCode["ParentJobCannotBeReplaced"] = -7] = "ParentJobCannotBeReplaced";
|
|
10
10
|
ErrorCode[ErrorCode["JobBelongsToJobScheduler"] = -8] = "JobBelongsToJobScheduler";
|
|
11
|
-
ErrorCode[ErrorCode["
|
|
11
|
+
ErrorCode[ErrorCode["JobHasFailedChildren"] = -9] = "JobHasFailedChildren";
|
|
12
12
|
})(ErrorCode || (ErrorCode = {}));
|
|
13
13
|
//# sourceMappingURL=error-code.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"error-code.js","sourceRoot":"","sources":["../../../src/enums/error-code.ts"],"names":[],"mappings":"AAAA,MAAM,CAAN,IAAY,SAUX;AAVD,WAAY,SAAS;IACnB,wDAAgB,CAAA;IAChB,gEAAoB,CAAA;IACpB,4DAAkB,CAAA;IAClB,sEAAuB,CAAA;IACvB,oEAAsB,CAAA;IACtB,gEAAoB,CAAA;IACpB,oFAA8B,CAAA;IAC9B,kFAA6B,CAAA;IAC7B,
|
|
1
|
+
{"version":3,"file":"error-code.js","sourceRoot":"","sources":["../../../src/enums/error-code.ts"],"names":[],"mappings":"AAAA,MAAM,CAAN,IAAY,SAUX;AAVD,WAAY,SAAS;IACnB,wDAAgB,CAAA;IAChB,gEAAoB,CAAA;IACpB,4DAAkB,CAAA;IAClB,sEAAuB,CAAA;IACvB,oEAAsB,CAAA;IACtB,gEAAoB,CAAA;IACpB,oFAA8B,CAAA;IAC9B,kFAA6B,CAAA;IAC7B,0EAAyB,CAAA;AAC3B,CAAC,EAVW,SAAS,KAAT,SAAS,QAUpB"}
|
|
@@ -28,7 +28,7 @@ export * from './moveStalledJobsToWait-8';
|
|
|
28
28
|
export * from './moveToActive-11';
|
|
29
29
|
export * from './moveToDelayed-8';
|
|
30
30
|
export * from './moveToFinished-14';
|
|
31
|
-
export * from './moveToWaitingChildren-
|
|
31
|
+
export * from './moveToWaitingChildren-7';
|
|
32
32
|
export * from './obliterate-2';
|
|
33
33
|
export * from './paginate-1';
|
|
34
34
|
export * from './pause-7';
|
|
@@ -28,7 +28,7 @@ export * from './moveStalledJobsToWait-8';
|
|
|
28
28
|
export * from './moveToActive-11';
|
|
29
29
|
export * from './moveToDelayed-8';
|
|
30
30
|
export * from './moveToFinished-14';
|
|
31
|
-
export * from './moveToWaitingChildren-
|
|
31
|
+
export * from './moveToWaitingChildren-7';
|
|
32
32
|
export * from './obliterate-2';
|
|
33
33
|
export * from './paginate-1';
|
|
34
34
|
export * from './pause-7';
|
|
@@ -70,6 +70,16 @@ local function getTargetQueueList(queueMetaKey, activeKey, waitKey, pausedKey)
|
|
|
70
70
|
end
|
|
71
71
|
return waitKey, false
|
|
72
72
|
end
|
|
73
|
+
--[[
|
|
74
|
+
Function to move job to wait to be picked up by a waiting worker.
|
|
75
|
+
]]
|
|
76
|
+
-- Includes
|
|
77
|
+
local function moveJobToWait(metaKey, activeKey, waitKey, pausedKey, markerKey, eventStreamKey,
|
|
78
|
+
jobId, pushCmd)
|
|
79
|
+
local target, isPausedOrMaxed = getTargetQueueList(metaKey, activeKey, waitKey, pausedKey)
|
|
80
|
+
addJobInTargetList(target, markerKey, pushCmd, isPausedOrMaxed, jobId)
|
|
81
|
+
rcall("XADD", eventStreamKey, "*", "event", "waiting", "jobId", jobId, 'prev', 'active')
|
|
82
|
+
end
|
|
73
83
|
--[[
|
|
74
84
|
Function to trim events, default 10000.
|
|
75
85
|
]]
|
|
@@ -132,17 +142,11 @@ if (#stalling > 0) then
|
|
|
132
142
|
-- If this job has been stalled too many times, such as if it crashes the worker, then fail it.
|
|
133
143
|
local stalledCount = rcall("HINCRBY", jobKey, "stc", 1)
|
|
134
144
|
if stalledCount > maxStalledJobCount then
|
|
135
|
-
local jobAttributes = rcall("HMGET", jobKey, "opts", "parent")
|
|
136
|
-
local rawOpts = jobAttributes[1]
|
|
137
|
-
local rawParentData = jobAttributes[2]
|
|
138
|
-
local opts = cjson.decode(rawOpts)
|
|
139
145
|
local failedReason = "job stalled more than allowable limit"
|
|
140
146
|
rcall("HSET", jobKey, "defa", failedReason)
|
|
141
147
|
end
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
addJobInTargetList(target, markerKey, "RPUSH", isPausedOrMaxed, jobId)
|
|
145
|
-
rcall("XADD", eventStreamKey, "*", "event", "waiting", "jobId", jobId, 'prev', 'active')
|
|
148
|
+
moveJobToWait(metaKey, activeKey, waitKey, pausedKey, markerKey, eventStreamKey, jobId,
|
|
149
|
+
"RPUSH")
|
|
146
150
|
-- Emit the stalled event
|
|
147
151
|
rcall("XADD", eventStreamKey, "*", "event", "stalled", "jobId", jobId)
|
|
148
152
|
table.insert(stalled, jobId)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"moveStalledJobsToWait-8.js","sourceRoot":"","sources":["../../../src/scripts/moveStalledJobsToWait-8.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,GAAG
|
|
1
|
+
{"version":3,"file":"moveStalledJobsToWait-8.js","sourceRoot":"","sources":["../../../src/scripts/moveStalledJobsToWait-8.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqKf,CAAC;AACF,MAAM,CAAC,MAAM,qBAAqB,GAAG;IACnC,IAAI,EAAE,uBAAuB;IAC7B,OAAO;IACP,IAAI,EAAE,CAAC;CACR,CAAC"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
const content = `--[[
|
|
2
|
+
Moves job from active to waiting children set.
|
|
3
|
+
Input:
|
|
4
|
+
KEYS[1] active key
|
|
5
|
+
KEYS[2] wait-children key
|
|
6
|
+
KEYS[3] job key
|
|
7
|
+
KEYS[4] job dependencies key
|
|
8
|
+
KEYS[5] job unsuccessful key
|
|
9
|
+
KEYS[6] stalled key
|
|
10
|
+
KEYS[7] events key
|
|
11
|
+
ARGV[1] token
|
|
12
|
+
ARGV[2] child key
|
|
13
|
+
ARGV[3] timestamp
|
|
14
|
+
ARGV[4] jobId
|
|
15
|
+
ARGV[5] prefix
|
|
16
|
+
Output:
|
|
17
|
+
0 - OK
|
|
18
|
+
1 - There are not pending dependencies.
|
|
19
|
+
-1 - Missing job.
|
|
20
|
+
-2 - Missing lock
|
|
21
|
+
-3 - Job not in active set
|
|
22
|
+
-9 - Job has failed children
|
|
23
|
+
]]
|
|
24
|
+
local rcall = redis.call
|
|
25
|
+
local activeKey = KEYS[1]
|
|
26
|
+
local waitingChildrenKey = KEYS[2]
|
|
27
|
+
local jobKey = KEYS[3]
|
|
28
|
+
local jobDependenciesKey = KEYS[4]
|
|
29
|
+
local jobUnsuccessfulKey = KEYS[5]
|
|
30
|
+
local stalledKey = KEYS[6]
|
|
31
|
+
local eventStreamKey = KEYS[7]
|
|
32
|
+
local token = ARGV[1]
|
|
33
|
+
local timestamp = ARGV[3]
|
|
34
|
+
local jobId = ARGV[4]
|
|
35
|
+
--- Includes
|
|
36
|
+
local function removeLock(jobKey, stalledKey, token, jobId)
|
|
37
|
+
if token ~= "0" then
|
|
38
|
+
local lockKey = jobKey .. ':lock'
|
|
39
|
+
local lockToken = rcall("GET", lockKey)
|
|
40
|
+
if lockToken == token then
|
|
41
|
+
rcall("DEL", lockKey)
|
|
42
|
+
rcall("SREM", stalledKey, jobId)
|
|
43
|
+
else
|
|
44
|
+
if lockToken then
|
|
45
|
+
-- Lock exists but token does not match
|
|
46
|
+
return -6
|
|
47
|
+
else
|
|
48
|
+
-- Lock is missing completely
|
|
49
|
+
return -2
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
return 0
|
|
54
|
+
end
|
|
55
|
+
local function removeJobFromActive(activeKey, stalledKey, jobKey, jobId,
|
|
56
|
+
token)
|
|
57
|
+
local errorCode = removeLock(jobKey, stalledKey, token, jobId)
|
|
58
|
+
if errorCode < 0 then
|
|
59
|
+
return errorCode
|
|
60
|
+
end
|
|
61
|
+
local numRemovedElements = rcall("LREM", activeKey, -1, jobId)
|
|
62
|
+
if numRemovedElements < 1 then
|
|
63
|
+
return -3
|
|
64
|
+
end
|
|
65
|
+
return 0
|
|
66
|
+
end
|
|
67
|
+
local function moveToWaitingChildren(activeKey, waitingChildrenKey, stalledKey, eventStreamKey,
|
|
68
|
+
jobKey, jobId, timestamp, token)
|
|
69
|
+
local errorCode = removeJobFromActive(activeKey, stalledKey, jobKey, jobId, token)
|
|
70
|
+
if errorCode < 0 then
|
|
71
|
+
return errorCode
|
|
72
|
+
end
|
|
73
|
+
local score = tonumber(timestamp)
|
|
74
|
+
rcall("ZADD", waitingChildrenKey, score, jobId)
|
|
75
|
+
rcall("XADD", eventStreamKey, "*", "event", "waiting-children", "jobId", jobId, 'prev', 'active')
|
|
76
|
+
return 0
|
|
77
|
+
end
|
|
78
|
+
if rcall("EXISTS", jobKey) == 1 then
|
|
79
|
+
if rcall("ZCARD", jobUnsuccessfulKey) ~= 0 then
|
|
80
|
+
return -9
|
|
81
|
+
else
|
|
82
|
+
if ARGV[2] ~= "" then
|
|
83
|
+
if rcall("SISMEMBER", jobDependenciesKey, ARGV[2]) ~= 0 then
|
|
84
|
+
return moveToWaitingChildren(activeKey, waitingChildrenKey, stalledKey, eventStreamKey,
|
|
85
|
+
jobKey, jobId, timestamp, token)
|
|
86
|
+
end
|
|
87
|
+
return 1
|
|
88
|
+
else
|
|
89
|
+
if rcall("SCARD", jobDependenciesKey) ~= 0 then
|
|
90
|
+
return moveToWaitingChildren(activeKey, waitingChildrenKey, stalledKey, eventStreamKey,
|
|
91
|
+
jobKey, jobId, timestamp, token)
|
|
92
|
+
end
|
|
93
|
+
return 1
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
return -1
|
|
98
|
+
`;
|
|
99
|
+
export const moveToWaitingChildren = {
|
|
100
|
+
name: 'moveToWaitingChildren',
|
|
101
|
+
content,
|
|
102
|
+
keys: 7,
|
|
103
|
+
};
|
|
104
|
+
//# sourceMappingURL=moveToWaitingChildren-7.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"moveToWaitingChildren-7.js","sourceRoot":"","sources":["../../../src/scripts/moveToWaitingChildren-7.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiGf,CAAC;AACF,MAAM,CAAC,MAAM,qBAAqB,GAAG;IACnC,IAAI,EAAE,uBAAuB;IAC7B,OAAO;IACP,IAAI,EAAE,CAAC;CACR,CAAC"}
|