abundance 1.1.2 → 1.2.0
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/lib/garden.rb +58 -62
- data/lib/gardener.rb +7 -8
- data/lib/toolshed.rb +64 -110
- metadata +2 -2
data/lib/garden.rb
CHANGED
@@ -32,68 +32,67 @@ class Garden
|
|
32
32
|
def initialize
|
33
33
|
@pid = fork do
|
34
34
|
@quit = false; @full_crop = false; @do_init = nil; @seed_all = nil; @init_all_crop = []
|
35
|
-
@harvest = []; @
|
35
|
+
@harvest = []; @rows_socket_paths = []; @init_done = []; @seed_all_done = []; @seed_all_crop = []
|
36
36
|
@seeds = []; @sprouts = []; @crops = []; @id = 0
|
37
|
-
|
38
|
-
@socket_client_temp = Toolshed.socket_client_temp
|
37
|
+
set_my_socket_as_a(:garden)
|
39
38
|
loop do
|
40
39
|
catch :fill_rows do
|
41
40
|
loop do
|
42
|
-
if ! @seed_all.nil? && ! @
|
43
|
-
|
44
|
-
unless @seed_all_done.include?(
|
45
|
-
|
46
|
-
@seed_all_done <<
|
41
|
+
if ! @seed_all.nil? && ! @rows_socket_paths.empty? && @seed_all_done.size != @seed_all[0]
|
42
|
+
row_socket_path = @rows_socket_paths.shift
|
43
|
+
unless @seed_all_done.include?( row_socket_path )
|
44
|
+
socket_send(:seed_all,@seed_all[1],row_socket_path)
|
45
|
+
@seed_all_done << row_socket_path
|
47
46
|
else
|
48
|
-
@
|
47
|
+
@rows_socket_paths << row_socket_path
|
49
48
|
end
|
50
|
-
elsif ! @do_init.nil? && ! @
|
51
|
-
|
52
|
-
unless @init_done.include?(
|
53
|
-
|
54
|
-
@init_done <<
|
49
|
+
elsif ! @do_init.nil? && ! @rows_socket_paths.empty? && @init_done.size != @do_init
|
50
|
+
row_socket_path = @rows_socket_paths.shift
|
51
|
+
unless @init_done.include?( row_socket_path )
|
52
|
+
socket_send(:init,'init_status',row_socket_path)
|
53
|
+
@init_done << row_socket_path
|
55
54
|
else
|
56
|
-
@
|
55
|
+
@rows_socket_paths << row_socket_path
|
57
56
|
end
|
58
|
-
elsif ! @seeds.empty? && ! @
|
57
|
+
elsif ! @seeds.empty? && ! @rows_socket_paths.empty?
|
59
58
|
seed = @seeds.shift
|
60
59
|
@sprouts[seed[:id]] = seed
|
61
|
-
|
62
|
-
|
63
|
-
elsif @quit && ! @
|
60
|
+
row_socket_path = @rows_socket_paths.shift
|
61
|
+
socket_send(:sprout,seed,row_socket_path)
|
62
|
+
elsif @quit && ! @rows_socket_paths.empty?
|
64
63
|
seed = nil
|
65
|
-
|
66
|
-
|
64
|
+
row_socket_path = @rows_socket_paths.shift
|
65
|
+
socket_send(:quit,seed,row_socket_path)
|
67
66
|
else
|
68
67
|
throw :fill_rows
|
69
68
|
end
|
70
69
|
end
|
71
70
|
end
|
72
|
-
command, data,
|
71
|
+
command, data, client_socket_path = socket_recv
|
73
72
|
case command
|
74
73
|
when :seed
|
75
74
|
@id += 1; @seeds << {:id => @id , :seed => data}
|
76
|
-
|
75
|
+
socket_send(command,@id,client_socket_path)
|
77
76
|
when :row
|
78
77
|
if @quit
|
79
78
|
command = :quit
|
80
79
|
seed = nil
|
81
80
|
elsif @seeds.empty?
|
82
81
|
seed = nil
|
83
|
-
@
|
82
|
+
@rows_socket_paths << data
|
84
83
|
else
|
85
84
|
seed = @seeds.shift
|
86
85
|
@sprouts[seed[:id]] = seed
|
87
86
|
end
|
88
|
-
|
87
|
+
socket_send(command,seed,client_socket_path)
|
89
88
|
when :crop
|
90
89
|
@sprouts[data[:id]] = nil
|
91
|
-
@crops[data[:id]] = data
|
90
|
+
@crops[data[:id]] = data
|
92
91
|
if @harvest[data[:id]]
|
93
|
-
|
92
|
+
socket_send(command,data, @harvest[data[:id]][:client_socket_path])
|
94
93
|
@crops[data[:id]] = @harvest[data[:id]] = nil
|
95
94
|
elsif @full_crop && @seeds.compact.empty? && @sprouts.compact.empty?
|
96
|
-
|
95
|
+
socket_send(command,@crops.compact,@mem_client_socket_path)
|
97
96
|
@crops.clear; @full_crop = false
|
98
97
|
end
|
99
98
|
when :growth
|
@@ -101,81 +100,79 @@ class Garden
|
|
101
100
|
when :progress
|
102
101
|
value = @crops.size.to_f / (@crops.size + @sprouts.compact.size + @seeds.size)
|
103
102
|
value = 1 if value.nan?; progress = sprintf( "%.2f", value)
|
104
|
-
|
103
|
+
socket_send(command,progress,client_socket_path)
|
105
104
|
when :seed
|
106
|
-
|
105
|
+
socket_send(command,@seeds.size,client_socket_path)
|
107
106
|
when :sprout
|
108
|
-
|
107
|
+
socket_send(command,@sprouts.compact.size,client_socket_path)
|
109
108
|
when :crop
|
110
|
-
|
109
|
+
socket_send(command,@crops.size,client_socket_path)
|
111
110
|
else
|
112
|
-
|
111
|
+
socket_send(command,false,client_socket_path)
|
113
112
|
end
|
114
113
|
when :harvest
|
115
114
|
case data
|
116
115
|
when :all
|
117
|
-
|
116
|
+
socket_send(command,{:seeds => @seeds, :sprouts => @sprouts.compact, :crops => @crops.compact},client_socket_path)
|
118
117
|
when :seed
|
119
|
-
|
118
|
+
socket_send(command,@seeds,client_socket_path)
|
120
119
|
when :sprout
|
121
|
-
|
120
|
+
socket_send(command,@sprouts.compact,client_socket_path)
|
122
121
|
when :crop
|
123
|
-
|
122
|
+
socket_send(command,@crops.compact,client_socket_path)
|
124
123
|
@crops.clear
|
125
124
|
when :full_crop
|
126
125
|
if @seeds.compact.empty? && @sprouts.compact.empty?
|
127
|
-
|
126
|
+
socket_send(command,@crops.compact,client_socket_path)
|
128
127
|
@crops.clear
|
129
128
|
else
|
130
129
|
@full_crop = true
|
131
|
-
@
|
130
|
+
@mem_client_socket_path = client_socket_path
|
132
131
|
end
|
133
132
|
else
|
134
133
|
if data.is_a? Integer
|
135
134
|
if @crops[data]
|
136
|
-
|
135
|
+
socket_send(command,@crops[data],client_socket_path)
|
137
136
|
@crops[data] = nil
|
138
137
|
else
|
139
|
-
@harvest[data] = {:
|
138
|
+
@harvest[data] = {:client_socket_path => client_socket_path}
|
140
139
|
end
|
141
140
|
else
|
142
|
-
|
141
|
+
socket_send(command,false,client_socket_path)
|
143
142
|
end
|
144
143
|
end
|
145
144
|
when :init
|
146
145
|
@do_init = data
|
147
|
-
@init_return = {:
|
146
|
+
@init_return = {:client_socket_path => client_socket_path}
|
148
147
|
when :init_crop
|
149
|
-
socket_server_send(command,true,clientaddr,clientport)
|
150
148
|
@init_all_crop << data
|
151
149
|
if @init_all_crop.size == @do_init
|
152
|
-
|
150
|
+
socket_send(command,@init_all_crop, @init_return[:client_socket_path])
|
153
151
|
@init_return = Hash.new; @init_done = Array.new; @do_init = nil; @init_all_crop = Array.new
|
154
152
|
end
|
155
153
|
when :seed_all
|
156
154
|
@seed_all = data
|
157
|
-
@seed_all_return = {:
|
155
|
+
@seed_all_return = {:client_socket_path => client_socket_path, :data => []}
|
158
156
|
when :seed_all_crop
|
159
|
-
socket_server_send(command,true,clientaddr,clientport)
|
160
157
|
@seed_all_crop << data
|
161
158
|
if @seed_all_crop.size == @seed_all[0]
|
162
|
-
|
159
|
+
socket_send(command,@seed_all_crop, @seed_all_return[:client_socket_path])
|
163
160
|
@seed_all = nil; @seed_all_return = Hash.new; @seed_all_done = Array.new; @seed_all_crop = Array.new
|
164
161
|
end
|
165
162
|
when :close
|
166
163
|
if data[:level] == :garden
|
167
164
|
@seeds_pid = data[:pid]
|
168
165
|
@quit = true
|
169
|
-
@
|
166
|
+
@mem_client_socket_path = client_socket_path
|
170
167
|
else
|
171
168
|
@seeds_pid.delete(data[:pid].to_i)
|
172
169
|
if @seeds_pid.empty?
|
173
|
-
|
170
|
+
socket_send(:close,{:seeds => @seeds, :sprouts => @sprouts.compact, :crops => @crops.compact}, @mem_client_socket_path)
|
174
171
|
exit
|
175
172
|
end
|
176
173
|
end
|
177
174
|
else
|
178
|
-
|
175
|
+
socket_send(command,false,client_socket_path)
|
179
176
|
end
|
180
177
|
end
|
181
178
|
end
|
@@ -194,7 +191,7 @@ class Garden
|
|
194
191
|
#
|
195
192
|
|
196
193
|
def rows(rows,init_timeout,grow_block)
|
197
|
-
Rows.new(rows,init_timeout,grow_block)
|
194
|
+
Rows.new(rows,init_timeout,@pid,grow_block)
|
198
195
|
end
|
199
196
|
|
200
197
|
# :title:Rows
|
@@ -213,17 +210,16 @@ class Garden
|
|
213
210
|
# === Parameter
|
214
211
|
# * _rows_ = garden rows number, the number of concurent threads
|
215
212
|
# * _init_timeout_ = allow to pause execution to allow for larger garden rows to initialize
|
213
|
+
# * _garden_pid_ = the parent Garden's pid, for loopback communication purpose
|
216
214
|
# === Example
|
217
215
|
# rows = Rows.new(4,2) { grow_block }
|
218
216
|
|
219
|
-
def initialize(rows,init_timeout,gardener_block)
|
217
|
+
def initialize(rows,init_timeout,garden_pid,gardener_block)
|
220
218
|
@pids = []
|
221
219
|
rows.times do
|
222
|
-
row_port = Toolshed.available_port
|
223
220
|
@pids << fork do
|
224
|
-
@socket_client_perm = Toolshed.socket_client_perm
|
225
221
|
@seed_all = false
|
226
|
-
|
222
|
+
set_my_socket_as_a(:row,garden_pid)
|
227
223
|
t1 = Thread.new do
|
228
224
|
gardener_block.call
|
229
225
|
end
|
@@ -231,15 +227,15 @@ class Garden
|
|
231
227
|
t2 = Thread.new do
|
232
228
|
loop do
|
233
229
|
if $seed.nil?
|
234
|
-
command, data =
|
230
|
+
command, data = socket_duplex(:row,my_socket_path)
|
235
231
|
if command == :quit
|
236
232
|
pid = Process.pid
|
237
|
-
|
233
|
+
socket_send(:close,{:level => :seed, :pid => pid})
|
238
234
|
exit
|
239
235
|
end
|
240
236
|
$seed = data
|
241
237
|
if $seed.nil?
|
242
|
-
command, data,
|
238
|
+
command, data, client_socket_path = socket_recv
|
243
239
|
case command
|
244
240
|
when :sprout
|
245
241
|
$seed = data
|
@@ -248,15 +244,15 @@ class Garden
|
|
248
244
|
$seed = {:id => Process.pid, :seed => data}
|
249
245
|
when :init
|
250
246
|
$init = {:seed => 'init_status', :message => 'No Init Message', :id => Process.pid} if $init.nil?
|
251
|
-
|
247
|
+
socket_send(:init_crop,$init)
|
252
248
|
end
|
253
249
|
end
|
254
250
|
elsif ! $seed[:success].nil?
|
255
251
|
if @seed_all
|
256
|
-
|
252
|
+
socket_send(:seed_all_crop,$seed)
|
257
253
|
@seed_all = false
|
258
254
|
else
|
259
|
-
|
255
|
+
socket_send(:crop,$seed)
|
260
256
|
end
|
261
257
|
$seed = nil;
|
262
258
|
else
|
data/lib/gardener.rb
CHANGED
@@ -35,12 +35,11 @@ class Gardener
|
|
35
35
|
elsif options[:wheelbarrow] < 1024 then 1024
|
36
36
|
else options[:wheelbarrow]
|
37
37
|
end
|
38
|
-
Toolshed::garden_port = Toolshed.available_port
|
39
38
|
|
40
39
|
@garden = Garden.new
|
41
40
|
@garden_rows = @garden.rows(options[:rows], options[:init_timeout], gardener_block)
|
42
41
|
|
43
|
-
|
42
|
+
set_my_socket_as_a(:gardener,@garden.pid)
|
44
43
|
end
|
45
44
|
|
46
45
|
# The +init_status+ method for the Gardener instance allow to harvest an initialisation status message
|
@@ -49,7 +48,7 @@ class Gardener
|
|
49
48
|
# === Example
|
50
49
|
# puts gardener.init_status.inspect # => [{:message=>"init ok", :success=>true, :pid=>4760}, {:message=>"init failed", :success=>false, :pid=>4761}]
|
51
50
|
def init_status
|
52
|
-
command, data =
|
51
|
+
command, data = socket_duplex(:init,@garden_rows.pids.size)
|
53
52
|
data.map! do |row|
|
54
53
|
{:success => row[:success], :message => row[:message], :pid => row[:id]}
|
55
54
|
end
|
@@ -63,7 +62,7 @@ class Gardener
|
|
63
62
|
# id_seed_1 = gardener.seed("system 'ruby -v'")
|
64
63
|
|
65
64
|
def seed(command)
|
66
|
-
command, data =
|
65
|
+
command, data = socket_duplex(:seed,command)
|
67
66
|
return data
|
68
67
|
end
|
69
68
|
|
@@ -76,7 +75,7 @@ class Gardener
|
|
76
75
|
# {:success=>true, :message=>["row pref changed to local"], :seed=>"pref local", :pid=>14913}]
|
77
76
|
def seed_all(command)
|
78
77
|
seed = [@garden_rows.pids.size, command]
|
79
|
-
command, data =
|
78
|
+
command, data = socket_duplex(:seed_all, seed)
|
80
79
|
data.map! do |row|
|
81
80
|
{:success => row[:success], :message => row[:message], :pid => row[:id]}
|
82
81
|
end
|
@@ -95,7 +94,7 @@ class Gardener
|
|
95
94
|
# puts "progress is now #{progress}" # => progress is now 0.75
|
96
95
|
|
97
96
|
def growth(crop=:progress)
|
98
|
-
command, data =
|
97
|
+
command, data = socket_duplex(:growth,crop)
|
99
98
|
return data
|
100
99
|
end
|
101
100
|
|
@@ -114,7 +113,7 @@ class Gardener
|
|
114
113
|
# seed1_result = gardener.harvest(id_seed_1)
|
115
114
|
|
116
115
|
def harvest(crop)
|
117
|
-
command, data =
|
116
|
+
command, data = socket_duplex(:harvest,crop)
|
118
117
|
return data
|
119
118
|
end
|
120
119
|
|
@@ -124,7 +123,7 @@ class Gardener
|
|
124
123
|
# final_harvest = gardener.close
|
125
124
|
|
126
125
|
def close
|
127
|
-
command, data =
|
126
|
+
command, data = socket_duplex(:close,{:level => :garden, :pid => @garden_rows.pids})
|
128
127
|
return data
|
129
128
|
end
|
130
129
|
|
data/lib/toolshed.rb
CHANGED
@@ -10,142 +10,96 @@
|
|
10
10
|
#
|
11
11
|
# :title:Toolshed
|
12
12
|
|
13
|
+
# TODO:
|
14
|
+
# -dedicated server on garden for 'ready!' rows where rows go write their PID
|
15
|
+
|
13
16
|
module Toolshed
|
17
|
+
require 'ftools'
|
14
18
|
require 'socket'
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
# The Toolshed.available_port method scans for a an available UDP port and returns its value.
|
20
|
-
def Toolshed.available_port
|
21
|
-
port = @@start_port + 1
|
22
|
-
catch :scan_port do
|
23
|
-
stat = `netstat`
|
24
|
-
loop do
|
25
|
-
throw :scan_port unless stat =~ /localhost\.#{port}/
|
26
|
-
port += 1
|
27
|
-
end
|
28
|
-
end
|
29
|
-
@@start_port = port
|
30
|
-
return port
|
31
|
-
end
|
32
|
-
|
33
|
-
# The Toolshed.socket_client_perm method creates a client socket permanently connected to the main server socket. Returns the client socket object.
|
34
|
-
def Toolshed.socket_client_perm
|
35
|
-
socket = UDPSocket.new
|
36
|
-
socket.connect(UDP_HOST,@@garden_port)
|
37
|
-
return socket
|
38
|
-
end
|
39
|
-
|
40
|
-
# The Toolshed.socket_client_temp method creates a client socket available for changing connections to multiple socket servers. Returns the client socket object.
|
41
|
-
def Toolshed.socket_client_temp
|
42
|
-
UDPSocket.new
|
43
|
-
end
|
44
|
-
|
45
|
-
# The Toolshed.socket_server method creates a permanent main server socket. Returns the server socket object.
|
46
|
-
def Toolshed.socket_server(port)
|
47
|
-
socket_server = UDPSocket.new
|
48
|
-
socket_server.bind(nil,port)
|
49
|
-
return socket_server
|
50
|
-
end
|
51
|
-
|
19
|
+
SOCKET_ROOT = '/tmp/abundance/'
|
20
|
+
Dir.mkdir(SOCKET_ROOT) unless File.exist?(SOCKET_ROOT)
|
21
|
+
|
52
22
|
# The Toolshed::block_size= method sets the UDP block size for socket operations.
|
53
23
|
def Toolshed::block_size=(block_size)
|
54
24
|
@@block_size = block_size
|
55
25
|
end
|
56
26
|
|
57
|
-
# The
|
58
|
-
def Toolshed::block_size
|
59
|
-
@@block_size
|
60
|
-
end
|
27
|
+
# The +assign_sockets+ method assign a value client and server variables
|
61
28
|
|
62
|
-
|
63
|
-
|
64
|
-
|
29
|
+
def set_my_socket_as_a(role,garden_pid=Process.pid)
|
30
|
+
case role
|
31
|
+
when :garden
|
32
|
+
set_my_socket
|
33
|
+
else
|
34
|
+
set_garden_path(garden_pid)
|
35
|
+
set_my_socket
|
36
|
+
end
|
65
37
|
end
|
66
38
|
|
67
|
-
|
68
|
-
|
69
|
-
@@garden_port
|
39
|
+
def my_socket_path
|
40
|
+
@my_socket_path
|
70
41
|
end
|
71
42
|
|
72
|
-
#
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
end
|
77
|
-
recv_block,address = block_filter { @socket_client_perm.recvfrom(@@block_size) }
|
78
|
-
return Marshal.load(recv_block)
|
43
|
+
#
|
44
|
+
|
45
|
+
def socket_send(command,data,server_socket_path=@garden_path)
|
46
|
+
send_block(command,data,server_socket_path)
|
79
47
|
end
|
80
48
|
|
81
|
-
def
|
82
|
-
|
83
|
-
|
84
|
-
end
|
49
|
+
def socket_duplex(command,data,server_socket_path=@garden_path)
|
50
|
+
send_block(command,data,server_socket_path)
|
51
|
+
Marshal.load(recv_whole_block)
|
85
52
|
end
|
53
|
+
|
54
|
+
def socket_recv
|
55
|
+
Marshal.load(recv_whole_block)
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
86
59
|
|
87
|
-
|
88
|
-
|
89
|
-
@socket_client_temp.connect(UDP_HOST,port)
|
90
|
-
block_splitter([command,data]) do |block|
|
91
|
-
@socket_client_temp.send(block,0)
|
92
|
-
end
|
60
|
+
def socket_path(pid)
|
61
|
+
File.catname(pid.to_s,SOCKET_ROOT)
|
93
62
|
end
|
94
63
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
command, data = Marshal.load(block)
|
100
|
-
return command, data, clientport, clientname, clientaddr
|
64
|
+
def set_my_socket
|
65
|
+
@my_socket_path = socket_path(Process.pid)
|
66
|
+
File.delete(@my_socket_path) if File.exist?(@my_socket_path)
|
67
|
+
@my_socket = UNIXServer.open(@my_socket_path)
|
101
68
|
end
|
102
69
|
|
103
|
-
|
104
|
-
|
105
|
-
block_splitter([command,data]) do |block|
|
106
|
-
@socket_server.send(block, 0, clientaddr, clientport)
|
107
|
-
end
|
70
|
+
def set_garden_path(garden_pid)
|
71
|
+
@garden_path = socket_path(garden_pid)
|
108
72
|
end
|
109
73
|
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
74
|
+
def recv_whole_block
|
75
|
+
begin
|
76
|
+
client = @my_socket.accept; block = []
|
77
|
+
catch :whole_block do
|
78
|
+
loop do
|
79
|
+
packet = client.recvfrom(@@block_size)[0]
|
80
|
+
if packet == ''
|
81
|
+
throw :whole_block
|
82
|
+
else
|
83
|
+
block << packet
|
84
|
+
end
|
85
|
+
end
|
120
86
|
end
|
121
|
-
|
122
|
-
|
87
|
+
return block.join
|
88
|
+
rescue Errno::EADDRINUSE
|
89
|
+
retry
|
123
90
|
end
|
124
91
|
end
|
125
92
|
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
elsif block_array[0] == :block_part
|
136
|
-
@@sessions[block_array[1]] = {} if @@sessions[block_array[1]].nil?
|
137
|
-
@@sessions[block_array[1]][:data] = [] if @@sessions[block_array[1]][:data].nil?
|
138
|
-
@@sessions[block_array[1]][:data][block_array[2]] = block_array[3]
|
139
|
-
else
|
140
|
-
return block,address
|
141
|
-
end
|
142
|
-
if ! @@sessions[block_array[1]].nil? && ! @@sessions[block_array[1]][:data].nil? && @@sessions[block_array[1]][:data].size == @@sessions[block_array[1]][:size]
|
143
|
-
block = @@sessions[block_array[1]][:data].join
|
144
|
-
address = @@sessions[block_array[1]][:address]
|
145
|
-
@@sessions[block_array[1]] = nil
|
146
|
-
return block,address
|
147
|
-
end
|
93
|
+
def send_block(command,data,server_socket_path)
|
94
|
+
begin
|
95
|
+
client = UNIXSocket.open(server_socket_path)
|
96
|
+
client.send(Marshal.dump([command,data,@my_socket_path]),0)
|
97
|
+
client.close
|
98
|
+
rescue Errno::EADDRINUSE
|
99
|
+
retry
|
100
|
+
rescue Errno::ECONNREFUSED
|
101
|
+
retry
|
148
102
|
end
|
149
103
|
end
|
150
|
-
|
104
|
+
|
151
105
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: abundance
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Louis-Philippe Perron
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-01-
|
12
|
+
date: 2009-01-11 00:00:00 -05:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|