google_drive 0.3.11 → 1.0.0.pre1

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.
Files changed (34) hide show
  1. checksums.yaml +7 -7
  2. data/README.rdoc +27 -10
  3. data/lib/google_drive/acl.rb +40 -58
  4. data/lib/google_drive/acl_entry.rb +76 -56
  5. data/lib/google_drive/api_client_fetcher.rb +49 -0
  6. data/lib/google_drive/collection.rb +69 -71
  7. data/lib/google_drive/file.rb +171 -128
  8. data/lib/google_drive/session.rb +234 -268
  9. data/lib/google_drive/spreadsheet.rb +19 -163
  10. data/lib/google_drive/util.rb +126 -17
  11. data/lib/google_drive/worksheet.rb +108 -80
  12. data/lib/google_drive.rb +63 -57
  13. data/lib/google_drive_v1/acl.rb +115 -0
  14. data/lib/google_drive_v1/acl_entry.rb +100 -0
  15. data/lib/google_drive_v1/api_client_fetcher.rb +47 -0
  16. data/lib/google_drive_v1/authentication_error.rb +14 -0
  17. data/lib/{google_drive → google_drive_v1}/basic_fetcher.rb +1 -1
  18. data/lib/{google_drive → google_drive_v1}/client_login_fetcher.rb +2 -2
  19. data/lib/google_drive_v1/collection.rb +167 -0
  20. data/lib/google_drive_v1/error.rb +12 -0
  21. data/lib/google_drive_v1/file.rb +258 -0
  22. data/lib/google_drive_v1/list.rb +119 -0
  23. data/lib/google_drive_v1/list_row.rb +88 -0
  24. data/lib/{google_drive → google_drive_v1}/oauth1_fetcher.rb +1 -1
  25. data/lib/{google_drive → google_drive_v1}/oauth2_fetcher.rb +2 -2
  26. data/lib/google_drive_v1/record.rb +31 -0
  27. data/lib/google_drive_v1/session.rb +522 -0
  28. data/lib/google_drive_v1/spreadsheet.rb +248 -0
  29. data/lib/google_drive_v1/table.rb +60 -0
  30. data/lib/google_drive_v1/util.rb +73 -0
  31. data/lib/google_drive_v1/worksheet.rb +498 -0
  32. data/lib/google_drive_v1.rb +148 -0
  33. metadata +112 -77
  34. data/doc_src/google_drive/acl_entry.rb +0 -33
@@ -0,0 +1,522 @@
1
+ # Author: Hiroshi Ichikawa <http://gimite.net/>
2
+ # The license of this source is "New BSD Licence"
3
+
4
+ require "cgi"
5
+ require "stringio"
6
+
7
+ require "rubygems"
8
+ require "nokogiri"
9
+ require "oauth"
10
+ require "oauth2"
11
+
12
+ require "google_drive_v1/util"
13
+ require "google_drive_v1/client_login_fetcher"
14
+ require "google_drive_v1/oauth1_fetcher"
15
+ require "google_drive_v1/oauth2_fetcher"
16
+ require "google_drive_v1/error"
17
+ require "google_drive_v1/authentication_error"
18
+ require "google_drive_v1/spreadsheet"
19
+ require "google_drive_v1/worksheet"
20
+ require "google_drive_v1/collection"
21
+ require "google_drive_v1/file"
22
+
23
+
24
+ module GoogleDriveV1
25
+
26
+ # Use GoogleDriveV1.login or GoogleDriveV1.saved_session to get
27
+ # GoogleDriveV1::Session object.
28
+ class Session
29
+
30
+ include(Util)
31
+ extend(Util)
32
+
33
+ UPLOAD_CHUNK_SIZE = 512 * 1024
34
+
35
+ # DEPRECATED: Will be removed in the next version.
36
+ #
37
+ # The same as GoogleDriveV1.login.
38
+ def self.login(mail, password, proxy = nil)
39
+ warn(
40
+ "WARNING: GoogleDriveV1.login is deprecated and will be removed in the next version. " +
41
+ "Use GoogleDriveV1.login_with_oauth instead.")
42
+ session = Session.new(nil, ClientLoginFetcher.new({}, proxy))
43
+ session.login(mail, password)
44
+ return session
45
+ end
46
+
47
+ # The same as GoogleDriveV1.login_with_oauth.
48
+ def self.login_with_oauth(access_token, proxy = nil)
49
+ if proxy
50
+ warn(
51
+ "WARNING: Specifying a proxy object is deprecated and will not work in the next version. " +
52
+ "Set ENV[\"http_proxy\"] instead.")
53
+ end
54
+ case access_token
55
+ when OAuth::AccessToken
56
+ warn(
57
+ "WARNING: Authorization with OAuth1 is deprecated and will not work in the next version. " +
58
+ "Use OAuth2 instead.")
59
+ raise(GoogleDriveV1::Error, "proxy is not supported with OAuth1.") if proxy
60
+ fetcher = OAuth1Fetcher.new(access_token)
61
+ when OAuth2::AccessToken
62
+ fetcher = OAuth2Fetcher.new(access_token.token, proxy)
63
+ when String
64
+ fetcher = OAuth2Fetcher.new(access_token, proxy)
65
+ else
66
+ raise(GoogleDriveV1::Error,
67
+ "access_token is neither String, OAuth2::Token nor OAuth::Token: %p" % access_token)
68
+ end
69
+ return Session.new(nil, fetcher)
70
+ end
71
+
72
+ # The same as GoogleDriveV1.restore_session.
73
+ def self.restore_session(auth_tokens, proxy = nil)
74
+ warn(
75
+ "WARNING: GoogleDriveV1.restore_session is deprecated and will be removed in the next version. " +
76
+ "Use GoogleDriveV1.login_with_oauth instead.")
77
+ return Session.new(auth_tokens, nil, proxy)
78
+ end
79
+
80
+ # Creates a dummy GoogleDriveV1::Session object for testing.
81
+ def self.new_dummy()
82
+ return Session.new(nil, Object.new())
83
+ end
84
+
85
+ # DEPRECATED: Use GoogleDriveV1.restore_session instead.
86
+ def initialize(auth_tokens = nil, fetcher = nil, proxy = nil)
87
+ if fetcher
88
+ @fetcher = fetcher
89
+ else
90
+ @fetcher = ClientLoginFetcher.new(auth_tokens || {}, proxy)
91
+ end
92
+ end
93
+
94
+ # Authenticates with given +mail+ and +password+, and updates current session object
95
+ # if succeeds. Raises GoogleDriveV1::AuthenticationError if fails.
96
+ # Google Apps account is supported.
97
+ def login(mail, password)
98
+ if !@fetcher.is_a?(ClientLoginFetcher)
99
+ raise(GoogleDriveV1::Error,
100
+ "Cannot call login for session created by login_with_oauth.")
101
+ end
102
+ begin
103
+ @fetcher.auth_tokens = {
104
+ :wise => authenticate(mail, password, :wise),
105
+ :writely => authenticate(mail, password, :writely),
106
+ }
107
+ rescue GoogleDriveV1::Error => ex
108
+ return true if @on_auth_fail && @on_auth_fail.call()
109
+ raise(AuthenticationError, "Authentication failed for #{mail}: #{ex.message}")
110
+ end
111
+ end
112
+
113
+ # Authentication tokens.
114
+ def auth_tokens
115
+ warn(
116
+ "WARNING: GoogleDriveV1::Session\#auth_tokens is deprecated and will be removed in the next version.")
117
+ if !@fetcher.is_a?(ClientLoginFetcher)
118
+ raise(GoogleDriveV1::Error,
119
+ "Cannot call auth_tokens for session created by " +
120
+ "login_with_oauth.")
121
+ end
122
+ return @fetcher.auth_tokens
123
+ end
124
+
125
+ # Authentication token.
126
+ def auth_token(auth = :wise)
127
+ warn(
128
+ "WARNING: GoogleDriveV1::Session\#auth_token is deprecated and will be removed in the next version.")
129
+ return self.auth_tokens[auth]
130
+ end
131
+
132
+ # Proc or Method called when authentication has failed.
133
+ # When this function returns +true+, it tries again.
134
+ def on_auth_fail
135
+ warn(
136
+ "WARNING: GoogleDriveV1::Session\#on_auth_fail is deprecated and will be removed in the next version.")
137
+ return @on_auth_fail
138
+ end
139
+
140
+ def on_auth_fail=(func)
141
+ warn(
142
+ "WARNING: GoogleDriveV1::Session\#on_auth_fail is deprecated and will be removed in the next version.")
143
+ @on_auth_fail = func
144
+ end
145
+
146
+ # Returns list of files for the user as array of GoogleDriveV1::File or its subclass.
147
+ # You can specify query parameters described at
148
+ # https://developers.google.com/google-apps/documents-list/#getting_a_list_of_documents_and_files
149
+ #
150
+ # files doesn't return collections unless "showfolders" => true is specified.
151
+ #
152
+ # e.g.
153
+ # session.files
154
+ # session.files("title" => "hoge", "title-exact" => "true")
155
+ def files(params = {})
156
+ url = concat_url(
157
+ "#{DOCS_BASE_URL}?v=3", "?" + encode_query(params))
158
+ doc = request(:get, url, :auth => :writely)
159
+ return doc.css("feed > entry").map(){ |e| entry_element_to_file(e) }
160
+ end
161
+
162
+ # Returns GoogleDriveV1::File or its subclass whose title exactly matches +title+.
163
+ # Returns nil if not found. If multiple files with the +title+ are found, returns
164
+ # one of them.
165
+ #
166
+ # If given an Array, traverses collections by title. e.g.
167
+ # session.file_by_title(["myfolder", "mysubfolder/even/w/slash", "myfile"])
168
+ def file_by_title(title)
169
+ if title.is_a?(Array)
170
+ return self.root_collection.file_by_title(title)
171
+ else
172
+ return files("title" => title, "title-exact" => "true")[0]
173
+ end
174
+ end
175
+
176
+ # Returns list of spreadsheets for the user as array of GoogleDriveV1::Spreadsheet.
177
+ # You can specify query parameters e.g. "title", "title-exact".
178
+ #
179
+ # e.g.
180
+ # session.spreadsheets
181
+ # session.spreadsheets("title" => "hoge")
182
+ # session.spreadsheets("title" => "hoge", "title-exact" => "true")
183
+ def spreadsheets(params = {})
184
+ url = concat_url(
185
+ "#{DOCS_BASE_URL}/-/spreadsheet?v=3", "?" + encode_query(params))
186
+ doc = request(:get, url, :auth => :writely)
187
+ # The API may return non-spreadsheets too when title-exact is specified.
188
+ # Probably a bug. For workaround, only returns Spreadsheet instances.
189
+ return doc.css("feed > entry").
190
+ map(){ |e| entry_element_to_file(e) }.
191
+ select(){ |f| f.is_a?(Spreadsheet) }
192
+ end
193
+
194
+ # Returns GoogleDriveV1::Spreadsheet with given +key+.
195
+ #
196
+ # e.g.
197
+ # # http://spreadsheets.google.com/ccc?key=pz7XtlQC-PYx-jrVMJErTcg&hl=ja
198
+ # session.spreadsheet_by_key("pz7XtlQC-PYx-jrVMJErTcg")
199
+ def spreadsheet_by_key(key)
200
+ url = "https://spreadsheets.google.com/feeds/worksheets/#{key}/private/full"
201
+ return Spreadsheet.new(self, url)
202
+ end
203
+
204
+ # Returns GoogleDriveV1::Spreadsheet with given +url+. You must specify either of:
205
+ # - URL of the page you open to access the spreadsheet in your browser
206
+ # - URL of worksheet-based feed of the spreadseet
207
+ #
208
+ # e.g.
209
+ # session.spreadsheet_by_url(
210
+ # "https://docs.google.com/spreadsheet/ccc?key=pz7XtlQC-PYx-jrVMJErTcg")
211
+ # session.spreadsheet_by_url(
212
+ # "https://spreadsheets.google.com/feeds/" +
213
+ # "worksheets/pz7XtlQC-PYx-jrVMJErTcg/private/full")
214
+ def spreadsheet_by_url(url)
215
+ # Tries to parse it as URL of human-readable spreadsheet.
216
+ uri = URI.parse(url)
217
+ if ["spreadsheets.google.com", "docs.google.com"].include?(uri.host)
218
+ case uri.path
219
+ when /\/d\/([^\/]+)/
220
+ return spreadsheet_by_key($1)
221
+ when /\/ccc$/
222
+ if (uri.query || "").split(/&/).find(){ |s| s=~ /^key=(.*)$/ }
223
+ return spreadsheet_by_key($1)
224
+ end
225
+ end
226
+ end
227
+ # Assumes the URL is worksheets feed URL.
228
+ return Spreadsheet.new(self, url)
229
+ end
230
+
231
+ # Returns GoogleDriveV1::Spreadsheet with given +title+.
232
+ # Returns nil if not found. If multiple spreadsheets with the +title+ are found, returns
233
+ # one of them.
234
+ def spreadsheet_by_title(title)
235
+ return spreadsheets({"title" => title, "title-exact" => "true"})[0]
236
+ end
237
+
238
+ # Returns GoogleDriveV1::Worksheet with given +url+.
239
+ # You must specify URL of cell-based feed of the worksheet.
240
+ #
241
+ # e.g.
242
+ # session.worksheet_by_url(
243
+ # "http://spreadsheets.google.com/feeds/" +
244
+ # "cells/pz7XtlQC-PYxNmbBVgyiNWg/od6/private/full")
245
+ def worksheet_by_url(url)
246
+ return Worksheet.new(self, nil, url)
247
+ end
248
+
249
+ # Returns the root collection.
250
+ def root_collection
251
+ return Collection.new(self, Collection::ROOT_URL)
252
+ end
253
+
254
+ # Returns the top-level collections (direct children of the root collection).
255
+ def collections
256
+ return self.root_collection.subcollections
257
+ end
258
+
259
+ # Returns a top-level collection whose title exactly matches +title+ as
260
+ # GoogleDriveV1::Collection.
261
+ # Returns nil if not found. If multiple collections with the +title+ are found, returns
262
+ # one of them.
263
+ def collection_by_title(title)
264
+ return self.root_collection.subcollection_by_title(title)
265
+ end
266
+
267
+ # Returns GoogleDriveV1::Collection with given +url+.
268
+ # You must specify either of:
269
+ # - URL of the page you get when you go to https://docs.google.com/ with your browser and
270
+ # open a collection
271
+ # - URL of collection (folder) feed
272
+ #
273
+ # e.g.
274
+ # session.collection_by_url(
275
+ # "https://drive.google.com/#folders/" +
276
+ # "0B9GfDpQ2pBVUODNmOGE0NjIzMWU3ZC00NmUyLTk5NzEtYaFkZjY1MjAyxjMc")
277
+ # session.collection_by_url(
278
+ # "http://docs.google.com/feeds/default/private/full/folder%3A" +
279
+ # "0B9GfDpQ2pBVUODNmOGE0NjIzMWU3ZC00NmUyLTk5NzEtYaFkZjY1MjAyxjMc")
280
+ def collection_by_url(url)
281
+ uri = URI.parse(url)
282
+ if ["docs.google.com", "drive.google.com"].include?(uri.host) &&
283
+ uri.fragment =~ /^folders\/(.+)$/
284
+ # Looks like a URL of human-readable collection page. Converts to collection feed URL.
285
+ url = "#{DOCS_BASE_URL}/folder%3A#{$1}"
286
+ end
287
+ return Collection.new(self, to_v3_url(url))
288
+ end
289
+
290
+ # Creates new spreadsheet and returns the new GoogleDriveV1::Spreadsheet.
291
+ #
292
+ # e.g.
293
+ # session.create_spreadsheet("My new sheet")
294
+ def create_spreadsheet(
295
+ title = "Untitled",
296
+ feed_url = "https://docs.google.com/feeds/documents/private/full")
297
+
298
+ xml = <<-"EOS"
299
+ <atom:entry
300
+ xmlns:atom="http://www.w3.org/2005/Atom"
301
+ xmlns:docs="http://schemas.google.com/docs/2007">
302
+ <atom:category
303
+ scheme="http://schemas.google.com/g/2005#kind"
304
+ term="http://schemas.google.com/docs/2007#spreadsheet"
305
+ label="spreadsheet"/>
306
+ <atom:title>#{h(title)}</atom:title>
307
+ </atom:entry>
308
+ EOS
309
+
310
+ doc = request(:post, feed_url, :data => xml, :auth => :writely)
311
+ ss_url = doc.css(
312
+ "link[rel='http://schemas.google.com/spreadsheets/2006#worksheetsfeed']")[0]["href"]
313
+ return Spreadsheet.new(self, ss_url, title)
314
+
315
+ end
316
+
317
+ # Uploads a file with the given +title+ and +content+.
318
+ # Returns a GoogleSpreadsheet::File object.
319
+ #
320
+ # e.g.
321
+ # # Uploads and converts to a Google Docs document:
322
+ # session.upload_from_string(
323
+ # "Hello world.", "Hello", :content_type => "text/plain")
324
+ #
325
+ # # Uploads without conversion:
326
+ # session.upload_from_string(
327
+ # "Hello world.", "Hello", :content_type => "text/plain", :convert => false)
328
+ #
329
+ # # Uploads and converts to a Google Spreadsheet:
330
+ # session.upload_from_string("hoge\tfoo\n", "Hoge", :content_type => "text/tab-separated-values")
331
+ # session.upload_from_string("hoge,foo\n", "Hoge", :content_type => "text/tsv")
332
+ def upload_from_string(content, title = "Untitled", params = {})
333
+ return upload_from_io(StringIO.new(content), title, params)
334
+ end
335
+
336
+ # Uploads a local file.
337
+ # Returns a GoogleSpreadsheet::File object.
338
+ #
339
+ # e.g.
340
+ # # Uploads a text file and converts to a Google Docs document:
341
+ # session.upload_from_file("/path/to/hoge.txt")
342
+ #
343
+ # # Uploads without conversion:
344
+ # session.upload_from_file("/path/to/hoge.txt", "Hoge", :convert => false)
345
+ #
346
+ # # Uploads with explicit content type:
347
+ # session.upload_from_file("/path/to/hoge", "Hoge", :content_type => "text/plain")
348
+ #
349
+ # # Uploads a text file and converts to a Google Spreadsheet:
350
+ # session.upload_from_file("/path/to/hoge.tsv", "Hoge")
351
+ # session.upload_from_file("/path/to/hoge.csv", "Hoge")
352
+ # session.upload_from_file("/path/to/hoge", "Hoge", :content_type => "text/tab-separated-values")
353
+ # session.upload_from_file("/path/to/hoge", "Hoge", :content_type => "text/csv")
354
+ def upload_from_file(path, title = nil, params = {})
355
+ file_name = ::File.basename(path)
356
+ params = {:file_name => file_name}.merge(params)
357
+ open(path, "rb") do |f|
358
+ return upload_from_io(f, title || file_name, params)
359
+ end
360
+ end
361
+
362
+ # Uploads a file. Reads content from +io+.
363
+ # Returns a GoogleSpreadsheet::File object.
364
+ def upload_from_io(io, title = "Untitled", params = {})
365
+ doc = request(:get, "#{DOCS_BASE_URL}?v=3",
366
+ :auth => :writely)
367
+ initial_url = doc.css(
368
+ "link[rel='http://schemas.google.com/g/2005#resumable-create-media']")[0]["href"]
369
+ entry = upload_raw(:post, initial_url, io, title, params)
370
+ return entry_element_to_file(entry)
371
+ end
372
+
373
+ def upload_raw(method, url, io, title = "Untitled", params = {}) #:nodoc:
374
+
375
+ params = {:convert => true}.merge(params)
376
+ pos = io.pos
377
+ io.seek(0, IO::SEEK_END)
378
+ total_bytes = io.pos - pos
379
+ io.pos = pos
380
+ content_type = params[:content_type]
381
+ if !content_type && params[:file_name]
382
+ content_type = EXT_TO_CONTENT_TYPE[::File.extname(params[:file_name]).downcase]
383
+ end
384
+ if !content_type
385
+ content_type = "application/octet-stream"
386
+ end
387
+
388
+ initial_xml = <<-"EOS"
389
+ <entry xmlns="http://www.w3.org/2005/Atom"
390
+ xmlns:docs="http://schemas.google.com/docs/2007">
391
+ <title>#{h(title)}</title>
392
+ </entry>
393
+ EOS
394
+
395
+ default_initial_header = {
396
+ "Content-Type" => "application/atom+xml;charset=utf-8",
397
+ "X-Upload-Content-Type" => content_type,
398
+ "X-Upload-Content-Length" => total_bytes.to_s(),
399
+ }
400
+ initial_full_url = concat_url(url, params[:convert] ? "?convert=true" : "?convert=false")
401
+ initial_response = request(method, initial_full_url,
402
+ :header => default_initial_header.merge(params[:header] || {}),
403
+ :data => initial_xml,
404
+ :auth => :writely,
405
+ :response_type => :response)
406
+ upload_url = initial_response["location"]
407
+
408
+ if total_bytes > 0
409
+ sent_bytes = 0
410
+ while data = io.read(UPLOAD_CHUNK_SIZE)
411
+ content_range = "bytes %d-%d/%d" % [
412
+ sent_bytes,
413
+ sent_bytes + data.bytesize - 1,
414
+ total_bytes,
415
+ ]
416
+ upload_header = {
417
+ "Content-Type" => content_type,
418
+ "Content-Range" => content_range,
419
+ }
420
+ doc = request(
421
+ :put, upload_url, :header => upload_header, :data => data, :auth => :writely)
422
+ sent_bytes += data.bytesize
423
+ end
424
+ else
425
+ upload_header = {
426
+ "Content-Type" => content_type,
427
+ }
428
+ doc = request(
429
+ :put, upload_url, :header => upload_header, :data => "", :auth => :writely)
430
+ end
431
+
432
+ return doc.root
433
+
434
+ end
435
+
436
+ def entry_element_to_file(entry) #:nodoc:
437
+ type, resource_id = entry.css("gd|resourceId").text.split(/:/)
438
+ title = entry.css("title").text
439
+ case type
440
+ when "folder"
441
+ return Collection.new(self, entry)
442
+ when "spreadsheet"
443
+ worksheets_feed_link = entry.css(
444
+ "link[rel='http://schemas.google.com/spreadsheets/2006#worksheetsfeed']")[0]
445
+ return Spreadsheet.new(self, worksheets_feed_link["href"], title)
446
+ else
447
+ return GoogleDriveV1::File.new(self, entry)
448
+ end
449
+ end
450
+
451
+ def request(method, url, params = {}) #:nodoc:
452
+
453
+ # Always uses HTTPS.
454
+ url = url.gsub(%r{^http://}, "https://")
455
+ data = params[:data]
456
+ auth = params[:auth] || :wise
457
+ if params[:header]
458
+ extra_header = params[:header]
459
+ elsif data
460
+ extra_header = {"Content-Type" => "application/atom+xml;charset=utf-8"}
461
+ else
462
+ extra_header = {}
463
+ end
464
+ response_type = params[:response_type] || :xml
465
+
466
+ while true
467
+ response = @fetcher.request_raw(method, url, data, extra_header, auth)
468
+ if response.code == "401" && @on_auth_fail && @on_auth_fail.call()
469
+ next
470
+ end
471
+ if !(response.code =~ /^[23]/)
472
+ raise(
473
+ response.code == "401" ? AuthenticationError : GoogleDriveV1::Error,
474
+ "Response code #{response.code} for #{method} #{url}: " +
475
+ CGI.unescapeHTML(response.body))
476
+ end
477
+ return convert_response(response, response_type)
478
+ end
479
+
480
+ end
481
+
482
+ def inspect
483
+ return "#<%p:0x%x>" % [self.class, self.object_id]
484
+ end
485
+
486
+ private
487
+
488
+ def convert_response(response, response_type)
489
+ case response_type
490
+ when :xml
491
+ return Nokogiri.XML(response.body)
492
+ when :raw
493
+ return response.body
494
+ when :response
495
+ return response
496
+ else
497
+ raise(GoogleDriveV1::Error,
498
+ "Unknown params[:response_type]: %s" % response_type)
499
+ end
500
+ end
501
+
502
+ def authenticate(mail, password, auth)
503
+ params = {
504
+ "accountType" => "HOSTED_OR_GOOGLE",
505
+ "Email" => mail,
506
+ "Passwd" => password,
507
+ "service" => auth.to_s(),
508
+ "source" => "Gimite-RubyGoogleDrive-1.00",
509
+ }
510
+ header = {"Content-Type" => "application/x-www-form-urlencoded"}
511
+ response = request(:post,
512
+ "https://www.google.com/accounts/ClientLogin",
513
+ :data => encode_query(params),
514
+ :auth => :none,
515
+ :header => header,
516
+ :response_type => :raw)
517
+ return response.slice(/^Auth=(.*)$/, 1)
518
+ end
519
+
520
+ end
521
+
522
+ end