openstudio-workflow 1.3.4 → 1.3.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +89 -77
  3. data/README.md +67 -93
  4. data/Rakefile +36 -36
  5. data/lib/openstudio-workflow.rb +65 -65
  6. data/lib/openstudio/workflow/adapters/input/local.rb +311 -324
  7. data/lib/openstudio/workflow/adapters/output/local.rb +158 -161
  8. data/lib/openstudio/workflow/adapters/output/socket.rb +106 -107
  9. data/lib/openstudio/workflow/adapters/output/web.rb +82 -82
  10. data/lib/openstudio/workflow/adapters/output_adapter.rb +163 -163
  11. data/lib/openstudio/workflow/job.rb +57 -57
  12. data/lib/openstudio/workflow/jobs/resources/monthly_report.idf +222 -222
  13. data/lib/openstudio/workflow/jobs/run_energyplus.rb +70 -70
  14. data/lib/openstudio/workflow/jobs/run_ep_measures.rb +73 -73
  15. data/lib/openstudio/workflow/jobs/run_initialization.rb +203 -203
  16. data/lib/openstudio/workflow/jobs/run_os_measures.rb +89 -89
  17. data/lib/openstudio/workflow/jobs/run_postprocess.rb +73 -73
  18. data/lib/openstudio/workflow/jobs/run_preprocess.rb +104 -104
  19. data/lib/openstudio/workflow/jobs/run_reporting_measures.rb +118 -118
  20. data/lib/openstudio/workflow/jobs/run_translation.rb +84 -84
  21. data/lib/openstudio/workflow/multi_delegator.rb +62 -62
  22. data/lib/openstudio/workflow/registry.rb +172 -172
  23. data/lib/openstudio/workflow/run.rb +342 -328
  24. data/lib/openstudio/workflow/time_logger.rb +96 -96
  25. data/lib/openstudio/workflow/util.rb +49 -49
  26. data/lib/openstudio/workflow/util/energyplus.rb +575 -605
  27. data/lib/openstudio/workflow/util/io.rb +68 -68
  28. data/lib/openstudio/workflow/util/measure.rb +658 -650
  29. data/lib/openstudio/workflow/util/model.rb +151 -151
  30. data/lib/openstudio/workflow/util/post_process.rb +235 -238
  31. data/lib/openstudio/workflow/util/weather_file.rb +143 -143
  32. data/lib/openstudio/workflow/version.rb +40 -40
  33. data/lib/openstudio/workflow_json.rb +475 -476
  34. data/lib/openstudio/workflow_runner.rb +263 -268
  35. metadata +24 -24
@@ -1,324 +1,311 @@
1
- # *******************************************************************************
2
- # OpenStudio(R), Copyright (c) 2008-2018, Alliance for Sustainable Energy, LLC.
3
- # All rights reserved.
4
- # Redistribution and use in source and binary forms, with or without
5
- # modification, are permitted provided that the following conditions are met:
6
- #
7
- # (1) Redistributions of source code must retain the above copyright notice,
8
- # this list of conditions and the following disclaimer.
9
- #
10
- # (2) Redistributions in binary form must reproduce the above copyright notice,
11
- # this list of conditions and the following disclaimer in the documentation
12
- # and/or other materials provided with the distribution.
13
- #
14
- # (3) Neither the name of the copyright holder nor the names of any contributors
15
- # may be used to endorse or promote products derived from this software without
16
- # specific prior written permission from the respective party.
17
- #
18
- # (4) Other than as required in clauses (1) and (2), distributions in any form
19
- # of modifications or other derivative works may not use the "OpenStudio"
20
- # trademark, "OS", "os", or any other confusingly similar designation without
21
- # specific prior written permission from Alliance for Sustainable Energy, LLC.
22
- #
23
- # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24
- # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25
- # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26
- # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER, THE UNITED STATES
27
- # GOVERNMENT, OR ANY CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28
- # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29
- # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30
- # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31
- # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32
- # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
33
- # EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34
- # *******************************************************************************
35
-
36
- require 'openstudio/workflow_json'
37
-
38
- # Local file based workflow
39
- module OpenStudio
40
- module Workflow
41
- module InputAdapter
42
- class Local
43
- def initialize(osw_path = './workflow.osw')
44
- @osw_abs_path = File.absolute_path(osw_path, Dir.pwd)
45
-
46
- @workflow = nil
47
- if File.exist? @osw_abs_path
48
- @workflow = ::JSON.parse(File.read(@osw_abs_path), symbolize_names: true)
49
- end
50
-
51
- begin
52
- # configure the OSW with paths for loaded extension gems
53
- # Bundler.require is called in the CLI to load extension gems
54
- @workflow = OpenStudio::Extension::configure_osw(@workflow)
55
- rescue NameError => e
56
- end
57
-
58
- @workflow_json = nil
59
- @run_options = nil
60
- if @workflow
61
- begin
62
- # Create a temporary WorkflowJSON, will not be same one used in registry during simulation
63
- @workflow_json = OpenStudio::WorkflowJSON.new(JSON.fast_generate(workflow))
64
- @workflow_json.setOswDir(osw_dir)
65
- rescue NameError => e
66
- @workflow_json = WorkflowJSON_Shim.new(workflow, osw_dir)
67
- end
68
-
69
- begin
70
- @run_options = @workflow_json.runOptions
71
- rescue
72
- end
73
- end
74
- end
75
-
76
- # Get the OSW file from the local filesystem
77
- #
78
- def workflow
79
- raise "Could not read workflow from #{@osw_abs_path}" if @workflow.nil?
80
- @workflow
81
- end
82
-
83
- # Get the OSW path
84
- #
85
- def osw_path
86
- @osw_abs_path
87
- end
88
-
89
- # Get the OSW dir
90
- #
91
- def osw_dir
92
- File.dirname(@osw_abs_path)
93
- end
94
-
95
- # Get the run dir
96
- #
97
- def run_dir
98
- result = File.join(osw_dir, 'run')
99
- if @workflow_json
100
- begin
101
- result = @workflow_json.absoluteRunDir.to_s
102
- rescue
103
- end
104
- end
105
- result
106
- end
107
-
108
- def output_adapter(user_options, default, logger)
109
-
110
- # user option trumps all others
111
- return user_options[:output_adapter] if user_options[:output_adapter]
112
-
113
- # try to read from OSW
114
- if @run_options && !@run_options.empty?
115
- custom_adapter = @run_options.get.customOutputAdapter
116
- if !custom_adapter.empty?
117
- begin
118
- custom_file_name = custom_adapter.get.customFileName
119
- class_name = custom_adapter.get.className
120
- options = ::JSON.parse(custom_adapter.get.options, :symbolize_names => true)
121
-
122
- # merge with user options, user options will replace options loaded from OSW
123
- options.merge!(user_options)
124
-
125
- # stick output_directory in options
126
- options[:output_directory] = run_dir
127
-
128
- p = @workflow_json.findFile(custom_file_name)
129
- if !p.empty?
130
- load(p.get.to_s)
131
- output_adapter = eval("#{class_name}.new(options)")
132
- return output_adapter
133
- else
134
- log_message = "Failed to load custom adapter file '#{custom_file_name}'"
135
- logger.error log_message
136
- raise log_message
137
- end
138
- rescue
139
- log_message = "Failed to load custom adapter '#{class_name}' from file '#{custom_file_name}'"
140
- logger.error log_message
141
- raise log_message
142
- end
143
- end
144
- end
145
-
146
- return default
147
- end
148
-
149
- def jobs(user_options, default, logger)
150
-
151
- # user option trumps all others
152
- return user_options[:jobs] if user_options[:jobs]
153
-
154
- # try to read from OSW
155
- begin
156
- #log_message = "Reading custom job states from OSW is not currently supported'"
157
- #logger.info log_message
158
- rescue
159
- end
160
-
161
- return default
162
- end
163
-
164
- def debug(user_options, default)
165
-
166
- # user option trumps all others
167
- return user_options[:debug] if user_options[:debug]
168
-
169
- # try to read from OSW
170
- if @run_options && !@run_options.empty?
171
- return @run_options.get.debug
172
- end
173
-
174
- return default
175
- end
176
-
177
- def fast(user_options, default)
178
-
179
- # user option trumps all others
180
- return user_options[:fast] if user_options[:fast]
181
-
182
- # try to read from OSW
183
- if @run_options && !@run_options.empty?
184
- if @run_options.get.respond_to?(:fast)
185
- return @run_options.get.fast
186
- else
187
- if @workflow[:run_options]
188
- return @workflow[:run_options][:fast]
189
- end
190
- end
191
- end
192
-
193
- return default
194
- end
195
-
196
- def preserve_run_dir(user_options, default)
197
-
198
- # user option trumps all others
199
- return user_options[:preserve_run_dir] if user_options[:preserve_run_dir]
200
-
201
- # try to read from OSW
202
- if @run_options && !@run_options.empty?
203
- return @run_options.get.preserveRunDir
204
- end
205
-
206
- return default
207
- end
208
-
209
- def skip_expand_objects(user_options, default)
210
-
211
- # user option trumps all others
212
- return user_options[:skip_expand_objects] if user_options[:skip_expand_objects]
213
-
214
- # try to read from OSW
215
- if @run_options && !@run_options.empty?
216
- if @run_options.get.respond_to?(:skipExpandObjects)
217
- return @run_options.get.skipExpandObjects
218
- else
219
- if @workflow[:run_options]
220
- return @workflow[:run_options][:skip_expand_objects]
221
- end
222
- end
223
- end
224
-
225
- return default
226
- end
227
-
228
- def skip_energyplus_preprocess(user_options, default)
229
-
230
- # user option trumps all others
231
- return user_options[:skip_energyplus_preprocess] if user_options[:skip_energyplus_preprocess]
232
-
233
- # try to read from OSW
234
- if @run_options && !@run_options.empty?
235
- if @run_options.get.respond_to?(:skipEnergyPlusPreprocess)
236
- return @run_options.get.skipEnergyPlusPreprocess
237
- else
238
- if @workflow[:run_options]
239
- return @workflow[:run_options][:skip_energyplus_preprocess]
240
- end
241
- end
242
- end
243
-
244
- return default
245
- end
246
-
247
- def cleanup(user_options, default)
248
-
249
- # user option trumps all others
250
- return user_options[:cleanup] if user_options[:cleanup]
251
-
252
- # try to read from OSW
253
- if @run_options && !@run_options.empty?
254
- return @run_options.get.cleanup
255
- end
256
-
257
- return default
258
- end
259
-
260
- def energyplus_path(user_options, default)
261
-
262
- # user option trumps all others
263
- return user_options[:energyplus_path] if user_options[:energyplus_path]
264
-
265
- return default
266
- end
267
-
268
- def profile(user_options, default)
269
-
270
- # user option trumps all others
271
- return user_options[:profile] if user_options[:profile]
272
-
273
- return default
274
- end
275
-
276
- def verify_osw(user_options, default)
277
-
278
- # user option trumps all others
279
- return user_options[:verify_osw] if user_options[:verify_osw]
280
-
281
- return default
282
- end
283
-
284
- def weather_file(user_options, default)
285
-
286
- # user option trumps all others
287
- return user_options[:weather_file] if user_options[:weather_file]
288
-
289
- # try to read from OSW
290
- if !@workflow_json.weatherFile.empty?
291
- return @workflow_json.weatherFile.get.to_s
292
- end
293
-
294
- return default
295
- end
296
-
297
- # Get the associated OSD (datapoint) file from the local filesystem
298
- #
299
- def datapoint
300
- # DLM: should this come from the OSW? the osd id and checksum are specified there.
301
- osd_abs_path = File.join(osw_dir, 'datapoint.osd')
302
- result = nil
303
- if File.exist? osd_abs_path
304
- result = ::JSON.parse(File.read(osd_abs_path), symbolize_names: true)
305
- end
306
- return result
307
- end
308
-
309
- # Get the associated OSA (analysis) definition from the local filesystem
310
- #
311
- def analysis
312
- # DLM: should this come from the OSW? the osd id and checksum are specified there.
313
- osa_abs_path = File.join(osw_dir, '../analysis.json')
314
- result = nil
315
- if File.exist? osa_abs_path
316
- result = ::JSON.parse(File.read(osa_abs_path), symbolize_names: true)
317
- end
318
- return result
319
- end
320
-
321
- end
322
- end
323
- end
324
- end
1
+ # *******************************************************************************
2
+ # OpenStudio(R), Copyright (c) 2008-2020, Alliance for Sustainable Energy, LLC.
3
+ # All rights reserved.
4
+ # Redistribution and use in source and binary forms, with or without
5
+ # modification, are permitted provided that the following conditions are met:
6
+ #
7
+ # (1) Redistributions of source code must retain the above copyright notice,
8
+ # this list of conditions and the following disclaimer.
9
+ #
10
+ # (2) Redistributions in binary form must reproduce the above copyright notice,
11
+ # this list of conditions and the following disclaimer in the documentation
12
+ # and/or other materials provided with the distribution.
13
+ #
14
+ # (3) Neither the name of the copyright holder nor the names of any contributors
15
+ # may be used to endorse or promote products derived from this software without
16
+ # specific prior written permission from the respective party.
17
+ #
18
+ # (4) Other than as required in clauses (1) and (2), distributions in any form
19
+ # of modifications or other derivative works may not use the "OpenStudio"
20
+ # trademark, "OS", "os", or any other confusingly similar designation without
21
+ # specific prior written permission from Alliance for Sustainable Energy, LLC.
22
+ #
23
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER, THE UNITED STATES
27
+ # GOVERNMENT, OR ANY CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28
+ # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29
+ # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30
+ # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31
+ # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32
+ # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
33
+ # EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34
+ # *******************************************************************************
35
+
36
+ require 'openstudio/workflow_json'
37
+
38
+ # Local file based workflow
39
+ module OpenStudio
40
+ module Workflow
41
+ module InputAdapter
42
+ class Local
43
+ def initialize(osw_path = './workflow.osw')
44
+ @osw_abs_path = File.absolute_path(osw_path, Dir.pwd)
45
+
46
+ @workflow = nil
47
+ if File.exist? @osw_abs_path
48
+ @workflow = ::JSON.parse(File.read(@osw_abs_path), symbolize_names: true)
49
+ end
50
+
51
+ begin
52
+ # configure the OSW with paths for loaded extension gems
53
+ # Bundler.require is called in the CLI to load extension gems
54
+ @workflow = OpenStudio::Extension.configure_osw(@workflow)
55
+ rescue NameError => e
56
+ end
57
+
58
+ @workflow_json = nil
59
+ @run_options = nil
60
+ if @workflow
61
+ begin
62
+ # Create a temporary WorkflowJSON, will not be same one used in registry during simulation
63
+ @workflow_json = OpenStudio::WorkflowJSON.new(JSON.fast_generate(workflow))
64
+ @workflow_json.setOswDir(osw_dir)
65
+ rescue NameError => e
66
+ @workflow_json = WorkflowJSON_Shim.new(workflow, osw_dir)
67
+ end
68
+
69
+ begin
70
+ @run_options = @workflow_json.runOptions
71
+ rescue StandardError
72
+ end
73
+ end
74
+ end
75
+
76
+ # Get the OSW file from the local filesystem
77
+ #
78
+ def workflow
79
+ raise "Could not read workflow from #{@osw_abs_path}" if @workflow.nil?
80
+ @workflow
81
+ end
82
+
83
+ # Get the OSW path
84
+ #
85
+ def osw_path
86
+ @osw_abs_path
87
+ end
88
+
89
+ # Get the OSW dir
90
+ #
91
+ def osw_dir
92
+ File.dirname(@osw_abs_path)
93
+ end
94
+
95
+ # Get the run dir
96
+ #
97
+ def run_dir
98
+ result = File.join(osw_dir, 'run')
99
+ if @workflow_json
100
+ begin
101
+ result = @workflow_json.absoluteRunDir.to_s
102
+ rescue StandardError
103
+ end
104
+ end
105
+ result
106
+ end
107
+
108
+ def output_adapter(user_options, default, logger)
109
+ # user option trumps all others
110
+ return user_options[:output_adapter] if user_options[:output_adapter]
111
+
112
+ # try to read from OSW
113
+ if @run_options && !@run_options.empty?
114
+ custom_adapter = @run_options.get.customOutputAdapter
115
+ if !custom_adapter.empty?
116
+ begin
117
+ custom_file_name = custom_adapter.get.customFileName
118
+ class_name = custom_adapter.get.className
119
+ options = ::JSON.parse(custom_adapter.get.options, symbolize_names: true)
120
+
121
+ # merge with user options, user options will replace options loaded from OSW
122
+ options.merge!(user_options)
123
+
124
+ # stick output_directory in options
125
+ options[:output_directory] = run_dir
126
+
127
+ p = @workflow_json.findFile(custom_file_name)
128
+ if !p.empty?
129
+ load(p.get.to_s)
130
+ output_adapter = eval("#{class_name}.new(options)")
131
+ return output_adapter
132
+ else
133
+ log_message = "Failed to load custom adapter file '#{custom_file_name}'"
134
+ logger.error log_message
135
+ raise log_message
136
+ end
137
+ rescue StandardError
138
+ log_message = "Failed to load custom adapter '#{class_name}' from file '#{custom_file_name}'"
139
+ logger.error log_message
140
+ raise log_message
141
+ end
142
+ end
143
+ end
144
+
145
+ return default
146
+ end
147
+
148
+ def jobs(user_options, default, logger)
149
+ # user option trumps all others
150
+ return user_options[:jobs] if user_options[:jobs]
151
+
152
+ # try to read from OSW
153
+ begin
154
+ # log_message = "Reading custom job states from OSW is not currently supported'"
155
+ # logger.info log_message
156
+ rescue StandardError
157
+ end
158
+
159
+ return default
160
+ end
161
+
162
+ def debug(user_options, default)
163
+ # user option trumps all others
164
+ return user_options[:debug] if user_options[:debug]
165
+
166
+ # try to read from OSW
167
+ if @run_options && !@run_options.empty?
168
+ return @run_options.get.debug
169
+ end
170
+
171
+ return default
172
+ end
173
+
174
+ def fast(user_options, default)
175
+ # user option trumps all others
176
+ return user_options[:fast] if user_options[:fast]
177
+
178
+ # try to read from OSW
179
+ if @run_options && !@run_options.empty?
180
+ if @run_options.get.respond_to?(:fast)
181
+ return @run_options.get.fast
182
+ else
183
+ if @workflow[:run_options]
184
+ return @workflow[:run_options][:fast]
185
+ end
186
+ end
187
+ end
188
+
189
+ return default
190
+ end
191
+
192
+ def preserve_run_dir(user_options, default)
193
+ # user option trumps all others
194
+ return user_options[:preserve_run_dir] if user_options[:preserve_run_dir]
195
+
196
+ # try to read from OSW
197
+ if @run_options && !@run_options.empty?
198
+ return @run_options.get.preserveRunDir
199
+ end
200
+
201
+ return default
202
+ end
203
+
204
+ def skip_expand_objects(user_options, default)
205
+ # user option trumps all others
206
+ return user_options[:skip_expand_objects] if user_options[:skip_expand_objects]
207
+
208
+ # try to read from OSW
209
+ if @run_options && !@run_options.empty?
210
+ if @run_options.get.respond_to?(:skipExpandObjects)
211
+ return @run_options.get.skipExpandObjects
212
+ else
213
+ if @workflow[:run_options]
214
+ return @workflow[:run_options][:skip_expand_objects]
215
+ end
216
+ end
217
+ end
218
+
219
+ return default
220
+ end
221
+
222
+ def skip_energyplus_preprocess(user_options, default)
223
+ # user option trumps all others
224
+ return user_options[:skip_energyplus_preprocess] if user_options[:skip_energyplus_preprocess]
225
+
226
+ # try to read from OSW
227
+ if @run_options && !@run_options.empty?
228
+ if @run_options.get.respond_to?(:skipEnergyPlusPreprocess)
229
+ return @run_options.get.skipEnergyPlusPreprocess
230
+ else
231
+ if @workflow[:run_options]
232
+ return @workflow[:run_options][:skip_energyplus_preprocess]
233
+ end
234
+ end
235
+ end
236
+
237
+ return default
238
+ end
239
+
240
+ def cleanup(user_options, default)
241
+ # user option trumps all others
242
+ return user_options[:cleanup] if user_options[:cleanup]
243
+
244
+ # try to read from OSW
245
+ if @run_options && !@run_options.empty?
246
+ return @run_options.get.cleanup
247
+ end
248
+
249
+ return default
250
+ end
251
+
252
+ def energyplus_path(user_options, default)
253
+ # user option trumps all others
254
+ return user_options[:energyplus_path] if user_options[:energyplus_path]
255
+
256
+ return default
257
+ end
258
+
259
+ def profile(user_options, default)
260
+ # user option trumps all others
261
+ return user_options[:profile] if user_options[:profile]
262
+
263
+ return default
264
+ end
265
+
266
+ def verify_osw(user_options, default)
267
+ # user option trumps all others
268
+ return user_options[:verify_osw] if user_options[:verify_osw]
269
+
270
+ return default
271
+ end
272
+
273
+ def weather_file(user_options, default)
274
+ # user option trumps all others
275
+ return user_options[:weather_file] if user_options[:weather_file]
276
+
277
+ # try to read from OSW
278
+ if !@workflow_json.weatherFile.empty?
279
+ return @workflow_json.weatherFile.get.to_s
280
+ end
281
+
282
+ return default
283
+ end
284
+
285
+ # Get the associated OSD (datapoint) file from the local filesystem
286
+ #
287
+ def datapoint
288
+ # DLM: should this come from the OSW? the osd id and checksum are specified there.
289
+ osd_abs_path = File.join(osw_dir, 'datapoint.osd')
290
+ result = nil
291
+ if File.exist? osd_abs_path
292
+ result = ::JSON.parse(File.read(osd_abs_path), symbolize_names: true)
293
+ end
294
+ return result
295
+ end
296
+
297
+ # Get the associated OSA (analysis) definition from the local filesystem
298
+ #
299
+ def analysis
300
+ # DLM: should this come from the OSW? the osd id and checksum are specified there.
301
+ osa_abs_path = File.join(osw_dir, '../analysis.json')
302
+ result = nil
303
+ if File.exist? osa_abs_path
304
+ result = ::JSON.parse(File.read(osa_abs_path), symbolize_names: true)
305
+ end
306
+ return result
307
+ end
308
+ end
309
+ end
310
+ end
311
+ end