wash-out 0.10.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.rspec +1 -0
  4. data/.travis.yml +35 -0
  5. data/Appraisals +25 -0
  6. data/CHANGELOG.md +102 -0
  7. data/Gemfile +16 -0
  8. data/Guardfile +12 -0
  9. data/LICENSE +22 -0
  10. data/README.md +246 -0
  11. data/Rakefile +13 -0
  12. data/app/helpers/wash_out_helper.rb +106 -0
  13. data/app/views/wash_out/document/error.builder +9 -0
  14. data/app/views/wash_out/document/response.builder +10 -0
  15. data/app/views/wash_out/document/wsdl.builder +68 -0
  16. data/app/views/wash_out/rpc/error.builder +10 -0
  17. data/app/views/wash_out/rpc/response.builder +11 -0
  18. data/app/views/wash_out/rpc/wsdl.builder +68 -0
  19. data/gemfiles/rails_3.1.3.gemfile +20 -0
  20. data/gemfiles/rails_3.2.12.gemfile +20 -0
  21. data/gemfiles/rails_4.0.0.gemfile +19 -0
  22. data/gemfiles/rails_4.1.0.gemfile +19 -0
  23. data/gemfiles/rails_4.2.0.gemfile +19 -0
  24. data/gemfiles/rails_5.0.0.beta2.gemfile +19 -0
  25. data/init.rb +1 -0
  26. data/lib/wash_out.rb +53 -0
  27. data/lib/wash_out/configurable.rb +41 -0
  28. data/lib/wash_out/dispatcher.rb +218 -0
  29. data/lib/wash_out/engine.rb +12 -0
  30. data/lib/wash_out/middleware.rb +41 -0
  31. data/lib/wash_out/model.rb +29 -0
  32. data/lib/wash_out/param.rb +200 -0
  33. data/lib/wash_out/router.rb +95 -0
  34. data/lib/wash_out/soap.rb +48 -0
  35. data/lib/wash_out/soap_config.rb +93 -0
  36. data/lib/wash_out/type.rb +29 -0
  37. data/lib/wash_out/version.rb +3 -0
  38. data/lib/wash_out/wsse.rb +101 -0
  39. data/spec/dummy/Rakefile +7 -0
  40. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  41. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  42. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  43. data/spec/dummy/config.ru +4 -0
  44. data/spec/dummy/config/application.rb +51 -0
  45. data/spec/dummy/config/boot.rb +10 -0
  46. data/spec/dummy/config/environment.rb +5 -0
  47. data/spec/dummy/config/environments/development.rb +23 -0
  48. data/spec/dummy/config/environments/test.rb +30 -0
  49. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  50. data/spec/dummy/config/initializers/inflections.rb +10 -0
  51. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  52. data/spec/dummy/config/initializers/secret_token.rb +8 -0
  53. data/spec/dummy/config/initializers/session_store.rb +8 -0
  54. data/spec/dummy/config/locales/en.yml +5 -0
  55. data/spec/dummy/config/routes.rb +58 -0
  56. data/spec/dummy/public/404.html +26 -0
  57. data/spec/dummy/public/422.html +26 -0
  58. data/spec/dummy/public/500.html +26 -0
  59. data/spec/dummy/public/favicon.ico +0 -0
  60. data/spec/dummy/public/stylesheets/.gitkeep +0 -0
  61. data/spec/dummy/script/rails +6 -0
  62. data/spec/lib/wash_out/dispatcher_spec.rb +99 -0
  63. data/spec/lib/wash_out/middleware_spec.rb +33 -0
  64. data/spec/lib/wash_out/param_spec.rb +94 -0
  65. data/spec/lib/wash_out/router_spec.rb +22 -0
  66. data/spec/lib/wash_out/type_spec.rb +41 -0
  67. data/spec/lib/wash_out_spec.rb +754 -0
  68. data/spec/spec_helper.rb +82 -0
  69. data/wash_out.gemspec +21 -0
  70. metadata +128 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 7847d6250a06240d3f298c1062157159ab87e1dffb26201535632e081c1aaefe
4
+ data.tar.gz: 1c2408211e747e804ed54f1a5531e4b77c93d33dc82d6aa8ec84e8c7c97eabfd
5
+ SHA512:
6
+ metadata.gz: 2a4470c56ba059a8c0aabced0c6806eb4864b09edad54a125a44ddda9a561437da81ce3e1092ce73bcf792fcd60f63a61aff7da09bb97521252fd5d20b398394
7
+ data.tar.gz: 54448aafe1845dcb231b361683094fe14457b5a6f6a43be7f4c9d3bea4143f9cf847d7f46524a6b3b2bc8dee983a4e185aa3c530b40971cc0156664bf0cb5ed9
@@ -0,0 +1,17 @@
1
+ .rbx/
2
+ .bundle/
3
+ *.gem
4
+ .idea/
5
+ .ruby-gemset
6
+ .ruby-version
7
+ .rvmrc
8
+ *.swp
9
+ log/*.log
10
+ pkg/
11
+ spec/dummy/db/*.sqlite3
12
+ spec/dummy/log/*.log
13
+ spec/dummy/tmp/
14
+ gemfiles/*.lock
15
+ coverage
16
+ tags
17
+ Gemfile.lock
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --colour
@@ -0,0 +1,35 @@
1
+ script: bundle exec rspec
2
+ gemfile:
3
+ - gemfiles/rails_3.1.3.gemfile
4
+ - gemfiles/rails_3.2.12.gemfile
5
+ - gemfiles/rails_4.0.0.gemfile
6
+ - gemfiles/rails_4.1.0.gemfile
7
+ - gemfiles/rails_4.2.0.gemfile
8
+ - gemfiles/rails_5.0.0.beta2.gemfile
9
+ rvm:
10
+ - 1.9.3
11
+ - 2.0.0
12
+ - 2.1.8
13
+ - 2.2.4
14
+ - 2.3.0
15
+ - jruby
16
+ matrix:
17
+ exclude:
18
+ - rvm: 2.2.4
19
+ gemfile: gemfiles/rails_3.1.3.gemfile
20
+ - rvm: 2.2.4
21
+ gemfile: gemfiles/rails_3.2.12.gemfile
22
+ - rvm: 2.3.0
23
+ gemfile: gemfiles/rails_3.1.3.gemfile
24
+ - rvm: 2.3.0
25
+ gemfile: gemfiles/rails_3.2.12.gemfile
26
+ - rvm: 1.9.3
27
+ gemfile: gemfiles/rails_5.0.0.beta2.gemfile
28
+ - rvm: 2.0.0
29
+ gemfile: gemfiles/rails_5.0.0.beta2.gemfile
30
+ - rvm: 2.1.8
31
+ gemfile: gemfiles/rails_5.0.0.beta2.gemfile
32
+ - rvm: jruby
33
+ gemfile: gemfiles/rails_5.0.0.beta2.gemfile
34
+ before_install:
35
+ - gem update bundler
@@ -0,0 +1,25 @@
1
+ appraise "rails-3.1.3" do
2
+ gem "rails", "3.1.3"
3
+ gem "test-unit"
4
+ end
5
+
6
+ appraise "rails-3.2.12" do
7
+ gem "rails", "3.2.12"
8
+ gem "test-unit"
9
+ end
10
+
11
+ appraise "rails-4.0.0" do
12
+ gem "rails", "4.0.0"
13
+ end
14
+
15
+ appraise "rails-4.1.0" do
16
+ gem "rails", "4.1.0"
17
+ end
18
+
19
+ appraise "rails-4.2.0" do
20
+ gem "rails", "4.2.0"
21
+ end
22
+
23
+ appraise "rails-5.0.0.beta2" do
24
+ gem "rails", "5.0.0.beta2"
25
+ end
@@ -0,0 +1,102 @@
1
+ # Changelog
2
+
3
+ ## Not Supported!
4
+
5
+ This is here for historical reasons. Please refer to [Releases](https://github.com/inossidabile/wash_out/releases) page to get actual information.
6
+
7
+ ## 0.7.1
8
+
9
+ * Parser switcher [@inossidabile][]
10
+ * Namespaces support patched [@inossidabile][]
11
+
12
+ ## 0.7.0
13
+
14
+ * WSDL Document mode support [@gorism][]
15
+
16
+ ## 0.6.0
17
+
18
+ * Switched to Savon2 family [@inossidabile][]
19
+ * Main spec refactored greatly [@inossidabile][]
20
+
21
+ ## 0.5.4
22
+
23
+ * Ability to manually specify `response_tag` for `soap_action` [@inossidabile][]
24
+
25
+ ## 0.5.2
26
+
27
+ * .NET-compliant response tags [@ebeigarts][]
28
+ * Tiny fixes [@ebeigarts][]
29
+
30
+ ## 0.5.1
31
+
32
+ * Better routing points [@inossidabile][]
33
+
34
+ ## 0.5.0
35
+
36
+ * WSSE password authentication [@dhinus][]
37
+ * Ruby 1.8 compatibility restores [@dhinus][]
38
+
39
+ ## 0.4.2
40
+
41
+ * SOAP hrefs are now supported [@inossidabile][]
42
+ * Better camelization: reusable types and methods are now supported [@inossidabile][]
43
+
44
+ ## 0.4.1
45
+
46
+ * .NET-compliant :integer type WSDL [@inossidabile][]
47
+
48
+ ## 0.4.0
49
+
50
+ * Better content-type for the response (#33) [@inossidabile][]
51
+ * Date type support (#18) [@inossidabile][]
52
+ * Avoid duplication of inner types [@inossidabile][]
53
+ * Output camelization support [@inossidabile][]
54
+ * External types declaration support (#21, #41) [@inossidabile][]
55
+
56
+ ## 0.3.7
57
+
58
+ * Better empty parameters handling (#26, #30) [@rngtng][]
59
+
60
+ ## 0.3.6
61
+
62
+ * Unicorn stream reading bug (#20)
63
+ * .NET minOccurs/maxOccurs basic WSDL compatibility (#22, #23)
64
+
65
+ ## 0.3.5
66
+
67
+ * Very evil thread-safety bug fixed. You are encouraged to never use anything below this version.
68
+
69
+ ## 0.3.4
70
+
71
+ * WSDL generation fixed to support complex structures for return values
72
+ * Configuration moved to OrderedOptions with proper Engine binding
73
+ * `snakecase` configuration directive added: if set to false, wash_out won't modify params keys
74
+
75
+ ## 0.3.3
76
+
77
+ * Tiny fixes in wash_out behavior with inline arrays (#11, #12)
78
+ * Ability to change namespace
79
+
80
+ ## 0.3.2
81
+
82
+ * WashOut doesn't check existance of parameters anymore you should do it yourself from now
83
+ * Proper handling of blank parameters (#10)
84
+ * Proper handling of complex structures inside arrays (#9)
85
+ * Response performance improved
86
+
87
+ ## 0.3.1
88
+
89
+ * Support of complex structures inside array
90
+ * Better Nori handling (no more dependency on Savon hijacking)
91
+
92
+ ## 0.3.0
93
+
94
+ * The syntax for empty set (no input params or output params) changed from [] to nil.
95
+ * SOAP response format improved. All results are now wrapped into tns:messages instead of soap:Body.
96
+ * Arrays (minOccurs/maxOccurs) are now supported with `:foo => [:integer]` syntax.
97
+
98
+ [@inossidabile]: http://staal.io
99
+ [@rngtng]: https://github.com/rngtng
100
+ [@dhinus]: https://github.com/dhinus
101
+ [@ebeigarts]: https://github.com/ebeigarts
102
+ [@gorism]: https://github.com/gorism
data/Gemfile ADDED
@@ -0,0 +1,16 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ gem 'appraisal'
6
+ gem 'guard'
7
+ gem 'guard-rspec'
8
+ gem 'httpi'
9
+ gem 'pry'
10
+ gem 'rb-fsevent'
11
+ gem 'rspec-rails'
12
+ gem 'savon', '>= 2.0.0'
13
+ gem 'simplecov'
14
+ gem 'simplecov-summary'
15
+ gem 'tzinfo'
16
+ gem 'wasabi'
@@ -0,0 +1,12 @@
1
+ # More info at https://github.com/guard/guard#readme
2
+
3
+ # Could be changed to whatever you want.
4
+ # See: https://github.com/guard/guard#notification
5
+ notification :off
6
+
7
+ guard 'rspec' do
8
+ watch %r{^spec/.+_spec\.rb$}
9
+ watch %r{lib/} do 'spec' end
10
+ end
11
+
12
+ # vim:ft=ruby
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License
2
+
3
+ Copyright (c) 2012 Round Lake, inc.,
4
+ Peter Zotov <whitequark@whitequark.org>.
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in
14
+ all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
+ THE SOFTWARE.
@@ -0,0 +1,246 @@
1
+ # WashOut
2
+
3
+ WashOut is a gem that greatly simplifies creation of SOAP service providers.
4
+
5
+ [![Gem Version](https://badge.fury.io/rb/wash_out.png)](http://badge.fury.io/rb/wash_out)
6
+ [![Travis CI](https://secure.travis-ci.org/inossidabile/wash_out.png)](https://travis-ci.org/inossidabile/wash_out)
7
+ [![Code Climate](https://codeclimate.com/github/inossidabile/wash_out.png)](https://codeclimate.com/github/inossidabile/wash_out)
8
+
9
+ But if you have a chance, please [http://stopsoap.com/](http://stopsoap.com/).
10
+
11
+ ## Compatibility
12
+
13
+ Rails >3.0 only. MRI 1.9, 2.0, JRuby (--1.9).
14
+
15
+ Ruby 1.8 is not officially supported since 0.5.3. We will accept further compatibilty pull-requests but no upcoming versions will be tested against it.
16
+
17
+ Rubinius support temporarily dropped since 0.6.2 due to Rails 4 incompatibility.
18
+
19
+ ## Installation
20
+
21
+ In your Gemfile, add this line:
22
+
23
+ gem 'wash_out'
24
+
25
+ Please read [release details](https://github.com/inossidabile/wash_out/releases) if you are upgrading. We break backward compatibility between large ticks but you can expect it to be specified at release notes.
26
+
27
+ ## Usage
28
+
29
+ A SOAP endpoint in WashOut is simply a Rails controller which includes the module WashOut::SOAP. Each SOAP
30
+ action corresponds to a certain controller method; this mapping, as well as the argument definition, is defined
31
+ by [soap_action][] method. Check the method documentation for complete info; here, only a few examples will be
32
+ demonstrated.
33
+
34
+ [soap_action]: http://rubydoc.info/gems/wash_out/WashOut/SOAP/ClassMethods#soap_action-instance_method
35
+
36
+ ```ruby
37
+ # app/controllers/rumbas_controller.rb
38
+ class RumbasController < ApplicationController
39
+ soap_service namespace: 'urn:WashOut'
40
+
41
+ # Simple case
42
+ soap_action "integer_to_string",
43
+ :args => :integer,
44
+ :return => :string
45
+ def integer_to_string
46
+ render :soap => params[:value].to_s
47
+ end
48
+
49
+ soap_action "concat",
50
+ :args => { :a => :string, :b => :string },
51
+ :return => :string
52
+ def concat
53
+ render :soap => (params[:a] + params[:b])
54
+ end
55
+
56
+ # Complex structures
57
+ soap_action "AddCircle",
58
+ :args => { :circle => { :center => { :x => :integer,
59
+ :y => :integer },
60
+ :radius => :double } },
61
+ :return => nil, # [] for wash_out below 0.3.0
62
+ :to => :add_circle
63
+ def add_circle
64
+ circle = params[:circle]
65
+
66
+ raise SOAPError, "radius is too small" if circle[:radius] < 3.0
67
+
68
+ Circle.new(circle[:center][:x], circle[:center][:y], circle[:radius])
69
+
70
+ render :soap => nil
71
+ end
72
+
73
+ # Arrays
74
+ soap_action "integers_to_boolean",
75
+ :args => { :data => [:integer] },
76
+ :return => [:boolean]
77
+ def integers_to_boolean
78
+ render :soap => params[:data].map{|x| x ? 1 : 0}
79
+ end
80
+
81
+ # Params from XML attributes;
82
+ # e.g. for a request to the 'AddCircle' action:
83
+ # <soapenv:Envelope>
84
+ # <soapenv:Body>
85
+ # <AddCircle>
86
+ # <Circle radius="5.0">
87
+ # <Center x="10" y="12" />
88
+ # </Circle>
89
+ # </AddCircle>
90
+ # </soapenv:Body>
91
+ # </soapenv:Envelope>
92
+ soap_action "AddCircle",
93
+ :args => { :circle => { :center => { :@x => :integer,
94
+ :@y => :integer },
95
+ :@radius => :double } },
96
+ :return => nil, # [] for wash_out below 0.3.0
97
+ :to => :add_circle
98
+ def add_circle
99
+ circle = params[:circle]
100
+ Circle.new(circle[:center][:x], circle[:center][:y], circle[:radius])
101
+
102
+ render :soap => nil
103
+ end
104
+
105
+ # With a customised input tag name, in case params are wrapped;
106
+ # e.g. for a request to the 'IntegersToBoolean' action:
107
+ # <soapenv:Envelope>
108
+ # <soapenv:Body>
109
+ # <MyRequest> <!-- not <IntegersToBoolean> -->
110
+ # <Data>...</Data>
111
+ # </MyRequest>
112
+ # </soapenv:Body>
113
+ # </soapenv:Envelope>
114
+ soap_action "integers_to_boolean",
115
+ :args => { :my_request => { :data => [:integer] } },
116
+ :as => 'MyRequest',
117
+ :return => [:boolean]
118
+
119
+ # You can use all Rails features like filtering, too. A SOAP controller
120
+ # is just like a normal controller with a special routing.
121
+ before_filter :dump_parameters
122
+ def dump_parameters
123
+ Rails.logger.debug params.inspect
124
+ end
125
+ end
126
+ ```
127
+
128
+ ```ruby
129
+ # config/routes.rb
130
+ WashOutSample::Application.routes.draw do
131
+ wash_out :rumbas
132
+ end
133
+ ```
134
+
135
+ In such a setup, the generated WSDL may be queried at path `/rumbas/wsdl`. So, with a
136
+ gem like Savon, a request can be done using this path:
137
+
138
+ ```ruby
139
+ require 'savon'
140
+
141
+ client = Savon::Client.new(wsdl: "http://localhost:3000/rumbas/wsdl")
142
+
143
+ client.operations # => [:integer_to_string, :concat, :add_circle]
144
+
145
+ result = client.call(:concat, message: { :a => "123", :b => "abc" })
146
+
147
+ # actual wash_out
148
+ result.to_hash # => {:concat_reponse => {:value=>"123abc"}}
149
+
150
+ # wash_out below 0.3.0 (and this is malformed response so please update)
151
+ result.to_hash # => {:value=>"123abc"}
152
+ ```
153
+
154
+ ## Reusable types
155
+
156
+ Basic inline types definition is fast and furious for the simple cases. You have an option to describe SOAP types
157
+ inside separate classes for the complex ones. Here's the way to do that:
158
+
159
+ ```ruby
160
+ class Fluffy < WashOut::Type
161
+ map :universe => {
162
+ :name => :string,
163
+ :age => :int
164
+ }
165
+ end
166
+
167
+ class FluffyContainer < WashOut::Type
168
+ type_name 'fluffy_con'
169
+ map :fluffy => Fluffy
170
+ end
171
+ ```
172
+
173
+ To use defined type inside your inline declaration, pass the class instead of type symbol (`:fluffy => Fluffy`).
174
+
175
+ Note that WashOut extends the `ActiveRecord` so every model you use is already a WashOut::Type and can be used
176
+ inside your interface declarations.
177
+
178
+ ## WSSE Authentication
179
+
180
+ WashOut provides two mechanism for WSSE Authentication.
181
+
182
+ ### Static Authentication
183
+
184
+ You can configure the service to validate against a username and password with the following configuration:
185
+
186
+ ```ruby
187
+ soap_service namespace: "wash_out", wsse_username: "username", wsse_password: "password"
188
+ ```
189
+
190
+ With this mechanism, all the actions in the controller will be authenticated against the specified username and password. If you need to authenticate different users, you can use the dynamic mechanism described below.
191
+
192
+ ### Dynamic Authentication
193
+
194
+ Dynamic authentication allows you to process the username and password any way you want, with the most common case being authenticating against a database. The configuration option for this mechanism is called `wsse_auth_callback`:
195
+
196
+ ```ruby
197
+ soap_service namespace: "wash_out", wsse_auth_callback: ->(username, password) {
198
+ return !User.find_by(username: username).authenticate(password).blank?
199
+ }
200
+ ```
201
+
202
+ Keep in mind that the password may already be hashed by the SOAP client, so you would have to check against that condition too as per [spec](http://www.oasis-open.org/committees/download.php/16782/wss-v1.1-spec-os-UsernameTokenProfile.pdf)
203
+
204
+ ## Configuration
205
+
206
+ Use `config.wash_out...` inside your environment configuration to setup WashOut globally.
207
+ To override the values on a specific controller just add an override as part of the arguments to the `soap_service` method.
208
+
209
+ Available properties are:
210
+
211
+ * **parser**: XML parser to use – `:rexml` or `:nokogiri`. The first one is default but the latter is much faster. Be sure to add `gem nokogiri` if you want to use it.
212
+ * **wsdl_style**: sets WSDL style. Supported values are: 'document' and 'rpc'.
213
+ * **catch_xml_errors**: intercept Rails parsing exceptions to return correct XML response for corrupt XML input. Default is `false`.
214
+ * **namespace**: SOAP namespace to use. Default is `urn:WashOut`.
215
+ * **snakecase_input**: Determines if WashOut should modify parameters keys to snakecase. Default is `false`.
216
+ * **camelize_wsdl**: Determines if WashOut should camelize types within WSDL and responses. Supports `true` for CamelCase and `:lower` for camelCase. Default is `false`.
217
+
218
+ ### Camelization
219
+
220
+ Note that WSDL camelization will affect method names but only if they were given as a symbol:
221
+
222
+ ```ruby
223
+ soap_action :foo # this will be affected
224
+ soap_action "foo" # this will be passed as is
225
+ ```
226
+
227
+ ## Maintainers
228
+
229
+ * Boris Staal, [@inossidabile](http://staal.io)
230
+
231
+ ## Contributors (in random order)
232
+
233
+ * Mikael Henriksson, [@mhenrixon](http://twitter.com/mhenrixon)
234
+ * Björn Nilsson [@Bjorn-Nilsson](https://github.com/Bjorn-Nilsson)
235
+ * Tobias Bielohlawek [@rngtng](https://github.com/rngtng)
236
+ * Francesco Negri [@dhinus](https://github.com/dhinus)
237
+ * Edgars Beigarts [@ebeigarts](https://github.com/ebeigarts)
238
+ * [Exad](https://github.com/exad) [@wknechtel](https://github.com/wknechtel) and [@☈king](https://github.com/rking)
239
+ * Mark Goris [@gorism](https://github.com/gorism)
240
+ * ... and [others](https://github.com/inossidabile/wash_out/graphs/contributors)
241
+
242
+ ## License
243
+
244
+ It is free software, and may be redistributed under the terms of MIT license.
245
+
246
+ [![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/inossidabile/wash_out/trend.png)](https://bitdeli.com/free "Bitdeli Badge")