tracksperanto 2.9.8 → 2.9.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.txt +4 -0
- data/bin/tracksperanto +10 -0
- data/lib/middleware/lens_disto.rb +130 -0
- data/lib/tracksperanto/casts.rb +8 -0
- data/lib/tracksperanto.rb +1 -1
- data/test/import/test_3de_import.rb +12 -0
- data/test/middleware/test_lens_middleware.rb +75 -0
- data/test/test_casts.rb +19 -1
- data/tracksperanto.gemspec +4 -2
- metadata +23 -21
data/History.txt
CHANGED
data/bin/tracksperanto
CHANGED
@@ -81,6 +81,16 @@ op.on(" -pad", "--pad PAD_FRACTION_VALUES_COMMA_SEPARATED", String, mwd("Pad"))
|
|
81
81
|
$middlewares.push(["Pad", {"left_pad" => left, "right_pad"=> right, "top_pad" => top, "bottom_pad" => bottom}])
|
82
82
|
end
|
83
83
|
|
84
|
+
op.on(" -u", "--undistort K_AND_KCUBE_COMMA_SEPARATED", String, mwd("LensDisto")) do | coefficients |
|
85
|
+
k, kcube = coefficients.split(",").map{|e| e.to_f }
|
86
|
+
$middlewares.push(["LensDisto", {"k" => k, "kcube"=> kcube, "remove" => true}])
|
87
|
+
end
|
88
|
+
|
89
|
+
op.on(" -d", "--distort K_AND_KCUBE_COMMA_SEPARATED", String, mwd("LensDisto")) do | coefficients |
|
90
|
+
k, kcube = coefficients.split(",").map{|e| e.to_f }
|
91
|
+
$middlewares.push(["LensDisto", {"k" => k, "kcube"=> kcube, "remove" => false}])
|
92
|
+
end
|
93
|
+
|
84
94
|
op.on(" -crop", "--crop CROP_VALUES_COMMA_SEPARATED", String, mwd("Crop")) do | pads|
|
85
95
|
left, right, top, bottom = pads.split(",").map{|e| e.to_i }
|
86
96
|
$middlewares.push(["Crop", {"left" => left, "right"=> right, "top" => top, "bottom" => bottom}])
|
@@ -0,0 +1,130 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
class Tracksperanto::Middleware::LensDisto < Tracksperanto::Middleware::Base
|
3
|
+
include Tracksperanto::UVCoordinates
|
4
|
+
|
5
|
+
class Vector2 < Struct.new(:x, :y)
|
6
|
+
end
|
7
|
+
|
8
|
+
class RF < Struct.new(:r, :f)
|
9
|
+
def inspect
|
10
|
+
'(%0.3f %0.3f)' % [r, f]
|
11
|
+
end
|
12
|
+
|
13
|
+
def m
|
14
|
+
r * f
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
parameter :k, :cast => :float, :desc => "Quartic distortion coefficient", :default => 0
|
19
|
+
parameter :kcube, :cast => :float, :desc => "Cubic distortion coefficient", :default => 0
|
20
|
+
parameter :remove, :cast => :bool, :desc => "Remove distortion instead of adding it"
|
21
|
+
|
22
|
+
STEPS = 256
|
23
|
+
|
24
|
+
def self.action_description
|
25
|
+
"Apply or remove lens distortion with the Syntheyes algorithm"
|
26
|
+
end
|
27
|
+
|
28
|
+
def start_export(w, h)
|
29
|
+
@width, @height = w, h
|
30
|
+
@aspect = @width.to_f / @height
|
31
|
+
|
32
|
+
# Generate the lookup table
|
33
|
+
@lut = [RF.new(0.0, 1.0)]
|
34
|
+
max_r = @aspect + 1
|
35
|
+
|
36
|
+
increment = max_r / STEPS
|
37
|
+
r = 0
|
38
|
+
STEPS.times do | mult |
|
39
|
+
r += increment
|
40
|
+
@lut.push(RF.new(r, disto_radius(r)))
|
41
|
+
end
|
42
|
+
|
43
|
+
@lut.inspect
|
44
|
+
super
|
45
|
+
end
|
46
|
+
|
47
|
+
def export_point(frame, float_x, float_y, float_residual)
|
48
|
+
x, y = remove ? undisto(float_x, float_y) : disto(float_x, float_y)
|
49
|
+
super(frame, x, y, float_residual)
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def with_uv(x, y)
|
55
|
+
vec = Vector2.new(convert_to_uv(x, @width), convert_to_uv(y, @height))
|
56
|
+
yield(vec)
|
57
|
+
[convert_from_uv(@width, vec.x), convert_from_uv(@height, vec.y)]
|
58
|
+
end
|
59
|
+
|
60
|
+
# Radius is equal to aspect at the rightmost extremity
|
61
|
+
def disto_radius(r)
|
62
|
+
r2 = r ** 2
|
63
|
+
# Skipping the square root speeds things up if we don't need it
|
64
|
+
f = if kcube.abs > 0.00001
|
65
|
+
1 + (r2 * (k + kcube * Math.sqrt(r2)));
|
66
|
+
else
|
67
|
+
1 + (r2 * k);
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def disto(x, y)
|
72
|
+
with_uv(x, y) do | pt |
|
73
|
+
# Get the radius of the point
|
74
|
+
x = pt.x * @aspect
|
75
|
+
r = Math.sqrt(x.abs**2 + pt.y.abs**2)
|
76
|
+
|
77
|
+
# Find the good tuples to interpolate on
|
78
|
+
f = disto_interpolated(r)
|
79
|
+
|
80
|
+
pt.x = pt.x * f
|
81
|
+
pt.y = pt.y * f
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
|
86
|
+
def undisto(x, y)
|
87
|
+
with_uv(x, y) do | pt |
|
88
|
+
# Get the radius of the point
|
89
|
+
x = pt.x * @aspect
|
90
|
+
r = Math.sqrt(x.abs**2 + pt.y.abs**2)
|
91
|
+
|
92
|
+
# Find the good tuples to interpolate on
|
93
|
+
f = undisto_interpolated(r)
|
94
|
+
|
95
|
+
pt.x = pt.x / f
|
96
|
+
pt.y = pt.y / f
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def disto_interpolated(r)
|
101
|
+
left , right = nil, nil
|
102
|
+
@lut.each_with_index do | rf, i |
|
103
|
+
if rf.r > r
|
104
|
+
right = rf
|
105
|
+
left = @lut[i -1]
|
106
|
+
return lerp(r, left.r, right.r, left.f, right.f)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def undisto_interpolated(r)
|
112
|
+
left , right = nil, nil
|
113
|
+
@lut.each_with_index do | xf, i |
|
114
|
+
if xf.m > r
|
115
|
+
right = xf
|
116
|
+
left = @lut[i -1]
|
117
|
+
return lerp(r, left.m, right.m, left.f, right.f)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def lerp(x, left_x, right_x, left_y, right_y)
|
123
|
+
dx = right_x - left_x
|
124
|
+
dy = right_y - left_y
|
125
|
+
t = (x - left_x) / dx
|
126
|
+
left_y + (dy * t)
|
127
|
+
end
|
128
|
+
|
129
|
+
|
130
|
+
end
|
data/lib/tracksperanto/casts.rb
CHANGED
@@ -29,4 +29,12 @@ module Tracksperanto::Casts
|
|
29
29
|
define_method("#{an_attr}=") { |to| instance_variable_set("@#{an_attr}", to.to_s) }
|
30
30
|
end
|
31
31
|
end
|
32
|
+
|
33
|
+
def cast_to_bool(*attributes)
|
34
|
+
attributes.each do | an_attr |
|
35
|
+
define_method(an_attr) { !!instance_variable_get("@#{an_attr}") }
|
36
|
+
define_method("#{an_attr}=") { |to| instance_variable_set("@#{an_attr}", !!to) }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
32
40
|
end
|
data/lib/tracksperanto.rb
CHANGED
@@ -27,4 +27,16 @@ class EqualizerImportTest < Test::Unit::TestCase
|
|
27
27
|
assert_in_delta 232.449011732690479, first_kf.abs_y, DELTA
|
28
28
|
assert_equal 39, first_kf.frame
|
29
29
|
end
|
30
|
+
|
31
|
+
def test_parsing_from_another_fixture
|
32
|
+
fixture = File.open(File.dirname(__FILE__) + '/samples/3de_v4/FB1880_man_v05.txt')
|
33
|
+
|
34
|
+
parser = Tracksperanto::Import::Equalizer4.new(:io => fixture, :width => 1024, :height => 512)
|
35
|
+
trackers = parser.to_a
|
36
|
+
assert_equal 27, trackers.length
|
37
|
+
|
38
|
+
first_t = trackers[0]
|
39
|
+
assert_equal "01", first_t.name
|
40
|
+
assert_equal 115, first_t.length
|
41
|
+
end
|
30
42
|
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
require File.expand_path(File.dirname(__FILE__)) + '/../helper'
|
3
|
+
|
4
|
+
class LensMiddlewareTest < Test::Unit::TestCase
|
5
|
+
|
6
|
+
def test_action_description
|
7
|
+
assert_equal "Apply or remove lens distortion with the Syntheyes algorithm", Tracksperanto::Middleware::LensDisto.action_description
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_lens_bypasses_centerpoint
|
11
|
+
receiver = flexmock
|
12
|
+
receiver.should_receive(:start_export).once.with(1920, 1080)
|
13
|
+
receiver.should_receive(:start_tracker_segment).once.with("Tracker")
|
14
|
+
receiver.should_receive(:export_point).once.with(1, 1920 / 2.0, 1080.0 / 2.0, 0)
|
15
|
+
receiver.should_receive(:end_tracker_segment).once
|
16
|
+
receiver.should_receive(:end_export).once
|
17
|
+
|
18
|
+
m = Tracksperanto::Middleware::LensDisto.new(receiver, :k => 0.0168)
|
19
|
+
m.start_export(1920, 1080)
|
20
|
+
m.start_tracker_segment("Tracker")
|
21
|
+
m.export_point(1, 1920 / 2.0, 1080.0 / 2.0, 0)
|
22
|
+
m.end_tracker_segment
|
23
|
+
m.end_export
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_lens_distorted
|
27
|
+
receiver = flexmock
|
28
|
+
receiver.should_receive(:start_export).once.with(1920, 1080)
|
29
|
+
receiver.should_receive(:start_tracker_segment).once.with("Tracker")
|
30
|
+
receiver.should_receive(:export_point).once.with(1, 66.03001446825158, 43.978678913818925, 0)
|
31
|
+
receiver.should_receive(:end_tracker_segment).once
|
32
|
+
receiver.should_receive(:end_export).once
|
33
|
+
|
34
|
+
m = Tracksperanto::Middleware::LensDisto.new(receiver, :k => -0.0298, :kcube => 0.0078)
|
35
|
+
m.start_export(1920, 1080)
|
36
|
+
m.start_tracker_segment("Tracker")
|
37
|
+
m.export_point(1, 12.0, 14.0, 0)
|
38
|
+
m.end_tracker_segment
|
39
|
+
m.end_export
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_lens_undistorted
|
43
|
+
receiver = flexmock
|
44
|
+
receiver.should_receive(:start_export).once.with(1920, 1080)
|
45
|
+
receiver.should_receive(:start_tracker_segment).once.with("Tracker")
|
46
|
+
receiver.should_receive(:export_point).once.with(1, 11.999914830236555, 13.99995274335909, 0)
|
47
|
+
receiver.should_receive(:end_tracker_segment).once
|
48
|
+
receiver.should_receive(:end_export).once
|
49
|
+
|
50
|
+
m = Tracksperanto::Middleware::LensDisto.new(receiver, :k => -0.0298, :kcube => 0.0078, :remove => true)
|
51
|
+
m.start_export(1920, 1080)
|
52
|
+
m.start_tracker_segment("Tracker")
|
53
|
+
m.export_point(1, 66.03001446825158, 43.978678913818925, 0)
|
54
|
+
m.end_tracker_segment
|
55
|
+
m.end_export
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_roundtrip
|
59
|
+
receiver = flexmock
|
60
|
+
receiver.should_receive(:start_export).once.with(1920, 1080)
|
61
|
+
receiver.should_receive(:start_tracker_segment).once.with("Tracker")
|
62
|
+
receiver.should_receive(:export_point).once.with(1, 1.0, 1.0, 0)
|
63
|
+
receiver.should_receive(:end_tracker_segment).once
|
64
|
+
receiver.should_receive(:end_export).once
|
65
|
+
|
66
|
+
apply = Tracksperanto::Middleware::LensDisto.new(receiver, :k => -0.0298, :kcube => 0.2178)
|
67
|
+
remove = Tracksperanto::Middleware::LensDisto.new(apply, :k => -0.0298, :kcube => 0.2178, :remove => true)
|
68
|
+
|
69
|
+
remove.start_export(1920, 1080)
|
70
|
+
remove.start_tracker_segment("Tracker")
|
71
|
+
remove.export_point(1, 1.0, 1.0, 0)
|
72
|
+
remove.end_tracker_segment
|
73
|
+
remove.end_export
|
74
|
+
end
|
75
|
+
end
|
data/test/test_casts.rb
CHANGED
@@ -10,6 +10,7 @@ class TestCasts < Test::Unit::TestCase
|
|
10
10
|
cast_to_string :str_attr
|
11
11
|
cast_to_int :int_attr
|
12
12
|
cast_to_float :float_attr
|
13
|
+
cast_to_bool :truthy
|
13
14
|
end
|
14
15
|
|
15
16
|
class Junk
|
@@ -31,7 +32,24 @@ class TestCasts < Test::Unit::TestCase
|
|
31
32
|
assert_kind_of Float, t.float_attr
|
32
33
|
assert_in_delta 0, t.float_attr, D
|
33
34
|
end
|
34
|
-
|
35
|
+
|
36
|
+
def test_cast_to_bool
|
37
|
+
t = Testable.new
|
38
|
+
assert_equal false, t.truthy
|
39
|
+
|
40
|
+
t.truthy = nil
|
41
|
+
assert_equal false, t.truthy
|
42
|
+
|
43
|
+
t.truthy = false
|
44
|
+
assert_equal false, t.truthy
|
45
|
+
|
46
|
+
t.truthy = "yes"
|
47
|
+
assert_equal true, t.truthy
|
48
|
+
|
49
|
+
t.truthy = 1
|
50
|
+
assert_equal true, t.truthy
|
51
|
+
end
|
52
|
+
|
35
53
|
def test_cast_to_int
|
36
54
|
t = Testable.new
|
37
55
|
|
data/tracksperanto.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "tracksperanto"
|
8
|
-
s.version = "2.9.
|
8
|
+
s.version = "2.9.9"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Julik Tarkhanov"]
|
12
|
-
s.date = "2012-
|
12
|
+
s.date = "2012-04-10"
|
13
13
|
s.description = "Converts 2D track exports between different apps like Flame, MatchMover, PFTrack..."
|
14
14
|
s.email = "me@julik.nl"
|
15
15
|
s.executables = ["tracksperanto"]
|
@@ -66,6 +66,7 @@ Gem::Specification.new do |s|
|
|
66
66
|
"lib/middleware/flop.rb",
|
67
67
|
"lib/middleware/golden.rb",
|
68
68
|
"lib/middleware/length_cutoff.rb",
|
69
|
+
"lib/middleware/lens_disto.rb",
|
69
70
|
"lib/middleware/lerp.rb",
|
70
71
|
"lib/middleware/lint.rb",
|
71
72
|
"lib/middleware/move_to_first.rb",
|
@@ -153,6 +154,7 @@ Gem::Specification.new do |s|
|
|
153
154
|
"test/middleware/test_flop_middleware.rb",
|
154
155
|
"test/middleware/test_golden_middleware.rb",
|
155
156
|
"test/middleware/test_length_cutoff_middleware.rb",
|
157
|
+
"test/middleware/test_lens_middleware.rb",
|
156
158
|
"test/middleware/test_lerp_middleware.rb",
|
157
159
|
"test/middleware/test_lint_middleware.rb",
|
158
160
|
"test/middleware/test_move_to_first_frame_middleware.rb",
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tracksperanto
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.9.
|
4
|
+
version: 2.9.9
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-04-10 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: obuf
|
16
|
-
requirement: &
|
16
|
+
requirement: &12549320 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: 1.1.0
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *12549320
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: progressive_io
|
27
|
-
requirement: &
|
27
|
+
requirement: &12549080 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ~>
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '1.0'
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *12549080
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: flame_channel_parser
|
38
|
-
requirement: &
|
38
|
+
requirement: &12548840 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ~>
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: '4.0'
|
44
44
|
type: :runtime
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *12548840
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: progressbar
|
49
|
-
requirement: &
|
49
|
+
requirement: &12548600 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - =
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: 0.10.0
|
55
55
|
type: :runtime
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *12548600
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: update_hints
|
60
|
-
requirement: &
|
60
|
+
requirement: &12548360 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ~>
|
@@ -65,10 +65,10 @@ dependencies:
|
|
65
65
|
version: '1.0'
|
66
66
|
type: :runtime
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *12548360
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: jeweler
|
71
|
-
requirement: &
|
71
|
+
requirement: &12548120 !ruby/object:Gem::Requirement
|
72
72
|
none: false
|
73
73
|
requirements:
|
74
74
|
- - ! '>='
|
@@ -76,10 +76,10 @@ dependencies:
|
|
76
76
|
version: '0'
|
77
77
|
type: :development
|
78
78
|
prerelease: false
|
79
|
-
version_requirements: *
|
79
|
+
version_requirements: *12548120
|
80
80
|
- !ruby/object:Gem::Dependency
|
81
81
|
name: rake
|
82
|
-
requirement: &
|
82
|
+
requirement: &12547880 !ruby/object:Gem::Requirement
|
83
83
|
none: false
|
84
84
|
requirements:
|
85
85
|
- - ! '>='
|
@@ -87,10 +87,10 @@ dependencies:
|
|
87
87
|
version: '0'
|
88
88
|
type: :development
|
89
89
|
prerelease: false
|
90
|
-
version_requirements: *
|
90
|
+
version_requirements: *12547880
|
91
91
|
- !ruby/object:Gem::Dependency
|
92
92
|
name: flexmock
|
93
|
-
requirement: &
|
93
|
+
requirement: &12547640 !ruby/object:Gem::Requirement
|
94
94
|
none: false
|
95
95
|
requirements:
|
96
96
|
- - ~>
|
@@ -98,10 +98,10 @@ dependencies:
|
|
98
98
|
version: '0.8'
|
99
99
|
type: :development
|
100
100
|
prerelease: false
|
101
|
-
version_requirements: *
|
101
|
+
version_requirements: *12547640
|
102
102
|
- !ruby/object:Gem::Dependency
|
103
103
|
name: cli_test
|
104
|
-
requirement: &
|
104
|
+
requirement: &12547400 !ruby/object:Gem::Requirement
|
105
105
|
none: false
|
106
106
|
requirements:
|
107
107
|
- - ~>
|
@@ -109,7 +109,7 @@ dependencies:
|
|
109
109
|
version: '1.0'
|
110
110
|
type: :development
|
111
111
|
prerelease: false
|
112
|
-
version_requirements: *
|
112
|
+
version_requirements: *12547400
|
113
113
|
description: Converts 2D track exports between different apps like Flame, MatchMover,
|
114
114
|
PFTrack...
|
115
115
|
email: me@julik.nl
|
@@ -168,6 +168,7 @@ files:
|
|
168
168
|
- lib/middleware/flop.rb
|
169
169
|
- lib/middleware/golden.rb
|
170
170
|
- lib/middleware/length_cutoff.rb
|
171
|
+
- lib/middleware/lens_disto.rb
|
171
172
|
- lib/middleware/lerp.rb
|
172
173
|
- lib/middleware/lint.rb
|
173
174
|
- lib/middleware/move_to_first.rb
|
@@ -255,6 +256,7 @@ files:
|
|
255
256
|
- test/middleware/test_flop_middleware.rb
|
256
257
|
- test/middleware/test_golden_middleware.rb
|
257
258
|
- test/middleware/test_length_cutoff_middleware.rb
|
259
|
+
- test/middleware/test_lens_middleware.rb
|
258
260
|
- test/middleware/test_lerp_middleware.rb
|
259
261
|
- test/middleware/test_lint_middleware.rb
|
260
262
|
- test/middleware/test_move_to_first_frame_middleware.rb
|
@@ -297,7 +299,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
297
299
|
version: '0'
|
298
300
|
segments:
|
299
301
|
- 0
|
300
|
-
hash:
|
302
|
+
hash: 179279919
|
301
303
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
302
304
|
none: false
|
303
305
|
requirements:
|