encapsulator 0.1.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/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