encapsulator 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md ADDED
@@ -0,0 +1,50 @@
1
+ # Encapsulator
2
+
3
+ [![DOI](https://zenodo.org/badge/94570522.svg)](https://zenodo.org/badge/latestdoi/94570522)
4
+
5
+ ## Installation
6
+
7
+ ### Fedora 25
8
+
9
+ ```
10
+ sudo dnf install ruby
11
+ gem install json rgl rake bundler
12
+ git clone https://github.com/tfjmp/encapsulator.git
13
+ cd encapsulator
14
+ rake install
15
+ encapsulator --install fedora
16
+ encapsulator -h
17
+ ```
18
+
19
+ ### Ubuntu
20
+
21
+ ```
22
+ sudo apt install ruby
23
+ gem install json rgl rake bundler
24
+ git clone https://github.com/tfjmp/encapsulator.git
25
+ cd encapsulator
26
+ rake install
27
+ encapsulator --install ubuntu
28
+ encapsulator -h
29
+ ```
30
+
31
+ ### MacOS
32
+
33
+ ```
34
+ brew install ruby
35
+ gem install json rgl rake bundler
36
+ git clone https://github.com/tfjmp/encapsulator.git
37
+ cd encapsulator
38
+ rake install
39
+ encapsulator --install mac
40
+ encapsulator -h
41
+ ```
42
+
43
+ ## USAGE
44
+
45
+ ```
46
+ # extract info from ddg.json
47
+ encapsulator --info <your_RDT_prov.json>
48
+ # select an output node to generate the code to be generate
49
+ encapsulator --code <your_RDT_prov.json> <output_node_name> <new R script>
50
+ ```
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "encapsulator"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/encapsulator ADDED
@@ -0,0 +1,56 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "encapsulator"
4
+
5
+ if ARGV[0] == '--info'
6
+ Encapsulator::CLI::info ARGV[1]
7
+ elsif ARGV[0] == '--encapsulate'
8
+ system 'rm', '-rf', '.'+ARGV[1]
9
+ out_path = '.'+ARGV[1]+'/workspace'
10
+ system 'mkdir', '-p', out_path
11
+ for i in 3..ARGV.size
12
+ break unless !ARGV[i].nil?
13
+ out_name = '.'+ARGV[1]+'/workspace/'+ARGV[i]+'.R'
14
+ Encapsulator::CLI::source_code ARGV[2], ARGV[i], out_name
15
+ Encapsulator::ProvR.tidy out_name
16
+ Encapsulator::CLI::script_inputs ARGV[2], ARGV[i], out_path
17
+ puts "Generated script for output #{ARGV[i]}"
18
+ end
19
+ Encapsulator::CLI::encapsulate ARGV[1], ARGV[2]
20
+ puts 'WARNING: We are sorry due to remote API change, capsule need to be manually uploaded to: https://app.vagrantup.com'
21
+ elsif ARGV[0] == '--decapsulate'
22
+ decapsulate ARGV[1]
23
+ elsif ARGV[0] == '--jpg'
24
+ Encapsulator::CLI::get_jpg ARGV[1]
25
+ elsif ARGV[0] == '--png'
26
+ Encapsulator::CLI::get_png ARGV[1]
27
+ elsif ARGV[0] == '--svg'
28
+ Encapsulator::CLI::get_svg ARGV[1]
29
+ elsif ARGV[0] == '--code'
30
+ out_path = '.encapsulator'
31
+ system 'rm', '-rf', out_path
32
+ system 'mkdir', '-p', out_path
33
+ for i in 2..ARGV.size
34
+ break unless !ARGV[i].nil?
35
+ out_name = out_path+'/'+ARGV[i]+'.R'
36
+ Encapsulator::CLI::source_code ARGV[1], ARGV[i], out_name
37
+ Encapsulator::ProvR.tidy out_name
38
+ Encapsulator::CLI::script_inputs ARGV[1], ARGV[i], out_path
39
+ puts "Generated script for output #{ARGV[i]}"
40
+ end
41
+ puts 'Scripts written in '+File.expand_path(out_path)
42
+ elsif ARGV[0] == '--run'
43
+ Encapsulator::ProvR::run ARGV[1]
44
+ elsif ARGV[0] == '--version'
45
+ puts Encapsulator::VERSION
46
+ elsif ARGV[0] == '--install'
47
+ if ARGV[1] == 'fedora'
48
+ Encapsulator::Installer.install_fedora
49
+ elsif ARGV[1] == 'ubuntu'
50
+ Encapsulator::Installer::install_ubuntu
51
+ elsif ARGV[1] == 'mac'
52
+ Encapsulator::Installer::install_mac
53
+ end
54
+ else
55
+ Encapsulator::CLI::usage
56
+ end
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,6 @@
1
+ require 'encapsulator/version'
2
+ require 'encapsulator/provjson_parser'
3
+ require 'encapsulator/rjson_parser'
4
+ require 'encapsulator/installer'
5
+ require 'encapsulator/provr'
6
+ require 'encapsulator/cli'
@@ -0,0 +1,131 @@
1
+ module Encapsulator
2
+ module CLI
3
+ def CLI.usage
4
+ puts "USAGE\n\n"
5
+ puts '--info <path to R script> display information about the provenance graph'
6
+ puts '--jpg <path to R script> output graph as jpg'
7
+ puts '--png <path to R script> output graph as png'
8
+ puts '--svg <path to R script> output graph as svg'
9
+ puts '--code <path to R script> <output> [output] ... [output] create the source necessary to generate the specified output'
10
+ puts '--run <path to R script> run the provided r script'
11
+ puts '--encapsulate <user>/<project> <script> <output> [output] ... [output] create the specified capsule'
12
+ puts '--decapsulate <user>/<project> download the coresponding capsule'
13
+ end
14
+
15
+ def CLI.vagrant vm_name, install_instructions
16
+ provision = Array.new
17
+ provision << '# -*- mode: ruby -*-'
18
+ provision << '# vi: set ft=ruby :'
19
+ provision << 'Vagrant.configure(2) do |config|'
20
+ provision << " "+'config.vm.box = "jhcook/fedora25"'
21
+ provision << " "+'config.vm.provider "virtualbox" do |vb|'
22
+ provision << " "+'vb.gui = true'
23
+ provision << " "+'vb.memory = 2048'
24
+ provision << " "+'vb.customize ["modifyvm", :id, "--cpuexecutioncap", "70"]'
25
+ provision << " "+'vb.cpus = 2'
26
+ provision << " "+"vb.name = \"#{vm_name.gsub '/', '_'}\""
27
+ provision << 'end'
28
+ provision << 'config.vm.provision "shell", inline: <<-SHELL'
29
+ provision << " "+'cp -a /vagrant/workspace/. /home/vagrant/Documents'
30
+ provision << " "+'sudo dnf -y -v install openssl-devel libxml2-devel'
31
+ provision << " "+'sudo dnf -y -v install libcurl libcurl-devel'
32
+ provision << " "+'sudo dnf -y -v install perl-CPAN'
33
+ provision << " "+'sudo dnf -y -v install ruby'
34
+ provision << " "+'wget https://atom.io/download/rpm'
35
+ provision << " "+'mv ./rpm ./atom.rpm'
36
+ provision << " "+'sudo dnf -y -v install ./atom.rpm'
37
+ provision << " "+'rm -rf ./atom.rpm'
38
+ provision << install_instructions
39
+ provision << " "+'wget https://download1.rstudio.org/rstudio-1.0.143-x86_64.rpm'
40
+ provision << " "+'sudo dnf -y -v install ./rstudio-1.0.143-x86_64.rpm'
41
+ provision << " "+'rm -rf ./rstudio-1.0.143-x86_64.rpm'
42
+ provision << 'SHELL'
43
+ provision << 'end'
44
+ end
45
+
46
+ def CLI.encapsulate capsule_name, script
47
+ ProvR.run_script script do
48
+ v = Encapsulator::RJSONParser.new('../'+script).read_json_file('ddg.json')
49
+ system 'mkdir', '-p', '../.'+capsule_name
50
+ Dir.chdir '../.'+capsule_name do
51
+ puts "In directory #{Dir.pwd}..."
52
+ File.open("Vagrantfile", "w+") do |f|
53
+ puts 'Encapsulator will attempt to install the following packages:'
54
+ v.packages_show
55
+ script = CLI.vagrant capsule_name, v.install
56
+ f.puts(script)
57
+ end
58
+ puts 'Provision script is ready...'
59
+ puts 'getting your capsule ready, be patient...'
60
+ system("vagrant", "up", out: $stdout, err: $stdout)
61
+ system("vagrant", "halt", out: $stdout, err: $stdout)
62
+ end
63
+ puts 'Your capsule should be visible in the virtualbox interface.'
64
+ end
65
+ end
66
+
67
+ def CLI.decapsulate capsule_name
68
+ puts "looking for the capsule #{vm}..."
69
+ system("vagrant", "init", capsule_name, out: $stdout, err: $stdout)
70
+ puts 'getting your capsule ready, be patient...'
71
+ system("vagrant", "up", out: $stdout, err: $stdout)
72
+ system("vagrant", "halt", out: $stdout, err: $stdout)
73
+ puts 'you should find your capsule in the virtualbox GUI.'
74
+ end
75
+
76
+ def CLI.source_code script, target_output, destination
77
+ ProvR.run_script script do
78
+ script = Encapsulator::RJSONParser.new('../'+script).read_json_file('ddg.json').script target_output
79
+ end
80
+ if script.nil?
81
+ abort "#{target_output} is not a valid output file."
82
+ else
83
+ File.open(destination, "w+") do |f|
84
+ f.puts(script)
85
+ end
86
+ ProvR.tidy destination
87
+ puts "Script written to #{destination}"
88
+ end
89
+ end
90
+
91
+ def CLI.get_jpg script
92
+ ProvR.run_script script do
93
+ Encapsulator::RJSONParser.new('../'+script).read_json_file('ddg.json').jpg
94
+ end
95
+ end
96
+
97
+ def CLI.get_png script
98
+ ProvR.run_script script do
99
+ Encapsulator::RJSONParser.new('../'+script).read_json_file('ddg.json').png
100
+ end
101
+ end
102
+
103
+ def CLI.get_svg script
104
+ ProvR.run_script script do
105
+ Encapsulator::RJSONParser.new('../'+script).read_json_file('ddg.json').svg
106
+ end
107
+ end
108
+
109
+ def CLI.info script
110
+ ProvR.run_script script do
111
+ Encapsulator::RJSONParser.new('../'+script).read_json_file('ddg.json').show
112
+ end
113
+ end
114
+
115
+ def CLI.script_inputs script, target_output, destination
116
+ inputs = nil
117
+ destination = '../'+destination
118
+ ProvR.run_script script do
119
+ inputs = Encapsulator::RJSONParser.new('../'+script).read_json_file('ddg.json').script_inputs target_output
120
+ inputs.each do |path, file|
121
+ next unless !file.include? destination
122
+ dest_path = path.gsub '..', destination
123
+ dest = file.gsub '..', destination
124
+ system 'mkdir', '-p', dest_path
125
+ system 'cp', '-f', file, dest
126
+ puts "Saved input #{dest} for script #{target_output}.R"
127
+ end
128
+ end
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,20 @@
1
+ module Encapsulator
2
+ class Installer
3
+ def self.install_fedora
4
+ system 'wget', 'http://download.virtualbox.org/virtualbox/5.1.22/VirtualBox-5.1-5.1.22_115126_fedora25-1.x86_64.rpm', out: $stdout, err: $stdout
5
+ system 'sudo', 'dnf', '-y', '-v', 'install', './VirtualBox-5.1-5.1.22_115126_fedora25-1.x86_64.rpm', out: $stdout, err: $stdout
6
+ system 'sudo', 'dnf', '-y', '-v', 'install', 'vagrant', out: $stdout, err: $stdout
7
+ end
8
+
9
+ def self.install_ubuntu
10
+ system 'sudo', 'apt', '-y', 'install', 'virtualbox', 'virtualbox-ext-pack', out: $stdout, err: $stdout
11
+ system 'sudo', 'apt', '-y', 'install', 'vagrant', out: $stdout, err: $stdout
12
+ end
13
+
14
+ def self.install_mac
15
+ system 'brew', 'cask', 'install', 'virtualbox', out: $stdout, err: $stdout
16
+ system 'brew', 'cask', 'install', 'vagrant', out: $stdout, err: $stdout
17
+ system 'brew', 'cask', 'install', 'vagrant-manager', out: $stdout, err: $stdout
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,100 @@
1
+ require 'json'
2
+
3
+ module Encapsulator
4
+ class ProvJSONParser
5
+ attr_reader :filename
6
+
7
+ def read_json_file filename
8
+ if filename != nil
9
+ @filename=filename
10
+ parse_json File.read(filename) unless !File.file?(filename)
11
+ print "File does not exist\n" unless File.file?(filename)
12
+ end
13
+ self
14
+ end
15
+
16
+ def read_log_file filename
17
+ if filename != nil
18
+ open(filename) do |file|
19
+ file.each_line do |line|
20
+ parse_json line
21
+ end
22
+ end unless !File.file?(filename)
23
+ print "File does not exist\n" unless File.file?(filename)
24
+ end
25
+ self
26
+ end
27
+
28
+ def used k, v
29
+ end
30
+
31
+ def wasGeneratedBy k, v
32
+ end
33
+
34
+ def wasDerivedFrom k, v
35
+ end
36
+
37
+ def wasInformedBy k, v
38
+ end
39
+
40
+ def wasAssociatedWith k, v
41
+ end
42
+
43
+ def prefix k, v
44
+ end
45
+
46
+ def entity k, v
47
+ end
48
+
49
+ def activity k, v
50
+ end
51
+
52
+ def agent k, v
53
+ end
54
+
55
+ def parse_json string
56
+ begin
57
+ json = JSON.parse(string)
58
+ rescue JSON::ParserError
59
+ puts 'Failed parsing.'
60
+ abort
61
+ end
62
+
63
+ json['prefix'].each do |k, v|
64
+ self.prefix k, v
65
+ end unless !json.key? 'prefix'
66
+
67
+ json['entity'].each do |k, v|
68
+ self.entity k, v
69
+ end unless !json.key? 'entity'
70
+
71
+ json['activity'].each do |k, v|
72
+ self.activity k, v
73
+ end unless !json.key? 'activity'
74
+
75
+ json['agent'].each do |k, v|
76
+ self.activity k, v
77
+ end unless !json.key? 'agent'
78
+
79
+ json['used'].each do |k, v|
80
+ self.used k, v
81
+ end unless !json.key? 'used'
82
+
83
+ json['wasGeneratedBy'].each do |k, v|
84
+ self.wasGeneratedBy k, v
85
+ end unless !json.key? 'wasGeneratedBy'
86
+
87
+ json['wasDerivedFrom'].each do |k, v|
88
+ self.wasDerivedFrom k, v
89
+ end unless !json.key? 'wasDerivedFrom'
90
+
91
+ json['wasInformedBy'].each do |k, v|
92
+ self.wasInformedBy k, v
93
+ end unless !json.key? 'wasInformedBy'
94
+
95
+ json['wasAssociatedWith'].each do |k, v|
96
+ self.wasAssociatedWith k, v
97
+ end unless !json.key? 'wasAssociatedWith'
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,33 @@
1
+ module Encapsulator
2
+ module ProvR
3
+ def ProvR.run script
4
+ require 'rinruby'
5
+ r = RinRuby.new(echo: false)
6
+ r.eval "install.packages('devtools')"
7
+ r.eval "require('devtools')"
8
+ r.eval "install_github('provtools/provR', ref='dev')"
9
+ r.eval "require('provR')"
10
+ r.eval "prov.capture('#{script}', save=TRUE)"
11
+ end
12
+
13
+ def ProvR.tidy script
14
+ require 'rinruby'
15
+ r = RinRuby.new(echo: false)
16
+ r.eval "install.packages('formatR', repos = 'http://cran.rstudio.com')"
17
+ r.eval "require('formatR')"
18
+ r.eval "tidy_file('#{script}')"
19
+ end
20
+
21
+ $ran_script=false
22
+ def ProvR.run_script script
23
+ if !$ran_script
24
+ run script
25
+ $ran_script = true
26
+ end
27
+ prov_folder = script.gsub('.R', '_ddg')
28
+ Dir.chdir prov_folder do
29
+ yield
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,233 @@
1
+ require 'find'
2
+ require 'rgl/adjacency'
3
+ require 'rgl/dot'
4
+ require 'rgl/topsort'
5
+ require 'rgl/transitivity'
6
+ require 'rgl/traversal'
7
+
8
+ module Encapsulator
9
+ class RJSONParser < ProvJSONParser
10
+ attr_reader :dg
11
+ attr_reader :map
12
+ attr_reader :files
13
+ attr_reader :instructions
14
+ attr_reader :libraries
15
+ attr_reader :packages
16
+ attr_reader :file
17
+
18
+ def initialize r_file
19
+ @dg = RGL::DirectedAdjacencyGraph.new # initialise the graph structure
20
+ @map = Hash.new(0)
21
+ @files = Hash.new
22
+ @copies = Hash.new
23
+ @instructions = Hash.new
24
+ @libraries = Hash.new
25
+ @packages = Hash.new
26
+ @script = IO.readlines(r_file)
27
+ end
28
+
29
+ def get_operation start_line, end_line
30
+ start_line-=1
31
+ end_line-=1
32
+ operation = ''
33
+ for i in start_line..end_line
34
+ operation += @script[i] unless @script[i].nil?
35
+ end
36
+ return operation
37
+ end
38
+
39
+ def add key
40
+ @map[key]=@map[key]+1
41
+ end
42
+
43
+ def used k, v
44
+ @dg.add_edge v['prov:activity'], v['prov:entity']
45
+ end
46
+
47
+ def wasGeneratedBy k, v
48
+ @dg.add_edge v['prov:entity'], v['prov:activity']
49
+ end
50
+
51
+ def wasDerivedFrom k, v
52
+ @dg.add_edge v['prov:generatedEntity'], v['prov:usedEntity']
53
+ end
54
+
55
+ def wasInformedBy k, v
56
+ #@dg.add_edge v['prov:informed'], v['prov:informant']
57
+ end
58
+
59
+ def wasAssociatedWith k, v
60
+ @dg.add_edge v['prov:activity'], v['prov:agent']
61
+ @dg.add_edge v['prov:agent'], v['prov:plan'] unless !v.key? 'prov:plan'
62
+ end
63
+
64
+ def entity k, v
65
+ self.add v['rdt:type']
66
+ if v['rdt:type'] == 'File'
67
+ @files[k]=v['rdt:name']
68
+ end
69
+ end
70
+
71
+ def activity k, v
72
+ self.add v['rdt:type']
73
+ if v['rdt:type'] == 'Operation'
74
+ @instructions[k]=get_operation(v['rdt:startLine'].to_i, v['rdt:endLine'].to_i)
75
+ end
76
+ if /(library|require)\(('|")[a-zA-Z]+('|")/.match v['rdt:name']
77
+ @libraries[k]=v['rdt:name']
78
+ end
79
+ if k == 'environment'
80
+ v['rdt:installedPackages'].each do |l|
81
+ packages[l['package']]=l['version']
82
+ end
83
+ end
84
+ end
85
+
86
+ def agent k, v
87
+ self.add v['rdt:type']
88
+ end
89
+
90
+ def information
91
+ str = "\n------\n"
92
+ str += "Graph:\n"
93
+ str += "------\n"
94
+ if @dg.directed?
95
+ str += "directed\n"
96
+ else
97
+ str += "not directed\n"
98
+ end
99
+
100
+ if @dg.acyclic?
101
+ str += "acyclic\n"
102
+ else
103
+ str += "not acyclic\n"
104
+ end
105
+
106
+ str += @dg.num_edges.to_s() +" edges.\n"
107
+ str += @dg.num_vertices.to_s() +" vertices.\n"
108
+ str += (@dg.num_edges.to_f/@dg.num_vertices).to_s() + " edges/vertices ratio.\n"
109
+ puts str
110
+ end
111
+
112
+ def svg
113
+ @dg.write_to_graphic_file('svg')
114
+ end
115
+
116
+ def jpg
117
+ @dg.write_to_graphic_file('jpg')
118
+ end
119
+
120
+ def png
121
+ @dg.write_to_graphic_file('png')
122
+ end
123
+
124
+ def get_list file
125
+ id = ''
126
+ @files.each do |k, v|
127
+ if v == file
128
+ id = k
129
+ break
130
+ end
131
+ end
132
+ if id==''
133
+ return Array.new
134
+ end
135
+ tree = @dg.bfs_search_tree_from(id)
136
+ g = @dg.vertices_filtered_by {|v| tree.has_vertex? v}
137
+ list = g.vertices
138
+ end
139
+
140
+ def source_code file
141
+ statements = Array.new
142
+ list = get_list file
143
+ list.delete_if { |v| !v.include?('p') }
144
+ list = list.sort_by{ |m| m.tr('p', '').to_i }
145
+ list.each do |v|
146
+ next unless !@instructions[v].nil?
147
+ statements << @instructions[v]
148
+ end
149
+ return statements
150
+ end
151
+
152
+ def script_inputs file
153
+ inputs = Hash.new
154
+ list = get_list file
155
+ list.delete_if { |v| !is_input_with_id?(v) }
156
+ list.each do |v|
157
+ next unless !@files[v].nil?
158
+ Find.find '..' do |path|
159
+ if path.include? '/'+@files[v]
160
+ inputs[path.gsub @files[v], '']= path
161
+ end
162
+ end
163
+ end
164
+ return inputs
165
+ end
166
+
167
+ def script output
168
+ script = Array.new
169
+ @libraries.each do |k, v|
170
+ script << v
171
+ end
172
+ statements = source_code output
173
+ script << statements unless statements.empty?
174
+ end
175
+
176
+ def show
177
+ file_show
178
+ puts "\n\n"
179
+ packages_show
180
+ end
181
+
182
+ def file_show
183
+ puts 'Files'
184
+ puts '-----'
185
+ @files.each do |key, value|
186
+ if is_input? value
187
+ puts "Input #{value}"
188
+ else
189
+ puts "Output #{value}"
190
+ end
191
+ end
192
+ end
193
+
194
+ def packages_show
195
+ puts 'Packages'
196
+ puts '--------'
197
+ @packages.each do |key, value|
198
+ if !['datasets', 'utils', 'graphics', 'grDevices', 'methods', 'stats', 'provR', 'devtools'].include?(key)
199
+ puts "#{key} v#{value}"
200
+ end
201
+ end
202
+ end
203
+
204
+ def is_input? file_name
205
+ source_code(file_name).empty?
206
+ end
207
+
208
+ def is_input_with_id? id
209
+ @files.each do |key, value|
210
+ if id == key
211
+ if is_input? value
212
+ return true
213
+ end
214
+ end
215
+ end
216
+ return false
217
+ end
218
+
219
+ def install
220
+ instructions = Array.new
221
+ @packages.each do |key, value|
222
+ if key == 'base'
223
+ instructions << " sudo dnf -y -v install R-#{value}"
224
+ instructions << " sudo dnf -y -v install R"
225
+ instructions << " sudo su - -c \"R -e \\\\\\\"install.packages(\'devtools\', repos=\'http://cran.rstudio.com/\', dependencies = TRUE)\\\\\\\"\""
226
+ elsif !['datasets', 'utils', 'graphics', 'grDevices', 'methods', 'stats', 'provR', 'devtools'].include?(key)
227
+ instructions << " sudo su - -c \"R -e \\\\\\\"require('devtools');install_version(\'#{key}\', version=\'#{value}\', repos=\'http://cran.rstudio.com/\')\\\\\\\"\""
228
+ end
229
+ end
230
+ return instructions
231
+ end
232
+ end
233
+ end