Skip to content

Commit 54f5ede

Browse files
committedSep 7, 2018
Fix quoting in error messages for Unicode
1 parent e40eb2d commit 54f5ede

9 files changed

+198
-35
lines changed
 

‎.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ luacov.report.out
44
doc
55
build
66
package
7+
scripts/UnicodeData-*

‎.luacheckrc

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
std = "min"
22
cache = true
3-
include_files = {"src", "spec/*.lua", "install.lua"}
3+
include_files = {"src", "spec/*.lua", "scripts/*.lua"}
44

55
files["spec/*_spec.lua"].std = "+busted"
66
files["src/luacheck/argparse.lua"].max_line_length = 140
7+
files["src/luacheck/unicode_printability_boundaries.lua"].max_line_length = false

‎luacheck-dev-1.rockspec

+2
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ build = {
5656
["luacheck.stages.resolve_locals"] = "src/luacheck/stages/resolve_locals.lua",
5757
["luacheck.stages.unwrap_parens"] = "src/luacheck/stages/unwrap_parens.lua",
5858
["luacheck.standards"] = "src/luacheck/standards.lua",
59+
["luacheck.unicode"] = "src/luacheck/unicode.lua",
60+
["luacheck.unicode_printability_boundaries"] = "src/luacheck/unicode_printability_boundaries.lua",
5961
["luacheck.utils"] = "src/luacheck/utils.lua",
6062
["luacheck.version"] = "src/luacheck/version.lua"
6163
},
+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#!/usr/bin/env bash
2+
set -eu
3+
set -o pipefail
4+
5+
# Generates luacheck.unicode_printability_boundaries module given Unicode version.
6+
# Should be executed from root Luacheck directory.
7+
8+
url="https://www.unicode.org/Public/$1/ucd/UnicodeData.txt"
9+
cache="scripts/UnicodeData-$1.txt"
10+
11+
if [ ! -e "$cache" ]; then
12+
wget -O "$cache" "$url"
13+
fi
14+
15+
(
16+
echo "-- Autogenerated using data from $url";
17+
lua scripts/unicode_data_to_printability_module.lua < "$cache"
18+
) > src/luacheck/unicode_printability_boundaries.lua
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
-- Reads Unicode character data in UnicodeData.txt format from stdin.
2+
-- Prints a Lua module retuning an array of first codepoints of
3+
-- each continuous block of codepoints that are all printable or all not printable.
4+
-- See https://unicode.org/reports/tr44/
5+
6+
local category_printabilities = {
7+
Lu = true,
8+
Ll = true,
9+
Lt = true,
10+
Lm = true,
11+
Lo = true,
12+
Mn = true,
13+
Mc = true,
14+
Me = true,
15+
Nd = true,
16+
Nl = true,
17+
No = true,
18+
Pc = true,
19+
Pd = true,
20+
Ps = true,
21+
Pe = true,
22+
Pi = true,
23+
Pf = true,
24+
Po = true,
25+
Sm = true,
26+
Sc = true,
27+
Sk = true,
28+
So = true,
29+
Zs = true,
30+
Zl = false,
31+
Zp = false,
32+
Cc = false,
33+
Cf = false,
34+
Cs = false,
35+
Co = false,
36+
Cn = false
37+
}
38+
39+
local codepoint_printabilities = {}
40+
local max_codepoint = 0
41+
42+
local range_start_codepoint
43+
44+
for line in io.lines() do
45+
local codepoint_hex, name, category = assert(line:match("^([^;]+);([^;]+);([^;]+)"))
46+
local codepoint = assert(tonumber("0x" .. codepoint_hex))
47+
local printability = category_printabilities[category]
48+
assert(printability ~= nil)
49+
50+
if name:find(", First>$") then
51+
assert(not range_start_codepoint)
52+
range_start_codepoint = codepoint
53+
elseif name:find(", Last>$") then
54+
assert(range_start_codepoint and range_start_codepoint >= range_start_codepoint)
55+
56+
for range_codepoint = range_start_codepoint, codepoint do
57+
codepoint_printabilities[range_codepoint] = printability
58+
end
59+
60+
range_start_codepoint = nil
61+
else
62+
codepoint_printabilities[codepoint] = printability
63+
end
64+
65+
max_codepoint = math.max(max_codepoint, codepoint)
66+
end
67+
68+
assert(not range_start_codepoint)
69+
70+
local parts = {"return {"}
71+
local prev_printability = true
72+
73+
-- Iterate up to a non-existent codepoint to ensure that the last required codepoint is printed.
74+
for codepoint = 0, max_codepoint + 1 do
75+
local printability = codepoint_printabilities[codepoint] or false
76+
77+
if printability ~= prev_printability then
78+
table.insert(parts, ("%d,"):format(codepoint))
79+
end
80+
81+
prev_printability = printability
82+
end
83+
84+
table.insert(parts, "}")
85+
print(table.concat(parts))
86+

‎src/luacheck/decoder.lua

+40-28
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
local unicode = require "luacheck.unicode"
12
local utils = require "luacheck.utils"
23

34
local decoder = {}
@@ -11,9 +12,9 @@ local ssub = string.sub
1112
-- and provide Unicode-aware access to them with a common interface.
1213
-- Source bytes should not be accessed directly.
1314
-- Provided methods are:
14-
-- `Chars:get_first_byte(index)`: returns the first byte of the character at given index or nil.
15+
-- `Chars:get_codepoint(index)`: returns codepoint at given index as integer or nil if index is out of range.
1516
-- `Chars:get_substring(from, to)`: returns substring of original bytes corresponding to characters from `from` to `to`.
16-
-- `Chars:get_quoted_substring(from. to)`: same but quotes and escapes characters to make them printable.
17+
-- `Chars:get_quoted_substring(from. to)`: like get_substring but quotes and escapes characters to make them printable.
1718
-- `Chars:get_length()`: returns total number of characters.
1819
-- `Chars:find(pattern, from)`: `string.find` but `from` is in characters. Return values are still in bytes.
1920

@@ -24,20 +25,20 @@ function LatinChars:__init(bytes)
2425
self._bytes = bytes
2526
end
2627

27-
function LatinChars:get_first_byte(index)
28+
function LatinChars:get_codepoint(index)
2829
return sbyte(self._bytes, index)
2930
end
3031

3132
function LatinChars:get_substring(from, to)
3233
return ssub(self._bytes, from, to)
3334
end
3435

35-
local function decimal_escaper(byte)
36-
return "\\" .. tostring(sbyte(byte))
36+
local function hexadecimal_escaper(byte)
37+
return ("\\x%02X"):format(sbyte(byte))
3738
end
3839

3940
function LatinChars:get_quoted_substring(from, to)
40-
return "'" .. sgsub(ssub(self._bytes, from, to), "[^\32-\126]", decimal_escaper) .. "'"
41+
return '"' .. sgsub(ssub(self._bytes, from, to), "[^\32-\126]", hexadecimal_escaper) .. '"'
4142
end
4243

4344
function LatinChars:get_length()
@@ -48,32 +49,28 @@ function LatinChars:find(pattern, from)
4849
return sfind(self._bytes, pattern, from)
4950
end
5051

51-
-- Decodes `bytes` as UTF8. Returns arrays of first bytes of characters and their byte offsets.
52-
-- Byte offset has one extra item pointing to one byte past the end of `bytes`.
52+
-- Decodes `bytes` as UTF8. Returns arrays of codepoints as integers and their byte offsets.
53+
-- Byte offsets have one extra item pointing to one byte past the end of `bytes`.
5354
-- On decoding error returns nothing.
54-
local function get_first_bytes_and_byte_offsets(bytes)
55-
-- TODO: group codepoints into grapheme clusters.
56-
local first_bytes = {}
55+
local function get_codepoints_and_byte_offsets(bytes)
56+
local codepoints = {}
5757
local byte_offsets = {}
5858

5959
local byte_index = 1
60-
local char_index = 1
60+
local codepoint_index = 1
6161

6262
while true do
63-
byte_offsets[char_index] = byte_index
63+
byte_offsets[codepoint_index] = byte_index
6464

6565
-- Attempt to decode the next codepoint from UTF8.
6666
local codepoint = sbyte(bytes, byte_index)
6767

6868
if not codepoint then
69-
return first_bytes, byte_offsets
69+
return codepoints, byte_offsets
7070
end
7171

72-
first_bytes[char_index] = codepoint
73-
7472
byte_index = byte_index + 1
7573

76-
-- luacheck: ignore 311/codepoint (TODO: use codepoints for grapheme clustering)
7774
if codepoint >= 0x80 then
7875
-- Not ASCII.
7976

@@ -133,22 +130,23 @@ local function get_first_bytes_and_byte_offsets(bytes)
133130
end
134131
end
135132

136-
char_index = char_index + 1
133+
codepoints[codepoint_index] = codepoint
134+
codepoint_index = codepoint_index + 1
137135
end
138136
end
139137

140138
-- `UnicodeChars` is the general case for non-latin1 strings.
141139
-- Assumes UTF8, on decoding error falls back to latin1.
142140
local UnicodeChars = utils.class()
143141

144-
function UnicodeChars:__init(bytes, first_bytes, byte_offsets)
142+
function UnicodeChars:__init(bytes, codepoints, byte_offsets)
145143
self._bytes = bytes
146-
self._first_bytes = first_bytes
144+
self._codepoints = codepoints
147145
self._byte_offsets = byte_offsets
148146
end
149147

150-
function UnicodeChars:get_first_byte(index)
151-
return self._first_bytes[index]
148+
function UnicodeChars:get_codepoint(index)
149+
return self._codepoints[index]
152150
end
153151

154152
function UnicodeChars:get_substring(from, to)
@@ -157,12 +155,26 @@ function UnicodeChars:get_substring(from, to)
157155
end
158156

159157
function UnicodeChars:get_quoted_substring(from, to)
160-
-- TODO: fix for Unicode.
161-
return "'" .. sgsub(self:get_substring(from, to), "[^\32-\126]", decimal_escaper) .. "'"
158+
-- This is only called on syntax error, it's okay to be slow.
159+
local parts = {"'"}
160+
161+
for index = from, to do
162+
local codepoint = self._codepoints[index]
163+
164+
if unicode.is_printable(codepoint) then
165+
table.insert(parts, self:get_substring(index, index))
166+
else
167+
table.insert(parts, (codepoint > 255 and "\\u{%X}" or "\\x%02X"):format(codepoint))
168+
end
169+
end
170+
171+
172+
table.insert(parts, "'")
173+
return table.concat(parts)
162174
end
163175

164176
function UnicodeChars:get_length()
165-
return #self._first_bytes
177+
return #self._codepoints
166178
end
167179

168180
function UnicodeChars:find(pattern, from)
@@ -172,10 +184,10 @@ end
172184
function decoder.decode(bytes)
173185
-- TODO: check if this optimization actually helps.
174186
if sfind(bytes, "[\128-\255]") then
175-
local first_bytes, byte_offsets = get_first_bytes_and_byte_offsets(bytes)
187+
local codepoints, byte_offsets = get_codepoints_and_byte_offsets(bytes)
176188

177-
if first_bytes then
178-
return UnicodeChars(bytes, first_bytes, byte_offsets)
189+
if codepoints then
190+
return UnicodeChars(bytes, codepoints, byte_offsets)
179191
end
180192
end
181193

‎src/luacheck/lexer.lua

+11-6
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ local simple_escapes = {
9898
local function next_byte(state)
9999
local offset = state.offset + 1
100100
state.offset = offset
101-
return state.src:get_first_byte(offset)
101+
return state.src:get_codepoint(offset)
102102
end
103103

104104
-- Skipping helpers.
@@ -454,10 +454,10 @@ local function lex_number(state, b)
454454
if not is_float then
455455
if b == BYTE_u or b == BYTE_U then
456456
-- It may be uint64_t literal.
457-
local b1 = state.src:get_first_byte(state.offset+1)
457+
local b1 = state.src:get_codepoint(state.offset+1)
458458

459459
if b1 == BYTE_l or b1 == BYTE_L then
460-
local b2 = state.src:get_first_byte(state.offset+2)
460+
local b2 = state.src:get_codepoint(state.offset+2)
461461

462462
if b2 == BYTE_l or b2 == BYTE_L then
463463
-- It is uint64_t literal.
@@ -466,10 +466,10 @@ local function lex_number(state, b)
466466
end
467467
elseif b == BYTE_l or b == BYTE_L then
468468
-- It may be uint64_t or int64_t literal.
469-
local b1 = state.src:get_first_byte(state.offset+1)
469+
local b1 = state.src:get_codepoint(state.offset+1)
470470

471471
if b1 == BYTE_l or b1 == BYTE_L then
472-
local b2 = state.src:get_first_byte(state.offset+2)
472+
local b2 = state.src:get_codepoint(state.offset+2)
473473

474474
if b2 == BYTE_u or b2 == BYTE_U then
475475
-- It is uint64_t literal.
@@ -641,6 +641,11 @@ end
641641

642642
local function lex_any(state, b)
643643
state.offset = state.offset + 1
644+
645+
if b > 255 then
646+
b = 255
647+
end
648+
644649
return schar(b)
645650
end
646651

@@ -718,7 +723,7 @@ end
718723
-- On error returns nil, error message, error location (line, offset), error end offset.
719724
function lexer.next_token(state)
720725
local line_offsets = state.line_offsets
721-
local b = skip_space(state, state.src:get_first_byte(state.offset))
726+
local b = skip_space(state, state.src:get_codepoint(state.offset))
722727

723728
-- Save location of token start.
724729
local token_line = state.line

‎src/luacheck/unicode.lua

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
local unicode_printability_boundaries = require "luacheck.unicode_printability_boundaries"
2+
3+
local unicode = {}
4+
5+
-- unicode_printability_boundaries is an array of first codepoints of
6+
-- each continuous block of codepoints that are all printable or all not printable.
7+
8+
function unicode.is_printable(codepoint)
9+
-- Binary search for index of the first boundary less than or equal to given codepoint.
10+
local floor_boundary_index
11+
12+
-- Target index is always in [begin_index..end_index).
13+
local begin_index = 1
14+
local end_index = #unicode_printability_boundaries + 1
15+
16+
while end_index - begin_index > 1 do
17+
local mid_index = math.floor((begin_index + end_index) / 2)
18+
local mid_codepoint = unicode_printability_boundaries[mid_index]
19+
20+
if codepoint < mid_codepoint then
21+
end_index = mid_index
22+
elseif codepoint > mid_codepoint then
23+
begin_index = mid_index
24+
else
25+
floor_boundary_index = mid_index
26+
break
27+
end
28+
end
29+
30+
floor_boundary_index = floor_boundary_index or begin_index
31+
-- floor_boundary_index is the number of the block containing codepoint.
32+
-- Printable and not printable blocks alternate and the first one is not printable (zero is not printable).
33+
return floor_boundary_index % 2 == 0
34+
end
35+
36+
return unicode
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
-- Autogenerated using data from https://www.unicode.org/Public/11.0.0/ucd/UnicodeData.txt
2+
return {0,32,127,160,173,174,888,890,896,900,907,908,909,910,930,931,1328,1329,1367,1369,1419,1421,1424,1425,1480,1488,1515,1519,1525,1542,1564,1566,1757,1758,1806,1808,1867,1869,1970,1984,2043,2045,2094,2096,2111,2112,2140,2142,2143,2144,2155,2208,2229,2230,2238,2259,2274,2275,2436,2437,2445,2447,2449,2451,2473,2474,2481,2482,2483,2486,2490,2492,2501,2503,2505,2507,2511,2519,2520,2524,2526,2527,2532,2534,2559,2561,2564,2565,2571,2575,2577,2579,2601,2602,2609,2610,2612,2613,2615,2616,2618,2620,2621,2622,2627,2631,2633,2635,2638,2641,2642,2649,2653,2654,2655,2662,2679,2689,2692,2693,2702,2703,2706,2707,2729,2730,2737,2738,2740,2741,2746,2748,2758,2759,2762,2763,2766,2768,2769,2784,2788,2790,2802,2809,2816,2817,2820,2821,2829,2831,2833,2835,2857,2858,2865,2866,2868,2869,2874,2876,2885,2887,2889,2891,2894,2902,2904,2908,2910,2911,2916,2918,2936,2946,2948,2949,2955,2958,2961,2962,2966,2969,2971,2972,2973,2974,2976,2979,2981,2984,2987,2990,3002,3006,3011,3014,3017,3018,3022,3024,3025,3031,3032,3046,3067,3072,3085,3086,3089,3090,3113,3114,3130,3133,3141,3142,3145,3146,3150,3157,3159,3160,3163,3168,3172,3174,3184,3192,3213,3214,3217,3218,3241,3242,3252,3253,3258,3260,3269,3270,3273,3274,3278,3285,3287,3294,3295,3296,3300,3302,3312,3313,3315,3328,3332,3333,3341,3342,3345,3346,3397,3398,3401,3402,3408,3412,3428,3430,3456,3458,3460,3461,3479,3482,3506,3507,3516,3517,3518,3520,3527,3530,3531,3535,3541,3542,3543,3544,3552,3558,3568,3570,3573,3585,3643,3647,3676,3713,3715,3716,3717,3719,3721,3722,3723,3725,3726,3732,3736,3737,3744,3745,3748,3749,3750,3751,3752,3754,3756,3757,3770,3771,3774,3776,3781,3782,3783,3784,3790,3792,3802,3804,3808,3840,3912,3913,3949,3953,3992,3993,4029,4030,4045,4046,4059,4096,4294,4295,4296,4301,4302,4304,4681,4682,4686,4688,4695,4696,4697,4698,4702,4704,4745,4746,4750,4752,4785,4786,4790,4792,4799,4800,4801,4802,4806,4808,4823,4824,4881,4882,4886,4888,4955,4957,4989,4992,5018,5024,5110,5112,5118,5120,5789,5792,5881,5888,5901,5902,5909,5920,5943,5952,5972,5984,5997,5998,6001,6002,6004,6016,6110,6112,6122,6128,6138,6144,6158,6160,6170,6176,6265,6272,6315,6320,6390,6400,6431,6432,6444,6448,6460,6464,6465,6468,6510,6512,6517,6528,6572,6576,6602,6608,6619,6622,6684,6686,6751,6752,6781,6783,6794,6800,6810,6816,6830,6832,6847,6912,6988,6992,7037,7040,7156,7164,7224,7227,7242,7245,7305,7312,7355,7357,7368,7376,7418,7424,7674,7675,7958,7960,7966,7968,8006,8008,8014,8016,8024,8025,8026,8027,8028,8029,8030,8031,8062,8064,8117,8118,8133,8134,8148,8150,8156,8157,8176,8178,8181,8182,8191,8192,8203,8208,8232,8239,8288,8304,8306,8308,8335,8336,8349,8352,8384,8400,8433,8448,8588,8592,9255,9280,9291,9312,11124,11126,11158,11160,11209,11210,11263,11264,11311,11312,11359,11360,11508,11513,11558,11559,11560,11565,11566,11568,11624,11631,11633,11647,11671,11680,11687,11688,11695,11696,11703,11704,11711,11712,11719,11720,11727,11728,11735,11736,11743,11744,11855,11904,11930,11931,12020,12032,12246,12272,12284,12288,12352,12353,12439,12441,12544,12549,12592,12593,12687,12688,12731,12736,12772,12784,12831,12832,13055,13056,19894,19904,40944,40960,42125,42128,42183,42192,42540,42560,42744,42752,42938,42999,43052,43056,43066,43072,43128,43136,43206,43214,43226,43232,43348,43359,43389,43392,43470,43471,43482,43486,43519,43520,43575,43584,43598,43600,43610,43612,43715,43739,43767,43777,43783,43785,43791,43793,43799,43808,43815,43816,43823,43824,43878,43888,44014,44016,44026,44032,55204,55216,55239,55243,55292,63744,64110,64112,64218,64256,64263,64275,64280,64285,64311,64312,64317,64318,64319,64320,64322,64323,64325,64326,64450,64467,64832,64848,64912,64914,64968,65008,65022,65024,65050,65056,65107,65108,65127,65128,65132,65136,65141,65142,65277,65281,65471,65474,65480,65482,65488,65490,65496,65498,65501,65504,65511,65512,65519,65532,65534,65536,65548,65549,65575,65576,65595,65596,65598,65599,65614,65616,65630,65664,65787,65792,65795,65799,65844,65847,65935,65936,65948,65952,65953,66000,66046,66176,66205,66208,66257,66272,66300,66304,66340,66349,66379,66384,66427,66432,66462,66463,66500,66504,66518,66560,66718,66720,66730,66736,66772,66776,66812,66816,66856,66864,66916,66927,66928,67072,67383,67392,67414,67424,67432,67584,67590,67592,67593,67594,67638,67639,67641,67644,67645,67647,67670,67671,67743,67751,67760,67808,67827,67828,67830,67835,67868,67871,67898,67903,67904,67968,68024,68028,68048,68050,68100,68101,68103,68108,68116,68117,68120,68121,68150,68152,68155,68159,68169,68176,68185,68192,68256,68288,68327,68331,68343,68352,68406,68409,68438,68440,68467,68472,68498,68505,68509,68521,68528,68608,68681,68736,68787,68800,68851,68858,68904,68912,68922,69216,69247,69376,69416,69424,69466,69632,69710,69714,69744,69759,69821,69822,69826,69840,69865,69872,69882,69888,69941,69942,69959,69968,70007,70016,70094,70096,70112,70113,70133,70144,70162,70163,70207,70272,70279,70280,70281,70282,70286,70287,70302,70303,70314,70320,70379,70384,70394,70400,70404,70405,70413,70415,70417,70419,70441,70442,70449,70450,70452,70453,70458,70459,70469,70471,70473,70475,70478,70480,70481,70487,70488,70493,70500,70502,70509,70512,70517,70656,70746,70747,70748,70749,70751,70784,70856,70864,70874,71040,71094,71096,71134,71168,71237,71248,71258,71264,71277,71296,71352,71360,71370,71424,71451,71453,71468,71472,71488,71680,71740,71840,71923,71935,71936,72192,72264,72272,72324,72326,72355,72384,72441,72704,72713,72714,72759,72760,72774,72784,72813,72816,72848,72850,72872,72873,72887,72960,72967,72968,72970,72971,73015,73018,73019,73020,73022,73023,73032,73040,73050,73056,73062,73063,73065,73066,73103,73104,73106,73107,73113,73120,73130,73440,73465,73728,74650,74752,74863,74864,74869,74880,75076,77824,78895,82944,83527,92160,92729,92736,92767,92768,92778,92782,92784,92880,92910,92912,92918,92928,92998,93008,93018,93019,93026,93027,93048,93053,93072,93760,93851,93952,94021,94032,94079,94095,94112,94176,94178,94208,100338,100352,101107,110592,110879,110960,111356,113664,113771,113776,113789,113792,113801,113808,113818,113820,113824,118784,119030,119040,119079,119081,119155,119163,119273,119296,119366,119520,119540,119552,119639,119648,119673,119808,119893,119894,119965,119966,119968,119970,119971,119973,119975,119977,119981,119982,119994,119995,119996,119997,120004,120005,120070,120071,120075,120077,120085,120086,120093,120094,120122,120123,120127,120128,120133,120134,120135,120138,120145,120146,120486,120488,120780,120782,121484,121499,121504,121505,121520,122880,122887,122888,122905,122907,122914,122915,122917,122918,122923,124928,125125,125127,125143,125184,125259,125264,125274,125278,125280,126065,126133,126464,126468,126469,126496,126497,126499,126500,126501,126503,126504,126505,126515,126516,126520,126521,126522,126523,126524,126530,126531,126535,126536,126537,126538,126539,126540,126541,126544,126545,126547,126548,126549,126551,126552,126553,126554,126555,126556,126557,126558,126559,126560,126561,126563,126564,126565,126567,126571,126572,126579,126580,126584,126585,126589,126590,126591,126592,126602,126603,126620,126625,126628,126629,126634,126635,126652,126704,126706,126976,127020,127024,127124,127136,127151,127153,127168,127169,127184,127185,127222,127232,127245,127248,127340,127344,127405,127462,127491,127504,127548,127552,127561,127568,127570,127584,127590,127744,128725,128736,128749,128752,128762,128768,128884,128896,128985,129024,129036,129040,129096,129104,129114,129120,129160,129168,129198,129280,129292,129296,129343,129344,129393,129395,129399,129402,129403,129404,129443,129456,129466,129472,129475,129488,129536,129632,129646,131072,173783,173824,177973,177984,178206,178208,183970,183984,191457,194560,195102,917760,918000,}

0 commit comments

Comments
 (0)
Please sign in to comment.