msg 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (119) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.md +9 -0
  3. data/Rakefile +35 -0
  4. data/app/assets/images/msg/message.png +0 -0
  5. data/app/assets/images/msg/ping.png +0 -0
  6. data/app/assets/images/msg/sending.png +0 -0
  7. data/app/assets/javascripts/lib/jquery.peity.js +261 -0
  8. data/app/assets/javascripts/msg.js.coffee +6 -0
  9. data/app/assets/stylesheets/msg.css.sass +218 -0
  10. data/app/controllers/msg/bounces_controller.rb +67 -0
  11. data/app/controllers/msg/engine_controller.rb +23 -0
  12. data/app/controllers/msg/envelopes_controller.rb +22 -0
  13. data/app/controllers/msg/messages_controller.rb +85 -0
  14. data/app/controllers/msg/sendings_controller.rb +58 -0
  15. data/app/helpers/msg/msg_helper.rb +40 -0
  16. data/app/mailers/msg/devise_mailer.rb +20 -0
  17. data/app/mailers/msg/msg_mailer.rb +23 -0
  18. data/app/models/msg/bounce.rb +19 -0
  19. data/app/models/msg/envelope.rb +56 -0
  20. data/app/models/msg/message.rb +26 -0
  21. data/app/models/msg/sending.rb +54 -0
  22. data/app/views/layouts/msg/default.html.haml +30 -0
  23. data/app/views/layouts/msg/email.html.haml +10 -0
  24. data/app/views/msg/bounces/_listing.html.haml +5 -0
  25. data/app/views/msg/bounces/_report.html.haml +10 -0
  26. data/app/views/msg/bounces/index.html.haml +5 -0
  27. data/app/views/msg/devise_mailer/confirmation_instructions.en.html.haml +1 -0
  28. data/app/views/msg/devise_mailer/reset_password_instructions.en.html.haml +1 -0
  29. data/app/views/msg/envelopes/_listing.html.haml +5 -0
  30. data/app/views/msg/messages/_action_menu.html.haml +10 -0
  31. data/app/views/msg/messages/_form.html.haml +38 -0
  32. data/app/views/msg/messages/_instructions.html.haml +28 -0
  33. data/app/views/msg/messages/_message.html.haml +11 -0
  34. data/app/views/msg/messages/_saved_messages.html.haml +2 -0
  35. data/app/views/msg/messages/_transactional_messages.html.haml +3 -0
  36. data/app/views/msg/messages/edit.html.haml +7 -0
  37. data/app/views/msg/messages/index.html.haml +23 -0
  38. data/app/views/msg/messages/new.html.haml +7 -0
  39. data/app/views/msg/messages/preview.html.haml +4 -0
  40. data/app/views/msg/messages/show.html.haml +25 -0
  41. data/app/views/msg/msg_mailer/message_in_envelope.html.haml +2 -0
  42. data/app/views/msg/sendings/_form.html.haml +45 -0
  43. data/app/views/msg/sendings/_listing.html.haml +17 -0
  44. data/app/views/msg/sendings/_report.html.haml +8 -0
  45. data/app/views/msg/sendings/_sending.html.haml +22 -0
  46. data/app/views/msg/sendings/_sendings.html.haml +2 -0
  47. data/app/views/msg/sendings/index.html.haml +8 -0
  48. data/app/views/msg/sendings/new.html.haml +9 -0
  49. data/app/views/msg/sendings/review.html.haml +2 -0
  50. data/app/views/msg/sendings/show.html.haml +50 -0
  51. data/app/views/msg/shared/_toolbar.html.haml +17 -0
  52. data/config/cucumber.yml +8 -0
  53. data/config/locales/en.yml +76 -0
  54. data/config/routes.rb +26 -0
  55. data/db/migrate/20130320141926_msg_data.rb +54 -0
  56. data/db/migrate/20130327134754_sending_circumstances.rb +6 -0
  57. data/lib/msg.rb +88 -0
  58. data/lib/msg/engine.rb +23 -0
  59. data/lib/msg/receivers.rb +64 -0
  60. data/lib/msg/version.rb +3 -0
  61. data/lib/tasks/cucumber.rake +65 -0
  62. data/lib/tasks/msg_tasks.rake +4 -0
  63. data/spec/controllers/msg/bounces_controller_spec.rb +48 -0
  64. data/spec/controllers/msg/envelopes_controller_spec.rb +22 -0
  65. data/spec/controllers/msg/messages_controller_spec.rb +9 -0
  66. data/spec/controllers/msg/sendings_controller_spec.rb +47 -0
  67. data/spec/dummy/README.rdoc +261 -0
  68. data/spec/dummy/Rakefile +7 -0
  69. data/spec/dummy/app/assets/javascripts/application.js +15 -0
  70. data/spec/dummy/app/assets/stylesheets/application.css +13 -0
  71. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  72. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  73. data/spec/dummy/app/models/user.rb +14 -0
  74. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  75. data/spec/dummy/config.ru +4 -0
  76. data/spec/dummy/config/application.rb +59 -0
  77. data/spec/dummy/config/boot.rb +10 -0
  78. data/spec/dummy/config/database.yml +25 -0
  79. data/spec/dummy/config/environment.rb +5 -0
  80. data/spec/dummy/config/environments/development.rb +37 -0
  81. data/spec/dummy/config/environments/production.rb +67 -0
  82. data/spec/dummy/config/environments/test.rb +41 -0
  83. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  84. data/spec/dummy/config/initializers/devise.rb +285 -0
  85. data/spec/dummy/config/initializers/inflections.rb +15 -0
  86. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  87. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  88. data/spec/dummy/config/initializers/session_store.rb +8 -0
  89. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  90. data/spec/dummy/config/locales/en.yml +5 -0
  91. data/spec/dummy/config/routes.rb +9 -0
  92. data/spec/dummy/db/development.sqlite3 +0 -0
  93. data/spec/dummy/db/migrate/2013032210540_users.rb +49 -0
  94. data/spec/dummy/db/migrate/20130326093048_msg_data.msg.rb +55 -0
  95. data/spec/dummy/db/schema.rb +96 -0
  96. data/spec/dummy/db/test.sqlite3 +0 -0
  97. data/spec/dummy/log/development.log +143 -0
  98. data/spec/dummy/log/test.log +1022 -0
  99. data/spec/dummy/public/404.html +26 -0
  100. data/spec/dummy/public/422.html +26 -0
  101. data/spec/dummy/public/500.html +25 -0
  102. data/spec/dummy/public/favicon.ico +0 -0
  103. data/spec/dummy/script/rails +6 -0
  104. data/spec/factories/msg/bounces.rb +9 -0
  105. data/spec/factories/msg/envelopes.rb +10 -0
  106. data/spec/factories/msg/messages.rb +10 -0
  107. data/spec/factories/msg/sendings.rb +7 -0
  108. data/spec/factories/users.rb +11 -0
  109. data/spec/helpers/msg/msg_helper_spec.rb +17 -0
  110. data/spec/lib/msg_spec.rb +15 -0
  111. data/spec/mailers/msg/devise_mailer_spec.rb +21 -0
  112. data/spec/mailers/msg/msg_mailer_spec.rb +36 -0
  113. data/spec/models/msg/bounce_spec.rb +19 -0
  114. data/spec/models/msg/envelope_spec.rb +62 -0
  115. data/spec/models/msg/message_spec.rb +19 -0
  116. data/spec/models/msg/sending_spec.rb +10 -0
  117. data/spec/routing/sendings_routing_spec.rb +31 -0
  118. data/spec/spec_helper.rb +70 -0
  119. metadata +446 -0
@@ -0,0 +1,20 @@
1
+ Copyright 2013 YOURNAME
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.
@@ -0,0 +1,9 @@
1
+ = Msg
2
+
3
+ ## Notes.
4
+
5
+ * SES account required
6
+
7
+ * receiver classes must respond to :name, :email and :for_email
8
+
9
+ * must set devise mailer if using
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env rake
2
+ begin
3
+ require 'bundler/setup'
4
+ rescue LoadError
5
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
6
+ end
7
+ begin
8
+ require 'rdoc/task'
9
+ rescue LoadError
10
+ require 'rdoc/rdoc'
11
+ require 'rake/rdoctask'
12
+ RDoc::Task = Rake::RDocTask
13
+ end
14
+
15
+ RDoc::Task.new(:rdoc) do |rdoc|
16
+ rdoc.rdoc_dir = 'rdoc'
17
+ rdoc.title = 'Msg'
18
+ rdoc.options << '--line-numbers'
19
+ rdoc.rdoc_files.include('README.rdoc')
20
+ rdoc.rdoc_files.include('lib/**/*.rb')
21
+ end
22
+
23
+ APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
24
+ load 'rails/tasks/engine.rake'
25
+
26
+ Bundler::GemHelper.install_tasks
27
+ Dir[File.join(File.dirname(__FILE__), 'tasks/**/*.rake')].each {|f| load f }
28
+
29
+ require 'rspec/core'
30
+ require 'rspec/core/rake_task'
31
+
32
+ desc "Run all specs in spec directory (excluding plugin specs)"
33
+ RSpec::Core::RakeTask.new(:spec => 'app:db:test:prepare')
34
+
35
+ task :default => :spec
@@ -0,0 +1,261 @@
1
+ // Peity jQuery plugin version 1.2.0
2
+ // (c) 2013 Ben Pickles
3
+ //
4
+ // http://benpickles.github.com/peity
5
+ //
6
+ // Released under MIT license.
7
+ (function($, document, Math, devicePixelRatio) {
8
+ var canvasSupported = document.createElement("canvas").getContext
9
+
10
+ var peity = $.fn.peity = function(type, options) {
11
+ if (canvasSupported) {
12
+ this.each(function() {
13
+ var $this = $(this)
14
+ var chart = $this.data("peity")
15
+
16
+ if (chart) {
17
+ if (type) chart.type = type
18
+ $.extend(chart.opts, options)
19
+ chart.draw()
20
+ } else {
21
+ var defaults = peity.defaults[type]
22
+ var data = {}
23
+
24
+ $.each($this.data(), function(name, value) {
25
+ if (name in defaults) data[name] = value
26
+ })
27
+
28
+ var opts = $.extend({}, defaults, data, options)
29
+ var chart = new Peity($this, type, opts)
30
+ chart.draw()
31
+
32
+ $this
33
+ .change(function() { chart.draw() })
34
+ .data("peity", chart)
35
+ }
36
+ });
37
+ }
38
+
39
+ return this;
40
+ };
41
+
42
+ var Peity = function($el, type, opts) {
43
+ this.$el = $el
44
+ this.type = type
45
+ this.opts = opts
46
+ }
47
+
48
+ var PeityPrototype = Peity.prototype
49
+
50
+ PeityPrototype.colours = function() {
51
+ var colours = this.opts.colours
52
+ var func = colours
53
+
54
+ if (!$.isFunction(func)) {
55
+ func = function(_, i) {
56
+ return colours[i % colours.length]
57
+ }
58
+ }
59
+
60
+ return func
61
+ }
62
+
63
+ PeityPrototype.draw = function() {
64
+ peity.graphers[this.type].call(this, this.opts)
65
+ }
66
+
67
+ PeityPrototype.prepareCanvas = function(width, height) {
68
+ var canvas = this.canvas
69
+ var $canvas
70
+
71
+ if (canvas) {
72
+ this.context.clearRect(0, 0, canvas.width, canvas.height)
73
+ $canvas = $(canvas)
74
+ } else {
75
+ $canvas = $("<canvas>").css({
76
+ height: height,
77
+ width: width
78
+ }).addClass("peity").data("peity", this)
79
+
80
+ this.canvas = canvas = $canvas[0]
81
+ this.context = canvas.getContext("2d")
82
+ this.$el.hide().after(canvas)
83
+ }
84
+
85
+ canvas.height = $canvas.height() * devicePixelRatio
86
+ canvas.width = $canvas.width() * devicePixelRatio
87
+
88
+ return canvas
89
+ }
90
+
91
+ PeityPrototype.values = function() {
92
+ return $.map(this.$el.text().split(this.opts.delimiter), function(value) {
93
+ return parseFloat(value)
94
+ })
95
+ }
96
+
97
+ peity.defaults = {}
98
+ peity.graphers = {}
99
+
100
+ peity.register = function(type, defaults, grapher) {
101
+ this.defaults[type] = defaults
102
+ this.graphers[type] = grapher
103
+ }
104
+
105
+ peity.register(
106
+ 'pie',
107
+ {
108
+ colours: ["#ff9900", "#fff4dd", "#ffc66e"],
109
+ delimiter: null,
110
+ diameter: 16
111
+ },
112
+ function(opts) {
113
+ if (!opts.delimiter) {
114
+ var delimiter = this.$el.text().match(/[^0-9\.]/)
115
+ opts.delimiter = delimiter ? delimiter[0] : ","
116
+ }
117
+
118
+ var values = this.values()
119
+
120
+ if (opts.delimiter == "/") {
121
+ var v1 = values[0]
122
+ var v2 = values[1]
123
+ values = [v1, v2 - v1]
124
+ }
125
+
126
+ var i = 0
127
+ var length = values.length
128
+ var sum = 0
129
+
130
+ for (; i < length; i++) {
131
+ sum += values[i]
132
+ }
133
+
134
+ var canvas = this.prepareCanvas(opts.width || opts.diameter, opts.height || opts.diameter)
135
+ var context = this.context
136
+ var width = canvas.width
137
+ var height = canvas.height
138
+ var radius = Math.min(width, height) / 2
139
+ var pi = Math.PI
140
+ var colours = this.colours()
141
+
142
+ context.save()
143
+ context.translate(width / 2, height / 2)
144
+ context.rotate(-pi / 2)
145
+
146
+ for (i = 0; i < length; i++) {
147
+ var value = values[i]
148
+ var slice = (value / sum) * pi * 2
149
+
150
+ context.beginPath()
151
+ context.moveTo(0, 0)
152
+ context.arc(0, 0, radius, 0, slice, false)
153
+ context.fillStyle = colours.call(this, value, i, values)
154
+ context.fill()
155
+ context.rotate(slice)
156
+ }
157
+
158
+ context.restore()
159
+ }
160
+ )
161
+
162
+ peity.register(
163
+ "line",
164
+ {
165
+ colour: "#c6d9fd",
166
+ strokeColour: "#4d89f9",
167
+ strokeWidth: 1,
168
+ delimiter: ",",
169
+ height: 16,
170
+ max: null,
171
+ min: 0,
172
+ width: 32
173
+ },
174
+ function(opts) {
175
+ var values = this.values()
176
+ if (values.length == 1) values.push(values[0])
177
+ var max = Math.max.apply(Math, values.concat([opts.max]));
178
+ var min = Math.min.apply(Math, values.concat([opts.min]))
179
+
180
+ var canvas = this.prepareCanvas(opts.width, opts.height)
181
+ var context = this.context
182
+ var width = canvas.width
183
+ var height = canvas.height
184
+ var xQuotient = width / (values.length - 1)
185
+ var yQuotient = height / (max - min)
186
+
187
+ var coords = [];
188
+ var i;
189
+
190
+ context.beginPath();
191
+ context.moveTo(0, height + (min * yQuotient))
192
+
193
+ for (i = 0; i < values.length; i++) {
194
+ var x = i * xQuotient
195
+ var y = height - (yQuotient * (values[i] - min))
196
+
197
+ coords.push({ x: x, y: y });
198
+ context.lineTo(x, y);
199
+ }
200
+
201
+ context.lineTo(width, height + (min * yQuotient))
202
+ context.fillStyle = opts.colour;
203
+ context.fill();
204
+
205
+ if (opts.strokeWidth) {
206
+ context.beginPath();
207
+ context.moveTo(0, coords[0].y);
208
+ for (i = 0; i < coords.length; i++) {
209
+ context.lineTo(coords[i].x, coords[i].y);
210
+ }
211
+ context.lineWidth = opts.strokeWidth * devicePixelRatio;
212
+ context.strokeStyle = opts.strokeColour;
213
+ context.stroke();
214
+ }
215
+ }
216
+ );
217
+
218
+ peity.register(
219
+ 'bar',
220
+ {
221
+ colours: ["#4D89F9"],
222
+ delimiter: ",",
223
+ height: 16,
224
+ max: null,
225
+ min: 0,
226
+ spacing: devicePixelRatio,
227
+ width: 32
228
+ },
229
+ function(opts) {
230
+ var values = this.values()
231
+ var max = Math.max.apply(Math, values.concat([opts.max]));
232
+ var min = Math.min.apply(Math, values.concat([opts.min]))
233
+
234
+ var canvas = this.prepareCanvas(opts.width, opts.height)
235
+ var context = this.context
236
+
237
+ var width = canvas.width
238
+ var height = canvas.height
239
+ var yQuotient = height / (max - min)
240
+ var space = opts.spacing
241
+ var xQuotient = (width + space) / values.length
242
+ var colours = this.colours()
243
+
244
+ for (var i = 0; i < values.length; i++) {
245
+ var value = values[i]
246
+ var y = height - (yQuotient * (value - min))
247
+ var h
248
+
249
+ if (value == 0) {
250
+ if (min >= 0 || max > 0) y -= 1
251
+ h = 1
252
+ } else {
253
+ h = yQuotient * values[i]
254
+ }
255
+
256
+ context.fillStyle = colours.call(this, value, i, values)
257
+ context.fillRect(i * xQuotient, y, xQuotient - space, h)
258
+ }
259
+ }
260
+ );
261
+ })(jQuery, document, Math, window.devicePixelRatio || 1);
@@ -0,0 +1,6 @@
1
+ #= require lib/jquery.peity
2
+
3
+ jQuery ($) ->
4
+ $.activate_with () ->
5
+ @find_including_self('span.pie').peity "pie",
6
+ colours: ['#cacac8', '#74b87a', '#ed1c24']
@@ -0,0 +1,218 @@
1
+ @import lib/definitions
2
+
3
+ $red: #ed1c24
4
+ $green: #74b87a
5
+ $dark: #616265
6
+ $mid: #9a9b9d
7
+
8
+ .message_list
9
+ div.message
10
+ margin-top: 5px
11
+ margin-bottom: 20px
12
+ p.description
13
+ margin: 0
14
+ color: $mid
15
+ font-size: 85%
16
+ p.excerpt
17
+ margin: 0
18
+
19
+ .sending_list
20
+ div.sending
21
+ margin-top: 5px
22
+ margin-bottom: 20px
23
+ p.description
24
+ margin: 0
25
+ color: $mid
26
+ font-size: 85%
27
+ p.responses
28
+ margin: 0
29
+
30
+ h2
31
+ a.message
32
+ margin-left: -32px
33
+ +big_icon_link("msg/message.png")
34
+ color: $text
35
+ +hover
36
+ // a.sending
37
+ // margin-left: -32px
38
+ // +big_icon_link("msg/sending.png")
39
+ // color: $text
40
+ // +hover
41
+
42
+ h2.section
43
+ font-size: 1.25em
44
+ line-height: 26px
45
+ clear: both
46
+ margin-top: 2em
47
+
48
+ #sending
49
+ position: relative
50
+ h2.subject
51
+ margin: 50px 0 30px -32px
52
+ margin-top: 50px
53
+ +big_icon_link("msg/sending.png")
54
+ .envelope
55
+ +box-shadow(1px 3px 8px $dark)
56
+ .headers
57
+ position: relative
58
+ overflow: hidden
59
+ margin: 0
60
+ padding: 10px 0
61
+ width: 100%
62
+ font-size: 0.8em
63
+ background-color: $palest
64
+ p
65
+ margin: 0 20px
66
+ span.field
67
+ display: inline-block
68
+ width: 45px
69
+ iframe.body
70
+ width: 100%
71
+ height: 700px
72
+ background-color: white
73
+ border: 0
74
+
75
+ ul.envelopes
76
+ padding: 0
77
+ margin: 0
78
+ list-style: none
79
+ li
80
+ &.unread
81
+ color: $mid
82
+ &.read
83
+ color: $green
84
+ font-weight: bold
85
+ &.bounced
86
+ color: $red
87
+ font-weight: bold
88
+
89
+ #preview_message, #send_message
90
+ width: 800px
91
+ .header
92
+ width: 770px
93
+ div.headers
94
+ position: relative
95
+ overflow: hidden
96
+ margin: 0
97
+ padding: 10px 0
98
+ width: 100%
99
+ font-size: 0.8em
100
+ p
101
+ margin: 0 20px
102
+ span.field
103
+ display: inline-block
104
+ width: 45px
105
+ form.new_sending
106
+ position: relative
107
+ margin-top: 0
108
+ iframe.body
109
+ position: relative
110
+ margin: 0 0 20px 0
111
+ width: 550px
112
+ height: 400px
113
+ background-color: white
114
+ border: 0
115
+ +box-shadow(1px 3px 8px $dark)
116
+ div.receivers
117
+ position: absolute
118
+ top: 0
119
+ right: 0
120
+ width: 196px
121
+ height: 400px
122
+ overflow: auto
123
+ font-size: 0.8em
124
+ h3
125
+ margin-top: 0
126
+ ul
127
+ margin: 0
128
+ padding: 0
129
+ list-style: none
130
+ &.choose_receivers
131
+ padding-left: 18px
132
+ #message
133
+ width: 800px
134
+ .header
135
+ width: 770px
136
+ form.message
137
+ p.subject
138
+ margin: 3px 0
139
+ input[type="text"]
140
+ width: 742px
141
+ font-size: 2.5em
142
+ font-weight: bold
143
+
144
+ p.sender
145
+ color: $mid
146
+ margin: 6px 0
147
+ input[type="text"]
148
+ font-size: 1em
149
+ float: left
150
+ margin-bottom: 6px
151
+ input.from_name
152
+ width: 260px
153
+ margin-right: 10px
154
+ input.from_address
155
+ width: 460px
156
+
157
+ p.function
158
+ color: $mid
159
+ margin: 6px 0 12px 0
160
+ input[type="text"]
161
+ font-size: 1em
162
+ span.transactional_detail
163
+ display: block
164
+ float: right
165
+ margin: 0 4px
166
+ input[type="text"]
167
+ width: 510px
168
+
169
+ div.messagebody
170
+ position: relative
171
+ p.show_details
172
+ margin: 2px 220px 0 0
173
+ float: right
174
+ textarea
175
+ width: 530px
176
+ height: 360px
177
+ font-size: 1.2em
178
+ div.instructions
179
+ position: absolute
180
+ width: 205px
181
+ right: 0
182
+ top: 16px
183
+ color: $mid
184
+ font-size: 80%
185
+ ul
186
+ list-style: none
187
+ padding: 0
188
+
189
+ p.saved
190
+ margin: 0 0 12px 0
191
+ span.saved_detail
192
+ display: block
193
+ margin: 6px 0
194
+ input[type="text"]
195
+ width: 742px
196
+ font-size: 1em
197
+
198
+ div.buttons
199
+ margin-top: 20px
200
+
201
+ #bouncebox
202
+ margin-top: 200px
203
+
204
+ #receivers
205
+ margin-top: 150px
206
+
207
+ #sentbox, #bouncebox
208
+ ul
209
+ padding: 0
210
+ list-style: none
211
+ li
212
+ margin-bottom: 12px
213
+ li.sending
214
+ a
215
+ display: block
216
+ font-weight: bold
217
+ margin-left: -20px
218
+