attsynaptic-synaptic4r 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,288 @@
1
+ ####-------------------------------------------------------------------------------------------------------
2
+ module Synaptic4r
3
+
4
+ ####------------------------------------------------------------------------------------------------------
5
+ class Request
6
+
7
+ ####------------------------------------------------------------------------------------------------------
8
+ include Rest
9
+
10
+
11
+ #.......................................................................................................
12
+ # argument specification
13
+ #.......................................................................................................
14
+ define_rest_arg :uid, :header => :hide
15
+
16
+ define_rest_arg :key, :header => :hide
17
+
18
+ define_rest_arg :site, :header => :hide
19
+
20
+ define_rest_arg :file, :header => :none, :cli => 'file',
21
+ :desc => 'file to upload'
22
+
23
+ define_rest_arg :lifetime, :header => :none, :cli => ['lifetime', '-f'],
24
+ :desc => 'lifetime in minutes of request URL (default is 5 minuts)'
25
+
26
+ define_rest_arg :account, :header => :none, :cli => ['account', '-u'],
27
+ :desc => "user account name specified in #{ENV['HOME']}./synaptic4r"
28
+
29
+ define_rest_arg :oid, :header => :none, :cli => ['oid', '-o'],
30
+ :desc => 'system assigned object identifier'
31
+
32
+ define_rest_arg :rpath, :header => :none, :cli => 'rpath',
33
+ :desc => 'remote file or directory path'
34
+
35
+ define_rest_arg :namespace, :header => :none, :cli => ['namespace', '-n'],
36
+ :desc => 'root namespace used for remote file path (default is uid)'
37
+
38
+ define_rest_arg :create_beginoffset, :header => :none, :cli => ['beginoffset', '-b'],
39
+ :desc => 'begining byte offset in file'
40
+
41
+ define_rest_arg :create_endoffset, :header => :none, :cli => ['endoffset', '-d'],
42
+ :desc => 'end byte offset in file'
43
+
44
+ define_rest_arg :content_type, :header => :http, :cli => ['content-type', '-c'],
45
+ :desc => 'http content type'
46
+
47
+ define_rest_arg :beginoffset, :header => :http, :cli => ['beginoffset', '-b'],
48
+ :desc => 'begining byte offset in file'
49
+
50
+ define_rest_arg :endoffset, :header => :http, :cli => ['endoffset', '-d'],
51
+ :desc => 'end byte offset in file'
52
+
53
+ define_rest_arg :useracl, :header => :emc, :cli => ['useracl', '-a'],
54
+ :desc => 'access control list'
55
+
56
+ define_rest_arg :groupacl, :header => :emc, :cli => ['groupacl', '-g'],
57
+ :desc => 'user group acess control list'
58
+
59
+ define_rest_arg :tags, :header => :emc, :cli => ['tags', '-t'],
60
+ :desc => 'listable metadata tag name'
61
+
62
+ define_rest_arg :include_meta, :header => :emc, :cli => ['include-meta', '-e', :flag],
63
+ :desc => 'include object metadata in query result', :map => lambda{|v| v ? 1 : 0}
64
+
65
+ define_rest_arg :meta, :header => :emc, :cli => ['meta', '-m'],
66
+ :desc => 'user nonlistable metadata name=value pairs'
67
+
68
+ define_rest_arg :listable_meta, :header => :emc, :cli => ['listable-meta', '-i'],
69
+ :desc => 'user listable metadata tag name=value pairs'
70
+
71
+ #.......................................................................................................
72
+ # method specification
73
+ #.......................................................................................................
74
+ #### all methods
75
+ define_rest_method :all,
76
+ :required => [:uid, :key, :site],
77
+ :optional => [:account]
78
+
79
+ #### POST
80
+ define_rest_method :create_file,
81
+ :desc => 'create a file',
82
+ :result_class => StorageObject,
83
+ :http_method => :post,
84
+ :required => [:file, [:rpath, :listable_meta]],
85
+ :optional => [:content_type, :namespace, :create_beginoffset, :create_endoffset],
86
+ :exe => lambda {|req, args|
87
+ ext = req.extent(args[:file], args[:create_beginoffset],
88
+ args[:create_endoffset])
89
+ req.add_payload(args, ext)},
90
+ :map_required_args => lambda {|vals|
91
+ pvals = vals.select{|v| /^-i/.match(v) or not /^-/.match(v)}
92
+ ovals = if pvals.length.eql?(1)
93
+ pvals + [pvals.first]
94
+ elsif /\/$/.match(pvals.last) and pvals.length.eql?(2)
95
+ [pvals.first, pvals.last+File.basename(pvals.first)]
96
+ else
97
+ pvals
98
+ end
99
+ {:pvals => ovals, :dlen => ovals.length - pvals.length}},
100
+ :banner => 'Usage: synrest create-file file [remote-path|-i list-meta] [options]'
101
+
102
+ define_rest_method :create_dir,
103
+ :desc => 'create a directory',
104
+ :result_class => StorageObject,
105
+ :http_method => :post,
106
+ :required => [:rpath],
107
+ :optional => [:namespace],
108
+ :exe => lambda {|req, args| args[:rpath] += '/'}
109
+
110
+ define_rest_method :create_version,
111
+ :desc => 'create an immutable version of a file or directory',
112
+ :result_class => StorageObject,
113
+ :http_method => :post,
114
+ :required => [[:rpath, :oid]],
115
+ :optional => [:namespace],
116
+ :query => 'versions'
117
+
118
+ define_rest_method :update_nonlistable_metadata,
119
+ :desc => 'update nonlistable user metadata for a file or directory',
120
+ :http_method => :post,
121
+ :result_class => Result,
122
+ :required => [:meta, [:rpath, :oid]],
123
+ :optional => [:namespace],
124
+ :query => 'metadata/user'
125
+
126
+ define_rest_method :update_listable_metadata,
127
+ :desc => 'update listable user metadata for a file or directory',
128
+ :http_method => :post,
129
+ :result_class => Result,
130
+ :required => [:listable_meta, [:rpath, :oid]],
131
+ :optional => [:namespace],
132
+ :query => 'metadata/user'
133
+
134
+ define_rest_method :update_acl,
135
+ :desc => 'update access control list for a file or directory',
136
+ :http_method => :post,
137
+ :result_class => Result,
138
+ :required => [[:useracl, :groupacl], [:rpath, :oid]],
139
+ :optional => [:namespace],
140
+ :query => 'acl'
141
+
142
+ #### GET
143
+ define_rest_method :get,
144
+ :desc => 'get the contents of a file or directory',
145
+ :result_class => Download,
146
+ :http_method => :get,
147
+ :required => [[:rpath, :oid]],
148
+ :optional => [:namespace, :beginoffset, :endoffset],
149
+ :map_required_args => lambda {|vals|
150
+ pvals = vals.select{|v| /^-o/.match(v) or not /^-/.match(v)}
151
+ if pvals.empty?
152
+ {:pvals => [''], :dlen => 1}
153
+ else
154
+ {:pvals => pvals, :dlen => 0}
155
+ end},
156
+ :exe => lambda {|req, args|
157
+ if args[:beginoffset] and args[:endoffset]
158
+ ext = {:offset => args[:beginoffset].to_i,
159
+ :length => args[:endoffset].to_i - args[:beginoffset].to_i + 1}
160
+ req.set_header_range(args, ext); end},
161
+ :banner => 'Usage: synrest get [remote-path|-o oid] [options]'
162
+
163
+ define_rest_method :get_by_tag,
164
+ :desc => 'get files and directories with specified listable user metadata tag',
165
+ :result_class => StorageObjectList,
166
+ :http_method => :get,
167
+ :required => [:tags],
168
+ :optional => [:include_meta]
169
+
170
+
171
+ define_rest_method :get_user_metadata,
172
+ :desc => 'get both listable and nonlistable user metadata for a file or directory',
173
+ :result_class => UserMetadata,
174
+ :http_method => :get,
175
+ :required => [[:rpath, :oid]],
176
+ :optional => [:namespace],
177
+ :query => 'metadata/user'
178
+
179
+ define_rest_method :get_system_metadata,
180
+ :desc => 'get system metadata for a file or directory',
181
+ :http_method => :get,
182
+ :result_class => SystemMetadata,
183
+ :required => [[:rpath, :oid]],
184
+ :optional => [:namespace],
185
+ :query => 'metadata/system'
186
+
187
+ define_rest_method :get_acl,
188
+ :desc => 'get user and group access control list for a file or directory',
189
+ :result_class => Acl,
190
+ :http_method => :get,
191
+ :required => [[:rpath, :oid]],
192
+ :optional => [:namespace],
193
+ :query => 'acl'
194
+
195
+ define_rest_method :get_versions,
196
+ :desc => 'get versions of a file or directory',
197
+ :http_method => :get,
198
+ :result_class => Versions,
199
+ :required => [[:rpath, :oid]],
200
+ :optional => [:namespace],
201
+ :query => 'versions'
202
+
203
+ define_rest_method :get_all_tags,
204
+ :desc => 'get all defined tags',
205
+ :http_method => :get,
206
+ :result_class => Tags,
207
+ :required => [],
208
+ :optional => [:namespace, :tags],
209
+ :query => 'listabletags'
210
+
211
+
212
+ define_rest_method :get_tags,
213
+ :desc => 'get listable user metadata tags for a file or directory',
214
+ :http_method => :get,
215
+ :result_class => Tags,
216
+ :required => [[:rpath, :oid]],
217
+ :optional => [:namespace],
218
+ :query => 'metadata/tags'
219
+
220
+ #### PUT
221
+ define_rest_method :update,
222
+ :desc => 'update a file or directory',
223
+ :http_method => :put,
224
+ :result_class => Result,
225
+ :required => [:file, [:rpath, :oid]],
226
+ :optional => [:namespace, :beginoffset, :endoffset],
227
+ :exe => lambda {|req, args|
228
+ ext = req.extent(args[:file], args[:beginoffset], args[:endoffset])
229
+ req.set_header_range(args, ext)
230
+ req.add_payload(args, ext)
231
+ req.set_header_extent(args, ext)},
232
+ :map_required_args => lambda {|vals|
233
+ pvals = vals.select{|v| not /^-/.match(v)}
234
+ ovals = if pvals.length.eql?(1)
235
+ pvals + [pvals.first]
236
+ elsif /\/$/.match(pvals.last) and pvals.length.eql?(2)
237
+ [pvals.first, pvals.last+File.basename(pvals.first)]
238
+ else
239
+ pvals
240
+ end
241
+ {:pvals => ovals, :dlen => ovals.length - pvals.length}},
242
+ :banner => 'Usage: synrest update file [remote-path|-o oid] [options]'
243
+
244
+ #### DELETE
245
+ define_rest_method :delete,
246
+ :desc => 'delete a file or directory',
247
+ :result_class => Result,
248
+ :http_method => :delete,
249
+ :required => [[:rpath, :oid]],
250
+ :optional => [:namespace]
251
+
252
+ define_rest_method :delete_user_metadata,
253
+ :desc => 'delete user metadata for a file or directory',
254
+ :result_class => Result,
255
+ :http_method => :delete,
256
+ :required => [:tags, [:rpath, :oid]],
257
+ :optional => [:namespace],
258
+ :query => 'metadata/user'
259
+
260
+ #### Other methods
261
+ define_rest_method :get_object_url,
262
+ :desc => 'retrieve a shareable URL for linking to storage objects',
263
+ :result_class => ShareableUrl,
264
+ :http_method => :delete,
265
+ :required => [[:rpath, :oid]],
266
+ :optional => [:lifetime],
267
+ :diagnostics => false
268
+
269
+ #.......................................................................................................
270
+ # other requests
271
+ #.......................................................................................................
272
+ def get_object_url(args)
273
+ esc = '/=&?%'
274
+ exp = (args[:lifetime].nil? ? 5 : args[:lifetime].to_i)*60 + Time.now.to_i
275
+ res = /.*(\/rest.*)/.match(url).captures.first
276
+ user = headers['x-emc-uid']
277
+ @sign = "GET\n#{res}\n#{user}\n#{exp}"
278
+ digest = OpenSSL::HMAC.digest(OpenSSL::Digest.new('sha1'), Base64.decode64(key), sign)
279
+ signature = Base64.encode64(digest.to_s()).chomp()
280
+ @url = "#{url}?uid=#{URI.encode(user, esc)}&expires=#{exp}&signature=#{URI.encode(signature, esc)}"
281
+ end
282
+
283
+
284
+ #### Request
285
+ end
286
+
287
+ #### Synaptic4r
288
+ end
@@ -0,0 +1,355 @@
1
+ ###########################################################################################################
2
+ module Synaptic4r
3
+
4
+ ###########################################################################################################
5
+ module Utils
6
+
7
+ #.......................................................................................................
8
+ def unary_args_given?(unary_args, args)
9
+ unary_args.each{|a| raise ArgumentError, "Required argument '#{a}' is missing." unless args.include?(a)}
10
+ end
11
+
12
+ #.......................................................................................................
13
+ def symbolize(e)
14
+ if e.kind_of?(Hash)
15
+ e.inject({}){|h, (k,v)| h.update(k.to_sym => v)}
16
+ elsif e.kind_of?(Array)
17
+ e.map{|v| v.to_sym}
18
+ end
19
+ end
20
+
21
+ #.......................................................................................................
22
+ def create_timestamp()
23
+ Time.now().httpdate()
24
+ end
25
+
26
+ #.......................................................................................................
27
+ def read_file(file, offset, length)
28
+ IO.read(file, length, offset)
29
+ end
30
+
31
+ #### Utils
32
+ end
33
+
34
+ ###########################################################################################################
35
+ module Rest
36
+
37
+ #------------------------------------------------------------------------------------------------------
38
+ class << self
39
+
40
+ def included(base)
41
+ base.send(:extend, ClassMethods)
42
+ base.send(:include, InstanceMethods)
43
+ end
44
+
45
+ #### self
46
+ end
47
+
48
+
49
+ ####-----------------------------------------------------------------------------------------------------
50
+ module ClassMethods
51
+
52
+ #.......................................................................................................
53
+ @@method_defs = Hash.new{|h,k| h[k] = {:required => [], :optional => []}}
54
+ @@arg_defs = Hash.new{|h,k| h[k] = {}}
55
+
56
+ #.......................................................................................................
57
+ def method_defs
58
+ @@method_defs
59
+ end
60
+
61
+ #.......................................................................................................
62
+ def arg_defs
63
+ @@arg_defs
64
+ end
65
+
66
+ #.......................................................................................................
67
+ def define_rest_method(meth, args)
68
+ [meth].flatten.each do |m|
69
+ method_defs[m][:required] += args[:required] if args[:required]
70
+ method_defs[m][:optional] += args[:optional] if args[:optional]
71
+ method_defs[m][:http_method] = args[:http_method]
72
+ method_defs[m][:desc] = args[:desc]
73
+ method_defs[m][:result_class] = args[:result_class]
74
+ method_defs[m][:query] = args[:query]
75
+ method_defs[m][:exe] = args[:exe]
76
+ method_defs[m][:map_required_args] = args[:map_required_args]
77
+ method_defs[m][:banner] = args[:banner]
78
+ method_defs[m][:diagnostics] = args[:diagnostics]
79
+ end
80
+ end
81
+
82
+ #.......................................................................................................
83
+ def define_rest_arg(arg, opts)
84
+ arg_defs[arg].update(opts)
85
+ end
86
+
87
+ #.......................................................................................................
88
+ def args
89
+ method_defs
90
+ end
91
+
92
+ #.......................................................................................................
93
+ def has_rest_method?(meth)
94
+ rest_methods.include?(meth)
95
+ end
96
+
97
+ #.......................................................................................................
98
+ def rest_methods
99
+ args.keys.inject([]){|r,m| m.eql?(:all) ? r : r << m}
100
+ end
101
+ #.......................................................................................................
102
+ def http_method(meth)
103
+ args[meth][:http_method]
104
+ end
105
+
106
+ #.......................................................................................................
107
+ def required_rest_args(meth)
108
+ args[meth][:required] + args_all_methods(:required)
109
+ end
110
+
111
+ #.......................................................................................................
112
+ def unary_rest_args(meth)
113
+ args[meth][:required].inject([]){|r,a| a.kind_of?(Array) ? r : r << a}
114
+ end
115
+
116
+ #.......................................................................................................
117
+ def exclusive_rest_args(meth)
118
+ args[meth][:required].inject([]){|r,a| a.kind_of?(Array) ? r << a : r}
119
+ end
120
+
121
+ #.......................................................................................................
122
+ def optional_rest_args(meth)
123
+ args[meth][:optional] + args_all_methods(:optional)
124
+ end
125
+
126
+ #.......................................................................................................
127
+ def rest_arg(arg)
128
+ arg_defs[arg]
129
+ end
130
+
131
+ #.......................................................................................................
132
+ def args_all_methods(type)
133
+ args[:all][type].inject([]){|r,a| rest_arg(a)[:header].eql?(:hide) ? r : r << a}
134
+ end
135
+
136
+ #.......................................................................................................
137
+ def desc(meth)
138
+ args[meth][:desc]
139
+ end
140
+
141
+ #.......................................................................................................
142
+ def exe(meth)
143
+ args[meth][:exe]
144
+ end
145
+
146
+ #.......................................................................................................
147
+ def banner(meth)
148
+ args[meth][:banner]
149
+ end
150
+
151
+ #.......................................................................................................
152
+ def diagnostics(meth)
153
+ args[meth][:diagnostics].nil? ? true : args[meth][:diagnostics]
154
+ end
155
+
156
+ #.......................................................................................................
157
+ def map_required_args(meth)
158
+ args[meth][:map_required_args]
159
+ end
160
+
161
+ #.......................................................................................................
162
+ def result_class(meth)
163
+ args[meth][:result_class]
164
+ end
165
+
166
+ #.......................................................................................................
167
+ def query(meth)
168
+ args[meth][:query]
169
+ end
170
+
171
+ #.......................................................................................................
172
+ def header_args(meth)
173
+ unary_rest_args(meth) + exclusive_rest_args(meth).flatten + optional_rest_args(meth) -
174
+ non_header_args(meth)
175
+ end
176
+
177
+ #.......................................................................................................
178
+ def emc_headers
179
+ arg_defs.inject([]){|r, (a, d)| d[:header].eql?(:emc) ? r.push(a) : r}
180
+ end
181
+
182
+ #.......................................................................................................
183
+ def non_header_args(meth)
184
+ arg_defs.inject([]){|r, (a, d)| d[:header].eql?(:none) ? r.push(a) : r}
185
+ end
186
+
187
+ #### ClassMethods
188
+ end
189
+
190
+ ####-----------------------------------------------------------------------------------------------------
191
+ module InstanceMethods
192
+
193
+ #.......................................................................................................
194
+ include Utils
195
+
196
+ #.......................................................................................................
197
+ attr_reader :headers, :uid, :key, :site, :subtenant, :payload, :meth, :sign, :url
198
+
199
+ #.......................................................................................................
200
+ def initialize(args)
201
+ unary_args_given?([:uid, :subtenant, :key, :site], args)
202
+ @uid = args[:uid]
203
+ @key = args[:key]
204
+ @site = args[:site]
205
+ @subtenant = args[:subtenant]
206
+ @headers = credentials
207
+ end
208
+
209
+ #.......................................................................................................
210
+ def execute(meth, *args, &blk)
211
+ @meth = meth
212
+ args = args.first || {}
213
+ set_remote_file(args)
214
+ unary_args_given?(self.class.unary_rest_args(meth), args)
215
+ exclusive_args_given?(self.class.exclusive_rest_args(meth), args)
216
+ self.class.exe(meth)[self, args] if self.class.exe(meth)
217
+ build_service_url(args)
218
+ add_header_attr(args)
219
+ create_signature
220
+ res = if self.respond_to?(meth)
221
+ self.send(meth, args)
222
+ else
223
+ if args[:dump].nil? and args[:payload].nil?
224
+ RestClient::Request.execute(:method => self.class.http_method(meth), :url => url,
225
+ :headers => headers, :payload => payload)
226
+ end
227
+ end
228
+ self.class.result_class(meth).new(:result => res, :headers => headers, :url => url, :sign => sign,
229
+ :http_request => self.class.http_method(meth),
230
+ :payload => args[:payload] ? payload : nil)
231
+ end
232
+
233
+ #.......................................................................................................
234
+ def exclusive_args_given?(exclusive_args, args)
235
+ exclusive_args.each do |alist|
236
+ unless alist.select{|a| args.keys.include?(a)}.length.eql?(1)
237
+ acli = alist.map{|a| [self.class.rest_arg(a)[:cli]].flatten.first}
238
+ raise ArgumentError, "One of '#{acli.join(', ')}' is required as an argument."
239
+ end
240
+ end
241
+ end
242
+
243
+ #.......................................................................................................
244
+ def add_header_attr(given={})
245
+ to_emc = lambda{|a| h = a.to_s.gsub(/_/,'-'); self.class.emc_headers.include?(a) ? "x-emc-#{h}" : h}
246
+ header_args = self.class.header_args(meth)
247
+ given.keys.each do |k|
248
+ headers.update(to_emc[k] => given[k]) if header_args.include?(k)
249
+ end
250
+ end
251
+
252
+ #.......................................................................................................
253
+ def set_remote_file(args)
254
+ if args[:rpath]
255
+ if args[:namespace]
256
+ args[:rpath] = args[:namespace] + '/' + args[:rpath]
257
+ else
258
+ args[:rpath] = uid + '/' + args[:rpath]
259
+ end
260
+ end
261
+ end
262
+
263
+ #.......................................................................................................
264
+ def build_service_url(args={})
265
+ surl = if args[:rpath]
266
+ 'namespace/' + args[:rpath]
267
+ else
268
+ 'objects' + (args[:oid].nil? ? '' : "/#{args[:oid]}")
269
+ end
270
+ @url = (/\/$/.match(site).nil? ? site + '/' : site) + surl +
271
+ ((q = self.class.query(meth)).nil? ? '' : "?#{q}")
272
+ end
273
+
274
+ #.......................................................................................................
275
+ def create_signature
276
+ @sign = create_sign_string
277
+ digest = OpenSSL::HMAC.digest(OpenSSL::Digest.new('sha1'), Base64.decode64(key), sign)
278
+ headers['x-emc-signature'] = Base64.encode64(digest.to_s()).chomp()
279
+ end
280
+
281
+ #.......................................................................................................
282
+ def create_sign_string
283
+ composite_string = (self.class.http_method(meth).to_s.upcase || '') + "\n" + \
284
+ (headers['content-type'] || '') + "\n" + \
285
+ (headers['range'] || '') + "\n" + \
286
+ (headers['date'] || '') + "\n"
287
+ if url
288
+ composite_string += URI.parse(url).path.downcase
289
+ composite_string += "?" + URI.parse(url).query.downcase unless URI.parse(url).query.nil?
290
+ end
291
+ composite_string += "\n" + canonicalize_custom_headers
292
+ end
293
+
294
+ #.......................................................................................................
295
+ def canonicalize_custom_headers
296
+ headers.select do |key, value|
297
+ /^x-emc-/.match(key)
298
+ end.sort.inject("") do |h, (k, v)|
299
+ h += "#{k}:#{v}\n"
300
+ end.chomp
301
+ end
302
+
303
+ #.......................................................................................................
304
+ def set_header_range(args, ext)
305
+ headers['range'] = "bytes=#{ext[:offset]}-#{ext[:offset]+ext[:length]-1}"
306
+ end
307
+
308
+ #.......................................................................................................
309
+ def extent(file, begin_offset, end_offset)
310
+ if file
311
+ file_offset = File.size(file) - 1
312
+ offset = begin_offset.to_i
313
+ end_offset = end_offset.nil? ? file_offset : end_offset.to_i
314
+ end_offset = file_offset if end_offset > file_offset
315
+ length = end_offset - offset + 1
316
+ {:offset => offset, :length => length}
317
+ end
318
+ end
319
+
320
+ #.......................................................................................................
321
+ def set_header_extent(args, ext)
322
+ args[:beginoffset] = ext[:offset]
323
+ args[:endoffset] = ext[:offset] + ext[:length] - 1
324
+ end
325
+
326
+ #.......................................................................................................
327
+ def add_payload(args, ext)
328
+ if args[:file]
329
+ @payload = read_file(args[:file], ext[:offset], ext[:length])
330
+ if @payload
331
+ headers['content-length'] = ext[:length]
332
+ headers['content-md5'] = Base64.encode64(Digest::MD5.digest(payload)).chomp()
333
+ end
334
+ end
335
+ end
336
+
337
+ #.......................................................................................................
338
+ def credentials
339
+ curr_time = create_timestamp
340
+ {'x-emc-uid' => subtenant + '/' + uid,
341
+ 'date' => curr_time,
342
+ 'x-emc-date' => curr_time,
343
+ 'content-type' => 'application/octet-stream',
344
+ 'accept' => '*/*'}
345
+ end
346
+
347
+ #### InstanceMethods
348
+ end
349
+
350
+
351
+ ### Rest
352
+ end
353
+
354
+ #### Synaptic4r
355
+ end