msg 0.1.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 (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
+