mailcatcher 0.8.0.beta2 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8ff3f1552fd9c0b07632dec0f3a993fbfaf6b31d61e683d9d6b4f26c477402d4
4
- data.tar.gz: 4099ebb85358d92e529a532625f52f900ad73e88e0c87e65937e2b5efb52ccad
3
+ metadata.gz: f1ad943e545062719f2c945235f105836fdb4bc3f8596d99bba21460b8a6ac27
4
+ data.tar.gz: 259a86e83b6f9c4ddb51fc8b8ad08fab065c3c2e7d55bc4570b3c148614eb690
5
5
  SHA512:
6
- metadata.gz: 336a8ba8f7dc2771fb09fb485a20a9bc548856262714afd7992984e757eead7025a4fcbc4e1b0f758a3996abcf538be847cc49073124e280b2422cb97961d00c
7
- data.tar.gz: 39f80d5d70717fc6e29a7933a7dbc79387caee7cd07a2f32f0c0545cfe514973b640887b7813a1179398e9e983de679fddb4df18bb71b9b0b9892c5d9d026ecf
6
+ metadata.gz: e2b053e9b9a7560e61418bda9599bc49ed8fb0a2d33324d5b1ff0d86d2a4dfb130ddb82397c056fff5f785beb6813eeddd1a6fc15bef20482fcebcf5bae7ad0b
7
+ data.tar.gz: af6ee3373801fc8d8cd62232b6ebe221a65b926154935a94c6a2de5f12616b5b40c5cb622658273f5e571f9db0083367b4fecd8521a8154bb7f7b294abde0b58
checksums.yaml.gz.sig CHANGED
Binary file
data/README.md CHANGED
@@ -26,11 +26,58 @@ MailCatcher runs a super simple SMTP server which catches any message sent to it
26
26
  3. Go to http://127.0.0.1:1080/
27
27
  4. Send mail through smtp://127.0.0.1:1025
28
28
 
29
- Use `mailcatcher --help` to see the command line options. The brave can get the source from [the GitHub repository][mailcatcher-github].
29
+ ### Command Line Options
30
+
31
+ Use `mailcatcher --help` to see the command line options.
32
+
33
+ ```
34
+ Usage: mailcatcher [options]
35
+
36
+ MailCatcher v0.8.0
37
+
38
+ --ip IP Set the ip address of both servers
39
+ --smtp-ip IP Set the ip address of the smtp server
40
+ --smtp-port PORT Set the port of the smtp server
41
+ --http-ip IP Set the ip address of the http server
42
+ --http-port PORT Set the port address of the http server
43
+ --messages-limit COUNT Only keep up to COUNT most recent messages
44
+ --http-path PATH Add a prefix to all HTTP paths
45
+ --no-quit Don't allow quitting the process
46
+ -f, --foreground Run in the foreground
47
+ -b, --browse Open web browser
48
+ -v, --verbose Be more verbose
49
+ -h, --help Display this help information
50
+ --version Display the current version
51
+ ```
52
+
53
+ ### Upgrading
54
+
55
+ Upgrading works the same as installation:
56
+
57
+ ```
58
+ gem install mailcatcher
59
+ ```
60
+
61
+ ### Ruby
62
+
63
+ If you have trouble with the setup commands, make sure you have [Ruby installed](https://www.ruby-lang.org/en/documentation/installation/):
64
+
65
+ ```
66
+ ruby -v
67
+ gem environment
68
+ ```
69
+
70
+ You might need to install build tools for some of the gem dependencies. On Debian or Ubuntu, `apt install build-essential`. On macOS, `xcode-select --install`.
71
+
72
+ If you encounter issues installing [thin](https://rubygems.org/gems/thin), try:
73
+
74
+ ```
75
+ gem install thin -v 1.5.1 -- --with-cflags="-Wno-error=implicit-function-declaration"
76
+ ```
30
77
 
31
78
  ### Bundler
32
79
 
33
- Please don't put mailcatcher into your Gemfile. It will conflict with your applications gems at some point.
80
+ Please don't put mailcatcher into your Gemfile. It will conflict with your application's gems at some point.
34
81
 
35
82
  Instead, pop a note in your README stating you use mailcatcher, and to run `gem install mailcatcher` then `mailcatcher` to get started.
36
83
 
@@ -51,11 +98,11 @@ To set up your rails app, I recommend adding this to your `environments/developm
51
98
 
52
99
  ### PHP
53
100
 
54
- For projects using PHP, or PHP frameworks and application platforms like Drupal, you can set [PHP's mail configuration](http://www.php.net/manual/en/mail.configuration.php) in your [php.ini](http://www.php.net/manual/en/configuration.file.php) to send via MailCatcher with:
101
+ For projects using PHP, or PHP frameworks and application platforms like Drupal, you can set [PHP's mail configuration](https://www.php.net/manual/en/mail.configuration.php) in your [php.ini](https://www.php.net/manual/en/configuration.file.php) to send via MailCatcher with:
55
102
 
56
103
  sendmail_path = /usr/bin/env catchmail -f some@from.address
57
104
 
58
- You can do this in your [Apache configuration](http://php.net/manual/en/configuration.changes.php) like so:
105
+ You can do this in your [Apache configuration](https://www.php.net/manual/en/configuration.changes.php) like so:
59
106
 
60
107
  php_admin_value sendmail_path "/usr/bin/env catchmail -f some@from.address"
61
108
 
@@ -80,19 +127,13 @@ if DEBUG:
80
127
 
81
128
  ### API
82
129
 
83
- A fairly RESTful URL schema means you can download a list of messages in JSON from `/messages`, each message's metadata with `/messages/:id.json`, and then the pertinent parts with `/messages/:id.html` and `/messages/:id.plain` for the default HTML and plain text version, `/messages/:id/:cid` for individual attachments by CID, or the whole message with `/messages/:id.source`.
130
+ A fairly RESTful URL schema means you can download a list of messages in JSON from `/messages`, each message's metadata with `/messages/:id.json`, and then the pertinent parts with `/messages/:id.html` and `/messages/:id.plain` for the default HTML and plain text version, `/messages/:id/parts/:cid` for individual attachments by CID, or the whole message with `/messages/:id.source`.
84
131
 
85
132
  ## Caveats
86
133
 
87
134
  * Mail processing is fairly basic but easily modified. If something doesn't work for you, fork and fix it or [file an issue][mailcatcher-issues] and let me know. Include the whole message you're having problems with.
88
135
  * Encodings are difficult. MailCatcher does not completely support utf-8 straight over the wire, you must use a mail library which encodes things properly based on SMTP server capabilities.
89
136
 
90
- ## TODO
91
-
92
- * Add mail delivery on request, optionally multiple times.
93
- * Compatibility testing against CampaignMonitor's [design guidelines](http://www.campaignmonitor.com/design-guidelines/) and [CSS support matrix](http://www.campaignmonitor.com/css/).
94
- * Forward mail to rendering service, maybe CampaignMonitor?
95
-
96
137
  ## Thanks
97
138
 
98
139
  MailCatcher is just a mishmash of other people's hard work. Thank you so much to the people who have built the wonderful guts on which this project relies.
@@ -109,4 +150,4 @@ Copyright © 2010-2019 Samuel Cochran (sj26@sj26.com). Released under the MIT Li
109
150
  [license]: https://github.com/sj26/mailcatcher/blob/master/LICENSE
110
151
  [mailcatcher-github]: https://github.com/sj26/mailcatcher
111
152
  [mailcatcher-issues]: https://github.com/sj26/mailcatcher/issues
112
- [websockets]: http://www.whatwg.org/specs/web-socket-protocol/
153
+ [websockets]: https://tools.ietf.org/html/rfc6455
@@ -36,6 +36,7 @@ module MailCatcher::Mail extend self
36
36
  FOREIGN KEY (message_id) REFERENCES message (id) ON DELETE CASCADE
37
37
  )
38
38
  SQL
39
+ db.execute("PRAGMA foreign_keys = ON")
39
40
  end
40
41
  end
41
42
  end
@@ -6,10 +6,11 @@ require "mail_catcher/mail"
6
6
 
7
7
  class MailCatcher::Smtp < EventMachine::Protocols::SmtpServer
8
8
  # We override EM's mail from processing to allow multiple mail-from commands
9
- # per [RFC 2821](http://tools.ietf.org/html/rfc2821#section-4.1.1.2)
9
+ # per [RFC 2821](https://tools.ietf.org/html/rfc2821#section-4.1.1.2)
10
10
  def process_mail_from sender
11
11
  if @state.include? :mail_from
12
12
  @state -= [:mail_from, :rcpt, :data]
13
+
13
14
  receive_reset
14
15
  end
15
16
 
@@ -22,25 +23,34 @@ class MailCatcher::Smtp < EventMachine::Protocols::SmtpServer
22
23
 
23
24
  def receive_reset
24
25
  @current_message = nil
26
+
25
27
  true
26
28
  end
27
29
 
28
30
  def receive_sender(sender)
31
+ # EventMachine SMTP advertises size extensions [https://tools.ietf.org/html/rfc1870]
32
+ # so strip potential " SIZE=..." suffixes from senders
33
+ sender = $` if sender =~ / SIZE=\d+\z/
34
+
29
35
  current_message[:sender] = sender
36
+
30
37
  true
31
38
  end
32
39
 
33
40
  def receive_recipient(recipient)
34
41
  current_message[:recipients] ||= []
35
42
  current_message[:recipients] << recipient
43
+
36
44
  true
37
45
  end
38
46
 
39
47
  def receive_data_chunk(lines)
40
48
  current_message[:source] ||= +""
49
+
41
50
  lines.each do |line|
42
51
  current_message[:source] << line << "\r\n"
43
52
  end
53
+
44
54
  true
45
55
  end
46
56
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MailCatcher
4
- VERSION = "0.8.0.beta2"
4
+ VERSION = "0.9.0"
5
5
  end
@@ -4,14 +4,31 @@ require "pathname"
4
4
  require "net/http"
5
5
  require "uri"
6
6
 
7
+ require "faye/websocket"
7
8
  require "sinatra"
8
- require "skinny"
9
9
 
10
10
  require "mail_catcher/bus"
11
11
  require "mail_catcher/mail"
12
12
 
13
+ Faye::WebSocket.load_adapter("thin")
14
+
15
+ # Faye's adapter isn't smart enough to close websockets when thin is stopped,
16
+ # so we teach it to do so.
17
+ class Thin::Backends::Base
18
+ alias :thin_stop :stop
19
+
20
+ def stop
21
+ thin_stop
22
+ @connections.each_value do |connection|
23
+ if connection.socket_stream
24
+ connection.socket_stream.close_connection_after_writing
25
+ end
26
+ end
27
+ end
28
+ end
29
+
13
30
  class Sinatra::Request
14
- include Skinny::Helpers
31
+ include Faye::WebSocket::Adapter
15
32
  end
16
33
 
17
34
  module MailCatcher
@@ -62,20 +79,24 @@ module MailCatcher
62
79
 
63
80
  get "/messages" do
64
81
  if request.websocket?
65
- request.websocket!(
66
- :on_start => proc do |websocket|
67
- bus_subscription = MailCatcher::Bus.subscribe do |message|
68
- begin
69
- websocket.send_message(JSON.generate(message))
70
- rescue => exception
71
- MailCatcher.log_exception("Error sending message through websocket", message, exception)
72
- end
82
+ bus_subscription = nil
83
+
84
+ ws = Faye::WebSocket.new(request.env)
85
+ ws.on(:open) do |_|
86
+ bus_subscription = MailCatcher::Bus.subscribe do |message|
87
+ begin
88
+ ws.send(JSON.generate(message))
89
+ rescue => exception
90
+ MailCatcher.log_exception("Error sending message through websocket", message, exception)
73
91
  end
92
+ end
93
+ end
74
94
 
75
- websocket.on_close do |*|
76
- MailCatcher::Bus.unsubscribe bus_subscription
77
- end
78
- end)
95
+ ws.on(:close) do |_|
96
+ MailCatcher::Bus.unsubscribe(bus_subscription) if bus_subscription
97
+ end
98
+
99
+ ws.rack_response
79
100
  else
80
101
  content_type :json
81
102
  JSON.generate(Mail.messages)
data/lib/mail_catcher.rb CHANGED
@@ -1,15 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Apparently rubygems won't activate these on its own, so here we go. Let's
4
- # repeat the invention of Bundler all over again.
5
- gem "eventmachine", "1.0.9.1"
6
- gem "mail", "~> 2.3"
7
- gem "rack", "~> 1.5"
8
- gem "sinatra", "~> 1.2"
9
- gem "sqlite3", "~> 1.3"
10
- gem "thin", "~> 1.5.0"
11
- gem "skinny", "~> 0.2.3"
12
-
13
3
  require "open3"
14
4
  require "optparse"
15
5
  require "rbconfig"
@@ -47,18 +37,10 @@ module MailCatcher extend self
47
37
  end
48
38
  end
49
39
 
50
- def mac?
51
- RbConfig::CONFIG["host_os"] =~ /darwin/
52
- end
53
-
54
40
  def windows?
55
41
  RbConfig::CONFIG["host_os"] =~ /mswin|mingw/
56
42
  end
57
43
 
58
- def macruby?
59
- mac? and const_defined? :MACRUBY_VERSION
60
- end
61
-
62
44
  def browseable?
63
45
  windows? or which? "open"
64
46
  end
@@ -79,7 +61,7 @@ module MailCatcher extend self
79
61
  puts "*** #{message}: #{context.inspect}"
80
62
  puts " Exception: #{exception}"
81
63
  puts " Backtrace:", *exception.backtrace.map { |line| " #{line.sub(gems_regexp, gems_replace)}" }
82
- puts " Please submit this as an issue at http://github.com/sj26/mailcatcher/issues"
64
+ puts " Please submit this as an issue at https://github.com/sj26/mailcatcher/issues"
83
65
  end
84
66
 
85
67
  @@defaults = {
@@ -108,6 +90,9 @@ module MailCatcher extend self
108
90
  OptionParser.new do |parser|
109
91
  parser.banner = "Usage: mailcatcher [options]"
110
92
  parser.version = VERSION
93
+ parser.separator ""
94
+ parser.separator "MailCatcher v#{VERSION}"
95
+ parser.separator ""
111
96
 
112
97
  parser.on("--ip IP", "Set the ip address of both servers") do |ip|
113
98
  options[:smtp_ip] = options[:http_ip] = ip
@@ -143,13 +128,6 @@ module MailCatcher extend self
143
128
  options[:quit] = false
144
129
  end
145
130
 
146
- if mac?
147
- parser.on("--[no-]growl") do |growl|
148
- puts "Growl is no longer supported"
149
- exit -2
150
- end
151
- end
152
-
153
131
  unless windows?
154
132
  parser.on("-f", "--foreground", "Run in the foreground") do
155
133
  options[:daemon] = false
@@ -166,10 +144,15 @@ module MailCatcher extend self
166
144
  options[:verbose] = true
167
145
  end
168
146
 
169
- parser.on("-h", "--help", "Display this help information") do
147
+ parser.on_tail("-h", "--help", "Display this help information") do
170
148
  puts parser
171
149
  exit
172
150
  end
151
+
152
+ parser.on_tail("--version", "Display the current version") do
153
+ puts "MailCatcher v#{VERSION}"
154
+ exit
155
+ end
173
156
  end.parse!
174
157
  end
175
158
  end
@@ -188,7 +171,7 @@ module MailCatcher extend self
188
171
  $stdout.sync = $stderr.sync = true
189
172
  end
190
173
 
191
- puts "Starting MailCatcher"
174
+ puts "Starting MailCatcher v#{VERSION}"
192
175
 
193
176
  Thin::Logging.debug = development?
194
177
  Thin::Logging.silent = !development?
@@ -202,12 +185,18 @@ module MailCatcher extend self
202
185
  end
203
186
 
204
187
  # Let Thin set itself up inside our EventMachine loop
205
- # (Skinny/WebSockets just works on the inside)
188
+ # Faye connections are hijacked but continue to be supervised by thin
206
189
  rescue_port options[:http_port] do
207
- Thin::Server.start(options[:http_ip], options[:http_port], Web)
190
+ Thin::Server.start(options[:http_ip], options[:http_port], Web, signals: false)
208
191
  puts "==> #{http_url}"
209
192
  end
210
193
 
194
+ # Make sure we quit nicely when asked
195
+ # We need to handle outside the trap context, hence the timer
196
+ %w(INT TERM QUIT).each do |signal|
197
+ trap(signal) { EM.add_timer(0) { quit! } }
198
+ end
199
+
211
200
  # Open the web browser before detatching console
212
201
  if options[:browse]
213
202
  EventMachine.next_tick do
@@ -230,6 +219,8 @@ module MailCatcher extend self
230
219
  end
231
220
 
232
221
  def quit!
222
+ MailCatcher::Bus.push(type: "quit")
223
+
233
224
  EventMachine.next_tick { EventMachine.stop_event_loop }
234
225
  end
235
226
 
@@ -240,7 +231,7 @@ protected
240
231
  end
241
232
 
242
233
  def http_url
243
- "http://#{@@options[:http_ip]}:#{@@options[:http_port]}#{@@options[:http_path]}"
234
+ "http://#{@@options[:http_ip]}:#{@@options[:http_port]}#{@@options[:http_path]}".chomp("/")
244
235
  end
245
236
 
246
237
  def rescue_port port
Binary file
Binary file
Binary file
@@ -1 +1 @@
1
- html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td,article,aside,canvas,details,embed,figure,figcaption,footer,header,hgroup,menu,nav,output,ruby,section,summary,time,mark,audio,video{margin:0;padding:0;border:0;font:inherit;font-size:100%;vertical-align:baseline}html{line-height:1}ol,ul{list-style:none}table{border-collapse:collapse;border-spacing:0}caption,th,td{text-align:left;font-weight:normal;vertical-align:middle}q,blockquote{quotes:none}q:before,q:after,blockquote:before,blockquote:after{content:"";content:none}a img{border:none}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}html,body{width:100%;height:100%}body{display:-moz-box;display:-webkit-box;display:box;-moz-box-orient:vertical;-webkit-box-orient:vertical;box-orient:vertical;background:#eee;color:#000;font-size:12px;font-family:Helvetica, sans-serif}body html{font-size:75%;line-height:1.5em}body.iframe{background:#fff}body.iframe h1{font-size:1.3em;margin:12px}body.iframe p,body.iframe form{margin:0 12px 12px 12px;line-height:1.25}body.iframe .loading{color:#666;margin-left:0.5em}.button{padding:0.5em 1em;border:1px solid #ccc;-moz-border-radius:2px;-webkit-border-radius:2px;border-radius:2px;background:url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjAuNSIgeTE9IjAuMCIgeDI9IjAuNSIgeTI9IjEuMCI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iI2Y0ZjRmNCIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iI2VjZWNlYyIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA=="),#ececec;background:-webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #f4f4f4), color-stop(100%, #ececec)),#ececec;background:-moz-linear-gradient(#f4f4f4, #ececec),#ececec;background:-webkit-linear-gradient(#f4f4f4, #ececec),#ececec;background:linear-gradient(#f4f4f4, #ececec),#ececec;color:#666;text-shadow:1px 1px 0 #fff;text-decoration:none}.button:hover,.button:focus{border-color:#999;border-bottom-color:#666;background:url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjAuNSIgeTE9IjAuMCIgeDI9IjAuNSIgeTI9IjEuMCI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iI2VlZWVlZSIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iI2RkZGRkZCIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA=="),#ddd;background:-webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #eee), color-stop(100%, #ddd)),#ddd;background:-moz-linear-gradient(#eee, #ddd),#ddd;background:-webkit-linear-gradient(#eee, #ddd),#ddd;background:linear-gradient(#eee, #ddd),#ddd;color:#333;text-decoration:none}.button:active,.button.active{border-color:#666;border-bottom-color:#999;background:url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjAuNSIgeTE9IjAuMCIgeDI9IjAuNSIgeTI9IjEuMCI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iI2RkZGRkZCIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iI2VlZWVlZSIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA=="),#eee;background:-webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #ddd), color-stop(100%, #eee)),#eee;background:-moz-linear-gradient(#ddd, #eee),#eee;background:-webkit-linear-gradient(#ddd, #eee),#eee;background:linear-gradient(#ddd, #eee),#eee;color:#333;text-decoration:none;text-shadow:-1px -1px 0 #eee}body>header{overflow:hidden;*zoom:1;border-bottom:1px solid #ccc}body>header h1{float:left;margin-left:6px;padding:6px;padding-left:30px;background:url(logo.png) left no-repeat;font-size:18px;font-weight:bold}body>header h1 a{color:black;text-decoration:none;text-shadow:0 1px 0 white;-moz-transition:ease 0.1s;-o-transition:ease 0.1s;-webkit-transition:ease 0.1s;transition:ease 0.1s}body>header h1 a:hover{color:#4183C4}body>header nav{border-left:1px solid #ccc}body>header nav.project{float:left}body>header nav.app{float:right}body>header nav li{display:block;float:left;border-left:1px solid #fff;border-right:1px solid #ccc}body>header nav li input{margin:6px}body>header nav li a{display:block;padding:10px;text-decoration:none;text-shadow:0 1px 0 white;background:url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjAuNSIgeTE9IjAuMCIgeDI9IjAuNSIgeTI9IjEuMCI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iI2Y0ZjRmNCIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iI2VjZWNlYyIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA=="),#ececec;background:-webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #f4f4f4), color-stop(100%, #ececec)),#ececec;background:-moz-linear-gradient(#f4f4f4, #ececec),#ececec;background:-webkit-linear-gradient(#f4f4f4, #ececec),#ececec;background:linear-gradient(#f4f4f4, #ececec),#ececec;color:#666;text-shadow:1px 1px 0 #fff;text-decoration:none}body>header nav li a:hover,body>header nav li a:focus{background:url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjAuNSIgeTE9IjAuMCIgeDI9IjAuNSIgeTI9IjEuMCI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iI2VlZWVlZSIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iI2RkZGRkZCIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA=="),#ddd;background:-webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #eee), color-stop(100%, #ddd)),#ddd;background:-moz-linear-gradient(#eee, #ddd),#ddd;background:-webkit-linear-gradient(#eee, #ddd),#ddd;background:linear-gradient(#eee, #ddd),#ddd;color:#333;text-decoration:none}body>header nav li a:active,body>header nav li a.active{background:url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjAuNSIgeTE9IjAuMCIgeDI9IjAuNSIgeTI9IjEuMCI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iI2RkZGRkZCIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iI2VlZWVlZSIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA=="),#eee;background:-webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #ddd), color-stop(100%, #eee)),#eee;background:-moz-linear-gradient(#ddd, #eee),#eee;background:-webkit-linear-gradient(#ddd, #eee),#eee;background:linear-gradient(#ddd, #eee),#eee;color:#333;text-decoration:none;text-shadow:-1px -1px 0 #eee}#messages{width:100%;height:10em;min-height:3em;overflow:auto;background:#fff;border-top:1px solid #fff}#messages table{overflow:hidden;*zoom:1;width:100%}#messages table thead tr{background:#eee;color:#333}#messages table thead tr th{padding:0.25em;font-weight:bold;color:#666;text-shadow:0 1px 0 white}#messages table tbody tr{cursor:pointer;-moz-transition:ease 0.1s;-o-transition:ease 0.1s;-webkit-transition:ease 0.1s;transition:ease 0.1s;color:#333}#messages table tbody tr:hover{color:#000}#messages table tbody tr:nth-child(even){background:#f0f0f0}#messages table tbody tr.selected{background:Highlight;color:HighlightText}#messages table tbody tr td{padding:0.25em}#messages table tbody tr td.blank{color:#666;font-style:italic}#resizer{padding-bottom:5px;cursor:ns-resize}#resizer .ruler{border-top:1px solid #ccc;border-bottom:1px solid #fff}#message{display:-moz-box;display:-webkit-box;display:box;-moz-box-orient:vertical;-webkit-box-orient:vertical;box-orient:vertical;-moz-box-flex:1;-webkit-box-flex:1;box-flex:1}#message>header{overflow:hidden;*zoom:1}#message>header .metadata{overflow:hidden;*zoom:1;padding:0.5em;padding-top:0}#message>header .metadata dt,#message>header .metadata dd{padding:0.25em}#message>header .metadata dt{float:left;clear:left;width:8em;margin-right:0.5em;text-align:right;font-weight:bold;color:#666;text-shadow:0 1px 0 white}#message>header .metadata dd.subject{font-weight:bold}#message>header .metadata .attachments{display:none}#message>header .metadata .attachments ul{display:inline}#message>header .metadata .attachments ul li{display:inline-block;vertical-align:middle;*vertical-align:auto;*zoom:1;*display:inline;margin-right:0.5em}#message>header .views ul{padding:0 0.5em;border-bottom:1px solid #ccc}#message>header .views .tab{display:inline-block;vertical-align:middle;*vertical-align:auto;*zoom:1;*display:inline}#message>header .views .tab a{display:inline-block;vertical-align:middle;*vertical-align:auto;*zoom:1;*display:inline;padding:0.5em;border:1px solid #ccc;background:#ddd;color:#333;border-width:1px 1px 0 1px;cursor:pointer;text-shadow:0 1px 0 #eeeeee;text-decoration:none}#message>header .views .tab:not(.selected):hover a{background-color:#eee}#message>header .views .tab.selected a{background:#fff;color:#000;height:13px;-moz-box-shadow:1px 1px 0 #ccc;-webkit-box-shadow:1px 1px 0 #ccc;box-shadow:1px 1px 0 #ccc;margin-bottom:-2px;cursor:default}#message>header .views .action{display:inline-block;vertical-align:middle;*vertical-align:auto;*zoom:1;*display:inline;float:right;margin:0 0.25em}.fractal-analysis{margin:12px 0}.fractal-analysis .report-intro{font-weight:bold}.fractal-analysis .report-intro.valid{color:#090}.fractal-analysis .report-intro.invalid{color:#c33}.fractal-analysis code{font-family:Monaco, "Courier New", Courier, monospace;background-color:#f8f8ff;color:#444;padding:0 0.2em;border:1px solid #dedede}.fractal-analysis ul{margin:1em 0 1em 1em;list-style-type:square}.fractal-analysis ol{margin:1em 0 1em 2em;list-style-type:decimal}.fractal-analysis ul li,.fractal-analysis ol li{display:list-item;margin:0.5em 0 0.5em 1em}.fractal-analysis .error-intro strong{font-weight:bold}.fractal-analysis .unsupported-clients dt{padding-left:1em}.fractal-analysis .unsupported-clients dd{padding-left:2em}.fractal-analysis .unsupported-clients dd ul li{display:list-item}iframe{display:-moz-box;display:-webkit-box;display:box;-moz-box-flex:1;-webkit-box-flex:1;box-flex:1;background:#fff}
1
+ html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td,article,aside,canvas,details,embed,figure,figcaption,footer,header,hgroup,menu,nav,output,ruby,section,summary,time,mark,audio,video{margin:0;padding:0;border:0;font:inherit;font-size:100%;vertical-align:baseline}html{line-height:1}ol,ul{list-style:none}table{border-collapse:collapse;border-spacing:0}caption,th,td{text-align:left;font-weight:normal;vertical-align:middle}q,blockquote{quotes:none}q:before,q:after,blockquote:before,blockquote:after{content:"";content:none}a img{border:none}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}html,body{width:100%;height:100%}body{display:-moz-box;display:-webkit-box;display:box;-moz-box-orient:vertical;-webkit-box-orient:vertical;box-orient:vertical;background:#eee;color:#000;font-size:12px;font-family:Helvetica, sans-serif}body html{font-size:75%;line-height:1.5em}body.iframe{background:#fff}body.iframe h1{font-size:1.3em;margin:12px}body.iframe p,body.iframe form{margin:0 12px 12px 12px;line-height:1.25}body.iframe .loading{color:#666;margin-left:0.5em}.button{padding:0.5em 1em;border:1px solid #ccc;-moz-border-radius:2px;-webkit-border-radius:2px;border-radius:2px;background:url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjAuNSIgeTE9IjAuMCIgeDI9IjAuNSIgeTI9IjEuMCI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iI2Y0ZjRmNCIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iI2VjZWNlYyIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA=="),#ececec;background:-webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #f4f4f4), color-stop(100%, #ececec)),#ececec;background:-moz-linear-gradient(#f4f4f4, #ececec),#ececec;background:-webkit-linear-gradient(#f4f4f4, #ececec),#ececec;background:linear-gradient(#f4f4f4, #ececec),#ececec;color:#666;text-shadow:1px 1px 0 #fff;text-decoration:none}.button:hover,.button:focus{border-color:#999;border-bottom-color:#666;background:url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjAuNSIgeTE9IjAuMCIgeDI9IjAuNSIgeTI9IjEuMCI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iI2VlZWVlZSIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iI2RkZGRkZCIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA=="),#ddd;background:-webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #eee), color-stop(100%, #ddd)),#ddd;background:-moz-linear-gradient(#eee, #ddd),#ddd;background:-webkit-linear-gradient(#eee, #ddd),#ddd;background:linear-gradient(#eee, #ddd),#ddd;color:#333;text-decoration:none}.button:active,.button.active{border-color:#666;border-bottom-color:#999;background:url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjAuNSIgeTE9IjAuMCIgeDI9IjAuNSIgeTI9IjEuMCI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iI2RkZGRkZCIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iI2VlZWVlZSIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA=="),#eee;background:-webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #ddd), color-stop(100%, #eee)),#eee;background:-moz-linear-gradient(#ddd, #eee),#eee;background:-webkit-linear-gradient(#ddd, #eee),#eee;background:linear-gradient(#ddd, #eee),#eee;color:#333;text-decoration:none;text-shadow:-1px -1px 0 #eee}body>header{overflow:hidden;*zoom:1;border-bottom:1px solid #ccc}body>header h1{float:left;margin-left:6px;padding:6px;padding-left:30px;background:url(logo.png) left no-repeat;background-size:24px 24px;font-size:18px;font-weight:bold}body>header h1 a{color:black;text-decoration:none;text-shadow:0 1px 0 white;-moz-transition:ease 0.1s;-o-transition:ease 0.1s;-webkit-transition:ease 0.1s;transition:ease 0.1s}body>header h1 a:hover{color:#4183C4}body>header nav{border-left:1px solid #ccc}body>header nav.project{float:left}body>header nav.app{float:right}body>header nav li{display:block;float:left;border-left:1px solid #fff;border-right:1px solid #ccc}body>header nav li input{margin:6px}body>header nav li a{display:block;padding:10px;text-decoration:none;text-shadow:0 1px 0 white;background:url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjAuNSIgeTE9IjAuMCIgeDI9IjAuNSIgeTI9IjEuMCI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iI2Y0ZjRmNCIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iI2VjZWNlYyIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA=="),#ececec;background:-webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #f4f4f4), color-stop(100%, #ececec)),#ececec;background:-moz-linear-gradient(#f4f4f4, #ececec),#ececec;background:-webkit-linear-gradient(#f4f4f4, #ececec),#ececec;background:linear-gradient(#f4f4f4, #ececec),#ececec;color:#666;text-shadow:1px 1px 0 #fff;text-decoration:none}body>header nav li a:hover,body>header nav li a:focus{background:url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjAuNSIgeTE9IjAuMCIgeDI9IjAuNSIgeTI9IjEuMCI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iI2VlZWVlZSIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iI2RkZGRkZCIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA=="),#ddd;background:-webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #eee), color-stop(100%, #ddd)),#ddd;background:-moz-linear-gradient(#eee, #ddd),#ddd;background:-webkit-linear-gradient(#eee, #ddd),#ddd;background:linear-gradient(#eee, #ddd),#ddd;color:#333;text-decoration:none}body>header nav li a:active,body>header nav li a.active{background:url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjAuNSIgeTE9IjAuMCIgeDI9IjAuNSIgeTI9IjEuMCI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iI2RkZGRkZCIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iI2VlZWVlZSIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA=="),#eee;background:-webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #ddd), color-stop(100%, #eee)),#eee;background:-moz-linear-gradient(#ddd, #eee),#eee;background:-webkit-linear-gradient(#ddd, #eee),#eee;background:linear-gradient(#ddd, #eee),#eee;color:#333;text-decoration:none;text-shadow:-1px -1px 0 #eee}#messages{width:100%;height:10em;min-height:3em;overflow:auto;background:#fff;border-top:1px solid #fff}#messages table{overflow:hidden;*zoom:1;width:100%}#messages table thead tr{background:#eee;color:#333}#messages table thead tr th{padding:0.25em;font-weight:bold;color:#666;text-shadow:0 1px 0 white}#messages table tbody tr{cursor:pointer;-moz-transition:ease 0.1s;-o-transition:ease 0.1s;-webkit-transition:ease 0.1s;transition:ease 0.1s;color:#333}#messages table tbody tr:hover{color:#000}#messages table tbody tr:nth-child(even){background:#f0f0f0}#messages table tbody tr.selected{background:Highlight;color:HighlightText}#messages table tbody tr td{padding:0.25em}#messages table tbody tr td.blank{color:#666;font-style:italic}#resizer{padding-bottom:5px;cursor:ns-resize}#resizer .ruler{border-top:1px solid #ccc;border-bottom:1px solid #fff}#message{display:-moz-box;display:-webkit-box;display:box;-moz-box-orient:vertical;-webkit-box-orient:vertical;box-orient:vertical;-moz-box-flex:1;-webkit-box-flex:1;box-flex:1}#message>header{overflow:hidden;*zoom:1}#message>header .metadata{overflow:hidden;*zoom:1;padding:0.5em;padding-top:0}#message>header .metadata dt,#message>header .metadata dd{padding:0.25em}#message>header .metadata dt{float:left;clear:left;width:8em;margin-right:0.5em;text-align:right;font-weight:bold;color:#666;text-shadow:0 1px 0 white}#message>header .metadata dd.subject{font-weight:bold}#message>header .metadata .attachments{display:none}#message>header .metadata .attachments ul{display:inline}#message>header .metadata .attachments ul li{display:inline-block;vertical-align:middle;*vertical-align:auto;*zoom:1;*display:inline;margin-right:0.5em}#message>header .views ul{padding:0 0.5em;border-bottom:1px solid #ccc}#message>header .views .tab{display:inline-block;vertical-align:middle;*vertical-align:auto;*zoom:1;*display:inline}#message>header .views .tab a{display:inline-block;vertical-align:middle;*vertical-align:auto;*zoom:1;*display:inline;padding:0.5em;border:1px solid #ccc;background:#ddd;color:#333;border-width:1px 1px 0 1px;cursor:pointer;text-shadow:0 1px 0 #eeeeee;text-decoration:none}#message>header .views .tab:not(.selected):hover a{background-color:#eee}#message>header .views .tab.selected a{background:#fff;color:#000;height:13px;-moz-box-shadow:1px 1px 0 #ccc;-webkit-box-shadow:1px 1px 0 #ccc;box-shadow:1px 1px 0 #ccc;margin-bottom:-2px;cursor:default}#message>header .views .action{display:inline-block;vertical-align:middle;*vertical-align:auto;*zoom:1;*display:inline;float:right;margin:0 0.25em}.fractal-analysis{margin:12px 0}.fractal-analysis .report-intro{font-weight:bold}.fractal-analysis .report-intro.valid{color:#090}.fractal-analysis .report-intro.invalid{color:#c33}.fractal-analysis code{font-family:Monaco, "Courier New", Courier, monospace;background-color:#f8f8ff;color:#444;padding:0 0.2em;border:1px solid #dedede}.fractal-analysis ul{margin:1em 0 1em 1em;list-style-type:square}.fractal-analysis ol{margin:1em 0 1em 2em;list-style-type:decimal}.fractal-analysis ul li,.fractal-analysis ol li{display:list-item;margin:0.5em 0 0.5em 1em}.fractal-analysis .error-intro strong{font-weight:bold}.fractal-analysis .unsupported-clients dt{padding-left:1em}.fractal-analysis .unsupported-clients dd{padding-left:2em}.fractal-analysis .unsupported-clients dd ul li{display:list-item}iframe{display:-moz-box;display:-webkit-box;display:box;-moz-box-flex:1;-webkit-box-flex:1;box-flex:1;background:#fff}@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi){body>header h1{background-image:url(logo_2x.png)}}#noscript-overlay{position:absolute;top:0;left:0;right:0;bottom:0;display:flex;align-items:center;justify-content:center;background-color:rgba(0,0,0,0.5);cursor:default;outline:none}#noscript{display:block;max-width:100%;margin:2rem;padding:2rem;border-radius:0.5rem;background-color:#fff;box-shadow:0 0 1rem 0 rgba(0,0,0,0.4)}