waz-storage 1.2.0 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. data/.gitignore +9 -9
  2. data/CHANGELOG.rdoc +72 -72
  3. data/Gemfile +4 -4
  4. data/Gemfile.lock +46 -40
  5. data/LICENSE +18 -18
  6. data/README.rdoc +310 -310
  7. data/lib/waz-blobs.rb +4 -4
  8. data/lib/waz-queues.rb +6 -6
  9. data/lib/waz-storage.rb +39 -39
  10. data/lib/waz-tables.rb +4 -4
  11. data/lib/waz/blobs/blob_object.rb +122 -122
  12. data/lib/waz/blobs/container.rb +172 -161
  13. data/lib/waz/blobs/exceptions.rb +10 -10
  14. data/lib/waz/blobs/service.rb +181 -156
  15. data/lib/waz/queues/exceptions.rb +28 -28
  16. data/lib/waz/queues/message.rb +64 -64
  17. data/lib/waz/queues/queue.rb +164 -164
  18. data/lib/waz/queues/service.rb +105 -105
  19. data/lib/waz/storage/base.rb +70 -70
  20. data/lib/waz/storage/exceptions.rb +33 -33
  21. data/lib/waz/storage/validation_rules.rb +25 -25
  22. data/lib/waz/tables/edm_type_helper.rb +44 -44
  23. data/lib/waz/tables/exceptions.rb +44 -44
  24. data/lib/waz/tables/service.rb +178 -178
  25. data/lib/waz/tables/table.rb +74 -74
  26. data/lib/waz/tables/table_array.rb +10 -10
  27. data/rakefile +8 -21
  28. data/{tests → spec}/configuration.rb +22 -22
  29. data/{tests/waz/blobs/blob_object_test.rb → spec/waz/blobs/blob_object_spec.rb} +80 -80
  30. data/{tests/waz/blobs/container_test.rb → spec/waz/blobs/container_spec.rb} +175 -162
  31. data/{tests/waz/blobs/service_test.rb → spec/waz/blobs/service_spec.rb} +336 -282
  32. data/{tests/waz/queues/message_test.rb → spec/waz/queues/message_spec.rb} +32 -32
  33. data/{tests/waz/queues/queue_test.rb → spec/waz/queues/queue_spec.rb} +205 -205
  34. data/{tests/waz/queues/service_test.rb → spec/waz/queues/service_spec.rb} +298 -298
  35. data/{tests → spec}/waz/storage/base_tests.rb +81 -81
  36. data/{tests/waz/storage/shared_key_core_service_test.rb → spec/waz/storage/shared_key_core_service_spec.rb} +141 -141
  37. data/{tests/waz/tables/service_test.rb → spec/waz/tables/service_spec.rb} +613 -613
  38. data/{tests/waz/tables/table_test.rb → spec/waz/tables/table_spec.rb} +97 -97
  39. data/waz-storage.gemspec +29 -27
  40. metadata +47 -26
data/.gitignore CHANGED
@@ -1,9 +1,9 @@
1
- tests/waz/func/*.rb
2
- coverage
3
- pkg/*
4
- rdoc/*
5
- sdk/*
6
- sdk
7
- .rvmrc
8
- vendor/
9
- .bundle
1
+ tests/waz/func/*.rb
2
+ coverage
3
+ pkg/*
4
+ rdoc/*
5
+ sdk/*
6
+ sdk
7
+ .rvmrc
8
+ vendor/
9
+ .bundle
data/CHANGELOG.rdoc CHANGED
@@ -1,72 +1,72 @@
1
- = Revision History for Windows Azure Storage for Ruby
2
- === v1.1 - (smarx)
3
- - Upload from stream, plus XML/URI escaping in various places, and a few other minor fixes
4
- - Add upload method to container
5
- - Add put_block_list to support upload
6
- - Fix message canonicalization of ?comp= parameters for versions prior to 2009-09-19 (seems put_block was broken)
7
- - Unescape query string parameters when constructing signatures (needed for put_block, since some base64-encoded names include non-URI-friendly characters)
8
- - XML-escape property values for table entities (needed to insert things containing &, <, etc.)
9
- - Remove Unicode characters from rakefile (was breaking something on Windows)
10
- - Add tests for put_block_list and upload
11
- - Fix tests for content type (typo, = instead of .should ==)
12
- - Fix tests using RestClient.beautify_headers (expects an array, not a scalar)
13
-
14
- === v1.0.6 - (hermes.logicalbricks)
15
- - Update tests to rspec 2.5.0
16
- - Allow authorization using only SharedAccessSignature
17
-
18
- === v1.0.5 - (tomconte)
19
- - Fixed for list_blobs as it wasn't fully merged to 2009-09-19. Now it works without 403 exceptions
20
-
21
- === v1.0.3 - (Johnny Halife)
22
- - Merged with sriramk fix for loading path issues on some environments
23
-
24
- === v1.0.2 - (Johnny Halife)
25
- - Completed Blobs API migration to 2009-09-19, _fully supporting_ what third-party tools does (e.g. Cerebrata) [thanks percent20]
26
-
27
- === v1.0.1 - (Johnny halife)
28
- - Added syntax's sugar for ensuring a queue (get or create)
29
-
30
- === v1.0 - (Juan Pablo Garcia Dalolla)
31
- - Added support for table service to query, get_one, insert, update, merge and delete entities.
32
- - Added support for running against the Storage Developement Fabriq shipped with Microsoft SDK.
33
- - Added signature support for Tables service according to msdn.microsoft.com/en-us/library/dd179428.aspx
34
- - Added support to enumerate, create, and delete tables on give storage account.
35
- - Improved support for stacked connection management.
36
-
37
- === v0.5.81 - (Johnny Halife)
38
- - When simulating a container using a forward slash starting the blob name it crashed with 404, now it's fixed.
39
-
40
- === v0.5.8 - (Johnny Halife)
41
- - Fixed an issue on the Queues Documentation (thanks @ezequielm)
42
- - Added _naming validation for Containers_ according to http://msdn.microsoft.com/en-us/library/dd135715.aspx (thanks @panosjee)
43
- - Added _naming validation for Queues_ according to http://msdn.microsoft.com/en-us/library/dd179349.aspx (thanks @panosjee)
44
- - Added _support for Blob snapshots_
45
- - Added support for rest-client 1.3.0. (thanks @jpgd)
46
-
47
- === v0.5.7 - (Johnny Halife)
48
- - Fixes a critical bug on URL management that some time prevents message from being deleted, caused by a missing encoding on the URL parameters.
49
-
50
- === v0.5.6 - (Johnny Halife)
51
- - Added signature support for 2009-09-19 Version of the Storage API
52
- - Queues API has been migrated to the 2009-09-19 Version of the Storage API
53
- - Added a new parameter for listing queues with metadata
54
- - Added support for DequeueCount on messages being retrieved from the Queue
55
- - <strong>Known Issue</strong>: Creating a queue multiple times with same metadata throws 409.
56
-
57
- === v0.5.5 - (Johnny Halife)
58
- - Added a Change Log
59
- - Added support for copy-blob [WAZ::Blobs::BlobObject.copy("container/blob_name")]
60
- - Refactored out the whole request logic to an _execute_ method on the SharedKeyCoreService
61
- - Added transparent support for block management (users don't know if their blob is being uploaded chunked or not)
62
- - Added support for a blob to list its blocks
63
-
64
- === v0.5.4 - Sat Oct 17 19:35:48 2009 -0300 (Johnny Halife)
65
- - Fixed method name for String.start_with? (previously starts_with?)
66
-
67
- === v0.5.3 - Sat Oct 17 18:20:51 2009 -0300 (Johnny Halife)
68
- - Added the stack-based contextual connection handling (WAZ::Storage::Base.establish_connection {|block| }
69
- - Added string extensions for non rails environments (and work to work on heroku) String.starts_with?
70
-
71
- === v0.5.2 - Thu Oct 15 22:08:01 2009 -0300 (Johnny Halife)
72
- - Initial Version
1
+ = Revision History for Windows Azure Storage for Ruby
2
+ === v1.1 - (smarx)
3
+ - Upload from stream, plus XML/URI escaping in various places, and a few other minor fixes
4
+ - Add upload method to container
5
+ - Add put_block_list to support upload
6
+ - Fix message canonicalization of ?comp= parameters for versions prior to 2009-09-19 (seems put_block was broken)
7
+ - Unescape query string parameters when constructing signatures (needed for put_block, since some base64-encoded names include non-URI-friendly characters)
8
+ - XML-escape property values for table entities (needed to insert things containing &, <, etc.)
9
+ - Remove Unicode characters from rakefile (was breaking something on Windows)
10
+ - Add tests for put_block_list and upload
11
+ - Fix tests for content type (typo, = instead of .should ==)
12
+ - Fix tests using RestClient.beautify_headers (expects an array, not a scalar)
13
+
14
+ === v1.0.6 - (hermes.logicalbricks)
15
+ - Update tests to rspec 2.5.0
16
+ - Allow authorization using only SharedAccessSignature
17
+
18
+ === v1.0.5 - (tomconte)
19
+ - Fixed for list_blobs as it wasn't fully merged to 2009-09-19. Now it works without 403 exceptions
20
+
21
+ === v1.0.3 - (Johnny Halife)
22
+ - Merged with sriramk fix for loading path issues on some environments
23
+
24
+ === v1.0.2 - (Johnny Halife)
25
+ - Completed Blobs API migration to 2009-09-19, _fully supporting_ what third-party tools does (e.g. Cerebrata) [thanks percent20]
26
+
27
+ === v1.0.1 - (Johnny halife)
28
+ - Added syntax's sugar for ensuring a queue (get or create)
29
+
30
+ === v1.0 - (Juan Pablo Garcia Dalolla)
31
+ - Added support for table service to query, get_one, insert, update, merge and delete entities.
32
+ - Added support for running against the Storage Developement Fabriq shipped with Microsoft SDK.
33
+ - Added signature support for Tables service according to msdn.microsoft.com/en-us/library/dd179428.aspx
34
+ - Added support to enumerate, create, and delete tables on give storage account.
35
+ - Improved support for stacked connection management.
36
+
37
+ === v0.5.81 - (Johnny Halife)
38
+ - When simulating a container using a forward slash starting the blob name it crashed with 404, now it's fixed.
39
+
40
+ === v0.5.8 - (Johnny Halife)
41
+ - Fixed an issue on the Queues Documentation (thanks @ezequielm)
42
+ - Added _naming validation for Containers_ according to http://msdn.microsoft.com/en-us/library/dd135715.aspx (thanks @panosjee)
43
+ - Added _naming validation for Queues_ according to http://msdn.microsoft.com/en-us/library/dd179349.aspx (thanks @panosjee)
44
+ - Added _support for Blob snapshots_
45
+ - Added support for rest-client 1.3.0. (thanks @jpgd)
46
+
47
+ === v0.5.7 - (Johnny Halife)
48
+ - Fixes a critical bug on URL management that some time prevents message from being deleted, caused by a missing encoding on the URL parameters.
49
+
50
+ === v0.5.6 - (Johnny Halife)
51
+ - Added signature support for 2009-09-19 Version of the Storage API
52
+ - Queues API has been migrated to the 2009-09-19 Version of the Storage API
53
+ - Added a new parameter for listing queues with metadata
54
+ - Added support for DequeueCount on messages being retrieved from the Queue
55
+ - <strong>Known Issue</strong>: Creating a queue multiple times with same metadata throws 409.
56
+
57
+ === v0.5.5 - (Johnny Halife)
58
+ - Added a Change Log
59
+ - Added support for copy-blob [WAZ::Blobs::BlobObject.copy("container/blob_name")]
60
+ - Refactored out the whole request logic to an _execute_ method on the SharedKeyCoreService
61
+ - Added transparent support for block management (users don't know if their blob is being uploaded chunked or not)
62
+ - Added support for a blob to list its blocks
63
+
64
+ === v0.5.4 - Sat Oct 17 19:35:48 2009 -0300 (Johnny Halife)
65
+ - Fixed method name for String.start_with? (previously starts_with?)
66
+
67
+ === v0.5.3 - Sat Oct 17 18:20:51 2009 -0300 (Johnny Halife)
68
+ - Added the stack-based contextual connection handling (WAZ::Storage::Base.establish_connection {|block| }
69
+ - Added string extensions for non rails environments (and work to work on heroku) String.starts_with?
70
+
71
+ === v0.5.2 - Thu Oct 15 22:08:01 2009 -0300 (Johnny Halife)
72
+ - Initial Version
data/Gemfile CHANGED
@@ -1,4 +1,4 @@
1
- source 'https://rubygems.org'
2
-
3
- # Specify your gem's dependencies in waz-storage.gemspec
4
- gemspec
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in waz-storage.gemspec
4
+ gemspec
data/Gemfile.lock CHANGED
@@ -1,40 +1,46 @@
1
- PATH
2
- remote: .
3
- specs:
4
- waz-storage (1.1.2)
5
- rest-client
6
- ruby-hmac
7
-
8
- GEM
9
- remote: https://rubygems.org/
10
- specs:
11
- diff-lcs (1.1.3)
12
- metaclass (0.0.1)
13
- mime-types (1.19)
14
- mocha (0.10.5)
15
- metaclass (~> 0.0.1)
16
- multi_json (1.5.0)
17
- rest-client (1.6.7)
18
- mime-types (>= 1.16)
19
- rspec (2.9.0)
20
- rspec-core (~> 2.9.0)
21
- rspec-expectations (~> 2.9.0)
22
- rspec-mocks (~> 2.9.0)
23
- rspec-core (2.9.0)
24
- rspec-expectations (2.9.1)
25
- diff-lcs (~> 1.1.3)
26
- rspec-mocks (2.9.0)
27
- ruby-hmac (0.4.0)
28
- simplecov (0.7.1)
29
- multi_json (~> 1.0)
30
- simplecov-html (~> 0.7.1)
31
- simplecov-html (0.7.1)
32
-
33
- PLATFORMS
34
- ruby
35
-
36
- DEPENDENCIES
37
- mocha
38
- rspec
39
- simplecov
40
- waz-storage!
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ waz-storage (1.2.0)
5
+ rest-client
6
+ ruby-hmac
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ diff-lcs (1.1.3)
12
+ json (1.7.5)
13
+ metaclass (0.0.1)
14
+ mime-types (1.19)
15
+ mocha (0.10.5)
16
+ metaclass (~> 0.0.1)
17
+ multi_json (1.5.0)
18
+ rake (10.0.2)
19
+ rdoc (3.12)
20
+ json (~> 1.4)
21
+ rest-client (1.6.7)
22
+ mime-types (>= 1.16)
23
+ rspec (2.9.0)
24
+ rspec-core (~> 2.9.0)
25
+ rspec-expectations (~> 2.9.0)
26
+ rspec-mocks (~> 2.9.0)
27
+ rspec-core (2.9.0)
28
+ rspec-expectations (2.9.1)
29
+ diff-lcs (~> 1.1.3)
30
+ rspec-mocks (2.9.0)
31
+ ruby-hmac (0.4.0)
32
+ simplecov (0.7.1)
33
+ multi_json (~> 1.0)
34
+ simplecov-html (~> 0.7.1)
35
+ simplecov-html (0.7.1)
36
+
37
+ PLATFORMS
38
+ ruby
39
+
40
+ DEPENDENCIES
41
+ mocha
42
+ rake
43
+ rdoc
44
+ rspec
45
+ simplecov
46
+ waz-storage!
data/LICENSE CHANGED
@@ -1,19 +1,19 @@
1
- Copyright (c) 2009 Johnny G. Halife
2
-
3
- Permission is hereby granted, free of charge, to any person obtaining a copy
4
- of this software and associated documentation files (the "Software"), to deal
5
- in the Software without restriction, including without limitation the rights
6
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
- copies of the Software, and to permit persons to whom the Software is
8
- furnished to do so, subject to the following conditions:
9
-
10
- The above copyright notice and this permission notice shall be included in
11
- all copies or substantial portions of the Software.
12
-
13
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
1
+ Copyright (c) 2009 Johnny G. Halife
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
19
  THE SOFTWARE.
data/README.rdoc CHANGED
@@ -1,310 +1,310 @@
1
- = Windows Azure Storage library — simple gem for accessing WAZ‘s Storage REST API
2
- A simple implementation of Windows Azure Storage API for Ruby, inspired by the S3 gems and self experience of dealing with queues. The major
3
- goal of the whole gem is to enable ruby developers [like me =)] to leverage Windows Azure Storage features and have another option
4
- for cloud storage.
5
-
6
- The whole gem is implemented based on Microsoft's specs from the communication and underlying service description and protocol (REST). The API
7
- is for ruby developers built by a ruby developer. I'm trying to follow idioms, patterns and fluent type of doing APIs on Ruby.
8
-
9
- This work isn't related at all with StorageClient Sample shipped with Microsoft SDK and written in .NET, the whole API is based on my own understanding,
10
- experience and values of elegance and ruby development.
11
-
12
- Full documentation for the gem is available at http://waz-storage.heroku.com
13
-
14
- === How does this differ from <em>waz-queues</em> and <em>waz-blobs</em> work?
15
- Well, this is a sum up of the whole experience of writing those gems and getting them to work together to simplify
16
- end user experience. Although there're some breaking changes, it's pretty backward compatible with existing gems.
17
-
18
- === What's new on v1.1.4?
19
- - Fixes an issue with Double Encoding (thanks Phil Ibis!)
20
-
21
- === What's new on v1.1.2?
22
-
23
- The main difference with the original library is the adding of the method "railsetag".
24
- This method add to any blob object an "x_ms_meta_railsetag" header, its value is calculated as the rails etag way (Digest::MD5.hexdigest(file))
25
-
26
- By doing so we can easily know if a locale copy of a file is up-to-date on Azure CDN.
27
- This is very much used in the "waz-sync" gem which purpose is to sync file between local storage and Azure.
28
-
29
- === What's new on the v1.1 version? [thanks to smarx]
30
- - Upload from stream, plus XML/URI escaping in various places, and a few other minor fixes
31
- - Add upload method to container
32
- - Add put_block_list to support upload
33
- - Fix message canonicalization of ?comp= parameters for versions prior to 2009-09-19 (seems put_block was broken)
34
- - Unescape query string parameters when constructing signatures (needed for put_block, since some base64-encoded names include non-URI-friendly characters)
35
- - XML-escape property values for table entities (needed to insert things containing &, <, etc.)
36
- - Remove Unicode characters from rakefile (was breaking something on Windows)
37
- - Add tests for put_block_list and upload
38
- - Fix tests for content type (typo, = instead of .should ==)
39
- - Fix tests using RestClient.beautify_headers (expects an array, not a scalar)
40
-
41
- === What's new on the v1.0.6 version? [thanks to hermes.logicalbricks]
42
- - Update tests to rspec 2.5.0
43
- - Allow authorization using only SharedAccessSignature
44
-
45
- === What's new on the version version?
46
- - Fixed for list_blobs as it wasn't fully merged to 2009-09-19. Now it works without 403 exceptions [Thanks tomconte]
47
-
48
- === What's new on the v1.0.3 version?
49
- - Merged with sriramk fix for loading path issues on some environments
50
-
51
- === What's new on the 1.0.2 version?
52
- - Completed Blobs API migration to 2009-09-19, _fully supporting_ what third-party tools does (e.g. Cerebrata) [thanks percent20]
53
-
54
- === What's new on the 1.0.1 version?
55
- - Added Syntax's sugar for ensuring a Queue (get or create)
56
-
57
- === What's new on the 1.0 version?
58
- - Added support for table service to query, get_one, insert, update, merge and delete entities.
59
- - Added support for running against the Storage Developement Fabriq shipped with Microsoft SDK.
60
- - Added signature support for Tables service according to msdn.microsoft.com/en-us/library/dd179428.aspx
61
- - Added support to enumerate, create, and delete tables on give storage account.
62
- - Improved support for stacked connection management.
63
-
64
- === What's new on the 0.5.81 version?
65
- - When simulating a container using a forward slash starting the blob name it crashed with 404, now it's fixed.
66
-
67
- === What's new on the 0.5.8 version?
68
- - Fixed an issue on the Queues Documentation (thanks @ezequielm)
69
- - Added <b>naming validation for Containers</b> according to http://msdn.microsoft.com/en-us/library/dd135715.aspx (thanks @panosjee)
70
- - Added <b>naming validation for Queues</b> according to http://msdn.microsoft.com/en-us/library/dd179349.aspx (thanks @panosjee)
71
- - Added <b>support for Blob snapshots</b>
72
- - Added support for rest-client 1.3.0. (thanks @jpgd)
73
-
74
- === What's new on the 0.5.7 version?
75
- - Fixes a critical bug on URL management that some time prevents messages from being deleted, caused by a missing encoding on the URL parameters.
76
-
77
- === What's new on the 0.5.6 version?
78
- - Added new <b>shared key authentication support for 2009-09-19 Version of the Storage API</b>
79
- - Queues API has been migrated to the <b>2009-09-19 Version of the Storage API</b>
80
- - Added a new parameter for <b>listing queues with metadata</b>
81
- - Added support for <b>DequeueCount</b> on messages being retrieved from the Queue
82
- - <b>Known Issue</b>: Creating a queue multiple times with same metadata throws 409.
83
-
84
- == Getting started
85
- sudo gem install waz-storage --source http://gemcutter.org
86
-
87
- == Basic Configuration
88
- One of the major changes from the waz-queues and waz-blobs APIs was the ability to set a single storage account (99% of the cases) to be
89
- used on your code just once. Since Windows Azure Storage Services are all related to a single account that includes Tables, Queues and Blobs,
90
- I've changed the API in order to make ease that administration by requiring you to set the configuration just once:
91
-
92
- require 'waz-queues' #=> if you want to use queues
93
- require 'waz-blobs' #=> if you want to use blobs (or you can include both for using both)
94
-
95
- WAZ::Storage::Base.establish_connection!(:account_name => account_name,
96
- :access_key => access_key)
97
-
98
- As you can see you, the way to get started it pretty simple, just include the establish_connection! call on your application bootstrapper, for example
99
- if you are doing a sinatra-rb application it can be
100
-
101
- configure :production do
102
- # here is were you hook up with WAZ Storage Stuff.
103
- end
104
-
105
- That's all you need to get started and running your Windows Azure Code on a sinatra application.
106
-
107
- == Usage: Queues
108
- Windows Azure Queues are extremely powerful for asyc programming, they are very useful when you don’t need "always consistent"
109
- data operations allowing you to enqueue and process on background. It’s important to mention that being WAZ-Queues a buffered
110
- message system, you should design for idempotent operations given the fact that there’s no guarantee that a message can be repeated.
111
-
112
- The implementation of the Windows Azure Queues REST API available online at http://msdn.microsoft.com/en-us/library/dd179363.aspx is fully
113
- covered here.
114
-
115
- Here's a quick getting started of the usage of the API:
116
-
117
- WAZ::Storage::Base.establish_connection!(:account_name => account_name,
118
- :access_key => access_key)
119
-
120
- # NEW! Now you can do ensure and it will return the queue, first trying to retrieve it
121
- # and then if it doesn't exist, will created it
122
- queue = WAZ::Queues::Queue.ensure('my-queue')
123
-
124
- # excepts that the metadata for the queue changes this method behaves as PUT (create/replace)
125
- # remarks: it performs a validation whether metadata changed or not (if changed HTTP 409 conflict)
126
- queue = WAZ::Queues::Queue.create('my-queue')
127
-
128
- 10.times do |m|
129
- # enqueue a receives string. Message content can be anything up to 8KB
130
- # you can serialize and send anything that serializes to UTF-8 string (JSON, XML, etc)
131
- queue.enqueue!("message##{m}")
132
- end
133
-
134
- while(queue.size > 0) do
135
- # Since WAZ implements the peek lock pattern we are locking messages (not dequeuing)
136
- # it has two parameters how many messages and for how long they are locked
137
- messages = queue.lock(10)
138
-
139
- puts "dequeued message: #{messages.size}"
140
-
141
- # deletes the message from the queue so other clients do not pick it after
142
- # visibility time out expires
143
- messages.each {|m| m.destroy!}
144
- end
145
-
146
- It's pretty intuitive, but full documentation (RDoc) is available for the API for further reference.
147
-
148
- == Usage: Blobs
149
- The blobs implementation inside this gem is fully compliant with the spec available at http://msdn.microsoft.com/en-us/library/dd135733.aspx. The Windows
150
- Azure Blobs REST API isn't fully covered here (see TODO's for more information). It's pretty usable and stable right now,
151
- I've been doing lot of testing around and it works seamlessly with the current Windows Azure implementation.
152
-
153
- require 'waz-blobs'
154
-
155
- WAZ::Storage::Base.establish_connection!(:account_name => account_name,
156
- :access_key => access_key)
157
-
158
- # creates a container
159
- container = WAZ::Blobs::Container.create('my-container')
160
-
161
- # stores a blob with custom properties (metadata)
162
- blob = container.store('my_blob.txt',
163
- 'this is the content of my blob',
164
- 'plain/text',
165
- {:x_ms_meta_Custom_Property => "custom_value" })
166
-
167
- # return a specific blob from a container
168
- blob = container['my_blob.txt']
169
-
170
- # retrieves a blob value
171
- blob.value
172
-
173
- It's pretty intuitive, but full documentation (RDoc) is available for the API for further reference.
174
-
175
- === Using Blob with Shared Acess Signature
176
- This feature allow to access a blob only with the information of the blob's name, the container, and the Shared Access Signature. If you don't have permission to perform an action (for example: list the blobs, create a new blob or something like that) you will receive an exception. If you want more details about this: http://msdn.microsoft.com/en-us/library/ee395415.aspx
177
-
178
- require 'waz-blobs'
179
-
180
- WAZ::Storage::Base.establish_connection!(:account_name=> 'mysharedblob',
181
- :use_sas_auth_only=> true,
182
- :sharedaccesssignature =>"?se=XXXXXX&sr=c&si=XXXXX&sig=XXXXXXXXXXXXXXXXXXXXX")
183
-
184
- container = WAZ::Blobs::Container.new(:name=>'container')
185
-
186
- blob = container.store('myfile.txt',File.read('fileofthecontent.txt'),'plain/text')
187
-
188
- The feature was only tested storing a blob.
189
-
190
- == Usage: Tables
191
- The tables implementation inside this gem is fully compliant with the spec available at http://msdn.microsoft.com/en-us/library/dd179423.aspx. The Windows
192
- Azure Tables REST API is fully covered here.
193
-
194
- require 'waz-storage'
195
- require 'waz-tables'
196
-
197
- WAZ::Storage::Base.establish_connection!(:account_name => account_name,
198
- :access_key => access_key)
199
-
200
- # creates a new table
201
- table = WAZ::Tables::Table.create('my-table')
202
-
203
- # list available tables
204
- # (returns a maximum of 1,000 items at one time (more details here: http://msdn.microsoft.com/en-us/library/dd135718.aspx)
205
- tables = WAZ::Tables::Table.list
206
-
207
- # more tables
208
- WAZ::Tables::Table.list(tables.continuation_token)
209
-
210
- # get a specific table, returning nil when the specified table is not found
211
- my_table = WAZ::Tables::Table.find('my-table')
212
-
213
- # table properties
214
- my_table.name
215
- my_table.url
216
-
217
- # delete a table
218
- my_table.destroy!
219
-
220
- # Entity operations using the Table service
221
-
222
- # get the existing service instance
223
- service = WAZ::Tables::Table.service_instance
224
-
225
- # define a new entity
226
- entity = { :address => 'Mountain View',
227
- :age => 23,
228
- :amount_due => 200.23,
229
- :binary_data => File.open(__FILE__),
230
- :customer_code => 'aaaaaaaa-bbbb-cccc-dddd-aaaabbbbcccc',
231
- :customer_since => Time.now.utc,
232
- :is_active => true,
233
- :num_of_orders => 255,
234
- :partition_key => 'customer',
235
- :row_key => "myRowKey#{rand(2000000).to_s}",
236
- :Timestamp => Time.now.utc }
237
-
238
- # inserts a new entity
239
- service.insert_entity('customer_table', entity)
240
-
241
- # retrieves all entities from a table
242
- # (returns a maximum of 1,000 items at one time (more details here: http://msdn.microsoft.com/en-us/library/dd135718.aspx)
243
- # Remarks on development storage it retrieves all items instead the first 1,000
244
- entities = service.query('customer_table')
245
-
246
- # retrieves more entities providing the obtained continuation_token
247
- service.query('customer_table', {:continuation_token => entities.continuation_token} )
248
-
249
- # retrieves all records that match with the specified query but only the first fifteen rows
250
- service.query('customer_table', {:expression => "(PartitionKey eq 'customer') and (Age eq 23)", :top => 15} )
251
-
252
- # get an existing entity by its partion_key and row_key
253
- entity = service.get_entity('customer_table', 'customer', 'rowKey1')
254
-
255
- # updates an entity
256
- entity[:age] = 90
257
- service.update_entity('customer_table', new_entity)
258
-
259
- # merges an entity (more details here: http://msdn.microsoft.com/en-us/library/dd179392.aspx)
260
- entity[:age] = 20
261
- service.merge_entity('customer_table', new_entity)
262
-
263
- # deletes an entity
264
- service.delete_entity('customer_table', 'customer', 'rowKey1')
265
-
266
- It's pretty intuitive, but full documentation (RDoc) is available for the API for further reference.
267
-
268
- == Usage: Contextual Connection Handling
269
- Sometimes while you are building a web application you may require handling different storage account but contextualized. The sample
270
- that comes to my mind is something like a Storage Explorer or Account Monitor for WAZ.
271
-
272
- That is why? I've added a new way of handling a stack-based contextual connection handling. The usage is pretty simple:
273
-
274
- WAZ::Storage::Base.establish_connection(options) do
275
- container = WAZ::Blobs::Container.find('container-name')
276
- blob = container['blob-name']
277
- blob.destroy!
278
- end
279
-
280
- As it is described on the example above, there's a new way of establishing a connection and use it on a given block. The whole implementation
281
- is stack based, and will let you scope your context for some rare cases where you have another account.
282
-
283
- *Disclaimer*: Moving objects across context isn't contemplated yet, and if you try to do changes among scopes you will get
284
- to some wired Windows Azure Errors regarding objects that may not exist.
285
-
286
- === Remarks
287
- Windows Azure Storage API works flawlessly from Heroku and custom ruby hosting deployments on EC2, as far as I tested it. You can leverage the storage
288
- services without the need of having to write the application on .NET or hosting your application on Windows Azure.
289
-
290
- The documentation and implementation exposed here is for the pre-release version and is subject to change on the future.
291
-
292
- === TODO's
293
- As far as users start using it, I'll be building a backlog and probably handling a wish-list of features, but right now I've the following
294
- TODO's already enqueued for further releases of the waz-storage API.
295
-
296
- -Generate a sample application to better show the usage.
297
-
298
- The things listed above do not represent any sort of priority, or the order they are going to be tackled. It's just a list.
299
-
300
- == Meta
301
-
302
- Written by Johnny G. Halife (johnny.halife at me dot com)
303
-
304
- contributed by: Ezequiel Morito (http://twitter.com/ezequielm), Juan Pablo Garcia (http://twitter.com/jpgd), Steve Marx (http://twitter.com/smarx), G. Montard (http://github.com/gmontard)
305
-
306
- Released under the MIT License: http://www.opensource.org/licenses/mit-license.php
307
-
308
- http://waz-storage.heroku.com
309
-
310
- http://github.com/johnnyhalife/waz-storage
1
+ = Windows Azure Storage library — simple gem for accessing WAZ‘s Storage REST API
2
+ A simple implementation of Windows Azure Storage API for Ruby, inspired by the S3 gems and self experience of dealing with queues. The major
3
+ goal of the whole gem is to enable ruby developers [like me =)] to leverage Windows Azure Storage features and have another option
4
+ for cloud storage.
5
+
6
+ The whole gem is implemented based on Microsoft's specs from the communication and underlying service description and protocol (REST). The API
7
+ is for ruby developers built by a ruby developer. I'm trying to follow idioms, patterns and fluent type of doing APIs on Ruby.
8
+
9
+ This work isn't related at all with StorageClient Sample shipped with Microsoft SDK and written in .NET, the whole API is based on my own understanding,
10
+ experience and values of elegance and ruby development.
11
+
12
+ Full documentation for the gem is available at http://waz-storage.heroku.com
13
+
14
+ === How does this differ from <em>waz-queues</em> and <em>waz-blobs</em> work?
15
+ Well, this is a sum up of the whole experience of writing those gems and getting them to work together to simplify
16
+ end user experience. Although there're some breaking changes, it's pretty backward compatible with existing gems.
17
+
18
+ === What's new on v1.1.4?
19
+ - Fixes an issue with Double Encoding (thanks Phil Ibis!)
20
+
21
+ === What's new on v1.1.2?
22
+
23
+ The main difference with the original library is the adding of the method "railsetag".
24
+ This method add to any blob object an "x_ms_meta_railsetag" header, its value is calculated as the rails etag way (Digest::MD5.hexdigest(file))
25
+
26
+ By doing so we can easily know if a locale copy of a file is up-to-date on Azure CDN.
27
+ This is very much used in the "waz-sync" gem which purpose is to sync file between local storage and Azure.
28
+
29
+ === What's new on the v1.1 version? [thanks to smarx]
30
+ - Upload from stream, plus XML/URI escaping in various places, and a few other minor fixes
31
+ - Add upload method to container
32
+ - Add put_block_list to support upload
33
+ - Fix message canonicalization of ?comp= parameters for versions prior to 2009-09-19 (seems put_block was broken)
34
+ - Unescape query string parameters when constructing signatures (needed for put_block, since some base64-encoded names include non-URI-friendly characters)
35
+ - XML-escape property values for table entities (needed to insert things containing &, <, etc.)
36
+ - Remove Unicode characters from rakefile (was breaking something on Windows)
37
+ - Add tests for put_block_list and upload
38
+ - Fix tests for content type (typo, = instead of .should ==)
39
+ - Fix tests using RestClient.beautify_headers (expects an array, not a scalar)
40
+
41
+ === What's new on the v1.0.6 version? [thanks to hermes.logicalbricks]
42
+ - Update tests to rspec 2.5.0
43
+ - Allow authorization using only SharedAccessSignature
44
+
45
+ === What's new on the version version?
46
+ - Fixed for list_blobs as it wasn't fully merged to 2009-09-19. Now it works without 403 exceptions [Thanks tomconte]
47
+
48
+ === What's new on the v1.0.3 version?
49
+ - Merged with sriramk fix for loading path issues on some environments
50
+
51
+ === What's new on the 1.0.2 version?
52
+ - Completed Blobs API migration to 2009-09-19, _fully supporting_ what third-party tools does (e.g. Cerebrata) [thanks percent20]
53
+
54
+ === What's new on the 1.0.1 version?
55
+ - Added Syntax's sugar for ensuring a Queue (get or create)
56
+
57
+ === What's new on the 1.0 version?
58
+ - Added support for table service to query, get_one, insert, update, merge and delete entities.
59
+ - Added support for running against the Storage Developement Fabriq shipped with Microsoft SDK.
60
+ - Added signature support for Tables service according to msdn.microsoft.com/en-us/library/dd179428.aspx
61
+ - Added support to enumerate, create, and delete tables on give storage account.
62
+ - Improved support for stacked connection management.
63
+
64
+ === What's new on the 0.5.81 version?
65
+ - When simulating a container using a forward slash starting the blob name it crashed with 404, now it's fixed.
66
+
67
+ === What's new on the 0.5.8 version?
68
+ - Fixed an issue on the Queues Documentation (thanks @ezequielm)
69
+ - Added <b>naming validation for Containers</b> according to http://msdn.microsoft.com/en-us/library/dd135715.aspx (thanks @panosjee)
70
+ - Added <b>naming validation for Queues</b> according to http://msdn.microsoft.com/en-us/library/dd179349.aspx (thanks @panosjee)
71
+ - Added <b>support for Blob snapshots</b>
72
+ - Added support for rest-client 1.3.0. (thanks @jpgd)
73
+
74
+ === What's new on the 0.5.7 version?
75
+ - Fixes a critical bug on URL management that some time prevents messages from being deleted, caused by a missing encoding on the URL parameters.
76
+
77
+ === What's new on the 0.5.6 version?
78
+ - Added new <b>shared key authentication support for 2009-09-19 Version of the Storage API</b>
79
+ - Queues API has been migrated to the <b>2009-09-19 Version of the Storage API</b>
80
+ - Added a new parameter for <b>listing queues with metadata</b>
81
+ - Added support for <b>DequeueCount</b> on messages being retrieved from the Queue
82
+ - <b>Known Issue</b>: Creating a queue multiple times with same metadata throws 409.
83
+
84
+ == Getting started
85
+ sudo gem install waz-storage --source http://gemcutter.org
86
+
87
+ == Basic Configuration
88
+ One of the major changes from the waz-queues and waz-blobs APIs was the ability to set a single storage account (99% of the cases) to be
89
+ used on your code just once. Since Windows Azure Storage Services are all related to a single account that includes Tables, Queues and Blobs,
90
+ I've changed the API in order to make ease that administration by requiring you to set the configuration just once:
91
+
92
+ require 'waz-queues' #=> if you want to use queues
93
+ require 'waz-blobs' #=> if you want to use blobs (or you can include both for using both)
94
+
95
+ WAZ::Storage::Base.establish_connection!(:account_name => account_name,
96
+ :access_key => access_key)
97
+
98
+ As you can see you, the way to get started it pretty simple, just include the establish_connection! call on your application bootstrapper, for example
99
+ if you are doing a sinatra-rb application it can be
100
+
101
+ configure :production do
102
+ # here is were you hook up with WAZ Storage Stuff.
103
+ end
104
+
105
+ That's all you need to get started and running your Windows Azure Code on a sinatra application.
106
+
107
+ == Usage: Queues
108
+ Windows Azure Queues are extremely powerful for asyc programming, they are very useful when you don’t need "always consistent"
109
+ data operations allowing you to enqueue and process on background. It’s important to mention that being WAZ-Queues a buffered
110
+ message system, you should design for idempotent operations given the fact that there’s no guarantee that a message can be repeated.
111
+
112
+ The implementation of the Windows Azure Queues REST API available online at http://msdn.microsoft.com/en-us/library/dd179363.aspx is fully
113
+ covered here.
114
+
115
+ Here's a quick getting started of the usage of the API:
116
+
117
+ WAZ::Storage::Base.establish_connection!(:account_name => account_name,
118
+ :access_key => access_key)
119
+
120
+ # NEW! Now you can do ensure and it will return the queue, first trying to retrieve it
121
+ # and then if it doesn't exist, will created it
122
+ queue = WAZ::Queues::Queue.ensure('my-queue')
123
+
124
+ # excepts that the metadata for the queue changes this method behaves as PUT (create/replace)
125
+ # remarks: it performs a validation whether metadata changed or not (if changed HTTP 409 conflict)
126
+ queue = WAZ::Queues::Queue.create('my-queue')
127
+
128
+ 10.times do |m|
129
+ # enqueue a receives string. Message content can be anything up to 8KB
130
+ # you can serialize and send anything that serializes to UTF-8 string (JSON, XML, etc)
131
+ queue.enqueue!("message##{m}")
132
+ end
133
+
134
+ while(queue.size > 0) do
135
+ # Since WAZ implements the peek lock pattern we are locking messages (not dequeuing)
136
+ # it has two parameters how many messages and for how long they are locked
137
+ messages = queue.lock(10)
138
+
139
+ puts "dequeued message: #{messages.size}"
140
+
141
+ # deletes the message from the queue so other clients do not pick it after
142
+ # visibility time out expires
143
+ messages.each {|m| m.destroy!}
144
+ end
145
+
146
+ It's pretty intuitive, but full documentation (RDoc) is available for the API for further reference.
147
+
148
+ == Usage: Blobs
149
+ The blobs implementation inside this gem is fully compliant with the spec available at http://msdn.microsoft.com/en-us/library/dd135733.aspx. The Windows
150
+ Azure Blobs REST API isn't fully covered here (see TODO's for more information). It's pretty usable and stable right now,
151
+ I've been doing lot of testing around and it works seamlessly with the current Windows Azure implementation.
152
+
153
+ require 'waz-blobs'
154
+
155
+ WAZ::Storage::Base.establish_connection!(:account_name => account_name,
156
+ :access_key => access_key)
157
+
158
+ # creates a container
159
+ container = WAZ::Blobs::Container.create('my-container')
160
+
161
+ # stores a blob with custom properties (metadata)
162
+ blob = container.store('my_blob.txt',
163
+ 'this is the content of my blob',
164
+ 'plain/text',
165
+ {:x_ms_meta_Custom_Property => "custom_value" })
166
+
167
+ # return a specific blob from a container
168
+ blob = container['my_blob.txt']
169
+
170
+ # retrieves a blob value
171
+ blob.value
172
+
173
+ It's pretty intuitive, but full documentation (RDoc) is available for the API for further reference.
174
+
175
+ === Using Blob with Shared Acess Signature
176
+ This feature allow to access a blob only with the information of the blob's name, the container, and the Shared Access Signature. If you don't have permission to perform an action (for example: list the blobs, create a new blob or something like that) you will receive an exception. If you want more details about this: http://msdn.microsoft.com/en-us/library/ee395415.aspx
177
+
178
+ require 'waz-blobs'
179
+
180
+ WAZ::Storage::Base.establish_connection!(:account_name=> 'mysharedblob',
181
+ :use_sas_auth_only=> true,
182
+ :sharedaccesssignature =>"?se=XXXXXX&sr=c&si=XXXXX&sig=XXXXXXXXXXXXXXXXXXXXX")
183
+
184
+ container = WAZ::Blobs::Container.new(:name=>'container')
185
+
186
+ blob = container.store('myfile.txt',File.read('fileofthecontent.txt'),'plain/text')
187
+
188
+ The feature was only tested storing a blob.
189
+
190
+ == Usage: Tables
191
+ The tables implementation inside this gem is fully compliant with the spec available at http://msdn.microsoft.com/en-us/library/dd179423.aspx. The Windows
192
+ Azure Tables REST API is fully covered here.
193
+
194
+ require 'waz-storage'
195
+ require 'waz-tables'
196
+
197
+ WAZ::Storage::Base.establish_connection!(:account_name => account_name,
198
+ :access_key => access_key)
199
+
200
+ # creates a new table
201
+ table = WAZ::Tables::Table.create('my-table')
202
+
203
+ # list available tables
204
+ # (returns a maximum of 1,000 items at one time (more details here: http://msdn.microsoft.com/en-us/library/dd135718.aspx)
205
+ tables = WAZ::Tables::Table.list
206
+
207
+ # more tables
208
+ WAZ::Tables::Table.list(tables.continuation_token)
209
+
210
+ # get a specific table, returning nil when the specified table is not found
211
+ my_table = WAZ::Tables::Table.find('my-table')
212
+
213
+ # table properties
214
+ my_table.name
215
+ my_table.url
216
+
217
+ # delete a table
218
+ my_table.destroy!
219
+
220
+ # Entity operations using the Table service
221
+
222
+ # get the existing service instance
223
+ service = WAZ::Tables::Table.service_instance
224
+
225
+ # define a new entity
226
+ entity = { :address => 'Mountain View',
227
+ :age => 23,
228
+ :amount_due => 200.23,
229
+ :binary_data => File.open(__FILE__),
230
+ :customer_code => 'aaaaaaaa-bbbb-cccc-dddd-aaaabbbbcccc',
231
+ :customer_since => Time.now.utc,
232
+ :is_active => true,
233
+ :num_of_orders => 255,
234
+ :partition_key => 'customer',
235
+ :row_key => "myRowKey#{rand(2000000).to_s}",
236
+ :Timestamp => Time.now.utc }
237
+
238
+ # inserts a new entity
239
+ service.insert_entity('customer_table', entity)
240
+
241
+ # retrieves all entities from a table
242
+ # (returns a maximum of 1,000 items at one time (more details here: http://msdn.microsoft.com/en-us/library/dd135718.aspx)
243
+ # Remarks on development storage it retrieves all items instead the first 1,000
244
+ entities = service.query('customer_table')
245
+
246
+ # retrieves more entities providing the obtained continuation_token
247
+ service.query('customer_table', {:continuation_token => entities.continuation_token} )
248
+
249
+ # retrieves all records that match with the specified query but only the first fifteen rows
250
+ service.query('customer_table', {:expression => "(PartitionKey eq 'customer') and (Age eq 23)", :top => 15} )
251
+
252
+ # get an existing entity by its partion_key and row_key
253
+ entity = service.get_entity('customer_table', 'customer', 'rowKey1')
254
+
255
+ # updates an entity
256
+ entity[:age] = 90
257
+ service.update_entity('customer_table', new_entity)
258
+
259
+ # merges an entity (more details here: http://msdn.microsoft.com/en-us/library/dd179392.aspx)
260
+ entity[:age] = 20
261
+ service.merge_entity('customer_table', new_entity)
262
+
263
+ # deletes an entity
264
+ service.delete_entity('customer_table', 'customer', 'rowKey1')
265
+
266
+ It's pretty intuitive, but full documentation (RDoc) is available for the API for further reference.
267
+
268
+ == Usage: Contextual Connection Handling
269
+ Sometimes while you are building a web application you may require handling different storage account but contextualized. The sample
270
+ that comes to my mind is something like a Storage Explorer or Account Monitor for WAZ.
271
+
272
+ That is why? I've added a new way of handling a stack-based contextual connection handling. The usage is pretty simple:
273
+
274
+ WAZ::Storage::Base.establish_connection(options) do
275
+ container = WAZ::Blobs::Container.find('container-name')
276
+ blob = container['blob-name']
277
+ blob.destroy!
278
+ end
279
+
280
+ As it is described on the example above, there's a new way of establishing a connection and use it on a given block. The whole implementation
281
+ is stack based, and will let you scope your context for some rare cases where you have another account.
282
+
283
+ *Disclaimer*: Moving objects across context isn't contemplated yet, and if you try to do changes among scopes you will get
284
+ to some wired Windows Azure Errors regarding objects that may not exist.
285
+
286
+ === Remarks
287
+ Windows Azure Storage API works flawlessly from Heroku and custom ruby hosting deployments on EC2, as far as I tested it. You can leverage the storage
288
+ services without the need of having to write the application on .NET or hosting your application on Windows Azure.
289
+
290
+ The documentation and implementation exposed here is for the pre-release version and is subject to change on the future.
291
+
292
+ === TODO's
293
+ As far as users start using it, I'll be building a backlog and probably handling a wish-list of features, but right now I've the following
294
+ TODO's already enqueued for further releases of the waz-storage API.
295
+
296
+ -Generate a sample application to better show the usage.
297
+
298
+ The things listed above do not represent any sort of priority, or the order they are going to be tackled. It's just a list.
299
+
300
+ == Meta
301
+
302
+ Written by Johnny G. Halife (johnny.halife at me dot com)
303
+
304
+ contributed by: Ezequiel Morito (http://twitter.com/ezequielm), Juan Pablo Garcia (http://twitter.com/jpgd), Steve Marx (http://twitter.com/smarx), G. Montard (http://github.com/gmontard)
305
+
306
+ Released under the MIT License: http://www.opensource.org/licenses/mit-license.php
307
+
308
+ http://waz-storage.heroku.com
309
+
310
+ http://github.com/johnnyhalife/waz-storage