girl 0.73.0 → 0.77.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of girl might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/lib/girl/head.rb +0 -11
- data/lib/girl/proxy_worker.rb +72 -73
- data/lib/girl/proxyd_worker.rb +50 -39
- data/lib/girl/version.rb +1 -1
- metadata +3 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 67fe23b6655278a6589fda1afc4ae23af79dfb0f25d023cd357b4722e07fb1a2
|
4
|
+
data.tar.gz: af7f01bb573014f78d4ecbc06926749d2326c74862b02b53b2f300fd2a927cd0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5f5ef13b0650eb3c289de191f8aeabfd1e288b58a6fbd680ced51c027cd43d9a4bc7ad988398e611a0dd3cc88ddd894e87dc7252b03b24e8a1e7dd5464d81b73
|
7
|
+
data.tar.gz: '094ee98b813b04ec12b8a1ea9181c6353cf69eb69ecc595bbbe1f326f1cf6a70b9a11778cfc4d0eee84f59308a0b5ec4f556bab8982befd0d5a1a51b4e850ba3'
|
data/lib/girl/head.rb
CHANGED
@@ -30,21 +30,10 @@ module Girl
|
|
30
30
|
RESERVED_ROUTE = <<EOF
|
31
31
|
0.0.0.0/8
|
32
32
|
10.0.0.0/8
|
33
|
-
100.64.0.0/10
|
34
33
|
127.0.0.0/8
|
35
34
|
169.254.0.0/16
|
36
35
|
172.16.0.0/12
|
37
|
-
192.0.0.0/24
|
38
|
-
192.0.2.0/24
|
39
|
-
192.31.196.0/24
|
40
|
-
192.52.193.0/24
|
41
|
-
192.88.99.0/24
|
42
36
|
192.168.0.0/16
|
43
|
-
192.175.48.0/24
|
44
|
-
198.18.0.0/15
|
45
|
-
198.51.100.0/24
|
46
|
-
203.0.113.0/24
|
47
|
-
240.0.0.0/4
|
48
37
|
255.255.255.255/32
|
49
38
|
EOF
|
50
39
|
end
|
data/lib/girl/proxy_worker.rb
CHANGED
@@ -113,7 +113,7 @@ module Girl
|
|
113
113
|
|
114
114
|
@tun_info[ :src_exts ].each do | src_id, src_ext |
|
115
115
|
if src_ext[ :src ].closed? && ( now - src_ext[ :last_continue_at ] > EXPIRE_AFTER )
|
116
|
-
puts "p#{ Process.pid } #{ Time.new } expire src ext #{
|
116
|
+
puts "p#{ Process.pid } #{ Time.new } expire src ext #{ src_ext[ :destination_domain ] }"
|
117
117
|
del_src_ext( src_id )
|
118
118
|
end
|
119
119
|
end
|
@@ -123,20 +123,16 @@ module Girl
|
|
123
123
|
end
|
124
124
|
|
125
125
|
@src_infos.each do | src, src_info |
|
126
|
-
|
127
|
-
|
128
|
-
if is_expired
|
129
|
-
puts "p#{ Process.pid } #{ Time.new } expire src"
|
126
|
+
if now - src_info[ :last_continue_at ] > EXPIRE_AFTER
|
127
|
+
puts "p#{ Process.pid } #{ Time.new } expire src #{ src_info[ :destination_domain ] }"
|
130
128
|
set_is_closing( src )
|
131
129
|
need_trigger = true
|
132
130
|
end
|
133
131
|
end
|
134
132
|
|
135
133
|
@dst_infos.each do | dst, dst_info |
|
136
|
-
|
137
|
-
|
138
|
-
if is_expired
|
139
|
-
puts "p#{ Process.pid } #{ Time.new } expire dst"
|
134
|
+
if now - dst_info[ :last_continue_at ] > EXPIRE_AFTER
|
135
|
+
puts "p#{ Process.pid } #{ Time.new } expire dst #{ dst_info[ :domain ] }"
|
140
136
|
set_is_closing( dst )
|
141
137
|
need_trigger = true
|
142
138
|
end
|
@@ -337,6 +333,7 @@ module Girl
|
|
337
333
|
#
|
338
334
|
def new_a_dst( src, ip_info )
|
339
335
|
src_info = @src_infos[ src ]
|
336
|
+
domain = src_info[ :destination_domain ]
|
340
337
|
destination_addr = Socket.sockaddr_in( src_info[ :destination_port ], ip_info.ip_address )
|
341
338
|
dst = Socket.new( ip_info.ipv4? ? Socket::AF_INET : Socket::AF_INET6, Socket::SOCK_STREAM, 0 )
|
342
339
|
|
@@ -357,15 +354,15 @@ module Girl
|
|
357
354
|
# puts "debug1 a new dst #{ dst.local_address.inspect }"
|
358
355
|
local_port = dst.local_address.ip_port
|
359
356
|
@dst_infos[ dst ] = {
|
360
|
-
local_port: local_port,
|
361
|
-
src: src,
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
is_closing: false
|
357
|
+
local_port: local_port, # 本地端口
|
358
|
+
src: src, # 对应src
|
359
|
+
domain: domain, # 域名
|
360
|
+
wbuff: '', # 写前
|
361
|
+
cache: '', # 块读出缓存
|
362
|
+
chunks: [], # 块队列,写前达到块大小时结一个块 filename
|
363
|
+
spring: 0, # 块后缀,结块时,如果块队列不为空,则自增,为空,则置为0
|
364
|
+
last_continue_at: Time.new, # 上一次发生流量的时间
|
365
|
+
is_closing: false # 是否准备关闭
|
369
366
|
}
|
370
367
|
|
371
368
|
add_read( dst, :dst )
|
@@ -396,27 +393,29 @@ module Girl
|
|
396
393
|
new_a_tun
|
397
394
|
end
|
398
395
|
|
396
|
+
src_info = @src_infos[ src ]
|
397
|
+
src_id = src_info[ :id ]
|
398
|
+
destination_port = src_info[ :destination_port ]
|
399
|
+
destination_domain = src_info[ :destination_domain ]
|
400
|
+
|
399
401
|
src_ext = {
|
400
|
-
src: src,
|
401
|
-
dst_port: nil,
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
402
|
+
src: src, # src
|
403
|
+
dst_port: nil, # 远端dst端口
|
404
|
+
destination_domain: destination_domain, # 目的地域名
|
405
|
+
wmems: {}, # 写后 pack_id => data
|
406
|
+
send_ats: {}, # 上一次发出时间 pack_id => send_at
|
407
|
+
relay_pack_id: 0, # 转发到几
|
408
|
+
continue_dst_pack_id: 0, # 收到几
|
409
|
+
pieces: {}, # 跳号包 dst_pack_id => data
|
410
|
+
is_dst_closed: false, # dst是否已关闭
|
411
|
+
biggest_dst_pack_id: 0, # dst最大包号码
|
412
|
+
completed_pack_id: 0, # 完成到几(对面收到几)
|
413
|
+
last_continue_at: Time.new # 上一次发生流量的时间
|
411
414
|
}
|
412
415
|
|
413
|
-
src_info = @src_infos[ src ]
|
414
|
-
src_id = src_info[ :id ]
|
415
416
|
@tun_info[ :src_exts ][ src_id ] = src_ext
|
416
417
|
src_info[ :proxy_type ] = :tunnel
|
417
418
|
|
418
|
-
destination_port = src_info[ :destination_port ]
|
419
|
-
destination_domain = src_info[ :destination_domain ]
|
420
419
|
destination_domain_port = [ destination_domain, destination_port ].join( ':' )
|
421
420
|
data = [ [ 0, A_NEW_SOURCE, src_id ].pack( 'Q>CQ>' ), @custom.encode( destination_domain_port ) ].join
|
422
421
|
loop_send_a_new_source( src_ext, data )
|
@@ -602,6 +601,23 @@ module Girl
|
|
602
601
|
end
|
603
602
|
end
|
604
603
|
|
604
|
+
##
|
605
|
+
# send data
|
606
|
+
#
|
607
|
+
def send_data( tun, data, to_addr )
|
608
|
+
begin
|
609
|
+
tun.sendmsg( data, 0, to_addr )
|
610
|
+
rescue IO::WaitWritable, Errno::EINTR
|
611
|
+
return false
|
612
|
+
rescue Errno::EHOSTUNREACH, Errno::ENETUNREACH, Errno::ENETDOWN => e
|
613
|
+
puts "#{ Time.new } #{ e.class }, close tun"
|
614
|
+
close_tun( tun )
|
615
|
+
return false
|
616
|
+
end
|
617
|
+
|
618
|
+
true
|
619
|
+
end
|
620
|
+
|
605
621
|
##
|
606
622
|
# close src
|
607
623
|
#
|
@@ -768,6 +784,7 @@ module Girl
|
|
768
784
|
# puts "debug2 write src #{ written }"
|
769
785
|
data = data[ written..-1 ]
|
770
786
|
src_info[ from ] = data
|
787
|
+
src_info[ :last_continue_at ] = Time.new
|
771
788
|
end
|
772
789
|
|
773
790
|
##
|
@@ -819,6 +836,7 @@ module Girl
|
|
819
836
|
# puts "debug2 write dst #{ written }"
|
820
837
|
data = data[ written..-1 ]
|
821
838
|
dst_info[ from ] = data
|
839
|
+
dst_info[ :last_continue_at ] = Time.new
|
822
840
|
end
|
823
841
|
|
824
842
|
##
|
@@ -836,13 +854,7 @@ module Girl
|
|
836
854
|
while @tun_info[ :ctlmsgs ].any?
|
837
855
|
to_addr, data = @tun_info[ :ctlmsgs ].first
|
838
856
|
|
839
|
-
|
840
|
-
tun.sendmsg( data, 0, to_addr )
|
841
|
-
rescue IO::WaitWritable, Errno::EINTR
|
842
|
-
return
|
843
|
-
rescue Errno::EHOSTUNREACH, Errno::ENETUNREACH => e
|
844
|
-
puts "#{ Time.new } #{ e.class }, close tun"
|
845
|
-
close_tun( tun )
|
857
|
+
unless send_data( tun, data, to_addr )
|
846
858
|
return
|
847
859
|
end
|
848
860
|
|
@@ -858,13 +870,7 @@ module Girl
|
|
858
870
|
data = src_ext[ :wmems ][ pack_id ]
|
859
871
|
|
860
872
|
if data
|
861
|
-
|
862
|
-
tun.sendmsg( data, 0, @tun_info[ :tund_addr ] )
|
863
|
-
rescue IO::WaitWritable, Errno::EINTR
|
864
|
-
return
|
865
|
-
rescue Errno::EHOSTUNREACH, Errno::ENETUNREACH => e
|
866
|
-
puts "#{ Time.new } #{ e.class }, close tun"
|
867
|
-
close_tun( tun )
|
873
|
+
unless send_data( tun, data, @tun_info[ :tund_addr ] )
|
868
874
|
return
|
869
875
|
end
|
870
876
|
end
|
@@ -930,13 +936,7 @@ module Girl
|
|
930
936
|
|
931
937
|
data = [ [ pack_id, src_id ].pack( 'Q>Q>' ), data ].join
|
932
938
|
|
933
|
-
|
934
|
-
tun.sendmsg( data, 0, @tun_info[ :tund_addr ] )
|
935
|
-
rescue IO::WaitWritable, Errno::EINTR
|
936
|
-
return
|
937
|
-
rescue Errno::EHOSTUNREACH, Errno::ENETUNREACH => e
|
938
|
-
puts "#{ Time.new } #{ e.class }, close tun"
|
939
|
-
close_tun( tun )
|
939
|
+
unless send_data( tun, data, @tun_info[ :tund_addr ] )
|
940
940
|
return
|
941
941
|
end
|
942
942
|
|
@@ -967,26 +967,25 @@ module Girl
|
|
967
967
|
return
|
968
968
|
end
|
969
969
|
|
970
|
-
id = rand( ( 2 ** 64 ) -
|
970
|
+
id = rand( ( 2 ** 64 ) - 2 ) + 1
|
971
971
|
# puts "debug1 accept a src #{ addrinfo.inspect } #{ id }"
|
972
972
|
|
973
973
|
@src_infos[ src ] = {
|
974
|
-
id: id,
|
975
|
-
proxy_proto: :uncheck,
|
976
|
-
proxy_type: :uncheck,
|
977
|
-
dst: nil,
|
978
|
-
destination_domain: nil,
|
979
|
-
destination_port: nil,
|
980
|
-
biggest_pack_id: 0,
|
981
|
-
is_connect: true,
|
982
|
-
rbuffs: [],
|
983
|
-
wbuff: '',
|
984
|
-
cache: '',
|
985
|
-
chunks: [],
|
986
|
-
spring: 0,
|
987
|
-
|
988
|
-
|
989
|
-
is_closing: false # 是否准备关闭
|
974
|
+
id: id, # id
|
975
|
+
proxy_proto: :uncheck, # :uncheck / :http / :socks5
|
976
|
+
proxy_type: :uncheck, # :uncheck / :checking / :direct / :tunnel / :negotiation
|
977
|
+
dst: nil, # :direct的场合,对应的dst
|
978
|
+
destination_domain: nil, # 目的地域名
|
979
|
+
destination_port: nil, # 目的地端口
|
980
|
+
biggest_pack_id: 0, # 最大包号码
|
981
|
+
is_connect: true, # 代理协议是http的场合,是否是CONNECT
|
982
|
+
rbuffs: [], # 非CONNECT,dst或者远端dst未准备好,暂存流量 [ pack_id, data ]
|
983
|
+
wbuff: '', # 写前
|
984
|
+
cache: '', # 块读出缓存
|
985
|
+
chunks: [], # 块队列,写前达到块大小时结一个块 filename
|
986
|
+
spring: 0, # 块后缀,结块时,如果块队列不为空,则自增,为空,则置为0
|
987
|
+
last_continue_at: Time.new, # 上一次发生流量的时间
|
988
|
+
is_closing: false # 是否准备关闭
|
990
989
|
}
|
991
990
|
|
992
991
|
add_read( src, :src )
|
@@ -1008,7 +1007,7 @@ module Girl
|
|
1008
1007
|
|
1009
1008
|
# puts "debug2 read src #{ data.inspect }"
|
1010
1009
|
src_info = @src_infos[ src ]
|
1011
|
-
src_info[ :
|
1010
|
+
src_info[ :last_continue_at ] = Time.new
|
1012
1011
|
proxy_type = src_info[ :proxy_type ]
|
1013
1012
|
|
1014
1013
|
case proxy_type
|
@@ -1198,7 +1197,7 @@ module Girl
|
|
1198
1197
|
|
1199
1198
|
# puts "debug2 read dst #{ data.inspect }"
|
1200
1199
|
dst_info = @dst_infos[ dst ]
|
1201
|
-
dst_info[ :
|
1200
|
+
dst_info[ :last_continue_at ] = Time.new
|
1202
1201
|
src = dst_info[ :src ]
|
1203
1202
|
|
1204
1203
|
if src.closed?
|
data/lib/girl/proxyd_worker.rb
CHANGED
@@ -112,7 +112,7 @@ module Girl
|
|
112
112
|
|
113
113
|
tund_info[ :dst_exts ].each do | dst_local_port, dst_ext |
|
114
114
|
if dst_ext[ :dst ].closed? && ( now - dst_ext[ :last_continue_at ] > EXPIRE_AFTER )
|
115
|
-
puts "p#{ Process.pid } #{ Time.new } expire dst ext #{
|
115
|
+
puts "p#{ Process.pid } #{ Time.new } expire dst ext #{ dst_ext[ :domain_port ] }"
|
116
116
|
del_dst_ext( tund, dst_local_port )
|
117
117
|
end
|
118
118
|
end
|
@@ -123,10 +123,8 @@ module Girl
|
|
123
123
|
end
|
124
124
|
|
125
125
|
@dst_infos.each do | dst, dst_info |
|
126
|
-
|
127
|
-
|
128
|
-
if is_expired
|
129
|
-
puts "p#{ Process.pid } #{ Time.new } expire dst"
|
126
|
+
if now - dst_info[ :last_continue_at ] > EXPIRE_AFTER
|
127
|
+
puts "p#{ Process.pid } #{ Time.new } expire dst #{ dst_info[ :domain_port ] }"
|
130
128
|
set_is_closing( dst )
|
131
129
|
need_trigger = true
|
132
130
|
end
|
@@ -195,7 +193,7 @@ module Girl
|
|
195
193
|
|
196
194
|
if Time.new - created_at < RESOLV_CACHE_EXPIRE
|
197
195
|
# puts "debug1 #{ destination_domain_port } hit resolv cache #{ Addrinfo.new( destination_addr ).inspect }"
|
198
|
-
deal_with_destination_addr( tund, src_id, destination_addr )
|
196
|
+
deal_with_destination_addr( tund, src_id, destination_addr, destination_domain_port )
|
199
197
|
return
|
200
198
|
end
|
201
199
|
|
@@ -223,7 +221,7 @@ module Girl
|
|
223
221
|
@resolv_caches[ destination_domain_port ] = [ destination_addr, Time.new ]
|
224
222
|
|
225
223
|
unless tund.closed?
|
226
|
-
if deal_with_destination_addr( tund, src_id, destination_addr )
|
224
|
+
if deal_with_destination_addr( tund, src_id, destination_addr, destination_domain_port )
|
227
225
|
next_tick
|
228
226
|
end
|
229
227
|
end
|
@@ -235,7 +233,7 @@ module Girl
|
|
235
233
|
##
|
236
234
|
# deal with destination addr
|
237
235
|
#
|
238
|
-
def deal_with_destination_addr( tund, src_id, destination_addr )
|
236
|
+
def deal_with_destination_addr( tund, src_id, destination_addr, destination_domain_port )
|
239
237
|
dst = Socket.new( Addrinfo.new( destination_addr ).ipv4? ? Socket::AF_INET : Socket::AF_INET6, Socket::SOCK_STREAM, 0 )
|
240
238
|
dst.setsockopt( Socket::SOL_TCP, Socket::TCP_NODELAY, 1 )
|
241
239
|
|
@@ -250,33 +248,34 @@ module Girl
|
|
250
248
|
local_port = dst.local_address.ip_port
|
251
249
|
|
252
250
|
@dst_infos[ dst ] = {
|
253
|
-
local_port: local_port,
|
254
|
-
tund: tund,
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
is_closing: false
|
251
|
+
local_port: local_port, # 本地端口
|
252
|
+
tund: tund, # 对应tund
|
253
|
+
domain_port: destination_domain_port, # 域名和端口
|
254
|
+
biggest_pack_id: 0, # 最大包号码
|
255
|
+
wbuff: '', # 写前
|
256
|
+
cache: '', # 块读出缓存
|
257
|
+
chunks: [], # 块队列,写前达到块大小时结一个块 filename
|
258
|
+
spring: 0, # 块后缀,结块时,如果块队列不为空,则自增,为空,则置为0
|
259
|
+
last_continue_at: Time.new, # 上一次发生流量的时间
|
260
|
+
is_closing: false # 是否准备关闭
|
263
261
|
}
|
264
262
|
add_read( dst, :dst )
|
265
263
|
|
266
264
|
tund_info = @tund_infos[ tund ]
|
267
265
|
tund_info[ :dst_local_ports ][ src_id ] = local_port
|
268
266
|
tund_info[ :dst_exts ][ local_port ] = {
|
269
|
-
dst: dst,
|
270
|
-
src_id: src_id,
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
267
|
+
dst: dst, # dst
|
268
|
+
src_id: src_id, # 近端src id
|
269
|
+
domain_port: destination_domain_port, # 域名和端口
|
270
|
+
wmems: {}, # 写后 pack_id => data
|
271
|
+
send_ats: {}, # 上一次发出时间 pack_id => send_at
|
272
|
+
relay_pack_id: 0, # 转发到几
|
273
|
+
continue_src_pack_id: 0, # 收到几
|
274
|
+
pieces: {}, # 跳号包 src_pack_id => data
|
275
|
+
is_src_closed: false, # src是否已关闭
|
276
|
+
biggest_src_pack_id: 0, # src最大包号码
|
277
|
+
completed_pack_id: 0, # 完成到几(对面收到几)
|
278
|
+
last_continue_at: Time.new # 上一次发生流量的时间
|
280
279
|
}
|
281
280
|
|
282
281
|
data = [ 0, PAIRED, src_id, local_port ].pack( 'Q>CQ>n' )
|
@@ -416,6 +415,23 @@ module Girl
|
|
416
415
|
end
|
417
416
|
end
|
418
417
|
|
418
|
+
##
|
419
|
+
# send data
|
420
|
+
#
|
421
|
+
def send_data( tund, data, to_addr )
|
422
|
+
begin
|
423
|
+
tund.sendmsg( data, 0, to_addr )
|
424
|
+
rescue IO::WaitWritable, Errno::EINTR
|
425
|
+
return false
|
426
|
+
rescue Errno::EHOSTUNREACH, Errno::ENETUNREACH, Errno::ENETDOWN => e
|
427
|
+
puts "#{ Time.new } #{ e.class }, close tund"
|
428
|
+
close_tund( tund )
|
429
|
+
return false
|
430
|
+
end
|
431
|
+
|
432
|
+
true
|
433
|
+
end
|
434
|
+
|
419
435
|
##
|
420
436
|
# close dst
|
421
437
|
#
|
@@ -586,6 +602,7 @@ module Girl
|
|
586
602
|
# puts "debug2 write dst #{ written }"
|
587
603
|
data = data[ written..-1 ]
|
588
604
|
dst_info[ from ] = data
|
605
|
+
dst_info[ :last_continue_at ] = Time.new
|
589
606
|
end
|
590
607
|
|
591
608
|
##
|
@@ -603,9 +620,7 @@ module Girl
|
|
603
620
|
while tund_info[ :ctlmsgs ].any?
|
604
621
|
data = tund_info[ :ctlmsgs ].first
|
605
622
|
|
606
|
-
|
607
|
-
tund.sendmsg( data, 0, tund_info[ :tun_addr ] )
|
608
|
-
rescue IO::WaitWritable, Errno::EINTR
|
623
|
+
unless send_data( tund, data, tund_info[ :tun_addr ] )
|
609
624
|
return
|
610
625
|
end
|
611
626
|
|
@@ -621,9 +636,7 @@ module Girl
|
|
621
636
|
data = dst_ext[ :wmems ][ pack_id ]
|
622
637
|
|
623
638
|
if data
|
624
|
-
|
625
|
-
tund.sendmsg( data, 0, tund_info[ :tun_addr ] )
|
626
|
-
rescue IO::WaitWritable, Errno::EINTR
|
639
|
+
unless send_data( tund, data, tund_info[ :tun_addr ] )
|
627
640
|
return
|
628
641
|
end
|
629
642
|
end
|
@@ -689,9 +702,7 @@ module Girl
|
|
689
702
|
|
690
703
|
data = [ [ pack_id, dst_local_port ].pack( 'Q>n' ), data ].join
|
691
704
|
|
692
|
-
|
693
|
-
tund.sendmsg( data, 0, tund_info[ :tun_addr ] )
|
694
|
-
rescue IO::WaitWritable, Errno::EINTR
|
705
|
+
unless send_data( tund, data, tund_info[ :tun_addr ] )
|
695
706
|
return
|
696
707
|
end
|
697
708
|
|
@@ -775,7 +786,7 @@ module Girl
|
|
775
786
|
|
776
787
|
# puts "debug2 read dst #{ data.inspect }"
|
777
788
|
dst_info = @dst_infos[ dst ]
|
778
|
-
dst_info[ :
|
789
|
+
dst_info[ :last_continue_at ] = Time.new
|
779
790
|
tund = dst_info[ :tund ]
|
780
791
|
|
781
792
|
if tund.closed?
|
data/lib/girl/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: girl
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.77.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- takafan
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-07-
|
11
|
+
date: 2020-07-26 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: while internet is evil, here's a girl.
|
14
14
|
email:
|
@@ -49,8 +49,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
49
49
|
- !ruby/object:Gem::Version
|
50
50
|
version: '0'
|
51
51
|
requirements: []
|
52
|
-
|
53
|
-
rubygems_version: 2.7.6.2
|
52
|
+
rubygems_version: 3.1.2
|
54
53
|
signing_key:
|
55
54
|
specification_version: 4
|
56
55
|
summary: 妹子
|