EXtremeZip 2022.3.9 → 2023.1.29

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9ffc2dc7996aae9f38e3bc7c4e4d605ea328ff5f7e0f72e423a2de2d99918c0c
4
- data.tar.gz: bb9d5e826e23cb08d999d00b7245df1523b0587629dfbf97d4105769148c71f6
3
+ metadata.gz: 60ef4ba8a8aceb8f6be2cfb73bc763b98a293af4016429d02f49d588f2240f82
4
+ data.tar.gz: 82cc59f0b151bb1826e285a72e33bebfc3d9d0b110ffd6d41d08c96a6aedb08b
5
5
  SHA512:
6
- metadata.gz: 394dc5e472b751f9194ffc7e4caf75e7f1c8eb3749c4bb532574946406db561b077cb8b0ff8d5da1e9c0c5a722dc1db352cfca7d66e528262ce0f59f97903859
7
- data.tar.gz: 4c1c3e03d27df42cc1d7382aad01000b0731199a3316512b4261d7f9de08191f9fac3623fce0c8a9c74e1acb2400ddbeae5e3a67ca32904286d847e0ce2e3984
6
+ metadata.gz: 3b40ef64705493182c4e4dada135361fa02109bc20ac0763e598a18f9f052909a5290061b37ce46fb53d65b12cc25aa3f1e47a0fe9c5453a785d5dec0ef90865
7
+ data.tar.gz: 8f86b1fe790d74cb1e0a2b251c13a5a3324a293e16d9e9cc90571358eab54d74259cf32bf287b3d9be21789b9e907951c27fe2762135df51eb836c56b3ca967a
data/bin/exz CHANGED
@@ -4,18 +4,13 @@ require 'extremezip.zzaqsv'
4
4
  require 'notifier'
5
5
 
6
6
  if ARGV.empty? # 未指定命令行参数。
7
+ puts("exz filename")
7
8
  else # 指定了命令行参数。
8
- puts("process id: #{Process.pid}"); # Debug
9
+ $rootPath = ARGV[0] # 记录要打包的目录树的根目录。
9
10
 
10
- $rootPath = ARGV[0] # 记录要打包的目录树的根目录。
11
+ exzObject = ExtremeZip.new # 创建压缩对象
11
12
 
12
- exzObject = ExtremeZip.new # 创建压缩对象
13
-
14
- exzObject.exz($rootPath) # 压缩
13
+ exzObject.exz($rootPath) # 压缩
15
14
 
16
- Notifier.notify(
17
- image: "image.png",
18
- title: "exz finished",
19
- message: $rootPath
20
- )
15
+ Notifier.notify( image: "image.png", title: "exz finished", message: $rootPath )
21
16
  end
@@ -67,11 +67,11 @@ class ExtremeUnZip
67
67
  checkMemoryUsage(34)
68
68
 
69
69
  begin # 解压
70
- currentRawData = LZMA.decompress(currentCompressed) # 解压这一块
70
+ currentRawData = LZMA.decompress(currentCompressed) # 解压这一块
71
71
 
72
- dataFile.syswrite(currentRawData) # 写入内容
72
+ dataFile.syswrite(currentRawData) # 写入内容
73
73
  rescue RuntimeError => e # 解压失败
74
- puts "Warning: the exz file may be incomplete." # 报告错误。文件可能不完整。
74
+ puts "Warning: the exz file may be incomplete." # 报告错误。文件可能不完整。
75
75
  end # begin # 解压
76
76
 
77
77
  dataBlockCounter += 1 # count
@@ -81,55 +81,56 @@ class ExtremeUnZip
81
81
  end # if (fileVersion==14) #14版本
82
82
 
83
83
  dataFileName # 返回解压后的数据块整体
84
- end # def extractVfsDataWithVersionExternalFile(wholeCbor, fileVersion) #根据版本号,提取VFS数据内容
84
+ end # def extractVfsDataWithVersionExternalFile(wholeCbor, fileVersion) #根据版本号,提取VFS数据内容
85
85
 
86
86
  # 解压
87
- def exuz(rootPath)
88
- result = true # 解压结果
87
+ def exuz(rootPath)
88
+ result = true # 解压结果
89
89
 
90
- currentBlockFile = File.new(rootPath, 'rb') # 打开文件
90
+ currentBlockFile = File.new(rootPath, 'rb') # 打开文件
91
91
 
92
- @wholeFileContent = currentBlockFile.read # 读取全部内容
92
+ @wholeFileContent = currentBlockFile.read # 读取全部内容
93
93
 
94
- currentBlockFile.close # 关闭文件
94
+ currentBlockFile.close # 关闭文件
95
95
 
96
- checkMemoryUsage(60)
96
+ checkMemoryUsage(60)
97
97
 
98
- wholeCborByteArray = @wholeFileContent[4..-1] # 从第5个到末尾
98
+ wholeCborByteArray = @wholeFileContent[4..-1] # 从第5个到末尾
99
99
 
100
- begin # 可能出错。
101
- options = {:tolerant => true}
100
+ begin # 可能出错。
101
+ options = {:tolerant => true}
102
102
 
103
- wholeCbor = CBOR.decode(wholeCborByteArray, options) # 解码
103
+ wholeCbor = CBOR.decode(wholeCborByteArray, options) # 解码
104
104
 
105
- fileVersion = wholeCbor['version'] # 获取版本号
105
+ fileVersion = wholeCbor['version'] # 获取版本号
106
106
 
107
- if (fileVersion < 14) # 版本号过小
108
- checkMemoryUsage(85)
109
- puts 'file version too old' # 报告错误
110
- else # 版本号够大
111
- compressedVfsMenu = wholeCbor['vfsMenu'] # 获取压缩后的目录内容
107
+ if (fileVersion < 14) # 版本号过小
108
+ checkMemoryUsage(85)
109
+ puts 'file version too old' # 报告错误
110
+ else # 版本号够大
111
+ compressedVfsMenu = wholeCbor['vfsMenu'] # 获取压缩后的目录内容
112
+ puts "compressed vfs menu size: #{compressedVfsMenu.size}" # D3bug
112
113
 
113
- checkMemoryUsage(90)
114
- replyByteArray = LZMA.decompress(compressedVfsMenu) # 解码目录VFS字节数组内容
115
-
116
- checkMemoryUsage(95)
117
-
118
- victoriaFreshDataFile = extractVfsDataWithVersionExternalFile(wholeCbor, fileVersion) # 根据版本号,提取VFS数据内容
119
-
120
- checkMemoryUsage(100)
121
- $clipDownloader = VictoriaFresh.new # 创建下载器。
122
-
123
- $clipDownloader.releaseFilesExternalDataFile(replyByteArray, victoriaFreshDataFile) # 释放各个文件
124
-
125
- fileToRemove = File.new(victoriaFreshDataFile) # 要删除的文件
126
- end # if (fileVersion<14) #版本号过小
114
+ checkMemoryUsage(90)
115
+ replyByteArray = LZMA.decompress(compressedVfsMenu) # 解码目录VFS字节数组内容
116
+
117
+ checkMemoryUsage(95)
118
+
119
+ victoriaFreshDataFile = extractVfsDataWithVersionExternalFile(wholeCbor, fileVersion) # 根据版本号,提取VFS数据内容
120
+
121
+ checkMemoryUsage(100)
122
+ $clipDownloader = VictoriaFresh.new # 创建下载器。
123
+
124
+ $clipDownloader.releaseFilesExternalDataFile(replyByteArray, victoriaFreshDataFile) # 释放各个文件
125
+
126
+ fileToRemove = File.new(victoriaFreshDataFile) # 要删除的文件
127
+ end # if (fileVersion<14) #版本号过小
127
128
 
128
- result =true # 解压成功
129
- rescue EOFError => e # 文件内容提前到末尾。一般是压缩包文件未传输完全 。
130
- puts "Error: the exz file may be incomplete." # 报告错误。文件可能不完整。
129
+ result =true # 解压成功
130
+ rescue EOFError => e # 文件内容提前到末尾。一般是压缩包文件未传输完全 。
131
+ puts "Error: the exz file may be incomplete." # 报告错误。文件可能不完整。
131
132
 
132
- result = false # 失败
133
- end #begin # 可能出错。
134
- end # def exuz(rootPath)
133
+ result = false # 失败
134
+ end #begin # 可能出错。
135
+ end # def exuz(rootPath)
135
136
  end # class ExtremeUnZip
@@ -11,65 +11,131 @@ require 'get_process_mem'
11
11
  require 'pathname'
12
12
 
13
13
  def checkMemoryUsage(lineNumber)
14
- mem = GetProcessMem.new
14
+ mem = GetProcessMem.new
15
15
 
16
- puts("#{lineNumber} , Memory: #{mem.mb}, process id: #{Process.pid}"); # Debug
16
+ puts("#{lineNumber} , Memory: #{mem.mb}, process id: #{Process.pid}"); # Debug
17
17
  end # def checkMemoryUsage
18
18
 
19
19
  class ExtremeZip
20
- def initialize
21
- @wholeCbor = {} # 整个CBOR结构
22
- @vfsDataList = [] # 数据块压缩块列表
23
- @filePartCounter = 0 # 文件分块计数器
24
- @responsePipeList = [] # 任务回复管道列表
25
- @processIdList = [] # 子进程编号列表。
26
- @processTimestamp = Time.new.to_i # 记录进程启动的时间戳。
27
-
28
- @maxSubProcessAmount = Etc.nprocessors # 获取最大的子进程个数
29
-
30
- @dataBlockLength = 33554432 # 数据块单元长度, 32MiB
31
-
32
- @clipDownloader = VictoriaFresh.new # 创建下载器。
20
+ def initialize
21
+ @wholeCbor = {} # 整个CBOR结构
22
+ @vfsDataList = [] # 数据块压缩块列表
23
+ @filePartCounter = 0 # 文件分块计数器
24
+ @responsePipeList = [] # 任务回复管道列表
25
+ @processIdList = [] # 子进程编号列表。
26
+ @processTimestamp = Time.new.to_i # 记录进程启动的时间戳。
27
+ @topFileList=[] # top file list. by length.
28
+ @maxSubProcessAmount = Etc.nprocessors # 获取最大的子进程个数
29
+ @leastTopFileLength=-4 # least top file length
30
+ @dataBlockLength = 33554432 # 数据块单元长度, 32MiB
31
+
32
+ @clipDownloader = VictoriaFresh.new # 创建下载器。
33
+
34
+ @clipDownloader.diskFlush = true # 向磁盘写入缓存
35
+ @clipDownloader.diskMultiFile = true # 写多个磁盘文件
36
+ @clipDownloader.diskFileName = 'victoriafreshdata.v.' # 磁盘文件名前缀
37
+ @clipDownloader.diskFlushSize = @dataBlockLength # 磁盘文件大小
38
+ @clipDownloader.ignoreFileName= '.exzignore' # 设置用于指定忽略文件列表的文件名。
39
+ end # def initialize
40
+
41
+ # report top large file list.
42
+ def reportTopLargeFileList(victoriaFresh)
43
+ #puts "vfs menu content: #{victoriaFresh}"
44
+ puts "vfs menu class: #{victoriaFresh.class}"
45
+
46
+ reportRememberOneFileNode(victoriaFresh, '.') # process one file node
47
+
48
+ puts("Top large files:")
49
+
50
+ @topFileList.each do |topFile|
51
+ puts("#{topFile['name']}, #{topFile['parent_path']}, #{topFile['file_length']}")
52
+ end
53
+ end # def reportTopLargeFileList(victoriaFresh) # report top large file list.
54
+
55
+ # process one file node
56
+ def reportRememberOneFileNode(victoriaFresh, parentPath)
57
+ if (victoriaFresh['is_file']) # it is a file
58
+ file_lenght=victoriaFresh['file_length'] # get file length
59
+
60
+ if (file_lenght > (@leastTopFileLength) ) # larger than least top file length
61
+ insertedFileObject=false
62
+ if (@topFileList.size>=10) # already have 10 files in top list
63
+ @topFileList.pop # pop last one.
64
+ end # if (@topFileList.size>=10) # already have 10 files in top list
65
+
66
+ #puts("#{__LINE__}, parent path: #{victoriaFresh['parent_path']}")
67
+ toInsertFileObject=victoriaFresh
68
+ toInsertFileObject['parent_path']=parentPath
69
+ #puts("#{__LINE__}, parent path: #{toInsertFileObject['parent_path']}, #{victoriaFresh['parent_path']}")
70
+ topFileIndex=0
71
+ #if (@topFileList.size==0) # no item in list
72
+ #puts("#{__LINE__}, insert, #{toInsertFileObject['name']}, #{toInsertFileObject['file_length']}")
73
+ #@topFileList.insert(topFileIndex, toInsertFileObject) # insert into top file list.
74
+ #else # if (@topFileList.size==0) # no item in list
75
+ #topFileIndex=@topFileList.size - 1
76
+
77
+ fileIndexRange=0..(@topFileList.size-1)
78
+ fileIndexRange.each do |topFileIndex|
79
+ #while (topFileIndex>=0) do # find insert point one by one
80
+ currentTopFile=@topFileList[topFileIndex]
81
+
82
+ if (file_lenght>currentTopFile['file_length'])
83
+ #puts("#{__LINE__}, insert, #{toInsertFileObject['name']}, #{toInsertFileObject['file_length']}, #{parentPath}, #{toInsertFileObject['parent_path']}")
84
+ @topFileList.insert(topFileIndex, toInsertFileObject) # insert into top file list.
85
+ insertedFileObject=true
86
+ break
87
+ end
88
+
89
+ #topFileIndex -= 1
90
+ end # while (topFileIndex>=0) do # find insert point one by one
91
+ #end # if (@topFileList.size==0) # no item in list
92
+
93
+ unless insertedFileObject # not inserted file object
94
+ @topFileList << (toInsertFileObject) # insert into top file list.
33
95
 
34
- @clipDownloader.diskFlush = true # 向磁盘写入缓存
35
- @clipDownloader.diskMultiFile = true # 写多个磁盘文件
36
- @clipDownloader.diskFileName = 'victoriafreshdata.v.' # 磁盘文件名前缀
37
- @clipDownloader.diskFlushSize = @dataBlockLength # 磁盘文件大小
38
- @clipDownloader.ignoreFileName= '.exzignore' # 设置用于指定忽略文件列表的文件名。
39
- end # def initialize
96
+ end # unless insertedFileObject # not inserted file object
97
+
98
+ @leastTopFileLength=@topFileList.last['file_length']
99
+ end # if (file_lenght>leastTopFileLength) # larger than least top file length
100
+ else # it is a directory
101
+ victoriaFresh['sub_files'].each do |sub_file|
102
+ reportRememberOneFileNode(sub_file, "#{parentPath}/#{victoriaFresh['name']}")
103
+ end
104
+ end # else # it is a directory
105
+ end # reportRememberOneFileNode(victoriaFresh) # process one file node
40
106
 
41
- # 压缩目录数据。
42
- def compressVfsMenu(victoriaFresh)
43
- replyByteArray = victoriaFresh.to_cbor # #打包成字节数组。
107
+ # 压缩目录数据。
108
+ def compressVfsMenu(victoriaFresh)
109
+ replyByteArray = victoriaFresh.to_cbor # #打包成字节数组。
44
110
 
45
- # 压缩目录数据并放入CBOR:
46
- compressedVfsMenu = LZMA.compress(replyByteArray) # 压缩目录数据
111
+ # 压缩目录数据并放入CBOR:
112
+ compressedVfsMenu = LZMA.compress(replyByteArray) # 压缩目录数据
47
113
 
48
- @wholeCbor['vfsMenu'] = compressedVfsMenu # 加入目录
49
- end # compressVfsMenu(victoriaFresh) # 压缩目录数据。
114
+ @wholeCbor['vfsMenu'] = compressedVfsMenu # 加入目录
115
+ end # compressVfsMenu(victoriaFresh) # 压缩目录数据。
50
116
 
51
- # 加入基本文件信息
52
- def addBasicFileInformation
53
- @wholeCbor['version'] = 251 # 文件格式版本号
117
+ # 加入基本文件信息
118
+ def addBasicFileInformation
119
+ @wholeCbor['version'] = 251 # 文件格式版本号
54
120
 
55
- uuid = UUID.new # 获取生成器
56
- @wholeCbor['uuid'] = uuid.generate # 指定本个压缩包的唯一编号
121
+ uuid = UUID.new # 获取生成器
122
+ @wholeCbor['uuid'] = uuid.generate # 指定本个压缩包的唯一编号
57
123
 
58
- @wholeCbor['website']='https://rubygems.org/gems/EXtremeZip' # 加入网站地址
124
+ @wholeCbor['website']='https://rubygems.org/gems/EXtremeZip' # 加入网站地址
59
125
 
60
- @wholeCbor['vfsDataListStart']=198910 # 压缩 VFS 数据列表起始位置。
61
- end # addBasicFileInformation # 加入基本文件信息
126
+ @wholeCbor['vfsDataListStart']=198910 # 压缩 VFS 数据列表起始位置。
127
+ end # addBasicFileInformation # 加入基本文件信息
62
128
 
63
- def writeStamp(rootPath) # 更新时间戳文件
64
- directoryPathName=Pathname.new(rootPath) #构造路径名字对象。
65
- datastore= "#{directoryPathName.expand_path}/.exzstamp" # 配置文件路径
66
- puts "writing stamp file: #{datastore}" # Debug
129
+ def writeStamp(rootPath) # 更新时间戳文件
130
+ directoryPathName=Pathname.new(rootPath) #构造路径名字对象。
131
+ datastore= "#{directoryPathName.expand_path}/.exzstamp" # 配置文件路径
132
+ puts "writing stamp file: #{datastore}" # Debug
67
133
 
68
- #stamp = wholeCbor['timestamp'] # 获取时间戳
69
- stampCbor={} # 时间戳对象。
70
- stampCbor['timestamp']= @processTimestamp # 设置时间戳。
134
+ #stamp = wholeCbor['timestamp'] # 获取时间戳
135
+ stampCbor={} # 时间戳对象。
136
+ stampCbor['timestamp']= @processTimestamp # 设置时间戳。
71
137
 
72
- compressed= stampCbor.to_cbor
138
+ compressed= stampCbor.to_cbor
73
139
 
74
140
  extremeZipOutputFile = File.new(datastore, 'wb') # 创建文件
75
141
  extremeZipOutputFile.syswrite(compressed) # 写入文件
@@ -154,6 +220,8 @@ class ExtremeZip
154
220
  addBasicFileInformation # 加入基本文件信息
155
221
 
156
222
  processIdList, responsePipeList = launchSubProcesses # 启动子进程。
223
+
224
+ reportTopLargeFileList(victoriaFresh) # report top large file list.
157
225
 
158
226
  receiveCompressedVfsDataList(processIdList, responsePipeList) # 接收压缩后的数据块列表
159
227
 
@@ -178,7 +246,6 @@ class ExtremeZip
178
246
  if fileExists # 存在文件,则表明将要发生增量压缩
179
247
  writeStamp (rootPath) # 更新时间戳文件
180
248
  end # if fileExists # 存在文件,则表明用户要求增量压缩
181
-
182
249
  end # def exz(rootPath)
183
250
 
184
251
  # 写入压缩块文件
@@ -206,7 +273,7 @@ class ExtremeZip
206
273
 
207
274
  #wholeFileContent=File.read("comressed.#{processCounter}.cex", 'rb') # 读取压缩块。
208
275
 
209
- puts "wirte file contetn length: #{wholeFileContent.length}" # Debghu
276
+ #puts "wirte file contetn length: #{wholeFileContent.length}" # Debghu
210
277
 
211
278
  extremeZipOutputFile.syswrite(wholeFileContent) # 写入文件
212
279
 
@@ -266,58 +333,58 @@ class ExtremeZip
266
333
 
267
334
  # 计划一个块的压缩计算
268
335
  def schedule1Block(filePartCounter)
269
- currentBlockData = readBlockFile(filePartCounter) # 读取块文件内容
336
+ currentBlockData = readBlockFile(filePartCounter) # 读取块文件内容
270
337
 
271
- currentResponsePipe = Cod.pipe # 任务回复管道
338
+ currentResponsePipe = Cod.pipe # 任务回复管道
272
339
 
273
- p1 = fork do # 复制出子进程
274
- compressInSubProcess(currentBlockData, currentResponsePipe) # 在子进程中具体执行的压缩代码
275
- end # p1 = fork do #复制出子进程
340
+ p1 = fork do # 复制出子进程
341
+ compressInSubProcess(currentBlockData, currentResponsePipe) # 在子进程中具体执行的压缩代码
342
+ end # p1 = fork do #复制出子进程
276
343
 
277
- # processDataLength += @dataBlockLength # 计数
278
- checkMemoryUsage(130)
344
+ # processDataLength += @dataBlockLength # 计数
345
+ #checkMemoryUsage(130)
279
346
 
280
- # 记录管道:
281
- # taskPipeList << currentTaskPipe
282
- @responsePipeList << currentResponsePipe # 记录回复管道
347
+ # 记录管道:
348
+ # taskPipeList << currentTaskPipe
349
+ @responsePipeList << currentResponsePipe # 记录回复管道
283
350
 
284
- @processIdList << p1 # 记录到子进程列表中
351
+ @processIdList << p1 # 记录到子进程列表中
285
352
 
286
- @filePartCounter += 1 # 计数
353
+ @filePartCounter += 1 # 计数
287
354
 
288
- [currentResponsePipe, p1]
355
+ [currentResponsePipe, p1]
289
356
  end # schedule1Block(filePartCounter) # 计划一个块的压缩计算
290
357
 
291
358
  # 启动子进程。
292
359
  def launchSubProcesses
293
- while ((@filePartCounter < @filePartAmount) && (@filePartCounter<@maxSubProcessAmount)) # 未处理完毕,并且未达到最大子进程个数
294
- currentResponsePipe, p1 = schedule1Block(@filePartCounter) # 计划一个块的压缩计算
295
- end # while processDataLength < victoriaFreshData.byte_size do #未处理完毕
360
+ while ((@filePartCounter < @filePartAmount) && (@filePartCounter<@maxSubProcessAmount)) # 未处理完毕,并且未达到最大子进程个数
361
+ currentResponsePipe, p1 = schedule1Block(@filePartCounter) # 计划一个块的压缩计算
362
+ end # while processDataLength < victoriaFreshData.byte_size do #未处理完毕
296
363
 
297
- [@processIdList, @responsePipeList]
364
+ [@processIdList, @responsePipeList]
298
365
  end # launchSubProcesses # 启动子进程。
299
366
 
300
367
  # 在子进程中具体执行的压缩代码
301
368
  def compressInSubProcess(currentBlockData, currentResponsePipe)
302
- checkMemoryUsage(115) # Debug
303
- currentBlockDataToCompress = currentBlockData # 读取数据块
369
+ #checkMemoryUsage(115) # Debug
370
+ currentBlockDataToCompress = currentBlockData # 读取数据块
304
371
 
305
- currentCompressedVfsData = LZMA.compress(currentBlockDataToCompress) # 压缩当前块
372
+ currentCompressedVfsData = LZMA.compress(currentBlockDataToCompress) # 压缩当前块
306
373
 
307
- checkMemoryUsage(120)
308
- puts("compressed data length: #{currentCompressedVfsData.bytesize}") # Debug.
374
+ #checkMemoryUsage(120)
375
+ #puts("compressed data length: #{currentCompressedVfsData.bytesize}") # Debug.
309
376
 
310
- currentResponsePipe.put currentCompressedVfsData # 将压缩后的数据块写入到回复管道中
377
+ currentResponsePipe.put currentCompressedVfsData # 将压缩后的数据块写入到回复管道中
311
378
 
312
- puts("finished #{Process.pid}") # Debug
379
+ puts("finished #{Process.pid}") # Debug
313
380
  end # compressInSubProcess(currentBlockData, currentResponsePipe) # 在子进程中具体执行的压缩代码
314
381
 
315
382
  # 从子进程中读取数据,并终止子进程
316
383
  def receiveFromSubProcess(currentSubProcess, responsePipeList, processCounter)
317
- puts("waiting #{currentSubProcess}") # Debug
318
- checkMemoryUsage(140)
384
+ puts("waiting #{currentSubProcess}") # Debug
385
+ #checkMemoryUsage(140)
319
386
 
320
- currentResponsePipe = responsePipeList[processCounter] # 任务回复管道
387
+ currentResponsePipe = responsePipeList[processCounter] # 任务回复管道
321
388
 
322
389
  currentCompressedVfsDataFromSubProcess = currentResponsePipe.get # 读取压缩后数据
323
390
  checkMemoryUsage(145)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: EXtremeZip
3
3
  version: !ruby/object:Gem::Version
4
- version: 2022.3.9
4
+ version: 2023.1.29
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hxcan Cai
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-03-09 00:00:00.000000000 Z
11
+ date: 2023-01-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: cod
@@ -145,7 +145,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
145
145
  - !ruby/object:Gem::Version
146
146
  version: '0'
147
147
  requirements: []
148
- rubygems_version: 3.1.6
148
+ rubygems_version: 3.2.33
149
149
  signing_key:
150
150
  specification_version: 4
151
151
  summary: EXtremeZip