capistrano_mailer 3.2.7 → 3.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,22 @@
1
+ <%= @site_name %> Notification
2
+ ===========================================================
3
+
4
+ <%= @site_name %> <%=@task_name.titleize unless @task_name.nil? %>
5
+ ===========================================================
6
+ Brought to you by: Capistrano Mailer - http://github.com/pboling/capistrano_mailer
7
+ Released: <%= @date %> at <%= @time %>
8
+
9
+ <%= @sections.map { |section|
10
+ data = @section_data[section.to_sym]
11
+ if !data.empty?
12
+ if %w(extra_information release_data).include?(section)
13
+ render :partial => 'section_custom.text.erb', :locals => {:section_title => section, :data => data}
14
+ else
15
+ render :partial => 'section.text.erb', :locals => {:section_title => section, :data => data}
16
+ end
17
+ end
18
+ }.join unless @sections.nil? %>
19
+
20
+ ===========================================================
21
+ Copyright 2009 9thBit LLC under MIT License
22
+ Copyright 2007-8 Sagebit LLC under MIT License
@@ -1,31 +1,31 @@
1
- <div style="margin: 20px; padding: 0 0 20px 0;">
2
-
3
- <h2 style="margin: 0px; padding: 10px 10px 5px 10px; background: #eee; border-left: 10px solid #ccc; color: #333;">
4
- <%= section_title.titleize unless section_title.nil? -%>
5
- </h2>
6
- <% if data.is_a?(Array) then data = data[0] end -%>
7
- <% arr = case section_title
8
- when 'deployment'
9
- [:date,:time,:rails_env,:task_name,:inferred_command,:host,:release_name]
10
- when 'source_control'
11
- [:scm,:released,:branch,:revision,:deploy_via,:deploy_to,:repository]
12
- when 'latest_release'
13
- [:latest_release,:latest_revision,:real_revision,:release_path,:current_path]
14
- when 'previous_release'
15
- [:current_release,:current_revision,:previous_release,:previous_revision,:releases]
16
- when 'other_deployment_info'
17
- [:ip_address,:run_method,:source,:strategy,:version_dir,:shared_dir,:current_dir,:releases_path,:shared_path]
18
- end -%>
19
- <% if !arr.nil? && arr.is_a?(Array) %>
20
- <% arr.each do |key| -%>
21
- <% if key.is_a?(Symbol) && !data[key].nil?-%>
22
- <p style="margin: 10px; padding: 0px;">
23
- <span style="float:left; width:150px; padding: 10px 10px 0;"><%= key.to_s.titleize %></span>
24
- <span style="float:left; width:490px; padding: 10px 10px 0;"><%= data[key].is_a?(Array) ? data[key].to_sentence : data[key].is_a?(String) ? data[key] : data[key].inspect %></span>
25
- </p>
26
- <% end -%>
27
- <% end -%>
28
- <% end -%>
29
- <p style="clear:both"></p>
30
-
31
- </div>
1
+ <div style="margin: 20px; padding: 0 0 20px 0;">
2
+
3
+ <h2 style="margin: 0px; padding: 10px 10px 5px 10px; background: #eee; border-left: 10px solid #ccc; color: #333;">
4
+ <%= section_title.titleize unless section_title.nil? -%>
5
+ </h2>
6
+ <% if data.is_a?(Array) then data = data[0] end -%>
7
+ <% arr = case section_title
8
+ when 'deployment'
9
+ [:date,:time,:rails_env,:task_name,:inferred_command,:host,:release_name,:release_notes]
10
+ when 'source_control'
11
+ [:scm,:released,:branch,:revision,:deploy_via,:deploy_to,:repository]
12
+ when 'latest_release'
13
+ [:latest_release,:latest_revision,:real_revision,:release_path,:current_path]
14
+ when 'previous_release'
15
+ [:current_release,:current_revision,:previous_release,:previous_revision,:releases]
16
+ when 'other_deployment_info'
17
+ [:ip_address,:run_method,:source,:strategy,:version_dir,:shared_dir,:current_dir,:releases_path,:shared_path]
18
+ end -%>
19
+ <% if !arr.nil? && arr.is_a?(Array) %>
20
+ <% arr.each do |key| -%>
21
+ <% if key.is_a?(Symbol) && !data[key].nil?-%>
22
+ <p style="margin: 10px; padding: 0px;">
23
+ <span style="float:left; width:150px; padding: 10px 10px 0;"><%= key.to_s.titleize %></span>
24
+ <span style="float:left; width:490px; padding: 10px 10px 0;"><%= data[key].is_a?(Array) ? data[key].to_sentence : data[key].is_a?(String) ? data[key] : data[key].inspect %></span>
25
+ </p>
26
+ <% end -%>
27
+ <% end -%>
28
+ <% end -%>
29
+ <p style="clear:both"></p>
30
+
31
+ </div>
@@ -1,23 +1,23 @@
1
- <%= section_title.titleize unless section_title.nil? -%>
2
- ===========================================================
3
-
4
- <% if data.is_a?(Array) then data = data[0] end -%>
5
- <% arr = case section_title
6
- when 'deployment'
7
- [:date,:time,:rails_env,:task,:inferred_command,:host,:release_name]
8
- when 'source_control'
9
- [:scm,:released,:branch,:revision,:deploy_via,:deploy_to,:repository]
10
- when 'latest_release'
11
- [:latest_release,:latest_revision,:real_revision,:release_path,:current_path]
12
- when 'previous_release'
13
- [:current_release,:current_revision,:previous_release,:previous_revision,:releases]
14
- when 'other_deployment_info'
15
- [:ip_address,:run_method,:source,:strategy,:version_dir,:shared_dir,:current_dir,:releases_path,:shared_path]
16
- end -%>
17
- <% if !arr.nil? && arr.is_a?(Array) %>
18
- <% arr.each do |key| -%>
19
- <% if key.is_a?(Symbol) && !data[key].nil?-%>
20
- <%= key.to_s.titleize %> <%= data[key].is_a?(Array) ? data[key].to_sentence : data[key].is_a?(String) ? data[key] : data[key].inspect %>
21
- <% end -%>
22
- <% end -%>
23
- <% end -%>
1
+ <%= section_title.titleize unless section_title.nil? -%>
2
+ ===========================================================
3
+
4
+ <% if data.is_a?(Array) then data = data[0] end -%>
5
+ <% arr = case section_title
6
+ when 'deployment'
7
+ [:date,:time,:rails_env,:task,:inferred_command,:host,:release_name,:release_notes]
8
+ when 'source_control'
9
+ [:scm,:released,:branch,:revision,:deploy_via,:deploy_to,:repository]
10
+ when 'latest_release'
11
+ [:latest_release,:latest_revision,:real_revision,:release_path,:current_path]
12
+ when 'previous_release'
13
+ [:current_release,:current_revision,:previous_release,:previous_revision,:releases]
14
+ when 'other_deployment_info'
15
+ [:ip_address,:run_method,:source,:strategy,:version_dir,:shared_dir,:current_dir,:releases_path,:shared_path]
16
+ end -%>
17
+ <% if !arr.nil? && arr.is_a?(Array) %>
18
+ <% arr.each do |key| -%>
19
+ <% if key.is_a?(Symbol) && !data[key].nil?-%>
20
+ <%= key.to_s.titleize %> <%= data[key].is_a?(Array) ? data[key].to_sentence : data[key].is_a?(String) ? data[key] : data[key].inspect %>
21
+ <% end -%>
22
+ <% end -%>
23
+ <% end -%>
@@ -7,9 +7,10 @@
7
7
  <p style="margin: 10px; padding: 0px;">
8
8
  <span style="float:left; width:150px; padding: 10px 10px 0;"><%= key %></span>
9
9
  <span style="float:left; width:490px; padding: 10px 10px 0;"><%= value.is_a?(Array) ? value.to_sentence : value.is_a?(String) ? value : value.inspect%></span>
10
+ <span style="clear: both;"></span>
10
11
  </p>
11
12
  <% end -%>
12
13
  <% end unless data.nil?-%>
13
14
  <p style="clear:both"></p>
14
-
15
+
15
16
  </div>
@@ -0,0 +1 @@
1
+ <%= render "message_body" %>
@@ -0,0 +1 @@
1
+ <%= render "message_body" %>
@@ -0,0 +1 @@
1
+ <%= render "message_body" %>
@@ -0,0 +1 @@
1
+ <%= render "message_body" %>
metadata CHANGED
@@ -1,73 +1,136 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: capistrano_mailer
3
- version: !ruby/object:Gem::Version
4
- version: 3.2.7
3
+ version: !ruby/object:Gem::Version
4
+ hash: 11
5
5
  prerelease:
6
+ segments:
7
+ - 3
8
+ - 3
9
+ - 0
10
+ version: 3.3.0
6
11
  platform: ruby
7
- authors:
12
+ authors:
8
13
  - Peter Boling
9
14
  - Dave Nolan
10
15
  autorequire:
11
16
  bindir: bin
12
17
  cert_chain: []
13
- date: 2011-12-12 00:00:00.000000000Z
14
- dependencies:
15
- - !ruby/object:Gem::Dependency
16
- name: actionmailer
17
- requirement: &70359182869000 !ruby/object:Gem::Requirement
18
+
19
+ date: 2014-03-21 00:00:00 Z
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: capistrano-log_with_awesome
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
18
25
  none: false
19
- requirements:
20
- - - ! '>='
21
- - !ruby/object:Gem::Version
22
- version: '0'
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 0
32
+ version: "0"
23
33
  type: :runtime
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: actionmailer
24
37
  prerelease: false
25
- version_requirements: *70359182869000
26
- description: Capistrano Deployment Email Notification. Keep the whole team informed
27
- of each release!
28
- email:
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ hash: 3
44
+ segments:
45
+ - 0
46
+ version: "0"
47
+ - - <
48
+ - !ruby/object:Gem::Version
49
+ hash: 5
50
+ segments:
51
+ - 3
52
+ version: "3"
53
+ type: :runtime
54
+ version_requirements: *id002
55
+ description: Capistrano Deployment Email Notification. Keep the whole team informed of each release! (Rails 2.X version)
56
+ email:
29
57
  - peter.boling@gmail.com
30
58
  - dave@textgoeshere.org.uk
31
59
  executables: []
60
+
32
61
  extensions: []
33
- extra_rdoc_files:
34
- - README.rdoc
35
- files:
36
- - MIT-LICENSE
37
- - README.rdoc
38
- - Rakefile
39
- - VERSION.yml
40
- - capistrano_mailer.gemspec
62
+
63
+ extra_rdoc_files:
64
+ - CHANGELOG.md
65
+ - LICENSE.txt
66
+ - README.md
67
+ files:
41
68
  - lib/cap_mailer.rb
42
69
  - lib/capistrano/mailer.rb
70
+ - lib/capistrano/mailer_recipes.rb
71
+ - lib/capistrano_mailer/version.rb
72
+ - lib/capistrano_mailer.rb
73
+ - test/build_gem_test.rb
74
+ - spec/create_gemset_spec.rb
75
+ - spec/empty_gemset_spec.rb
76
+ - spec/install_ruby_spec.rb
77
+ - spec/rvm_paths_spec.rb
78
+ - spec/spec_helper.rb
79
+ - spec/support/abort_matcher.rb
80
+ - spec/support/capistrano.rb
81
+ - views/cap_mailer/_message_body.html.erb
82
+ - views/cap_mailer/_message_body.text.erb
43
83
  - views/cap_mailer/_section.html.erb
44
84
  - views/cap_mailer/_section.text.erb
45
85
  - views/cap_mailer/_section_custom.html.erb
46
86
  - views/cap_mailer/_section_custom.text.erb
47
- - views/cap_mailer/notification_email.text.html.erb
48
- - views/cap_mailer/notification_email.text.plain.erb
87
+ - views/cap_mailer/failed.notification_email.html.erb
88
+ - views/cap_mailer/failed.notification_email.plain.erb
89
+ - views/cap_mailer/notification_email.html.erb
90
+ - views/cap_mailer/notification_email.plain.erb
91
+ - LICENSE.txt
92
+ - README.md
93
+ - CHANGELOG.md
94
+ - Rakefile
49
95
  homepage: http://github.com/pboling/capistrano_mailer
50
96
  licenses: []
97
+
51
98
  post_install_message:
52
99
  rdoc_options: []
53
- require_paths:
100
+
101
+ require_paths:
54
102
  - lib
55
- required_ruby_version: !ruby/object:Gem::Requirement
103
+ required_ruby_version: !ruby/object:Gem::Requirement
56
104
  none: false
57
- requirements:
58
- - - ! '>='
59
- - !ruby/object:Gem::Version
60
- version: '0'
61
- required_rubygems_version: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - ">="
107
+ - !ruby/object:Gem::Version
108
+ hash: 3
109
+ segments:
110
+ - 0
111
+ version: "0"
112
+ required_rubygems_version: !ruby/object:Gem::Requirement
62
113
  none: false
63
- requirements:
64
- - - ! '>='
65
- - !ruby/object:Gem::Version
66
- version: '0'
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ hash: 3
118
+ segments:
119
+ - 0
120
+ version: "0"
67
121
  requirements: []
122
+
68
123
  rubyforge_project:
69
- rubygems_version: 1.8.10
124
+ rubygems_version: 1.8.29
70
125
  signing_key:
71
126
  specification_version: 3
72
127
  summary: Capistrano Deployment Email Notification
73
- test_files: []
128
+ test_files:
129
+ - test/build_gem_test.rb
130
+ - spec/create_gemset_spec.rb
131
+ - spec/empty_gemset_spec.rb
132
+ - spec/install_ruby_spec.rb
133
+ - spec/rvm_paths_spec.rb
134
+ - spec/spec_helper.rb
135
+ - spec/support/abort_matcher.rb
136
+ - spec/support/capistrano.rb
data/MIT-LICENSE DELETED
@@ -1,21 +0,0 @@
1
- # Copyright (c) 2009 9thBit LLC (http://www.9thbit.net)
2
- # Copyright (c) 2007-8 Sagebit, LLC (http://www.sagebit.com)
3
- #
4
- # Permission is hereby granted, free of charge, to any person obtaining
5
- # a copy of this software and associated documentation files (the
6
- # "Software"), to deal in the Software without restriction, including
7
- # without limitation the rights to use, copy, modify, merge, publish,
8
- # distribute, sublicense, and/or sell copies of the Software, and to
9
- # permit persons to whom the Software is furnished to do so, subject to
10
- # the following conditions:
11
- #
12
- # The above copyright notice and this permission notice shall be
13
- # included in all copies or substantial portions of the Software.
14
- #
15
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
- # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
- # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
- # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
- # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
- # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
- # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc DELETED
@@ -1,198 +0,0 @@
1
- = Capistrano Mailer For Rails <= 2.3.x
2
-
3
- * For Capistrano Deployment Email Notification
4
- * It is a Capistrano Plugin / Ruby Gem that requires ActionMailer
5
- * It is MIT-LICENSE (License file is in source only for now because github won't build the gem if it is bundled with the gem... ?)
6
-
7
- Ever wanted to be emailed whenever someone on the team does a cap deploy of trunk or some tag to some server.
8
- Wouldn't it be nice to know about it every time a release was deployed? For large rails projects this type of coordination is essential,
9
- and this plugin makes sure everyone on the need to know list is notified when something new is deployed.
10
-
11
- This plugin/gem is an extension to Capistrano.
12
-
13
- That means it registers itself with Capistrano as a plugin and is therefore available to call in your recipes.
14
-
15
- If you are looking to roll your own email integration into capistrano then try this pastie:
16
- http://pastie.org/146264 (thanks to Mislav Marohnić).
17
- But if you want to take the easy road to riches then keep reading ;)
18
- -- figurative "riches" of course, I promise nothing in return for your using this plugin
19
-
20
- Important Note:
21
- The first time you deploy to a server (a 'cold' deploy) capistrano mailer will cause an error because it uses capistrano's previous release variables, and when there are no previous releases capistrano throws an error. In the next version this will be fixed, just don't have time at the moment. If you would like to work on this 'first deploy' problem please fork my repo and work on it!
22
-
23
- == Home Page
24
-
25
- http://github.com/pboling/capistrano_mailer
26
-
27
-
28
- == Credit where Credit is Due
29
-
30
- * Thanks to Dustin Deyoung of Sagebit, LLC (http://www.sagebit.com) for the beautiful HTML email templates.
31
-
32
-
33
- == Requirements
34
-
35
- * Rails 1.2.6 - 2.3.X (might work with older versions, but has not been tested)
36
-
37
- * at least Capistrano 2.4.3 (might work with capistrano as old as 2.1.0, but has not been tested)
38
-
39
- * Known to be compatible with SCMs as of version 3.1.2: Perforce, SVN, and Git
40
-
41
- * Known to be compatible with, but does not require, the deprec gem.
42
-
43
-
44
- == Installation
45
-
46
- Install the latest Rails 2 compatible version of the gem:
47
-
48
- [sudo] gem install capistrano_mailer -v 3.2.7
49
-
50
- == Upgrading
51
-
52
- The 3.x versions of the gem will remain compatible with Rails 2.x, while the 4+ versions of the gem will move forward with Rails 3+
53
-
54
- From version 3.1.x to version 3.2.x
55
-
56
- 1. Update the way CapistranoMailer is configured using the new method: CapMailer.configure (see Usage below).
57
- 2. require the cap mailer config file (see Usage below)
58
-
59
- From version 2.1.0 to version 3.1.x:
60
-
61
- 1. Update the way CapistranoMailer is configured using the new method: CapMailer.configure_capistrano_mailer (changed in later versions to just 'configure') (see Usage below).
62
- 2. Update the require statement at the top of deploy.rb, see below (note for plugin change from capistrano_mailer to capistrano/mailer).
63
- 3. Change the mailer.send to mailer.send_notification_email in your cap recipe.
64
-
65
- == Usage
66
-
67
- 1. Install as gem or plugin. You need to have already setup capistrano in the project, including the 'capify .' command.
68
-
69
- 2. Add this line to the top of your config/deploy.rb:
70
-
71
- # For plugin:
72
- # You must make capistrano_mailer's libraries available in Ruby's load path. This is one way to do that:
73
- # Add to the top of your config/deploy.rb file:
74
- $:.unshift 'vendor/plugins/capistrano_mailer/lib'
75
-
76
- # For frozen gem:
77
- # You must make capistrano_mailer's libraries available in Ruby's load path. This is one way to do that:
78
- # Add to the top of your config/deploy.rb file:
79
- $:.unshift 'vendor/gems/capistrano_mailer-x.x.x/lib'
80
-
81
- # then for gem or plugin:
82
- ####################################
83
- # Capistrano Plugins go here
84
- require 'capistrano/mailer'
85
- #configure capistrano_mailer:
86
- # The configuration file can go anywhere, but in past versions of the gem it was required to be in the config/ dir.
87
- require 'config/cap_mailer_settings'
88
- ####################################
89
-
90
- 3. Configure Caistrano Mailer in the settings file required in step 2:
91
-
92
- # If installed as a plugin might need the require here as well
93
-
94
- ActionMailer::Base.delivery_method = :smtp # or :sendmail, or whatever
95
- ActionMailer::Base.smtp_settings = { # if using :smtp
96
- :address => "mail.example.com",
97
- :port => 25,
98
- :domain => 'default.com',
99
- :perform_deliveries => true,
100
- :user_name => "releases@example.com",
101
- :password => "mypassword",
102
- :authentication => :login }
103
- ActionMailer::Base.default_charset = "utf-8"# or "latin1" or whatever you are using
104
-
105
- CapMailer.configure do |config|
106
- config[:recipient_addresses] = ["dev1@example.com"]
107
- # NOTE: THERE IS A BUG IN RAILS 2.3.3 which forces us to NOT use anything but a simple email address string for the sender address.
108
- # https://rails.lighthouseapp.com/projects/8994/tickets/2340
109
- # Therefore %("Capistrano Deployment" <releases@example.com>) style addresses may not work in Rails 2.3.3
110
- config[:sender_address] = "deployment@example.com"
111
- config[:subject_prepend] = "[EMPTY-CAP-DEPLOY]"
112
- config[:site_name] = "Empty Example.com App"
113
- config[:email_content_type] = "text/html" # OR "text/plain" if you want the plain text version of the email
114
- end
115
-
116
- 4. Add these two tasks to your deploy.rb:
117
-
118
- namespace :show do
119
- desc "Show some internal Cap-Fu: What's mah NAYM?!?"
120
- task :me do
121
- set :task_name, task_call_frames.first.task.fully_qualified_name
122
- #puts "Running #{task_name} task"
123
- end
124
- end
125
-
126
- namespace :deploy do
127
- ...
128
-
129
- desc "Send email notification of deployment (only send variables you want to be in the email)"
130
- task :notify, :roles => :app do
131
- show.me # this sets the task_name variable
132
- mailer.send_notification_email(self)
133
- end
134
-
135
- ...
136
- end
137
-
138
- Make _sure_ you've defined `rails_env`, `repository`, `deploy_to`, `host`, and `application`.
139
- task_name is defined by the show:me task above, and the others are defined behind the scenes by Capistrano!
140
-
141
- The only parameter to mailer.send_notification_email that is *required* is the first. _Minimally_ you need to define the capistrano variables:
142
- :rails_env
143
- :repository
144
- :task_name (provided by the show:me task included in this readme)
145
- :deploy_to
146
- :host
147
- :application
148
-
149
- But there are tons of others - just take a look at lib/mailer/cap_mailer.rb.
150
-
151
- If anyone has a cool way of recording the *output* into a capistrano accessible variable,
152
- so that it can be shoved into the release email that would be an excellent contribution!
153
-
154
- 5. Then add the hook somewhere in your deploy.rb:
155
-
156
- after "deploy", "deploy:notify"
157
-
158
- 6. Enjoy and Happy Capping!
159
-
160
- 7. Customization
161
-
162
- If you want to use your own views you'll need to recreate the notification_email view:
163
- First you need to define where your templates are:
164
-
165
- CapMailer.configure_capistrano_mailer do |config|
166
- config[:template_root] = "app/views/capistrano_mailer/"
167
- end
168
-
169
- Then you'll need to create templates there called:
170
-
171
- notification_email.text.html.erb
172
-
173
- and / or
174
-
175
- notification_email.text.plain.erb
176
-
177
- Take a look at the templates that comes with the plugin to see how it is done (views/cap_mailer/...)
178
-
179
- == Authors
180
-
181
- Peter Boling (pboling) - Wrote original & Maintainer
182
- Dave Nolan (textgoeshere) - lots of refactoring merged into 3.2 release
183
-
184
- == Contributors
185
-
186
- Dustin Deyoung - HTML Email Templates
187
- mixonix - SCMs compatibility
188
- greut - SCMs compatibility
189
-
190
- ----------------------------------------------------------------------------------
191
-
192
- This plugin started as a collaboration between Sagebit, LLC (http://www.sagebit.com) and Peter Boling (http://www.peterboling.com).
193
- Written initially while Peter Boling was working at Sagebit for use in various projects.
194
-
195
- Author: Peter Boling, peter.boling at gmail dot com
196
-
197
- Copyright (c) 2009-2011 Peter Boling of 9thBit LLC, released under the MIT license
198
- Copyright (c) 2007-2008 Sagebit LLC, released under the MIT license