wao 0.1.0 → 0.1.1

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,2274 +0,0 @@
1
- semver = {
2
- _VERSION = '1.2.1',
3
- _DESCRIPTION = 'semver for Lua',
4
- _URL = 'https://github.com/kikito/semver.lua',
5
- _LICENSE = [[
6
- MIT LICENSE
7
-
8
- Copyright (c) 2015 Enrique García Cota
9
-
10
- Permission is hereby granted, free of charge, to any person obtaining a
11
- copy of tother software and associated documentation files (the
12
- "Software"), to deal in the Software without restriction, including
13
- without limitation the rights to use, copy, modify, merge, publish,
14
- distribute, sublicense, and/or sell copies of the Software, and to
15
- permit persons to whom the Software is furnished to do so, subject to
16
- the following conditions:
17
-
18
- The above copyright notice and tother permission notice shall be included
19
- in all copies or substantial portions of the Software.
20
-
21
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22
- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
24
- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
25
- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
26
- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
27
- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28
- ]]
29
- }
30
-
31
- local function checkPositiveInteger(number, name)
32
- assert(number >= 0, name .. ' must be a valid positive number')
33
- assert(math.floor(number) == number, name .. ' must be an integer')
34
- end
35
-
36
- local function present(value)
37
- return value and value ~= ''
38
- end
39
-
40
-
41
- local function splitByDot(str)
42
- str = str or ""
43
- local t, count = {}, 0
44
- str:gsub("([^%.]+)", function(c)
45
- count = count + 1
46
- t[count] = c
47
- end)
48
- return t
49
- end
50
-
51
- local function parsePrereleaseAndBuildWithSign(str)
52
- local prereleaseWithSign, buildWithSign = str:match("^(-[^+]+)(+.+)$")
53
- if not (prereleaseWithSign and buildWithSign) then
54
- prereleaseWithSign = str:match("^(-.+)$")
55
- buildWithSign = str:match("^(+.+)$")
56
- end
57
- assert(prereleaseWithSign or buildWithSign, ("The parameter %q must begin with + or - to denote a prerelease or a build"):format(str))
58
- return prereleaseWithSign, buildWithSign
59
- end
60
-
61
- local function parsePrerelease(prereleaseWithSign)
62
- if prereleaseWithSign then
63
- local prerelease = prereleaseWithSign:match("^-(%w[%.%w-]*)$")
64
- assert(prerelease, ("The prerelease %q is not a slash followed by alphanumerics, dots and slashes"):format(prereleaseWithSign))
65
- return prerelease
66
- end
67
- end
68
-
69
- local function parseBuild(buildWithSign)
70
- if buildWithSign then
71
- local build = buildWithSign:match("^%+(%w[%.%w-]*)$")
72
- assert(build, ("The build %q is not a + sign followed by alphanumerics, dots and slashes"):format(buildWithSign))
73
- return build
74
- end
75
- end
76
-
77
- local function parsePrereleaseAndBuild(str)
78
- if not present(str) then return nil, nil end
79
-
80
- local prereleaseWithSign, buildWithSign = parsePrereleaseAndBuildWithSign(str)
81
-
82
- local prerelease = parsePrerelease(prereleaseWithSign)
83
- local build = parseBuild(buildWithSign)
84
-
85
- return prerelease, build
86
- end
87
-
88
- local function parseVersion(str)
89
- local sMajor, sMinor, sPatch, sPrereleaseAndBuild = str:match("^(%d+)%.?(%d*)%.?(%d*)(.-)$")
90
- assert(type(sMajor) == 'string', ("Could not extract version number(s) from %q"):format(str))
91
- local major, minor, patch = tonumber(sMajor), tonumber(sMinor), tonumber(sPatch)
92
- local prerelease, build = parsePrereleaseAndBuild(sPrereleaseAndBuild)
93
- return major, minor, patch, prerelease, build
94
- end
95
-
96
-
97
- local function compare(a,b)
98
- return a == b and 0 or a < b and -1 or 1
99
- end
100
-
101
- local function compareIds(myId, otherId)
102
- if myId == otherId then return 0
103
- elseif not myId then return -1
104
- elseif not otherId then return 1
105
- end
106
-
107
- local selfNumber, otherNumber = tonumber(myId), tonumber(otherId)
108
-
109
- if selfNumber and otherNumber then
110
- return compare(selfNumber, otherNumber)
111
- elseif selfNumber then
112
- return -1
113
- elseif otherNumber then
114
- return 1
115
- else
116
- return compare(myId, otherId)
117
- end
118
- end
119
-
120
- local function smallerIdList(myIds, otherIds)
121
- local myLength = #myIds
122
- local comparison
123
-
124
- for i=1, myLength do
125
- comparison = compareIds(myIds[i], otherIds[i])
126
- if comparison ~= 0 then
127
- return comparison == -1
128
- end
129
- end
130
-
131
- return myLength < #otherIds
132
- end
133
-
134
- local function smallerPrerelease(mine, other)
135
- if mine == other or not mine then return false
136
- elseif not other then return true
137
- end
138
-
139
- return smallerIdList(splitByDot(mine), splitByDot(other))
140
- end
141
-
142
- local methods = {}
143
-
144
- function methods:nextMajor()
145
- return semver(self.major + 1, 0, 0)
146
- end
147
- function methods:nextMinor()
148
- return semver(self.major, self.minor + 1, 0)
149
- end
150
- function methods:nextPatch()
151
- return semver(self.major, self.minor, self.patch + 1)
152
- end
153
-
154
- local mt = { __index = methods }
155
- function mt:__eq(other)
156
- return self.major == other.major and
157
- self.minor == other.minor and
158
- self.patch == other.patch and
159
- self.prerelease == other.prerelease
160
- end
161
- function mt:__lt(other)
162
- if self.major ~= other.major then return self.major < other.major end
163
- if self.minor ~= other.minor then return self.minor < other.minor end
164
- if self.patch ~= other.patch then return self.patch < other.patch end
165
- return smallerPrerelease(self.prerelease, other.prerelease)
166
-
167
- end
168
-
169
- function mt:__pow(other)
170
- if self.major == 0 then
171
- return self == other
172
- end
173
- return self.major == other.major and
174
- self.minor <= other.minor
175
- end
176
- function mt:__tostring()
177
- local buffer = { ("%d.%d.%d"):format(self.major, self.minor, self.patch) }
178
- if self.prerelease then table.insert(buffer, "-" .. self.prerelease) end
179
- if self.build then table.insert(buffer, "+" .. self.build) end
180
- return table.concat(buffer)
181
- end
182
-
183
- local function new(major, minor, patch, prerelease, build)
184
- assert(major, "At least one parameter is needed")
185
-
186
- if type(major) == 'string' then
187
- major,minor,patch,prerelease,build = parseVersion(major)
188
- end
189
- patch = patch or 0
190
- minor = minor or 0
191
-
192
- checkPositiveInteger(major, "major")
193
- checkPositiveInteger(minor, "minor")
194
- checkPositiveInteger(patch, "patch")
195
-
196
- local result = {major=major, minor=minor, patch=patch, prerelease=prerelease, build=build}
197
- return setmetatable(result, mt)
198
- end
199
-
200
- setmetatable(semver, { __call = function(_, ...) return new(...) end })
201
- semver._VERSION= semver(semver._VERSION)
202
-
203
- local band, bor, lshift
204
- = bit32.band, bit32.bor, bit32.lshift
205
- local type, setmetatable, ipairs, select
206
- = type, setmetatable, ipairs, select
207
- local unpack, tonumber, error
208
- = unpack, tonumber, error
209
- local strsub, strbyte, strchar, gmatch, gsub
210
- = string.sub, string.byte, string.char, string.gmatch, string.gsub
211
- local strmatch, strfind, strformat
212
- = string.match, string.find, string.format
213
- local tinsert, tremove, tconcat
214
- = table.insert, table.remove, table.concat
215
- local max, min, floor, ceil, abs
216
- = math.max, math.min, math.floor, math.ceil, math.abs
217
- local clock = os.clock
218
-
219
- local percentEncode_pattern = '[^A-Za-z0-9%-=;\',./~!@#$%&*%(%)_%+ %?]'
220
- local function percentEncode_replace(v)
221
- return strformat('%%%02X', strbyte(v))
222
- end
223
-
224
- local function indexOf(a, b, start)
225
- if (#b == 0) then
226
- return nil
227
- end
228
- return strfind(a, b, start, true)
229
- end
230
-
231
- local htmlEncode_pattern = '[&<>\n]'
232
- local htmlEncode_replace = {
233
- ['&'] = '&amp;', ['<'] = '&lt;', ['>'] = '&gt;', ['\n'] = '&para;<br>'
234
- }
235
-
236
- local diff_main,
237
- diff_cleanupSemantic,
238
- diff_cleanupEfficiency,
239
- diff_levenshtein,
240
- diff_prettyHtml
241
-
242
- local match_main
243
-
244
- local patch_make,
245
- patch_toText,
246
- patch_fromText,
247
- patch_apply
248
-
249
- local DIFF_DELETE = -1
250
- local DIFF_INSERT = 1
251
- local DIFF_EQUAL = 0
252
-
253
- local Diff_Timeout = 1.0
254
- local Diff_EditCost = 4
255
- local Match_Threshold = 0.5
256
- local Match_Distance = 1000
257
- local Patch_DeleteThreshold = 0.5
258
- local Patch_Margin = 4
259
- local Match_MaxBits = 32
260
-
261
- function settings(new)
262
- if new then
263
- Diff_Timeout = new.Diff_Timeout or Diff_Timeout
264
- Diff_EditCost = new.Diff_EditCost or Diff_EditCost
265
- Match_Threshold = new.Match_Threshold or Match_Threshold
266
- Match_Distance = new.Match_Distance or Match_Distance
267
- Patch_DeleteThreshold = new.Patch_DeleteThreshold or Patch_DeleteThreshold
268
- Patch_Margin = new.Patch_Margin or Patch_Margin
269
- Match_MaxBits = new.Match_MaxBits or Match_MaxBits
270
- else
271
- return {
272
- Diff_Timeout = Diff_Timeout;
273
- Diff_EditCost = Diff_EditCost;
274
- Match_Threshold = Match_Threshold;
275
- Match_Distance = Match_Distance;
276
- Patch_DeleteThreshold = Patch_DeleteThreshold;
277
- Patch_Margin = Patch_Margin;
278
- Match_MaxBits = Match_MaxBits;
279
- }
280
- end
281
- end
282
-
283
- local _diff_compute,
284
- _diff_bisect,
285
- _diff_halfMatchI,
286
- _diff_halfMatch,
287
- _diff_cleanupSemanticScore,
288
- _diff_cleanupSemanticLossless,
289
- _diff_cleanupMerge,
290
- _diff_commonPrefix,
291
- _diff_commonSuffix,
292
- _diff_commonOverlap,
293
- _diff_xIndex,
294
- _diff_text1,
295
- _diff_text2,
296
- _diff_toDelta,
297
- _diff_fromDelta
298
-
299
- function diff_main(text1, text2, opt_checklines, opt_deadline)
300
- if opt_deadline == nil then
301
- if Diff_Timeout <= 0 then
302
- opt_deadline = 2 ^ 31
303
- else
304
- opt_deadline = clock() + Diff_Timeout
305
- end
306
- end
307
- local deadline = opt_deadline
308
-
309
- if text1 == nil or text1 == nil then
310
- error('Null inputs. (diff_main)')
311
- end
312
-
313
- if text1 == text2 then
314
- if #text1 > 0 then
315
- return {{DIFF_EQUAL, text1}}
316
- end
317
- return {}
318
- end
319
-
320
- local checklines = false
321
-
322
- local commonlength = _diff_commonPrefix(text1, text2)
323
- local commonprefix
324
- if commonlength > 0 then
325
- commonprefix = strsub(text1, 1, commonlength)
326
- text1 = strsub(text1, commonlength + 1)
327
- text2 = strsub(text2, commonlength + 1)
328
- end
329
-
330
- commonlength = _diff_commonSuffix(text1, text2)
331
- local commonsuffix
332
- if commonlength > 0 then
333
- commonsuffix = strsub(text1, -commonlength)
334
- text1 = strsub(text1, 1, -commonlength - 1)
335
- text2 = strsub(text2, 1, -commonlength - 1)
336
- end
337
-
338
- local diffs = _diff_compute(text1, text2, checklines, deadline)
339
-
340
- if commonprefix then
341
- tinsert(diffs, 1, {DIFF_EQUAL, commonprefix})
342
- end
343
- if commonsuffix then
344
- diffs[#diffs + 1] = {DIFF_EQUAL, commonsuffix}
345
- end
346
-
347
- _diff_cleanupMerge(diffs)
348
- return diffs
349
- end
350
-
351
- function diff_cleanupSemantic(diffs)
352
- local changes = false
353
- local equalities = {}
354
- local equalitiesLength = 0
355
- local lastEquality = nil
356
- local pointer = 1
357
- local length_insertions1 = 0
358
- local length_deletions1 = 0
359
- local length_insertions2 = 0
360
- local length_deletions2 = 0
361
-
362
- while diffs[pointer] do
363
- if diffs[pointer][1] == DIFF_EQUAL then
364
- equalitiesLength = equalitiesLength + 1
365
- equalities[equalitiesLength] = pointer
366
- length_insertions1 = length_insertions2
367
- length_deletions1 = length_deletions2
368
- length_insertions2 = 0
369
- length_deletions2 = 0
370
- lastEquality = diffs[pointer][2]
371
- else
372
- if diffs[pointer][1] == DIFF_INSERT then
373
- length_insertions2 = length_insertions2 + #(diffs[pointer][2])
374
- else
375
- length_deletions2 = length_deletions2 + #(diffs[pointer][2])
376
- end
377
- if lastEquality
378
- and (#lastEquality <= max(length_insertions1, length_deletions1))
379
- and (#lastEquality <= max(length_insertions2, length_deletions2)) then
380
- tinsert(diffs, equalities[equalitiesLength],
381
- {DIFF_DELETE, lastEquality})
382
- diffs[equalities[equalitiesLength] + 1][1] = DIFF_INSERT
383
- equalitiesLength = equalitiesLength - 1
384
- equalitiesLength = equalitiesLength - 1
385
- pointer = (equalitiesLength > 0) and equalities[equalitiesLength] or 0
386
- length_insertions1, length_deletions1 = 0, 0
387
- length_insertions2, length_deletions2 = 0, 0
388
- lastEquality = nil
389
- changes = true
390
- end
391
- end
392
- pointer = pointer + 1
393
- end
394
-
395
- if changes then
396
- _diff_cleanupMerge(diffs)
397
- end
398
- _diff_cleanupSemanticLossless(diffs)
399
-
400
- pointer = 2
401
- while diffs[pointer] do
402
- if (diffs[pointer - 1][1] == DIFF_DELETE and
403
- diffs[pointer][1] == DIFF_INSERT) then
404
- local deletion = diffs[pointer - 1][2]
405
- local insertion = diffs[pointer][2]
406
- local overlap_length1 = _diff_commonOverlap(deletion, insertion)
407
- local overlap_length2 = _diff_commonOverlap(insertion, deletion)
408
- if (overlap_length1 >= overlap_length2) then
409
- if (overlap_length1 >= #deletion / 2 or
410
- overlap_length1 >= #insertion / 2) then
411
- tinsert(diffs, pointer,
412
- {DIFF_EQUAL, strsub(insertion, 1, overlap_length1)})
413
- diffs[pointer - 1][2] =
414
- strsub(deletion, 1, #deletion - overlap_length1)
415
- diffs[pointer + 1][2] = strsub(insertion, overlap_length1 + 1)
416
- pointer = pointer + 1
417
- end
418
- else
419
- if (overlap_length2 >= #deletion / 2 or
420
- overlap_length2 >= #insertion / 2) then
421
- tinsert(diffs, pointer,
422
- {DIFF_EQUAL, strsub(deletion, 1, overlap_length2)})
423
- diffs[pointer - 1] = {DIFF_INSERT,
424
- strsub(insertion, 1, #insertion - overlap_length2)}
425
- diffs[pointer + 1] = {DIFF_DELETE,
426
- strsub(deletion, overlap_length2 + 1)}
427
- pointer = pointer + 1
428
- end
429
- end
430
- pointer = pointer + 1
431
- end
432
- pointer = pointer + 1
433
- end
434
- end
435
-
436
- function diff_cleanupEfficiency(diffs)
437
- local changes = false
438
- local equalities = {}
439
- local equalitiesLength = 0
440
- local lastEquality = nil
441
- local pointer = 1
442
- local pre_ins = 0
443
- local pre_del = 0
444
- local post_ins = 0
445
- local post_del = 0
446
-
447
- while diffs[pointer] do
448
- if diffs[pointer][1] == DIFF_EQUAL then
449
- local diffText = diffs[pointer][2]
450
- if (#diffText < Diff_EditCost) and (post_ins == 1 or post_del == 1) then
451
- equalitiesLength = equalitiesLength + 1
452
- equalities[equalitiesLength] = pointer
453
- pre_ins, pre_del = post_ins, post_del
454
- lastEquality = diffText
455
- else
456
- equalitiesLength = 0
457
- lastEquality = nil
458
- end
459
- post_ins, post_del = 0, 0
460
- else
461
- if diffs[pointer][1] == DIFF_DELETE then
462
- post_del = 1
463
- else
464
- post_ins = 1
465
- end
466
- if lastEquality and (
467
- (pre_ins+pre_del+post_ins+post_del == 4)
468
- or
469
- (
470
- (#lastEquality < Diff_EditCost / 2)
471
- and
472
- (pre_ins+pre_del+post_ins+post_del == 3)
473
- )) then
474
- tinsert(diffs, equalities[equalitiesLength],
475
- {DIFF_DELETE, lastEquality})
476
- diffs[equalities[equalitiesLength] + 1][1] = DIFF_INSERT
477
- equalitiesLength = equalitiesLength - 1
478
- lastEquality = nil
479
- if (pre_ins == 1) and (pre_del == 1) then
480
- post_ins, post_del = 1, 1
481
- equalitiesLength = 0
482
- else
483
- equalitiesLength = equalitiesLength - 1
484
- pointer = (equalitiesLength > 0) and equalities[equalitiesLength] or 0
485
- post_ins, post_del = 0, 0
486
- end
487
- changes = true
488
- end
489
- end
490
- pointer = pointer + 1
491
- end
492
-
493
- if changes then
494
- _diff_cleanupMerge(diffs)
495
- end
496
- end
497
-
498
- function diff_levenshtein(diffs)
499
- local levenshtein = 0
500
- local insertions, deletions = 0, 0
501
- for x, diff in ipairs(diffs) do
502
- local op, data = diff[1], diff[2]
503
- if (op == DIFF_INSERT) then
504
- insertions = insertions + #data
505
- elseif (op == DIFF_DELETE) then
506
- deletions = deletions + #data
507
- elseif (op == DIFF_EQUAL) then
508
- levenshtein = levenshtein + max(insertions, deletions)
509
- insertions = 0
510
- deletions = 0
511
- end
512
- end
513
- levenshtein = levenshtein + max(insertions, deletions)
514
- return levenshtein
515
- end
516
-
517
- function diff_prettyHtml(diffs)
518
- local html = {}
519
- for x, diff in ipairs(diffs) do
520
- local op = diff[1]
521
- local data = diff[2]
522
- local text = gsub(data, htmlEncode_pattern, htmlEncode_replace)
523
- if op == DIFF_INSERT then
524
- html[x] = '<ins style="background:#e6ffe6;">' .. text .. '</ins>'
525
- elseif op == DIFF_DELETE then
526
- html[x] = '<del style="background:#ffe6e6;">' .. text .. '</del>'
527
- elseif op == DIFF_EQUAL then
528
- html[x] = '<span>' .. text .. '</span>'
529
- end
530
- end
531
- return tconcat(html)
532
- end
533
-
534
- function _diff_compute(text1, text2, checklines, deadline)
535
- if #text1 == 0 then
536
- return {{DIFF_INSERT, text2}}
537
- end
538
-
539
- if #text2 == 0 then
540
- return {{DIFF_DELETE, text1}}
541
- end
542
-
543
- local diffs
544
-
545
- local longtext = (#text1 > #text2) and text1 or text2
546
- local shorttext = (#text1 > #text2) and text2 or text1
547
- local i = indexOf(longtext, shorttext)
548
-
549
- if i ~= nil then
550
- diffs = {
551
- {DIFF_INSERT, strsub(longtext, 1, i - 1)},
552
- {DIFF_EQUAL, shorttext},
553
- {DIFF_INSERT, strsub(longtext, i + #shorttext)}
554
- }
555
- if #text1 > #text2 then
556
- diffs[1][1], diffs[3][1] = DIFF_DELETE, DIFF_DELETE
557
- end
558
- return diffs
559
- end
560
-
561
- if #shorttext == 1 then
562
- return {{DIFF_DELETE, text1}, {DIFF_INSERT, text2}}
563
- end
564
-
565
- do
566
- local
567
- text1_a, text1_b,
568
- text2_a, text2_b,
569
- mid_common = _diff_halfMatch(text1, text2)
570
-
571
- if text1_a then
572
- local diffs_a = diff_main(text1_a, text2_a, checklines, deadline)
573
- local diffs_b = diff_main(text1_b, text2_b, checklines, deadline)
574
- local diffs_a_len = #diffs_a
575
- diffs = diffs_a
576
- diffs[diffs_a_len + 1] = {DIFF_EQUAL, mid_common}
577
- for i, b_diff in ipairs(diffs_b) do
578
- diffs[diffs_a_len + 1 + i] = b_diff
579
- end
580
- return diffs
581
- end
582
- end
583
-
584
- return _diff_bisect(text1, text2, deadline)
585
- end
586
-
587
- function _diff_bisect(text1, text2, deadline)
588
- local text1_length = #text1
589
- local text2_length = #text2
590
- local _sub, _element
591
- local max_d = ceil((text1_length + text2_length) / 2)
592
- local v_offset = max_d
593
- local v_length = 2 * max_d
594
- local v1 = {}
595
- local v2 = {}
596
- for x = 0, v_length - 1 do
597
- v1[x] = -1
598
- v2[x] = -1
599
- end
600
- v1[v_offset + 1] = 0
601
- v2[v_offset + 1] = 0
602
- local delta = text1_length - text2_length
603
- local front = (delta % 2 ~= 0)
604
- local k1start = 0
605
- local k1end = 0
606
- local k2start = 0
607
- local k2end = 0
608
- for d = 0, max_d - 1 do
609
- if clock() > deadline then
610
- break
611
- end
612
- for k1 = -d + k1start, d - k1end, 2 do
613
- local k1_offset = v_offset + k1
614
- local x1
615
- if (k1 == -d) or ((k1 ~= d) and
616
- (v1[k1_offset - 1] < v1[k1_offset + 1])) then
617
- x1 = v1[k1_offset + 1]
618
- else
619
- x1 = v1[k1_offset - 1] + 1
620
- end
621
- local y1 = x1 - k1
622
- while (x1 <= text1_length) and (y1 <= text2_length)
623
- and (strsub(text1, x1, x1) == strsub(text2, y1, y1)) do
624
- x1 = x1 + 1
625
- y1 = y1 + 1
626
- end
627
- v1[k1_offset] = x1
628
- if x1 > text1_length + 1 then
629
- k1end = k1end + 2
630
- elseif y1 > text2_length + 1 then
631
- k1start = k1start + 2
632
- elseif front then
633
- local k2_offset = v_offset + delta - k1
634
- if k2_offset >= 0 and k2_offset < v_length and v2[k2_offset] ~= -1 then
635
- local x2 = text1_length - v2[k2_offset] + 1
636
- if x1 > x2 then
637
- return _diff_bisectSplit(text1, text2, x1, y1, deadline)
638
- end
639
- end
640
- end
641
- end
642
-
643
- for k2 = -d + k2start, d - k2end, 2 do
644
- local k2_offset = v_offset + k2
645
- local x2
646
- if (k2 == -d) or ((k2 ~= d) and
647
- (v2[k2_offset - 1] < v2[k2_offset + 1])) then
648
- x2 = v2[k2_offset + 1]
649
- else
650
- x2 = v2[k2_offset - 1] + 1
651
- end
652
- local y2 = x2 - k2
653
- while (x2 <= text1_length) and (y2 <= text2_length)
654
- and (strsub(text1, -x2, -x2) == strsub(text2, -y2, -y2)) do
655
- x2 = x2 + 1
656
- y2 = y2 + 1
657
- end
658
- v2[k2_offset] = x2
659
- if x2 > text1_length + 1 then
660
- k2end = k2end + 2
661
- elseif y2 > text2_length + 1 then
662
- k2start = k2start + 2
663
- elseif not front then
664
- local k1_offset = v_offset + delta - k2
665
- if k1_offset >= 0 and k1_offset < v_length and v1[k1_offset] ~= -1 then
666
- local x1 = v1[k1_offset]
667
- local y1 = v_offset + x1 - k1_offset
668
- x2 = text1_length - x2 + 1
669
- if x1 > x2 then
670
- return _diff_bisectSplit(text1, text2, x1, y1, deadline)
671
- end
672
- end
673
- end
674
- end
675
- end
676
- return {{DIFF_DELETE, text1}, {DIFF_INSERT, text2}}
677
- end
678
-
679
- function _diff_bisectSplit(text1, text2, x, y, deadline)
680
- local text1a = strsub(text1, 1, x - 1)
681
- local text2a = strsub(text2, 1, y - 1)
682
- local text1b = strsub(text1, x)
683
- local text2b = strsub(text2, y)
684
-
685
- local diffs = diff_main(text1a, text2a, false, deadline)
686
- local diffsb = diff_main(text1b, text2b, false, deadline)
687
-
688
- local diffs_len = #diffs
689
- for i, v in ipairs(diffsb) do
690
- diffs[diffs_len + i] = v
691
- end
692
- return diffs
693
- end
694
-
695
- function _diff_commonPrefix(text1, text2)
696
- if (#text1 == 0) or (#text2 == 0) or (strbyte(text1, 1) ~= strbyte(text2, 1))
697
- then
698
- return 0
699
- end
700
- local pointermin = 1
701
- local pointermax = min(#text1, #text2)
702
- local pointermid = pointermax
703
- local pointerstart = 1
704
- while (pointermin < pointermid) do
705
- if (strsub(text1, pointerstart, pointermid)
706
- == strsub(text2, pointerstart, pointermid)) then
707
- pointermin = pointermid
708
- pointerstart = pointermin
709
- else
710
- pointermax = pointermid
711
- end
712
- pointermid = floor(pointermin + (pointermax - pointermin) / 2)
713
- end
714
- return pointermid
715
- end
716
-
717
- function _diff_commonSuffix(text1, text2)
718
- if (#text1 == 0) or (#text2 == 0)
719
- or (strbyte(text1, -1) ~= strbyte(text2, -1)) then
720
- return 0
721
- end
722
- local pointermin = 1
723
- local pointermax = min(#text1, #text2)
724
- local pointermid = pointermax
725
- local pointerend = 1
726
- while (pointermin < pointermid) do
727
- if (strsub(text1, -pointermid, -pointerend)
728
- == strsub(text2, -pointermid, -pointerend)) then
729
- pointermin = pointermid
730
- pointerend = pointermin
731
- else
732
- pointermax = pointermid
733
- end
734
- pointermid = floor(pointermin + (pointermax - pointermin) / 2)
735
- end
736
- return pointermid
737
- end
738
-
739
- function _diff_commonOverlap(text1, text2)
740
- local text1_length = #text1
741
- local text2_length = #text2
742
- if text1_length == 0 or text2_length == 0 then
743
- return 0
744
- end
745
- if text1_length > text2_length then
746
- text1 = strsub(text1, text1_length - text2_length + 1)
747
- elseif text1_length < text2_length then
748
- text2 = strsub(text2, 1, text1_length)
749
- end
750
- local text_length = min(text1_length, text2_length)
751
- if text1 == text2 then
752
- return text_length
753
- end
754
-
755
- local best = 0
756
- local length = 1
757
- while true do
758
- local pattern = strsub(text1, text_length - length + 1)
759
- local found = strfind(text2, pattern, 1, true)
760
- if found == nil then
761
- return best
762
- end
763
- length = length + found - 1
764
- if found == 1 or strsub(text1, text_length - length + 1) ==
765
- strsub(text2, 1, length) then
766
- best = length
767
- length = length + 1
768
- end
769
- end
770
- end
771
-
772
- function _diff_halfMatchI(longtext, shorttext, i)
773
- local seed = strsub(longtext, i, i + floor(#longtext / 4))
774
- local j = 0
775
- local best_common = ''
776
- local best_longtext_a, best_longtext_b, best_shorttext_a, best_shorttext_b
777
- while true do
778
- j = indexOf(shorttext, seed, j + 1)
779
- if (j == nil) then
780
- break
781
- end
782
- local prefixLength = _diff_commonPrefix(strsub(longtext, i),
783
- strsub(shorttext, j))
784
- local suffixLength = _diff_commonSuffix(strsub(longtext, 1, i - 1),
785
- strsub(shorttext, 1, j - 1))
786
- if #best_common < suffixLength + prefixLength then
787
- best_common = strsub(shorttext, j - suffixLength, j - 1)
788
- .. strsub(shorttext, j, j + prefixLength - 1)
789
- best_longtext_a = strsub(longtext, 1, i - suffixLength - 1)
790
- best_longtext_b = strsub(longtext, i + prefixLength)
791
- best_shorttext_a = strsub(shorttext, 1, j - suffixLength - 1)
792
- best_shorttext_b = strsub(shorttext, j + prefixLength)
793
- end
794
- end
795
- if #best_common * 2 >= #longtext then
796
- return {best_longtext_a, best_longtext_b,
797
- best_shorttext_a, best_shorttext_b, best_common}
798
- else
799
- return nil
800
- end
801
- end
802
-
803
- function _diff_halfMatch(text1, text2)
804
- if Diff_Timeout <= 0 then
805
- return nil
806
- end
807
- local longtext = (#text1 > #text2) and text1 or text2
808
- local shorttext = (#text1 > #text2) and text2 or text1
809
- if (#longtext < 4) or (#shorttext * 2 < #longtext) then
810
- return nil
811
- end
812
-
813
- local hm1 = _diff_halfMatchI(longtext, shorttext, ceil(#longtext / 4))
814
- local hm2 = _diff_halfMatchI(longtext, shorttext, ceil(#longtext / 2))
815
- local hm
816
- if not hm1 and not hm2 then
817
- return nil
818
- elseif not hm2 then
819
- hm = hm1
820
- elseif not hm1 then
821
- hm = hm2
822
- else
823
- hm = (#hm1[5] > #hm2[5]) and hm1 or hm2
824
- end
825
-
826
- local text1_a, text1_b, text2_a, text2_b
827
- if (#text1 > #text2) then
828
- text1_a, text1_b = hm[1], hm[2]
829
- text2_a, text2_b = hm[3], hm[4]
830
- else
831
- text2_a, text2_b = hm[1], hm[2]
832
- text1_a, text1_b = hm[3], hm[4]
833
- end
834
- local mid_common = hm[5]
835
- return text1_a, text1_b, text2_a, text2_b, mid_common
836
- end
837
-
838
- function _diff_cleanupSemanticScore(one, two)
839
- if (#one == 0) or (#two == 0) then
840
- return 6
841
- end
842
-
843
- local char1 = strsub(one, -1)
844
- local char2 = strsub(two, 1, 1)
845
- local nonAlphaNumeric1 = strmatch(char1, '%W')
846
- local nonAlphaNumeric2 = strmatch(char2, '%W')
847
- local whitespace1 = nonAlphaNumeric1 and strmatch(char1, '%s')
848
- local whitespace2 = nonAlphaNumeric2 and strmatch(char2, '%s')
849
- local lineBreak1 = whitespace1 and strmatch(char1, '%c')
850
- local lineBreak2 = whitespace2 and strmatch(char2, '%c')
851
- local blankLine1 = lineBreak1 and strmatch(one, '\n\r?\n$')
852
- local blankLine2 = lineBreak2 and strmatch(two, '^\r?\n\r?\n')
853
-
854
- if blankLine1 or blankLine2 then
855
- return 5
856
- elseif lineBreak1 or lineBreak2 then
857
- return 4
858
- elseif nonAlphaNumeric1 and not whitespace1 and whitespace2 then
859
- return 3
860
- elseif whitespace1 or whitespace2 then
861
- return 2
862
- elseif nonAlphaNumeric1 or nonAlphaNumeric2 then
863
- return 1
864
- end
865
- return 0
866
- end
867
-
868
- function _diff_cleanupSemanticLossless(diffs)
869
- local pointer = 2
870
- while diffs[pointer + 1] do
871
- local prevDiff, nextDiff = diffs[pointer - 1], diffs[pointer + 1]
872
- if (prevDiff[1] == DIFF_EQUAL) and (nextDiff[1] == DIFF_EQUAL) then
873
- local diff = diffs[pointer]
874
-
875
- local equality1 = prevDiff[2]
876
- local edit = diff[2]
877
- local equality2 = nextDiff[2]
878
-
879
- local commonOffset = _diff_commonSuffix(equality1, edit)
880
- if commonOffset > 0 then
881
- local commonString = strsub(edit, -commonOffset)
882
- equality1 = strsub(equality1, 1, -commonOffset - 1)
883
- edit = commonString .. strsub(edit, 1, -commonOffset - 1)
884
- equality2 = commonString .. equality2
885
- end
886
-
887
- local bestEquality1 = equality1
888
- local bestEdit = edit
889
- local bestEquality2 = equality2
890
- local bestScore = _diff_cleanupSemanticScore(equality1, edit)
891
- + _diff_cleanupSemanticScore(edit, equality2)
892
-
893
- while strbyte(edit, 1) == strbyte(equality2, 1) do
894
- equality1 = equality1 .. strsub(edit, 1, 1)
895
- edit = strsub(edit, 2) .. strsub(equality2, 1, 1)
896
- equality2 = strsub(equality2, 2)
897
- local score = _diff_cleanupSemanticScore(equality1, edit)
898
- + _diff_cleanupSemanticScore(edit, equality2)
899
- if score >= bestScore then
900
- bestScore = score
901
- bestEquality1 = equality1
902
- bestEdit = edit
903
- bestEquality2 = equality2
904
- end
905
- end
906
- if prevDiff[2] ~= bestEquality1 then
907
- if #bestEquality1 > 0 then
908
- diffs[pointer - 1][2] = bestEquality1
909
- else
910
- tremove(diffs, pointer - 1)
911
- pointer = pointer - 1
912
- end
913
- diffs[pointer][2] = bestEdit
914
- if #bestEquality2 > 0 then
915
- diffs[pointer + 1][2] = bestEquality2
916
- else
917
- tremove(diffs, pointer + 1, 1)
918
- pointer = pointer - 1
919
- end
920
- end
921
- end
922
- pointer = pointer + 1
923
- end
924
- end
925
-
926
- function _diff_cleanupMerge(diffs)
927
- diffs[#diffs + 1] = {DIFF_EQUAL, ''}
928
- local pointer = 1
929
- local count_delete, count_insert = 0, 0
930
- local text_delete, text_insert = '', ''
931
- local commonlength
932
- while diffs[pointer] do
933
- local diff_type = diffs[pointer][1]
934
- if diff_type == DIFF_INSERT then
935
- count_insert = count_insert + 1
936
- text_insert = text_insert .. diffs[pointer][2]
937
- pointer = pointer + 1
938
- elseif diff_type == DIFF_DELETE then
939
- count_delete = count_delete + 1
940
- text_delete = text_delete .. diffs[pointer][2]
941
- pointer = pointer + 1
942
- elseif diff_type == DIFF_EQUAL then
943
- if count_delete + count_insert > 1 then
944
- if (count_delete > 0) and (count_insert > 0) then
945
- commonlength = _diff_commonPrefix(text_insert, text_delete)
946
- if commonlength > 0 then
947
- local back_pointer = pointer - count_delete - count_insert
948
- if (back_pointer > 1) and (diffs[back_pointer - 1][1] == DIFF_EQUAL)
949
- then
950
- diffs[back_pointer - 1][2] = diffs[back_pointer - 1][2]
951
- .. strsub(text_insert, 1, commonlength)
952
- else
953
- tinsert(diffs, 1,
954
- {DIFF_EQUAL, strsub(text_insert, 1, commonlength)})
955
- pointer = pointer + 1
956
- end
957
- text_insert = strsub(text_insert, commonlength + 1)
958
- text_delete = strsub(text_delete, commonlength + 1)
959
- end
960
- commonlength = _diff_commonSuffix(text_insert, text_delete)
961
- if commonlength ~= 0 then
962
- diffs[pointer][2] =
963
- strsub(text_insert, -commonlength) .. diffs[pointer][2]
964
- text_insert = strsub(text_insert, 1, -commonlength - 1)
965
- text_delete = strsub(text_delete, 1, -commonlength - 1)
966
- end
967
- end
968
- pointer = pointer - count_delete - count_insert
969
- for i = 1, count_delete + count_insert do
970
- tremove(diffs, pointer)
971
- end
972
- if #text_delete > 0 then
973
- tinsert(diffs, pointer, {DIFF_DELETE, text_delete})
974
- pointer = pointer + 1
975
- end
976
- if #text_insert > 0 then
977
- tinsert(diffs, pointer, {DIFF_INSERT, text_insert})
978
- pointer = pointer + 1
979
- end
980
- pointer = pointer + 1
981
- elseif (pointer > 1) and (diffs[pointer - 1][1] == DIFF_EQUAL) then
982
- diffs[pointer - 1][2] = diffs[pointer - 1][2] .. diffs[pointer][2]
983
- tremove(diffs, pointer)
984
- else
985
- pointer = pointer + 1
986
- end
987
- count_insert, count_delete = 0, 0
988
- text_delete, text_insert = '', ''
989
- end
990
- end
991
- if diffs[#diffs][2] == '' then
992
- diffs[#diffs] = nil
993
- end
994
-
995
- local changes = false
996
- pointer = 2
997
- while pointer < #diffs do
998
- local prevDiff, nextDiff = diffs[pointer - 1], diffs[pointer + 1]
999
- if (prevDiff[1] == DIFF_EQUAL) and (nextDiff[1] == DIFF_EQUAL) then
1000
- local diff = diffs[pointer]
1001
- local currentText = diff[2]
1002
- local prevText = prevDiff[2]
1003
- local nextText = nextDiff[2]
1004
- if #prevText == 0 then
1005
- tremove(diffs, pointer - 1)
1006
- changes = true
1007
- elseif strsub(currentText, -#prevText) == prevText then
1008
- diff[2] = prevText .. strsub(currentText, 1, -#prevText - 1)
1009
- nextDiff[2] = prevText .. nextDiff[2]
1010
- tremove(diffs, pointer - 1)
1011
- changes = true
1012
- elseif strsub(currentText, 1, #nextText) == nextText then
1013
- prevDiff[2] = prevText .. nextText
1014
- diff[2] = strsub(currentText, #nextText + 1) .. nextText
1015
- tremove(diffs, pointer + 1)
1016
- changes = true
1017
- end
1018
- end
1019
- pointer = pointer + 1
1020
- end
1021
-
1022
- if changes then
1023
- return _diff_cleanupMerge(diffs)
1024
- end
1025
- end
1026
-
1027
- function _diff_xIndex(diffs, loc)
1028
- local chars1 = 1
1029
- local chars2 = 1
1030
- local last_chars1 = 1
1031
- local last_chars2 = 1
1032
- local x
1033
- for _x, diff in ipairs(diffs) do
1034
- x = _x
1035
- if diff[1] ~= DIFF_INSERT then
1036
- chars1 = chars1 + #diff[2]
1037
- end
1038
- if diff[1] ~= DIFF_DELETE then
1039
- chars2 = chars2 + #diff[2]
1040
- end
1041
- if chars1 > loc then
1042
- break
1043
- end
1044
- last_chars1 = chars1
1045
- last_chars2 = chars2
1046
- end
1047
- if diffs[x + 1] and (diffs[x][1] == DIFF_DELETE) then
1048
- return last_chars2
1049
- end
1050
- return last_chars2 + (loc - last_chars1)
1051
- end
1052
-
1053
- function _diff_text1(diffs)
1054
- local text = {}
1055
- for x, diff in ipairs(diffs) do
1056
- if diff[1] ~= DIFF_INSERT then
1057
- text[#text + 1] = diff[2]
1058
- end
1059
- end
1060
- return tconcat(text)
1061
- end
1062
-
1063
- function _diff_text2(diffs)
1064
- local text = {}
1065
- for x, diff in ipairs(diffs) do
1066
- if diff[1] ~= DIFF_DELETE then
1067
- text[#text + 1] = diff[2]
1068
- end
1069
- end
1070
- return tconcat(text)
1071
- end
1072
-
1073
- function _diff_toDelta(diffs)
1074
- local text = {}
1075
- for x, diff in ipairs(diffs) do
1076
- local op, data = diff[1], diff[2]
1077
- if op == DIFF_INSERT then
1078
- text[x] = '+' .. gsub(data, percentEncode_pattern, percentEncode_replace)
1079
- elseif op == DIFF_DELETE then
1080
- text[x] = '-' .. #data
1081
- elseif op == DIFF_EQUAL then
1082
- text[x] = '=' .. #data
1083
- end
1084
- end
1085
- return tconcat(text, '\t')
1086
- end
1087
-
1088
- function _diff_fromDelta(text1, delta)
1089
- local diffs = {}
1090
- local diffsLength = 0
1091
- local pointer = 1
1092
- for token in gmatch(delta, '[^\t]+') do
1093
- local tokenchar, param = strsub(token, 1, 1), strsub(token, 2)
1094
- if (tokenchar == '+') then
1095
- local invalidDecode = false
1096
- local decoded = gsub(param, '%%(.?.?)',
1097
- function(c)
1098
- local n = tonumber(c, 16)
1099
- if (#c ~= 2) or (n == nil) then
1100
- invalidDecode = true
1101
- return ''
1102
- end
1103
- return strchar(n)
1104
- end)
1105
- if invalidDecode then
1106
- error('Illegal escape in _diff_fromDelta: ' .. param)
1107
- end
1108
- diffsLength = diffsLength + 1
1109
- diffs[diffsLength] = {DIFF_INSERT, decoded}
1110
- elseif (tokenchar == '-') or (tokenchar == '=') then
1111
- local n = tonumber(param)
1112
- if (n == nil) or (n < 0) then
1113
- error('Invalid number in _diff_fromDelta: ' .. param)
1114
- end
1115
- local text = strsub(text1, pointer, pointer + n - 1)
1116
- pointer = pointer + n
1117
- if (tokenchar == '=') then
1118
- diffsLength = diffsLength + 1
1119
- diffs[diffsLength] = {DIFF_EQUAL, text}
1120
- else
1121
- diffsLength = diffsLength + 1
1122
- diffs[diffsLength] = {DIFF_DELETE, text}
1123
- end
1124
- else
1125
- error('Invalid diff operation in _diff_fromDelta: ' .. token)
1126
- end
1127
- end
1128
- if (pointer ~= #text1 + 1) then
1129
- error('Delta length (' .. (pointer - 1)
1130
- .. ') does not equal source text length (' .. #text1 .. ').')
1131
- end
1132
- return diffs
1133
- end
1134
-
1135
- local _match_bitap, _match_alphabet
1136
-
1137
- function match_main(text, pattern, loc)
1138
- if text == nil or pattern == nil or loc == nil then
1139
- error('Null inputs. (match_main)')
1140
- end
1141
-
1142
- if text == pattern then
1143
- return 1
1144
- elseif #text == 0 then
1145
- return -1
1146
- end
1147
- loc = max(1, min(loc, #text))
1148
- if strsub(text, loc, loc + #pattern - 1) == pattern then
1149
- return loc
1150
- else
1151
- return _match_bitap(text, pattern, loc)
1152
- end
1153
- end
1154
-
1155
- function _match_alphabet(pattern)
1156
- local s = {}
1157
- local i = 0
1158
- for c in gmatch(pattern, '.') do
1159
- s[c] = bor(s[c] or 0, lshift(1, #pattern - i - 1))
1160
- i = i + 1
1161
- end
1162
- return s
1163
- end
1164
-
1165
- function _match_bitap(text, pattern, loc)
1166
- if #pattern > Match_MaxBits then
1167
- error('Pattern too long.')
1168
- end
1169
-
1170
- local s = _match_alphabet(pattern)
1171
-
1172
- local function _match_bitapScore(e, x)
1173
- local accuracy = e / #pattern
1174
- local proximity = abs(loc - x)
1175
- if (Match_Distance == 0) then
1176
- return (proximity == 0) and 1 or accuracy
1177
- end
1178
- return accuracy + (proximity / Match_Distance)
1179
- end
1180
-
1181
- local score_threshold = Match_Threshold
1182
- local best_loc = indexOf(text, pattern, loc)
1183
- if best_loc then
1184
- score_threshold = min(_match_bitapScore(0, best_loc), score_threshold)
1185
- end
1186
-
1187
- local matchmask = lshift(1, #pattern - 1)
1188
- best_loc = -1
1189
-
1190
- local bin_min, bin_mid
1191
- local bin_max = #pattern + #text
1192
- local last_rd
1193
- for d = 0, #pattern - 1, 1 do
1194
- bin_min = 0
1195
- bin_mid = bin_max
1196
- while (bin_min < bin_mid) do
1197
- if (_match_bitapScore(d, loc + bin_mid) <= score_threshold) then
1198
- bin_min = bin_mid
1199
- else
1200
- bin_max = bin_mid
1201
- end
1202
- bin_mid = floor(bin_min + (bin_max - bin_min) / 2)
1203
- end
1204
- bin_max = bin_mid
1205
- local start = max(1, loc - bin_mid + 1)
1206
- local finish = min(loc + bin_mid, #text) + #pattern
1207
-
1208
- local rd = {}
1209
- for j = start, finish do
1210
- rd[j] = 0
1211
- end
1212
- rd[finish + 1] = lshift(1, d) - 1
1213
- for j = finish, start, -1 do
1214
- local charMatch = s[strsub(text, j - 1, j - 1)] or 0
1215
- if (d == 0) then
1216
- rd[j] = band(bor((rd[j + 1] * 2), 1), charMatch)
1217
- else
1218
- rd[j] = bor(
1219
- band(
1220
- bor(
1221
- lshift(rd[j + 1], 1),
1222
- 1
1223
- ),
1224
- charMatch
1225
- ),
1226
- bor(
1227
- bor(
1228
- lshift(bor(last_rd[j + 1], last_rd[j]), 1),
1229
- 1
1230
- ),
1231
- last_rd[j + 1]
1232
- )
1233
- )
1234
- end
1235
- if (band(rd[j], matchmask) ~= 0) then
1236
- local score = _match_bitapScore(d, j - 1)
1237
- if (score <= score_threshold) then
1238
- score_threshold = score
1239
- best_loc = j - 1
1240
- if (best_loc > loc) then
1241
- start = max(1, loc * 2 - best_loc)
1242
- else
1243
- break
1244
- end
1245
- end
1246
- end
1247
- end
1248
- if (_match_bitapScore(d + 1, loc) > score_threshold) then
1249
- break
1250
- end
1251
- last_rd = rd
1252
- end
1253
- return best_loc
1254
- end
1255
-
1256
- local _patch_addContext,
1257
- _patch_deepCopy,
1258
- _patch_addPadding,
1259
- _patch_splitMax,
1260
- _patch_appendText,
1261
- _new_patch_obj
1262
-
1263
- function patch_make(a, opt_b, opt_c)
1264
- local text1, diffs
1265
- local type_a, type_b, type_c = type(a), type(opt_b), type(opt_c)
1266
- if (type_a == 'string') and (type_b == 'string') and (type_c == 'nil') then
1267
- text1 = a
1268
- diffs = diff_main(text1, opt_b, true)
1269
- if (#diffs > 2) then
1270
- diff_cleanupSemantic(diffs)
1271
- diff_cleanupEfficiency(diffs)
1272
- end
1273
- elseif (type_a == 'table') and (type_b == 'nil') and (type_c == 'nil') then
1274
- diffs = a
1275
- text1 = _diff_text1(diffs)
1276
- elseif (type_a == 'string') and (type_b == 'table') and (type_c == 'nil') then
1277
- text1 = a
1278
- diffs = opt_b
1279
- elseif (type_a == 'string') and (type_b == 'string') and (type_c == 'table')
1280
- then
1281
- text1 = a
1282
- diffs = opt_c
1283
- else
1284
- error('Unknown call format to patch_make.')
1285
- end
1286
-
1287
- if (diffs[1] == nil) then
1288
- return {}
1289
- end
1290
-
1291
- local patches = {}
1292
- local patch = _new_patch_obj()
1293
- local patchDiffLength = 0
1294
- local char_count1 = 0
1295
- local char_count2 = 0
1296
- local prepatch_text, postpatch_text = text1, text1
1297
- for x, diff in ipairs(diffs) do
1298
- local diff_type, diff_text = diff[1], diff[2]
1299
-
1300
- if (patchDiffLength == 0) and (diff_type ~= DIFF_EQUAL) then
1301
- patch.start1 = char_count1 + 1
1302
- patch.start2 = char_count2 + 1
1303
- end
1304
-
1305
- if (diff_type == DIFF_INSERT) then
1306
- patchDiffLength = patchDiffLength + 1
1307
- patch.diffs[patchDiffLength] = diff
1308
- patch.length2 = patch.length2 + #diff_text
1309
- postpatch_text = strsub(postpatch_text, 1, char_count2)
1310
- .. diff_text .. strsub(postpatch_text, char_count2 + 1)
1311
- elseif (diff_type == DIFF_DELETE) then
1312
- patch.length1 = patch.length1 + #diff_text
1313
- patchDiffLength = patchDiffLength + 1
1314
- patch.diffs[patchDiffLength] = diff
1315
- postpatch_text = strsub(postpatch_text, 1, char_count2)
1316
- .. strsub(postpatch_text, char_count2 + #diff_text + 1)
1317
- elseif (diff_type == DIFF_EQUAL) then
1318
- if (#diff_text <= Patch_Margin * 2)
1319
- and (patchDiffLength ~= 0) and (#diffs ~= x) then
1320
- patchDiffLength = patchDiffLength + 1
1321
- patch.diffs[patchDiffLength] = diff
1322
- patch.length1 = patch.length1 + #diff_text
1323
- patch.length2 = patch.length2 + #diff_text
1324
- elseif (#diff_text >= Patch_Margin * 2) then
1325
- if (patchDiffLength ~= 0) then
1326
- _patch_addContext(patch, prepatch_text)
1327
- patches[#patches + 1] = patch
1328
- patch = _new_patch_obj()
1329
- patchDiffLength = 0
1330
- prepatch_text = postpatch_text
1331
- char_count1 = char_count2
1332
- end
1333
- end
1334
- end
1335
-
1336
- if (diff_type ~= DIFF_INSERT) then
1337
- char_count1 = char_count1 + #diff_text
1338
- end
1339
- if (diff_type ~= DIFF_DELETE) then
1340
- char_count2 = char_count2 + #diff_text
1341
- end
1342
- end
1343
-
1344
- if (patchDiffLength > 0) then
1345
- _patch_addContext(patch, prepatch_text)
1346
- patches[#patches + 1] = patch
1347
- end
1348
-
1349
- return patches
1350
- end
1351
-
1352
- function patch_apply(patches, text)
1353
- if patches[1] == nil then
1354
- return text, {}
1355
- end
1356
-
1357
- patches = _patch_deepCopy(patches)
1358
-
1359
- local nullPadding = _patch_addPadding(patches)
1360
- text = nullPadding .. text .. nullPadding
1361
-
1362
- _patch_splitMax(patches)
1363
- local delta = 0
1364
- local results = {}
1365
- for x, patch in ipairs(patches) do
1366
- local expected_loc = patch.start2 + delta
1367
- local text1 = _diff_text1(patch.diffs)
1368
- local start_loc
1369
- local end_loc = -1
1370
- if #text1 > Match_MaxBits then
1371
- start_loc = match_main(text,
1372
- strsub(text1, 1, Match_MaxBits), expected_loc)
1373
- if start_loc ~= -1 then
1374
- end_loc = match_main(text, strsub(text1, -Match_MaxBits),
1375
- expected_loc + #text1 - Match_MaxBits)
1376
- if end_loc == -1 or start_loc >= end_loc then
1377
- start_loc = -1
1378
- end
1379
- end
1380
- else
1381
- start_loc = match_main(text, text1, expected_loc)
1382
- end
1383
- if start_loc == -1 then
1384
- results[x] = false
1385
- delta = delta - patch.length2 - patch.length1
1386
- else
1387
- results[x] = true
1388
- delta = start_loc - expected_loc
1389
- local text2
1390
- if end_loc == -1 then
1391
- text2 = strsub(text, start_loc, start_loc + #text1 - 1)
1392
- else
1393
- text2 = strsub(text, start_loc, end_loc + Match_MaxBits - 1)
1394
- end
1395
- if text1 == text2 then
1396
- text = strsub(text, 1, start_loc - 1) .. _diff_text2(patch.diffs)
1397
- .. strsub(text, start_loc + #text1)
1398
- else
1399
- local diffs = diff_main(text1, text2, false)
1400
- if (#text1 > Match_MaxBits)
1401
- and (diff_levenshtein(diffs) / #text1 > Patch_DeleteThreshold) then
1402
- results[x] = false
1403
- else
1404
- _diff_cleanupSemanticLossless(diffs)
1405
- local index1 = 1
1406
- local index2
1407
- for y, mod in ipairs(patch.diffs) do
1408
- if mod[1] ~= DIFF_EQUAL then
1409
- index2 = _diff_xIndex(diffs, index1)
1410
- end
1411
- if mod[1] == DIFF_INSERT then
1412
- text = strsub(text, 1, start_loc + index2 - 2)
1413
- .. mod[2] .. strsub(text, start_loc + index2 - 1)
1414
- elseif mod[1] == DIFF_DELETE then
1415
- text = strsub(text, 1, start_loc + index2 - 2) .. strsub(text,
1416
- start_loc + _diff_xIndex(diffs, index1 + #mod[2] - 1))
1417
- end
1418
- if mod[1] ~= DIFF_DELETE then
1419
- index1 = index1 + #mod[2]
1420
- end
1421
- end
1422
- end
1423
- end
1424
- end
1425
- end
1426
- text = strsub(text, #nullPadding + 1, -#nullPadding - 1)
1427
- return text, results
1428
- end
1429
-
1430
- function patch_toText(patches)
1431
- local text = {}
1432
- for x, patch in ipairs(patches) do
1433
- _patch_appendText(patch, text)
1434
- end
1435
- return tconcat(text)
1436
- end
1437
-
1438
- function patch_fromText(textline)
1439
- local patches = {}
1440
- if (#textline == 0) then
1441
- return patches
1442
- end
1443
- local text = {}
1444
- for line in gmatch(textline, '([^\n]*)') do
1445
- text[#text + 1] = line
1446
- end
1447
- local textPointer = 1
1448
- while (textPointer <= #text) do
1449
- local start1, length1, start2, length2
1450
- = strmatch(text[textPointer], '^@@ %-(%d+),?(%d*) %+(%d+),?(%d*) @@$')
1451
- if (start1 == nil) then
1452
- error('Invalid patch string: "' .. text[textPointer] .. '"')
1453
- end
1454
- local patch = _new_patch_obj()
1455
- patches[#patches + 1] = patch
1456
-
1457
- start1 = tonumber(start1)
1458
- length1 = tonumber(length1) or 1
1459
- if (length1 == 0) then
1460
- start1 = start1 + 1
1461
- end
1462
- patch.start1 = start1
1463
- patch.length1 = length1
1464
-
1465
- start2 = tonumber(start2)
1466
- length2 = tonumber(length2) or 1
1467
- if (length2 == 0) then
1468
- start2 = start2 + 1
1469
- end
1470
- patch.start2 = start2
1471
- patch.length2 = length2
1472
-
1473
- textPointer = textPointer + 1
1474
-
1475
- while true do
1476
- local line = text[textPointer]
1477
- if (line == nil) then
1478
- break
1479
- end
1480
- local sign; sign, line = strsub(line, 1, 1), strsub(line, 2)
1481
-
1482
- local invalidDecode = false
1483
- local decoded = gsub(line, '%%(.?.?)',
1484
- function(c)
1485
- local n = tonumber(c, 16)
1486
- if (#c ~= 2) or (n == nil) then
1487
- invalidDecode = true
1488
- return ''
1489
- end
1490
- return strchar(n)
1491
- end)
1492
- if invalidDecode then
1493
- error('Illegal escape in patch_fromText: ' .. line)
1494
- end
1495
-
1496
- line = decoded
1497
-
1498
- if (sign == '-') then
1499
- patch.diffs[#patch.diffs + 1] = {DIFF_DELETE, line}
1500
- elseif (sign == '+') then
1501
- patch.diffs[#patch.diffs + 1] = {DIFF_INSERT, line}
1502
- elseif (sign == ' ') then
1503
- patch.diffs[#patch.diffs + 1] = {DIFF_EQUAL, line}
1504
- elseif (sign == '@') then
1505
- break
1506
- elseif (sign == '') then
1507
- else
1508
- error('Invalid patch mode "' .. sign .. '" in: ' .. line)
1509
- end
1510
- textPointer = textPointer + 1
1511
- end
1512
- end
1513
- return patches
1514
- end
1515
-
1516
- local patch_meta = {
1517
- __tostring = function(patch)
1518
- local buf = {}
1519
- _patch_appendText(patch, buf)
1520
- return tconcat(buf)
1521
- end
1522
- }
1523
-
1524
- function _new_patch_obj()
1525
- return setmetatable({
1526
- diffs = {};
1527
- start1 = 1;
1528
- start2 = 1;
1529
- length1 = 0;
1530
- length2 = 0;
1531
- }, patch_meta)
1532
- end
1533
-
1534
- function _patch_addContext(patch, text)
1535
- if (#text == 0) then
1536
- return
1537
- end
1538
- local pattern = strsub(text, patch.start2, patch.start2 + patch.length1 - 1)
1539
- local padding = 0
1540
-
1541
- local firstMatch = indexOf(text, pattern)
1542
- local secondMatch = nil
1543
- if (firstMatch ~= nil) then
1544
- secondMatch = indexOf(text, pattern, firstMatch + 1)
1545
- end
1546
- while (#pattern == 0 or secondMatch ~= nil)
1547
- and (#pattern < Match_MaxBits - Patch_Margin - Patch_Margin) do
1548
- padding = padding + Patch_Margin
1549
- pattern = strsub(text, max(1, patch.start2 - padding),
1550
- patch.start2 + patch.length1 - 1 + padding)
1551
- firstMatch = indexOf(text, pattern)
1552
- if (firstMatch ~= nil) then
1553
- secondMatch = indexOf(text, pattern, firstMatch + 1)
1554
- else
1555
- secondMatch = nil
1556
- end
1557
- end
1558
- padding = padding + Patch_Margin
1559
-
1560
- local prefix = strsub(text, max(1, patch.start2 - padding), patch.start2 - 1)
1561
- if (#prefix > 0) then
1562
- tinsert(patch.diffs, 1, {DIFF_EQUAL, prefix})
1563
- end
1564
-
1565
- local suffix = strsub(text, patch.start2 + patch.length1,
1566
- patch.start2 + patch.length1 - 1 + padding)
1567
- if (#suffix > 0) then
1568
- patch.diffs[#patch.diffs + 1] = {DIFF_EQUAL, suffix}
1569
- end
1570
-
1571
- patch.start1 = patch.start1 - #prefix
1572
- patch.start2 = patch.start2 - #prefix
1573
- patch.length1 = patch.length1 + #prefix + #suffix
1574
- patch.length2 = patch.length2 + #prefix + #suffix
1575
- end
1576
-
1577
- function _patch_deepCopy(patches)
1578
- local patchesCopy = {}
1579
- for x, patch in ipairs(patches) do
1580
- local patchCopy = _new_patch_obj()
1581
- local diffsCopy = {}
1582
- for i, diff in ipairs(patch.diffs) do
1583
- diffsCopy[i] = {diff[1], diff[2]}
1584
- end
1585
- patchCopy.diffs = diffsCopy
1586
- patchCopy.start1 = patch.start1
1587
- patchCopy.start2 = patch.start2
1588
- patchCopy.length1 = patch.length1
1589
- patchCopy.length2 = patch.length2
1590
- patchesCopy[x] = patchCopy
1591
- end
1592
- return patchesCopy
1593
- end
1594
-
1595
- function _patch_addPadding(patches)
1596
- local paddingLength = Patch_Margin
1597
- local nullPadding = ''
1598
- for x = 1, paddingLength do
1599
- nullPadding = nullPadding .. strchar(x)
1600
- end
1601
-
1602
- for x, patch in ipairs(patches) do
1603
- patch.start1 = patch.start1 + paddingLength
1604
- patch.start2 = patch.start2 + paddingLength
1605
- end
1606
-
1607
- local patch = patches[1]
1608
- local diffs = patch.diffs
1609
- local firstDiff = diffs[1]
1610
- if (firstDiff == nil) or (firstDiff[1] ~= DIFF_EQUAL) then
1611
- tinsert(diffs, 1, {DIFF_EQUAL, nullPadding})
1612
- patch.start1 = patch.start1 - paddingLength
1613
- patch.start2 = patch.start2 - paddingLength
1614
- patch.length1 = patch.length1 + paddingLength
1615
- patch.length2 = patch.length2 + paddingLength
1616
- elseif (paddingLength > #firstDiff[2]) then
1617
- local extraLength = paddingLength - #firstDiff[2]
1618
- firstDiff[2] = strsub(nullPadding, #firstDiff[2] + 1) .. firstDiff[2]
1619
- patch.start1 = patch.start1 - extraLength
1620
- patch.start2 = patch.start2 - extraLength
1621
- patch.length1 = patch.length1 + extraLength
1622
- patch.length2 = patch.length2 + extraLength
1623
- end
1624
-
1625
- patch = patches[#patches]
1626
- diffs = patch.diffs
1627
- local lastDiff = diffs[#diffs]
1628
- if (lastDiff == nil) or (lastDiff[1] ~= DIFF_EQUAL) then
1629
- diffs[#diffs + 1] = {DIFF_EQUAL, nullPadding}
1630
- patch.length1 = patch.length1 + paddingLength
1631
- patch.length2 = patch.length2 + paddingLength
1632
- elseif (paddingLength > #lastDiff[2]) then
1633
- local extraLength = paddingLength - #lastDiff[2]
1634
- lastDiff[2] = lastDiff[2] .. strsub(nullPadding, 1, extraLength)
1635
- patch.length1 = patch.length1 + extraLength
1636
- patch.length2 = patch.length2 + extraLength
1637
- end
1638
-
1639
- return nullPadding
1640
- end
1641
-
1642
- function _patch_splitMax(patches)
1643
- local patch_size = Match_MaxBits
1644
- local x = 1
1645
- while true do
1646
- local patch = patches[x]
1647
- if patch == nil then
1648
- return
1649
- end
1650
- if patch.length1 > patch_size then
1651
- local bigpatch = patch
1652
- tremove(patches, x)
1653
- x = x - 1
1654
- local start1 = bigpatch.start1
1655
- local start2 = bigpatch.start2
1656
- local precontext = ''
1657
- while bigpatch.diffs[1] do
1658
- local patch = _new_patch_obj()
1659
- local empty = true
1660
- patch.start1 = start1 - #precontext
1661
- patch.start2 = start2 - #precontext
1662
- if precontext ~= '' then
1663
- patch.length1, patch.length2 = #precontext, #precontext
1664
- patch.diffs[#patch.diffs + 1] = {DIFF_EQUAL, precontext}
1665
- end
1666
- while bigpatch.diffs[1] and (patch.length1 < patch_size-Patch_Margin) do
1667
- local diff_type = bigpatch.diffs[1][1]
1668
- local diff_text = bigpatch.diffs[1][2]
1669
- if (diff_type == DIFF_INSERT) then
1670
- patch.length2 = patch.length2 + #diff_text
1671
- start2 = start2 + #diff_text
1672
- patch.diffs[#(patch.diffs) + 1] = bigpatch.diffs[1]
1673
- tremove(bigpatch.diffs, 1)
1674
- empty = false
1675
- elseif (diff_type == DIFF_DELETE) and (#patch.diffs == 1)
1676
- and (patch.diffs[1][1] == DIFF_EQUAL)
1677
- and (#diff_text > 2 * patch_size) then
1678
- patch.length1 = patch.length1 + #diff_text
1679
- start1 = start1 + #diff_text
1680
- empty = false
1681
- patch.diffs[#patch.diffs + 1] = {diff_type, diff_text}
1682
- tremove(bigpatch.diffs, 1)
1683
- else
1684
- diff_text = strsub(diff_text, 1,
1685
- patch_size - patch.length1 - Patch_Margin)
1686
- patch.length1 = patch.length1 + #diff_text
1687
- start1 = start1 + #diff_text
1688
- if (diff_type == DIFF_EQUAL) then
1689
- patch.length2 = patch.length2 + #diff_text
1690
- start2 = start2 + #diff_text
1691
- else
1692
- empty = false
1693
- end
1694
- patch.diffs[#patch.diffs + 1] = {diff_type, diff_text}
1695
- if (diff_text == bigpatch.diffs[1][2]) then
1696
- tremove(bigpatch.diffs, 1)
1697
- else
1698
- bigpatch.diffs[1][2]
1699
- = strsub(bigpatch.diffs[1][2], #diff_text + 1)
1700
- end
1701
- end
1702
- end
1703
- precontext = _diff_text2(patch.diffs)
1704
- precontext = strsub(precontext, -Patch_Margin)
1705
- local postcontext = strsub(_diff_text1(bigpatch.diffs), 1, Patch_Margin)
1706
- if postcontext ~= '' then
1707
- patch.length1 = patch.length1 + #postcontext
1708
- patch.length2 = patch.length2 + #postcontext
1709
- if patch.diffs[1]
1710
- and (patch.diffs[#patch.diffs][1] == DIFF_EQUAL) then
1711
- patch.diffs[#patch.diffs][2] = patch.diffs[#patch.diffs][2]
1712
- .. postcontext
1713
- else
1714
- patch.diffs[#patch.diffs + 1] = {DIFF_EQUAL, postcontext}
1715
- end
1716
- end
1717
- if not empty then
1718
- x = x + 1
1719
- tinsert(patches, x, patch)
1720
- end
1721
- end
1722
- end
1723
- x = x + 1
1724
- end
1725
- end
1726
-
1727
- function _patch_appendText(patch, text)
1728
- local coords1, coords2
1729
- local length1, length2 = patch.length1, patch.length2
1730
- local start1, start2 = patch.start1, patch.start2
1731
- local diffs = patch.diffs
1732
-
1733
- if length1 == 1 then
1734
- coords1 = start1
1735
- else
1736
- coords1 = ((length1 == 0) and (start1 - 1) or start1) .. ',' .. length1
1737
- end
1738
-
1739
- if length2 == 1 then
1740
- coords2 = start2
1741
- else
1742
- coords2 = ((length2 == 0) and (start2 - 1) or start2) .. ',' .. length2
1743
- end
1744
- text[#text + 1] = '@@ -' .. coords1 .. ' +' .. coords2 .. ' @@\n'
1745
-
1746
- local op
1747
- for x, diff in ipairs(patch.diffs) do
1748
- local diff_type = diff[1]
1749
- if diff_type == DIFF_INSERT then
1750
- op = '+'
1751
- elseif diff_type == DIFF_DELETE then
1752
- op = '-'
1753
- elseif diff_type == DIFF_EQUAL then
1754
- op = ' '
1755
- end
1756
- text[#text + 1] = op
1757
- .. gsub(diffs[x][2], percentEncode_pattern, percentEncode_replace)
1758
- .. '\n'
1759
- end
1760
-
1761
- return text
1762
- end
1763
-
1764
- local _M = {}
1765
-
1766
- _M.DIFF_DELETE = DIFF_DELETE
1767
- _M.DIFF_INSERT = DIFF_INSERT
1768
- _M.DIFF_EQUAL = DIFF_EQUAL
1769
-
1770
- _M.diff_main = diff_main
1771
- _M.diff_cleanupSemantic = diff_cleanupSemantic
1772
- _M.diff_cleanupEfficiency = diff_cleanupEfficiency
1773
- _M.diff_levenshtein = diff_levenshtein
1774
- _M.diff_prettyHtml = diff_prettyHtml
1775
-
1776
- _M.match_main = match_main
1777
-
1778
- _M.patch_make = patch_make
1779
- _M.patch_toText = patch_toText
1780
- _M.patch_fromText = patch_fromText
1781
- _M.patch_apply = patch_apply
1782
-
1783
- _M.diff_commonPrefix = _diff_commonPrefix
1784
- _M.diff_commonSuffix = _diff_commonSuffix
1785
- _M.diff_commonOverlap = _diff_commonOverlap
1786
- _M.diff_halfMatch = _diff_halfMatch
1787
- _M.diff_bisect = _diff_bisect
1788
- _M.diff_cleanupMerge = _diff_cleanupMerge
1789
- _M.diff_cleanupSemanticLossless = _diff_cleanupSemanticLossless
1790
- _M.diff_text1 = _diff_text1
1791
- _M.diff_text2 = _diff_text2
1792
- _M.diff_toDelta = _diff_toDelta
1793
- _M.diff_fromDelta = _diff_fromDelta
1794
- _M.diff_xIndex = _diff_xIndex
1795
- _M.match_alphabet = _match_alphabet
1796
- _M.match_bitap = _match_bitap
1797
- _M.new_patch_obj = _new_patch_obj
1798
- _M.patch_addContext = _patch_addContext
1799
- _M.patch_splitMax = _patch_splitMax
1800
- _M.patch_addPadding = _patch_addPadding
1801
- _M.settings = settings
1802
-
1803
- dmp = _M
1804
-
1805
- local bint = require('.bint')(256)
1806
- local json = require('json')
1807
- local base64 = require(".base64")
1808
- local ao = require("ao")
1809
-
1810
- Transferable = true
1811
-
1812
- local function checkValidAddress(address)
1813
- if not address or type(address) ~= 'string' then
1814
- return false
1815
- end
1816
-
1817
- return string.match(address, "^[%w%-_]+$") ~= nil and #address == 43
1818
- end
1819
-
1820
- local function checkValidAmount(data)
1821
- return (math.type(tonumber(data)) == 'integer' or math.type(tonumber(data)) == 'float') and bint(data) > 0
1822
- end
1823
-
1824
- local function decodeMessageData(data)
1825
- local status, decodedData = pcall(json.decode, data)
1826
-
1827
- if not status or type(decodedData) ~= 'table' then
1828
- return false, nil
1829
- end
1830
-
1831
- return true, decodedData
1832
- end
1833
-
1834
- -- Read process state
1835
- Handlers.add('Info', Handlers.utils.hasMatchingTag('Action', 'Info'), function(msg)
1836
- ao.send({
1837
- Target = msg.From,
1838
- Action = 'Read-Success',
1839
- Data = json.encode({
1840
- Name = Name,
1841
- Description = Description,
1842
- Ticker = Ticker,
1843
- Denomination = Denomination,
1844
- Balances = Balances,
1845
- Transferable = Transferable,
1846
- Thumbnail = Thumbnail,
1847
- Collections = Collections
1848
- })
1849
- })
1850
- end)
1851
-
1852
- -- Transfer balance to recipient (Data - { Recipient, Quantity })
1853
- Handlers.add('Transfer', Handlers.utils.hasMatchingTag('Action', 'Transfer'), function(msg)
1854
- if not Transferable then
1855
- ao.send({ Target = msg.From, Action = 'Validation-Error', Tags = { Status = 'Error', Message = 'Transfers are not allowed' } })
1856
- return
1857
- end
1858
-
1859
- local data = {
1860
- Recipient = msg.Tags.Recipient,
1861
- Quantity = msg.Tags.Quantity
1862
- }
1863
-
1864
- if checkValidAddress(data.Recipient) and checkValidAmount(data.Quantity) then
1865
- -- Transfer is valid, calculate balances
1866
- if not Balances[data.Recipient] then
1867
- Balances[data.Recipient] = '0'
1868
- end
1869
-
1870
- Balances[msg.From] = tostring(bint(Balances[msg.From]) - bint(data.Quantity))
1871
- Balances[data.Recipient] = tostring(bint(Balances[data.Recipient]) + bint(data.Quantity))
1872
-
1873
- -- If new balance zeroes out then remove it from the table
1874
- if bint(Balances[msg.From]) <= 0 then
1875
- Balances[msg.From] = nil
1876
- end
1877
- if bint(Balances[data.Recipient]) <= 0 then
1878
- Balances[data.Recipient] = nil
1879
- end
1880
-
1881
- local debitNoticeTags = {
1882
- Status = 'Success',
1883
- Message = 'Balance transferred, debit notice issued',
1884
- Recipient = msg.Tags.Recipient,
1885
- Quantity = msg.Tags.Quantity,
1886
- }
1887
-
1888
- local creditNoticeTags = {
1889
- Status = 'Success',
1890
- Message = 'Balance transferred, credit notice issued',
1891
- Sender = msg.From,
1892
- Quantity = msg.Tags.Quantity,
1893
- }
1894
-
1895
- for tagName, tagValue in pairs(msg) do
1896
- if string.sub(tagName, 1, 2) == 'X-' then
1897
- debitNoticeTags[tagName] = tagValue
1898
- creditNoticeTags[tagName] = tagValue
1899
- end
1900
- end
1901
-
1902
- -- Send a debit notice to the sender
1903
- ao.send({
1904
- Target = msg.From,
1905
- Action = 'Debit-Notice',
1906
- Tags = debitNoticeTags,
1907
- Data = json.encode({
1908
- Recipient = data.Recipient,
1909
- Quantity = tostring(data.Quantity)
1910
- })
1911
- })
1912
-
1913
- -- Send a credit notice to the recipient
1914
- ao.send({
1915
- Target = data.Recipient,
1916
- Action = 'Credit-Notice',
1917
- Tags = creditNoticeTags,
1918
- Data = json.encode({
1919
- Sender = msg.From,
1920
- Quantity = tostring(data.Quantity)
1921
- })
1922
- })
1923
- end
1924
- end)
1925
-
1926
- -- Mint new tokens (Data - { Quantity })
1927
- Handlers.add('Mint', Handlers.utils.hasMatchingTag('Action', 'Mint'), function(msg)
1928
- local decodeCheck, data = decodeMessageData(msg.Data)
1929
-
1930
- if decodeCheck and data then
1931
- -- Check if quantity is present
1932
- if not data.Quantity then
1933
- ao.send({ Target = msg.From, Action = 'Input-Error', Tags = { Status = 'Error', Message = 'Invalid arguments, required { Quantity }' } })
1934
- return
1935
- end
1936
-
1937
- -- Check if quantity is a valid integer greater than zero
1938
- if not checkValidAmount(data.Quantity) then
1939
- ao.send({ Target = msg.From, Action = 'Validation-Error', Tags = { Status = 'Error', Message = 'Quantity must be an integer greater than zero' } })
1940
- return
1941
- end
1942
-
1943
- -- Check if owner is sender
1944
- if msg.From ~= Owner then
1945
- ao.send({ Target = msg.From, Action = 'Validation-Error', Tags = { Status = 'Error', Message = 'Only the process owner can mint new tokens' } })
1946
- return
1947
- end
1948
-
1949
- -- Mint request is valid, add tokens to the pool
1950
- if not Balances[Owner] then
1951
- Balances[Owner] = '0'
1952
- end
1953
-
1954
- Balances[Owner] = tostring(bint(Balances[Owner]) + bint(data.Quantity))
1955
-
1956
- ao.send({ Target = msg.From, Action = 'Mint-Success', Tags = { Status = 'Success', Message = 'Tokens minted' } })
1957
- else
1958
- ao.send({
1959
- Target = msg.From,
1960
- Action = 'Input-Error',
1961
- Tags = {
1962
- Status = 'Error',
1963
- Message = string.format('Failed to parse data, received: %s. %s', msg.Data,
1964
- 'Data must be an object - { Quantity }')
1965
- }
1966
- })
1967
- end
1968
- end)
1969
-
1970
- -- Read balance (Data - { Target })
1971
- Handlers.add('Balance', Handlers.utils.hasMatchingTag('Action', 'Balance'), function(msg)
1972
- local decodeCheck, data = decodeMessageData(msg.Data)
1973
-
1974
- if decodeCheck and data then
1975
- -- Check if target is present
1976
- if not data.Target then
1977
- ao.send({ Target = msg.From, Action = 'Input-Error', Tags = { Status = 'Error', Message = 'Invalid arguments, required { Target }' } })
1978
- return
1979
- end
1980
-
1981
- -- Check if target is a valid address
1982
- if not checkValidAddress(data.Target) then
1983
- ao.send({ Target = msg.From, Action = 'Validation-Error', Tags = { Status = 'Error', Message = 'Target is not a valid address' } })
1984
- return
1985
- end
1986
-
1987
- -- Check if target has a balance
1988
- if not Balances[data.Target] then
1989
- ao.send({ Target = msg.From, Action = 'Read-Error', Tags = { Status = 'Error', Message = 'Target does not have a balance' } })
1990
- return
1991
- end
1992
-
1993
- ao.send({
1994
- Target = msg.From,
1995
- Action = 'Read-Success',
1996
- Tags = { Status = 'Success', Message = 'Balance received' },
1997
- Data =
1998
- Balances[data.Target]
1999
- })
2000
- else
2001
- ao.send({
2002
- Target = msg.From,
2003
- Action = 'Input-Error',
2004
- Tags = {
2005
- Status = 'Error',
2006
- Message = string.format('Failed to parse data, received: %s. %s', msg.Data,
2007
- 'Data must be an object - { Target }')
2008
- }
2009
- })
2010
- end
2011
- end)
2012
-
2013
- -- Read balances
2014
- Handlers.add('Balances', Handlers.utils.hasMatchingTag('Action', 'Balances'),
2015
- function(msg) ao.send({ Target = msg.From, Action = 'Read-Success', Data = json.encode(Balances) }) end)
2016
-
2017
- -- Initialize a request to add the uploaded asset to a profile
2018
- Handlers.add('Add-Asset-To-Profile', Handlers.utils.hasMatchingTag('Action', 'Add-Asset-To-Profile'), function(msg)
2019
- if checkValidAddress(msg.Tags.ProfileProcess) then
2020
- -- ao.assign({ Processes = { msg.Tags.ProfileProcess }, Message = ao.id })
2021
- ao.send({
2022
- Target = msg.Tags.ProfileProcess,
2023
- Action = 'Add-Uploaded-Asset',
2024
- Data = json.encode({
2025
- Id = ao.id,
2026
- Quantity = msg.Tags.Quantity or '0'
2027
- })
2028
- })
2029
- else
2030
- ao.send({
2031
- Target = msg.From,
2032
- Action = 'Input-Error',
2033
- Tags = {
2034
- Status = 'Error',
2035
- Message = 'ProfileProcess tag not specified or not a valid Process ID'
2036
- }
2037
- })
2038
- end
2039
- end)
2040
-
2041
- Handlers.add('Add-To-Collection-Success', Handlers.utils.hasMatchingTag('Action', 'Add-To-Collection-Success'), function(msg)
2042
- local exists = false
2043
- for i, id in ipairs(Collections) do
2044
- if id == msg.From then
2045
- exists = true
2046
- break
2047
- end
2048
- end
2049
-
2050
- if not exists then
2051
- table.insert(Collections, msg.From)
2052
- end
2053
- end)
2054
-
2055
- Handlers.add('Remove-From-Collection-Success', Handlers.utils.hasMatchingTag('Action', 'Remove-From-Collection-Success'), function(msg)
2056
- for i, id in ipairs(Collections) do
2057
- if id == msg.From then
2058
- table.remove(Collections, i)
2059
- break
2060
- end
2061
- end
2062
- end)
2063
-
2064
-
2065
- if not data then
2066
- data = nil
2067
- end
2068
-
2069
- if not version then
2070
- version = "0.0.1"
2071
- end
2072
-
2073
- if not versions then
2074
- versions = {}
2075
- end
2076
-
2077
- if not editors then
2078
- editors = { ao.env.Process.Owner }
2079
- end
2080
-
2081
- local function reverse_patch(patch)
2082
- local reversed_patch = {}
2083
- for _, p in ipairs(patch) do
2084
- local diffs = p.diffs
2085
- local reversed_diffs = {}
2086
- for _, diff in ipairs(diffs) do
2087
- local op, text = diff[1], diff[2]
2088
- table.insert(reversed_diffs, { -op, text })
2089
- end
2090
- table.insert(reversed_patch, {
2091
- diffs = reversed_diffs,
2092
- start1 = p.start2,
2093
- start2 = p.start1,
2094
- length1 = p.length2,
2095
- length2 = p.length1
2096
- })
2097
- end
2098
- return reversed_patch
2099
- end
2100
-
2101
- local function is_editor(from)
2102
- for _, editor in ipairs(editors) do
2103
- if from == editor then
2104
- return true
2105
- end
2106
- end
2107
- return false
2108
- end
2109
-
2110
- local function checkValidAddress(address)
2111
- if not address or type(address) ~= 'string' then
2112
- return false
2113
- end
2114
-
2115
- return string.match(address, "^[%w%-_]+$") ~= nil and #address == 43
2116
- end
2117
-
2118
- Handlers.add(
2119
- "get",
2120
- Handlers.utils.hasMatchingTag("Action", "Get"),
2121
- function (msg)
2122
- if msg.Tags.Version then
2123
- local __patches = nil
2124
- for j = #versions, 1, -1 do
2125
- local v = versions[j]
2126
- local _data = data
2127
- if __patches then
2128
- local _patches = dmp.patch_fromText(base64.decode(__patches))
2129
- local reversed = reverse_patch(_patches)
2130
- _data = dmp.patch_apply(reversed, _data)
2131
- end
2132
- __patches = v.patches
2133
- if v.version == msg.Tags.Version then
2134
- ao.send({
2135
- Target = msg.From,
2136
- Tags = {
2137
- Data = _data,
2138
- Version = v.version,
2139
- Date = tostring(v.date)
2140
- }
2141
- })
2142
- end
2143
- end
2144
- else
2145
- ao.send({
2146
- Target = msg.From,
2147
- Tags = {
2148
- Data = data,
2149
- Version = version
2150
- }
2151
- })
2152
- end
2153
- end
2154
- )
2155
-
2156
- Handlers.add(
2157
- "list",
2158
- Handlers.utils.hasMatchingTag("Action", "List"),
2159
- function (msg)
2160
- ao.send({Target = msg.From, Tags = {
2161
- Versions = json.encode(versions)
2162
-
2163
- }})
2164
- end
2165
- )
2166
-
2167
- Handlers.add(
2168
- "editors",
2169
- Handlers.utils.hasMatchingTag("Action", "Editors"),
2170
- function (msg)
2171
- ao.send({Target = msg.From, Tags = {
2172
- Editors = json.encode(editors)
2173
-
2174
- }})
2175
- end
2176
- )
2177
-
2178
- Handlers.add(
2179
- "add-editor",
2180
- Handlers.utils.hasMatchingTag("Action", "Add-Editor"),
2181
- function (msg)
2182
- assert(type(msg.Tags.Editor) == "string" and checkValidAddress(msg.Tags.Editor), 'A valid editor is required!')
2183
- local exists = false
2184
- for _, editor in ipairs(editors) do
2185
- if msg.Tags.Editor == editor then
2186
- exists = true
2187
- break
2188
- end
2189
- end
2190
- assert(exists == false, 'Editor already exists!')
2191
- table.insert(editors,msg.Tags.Editor)
2192
- ao.send({
2193
- Target = msg.From,
2194
- Data = "editor added!",
2195
- Tags = {
2196
- Editors = json.encode(editors)
2197
-
2198
- }
2199
- })
2200
- end
2201
- )
2202
-
2203
- Handlers.add(
2204
- "remove-editor",
2205
- Handlers.utils.hasMatchingTag("Action", "Remove-Editor"),
2206
- function (msg)
2207
- assert(type(msg.Tags.Editor) == "string" and checkValidAddress(msg.Tags.Editor), 'A valid editor is required!')
2208
- local exists = false
2209
- for i, editor in ipairs(editors) do
2210
- if msg.Tags.Editor == editor then
2211
- exists = true
2212
- table.remove(editors, i)
2213
- break
2214
- end
2215
- end
2216
- assert(exists == true, 'Editor does not exist!')
2217
- ao.send({
2218
- Target = msg.From,
2219
- Data = "editor removed!",
2220
- Tags = {
2221
- Editors = json.encode(editors)
2222
-
2223
- }
2224
- })
2225
- end
2226
- )
2227
-
2228
- Handlers.add(
2229
- "update",
2230
- Handlers.utils.hasMatchingTag("Action", "Update"),
2231
- function (msg)
2232
- local ver = msg.Tags.Version
2233
- assert(type(ver) == "string", 'Version is required!')
2234
- assert(type(msg.Data) == "string", 'Data is required!')
2235
- assert(is_editor(msg.From), 'sender is not an editor!')
2236
- if ver == "major" then
2237
- version = tostring(semver(version):nextMajor())
2238
- elseif ver == "minor" then
2239
- version = tostring(semver(version):nextMinor())
2240
- elseif ver == "patch" then
2241
- version = tostring(semver(version):nextPatch())
2242
- else
2243
- assert(semver(ver) > semver(version), "Version must be higher!")
2244
- version = ver
2245
- end
2246
- local _patches = dmp.patch_fromText(base64.decode(msg.Data))
2247
- data = dmp.patch_apply(_patches, data)
2248
- table.insert(versions, { version = msg.Tags.Version, date = msg.Timestamp, patches = msg.Data, editor = msg.From })
2249
- Handlers.utils.reply("updated!")(msg)
2250
- end
2251
- )
2252
-
2253
- Handlers.add(
2254
- "patches",
2255
- Handlers.utils.hasMatchingTag("Action", "Patches"),
2256
- function (msg)
2257
- local patches = dmp.patch_make(data, msg.Data)
2258
- ao.send({
2259
- Target = msg.From,
2260
- Tags = {
2261
- Patches = base64.encode(dmp.patch_toText(patches)),
2262
- }
2263
- })
2264
- end
2265
- )
2266
-
2267
- Handlers.add(
2268
- "assigned",
2269
- Handlers.utils.hasMatchingTag("Action", "Assigned"),
2270
- function (msg)
2271
- data = msg.Data
2272
- table.insert(versions, { version = version, date = nil, patches = nil, editor = ao.env.Process.Owner })
2273
- end
2274
- )