gated_release 0.1.0 → 0.2.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.
Files changed (83) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +6 -0
  3. data/CHANGELOG.md +22 -0
  4. data/Gemfile.lock +54 -6
  5. data/MIT-LICENSE +20 -0
  6. data/README.md +32 -1
  7. data/Rakefile +25 -2
  8. data/app/assets/config/gated_release_manifest.js +2 -0
  9. data/app/assets/images/gated_release/.keep +0 -0
  10. data/app/assets/javascripts/gated_release/application.js +13 -0
  11. data/app/assets/stylesheets/gated_release/application.css +15 -0
  12. data/app/assets/stylesheets/gated_release/gates.css +131 -0
  13. data/app/controllers/gated_release/application_controller.rb +5 -0
  14. data/app/controllers/gated_release/gates_controller.rb +47 -0
  15. data/app/helpers/gated_release/application_helper.rb +12 -0
  16. data/app/jobs/gated_release/application_job.rb +4 -0
  17. data/app/mailers/gated_release/application_mailer.rb +6 -0
  18. data/app/models/gated_release/application_record.rb +5 -0
  19. data/{lib → app/models}/gated_release/gate.rb +9 -2
  20. data/app/views/gated_release/gates/index.html.erb +64 -0
  21. data/app/views/layouts/gated_release/application.html.erb +18 -0
  22. data/config/routes.rb +11 -0
  23. data/gated_release.gemspec +6 -3
  24. data/lib/gated_release.rb +1 -1
  25. data/lib/gated_release/engine.rb +13 -0
  26. data/lib/gated_release/version.rb +1 -1
  27. data/lib/tasks/gated_release_tasks.rake +4 -0
  28. data/spec/dummy/Rakefile +6 -0
  29. data/spec/dummy/app/assets/config/manifest.js +5 -0
  30. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  31. data/spec/dummy/app/assets/javascripts/cable.js +13 -0
  32. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  33. data/spec/dummy/app/channels/application_cable/channel.rb +4 -0
  34. data/spec/dummy/app/channels/application_cable/connection.rb +4 -0
  35. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  36. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  37. data/spec/dummy/app/jobs/application_job.rb +2 -0
  38. data/spec/dummy/app/mailers/application_mailer.rb +4 -0
  39. data/spec/dummy/app/models/application_record.rb +3 -0
  40. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  41. data/spec/dummy/app/views/layouts/mailer.html.erb +13 -0
  42. data/spec/dummy/app/views/layouts/mailer.text.erb +1 -0
  43. data/spec/dummy/bin/bundle +3 -0
  44. data/spec/dummy/bin/rails +4 -0
  45. data/spec/dummy/bin/rake +4 -0
  46. data/spec/dummy/bin/setup +34 -0
  47. data/spec/dummy/bin/update +29 -0
  48. data/spec/dummy/config.ru +5 -0
  49. data/spec/dummy/config/application.rb +15 -0
  50. data/spec/dummy/config/boot.rb +5 -0
  51. data/spec/dummy/config/cable.yml +9 -0
  52. data/spec/dummy/config/database.yml +25 -0
  53. data/spec/dummy/config/environment.rb +5 -0
  54. data/spec/dummy/config/environments/development.rb +54 -0
  55. data/spec/dummy/config/environments/production.rb +86 -0
  56. data/spec/dummy/config/environments/test.rb +42 -0
  57. data/spec/dummy/config/initializers/application_controller_renderer.rb +6 -0
  58. data/spec/dummy/config/initializers/assets.rb +11 -0
  59. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  60. data/spec/dummy/config/initializers/cookies_serializer.rb +5 -0
  61. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  62. data/spec/dummy/config/initializers/inflections.rb +16 -0
  63. data/spec/dummy/config/initializers/mime_types.rb +4 -0
  64. data/spec/dummy/config/initializers/new_framework_defaults.rb +24 -0
  65. data/spec/dummy/config/initializers/session_store.rb +3 -0
  66. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  67. data/spec/dummy/config/locales/en.yml +23 -0
  68. data/spec/dummy/config/puma.rb +47 -0
  69. data/spec/dummy/config/routes.rb +3 -0
  70. data/spec/dummy/config/secrets.yml +22 -0
  71. data/spec/dummy/config/spring.rb +6 -0
  72. data/spec/dummy/db/schema.rb +15 -0
  73. data/spec/dummy/public/404.html +67 -0
  74. data/spec/dummy/public/422.html +67 -0
  75. data/spec/dummy/public/500.html +66 -0
  76. data/spec/dummy/public/apple-touch-icon-precomposed.png +0 -0
  77. data/spec/dummy/public/apple-touch-icon.png +0 -0
  78. data/spec/dummy/public/favicon.ico +0 -0
  79. data/spec/gated_release_spec.rb +8 -0
  80. data/spec/generators/install/install_generator_spec.rb +25 -0
  81. data/spec/models/gated_release/gate_spec.rb +293 -0
  82. data/spec/spec_helper.rb +36 -0
  83. metadata +160 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 76ee56e30f5bec17b5b0b170ae36c54c1890eae0
4
- data.tar.gz: 11a70be7aed859789307ccf302bd5423efac9a75
3
+ metadata.gz: 8d2923b054974e2efa9fecc05808c04a04f823f7
4
+ data.tar.gz: 8cccd31a0145cf092869e85bd17848f12250911f
5
5
  SHA512:
6
- metadata.gz: 92d02bd595b2df90cbdf2f826f20433f16d41409f8ea1d58499edf9a6aa0f7c82b8553a8f9f9648d3cc02cae3f9de8499a1e24e07c52dcb6d41b733654160db8
7
- data.tar.gz: fe7ac538785a7247b5a5bdc7c5dea596a549afe665f85fe5a29bd3cf81edaf5d8724c5fb7092a7768104fbb71ef156a357ffe52838869dc92f102ce5483b31fe
6
+ metadata.gz: 9b3113d3cc9e160107521f8b7a1a81bf9ed11a2fe4f400b3c35c0b1adb98d2b809598df8dfbd330a073e35e5e9aa3df53b49db585da073c3386363df40a6dbd8
7
+ data.tar.gz: e9ca556223904d115d4dbd616a6300c71d6b8c8fdbfb5363102cfeda5a8ba9dc349b27f732f236ff5a2087bc972fd2c63e732b3c27fdb787d84bb462dd1d45b4
data/.gitignore CHANGED
@@ -3,9 +3,15 @@
3
3
  /_yardoc/
4
4
  /coverage/
5
5
  /doc/
6
+ log/*.log
6
7
  /pkg/
7
8
  /spec/reports/
8
9
  /tmp/
10
+ /vendor/
11
+ spec/dummy/db/*.sqlite3
12
+ spec/dummy/db/*.sqlite3-journal
13
+ spec/dummy/log/*.log
14
+ spec/dummy/tmp/
9
15
 
10
16
  # rspec failure tracking
11
17
  .rspec_status
data/CHANGELOG.md ADDED
@@ -0,0 +1,22 @@
1
+ Change Log
2
+ ==========
3
+
4
+ All notable changes to this project will be documented in this file.
5
+
6
+ The format is based on [Keep a Changelog](http://keepachangelog.com/)
7
+ and this project adheres to [Semantic Versioning](http://semver.org/).
8
+
9
+ ## [0.0.2] - 2017-03-17
10
+
11
+ ### Added
12
+
13
+ - Admin panel using a Rails engine
14
+
15
+ ## 0.0.1 - 2017-03-17
16
+
17
+ ### Added
18
+
19
+ - Allow to manage gates using the Rails console
20
+ - Initial release :)
21
+
22
+ [0.2.0]: https://github.com/redbubble/gated_release/compare/v0.1.0...v0.2.0
data/Gemfile.lock CHANGED
@@ -1,12 +1,23 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- gated_release (0.1.0)
4
+ gated_release (0.2.0)
5
5
  activerecord (>= 4.0, < 6)
6
+ rails (>= 4.0, < 6)
6
7
 
7
8
  GEM
8
9
  remote: https://rubygems.org/
9
10
  specs:
11
+ actioncable (5.0.2)
12
+ actionpack (= 5.0.2)
13
+ nio4r (>= 1.2, < 3.0)
14
+ websocket-driver (~> 0.6.1)
15
+ actionmailer (5.0.2)
16
+ actionpack (= 5.0.2)
17
+ actionview (= 5.0.2)
18
+ activejob (= 5.0.2)
19
+ mail (~> 2.5, >= 2.5.4)
20
+ rails-dom-testing (~> 2.0)
10
21
  actionpack (5.0.2)
11
22
  actionview (= 5.0.2)
12
23
  activesupport (= 5.0.2)
@@ -20,6 +31,9 @@ GEM
20
31
  erubis (~> 2.7.0)
21
32
  rails-dom-testing (~> 2.0)
22
33
  rails-html-sanitizer (~> 1.0, >= 1.0.3)
34
+ activejob (5.0.2)
35
+ activesupport (= 5.0.2)
36
+ globalid (>= 0.3.6)
23
37
  activemodel (5.0.2)
24
38
  activesupport (= 5.0.2)
25
39
  activerecord (5.0.2)
@@ -40,17 +54,37 @@ GEM
40
54
  generator_spec (0.9.3)
41
55
  activesupport (>= 3.0.0)
42
56
  railties (>= 3.0.0)
57
+ globalid (0.3.7)
58
+ activesupport (>= 4.1.0)
43
59
  i18n (0.8.1)
44
60
  loofah (2.0.3)
45
61
  nokogiri (>= 1.5.9)
62
+ mail (2.6.4)
63
+ mime-types (>= 1.16, < 4)
46
64
  method_source (0.8.2)
65
+ mime-types (3.1)
66
+ mime-types-data (~> 3.2015)
67
+ mime-types-data (3.2016.0521)
47
68
  mini_portile2 (2.1.0)
48
69
  minitest (5.10.1)
70
+ nio4r (2.0.0)
49
71
  nokogiri (1.7.0.1)
50
72
  mini_portile2 (~> 2.1.0)
51
73
  rack (2.0.1)
52
74
  rack-test (0.6.3)
53
75
  rack (>= 1.0)
76
+ rails (5.0.2)
77
+ actioncable (= 5.0.2)
78
+ actionmailer (= 5.0.2)
79
+ actionpack (= 5.0.2)
80
+ actionview (= 5.0.2)
81
+ activejob (= 5.0.2)
82
+ activemodel (= 5.0.2)
83
+ activerecord (= 5.0.2)
84
+ activesupport (= 5.0.2)
85
+ bundler (>= 1.3.0, < 2.0)
86
+ railties (= 5.0.2)
87
+ sprockets-rails (>= 2.0.0)
54
88
  rails-dom-testing (2.0.2)
55
89
  activesupport (>= 4.2.0, < 6.0)
56
90
  nokogiri (~> 1.6)
@@ -63,10 +97,6 @@ GEM
63
97
  rake (>= 0.8.7)
64
98
  thor (>= 0.18.1, < 2.0)
65
99
  rake (10.5.0)
66
- rspec (3.5.0)
67
- rspec-core (~> 3.5.0)
68
- rspec-expectations (~> 3.5.0)
69
- rspec-mocks (~> 3.5.0)
70
100
  rspec-core (3.5.4)
71
101
  rspec-support (~> 3.5.0)
72
102
  rspec-expectations (3.5.0)
@@ -75,12 +105,30 @@ GEM
75
105
  rspec-mocks (3.5.0)
76
106
  diff-lcs (>= 1.2.0, < 2.0)
77
107
  rspec-support (~> 3.5.0)
108
+ rspec-rails (3.5.2)
109
+ actionpack (>= 3.0)
110
+ activesupport (>= 3.0)
111
+ railties (>= 3.0)
112
+ rspec-core (~> 3.5.0)
113
+ rspec-expectations (~> 3.5.0)
114
+ rspec-mocks (~> 3.5.0)
115
+ rspec-support (~> 3.5.0)
78
116
  rspec-support (3.5.0)
117
+ sprockets (3.7.1)
118
+ concurrent-ruby (~> 1.0)
119
+ rack (> 1, < 3)
120
+ sprockets-rails (3.2.0)
121
+ actionpack (>= 4.0)
122
+ activesupport (>= 4.0)
123
+ sprockets (>= 3.0.0)
79
124
  sqlite3 (1.3.13)
80
125
  thor (0.19.4)
81
126
  thread_safe (0.3.6)
82
127
  tzinfo (1.2.2)
83
128
  thread_safe (~> 0.1)
129
+ websocket-driver (0.6.5)
130
+ websocket-extensions (>= 0.1.0)
131
+ websocket-extensions (0.1.2)
84
132
 
85
133
  PLATFORMS
86
134
  ruby
@@ -91,7 +139,7 @@ DEPENDENCIES
91
139
  gated_release!
92
140
  generator_spec (~> 0.9.0)
93
141
  rake (~> 10.0)
94
- rspec (~> 3.0)
142
+ rspec-rails (~> 3.0)
95
143
  sqlite3 (~> 1.3)
96
144
 
97
145
  BUNDLED WITH
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2017 David Carlin
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # GatedRelease
2
2
 
3
+ [![Gem Version](https://badge.fury.io/rb/gated_release.svg)](http://badge.fury.io/rb/gated_release)
4
+ [![Build Status](https://travis-ci.org/redbubble/gated_release.svg?branch=master)](https://travis-ci.org/redbubble/gated_release)
5
+ [![Code Climate](https://codeclimate.com/github/redbubble/gated_release.svg)](https://codeclimate.com/github/redbubble/gated/release)
6
+ [![Inline docs](http://inch-ci.org/github/redbubble/gated_release.svg?branch=master)](http://inch-ci.org/github/redbubble/gated_release)
7
+
3
8
  This gem allows you to easily manage split code paths in your application without redeploys.
4
9
 
5
10
  ## Installation
@@ -9,7 +14,7 @@ This gem allows you to easily manage split code paths in your application withou
9
14
  Add this line to your application's Gemfile:
10
15
 
11
16
  ```ruby
12
- gem 'gated_release', '0.1.0' # see semver.org
17
+ gem 'gated_release', '0.2.0' # see semver.org
13
18
  ```
14
19
 
15
20
  And then execute:
@@ -29,6 +34,14 @@ $ bundle exec rails generate gated_release:install
29
34
  $ bundle exec rake db:migrate
30
35
  ```
31
36
 
37
+ Mount it in your config/routes.rb file
38
+
39
+ ```ruby
40
+ mount GatedRelease::Engine => "/gated_release"
41
+ ```
42
+
43
+ and visit `http://localhost:3000/gated_release`
44
+
32
45
  ## Usage
33
46
 
34
47
  ```ruby
@@ -38,6 +51,20 @@ GatedRelease::Gate.get('gate-name').run(
38
51
  )
39
52
  ```
40
53
 
54
+ ```ruby
55
+ # Close the gate on any error from the open code path
56
+ GatedRelease::Gate.get('gate-name').run(
57
+ open: -> { code_to_run_for_open_gate },
58
+ closed: -> { code_to_run_for_closed_gate },
59
+ close_on_error: true
60
+ )
61
+ ```
62
+
63
+
64
+ ### Managing Gates
65
+ Gates can be managed from the page: `http://localhost:3000/gated_release`.
66
+ They can also be manually modified with the following commands:
67
+
41
68
  To open the gate:
42
69
  ```ruby
43
70
  GatedRelease::Gate.get('gate-name').open!
@@ -58,6 +85,10 @@ To put the gate into 'percentage' state, where a set percentage of code executio
58
85
  GatedRelease::Gate.get('gate-name').percentage!(10)
59
86
  ```
60
87
 
88
+ ## Credits
89
+
90
+ Thanks to John Sardine for the table css: http://johnsardine.com/freebies/dl-html-css/simple-little-tab/
91
+
61
92
  ## Development
62
93
 
63
94
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
data/Rakefile CHANGED
@@ -1,6 +1,29 @@
1
- require "bundler/gem_tasks"
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'bundler/gem_tasks'
2
8
  require "rspec/core/rake_task"
9
+ require 'rdoc/task'
10
+
11
+ RSpec::Core::RakeTask.new(spec: 'app:db:test:prepare')
12
+
13
+ RDoc::Task.new(:rdoc) do |rdoc|
14
+ rdoc.rdoc_dir = 'rdoc'
15
+ rdoc.title = 'GatedRelease'
16
+ rdoc.options << '--line-numbers'
17
+ rdoc.rdoc_files.include('README.md')
18
+ rdoc.rdoc_files.include('lib/**/*.rb')
19
+ end
20
+
21
+ APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
22
+ load 'rails/tasks/engine.rake'
23
+
24
+ Bundler::GemHelper.install_tasks
25
+
3
26
 
4
- RSpec::Core::RakeTask.new(:spec)
27
+ load 'rails/tasks/statistics.rake'
5
28
 
6
29
  task :default => :spec
@@ -0,0 +1,2 @@
1
+ //= link_directory ../javascripts/gated_release .js
2
+ //= link_directory ../stylesheets/gated_release .css
File without changes
@@ -0,0 +1,13 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
+ // or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // compiled file. JavaScript code in this file should be added after the last require_* statement.
9
+ //
10
+ // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
11
+ // about supported directives.
12
+ //
13
+ //= require_tree .
@@ -0,0 +1,15 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9
+ * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
10
+ * files in this directory. Styles in this file should be added after the last require_* statement.
11
+ * It is generally better to create a new file per style scope.
12
+ *
13
+ *= require 'gated_release/gates'
14
+ *= require_self
15
+ */
@@ -0,0 +1,131 @@
1
+ body {
2
+ margin: 0;
3
+ font-family: Arial, Helvetica, sans-serif;
4
+ font-size: 14px;
5
+ }
6
+
7
+ input[type=submit] {
8
+ padding: 10px;
9
+ }
10
+
11
+ .alert {
12
+ width: 100%;
13
+ text-align: center;
14
+ background-color: #f0f6ff;
15
+ padding: 8px;
16
+ border-bottom: 1px solid #72b2ff;
17
+ color: #333;
18
+ font-size: 110%;
19
+
20
+ }
21
+
22
+ #gates {
23
+ color:#666;
24
+ text-shadow: 1px 1px 0px #fff;
25
+ margin: 20px;
26
+ }
27
+ .gated-release-search-form {
28
+ float: right;
29
+ }
30
+
31
+ .gated-release-heading {
32
+ float: left;
33
+ margin: 0 0 10px 0;
34
+ }
35
+
36
+ /* http://johnsardine.com/freebies/dl-html-css/simple-little-tab/ */
37
+ table a:link {
38
+ color: #666;
39
+ font-weight: bold;
40
+ text-decoration:none;
41
+ }
42
+ table a:visited {
43
+ color: #999999;
44
+ font-weight:bold;
45
+ text-decoration:none;
46
+ }
47
+ table a:active,
48
+ table a:hover {
49
+ color: #bd5a35;
50
+ text-decoration:underline;
51
+ }
52
+
53
+ table {
54
+ width: 100%;
55
+ font-size: 1em;
56
+ background:#eaebec;
57
+ border:#ccc 1px solid;
58
+
59
+ -moz-border-radius:3px;
60
+ -webkit-border-radius:3px;
61
+ border-radius:3px;
62
+
63
+ -moz-box-shadow: 0 1px 2px #d1d1d1;
64
+ -webkit-box-shadow: 0 1px 2px #d1d1d1;
65
+ box-shadow: 0 1px 2px #d1d1d1;
66
+ }
67
+ table th {
68
+ padding:21px 25px 22px 25px;
69
+ border-top:1px solid #fafafa;
70
+ border-bottom:1px solid #e0e0e0;
71
+
72
+ background: #ededed;
73
+ background: -webkit-gradient(linear, left top, left bottom, from(#ededed), to(#ebebeb));
74
+ background: -moz-linear-gradient(top, #ededed, #ebebeb);
75
+ }
76
+ table th:first-child {
77
+ text-align: left;
78
+ padding-left:20px;
79
+ }
80
+ table tr:first-child th:first-child {
81
+ -moz-border-radius-topleft:3px;
82
+ -webkit-border-top-left-radius:3px;
83
+ border-top-left-radius:3px;
84
+ }
85
+ table tr:first-child th:last-child {
86
+ -moz-border-radius-topright:3px;
87
+ -webkit-border-top-right-radius:3px;
88
+ border-top-right-radius:3px;
89
+ }
90
+ table tr {
91
+ text-align: center;
92
+ padding-left:20px;
93
+ }
94
+ table td:first-child {
95
+ text-align: left;
96
+ padding-left:20px;
97
+ border-left: 0;
98
+ }
99
+ table td {
100
+ padding:18px;
101
+ border-top: 1px solid #ffffff;
102
+ border-bottom:1px solid #e0e0e0;
103
+ border-left: 1px solid #e0e0e0;
104
+
105
+ background: #fafafa;
106
+ background: -webkit-gradient(linear, left top, left bottom, from(#fbfbfb), to(#fafafa));
107
+ background: -moz-linear-gradient(top, #fbfbfb, #fafafa);
108
+ }
109
+ table tr:nth-child(even) td {
110
+ background: #f6f6f6;
111
+ background: -webkit-gradient(linear, left top, left bottom, from(#f8f8f8), to(#f6f6f6));
112
+ background: -moz-linear-gradient(top, #f8f8f8, #f6f6f6);
113
+ }
114
+ table tr:last-child td {
115
+ border-bottom:0;
116
+ }
117
+ table tr:last-child td:first-child {
118
+ -moz-border-radius-bottomleft:3px;
119
+ -webkit-border-bottom-left-radius:3px;
120
+ border-bottom-left-radius:3px;
121
+ }
122
+ table tr:last-child td:last-child {
123
+ -moz-border-radius-bottomright:3px;
124
+ -webkit-border-bottom-right-radius:3px;
125
+ border-bottom-right-radius:3px;
126
+ }
127
+ table tr:hover td {
128
+ background: #f2f2f2;
129
+ background: -webkit-gradient(linear, left top, left bottom, from(#f2f2f2), to(#f0f0f0));
130
+ background: -moz-linear-gradient(top, #f2f2f2, #f0f0f0);
131
+ }