vuzitruby 1.0.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 ADDED
@@ -0,0 +1,101 @@
1
+ = VuzitRuby - Vuzit Web Services library
2
+
3
+ == INTRODUCTION
4
+
5
+ This is a library that allows developers to directly access the Vuzit Web
6
+ Service API through a simple Ruby script:
7
+
8
+ http://vuzit.com/developer/documents_api
9
+
10
+ Below is a basic upload example:
11
+
12
+ require "vuzitruby"
13
+
14
+ Vuzit::Service.public_key = 'YOUR_PUBLIC_API_KEY'
15
+ Vuzit::Service.private_key = 'YOUR_PRIVATE_API_KEY'
16
+
17
+ doc = Vuzit::Document.upload("c:/path/to/document.pdf")
18
+
19
+ puts "Document id: " + doc.id
20
+
21
+ To get started all you need to do is download the code, sign up for a free
22
+ account (https://ssl.vuzit.com/signup) and replace the public and
23
+ private keys with the keys from your account.
24
+
25
+ == SETUP
26
+
27
+ The client library is a RubyGem called *vuzitruby*. To install, type:
28
+
29
+ sudo gem install vuzitruby
30
+
31
+ == GETTING STARTED
32
+
33
+ * Download the code - http://github.com/vuzit/vuzitruby/downloads
34
+ * Sign up for a free Vuzit account - https://ssl.vuzit.com/signup
35
+ * Code Examples - http://wiki.github.com/vuzit/vuzitruby/code-examples
36
+ * Vuzit API Reference - http://doc.vuzit.com/vuzitruby
37
+
38
+ == EXAMPLES
39
+
40
+ Find Document Example - how to load a document:
41
+
42
+ require "vuzitruby"
43
+
44
+ Vuzit::Service.public_key = 'YOUR_PUBLIC_API_KEY'
45
+ Vuzit::Service.private_key = 'YOUR_PRIVATE_API_KEY'
46
+
47
+ doc = Vuzit::Document::find("DOCUMENT_ID")
48
+ puts "Document id: " + doc.id
49
+ puts "Document title: " + doc.title
50
+
51
+ Delete (destroy) Document Example:
52
+
53
+ require "vuzitruby"
54
+
55
+ Vuzit::Service.public_key = 'YOUR_PUBLIC_API_KEY'
56
+ Vuzit::Service.private_key = 'YOUR_PRIVATE_API_KEY'
57
+
58
+ doc = Vuzit::Document::destroy("DOCUMENT_ID")
59
+
60
+ Upload and View with the JavaScript API Example for a Rails RHTML file:
61
+
62
+ <%
63
+ require "vuzitruby"
64
+ require 'cgi'
65
+
66
+ Vuzit::Service.public_key = 'YOUR_PUBLIC_API_KEY'
67
+ Vuzit::Service.private_key = 'YOUR_PRIVATE_API_KEY'
68
+
69
+ doc = Vuzit::Document.upload("c:/path/to/document.pdf")
70
+ timestamp = Time.now
71
+ sig = Vuzit::Service.get_signature("show", doc.id, timestamp)
72
+ %>
73
+ <html>
74
+ <head>
75
+ <link href="http://vuzit.com/stylesheets/Vuzit-2.6.css" rel="Stylesheet" type="text/css" />
76
+ <script src="http://vuzit.com/javascripts/Vuzit-2.6.js" type="text/javascript"></script>
77
+ <script type="text/javascript">
78
+ // Called when the page is loaded.
79
+ function initialize() {
80
+ vuzit.Base.PublicKeySet("<%= Vuzit::Service.public_key %>");
81
+ var options = {signature: '<%= CGI.escape(sig) %>',
82
+ timestamp: '<%= timestamp %>', ssl: true}
83
+ var viewer = vuzit.Viewer.fromId("<%= doc.id %>", options);
84
+
85
+ viewer.display(document.getElementById("vuzit_viewer"), { zoom: 1 });
86
+ }
87
+ </script>
88
+ </head>
89
+ <body onload="initialize()">
90
+ <div id="vuzit_viewer" style="width: 650px; height: 500px;"></div>
91
+ </body>
92
+ </html>
93
+
94
+ == LICENSE
95
+
96
+ Released under the MIT license:
97
+
98
+ http://www.opensource.org/licenses/mit-license.php
99
+
100
+ This means you can use it in proprietary products. See LICENSE file.
101
+
data/Rakefile ADDED
@@ -0,0 +1,41 @@
1
+ require 'rubygems'
2
+ require 'spec/rake/spectask'
3
+
4
+ spec = Gem::Specification.new do |s|
5
+ s.name = 'vuzitruby'
6
+ s.version = "1.0.0"
7
+ s.homepage = 'http://vuzit.com/'
8
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
9
+ s.authors = ["Brent Matzelle"]
10
+ s.date = %q{2009-3-30}
11
+ s.description = %q{This is a library for the Vuzit Web Services API. For
12
+ more information on the platform, visit
13
+ http://vuzit.com/developer}
14
+ s.email = %q{support@vuzit.com}
15
+ s.extra_rdoc_files = ["README"]
16
+ s.files = ["README", "Rakefile", "lib/vuzitruby.rb",
17
+ "lib/vuzitruby/document.rb", "lib/vuzitruby/exception.rb",
18
+ "lib/vuzitruby/service.rb"]
19
+ s.has_rdoc = true
20
+ #s.rdoc_options = ["--main", "README"]
21
+ s.require_paths = ["lib"]
22
+ s.rubyforge_project = %q{vuzitruby}
23
+ s.rubygems_version = %q{1.0.0}
24
+ s.summary = %q{Ruby client library for the Vuzit Web Services API}
25
+ s.extra_rdoc_files = ["README"]
26
+ end
27
+
28
+ namespace :github do
29
+ desc "Prepare for GitHub gem packaging"
30
+ task :prepare do
31
+ `rake debug_gem > vuzitruby.gemspec`
32
+ end
33
+ end
34
+
35
+ require 'rake/testtask'
36
+ Rake::TestTask.new(:test) do |test|
37
+ test.libs << 'lib' << 'test'
38
+ test.pattern = 'test/**/*_test.rb'
39
+ test.verbose = true
40
+ end
41
+
@@ -0,0 +1,276 @@
1
+ require 'rexml/document'
2
+ require 'uri'
3
+ require 'cgi'
4
+
5
+ class Hash #:nodoc:all
6
+ # Taken from Rails, with appreciation to DHH
7
+ def stringify_keys
8
+ inject({}) do |options, (key, value)|
9
+ options[key.to_s] = value
10
+ options
11
+ end
12
+ end unless method_defined?(:stringify_keys)
13
+ end
14
+
15
+ module Vuzit
16
+
17
+ # Class for uploading, loading, and deleting documents using the Vuzit Web
18
+ # Service API: http://vuzit.com/developer/documents_api
19
+ #
20
+ # To use this class you need to {sign up}[http://vuzit.com/signup] for
21
+ # Vuzit first.
22
+ class Document
23
+ # The document ID
24
+ attr_accessor :id
25
+
26
+ # The document title
27
+ attr_accessor :title
28
+
29
+ # The document subject
30
+ attr_accessor :subject
31
+
32
+ # Number of pages of the document
33
+ attr_accessor :page_count
34
+
35
+ # Page width of the document in pixels
36
+ attr_accessor :page_width
37
+
38
+ # Page height of the document in pixels
39
+ attr_accessor :page_height
40
+
41
+ # File size of the original document bytes
42
+ attr_accessor :file_size
43
+
44
+ TRIES = 3 #:nodoc:
45
+
46
+ # Constructor.
47
+ def initialize #:nodoc:
48
+ # Set the defaults
49
+ @id = @title = @subject = nil
50
+ @page_count = @page_width = @page_height = @file_size = -1
51
+ end
52
+
53
+ # Deletes a document by the ID. Returns true if it succeeded. It throws
54
+ # a Vuzit::Exception on failure. It returns _true_ on success.
55
+ #
56
+ # Example:
57
+ #
58
+ # Vuzit::Service.public_key = 'YOUR_PUBLIC_API_KEY'
59
+ # Vuzit::Service.private_key = 'YOUR_PRIVATE_API_KEY'
60
+ #
61
+ # result = Vuzit::Document.destroy("DOCUMENT_ID")
62
+ def self.destroy(id)
63
+ timestamp = Time.now
64
+ sig = CGI.escape(Vuzit::Service::get_signature('destroy', id, timestamp))
65
+
66
+ # Create the connection
67
+ uri = URI.parse(Vuzit::Service.service_url)
68
+ http = Net::HTTP.new(uri.host, uri.port)
69
+
70
+ query = "/documents/#{id}.xml?key=#{Vuzit::Service.public_key}" +
71
+ "&signature=#{sig}&timestamp=#{timestamp.to_i}"
72
+ request = Net::HTTP::Delete.new(query)
73
+ response = http.start { http.request(request) }
74
+
75
+ if response.code.to_i != 200
76
+ # Some type of error ocurred
77
+ begin
78
+ doc = REXML::Document.new(response.body)
79
+ rescue Exception => ex
80
+ raise Vuzit::Exception.new("XML error: #{ex.message}")
81
+ end
82
+
83
+ if doc.root != nil
84
+ code = doc.root.elements['code']
85
+ if code != nil
86
+ raise Vuzit::Exception.new(doc.root.elements['msg'].text, code.text.to_i);
87
+ end
88
+ end
89
+
90
+ # At this point we don't know what the error is
91
+ raise Vuzit::Exception.new("Unknown error occurred #{response.message}", response.code)
92
+ end
93
+
94
+ debug(response.code + " " + response.message + "\n")
95
+
96
+ return true
97
+ end
98
+
99
+ # Finds a document by the ID. It throws a Vuzit::Exception on failure.
100
+ #
101
+ # Example:
102
+ #
103
+ # Vuzit::Service.public_key = 'YOUR_PUBLIC_API_KEY'
104
+ # Vuzit::Service.private_key = 'YOUR_PRIVATE_API_KEY'
105
+ #
106
+ # doc = Vuzit::Document.find("DOCUMENT_ID")
107
+ # puts doc.id
108
+ # puts doc.title
109
+ def self.find(id)
110
+ timestamp = Time.now
111
+ sig = CGI.escape(Vuzit::Service::get_signature('show', id, timestamp))
112
+
113
+ # Create the connection
114
+ uri = URI.parse(Vuzit::Service.service_url)
115
+ http = Net::HTTP.new(uri.host, uri.port)
116
+
117
+ query = "/documents/#{id}.xml?key=#{Vuzit::Service.public_key}" +
118
+ "&signature=#{sig}&timestamp=#{timestamp.to_i}"
119
+ request = Net::HTTP::Get.new(query)
120
+ response = http.start { http.request(request) }
121
+
122
+ # TODO: Check if response.code.to_i != 200
123
+
124
+ begin
125
+ doc = REXML::Document.new(response.body)
126
+ rescue Exception => ex
127
+ raise Vuzit::Exception.new("XML error: #{ex.message}")
128
+ end
129
+
130
+ if doc.root == nil
131
+ raise Vuzit::Exception.new("No response from server");
132
+ end
133
+
134
+ debug(response.code + " " + response.message + "\n" + response.body)
135
+
136
+ code = doc.root.elements['code']
137
+ if code != nil
138
+ raise Vuzit::Exception.new(doc.root.elements['msg'].text, code.text.to_i);
139
+ end
140
+
141
+ id = doc.root.elements['web_id']
142
+ if id == nil
143
+ raise Vuzit::Exception.new("Unknown error occurred");
144
+ end
145
+
146
+ result = Vuzit::Document.new
147
+ result.id = id.text
148
+ result.title = doc.root.elements['title'].text
149
+ result.subject = doc.root.elements['subject'].text
150
+ result.page_count = doc.root.elements['page_count'].text.to_i
151
+ result.page_width = doc.root.elements['width'].text.to_i
152
+ result.page_height = doc.root.elements['height'].text.to_i
153
+ result.file_size = doc.root.elements['file_size'].text.to_i
154
+
155
+ return result
156
+ end
157
+
158
+ # Uploads a file to Vuzit. It throws a Vuzit::Exception on failure.
159
+ #
160
+ # Example:
161
+ #
162
+ # Vuzit::Service.public_key = 'YOUR_PUBLIC_API_KEY'
163
+ # Vuzit::Service.private_key = 'YOUR_PRIVATE_API_KEY'
164
+ #
165
+ # doc = Vuzit::Document.upload("c:/path/to/document.pdf", :secure => true)
166
+ # puts doc.id
167
+ def self.upload(file, options = {})
168
+ raise ArgumentError, "Options must be a hash" unless options.kind_of? Hash
169
+
170
+ timestamp = Time.now
171
+ sig = Vuzit::Service::get_signature('create', nil, timestamp)
172
+ # Make a request form
173
+ fields = Hash.new
174
+ fields[:format] = 'xml'
175
+ fields[:key] = Vuzit::Service::public_key
176
+
177
+ if options[:secure] != nil
178
+ fields[:secure] = options[:secure] == true ? '1' : '0'
179
+ else
180
+ fields[:secure] = '1'
181
+ end
182
+
183
+ fields[:signature] = sig
184
+ fields[:timestamp] = timestamp.to_i
185
+ fields[:file_type] = options[:file_type]
186
+ response = nil
187
+
188
+ File.open(file, "rb") do |f|
189
+ fields[:upload] = f
190
+ response = send_request 'create', fields
191
+ end
192
+
193
+ debug(response.code + " " + response.message + "\n" + response.body)
194
+
195
+ # TODO: check the response.code.to_i to make sure it's 201
196
+
197
+ begin
198
+ doc = REXML::Document.new(response.body)
199
+ rescue Exception => ex
200
+ raise Vuzit::Exception.new("XML error: #{ex.message}")
201
+ end
202
+
203
+ if doc.root == nil
204
+ raise Vuzit::Exception.new("No response from server");
205
+ end
206
+
207
+ code = doc.root.elements['code']
208
+ if code != nil
209
+ raise Vuzit::Exception.new(doc.root.elements['msg'].text, code.text.to_i);
210
+ end
211
+
212
+ id = doc.root.elements['web_id']
213
+ if id == nil
214
+ raise Vuzit::Exception.new("Unknown error occurred");
215
+ end
216
+
217
+ result = Vuzit::Document.new
218
+ result.id = id.text
219
+
220
+ return result
221
+ end
222
+
223
+ private
224
+
225
+ # Sends debug messages if activated
226
+ def self.debug(text)
227
+ $stderr.puts(text) if Vuzit::Service::debug == true
228
+ end
229
+
230
+ # Makes a HTTP POST.
231
+ def self.send_request(method, fields = {})
232
+ # See if method is given
233
+ raise ArgumentError, "Method should be given" if method.nil? || method.empty?
234
+
235
+ debug("** Remote method call: #{method}; fields: #{fields.inspect}")
236
+
237
+ # replace pesky hashes to prevent accidents
238
+ fields = fields.stringify_keys
239
+
240
+ # Complete fields with the method name
241
+ fields['method'] = method
242
+
243
+ fields.reject! { |k, v| v.nil? }
244
+
245
+ debug("** POST parameters: #{fields.inspect}")
246
+
247
+ # Create the connection
248
+ uri = URI.parse(Vuzit::Service.service_url)
249
+ http = Net::HTTP.new(uri.host, uri.port)
250
+
251
+ # API methods can be SLOW. Make sure this is set to something big to prevent spurious timeouts
252
+ http.read_timeout = 15 * 60
253
+
254
+ request = Net::HTTP::Post.new('/documents')
255
+ request.multipart_params = fields
256
+
257
+ tries = TRIES
258
+ begin
259
+ tries -= 1
260
+ res = http.request(request)
261
+ rescue Exception
262
+ $stderr.puts "Request encountered error, will retry #{tries} more."
263
+ if tries > 0
264
+ # Retrying several times with sleeps is recommended.
265
+ # This will prevent temporary downtimes at Scribd from breaking API applications
266
+ sleep(20)
267
+ retry
268
+ end
269
+ raise $!
270
+ end
271
+ return res
272
+ end
273
+
274
+ end
275
+
276
+ end
@@ -0,0 +1,33 @@
1
+
2
+ module Vuzit
3
+ # Vuzit library exception handler class.
4
+ class Exception < StandardError
5
+ # The web service error message
6
+ attr_reader :message
7
+
8
+ # The web service error code
9
+ attr_reader :code
10
+
11
+ # Constructor for errors.
12
+ #
13
+ # Example:
14
+ #
15
+ # begin
16
+ # doc = Vuzit::Document.find("DOCUMENT_ID")
17
+ # rescue Vuzit::Exception => ex
18
+ # puts "Error code: #{ex.code}, message: #{ex.message}"
19
+ # end
20
+ def initialize(message, code = 0)
21
+ @message = message
22
+ @code = code
23
+ end
24
+
25
+ # Returns the string representation of the error in this format:
26
+ #
27
+ # Vuzit::Exception: [CODE]: MESSAGE
28
+ def to_s
29
+ return "Vuzit::Exception: [#{@code}]: #{@message}";
30
+ end
31
+ end
32
+ end
33
+
@@ -0,0 +1,149 @@
1
+
2
+ require 'net/https'
3
+ require "rubygems"
4
+ require "mime/types" # Requires gem install mime-types
5
+ require "base64"
6
+ require 'cgi'
7
+ require 'md5'
8
+
9
+ module Net #:nodoc:all
10
+ # Enhances the HTTP::Post class for multi-part post transactions
11
+ class HTTP::Post
12
+ def multipart_params=(param_hash={})
13
+ boundary_token = [Array.new(8) {rand(256)}].join
14
+ self.content_type = "multipart/form-data; boundary=#{boundary_token}"
15
+ boundary_marker = "--#{boundary_token}\r\n"
16
+ self.body = param_hash.map { |param_name, param_value|
17
+ boundary_marker + case param_value
18
+ when File
19
+ file_to_multipart(param_name, param_value)
20
+ else
21
+ text_to_multipart(param_name, param_value.to_s)
22
+ end
23
+ }.join('') + "--#{boundary_token}--\r\n"
24
+ end
25
+
26
+ protected
27
+ def file_to_multipart(key,file)
28
+ filename = File.basename(file.path)
29
+ mime_types = MIME::Types.of(filename)
30
+ mime_type = mime_types.empty? ? "application/octet-stream" : mime_types.first.content_type
31
+ part = %Q|Content-Disposition: form-data; name="#{key}"; filename="#{filename}"\r\n|
32
+ part += "Content-Transfer-Encoding: binary\r\n"
33
+ part += "Content-Type: #{mime_type}\r\n\r\n#{file.read}\r\n"
34
+ end
35
+
36
+ def text_to_multipart(key,value)
37
+ "Content-Disposition: form-data; name=\"#{key}\"\r\n\r\n#{value}\r\n"
38
+ end
39
+ end
40
+ end
41
+
42
+ module Vuzit
43
+
44
+ # Global data class.
45
+ class Service
46
+ @@public_key = nil
47
+ @@private_key = nil
48
+ @@service_url = 'http://vuzit.com'
49
+ @@debug = false
50
+
51
+ # TODO: For all of the set variables do not allow nil values
52
+
53
+ # Sets the Vuzit public API key
54
+ def self.public_key=(value)
55
+ @@public_key = value
56
+ end
57
+
58
+ # Returns the Vuzit public API key
59
+ def self.public_key
60
+ @@public_key
61
+ end
62
+
63
+ # Sets Vuzit private API key. Do NOT share this with anyone!
64
+ def self.private_key=(value)
65
+ @@private_key = value
66
+ end
67
+
68
+ # Returns the Vuzit private API key. Do NOT share this with anyone!
69
+ def self.private_key
70
+ @@private_key
71
+ end
72
+
73
+ # Sets the URL of the Vuzit web service. This only needs to be changed if
74
+ # you are running Vuzit Enterprise on your own server.
75
+ # The default value is "http://vuzit.com"
76
+ def self.service_url=(value)
77
+ @@service_url = value
78
+ end
79
+
80
+ # Returns the URL of the Vuzit web service.
81
+ def self.service_url
82
+ @@service_url
83
+ end
84
+
85
+ # Switch this to _true_ if you would like to see debug messages in the
86
+ # output.
87
+ def self.debug=(value)
88
+ @@debug = value
89
+ end
90
+
91
+ # Returns whether debugging is turned on or off.
92
+ def self.debug
93
+ @@debug
94
+ end
95
+
96
+ # Returns The signature string. NOTE: If you are going to use this
97
+ # with the Vuzit Javascript API then the value must be encoded with the
98
+ # CGI.escape function. See the Wiki example for more information:
99
+ #
100
+ # http://wiki.github.com/vuzit/vuzitruby/code-samples
101
+ #
102
+ # Example:
103
+ #
104
+ # timestamp = Time.now
105
+ # sig = Vuzit::Service.get_signature("show", "DOCUMENT_ID", timestamp)
106
+ def self.get_signature(service, id = '', time = nil)
107
+ if Vuzit::Service.public_key == nil || Vuzit::Service.private_key == nil
108
+ raise Vuzit::Exception.new("The public_key or private_key variables are nil")
109
+ end
110
+ time = (time == nil) ? Time.now.to_i : time.to_i
111
+
112
+ if @@public_key == nil
113
+ raise Vuzit::Exception.new("Vuzit::Service.public_key not set")
114
+ end
115
+
116
+ if @@private_key == nil
117
+ raise Vuzit::Exception.new("Vuzit::Service.private_key not set")
118
+ end
119
+
120
+ msg = "#{service}#{id}#{@@public_key}#{time}"
121
+ hmac = hmac_sha1(@@private_key, msg)
122
+ result = Base64::encode64(hmac).chomp
123
+
124
+ return result
125
+ end
126
+
127
+ private
128
+
129
+ # Creates the SHA1 key.
130
+ def self.hmac_sha1(key, s)
131
+ ipad = [].fill(0x36, 0, 64)
132
+ opad = [].fill(0x5C, 0, 64)
133
+ key = key.unpack("C*")
134
+ key += [].fill(0, 0, 64-key.length) if key.length < 64
135
+
136
+ inner = []
137
+ 64.times { |i| inner.push(key[i] ^ ipad[i]) }
138
+ inner += s.unpack("C*")
139
+
140
+ outer = []
141
+ 64.times { |i| outer.push(key[i] ^ opad[i]) }
142
+ outer = outer.pack("c*")
143
+ outer += Digest::SHA1.digest(inner.pack("c*"))
144
+
145
+ return Digest::SHA1.digest(outer)
146
+ end
147
+ end
148
+ end
149
+
data/lib/vuzitruby.rb ADDED
@@ -0,0 +1,9 @@
1
+ $:.unshift(File.dirname(__FILE__))
2
+
3
+ # This prevents the "require 'some_gem'" error
4
+ require 'rubygems'
5
+
6
+ require 'vuzitruby/service'
7
+ require 'vuzitruby/document'
8
+ require 'vuzitruby/exception'
9
+
metadata ADDED
@@ -0,0 +1,59 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: vuzitruby
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Brent Matzelle
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-03-30 00:00:00 -04:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: This is a library for the Vuzit Web Services API. For more information on the platform, visit http://vuzit.com/developer
17
+ email: support@vuzit.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - README
24
+ files:
25
+ - README
26
+ - Rakefile
27
+ - lib/vuzitruby.rb
28
+ - lib/vuzitruby/document.rb
29
+ - lib/vuzitruby/exception.rb
30
+ - lib/vuzitruby/service.rb
31
+ has_rdoc: true
32
+ homepage: http://vuzit.com/
33
+ post_install_message:
34
+ rdoc_options:
35
+ - --main
36
+ - README
37
+ require_paths:
38
+ - lib
39
+ required_ruby_version: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: "0"
44
+ version:
45
+ required_rubygems_version: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: "0"
50
+ version:
51
+ requirements: []
52
+
53
+ rubyforge_project: vuzitruby
54
+ rubygems_version: 1.3.1
55
+ signing_key:
56
+ specification_version: 2
57
+ summary: Ruby client library for the Vuzit Web Services API
58
+ test_files: []
59
+