coderunner 0.14.21 → 0.14.22
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION +1 -1
- data/coderunner.gemspec +5 -7
- data/lib/coderunner.rb +2 -1
- data/lib/coderunner/class_methods.rb +53 -0
- data/lib/coderunner/instance_methods.rb +19 -32
- data/lib/coderunner/run.rb +32 -0
- data/test/test_coderunner.rb +1 -0
- metadata +50 -78
- checksums.yaml +0 -7
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.14.
|
1
|
+
0.14.22
|
data/coderunner.gemspec
CHANGED
@@ -2,17 +2,14 @@
|
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
3
|
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
|
-
# stub: coderunner 0.14.21 ruby lib
|
6
|
-
# stub: ext/extconf.rb
|
7
5
|
|
8
6
|
Gem::Specification.new do |s|
|
9
7
|
s.name = "coderunner"
|
10
|
-
s.version = "0.14.
|
8
|
+
s.version = "0.14.22"
|
11
9
|
|
12
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
13
|
-
s.require_paths = ["lib"]
|
14
11
|
s.authors = ["Edmund Highcock"]
|
15
|
-
s.date = "2014-
|
12
|
+
s.date = "2014-08-12"
|
16
13
|
s.description = "CodeRunner is a framework for the automated running and analysis of simulations. It automatically generates any necessary input files, organises the output data and analyses it. Because it is a modular system, it can easily be customised to work with any system and any simulation code. One of its greatest strengths is that it is independent of any one simulation code; thus it can easily plot and compare the data from different codes."
|
17
14
|
s.email = "edmundhighcock@sourceforge.net"
|
18
15
|
s.executables = ["coderunner"]
|
@@ -92,13 +89,14 @@ Gem::Specification.new do |s|
|
|
92
89
|
]
|
93
90
|
s.homepage = "http://coderunner.sourceforge.net"
|
94
91
|
s.licenses = ["GPLv3"]
|
92
|
+
s.require_paths = ["lib"]
|
95
93
|
s.required_ruby_version = Gem::Requirement.new(">= 1.9.1")
|
96
94
|
s.rubyforge_project = "coderunner"
|
97
|
-
s.rubygems_version = "
|
95
|
+
s.rubygems_version = "1.8.11"
|
98
96
|
s.summary = "A framework for the automated running and analysis of simulations."
|
99
97
|
|
100
98
|
if s.respond_to? :specification_version then
|
101
|
-
s.specification_version =
|
99
|
+
s.specification_version = 3
|
102
100
|
|
103
101
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
104
102
|
s.add_runtime_dependency(%q<graphkit>, [">= 0.3.2"])
|
data/lib/coderunner.rb
CHANGED
@@ -231,7 +231,8 @@ EOF
|
|
231
231
|
["status_loop", "sl", 0, 'Loop, updating the filtered runs, then printing out a summary of the status of the filtered runs. ', [], [:U, :N, :j, :f, :O]],
|
232
232
|
["submit", "sub", 0, 'Submit a run to be simulated.', [], [:p, :n, :W, :k, :v, :T, :d, :J]],
|
233
233
|
["submit_command", "subcom", 2, 'Submit an arbitrary shell command to the batch queue.', ['job name', 'command'], [:n, :W, :v, :T, :d]],
|
234
|
-
["write_graph", "wg", 1, 'Write a graph to disk.', ['filename'], [:G, :g, :w, :O, :U, :N, :j, :f]]
|
234
|
+
["write_graph", "wg", 1, 'Write a graph to disk.', ['filename'], [:G, :g, :w, :O, :U, :N, :j, :f]],
|
235
|
+
["write_report", "wr", 0, 'Writes out a summary of a given run in a LaTeX document.', [], [:j, :f, :U, :N]],
|
235
236
|
]
|
236
237
|
|
237
238
|
# This lists all the commands available on the command line. The first two items in each array indicate the long and short form of the command, and the third indicates the number of arguments the command takes. They are all implemented as Code Runner class methods (the method is named after the long form). The short form of the command is available as a global method in Code Runner interactive mode.
|
@@ -78,6 +78,59 @@ class CodeRunner
|
|
78
78
|
runner.continue_in_new_folder(folder, options)
|
79
79
|
end
|
80
80
|
|
81
|
+
# This section defines the report report writing function in. The latex header is defined in run.rb. It is a run method and can be redefined in a particular CRMOD.
|
82
|
+
# The function is simply called as follows:
|
83
|
+
#
|
84
|
+
# interactively: wr j:<run no.>
|
85
|
+
# command line: coderunner write_report -j <run no>
|
86
|
+
#
|
87
|
+
# The requirements to use this function are:
|
88
|
+
#
|
89
|
+
# 1. pdflatex version 2014 or higher
|
90
|
+
# 2. gnuplot
|
91
|
+
# 3. ability to write eps graphs
|
92
|
+
#
|
93
|
+
# The graphs which are written out to the PDF are read in from a given CRMOD. It should be defined in the main .rb file for the CRMOD, e.g. gs2.rb.
|
94
|
+
# As seen below, this function should be called 'latex_graphs'. To see an example of what this function should look like see GS2CRMOD, but it is simply an array of graphkits
|
95
|
+
# and latex code blocks which describe plots.
|
96
|
+
def self.write_report(copts={})
|
97
|
+
runner = fetch_runner(copts)
|
98
|
+
runs = runner.filtered_ids.map{|id| runner.combined_run_list[id]}
|
99
|
+
|
100
|
+
#Loop through the runs and write a latex file for each
|
101
|
+
runs.each do |r|
|
102
|
+
Dir.chdir(runner.root_folder) do
|
103
|
+
FileUtils.makedirs("run_docs")
|
104
|
+
FileUtils.makedirs("run_docs/id_#{r.id}")
|
105
|
+
Dir.chdir("run_docs/id_#{r.id}") do
|
106
|
+
|
107
|
+
File.open("summary.tex", 'w') do |file|
|
108
|
+
file.puts r.latex_report_header
|
109
|
+
file.puts <<-EOF.gsub(/^ {14}/, "")
|
110
|
+
\\begin{itemize}
|
111
|
+
EOF
|
112
|
+
|
113
|
+
#Need to call some methods here which reads the graphs we want from gs2crmod, generates the graphs
|
114
|
+
#then generates the latex code to display graphs.
|
115
|
+
latex_code = r.latex_graphs.inject("") do |tmp_latex_code, (kit, latexstring)|
|
116
|
+
kit.gnuplot_write(kit.file_name) #write the graph
|
117
|
+
tmp_latex_code += "\\item " + latexstring + " \n\n\\newfig{#{kit.file_name}}"
|
118
|
+
tmp_latex_code += "\n\n"
|
119
|
+
tmp_latex_code
|
120
|
+
end
|
121
|
+
|
122
|
+
file.puts <<-EOF.gsub(/^ {14}/, "")
|
123
|
+
#{latex_code}
|
124
|
+
\\end{itemize}
|
125
|
+
\\end{document}
|
126
|
+
EOF
|
127
|
+
end #file write
|
128
|
+
system "pdflatex summary.tex"
|
129
|
+
end
|
130
|
+
end #chdir
|
131
|
+
end # run loop
|
132
|
+
end
|
133
|
+
|
81
134
|
def self.delete(copts={})
|
82
135
|
runner = fetch_runner(copts)
|
83
136
|
runner.destroy
|
@@ -1,6 +1,4 @@
|
|
1
1
|
|
2
|
-
# A comment
|
3
|
-
|
4
2
|
class CodeRunner # declare the constant
|
5
3
|
end
|
6
4
|
|
@@ -1166,6 +1164,7 @@ Conditions contain a single = sign: #{conditions}
|
|
1166
1164
|
# A hook... default is to do nothing
|
1167
1165
|
@submission_script = @run_class.modify_job_script(self, runs, @submission_script)
|
1168
1166
|
# To get out of job_chain_files folder
|
1167
|
+
p 'test'
|
1169
1168
|
@submission_script = "cd .. \n" + @submission_script
|
1170
1169
|
old_job_nos = queue_status.scan(/^\s*(\d+)/).map{|match| match[0].to_i}
|
1171
1170
|
################ Submit the run
|
@@ -1727,23 +1726,23 @@ EOF
|
|
1727
1726
|
unless FileTest.exist? temp_root + relative + archive_name
|
1728
1727
|
eputs "Archiving #{index} out of #{size}" if options[:verbose]
|
1729
1728
|
Dir.chdir(run.directory + '/..') do
|
1730
|
-
|
1731
|
-
|
1732
|
-
|
1733
|
-
|
1734
|
-
|
1735
|
-
|
1736
|
-
|
1737
|
-
|
1738
|
-
|
1739
|
-
|
1740
|
-
|
1741
|
-
|
1742
|
-
|
1743
|
-
|
1744
|
-
|
1745
|
-
|
1746
|
-
|
1729
|
+
command = "tar -cW#{very_verbose}f #{tar_name} #{File.basename(run.directory)}"
|
1730
|
+
eputs command if options[:verbose]
|
1731
|
+
unless system command
|
1732
|
+
raise "Archiving failed"
|
1733
|
+
end
|
1734
|
+
break unless comp
|
1735
|
+
command = "gzip -4 -vf #{tar_name}"
|
1736
|
+
eputs command if options[:verbose]
|
1737
|
+
unless system command
|
1738
|
+
raise "Compression failed"
|
1739
|
+
end
|
1740
|
+
command = "gzip -t #{archive_name}"
|
1741
|
+
eputs command if options[:verbose]
|
1742
|
+
unless system command
|
1743
|
+
raise "Compression failed"
|
1744
|
+
end
|
1745
|
+
#exit
|
1747
1746
|
end
|
1748
1747
|
FileUtils.mv(relative.delsubstr('/') + archive_name, temp_root + '/' + relative + archive_name)
|
1749
1748
|
end
|
@@ -1770,22 +1769,10 @@ EOF
|
|
1770
1769
|
#FileUtils.rm_r(".tmparch")
|
1771
1770
|
end
|
1772
1771
|
end
|
1773
|
-
|
1774
|
-
|
1775
|
-
|
1776
|
-
|
1777
|
-
|
1778
1772
|
end
|
1779
1773
|
|
1780
|
-
|
1781
|
-
|
1782
|
-
|
1783
|
-
|
1784
|
-
|
1785
|
-
|
1786
|
-
|
1787
1774
|
[
|
1788
|
-
|
1775
|
+
"/graphs_and_films.rb",
|
1789
1776
|
"/remote_code_runner.rb",
|
1790
1777
|
"/merged_code_runner.rb",
|
1791
1778
|
'/run.rb',
|
data/lib/coderunner/run.rb
CHANGED
@@ -1078,6 +1078,38 @@ def actual_number_of_processors
|
|
1078
1078
|
@nprocs.split('x').slice(0..1).map{|n| n.to_i}.inject(1){|ntot, n| ntot*n}
|
1079
1079
|
end
|
1080
1080
|
|
1081
|
+
def latex_report_header
|
1082
|
+
#gsub is a hack which removes 14 spaces from the beginning of the file. This allows nice code indentation here.
|
1083
|
+
<<-EOF.gsub(/^ {4}/, "")
|
1084
|
+
% Set up
|
1085
|
+
\\documentclass[11pt, twocolumn]{report}
|
1086
|
+
\\usepackage{amsmath}
|
1087
|
+
\\usepackage{amsthm}
|
1088
|
+
\\usepackage{amssymb}
|
1089
|
+
\\usepackage{graphicx}
|
1090
|
+
\\usepackage{caption}
|
1091
|
+
\\usepackage{subcaption}
|
1092
|
+
\\usepackage{wrapfig}
|
1093
|
+
\\usepackage{epstopdf}
|
1094
|
+
\\usepackage{fullpage}
|
1095
|
+
|
1096
|
+
\\newcommand{\\newfig}[1]{
|
1097
|
+
\\includegraphics[width=\\linewidth]{#1}
|
1098
|
+
}
|
1099
|
+
|
1100
|
+
\\begin{document}
|
1101
|
+
|
1102
|
+
% Title Page
|
1103
|
+
\\title{Run summary for run number #{id}}
|
1104
|
+
\\date{#{Time.now}}
|
1105
|
+
\\author{CodeRunner}
|
1106
|
+
|
1107
|
+
\\maketitle
|
1108
|
+
|
1109
|
+
EOF
|
1110
|
+
|
1111
|
+
end
|
1112
|
+
|
1081
1113
|
end
|
1082
1114
|
|
1083
1115
|
end
|
data/test/test_coderunner.rb
CHANGED
@@ -128,6 +128,7 @@ class TestCodeRunner < Test::Unit::TestCase
|
|
128
128
|
def test_remote_coderunner
|
129
129
|
puts 'testing remote coderunner'
|
130
130
|
rc = RemoteCodeRunner.new(ENV['USER'] + '@localhost', Dir.pwd + '/test/results', U: true, N: true).update
|
131
|
+
p rc
|
131
132
|
assert_equal(@runner.ids.sort, rc.ids.sort)
|
132
133
|
rc.print_out(0)
|
133
134
|
wdvh = rc.graphkit("width:height:depth:volume;;;height")
|
metadata
CHANGED
@@ -1,155 +1,126 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: coderunner
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.14.
|
4
|
+
version: 0.14.22
|
5
|
+
prerelease:
|
5
6
|
platform: ruby
|
6
7
|
authors:
|
7
8
|
- Edmund Highcock
|
8
9
|
autorequire:
|
9
10
|
bindir: bin
|
10
11
|
cert_chain: []
|
11
|
-
date: 2014-
|
12
|
+
date: 2014-08-12 00:00:00.000000000 Z
|
12
13
|
dependencies:
|
13
14
|
- !ruby/object:Gem::Dependency
|
14
15
|
name: graphkit
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirement: &18535160 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
16
18
|
requirements:
|
17
|
-
- -
|
19
|
+
- - ! '>='
|
18
20
|
- !ruby/object:Gem::Version
|
19
21
|
version: 0.3.2
|
20
22
|
type: :runtime
|
21
23
|
prerelease: false
|
22
|
-
version_requirements:
|
23
|
-
requirements:
|
24
|
-
- - ">="
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: 0.3.2
|
24
|
+
version_requirements: *18535160
|
27
25
|
- !ruby/object:Gem::Dependency
|
28
26
|
name: parallelpipes
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
27
|
+
requirement: &18550940 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
30
29
|
requirements:
|
31
|
-
- -
|
30
|
+
- - ! '>='
|
32
31
|
- !ruby/object:Gem::Version
|
33
32
|
version: 1.0.0
|
34
33
|
type: :runtime
|
35
34
|
prerelease: false
|
36
|
-
version_requirements:
|
37
|
-
requirements:
|
38
|
-
- - ">="
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: 1.0.0
|
35
|
+
version_requirements: *18550940
|
41
36
|
- !ruby/object:Gem::Dependency
|
42
37
|
name: rubyhacks
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
38
|
+
requirement: &18550140 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
44
40
|
requirements:
|
45
|
-
- -
|
41
|
+
- - ! '>='
|
46
42
|
- !ruby/object:Gem::Version
|
47
43
|
version: 0.1.4
|
48
44
|
type: :runtime
|
49
45
|
prerelease: false
|
50
|
-
version_requirements:
|
51
|
-
requirements:
|
52
|
-
- - ">="
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: 0.1.4
|
46
|
+
version_requirements: *18550140
|
55
47
|
- !ruby/object:Gem::Dependency
|
56
48
|
name: rb-gsl
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
49
|
+
requirement: &18549500 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
58
51
|
requirements:
|
59
|
-
- -
|
52
|
+
- - ! '>='
|
60
53
|
- !ruby/object:Gem::Version
|
61
54
|
version: 1.12.0
|
62
55
|
type: :runtime
|
63
56
|
prerelease: false
|
64
|
-
version_requirements:
|
65
|
-
requirements:
|
66
|
-
- - ">="
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: 1.12.0
|
57
|
+
version_requirements: *18549500
|
69
58
|
- !ruby/object:Gem::Dependency
|
70
59
|
name: gsl_extras
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
60
|
+
requirement: &18548880 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
72
62
|
requirements:
|
73
|
-
- -
|
63
|
+
- - ! '>='
|
74
64
|
- !ruby/object:Gem::Version
|
75
65
|
version: 0.3.0
|
76
66
|
type: :runtime
|
77
67
|
prerelease: false
|
78
|
-
version_requirements:
|
79
|
-
requirements:
|
80
|
-
- - ">="
|
81
|
-
- !ruby/object:Gem::Version
|
82
|
-
version: 0.3.0
|
68
|
+
version_requirements: *18548880
|
83
69
|
- !ruby/object:Gem::Dependency
|
84
70
|
name: hostmanager
|
85
|
-
requirement: !ruby/object:Gem::Requirement
|
71
|
+
requirement: &18547920 !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
86
73
|
requirements:
|
87
|
-
- -
|
74
|
+
- - ! '>'
|
88
75
|
- !ruby/object:Gem::Version
|
89
76
|
version: 0.1.0
|
90
77
|
type: :runtime
|
91
78
|
prerelease: false
|
92
|
-
version_requirements:
|
93
|
-
requirements:
|
94
|
-
- - ">"
|
95
|
-
- !ruby/object:Gem::Version
|
96
|
-
version: 0.1.0
|
79
|
+
version_requirements: *18547920
|
97
80
|
- !ruby/object:Gem::Dependency
|
98
81
|
name: shoulda
|
99
|
-
requirement: !ruby/object:Gem::Requirement
|
82
|
+
requirement: &18546220 !ruby/object:Gem::Requirement
|
83
|
+
none: false
|
100
84
|
requirements:
|
101
|
-
- -
|
85
|
+
- - ! '>='
|
102
86
|
- !ruby/object:Gem::Version
|
103
87
|
version: '0'
|
104
88
|
type: :development
|
105
89
|
prerelease: false
|
106
|
-
version_requirements:
|
107
|
-
requirements:
|
108
|
-
- - ">="
|
109
|
-
- !ruby/object:Gem::Version
|
110
|
-
version: '0'
|
90
|
+
version_requirements: *18546220
|
111
91
|
- !ruby/object:Gem::Dependency
|
112
92
|
name: rdoc
|
113
|
-
requirement: !ruby/object:Gem::Requirement
|
93
|
+
requirement: &18544440 !ruby/object:Gem::Requirement
|
94
|
+
none: false
|
114
95
|
requirements:
|
115
|
-
- -
|
96
|
+
- - ~>
|
116
97
|
- !ruby/object:Gem::Version
|
117
98
|
version: '3.12'
|
118
99
|
type: :development
|
119
100
|
prerelease: false
|
120
|
-
version_requirements:
|
121
|
-
requirements:
|
122
|
-
- - "~>"
|
123
|
-
- !ruby/object:Gem::Version
|
124
|
-
version: '3.12'
|
101
|
+
version_requirements: *18544440
|
125
102
|
- !ruby/object:Gem::Dependency
|
126
103
|
name: bundler
|
127
|
-
requirement: !ruby/object:Gem::Requirement
|
104
|
+
requirement: &18559040 !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
128
106
|
requirements:
|
129
|
-
- -
|
107
|
+
- - ! '>'
|
130
108
|
- !ruby/object:Gem::Version
|
131
109
|
version: 1.0.0
|
132
110
|
type: :development
|
133
111
|
prerelease: false
|
134
|
-
version_requirements:
|
135
|
-
requirements:
|
136
|
-
- - ">"
|
137
|
-
- !ruby/object:Gem::Version
|
138
|
-
version: 1.0.0
|
112
|
+
version_requirements: *18559040
|
139
113
|
- !ruby/object:Gem::Dependency
|
140
114
|
name: jeweler
|
141
|
-
requirement: !ruby/object:Gem::Requirement
|
115
|
+
requirement: &18557720 !ruby/object:Gem::Requirement
|
116
|
+
none: false
|
142
117
|
requirements:
|
143
|
-
- -
|
118
|
+
- - ! '>='
|
144
119
|
- !ruby/object:Gem::Version
|
145
120
|
version: 2.0.0
|
146
121
|
type: :development
|
147
122
|
prerelease: false
|
148
|
-
version_requirements:
|
149
|
-
requirements:
|
150
|
-
- - ">="
|
151
|
-
- !ruby/object:Gem::Version
|
152
|
-
version: 2.0.0
|
123
|
+
version_requirements: *18557720
|
153
124
|
description: CodeRunner is a framework for the automated running and analysis of simulations.
|
154
125
|
It automatically generates any necessary input files, organises the output data
|
155
126
|
and analyses it. Because it is a modular system, it can easily be customised to
|
@@ -166,7 +137,7 @@ extra_rdoc_files:
|
|
166
137
|
- README.md
|
167
138
|
- README.rdoc
|
168
139
|
files:
|
169
|
-
-
|
140
|
+
- .document
|
170
141
|
- Gemfile
|
171
142
|
- LICENSE.txt
|
172
143
|
- README.md
|
@@ -235,25 +206,26 @@ files:
|
|
235
206
|
homepage: http://coderunner.sourceforge.net
|
236
207
|
licenses:
|
237
208
|
- GPLv3
|
238
|
-
metadata: {}
|
239
209
|
post_install_message:
|
240
210
|
rdoc_options: []
|
241
211
|
require_paths:
|
242
212
|
- lib
|
243
213
|
required_ruby_version: !ruby/object:Gem::Requirement
|
214
|
+
none: false
|
244
215
|
requirements:
|
245
|
-
- -
|
216
|
+
- - ! '>='
|
246
217
|
- !ruby/object:Gem::Version
|
247
218
|
version: 1.9.1
|
248
219
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
220
|
+
none: false
|
249
221
|
requirements:
|
250
|
-
- -
|
222
|
+
- - ! '>='
|
251
223
|
- !ruby/object:Gem::Version
|
252
224
|
version: '0'
|
253
225
|
requirements: []
|
254
226
|
rubyforge_project: coderunner
|
255
|
-
rubygems_version:
|
227
|
+
rubygems_version: 1.8.11
|
256
228
|
signing_key:
|
257
|
-
specification_version:
|
229
|
+
specification_version: 3
|
258
230
|
summary: A framework for the automated running and analysis of simulations.
|
259
231
|
test_files: []
|
checksums.yaml
DELETED
@@ -1,7 +0,0 @@
|
|
1
|
-
---
|
2
|
-
SHA1:
|
3
|
-
metadata.gz: f31da7c1a3066436f1928a1e63927d1ae159c7c1
|
4
|
-
data.tar.gz: 2fbf034e17fffa91edb9f7e1b6cccb303d96d5b2
|
5
|
-
SHA512:
|
6
|
-
metadata.gz: c9210fef0749606da3dbe287e1b7ea262ae709be197eda71410b2a4f4e68c414ec1bca67c859f29b05fe302ae0634b743990ce29687e1b47d17f0730c147da37
|
7
|
-
data.tar.gz: 842086ee9b7c6e62d144bb68724b83797040bb3b6bb8a90c06102ce40baa48bb658e0c508526e79717c14f77fa52bea6da3cb02b9fb77751a74aa42a5ba1971c
|