miga-base 0.3.0.2 → 0.3.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/actions/{project_info.rb → about.rb} +3 -2
- data/actions/init.rb +9 -3
- data/bin/miga +54 -21
- data/lib/miga/daemon.rb +38 -1
- data/lib/miga/dataset_result.rb +4 -2
- data/lib/miga/project.rb +2 -0
- data/lib/miga/version.rb +2 -2
- data/scripts/ogs.bash +2 -1
- data/test/daemon_test.rb +18 -1
- data/test/taxonomy_test.rb +1 -0
- metadata +17 -17
- /data/actions/{create_dataset.rb → add.rb} +0 -0
- /data/actions/{list_files.rb → files.rb} +0 -0
- /data/actions/{find_datasets.rb → find.rb} +0 -0
- /data/actions/{download_dataset.rb → get.rb} +0 -0
- /data/actions/{import_datasets.rb → ln.rb} +0 -0
- /data/actions/{list_datasets.rb → ls.rb} +0 -0
- /data/actions/{create_project.rb → new.rb} +0 -0
- /data/actions/{unlink_dataset.rb → rm.rb} +0 -0
- /data/actions/{run_local.rb → run.rb} +0 -0
- /data/actions/{result_stats.rb → stats.rb} +0 -0
- /data/actions/{tax_distributions.rb → tax_dist.rb} +0 -0
- /data/actions/{index_taxonomy.rb → tax_index.rb} +0 -0
- /data/actions/{add_taxonomy.rb → tax_set.rb} +0 -0
- /data/actions/{test_taxonomy.rb → tax_test.rb} +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f402fe3633ac475e3c3d753d28131b78b5cab562
|
4
|
+
data.tar.gz: 5df9dd884c904d613ab34205da6f7d75f031237a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f6013b57eab9606b6b4130f92e06afb549b46392862e3b67c1ed5698d9a4c8eda8ca765047d4e548b49841723f6c67985a3635d28619fde85a5055fd481aa10b
|
7
|
+
data.tar.gz: bbe04db4291ca2c58cf22232b82740af5072f217bc66ac254a92d0783d74e26d762d4276dad80f9e8ca640d5d5f80b54c47b5d1ca5fa1ec4d85beb90ac057962
|
@@ -10,7 +10,7 @@ OptionParser.new do |opt|
|
|
10
10
|
opt.on("-p", "--processing",
|
11
11
|
"Print information on processing advance."){ |v| o[:processing]=v }
|
12
12
|
opt.on("-m", "--metadata STRING",
|
13
|
-
"Print name and metadata field only.
|
13
|
+
"Print name and metadata field only."
|
14
14
|
){ |v| o[:datum]=v }
|
15
15
|
opt_common(opt, o)
|
16
16
|
end.parse!
|
@@ -24,7 +24,8 @@ p = MiGA::Project.load(o[:project])
|
|
24
24
|
raise "Impossible to load project: #{o[:project]}" if p.nil?
|
25
25
|
|
26
26
|
if not o[:datum].nil?
|
27
|
-
|
27
|
+
v = p.metadata[ o[:datum] ]
|
28
|
+
puts v.nil? ? "?" : v
|
28
29
|
elsif o[:processing]
|
29
30
|
keys = MiGA::Project.DISTANCE_TASKS + MiGA::Project.INCLADE_TASKS
|
30
31
|
puts MiGA::MiGA.tabulate([:task, :status], keys.map do |k|
|
data/actions/init.rb
CHANGED
@@ -109,7 +109,7 @@ File.open(File.expand_path("utils/requirements.txt", miga), "r") do |fh|
|
|
109
109
|
loop do
|
110
110
|
d_path = File.dirname(`which "#{r[1]}"`)
|
111
111
|
if o[:ask] or d_path=="."
|
112
|
-
path = ask_user("Where can I find it?", d_path, nil, true)
|
112
|
+
path = ask_user("Where can I find it?", d_path, nil, true)
|
113
113
|
else
|
114
114
|
path = d_path
|
115
115
|
$stderr.puts path
|
@@ -205,11 +205,13 @@ case v[:type]
|
|
205
205
|
v[:var] = ask_user(
|
206
206
|
"How should I pass variables?\n %1$s: keys, %2$s: values.\n",
|
207
207
|
"%1$s=%2$s")
|
208
|
-
v[:
|
208
|
+
v[:varsep] = ask_user("What should I use to separate variables?", " ")
|
209
209
|
v[:alive] = ask_user(
|
210
210
|
"How can I know that a process is still alive?\n %1$s: PID, " +
|
211
211
|
"output should be 1 for running and 0 for non-running.\n",
|
212
212
|
"ps -p '%1$s'|tail -n+2|wc -l")
|
213
|
+
v[:kill] = ask_user(
|
214
|
+
"How should I terminate tasks?\n %s: process ID.", "kill -9 '%s'")
|
213
215
|
else # [qm]sub
|
214
216
|
queue = ask_user("What queue should I use?", nil, nil, true)
|
215
217
|
v[:latency] = ask_user("How long should I sleep? (in seconds)", "150").to_i
|
@@ -225,13 +227,15 @@ case v[:type]
|
|
225
227
|
v[:var] = ask_user(
|
226
228
|
"How should I pass variables?\n %1$s: keys, %2$s: values.\n",
|
227
229
|
"%1$s=%2$s")
|
228
|
-
v[:
|
230
|
+
v[:varsep] = ask_user("What should I use to separate variables?", ",")
|
229
231
|
if v[:type] == "qsub"
|
230
232
|
v[:alive] = ask_user(
|
231
233
|
"How can I know that a process is still alive?\n %1$s: job id, " +
|
232
234
|
"output should be 1 for running and 0 for non-running.\n",
|
233
235
|
"qstat -f '%1$s'|grep ' job_state ='|perl -pe 's/.*= //'|grep '[^C]'" +
|
234
236
|
"|tail -n1|wc -l|awk '{print $1}'")
|
237
|
+
v[:kill] = ask_user(
|
238
|
+
"How should I terminate tasks?\n %s: process ID.", "qdel '%s'")
|
235
239
|
else
|
236
240
|
v[:alive] = ask_user(
|
237
241
|
"How can I know that a process is still alive?\n %1$s: job id, " +
|
@@ -239,6 +243,8 @@ case v[:type]
|
|
239
243
|
"checkjob '%1$s'|grep '^State:'|perl -pe 's/.*: //'" +
|
240
244
|
"|grep 'Deferred\\|Hold\\|Idle\\|Starting\\|Running\\|Blocked'"+
|
241
245
|
"|tail -n1|wc -l|awk '{print $1}'")
|
246
|
+
v[:kill] = ask_user(
|
247
|
+
"How should I terminate tasks?\n %s: process ID.", "canceljob '%s'")
|
242
248
|
end
|
243
249
|
end
|
244
250
|
File.open(File.expand_path(".miga_daemon.json", ENV["HOME"]), "w") do |fh|
|
data/bin/miga
CHANGED
@@ -12,35 +12,65 @@ require "miga"
|
|
12
12
|
|
13
13
|
$task_desc = {
|
14
14
|
# Projects
|
15
|
-
|
16
|
-
|
15
|
+
new: "Creates an empty MiGA project.",
|
16
|
+
about: "Displays information about a MiGA project.",
|
17
17
|
plugins: "Lists or (un)installs plugins in a MiGA project.",
|
18
18
|
# Datasets
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
list_datasets: "Lists all registered datasets in an MiGA project.",
|
19
|
+
add: "Creates an empty dataset in a pre-existing MiGA project.",
|
20
|
+
get: "Creates an empty dataset in a pre-existing MiGA project.",
|
21
|
+
rm: "Removes a dataset from an MiGA project.",
|
22
|
+
find: "Finds unregistered datasets based on result files.",
|
23
|
+
ln: "Link datasets (including results) from one project to another.",
|
24
|
+
ls: "Lists all registered datasets in an MiGA project.",
|
26
25
|
# Results
|
27
26
|
add_result: "Registers a result.",
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
run_local: "Executes locally one step analysis producing the given result.",
|
27
|
+
stats: "Extracts statistics for the given result.",
|
28
|
+
files: "Lists all registered files from the results of a dataset or project.",
|
29
|
+
run: "Executes locally one step analysis producing the given result.",
|
32
30
|
# System
|
33
31
|
init: "Initialize MiGA to process new projects.",
|
34
32
|
daemon: "Controls the daemon of a MiGA project.",
|
35
33
|
date: "Returns the current date in standard MiGA format.",
|
36
|
-
console: "Opens an IRB console with MiGA
|
34
|
+
console: "Opens an IRB console with MiGA.",
|
37
35
|
# Taxonomy
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
36
|
+
tax_set: "Registers taxonomic information for datasets.",
|
37
|
+
tax_test: "Returns test of taxonomic distributions for query datasets.",
|
38
|
+
tax_index: "Creates a taxonomy-indexed list of the datasets.",
|
39
|
+
tax_dist: "Estimates distributions of distance by taxonomy.",
|
42
40
|
}
|
43
41
|
|
42
|
+
$task_alias = {
|
43
|
+
# Projects
|
44
|
+
create_project: :new,
|
45
|
+
project_info: :about,
|
46
|
+
# Datasets
|
47
|
+
create_dataset: :add,
|
48
|
+
download_dataset: :get,
|
49
|
+
unlink_dataset: :rm,
|
50
|
+
find_datasets: :find,
|
51
|
+
import_datasets: :ln,
|
52
|
+
list_datasets: :ls,
|
53
|
+
# Results
|
54
|
+
result_stats: :stats,
|
55
|
+
list_files: :files,
|
56
|
+
run_local: :run,
|
57
|
+
# System
|
58
|
+
c: :console,
|
59
|
+
# Taxonomy
|
60
|
+
add_taxonomy: :tax_set,
|
61
|
+
test_taxonomy: :tax_test,
|
62
|
+
index_taxonomy: :tax_index,
|
63
|
+
tax_distributions: :tax_dist,
|
64
|
+
}
|
65
|
+
|
66
|
+
$task_alias.each do |nick, task|
|
67
|
+
$task_desc[task] = (
|
68
|
+
($task_desc[task] =~ /\(alias: .*\)\./) ?
|
69
|
+
$task_desc[task].sub(/\)\.$/, ", #{nick}).") :
|
70
|
+
$task_desc[task].sub(/\.$/, " (alias: #{nick}).")
|
71
|
+
)
|
72
|
+
end
|
73
|
+
|
44
74
|
##=> Functions <=
|
45
75
|
|
46
76
|
# OptParse banner
|
@@ -142,7 +172,7 @@ def add_metadata(o, obj)
|
|
142
172
|
when "nil"; v = nil
|
143
173
|
end
|
144
174
|
obj.metadata[k] = v
|
145
|
-
end
|
175
|
+
end unless o[:metadata].nil?
|
146
176
|
[:type, :name, :user, :description, :comments].each do |k|
|
147
177
|
obj.metadata[k] = o[k] unless o[k].nil?
|
148
178
|
end
|
@@ -153,14 +183,17 @@ end
|
|
153
183
|
|
154
184
|
execs = $task_desc.keys.map{ |k| k.to_s }
|
155
185
|
|
156
|
-
|
186
|
+
ARGV[0] = $task_alias[ARGV[0].to_sym] unless
|
187
|
+
ARGV[0].nil? or $task_alias[ARGV[0].to_sym].nil?
|
188
|
+
|
189
|
+
case ARGV[0].to_s
|
157
190
|
when "-v", "--version"
|
158
191
|
puts MiGA::MiGA.VERSION
|
159
192
|
when "-V", "--long-version"
|
160
193
|
puts MiGA::MiGA.LONG_VERSION
|
161
194
|
when "-C", "--citation"
|
162
195
|
puts MiGA::MiGA.CITATION
|
163
|
-
when "console"
|
196
|
+
when "console"
|
164
197
|
require "irb"
|
165
198
|
require "irb/completion"
|
166
199
|
ARGV.shift
|
data/lib/miga/daemon.rb
CHANGED
@@ -17,6 +17,10 @@ class MiGA::Daemon < MiGA::MiGA
|
|
17
17
|
return nil unless File.exist? f
|
18
18
|
DateTime.parse(File.read(f))
|
19
19
|
end
|
20
|
+
|
21
|
+
# Shutdown all spawned daemons before exit.
|
22
|
+
$_MIGA_DAEMON_LAIR = []
|
23
|
+
END { $_MIGA_DAEMON_LAIR.each{ |d| d.terminate } }
|
20
24
|
|
21
25
|
# MiGA::Project in which the daemon is running.
|
22
26
|
attr_reader :project
|
@@ -33,6 +37,7 @@ class MiGA::Daemon < MiGA::MiGA
|
|
33
37
|
# Initialize an unactive daemon for the MiGA::Project +project+. See #daemon
|
34
38
|
# to wake the daemon.
|
35
39
|
def initialize(project)
|
40
|
+
$_MIGA_DAEMON_LAIR << self
|
36
41
|
@project = project
|
37
42
|
@runopts = JSON.parse(
|
38
43
|
File.read(File.expand_path("daemon/daemon.json", project.path)),
|
@@ -68,6 +73,13 @@ class MiGA::Daemon < MiGA::MiGA
|
|
68
73
|
raise "Daemon's #{k} cannot be set to zero." if !force and v==0
|
69
74
|
@runopts[k] = v
|
70
75
|
end
|
76
|
+
if k==:kill and v.nil?
|
77
|
+
case @runopts[:type].to_s
|
78
|
+
when "bash" ; return "kill -9 '%s'"
|
79
|
+
when "qsub" ; return "qdel '%s'"
|
80
|
+
else ; return "canceljob '%s'"
|
81
|
+
end
|
82
|
+
end
|
71
83
|
@runopts[k]
|
72
84
|
end
|
73
85
|
|
@@ -117,13 +129,22 @@ class MiGA::Daemon < MiGA::MiGA
|
|
117
129
|
end
|
118
130
|
|
119
131
|
##
|
120
|
-
# Tell the world that you're alive
|
132
|
+
# Tell the world that you're alive.
|
121
133
|
def declare_alive
|
122
134
|
f = File.open(File.expand_path("daemon/alive", project.path), "w")
|
123
135
|
f.print Time.now.to_s
|
124
136
|
f.close
|
125
137
|
end
|
126
138
|
|
139
|
+
##
|
140
|
+
# Report status in a JSON file.
|
141
|
+
def report_status
|
142
|
+
f = File.open(File.expand_path("daemon/status.json", project.path), "w")
|
143
|
+
f.print JSON.pretty_generate(
|
144
|
+
jobs_running:@jobs_running, jobs_to_run:@jobs_to_run)
|
145
|
+
f.close
|
146
|
+
end
|
147
|
+
|
127
148
|
##
|
128
149
|
# Traverse datasets
|
129
150
|
def check_datasets
|
@@ -240,8 +261,10 @@ class MiGA::Daemon < MiGA::MiGA
|
|
240
261
|
@loop_i = 0
|
241
262
|
purge!
|
242
263
|
end
|
264
|
+
report_status
|
243
265
|
sleep(latency)
|
244
266
|
if shutdown_when_done? and jobs_running.size+jobs_to_run.size == 0
|
267
|
+
say "Nothing else to do, shutting down."
|
245
268
|
return false
|
246
269
|
end
|
247
270
|
true
|
@@ -253,6 +276,20 @@ class MiGA::Daemon < MiGA::MiGA
|
|
253
276
|
print "[#{Time.new.inspect}] ", *opts, "\n"
|
254
277
|
end
|
255
278
|
|
279
|
+
##
|
280
|
+
# Terminates a daemon.
|
281
|
+
def terminate
|
282
|
+
say "Terminating daemon..."
|
283
|
+
report_status
|
284
|
+
k = runopts(:kill)
|
285
|
+
@jobs_running.each do |i|
|
286
|
+
`#{k % i[:pid]}`
|
287
|
+
puts "Terminating pid:#{i[:pid]} for #{i[:task_name]}"
|
288
|
+
end
|
289
|
+
f = File.expand_path("daemon/alive", project.path)
|
290
|
+
File.unlink(f) if File.exist? f
|
291
|
+
end
|
292
|
+
|
256
293
|
private
|
257
294
|
|
258
295
|
def launch_job(job)
|
data/lib/miga/dataset_result.rb
CHANGED
@@ -44,9 +44,11 @@ module MiGA::DatasetResult
|
|
44
44
|
r = MiGA::Result.new("#{base}.json")
|
45
45
|
if result_files_exist?(base, ".2.clipped.fastq")
|
46
46
|
r = add_files_to_ds_result(r, name,
|
47
|
-
pair1:".1.clipped.fastq", pair2:".2.clipped.fastq"
|
47
|
+
pair1:".1.clipped.fastq", pair2:".2.clipped.fastq",
|
48
|
+
single:".1.clipped.single.fastq")
|
49
|
+
else
|
50
|
+
r = add_files_to_ds_result(r, name, single:".1.clipped.fastq")
|
48
51
|
end
|
49
|
-
r.add_file(:single, "#{name}.1.clipped.single.fastq")
|
50
52
|
r.add_file(:trimming_sumary, "#{name}.1.fastq.trimmed.summary.txt")
|
51
53
|
add_result(:raw_reads) #-> Post gunzip
|
52
54
|
r
|
data/lib/miga/project.rb
CHANGED
@@ -380,6 +380,8 @@ class MiGA::Project < MiGA::MiGA
|
|
380
380
|
# List plugins installed in the project.
|
381
381
|
def plugins ; metadata[:plugins] ||= [] ; end
|
382
382
|
|
383
|
+
##
|
384
|
+
# Loads the plugins installed in the project.
|
383
385
|
def load_plugins
|
384
386
|
plugins.each { |pl| require File.expand_path("lib-plugin.rb", pl) }
|
385
387
|
end
|
data/lib/miga/version.rb
CHANGED
@@ -10,7 +10,7 @@ module MiGA
|
|
10
10
|
# - Float representing the major.minor version.
|
11
11
|
# - Integer representing gem releases of the current version.
|
12
12
|
# - Integer representing minor changes that require new version number.
|
13
|
-
VERSION = [0.3, 0,
|
13
|
+
VERSION = [0.3, 0, 5]
|
14
14
|
|
15
15
|
##
|
16
16
|
# Nickname for the current major.minor version.
|
@@ -18,7 +18,7 @@ module MiGA
|
|
18
18
|
|
19
19
|
##
|
20
20
|
# Date of the current gem release.
|
21
|
-
VERSION_DATE = Date.new(2017,
|
21
|
+
VERSION_DATE = Date.new(2017, 7, 8)
|
22
22
|
|
23
23
|
##
|
24
24
|
# Reference of MiGA.
|
data/scripts/ogs.bash
CHANGED
@@ -31,7 +31,8 @@ if [[ ! -s miga-project.ogs ]] ; then
|
|
31
31
|
|
32
32
|
# Estimate OGs and Clean RBMs
|
33
33
|
ogs.mcl.rb -o miga-project.ogs -d miga-project.rbm -t "$CORES"
|
34
|
-
|
34
|
+
[[ $(miga about -P "$PROJECT" -m clean_ogs) == "false" ]] \
|
35
|
+
|| rm -rf miga-project.rbm
|
35
36
|
fi
|
36
37
|
|
37
38
|
# Calculate Statistics
|
data/test/daemon_test.rb
CHANGED
@@ -10,7 +10,7 @@ class DaemonTest < Test::Unit::TestCase
|
|
10
10
|
FileUtils.touch("#{ENV["MIGA_HOME"]}/.miga_rc")
|
11
11
|
File.open("#{ENV["MIGA_HOME"]}/.miga_daemon.json", "w") do |fh|
|
12
12
|
fh.puts '{"maxjobs":1,"ppn":1,"latency":2,"varsep":" ","var":"%s=%s",
|
13
|
-
"cmd":"%5$s","alive":"echo 1 # %s"}'
|
13
|
+
"cmd":"%5$s","alive":"echo 1 # %s","type":"bash"}'
|
14
14
|
end
|
15
15
|
$p1 = MiGA::Project.new(File.expand_path("project1", $tmp))
|
16
16
|
$d1 = MiGA::Daemon.new($p1)
|
@@ -113,6 +113,12 @@ class DaemonTest < Test::Unit::TestCase
|
|
113
113
|
assert_raise do
|
114
114
|
$d1.runopts(:latency, "!")
|
115
115
|
end
|
116
|
+
assert_equal("bash", $d1.runopts(:type))
|
117
|
+
assert_equal("kill -9 '%s'", $d1.runopts(:kill))
|
118
|
+
$d1.runopts(:type, "qsub")
|
119
|
+
assert_equal("qdel '%s'", $d1.runopts(:kill))
|
120
|
+
$d1.runopts(:type, "msub")
|
121
|
+
assert_equal("canceljob '%s'", $d1.runopts(:kill))
|
116
122
|
end
|
117
123
|
|
118
124
|
def test_say
|
@@ -122,4 +128,15 @@ class DaemonTest < Test::Unit::TestCase
|
|
122
128
|
assert(out.string =~ /^\[.*\] Olm/)
|
123
129
|
end
|
124
130
|
|
131
|
+
def test_terminate
|
132
|
+
d = $d1
|
133
|
+
d.declare_alive
|
134
|
+
assert_not_nil(d.last_alive)
|
135
|
+
out = capture_stdout do
|
136
|
+
d.terminate
|
137
|
+
end
|
138
|
+
assert(out.string =~ /Terminating daemon/)
|
139
|
+
assert_nil(d.last_alive)
|
140
|
+
end
|
141
|
+
|
125
142
|
end
|
data/test/taxonomy_test.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: miga-base
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.0.
|
4
|
+
version: 0.3.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Luis M. Rodriguez-R
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-07-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rest-client
|
@@ -407,26 +407,26 @@ files:
|
|
407
407
|
- utils/subclades-nj.R
|
408
408
|
- utils/subclades.R
|
409
409
|
- bin/miga
|
410
|
+
- actions/about.rb
|
411
|
+
- actions/add.rb
|
410
412
|
- actions/add_result.rb
|
411
|
-
- actions/add_taxonomy.rb
|
412
|
-
- actions/create_dataset.rb
|
413
|
-
- actions/create_project.rb
|
414
413
|
- actions/daemon.rb
|
415
414
|
- actions/date.rb
|
416
|
-
- actions/
|
417
|
-
- actions/
|
418
|
-
- actions/
|
419
|
-
- actions/index_taxonomy.rb
|
415
|
+
- actions/files.rb
|
416
|
+
- actions/find.rb
|
417
|
+
- actions/get.rb
|
420
418
|
- actions/init.rb
|
421
|
-
- actions/
|
422
|
-
- actions/
|
419
|
+
- actions/ln.rb
|
420
|
+
- actions/ls.rb
|
421
|
+
- actions/new.rb
|
423
422
|
- actions/plugins.rb
|
424
|
-
- actions/
|
425
|
-
- actions/
|
426
|
-
- actions/
|
427
|
-
- actions/
|
428
|
-
- actions/
|
429
|
-
- actions/
|
423
|
+
- actions/rm.rb
|
424
|
+
- actions/run.rb
|
425
|
+
- actions/stats.rb
|
426
|
+
- actions/tax_dist.rb
|
427
|
+
- actions/tax_index.rb
|
428
|
+
- actions/tax_set.rb
|
429
|
+
- actions/tax_test.rb
|
430
430
|
- Gemfile
|
431
431
|
- Rakefile
|
432
432
|
- README.md
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|