Showing 127 changed files with 2566 additions and 2781 deletions
+7 -9
mojo/lib/Mojo.pm
... ...
@@ -130,7 +130,7 @@ plugins, since non-blocking requests that are already in progress will
130 130
 interfere with new blocking ones.
131 131
 
132 132
   # Perform blocking request
133
-  my $body = $app->ua->get('mojolicio.us')->res->body;
133
+  my $body = $app->ua->get('example.com')->res->body;
134 134
 
135 135
 =head1 METHODS
136 136
 
... ...
@@ -153,17 +153,15 @@ object.
153 153
 
154 154
 =head2 config
155 155
 
156
-  my $config = $app->config;
157
-  my $foo    = $app->config('foo');
158
-  $app       = $app->config({foo => 'bar'});
159
-  $app       = $app->config(foo => 'bar');
156
+  my $hash = $app->config;
157
+  my $foo  = $app->config('foo');
158
+  $app     = $app->config({foo => 'bar'});
159
+  $app     = $app->config(foo => 'bar');
160 160
 
161 161
 Application configuration.
162 162
 
163
-  # Manipulate configuration
164
-  $app->config->{foo} = 'bar';
165
-  my $foo = $app->config->{foo};
166
-  delete $app->config->{foo};
163
+  # Remove value
164
+  my $foo = delete $app->config->{foo};
167 165
 
168 166
 =head2 handler
169 167
 
+3 -2
mojo/lib/Mojo/Asset.pm
... ...
@@ -83,9 +83,10 @@ subclass.
83 83
 =head2 get_chunk
84 84
 
85 85
   my $bytes = $asset->get_chunk($offset);
86
+  my $bytes = $asset->get_chunk($offset, $max);
86 87
 
87
-Get chunk of data starting from a specific position. Meant to be overloaded
88
-in a subclass.
88
+Get chunk of data starting from a specific position, defaults to a maximum
89
+chunk size of C<131072> bytes. Meant to be overloaded in a subclass.
89 90
 
90 91
 =head2 is_file
91 92
 
+16 -13
mojo/lib/Mojo/Asset/File.pm
... ...
@@ -22,7 +22,7 @@ has handle => sub {
22 22
   }
23 23
 
24 24
   # Open new or temporary file
25
-  my $base = catfile File::Spec::Functions::tmpdir, 'mojo.tmp';
25
+  my $base = catfile $self->tmpdir, 'mojo.tmp';
26 26
   my $name = defined $path ? $path : $base;
27 27
   until ($handle->open($name, O_CREAT | O_EXCL | O_RDWR)) {
28 28
     croak qq{Can't open file "$name": $!} if defined $path || $! != $!{EEXIST};
... ...
@@ -57,14 +57,14 @@ sub add_chunk {
57 57
 }
58 58
 
59 59
 sub contains {
60
-  my ($self, $string) = @_;
60
+  my ($self, $str) = @_;
61 61
 
62 62
   my $handle = $self->handle;
63 63
   $handle->sysseek($self->start_range, SEEK_SET);
64 64
 
65 65
   # Calculate window size
66 66
   my $end  = defined $self->end_range ? $self->end_range : $self->size;
67
-  my $len  = length $string;
67
+  my $len  = length $str;
68 68
   my $size = $len > 131072 ? $len : 131072;
69 69
   $size = $end - $self->start_range if $size > $end - $self->start_range;
70 70
 
... ...
@@ -79,7 +79,7 @@ sub contains {
79 79
     $window .= $buffer;
80 80
 
81 81
     # Search window
82
-    my $pos = index $window, $string;
82
+    my $pos = index $window, $str;
83 83
     return $offset + $pos if $pos >= 0;
84 84
     $offset += $read;
85 85
     return -1 if $read == 0 || $offset == $end;
... ...
@@ -92,19 +92,20 @@ sub contains {
92 92
 }
93 93
 
94 94
 sub get_chunk {
95
-  my ($self, $start) = @_;
95
+  my ($self, $offset, $max) = @_;
96
+  $max = defined $max ? $max : 131072;
96 97
 
97
-  $start += $self->start_range;
98
+  $offset += $self->start_range;
98 99
   my $handle = $self->handle;
99
-  $handle->sysseek($start, SEEK_SET);
100
+  $handle->sysseek($offset, SEEK_SET);
100 101
 
101 102
   my $buffer;
102 103
   if (defined(my $end = $self->end_range)) {
103
-    my $chunk = $end + 1 - $start;
104
+    my $chunk = $end + 1 - $offset;
104 105
     return '' if $chunk <= 0;
105
-    $handle->sysread($buffer, $chunk > 131072 ? 131072 : $chunk);
106
+    $handle->sysread($buffer, $chunk > $max ? $max : $chunk);
106 107
   }
107
-  else { $handle->sysread($buffer, 131072) }
108
+  else { $handle->sysread($buffer, $max) }
108 109
 
109 110
   return $buffer;
110 111
 }
... ...
@@ -199,7 +200,7 @@ necessary.
199 200
   $file      = $file->tmpdir('/tmp');
200 201
 
201 202
 Temporary directory used to generate C<path>, defaults to the value of the
202
-C<MOJO_TMPDIR> environment variable or auto detection.
203
+MOJO_TMPDIR environment variable or auto detection.
203 204
 
204 205
 =head1 METHODS
205 206
 
... ...
@@ -220,9 +221,11 @@ Check if asset contains a specific string.
220 221
 
221 222
 =head2 get_chunk
222 223
 
223
-  my $bytes = $file->get_chunk($start);
224
+  my $bytes = $file->get_chunk($offset);
225
+  my $bytes = $file->get_chunk($offset, $max);
224 226
 
225
-Get chunk of data starting from a specific position.
227
+Get chunk of data starting from a specific position, defaults to a maximum
228
+chunk size of C<131072> bytes.
226 229
 
227 230
 =head2 is_file
228 231
 
+12 -10
mojo/lib/Mojo/Asset/Memory.pm
... ...
@@ -21,26 +21,26 @@ sub add_chunk {
21 21
 }
22 22
 
23 23
 sub contains {
24
-  my ($self, $string) = @_;
24
+  my ($self, $str) = @_;
25 25
 
26 26
   my $start = $self->start_range;
27
-  my $pos = index $self->{content}, $string, $start;
27
+  my $pos = index $self->{content}, $str, $start;
28 28
   $pos -= $start if $start && $pos >= 0;
29 29
   my $end = $self->end_range;
30 30
 
31
-  return $end && ($pos + length $string) >= $end ? -1 : $pos;
31
+  return $end && ($pos + length $str) >= $end ? -1 : $pos;
32 32
 }
33 33
 
34 34
 sub get_chunk {
35
-  my ($self, $start) = @_;
35
+  my ($self, $offset, $max) = @_;
36
+  $max = defined $max ? $max : 131072;
36 37
 
37
-  $start += $self->start_range;
38
-  my $size = 131072;
38
+  $offset += $self->start_range;
39 39
   if (my $end = $self->end_range) {
40
-    $size = $end + 1 - $start if ($start + $size) > $end;
40
+    $max = $end + 1 - $offset if ($offset + $max) > $end;
41 41
   }
42 42
 
43
-  return substr shift->{content}, $start, $size;
43
+  return substr shift->{content}, $offset, $max;
44 44
 }
45 45
 
46 46
 sub move_to {
... ...
@@ -110,7 +110,7 @@ automatically upgrade to a L<Mojo::Asset::File> object.
110 110
 
111 111
 Maximum size in bytes of data to keep in memory before automatically upgrading
112 112
 to a L<Mojo::Asset::File> object, defaults to the value of the
113
-C<MOJO_MAX_MEMORY_SIZE> environment variable or C<262144>.
113
+MOJO_MAX_MEMORY_SIZE environment variable or C<262144>.
114 114
 
115 115
 =head1 METHODS
116 116
 
... ...
@@ -139,8 +139,10 @@ Check if asset contains a specific string.
139 139
 =head2 get_chunk
140 140
 
141 141
   my $bytes = $mem->get_chunk($offset);
142
+  my $bytes = $mem->get_chunk($offset, $max);
142 143
 
143
-Get chunk of data starting from a specific position.
144
+Get chunk of data starting from a specific position, defaults to a maximum
145
+chunk size of C<131072> bytes.
144 146
 
145 147
 =head2 move_to
146 148
 
+4 -3
mojo/lib/Mojo/Base.pm
... ...
@@ -213,7 +213,7 @@ pass it either a hash or a hash reference with attribute values.
213 213
 Create attribute accessor for hash-based objects, an array reference can be
214 214
 used to create more than one at a time. Pass an optional second argument to
215 215
 set a default value, it should be a constant or a callback. The callback will
216
-be excuted at accessor read time if there's no set value. Accessors can be
216
+be executed at accessor read time if there's no set value. Accessors can be
217 217
 chained, that means they return their invocant when they are called with an
218 218
 argument.
219 219
 
... ...
@@ -222,7 +222,8 @@ argument.
222 222
   $object = $object->tap(sub {...});
223 223
 
224 224
 K combinator, tap into a method chain to perform operations on an object
225
-within the chain.
225
+within the chain. The object will be the first argument passed to the closure
226
+and is also available via C<$_>.
226 227
 
227 228
 =head2 C<say>
228 229
 
... ...
@@ -230,7 +231,7 @@ Backported from perl-5.10.1
230 231
 
231 232
 =head1 DEBUGGING
232 233
 
233
-You can set the C<MOJO_BASE_DEBUG> environment variable to get some advanced
234
+You can set the MOJO_BASE_DEBUG environment variable to get some advanced
234 235
 diagnostics information printed to C<STDERR>.
235 236
 
236 237
   MOJO_BASE_DEBUG=1
+7 -14
mojo/lib/Mojo/ByteStream.pm
... ...
@@ -10,12 +10,11 @@ our @EXPORT_OK = ('b');
10 10
 
11 11
 # Turn most functions from Mojo::Util into methods
12 12
 my @UTILS = (
13
-  qw(b64_decode b64_encode camelize decamelize hmac_md5_sum hmac_sha1_sum),
14
-  qw(html_unescape md5_bytes md5_sum punycode_decode punycode_encode quote),
15
-  qw(sha1_bytes sha1_sum slurp spurt squish trim unquote url_escape),
16
-  qw(url_unescape xml_escape xor_encode)
13
+  qw(b64_decode b64_encode camelize decamelize hmac_sha1_sum html_unescape),
14
+  qw(md5_bytes md5_sum punycode_decode punycode_encode quote sha1_bytes),
15
+  qw(sha1_sum slurp spurt squish trim unquote url_escape url_unescape),
16
+  qw(xml_escape xor_encode)
17 17
 );
18
-push @UTILS, 'html_escape';    # DEPRECATED in Rainbow!
19 18
 for my $name (@UTILS) {
20 19
   my $sub = Mojo::Util->can($name);
21 20
   Mojo::Util::monkey_patch __PACKAGE__, $name, sub {
... ...
@@ -165,12 +164,6 @@ Encode bytestream with L<Mojo::Util/"encode">, defaults to C<UTF-8>.
165 164
 
166 165
   $stream->trim->quote->encode->say;
167 166
 
168
-=head2 hmac_md5_sum
169
-
170
-  $stream = $stream->hmac_md5_sum('passw0rd');
171
-
172
-Generate HMAC-MD5 checksum for bytestream with L<Mojo::Util/"hmac_md5_sum">.
173
-
174 167
 =head2 hmac_sha1_sum
175 168
 
176 169
   $stream = $stream->hmac_sha1_sum('passw0rd');
... ...
@@ -226,7 +219,7 @@ Print bytestream to handle and append a newline, defaults to C<STDOUT>.
226 219
 
227 220
 =head2 secure_compare
228 221
 
229
-  my $success = $stream->secure_compare($string);
222
+  my $success = $stream->secure_compare($str);
230 223
 
231 224
 Compare bytestream with L<Mojo::Util/"secure_compare">.
232 225
 
... ...
@@ -284,8 +277,8 @@ L<Mojo::Util/"squish">.
284 277
 
285 278
 =head2 to_string
286 279
 
287
-  my $string = $stream->to_string;
288
-  my $string = "$stream";
280
+  my $str = $stream->to_string;
281
+  my $str = "$stream";
289 282
 
290 283
 Stringify bytestream.
291 284
 
+12 -6
mojo/lib/Mojo/Collection.pm
... ...
@@ -28,16 +28,15 @@ sub each {
28 28
 
29 29
 sub first {
30 30
   my ($self, $cb) = @_;
31
-  return $cb ? do { (ref $cb) eq 'CODE' ? List::Util::first { $cb->($_) } @$self : List::Util::first { $_ =~ $cb } @$self } : $self->[0];
31
+  return $self->[0] unless $cb;
32
+  return List::Util::first { $cb->($_) } @$self if ref $cb eq 'CODE';
33
+  return List::Util::first { $_ =~ $cb } @$self;
32 34
 }
33 35
 
34 36
 sub grep {
35 37
   my ($self, $cb) = @_;
36
-  if ((ref $cb) eq 'CODE') {
37
-    return $self->new(grep { $cb->($_) } @$self);
38
-  } else {
39
-    return $self->new(grep { $_ =~ $cb } @$self);
40
-  }
38
+  return $self->new(grep { $cb->($_) } @$self) if ref $cb eq 'CODE';
39
+  return $self->new(grep { $_ =~ $cb } @$self);
41 40
 }
42 41
 
43 42
 sub join {
... ...
@@ -232,6 +231,13 @@ from the results.
232 231
 
233 232
 Create a new collection without duplicate elements.
234 233
 
234
+=head1 ELEMENTS
235
+
236
+Direct array reference access to elements is also possible.
237
+
238
+  say $collection->[23];
239
+  say for @$collection;
240
+
235 241
 =head1 SEE ALSO
236 242
 
237 243
 L<Mojolicious>, L<Mojolicious::Guides>, L<http://mojolicio.us>.
+12 -20
mojo/lib/Mojo/Content.pm
... ...
@@ -27,7 +27,7 @@ sub build_body    { shift->_build('get_body_chunk') }
27 27
 sub build_headers { shift->_build('get_header_chunk') }
28 28
 
29 29
 sub charset {
30
-  my $type = shift->headers->content_type || '';
30
+  my $type = do {my $tmp = shift->headers->content_type; defined $tmp ? $tmp : ''};
31 31
   return $type =~ /charset="?([^"\s;]+)"?/i ? $1 : undef;
32 32
 }
33 33
 
... ...
@@ -64,15 +64,13 @@ sub get_header_chunk {
64 64
   return substr $self->{header_buffer}, $offset, 131072;
65 65
 }
66 66
 
67
-sub has_leftovers { !!length shift->leftovers }
68
-
69 67
 sub header_size { length shift->build_headers }
70 68
 
71 69
 sub is_chunked { !!shift->headers->transfer_encoding }
72 70
 
73
-sub is_compressed { (shift->headers->content_encoding || '') =~ /^gzip$/i }
71
+sub is_compressed { (do {my $tmp = shift->headers->content_encoding; defined $tmp ? $tmp : ''}) =~ /^gzip$/i }
74 72
 
75
-sub is_dynamic { $_[0]->{dynamic} && !defined $_[0]->headers->content_length }
73
+sub is_dynamic { $_[0]{dynamic} && !defined $_[0]->headers->content_length }
76 74
 
77 75
 sub is_finished { my $tmp = shift->{state}; (defined $tmp ? $tmp : '') eq 'finished' }
78 76
 
... ...
@@ -117,8 +115,8 @@ sub parse {
117 115
   # Relaxed parsing
118 116
   my $headers = $self->headers;
119 117
   if ($self->auto_relax) {
120
-    my $connection = $headers->connection || '';
121
-    my $len = defined $headers->content_length ? $headers->content_length : '';
118
+    my $connection = defined $headers->connection ? $headers->connection : '';
119
+    my $len        = defined $headers->content_length ? $headers->content_length : '';
122 120
     $self->relaxed(1)
123 121
       if !length $len && ($connection =~ /close/i || $headers->content_type);
124 122
   }
... ...
@@ -155,7 +153,7 @@ sub parse_body {
155 153
 sub progress {
156 154
   my $self = shift;
157 155
   return 0 unless my $state = $self->{state};
158
-  return 0 unless grep { $_ eq $state } qw(body finished);
156
+  return 0 unless $state eq 'body' || $state eq 'finished';
159 157
   return $self->{raw_size} - ($self->{header_size} || 0);
160 158
 }
161 159
 
... ...
@@ -398,7 +396,7 @@ Content headers, defaults to a L<Mojo::Headers> object.
398 396
   $content = $content->max_buffer_size(1024);
399 397
 
400 398
 Maximum size in bytes of buffer for content parser, defaults to the value of
401
-the C<MOJO_MAX_BUFFER_SIZE> environment variable or C<262144>.
399
+the MOJO_MAX_BUFFER_SIZE environment variable or C<262144>.
402 400
 
403 401
 =head2 max_leftover_size
404 402
 
... ...
@@ -406,7 +404,7 @@ the C<MOJO_MAX_BUFFER_SIZE> environment variable or C<262144>.
406 404
   $content = $content->max_leftover_size(1024);
407 405
 
408 406
 Maximum size in bytes of buffer for pipelined HTTP requests, defaults to the
409
-value of the C<MOJO_MAX_LEFTOVER_SIZE> environment variable or C<262144>.
407
+value of the MOJO_MAX_LEFTOVER_SIZE environment variable or C<262144>.
410 408
 
411 409
 =head2 relaxed
412 410
 
... ...
@@ -449,13 +447,13 @@ Extract multipart boundary from C<Content-Type> header.
449 447
 
450 448
 =head2 build_body
451 449
 
452
-  my $string = $content->build_body;
450
+  my $str = $content->build_body;
453 451
 
454 452
 Render whole body.
455 453
 
456 454
 =head2 build_headers
457 455
 
458
-  my $string = $content->build_headers;
456
+  my $str = $content->build_headers;
459 457
 
460 458
 Render all headers.
461 459
 
... ...
@@ -481,20 +479,14 @@ Generate dynamic content.
481 479
 
482 480
   my $bytes = $content->get_body_chunk(0);
483 481
 
484
-Get a chunk of content starting from a specfic position. Meant to be
482
+Get a chunk of content starting from a specific position. Meant to be
485 483
 overloaded in a subclass.
486 484
 
487 485
 =head2 get_header_chunk
488 486
 
489 487
   my $bytes = $content->get_header_chunk(13);
490 488
 
491
-Get a chunk of the headers starting from a specfic position.
492
-
493
-=head2 has_leftovers
494
-
495
-  my $success = $content->has_leftovers;
496
-
497
-Check if there are leftovers.
489
+Get a chunk of the headers starting from a specific position.
498 490
 
499 491
 =head2 header_size
500 492
 
+2 -2
mojo/lib/Mojo/Content/MultiPart.pm
... ...
@@ -52,7 +52,7 @@ sub build_boundary {
52 52
 
53 53
   # Add boundary to Content-Type header
54 54
   my $headers = $self->headers;
55
-  ($headers->content_type || '') =~ m!^(.*multipart/[^;]+)(.*)$!;
55
+  (defined $headers->content_type ? $headers->content_type : '') =~ m!^(.*multipart/[^;]+)(.*)$!;
56 56
   my $before = $1 || 'multipart/mixed';
57 57
   my $after  = $2 || '';
58 58
   $headers->content_type("$before; boundary=$boundary$after");
... ...
@@ -289,7 +289,7 @@ Clone content if possible, otherwise return C<undef>.
289 289
 
290 290
   my $bytes = $multi->get_body_chunk(0);
291 291
 
292
-Get a chunk of content starting from a specfic position.
292
+Get a chunk of content starting from a specific position.
293 293
 
294 294
 =head2 is_multipart
295 295
 
+2 -2
mojo/lib/Mojo/Content/Single.pm
... ...
@@ -145,7 +145,7 @@ Clone content if possible, otherwise return C<undef>.
145 145
 
146 146
   my $bytes = $single->get_body_chunk(0);
147 147
 
148
-Get a chunk of content starting from a specfic position.
148
+Get a chunk of content starting from a specific position.
149 149
 
150 150
 =head2 parse
151 151
 
... ...
@@ -154,7 +154,7 @@ Get a chunk of content starting from a specfic position.
154 154
     = $single->parse("Content-Type: multipart/form-data\x0d\x0a\x0d\x0a");
155 155
 
156 156
 Parse content chunk and upgrade to L<Mojo::Content::MultiPart> object if
157
-possible.
157
+necessary.
158 158
 
159 159
 =head1 SEE ALSO
160 160
 
+13 -16
mojo/lib/Mojo/Cookie.pm
... ...
@@ -14,30 +14,26 @@ sub parse     { croak 'Method "parse" not implemented by subclass' }
14 14
 sub to_string { croak 'Method "to_string" not implemented by subclass' }
15 15
 
16 16
 sub _tokenize {
17
-  my ($self, $string) = @_;
17
+  my ($self, $str) = @_;
18 18
 
19 19
   # Nibbling parser
20 20
   my (@tree, @token);
21
-  while ($string) {
22
-
23
-    # Name
24
-    last unless $string =~ s/^\s*([^=;,]+)\s*=?\s*//;
21
+  while ($str =~ s/^\s*([^=;,]+)\s*=?\s*//) {
25 22
     my $name = $1;
26 23
 
27 24
     # "expires" is a special case, thank you Netscape...
28
-    $string =~ s/^([^;,]+,?[^;,]+)/"$1"/ if $name =~ /^expires$/i;
25
+    $str =~ s/^([^;,]+,?[^;,]+)/"$1"/ if $name =~ /^expires$/i;
29 26
 
30 27
     # Value
31 28
     my $value;
32
-    $value = unquote $1 if $string =~ s/^("(?:\\\\|\\"|[^"])+"|[^;,]+)\s*//;
29
+    $value = unquote $1 if $str =~ s/^("(?:\\\\|\\"|[^"])+"|[^;,]+)\s*//;
33 30
     push @token, [$name, $value];
34 31
 
35 32
     # Separator
36
-    $string =~ s/^\s*;\s*//;
37
-    if ($string =~ s/^\s*,\s*//) {
38
-      push @tree, [@token];
39
-      @token = ();
40
-    }
33
+    $str =~ s/^\s*;\s*//;
34
+    next unless $str =~ s/^\s*,\s*//;
35
+    push @tree, [@token];
36
+    @token = ();
41 37
   }
42 38
 
43 39
   # Take care of final token
... ...
@@ -60,7 +56,8 @@ Mojo::Cookie - HTTP cookie base class
60 56
 
61 57
 =head1 DESCRIPTION
62 58
 
63
-L<Mojo::Cookie> is an abstract base class for HTTP cookies.
59
+L<Mojo::Cookie> is an abstract base class for HTTP cookies as described in RFC
60
+6265.
64 61
 
65 62
 =head1 ATTRIBUTES
66 63
 
... ...
@@ -87,14 +84,14 @@ following new ones.
87 84
 
88 85
 =head2 parse
89 86
 
90
-  my $cookies = $cookie->parse($string);
87
+  my $cookies = $cookie->parse($str);
91 88
 
92 89
 Parse cookies. Meant to be overloaded in a subclass.
93 90
 
94 91
 =head2 to_string
95 92
 
96
-  my $string = $cookie->to_string;
97
-  my $string = "$cookie";
93
+  my $str = $cookie->to_string;
94
+  my $str = "$cookie";
98 95
 
99 96
 Render cookie. Meant to be overloaded in a subclass.
100 97
 
+7 -7
mojo/lib/Mojo/Cookie/Request.pm
... ...
@@ -4,14 +4,13 @@ use Mojo::Base 'Mojo::Cookie';
4 4
 use Mojo::Util 'quote';
5 5
 
6 6
 sub parse {
7
-  my ($self, $string) = @_;
7
+  my ($self, $str) = @_;
8 8
 
9 9
   my @cookies;
10
-  for my $token (map {@$_} $self->_tokenize($string)) {
10
+  for my $token (map {@$_} $self->_tokenize(defined $str ? $str : '')) {
11 11
     my ($name, $value) = @$token;
12 12
     next if $name =~ /^\$/;
13
-    push @cookies,
14
-      Mojo::Cookie::Request->new(name => $name, value => defined $value ? $value : '');
13
+    push @cookies, $self->new(name => $name, value => defined $value ? $value : '');
15 14
   }
16 15
 
17 16
   return \@cookies;
... ...
@@ -42,7 +41,8 @@ Mojo::Cookie::Request - HTTP request cookie
42 41
 
43 42
 =head1 DESCRIPTION
44 43
 
45
-L<Mojo::Cookie::Request> is a container for HTTP request cookies.
44
+L<Mojo::Cookie::Request> is a container for HTTP request cookies as described
45
+in RFC 6265.
46 46
 
47 47
 =head1 ATTRIBUTES
48 48
 
... ...
@@ -55,13 +55,13 @@ implements the following new ones.
55 55
 
56 56
 =head2 parse
57 57
 
58
-  my $cookies = $cookie->parse('f=b; g=a');
58
+  my $cookies = Mojo::Cookie::Request->parse('f=b; g=a');
59 59
 
60 60
 Parse cookies.
61 61
 
62 62
 =head2 to_string
63 63
 
64
-  my $string = $cookie->to_string;
64
+  my $str = $cookie->to_string;
65 65
 
66 66
 Render cookie.
67 67
 
+12 -15
mojo/lib/Mojo/Cookie/Response.pm
... ...
@@ -10,10 +10,8 @@ sub expires {
10 10
   my $self = shift;
11 11
 
12 12
   # Upgrade
13
-  return $self->{expires}
14
-    = defined $self->{expires} && !ref $self->{expires}
15
-    ? Mojo::Date->new($self->{expires})
16
-    : $self->{expires}
13
+  my $e = $self->{expires};
14
+  return $self->{expires} = defined $e && !ref $e ? Mojo::Date->new($e) : $e
17 15
     unless @_;
18 16
   $self->{expires} = shift;
19 17
 
... ...
@@ -21,23 +19,21 @@ sub expires {
21 19
 }
22 20
 
23 21
 sub parse {
24
-  my ($self, $string) = @_;
22
+  my ($self, $str) = @_;
25 23
 
26 24
   my @cookies;
27
-  for my $token ($self->_tokenize($string)) {
25
+  for my $token ($self->_tokenize(defined $str ? $str : '')) {
28 26
     for my $i (0 .. $#$token) {
29 27
       my ($name, $value) = @{$token->[$i]};
30 28
 
31 29
       # This will only run once
32
-      push(@cookies,
33
-        Mojo::Cookie::Response->new(name => $name, value => defined $value ? $value : ''))
34
-        and next
30
+      push @cookies, $self->new(name => $name, value => defined $value ? $value : '') and next
35 31
         unless $i;
36 32
 
37 33
       # Attributes (Netscape and RFC 6265)
38
-      next
39
-        unless my @match
34
+      my @match
40 35
         = $name =~ /^(expires|domain|path|secure|Max-Age|HttpOnly)$/msi;
36
+      next unless @match;
41 37
       my $attr = lc $match[0];
42 38
       $attr =~ tr/-/_/;
43 39
       $cookies[-1]->$attr($attr =~ /(?:secure|HttpOnly)/i ? 1 : $value);
... ...
@@ -94,12 +90,13 @@ Mojo::Cookie::Response - HTTP response cookie
94 90
 
95 91
 =head1 DESCRIPTION
96 92
 
97
-L<Mojo::Cookie::Response> is a container for HTTP response cookies.
93
+L<Mojo::Cookie::Response> is a container for HTTP response cookies as
94
+described in RFC 6265.
98 95
 
99 96
 =head1 ATTRIBUTES
100 97
 
101 98
 L<Mojo::Cookie::Response> inherits all attributes from L<Mojo::Cookie> and
102
-implements the followign new ones.
99
+implements the following new ones.
103 100
 
104 101
 =head2 domain
105 102
 
... ...
@@ -153,13 +150,13 @@ Expiration for cookie.
153 150
 
154 151
 =head2 parse
155 152
 
156
-  my $cookies = $cookie->parse('f=b; path=/');
153
+  my $cookies = Mojo::Cookie::Response->parse('f=b; path=/');
157 154
 
158 155
 Parse cookies.
159 156
 
160 157
 =head2 to_string
161 158
 
162
-  my $string = $cookie->to_string;
159
+  my $str = $cookie->to_string;
163 160
 
164 161
 Render cookie.
165 162
 
+58 -81
mojo/lib/Mojo/DOM.pm
... ...
@@ -18,12 +18,11 @@ use Scalar::Util qw(blessed weaken);
18 18
 sub AUTOLOAD {
19 19
   my $self = shift;
20 20
 
21
-  # Method
22 21
   my ($package, $method) = our $AUTOLOAD =~ /^([\w:]+)::(\w+)$/;
23 22
   croak "Undefined subroutine &${package}::$method called"
24 23
     unless blessed $self && $self->isa(__PACKAGE__);
25 24
 
26
-  # Search children
25
+  # Search children of current element
27 26
   my $children = $self->children($method);
28 27
   return @$children > 1 ? $children : $children->[0] if @$children;
29 28
   croak qq{Can't locate object method "$method" via package "$package"};
... ...
@@ -38,9 +37,8 @@ sub new {
38 37
 }
39 38
 
40 39
 sub all_text {
41
-  my ($self, $trim) = @_;
42
-  my $tree = $self->tree;
43
-  return _text(_elements($tree), 1, _trim($tree, $trim));
40
+  my $tree = shift->tree;
41
+  return _text(_elements($tree), 1, _trim($tree, @_));
44 42
 }
45 43
 
46 44
 sub append { shift->_add(1, @_) }
... ...
@@ -71,21 +69,17 @@ sub attrs {
71 69
   return $self;
72 70
 }
73 71
 
74
-sub charset { shift->_html(charset => @_) }
75
-
76 72
 sub children {
77 73
   my ($self, $type) = @_;
78 74
 
79 75
   my @children;
80
-  my $charset = $self->charset;
81
-  my $xml     = $self->xml;
82
-  my $tree    = $self->tree;
76
+  my $xml  = $self->xml;
77
+  my $tree = $self->tree;
83 78
   for my $e (@$tree[($tree->[0] eq 'root' ? 1 : 4) .. $#$tree]) {
84 79
 
85 80
     # Make sure child is the right type
86
-    next unless $e->[0] eq 'tag';
87
-    next if defined $type && $e->[1] ne $type;
88
-    push @children, $self->new->charset($charset)->tree($e)->xml($xml);
81
+    next if $e->[0] ne 'tag' || (defined $type && $e->[1] ne $type);
82
+    push @children, $self->new->tree($e)->xml($xml);
89 83
   }
90 84
 
91 85
   return Mojo::Collection->new(@children);
... ...
@@ -94,23 +88,20 @@ sub children {
94 88
 sub content_xml {
95 89
   my $self = shift;
96 90
 
97
-  # Render children
98
-  my $tree    = $self->tree;
99
-  my $charset = $self->charset;
100
-  my $xml     = $self->xml;
101
-  return join '', map {
102
-    Mojo::DOM::HTML->new(charset => $charset, tree => $_, xml => $xml)->render
103
-  } @$tree[($tree->[0] eq 'root' ? 1 : 4) .. $#$tree];
91
+  # Render children individually
92
+  my $tree = $self->tree;
93
+  my $xml  = $self->xml;
94
+  return join '',
95
+    map { Mojo::DOM::HTML->new(tree => $_, xml => $xml)->render }
96
+    @$tree[($tree->[0] eq 'root' ? 1 : 4) .. $#$tree];
104 97
 }
105 98
 
106 99
 sub find {
107 100
   my ($self, $selector) = @_;
108
-
109
-  my $charset = $self->charset;
110
-  my $xml     = $self->xml;
111
-  return Mojo::Collection->new(
112
-    map { $self->new->charset($charset)->tree($_)->xml($xml) }
113
-      @{Mojo::DOM::CSS->new(tree => $self->tree)->select($selector)});
101
+  my $xml = $self->xml;
102
+  my $results = Mojo::DOM::CSS->new(tree => $self->tree)->select($selector);
103
+  return Mojo::Collection->new(map { $self->new->tree($_)->xml($xml) }
104
+      @$results);
114 105
 }
115 106
 
116 107
 sub namespace {
... ...
@@ -119,8 +110,7 @@ sub namespace {
119 110
   # Extract namespace prefix and search parents
120 111
   return '' if (my $current = $self->tree)->[0] eq 'root';
121 112
   my $ns = $current->[1] =~ /^(.*?):/ ? "xmlns:$1" : undef;
122
-  while ($current) {
123
-    last if $current->[0] eq 'root';
113
+  while ($current->[0] ne 'root') {
124 114
 
125 115
     # Namespace for prefix
126 116
     my $attrs = $current->[2];
... ...
@@ -141,15 +131,10 @@ sub next { shift->_sibling(1) }
141 131
 sub parent {
142 132
   my $self = shift;
143 133
   return undef if (my $tree = $self->tree)->[0] eq 'root';
144
-  return $self->new->charset($self->charset)->tree($tree->[3])
145
-    ->xml($self->xml);
134
+  return $self->new->tree($tree->[3])->xml($self->xml);
146 135
 }
147 136
 
148
-sub parse {
149
-  my $self = shift;
150
-  $self->[0]->parse(@_);
151
-  return $self;
152
-}
137
+sub parse { shift->_html(parse => shift) }
153 138
 
154 139
 sub prepend { shift->_add(0, @_) }
155 140
 
... ...
@@ -168,12 +153,10 @@ sub remove { shift->replace('') }
168 153
 sub replace {
169 154
   my ($self, $new) = @_;
170 155
 
171
-  # Parse
172 156
   my $tree = $self->tree;
173 157
   if   ($tree->[0] eq 'root') { return $self->xml(undef)->parse($new) }
174 158
   else                        { $new = $self->_parse("$new") }
175 159
 
176
-  # Find and replace
177 160
   my $parent = $tree->[3];
178 161
   my $i = $parent->[0] eq 'root' ? 1 : 4;
179 162
   for my $e (@$parent[$i .. $#$parent]) {
... ...
@@ -202,13 +185,12 @@ sub root {
202 185
     $root = $parent;
203 186
   }
204 187
 
205
-  return $self->new->charset($self->charset)->tree($root)->xml($self->xml);
188
+  return $self->new->tree($root)->xml($self->xml);
206 189
 }
207 190
 
208 191
 sub text {
209
-  my ($self, $trim) = @_;
210
-  my $tree = $self->tree;
211
-  return _text(_elements($tree), 0, _trim($tree, $trim));
192
+  my $tree = shift->tree;
193
+  return _text(_elements($tree), 0, _trim($tree, @_));
212 194
 }
213 195
 
214 196
 sub text_after {
... ...
@@ -309,11 +291,7 @@ sub _parent {
309 291
   return \@new;
310 292
 }
311 293
 
312
-sub _parse {
313
-  my $self = shift;
314
-  Mojo::DOM::HTML->new(charset => $self->charset, xml => $self->xml)
315
-    ->parse(shift)->tree;
316
-}
294
+sub _parse { Mojo::DOM::HTML->new(xml => shift->xml)->parse(shift)->tree }
317 295
 
318 296
 sub _sibling {
319 297
   my ($self, $next) = @_;
... ...
@@ -410,7 +388,7 @@ Mojo::DOM - Minimalistic HTML/XML DOM parser with CSS selectors
410 388
   $dom->div->p->[1]->append('<p id="c">C</p>');
411 389
 
412 390
   # Render
413
-  say $dom;
391
+  say "$dom";
414 392
 
415 393
 =head1 DESCRIPTION
416 394
 
... ...
@@ -452,7 +430,8 @@ following new ones.
452 430
   my $dom = Mojo::DOM->new;
453 431
   my $dom = Mojo::DOM->new('<foo bar="baz">test</foo>');
454 432
 
455
-Construct a new array-based L<Mojo::DOM> object.
433
+Construct a new array-based L<Mojo::DOM> object and C<parse> HTML/XML document
434
+if necessary.
456 435
 
457 436
 =head2 all_text
458 437
 
... ...
@@ -472,7 +451,7 @@ enabled by default.
472 451
 
473 452
   $dom = $dom->append('<p>Hi!</p>');
474 453
 
475
-Append to element.
454
+Append HTML/XML to element.
476 455
 
477 456
   # "<div><h1>A</h1><h2>B</h2></div>"
478 457
   $dom->parse('<div><h1>A</h1></div>')->at('h1')->append('<h2>B</h2>')->root;
... ...
@@ -481,7 +460,7 @@ Append to element.
481 460
 
482 461
   $dom = $dom->append_content('<p>Hi!</p>');
483 462
 
484
-Append to element content.
463
+Append HTML/XML to element content.
485 464
 
486 465
   # "<div><h1>AB</h1></div>"
487 466
   $dom->parse('<div><h1>A</h1></div>')->at('h1')->append_content('B')->root;
... ...
@@ -490,8 +469,9 @@ Append to element content.
490 469
 
491 470
   my $result = $dom->at('html title');
492 471
 
493
-Find a single element with CSS selectors. All selectors from L<Mojo::DOM::CSS>
494
-are supported.
472
+Find first element matching the CSS selector and return it as a L<Mojo::DOM>
473
+object or return C<undef> if none could be found. All selectors from
474
+L<Mojo::DOM::CSS> are supported.
495 475
 
496 476
   # Find first element with "svg" namespace definition
497 477
   my $namespace = $dom->at('[xmlns\:svg]')->{'xmlns:svg'};
... ...
@@ -505,20 +485,13 @@ are supported.
505 485
 
506 486
 Element attributes.
507 487
 
508
-=head2 charset
509
-
510
-  my $charset = $dom->charset;
511
-  $dom        = $dom->charset('UTF-8');
512
-
513
-Charset used for decoding and encoding HTML/XML.
514
-
515 488
 =head2 children
516 489
 
517 490
   my $collection = $dom->children;
518 491
   my $collection = $dom->children('div');
519 492
 
520
-Return a L<Mojo::Collection> object containing the children of this element,
521
-similar to C<find>.
493
+Return a L<Mojo::Collection> object containing the children of this element as
494
+L<Mojo::DOM> objects, similar to C<find>.
522 495
 
523 496
   # Show type of random child element
524 497
   say $dom->children->shuffle->first->type;
... ...
@@ -527,8 +500,7 @@ similar to C<find>.
527 500
 
528 501
   my $xml = $dom->content_xml;
529 502
 
530
-Render content of this element to XML. Note that the XML will be encoded if a
531
-C<charset> has been defined.
503
+Render content of this element to XML.
532 504
 
533 505
   # "<b>test</b>"
534 506
   $dom->parse('<div><b>test</b></div>')->div->content_xml;
... ...
@@ -537,8 +509,9 @@ C<charset> has been defined.
537 509
 
538 510
   my $collection = $dom->find('html title');
539 511
 
540
-Find elements with CSS selectors and return a L<Mojo::Collection> object. All
541
-selectors from L<Mojo::DOM::CSS> are supported.
512
+Find all elements matching the CSS selector and return a L<Mojo::Collection>
513
+object containing these elements as L<Mojo::DOM> objects. All selectors from
514
+L<Mojo::DOM::CSS> are supported.
542 515
 
543 516
   # Find a specific element and extract information
544 517
   my $id = $dom->find('div')->[23]{id};
... ...
@@ -562,7 +535,8 @@ Find element namespace.
562 535
 
563 536
   my $sibling = $dom->next;
564 537
 
565
-Next sibling of element.
538
+Return L<Mojo::DOM> object for next sibling of element or C<undef> if there
539
+are no more siblings.
566 540
 
567 541
   # "<h2>B</h2>"
568 542
   $dom->parse('<div><h1>A</h1><h2>B</h2></div>')->at('h1')->next;
... ...
@@ -571,7 +545,8 @@ Next sibling of element.
571 545
 
572 546
   my $parent = $dom->parent;
573 547
 
574
-Parent of element.
548
+Return L<Mojo::DOM> object for parent of element or C<undef> if this element
549
+has no parent.
575 550
 
576 551
 =head2 parse
577 552
 
... ...
@@ -579,14 +554,14 @@ Parent of element.
579 554
 
580 555
 Parse HTML/XML document with L<Mojo::DOM::HTML>.
581 556
 
582
-  # Parse UTF-8 encoded XML
583
-  my $dom = Mojo::DOM->new->charset('UTF-8')->xml(1)->parse($xml);
557
+  # Parse XML
558
+  my $dom = Mojo::DOM->new->xml(1)->parse($xml);
584 559
 
585 560
 =head2 prepend
586 561
 
587 562
   $dom = $dom->prepend('<p>Hi!</p>');
588 563
 
589
-Prepend to element.
564
+Prepend HTML/XML to element.
590 565
 
591 566
   # "<div><h1>A</h1><h2>B</h2></div>"
592 567
   $dom->parse('<div><h2>B</h2></div>')->at('h2')->prepend('<h1>A</h1>')->root;
... ...
@@ -595,7 +570,7 @@ Prepend to element.
595 570
 
596 571
   $dom = $dom->prepend_content('<p>Hi!</p>');
597 572
 
598
-Prepend to element content.
573
+Prepend HTML/XML to element content.
599 574
 
600 575
   # "<div><h2>AB</h2></div>"
601 576
   $dom->parse('<div><h2>B</h2></div>')->at('h2')->prepend_content('A')->root;
... ...
@@ -604,7 +579,8 @@ Prepend to element content.
604 579
 
605 580
   my $sibling = $dom->previous;
606 581
 
607
-Previous sibling of element.
582
+Return L<Mojo::DOM> object for previous sibling of element or C<undef> if
583
+there are no more siblings.
608 584
 
609 585
   # "<h1>A</h1>"
610 586
   $dom->parse('<div><h1>A</h1><h2>B</h2></div>')->at('h2')->previous;
... ...
@@ -613,7 +589,7 @@ Previous sibling of element.
613 589
 
614 590
   my $old = $dom->remove;
615 591
 
616
-Remove element.
592
+Remove element and return it as a L<Mojo::DOM> object.
617 593
 
618 594
   # "<div></div>"
619 595
   $dom->parse('<div><h1>A</h1></div>')->at('h1')->remove->root;
... ...
@@ -622,7 +598,8 @@ Remove element.
622 598
 
623 599
   my $old = $dom->replace('<div>test</div>');
624 600
 
625
-Replace element.
601
+Replace element with HTML/XML and return the replaced element as a
602
+L<Mojo::DOM> object.
626 603
 
627 604
   # "<div><h2>B</h2></div>"
628 605
   $dom->parse('<div><h1>A</h1></div>')->at('h1')->replace('<h2>B</h2>')->root;
... ...
@@ -632,9 +609,9 @@ Replace element.
632 609
 
633 610
 =head2 replace_content
634 611
 
635
-  $dom = $dom->replace_content('test');
612
+  $dom = $dom->replace_content('<p>test</p>');
636 613
 
637
-Replace element content.
614
+Replace element content with HTML/XML.
638 615
 
639 616
   # "<div><h1>B</h1></div>"
640 617
   $dom->parse('<div><h1>A</h1></div>')->at('h1')->replace_content('B')->root;
... ...
@@ -646,7 +623,7 @@ Replace element content.
646 623
 
647 624
   my $root = $dom->root;
648 625
 
649
-Find root node.
626
+Return L<Mojo::DOM> object for root node.
650 627
 
651 628
 =head2 text
652 629
 
... ...
@@ -695,8 +672,7 @@ is enabled by default.
695 672
   my $xml = $dom->to_xml;
696 673
   my $xml = "$dom";
697 674
 
698
-Render this element and its content to XML. Note that the XML will be encoded
699
-if a C<charset> has been defined.
675
+Render this element and its content to XML.
700 676
 
701 677
   # "<b>test</b>"
702 678
   $dom->parse('<div><b>test</b></div>')->div->b->to_xml;
... ...
@@ -704,9 +680,10 @@ if a C<charset> has been defined.
704 680
 =head2 tree
705 681
 
706 682
   my $tree = $dom->tree;
707
-  $dom     = $dom->tree(['root', [qw(text lalala)]]);
683
+  $dom     = $dom->tree(['root', ['text', 'foo']]);
708 684
 
709
-Document Object Model.
685
+Document Object Model. Note that this structure should only be used very
686
+carefully since it is very dynamic.
710 687
 
711 688
 =head2 type
712 689
 
+4 -3
mojo/lib/Mojo/DOM/CSS.pm
... ...
@@ -52,7 +52,7 @@ sub select {
52 52
 
53 53
       # Try all selectors with element
54 54
       for my $part (@$pattern) {
55
-        push(@results, $current) and last
55
+        push @results, $current and last
56 56
           if $self->_combinator([reverse @$part], $current, $tree);
57 57
       }
58 58
     }
... ...
@@ -600,9 +600,10 @@ L<Mojo::DOM::CSS> implements the following attributes.
600 600
 =head2 tree
601 601
 
602 602
   my $tree = $css->tree;
603
-  $css     = $css->tree(['root', [qw(text lalala)]]);
603
+  $css     = $css->tree(['root', ['text', 'foo']]);
604 604
 
605
-Document Object Model.
605
+Document Object Model. Note that this structure should only be used very
606
+carefully since it is very dynamic.
606 607
 
607 608
 =head1 METHODS
608 609
 
+30 -89
mojo/lib/Mojo/DOM/HTML.pm
... ...
@@ -1,14 +1,13 @@
1 1
 package Mojo::DOM::HTML;
2 2
 use Mojo::Base -base;
3 3
 
4
-use Mojo::Util qw(decode encode html_unescape xml_escape);
4
+use Mojo::Util qw(html_unescape xml_escape);
5 5
 use Scalar::Util 'weaken';
6 6
 
7
-has [qw(charset xml)];
7
+has 'xml';
8 8
 has tree => sub { ['root'] };
9 9
 
10 10
 my $ATTR_RE = qr/
11
-  \s*
12 11
   ([^=\s>]+)       # Key
13 12
   (?:
14 13
     \s*=\s*
... ...
@@ -42,6 +41,7 @@ my $TOKEN_RE = qr/
42 41
     <(
43 42
       \s*
44 43
       [^>\s]+                                       # Tag
44
+      \s*
45 45
       (?:$ATTR_RE)*                                 # Attributes
46 46
     )>
47 47
   )??
... ...
@@ -76,9 +76,6 @@ my %INLINE = map { $_ => 1 } (
76 76
 sub parse {
77 77
   my ($self, $html) = @_;
78 78
 
79
-  my $charset = $self->charset;
80
-  defined ($html = decode($charset, $html)) || return $self->charset(undef) if $charset;
81
-
82 79
   my $tree    = ['root'];
83 80
   my $current = $tree;
84 81
   while ($html =~ m/\G$TOKEN_RE/gcs) {
... ...
@@ -86,22 +83,22 @@ sub parse {
86 83
       = ($1, $2, $3, $4, $5, $6);
87 84
 
88 85
     # Text
89
-    if (length $text) {
90
-      $text = html_unescape $text if (index $text, '&') >= 0;
91
-      $self->_text($text, \$current);
92
-    }
86
+    if (length $text) { push @$current, ['text', html_unescape($text)] }
93 87
 
94 88
     # DOCTYPE
95
-    if ($doctype) { $self->_doctype($doctype, \$current) }
89
+    if ($doctype) { push @$current, ['doctype', $doctype] }
96 90
 
97 91
     # Comment
98
-    elsif ($comment) { $self->_comment($comment, \$current) }
92
+    elsif ($comment) { push @$current, ['comment', $comment] }
99 93
 
100 94
     # CDATA
101
-    elsif ($cdata) { $self->_cdata($cdata, \$current) }
95
+    elsif ($cdata) { push @$current, ['cdata', $cdata] }
102 96
 
103
-    # Processing instruction
104
-    elsif ($pi) { $self->_pi($pi, \$current) }
97
+    # Processing instruction (try to detect XML)
98
+    elsif ($pi) {
99
+      $self->xml(1) if !defined $self->xml && $pi =~ /xml/i;
100
+      push @$current, ['pi', $pi];
101
+    }
105 102
 
106 103
     # End
107 104
     next unless $tag;
... ...
@@ -121,12 +118,10 @@ sub parse {
121 118
         # Empty tag
122 119
         next if $key eq '/';
123 120
 
124
-        # Add unescaped value
125
-        $value = html_unescape $value if $value && (index $value, '&') >= 0;
126
-        $attrs{$key} = $value;
121
+        $attrs{$key} = defined $value ? html_unescape($value) : $value;
127 122
       }
128 123
 
129
-      # Start
124
+      # Tag
130 125
       $self->_start($start, \%attrs, \$current);
131 126
 
132 127
       # Empty element
... ...
@@ -134,9 +129,9 @@ sub parse {
134 129
         if (!$self->xml && $VOID{$start}) || $attr =~ m!/\s*$!;
135 130
 
136 131
       # Relaxed "script" or "style"
137
-      if (grep { $_ eq $start } qw(script style)) {
132
+      if ($start eq 'script' || $start eq 'style') {
138 133
         if ($html =~ m!\G(.*?)<\s*/\s*$start\s*>!gcsi) {
139
-          $self->_raw($1, \$current);
134
+          push @$current, ['raw', $1];
140 135
           $self->_end($start, \$current);
141 136
         }
142 137
       }
... ...
@@ -146,17 +141,7 @@ sub parse {
146 141
   return $self->tree($tree);
147 142
 }
148 143
 
149
-sub render {
150
-  my $self    = shift;
151
-  my $content = $self->_render($self->tree);
152
-  my $charset = $self->charset;
153
-  return $charset ? encode($charset, $content) : $content;
154
-}
155
-
156
-sub _cdata {
157
-  my ($self, $cdata, $current) = @_;
158
-  push @$$current, ['cdata', $cdata];
159
-}
144
+sub render { $_[0]->_render($_[0]->tree) }
160 145
 
161 146
 sub _close {
162 147
   my ($self, $current, $tags, $stop) = @_;
... ...
@@ -165,8 +150,7 @@ sub _close {
165 150
 
166 151
   # Check if parents need to be closed
167 152
   my $parent = $$current;
168
-  while ($parent) {
169
-    last if $parent->[0] eq 'root' || $parent->[1] eq $stop;
153
+  while ($parent->[0] ne 'root' && $parent->[1] ne $stop) {
170 154
 
171 155
     # Close
172 156
     $tags->{$parent->[1]} and $self->_end($parent->[1], $current);
... ...
@@ -176,27 +160,13 @@ sub _close {
176 160
   }
177 161
 }
178 162
 
179
-sub _comment {
180
-  my ($self, $comment, $current) = @_;
181
-  push @$$current, ['comment', $comment];
182
-}
183
-
184
-sub _doctype {
185
-  my ($self, $doctype, $current) = @_;
186
-  push @$$current, ['doctype', $doctype];
187
-}
188
-
189 163
 sub _end {
190 164
   my ($self, $end, $current) = @_;
191 165
 
192
-  # Not a tag
193
-  return if $$current->[0] eq 'root';
194
-
195 166
   # Search stack for start tag
196 167
   my $found = 0;
197 168
   my $next  = $$current;
198
-  while ($next) {
199
-    last if $next->[0] eq 'root';
169
+  while ($next->[0] ne 'root') {
200 170
 
201 171
     # Right tag
202 172
     ++$found and last if $next->[1] eq $end;
... ...
@@ -213,17 +183,14 @@ sub _end {
213 183
 
214 184
   # Walk backwards
215 185
   $next = $$current;
216
-  while ($$current = $next) {
217
-    last if $$current->[0] eq 'root';
186
+  while (($$current = $next) && $$current->[0] ne 'root') {
218 187
     $next = $$current->[3];
219 188
 
220 189
     # Match
221 190
     if ($end eq $$current->[1]) { return $$current = $$current->[3] }
222 191
 
223 192
     # Optional elements
224
-    elsif ($OPTIONAL{$$current->[1]}) {
225
-      $self->_end($$current->[1], $current);
226
-    }
193
+    elsif ($OPTIONAL{$$current->[1]}) { $self->_end($$current->[1], $current) }
227 194
 
228 195
     # Table
229 196
     elsif ($end eq 'table') { $self->_close($current) }
... ...
@@ -233,18 +200,6 @@ sub _end {
233 200
   }
234 201
 }
235 202
 
236
-# Try to detect XML from processing instructions
237
-sub _pi {
238
-  my ($self, $pi, $current) = @_;
239
-  $self->xml(1) if !defined $self->xml && $pi =~ /xml/i;
240
-  push @$$current, ['pi', $pi];
241
-}
242
-
243
-sub _raw {
244
-  my ($self, $raw, $current) = @_;
245
-  push @$$current, ['raw', $raw];
246
-}
247
-
248 203
 sub _render {
249 204
   my ($self, $tree) = @_;
250 205
 
... ...
@@ -338,21 +293,18 @@ sub _start {
338 293
     elsif ($start eq 'tr') { $self->_close($current, {tr => 1}) }
339 294
 
340 295
     # "<th>" and "<td>"
341
-    elsif (grep { $_ eq $start } qw(th td)) {
342
-      $self->_close($current, {th => 1});
343
-      $self->_close($current, {td => 1});
296
+    elsif ($start eq 'th' || $start eq 'td') {
297
+      $self->_close($current, {$_ => 1}) for qw(th td);
344 298
     }
345 299
 
346 300
     # "<dt>" and "<dd>"
347
-    elsif (grep { $_ eq $start } qw(dt dd)) {
348
-      $self->_end('dt', $current);
349
-      $self->_end('dd', $current);
301
+    elsif ($start eq 'dt' || $start eq 'dd') {
302
+      $self->_end($_, $current) for qw(dt dd);
350 303
     }
351 304
 
352 305
     # "<rt>" and "<rp>"
353
-    elsif (grep { $_ eq $start } qw(rt rp)) {
354
-      $self->_end('rt', $current);
355
-      $self->_end('rp', $current);
306
+    elsif ($start eq 'rt' || $start eq 'rp') {
307
+      $self->_end($_, $current) for qw(rt rp);
356 308
     }
357 309
   }
358 310
 
... ...
@@ -363,11 +315,6 @@ sub _start {
363 315
   $$current = $new;
364 316
 }
365 317
 
366
-sub _text {
367
-  my ($self, $text, $current) = @_;
368
-  push @$$current, ['text', $text];
369
-}
370
-
371 318
 1;
372 319
 
373 320
 =head1 NAME
... ...
@@ -391,19 +338,13 @@ L<Mojo::DOM::HTML> is the HTML/XML engine used by L<Mojo::DOM>.
391 338
 
392 339
 L<Mojo::DOM::HTML> implements the following attributes.
393 340
 
394
-=head2 charset
395
-
396
-  my $charset = $html->charset;
397
-  $html       = $html->charset('UTF-8');
398
-
399
-Charset used for decoding and encoding HTML/XML.
400
-
401 341
 =head2 tree
402 342
 
403 343
   my $tree = $html->tree;
404
-  $html    = $html->tree(['root', [qw(text lalala)]]);
344
+  $html    = $html->tree(['root', ['text', 'foo']]);
405 345
 
406
-Document Object Model.
346
+Document Object Model. Note that this structure should only be used very
347
+carefully since it is very dynamic.
407 348
 
408 349
 =head2 xml
409 350
 
+4 -4
mojo/lib/Mojo/Date.pm
... ...
@@ -57,7 +57,7 @@ sub to_string {
57 57
 
58 58
   # RFC 2616 (Sun, 06 Nov 1994 08:49:37 GMT)
59 59
   my ($s, $m, $h, $mday, $month, $year, $wday) = gmtime(defined $self->epoch ? $self->epoch : time);
60
-  return sprintf "%s, %02d %s %04d %02d:%02d:%02d GMT", $DAYS[$wday], $mday,
60
+  return sprintf '%s, %02d %s %04d %02d:%02d:%02d GMT', $DAYS[$wday], $mday,
61 61
     $MONTHS[$month], $year + 1900, $h, $m, $s;
62 62
 }
63 63
 
... ...
@@ -109,7 +109,7 @@ following new ones.
109 109
   my $date = Mojo::Date->new;
110 110
   my $date = Mojo::Date->new('Sun Nov  6 08:49:37 1994');
111 111
 
112
-Construct a new L<Mojo::Date> object.
112
+Construct a new L<Mojo::Date> object and C<parse> date if necessary.
113 113
 
114 114
 =head2 parse
115 115
 
... ...
@@ -131,8 +131,8 @@ Parse date.
131 131
 
132 132
 =head2 to_string
133 133
 
134
-  my $string = $date->to_string;
135
-  my $string = "$date";
134
+  my $str = $date->to_string;
135
+  my $str = "$date";
136 136
 
137 137
 Render date suitable for HTTP messages.
138 138
 
+1 -1
mojo/lib/Mojo/EventEmitter.pm
... ...
@@ -198,7 +198,7 @@ Unsubscribe from event.
198 198
 
199 199
 =head1 DEBUGGING
200 200
 
201
-You can set the C<MOJO_EVENTEMITTER_DEBUG> environment variable to get some
201
+You can set the MOJO_EVENTEMITTER_DEBUG environment variable to get some
202 202
 advanced diagnostics information printed to C<STDERR>.
203 203
 
204 204
   MOJO_EVENTEMITTER_DEBUG=1
+13 -15
mojo/lib/Mojo/Exception.pm
... ...
@@ -9,7 +9,7 @@ use Scalar::Util 'blessed';
9 9
 
10 10
 has [qw(frames line lines_before lines_after)] => sub { [] };
11 11
 has message => 'Exception!';
12
-has verbose => sub { $ENV{MOJO_EXCEPTION_VERBOSE} || 0 };
12
+has 'verbose';
13 13
 
14 14
 sub new {
15 15
   my $self = shift->SUPER::new;
... ...
@@ -22,19 +22,19 @@ sub to_string {
22 22
   my $self = shift;
23 23
 
24 24
   return $self->message unless $self->verbose;
25
-  my $string = $self->message ? $self->message : '';
25
+  my $str = $self->message ? $self->message : '';
26 26
 
27 27
   # Before
28
-  $string .= $_->[0] . ': ' . $_->[1] . "\n" for @{$self->lines_before};
28
+  $str .= $_->[0] . ': ' . $_->[1] . "\n" for @{$self->lines_before};
29 29
 
30 30
   # Line
31
-  $string .= ($self->line->[0] . ': ' . $self->line->[1] . "\n")
31
+  $str .= ($self->line->[0] . ': ' . $self->line->[1] . "\n")
32 32
     if $self->line->[0];
33 33
 
34 34
   # After
35
-  $string .= $_->[0] . ': ' . $_->[1] . "\n" for @{$self->lines_after};
35
+  $str .= $_->[0] . ': ' . $_->[1] . "\n" for @{$self->lines_after};
36 36
 
37
-  return $string;
37
+  return $str;
38 38
 }
39 39
 
40 40
 sub trace {
... ...
@@ -100,8 +100,7 @@ sub _detect {
100 100
 
101 101
   # Search for context in files
102 102
   for my $frame (@trace) {
103
-    next unless -r $frame->[0];
104
-    open my $handle, '<:utf8', $frame->[0];
103
+    next unless -r $frame->[0] && open my $handle, '<:utf8', $frame->[0];
105 104
     $self->_context($frame->[1], [[<$handle>]]);
106 105
     return $self;
107 106
   }
... ...
@@ -148,21 +147,21 @@ Stacktrace.
148 147
   my $line = $e->line;
149 148
   $e       = $e->line([3 => 'foo']);
150 149
 
151
-The line where the exception occured.
150
+The line where the exception occurred.
152 151
 
153 152
 =head2 lines_after
154 153
 
155 154
   my $lines = $e->lines_after;
156 155
   $e        = $e->lines_after([[1 => 'bar'], [2 => 'baz']]);
157 156
 
158
-Lines after the line where the exception occured.
157
+Lines after the line where the exception occurred.
159 158
 
160 159
 =head2 lines_before
161 160
 
162 161
   my $lines = $e->lines_before;
163 162
   $e        = $e->lines_before([[4 => 'bar'], [5 => 'baz']]);
164 163
 
165
-Lines before the line where the exception occured.
164
+Lines before the line where the exception occurred.
166 165
 
167 166
 =head2 message
168 167
 
... ...
@@ -176,8 +175,7 @@ Exception message.
176 175
   my $verbose = $e->verbose;
177 176
   $e          = $e->verbose(1);
178 177
 
179
-Activate verbose rendering, defaults to the value of the
180
-C<MOJO_EXCEPTION_VERBOSE> environment variable or C<0>.
178
+Render exception with context.
181 179
 
182 180
 =head1 METHODS
183 181
 
... ...
@@ -200,8 +198,8 @@ Throw exception with stacktrace.
200 198
 
201 199
 =head2 to_string
202 200
 
203
-  my $string = $e->to_string;
204
-  my $string = "$e";
201
+  my $str = $e->to_string;
202
+  my $str = "$e";
205 203
 
206 204
 Render exception.
207 205
 
+28 -41
mojo/lib/Mojo/Headers.pm
... ...
@@ -29,21 +29,18 @@ sub add {
29 29
   my ($self, $name) = (shift, shift);
30 30
 
31 31
   # Make sure we have a normal case entry for name
32
-  my $lcname = lc $name;
33
-  $self->{normalcase}{$lcname} = $self->{normalcase}{$lcname} ? $self->{normalcase}{$lcname} : $name unless $NORMALCASE{$lcname};
32
+  my $key = lc $name;
33
+  $self->{normalcase}{$key} = defined $self->{normalcase}{$key} ? $self->{normalcase}{$key} : $name unless $NORMALCASE{$key};
34 34
 
35 35
   # Add lines
36
-  push @{$self->{headers}{$lcname}}, map { ref $_ eq 'ARRAY' ? $_ : [$_] } @_;
36
+  push @{$self->{headers}{$key}}, map { ref $_ eq 'ARRAY' ? $_ : [$_] } @_;
37 37
 
38 38
   return $self;
39 39
 }
40 40
 
41 41
 sub clone {
42
-  my $self  = shift;
43
-  my $clone = $self->new;
44
-  $clone->{headers}{$_} = [@{$self->{headers}{$_}}]
45
-    for keys %{$self->{headers}};
46
-  return $clone;
42
+  my $self = shift;
43
+  return $self->new->from_hash($self->to_hash(1));
47 44
 }
48 45
 
49 46
 sub from_hash {
... ...
@@ -102,10 +99,10 @@ sub parse {
102 99
     }
103 100
 
104 101
     # New header
105
-    if ($line =~ /^(\S+)\s*:\s*(.*)$/) { push @$headers, $1, $2 }
102
+    if ($line =~ /^(\S+)\s*:\s*(.*)$/) { push @$headers, $1, [$2] }
106 103
 
107 104
     # Multiline
108
-    elsif (@$headers && $line =~ s/^\s+//) { $headers->[-1] .= " $line" }
105
+    elsif (@$headers && $line =~ s/^\s+//) { push @{$headers->[-1]}, $line }
109 106
 
110 107
     # Empty line
111 108
     else {
... ...
@@ -132,30 +129,16 @@ sub remove {
132 129
 
133 130
 sub to_hash {
134 131
   my ($self, $multi) = @_;
135
-
136 132
   my %hash;
137
-  for my $header (@{$self->names}) {
138
-    my @headers = $self->header($header);
139
-
140
-    # Multi line
141
-    if ($multi) { $hash{$header} = [@headers] }
142
-
143
-    # Flat
144
-    else {
145
-
146
-      # Turn single value arrays into strings
147
-      @$_ == 1 and $_ = $_->[0] for @headers;
148
-      $hash{$header} = @headers > 1 ? [@headers] : $headers[0];
149
-    }
150
-  }
151
-
133
+  $hash{$_} = $multi ? [$self->header($_)] : scalar $self->header($_)
134
+    for @{$self->names};
152 135
   return \%hash;
153 136
 }
154 137
 
155 138
 sub to_string {
156 139
   my $self = shift;
157 140
 
158
-  # Format multiline values
141
+  # Make sure multiline values are formatted correctly
159 142
   my @headers;
160 143
   for my $name (@{$self->names}) {
161 144
     push @headers, "$name: " . join("\x0d\x0a ", @$_) for $self->header($name);
... ...
@@ -201,7 +184,7 @@ L<Mojo::Headers> implements the following attributes.
201 184
   $headers = $headers->max_line_size(1024);
202 185
 
203 186
 Maximum header line size in bytes, defaults to the value of the
204
-C<MOJO_MAX_LINE_SIZE> environment variable or C<10240>.
187
+MOJO_MAX_LINE_SIZE environment variable or C<10240>.
205 188
 
206 189
 =head1 METHODS
207 190
 
... ...
@@ -245,9 +228,11 @@ Shortcut for the C<Accept-Ranges> header.
245 228
 
246 229
 =head2 add
247 230
 
248
-  $headers = $headers->add('Content-Type', 'text/plain');
231
+  $headers = $headers->add(Foo => 'one value');
232
+  $headers = $headers->add(Foo => 'first value', 'second value');
233
+  $headers = $headers->add(Foo => ['first line', 'second line']);
249 234
 
250
-Add one or more header lines.
235
+Add one or more header values with one or more lines.
251 236
 
252 237
 =head2 authorization
253 238
 
... ...
@@ -359,13 +344,15 @@ Shortcut for the C<Expires> header.
359 344
   $headers = $headers->from_hash({'Content-Type' => 'text/html'});
360 345
   $headers = $headers->from_hash({});
361 346
 
362
-Parse headers from a hash reference.
347
+Parse headers from a hash reference, an empty hash removes all headers.
363 348
 
364 349
 =head2 header
365 350
 
366
-  my $string = $headers->header('Content-Type');
367
-  my @lines  = $headers->header('Content-Type');
368
-  $headers   = $headers->header('Content-Type' => 'text/plain');
351
+  my $value  = $headers->header('Foo');
352
+  my @values = $headers->header('Foo');
353
+  $headers   = $headers->header(Foo => 'one value');
354
+  $headers   = $headers->header(Foo => 'first value', 'second value');
355
+  $headers   = $headers->header(Foo => ['first line', 'second line']);
369 356
 
370 357
 Get or replace the current header values.
371 358
 
... ...
@@ -466,14 +453,14 @@ Shortcut for the C<Range> header.
466 453
 =head2 referrer
467 454
 
468 455
   my $referrer = $headers->referrer;
469
-  $headers     = $headers->referrer('http://mojolicio.us');
456
+  $headers     = $headers->referrer('http://example.com');
470 457
 
471 458
 Shortcut for the C<Referer> header, there was a typo in RFC 2068 which
472 459
 resulted in C<Referer> becoming an official header.
473 460
 
474 461
 =head2 remove
475 462
 
476
-  $headers = $headers->remove('Content-Type');
463
+  $headers = $headers->remove('Foo');
477 464
 
478 465
 Remove a header.
479 466
 
... ...
@@ -500,8 +487,8 @@ Shortcut for the C<Sec-WebSocket-Key> header from RFC 6455.
500 487
 
501 488
 =head2 sec_websocket_protocol
502 489
 
503
-  my $protocol = $headers->sec_websocket_protocol;
504
-  $headers     = $headers->sec_websocket_protocol('sample');
490
+  my $proto = $headers->sec_websocket_protocol;
491
+  $headers  = $headers->sec_websocket_protocol('sample');
505 492
 
506 493
 Shortcut for the C<Sec-WebSocket-Protocol> header from RFC 6455.
507 494
 
... ...
@@ -545,14 +532,14 @@ Shortcut for the C<TE> header.
545 532
   my $single = $headers->to_hash;
546 533
   my $multi  = $headers->to_hash(1);
547 534
 
548
-Turn headers into hash reference, nested array references to represent multi
549
-line values are disabled by default.
535
+Turn headers into hash reference, nested array references to represent
536
+multiline values are disabled by default.
550 537
 
551 538
   say $headers->to_hash->{DNT};
552 539
 
553 540
 =head2 to_string
554 541
 
555
-  my $string = $headers->to_string;
542
+  my $str = $headers->to_string;
556 543
 
557 544
 Turn headers into a string, suitable for HTTP messages.
558 545
 
+7 -15
mojo/lib/Mojo/Home.pm
... ...
@@ -80,14 +80,6 @@ sub parse {
80 80
 sub rel_dir { catdir(@{shift->{parts} || []}, split '/', shift) }
81 81
 sub rel_file { catfile(@{shift->{parts} || []}, split '/', shift) }
82 82
 
83
-# DEPRECATED in Rainbow!
84
-sub slurp_rel_file {
85
-  warn <<EOF;
86
-Mojo::Home->slurp_rel_file is DEPRECATED in favor of Mojo::Util->slurp!!!
87
-EOF
88
-  slurp shift->rel_file(@_);
89
-}
90
-
91 83
 sub to_string { catdir(@{shift->{parts} || []}) }
92 84
 
93 85
 1;
... ...
@@ -121,15 +113,15 @@ following new ones.
121 113
   my $home = Mojo::Home->new;
122 114
   my $home = Mojo::Home->new('/home/sri/myapp');
123 115
 
124
-Construct a new L<Mojo::Home> object.
116
+Construct a new L<Mojo::Home> object and C<parse> home directory if necessary.
125 117
 
126 118
 =head2 detect
127 119
 
128 120
   $home = $home->detect;
129 121
   $home = $home->detect('My::App');
130 122
 
131
-Detect home directory from the value of the C<MOJO_HOME> environment variable
132
-or application class.
123
+Detect home directory from the value of the MOJO_HOME environment variable or
124
+application class.
133 125
 
134 126
 =head2 lib_dir
135 127
 
... ...
@@ -143,9 +135,9 @@ Path to C<lib> directory of application.
143 135
   my $files = $home->list_files('foo/bar');
144 136
 
145 137
 Portably list all files recursively in directory relative to the home
146
-diectory.
138
+directory.
147 139
 
148
-  $home->rel_file($home->list_files('templates/layouts')->[1]);
140
+  say $home->rel_file($home->list_files('templates/layouts')->[1]);
149 141
 
150 142
 =head2 mojo_lib_dir
151 143
 
... ...
@@ -174,8 +166,8 @@ Portably generate an absolute path for a file relative to the home directory.
174 166
 
175 167
 =head2 to_string
176 168
 
177
-  my $string = $home->to_string;
178
-  my $string = "$home";
169
+  my $str = $home->to_string;
170
+  my $str = "$home";
179 171
 
180 172
 Home directory.
181 173
 
+51 -62
mojo/lib/Mojo/IOLoop.pm
... ...
@@ -9,9 +9,8 @@ use Mojo::IOLoop::Delay;
9 9
 use Mojo::IOLoop::Server;
10 10
 use Mojo::IOLoop::Stream;
11 11
 use Mojo::Reactor::Poll;
12
-use Mojo::Util 'md5_sum';
12
+use Mojo::Util qw(md5_sum steady_time);
13 13
 use Scalar::Util 'weaken';
14
-use Time::HiRes 'time';
15 14
 
16 15
 use constant DEBUG => $ENV{MOJO_IOLOOP_DEBUG} || 0;
17 16
 
... ...
@@ -39,9 +38,6 @@ sub acceptor {
39 38
   # Find acceptor for id
40 39
   return $self->{acceptors}{$acceptor} unless ref $acceptor;
41 40
 
42
-  # Make sure connection manager is running
43
-  $self->_manager;
44
-
45 41
   # Connect acceptor with reactor
46 42
   my $id = $self->_id;
47 43
   $self->{acceptors}{$id} = $acceptor;
... ...
@@ -58,8 +54,8 @@ sub client {
58 54
   my ($self, $cb) = (shift, pop);
59 55
   $self = $self->singleton unless ref $self;
60 56
 
61
-  # Make sure connection manager is running
62
-  $self->_manager;
57
+  # Make sure timers are running
58
+  $self->_timers;
63 59
 
64 60
   my $id     = $self->_id;
65 61
   my $c      = $self->{connections}{$id} ||= {};
... ...
@@ -117,7 +113,8 @@ sub recurring {
117 113
 sub remove {
118 114
   my ($self, $id) = @_;
119 115
   $self = $self->singleton unless ref $self;
120
-  if (my $c = $self->{connections}{$id}) { return $c->{finish} = 1 }
116
+  my $c = $self->{connections}{$id};
117
+  if ($c && (my $stream = $c->{stream})) { return $stream->close_gracefully }
121 118
   $self->_remove($id);
122 119
 }
123 120
 
... ...
@@ -182,18 +179,20 @@ sub timer {
182 179
 sub _accepting {
183 180
   my $self = shift;
184 181
 
185
-  # Check connection limit
186
-  return if $self->{accepting};
182
+  # Check if we have acceptors
187 183
   my $acceptors = $self->{acceptors} ||= {};
188
-  return unless keys %$acceptors;
184
+  return $self->_remove(delete $self->{accept}) unless keys %$acceptors;
185
+
186
+  # Check connection limit
189 187
   my $i   = keys %{$self->{connections}};
190 188
   my $max = $self->max_connections;
191 189
   return unless $i < $max;
192 190
 
193 191
   # Acquire accept mutex
194 192
   if (my $cb = $self->lock) { return unless $self->$cb(!$i) }
193
+  $self->_remove(delete $self->{accept});
195 194
 
196
-  # Check if multi-accept is desirable and start accepting
195
+  # Check if multi-accept is desirable
197 196
   my $multi = $self->multi_accept;
198 197
   $_->multi_accept($max < $multi ? 1 : $multi)->start for values %$acceptors;
199 198
   $self->{accepting}++;
... ...
@@ -202,38 +201,17 @@ sub _accepting {
202 201
 sub _id {
203 202
   my $self = shift;
204 203
   my $id;
205
-  do { $id = md5_sum('c' . time . rand 999) }
204
+  do { $id = md5_sum('c' . steady_time . rand 999) }
206 205
     while $self->{connections}{$id} || $self->{acceptors}{$id};
207 206
   return $id;
208 207
 }
209 208
 
210
-sub _manage {
211
-  my $self = shift;
212
-
213
-  # Try to acquire accept mutex
214
-  $self->_accepting;
215
-
216
-  # Close connections gracefully
217
-  my $connections = $self->{connections} ||= {};
218
-  while (my ($id, $c) = each %$connections) {
219
-    $self->_remove($id)
220
-      if $c->{finish} && (!$c->{stream} || !$c->{stream}->is_writing);
221
-  }
222
-
223
-  # Graceful stop
224
-  $self->_remove(delete $self->{manager})
225
-    unless keys %$connections || keys %{$self->{acceptors}};
226
-  $self->stop if $self->max_connections == 0 && keys %$connections == 0;
227
-}
228
-
229
-sub _manager {
230
-  my $self = shift;
231
-  $self->{manager} ||= $self->recurring($self->accept_interval => \&_manage);
232
-}
233
-
234 209
 sub _not_accepting {
235 210
   my $self = shift;
236 211
 
212
+  # Make sure timers are running
213
+  $self->_timers;
214
+
237 215
   # Release accept mutex
238 216
   return unless delete $self->{accepting};
239 217
   return unless my $cb = $self->unlock;
... ...
@@ -250,33 +228,42 @@ sub _remove {
250 228
   return if $reactor->remove($id);
251 229
 
252 230
   # Acceptor
253
-  if (delete $self->{acceptors}{$id}) { delete $self->{accepting} }
231
+  if (delete $self->{acceptors}{$id}) { $self->_not_accepting }
254 232
 
255
-  # Connection (stream needs to be deleted first)
256
-  else {
257
-    delete(($self->{connections}{$id} || {})->{stream});
258
-    delete $self->{connections}{$id};
259
-  }
233
+  # Connection
234
+  else { delete $self->{connections}{$id} }
235
+}
236
+
237
+sub _stop {
238
+  my $self = shift;
239
+  return      if keys %{$self->{connections}};
240
+  $self->stop if $self->max_connections == 0;
241
+  return      if keys %{$self->{acceptors}};
242
+  $self->{$_} && $self->_remove(delete $self->{$_}) for qw(accept stop);
260 243
 }
261 244
 
262 245
 sub _stream {
263 246
   my ($self, $stream, $id) = @_;
264 247
 
265
-  # Make sure connection manager is running
266
-  $self->_manager;
248
+  # Make sure timers are running
249
+  $self->_timers;
267 250
 
268 251
   # Connect stream with reactor
269 252
   $self->{connections}{$id}{stream} = $stream;
270 253
   weaken $stream->reactor($self->reactor)->{reactor};
271
-
272
-  # Start streaming
273 254
   weaken $self;
274
-  $stream->on(close => sub { $self->{connections}{$id}{finish} = 1 });
255
+  $stream->on(close => sub { $self && $self->_remove($id) });
275 256
   $stream->start;
276 257
 
277 258
   return $id;
278 259
 }
279 260
 
261
+sub _timers {
262
+  my $self = shift;
263
+  $self->{accept} ||= $self->recurring($self->accept_interval => \&_accepting);
264
+  $self->{stop} ||= $self->recurring(1 => \&_stop);
265
+}
266
+
280 267
 1;
281 268
 
282 269
 =head1 NAME
... ...
@@ -334,12 +321,14 @@ solid and scalable non-blocking TCP clients and servers.
334 321
 
335 322
 Optional modules L<EV> (4.0+), L<IO::Socket::IP> (0.16+) and
336 323
 L<IO::Socket::SSL> (1.75+) are supported transparently, and used if installed.
337
-Individual features can also be disabled with the C<MOJO_NO_IPV6> and
338
-C<MOJO_NO_TLS> environment variables.
324
+Individual features can also be disabled with the MOJO_NO_IPV6 and MOJO_NO_TLS
325
+environment variables.
339 326
 
340
-A TLS certificate and key are also built right in, to make writing test
341
-servers as easy as possible. Also note that for convenience the C<PIPE> signal
342
-will be set to C<IGNORE> when L<Mojo::IOLoop> is loaded.
327
+The event loop will be resilient to time jumps if a monotonic clock is
328
+available through L<Time::HiRes>. A TLS certificate and key are also built
329
+right in, to make writing test servers as easy as possible. Also note that for
330
+convenience the C<PIPE> signal will be set to C<IGNORE> when L<Mojo::IOLoop>
331
+is loaded.
343 332
 
344 333
 See L<Mojolicious::Guides::Cookbook> for more.
345 334
 
... ...
@@ -352,9 +341,9 @@ L<Mojo::IOLoop> implements the following attributes.
352 341
   my $interval = $loop->accept_interval;
353 342
   $loop        = $loop->accept_interval(0.5);
354 343
 
355
-Interval in seconds for trying to reacquire the accept mutex and connection
356
-management, defaults to C<0.025>. Note that changing this value can affect
357
-performance and idle CPU usage.
344
+Interval in seconds for trying to reacquire the accept mutex, defaults to
345
+C<0.025>. Note that changing this value can affect performance and idle CPU
346
+usage.
358 347
 
359 348
 =head2 lock
360 349
 
... ...
@@ -462,17 +451,17 @@ L<Mojo::IOLoop::Client/"connect">.
462 451
   my $delay = $loop->delay(sub {...});
463 452
   my $delay = $loop->delay(sub {...}, sub {...});
464 453
 
465
-Get L<Mojo::IOLoop::Delay> object to control the flow of events. A single
466
-callback will be treated as a subscriber to the C<finish> event, and multiple
467
-ones as a chain of steps.
454
+Get L<Mojo::IOLoop::Delay> object to manage callbacks and control the flow of
455
+events. A single callback will be treated as a subscriber to the C<finish>
456
+event, and multiple ones as a chain of steps.
468 457
 
469 458
   # Synchronize multiple events
470 459
   my $delay = Mojo::IOLoop->delay(sub { say 'BOOM!' });
471 460
   for my $i (1 .. 10) {
472
-    $delay->begin;
461
+    my $end = $delay->begin;
473 462
     Mojo::IOLoop->timer($i => sub {
474 463
       say 10 - $i;
475
-      $delay->end;
464
+      $end->();
476 465
     });
477 466
   }
478 467
 
... ...
@@ -614,7 +603,7 @@ seconds.
614 603
 
615 604
 =head1 DEBUGGING
616 605
 
617
-You can set the C<MOJO_IOLOOP_DEBUG> environment variable to get some advanced
606
+You can set the MOJO_IOLOOP_DEBUG environment variable to get some advanced
618 607
 diagnostics information printed to C<STDERR>.
619 608
 
620 609
   MOJO_IOLOOP_DEBUG=1
+1 -1
mojo/lib/Mojo/IOLoop/Client.pm
... ...
@@ -149,7 +149,7 @@ Mojo::IOLoop::Client - Non-blocking TCP client
149 149
     my ($client, $err) = @_;
150 150
     ...
151 151
   });
152
-  $client->connect(address => 'mojolicio.us', port => 80);
152
+  $client->connect(address => 'example.com', port => 80);
153 153
 
154 154
   # Start reactor if necessary
155 155
   $client->reactor->start unless $client->reactor->is_running;
+27 -40
mojo/lib/Mojo/IOLoop/Delay.pm
... ...
@@ -6,13 +6,12 @@ use Mojo::IOLoop;
6 6
 has ioloop => sub { Mojo::IOLoop->singleton };
7 7
 
8 8
 sub begin {
9
-  my $self = shift;
10
-  my $id   = $self->{counter}++;
11
-  return sub { shift; $self->_step($id, @_) };
9
+  my ($self, $ignore) = @_;
10
+  $self->{pending}++;
11
+  my $id = $self->{counter}++;
12
+  return sub { (defined $ignore ? $ignore : 1) and shift; $self->_step($id, @_) };
12 13
 }
13 14
 
14
-sub end { shift->_step(undef, @_) }
15
-
16 15
 sub steps {
17 16
   my $self = shift;
18 17
   $self->{steps} = [@_];
... ...
@@ -31,25 +30,16 @@ sub wait {
31 30
 sub _step {
32 31
   my ($self, $id) = (shift, shift);
33 32
 
34
-  # Arguments
35
-  my $ordered   = $self->{ordered}   ||= [];
36
-  my $unordered = $self->{unordered} ||= [];
37
-  if (defined $id) { $ordered->[$id] = [@_] }
38
-  else             { push @$unordered, @_ }
39
-
40
-  # Wait for more events
41
-  return $self->{counter} if --$self->{counter};
42
-
43
-  # Next step
44
-  my $cb = shift @{$self->{steps} ||= []};
45
-  $self->{$_} = [] for qw(ordered unordered);
46
-  my @args = ((map {@$_} grep {defined} @$ordered), @$unordered);
47
-  $self->$cb(@args) if $cb;
33
+  $self->{args}[$id] = [@_];
34
+  return $self->{pending} if --$self->{pending} || $self->{lock};
35
+  local $self->{lock} = 1;
36
+  my @args = map {@$_} @{delete $self->{args}};
48 37
 
49
-  # Finished
50
-  $self->emit('finish', @args)
51
-    if !$self->{counter} && !@{$self->{steps}} && !$self->{finished}++;
38
+  $self->{counter} = 0;
39
+  if (my $cb = shift @{$self->{steps} ||= []}) { $self->$cb(@args) }
52 40
 
41
+  if (!$self->{counter}) { $self->emit(finish => @args) }
42
+  elsif (!$self->{pending}) { $self->ioloop->timer(0 => $self->begin) }
53 43
   return 0;
54 44
 }
55 45
 
... ...
@@ -57,7 +47,7 @@ sub _step {
57 47
 
58 48
 =head1 NAME
59 49
 
60
-Mojo::IOLoop::Delay - Control the flow of events
50
+Mojo::IOLoop::Delay - Manage callbacks and control the flow of events
61 51
 
62 52
 =head1 SYNOPSIS
63 53
 
... ...
@@ -67,10 +57,10 @@ Mojo::IOLoop::Delay - Control the flow of events
67 57
   my $delay = Mojo::IOLoop::Delay->new;
68 58
   $delay->on(finish => sub { say 'BOOM!' });
69 59
   for my $i (1 .. 10) {
70
-    $delay->begin;
60
+    my $end = $delay->begin;
71 61
     Mojo::IOLoop->timer($i => sub {
72 62
       say 10 - $i;
73
-      $delay->end;
63
+      $end->();
74 64
     });
75 65
   }
76 66
 
... ...
@@ -105,7 +95,8 @@ Mojo::IOLoop::Delay - Control the flow of events
105 95
 
106 96
 =head1 DESCRIPTION
107 97
 
108
-L<Mojo::IOLoop::Delay> controls the flow of events for L<Mojo::IOLoop>.
98
+L<Mojo::IOLoop::Delay> manages callbacks and controls the flow of events for
99
+L<Mojo::IOLoop>.
109 100
 
110 101
 =head1 EVENTS
111 102
 
... ...
@@ -142,22 +133,17 @@ implements the following new ones.
142 133
 =head2 begin
143 134
 
144 135
   my $cb = $delay->begin;
136
+  my $cb = $delay->begin(0);
145 137
 
146
-Increment active event counter, the returned callback can be used instead of
147
-C<end>, which has the advantage of preserving the order of arguments. Note
148
-that the first argument passed to the callback will be ignored.
138
+Increment active event counter, the returned callback can be used to decrement
139
+the active event counter again. Arguments passed to the callback are queued in
140
+the right order for the next step or C<finish> event and C<wait> method, the
141
+first argument will be ignored by default.
149 142
 
143
+  # Capture all arguments
150 144
   my $delay = Mojo::IOLoop->delay;
151
-  Mojo::UserAgent->new->get('mojolicio.us' => $delay->begin);
152
-  my $tx = $delay->wait;
153
-
154
-=head2 end
155
-
156
-  my $remaining = $delay->end;
157
-  my $remaining = $delay->end(@args);
158
-
159
-Decrement active event counter, all arguments are queued for the next step or
160
-C<finish> event and C<wait> method.
145
+  Mojo::IOLoop->client({port => 3000} => $delay->begin(0));
146
+  my ($loop, $err, $stream) = $delay->wait;
161 147
 
162 148
 =head2 steps
163 149
 
... ...
@@ -165,7 +151,8 @@ C<finish> event and C<wait> method.
165 151
 
166 152
 Sequentialize multiple events, the first callback will run right away, and the
167 153
 next one once the active event counter reaches zero, this chain will continue
168
-until there are no more callbacks left.
154
+until there are no more callbacks or a callback does not increment the active
155
+event counter.
169 156
 
170 157
 =head2 wait
171 158
 
+1 -1
mojo/lib/Mojo/IOLoop/Server.pm
... ...
@@ -109,7 +109,7 @@ sub start {
109 109
     $self->{handle} => sub { $self->_accept for 1 .. $self->multi_accept });
110 110
 }
111 111
 
112
-sub stop { $_[0]->reactor->remove($_[0]->{handle}) }
112
+sub stop { $_[0]->reactor->remove($_[0]{handle}) }
113 113
 
114 114
 sub _accept {
115 115
   my $self = shift;
+70 -65
mojo/lib/Mojo/IOLoop/Stream.pm
... ...
@@ -3,56 +3,65 @@ use Mojo::Base 'Mojo::EventEmitter';
3 3
 
4 4
 use Errno qw(EAGAIN ECONNRESET EINTR EPIPE EWOULDBLOCK);
5 5
 use Scalar::Util 'weaken';
6
-use Time::HiRes 'time';
7 6
 
8 7
 has reactor => sub {
9 8
   require Mojo::IOLoop;
10 9
   Mojo::IOLoop->singleton->reactor;
11 10
 };
12
-has timeout => 15;
13 11
 
14 12
 sub DESTROY { shift->close }
15 13
 
16
-sub new { shift->SUPER::new(handle => shift, buffer => '', active => time) }
14
+sub new { shift->SUPER::new(handle => shift, buffer => '') }
17 15
 
18 16
 sub close {
19 17
   my $self = shift;
20 18
 
21 19
   # Cleanup
22 20
   return unless my $reactor = $self->{reactor};
23
-  $reactor->remove(delete $self->{timer}) if $self->{timer};
24
-  return unless my $handle = delete $self->{handle};
21
+  return unless my $handle  = delete $self->timeout(0)->{handle};
25 22
   $reactor->remove($handle);
26 23
 
27 24
   close $handle;
28 25
   $self->emit_safe('close');
29 26
 }
30 27
 
28
+sub close_gracefully {
29
+  my $self = shift;
30
+  return $self->{graceful} = 1 if $self->is_writing;
31
+  $self->close;
32
+}
33
+
31 34
 sub handle { shift->{handle} }
32 35
 
33 36
 sub is_readable {
34 37
   my $self = shift;
35
-  $self->{active} = time;
38
+  $self->_again;
36 39
   return $self->{handle} && $self->reactor->is_readable($self->{handle});
37 40
 }
38 41
 
39 42
 sub is_writing {
40 43
   my $self = shift;
41
-  return undef unless exists $self->{handle};
44
+  return undef unless $self->{handle};
42 45
   return !!length($self->{buffer}) || $self->has_subscribers('drain');
43 46
 }
44 47
 
45 48
 sub start {
46 49
   my $self = shift;
47
-  return $self->_startup unless $self->{startup}++;
48
-  return unless delete $self->{paused};
49
-  $self->reactor->watch($self->{handle}, 1, $self->is_writing);
50
+
51
+  my $reactor = $self->reactor;
52
+  $reactor->io($self->timeout(15)->{handle},
53
+    sub { pop() ? $self->_write : $self->_read })
54
+    unless $self->{timer};
55
+
56
+  # Resume
57
+  $reactor->watch($self->{handle}, 1, $self->is_writing)
58
+    if delete $self->{paused};
50 59
 }
51 60
 
52 61
 sub stop {
53 62
   my $self = shift;
54
-  return if $self->{paused}++;
55
-  $self->reactor->watch($self->{handle}, 0, $self->is_writing);
63
+  $self->reactor->watch($self->{handle}, 0, $self->is_writing)
64
+    unless $self->{paused}++;
56 65
 }
57 66
 
58 67
 sub steal_handle {
... ...
@@ -61,6 +70,21 @@ sub steal_handle {
61 70
   return delete $self->{handle};
62 71
 }
63 72
 
73
+sub timeout {
74
+  my $self = shift;
75
+
76
+  return $self->{timeout} unless @_;
77
+
78
+  my $reactor = $self->reactor;
79
+  $reactor->remove(delete $self->{timer}) if $self->{timer};
80
+  return $self unless my $timeout = $self->{timeout} = shift;
81
+  weaken $self;
82
+  $self->{timer}
83
+    = $reactor->timer($timeout => sub { $self->emit_safe('timeout')->close });
84
+
85
+  return $self;
86
+}
87
+
64 88
 sub write {
65 89
   my ($self, $chunk, $cb) = @_;
66 90
 
... ...
@@ -73,42 +97,27 @@ sub write {
73 97
   return $self;
74 98
 }
75 99
 
76
-sub _read {
77
-  my $self = shift;
78
-
79
-  my $read = $self->{handle}->sysread(my $buffer, 131072, 0);
80
-  unless (defined $read) {
81
-
82
-    # Retry
83
-    return if grep { $_ == $! } EAGAIN, EINTR, EWOULDBLOCK;
100
+sub _again { $_[0]->reactor->again($_[0]{timer}) if $_[0]{timer} }
84 101
 
85
-    # Closed
86
-    return $self->close if grep { $_ == $! } ECONNRESET, EPIPE;
102
+sub _error {
103
+  my $self = shift;
87 104
 
88
-    # Read error
89
-    return $self->emit_safe(error => $!)->close;
90
-  }
105
+  # Retry
106
+  return if $! == EAGAIN || $! == EINTR || $! == EWOULDBLOCK;
91 107
 
92
-  # EOF
93
-  return $self->close if $read == 0;
108
+  # Closed
109
+  return $self->close if $! == ECONNRESET || $! == EPIPE;
94 110
 
95
-  $self->emit_safe(read => $buffer)->{active} = time;
111
+  # Error
112
+  $self->emit_safe(error => $!)->close;
96 113
 }
97 114
 
98
-sub _startup {
115
+sub _read {
99 116
   my $self = shift;
100
-
101
-  # Timeout (ignore 0 timeout)
102
-  my $reactor = $self->reactor;
103
-  weaken $self;
104
-  $self->{timer} = $reactor->recurring(
105
-    0.5 => sub {
106
-      return unless my $t = $self->timeout;
107
-      $self->emit_safe('timeout')->close if (time - $self->{active}) >= $t;
108
-    }
109
-  );
110
-
111
-  $reactor->io($self->{handle}, sub { pop() ? $self->_write : $self->_read });
117
+  my $read = $self->{handle}->sysread(my $buffer, 131072, 0);
118
+  return $self->_error unless defined $read;
119
+  return $self->close if $read == 0;
120
+  $self->emit_safe(read => $buffer)->_again;
112 121
 }
113 122
 
114 123
 sub _write {
... ...
@@ -117,25 +126,15 @@ sub _write {
117 126
   my $handle = $self->{handle};
118 127
   if (length $self->{buffer}) {
119 128
     my $written = $handle->syswrite($self->{buffer});
120
-    unless (defined $written) {
121
-
122
-      # Retry
123
-      return if grep { $_ == $! } EAGAIN, EINTR, EWOULDBLOCK;
124
-
125
-      # Closed
126
-      return $self->close if grep { $_ == $! } ECONNRESET, EPIPE;
127
-
128
-      # Write error
129
-      return $self->emit_safe(error => $!)->close;
130
-    }
131
-
129
+    return $self->_error unless defined $written;
132 130
     $self->emit_safe(write => substr($self->{buffer}, 0, $written, ''));
133
-    $self->{active} = time;
131
+    $self->_again;
134 132
   }
135 133
 
136
-  $self->emit_safe('drain') if !length $self->{buffer};
134
+  $self->emit_safe('drain') unless length $self->{buffer};
137 135
   return if $self->is_writing;
138
-  $self->reactor->watch($handle, !$self->{paused}, 0);
136
+  return $self->close if $self->{graceful};
137
+  $self->reactor->watch($handle, !$self->{paused}, 0) if $self->{handle};
139 138
 }
140 139
 
141 140
 1;
... ...
@@ -247,15 +246,6 @@ L<Mojo::IOLoop::Stream> implements the following attributes.
247 246
 Low level event reactor, defaults to the C<reactor> attribute value of the
248 247
 global L<Mojo::IOLoop> singleton.
249 248
 
250
-=head2 timeout
251
-
252
-  my $timeout = $stream->timeout;
253
-  $stream     = $stream->timeout(45);
254
-
255
-Maximum amount of time in seconds stream can be inactive before getting closed
256
-automatically, defaults to C<15>. Setting the value to C<0> will allow this
257
-stream to be inactive indefinitely.
258
-
259 249
 =head1 METHODS
260 250
 
261 251
 L<Mojo::IOLoop::Stream> inherits all methods from L<Mojo::EventEmitter> and
... ...
@@ -273,6 +263,12 @@ Construct a new L<Mojo::IOLoop::Stream> object.
273 263
 
274 264
 Close stream immediately.
275 265
 
266
+=head2 close_gracefully
267
+
268
+  $stream->close_gracefully;
269
+
270
+Close stream gracefully.
271
+
276 272
 =head2 handle
277 273
 
278 274
   my $handle = $stream->handle;
... ...
@@ -310,6 +306,15 @@ Stop watching for new data on the stream.
310 306
 
311 307
 Steal handle from stream and prevent it from getting closed automatically.
312 308
 
309
+=head2 timeout
310
+
311
+  my $timeout = $stream->timeout;
312
+  $stream     = $stream->timeout(45);
313
+
314
+Maximum amount of time in seconds stream can be inactive before getting closed
315
+automatically, defaults to C<15>. Setting the value to C<0> will allow this
316
+stream to be inactive indefinitely.
317
+
313 318
 =head2 write
314 319
 
315 320
   $stream = $stream->write($bytes);
+9 -10
mojo/lib/Mojo/JSON.pm
... ...
@@ -98,7 +98,7 @@ sub decode {
98 98
 
99 99
 sub encode {
100 100
   my ($self, $ref) = @_;
101
-  return Mojo::Util::encode 'UTF-8', _encode_values($ref);
101
+  return Mojo::Util::encode 'UTF-8', _encode_value($ref);
102 102
 }
103 103
 
104 104
 sub false {$FALSE}
... ...
@@ -251,23 +251,23 @@ sub _decode_value {
251 251
 
252 252
 sub _encode_array {
253 253
   my $array = shift;
254
-  return '[' . join(',', map { _encode_values($_) } @$array) . ']';
254
+  return '[' . join(',', map { _encode_value($_) } @$array) . ']';
255 255
 }
256 256
 
257 257
 sub _encode_object {
258 258
   my $object = shift;
259
-  my @pairs = map { _encode_string($_) . ':' . _encode_values($object->{$_}) }
259
+  my @pairs = map { _encode_string($_) . ':' . _encode_value($object->{$_}) }
260 260
     keys %$object;
261 261
   return '{' . join(',', @pairs) . '}';
262 262
 }
263 263
 
264 264
 sub _encode_string {
265
-  my $string = shift;
266
-  $string =~ s!([\x00-\x1F\x7F\x{2028}\x{2029}\\"/\b\f\n\r\t])!$REVERSE{$1}!gs;
267
-  return "\"$string\"";
265
+  my $str = shift;
266
+  $str =~ s!([\x00-\x1F\x7F\x{2028}\x{2029}\\"/\b\f\n\r\t])!$REVERSE{$1}!gs;
267
+  return "\"$str\"";
268 268
 }
269 269
 
270
-sub _encode_values {
270
+sub _encode_value {
271 271
   my $value = shift;
272 272
 
273 273
   # Reference
... ...
@@ -285,7 +285,7 @@ sub _encode_values {
285 285
 
286 286
     # Blessed reference with TO_JSON method
287 287
     if (blessed $value && (my $sub = $value->can('TO_JSON'))) {
288
-      return _encode_values($value->$sub);
288
+      return _encode_value($value->$sub);
289 289
     }
290 290
   }
291 291
 
... ...
@@ -294,8 +294,7 @@ sub _encode_values {
294 294
 
295 295
   # Number
296 296
   my $flags = B::svref_2object(\$value)->FLAGS;
297
-  return $value
298
-    if $flags & (B::SVp_IOK | B::SVp_NOK) && !($flags & B::SVp_POK);
297
+  return 0 + $value if $flags & (B::SVp_IOK | B::SVp_NOK) && $value * 0 == 0;
299 298
 
300 299
   # String
301 300
   return _encode_string($value);
+9 -4
mojo/lib/Mojo/JSON/Pointer.pm
... ...
@@ -1,7 +1,6 @@
1 1
 package Mojo::JSON::Pointer;
2 2
 use Mojo::Base -base;
3 3
 
4
-use Mojo::Util qw(decode url_unescape);
5 4
 use Scalar::Util 'looks_like_number';
6 5
 
7 6
 sub contains { shift->_pointer(1, @_) }
... ...
@@ -10,9 +9,8 @@ sub get      { shift->_pointer(0, @_) }
10 9
 sub _pointer {
11 10
   my ($self, $contains, $data, $pointer) = @_;
12 11
 
13
-  $pointer = decode('UTF-8', url_unescape $pointer);
14 12
   return $data unless $pointer =~ s!^/!!;
15
-  for my $p (split '/', $pointer) {
13
+  for my $p ($pointer eq '' ? ($pointer) : (split '/', $pointer)) {
16 14
     $p =~ s/~0/~/g;
17 15
     $p =~ s!~1!/!g;
18 16
 
... ...
@@ -33,6 +31,8 @@ sub _pointer {
33 31
 
34 32
 1;
35 33
 
34
+=encoding utf8
35
+
36 36
 =head1 NAME
37 37
 
38 38
 Mojo::JSON::Pointer - JSON Pointers
... ...
@@ -47,7 +47,7 @@ Mojo::JSON::Pointer - JSON Pointers
47 47
 
48 48
 =head1 DESCRIPTION
49 49
 
50
-L<Mojo::JSON::Pointer> implements JSON Pointers.
50
+L<Mojo::JSON::Pointer> is a relaxed implementation of RFC 6901.
51 51
 
52 52
 =head1 METHODS
53 53
 
... ...
@@ -59,10 +59,12 @@ Check if data structure contains a value that can be identified with the given
59 59
 JSON Pointer.
60 60
 
61 61
   # True
62
+  $pointer->contains({'♥' => 'mojolicious'}, '/♥');
62 63
   $pointer->contains({foo => 'bar', baz => [4, 5, 6]}, '/foo');
63 64
   $pointer->contains({foo => 'bar', baz => [4, 5, 6]}, '/baz/2');
64 65
 
65 66
   # False
67
+  $pointer->contains({'♥' => 'mojolicious'}, '/☃');
66 68
   $pointer->contains({foo => 'bar', baz => [4, 5, 6]}, '/bar');
67 69
   $pointer->contains({foo => 'bar', baz => [4, 5, 6]}, '/baz/9');
68 70
 
... ...
@@ -72,6 +74,9 @@ JSON Pointer.
72 74
 
73 75
 Extract value identified by the given JSON Pointer.
74 76
 
77
+  # "mojolicious"
78
+  $pointer->get({'♥' => 'mojolicious'}, '/♥');
79
+
75 80
   # "bar"
76 81
   $pointer->get({foo => 'bar', baz => [4, 5, 6]}, '/foo');
77 82
 
+5 -5
mojo/lib/Mojo/Log.pm
... ...
@@ -3,18 +3,18 @@ use Mojo::Base 'Mojo::EventEmitter';
3 3
 
4 4
 use Carp 'croak';
5 5
 use Fcntl ':flock';
6
+use Mojo::Util 'encode';
6 7
 
7 8
 has handle => sub {
8 9
 
9 10
   # File
10 11
   if (my $path = shift->path) {
11 12
     croak qq{Can't open log file "$path": $!}
12
-      unless open my $file, '>>:utf8', $path;
13
+      unless open my $file, '>>', $path;
13 14
     return $file;
14 15
   }
15 16
 
16 17
   # STDERR
17
-  binmode STDERR, ':utf8';
18 18
   return \*STDERR;
19 19
 };
20 20
 has level => 'debug';
... ...
@@ -63,7 +63,7 @@ sub _message {
63 63
 
64 64
   flock $handle, LOCK_EX;
65 65
   croak "Can't write to log: $!"
66
-    unless defined $handle->syswrite($self->format($level, @lines));
66
+    unless $handle->print(encode 'UTF-8', $self->format($level, @lines));
67 67
   flock $handle, LOCK_UN;
68 68
 }
69 69
 
... ...
@@ -131,8 +131,8 @@ or C<STDERR>.
131 131
   my $level = $log->level;
132 132
   $log      = $log->level('debug');
133 133
 
134
-Active log level, defaults to the value of the C<MOJO_LOG_LEVEL> environment
135
-variable or C<debug>.
134
+Active log level, defaults to C<debug>. Note that the MOJO_LOG_LEVEL
135
+environment variable can override this value.
136 136
 
137 137
 These levels are currently available:
138 138
 
+55 -153
mojo/lib/Mojo/Message.pm
... ...
@@ -10,7 +10,6 @@ use Mojo::JSON::Pointer;
10 10
 use Mojo::Parameters;
11 11
 use Mojo::Upload;
12 12
 use Mojo::Util 'decode';
13
-use Scalar::Util 'weaken';
14 13
 
15 14
 has content => sub { Mojo::Content::Single->new };
16 15
 has default_charset  => 'UTF-8';
... ...
@@ -22,20 +21,15 @@ sub body {
22 21
   my $self = shift;
23 22
 
24 23
   # Downgrade multipart content
25
-  $self->content(Mojo::Content::Single->new) if $self->content->is_multipart;
26 24
   my $content = $self->content;
25
+  $content = $self->content(Mojo::Content::Single->new)->content
26
+    if $content->is_multipart;
27 27
 
28 28
   # Get
29
-  return $content->asset->slurp unless defined(my $new = shift);
30
-
31
-  # Callback
32
-  if (ref $new eq 'CODE') {
33
-    weaken $self;
34
-    return $content->unsubscribe('read')->on(read => sub { $self->$new(pop) });
35
-  }
29
+  return $content->asset->slurp unless @_;
36 30
 
37 31
   # Set raw content
38
-  else { $content->asset(Mojo::Asset::Memory->new->add_chunk($new)) }
32
+  $content->asset(Mojo::Asset::Memory->new->add_chunk(@_));
39 33
 
40 34
   return $self;
41 35
 }
... ...
@@ -48,18 +42,15 @@ sub body_params {
48 42
   $params->charset($self->content->charset || $self->default_charset);
49 43
 
50 44
   # "x-application-urlencoded" and "application/x-www-form-urlencoded"
51
-  my $type = $self->headers->content_type || '';
45
+  my $type = defined $self->headers->content_type ? $self->headers->content_type : '';
52 46
   if ($type =~ m!(?:x-application|application/x-www-form)-urlencoded!i) {
53 47
     $params->parse($self->content->asset->slurp);
54 48
   }
55 49
 
56 50
   # "multipart/formdata"
57 51
   elsif ($type =~ m!multipart/form-data!i) {
58
-    my $formdata = $self->_parse_formdata;
59
-    for my $data (@$formdata) {
60
-      my ($name, $filename, $value) = @$data;
61
-      next if defined $filename;
62
-      $params->append($name, $value);
52
+    for my $data (@{$self->_parse_formdata}) {
53
+      $params->append($data->[0], $data->[2]) unless defined $data->[1];
63 54
     }
64 55
   }
65 56
 
... ...
@@ -72,23 +63,18 @@ sub build_body       { shift->_build('get_body_chunk') }
72 63
 sub build_headers    { shift->_build('get_header_chunk') }
73 64
 sub build_start_line { shift->_build('get_start_line_chunk') }
74 65
 
75
-sub cookie {
76
-  my ($self, $name) = @_;
77
-  $self->{cookies} ||= _nest($self->cookies);
78
-  return unless my $cookies = $self->{cookies}{$name};
79
-  my @cookies = ref $cookies eq 'ARRAY' ? @$cookies : ($cookies);
80
-  return wantarray ? @cookies : $cookies[0];
81
-}
66
+sub cookie { shift->_cache(cookies => @_) }
82 67
 
83 68
 sub cookies { croak 'Method "cookies" not implemented by subclass' }
84 69
 
85 70
 sub dom {
86 71
   my $self = shift;
87 72
 
88
-  return undef if $self->is_multipart;
89
-  my $dom = $self->{dom}
90
-    ||= Mojo::DOM->new->charset(defined $self->content->charset ? $self->content->charset : undef)
91
-    ->parse($self->body);
73
+  return undef if $self->content->is_multipart;
74
+  my $html    = $self->body;
75
+  my $charset = $self->content->charset;
76
+  $html = do { my $tmp = decode($charset, $html); defined $tmp ? $tmp : $html } if $charset;
77
+  my $dom = $self->{dom} ||= Mojo::DOM->new($html);
92 78
 
93 79
   return @_ ? $dom->find(@_) : $dom;
94 80
 }
... ...
@@ -121,9 +107,10 @@ sub fix_headers {
121 107
   my $self = shift;
122 108
 
123 109
   # Content-Length or Connection (unless chunked transfer encoding is used)
124
-  return $self if $self->{fix}++ || $self->is_chunked;
110
+  my $content = $self->content;
111
+  return $self if $self->{fix}++ || $content->is_chunked;
125 112
   my $headers = $self->headers;
126
-  $self->is_dynamic
113
+  $content->is_dynamic
127 114
     ? $headers->connection('close')
128 115
     : $headers->content_length($self->body_size)
129 116
     unless $headers->content_length;
... ...
@@ -152,39 +139,28 @@ sub get_start_line_chunk {
152 139
   croak 'Method "get_start_line_chunk" not implemented by subclass';
153 140
 }
154 141
 
155
-sub has_leftovers { shift->content->has_leftovers }
156
-
157 142
 sub header_size { shift->fix_headers->content->header_size }
158 143
 
159
-sub headers    { shift->content->headers }
160
-sub is_chunked { shift->content->is_chunked }
161
-sub is_dynamic { shift->content->is_dynamic }
144
+sub headers { shift->content->headers }
162 145
 
163 146
 sub is_finished { do { my $tmp = shift->{state}; defined $tmp ? $tmp : ''} eq 'finished' }
164 147
 
165
-sub is_limit_exceeded {
166
-  return undef unless my $code = (shift->error)[1];
167
-  return !!grep { $_ eq $code } 413, 431;
168
-}
169
-
170
-sub is_multipart { shift->content->is_multipart }
148
+sub is_limit_exceeded { !!shift->{limit} }
171 149
 
172 150
 sub json {
173 151
   my ($self, $pointer) = @_;
174
-  return undef if $self->is_multipart;
152
+  return undef if $self->content->is_multipart;
175 153
   my $data = $self->{json} ||= Mojo::JSON->new->decode($self->body);
176 154
   return $pointer ? Mojo::JSON::Pointer->new->get($data, $pointer) : $data;
177 155
 }
178 156
 
179
-sub leftovers { shift->content->leftovers }
180
-
181 157
 sub param { shift->body_params->param(@_) }
182 158
 
183 159
 sub parse {
184 160
   my ($self, $chunk) = @_;
185 161
 
186 162
   # Check message size
187
-  return $self->error('Maximum message size exceeded', 413)
163
+  return $self->_limit('Maximum message size exceeded', 413)
188 164
     if ($self->{raw_size} += length($chunk = defined $chunk ? $chunk : '')) > $self->max_message_size;
189 165
 
190 166
   $self->{buffer} .= $chunk;
... ...
@@ -195,18 +171,19 @@ sub parse {
195 171
     # Check line size
196 172
     my $len = index $self->{buffer}, "\x0a";
197 173
     $len = length $self->{buffer} if $len < 0;
198
-    return $self->error('Maximum line size exceeded', 431)
174
+    return $self->_limit('Maximum line size exceeded', 431)
199 175
       if $len > $self->max_line_size;
200 176
 
201 177
     $self->{state} = 'content' if $self->extract_start_line(\$self->{buffer});
202 178
   }
203 179
 
204 180
   # Content
181
+  my $state = defined $self->{state} ? $self->{state} : '';
205 182
   $self->content($self->content->parse(delete $self->{buffer}))
206
-    if grep { $_ eq (defined $self->{state} ? $self->{state} : '') } qw(content finished);
183
+    if $state eq 'content' || $state eq 'finished';
207 184
 
208 185
   # Check line size
209
-  return $self->error('Maximum line size exceeded', 431)
186
+  return $self->_limit('Maximum line size exceeded', 431)
210 187
     if $self->headers->is_limit_exceeded;
211 188
 
212 189
   # Check buffer size
... ...
@@ -223,31 +200,23 @@ sub to_string {
223 200
   return $self->build_start_line . $self->build_headers . $self->build_body;
224 201
 }
225 202
 
226
-sub upload {
227
-  my ($self, $name) = @_;
228
-  $self->{uploads} ||= _nest($self->uploads);
229
-  return unless my $uploads = $self->{uploads}{$name};
230
-  my @uploads = ref $uploads eq 'ARRAY' ? @$uploads : ($uploads);
231
-  return wantarray ? @uploads : $uploads[0];
232
-}
203
+sub upload { shift->_cache(uploads => @_) }
233 204
 
234 205
 sub uploads {
235 206
   my $self = shift;
236 207
 
237 208
   my @uploads;
238
-  my $formdata = $self->_parse_formdata;
239
-  for my $data (@$formdata) {
240
-    my ($name, $filename, $part) = @$data;
209
+  for my $data (@{$self->_parse_formdata}) {
241 210
 
242 211
     # Just a form value
243
-    next unless defined $filename;
212
+    next unless defined $data->[1];
244 213
 
245 214
     # Uploaded file
246 215
     my $upload = Mojo::Upload->new(
247
-      name     => $name,
248
-      asset    => $part->asset,
249
-      filename => $filename,
250
-      headers  => $part->headers
216
+      name     => $data->[0],
217
+      filename => $data->[1],
218
+      asset    => $data->[2]->asset,
219
+      headers  => $data->[2]->headers
251 220
     );
252 221
     push @uploads, $upload;
253 222
   }
... ...
@@ -255,9 +224,6 @@ sub uploads {
255 224
   return \@uploads;
256 225
 }
257 226
 
258
-sub write       { shift->_write(write       => @_) }
259
-sub write_chunk { shift->_write(write_chunk => @_) }
260
-
261 227
 sub _build {
262 228
   my ($self, $method) = @_;
263 229
 
... ...
@@ -278,25 +244,23 @@ sub _build {
278 244
   return $buffer;
279 245
 }
280 246
 
281
-sub _nest {
282
-  my $array = shift;
283
-
284
-  # Turn array of objects into hash
285
-  my $hash = {};
286
-  for my $object (@$array) {
287
-    my $name = $object->name;
247
+sub _cache {
248
+  my ($self, $method, $name) = @_;
288 249
 
289
-    # Multiple objects with same name
290
-    if (exists $hash->{$name}) {
291
-      $hash->{$name} = [$hash->{$name}] unless ref $hash->{$name} eq 'ARRAY';
292
-      push @{$hash->{$name}}, $object;
293
-    }
294
-
295
-    # Single object
296
-    else { $hash->{$name} = $object }
250
+  # Cache objects by name
251
+  unless ($self->{$method}) {
252
+    $self->{$method} = {};
253
+    push @{$self->{$method}{$_->name}}, $_ for @{$self->$method};
297 254
   }
298 255
 
299
-  return $hash;
256
+  return unless my $objects = $self->{$method}{$name};
257
+  return wantarray ? @$objects : $objects->[0];
258
+}
259
+
260
+sub _limit {
261
+  my $self = shift;
262
+  $self->{limit} = 1;
263
+  $self->error(@_);
300 264
 }
301 265
 
302 266
 sub _parse_formdata {
... ...
@@ -309,8 +273,7 @@ sub _parse_formdata {
309 273
   my $charset = $content->charset || $self->default_charset;
310 274
 
311 275
   # Check all parts for form data
312
-  my @parts;
313
-  push @parts, $content;
276
+  my @parts = ($content);
314 277
   while (my $part = shift @parts) {
315 278
 
316 279
     # Nested multipart content
... ...
@@ -320,8 +283,7 @@ sub _parse_formdata {
320 283
     }
321 284
 
322 285
     # Extract information from Content-Disposition header
323
-    my $disposition = $part->headers->content_disposition;
324
-    next unless $disposition;
286
+    next unless my $disposition = $part->headers->content_disposition;
325 287
     my ($name)     = $disposition =~ /[; ]name="?([^";]+)"?/;
326 288
     my ($filename) = $disposition =~ /[; ]filename="?([^"]*)"?/;
327 289
     if ($charset) {
... ...
@@ -342,13 +304,6 @@ sub _parse_formdata {
342 304
   return \@formdata;
343 305
 }
344 306
 
345
-sub _write {
346
-  my ($self, $method, $chunk, $cb) = @_;
347
-  weaken $self;
348
-  $self->content->$method($chunk => sub { shift and $self->$cb(@_) if $cb });
349
-  return $self;
350
-}
351
-
352 307
 1;
353 308
 
354 309
 =head1 NAME
... ...
@@ -436,7 +391,7 @@ Default charset used for form data parsing, defaults to C<UTF-8>.
436 391
   $msg     = $msg->max_line_size(1024);
437 392
 
438 393
 Maximum start line size in bytes, defaults to the value of the
439
-C<MOJO_MAX_LINE_SIZE> environment variable or C<10240>.
394
+MOJO_MAX_LINE_SIZE environment variable or C<10240>.
440 395
 
441 396
 =head2 max_message_size
442 397
 
... ...
@@ -444,10 +399,10 @@ C<MOJO_MAX_LINE_SIZE> environment variable or C<10240>.
444 399
   $msg     = $msg->max_message_size(1024);
445 400
 
446 401
 Maximum message size in bytes, defaults to the value of the
447
-C<MOJO_MAX_MESSAGE_SIZE> environment variable or C<5242880>. Note that
448
-increasing this value can also drastically increase memory usage, should you
449
-for example attempt to parse an excessively large message body with the
450
-C<body_params>, C<dom> or C<json> methods.
402
+MOJO_MAX_MESSAGE_SIZE environment variable or C<5242880>. Note that increasing
403
+this value can also drastically increase memory usage, should you for example
404
+attempt to parse an excessively large message body with the C<body_params>,
405
+C<dom> or C<json> methods.
451 406
 
452 407
 =head2 version
453 408
 
... ...
@@ -465,14 +420,8 @@ implements the following new ones.
465 420
 
466 421
   my $bytes = $msg->body;
467 422
   $msg      = $msg->body('Hello!');
468
-  my $cb    = $msg->body(sub {...});
469 423
 
470
-Access C<content> data or replace all subscribers of the C<read> event.
471
-
472
-  $msg->body(sub {
473
-    my ($msg, $bytes) = @_;
474
-    say "Streaming: $bytes";
475
-  });
424
+Slurp or replace C<content>.
476 425
 
477 426
 =head2 body_params
478 427
 
... ...
@@ -556,7 +505,7 @@ Error and code.
556 505
 
557 506
 =head2 extract_start_line
558 507
 
559
-  my $success = $msg->extract_start_line(\$string);
508
+  my $success = $msg->extract_start_line(\$str);
560 509
 
561 510
 Extract start line from string. Meant to be overloaded in a subclass.
562 511
 
... ...
@@ -591,12 +540,6 @@ Get a chunk of header data, starting from a specific position.
591 540
 Get a chunk of start line data starting from a specific position. Meant to be
592 541
 overloaded in a subclass.
593 542
 
594
-=head2 has_leftovers
595
-
596
-  my $success = $msg->has_leftovers;
597
-
598
-Check if there are leftovers.
599
-
600 543
 =head2 header_size
601 544
 
602 545
   my $size = $msg->header_size;
... ...
@@ -609,19 +552,6 @@ Size of headers in bytes.
609 552
 
610 553
 Message headers, usually a L<Mojo::Headers> object.
611 554
 
612
-=head2 is_chunked
613
-
614
-  my $success = $msg->is_chunked;
615
-
616
-Check if content is chunked.
617
-
618
-=head2 is_dynamic
619
-
620
-  my $success = $msg->is_dynamic;
621
-
622
-Check if content will be dynamically generated, which prevents C<clone> from
623
-working.
624
-
625 555
 =head2 is_finished
626 556
 
627 557
   my $success = $msg->is_finished;
... ...
@@ -634,12 +564,6 @@ Check if message parser/generator is finished.
634 564
 
635 565
 Check if message has exceeded C<max_line_size> or C<max_message_size>.
636 566
 
637
-=head2 is_multipart
638
-
639
-  my $success = $msg->is_multipart;
640
-
641
-Check if content is a L<Mojo::Content::MultiPart> object.
642
-
643 567
 =head2 json
644 568
 
645 569
   my $hash  = $msg->json;
... ...
@@ -655,12 +579,6 @@ it should not be called before the entire message body has been received.
655 579
   say $msg->json->{foo}{bar}[23];
656 580
   say $msg->json('/foo/bar/23');
657 581
 
658
-=head2 leftovers
659
-
660
-  my $bytes = $msg->leftovers;
661
-
662
-Get leftover data from content parser.
663
-
664 582
 =head2 param
665 583
 
666 584
   my @names = $msg->param;
... ...
@@ -684,7 +602,7 @@ Size of the start line in bytes.
684 602
 
685 603
 =head2 to_string
686 604
 
687
-  my $string = $msg->to_string;
605
+  my $str = $msg->to_string;
688 606
 
689 607
 Render whole message.
690 608
 
... ...
@@ -706,22 +624,6 @@ entire message body has been received.
706 624
 
707 625
 All C<multipart/form-data> file uploads, usually L<Mojo::Upload> objects.
708 626
 
709
-=head2 write
710
-
711
-  $msg = $msg->write($bytes);
712
-  $msg = $msg->write($bytes => sub {...});
713
-
714
-Write dynamic content non-blocking, the optional drain callback will be
715
-invoked once all data has been written.
716
-
717
-=head2 write_chunk
718
-
719
-  $msg = $msg->write_chunk($bytes);
720
-  $msg = $msg->write_chunk($bytes => sub {...});
721
-
722
-Write dynamic content non-blocking with C<chunked> transfer encoding, the
723
-optional drain callback will be invoked once all data has been written.
724
-
725 627
 =head1 SEE ALSO
726 628
 
727 629
 L<Mojolicious>, L<Mojolicious::Guides>, L<http://mojolicio.us>.
+12 -14
mojo/lib/Mojo/Message/Request.pm
... ...
@@ -2,7 +2,6 @@ package Mojo::Message::Request;
2 2
 use Mojo::Base 'Mojo::Message';
3 3
 
4 4
 use Mojo::Cookie::Request;
5
-use Mojo::Parameters;
6 5
 use Mojo::Util qw(b64_encode b64_decode get_line);
7 6
 use Mojo::URL;
8 7
 
... ...
@@ -11,7 +10,7 @@ has method => 'GET';
11 10
 has url => sub { Mojo::URL->new };
12 11
 
13 12
 my $START_LINE_RE = qr|
14
-  ^\s*
13
+  ^
15 14
   ([a-zA-Z]+)                                  # Method
16 15
   \s+
17 16
   ([0-9a-zA-Z\-._~:/?#[\]\@!\$&'()*+,;=\%]+)   # Path
... ...
@@ -79,11 +78,8 @@ sub fix_headers {
79 78
   $headers->authorization('Basic ' . b64_encode($auth, ''))
80 79
     if $auth && !$headers->authorization;
81 80
 
82
-  # Proxy
81
+  # Basic proxy authentication
83 82
   if (my $proxy = $self->proxy) {
84
-    $url = $proxy if $self->method eq 'CONNECT';
85
-
86
-    # Basic proxy authentication
87 83
     my $proxy_auth = $proxy->userinfo;
88 84
     $headers->proxy_authorization('Basic ' . b64_encode($proxy_auth, ''))
89 85
       if $proxy_auth && !$headers->proxy_authorization;
... ...
@@ -119,7 +115,7 @@ sub get_start_line_chunk {
119 115
     # Proxy
120 116
     elsif ($self->proxy) {
121 117
       my $clone = $url = $url->clone->userinfo(undef);
122
-      my $upgrade = lc($self->headers->upgrade || '');
118
+      my $upgrade = lc(defined $self->headers->upgrade ? $self->headers->upgrade : '');
123 119
       $path = $clone
124 120
         unless $upgrade eq 'websocket' || $url->protocol eq 'https';
125 121
     }
... ...
@@ -137,7 +133,7 @@ sub is_secure {
137 133
 }
138 134
 
139 135
 sub is_xhr {
140
-  (shift->headers->header('X-Requested-With') || '') =~ /XMLHttpRequest/i;
136
+  (do {my $tmp = shift->headers->header('X-Requested-With'); defined $tmp ? $tmp : ''}) =~ /XMLHttpRequest/i;
141 137
 }
142 138
 
143 139
 sub param { shift->params->param(@_) }
... ...
@@ -145,7 +141,7 @@ sub param { shift->params->param(@_) }
145 141
 sub params {
146 142
   my $self = shift;
147 143
   return $self->{params}
148
-    ||= Mojo::Parameters->new->merge($self->body_params, $self->query_params);
144
+    ||= $self->body_params->clone->merge($self->query_params);
149 145
 }
150 146
 
151 147
 sub parse {
... ...
@@ -233,7 +229,7 @@ sub _parse_env {
233 229
   $self->method($env->{REQUEST_METHOD}) if $env->{REQUEST_METHOD};
234 230
 
235 231
   # Scheme/Version
236
-  if (($env->{SERVER_PROTOCOL} || '') =~ m!^([^/]+)/([^/]+)$!) {
232
+  if ((defined $env->{SERVER_PROTOCOL} ? $env->{SERVER_PROTOCOL} : '') =~ m!^([^/]+)/([^/]+)$!) {
237 233
     $base->scheme($1);
238 234
     $self->version($2);
239 235
   }
... ...
@@ -291,7 +287,7 @@ Mojo::Message::Request - HTTP request
291 287
 =head1 DESCRIPTION
292 288
 
293 289
 L<Mojo::Message::Request> is a container for HTTP requests as described in RFC
294
-2616.
290
+2616 and RFC 2817.
295 291
 
296 292
 =head1 EVENTS
297 293
 
... ...
@@ -329,8 +325,10 @@ HTTP request method, defaults to C<GET>.
329 325
 
330 326
 HTTP request URL, defaults to a L<Mojo::URL> object.
331 327
 
332
-  # Get request path
333
-  say $req->url->path;
328
+  # Get request information
329
+  say $req->url->to_abs->userinfo;
330
+  say $req->url->to_abs->host;
331
+  say $req->url->to_abs->path;
334 332
 
335 333
 =head1 METHODS
336 334
 
... ...
@@ -353,7 +351,7 @@ Access request cookies, usually L<Mojo::Cookie::Request> objects.
353 351
 
354 352
 =head2 extract_start_line
355 353
 
356
-  my $success = $req->extract_start_line(\$string);
354
+  my $success = $req->extract_start_line(\$str);
357 355
 
358 356
 Extract request line from string.
359 357
 
+2 -2
mojo/lib/Mojo/Message/Response.pm
... ...
@@ -129,7 +129,7 @@ sub get_start_line_chunk {
129 129
 sub is_empty {
130 130
   my $self = shift;
131 131
   return undef unless my $code = $self->code;
132
-  return $self->is_status_class(100) || grep { $_ eq $code } qw(204 304);
132
+  return $self->is_status_class(100) || $code eq 204 || $code eq 304;
133 133
 }
134 134
 
135 135
 sub is_status_class {
... ...
@@ -214,7 +214,7 @@ Generate default response message for code.
214 214
 
215 215
 =head2 extract_start_line
216 216
 
217
-  my $success = $req->extract_start_line(\$string);
217
+  my $success = $res->extract_start_line(\$str);
218 218
 
219 219
 Extract status line from string.
220 220
 
+46 -42
mojo/lib/Mojo/Parameters.pm
... ...
@@ -1,14 +1,14 @@
1 1
 package Mojo::Parameters;
2 2
 use Mojo::Base -base;
3 3
 use overload
4
+  '@{}'    => sub { shift->params },
4 5
   'bool'   => sub {1},
5 6
   '""'     => sub { shift->to_string },
6 7
   fallback => 1;
7 8
 
8 9
 use Mojo::Util qw(decode encode url_escape url_unescape);
9 10
 
10
-has charset        => 'UTF-8';
11
-has pair_separator => '&';
11
+has charset => 'UTF-8';
12 12
 
13 13
 sub new { shift->SUPER::new->parse(@_) }
14 14
 
... ...
@@ -33,8 +33,7 @@ sub append {
33 33
 sub clone {
34 34
   my $self = shift;
35 35
 
36
-  my $clone = Mojo::Parameters->new->charset($self->charset)
37
-    ->pair_separator($self->pair_separator);
36
+  my $clone = $self->new->charset($self->charset);
38 37
   if (defined $self->{string}) { $clone->{string} = $self->{string} }
39 38
   else                         { $clone->params([@{$self->params}]) }
40 39
 
... ...
@@ -78,18 +77,15 @@ sub params {
78 77
   }
79 78
 
80 79
   # Parse string
81
-  if (defined(my $string = delete $self->{string})) {
80
+  if (defined(my $str = delete $self->{string})) {
82 81
     my $params = $self->{params} = [];
83
-
84
-    # Detect pair separator for reconstruction
85
-    return $params unless length(defined $string ? $string : '');
86
-    $self->pair_separator(';') if $string =~ /;/ && $string !~ /\&/;
82
+    return $params unless length $str;
87 83
 
88 84
     # W3C suggests to also accept ";" as a separator
89 85
     my $charset = $self->charset;
90
-    for my $pair (split /[\&\;]+/, $string) {
91
-      $pair =~ /^([^=]*)(?:=(.*))?$/;
92
-      my $name  = defined $1 ? $1 : '';
86
+    for my $pair (split /&|;/, $str) {
87
+      next unless $pair =~ /^([^=]+)(?:=(.*))?$/;
88
+      my $name = $1;
93 89
       my $value = defined $2 ? $2 : '';
94 90
 
95 91
       # Replace "+" with whitespace, unescape and decode
... ...
@@ -157,9 +153,9 @@ sub to_string {
157 153
 
158 154
   # String
159 155
   my $charset = $self->charset;
160
-  if (defined(my $string = $self->{string})) {
161
-    $string = encode $charset, $string if $charset;
162
-    return url_escape $string, '^A-Za-z0-9\-._~!$&\'()*+,;=%:@/?';
156
+  if (defined(my $str = $self->{string})) {
157
+    $str = encode $charset, $str if $charset;
158
+    return url_escape $str, '^A-Za-z0-9\-._~!$&\'()*+,;=%:@/?';
163 159
   }
164 160
 
165 161
   # Build pairs
... ...
@@ -170,23 +166,22 @@ sub to_string {
170 166
     my ($name, $value) = @{$params}[$i, $i + 1];
171 167
 
172 168
     # Escape and replace whitespace with "+"
173
-    $name = encode $charset, $name if $charset;
174
-    $name = url_escape $name, '^A-Za-z0-9\-._~!$\'()*,:@/?';
175
-    $name =~ s/\%20/\+/g;
176
-    if ($value) {
177
-      $value = encode $charset, $value if $charset;
178
-      $value = url_escape $value, '^A-Za-z0-9\-._~!$\'()*,:@/?';
179
-      $value =~ s/\%20/\+/g;
180
-    }
169
+    $name  = encode $charset,   $name if $charset;
170
+    $name  = url_escape $name,  '^A-Za-z0-9\-._~!$\'()*,:@/?';
171
+    $value = encode $charset,   $value if $charset;
172
+    $value = url_escape $value, '^A-Za-z0-9\-._~!$\'()*,:@/?';
173
+    s/\%20/\+/g for $name, $value;
181 174
 
182
-    push @pairs, defined $value ? "$name=$value" : $name;
175
+    push @pairs, "$name=$value";
183 176
   }
184 177
 
185
-  return join $self->pair_separator, @pairs;
178
+  return join '&', @pairs;
186 179
 }
187 180
 
188 181
 1;
189 182
 
183
+=encoding utf8
184
+
190 185
 =head1 NAME
191 186
 
192 187
 Mojo::Parameters - Parameters
... ...
@@ -201,11 +196,12 @@ Mojo::Parameters - Parameters
201 196
 
202 197
   # Build
203 198
   my $params = Mojo::Parameters->new(foo => 'bar', baz => 23);
199
+  push @$params, i => '♥ mojolicious';
204 200
   say "$params";
205 201
 
206 202
 =head1 DESCRIPTION
207 203
 
208
-L<Mojo::Parameters> is a container for form parameters.
204
+L<Mojo::Parameters> is a container for form parameters used by L<Mojo::URL>.
209 205
 
210 206
 =head1 ATTRIBUTES
211 207
 
... ...
@@ -221,13 +217,6 @@ Charset used for encoding and decoding parameters, defaults to C<UTF-8>.
221 217
   # Disable encoding and decoding
222 218
   $params->charset(undef);
223 219
 
224
-=head2 pair_separator
225
-
226
-  my $separator = $params->pair_separator;
227
-  $params       = $params->pair_separator(';');
228
-
229
-Separator for parameter pairs, defaults to C<&>.
230
-
231 220
 =head1 METHODS
232 221
 
233 222
 L<Mojo::Parameters> inherits all methods from L<Mojo::Base> and implements the
... ...
@@ -241,7 +230,8 @@ following new ones.
241 230
   my $params = Mojo::Parameters->new(foo => ['ba;r', 'b;az']);
242 231
   my $params = Mojo::Parameters->new(foo => ['ba;r', 'b;az'], bar => 23);
243 232
 
244
-Construct a new L<Mojo::Parameters> object.
233
+Construct a new L<Mojo::Parameters> object and C<parse> parameters if
234
+necessary.
245 235
 
246 236
 =head2 append
247 237
 
... ...
@@ -249,7 +239,7 @@ Construct a new L<Mojo::Parameters> object.
249 239
   $params = $params->append(foo => ['ba;r', 'b;az']);
250 240
   $params = $params->append(foo => ['ba;r', 'b;az'], bar => 23);
251 241
 
252
-Append parameters.
242
+Append parameters. Note that this method will normalize the parameters.
253 243
 
254 244
   # "foo=bar&foo=baz"
255 245
   Mojo::Parameters->new('foo=bar')->append(foo => 'baz');
... ...
@@ -270,7 +260,8 @@ Clone parameters.
270 260
 
271 261
   $params = $params->merge(Mojo::Parameters->new(foo => 'b;ar', baz => 23));
272 262
 
273
-Merge L<Mojo::Parameters> objects.
263
+Merge L<Mojo::Parameters> objects. Note that this method will normalize the
264
+parameters.
274 265
 
275 266
 =head2 param
276 267
 
... ...
@@ -280,14 +271,18 @@ Merge L<Mojo::Parameters> objects.
280 271
   my $foo   = $params->param(foo => 'ba;r');
281 272
   my @foo   = $params->param(foo => qw(ba;r ba;z));
282 273
 
283
-Check and replace parameter values.
274
+Check and replace parameter value. Be aware that if you request a parameter by
275
+name in scalar context, you will receive only the I<first> value for that
276
+parameter, if there are multiple values for that name. In list context you
277
+will receive I<all> of the values for that name. Note that this method will
278
+normalize the parameters.
284 279
 
285 280
 =head2 params
286 281
 
287 282
   my $array = $params->params;
288 283
   $params   = $params->params([foo => 'b;ar', baz => 23]);
289 284
 
290
-Parsed parameters.
285
+Parsed parameters. Note that this method will normalize the parameters.
291 286
 
292 287
 =head2 parse
293 288
 
... ...
@@ -299,7 +294,7 @@ Parse parameters.
299 294
 
300 295
   $params = $params->remove('foo');
301 296
 
302
-Remove parameters.
297
+Remove parameters. Note that this method will normalize the parameters.
303 298
 
304 299
   # "bar=yada"
305 300
   Mojo::Parameters->new('foo=bar&foo=baz&bar=yada')->remove('foo');
... ...
@@ -308,18 +303,27 @@ Remove parameters.
308 303
 
309 304
   my $hash = $params->to_hash;
310 305
 
311
-Turn parameters into a hash reference.
306
+Turn parameters into a hash reference. Note that this method will normalize
307
+the parameters.
312 308
 
313 309
   # "baz"
314 310
   Mojo::Parameters->new('foo=bar&foo=baz')->to_hash->{foo}[1];
315 311
 
316 312
 =head2 to_string
317 313
 
318
-  my $string = $params->to_string;
319
-  my $string = "$params";
314
+  my $str = $params->to_string;
315
+  my $str = "$params";
320 316
 
321 317
 Turn parameters into a string.
322 318
 
319
+=head1 PARAMETERS
320
+
321
+Direct array reference access to the parsed parameters is also possible. Note
322
+that this will normalize the parameters.
323
+
324
+  say $params->[0];
325
+  say for @$params;
326
+
323 327
 =head1 SEE ALSO
324 328
 
325 329
 L<Mojolicious>, L<Mojolicious::Guides>, L<http://mojolicio.us>.
+115 -68
mojo/lib/Mojo/Path.pm
... ...
@@ -1,6 +1,7 @@
1 1
 package Mojo::Path;
2 2
 use Mojo::Base -base;
3 3
 use overload
4
+  '@{}'    => sub { shift->parts },
4 5
   'bool'   => sub {1},
5 6
   '""'     => sub { shift->to_string },
6 7
   fallback => 1;
... ...
@@ -8,8 +9,6 @@ use overload
8 9
 use Mojo::Util qw(decode encode url_escape url_unescape);
9 10
 
10 11
 has charset => 'UTF-8';
11
-has [qw(leading_slash trailing_slash)];
12
-has parts => sub { [] };
13 12
 
14 13
 sub new { shift->SUPER::new->parse(@_) }
15 14
 
... ...
@@ -21,15 +20,11 @@ sub canonicalize {
21 20
 
22 21
     # ".."
23 22
     if ($part eq '..') {
24
-      unless (@parts && $parts[-1] ne '..') { push @parts, '..' }
25
-      else                                  { pop @parts }
26
-      next;
23
+      (@parts && $parts[-1] ne '..') ? pop @parts : push @parts, '..';
27 24
     }
28 25
 
29
-    # "."
30
-    next if grep { $_ eq $part } '.', '';
31
-
32
-    push @parts, $part;
26
+    # Something else than "."
27
+    elsif ($part ne '.' && $part ne '') { push @parts, $part }
33 28
   }
34 29
   $self->trailing_slash(undef) unless @parts;
35 30
 
... ...
@@ -37,25 +32,25 @@ sub canonicalize {
37 32
 }
38 33
 
39 34
 sub clone {
40
-  my $self  = shift;
41
-  my $clone = Mojo::Path->new;
42
-  $clone->leading_slash($self->leading_slash);
43
-  $clone->trailing_slash($self->trailing_slash);
44
-  return $clone->charset($self->charset)->parts([@{$self->parts}]);
35
+  my $self = shift;
36
+
37
+  my $clone = $self->new->charset($self->charset);
38
+  if (my $parts = $self->{parts}) {
39
+    $clone->{$_} = $self->{$_} for qw(leading_slash trailing_slash);
40
+    $clone->{parts} = [@$parts];
41
+  }
42
+  else { $clone->{path} = $self->{path} }
43
+
44
+  return $clone;
45 45
 }
46 46
 
47 47
 sub contains {
48 48
   my ($self, $path) = @_;
49
-
50
-  my $parts = $self->new($path)->parts;
51
-  for my $part (@{$self->parts}) {
52
-    return 1 unless defined(my $try = shift @$parts);
53
-    return undef unless $part eq $try;
54
-  }
55
-
56
-  return !@$parts;
49
+  return $path eq '/' || $self->to_route =~ m!^\Q$path\E(?:/|$)!;
57 50
 }
58 51
 
52
+sub leading_slash { shift->_parse(leading_slash => @_) }
53
+
59 54
 sub merge {
60 55
   my ($self, $path) = @_;
61 56
 
... ...
@@ -70,19 +65,19 @@ sub merge {
70 65
 }
71 66
 
72 67
 sub parse {
73
-  my ($self, $path) = @_;
68
+  my $self = shift;
69
+  $self->{path} = shift;
70
+  delete $self->{$_} for qw(leading_slash parts trailing_slash);
71
+  return $self;
72
+}
74 73
 
75
-  $path = url_unescape defined $path ? $path : '';
76
-  my $charset = $self->charset;
77
-  $path = do { my $tmp = decode($charset, $path); defined $tmp ? $tmp : $path } if $charset;
78
-  $self->leading_slash($path =~ s!^/!!  ? 1 : undef);
79
-  $self->trailing_slash($path =~ s!/$!! ? 1 : undef);
74
+sub parts { shift->_parse(parts => @_) }
80 75
 
81
-  return $self->parts([split '/', $path, -1]);
76
+sub to_abs_string {
77
+  my $path = shift->to_string;
78
+  return $path =~ m!^/! ? $path : "/$path";
82 79
 }
83 80
 
84
-sub to_abs_string { $_[0]->leading_slash ? "$_[0]" : "/$_[0]" }
85
-
86 81
 sub to_dir {
87 82
   my $clone = shift->clone;
88 83
   pop @{$clone->parts} unless $clone->trailing_slash;
... ...
@@ -90,24 +85,50 @@ sub to_dir {
90 85
 }
91 86
 
92 87
 sub to_route {
93
-  my $self = shift;
94
-  return '/' . join('/', @{$self->parts}) . ($self->trailing_slash ? '/' : '');
88
+  my $clone = shift->clone;
89
+  my $route = join '/', @{$clone->parts};
90
+  return "/$route" . ($clone->trailing_slash ? '/' : '');
95 91
 }
96 92
 
97 93
 sub to_string {
98 94
   my $self = shift;
99 95
 
100
-  my @parts   = @{$self->parts};
96
+  # Path
101 97
   my $charset = $self->charset;
98
+  if (defined(my $path = $self->{path})) {
99
+    $path = encode $charset, $path if $charset;
100
+    return url_escape $path, '^A-Za-z0-9\-._~!$&\'()*+,;=%:@/';
101
+  }
102
+
103
+  # Build path
104
+  my @parts = @{$self->parts};
102 105
   @parts = map { encode $charset, $_ } @parts if $charset;
103 106
   my $path = join '/',
104 107
     map { url_escape $_, '^A-Za-z0-9\-._~!$&\'()*+,;=:@' } @parts;
105 108
   $path = "/$path" if $self->leading_slash;
106 109
   $path = "$path/" if $self->trailing_slash;
107
-
108 110
   return $path;
109 111
 }
110 112
 
113
+sub trailing_slash { shift->_parse(trailing_slash => @_) }
114
+
115
+sub _parse {
116
+  my ($self, $name) = (shift, shift);
117
+
118
+  unless ($self->{parts}) {
119
+    my $path = url_unescape do { my $tmp = delete($self->{path}); defined $tmp ? $tmp : '' };
120
+    my $charset = $self->charset;
121
+    $path = do { my $tmp = decode($charset, $path); defined $tmp ? $tmp : $path } if $charset;
122
+    $self->{leading_slash}  = $path =~ s!^/!! ? 1 : undef;
123
+    $self->{trailing_slash} = $path =~ s!/$!! ? 1 : undef;
124
+    $self->{parts} = [split '/', $path, -1];
125
+  }
126
+
127
+  return $self->{$name} unless @_;
128
+  $self->{$name} = shift;
129
+  return $self;
130
+}
131
+
111 132
 1;
112 133
 
113 134
 =encoding utf8
... ...
@@ -120,13 +141,18 @@ Mojo::Path - Path
120 141
 
121 142
   use Mojo::Path;
122 143
 
144
+  # Parse
123 145
   my $path = Mojo::Path->new('/foo%2Fbar%3B/baz.html');
124
-  shift @{$path->parts};
146
+  say $path->[0];
147
+
148
+  # Build
149
+  my $path = Mojo::Path->new('/i/♥');
150
+  push @$path, 'mojolicious';
125 151
   say "$path";
126 152
 
127 153
 =head1 DESCRIPTION
128 154
 
129
-L<Mojo::Path> is a container for URL paths.
155
+L<Mojo::Path> is a container for paths used by L<Mojo::URL>.
130 156
 
131 157
 =head1 ATTRIBUTES
132 158
 
... ...
@@ -142,30 +168,6 @@ Charset used for encoding and decoding, defaults to C<UTF-8>.
142 168
   # Disable encoding and decoding
143 169
   $path->charset(undef);
144 170
 
145
-=head2 leading_slash
146
-
147
-  my $leading_slash = $path->leading_slash;
148
-  $path             = $path->leading_slash(1);
149
-
150
-Path has a leading slash.
151
-
152
-=head2 parts
153
-
154
-  my $parts = $path->parts;
155
-  $path     = $path->parts([qw(foo bar baz)]);
156
-
157
-The path parts.
158
-
159
-  # Part with slash
160
-  push @{$path->parts}, 'foo/bar';
161
-
162
-=head2 trailing_slash
163
-
164
-  my $trailing_slash = $path->trailing_slash;
165
-  $path              = $path->trailing_slash(1);
166
-
167
-Path has a trailing slash.
168
-
169 171
 =head1 METHODS
170 172
 
171 173
 L<Mojo::Path> inherits all methods from L<Mojo::Base> and implements the
... ...
@@ -176,7 +178,7 @@ following new ones.
176 178
   my $path = Mojo::Path->new;
177 179
   my $path = Mojo::Path->new('/foo%2Fbar%3B/baz.html');
178 180
 
179
-Construct a new L<Mojo::Path> object.
181
+Construct a new L<Mojo::Path> object and C<parse> path if necessary.
180 182
 
181 183
 =head2 canonicalize
182 184
 
... ...
@@ -185,7 +187,7 @@ Construct a new L<Mojo::Path> object.
185 187
 Canonicalize path.
186 188
 
187 189
   # "/foo/baz"
188
-  Mojo::Path->new('/foo/bar/../baz')->canonicalize;
190
+  Mojo::Path->new('/foo/./bar/../baz')->canonicalize;
189 191
 
190 192
 =head2 clone
191 193
 
... ...
@@ -209,13 +211,22 @@ Check if path contains given prefix.
209 211
   Mojo::Path->new('/foo/bar')->contains('/bar');
210 212
   Mojo::Path->new('/foo/bar')->contains('/whatever');
211 213
 
214
+=head2 leading_slash
215
+
216
+  my $slash = $path->leading_slash;
217
+  $path     = $path->leading_slash(1);
218
+
219
+Path has a leading slash. Note that this method will normalize the path and
220
+that C<%2F> will be treated as C</> for security reasons.
221
+
212 222
 =head2 merge
213 223
 
214 224
   $path = $path->merge('/foo/bar');
215 225
   $path = $path->merge('foo/bar');
216 226
   $path = $path->merge(Mojo::Path->new('foo/bar'));
217 227
 
218
-Merge paths.
228
+Merge paths. Note that this method will normalize both paths if necessary and
229
+that C<%2F> will be treated as C</> for security reasons.
219 230
 
220 231
   # "/baz/yada"
221 232
   Mojo::Path->new('/foo/bar')->merge('/baz/yada');
... ...
@@ -230,17 +241,29 @@ Merge paths.
230 241
 
231 242
   $path = $path->parse('/foo%2Fbar%3B/baz.html');
232 243
 
233
-Parse path. Note that C<%2F> will be treated as C</> for security reasons.
244
+Parse path.
234 245
 
235 246
 =head2 to_abs_string
236 247
 
237
-  my $string = $path->to_abs_string;
248
+  my $str = $path->to_abs_string;
238 249
 
239 250
 Turn path into an absolute string.
240 251
 
241 252
   # "/i/%E2%99%A5/mojolicious"
253
+  Mojo::Path->new('/i/%E2%99%A5/mojolicious')->to_abs_string;
242 254
   Mojo::Path->new('i/%E2%99%A5/mojolicious')->to_abs_string;
243 255
 
256
+=head2 parts
257
+
258
+  my $parts = $path->parts;
259
+  $path     = $path->parts([qw(foo bar baz)]);
260
+
261
+The path parts. Note that this method will normalize the path and that C<%2F>
262
+will be treated as C</> for security reasons.
263
+
264
+  # Part with slash
265
+  push @{$path->parts}, 'foo/bar';
266
+
244 267
 =head2 to_dir
245 268
 
246 269
   my $dir = $route->to_dir;
... ...
@@ -248,6 +271,9 @@ Turn path into an absolute string.
248 271
 Clone path and remove everything after the right-most slash.
249 272
 
250 273
   # "/i/%E2%99%A5/"
274
+  Mojo::Path->new('/i/%E2%99%A5/mojolicious')->to_dir->to_abs_string;
275
+
276
+  # "i/%E2%99%A5/"
251 277
   Mojo::Path->new('i/%E2%99%A5/mojolicious')->to_dir->to_abs_string;
252 278
 
253 279
 =head2 to_route
... ...
@@ -257,18 +283,39 @@ Clone path and remove everything after the right-most slash.
257 283
 Turn path into a route.
258 284
 
259 285
   # "/i/♥/mojolicious"
286
+  Mojo::Path->new('/i/%E2%99%A5/mojolicious')->to_route;
260 287
   Mojo::Path->new('i/%E2%99%A5/mojolicious')->to_route;
261 288
 
262 289
 =head2 to_string
263 290
 
264
-  my $string = $path->to_string;
265
-  my $string = "$path";
291
+  my $str = $path->to_string;
292
+  my $str = "$path";
266 293
 
267 294
 Turn path into a string.
268 295
 
296
+  # "/i/%E2%99%A5/mojolicious"
297
+  Mojo::Path->new('/i/%E2%99%A5/mojolicious')->to_string;
298
+
269 299
   # "i/%E2%99%A5/mojolicious"
270 300
   Mojo::Path->new('i/%E2%99%A5/mojolicious')->to_string;
271 301
 
302
+=head2 trailing_slash
303
+
304
+  my $slash = $path->trailing_slash;
305
+  $path     = $path->trailing_slash(1);
306
+
307
+Path has a trailing slash. Note that this method will normalize the path and
308
+that C<%2F> will be treated as C</> for security reasons.
309
+
310
+=head1 PATH PARTS
311
+
312
+Direct array reference access to path parts is also possible. Note that this
313
+will normalize the path and that C<%2F> will be treated as C</> for security
314
+reasons.
315
+
316
+  say $path->[0];
317
+  say for @$path;
318
+
272 319
 =head1 SEE ALSO
273 320
 
274 321
 L<Mojolicious>, L<Mojolicious::Guides>, L<http://mojolicio.us>.
+10 -1
mojo/lib/Mojo/Reactor.pm
... ...
@@ -5,6 +5,8 @@ use Carp 'croak';
5 5
 use IO::Poll qw(POLLERR POLLHUP POLLIN);
6 6
 use Mojo::Loader;
7 7
 
8
+sub again { croak 'Method "again" not implemented by subclass' }
9
+
8 10
 sub detect {
9 11
   my $try = $ENV{MOJO_REACTOR} || 'Mojo::Reactor::EV';
10 12
   return Mojo::Loader->new->load($try) ? 'Mojo::Reactor::Poll' : $try;
... ...
@@ -46,6 +48,7 @@ Mojo::Reactor - Low level event reactor base class
46 48
 
47 49
   $ENV{MOJO_REACTOR} ||= 'Mojo::Reactor::MyEventLoop';
48 50
 
51
+  sub again      {...}
49 52
   sub io         {...}
50 53
   sub is_running {...}
51 54
   sub one_tick   {...}
... ...
@@ -84,12 +87,18 @@ Emitted safely for exceptions caught in callbacks.
84 87
 L<Mojo::Reactor> inherits all methods from L<Mojo::EventEmitter> and
85 88
 implements the following new ones.
86 89
 
90
+=head2 again
91
+
92
+  $reactor->again($id);
93
+
94
+Restart active timer. Meant to be overloaded in a subclass.
95
+
87 96
 =head2 detect
88 97
 
89 98
   my $class = Mojo::Reactor->detect;
90 99
 
91 100
 Detect and load the best reactor implementation available, will try the value
92
-of the C<MOJO_REACTOR> environment variable, L<Mojo::Reactor::EV> or
101
+of the MOJO_REACTOR environment variable, L<Mojo::Reactor::EV> or
93 102
 L<Mojo::Reactor::Poll>.
94 103
 
95 104
   # Instantiate best reactor implementation available
+9 -1
mojo/lib/Mojo/Reactor/EV.pm
... ...
@@ -13,6 +13,8 @@ sub DESTROY { undef $EV }
13 13
 # We have to fall back to Mojo::Reactor::Poll, since EV is unique
14 14
 sub new { $EV++ ? Mojo::Reactor::Poll->new : shift->SUPER::new }
15 15
 
16
+sub again { shift->{timers}{shift()}{watcher}->again }
17
+
16 18
 sub is_running { !!EV::depth }
17 19
 
18 20
 sub one_tick { EV::run(EV::RUN_ONCE) }
... ...
@@ -59,7 +61,7 @@ sub _timer {
59 61
   my $id = $self->SUPER::_timer(0, 0, $cb);
60 62
   weaken $self;
61 63
   $self->{timers}{$id}{watcher} = EV::timer(
62
-    $after => ($recurring ? $after : 0) => sub {
64
+    $after => $after => sub {
63 65
       $self->_sandbox("Timer $id", $self->{timers}{$id}{cb});
64 66
       delete $self->{timers}{$id} unless $recurring;
65 67
     }
... ...
@@ -117,6 +119,12 @@ implements the following new ones.
117 119
 
118 120
 Construct a new L<Mojo::Reactor::EV> object.
119 121
 
122
+=head2 again
123
+
124
+  $reactor->again($id);
125
+
126
+Restart active timer.
127
+
120 128
 =head2 is_running
121 129
 
122 130
   my $success = $reactor->is_running;
+26 -13
mojo/lib/Mojo/Reactor/Poll.pm
... ...
@@ -3,8 +3,13 @@ use Mojo::Base 'Mojo::Reactor';
3 3
 
4 4
 use IO::Poll qw(POLLERR POLLHUP POLLIN POLLOUT);
5 5
 use List::Util 'min';
6
-use Mojo::Util 'md5_sum';
7
-use Time::HiRes qw(time usleep);
6
+use Mojo::Util qw(md5_sum steady_time);
7
+use Time::HiRes 'usleep';
8
+
9
+sub again {
10
+  my $timer = shift->{timers}{shift()};
11
+  $timer->{time} = steady_time + $timer->{after};
12
+}
8 13
 
9 14
 sub io {
10 15
   my ($self, $handle, $cb) = @_;
... ...
@@ -31,7 +36,7 @@ sub one_tick {
31 36
 
32 37
     # Calculate ideal timeout based on timers
33 38
     my $min = min map { $_->{time} } values %{$self->{timers}};
34
-    my $timeout = defined $min ? ($min - time) : 0.5;
39
+    my $timeout = defined $min ? ($min - steady_time) : 0.5;
35 40
     $timeout = 0 if $timeout < 0;
36 41
 
37 42
     # I/O
... ...
@@ -46,12 +51,14 @@ sub one_tick {
46 51
     # Wait for timeout if poll can't be used
47 52
     elsif ($timeout) { usleep $timeout * 1000000 }
48 53
 
49
-    # Timers
50
-    while (my ($id, $t) = each %{$self->{timers} || {}}) {
51
-      next unless $t->{time} <= (my $time = time);
54
+    # Timers (time should not change in between timers)
55
+    my $now = steady_time;
56
+    for my $id (keys %{$self->{timers}}) {
57
+      next unless my $t = $self->{timers}{$id};
58
+      next unless $t->{time} <= $now;
52 59
 
53 60
       # Recurring timer
54
-      if (exists $t->{recurring}) { $t->{time} = $time + $t->{recurring} }
61
+      if (exists $t->{recurring}) { $t->{time} = $now + $t->{recurring} }
55 62
 
56 63
       # Normal timer
57 64
       else { $self->remove($id) }
... ...
@@ -105,10 +112,12 @@ sub _sandbox {
105 112
 sub _timer {
106 113
   my ($self, $recurring, $after, $cb) = @_;
107 114
 
115
+  my $timers = $self->{timers} = defined $self->{timers} ? $self->{timers} : {};
108 116
   my $id;
109
-  do { $id = md5_sum('t' . time . rand 999) } while $self->{timers}{$id};
110
-  my $t = $self->{timers}{$id} = {cb => $cb, time => time + $after};
111
-  $t->{recurring} = $after if $recurring;
117
+  do { $id = md5_sum('t' . steady_time . rand 999) } while $timers->{$id};
118
+  my $timer = $timers->{$id}
119
+    = {cb => $cb, after => $after, time => steady_time + $after};
120
+  $timer->{recurring} = $after if $recurring;
112 121
 
113 122
   return $id;
114 123
 }
... ...
@@ -145,9 +154,7 @@ Mojo::Reactor::Poll - Low level event reactor with poll support
145 154
 
146 155
 =head1 DESCRIPTION
147 156
 
148
-L<Mojo::Reactor::Poll> is a low level event reactor based on L<IO::Poll>. Note
149
-that this reactor was designed for maximum portability, and therefore does not
150
-use a monotonic clock to handle time jumps.
157
+L<Mojo::Reactor::Poll> is a low level event reactor based on L<IO::Poll>.
151 158
 
152 159
 =head1 EVENTS
153 160
 
... ...
@@ -158,6 +165,12 @@ L<Mojo::Reactor::Poll> inherits all events from L<Mojo::Reactor>.
158 165
 L<Mojo::Reactor::Poll> inherits all methods from L<Mojo::Reactor> and
159 166
 implements the following new ones.
160 167
 
168
+=head2 again
169
+
170
+  $reactor->again($id);
171
+
172
+Restart active timer.
173
+
161 174
 =head2 io
162 175
 
163 176
   $reactor = $reactor->io($handle => sub {...});
+2 -1
mojo/lib/Mojo/Server.pm
... ...
@@ -35,7 +35,7 @@ sub load_app {
35 35
     local $ENV{MOJO_EXE};
36 36
 
37 37
     # Try to load application from script into sandbox
38
-    $self->app(my $app = eval sprintf <<'EOF', md5_sum($path . $$));
38
+    my $app = eval sprintf <<'EOF', md5_sum($path . $$);
39 39
 package Mojo::Server::SandBox::%s;
40 40
 my $app = do $path;
41 41
 if (!$app && (my $e = $@ || $!)) { die $e }
... ...
@@ -44,6 +44,7 @@ EOF
44 44
     die qq{Couldn't load application from file "$path": $@} if !$app && $@;
45 45
     die qq{File "$path" did not return an application object.\n}
46 46
       unless blessed $app && $app->isa('Mojo');
47
+    $self->app($app);
47 48
   };
48 49
   FindBin->again;
49 50
 
+2 -2
mojo/lib/Mojo/Server/CGI.pm
... ...
@@ -34,7 +34,7 @@ sub run {
34 34
   return undef unless _write($res, 'get_header_chunk');
35 35
 
36 36
   # Response body
37
-  return undef unless _write($res, 'get_body_chunk');
37
+  $tx->is_empty or _write($res, 'get_body_chunk') or return undef;
38 38
 
39 39
   # Finish transaction
40 40
   $tx->server_close;
... ...
@@ -112,7 +112,7 @@ implements the following new ones.
112 112
   my $nph = $cgi->nph;
113 113
   $cgi    = $cgi->nph(1);
114 114
 
115
-Activate non parsed header mode.
115
+Activate non-parsed header mode.
116 116
 
117 117
 =head1 METHODS
118 118
 
+15 -16
mojo/lib/Mojo/Server/Daemon.pm
... ...
@@ -108,9 +108,7 @@ sub _build_tx {
108 108
   );
109 109
 
110 110
   # Kept alive if we have more than one request on the connection
111
-  $tx->kept_alive(1) if ++$c->{requests} > 1;
112
-
113
-  return $tx;
111
+  return ++$c->{requests} > 1 ? $tx->kept_alive(1) : $tx;
114 112
 }
115 113
 
116 114
 sub _close {
... ...
@@ -153,9 +151,9 @@ sub _finish {
153 151
   return $self->_remove($id) if $req->error || !$tx->keep_alive;
154 152
 
155 153
   # Build new transaction for leftovers
156
-  return unless $req->has_leftovers;
154
+  return unless length(my $leftovers = $req->content->leftovers);
157 155
   $tx = $c->{tx} = $self->_build_tx($id, $c);
158
-  $tx->server_read($req->leftovers);
156
+  $tx->server_read($leftovers);
159 157
 }
160 158
 
161 159
 sub _listen {
... ...
@@ -210,12 +208,12 @@ sub _read {
210 208
   my ($self, $id, $chunk) = @_;
211 209
 
212 210
   # Make sure we have a transaction and parse chunk
213
-  my $c = $self->{connections}{$id};
211
+  return unless my $c = $self->{connections}{$id};
214 212
   my $tx = $c->{tx} ||= $self->_build_tx($id, $c);
215 213
   warn "-- Server <<< Client (@{[$tx->req->url->to_abs]})\n$chunk\n" if DEBUG;
216 214
   $tx->server_read($chunk);
217 215
 
218
-  # Last keep alive request or corrupted connection
216
+  # Last keep-alive request or corrupted connection
219 217
   $tx->res->headers->connection('close')
220 218
     if (($c->{requests} || 0) >= $self->max_requests) || $tx->req->error;
221 219
 
... ...
@@ -234,7 +232,7 @@ sub _write {
234 232
   my ($self, $id) = @_;
235 233
 
236 234
   # Not writing
237
-  my $c = $self->{connections}{$id};
235
+  return unless my $c  = $self->{connections}{$id};
238 236
   return unless my $tx = $c->{tx};
239 237
   return unless $tx->is_writing;
240 238
 
... ...
@@ -257,7 +255,7 @@ sub _write {
257 255
       return unless $c->{tx};
258 256
     }
259 257
   }
260
-  $stream->write('', $cb);
258
+  $stream->write('' => $cb);
261 259
 }
262 260
 
263 261
 1;
... ...
@@ -292,13 +290,14 @@ Mojo::Server::Daemon - Non-blocking I/O HTTP and WebSocket server
292 290
 =head1 DESCRIPTION
293 291
 
294 292
 L<Mojo::Server::Daemon> is a full featured, highly portable non-blocking I/O
295
-HTTP and WebSocket server, with C<IPv6>, C<TLS>, C<Comet> (long polling) and
296
-multiple event loop support.
293
+HTTP and WebSocket server, with C<IPv6>, C<TLS>, C<Comet> (long polling),
294
+C<keep-alive>, connection pooling, timeout, cookie, multipart and multiple
295
+event loop support.
297 296
 
298 297
 Optional modules L<EV> (4.0+), L<IO::Socket::IP> (0.16+) and
299 298
 L<IO::Socket::SSL> (1.75+) are supported transparently through
300 299
 L<Mojo::IOLoop>, and used if installed. Individual features can also be
301
-disabled with the C<MOJO_NO_IPV6> and C<MOJO_NO_TLS> environment variables.
300
+disabled with the MOJO_NO_IPV6 and MOJO_NO_TLS environment variables.
302 301
 
303 302
 See L<Mojolicious::Guides::Cookbook> for more.
304 303
 
... ...
@@ -331,7 +330,7 @@ Group for server process.
331 330
   $daemon     = $daemon->inactivity_timeout(5);
332 331
 
333 332
 Maximum amount of time in seconds a connection can be inactive before getting
334
-closed, defaults to the value of the C<MOJO_INACTIVITY_TIMEOUT> environment
333
+closed, defaults to the value of the MOJO_INACTIVITY_TIMEOUT environment
335 334
 variable or C<15>. Setting the value to C<0> will allow connections to be
336 335
 inactive indefinitely.
337 336
 
... ...
@@ -349,7 +348,7 @@ L<Mojo::IOLoop> singleton.
349 348
   $daemon    = $daemon->listen(['https://localhost:3000']);
350 349
 
351 350
 List of one or more locations to listen on, defaults to the value of the
352
-C<MOJO_LISTEN> environment variable or C<http://*:3000>.
351
+MOJO_LISTEN environment variable or C<http://*:3000>.
353 352
 
354 353
   # Listen on IPv6 interface
355 354
   $daemon->listen(['http://[::1]:4000']);
... ...
@@ -398,7 +397,7 @@ Maximum number of parallel client connections, defaults to C<1000>.
398 397
   my $max = $daemon->max_requests;
399 398
   $daemon = $daemon->max_requests(100);
400 399
 
401
-Maximum number of keep alive requests per connection, defaults to C<25>.
400
+Maximum number of keep-alive requests per connection, defaults to C<25>.
402 401
 
403 402
 =head2 silent
404 403
 
... ...
@@ -445,7 +444,7 @@ Stop accepting connections.
445 444
 
446 445
 =head1 DEBUGGING
447 446
 
448
-You can set the C<MOJO_DAEMON_DEBUG> environment variable to get some advanced
447
+You can set the MOJO_DAEMON_DEBUG environment variable to get some advanced
449 448
 diagnostics information printed to C<STDERR>.
450 449
 
451 450
   MOJO_DAEMON_DEBUG=1
+16 -13
mojo/lib/Mojo/Server/Hypnotoad.pm
... ...
@@ -7,6 +7,7 @@ use Cwd 'abs_path';
7 7
 use File::Basename 'dirname';
8 8
 use File::Spec::Functions 'catfile';
9 9
 use Mojo::Server::Prefork;
10
+use Mojo::Util 'steady_time';
10 11
 use POSIX 'setsid';
11 12
 use Scalar::Util 'weaken';
12 13
 
... ...
@@ -62,7 +63,7 @@ sub run {
62 63
   }
63 64
 
64 65
   # Start accepting connections
65
-  local $SIG{USR2} = sub { $self->{upgrade} ||= time };
66
+  local $SIG{USR2} = sub { $self->{upgrade} ||= steady_time };
66 67
   $prefork->run;
67 68
 }
68 69
 
... ...
@@ -123,7 +124,7 @@ sub _manage {
123 124
 
124 125
     # Timeout
125 126
     kill 'KILL', $self->{new}
126
-      if $self->{upgrade} + $self->{upgrade_timeout} <= time;
127
+      if $self->{upgrade} + $self->{upgrade_timeout} <= steady_time;
127 128
   }
128 129
 }
129 130
 
... ...
@@ -161,9 +162,10 @@ Mojo::Server::Hypnotoad - ALL GLORY TO THE HYPNOTOAD!
161 162
 L<Mojo::Server::Hypnotoad> is a full featured, UNIX optimized, preforking
162 163
 non-blocking I/O HTTP and WebSocket server, built around the very well tested
163 164
 and reliable L<Mojo::Server::Prefork>, with C<IPv6>, C<TLS>, C<Comet> (long
164
-polling), multiple event loop and hot deployment support that just works. Note
165
-that the server uses signals for process management, so you should avoid
166
-modifying signal handlers in your applications.
165
+polling), C<keep-alive>, connection pooling, timeout, cookie, multipart,
166
+multiple event loop and hot deployment support that just works. Note that the
167
+server uses signals for process management, so you should avoid modifying
168
+signal handlers in your applications.
167 169
 
168 170
 To start applications with it you can use the L<hypnotoad> script.
169 171
 
... ...
@@ -181,7 +183,7 @@ C<production> mode.
181 183
 Optional modules L<EV> (4.0+), L<IO::Socket::IP> (0.16+) and
182 184
 L<IO::Socket::SSL> (1.75+) are supported transparently through
183 185
 L<Mojo::IOLoop>, and used if installed. Individual features can also be
184
-disabled with the C<MOJO_NO_IPV6> and C<MOJO_NO_TLS> environment variables.
186
+disabled with the MOJO_NO_IPV6 and MOJO_NO_TLS environment variables.
185 187
 
186 188
 See L<Mojolicious::Guides::Cookbook> for more.
187 189
 
... ...
@@ -254,9 +256,9 @@ L<Mojolicious::Guides::Cookbook/"Hypnotoad"> for examples.
254 256
 
255 257
   accept_interval => 0.5
256 258
 
257
-Interval in seconds for trying to reacquire the accept mutex and connection
258
-management, defaults to C<0.025>. Note that changing this value can affect
259
-performance and idle CPU usage.
259
+Interval in seconds for trying to reacquire the accept mutex, defaults to
260
+C<0.025>. Note that changing this value can affect performance and idle CPU
261
+usage.
260 262
 
261 263
 =head2 accepts
262 264
 
... ...
@@ -321,7 +323,7 @@ be inactive indefinitely.
321 323
 
322 324
   keep_alive_requests => 50
323 325
 
324
-Number of keep alive requests per connection, defaults to C<25>.
326
+Number of keep-alive requests per connection, defaults to C<25>.
325 327
 
326 328
 =head2 listen
327 329
 
... ...
@@ -339,10 +341,11 @@ appended, defaults to a random temporary path.
339 341
 
340 342
 =head2 lock_timeout
341 343
 
342
-  lock_timeout => 1
344
+  lock_timeout => 0.5
343 345
 
344 346
 Maximum amount of time in seconds a worker may block when waiting for the
345
-accept mutex, defaults to C<0.5>.
347
+accept mutex, defaults to C<1>. Note that changing this value can affect
348
+performance and idle CPU usage.
346 349
 
347 350
 =head2 multi_accept
348 351
 
... ...
@@ -364,7 +367,7 @@ the server has been stopped.
364 367
 
365 368
 Activate reverse proxy support, which allows for the C<X-Forwarded-For> and
366 369
 C<X-Forwarded-HTTPS> headers to be picked up automatically, defaults to the
367
-value of the C<MOJO_REVERSE_PROXY> environment variable.
370
+value of the MOJO_REVERSE_PROXY environment variable.
368 371
 
369 372
 =head2 upgrade_timeout
370 373
 
+6 -5
mojo/lib/Mojo/Server/Morbo.pm
... ...
@@ -25,7 +25,7 @@ sub check_file {
25 25
 sub run {
26 26
   my ($self, $app) = @_;
27 27
 
28
-  # Prepare environment
28
+  # Clean manager environment
29 29
   local $SIG{CHLD} = sub { $self->_reap };
30 30
   local $SIG{INT} = local $SIG{TERM} = local $SIG{QUIT} = sub {
31 31
     $self->{finished} = 1;
... ...
@@ -37,7 +37,6 @@ sub run {
37 37
   # Prepare and cache listen sockets for smooth restarting
38 38
   my $daemon = Mojo::Server::Daemon->new(silent => 1)->start->stop;
39 39
 
40
-  # Watch files and manage worker
41 40
   $self->_manage while !$self->{finished} || $self->{running};
42 41
   exit 0;
43 42
 }
... ...
@@ -116,8 +115,10 @@ Mojo::Server::Morbo - DOOOOOOOOOOOOOOOOOOM!
116 115
 
117 116
 L<Mojo::Server::Morbo> is a full featured, self-restart capable non-blocking
118 117
 I/O HTTP and WebSocket server, built around the very well tested and reliable
119
-L<Mojo::Server::Daemon>, with C<IPv6>, C<TLS>, C<Comet> (long polling) and
120
-multiple event loop support.
118
+L<Mojo::Server::Daemon>, with C<IPv6>, C<TLS>, C<Comet> (long polling),
119
+C<keep-alive>, connection pooling, timeout, cookie, multipart and multiple
120
+event loop support. Note that the server uses signals for process management,
121
+so you should avoid modifying signal handlers in your applications.
121 122
 
122 123
 To start applications with it you can use the L<morbo> script.
123 124
 
... ...
@@ -127,7 +128,7 @@ To start applications with it you can use the L<morbo> script.
127 128
 Optional modules L<EV> (4.0+), L<IO::Socket::IP> (0.16+) and
128 129
 L<IO::Socket::SSL> (1.75+) are supported transparently through
129 130
 L<Mojo::IOLoop>, and used if installed. Individual features can also be
130
-disabled with the C<MOJO_NO_IPV6> and C<MOJO_NO_TLS> environment variables.
131
+disabled with the MOJO_NO_IPV6 and MOJO_NO_TLS environment variables.
131 132
 
132 133
 See L<Mojolicious::Guides::Cookbook> for more.
133 134
 
+5 -2
mojo/lib/Mojo/Server/PSGI.pm
... ...
@@ -29,8 +29,8 @@ sub run {
29 29
   }
30 30
 
31 31
   # PSGI response
32
-  return [$res->code || 404,
33
-    \@headers, Mojo::Server::PSGI::_IO->new(tx => $tx)];
32
+  my $io = Mojo::Server::PSGI::_IO->new(tx => $tx, empty => $tx->is_empty);
33
+  return [$res->code || 404, \@headers, $io];
34 34
 }
35 35
 
36 36
 sub to_psgi_app {
... ...
@@ -50,6 +50,9 @@ sub close { shift->{tx}->server_close }
50 50
 sub getline {
51 51
   my $self = shift;
52 52
 
53
+  # Empty
54
+  return undef if $self->{empty};
55
+
53 56
   # No content yet, try again later
54 57
   my $chunk = $self->{tx}->res->get_body_chunk($self->{offset} = defined $self->{offset} ? $self->{offset} : 0);
55 58
   return '' unless defined $chunk;
+24 -19
mojo/lib/Mojo/Server/Prefork.pm
... ...
@@ -5,6 +5,7 @@ use Fcntl ':flock';
5 5
 use File::Spec::Functions qw(catfile tmpdir);
6 6
 use IO::Poll 'POLLIN';
7 7
 use List::Util 'shuffle';
8
+use Mojo::Util 'steady_time';
8 9
 use POSIX 'WNOHANG';
9 10
 use Scalar::Util 'weaken';
10 11
 use Time::HiRes ();
... ...
@@ -14,7 +15,7 @@ has accept_interval => 0.025;
14 15
 has [qw(graceful_timeout heartbeat_timeout)] => 20;
15 16
 has heartbeat_interval => 5;
16 17
 has lock_file          => sub { catfile tmpdir, 'prefork.lock' };
17
-has lock_timeout       => 0.5;
18
+has lock_timeout       => 1;
18 19
 has multi_accept       => 50;
19 20
 has pid_file           => sub { catfile tmpdir, 'prefork.pid' };
20 21
 has workers            => 4;
... ...
@@ -70,10 +71,10 @@ sub run {
70 71
   local $SIG{TTOU} = sub {
71 72
     $self->workers($self->workers - 1) if $self->workers > 0;
72 73
     return unless $self->workers;
73
-    $self->{pool}{shuffle keys %{$self->{pool}}}{graceful} ||= time;
74
+    $self->{pool}{shuffle keys %{$self->{pool}}}{graceful} ||= steady_time;
74 75
   };
75 76
 
76
-  # Preload application and start accepting connections
77
+  # Preload application before starting workers
77 78
   $self->start->app->log->info("Manager $$ started.");
78 79
   $self->{running} = 1;
79 80
   $self->_manage while $self->{running};
... ...
@@ -89,7 +90,8 @@ sub _heartbeat {
89 90
   return unless $self->{reader}->sysread(my $chunk, 4194304);
90 91
 
91 92
   # Update heartbeats
92
-  $self->{pool}{$1} and $self->emit(heartbeat => $1)->{pool}{$1}{time} = time
93
+  my $time = steady_time;
94
+  $self->{pool}{$1} and $self->emit(heartbeat => $1)->{pool}{$1}{time} = $time
93 95
     while $chunk =~ /(\d+)\n/g;
94 96
 }
95 97
 
... ...
@@ -113,17 +115,18 @@ sub _manage {
113 115
     # No heartbeat (graceful stop)
114 116
     my $interval = $self->heartbeat_interval;
115 117
     my $timeout  = $self->heartbeat_timeout;
116
-    if (!$w->{graceful} && ($w->{time} + $interval + $timeout <= time)) {
118
+    my $time     = steady_time;
119
+    if (!$w->{graceful} && ($w->{time} + $interval + $timeout <= $time)) {
117 120
       $log->info("Worker $pid has no heartbeat, restarting.");
118
-      $w->{graceful} = time;
121
+      $w->{graceful} = $time;
119 122
     }
120 123
 
121 124
     # Graceful stop with timeout
122
-    $w->{graceful} ||= time if $self->{graceful};
125
+    $w->{graceful} ||= $time if $self->{graceful};
123 126
     if ($w->{graceful}) {
124 127
       $log->debug("Trying to stop worker $pid gracefully.");
125 128
       kill 'QUIT', $pid;
126
-      $w->{force} = 1 if $w->{graceful} + $self->graceful_timeout <= time;
129
+      $w->{force} = 1 if $w->{graceful} + $self->graceful_timeout <= $time;
127 130
     }
128 131
 
129 132
     # Normal stop
... ...
@@ -151,7 +154,7 @@ sub _pid_file {
151 154
 sub _reap {
152 155
   my ($self, $pid) = @_;
153 156
 
154
-  # CLean up dead worker
157
+  # Clean up dead worker
155 158
   $self->app->log->debug("Worker $pid stopped.")
156 159
     if delete $self->emit(reap => $pid)->{pool}{$pid};
157 160
 }
... ...
@@ -161,7 +164,8 @@ sub _spawn {
161 164
 
162 165
   # Manager
163 166
   die "Can't fork: $!" unless defined(my $pid = fork);
164
-  return $self->emit(spawn => $pid)->{pool}{$pid} = {time => time} if $pid;
167
+  return $self->emit(spawn => $pid)->{pool}{$pid} = {time => steady_time}
168
+    if $pid;
165 169
 
166 170
   # Prepare lock file
167 171
   my $file = $self->{lock_file};
... ...
@@ -208,7 +212,6 @@ sub _spawn {
208 212
   $SIG{QUIT} = sub { $loop->max_connections(0) };
209 213
   delete $self->{$_} for qw(poll reader);
210 214
 
211
-  # Start event loop
212 215
   $self->app->log->debug("Worker $$ started.");
213 216
   $loop->start;
214 217
   exit 0;
... ...
@@ -254,14 +257,15 @@ Mojo::Server::Prefork - Preforking non-blocking I/O HTTP and WebSocket server
254 257
 L<Mojo::Server::Prefork> is a full featured, UNIX optimized, preforking
255 258
 non-blocking I/O HTTP and WebSocket server, built around the very well tested
256 259
 and reliable L<Mojo::Server::Daemon>, with C<IPv6>, C<TLS>, C<Comet> (long
257
-polling) and multiple event loop support. Note that the server uses signals
258
-for process management, so you should avoid modifying signal handlers in your
260
+polling), C<keep-alive>, connection pooling, timeout, cookie, multipart and
261
+multiple event loop support. Note that the server uses signals for process
262
+management, so you should avoid modifying signal handlers in your
259 263
 applications.
260 264
 
261 265
 Optional modules L<EV> (4.0+), L<IO::Socket::IP> (0.16+) and
262 266
 L<IO::Socket::SSL> (1.75+) are supported transparently through
263 267
 L<Mojo::IOLoop>, and used if installed. Individual features can also be
264
-disabled with the C<MOJO_NO_IPV6> and C<MOJO_NO_TLS> environment variables.
268
+disabled with the MOJO_NO_IPV6 and MOJO_NO_TLS environment variables.
265 269
 
266 270
 See L<Mojolicious::Guides::Cookbook> for more.
267 271
 
... ...
@@ -392,9 +396,9 @@ and implements the following new ones.
392 396
   my $interval = $prefork->accept_interval;
393 397
   $prefork     = $prefork->accept_interval(0.5);
394 398
 
395
-Interval in seconds for trying to reacquire the accept mutex and connection
396
-management, defaults to C<0.025>. Note that changing this value can affect
397
-performance and idle CPU usage.
399
+Interval in seconds for trying to reacquire the accept mutex, defaults to
400
+C<0.025>. Note that changing this value can affect performance and idle CPU
401
+usage.
398 402
 
399 403
 =head2 accepts
400 404
 
... ...
@@ -441,10 +445,11 @@ appended, defaults to a random temporary path.
441 445
 =head2 lock_timeout
442 446
 
443 447
   my $timeout = $prefork->lock_timeout;
444
-  $prefork    = $prefork->lock_timeout(1);
448
+  $prefork    = $prefork->lock_timeout(0.5);
445 449
 
446 450
 Maximum amount of time in seconds a worker may block when waiting for the
447
-accept mutex, defaults to C<0.5>.
451
+accept mutex, defaults to C<1>. Note that changing this value can affect
452
+performance and idle CPU usage.
448 453
 
449 454
 =head2 multi_accept
450 455
 
+35 -44
mojo/lib/Mojo/Template.pm
... ...
@@ -27,6 +27,7 @@ sub build {
27 27
   my $self = shift;
28 28
 
29 29
   my (@lines, $cpst, $multi);
30
+  my $escape = $self->auto_escape;
30 31
   for my $line (@{$self->tree}) {
31 32
     push @lines, '';
32 33
     for (my $j = 0; $j < @{$line}; $j += 2) {
... ...
@@ -58,13 +59,12 @@ sub build {
58 59
       if ($type eq 'code' || $multi) { $lines[-1] .= "$value" }
59 60
 
60 61
       # Expression
61
-      if (grep { $_ eq $type } qw(expr escp)) {
62
+      if ($type eq 'expr' || $type eq 'escp') {
62 63
 
63 64
         # Start
64 65
         unless ($multi) {
65 66
 
66 67
           # Escaped
67
-          my $escape = $self->auto_escape;
68 68
           if (($type eq 'escp' && !$escape) || ($type eq 'expr' && $escape)) {
69 69
             $lines[-1] .= "\$_M .= _escape";
70 70
             $lines[-1] .= " scalar $value" if length $value;
... ...
@@ -99,7 +99,9 @@ sub compile {
99 99
 
100 100
   # Compile with line directive
101 101
   return undef unless my $code = $self->code;
102
-  my $compiled = eval qq{#line 1 "@{[$self->name]}"\n$code};
102
+  my $name = $self->name;
103
+  $name =~ s/"//g;
104
+  my $compiled = eval qq{#line 1 "$name"\n$code};
103 105
   $self->compiled($compiled) and return undef unless $@;
104 106
 
105 107
   # Use local stacktrace for compile exceptions
... ...
@@ -124,10 +126,10 @@ sub interpret {
124 126
 }
125 127
 
126 128
 sub parse {
127
-  my ($self, $tmpl) = @_;
129
+  my ($self, $template) = @_;
128 130
 
129 131
   # Clean start
130
-  delete $self->template($tmpl)->{tree};
132
+  my $tree = $self->template($template)->tree([])->tree;
131 133
 
132 134
   my $tag     = $self->tag_start;
133 135
   my $replace = $self->replace_mark;
... ...
@@ -140,7 +142,6 @@ sub parse {
140 142
   my $end     = $self->tag_end;
141 143
   my $start   = $self->line_start;
142 144
 
143
-  # Precompile
144 145
   my $token_re = qr/
145 146
     (
146 147
       \Q$tag$replace\E                       # Replace
... ...
@@ -174,28 +175,23 @@ sub parse {
174 175
   # Split lines
175 176
   my $state = 'text';
176 177
   my ($trimming, @capture_token);
177
-  for my $line (split /\n/, $tmpl) {
178
+  for my $line (split /\n/, $template) {
178 179
     $trimming = 0 if $state eq 'text';
179 180
 
180
-    # Perl line
181
+    # Turn Perl line into mixed line
181 182
     if ($state eq 'text' && $line !~ s/^(\s*)\Q$start$replace\E/$1$start/) {
182
-      $line =~ s/^(\s*)\Q$start\E(\Q$expr\E)?//
183
-        and $line = $2 ? "$1$tag$2$line $end" : "$tag$line $trim$end";
184
-    }
185
-
186
-    # Escaped line ending
187
-    if ($line =~ /(\\+)$/) {
188
-      my $len = length $1;
183
+      if ($line =~ s/^(\s*)\Q$start\E(?:(\Q$cmnt\E)|(\Q$expr\E))?//) {
189 184
 
190
-      # Newline
191
-      if ($len == 1) { $line =~ s/\\$// }
185
+        # Comment
186
+        if ($2) { $line = "$tag$2 $trim$end" }
192 187
 
193
-      # Backslash
194
-      elsif ($len > 1) { $line =~ s/\\\\$/\\\n/ }
188
+        # Expression or code
189
+        else { $line = $3 ? "$1$tag$3$line $end" : "$tag$line $trim$end" }
190
+      }
195 191
     }
196 192
 
197
-    # Normal line ending
198
-    else { $line .= "\n" }
193
+    # Escaped line ending
194
+    $line .= "\n" unless $line =~ s/\\\\$/\\\n/ || $line =~ s/\\$//;
199 195
 
200 196
     # Mixed line
201 197
     my @token;
... ...
@@ -233,7 +229,7 @@ sub parse {
233 229
       # Comment
234 230
       elsif ($token =~ /^\Q$tag$cmnt\E$/) { $state = 'cmnt' }
235 231
 
236
-      # Value
232
+      # Text
237 233
       else {
238 234
 
239 235
         # Replace
... ...
@@ -251,27 +247,27 @@ sub parse {
251 247
         @capture_token = ();
252 248
       }
253 249
     }
254
-    push @{$self->tree}, \@token;
250
+    push @$tree, \@token;
255 251
   }
256 252
 
257 253
   return $self;
258 254
 }
259 255
 
260 256
 sub render {
261
-  my $self = shift->parse(shift)->build;
262
-  return $self->compile || $self->interpret(@_);
257
+  my $self = shift;
258
+  return $self->parse(shift)->build->compile || $self->interpret(@_);
263 259
 }
264 260
 
265 261
 sub render_file {
266 262
   my ($self, $path) = (shift, shift);
267 263
 
268 264
   $self->name($path) unless defined $self->{name};
269
-  my $tmpl     = slurp $path;
265
+  my $template = slurp $path;
270 266
   my $encoding = $self->encoding;
271 267
   croak qq{Template "$path" has invalid encoding.}
272
-    if $encoding && !defined($tmpl = decode $encoding, $tmpl);
268
+    if $encoding && !defined($template = decode $encoding, $template);
273 269
 
274
-  return $self->render($tmpl, @_);
270
+  return $self->render($template, @_);
275 271
 }
276 272
 
277 273
 sub _trim {
... ...
@@ -280,8 +276,8 @@ sub _trim {
280 276
   # Walk line backwards
281 277
   for (my $j = @$line - 4; $j >= 0; $j -= 2) {
282 278
 
283
-    # Skip capture
284
-    next if grep { $_ eq $line->[$j] } qw(cpst cpen);
279
+    # Skip captures
280
+    next if $line->[$j] eq 'cpst' || $line->[$j] eq 'cpen';
285 281
 
286 282
     # Only trim text
287 283
     return unless $line->[$j] eq 'text';
... ...
@@ -344,14 +340,14 @@ Mojo::Template - Perl-ish templates!
344 340
 
345 341
   # More advanced
346 342
   my $output = $mt->render(<<'EOF', 23, 'foo bar');
347
-  % my ($number, $text) = @_;
343
+  % my ($num, $text) = @_;
348 344
   %= 5 * 5
349 345
   <!DOCTYPE html>
350 346
   <html>
351 347
     <head><title>More advanced</title></head>
352 348
     <body>
353 349
       test 123
354
-      foo <% my $i = $number + 2; %>
350
+      foo <% my $i = $num + 2; %>
355 351
       % for (1 .. 23) {
356 352
       * some text <%= $i++ %>
357 353
       % }
... ...
@@ -383,7 +379,7 @@ automatically enabled.
383 379
   % Perl code line, treated as "<% line =%>"
384 380
   %= Perl expression line, treated as "<%= line %>"
385 381
   %== Perl expression line, treated as "<%== line %>"
386
-  %# Comment line, treated as "<%# line =%>"
382
+  %# Comment line, useful for debugging
387 383
   %% Replaced with "%", useful for generating templates
388 384
 
389 385
 Escaping behavior can be reversed with the C<auto_escape> attribute, this is
... ...
@@ -616,14 +612,15 @@ Characters indicating the end of a tag, defaults to C<%E<gt>>.
616 612
   my $template = $mt->template;
617 613
   $mt          = $mt->template($template);
618 614
 
619
-Raw template.
615
+Raw unparsed template.
620 616
 
621 617
 =head2 tree
622 618
 
623 619
   my $tree = $mt->tree;
624
-  $mt      = $mt->tree($tree);
620
+  $mt      = $mt->tree([['text', 'foo']]);
625 621
 
626
-Parsed tree.
622
+Template in parsed form. Note that this structure should only be used very
623
+carefully since it is very dynamic.
627 624
 
628 625
 =head2 trim_mark
629 626
 
... ...
@@ -639,12 +636,6 @@ Character activating automatic whitespace trimming, defaults to C<=>.
639 636
 L<Mojo::Template> inherits all methods from L<Mojo::Base> and implements the
640 637
 following new ones.
641 638
 
642
-=head2 new
643
-
644
-  my $mt = Mojo::Template->new;
645
-
646
-Construct a new L<Mojo::Template> object.
647
-
648 639
 =head2 build
649 640
 
650 641
   $mt = $mt->build;
... ...
@@ -693,8 +684,8 @@ Render template file.
693 684
 
694 685
 =head1 DEBUGGING
695 686
 
696
-You can set the C<MOJO_TEMPLATE_DEBUG> environment variable to get some
697
-advanced diagnostics information printed to C<STDERR>.
687
+You can set the MOJO_TEMPLATE_DEBUG environment variable to get some advanced
688
+diagnostics information printed to C<STDERR>.
698 689
 
699 690
   MOJO_TEMPLATE_DEBUG=1
700 691
 
+11 -19
mojo/lib/Mojo/Transaction.pm
... ...
@@ -12,7 +12,7 @@ has res => sub { Mojo::Message::Response->new };
12 12
 sub client_close {
13 13
   my $self = shift;
14 14
   $self->res->finish;
15
-  return $self->server_close(@_);
15
+  return $self->server_close;
16 16
 }
17 17
 
18 18
 sub client_read  { croak 'Method "client_read" not implemented by subclass' }
... ...
@@ -36,11 +36,7 @@ sub is_finished { do {my $tmp = shift->{state}; defined $tmp ? $tmp : ''} eq 'fi
36 36
 
37 37
 sub is_websocket {undef}
38 38
 
39
-sub is_writing {
40
-  return 1 unless my $state = shift->{state};
41
-  return !!grep { $_ eq $state }
42
-    qw(write write_start_line write_headers write_body);
43
-}
39
+sub is_writing { (do {my $tmp = shift->{state}; defined $tmp ? $tmp : 'write'}) eq 'write' }
44 40
 
45 41
 sub remote_address {
46 42
   my $self = shift;
... ...
@@ -54,31 +50,27 @@ sub remote_address {
54 50
   # Reverse proxy
55 51
   if ($ENV{MOJO_REVERSE_PROXY}) {
56 52
     return $self->{forwarded_for} if $self->{forwarded_for};
57
-    my $forwarded = $self->req->headers->header('X-Forwarded-For') || '';
53
+    my $forwarded = defined $self->req->headers->header('X-Forwarded-For') ? $self->req->headers->header('X-Forwarded-For') : '';
58 54
     $forwarded =~ /([^,\s]+)$/ and return $self->{forwarded_for} = $1;
59 55
   }
60 56
 
61 57
   return $self->{remote_address};
62 58
 }
63 59
 
64
-sub resume {
65
-  my $self = shift;
66
-  if ((defined $self->{state} ? $self->{state} : '') eq 'paused') { $self->{state} = 'write_body' }
67
-  elsif (!$self->is_writing) { $self->{state} = 'write' }
68
-  return $self->emit('resume');
69
-}
70
-
71
-sub server_close {
72
-  my $self = shift;
73
-  $self->{state} = 'finished';
74
-  return $self->emit('finish');
75
-}
60
+sub resume       { shift->_state(qw(write resume)) }
61
+sub server_close { shift->_state(qw(finished finish)) }
76 62
 
77 63
 sub server_read  { croak 'Method "server_read" not implemented by subclass' }
78 64
 sub server_write { croak 'Method "server_write" not implemented by subclass' }
79 65
 
80 66
 sub success { $_[0]->error ? undef : $_[0]->res }
81 67
 
68
+sub _state {
69
+  my ($self, $state, $event) = @_;
70
+  $self->{state} = $state;
71
+  return $self->emit($event);
72
+}
73
+
82 74
 1;
83 75
 
84 76
 =head1 NAME
+43 -32
mojo/lib/Mojo/Transaction/HTTP.pm
... ...
@@ -8,32 +8,35 @@ sub client_read {
8 8
 
9 9
   # Skip body for HEAD request
10 10
   my $res = $self->res;
11
-  $res->content->skip_body(1) if $self->req->method eq 'HEAD';
11
+  $res->content->skip_body(1) if uc $self->req->method eq 'HEAD';
12 12
   return unless $res->parse($chunk)->is_finished;
13 13
 
14
-  # Unexpected 1xx reponse
14
+  # Unexpected 1xx response
15 15
   return $self->{state} = 'finished'
16 16
     if !$res->is_status_class(100) || $res->headers->upgrade;
17 17
   $self->res($res->new)->emit(unexpected => $res);
18
-  $self->client_read($res->leftovers) if $res->has_leftovers;
18
+  return unless length(my $leftovers = $res->content->leftovers);
19
+  $self->client_read($leftovers);
19 20
 }
20 21
 
21 22
 sub client_write { shift->_write(0) }
22 23
 
24
+sub is_empty { !!(uc $_[0]->req->method eq 'HEAD' || $_[0]->res->is_empty) }
25
+
23 26
 sub keep_alive {
24 27
   my $self = shift;
25 28
 
26 29
   # Close
27 30
   my $req      = $self->req;
28 31
   my $res      = $self->res;
29
-  my $req_conn = lc($req->headers->connection || '');
30
-  my $res_conn = lc($res->headers->connection || '');
32
+  my $req_conn = lc(defined $req->headers->connection ? $req->headers->connection : '');
33
+  my $res_conn = lc(defined $res->headers->connection ? $res->headers->connection : '');
31 34
   return undef if $req_conn eq 'close' || $res_conn eq 'close';
32 35
 
33
-  # Keep alive
36
+  # Keep-alive
34 37
   return 1 if $req_conn eq 'keep-alive' || $res_conn eq 'keep-alive';
35 38
 
36
-  # No keep alive for 1.0
39
+  # No keep-alive for 1.0
37 40
   return !($req->version eq '1.0' || $res->version eq '1.0');
38 41
 }
39 42
 
... ...
@@ -48,7 +51,7 @@ sub server_read {
48 51
   # Generate response
49 52
   return unless $req->is_finished && !$self->{handled}++;
50 53
   $self->emit(upgrade => Mojo::Transaction::WebSocket->new(handshake => $self))
51
-    if lc($req->headers->upgrade || '') eq 'websocket';
54
+    if lc(defined $req->headers->upgrade ? $req->headers->upgrade : '') eq 'websocket';
52 55
   $self->emit('request');
53 56
 }
54 57
 
... ...
@@ -57,10 +60,10 @@ sub server_write { shift->_write(1) }
57 60
 sub _body {
58 61
   my ($self, $msg, $finish) = @_;
59 62
 
60
-  # Prepare chunk
63
+  # Prepare body chunk
61 64
   my $buffer = $msg->get_body_chunk($self->{offset});
62 65
   my $written = defined $buffer ? length $buffer : 0;
63
-  $self->{write} = $msg->is_dynamic ? 1 : ($self->{write} - $written);
66
+  $self->{write} = $msg->content->is_dynamic ? 1 : ($self->{write} - $written);
64 67
   $self->{offset} = $self->{offset} + $written;
65 68
   if (defined $buffer) { delete $self->{delay} }
66 69
 
... ...
@@ -71,7 +74,7 @@ sub _body {
71 74
   }
72 75
 
73 76
   # Finished
74
-  $self->{state} = $finish ? 'finished' : 'read_response'
77
+  $self->{state} = $finish ? 'finished' : 'read'
75 78
     if $self->{write} <= 0 || (defined $buffer && !length $buffer);
76 79
 
77 80
   return defined $buffer ? $buffer : '';
... ...
@@ -80,24 +83,23 @@ sub _body {
80 83
 sub _headers {
81 84
   my ($self, $msg, $head) = @_;
82 85
 
83
-  # Prepare chunk
86
+  # Prepare header chunk
84 87
   my $buffer = $msg->get_header_chunk($self->{offset});
85 88
   my $written = defined $buffer ? length $buffer : 0;
86 89
   $self->{write}  = $self->{write} - $written;
87 90
   $self->{offset} = $self->{offset} + $written;
88 91
 
89
-  # Write body
92
+  # Switch to body
90 93
   if ($self->{write} <= 0) {
91 94
     $self->{offset} = 0;
92 95
 
93 96
     # Response without body
94
-    $head = $head && ($self->req->method eq 'HEAD' || $msg->is_empty);
95
-    if ($head) { $self->{state} = 'finished' }
97
+    if ($head && $self->is_empty) { $self->{state} = 'finished' }
96 98
 
97 99
     # Body
98 100
     else {
99
-      $self->{state} = 'write_body';
100
-      $self->{write} = $msg->is_dynamic ? 1 : $msg->body_size;
101
+      $self->{http_state} = 'body';
102
+      $self->{write} = $msg->content->is_dynamic ? 1 : $msg->body_size;
101 103
     }
102 104
   }
103 105
 
... ...
@@ -107,17 +109,17 @@ sub _headers {
107 109
 sub _start_line {
108 110
   my ($self, $msg) = @_;
109 111
 
110
-  # Prepare chunk
112
+  # Prepare start line chunk
111 113
   my $buffer = $msg->get_start_line_chunk($self->{offset});
112 114
   my $written = defined $buffer ? length $buffer : 0;
113 115
   $self->{write}  = $self->{write} - $written;
114 116
   $self->{offset} = $self->{offset} + $written;
115 117
 
116
-  # Write headers
118
+  # Switch to headers
117 119
   if ($self->{write} <= 0) {
118
-    $self->{state}  = 'write_headers';
119
-    $self->{write}  = $msg->header_size;
120
-    $self->{offset} = 0;
120
+    $self->{http_state} = 'headers';
121
+    $self->{write}      = $msg->header_size;
122
+    $self->{offset}     = 0;
121 123
   }
122 124
 
123 125
   return $buffer;
... ...
@@ -126,31 +128,34 @@ sub _start_line {
126 128
 sub _write {
127 129
   my ($self, $server) = @_;
128 130
 
129
-  # Start writing
131
+  # Client starts writing right away
132
+  $self->{state} ||= 'write' unless $server;
133
+  return '' unless $self->{state} eq 'write';
134
+
135
+  # Nothing written yet
130 136
   $self->{$_} ||= 0 for qw(offset write);
131 137
   my $msg = $server ? $self->res : $self->req;
132
-  if ($server ? ($self->{state} eq 'write') : !$self->{state}) {
138
+  unless ($self->{http_state}) {
133 139
 
134 140
     # Connection header
135 141
     my $headers = $msg->headers;
136 142
     $headers->connection($self->keep_alive ? 'keep-alive' : 'close')
137 143
       unless $headers->connection;
138 144
 
139
-    # Write start line
140
-    $self->{state} = 'write_start_line';
141
-    $self->{write} = $msg->start_line_size;
145
+    # Switch to start line
146
+    $self->{http_state} = 'start_line';
147
+    $self->{write}      = $msg->start_line_size;
142 148
   }
143 149
 
144 150
   # Start line
145 151
   my $chunk = '';
146
-  $chunk .= $self->_start_line($msg) if $self->{state} eq 'write_start_line';
152
+  $chunk .= $self->_start_line($msg) if $self->{http_state} eq 'start_line';
147 153
 
148 154
   # Headers
149
-  $chunk .= $self->_headers($msg, $server)
150
-    if $self->{state} eq 'write_headers';
155
+  $chunk .= $self->_headers($msg, $server) if $self->{http_state} eq 'headers';
151 156
 
152 157
   # Body
153
-  $chunk .= $self->_body($msg, $server) if $self->{state} eq 'write_body';
158
+  $chunk .= $self->_body($msg, $server) if $self->{http_state} eq 'body';
154 159
 
155 160
   return $chunk;
156 161
 }
... ...
@@ -168,7 +173,7 @@ Mojo::Transaction::HTTP - HTTP transaction
168 173
   # Client
169 174
   my $tx = Mojo::Transaction::HTTP->new;
170 175
   $tx->req->method('GET');
171
-  $tx->req->url->parse('http://mojolicio.us');
176
+  $tx->req->url->parse('http://example.com');
172 177
   $tx->req->headers->accept('application/json');
173 178
   say $tx->res->code;
174 179
   say $tx->res->headers->content_type;
... ...
@@ -259,6 +264,12 @@ Read data client-side, used to implement user agents.
259 264
 
260 265
 Write data client-side, used to implement user agents.
261 266
 
267
+=head2 is_empty
268
+
269
+  my $success = $tx->is_empty;
270
+
271
+Check transaction for C<HEAD> request and C<1xx>, C<204> or C<304> response.
272
+
262 273
 =head2 keep_alive
263 274
 
264 275
   my $success = $tx->keep_alive;
+95 -39
mojo/lib/Mojo/Transaction/WebSocket.pm
... ...
@@ -2,15 +2,17 @@ package Mojo::Transaction::WebSocket;
2 2
 use Mojo::Base 'Mojo::Transaction';
3 3
 
4 4
 use Config;
5
+use Mojo::JSON;
5 6
 use Mojo::Transaction::HTTP;
6 7
 use Mojo::Util qw(b64_encode decode encode sha1_bytes xor_encode);
7 8
 
8 9
 use constant DEBUG => $ENV{MOJO_WEBSOCKET_DEBUG} || 0;
9 10
 
10
-# 64bit Perl
11
-use constant MODERN => $Config{ivsize} > 4;
11
+# Perl with support for quads
12
+use constant MODERN =>
13
+  ((defined $Config{use64bitint} ? $Config{use64bitint} : '') eq 'define' || $Config{longsize} >= 8);
12 14
 
13
-# Unique value from the spec
15
+# Unique value from RFC 6455
14 16
 use constant GUID => '258EAFA5-E914-47DA-95CA-C5AB0DC85B11';
15 17
 
16 18
 # Opcodes
... ...
@@ -89,10 +91,8 @@ sub client_handshake {
89 91
   my $self = shift;
90 92
 
91 93
   my $headers = $self->req->headers;
92
-  $headers->upgrade('websocket')  unless $headers->upgrade;
93
-  $headers->connection('Upgrade') unless $headers->connection;
94
-  $headers->sec_websocket_protocol('mojo')
95
-    unless $headers->sec_websocket_protocol;
94
+  $headers->upgrade('websocket')      unless $headers->upgrade;
95
+  $headers->connection('Upgrade')     unless $headers->connection;
96 96
   $headers->sec_websocket_version(13) unless $headers->sec_websocket_version;
97 97
 
98 98
   # Generate WebSocket challenge
... ...
@@ -107,7 +107,13 @@ sub connection { shift->handshake->connection }
107 107
 
108 108
 sub finish {
109 109
   my $self = shift;
110
-  $self->send([1, 0, 0, 0, CLOSE, ''])->{finished} = 1;
110
+
111
+  my $close = $self->{close} = [@_];
112
+  my $payload = $close->[0] ? pack('n', $close->[0]) : '';
113
+  $payload .= encode 'UTF-8', $close->[1] if defined $close->[1];
114
+  $close->[0] = defined $close->[0] ? $close->[0] : 1005;
115
+  $self->send([1, 0, 0, 0, CLOSE, $payload])->{finished} = 1;
116
+
111 117
   return $self;
112 118
 }
113 119
 
... ...
@@ -159,7 +165,7 @@ sub parse_frame {
159 165
   }
160 166
 
161 167
   # Check message size
162
-  $self->finish and return undef if $len > $self->max_websocket_size;
168
+  $self->finish(1009) and return undef if $len > $self->max_websocket_size;
163 169
 
164 170
   # Check if whole packet has arrived
165 171
   my $masked = vec($head, 1, 8) & 0b10000000;
... ...
@@ -193,16 +199,21 @@ sub resume {
193 199
 sub send {
194 200
   my ($self, $frame, $cb) = @_;
195 201
 
196
-  # Binary or raw text
197 202
   if (ref $frame eq 'HASH') {
203
+
204
+    # JSON
205
+    $frame->{text} = Mojo::JSON->new->encode($frame->{json}) if $frame->{json};
206
+
207
+    # Binary or raw text
198 208
     $frame
199 209
       = exists $frame->{text}
200 210
       ? [1, 0, 0, 0, TEXT, $frame->{text}]
201 211
       : [1, 0, 0, 0, BINARY, $frame->{binary}];
202 212
   }
203 213
 
204
-  # Text
205
-  elsif (!ref $frame) { $frame = [1, 0, 0, 0, TEXT, encode('UTF-8', $frame)] }
214
+  # Text or object (forcing stringification)
215
+  $frame = [1, 0, 0, 0, TEXT, encode('UTF-8', "$frame")]
216
+    if ref $frame ne 'ARRAY';
206 217
 
207 218
   $self->once(drain => $cb) if $cb;
208 219
   $self->{write} .= $self->build_frame(@$frame);
... ...
@@ -211,14 +222,19 @@ sub send {
211 222
   return $self->emit('resume');
212 223
 }
213 224
 
225
+sub server_close {
226
+  my $self = shift;
227
+  $self->{state} = 'finished';
228
+  return $self->emit(finish => $self->{close} ? (@{$self->{close}}) : 1006);
229
+}
230
+
214 231
 sub server_handshake {
215 232
   my $self = shift;
216 233
 
217
-  # WebSocket handshake
218 234
   my $res_headers = $self->res->code(101)->headers;
219 235
   $res_headers->upgrade('websocket')->connection('Upgrade');
220 236
   my $req_headers = $self->req->headers;
221
-  ($req_headers->sec_websocket_protocol || '') =~ /^\s*([^,]+)/
237
+  (defined $req_headers->sec_websocket_protocol ? $req_headers->sec_websocket_protocol : '') =~ /^\s*([^,]+)/
222 238
     and $res_headers->sec_websocket_protocol($1);
223 239
   $res_headers->sec_websocket_accept(
224 240
     _challenge($req_headers->sec_websocket_key));
... ...
@@ -259,25 +275,29 @@ sub _message {
259 275
   return if $op == PONG;
260 276
 
261 277
   # Close
262
-  return $self->finish if $op == CLOSE;
278
+  if ($op == CLOSE) {
279
+    return $self->finish unless length $frame->[5] >= 2;
280
+    return $self->finish(unpack('n', substr($frame->[5], 0, 2, '')),
281
+      decode('UTF-8', $frame->[5]));
282
+  }
263 283
 
264 284
   # Append chunk and check message size
265 285
   $self->{op} = $op unless exists $self->{op};
266 286
   $self->{message} .= $frame->[5];
267
-  $self->finish and last
287
+  return $self->finish(1009)
268 288
     if length $self->{message} > $self->max_websocket_size;
269 289
 
270 290
   # No FIN bit (Continuation)
271 291
   return unless $frame->[0];
272 292
 
273
-  # Message
293
+  # Whole message
274 294
   my $msg = delete $self->{message};
275
-  if (delete $self->{op} == TEXT) {
276
-    $self->emit(text => $msg);
277
-    $msg = decode 'UTF-8', $msg if $msg;
278
-  }
279
-  else { $self->emit(binary => $msg); }
280
-  $self->emit(message => $msg);
295
+  $self->emit(json => Mojo::JSON->new->decode($msg))
296
+    if $self->has_subscribers('json');
297
+  $op = delete $self->{op};
298
+  $self->emit($op == TEXT ? 'text' : 'binary' => $msg);
299
+  $self->emit(message => $op == TEXT ? decode('UTF-8', $msg) : $msg)
300
+    if $self->has_subscribers('message');
281 301
 }
282 302
 
283 303
 1;
... ...
@@ -298,15 +318,15 @@ Mojo::Transaction::WebSocket - WebSocket transaction
298 318
     say "Message: $msg";
299 319
   });
300 320
   $ws->on(finish => sub {
301
-    my $ws = shift;
302
-    say 'WebSocket closed.';
321
+    my ($ws, $code, $reason) = @_;
322
+    say "WebSocket closed with status $code.";
303 323
   });
304 324
 
305 325
 =head1 DESCRIPTION
306 326
 
307 327
 L<Mojo::Transaction::WebSocket> is a container for WebSocket transactions as
308
-described in RFC 6455. Note that 64bit frames require a Perl with 64bit
309
-integer support, or they are limited to 32bit.
328
+described in RFC 6455. Note that 64bit frames require a Perl with support for
329
+quads or they are limited to 32bit.
310 330
 
311 331
 =head1 EVENTS
312 332
 
... ...
@@ -341,6 +361,15 @@ Emitted once all data has been sent.
341 361
     $ws->send(time);
342 362
   });
343 363
 
364
+=head2 finish
365
+
366
+  $ws->on(finish => sub {
367
+    my ($ws, $code, $reason) = @_;
368
+    ...
369
+  });
370
+
371
+Emitted when transaction is finished.
372
+
344 373
 =head2 frame
345 374
 
346 375
   $ws->on(frame => sub {
... ...
@@ -361,6 +390,22 @@ Emitted when a WebSocket frame has been received.
361 390
     say "Payload: $frame->[5]";
362 391
   });
363 392
 
393
+=head2 json
394
+
395
+  $ws->on(json => sub {
396
+    my ($ws, $json) = @_;
397
+    ...
398
+  });
399
+
400
+Emitted when a complete WebSocket message has been received, all text and
401
+binary messages will be automatically JSON decoded. Note that this event only
402
+gets emitted when it has at least one subscriber.
403
+
404
+  $ws->on(json => sub {
405
+    my ($ws, $hash) = @_;
406
+    say "Message: $hash->{msg}";
407
+  });
408
+
364 409
 =head2 message
365 410
 
366 411
   $ws->on(message => sub {
... ...
@@ -369,7 +414,8 @@ Emitted when a WebSocket frame has been received.
369 414
   });
370 415
 
371 416
 Emitted when a complete WebSocket message has been received, text messages
372
-will be automatically decoded.
417
+will be automatically decoded. Note that this event only gets emitted when it
418
+has at least one subscriber.
373 419
 
374 420
   $ws->on(message => sub {
375 421
     my ($ws, $msg) = @_;
... ...
@@ -416,7 +462,7 @@ Mask outgoing frames with XOR cipher and a random 32bit key.
416 462
   $ws      = $ws->max_websocket_size(1024);
417 463
 
418 464
 Maximum WebSocket message size in bytes, defaults to the value of the
419
-C<MOJO_MAX_WEBSOCKET_SIZE> environment variable or C<262144>.
465
+MOJO_MAX_WEBSOCKET_SIZE environment variable or C<262144>.
420 466
 
421 467
 =head1 METHODS
422 468
 
... ...
@@ -425,7 +471,7 @@ L<Mojo::Transaction> and implements the following new ones.
425 471
 
426 472
 =head2 new
427 473
 
428
-  my $multi = Mojo::Content::MultiPart->new;
474
+  my $ws = Mojo::Transaction::WebSocket->new;
429 475
 
430 476
 Construct a new L<Mojo::Transaction::WebSocket> object and subscribe to
431 477
 C<frame> event with default message parser, which also handles C<PING> and
... ...
@@ -437,15 +483,15 @@ C<CLOSE> frames automatically.
437 483
 
438 484
 Build WebSocket frame.
439 485
 
440
-  # Continuation frame with FIN bit and payload
441
-  say $ws->build_frame(1, 0, 0, 0, 0, 'World!');
442
-
443
-  # Text frame with payload
444
-  say $ws->build_frame(0, 0, 0, 0, 1, 'Hello');
445
-
446 486
   # Binary frame with FIN bit and payload
447 487
   say $ws->build_frame(1, 0, 0, 0, 2, 'Hello World!');
448 488
 
489
+  # Text frame with payload but without FIN bit
490
+  say $ws->build_frame(0, 0, 0, 0, 1, 'Hello ');
491
+
492
+  # Continuation frame with FIN bit and payload
493
+  say $ws->build_frame(1, 0, 0, 0, 0, 'World!');
494
+
449 495
   # Close frame with FIN bit and without payload
450 496
   say $ws->build_frame(1, 0, 0, 0, 8, '');
451 497
 
... ...
@@ -489,8 +535,10 @@ Connection identifier or socket.
489 535
 =head2 finish
490 536
 
491 537
   $ws = $ws->finish;
538
+  $ws = $ws->finish(1000);
539
+  $ws = $ws->finish(1003 => 'Cannot accept data!');
492 540
 
493
-Finish the WebSocket connection gracefully.
541
+Close WebSocket connection gracefully.
494 542
 
495 543
 =head2 is_websocket
496 544
 
... ...
@@ -565,7 +613,9 @@ Resume C<handshake> transaction.
565 613
 
566 614
   $ws = $ws->send({binary => $bytes});
567 615
   $ws = $ws->send({text   => $bytes});
616
+  $ws = $ws->send({json   => {test => [1, 2, 3]}});
568 617
   $ws = $ws->send([$fin, $rsv1, $rsv2, $rsv3, $op, $bytes]);
618
+  $ws = $ws->send(Mojo::ByteStream->new($chars));
569 619
   $ws = $ws->send($chars);
570 620
   $ws = $ws->send($chars => sub {...});
571 621
 
... ...
@@ -575,6 +625,12 @@ will be invoked once all data has been written.
575 625
   # Send "Ping" frame
576 626
   $ws->send([1, 0, 0, 0, 9, 'Hello World!']);
577 627
 
628
+=head2 server_close
629
+
630
+  $ws->server_close;
631
+
632
+Transaction closed server-side, used to implement web servers.
633
+
578 634
 =head2 server_handshake
579 635
 
580 636
   $ws->server_handshake;
... ...
@@ -595,8 +651,8 @@ Write data server-side, used to implement web servers.
595 651
 
596 652
 =head1 DEBUGGING
597 653
 
598
-You can set the C<MOJO_WEBSOCKET_DEBUG> environment variable to get some
599
-advanced diagnostics information printed to C<STDERR>.
654
+You can set the MOJO_WEBSOCKET_DEBUG environment variable to get some advanced
655
+diagnostics information printed to C<STDERR>.
600 656
 
601 657
   MOJO_WEBSOCKET_DEBUG=1
602 658
 
+65 -70
mojo/lib/Mojo/URL.pm
... ...
@@ -15,10 +15,11 @@ has [qw(fragment host port scheme userinfo)];
15 15
 sub new { shift->SUPER::new->parse(@_) }
16 16
 
17 17
 sub authority {
18
-  my ($self, $authority) = @_;
18
+  my $self = shift;
19 19
 
20 20
   # New authority
21
-  if (defined $authority) {
21
+  if (@_) {
22
+    return $self unless defined(my $authority = shift);
22 23
 
23 24
     # Userinfo
24 25
     $authority =~ s/^([^\@]+)\@// and $self->userinfo(url_unescape $1);
... ...
@@ -32,10 +33,11 @@ sub authority {
32 33
   }
33 34
 
34 35
   # Build authority
35
-  my $userinfo = $self->userinfo;
36
-  $authority .= url_escape($userinfo, '^A-Za-z0-9\-._~!$&\'()*+,;=:') . '@'
37
-    if $userinfo;
38
-  $authority .= defined $self->ihost ? $self->ihost : '';
36
+  return undef unless defined(my $authority = $self->ihost);
37
+  if (my $userinfo = $self->userinfo) {
38
+    $userinfo = url_escape $userinfo, '^A-Za-z0-9\-._~!$&\'()*+,;=:';
39
+    $authority = $userinfo . '@' . $authority;
40
+  }
39 41
   if (my $port = $self->port) { $authority .= ":$port" }
40 42
 
41 43
   return $authority;
... ...
@@ -44,14 +46,10 @@ sub authority {
44 46
 sub clone {
45 47
   my $self = shift;
46 48
 
47
-  my $clone = Mojo::URL->new;
48
-  $clone->scheme($self->scheme);
49
-  $clone->userinfo($self->userinfo);
50
-  $clone->host($self->host);
51
-  $clone->port($self->port);
49
+  my $clone = $self->new;
50
+  $clone->$_($self->$_) for qw(scheme userinfo host port fragment);
52 51
   $clone->path($self->path->clone);
53 52
   $clone->query($self->query->clone);
54
-  $clone->fragment($self->fragment);
55 53
   $clone->base($self->base->clone) if $self->{base};
56 54
 
57 55
   return $clone;
... ...
@@ -66,11 +64,11 @@ sub ihost {
66 64
     if @_;
67 65
 
68 66
   # Check if host needs to be encoded
69
-  return undef unless my $host = $self->host;
67
+  return undef unless defined(my $host = $self->host);
70 68
   return lc $host unless $host =~ /[^\x00-\x7f]/;
71 69
 
72 70
   # Encode
73
-  return join '.',
71
+  return lc join '.',
74 72
     map { /[^\x00-\x7f]/ ? ('xn--' . punycode_encode $_) : $_ } split /\./,
75 73
     $host;
76 74
 }
... ...
@@ -81,25 +79,20 @@ sub parse {
81 79
   my ($self, $url) = @_;
82 80
   return $self unless $url;
83 81
 
84
-  # Official regex
85
-  $url =~ m!(?:([^:/?#]+):)?(?://([^/?#]*))?([^?#]*)(?:\?([^#]*))?(?:#(.*))?!;
86
-  $self->scheme($1);
87
-  $self->authority($2);
88
-  $self->path->parse($3);
89
-  $self->query($4);
90
-  $self->fragment($5);
91
-
92
-  return $self;
82
+  # Official regex from RFC 3986
83
+  $url =~ m!^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?!;
84
+  return $self->scheme($2)->authority($4)->path($5)->query($7)->fragment($9);
93 85
 }
94 86
 
95 87
 sub path {
96
-  my ($self, $path) = @_;
88
+  my $self = shift;
97 89
 
98 90
   # Old path
99 91
   $self->{path} ||= Mojo::Path->new;
100
-  return $self->{path} unless $path;
92
+  return $self->{path} unless @_;
101 93
 
102 94
   # New path
95
+  my $path = shift;
103 96
   $self->{path} = ref $path ? $path : $self->{path}->merge($path);
104 97
 
105 98
   return $self;
... ...
@@ -200,32 +193,24 @@ sub to_rel {
200 193
 sub to_string {
201 194
   my $self = shift;
202 195
 
203
-  # Protocol
196
+  # Scheme
204 197
   my $url = '';
205
-  if (my $proto = $self->protocol) { $url .= "$proto://" }
198
+  if (my $proto = $self->protocol) { $url .= "$proto:" }
206 199
 
207 200
   # Authority
208 201
   my $authority = $self->authority;
209
-  $url .= $url ? $authority : $authority ? "//$authority" : '';
210
-
211
-  # Relative path
212
-  my $path = $self->path;
213
-  if (!$url) { $url .= "$path" }
202
+  $url .= "//$authority" if defined $authority;
214 203
 
215
-  # Absolute path
216
-  elsif ($path->leading_slash) { $url .= "$path" }
217
-  else                         { $url .= @{$path->parts} ? "/$path" : '' }
204
+  # Path
205
+  my $path = $self->path->to_string;
206
+  $url .= !$authority || $path eq '' || $path =~ m!^/! ? $path : "/$path";
218 207
 
219 208
   # Query
220
-  my $query = join '', $self->query;
221
-  $url .= "?$query" if length $query;
209
+  if (length(my $query = $self->query->to_string)) { $url .= "?$query" }
222 210
 
223 211
   # Fragment
224
-  my $fragment = $self->fragment;
225
-  $url .= '#' . url_escape $fragment, '^A-Za-z0-9\-._~!$&\'()*+,;=%:@/?'
226
-    if $fragment;
227
-
228
-  return $url;
212
+  return $url unless defined(my $fragment = $self->fragment);
213
+  return $url . '#' . url_escape $fragment, '^A-Za-z0-9\-._~!$&\'()*+,;=%:@/?';
229 214
 }
230 215
 
231 216
 1;
... ...
@@ -242,7 +227,7 @@ Mojo::URL - Uniform Resource Locator
242 227
 
243 228
   # Parse
244 229
   my $url
245
-    = Mojo::URL->new('http://sri:foobar@kraih.com:3000/foo/bar?foo=bar#23');
230
+    = Mojo::URL->new('http://sri:foobar@example.com:3000/foo/bar?foo=bar#23');
246 231
   say $url->scheme;
247 232
   say $url->userinfo;
248 233
   say $url->host;
... ...
@@ -255,7 +240,7 @@ Mojo::URL - Uniform Resource Locator
255 240
   my $url = Mojo::URL->new;
256 241
   $url->scheme('http');
257 242
   $url->userinfo('sri:foobar');
258
-  $url->host('kraih.com');
243
+  $url->host('example.com');
259 244
   $url->port(3000);
260 245
   $url->path('/foo/bar');
261 246
   $url->path('baz');
... ...
@@ -324,7 +309,7 @@ following new ones.
324 309
   my $url = Mojo::URL->new;
325 310
   my $url = Mojo::URL->new('http://127.0.0.1:3000/foo?f=b&baz=2#foo');
326 311
 
327
-Construct a new L<Mojo::URL> object.
312
+Construct a new L<Mojo::URL> object and C<parse> URL if necessary.
328 313
 
329 314
 =head2 authority
330 315
 
... ...
@@ -359,7 +344,16 @@ Check if URL is absolute.
359 344
 
360 345
   $url = $url->parse('http://127.0.0.1:3000/foo/bar?fo=o&baz=23#foo');
361 346
 
362
-Parse URL.
347
+Parse relative or absolute URL.
348
+
349
+  # "/test/123"
350
+  $url->parse('/test/123?foo=bar')->path;
351
+
352
+  # "example.com"
353
+  $url->parse('http://example.com/test/123?foo=bar')->host;
354
+
355
+  # "sri@example.com"
356
+  $url->parse('mailto:sri@example.com')->path;
363 357
 
364 358
 =head2 path
365 359
 
... ...
@@ -368,17 +362,17 @@ Parse URL.
368 362
   $url     = $url->path('foo/bar');
369 363
   $url     = $url->path(Mojo::Path->new);
370 364
 
371
-Path part of this URL, relative paths will be appended to the existing path,
365
+Path part of this URL, relative paths will be merged with the existing path,
372 366
 defaults to a L<Mojo::Path> object.
373 367
 
374
-  # "http://mojolicio.us/DOM/HTML"
375
-  Mojo::URL->new('http://mojolicio.us/perldoc/Mojo')->path('/DOM/HTML');
368
+  # "http://example.com/DOM/HTML"
369
+  Mojo::URL->new('http://example.com/perldoc/Mojo')->path('/DOM/HTML');
376 370
 
377
-  # "http://mojolicio.us/perldoc/DOM/HTML"
378
-  Mojo::URL->new('http://mojolicio.us/perldoc/Mojo')->path('DOM/HTML');
371
+  # "http://example.com/perldoc/DOM/HTML"
372
+  Mojo::URL->new('http://example.com/perldoc/Mojo')->path('DOM/HTML');
379 373
 
380
-  # "http://mojolicio.us/perldoc/Mojo/DOM/HTML"
381
-  Mojo::URL->new('http://mojolicio.us/perldoc/Mojo/')->path('DOM/HTML');
374
+  # "http://example.com/perldoc/Mojo/DOM/HTML"
375
+  Mojo::URL->new('http://example.com/perldoc/Mojo/')->path('DOM/HTML');
382 376
 
383 377
 =head2 protocol
384 378
 
... ...
@@ -387,7 +381,7 @@ defaults to a L<Mojo::Path> object.
387 381
 Normalized version of C<scheme>.
388 382
 
389 383
   # "http"
390
-  Mojo::URL->new('HtTp://mojolicio.us')->protocol;
384
+  Mojo::URL->new('HtTp://example.com')->protocol;
391 385
 
392 386
 =head2 query
393 387
 
... ...
@@ -397,44 +391,45 @@ Normalized version of C<scheme>.
397 391
   $url      = $url->query({append => 'to'});
398 392
   $url      = $url->query(Mojo::Parameters->new);
399 393
 
400
-Query part of this URL, defaults to a L<Mojo::Parameters> object.
394
+Query part of this URL, pairs in an array will be merged and pairs in a hash
395
+appended, defaults to a L<Mojo::Parameters> object.
401 396
 
402 397
   # "2"
403
-  Mojo::URL->new('http://mojolicio.us?a=1&b=2')->query->param('b');
398
+  Mojo::URL->new('http://example.com?a=1&b=2')->query->param('b');
404 399
 
405
-  # "http://mojolicio.us?a=2&c=3"
406
-  Mojo::URL->new('http://mojolicio.us?a=1&b=2')->query(a => 2, c => 3);
400
+  # "http://example.com?a=2&c=3"
401
+  Mojo::URL->new('http://example.com?a=1&b=2')->query(a => 2, c => 3);
407 402
 
408
-  # "http://mojolicio.us?a=2&a=3"
409
-  Mojo::URL->new('http://mojolicio.us?a=1&b=2')->query(a => [2, 3]);
403
+  # "http://example.com?a=2&a=3"
404
+  Mojo::URL->new('http://example.com?a=1&b=2')->query(a => [2, 3]);
410 405
 
411
-  # "http://mojolicio.us?a=2&b=2&c=3"
412
-  Mojo::URL->new('http://mojolicio.us?a=1&b=2')->query([a => 2, c => 3]);
406
+  # "http://example.com?a=2&b=2&c=3"
407
+  Mojo::URL->new('http://example.com?a=1&b=2')->query([a => 2, c => 3]);
413 408
 
414
-  # "http://mojolicio.us?b=2"
415
-  Mojo::URL->new('http://mojolicio.us?a=1&b=2')->query([a => undef]);
409
+  # "http://example.com?b=2"
410
+  Mojo::URL->new('http://example.com?a=1&b=2')->query([a => undef]);
416 411
 
417
-  # "http://mojolicio.us?a=1&b=2&a=2&c=3"
418
-  Mojo::URL->new('http://mojolicio.us?a=1&b=2')->query({a => 2, c => 3});
412
+  # "http://example.com?a=1&b=2&a=2&c=3"
413
+  Mojo::URL->new('http://example.com?a=1&b=2')->query({a => 2, c => 3});
419 414
 
420 415
 =head2 to_abs
421 416
 
422 417
   my $abs = $url->to_abs;
423
-  my $abs = $url->to_abs(Mojo::URL->new('http://kraih.com/foo'));
418
+  my $abs = $url->to_abs(Mojo::URL->new('http://example.com/foo'));
424 419
 
425 420
 Clone relative URL and turn it into an absolute one.
426 421
 
427 422
 =head2 to_rel
428 423
 
429 424
   my $rel = $url->to_rel;
430
-  my $rel = $url->to_rel(Mojo::URL->new('http://kraih.com/foo'));
425
+  my $rel = $url->to_rel(Mojo::URL->new('http://example.com/foo'));
431 426
 
432 427
 Clone absolute URL and turn it into a relative one.
433 428
 
434 429
 =head2 to_string
435 430
 
436
-  my $string = $url->to_string;
437
-  my $string = "$url";
431
+  my $str = $url->to_string;
432
+  my $str = "$url";
438 433
 
439 434
 Turn URL into a string.
440 435
 
+2 -2
mojo/lib/Mojo/Upload.pm
... ...
@@ -1,7 +1,6 @@
1 1
 package Mojo::Upload;
2 2
 use Mojo::Base -base;
3 3
 
4
-use Carp 'croak';
5 4
 use Mojo::Asset::File;
6 5
 use Mojo::Headers;
7 6
 
... ...
@@ -45,7 +44,8 @@ L<Mojo::Upload> implements the following attributes.
45 44
   my $asset = $upload->asset;
46 45
   $upload   = $upload->asset(Mojo::Asset::File->new);
47 46
 
48
-Asset containing the uploaded data, defaults to a L<Mojo::Asset::File> object.
47
+Asset containing the uploaded data, usually a L<Mojo::Asset::File> or
48
+L<Mojo::Asset::Memory> object.
49 49
 
50 50
 =head2 filename
51 51
 
+113 -146
mojo/lib/Mojo/UserAgent.pm
... ...
@@ -59,8 +59,6 @@ sub app_url {
59 59
   return Mojo::URL->new("$self->{proto}://localhost:$self->{port}/");
60 60
 }
61 61
 
62
-sub build_form_tx      { shift->transactor->form(@_) }
63
-sub build_json_tx      { shift->transactor->json(@_) }
64 62
 sub build_tx           { shift->transactor->tx(@_) }
65 63
 sub build_websocket_tx { shift->transactor->websocket(@_) }
66 64
 
... ...
@@ -76,25 +74,11 @@ sub need_proxy {
76 74
   return !first { $host =~ /\Q$_\E$/ } @{$self->no_proxy || []};
77 75
 }
78 76
 
79
-sub post_form {
80
-  my $self = shift;
81
-  my $cb = ref $_[-1] eq 'CODE' ? pop : undef;
82
-  return $self->start($self->build_form_tx(@_), $cb);
83
-}
84
-
85
-sub post_json {
86
-  my $self = shift;
87
-  my $cb = ref $_[-1] eq 'CODE' ? pop : undef;
88
-  return $self->start($self->build_json_tx(@_), $cb);
89
-}
90
-
91 77
 sub start {
92 78
   my ($self, $tx, $cb) = @_;
93 79
 
94 80
   # Non-blocking
95 81
   if ($cb) {
96
-
97
-    # Start non-blocking
98 82
     warn "-- Non-blocking request (@{[$tx->req->url->to_abs]})\n" if DEBUG;
99 83
     unless ($self->{nb}) {
100 84
       croak 'Blocking request in progress' if keys %{$self->{connections}};
... ...
@@ -105,7 +89,7 @@ sub start {
105 89
     return $self->_start($tx, $cb);
106 90
   }
107 91
 
108
-  # Start blocking
92
+  # Blocking
109 93
   warn "-- Blocking request (@{[$tx->req->url->to_abs]})\n" if DEBUG;
110 94
   if ($self->{nb}) {
111 95
     croak 'Non-blocking requests in progress' if keys %{$self->{connections}};
... ...
@@ -113,9 +97,7 @@ sub start {
113 97
     $self->_cleanup;
114 98
     delete $self->{nb};
115 99
   }
116
-  $self->_start($tx => sub { $tx = pop });
117
-
118
-  # Start event loop
100
+  $self->_start($tx => sub { shift->ioloop->stop; $tx = shift });
119 101
   $self->ioloop->start;
120 102
 
121 103
   return $tx;
... ...
@@ -166,7 +148,7 @@ sub _cleanup {
166 148
   # Clean up active connections (by closing them)
167 149
   $self->_handle($_ => 1) for keys %{$self->{connections} || {}};
168 150
 
169
-  # Clean up keep alive connections
151
+  # Clean up keep-alive connections
170 152
   $loop->remove($_->[1]) for @{delete $self->{cache} || []};
171 153
 
172 154
   # Stop server
... ...
@@ -311,17 +293,16 @@ sub _finish {
311 293
     }
312 294
   }
313 295
 
314
-  # Stop event loop if necessary
315 296
   $self->$cb($tx);
316
-  $self->ioloop->stop unless $self->{nb};
317 297
 }
318 298
 
319 299
 sub _handle {
320 300
   my ($self, $id, $close) = @_;
321 301
 
322 302
   # Remove request timeout
303
+  return unless my $loop = $self->_loop;
323 304
   my $c = $self->{connections}{$id};
324
-  $self->_loop->remove($c->{timeout}) if $c->{timeout};
305
+  $loop->remove($c->{timeout}) if $c->{timeout};
325 306
 
326 307
   # Finish WebSocket
327 308
   my $old = $c->{tx};
... ...
@@ -336,7 +317,7 @@ sub _handle {
336 317
     if (my $jar = $self->cookie_jar) { $jar->extract($old) }
337 318
     $old->client_close;
338 319
     $self->_finish($new, $c->{cb});
339
-    $new->client_read($old->res->leftovers);
320
+    $new->client_read($old->res->content->leftovers);
340 321
   }
341 322
 
342 323
   # Finish normal connection
... ...
@@ -352,7 +333,7 @@ sub _handle {
352 333
   }
353 334
 }
354 335
 
355
-sub _loop { $_[0]->{nb} ? Mojo::IOLoop->singleton : $_[0]->ioloop }
336
+sub _loop { $_[0]{nb} ? Mojo::IOLoop->singleton : $_[0]->ioloop }
356 337
 
357 338
 sub _read {
358 339
   my ($self, $id, $chunk) = @_;
... ...
@@ -380,7 +361,7 @@ sub _remove {
380 361
 
381 362
   # Keep connection alive
382 363
   $self->_cache(join(':', $self->transactor->endpoint($tx)), $id)
383
-    unless $tx->req->method eq 'CONNECT' && (defined $tx->res->code ? $tx->res->code : '') eq '200';
364
+    unless uc $tx->req->method eq 'CONNECT' && (defined $tx->res->code ? $tx->res->code : '') eq '200';
384 365
 }
385 366
 
386 367
 sub _redirect {
... ...
@@ -421,7 +402,8 @@ sub _start {
421 402
   my $url = $req->url;
422 403
   if ($self->{port} || !$url->is_abs) {
423 404
     if (my $app = $self->app) { $self->_server->app($app) }
424
-    $url = $req->url($url->base($self->app_url)->to_abs)->url
405
+    my $base = $self->app_url;
406
+    $url->scheme($base->scheme)->authority($base->authority)
425 407
       unless $url->is_abs;
426 408
   }
427 409
 
... ...
@@ -447,10 +429,10 @@ sub _start {
447 429
 
448 430
   # Connect and add request timeout if necessary
449 431
   my $id = $self->emit(start => $tx)->_connection($tx, $cb);
450
-  if (my $t = $self->request_timeout) {
432
+  if (my $timeout = $self->request_timeout) {
451 433
     weaken $self;
452 434
     $self->{connections}{$id}{timeout} = $self->_loop->timer(
453
-      $t => sub { $self->_error($id => 'Request timeout') });
435
+      $timeout => sub { $self->_error($id => 'Request timeout') });
454 436
   }
455 437
 
456 438
   return $id;
... ...
@@ -504,7 +486,7 @@ Mojo::UserAgent - Non-blocking I/O HTTP and WebSocket user agent
504 486
   say $ua->get('www.☃.net?hello=there' => {DNT => 1})->res->body;
505 487
 
506 488
   # Form POST with exception handling
507
-  my $tx = $ua->post_form('search.cpan.org/search' => {q => 'mojo'});
489
+  my $tx = $ua->post('https://metacpan.org/search' => form => {q => 'mojo'});
508 490
   if (my $res = $tx->success) { say $res->body }
509 491
   else {
510 492
     my ($err, $code) = $tx->error;
... ...
@@ -532,20 +514,15 @@ Mojo::UserAgent - Non-blocking I/O HTTP and WebSocket user agent
532 514
 
533 515
   # TLS certificate authentication and JSON POST
534 516
   my $tx = $ua->cert('tls.crt')->key('tls.key')
535
-    ->post_json('https://mojolicio.us' => {top => 'secret'});
536
-
537
-  # Custom JSON PUT request
538
-  my $tx = $ua->build_json_tx('http://mojolicious/foo' => {hi => 'there'});
539
-  $tx->req->method('PUT');
540
-  say $ua->start($tx)->res->body;
517
+    ->post('https://mojolicio.us' => json => {top => 'secret'});
541 518
 
542 519
   # Blocking parallel requests (does not work inside a running event loop)
543 520
   my $delay = Mojo::IOLoop->delay;
544 521
   for my $url ('mojolicio.us', 'cpan.org') {
545
-    $delay->begin;
522
+    my $end = $delay->begin(0);
546 523
     $ua->get($url => sub {
547 524
       my ($ua, $tx) = @_;
548
-      $delay->end($tx->res->dom->at('title')->text);
525
+      $end->($tx->res->dom->at('title')->text);
549 526
     });
550 527
   }
551 528
   my @titles = $delay->wait;
... ...
@@ -556,37 +533,38 @@ Mojo::UserAgent - Non-blocking I/O HTTP and WebSocket user agent
556 533
     ...
557 534
   });
558 535
   for my $url ('mojolicio.us', 'cpan.org') {
559
-    $delay->begin;
536
+    my $end = $delay->begin(0);
560 537
     $ua->get($url => sub {
561 538
       my ($ua, $tx) = @_;
562
-      $delay->end($tx->res->dom->at('title')->text);
539
+      $end->($tx->res->dom->at('title')->text);
563 540
     });
564 541
   }
565 542
   $delay->wait unless Mojo::IOLoop->is_running;
566 543
 
567
-  # Non-blocking WebSocket connection
568
-  $ua->websocket('ws://websockets.org:8787' => sub {
544
+  # Non-blocking WebSocket connection sending and receiving JSON messages
545
+  $ua->websocket('ws://example.com/echo.json' => sub {
569 546
     my ($ua, $tx) = @_;
570
-    $tx->on(finish  => sub { say 'WebSocket closed.' });
571
-    $tx->on(message => sub {
572
-      my ($tx, $msg) = @_;
573
-      say "WebSocket message: $msg";
547
+    say 'WebSocket handshake failed!' and return unless $tx->is_websocket;
548
+    $tx->on(json => sub {
549
+      my ($tx, $hash) = @_;
550
+      say "WebSocket message via JSON: $hash->{msg}";
574 551
       $tx->finish;
575 552
     });
576
-    $tx->send('hi there!');
553
+    $tx->send({json => {msg => 'Hello World!'}});
577 554
   });
578 555
   Mojo::IOLoop->start unless Mojo::IOLoop->is_running;
579 556
 
580 557
 =head1 DESCRIPTION
581 558
 
582 559
 L<Mojo::UserAgent> is a full featured non-blocking I/O HTTP and WebSocket user
583
-agent, with C<IPv6>, C<TLS>, C<SNI>, C<IDNA>, C<Comet> (long polling), C<gzip>
560
+agent, with C<IPv6>, C<TLS>, C<SNI>, C<IDNA>, C<Comet> (long polling),
561
+C<keep-alive>, connection pooling, timeout, cookie, multipart, proxy, C<gzip>
584 562
 compression and multiple event loop support.
585 563
 
586 564
 Optional modules L<EV> (4.0+), L<IO::Socket::IP> (0.16+) and
587 565
 L<IO::Socket::SSL> (1.75+) are supported transparently through
588 566
 L<Mojo::IOLoop>, and used if installed. Individual features can also be
589
-disabled with the C<MOJO_NO_IPV6> and C<MOJO_NO_TLS> environment variables.
567
+disabled with the MOJO_NO_IPV6 and MOJO_NO_TLS environment variables.
590 568
 
591 569
 See L<Mojolicious::Guides::Cookbook> for more.
592 570
 
... ...
@@ -634,7 +612,7 @@ L<Mojo::UserAgent> implements the following attributes.
634 612
   $ua    = $ua->ca('/etc/tls/ca.crt');
635 613
 
636 614
 Path to TLS certificate authority file, defaults to the value of the
637
-C<MOJO_CA_FILE> environment variable. Also activates hostname verification.
615
+MOJO_CA_FILE environment variable. Also activates hostname verification.
638 616
 
639 617
   # Show certificate authorities for debugging
640 618
   IO::Socket::SSL::set_defaults(
... ...
@@ -645,7 +623,7 @@ C<MOJO_CA_FILE> environment variable. Also activates hostname verification.
645 623
   my $cert = $ua->cert;
646 624
   $ua      = $ua->cert('/etc/tls/client.crt');
647 625
 
648
-Path to TLS certificate file, defaults to the value of the C<MOJO_CERT_FILE>
626
+Path to TLS certificate file, defaults to the value of the MOJO_CERT_FILE
649 627
 environment variable.
650 628
 
651 629
 =head2 connect_timeout
... ...
@@ -654,7 +632,7 @@ environment variable.
654 632
   $ua         = $ua->connect_timeout(5);
655 633
 
656 634
 Maximum amount of time in seconds establishing a connection may take before
657
-getting canceled, defaults to the value of the C<MOJO_CONNECT_TIMEOUT>
635
+getting canceled, defaults to the value of the MOJO_CONNECT_TIMEOUT
658 636
 environment variable or C<10>.
659 637
 
660 638
 =head2 cookie_jar
... ...
@@ -688,7 +666,7 @@ Proxy server to use for HTTPS and WebSocket requests.
688 666
   $ua         = $ua->inactivity_timeout(15);
689 667
 
690 668
 Maximum amount of time in seconds a connection can be inactive before getting
691
-closed, defaults to the value of the C<MOJO_INACTIVITY_TIMEOUT> environment
669
+closed, defaults to the value of the MOJO_INACTIVITY_TIMEOUT environment
692 670
 variable or C<20>. Setting the value to C<0> will allow connections to be
693 671
 inactive indefinitely.
694 672
 
... ...
@@ -705,8 +683,8 @@ L<Mojo::IOLoop> object.
705 683
   my $key = $ua->key;
706 684
   $ua     = $ua->key('/etc/tls/client.crt');
707 685
 
708
-Path to TLS key file, defaults to the value of the C<MOJO_KEY_FILE>
709
-environment variable.
686
+Path to TLS key file, defaults to the value of the MOJO_KEY_FILE environment
687
+variable.
710 688
 
711 689
 =head2 local_address
712 690
 
... ...
@@ -720,7 +698,7 @@ Local address to bind to.
720 698
   my $max = $ua->max_connections;
721 699
   $ua     = $ua->max_connections(5);
722 700
 
723
-Maximum number of keep alive connections that the user agent will retain
701
+Maximum number of keep-alive connections that the user agent will retain
724 702
 before it starts closing the oldest cached ones, defaults to C<5>.
725 703
 
726 704
 =head2 max_redirects
... ...
@@ -729,8 +707,7 @@ before it starts closing the oldest cached ones, defaults to C<5>.
729 707
   $ua     = $ua->max_redirects(3);
730 708
 
731 709
 Maximum number of redirects the user agent will follow before it fails,
732
-defaults to the value of the C<MOJO_MAX_REDIRECTS> environment variable or
733
-C<0>.
710
+defaults to the value of the MOJO_MAX_REDIRECTS environment variable or C<0>.
734 711
 
735 712
 =head2 name
736 713
 
... ...
@@ -753,7 +730,7 @@ Domains that don't require a proxy server to be used.
753 730
 
754 731
 Maximum amount of time in seconds establishing a connection, sending the
755 732
 request and receiving a whole response may take before getting canceled,
756
-defaults to the value of the C<MOJO_REQUEST_TIMEOUT> environment variable or
733
+defaults to the value of the MOJO_REQUEST_TIMEOUT environment variable or
757 734
 C<0>. Setting the value to C<0> will allow the user agent to wait
758 735
 indefinitely. The timeout will reset for every followed redirect.
759 736
 
... ...
@@ -802,54 +779,47 @@ Get absolute L<Mojo::URL> object for C<app> and switch protocol if necessary.
802 779
   # Port currently used for processing relative URLs
803 780
   say $ua->app_url->port;
804 781
 
805
-=head2 build_form_tx
806
-
807
-  my $tx = $ua->build_form_tx('http://kraih.com' => {a => 'b'});
808
-  my $tx = $ua->build_form_tx('kraih.com', 'UTF-8', {a => 'b'}, {DNT => 1});
809
-
810
-Generate L<Mojo::Transaction::HTTP> object with
811
-L<Mojo::UserAgent::Transactor/"form">.
812
-
813
-=head2 build_json_tx
814
-
815
-  my $tx = $ua->build_json_tx('http://kraih.com' => {a => 'b'});
816
-  my $tx = $ua->build_json_tx('kraih.com' => {a => 'b'} => {DNT => 1});
817
-
818
-Generate L<Mojo::Transaction::HTTP> object with
819
-L<Mojo::UserAgent::Transactor/"json">.
820
-
821 782
 =head2 build_tx
822 783
 
823
-  my $tx = $ua->build_tx(GET => 'kraih.com');
824
-  my $tx = $ua->build_tx(PUT => 'http://kraih.com' => {DNT => 1} => 'Hi!');
784
+  my $tx = $ua->build_tx(GET => 'example.com');
785
+  my $tx = $ua->build_tx(PUT => 'http://example.com' => {DNT => 1} => 'Hi!');
786
+  my $tx = $ua->build_tx(
787
+    PUT => 'http://example.com' => {DNT => 1} => form => {a => 'b'});
788
+  my $tx = $ua->build_tx(
789
+    PUT => 'http://example.com' => {DNT => 1} => json => {a => 'b'});
825 790
 
826 791
 Generate L<Mojo::Transaction::HTTP> object with
827 792
 L<Mojo::UserAgent::Transactor/"tx">.
828 793
 
829 794
   # Request with cookie
830
-  my $tx = $ua->build_tx(GET => 'kraih.com');
795
+  my $tx = $ua->build_tx(GET => 'example.com');
831 796
   $tx->req->cookies({name => 'foo', value => 'bar'});
832 797
   $ua->start($tx);
833 798
 
834 799
 =head2 build_websocket_tx
835 800
 
836
-  my $tx = $ua->build_websocket_tx('ws://localhost:3000');
837
-  my $tx = $ua->build_websocket_tx('ws://localhost:3000' => {DNT => 1});
801
+  my $tx = $ua->build_websocket_tx('ws://example.com');
802
+  my $tx =
803
+    $ua->build_websocket_tx('ws://example.com' => {DNT => 1} => ['v1.proto']);
838 804
 
839 805
 Generate L<Mojo::Transaction::HTTP> object with
840 806
 L<Mojo::UserAgent::Transactor/"websocket">.
841 807
 
842 808
 =head2 delete
843 809
 
844
-  my $tx = $ua->delete('kraih.com');
845
-  my $tx = $ua->delete('http://kraih.com' => {DNT => 1} => 'Hi!');
810
+  my $tx = $ua->delete('example.com');
811
+  my $tx = $ua->delete('http://example.com' => {DNT => 1} => 'Hi!');
812
+  my $tx = $ua->delete(
813
+    'http://example.com' => {DNT => 1} => form => {a => 'b'});
814
+  my $tx = $ua->delete(
815
+    'http://example.com' => {DNT => 1} => json => {a => 'b'});
846 816
 
847 817
 Perform blocking HTTP C<DELETE> request and return resulting
848 818
 L<Mojo::Transaction::HTTP> object, takes the same arguments as
849 819
 L<Mojo::UserAgent::Transactor/"tx"> (except for the method). You can also
850 820
 append a callback to perform requests non-blocking.
851 821
 
852
-  $ua->delete('http://kraih.com' => sub {
822
+  $ua->delete('http://example.com' => sub {
853 823
     my ($ua, $tx) = @_;
854 824
     say $tx->res->body;
855 825
   });
... ...
@@ -859,21 +829,23 @@ append a callback to perform requests non-blocking.
859 829
 
860 830
   $ua = $ua->detect_proxy;
861 831
 
862
-Check environment variables C<HTTP_PROXY>, C<http_proxy>, C<HTTPS_PROXY>,
863
-C<https_proxy>, C<NO_PROXY> and C<no_proxy> for proxy information. Automatic
864
-proxy detection can be enabled with the C<MOJO_PROXY> environment variable.
832
+Check environment variables HTTP_PROXY, http_proxy, HTTPS_PROXY, https_proxy,
833
+NO_PROXY and no_proxy for proxy information. Automatic proxy detection can be
834
+enabled with the MOJO_PROXY environment variable.
865 835
 
866 836
 =head2 get
867 837
 
868
-  my $tx = $ua->get('kraih.com');
869
-  my $tx = $ua->get('http://kraih.com' => {DNT => 1} => 'Hi!');
838
+  my $tx = $ua->get('example.com');
839
+  my $tx = $ua->get('http://example.com' => {DNT => 1} => 'Hi!');
840
+  my $tx = $ua->get('http://example.com' => {DNT => 1} => form => {a => 'b'});
841
+  my $tx = $ua->get('http://example.com' => {DNT => 1} => json => {a => 'b'});
870 842
 
871 843
 Perform blocking HTTP C<GET> request and return resulting
872 844
 L<Mojo::Transaction::HTTP> object, takes the same arguments as
873 845
 L<Mojo::UserAgent::Transactor/"tx"> (except for the method). You can also
874 846
 append a callback to perform requests non-blocking.
875 847
 
876
-  $ua->get('http://kraih.com' => sub {
848
+  $ua->get('http://example.com' => sub {
877 849
     my ($ua, $tx) = @_;
878 850
     say $tx->res->body;
879 851
   });
... ...
@@ -881,15 +853,19 @@ append a callback to perform requests non-blocking.
881 853
 
882 854
 =head2 head
883 855
 
884
-  my $tx = $ua->head('kraih.com');
885
-  my $tx = $ua->head('http://kraih.com' => {DNT => 1} => 'Hi!');
856
+  my $tx = $ua->head('example.com');
857
+  my $tx = $ua->head('http://example.com' => {DNT => 1} => 'Hi!');
858
+  my $tx = $ua->head(
859
+    'http://example.com' => {DNT => 1} => form => {a => 'b'});
860
+  my $tx = $ua->head(
861
+    'http://example.com' => {DNT => 1} => json => {a => 'b'});
886 862
 
887 863
 Perform blocking HTTP C<HEAD> request and return resulting
888 864
 L<Mojo::Transaction::HTTP> object, takes the same arguments as
889 865
 L<Mojo::UserAgent::Transactor/"tx"> (except for the method). You can also
890 866
 append a callback to perform requests non-blocking.
891 867
 
892
-  $ua->head('http://kraih.com' => sub {
868
+  $ua->head('http://example.com' => sub {
893 869
     my ($ua, $tx) = @_;
894 870
     say $tx->res->body;
895 871
   });
... ...
@@ -897,21 +873,25 @@ append a callback to perform requests non-blocking.
897 873
 
898 874
 =head2 need_proxy
899 875
 
900
-  my $success = $ua->need_proxy('intranet.mojolicio.us');
876
+  my $success = $ua->need_proxy('intranet.example.com');
901 877
 
902 878
 Check if request for domain would use a proxy server.
903 879
 
904 880
 =head2 options
905 881
 
906
-  my $tx = $ua->options('kraih.com');
907
-  my $tx = $ua->options('http://kraih.com' => {DNT => 1} => 'Hi!');
882
+  my $tx = $ua->options('example.com');
883
+  my $tx = $ua->options('http://example.com' => {DNT => 1} => 'Hi!');
884
+  my $tx = $ua->options(
885
+    'http://example.com' => {DNT => 1} => form => {a => 'b'});
886
+  my $tx = $ua->options(
887
+    'http://example.com' => {DNT => 1} => json => {a => 'b'});
908 888
 
909 889
 Perform blocking HTTP C<OPTIONS> request and return resulting
910 890
 L<Mojo::Transaction::HTTP> object, takes the same arguments as
911 891
 L<Mojo::UserAgent::Transactor/"tx"> (except for the method). You can also
912 892
 append a callback to perform requests non-blocking.
913 893
 
914
-  $ua->options('http://kraih.com' => sub {
894
+  $ua->options('http://example.com' => sub {
915 895
     my ($ua, $tx) = @_;
916 896
     say $tx->res->body;
917 897
   });
... ...
@@ -919,15 +899,19 @@ append a callback to perform requests non-blocking.
919 899
 
920 900
 =head2 patch
921 901
 
922
-  my $tx = $ua->patch('kraih.com');
923
-  my $tx = $ua->patch('http://kraih.com' => {DNT => 1} => 'Hi!');
902
+  my $tx = $ua->patch('example.com');
903
+  my $tx = $ua->patch('http://example.com' => {DNT => 1} => 'Hi!');
904
+  my $tx = $ua->patch(
905
+    'http://example.com' => {DNT => 1} => form => {a => 'b'});
906
+  my $tx = $ua->patch(
907
+    'http://example.com' => {DNT => 1} => json => {a => 'b'});
924 908
 
925 909
 Perform blocking HTTP C<PATCH> request and return resulting
926 910
 L<Mojo::Transaction::HTTP> object, takes the same arguments as
927 911
 L<Mojo::UserAgent::Transactor/"tx"> (except for the method). You can also
928 912
 append a callback to perform requests non-blocking.
929 913
 
930
-  $ua->patch('http://kraih.com' => sub {
914
+  $ua->patch('http://example.com' => sub {
931 915
     my ($ua, $tx) = @_;
932 916
     say $tx->res->body;
933 917
   });
... ...
@@ -935,47 +919,19 @@ append a callback to perform requests non-blocking.
935 919
 
936 920
 =head2 post
937 921
 
938
-  my $tx = $ua->post('kraih.com');
939
-  my $tx = $ua->post('http://kraih.com' => {DNT => 1} => 'Hi!');
922
+  my $tx = $ua->post('example.com');
923
+  my $tx = $ua->post('http://example.com' => {DNT => 1} => 'Hi!');
924
+  my $tx = $ua->post(
925
+    'http://example.com' => {DNT => 1} => form => {a => 'b'});
926
+  my $tx = $ua->post(
927
+    'http://example.com' => {DNT => 1} => json => {a => 'b'});
940 928
 
941 929
 Perform blocking HTTP C<POST> request and return resulting
942 930
 L<Mojo::Transaction::HTTP> object, takes the same arguments as
943 931
 L<Mojo::UserAgent::Transactor/"tx"> (except for the method). You can also
944 932
 append a callback to perform requests non-blocking.
945 933
 
946
-  $ua->post('http://kraih.com' => sub {
947
-    my ($ua, $tx) = @_;
948
-    say $tx->res->body;
949
-  });
950
-  Mojo::IOLoop->start unless Mojo::IOLoop->is_running;
951
-
952
-=head2 post_form
953
-
954
-  my $tx = $ua->post_form('http://kraih.com' => {a => 'b'});
955
-  my $tx = $ua->post_form('kraih.com', 'UTF-8', {a => 'b'}, {DNT => 1});
956
-
957
-Perform blocking HTTP C<POST> request with form data and return resulting
958
-L<Mojo::Transaction::HTTP> object, takes the same arguments as
959
-L<Mojo::UserAgent::Transactor/"form">. You can also append a callback to
960
-perform requests non-blocking.
961
-
962
-  $ua->post_form('http://kraih.com' => {q => 'test'} => sub {
963
-    my ($ua, $tx) = @_;
964
-    say $tx->res->body;
965
-  });
966
-  Mojo::IOLoop->start unless Mojo::IOLoop->is_running;
967
-
968
-=head2 post_json
969
-
970
-  my $tx = $ua->post_json('http://kraih.com' => {a => 'b'});
971
-  my $tx = $ua->post_json('kraih.com' => {a => 'b'} => {DNT => 1});
972
-
973
-Perform blocking HTTP C<POST> request with JSON data and return resulting
974
-L<Mojo::Transaction::HTTP> object, takes the same arguments as
975
-L<Mojo::UserAgent::Transactor/"json">. You can also append a callback to
976
-perform requests non-blocking.
977
-
978
-  $ua->post_json('http://kraih.com' => {q => 'test'} => sub {
934
+  $ua->post('http://example.com' => sub {
979 935
     my ($ua, $tx) = @_;
980 936
     say $tx->res->body;
981 937
   });
... ...
@@ -983,15 +939,17 @@ perform requests non-blocking.
983 939
 
984 940
 =head2 put
985 941
 
986
-  my $tx = $ua->put('kraih.com');
987
-  my $tx = $ua->put('http://kraih.com' => {DNT => 1} => 'Hi!');
942
+  my $tx = $ua->put('example.com');
943
+  my $tx = $ua->put('http://example.com' => {DNT => 1} => 'Hi!');
944
+  my $tx = $ua->put('http://example.com' => {DNT => 1} => form => {a => 'b'});
945
+  my $tx = $ua->put('http://example.com' => {DNT => 1} => json => {a => 'b'});
988 946
 
989 947
 Perform blocking HTTP C<PUT> request and return resulting
990 948
 L<Mojo::Transaction::HTTP> object, takes the same arguments as
991 949
 L<Mojo::UserAgent::Transactor/"tx"> (except for the method). You can also
992 950
 append a callback to perform requests non-blocking.
993 951
 
994
-  $ua->put('http://kraih.com' => sub {
952
+  $ua->put('http://example.com' => sub {
995 953
     my ($ua, $tx) = @_;
996 954
     say $tx->res->body;
997 955
   });
... ...
@@ -1004,7 +962,7 @@ append a callback to perform requests non-blocking.
1004 962
 Perform blocking request. You can also append a callback to perform requests
1005 963
 non-blocking.
1006 964
 
1007
-  my $tx = $ua->build_tx(GET => 'http://kraih.com');
965
+  my $tx = $ua->build_tx(GET => 'http://example.com');
1008 966
   $ua->start($tx => sub {
1009 967
     my ($ua, $tx) = @_;
1010 968
     say $tx->res->body;
... ...
@@ -1013,17 +971,26 @@ non-blocking.
1013 971
 
1014 972
 =head2 websocket
1015 973
 
1016
-  $ua->websocket('ws://localhost:3000' => sub {...});
1017
-  $ua->websocket('ws://localhost:3000' => {DNT => 1} => sub {...});
974
+  $ua->websocket('ws://example.com' => sub {...});
975
+  $ua->websocket(
976
+    'ws://example.com' => {DNT => 1} => ['v1.proto'] => sub {...});
1018 977
 
1019 978
 Open a non-blocking WebSocket connection with transparent handshake, takes the
1020
-same arguments as L<Mojo::UserAgent::Transactor/"websocket">.
979
+same arguments as L<Mojo::UserAgent::Transactor/"websocket">. The callback
980
+will receive either a L<Mojo::Transaction::WebSocket> or
981
+L<Mojo::Transaction::HTTP> object.
1021 982
 
1022
-  $ua->websocket('ws://localhost:3000/echo' => sub {
983
+  $ua->websocket('ws://example.com/echo' => sub {
1023 984
     my ($ua, $tx) = @_;
985
+    say 'WebSocket handshake failed!' and return unless $tx->is_websocket;
986
+    $tx->on(finish => sub {
987
+      my ($tx, $code, $reason) = @_;
988
+      say "WebSocket closed with status $code.";
989
+    });
1024 990
     $tx->on(message => sub {
1025 991
       my ($tx, $msg) = @_;
1026
-      say $msg;
992
+      say "WebSocket message: $msg";
993
+      $tx->finish;
1027 994
     });
1028 995
     $tx->send('Hi!');
1029 996
   });
... ...
@@ -1031,8 +998,8 @@ same arguments as L<Mojo::UserAgent::Transactor/"websocket">.
1031 998
 
1032 999
 =head1 DEBUGGING
1033 1000
 
1034
-You can set the C<MOJO_USERAGENT_DEBUG> environment variable to get some
1035
-advanced diagnostics information printed to C<STDERR>.
1001
+You can set the MOJO_USERAGENT_DEBUG environment variable to get some advanced
1002
+diagnostics information printed to C<STDERR>.
1036 1003
 
1037 1004
   MOJO_USERAGENT_DEBUG=1
1038 1005
 
+6 -6
mojo/lib/Mojo/UserAgent/CookieJar.pm
... ...
@@ -43,11 +43,11 @@ sub extract {
43 43
   for my $cookie (@{$tx->res->cookies}) {
44 44
 
45 45
     # Validate domain
46
-    my $host = lc $url->ihost;
46
+    my $host = $url->ihost;
47 47
     my $domain = lc(defined $cookie->domain ? $cookie->domain : $host);
48 48
     $domain =~ s/^\.//;
49
-    next unless $host eq $domain || $host =~ /\Q.$domain\E$/;
50
-    next if $host =~ /\.\d+$/;
49
+    next
50
+      if $host ne $domain && ($host !~ /\Q.$domain\E$/ || $host =~ /\.\d+$/);
51 51
     $cookie->domain($domain);
52 52
 
53 53
     # Validate path
... ...
@@ -61,7 +61,7 @@ sub extract {
61 61
 sub find {
62 62
   my ($self, $url) = @_;
63 63
 
64
-  return unless my $domain = lc(defined $url->ihost ? $url->ihost : '');
64
+  return unless my $domain = $url->ihost;
65 65
   my $path = $url->path->to_abs_string;
66 66
   my @found;
67 67
   while ($domain =~ /[^.]+\.[^.]+|localhost$/) {
... ...
@@ -129,8 +129,8 @@ Mojo::UserAgent::CookieJar - Cookie jar for HTTP user agents
129 129
 
130 130
 =head1 DESCRIPTION
131 131
 
132
-L<Mojo::UserAgent::CookieJar> is a minimalistic and relaxed cookie jar used by
133
-L<Mojo::UserAgent>.
132
+L<Mojo::UserAgent::CookieJar> is a minimalistic and relaxed cookie jar based
133
+on RFC 6265 for L<Mojo::UserAgent>.
134 134
 
135 135
 =head1 ATTRIBUTES
136 136
 
+159 -125
mojo/lib/Mojo/UserAgent/Transactor.pm
... ...
@@ -13,6 +13,19 @@ use Mojo::Transaction::WebSocket;
13 13
 use Mojo::URL;
14 14
 use Mojo::Util 'encode';
15 15
 
16
+has generators => sub { {} };
17
+
18
+sub new {
19
+  my $self = shift->SUPER::new(@_);
20
+  return $self->add_generator(form => \&_form)->add_generator(json => \&_json);
21
+}
22
+
23
+sub add_generator {
24
+  my ($self, $name, $cb) = @_;
25
+  $self->generators->{$name} = $cb;
26
+  return $self;
27
+}
28
+
16 29
 sub endpoint {
17 30
   my ($self, $tx) = @_;
18 31
 
... ...
@@ -25,54 +38,11 @@ sub endpoint {
25 38
 
26 39
   # Proxy for normal HTTP requests
27 40
   return $self->_proxy($tx, $proto, $host, $port)
28
-    if $proto eq 'http' && lc($req->headers->upgrade || '') ne 'websocket';
41
+    if $proto eq 'http' && lc(defined $req->headers->upgrade ? $req->headers->upgrade : '') ne 'websocket';
29 42
 
30 43
   return $proto, $host, $port;
31 44
 }
32 45
 
33
-sub form {
34
-  my ($self, $url, $encoding) = (shift, shift, shift);
35
-  my $form = ref $encoding ? $encoding : shift;
36
-  $encoding = undef if ref $encoding;
37
-
38
-  # Start with normal POST transaction
39
-  my $tx = $self->tx(POST => $url, @_);
40
-
41
-  # Check for uploads and force multipart if necessary
42
-  my $multipart;
43
-  for my $value (map { ref $_ eq 'ARRAY' ? @$_ : $_ } values %$form) {
44
-    ++$multipart and last if ref $value eq 'HASH';
45
-  }
46
-  my $req     = $tx->req;
47
-  my $headers = $req->headers;
48
-  $headers->content_type('multipart/form-data') if $multipart;
49
-
50
-  # Multipart
51
-  if ((defined $headers->content_type ? $headers->content_type : '') eq 'multipart/form-data') {
52
-    my $parts = $self->_multipart($encoding, $form);
53
-    $req->content(
54
-      Mojo::Content::MultiPart->new(headers => $headers, parts => $parts));
55
-  }
56
-
57
-  # Urlencoded
58
-  else {
59
-    $headers->content_type('application/x-www-form-urlencoded');
60
-    my $p = Mojo::Parameters->new(map { $_ => $form->{$_} } sort keys %$form);
61
-    $p->charset($encoding) if defined $encoding;
62
-    $req->body($p->to_string);
63
-  }
64
-
65
-  return $tx;
66
-}
67
-
68
-sub json {
69
-  my ($self, $url, $data) = (shift, shift, shift);
70
-  my $tx = $self->tx(POST => $url, @_, Mojo::JSON->new->encode($data));
71
-  my $headers = $tx->req->headers;
72
-  $headers->content_type('application/json') unless $headers->content_type;
73
-  return $tx;
74
-}
75
-
76 46
 sub peer {
77 47
   my ($self, $tx) = @_;
78 48
   return $self->_proxy($tx, $self->endpoint($tx));
... ...
@@ -83,14 +53,14 @@ sub proxy_connect {
83 53
 
84 54
   # Already a CONNECT request
85 55
   my $req = $old->req;
86
-  return undef if $req->method eq 'CONNECT';
56
+  return undef if uc $req->method eq 'CONNECT';
87 57
 
88 58
   # No proxy
89 59
   return undef unless my $proxy = $req->proxy;
90 60
 
91 61
   # WebSocket and/or HTTPS
92 62
   my $url = $req->url;
93
-  my $upgrade = lc($req->headers->upgrade || '');
63
+  my $upgrade = lc(defined $req->headers->upgrade ? $req->headers->upgrade : '');
94 64
   return undef unless $upgrade eq 'websocket' || $url->protocol eq 'https';
95 65
 
96 66
   # CONNECT request
... ...
@@ -116,8 +86,8 @@ sub redirect {
116 86
   # Clone request if necessary
117 87
   my $new    = Mojo::Transaction::HTTP->new;
118 88
   my $req    = $old->req;
119
-  my $method = $req->method;
120
-  if (grep { $_ eq $code } 301, 307, 308) {
89
+  my $method = uc $req->method;
90
+  if ($code eq 301 || $code eq 307 || $code eq 308) {
121 91
     return undef unless my $req = $req->clone;
122 92
     $new->req($req);
123 93
     $req->headers->remove('Host')->remove('Cookie')->remove('Referer');
... ...
@@ -140,8 +110,14 @@ sub tx {
140 110
   # Headers
141 111
   $req->headers->from_hash(shift) if ref $_[0] eq 'HASH';
142 112
 
113
+  # Generator
114
+  if (@_ > 1) {
115
+    return $tx unless my $generator = $self->generators->{shift()};
116
+    $self->$generator($tx, @_);
117
+  }
118
+
143 119
   # Body
144
-  $req->body(shift) if @_;
120
+  elsif (@_) { $req->body(shift) }
145 121
 
146 122
   return $tx;
147 123
 }
... ...
@@ -158,11 +134,13 @@ sub websocket {
158 134
   my $self = shift;
159 135
 
160 136
   # New WebSocket transaction
161
-  my $tx    = $self->tx(GET => @_);
162
-  my $req   = $tx->req;
163
-  my $abs   = $req->url->to_abs;
164
-  my $proto = $abs->protocol;
165
-  $req->url($abs->scheme($proto eq 'wss' ? 'https' : 'http')) if $proto;
137
+  my $sub = ref $_[-1] eq 'ARRAY' ? pop : [];
138
+  my $tx = $self->tx(GET => @_);
139
+  my $req = $tx->req;
140
+  $req->headers->sec_websocket_protocol(join ', ', @$sub) if @$sub;
141
+  my $url   = $req->url;
142
+  my $proto = $url->protocol;
143
+  $url->scheme($proto eq 'wss' ? 'https' : 'http') if $proto;
166 144
 
167 145
   # Handshake
168 146
   Mojo::Transaction::WebSocket->new(handshake => $tx)->client_handshake;
... ...
@@ -170,8 +148,48 @@ sub websocket {
170 148
   return $tx;
171 149
 }
172 150
 
151
+sub _form {
152
+  my ($self, $tx, $form, %options) = @_;
153
+
154
+  # Check for uploads and force multipart if necessary
155
+  my $multipart;
156
+  for my $value (map { ref $_ eq 'ARRAY' ? @$_ : $_ } values %$form) {
157
+    ++$multipart and last if ref $value eq 'HASH';
158
+  }
159
+  my $req     = $tx->req;
160
+  my $headers = $req->headers;
161
+  $headers->content_type('multipart/form-data') if $multipart;
162
+
163
+  # Multipart
164
+  if ((defined $headers->content_type ? $headers->content_type : '') eq 'multipart/form-data') {
165
+    my $parts = $self->_multipart($options{charset}, $form);
166
+    $req->content(
167
+      Mojo::Content::MultiPart->new(headers => $headers, parts => $parts));
168
+    return $tx;
169
+  }
170
+
171
+  # Query parameters or urlencoded
172
+  my $p = Mojo::Parameters->new(map { $_ => $form->{$_} } sort keys %$form);
173
+  $p->charset($options{charset}) if defined $options{charset};
174
+  my $method = uc $req->method;
175
+  if ($method eq 'GET' || $method eq 'HEAD') { $req->url->query->merge($p) }
176
+  else {
177
+    $req->body($p->to_string);
178
+    $headers->content_type('application/x-www-form-urlencoded');
179
+  }
180
+  return $tx;
181
+}
182
+
183
+sub _json {
184
+  my ($self, $tx, $data) = @_;
185
+  $tx->req->body(Mojo::JSON->new->encode($data));
186
+  my $headers = $tx->req->headers;
187
+  $headers->content_type('application/json') unless $headers->content_type;
188
+  return $tx;
189
+}
190
+
173 191
 sub _multipart {
174
-  my ($self, $encoding, $form) = @_;
192
+  my ($self, $charset, $form) = @_;
175 193
 
176 194
   my @parts;
177 195
   for my $name (sort keys %$form) {
... ...
@@ -199,18 +217,18 @@ sub _multipart {
199 217
 
200 218
         # Filename and headers
201 219
         $filename = delete $value->{filename} || $name;
202
-        $filename = encode $encoding, $filename if $encoding;
220
+        $filename = encode $charset, $filename if $charset;
203 221
         $headers->from_hash($value);
204 222
       }
205 223
 
206 224
       # Field
207 225
       else {
208
-        $value = encode $encoding, $value if $encoding;
226
+        $value = encode $charset, $value if $charset;
209 227
         $part->asset(Mojo::Asset::Memory->new->add_chunk($value));
210 228
       }
211 229
 
212 230
       # Content-Disposition
213
-      $name = encode $encoding, $name if $encoding;
231
+      $name = encode $charset, $name if $charset;
214 232
       my $disposition = qq{form-data; name="$name"};
215 233
       $disposition .= qq{; filename="$filename"} if $filename;
216 234
       $headers->content_disposition($disposition);
... ...
@@ -245,87 +263,56 @@ Mojo::UserAgent::Transactor - User agent transactor
245 263
 
246 264
   # Simple GET request
247 265
   my $t = Mojo::UserAgent::Transactor->new;
248
-  say $t->tx(GET => 'http://mojolicio.us')->req->to_string;
266
+  say $t->tx(GET => 'http://example.com')->req->to_string;
249 267
 
250 268
   # PATCH request with "Do Not Track" header and content
251
-  say $t->tx(PATCH => 'mojolicio.us' => {DNT => 1} => 'Hi!')->req->to_string;
269
+  say $t->tx(PATCH => 'example.com' => {DNT => 1} => 'Hi!')->req->to_string;
252 270
 
253 271
   # POST request with form data
254
-  say $t->form('http://kraih.com' => {a => [1, 2], b => 3})->req->to_string;
272
+  say $t->tx(POST => 'example.com' => form => {a => 'b'})->req->to_string;
255 273
 
256
-  # POST request with JSON data
257
-  say $t->json('http://kraih.com' => {a => [1, 2], b => 3})->req->to_string;
274
+  # PUT request with JSON data
275
+  say $t->tx(PUT => 'example.com' => json => {a => 'b'})->req->to_string;
258 276
 
259 277
 =head1 DESCRIPTION
260 278
 
261 279
 L<Mojo::UserAgent::Transactor> is the transaction building and manipulation
262 280
 framework used by L<Mojo::UserAgent>.
263 281
 
264
-=head1 METHODS
282
+=head1 ATTRIBUTES
265 283
 
266
-L<Mojo::UserAgent::Transactor> inherits all methods from L<Mojo::Base> and
267
-implements the following new ones.
284
+L<Mojo::UserAgent::Transactor> implements the following attributes.
268 285
 
269
-=head2 endpoint
286
+=head2 generators
270 287
 
271
-  my ($proto, $host, $port) = $t->endpoint(Mojo::Transaction::HTTP->new);
288
+  my $generators = $t->generators;
289
+  $t             = $t->generators({foo => sub {...}});
272 290
 
273
-Actual endpoint for transaction.
291
+Registered content generators.
274 292
 
275
-=head2 form
293
+=head1 METHODS
276 294
 
277
-  my $tx = $t->form('kraih.com' => {a => 'b'});
278
-  my $tx = $t->form('http://kraih.com' => {a => 'b'});
279
-  my $tx = $t->form('http://kraih.com' => {a => [qw(b c d)]});
280
-  my $tx = $t->form('http://kraih.com' => {mytext => {file => '/foo.txt'}});
281
-  my $tx = $t->form('http://kraih.com' => {mytext => {content => 'lalala'}});
282
-  my $tx = $t->form('http://kraih.com' =>
283
-    {mytexts => [{content => 'first'}, {content => 'second'}]});
284
-  my $tx = $t->form('http://kraih.com' => {
285
-    myzip => {
286
-      file     => Mojo::Asset::Memory->new->add_chunk('lalala'),
287
-      filename => 'foo.zip',
288
-      DNT      => 1
289
-    }
290
-  });
291
-  my $tx = $t->form('http://kraih.com' => 'UTF-8' => {a => 'b'});
292
-  my $tx = $t->form('http://kraih.com' => {a => 'b'} => {DNT => 1});
293
-  my $tx = $t->form('http://kraih.com', 'UTF-8', {a => 'b'}, {DNT => 1});
295
+L<Mojo::UserAgent::Transactor> inherits all methods from L<Mojo::Base> and
296
+implements the following new ones.
294 297
 
295
-Versatile L<Mojo::Transaction::HTTP> transaction builder for C<POST> requests
296
-with form data.
298
+=head2 new
297 299
 
298
-  # Multipart upload with filename
299
-  my $tx = $t->form(
300
-    'mojolicio.us' => {fun => {content => 'Hello!', filename => 'test.txt'}});
300
+  my $t = Mojo::UserAgent::Transactor->new;
301 301
 
302
-  # Multipart upload streamed from file
303
-  my $tx = $t->form('mojolicio.us' => {fun => {file => '/etc/passwd'}});
302
+Construct a new transactor and register C<form> and C<json> content
303
+generators.
304 304
 
305
-While the "multipart/form-data" content type will be automatically used
306
-instead of "application/x-www-form-urlencoded" when necessary, you can also
307
-enforce it by setting the header manually.
305
+=head2 add_generator
308 306
 
309
-  # Force multipart
310
-  my $tx = $t->form(
311
-    'http://kraih.com/foo',
312
-    {a => 'b'},
313
-    {'Content-Type' => 'multipart/form-data'}
314
-  );
307
+  $t = $t->add_generator(foo => sub {...});
315 308
 
316
-=head2 json
309
+Register a new content generator.
317 310
 
318
-  my $tx = $t->json('kraih.com' => {a => 'b'});
319
-  my $tx = $t->json('http://kraih.com' => [1, 2, 3]);
320
-  my $tx = $t->json('http://kraih.com' => {a => 'b'} => {DNT => 1});
321
-  my $tx = $t->json('http://kraih.com' => [1, 2, 3] => {DNT => 1});
311
+=head2 endpoint
322 312
 
323
-Versatile L<Mojo::Transaction::HTTP> transaction builder for C<POST> requests
324
-with JSON data.
313
+  my ($proto, $host, $port) = $t->endpoint(Mojo::Transaction::HTTP->new);
325 314
 
326
-  # Change method
327
-  my $tx = $t->json('mojolicio.us/hello', {hello => 'world'});
328
-  $tx->req->method('PATCH');
315
+Actual endpoint for transaction.
329 316
 
330 317
 =head2 peer
331 318
 
... ...
@@ -349,26 +336,73 @@ C<307> or C<308> redirect response if possible.
349 336
 
350 337
 =head2 tx
351 338
 
352
-  my $tx = $t->tx(GET  => 'kraih.com');
353
-  my $tx = $t->tx(POST => 'http://kraih.com');
354
-  my $tx = $t->tx(GET  => 'http://kraih.com' => {DNT => 1});
355
-  my $tx = $t->tx(PUT  => 'http://kraih.com' => 'Hi!');
356
-  my $tx = $t->tx(POST => 'http://kraih.com' => {DNT => 1} => 'Hi!');
339
+  my $tx = $t->tx(GET  => 'example.com');
340
+  my $tx = $t->tx(POST => 'http://example.com');
341
+  my $tx = $t->tx(GET  => 'http://example.com' => {DNT => 1});
342
+  my $tx = $t->tx(PUT  => 'http://example.com' => 'Hi!');
343
+  my $tx = $t->tx(PUT  => 'http://example.com' => form => {a => 'b'});
344
+  my $tx = $t->tx(PUT  => 'http://example.com' => json => {a => 'b'});
345
+  my $tx = $t->tx(POST => 'http://example.com' => {DNT => 1} => 'Hi!');
346
+  my $tx = $t->tx(
347
+    PUT  => 'http://example.com' => {DNT => 1} => form => {a => 'b'});
348
+  my $tx = $t->tx(
349
+    PUT  => 'http://example.com' => {DNT => 1} => json => {a => 'b'});
357 350
 
358 351
 Versatile general purpose L<Mojo::Transaction::HTTP> transaction builder for
359
-requests.
352
+requests, with support for content generators.
360 353
 
361 354
   # Inspect generated request
362
-  say $t->tx(GET => 'mojolicio.us' => {DNT => 1} => 'Bye!')->req->to_string;
355
+  say $t->tx(GET => 'example.com' => {DNT => 1} => 'Bye!')->req->to_string;
363 356
 
364 357
   # Streaming response
365
-  my $tx = $t->tx(GET => 'http://mojolicio.us');
366
-  $tx->res->body(sub { say $_[1] });
358
+  my $tx = $t->tx(GET => 'http://example.com');
359
+  $tx->res->content->unsubscribe('read')->on(read => sub { say $_[1] });
367 360
 
368 361
   # Custom socket
369
-  my $tx = $t->tx(GET => 'http://mojolicio.us');
362
+  my $tx = $t->tx(GET => 'http://example.com');
370 363
   $tx->connection($sock);
371 364
 
365
+  # Generate query parameters
366
+  my $tx = $t->tx(GET => 'http://example.com' => form => {a => 'b'});
367
+
368
+  # Use form generator with custom charset
369
+  my $tx = $t->tx(
370
+    PUT => 'http://example.com' => form => {a => 'b'} => charset => 'UTF-8');
371
+
372
+  # Multiple form values with the same name
373
+  my $tx = $t->tx(PUT => 'http://example.com' => form => {a => [qw(b c d)]});
374
+
375
+  # Multipart upload streamed from file
376
+  my $tx = $t->tx(
377
+    PUT => 'http://example.com' => form => {mytext => {file => '/foo.txt'}});
378
+
379
+  # Multipart upload with in-memory content
380
+  my $tx = $t->tx(
381
+    POST => 'http://example.com' => form => {mytext => {content => 'lala'}});
382
+
383
+  # Upload multiple files with same name
384
+  my $tx = $t->tx(POST => 'http://example.com' =>
385
+    form => {mytext => [{content => 'first'}, {content => 'second'}]});
386
+
387
+  # Customized upload with filename and header
388
+  my $tx = $t->tx(POST => 'http://example.com' => form => {
389
+    myzip => {
390
+      file           => Mojo::Asset::Memory->new->add_chunk('lalala'),
391
+      filename       => 'foo.zip',
392
+      'Content-Type' => 'text/plain'
393
+    }
394
+  });
395
+
396
+The C<form> content generator will automatically use query parameters for
397
+C<GET>/C<HEAD> requests and the "application/x-www-form-urlencoded" content
398
+type for everything else. Both get upgraded automatically to using the
399
+"multipart/form-data" content type when necessary or when the header has been
400
+set manually.
401
+
402
+  # Force "multipart/form-data"
403
+  my $headers = {'Content-Type' => 'multipart/form-data'};
404
+  my $tx = $t->tx(POST => 'example.com' => $headers => form => {a => 'b'});
405
+
372 406
 =head2 upgrade
373 407
 
374 408
   my $tx = $t->upgrade(Mojo::Transaction::HTTP->new);
... ...
@@ -378,8 +412,8 @@ handshake if possible.
378 412
 
379 413
 =head2 websocket
380 414
 
381
-  my $tx = $t->websocket('ws://localhost:3000');
382
-  my $tx = $t->websocket('ws://localhost:3000' => {DNT => 1});
415
+  my $tx = $t->websocket('ws://example.com');
416
+  my $tx = $t->websocket('ws://example.com' => {DNT => 1} => ['v1.proto']);
383 417
 
384 418
 Versatile L<Mojo::Transaction::HTTP> transaction builder for WebSocket
385 419
 handshake requests.
+117 -128
mojo/lib/Mojo/Util.pm
... ...
@@ -1,13 +1,18 @@
1 1
 package Mojo::Util;
2 2
 use Mojo::Base 'Exporter';
3 3
 
4
-use Carp 'croak';
4
+use Carp qw(carp croak);
5 5
 use Digest::MD5 qw(md5 md5_hex);
6 6
 BEGIN {eval {require Digest::SHA; import Digest::SHA qw(sha1 sha1_hex)}}
7 7
 use Encode 'find_encoding';
8 8
 use File::Basename 'dirname';
9 9
 use File::Spec::Functions 'catfile';
10 10
 use MIME::Base64 qw(decode_base64 encode_base64);
11
+use Time::HiRes ();
12
+
13
+# Check for monotonic clock support
14
+use constant MONOTONIC => eval
15
+  '!!Time::HiRes::clock_gettime(Time::HiRes::CLOCK_MONOTONIC())';
11 16
 
12 17
 # Punycode bootstring parameters
13 18
 use constant {
... ...
@@ -23,46 +28,33 @@ use constant {
23 28
 # To update HTML5 entities run this command
24 29
 # perl examples/entities.pl > lib/Mojo/entities.txt
25 30
 my %ENTITIES;
26
-{
27
-  open my $entities, '<', catfile(dirname(__FILE__), 'entities.txt');
28
-  for my $entity (<$entities>) {
29
-    next unless $entity =~ /^(\S+)\s+U\+(\S+)(?:\s+U\+(\S+))?/;
30
-    $ENTITIES{$1} = defined $3 ? (chr(hex $2) . chr(hex $3)) : chr(hex $2);
31
-  }
31
+for my $line (split "\x0a", slurp(catfile dirname(__FILE__), 'entities.txt')) {
32
+  next unless $line =~ /^(\S+)\s+U\+(\S+)(?:\s+U\+(\S+))?/;
33
+  $ENTITIES{$1} = defined $3 ? (chr(hex $2) . chr(hex $3)) : chr(hex $2);
32 34
 }
33 35
 
34
-# DEPRECATED in Rainbow!
35
-my %REVERSE = ("\x{0027}" => '#39;');
36
-$REVERSE{$ENTITIES{$_}} = defined $REVERSE{$ENTITIES{$_}} ? $REVERSE{$ENTITIES{$_}} : $_
37
-  for sort  { @{[$a =~ /[A-Z]/g]} <=> @{[$b =~ /[A-Z]/g]} }
38
-  sort grep {/;/} keys %ENTITIES;
39
-
40 36
 # Encoding cache
41 37
 my %CACHE;
42 38
 
43 39
 our @EXPORT_OK = (
44 40
   qw(b64_decode b64_encode camelize class_to_file class_to_path decamelize),
45
-  qw(decode encode get_line hmac_md5_sum hmac_sha1_sum html_unescape),
46
-  qw(md5_bytes md5_sum monkey_patch punycode_decode punycode_encode quote),
47
-  qw(secure_compare sha1_bytes sha1_sum slurp spurt squish trim unquote),
48
-  qw(url_escape url_unescape xml_escape xor_encode)
41
+  qw(decode deprecated encode get_line hmac_sha1_sum html_unescape md5_bytes),
42
+  qw(md5_sum monkey_patch punycode_decode punycode_encode quote),
43
+  qw(secure_compare sha1_bytes sha1_sum slurp spurt squish steady_time trim),
44
+  qw(unquote url_escape url_unescape xml_escape xor_encode)
49 45
 );
50 46
 
51
-# DEPRECATED in Rainbow!
52
-push @EXPORT_OK, 'html_escape';
53
-
54 47
 sub b64_decode { decode_base64($_[0]) }
55
-
56 48
 sub b64_encode { encode_base64($_[0], $_[1]) }
57 49
 
58 50
 sub camelize {
59
-  my $string = shift;
60
-  return $string if $string =~ /^[A-Z]/;
51
+  my $str = shift;
52
+  return $str if $str =~ /^[A-Z]/;
61 53
 
62 54
   # Camel case words
63 55
   return join '::', map {
64 56
     join '', map { ucfirst lc } split /_/, $_
65
-  } split /-/, $string;
57
+  } split /-/, $str;
66 58
 }
67 59
 
68 60
 sub class_to_file {
... ...
@@ -75,12 +67,12 @@ sub class_to_file {
75 67
 sub class_to_path { join '.', join('/', split /::|'/, shift), 'pm' }
76 68
 
77 69
 sub decamelize {
78
-  my $string = shift;
79
-  return $string if $string !~ /^[A-Z]/;
70
+  my $str = shift;
71
+  return $str if $str !~ /^[A-Z]/;
80 72
 
81 73
   # Module parts
82 74
   my @parts;
83
-  for my $part (split /::/, $string) {
75
+  for my $part (split /::/, $str) {
84 76
 
85 77
     # Snake case words
86 78
     my @words;
... ...
@@ -98,6 +90,11 @@ sub decode {
98 90
   return $bytes;
99 91
 }
100 92
 
93
+sub deprecated {
94
+  local $Carp::CarpLevel = 1;
95
+  $ENV{MOJO_FATAL_DEPRECATIONS} ? croak(@_) : carp(@_);
96
+}
97
+
101 98
 sub encode { _encoding($_[0])->encode("$_[1]") }
102 99
 
103 100
 sub get_line {
... ...
@@ -112,26 +109,22 @@ sub get_line {
112 109
   return $line;
113 110
 }
114 111
 
115
-sub hmac_md5_sum  { _hmac(\&md5,  @_) }
116
-sub hmac_sha1_sum { _hmac(\&sha1, @_) }
117
-
118
-# DEPRECATED in Rainbow!
119
-sub html_escape {
120
-  warn <<EOF;
121
-Mojo::Util->html_escape is DEPRECATED in favor of Mojo::Util->xml_escape!!!
122
-EOF
123
-  my ($string, $pattern) = @_;
124
-  $pattern ||= '^\n\r\t !#$%(-;=?-~';
125
-  return $string unless $string =~ /[^$pattern]/;
126
-  $string =~ s/([$pattern])/_encode($1)/ge;
127
-  return $string;
112
+sub hmac_sha1_sum {
113
+  my ($str, $secret) = @_;
114
+  $secret = $secret ? "$secret" : 'Very insecure!';
115
+  $secret = sha1 $secret if length $secret > 64;
116
+
117
+  my $ipad = $secret ^ (chr(0x36) x 64);
118
+  my $opad = $secret ^ (chr(0x5c) x 64);
119
+  return unpack 'H*', sha1($opad . sha1($ipad . $str));
128 120
 }
129 121
 
130 122
 sub html_unescape {
131
-  my $string = shift;
132
-  $string
123
+  my $str = shift;
124
+  return $str if index($str, '&') == -1;
125
+  $str
133 126
     =~ s/&(?:\#((?:\d{1,7}|x[[:xdigit:]]{1,6}));|(\w+;?))/_decode($1, $2)/ge;
134
-  return $string;
127
+  return $str;
135 128
 }
136 129
 
137 130
 sub md5_bytes { md5(@_) }
... ...
@@ -195,7 +188,7 @@ sub punycode_encode {
195 188
   my @input = map {ord} split //, $output;
196 189
   my @chars = sort grep { $_ >= PC_INITIAL_N } @input;
197 190
 
198
-  # Handle non basic characters
191
+  # Handle non-basic characters
199 192
   $output =~ s/[^\x00-\x7f]+//gs;
200 193
   my $h = my $b = length $output;
201 194
   $output .= "\x2d" if $b > 0;
... ...
@@ -252,9 +245,9 @@ sub punycode_encode {
252 245
 }
253 246
 
254 247
 sub quote {
255
-  my $string = shift;
256
-  $string =~ s/(["\\])/\\$1/g;
257
-  return qq{"$string"};
248
+  my $str = shift;
249
+  $str =~ s/(["\\])/\\$1/g;
250
+  return qq{"$str"};
258 251
 }
259 252
 
260 253
 sub secure_compare {
... ...
@@ -285,49 +278,55 @@ sub spurt {
285 278
 }
286 279
 
287 280
 sub squish {
288
-  my $string = trim(@_);
289
-  $string =~ s/\s+/ /g;
290
-  return $string;
281
+  my $str = trim(@_);
282
+  $str =~ s/\s+/ /g;
283
+  return $str;
284
+}
285
+
286
+sub steady_time () {
287
+  MONOTONIC
288
+    ? Time::HiRes::clock_gettime(Time::HiRes::CLOCK_MONOTONIC())
289
+    : Time::HiRes::time;
291 290
 }
292 291
 
293 292
 sub trim {
294
-  my $string = shift;
295
-  $string =~ s/^\s+|\s+$//g;
296
-  return $string;
293
+  my $str = shift;
294
+  $str =~ s/^\s+|\s+$//g;
295
+  return $str;
297 296
 }
298 297
 
299 298
 sub unquote {
300
-  my $string = shift;
301
-  return $string unless $string =~ s/^"(.*)"$/$1/g;
302
-  $string =~ s/\\\\/\\/g;
303
-  $string =~ s/\\"/"/g;
304
-  return $string;
299
+  my $str = shift;
300
+  return $str unless $str =~ s/^"(.*)"$/$1/g;
301
+  $str =~ s/\\\\/\\/g;
302
+  $str =~ s/\\"/"/g;
303
+  return $str;
305 304
 }
306 305
 
307 306
 sub url_escape {
308
-  my ($string, $pattern) = @_;
307
+  my ($str, $pattern) = @_;
309 308
   $pattern ||= '^A-Za-z0-9\-._~';
310
-  $string =~ s/([$pattern])/sprintf('%%%02X',ord($1))/ge;
311
-  return $string;
309
+  $str =~ s/([$pattern])/sprintf('%%%02X',ord($1))/ge;
310
+  return $str;
312 311
 }
313 312
 
314 313
 sub url_unescape {
315
-  my $string = shift;
316
-  return $string if index($string, '%') == -1;
317
-  $string =~ s/%([[:xdigit:]]{2})/chr(hex($1))/ge;
318
-  return $string;
314
+  my $str = shift;
315
+  return $str if index($str, '%') == -1;
316
+  $str =~ s/%([[:xdigit:]]{2})/chr(hex($1))/ge;
317
+  return $str;
319 318
 }
320 319
 
321 320
 sub xml_escape {
322
-  my $string = shift;
321
+  my $str = shift;
323 322
 
324
-  $string =~ s/&/&amp;/g;
325
-  $string =~ s/</&lt;/g;
326
-  $string =~ s/>/&gt;/g;
327
-  $string =~ s/"/&quot;/g;
328
-  $string =~ s/'/&#39;/g;
323
+  $str =~ s/&/&amp;/g;
324
+  $str =~ s/</&lt;/g;
325
+  $str =~ s/>/&gt;/g;
326
+  $str =~ s/"/&quot;/g;
327
+  $str =~ s/'/&#39;/g;
329 328
 
330
-  return $string;
329
+  return $str;
331 330
 }
332 331
 
333 332
 sub xor_encode {
... ...
@@ -357,42 +356,24 @@ sub _adapt {
357 356
 }
358 357
 
359 358
 sub _decode {
359
+  my ($point, $name) = @_;
360 360
 
361
-  # Numeric
362
-  return substr($_[0], 0, 1) eq 'x' ? chr(hex $_[0]) : chr($_[0]) unless $_[1];
361
+  # Code point
362
+  return chr($point !~ /^x/ ? $point : hex $point) unless defined $name;
363 363
 
364 364
   # Find entity name
365
-  my $rest   = '';
366
-  my $entity = $_[1];
367
-  while (length $entity) {
368
-    return "$ENTITIES{$entity}$rest" if exists $ENTITIES{$entity};
369
-    $rest = chop($entity) . $rest;
365
+  my $rest = '';
366
+  while (length $name) {
367
+    return "$ENTITIES{$name}$rest" if exists $ENTITIES{$name};
368
+    $rest = chop($name) . $rest;
370 369
   }
371
-  return "&$_[1]";
372
-}
373
-
374
-# DEPRECATED in Rainbow!
375
-sub _encode {
376
-  return exists $REVERSE{$_[0]} ? "&$REVERSE{$_[0]}" : "&#@{[ord($_[0])]};";
370
+  return "&$rest";
377 371
 }
378 372
 
379 373
 sub _encoding {
380 374
   $CACHE{$_[0]} = defined $CACHE{$_[0]} ? $CACHE{$_[0]} : defined find_encoding($_[0]) ? find_encoding($_[0]) : croak "Unknown encoding '$_[0]'";
381 375
 }
382 376
 
383
-sub _hmac {
384
-  my ($hash, $string, $secret) = @_;
385
-
386
-  # Secret
387
-  $secret = $secret ? "$secret" : 'Very insecure!';
388
-  $secret = $hash->($secret) if length $secret > 64;
389
-
390
-  # HMAC
391
-  my $ipad = $secret ^ (chr(0x36) x 64);
392
-  my $opad = $secret ^ (chr(0x5c) x 64);
393
-  return unpack 'H*', $hash->($opad . $hash->($ipad . $string));
394
-}
395
-
396 377
 1;
397 378
 
398 379
 =head1 NAME
... ...
@@ -403,8 +384,8 @@ Mojo::Util - Portable utility functions
403 384
 
404 385
   use Mojo::Util qw(b64_encode url_escape url_unescape);
405 386
 
406
-  my $string = 'test=23';
407
-  my $escaped = url_escape $string;
387
+  my $str = 'test=23';
388
+  my $escaped = url_escape $str;
408 389
   say url_unescape $escaped;
409 390
   say b64_encode $escaped, '';
410 391
 
... ...
@@ -418,14 +399,14 @@ L<Mojo::Util> implements the following functions.
418 399
 
419 400
 =head2 b64_decode
420 401
 
421
-  my $string = b64_decode $b64;
402
+  my $str = b64_decode $b64;
422 403
 
423 404
 Base64 decode string.
424 405
 
425 406
 =head2 b64_encode
426 407
 
427
-  my $b64 = b64_encode $string;
428
-  my $b64 = b64_encode $string, "\n";
408
+  my $b64 = b64_encode $str;
409
+  my $b64 = b64_encode $str, "\n";
429 410
 
430 411
 Base64 encode string, the line ending defaults to a newline.
431 412
 
... ...
@@ -485,6 +466,13 @@ Convert camel case string to snake case and replace C<::> with C<->.
485 466
 
486 467
 Decode bytes to characters and return C<undef> if decoding failed.
487 468
 
469
+=head2 deprecated
470
+
471
+  deprecated 'foo is DEPRECATED in favor of bar';
472
+
473
+Warn about deprecated feature from perspective of caller. You can also set the
474
+MOJO_FATAL_DEPRECATIONS environment variable to make them die instead.
475
+
488 476
 =head2 encode
489 477
 
490 478
   my $bytes = encode 'UTF-8', $chars;
... ...
@@ -493,38 +481,32 @@ Encode characters to bytes.
493 481
 
494 482
 =head2 get_line
495 483
 
496
-  my $line = get_line \$string;
484
+  my $line = get_line \$str;
497 485
 
498 486
 Extract whole line from string or return C<undef>. Lines are expected to end
499 487
 with C<0x0d 0x0a> or C<0x0a>.
500 488
 
501
-=head2 hmac_md5_sum
502
-
503
-  my $checksum = hmac_md5_sum $string, 'passw0rd';
504
-
505
-Generate HMAC-MD5 checksum for string.
506
-
507 489
 =head2 hmac_sha1_sum
508 490
 
509
-  my $checksum = hmac_sha1_sum $string, 'passw0rd';
491
+  my $checksum = hmac_sha1_sum $str, 'passw0rd';
510 492
 
511 493
 Generate HMAC-SHA1 checksum for string.
512 494
 
513 495
 =head2 html_unescape
514 496
 
515
-  my $string = html_unescape $escaped;
497
+  my $str = html_unescape $escaped;
516 498
 
517 499
 Unescape all HTML entities in string.
518 500
 
519 501
 =head2 md5_bytes
520 502
 
521
-  my $checksum = md5_bytes $string;
503
+  my $checksum = md5_bytes $str;
522 504
 
523 505
 Generate binary MD5 checksum for string.
524 506
 
525 507
 =head2 md5_sum
526 508
 
527
-  my $checksum = md5_sum $string;
509
+  my $checksum = md5_sum $str;
528 510
 
529 511
 Generate MD5 checksum for string.
530 512
 
... ...
@@ -542,37 +524,37 @@ Monkey patch functions into package.
542 524
 
543 525
 =head2 punycode_decode
544 526
 
545
-  my $string = punycode_decode $punycode;
527
+  my $str = punycode_decode $punycode;
546 528
 
547 529
 Punycode decode string.
548 530
 
549 531
 =head2 punycode_encode
550 532
 
551
-  my $punycode = punycode_encode $string;
533
+  my $punycode = punycode_encode $str;
552 534
 
553 535
 Punycode encode string.
554 536
 
555 537
 =head2 quote
556 538
 
557
-  my $quoted = quote $string;
539
+  my $quoted = quote $str;
558 540
 
559 541
 Quote string.
560 542
 
561 543
 =head2 secure_compare
562 544
 
563
-  my $success = secure_compare $string1, $string2;
545
+  my $success = secure_compare $str1, $str2;
564 546
 
565 547
 Constant time comparison algorithm to prevent timing attacks.
566 548
 
567 549
 =head2 sha1_bytes
568 550
 
569
-  my $checksum = sha1_bytes $string;
551
+  my $checksum = sha1_bytes $str;
570 552
 
571 553
 Generate binary SHA1 checksum for string.
572 554
 
573 555
 =head2 sha1_sum
574 556
 
575
-  my $checksum = sha1_sum $string;
557
+  my $checksum = sha1_sum $str;
576 558
 
577 559
 Generate SHA1 checksum for string.
578 560
 
... ...
@@ -590,46 +572,53 @@ Write all data at once to file.
590 572
 
591 573
 =head2 squish
592 574
 
593
-  my $squished = squish $string;
575
+  my $squished = squish $str;
594 576
 
595 577
 Trim whitespace characters from both ends of string and then change all
596 578
 consecutive groups of whitespace into one space each.
597 579
 
580
+=head2 steady_time
581
+
582
+  my $time = steady_time;
583
+
584
+High resolution time, resilient to time jumps if a monotonic clock is
585
+available through L<Time::HiRes>.
586
+
598 587
 =head2 trim
599 588
 
600
-  my $trimmed = trim $string;
589
+  my $trimmed = trim $str;
601 590
 
602 591
 Trim whitespace characters from both ends of string.
603 592
 
604 593
 =head2 unquote
605 594
 
606
-  my $string = unquote $quoted;
595
+  my $str = unquote $quoted;
607 596
 
608 597
 Unquote string.
609 598
 
610 599
 =head2 url_escape
611 600
 
612
-  my $escaped = url_escape $string;
613
-  my $escaped = url_escape $string, '^A-Za-z0-9\-._~';
601
+  my $escaped = url_escape $str;
602
+  my $escaped = url_escape $str, '^A-Za-z0-9\-._~';
614 603
 
615 604
 Percent encode unsafe characters in string, the pattern used defaults to
616 605
 C<^A-Za-z0-9\-._~>.
617 606
 
618 607
 =head2 url_unescape
619 608
 
620
-  my $string = url_unescape $escaped;
609
+  my $str = url_unescape $escaped;
621 610
 
622 611
 Decode percent encoded characters in string.
623 612
 
624 613
 =head2 xml_escape
625 614
 
626
-  my $escaped = xml_escape $string;
615
+  my $escaped = xml_escape $str;
627 616
 
628 617
 Escape unsafe characters C<&>, C<E<lt>>, C<E<gt>>, C<"> and C<'> in string.
629 618
 
630 619
 =head2 xor_encode
631 620
 
632
-  my $encoded = xor_encode $string, $key;
621
+  my $encoded = xor_encode $str, $key;
633 622
 
634 623
 XOR encode string with variable length key.
635 624
 
+61 -52
mojo/lib/Mojolicious.pm
... ...
@@ -14,6 +14,7 @@ use Mojolicious::Sessions;
14 14
 use Mojolicious::Static;
15 15
 use Mojolicious::Types;
16 16
 use Scalar::Util qw(blessed weaken);
17
+use Time::HiRes 'gettimeofday';
17 18
 
18 19
 has commands => sub {
19 20
   my $commands = Mojolicious::Commands->new(app => shift);
... ...
@@ -21,7 +22,7 @@ has commands => sub {
21 22
   return $commands;
22 23
 };
23 24
 has controller_class => 'Mojolicious::Controller';
24
-has mode => sub { $ENV{MOJO_MODE} || 'development' };
25
+has mode => sub { $ENV{MOJO_MODE} || $ENV{PLACK_ENV} || 'development' };
25 26
 has moniker  => sub { decamelize ref shift };
26 27
 has plugins  => sub { Mojolicious::Plugins->new };
27 28
 has renderer => sub { Mojolicious::Renderer->new };
... ...
@@ -32,29 +33,26 @@ has secret   => sub {
32 33
   # Warn developers about insecure default
33 34
   $self->log->debug('Your secret passphrase needs to be changed!!!');
34 35
 
35
-  # Default to application name
36
-  return ref $self;
36
+  # Default to moniker
37
+  return $self->moniker;
37 38
 };
38 39
 has sessions => sub { Mojolicious::Sessions->new };
39 40
 has static   => sub { Mojolicious::Static->new };
40 41
 has types    => sub { Mojolicious::Types->new };
41 42
 
42
-our $CODENAME = 'Rainbow';
43
-our $VERSION  = '3.84';
43
+our $CODENAME = 'Top Hat';
44
+our $VERSION  = '4.07';
44 45
 
45 46
 sub AUTOLOAD {
46 47
   my $self = shift;
47 48
 
48
-  # Method
49 49
   my ($package, $method) = our $AUTOLOAD =~ /^([\w:]+)::(\w+)$/;
50 50
   croak "Undefined subroutine &${package}::$method called"
51 51
     unless blessed $self && $self->isa(__PACKAGE__);
52 52
 
53
-  # Check for helper
53
+  # Call helper with fresh controller
54 54
   croak qq{Can't locate object method "$method" via package "$package"}
55 55
     unless my $helper = $self->renderer->helpers->{$method};
56
-
57
-  # Call helper with fresh controller
58 56
   return $self->controller_class->new(app => $self)->$helper(@_);
59 57
 }
60 58
 
... ...
@@ -72,18 +70,18 @@ sub new {
72 70
 
73 71
   # Hide controller attributes/methods and "handler"
74 72
   $r->hide(qw(AUTOLOAD DESTROY app cookie finish flash handler on param));
75
-  $r->hide(qw(redirect_to render render_data render_exception render_json));
76
-  $r->hide(qw(render_not_found render_partial render_static render_text));
77
-  $r->hide(qw(rendered req res respond_to send session signed_cookie stash));
78
-  $r->hide(qw(tx ua url_for write write_chunk));
73
+  $r->hide(qw(redirect_to render render_exception render_maybe));
74
+  $r->hide(qw(render_not_found render_static rendered req res respond_to));
75
+  $r->hide(qw(send session signed_cookie stash tx ua url_for write));
76
+  $r->hide('write_chunk');
79 77
 
80 78
   # Check if we have a log directory
81 79
   my $mode = $self->mode;
82 80
   $self->log->path($home->rel_file("log/$mode.log"))
83 81
     if -w $home->rel_file('log');
84 82
 
85
-  $self->plugin($_) for qw(HeaderCondition DefaultHelpers TagHelpers);
86
-  $self->plugin($_) for qw(EPLRenderer EPRenderer RequestTimer PoweredBy);
83
+  $self->plugin($_)
84
+    for qw(HeaderCondition DefaultHelpers TagHelpers EPLRenderer EPRenderer);
87 85
 
88 86
   # Exception handling should be first in chain
89 87
   $self->hook(around_dispatch => \&_exception);
... ...
@@ -112,7 +110,7 @@ sub dispatch {
112 110
 
113 111
   # Prepare transaction
114 112
   my $tx = $c->tx;
115
-  $c->res->code(undef) if $tx->is_websocket;
113
+  $tx->res->code(undef) if $tx->is_websocket;
116 114
   $self->sessions->load($c);
117 115
   my $plugins = $self->plugins->emit_hook(before_dispatch => $c);
118 116
 
... ...
@@ -120,11 +118,14 @@ sub dispatch {
120 118
   $self->static->dispatch($c) and $plugins->emit_hook(after_static => $c)
121 119
     unless $tx->res->code;
122 120
 
123
-  # DEPRECATED in Rainbow!
124
-  if ($plugins->has_subscribers('after_static_dispatch')) {
125
-    warn <<EOF and $plugins->emit_hook_reverse(after_static_dispatch => $c);
126
-after_static_dispatch hook is DEPRECATED in favor of before_routes!!!
127
-EOF
121
+  # Start timer (ignore static files)
122
+  my $stash = $c->stash;
123
+  unless ($stash->{'mojo.static'} || $stash->{'mojo.started'}) {
124
+    my $req    = $c->req;
125
+    my $method = $req->method;
126
+    my $path   = $req->url->path->to_abs_string;
127
+    $self->log->debug(qq{$method "$path".});
128
+    $stash->{'mojo.started'} = [gettimeofday];
128 129
   }
129 130
 
130 131
   # Routes
... ...
@@ -157,11 +158,7 @@ sub handler {
157 158
     unless $self->{dispatch};
158 159
 
159 160
   # Process with chain
160
-  unless (eval { $self->plugins->emit_chain(around_dispatch => $c) }) {
161
-    $self->log->fatal("Processing request failed: $@");
162
-    $tx->res->code(500);
163
-    $tx->resume;
164
-  }
161
+  $self->plugins->emit_chain(around_dispatch => $c);
165 162
 
166 163
   # Delayed response
167 164
   $self->log->debug('Nothing has been rendered, expecting delayed response.')
... ...
@@ -255,10 +252,11 @@ L<Mojolicious::Controller>.
255 252
   my $mode = $app->mode;
256 253
   $app     = $app->mode('production');
257 254
 
258
-The operating mode for your application, defaults to the value of the
259
-C<MOJO_MODE> environment variable or C<development>. You can also add per
260
-mode logic to your application by defining methods named C<${mode}_mode> in
261
-the application class, which will be called right before C<startup>.
255
+The operating mode for your application, defaults to a value from the
256
+MOJO_MODE and PLACK_ENV environment variables or C<development>. You can also
257
+add per mode logic to your application by defining methods named
258
+C<${mode}_mode> in the application class, which will be called right before
259
+C<startup>.
262 260
 
263 261
   sub development_mode {
264 262
     my $self = shift;
... ...
@@ -332,9 +330,9 @@ startup method to define the url endpoints for your application.
332 330
   $app       = $app->secret('passw0rd');
333 331
 
334 332
 A secret passphrase used for signed cookies and the like, defaults to the
335
-application name which is not very secure, so you should change it!!! As long
336
-as you are using the insecure default there will be debug messages in the log
337
-file reminding you to change your passphrase.
333
+C<moniker> of this application, which is not very secure, so you should change
334
+it!!! As long as you are using the insecure default there will be debug
335
+messages in the log file reminding you to change your passphrase.
338 336
 
339 337
 =head2 sessions
340 338
 
... ...
@@ -346,6 +344,9 @@ object. You can usually leave this alone, see
346 344
 L<Mojolicious::Controller/"session"> for more information about working with
347 345
 session data.
348 346
 
347
+  # Change name of cookie used for all sessions
348
+  $app->sessions->cookie_name('mysession');
349
+
349 350
 =head2 static
350 351
 
351 352
   my $static = $app->static;
... ...
@@ -368,6 +369,7 @@ L<Mojolicious::Static> object.
368 369
 Responsible for connecting file extensions with MIME types, defaults to a
369 370
 L<Mojolicious::Types> object.
370 371
 
372
+  # Add custom MIME type
371 373
   $app->types->type(twt => 'text/tweet');
372 374
 
373 375
 =head1 METHODS
... ...
@@ -382,7 +384,8 @@ new ones.
382 384
 Construct a new L<Mojolicious> application, calling C<${mode}_mode> and
383 385
 C<startup> in the process. Will automatically detect your home directory and
384 386
 set up logging based on your current operating mode. Also sets up the
385
-renderer, static file server and a default set of plugins.
387
+renderer, static file server, a default set of plugins and an
388
+C<around_dispatch> hook with the default exception handling.
386 389
 
387 390
 =head2 build_tx
388 391
 
... ...
@@ -393,18 +396,16 @@ object.
393 396
 
394 397
 =head2 defaults
395 398
 
396
-  my $defaults = $app->defaults;
397
-  my $foo      = $app->defaults('foo');
398
-  $app         = $app->defaults({foo => 'bar'});
399
-  $app         = $app->defaults(foo => 'bar');
399
+  my $hash = $app->defaults;
400
+  my $foo  = $app->defaults('foo');
401
+  $app     = $app->defaults({foo => 'bar'});
402
+  $app     = $app->defaults(foo => 'bar');
400 403
 
401 404
 Default values for L<Mojolicious::Controller/"stash">, assigned for every new
402 405
 request.
403 406
 
404
-  # Manipulate defaults
405
-  $app->defaults->{foo} = 'bar';
406
-  my $foo = $app->defaults->{foo};
407
-  delete $app->defaults->{foo};
407
+  # Remove value
408
+  my $foo = delete $app->defaults->{foo};
408 409
 
409 410
 =head2 dispatch
410 411
 
... ...
@@ -449,7 +450,7 @@ requests indiscriminately.
449 450
   # Dispatchers will not run if there's already a response code defined
450 451
   $app->hook(before_dispatch => sub {
451 452
     my $c = shift;
452
-    $c->render(text => 'Skipped dispatchers!')
453
+    $c->render(text => 'Skipped static file server and router!')
453 454
       if $c->req->url->path->to_route =~ /do_not_dispatch/;
454 455
   });
455 456
 
... ...
@@ -486,7 +487,8 @@ Very useful for rewriting incoming requests and other preprocessing tasks.
486 487
 
487 488
 =item after_static
488 489
 
489
-Emitted after the static file server decided to serve a static file.
490
+Emitted after a static file response has been generated by the static file
491
+server.
490 492
 
491 493
   $app->hook(after_static => sub {
492 494
     my $c = shift;
... ...
@@ -498,8 +500,8 @@ controller object)
498 500
 
499 501
 =item before_routes
500 502
 
501
-Emitted after the static file server decided if a static file should be served
502
-and before the router starts its work.
503
+Emitted after the static file server determined if a static file should be
504
+served and before the router starts its work.
503 505
 
504 506
   $app->hook(before_routes => sub {
505 507
     my $c = shift;
... ...
@@ -623,13 +625,13 @@ L<http://creativecommons.org/licenses/by-sa/3.0>.
623 625
 
624 626
 =head2 jQuery
625 627
 
626
-  Copyright (C) 2005, 2012 jQuery Foundation, Inc.
628
+  Copyright (C) 2005, 2013 jQuery Foundation, Inc.
627 629
 
628 630
 Licensed under the MIT License, L<http://creativecommons.org/licenses/MIT>.
629 631
 
630 632
 =head2 prettify.js
631 633
 
632
-  Copyright (C) 2006, Google Inc.
634
+  Copyright (C) 2006, 2013 Google Inc.
633 635
 
634 636
 Licensed under the Apache License, Version 2.0
635 637
 L<http://www.apache.org/licenses/LICENSE-2.0>.
... ...
@@ -639,6 +641,8 @@ L<http://www.apache.org/licenses/LICENSE-2.0>.
639 641
 Every major release of L<Mojolicious> has a code name, these are the ones that
640 642
 have been used in the past.
641 643
 
644
+4.0, C<Top Hat> (u1F3A9)
645
+
642 646
 3.0, C<Rainbow> (u1F308)
643 647
 
644 648
 2.0, C<Leaf Fluttering In Wind> (u1F343)
... ...
@@ -657,6 +661,11 @@ have been used in the past.
657 661
 
658 662
 0.999920, C<Snowman> (u2603)
659 663
 
664
+=head1 SPONSORS
665
+
666
+Some of the work on this distribution has been sponsored by
667
+L<The Perl Foundation|http://www.perlfoundation.org>, thank you!
668
+
660 669
 =head1 PROJECT FOUNDER
661 670
 
662 671
 Sebastian Riedel, C<sri@cpan.org>
... ...
@@ -671,6 +680,8 @@ Abhijit Menon-Sen, C<ams@cpan.org>
671 680
 
672 681
 Glen Hinkle, C<tempire@cpan.org>
673 682
 
683
+Joel Berger, C<jberger@cpan.org>
684
+
674 685
 Marcus Ramberg, C<mramberg@cpan.org>
675 686
 
676 687
 =back
... ...
@@ -753,6 +764,8 @@ Dmitriy Shalashov
753 764
 
754 765
 Dmitry Konstantinov
755 766
 
767
+Dominik Jarmulowicz
768
+
756 769
 Dominique Dumont
757 770
 
758 771
 Douglas Christopher Wilson
... ...
@@ -779,8 +792,6 @@ Jaroslav Muhin
779 792
 
780 793
 Jesse Vincent
781 794
 
782
-Joel Berger
783
-
784 795
 Johannes Plunien
785 796
 
786 797
 John Kingsley
... ...
@@ -877,8 +888,6 @@ Tatsuhiko Miyagawa
877 888
 
878 889
 Terrence Brannon
879 890
 
880
-The Perl Foundation
881
-
882 891
 Tomas Znamenacek
883 892
 
884 893
 Ulrich Habel
+2 -2
mojo/lib/Mojolicious/Command/cpanify.pm
... ...
@@ -24,8 +24,8 @@ sub run {
24 24
     'u|user=s'     => \(my $user     = '');
25 25
   die $self->usage unless my $file = shift @args;
26 26
 
27
-  my $tx = Mojo::UserAgent->new->detect_proxy->post_form(
28
-    "https://$user:$password\@pause.perl.org/pause/authenquery" => {
27
+  my $tx = Mojo::UserAgent->new->detect_proxy->post(
28
+    "https://$user:$password\@pause.perl.org/pause/authenquery" => form => {
29 29
       HIDDENNAME                        => $user,
30 30
       CAN_MULTIPART                     => 1,
31 31
       pause99_add_uri_upload            => basename($file),
+1 -1
mojo/lib/Mojolicious/Command/generate/app.pm
... ...
@@ -57,7 +57,7 @@ use strict;
57 57
 use warnings;
58 58
 
59 59
 use FindBin;
60
-use lib "$FindBin::Bin/../lib";
60
+BEGIN { unshift @INC, "$FindBin::Bin/../lib" }
61 61
 
62 62
 # Start command line interface for application
63 63
 require Mojolicious::Commands;
+1 -1
mojo/lib/Mojolicious/Command/generate/plugin.pm
... ...
@@ -86,7 +86,7 @@ plugin '<%= $name %>';
86 86
 
87 87
 get '/' => sub {
88 88
   my $self = shift;
89
-  $self->render_text('Hello Mojo!');
89
+  $self->render(text => 'Hello Mojo!');
90 90
 };
91 91
 
92 92
 my $t = Test::Mojo->new;
+29 -52
mojo/lib/Mojolicious/Command/get.pm
... ...
@@ -8,6 +8,7 @@ use Mojo::JSON;
8 8
 use Mojo::JSON::Pointer;
9 9
 use Mojo::UserAgent;
10 10
 use Mojo::Util qw(decode encode);
11
+use Scalar::Util 'weaken';
11 12
 
12 13
 has description => "Perform HTTP request.\n";
13 14
 has usage       => <<"EOF";
... ...
@@ -27,7 +28,7 @@ usage: $0 get [OPTIONS] URL [SELECTOR|JSON-POINTER] [COMMANDS]
27 28
 
28 29
 These options are available:
29 30
   -C, --charset <charset>     Charset of HTML/XML content, defaults to auto
30
-                              detection or "UTF-8".
31
+                              detection.
31 32
   -c, --content <content>     Content to send with request.
32 33
   -H, --header <name:value>   Additional HTTP header.
33 34
   -M, --method <method>       HTTP method to use, defaults to "GET".
... ...
@@ -46,59 +47,38 @@ sub run {
46 47
     'r|redirect'  => \my $redirect,
47 48
     'v|verbose'   => \my $verbose;
48 49
 
49
-  die $self->usage unless my $url = decode 'UTF-8', do {my $tmp = shift @args; defined $tmp ? $tmp : ''};
50
+  @args = map { decode 'UTF-8', $_ } @args;
51
+  die $self->usage unless my $url = shift @args;
50 52
   my $selector = shift @args;
51 53
 
52 54
   # Parse header pairs
53 55
   my %headers;
54 56
   /^\s*([^:]+)\s*:\s*(.+)$/ and $headers{$1} = $2 for @headers;
55 57
 
56
-  # Use global event loop singleton
58
+  # Detect proxy for absolute URLs
57 59
   my $ua = Mojo::UserAgent->new(ioloop => Mojo::IOLoop->singleton);
60
+  $url !~ m!^/! ? $ua->detect_proxy : $ua->app($self->app);
58 61
   $ua->max_redirects(10) if $redirect;
59 62
 
60
-  # Detect proxy for absolute URLs
61
-  if   ($url !~ m!/!) { $ua->detect_proxy }
62
-  else                { $ua->app($self->app) }
63
-
64
-  # Do the real work with "start" event
65
-  my $v = my $buffer = '';
63
+  my $buffer = '';
66 64
   $ua->on(
67 65
     start => sub {
68
-      my $tx = pop;
69
-
70
-      # Verbose callback
71
-      my $v  = $verbose;
72
-      my $cb = sub {
73
-        my $res = shift;
74
-
75
-        # Wait for headers
76
-        return unless $v && $res->headers->is_finished;
77
-        $v = undef;
78
-
79
-        # Show request
80
-        my $req         = $tx->req;
81
-        my $startline   = $req->build_start_line;
82
-        my $req_headers = $req->build_headers;
83
-        warn "$startline$req_headers";
84
-
85
-        # Show response
86
-        my $version     = $res->version;
87
-        my $code        = $res->code;
88
-        my $msg         = $res->message;
89
-        my $res_headers = $res->headers->to_string;
90
-        warn "HTTP/$version $code $msg\n$res_headers\n\n";
91
-      };
92
-      $tx->res->on(progress => $cb);
93
-
94
-      # Stream content
95
-      $tx->res->body(
96
-        sub {
97
-          $cb->(my $res = shift);
98
-
99
-          # Ignore intermediate content
100
-          return if $redirect && $res->is_status_class(300);
101
-          $selector ? ($buffer .= pop) : print(pop);
66
+      my ($ua, $tx) = @_;
67
+
68
+      # Verbose
69
+      weaken $tx;
70
+      $tx->res->content->on(
71
+        body => sub {
72
+          warn $tx->req->$_ for qw(build_start_line build_headers);
73
+          warn $tx->res->$_ for qw(build_start_line build_headers);
74
+        }
75
+      ) if $verbose;
76
+
77
+      # Stream content (ignore redirects)
78
+      $tx->res->content->unsubscribe('read')->on(
79
+        read => sub {
80
+          return if $redirect && $tx->res->is_status_class(300);
81
+          defined $selector ? ($buffer .= pop) : print pop;
102 82
         }
103 83
       );
104 84
     }
... ...
@@ -113,8 +93,8 @@ sub run {
113 93
   warn qq{Problem loading URL "$url". ($err)\n} if $err && !$code;
114 94
 
115 95
   # JSON Pointer
116
-  return unless $selector;
117
-  my $type = $tx->res->headers->content_type || '';
96
+  return unless defined $selector;
97
+  my $type = defined $tx->res->headers->content_type ? $tx->res->headers->content_type : '';
118 98
   return _json($buffer, $selector) if $type =~ /json/i;
119 99
 
120 100
   # Selector
... ...
@@ -126,19 +106,16 @@ sub _json {
126 106
   return unless my $data = $json->decode(shift);
127 107
   return unless defined($data = Mojo::JSON::Pointer->new->get($data, shift));
128 108
   return _say($data) unless ref $data eq 'HASH' || ref $data eq 'ARRAY';
129
-  say($json->encode($data));
109
+  say $json->encode($data);
130 110
 }
131 111
 
132
-sub _say {
133
-  return unless length(my $value = shift);
134
-  say encode('UTF-8', $value);
135
-}
112
+sub _say { say encode('UTF-8', $_[0]) if length $_[0] }
136 113
 
137 114
 sub _select {
138 115
   my ($buffer, $selector, $charset, @args) = @_;
139 116
 
140
-  my $dom     = Mojo::DOM->new->charset($charset)->parse($buffer);
141
-  my $results = $dom->find($selector);
117
+  $buffer = do {my $tmp = decode($charset, $buffer); defined $tmp ? $tmp : $buffer} if $charset;
118
+  my $results = Mojo::DOM->new($buffer)->find($selector);
142 119
 
143 120
   my $finished;
144 121
   while (defined(my $command = shift @args)) {
+3 -3
mojo/lib/Mojolicious/Command/prefork.pm
... ...
@@ -25,7 +25,7 @@ These options are available:
25 25
                                        value of MOJO_INACTIVITY_TIMEOUT or 15.
26 26
       --lock-file <path>               Path to lock file, defaults to a random
27 27
                                        file.
28
-  -L, --lock-timeout <seconds>         Lock timeout, defaults to 0.5.
28
+  -L, --lock-timeout <seconds>         Lock timeout, defaults to 1.
29 29
   -l, --listen <location>              One or more locations you want to
30 30
                                        listen on, defaults to the value of
31 31
                                        MOJO_LISTEN or "http://*:3000".
... ...
@@ -48,7 +48,7 @@ sub run {
48 48
   my $prefork = Mojo::Server::Prefork->new(app => $self->app);
49 49
   GetOptionsFromArray \@args,
50 50
     'A|accepts=i'           => sub { $prefork->accepts($_[1]) },
51
-    'a|accept-interval=i'   => sub { $prefork->accept_interval($_[1]) },
51
+    'a|accept-interval=f'   => sub { $prefork->accept_interval($_[1]) },
52 52
     'b|backlog=i'           => sub { $prefork->backlog($_[1]) },
53 53
     'c|clients=i'           => sub { $prefork->max_clients($_[1]) },
54 54
     'G|graceful-timeout=i'  => sub { $prefork->graceful_timeout($_[1]) },
... ...
@@ -57,7 +57,7 @@ sub run {
57 57
     'H|heartbeat-timeout=i' => sub { $prefork->heartbeat_timeout($_[1]) },
58 58
     'i|inactivity=i'        => sub { $prefork->inactivity_timeout($_[1]) },
59 59
     'lock-file=s'           => sub { $prefork->lock_file($_[1]) },
60
-    'L|lock-timeout=i'      => sub { $prefork->lock_timeout($_[1]) },
60
+    'L|lock-timeout=f'      => sub { $prefork->lock_timeout($_[1]) },
61 61
     'l|listen=s'     => \my @listen,
62 62
     'multi-accept=i' => sub { $prefork->multi_accept($_[1]) },
63 63
     'P|pid-file=s'   => sub { $prefork->pid_file($_[1]) },
+24 -39
mojo/lib/Mojolicious/Command/routes.pm
... ...
@@ -3,6 +3,7 @@ use Mojo::Base 'Mojolicious::Command';
3 3
 
4 4
 use MojoLegacy::re 'regexp_pattern';
5 5
 use Getopt::Long qw(GetOptionsFromArray :config no_auto_abbrev no_ignore_case);
6
+use Mojo::Util 'encode';
6 7
 
7 8
 has description => "Show available routes.\n";
8 9
 has usage       => <<"EOF";
... ...
@@ -25,67 +26,51 @@ sub run {
25 26
 sub _draw {
26 27
   my ($self, $routes, $verbose) = @_;
27 28
 
28
-  # Calculate column widths
29
-  my @length = (0, 0, 0);
29
+  my @table = (0, 0, 0);
30 30
   for my $node (@$routes) {
31 31
 
32
-    # Pattern
33
-    my $len = length $node->[0];
34
-    $length[0] = $len if $len > $length[0];
35
-
36 32
     # Methods
37
-    unless (defined $node->[1]->via) { $len = length '*' }
38
-    else { $len = length(join ',', @{$node->[1]->via}) }
39
-    $length[1] = $len if $len > $length[1];
33
+    my $via = $node->[0]->via;
34
+    $node->[2] = !$via ? '*' : uc join ',', @$via;
40 35
 
41 36
     # Name
42
-    $len = length $node->[1]->name;
43
-    $len += 2 if $node->[1]->has_custom_name;
44
-    $length[2] = $len if $len > $length[2];
37
+    my $name = $node->[0]->name;
38
+    $node->[3] = $node->[0]->has_custom_name ? qq{"$name"} : $name;
39
+
40
+    # Check column width
41
+    $table[$_] = _max($table[$_], length $node->[$_ + 1]) for 0 .. 2;
45 42
   }
46 43
 
47
-  # Draw all routes
48 44
   for my $node (@$routes) {
49
-    my @parts;
50
-
51
-    # Pattern
52
-    push @parts, $node->[0];
53
-    $parts[-1] .= ' ' x ($length[0] - length $parts[-1]);
54
-
55
-    # Methods
56
-    my $methods;
57
-    unless (defined $node->[1]->via) { $methods = '*' }
58
-    else { $methods = uc join ',', @{$node->[1]->via} }
59
-    push @parts, $methods . ' ' x ($length[1] - length $methods);
45
+    my @parts = map { _padding($node->[$_ + 1], $table[$_]) } 0 .. 2;
60 46
 
61
-    # Name
62
-    my $name = $node->[1]->name;
63
-    $name = qq{"$name"} if $node->[1]->has_custom_name;
64
-    push @parts, $name . ' ' x ($length[2] - length $name);
65
-
66
-    # Regex
67
-    my $pattern = $node->[1]->pattern;
68
-    $pattern->match('/', $node->[1]->is_endpoint);
47
+    # Regex (verbose)
48
+    my $pattern = $node->[0]->pattern;
49
+    $pattern->match('/', $node->[0]->is_endpoint);
69 50
     my $regex = (regexp_pattern $pattern->regex)[0];
70
-    my $format = (regexp_pattern $pattern->format_regex || '')[0];
51
+    my $format = (regexp_pattern($pattern->format_regex || ''))[0];
71 52
     my $optional
72 53
       = !$pattern->constraints->{format} || $pattern->defaults->{format};
73
-    $format .= '?' if $format && $optional;
74
-    push @parts, $format ? "$regex$format" : $regex if $verbose;
54
+    $regex .= $optional ? "(?:$format)?" : $format if $format;
55
+    push @parts, $regex if $verbose;
75 56
 
76
-    say join('  ', @parts);
57
+    say encode('UTF-8', join('  ', @parts));
77 58
   }
78 59
 }
79 60
 
61
+sub _max { $_[1] > $_[0] ? $_[1] : $_[0] }
62
+
63
+sub _padding { $_[0] . ' ' x ($_[1] - length $_[0]) }
64
+
80 65
 sub _walk {
81
-  my ($self, $node, $depth, $routes) = @_;
66
+  my ($self, $route, $depth, $routes) = @_;
82 67
 
83 68
   my $prefix = '';
84 69
   if (my $i = $depth * 2) { $prefix .= ' ' x $i . '+' }
85
-  push @$routes, [$prefix . ($node->pattern->pattern || '/'), $node];
70
+  push @$routes, [$route, $prefix . ($route->pattern->pattern || '/')];
86 71
 
87 72
   $depth++;
88
-  $self->_walk($_, $depth, $routes) for @{$node->children};
73
+  $self->_walk($_, $depth, $routes) for @{$route->children};
89 74
   $depth--;
90 75
 }
91 76
 
+1 -1
mojo/lib/Mojolicious/Command/test.pm
... ...
@@ -31,7 +31,7 @@ sub run {
31 31
     die "Can't find test directory.\n" unless -d $path;
32 32
 
33 33
     my $home = Mojo::Home->new($path);
34
-    /\.t$/ and push(@args, $home->rel_file($_)) for @{$home->list_files};
34
+    /\.t$/ and push @args, $home->rel_file($_) for @{$home->list_files};
35 35
     say "Running tests from '", realpath($path), "'.";
36 36
   }
37 37
 
+3 -3
mojo/lib/Mojolicious/Command/version.pm
... ...
@@ -23,9 +23,9 @@ CORE
23 23
   Mojolicious ($Mojolicious::VERSION, $Mojolicious::CODENAME)
24 24
 
25 25
 OPTIONAL
26
-  EV              ($ev)
27
-  IO::Socket::IP  ($ipv6)
28
-  IO::Socket::SSL ($tls)
26
+  EV 4.0+               ($ev)
27
+  IO::Socket::IP 0.16+  ($ipv6)
28
+  IO::Socket::SSL 1.75+ ($tls)
29 29
 
30 30
 EOF
31 31
 
+4 -15
mojo/lib/Mojolicious/Commands.pm
... ...
@@ -11,8 +11,8 @@ These options are available for all commands:
11 11
     -h, --help          Get more information on a specific command.
12 12
         --home <path>   Path to your applications home directory, defaults to
13 13
                         the value of MOJO_HOME or auto detection.
14
-    -m, --mode <name>   Run mode of your application, defaults to the value
15
-                        of MOJO_MODE or "development".
14
+    -m, --mode <name>   Run mode of your application, defaults to the value of
15
+                        MOJO_MODE/PLACK_ENV or "development".
16 16
 
17 17
 See '$0 help COMMAND' for more information on a specific command.
18 18
 EOF
... ...
@@ -103,17 +103,6 @@ sub run {
103 103
   return print $self->hint;
104 104
 }
105 105
 
106
-# DEPRECATED in Rainbow!
107
-sub start {
108
-  warn <<EOF;
109
-Mojolicious::Commands->start is DEPRECATED in favor of
110
-Mojolicious::Commands->start_app!!!
111
-EOF
112
-  my $self = shift;
113
-  return $self->start_app($ENV{MOJO_APP} => @_) if $ENV{MOJO_APP};
114
-  return $self->new->app->start(@_);
115
-}
116
-
117 106
 sub start_app {
118 107
   my $self = shift;
119 108
   return Mojo::Server->new->build_app(shift)->start(@_);
... ...
@@ -179,7 +168,7 @@ Upload files to CPAN.
179 168
 
180 169
   $ ./myapp.pl daemon
181 170
 
182
-Start application with standalone HTTP and WebSocket server server.
171
+Start application with standalone HTTP and WebSocket server.
183 172
 
184 173
 =head2 eval
185 174
 
... ...
@@ -320,7 +309,7 @@ Try to detect environment.
320 309
   $commands->run(@ARGV);
321 310
 
322 311
 Load and run commands. Automatic deployment environment detection can be
323
-disabled with the C<MOJO_NO_DETECT> environment variable.
312
+disabled with the MOJO_NO_DETECT environment variable.
324 313
 
325 314
 =head2 start_app
326 315
 
+106 -154
mojo/lib/Mojolicious/Controller.pm
... ...
@@ -4,7 +4,6 @@ use Mojo::Base -base;
4 4
 # No imports, for security reasons!
5 5
 use Carp ();
6 6
 use Mojo::ByteStream;
7
-use Mojo::Cookie::Response;
8 7
 use Mojo::Exception;
9 8
 use Mojo::Transaction::HTTP;
10 9
 use Mojo::URL;
... ...
@@ -12,11 +11,11 @@ use Mojo::Util;
12 11
 use Mojolicious;
13 12
 use Mojolicious::Routes::Match;
14 13
 use Scalar::Util ();
14
+use Time::HiRes  ();
15 15
 
16 16
 has app => sub { Mojolicious->new };
17
-has match => sub {
18
-  Mojolicious::Routes::Match->new(GET => '/')->root(shift->app->routes);
19
-};
17
+has match =>
18
+  sub { Mojolicious::Routes::Match->new(root => shift->app->routes) };
20 19
 has tx => sub { Mojo::Transaction::HTTP->new };
21 20
 
22 21
 # Reserved stash values
... ...
@@ -28,12 +27,11 @@ my %RESERVED = map { $_ => 1 } (
28 27
 sub AUTOLOAD {
29 28
   my $self = shift;
30 29
 
31
-  # Method
32 30
   my ($package, $method) = our $AUTOLOAD =~ /^([\w:]+)::(\w+)$/;
33 31
   Carp::croak "Undefined subroutine &${package}::$method called"
34 32
     unless Scalar::Util::blessed $self && $self->isa(__PACKAGE__);
35 33
 
36
-  # Call helper
34
+  # Call helper with current controller
37 35
   Carp::croak qq{Can't locate object method "$method" via package "$package"}
38 36
     unless my $helper = $self->app->renderer->helpers->{$method};
39 37
   return $self->$helper(@_);
... ...
@@ -42,19 +40,17 @@ sub AUTOLOAD {
42 40
 sub DESTROY { }
43 41
 
44 42
 sub cookie {
45
-  my ($self, $name, $value, $options) = @_;
46
-  $options ||= {};
43
+  my ($self, $name) = (shift, shift);
47 44
 
48 45
   # Response cookie
49
-  if (defined $value) {
46
+  if (@_) {
50 47
 
51 48
     # Cookie too big
49
+    my $cookie = {name => $name, value => shift, %{shift || {}}};
52 50
     $self->app->log->error(qq{Cookie "$name" is bigger than 4096 bytes.})
53
-      if length $value > 4096;
51
+      if length $cookie->{value} > 4096;
54 52
 
55
-    # Create new cookie
56
-    $self->res->cookies(
57
-      Mojo::Cookie::Response->new(name => $name, value => $value, %$options));
53
+    $self->res->cookies($cookie);
58 54
     return $self;
59 55
   }
60 56
 
... ...
@@ -65,20 +61,20 @@ sub cookie {
65 61
 }
66 62
 
67 63
 sub finish {
68
-  my ($self, $chunk) = @_;
64
+  my $self = shift;
69 65
 
70 66
   # WebSocket
71 67
   my $tx = $self->tx;
72
-  $tx->finish and return $self if $tx->is_websocket;
68
+  $tx->finish(@_) and return $self if $tx->is_websocket;
73 69
 
74 70
   # Chunked stream
75
-  if ($tx->res->is_chunked) {
76
-    $self->write_chunk($chunk) if defined $chunk;
71
+  if ($tx->res->content->is_chunked) {
72
+    $self->write_chunk(@_) if @_;
77 73
     return $self->write_chunk('');
78 74
   }
79 75
 
80 76
   # Normal stream
81
-  $self->write($chunk) if defined $chunk;
77
+  $self->write(@_) if @_;
82 78
   return $self->write('');
83 79
 }
84 80
 
... ...
@@ -152,44 +148,27 @@ sub render {
152 148
   my $self = shift;
153 149
 
154 150
   # Template may be first argument
155
-  my $template = @_ % 2 && !ref $_[0] ? shift : undef;
156
-  my $args = ref $_[0] ? $_[0] : {@_};
151
+  my ($template, $args) = (@_ % 2 ? shift : undef, {@_});
157 152
   $args->{template} = $template if $template;
158
-
159
-  # Detect template name
160
-  my $stash = $self->stash;
161
-  unless ($args->{template} || $stash->{template}) {
162
-
163
-    # Normal default template
164
-    my $controller = $args->{controller} || $stash->{controller};
165
-    my $action     = $args->{action}     || $stash->{action};
166
-    if ($controller && $action) {
167
-      $stash->{template} = join '/',
168
-        split(/-/, Mojo::Util::decamelize($controller)), $action;
169
-    }
170
-
171
-    # Try the route name if we don't have controller and action
172
-    elsif (my $endpoint = $self->match->endpoint) {
173
-      $stash->{template} = $endpoint->name;
174
-    }
175
-  }
153
+  my $maybe = delete $args->{'mojo.maybe'};
176 154
 
177 155
   # Render
178 156
   my $app = $self->app;
179 157
   my ($output, $format) = $app->renderer->render($self, $args);
180
-  return undef unless defined $output;
181
-  return Mojo::ByteStream->new($output) if $args->{partial};
158
+  return defined $output ? Mojo::ByteStream->new($output) : undef
159
+    if $args->{partial};
160
+
161
+  # Maybe
162
+  return $maybe ? undef : !$self->render_not_found unless defined $output;
182 163
 
183 164
   # Prepare response
184 165
   $app->plugins->emit_hook(after_render => $self, \$output, $format);
185 166
   my $headers = $self->res->body($output)->headers;
186 167
   $headers->content_type($app->types->type($format) || 'text/plain')
187 168
     unless $headers->content_type;
188
-  return !!$self->rendered($stash->{status});
169
+  return !!$self->rendered($self->stash->{status});
189 170
 }
190 171
 
191
-sub render_data { shift->render(data => @_) }
192
-
193 172
 sub render_exception {
194 173
   my ($self, $e) = @_;
195 174
 
... ...
@@ -214,14 +193,15 @@ sub render_exception {
214 193
   };
215 194
   my $inline = $renderer->_bundled(
216 195
     $mode eq 'development' ? 'exception.development' : 'exception');
217
-  return if $self->_fallbacks($options, 'exception', $inline);
196
+  return $self if $self->_fallbacks($options, 'exception', $inline);
218 197
   $self->_fallbacks({%$options, format => 'html'}, 'exception', $inline);
198
+  return $self;
219 199
 }
220 200
 
221
-sub render_json { shift->render(json => @_) }
222
-
223 201
 sub render_later { shift->stash('mojo.rendered' => 1) }
224 202
 
203
+sub render_maybe { shift->render(@_, 'mojo.maybe' => 1) }
204
+
225 205
 sub render_not_found {
226 206
   my $self = shift;
227 207
 
... ...
@@ -234,15 +214,9 @@ sub render_not_found {
234 214
     = {template => "not_found.$mode", format => $format, status => 404};
235 215
   my $inline = $renderer->_bundled(
236 216
     $mode eq 'development' ? 'not_found.development' : 'not_found');
237
-  return if $self->_fallbacks($options, 'not_found', $inline);
217
+  return $self if $self->_fallbacks($options, 'not_found', $inline);
238 218
   $self->_fallbacks({%$options, format => 'html'}, 'not_found', $inline);
239
-}
240
-
241
-sub render_partial {
242
-  my $self = shift;
243
-  my $template = @_ % 2 ? shift : undef;
244
-  return $self->render(
245
-    {@_, partial => 1, defined $template ? (template => $template) : ()});
219
+  return $self;
246 220
 }
247 221
 
248 222
 sub render_static {
... ...
@@ -250,11 +224,9 @@ sub render_static {
250 224
   my $app = $self->app;
251 225
   return !!$self->rendered if $app->static->serve($self, $file);
252 226
   $app->log->debug(qq{File "$file" not found, public directory missing?});
253
-  return undef;
227
+  return !$self->render_not_found;
254 228
 }
255 229
 
256
-sub render_text { shift->render(text => @_) }
257
-
258 230
 sub rendered {
259 231
   my ($self, $status) = @_;
260 232
 
... ...
@@ -263,8 +235,20 @@ sub rendered {
263 235
   $res->code($status || 200) if $status || !$res->code;
264 236
 
265 237
   # Finish transaction
266
-  unless ($self->stash->{'mojo.finished'}++) {
238
+  my $stash = $self->stash;
239
+  unless ($stash->{'mojo.finished'}++) {
240
+
241
+    # Stop timer
267 242
     my $app = $self->app;
243
+    if (my $started = delete $stash->{'mojo.started'}) {
244
+      my $elapsed = sprintf '%f',
245
+        Time::HiRes::tv_interval($started, [Time::HiRes::gettimeofday()]);
246
+      my $rps  = $elapsed == 0 ? '??' : sprintf '%.3f', 1 / $elapsed;
247
+      my $code = $res->code;
248
+      my $msg  = $res->message || $res->default_message($code);
249
+      $app->log->debug("$code $msg (${elapsed}s, $rps/s).");
250
+    }
251
+
268 252
     $app->plugins->emit_hook_reverse(after_dispatch => $self);
269 253
     $app->sessions->store($self);
270 254
   }
... ...
@@ -304,7 +288,9 @@ sub respond_to {
304 288
   }
305 289
 
306 290
   # Dispatch
307
-  ref $target eq 'CODE' ? $target->($self) : $self->render($target);
291
+  ref $target eq 'CODE' ? $target->($self) : $self->render(%$target);
292
+
293
+  return $self;
308 294
 }
309 295
 
310 296
 sub send {
... ...
@@ -438,14 +424,16 @@ sub url_for {
438 424
 sub write {
439 425
   my ($self, $chunk, $cb) = @_;
440 426
   ($cb, $chunk) = ($chunk, undef) if ref $chunk eq 'CODE';
441
-  $self->res->write($chunk => sub { shift and $self->$cb(@_) if $cb });
427
+  my $content = $self->res->content;
428
+  $content->write($chunk => sub { shift and $self->$cb(@_) if $cb });
442 429
   return $self->rendered;
443 430
 }
444 431
 
445 432
 sub write_chunk {
446 433
   my ($self, $chunk, $cb) = @_;
447 434
   ($cb, $chunk) = ($chunk, undef) if ref $chunk eq 'CODE';
448
-  $self->res->write_chunk($chunk => sub { shift and $self->$cb(@_) if $cb });
435
+  my $content = $self->res->content;
436
+  $content->write_chunk($chunk => sub { shift and $self->$cb(@_) if $cb });
449 437
   return $self->rendered;
450 438
 }
451 439
 
... ...
@@ -453,18 +441,16 @@ sub _fallbacks {
453 441
   my ($self, $options, $template, $inline) = @_;
454 442
 
455 443
   # Mode specific template
456
-  return 1 if $self->render($options);
444
+  return 1 if $self->render_maybe(%$options);
457 445
 
458 446
   # Normal template
459
-  $options->{template} = $template;
460
-  return 1 if $self->render($options);
447
+  return 1 if $self->render_maybe(%$options, template => $template);
461 448
 
462 449
   # Inline template
463 450
   my $stash = $self->stash;
464 451
   return undef unless $stash->{format} eq 'html';
465 452
   delete $stash->{$_} for qw(extends layout);
466
-  delete $options->{template};
467
-  return $self->render(%$options, inline => $inline, handler => 'ep');
453
+  return $self->render_maybe(%$options, inline => $inline, handler => 'ep');
468 454
 }
469 455
 
470 456
 1;
... ...
@@ -548,14 +534,16 @@ implements the following new ones.
548 534
 Access request cookie values and create new response cookies.
549 535
 
550 536
   # Create response cookie with domain and expiration date
551
-  $c->cookie(user => 'sri', {domain => 'mojolicio.us', expires => time + 60});
537
+  $c->cookie(user => 'sri', {domain => 'example.com', expires => time + 60});
552 538
 
553 539
 =head2 finish
554 540
 
555 541
   $c = $c->finish;
542
+  $c = $c->finish(1000);
543
+  $c = $c->finish(1003 => 'Cannot accept data!');
556 544
   $c = $c->finish('Bye!');
557 545
 
558
-Gracefully end WebSocket connection or long poll stream.
546
+Close WebSocket connection or long poll stream gracefully.
559 547
 
560 548
 =head2 flash
561 549
 
... ...
@@ -588,20 +576,17 @@ L<Mojo::Transaction::WebSocket> object.
588 576
     $c->app->log->debug("Message: $msg");
589 577
   });
590 578
 
591
-  # Receive JSON object via WebSocket "Text" message
592
-  use Mojo::JSON 'j';
593
-  $c->on(text => sub {
594
-    my ($c, $bytes) = @_;
595
-    my $test = j($bytes)->{test};
596
-    $c->app->log->debug("Test: $test");
579
+  # Receive JSON object via WebSocket message
580
+  $c->on(json => sub {
581
+    my ($c, $hash) = @_;
582
+    $c->app->log->debug("Test: $hash->{test}");
597 583
   });
598 584
 
599
-  # Receive JSON object via WebSocket "Binary" message
600
-  use Mojo::JSON 'j';
585
+  # Receive WebSocket "Binary" message
601 586
   $c->on(binary => sub {
602 587
     my ($c, $bytes) = @_;
603
-    my $test = j($bytes)->{test};
604
-    $c->app->log->debug("Test: $test");
588
+    my $len = length $bytes;
589
+    $c->app->log->debug("Received $len bytes.");
605 590
   });
606 591
 
607 592
 =head2 param
... ...
@@ -615,8 +600,8 @@ L<Mojo::Transaction::WebSocket> object.
615 600
 
616 601
 Access GET/POST parameters, file uploads and route placeholder values that are
617 602
 not reserved stash values. Note that this method is context sensitive in some
618
-cases and therefore needs to be used with care, every GET/POST parameter can
619
-have multiple values, which might have unexpected consequences.
603
+cases and therefore needs to be used with care, there can always be multiple
604
+values, which might have unexpected consequences.
620 605
 
621 606
   # List context is ambiguous and should be avoided
622 607
   my $hash = {foo => $self->param('foo')};
... ...
@@ -658,7 +643,6 @@ Prepare a C<302> redirect response, takes the same arguments as C<url_for>.
658 643
 
659 644
   my $success = $c->render;
660 645
   my $success = $c->render(controller => 'foo', action => 'bar');
661
-  my $success = $c->render({controller => 'foo', action => 'bar'});
662 646
   my $success = $c->render(template => 'foo/index');
663 647
   my $success = $c->render(template => 'index', format => 'html');
664 648
   my $success = $c->render(data => $bytes);
... ...
@@ -673,42 +657,22 @@ C<after_render> hook unless the result is C<partial>. If no template is
673 657
 provided a default one based on controller and action or route name will be
674 658
 generated, all additional values get merged into the C<stash>.
675 659
 
676
-=head2 render_data
677
-
678
-  $c->render_data($bytes);
679
-  $c->render_data($bytes, format => 'png');
680
-
681
-Render the given content as raw bytes, similar to C<render_text> but data will
682
-not be encoded. All additional values get merged into the C<stash>.
683
-
684
-  # Longer version
685
-  $c->render(data => $bytes);
686
-
687 660
 =head2 render_exception
688 661
 
689
-  $c->render_exception('Oops!');
690
-  $c->render_exception(Mojo::Exception->new('Oops!'));
662
+  $c = $c->render_exception('Oops!');
663
+  $c = $c->render_exception(Mojo::Exception->new('Oops!'));
691 664
 
692 665
 Render the exception template C<exception.$mode.$format.*> or
693
-C<exception.$format.*> and set the response status code to C<500>.
694
-
695
-=head2 render_json
696
-
697
-  $c->render_json({foo => 'bar'});
698
-  $c->render_json([1, 2, -3], status => 201);
699
-
700
-Render a data structure as JSON. All additional values get merged into the
701
-C<stash>.
702
-
703
-  # Longer version
704
-  $c->render(json => {foo => 'bar'});
666
+C<exception.$format.*> and set the response status code to C<500>. Also sets
667
+the stash values C<exception> to a L<Mojo::Exception> object and C<snapshot>
668
+to a copy of the C<stash> for use in the templates.
705 669
 
706 670
 =head2 render_later
707 671
 
708 672
   $c = $c->render_later;
709 673
 
710 674
 Disable automatic rendering to delay response generation, only necessary if
711
-automatic rendring would result in a response.
675
+automatic rendering would result in a response.
712 676
 
713 677
   # Delayed rendering
714 678
   $c->render_later;
... ...
@@ -716,23 +680,24 @@ automatic rendring would result in a response.
716 680
     $c->render(text => 'Delayed by 2 seconds!');
717 681
   });
718 682
 
719
-=head2 render_not_found
683
+=head2 render_maybe
720 684
 
721
-  $c->render_not_found;
685
+  my $success = $c->render_maybe;
686
+  my $success = $c->render_maybe(controller => 'foo', action => 'bar');
687
+  my $success = $c->render_maybe('foo/index', format => 'html');
722 688
 
723
-Render the not found template C<not_found.$mode.$format.*> or
724
-C<not_found.$format.*> and set the response status code to C<404>.
689
+Try to render content but do not call C<render_not_found> if no response could
690
+be generated, takes the same arguments as C<render>.
725 691
 
726
-=head2 render_partial
692
+  # Render template "index_local" only if it exists
693
+  $self->render_maybe('index_local') or $self->render('index');
727 694
 
728
-  my $output = $c->render_partial('menubar');
729
-  my $output = $c->render_partial('menubar', format => 'txt');
730
-  my $output = $c->render_partial(template => 'menubar');
695
+=head2 render_not_found
731 696
 
732
-Same as C<render> but returns the rendered result.
697
+  $c = $c->render_not_found;
733 698
 
734
-  # Longer version
735
-  my $output = $c->render('menubar', partial => 1);
699
+Render the not found template C<not_found.$mode.$format.*> or
700
+C<not_found.$format.*> and set the response status code to C<404>.
736 701
 
737 702
 =head2 render_static
738 703
 
... ...
@@ -743,22 +708,6 @@ Render a static file using L<Mojolicious::Static/"serve">, usually from the
743 708
 C<public> directories or C<DATA> sections of your application. Note that this
744 709
 method does not protect from traversing to parent directories.
745 710
 
746
-=head2 render_text
747
-
748
-  $c->render_text('Hello World!');
749
-  $c->render_text('Hello World!', layout => 'green');
750
-
751
-Render the given content as Perl characters, which will be encoded to bytes.
752
-All additional values get merged into the C<stash>. See C<render_data> for an
753
-alternative without encoding. Note that this does not change the content type
754
-of the response, which is C<text/html;charset=UTF-8> by default.
755
-
756
-  # Longer version
757
-  $c->render(text => 'Hello World!');
758
-
759
-  # Render "text/plain" response
760
-  $c->render_text('Hello World!', format => 'txt');
761
-
762 711
 =head2 rendered
763 712
 
764 713
   $c = $c->rendered;
... ...
@@ -777,7 +726,9 @@ Get L<Mojo::Message::Request> object from L<Mojo::Transaction/"req">.
777 726
   my $req = $c->tx->req;
778 727
 
779 728
   # Extract request information
780
-  my $userinfo = $c->req->url->userinfo;
729
+  my $url      = $c->req->url->to_abs;
730
+  my $userinfo = $c->req->url->to_abs->userinfo;
731
+  my $host     = $c->req->url->to_abs->host;
781 732
   my $agent    = $c->req->headers->user_agent;
782 733
   my $body     = $c->req->body;
783 734
   my $foo      = $c->req->json('/23/foo');
... ...
@@ -797,7 +748,7 @@ Get L<Mojo::Message::Response> object from L<Mojo::Transaction/"res">.
797 748
 
798 749
 =head2 respond_to
799 750
 
800
-  $c->respond_to(
751
+  $c = $c->respond_to(
801 752
     json => {json => {message => 'Welcome!'}},
802 753
     html => {template => 'welcome'},
803 754
     any  => sub {...}
... ...
@@ -811,7 +762,7 @@ more than one MIME type will be ignored, unless the C<X-Requested-With> header
811 762
 is set to the value C<XMLHttpRequest>.
812 763
 
813 764
   $c->respond_to(
814
-    json => sub { $c->render_json({just => 'works'}) },
765
+    json => sub { $c->render(json => {just => 'works'}) },
815 766
     xml  => {text => '<just>works</just>'},
816 767
     any  => {data => '', status => 204}
817 768
   );
... ...
@@ -820,7 +771,9 @@ is set to the value C<XMLHttpRequest>.
820 771
 
821 772
   $c = $c->send({binary => $bytes});
822 773
   $c = $c->send({text   => $bytes});
774
+  $c = $c->send({json   => {test => [1, 2, 3]}});
823 775
   $c = $c->send([$fin, $rsv1, $rsv2, $rsv3, $op, $bytes]);
776
+  $c = $c->send(Mojo::ByteStream->new($chars));
824 777
   $c = $c->send($chars);
825 778
   $c = $c->send($chars => sub {...});
826 779
 
... ...
@@ -831,8 +784,7 @@ will be invoked once all data has been written.
831 784
   $c->send('I ♥ Mojolicious!');
832 785
 
833 786
   # Send JSON object as "Text" message
834
-  use Mojo::JSON 'j';
835
-  $c->send({text => j({test => 'I ♥ Mojolicious!'})});
787
+  $c->send({json => {test => 'I ♥ Mojolicious!'}});
836 788
 
837 789
   # Send JSON object as "Binary" message
838 790
   use Mojo::JSON 'j';
... ...
@@ -885,10 +837,10 @@ discarded.
885 837
 
886 838
 =head2 stash
887 839
 
888
-  my $stash = $c->stash;
889
-  my $foo   = $c->stash('foo');
890
-  $c        = $c->stash({foo => 'bar'});
891
-  $c        = $c->stash(foo => 'bar');
840
+  my $hash = $c->stash;
841
+  my $foo  = $c->stash('foo');
842
+  $c       = $c->stash({foo => 'bar'});
843
+  $c       = $c->stash(foo => 'bar');
892 844
 
893 845
 Non persistent data storage and exchange, application wide default values can
894 846
 be set with L<Mojolicious/"defaults">. Many stash values have a special
... ...
@@ -897,10 +849,8 @@ C<controller>, C<data>, C<extends>, C<format>, C<handler>, C<json>, C<layout>,
897 849
 C<namespace>, C<partial>, C<path>, C<status>, C<template> and C<text>. Note
898 850
 that all stash values with a C<mojo.*> prefix are reserved for internal use.
899 851
 
900
-  # Manipulate stash
901
-  $c->stash->{foo} = 'bar';
902
-  my $foo = $c->stash->{foo};
903
-  delete $c->stash->{foo};
852
+  # Remove value
853
+  my $foo = delete $c->stash->{foo};
904 854
 
905 855
 =head2 ua
906 856
 
... ...
@@ -912,25 +862,25 @@ Get L<Mojo::UserAgent> object from L<Mojo/"ua">.
912 862
   my $ua = $c->app->ua;
913 863
 
914 864
   # Blocking
915
-  my $tx = $c->ua->get('http://mojolicio.us');
916
-  my $tx = $c->ua->post_form('http://kraih.com/login' => {user => 'mojo'});
865
+  my $tx = $c->ua->get('http://example.com');
866
+  my $tx = $c->ua->post('example.com/login' => form => {user => 'mojo'});
917 867
 
918 868
   # Non-blocking
919
-  $c->ua->get('http://mojolicio.us' => sub {
869
+  $c->ua->get('http://example.com' => sub {
920 870
     my ($ua, $tx) = @_;
921
-    $c->render_data($tx->res->body);
871
+    $c->render(data => $tx->res->body);
922 872
   });
923 873
 
924 874
   # Parallel non-blocking
925 875
   my $delay = Mojo::IOLoop->delay(sub {
926 876
     my ($delay, @titles) = @_;
927
-    $c->render_json(\@titles);
877
+    $c->render(json => \@titles);
928 878
   });
929 879
   for my $url ('http://mojolicio.us', 'https://metacpan.org') {
930
-    $delay->begin;
880
+    my $end = $delay->begin(0);
931 881
     $c->ua->get($url => sub {
932 882
       my ($ua, $tx) = @_;
933
-      $delay->end($tx->res->dom->html->head->title->text);
883
+      $end->($tx->res->dom->html->head->title->text);
934 884
     });
935 885
   }
936 886
 
... ...
@@ -938,7 +888,9 @@ Get L<Mojo::UserAgent> object from L<Mojo/"ua">.
938 888
 
939 889
   my $url = $c->url_for;
940 890
   my $url = $c->url_for(name => 'sebastian');
891
+  my $url = $c->url_for({name => 'sebastian'});
941 892
   my $url = $c->url_for('test', name => 'sebastian');
893
+  my $url = $c->url_for('test', {name => 'sebastian'});
942 894
   my $url = $c->url_for('/perldoc');
943 895
   my $url = $c->url_for('http://mojolicio.us/perldoc');
944 896
 
+6 -4
mojo/lib/Mojolicious/Guides.pod
... ...
@@ -32,10 +32,12 @@ overview of what L<Mojolicious> is all about.
32 32
 
33 33
 =item L<Mojolicious::Lite>
34 34
 
35
-A really fast and fun way to get started developing web applications with
36
-Mojolicious is the L<Mojolicious::Lite> tutorial. Almost everything you learn
37
-there can also be applied to normal L<Mojolicious> applications and is
38
-considered a prerequisite for the guides. You should definitely take a look!
35
+A fast and fun way to get started developing web applications with Mojolicious
36
+is the L<Mojolicious::Lite> tutorial. This micro web framework is only a thin
37
+wrapper around the normal web framework, so almost everything you learn here
38
+also applies to full L<Mojolicious> applications. The simplified notation
39
+introduced in the tutorial is commonly used throughout the guides and is
40
+therefore considered a prerequisite, you should definitely take a look!
39 41
 
40 42
 =back
41 43
 
+1 -1
mojo/lib/Mojolicious/Guides/Contributing.pod
... ...
@@ -130,7 +130,7 @@ The pumpking has veto rights and may select his successor.
130 130
 
131 131
 It's not a feature without a test and documentation.
132 132
 
133
-A feature is only needed when the majority of the userbase benefits from it.
133
+A feature is only needed when the majority of the user base benefits from it.
134 134
 
135 135
 Features may only be changed in a major release or after being deprecated for
136 136
 at least 3 months.
+78 -33
mojo/lib/Mojolicious/Guides/Cookbook.pod
... ...
@@ -42,6 +42,15 @@ On UNIX platforms you can also add preforking with L<Mojo::Server::Prefork>.
42 42
   $ ./script/myapp prefork
43 43
   Server available at http://127.0.0.1:3000.
44 44
 
45
+Since all built-in web servers are based on the L<Mojo::IOLoop> event loop,
46
+they scale best with non-blocking operations. But if your application for some
47
+reason needs to perform many blocking operations, you can improve performance
48
+by increasing the number of worker processes and decreasing the number of
49
+concurrent connections each worker is allowed to handle.
50
+
51
+  $ ./script/myapp prefork -m production -w 10 -c 1
52
+  Server available at http://127.0.0.1:3000.
53
+
45 54
 =head2 Morbo
46 55
 
47 56
 After reading the L<Mojolicious::Lite> tutorial, you should already be
... ...
@@ -129,8 +138,8 @@ timers.
129 138
 
130 139
 =head2 Nginx
131 140
 
132
-One of the most popular setups these days is the built-in web server behind a
133
-Nginx reverse proxy.
141
+One of the most popular setups these days is Hypnotoad behind an Nginx reverse
142
+proxy, which even supports WebSockets in newer versions.
134 143
 
135 144
   upstream myapp {
136 145
     server 127.0.0.1:8080;
... ...
@@ -139,8 +148,10 @@ Nginx reverse proxy.
139 148
     listen 80;
140 149
     server_name localhost;
141 150
     location / {
142
-      proxy_read_timeout 300;
143 151
       proxy_pass http://myapp;
152
+      proxy_http_version 1.1;
153
+      proxy_set_header Upgrade $http_upgrade;
154
+      proxy_set_header Connection "upgrade";
144 155
       proxy_set_header Host $host;
145 156
       proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
146 157
       proxy_set_header X-Forwarded-HTTPS 0;
... ...
@@ -150,7 +161,7 @@ Nginx reverse proxy.
150 161
 =head2 Apache/mod_proxy
151 162
 
152 163
 Another good reverse proxy is Apache with C<mod_proxy>, the configuration
153
-looks very similar to the Nginx one above.
164
+looks quite similar to the Nginx one above.
154 165
 
155 166
   <VirtualHost *:80>
156 167
     ServerName localhost
... ...
@@ -184,12 +195,12 @@ simple to deploy with L<Plack>.
184 195
   HTTP::Server::PSGI: Accepting connections at http://0:5000/
185 196
 
186 197
 L<Plack> provides many server and protocol adapters for you to choose from,
187
-such as C<FCGI>, C<SCGI> and C<mod_perl>.
198
+such as C<FCGI>, C<uWSGI> and C<mod_perl>.
188 199
 
189 200
   $ plackup ./script/myapp -s FCGI -l /tmp/myapp.sock
190 201
 
191 202
 If an older server adapter is not be able to correctly detect the application
192
-home directory, you can simply use the C<MOJO_HOME> environment variable.
203
+home directory, you can simply use the MOJO_HOME environment variable.
193 204
 
194 205
   $ MOJO_HOME=/home/sri/myapp plackup ./script/myapp
195 206
   HTTP::Server::PSGI: Accepting connections at http://0:5000/
... ...
@@ -247,8 +258,7 @@ incoming requests is also quite common.
247 258
   # Move first part from path to base path in production mode
248 259
   app->hook(before_dispatch => sub {
249 260
     my $self = shift;
250
-    push @{$self->req->url->base->path->parts},
251
-      shift @{$self->req->url->path->parts};
261
+    push @{$self->req->url->base->path}, shift @{$self->req->url->path};
252 262
   }) if app->mode eq 'production';
253 263
 
254 264
 =head2 Application embedding
... ...
@@ -440,9 +450,10 @@ shouldn't block for too long.
440 450
 =head2 WebSocket web service
441 451
 
442 452
 The WebSocket protocol offers full bi-directional low-latency communication
443
-channels between clients and servers. Receiving messages is as easy as
444
-subscribing to the event L<Mojo::Transaction::WebSocket/"message"> with the
445
-method L<Mojolicious::Controller/"on">.
453
+channels between clients and servers. Receive messages just by subscribing to
454
+events such as L<Mojo::Transaction::WebSocket/"message"> with the method
455
+L<Mojolicious::Controller/"on"> and return them with
456
+L<Mojolicious::Controller/"send">.
446 457
 
447 458
   use Mojolicious::Lite;
448 459
   use Mojo::IOLoop;
... ...
@@ -454,8 +465,8 @@ method L<Mojolicious::Controller/"on">.
454 465
   websocket '/echo' => sub {
455 466
     my $self = shift;
456 467
 
457
-    # Connected
458
-    $self->app->log->debug('WebSocket connected.');
468
+    # Opened
469
+    $self->app->log->debug('WebSocket opened.');
459 470
 
460 471
     # Increase inactivity timeout for connection a bit
461 472
     Mojo::IOLoop->stream($self->tx->connection)->timeout(300);
... ...
@@ -466,10 +477,10 @@ method L<Mojolicious::Controller/"on">.
466 477
       $self->send("echo: $msg");
467 478
     });
468 479
 
469
-    # Disconnected
480
+    # Closed
470 481
     $self->on(finish => sub {
471
-      my $self = shift;
472
-      $self->app->log->debug('WebSocket disconnected.');
482
+      my ($self, $code, $reason) = @_;
483
+      $self->app->log->debug("WebSocket closed with status $code.");
473 484
     });
474 485
   };
475 486
 
... ...
@@ -521,6 +532,13 @@ L<Test::Mojo> API to be used.
521 532
     ->message_is('echo: Hello Mojo!')
522 533
     ->finish_ok;
523 534
 
535
+  # Test JSON web service
536
+  $t->websocket_ok('/echo.json')
537
+    ->send_ok({json => {test => [1, 2, 3]}})
538
+    ->message_ok
539
+    ->json_message_is('/test', [1, 2, 3])
540
+    ->finish_ok;
541
+
524 542
   done_testing();
525 543
 
526 544
 =head2 EventSource web service
... ...
@@ -794,7 +812,7 @@ You can just add username and password to the URL.
794 812
   use Mojo::UserAgent;
795 813
 
796 814
   my $ua = Mojo::UserAgent->new;
797
-  say $ua->get('https://sri:secret@mojolicio.us/hideout')->res->body;
815
+  say $ua->get('https://sri:secret@example.com/hideout')->res->body;
798 816
 
799 817
 =head2 Decorating followup requests
800 818
 
... ...
@@ -820,6 +838,42 @@ them.
820 838
 
821 839
 This even works for proxy C<CONNECT> requests.
822 840
 
841
+=head2 Content generators
842
+
843
+Generate the same type of content repeatedly for multiple requests.
844
+
845
+  use Mojo::UserAgent;
846
+  use Mojo::Asset::File;
847
+
848
+  # Add "stream" generator
849
+  my $ua = Mojo::UserAgent->new;
850
+  $ua->transactor->add_generator(stream => sub {
851
+    my ($transactor, $tx, $path) = @_;
852
+    $tx->req->content->asset(Mojo::Asset::File->new(path => $path));
853
+  });
854
+
855
+  # Send multiple files streaming via PUT and POST
856
+  $ua->put('http://example.com/upload'  => stream => '/home/sri/mojo.png');
857
+  $ua->post('http://example.com/upload' => stream => '/home/sri/mango.png');
858
+
859
+The C<json> and C<form> content generators are always available.
860
+
861
+  use Mojo::UserAgent;
862
+
863
+  # Send JSON content via PATCH
864
+  my $ua = Mojo::UserAgent->new;
865
+  my $tx = $ua->patch('http://api.example.com' => json => {foo => 'bar'});
866
+
867
+  # Send "application/x-www-form-urlencoded" content via POST
868
+  my $tx2 = $ua->post('http://search.example.com' => form => {q => 'test'});
869
+
870
+  # Send "multipart/form-data" content via PUT
871
+  my $tx3 = $ua->put('http://upload.example.com' =>
872
+    form => {test => {content => 'Hello World!'}});
873
+
874
+For more information about available content generators see also
875
+L<Mojo::UserAgent::Transactor/"tx">.
876
+
823 877
 =head2 Streaming response
824 878
 
825 879
 Receiving a streaming response can be really tricky in most HTTP clients, but
... ...
@@ -829,7 +883,7 @@ L<Mojo::UserAgent> makes it actually easy.
829 883
 
830 884
   # Build a normal transaction
831 885
   my $ua = Mojo::UserAgent->new;
832
-  my $tx = $ua->build_tx(GET => 'http://mojolicio.us');
886
+  my $tx = $ua->build_tx(GET => 'http://example.com');
833 887
 
834 888
   # Replace "read" events to disable default content parser
835 889
   $tx->res->content->unsubscribe('read')->on(read => sub {
... ...
@@ -852,7 +906,7 @@ Sending a streaming request is almost just as easy.
852 906
 
853 907
   # Build a normal transaction
854 908
   my $ua = Mojo::UserAgent->new;
855
-  my $tx = $ua->build_tx(GET => 'http://mojolicio.us');
909
+  my $tx = $ua->build_tx(GET => 'http://example.com');
856 910
 
857 911
   # Prepare content
858 912
   my $content = 'Hello world!';
... ...
@@ -888,7 +942,7 @@ above C<250KB> into a temporary file.
888 942
   $tx->res->content->asset->move_to('mojo.tar.gz');
889 943
 
890 944
 To protect you from excessively large files there is also a limit of C<5MB> by
891
-default, which you can tweak with the C<MOJO_MAX_MESSAGE_SIZE> environment
945
+default, which you can tweak with the MOJO_MAX_MESSAGE_SIZE environment
892 946
 variable.
893 947
 
894 948
   # Increase limit to 1GB
... ...
@@ -902,21 +956,12 @@ Uploading a large file is even easier.
902 956
 
903 957
   # Upload file via POST and "multipart/form-data"
904 958
   my $ua = Mojo::UserAgent->new;
905
-  $ua->post_form('mojolicio.us/upload',
906
-    {image => {file => '/home/sri/hello.png'}});
959
+  $ua->post('example.com/upload' =>
960
+    form => {image => {file => '/home/sri/hello.png'}});
907 961
 
908 962
 And once again you don't have to worry about memory usage, all data will be
909 963
 streamed directly from the file.
910 964
 
911
-  use Mojo::UserAgent;
912
-
913
-  # Upload file via PUT
914
-  my $ua     = Mojo::UserAgent->new;
915
-  my $asset  = Mojo::Asset::File->new(path => '/home/sri/hello.png');
916
-  my $tx     = $ua->build_tx(PUT => 'mojolicio.us/upload');
917
-  $tx->req->content->asset($asset);
918
-  $ua->start($tx);
919
-
920 965
 =head2 Non-blocking
921 966
 
922 967
 L<Mojo::UserAgent> has been designed from the ground up to be non-blocking,
... ...
@@ -1030,7 +1075,7 @@ Fun hacks you might not use very often but that might come in handy some day.
1030 1075
 
1031 1076
 =head2 Adding commands to Mojolicious
1032 1077
 
1033
-By now you've propably used many of the built-in commands described in
1078
+By now you've probably used many of the built-in commands described in
1034 1079
 L<Mojolicious::Commands>, but did you know that you can just add new ones and
1035 1080
 that they will be picked up automatically by the command line interface?
1036 1081
 
... ...
@@ -1056,7 +1101,7 @@ There are many more useful methods and attributes in L<Mojolicious::Command>
1056 1101
 that you can use or overload.
1057 1102
 
1058 1103
   $ mojo spy secret
1059
-  The secret of this application is "Mojolicious::Lite".
1104
+  The secret of this application is "HelloWorld".
1060 1105
 
1061 1106
   $ ./myapp.pl spy secret
1062 1107
   The secret of this application is "secr3t".
+6 -7
mojo/lib/Mojolicious/Guides/FAQ.pod
... ...
@@ -62,7 +62,7 @@ which we already have done in the past.
62 62
 To protect your applications from excessively large requests and responses,
63 63
 our HTTP parser has a cap after which it will automatically stop accepting new
64 64
 data, and in most cases force the connection to be closed. This limit is
65
-around C<5MB> by default, you can use the C<MOJO_MAX_MESSAGE_SIZE> environment
65
+around C<5MB> by default, you can use the MOJO_MAX_MESSAGE_SIZE environment
66 66
 variable to change this value.
67 67
 
68 68
 =head2 What does the error "Maximum line size exceeded" mean?
... ...
@@ -71,15 +71,15 @@ This is a very similar protection mechanism to the one described in the
71 71
 previous answer, but a little more specific. It limits the maximum length of
72 72
 any C<\x0d\x0a> terminated part of a HTTP message, such as request line,
73 73
 status line and headers. This limit is around C<10KB> by default, you can use
74
-the C<MOJO_MAX_LINE_SIZE> environment variable to change this value.
74
+the MOJO_MAX_LINE_SIZE environment variable to change this value.
75 75
 
76 76
 =head2 What does the error "Maximum buffer size exceeded" mean?
77 77
 
78 78
 This protection mechanism is very similar to those mentioned in the two
79 79
 previous answers. It limits how much content the HTTP parser is allowed to
80 80
 buffer when parsing chunked, compressed and multipart messages. This limit is
81
-around C<256KB> by default, you can use the C<MOJO_MAX_BUFFER_SIZE>
82
-environment variable to change this value.
81
+around C<256KB> by default, you can use the MOJO_MAX_BUFFER_SIZE environment
82
+variable to change this value.
83 83
 
84 84
 =head2 What does the error "EV does not work with ithreads" mean?
85 85
 
... ...
@@ -87,15 +87,14 @@ The L<Mojolicious> user agent and web servers are based on an event loop that
87 87
 supports multiple reactor backends. One of these backends is L<EV>, it is very
88 88
 fast and will be automatically used if installed. On Windows however, the
89 89
 C<ithreads> based C<fork()> emulation can interfere with it, and you may have
90
-to use the C<MOJO_REACTOR> environment variable to enforce a more portable
91
-one.
90
+to use the MOJO_REACTOR environment variable to enforce a more portable one.
92 91
 
93 92
   MOJO_REACTOR=Mojo::Reactor::Poll
94 93
 
95 94
 =head2 What does "Your secret passphrase needs to be changed" mean?
96 95
 
97 96
 L<Mojolicious> uses a secret passphrase for security features such as signed
98
-cookies. It defaults to the name of your application, which is not very
97
+cookies. It defaults to the moniker of your application, which is not very
99 98
 secure, so we added this log message as a reminder. You can change the
100 99
 passphrase with the attribute L<Mojolicious/"secret">.
101 100
 
+35 -23
mojo/lib/Mojolicious/Guides/Growing.pod
... ...
@@ -300,7 +300,7 @@ on L<Mojo::DOM>.
300 300
     ->element_exists('form input[type="submit"]');
301 301
 
302 302
   # Test login with valid credentials
303
-  $t->post_form_ok('/' => {user => 'sri', pass => 'secr3t'})
303
+  $t->post_ok('/' => form => {user => 'sri', pass => 'secr3t'})
304 304
     ->status_is(200)->text_like('html body' => qr/Welcome sri/);
305 305
 
306 306
   # Test accessing a protected page
... ...
@@ -319,20 +319,23 @@ against your application.
319 319
 
320 320
   $ ./myapp.pl test
321 321
   $ ./myapp.pl test t/login.t
322
+  $ ./myapp.pl test -v t/login.t
322 323
 
323
-To make the tests less noisy and limit log output to just C<error> messages
324
-you can also add a line like this.
325
-
326
-  $t->app->log->level('error');
327
-
328
-Quick C<GET> requests can be performed right from the command line.
324
+Or perform quick requests right from the command line.
329 325
 
330 326
   $ ./myapp.pl get /
331 327
   Wrong username or password.
332 328
 
333 329
   $ ./myapp.pl get -v '/?user=sri&pass=secr3t'
330
+  GET /?user=sri&pass=secr3t HTTP/1.1
331
+  User-Agent: Mojolicious (Perl)
332
+  Connection: keep-alive
333
+  Accept-Encoding: gzip
334
+  Content-Length: 0
335
+  Host: localhost:59472
336
+
334 337
   HTTP/1.1 200 OK
335
-  Connection: Keep-Alive
338
+  Connection: keep-alive
336 339
   Date: Sun, 18 Jul 2010 13:09:58 GMT
337 340
   Server: Mojolicious (Perl)
338 341
   Content-Length: 12
... ...
@@ -413,12 +416,17 @@ like this.
413 416
     $self->redirect_to('protected');
414 417
   } => 'index';
415 418
 
416
-  # A protected page auto rendering "protected.html.ep"
417
-  get '/protected' => sub {
418
-    my $self = shift;
419
+  # Make sure user is logged in for actions in this group
420
+  group {
421
+    under sub {
422
+      my $self = shift;
423
+
424
+      # Redirect to main page with a 302 response if user is not logged in
425
+      return $self->session('user') || !$self->redirect_to('index');
426
+    };
419 427
 
420
-    # Redirect to main page with a 302 response if user is not logged in
421
-    return $self->redirect_to('index') unless $self->session('user');
428
+    # A protected page auto rendering "protected.html.ep"
429
+    get '/protected';
422 430
   };
423 431
 
424 432
   # Logout action
... ...
@@ -521,10 +529,11 @@ actual action code needs to be changed.
521 529
       $self->redirect_to('protected');
522 530
     } => 'index');
523 531
 
524
-    $r->get('/protected' => sub {
532
+    my $logged_in = $r->under(sub {
525 533
       my $self = shift;
526
-      return $self->redirect_to('index') unless $self->session('user');
534
+      return $self->session('user') || !$self->redirect_to('index');
527 535
     });
536
+    $logged_in->get('/protected');
528 537
 
529 538
     $r->get('/logout' => sub {
530 539
       my $self = shift;
... ...
@@ -536,7 +545,8 @@ actual action code needs to be changed.
536 545
   1;
537 546
 
538 547
 The C<startup> method gets called right after instantiation and is the place
539
-where the whole application gets set up.
548
+where the whole application gets set up. Since full L<Mojolicious>
549
+applications can use nested routes they have no need for C<group> blocks.
540 550
 
541 551
 =head2 Simplified application script
542 552
 
... ...
@@ -580,9 +590,9 @@ Once again the actual action code does not change at all.
580 590
     $self->redirect_to('protected');
581 591
   }
582 592
 
583
-  sub protected {
593
+  sub logged_in {
584 594
     my $self = shift;
585
-    return $self->redirect_to('index') unless $self->session('user');
595
+    return $self->session('user') || !$self->redirect_to('index');
586 596
   }
587 597
 
588 598
   sub logout {
... ...
@@ -614,8 +624,9 @@ information.
614 624
 
615 625
     my $r = $self->routes;
616 626
     $r->any('/')->to('login#index')->name('index');
617
-    $r->get('/protected')->to('login#protected')->name('protected');
618
-    $r->get('/logout')->to('login#logout')->name('logout');
627
+    my $logged_in = $r->under->to('login#logged_in');
628
+    $logged_in->get('/protected')->to('login#protected');
629
+    $r->get('/logout')->to('login#logout');
619 630
   }
620 631
 
621 632
   1;
... ...
@@ -641,7 +652,8 @@ Finally C<myapp.pl> can be replaced with a proper L<Mojolicious> script.
641 652
   $ touch script/myapp
642 653
   $ chmod 744 script/myapp
643 654
 
644
-Only a few small details change.
655
+Only a few small details change, since installable scripts can't use L<lib>
656
+without breaking updated dual-life modules.
645 657
 
646 658
   #!/usr/bin/env perl
647 659
 
... ...
@@ -649,7 +661,7 @@ Only a few small details change.
649 661
   use warnings;
650 662
 
651 663
   use FindBin;
652
-  use lib "$FindBin::Bin/../lib";
664
+  BEGIN { unshift @INC, "$FindBin::Bin/../lib" }
653 665
 
654 666
   # Start command line interface for application
655 667
   require Mojolicious::Commands;
... ...
@@ -673,7 +685,7 @@ C<t/login.t> can be simplified.
673 685
     ->element_exists('form input[name="pass"]')
674 686
     ->element_exists('form input[type="submit"]');
675 687
 
676
-  $t->post_form_ok('/' => {user => 'sri', pass => 'secr3t'})
688
+  $t->post_ok('/' => form => {user => 'sri', pass => 'secr3t'})
677 689
     ->status_is(200)->text_like('html body' => qr/Welcome sri/);
678 690
 
679 691
   $t->get_ok('/protected')->status_is(200)->text_like('a' => qr/Logout/);
+28 -29
mojo/lib/Mojolicious/Guides/Rendering.pod
... ...
@@ -66,7 +66,7 @@ start characters.
66 66
   % Perl code line, treated as "<% line =%>"
67 67
   %= Perl expression line, treated as "<%= line %>"
68 68
   %== Perl expression line, treated as "<%== line %>"
69
-  %# Comment line, treated as "<%# line =%>"
69
+  %# Comment line, useful for debugging
70 70
   %% Replaced with "%", useful for generating templates
71 71
 
72 72
 Tags and lines work pretty much the same, but depending on context one will
... ...
@@ -196,17 +196,17 @@ too.
196 196
 
197 197
 =head2 Rendering text
198 198
 
199
-Perl characters can be rendered with the C<text> stash value, the given
199
+Characters can be rendered to bytes with the C<text> stash value, the given
200 200
 content will be automatically encoded to bytes.
201 201
 
202 202
   $self->render(text => 'Hello Wörld!');
203 203
 
204 204
 =head2 Rendering data
205 205
 
206
-Raw bytes can be rendered with the C<data> stash value, no encoding will be
206
+Bytes can be rendered with the C<data> stash value, no encoding will be
207 207
 performed.
208 208
 
209
-  $self->render(data => $octets);
209
+  $self->render(data => $bytes);
210 210
 
211 211
 =head2 Rendering JSON
212 212
 
... ...
@@ -217,11 +217,17 @@ renderer which get directly encoded to JSON.
217 217
 
218 218
 =head2 Partial rendering
219 219
 
220
-Sometimes you might want to access the rendered result, for example to
221
-generate emails, this can be done using the C<partial> stash value.
220
+Sometimes you might want to use the rendered result directly instead of
221
+generating a response, for example to send emails, this can be done using the
222
+C<partial> stash value.
222 223
 
223 224
   my $html = $self->render('mail', partial => 1);
224 225
 
226
+No encoding will be performed, making it easy to reuse the result in other
227
+templates or to generate binary data.
228
+
229
+  $self->render(data => $self->render('pdf_invoice', partial => 1));
230
+
225 231
 =head2 Status code
226 232
 
227 233
 Response status codes can be changed with the C<status> stash value.
... ...
@@ -328,10 +334,10 @@ used or an empty C<204> response rendered automatically.
328 334
 
329 335
 By now you've probably already encountered the built-in 404 (Not Found) and
330 336
 500 (Server Error) pages, that get rendered automatically when you make a
331
-mistake. Especially during development they can be a great help, the methods
337
+mistake. Especially during development they can be a great help, you can
338
+render them manually with the methods
332 339
 L<Mojolicious::Controller/"render_exception"> and
333
-L<Mojolicious::Controller/"render_not_found"> can be used to render them
334
-manually.
340
+L<Mojolicious::Controller/"render_not_found">.
335 341
 
336 342
   use Mojolicious::Lite;
337 343
   use Scalar::Util 'looks_like_number';
... ...
@@ -348,7 +354,7 @@ manually.
348 354
     return $self->render_exception('Division by zero!') if $divisor == 0;
349 355
 
350 356
     # 200
351
-    $self->render_text($dividend / $divisor);
357
+    $self->render(text => $dividend / $divisor);
352 358
   };
353 359
 
354 360
   app->start;
... ...
@@ -363,7 +369,12 @@ templates.
363 369
   <!DOCTYPE html>
364 370
   <html>
365 371
     <head><title>Server error</title></head>
366
-    <body><%= $exception %></body>
372
+    <body>
373
+      <h1>Exception</h1>
374
+      <p><%= $exception->message %></p>
375
+      <h1>Stash</h1>
376
+      <pre><%= dumper $snapshot %></pre>
377
+    </body>
367 378
   </html>
368 379
 
369 380
 =head2 Helpers
... ...
@@ -580,18 +591,6 @@ template with named blocks that child templates can override.
580 591
 
581 592
 This chain could go on and on to allow a very high level of template reuse.
582 593
 
583
-=head2 Memorizing template blocks
584
-
585
-Compiled templates are always cached in memory, but with the helper
586
-L<Mojolicious::Plugin::DefaultHelpers/"memorize"> you can go one step further
587
-and prevent template blocks from getting executed more than once.
588
-
589
-  @@ cached.html.ep
590
-  % use Time::Piece;
591
-  %= memorize begin
592
-    This template was compiled at <%= localtime->hms %>.
593
-  % end
594
-
595 594
 =head2 Adding helpers
596 595
 
597 596
 Adding and redefining helpers is very easy, you can use them to do pretty much
... ...
@@ -600,8 +599,8 @@ everything.
600 599
   use Mojolicious::Lite;
601 600
 
602 601
   helper debug => sub {
603
-    my ($self, $string) = @_;
604
-    $self->app->log->debug($string);
602
+    my ($self, $str) = @_;
603
+    $self->app->log->debug($str);
605 604
   };
606 605
 
607 606
   get '/' => sub {
... ...
@@ -654,8 +653,8 @@ applications, plugins make that very simple.
654 653
   sub register {
655 654
     my ($self, $app) = @_;
656 655
     $app->helper(debug => sub {
657
-      my ($self, $string) = @_;
658
-      $self->app->log->debug($string);
656
+      my ($self, $str) = @_;
657
+      $self->app->log->debug($str);
659 658
     });
660 659
   }
661 660
 
... ...
@@ -670,7 +669,7 @@ The C<register> method will be called when you load the plugin.
670 669
   get '/' => sub {
671 670
     my $self = shift;
672 671
     $self->debug('It works.');
673
-    $self->render_text('Hello.');
672
+    $self->render(text => 'Hello.');
674 673
   };
675 674
 
676 675
   app->start;
... ...
@@ -681,7 +680,7 @@ generated.
681 680
   $ mojo generate plugin DebugHelper
682 681
 
683 682
 And if you have a C<PAUSE> account (which can be requested at
684
-L<http://pause.perl.org>), you are only a few commands away from relasing it
683
+L<http://pause.perl.org>), you are only a few commands away from releasing it
685 684
 to CPAN.
686 685
 
687 686
   $ perl Makefile.PL
+18 -10
mojo/lib/Mojolicious/Guides/Routing.pod
... ...
@@ -99,7 +99,7 @@ characters except C</> and C<.>.
99 99
   /sebastian23/hello  -> /:name/hello -> {name => 'sebastian23'}
100 100
   /sebastian 23/hello -> /:name/hello -> {name => 'sebastian 23'}
101 101
 
102
-A generic placeholder can be surrounded by parentheses to separate it from the
102
+All placeholders can be surrounded by parentheses to separate them from the
103 103
 surrounding text.
104 104
 
105 105
   /hello             -> /(:name)hello -> undef
... ...
@@ -221,7 +221,7 @@ L<Mojolicious::Controller/"stash">.
221 221
 =head2 Nested routes
222 222
 
223 223
 It is also possible to build tree structures from routes to remove repetitive
224
-code. A route with children can't match on it's own though, only the actual
224
+code. A route with children can't match on its own though, only the actual
225 225
 endpoints of these nested routes can.
226 226
 
227 227
   # /foo     -> undef
... ...
@@ -301,7 +301,7 @@ dispatching to it.
301 301
 You can use the C<namespace> stash value to change the namespace of a whole
302 302
 route with all its children.
303 303
 
304
-  # /bye -> MyApp::Controller::Foo->bye
304
+  # /bye -> MyApp::Controller::Foo::Bar->bye
305 305
   $r->route('/bye')
306 306
     ->to(namespace => 'MyApp::Controller::Foo::Bar', action => 'bye');
307 307
 
... ...
@@ -425,12 +425,12 @@ routes and allows selective re-enabling.
425 425
   # /foo      -> {controller => 'foo', action => 'bar'}
426 426
   # /foo.html -> undef
427 427
   # /baz      -> undef
428
-  # /baz.txt  -> {controller => 'bar', action => 'baz', format => 'txt'}
429
-  # /baz.html -> {controller => 'bar', action => 'baz', format => 'html'}
428
+  # /baz.txt  -> {controller => 'baz', action => 'yada', format => 'txt'}
429
+  # /baz.html -> {controller => 'baz', action => 'yada', format => 'html'}
430 430
   # /baz.xml  -> undef
431 431
   my $inactive = $r->route(format => 0);
432
-  $inactive->route('/foo')->to('foo#none');
433
-  $inactive->route('/baz', format => [qw(txt html)])->to('bar#baz');
432
+  $inactive->route('/foo')->to('foo#bar');
433
+  $inactive->route('/baz', format => [qw(txt html)])->to('baz#yada');
434 434
 
435 435
 =head2 Named routes
436 436
 
... ...
@@ -489,6 +489,14 @@ methods to pass.
489 489
   $r->route('/bye')->via('GET', 'POST')
490 490
     ->to(controller => 'foo', action => 'bye');
491 491
 
492
+With one small exception, C<HEAD> requests are considered equal to C<GET> and
493
+content will not be sent with the response.
494
+
495
+  # GET /test  -> {controller => 'bar', action => 'test'}
496
+  # HEAD /test -> {controller => 'bar', action => 'test'}
497
+  # PUT /test  -> undef
498
+  $r->route('/test')->via('GET')->to(controller => 'bar', action => 'test');
499
+
492 500
 =head2 WebSockets
493 501
 
494 502
 With the method L<Mojolicious::Routes::Route/"websocket"> you can restrict
... ...
@@ -634,7 +642,7 @@ Same for monitoring tasks.
634 642
   $self->hook(after_dispatch => sub {
635 643
     my $self = shift;
636 644
     return unless my $e = $self->stash('exception');
637
-    $self->ua->post_form('https://kraih.com/bugs' => {exception => $e});
645
+    $self->ua->post('https://example.com/bugs' => form => {exception => $e});
638 646
   });
639 647
 
640 648
 For a full list of available hooks see L<Mojolicious/"hook">.
... ...
@@ -682,7 +690,7 @@ Less commonly used and more powerful features.
682 690
 =head2 IRIs
683 691
 
684 692
 IRIs are handled transparently, that means paths are guaranteed to be
685
-unescaped and decoded to Perl characters.
693
+unescaped and decoded from bytes to characters.
686 694
 
687 695
   # GET /☃ (unicode snowman) -> {controller => 'foo', action => 'snowman'}
688 696
   $r->get('/☃')->to('foo#snowman');
... ...
@@ -829,7 +837,7 @@ self-contained applications under a prefix.
829 837
   plugin Mount => {'/prefix' => '/home/sri/myapp.pl'};
830 838
 
831 839
   # Normal route
832
-  get '/' => sub { shift->render_text('Hello World!') };
840
+  get '/' => sub { shift->render(text => 'Hello World!') };
833 841
 
834 842
   app->start;
835 843
 
+133 -107
mojo/lib/Mojolicious/Lite.pm
... ...
@@ -61,6 +61,8 @@ sub import {
61 61
 
62 62
 1;
63 63
 
64
+=encoding utf8
65
+
64 66
 =head1 NAME
65 67
 
66 68
 Mojolicious::Lite - Real-time micro web framework
... ...
@@ -108,8 +110,6 @@ featured web application.
108 110
 
109 111
   app->start;
110 112
 
111
-=head2 Generator
112
-
113 113
 There is also a helper command to generate a small example application.
114 114
 
115 115
   $ mojo generate lite_app
... ...
@@ -132,9 +132,8 @@ just work without commands.
132 132
   $ ./myapp.pl
133 133
   ...List of available commands (or automatically detected environment)...
134 134
 
135
-=head2 Start
136
-
137
-The app->start call that starts the L<Mojolicious> command system can be
135
+The C<app-E<gt>start> call that starts the L<Mojolicious> command system
136
+should usually be the last expression in your application and can be
138 137
 customized to override normal C<@ARGV> use.
139 138
 
140 139
   app->start('cgi');
... ...
@@ -151,12 +150,13 @@ every change.
151 150
 =head2 Routes
152 151
 
153 152
 Routes are basically just fancy paths that can contain different kinds of
154
-placeholders. C<$self> is a L<Mojolicious::Controller> object containing both,
155
-the HTTP request and response.
153
+placeholders and usually lead to an action. The first argument passed to all
154
+actions (the invocant C<$self>) is a L<Mojolicious::Controller> object
155
+containing both the HTTP request and response.
156 156
 
157 157
   use Mojolicious::Lite;
158 158
 
159
-  # /foo
159
+  # Route leading to an action
160 160
   get '/foo' => sub {
161 161
     my $self = shift;
162 162
     $self->render(text => 'Hello World!');
... ...
@@ -164,9 +164,12 @@ the HTTP request and response.
164 164
 
165 165
   app->start;
166 166
 
167
+Response content is often generated by actions with
168
+L<Mojolicious::Controller/"render">, but more about that later.
169
+
167 170
 =head2 GET/POST parameters
168 171
 
169
-All C<GET> and C<POST> parameters are accessible via
172
+All C<GET> and C<POST> parameters sent with the request are accessible via
170 173
 L<Mojolicious::Controller/"param">.
171 174
 
172 175
   use Mojolicious::Lite;
... ...
@@ -187,7 +190,7 @@ which can be inlined in the C<DATA> section.
187 190
 
188 191
   use Mojolicious::Lite;
189 192
 
190
-  # /bar
193
+  # Route leading to an action that renders a template
191 194
   get '/bar' => sub {
192 195
     my $self = shift;
193 196
     $self->stash(one => 23);
... ...
@@ -210,11 +213,13 @@ full access to all HTTP features and information.
210 213
 
211 214
   use Mojolicious::Lite;
212 215
 
213
-  # /agent
216
+  # Access request and reponse information
214 217
   get '/agent' => sub {
215 218
     my $self = shift;
219
+    my $host = $self->req->url->to_abs->host;
220
+    my $ua   = $self->req->headers->user_agent;
216 221
     $self->res->headers->header('X-Bender' => 'Bite my shiny metal ass!');
217
-    $self->render(text => $self->req->headers->user_agent);
222
+    $self->render(text => "Request by $ua reached $host.");
218 223
   };
219 224
 
220 225
   app->start;
... ...
@@ -230,13 +235,13 @@ without non-word characters.
230 235
 
231 236
   use Mojolicious::Lite;
232 237
 
233
-  # /
238
+  # Render the template "index.html.ep"
234 239
   get '/' => sub {
235 240
     my $self = shift;
236 241
     $self->render;
237 242
   } => 'index';
238 243
 
239
-  # /hello
244
+  # Render the template "hello.html.ep"
240 245
   get '/hello';
241 246
 
242 247
   app->start;
... ...
@@ -258,11 +263,7 @@ L<Mojolicious::Plugin::DefaultHelpers/"content">.
258 263
 
259 264
   use Mojolicious::Lite;
260 265
 
261
-  # /with_layout
262
-  get '/with_layout' => sub {
263
-    my $self = shift;
264
-    $self->render('with_layout');
265
-  };
266
+  get '/with_layout';
266 267
 
267 268
   app->start;
268 269
   __DATA__
... ...
@@ -286,7 +287,6 @@ delimited by the C<begin> and C<end> keywords.
286 287
 
287 288
   use Mojolicious::Lite;
288 289
 
289
-  # /with_block
290 290
   get '/with_block' => 'block';
291 291
 
292 292
   app->start;
... ...
@@ -313,11 +313,7 @@ pass around blocks of captured content.
313 313
 
314 314
   use Mojolicious::Lite;
315 315
 
316
-  # /captured
317
-  get '/captured' => sub {
318
-    my $self = shift;
319
-    $self->render('captured');
320
-  };
316
+  get '/captured';
321 317
 
322 318
   app->start;
323 319
   __DATA__
... ...
@@ -350,7 +346,7 @@ L<Mojolicious::Plugin::TagHelpers>.
350 346
 
351 347
   use Mojolicious::Lite;
352 348
 
353
-  # "whois" helper
349
+  # A helper to identify visitors
354 350
   helper whois => sub {
355 351
     my $self  = shift;
356 352
     my $agent = $self->req->headers->user_agent || 'Anonymous';
... ...
@@ -358,7 +354,7 @@ L<Mojolicious::Plugin::TagHelpers>.
358 354
     return "$agent ($ip)";
359 355
   };
360 356
 
361
-  # /secret
357
+  # Use helper in action and template
362 358
   get '/secret' => sub {
363 359
     my $self = shift;
364 360
     my $user = $self->whois;
... ...
@@ -434,7 +430,7 @@ C<.>.
434 430
 
435 431
 =head2 HTTP methods
436 432
 
437
-Routes can be restricted to specific request methods.
433
+Routes can be restricted to specific request methods with different keywords.
438 434
 
439 435
   use Mojolicious::Lite;
440 436
 
... ...
@@ -542,11 +538,11 @@ are only evaluated if the callback returned a true value.
542 538
     return undef;
543 539
   };
544 540
 
545
-  # / (with authentication)
541
+  # Only reached when authenticated
546 542
   get '/' => 'index';
547 543
 
548 544
   app->start;
549
-  __DATA__;
545
+  __DATA__
550 546
 
551 547
   @@ denied.html.ep
552 548
   You are not Bender, permission denied.
... ...
@@ -567,7 +563,7 @@ Prefixing multiple routes is another good use for C<under>.
567 563
   # /foo/baz
568 564
   get '/baz' => {text => 'foo baz'};
569 565
 
570
-  # /
566
+  # / (reset)
571 567
   under '/' => {message => 'whatever'};
572 568
 
573 569
   # /bar
... ...
@@ -594,7 +590,7 @@ C<under> statements.
594 590
     # Local logic shared only by routes in this group
595 591
     under '/admin' => sub {
596 592
       my $self = shift;
597
-      return 1 if $self->req->heaers->header('X-Awesome');
593
+      return 1 if $self->req->headers->header('X-Awesome');
598 594
       $self->render(text => "You're not awesome enough.");
599 595
       return undef;
600 596
     };
... ...
@@ -621,7 +617,6 @@ Formats can be automatically detected by looking at file extensions.
621 617
     $self->render('detected');
622 618
   };
623 619
 
624
-
625 620
   app->start;
626 621
   __DATA__
627 622
 
... ...
@@ -643,9 +638,9 @@ Restrictive placeholders can also be used.
643 638
   # /hello.txt
644 639
   get '/hello' => [format => [qw(json txt)]] => sub {
645 640
     my $self = shift;
646
-    return $self->render_json({hello => 'world'})
641
+    return $self->render(json => {hello => 'world'})
647 642
       if $self->stash('format') eq 'json';
648
-    $self->render_text('hello world');
643
+    $self->render(text => 'hello world');
649 644
   };
650 645
 
651 646
   app->start;
... ...
@@ -697,6 +692,47 @@ L<Mojolicious/"types">.
697 692
 
698 693
   app->types->type(rdf => 'application/rdf+xml');
699 694
 
695
+=head2 Static files
696
+
697
+Similar to templates, but with only a single file extension and optional
698
+Base64 encoding, static files can be inlined in the C<DATA> section and are
699
+served automatically.
700
+
701
+  use Mojolicious::Lite;
702
+
703
+  app->start;
704
+  __DATA__
705
+
706
+  @@ something.js
707
+  alert('hello!');
708
+
709
+  @@ test.txt (base64)
710
+  dGVzdCAxMjMKbGFsYWxh
711
+
712
+External static files are not limited to a single file extension and will be
713
+served automatically from a C<public> directory if it exists.
714
+
715
+  $ mkdir public
716
+  $ mv something.js public/something.js
717
+  $ mv mojolicious.tar.gz public/mojolicious.tar.gz
718
+
719
+Both have a higher precedence than routes.
720
+
721
+=head2 External templates
722
+
723
+External templates will be searched by the renderer in a C<templates>
724
+directory if it exists.
725
+
726
+  use Mojolicious::Lite;
727
+
728
+  # Render template "templates/foo/bar.html.ep"
729
+  any '/external' => sub {
730
+    my $self = shift;
731
+    $self->render('foo/bar');
732
+  };
733
+
734
+  app->start;
735
+
700 736
 =head2 Conditions
701 737
 
702 738
 Conditions such as C<agent> and C<host> from
... ...
@@ -705,13 +741,13 @@ constructs.
705 741
 
706 742
   use Mojolicious::Lite;
707 743
 
708
-  # /foo (Firefox)
744
+  # Firefox
709 745
   get '/foo' => (agent => qr/Firefox/) => sub {
710 746
     my $self = shift;
711 747
     $self->render(text => 'Congratulations, you are using a cool browser.');
712 748
   };
713 749
 
714
-  # /foo (Internet Explorer)
750
+  # Internet Explorer
715 751
   get '/foo' => (agent => qr/Internet Explorer/) => sub {
716 752
     my $self = shift;
717 753
     $self->render(text => 'Dude, you really need to upgrade to Firefox.');
... ...
@@ -729,10 +765,12 @@ constructs.
729 765
 
730 766
 Signed cookie based sessions just work out of the box as soon as you start
731 767
 using them through the helper
732
-L<Mojolicious::Plugin::DefaultHelpers/"session">.
768
+L<Mojolicious::Plugin::DefaultHelpers/"session">, just be aware that all
769
+session data gets serialized with L<Mojo::JSON>.
733 770
 
734 771
   use Mojolicious::Lite;
735 772
 
773
+  # Access session data in action and template
736 774
   get '/counter' => sub {
737 775
     my $self = shift;
738 776
     $self->session->{counter}++;
... ...
@@ -744,10 +782,6 @@ L<Mojolicious::Plugin::DefaultHelpers/"session">.
744 782
   @@ counter.html.ep
745 783
   Counter: <%= session 'counter' %>
746 784
 
747
-Just be aware that all session data gets serialized with L<Mojo::JSON>.
748
-
749
-=head2 Secret
750
-
751 785
 Note that you should use a custom L<Mojolicious/"secret"> to make signed
752 786
 cookies really secure.
753 787
 
... ...
@@ -797,7 +831,7 @@ temporary file.
797 831
   </html>
798 832
 
799 833
 To protect you from excessively large files there is also a limit of C<5MB> by
800
-default, which you can tweak with the C<MOJO_MAX_MESSAGE_SIZE> environment
834
+default, which you can tweak with the MOJO_MAX_MESSAGE_SIZE environment
801 835
 variable.
802 836
 
803 837
   # Increase limit to 1GB
... ...
@@ -811,68 +845,95 @@ L<Mojo::JSON> and L<Mojo::DOM> this can be a very powerful tool.
811 845
 
812 846
   use Mojolicious::Lite;
813 847
 
814
-  get '/test' => sub {
848
+  get '/headers' => sub {
815 849
     my $self = shift;
816
-    $self->render(data => $self->ua->get('http://mojolicio.us')->res->body);
850
+    my $url  = $self->param('url') || 'http://mojolicio.us';
851
+    my $dom  = $self->ua->get($url)->res->dom;
852
+    $self->render(json => [$dom->find('h1, h2, h3')->pluck('text')->each]);
817 853
   };
818 854
 
819 855
   app->start;
820 856
 
821 857
 =head2 WebSockets
822 858
 
823
-WebSocket applications have never been this easy before.
859
+WebSocket applications have never been this simple before. Just receive
860
+messages by subscribing to events such as
861
+L<Mojo::Transaction::WebSocket/"json"> with L<Mojolicious::Controller/"on">
862
+and return them with L<Mojolicious::Controller/"send">.
824 863
 
825 864
   use Mojolicious::Lite;
826 865
 
827 866
   websocket '/echo' => sub {
828 867
     my $self = shift;
829
-    $self->on(message => sub {
830
-      my ($self, $msg) = @_;
831
-      $self->send("echo: $msg");
868
+    $self->on(json => sub {
869
+      my ($self, $hash) = @_;
870
+      $hash->{msg} = "echo: $hash->{msg}";
871
+      $self->send({json => $hash});
832 872
     });
833 873
   };
834 874
 
875
+  get '/' => 'index';
876
+
835 877
   app->start;
878
+  __DATA__
836 879
 
837
-The event L<Mojo::Transaction::WebSocket/"message">, which you can subscribe
838
-to with L<Mojolicious::Controller/"on">, will be emitted for every new
839
-WebSocket message that is received.
880
+  @@ index.html.ep
881
+  <!DOCTYPE html>
882
+  <html>
883
+    <head>
884
+      <title>Echo</title>
885
+      %= javascript begin
886
+        var ws = new WebSocket('<%= url_for('echo')->to_abs %>');
887
+        ws.onmessage = function (event) {
888
+          document.body.innerHTML += JSON.parse(event.data).msg;
889
+        };
890
+        ws.onopen = function (event) {
891
+          ws.send(JSON.stringify({msg: 'I ♥ Mojolicious!'}));
892
+        };
893
+      % end
894
+    </head>
895
+  </html>
840 896
 
841
-=head2 External templates
897
+For more information about real-time web features see also
898
+L<Mojolicious::Guides::Cookbook/"REAL-TIME WEB">.
842 899
 
843
-External templates will be searched by the renderer in a C<templates>
844
-directory.
900
+=head2 Mode
901
+
902
+You can use the L<Mojo::Log> object from L<Mojo/"log"> to portably collect
903
+debug messages and automatically disable them later in a production setup by
904
+changing the L<Mojolicious> operating mode.
845 905
 
846 906
   use Mojolicious::Lite;
847 907
 
848
-  # /external
849
-  any '/external' => sub {
908
+  get '/' => sub {
850 909
     my $self = shift;
851
-
852
-    # templates/foo/bar.html.ep
853
-    $self->render('foo/bar');
910
+    $self->app->log->debug('Rendering "Hello World!" message.');
911
+    $self->render(text => 'Hello World!');
854 912
   };
855 913
 
914
+  app->log->debug('Starting application.');
856 915
   app->start;
857 916
 
858
-=head2 Static files
917
+The default operating mode will usually be C<development> and can be changed
918
+with command line options or the MOJO_MODE and PLACK_ENV environment
919
+variables. A mode other than C<development> will raise the log level from
920
+C<debug> to C<info>.
859 921
 
860
-Static files will be automatically served from the C<DATA> section (even
861
-Base64 encoded) or a C<public> directory if it exists.
922
+  $ ./myapp.pl daemon -m production
862 923
 
863
-  @@ something.js
864
-  alert('hello!');
924
+All messages will be written to C<STDERR> or a C<log/$mode.log> file if a
925
+C<log> directory exists.
865 926
 
866
-  @@ test.txt (base64)
867
-  dGVzdCAxMjMKbGFsYWxh
927
+  $ mkdir log
868 928
 
869
-  $ mkdir public
870
-  $ mv something.js public/something.js
929
+Mode changes also affects a few other aspects of the framework, such as mode
930
+specific C<exception> and C<not_found> templates.
871 931
 
872 932
 =head2 Testing
873 933
 
874 934
 Testing your application is as easy as creating a C<t> directory and filling
875
-it with normal Perl unit tests.
935
+it with normal Perl unit tests, which can be a lot of fun thanks to
936
+L<Test::Mojo>.
876 937
 
877 938
   use Test::More;
878 939
   use Test::Mojo;
... ...
@@ -888,42 +949,7 @@ it with normal Perl unit tests.
888 949
 Run all unit tests with the C<test> command.
889 950
 
890 951
   $ ./myapp.pl test
891
-
892
-To make your tests more noisy and show you all log messages you can also
893
-change the application log level directly in your test files.
894
-
895
-  $t->app->log->level('debug');
896
-
897
-=head2 Mode
898
-
899
-To disable debug messages later in a production setup, you can change the
900
-L<Mojolicious> operating mode with command line options or the C<MOJO_MODE>
901
-environment variable, the default will usually be C<development>.
902
-
903
-  $ ./myapp.pl daemon -m production
904
-
905
-This also affects many other aspects of the framework, such as mode specific
906
-C<exception> and C<not_found> templates.
907
-
908
-=head2 Logging
909
-
910
-L<Mojo::Log> messages will be automatically written to C<STDERR> or a
911
-C<log/$mode.log> file if a C<log> directory exists.
912
-
913
-  $ mkdir log
914
-
915
-For more control the L<Mojolicious> object can be accessed directly.
916
-
917
-  use Mojolicious::Lite;
918
-
919
-  app->log->level('error');
920
-  app->routes->get('/foo/:bar' => sub {
921
-    my $self = shift;
922
-    $self->app->log->debug('Got a request for "Hello Mojo!".');
923
-    $self->render(text => 'Hello Mojo!');
924
-  });
925
-
926
-  app->start;
952
+  $ ./myapp.pl test -v
927 953
 
928 954
 =head2 More
929 955
 
... ...
@@ -1030,7 +1056,7 @@ more argument variations.
1030 1056
   my $route = websocket '/:foo' => sub {...};
1031 1057
 
1032 1058
 Generate route with L<Mojolicious::Routes::Route/"websocket">, matching only
1033
-C<WebSocket> handshakes. See also the tutorial above for more argument
1059
+WebSocket handshakes. See also the tutorial above for more argument
1034 1060
 variations.
1035 1061
 
1036 1062
 =head1 ATTRIBUTES
+2 -1
mojo/lib/Mojolicious/Plugin/Charset.pm
... ...
@@ -53,7 +53,8 @@ L<Mojolicious::Plugin> and implements the following new ones.
53 53
 
54 54
   $plugin->register(Mojolicious->new, {charset => 'Shift_JIS'});
55 55
 
56
-Register hooks in L<Mojolicious> application.
56
+Register C<before_dispatch> hook in L<Mojolicious> application and change a
57
+few defaults.
57 58
 
58 59
 =head1 SEE ALSO
59 60
 
+6 -3
mojo/lib/Mojolicious/Plugin/Config.pm
... ...
@@ -64,7 +64,7 @@ Mojolicious::Plugin::Config - Perl-ish configuration plugin
64 64
 
65 65
 =head1 SYNOPSIS
66 66
 
67
-  # myapp.conf
67
+  # myapp.conf (it's just Perl returning a hash)
68 68
   {
69 69
     foo       => "bar",
70 70
     music_dir => app->home->rel_dir('music')
... ...
@@ -72,15 +72,18 @@ Mojolicious::Plugin::Config - Perl-ish configuration plugin
72 72
 
73 73
   # Mojolicious
74 74
   my $config = $self->plugin('Config');
75
+  say $config->{foo};
75 76
 
76 77
   # Mojolicious::Lite
77 78
   my $config = plugin 'Config';
79
+  say $config->{foo};
78 80
 
79 81
   # foo.html.ep
80 82
   %= $config->{foo}
81 83
 
82 84
   # The configuration is available application wide
83 85
   my $config = app->config;
86
+  say $config->{foo};
84 87
 
85 88
   # Everything can be customized with options
86 89
   my $config = plugin Config => {file => '/etc/myapp.stuff'};
... ...
@@ -122,7 +125,7 @@ File extension for generated configuration filenames, defaults to C<conf>.
122 125
   plugin Config => {file => 'myapp.conf'};
123 126
   plugin Config => {file => '/etc/foo.stuff'};
124 127
 
125
-Full path to configuration file, defaults to the value of the C<MOJO_CONFIG>
128
+Full path to configuration file, defaults to the value of the MOJO_CONFIG
126 129
 environment variable or C<myapp.conf> in the application home directory.
127 130
 
128 131
 =head1 METHODS
... ...
@@ -159,7 +162,7 @@ Parse configuration file.
159 162
   my $config = $plugin->register(Mojolicious->new);
160 163
   my $config = $plugin->register(Mojolicious->new, {file => '/etc/app.conf'});
161 164
 
162
-Register plugin in L<Mojolicious> application.
165
+Register plugin in L<Mojolicious> application and merge configuration.
163 166
 
164 167
 =head1 SEE ALSO
165 168
 
+8 -55
mojo/lib/Mojolicious/Plugin/DefaultHelpers.pm
... ...
@@ -12,7 +12,7 @@ sub register {
12 12
     $app->helper($name => sub { shift->$name(@_) });
13 13
   }
14 14
 
15
-  # Stash key shortcuts
15
+  # Stash key shortcuts (should not generate log messages)
16 16
   for my $name (qw(extends layout title)) {
17 17
     $app->helper(
18 18
       $name => sub {
... ...
@@ -26,46 +26,13 @@ sub register {
26 26
   }
27 27
 
28 28
   $app->helper(config => sub { shift->app->config(@_) });
29
+
29 30
   $app->helper(content       => \&_content);
30 31
   $app->helper(content_for   => \&_content_for);
31 32
   $app->helper(current_route => \&_current_route);
32 33
   $app->helper(dumper        => \&_dumper);
33 34
   $app->helper(include       => \&_include);
34
-
35
-  my %mem;
36
-  $app->helper(
37
-    memorize => sub {
38
-      my $self = shift;
39
-      return '' unless ref(my $cb = pop) eq 'CODE';
40
-      my ($name, $args)
41
-        = ref $_[0] eq 'HASH' ? (undef, shift) : (shift, shift || {});
42
-
43
-      # Default name
44
-      $name ||= join '', map { $_ || '' } (caller(1))[0 .. 3];
45
-
46
-      # Expire old results
47
-      my $expires = $args->{expires} || 0;
48
-      delete $mem{$name}
49
-        if exists $mem{$name} && $expires > 0 && $mem{$name}{expires} < time;
50
-
51
-      # Memorized result
52
-      return $mem{$name}{content} if exists $mem{$name};
53
-
54
-      # Memorize new result
55
-      $mem{$name}{expires} = $expires;
56
-      return $mem{$name}{content} = $cb->();
57
-    }
58
-  );
59
-
60
-  # DEPRECATED in Rainbow!
61
-  $app->helper(
62
-    render_content => sub {
63
-      warn "Mojolicious::Controller->render_content is DEPRECATED!\n";
64
-      shift->content(@_);
65
-    }
66
-  );
67
-
68
-  $app->helper(url_with => \&_url_with);
35
+  $app->helper(url_with      => \&_url_with);
69 36
 }
70 37
 
71 38
 sub _content {
... ...
@@ -94,7 +61,10 @@ sub _current_route {
94 61
   return $endpoint->name eq shift;
95 62
 }
96 63
 
97
-sub _dumper { shift; Data::Dumper->new([@_])->Indent(1)->Terse(1)->Dump }
64
+sub _dumper {
65
+  my $self = shift;
66
+  return Data::Dumper->new([@_])->Indent(1)->Sortkeys(1)->Terse(1)->Dump;
67
+}
98 68
 
99 69
 sub _include {
100 70
   my $self     = shift;
... ...
@@ -110,7 +80,7 @@ sub _include {
110 80
   my @keys = keys %$args;
111 81
   local @{$self->stash}{@keys} = @{$args}{@keys};
112 82
 
113
-  return $self->render_partial(layout => $layout, extend => $extends);
83
+  return $self->render(partial => 1, layout => $layout, extend => $extends);
114 84
 }
115 85
 
116 86
 sub _url_with {
... ...
@@ -229,23 +199,6 @@ only available in the partial template.
229 199
 Render this template with a layout. All additional values get merged into the
230 200
 C<stash>.
231 201
 
232
-=head2 memorize
233
-
234
-  %= memorize begin
235
-    %= time
236
-  % end
237
-  %= memorize {expires => time + 1} => begin
238
-    %= time
239
-  % end
240
-  %= memorize foo => begin
241
-    %= time
242
-  % end
243
-  %= memorize foo => {expires => time + 1} => begin
244
-    %= time
245
-  % end
246
-
247
-Memorize block result in memory and prevent future execution.
248
-
249 202
 =head2 param
250 203
 
251 204
   %= param 'foo'
+12 -14
mojo/lib/Mojolicious/Plugin/EPLRenderer.pm
... ...
@@ -16,11 +16,13 @@ sub _epl {
16 16
   return undef unless defined $path;
17 17
 
18 18
   # Cached
19
-  my $cache = $renderer->cache;
20 19
   my $key   = delete $options->{cache} || $path;
21
-  my $mt    = $cache->get($key) || Mojo::Template->new;
20
+  my $cache = $renderer->cache;
21
+  my $mt    = $cache->get($key);
22
+  $mt ||= $cache->set($key => Mojo::Template->new)->get($key);
23
+  my $log = $c->app->log;
22 24
   if ($mt->compiled) {
23
-    $c->app->log->debug("Rendering cached @{[$mt->name]}.");
25
+    $log->debug("Rendering cached @{[$mt->name]}.");
24 26
     $$output = $mt->interpret($c);
25 27
   }
26 28
 
... ...
@@ -29,7 +31,7 @@ sub _epl {
29 31
 
30 32
     # Inline
31 33
     if (defined $inline) {
32
-      $c->app->log->debug('Rendering inline template.');
34
+      $log->debug('Rendering inline template.');
33 35
       $$output = $mt->name('inline template')->render($inline, $c);
34 36
     }
35 37
 
... ...
@@ -40,24 +42,20 @@ sub _epl {
40 42
 
41 43
       # Try template
42 44
       if (-r $path) {
43
-        $c->app->log->debug(qq{Rendering template "$t".});
44
-        $$output = $mt->name("template $t")->render_file($path, $c);
45
+        $log->debug(qq{Rendering template "$t".});
46
+        $$output = $mt->name(qq{template "$t"})->render_file($path, $c);
45 47
       }
46 48
 
47 49
       # Try DATA section
48 50
       elsif (my $d = $renderer->get_data_template($options)) {
49
-        $c->app->log->debug(qq{Rendering template "$t" from DATA section.});
50
-        $$output = $mt->name("template $t from DATA section")->render($d, $c);
51
+        $log->debug(qq{Rendering template "$t" from DATA section.});
52
+        $$output
53
+          = $mt->name(qq{template "$t" from DATA section})->render($d, $c);
51 54
       }
52 55
 
53 56
       # No template
54
-      else {
55
-        $c->app->log->debug(qq{Template "$t" not found.}) and return undef;
56
-      }
57
+      else { $log->debug(qq{Template "$t" not found.}) and return undef }
57 58
     }
58
-
59
-    # Cache
60
-    $cache->set($key => $mt);
61 59
   }
62 60
 
63 61
   # Exception or success
+1 -1
mojo/lib/Mojolicious/Plugin/HeaderCondition.pm
... ...
@@ -76,7 +76,7 @@ L<Mojolicious::Plugin> and implements the following new ones.
76 76
 
77 77
   $plugin->register(Mojolicious->new);
78 78
 
79
-Register condition in L<Mojolicious> application.
79
+Register conditions in L<Mojolicious> application.
80 80
 
81 81
 =head1 SEE ALSO
82 82
 
+5 -2
mojo/lib/Mojolicious/Plugin/JSONConfig.pm
... ...
@@ -40,7 +40,7 @@ Mojolicious::Plugin::JSONConfig - JSON configuration plugin
40 40
 
41 41
 =head1 SYNOPSIS
42 42
 
43
-  # myapp.json
43
+  # myapp.json (it's just JSON with embedded Perl)
44 44
   {
45 45
     "foo"       : "bar",
46 46
     "music_dir" : "<%= app->home->rel_dir('music') %>"
... ...
@@ -48,15 +48,18 @@ Mojolicious::Plugin::JSONConfig - JSON configuration plugin
48 48
 
49 49
   # Mojolicious
50 50
   my $config = $self->plugin('JSONConfig');
51
+  say $config->{foo};
51 52
 
52 53
   # Mojolicious::Lite
53 54
   my $config = plugin 'JSONConfig';
55
+  say $config->{foo};
54 56
 
55 57
   # foo.html.ep
56 58
   %= $config->{foo}
57 59
 
58 60
   # The configuration is available application wide
59 61
   my $config = app->config;
62
+  say $config->{foo};
60 63
 
61 64
   # Everything can be customized with options
62 65
   my $config = plugin JSONConfig => {file => '/etc/myapp.conf'};
... ...
@@ -111,7 +114,7 @@ Process content with C<render> and parse it with L<Mojo::JSON>.
111 114
   my $config = $plugin->register(Mojolicious->new);
112 115
   my $config = $plugin->register(Mojolicious->new, {file => '/etc/foo.conf'});
113 116
 
114
-Register plugin in L<Mojolicious> application.
117
+Register plugin in L<Mojolicious> application and merge configuration.
115 118
 
116 119
 =head2 render
117 120
 
+3 -3
mojo/lib/Mojolicious/Plugin/Mount.pm
... ...
@@ -41,13 +41,13 @@ Mojolicious::Plugin::Mount - Application mount plugin
41 41
   $example->to(message => 'It works great!');
42 42
 
43 43
   # Mount application with host
44
-  plugin Mount => {'mojolicio.us' => '/home/sri/myapp.pl'};
44
+  plugin Mount => {'example.com' => '/home/sri/myapp.pl'};
45 45
 
46 46
   # Host and path
47
-  plugin Mount => {'mojolicio.us/myapp' => '/home/sri/myapp.pl'};
47
+  plugin Mount => {'example.com/myapp' => '/home/sri/myapp.pl'};
48 48
 
49 49
   # Or even hosts with wildcard subdomains
50
-  plugin Mount => {'*.mojolicio.us/myapp' => '/home/sri/myapp.pl'};
50
+  plugin Mount => {'*.example.com/myapp' => '/home/sri/myapp.pl'};
51 51
 
52 52
 =head1 DESCRIPTION
53 53
 
+4 -7
mojo/lib/Mojolicious/Plugin/PODRenderer.pm
... ...
@@ -4,7 +4,7 @@ use Mojo::Base 'Mojolicious::Plugin';
4 4
 use Mojo::Asset::File;
5 5
 use Mojo::ByteStream 'b';
6 6
 use Mojo::DOM;
7
-use Mojo::Util 'url_escape';
7
+use Mojo::Util qw'slurp url_escape';
8 8
 BEGIN {eval {require Pod::Simple::HTML; import Pod::Simple::HTML}}
9 9
 BEGIN {eval {require Pod::Simple::Search; import Pod::Simple::Search}}
10 10
 
... ...
@@ -44,10 +44,7 @@ sub _perldoc {
44 44
   my $path = Pod::Simple::Search->new->find($module, @PATHS);
45 45
   return $self->redirect_to("http://metacpan.org/module/$module")
46 46
     unless $path && -r $path;
47
-
48
-  # Turn POD into HTML
49
-  open my $file, '<', $path;
50
-  my $html = _pod_to_html(join '', <$file>);
47
+  my $html = _pod_to_html(slurp $path);
51 48
 
52 49
   # Rewrite links
53 50
   my $dom     = Mojo::DOM->new("$html");
... ...
@@ -81,7 +78,7 @@ sub _perldoc {
81 78
       # Anchor and text
82 79
       my $name = my $text = $e->all_text;
83 80
       $name =~ s/\s+/_/g;
84
-      $name =~ s/\W//g;
81
+      $name =~ s/[^\w\-]//g;
85 82
       my $anchor = $name;
86 83
       my $i      = 1;
87 84
       $anchor = $name . $i++ while $anchors{$anchor}++;
... ...
@@ -206,7 +203,7 @@ L<Mojolicious::Plugin> and implements the following new ones.
206 203
   my $route = $plugin->register(Mojolicious->new);
207 204
   my $route = $plugin->register(Mojolicious->new, {name => 'foo'});
208 205
 
209
-Register renderer in L<Mojolicious> application.
206
+Register renderer and helper in L<Mojolicious> application.
210 207
 
211 208
 =head1 SEE ALSO
212 209
 
+6 -12
mojo/lib/Mojolicious/Plugin/TagHelpers.pm
... ...
@@ -1,7 +1,7 @@
1 1
 package Mojolicious::Plugin::TagHelpers;
2 2
 use Mojo::Base 'Mojolicious::Plugin';
3 3
 
4
-use Mojo::ByteStream 'b';
4
+use Mojo::ByteStream;
5 5
 use Mojo::Util 'xml_escape';
6 6
 
7 7
 sub register {
... ...
@@ -13,14 +13,6 @@ sub register {
13 13
     $app->helper("${name}_field" => sub { _input(@_, type => $name) });
14 14
   }
15 15
 
16
-  # DEPRECATED in Rainbow!
17
-  $app->helper(
18
-    base_tag => sub {
19
-      warn "base_tag is DEPRECATED!!!\n";
20
-      _tag('base', href => shift->req->url->base, @_);
21
-    }
22
-  );
23
-
24 16
   $app->helper(check_box =>
25 17
       sub { _input(shift, shift, value => shift, @_, type => 'checkbox') });
26 18
   $app->helper(file_field =>
... ...
@@ -220,7 +212,7 @@ sub _tag {
220 212
   else { $tag .= ' />' }
221 213
 
222 214
   # Prevent escaping
223
-  return b($tag);
215
+  return Mojo::ByteStream->new($tag);
224 216
 }
225 217
 
226 218
 sub _text_area {
... ...
@@ -361,7 +353,7 @@ Generate file input element.
361 353
     %= text_field 'first_name'
362 354
     %= submit_button
363 355
   % end
364
-  %= form_for 'http://kraih.com/login' => (method => 'POST') => begin
356
+  %= form_for 'http://example.com/login' => (method => 'POST') => begin
365 357
     %= text_field 'first_name'
366 358
     %= submit_button
367 359
   % end
... ...
@@ -381,7 +373,7 @@ but not C<GET>, a C<method> attribute will be automatically added.
381 373
     <input name="first_name" />
382 374
     <input value="Ok" type="submit" />
383 375
   </form>
384
-  <form action="http://kraih.com/login" method="POST">
376
+  <form action="http://example.com/login" method="POST">
385 377
     <input name="first_name" />
386 378
     <input value="Ok" type="submit" />
387 379
   </form>
... ...
@@ -440,6 +432,7 @@ Generate portable script tag for C<Javascript> asset.
440 432
   %= link_to index => {format => 'txt'} => (class => 'links') => begin
441 433
     Home
442 434
   % end
435
+  %= link_to Contact => Mojo::URL->new('mailto:sri@example.com')
443 436
   <%= link_to index => begin %>Home<% end %>
444 437
   <%= link_to '/path/to/file' => begin %>File<% end %>
445 438
   <%= link_to 'http://mojolicio.us' => begin %>Mojolicious<% end %>
... ...
@@ -453,6 +446,7 @@ capitalized link target as content.
453 446
   <a class="links" href="/path/to/index.txt">
454 447
     Home
455 448
   </a>
449
+  <a href="mailto:sri@example.com">Contact</a>
456 450
   <a href="/path/to/index">Home</a>
457 451
   <a href="/path/to/file">File</a>
458 452
   <a href="http://mojolicio.us">Mojolicious</a>
+1 -10
mojo/lib/Mojolicious/Plugins.pm
... ...
@@ -101,8 +101,7 @@ Renderer for plain embedded Perl templates, loaded automatically.
101 101
 
102 102
 =item L<Mojolicious::Plugin::EPRenderer>
103 103
 
104
-Renderer for more sophisiticated embedded Perl templates, loaded
105
-automatically.
104
+Renderer for more sophisticated embedded Perl templates, loaded automatically.
106 105
 
107 106
 =item L<Mojolicious::Plugin::HeaderCondition>
108 107
 
... ...
@@ -121,14 +120,6 @@ Mount whole L<Mojolicious> applications.
121 120
 Renderer for turning POD into HTML and documentation browser for
122 121
 L<Mojolicious::Guides>.
123 122
 
124
-=item L<Mojolicious::Plugin::PoweredBy>
125
-
126
-Add an C<X-Powered-By> header to outgoing responses, loaded automatically.
127
-
128
-=item L<Mojolicious::Plugin::RequestTimer>
129
-
130
-Log timing information, loaded automatically.
131
-
132 123
 =item L<Mojolicious::Plugin::TagHelpers>
133 124
 
134 125
 Template specific helper collection, loaded automatically.
+49 -51
mojo/lib/Mojolicious/Renderer.pm
... ...
@@ -6,7 +6,7 @@ use Mojo::Cache;
6 6
 use Mojo::JSON;
7 7
 use Mojo::Home;
8 8
 use Mojo::Loader;
9
-use Mojo::Util qw(encode slurp);
9
+use Mojo::Util qw(decamelize encode slurp);
10 10
 
11 11
 has cache   => sub { Mojo::Cache->new };
12 12
 has classes => sub { ['main'] };
... ...
@@ -24,13 +24,10 @@ my %TEMPLATES = map { $_ => slurp $HOME->rel_file($_) } @{$HOME->list_files};
24 24
 
25 25
 sub new {
26 26
   my $self = shift->SUPER::new(@_);
27
-
28
-  $self->add_handler(
29
-    json => sub { ${$_[2]} = Mojo::JSON->new->encode($_[3]->{json}) });
30
-  $self->add_handler(data => sub { ${$_[2]} = $_[3]->{data} });
31
-  $self->add_handler(text => sub { ${$_[2]} = $_[3]->{text} });
32
-
33
-  return $self;
27
+  $self->add_handler(data => sub { ${$_[2]} = $_[3]{data} });
28
+  $self->add_handler(text => sub { ${$_[2]} = $_[3]{text} });
29
+  return $self->add_handler(
30
+    json => sub { ${$_[2]} = Mojo::JSON->new->encode($_[3]{json}) });
34 31
 }
35 32
 
36 33
 sub add_handler { shift->_add(handlers => @_) }
... ...
@@ -66,69 +63,56 @@ sub render {
66 63
   # Merge stash and arguments
67 64
   @{$stash}{keys %$args} = values %$args;
68 65
 
69
-  # Extract important stash values
70 66
   my $options = {
71 67
     encoding => $self->encoding,
72 68
     handler  => $stash->{handler},
73 69
     template => delete $stash->{template}
74 70
   };
75
-  my $data   = delete $stash->{data};
76
-  my $format = $options->{format} = $stash->{format} || $self->default_format;
77 71
   my $inline = $options->{inline} = delete $stash->{inline};
78
-  my $json   = delete $stash->{json};
79
-  my $text   = delete $stash->{text};
80 72
   $options->{handler} = defined $options->{handler} ? $options->{handler} : $self->default_handler if defined $inline;
81
-
82
-  # Text
83
-  my $output;
84
-  my $content = $stash->{'mojo.content'} ||= {};
85
-  if (defined $text) {
86
-    $self->handlers->{text}->($self, $c, \$output, {text => $text});
87
-    $content->{content} = $output
88
-      if ($c->stash->{extends} || $c->stash->{layout});
89
-  }
73
+  $options->{format} = $stash->{format} || $self->default_format;
90 74
 
91 75
   # Data
92
-  elsif (defined $data) {
76
+  my $output;
77
+  if (defined(my $data = delete $stash->{data})) {
93 78
     $self->handlers->{data}->($self, $c, \$output, {data => $data});
94
-    $content->{content} = $output
95
-      if ($c->stash->{extends} || $c->stash->{layout});
79
+    return $output, $options->{format};
96 80
   }
97 81
 
98 82
   # JSON
99
-  elsif (defined $json) {
83
+  elsif (my $json = delete $stash->{json}) {
100 84
     $self->handlers->{json}->($self, $c, \$output, {json => $json});
101
-    $format = 'json';
102
-    $content->{content} = $output
103
-      if ($c->stash->{extends} || $c->stash->{layout});
85
+    return $output, 'json';
86
+  }
87
+
88
+  # Text
89
+  elsif (defined(my $text = delete $stash->{text})) {
90
+    $self->handlers->{text}->($self, $c, \$output, {text => $text});
104 91
   }
105 92
 
106 93
   # Template or templateless handler
107 94
   else {
108
-    return undef unless $self->_render_template($c, \$output, $options);
109
-    $content->{content} = $output
110
-      if ($c->stash->{extends} || $c->stash->{layout});
95
+    $options->{template} ||= $self->_generate_template($c);
96
+    return unless $self->_render_template($c, \$output, $options);
111 97
   }
112 98
 
113
-  # Extendable content
114
-  if (!$json && !defined $data) {
115
-
116
-    # Extends
117
-    while ((my $extends = $self->_extends($c)) && !defined $inline) {
118
-      $options->{handler}  = $stash->{handler};
119
-      $options->{format}   = $stash->{format} || $self->default_format;
120
-      $options->{template} = $extends;
121
-      $self->_render_template($c, \$output, $options);
122
-      $content->{content} = $output
123
-        if $content->{content} !~ /\S/ && $output =~ /\S/;
124
-    }
125
-
126
-    # Encoding
127
-    $output = encode $options->{encoding}, $output
128
-      if !$partial && $options->{encoding} && $output;
99
+  # Extends
100
+  my $content = $stash->{'mojo.content'} ||= {};
101
+  local $content->{content} = $output if $stash->{extends} || $stash->{layout};
102
+  while ((my $extends = $self->_extends($stash)) && !defined $inline) {
103
+    $options->{handler}  = $stash->{handler};
104
+    $options->{format}   = $stash->{format} || $self->default_format;
105
+    $options->{template} = $extends;
106
+    $self->_render_template($c, \$output, $options);
107
+    $content->{content} = $output
108
+      if $content->{content} !~ /\S/ && $output =~ /\S/;
129 109
   }
130 110
 
131
-  return $output, $format;
111
+  # Encoding
112
+  $output = encode $options->{encoding}, $output
113
+    if !$partial && $options->{encoding} && $output;
114
+
115
+  return $output, $options->{format};
132 116
 }
133 117
 
134 118
 sub template_name {
... ...
@@ -187,13 +171,27 @@ sub _detect_handler {
187 171
 }
188 172
 
189 173
 sub _extends {
190
-  my ($self, $c) = @_;
191
-  my $stash  = $c->stash;
174
+  my ($self, $stash) = @_;
192 175
   my $layout = delete $stash->{layout};
193 176
   $stash->{extends} ||= join('/', 'layouts', $layout) if $layout;
194 177
   return delete $stash->{extends};
195 178
 }
196 179
 
180
+sub _generate_template {
181
+  my ($self, $c) = @_;
182
+
183
+  # Normal default template
184
+  my $stash      = $c->stash;
185
+  my $controller = $stash->{controller};
186
+  my $action     = $stash->{action};
187
+  return join '/', split(/-/, decamelize($controller)), $action
188
+    if $controller && $action;
189
+
190
+  # Try the route name if we don't have controller and action
191
+  return undef unless my $endpoint = $c->match->endpoint;
192
+  return $endpoint->name;
193
+}
194
+
197 195
 sub _render_template {
198 196
   my ($self, $c, $output, $options) = @_;
199 197
 
+54 -82
mojo/lib/Mojolicious/Routes.pm
... ...
@@ -20,57 +20,59 @@ sub add_shortcut  { shift->_add(shortcuts  => @_) }
20 20
 sub auto_render {
21 21
   my ($self, $c) = @_;
22 22
   my $stash = $c->stash;
23
-  return undef if $stash->{'mojo.rendered'} || $c->tx->is_websocket;
24
-  $c->render or ($stash->{'mojo.routed'} or $c->render_not_found);
23
+  return if $stash->{'mojo.rendered'};
24
+  $c->render_maybe or $stash->{'mojo.routed'} or $c->render_not_found;
25 25
 }
26 26
 
27 27
 sub dispatch {
28 28
   my ($self, $c) = @_;
29 29
 
30
-  # Prepare path
30
+  # Path (partial path gets priority)
31 31
   my $req  = $c->req;
32 32
   my $path = $c->stash->{path};
33 33
   if (defined $path) { $path = "/$path" if $path !~ m!^/! }
34 34
   else               { $path = $req->url->path->to_route }
35 35
 
36
-  # Prepare match
37
-  my $method = $req->method;
38
-  my $websocket = $c->tx->is_websocket ? 1 : 0;
39
-  my $m = Mojolicious::Routes::Match->new($method => $path, $websocket);
40
-  $c->match($m);
36
+  # Method (HEAD will be treated as GET)
37
+  my $method = uc $req->method;
38
+  $method = 'GET' if $method eq 'HEAD';
41 39
 
42 40
   # Check cache
43 41
   my $cache = $self->cache;
44
-  if ($cache && (my $cached = $cache->get("$method:$path:$websocket"))) {
45
-    $m->root($self)->endpoint($cached->{endpoint});
46
-    $m->stack($cached->{stack})->captures($cached->{captures});
42
+  my $ws    = $c->tx->is_websocket ? 1 : 0;
43
+  my $match = Mojolicious::Routes::Match->new(root => $self);
44
+  $c->match($match);
45
+  if ($cache && (my $cached = $cache->get("$method:$path:$ws"))) {
46
+    $match->endpoint($cached->{endpoint})->stack($cached->{stack});
47 47
   }
48 48
 
49 49
   # Check routes
50 50
   else {
51
-    $m->match($self, $c);
51
+    my $options = {method => $method, path => $path, websocket => $ws};
52
+    $match->match($c => $options);
52 53
 
53 54
     # Cache routes without conditions
54
-    if ($cache && (my $endpoint = $m->endpoint)) {
55
-      $cache->set(
56
-        "$method:$path:$websocket" => {
57
-          endpoint => $endpoint,
58
-          stack    => $m->stack,
59
-          captures => $m->captures
60
-        }
61
-      ) unless $endpoint->has_conditions;
55
+    if ($cache && (my $endpoint = $match->endpoint)) {
56
+      my $result = {endpoint => $endpoint, stack => $match->stack};
57
+      $cache->set("$method:$path:$ws" => $result)
58
+        unless $endpoint->has_conditions;
62 59
     }
63 60
   }
64 61
 
65 62
   # Dispatch
66
-  return undef unless $m && @{$m->stack};
67
-  return undef if $self->_walk($c);
63
+  return undef unless $self->_walk($c);
68 64
   $self->auto_render($c);
69 65
   return 1;
70 66
 }
71 67
 
72 68
 sub hide { push @{shift->hidden}, @_ }
73 69
 
70
+sub is_hidden {
71
+  my ($self, $method) = @_;
72
+  my $hiding = $self->{hiding} ||= {map { $_ => 1 } @{$self->hidden}};
73
+  return !!($hiding->{$method} || index($method, '_') == 0);
74
+}
75
+
74 76
 sub lookup {
75 77
   my ($self, $name) = @_;
76 78
   my $reverse = $self->{reverse} ||= {};
... ...
@@ -79,18 +81,6 @@ sub lookup {
79 81
   return $reverse->{$name} = $route;
80 82
 }
81 83
 
82
-# DEPRECATED in Rainbow!
83
-sub namespace {
84
-  warn <<EOF;
85
-Mojolicious::Routes->namespace is DEPRECATED in favor of
86
-Mojolicious::Routes->namespaces!
87
-EOF
88
-  my $self = shift;
89
-  return $self->namespaces->[0] unless @_;
90
-  $self->namespaces->[0] = shift;
91
-  return $self;
92
-}
93
-
94 84
 sub route {
95 85
   shift->add_child(Mojolicious::Routes::Route->new(@_))->children->[-1];
96 86
 }
... ...
@@ -102,11 +92,11 @@ sub _add {
102 92
 }
103 93
 
104 94
 sub _callback {
105
-  my ($self, $c, $field, $staging) = @_;
95
+  my ($self, $c, $field, $nested) = @_;
106 96
   $c->stash->{'mojo.routed'}++;
107 97
   $c->app->log->debug('Routing to a callback.');
108 98
   my $continue = $field->{cb}->($c);
109
-  return !$staging || $continue ? 1 : undef;
99
+  return !$nested || $continue ? 1 : undef;
110 100
 }
111 101
 
112 102
 sub _class {
... ...
@@ -117,7 +107,7 @@ sub _class {
117 107
 
118 108
   # Application class
119 109
   my @classes;
120
-  my $class = camelize $field->{controller} || '';
110
+  my $class = $field->{controller} ? camelize($field->{controller}) : '';
121 111
   if ($field->{app}) { push @classes, $field->{app} }
122 112
 
123 113
   # Specific namespace
... ...
@@ -150,7 +140,7 @@ sub _class {
150 140
 }
151 141
 
152 142
 sub _controller {
153
-  my ($self, $c, $field, $staging) = @_;
143
+  my ($self, $c, $field, $nested) = @_;
154 144
 
155 145
   # Load and instantiate controller/application
156 146
   my $app;
... ...
@@ -178,7 +168,7 @@ sub _controller {
178 168
 
179 169
     # Try to call action
180 170
     if (my $sub = $app->can($method)) {
181
-      $c->stash->{'mojo.routed'}++ unless $staging;
171
+      $c->stash->{'mojo.routed'}++ unless $nested;
182 172
       $continue = $app->$sub;
183 173
     }
184 174
 
... ...
@@ -186,7 +176,7 @@ sub _controller {
186 176
     else { $log->debug('Action not found in controller.') }
187 177
   }
188 178
 
189
-  return !$staging || $continue ? 1 : undef;
179
+  return !$nested || $continue ? 1 : undef;
190 180
 }
191 181
 
192 182
 sub _load {
... ...
@@ -205,10 +195,9 @@ sub _method {
205 195
   my ($self, $c, $field) = @_;
206 196
 
207 197
   # Hidden
208
-  $self->{hiding} = {map { $_ => 1 } @{$self->hidden}} unless $self->{hiding};
209 198
   return undef unless my $method = $field->{action};
210 199
   $c->app->log->debug(qq{Action "$method" is not allowed.}) and return undef
211
-    if $self->{hiding}{$method} || index($method, '_') == 0;
200
+    if $self->is_hidden($method);
212 201
 
213 202
   # Invalid
214 203
   $c->app->log->debug(qq{Action "$method" is invalid.}) and return undef
... ...
@@ -220,28 +209,28 @@ sub _method {
220 209
 sub _walk {
221 210
   my ($self, $c) = @_;
222 211
 
223
-  my $stack   = $c->match->stack;
224
-  my $stash   = $c->stash;
225
-  my $staging = @$stack;
212
+  my $stack = $c->match->stack;
213
+  return undef unless my $nested = @$stack;
214
+  my $stash = $c->stash;
226 215
   $stash->{'mojo.captures'} ||= {};
227 216
   for my $field (@$stack) {
228
-    $staging--;
217
+    $nested--;
229 218
 
230
-    # Merge in captures
219
+    # Merge captures into stash
231 220
     my @keys = keys %$field;
232 221
     @{$stash}{@keys} = @{$stash->{'mojo.captures'}}{@keys} = values %$field;
233 222
 
234 223
     # Dispatch
235 224
     my $continue
236 225
       = $field->{cb}
237
-      ? $self->_callback($c, $field, $staging)
238
-      : $self->_controller($c, $field, $staging);
226
+      ? $self->_callback($c, $field, $nested)
227
+      : $self->_controller($c, $field, $nested);
239 228
 
240 229
     # Break the chain
241
-    return 1 if $staging && !$continue;
230
+    return undef if $nested && !$continue;
242 231
   }
243 232
 
244
-  return undef;
233
+  return 1;
245 234
 }
246 235
 
247 236
 1;
... ...
@@ -254,38 +243,15 @@ Mojolicious::Routes - Always find your destination with routes!
254 243
 
255 244
   use Mojolicious::Routes;
256 245
 
257
-  # New route tree
246
+  # Simple route
258 247
   my $r = Mojolicious::Routes->new;
248
+  $r->route('/')->to(controller => 'blog', action => 'welcome');
259 249
 
260
-  # Normal route matching "/articles" with parameters "controller" and
261
-  # "action"
262
-  $r->route('/articles')->to(controller => 'article', action => 'list');
263
-
264
-  # Route with a placeholder matching everything but "/" and "."
265
-  $r->route('/:controller')->to(action => 'list');
266
-
267
-  # Route with a placeholder and regex constraint
268
-  $r->route('/articles/:id', id => qr/\d+/)
269
-    ->to(controller => 'article', action => 'view');
270
-
271
-  # Route with an optional parameter "year"
272
-  $r->route('/archive/:year')
273
-    ->to(controller => 'archive', action => 'list', year => undef);
274
-
275
-  # Nested route for two actions sharing the same "controller" parameter
276
-  my $books = $r->route('/books/:id')->to(controller => 'book');
277
-  $books->route('/edit')->to(action => 'edit');
278
-  $books->route('/delete')->to(action => 'delete');
279
-
280
-  # Bridges can be used to chain multiple routes
281
-  $r->bridge->to(controller => 'foo', action =>'auth')
282
-    ->route('/blog')->to(action => 'list');
283
-
284
-  # Simplified Mojolicious::Lite style route generation is also possible
285
-  $r->get('/')->to(controller => 'blog', action => 'welcome');
250
+  # More advanced routes
286 251
   my $blog = $r->under('/blog');
287
-  $blog->post('/list')->to('blog#list');
288
-  $blog->get(sub { shift->render(text => 'Go away!') });
252
+  $blog->get('/list')->to('blog#list');
253
+  $blog->get('/:id' => [id => qr/\d+/])->to('blog#show', id => 23);
254
+  $blog->patch(sub { shift->render(text => 'Go away!', status => 405) });
289 255
 
290 256
 =head1 DESCRIPTION
291 257
 
... ...
@@ -328,7 +294,7 @@ Contains all available conditions.
328 294
   my $hidden = $r->hidden;
329 295
   $r         = $r->hidden([qw(attr has new)]);
330 296
 
331
-Controller methods and attributes that are hidden from routes, defaults to
297
+Controller methods and attributes that are hidden from router, defaults to
332 298
 C<attr>, C<has>, C<new> and C<tap>.
333 299
 
334 300
 =head2 namespaces
... ...
@@ -381,7 +347,13 @@ Match routes with L<Mojolicious::Routes::Match> and dispatch.
381 347
 
382 348
   $r = $r->hide(qw(foo bar));
383 349
 
384
-Hide controller methods and attributes from routes.
350
+Hide controller methods and attributes from router.
351
+
352
+=head2 is_hidden
353
+
354
+  my $success = $r->is_hidden('foo');
355
+
356
+Check if controller method or attribute is hidden from router.
385 357
 
386 358
 =head2 lookup
387 359
 
+83 -124
mojo/lib/Mojolicious/Routes/Match.pm
... ...
@@ -1,34 +1,50 @@
1 1
 package Mojolicious::Routes::Match;
2 2
 use Mojo::Base -base;
3 3
 
4
-has captures => sub { {} };
5 4
 has [qw(endpoint root)];
6 5
 has stack => sub { [] };
7 6
 
8
-sub new {
9
-  my $self = shift->SUPER::new;
10
-  $self->{method}    = uc shift;
11
-  $self->{path}      = shift;
12
-  $self->{websocket} = shift;
13
-  return $self;
7
+sub match { $_[0]->_match($_[0]->root, $_[1], $_[2]) }
8
+
9
+sub path_for {
10
+  my ($self, $name, %values) = (shift, _values(@_));
11
+
12
+  # Current route
13
+  my $endpoint;
14
+  if ($name && $name eq 'current' || !$name) {
15
+    return unless $endpoint = $self->endpoint;
16
+  }
17
+
18
+  # Find endpoint
19
+  else { return $name unless $endpoint = $self->root->lookup($name) }
20
+
21
+  # Merge values (clear format)
22
+  my $captures = $self->stack->[-1] || {};
23
+  %values = (%$captures, format => undef, %values);
24
+  my $pattern = $endpoint->pattern;
25
+  $values{format}
26
+    = defined $captures->{format}
27
+    ? $captures->{format}
28
+    : $pattern->defaults->{format}
29
+    if $pattern->constraints->{format};
30
+
31
+  my $path = $endpoint->render('', \%values);
32
+  return wantarray ? ($path, $endpoint->has_websocket) : $path;
14 33
 }
15 34
 
16
-sub match {
17
-  my ($self, $r, $c) = @_;
35
+sub _match {
36
+  my ($self, $r, $c, $options) = @_;
18 37
 
19 38
   # Pattern
20
-  $self->root($r) unless $self->root;
21
-  my $path    = $self->{path};
22
-  my $pattern = $r->pattern;
23
-  return unless my $captures = $pattern->shape_match(\$path, $r->is_endpoint);
24
-  $self->{path} = $path;
25
-  $captures = {%{$self->captures}, %$captures};
39
+  my $path = $options->{path};
40
+  return
41
+    unless my $captures = $r->pattern->match_partial(\$path, $r->is_endpoint);
42
+  local $options->{path} = $path;
43
+  $captures = $self->{captures} = {%{$self->{captures} || {}}, %$captures};
26 44
 
27 45
   # Method
28
-  if (my $methods = $r->via) {
29
-    my $method = $self->{method} eq 'HEAD' ? 'GET' : $self->{method};
30
-    return unless grep { $_ eq $method } @$methods;
31
-  }
46
+  my $methods = $r->via;
47
+  return if $methods && !grep { $_ eq $options->{method} } @$methods;
32 48
 
33 49
   # Conditions
34 50
   if (my $over = $r->over) {
... ...
@@ -40,7 +56,7 @@ sub match {
40 56
   }
41 57
 
42 58
   # WebSocket
43
-  return if $r->is_websocket && !$self->{websocket};
59
+  return if $r->is_websocket && !$options->{websocket};
44 60
 
45 61
   # Partial
46 62
   my $empty = !length $path || $path eq '/';
... ...
@@ -50,93 +66,45 @@ sub match {
50 66
     $empty = 1;
51 67
   }
52 68
 
53
-  # Update stack
54
-  $self->captures($captures);
69
+  # Endpoint (or bridge)
55 70
   my $endpoint = $r->is_endpoint;
56
-  if ($r->inline || ($endpoint && $empty)) {
71
+  if (($endpoint && $empty) || $r->inline) {
57 72
     push @{$self->stack}, {%$captures};
73
+    return $self->endpoint($r) if $endpoint && $empty;
58 74
     delete $captures->{$_} for qw(app cb);
59 75
   }
60 76
 
61
-  # Endpoint
62
-  return $self->endpoint($r) if $endpoint && $empty;
63
-
64 77
   # Match children
65 78
   my $snapshot = [@{$self->stack}];
66 79
   for my $child (@{$r->children}) {
67
-    $self->match($child, $c);
80
+    $self->_match($child, $c, $options);
68 81
 
69 82
     # Endpoint found
70 83
     return if $self->endpoint;
71 84
 
72 85
     # Reset
73
-    $self->{path} = $path;
74
-    if   ($r->parent) { $self->captures($captures)->stack([@$snapshot]) }
75
-    else              { $self->captures({})->stack([]) }
86
+    if   ($r->parent) { $self->stack([@$snapshot])->{captures} = $captures }
87
+    else              { $self->stack([])->{captures}           = {} }
76 88
   }
77 89
 }
78 90
 
79
-sub path_for {
80
-  my $self = shift;
81
-
82
-  # Single argument
83
-  my (%values, $name);
84
-  if (@_ == 1) {
85
-
86
-    # Hash
87
-    %values = %{shift()} if ref $_[0] eq 'HASH';
88
-
89
-    # Name
90
-    $name = $_[0] if $_[0];
91
-  }
92
-
93
-  # Multiple arguments
94
-  elsif (@_ > 1) {
95
-
96
-    # Odd
97
-    if (@_ % 2) { ($name, %values) = (shift, @_) }
98
-
99
-    # Even
100
-    else {
91
+sub _values {
101 92
 
102
-      # Name and hash
103
-      if (ref $_[1] eq 'HASH') { ($name, %values) = (shift, %{shift()}) }
93
+  # Hash or name (one)
94
+  return ref $_[0] eq 'HASH' ? (undef, %{shift()}) : @_ if @_ == 1;
104 95
 
105
-      # Just values
106
-      else { %values = @_ }
96
+  # Name and values (odd)
97
+  return shift, @_ if @_ % 2;
107 98
 
108
-    }
109
-  }
110
-
111
-  # Current route
112
-  my $endpoint;
113
-  if ($name && $name eq 'current' || !$name) {
114
-    return unless $endpoint = $self->endpoint;
115
-  }
116
-
117
-  # Find endpoint
118
-  else { return $name unless $endpoint = $self->root->lookup($name) }
119
-
120
-  # Merge values
121
-  my $captures = $self->captures;
122
-  %values = (%$captures, format => undef, %values);
123
-  my $pattern = $endpoint->pattern;
124
-  $values{format}
125
-    = defined $captures->{format}
126
-    ? $captures->{format}
127
-    : $pattern->defaults->{format}
128
-    if $pattern->constraints->{format};
129
-
130
-  # Render
131
-  my $path = $endpoint->render('', \%values);
132
-  return wantarray ? ($path, $endpoint->has_websocket) : $path;
99
+  # Name and hash or just values (even)
100
+  return ref $_[1] eq 'HASH' ? (shift, %{shift()}) : (undef, @_);
133 101
 }
134 102
 
135 103
 1;
136 104
 
137 105
 =head1 NAME
138 106
 
139
-Mojolicious::Routes::Match - Routes visitor
107
+Mojolicious::Routes::Match - Find routes
140 108
 
141 109
 =head1 SYNOPSIS
142 110
 
... ...
@@ -146,49 +114,47 @@ Mojolicious::Routes::Match - Routes visitor
146 114
 
147 115
   # Routes
148 116
   my $r = Mojolicious::Routes->new;
149
-  $r->get('/foo')->to(action => 'foo');
150
-  $r->put('/bar')->to(action => 'bar');
117
+  $r->get('/:controller/:action');
118
+  $r->put('/:controller/:action');
151 119
 
152 120
   # Match
153 121
   my $c = Mojolicious::Controller->new;
154
-  my $m = Mojolicious::Routes::Match->new(PUT => '/bar');
155
-  $m->match($r, $c);
156
-  say $m->captures->{action};
122
+  my $match = Mojolicious::Routes::Match->new(root => $r);
123
+  $match->match($c => {method => 'PUT', path => '/foo/bar'});
124
+  say $match->stack->[0]{controller};
125
+  say $match->stack->[0]{action};
126
+
127
+  # Render
128
+  say $match->path_for;
129
+  say $match->path_for(action => 'baz');
157 130
 
158 131
 =head1 DESCRIPTION
159 132
 
160
-L<Mojolicious::Routes::Match> is a visitor for L<Mojolicious::Routes>
133
+L<Mojolicious::Routes::Match> finds routes in L<Mojolicious::Routes>
161 134
 structures.
162 135
 
163 136
 =head1 ATTRIBUTES
164 137
 
165 138
 L<Mojolicious::Routes::Match> implements the following attributes.
166 139
 
167
-=head2 captures
168
-
169
-  my $captures = $m->captures;
170
-  $m           = $m->captures({foo => 'bar'});
171
-
172
-Captured parameters.
173
-
174 140
 =head2 endpoint
175 141
 
176
-  my $endpoint = $m->endpoint;
177
-  $m           = $m->endpoint(Mojolicious::Routes->new);
142
+  my $endpoint = $match->endpoint;
143
+  $match       = $match->endpoint(Mojolicious::Routes::Route->new);
178 144
 
179
-The route endpoint that actually matched.
145
+The route endpoint that matched.
180 146
 
181 147
 =head2 root
182 148
 
183
-  my $root = $m->root;
184
-  $m       = $m->root($routes);
149
+  my $root = $match->root;
150
+  $match   = $match->root(Mojolicious::Routes->new);
185 151
 
186
-The root of the route tree.
152
+The root of the route structure.
187 153
 
188 154
 =head2 stack
189 155
 
190
-  my $stack = $m->stack;
191
-  $m        = $m->stack([{foo => 'bar'}]);
156
+  my $stack = $match->stack;
157
+  $match    = $match->stack([{foo => 'bar'}]);
192 158
 
193 159
 Captured parameters with nesting history.
194 160
 
... ...
@@ -197,33 +163,26 @@ Captured parameters with nesting history.
197 163
 L<Mojolicious::Routes::Match> inherits all methods from L<Mojo::Base> and
198 164
 implements the following new ones.
199 165
 
200
-=head2 new
201
-
202
-  my $m = Mojolicious::Routes::Match->new(GET => '/foo');
203
-  my $m = Mojolicious::Routes::Match->new(GET => '/foo', $ws);
204
-
205
-Construct a new L<Mojolicious::Routes::Match> object.
206
-
207 166
 =head2 match
208 167
 
209
-  $m->match(Mojolicious::Routes->new, Mojolicious::Controller->new);
168
+  $match->match(Mojolicious::Controller->new, {method => 'GET', path => '/'});
210 169
 
211
-Match against a route tree.
170
+Match controller and options against C<root> to find appropriate C<endpoint>.
212 171
 
213 172
 =head2 path_for
214 173
 
215
-  my $path        = $m->path_for;
216
-  my $path        = $m->path_for(foo => 'bar');
217
-  my $path        = $m->path_for({foo => 'bar'});
218
-  my $path        = $m->path_for('named');
219
-  my $path        = $m->path_for('named', foo => 'bar');
220
-  my $path        = $m->path_for('named', {foo => 'bar'});
221
-  my ($path, $ws) = $m->path_for;
222
-  my ($path, $ws) = $m->path_for(foo => 'bar');
223
-  my ($path, $ws) = $m->path_for({foo => 'bar'});
224
-  my ($path, $ws) = $m->path_for('named');
225
-  my ($path, $ws) = $m->path_for('named', foo => 'bar');
226
-  my ($path, $ws) = $m->path_for('named', {foo => 'bar'});
174
+  my $path        = $match->path_for;
175
+  my $path        = $match->path_for(foo => 'bar');
176
+  my $path        = $match->path_for({foo => 'bar'});
177
+  my $path        = $match->path_for('named');
178
+  my $path        = $match->path_for('named', foo => 'bar');
179
+  my $path        = $match->path_for('named', {foo => 'bar'});
180
+  my ($path, $ws) = $match->path_for;
181
+  my ($path, $ws) = $match->path_for(foo => 'bar');
182
+  my ($path, $ws) = $match->path_for({foo => 'bar'});
183
+  my ($path, $ws) = $match->path_for('named');
184
+  my ($path, $ws) = $match->path_for('named', foo => 'bar');
185
+  my ($path, $ws) = $match->path_for('named', {foo => 'bar'});
227 186
 
228 187
 Render matching route with parameters into path.
229 188
 
+61 -61
mojo/lib/Mojolicious/Routes/Pattern.pm
... ...
@@ -14,8 +14,37 @@ sub new { shift->SUPER::new->parse(@_) }
14 14
 
15 15
 sub match {
16 16
   my ($self, $path, $detect) = @_;
17
-  my $result = $self->shape_match(\$path, $detect);
18
-  return !$path || $path eq '/' ? $result : undef;
17
+  my $captures = $self->match_partial(\$path, $detect);
18
+  return !$path || $path eq '/' ? $captures : undef;
19
+}
20
+
21
+sub match_partial {
22
+  my ($self, $pathref, $detect) = @_;
23
+
24
+  # Compile on demand
25
+  my $regex = $self->regex || $self->_compile;
26
+  my $format
27
+    = $detect ? ($self->format_regex || $self->_compile_format) : undef;
28
+
29
+  # Match
30
+  return undef unless my @captures = $$pathref =~ $regex;
31
+  $$pathref =~ s/$regex//;
32
+
33
+  # Merge captures
34
+  my $captures = {%{$self->defaults}};
35
+  for my $placeholder (@{$self->placeholders}) {
36
+    last unless @captures;
37
+    my $capture = shift @captures;
38
+    $captures->{$placeholder} = $capture if defined $capture;
39
+  }
40
+
41
+  # Format
42
+  my $constraint = $self->constraints->{format};
43
+  return $captures if !$detect || defined $constraint && !$constraint;
44
+  if ($$pathref =~ s!^/?$format!!) { $captures->{format} = $1 }
45
+  elsif ($constraint) { return undef unless $captures->{format} }
46
+
47
+  return $captures;
19 48
 }
20 49
 
21 50
 sub parse {
... ...
@@ -36,8 +65,10 @@ sub render {
36 65
   my $format = ($values ||= {})->{format};
37 66
   $values = {%{$self->defaults}, %$values};
38 67
 
39
-  my $string   = '';
40
-  my $optional = 1;
68
+  # Placeholders can only be optional without a format
69
+  my $optional = !$format;
70
+
71
+  my $str = '';
41 72
   for my $token (reverse @{$self->tree}) {
42 73
     my $op       = $token->[0];
43 74
     my $rendered = '';
... ...
@@ -52,7 +83,7 @@ sub render {
52 83
     }
53 84
 
54 85
     # Placeholder, relaxed or wildcard
55
-    elsif (grep { $_ eq $op } qw(placeholder relaxed wildcard)) {
86
+    elsif ($op eq 'placeholder' || $op eq 'relaxed' || $op eq 'wildcard') {
56 87
       my $name = $token->[1];
57 88
       $rendered = defined $values->{$name} ? $values->{$name} : '';
58 89
       my $default = $self->defaults->{$name};
... ...
@@ -60,49 +91,20 @@ sub render {
60 91
       elsif ($optional) { $rendered = '' }
61 92
     }
62 93
 
63
-    $string = "$rendered$string";
94
+    $str = "$rendered$str";
64 95
   }
65 96
 
66 97
   # Format is optional
67
-  $string ||= '/';
68
-  return $render && $format ? "$string.$format" : $string;
69
-}
70
-
71
-sub shape_match {
72
-  my ($self, $pathref, $detect) = @_;
73
-
74
-  # Compile on demand
75
-  my $regex = $self->regex || $self->_compile;
76
-  my $format
77
-    = $detect ? ($self->format_regex || $self->_compile_format) : undef;
78
-
79
-  # Match
80
-  return undef unless my @captures = $$pathref =~ $regex;
81
-  $$pathref =~ s/($regex)//;
82
-
83
-  # Merge captures
84
-  my $result = {%{$self->defaults}};
85
-  for my $placeholder (@{$self->placeholders}) {
86
-    last unless @captures;
87
-    my $capture = shift @captures;
88
-    $result->{$placeholder} = $capture if defined $capture;
89
-  }
90
-
91
-  # Format
92
-  my $constraint = $self->constraints->{format};
93
-  return $result if !$detect || defined $constraint && !$constraint;
94
-  if ($$pathref =~ s!^/?$format!!) { $result->{format} = $1 }
95
-  elsif ($constraint) { return undef unless $result->{format} }
96
-
97
-  return $result;
98
+  $str ||= '/';
99
+  return $render && $format ? "$str.$format" : $str;
98 100
 }
99 101
 
100 102
 sub _compile {
101 103
   my $self = shift;
102 104
 
103 105
   my $block = my $regex = '';
104
-  my $constraints = $self->constraints;
105 106
   my $optional    = 1;
107
+  my $constraints = $self->constraints;
106 108
   my $defaults    = $self->defaults;
107 109
   for my $token (reverse @{$self->tree}) {
108 110
     my $op       = $token->[0];
... ...
@@ -110,10 +112,7 @@ sub _compile {
110 112
 
111 113
     # Slash
112 114
     if ($op eq 'slash') {
113
-
114
-      # Full block
115
-      $block = $optional ? "(?:/$block)?" : "/$block";
116
-      $regex = "$block$regex";
115
+      $regex = ($optional ? "(?:/$block)?" : "/$block") . $regex;
117 116
       $block = '';
118 117
       next;
119 118
     }
... ...
@@ -125,7 +124,7 @@ sub _compile {
125 124
     }
126 125
 
127 126
     # Placeholder
128
-    elsif (grep { $_ eq $op } qw(placeholder relaxed wildcard)) {
127
+    elsif ($op eq 'placeholder' || $op eq 'relaxed' || $op eq 'wildcard') {
129 128
       my $name = $token->[1];
130 129
       unshift @{$self->placeholders}, $name;
131 130
 
... ...
@@ -153,7 +152,6 @@ sub _compile {
153 152
   # Not rooted with a slash
154 153
   $regex = "$block$regex" if $block;
155 154
 
156
-  # Compile
157 155
   return $self->regex(qr/^$regex/s)->regex;
158 156
 }
159 157
 
... ...
@@ -210,7 +208,7 @@ sub _tokenize {
210 208
     }
211 209
 
212 210
     # Relaxed or wildcard start (upgrade when quoted)
213
-    elsif (grep { $_ eq $char } $relaxed, $wildcard) {
211
+    elsif ($char eq $relaxed || $char eq $wildcard) {
214 212
       push @tree, ['placeholder', ''] unless $quoted;
215 213
       $tree[-1][0] = $state = $char eq $relaxed ? 'relaxed' : 'wildcard';
216 214
     }
... ...
@@ -259,8 +257,8 @@ Mojolicious::Routes::Pattern - Routes pattern engine
259 257
   my $pattern = Mojolicious::Routes::Pattern->new('/test/:name');
260 258
 
261 259
   # Match routes
262
-  my $result  = $pattern->match('/test/sebastian');
263
-  say $result->{name};
260
+  my $captures = $pattern->match('/test/sebastian');
261
+  say $captures->{name};
264 262
 
265 263
 =head1 DESCRIPTION
266 264
 
... ...
@@ -343,9 +341,10 @@ Character indicating a relaxed placeholder, defaults to C<#>.
343 341
 =head2 tree
344 342
 
345 343
   my $tree = $pattern->tree;
346
-  $pattern = $pattern->tree([ ... ]);
344
+  $pattern = $pattern->tree([['slash'], ['text', 'foo']]);
347 345
 
348
-Pattern in parsed form.
346
+Pattern in parsed form. Note that this structure should only be used very
347
+carefully since it is very dynamic.
349 348
 
350 349
 =head2 wildcard_start
351 350
 
... ...
@@ -366,22 +365,31 @@ implements the following new ones.
366 365
     = Mojolicious::Routes::Pattern->new('/:action', action => qr/\w+/);
367 366
   my $pattern = Mojolicious::Routes::Pattern->new(format => 0);
368 367
 
369
-Construct a new L<Mojolicious::Routes::Pattern> object.
368
+Construct a new L<Mojolicious::Routes::Pattern> object and C<parse> pattern if
369
+necessary.
370 370
 
371 371
 =head2 match
372 372
 
373
-  my $result = $pattern->match('/foo/bar');
374
-  my $result = $pattern->match('/foo/bar', 1);
373
+  my $captures = $pattern->match('/foo/bar');
374
+  my $captures = $pattern->match('/foo/bar', 1);
375 375
 
376 376
 Match pattern against entire path, format detection is disabled by default.
377 377
 
378
+=head2 match_partial
379
+
380
+  my $captures = $pattern->match_partial(\$path);
381
+  my $captures = $pattern->match_partial(\$path, 1);
382
+
383
+Match pattern against path and remove matching parts, format detection is
384
+disabled by default.
385
+
378 386
 =head2 parse
379 387
 
380 388
   $pattern = $pattern->parse('/:action');
381 389
   $pattern = $pattern->parse('/:action', action => qr/\w+/);
382 390
   $pattern = $pattern->parse(format => 0);
383 391
 
384
-Parse a raw pattern.
392
+Parse pattern.
385 393
 
386 394
 =head2 render
387 395
 
... ...
@@ -391,14 +399,6 @@ Parse a raw pattern.
391 399
 Render pattern into a path with parameters, format rendering is disabled by
392 400
 default.
393 401
 
394
-=head2 shape_match
395
-
396
-  my $result = $pattern->shape_match(\$path);
397
-  my $result = $pattern->shape_match(\$path, 1);
398
-
399
-Match pattern against path and remove matching parts, format detection is
400
-disabled by default.
401
-
402 402
 =head1 SEE ALSO
403 403
 
404 404
 L<Mojolicious>, L<Mojolicious::Guides>, L<http://mojolicio.us>.
+27 -48
mojo/lib/Mojolicious/Routes/Route.pm
... ...
@@ -12,12 +12,11 @@ has pattern    => sub { Mojolicious::Routes::Pattern->new };
12 12
 sub AUTOLOAD {
13 13
   my $self = shift;
14 14
 
15
-  # Method
16 15
   my ($package, $method) = our $AUTOLOAD =~ /^([\w:]+)::(\w+)$/;
17 16
   croak "Undefined subroutine &${package}::$method called"
18 17
     unless blessed $self && $self->isa(__PACKAGE__);
19 18
 
20
-  # Call shortcut
19
+  # Call shortcut with current route
21 20
   croak qq{Can't locate object method "$method" via package "$package"}
22 21
     unless my $shortcut = $self->root->shortcuts->{$method};
23 22
   return $self->$shortcut(@_);
... ...
@@ -152,51 +151,25 @@ sub route {
152 151
 sub to {
153 152
   my $self = shift;
154 153
 
155
-  # No argument
156 154
   my $pattern = $self->pattern;
157 155
   return $pattern->defaults unless @_;
156
+  my ($shortcut, %defaults) = _defaults(@_);
158 157
 
159
-  # Single argument
160
-  my ($shortcut, $defaults);
161
-  if (@_ == 1) {
162
-    $defaults = shift if ref $_[0] eq 'HASH';
163
-    $shortcut = shift if $_[0];
164
-  }
165
-
166
-  # Multiple arguments
167
-  else {
168
-
169
-    # Odd
170
-    if (@_ % 2) { ($shortcut, $defaults) = (shift, {@_}) }
171
-
172
-    # Even
173
-    else {
174
-
175
-      # Shortcut and defaults
176
-      if (ref $_[1] eq 'HASH') { ($shortcut, $defaults) = (shift, shift) }
177
-
178
-      # Just defaults
179
-      else { $defaults = {@_} }
180
-    }
181
-  }
182
-
183
-  # Shortcut
184 158
   if ($shortcut) {
185 159
 
186
-    # App
160
+    # Application
187 161
     if (ref $shortcut || $shortcut =~ /^[\w:]+$/) {
188
-      $defaults->{app} = $shortcut;
162
+      $defaults{app} = $shortcut;
189 163
     }
190 164
 
191 165
     # Controller and action
192 166
     elsif ($shortcut =~ /^([\w\-:]+)?\#(\w+)?$/) {
193
-      $defaults->{controller} = $1 if defined $1;
194
-      $defaults->{action}     = $2 if defined $2;
167
+      $defaults{controller} = $1 if defined $1;
168
+      $defaults{action}     = $2 if defined $2;
195 169
     }
196 170
   }
197 171
 
198
-  # Merge defaults
199
-  $pattern->defaults({%{$pattern->defaults}, %$defaults}) if $defaults;
172
+  $pattern->defaults({%{$pattern->defaults}, %defaults});
200 173
 
201 174
   return $self;
202 175
 }
... ...
@@ -224,6 +197,18 @@ sub websocket {
224 197
   return $route;
225 198
 }
226 199
 
200
+sub _defaults {
201
+
202
+  # Hash or shortcut (one)
203
+  return ref $_[0] eq 'HASH' ? (undef, %{shift()}) : @_ if @_ == 1;
204
+
205
+  # Shortcut and values (odd)
206
+  return shift, @_ if @_ % 2;
207
+
208
+  # Shortcut and hash or just values (even)
209
+  return ref $_[1] eq 'HASH' ? (shift, %{shift()}) : (undef, @_);
210
+}
211
+
227 212
 sub _generate_route {
228 213
   my ($self, $methods, @args) = @_;
229 214
 
... ...
@@ -328,11 +313,12 @@ implements the following new ones.
328 313
   my $r = Mojolicious::Routes::Route->new;
329 314
   my $r = Mojolicious::Routes::Route->new('/:controller/:action');
330 315
 
331
-Construct a new L<Mojolicious::Routes::Route> object.
316
+Construct a new L<Mojolicious::Routes::Route> object and <parse> pattern if
317
+necessary.
332 318
 
333 319
 =head2 add_child
334 320
 
335
-  $r = $r->add_child(Mojolicious::Route->new);
321
+  $r = $r->add_child(Mojolicious::Routes::Route->new);
336 322
 
337 323
 Add a new child to this route, it will be automatically removed from its
338 324
 current parent if necessary.
... ...
@@ -375,19 +361,12 @@ L<Mojolicious::Lite> tutorial for more argument variations.
375 361
 =head2 detour
376 362
 
377 363
   $r = $r->detour(action => 'foo');
378
-  $r = $r->detour({action => 'foo'});
379 364
   $r = $r->detour('controller#action');
380
-  $r = $r->detour('controller#action', foo => 'bar');
381
-  $r = $r->detour('controller#action', {foo => 'bar'});
382
-  $r = $r->detour(Mojolicious->new);
383 365
   $r = $r->detour(Mojolicious->new, foo => 'bar');
384
-  $r = $r->detour(Mojolicious->new, {foo => 'bar'});
385
-  $r = $r->detour('MyApp');
386
-  $r = $r->detour('MyApp', foo => 'bar');
387 366
   $r = $r->detour('MyApp', {foo => 'bar'});
388 367
 
389 368
 Set default parameters for this route and allow partial matching to simplify
390
-application embedding.
369
+application embedding, takes the same arguments as C<to>.
391 370
 
392 371
 =head2 find
393 372
 
... ...
@@ -475,7 +454,7 @@ routing cache, since conditions are too complex for caching.
475 454
   $r = $r->parse('/:action', action => qr/\w+/);
476 455
   $r = $r->parse(format => 0);
477 456
 
478
-Parse a pattern.
457
+Parse pattern.
479 458
 
480 459
 =head2 patch
481 460
 
... ...
@@ -559,7 +538,7 @@ Set default parameters for this route.
559 538
 
560 539
 =head2 to_string
561 540
 
562
-  my $string = $r->to_string;
541
+  my $str = $r->to_string;
563 542
 
564 543
 Stringify the whole route.
565 544
 
... ...
@@ -589,9 +568,9 @@ restrictions.
589 568
 
590 569
 =head2 websocket
591 570
 
592
-  my $websocket = $r->websocket('/:foo' => sub {...});
571
+  my $ws = $r->websocket('/:foo' => sub {...});
593 572
 
594
-Generate route matching only C<WebSocket> handshakes. See also the
573
+Generate route matching only WebSocket handshakes. See also the
595 574
 L<Mojolicious::Lite> tutorial for more argument variations.
596 575
 
597 576
   $r->websocket('/echo')->to('example#echo');
+3 -3
mojo/lib/Mojolicious/Static.pm
... ...
@@ -6,7 +6,6 @@ use Mojo::Asset::File;
6 6
 use Mojo::Asset::Memory;
7 7
 use Mojo::Home;
8 8
 use Mojo::Loader;
9
-use Mojo::Path;
10 9
 
11 10
 has classes => sub { ['main'] };
12 11
 has paths   => sub { [] };
... ...
@@ -23,8 +22,9 @@ sub dispatch {
23 22
 
24 23
   # Canonical path
25 24
   my $stash = $c->stash;
26
-  my $path = $stash->{path} || $c->req->url->path->clone->canonicalize;
27
-  return undef unless my @parts = @{Mojo::Path->new("$path")->parts};
25
+  my $path  = $c->req->url->path;
26
+  $path = $stash->{path} ? $path->new($stash->{path}) : $path->clone;
27
+  return undef unless my @parts = @{$path->canonicalize->parts};
28 28
 
29 29
   # Serve static file and prevent directory traversal
30 30
   return undef if $parts[0] eq '..' || !$self->serve($c, join('/', @parts));
+32 -33
mojo/lib/Mojolicious/Types.pm
... ...
@@ -3,32 +3,32 @@ use Mojo::Base -base;
3 3
 
4 4
 has types => sub {
5 5
   {
6
-    appcache => 'text/cache-manifest',
7
-    atom     => 'application/atom+xml',
8
-    bin      => 'application/octet-stream',
9
-    css      => 'text/css',
10
-    gif      => 'image/gif',
11
-    gz       => 'application/x-gzip',
12
-    htm      => 'text/html',
13
-    html     => 'text/html;charset=UTF-8',
14
-    ico      => 'image/x-icon',
15
-    jpeg     => 'image/jpeg',
16
-    jpg      => 'image/jpeg',
17
-    js       => 'application/javascript',
18
-    json     => 'application/json',
19
-    mp3      => 'audio/mpeg',
20
-    mp4      => 'video/mp4',
21
-    ogg      => 'audio/ogg',
22
-    ogv      => 'video/ogg',
23
-    pdf      => 'application/pdf',
24
-    png      => 'image/png',
25
-    rss      => 'application/rss+xml',
26
-    svg      => 'image/svg+xml',
27
-    txt      => 'text/plain',
28
-    webm     => 'video/webm',
29
-    woff     => 'application/font-woff',
6
+    appcache => ['text/cache-manifest'],
7
+    atom     => ['application/atom+xml'],
8
+    bin      => ['application/octet-stream'],
9
+    css      => ['text/css'],
10
+    gif      => ['image/gif'],
11
+    gz       => ['application/x-gzip'],
12
+    htm      => ['text/html'],
13
+    html     => ['text/html;charset=UTF-8'],
14
+    ico      => ['image/x-icon'],
15
+    jpeg     => ['image/jpeg'],
16
+    jpg      => ['image/jpeg'],
17
+    js       => ['application/javascript'],
18
+    json     => ['application/json'],
19
+    mp3      => ['audio/mpeg'],
20
+    mp4      => ['video/mp4'],
21
+    ogg      => ['audio/ogg'],
22
+    ogv      => ['video/ogg'],
23
+    pdf      => ['application/pdf'],
24
+    png      => ['image/png'],
25
+    rss      => ['application/rss+xml'],
26
+    svg      => ['image/svg+xml'],
27
+    txt      => ['text/plain'],
28
+    webm     => ['video/webm'],
29
+    woff     => ['application/font-woff'],
30 30
     xml      => ['application/xml', 'text/xml'],
31
-    zip      => 'application/zip'
31
+    zip      => ['application/zip']
32 32
   };
33 33
 };
34 34
 
... ...
@@ -40,24 +40,23 @@ sub detect {
40 40
   /^\s*([^,; ]+)(?:\s*\;\s*q=(\d+(?:\.\d+)?))?\s*$/i
41 41
     and $types{lc $1} = defined $2 ? $2 : 1
42 42
     for split /,/, defined $accept ? $accept : '';
43
-  my @types = sort { $types{$b} <=> $types{$a} } sort keys %types;
44
-  return [] if !$prioritize && @types > 1;
43
+  my @detected = sort { $types{$b} <=> $types{$a} } sort keys %types;
44
+  return [] if !$prioritize && @detected > 1;
45 45
 
46 46
   # Detect extensions from MIME types
47 47
   my %reverse;
48 48
   my $types = $self->types;
49 49
   for my $ext (sort keys %$types) {
50
-    my @types = ref $types->{$ext} ? @{$types->{$ext}} : ($types->{$ext});
50
+    my @types = @{$types->{$ext}};
51 51
     push @{$reverse{$_}}, $ext for map { s/\;.*$//; lc $_ } @types;
52 52
   }
53
-  return [map { @{defined $reverse{$_} ? $reverse{$_} : []} } @types];
53
+  return [map { @{defined $reverse{$_} ? $reverse{$_} : []} } @detected];
54 54
 }
55 55
 
56 56
 sub type {
57 57
   my ($self, $ext, $type) = @_;
58
-  my $types = $self->types;
59
-  return ref $types->{$ext} ? $types->{$ext}[0] : $types->{$ext} unless $type;
60
-  $types->{$ext} = $type;
58
+  return $self->types->{$ext}[0] unless $type;
59
+  $self->types->{$ext} = ref $type ? $type : [$type];
61 60
   return $self;
62 61
 }
63 62
 
... ...
@@ -115,7 +114,7 @@ L<Mojolicious::Types> implements the following attributes.
115 114
 =head2 types
116 115
 
117 116
   my $map = $types->types;
118
-  $types  = $types->types({png => 'image/png'});
117
+  $types  = $types->types({png => ['image/png']});
119 118
 
120 119
 List of MIME types.
121 120
 
+6 -4
mojo/lib/Mojolicious/public/mojo/jquery/jquery.js
... ...
@@ -1,4 +1,6 @@
1
-/*! jQuery v1.9.0 | (c) 2005, 2012 jQuery Foundation, Inc. | jquery.org/license */(function(e,t){"use strict";function n(e){var t=e.length,n=st.type(e);return st.isWindow(e)?!1:1===e.nodeType&&t?!0:"array"===n||"function"!==n&&(0===t||"number"==typeof t&&t>0&&t-1 in e)}function r(e){var t=Tt[e]={};return st.each(e.match(lt)||[],function(e,n){t[n]=!0}),t}function i(e,n,r,i){if(st.acceptData(e)){var o,a,s=st.expando,u="string"==typeof n,l=e.nodeType,c=l?st.cache:e,f=l?e[s]:e[s]&&s;if(f&&c[f]&&(i||c[f].data)||!u||r!==t)return f||(l?e[s]=f=K.pop()||st.guid++:f=s),c[f]||(c[f]={},l||(c[f].toJSON=st.noop)),("object"==typeof n||"function"==typeof n)&&(i?c[f]=st.extend(c[f],n):c[f].data=st.extend(c[f].data,n)),o=c[f],i||(o.data||(o.data={}),o=o.data),r!==t&&(o[st.camelCase(n)]=r),u?(a=o[n],null==a&&(a=o[st.camelCase(n)])):a=o,a}}function o(e,t,n){if(st.acceptData(e)){var r,i,o,a=e.nodeType,u=a?st.cache:e,l=a?e[st.expando]:st.expando;if(u[l]){if(t&&(r=n?u[l]:u[l].data)){st.isArray(t)?t=t.concat(st.map(t,st.camelCase)):t in r?t=[t]:(t=st.camelCase(t),t=t in r?[t]:t.split(" "));for(i=0,o=t.length;o>i;i++)delete r[t[i]];if(!(n?s:st.isEmptyObject)(r))return}(n||(delete u[l].data,s(u[l])))&&(a?st.cleanData([e],!0):st.support.deleteExpando||u!=u.window?delete u[l]:u[l]=null)}}}function a(e,n,r){if(r===t&&1===e.nodeType){var i="data-"+n.replace(Nt,"-$1").toLowerCase();if(r=e.getAttribute(i),"string"==typeof r){try{r="true"===r?!0:"false"===r?!1:"null"===r?null:+r+""===r?+r:wt.test(r)?st.parseJSON(r):r}catch(o){}st.data(e,n,r)}else r=t}return r}function s(e){var t;for(t in e)if(("data"!==t||!st.isEmptyObject(e[t]))&&"toJSON"!==t)return!1;return!0}function u(){return!0}function l(){return!1}function c(e,t){do e=e[t];while(e&&1!==e.nodeType);return e}function f(e,t,n){if(t=t||0,st.isFunction(t))return st.grep(e,function(e,r){var i=!!t.call(e,r,e);return i===n});if(t.nodeType)return st.grep(e,function(e){return e===t===n});if("string"==typeof t){var r=st.grep(e,function(e){return 1===e.nodeType});if(Wt.test(t))return st.filter(t,r,!n);t=st.filter(t,r)}return st.grep(e,function(e){return st.inArray(e,t)>=0===n})}function p(e){var t=zt.split("|"),n=e.createDocumentFragment();if(n.createElement)for(;t.length;)n.createElement(t.pop());return n}function d(e,t){return e.getElementsByTagName(t)[0]||e.appendChild(e.ownerDocument.createElement(t))}function h(e){var t=e.getAttributeNode("type");return e.type=(t&&t.specified)+"/"+e.type,e}function g(e){var t=nn.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function m(e,t){for(var n,r=0;null!=(n=e[r]);r++)st._data(n,"globalEval",!t||st._data(t[r],"globalEval"))}function y(e,t){if(1===t.nodeType&&st.hasData(e)){var n,r,i,o=st._data(e),a=st._data(t,o),s=o.events;if(s){delete a.handle,a.events={};for(n in s)for(r=0,i=s[n].length;i>r;r++)st.event.add(t,n,s[n][r])}a.data&&(a.data=st.extend({},a.data))}}function v(e,t){var n,r,i;if(1===t.nodeType){if(n=t.nodeName.toLowerCase(),!st.support.noCloneEvent&&t[st.expando]){r=st._data(t);for(i in r.events)st.removeEvent(t,i,r.handle);t.removeAttribute(st.expando)}"script"===n&&t.text!==e.text?(h(t).text=e.text,g(t)):"object"===n?(t.parentNode&&(t.outerHTML=e.outerHTML),st.support.html5Clone&&e.innerHTML&&!st.trim(t.innerHTML)&&(t.innerHTML=e.innerHTML)):"input"===n&&Zt.test(e.type)?(t.defaultChecked=t.checked=e.checked,t.value!==e.value&&(t.value=e.value)):"option"===n?t.defaultSelected=t.selected=e.defaultSelected:("input"===n||"textarea"===n)&&(t.defaultValue=e.defaultValue)}}function b(e,n){var r,i,o=0,a=e.getElementsByTagName!==t?e.getElementsByTagName(n||"*"):e.querySelectorAll!==t?e.querySelectorAll(n||"*"):t;if(!a)for(a=[],r=e.childNodes||e;null!=(i=r[o]);o++)!n||st.nodeName(i,n)?a.push(i):st.merge(a,b(i,n));return n===t||n&&st.nodeName(e,n)?st.merge([e],a):a}function x(e){Zt.test(e.type)&&(e.defaultChecked=e.checked)}function T(e,t){if(t in e)return t;for(var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=Nn.length;i--;)if(t=Nn[i]+n,t in e)return t;return r}function w(e,t){return e=t||e,"none"===st.css(e,"display")||!st.contains(e.ownerDocument,e)}function N(e,t){for(var n,r=[],i=0,o=e.length;o>i;i++)n=e[i],n.style&&(r[i]=st._data(n,"olddisplay"),t?(r[i]||"none"!==n.style.display||(n.style.display=""),""===n.style.display&&w(n)&&(r[i]=st._data(n,"olddisplay",S(n.nodeName)))):r[i]||w(n)||st._data(n,"olddisplay",st.css(n,"display")));for(i=0;o>i;i++)n=e[i],n.style&&(t&&"none"!==n.style.display&&""!==n.style.display||(n.style.display=t?r[i]||"":"none"));return e}function C(e,t,n){var r=mn.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function k(e,t,n,r,i){for(var o=n===(r?"border":"content")?4:"width"===t?1:0,a=0;4>o;o+=2)"margin"===n&&(a+=st.css(e,n+wn[o],!0,i)),r?("content"===n&&(a-=st.css(e,"padding"+wn[o],!0,i)),"margin"!==n&&(a-=st.css(e,"border"+wn[o]+"Width",!0,i))):(a+=st.css(e,"padding"+wn[o],!0,i),"padding"!==n&&(a+=st.css(e,"border"+wn[o]+"Width",!0,i)));return a}function E(e,t,n){var r=!0,i="width"===t?e.offsetWidth:e.offsetHeight,o=ln(e),a=st.support.boxSizing&&"border-box"===st.css(e,"boxSizing",!1,o);if(0>=i||null==i){if(i=un(e,t,o),(0>i||null==i)&&(i=e.style[t]),yn.test(i))return i;r=a&&(st.support.boxSizingReliable||i===e.style[t]),i=parseFloat(i)||0}return i+k(e,t,n||(a?"border":"content"),r,o)+"px"}function S(e){var t=V,n=bn[e];return n||(n=A(e,t),"none"!==n&&n||(cn=(cn||st("<iframe frameborder='0' width='0' height='0'/>").css("cssText","display:block !important")).appendTo(t.documentElement),t=(cn[0].contentWindow||cn[0].contentDocument).document,t.write("<!doctype html><html><body>"),t.close(),n=A(e,t),cn.detach()),bn[e]=n),n}function A(e,t){var n=st(t.createElement(e)).appendTo(t.body),r=st.css(n[0],"display");return n.remove(),r}function j(e,t,n,r){var i;if(st.isArray(t))st.each(t,function(t,i){n||kn.test(e)?r(e,i):j(e+"["+("object"==typeof i?t:"")+"]",i,n,r)});else if(n||"object"!==st.type(t))r(e,t);else for(i in t)j(e+"["+i+"]",t[i],n,r)}function D(e){return function(t,n){"string"!=typeof t&&(n=t,t="*");var r,i=0,o=t.toLowerCase().match(lt)||[];if(st.isFunction(n))for(;r=o[i++];)"+"===r[0]?(r=r.slice(1)||"*",(e[r]=e[r]||[]).unshift(n)):(e[r]=e[r]||[]).push(n)}}function L(e,n,r,i){function o(u){var l;return a[u]=!0,st.each(e[u]||[],function(e,u){var c=u(n,r,i);return"string"!=typeof c||s||a[c]?s?!(l=c):t:(n.dataTypes.unshift(c),o(c),!1)}),l}var a={},s=e===$n;return o(n.dataTypes[0])||!a["*"]&&o("*")}function H(e,n){var r,i,o=st.ajaxSettings.flatOptions||{};for(r in n)n[r]!==t&&((o[r]?e:i||(i={}))[r]=n[r]);return i&&st.extend(!0,e,i),e}function M(e,n,r){var i,o,a,s,u=e.contents,l=e.dataTypes,c=e.responseFields;for(o in c)o in r&&(n[c[o]]=r[o]);for(;"*"===l[0];)l.shift(),i===t&&(i=e.mimeType||n.getResponseHeader("Content-Type"));if(i)for(o in u)if(u[o]&&u[o].test(i)){l.unshift(o);break}if(l[0]in r)a=l[0];else{for(o in r){if(!l[0]||e.converters[o+" "+l[0]]){a=o;break}s||(s=o)}a=a||s}return a?(a!==l[0]&&l.unshift(a),r[a]):t}function q(e,t){var n,r,i,o,a={},s=0,u=e.dataTypes.slice(),l=u[0];if(e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u[1])for(n in e.converters)a[n.toLowerCase()]=e.converters[n];for(;i=u[++s];)if("*"!==i){if("*"!==l&&l!==i){if(n=a[l+" "+i]||a["* "+i],!n)for(r in a)if(o=r.split(" "),o[1]===i&&(n=a[l+" "+o[0]]||a["* "+o[0]])){n===!0?n=a[r]:a[r]!==!0&&(i=o[0],u.splice(s--,0,i));break}if(n!==!0)if(n&&e["throws"])t=n(t);else try{t=n(t)}catch(c){return{state:"parsererror",error:n?c:"No conversion from "+l+" to "+i}}}l=i}return{state:"success",data:t}}function _(){try{return new e.XMLHttpRequest}catch(t){}}function F(){try{return new e.ActiveXObject("Microsoft.XMLHTTP")}catch(t){}}function O(){return setTimeout(function(){Qn=t}),Qn=st.now()}function B(e,t){st.each(t,function(t,n){for(var r=(rr[t]||[]).concat(rr["*"]),i=0,o=r.length;o>i;i++)if(r[i].call(e,t,n))return})}function P(e,t,n){var r,i,o=0,a=nr.length,s=st.Deferred().always(function(){delete u.elem}),u=function(){if(i)return!1;for(var t=Qn||O(),n=Math.max(0,l.startTime+l.duration-t),r=n/l.duration||0,o=1-r,a=0,u=l.tweens.length;u>a;a++)l.tweens[a].run(o);return s.notifyWith(e,[l,o,n]),1>o&&u?n:(s.resolveWith(e,[l]),!1)},l=s.promise({elem:e,props:st.extend({},t),opts:st.extend(!0,{specialEasing:{}},n),originalProperties:t,originalOptions:n,startTime:Qn||O(),duration:n.duration,tweens:[],createTween:function(t,n){var r=st.Tween(e,l.opts,t,n,l.opts.specialEasing[t]||l.opts.easing);return l.tweens.push(r),r},stop:function(t){var n=0,r=t?l.tweens.length:0;if(i)return this;for(i=!0;r>n;n++)l.tweens[n].run(1);return t?s.resolveWith(e,[l,t]):s.rejectWith(e,[l,t]),this}}),c=l.props;for(R(c,l.opts.specialEasing);a>o;o++)if(r=nr[o].call(l,e,c,l.opts))return r;return B(l,c),st.isFunction(l.opts.start)&&l.opts.start.call(e,l),st.fx.timer(st.extend(u,{elem:e,anim:l,queue:l.opts.queue})),l.progress(l.opts.progress).done(l.opts.done,l.opts.complete).fail(l.opts.fail).always(l.opts.always)}function R(e,t){var n,r,i,o,a;for(n in e)if(r=st.camelCase(n),i=t[r],o=e[n],st.isArray(o)&&(i=o[1],o=e[n]=o[0]),n!==r&&(e[r]=o,delete e[n]),a=st.cssHooks[r],a&&"expand"in a){o=a.expand(o),delete e[r];for(n in o)n in e||(e[n]=o[n],t[n]=i)}else t[r]=i}function W(e,t,n){var r,i,o,a,s,u,l,c,f,p=this,d=e.style,h={},g=[],m=e.nodeType&&w(e);n.queue||(c=st._queueHooks(e,"fx"),null==c.unqueued&&(c.unqueued=0,f=c.empty.fire,c.empty.fire=function(){c.unqueued||f()}),c.unqueued++,p.always(function(){p.always(function(){c.unqueued--,st.queue(e,"fx").length||c.empty.fire()})})),1===e.nodeType&&("height"in t||"width"in t)&&(n.overflow=[d.overflow,d.overflowX,d.overflowY],"inline"===st.css(e,"display")&&"none"===st.css(e,"float")&&(st.support.inlineBlockNeedsLayout&&"inline"!==S(e.nodeName)?d.zoom=1:d.display="inline-block")),n.overflow&&(d.overflow="hidden",st.support.shrinkWrapBlocks||p.done(function(){d.overflow=n.overflow[0],d.overflowX=n.overflow[1],d.overflowY=n.overflow[2]}));for(r in t)if(o=t[r],Zn.exec(o)){if(delete t[r],u=u||"toggle"===o,o===(m?"hide":"show"))continue;g.push(r)}if(a=g.length){s=st._data(e,"fxshow")||st._data(e,"fxshow",{}),"hidden"in s&&(m=s.hidden),u&&(s.hidden=!m),m?st(e).show():p.done(function(){st(e).hide()}),p.done(function(){var t;st._removeData(e,"fxshow");for(t in h)st.style(e,t,h[t])});for(r=0;a>r;r++)i=g[r],l=p.createTween(i,m?s[i]:0),h[i]=s[i]||st.style(e,i),i in s||(s[i]=l.start,m&&(l.end=l.start,l.start="width"===i||"height"===i?1:0))}}function $(e,t,n,r,i){return new $.prototype.init(e,t,n,r,i)}function I(e,t){var n,r={height:e},i=0;for(t=t?1:0;4>i;i+=2-t)n=wn[i],r["margin"+n]=r["padding"+n]=e;return t&&(r.opacity=r.width=e),r}function z(e){return st.isWindow(e)?e:9===e.nodeType?e.defaultView||e.parentWindow:!1}var X,U,V=e.document,Y=e.location,J=e.jQuery,G=e.$,Q={},K=[],Z="1.9.0",et=K.concat,tt=K.push,nt=K.slice,rt=K.indexOf,it=Q.toString,ot=Q.hasOwnProperty,at=Z.trim,st=function(e,t){return new st.fn.init(e,t,X)},ut=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,lt=/\S+/g,ct=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,ft=/^(?:(<[\w\W]+>)[^>]*|#([\w-]*))$/,pt=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,dt=/^[\],:{}\s]*$/,ht=/(?:^|:|,)(?:\s*\[)+/g,gt=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,mt=/"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g,yt=/^-ms-/,vt=/-([\da-z])/gi,bt=function(e,t){return t.toUpperCase()},xt=function(){V.addEventListener?(V.removeEventListener("DOMContentLoaded",xt,!1),st.ready()):"complete"===V.readyState&&(V.detachEvent("onreadystatechange",xt),st.ready())};st.fn=st.prototype={jquery:Z,constructor:st,init:function(e,n,r){var i,o;if(!e)return this;if("string"==typeof e){if(i="<"===e.charAt(0)&&">"===e.charAt(e.length-1)&&e.length>=3?[null,e,null]:ft.exec(e),!i||!i[1]&&n)return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e);if(i[1]){if(n=n instanceof st?n[0]:n,st.merge(this,st.parseHTML(i[1],n&&n.nodeType?n.ownerDocument||n:V,!0)),pt.test(i[1])&&st.isPlainObject(n))for(i in n)st.isFunction(this[i])?this[i](n[i]):this.attr(i,n[i]);return this}if(o=V.getElementById(i[2]),o&&o.parentNode){if(o.id!==i[2])return r.find(e);this.length=1,this[0]=o}return this.context=V,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):st.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),st.makeArray(e,this))},selector:"",length:0,size:function(){return this.length},toArray:function(){return nt.call(this)},get:function(e){return null==e?this.toArray():0>e?this[this.length+e]:this[e]},pushStack:function(e){var t=st.merge(this.constructor(),e);return t.prevObject=this,t.context=this.context,t},each:function(e,t){return st.each(this,e,t)},ready:function(e){return st.ready.promise().done(e),this},slice:function(){return this.pushStack(nt.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(0>e?t:0);return this.pushStack(n>=0&&t>n?[this[n]]:[])},map:function(e){return this.pushStack(st.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:tt,sort:[].sort,splice:[].splice},st.fn.init.prototype=st.fn,st.extend=st.fn.extend=function(){var e,n,r,i,o,a,s=arguments[0]||{},u=1,l=arguments.length,c=!1;for("boolean"==typeof s&&(c=s,s=arguments[1]||{},u=2),"object"==typeof s||st.isFunction(s)||(s={}),l===u&&(s=this,--u);l>u;u++)if(null!=(e=arguments[u]))for(n in e)r=s[n],i=e[n],s!==i&&(c&&i&&(st.isPlainObject(i)||(o=st.isArray(i)))?(o?(o=!1,a=r&&st.isArray(r)?r:[]):a=r&&st.isPlainObject(r)?r:{},s[n]=st.extend(c,a,i)):i!==t&&(s[n]=i));return s},st.extend({noConflict:function(t){return e.$===st&&(e.$=G),t&&e.jQuery===st&&(e.jQuery=J),st},isReady:!1,readyWait:1,holdReady:function(e){e?st.readyWait++:st.ready(!0)},ready:function(e){if(e===!0?!--st.readyWait:!st.isReady){if(!V.body)return setTimeout(st.ready);st.isReady=!0,e!==!0&&--st.readyWait>0||(U.resolveWith(V,[st]),st.fn.trigger&&st(V).trigger("ready").off("ready"))}},isFunction:function(e){return"function"===st.type(e)},isArray:Array.isArray||function(e){return"array"===st.type(e)},isWindow:function(e){return null!=e&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?Q[it.call(e)]||"object":typeof e},isPlainObject:function(e){if(!e||"object"!==st.type(e)||e.nodeType||st.isWindow(e))return!1;try{if(e.constructor&&!ot.call(e,"constructor")&&!ot.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(n){return!1}var r;for(r in e);return r===t||ot.call(e,r)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw Error(e)},parseHTML:function(e,t,n){if(!e||"string"!=typeof e)return null;"boolean"==typeof t&&(n=t,t=!1),t=t||V;var r=pt.exec(e),i=!n&&[];return r?[t.createElement(r[1])]:(r=st.buildFragment([e],t,i),i&&st(i).remove(),st.merge([],r.childNodes))},parseJSON:function(n){return e.JSON&&e.JSON.parse?e.JSON.parse(n):null===n?n:"string"==typeof n&&(n=st.trim(n),n&&dt.test(n.replace(gt,"@").replace(mt,"]").replace(ht,"")))?Function("return "+n)():(st.error("Invalid JSON: "+n),t)},parseXML:function(n){var r,i;if(!n||"string"!=typeof n)return null;try{e.DOMParser?(i=new DOMParser,r=i.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(o){r=t}return r&&r.documentElement&&!r.getElementsByTagName("parsererror").length||st.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&st.trim(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(yt,"ms-").replace(vt,bt)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,t,r){var i,o=0,a=e.length,s=n(e);if(r){if(s)for(;a>o&&(i=t.apply(e[o],r),i!==!1);o++);else for(o in e)if(i=t.apply(e[o],r),i===!1)break}else if(s)for(;a>o&&(i=t.call(e[o],o,e[o]),i!==!1);o++);else for(o in e)if(i=t.call(e[o],o,e[o]),i===!1)break;return e},trim:at&&!at.call("\ufeff\u00a0")?function(e){return null==e?"":at.call(e)}:function(e){return null==e?"":(e+"").replace(ct,"")},makeArray:function(e,t){var r=t||[];return null!=e&&(n(Object(e))?st.merge(r,"string"==typeof e?[e]:e):tt.call(r,e)),r},inArray:function(e,t,n){var r;if(t){if(rt)return rt.call(t,e,n);for(r=t.length,n=n?0>n?Math.max(0,r+n):n:0;r>n;n++)if(n in t&&t[n]===e)return n}return-1},merge:function(e,n){var r=n.length,i=e.length,o=0;if("number"==typeof r)for(;r>o;o++)e[i++]=n[o];else for(;n[o]!==t;)e[i++]=n[o++];return e.length=i,e},grep:function(e,t,n){var r,i=[],o=0,a=e.length;for(n=!!n;a>o;o++)r=!!t(e[o],o),n!==r&&i.push(e[o]);return i},map:function(e,t,r){var i,o=0,a=e.length,s=n(e),u=[];if(s)for(;a>o;o++)i=t(e[o],o,r),null!=i&&(u[u.length]=i);else for(o in e)i=t(e[o],o,r),null!=i&&(u[u.length]=i);return et.apply([],u)},guid:1,proxy:function(e,n){var r,i,o;return"string"==typeof n&&(r=e[n],n=e,e=r),st.isFunction(e)?(i=nt.call(arguments,2),o=function(){return e.apply(n||this,i.concat(nt.call(arguments)))},o.guid=e.guid=e.guid||st.guid++,o):t},access:function(e,n,r,i,o,a,s){var u=0,l=e.length,c=null==r;if("object"===st.type(r)){o=!0;for(u in r)st.access(e,n,u,r[u],!0,a,s)}else if(i!==t&&(o=!0,st.isFunction(i)||(s=!0),c&&(s?(n.call(e,i),n=null):(c=n,n=function(e,t,n){return c.call(st(e),n)})),n))for(;l>u;u++)n(e[u],r,s?i:i.call(e[u],u,n(e[u],r)));return o?e:c?n.call(e):l?n(e[0],r):a},now:function(){return(new Date).getTime()}}),st.ready.promise=function(t){if(!U)if(U=st.Deferred(),"complete"===V.readyState)setTimeout(st.ready);else if(V.addEventListener)V.addEventListener("DOMContentLoaded",xt,!1),e.addEventListener("load",st.ready,!1);else{V.attachEvent("onreadystatechange",xt),e.attachEvent("onload",st.ready);var n=!1;try{n=null==e.frameElement&&V.documentElement}catch(r){}n&&n.doScroll&&function i(){if(!st.isReady){try{n.doScroll("left")}catch(e){return setTimeout(i,50)}st.ready()}}()}return U.promise(t)},st.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(e,t){Q["[object "+t+"]"]=t.toLowerCase()}),X=st(V);var Tt={};st.Callbacks=function(e){e="string"==typeof e?Tt[e]||r(e):st.extend({},e);var n,i,o,a,s,u,l=[],c=!e.once&&[],f=function(t){for(n=e.memory&&t,i=!0,u=a||0,a=0,s=l.length,o=!0;l&&s>u;u++)if(l[u].apply(t[0],t[1])===!1&&e.stopOnFalse){n=!1;break}o=!1,l&&(c?c.length&&f(c.shift()):n?l=[]:p.disable())},p={add:function(){if(l){var t=l.length;(function r(t){st.each(t,function(t,n){var i=st.type(n);"function"===i?e.unique&&p.has(n)||l.push(n):n&&n.length&&"string"!==i&&r(n)})})(arguments),o?s=l.length:n&&(a=t,f(n))}return this},remove:function(){return l&&st.each(arguments,function(e,t){for(var n;(n=st.inArray(t,l,n))>-1;)l.splice(n,1),o&&(s>=n&&s--,u>=n&&u--)}),this},has:function(e){return st.inArray(e,l)>-1},empty:function(){return l=[],this},disable:function(){return l=c=n=t,this},disabled:function(){return!l},lock:function(){return c=t,n||p.disable(),this},locked:function(){return!c},fireWith:function(e,t){return t=t||[],t=[e,t.slice?t.slice():t],!l||i&&!c||(o?c.push(t):f(t)),this},fire:function(){return p.fireWith(this,arguments),this},fired:function(){return!!i}};return p},st.extend({Deferred:function(e){var t=[["resolve","done",st.Callbacks("once memory"),"resolved"],["reject","fail",st.Callbacks("once memory"),"rejected"],["notify","progress",st.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return st.Deferred(function(n){st.each(t,function(t,o){var a=o[0],s=st.isFunction(e[t])&&e[t];i[o[1]](function(){var e=s&&s.apply(this,arguments);e&&st.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[a+"With"](this===r?n.promise():this,s?[e]:arguments)})}),e=null}).promise()},promise:function(e){return null!=e?st.extend(e,r):r}},i={};return r.pipe=r.then,st.each(t,function(e,o){var a=o[2],s=o[3];r[o[1]]=a.add,s&&a.add(function(){n=s},t[1^e][2].disable,t[2][2].lock),i[o[0]]=function(){return i[o[0]+"With"](this===i?r:this,arguments),this},i[o[0]+"With"]=a.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t,n,r,i=0,o=nt.call(arguments),a=o.length,s=1!==a||e&&st.isFunction(e.promise)?a:0,u=1===s?e:st.Deferred(),l=function(e,n,r){return function(i){n[e]=this,r[e]=arguments.length>1?nt.call(arguments):i,r===t?u.notifyWith(n,r):--s||u.resolveWith(n,r)}};if(a>1)for(t=Array(a),n=Array(a),r=Array(a);a>i;i++)o[i]&&st.isFunction(o[i].promise)?o[i].promise().done(l(i,r,o)).fail(u.reject).progress(l(i,n,t)):--s;return s||u.resolveWith(r,o),u.promise()}}),st.support=function(){var n,r,i,o,a,s,u,l,c,f,p=V.createElement("div");if(p.setAttribute("className","t"),p.innerHTML="  <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",r=p.getElementsByTagName("*"),i=p.getElementsByTagName("a")[0],!r||!i||!r.length)return{};o=V.createElement("select"),a=o.appendChild(V.createElement("option")),s=p.getElementsByTagName("input")[0],i.style.cssText="top:1px;float:left;opacity:.5",n={getSetAttribute:"t"!==p.className,leadingWhitespace:3===p.firstChild.nodeType,tbody:!p.getElementsByTagName("tbody").length,htmlSerialize:!!p.getElementsByTagName("link").length,style:/top/.test(i.getAttribute("style")),hrefNormalized:"/a"===i.getAttribute("href"),opacity:/^0.5/.test(i.style.opacity),cssFloat:!!i.style.cssFloat,checkOn:!!s.value,optSelected:a.selected,enctype:!!V.createElement("form").enctype,html5Clone:"<:nav></:nav>"!==V.createElement("nav").cloneNode(!0).outerHTML,boxModel:"CSS1Compat"===V.compatMode,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,boxSizingReliable:!0,pixelPosition:!1},s.checked=!0,n.noCloneChecked=s.cloneNode(!0).checked,o.disabled=!0,n.optDisabled=!a.disabled;try{delete p.test}catch(d){n.deleteExpando=!1}s=V.createElement("input"),s.setAttribute("value",""),n.input=""===s.getAttribute("value"),s.value="t",s.setAttribute("type","radio"),n.radioValue="t"===s.value,s.setAttribute("checked","t"),s.setAttribute("name","t"),u=V.createDocumentFragment(),u.appendChild(s),n.appendChecked=s.checked,n.checkClone=u.cloneNode(!0).cloneNode(!0).lastChild.checked,p.attachEvent&&(p.attachEvent("onclick",function(){n.noCloneEvent=!1}),p.cloneNode(!0).click());for(f in{submit:!0,change:!0,focusin:!0})p.setAttribute(l="on"+f,"t"),n[f+"Bubbles"]=l in e||p.attributes[l].expando===!1;return p.style.backgroundClip="content-box",p.cloneNode(!0).style.backgroundClip="",n.clearCloneStyle="content-box"===p.style.backgroundClip,st(function(){var r,i,o,a="padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;",s=V.getElementsByTagName("body")[0];s&&(r=V.createElement("div"),r.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px",s.appendChild(r).appendChild(p),p.innerHTML="<table><tr><td></td><td>t</td></tr></table>",o=p.getElementsByTagName("td"),o[0].style.cssText="padding:0;margin:0;border:0;display:none",c=0===o[0].offsetHeight,o[0].style.display="",o[1].style.display="none",n.reliableHiddenOffsets=c&&0===o[0].offsetHeight,p.innerHTML="",p.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",n.boxSizing=4===p.offsetWidth,n.doesNotIncludeMarginInBodyOffset=1!==s.offsetTop,e.getComputedStyle&&(n.pixelPosition="1%"!==(e.getComputedStyle(p,null)||{}).top,n.boxSizingReliable="4px"===(e.getComputedStyle(p,null)||{width:"4px"}).width,i=p.appendChild(V.createElement("div")),i.style.cssText=p.style.cssText=a,i.style.marginRight=i.style.width="0",p.style.width="1px",n.reliableMarginRight=!parseFloat((e.getComputedStyle(i,null)||{}).marginRight)),p.style.zoom!==t&&(p.innerHTML="",p.style.cssText=a+"width:1px;padding:1px;display:inline;zoom:1",n.inlineBlockNeedsLayout=3===p.offsetWidth,p.style.display="block",p.innerHTML="<div></div>",p.firstChild.style.width="5px",n.shrinkWrapBlocks=3!==p.offsetWidth,s.style.zoom=1),s.removeChild(r),r=p=o=i=null)}),r=o=u=a=i=s=null,n}();var wt=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,Nt=/([A-Z])/g;st.extend({cache:{},expando:"jQuery"+(Z+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(e){return e=e.nodeType?st.cache[e[st.expando]]:e[st.expando],!!e&&!s(e)},data:function(e,t,n){return i(e,t,n,!1)},removeData:function(e,t){return o(e,t,!1)},_data:function(e,t,n){return i(e,t,n,!0)},_removeData:function(e,t){return o(e,t,!0)},acceptData:function(e){var t=e.nodeName&&st.noData[e.nodeName.toLowerCase()];return!t||t!==!0&&e.getAttribute("classid")===t}}),st.fn.extend({data:function(e,n){var r,i,o=this[0],s=0,u=null;if(e===t){if(this.length&&(u=st.data(o),1===o.nodeType&&!st._data(o,"parsedAttrs"))){for(r=o.attributes;r.length>s;s++)i=r[s].name,i.indexOf("data-")||(i=st.camelCase(i.substring(5)),a(o,i,u[i]));st._data(o,"parsedAttrs",!0)}return u}return"object"==typeof e?this.each(function(){st.data(this,e)}):st.access(this,function(n){return n===t?o?a(o,e,st.data(o,e)):null:(this.each(function(){st.data(this,e,n)}),t)},null,n,arguments.length>1,null,!0)},removeData:function(e){return this.each(function(){st.removeData(this,e)})}}),st.extend({queue:function(e,n,r){var i;return e?(n=(n||"fx")+"queue",i=st._data(e,n),r&&(!i||st.isArray(r)?i=st._data(e,n,st.makeArray(r)):i.push(r)),i||[]):t},dequeue:function(e,t){t=t||"fx";var n=st.queue(e,t),r=n.length,i=n.shift(),o=st._queueHooks(e,t),a=function(){st.dequeue(e,t)};"inprogress"===i&&(i=n.shift(),r--),o.cur=i,i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,a,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return st._data(e,n)||st._data(e,n,{empty:st.Callbacks("once memory").add(function(){st._removeData(e,t+"queue"),st._removeData(e,n)})})}}),st.fn.extend({queue:function(e,n){var r=2;return"string"!=typeof e&&(n=e,e="fx",r--),r>arguments.length?st.queue(this[0],e):n===t?this:this.each(function(){var t=st.queue(this,e,n);st._queueHooks(this,e),"fx"===e&&"inprogress"!==t[0]&&st.dequeue(this,e)})},dequeue:function(e){return this.each(function(){st.dequeue(this,e)})},delay:function(e,t){return e=st.fx?st.fx.speeds[e]||e:e,t=t||"fx",this.queue(t,function(t,n){var r=setTimeout(t,e);n.stop=function(){clearTimeout(r)}})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,n){var r,i=1,o=st.Deferred(),a=this,s=this.length,u=function(){--i||o.resolveWith(a,[a])};for("string"!=typeof e&&(n=e,e=t),e=e||"fx";s--;)r=st._data(a[s],e+"queueHooks"),r&&r.empty&&(i++,r.empty.add(u));return u(),o.promise(n)}});var Ct,kt,Et=/[\t\r\n]/g,St=/\r/g,At=/^(?:input|select|textarea|button|object)$/i,jt=/^(?:a|area)$/i,Dt=/^(?:checked|selected|autofocus|autoplay|async|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped)$/i,Lt=/^(?:checked|selected)$/i,Ht=st.support.getSetAttribute,Mt=st.support.input;st.fn.extend({attr:function(e,t){return st.access(this,st.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){st.removeAttr(this,e)})},prop:function(e,t){return st.access(this,st.prop,e,t,arguments.length>1)},removeProp:function(e){return e=st.propFix[e]||e,this.each(function(){try{this[e]=t,delete this[e]}catch(n){}})},addClass:function(e){var t,n,r,i,o,a=0,s=this.length,u="string"==typeof e&&e;if(st.isFunction(e))return this.each(function(t){st(this).addClass(e.call(this,t,this.className))});if(u)for(t=(e||"").match(lt)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(Et," "):" ")){for(o=0;i=t[o++];)0>r.indexOf(" "+i+" ")&&(r+=i+" ");n.className=st.trim(r)}return this},removeClass:function(e){var t,n,r,i,o,a=0,s=this.length,u=0===arguments.length||"string"==typeof e&&e;if(st.isFunction(e))return this.each(function(t){st(this).removeClass(e.call(this,t,this.className))});if(u)for(t=(e||"").match(lt)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(Et," "):"")){for(o=0;i=t[o++];)for(;r.indexOf(" "+i+" ")>=0;)r=r.replace(" "+i+" "," ");n.className=e?st.trim(r):""}return this},toggleClass:function(e,t){var n=typeof e,r="boolean"==typeof t;return st.isFunction(e)?this.each(function(n){st(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if("string"===n)for(var i,o=0,a=st(this),s=t,u=e.match(lt)||[];i=u[o++];)s=r?s:!a.hasClass(i),a[s?"addClass":"removeClass"](i);else("undefined"===n||"boolean"===n)&&(this.className&&st._data(this,"__className__",this.className),this.className=this.className||e===!1?"":st._data(this,"__className__")||"")})},hasClass:function(e){for(var t=" "+e+" ",n=0,r=this.length;r>n;n++)if(1===this[n].nodeType&&(" "+this[n].className+" ").replace(Et," ").indexOf(t)>=0)return!0;return!1},val:function(e){var n,r,i,o=this[0];{if(arguments.length)return i=st.isFunction(e),this.each(function(r){var o,a=st(this);1===this.nodeType&&(o=i?e.call(this,r,a.val()):e,null==o?o="":"number"==typeof o?o+="":st.isArray(o)&&(o=st.map(o,function(e){return null==e?"":e+""})),n=st.valHooks[this.type]||st.valHooks[this.nodeName.toLowerCase()],n&&"set"in n&&n.set(this,o,"value")!==t||(this.value=o))});if(o)return n=st.valHooks[o.type]||st.valHooks[o.nodeName.toLowerCase()],n&&"get"in n&&(r=n.get(o,"value"))!==t?r:(r=o.value,"string"==typeof r?r.replace(St,""):null==r?"":r)}}}),st.extend({valHooks:{option:{get:function(e){var t=e.attributes.value;return!t||t.specified?e.value:e.text}},select:{get:function(e){for(var t,n,r=e.options,i=e.selectedIndex,o="select-one"===e.type||0>i,a=o?null:[],s=o?i+1:r.length,u=0>i?s:o?i:0;s>u;u++)if(n=r[u],!(!n.selected&&u!==i||(st.support.optDisabled?n.disabled:null!==n.getAttribute("disabled"))||n.parentNode.disabled&&st.nodeName(n.parentNode,"optgroup"))){if(t=st(n).val(),o)return t;a.push(t)}return a},set:function(e,t){var n=st.makeArray(t);return st(e).find("option").each(function(){this.selected=st.inArray(st(this).val(),n)>=0}),n.length||(e.selectedIndex=-1),n}}},attr:function(e,n,r){var i,o,a,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return e.getAttribute===t?st.prop(e,n,r):(a=1!==s||!st.isXMLDoc(e),a&&(n=n.toLowerCase(),o=st.attrHooks[n]||(Dt.test(n)?kt:Ct)),r===t?o&&a&&"get"in o&&null!==(i=o.get(e,n))?i:(e.getAttribute!==t&&(i=e.getAttribute(n)),null==i?t:i):null!==r?o&&a&&"set"in o&&(i=o.set(e,r,n))!==t?i:(e.setAttribute(n,r+""),r):(st.removeAttr(e,n),t))},removeAttr:function(e,t){var n,r,i=0,o=t&&t.match(lt);if(o&&1===e.nodeType)for(;n=o[i++];)r=st.propFix[n]||n,Dt.test(n)?!Ht&&Lt.test(n)?e[st.camelCase("default-"+n)]=e[r]=!1:e[r]=!1:st.attr(e,n,""),e.removeAttribute(Ht?n:r)},attrHooks:{type:{set:function(e,t){if(!st.support.radioValue&&"radio"===t&&st.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(e,n,r){var i,o,a,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return a=1!==s||!st.isXMLDoc(e),a&&(n=st.propFix[n]||n,o=st.propHooks[n]),r!==t?o&&"set"in o&&(i=o.set(e,r,n))!==t?i:e[n]=r:o&&"get"in o&&null!==(i=o.get(e,n))?i:e[n]},propHooks:{tabIndex:{get:function(e){var n=e.getAttributeNode("tabindex");return n&&n.specified?parseInt(n.value,10):At.test(e.nodeName)||jt.test(e.nodeName)&&e.href?0:t}}}}),kt={get:function(e,n){var r=st.prop(e,n),i="boolean"==typeof r&&e.getAttribute(n),o="boolean"==typeof r?Mt&&Ht?null!=i:Lt.test(n)?e[st.camelCase("default-"+n)]:!!i:e.getAttributeNode(n);return o&&o.value!==!1?n.toLowerCase():t},set:function(e,t,n){return t===!1?st.removeAttr(e,n):Mt&&Ht||!Lt.test(n)?e.setAttribute(!Ht&&st.propFix[n]||n,n):e[st.camelCase("default-"+n)]=e[n]=!0,n}},Mt&&Ht||(st.attrHooks.value={get:function(e,n){var r=e.getAttributeNode(n);return st.nodeName(e,"input")?e.defaultValue:r&&r.specified?r.value:t
2
-},set:function(e,n,r){return st.nodeName(e,"input")?(e.defaultValue=n,t):Ct&&Ct.set(e,n,r)}}),Ht||(Ct=st.valHooks.button={get:function(e,n){var r=e.getAttributeNode(n);return r&&("id"===n||"name"===n||"coords"===n?""!==r.value:r.specified)?r.value:t},set:function(e,n,r){var i=e.getAttributeNode(r);return i||e.setAttributeNode(i=e.ownerDocument.createAttribute(r)),i.value=n+="","value"===r||n===e.getAttribute(r)?n:t}},st.attrHooks.contenteditable={get:Ct.get,set:function(e,t,n){Ct.set(e,""===t?!1:t,n)}},st.each(["width","height"],function(e,n){st.attrHooks[n]=st.extend(st.attrHooks[n],{set:function(e,r){return""===r?(e.setAttribute(n,"auto"),r):t}})})),st.support.hrefNormalized||(st.each(["href","src","width","height"],function(e,n){st.attrHooks[n]=st.extend(st.attrHooks[n],{get:function(e){var r=e.getAttribute(n,2);return null==r?t:r}})}),st.each(["href","src"],function(e,t){st.propHooks[t]={get:function(e){return e.getAttribute(t,4)}}})),st.support.style||(st.attrHooks.style={get:function(e){return e.style.cssText||t},set:function(e,t){return e.style.cssText=t+""}}),st.support.optSelected||(st.propHooks.selected=st.extend(st.propHooks.selected,{get:function(e){var t=e.parentNode;return t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex),null}})),st.support.enctype||(st.propFix.enctype="encoding"),st.support.checkOn||st.each(["radio","checkbox"],function(){st.valHooks[this]={get:function(e){return null===e.getAttribute("value")?"on":e.value}}}),st.each(["radio","checkbox"],function(){st.valHooks[this]=st.extend(st.valHooks[this],{set:function(e,n){return st.isArray(n)?e.checked=st.inArray(st(e).val(),n)>=0:t}})});var qt=/^(?:input|select|textarea)$/i,_t=/^key/,Ft=/^(?:mouse|contextmenu)|click/,Ot=/^(?:focusinfocus|focusoutblur)$/,Bt=/^([^.]*)(?:\.(.+)|)$/;st.event={global:{},add:function(e,n,r,i,o){var a,s,u,l,c,f,p,d,h,g,m,y=3!==e.nodeType&&8!==e.nodeType&&st._data(e);if(y){for(r.handler&&(a=r,r=a.handler,o=a.selector),r.guid||(r.guid=st.guid++),(l=y.events)||(l=y.events={}),(s=y.handle)||(s=y.handle=function(e){return st===t||e&&st.event.triggered===e.type?t:st.event.dispatch.apply(s.elem,arguments)},s.elem=e),n=(n||"").match(lt)||[""],c=n.length;c--;)u=Bt.exec(n[c])||[],h=m=u[1],g=(u[2]||"").split(".").sort(),p=st.event.special[h]||{},h=(o?p.delegateType:p.bindType)||h,p=st.event.special[h]||{},f=st.extend({type:h,origType:m,data:i,handler:r,guid:r.guid,selector:o,needsContext:o&&st.expr.match.needsContext.test(o),namespace:g.join(".")},a),(d=l[h])||(d=l[h]=[],d.delegateCount=0,p.setup&&p.setup.call(e,i,g,s)!==!1||(e.addEventListener?e.addEventListener(h,s,!1):e.attachEvent&&e.attachEvent("on"+h,s))),p.add&&(p.add.call(e,f),f.handler.guid||(f.handler.guid=r.guid)),o?d.splice(d.delegateCount++,0,f):d.push(f),st.event.global[h]=!0;e=null}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,m=st.hasData(e)&&st._data(e);if(m&&(u=m.events)){for(t=(t||"").match(lt)||[""],l=t.length;l--;)if(s=Bt.exec(t[l])||[],d=g=s[1],h=(s[2]||"").split(".").sort(),d){for(f=st.event.special[d]||{},d=(r?f.delegateType:f.bindType)||d,p=u[d]||[],s=s[2]&&RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=p.length;o--;)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&f.teardown.call(e,h,m.handle)!==!1||st.removeEvent(e,d,m.handle),delete u[d])}else for(d in u)st.event.remove(e,d+t[l],n,r,!0);st.isEmptyObject(u)&&(delete m.handle,st._removeData(e,"events"))}},trigger:function(n,r,i,o){var a,s,u,l,c,f,p,d=[i||V],h=n.type||n,g=n.namespace?n.namespace.split("."):[];if(s=u=i=i||V,3!==i.nodeType&&8!==i.nodeType&&!Ot.test(h+st.event.triggered)&&(h.indexOf(".")>=0&&(g=h.split("."),h=g.shift(),g.sort()),c=0>h.indexOf(":")&&"on"+h,n=n[st.expando]?n:new st.Event(h,"object"==typeof n&&n),n.isTrigger=!0,n.namespace=g.join("."),n.namespace_re=n.namespace?RegExp("(^|\\.)"+g.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,n.result=t,n.target||(n.target=i),r=null==r?[n]:st.makeArray(r,[n]),p=st.event.special[h]||{},o||!p.trigger||p.trigger.apply(i,r)!==!1)){if(!o&&!p.noBubble&&!st.isWindow(i)){for(l=p.delegateType||h,Ot.test(l+h)||(s=s.parentNode);s;s=s.parentNode)d.push(s),u=s;u===(i.ownerDocument||V)&&d.push(u.defaultView||u.parentWindow||e)}for(a=0;(s=d[a++])&&!n.isPropagationStopped();)n.type=a>1?l:p.bindType||h,f=(st._data(s,"events")||{})[n.type]&&st._data(s,"handle"),f&&f.apply(s,r),f=c&&s[c],f&&st.acceptData(s)&&f.apply&&f.apply(s,r)===!1&&n.preventDefault();if(n.type=h,!(o||n.isDefaultPrevented()||p._default&&p._default.apply(i.ownerDocument,r)!==!1||"click"===h&&st.nodeName(i,"a")||!st.acceptData(i)||!c||!i[h]||st.isWindow(i))){u=i[c],u&&(i[c]=null),st.event.triggered=h;try{i[h]()}catch(m){}st.event.triggered=t,u&&(i[c]=u)}return n.result}},dispatch:function(e){e=st.event.fix(e);var n,r,i,o,a,s=[],u=nt.call(arguments),l=(st._data(this,"events")||{})[e.type]||[],c=st.event.special[e.type]||{};if(u[0]=e,e.delegateTarget=this,!c.preDispatch||c.preDispatch.call(this,e)!==!1){for(s=st.event.handlers.call(this,e,l),n=0;(o=s[n++])&&!e.isPropagationStopped();)for(e.currentTarget=o.elem,r=0;(a=o.handlers[r++])&&!e.isImmediatePropagationStopped();)(!e.namespace_re||e.namespace_re.test(a.namespace))&&(e.handleObj=a,e.data=a.data,i=((st.event.special[a.origType]||{}).handle||a.handler).apply(o.elem,u),i!==t&&(e.result=i)===!1&&(e.preventDefault(),e.stopPropagation()));return c.postDispatch&&c.postDispatch.call(this,e),e.result}},handlers:function(e,n){var r,i,o,a,s=[],u=n.delegateCount,l=e.target;if(u&&l.nodeType&&(!e.button||"click"!==e.type))for(;l!=this;l=l.parentNode||this)if(l.disabled!==!0||"click"!==e.type){for(i=[],r=0;u>r;r++)a=n[r],o=a.selector+" ",i[o]===t&&(i[o]=a.needsContext?st(o,this).index(l)>=0:st.find(o,this,null,[l]).length),i[o]&&i.push(a);i.length&&s.push({elem:l,handlers:i})}return n.length>u&&s.push({elem:this,handlers:n.slice(u)}),s},fix:function(e){if(e[st.expando])return e;var t,n,r=e,i=st.event.fixHooks[e.type]||{},o=i.props?this.props.concat(i.props):this.props;for(e=new st.Event(r),t=o.length;t--;)n=o[t],e[n]=r[n];return e.target||(e.target=r.srcElement||V),3===e.target.nodeType&&(e.target=e.target.parentNode),e.metaKey=!!e.metaKey,i.filter?i.filter(e,r):e},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(e,t){return null==e.which&&(e.which=null!=t.charCode?t.charCode:t.keyCode),e}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(e,n){var r,i,o,a=n.button,s=n.fromElement;return null==e.pageX&&null!=n.clientX&&(r=e.target.ownerDocument||V,i=r.documentElement,o=r.body,e.pageX=n.clientX+(i&&i.scrollLeft||o&&o.scrollLeft||0)-(i&&i.clientLeft||o&&o.clientLeft||0),e.pageY=n.clientY+(i&&i.scrollTop||o&&o.scrollTop||0)-(i&&i.clientTop||o&&o.clientTop||0)),!e.relatedTarget&&s&&(e.relatedTarget=s===e.target?n.toElement:s),e.which||a===t||(e.which=1&a?1:2&a?3:4&a?2:0),e}},special:{load:{noBubble:!0},click:{trigger:function(){return st.nodeName(this,"input")&&"checkbox"===this.type&&this.click?(this.click(),!1):t}},focus:{trigger:function(){if(this!==V.activeElement&&this.focus)try{return this.focus(),!1}catch(e){}},delegateType:"focusin"},blur:{trigger:function(){return this===V.activeElement&&this.blur?(this.blur(),!1):t},delegateType:"focusout"},beforeunload:{postDispatch:function(e){e.result!==t&&(e.originalEvent.returnValue=e.result)}}},simulate:function(e,t,n,r){var i=st.extend(new st.Event,n,{type:e,isSimulated:!0,originalEvent:{}});r?st.event.trigger(i,null,t):st.event.dispatch.call(t,i),i.isDefaultPrevented()&&n.preventDefault()}},st.removeEvent=V.removeEventListener?function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n,!1)}:function(e,n,r){var i="on"+n;e.detachEvent&&(e[i]===t&&(e[i]=null),e.detachEvent(i,r))},st.Event=function(e,n){return this instanceof st.Event?(e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||e.returnValue===!1||e.getPreventDefault&&e.getPreventDefault()?u:l):this.type=e,n&&st.extend(this,n),this.timeStamp=e&&e.timeStamp||st.now(),this[st.expando]=!0,t):new st.Event(e,n)},st.Event.prototype={isDefaultPrevented:l,isPropagationStopped:l,isImmediatePropagationStopped:l,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=u,e&&(e.preventDefault?e.preventDefault():e.returnValue=!1)},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=u,e&&(e.stopPropagation&&e.stopPropagation(),e.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=u,this.stopPropagation()}},st.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(e,t){st.event.special[e]={delegateType:t,bindType:t,handle:function(e){var n,r=this,i=e.relatedTarget,o=e.handleObj;return(!i||i!==r&&!st.contains(r,i))&&(e.type=o.origType,n=o.handler.apply(this,arguments),e.type=t),n}}}),st.support.submitBubbles||(st.event.special.submit={setup:function(){return st.nodeName(this,"form")?!1:(st.event.add(this,"click._submit keypress._submit",function(e){var n=e.target,r=st.nodeName(n,"input")||st.nodeName(n,"button")?n.form:t;r&&!st._data(r,"submitBubbles")&&(st.event.add(r,"submit._submit",function(e){e._submit_bubble=!0}),st._data(r,"submitBubbles",!0))}),t)},postDispatch:function(e){e._submit_bubble&&(delete e._submit_bubble,this.parentNode&&!e.isTrigger&&st.event.simulate("submit",this.parentNode,e,!0))},teardown:function(){return st.nodeName(this,"form")?!1:(st.event.remove(this,"._submit"),t)}}),st.support.changeBubbles||(st.event.special.change={setup:function(){return qt.test(this.nodeName)?(("checkbox"===this.type||"radio"===this.type)&&(st.event.add(this,"propertychange._change",function(e){"checked"===e.originalEvent.propertyName&&(this._just_changed=!0)}),st.event.add(this,"click._change",function(e){this._just_changed&&!e.isTrigger&&(this._just_changed=!1),st.event.simulate("change",this,e,!0)})),!1):(st.event.add(this,"beforeactivate._change",function(e){var t=e.target;qt.test(t.nodeName)&&!st._data(t,"changeBubbles")&&(st.event.add(t,"change._change",function(e){!this.parentNode||e.isSimulated||e.isTrigger||st.event.simulate("change",this.parentNode,e,!0)}),st._data(t,"changeBubbles",!0))}),t)},handle:function(e){var n=e.target;return this!==n||e.isSimulated||e.isTrigger||"radio"!==n.type&&"checkbox"!==n.type?e.handleObj.handler.apply(this,arguments):t},teardown:function(){return st.event.remove(this,"._change"),!qt.test(this.nodeName)}}),st.support.focusinBubbles||st.each({focus:"focusin",blur:"focusout"},function(e,t){var n=0,r=function(e){st.event.simulate(t,e.target,st.event.fix(e),!0)};st.event.special[t]={setup:function(){0===n++&&V.addEventListener(e,r,!0)},teardown:function(){0===--n&&V.removeEventListener(e,r,!0)}}}),st.fn.extend({on:function(e,n,r,i,o){var a,s;if("object"==typeof e){"string"!=typeof n&&(r=r||n,n=t);for(s in e)this.on(s,n,r,e[s],o);return this}if(null==r&&null==i?(i=n,r=n=t):null==i&&("string"==typeof n?(i=r,r=t):(i=r,r=n,n=t)),i===!1)i=l;else if(!i)return this;return 1===o&&(a=i,i=function(e){return st().off(e),a.apply(this,arguments)},i.guid=a.guid||(a.guid=st.guid++)),this.each(function(){st.event.add(this,e,i,r,n)})},one:function(e,t,n,r){return this.on(e,t,n,r,1)},off:function(e,n,r){var i,o;if(e&&e.preventDefault&&e.handleObj)return i=e.handleObj,st(e.delegateTarget).off(i.namespace?i.origType+"."+i.namespace:i.origType,i.selector,i.handler),this;if("object"==typeof e){for(o in e)this.off(o,n,e[o]);return this}return(n===!1||"function"==typeof n)&&(r=n,n=t),r===!1&&(r=l),this.each(function(){st.event.remove(this,e,r,n)})},bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},trigger:function(e,t){return this.each(function(){st.event.trigger(e,t,this)})},triggerHandler:function(e,n){var r=this[0];return r?st.event.trigger(e,n,r,!0):t},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),st.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(e,t){st.fn[t]=function(e,n){return arguments.length>0?this.on(t,null,e,n):this.trigger(t)},_t.test(t)&&(st.event.fixHooks[t]=st.event.keyHooks),Ft.test(t)&&(st.event.fixHooks[t]=st.event.mouseHooks)}),function(e,t){function n(e){return ht.test(e+"")}function r(){var e,t=[];return e=function(n,r){return t.push(n+=" ")>C.cacheLength&&delete e[t.shift()],e[n]=r}}function i(e){return e[P]=!0,e}function o(e){var t=L.createElement("div");try{return e(t)}catch(n){return!1}finally{t=null}}function a(e,t,n,r){var i,o,a,s,u,l,c,d,h,g;if((t?t.ownerDocument||t:R)!==L&&D(t),t=t||L,n=n||[],!e||"string"!=typeof e)return n;if(1!==(s=t.nodeType)&&9!==s)return[];if(!M&&!r){if(i=gt.exec(e))if(a=i[1]){if(9===s){if(o=t.getElementById(a),!o||!o.parentNode)return n;if(o.id===a)return n.push(o),n}else if(t.ownerDocument&&(o=t.ownerDocument.getElementById(a))&&O(t,o)&&o.id===a)return n.push(o),n}else{if(i[2])return Q.apply(n,K.call(t.getElementsByTagName(e),0)),n;if((a=i[3])&&W.getByClassName&&t.getElementsByClassName)return Q.apply(n,K.call(t.getElementsByClassName(a),0)),n}if(W.qsa&&!q.test(e)){if(c=!0,d=P,h=t,g=9===s&&e,1===s&&"object"!==t.nodeName.toLowerCase()){for(l=f(e),(c=t.getAttribute("id"))?d=c.replace(vt,"\\$&"):t.setAttribute("id",d),d="[id='"+d+"'] ",u=l.length;u--;)l[u]=d+p(l[u]);h=dt.test(e)&&t.parentNode||t,g=l.join(",")}if(g)try{return Q.apply(n,K.call(h.querySelectorAll(g),0)),n}catch(m){}finally{c||t.removeAttribute("id")}}}return x(e.replace(at,"$1"),t,n,r)}function s(e,t){for(var n=e&&t&&e.nextSibling;n;n=n.nextSibling)if(n===t)return-1;return e?1:-1}function u(e){return function(t){var n=t.nodeName.toLowerCase();return"input"===n&&t.type===e}}function l(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function c(e){return i(function(t){return t=+t,i(function(n,r){for(var i,o=e([],n.length,t),a=o.length;a--;)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))})})}function f(e,t){var n,r,i,o,s,u,l,c=X[e+" "];if(c)return t?0:c.slice(0);for(s=e,u=[],l=C.preFilter;s;){(!n||(r=ut.exec(s)))&&(r&&(s=s.slice(r[0].length)||s),u.push(i=[])),n=!1,(r=lt.exec(s))&&(n=r.shift(),i.push({value:n,type:r[0].replace(at," ")}),s=s.slice(n.length));for(o in C.filter)!(r=pt[o].exec(s))||l[o]&&!(r=l[o](r))||(n=r.shift(),i.push({value:n,type:o,matches:r}),s=s.slice(n.length));if(!n)break}return t?s.length:s?a.error(e):X(e,u).slice(0)}function p(e){for(var t=0,n=e.length,r="";n>t;t++)r+=e[t].value;return r}function d(e,t,n){var r=t.dir,i=n&&"parentNode"===t.dir,o=I++;return t.first?function(t,n,o){for(;t=t[r];)if(1===t.nodeType||i)return e(t,n,o)}:function(t,n,a){var s,u,l,c=$+" "+o;if(a){for(;t=t[r];)if((1===t.nodeType||i)&&e(t,n,a))return!0}else for(;t=t[r];)if(1===t.nodeType||i)if(l=t[P]||(t[P]={}),(u=l[r])&&u[0]===c){if((s=u[1])===!0||s===N)return s===!0}else if(u=l[r]=[c],u[1]=e(t,n,a)||N,u[1]===!0)return!0}}function h(e){return e.length>1?function(t,n,r){for(var i=e.length;i--;)if(!e[i](t,n,r))return!1;return!0}:e[0]}function g(e,t,n,r,i){for(var o,a=[],s=0,u=e.length,l=null!=t;u>s;s++)(o=e[s])&&(!n||n(o,r,i))&&(a.push(o),l&&t.push(s));return a}function m(e,t,n,r,o,a){return r&&!r[P]&&(r=m(r)),o&&!o[P]&&(o=m(o,a)),i(function(i,a,s,u){var l,c,f,p=[],d=[],h=a.length,m=i||b(t||"*",s.nodeType?[s]:s,[]),y=!e||!i&&t?m:g(m,p,e,s,u),v=n?o||(i?e:h||r)?[]:a:y;if(n&&n(y,v,s,u),r)for(l=g(v,d),r(l,[],s,u),c=l.length;c--;)(f=l[c])&&(v[d[c]]=!(y[d[c]]=f));if(i){if(o||e){if(o){for(l=[],c=v.length;c--;)(f=v[c])&&l.push(y[c]=f);o(null,v=[],l,u)}for(c=v.length;c--;)(f=v[c])&&(l=o?Z.call(i,f):p[c])>-1&&(i[l]=!(a[l]=f))}}else v=g(v===a?v.splice(h,v.length):v),o?o(null,a,v,u):Q.apply(a,v)})}function y(e){for(var t,n,r,i=e.length,o=C.relative[e[0].type],a=o||C.relative[" "],s=o?1:0,u=d(function(e){return e===t},a,!0),l=d(function(e){return Z.call(t,e)>-1},a,!0),c=[function(e,n,r){return!o&&(r||n!==j)||((t=n).nodeType?u(e,n,r):l(e,n,r))}];i>s;s++)if(n=C.relative[e[s].type])c=[d(h(c),n)];else{if(n=C.filter[e[s].type].apply(null,e[s].matches),n[P]){for(r=++s;i>r&&!C.relative[e[r].type];r++);return m(s>1&&h(c),s>1&&p(e.slice(0,s-1)).replace(at,"$1"),n,r>s&&y(e.slice(s,r)),i>r&&y(e=e.slice(r)),i>r&&p(e))}c.push(n)}return h(c)}function v(e,t){var n=0,r=t.length>0,o=e.length>0,s=function(i,s,u,l,c){var f,p,d,h=[],m=0,y="0",v=i&&[],b=null!=c,x=j,T=i||o&&C.find.TAG("*",c&&s.parentNode||s),w=$+=null==x?1:Math.E;for(b&&(j=s!==L&&s,N=n);null!=(f=T[y]);y++){if(o&&f){for(p=0;d=e[p];p++)if(d(f,s,u)){l.push(f);break}b&&($=w,N=++n)}r&&((f=!d&&f)&&m--,i&&v.push(f))}if(m+=y,r&&y!==m){for(p=0;d=t[p];p++)d(v,h,s,u);if(i){if(m>0)for(;y--;)v[y]||h[y]||(h[y]=G.call(l));h=g(h)}Q.apply(l,h),b&&!i&&h.length>0&&m+t.length>1&&a.uniqueSort(l)}return b&&($=w,j=x),v};return r?i(s):s}function b(e,t,n){for(var r=0,i=t.length;i>r;r++)a(e,t[r],n);return n}function x(e,t,n,r){var i,o,a,s,u,l=f(e);if(!r&&1===l.length){if(o=l[0]=l[0].slice(0),o.length>2&&"ID"===(a=o[0]).type&&9===t.nodeType&&!M&&C.relative[o[1].type]){if(t=C.find.ID(a.matches[0].replace(xt,Tt),t)[0],!t)return n;e=e.slice(o.shift().value.length)}for(i=pt.needsContext.test(e)?-1:o.length-1;i>=0&&(a=o[i],!C.relative[s=a.type]);i--)if((u=C.find[s])&&(r=u(a.matches[0].replace(xt,Tt),dt.test(o[0].type)&&t.parentNode||t))){if(o.splice(i,1),e=r.length&&p(o),!e)return Q.apply(n,K.call(r,0)),n;break}}return S(e,l)(r,t,M,n,dt.test(e)),n}function T(){}var w,N,C,k,E,S,A,j,D,L,H,M,q,_,F,O,B,P="sizzle"+-new Date,R=e.document,W={},$=0,I=0,z=r(),X=r(),U=r(),V=typeof t,Y=1<<31,J=[],G=J.pop,Q=J.push,K=J.slice,Z=J.indexOf||function(e){for(var t=0,n=this.length;n>t;t++)if(this[t]===e)return t;return-1},et="[\\x20\\t\\r\\n\\f]",tt="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",nt=tt.replace("w","w#"),rt="([*^$|!~]?=)",it="\\["+et+"*("+tt+")"+et+"*(?:"+rt+et+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+nt+")|)|)"+et+"*\\]",ot=":("+tt+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+it.replace(3,8)+")*)|.*)\\)|)",at=RegExp("^"+et+"+|((?:^|[^\\\\])(?:\\\\.)*)"+et+"+$","g"),ut=RegExp("^"+et+"*,"+et+"*"),lt=RegExp("^"+et+"*([\\x20\\t\\r\\n\\f>+~])"+et+"*"),ct=RegExp(ot),ft=RegExp("^"+nt+"$"),pt={ID:RegExp("^#("+tt+")"),CLASS:RegExp("^\\.("+tt+")"),NAME:RegExp("^\\[name=['\"]?("+tt+")['\"]?\\]"),TAG:RegExp("^("+tt.replace("w","w*")+")"),ATTR:RegExp("^"+it),PSEUDO:RegExp("^"+ot),CHILD:RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+et+"*(even|odd|(([+-]|)(\\d*)n|)"+et+"*(?:([+-]|)"+et+"*(\\d+)|))"+et+"*\\)|)","i"),needsContext:RegExp("^"+et+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+et+"*((?:-\\d)?\\d*)"+et+"*\\)|)(?=[^-]|$)","i")},dt=/[\x20\t\r\n\f]*[+~]/,ht=/\{\s*\[native code\]\s*\}/,gt=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,mt=/^(?:input|select|textarea|button)$/i,yt=/^h\d$/i,vt=/'|\\/g,bt=/\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,xt=/\\([\da-fA-F]{1,6}[\x20\t\r\n\f]?|.)/g,Tt=function(e,t){var n="0x"+t-65536;return n!==n?t:0>n?String.fromCharCode(n+65536):String.fromCharCode(55296|n>>10,56320|1023&n)};try{K.call(H.childNodes,0)[0].nodeType}catch(wt){K=function(e){for(var t,n=[];t=this[e];e++)n.push(t);return n}}E=a.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?"HTML"!==t.nodeName:!1},D=a.setDocument=function(e){var r=e?e.ownerDocument||e:R;return r!==L&&9===r.nodeType&&r.documentElement?(L=r,H=r.documentElement,M=E(r),W.tagNameNoComments=o(function(e){return e.appendChild(r.createComment("")),!e.getElementsByTagName("*").length}),W.attributes=o(function(e){e.innerHTML="<select></select>";var t=typeof e.lastChild.getAttribute("multiple");return"boolean"!==t&&"string"!==t}),W.getByClassName=o(function(e){return e.innerHTML="<div class='hidden e'></div><div class='hidden'></div>",e.getElementsByClassName&&e.getElementsByClassName("e").length?(e.lastChild.className="e",2===e.getElementsByClassName("e").length):!1}),W.getByName=o(function(e){e.id=P+0,e.innerHTML="<a name='"+P+"'></a><div name='"+P+"'></div>",H.insertBefore(e,H.firstChild);var t=r.getElementsByName&&r.getElementsByName(P).length===2+r.getElementsByName(P+0).length;return W.getIdNotName=!r.getElementById(P),H.removeChild(e),t}),C.attrHandle=o(function(e){return e.innerHTML="<a href='#'></a>",e.firstChild&&typeof e.firstChild.getAttribute!==V&&"#"===e.firstChild.getAttribute("href")})?{}:{href:function(e){return e.getAttribute("href",2)},type:function(e){return e.getAttribute("type")}},W.getIdNotName?(C.find.ID=function(e,t){if(typeof t.getElementById!==V&&!M){var n=t.getElementById(e);return n&&n.parentNode?[n]:[]}},C.filter.ID=function(e){var t=e.replace(xt,Tt);return function(e){return e.getAttribute("id")===t}}):(C.find.ID=function(e,n){if(typeof n.getElementById!==V&&!M){var r=n.getElementById(e);return r?r.id===e||typeof r.getAttributeNode!==V&&r.getAttributeNode("id").value===e?[r]:t:[]}},C.filter.ID=function(e){var t=e.replace(xt,Tt);return function(e){var n=typeof e.getAttributeNode!==V&&e.getAttributeNode("id");return n&&n.value===t}}),C.find.TAG=W.tagNameNoComments?function(e,n){return typeof n.getElementsByTagName!==V?n.getElementsByTagName(e):t}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){for(;n=o[i];i++)1===n.nodeType&&r.push(n);return r}return o},C.find.NAME=W.getByName&&function(e,n){return typeof n.getElementsByName!==V?n.getElementsByName(name):t},C.find.CLASS=W.getByClassName&&function(e,n){return typeof n.getElementsByClassName===V||M?t:n.getElementsByClassName(e)},_=[],q=[":focus"],(W.qsa=n(r.querySelectorAll))&&(o(function(e){e.innerHTML="<select><option selected=''></option></select>",e.querySelectorAll("[selected]").length||q.push("\\["+et+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)"),e.querySelectorAll(":checked").length||q.push(":checked")}),o(function(e){e.innerHTML="<input type='hidden' i=''/>",e.querySelectorAll("[i^='']").length&&q.push("[*^$]="+et+"*(?:\"\"|'')"),e.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),q.push(",.*:")})),(W.matchesSelector=n(F=H.matchesSelector||H.mozMatchesSelector||H.webkitMatchesSelector||H.oMatchesSelector||H.msMatchesSelector))&&o(function(e){W.disconnectedMatch=F.call(e,"div"),F.call(e,"[s!='']:x"),_.push("!=",ot)}),q=RegExp(q.join("|")),_=RegExp(_.join("|")),O=n(H.contains)||H.compareDocumentPosition?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)for(;t=t.parentNode;)if(t===e)return!0;return!1},B=H.compareDocumentPosition?function(e,t){var n;return e===t?(A=!0,0):(n=t.compareDocumentPosition&&e.compareDocumentPosition&&e.compareDocumentPosition(t))?1&n||e.parentNode&&11===e.parentNode.nodeType?e===r||O(R,e)?-1:t===r||O(R,t)?1:0:4&n?-1:1:e.compareDocumentPosition?-1:1}:function(e,t){var n,i=0,o=e.parentNode,a=t.parentNode,u=[e],l=[t];if(e===t)return A=!0,0;if(e.sourceIndex&&t.sourceIndex)return(~t.sourceIndex||Y)-(O(R,e)&&~e.sourceIndex||Y);if(!o||!a)return e===r?-1:t===r?1:o?-1:a?1:0;if(o===a)return s(e,t);for(n=e;n=n.parentNode;)u.unshift(n);for(n=t;n=n.parentNode;)l.unshift(n);for(;u[i]===l[i];)i++;return i?s(u[i],l[i]):u[i]===R?-1:l[i]===R?1:0},A=!1,[0,0].sort(B),W.detectDuplicates=A,L):L},a.matches=function(e,t){return a(e,null,null,t)},a.matchesSelector=function(e,t){if((e.ownerDocument||e)!==L&&D(e),t=t.replace(bt,"='$1']"),!(!W.matchesSelector||M||_&&_.test(t)||q.test(t)))try{var n=F.call(e,t);if(n||W.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(r){}return a(t,L,null,[e]).length>0},a.contains=function(e,t){return(e.ownerDocument||e)!==L&&D(e),O(e,t)},a.attr=function(e,t){var n;return(e.ownerDocument||e)!==L&&D(e),M||(t=t.toLowerCase()),(n=C.attrHandle[t])?n(e):M||W.attributes?e.getAttribute(t):((n=e.getAttributeNode(t))||e.getAttribute(t))&&e[t]===!0?t:n&&n.specified?n.value:null},a.error=function(e){throw Error("Syntax error, unrecognized expression: "+e)},a.uniqueSort=function(e){var t,n=[],r=1,i=0;if(A=!W.detectDuplicates,e.sort(B),A){for(;t=e[r];r++)t===e[r-1]&&(i=n.push(r));for(;i--;)e.splice(n[i],1)}return e},k=a.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=k(e)}else if(3===i||4===i)return e.nodeValue}else for(;t=e[r];r++)n+=k(t);return n},C=a.selectors={cacheLength:50,createPseudo:i,match:pt,find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(xt,Tt),e[3]=(e[4]||e[5]||"").replace(xt,Tt),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||a.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&a.error(e[0]),e},PSEUDO:function(e){var t,n=!e[5]&&e[2];return pt.CHILD.test(e[0])?null:(e[4]?e[2]=e[4]:n&&ct.test(n)&&(t=f(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){return"*"===e?function(){return!0}:(e=e.replace(xt,Tt).toLowerCase(),function(t){return t.nodeName&&t.nodeName.toLowerCase()===e})},CLASS:function(e){var t=z[e+" "];return t||(t=RegExp("(^|"+et+")"+e+"("+et+"|$)"))&&z(e,function(e){return t.test(e.className||typeof e.getAttribute!==V&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=a.attr(r,e);return null==i?"!="===t:t?(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.substr(i.length-n.length)===n:"~="===t?(" "+i+" ").indexOf(n)>-1:"|="===t?i===n||i.substr(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),a="last"!==e.slice(-4),s="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,u){var l,c,f,p,d,h,g=o!==a?"nextSibling":"previousSibling",m=t.parentNode,y=s&&t.nodeName.toLowerCase(),v=!u&&!s;if(m){if(o){for(;g;){for(f=t;f=f[g];)if(s?f.nodeName.toLowerCase()===y:1===f.nodeType)return!1;h=g="only"===e&&!h&&"nextSibling"}return!0}if(h=[a?m.firstChild:m.lastChild],a&&v){for(c=m[P]||(m[P]={}),l=c[e]||[],d=l[0]===$&&l[1],p=l[0]===$&&l[2],f=d&&m.childNodes[d];f=++d&&f&&f[g]||(p=d=0)||h.pop();)if(1===f.nodeType&&++p&&f===t){c[e]=[$,d,p];break}}else if(v&&(l=(t[P]||(t[P]={}))[e])&&l[0]===$)p=l[1];else for(;(f=++d&&f&&f[g]||(p=d=0)||h.pop())&&((s?f.nodeName.toLowerCase()!==y:1!==f.nodeType)||!++p||(v&&((f[P]||(f[P]={}))[e]=[$,p]),f!==t)););return p-=i,p===r||0===p%r&&p/r>=0}}},PSEUDO:function(e,t){var n,r=C.pseudos[e]||C.setFilters[e.toLowerCase()]||a.error("unsupported pseudo: "+e);return r[P]?r(t):r.length>1?(n=[e,e,"",t],C.setFilters.hasOwnProperty(e.toLowerCase())?i(function(e,n){for(var i,o=r(e,t),a=o.length;a--;)i=Z.call(e,o[a]),e[i]=!(n[i]=o[a])}):function(e){return r(e,0,n)}):r}},pseudos:{not:i(function(e){var t=[],n=[],r=S(e.replace(at,"$1"));return r[P]?i(function(e,t,n,i){for(var o,a=r(e,null,i,[]),s=e.length;s--;)(o=a[s])&&(e[s]=!(t[s]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),!n.pop()}}),has:i(function(e){return function(t){return a(e,t).length>0}}),contains:i(function(e){return function(t){return(t.textContent||t.innerText||k(t)).indexOf(e)>-1}}),lang:i(function(e){return ft.test(e||"")||a.error("unsupported lang: "+e),e=e.replace(xt,Tt).toLowerCase(),function(t){var n;do if(n=M?t.getAttribute("xml:lang")||t.getAttribute("lang"):t.lang)return n=n.toLowerCase(),n===e||0===n.indexOf(e+"-");while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===H},focus:function(e){return e===L.activeElement&&(!L.hasFocus||L.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeName>"@"||3===e.nodeType||4===e.nodeType)return!1;return!0},parent:function(e){return!C.pseudos.empty(e)},header:function(e){return yt.test(e.nodeName)},input:function(e){return mt.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||t.toLowerCase()===e.type)},first:c(function(){return[0]}),last:c(function(e,t){return[t-1]}),eq:c(function(e,t,n){return[0>n?n+t:n]}),even:c(function(e,t){for(var n=0;t>n;n+=2)e.push(n);return e}),odd:c(function(e,t){for(var n=1;t>n;n+=2)e.push(n);return e}),lt:c(function(e,t,n){for(var r=0>n?n+t:n;--r>=0;)e.push(r);return e}),gt:c(function(e,t,n){for(var r=0>n?n+t:n;t>++r;)e.push(r);return e})}};for(w in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})C.pseudos[w]=u(w);for(w in{submit:!0,reset:!0})C.pseudos[w]=l(w);S=a.compile=function(e,t){var n,r=[],i=[],o=U[e+" "];if(!o){for(t||(t=f(e)),n=t.length;n--;)o=y(t[n]),o[P]?r.push(o):i.push(o);o=U(e,v(i,r))}return o},C.pseudos.nth=C.pseudos.eq,C.filters=T.prototype=C.pseudos,C.setFilters=new T,D(),a.attr=st.attr,st.find=a,st.expr=a.selectors,st.expr[":"]=st.expr.pseudos,st.unique=a.uniqueSort,st.text=a.getText,st.isXMLDoc=a.isXML,st.contains=a.contains}(e);var Pt=/Until$/,Rt=/^(?:parents|prev(?:Until|All))/,Wt=/^.[^:#\[\.,]*$/,$t=st.expr.match.needsContext,It={children:!0,contents:!0,next:!0,prev:!0};st.fn.extend({find:function(e){var t,n,r;if("string"!=typeof e)return r=this,this.pushStack(st(e).filter(function(){for(t=0;r.length>t;t++)if(st.contains(r[t],this))return!0}));for(n=[],t=0;this.length>t;t++)st.find(e,this[t],n);return n=this.pushStack(st.unique(n)),n.selector=(this.selector?this.selector+" ":"")+e,n},has:function(e){var t,n=st(e,this),r=n.length;return this.filter(function(){for(t=0;r>t;t++)if(st.contains(this,n[t]))return!0})},not:function(e){return this.pushStack(f(this,e,!1))},filter:function(e){return this.pushStack(f(this,e,!0))},is:function(e){return!!e&&("string"==typeof e?$t.test(e)?st(e,this.context).index(this[0])>=0:st.filter(e,this).length>0:this.filter(e).length>0)},closest:function(e,t){for(var n,r=0,i=this.length,o=[],a=$t.test(e)||"string"!=typeof e?st(e,t||this.context):0;i>r;r++)for(n=this[r];n&&n.ownerDocument&&n!==t&&11!==n.nodeType;){if(a?a.index(n)>-1:st.find.matchesSelector(n,e)){o.push(n);break}n=n.parentNode}return this.pushStack(o.length>1?st.unique(o):o)},index:function(e){return e?"string"==typeof e?st.inArray(this[0],st(e)):st.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){var n="string"==typeof e?st(e,t):st.makeArray(e&&e.nodeType?[e]:e),r=st.merge(this.get(),n);return this.pushStack(st.unique(r))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),st.fn.andSelf=st.fn.addBack,st.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return st.dir(e,"parentNode")},parentsUntil:function(e,t,n){return st.dir(e,"parentNode",n)},next:function(e){return c(e,"nextSibling")},prev:function(e){return c(e,"previousSibling")
3
-},nextAll:function(e){return st.dir(e,"nextSibling")},prevAll:function(e){return st.dir(e,"previousSibling")},nextUntil:function(e,t,n){return st.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return st.dir(e,"previousSibling",n)},siblings:function(e){return st.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return st.sibling(e.firstChild)},contents:function(e){return st.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:st.merge([],e.childNodes)}},function(e,t){st.fn[e]=function(n,r){var i=st.map(this,t,n);return Pt.test(e)||(r=n),r&&"string"==typeof r&&(i=st.filter(r,i)),i=this.length>1&&!It[e]?st.unique(i):i,this.length>1&&Rt.test(e)&&(i=i.reverse()),this.pushStack(i)}}),st.extend({filter:function(e,t,n){return n&&(e=":not("+e+")"),1===t.length?st.find.matchesSelector(t[0],e)?[t[0]]:[]:st.find.matches(e,t)},dir:function(e,n,r){for(var i=[],o=e[n];o&&9!==o.nodeType&&(r===t||1!==o.nodeType||!st(o).is(r));)1===o.nodeType&&i.push(o),o=o[n];return i},sibling:function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n}});var zt="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",Xt=/ jQuery\d+="(?:null|\d+)"/g,Ut=RegExp("<(?:"+zt+")[\\s/>]","i"),Vt=/^\s+/,Yt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,Jt=/<([\w:]+)/,Gt=/<tbody/i,Qt=/<|&#?\w+;/,Kt=/<(?:script|style|link)/i,Zt=/^(?:checkbox|radio)$/i,en=/checked\s*(?:[^=]|=\s*.checked.)/i,tn=/^$|\/(?:java|ecma)script/i,nn=/^true\/(.*)/,rn=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,on={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],area:[1,"<map>","</map>"],param:[1,"<object>","</object>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:st.support.htmlSerialize?[0,"",""]:[1,"X<div>","</div>"]},an=p(V),sn=an.appendChild(V.createElement("div"));on.optgroup=on.option,on.tbody=on.tfoot=on.colgroup=on.caption=on.thead,on.th=on.td,st.fn.extend({text:function(e){return st.access(this,function(e){return e===t?st.text(this):this.empty().append((this[0]&&this[0].ownerDocument||V).createTextNode(e))},null,e,arguments.length)},wrapAll:function(e){if(st.isFunction(e))return this.each(function(t){st(this).wrapAll(e.call(this,t))});if(this[0]){var t=st(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){for(var e=this;e.firstChild&&1===e.firstChild.nodeType;)e=e.firstChild;return e}).append(this)}return this},wrapInner:function(e){return st.isFunction(e)?this.each(function(t){st(this).wrapInner(e.call(this,t))}):this.each(function(){var t=st(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=st.isFunction(e);return this.each(function(n){st(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){st.nodeName(this,"body")||st(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(e){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&this.appendChild(e)})},prepend:function(){return this.domManip(arguments,!0,function(e){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&this.insertBefore(e,this.firstChild)})},before:function(){return this.domManip(arguments,!1,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return this.domManip(arguments,!1,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},remove:function(e,t){for(var n,r=0;null!=(n=this[r]);r++)(!e||st.filter(e,[n]).length>0)&&(t||1!==n.nodeType||st.cleanData(b(n)),n.parentNode&&(t&&st.contains(n.ownerDocument,n)&&m(b(n,"script")),n.parentNode.removeChild(n)));return this},empty:function(){for(var e,t=0;null!=(e=this[t]);t++){for(1===e.nodeType&&st.cleanData(b(e,!1));e.firstChild;)e.removeChild(e.firstChild);e.options&&st.nodeName(e,"select")&&(e.options.length=0)}return this},clone:function(e,t){return e=null==e?!1:e,t=null==t?e:t,this.map(function(){return st.clone(this,e,t)})},html:function(e){return st.access(this,function(e){var n=this[0]||{},r=0,i=this.length;if(e===t)return 1===n.nodeType?n.innerHTML.replace(Xt,""):t;if(!("string"!=typeof e||Kt.test(e)||!st.support.htmlSerialize&&Ut.test(e)||!st.support.leadingWhitespace&&Vt.test(e)||on[(Jt.exec(e)||["",""])[1].toLowerCase()])){e=e.replace(Yt,"<$1></$2>");try{for(;i>r;r++)n=this[r]||{},1===n.nodeType&&(st.cleanData(b(n,!1)),n.innerHTML=e);n=0}catch(o){}}n&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(e){var t=st.isFunction(e);return t||"string"==typeof e||(e=st(e).not(this).detach()),this.domManip([e],!0,function(e){var t=this.nextSibling,n=this.parentNode;(n&&1===this.nodeType||11===this.nodeType)&&(st(this).remove(),t?t.parentNode.insertBefore(e,t):n.appendChild(e))})},detach:function(e){return this.remove(e,!0)},domManip:function(e,n,r){e=et.apply([],e);var i,o,a,s,u,l,c=0,f=this.length,p=this,m=f-1,y=e[0],v=st.isFunction(y);if(v||!(1>=f||"string"!=typeof y||st.support.checkClone)&&en.test(y))return this.each(function(i){var o=p.eq(i);v&&(e[0]=y.call(this,i,n?o.html():t)),o.domManip(e,n,r)});if(f&&(i=st.buildFragment(e,this[0].ownerDocument,!1,this),o=i.firstChild,1===i.childNodes.length&&(i=o),o)){for(n=n&&st.nodeName(o,"tr"),a=st.map(b(i,"script"),h),s=a.length;f>c;c++)u=i,c!==m&&(u=st.clone(u,!0,!0),s&&st.merge(a,b(u,"script"))),r.call(n&&st.nodeName(this[c],"table")?d(this[c],"tbody"):this[c],u,c);if(s)for(l=a[a.length-1].ownerDocument,st.map(a,g),c=0;s>c;c++)u=a[c],tn.test(u.type||"")&&!st._data(u,"globalEval")&&st.contains(l,u)&&(u.src?st.ajax({url:u.src,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0}):st.globalEval((u.text||u.textContent||u.innerHTML||"").replace(rn,"")));i=o=null}return this}}),st.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,t){st.fn[e]=function(e){for(var n,r=0,i=[],o=st(e),a=o.length-1;a>=r;r++)n=r===a?this:this.clone(!0),st(o[r])[t](n),tt.apply(i,n.get());return this.pushStack(i)}}),st.extend({clone:function(e,t,n){var r,i,o,a,s,u=st.contains(e.ownerDocument,e);if(st.support.html5Clone||st.isXMLDoc(e)||!Ut.test("<"+e.nodeName+">")?s=e.cloneNode(!0):(sn.innerHTML=e.outerHTML,sn.removeChild(s=sn.firstChild)),!(st.support.noCloneEvent&&st.support.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||st.isXMLDoc(e)))for(r=b(s),i=b(e),a=0;null!=(o=i[a]);++a)r[a]&&v(o,r[a]);if(t)if(n)for(i=i||b(e),r=r||b(s),a=0;null!=(o=i[a]);a++)y(o,r[a]);else y(e,s);return r=b(s,"script"),r.length>0&&m(r,!u&&b(e,"script")),r=i=o=null,s},buildFragment:function(e,t,n,r){for(var i,o,a,s,u,l,c,f=e.length,d=p(t),h=[],g=0;f>g;g++)if(o=e[g],o||0===o)if("object"===st.type(o))st.merge(h,o.nodeType?[o]:o);else if(Qt.test(o)){for(s=s||d.appendChild(t.createElement("div")),a=(Jt.exec(o)||["",""])[1].toLowerCase(),u=on[a]||on._default,s.innerHTML=u[1]+o.replace(Yt,"<$1></$2>")+u[2],c=u[0];c--;)s=s.lastChild;if(!st.support.leadingWhitespace&&Vt.test(o)&&h.push(t.createTextNode(Vt.exec(o)[0])),!st.support.tbody)for(o="table"!==a||Gt.test(o)?"<table>"!==u[1]||Gt.test(o)?0:s:s.firstChild,c=o&&o.childNodes.length;c--;)st.nodeName(l=o.childNodes[c],"tbody")&&!l.childNodes.length&&o.removeChild(l);for(st.merge(h,s.childNodes),s.textContent="";s.firstChild;)s.removeChild(s.firstChild);s=d.lastChild}else h.push(t.createTextNode(o));for(s&&d.removeChild(s),st.support.appendChecked||st.grep(b(h,"input"),x),g=0;o=h[g++];)if((!r||-1===st.inArray(o,r))&&(i=st.contains(o.ownerDocument,o),s=b(d.appendChild(o),"script"),i&&m(s),n))for(c=0;o=s[c++];)tn.test(o.type||"")&&n.push(o);return s=null,d},cleanData:function(e,n){for(var r,i,o,a,s=0,u=st.expando,l=st.cache,c=st.support.deleteExpando,f=st.event.special;null!=(o=e[s]);s++)if((n||st.acceptData(o))&&(i=o[u],r=i&&l[i])){if(r.events)for(a in r.events)f[a]?st.event.remove(o,a):st.removeEvent(o,a,r.handle);l[i]&&(delete l[i],c?delete o[u]:o.removeAttribute!==t?o.removeAttribute(u):o[u]=null,K.push(i))}}});var un,ln,cn,fn=/alpha\([^)]*\)/i,pn=/opacity\s*=\s*([^)]*)/,dn=/^(top|right|bottom|left)$/,hn=/^(none|table(?!-c[ea]).+)/,gn=/^margin/,mn=RegExp("^("+ut+")(.*)$","i"),yn=RegExp("^("+ut+")(?!px)[a-z%]+$","i"),vn=RegExp("^([+-])=("+ut+")","i"),bn={BODY:"block"},xn={position:"absolute",visibility:"hidden",display:"block"},Tn={letterSpacing:0,fontWeight:400},wn=["Top","Right","Bottom","Left"],Nn=["Webkit","O","Moz","ms"];st.fn.extend({css:function(e,n){return st.access(this,function(e,n,r){var i,o,a={},s=0;if(st.isArray(n)){for(i=ln(e),o=n.length;o>s;s++)a[n[s]]=st.css(e,n[s],!1,i);return a}return r!==t?st.style(e,n,r):st.css(e,n)},e,n,arguments.length>1)},show:function(){return N(this,!0)},hide:function(){return N(this)},toggle:function(e){var t="boolean"==typeof e;return this.each(function(){(t?e:w(this))?st(this).show():st(this).hide()})}}),st.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=un(e,"opacity");return""===n?"1":n}}}},cssNumber:{columnCount:!0,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":st.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var o,a,s,u=st.camelCase(n),l=e.style;if(n=st.cssProps[u]||(st.cssProps[u]=T(l,u)),s=st.cssHooks[n]||st.cssHooks[u],r===t)return s&&"get"in s&&(o=s.get(e,!1,i))!==t?o:l[n];if(a=typeof r,"string"===a&&(o=vn.exec(r))&&(r=(o[1]+1)*o[2]+parseFloat(st.css(e,n)),a="number"),!(null==r||"number"===a&&isNaN(r)||("number"!==a||st.cssNumber[u]||(r+="px"),st.support.clearCloneStyle||""!==r||0!==n.indexOf("background")||(l[n]="inherit"),s&&"set"in s&&(r=s.set(e,r,i))===t)))try{l[n]=r}catch(c){}}},css:function(e,n,r,i){var o,a,s,u=st.camelCase(n);return n=st.cssProps[u]||(st.cssProps[u]=T(e.style,u)),s=st.cssHooks[n]||st.cssHooks[u],s&&"get"in s&&(o=s.get(e,!0,r)),o===t&&(o=un(e,n,i)),"normal"===o&&n in Tn&&(o=Tn[n]),r?(a=parseFloat(o),r===!0||st.isNumeric(a)?a||0:o):o},swap:function(e,t,n,r){var i,o,a={};for(o in t)a[o]=e.style[o],e.style[o]=t[o];i=n.apply(e,r||[]);for(o in t)e.style[o]=a[o];return i}}),e.getComputedStyle?(ln=function(t){return e.getComputedStyle(t,null)},un=function(e,n,r){var i,o,a,s=r||ln(e),u=s?s.getPropertyValue(n)||s[n]:t,l=e.style;return s&&(""!==u||st.contains(e.ownerDocument,e)||(u=st.style(e,n)),yn.test(u)&&gn.test(n)&&(i=l.width,o=l.minWidth,a=l.maxWidth,l.minWidth=l.maxWidth=l.width=u,u=s.width,l.width=i,l.minWidth=o,l.maxWidth=a)),u}):V.documentElement.currentStyle&&(ln=function(e){return e.currentStyle},un=function(e,n,r){var i,o,a,s=r||ln(e),u=s?s[n]:t,l=e.style;return null==u&&l&&l[n]&&(u=l[n]),yn.test(u)&&!dn.test(n)&&(i=l.left,o=e.runtimeStyle,a=o&&o.left,a&&(o.left=e.currentStyle.left),l.left="fontSize"===n?"1em":u,u=l.pixelLeft+"px",l.left=i,a&&(o.left=a)),""===u?"auto":u}),st.each(["height","width"],function(e,n){st.cssHooks[n]={get:function(e,r,i){return r?0===e.offsetWidth&&hn.test(st.css(e,"display"))?st.swap(e,xn,function(){return E(e,n,i)}):E(e,n,i):t},set:function(e,t,r){var i=r&&ln(e);return C(e,t,r?k(e,n,r,st.support.boxSizing&&"border-box"===st.css(e,"boxSizing",!1,i),i):0)}}}),st.support.opacity||(st.cssHooks.opacity={get:function(e,t){return pn.test((t&&e.currentStyle?e.currentStyle.filter:e.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":t?"1":""},set:function(e,t){var n=e.style,r=e.currentStyle,i=st.isNumeric(t)?"alpha(opacity="+100*t+")":"",o=r&&r.filter||n.filter||"";n.zoom=1,(t>=1||""===t)&&""===st.trim(o.replace(fn,""))&&n.removeAttribute&&(n.removeAttribute("filter"),""===t||r&&!r.filter)||(n.filter=fn.test(o)?o.replace(fn,i):o+" "+i)}}),st(function(){st.support.reliableMarginRight||(st.cssHooks.marginRight={get:function(e,n){return n?st.swap(e,{display:"inline-block"},un,[e,"marginRight"]):t}}),!st.support.pixelPosition&&st.fn.position&&st.each(["top","left"],function(e,n){st.cssHooks[n]={get:function(e,r){return r?(r=un(e,n),yn.test(r)?st(e).position()[n]+"px":r):t}}})}),st.expr&&st.expr.filters&&(st.expr.filters.hidden=function(e){return 0===e.offsetWidth&&0===e.offsetHeight||!st.support.reliableHiddenOffsets&&"none"===(e.style&&e.style.display||st.css(e,"display"))},st.expr.filters.visible=function(e){return!st.expr.filters.hidden(e)}),st.each({margin:"",padding:"",border:"Width"},function(e,t){st.cssHooks[e+t]={expand:function(n){for(var r=0,i={},o="string"==typeof n?n.split(" "):[n];4>r;r++)i[e+wn[r]+t]=o[r]||o[r-2]||o[0];return i}},gn.test(e)||(st.cssHooks[e+t].set=C)});var Cn=/%20/g,kn=/\[\]$/,En=/\r?\n/g,Sn=/^(?:submit|button|image|reset)$/i,An=/^(?:input|select|textarea|keygen)/i;st.fn.extend({serialize:function(){return st.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=st.prop(this,"elements");return e?st.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!st(this).is(":disabled")&&An.test(this.nodeName)&&!Sn.test(e)&&(this.checked||!Zt.test(e))}).map(function(e,t){var n=st(this).val();return null==n?null:st.isArray(n)?st.map(n,function(e){return{name:t.name,value:e.replace(En,"\r\n")}}):{name:t.name,value:n.replace(En,"\r\n")}}).get()}}),st.param=function(e,n){var r,i=[],o=function(e,t){t=st.isFunction(t)?t():null==t?"":t,i[i.length]=encodeURIComponent(e)+"="+encodeURIComponent(t)};if(n===t&&(n=st.ajaxSettings&&st.ajaxSettings.traditional),st.isArray(e)||e.jquery&&!st.isPlainObject(e))st.each(e,function(){o(this.name,this.value)});else for(r in e)j(r,e[r],n,o);return i.join("&").replace(Cn,"+")};var jn,Dn,Ln=st.now(),Hn=/\?/,Mn=/#.*$/,qn=/([?&])_=[^&]*/,_n=/^(.*?):[ \t]*([^\r\n]*)\r?$/gm,Fn=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,On=/^(?:GET|HEAD)$/,Bn=/^\/\//,Pn=/^([\w.+-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,Rn=st.fn.load,Wn={},$n={},In="*/".concat("*");try{Dn=Y.href}catch(zn){Dn=V.createElement("a"),Dn.href="",Dn=Dn.href}jn=Pn.exec(Dn.toLowerCase())||[],st.fn.load=function(e,n,r){if("string"!=typeof e&&Rn)return Rn.apply(this,arguments);var i,o,a,s=this,u=e.indexOf(" ");return u>=0&&(i=e.slice(u,e.length),e=e.slice(0,u)),st.isFunction(n)?(r=n,n=t):n&&"object"==typeof n&&(o="POST"),s.length>0&&st.ajax({url:e,type:o,dataType:"html",data:n}).done(function(e){a=arguments,s.html(i?st("<div>").append(st.parseHTML(e)).find(i):e)}).complete(r&&function(e,t){s.each(r,a||[e.responseText,t,e])}),this},st.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){st.fn[t]=function(e){return this.on(t,e)}}),st.each(["get","post"],function(e,n){st[n]=function(e,r,i,o){return st.isFunction(r)&&(o=o||i,i=r,r=t),st.ajax({url:e,type:n,dataType:o,data:r,success:i})}}),st.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Dn,type:"GET",isLocal:Fn.test(jn[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":In,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":e.String,"text html":!0,"text json":st.parseJSON,"text xml":st.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?H(H(e,st.ajaxSettings),t):H(st.ajaxSettings,e)},ajaxPrefilter:D(Wn),ajaxTransport:D($n),ajax:function(e,n){function r(e,n,r,s){var l,f,v,b,T,N=n;2!==x&&(x=2,u&&clearTimeout(u),i=t,a=s||"",w.readyState=e>0?4:0,r&&(b=M(p,w,r)),e>=200&&300>e||304===e?(p.ifModified&&(T=w.getResponseHeader("Last-Modified"),T&&(st.lastModified[o]=T),T=w.getResponseHeader("etag"),T&&(st.etag[o]=T)),304===e?(l=!0,N="notmodified"):(l=q(p,b),N=l.state,f=l.data,v=l.error,l=!v)):(v=N,(e||!N)&&(N="error",0>e&&(e=0))),w.status=e,w.statusText=(n||N)+"",l?g.resolveWith(d,[f,N,w]):g.rejectWith(d,[w,N,v]),w.statusCode(y),y=t,c&&h.trigger(l?"ajaxSuccess":"ajaxError",[w,p,l?f:v]),m.fireWith(d,[w,N]),c&&(h.trigger("ajaxComplete",[w,p]),--st.active||st.event.trigger("ajaxStop")))}"object"==typeof e&&(n=e,e=t),n=n||{};var i,o,a,s,u,l,c,f,p=st.ajaxSetup({},n),d=p.context||p,h=p.context&&(d.nodeType||d.jquery)?st(d):st.event,g=st.Deferred(),m=st.Callbacks("once memory"),y=p.statusCode||{},v={},b={},x=0,T="canceled",w={readyState:0,getResponseHeader:function(e){var t;if(2===x){if(!s)for(s={};t=_n.exec(a);)s[t[1].toLowerCase()]=t[2];t=s[e.toLowerCase()]}return null==t?null:t},getAllResponseHeaders:function(){return 2===x?a:null},setRequestHeader:function(e,t){var n=e.toLowerCase();return x||(e=b[n]=b[n]||e,v[e]=t),this},overrideMimeType:function(e){return x||(p.mimeType=e),this},statusCode:function(e){var t;if(e)if(2>x)for(t in e)y[t]=[y[t],e[t]];else w.always(e[w.status]);return this},abort:function(e){var t=e||T;return i&&i.abort(t),r(0,t),this}};if(g.promise(w).complete=m.add,w.success=w.done,w.error=w.fail,p.url=((e||p.url||Dn)+"").replace(Mn,"").replace(Bn,jn[1]+"//"),p.type=n.method||n.type||p.method||p.type,p.dataTypes=st.trim(p.dataType||"*").toLowerCase().match(lt)||[""],null==p.crossDomain&&(l=Pn.exec(p.url.toLowerCase()),p.crossDomain=!(!l||l[1]===jn[1]&&l[2]===jn[2]&&(l[3]||("http:"===l[1]?80:443))==(jn[3]||("http:"===jn[1]?80:443)))),p.data&&p.processData&&"string"!=typeof p.data&&(p.data=st.param(p.data,p.traditional)),L(Wn,p,n,w),2===x)return w;c=p.global,c&&0===st.active++&&st.event.trigger("ajaxStart"),p.type=p.type.toUpperCase(),p.hasContent=!On.test(p.type),o=p.url,p.hasContent||(p.data&&(o=p.url+=(Hn.test(o)?"&":"?")+p.data,delete p.data),p.cache===!1&&(p.url=qn.test(o)?o.replace(qn,"$1_="+Ln++):o+(Hn.test(o)?"&":"?")+"_="+Ln++)),p.ifModified&&(st.lastModified[o]&&w.setRequestHeader("If-Modified-Since",st.lastModified[o]),st.etag[o]&&w.setRequestHeader("If-None-Match",st.etag[o])),(p.data&&p.hasContent&&p.contentType!==!1||n.contentType)&&w.setRequestHeader("Content-Type",p.contentType),w.setRequestHeader("Accept",p.dataTypes[0]&&p.accepts[p.dataTypes[0]]?p.accepts[p.dataTypes[0]]+("*"!==p.dataTypes[0]?", "+In+"; q=0.01":""):p.accepts["*"]);for(f in p.headers)w.setRequestHeader(f,p.headers[f]);if(p.beforeSend&&(p.beforeSend.call(d,w,p)===!1||2===x))return w.abort();T="abort";for(f in{success:1,error:1,complete:1})w[f](p[f]);if(i=L($n,p,n,w)){w.readyState=1,c&&h.trigger("ajaxSend",[w,p]),p.async&&p.timeout>0&&(u=setTimeout(function(){w.abort("timeout")},p.timeout));try{x=1,i.send(v,r)}catch(N){if(!(2>x))throw N;r(-1,N)}}else r(-1,"No Transport");return w},getScript:function(e,n){return st.get(e,t,n,"script")},getJSON:function(e,t,n){return st.get(e,t,n,"json")}}),st.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(e){return st.globalEval(e),e}}}),st.ajaxPrefilter("script",function(e){e.cache===t&&(e.cache=!1),e.crossDomain&&(e.type="GET",e.global=!1)}),st.ajaxTransport("script",function(e){if(e.crossDomain){var n,r=V.head||st("head")[0]||V.documentElement;return{send:function(t,i){n=V.createElement("script"),n.async=!0,e.scriptCharset&&(n.charset=e.scriptCharset),n.src=e.url,n.onload=n.onreadystatechange=function(e,t){(t||!n.readyState||/loaded|complete/.test(n.readyState))&&(n.onload=n.onreadystatechange=null,n.parentNode&&n.parentNode.removeChild(n),n=null,t||i(200,"success"))},r.insertBefore(n,r.firstChild)},abort:function(){n&&n.onload(t,!0)}}}});var Xn=[],Un=/(=)\?(?=&|$)|\?\?/;st.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Xn.pop()||st.expando+"_"+Ln++;return this[e]=!0,e}}),st.ajaxPrefilter("json jsonp",function(n,r,i){var o,a,s,u=n.jsonp!==!1&&(Un.test(n.url)?"url":"string"==typeof n.data&&!(n.contentType||"").indexOf("application/x-www-form-urlencoded")&&Un.test(n.data)&&"data");return u||"jsonp"===n.dataTypes[0]?(o=n.jsonpCallback=st.isFunction(n.jsonpCallback)?n.jsonpCallback():n.jsonpCallback,u?n[u]=n[u].replace(Un,"$1"+o):n.jsonp!==!1&&(n.url+=(Hn.test(n.url)?"&":"?")+n.jsonp+"="+o),n.converters["script json"]=function(){return s||st.error(o+" was not called"),s[0]},n.dataTypes[0]="json",a=e[o],e[o]=function(){s=arguments},i.always(function(){e[o]=a,n[o]&&(n.jsonpCallback=r.jsonpCallback,Xn.push(o)),s&&st.isFunction(a)&&a(s[0]),s=a=t}),"script"):t});var Vn,Yn,Jn=0,Gn=e.ActiveXObject&&function(){var e;for(e in Vn)Vn[e](t,!0)};st.ajaxSettings.xhr=e.ActiveXObject?function(){return!this.isLocal&&_()||F()}:_,Yn=st.ajaxSettings.xhr(),st.support.cors=!!Yn&&"withCredentials"in Yn,Yn=st.support.ajax=!!Yn,Yn&&st.ajaxTransport(function(n){if(!n.crossDomain||st.support.cors){var r;return{send:function(i,o){var a,s,u=n.xhr();if(n.username?u.open(n.type,n.url,n.async,n.username,n.password):u.open(n.type,n.url,n.async),n.xhrFields)for(s in n.xhrFields)u[s]=n.xhrFields[s];n.mimeType&&u.overrideMimeType&&u.overrideMimeType(n.mimeType),n.crossDomain||i["X-Requested-With"]||(i["X-Requested-With"]="XMLHttpRequest");try{for(s in i)u.setRequestHeader(s,i[s])}catch(l){}u.send(n.hasContent&&n.data||null),r=function(e,i){var s,l,c,f,p;try{if(r&&(i||4===u.readyState))if(r=t,a&&(u.onreadystatechange=st.noop,Gn&&delete Vn[a]),i)4!==u.readyState&&u.abort();else{f={},s=u.status,p=u.responseXML,c=u.getAllResponseHeaders(),p&&p.documentElement&&(f.xml=p),"string"==typeof u.responseText&&(f.text=u.responseText);try{l=u.statusText}catch(d){l=""}s||!n.isLocal||n.crossDomain?1223===s&&(s=204):s=f.text?200:404}}catch(h){i||o(-1,h)}f&&o(s,l,f,c)},n.async?4===u.readyState?setTimeout(r):(a=++Jn,Gn&&(Vn||(Vn={},st(e).unload(Gn)),Vn[a]=r),u.onreadystatechange=r):r()},abort:function(){r&&r(t,!0)}}}});var Qn,Kn,Zn=/^(?:toggle|show|hide)$/,er=RegExp("^(?:([+-])=|)("+ut+")([a-z%]*)$","i"),tr=/queueHooks$/,nr=[W],rr={"*":[function(e,t){var n,r,i=this.createTween(e,t),o=er.exec(t),a=i.cur(),s=+a||0,u=1,l=20;if(o){if(n=+o[2],r=o[3]||(st.cssNumber[e]?"":"px"),"px"!==r&&s){s=st.css(i.elem,e,!0)||n||1;do u=u||".5",s/=u,st.style(i.elem,e,s+r);while(u!==(u=i.cur()/a)&&1!==u&&--l)}i.unit=r,i.start=s,i.end=o[1]?s+(o[1]+1)*n:n}return i}]};st.Animation=st.extend(P,{tweener:function(e,t){st.isFunction(e)?(t=e,e=["*"]):e=e.split(" ");for(var n,r=0,i=e.length;i>r;r++)n=e[r],rr[n]=rr[n]||[],rr[n].unshift(t)},prefilter:function(e,t){t?nr.unshift(e):nr.push(e)}}),st.Tween=$,$.prototype={constructor:$,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||"swing",this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(st.cssNumber[n]?"":"px")},cur:function(){var e=$.propHooks[this.prop];return e&&e.get?e.get(this):$.propHooks._default.get(this)},run:function(e){var t,n=$.propHooks[this.prop];return this.pos=t=this.options.duration?st.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):$.propHooks._default.set(this),this}},$.prototype.init.prototype=$.prototype,$.propHooks={_default:{get:function(e){var t;return null==e.elem[e.prop]||e.elem.style&&null!=e.elem.style[e.prop]?(t=st.css(e.elem,e.prop,"auto"),t&&"auto"!==t?t:0):e.elem[e.prop]},set:function(e){st.fx.step[e.prop]?st.fx.step[e.prop](e):e.elem.style&&(null!=e.elem.style[st.cssProps[e.prop]]||st.cssHooks[e.prop])?st.style(e.elem,e.prop,e.now+e.unit):e.elem[e.prop]=e.now}}},$.propHooks.scrollTop=$.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},st.each(["toggle","show","hide"],function(e,t){var n=st.fn[t];st.fn[t]=function(e,r,i){return null==e||"boolean"==typeof e?n.apply(this,arguments):this.animate(I(t,!0),e,r,i)}}),st.fn.extend({fadeTo:function(e,t,n,r){return this.filter(w).css("opacity",0).show().end().animate({opacity:t},e,n,r)},animate:function(e,t,n,r){var i=st.isEmptyObject(e),o=st.speed(t,n,r),a=function(){var t=P(this,st.extend({},e),o);a.finish=function(){t.stop(!0)},(i||st._data(this,"finish"))&&t.stop(!0)};return a.finish=a,i||o.queue===!1?this.each(a):this.queue(o.queue,a)},stop:function(e,n,r){var i=function(e){var t=e.stop;delete e.stop,t(r)};return"string"!=typeof e&&(r=n,n=e,e=t),n&&e!==!1&&this.queue(e||"fx",[]),this.each(function(){var t=!0,n=null!=e&&e+"queueHooks",o=st.timers,a=st._data(this);if(n)a[n]&&a[n].stop&&i(a[n]);else for(n in a)a[n]&&a[n].stop&&tr.test(n)&&i(a[n]);for(n=o.length;n--;)o[n].elem!==this||null!=e&&o[n].queue!==e||(o[n].anim.stop(r),t=!1,o.splice(n,1));(t||!r)&&st.dequeue(this,e)})},finish:function(e){return e!==!1&&(e=e||"fx"),this.each(function(){var t,n=st._data(this),r=n[e+"queue"],i=n[e+"queueHooks"],o=st.timers,a=r?r.length:0;for(n.finish=!0,st.queue(this,e,[]),i&&i.cur&&i.cur.finish&&i.cur.finish.call(this),t=o.length;t--;)o[t].elem===this&&o[t].queue===e&&(o[t].anim.stop(!0),o.splice(t,1));for(t=0;a>t;t++)r[t]&&r[t].finish&&r[t].finish.call(this);delete n.finish})}}),st.each({slideDown:I("show"),slideUp:I("hide"),slideToggle:I("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(e,t){st.fn[e]=function(e,n,r){return this.animate(t,e,n,r)}}),st.speed=function(e,t,n){var r=e&&"object"==typeof e?st.extend({},e):{complete:n||!n&&t||st.isFunction(e)&&e,duration:e,easing:n&&t||t&&!st.isFunction(t)&&t};return r.duration=st.fx.off?0:"number"==typeof r.duration?r.duration:r.duration in st.fx.speeds?st.fx.speeds[r.duration]:st.fx.speeds._default,(null==r.queue||r.queue===!0)&&(r.queue="fx"),r.old=r.complete,r.complete=function(){st.isFunction(r.old)&&r.old.call(this),r.queue&&st.dequeue(this,r.queue)},r},st.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2}},st.timers=[],st.fx=$.prototype.init,st.fx.tick=function(){var e,n=st.timers,r=0;for(Qn=st.now();n.length>r;r++)e=n[r],e()||n[r]!==e||n.splice(r--,1);n.length||st.fx.stop(),Qn=t},st.fx.timer=function(e){e()&&st.timers.push(e)&&st.fx.start()},st.fx.interval=13,st.fx.start=function(){Kn||(Kn=setInterval(st.fx.tick,st.fx.interval))},st.fx.stop=function(){clearInterval(Kn),Kn=null},st.fx.speeds={slow:600,fast:200,_default:400},st.fx.step={},st.expr&&st.expr.filters&&(st.expr.filters.animated=function(e){return st.grep(st.timers,function(t){return e===t.elem}).length}),st.fn.offset=function(e){if(arguments.length)return e===t?this:this.each(function(t){st.offset.setOffset(this,e,t)});var n,r,i={top:0,left:0},o=this[0],a=o&&o.ownerDocument;if(a)return n=a.documentElement,st.contains(n,o)?(o.getBoundingClientRect!==t&&(i=o.getBoundingClientRect()),r=z(a),{top:i.top+(r.pageYOffset||n.scrollTop)-(n.clientTop||0),left:i.left+(r.pageXOffset||n.scrollLeft)-(n.clientLeft||0)}):i},st.offset={setOffset:function(e,t,n){var r=st.css(e,"position");"static"===r&&(e.style.position="relative");var i,o,a=st(e),s=a.offset(),u=st.css(e,"top"),l=st.css(e,"left"),c=("absolute"===r||"fixed"===r)&&st.inArray("auto",[u,l])>-1,f={},p={};c?(p=a.position(),i=p.top,o=p.left):(i=parseFloat(u)||0,o=parseFloat(l)||0),st.isFunction(t)&&(t=t.call(e,n,s)),null!=t.top&&(f.top=t.top-s.top+i),null!=t.left&&(f.left=t.left-s.left+o),"using"in t?t.using.call(e,f):a.css(f)}},st.fn.extend({position:function(){if(this[0]){var e,t,n={top:0,left:0},r=this[0];return"fixed"===st.css(r,"position")?t=r.getBoundingClientRect():(e=this.offsetParent(),t=this.offset(),st.nodeName(e[0],"html")||(n=e.offset()),n.top+=st.css(e[0],"borderTopWidth",!0),n.left+=st.css(e[0],"borderLeftWidth",!0)),{top:t.top-n.top-st.css(r,"marginTop",!0),left:t.left-n.left-st.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){for(var e=this.offsetParent||V.documentElement;e&&!st.nodeName(e,"html")&&"static"===st.css(e,"position");)e=e.offsetParent;return e||V.documentElement})}}),st.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(e,n){var r=/Y/.test(n);st.fn[e]=function(i){return st.access(this,function(e,i,o){var a=z(e);return o===t?a?n in a?a[n]:a.document.documentElement[i]:e[i]:(a?a.scrollTo(r?st(a).scrollLeft():o,r?o:st(a).scrollTop()):e[i]=o,t)},e,i,arguments.length,null)}}),st.each({Height:"height",Width:"width"},function(e,n){st.each({padding:"inner"+e,content:n,"":"outer"+e},function(r,i){st.fn[i]=function(i,o){var a=arguments.length&&(r||"boolean"!=typeof i),s=r||(i===!0||o===!0?"margin":"border");return st.access(this,function(n,r,i){var o;return st.isWindow(n)?n.document.documentElement["client"+e]:9===n.nodeType?(o=n.documentElement,Math.max(n.body["scroll"+e],o["scroll"+e],n.body["offset"+e],o["offset"+e],o["client"+e])):i===t?st.css(n,r,s):st.style(n,r,i,s)},n,a?i:t,a,null)}})}),e.jQuery=e.$=st,"function"==typeof define&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return st})})(window);
4
-//@ sourceMappingURL=jquery.min.map
1
+/*! jQuery v2.0.1 | (c) 2005, 2013 jQuery Foundation, Inc. | jquery.org/license
2
+//@ sourceMappingURL=jquery-2.0.1.min.map
3
+*/
4
+(function(e,undefined){var t,n,r=typeof undefined,i=e.location,o=e.document,s=o.documentElement,a=e.jQuery,u=e.$,l={},c=[],f="2.0.1",p=c.concat,h=c.push,d=c.slice,g=c.indexOf,m=l.toString,y=l.hasOwnProperty,v=f.trim,x=function(e,n){return new x.fn.init(e,n,t)},b=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,w=/\S+/g,T=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,C=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,k=/^-ms-/,N=/-([\da-z])/gi,E=function(e,t){return t.toUpperCase()},S=function(){o.removeEventListener("DOMContentLoaded",S,!1),e.removeEventListener("load",S,!1),x.ready()};x.fn=x.prototype={jquery:f,constructor:x,init:function(e,t,n){var r,i;if(!e)return this;if("string"==typeof e){if(r="<"===e.charAt(0)&&">"===e.charAt(e.length-1)&&e.length>=3?[null,e,null]:T.exec(e),!r||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof x?t[0]:t,x.merge(this,x.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:o,!0)),C.test(r[1])&&x.isPlainObject(t))for(r in t)x.isFunction(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return i=o.getElementById(r[2]),i&&i.parentNode&&(this.length=1,this[0]=i),this.context=o,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):x.isFunction(e)?n.ready(e):(e.selector!==undefined&&(this.selector=e.selector,this.context=e.context),x.makeArray(e,this))},selector:"",length:0,toArray:function(){return d.call(this)},get:function(e){return null==e?this.toArray():0>e?this[this.length+e]:this[e]},pushStack:function(e){var t=x.merge(this.constructor(),e);return t.prevObject=this,t.context=this.context,t},each:function(e,t){return x.each(this,e,t)},ready:function(e){return x.ready.promise().done(e),this},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(0>e?t:0);return this.pushStack(n>=0&&t>n?[this[n]]:[])},map:function(e){return this.pushStack(x.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:h,sort:[].sort,splice:[].splice},x.fn.init.prototype=x.fn,x.extend=x.fn.extend=function(){var e,t,n,r,i,o,s=arguments[0]||{},a=1,u=arguments.length,l=!1;for("boolean"==typeof s&&(l=s,s=arguments[1]||{},a=2),"object"==typeof s||x.isFunction(s)||(s={}),u===a&&(s=this,--a);u>a;a++)if(null!=(e=arguments[a]))for(t in e)n=s[t],r=e[t],s!==r&&(l&&r&&(x.isPlainObject(r)||(i=x.isArray(r)))?(i?(i=!1,o=n&&x.isArray(n)?n:[]):o=n&&x.isPlainObject(n)?n:{},s[t]=x.extend(l,o,r)):r!==undefined&&(s[t]=r));return s},x.extend({expando:"jQuery"+(f+Math.random()).replace(/\D/g,""),noConflict:function(t){return e.$===x&&(e.$=u),t&&e.jQuery===x&&(e.jQuery=a),x},isReady:!1,readyWait:1,holdReady:function(e){e?x.readyWait++:x.ready(!0)},ready:function(e){(e===!0?--x.readyWait:x.isReady)||(x.isReady=!0,e!==!0&&--x.readyWait>0||(n.resolveWith(o,[x]),x.fn.trigger&&x(o).trigger("ready").off("ready")))},isFunction:function(e){return"function"===x.type(e)},isArray:Array.isArray,isWindow:function(e){return null!=e&&e===e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?l[m.call(e)]||"object":typeof e},isPlainObject:function(e){if("object"!==x.type(e)||e.nodeType||x.isWindow(e))return!1;try{if(e.constructor&&!y.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(t){return!1}return!0},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw Error(e)},parseHTML:function(e,t,n){if(!e||"string"!=typeof e)return null;"boolean"==typeof t&&(n=t,t=!1),t=t||o;var r=C.exec(e),i=!n&&[];return r?[t.createElement(r[1])]:(r=x.buildFragment([e],t,i),i&&x(i).remove(),x.merge([],r.childNodes))},parseJSON:JSON.parse,parseXML:function(e){var t,n;if(!e||"string"!=typeof e)return null;try{n=new DOMParser,t=n.parseFromString(e,"text/xml")}catch(r){t=undefined}return(!t||t.getElementsByTagName("parsererror").length)&&x.error("Invalid XML: "+e),t},noop:function(){},globalEval:function(e){var t,n=eval;e=x.trim(e),e&&(1===e.indexOf("use strict")?(t=o.createElement("script"),t.text=e,o.head.appendChild(t).parentNode.removeChild(t)):n(e))},camelCase:function(e){return e.replace(k,"ms-").replace(N,E)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,t,n){var r,i=0,o=e.length,s=j(e);if(n){if(s){for(;o>i;i++)if(r=t.apply(e[i],n),r===!1)break}else for(i in e)if(r=t.apply(e[i],n),r===!1)break}else if(s){for(;o>i;i++)if(r=t.call(e[i],i,e[i]),r===!1)break}else for(i in e)if(r=t.call(e[i],i,e[i]),r===!1)break;return e},trim:function(e){return null==e?"":v.call(e)},makeArray:function(e,t){var n=t||[];return null!=e&&(j(Object(e))?x.merge(n,"string"==typeof e?[e]:e):h.call(n,e)),n},inArray:function(e,t,n){return null==t?-1:g.call(t,e,n)},merge:function(e,t){var n=t.length,r=e.length,i=0;if("number"==typeof n)for(;n>i;i++)e[r++]=t[i];else while(t[i]!==undefined)e[r++]=t[i++];return e.length=r,e},grep:function(e,t,n){var r,i=[],o=0,s=e.length;for(n=!!n;s>o;o++)r=!!t(e[o],o),n!==r&&i.push(e[o]);return i},map:function(e,t,n){var r,i=0,o=e.length,s=j(e),a=[];if(s)for(;o>i;i++)r=t(e[i],i,n),null!=r&&(a[a.length]=r);else for(i in e)r=t(e[i],i,n),null!=r&&(a[a.length]=r);return p.apply([],a)},guid:1,proxy:function(e,t){var n,r,i;return"string"==typeof t&&(n=e[t],t=e,e=n),x.isFunction(e)?(r=d.call(arguments,2),i=function(){return e.apply(t||this,r.concat(d.call(arguments)))},i.guid=e.guid=e.guid||x.guid++,i):undefined},access:function(e,t,n,r,i,o,s){var a=0,u=e.length,l=null==n;if("object"===x.type(n)){i=!0;for(a in n)x.access(e,t,a,n[a],!0,o,s)}else if(r!==undefined&&(i=!0,x.isFunction(r)||(s=!0),l&&(s?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(x(e),n)})),t))for(;u>a;a++)t(e[a],n,s?r:r.call(e[a],a,t(e[a],n)));return i?e:l?t.call(e):u?t(e[0],n):o},now:Date.now,swap:function(e,t,n,r){var i,o,s={};for(o in t)s[o]=e.style[o],e.style[o]=t[o];i=n.apply(e,r||[]);for(o in t)e.style[o]=s[o];return i}}),x.ready.promise=function(t){return n||(n=x.Deferred(),"complete"===o.readyState?setTimeout(x.ready):(o.addEventListener("DOMContentLoaded",S,!1),e.addEventListener("load",S,!1))),n.promise(t)},x.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(e,t){l["[object "+t+"]"]=t.toLowerCase()});function j(e){var t=e.length,n=x.type(e);return x.isWindow(e)?!1:1===e.nodeType&&t?!0:"array"===n||"function"!==n&&(0===t||"number"==typeof t&&t>0&&t-1 in e)}t=x(o),function(e,undefined){var t,n,r,i,o,s,a,u,l,c,f,p,h,d,g,m,y,v="sizzle"+-new Date,b=e.document,w=0,T=0,C=at(),k=at(),N=at(),E=!1,S=function(){return 0},j=typeof undefined,D=1<<31,A={}.hasOwnProperty,L=[],H=L.pop,q=L.push,O=L.push,F=L.slice,P=L.indexOf||function(e){var t=0,n=this.length;for(;n>t;t++)if(this[t]===e)return t;return-1},R="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",M="[\\x20\\t\\r\\n\\f]",W="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",$=W.replace("w","w#"),B="\\["+M+"*("+W+")"+M+"*(?:([*^$|!~]?=)"+M+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+$+")|)|)"+M+"*\\]",I=":("+W+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+B.replace(3,8)+")*)|.*)\\)|)",z=RegExp("^"+M+"+|((?:^|[^\\\\])(?:\\\\.)*)"+M+"+$","g"),_=RegExp("^"+M+"*,"+M+"*"),X=RegExp("^"+M+"*([>+~]|"+M+")"+M+"*"),U=RegExp(M+"*[+~]"),Y=RegExp("="+M+"*([^\\]'\"]*)"+M+"*\\]","g"),V=RegExp(I),G=RegExp("^"+$+"$"),J={ID:RegExp("^#("+W+")"),CLASS:RegExp("^\\.("+W+")"),TAG:RegExp("^("+W.replace("w","w*")+")"),ATTR:RegExp("^"+B),PSEUDO:RegExp("^"+I),CHILD:RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:RegExp("^(?:"+R+")$","i"),needsContext:RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Q=/^[^{]+\{\s*\[native \w/,K=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,Z=/^(?:input|select|textarea|button)$/i,et=/^h\d$/i,tt=/'|\\/g,nt=RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),rt=function(e,t,n){var r="0x"+t-65536;return r!==r||n?t:0>r?String.fromCharCode(r+65536):String.fromCharCode(55296|r>>10,56320|1023&r)};try{O.apply(L=F.call(b.childNodes),b.childNodes),L[b.childNodes.length].nodeType}catch(it){O={apply:L.length?function(e,t){q.apply(e,F.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function ot(e,t,r,i){var o,s,a,u,l,p,g,m,x,w;if((t?t.ownerDocument||t:b)!==f&&c(t),t=t||f,r=r||[],!e||"string"!=typeof e)return r;if(1!==(u=t.nodeType)&&9!==u)return[];if(h&&!i){if(o=K.exec(e))if(a=o[1]){if(9===u){if(s=t.getElementById(a),!s||!s.parentNode)return r;if(s.id===a)return r.push(s),r}else if(t.ownerDocument&&(s=t.ownerDocument.getElementById(a))&&y(t,s)&&s.id===a)return r.push(s),r}else{if(o[2])return O.apply(r,t.getElementsByTagName(e)),r;if((a=o[3])&&n.getElementsByClassName&&t.getElementsByClassName)return O.apply(r,t.getElementsByClassName(a)),r}if(n.qsa&&(!d||!d.test(e))){if(m=g=v,x=t,w=9===u&&e,1===u&&"object"!==t.nodeName.toLowerCase()){p=vt(e),(g=t.getAttribute("id"))?m=g.replace(tt,"\\$&"):t.setAttribute("id",m),m="[id='"+m+"'] ",l=p.length;while(l--)p[l]=m+xt(p[l]);x=U.test(e)&&t.parentNode||t,w=p.join(",")}if(w)try{return O.apply(r,x.querySelectorAll(w)),r}catch(T){}finally{g||t.removeAttribute("id")}}}return St(e.replace(z,"$1"),t,r,i)}function st(e){return Q.test(e+"")}function at(){var e=[];function t(n,r){return e.push(n+=" ")>i.cacheLength&&delete t[e.shift()],t[n]=r}return t}function ut(e){return e[v]=!0,e}function lt(e){var t=f.createElement("div");try{return!!e(t)}catch(n){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function ct(e,t,n){e=e.split("|");var r,o=e.length,s=n?null:t;while(o--)(r=i.attrHandle[e[o]])&&r!==t||(i.attrHandle[e[o]]=s)}function ft(e,t){var n=e.getAttributeNode(t);return n&&n.specified?n.value:e[t]===!0?t.toLowerCase():null}function pt(e,t){return e.getAttribute(t,"type"===t.toLowerCase()?1:2)}function ht(e){return"input"===e.nodeName.toLowerCase()?e.defaultValue:undefined}function dt(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&(~t.sourceIndex||D)-(~e.sourceIndex||D);if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function gt(e){return function(t){var n=t.nodeName.toLowerCase();return"input"===n&&t.type===e}}function mt(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function yt(e){return ut(function(t){return t=+t,ut(function(n,r){var i,o=e([],n.length,t),s=o.length;while(s--)n[i=o[s]]&&(n[i]=!(r[i]=n[i]))})})}s=ot.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?"HTML"!==t.nodeName:!1},n=ot.support={},c=ot.setDocument=function(e){var t=e?e.ownerDocument||e:b;return t!==f&&9===t.nodeType&&t.documentElement?(f=t,p=t.documentElement,h=!s(t),n.attributes=lt(function(e){return e.innerHTML="<a href='#'></a>",ct("type|href|height|width",pt,"#"===e.firstChild.getAttribute("href")),ct(R,ft,null==e.getAttribute("disabled")),e.className="i",!e.getAttribute("className")}),n.input=lt(function(e){return e.innerHTML="<input>",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")}),ct("value",ht,n.attributes&&n.input),n.getElementsByTagName=lt(function(e){return e.appendChild(t.createComment("")),!e.getElementsByTagName("*").length}),n.getElementsByClassName=lt(function(e){return e.innerHTML="<div class='a'></div><div class='a i'></div>",e.firstChild.className="i",2===e.getElementsByClassName("i").length}),n.getById=lt(function(e){return p.appendChild(e).id=v,!t.getElementsByName||!t.getElementsByName(v).length}),n.getById?(i.find.ID=function(e,t){if(typeof t.getElementById!==j&&h){var n=t.getElementById(e);return n&&n.parentNode?[n]:[]}},i.filter.ID=function(e){var t=e.replace(nt,rt);return function(e){return e.getAttribute("id")===t}}):(delete i.find.ID,i.filter.ID=function(e){var t=e.replace(nt,rt);return function(e){var n=typeof e.getAttributeNode!==j&&e.getAttributeNode("id");return n&&n.value===t}}),i.find.TAG=n.getElementsByTagName?function(e,t){return typeof t.getElementsByTagName!==j?t.getElementsByTagName(e):undefined}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},i.find.CLASS=n.getElementsByClassName&&function(e,t){return typeof t.getElementsByClassName!==j&&h?t.getElementsByClassName(e):undefined},g=[],d=[],(n.qsa=st(t.querySelectorAll))&&(lt(function(e){e.innerHTML="<select><option selected=''></option></select>",e.querySelectorAll("[selected]").length||d.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll(":checked").length||d.push(":checked")}),lt(function(e){var n=t.createElement("input");n.setAttribute("type","hidden"),e.appendChild(n).setAttribute("t",""),e.querySelectorAll("[t^='']").length&&d.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll(":enabled").length||d.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),d.push(",.*:")})),(n.matchesSelector=st(m=p.webkitMatchesSelector||p.mozMatchesSelector||p.oMatchesSelector||p.msMatchesSelector))&&lt(function(e){n.disconnectedMatch=m.call(e,"div"),m.call(e,"[s!='']:x"),g.push("!=",I)}),d=d.length&&RegExp(d.join("|")),g=g.length&&RegExp(g.join("|")),y=st(p.contains)||p.compareDocumentPosition?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},n.sortDetached=lt(function(e){return 1&e.compareDocumentPosition(t.createElement("div"))}),S=p.compareDocumentPosition?function(e,r){if(e===r)return E=!0,0;var i=r.compareDocumentPosition&&e.compareDocumentPosition&&e.compareDocumentPosition(r);return i?1&i||!n.sortDetached&&r.compareDocumentPosition(e)===i?e===t||y(b,e)?-1:r===t||y(b,r)?1:l?P.call(l,e)-P.call(l,r):0:4&i?-1:1:e.compareDocumentPosition?-1:1}:function(e,n){var r,i=0,o=e.parentNode,s=n.parentNode,a=[e],u=[n];if(e===n)return E=!0,0;if(!o||!s)return e===t?-1:n===t?1:o?-1:s?1:l?P.call(l,e)-P.call(l,n):0;if(o===s)return dt(e,n);r=e;while(r=r.parentNode)a.unshift(r);r=n;while(r=r.parentNode)u.unshift(r);while(a[i]===u[i])i++;return i?dt(a[i],u[i]):a[i]===b?-1:u[i]===b?1:0},t):f},ot.matches=function(e,t){return ot(e,null,null,t)},ot.matchesSelector=function(e,t){if((e.ownerDocument||e)!==f&&c(e),t=t.replace(Y,"='$1']"),!(!n.matchesSelector||!h||g&&g.test(t)||d&&d.test(t)))try{var r=m.call(e,t);if(r||n.disconnectedMatch||e.document&&11!==e.document.nodeType)return r}catch(i){}return ot(t,f,null,[e]).length>0},ot.contains=function(e,t){return(e.ownerDocument||e)!==f&&c(e),y(e,t)},ot.attr=function(e,t){(e.ownerDocument||e)!==f&&c(e);var r=i.attrHandle[t.toLowerCase()],o=r&&A.call(i.attrHandle,t.toLowerCase())?r(e,t,!h):undefined;return o===undefined?n.attributes||!h?e.getAttribute(t):(o=e.getAttributeNode(t))&&o.specified?o.value:null:o},ot.error=function(e){throw Error("Syntax error, unrecognized expression: "+e)},ot.uniqueSort=function(e){var t,r=[],i=0,o=0;if(E=!n.detectDuplicates,l=!n.sortStable&&e.slice(0),e.sort(S),E){while(t=e[o++])t===e[o]&&(i=r.push(o));while(i--)e.splice(r[i],1)}return e},o=ot.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=o(e)}else if(3===i||4===i)return e.nodeValue}else for(;t=e[r];r++)n+=o(t);return n},i=ot.selectors={cacheLength:50,createPseudo:ut,match:J,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(nt,rt),e[3]=(e[4]||e[5]||"").replace(nt,rt),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||ot.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&ot.error(e[0]),e},PSEUDO:function(e){var t,n=!e[5]&&e[2];return J.CHILD.test(e[0])?null:(e[3]&&e[4]!==undefined?e[2]=e[4]:n&&V.test(n)&&(t=vt(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(nt,rt).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=C[e+" "];return t||(t=RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&C(e,function(e){return t.test("string"==typeof e.className&&e.className||typeof e.getAttribute!==j&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=ot.attr(r,e);return null==i?"!="===t:t?(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i+" ").indexOf(n)>-1:"|="===t?i===n||i.slice(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),s="last"!==e.slice(-4),a="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,u){var l,c,f,p,h,d,g=o!==s?"nextSibling":"previousSibling",m=t.parentNode,y=a&&t.nodeName.toLowerCase(),x=!u&&!a;if(m){if(o){while(g){f=t;while(f=f[g])if(a?f.nodeName.toLowerCase()===y:1===f.nodeType)return!1;d=g="only"===e&&!d&&"nextSibling"}return!0}if(d=[s?m.firstChild:m.lastChild],s&&x){c=m[v]||(m[v]={}),l=c[e]||[],h=l[0]===w&&l[1],p=l[0]===w&&l[2],f=h&&m.childNodes[h];while(f=++h&&f&&f[g]||(p=h=0)||d.pop())if(1===f.nodeType&&++p&&f===t){c[e]=[w,h,p];break}}else if(x&&(l=(t[v]||(t[v]={}))[e])&&l[0]===w)p=l[1];else while(f=++h&&f&&f[g]||(p=h=0)||d.pop())if((a?f.nodeName.toLowerCase()===y:1===f.nodeType)&&++p&&(x&&((f[v]||(f[v]={}))[e]=[w,p]),f===t))break;return p-=i,p===r||0===p%r&&p/r>=0}}},PSEUDO:function(e,t){var n,r=i.pseudos[e]||i.setFilters[e.toLowerCase()]||ot.error("unsupported pseudo: "+e);return r[v]?r(t):r.length>1?(n=[e,e,"",t],i.setFilters.hasOwnProperty(e.toLowerCase())?ut(function(e,n){var i,o=r(e,t),s=o.length;while(s--)i=P.call(e,o[s]),e[i]=!(n[i]=o[s])}):function(e){return r(e,0,n)}):r}},pseudos:{not:ut(function(e){var t=[],n=[],r=a(e.replace(z,"$1"));return r[v]?ut(function(e,t,n,i){var o,s=r(e,null,i,[]),a=e.length;while(a--)(o=s[a])&&(e[a]=!(t[a]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),!n.pop()}}),has:ut(function(e){return function(t){return ot(e,t).length>0}}),contains:ut(function(e){return function(t){return(t.textContent||t.innerText||o(t)).indexOf(e)>-1}}),lang:ut(function(e){return G.test(e||"")||ot.error("unsupported lang: "+e),e=e.replace(nt,rt).toLowerCase(),function(t){var n;do if(n=h?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return n=n.toLowerCase(),n===e||0===n.indexOf(e+"-");while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===p},focus:function(e){return e===f.activeElement&&(!f.hasFocus||f.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeName>"@"||3===e.nodeType||4===e.nodeType)return!1;return!0},parent:function(e){return!i.pseudos.empty(e)},header:function(e){return et.test(e.nodeName)},input:function(e){return Z.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||t.toLowerCase()===e.type)},first:yt(function(){return[0]}),last:yt(function(e,t){return[t-1]}),eq:yt(function(e,t,n){return[0>n?n+t:n]}),even:yt(function(e,t){var n=0;for(;t>n;n+=2)e.push(n);return e}),odd:yt(function(e,t){var n=1;for(;t>n;n+=2)e.push(n);return e}),lt:yt(function(e,t,n){var r=0>n?n+t:n;for(;--r>=0;)e.push(r);return e}),gt:yt(function(e,t,n){var r=0>n?n+t:n;for(;t>++r;)e.push(r);return e})}};for(t in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})i.pseudos[t]=gt(t);for(t in{submit:!0,reset:!0})i.pseudos[t]=mt(t);function vt(e,t){var n,r,o,s,a,u,l,c=k[e+" "];if(c)return t?0:c.slice(0);a=e,u=[],l=i.preFilter;while(a){(!n||(r=_.exec(a)))&&(r&&(a=a.slice(r[0].length)||a),u.push(o=[])),n=!1,(r=X.exec(a))&&(n=r.shift(),o.push({value:n,type:r[0].replace(z," ")}),a=a.slice(n.length));for(s in i.filter)!(r=J[s].exec(a))||l[s]&&!(r=l[s](r))||(n=r.shift(),o.push({value:n,type:s,matches:r}),a=a.slice(n.length));if(!n)break}return t?a.length:a?ot.error(e):k(e,u).slice(0)}function xt(e){var t=0,n=e.length,r="";for(;n>t;t++)r+=e[t].value;return r}function bt(e,t,n){var i=t.dir,o=n&&"parentNode"===i,s=T++;return t.first?function(t,n,r){while(t=t[i])if(1===t.nodeType||o)return e(t,n,r)}:function(t,n,a){var u,l,c,f=w+" "+s;if(a){while(t=t[i])if((1===t.nodeType||o)&&e(t,n,a))return!0}else while(t=t[i])if(1===t.nodeType||o)if(c=t[v]||(t[v]={}),(l=c[i])&&l[0]===f){if((u=l[1])===!0||u===r)return u===!0}else if(l=c[i]=[f],l[1]=e(t,n,a)||r,l[1]===!0)return!0}}function wt(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function Tt(e,t,n,r,i){var o,s=[],a=0,u=e.length,l=null!=t;for(;u>a;a++)(o=e[a])&&(!n||n(o,r,i))&&(s.push(o),l&&t.push(a));return s}function Ct(e,t,n,r,i,o){return r&&!r[v]&&(r=Ct(r)),i&&!i[v]&&(i=Ct(i,o)),ut(function(o,s,a,u){var l,c,f,p=[],h=[],d=s.length,g=o||Et(t||"*",a.nodeType?[a]:a,[]),m=!e||!o&&t?g:Tt(g,p,e,a,u),y=n?i||(o?e:d||r)?[]:s:m;if(n&&n(m,y,a,u),r){l=Tt(y,h),r(l,[],a,u),c=l.length;while(c--)(f=l[c])&&(y[h[c]]=!(m[h[c]]=f))}if(o){if(i||e){if(i){l=[],c=y.length;while(c--)(f=y[c])&&l.push(m[c]=f);i(null,y=[],l,u)}c=y.length;while(c--)(f=y[c])&&(l=i?P.call(o,f):p[c])>-1&&(o[l]=!(s[l]=f))}}else y=Tt(y===s?y.splice(d,y.length):y),i?i(null,s,y,u):O.apply(s,y)})}function kt(e){var t,n,r,o=e.length,s=i.relative[e[0].type],a=s||i.relative[" "],l=s?1:0,c=bt(function(e){return e===t},a,!0),f=bt(function(e){return P.call(t,e)>-1},a,!0),p=[function(e,n,r){return!s&&(r||n!==u)||((t=n).nodeType?c(e,n,r):f(e,n,r))}];for(;o>l;l++)if(n=i.relative[e[l].type])p=[bt(wt(p),n)];else{if(n=i.filter[e[l].type].apply(null,e[l].matches),n[v]){for(r=++l;o>r;r++)if(i.relative[e[r].type])break;return Ct(l>1&&wt(p),l>1&&xt(e.slice(0,l-1).concat({value:" "===e[l-2].type?"*":""})).replace(z,"$1"),n,r>l&&kt(e.slice(l,r)),o>r&&kt(e=e.slice(r)),o>r&&xt(e))}p.push(n)}return wt(p)}function Nt(e,t){var n=0,o=t.length>0,s=e.length>0,a=function(a,l,c,p,h){var d,g,m,y=[],v=0,x="0",b=a&&[],T=null!=h,C=u,k=a||s&&i.find.TAG("*",h&&l.parentNode||l),N=w+=null==C?1:Math.random()||.1;for(T&&(u=l!==f&&l,r=n);null!=(d=k[x]);x++){if(s&&d){g=0;while(m=e[g++])if(m(d,l,c)){p.push(d);break}T&&(w=N,r=++n)}o&&((d=!m&&d)&&v--,a&&b.push(d))}if(v+=x,o&&x!==v){g=0;while(m=t[g++])m(b,y,l,c);if(a){if(v>0)while(x--)b[x]||y[x]||(y[x]=H.call(p));y=Tt(y)}O.apply(p,y),T&&!a&&y.length>0&&v+t.length>1&&ot.uniqueSort(p)}return T&&(w=N,u=C),b};return o?ut(a):a}a=ot.compile=function(e,t){var n,r=[],i=[],o=N[e+" "];if(!o){t||(t=vt(e)),n=t.length;while(n--)o=kt(t[n]),o[v]?r.push(o):i.push(o);o=N(e,Nt(i,r))}return o};function Et(e,t,n){var r=0,i=t.length;for(;i>r;r++)ot(e,t[r],n);return n}function St(e,t,r,o){var s,u,l,c,f,p=vt(e);if(!o&&1===p.length){if(u=p[0]=p[0].slice(0),u.length>2&&"ID"===(l=u[0]).type&&n.getById&&9===t.nodeType&&h&&i.relative[u[1].type]){if(t=(i.find.ID(l.matches[0].replace(nt,rt),t)||[])[0],!t)return r;e=e.slice(u.shift().value.length)}s=J.needsContext.test(e)?0:u.length;while(s--){if(l=u[s],i.relative[c=l.type])break;if((f=i.find[c])&&(o=f(l.matches[0].replace(nt,rt),U.test(u[0].type)&&t.parentNode||t))){if(u.splice(s,1),e=o.length&&xt(u),!e)return O.apply(r,o),r;break}}}return a(e,p)(o,t,!h,r,U.test(e)),r}i.pseudos.nth=i.pseudos.eq;function jt(){}jt.prototype=i.filters=i.pseudos,i.setFilters=new jt,n.sortStable=v.split("").sort(S).join("")===v,c(),[0,0].sort(S),n.detectDuplicates=E,x.find=ot,x.expr=ot.selectors,x.expr[":"]=x.expr.pseudos,x.unique=ot.uniqueSort,x.text=ot.getText,x.isXMLDoc=ot.isXML,x.contains=ot.contains}(e);var D={};function A(e){var t=D[e]={};return x.each(e.match(w)||[],function(e,n){t[n]=!0}),t}x.Callbacks=function(e){e="string"==typeof e?D[e]||A(e):x.extend({},e);var t,n,r,i,o,s,a=[],u=!e.once&&[],l=function(f){for(t=e.memory&&f,n=!0,s=i||0,i=0,o=a.length,r=!0;a&&o>s;s++)if(a[s].apply(f[0],f[1])===!1&&e.stopOnFalse){t=!1;break}r=!1,a&&(u?u.length&&l(u.shift()):t?a=[]:c.disable())},c={add:function(){if(a){var n=a.length;(function s(t){x.each(t,function(t,n){var r=x.type(n);"function"===r?e.unique&&c.has(n)||a.push(n):n&&n.length&&"string"!==r&&s(n)})})(arguments),r?o=a.length:t&&(i=n,l(t))}return this},remove:function(){return a&&x.each(arguments,function(e,t){var n;while((n=x.inArray(t,a,n))>-1)a.splice(n,1),r&&(o>=n&&o--,s>=n&&s--)}),this},has:function(e){return e?x.inArray(e,a)>-1:!(!a||!a.length)},empty:function(){return a=[],o=0,this},disable:function(){return a=u=t=undefined,this},disabled:function(){return!a},lock:function(){return u=undefined,t||c.disable(),this},locked:function(){return!u},fireWith:function(e,t){return t=t||[],t=[e,t.slice?t.slice():t],!a||n&&!u||(r?u.push(t):l(t)),this},fire:function(){return c.fireWith(this,arguments),this},fired:function(){return!!n}};return c},x.extend({Deferred:function(e){var t=[["resolve","done",x.Callbacks("once memory"),"resolved"],["reject","fail",x.Callbacks("once memory"),"rejected"],["notify","progress",x.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return x.Deferred(function(n){x.each(t,function(t,o){var s=o[0],a=x.isFunction(e[t])&&e[t];i[o[1]](function(){var e=a&&a.apply(this,arguments);e&&x.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[s+"With"](this===r?n.promise():this,a?[e]:arguments)})}),e=null}).promise()},promise:function(e){return null!=e?x.extend(e,r):r}},i={};return r.pipe=r.then,x.each(t,function(e,o){var s=o[2],a=o[3];r[o[1]]=s.add,a&&s.add(function(){n=a},t[1^e][2].disable,t[2][2].lock),i[o[0]]=function(){return i[o[0]+"With"](this===i?r:this,arguments),this},i[o[0]+"With"]=s.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=d.call(arguments),r=n.length,i=1!==r||e&&x.isFunction(e.promise)?r:0,o=1===i?e:x.Deferred(),s=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?d.call(arguments):r,n===a?o.notifyWith(t,n):--i||o.resolveWith(t,n)}},a,u,l;if(r>1)for(a=Array(r),u=Array(r),l=Array(r);r>t;t++)n[t]&&x.isFunction(n[t].promise)?n[t].promise().done(s(t,l,n)).fail(o.reject).progress(s(t,u,a)):--i;return i||o.resolveWith(l,n),o.promise()}}),x.support=function(t){var n=o.createElement("input"),r=o.createDocumentFragment(),i=o.createElement("div"),s=o.createElement("select"),a=s.appendChild(o.createElement("option"));return n.type?(n.type="checkbox",t.checkOn=""!==n.value,t.optSelected=a.selected,t.reliableMarginRight=!0,t.boxSizingReliable=!0,t.pixelPosition=!1,n.checked=!0,t.noCloneChecked=n.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!a.disabled,n=o.createElement("input"),n.value="t",n.type="radio",t.radioValue="t"===n.value,n.setAttribute("checked","t"),n.setAttribute("name","t"),r.appendChild(n),t.checkClone=r.cloneNode(!0).cloneNode(!0).lastChild.checked,t.focusinBubbles="onfocusin"in e,i.style.backgroundClip="content-box",i.cloneNode(!0).style.backgroundClip="",t.clearCloneStyle="content-box"===i.style.backgroundClip,x(function(){var n,r,s="padding:0;margin:0;border:0;display:block;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box",a=o.getElementsByTagName("body")[0];a&&(n=o.createElement("div"),n.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px",a.appendChild(n).appendChild(i),i.innerHTML="",i.style.cssText="-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%",x.swap(a,null!=a.style.zoom?{zoom:1}:{},function(){t.boxSizing=4===i.offsetWidth}),e.getComputedStyle&&(t.pixelPosition="1%"!==(e.getComputedStyle(i,null)||{}).top,t.boxSizingReliable="4px"===(e.getComputedStyle(i,null)||{width:"4px"}).width,r=i.appendChild(o.createElement("div")),r.style.cssText=i.style.cssText=s,r.style.marginRight=r.style.width="0",i.style.width="1px",t.reliableMarginRight=!parseFloat((e.getComputedStyle(r,null)||{}).marginRight)),a.removeChild(n))}),t):t}({});var L,H,q=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,O=/([A-Z])/g;function F(){Object.defineProperty(this.cache={},0,{get:function(){return{}}}),this.expando=x.expando+Math.random()}F.uid=1,F.accepts=function(e){return e.nodeType?1===e.nodeType||9===e.nodeType:!0},F.prototype={key:function(e){if(!F.accepts(e))return 0;var t={},n=e[this.expando];if(!n){n=F.uid++;try{t[this.expando]={value:n},Object.defineProperties(e,t)}catch(r){t[this.expando]=n,x.extend(e,t)}}return this.cache[n]||(this.cache[n]={}),n},set:function(e,t,n){var r,i=this.key(e),o=this.cache[i];if("string"==typeof t)o[t]=n;else if(x.isEmptyObject(o))x.extend(this.cache[i],t);else for(r in t)o[r]=t[r];return o},get:function(e,t){var n=this.cache[this.key(e)];return t===undefined?n:n[t]},access:function(e,t,n){return t===undefined||t&&"string"==typeof t&&n===undefined?this.get(e,t):(this.set(e,t,n),n!==undefined?n:t)},remove:function(e,t){var n,r,i,o=this.key(e),s=this.cache[o];if(t===undefined)this.cache[o]={};else{x.isArray(t)?r=t.concat(t.map(x.camelCase)):(i=x.camelCase(t),t in s?r=[t,i]:(r=i,r=r in s?[r]:r.match(w)||[])),n=r.length;while(n--)delete s[r[n]]}},hasData:function(e){return!x.isEmptyObject(this.cache[e[this.expando]]||{})},discard:function(e){e[this.expando]&&delete this.cache[e[this.expando]]}},L=new F,H=new F,x.extend({acceptData:F.accepts,hasData:function(e){return L.hasData(e)||H.hasData(e)},data:function(e,t,n){return L.access(e,t,n)},removeData:function(e,t){L.remove(e,t)},_data:function(e,t,n){return H.access(e,t,n)},_removeData:function(e,t){H.remove(e,t)}}),x.fn.extend({data:function(e,t){var n,r,i=this[0],o=0,s=null;if(e===undefined){if(this.length&&(s=L.get(i),1===i.nodeType&&!H.get(i,"hasDataAttrs"))){for(n=i.attributes;n.length>o;o++)r=n[o].name,0===r.indexOf("data-")&&(r=x.camelCase(r.slice(5)),P(i,r,s[r]));H.set(i,"hasDataAttrs",!0)}return s}return"object"==typeof e?this.each(function(){L.set(this,e)}):x.access(this,function(t){var n,r=x.camelCase(e);if(i&&t===undefined){if(n=L.get(i,e),n!==undefined)return n;if(n=L.get(i,r),n!==undefined)return n;if(n=P(i,r,undefined),n!==undefined)return n}else this.each(function(){var n=L.get(this,r);L.set(this,r,t),-1!==e.indexOf("-")&&n!==undefined&&L.set(this,e,t)})},null,t,arguments.length>1,null,!0)},removeData:function(e){return this.each(function(){L.remove(this,e)})}});function P(e,t,n){var r;if(n===undefined&&1===e.nodeType)if(r="data-"+t.replace(O,"-$1").toLowerCase(),n=e.getAttribute(r),"string"==typeof n){try{n="true"===n?!0:"false"===n?!1:"null"===n?null:+n+""===n?+n:q.test(n)?JSON.parse(n):n}catch(i){}L.set(e,t,n)}else n=undefined;return n}x.extend({queue:function(e,t,n){var r;return e?(t=(t||"fx")+"queue",r=H.get(e,t),n&&(!r||x.isArray(n)?r=H.access(e,t,x.makeArray(n)):r.push(n)),r||[]):undefined},dequeue:function(e,t){t=t||"fx";var n=x.queue(e,t),r=n.length,i=n.shift(),o=x._queueHooks(e,t),s=function(){x.dequeue(e,t)};"inprogress"===i&&(i=n.shift(),r--),o.cur=i,i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,s,o)),!r&&o&&o.empty.fire()
5
+},_queueHooks:function(e,t){var n=t+"queueHooks";return H.get(e,n)||H.access(e,n,{empty:x.Callbacks("once memory").add(function(){H.remove(e,[t+"queue",n])})})}}),x.fn.extend({queue:function(e,t){var n=2;return"string"!=typeof e&&(t=e,e="fx",n--),n>arguments.length?x.queue(this[0],e):t===undefined?this:this.each(function(){var n=x.queue(this,e,t);x._queueHooks(this,e),"fx"===e&&"inprogress"!==n[0]&&x.dequeue(this,e)})},dequeue:function(e){return this.each(function(){x.dequeue(this,e)})},delay:function(e,t){return e=x.fx?x.fx.speeds[e]||e:e,t=t||"fx",this.queue(t,function(t,n){var r=setTimeout(t,e);n.stop=function(){clearTimeout(r)}})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,t){var n,r=1,i=x.Deferred(),o=this,s=this.length,a=function(){--r||i.resolveWith(o,[o])};"string"!=typeof e&&(t=e,e=undefined),e=e||"fx";while(s--)n=H.get(o[s],e+"queueHooks"),n&&n.empty&&(r++,n.empty.add(a));return a(),i.promise(t)}});var R,M,W=/[\t\r\n\f]/g,$=/\r/g,B=/^(?:input|select|textarea|button)$/i;x.fn.extend({attr:function(e,t){return x.access(this,x.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){x.removeAttr(this,e)})},prop:function(e,t){return x.access(this,x.prop,e,t,arguments.length>1)},removeProp:function(e){return this.each(function(){delete this[x.propFix[e]||e]})},addClass:function(e){var t,n,r,i,o,s=0,a=this.length,u="string"==typeof e&&e;if(x.isFunction(e))return this.each(function(t){x(this).addClass(e.call(this,t,this.className))});if(u)for(t=(e||"").match(w)||[];a>s;s++)if(n=this[s],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(W," "):" ")){o=0;while(i=t[o++])0>r.indexOf(" "+i+" ")&&(r+=i+" ");n.className=x.trim(r)}return this},removeClass:function(e){var t,n,r,i,o,s=0,a=this.length,u=0===arguments.length||"string"==typeof e&&e;if(x.isFunction(e))return this.each(function(t){x(this).removeClass(e.call(this,t,this.className))});if(u)for(t=(e||"").match(w)||[];a>s;s++)if(n=this[s],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(W," "):"")){o=0;while(i=t[o++])while(r.indexOf(" "+i+" ")>=0)r=r.replace(" "+i+" "," ");n.className=e?x.trim(r):""}return this},toggleClass:function(e,t){var n=typeof e,i="boolean"==typeof t;return x.isFunction(e)?this.each(function(n){x(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if("string"===n){var o,s=0,a=x(this),u=t,l=e.match(w)||[];while(o=l[s++])u=i?u:!a.hasClass(o),a[u?"addClass":"removeClass"](o)}else(n===r||"boolean"===n)&&(this.className&&H.set(this,"__className__",this.className),this.className=this.className||e===!1?"":H.get(this,"__className__")||"")})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;r>n;n++)if(1===this[n].nodeType&&(" "+this[n].className+" ").replace(W," ").indexOf(t)>=0)return!0;return!1},val:function(e){var t,n,r,i=this[0];{if(arguments.length)return r=x.isFunction(e),this.each(function(n){var i;1===this.nodeType&&(i=r?e.call(this,n,x(this).val()):e,null==i?i="":"number"==typeof i?i+="":x.isArray(i)&&(i=x.map(i,function(e){return null==e?"":e+""})),t=x.valHooks[this.type]||x.valHooks[this.nodeName.toLowerCase()],t&&"set"in t&&t.set(this,i,"value")!==undefined||(this.value=i))});if(i)return t=x.valHooks[i.type]||x.valHooks[i.nodeName.toLowerCase()],t&&"get"in t&&(n=t.get(i,"value"))!==undefined?n:(n=i.value,"string"==typeof n?n.replace($,""):null==n?"":n)}}}),x.extend({valHooks:{option:{get:function(e){var t=e.attributes.value;return!t||t.specified?e.value:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,o="select-one"===e.type||0>i,s=o?null:[],a=o?i+1:r.length,u=0>i?a:o?i:0;for(;a>u;u++)if(n=r[u],!(!n.selected&&u!==i||(x.support.optDisabled?n.disabled:null!==n.getAttribute("disabled"))||n.parentNode.disabled&&x.nodeName(n.parentNode,"optgroup"))){if(t=x(n).val(),o)return t;s.push(t)}return s},set:function(e,t){var n,r,i=e.options,o=x.makeArray(t),s=i.length;while(s--)r=i[s],(r.selected=x.inArray(x(r).val(),o)>=0)&&(n=!0);return n||(e.selectedIndex=-1),o}}},attr:function(e,t,n){var i,o,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return typeof e.getAttribute===r?x.prop(e,t,n):(1===s&&x.isXMLDoc(e)||(t=t.toLowerCase(),i=x.attrHooks[t]||(x.expr.match.bool.test(t)?M:R)),n===undefined?i&&"get"in i&&null!==(o=i.get(e,t))?o:(o=x.find.attr(e,t),null==o?undefined:o):null!==n?i&&"set"in i&&(o=i.set(e,n,t))!==undefined?o:(e.setAttribute(t,n+""),n):(x.removeAttr(e,t),undefined))},removeAttr:function(e,t){var n,r,i=0,o=t&&t.match(w);if(o&&1===e.nodeType)while(n=o[i++])r=x.propFix[n]||n,x.expr.match.bool.test(n)&&(e[r]=!1),e.removeAttribute(n)},attrHooks:{type:{set:function(e,t){if(!x.support.radioValue&&"radio"===t&&x.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},propFix:{"for":"htmlFor","class":"className"},prop:function(e,t,n){var r,i,o,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return o=1!==s||!x.isXMLDoc(e),o&&(t=x.propFix[t]||t,i=x.propHooks[t]),n!==undefined?i&&"set"in i&&(r=i.set(e,n,t))!==undefined?r:e[t]=n:i&&"get"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){return e.hasAttribute("tabindex")||B.test(e.nodeName)||e.href?e.tabIndex:-1}}}}),M={set:function(e,t,n){return t===!1?x.removeAttr(e,n):e.setAttribute(n,n),n}},x.each(x.expr.match.bool.source.match(/\w+/g),function(e,t){var n=x.expr.attrHandle[t]||x.find.attr;x.expr.attrHandle[t]=function(e,t,r){var i=x.expr.attrHandle[t],o=r?undefined:(x.expr.attrHandle[t]=undefined)!=n(e,t,r)?t.toLowerCase():null;return x.expr.attrHandle[t]=i,o}}),x.support.optSelected||(x.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null}}),x.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){x.propFix[this.toLowerCase()]=this}),x.each(["radio","checkbox"],function(){x.valHooks[this]={set:function(e,t){return x.isArray(t)?e.checked=x.inArray(x(e).val(),t)>=0:undefined}},x.support.checkOn||(x.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})});var I=/^key/,z=/^(?:mouse|contextmenu)|click/,_=/^(?:focusinfocus|focusoutblur)$/,X=/^([^.]*)(?:\.(.+)|)$/;function U(){return!0}function Y(){return!1}function V(){try{return o.activeElement}catch(e){}}x.event={global:{},add:function(e,t,n,i,o){var s,a,u,l,c,f,p,h,d,g,m,y=H.get(e);if(y){n.handler&&(s=n,n=s.handler,o=s.selector),n.guid||(n.guid=x.guid++),(l=y.events)||(l=y.events={}),(a=y.handle)||(a=y.handle=function(e){return typeof x===r||e&&x.event.triggered===e.type?undefined:x.event.dispatch.apply(a.elem,arguments)},a.elem=e),t=(t||"").match(w)||[""],c=t.length;while(c--)u=X.exec(t[c])||[],d=m=u[1],g=(u[2]||"").split(".").sort(),d&&(p=x.event.special[d]||{},d=(o?p.delegateType:p.bindType)||d,p=x.event.special[d]||{},f=x.extend({type:d,origType:m,data:i,handler:n,guid:n.guid,selector:o,needsContext:o&&x.expr.match.needsContext.test(o),namespace:g.join(".")},s),(h=l[d])||(h=l[d]=[],h.delegateCount=0,p.setup&&p.setup.call(e,i,g,a)!==!1||e.addEventListener&&e.addEventListener(d,a,!1)),p.add&&(p.add.call(e,f),f.handler.guid||(f.handler.guid=n.guid)),o?h.splice(h.delegateCount++,0,f):h.push(f),x.event.global[d]=!0);e=null}},remove:function(e,t,n,r,i){var o,s,a,u,l,c,f,p,h,d,g,m=H.hasData(e)&&H.get(e);if(m&&(u=m.events)){t=(t||"").match(w)||[""],l=t.length;while(l--)if(a=X.exec(t[l])||[],h=g=a[1],d=(a[2]||"").split(".").sort(),h){f=x.event.special[h]||{},h=(r?f.delegateType:f.bindType)||h,p=u[h]||[],a=a[2]&&RegExp("(^|\\.)"+d.join("\\.(?:.*\\.|)")+"(\\.|$)"),s=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||a&&!a.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));s&&!p.length&&(f.teardown&&f.teardown.call(e,d,m.handle)!==!1||x.removeEvent(e,h,m.handle),delete u[h])}else for(h in u)x.event.remove(e,h+t[l],n,r,!0);x.isEmptyObject(u)&&(delete m.handle,H.remove(e,"events"))}},trigger:function(t,n,r,i){var s,a,u,l,c,f,p,h=[r||o],d=y.call(t,"type")?t.type:t,g=y.call(t,"namespace")?t.namespace.split("."):[];if(a=u=r=r||o,3!==r.nodeType&&8!==r.nodeType&&!_.test(d+x.event.triggered)&&(d.indexOf(".")>=0&&(g=d.split("."),d=g.shift(),g.sort()),c=0>d.indexOf(":")&&"on"+d,t=t[x.expando]?t:new x.Event(d,"object"==typeof t&&t),t.isTrigger=i?2:3,t.namespace=g.join("."),t.namespace_re=t.namespace?RegExp("(^|\\.)"+g.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,t.result=undefined,t.target||(t.target=r),n=null==n?[t]:x.makeArray(n,[t]),p=x.event.special[d]||{},i||!p.trigger||p.trigger.apply(r,n)!==!1)){if(!i&&!p.noBubble&&!x.isWindow(r)){for(l=p.delegateType||d,_.test(l+d)||(a=a.parentNode);a;a=a.parentNode)h.push(a),u=a;u===(r.ownerDocument||o)&&h.push(u.defaultView||u.parentWindow||e)}s=0;while((a=h[s++])&&!t.isPropagationStopped())t.type=s>1?l:p.bindType||d,f=(H.get(a,"events")||{})[t.type]&&H.get(a,"handle"),f&&f.apply(a,n),f=c&&a[c],f&&x.acceptData(a)&&f.apply&&f.apply(a,n)===!1&&t.preventDefault();return t.type=d,i||t.isDefaultPrevented()||p._default&&p._default.apply(h.pop(),n)!==!1||!x.acceptData(r)||c&&x.isFunction(r[d])&&!x.isWindow(r)&&(u=r[c],u&&(r[c]=null),x.event.triggered=d,r[d](),x.event.triggered=undefined,u&&(r[c]=u)),t.result}},dispatch:function(e){e=x.event.fix(e);var t,n,r,i,o,s=[],a=d.call(arguments),u=(H.get(this,"events")||{})[e.type]||[],l=x.event.special[e.type]||{};if(a[0]=e,e.delegateTarget=this,!l.preDispatch||l.preDispatch.call(this,e)!==!1){s=x.event.handlers.call(this,e,u),t=0;while((i=s[t++])&&!e.isPropagationStopped()){e.currentTarget=i.elem,n=0;while((o=i.handlers[n++])&&!e.isImmediatePropagationStopped())(!e.namespace_re||e.namespace_re.test(o.namespace))&&(e.handleObj=o,e.data=o.data,r=((x.event.special[o.origType]||{}).handle||o.handler).apply(i.elem,a),r!==undefined&&(e.result=r)===!1&&(e.preventDefault(),e.stopPropagation()))}return l.postDispatch&&l.postDispatch.call(this,e),e.result}},handlers:function(e,t){var n,r,i,o,s=[],a=t.delegateCount,u=e.target;if(a&&u.nodeType&&(!e.button||"click"!==e.type))for(;u!==this;u=u.parentNode||this)if(u.disabled!==!0||"click"!==e.type){for(r=[],n=0;a>n;n++)o=t[n],i=o.selector+" ",r[i]===undefined&&(r[i]=o.needsContext?x(i,this).index(u)>=0:x.find(i,this,null,[u]).length),r[i]&&r.push(o);r.length&&s.push({elem:u,handlers:r})}return t.length>a&&s.push({elem:this,handlers:t.slice(a)}),s},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(e,t){return null==e.which&&(e.which=null!=t.charCode?t.charCode:t.keyCode),e}},mouseHooks:{props:"button buttons clientX clientY offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(e,t){var n,r,i,s=t.button;return null==e.pageX&&null!=t.clientX&&(n=e.target.ownerDocument||o,r=n.documentElement,i=n.body,e.pageX=t.clientX+(r&&r.scrollLeft||i&&i.scrollLeft||0)-(r&&r.clientLeft||i&&i.clientLeft||0),e.pageY=t.clientY+(r&&r.scrollTop||i&&i.scrollTop||0)-(r&&r.clientTop||i&&i.clientTop||0)),e.which||s===undefined||(e.which=1&s?1:2&s?3:4&s?2:0),e}},fix:function(e){if(e[x.expando])return e;var t,n,r,i=e.type,s=e,a=this.fixHooks[i];a||(this.fixHooks[i]=a=z.test(i)?this.mouseHooks:I.test(i)?this.keyHooks:{}),r=a.props?this.props.concat(a.props):this.props,e=new x.Event(s),t=r.length;while(t--)n=r[t],e[n]=s[n];return e.target||(e.target=o),3===e.target.nodeType&&(e.target=e.target.parentNode),a.filter?a.filter(e,s):e},special:{load:{noBubble:!0},focus:{trigger:function(){return this!==V()&&this.focus?(this.focus(),!1):undefined},delegateType:"focusin"},blur:{trigger:function(){return this===V()&&this.blur?(this.blur(),!1):undefined},delegateType:"focusout"},click:{trigger:function(){return"checkbox"===this.type&&this.click&&x.nodeName(this,"input")?(this.click(),!1):undefined},_default:function(e){return x.nodeName(e.target,"a")}},beforeunload:{postDispatch:function(e){e.result!==undefined&&(e.originalEvent.returnValue=e.result)}}},simulate:function(e,t,n,r){var i=x.extend(new x.Event,n,{type:e,isSimulated:!0,originalEvent:{}});r?x.event.trigger(i,null,t):x.event.dispatch.call(t,i),i.isDefaultPrevented()&&n.preventDefault()}},x.removeEvent=function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n,!1)},x.Event=function(e,t){return this instanceof x.Event?(e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||e.getPreventDefault&&e.getPreventDefault()?U:Y):this.type=e,t&&x.extend(this,t),this.timeStamp=e&&e.timeStamp||x.now(),this[x.expando]=!0,undefined):new x.Event(e,t)},x.Event.prototype={isDefaultPrevented:Y,isPropagationStopped:Y,isImmediatePropagationStopped:Y,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=U,e&&e.preventDefault&&e.preventDefault()},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=U,e&&e.stopPropagation&&e.stopPropagation()},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=U,this.stopPropagation()}},x.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(e,t){x.event.special[e]={delegateType:t,bindType:t,handle:function(e){var n,r=this,i=e.relatedTarget,o=e.handleObj;return(!i||i!==r&&!x.contains(r,i))&&(e.type=o.origType,n=o.handler.apply(this,arguments),e.type=t),n}}}),x.support.focusinBubbles||x.each({focus:"focusin",blur:"focusout"},function(e,t){var n=0,r=function(e){x.event.simulate(t,e.target,x.event.fix(e),!0)};x.event.special[t]={setup:function(){0===n++&&o.addEventListener(e,r,!0)},teardown:function(){0===--n&&o.removeEventListener(e,r,!0)}}}),x.fn.extend({on:function(e,t,n,r,i){var o,s;if("object"==typeof e){"string"!=typeof t&&(n=n||t,t=undefined);for(s in e)this.on(s,t,n,e[s],i);return this}if(null==n&&null==r?(r=t,n=t=undefined):null==r&&("string"==typeof t?(r=n,n=undefined):(r=n,n=t,t=undefined)),r===!1)r=Y;else if(!r)return this;return 1===i&&(o=r,r=function(e){return x().off(e),o.apply(this,arguments)},r.guid=o.guid||(o.guid=x.guid++)),this.each(function(){x.event.add(this,e,r,n,t)})},one:function(e,t,n,r){return this.on(e,t,n,r,1)},off:function(e,t,n){var r,i;if(e&&e.preventDefault&&e.handleObj)return r=e.handleObj,x(e.delegateTarget).off(r.namespace?r.origType+"."+r.namespace:r.origType,r.selector,r.handler),this;if("object"==typeof e){for(i in e)this.off(i,t,e[i]);return this}return(t===!1||"function"==typeof t)&&(n=t,t=undefined),n===!1&&(n=Y),this.each(function(){x.event.remove(this,e,n,t)})},trigger:function(e,t){return this.each(function(){x.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];return n?x.event.trigger(e,t,n,!0):undefined}});var G=/^.[^:#\[\.,]*$/,J=/^(?:parents|prev(?:Until|All))/,Q=x.expr.match.needsContext,K={children:!0,contents:!0,next:!0,prev:!0};x.fn.extend({find:function(e){var t,n=[],r=this,i=r.length;if("string"!=typeof e)return this.pushStack(x(e).filter(function(){for(t=0;i>t;t++)if(x.contains(r[t],this))return!0}));for(t=0;i>t;t++)x.find(e,r[t],n);return n=this.pushStack(i>1?x.unique(n):n),n.selector=this.selector?this.selector+" "+e:e,n},has:function(e){var t=x(e,this),n=t.length;return this.filter(function(){var e=0;for(;n>e;e++)if(x.contains(this,t[e]))return!0})},not:function(e){return this.pushStack(et(this,e||[],!0))},filter:function(e){return this.pushStack(et(this,e||[],!1))},is:function(e){return!!et(this,"string"==typeof e&&Q.test(e)?x(e):e||[],!1).length},closest:function(e,t){var n,r=0,i=this.length,o=[],s=Q.test(e)||"string"!=typeof e?x(e,t||this.context):0;for(;i>r;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(11>n.nodeType&&(s?s.index(n)>-1:1===n.nodeType&&x.find.matchesSelector(n,e))){n=o.push(n);break}return this.pushStack(o.length>1?x.unique(o):o)},index:function(e){return e?"string"==typeof e?g.call(x(e),this[0]):g.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){var n="string"==typeof e?x(e,t):x.makeArray(e&&e.nodeType?[e]:e),r=x.merge(this.get(),n);return this.pushStack(x.unique(r))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}});function Z(e,t){while((e=e[t])&&1!==e.nodeType);return e}x.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return x.dir(e,"parentNode")},parentsUntil:function(e,t,n){return x.dir(e,"parentNode",n)},next:function(e){return Z(e,"nextSibling")},prev:function(e){return Z(e,"previousSibling")},nextAll:function(e){return x.dir(e,"nextSibling")},prevAll:function(e){return x.dir(e,"previousSibling")},nextUntil:function(e,t,n){return x.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return x.dir(e,"previousSibling",n)},siblings:function(e){return x.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return x.sibling(e.firstChild)},contents:function(e){return x.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:x.merge([],e.childNodes)}},function(e,t){x.fn[e]=function(n,r){var i=x.map(this,t,n);return"Until"!==e.slice(-5)&&(r=n),r&&"string"==typeof r&&(i=x.filter(r,i)),this.length>1&&(K[e]||x.unique(i),J.test(e)&&i.reverse()),this.pushStack(i)}}),x.extend({filter:function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?x.find.matchesSelector(r,e)?[r]:[]:x.find.matches(e,x.grep(t,function(e){return 1===e.nodeType}))},dir:function(e,t,n){var r=[],i=n!==undefined;while((e=e[t])&&9!==e.nodeType)if(1===e.nodeType){if(i&&x(e).is(n))break;r.push(e)}return r},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n}});function et(e,t,n){if(x.isFunction(t))return x.grep(e,function(e,r){return!!t.call(e,r,e)!==n});if(t.nodeType)return x.grep(e,function(e){return e===t!==n});if("string"==typeof t){if(G.test(t))return x.filter(t,e,n);t=x.filter(t,e)}return x.grep(e,function(e){return g.call(t,e)>=0!==n})}var tt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,nt=/<([\w:]+)/,rt=/<|&#?\w+;/,it=/<(?:script|style|link)/i,ot=/^(?:checkbox|radio)$/i,st=/checked\s*(?:[^=]|=\s*.checked.)/i,at=/^$|\/(?:java|ecma)script/i,ut=/^true\/(.*)/,lt=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,ct={option:[1,"<select multiple='multiple'>","</select>"],thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:[0,"",""]};ct.optgroup=ct.option,ct.tbody=ct.tfoot=ct.colgroup=ct.caption=ct.thead,ct.th=ct.td,x.fn.extend({text:function(e){return x.access(this,function(e){return e===undefined?x.text(this):this.empty().append((this[0]&&this[0].ownerDocument||o).createTextNode(e))},null,e,arguments.length)},append:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=ft(this,e);t.appendChild(e)}})},prepend:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=ft(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},remove:function(e,t){var n,r=e?x.filter(e,this):this,i=0;for(;null!=(n=r[i]);i++)t||1!==n.nodeType||x.cleanData(mt(n)),n.parentNode&&(t&&x.contains(n.ownerDocument,n)&&dt(mt(n,"script")),n.parentNode.removeChild(n));return this},empty:function(){var e,t=0;for(;null!=(e=this[t]);t++)1===e.nodeType&&(x.cleanData(mt(e,!1)),e.textContent="");return this},clone:function(e,t){return e=null==e?!1:e,t=null==t?e:t,this.map(function(){return x.clone(this,e,t)})},html:function(e){return x.access(this,function(e){var t=this[0]||{},n=0,r=this.length;if(e===undefined&&1===t.nodeType)return t.innerHTML;if("string"==typeof e&&!it.test(e)&&!ct[(nt.exec(e)||["",""])[1].toLowerCase()]){e=e.replace(tt,"<$1></$2>");try{for(;r>n;n++)t=this[n]||{},1===t.nodeType&&(x.cleanData(mt(t,!1)),t.innerHTML=e);t=0}catch(i){}}t&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var e=x.map(this,function(e){return[e.nextSibling,e.parentNode]}),t=0;return this.domManip(arguments,function(n){var r=e[t++],i=e[t++];i&&(r&&r.parentNode!==i&&(r=this.nextSibling),x(this).remove(),i.insertBefore(n,r))},!0),t?this:this.remove()},detach:function(e){return this.remove(e,!0)},domManip:function(e,t,n){e=p.apply([],e);var r,i,o,s,a,u,l=0,c=this.length,f=this,h=c-1,d=e[0],g=x.isFunction(d);if(g||!(1>=c||"string"!=typeof d||x.support.checkClone)&&st.test(d))return this.each(function(r){var i=f.eq(r);g&&(e[0]=d.call(this,r,i.html())),i.domManip(e,t,n)});if(c&&(r=x.buildFragment(e,this[0].ownerDocument,!1,!n&&this),i=r.firstChild,1===r.childNodes.length&&(r=i),i)){for(o=x.map(mt(r,"script"),pt),s=o.length;c>l;l++)a=r,l!==h&&(a=x.clone(a,!0,!0),s&&x.merge(o,mt(a,"script"))),t.call(this[l],a,l);if(s)for(u=o[o.length-1].ownerDocument,x.map(o,ht),l=0;s>l;l++)a=o[l],at.test(a.type||"")&&!H.access(a,"globalEval")&&x.contains(u,a)&&(a.src?x._evalUrl(a.src):x.globalEval(a.textContent.replace(lt,"")))}return this}}),x.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,t){x.fn[e]=function(e){var n,r=[],i=x(e),o=i.length-1,s=0;for(;o>=s;s++)n=s===o?this:this.clone(!0),x(i[s])[t](n),h.apply(r,n.get());return this.pushStack(r)}}),x.extend({clone:function(e,t,n){var r,i,o,s,a=e.cloneNode(!0),u=x.contains(e.ownerDocument,e);if(!(x.support.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||x.isXMLDoc(e)))for(s=mt(a),o=mt(e),r=0,i=o.length;i>r;r++)yt(o[r],s[r]);if(t)if(n)for(o=o||mt(e),s=s||mt(a),r=0,i=o.length;i>r;r++)gt(o[r],s[r]);else gt(e,a);return s=mt(a,"script"),s.length>0&&dt(s,!u&&mt(e,"script")),a},buildFragment:function(e,t,n,r){var i,o,s,a,u,l,c=0,f=e.length,p=t.createDocumentFragment(),h=[];for(;f>c;c++)if(i=e[c],i||0===i)if("object"===x.type(i))x.merge(h,i.nodeType?[i]:i);else if(rt.test(i)){o=o||p.appendChild(t.createElement("div")),s=(nt.exec(i)||["",""])[1].toLowerCase(),a=ct[s]||ct._default,o.innerHTML=a[1]+i.replace(tt,"<$1></$2>")+a[2],l=a[0];while(l--)o=o.firstChild;x.merge(h,o.childNodes),o=p.firstChild,o.textContent=""}else h.push(t.createTextNode(i));p.textContent="",c=0;while(i=h[c++])if((!r||-1===x.inArray(i,r))&&(u=x.contains(i.ownerDocument,i),o=mt(p.appendChild(i),"script"),u&&dt(o),n)){l=0;while(i=o[l++])at.test(i.type||"")&&n.push(i)}return p},cleanData:function(e){var t,n,r,i,o,s,a=x.event.special,u=0;for(;(n=e[u])!==undefined;u++){if(F.accepts(n)&&(o=n[H.expando],o&&(t=H.cache[o]))){if(r=Object.keys(t.events||{}),r.length)for(s=0;(i=r[s])!==undefined;s++)a[i]?x.event.remove(n,i):x.removeEvent(n,i,t.handle);H.cache[o]&&delete H.cache[o]}delete L.cache[n[L.expando]]}},_evalUrl:function(e){return x.ajax({url:e,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})}});function ft(e,t){return x.nodeName(e,"table")&&x.nodeName(1===t.nodeType?t:t.firstChild,"tr")?e.getElementsByTagName("tbody")[0]||e.appendChild(e.ownerDocument.createElement("tbody")):e}function pt(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function ht(e){var t=ut.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function dt(e,t){var n=e.length,r=0;for(;n>r;r++)H.set(e[r],"globalEval",!t||H.get(t[r],"globalEval"))}function gt(e,t){var n,r,i,o,s,a,u,l;if(1===t.nodeType){if(H.hasData(e)&&(o=H.access(e),s=H.set(t,o),l=o.events)){delete s.handle,s.events={};for(i in l)for(n=0,r=l[i].length;r>n;n++)x.event.add(t,i,l[i][n])}L.hasData(e)&&(a=L.access(e),u=x.extend({},a),L.set(t,u))}}function mt(e,t){var n=e.getElementsByTagName?e.getElementsByTagName(t||"*"):e.querySelectorAll?e.querySelectorAll(t||"*"):[];return t===undefined||t&&x.nodeName(e,t)?x.merge([e],n):n}function yt(e,t){var n=t.nodeName.toLowerCase();"input"===n&&ot.test(e.type)?t.checked=e.checked:("input"===n||"textarea"===n)&&(t.defaultValue=e.defaultValue)}x.fn.extend({wrapAll:function(e){var t;return x.isFunction(e)?this.each(function(t){x(this).wrapAll(e.call(this,t))}):(this[0]&&(t=x(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstElementChild)e=e.firstElementChild;return e}).append(this)),this)},wrapInner:function(e){return x.isFunction(e)?this.each(function(t){x(this).wrapInner(e.call(this,t))}):this.each(function(){var t=x(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=x.isFunction(e);return this.each(function(n){x(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){x.nodeName(this,"body")||x(this).replaceWith(this.childNodes)}).end()}});var vt,xt,bt=/^(none|table(?!-c[ea]).+)/,wt=/^margin/,Tt=RegExp("^("+b+")(.*)$","i"),Ct=RegExp("^("+b+")(?!px)[a-z%]+$","i"),kt=RegExp("^([+-])=("+b+")","i"),Nt={BODY:"block"},Et={position:"absolute",visibility:"hidden",display:"block"},St={letterSpacing:0,fontWeight:400},jt=["Top","Right","Bottom","Left"],Dt=["Webkit","O","Moz","ms"];function At(e,t){if(t in e)return t;var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=Dt.length;while(i--)if(t=Dt[i]+n,t in e)return t;return r}function Lt(e,t){return e=t||e,"none"===x.css(e,"display")||!x.contains(e.ownerDocument,e)}function Ht(t){return e.getComputedStyle(t,null)}function qt(e,t){var n,r,i,o=[],s=0,a=e.length;for(;a>s;s++)r=e[s],r.style&&(o[s]=H.get(r,"olddisplay"),n=r.style.display,t?(o[s]||"none"!==n||(r.style.display=""),""===r.style.display&&Lt(r)&&(o[s]=H.access(r,"olddisplay",Rt(r.nodeName)))):o[s]||(i=Lt(r),(n&&"none"!==n||!i)&&H.set(r,"olddisplay",i?n:x.css(r,"display"))));for(s=0;a>s;s++)r=e[s],r.style&&(t&&"none"!==r.style.display&&""!==r.style.display||(r.style.display=t?o[s]||"":"none"));return e}x.fn.extend({css:function(e,t){return x.access(this,function(e,t,n){var r,i,o={},s=0;if(x.isArray(t)){for(r=Ht(e),i=t.length;i>s;s++)o[t[s]]=x.css(e,t[s],!1,r);return o}return n!==undefined?x.style(e,t,n):x.css(e,t)},e,t,arguments.length>1)},show:function(){return qt(this,!0)},hide:function(){return qt(this)},toggle:function(e){var t="boolean"==typeof e;return this.each(function(){(t?e:Lt(this))?x(this).show():x(this).hide()})}}),x.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=vt(e,"opacity");return""===n?"1":n}}}},cssNumber:{columnCount:!0,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":"cssFloat"},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,s,a=x.camelCase(t),u=e.style;return t=x.cssProps[a]||(x.cssProps[a]=At(u,a)),s=x.cssHooks[t]||x.cssHooks[a],n===undefined?s&&"get"in s&&(i=s.get(e,!1,r))!==undefined?i:u[t]:(o=typeof n,"string"===o&&(i=kt.exec(n))&&(n=(i[1]+1)*i[2]+parseFloat(x.css(e,t)),o="number"),null==n||"number"===o&&isNaN(n)||("number"!==o||x.cssNumber[a]||(n+="px"),x.support.clearCloneStyle||""!==n||0!==t.indexOf("background")||(u[t]="inherit"),s&&"set"in s&&(n=s.set(e,n,r))===undefined||(u[t]=n)),undefined)}},css:function(e,t,n,r){var i,o,s,a=x.camelCase(t);return t=x.cssProps[a]||(x.cssProps[a]=At(e.style,a)),s=x.cssHooks[t]||x.cssHooks[a],s&&"get"in s&&(i=s.get(e,!0,n)),i===undefined&&(i=vt(e,t,r)),"normal"===i&&t in St&&(i=St[t]),""===n||n?(o=parseFloat(i),n===!0||x.isNumeric(o)?o||0:i):i}}),vt=function(e,t,n){var r,i,o,s=n||Ht(e),a=s?s.getPropertyValue(t)||s[t]:undefined,u=e.style;return s&&(""!==a||x.contains(e.ownerDocument,e)||(a=x.style(e,t)),Ct.test(a)&&wt.test(t)&&(r=u.width,i=u.minWidth,o=u.maxWidth,u.minWidth=u.maxWidth=u.width=a,a=s.width,u.width=r,u.minWidth=i,u.maxWidth=o)),a};function Ot(e,t,n){var r=Tt.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function Ft(e,t,n,r,i){var o=n===(r?"border":"content")?4:"width"===t?1:0,s=0;for(;4>o;o+=2)"margin"===n&&(s+=x.css(e,n+jt[o],!0,i)),r?("content"===n&&(s-=x.css(e,"padding"+jt[o],!0,i)),"margin"!==n&&(s-=x.css(e,"border"+jt[o]+"Width",!0,i))):(s+=x.css(e,"padding"+jt[o],!0,i),"padding"!==n&&(s+=x.css(e,"border"+jt[o]+"Width",!0,i)));return s}function Pt(e,t,n){var r=!0,i="width"===t?e.offsetWidth:e.offsetHeight,o=Ht(e),s=x.support.boxSizing&&"border-box"===x.css(e,"boxSizing",!1,o);if(0>=i||null==i){if(i=vt(e,t,o),(0>i||null==i)&&(i=e.style[t]),Ct.test(i))return i;r=s&&(x.support.boxSizingReliable||i===e.style[t]),i=parseFloat(i)||0}return i+Ft(e,t,n||(s?"border":"content"),r,o)+"px"}function Rt(e){var t=o,n=Nt[e];return n||(n=Mt(e,t),"none"!==n&&n||(xt=(xt||x("<iframe frameborder='0' width='0' height='0'/>").css("cssText","display:block !important")).appendTo(t.documentElement),t=(xt[0].contentWindow||xt[0].contentDocument).document,t.write("<!doctype html><html><body>"),t.close(),n=Mt(e,t),xt.detach()),Nt[e]=n),n}function Mt(e,t){var n=x(t.createElement(e)).appendTo(t.body),r=x.css(n[0],"display");return n.remove(),r}x.each(["height","width"],function(e,t){x.cssHooks[t]={get:function(e,n,r){return n?0===e.offsetWidth&&bt.test(x.css(e,"display"))?x.swap(e,Et,function(){return Pt(e,t,r)}):Pt(e,t,r):undefined},set:function(e,n,r){var i=r&&Ht(e);return Ot(e,n,r?Ft(e,t,r,x.support.boxSizing&&"border-box"===x.css(e,"boxSizing",!1,i),i):0)}}}),x(function(){x.support.reliableMarginRight||(x.cssHooks.marginRight={get:function(e,t){return t?x.swap(e,{display:"inline-block"},vt,[e,"marginRight"]):undefined}}),!x.support.pixelPosition&&x.fn.position&&x.each(["top","left"],function(e,t){x.cssHooks[t]={get:function(e,n){return n?(n=vt(e,t),Ct.test(n)?x(e).position()[t]+"px":n):undefined}}})}),x.expr&&x.expr.filters&&(x.expr.filters.hidden=function(e){return 0>=e.offsetWidth&&0>=e.offsetHeight},x.expr.filters.visible=function(e){return!x.expr.filters.hidden(e)}),x.each({margin:"",padding:"",border:"Width"},function(e,t){x.cssHooks[e+t]={expand:function(n){var r=0,i={},o="string"==typeof n?n.split(" "):[n];for(;4>r;r++)i[e+jt[r]+t]=o[r]||o[r-2]||o[0];return i}},wt.test(e)||(x.cssHooks[e+t].set=Ot)});var Wt=/%20/g,$t=/\[\]$/,Bt=/\r?\n/g,It=/^(?:submit|button|image|reset|file)$/i,zt=/^(?:input|select|textarea|keygen)/i;x.fn.extend({serialize:function(){return x.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=x.prop(this,"elements");return e?x.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!x(this).is(":disabled")&&zt.test(this.nodeName)&&!It.test(e)&&(this.checked||!ot.test(e))}).map(function(e,t){var n=x(this).val();return null==n?null:x.isArray(n)?x.map(n,function(e){return{name:t.name,value:e.replace(Bt,"\r\n")}}):{name:t.name,value:n.replace(Bt,"\r\n")}}).get()}}),x.param=function(e,t){var n,r=[],i=function(e,t){t=x.isFunction(t)?t():null==t?"":t,r[r.length]=encodeURIComponent(e)+"="+encodeURIComponent(t)};if(t===undefined&&(t=x.ajaxSettings&&x.ajaxSettings.traditional),x.isArray(e)||e.jquery&&!x.isPlainObject(e))x.each(e,function(){i(this.name,this.value)});else for(n in e)_t(n,e[n],t,i);return r.join("&").replace(Wt,"+")};function _t(e,t,n,r){var i;if(x.isArray(t))x.each(t,function(t,i){n||$t.test(e)?r(e,i):_t(e+"["+("object"==typeof i?t:"")+"]",i,n,r)});else if(n||"object"!==x.type(t))r(e,t);else for(i in t)_t(e+"["+i+"]",t[i],n,r)}x.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(e,t){x.fn[t]=function(e,n){return arguments.length>0?this.on(t,null,e,n):this.trigger(t)}}),x.fn.extend({hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)},bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)
6
+}});var Xt,Ut,Yt=x.now(),Vt=/\?/,Gt=/#.*$/,Jt=/([?&])_=[^&]*/,Qt=/^(.*?):[ \t]*([^\r\n]*)$/gm,Kt=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Zt=/^(?:GET|HEAD)$/,en=/^\/\//,tn=/^([\w.+-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,nn=x.fn.load,rn={},on={},sn="*/".concat("*");try{Ut=i.href}catch(an){Ut=o.createElement("a"),Ut.href="",Ut=Ut.href}Xt=tn.exec(Ut.toLowerCase())||[];function un(e){return function(t,n){"string"!=typeof t&&(n=t,t="*");var r,i=0,o=t.toLowerCase().match(w)||[];if(x.isFunction(n))while(r=o[i++])"+"===r[0]?(r=r.slice(1)||"*",(e[r]=e[r]||[]).unshift(n)):(e[r]=e[r]||[]).push(n)}}function ln(e,t,n,r){var i={},o=e===on;function s(a){var u;return i[a]=!0,x.each(e[a]||[],function(e,a){var l=a(t,n,r);return"string"!=typeof l||o||i[l]?o?!(u=l):undefined:(t.dataTypes.unshift(l),s(l),!1)}),u}return s(t.dataTypes[0])||!i["*"]&&s("*")}function cn(e,t){var n,r,i=x.ajaxSettings.flatOptions||{};for(n in t)t[n]!==undefined&&((i[n]?e:r||(r={}))[n]=t[n]);return r&&x.extend(!0,e,r),e}x.fn.load=function(e,t,n){if("string"!=typeof e&&nn)return nn.apply(this,arguments);var r,i,o,s=this,a=e.indexOf(" ");return a>=0&&(r=e.slice(a),e=e.slice(0,a)),x.isFunction(t)?(n=t,t=undefined):t&&"object"==typeof t&&(i="POST"),s.length>0&&x.ajax({url:e,type:i,dataType:"html",data:t}).done(function(e){o=arguments,s.html(r?x("<div>").append(x.parseHTML(e)).find(r):e)}).complete(n&&function(e,t){s.each(n,o||[e.responseText,t,e])}),this},x.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){x.fn[t]=function(e){return this.on(t,e)}}),x.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Ut,type:"GET",isLocal:Kt.test(Xt[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":sn,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":x.parseJSON,"text xml":x.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?cn(cn(e,x.ajaxSettings),t):cn(x.ajaxSettings,e)},ajaxPrefilter:un(rn),ajaxTransport:un(on),ajax:function(e,t){"object"==typeof e&&(t=e,e=undefined),t=t||{};var n,r,i,o,s,a,u,l,c=x.ajaxSetup({},t),f=c.context||c,p=c.context&&(f.nodeType||f.jquery)?x(f):x.event,h=x.Deferred(),d=x.Callbacks("once memory"),g=c.statusCode||{},m={},y={},v=0,b="canceled",T={readyState:0,getResponseHeader:function(e){var t;if(2===v){if(!o){o={};while(t=Qt.exec(i))o[t[1].toLowerCase()]=t[2]}t=o[e.toLowerCase()]}return null==t?null:t},getAllResponseHeaders:function(){return 2===v?i:null},setRequestHeader:function(e,t){var n=e.toLowerCase();return v||(e=y[n]=y[n]||e,m[e]=t),this},overrideMimeType:function(e){return v||(c.mimeType=e),this},statusCode:function(e){var t;if(e)if(2>v)for(t in e)g[t]=[g[t],e[t]];else T.always(e[T.status]);return this},abort:function(e){var t=e||b;return n&&n.abort(t),k(0,t),this}};if(h.promise(T).complete=d.add,T.success=T.done,T.error=T.fail,c.url=((e||c.url||Ut)+"").replace(Gt,"").replace(en,Xt[1]+"//"),c.type=t.method||t.type||c.method||c.type,c.dataTypes=x.trim(c.dataType||"*").toLowerCase().match(w)||[""],null==c.crossDomain&&(a=tn.exec(c.url.toLowerCase()),c.crossDomain=!(!a||a[1]===Xt[1]&&a[2]===Xt[2]&&(a[3]||("http:"===a[1]?"80":"443"))===(Xt[3]||("http:"===Xt[1]?"80":"443")))),c.data&&c.processData&&"string"!=typeof c.data&&(c.data=x.param(c.data,c.traditional)),ln(rn,c,t,T),2===v)return T;u=c.global,u&&0===x.active++&&x.event.trigger("ajaxStart"),c.type=c.type.toUpperCase(),c.hasContent=!Zt.test(c.type),r=c.url,c.hasContent||(c.data&&(r=c.url+=(Vt.test(r)?"&":"?")+c.data,delete c.data),c.cache===!1&&(c.url=Jt.test(r)?r.replace(Jt,"$1_="+Yt++):r+(Vt.test(r)?"&":"?")+"_="+Yt++)),c.ifModified&&(x.lastModified[r]&&T.setRequestHeader("If-Modified-Since",x.lastModified[r]),x.etag[r]&&T.setRequestHeader("If-None-Match",x.etag[r])),(c.data&&c.hasContent&&c.contentType!==!1||t.contentType)&&T.setRequestHeader("Content-Type",c.contentType),T.setRequestHeader("Accept",c.dataTypes[0]&&c.accepts[c.dataTypes[0]]?c.accepts[c.dataTypes[0]]+("*"!==c.dataTypes[0]?", "+sn+"; q=0.01":""):c.accepts["*"]);for(l in c.headers)T.setRequestHeader(l,c.headers[l]);if(c.beforeSend&&(c.beforeSend.call(f,T,c)===!1||2===v))return T.abort();b="abort";for(l in{success:1,error:1,complete:1})T[l](c[l]);if(n=ln(on,c,t,T)){T.readyState=1,u&&p.trigger("ajaxSend",[T,c]),c.async&&c.timeout>0&&(s=setTimeout(function(){T.abort("timeout")},c.timeout));try{v=1,n.send(m,k)}catch(C){if(!(2>v))throw C;k(-1,C)}}else k(-1,"No Transport");function k(e,t,o,a){var l,m,y,b,w,C=t;2!==v&&(v=2,s&&clearTimeout(s),n=undefined,i=a||"",T.readyState=e>0?4:0,l=e>=200&&300>e||304===e,o&&(b=fn(c,T,o)),b=pn(c,b,T,l),l?(c.ifModified&&(w=T.getResponseHeader("Last-Modified"),w&&(x.lastModified[r]=w),w=T.getResponseHeader("etag"),w&&(x.etag[r]=w)),204===e||"HEAD"===c.type?C="nocontent":304===e?C="notmodified":(C=b.state,m=b.data,y=b.error,l=!y)):(y=C,(e||!C)&&(C="error",0>e&&(e=0))),T.status=e,T.statusText=(t||C)+"",l?h.resolveWith(f,[m,C,T]):h.rejectWith(f,[T,C,y]),T.statusCode(g),g=undefined,u&&p.trigger(l?"ajaxSuccess":"ajaxError",[T,c,l?m:y]),d.fireWith(f,[T,C]),u&&(p.trigger("ajaxComplete",[T,c]),--x.active||x.event.trigger("ajaxStop")))}return T},getJSON:function(e,t,n){return x.get(e,t,n,"json")},getScript:function(e,t){return x.get(e,undefined,t,"script")}}),x.each(["get","post"],function(e,t){x[t]=function(e,n,r,i){return x.isFunction(n)&&(i=i||r,r=n,n=undefined),x.ajax({url:e,type:t,dataType:i,data:n,success:r})}});function fn(e,t,n){var r,i,o,s,a=e.contents,u=e.dataTypes;while("*"===u[0])u.shift(),r===undefined&&(r=e.mimeType||t.getResponseHeader("Content-Type"));if(r)for(i in a)if(a[i]&&a[i].test(r)){u.unshift(i);break}if(u[0]in n)o=u[0];else{for(i in n){if(!u[0]||e.converters[i+" "+u[0]]){o=i;break}s||(s=i)}o=o||s}return o?(o!==u[0]&&u.unshift(o),n[o]):undefined}function pn(e,t,n,r){var i,o,s,a,u,l={},c=e.dataTypes.slice();if(c[1])for(s in e.converters)l[s.toLowerCase()]=e.converters[s];o=c.shift();while(o)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!u&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u=o,o=c.shift())if("*"===o)o=u;else if("*"!==u&&u!==o){if(s=l[u+" "+o]||l["* "+o],!s)for(i in l)if(a=i.split(" "),a[1]===o&&(s=l[u+" "+a[0]]||l["* "+a[0]])){s===!0?s=l[i]:l[i]!==!0&&(o=a[0],c.unshift(a[1]));break}if(s!==!0)if(s&&e["throws"])t=s(t);else try{t=s(t)}catch(f){return{state:"parsererror",error:s?f:"No conversion from "+u+" to "+o}}}return{state:"success",data:t}}x.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(e){return x.globalEval(e),e}}}),x.ajaxPrefilter("script",function(e){e.cache===undefined&&(e.cache=!1),e.crossDomain&&(e.type="GET")}),x.ajaxTransport("script",function(e){if(e.crossDomain){var t,n;return{send:function(r,i){t=x("<script>").prop({async:!0,charset:e.scriptCharset,src:e.url}).on("load error",n=function(e){t.remove(),n=null,e&&i("error"===e.type?404:200,e.type)}),o.head.appendChild(t[0])},abort:function(){n&&n()}}}});var hn=[],dn=/(=)\?(?=&|$)|\?\?/;x.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=hn.pop()||x.expando+"_"+Yt++;return this[e]=!0,e}}),x.ajaxPrefilter("json jsonp",function(t,n,r){var i,o,s,a=t.jsonp!==!1&&(dn.test(t.url)?"url":"string"==typeof t.data&&!(t.contentType||"").indexOf("application/x-www-form-urlencoded")&&dn.test(t.data)&&"data");return a||"jsonp"===t.dataTypes[0]?(i=t.jsonpCallback=x.isFunction(t.jsonpCallback)?t.jsonpCallback():t.jsonpCallback,a?t[a]=t[a].replace(dn,"$1"+i):t.jsonp!==!1&&(t.url+=(Vt.test(t.url)?"&":"?")+t.jsonp+"="+i),t.converters["script json"]=function(){return s||x.error(i+" was not called"),s[0]},t.dataTypes[0]="json",o=e[i],e[i]=function(){s=arguments},r.always(function(){e[i]=o,t[i]&&(t.jsonpCallback=n.jsonpCallback,hn.push(i)),s&&x.isFunction(o)&&o(s[0]),s=o=undefined}),"script"):undefined}),x.ajaxSettings.xhr=function(){try{return new XMLHttpRequest}catch(e){}};var gn=x.ajaxSettings.xhr(),mn={0:200,1223:204},yn=0,vn={};e.ActiveXObject&&x(e).on("unload",function(){for(var e in vn)vn[e]();vn=undefined}),x.support.cors=!!gn&&"withCredentials"in gn,x.support.ajax=gn=!!gn,x.ajaxTransport(function(e){var t;return x.support.cors||gn&&!e.crossDomain?{send:function(n,r){var i,o,s=e.xhr();if(s.open(e.type,e.url,e.async,e.username,e.password),e.xhrFields)for(i in e.xhrFields)s[i]=e.xhrFields[i];e.mimeType&&s.overrideMimeType&&s.overrideMimeType(e.mimeType),e.crossDomain||n["X-Requested-With"]||(n["X-Requested-With"]="XMLHttpRequest");for(i in n)s.setRequestHeader(i,n[i]);t=function(e){return function(){t&&(delete vn[o],t=s.onload=s.onerror=null,"abort"===e?s.abort():"error"===e?r(s.status||404,s.statusText):r(mn[s.status]||s.status,s.statusText,"string"==typeof s.responseText?{text:s.responseText}:undefined,s.getAllResponseHeaders()))}},s.onload=t(),s.onerror=t("error"),t=vn[o=yn++]=t("abort"),s.send(e.hasContent&&e.data||null)},abort:function(){t&&t()}}:undefined});var xn,bn,wn=/^(?:toggle|show|hide)$/,Tn=RegExp("^(?:([+-])=|)("+b+")([a-z%]*)$","i"),Cn=/queueHooks$/,kn=[An],Nn={"*":[function(e,t){var n=this.createTween(e,t),r=n.cur(),i=Tn.exec(t),o=i&&i[3]||(x.cssNumber[e]?"":"px"),s=(x.cssNumber[e]||"px"!==o&&+r)&&Tn.exec(x.css(n.elem,e)),a=1,u=20;if(s&&s[3]!==o){o=o||s[3],i=i||[],s=+r||1;do a=a||".5",s/=a,x.style(n.elem,e,s+o);while(a!==(a=n.cur()/r)&&1!==a&&--u)}return i&&(n.unit=o,n.start=+s||+r||0,n.end=i[1]?s+(i[1]+1)*i[2]:+i[2]),n}]};function En(){return setTimeout(function(){xn=undefined}),xn=x.now()}function Sn(e,t,n){var r,i=(Nn[t]||[]).concat(Nn["*"]),o=0,s=i.length;for(;s>o;o++)if(r=i[o].call(n,t,e))return r}function jn(e,t,n){var r,i,o=0,s=kn.length,a=x.Deferred().always(function(){delete u.elem}),u=function(){if(i)return!1;var t=xn||En(),n=Math.max(0,l.startTime+l.duration-t),r=n/l.duration||0,o=1-r,s=0,u=l.tweens.length;for(;u>s;s++)l.tweens[s].run(o);return a.notifyWith(e,[l,o,n]),1>o&&u?n:(a.resolveWith(e,[l]),!1)},l=a.promise({elem:e,props:x.extend({},t),opts:x.extend(!0,{specialEasing:{}},n),originalProperties:t,originalOptions:n,startTime:xn||En(),duration:n.duration,tweens:[],createTween:function(t,n){var r=x.Tween(e,l.opts,t,n,l.opts.specialEasing[t]||l.opts.easing);return l.tweens.push(r),r},stop:function(t){var n=0,r=t?l.tweens.length:0;if(i)return this;for(i=!0;r>n;n++)l.tweens[n].run(1);return t?a.resolveWith(e,[l,t]):a.rejectWith(e,[l,t]),this}}),c=l.props;for(Dn(c,l.opts.specialEasing);s>o;o++)if(r=kn[o].call(l,e,c,l.opts))return r;return x.map(c,Sn,l),x.isFunction(l.opts.start)&&l.opts.start.call(e,l),x.fx.timer(x.extend(u,{elem:e,anim:l,queue:l.opts.queue})),l.progress(l.opts.progress).done(l.opts.done,l.opts.complete).fail(l.opts.fail).always(l.opts.always)}function Dn(e,t){var n,r,i,o,s;for(n in e)if(r=x.camelCase(n),i=t[r],o=e[n],x.isArray(o)&&(i=o[1],o=e[n]=o[0]),n!==r&&(e[r]=o,delete e[n]),s=x.cssHooks[r],s&&"expand"in s){o=s.expand(o),delete e[r];for(n in o)n in e||(e[n]=o[n],t[n]=i)}else t[r]=i}x.Animation=x.extend(jn,{tweener:function(e,t){x.isFunction(e)?(t=e,e=["*"]):e=e.split(" ");var n,r=0,i=e.length;for(;i>r;r++)n=e[r],Nn[n]=Nn[n]||[],Nn[n].unshift(t)},prefilter:function(e,t){t?kn.unshift(e):kn.push(e)}});function An(e,t,n){var r,i,o,s,a,u,l=this,c={},f=e.style,p=e.nodeType&&Lt(e),h=H.get(e,"fxshow");n.queue||(a=x._queueHooks(e,"fx"),null==a.unqueued&&(a.unqueued=0,u=a.empty.fire,a.empty.fire=function(){a.unqueued||u()}),a.unqueued++,l.always(function(){l.always(function(){a.unqueued--,x.queue(e,"fx").length||a.empty.fire()})})),1===e.nodeType&&("height"in t||"width"in t)&&(n.overflow=[f.overflow,f.overflowX,f.overflowY],"inline"===x.css(e,"display")&&"none"===x.css(e,"float")&&(f.display="inline-block")),n.overflow&&(f.overflow="hidden",l.always(function(){f.overflow=n.overflow[0],f.overflowX=n.overflow[1],f.overflowY=n.overflow[2]}));for(r in t)if(i=t[r],wn.exec(i)){if(delete t[r],o=o||"toggle"===i,i===(p?"hide":"show")){if("show"!==i||!h||h[r]===undefined)continue;p=!0}c[r]=h&&h[r]||x.style(e,r)}if(!x.isEmptyObject(c)){h?"hidden"in h&&(p=h.hidden):h=H.access(e,"fxshow",{}),o&&(h.hidden=!p),p?x(e).show():l.done(function(){x(e).hide()}),l.done(function(){var t;H.remove(e,"fxshow");for(t in c)x.style(e,t,c[t])});for(r in c)s=Sn(p?h[r]:0,r,l),r in h||(h[r]=s.start,p&&(s.end=s.start,s.start="width"===r||"height"===r?1:0))}}function Ln(e,t,n,r,i){return new Ln.prototype.init(e,t,n,r,i)}x.Tween=Ln,Ln.prototype={constructor:Ln,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||"swing",this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(x.cssNumber[n]?"":"px")},cur:function(){var e=Ln.propHooks[this.prop];return e&&e.get?e.get(this):Ln.propHooks._default.get(this)},run:function(e){var t,n=Ln.propHooks[this.prop];return this.pos=t=this.options.duration?x.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):Ln.propHooks._default.set(this),this}},Ln.prototype.init.prototype=Ln.prototype,Ln.propHooks={_default:{get:function(e){var t;return null==e.elem[e.prop]||e.elem.style&&null!=e.elem.style[e.prop]?(t=x.css(e.elem,e.prop,""),t&&"auto"!==t?t:0):e.elem[e.prop]},set:function(e){x.fx.step[e.prop]?x.fx.step[e.prop](e):e.elem.style&&(null!=e.elem.style[x.cssProps[e.prop]]||x.cssHooks[e.prop])?x.style(e.elem,e.prop,e.now+e.unit):e.elem[e.prop]=e.now}}},Ln.propHooks.scrollTop=Ln.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},x.each(["toggle","show","hide"],function(e,t){var n=x.fn[t];x.fn[t]=function(e,r,i){return null==e||"boolean"==typeof e?n.apply(this,arguments):this.animate(Hn(t,!0),e,r,i)}}),x.fn.extend({fadeTo:function(e,t,n,r){return this.filter(Lt).css("opacity",0).show().end().animate({opacity:t},e,n,r)},animate:function(e,t,n,r){var i=x.isEmptyObject(e),o=x.speed(t,n,r),s=function(){var t=jn(this,x.extend({},e),o);s.finish=function(){t.stop(!0)},(i||H.get(this,"finish"))&&t.stop(!0)};return s.finish=s,i||o.queue===!1?this.each(s):this.queue(o.queue,s)},stop:function(e,t,n){var r=function(e){var t=e.stop;delete e.stop,t(n)};return"string"!=typeof e&&(n=t,t=e,e=undefined),t&&e!==!1&&this.queue(e||"fx",[]),this.each(function(){var t=!0,i=null!=e&&e+"queueHooks",o=x.timers,s=H.get(this);if(i)s[i]&&s[i].stop&&r(s[i]);else for(i in s)s[i]&&s[i].stop&&Cn.test(i)&&r(s[i]);for(i=o.length;i--;)o[i].elem!==this||null!=e&&o[i].queue!==e||(o[i].anim.stop(n),t=!1,o.splice(i,1));(t||!n)&&x.dequeue(this,e)})},finish:function(e){return e!==!1&&(e=e||"fx"),this.each(function(){var t,n=H.get(this),r=n[e+"queue"],i=n[e+"queueHooks"],o=x.timers,s=r?r.length:0;for(n.finish=!0,x.queue(this,e,[]),i&&i.cur&&i.cur.finish&&i.cur.finish.call(this),t=o.length;t--;)o[t].elem===this&&o[t].queue===e&&(o[t].anim.stop(!0),o.splice(t,1));for(t=0;s>t;t++)r[t]&&r[t].finish&&r[t].finish.call(this);delete n.finish})}});function Hn(e,t){var n,r={height:e},i=0;for(t=t?1:0;4>i;i+=2-t)n=jt[i],r["margin"+n]=r["padding"+n]=e;return t&&(r.opacity=r.width=e),r}x.each({slideDown:Hn("show"),slideUp:Hn("hide"),slideToggle:Hn("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(e,t){x.fn[e]=function(e,n,r){return this.animate(t,e,n,r)}}),x.speed=function(e,t,n){var r=e&&"object"==typeof e?x.extend({},e):{complete:n||!n&&t||x.isFunction(e)&&e,duration:e,easing:n&&t||t&&!x.isFunction(t)&&t};return r.duration=x.fx.off?0:"number"==typeof r.duration?r.duration:r.duration in x.fx.speeds?x.fx.speeds[r.duration]:x.fx.speeds._default,(null==r.queue||r.queue===!0)&&(r.queue="fx"),r.old=r.complete,r.complete=function(){x.isFunction(r.old)&&r.old.call(this),r.queue&&x.dequeue(this,r.queue)},r},x.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2}},x.timers=[],x.fx=Ln.prototype.init,x.fx.tick=function(){var e,t=x.timers,n=0;for(xn=x.now();t.length>n;n++)e=t[n],e()||t[n]!==e||t.splice(n--,1);t.length||x.fx.stop(),xn=undefined},x.fx.timer=function(e){e()&&x.timers.push(e)&&x.fx.start()},x.fx.interval=13,x.fx.start=function(){bn||(bn=setInterval(x.fx.tick,x.fx.interval))},x.fx.stop=function(){clearInterval(bn),bn=null},x.fx.speeds={slow:600,fast:200,_default:400},x.fx.step={},x.expr&&x.expr.filters&&(x.expr.filters.animated=function(e){return x.grep(x.timers,function(t){return e===t.elem}).length}),x.fn.offset=function(e){if(arguments.length)return e===undefined?this:this.each(function(t){x.offset.setOffset(this,e,t)});var t,n,i=this[0],o={top:0,left:0},s=i&&i.ownerDocument;if(s)return t=s.documentElement,x.contains(t,i)?(typeof i.getBoundingClientRect!==r&&(o=i.getBoundingClientRect()),n=qn(s),{top:o.top+n.pageYOffset-t.clientTop,left:o.left+n.pageXOffset-t.clientLeft}):o},x.offset={setOffset:function(e,t,n){var r,i,o,s,a,u,l,c=x.css(e,"position"),f=x(e),p={};"static"===c&&(e.style.position="relative"),a=f.offset(),o=x.css(e,"top"),u=x.css(e,"left"),l=("absolute"===c||"fixed"===c)&&(o+u).indexOf("auto")>-1,l?(r=f.position(),s=r.top,i=r.left):(s=parseFloat(o)||0,i=parseFloat(u)||0),x.isFunction(t)&&(t=t.call(e,n,a)),null!=t.top&&(p.top=t.top-a.top+s),null!=t.left&&(p.left=t.left-a.left+i),"using"in t?t.using.call(e,p):f.css(p)}},x.fn.extend({position:function(){if(this[0]){var e,t,n=this[0],r={top:0,left:0};return"fixed"===x.css(n,"position")?t=n.getBoundingClientRect():(e=this.offsetParent(),t=this.offset(),x.nodeName(e[0],"html")||(r=e.offset()),r.top+=x.css(e[0],"borderTopWidth",!0),r.left+=x.css(e[0],"borderLeftWidth",!0)),{top:t.top-r.top-x.css(n,"marginTop",!0),left:t.left-r.left-x.css(n,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent||s;while(e&&!x.nodeName(e,"html")&&"static"===x.css(e,"position"))e=e.offsetParent;return e||s})}}),x.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,n){var r="pageYOffset"===n;x.fn[t]=function(i){return x.access(this,function(t,i,o){var s=qn(t);return o===undefined?s?s[n]:t[i]:(s?s.scrollTo(r?e.pageXOffset:o,r?o:e.pageYOffset):t[i]=o,undefined)},t,i,arguments.length,null)}});function qn(e){return x.isWindow(e)?e:9===e.nodeType&&e.defaultView}x.each({Height:"height",Width:"width"},function(e,t){x.each({padding:"inner"+e,content:t,"":"outer"+e},function(n,r){x.fn[r]=function(r,i){var o=arguments.length&&(n||"boolean"!=typeof r),s=n||(r===!0||i===!0?"margin":"border");return x.access(this,function(t,n,r){var i;return x.isWindow(t)?t.document.documentElement["client"+e]:9===t.nodeType?(i=t.documentElement,Math.max(t.body["scroll"+e],i["scroll"+e],t.body["offset"+e],i["offset"+e],i["client"+e])):r===undefined?x.css(t,n,s):x.style(t,n,r,s)},t,o?r:undefined,o,null)}})}),x.fn.size=function(){return this.length},x.fn.andSelf=x.fn.addBack,"object"==typeof module&&module&&"object"==typeof module.exports?module.exports=x:"function"==typeof define&&define.amd&&define("jquery",[],function(){return x}),"object"==typeof e&&"object"==typeof e.document&&(e.jQuery=e.$=x)})(window);
+1 -1
mojo/lib/Mojolicious/public/mojo/prettify/lang-apollo.js
... ...
@@ -1,2 +1,2 @@
1
-PR.registerLangHandler(PR.createSimpleLexer([["com",/^#[^\n\r]*/,null,"#"],["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r �\xa0"],["str",/^"(?:[^"\\]|\\[\S\s])*(?:"|$)/,null,'"']],[["kwd",/^(?:ADS|AD|AUG|BZF|BZMF|CAE|CAF|CA|CCS|COM|CS|DAS|DCA|DCOM|DCS|DDOUBL|DIM|DOUBLE|DTCB|DTCF|DV|DXCH|EDRUPT|EXTEND|INCR|INDEX|NDX|INHINT|LXCH|MASK|MSK|MP|MSU|NOOP|OVSK|QXCH|RAND|READ|RELINT|RESUME|RETURN|ROR|RXOR|SQUARE|SU|TCR|TCAA|OVSK|TCF|TC|TS|WAND|WOR|WRITE|XCH|XLQ|XXALQ|ZL|ZQ|ADD|ADZ|SUB|SUZ|MPY|MPR|MPZ|DVP|COM|ABS|CLA|CLZ|LDQ|STO|STQ|ALS|LLS|LRS|TRA|TSQ|TMI|TOV|AXT|TIX|DLY|INP|OUT)\s/,
1
+PR.registerLangHandler(PR.createSimpleLexer([["com",/^#[^\n\r]*/,null,"#"],["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r \u00a0"],["str",/^"(?:[^"\\]|\\[\S\s])*(?:"|$)/,null,'"']],[["kwd",/^(?:ADS|AD|AUG|BZF|BZMF|CAE|CAF|CA|CCS|COM|CS|DAS|DCA|DCOM|DCS|DDOUBL|DIM|DOUBLE|DTCB|DTCF|DV|DXCH|EDRUPT|EXTEND|INCR|INDEX|NDX|INHINT|LXCH|MASK|MSK|MP|MSU|NOOP|OVSK|QXCH|RAND|READ|RELINT|RESUME|RETURN|ROR|RXOR|SQUARE|SU|TCR|TCAA|OVSK|TCF|TC|TS|WAND|WOR|WRITE|XCH|XLQ|XXALQ|ZL|ZQ|ADD|ADZ|SUB|SUZ|MPY|MPR|MPZ|DVP|COM|ABS|CLA|CLZ|LDQ|STO|STQ|ALS|LLS|LRS|TRA|TSQ|TMI|TOV|AXT|TIX|DLY|INP|OUT)\s/,
2 2
 null],["typ",/^(?:-?GENADR|=MINUS|2BCADR|VN|BOF|MM|-?2CADR|-?[1-6]DNADR|ADRES|BBCON|[ES]?BANK=?|BLOCK|BNKSUM|E?CADR|COUNT\*?|2?DEC\*?|-?DNCHAN|-?DNPTR|EQUALS|ERASE|MEMORY|2?OCT|REMADR|SETLOC|SUBRO|ORG|BSS|BES|SYN|EQU|DEFINE|END)\s/,null],["lit",/^'(?:-*(?:\w|\\[!-~])(?:[\w-]*|\\[!-~])[!=?]?)?/],["pln",/^-*(?:[!-z]|\\[!-~])(?:[\w-]*|\\[!-~])[!=?]?/],["pun",/^[^\w\t\n\r "'-);\\\xa0]+/]]),["apollo","agc","aea"]);
+3
mojo/lib/Mojolicious/public/mojo/prettify/lang-basic.js
... ...
@@ -0,0 +1,3 @@
1
+var a=null;
2
+PR.registerLangHandler(PR.createSimpleLexer([["str",/^"(?:[^\n\r"\\]|\\.)*(?:"|$)/,a,'"'],["pln",/^\s+/,a," \r\n\t\u00a0"]],[["com",/^REM[^\n\r]*/,a],["kwd",/^\b(?:AND|CLOSE|CLR|CMD|CONT|DATA|DEF ?FN|DIM|END|FOR|GET|GOSUB|GOTO|IF|INPUT|LET|LIST|LOAD|NEW|NEXT|NOT|ON|OPEN|OR|POKE|PRINT|READ|RESTORE|RETURN|RUN|SAVE|STEP|STOP|SYS|THEN|TO|VERIFY|WAIT)\b/,a],["pln",/^[a-z][^\W_]?(?:\$|%)?/i,a],["lit",/^(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?/i,a,"0123456789"],["pun",
3
+/^.[^\s\w"$%.]*/,a]]),["basic","cbm"]);
+1 -1
mojo/lib/Mojolicious/public/mojo/prettify/lang-clj.js
... ...
@@ -14,5 +14,5 @@
14 14
  limitations under the License.
15 15
 */
16 16
 var a=null;
17
-PR.registerLangHandler(PR.createSimpleLexer([["opn",/^[([{]+/,a,"([{"],["clo",/^[)\]}]+/,a,")]}"],["com",/^;[^\n\r]*/,a,";"],["pln",/^[\t\n\r \xa0]+/,a,"\t\n\r \xa0"],["str",/^"(?:[^"\\]|\\[\S\s])*(?:"|$)/,a,'"']],[["kwd",/^(?:def|if|do|let|quote|var|fn|loop|recur|throw|try|monitor-enter|monitor-exit|defmacro|defn|defn-|macroexpand|macroexpand-1|for|doseq|dosync|dotimes|and|or|when|not|assert|doto|proxy|defstruct|first|rest|cons|defprotocol|deftype|defrecord|reify|defmulti|defmethod|meta|with-meta|ns|in-ns|create-ns|import|intern|refer|alias|namespace|resolve|ref|deref|refset|new|set!|memfn|to-array|into-array|aset|gen-class|reduce|map|filter|find|nil?|empty?|hash-map|hash-set|vec|vector|seq|flatten|reverse|assoc|dissoc|list|list?|disj|get|union|difference|intersection|extend|extend-type|extend-protocol|prn)\b/,a],
17
+PR.registerLangHandler(PR.createSimpleLexer([["opn",/^[([{]+/,a,"([{"],["clo",/^[)\]}]+/,a,")]}"],["com",/^;[^\n\r]*/,a,";"],["pln",/^[\t\n\r \xa0]+/,a,"\t\n\r \u00a0"],["str",/^"(?:[^"\\]|\\[\S\s])*(?:"|$)/,a,'"']],[["kwd",/^(?:def|if|do|let|quote|var|fn|loop|recur|throw|try|monitor-enter|monitor-exit|defmacro|defn|defn-|macroexpand|macroexpand-1|for|doseq|dosync|dotimes|and|or|when|not|assert|doto|proxy|defstruct|first|rest|cons|defprotocol|deftype|defrecord|reify|defmulti|defmethod|meta|with-meta|ns|in-ns|create-ns|import|intern|refer|alias|namespace|resolve|ref|deref|refset|new|set!|memfn|to-array|into-array|aset|gen-class|reduce|map|filter|find|nil?|empty?|hash-map|hash-set|vec|vector|seq|flatten|reverse|assoc|dissoc|list|list?|disj|get|union|difference|intersection|extend|extend-type|extend-protocol|prn)\b/,a],
18 18
 ["typ",/^:[\dA-Za-z-]+/]]),["clj"]);
+2 -2
mojo/lib/Mojolicious/public/mojo/prettify/lang-css.js
... ...
@@ -1,2 +1,2 @@
1
-PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\f\r ]+/,null," \t\r\n"]],[["str",/^"(?:[^\n\f\r"\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*"/,null],["str",/^'(?:[^\n\f\r'\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*'/,null],["lang-css-str",/^url\(([^"')]*)\)/i],["kwd",/^(?:url|rgb|!important|@import|@page|@media|@charset|inherit)(?=[^\w-]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*)\s*:/i],["com",/^\/\*[^*]*\*+(?:[^*/][^*]*\*+)*\//],["com",
2
-/^(?:<\!--|--\>)/],["lit",/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],["lit",/^#[\da-f]{3,6}/i],["pln",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i],["pun",/^[^\s\w"']+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[["kwd",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[["str",/^[^"')]+/]]),["css-str"]);
1
+PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\f\r ]+/,null," \t\r\n\u000c"]],[["str",/^"(?:[^\n\f\r"\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*"/,null],["str",/^'(?:[^\n\f\r'\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*'/,null],["lang-css-str",/^url\(([^"')]+)\)/i],["kwd",/^(?:url|rgb|!important|@import|@page|@media|@charset|inherit)(?=[^\w-]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*)\s*:/i],["com",/^\/\*[^*]*\*+(?:[^*/][^*]*\*+)*\//],
2
+["com",/^(?:<\!--|--\>)/],["lit",/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],["lit",/^#[\da-f]{3,6}\b/i],["pln",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i],["pun",/^[^\s\w"']+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[["kwd",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[["str",/^[^"')]+/]]),["css-str"]);
+3
mojo/lib/Mojolicious/public/mojo/prettify/lang-dart.js
... ...
@@ -0,0 +1,3 @@
1
+PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r \u00a0"]],[["com",/^#!.*/],["kwd",/^\b(?:import|library|part of|part|as|show|hide)\b/i],["com",/^\/\/.*/],["com",/^\/\*[^*]*\*+(?:[^*/][^*]*\*+)*\//],["kwd",/^\b(?:class|interface)\b/i],["kwd",/^\b(?:assert|break|case|catch|continue|default|do|else|finally|for|if|in|is|new|return|super|switch|this|throw|try|while)\b/i],["kwd",/^\b(?:abstract|const|extends|factory|final|get|implements|native|operator|set|static|typedef|var)\b/i],
2
+["typ",/^\b(?:bool|double|dynamic|int|num|object|string|void)\b/i],["kwd",/^\b(?:false|null|true)\b/i],["str",/^r?'''[\S\s]*?[^\\]'''/],["str",/^r?"""[\S\s]*?[^\\]"""/],["str",/^r?'('|[^\n\f\r]*?[^\\]')/],["str",/^r?"("|[^\n\f\r]*?[^\\]")/],["pln",/^[$_a-z]\w*/i],["pun",/^[!%&*+/:<-?^|~-]/],["lit",/^\b0x[\da-f]+/i],["lit",/^\b\d+(?:\.\d*)?(?:e[+-]?\d+)?/i],["lit",/^\b\.\d+(?:e[+-]?\d+)?/i],["pun",/^[(),.;[\]{}]/]]),
3
+["dart"]);
+2
mojo/lib/Mojolicious/public/mojo/prettify/lang-erlang.js
... ...
@@ -0,0 +1,2 @@
1
+PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t-\r ]+/,null,"\t\n\u000b\u000c\r "],["str",/^"(?:[^\n\f\r"\\]|\\[\S\s])*(?:"|$)/,null,'"'],["lit",/^[a-z]\w*/],["lit",/^'(?:[^\n\f\r'\\]|\\[^&])+'?/,null,"'"],["lit",/^\?[^\t\n ({]+/,null,"?"],["lit",/^(?:0o[0-7]+|0x[\da-f]+|\d+(?:\.\d+)?(?:e[+-]?\d+)?)/i,null,"0123456789"]],[["com",/^%[^\n]*/],["kwd",/^(?:module|attributes|do|let|in|letrec|apply|call|primop|case|of|end|when|fun|try|catch|receive|after|char|integer|float,atom,string,var)\b/],
2
+["kwd",/^-[_a-z]+/],["typ",/^[A-Z_]\w*/],["pun",/^[,.;]/]]),["erlang","erl"]);
+1 -1
mojo/lib/Mojolicious/public/mojo/prettify/lang-go.js
... ...
@@ -1 +1 @@
1
-PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r �\xa0"],["pln",/^(?:"(?:[^"\\]|\\[\S\s])*(?:"|$)|'(?:[^'\\]|\\[\S\s])+(?:'|$)|`[^`]*(?:`|$))/,null,"\"'"]],[["com",/^(?:\/\/[^\n\r]*|\/\*[\S\s]*?\*\/)/],["pln",/^(?:[^"'/`]|\/(?![*/]))+/]]),["go"]);
1
+PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r \u00a0"],["pln",/^(?:"(?:[^"\\]|\\[\S\s])*(?:"|$)|'(?:[^'\\]|\\[\S\s])+(?:'|$)|`[^`]*(?:`|$))/,null,"\"'"]],[["com",/^(?:\/\/[^\n\r]*|\/\*[\S\s]*?\*\/)/],["pln",/^(?:[^"'/`]|\/(?![*/]))+/]]),["go"]);
+1 -1
mojo/lib/Mojolicious/public/mojo/prettify/lang-hs.js
... ...
@@ -1,2 +1,2 @@
1
-PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t-\r ]+/,null,"\t\n\r "],["str",/^"(?:[^\n\f\r"\\]|\\[\S\s])*(?:"|$)/,null,'"'],["str",/^'(?:[^\n\f\r'\\]|\\[^&])'?/,null,"'"],["lit",/^(?:0o[0-7]+|0x[\da-f]+|\d+(?:\.\d+)?(?:e[+-]?\d+)?)/i,null,"0123456789"]],[["com",/^(?:--+[^\n\f\r]*|{-(?:[^-]|-+[^}-])*-})/],["kwd",/^(?:case|class|data|default|deriving|do|else|if|import|in|infix|infixl|infixr|instance|let|module|newtype|of|then|type|where|_)(?=[^\d'A-Za-z]|$)/,
1
+PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t-\r ]+/,null,"\t\n\u000b\u000c\r "],["str",/^"(?:[^\n\f\r"\\]|\\[\S\s])*(?:"|$)/,null,'"'],["str",/^'(?:[^\n\f\r'\\]|\\[^&])'?/,null,"'"],["lit",/^(?:0o[0-7]+|0x[\da-f]+|\d+(?:\.\d+)?(?:e[+-]?\d+)?)/i,null,"0123456789"]],[["com",/^(?:--+[^\n\f\r]*|{-(?:[^-]|-+[^}-])*-})/],["kwd",/^(?:case|class|data|default|deriving|do|else|if|import|in|infix|infixl|infixr|instance|let|module|newtype|of|then|type|where|_)(?=[^\d'A-Za-z]|$)/,
2 2
 null],["pln",/^(?:[A-Z][\w']*\.)*[A-Za-z][\w']*/],["pun",/^[^\d\t-\r "'A-Za-z]+/]]),["hs"]);
+2 -2
mojo/lib/Mojolicious/public/mojo/prettify/lang-lisp.js
... ...
@@ -1,3 +1,3 @@
1 1
 var a=null;
2
-PR.registerLangHandler(PR.createSimpleLexer([["opn",/^\(+/,a,"("],["clo",/^\)+/,a,")"],["com",/^;[^\n\r]*/,a,";"],["pln",/^[\t\n\r \xa0]+/,a,"\t\n\r \xa0"],["str",/^"(?:[^"\\]|\\[\S\s])*(?:"|$)/,a,'"']],[["kwd",/^(?:block|c[ad]+r|catch|con[ds]|def(?:ine|un)|do|eq|eql|equal|equalp|eval-when|flet|format|go|if|labels|lambda|let|load-time-value|locally|macrolet|multiple-value-call|nil|progn|progv|quote|require|return-from|setq|symbol-macrolet|t|tagbody|the|throw|unwind)\b/,a],
3
-["lit",/^[+-]?(?:[#0]x[\da-f]+|\d+\/\d+|(?:\.\d+|\d+(?:\.\d*)?)(?:[de][+-]?\d+)?)/i],["lit",/^'(?:-*(?:\w|\\[!-~])(?:[\w-]*|\\[!-~])[!=?]?)?/],["pln",/^-*(?:[_a-z]|\\[!-~])(?:[\w-]*|\\[!-~])[!=?]?/i],["pun",/^[^\w\t\n\r "'-);\\\xa0]+/]]),["cl","el","lisp","scm"]);
2
+PR.registerLangHandler(PR.createSimpleLexer([["opn",/^\(+/,a,"("],["clo",/^\)+/,a,")"],["com",/^;[^\n\r]*/,a,";"],["pln",/^[\t\n\r \xa0]+/,a,"\t\n\r \u00a0"],["str",/^"(?:[^"\\]|\\[\S\s])*(?:"|$)/,a,'"']],[["kwd",/^(?:block|c[ad]+r|catch|con[ds]|def(?:ine|un)|do|eq|eql|equal|equalp|eval-when|flet|format|go|if|labels|lambda|let|load-time-value|locally|macrolet|multiple-value-call|nil|progn|progv|quote|require|return-from|setq|symbol-macrolet|t|tagbody|the|throw|unwind)\b/,a],
3
+["lit",/^[+-]?(?:[#0]x[\da-f]+|\d+\/\d+|(?:\.\d+|\d+(?:\.\d*)?)(?:[de][+-]?\d+)?)/i],["lit",/^'(?:-*(?:\w|\\[!-~])(?:[\w-]*|\\[!-~])[!=?]?)?/],["pln",/^-*(?:[_a-z]|\\[!-~])(?:[\w-]*|\\[!-~])[!=?]?/i],["pun",/^[^\w\t\n\r "'-);\\\xa0]+/]]),["cl","el","lisp","lsp","scm","ss","rkt"]);
+1
mojo/lib/Mojolicious/public/mojo/prettify/lang-llvm.js
... ...
@@ -0,0 +1 @@
1
+PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r \u00a0"],["str",/^!?"(?:[^"\\]|\\[\S\s])*(?:"|$)/,null,'"'],["com",/^;[^\n\r]*/,null,";"]],[["pln",/^[!%@](?:[$\-.A-Z_a-z][\w$\-.]*|\d+)/],["kwd",/^[^\W\d]\w*/,null],["lit",/^\d+\.\d+/],["lit",/^(?:\d+|0[Xx][\dA-Fa-f]+)/],["pun",/^[(-*,:<->[\]{}]|\.\.\.$/]]),["llvm","ll"]);
+1 -1
mojo/lib/Mojolicious/public/mojo/prettify/lang-lua.js
... ...
@@ -1,2 +1,2 @@
1
-PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r �\xa0"],["str",/^(?:"(?:[^"\\]|\\[\S\s])*(?:"|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$))/,null,"\"'"]],[["com",/^--(?:\[(=*)\[[\S\s]*?(?:]\1]|$)|[^\n\r]*)/],["str",/^\[(=*)\[[\S\s]*?(?:]\1]|$)/],["kwd",/^(?:and|break|do|else|elseif|end|false|for|function|if|in|local|nil|not|or|repeat|return|then|true|until|while)\b/,null],["lit",/^[+-]?(?:0x[\da-f]+|(?:\.\d+|\d+(?:\.\d*)?)(?:e[+-]?\d+)?)/i],
1
+PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r \u00a0"],["str",/^(?:"(?:[^"\\]|\\[\S\s])*(?:"|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$))/,null,"\"'"]],[["com",/^--(?:\[(=*)\[[\S\s]*?(?:]\1]|$)|[^\n\r]*)/],["str",/^\[(=*)\[[\S\s]*?(?:]\1]|$)/],["kwd",/^(?:and|break|do|else|elseif|end|false|for|function|if|in|local|nil|not|or|repeat|return|then|true|until|while)\b/,null],["lit",/^[+-]?(?:0x[\da-f]+|(?:\.\d+|\d+(?:\.\d*)?)(?:e[+-]?\d+)?)/i],
2 2
 ["pln",/^[_a-z]\w*/i],["pun",/^[^\w\t\n\r \xa0][^\w\t\n\r "'+=\xa0-]*/]]),["lua"]);
+6
mojo/lib/Mojolicious/public/mojo/prettify/lang-matlab.js
... ...
@@ -0,0 +1,6 @@
1
+var a=null,b=window.PR,c=[[b.PR_PLAIN,/^[\t-\r \xa0]+/,a," \t\r\n\u000b\u000c\u00a0"],[b.PR_COMMENT,/^%{[^%]*%+(?:[^%}][^%]*%+)*}/,a],[b.PR_COMMENT,/^%[^\n\r]*/,a,"%"],["syscmd",/^![^\n\r]*/,a,"!"]],d=[["linecont",/^\.\.\.\s*[\n\r]/,a],["err",/^\?\?\? [^\n\r]*/,a],["wrn",/^Warning: [^\n\r]*/,a],["codeoutput",/^>>\s+/,a],["codeoutput",/^octave:\d+>\s+/,a],["lang-matlab-operators",/^((?:[A-Za-z]\w*(?:\.[A-Za-z]\w*)*|[).\]}])')/,a],["lang-matlab-identifiers",/^([A-Za-z]\w*(?:\.[A-Za-z]\w*)*)(?!')/,a],
2
+[b.PR_STRING,/^'(?:[^']|'')*'/,a],[b.PR_LITERAL,/^[+-]?\.?\d+(?:\.\d*)?(?:[Ee][+-]?\d+)?[ij]?/,a],[b.PR_TAG,/^[()[\]{}]/,a],[b.PR_PUNCTUATION,/^[!&*-/:->@\\^|~]/,a]],e=[["lang-matlab-identifiers",/^([A-Za-z]\w*(?:\.[A-Za-z]\w*)*)/,a],[b.PR_TAG,/^[()[\]{}]/,a],[b.PR_PUNCTUATION,/^[!&*-/:->@\\^|~]/,a],["transpose",/^'/,a]];
3
+b.registerLangHandler(b.createSimpleLexer([],[[b.PR_KEYWORD,/^\b(?:break|case|catch|classdef|continue|else|elseif|end|for|function|global|if|otherwise|parfor|persistent|return|spmd|switch|try|while)\b/,a],["const",/^\b(?:true|false|inf|Inf|nan|NaN|eps|pi|ans|nargin|nargout|varargin|varargout)\b/,a],[b.PR_TYPE,/^\b(?:cell|struct|char|double|single|logical|u?int(?:8|16|32|64)|sparse)\b/,a],["fun",/^\b(?:abs|accumarray|acos(?:d|h)?|acot(?:d|h)?|acsc(?:d|h)?|actxcontrol(?:list|select)?|actxGetRunningServer|actxserver|addlistener|addpath|addpref|addtodate|airy|align|alim|all|allchild|alpha|alphamap|amd|ancestor|and|angle|annotation|any|area|arrayfun|asec(?:d|h)?|asin(?:d|h)?|assert|assignin|atan[2dh]?|audiodevinfo|audioplayer|audiorecorder|aufinfo|auread|autumn|auwrite|avifile|aviinfo|aviread|axes|axis|balance|bar(?:3|3h|h)?|base2dec|beep|BeginInvoke|bench|bessel[h-ky]|beta|betainc|betaincinv|betaln|bicg|bicgstab|bicgstabl|bin2dec|bitand|bitcmp|bitget|bitmax|bitnot|bitor|bitset|bitshift|bitxor|blanks|blkdiag|bone|box|brighten|brush|bsxfun|builddocsearchdb|builtin|bvp4c|bvp5c|bvpget|bvpinit|bvpset|bvpxtend|calendar|calllib|callSoapService|camdolly|cameratoolbar|camlight|camlookat|camorbit|campan|campos|camproj|camroll|camtarget|camup|camva|camzoom|cart2pol|cart2sph|cast|cat|caxis|cd|cdf2rdf|cdfepoch|cdfinfo|cdflib(?:.(?:close|closeVar|computeEpoch|computeEpoch16|create|createAttr|createVar|delete|deleteAttr|deleteAttrEntry|deleteAttrgEntry|deleteVar|deleteVarRecords|epoch16Breakdown|epochBreakdown|getAttrEntry|getAttrgEntry|getAttrMaxEntry|getAttrMaxgEntry|getAttrName|getAttrNum|getAttrScope|getCacheSize|getChecksum|getCompression|getCompressionCacheSize|getConstantNames|getConstantValue|getCopyright|getFileBackward|getFormat|getLibraryCopyright|getLibraryVersion|getMajority|getName|getNumAttrEntries|getNumAttrgEntries|getNumAttributes|getNumgAttributes|getReadOnlyMode|getStageCacheSize|getValidate|getVarAllocRecords|getVarBlockingFactor|getVarCacheSize|getVarCompression|getVarData|getVarMaxAllocRecNum|getVarMaxWrittenRecNum|getVarName|getVarNum|getVarNumRecsWritten|getVarPadValue|getVarRecordData|getVarReservePercent|getVarsMaxWrittenRecNum|getVarSparseRecords|getVersion|hyperGetVarData|hyperPutVarData|inquire|inquireAttr|inquireAttrEntry|inquireAttrgEntry|inquireVar|open|putAttrEntry|putAttrgEntry|putVarData|putVarRecordData|renameAttr|renameVar|setCacheSize|setChecksum|setCompression|setCompressionCacheSize|setFileBackward|setFormat|setMajority|setReadOnlyMode|setStageCacheSize|setValidate|setVarAllocBlockRecords|setVarBlockingFactor|setVarCacheSize|setVarCompression|setVarInitialRecs|setVarPadValue|SetVarReservePercent|setVarsCacheSize|setVarSparseRecords))?|cdfread|cdfwrite|ceil|cell2mat|cell2struct|celldisp|cellfun|cellplot|cellstr|cgs|checkcode|checkin|checkout|chol|cholinc|cholupdate|circshift|cla|clabel|class|clc|clear|clearvars|clf|clipboard|clock|close|closereq|cmopts|cmpermute|cmunique|colamd|colon|colorbar|colordef|colormap|colormapeditor|colperm|Combine|comet|comet3|commandhistory|commandwindow|compan|compass|complex|computer|cond|condeig|condest|coneplot|conj|containers.Map|contour(?:[3cf]|slice)?|contrast|conv|conv2|convhull|convhulln|convn|cool|copper|copyfile|copyobj|corrcoef|cos(?:d|h)?|cot(?:d|h)?|cov|cplxpair|cputime|createClassFromWsdl|createSoapMessage|cross|csc(?:d|h)?|csvread|csvwrite|ctranspose|cumprod|cumsum|cumtrapz|curl|customverctrl|cylinder|daqread|daspect|datacursormode|datatipinfo|date|datenum|datestr|datetick|datevec|dbclear|dbcont|dbdown|dblquad|dbmex|dbquit|dbstack|dbstatus|dbstep|dbstop|dbtype|dbup|dde23|ddeget|ddesd|ddeset|deal|deblank|dec2base|dec2bin|dec2hex|decic|deconv|del2|delaunay|delaunay3|delaunayn|DelaunayTri|delete|demo|depdir|depfun|det|detrend|deval|diag|dialog|diary|diff|diffuse|dir|disp|display|dither|divergence|dlmread|dlmwrite|dmperm|doc|docsearch|dos|dot|dragrect|drawnow|dsearch|dsearchn|dynamicprops|echo|echodemo|edit|eig|eigs|ellipj|ellipke|ellipsoid|empty|enableNETfromNetworkDrive|enableservice|EndInvoke|enumeration|eomday|eq|erf|erfc|erfcinv|erfcx|erfinv|error|errorbar|errordlg|etime|etree|etreeplot|eval|evalc|evalin|event.(?:EventData|listener|PropertyEvent|proplistener)|exifread|exist|exit|exp|expint|expm|expm1|export2wsdlg|eye|ezcontour|ezcontourf|ezmesh|ezmeshc|ezplot|ezplot3|ezpolar|ezsurf|ezsurfc|factor|factorial|fclose|feather|feature|feof|ferror|feval|fft|fft2|fftn|fftshift|fftw|fgetl|fgets|fieldnames|figure|figurepalette|fileattrib|filebrowser|filemarker|fileparts|fileread|filesep|fill|fill3|filter|filter2|find|findall|findfigs|findobj|findstr|finish|fitsdisp|fitsinfo|fitsread|fitswrite|fix|flag|flipdim|fliplr|flipud|floor|flow|fminbnd|fminsearch|fopen|format|fplot|fprintf|frame2im|fread|freqspace|frewind|fscanf|fseek|ftell|FTP|full|fullfile|func2str|functions|funm|fwrite|fzero|gallery|gamma|gammainc|gammaincinv|gammaln|gca|gcbf|gcbo|gcd|gcf|gco|ge|genpath|genvarname|get|getappdata|getenv|getfield|getframe|getpixelposition|getpref|ginput|gmres|gplot|grabcode|gradient|gray|graymon|grid|griddata(?:3|n)?|griddedInterpolant|gsvd|gt|gtext|guidata|guide|guihandles|gunzip|gzip|h5create|h5disp|h5info|h5read|h5readatt|h5write|h5writeatt|hadamard|handle|hankel|hdf|hdf5|hdf5info|hdf5read|hdf5write|hdfinfo|hdfread|hdftool|help|helpbrowser|helpdesk|helpdlg|helpwin|hess|hex2dec|hex2num|hgexport|hggroup|hgload|hgsave|hgsetget|hgtransform|hidden|hilb|hist|histc|hold|home|horzcat|hostid|hot|hsv|hsv2rgb|hypot|ichol|idivide|ifft|ifft2|ifftn|ifftshift|ilu|im2frame|im2java|imag|image|imagesc|imapprox|imfinfo|imformats|import|importdata|imread|imwrite|ind2rgb|ind2sub|inferiorto|info|inline|inmem|inpolygon|input|inputdlg|inputname|inputParser|inspect|instrcallback|instrfind|instrfindall|int2str|integral(?:2|3)?|interp(?:1|1q|2|3|ft|n)|interpstreamspeed|intersect|intmax|intmin|inv|invhilb|ipermute|isa|isappdata|iscell|iscellstr|ischar|iscolumn|isdir|isempty|isequal|isequaln|isequalwithequalnans|isfield|isfinite|isfloat|isglobal|ishandle|ishghandle|ishold|isinf|isinteger|isjava|iskeyword|isletter|islogical|ismac|ismatrix|ismember|ismethod|isnan|isnumeric|isobject|isocaps|isocolors|isonormals|isosurface|ispc|ispref|isprime|isprop|isreal|isrow|isscalar|issorted|isspace|issparse|isstr|isstrprop|isstruct|isstudent|isunix|isvarname|isvector|javaaddpath|javaArray|javachk|javaclasspath|javacomponent|javaMethod|javaMethodEDT|javaObject|javaObjectEDT|javarmpath|jet|keyboard|kron|lasterr|lasterror|lastwarn|lcm|ldivide|ldl|le|legend|legendre|length|libfunctions|libfunctionsview|libisloaded|libpointer|libstruct|license|light|lightangle|lighting|lin2mu|line|lines|linkaxes|linkdata|linkprop|linsolve|linspace|listdlg|listfonts|load|loadlibrary|loadobj|log|log10|log1p|log2|loglog|logm|logspace|lookfor|lower|ls|lscov|lsqnonneg|lsqr|lt|lu|luinc|magic|makehgtform|mat2cell|mat2str|material|matfile|matlab.io.MatFile|matlab.mixin.(?:Copyable|Heterogeneous(?:.getDefaultScalarElement)?)|matlabrc|matlabroot|max|maxNumCompThreads|mean|median|membrane|memmapfile|memory|menu|mesh|meshc|meshgrid|meshz|meta.(?:class(?:.fromName)?|DynamicProperty|EnumeratedValue|event|MetaData|method|package(?:.(?:fromName|getAllPackages))?|property)|metaclass|methods|methodsview|mex(?:.getCompilerConfigurations)?|MException|mexext|mfilename|min|minres|minus|mislocked|mkdir|mkpp|mldivide|mlint|mlintrpt|mlock|mmfileinfo|mmreader|mod|mode|more|move|movefile|movegui|movie|movie2avi|mpower|mrdivide|msgbox|mtimes|mu2lin|multibandread|multibandwrite|munlock|namelengthmax|nargchk|narginchk|nargoutchk|native2unicode|nccreate|ncdisp|nchoosek|ncinfo|ncread|ncreadatt|ncwrite|ncwriteatt|ncwriteschema|ndgrid|ndims|ne|NET(?:.(?:addAssembly|Assembly|convertArray|createArray|createGeneric|disableAutoRelease|enableAutoRelease|GenericClass|invokeGenericMethod|NetException|setStaticProperty))?|netcdf.(?:abort|close|copyAtt|create|defDim|defGrp|defVar|defVarChunking|defVarDeflate|defVarFill|defVarFletcher32|delAtt|endDef|getAtt|getChunkCache|getConstant|getConstantNames|getVar|inq|inqAtt|inqAttID|inqAttName|inqDim|inqDimID|inqDimIDs|inqFormat|inqGrpName|inqGrpNameFull|inqGrpParent|inqGrps|inqLibVers|inqNcid|inqUnlimDims|inqVar|inqVarChunking|inqVarDeflate|inqVarFill|inqVarFletcher32|inqVarID|inqVarIDs|open|putAtt|putVar|reDef|renameAtt|renameDim|renameVar|setChunkCache|setDefaultFormat|setFill|sync)|newplot|nextpow2|nnz|noanimate|nonzeros|norm|normest|not|notebook|now|nthroot|null|num2cell|num2hex|num2str|numel|nzmax|ode(?:113|15i|15s|23|23s|23t|23tb|45)|odeget|odeset|odextend|onCleanup|ones|open|openfig|opengl|openvar|optimget|optimset|or|ordeig|orderfields|ordqz|ordschur|orient|orth|pack|padecoef|pagesetupdlg|pan|pareto|parseSoapResponse|pascal|patch|path|path2rc|pathsep|pathtool|pause|pbaspect|pcg|pchip|pcode|pcolor|pdepe|pdeval|peaks|perl|perms|permute|pie|pink|pinv|planerot|playshow|plot|plot3|plotbrowser|plotedit|plotmatrix|plottools|plotyy|plus|pol2cart|polar|poly|polyarea|polyder|polyeig|polyfit|polyint|polyval|polyvalm|pow2|power|ppval|prefdir|preferences|primes|print|printdlg|printopt|printpreview|prod|profile|profsave|propedit|propertyeditor|psi|publish|PutCharArray|PutFullMatrix|PutWorkspaceData|pwd|qhull|qmr|qr|qrdelete|qrinsert|qrupdate|quad|quad2d|quadgk|quadl|quadv|questdlg|quit|quiver|quiver3|qz|rand|randi|randn|randperm|RandStream(?:.(?:create|getDefaultStream|getGlobalStream|list|setDefaultStream|setGlobalStream))?|rank|rat|rats|rbbox|rcond|rdivide|readasync|real|reallog|realmax|realmin|realpow|realsqrt|record|rectangle|rectint|recycle|reducepatch|reducevolume|refresh|refreshdata|regexp|regexpi|regexprep|regexptranslate|rehash|rem|Remove|RemoveAll|repmat|reset|reshape|residue|restoredefaultpath|rethrow|rgb2hsv|rgb2ind|rgbplot|ribbon|rmappdata|rmdir|rmfield|rmpath|rmpref|rng|roots|rose|rosser|rot90|rotate|rotate3d|round|rref|rsf2csf|run|save|saveas|saveobj|savepath|scatter|scatter3|schur|sec|secd|sech|selectmoveresize|semilogx|semilogy|sendmail|serial|set|setappdata|setdiff|setenv|setfield|setpixelposition|setpref|setstr|setxor|shading|shg|shiftdim|showplottool|shrinkfaces|sign|sin(?:d|h)?|size|slice|smooth3|snapnow|sort|sortrows|sound|soundsc|spalloc|spaugment|spconvert|spdiags|specular|speye|spfun|sph2cart|sphere|spinmap|spline|spones|spparms|sprand|sprandn|sprandsym|sprank|spring|sprintf|spy|sqrt|sqrtm|squeeze|ss2tf|sscanf|stairs|startup|std|stem|stem3|stopasync|str2double|str2func|str2mat|str2num|strcat|strcmp|strcmpi|stream2|stream3|streamline|streamparticles|streamribbon|streamslice|streamtube|strfind|strjust|strmatch|strncmp|strncmpi|strread|strrep|strtok|strtrim|struct2cell|structfun|strvcat|sub2ind|subplot|subsasgn|subsindex|subspace|subsref|substruct|subvolume|sum|summer|superclasses|superiorto|support|surf|surf2patch|surface|surfc|surfl|surfnorm|svd|svds|swapbytes|symamd|symbfact|symmlq|symrcm|symvar|system|tan(?:d|h)?|tar|tempdir|tempname|tetramesh|texlabel|text|textread|textscan|textwrap|tfqmr|throw|tic|Tiff(?:.(?:getTagNames|getVersion))?|timer|timerfind|timerfindall|times|timeseries|title|toc|todatenum|toeplitz|toolboxdir|trace|transpose|trapz|treelayout|treeplot|tril|trimesh|triplequad|triplot|TriRep|TriScatteredInterp|trisurf|triu|tscollection|tsearch|tsearchn|tstool|type|typecast|uibuttongroup|uicontextmenu|uicontrol|uigetdir|uigetfile|uigetpref|uiimport|uimenu|uiopen|uipanel|uipushtool|uiputfile|uiresume|uisave|uisetcolor|uisetfont|uisetpref|uistack|uitable|uitoggletool|uitoolbar|uiwait|uminus|undocheckout|unicode2native|union|unique|unix|unloadlibrary|unmesh|unmkpp|untar|unwrap|unzip|uplus|upper|urlread|urlwrite|usejava|userpath|validateattributes|validatestring|vander|var|vectorize|ver|verctrl|verLessThan|version|vertcat|VideoReader(?:.isPlatformSupported)?|VideoWriter(?:.getProfiles)?|view|viewmtx|visdiff|volumebounds|voronoi|voronoin|wait|waitbar|waitfor|waitforbuttonpress|warndlg|warning|waterfall|wavfinfo|wavplay|wavread|wavrecord|wavwrite|web|weekday|what|whatsnew|which|whitebg|who|whos|wilkinson|winopen|winqueryreg|winter|wk1finfo|wk1read|wk1write|workspace|xlabel|xlim|xlsfinfo|xlsread|xlswrite|xmlread|xmlwrite|xor|xslt|ylabel|ylim|zeros|zip|zlabel|zlim|zoom)\b/,
4
+a],["fun_tbx",/^\b(?:addedvarplot|andrewsplot|anova[12n]|ansaribradley|aoctool|barttest|bbdesign|beta(?:cdf|fit|inv|like|pdf|rnd|stat)|bino(?:cdf|fit|inv|pdf|rnd|stat)|biplot|bootci|bootstrp|boxplot|candexch|candgen|canoncorr|capability|capaplot|caseread|casewrite|categorical|ccdesign|cdfplot|chi2(?:cdf|gof|inv|pdf|rnd|stat)|cholcov|Classification(?:BaggedEnsemble|Discriminant(?:.(?:fit|make|template))?|Ensemble|KNN(?:.(?:fit|template))?|PartitionedEnsemble|PartitionedModel|Tree(?:.(?:fit|template))?)|classify|classregtree|cluster|clusterdata|cmdscale|combnk|Compact(?:Classification(?:Discriminant|Ensemble|Tree)|Regression(?:Ensemble|Tree)|TreeBagger)|confusionmat|controlchart|controlrules|cophenet|copula(?:cdf|fit|param|pdf|rnd|stat)|cordexch|corr|corrcov|coxphfit|createns|crosstab|crossval|cvpartition|datasample|dataset|daugment|dcovary|dendrogram|dfittool|disttool|dummyvar|dwtest|ecdf|ecdfhist|ev(?:cdf|fit|inv|like|pdf|rnd|stat)|ExhaustiveSearcher|exp(?:cdf|fit|inv|like|pdf|rnd|stat)|factoran|fcdf|ff2n|finv|fitdist|fitensemble|fpdf|fracfact|fracfactgen|friedman|frnd|fstat|fsurfht|fullfact|gagerr|gam(?:cdf|fit|inv|like|pdf|rnd|stat)|GeneralizedLinearModel(?:.fit)?|geo(?:cdf|inv|mean|pdf|rnd|stat)|gev(?:cdf|fit|inv|like|pdf|rnd|stat)|gline|glmfit|glmval|glyphplot|gmdistribution(?:.fit)?|gname|gp(?:cdf|fit|inv|like|pdf|rnd|stat)|gplotmatrix|grp2idx|grpstats|gscatter|haltonset|harmmean|hist3|histfit|hmm(?:decode|estimate|generate|train|viterbi)|hougen|hyge(?:cdf|inv|pdf|rnd|stat)|icdf|inconsistent|interactionplot|invpred|iqr|iwishrnd|jackknife|jbtest|johnsrnd|KDTreeSearcher|kmeans|knnsearch|kruskalwallis|ksdensity|kstest|kstest2|kurtosis|lasso|lassoglm|lassoPlot|leverage|lhsdesign|lhsnorm|lillietest|LinearModel(?:.fit)?|linhyptest|linkage|logn(?:cdf|fit|inv|like|pdf|rnd|stat)|lsline|mad|mahal|maineffectsplot|manova1|manovacluster|mdscale|mhsample|mle|mlecov|mnpdf|mnrfit|mnrnd|mnrval|moment|multcompare|multivarichart|mvn(?:cdf|pdf|rnd)|mvregress|mvregresslike|mvt(?:cdf|pdf|rnd)|NaiveBayes(?:.fit)?|nan(?:cov|max|mean|median|min|std|sum|var)|nbin(?:cdf|fit|inv|pdf|rnd|stat)|ncf(?:cdf|inv|pdf|rnd|stat)|nct(?:cdf|inv|pdf|rnd|stat)|ncx2(?:cdf|inv|pdf|rnd|stat)|NeighborSearcher|nlinfit|nlintool|nlmefit|nlmefitsa|nlparci|nlpredci|nnmf|nominal|NonLinearModel(?:.fit)?|norm(?:cdf|fit|inv|like|pdf|rnd|stat)|normplot|normspec|ordinal|outlierMeasure|parallelcoords|paretotails|partialcorr|pcacov|pcares|pdf|pdist|pdist2|pearsrnd|perfcurve|perms|piecewisedistribution|plsregress|poiss(?:cdf|fit|inv|pdf|rnd|tat)|polyconf|polytool|prctile|princomp|ProbDist(?:Kernel|Parametric|UnivKernel|UnivParam)?|probplot|procrustes|qqplot|qrandset|qrandstream|quantile|randg|random|randsample|randtool|range|rangesearch|ranksum|rayl(?:cdf|fit|inv|pdf|rnd|stat)|rcoplot|refcurve|refline|regress|Regression(?:BaggedEnsemble|Ensemble|PartitionedEnsemble|PartitionedModel|Tree(?:.(?:fit|template))?)|regstats|relieff|ridge|robustdemo|robustfit|rotatefactors|rowexch|rsmdemo|rstool|runstest|sampsizepwr|scatterhist|sequentialfs|signrank|signtest|silhouette|skewness|slicesample|sobolset|squareform|statget|statset|stepwise|stepwisefit|surfht|tabulate|tblread|tblwrite|tcdf|tdfread|tiedrank|tinv|tpdf|TreeBagger|treedisp|treefit|treeprune|treetest|treeval|trimmean|trnd|tstat|ttest|ttest2|unid(?:cdf|inv|pdf|rnd|stat)|unif(?:cdf|inv|it|pdf|rnd|stat)|vartest(?:2|n)?|wbl(?:cdf|fit|inv|like|pdf|rnd|stat)|wblplot|wishrnd|x2fx|xptread|zscore|ztest)\b/,
5
+a],["fun_tbx",/^\b(?:adapthisteq|analyze75info|analyze75read|applycform|applylut|axes2pix|bestblk|blockproc|bwarea|bwareaopen|bwboundaries|bwconncomp|bwconvhull|bwdist|bwdistgeodesic|bweuler|bwhitmiss|bwlabel|bwlabeln|bwmorph|bwpack|bwperim|bwselect|bwtraceboundary|bwulterode|bwunpack|checkerboard|col2im|colfilt|conndef|convmtx2|corner|cornermetric|corr2|cp2tform|cpcorr|cpselect|cpstruct2pairs|dct2|dctmtx|deconvblind|deconvlucy|deconvreg|deconvwnr|decorrstretch|demosaic|dicom(?:anon|dict|info|lookup|read|uid|write)|edge|edgetaper|entropy|entropyfilt|fan2para|fanbeam|findbounds|fliptform|freqz2|fsamp2|fspecial|ftrans2|fwind1|fwind2|getheight|getimage|getimagemodel|getline|getneighbors|getnhood|getpts|getrangefromclass|getrect|getsequence|gray2ind|graycomatrix|graycoprops|graydist|grayslice|graythresh|hdrread|hdrwrite|histeq|hough|houghlines|houghpeaks|iccfind|iccread|iccroot|iccwrite|idct2|ifanbeam|im2bw|im2col|im2double|im2int16|im2java2d|im2single|im2uint16|im2uint8|imabsdiff|imadd|imadjust|ImageAdapter|imageinfo|imagemodel|imapplymatrix|imattributes|imbothat|imclearborder|imclose|imcolormaptool|imcomplement|imcontour|imcontrast|imcrop|imdilate|imdisplayrange|imdistline|imdivide|imellipse|imerode|imextendedmax|imextendedmin|imfill|imfilter|imfindcircles|imfreehand|imfuse|imgca|imgcf|imgetfile|imhandles|imhist|imhmax|imhmin|imimposemin|imlincomb|imline|immagbox|immovie|immultiply|imnoise|imopen|imoverview|imoverviewpanel|impixel|impixelinfo|impixelinfoval|impixelregion|impixelregionpanel|implay|impoint|impoly|impositionrect|improfile|imputfile|impyramid|imreconstruct|imrect|imregconfig|imregionalmax|imregionalmin|imregister|imresize|imroi|imrotate|imsave|imscrollpanel|imshow|imshowpair|imsubtract|imtool|imtophat|imtransform|imview|ind2gray|ind2rgb|interfileinfo|interfileread|intlut|ippl|iptaddcallback|iptcheckconn|iptcheckhandle|iptcheckinput|iptcheckmap|iptchecknargin|iptcheckstrs|iptdemos|iptgetapi|iptGetPointerBehavior|iptgetpref|ipticondir|iptnum2ordinal|iptPointerManager|iptprefs|iptremovecallback|iptSetPointerBehavior|iptsetpref|iptwindowalign|iradon|isbw|isflat|isgray|isicc|isind|isnitf|isrgb|isrset|lab2double|lab2uint16|lab2uint8|label2rgb|labelmatrix|makecform|makeConstrainToRectFcn|makehdr|makelut|makeresampler|maketform|mat2gray|mean2|medfilt2|montage|nitfinfo|nitfread|nlfilter|normxcorr2|ntsc2rgb|openrset|ordfilt2|otf2psf|padarray|para2fan|phantom|poly2mask|psf2otf|qtdecomp|qtgetblk|qtsetblk|radon|rangefilt|reflect|regionprops|registration.metric.(?:MattesMutualInformation|MeanSquares)|registration.optimizer.(?:OnePlusOneEvolutionary|RegularStepGradientDescent)|rgb2gray|rgb2ntsc|rgb2ycbcr|roicolor|roifill|roifilt2|roipoly|rsetwrite|std2|stdfilt|strel|stretchlim|subimage|tformarray|tformfwd|tforminv|tonemap|translate|truesize|uintlut|viscircles|warp|watershed|whitepoint|wiener2|xyz2double|xyz2uint16|ycbcr2rgb)\b/,
6
+a],["fun_tbx",/^\b(?:bintprog|color|fgoalattain|fminbnd|fmincon|fminimax|fminsearch|fminunc|fseminf|fsolve|fzero|fzmult|gangstr|ktrlink|linprog|lsqcurvefit|lsqlin|lsqnonlin|lsqnonneg|optimget|optimset|optimtool|quadprog)\b/,a],["ident",/^[A-Za-z]\w*(?:\.[A-Za-z]\w*)*/,a]]),["matlab-identifiers"]);b.registerLangHandler(b.createSimpleLexer([],e),["matlab-operators"]);b.registerLangHandler(b.createSimpleLexer(c,d),["matlab"]);
+1 -1
mojo/lib/Mojolicious/public/mojo/prettify/lang-ml.js
... ...
@@ -1,2 +1,2 @@
1
-PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r �\xa0"],["com",/^#(?:if[\t\n\r \xa0]+(?:[$_a-z][\w']*|``[^\t\n\r`]*(?:``|$))|else|endif|light)/i,null,"#"],["str",/^(?:"(?:[^"\\]|\\[\S\s])*(?:"|$)|'(?:[^'\\]|\\[\S\s])(?:'|$))/,null,"\"'"]],[["com",/^(?:\/\/[^\n\r]*|\(\*[\S\s]*?\*\))/],["kwd",/^(?:abstract|and|as|assert|begin|class|default|delegate|do|done|downcast|downto|elif|else|end|exception|extern|false|finally|for|fun|function|if|in|inherit|inline|interface|internal|lazy|let|match|member|module|mutable|namespace|new|null|of|open|or|override|private|public|rec|return|static|struct|then|to|true|try|type|upcast|use|val|void|when|while|with|yield|asr|land|lor|lsl|lsr|lxor|mod|sig|atomic|break|checked|component|const|constraint|constructor|continue|eager|event|external|fixed|functor|global|include|method|mixin|object|parallel|process|protected|pure|sealed|trait|virtual|volatile)\b/],
1
+PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r \u00a0"],["com",/^#(?:if[\t\n\r \xa0]+(?:[$_a-z][\w']*|``[^\t\n\r`]*(?:``|$))|else|endif|light)/i,null,"#"],["str",/^(?:"(?:[^"\\]|\\[\S\s])*(?:"|$)|'(?:[^'\\]|\\[\S\s])(?:'|$))/,null,"\"'"]],[["com",/^(?:\/\/[^\n\r]*|\(\*[\S\s]*?\*\))/],["kwd",/^(?:abstract|and|as|assert|begin|class|default|delegate|do|done|downcast|downto|elif|else|end|exception|extern|false|finally|for|fun|function|if|in|inherit|inline|interface|internal|lazy|let|match|member|module|mutable|namespace|new|null|of|open|or|override|private|public|rec|return|static|struct|then|to|true|try|type|upcast|use|val|void|when|while|with|yield|asr|land|lor|lsl|lsr|lxor|mod|sig|atomic|break|checked|component|const|constraint|constructor|continue|eager|event|external|fixed|functor|global|include|method|mixin|object|parallel|process|protected|pure|sealed|trait|virtual|volatile)\b/],
2 2
 ["lit",/^[+-]?(?:0x[\da-f]+|(?:\.\d+|\d+(?:\.\d*)?)(?:e[+-]?\d+)?)/i],["pln",/^(?:[_a-z][\w']*[!#?]?|``[^\t\n\r`]*(?:``|$))/i],["pun",/^[^\w\t\n\r "'\xa0]+/]]),["fs","ml"]);
+2
mojo/lib/Mojolicious/public/mojo/prettify/lang-mumps.js
... ...
@@ -0,0 +1,2 @@
1
+PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r \u00a0"],["str",/^"(?:[^"]|\\.)*"/,null,'"']],[["com",/^;[^\n\r]*/,null,";"],["dec",/^\$(?:d|device|ec|ecode|es|estack|et|etrap|h|horolog|i|io|j|job|k|key|p|principal|q|quit|st|stack|s|storage|sy|system|t|test|tl|tlevel|tr|trestart|x|y|z[a-z]*|a|ascii|c|char|d|data|e|extract|f|find|fn|fnumber|g|get|j|justify|l|length|na|name|o|order|p|piece|ql|qlength|qs|qsubscript|q|query|r|random|re|reverse|s|select|st|stack|t|text|tr|translate|nan)\b/i,
2
+null],["kwd",/^(?:[^$]b|break|c|close|d|do|e|else|f|for|g|goto|h|halt|h|hang|i|if|j|job|k|kill|l|lock|m|merge|n|new|o|open|q|quit|r|read|s|set|tc|tcommit|tre|trestart|tro|trollback|ts|tstart|u|use|v|view|w|write|x|xecute)\b/i,null],["lit",/^[+-]?(?:\.\d+|\d+(?:\.\d*)?)(?:e[+-]?\d+)?/i],["pln",/^[a-z][^\W_]*/i],["pun",/^[^\w\t\n\r"$%;^\xa0]|_/]]),["mumps"]);
+1 -1
mojo/lib/Mojolicious/public/mojo/prettify/lang-n.js
... ...
@@ -1,4 +1,4 @@
1 1
 var a=null;
2
-PR.registerLangHandler(PR.createSimpleLexer([["str",/^(?:'(?:[^\n\r'\\]|\\.)*'|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,a,'"'],["com",/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/,a,"#"],["pln",/^\s+/,a," \r\n\t\xa0"]],[["str",/^@"(?:[^"]|"")*(?:"|$)/,a],["str",/^<#[^#>]*(?:#>|$)/,a],["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,a],["com",/^\/\/[^\n\r]*/,a],["com",/^\/\*[\S\s]*?(?:\*\/|$)/,
2
+PR.registerLangHandler(PR.createSimpleLexer([["str",/^(?:'(?:[^\n\r'\\]|\\.)*'|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,a,'"'],["com",/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/,a,"#"],["pln",/^\s+/,a," \r\n\t\u00a0"]],[["str",/^@"(?:[^"]|"")*(?:"|$)/,a],["str",/^<#[^#>]*(?:#>|$)/,a],["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,a],["com",/^\/\/[^\n\r]*/,a],["com",/^\/\*[\S\s]*?(?:\*\/|$)/,
3 3
 a],["kwd",/^(?:abstract|and|as|base|catch|class|def|delegate|enum|event|extern|false|finally|fun|implements|interface|internal|is|macro|match|matches|module|mutable|namespace|new|null|out|override|params|partial|private|protected|public|ref|sealed|static|struct|syntax|this|throw|true|try|type|typeof|using|variant|virtual|volatile|when|where|with|assert|assert2|async|break|checked|continue|do|else|ensures|for|foreach|if|late|lock|new|nolate|otherwise|regexp|repeat|requires|return|surroundwith|unchecked|unless|using|while|yield)\b/,
4 4
 a],["typ",/^(?:array|bool|byte|char|decimal|double|float|int|list|long|object|sbyte|short|string|ulong|uint|ufloat|ulong|ushort|void)\b/,a],["lit",/^@[$_a-z][\w$@]*/i,a],["typ",/^@[A-Z]+[a-z][\w$@]*/,a],["pln",/^'?[$_a-z][\w$@]*/i,a],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,a,"0123456789"],["pun",/^.[^\s\w"-$'./@`]*/,a]]),["n","nemerle"]);
+3
mojo/lib/Mojolicious/public/mojo/prettify/lang-pascal.js
... ...
@@ -0,0 +1,3 @@
1
+var a=null;
2
+PR.registerLangHandler(PR.createSimpleLexer([["str",/^'(?:[^\n\r'\\]|\\.)*(?:'|$)/,a,"'"],["pln",/^\s+/,a," \r\n\t\u00a0"]],[["com",/^\(\*[\S\s]*?(?:\*\)|$)|^{[\S\s]*?(?:}|$)/,a],["kwd",/^(?:absolute|and|array|asm|assembler|begin|case|const|constructor|destructor|div|do|downto|else|end|external|for|forward|function|goto|if|implementation|in|inline|interface|interrupt|label|mod|not|object|of|or|packed|procedure|program|record|repeat|set|shl|shr|then|to|type|unit|until|uses|var|virtual|while|with|xor)\b/i,a],
3
+["lit",/^(?:true|false|self|nil)/i,a],["pln",/^[a-z][^\W_]*/i,a],["lit",/^(?:\$[\da-f]+|(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?)/i,a,"0123456789"],["pun",/^.[^\s\w$'./@]*/,a]]),["pascal"]);
+2
mojo/lib/Mojolicious/public/mojo/prettify/lang-r.js
... ...
@@ -0,0 +1,2 @@
1
+PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r \u00a0"],["str",/^"(?:[^"\\]|\\[\S\s])*(?:"|$)/,null,'"'],["str",/^'(?:[^'\\]|\\[\S\s])*(?:'|$)/,null,"'"]],[["com",/^#.*/],["kwd",/^(?:if|else|for|while|repeat|in|next|break|return|switch|function)(?![\w.])/],["lit",/^0[Xx][\dA-Fa-f]+([Pp]\d+)?[Li]?/],["lit",/^[+-]?(\d+(\.\d+)?|\.\d+)([Ee][+-]?\d+)?[Li]?/],["lit",/^(?:NULL|NA(?:_(?:integer|real|complex|character)_)?|Inf|TRUE|FALSE|NaN|\.\.(?:\.|\d+))(?![\w.])/],
2
+["pun",/^(?:<<?-|->>?|-|==|<=|>=|<|>|&&?|!=|\|\|?|[!*+/^]|%.*?%|[$=@~]|:{1,3}|[(),;?[\]{}])/],["pln",/^(?:[A-Za-z]+[\w.]*|\.[^\W\d][\w.]*)(?![\w.])/],["str",/^`.+`/]]),["r","s","R","S","Splus"]);
+1
mojo/lib/Mojolicious/public/mojo/prettify/lang-rd.js
... ...
@@ -0,0 +1 @@
1
+PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r \u00a0"],["com",/^%[^\n\r]*/,null,"%"]],[["lit",/^\\(?:cr|l?dots|R|tab)\b/],["kwd",/^\\[@-Za-z]+/],["kwd",/^#(?:ifn?def|endif)/],["pln",/^\\[{}]/],["pun",/^[()[\]{}]+/]]),["Rd","rd"]);
+1 -1
mojo/lib/Mojolicious/public/mojo/prettify/lang-scala.js
... ...
@@ -1,2 +1,2 @@
1
-PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r �\xa0"],["str",/^"(?:""(?:""?(?!")|[^"\\]|\\.)*"{0,3}|(?:[^\n\r"\\]|\\.)*"?)/,null,'"'],["lit",/^`(?:[^\n\r\\`]|\\.)*`?/,null,"`"],["pun",/^[!#%&(--:-@[-^{-~]+/,null,"!#%&()*+,-:;<=>?@[\\]^{|}~"]],[["str",/^'(?:[^\n\r'\\]|\\(?:'|[^\n\r']+))'/],["lit",/^'[$A-Z_a-z][\w$]*(?![\w$'])/],["kwd",/^(?:abstract|case|catch|class|def|do|else|extends|final|finally|for|forSome|if|implicit|import|lazy|match|new|object|override|package|private|protected|requires|return|sealed|super|throw|trait|try|type|val|var|while|with|yield)\b/],
1
+PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r \u00a0"],["str",/^"(?:""(?:""?(?!")|[^"\\]|\\.)*"{0,3}|(?:[^\n\r"\\]|\\.)*"?)/,null,'"'],["lit",/^`(?:[^\n\r\\`]|\\.)*`?/,null,"`"],["pun",/^[!#%&(--:-@[-^{-~]+/,null,"!#%&()*+,-:;<=>?@[\\]^{|}~"]],[["str",/^'(?:[^\n\r'\\]|\\(?:'|[^\n\r']+))'/],["lit",/^'[$A-Z_a-z][\w$]*(?![\w$'])/],["kwd",/^(?:abstract|case|catch|class|def|do|else|extends|final|finally|for|forSome|if|implicit|import|lazy|match|new|object|override|package|private|protected|requires|return|sealed|super|throw|trait|try|type|val|var|while|with|yield)\b/],
2 2
 ["lit",/^(?:true|false|null|this)\b/],["lit",/^(?:0(?:[0-7]+|x[\da-f]+)l?|(?:0|[1-9]\d*)(?:(?:\.\d+)?(?:e[+-]?\d+)?f?|l?)|\\.\d+(?:e[+-]?\d+)?f?)/i],["typ",/^[$_]*[A-Z][\d$A-Z_]*[a-z][\w$]*/],["pln",/^[$A-Z_a-z][\w$]*/],["com",/^\/(?:\/.*|\*(?:\/|\**[^*/])*(?:\*+\/?)?)/],["pun",/^(?:\.+|\/)/]]),["scala"]);
+1 -1
mojo/lib/Mojolicious/public/mojo/prettify/lang-sql.js
... ...
@@ -1,2 +1,2 @@
1
-PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r �\xa0"],["str",/^(?:"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*')/,null,"\"'"]],[["com",/^(?:--[^\n\r]*|\/\*[\S\s]*?(?:\*\/|$))/],["kwd",/^(?:add|all|alter|and|any|as|asc|authorization|backup|begin|between|break|browse|bulk|by|cascade|case|check|checkpoint|close|clustered|coalesce|collate|column|commit|compute|constraint|contains|containstable|continue|convert|create|cross|current|current_date|current_time|current_timestamp|current_user|cursor|database|dbcc|deallocate|declare|default|delete|deny|desc|disk|distinct|distributed|double|drop|dummy|dump|else|end|errlvl|escape|except|exec|execute|exists|exit|fetch|file|fillfactor|for|foreign|freetext|freetexttable|from|full|function|goto|grant|group|having|holdlock|identity|identitycol|identity_insert|if|in|index|inner|insert|intersect|into|is|join|key|kill|left|like|lineno|load|match|merge|national|nocheck|nonclustered|not|null|nullif|of|off|offsets|on|open|opendatasource|openquery|openrowset|openxml|option|or|order|outer|over|percent|plan|precision|primary|print|proc|procedure|public|raiserror|read|readtext|reconfigure|references|replication|restore|restrict|return|revoke|right|rollback|rowcount|rowguidcol|rule|save|schema|select|session_user|set|setuser|shutdown|some|statistics|system_user|table|textsize|then|to|top|tran|transaction|trigger|truncate|tsequal|union|unique|update|updatetext|use|user|using|values|varying|view|waitfor|when|where|while|with|writetext)(?=[^\w-]|$)/i,
1
+PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r \u00a0"],["str",/^(?:"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*')/,null,"\"'"]],[["com",/^(?:--[^\n\r]*|\/\*[\S\s]*?(?:\*\/|$))/],["kwd",/^(?:add|all|alter|and|any|apply|as|asc|authorization|backup|begin|between|break|browse|bulk|by|cascade|case|check|checkpoint|close|clustered|coalesce|collate|column|commit|compute|connect|constraint|contains|containstable|continue|convert|create|cross|current|current_date|current_time|current_timestamp|current_user|cursor|database|dbcc|deallocate|declare|default|delete|deny|desc|disk|distinct|distributed|double|drop|dummy|dump|else|end|errlvl|escape|except|exec|execute|exists|exit|fetch|file|fillfactor|following|for|foreign|freetext|freetexttable|from|full|function|goto|grant|group|having|holdlock|identity|identitycol|identity_insert|if|in|index|inner|insert|intersect|into|is|join|key|kill|left|like|lineno|load|match|matched|merge|natural|national|nocheck|nonclustered|nocycle|not|null|nullif|of|off|offsets|on|open|opendatasource|openquery|openrowset|openxml|option|or|order|outer|over|partition|percent|pivot|plan|preceding|precision|primary|print|proc|procedure|public|raiserror|read|readtext|reconfigure|references|replication|restore|restrict|return|revoke|right|rollback|rowcount|rowguidcol|rows?|rule|save|schema|select|session_user|set|setuser|shutdown|some|start|statistics|system_user|table|textsize|then|to|top|tran|transaction|trigger|truncate|tsequal|unbounded|union|unique|unpivot|update|updatetext|use|user|using|values|varying|view|waitfor|when|where|while|with|within|writetext|xml)(?=[^\w-]|$)/i,
2 2
 null],["lit",/^[+-]?(?:0x[\da-f]+|(?:\.\d+|\d+(?:\.\d*)?)(?:e[+-]?\d+)?)/i],["pln",/^[_a-z][\w-]*/i],["pun",/^[^\w\t\n\r "'\xa0][^\w\t\n\r "'+\xa0-]*/]]),["sql"]);
+3
mojo/lib/Mojolicious/public/mojo/prettify/lang-tcl.js
... ...
@@ -0,0 +1,3 @@
1
+var a=null;
2
+PR.registerLangHandler(PR.createSimpleLexer([["opn",/^{+/,a,"{"],["clo",/^}+/,a,"}"],["com",/^#[^\n\r]*/,a,"#"],["pln",/^[\t\n\r \xa0]+/,a,"\t\n\r \u00a0"],["str",/^"(?:[^"\\]|\\[\S\s])*(?:"|$)/,a,'"']],[["kwd",/^(?:after|append|apply|array|break|case|catch|continue|error|eval|exec|exit|expr|for|foreach|if|incr|info|proc|return|set|switch|trace|uplevel|upvar|while)\b/,a],["lit",/^[+-]?(?:[#0]x[\da-f]+|\d+\/\d+|(?:\.\d+|\d+(?:\.\d*)?)(?:[de][+-]?\d+)?)/i],["lit",
3
+/^'(?:-*(?:\w|\\[!-~])(?:[\w-]*|\\[!-~])[!=?]?)?/],["pln",/^-*(?:[_a-z]|\\[!-~])(?:[\w-]*|\\[!-~])[!=?]?/i],["pun",/^[^\w\t\n\r "'-);\\\xa0]+/]]),["tcl"]);
+1 -1
mojo/lib/Mojolicious/public/mojo/prettify/lang-tex.js
... ...
@@ -1 +1 @@
1
-PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r �\xa0"],["com",/^%[^\n\r]*/,null,"%"]],[["kwd",/^\\[@-Za-z]+/],["kwd",/^\\./],["typ",/^[$&]/],["lit",/[+-]?(?:\.\d+|\d+(?:\.\d*)?)(cm|em|ex|in|pc|pt|bp|mm)/i],["pun",/^[()=[\]{}]+/]]),["latex","tex"]);
1
+PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r \u00a0"],["com",/^%[^\n\r]*/,null,"%"]],[["kwd",/^\\[@-Za-z]+/],["kwd",/^\\./],["typ",/^[$&]/],["lit",/[+-]?(?:\.\d+|\d+(?:\.\d*)?)(cm|em|ex|in|pc|pt|bp|mm)/i],["pun",/^[()=[\]{}]+/]]),["latex","tex"]);
+2 -2
mojo/lib/Mojolicious/public/mojo/prettify/lang-vb.js
... ...
@@ -1,2 +1,2 @@
1
-PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0\u2028\u2029]+/,null,"\t\n\r �\xa0

"],["str",/^(?:["\u201c\u201d](?:[^"\u201c\u201d]|["\u201c\u201d]{2})(?:["\u201c\u201d]c|$)|["\u201c\u201d](?:[^"\u201c\u201d]|["\u201c\u201d]{2})*(?:["\u201c\u201d]|$))/i,null,'"“”'],["com",/^['\u2018\u2019].*/,null,"'‘’"]],[["kwd",/^(?:addhandler|addressof|alias|and|andalso|ansi|as|assembly|auto|boolean|byref|byte|byval|call|case|catch|cbool|cbyte|cchar|cdate|cdbl|cdec|char|cint|class|clng|cobj|const|cshort|csng|cstr|ctype|date|decimal|declare|default|delegate|dim|directcast|do|double|each|else|elseif|end|endif|enum|erase|error|event|exit|finally|for|friend|function|get|gettype|gosub|goto|handles|if|implements|imports|in|inherits|integer|interface|is|let|lib|like|long|loop|me|mod|module|mustinherit|mustoverride|mybase|myclass|namespace|new|next|not|notinheritable|notoverridable|object|on|option|optional|or|orelse|overloads|overridable|overrides|paramarray|preserve|private|property|protected|public|raiseevent|readonly|redim|removehandler|resume|return|select|set|shadows|shared|short|single|static|step|stop|string|structure|sub|synclock|then|throw|to|try|typeof|unicode|until|variant|wend|when|while|with|withevents|writeonly|xor|endif|gosub|let|variant|wend)\b/i,
2
-null],["com",/^rem.*/i],["lit",/^(?:true\b|false\b|nothing\b|\d+(?:e[+-]?\d+[dfr]?|[dfilrs])?|(?:&h[\da-f]+|&o[0-7]+)[ils]?|\d*\.\d+(?:e[+-]?\d+)?[dfr]?|#\s+(?:\d+[/-]\d+[/-]\d+(?:\s+\d+:\d+(?::\d+)?(\s*(?:am|pm))?)?|\d+:\d+(?::\d+)?(\s*(?:am|pm))?)\s+#)/i],["pln",/^(?:(?:[a-z]|_\w)\w*|\[(?:[a-z]|_\w)\w*])/i],["pun",/^[^\w\t\n\r "'[\]\xa0\u2018\u2019\u201c\u201d\u2028\u2029]+/],["pun",/^(?:\[|])/]]),["vb","vbs"]);
1
+PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0\u2028\u2029]+/,null,"\t\n\r \u00a0\u2028\u2029"],["str",/^(?:["\u201c\u201d](?:[^"\u201c\u201d]|["\u201c\u201d]{2})(?:["\u201c\u201d]c|$)|["\u201c\u201d](?:[^"\u201c\u201d]|["\u201c\u201d]{2})*(?:["\u201c\u201d]|$))/i,null,'"\u201c\u201d'],["com",/^['\u2018\u2019](?:_(?:\r\n?|[^\r]?)|[^\n\r_\u2028\u2029])*/,null,"'\u2018\u2019"]],[["kwd",/^(?:addhandler|addressof|alias|and|andalso|ansi|as|assembly|auto|boolean|byref|byte|byval|call|case|catch|cbool|cbyte|cchar|cdate|cdbl|cdec|char|cint|class|clng|cobj|const|cshort|csng|cstr|ctype|date|decimal|declare|default|delegate|dim|directcast|do|double|each|else|elseif|end|endif|enum|erase|error|event|exit|finally|for|friend|function|get|gettype|gosub|goto|handles|if|implements|imports|in|inherits|integer|interface|is|let|lib|like|long|loop|me|mod|module|mustinherit|mustoverride|mybase|myclass|namespace|new|next|not|notinheritable|notoverridable|object|on|option|optional|or|orelse|overloads|overridable|overrides|paramarray|preserve|private|property|protected|public|raiseevent|readonly|redim|removehandler|resume|return|select|set|shadows|shared|short|single|static|step|stop|string|structure|sub|synclock|then|throw|to|try|typeof|unicode|until|variant|wend|when|while|with|withevents|writeonly|xor|endif|gosub|let|variant|wend)\b/i,
2
+null],["com",/^rem\b.*/i],["lit",/^(?:true\b|false\b|nothing\b|\d+(?:e[+-]?\d+[dfr]?|[dfilrs])?|(?:&h[\da-f]+|&o[0-7]+)[ils]?|\d*\.\d+(?:e[+-]?\d+)?[dfr]?|#\s+(?:\d+[/-]\d+[/-]\d+(?:\s+\d+:\d+(?::\d+)?(\s*(?:am|pm))?)?|\d+:\d+(?::\d+)?(\s*(?:am|pm))?)\s+#)/i],["pln",/^(?:(?:[a-z]|_\w)\w*(?:\[[!#%&@]+])?|\[(?:[a-z]|_\w)\w*])/i],["pun",/^[^\w\t\n\r "'[\]\xa0\u2018\u2019\u201c\u201d\u2028\u2029]+/],["pun",/^(?:\[|])/]]),["vb","vbs"]);
+1 -1
mojo/lib/Mojolicious/public/mojo/prettify/lang-vhdl.js
... ...
@@ -1,3 +1,3 @@
1
-PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r �\xa0"]],[["str",/^(?:[box]?"(?:[^"]|"")*"|'.')/i],["com",/^--[^\n\r]*/],["kwd",/^(?:abs|access|after|alias|all|and|architecture|array|assert|attribute|begin|block|body|buffer|bus|case|component|configuration|constant|disconnect|downto|else|elsif|end|entity|exit|file|for|function|generate|generic|group|guarded|if|impure|in|inertial|inout|is|label|library|linkage|literal|loop|map|mod|nand|new|next|nor|not|null|of|on|open|or|others|out|package|port|postponed|procedure|process|pure|range|record|register|reject|rem|report|return|rol|ror|select|severity|shared|signal|sla|sll|sra|srl|subtype|then|to|transport|type|unaffected|units|until|use|variable|wait|when|while|with|xnor|xor)(?=[^\w-]|$)/i,
1
+PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r \u00a0"]],[["str",/^(?:[box]?"(?:[^"]|"")*"|'.')/i],["com",/^--[^\n\r]*/],["kwd",/^(?:abs|access|after|alias|all|and|architecture|array|assert|attribute|begin|block|body|buffer|bus|case|component|configuration|constant|disconnect|downto|else|elsif|end|entity|exit|file|for|function|generate|generic|group|guarded|if|impure|in|inertial|inout|is|label|library|linkage|literal|loop|map|mod|nand|new|next|nor|not|null|of|on|open|or|others|out|package|port|postponed|procedure|process|pure|range|record|register|reject|rem|report|return|rol|ror|select|severity|shared|signal|sla|sll|sra|srl|subtype|then|to|transport|type|unaffected|units|until|use|variable|wait|when|while|with|xnor|xor)(?=[^\w-]|$)/i,
2 2
 null],["typ",/^(?:bit|bit_vector|character|boolean|integer|real|time|string|severity_level|positive|natural|signed|unsigned|line|text|std_u?logic(?:_vector)?)(?=[^\w-]|$)/i,null],["typ",/^'(?:active|ascending|base|delayed|driving|driving_value|event|high|image|instance_name|last_active|last_event|last_value|left|leftof|length|low|path_name|pos|pred|quiet|range|reverse_range|right|rightof|simple_name|stable|succ|transaction|val|value)(?=[^\w-]|$)/i,null],["lit",/^\d+(?:_\d+)*(?:#[\w.\\]+#(?:[+-]?\d+(?:_\d+)*)?|(?:\.\d+(?:_\d+)*)?(?:e[+-]?\d+(?:_\d+)*)?)/i],
3 3
 ["pln",/^(?:[a-z]\w*|\\[^\\]*\\)/i],["pun",/^[^\w\t\n\r "'\xa0][^\w\t\n\r "'\xa0-]*/]]),["vhdl","vhd"]);
+1 -1
mojo/lib/Mojolicious/public/mojo/prettify/lang-wiki.js
... ...
@@ -1,2 +1,2 @@
1
-PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\d\t a-gi-z\xa0]+/,null,"\t �\xa0abcdefgijklmnopqrstuvwxyz0123456789"],["pun",/^[*=[\]^~]+/,null,"=*~^[]"]],[["lang-wiki.meta",/(?:^^|\r\n?|\n)(#[a-z]+)\b/],["lit",/^[A-Z][a-z][\da-z]+[A-Z][a-z][^\W_]+\b/],["lang-",/^{{{([\S\s]+?)}}}/],["lang-",/^`([^\n\r`]+)`/],["str",/^https?:\/\/[^\s#/?]*(?:\/[^\s#?]*)?(?:\?[^\s#]*)?(?:#\S*)?/i],["pln",/^(?:\r\n|[\S\s])[^\n\r#*=A-[^`h{~]*/]]),["wiki"]);
1
+PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\d\t a-gi-z\xa0]+/,null,"\t \u00a0abcdefgijklmnopqrstuvwxyz0123456789"],["pun",/^[*=[\]^~]+/,null,"=*~^[]"]],[["lang-wiki.meta",/(?:^^|\r\n?|\n)(#[a-z]+)\b/],["lit",/^[A-Z][a-z][\da-z]+[A-Z][a-z][^\W_]+\b/],["lang-",/^{{{([\S\s]+?)}}}/],["lang-",/^`([^\n\r`]+)`/],["str",/^https?:\/\/[^\s#/?]*(?:\/[^\s#?]*)?(?:\?[^\s#]*)?(?:#\S*)?/i],["pln",/^(?:\r\n|[\S\s])[^\n\r#*=A-[^`h{~]*/]]),["wiki"]);
2 2
 PR.registerLangHandler(PR.createSimpleLexer([["kwd",/^#[a-z]+/i,null,"#"]],[]),["wiki.meta"]);
+1 -1
mojo/lib/Mojolicious/public/mojo/prettify/prettify-mojo.css
... ...
@@ -1 +1 @@
1
-.str{color:#9daa7e}.kwd{color:#d5b57c}.com{color:#726d73}.typ{color:#dd7e5e}.lit{color:#fcf0a4}.pun,.opn,.clo{color:#a78353}.pln{color:#889dbc}.tag{color:#d5b57c}.atn{color:#dd7e5e}.atv{color:#9daa7e}.dec{color:#dd7e5e}
1
+.str{color:#9daa7e}.kwd{color:#d5b57c}.com{color:#726d73}.typ{color:#dd7e5e}.lit{color:#fcf0a4}.pun,.opn,.clo{color:#a78353}.pln{color:#889dbc}.tag{color:#d5b57c}.atn{color:#dd7e5e}.atv{color:#9daa7e}.dec{color:#dd7e5e}pre.prettyprint{border:0;padding-bottom:1.5em;padding-top:1.5em}
+30 -28
mojo/lib/Mojolicious/public/mojo/prettify/prettify.js
... ...
@@ -1,28 +1,30 @@
1
-var q=null;window.PR_SHOULD_USE_CONTINUATION=!0;
2
-(function(){function L(a){function m(a){var f=a.charCodeAt(0);if(f!==92)return f;var b=a.charAt(1);return(f=r[b])?f:"0"<=b&&b<="7"?parseInt(a.substring(1),8):b==="u"||b==="x"?parseInt(a.substring(2),16):a.charCodeAt(1)}function e(a){if(a<32)return(a<16?"\\x0":"\\x")+a.toString(16);a=String.fromCharCode(a);if(a==="\\"||a==="-"||a==="["||a==="]")a="\\"+a;return a}function h(a){for(var f=a.substring(1,a.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),a=
3
-[],b=[],o=f[0]==="^",c=o?1:0,i=f.length;c<i;++c){var j=f[c];if(/\\[bdsw]/i.test(j))a.push(j);else{var j=m(j),d;c+2<i&&"-"===f[c+1]?(d=m(f[c+2]),c+=2):d=j;b.push([j,d]);d<65||j>122||(d<65||j>90||b.push([Math.max(65,j)|32,Math.min(d,90)|32]),d<97||j>122||b.push([Math.max(97,j)&-33,Math.min(d,122)&-33]))}}b.sort(function(a,f){return a[0]-f[0]||f[1]-a[1]});f=[];j=[NaN,NaN];for(c=0;c<b.length;++c)i=b[c],i[0]<=j[1]+1?j[1]=Math.max(j[1],i[1]):f.push(j=i);b=["["];o&&b.push("^");b.push.apply(b,a);for(c=0;c<
4
-f.length;++c)i=f[c],b.push(e(i[0])),i[1]>i[0]&&(i[1]+1>i[0]&&b.push("-"),b.push(e(i[1])));b.push("]");return b.join("")}function y(a){for(var f=a.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),b=f.length,d=[],c=0,i=0;c<b;++c){var j=f[c];j==="("?++i:"\\"===j.charAt(0)&&(j=+j.substring(1))&&j<=i&&(d[j]=-1)}for(c=1;c<d.length;++c)-1===d[c]&&(d[c]=++t);for(i=c=0;c<b;++c)j=f[c],j==="("?(++i,d[i]===void 0&&(f[c]="(?:")):"\\"===j.charAt(0)&&
5
-(j=+j.substring(1))&&j<=i&&(f[c]="\\"+d[i]);for(i=c=0;c<b;++c)"^"===f[c]&&"^"!==f[c+1]&&(f[c]="");if(a.ignoreCase&&s)for(c=0;c<b;++c)j=f[c],a=j.charAt(0),j.length>=2&&a==="["?f[c]=h(j):a!=="\\"&&(f[c]=j.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return f.join("")}for(var t=0,s=!1,l=!1,p=0,d=a.length;p<d;++p){var g=a[p];if(g.ignoreCase)l=!0;else if(/[a-z]/i.test(g.source.replace(/\\u[\da-f]{4}|\\x[\da-f]{2}|\\[^UXux]/gi,""))){s=!0;l=!1;break}}for(var r=
6
-{b:8,t:9,n:10,v:11,f:12,r:13},n=[],p=0,d=a.length;p<d;++p){g=a[p];if(g.global||g.multiline)throw Error(""+g);n.push("(?:"+y(g)+")")}return RegExp(n.join("|"),l?"gi":"g")}function M(a){function m(a){switch(a.nodeType){case 1:if(e.test(a.className))break;for(var g=a.firstChild;g;g=g.nextSibling)m(g);g=a.nodeName;if("BR"===g||"LI"===g)h[s]="\n",t[s<<1]=y++,t[s++<<1|1]=a;break;case 3:case 4:g=a.nodeValue,g.length&&(g=p?g.replace(/\r\n?/g,"\n"):g.replace(/[\t\n\r ]+/g," "),h[s]=g,t[s<<1]=y,y+=g.length,
7
-t[s++<<1|1]=a)}}var e=/(?:^|\s)nocode(?:\s|$)/,h=[],y=0,t=[],s=0,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=document.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);m(a);return{a:h.join("").replace(/\n$/,""),c:t}}function B(a,m,e,h){m&&(a={a:m,d:a},e(a),h.push.apply(h,a.e))}function x(a,m){function e(a){for(var l=a.d,p=[l,"pln"],d=0,g=a.a.match(y)||[],r={},n=0,z=g.length;n<z;++n){var f=g[n],b=r[f],o=void 0,c;if(typeof b===
8
-"string")c=!1;else{var i=h[f.charAt(0)];if(i)o=f.match(i[1]),b=i[0];else{for(c=0;c<t;++c)if(i=m[c],o=f.match(i[1])){b=i[0];break}o||(b="pln")}if((c=b.length>=5&&"lang-"===b.substring(0,5))&&!(o&&typeof o[1]==="string"))c=!1,b="src";c||(r[f]=b)}i=d;d+=f.length;if(c){c=o[1];var j=f.indexOf(c),k=j+c.length;o[2]&&(k=f.length-o[2].length,j=k-c.length);b=b.substring(5);B(l+i,f.substring(0,j),e,p);B(l+i+j,c,C(b,c),p);B(l+i+k,f.substring(k),e,p)}else p.push(l+i,b)}a.e=p}var h={},y;(function(){for(var e=a.concat(m),
9
-l=[],p={},d=0,g=e.length;d<g;++d){var r=e[d],n=r[3];if(n)for(var k=n.length;--k>=0;)h[n.charAt(k)]=r;r=r[1];n=""+r;p.hasOwnProperty(n)||(l.push(r),p[n]=q)}l.push(/[\S\s]/);y=L(l)})();var t=m.length;return e}function u(a){var m=[],e=[];a.tripleQuotedStrings?m.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,q,"'\""]):a.multiLineStrings?m.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/,
10
-q,"'\"`"]):m.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,q,"\"'"]);a.verbatimStrings&&e.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,q]);var h=a.hashComments;h&&(a.cStyleComments?(h>1?m.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,q,"#"]):m.push(["com",/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/,q,"#"]),e.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,q])):m.push(["com",/^#[^\n\r]*/,
11
-q,"#"]));a.cStyleComments&&(e.push(["com",/^\/\/[^\n\r]*/,q]),e.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,q]));a.regexLiterals&&e.push(["lang-regex",/^(?:^^\.?|[!+-]|!=|!==|#|%|%=|&|&&|&&=|&=|\(|\*|\*=|\+=|,|-=|->|\/|\/=|:|::|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|[?@[^]|\^=|\^\^|\^\^=|{|\||\|=|\|\||\|\|=|~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/]);(h=a.types)&&e.push(["typ",h]);a=(""+a.keywords).replace(/^ | $/g,
12
-"");a.length&&e.push(["kwd",RegExp("^(?:"+a.replace(/[\s,]+/g,"|")+")\\b"),q]);m.push(["pln",/^\s+/,q," \r\n\t\xa0"]);e.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/,q],["pun",/^.[^\s\w"-$'./@\\`]*/,q]);return x(m,e)}function D(a,m){function e(a){switch(a.nodeType){case 1:if(k.test(a.className))break;if("BR"===a.nodeName)h(a),
13
-a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)e(a);break;case 3:case 4:if(p){var b=a.nodeValue,d=b.match(t);if(d){var c=b.substring(0,d.index);a.nodeValue=c;(b=b.substring(d.index+d[0].length))&&a.parentNode.insertBefore(s.createTextNode(b),a.nextSibling);h(a);c||a.parentNode.removeChild(a)}}}}function h(a){function b(a,d){var e=d?a.cloneNode(!1):a,f=a.parentNode;if(f){var f=b(f,1),g=a.nextSibling;f.appendChild(e);for(var h=g;h;h=g)g=h.nextSibling,f.appendChild(h)}return e}
14
-for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),e;(e=a.parentNode)&&e.nodeType===1;)a=e;d.push(a)}var k=/(?:^|\s)nocode(?:\s|$)/,t=/\r\n?|\n/,s=a.ownerDocument,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=s.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);for(l=s.createElement("LI");a.firstChild;)l.appendChild(a.firstChild);for(var d=[l],g=0;g<d.length;++g)e(d[g]);m===(m|0)&&d[0].setAttribute("value",
15
-m);var r=s.createElement("OL");r.className="linenums";for(var n=Math.max(0,m-1|0)||0,g=0,z=d.length;g<z;++g)l=d[g],l.className="L"+(g+n)%10,l.firstChild||l.appendChild(s.createTextNode("\xa0")),r.appendChild(l);a.appendChild(r)}function k(a,m){for(var e=m.length;--e>=0;){var h=m[e];A.hasOwnProperty(h)?window.console&&console.warn("cannot override language handler %s",h):A[h]=a}}function C(a,m){if(!a||!A.hasOwnProperty(a))a=/^\s*</.test(m)?"default-markup":"default-code";return A[a]}function E(a){var m=
16
-a.g;try{var e=M(a.h),h=e.a;a.a=h;a.c=e.c;a.d=0;C(m,h)(a);var k=/\bMSIE\b/.test(navigator.userAgent),m=/\n/g,t=a.a,s=t.length,e=0,l=a.c,p=l.length,h=0,d=a.e,g=d.length,a=0;d[g]=s;var r,n;for(n=r=0;n<g;)d[n]!==d[n+2]?(d[r++]=d[n++],d[r++]=d[n++]):n+=2;g=r;for(n=r=0;n<g;){for(var z=d[n],f=d[n+1],b=n+2;b+2<=g&&d[b+1]===f;)b+=2;d[r++]=z;d[r++]=f;n=b}for(d.length=r;h<p;){var o=l[h+2]||s,c=d[a+2]||s,b=Math.min(o,c),i=l[h+1],j;if(i.nodeType!==1&&(j=t.substring(e,b))){k&&(j=j.replace(m,"\r"));i.nodeValue=
17
-j;var u=i.ownerDocument,v=u.createElement("SPAN");v.className=d[a+1];var x=i.parentNode;x.replaceChild(v,i);v.appendChild(i);e<o&&(l[h+1]=i=u.createTextNode(t.substring(b,o)),x.insertBefore(i,v.nextSibling))}e=b;e>=o&&(h+=2);e>=c&&(a+=2)}}catch(w){"console"in window&&console.log(w&&w.stack?w.stack:w)}}var v=["break,continue,do,else,for,if,return,while"],w=[[v,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"],
18
-"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],F=[w,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],G=[w,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"],
19
-H=[G,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"],w=[w,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],I=[v,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"],
20
-J=[v,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],v=[v,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],K=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/,N=/\S/,O=u({keywords:[F,H,w,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END"+
21
-I,J,v],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),A={};k(O,["default-code"]);k(x([],[["pln",/^[^<?]+/],["dec",/^<!\w[^>]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",/^<xmp\b[^>]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^<script\b[^>]*>([\S\s]*?)(<\/script\b[^>]*>)/i],["lang-css",/^<style\b[^>]*>([\S\s]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),
22
-["default-markup","htm","html","mxml","xhtml","xml","xsl"]);k(x([["pln",/^\s+/,q," \t\r\n"],["atv",/^(?:"[^"]*"?|'[^']*'?)/,q,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/],["pun",/^[/<->]+/],["lang-js",/^on\w+\s*=\s*"([^"]+)"/i],["lang-js",/^on\w+\s*=\s*'([^']+)'/i],["lang-js",/^on\w+\s*=\s*([^\s"'>]+)/i],["lang-css",/^style\s*=\s*"([^"]+)"/i],["lang-css",/^style\s*=\s*'([^']+)'/i],["lang-css",
23
-/^style\s*=\s*([^\s"'>]+)/i]]),["in.tag"]);k(x([],[["atv",/^[\S\s]+/]]),["uq.val"]);k(u({keywords:F,hashComments:!0,cStyleComments:!0,types:K}),["c","cc","cpp","cxx","cyc","m"]);k(u({keywords:"null,true,false"}),["json"]);k(u({keywords:H,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:K}),["cs"]);k(u({keywords:G,cStyleComments:!0}),["java"]);k(u({keywords:v,hashComments:!0,multiLineStrings:!0}),["bsh","csh","sh"]);k(u({keywords:I,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}),
24
-["cv","py"]);k(u({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["perl","pl","pm"]);k(u({keywords:J,hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb"]);k(u({keywords:w,cStyleComments:!0,regexLiterals:!0}),["js"]);k(u({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes",
25
-hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);k(x([],[["str",/^[\S\s]+/]]),["regex"]);window.prettyPrintOne=function(a,m,e){var h=document.createElement("PRE");h.innerHTML=a;e&&D(h,e);E({g:m,i:e,h:h});return h.innerHTML};window.prettyPrint=function(a){function m(){for(var e=window.PR_SHOULD_USE_CONTINUATION?l.now()+250:Infinity;p<h.length&&l.now()<e;p++){var n=h[p],k=n.className;if(k.indexOf("prettyprint")>=0){var k=k.match(g),f,b;if(b=
26
-!k){b=n;for(var o=void 0,c=b.firstChild;c;c=c.nextSibling)var i=c.nodeType,o=i===1?o?b:c:i===3?N.test(c.nodeValue)?b:o:o;b=(f=o===b?void 0:o)&&"CODE"===f.tagName}b&&(k=f.className.match(g));k&&(k=k[1]);b=!1;for(o=n.parentNode;o;o=o.parentNode)if((o.tagName==="pre"||o.tagName==="code"||o.tagName==="xmp")&&o.className&&o.className.indexOf("prettyprint")>=0){b=!0;break}b||((b=(b=n.className.match(/\blinenums\b(?::(\d+))?/))?b[1]&&b[1].length?+b[1]:!0:!1)&&D(n,b),d={g:k,h:n,i:b},E(d))}}p<h.length?setTimeout(m,
27
-250):a&&a()}for(var e=[document.getElementsByTagName("pre"),document.getElementsByTagName("code"),document.getElementsByTagName("xmp")],h=[],k=0;k<e.length;++k)for(var t=0,s=e[k].length;t<s;++t)h.push(e[k][t]);var e=q,l=Date;l.now||(l={now:function(){return+new Date}});var p=0,d,g=/\blang(?:uage)?-([\w.]+)(?!\S)/;m()};window.PR={createSimpleLexer:x,registerLangHandler:k,sourceDecorator:u,PR_ATTRIB_NAME:"atn",PR_ATTRIB_VALUE:"atv",PR_COMMENT:"com",PR_DECLARATION:"dec",PR_KEYWORD:"kwd",PR_LITERAL:"lit",
28
-PR_NOCODE:"nocode",PR_PLAIN:"pln",PR_PUNCTUATION:"pun",PR_SOURCE:"src",PR_STRING:"str",PR_TAG:"tag",PR_TYPE:"typ"}})();
1
+!function(){var q=null;window.PR_SHOULD_USE_CONTINUATION=!0;
2
+(function(){function S(a){function d(e){var b=e.charCodeAt(0);if(b!==92)return b;var a=e.charAt(1);return(b=r[a])?b:"0"<=a&&a<="7"?parseInt(e.substring(1),8):a==="u"||a==="x"?parseInt(e.substring(2),16):e.charCodeAt(1)}function g(e){if(e<32)return(e<16?"\\x0":"\\x")+e.toString(16);e=String.fromCharCode(e);return e==="\\"||e==="-"||e==="]"||e==="^"?"\\"+e:e}function b(e){var b=e.substring(1,e.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),e=[],a=
3
+b[0]==="^",c=["["];a&&c.push("^");for(var a=a?1:0,f=b.length;a<f;++a){var h=b[a];if(/\\[bdsw]/i.test(h))c.push(h);else{var h=d(h),l;a+2<f&&"-"===b[a+1]?(l=d(b[a+2]),a+=2):l=h;e.push([h,l]);l<65||h>122||(l<65||h>90||e.push([Math.max(65,h)|32,Math.min(l,90)|32]),l<97||h>122||e.push([Math.max(97,h)&-33,Math.min(l,122)&-33]))}}e.sort(function(e,a){return e[0]-a[0]||a[1]-e[1]});b=[];f=[];for(a=0;a<e.length;++a)h=e[a],h[0]<=f[1]+1?f[1]=Math.max(f[1],h[1]):b.push(f=h);for(a=0;a<b.length;++a)h=b[a],c.push(g(h[0])),
4
+h[1]>h[0]&&(h[1]+1>h[0]&&c.push("-"),c.push(g(h[1])));c.push("]");return c.join("")}function s(e){for(var a=e.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),c=a.length,d=[],f=0,h=0;f<c;++f){var l=a[f];l==="("?++h:"\\"===l.charAt(0)&&(l=+l.substring(1))&&(l<=h?d[l]=-1:a[f]=g(l))}for(f=1;f<d.length;++f)-1===d[f]&&(d[f]=++x);for(h=f=0;f<c;++f)l=a[f],l==="("?(++h,d[h]||(a[f]="(?:")):"\\"===l.charAt(0)&&(l=+l.substring(1))&&l<=h&&
5
+(a[f]="\\"+d[l]);for(f=0;f<c;++f)"^"===a[f]&&"^"!==a[f+1]&&(a[f]="");if(e.ignoreCase&&m)for(f=0;f<c;++f)l=a[f],e=l.charAt(0),l.length>=2&&e==="["?a[f]=b(l):e!=="\\"&&(a[f]=l.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return a.join("")}for(var x=0,m=!1,j=!1,k=0,c=a.length;k<c;++k){var i=a[k];if(i.ignoreCase)j=!0;else if(/[a-z]/i.test(i.source.replace(/\\u[\da-f]{4}|\\x[\da-f]{2}|\\[^UXux]/gi,""))){m=!0;j=!1;break}}for(var r={b:8,t:9,n:10,v:11,
6
+f:12,r:13},n=[],k=0,c=a.length;k<c;++k){i=a[k];if(i.global||i.multiline)throw Error(""+i);n.push("(?:"+s(i)+")")}return RegExp(n.join("|"),j?"gi":"g")}function T(a,d){function g(a){var c=a.nodeType;if(c==1){if(!b.test(a.className)){for(c=a.firstChild;c;c=c.nextSibling)g(c);c=a.nodeName.toLowerCase();if("br"===c||"li"===c)s[j]="\n",m[j<<1]=x++,m[j++<<1|1]=a}}else if(c==3||c==4)c=a.nodeValue,c.length&&(c=d?c.replace(/\r\n?/g,"\n"):c.replace(/[\t\n\r ]+/g," "),s[j]=c,m[j<<1]=x,x+=c.length,m[j++<<1|1]=
7
+a)}var b=/(?:^|\s)nocode(?:\s|$)/,s=[],x=0,m=[],j=0;g(a);return{a:s.join("").replace(/\n$/,""),d:m}}function H(a,d,g,b){d&&(a={a:d,e:a},g(a),b.push.apply(b,a.g))}function U(a){for(var d=void 0,g=a.firstChild;g;g=g.nextSibling)var b=g.nodeType,d=b===1?d?a:g:b===3?V.test(g.nodeValue)?a:d:d;return d===a?void 0:d}function C(a,d){function g(a){for(var j=a.e,k=[j,"pln"],c=0,i=a.a.match(s)||[],r={},n=0,e=i.length;n<e;++n){var z=i[n],w=r[z],t=void 0,f;if(typeof w==="string")f=!1;else{var h=b[z.charAt(0)];
8
+if(h)t=z.match(h[1]),w=h[0];else{for(f=0;f<x;++f)if(h=d[f],t=z.match(h[1])){w=h[0];break}t||(w="pln")}if((f=w.length>=5&&"lang-"===w.substring(0,5))&&!(t&&typeof t[1]==="string"))f=!1,w="src";f||(r[z]=w)}h=c;c+=z.length;if(f){f=t[1];var l=z.indexOf(f),B=l+f.length;t[2]&&(B=z.length-t[2].length,l=B-f.length);w=w.substring(5);H(j+h,z.substring(0,l),g,k);H(j+h+l,f,I(w,f),k);H(j+h+B,z.substring(B),g,k)}else k.push(j+h,w)}a.g=k}var b={},s;(function(){for(var g=a.concat(d),j=[],k={},c=0,i=g.length;c<i;++c){var r=
9
+g[c],n=r[3];if(n)for(var e=n.length;--e>=0;)b[n.charAt(e)]=r;r=r[1];n=""+r;k.hasOwnProperty(n)||(j.push(r),k[n]=q)}j.push(/[\S\s]/);s=S(j)})();var x=d.length;return g}function v(a){var d=[],g=[];a.tripleQuotedStrings?d.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,q,"'\""]):a.multiLineStrings?d.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/,
10
+q,"'\"`"]):d.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,q,"\"'"]);a.verbatimStrings&&g.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,q]);var b=a.hashComments;b&&(a.cStyleComments?(b>1?d.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,q,"#"]):d.push(["com",/^#(?:(?:define|e(?:l|nd)if|else|error|ifn?def|include|line|pragma|undef|warning)\b|[^\n\r]*)/,q,"#"]),g.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h(?:h|pp|\+\+)?|[a-z]\w*)>/,q])):d.push(["com",
11
+/^#[^\n\r]*/,q,"#"]));a.cStyleComments&&(g.push(["com",/^\/\/[^\n\r]*/,q]),g.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,q]));if(b=a.regexLiterals){var s=(b=b>1?"":"\n\r")?".":"[\\S\\s]";g.push(["lang-regex",RegExp("^(?:^^\\.?|[+-]|[!=]=?=?|\\#|%=?|&&?=?|\\(|\\*=?|[+\\-]=|->|\\/=?|::?|<<?=?|>>?>?=?|,|;|\\?|@|\\[|~|{|\\^\\^?=?|\\|\\|?=?|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*("+("/(?=[^/*"+b+"])(?:[^/\\x5B\\x5C"+b+"]|\\x5C"+s+"|\\x5B(?:[^\\x5C\\x5D"+b+"]|\\x5C"+
12
+s+")*(?:\\x5D|$))+/")+")")])}(b=a.types)&&g.push(["typ",b]);b=(""+a.keywords).replace(/^ | $/g,"");b.length&&g.push(["kwd",RegExp("^(?:"+b.replace(/[\s,]+/g,"|")+")\\b"),q]);d.push(["pln",/^\s+/,q," \r\n\t\u00a0"]);b="^.[^\\s\\w.$@'\"`/\\\\]*";a.regexLiterals&&(b+="(?!s*/)");g.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/,
13
+q],["pun",RegExp(b),q]);return C(d,g)}function J(a,d,g){function b(a){var c=a.nodeType;if(c==1&&!x.test(a.className))if("br"===a.nodeName)s(a),a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)b(a);else if((c==3||c==4)&&g){var d=a.nodeValue,i=d.match(m);if(i)c=d.substring(0,i.index),a.nodeValue=c,(d=d.substring(i.index+i[0].length))&&a.parentNode.insertBefore(j.createTextNode(d),a.nextSibling),s(a),c||a.parentNode.removeChild(a)}}function s(a){function b(a,c){var d=
14
+c?a.cloneNode(!1):a,e=a.parentNode;if(e){var e=b(e,1),g=a.nextSibling;e.appendChild(d);for(var i=g;i;i=g)g=i.nextSibling,e.appendChild(i)}return d}for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),d;(d=a.parentNode)&&d.nodeType===1;)a=d;c.push(a)}for(var x=/(?:^|\s)nocode(?:\s|$)/,m=/\r\n?|\n/,j=a.ownerDocument,k=j.createElement("li");a.firstChild;)k.appendChild(a.firstChild);for(var c=[k],i=0;i<c.length;++i)b(c[i]);d===(d|0)&&c[0].setAttribute("value",d);var r=j.createElement("ol");
15
+r.className="linenums";for(var d=Math.max(0,d-1|0)||0,i=0,n=c.length;i<n;++i)k=c[i],k.className="L"+(i+d)%10,k.firstChild||k.appendChild(j.createTextNode("\u00a0")),r.appendChild(k);a.appendChild(r)}function p(a,d){for(var g=d.length;--g>=0;){var b=d[g];F.hasOwnProperty(b)?D.console&&console.warn("cannot override language handler %s",b):F[b]=a}}function I(a,d){if(!a||!F.hasOwnProperty(a))a=/^\s*</.test(d)?"default-markup":"default-code";return F[a]}function K(a){var d=a.h;try{var g=T(a.c,a.i),b=g.a;
16
+a.a=b;a.d=g.d;a.e=0;I(d,b)(a);var s=/\bMSIE\s(\d+)/.exec(navigator.userAgent),s=s&&+s[1]<=8,d=/\n/g,x=a.a,m=x.length,g=0,j=a.d,k=j.length,b=0,c=a.g,i=c.length,r=0;c[i]=m;var n,e;for(e=n=0;e<i;)c[e]!==c[e+2]?(c[n++]=c[e++],c[n++]=c[e++]):e+=2;i=n;for(e=n=0;e<i;){for(var p=c[e],w=c[e+1],t=e+2;t+2<=i&&c[t+1]===w;)t+=2;c[n++]=p;c[n++]=w;e=t}c.length=n;var f=a.c,h;if(f)h=f.style.display,f.style.display="none";try{for(;b<k;){var l=j[b+2]||m,B=c[r+2]||m,t=Math.min(l,B),A=j[b+1],G;if(A.nodeType!==1&&(G=x.substring(g,
17
+t))){s&&(G=G.replace(d,"\r"));A.nodeValue=G;var L=A.ownerDocument,o=L.createElement("span");o.className=c[r+1];var v=A.parentNode;v.replaceChild(o,A);o.appendChild(A);g<l&&(j[b+1]=A=L.createTextNode(x.substring(t,l)),v.insertBefore(A,o.nextSibling))}g=t;g>=l&&(b+=2);g>=B&&(r+=2)}}finally{if(f)f.style.display=h}}catch(u){D.console&&console.log(u&&u.stack||u)}}var D=window,y=["break,continue,do,else,for,if,return,while"],E=[[y,"auto,case,char,const,default,double,enum,extern,float,goto,inline,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"],
18
+"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],M=[E,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,delegate,dynamic_cast,explicit,export,friend,generic,late_check,mutable,namespace,nullptr,property,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],N=[E,"abstract,assert,boolean,byte,extends,final,finally,implements,import,instanceof,interface,null,native,package,strictfp,super,synchronized,throws,transient"],
19
+O=[N,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,internal,into,is,let,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var,virtual,where"],E=[E,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],P=[y,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"],
20
+Q=[y,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],W=[y,"as,assert,const,copy,drop,enum,extern,fail,false,fn,impl,let,log,loop,match,mod,move,mut,priv,pub,pure,ref,self,static,struct,true,trait,type,unsafe,use"],y=[y,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],R=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)\b/,
21
+V=/\S/,X=v({keywords:[M,O,E,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",P,Q,y],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),F={};p(X,["default-code"]);p(C([],[["pln",/^[^<?]+/],["dec",/^<!\w[^>]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",
22
+/^<xmp\b[^>]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^<script\b[^>]*>([\S\s]*?)(<\/script\b[^>]*>)/i],["lang-css",/^<style\b[^>]*>([\S\s]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),["default-markup","htm","html","mxml","xhtml","xml","xsl"]);p(C([["pln",/^\s+/,q," \t\r\n"],["atv",/^(?:"[^"]*"?|'[^']*'?)/,q,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/],["pun",/^[/<->]+/],
23
+["lang-js",/^on\w+\s*=\s*"([^"]+)"/i],["lang-js",/^on\w+\s*=\s*'([^']+)'/i],["lang-js",/^on\w+\s*=\s*([^\s"'>]+)/i],["lang-css",/^style\s*=\s*"([^"]+)"/i],["lang-css",/^style\s*=\s*'([^']+)'/i],["lang-css",/^style\s*=\s*([^\s"'>]+)/i]]),["in.tag"]);p(C([],[["atv",/^[\S\s]+/]]),["uq.val"]);p(v({keywords:M,hashComments:!0,cStyleComments:!0,types:R}),["c","cc","cpp","cxx","cyc","m"]);p(v({keywords:"null,true,false"}),["json"]);p(v({keywords:O,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:R}),
24
+["cs"]);p(v({keywords:N,cStyleComments:!0}),["java"]);p(v({keywords:y,hashComments:!0,multiLineStrings:!0}),["bash","bsh","csh","sh"]);p(v({keywords:P,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}),["cv","py","python"]);p(v({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:!0,multiLineStrings:!0,regexLiterals:2}),["perl","pl","pm"]);p(v({keywords:Q,
25
+hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb","ruby"]);p(v({keywords:E,cStyleComments:!0,regexLiterals:!0}),["javascript","js"]);p(v({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,throw,true,try,unless,until,when,while,yes",hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);p(v({keywords:W,cStyleComments:!0,multilineStrings:!0}),["rc","rs","rust"]);
26
+p(C([],[["str",/^[\S\s]+/]]),["regex"]);var Y=D.PR={createSimpleLexer:C,registerLangHandler:p,sourceDecorator:v,PR_ATTRIB_NAME:"atn",PR_ATTRIB_VALUE:"atv",PR_COMMENT:"com",PR_DECLARATION:"dec",PR_KEYWORD:"kwd",PR_LITERAL:"lit",PR_NOCODE:"nocode",PR_PLAIN:"pln",PR_PUNCTUATION:"pun",PR_SOURCE:"src",PR_STRING:"str",PR_TAG:"tag",PR_TYPE:"typ",prettyPrintOne:D.prettyPrintOne=function(a,d,g){var b=document.createElement("div");b.innerHTML="<pre>"+a+"</pre>";b=b.firstChild;g&&J(b,g,!0);K({h:d,j:g,c:b,i:1});
27
+return b.innerHTML},prettyPrint:D.prettyPrint=function(a,d){function g(){for(var b=D.PR_SHOULD_USE_CONTINUATION?c.now()+250:Infinity;i<p.length&&c.now()<b;i++){for(var d=p[i],j=h,k=d;k=k.previousSibling;){var m=k.nodeType,o=(m===7||m===8)&&k.nodeValue;if(o?!/^\??prettify\b/.test(o):m!==3||/\S/.test(k.nodeValue))break;if(o){j={};o.replace(/\b(\w+)=([\w%+\-.:]+)/g,function(a,b,c){j[b]=c});break}}k=d.className;if((j!==h||e.test(k))&&!v.test(k)){m=!1;for(o=d.parentNode;o;o=o.parentNode)if(f.test(o.tagName)&&
28
+o.className&&e.test(o.className)){m=!0;break}if(!m){d.className+=" prettyprinted";m=j.lang;if(!m){var m=k.match(n),y;if(!m&&(y=U(d))&&t.test(y.tagName))m=y.className.match(n);m&&(m=m[1])}if(w.test(d.tagName))o=1;else var o=d.currentStyle,u=s.defaultView,o=(o=o?o.whiteSpace:u&&u.getComputedStyle?u.getComputedStyle(d,q).getPropertyValue("white-space"):0)&&"pre"===o.substring(0,3);u=j.linenums;if(!(u=u==="true"||+u))u=(u=k.match(/\blinenums\b(?::(\d+))?/))?u[1]&&u[1].length?+u[1]:!0:!1;u&&J(d,u,o);r=
29
+{h:m,c:d,j:u,i:o};K(r)}}}i<p.length?setTimeout(g,250):"function"===typeof a&&a()}for(var b=d||document.body,s=b.ownerDocument||document,b=[b.getElementsByTagName("pre"),b.getElementsByTagName("code"),b.getElementsByTagName("xmp")],p=[],m=0;m<b.length;++m)for(var j=0,k=b[m].length;j<k;++j)p.push(b[m][j]);var b=q,c=Date;c.now||(c={now:function(){return+new Date}});var i=0,r,n=/\blang(?:uage)?-([\w.]+)(?!\S)/,e=/\bprettyprint\b/,v=/\bprettyprinted\b/,w=/pre|xmp/i,t=/^code$/i,f=/^(?:pre|code|xmp)$/i,
30
+h={};g()}};typeof define==="function"&&define.amd&&define("google-code-prettify",[],function(){return Y})})();}()
+34
mojo/lib/Mojolicious/public/mojo/prettify/run_prettify.js
... ...
@@ -0,0 +1,34 @@
1
+!function(){var r=null;
2
+(function(){function X(e){function j(){try{J.doScroll("left")}catch(e){P(j,50);return}w("poll")}function w(j){if(!(j.type=="readystatechange"&&x.readyState!="complete")&&((j.type=="load"?n:x)[z](i+j.type,w,!1),!m&&(m=!0)))e.call(n,j.type||j)}var Y=x.addEventListener,m=!1,C=!0,t=Y?"addEventListener":"attachEvent",z=Y?"removeEventListener":"detachEvent",i=Y?"":"on";if(x.readyState=="complete")e.call(n,"lazy");else{if(x.createEventObject&&J.doScroll){try{C=!n.frameElement}catch(A){}C&&j()}x[t](i+"DOMContentLoaded",
3
+w,!1);x[t](i+"readystatechange",w,!1);n[t](i+"load",w,!1)}}function Q(){S&&X(function(){var e=K.length;$(e?function(){for(var j=0;j<e;++j)(function(e){P(function(){n.exports[K[e]].apply(n,arguments)},0)})(j)}:void 0)})}for(var n=window,P=n.setTimeout,x=document,J=x.documentElement,L=x.head||x.getElementsByTagName("head")[0]||J,z="",A=x.scripts,m=A.length;--m>=0;){var M=A[m],T=M.src.match(/^[^#?]*\/run_prettify\.js(\?[^#]*)?(?:#.*)?$/);if(T){z=T[1]||"";M.parentNode.removeChild(M);break}}var S=!0,D=
4
+[],N=[],K=[];z.replace(/[&?]([^&=]+)=([^&]+)/g,function(e,j,w){w=decodeURIComponent(w);j=decodeURIComponent(j);j=="autorun"?S=!/^[0fn]/i.test(w):j=="lang"?D.push(w):j=="skin"?N.push(w):j=="callback"&&K.push(w)});m=0;for(z=D.length;m<z;++m)(function(){var e=x.createElement("script");e.onload=e.onerror=e.onreadystatechange=function(){if(e&&(!e.readyState||/loaded|complete/.test(e.readyState)))e.onerror=e.onload=e.onreadystatechange=r,--R,R||P(Q,0),e.parentNode&&e.parentNode.removeChild(e),e=r};e.type=
5
+"text/javascript";e.src="https://google-code-prettify.googlecode.com/svn/loader/lang-"+encodeURIComponent(D[m])+".js";L.insertBefore(e,L.firstChild)})(D[m]);for(var R=D.length,A=[],m=0,z=N.length;m<z;++m)A.push("https://google-code-prettify.googlecode.com/svn/loader/skins/"+encodeURIComponent(N[m])+".css");A.push("https://google-code-prettify.googlecode.com/svn/loader/prettify.css");(function(e){function j(m){if(m!==w){var n=x.createElement("link");n.rel="stylesheet";n.type="text/css";if(m+1<w)n.error=
6
+n.onerror=function(){j(m+1)};n.href=e[m];L.appendChild(n)}}var w=e.length;j(0)})(A);var $=function(){window.PR_SHOULD_USE_CONTINUATION=!0;var e;(function(){function j(a){function d(f){var b=f.charCodeAt(0);if(b!==92)return b;var a=f.charAt(1);return(b=i[a])?b:"0"<=a&&a<="7"?parseInt(f.substring(1),8):a==="u"||a==="x"?parseInt(f.substring(2),16):f.charCodeAt(1)}function h(f){if(f<32)return(f<16?"\\x0":"\\x")+f.toString(16);f=String.fromCharCode(f);return f==="\\"||f==="-"||f==="]"||f==="^"?"\\"+f:
7
+f}function b(f){var b=f.substring(1,f.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),f=[],a=b[0]==="^",c=["["];a&&c.push("^");for(var a=a?1:0,g=b.length;a<g;++a){var k=b[a];if(/\\[bdsw]/i.test(k))c.push(k);else{var k=d(k),o;a+2<g&&"-"===b[a+1]?(o=d(b[a+2]),a+=2):o=k;f.push([k,o]);o<65||k>122||(o<65||k>90||f.push([Math.max(65,k)|32,Math.min(o,90)|32]),o<97||k>122||f.push([Math.max(97,k)&-33,Math.min(o,122)&-33]))}}f.sort(function(f,a){return f[0]-
8
+a[0]||a[1]-f[1]});b=[];g=[];for(a=0;a<f.length;++a)k=f[a],k[0]<=g[1]+1?g[1]=Math.max(g[1],k[1]):b.push(g=k);for(a=0;a<b.length;++a)k=b[a],c.push(h(k[0])),k[1]>k[0]&&(k[1]+1>k[0]&&c.push("-"),c.push(h(k[1])));c.push("]");return c.join("")}function e(f){for(var a=f.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),c=a.length,d=[],g=0,k=0;g<c;++g){var o=a[g];o==="("?++k:"\\"===o.charAt(0)&&(o=+o.substring(1))&&(o<=k?d[o]=-1:a[g]=h(o))}for(g=
9
+1;g<d.length;++g)-1===d[g]&&(d[g]=++j);for(k=g=0;g<c;++g)o=a[g],o==="("?(++k,d[k]||(a[g]="(?:")):"\\"===o.charAt(0)&&(o=+o.substring(1))&&o<=k&&(a[g]="\\"+d[o]);for(g=0;g<c;++g)"^"===a[g]&&"^"!==a[g+1]&&(a[g]="");if(f.ignoreCase&&F)for(g=0;g<c;++g)o=a[g],f=o.charAt(0),o.length>=2&&f==="["?a[g]=b(o):f!=="\\"&&(a[g]=o.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return a.join("")}for(var j=0,F=!1,l=!1,I=0,c=a.length;I<c;++I){var p=a[I];if(p.ignoreCase)l=
10
+!0;else if(/[a-z]/i.test(p.source.replace(/\\u[\da-f]{4}|\\x[\da-f]{2}|\\[^UXux]/gi,""))){F=!0;l=!1;break}}for(var i={b:8,t:9,n:10,v:11,f:12,r:13},q=[],I=0,c=a.length;I<c;++I){p=a[I];if(p.global||p.multiline)throw Error(""+p);q.push("(?:"+e(p)+")")}return RegExp(q.join("|"),l?"gi":"g")}function m(a,d){function h(a){var c=a.nodeType;if(c==1){if(!b.test(a.className)){for(c=a.firstChild;c;c=c.nextSibling)h(c);c=a.nodeName.toLowerCase();if("br"===c||"li"===c)e[l]="\n",F[l<<1]=j++,F[l++<<1|1]=a}}else if(c==
11
+3||c==4)c=a.nodeValue,c.length&&(c=d?c.replace(/\r\n?/g,"\n"):c.replace(/[\t\n\r ]+/g," "),e[l]=c,F[l<<1]=j,j+=c.length,F[l++<<1|1]=a)}var b=/(?:^|\s)nocode(?:\s|$)/,e=[],j=0,F=[],l=0;h(a);return{a:e.join("").replace(/\n$/,""),d:F}}function n(a,d,h,b){d&&(a={a:d,e:a},h(a),b.push.apply(b,a.g))}function x(a){for(var d=void 0,h=a.firstChild;h;h=h.nextSibling)var b=h.nodeType,d=b===1?d?a:h:b===3?S.test(h.nodeValue)?a:d:d;return d===a?void 0:d}function C(a,d){function h(a){for(var l=a.e,j=[l,"pln"],c=
12
+0,p=a.a.match(e)||[],m={},q=0,f=p.length;q<f;++q){var B=p[q],y=m[B],u=void 0,g;if(typeof y==="string")g=!1;else{var k=b[B.charAt(0)];if(k)u=B.match(k[1]),y=k[0];else{for(g=0;g<i;++g)if(k=d[g],u=B.match(k[1])){y=k[0];break}u||(y="pln")}if((g=y.length>=5&&"lang-"===y.substring(0,5))&&!(u&&typeof u[1]==="string"))g=!1,y="src";g||(m[B]=y)}k=c;c+=B.length;if(g){g=u[1];var o=B.indexOf(g),H=o+g.length;u[2]&&(H=B.length-u[2].length,o=H-g.length);y=y.substring(5);n(l+k,B.substring(0,o),h,j);n(l+k+o,g,A(y,
13
+g),j);n(l+k+H,B.substring(H),h,j)}else j.push(l+k,y)}a.g=j}var b={},e;(function(){for(var h=a.concat(d),l=[],i={},c=0,p=h.length;c<p;++c){var m=h[c],q=m[3];if(q)for(var f=q.length;--f>=0;)b[q.charAt(f)]=m;m=m[1];q=""+m;i.hasOwnProperty(q)||(l.push(m),i[q]=r)}l.push(/[\S\s]/);e=j(l)})();var i=d.length;return h}function t(a){var d=[],h=[];a.tripleQuotedStrings?d.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,
14
+r,"'\""]):a.multiLineStrings?d.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/,r,"'\"`"]):d.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,r,"\"'"]);a.verbatimStrings&&h.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,r]);var b=a.hashComments;b&&(a.cStyleComments?(b>1?d.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,r,"#"]):d.push(["com",/^#(?:(?:define|e(?:l|nd)if|else|error|ifn?def|include|line|pragma|undef|warning)\b|[^\n\r]*)/,
15
+r,"#"]),h.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h(?:h|pp|\+\+)?|[a-z]\w*)>/,r])):d.push(["com",/^#[^\n\r]*/,r,"#"]));a.cStyleComments&&(h.push(["com",/^\/\/[^\n\r]*/,r]),h.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,r]));if(b=a.regexLiterals){var e=(b=b>1?"":"\n\r")?".":"[\\S\\s]";h.push(["lang-regex",RegExp("^(?:^^\\.?|[+-]|[!=]=?=?|\\#|%=?|&&?=?|\\(|\\*=?|[+\\-]=|->|\\/=?|::?|<<?=?|>>?>?=?|,|;|\\?|@|\\[|~|{|\\^\\^?=?|\\|\\|?=?|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*("+
16
+("/(?=[^/*"+b+"])(?:[^/\\x5B\\x5C"+b+"]|\\x5C"+e+"|\\x5B(?:[^\\x5C\\x5D"+b+"]|\\x5C"+e+")*(?:\\x5D|$))+/")+")")])}(b=a.types)&&h.push(["typ",b]);b=(""+a.keywords).replace(/^ | $/g,"");b.length&&h.push(["kwd",RegExp("^(?:"+b.replace(/[\s,]+/g,"|")+")\\b"),r]);d.push(["pln",/^\s+/,r," \r\n\t\u00a0"]);b="^.[^\\s\\w.$@'\"`/\\\\]*";a.regexLiterals&&(b+="(?!s*/)");h.push(["lit",/^@[$_a-z][\w$@]*/i,r],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,r],["pln",/^[$_a-z][\w$@]*/i,r],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,
17
+r,"0123456789"],["pln",/^\\[\S\s]?/,r],["pun",RegExp(b),r]);return C(d,h)}function z(a,d,h){function b(a){var c=a.nodeType;if(c==1&&!j.test(a.className))if("br"===a.nodeName)e(a),a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)b(a);else if((c==3||c==4)&&h){var d=a.nodeValue,i=d.match(m);if(i)c=d.substring(0,i.index),a.nodeValue=c,(d=d.substring(i.index+i[0].length))&&a.parentNode.insertBefore(l.createTextNode(d),a.nextSibling),e(a),c||a.parentNode.removeChild(a)}}
18
+function e(a){function b(a,c){var d=c?a.cloneNode(!1):a,f=a.parentNode;if(f){var f=b(f,1),h=a.nextSibling;f.appendChild(d);for(var e=h;e;e=h)h=e.nextSibling,f.appendChild(e)}return d}for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),d;(d=a.parentNode)&&d.nodeType===1;)a=d;c.push(a)}for(var j=/(?:^|\s)nocode(?:\s|$)/,m=/\r\n?|\n/,l=a.ownerDocument,i=l.createElement("li");a.firstChild;)i.appendChild(a.firstChild);for(var c=[i],p=0;p<c.length;++p)b(c[p]);d===(d|0)&&c[0].setAttribute("value",
19
+d);var n=l.createElement("ol");n.className="linenums";for(var d=Math.max(0,d-1|0)||0,p=0,q=c.length;p<q;++p)i=c[p],i.className="L"+(p+d)%10,i.firstChild||i.appendChild(l.createTextNode("\u00a0")),n.appendChild(i);a.appendChild(n)}function i(a,d){for(var h=d.length;--h>=0;){var b=d[h];U.hasOwnProperty(b)?V.console&&console.warn("cannot override language handler %s",b):U[b]=a}}function A(a,d){if(!a||!U.hasOwnProperty(a))a=/^\s*</.test(d)?"default-markup":"default-code";return U[a]}function D(a){var d=
20
+a.h;try{var h=m(a.c,a.i),b=h.a;a.a=b;a.d=h.d;a.e=0;A(d,b)(a);var e=/\bMSIE\s(\d+)/.exec(navigator.userAgent),e=e&&+e[1]<=8,d=/\n/g,i=a.a,j=i.length,h=0,l=a.d,n=l.length,b=0,c=a.g,p=c.length,t=0;c[p]=j;var q,f;for(f=q=0;f<p;)c[f]!==c[f+2]?(c[q++]=c[f++],c[q++]=c[f++]):f+=2;p=q;for(f=q=0;f<p;){for(var x=c[f],y=c[f+1],u=f+2;u+2<=p&&c[u+1]===y;)u+=2;c[q++]=x;c[q++]=y;f=u}c.length=q;var g=a.c,k;if(g)k=g.style.display,g.style.display="none";try{for(;b<n;){var o=l[b+2]||j,H=c[t+2]||j,u=Math.min(o,H),E=l[b+
21
+1],W;if(E.nodeType!==1&&(W=i.substring(h,u))){e&&(W=W.replace(d,"\r"));E.nodeValue=W;var Z=E.ownerDocument,s=Z.createElement("span");s.className=c[t+1];var z=E.parentNode;z.replaceChild(s,E);s.appendChild(E);h<o&&(l[b+1]=E=Z.createTextNode(i.substring(u,o)),z.insertBefore(E,s.nextSibling))}h=u;h>=o&&(b+=2);h>=H&&(t+=2)}}finally{if(g)g.style.display=k}}catch(v){V.console&&console.log(v&&v.stack||v)}}var V=window,G=["break,continue,do,else,for,if,return,while"],O=[[G,"auto,case,char,const,default,double,enum,extern,float,goto,inline,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"],
22
+"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],J=[O,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,delegate,dynamic_cast,explicit,export,friend,generic,late_check,mutable,namespace,nullptr,property,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],K=[O,"abstract,assert,boolean,byte,extends,final,finally,implements,import,instanceof,interface,null,native,package,strictfp,super,synchronized,throws,transient"],
23
+L=[K,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,internal,into,is,let,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var,virtual,where"],O=[O,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],M=[G,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"],
24
+N=[G,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],R=[G,"as,assert,const,copy,drop,enum,extern,fail,false,fn,impl,let,log,loop,match,mod,move,mut,priv,pub,pure,ref,self,static,struct,true,trait,type,unsafe,use"],G=[G,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],Q=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)\b/,
25
+S=/\S/,T=t({keywords:[J,L,O,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",M,N,G],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),U={};i(T,["default-code"]);i(C([],[["pln",/^[^<?]+/],["dec",/^<!\w[^>]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",
26
+/^<xmp\b[^>]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^<script\b[^>]*>([\S\s]*?)(<\/script\b[^>]*>)/i],["lang-css",/^<style\b[^>]*>([\S\s]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),["default-markup","htm","html","mxml","xhtml","xml","xsl"]);i(C([["pln",/^\s+/,r," \t\r\n"],["atv",/^(?:"[^"]*"?|'[^']*'?)/,r,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/],["pun",/^[/<->]+/],
27
+["lang-js",/^on\w+\s*=\s*"([^"]+)"/i],["lang-js",/^on\w+\s*=\s*'([^']+)'/i],["lang-js",/^on\w+\s*=\s*([^\s"'>]+)/i],["lang-css",/^style\s*=\s*"([^"]+)"/i],["lang-css",/^style\s*=\s*'([^']+)'/i],["lang-css",/^style\s*=\s*([^\s"'>]+)/i]]),["in.tag"]);i(C([],[["atv",/^[\S\s]+/]]),["uq.val"]);i(t({keywords:J,hashComments:!0,cStyleComments:!0,types:Q}),["c","cc","cpp","cxx","cyc","m"]);i(t({keywords:"null,true,false"}),["json"]);i(t({keywords:L,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:Q}),
28
+["cs"]);i(t({keywords:K,cStyleComments:!0}),["java"]);i(t({keywords:G,hashComments:!0,multiLineStrings:!0}),["bash","bsh","csh","sh"]);i(t({keywords:M,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}),["cv","py","python"]);i(t({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:!0,multiLineStrings:!0,regexLiterals:2}),["perl","pl","pm"]);i(t({keywords:N,
29
+hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb","ruby"]);i(t({keywords:O,cStyleComments:!0,regexLiterals:!0}),["javascript","js"]);i(t({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,throw,true,try,unless,until,when,while,yes",hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);i(t({keywords:R,cStyleComments:!0,multilineStrings:!0}),["rc","rs","rust"]);
30
+i(C([],[["str",/^[\S\s]+/]]),["regex"]);var X=V.PR={createSimpleLexer:C,registerLangHandler:i,sourceDecorator:t,PR_ATTRIB_NAME:"atn",PR_ATTRIB_VALUE:"atv",PR_COMMENT:"com",PR_DECLARATION:"dec",PR_KEYWORD:"kwd",PR_LITERAL:"lit",PR_NOCODE:"nocode",PR_PLAIN:"pln",PR_PUNCTUATION:"pun",PR_SOURCE:"src",PR_STRING:"str",PR_TAG:"tag",PR_TYPE:"typ",prettyPrintOne:function(a,d,e){var b=document.createElement("div");b.innerHTML="<pre>"+a+"</pre>";b=b.firstChild;e&&z(b,e,!0);D({h:d,j:e,c:b,i:1});return b.innerHTML},
31
+prettyPrint:e=e=function(a,d){function e(){for(var b=V.PR_SHOULD_USE_CONTINUATION?c.now()+250:Infinity;p<j.length&&c.now()<b;p++){for(var d=j[p],m=k,l=d;l=l.previousSibling;){var n=l.nodeType,s=(n===7||n===8)&&l.nodeValue;if(s?!/^\??prettify\b/.test(s):n!==3||/\S/.test(l.nodeValue))break;if(s){m={};s.replace(/\b(\w+)=([\w%+\-.:]+)/g,function(a,b,c){m[b]=c});break}}l=d.className;if((m!==k||f.test(l))&&!w.test(l)){n=!1;for(s=d.parentNode;s;s=s.parentNode)if(g.test(s.tagName)&&s.className&&f.test(s.className)){n=
32
+!0;break}if(!n){d.className+=" prettyprinted";n=m.lang;if(!n){var n=l.match(q),A;if(!n&&(A=x(d))&&u.test(A.tagName))n=A.className.match(q);n&&(n=n[1])}if(y.test(d.tagName))s=1;else var s=d.currentStyle,v=i.defaultView,s=(s=s?s.whiteSpace:v&&v.getComputedStyle?v.getComputedStyle(d,r).getPropertyValue("white-space"):0)&&"pre"===s.substring(0,3);v=m.linenums;if(!(v=v==="true"||+v))v=(v=l.match(/\blinenums\b(?::(\d+))?/))?v[1]&&v[1].length?+v[1]:!0:!1;v&&z(d,v,s);t={h:n,c:d,j:v,i:s};D(t)}}}p<j.length?
33
+P(e,250):"function"===typeof a&&a()}for(var b=d||document.body,i=b.ownerDocument||document,b=[b.getElementsByTagName("pre"),b.getElementsByTagName("code"),b.getElementsByTagName("xmp")],j=[],m=0;m<b.length;++m)for(var l=0,n=b[m].length;l<n;++l)j.push(b[m][l]);var b=r,c=Date;c.now||(c={now:function(){return+new Date}});var p=0,t,q=/\blang(?:uage)?-([\w.]+)(?!\S)/,f=/\bprettyprint\b/,w=/\bprettyprinted\b/,y=/pre|xmp/i,u=/^code$/i,g=/^(?:pre|code|xmp)$/i,k={};e()}};typeof define==="function"&&define.amd&&
34
+define("google-code-prettify",[],function(){return X})})();return e}();R||P(Q,0)})();}()
+2 -2
mojo/lib/Mojolicious/templates/exception.development.html.ep
... ...
@@ -5,8 +5,8 @@
5 5
     <meta http-equiv="Pragma" content="no-cache">
6 6
     <meta http-equiv="Expires" content="-1">
7 7
     %= javascript '/mojo/jquery/jquery.js'
8
+    %= javascript '/mojo/prettify/run_prettify.js'
8 9
     %= stylesheet '/mojo/prettify/prettify-mojo.css'
9
-    %= javascript '/mojo/prettify/prettify.js'
10 10
     %= stylesheet begin
11 11
       a img { border: 0 }
12 12
       body {
... ...
@@ -97,7 +97,7 @@
97 97
       }
98 98
     % end
99 99
   </head>
100
-  <body onload="prettyPrint()">
100
+  <body>
101 101
     %= include inline => app->renderer->_bundled('mojobar')
102 102
     <div id="wrapperlicious">
103 103
       <div id="nothing" class="box spaced"></div>
+10 -11
mojo/lib/Mojolicious/templates/not_found.development.html.ep
... ...
@@ -2,8 +2,8 @@
2 2
 <html>
3 3
   <head>
4 4
     <title>Page not found</title>
5
+    %= javascript '/mojo/prettify/run_prettify.js'
5 6
     %= stylesheet '/mojo/prettify/prettify-mojo.css'
6
-    %= javascript '/mojo/prettify/prettify.js'
7 7
     %= stylesheet begin
8 8
       body {
9 9
         background-color: #f5f6f8;
... ...
@@ -73,7 +73,7 @@
73 73
       }
74 74
     % end
75 75
   </head>
76
-  <body onload="prettyPrint()">
76
+  <body>
77 77
     %= include inline => app->renderer->_bundled('mojobar')
78 78
     <div id="wrapperlicious">
79 79
       <div id="routes">
... ...
@@ -84,25 +84,24 @@
84 84
           <code><%= $self->req->url->path %></code>, maybe you need to add a
85 85
           new one?
86 86
         </p>
87
-        % my $walk;
88
-        % $walk = begin
89
-          % my ($node, $depth) = @_;
87
+        % my $walk = begin
88
+          % my ($walk, $route, $depth) = @_;
90 89
           <tr>
91 90
             <td>
92
-              % my $pattern = $node->pattern->pattern || '/';
91
+              % my $pattern = $route->pattern->pattern || '/';
93 92
               % $pattern = "+$pattern" if $depth;
94 93
               <pre><%= '  ' x $depth %><%= $pattern %></pre>
95 94
             </td>
96 95
             <td>
97
-              <pre><%= uc(join ',', @{$node->via || []}) || '*' %></pre>
96
+              <pre><%= uc(join ',', @{$route->via || []}) || '*' %></pre>
98 97
             </td>
99 98
             <td>
100
-              % my $name = $node->name;
101
-              <pre><%= $node->has_custom_name ? qq{"$name"} : $name %></pre>
99
+              % my $name = $route->name;
100
+              <pre><%= $route->has_custom_name ? qq{"$name"} : $name %></pre>
102 101
             </td>
103 102
           </tr>
104 103
           % $depth++;
105
-          %= $walk->($_, $depth) for @{$node->children};
104
+          %= $walk->($walk, $_, $depth) for @{$route->children};
106 105
           % $depth--;
107 106
         % end
108 107
         <table>
... ...
@@ -111,7 +110,7 @@
111 110
             <th>Methods</th>
112 111
             <th>Name</th>
113 112
           </tr>
114
-          %= $walk->($_, 0) for @{app->routes->children};
113
+          %= $walk->($walk, $_, 0) for @{app->routes->children};
115 114
         </table>
116 115
       </div>
117 116
     </div>
+2 -2
mojo/lib/Mojolicious/templates/perldoc.html.ep
... ...
@@ -2,8 +2,8 @@
2 2
 <html>
3 3
   <head>
4 4
     <title><%= $title %></title>
5
+    %= javascript '/mojo/prettify/run_prettify.js'
5 6
     %= stylesheet '/mojo/prettify/prettify-mojo.css'
6
-    %= javascript '/mojo/prettify/prettify.js'
7 7
     %= stylesheet begin
8 8
       a { color: inherit }
9 9
       a:hover { color: #2a2a2a }
... ...
@@ -61,7 +61,7 @@
61 61
       }
62 62
     % end
63 63
   </head>
64
-  <body onload="prettyPrint()">
64
+  <body>
65 65
     %= include inline => app->renderer->_bundled('mojobar')
66 66
     % my $link = begin
67 67
       %= link_to shift, shift, class => "mojoscroll"
+96 -105
mojo/lib/Test/Mojo.pm
... ...
@@ -102,10 +102,18 @@ sub element_exists_not {
102 102
 }
103 103
 
104 104
 sub finish_ok {
105
-  my ($self, $desc) = @_;
106
-  $self->tx->finish;
105
+  my $self = shift;
106
+  $self->tx->finish(@_);
107
+  Mojo::IOLoop->one_tick while !$self->{finished};
108
+  return $self->_test('ok', 1, 'closed WebSocket');
109
+}
110
+
111
+sub finished_ok {
112
+  my ($self, $code) = @_;
107 113
   Mojo::IOLoop->one_tick while !$self->{finished};
108
-  return $self->_test('ok', 1, $desc || 'finished websocket');
114
+  Test::More::diag "WebSocket closed with status $self->{finished}[0]"
115
+    unless my $ok = grep { $self->{finished}[0] == $_ } $code, 1006;
116
+  return $self->_test('ok', $ok, "WebSocket closed with status $code");
109 117
 }
110 118
 
111 119
 sub get_ok  { shift->_request_ok(get  => @_) }
... ...
@@ -138,12 +146,6 @@ sub header_unlike {
138 146
     $regex, $desc || "$name is not similar");
139 147
 }
140 148
 
141
-sub json_content_is {
142
-  my ($self, $data, $desc) = @_;
143
-  $desc ||= 'exact match for JSON structure';
144
-  return $self->_test('is_deeply', $self->tx->res->json, $data, $desc);
145
-}
146
-
147 149
 sub json_has {
148 150
   my ($self, $p, $desc) = @_;
149 151
   $desc ||= qq{has value for JSON Pointer "$p"};
... ...
@@ -159,8 +161,9 @@ sub json_hasnt {
159 161
 }
160 162
 
161 163
 sub json_is {
162
-  my ($self, $p, $data, $desc) = @_;
163
-  $desc ||= qq{exact match for JSON Pointer "$p"};
164
+  my $self = shift;
165
+  my ($p, $data) = ref $_[0] ? ('', shift) : (shift, shift);
166
+  my $desc = shift || qq{exact match for JSON Pointer "$p"};
164 167
   return $self->_test('is_deeply', $self->tx->res->json($p), $data, $desc);
165 168
 }
166 169
 
... ...
@@ -177,8 +180,9 @@ sub json_message_hasnt {
177 180
 }
178 181
 
179 182
 sub json_message_is {
180
-  my ($self, $p, $data, $desc) = @_;
181
-  $desc ||= qq{exact match for JSON Pointer "$p"};
183
+  my $self = shift;
184
+  my ($p, $data) = ref $_[0] ? ('', shift) : (shift, shift);
185
+  my $desc = shift || qq{exact match for JSON Pointer "$p"};
182 186
   return $self->_test('is_deeply', $self->_json(get => $p), $data, $desc);
183 187
 }
184 188
 
... ...
@@ -199,7 +203,7 @@ sub message_like {
199 203
 
200 204
 sub message_ok {
201 205
   my ($self, $desc) = @_;
202
-  return $self->_test('ok', !!$self->_wait(1), $desc, 'message received');
206
+  return $self->_test('ok', !!$self->_wait, $desc || 'message received');
203 207
 }
204 208
 
205 209
 sub message_unlike {
... ...
@@ -217,20 +221,7 @@ sub or {
217 221
 
218 222
 sub patch_ok { shift->_request_ok(patch => @_) }
219 223
 sub post_ok  { shift->_request_ok(post  => @_) }
220
-
221
-sub post_form_ok {
222
-  my ($self, $url) = (shift, shift);
223
-  my $tx = $self->tx($self->ua->post_form($url, @_))->tx;
224
-  return $self->_test('ok', $tx->is_finished, encode('UTF-8', "post $url"));
225
-}
226
-
227
-sub post_json_ok {
228
-  my ($self, $url) = (shift, shift);
229
-  my $tx = $self->tx($self->ua->post_json($url, @_))->tx;
230
-  return $self->_test('ok', $tx->is_finished, encode('UTF-8', "post $url"));
231
-}
232
-
233
-sub put_ok { shift->_request_ok(put => @_) }
224
+sub put_ok   { shift->_request_ok(put   => @_) }
234 225
 
235 226
 sub request_ok {
236 227
   my $self = shift;
... ...
@@ -293,12 +284,12 @@ sub websocket_ok {
293 284
 
294 285
   # Establish WebSocket connection
295 286
   $self->{messages} = [];
296
-  $self->{finished} = 0;
287
+  $self->{finished} = undef;
297 288
   $self->ua->websocket(
298 289
     $url => @_ => sub {
299
-      my $tx = pop;
290
+      my ($ua, $tx) = @_;
300 291
       $self->tx($tx);
301
-      $tx->on(finish => sub { $self->{finished} = 1 });
292
+      $tx->on(finish => sub { shift; $self->{finished} = [@_] });
302 293
       $tx->on(binary => sub { push @{$self->{messages}}, [binary => pop] });
303 294
       $tx->on(text   => sub { push @{$self->{messages}}, [text   => pop] });
304 295
       Mojo::IOLoop->stop;
... ...
@@ -306,7 +297,7 @@ sub websocket_ok {
306 297
   );
307 298
   Mojo::IOLoop->start;
308 299
 
309
-  my $desc = encode 'UTF-8', "websocket $url";
300
+  my $desc = encode 'UTF-8', "WebSocket $url";
310 301
   return $self->_test('ok', $self->tx->res->code eq 101, $desc);
311 302
 }
312 303
 
... ...
@@ -320,13 +311,13 @@ sub _get_content {
320 311
 sub _json {
321 312
   my ($self, $method, $p) = @_;
322 313
   return Mojo::JSON::Pointer->new->$method(
323
-    Mojo::JSON->new->decode(@{$self->_wait || []}[1]), $p);
314
+    Mojo::JSON->new->decode(@{$self->message}[1]), $p);
324 315
 }
325 316
 
326 317
 sub _message {
327 318
   my ($self, $name, $value, $desc) = @_;
328 319
   local $Test::Builder::Level = $Test::Builder::Level + 1;
329
-  my ($type, $msg) = @{$self->_wait || ['']};
320
+  my ($type, $msg) = @{$self->message};
330 321
 
331 322
   # Type check
332 323
   if (ref $value eq 'HASH') {
... ...
@@ -342,16 +333,14 @@ sub _message {
342 333
 }
343 334
 
344 335
 sub _request_ok {
345
-  my ($self, $method, $url, $headers, $body) = @_;
346
-  $body = $headers if !ref $headers && @_ > 3;
347
-  $headers = {} if !ref $headers;
336
+  my ($self, $method, $url) = (shift, shift, shift);
348 337
 
349 338
   # Perform request against application
350
-  $self->tx($self->ua->$method($url, $headers, $body));
339
+  $self->tx($self->ua->$method($url, @_));
351 340
   local $Test::Builder::Level = $Test::Builder::Level + 1;
352 341
   my ($err, $code) = $self->tx->error;
353 342
   Test::More::diag $err if !(my $ok = !$err || $code) && $err;
354
-  return $self->_test('ok', $ok, encode('UTF-8', "$method $url"));
343
+  return $self->_test('ok', $ok, encode('UTF-8', "@{[uc $method]} $url"));
355 344
 }
356 345
 
357 346
 sub _test {
... ...
@@ -367,22 +356,15 @@ sub _text {
367 356
 }
368 357
 
369 358
 sub _wait {
370
-  my ($self, $wait) = @_;
371
-
372
-  # DEPRECATED in Rainbow!
373
-  my $new = $self->{new} = defined $self->{new} ? $self->{new} : $wait;
374
-  warn <<EOF unless $new;
375
-Testing WebSocket messages without Test::Mojo->message_ok is DEPRECATED!!!
376
-EOF
377
-  return $self->message if $new && !$wait;
378
-
379
-  # Wait for message
359
+  my $self = shift;
380 360
   Mojo::IOLoop->one_tick while !$self->{finished} && !@{$self->{messages}};
381 361
   return $self->message(shift @{$self->{messages}})->message;
382 362
 }
383 363
 
384 364
 1;
385 365
 
366
+=encoding utf8
367
+
386 368
 =head1 NAME
387 369
 
388 370
 Test::Mojo - Testing Mojo!
... ...
@@ -398,10 +380,10 @@ Test::Mojo - Testing Mojo!
398 380
   $t->get_ok('/welcome')->status_is(200)->text_is('div#message' => 'Hello!');
399 381
 
400 382
   # JSON
401
-  $t->post_form_ok('/search.json' => {q => 'Perl'})
383
+  $t->post_ok('/search.json' => form => {q => 'Perl'})
402 384
     ->status_is(200)
403
-    ->header_is('X-Powered-By' => 'Mojolicious (Perl)')
404
-    ->header_isnt('X-Bender' => 'Bite my shiny metal ass!');
385
+    ->header_is('Server' => 'Mojolicious (Perl)')
386
+    ->header_isnt('X-Bender' => 'Bite my shiny metal ass!')
405 387
     ->json_is('/results/4/title' => 'Perl rocks!');
406 388
 
407 389
   # WebSocket
... ...
@@ -444,7 +426,7 @@ Current transaction, usually a L<Mojo::Transaction::HTTP> object.
444 426
 
445 427
   # More specific tests
446 428
   is $t->tx->res->json->{foo}, 'bar', 'right value';
447
-  ok $t->tx->res->is_multipart, 'multipart content';
429
+  ok $t->tx->res->content->is_multipart, 'multipart content';
448 430
 
449 431
   # Test custom transactions
450 432
   $t->tx($t->tx->previous)->status_is(302)->header_like(Location => qr/foo/);
... ...
@@ -459,15 +441,18 @@ User agent used for testing, defaults to a L<Mojo::UserAgent> object.
459 441
   # Allow redirects
460 442
   $t->ua->max_redirects(10);
461 443
 
444
+  # Use absolute URL for request with Basic authentication
445
+  my $url = $t->ua->app_url->userinfo('sri:secr3t')->path('/secrets.json');
446
+  $t->post_ok($url => json => {limit => 10})
447
+    ->status_is(200)
448
+    ->json_is('/1/content', 'Mojo rocks!');
449
+
462 450
   # Customize all transactions (including followed redirects)
463 451
   $t->ua->on(start => sub {
464 452
     my ($ua, $tx) = @_;
465 453
     $tx->req->headers->accept_language('en-US');
466 454
   });
467 455
 
468
-  # Request with Basic authentication
469
-  $t->get_ok($t->ua->app_url->userinfo('sri:secr3t')->path('/secrets'));
470
-
471 456
 =head1 METHODS
472 457
 
473 458
 L<Test::Mojo> inherits all methods from L<Mojo::Base> and implements the
... ...
@@ -566,9 +551,11 @@ Opposite of C<content_type_like>.
566 551
 
567 552
   $t = $t->delete_ok('/foo');
568 553
   $t = $t->delete_ok('/foo' => {DNT => 1} => 'Hi!');
554
+  $t = $t->delete_ok('/foo' => {DNT => 1} => form => {a => 'b'});
555
+  $t = $t->delete_ok('/foo' => {DNT => 1} => json => {a => 'b'});
569 556
 
570 557
 Perform a C<DELETE> request and check for transport errors, takes the same
571
-arguments as L<Mojo::UserAgent/"delete">.
558
+arguments as L<Mojo::UserAgent/"delete">, except for the callback.
572 559
 
573 560
 =head2 element_exists
574 561
 
... ...
@@ -588,25 +575,36 @@ Opposite of C<element_exists>.
588 575
 =head2 finish_ok
589 576
 
590 577
   $t = $t->finish_ok;
591
-  $t = $t->finish_ok('finished successfully');
578
+  $t = $t->finish_ok(1000);
579
+  $t = $t->finish_ok(1003 => 'Cannot accept data!');
580
+
581
+Close WebSocket connection gracefully.
582
+
583
+=head2 finished_ok
592 584
 
593
-Finish C<WebSocket> connection.
585
+  $t = $t->finished_ok(1000);
586
+
587
+Wait for WebSocket connection to be closed gracefully and check status.
594 588
 
595 589
 =head2 get_ok
596 590
 
597 591
   $t = $t->get_ok('/foo');
598 592
   $t = $t->get_ok('/foo' => {DNT => 1} => 'Hi!');
593
+  $t = $t->get_ok('/foo' => {DNT => 1} => form => {a => 'b'});
594
+  $t = $t->get_ok('/foo' => {DNT => 1} => json => {a => 'b'});
599 595
 
600 596
 Perform a C<GET> request and check for transport errors, takes the same
601
-arguments as L<Mojo::UserAgent/"get">.
597
+arguments as L<Mojo::UserAgent/"get">, except for the callback.
602 598
 
603 599
 =head2 head_ok
604 600
 
605 601
   $t = $t->head_ok('/foo');
606 602
   $t = $t->head_ok('/foo' => {DNT => 1} => 'Hi!');
603
+  $t = $t->head_ok('/foo' => {DNT => 1} => form => {a => 'b'});
604
+  $t = $t->head_ok('/foo' => {DNT => 1} => json => {a => 'b'});
607 605
 
608 606
 Perform a C<HEAD> request and check for transport errors, takes the same
609
-arguments as L<Mojo::UserAgent/"head">.
607
+arguments as L<Mojo::UserAgent/"head">, except for the callback.
610 608
 
611 609
 =head2 header_is
612 610
 
... ...
@@ -636,14 +634,6 @@ Check response header for similar match.
636 634
 
637 635
 Opposite of C<header_like>.
638 636
 
639
-=head2 json_content_is
640
-
641
-  $t = $t->json_content_is([1, 2, 3]);
642
-  $t = $t->json_content_is([1, 2, 3], 'right content');
643
-  $t = $t->json_content_is({foo => 'bar', baz => 23}, 'right content');
644
-
645
-Check response content for JSON data.
646
-
647 637
 =head2 json_has
648 638
 
649 639
   $t = $t->json_has('/foo');
... ...
@@ -661,12 +651,13 @@ Opposite of C<json_has>.
661 651
 
662 652
 =head2 json_is
663 653
 
664
-  $t = $t->json_is('/' => {foo => [1, 2, 3]});
654
+  $t = $t->json_is({foo => [1, 2, 3]});
655
+  $t = $t->json_is({foo => [1, 2, 3]}, 'right content');
665 656
   $t = $t->json_is('/foo' => [1, 2, 3]);
666 657
   $t = $t->json_is('/foo/1' => 2, 'right value');
667 658
 
668 659
 Check the value extracted from JSON response using the given JSON Pointer with
669
-L<Mojo::JSON::Pointer>.
660
+L<Mojo::JSON::Pointer>, which defaults to the root value if it is omitted.
670 661
 
671 662
 =head2 json_message_has
672 663
 
... ...
@@ -685,12 +676,14 @@ Opposite of C<json_message_has>.
685 676
 
686 677
 =head2 json_message_is
687 678
 
688
-  $t = $t->json_message_is('/' => {foo => [1, 2, 3]});
679
+  $t = $t->json_message_is({foo => [1, 2, 3]});
680
+  $t = $t->json_message_is({foo => [1, 2, 3]}, 'right content');
689 681
   $t = $t->json_message_is('/foo' => [1, 2, 3]);
690 682
   $t = $t->json_message_is('/foo/1' => 2, 'right value');
691 683
 
692 684
 Check the value extracted from JSON WebSocket message using the given JSON
693
-Pointer with L<Mojo::JSON::Pointer>.
685
+Pointer with L<Mojo::JSON::Pointer>, which defaults to the root value if it is
686
+omitted.
694 687
 
695 688
 =head2 message_is
696 689
 
... ...
@@ -746,9 +739,11 @@ Opposite of C<message_like>.
746 739
 
747 740
   $t = $t->options_ok('/foo');
748 741
   $t = $t->options_ok('/foo' => {DNT => 1} => 'Hi!');
742
+  $t = $t->options_ok('/foo' => {DNT => 1} => form => {a => 'b'});
743
+  $t = $t->options_ok('/foo' => {DNT => 1} => json => {a => 'b'});
749 744
 
750 745
 Perform a C<OPTIONS> request and check for transport errors, takes the same
751
-arguments as L<Mojo::UserAgent/"options">.
746
+arguments as L<Mojo::UserAgent/"options">, except for the callback.
752 747
 
753 748
 =head2 or
754 749
 
... ...
@@ -764,49 +759,40 @@ Invoke callback if previous test failed.
764 759
 
765 760
   $t = $t->patch_ok('/foo');
766 761
   $t = $t->patch_ok('/foo' => {DNT => 1} => 'Hi!');
762
+  $t = $t->patch_ok('/foo' => {DNT => 1} => form => {a => 'b'});
763
+  $t = $t->patch_ok('/foo' => {DNT => 1} => json => {a => 'b'});
767 764
 
768 765
 Perform a C<PATCH> request and check for transport errors, takes the same
769
-arguments as L<Mojo::UserAgent/"patch">.
766
+arguments as L<Mojo::UserAgent/"patch">, except for the callback.
770 767
 
771 768
 =head2 post_ok
772 769
 
773 770
   $t = $t->post_ok('/foo');
774 771
   $t = $t->post_ok('/foo' => {DNT => 1} => 'Hi!');
772
+  $t = $t->post_ok('/foo' => {DNT => 1} => form => {a => 'b'});
773
+  $t = $t->post_ok('/foo' => {DNT => 1} => json => {a => 'b'});
775 774
 
776 775
 Perform a C<POST> request and check for transport errors, takes the same
777
-arguments as L<Mojo::UserAgent/"post">.
778
-
779
-=head2 post_form_ok
780
-
781
-  $t = $t->post_form_ok('/foo' => {a => 'b'});
782
-  $t = $t->post_form_ok('/foo' => 'UTF-8' => {a => 'b'} => {DNT => 1});
783
-
784
-Perform a C<POST> request with form data and check for transport errors, takes
785
-the same arguments as L<Mojo::UserAgent/"post_form">.
776
+arguments as L<Mojo::UserAgent/"post">, except for the callback.
786 777
 
787 778
   # Test file upload
788
-  $t->post_form_ok('/upload' => {foo => {content => 'bar'}})->status_is(200);
789
-
790
-=head2 post_json_ok
791
-
792
-  $t = $t->post_json_ok('/foo' => {a => 'b'});
793
-  $t = $t->post_json_ok('/foo' => {a => 'b'} => {DNT => 1});
794
-
795
-Perform a C<POST> request with JSON data and check for transport errors, takes
796
-the same arguments as L<Mojo::UserAgent/"post_json">.
779
+  $t->post_ok('/upload' => form => {foo => {content => 'bar'}})
780
+    ->status_is(200);
797 781
 
798 782
   # Test JSON API
799
-  $t->post_json_ok('/hello.json' => {hello => 'world'})
783
+  $t->post_json_ok('/hello.json' => json => {hello => 'world'})
800 784
     ->status_is(200)
801
-    ->json_content_is({bye => 'world'});
785
+    ->json_is({bye => 'world'});
802 786
 
803 787
 =head2 put_ok
804 788
 
805 789
   $t = $t->put_ok('/foo');
806 790
   $t = $t->put_ok('/foo' => {DNT => 1} => 'Hi!');
791
+  $t = $t->put_ok('/foo' => {DNT => 1} => form => {a => 'b'});
792
+  $t = $t->put_ok('/foo' => {DNT => 1} => json => {a => 'b'});
807 793
 
808 794
 Perform a C<PUT> request and check for transport errors, takes the same
809
-arguments as L<Mojo::UserAgent/"put">.
795
+arguments as L<Mojo::UserAgent/"put">, except for the callback.
810 796
 
811 797
 =head2 request_ok
812 798
 
... ...
@@ -815,12 +801,9 @@ arguments as L<Mojo::UserAgent/"put">.
815 801
 
816 802
 Perform request and check for transport errors.
817 803
 
818
-  # Customize transaction
819
-  my $tx = $t->ua->build_json_tx('/user/99' => {name => 'sri'});
820
-  $tx->req->method('PUT');
821
-  $t->request_ok($tx)
822
-    ->status_is(200)
823
-    ->json_is('/message' => 'User has been replaced.');
804
+  # Request with custom method
805
+  my $tx = $t->ua->build_tx(FOO => '/test.json' => json => {foo => 1});
806
+  $t->request_ok($tx)->status_is(200)->json_is({success => 1});
824 807
 
825 808
 =head2 reset_session
826 809
 
... ...
@@ -832,12 +815,20 @@ Reset user agent session.
832 815
 
833 816
   $t = $t->send_ok({binary => $bytes});
834 817
   $t = $t->send_ok({text   => $bytes});
818
+  $t = $t->send_ok({json   => {test => [1, 2, 3]}});
835 819
   $t = $t->send_ok([$fin, $rsv1, $rsv2, $rsv3, $op, $payload]);
836 820
   $t = $t->send_ok($chars);
837 821
   $t = $t->send_ok($chars, 'sent successfully');
838 822
 
839 823
 Send message or frame via WebSocket.
840 824
 
825
+  # Send JSON object as "Text" message
826
+  $t->websocket_ok('/echo.json')
827
+    ->send_ok({json => {test => 'I ♥ Mojolicious!'}})
828
+    ->message_ok
829
+    ->json_message_is('/test' => 'I ♥ Mojolicious!')
830
+    ->finish_ok;
831
+
841 832
 =head2 status_is
842 833
 
843 834
   $t = $t->status_is(200);
... ...
@@ -885,10 +876,10 @@ Opposite of C<text_like>.
885 876
 =head2 websocket_ok
886 877
 
887 878
   $t = $t->websocket_ok('/echo');
888
-  $t = $t->websocket_ok('/echo' => {DNT => 1});
879
+  $t = $t->websocket_ok('/echo' => {DNT => 1} => ['v1.proto']);
889 880
 
890
-Open a C<WebSocket> connection with transparent handshake, takes the same
891
-arguments as L<Mojo::UserAgent/"websocket">.
881
+Open a WebSocket connection with transparent handshake, takes the same
882
+arguments as L<Mojo::UserAgent/"websocket">, except for the callback.
892 883
 
893 884
 =head1 SEE ALSO
894 885
 
+23 -41
mojo/lib/ojo.pm
... ...
@@ -29,14 +29,12 @@ sub import {
29 29
     a => sub { $caller->can('any')->(@_) and return $UA->app },
30 30
     b => \&b,
31 31
     c => \&c,
32
-    d => sub { _request($UA->build_tx(DELETE => @_)) },
33
-    f => sub { _request($UA->build_form_tx(@_)) },
34
-    g => sub { _request($UA->build_tx(GET    => @_)) },
35
-    h => sub { _request($UA->build_tx(HEAD   => @_)) },
32
+    d => sub { _request($UA->build_tx(DELETE  => @_)) },
33
+    g => sub { _request($UA->build_tx(GET     => @_)) },
34
+    h => sub { _request($UA->build_tx(HEAD    => @_)) },
36 35
     j => \&j,
37
-    n => sub { _request($UA->build_json_tx(@_)) },
38 36
     o => sub { _request($UA->build_tx(OPTIONS => @_)) },
39
-    p => sub { _request($UA->build_tx(POST => @_)) },
37
+    p => sub { _request($UA->build_tx(POST    => @_)) },
40 38
     r => sub { $UA->app->dumper(@_) },
41 39
     t => sub { _request($UA->build_tx(PATCH => @_)) },
42 40
     u => sub { _request($UA->build_tx(PUT => @_)) },
... ...
@@ -65,14 +63,14 @@ ojo - Fun oneliners with Mojo!
65 63
 
66 64
 A collection of automatically exported functions for fun Perl oneliners. Ten
67 65
 redirects will be followed by default, you can change this behavior with the
68
-C<MOJO_MAX_REDIRECTS> environment variable.
66
+MOJO_MAX_REDIRECTS environment variable.
69 67
 
70
-  $ MOJO_MAX_REDIRECTS=0 perl -Mojo -E 'say g("mojolicio.us")->code'
68
+  $ MOJO_MAX_REDIRECTS=0 perl -Mojo -E 'say g("example.com")->code'
71 69
 
72 70
 Proxy detection is enabled by default, but you can disable it with the
73
-C<MOJO_PROXY> environment variable.
71
+MOJO_PROXY environment variable.
74 72
 
75
-  $ MOJO_PROXY=0 perl -Mojo -E 'say g("mojolicio.us")->body'
73
+  $ MOJO_PROXY=0 perl -Mojo -E 'say g("example.com")->body'
76 74
 
77 75
 =head1 FUNCTIONS
78 76
 
... ...
@@ -104,24 +102,16 @@ Turn list into a L<Mojo::Collection> object.
104 102
 
105 103
 =head2 d
106 104
 
107
-  my $res = d('mojolicio.us');
108
-  my $res = d('http://mojolicio.us' => {DNT => 1} => 'Hi!');
105
+  my $res = d('example.com');
106
+  my $res = d('http://example.com' => {DNT => 1} => 'Hi!');
109 107
 
110 108
 Perform C<DELETE> request with L<Mojo::UserAgent/"delete"> and return
111 109
 resulting L<Mojo::Message::Response> object.
112 110
 
113
-=head2 f
114
-
115
-  my $res = f('http://kraih.com' => {a => 'b'});
116
-  my $res = f('kraih.com' => 'UTF-8' => {a => 'b'} => {DNT => 1});
117
-
118
-Perform C<POST> request with L<Mojo::UserAgent/"post_form"> and return
119
-resulting L<Mojo::Message::Response> object.
120
-
121 111
 =head2 g
122 112
 
123
-  my $res = g('mojolicio.us');
124
-  my $res = g('http://mojolicio.us' => {DNT => 1} => 'Hi!');
113
+  my $res = g('example.com');
114
+  my $res = g('http://example.com' => {DNT => 1} => 'Hi!');
125 115
 
126 116
 Perform C<GET> request with L<Mojo::UserAgent/"get"> and return resulting
127 117
 L<Mojo::Message::Response> object.
... ...
@@ -130,8 +120,8 @@ L<Mojo::Message::Response> object.
130 120
 
131 121
 =head2 h
132 122
 
133
-  my $res = h('mojolicio.us');
134
-  my $res = h('http://mojolicio.us' => {DNT => 1} => 'Hi!');
123
+  my $res = h('example.com');
124
+  my $res = h('http://example.com' => {DNT => 1} => 'Hi!');
135 125
 
136 126
 Perform C<HEAD> request with L<Mojo::UserAgent/"head"> and return resulting
137 127
 L<Mojo::Message::Response> object.
... ...
@@ -146,26 +136,18 @@ Encode Perl data structure or decode JSON with L<Mojo::JSON>.
146 136
 
147 137
   $ perl -Mojo -E 'b(j({hello => "world!"}))->spurt("hello.json")'
148 138
 
149
-=head2 n
150
-
151
-  my $res = n('http://kraih.com' => {a => 'b'});
152
-  my $res = n('kraih.com' => {a => 'b'} => {DNT => 1});
153
-
154
-Perform C<POST> request with L<Mojo::UserAgent/"post_json"> and return
155
-resulting L<Mojo::Message::Response> object.
156
-
157 139
 =head2 o
158 140
 
159
-  my $res = o('mojolicio.us');
160
-  my $res = o('http://mojolicio.us' => {DNT => 1} => 'Hi!');
141
+  my $res = o('example.com');
142
+  my $res = o('http://example.com' => {DNT => 1} => 'Hi!');
161 143
 
162 144
 Perform C<OPTIONS> request with L<Mojo::UserAgent/"options"> and return
163 145
 resulting L<Mojo::Message::Response> object.
164 146
 
165 147
 =head2 p
166 148
 
167
-  my $res = p('mojolicio.us');
168
-  my $res = p('http://mojolicio.us' => {DNT => 1} => 'Hi!');
149
+  my $res = p('example.com');
150
+  my $res = p('http://example.com' => {DNT => 1} => 'Hi!');
169 151
 
170 152
 Perform C<POST> request with L<Mojo::UserAgent/"post"> and return resulting
171 153
 L<Mojo::Message::Response> object.
... ...
@@ -176,20 +158,20 @@ L<Mojo::Message::Response> object.
176 158
 
177 159
 Dump a Perl data structure with L<Data::Dumper>.
178 160
 
179
-  perl -Mojo -E 'say r(g("mojolicio.us")->headers->to_hash)'
161
+  perl -Mojo -E 'say r(g("example.com")->headers->to_hash)'
180 162
 
181 163
 =head2 t
182 164
 
183
-  my $res = t('mojolicio.us');
184
-  my $res = t('http://mojolicio.us' => {DNT => 1} => 'Hi!');
165
+  my $res = t('example.com');
166
+  my $res = t('http://example.com' => {DNT => 1} => 'Hi!');
185 167
 
186 168
 Perform C<PATCH> request with L<Mojo::UserAgent/"patch"> and return resulting
187 169
 L<Mojo::Message::Response> object.
188 170
 
189 171
 =head2 u
190 172
 
191
-  my $res = u('mojolicio.us');
192
-  my $res = u('http://mojolicio.us' => {DNT => 1} => 'Hi!');
173
+  my $res = u('example.com');
174
+  my $res = u('http://example.com' => {DNT => 1} => 'Hi!');
193 175
 
194 176
 Perform C<PUT> request with L<Mojo::UserAgent/"put"> and return resulting
195 177
 L<Mojo::Message::Response> object.
+1 -1
mojo/script/hypnotoad
... ...
@@ -4,7 +4,7 @@ use strict;
4 4
 use warnings;
5 5
 
6 6
 use FindBin;
7
-use lib "$FindBin::Bin/../lib";
7
+BEGIN { unshift @INC, "$FindBin::Bin/../lib" }
8 8
 
9 9
 use Getopt::Long qw(GetOptions :config no_auto_abbrev no_ignore_case);
10 10
 
+1 -1
mojo/script/mojo
... ...
@@ -4,7 +4,7 @@ use strict;
4 4
 use warnings;
5 5
 
6 6
 use FindBin;
7
-use lib "$FindBin::Bin/../lib";
7
+BEGIN { unshift @INC, "$FindBin::Bin/../lib" }
8 8
 
9 9
 require Mojolicious::Commands;
10 10
 Mojolicious::Commands->start_app('Mojo::HelloWorld');
+1 -1
mojo/script/morbo
... ...
@@ -4,7 +4,7 @@ use strict;
4 4
 use warnings;
5 5
 
6 6
 use FindBin;
7
-use lib "$FindBin::Bin/../lib";
7
+BEGIN { unshift @INC, "$FindBin::Bin/../lib" }
8 8
 
9 9
 use Getopt::Long qw(GetOptions :config no_auto_abbrev no_ignore_case);
10 10