attsynaptic-synaptic4r 0.1.4

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.
@@ -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