Showing 125 changed files with 3965 additions and 2478 deletions
+2
mojo/README
... ...
@@ -0,0 +1,2 @@
1
+mojo-legacy 4.57
2
+https://github.com/jamadam/mojo-legacy
+10 -6
mojo/lib/Mojo.pm
... ...
@@ -15,10 +15,10 @@ has log  => sub { Mojo::Log->new };
15 15
 has ua   => sub {
16 16
   my $self = shift;
17 17
 
18
-  my $ua = Mojo::UserAgent->new->app($self);
18
+  my $ua = Mojo::UserAgent->new;
19
+  weaken $ua->server->app($self)->{app};
19 20
   weaken $self;
20 21
   $ua->on(error => sub { $self->log->error($_[1]) });
21
-  weaken $ua->{app};
22 22
 
23 23
   return $ua;
24 24
 };
... ...
@@ -27,7 +27,8 @@ sub new {
27 27
   my $self = shift->SUPER::new(@_);
28 28
 
29 29
   # Check if we have a log directory
30
-  my $home = $self->home->detect(ref $self);
30
+  my $home = $self->home;
31
+  $home->detect(ref $self) unless @{$home->parts};
31 32
   $self->log->path($home->rel_file('log/mojo.log'))
32 33
     if -w $home->rel_file('log');
33 34
 
... ...
@@ -58,6 +59,8 @@ sub _dict {
58 59
 
59 60
 1;
60 61
 
62
+=encoding utf8
63
+
61 64
 =head1 NAME
62 65
 
63 66
 Mojo - Duct tape for the HTML5 web!
... ...
@@ -92,7 +95,7 @@ frameworks. It provides all the basic tools and helpers needed to write
92 95
 simple web applications and higher level web frameworks, such as
93 96
 L<Mojolicious>.
94 97
 
95
-See L<Mojolicious> for more!
98
+See L<Mojolicious::Guides> for more!
96 99
 
97 100
 =head1 ATTRIBUTES
98 101
 
... ...
@@ -130,7 +133,7 @@ plugins, since non-blocking requests that are already in progress will
130 133
 interfere with new blocking ones.
131 134
 
132 135
   # Perform blocking request
133
-  my $body = $app->ua->get('example.com')->res->body;
136
+  say $app->ua->get('example.com')->res->body;
134 137
 
135 138
 =head1 METHODS
136 139
 
... ...
@@ -142,7 +145,8 @@ new ones.
142 145
   my $app = Mojo->new;
143 146
 
144 147
 Construct a new L<Mojo> application. Will automatically detect your home
145
-directory and set up logging to C<log/mojo.log> if there's a C<log> directory.
148
+directory if necessary and set up logging to C<log/mojo.log> if there's a
149
+C<log> directory.
146 150
 
147 151
 =head2 build_tx
148 152
 
+5 -3
mojo/lib/Mojo/Asset.pm
... ...
@@ -20,6 +20,8 @@ sub slurp   { croak 'Method "slurp" not implemented by subclass' }
20 20
 
21 21
 1;
22 22
 
23
+=encoding utf8
24
+
23 25
 =head1 NAME
24 26
 
25 27
 Mojo::Asset - HTTP content storage base class
... ...
@@ -58,7 +60,7 @@ Pretend file ends earlier.
58 60
 =head2 start_range
59 61
 
60 62
   my $start = $asset->start_range;
61
-  $asset    = $asset->start_range(0);
63
+  $asset    = $asset->start_range(3);
62 64
 
63 65
 Pretend file starts later.
64 66
 
... ...
@@ -96,9 +98,9 @@ False.
96 98
 
97 99
 =head2 is_range
98 100
 
99
-  my $success = $asset->is_range;
101
+  my $bool = $asset->is_range;
100 102
 
101
-Check if asset has a C<start_range> or C<end_range>.
103
+Check if asset has a L</"start_range"> or L</"end_range">.
102 104
 
103 105
 =head2 move_to
104 106
 
+9 -7
mojo/lib/Mojo/Asset/File.pm
... ...
@@ -26,7 +26,7 @@ has handle => sub {
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};
29
-    $name = "$base." . md5_sum(time . $$ . rand 9999999);
29
+    $name = "$base." . md5_sum(time . $$ . rand 9 x 7);
30 30
   }
31 31
   $self->path($name);
32 32
 
... ...
@@ -140,6 +140,8 @@ sub slurp {
140 140
 
141 141
 1;
142 142
 
143
+=encoding utf8
144
+
143 145
 =head1 NAME
144 146
 
145 147
 Mojo::Asset::File - File storage for HTTP content
... ...
@@ -174,8 +176,8 @@ implements the following new ones.
174 176
 
175 177
 =head2 cleanup
176 178
 
177
-  my $cleanup = $file->cleanup;
178
-  $file       = $file->cleanup(1);
179
+  my $bool = $file->cleanup;
180
+  $file    = $file->cleanup($bool);
179 181
 
180 182
 Delete file automatically once it's not used anymore.
181 183
 
... ...
@@ -184,14 +186,14 @@ Delete file automatically once it's not used anymore.
184 186
   my $handle = $file->handle;
185 187
   $file      = $file->handle(IO::File->new);
186 188
 
187
-File handle, created on demand.
189
+Filehandle, created on demand.
188 190
 
189 191
 =head2 path
190 192
 
191 193
   my $path = $file->path;
192 194
   $file    = $file->path('/home/sri/foo.txt');
193 195
 
194
-File path used to create C<handle>, can also be automatically generated if
196
+File path used to create L</"handle">, can also be automatically generated if
195 197
 necessary.
196 198
 
197 199
 =head2 tmpdir
... ...
@@ -199,7 +201,7 @@ necessary.
199 201
   my $tmpdir = $file->tmpdir;
200 202
   $file      = $file->tmpdir('/tmp');
201 203
 
202
-Temporary directory used to generate C<path>, defaults to the value of the
204
+Temporary directory used to generate L</"path">, defaults to the value of the
203 205
 MOJO_TMPDIR environment variable or auto detection.
204 206
 
205 207
 =head1 METHODS
... ...
@@ -237,7 +239,7 @@ True.
237 239
 
238 240
   $file = $file->move_to('/home/sri/bar.txt');
239 241
 
240
-Move asset data into a specific file and disable C<cleanup>.
242
+Move asset data into a specific file and disable L</"cleanup">.
241 243
 
242 244
 =head2 size
243 245
 
+5 -3
mojo/lib/Mojo/Asset/Memory.pm
... ...
@@ -55,6 +55,8 @@ sub slurp { shift->{content} }
55 55
 
56 56
 1;
57 57
 
58
+=encoding utf8
59
+
58 60
 =head1 NAME
59 61
 
60 62
 Mojo::Asset::Memory - In-memory storage for HTTP content
... ...
@@ -97,10 +99,10 @@ implements the following new ones.
97 99
 
98 100
 =head2 auto_upgrade
99 101
 
100
-  my $upgrade = $mem->auto_upgrade;
101
-  $mem        = $mem->auto_upgrade(1);
102
+  my $bool = $mem->auto_upgrade;
103
+  $mem     = $mem->auto_upgrade($bool);
102 104
 
103
-Try to detect if content size exceeds C<max_memory_size> limit and
105
+Try to detect if content size exceeds L</"max_memory_size"> limit and
104 106
 automatically upgrade to a L<Mojo::Asset::File> object.
105 107
 
106 108
 =head2 max_memory_size
+13 -15
mojo/lib/Mojo/Base.pm
... ...
@@ -14,7 +14,6 @@ use IO::Handle ();
14 14
 sub import {
15 15
   my $class = shift;
16 16
   return unless my $flag = shift;
17
-  no strict 'refs';
18 17
 
19 18
   # Base
20 19
   if ($flag eq '-base') { $flag = $class }
... ...
@@ -23,21 +22,24 @@ sub import {
23 22
   elsif ($flag eq '-strict') { $flag = undef }
24 23
 
25 24
   # Module
26
-  else {
27
-    my $file = $flag;
28
-    $file =~ s/::|'/\//g;
29
-    require "$file.pm" unless $flag->can('new');
25
+  elsif ((my $file = $flag) && !$flag->can('new')) {
26
+    $file =~ s!::|'!/!g;
27
+    require "$file.pm";
30 28
   }
31 29
 
32 30
   # ISA
33 31
   if ($flag) {
34 32
     my $caller = caller;
33
+    no strict 'refs';
35 34
     push @{"${caller}::ISA"}, $flag;
36 35
     *{"${caller}::has"} = sub { attr($caller, @_) };
37 36
   }
38 37
   
39 38
   my $caller = caller;
40
-  *{"${caller}::say"} = sub { say(@_) };
39
+  {
40
+    no strict 'refs';
41
+    *{"${caller}::say"} = sub { say(@_) };
42
+  }
41 43
 
42 44
   # Mojo modules are strict!
43 45
   strict->import;
... ...
@@ -51,9 +53,6 @@ sub new {
51 53
   bless @_ ? @_ > 1 ? {@_} : {%{$_[0]}} : {}, ref $class || $class;
52 54
 }
53 55
 
54
-# Performance is very important for something as often used as accessors,
55
-# so we optimize them by compiling our own code, don't be scared, we have
56
-# tests for every single case
57 56
 sub attr {
58 57
   my ($class, $attrs, $default) = @_;
59 58
   return unless ($class = ref $class || $class) && $attrs;
... ...
@@ -61,7 +60,6 @@ sub attr {
61 60
   Carp::croak 'Default has to be a code reference or constant value'
62 61
     if ref $default && ref $default ne 'CODE';
63 62
 
64
-  # Compile attributes
65 63
   for my $attr (@{ref $attrs eq 'ARRAY' ? $attrs : [$attrs]}) {
66 64
     Carp::croak qq{Attribute "$attr" invalid} unless $attr =~ /^[a-zA-Z_]\w*$/;
67 65
 
... ...
@@ -89,8 +87,6 @@ sub attr {
89 87
     # Footer (return invocant)
90 88
     $code .= "  \$_[0];\n}";
91 89
 
92
-    # We compile custom attribute code for speed
93
-    no strict 'refs';
94 90
     warn "-- Attribute $attr in $class\n$code\n\n" if $ENV{MOJO_BASE_DEBUG};
95 91
     Carp::croak "Mojo::Base error: $@" unless eval "$code;1";
96 92
   }
... ...
@@ -104,6 +100,8 @@ sub tap {
104 100
 
105 101
 1;
106 102
 
103
+=encoding utf8
104
+
107 105
 =head1 NAME
108 106
 
109 107
 Mojo::Base - Minimal base class for Mojo projects
... ...
@@ -185,7 +183,7 @@ flag or a base class.
185 183
   has [qw(name1 name2 name3)] => 'foo';
186 184
   has [qw(name1 name2 name3)] => sub {...};
187 185
 
188
-Create attributes for hash-based objects, just like the C<attr> method.
186
+Create attributes for hash-based objects, just like the L</"attr"> method.
189 187
 
190 188
 =head1 METHODS
191 189
 
... ...
@@ -222,8 +220,8 @@ argument.
222 220
   $object = $object->tap(sub {...});
223 221
 
224 222
 K combinator, tap into a method chain to perform operations on an object
225
-within the chain. The object will be the first argument passed to the closure
226
-and is also available via C<$_>.
223
+within the chain. The object will be the first argument passed to the callback
224
+and is also available as C<$_>.
227 225
 
228 226
 =head2 C<say>
229 227
 
+22 -6
mojo/lib/Mojo/ByteStream.pm
... ...
@@ -1,5 +1,5 @@
1 1
 package Mojo::ByteStream;
2
-use Mojo::Base -base;
2
+use Mojo::Base -strict;
3 3
 use overload '""' => sub { shift->to_string }, fallback => 1;
4 4
 
5 5
 use Exporter 'import';
... ...
@@ -63,10 +63,14 @@ sub split {
63 63
   return Mojo::Collection->new(map { $self->new($_) } split $pattern, $$self);
64 64
 }
65 65
 
66
+sub tap { shift->Mojo::Base::tap(@_) }
67
+
66 68
 sub to_string { ${$_[0]} }
67 69
 
68 70
 1;
69 71
 
72
+=encoding utf8
73
+
70 74
 =head1 NAME
71 75
 
72 76
 Mojo::ByteStream - ByteStream
... ...
@@ -104,8 +108,7 @@ Construct a new scalar-based L<Mojo::ByteStream> object.
104 108
 
105 109
 =head1 METHODS
106 110
 
107
-L<Mojo::ByteStream> inherits all methods from L<Mojo::Base> and implements the
108
-following new ones.
111
+L<Mojo::ByteStream> implements the following methods.
109 112
 
110 113
 =head2 new
111 114
 
... ...
@@ -219,7 +222,7 @@ Print bytestream to handle and append a newline, defaults to C<STDOUT>.
219 222
 
220 223
 =head2 secure_compare
221 224
 
222
-  my $success = $stream->secure_compare($str);
225
+  my $bool = $stream->secure_compare($str);
223 226
 
224 227
 Compare bytestream with L<Mojo::Util/"secure_compare">.
225 228
 
... ...
@@ -263,9 +266,10 @@ Write all data from bytestream at once to file with L<Mojo::Util/"spurt">.
263 266
 
264 267
   my $collection = $stream->split(',');
265 268
 
266
-Turn bytestream into L<Mojo::Collection>.
269
+Turn bytestream into L<Mojo::Collection> object containing L<Mojo::ByteStream>
270
+objects.
267 271
 
268
-  b('a,b,c')->split(',')->pluck('quote')->join(',')->say;
272
+  b('a,b,c')->split(',')->quote->join(',')->say;
269 273
 
270 274
 =head2 squish
271 275
 
... ...
@@ -275,6 +279,12 @@ Trim whitespace characters from both ends of bytestream and then change all
275 279
 consecutive groups of whitespace into one space each with
276 280
 L<Mojo::Util/"squish">.
277 281
 
282
+=head2 tap
283
+
284
+  $stream = $stream->tap(sub {...});
285
+
286
+Alias for L<Mojo::Base/"tap">.
287
+
278 288
 =head2 to_string
279 289
 
280 290
   my $str = $stream->to_string;
... ...
@@ -327,6 +337,12 @@ bytestream with L<Mojo::Util/"xml_escape">.
327 337
 
328 338
 XOR encode bytestream with L<Mojo::Util/"xor_encode">.
329 339
 
340
+=head1 BYTESTREAM
341
+
342
+Direct scalar reference access to the bytestream is also possible.
343
+
344
+  $$stream .= 'foo';
345
+
330 346
 =head1 SEE ALSO
331 347
 
332 348
 L<Mojolicious>, L<Mojolicious::Guides>, L<http://mojolicio.us>.
+2
mojo/lib/Mojo/Cache.pm
... ...
@@ -19,6 +19,8 @@ sub set {
19 19
 
20 20
 1;
21 21
 
22
+=encoding utf8
23
+
22 24
 =head1 NAME
23 25
 
24 26
 Mojo::Cache - Naive in-memory cache
+76 -23
mojo/lib/Mojo/Collection.pm
... ...
@@ -1,16 +1,29 @@
1 1
 package Mojo::Collection;
2
-use Mojo::Base -base;
3
-use overload
4
-  'bool'   => sub {1},
5
-  '""'     => sub { shift->join("\n") },
6
-  fallback => 1;
2
+use Mojo::Base -strict;
3
+use overload bool => sub {1}, '""' => sub { shift->join("\n") }, fallback => 1;
7 4
 
5
+use Carp 'croak';
8 6
 use Exporter 'import';
9 7
 use List::Util;
10 8
 use Mojo::ByteStream;
9
+use Scalar::Util 'blessed';
11 10
 
12 11
 our @EXPORT_OK = ('c');
13 12
 
13
+sub AUTOLOAD {
14
+  my $self = shift;
15
+
16
+  my ($package, $method) = our $AUTOLOAD =~ /^([\w:]+)::(\w+)$/;
17
+  croak "Undefined subroutine &${package}::$method called"
18
+    unless blessed $self && $self->isa(__PACKAGE__);
19
+
20
+  croak qq{Can't locate object method "$method" via package "$package"}
21
+    unless @$self;
22
+  return $self->pluck($method, @_);
23
+}
24
+
25
+sub DESTROY { }
26
+
14 27
 sub new {
15 28
   my $class = shift;
16 29
   return bless [@_], ref $class || $class;
... ...
@@ -18,6 +31,10 @@ sub new {
18 31
 
19 32
 sub c { __PACKAGE__->new(@_) }
20 33
 
34
+sub compact {
35
+  shift->grep(sub { length(defined $_ ? $_ : '') });
36
+}
37
+
21 38
 sub each {
22 39
   my ($self, $cb) = @_;
23 40
   return @$self unless $cb;
... ...
@@ -33,16 +50,15 @@ sub first {
33 50
   return List::Util::first { $_ =~ $cb } @$self;
34 51
 }
35 52
 
53
+sub flatten { $_[0]->new(_flatten(@{$_[0]})) }
54
+
36 55
 sub grep {
37 56
   my ($self, $cb) = @_;
38 57
   return $self->new(grep { $cb->($_) } @$self) if ref $cb eq 'CODE';
39 58
   return $self->new(grep { $_ =~ $cb } @$self);
40 59
 }
41 60
 
42
-sub join {
43
-  my ($self, $expr) = @_;
44
-  return Mojo::ByteStream->new(join $expr, map({"$_"} @$self));
45
-}
61
+sub join { Mojo::ByteStream->new(join $_[1], map({"$_"} @{$_[0]})) }
46 62
 
47 63
 sub map {
48 64
   my ($self, $cb) = @_;
... ...
@@ -54,15 +70,9 @@ sub pluck {
54 70
   return $self->map(sub { $_->$method(@args) });
55 71
 }
56 72
 
57
-sub reverse {
58
-  my $self = shift;
59
-  return $self->new(reverse @$self);
60
-}
73
+sub reverse { $_[0]->new(reverse @{$_[0]}) }
61 74
 
62
-sub shuffle {
63
-  my $self = shift;
64
-  return $self->new(List::Util::shuffle @$self);
65
-}
75
+sub shuffle { $_[0]->new(List::Util::shuffle @{$_[0]}) }
66 76
 
67 77
 sub size { scalar @{$_[0]} }
68 78
 
... ...
@@ -76,14 +86,24 @@ sub sort {
76 86
   return $self->new($cb ? sort { $a->$cb($b) } @$self : sort @$self);
77 87
 }
78 88
 
89
+sub tap { shift->Mojo::Base::tap(@_) }
90
+
79 91
 sub uniq {
80 92
   my $self = shift;
81 93
   my %seen;
82 94
   return $self->grep(sub { !$seen{$_}++ });
83 95
 }
84 96
 
97
+sub _flatten {
98
+  map { _ref($_) ? _flatten(@$_) : $_ } @_;
99
+}
100
+
101
+sub _ref { ref $_[0] && (ref $_[0] eq 'ARRAY' || $_[0]->isa(__PACKAGE__)) }
102
+
85 103
 1;
86 104
 
105
+=encoding utf8
106
+
87 107
 =head1 NAME
88 108
 
89 109
 Mojo::Collection - Collection
... ...
@@ -119,8 +139,7 @@ Construct a new array-based L<Mojo::Collection> object.
119 139
 
120 140
 =head1 METHODS
121 141
 
122
-L<Mojo::Collection> inherits all methods from L<Mojo::Base> and implements the
123
-following new ones.
142
+L<Mojo::Collection> implements the following methods.
124 143
 
125 144
 =head2 new
126 145
 
... ...
@@ -128,12 +147,21 @@ following new ones.
128 147
 
129 148
 Construct a new array-based L<Mojo::Collection> object.
130 149
 
150
+=head2 compact
151
+
152
+  my $new = $collection->compact;
153
+
154
+Create a new collection with all elements that are defined and not an empty
155
+string.
156
+
131 157
 =head2 each
132 158
 
133 159
   my @elements = $collection->each;
134 160
   $collection  = $collection->each(sub {...});
135 161
 
136
-Evaluate callback for each element in collection.
162
+Evaluate callback for each element in collection or return all elements as a
163
+list if none has been provided. The element will be the first argument passed
164
+to the callback and is also available as C<$_>.
137 165
 
138 166
   $collection->each(sub {
139 167
     my ($e, $count) = @_;
... ...
@@ -148,10 +176,18 @@ Evaluate callback for each element in collection.
148 176
 
149 177
 Evaluate regular expression or callback for each element in collection and
150 178
 return the first one that matched the regular expression, or for which the
151
-callback returned true.
179
+callback returned true. The element will be the first argument passed to the
180
+callback and is also available as C<$_>.
152 181
 
153 182
   my $five = $collection->first(sub { $_ == 5 });
154 183
 
184
+=head2 flatten
185
+
186
+  my $new = $collection->flatten;
187
+
188
+Flatten nested collections/arrays recursively and create a new collection with
189
+all elements.
190
+
155 191
 =head2 grep
156 192
 
157 193
   my $new = $collection->grep(qr/foo/);
... ...
@@ -159,7 +195,8 @@ callback returned true.
159 195
 
160 196
 Evaluate regular expression or callback for each element in collection and
161 197
 create a new collection with all elements that matched the regular expression,
162
-or for which the callback returned true.
198
+or for which the callback returned true. The element will be the first
199
+argument passed to the callback and is also available as C<$_>.
163 200
 
164 201
   my $interesting = $collection->grep(qr/mojo/i);
165 202
 
... ...
@@ -176,7 +213,8 @@ Turn collection into L<Mojo::ByteStream>.
176 213
   my $new = $collection->map(sub {...});
177 214
 
178 215
 Evaluate callback for each element in collection and create a new collection
179
-from the results.
216
+from the results. The element will be the first argument passed to the
217
+callback and is also available as C<$_>.
180 218
 
181 219
   my $doubled = $collection->map(sub { $_ * 2 });
182 220
 
... ...
@@ -225,12 +263,27 @@ from the results.
225 263
 
226 264
   my $insensitive = $collection->sort(sub { uc(shift) cmp uc(shift) });
227 265
 
266
+=head2 tap
267
+
268
+  $collection = $collection->tap(sub {...});
269
+
270
+Alias for L<Mojo::Base/"tap">.
271
+
228 272
 =head2 uniq
229 273
 
230 274
   my $new = $collection->uniq;
231 275
 
232 276
 Create a new collection without duplicate elements.
233 277
 
278
+=head1 ELEMENT METHODS
279
+
280
+In addition to the methods above, you can also call methods provided by all
281
+elements in the collection directly and create a new collection from the
282
+results, similar to L</"pluck">.
283
+
284
+  push @$collection, Mojo::DOM->new("<div><h1>$_</h1></div>") for 1 .. 9;
285
+  say $collection->at('h1')->type('h2')->prepend_content('Test ')->root;
286
+
234 287
 =head1 ELEMENTS
235 288
 
236 289
 Direct array reference access to elements is also possible.
+22 -20
mojo/lib/Mojo/Content.pm
... ...
@@ -18,7 +18,7 @@ sub body_size { croak 'Method "body_size" not implemented by subclass' }
18 18
 
19 19
 sub boundary {
20 20
   return undef unless my $type = shift->headers->content_type;
21
-  $type =~ m!multipart.*boundary=(?:"([^"]+)"|([\w'(),.:?\-+/]+))!i
21
+  $type =~ m!multipart.*boundary\s*=\s*(?:"([^"]+)"|([\w'(),.:?\-+/]+))!i
22 22
     and return defined $1 ? $1 : $2;
23 23
   return undef;
24 24
 }
... ...
@@ -27,8 +27,8 @@ 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 = do {my $tmp = shift->headers->content_type; defined $tmp ? $tmp : ''};
31
-  return $type =~ /charset="?([^"\s;]+)"?/i ? $1 : undef;
30
+  my $type = do { my $type = shift->headers->content_type; defined $type ? $type : ''};
31
+  return $type =~ /charset\s*=\s*"?([^"\s;]+)"?/i ? $1 : undef;
32 32
 }
33 33
 
34 34
 sub clone {
... ...
@@ -220,7 +220,7 @@ sub _parse_chunked {
220 220
     # Start new chunk (ignore the chunk extension)
221 221
     unless ($self->{chunk_len}) {
222 222
       last
223
-        unless $self->{pre_buffer} =~ s/^(?:\x0d?\x0a)?([[:xdigit:]]+).*\x0a//;
223
+        unless $self->{pre_buffer} =~ s/^(?:\x0d?\x0a)?([0-9a-fA-F]+).*\x0a//;
224 224
       next if $self->{chunk_len} = hex $1;
225 225
 
226 226
       # Last chunk
... ...
@@ -306,6 +306,8 @@ sub _uncompress {
306 306
 
307 307
 1;
308 308
 
309
+=encoding utf8
310
+
309 311
 =head1 NAME
310 312
 
311 313
 Mojo::Content - HTTP content base class
... ...
@@ -378,8 +380,8 @@ L<Mojo::Content> implements the following attributes.
378 380
 
379 381
 =head2 auto_relax
380 382
 
381
-  my $relax = $content->auto_relax;
382
-  $content  = $content->auto_relax(1);
383
+  my $bool = $content->auto_relax;
384
+  $content = $content->auto_relax($bool);
383 385
 
384 386
 Try to detect when relaxed parsing is necessary.
385 387
 
... ...
@@ -408,16 +410,16 @@ value of the MOJO_MAX_LEFTOVER_SIZE environment variable or C<262144>.
408 410
 
409 411
 =head2 relaxed
410 412
 
411
-  my $relaxed = $content->relaxed;
412
-  $content    = $content->relaxed(1);
413
+  my $bool = $content->relaxed;
414
+  $content = $content->relaxed($bool);
413 415
 
414 416
 Activate relaxed parsing for responses that are terminated with a connection
415 417
 close.
416 418
 
417 419
 =head2 skip_body
418 420
 
419
-  my $skip = $content->skip_body;
420
-  $content = $content->skip_body(1);
421
+  my $bool = $content->skip_body;
422
+  $content = $content->skip_body($bool);
421 423
 
422 424
 Skip body parsing and finish after headers.
423 425
 
... ...
@@ -428,7 +430,7 @@ implements the following new ones.
428 430
 
429 431
 =head2 body_contains
430 432
 
431
-  my $success = $content->body_contains('foo bar baz');
433
+  my $bool = $content->body_contains('foo bar baz');
432 434
 
433 435
 Check if content contains a specific string. Meant to be overloaded in a
434 436
 subclass.
... ...
@@ -496,34 +498,34 @@ Size of headers in bytes.
496 498
 
497 499
 =head2 is_chunked
498 500
 
499
-  my $success = $content->is_chunked;
501
+  my $bool = $content->is_chunked;
500 502
 
501 503
 Check if content is chunked.
502 504
 
503 505
 =head2 is_compressed
504 506
 
505
-  my $success = $content->is_compressed;
507
+  my $bool = $content->is_compressed;
506 508
 
507 509
 Check if content is C<gzip> compressed.
508 510
 
509 511
 =head2 is_dynamic
510 512
 
511
-  my $success = $content->is_dynamic;
513
+  my $bool = $content->is_dynamic;
512 514
 
513
-Check if content will be dynamically generated, which prevents C<clone> from
514
-working.
515
+Check if content will be dynamically generated, which prevents L</"clone">
516
+from working.
515 517
 
516 518
 =head2 is_finished
517 519
 
518
-  my $success = $content->is_finished;
520
+  my $bool = $content->is_finished;
519 521
 
520 522
 Check if parser is finished.
521 523
 
522 524
 =head2 is_limit_exceeded
523 525
 
524
-  my $success = $content->is_limit_exceeded;
526
+  my $bool = $content->is_limit_exceeded;
525 527
 
526
-Check if buffer has exceeded C<max_buffer_size>.
528
+Check if buffer has exceeded L</"max_buffer_size">.
527 529
 
528 530
 =head2 is_multipart
529 531
 
... ...
@@ -533,7 +535,7 @@ False.
533 535
 
534 536
 =head2 is_parsing_body
535 537
 
536
-  my $success = $content->is_parsing_body;
538
+  my $bool = $content->is_parsing_body;
537 539
 
538 540
 Check if body parsing started yet.
539 541
 
+5 -3
mojo/lib/Mojo/Content/MultiPart.pm
... ...
@@ -45,7 +45,7 @@ sub build_boundary {
45 45
   my $boundary;
46 46
   my $size = 1;
47 47
   while (1) {
48
-    $boundary = b64_encode join('', map chr(rand(256)), 1 .. $size++ * 3);
48
+    $boundary = b64_encode join('', map chr(rand 256), 1 .. $size++ * 3);
49 49
     $boundary =~ s/\W/X/g;
50 50
     last unless $self->body_contains($boundary);
51 51
   }
... ...
@@ -199,6 +199,8 @@ sub _read {
199 199
 
200 200
 1;
201 201
 
202
+=encoding utf8
203
+
202 204
 =head1 NAME
203 205
 
204 206
 Mojo::Content::MultiPart - HTTP multipart content
... ...
@@ -258,12 +260,12 @@ implements the following new ones.
258 260
 
259 261
   my $multi = Mojo::Content::MultiPart->new;
260 262
 
261
-Construct a new L<Mojo::Content::MultiPart> object and subscribe to C<read>
263
+Construct a new L<Mojo::Content::MultiPart> object and subscribe to L</"read">
262 264
 event with default content parser.
263 265
 
264 266
 =head2 body_contains
265 267
 
266
-  my $success = $multi->body_contains('foobarbaz');
268
+  my $bool = $multi->body_contains('foobarbaz');
267 269
 
268 270
 Check if content parts contain a specific string.
269 271
 
+6 -4
mojo/lib/Mojo/Content/Single.pm
... ...
@@ -46,13 +46,15 @@ sub parse {
46 46
 
47 47
   # Content needs to be upgraded to multipart
48 48
   $self->unsubscribe(read => $self->{read});
49
-  my $multi = Mojo::Content::MultiPart->new($self);
49
+  my $multi = Mojo::Content::MultiPart->new(%$self);
50 50
   $self->emit(upgrade => $multi);
51 51
   return $multi->parse;
52 52
 }
53 53
 
54 54
 1;
55 55
 
56
+=encoding utf8
57
+
56 58
 =head1 NAME
57 59
 
58 60
 Mojo::Content::Single - HTTP content
... ...
@@ -120,12 +122,12 @@ implements the following new ones.
120 122
 
121 123
   my $single = Mojo::Content::Single->new;
122 124
 
123
-Construct a new L<Mojo::Content::Single> object and subscribe to C<read> event
124
-with default content parser.
125
+Construct a new L<Mojo::Content::Single> object and subscribe to L</"read">
126
+event with default content parser.
125 127
 
126 128
 =head2 body_contains
127 129
 
128
-  my $success = $single->body_contains('1234567');
130
+  my $bool = $single->body_contains('1234567');
129 131
 
130 132
 Check if content contains a specific string.
131 133
 
+3 -32
mojo/lib/Mojo/Cookie.pm
... ...
@@ -1,47 +1,18 @@
1 1
 package Mojo::Cookie;
2 2
 use Mojo::Base -base;
3
-use overload
4
-  'bool'   => sub {1},
5
-  '""'     => sub { shift->to_string },
6
-  fallback => 1;
3
+use overload bool => sub {1}, '""' => sub { shift->to_string }, fallback => 1;
7 4
 
8 5
 use Carp 'croak';
9
-use Mojo::Util 'unquote';
10 6
 
11 7
 has [qw(name value)];
12 8
 
13 9
 sub parse     { croak 'Method "parse" not implemented by subclass' }
14 10
 sub to_string { croak 'Method "to_string" not implemented by subclass' }
15 11
 
16
-sub _tokenize {
17
-  my ($self, $str) = @_;
18
-
19
-  # Nibbling parser
20
-  my (@tree, @token);
21
-  while ($str =~ s/^\s*([^=;,]+)\s*=?\s*//) {
22
-    my $name = $1;
23
-
24
-    # "expires" is a special case, thank you Netscape...
25
-    $str =~ s/^([^;,]+,?[^;,]+)/"$1"/ if $name =~ /^expires$/i;
26
-
27
-    # Value
28
-    my $value;
29
-    $value = unquote $1 if $str =~ s/^("(?:\\\\|\\"|[^"])+"|[^;,]+)\s*//;
30
-    push @token, [$name, $value];
31
-
32
-    # Separator
33
-    $str =~ s/^\s*;\s*//;
34
-    next unless $str =~ s/^\s*,\s*//;
35
-    push @tree, [@token];
36
-    @token = ();
37
-  }
38
-
39
-  # Take care of final token
40
-  return @token ? (@tree, \@token) : @tree;
41
-}
42
-
43 12
 1;
44 13
 
14
+=encoding utf8
15
+
45 16
 =head1 NAME
46 17
 
47 18
 Mojo::Cookie - HTTP cookie base class
+8 -6
mojo/lib/Mojo/Cookie/Request.pm
... ...
@@ -1,14 +1,15 @@
1 1
 package Mojo::Cookie::Request;
2 2
 use Mojo::Base 'Mojo::Cookie';
3 3
 
4
-use Mojo::Util 'quote';
4
+use Mojo::Util qw(quote split_header);
5 5
 
6 6
 sub parse {
7 7
   my ($self, $str) = @_;
8 8
 
9 9
   my @cookies;
10
-  for my $token (map {@$_} $self->_tokenize(defined $str ? $str : '')) {
11
-    my ($name, $value) = @$token;
10
+  my @pairs = map {@$_} @{split_header(defined $str? $str: '')};
11
+  while (@pairs) {
12
+    my ($name, $value) = (shift @pairs, shift @pairs);
12 13
     next if $name =~ /^\$/;
13 14
     push @cookies, $self->new(name => $name, value => defined $value ? $value : '');
14 15
   }
... ...
@@ -18,14 +19,15 @@ sub parse {
18 19
 
19 20
 sub to_string {
20 21
   my $self = shift;
21
-  return '' unless my $name = $self->name;
22
+  return '' unless length(my $name = defined $self->name ? $self->name : '');
22 23
   my $value = defined $self->value ? $self->value : '';
23
-  $value = $value =~ /[,;"]/ ? quote($value) : $value;
24
-  return "$name=$value";
24
+  return join '=', $name, $value =~ /[,;" ]/ ? quote($value) : $value;
25 25
 }
26 26
 
27 27
 1;
28 28
 
29
+=encoding utf8
30
+
29 31
 =head1 NAME
30 32
 
31 33
 Mojo::Cookie::Request - HTTP request cookie
+38 -22
mojo/lib/Mojo/Cookie/Response.pm
... ...
@@ -2,9 +2,9 @@ package Mojo::Cookie::Response;
2 2
 use Mojo::Base 'Mojo::Cookie';
3 3
 
4 4
 use Mojo::Date;
5
-use Mojo::Util 'quote';
5
+use Mojo::Util qw(quote split_header);
6 6
 
7
-has [qw(domain httponly max_age path secure)];
7
+has [qw(domain httponly max_age origin path secure)];
8 8
 
9 9
 sub expires {
10 10
   my $self = shift;
... ...
@@ -22,21 +22,29 @@ sub parse {
22 22
   my ($self, $str) = @_;
23 23
 
24 24
   my @cookies;
25
-  for my $token ($self->_tokenize(defined $str ? $str : '')) {
26
-    for my $i (0 .. $#$token) {
27
-      my ($name, $value) = @{$token->[$i]};
25
+  my $tree = split_header(defined $str ? $str : '');
26
+  while (my $pairs = shift @$tree) {
27
+    my $i = 0;
28
+    while (@$pairs) {
29
+      my ($name, $value) = (shift @$pairs, shift @$pairs);
30
+
31
+      # "expires" is a special case, thank you Netscape...
32
+      if ($name =~ /^expires$/i) {
33
+        push @$pairs, @{my $elem = shift @$tree; defined $elem ? $elem : []};
34
+        my $len = (defined $pairs->[0] ? $pairs->[0] : '') =~ /-/ ? 6 : 10;
35
+        $value .= join ' ', ',', grep {defined} splice @$pairs, 0, $len;
36
+      }
28 37
 
29 38
       # This will only run once
30 39
       push @cookies, $self->new(name => $name, value => defined $value ? $value : '') and next
31
-        unless $i;
40
+        unless $i++;
32 41
 
33 42
       # Attributes (Netscape and RFC 6265)
34
-      my @match
35
-        = $name =~ /^(expires|domain|path|secure|Max-Age|HttpOnly)$/msi;
36
-      next unless @match;
37
-      my $attr = lc $match[0];
38
-      $attr =~ tr/-/_/;
39
-      $cookies[-1]->$attr($attr =~ /(?:secure|HttpOnly)/i ? 1 : $value);
43
+      next unless $name =~ /^(expires|domain|path|secure|max-age|httponly)$/i;
44
+      my $attr = lc $1;
45
+      $attr = 'max_age' if $attr eq 'max-age';
46
+      $cookies[-1]
47
+        ->$attr($attr eq 'secure' || $attr eq 'httponly' ? 1 : $value);
40 48
     }
41 49
   }
42 50
 
... ...
@@ -47,10 +55,9 @@ sub to_string {
47 55
   my $self = shift;
48 56
 
49 57
   # Name and value (Netscape)
50
-  return '' unless my $name = $self->name;
58
+  return '' unless length(my $name = defined $self->name ? $self->name : '');
51 59
   my $value = defined $self->value ? $self->value : '';
52
-  $value = $value =~ /[,;"]/ ? quote($value) : $value;
53
-  my $cookie = "$name=$value";
60
+  my $cookie = join '=', $name, $value =~ /[,;" ]/ ? quote($value) : $value;
54 61
 
55 62
   # "expires" (Netscape)
56 63
   if (defined(my $e = $self->expires)) { $cookie .= "; expires=$e" }
... ...
@@ -62,19 +69,21 @@ sub to_string {
62 69
   if (my $path = $self->path) { $cookie .= "; path=$path" }
63 70
 
64 71
   # "secure" (Netscape)
65
-  if (my $secure = $self->secure) { $cookie .= "; secure" }
72
+  $cookie .= "; secure" if $self->secure;
66 73
 
67 74
   # "Max-Age" (RFC 6265)
68
-  if (defined(my $m = $self->max_age)) { $cookie .= "; Max-Age=$m" }
75
+  if (defined(my $max = $self->max_age)) { $cookie .= "; Max-Age=$max" }
69 76
 
70 77
   # "HttpOnly" (RFC 6265)
71
-  if (my $httponly = $self->httponly) { $cookie .= "; HttpOnly" }
78
+  $cookie .= "; HttpOnly" if $self->httponly;
72 79
 
73 80
   return $cookie;
74 81
 }
75 82
 
76 83
 1;
77 84
 
85
+=encoding utf8
86
+
78 87
 =head1 NAME
79 88
 
80 89
 Mojo::Cookie::Response - HTTP response cookie
... ...
@@ -107,8 +116,8 @@ Cookie domain.
107 116
 
108 117
 =head2 httponly
109 118
 
110
-  my $httponly = $cookie->httponly;
111
-  $cookie      = $cookie->httponly(1);
119
+  my $bool = $cookie->httponly;
120
+  $cookie  = $cookie->httponly($bool);
112 121
 
113 122
 HttpOnly flag, which can prevent client-side scripts from accessing this
114 123
 cookie.
... ...
@@ -120,6 +129,13 @@ cookie.
120 129
 
121 130
 Max age for cookie.
122 131
 
132
+=head2 origin
133
+
134
+  my $origin = $cookie->origin;
135
+  $cookie    = $cookie->origin('mojolicio.us');
136
+
137
+Origin of the cookie.
138
+
123 139
 =head2 path
124 140
 
125 141
   my $path = $cookie->path;
... ...
@@ -129,8 +145,8 @@ Cookie path.
129 145
 
130 146
 =head2 secure
131 147
 
132
-  my $secure = $cookie->secure;
133
-  $cookie    = $cookie->secure(1);
148
+  my $bool = $cookie->secure;
149
+  $cookie  = $cookie->secure($bool);
134 150
 
135 151
 Secure flag, which instructs browsers to only send this cookie over HTTPS
136 152
 connections.
+229 -158
mojo/lib/Mojo/DOM.pm
... ...
@@ -1,8 +1,8 @@
1 1
 package Mojo::DOM;
2
-use Mojo::Base -base;
2
+use Mojo::Base -strict;
3 3
 use overload
4
-  '%{}'    => sub { shift->attrs },
5
-  'bool'   => sub {1},
4
+  '%{}'    => sub { shift->attr },
5
+  bool     => sub {1},
6 6
   '""'     => sub { shift->to_xml },
7 7
   fallback => 1;
8 8
 
... ...
@@ -36,23 +36,22 @@ sub new {
36 36
   return @_ ? $self->parse(@_) : $self;
37 37
 }
38 38
 
39
-sub all_text {
40
-  my $tree = shift->tree;
41
-  return _text(_elements($tree), 1, _trim($tree, @_));
42
-}
39
+sub all_text { shift->_content(1, @_) }
40
+
41
+sub ancestors { _select($_[0]->_collect(_ancestors($_[0]->tree)), $_[1]) }
43 42
 
44 43
 sub append { shift->_add(1, @_) }
45 44
 
46 45
 sub append_content {
47 46
   my ($self, $new) = @_;
48 47
   my $tree = $self->tree;
49
-  push @$tree, @{_parent($self->_parse("$new"), $tree)};
48
+  push @$tree, _link($self->_parse("$new"), $tree);
50 49
   return $self;
51 50
 }
52 51
 
53 52
 sub at { shift->find(@_)->[0] }
54 53
 
55
-sub attrs {
54
+sub attr {
56 55
   my $self = shift;
57 56
 
58 57
   # Hash
... ...
@@ -70,45 +69,35 @@ sub attrs {
70 69
 }
71 70
 
72 71
 sub children {
73
-  my ($self, $type) = @_;
74
-
75
-  my @children;
76
-  my $xml  = $self->xml;
77
-  my $tree = $self->tree;
78
-  for my $e (@$tree[($tree->[0] eq 'root' ? 1 : 4) .. $#$tree]) {
79
-
80
-    # Make sure child is the right type
81
-    next if $e->[0] ne 'tag' || (defined $type && $e->[1] ne $type);
82
-    push @children, $self->new->tree($e)->xml($xml);
83
-  }
84
-
85
-  return Mojo::Collection->new(@children);
72
+  my $self = shift;
73
+  return _select(
74
+    $self->_collect(grep { $_->[0] eq 'tag' } _nodes($self->tree)), @_);
86 75
 }
87 76
 
88 77
 sub content_xml {
89 78
   my $self = shift;
90
-
91
-  # Render children individually
92
-  my $tree = $self->tree;
93 79
   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];
80
+  return join '', map { _render($_, $xml) } _nodes($self->tree);
97 81
 }
98 82
 
99 83
 sub find {
100
-  my ($self, $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);
84
+  my $self = shift;
85
+  my $results = Mojo::DOM::CSS->new(tree => $self->tree)->select(@_);
86
+  return $self->_collect(@$results);
87
+}
88
+
89
+sub match {
90
+  my $self = shift;
91
+  return undef unless Mojo::DOM::CSS->new(tree => $self->tree)->match(@_);
92
+  return $self;
105 93
 }
106 94
 
107 95
 sub namespace {
108 96
   my $self = shift;
109 97
 
110
-  # Extract namespace prefix and search parents
111 98
   return '' if (my $current = $self->tree)->[0] eq 'root';
99
+
100
+  # Extract namespace prefix and search parents
112 101
   my $ns = $current->[1] =~ /^(.*?):/ ? "xmlns:$1" : undef;
113 102
   while ($current->[0] ne 'root') {
114 103
 
... ...
@@ -119,14 +108,13 @@ sub namespace {
119 108
     # Namespace attribute
120 109
     elsif (defined $attrs->{xmlns}) { return $attrs->{xmlns} }
121 110
 
122
-    # Parent
123 111
     $current = $current->[3];
124 112
   }
125 113
 
126 114
   return '';
127 115
 }
128 116
 
129
-sub next { shift->_sibling(1) }
117
+sub next { shift->_siblings->[1][0] }
130 118
 
131 119
 sub parent {
132 120
   my $self = shift;
... ...
@@ -134,201 +122,228 @@ sub parent {
134 122
   return $self->new->tree($tree->[3])->xml($self->xml);
135 123
 }
136 124
 
137
-sub parse { shift->_html(parse => shift) }
125
+sub parse { shift->_delegate(parse => shift) }
138 126
 
139 127
 sub prepend { shift->_add(0, @_) }
140 128
 
141 129
 sub prepend_content {
142 130
   my ($self, $new) = @_;
143 131
   my $tree = $self->tree;
144
-  splice @$tree, $tree->[0] eq 'root' ? 1 : 4, 0,
145
-    @{_parent($self->_parse("$new"), $tree)};
132
+  splice @$tree, _offset($tree), 0, _link($self->_parse("$new"), $tree);
146 133
   return $self;
147 134
 }
148 135
 
149
-sub previous { shift->_sibling(0) }
136
+sub previous { shift->_siblings->[0][-1] }
150 137
 
151 138
 sub remove { shift->replace('') }
152 139
 
153 140
 sub replace {
154 141
   my ($self, $new) = @_;
155
-
156 142
   my $tree = $self->tree;
157
-  if   ($tree->[0] eq 'root') { return $self->xml(undef)->parse($new) }
158
-  else                        { $new = $self->_parse("$new") }
159
-
160
-  my $parent = $tree->[3];
161
-  my $i = $parent->[0] eq 'root' ? 1 : 4;
162
-  for my $e (@$parent[$i .. $#$parent]) {
163
-    last if $e == $tree;
164
-    $i++;
165
-  }
166
-  splice @$parent, $i, 1, @{_parent($new, $parent)};
167
-
168
-  return $self;
143
+  return $self->xml(undef)->parse($new) if $tree->[0] eq 'root';
144
+  return $self->_replace($tree, $self->_parse("$new"));
169 145
 }
170 146
 
171 147
 sub replace_content {
172 148
   my ($self, $new) = @_;
173 149
   my $tree = $self->tree;
174
-  splice @$tree, $tree->[0] eq 'root' ? 1 : 4, $#$tree,
175
-    @{_parent($self->_parse("$new"), $tree)};
150
+  splice @$tree, _offset($tree), $#$tree, _link($self->_parse("$new"), $tree);
176 151
   return $self;
177 152
 }
178 153
 
179 154
 sub root {
180 155
   my $self = shift;
156
+  return $self unless my $tree = _ancestors($self->tree, 1);
157
+  return $self->new->tree($tree)->xml($self->xml);
158
+}
181 159
 
182
-  my $root = $self->tree;
183
-  while ($root->[0] eq 'tag') {
184
-    last unless my $parent = $root->[3];
185
-    $root = $parent;
186
-  }
160
+sub siblings { _select(Mojo::Collection->new(@{_siblings($_[0], 1)}), $_[1]) }
187 161
 
188
-  return $self->new->tree($root)->xml($self->xml);
162
+sub strip {
163
+  my $self = shift;
164
+  my $tree = $self->tree;
165
+  return $self if $tree->[0] eq 'root';
166
+  return $self->_replace($tree, ['root', _nodes($tree)]);
189 167
 }
190 168
 
191
-sub text {
192
-  my $tree = shift->tree;
193
-  return _text(_elements($tree), 0, _trim($tree, @_));
194
-}
169
+sub tap { shift->Mojo::Base::tap(@_) }
170
+
171
+sub text { shift->_content(0, @_) }
195 172
 
196 173
 sub text_after {
197 174
   my ($self, $trim) = @_;
198 175
 
199
-  # Find following text elements
200 176
   return '' if (my $tree = $self->tree)->[0] eq 'root';
201
-  my (@elements, $started);
202
-  for my $e (@{_elements($tree->[3])}) {
203
-    ++$started and next if $e eq $tree;
177
+
178
+  my (@nodes, $started);
179
+  for my $n (_nodes($tree->[3])) {
180
+    ++$started and next if $n eq $tree;
204 181
     next unless $started;
205
-    last if $e->[0] eq 'tag';
206
-    push @elements, $e;
182
+    last if $n->[0] eq 'tag';
183
+    push @nodes, $n;
207 184
   }
208 185
 
209
-  return _text(\@elements, 0, _trim($tree->[3], $trim));
186
+  return _text(\@nodes, 0, _trim($tree->[3], $trim));
210 187
 }
211 188
 
212 189
 sub text_before {
213 190
   my ($self, $trim) = @_;
214 191
 
215
-  # Find preceding text elements
216 192
   return '' if (my $tree = $self->tree)->[0] eq 'root';
217
-  my @elements;
218
-  for my $e (@{_elements($tree->[3])}) {
219
-    last if $e eq $tree;
220
-    push @elements, $e;
221
-    @elements = () if $e->[0] eq 'tag';
193
+
194
+  my @nodes;
195
+  for my $n (_nodes($tree->[3])) {
196
+    last if $n eq $tree;
197
+    push @nodes, $n;
198
+    @nodes = () if $n->[0] eq 'tag';
222 199
   }
223 200
 
224
-  return _text(\@elements, 0, _trim($tree->[3], $trim));
201
+  return _text(\@nodes, 0, _trim($tree->[3], $trim));
225 202
 }
226 203
 
227 204
 sub to_xml { shift->[0]->render }
228 205
 
229
-sub tree { shift->_html(tree => @_) }
206
+sub tree { shift->_delegate(tree => @_) }
230 207
 
231 208
 sub type {
232 209
   my ($self, $type) = @_;
233
-
234
-  # Get
235 210
   return '' if (my $tree = $self->tree)->[0] eq 'root';
236 211
   return $tree->[1] unless $type;
237
-
238
-  # Set
239 212
   $tree->[1] = $type;
240
-
241 213
   return $self;
242 214
 }
243 215
 
244
-sub xml { shift->_html(xml => @_) }
216
+sub xml { shift->_delegate(xml => @_) }
245 217
 
246 218
 sub _add {
247 219
   my ($self, $offset, $new) = @_;
248 220
 
249
-  # Not a tag
250 221
   return $self if (my $tree = $self->tree)->[0] eq 'root';
251 222
 
252
-  # Find parent
253 223
   my $parent = $tree->[3];
254
-  my $i = $parent->[0] eq 'root' ? 1 : 4;
255
-  for my $e (@$parent[$i .. $#$parent]) {
256
-    last if $e == $tree;
257
-    $i++;
258
-  }
259
-
260
-  # Add children
261
-  splice @$parent, $i + $offset, 0, @{_parent($self->_parse("$new"), $parent)};
224
+  splice @$parent, _parent($parent, $tree) + $offset, 0,
225
+    _link($self->_parse("$new"), $parent);
262 226
 
263 227
   return $self;
264 228
 }
265 229
 
266
-sub _elements {
267
-  return [] unless my $e = shift;
268
-  return [@$e[($e->[0] eq 'root' ? 1 : 4) .. $#$e]];
230
+sub _ancestors {
231
+  my ($tree, $root) = @_;
232
+  my @ancestors;
233
+  push @ancestors, $tree while ($tree->[0] eq 'tag') && ($tree = $tree->[3]);
234
+  return $root ? $ancestors[-1] : @ancestors[0 .. $#ancestors - 1];
235
+}
236
+
237
+sub _collect {
238
+  my $self = shift;
239
+  my $xml  = $self->xml;
240
+  return Mojo::Collection->new(@_)
241
+    ->map(sub { $self->new->tree($_)->xml($xml) });
242
+}
243
+
244
+sub _content {
245
+  my $tree = shift->tree;
246
+  return _text([_nodes($tree)], shift, _trim($tree, @_));
269 247
 }
270 248
 
271
-sub _html {
249
+sub _delegate {
272 250
   my ($self, $method) = (shift, shift);
273 251
   return $self->[0]->$method unless @_;
274 252
   $self->[0]->$method(@_);
275 253
   return $self;
276 254
 }
277 255
 
278
-sub _parent {
256
+sub _link {
279 257
   my ($children, $parent) = @_;
280 258
 
281 259
   # Link parent to children
282 260
   my @new;
283
-  for my $e (@$children[1 .. $#$children]) {
284
-    if ($e->[0] eq 'tag') {
285
-      $e->[3] = $parent;
286
-      weaken $e->[3];
287
-    }
288
-    push @new, $e;
261
+  for my $n (@$children[1 .. $#$children]) {
262
+    push @new, $n;
263
+    next unless $n->[0] eq 'tag';
264
+    $n->[3] = $parent;
265
+    weaken $n->[3];
266
+  }
267
+
268
+  return @new;
269
+}
270
+
271
+sub _nodes {
272
+  return unless my $n = shift;
273
+  return @$n[_offset($n) .. $#$n];
274
+}
275
+
276
+sub _offset { $_[0][0] eq 'root' ? 1 : 4 }
277
+
278
+sub _parent {
279
+  my ($parent, $child) = @_;
280
+
281
+  # Find parent offset for child
282
+  my $i = _offset($parent);
283
+  for my $n (@$parent[$i .. $#$parent]) {
284
+    last if $n == $child;
285
+    $i++;
289 286
   }
290 287
 
291
-  return \@new;
288
+  return $i;
292 289
 }
293 290
 
294 291
 sub _parse { Mojo::DOM::HTML->new(xml => shift->xml)->parse(shift)->tree }
295 292
 
296
-sub _sibling {
297
-  my ($self, $next) = @_;
293
+sub _render { Mojo::DOM::HTML->new(tree => shift, xml => shift)->render }
294
+
295
+sub _replace {
296
+  my ($self, $tree, $new) = @_;
297
+  my $parent = $tree->[3];
298
+  splice @$parent, _parent($parent, $tree), 1, _link($new, $parent);
299
+  return $self->parent;
300
+}
301
+
302
+sub _select {
303
+  my ($self, $selector) = @_;
304
+  return defined $selector ? $self->grep(sub { $_->match($selector) }) : $self;
305
+}
306
+
307
+sub _siblings {
308
+  my ($self, $merge) = @_;
298 309
 
299
-  # Make sure we have a parent
300
-  return undef unless my $parent = $self->parent;
310
+  return $merge ? [] : [[], []] unless my $parent = $self->parent;
301 311
 
302
-  # Find previous or next sibling
303
-  my ($previous, $current);
312
+  my $tree = $self->tree;
313
+  my (@before, @after, $match);
304 314
   for my $child ($parent->children->each) {
305
-    ++$current and next if $child->tree eq $self->tree;
306
-    return $next ? $child : $previous if $current;
307
-    $previous = $child;
315
+    ++$match and next if $child->tree eq $tree;
316
+    $match ? push @after, $child : push @before, $child;
308 317
   }
309 318
 
310
-  # No siblings
311
-  return undef;
319
+  return $merge ? [@before, @after] : [\@before, \@after];
312 320
 }
313 321
 
314 322
 sub _text {
315
-  my ($elements, $recurse, $trim) = @_;
323
+  my ($nodes, $recurse, $trim) = @_;
324
+
325
+  # Merge successive text nodes
326
+  my $i = 0;
327
+  while (my $next = $nodes->[$i + 1]) {
328
+    ++$i and next unless $nodes->[$i][0] eq 'text' && $next->[0] eq 'text';
329
+    splice @$nodes, $i, 2, ['text', $nodes->[$i][1] . $next->[1]];
330
+  }
316 331
 
317 332
   my $text = '';
318
-  for my $e (@$elements) {
319
-    my $type = $e->[0];
333
+  for my $n (@$nodes) {
334
+    my $type = $n->[0];
320 335
 
321 336
     # Nested tag
322 337
     my $content = '';
323 338
     if ($type eq 'tag' && $recurse) {
324
-      $content = _text(_elements($e), 1, _trim($e, $trim));
339
+      $content = _text([_nodes($n)], 1, _trim($n, $trim));
325 340
     }
326 341
 
327 342
     # Text
328
-    elsif ($type eq 'text') { $content = $trim ? squish($e->[1]) : $e->[1] }
343
+    elsif ($type eq 'text') { $content = $trim ? squish($n->[1]) : $n->[1] }
329 344
 
330 345
     # CDATA or raw text
331
-    elsif ($type eq 'cdata' || $type eq 'raw') { $content = $e->[1] }
346
+    elsif ($type eq 'cdata' || $type eq 'raw') { $content = $n->[1] }
332 347
 
333 348
     # Add leading whitespace if punctuation allows it
334 349
     $content = " $content" if $text =~ /\S\z/ && $content =~ /^[^.!?,;:\s]+/;
... ...
@@ -357,6 +372,8 @@ sub _trim {
357 372
 
358 373
 1;
359 374
 
375
+=encoding utf8
376
+
360 377
 =head1 NAME
361 378
 
362 379
 Mojo::DOM - Minimalistic HTML/XML DOM parser with CSS selectors
... ...
@@ -370,7 +387,8 @@ Mojo::DOM - Minimalistic HTML/XML DOM parser with CSS selectors
370 387
 
371 388
   # Find
372 389
   say $dom->at('#b')->text;
373
-  say $dom->find('p')->pluck('text');
390
+  say $dom->find('p')->text;
391
+  say $dom->find('[id]')->attr('id');
374 392
 
375 393
   # Walk
376 394
   say $dom->div->p->[0]->text;
... ...
@@ -386,6 +404,7 @@ Mojo::DOM - Minimalistic HTML/XML DOM parser with CSS selectors
386 404
 
387 405
   # Modify
388 406
   $dom->div->p->[1]->append('<p id="c">C</p>');
407
+  $dom->find(':not(p)')->strip;
389 408
 
390 409
   # Render
391 410
   say "$dom";
... ...
@@ -399,7 +418,7 @@ use it for validation.
399 418
 =head1 CASE SENSITIVITY
400 419
 
401 420
 L<Mojo::DOM> defaults to HTML semantics, that means all tags and attributes
402
-are lowercased and selectors need to be lower case as well.
421
+are lowercased and selectors need to be lowercase as well.
403 422
 
404 423
   my $dom = Mojo::DOM->new('<P ID="greeting">Hi!</P>');
405 424
   say $dom->at('p')->text;
... ...
@@ -412,7 +431,7 @@ into XML mode and everything becomes case sensitive.
412 431
   say $dom->at('P')->text;
413 432
   say $dom->P->{ID};
414 433
 
415
-XML detection can also be disabled with the C<xml> method.
434
+XML detection can also be disabled with the L</"xml"> method.
416 435
 
417 436
   # Force XML semantics
418 437
   $dom->xml(1);
... ...
@@ -422,16 +441,15 @@ XML detection can also be disabled with the C<xml> method.
422 441
 
423 442
 =head1 METHODS
424 443
 
425
-L<Mojo::DOM> inherits all methods from L<Mojo::Base> and implements the
426
-following new ones.
444
+L<Mojo::DOM> implements the following methods.
427 445
 
428 446
 =head2 new
429 447
 
430 448
   my $dom = Mojo::DOM->new;
431 449
   my $dom = Mojo::DOM->new('<foo bar="baz">test</foo>');
432 450
 
433
-Construct a new array-based L<Mojo::DOM> object and C<parse> HTML/XML document
434
-if necessary.
451
+Construct a new array-based L<Mojo::DOM> object and L</"parse"> HTML/XML
452
+fragment if necessary.
435 453
 
436 454
 =head2 all_text
437 455
 
... ...
@@ -447,11 +465,23 @@ enabled by default.
447 465
   # "foo\nbarbaz\n"
448 466
   $dom->parse("<div>foo\n<p>bar</p>baz\n</div>")->div->all_text(0);
449 467
 
468
+=head2 ancestors
469
+
470
+  my $collection = $dom->ancestors;
471
+  my $collection = $dom->ancestors('div');
472
+
473
+Find all ancestors of this element matching the CSS selector and return a
474
+L<Mojo::Collection> object containing these elements as L<Mojo::DOM> objects.
475
+All selectors from L<Mojo::DOM::CSS> are supported.
476
+
477
+  # List types of ancestor elements
478
+  say $dom->ancestors->type;
479
+
450 480
 =head2 append
451 481
 
452 482
   $dom = $dom->append('<p>Hi!</p>');
453 483
 
454
-Append HTML/XML to element.
484
+Append HTML/XML fragment to element.
455 485
 
456 486
   # "<div><h1>A</h1><h2>B</h2></div>"
457 487
   $dom->parse('<div><h1>A</h1></div>')->at('h1')->append('<h2>B</h2>')->root;
... ...
@@ -460,7 +490,7 @@ Append HTML/XML to element.
460 490
 
461 491
   $dom = $dom->append_content('<p>Hi!</p>');
462 492
 
463
-Append HTML/XML to element content.
493
+Append HTML/XML fragment to element content.
464 494
 
465 495
   # "<div><h1>AB</h1></div>"
466 496
   $dom->parse('<div><h1>A</h1></div>')->at('h1')->append_content('B')->root;
... ...
@@ -476,22 +506,26 @@ L<Mojo::DOM::CSS> are supported.
476 506
   # Find first element with "svg" namespace definition
477 507
   my $namespace = $dom->at('[xmlns\:svg]')->{'xmlns:svg'};
478 508
 
479
-=head2 attrs
509
+=head2 attr
480 510
 
481
-  my $attrs = $dom->attrs;
482
-  my $foo   = $dom->attrs('foo');
483
-  $dom      = $dom->attrs({foo => 'bar'});
484
-  $dom      = $dom->attrs(foo => 'bar');
511
+  my $attrs = $dom->attr;
512
+  my $foo   = $dom->attr('foo');
513
+  $dom      = $dom->attr({foo => 'bar'});
514
+  $dom      = $dom->attr(foo => 'bar');
485 515
 
486 516
 Element attributes.
487 517
 
518
+  # List id attributes
519
+  say $dom->find('*')->attr('id')->compact;
520
+
488 521
 =head2 children
489 522
 
490 523
   my $collection = $dom->children;
491 524
   my $collection = $dom->children('div');
492 525
 
493
-Return a L<Mojo::Collection> object containing the children of this element as
494
-L<Mojo::DOM> objects, similar to C<find>.
526
+Find all children of this element matching the CSS selector and return a
527
+L<Mojo::Collection> object containing these elements as L<Mojo::DOM> objects.
528
+All selectors from L<Mojo::DOM::CSS> are supported.
495 529
 
496 530
   # Show type of random child element
497 531
   say $dom->children->shuffle->first->type;
... ...
@@ -517,7 +551,16 @@ L<Mojo::DOM::CSS> are supported.
517 551
   my $id = $dom->find('div')->[23]{id};
518 552
 
519 553
   # Extract information from multiple elements
520
-  my @headers = $dom->find('h1, h2, h3')->pluck('text')->each;
554
+  my @headers = $dom->find('h1, h2, h3')->text->each;
555
+  my @links   = $dom->find('a[href]')->attr('href')->each;
556
+
557
+=head2 match
558
+
559
+  my $result = $dom->match('html title');
560
+
561
+Match the CSS selector against this element and return it as a L<Mojo::DOM>
562
+object or return C<undef> if it didn't match. All selectors from
563
+L<Mojo::DOM::CSS> are supported.
521 564
 
522 565
 =head2 namespace
523 566
 
... ...
@@ -552,7 +595,7 @@ has no parent.
552 595
 
553 596
   $dom = $dom->parse('<foo bar="baz">test</foo>');
554 597
 
555
-Parse HTML/XML document with L<Mojo::DOM::HTML>.
598
+Parse HTML/XML fragment with L<Mojo::DOM::HTML>.
556 599
 
557 600
   # Parse XML
558 601
   my $dom = Mojo::DOM->new->xml(1)->parse($xml);
... ...
@@ -561,7 +604,7 @@ Parse HTML/XML document with L<Mojo::DOM::HTML>.
561 604
 
562 605
   $dom = $dom->prepend('<p>Hi!</p>');
563 606
 
564
-Prepend HTML/XML to element.
607
+Prepend HTML/XML fragment to element.
565 608
 
566 609
   # "<div><h1>A</h1><h2>B</h2></div>"
567 610
   $dom->parse('<div><h2>B</h2></div>')->at('h2')->prepend('<h1>A</h1>')->root;
... ...
@@ -570,7 +613,7 @@ Prepend HTML/XML to element.
570 613
 
571 614
   $dom = $dom->prepend_content('<p>Hi!</p>');
572 615
 
573
-Prepend HTML/XML to element content.
616
+Prepend HTML/XML fragment to element content.
574 617
 
575 618
   # "<div><h2>AB</h2></div>"
576 619
   $dom->parse('<div><h2>B</h2></div>')->at('h2')->prepend_content('A')->root;
... ...
@@ -587,31 +630,31 @@ there are no more siblings.
587 630
 
588 631
 =head2 remove
589 632
 
590
-  my $old = $dom->remove;
633
+  my $parent = $dom->remove;
591 634
 
592
-Remove element and return it as a L<Mojo::DOM> object.
635
+Remove element and return L<Mojo::DOM> object for parent of element.
593 636
 
594 637
   # "<div></div>"
595
-  $dom->parse('<div><h1>A</h1></div>')->at('h1')->remove->root;
638
+  $dom->parse('<div><h1>A</h1></div>')->at('h1')->remove;
596 639
 
597 640
 =head2 replace
598 641
 
599
-  my $old = $dom->replace('<div>test</div>');
642
+  my $parent = $dom->replace('<div>test</div>');
600 643
 
601
-Replace element with HTML/XML and return the replaced element as a
602
-L<Mojo::DOM> object.
644
+Replace element with HTML/XML fragment and return L<Mojo::DOM> object for
645
+parent of element.
603 646
 
604 647
   # "<div><h2>B</h2></div>"
605
-  $dom->parse('<div><h1>A</h1></div>')->at('h1')->replace('<h2>B</h2>')->root;
648
+  $dom->parse('<div><h1>A</h1></div>')->at('h1')->replace('<h2>B</h2>');
606 649
 
607 650
   # "<div></div>"
608
-  $dom->parse('<div><h1>A</h1></div>')->at('h1')->replace('')->root;
651
+  $dom->parse('<div><h1>A</h1></div>')->at('h1')->replace('');
609 652
 
610 653
 =head2 replace_content
611 654
 
612 655
   $dom = $dom->replace_content('<p>test</p>');
613 656
 
614
-Replace element content with HTML/XML.
657
+Replace element content with HTML/XML fragment.
615 658
 
616 659
   # "<div><h1>B</h1></div>"
617 660
   $dom->parse('<div><h1>A</h1></div>')->at('h1')->replace_content('B')->root;
... ...
@@ -625,6 +668,34 @@ Replace element content with HTML/XML.
625 668
 
626 669
 Return L<Mojo::DOM> object for root node.
627 670
 
671
+=head2 siblings
672
+
673
+  my $collection = $dom->siblings;
674
+  my $collection = $dom->siblings('div');
675
+
676
+Find all siblings of this element matching the CSS selector and return a
677
+L<Mojo::Collection> object containing these elements as L<Mojo::DOM> objects.
678
+All selectors from L<Mojo::DOM::CSS> are supported.
679
+
680
+  # List types of sibling elements
681
+  say $dom->siblings->type;
682
+
683
+=head2 strip
684
+
685
+  my $parent = $dom->strip;
686
+
687
+Remove element while preserving its content and return L<Mojo::DOM> object for
688
+parent of element.
689
+
690
+  # "<div>A</div>"
691
+  $dom->parse('<div><h1>A</h1></div>')->at('h1')->strip;
692
+
693
+=head2 tap
694
+
695
+  $dom = $dom->tap(sub {...});
696
+
697
+Alias for L<Mojo::Base/"tap">.
698
+
628 699
 =head2 text
629 700
 
630 701
   my $trimmed   = $dom->text;
... ...
@@ -693,12 +764,12 @@ carefully since it is very dynamic.
693 764
 Element type.
694 765
 
695 766
   # List types of child elements
696
-  say $dom->children->pluck('type');
767
+  say $dom->children->type;
697 768
 
698 769
 =head2 xml
699 770
 
700
-  my $xml = $dom->xml;
701
-  $dom    = $dom->xml(1);
771
+  my $bool = $dom->xml;
772
+  $dom     = $dom->xml($bool);
702 773
 
703 774
 Disable HTML semantics in parser and activate case sensitivity, defaults to
704 775
 auto detection based on processing instructions.
... ...
@@ -711,7 +782,7 @@ L<Mojo::Collection> object, depending on number of children.
711 782
 
712 783
   say $dom->p->text;
713 784
   say $dom->div->[23]->text;
714
-  say $dom->div->pluck('text');
785
+  say $dom->div->text;
715 786
 
716 787
 =head1 ELEMENT ATTRIBUTES
717 788
 
+47 -40
mojo/lib/Mojo/DOM/CSS.pm
... ...
@@ -3,14 +3,14 @@ use Mojo::Base -base;
3 3
 
4 4
 has 'tree';
5 5
 
6
-my $ESCAPE_RE = qr/\\[^[:xdigit:]]|\\[[:xdigit:]]{1,6}/;
6
+my $ESCAPE_RE = qr/\\[^0-9a-fA-F]|\\[0-9a-fA-F]{1,6}/;
7 7
 my $ATTR_RE   = qr/
8 8
   \[
9
-  ((?:$ESCAPE_RE|[\w\-])+)        # Key
9
+  ((?:$ESCAPE_RE|[\w\-])+)           # Key
10 10
   (?:
11
-    (\W)?                         # Operator
11
+    (\W)?                            # Operator
12 12
     =
13
-    (?:"((?:\\"|[^"])+)"|(\S+))   # Value
13
+    (?:"((?:\\"|[^"])*)"|([^\]]+))   # Value
14 14
   )?
15 15
   \]
16 16
 /x;
... ...
@@ -33,6 +33,13 @@ my $TOKEN_RE        = qr/
33 33
   )?
34 34
 /x;
35 35
 
36
+sub match {
37
+  my $self = shift;
38
+  my $tree = $self->tree;
39
+  return undef if $tree->[0] eq 'root';
40
+  return $self->_match($self->_compile(shift), $tree, $tree);
41
+}
42
+
36 43
 sub select {
37 44
   my $self = shift;
38 45
 
... ...
@@ -43,19 +50,14 @@ sub select {
43 50
   while (my $current = shift @queue) {
44 51
     my $type = $current->[0];
45 52
 
46
-    # Root
47
-    if ($type eq 'root') { unshift @queue, @$current[1 .. $#$current] }
48
-
49 53
     # Tag
50
-    elsif ($type eq 'tag') {
54
+    if ($type eq 'tag') {
51 55
       unshift @queue, @$current[4 .. $#$current];
52
-
53
-      # Try all selectors with element
54
-      for my $part (@$pattern) {
55
-        push @results, $current and last
56
-          if $self->_combinator([reverse @$part], $current, $tree);
57
-      }
56
+      push @results, $current if $self->_match($pattern, $current, $tree);
58 57
     }
58
+
59
+    # Root
60
+    elsif ($type eq 'root') { unshift @queue, @$current[1 .. $#$current] }
59 61
   }
60 62
 
61 63
   return \@results;
... ...
@@ -125,7 +127,6 @@ sub _compile {
125 127
     my ($separator, $element, $pc, $attrs, $combinator)
126 128
       = ($1, defined $2 ? $2 : '', $3, $6, $11);
127 129
 
128
-    # Trash
129 130
     next unless $separator || $element || $pc || $attrs || $combinator;
130 131
 
131 132
     # New selector
... ...
@@ -149,12 +150,8 @@ sub _compile {
149 150
 
150 151
     # Class or ID
151 152
     while ($element =~ /$CLASS_ID_RE/g) {
152
-
153
-      # Class
154 153
       push @$selector, ['attr', 'class', $self->_regex('~', $1)] if defined $1;
155
-
156
-      # ID
157
-      push @$selector, ['attr', 'id', $self->_regex('', $2)] if defined $2;
154
+      push @$selector, ['attr', 'id',    $self->_regex('',  $2)] if defined $2;
158 155
     }
159 156
 
160 157
     # Pseudo classes
... ...
@@ -187,28 +184,33 @@ sub _equation {
187 184
   my ($self, $equation) = @_;
188 185
 
189 186
   # "even"
190
-  my $num = [1, 1];
191
-  if ($equation =~ /^even$/i) { $num = [2, 2] }
187
+  return [2, 2] if $equation =~ /^even$/i;
192 188
 
193 189
   # "odd"
194
-  elsif ($equation =~ /^odd$/i) { $num = [2, 1] }
190
+  return [2, 1] if $equation =~ /^odd$/i;
195 191
 
196 192
   # Equation
197
-  elsif ($equation =~ /(?:(-?(?:\d+)?)?(n))?\s*\+?\s*(-?\s*\d+)?\s*$/i) {
198
-    $num->[0] = defined($1) && length($1) ? $1 : $2 ? 1 : 0;
199
-    $num->[0] = -1 if $num->[0] eq '-';
200
-    $num->[1] = defined $3 ? $3 : 0;
201
-    $num->[1] =~ s/\s+//g;
202
-  }
203
-
193
+  my $num = [1, 1];
194
+  return $num if $equation !~ /(?:(-?(?:\d+)?)?(n))?\s*\+?\s*(-?\s*\d+)?\s*$/i;
195
+  $num->[0] = defined($1) && length($1) ? $1 : $2 ? 1 : 0;
196
+  $num->[0] = -1 if $num->[0] eq '-';
197
+  $num->[1] = defined $3 ? $3 : 0;
198
+  $num->[1] =~ s/\s+//g;
204 199
   return $num;
205 200
 }
206 201
 
202
+sub _match {
203
+  my ($self, $pattern, $current, $tree) = @_;
204
+  $self->_combinator([reverse @$_], $current, $tree) and return 1
205
+    for @$pattern;
206
+  return undef;
207
+}
208
+
207 209
 sub _parent {
208 210
   my ($self, $selectors, $current, $tree) = @_;
209 211
   return undef unless my $parent = $current->[3];
210 212
   return undef if $parent->[0] eq 'root';
211
-  return $self->_combinator($selectors, $parent, $tree) ? 1 : undef;
213
+  return $self->_combinator($selectors, $parent, $tree);
212 214
 }
213 215
 
214 216
 sub _pc {
... ...
@@ -251,10 +253,9 @@ sub _pc {
251 253
 
252 254
     # Siblings
253 255
     my $parent = $current->[3];
254
-    my $start = $parent->[0] eq 'root' ? 1 : 4;
255 256
     my @siblings;
256 257
     my $type = $class =~ /of-type$/ ? $current->[1] : undef;
257
-    for my $i ($start .. $#$parent) {
258
+    for my $i (($parent->[0] eq 'root' ? 1 : 4) .. $#$parent) {
258 259
       my $sibling = $parent->[$i];
259 260
       next unless $sibling->[0] eq 'tag';
260 261
       next if defined $type && $type ne $sibling->[1];
... ...
@@ -279,8 +280,7 @@ sub _pc {
279 280
 
280 281
     # Siblings
281 282
     my $parent = $current->[3];
282
-    my $start = $parent->[0] eq 'root' ? 1 : 4;
283
-    for my $i ($start .. $#$parent) {
283
+    for my $i (($parent->[0] eq 'root' ? 1 : 4) .. $#$parent) {
284 284
       my $sibling = $parent->[$i];
285 285
       next if $sibling->[0] ne 'tag' || $sibling eq $current;
286 286
       return undef unless defined $type && $sibling->[1] ne $type;
... ...
@@ -345,8 +345,7 @@ sub _sibling {
345 345
 
346 346
   my $parent = $current->[3];
347 347
   my $found;
348
-  my $start = $parent->[0] eq 'root' ? 1 : 4;
349
-  for my $e (@$parent[$start .. $#$parent]) {
348
+  for my $e (@$parent[($parent->[0] eq 'root' ? 1 : 4) .. $#$parent]) {
350 349
     return $found if $e eq $current;
351 350
     next unless $e->[0] eq 'tag';
352 351
 
... ...
@@ -367,7 +366,7 @@ sub _unescape {
367 366
   $value =~ s/\\\n//g;
368 367
 
369 368
   # Unescape Unicode characters
370
-  $value =~ s/\\([[:xdigit:]]{1,6})\s?/pack('U', hex $1)/ge;
369
+  $value =~ s/\\([0-9a-fA-F]{1,6})\s?/pack('U', hex $1)/ge;
371 370
 
372 371
   # Remove backslash
373 372
   $value =~ s/\\//g;
... ...
@@ -377,6 +376,8 @@ sub _unescape {
377 376
 
378 377
 1;
379 378
 
379
+=encoding utf8
380
+
380 381
 =head1 NAME
381 382
 
382 383
 Mojo::DOM::CSS - CSS selector engine
... ...
@@ -591,7 +592,7 @@ Elements of type C<E>, C<F> and C<G>.
591 592
 
592 593
 An C<E> element whose attributes match all following attribute selectors.
593 594
 
594
-  my $links = $css->select('a[foo^="b"][foo$="ar"]');
595
+  my $links = $css->select('a[foo^=b][foo$=ar]');
595 596
 
596 597
 =head1 ATTRIBUTES
597 598
 
... ...
@@ -610,11 +611,17 @@ carefully since it is very dynamic.
610 611
 L<Mojo::DOM::CSS> inherits all methods from L<Mojo::Base> and implements the
611 612
 following new ones.
612 613
 
614
+=head2 match
615
+
616
+  my $bool = $css->match('head > title');
617
+
618
+Match CSS selector against first node in L</"tree">.
619
+
613 620
 =head2 select
614 621
 
615 622
   my $results = $css->select('head > title');
616 623
 
617
-Run CSS selector against C<tree>.
624
+Run CSS selector against L</"tree">.
618 625
 
619 626
 =head1 SEE ALSO
620 627
 
+57 -63
mojo/lib/Mojo/DOM/HTML.pm
... ...
@@ -8,7 +8,7 @@ has 'xml';
8 8
 has tree => sub { ['root'] };
9 9
 
10 10
 my $ATTR_RE = qr/
11
-  ([^=\s>]+)       # Key
11
+  ([^<>=\s]+)      # Key
12 12
   (?:
13 13
     \s*=\s*
14 14
     (?:
... ...
@@ -40,50 +40,52 @@ my $TOKEN_RE = qr/
40 40
   |
41 41
     <(
42 42
       \s*
43
-      [^>\s]+                                       # Tag
43
+      [^<>\s]+                                      # Tag
44 44
       \s*
45 45
       (?:$ATTR_RE)*                                 # Attributes
46 46
     )>
47
+  |
48
+    (<)                                             # Runaway "<"
47 49
   )??
48 50
 /xis;
49 51
 
50
-# Optional HTML elements
51
-my %OPTIONAL = map { $_ => 1 }
52
-  qw(body colgroup dd head li optgroup option p rt rp tbody td tfoot th);
53
-
54
-# Elements that break HTML paragraphs
52
+# HTML elements that break paragraphs
55 53
 my %PARAGRAPH = map { $_ => 1 } (
56 54
   qw(address article aside blockquote dir div dl fieldset footer form h1 h2),
57
-  qw(h3 h4 h5 h6 header hgroup hr menu nav ol p pre section table ul)
55
+  qw(h3 h4 h5 h6 header hr main menu nav ol p pre section table ul)
58 56
 );
59 57
 
60
-# HTML table elements
61
-my %TABLE = map { $_ => 1 } qw(col colgroup tbody td th thead tr);
58
+# HTML table elements with optional end tags
59
+my %TABLE = map { $_ => 1 } qw(colgroup tbody td tfoot th thead tr);
62 60
 
63
-# HTML void elements
61
+# HTML elements without end tags
64 62
 my %VOID = map { $_ => 1 } (
65
-  qw(area base br col command embed hr img input keygen link meta param),
63
+  qw(area base br col embed hr img input keygen link menuitem meta param),
66 64
   qw(source track wbr)
67 65
 );
68 66
 
69
-# HTML inline elements
70
-my %INLINE = map { $_ => 1 } (
71
-  qw(a abbr acronym applet b basefont bdo big br button cite code del dfn em),
72
-  qw(font i iframe img ins input kbd label map object q s samp script select),
73
-  qw(small span strike strong sub sup textarea tt u var)
67
+# HTML elements categorized as phrasing content (and obsolete inline elements)
68
+my @PHRASING = (
69
+  qw(a abbr area audio b bdi bdo br button canvas cite code data datalist),
70
+  qw(del dfn em embed i iframe img input ins kbd keygen label link map mark),
71
+  qw(math meta meter noscript object output progress q ruby s samp script),
72
+  qw(select small span strong sub sup svg template textarea time u var video),
73
+  qw(wbr)
74 74
 );
75
+my @OBSOLETE = qw(acronym applet basefont big font strike tt);
76
+my %PHRASING = map { $_ => 1 } @OBSOLETE, @PHRASING;
75 77
 
76 78
 sub parse {
77 79
   my ($self, $html) = @_;
78 80
 
79
-  my $tree    = ['root'];
80
-  my $current = $tree;
81
+  my $current = my $tree = ['root'];
81 82
   while ($html =~ m/\G$TOKEN_RE/gcs) {
82
-    my ($text, $pi, $comment, $cdata, $doctype, $tag)
83
-      = ($1, $2, $3, $4, $5, $6);
83
+    my ($text, $pi, $comment, $cdata, $doctype, $tag, $runaway)
84
+      = ($1, $2, $3, $4, $5, $6, $11);
84 85
 
85
-    # Text
86
-    if (length $text) { push @$current, ['text', html_unescape($text)] }
86
+    # Text (and runaway "<")
87
+    $text .= '<' if defined $runaway;
88
+    push @$current, ['text', html_unescape $text] if length $text;
87 89
 
88 90
     # DOCTYPE
89 91
     if ($doctype) { push @$current, ['doctype', $doctype] }
... ...
@@ -124,7 +126,7 @@ sub parse {
124 126
       # Tag
125 127
       $self->_start($start, \%attrs, \$current);
126 128
 
127
-      # Empty element
129
+      # Element without end tag
128 130
       $self->_end($start, \$current)
129 131
         if (!$self->xml && $VOID{$start}) || $attr =~ m!/\s*$!;
130 132
 
... ...
@@ -144,18 +146,12 @@ sub parse {
144 146
 sub render { $_[0]->_render($_[0]->tree) }
145 147
 
146 148
 sub _close {
147
-  my ($self, $current, $tags, $stop) = @_;
148
-  $tags ||= \%TABLE;
149
-  $stop ||= 'table';
149
+  my ($self, $current, $allowed, $scope) = @_;
150 150
 
151
-  # Check if parents need to be closed
151
+  # Close allowed parent elements in scope
152 152
   my $parent = $$current;
153
-  while ($parent->[0] ne 'root' && $parent->[1] ne $stop) {
154
-
155
-    # Close
156
-    $tags->{$parent->[1]} and $self->_end($parent->[1], $current);
157
-
158
-    # Try next
153
+  while ($parent->[0] ne 'root' && $parent->[1] ne $scope) {
154
+    $self->_end($parent->[1], $current) if $allowed->{$parent->[1]};
159 155
     $parent = $parent->[3];
160 156
   }
161 157
 }
... ...
@@ -171,10 +167,9 @@ sub _end {
171 167
     # Right tag
172 168
     ++$found and last if $next->[1] eq $end;
173 169
 
174
-    # Inline elements can only cross other inline elements
175
-    return if !$self->xml && $INLINE{$end} && !$INLINE{$next->[1]};
170
+    # Phrasing content can only cross phrasing content
171
+    return if !$self->xml && $PHRASING{$end} && !$PHRASING{$next->[1]};
176 172
 
177
-    # Parent
178 173
     $next = $next->[3];
179 174
   }
180 175
 
... ...
@@ -189,11 +184,8 @@ sub _end {
189 184
     # Match
190 185
     if ($end eq $$current->[1]) { return $$current = $$current->[3] }
191 186
 
192
-    # Optional elements
193
-    elsif ($OPTIONAL{$$current->[1]}) { $self->_end($$current->[1], $current) }
194
-
195 187
     # Table
196
-    elsif ($end eq 'table') { $self->_close($current) }
188
+    elsif ($end eq 'table') { $self->_close($current, \%TABLE, $end) }
197 189
 
198 190
     # Missing end tag
199 191
     $self->_end($$current->[1], $current);
... ...
@@ -211,19 +203,19 @@ sub _render {
211 203
   return $tree->[1] if $e eq 'raw';
212 204
 
213 205
   # DOCTYPE
214
-  return "<!DOCTYPE" . $tree->[1] . ">" if $e eq 'doctype';
206
+  return '<!DOCTYPE' . $tree->[1] . '>' if $e eq 'doctype';
215 207
 
216 208
   # Comment
217
-  return "<!--" . $tree->[1] . "-->" if $e eq 'comment';
209
+  return '<!--' . $tree->[1] . '-->' if $e eq 'comment';
218 210
 
219 211
   # CDATA
220
-  return "<![CDATA[" . $tree->[1] . "]]>" if $e eq 'cdata';
212
+  return '<![CDATA[' . $tree->[1] . ']]>' if $e eq 'cdata';
221 213
 
222 214
   # Processing instruction
223
-  return "<?" . $tree->[1] . "?>" if $e eq 'pi';
215
+  return '<?' . $tree->[1] . '?>' if $e eq 'pi';
224 216
 
225 217
   # Start tag
226
-  my $start = $e eq 'root' ? 1 : 2;
218
+  my $start   = 1;
227 219
   my $content = '';
228 220
   if ($e eq 'tag') {
229 221
     $start = 4;
... ...
@@ -246,7 +238,7 @@ sub _render {
246 238
     my $attrs = join ' ', @attrs;
247 239
     $content .= " $attrs" if $attrs;
248 240
 
249
-    # Empty tag
241
+    # Element without end tag
250 242
     return $self->xml || $VOID{$tag} ? "$content />" : "$content></$tag>"
251 243
       unless $tree->[4];
252 244
 
... ...
@@ -269,40 +261,40 @@ sub _start {
269 261
   # Autoclose optional HTML elements
270 262
   if (!$self->xml && $$current->[0] ne 'root') {
271 263
 
272
-    # "<li>"
264
+    # "li"
273 265
     if ($start eq 'li') { $self->_close($current, {li => 1}, 'ul') }
274 266
 
275
-    # "<p>"
267
+    # "p"
276 268
     elsif ($PARAGRAPH{$start}) { $self->_end('p', $current) }
277 269
 
278
-    # "<head>"
270
+    # "head"
279 271
     elsif ($start eq 'body') { $self->_end('head', $current) }
280 272
 
281
-    # "<optgroup>"
273
+    # "optgroup"
282 274
     elsif ($start eq 'optgroup') { $self->_end('optgroup', $current) }
283 275
 
284
-    # "<option>"
276
+    # "option"
285 277
     elsif ($start eq 'option') { $self->_end('option', $current) }
286 278
 
287
-    # "<colgroup>", "<thead>", "tbody" and "tfoot"
279
+    # "colgroup", "thead", "tbody" and "tfoot"
288 280
     elsif (grep { $_ eq $start } qw(colgroup thead tbody tfoot)) {
289
-      $self->_close($current);
281
+      $self->_close($current, \%TABLE, 'table');
290 282
     }
291 283
 
292
-    # "<tr>"
293
-    elsif ($start eq 'tr') { $self->_close($current, {tr => 1}) }
284
+    # "tr"
285
+    elsif ($start eq 'tr') { $self->_close($current, {tr => 1}, 'table') }
294 286
 
295
-    # "<th>" and "<td>"
287
+    # "th" and "td"
296 288
     elsif ($start eq 'th' || $start eq 'td') {
297
-      $self->_close($current, {$_ => 1}) for qw(th td);
289
+      $self->_close($current, {$_ => 1}, 'table') for qw(th td);
298 290
     }
299 291
 
300
-    # "<dt>" and "<dd>"
292
+    # "dt" and "dd"
301 293
     elsif ($start eq 'dt' || $start eq 'dd') {
302 294
       $self->_end($_, $current) for qw(dt dd);
303 295
     }
304 296
 
305
-    # "<rt>" and "<rp>"
297
+    # "rt" and "rp"
306 298
     elsif ($start eq 'rt' || $start eq 'rp') {
307 299
       $self->_end($_, $current) for qw(rt rp);
308 300
     }
... ...
@@ -317,6 +309,8 @@ sub _start {
317 309
 
318 310
 1;
319 311
 
312
+=encoding utf8
313
+
320 314
 =head1 NAME
321 315
 
322 316
 Mojo::DOM::HTML - HTML/XML engine
... ...
@@ -348,8 +342,8 @@ carefully since it is very dynamic.
348 342
 
349 343
 =head2 xml
350 344
 
351
-  my $xml = $html->xml;
352
-  $html   = $html->xml(1);
345
+  my $bool = $html->xml;
346
+  $html    = $html->xml($bool);
353 347
 
354 348
 Disable HTML semantics in parser and activate case sensitivity, defaults to
355 349
 auto detection based on processing instructions.
... ...
@@ -363,7 +357,7 @@ following new ones.
363 357
 
364 358
   $html = $html->parse('<foo bar="baz">test</foo>');
365 359
 
366
-Parse HTML/XML document.
360
+Parse HTML/XML fragment.
367 361
 
368 362
 =head2 render
369 363
 
+4 -5
mojo/lib/Mojo/Date.pm
... ...
@@ -1,9 +1,6 @@
1 1
 package Mojo::Date;
2 2
 use Mojo::Base -base;
3
-use overload
4
-  'bool'   => sub {1},
5
-  '""'     => sub { shift->to_string },
6
-  fallback => 1;
3
+use overload bool => sub {1}, '""' => sub { shift->to_string }, fallback => 1;
7 4
 
8 5
 use Time::Local 'timegm';
9 6
 
... ...
@@ -63,6 +60,8 @@ sub to_string {
63 60
 
64 61
 1;
65 62
 
63
+=encoding utf8
64
+
66 65
 =head1 NAME
67 66
 
68 67
 Mojo::Date - HTTP date
... ...
@@ -109,7 +108,7 @@ following new ones.
109 108
   my $date = Mojo::Date->new;
110 109
   my $date = Mojo::Date->new('Sun Nov  6 08:49:37 1994');
111 110
 
112
-Construct a new L<Mojo::Date> object and C<parse> date if necessary.
111
+Construct a new L<Mojo::Date> object and L</"parse"> date if necessary.
113 112
 
114 113
 =head2 parse
115 114
 
+14 -17
mojo/lib/Mojo/EventEmitter.pm
... ...
@@ -9,12 +9,12 @@ sub emit {
9 9
   my ($self, $name) = (shift, shift);
10 10
 
11 11
   if (my $s = $self->{events}{$name}) {
12
-    warn "-- Emit $name in @{[blessed($self)]} (@{[scalar(@$s)]})\n" if DEBUG;
12
+    warn "-- Emit $name in @{[blessed $self]} (@{[scalar @$s]})\n" if DEBUG;
13 13
     for my $cb (@$s) { $self->$cb(@_) }
14 14
   }
15 15
   else {
16
-    warn "-- Emit $name in @{[blessed($self)]} (0)\n" if DEBUG;
17
-    warn $_[0] if $name eq 'error';
16
+    warn "-- Emit $name in @{[blessed $self]} (0)\n" if DEBUG;
17
+    die "@{[blessed $self]}: $_[0]" if $name eq 'error';
18 18
   }
19 19
 
20 20
   return $self;
... ...
@@ -24,22 +24,16 @@ sub emit_safe {
24 24
   my ($self, $name) = (shift, shift);
25 25
 
26 26
   if (my $s = $self->{events}{$name}) {
27
-    warn "-- Emit $name in @{[blessed($self)]} safely (@{[scalar(@$s)]})\n"
27
+    warn "-- Emit $name in @{[blessed $self]} safely (@{[scalar @$s]})\n"
28 28
       if DEBUG;
29 29
     for my $cb (@$s) {
30
-      unless (eval { $self->$cb(@_); 1 }) {
31
-
32
-        # Error event failed
33
-        if ($name eq 'error') { warn qq{Event "error" failed: $@} }
34
-
35
-        # Normal event failed
36
-        else { $self->emit_safe('error', qq{Event "$name" failed: $@}) }
37
-      }
30
+      $self->emit(error => qq{Event "$name" failed: $@})
31
+        unless eval { $self->$cb(@_); 1 };
38 32
     }
39 33
   }
40 34
   else {
41
-    warn "-- Emit $name in @{[blessed($self)]} safely (0)\n" if DEBUG;
42
-    warn $_[0] if $name eq 'error';
35
+    warn "-- Emit $name in @{[blessed $self]} safely (0)\n" if DEBUG;
36
+    die "@{[blessed $self]}: $_[0]" if $name eq 'error';
43 37
   }
44 38
 
45 39
   return $self;
... ...
@@ -76,6 +70,7 @@ sub unsubscribe {
76 70
   # One
77 71
   if ($cb) {
78 72
     $self->{events}{$name} = [grep { $cb ne $_ } @{$self->{events}{$name}}];
73
+    delete $self->{events}{$name} unless @{$self->{events}{$name}};
79 74
   }
80 75
 
81 76
   # All
... ...
@@ -86,6 +81,8 @@ sub unsubscribe {
86 81
 
87 82
 1;
88 83
 
84
+=encoding utf8
85
+
89 86
 =head1 NAME
90 87
 
91 88
 Mojo::EventEmitter - Event emitter base class
... ...
@@ -126,7 +123,7 @@ L<Mojo::EventEmitter> can emit the following events.
126 123
     ...
127 124
   });
128 125
 
129
-Emitted safely for event errors.
126
+Emitted for event errors, fatal if unhandled.
130 127
 
131 128
   $e->on(error => sub {
132 129
     my ($e, $err) = @_;
... ...
@@ -150,11 +147,11 @@ Emit event.
150 147
   $e = $e->emit_safe('foo');
151 148
   $e = $e->emit_safe('foo', 123);
152 149
 
153
-Emit event safely and emit C<error> event on failure.
150
+Emit event safely and emit L</"error"> event on failure.
154 151
 
155 152
 =head2 has_subscribers
156 153
 
157
-  my $success = $e->has_subscribers('foo');
154
+  my $bool = $e->has_subscribers('foo');
158 155
 
159 156
 Check if event has subscribers.
160 157
 
+23 -28
mojo/lib/Mojo/Exception.pm
... ...
@@ -1,9 +1,6 @@
1 1
 package Mojo::Exception;
2 2
 use Mojo::Base -base;
3
-use overload
4
-  'bool'   => sub {1},
5
-  '""'     => sub { shift->to_string },
6
-  fallback => 1;
3
+use overload bool => sub {1}, '""' => sub { shift->to_string }, fallback => 1;
7 4
 
8 5
 use Scalar::Util 'blessed';
9 6
 
... ...
@@ -46,40 +43,36 @@ sub trace {
46 43
 }
47 44
 
48 45
 sub _context {
49
-  my ($self, $line, $lines) = @_;
50
-
51
-  # Wrong file
52
-  return unless defined $lines->[0][$line - 1];
46
+  my ($self, $num, $lines) = @_;
53 47
 
54 48
   # Line
55
-  $self->line([$line]);
56
-  for my $l (@$lines) {
57
-    chomp(my $code = $l->[$line - 1]);
49
+  return unless defined $lines->[0][$num - 1];
50
+  $self->line([$num]);
51
+  for my $line (@$lines) {
52
+    chomp(my $code = $line->[$num - 1]);
58 53
     push @{$self->line}, $code;
59 54
   }
60 55
 
61 56
   # Before
62 57
   for my $i (2 .. 6) {
63
-    last if ((my $previous = $line - $i) < 0);
64
-    if (defined $lines->[0][$previous]) {
65
-      unshift @{$self->lines_before}, [$previous + 1];
66
-      for my $l (@$lines) {
67
-        chomp(my $code = $l->[$previous]);
68
-        push @{$self->lines_before->[0]}, $code;
69
-      }
58
+    last if ((my $previous = $num - $i) < 0);
59
+    next unless defined $lines->[0][$previous];
60
+    unshift @{$self->lines_before}, [$previous + 1];
61
+    for my $line (@$lines) {
62
+      chomp(my $code = $line->[$previous]);
63
+      push @{$self->lines_before->[0]}, $code;
70 64
     }
71 65
   }
72 66
 
73 67
   # After
74 68
   for my $i (0 .. 4) {
75
-    next if ((my $next = $line + $i) < 0);
76
-    if (defined $lines->[0][$next]) {
77
-      push @{$self->lines_after}, [$next + 1];
78
-      for my $l (@$lines) {
79
-        next unless defined(my $code = $l->[$next]);
80
-        chomp $code;
81
-        push @{$self->lines_after->[-1]}, $code;
82
-      }
69
+    next if ((my $next = $num + $i) < 0);
70
+    next unless defined $lines->[0][$next];
71
+    push @{$self->lines_after}, [$next + 1];
72
+    for my $line (@$lines) {
73
+      last unless defined(my $code = $line->[$next]);
74
+      chomp $code;
75
+      push @{$self->lines_after->[-1]}, $code;
83 76
     }
84 77
   }
85 78
 }
... ...
@@ -113,6 +106,8 @@ sub _detect {
113 106
 
114 107
 1;
115 108
 
109
+=encoding utf8
110
+
116 111
 =head1 NAME
117 112
 
118 113
 Mojo::Exception - Exceptions with context
... ...
@@ -172,8 +167,8 @@ Exception message.
172 167
 
173 168
 =head2 verbose
174 169
 
175
-  my $verbose = $e->verbose;
176
-  $e          = $e->verbose(1);
170
+  my $bool = $e->verbose;
171
+  $e       = $e->verbose($bool);
177 172
 
178 173
 Render exception with context.
179 174
 
+56 -8
mojo/lib/Mojo/Headers.pm
... ...
@@ -8,13 +8,13 @@ has max_line_size => sub { $ENV{MOJO_MAX_LINE_SIZE} || 10240 };
8 8
 # Common headers
9 9
 my @HEADERS = (
10 10
   qw(Accept Accept-Charset Accept-Encoding Accept-Language Accept-Ranges),
11
-  qw(Authorization Cache-Control Connection Content-Disposition),
11
+  qw(Allow Authorization Cache-Control Connection Content-Disposition),
12 12
   qw(Content-Encoding Content-Length Content-Range Content-Type Cookie DNT),
13
-  qw(Date ETag Expect Expires Host If-Modified-Since Last-Modified Location),
14
-  qw(Origin Proxy-Authenticate Proxy-Authorization Range),
13
+  qw(Date ETag Expect Expires Host If-Modified-Since Last-Modified Link),
14
+  qw(Location Origin Proxy-Authenticate Proxy-Authorization Range),
15 15
   qw(Sec-WebSocket-Accept Sec-WebSocket-Extensions Sec-WebSocket-Key),
16 16
   qw(Sec-WebSocket-Protocol Sec-WebSocket-Version Server Set-Cookie Status),
17
-  qw(TE Trailer Transfer-Encoding Upgrade User-Agent WWW-Authenticate)
17
+  qw(TE Trailer Transfer-Encoding Upgrade User-Agent Vary WWW-Authenticate)
18 18
 );
19 19
 for my $header (@HEADERS) {
20 20
   my $name = lc $header;
... ...
@@ -22,7 +22,7 @@ for my $header (@HEADERS) {
22 22
   monkey_patch __PACKAGE__, $name, sub { scalar shift->header($header => @_) };
23 23
 }
24 24
 
25
-# Lower case headers
25
+# Lowercase headers
26 26
 my %NORMALCASE = map { lc($_) => $_ } @HEADERS;
27 27
 
28 28
 sub add {
... ...
@@ -38,6 +38,12 @@ sub add {
38 38
   return $self;
39 39
 }
40 40
 
41
+sub append {
42
+  my ($self, $name, $value) = @_;
43
+  my $old = $self->header($name);
44
+  return $self->header($name => defined $old ? "$old, $value" : $value);
45
+}
46
+
41 47
 sub clone {
42 48
   my $self = shift;
43 49
   return $self->new->from_hash($self->to_hash(1));
... ...
@@ -149,6 +155,8 @@ sub to_string {
149 155
 
150 156
 1;
151 157
 
158
+=encoding utf8
159
+
152 160
 =head1 NAME
153 161
 
154 162
 Mojo::Headers - Headers
... ...
@@ -234,6 +242,29 @@ Shortcut for the C<Accept-Ranges> header.
234 242
 
235 243
 Add one or more header values with one or more lines.
236 244
 
245
+  # "Vary: Accept"
246
+  # "Vary: Accept-Encoding"
247
+  $headers->vary('Accept')->add(Vary => 'Accept-Encoding')->to_string;
248
+
249
+=head2 allow
250
+
251
+  my $allow = $headers->allow;
252
+  $headers  = $headers->allow('GET, POST');
253
+
254
+Shortcut for the C<Allow> header.
255
+
256
+=head2 append
257
+
258
+  $headers = $headers->append(Vary => 'Accept-Encoding');
259
+
260
+Append value to header and flatten it if necessary.
261
+
262
+  # "Vary: Accept"
263
+  $headers->append(Vary => 'Accept')->to_string;
264
+
265
+  # "Vary: Accept, Accept-Encoding"
266
+  $headers->vary('Accept')->append(Vary => 'Accept-Encoding')->to_string;
267
+
237 268
 =head2 authorization
238 269
 
239 270
   my $authorization = $headers->authorization;
... ...
@@ -380,13 +411,13 @@ Shortcut for the C<If-Modified-Since> header.
380 411
 
381 412
 =head2 is_finished
382 413
 
383
-  my $success = $headers->is_finished;
414
+  my $bool = $headers->is_finished;
384 415
 
385 416
 Check if header parser is finished.
386 417
 
387 418
 =head2 is_limit_exceeded
388 419
 
389
-  my $success = $headers->is_limit_exceeded;
420
+  my $bool = $headers->is_limit_exceeded;
390 421
 
391 422
 Check if a header has exceeded C<max_line_size>.
392 423
 
... ...
@@ -403,6 +434,13 @@ Shortcut for the C<Last-Modified> header.
403 434
 
404 435
 Get leftover data from header parser.
405 436
 
437
+=head2 link
438
+
439
+  my $link = $headers->link;
440
+  $headers = $headers->link('<http://127.0.0.1/foo/3>; rel="next"');
441
+
442
+Shortcut for the C<Link> header from RFC 5988.
443
+
406 444
 =head2 location
407 445
 
408 446
   my $location = $headers->location;
... ...
@@ -414,7 +452,10 @@ Shortcut for the C<Location> header.
414 452
 
415 453
   my $names = $headers->names;
416 454
 
417
-Generate a list of all currently defined headers.
455
+Return a list of all currently defined headers.
456
+
457
+  # Names of all headers
458
+  say for @{$headers->names};
418 459
 
419 460
 =head2 origin
420 461
 
... ...
@@ -571,6 +612,13 @@ Shortcut for the C<Upgrade> header.
571 612
 
572 613
 Shortcut for the C<User-Agent> header.
573 614
 
615
+=head2 vary
616
+
617
+  my $vary = $headers->vary;
618
+  $headers = $headers->vary('*');
619
+
620
+Shortcut for the C<Vary> header.
621
+
574 622
 =head2 www_authenticate
575 623
 
576 624
   my $authenticate = $headers->www_authenticate;
+2
mojo/lib/Mojo/HelloWorld.pm
... ...
@@ -7,6 +7,8 @@ any '/*whatever' => {whatever => '', text => 'Your Mojo is working!'};
7 7
 
8 8
 1;
9 9
 
10
+=encoding utf8
11
+
10 12
 =head1 NAME
11 13
 
12 14
 Mojo::HelloWorld - Hello World!
+27 -23
mojo/lib/Mojo/Home.pm
... ...
@@ -1,9 +1,6 @@
1 1
 package Mojo::Home;
2 2
 use Mojo::Base -base;
3
-use overload
4
-  'bool'   => sub {1},
5
-  '""'     => sub { shift->to_string },
6
-  fallback => 1;
3
+use overload bool => sub {1}, '""' => sub { shift->to_string }, fallback => 1;
7 4
 
8 5
 use Cwd 'abs_path';
9 6
 use File::Basename 'dirname';
... ...
@@ -12,16 +9,15 @@ use File::Spec::Functions qw(abs2rel catdir catfile splitdir);
12 9
 use FindBin;
13 10
 use Mojo::Util qw(class_to_path slurp);
14 11
 
12
+has parts => sub { [] };
13
+
15 14
 sub new { shift->SUPER::new->parse(@_) }
16 15
 
17 16
 sub detect {
18 17
   my $self = shift;
19 18
 
20 19
   # Environment variable
21
-  if ($ENV{MOJO_HOME}) {
22
-    $self->{parts} = [splitdir(abs_path $ENV{MOJO_HOME})];
23
-    return $self;
24
-  }
20
+  return $self->parts([splitdir(abs_path $ENV{MOJO_HOME})]) if $ENV{MOJO_HOME};
25 21
 
26 22
   # Try to find home from lib directory
27 23
   if (my $class = @_ ? shift : 'Mojo::HelloWorld') {
... ...
@@ -34,28 +30,23 @@ sub detect {
34 30
       pop @home while @home && ($home[-1] =~ /^b?lib$/ || $home[-1] eq '');
35 31
 
36 32
       # Turn into absolute path
37
-      $self->{parts} = [splitdir(abs_path(catdir(@home) || '.'))];
33
+      return $self->parts([splitdir(abs_path(catdir(@home) || '.'))]);
38 34
     }
39 35
   }
40 36
 
41 37
   # FindBin fallback
42
-  $self->{parts} = [split /\//, $FindBin::Bin] unless $self->{parts};
43
-
44
-  return $self;
38
+  return $self->parts([split /\//, $FindBin::Bin]);
45 39
 }
46 40
 
47 41
 sub lib_dir {
48
-  my $path = catdir @{shift->{parts} || []}, 'lib';
42
+  my $path = catdir @{shift->parts}, 'lib';
49 43
   return -d $path ? $path : undef;
50 44
 }
51 45
 
52 46
 sub list_files {
53 47
   my ($self, $dir) = @_;
54 48
 
55
-  # Files relative to directory
56
-  my $parts = $self->{parts} || [];
57
-  my $root = catdir @$parts;
58
-  $dir = catdir $root, split '/', ($dir || '');
49
+  $dir = catdir @{$self->parts}, split '/', (defined $dir ? $dir : '');
59 50
   return [] unless -d $dir;
60 51
   my @files;
61 52
   find {
... ...
@@ -73,17 +64,18 @@ sub mojo_lib_dir { catdir(dirname(__FILE__), '..') }
73 64
 
74 65
 sub parse {
75 66
   my ($self, $path) = @_;
76
-  $self->{parts} = [splitdir $path] if defined $path;
77
-  return $self;
67
+  return defined $path ? $self->parts([splitdir $path]) : $self;
78 68
 }
79 69
 
80
-sub rel_dir { catdir(@{shift->{parts} || []}, split '/', shift) }
81
-sub rel_file { catfile(@{shift->{parts} || []}, split '/', shift) }
70
+sub rel_dir { catdir(@{shift->parts}, split '/', shift) }
71
+sub rel_file { catfile(@{shift->parts}, split '/', shift) }
82 72
 
83
-sub to_string { catdir(@{shift->{parts} || []}) }
73
+sub to_string { catdir(@{shift->parts}) }
84 74
 
85 75
 1;
86 76
 
77
+=encoding utf8
78
+
87 79
 =head1 NAME
88 80
 
89 81
 Mojo::Home - Home sweet home!
... ...
@@ -103,6 +95,17 @@ Mojo::Home - Home sweet home!
103 95
 
104 96
 L<Mojo::Home> is a container for home directories.
105 97
 
98
+=head1 ATTRIBUTES
99
+
100
+L<Mojo::Home> implements the following attributes.
101
+
102
+=head2 parts
103
+
104
+  my $parts = $home->parts;
105
+  $home     = $home->parts([]);
106
+
107
+Home directory parts.
108
+
106 109
 =head1 METHODS
107 110
 
108 111
 L<Mojo::Home> inherits all methods from L<Mojo::Base> and implements the
... ...
@@ -113,7 +116,8 @@ following new ones.
113 116
   my $home = Mojo::Home->new;
114 117
   my $home = Mojo::Home->new('/home/sri/myapp');
115 118
 
116
-Construct a new L<Mojo::Home> object and C<parse> home directory if necessary.
119
+Construct a new L<Mojo::Home> object and L</"parse"> home directory if
120
+necessary.
117 121
 
118 122
 =head2 detect
119 123
 
+67 -74
mojo/lib/Mojo/IOLoop.pm
... ...
@@ -10,7 +10,7 @@ use Mojo::IOLoop::Server;
10 10
 use Mojo::IOLoop::Stream;
11 11
 use Mojo::Reactor::Poll;
12 12
 use Mojo::Util qw(md5_sum steady_time);
13
-use Scalar::Util 'weaken';
13
+use Scalar::Util qw(blessed weaken);
14 14
 
15 15
 use constant DEBUG => $ENV{MOJO_IOLOOP_DEBUG} || 0;
16 16
 
... ...
@@ -22,7 +22,9 @@ has multi_accept    => 50;
22 22
 has reactor         => sub {
23 23
   my $class = Mojo::Reactor::Poll->detect;
24 24
   warn "-- Reactor initialized ($class)\n" if DEBUG;
25
-  return $class->new;
25
+  my $reactor = $class->new;
26
+  $reactor->on(error => sub { warn "@{[blessed $_[0]]}: $_[1]" });
27
+  return $reactor;
26 28
 };
27 29
 
28 30
 # Ignore PIPE signal
... ...
@@ -32,8 +34,7 @@ $SIG{PIPE} = 'IGNORE';
32 34
 __PACKAGE__->singleton->reactor;
33 35
 
34 36
 sub acceptor {
35
-  my ($self, $acceptor) = @_;
36
-  $self = $self->singleton unless ref $self;
37
+  my ($self, $acceptor) = (_instance(shift), @_);
37 38
 
38 39
   # Find acceptor for id
39 40
   return $self->{acceptors}{$acceptor} unless ref $acceptor;
... ...
@@ -44,35 +45,28 @@ sub acceptor {
44 45
   weaken $acceptor->reactor($self->reactor)->{reactor};
45 46
   $self->{accepts} = $self->max_accepts if $self->max_accepts;
46 47
 
47
-  # Stop accepting so new acceptor can get picked up
48
+  # Allow new acceptor to get picked up
48 49
   $self->_not_accepting;
49 50
 
50 51
   return $id;
51 52
 }
52 53
 
53 54
 sub client {
54
-  my ($self, $cb) = (shift, pop);
55
-  $self = $self->singleton unless ref $self;
55
+  my ($self, $cb) = (_instance(shift), pop);
56 56
 
57 57
   # Make sure timers are running
58
-  $self->_timers;
58
+  $self->_recurring;
59 59
 
60
-  my $id     = $self->_id;
61
-  my $c      = $self->{connections}{$id} ||= {};
62
-  my $client = $c->{client} = Mojo::IOLoop::Client->new;
60
+  my $id = $self->_id;
61
+  my $client = $self->{connections}{$id}{client} = Mojo::IOLoop::Client->new;
63 62
   weaken $client->reactor($self->reactor)->{reactor};
64 63
 
65 64
   weaken $self;
66 65
   $client->on(
67 66
     connect => sub {
68
-      my $handle = pop;
69
-
70
-      # Turn handle into stream
71
-      my $c = $self->{connections}{$id};
72
-      delete $c->{client};
73
-      my $stream = $c->{stream} = Mojo::IOLoop::Stream->new($handle);
67
+      delete $self->{connections}{$id}{client};
68
+      my $stream = Mojo::IOLoop::Stream->new(pop);
74 69
       $self->_stream($stream => $id);
75
-
76 70
       $self->$cb(undef, $stream);
77 71
     }
78 72
   );
... ...
@@ -88,8 +82,7 @@ sub client {
88 82
 }
89 83
 
90 84
 sub delay {
91
-  my $self = shift;
92
-  $self = $self->singleton unless ref $self;
85
+  my $self = _instance(shift);
93 86
 
94 87
   my $delay = Mojo::IOLoop::Delay->new;
95 88
   weaken $delay->ioloop($self)->{ioloop};
... ...
@@ -103,42 +96,24 @@ sub generate_port { Mojo::IOLoop::Server->generate_port }
103 96
 sub is_running { (ref $_[0] ? $_[0] : $_[0]->singleton)->reactor->is_running }
104 97
 sub one_tick   { (ref $_[0] ? $_[0] : $_[0]->singleton)->reactor->one_tick }
105 98
 
106
-sub recurring {
107
-  my ($self, $after, $cb) = @_;
108
-  $self = $self->singleton unless ref $self;
109
-  weaken $self;
110
-  return $self->reactor->recurring($after => sub { $self->$cb });
111
-}
99
+sub recurring { shift->_timer(recurring => @_) }
112 100
 
113 101
 sub remove {
114
-  my ($self, $id) = @_;
115
-  $self = $self->singleton unless ref $self;
102
+  my ($self, $id) = (_instance(shift), @_);
116 103
   my $c = $self->{connections}{$id};
117 104
   if ($c && (my $stream = $c->{stream})) { return $stream->close_gracefully }
118 105
   $self->_remove($id);
119 106
 }
120 107
 
121 108
 sub server {
122
-  my ($self, $cb) = (shift, pop);
123
-  $self = $self->singleton unless ref $self;
109
+  my ($self, $cb) = (_instance(shift), pop);
124 110
 
125 111
   my $server = Mojo::IOLoop::Server->new;
126 112
   weaken $self;
127 113
   $server->on(
128 114
     accept => sub {
129
-      my $handle = pop;
130
-
131
-      # Turn handle into stream
132
-      my $stream = Mojo::IOLoop::Stream->new($handle);
115
+      my $stream = Mojo::IOLoop::Stream->new(pop);
133 116
       $self->$cb($stream, $self->stream($stream));
134
-
135
-      # Enforce connection limit (randomize to improve load balancing)
136
-      $self->max_connections(0)
137
-        if defined $self->{accepts}
138
-        && ($self->{accepts} -= int(rand 2) + 1) <= 0;
139
-
140
-      # Stop accepting to release accept mutex
141
-      $self->_not_accepting;
142 117
     }
143 118
   );
144 119
   $server->listen(@_);
... ...
@@ -158,24 +133,23 @@ sub start {
158 133
 sub stop { (ref $_[0] ? $_[0] : $_[0]->singleton)->reactor->stop }
159 134
 
160 135
 sub stream {
161
-  my ($self, $stream) = @_;
162
-  $self = $self->singleton unless ref $self;
163
-
164
-  # Connect stream with reactor
165
-  return $self->_stream($stream, $self->_id) if ref $stream;
136
+  my ($self, $stream) = (_instance(shift), @_);
166 137
 
167 138
   # Find stream for id
168
-  return undef unless my $c = $self->{connections}{$stream};
169
-  return $c->{stream};
170
-}
139
+  return ($self->{connections}{$stream} || {})->{stream} unless ref $stream;
171 140
 
172
-sub timer {
173
-  my ($self, $after, $cb) = @_;
174
-  $self = $self->singleton unless ref $self;
175
-  weaken $self;
176
-  return $self->reactor->timer($after => sub { $self->$cb });
141
+  # Release accept mutex
142
+  $self->_not_accepting;
143
+
144
+  # Enforce connection limit (randomize to improve load balancing)
145
+  $self->max_connections(0)
146
+    if defined $self->{accepts} && ($self->{accepts} -= int(rand 2) + 1) <= 0;
147
+
148
+  return $self->_stream($stream, $self->_id);
177 149
 }
178 150
 
151
+sub timer { shift->_timer(timer => @_) }
152
+
179 153
 sub _accepting {
180 154
   my $self = shift;
181 155
 
... ...
@@ -206,11 +180,13 @@ sub _id {
206 180
   return $id;
207 181
 }
208 182
 
183
+sub _instance { ref $_[0] ? $_[0] : $_[0]->singleton }
184
+
209 185
 sub _not_accepting {
210 186
   my $self = shift;
211 187
 
212 188
   # Make sure timers are running
213
-  $self->_timers;
189
+  $self->_recurring;
214 190
 
215 191
   # Release accept mutex
216 192
   return unless delete $self->{accepting};
... ...
@@ -220,6 +196,12 @@ sub _not_accepting {
220 196
   $_->stop for values %{$self->{acceptors} || {}};
221 197
 }
222 198
 
199
+sub _recurring {
200
+  my $self = shift;
201
+  $self->{accept} ||= $self->recurring($self->accept_interval => \&_accepting);
202
+  $self->{stop} ||= $self->recurring(1 => \&_stop);
203
+}
204
+
223 205
 sub _remove {
224 206
   my ($self, $id) = @_;
225 207
 
... ...
@@ -246,7 +228,7 @@ sub _stream {
246 228
   my ($self, $stream, $id) = @_;
247 229
 
248 230
   # Make sure timers are running
249
-  $self->_timers;
231
+  $self->_recurring;
250 232
 
251 233
   # Connect stream with reactor
252 234
   $self->{connections}{$id}{stream} = $stream;
... ...
@@ -258,14 +240,16 @@ sub _stream {
258 240
   return $id;
259 241
 }
260 242
 
261
-sub _timers {
262
-  my $self = shift;
263
-  $self->{accept} ||= $self->recurring($self->accept_interval => \&_accepting);
264
-  $self->{stop} ||= $self->recurring(1 => \&_stop);
243
+sub _timer {
244
+  my ($self, $method, $after, $cb) = (_instance(shift), @_);
245
+  weaken $self;
246
+  return $self->reactor->$method($after => sub { $self->$cb });
265 247
 }
266 248
 
267 249
 1;
268 250
 
251
+=encoding utf8
252
+
269 253
 =head1 NAME
270 254
 
271 255
 Mojo::IOLoop - Minimalistic event loop
... ...
@@ -319,17 +303,18 @@ L<Mojo::IOLoop> is a very minimalistic event loop based on L<Mojo::Reactor>,
319 303
 it has been reduced to the absolute minimal feature set required to build
320 304
 solid and scalable non-blocking TCP clients and servers.
321 305
 
322
-Optional modules L<EV> (4.0+), L<IO::Socket::IP> (0.16+) and
323
-L<IO::Socket::SSL> (1.75+) are supported transparently, and used if installed.
324
-Individual features can also be disabled with the MOJO_NO_IPV6 and MOJO_NO_TLS
325
-environment variables.
326
-
327 306
 The event loop will be resilient to time jumps if a monotonic clock is
328 307
 available through L<Time::HiRes>. A TLS certificate and key are also built
329 308
 right in, to make writing test servers as easy as possible. Also note that for
330 309
 convenience the C<PIPE> signal will be set to C<IGNORE> when L<Mojo::IOLoop>
331 310
 is loaded.
332 311
 
312
+For better scalability (epoll, kqueue) and to provide IPv6 as well as TLS
313
+support, the optional modules L<EV> (4.0+), L<IO::Socket::IP> (0.16+) and
314
+L<IO::Socket::SSL> (1.75+) will be used automatically if they are installed.
315
+Individual features can also be disabled with the MOJO_NO_IPV6 and MOJO_NO_TLS
316
+environment variables.
317
+
333 318
 See L<Mojolicious::Guides::Cookbook> for more.
334 319
 
335 320
 =head1 ATTRIBUTES
... ...
@@ -396,7 +381,7 @@ Number of connections to accept at once, defaults to C<50>.
396 381
   $loop       = $loop->reactor(Mojo::Reactor->new);
397 382
 
398 383
 Low level event reactor, usually a L<Mojo::Reactor::Poll> or
399
-L<Mojo::Reactor::EV> object.
384
+L<Mojo::Reactor::EV> object with a default C<error> event.
400 385
 
401 386
   # Watch if handle becomes readable or writable
402 387
   $loop->reactor->io($handle => sub {
... ...
@@ -464,6 +449,7 @@ event, and multiple ones as a chain of steps.
464 449
       $end->();
465 450
     });
466 451
   }
452
+  $delay->wait unless Mojo::IOLoop->is_running;
467 453
 
468 454
   # Sequentialize multiple events
469 455
   my $delay = Mojo::IOLoop->delay(
... ...
@@ -486,8 +472,6 @@ event, and multiple ones as a chain of steps.
486 472
     # Third step (the end)
487 473
     sub { say 'And done after 5 seconds total.' }
488 474
   );
489
-
490
-  # Wait for events if necessary
491 475
   $delay->wait unless Mojo::IOLoop->is_running;
492 476
 
493 477
 =head2 generate_port
... ...
@@ -499,8 +483,8 @@ Find a free TCP port, this is a utility function primarily used for tests.
499 483
 
500 484
 =head2 is_running
501 485
 
502
-  my $success = Mojo::IOLoop->is_running;
503
-  my $success = $loop->is_running;
486
+  my $bool = Mojo::IOLoop->is_running;
487
+  my $bool = $loop->is_running;
504 488
 
505 489
 Check if event loop is running.
506 490
 
... ...
@@ -514,6 +498,11 @@ Check if event loop is running.
514 498
 Run event loop until an event occurs. Note that this method can recurse back
515 499
 into the reactor, so you need to be careful.
516 500
 
501
+  # Don't block longer than 0.5 seconds
502
+  my $id = Mojo::IOLoop->timer(0.5 => sub {});
503
+  Mojo::IOLoop->one_tick;
504
+  Mojo::IOLoop->remove($id);
505
+
517 506
 =head2 recurring
518 507
 
519 508
   my $id = Mojo::IOLoop->recurring(0.5 => sub {...});
... ...
@@ -559,13 +548,17 @@ loop object from everywhere inside the process.
559 548
   Mojo::IOLoop->timer(2 => sub { Mojo::IOLoop->stop });
560 549
   Mojo::IOLoop->start;
561 550
 
551
+  # Restart active timer
552
+  my $id = Mojo::IOLoop->timer(3 => sub { say 'Timeout!' });
553
+  Mojo::IOLoop->singleton->reactor->again($id);
554
+
562 555
 =head2 start
563 556
 
564 557
   Mojo::IOLoop->start;
565 558
   $loop->start;
566 559
 
567
-Start the event loop, this will block until C<stop> is called. Note that some
568
-reactors stop automatically if there are no events being watched anymore.
560
+Start the event loop, this will block until L</"stop"> is called. Note that
561
+some reactors stop automatically if there are no events being watched anymore.
569 562
 
570 563
   # Start event loop only if it is not running already
571 564
   Mojo::IOLoop->start unless Mojo::IOLoop->is_running;
... ...
@@ -576,7 +569,7 @@ reactors stop automatically if there are no events being watched anymore.
576 569
   $loop->stop;
577 570
 
578 571
 Stop the event loop, this will not interrupt any existing connections and the
579
-event loop can be restarted by running C<start> again.
572
+event loop can be restarted by running L</"start"> again.
580 573
 
581 574
 =head2 stream
582 575
 
+58 -45
mojo/lib/Mojo/IOLoop/Client.pm
... ...
@@ -34,7 +34,7 @@ sub connect {
34 34
 
35 35
 sub _cleanup {
36 36
   my $self = shift;
37
-  return $self unless my $reactor = $self->{reactor};
37
+  return $self unless my $reactor = $self->reactor;
38 38
   $self->{$_} && $reactor->remove(delete $self->{$_})
39 39
     for qw(delay timer handle);
40 40
   return $self;
... ...
@@ -50,18 +50,17 @@ sub _connect {
50 50
     my %options = (
51 51
       Blocking => 0,
52 52
       PeerAddr => $address eq 'localhost' ? '127.0.0.1' : $address,
53
-      PeerPort => $args->{port} || ($args->{tls} ? 443 : 80),
54
-      Proto    => 'tcp'
53
+      PeerPort => $args->{port} || ($args->{tls} ? 443 : 80)
55 54
     );
56 55
     $options{LocalAddr} = $args->{local_address} if $args->{local_address};
57 56
     $options{PeerAddr} =~ s/[\[\]]//g if $options{PeerAddr};
58 57
     my $class = IPV6 ? 'IO::Socket::IP' : 'IO::Socket::INET';
59
-    return $self->emit_safe(error => "Couldn't connect")
58
+    return $self->emit(error => "Couldn't connect: $@")
60 59
       unless $self->{handle} = $handle = $class->new(%options);
61 60
 
62 61
     # Timeout
63 62
     $self->{timer} = $reactor->timer($args->{timeout} || 10,
64
-      sub { $self->emit_safe(error => 'Connect timeout') });
63
+      sub { $self->emit(error => 'Connect timeout') });
65 64
   }
66 65
   $handle->blocking(0);
67 66
 
... ...
@@ -73,16 +72,15 @@ sub _connect {
73 72
 sub _tls {
74 73
   my $self = shift;
75 74
 
76
-  # Switch between reading and writing
75
+  # Connected
77 76
   my $handle = $self->{handle};
78
-  if ($self->{tls} && !$handle->connect_SSL) {
79
-    my $err = $IO::Socket::SSL::SSL_ERROR;
80
-    if    ($err == TLS_READ)  { $self->reactor->watch($handle, 1, 0) }
81
-    elsif ($err == TLS_WRITE) { $self->reactor->watch($handle, 1, 1) }
82
-    return;
83
-  }
77
+  return $self->_cleanup->emit_safe(connect => $handle)
78
+    if $handle->connect_SSL;
84 79
 
85
-  $self->_cleanup->emit_safe(connect => $handle);
80
+  # Switch between reading and writing
81
+  my $err = $IO::Socket::SSL::SSL_ERROR;
82
+  if    ($err == TLS_READ)  { $self->reactor->watch($handle, 1, 0) }
83
+  elsif ($err == TLS_WRITE) { $self->reactor->watch($handle, 1, 1) }
86 84
 }
87 85
 
88 86
 sub _try {
... ...
@@ -90,47 +88,44 @@ sub _try {
90 88
 
91 89
   # Retry or handle exceptions
92 90
   my $handle = $self->{handle};
93
-  return $! == EINPROGRESS ? undef : $self->emit_safe(error => $!)
91
+  return $! == EINPROGRESS ? undef : $self->emit(error => $!)
94 92
     if IPV6 && !$handle->connect;
95
-  return $self->emit_safe(error => $! = $handle->sockopt(SO_ERROR))
93
+  return $self->emit(error => $! = $handle->sockopt(SO_ERROR))
96 94
     if !IPV6 && !$handle->connected;
97 95
 
98 96
   # Disable Nagle's algorithm
99 97
   setsockopt $handle, IPPROTO_TCP, TCP_NODELAY, 1;
100 98
 
101
-  # TLS
102
-  if ($args->{tls} && !$handle->isa('IO::Socket::SSL')) {
103
-    return $self->emit_safe(
104
-      error => 'IO::Socket::SSL 1.75 required for TLS support')
105
-      unless TLS;
106
-
107
-    # Upgrade
108
-    weaken $self;
109
-    my %options = (
110
-      SSL_ca_file => $args->{tls_ca}
111
-        && -T $args->{tls_ca} ? $args->{tls_ca} : undef,
112
-      SSL_cert_file      => $args->{tls_cert},
113
-      SSL_error_trap     => sub { $self->_cleanup->emit_safe(error => $_[1]) },
114
-      SSL_hostname       => $args->{address},
115
-      SSL_key_file       => $args->{tls_key},
116
-      SSL_startHandshake => 0,
117
-      SSL_verify_mode    => $args->{tls_ca} ? 0x01 : 0x00,
118
-      SSL_verifycn_name  => $args->{address},
119
-      SSL_verifycn_scheme => $args->{tls_ca} ? 'http' : undef
120
-    );
121
-    $self->{tls} = 1;
122
-    my $reactor = $self->reactor;
123
-    $reactor->remove($handle);
124
-    return $self->emit_safe(error => 'TLS upgrade failed')
125
-      unless $handle = IO::Socket::SSL->start_SSL($handle, %options);
126
-    return $reactor->io($handle => sub { $self->_tls })->watch($handle, 0, 1);
127
-  }
99
+  return $self->_cleanup->emit_safe(connect => $handle)
100
+    if !$args->{tls} || $handle->isa('IO::Socket::SSL');
101
+  return $self->emit(error => 'IO::Socket::SSL 1.75 required for TLS support')
102
+    unless TLS;
128 103
 
129
-  $self->_cleanup->emit_safe(connect => $handle);
104
+  # Upgrade
105
+  weaken $self;
106
+  my %options = (
107
+    SSL_ca_file => $args->{tls_ca}
108
+      && -T $args->{tls_ca} ? $args->{tls_ca} : undef,
109
+    SSL_cert_file       => $args->{tls_cert},
110
+    SSL_error_trap      => sub { $self->_cleanup->emit(error => $_[1]) },
111
+    SSL_hostname        => $args->{address},
112
+    SSL_key_file        => $args->{tls_key},
113
+    SSL_startHandshake  => 0,
114
+    SSL_verify_mode     => $args->{tls_ca} ? 0x01 : 0x00,
115
+    SSL_verifycn_name   => $args->{address},
116
+    SSL_verifycn_scheme => $args->{tls_ca} ? 'http' : undef
117
+  );
118
+  my $reactor = $self->reactor;
119
+  $reactor->remove($handle);
120
+  return $self->emit(error => 'TLS upgrade failed')
121
+    unless $handle = IO::Socket::SSL->start_SSL($handle, %options);
122
+  $reactor->io($handle => sub { $self->_tls })->watch($handle, 0, 1);
130 123
 }
131 124
 
132 125
 1;
133 126
 
127
+=encoding utf8
128
+
134 129
 =head1 NAME
135 130
 
136 131
 Mojo::IOLoop::Client - Non-blocking TCP client
... ...
@@ -179,7 +174,7 @@ Emitted safely once the connection is established.
179 174
     ...
180 175
   });
181 176
 
182
-Emitted safely if an error occurs on the connection.
177
+Emitted if an error occurs on the connection, fatal if unhandled.
183 178
 
184 179
 =head1 ATTRIBUTES
185 180
 
... ...
@@ -211,39 +206,57 @@ These options are currently available:
211 206
 
212 207
 =item address
213 208
 
209
+  address => 'mojolicio.us'
210
+
214 211
 Address or host name of the peer to connect to, defaults to C<localhost>.
215 212
 
216 213
 =item handle
217 214
 
215
+  handle => $handle
216
+
218 217
 Use an already prepared handle.
219 218
 
220 219
 =item local_address
221 220
 
221
+  local_address => '127.0.0.1'
222
+
222 223
 Local address to bind to.
223 224
 
224 225
 =item port
225 226
 
226
-Port to connect to.
227
+  port => 80
228
+
229
+Port to connect to, defaults to C<80> or C<443> with C<tls> option.
227 230
 
228 231
 =item timeout
229 232
 
233
+  timeout => 15
234
+
230 235
 Maximum amount of time in seconds establishing connection may take before
231 236
 getting canceled, defaults to C<10>.
232 237
 
233 238
 =item tls
234 239
 
240
+  tls => 1
241
+
235 242
 Enable TLS.
236 243
 
237 244
 =item tls_ca
238 245
 
246
+  tls_ca => '/etc/tls/ca.crt'
247
+
239 248
 Path to TLS certificate authority file. Also activates hostname verification.
240 249
 
241 250
 =item tls_cert
242 251
 
252
+  tls_cert => '/etc/tls/client.crt'
253
+
243 254
 Path to the TLS certificate file.
244 255
 
245 256
 =item tls_key
246 257
 
258
+  tls_key => '/etc/tls/client.key'
259
+
247 260
 Path to the TLS key file.
248 261
 
249 262
 =back
+35 -17
mojo/lib/Mojo/IOLoop/Delay.pm
... ...
@@ -15,36 +15,44 @@ sub begin {
15 15
 sub steps {
16 16
   my $self = shift;
17 17
   $self->{steps} = [@_];
18
-  $self->begin->();
18
+  $self->ioloop->timer(0 => $self->begin);
19 19
   return $self;
20 20
 }
21 21
 
22 22
 sub wait {
23 23
   my $self = shift;
24
+
24 25
   my @args;
26
+  $self->once(error => \&_die);
25 27
   $self->once(finish => sub { shift->ioloop->stop; @args = @_ });
26 28
   $self->ioloop->start;
29
+
27 30
   return wantarray ? @args : $args[0];
28 31
 }
29 32
 
33
+sub _die { $_[0]->has_subscribers('error') ? $_[0]->ioloop->stop : die $_[1] }
34
+
30 35
 sub _step {
31 36
   my ($self, $id) = (shift, shift);
32 37
 
33 38
   $self->{args}[$id] = [@_];
34
-  return $self->{pending} if --$self->{pending} || $self->{lock};
39
+  return if $self->{fail} || --$self->{pending} || $self->{lock};
35 40
   local $self->{lock} = 1;
36 41
   my @args = map {@$_} @{delete $self->{args}};
37 42
 
38 43
   $self->{counter} = 0;
39
-  if (my $cb = shift @{$self->{steps} ||= []}) { $self->$cb(@args) }
44
+  if (my $cb = shift @{$self->{steps} ||= []}) {
45
+    eval { $self->$cb(@args); 1 } or return $self->emit(error => $@)->{fail}++;
46
+  }
40 47
 
41
-  if (!$self->{counter}) { $self->emit(finish => @args) }
42
-  elsif (!$self->{pending}) { $self->ioloop->timer(0 => $self->begin) }
43
-  return 0;
48
+  return $self->emit(finish => @args) unless $self->{counter};
49
+  $self->ioloop->timer(0 => $self->begin) unless $self->{pending};
44 50
 }
45 51
 
46 52
 1;
47 53
 
54
+=encoding utf8
55
+
48 56
 =head1 NAME
49 57
 
50 58
 Mojo::IOLoop::Delay - Manage callbacks and control the flow of events
... ...
@@ -63,6 +71,7 @@ Mojo::IOLoop::Delay - Manage callbacks and control the flow of events
63 71
       $end->();
64 72
     });
65 73
   }
74
+  $delay->wait unless Mojo::IOLoop->is_running;
66 75
 
67 76
   # Sequentialize multiple events
68 77
   my $delay = Mojo::IOLoop::Delay->new;
... ...
@@ -89,8 +98,6 @@ Mojo::IOLoop::Delay - Manage callbacks and control the flow of events
89 98
       say 'And done after 5 seconds total.';
90 99
     }
91 100
   );
92
-
93
-  # Wait for events if necessary
94 101
   $delay->wait unless Mojo::IOLoop->is_running;
95 102
 
96 103
 =head1 DESCRIPTION
... ...
@@ -103,6 +110,16 @@ L<Mojo::IOLoop>.
103 110
 L<Mojo::IOLoop::Delay> inherits all events from L<Mojo::EventEmitter> and can
104 111
 emit the following new ones.
105 112
 
113
+=head2 error
114
+
115
+  $delay->on(error => sub {
116
+    my ($delay, $err) = @_;
117
+    ...
118
+  });
119
+
120
+Emitted if an error occurs in one of the steps, breaking the chain, fatal if
121
+unhandled.
122
+
106 123
 =head2 finish
107 124
 
108 125
   $delay->on(finish => sub {
... ...
@@ -132,13 +149,13 @@ implements the following new ones.
132 149
 
133 150
 =head2 begin
134 151
 
135
-  my $cb = $delay->begin;
136
-  my $cb = $delay->begin(0);
152
+  my $without_first_arg = $delay->begin;
153
+  my $with_first_arg    = $delay->begin(0);
137 154
 
138 155
 Increment active event counter, the returned callback can be used to decrement
139 156
 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.
157
+the right order for the next step or L</"finish"> event and L</"wait"> method,
158
+the first argument will be ignored by default.
142 159
 
143 160
   # Capture all arguments
144 161
   my $delay = Mojo::IOLoop->delay;
... ...
@@ -150,16 +167,17 @@ first argument will be ignored by default.
150 167
   $delay = $delay->steps(sub {...}, sub {...});
151 168
 
152 169
 Sequentialize multiple events, the first callback will run right away, and the
153
-next one once the active event counter reaches zero, this chain will continue
154
-until there are no more callbacks or a callback does not increment the active
155
-event counter.
170
+next one once the active event counter reaches zero. This chain will continue
171
+until there are no more callbacks, a callback does not increment the active
172
+event counter or an error occurs in a callback.
156 173
 
157 174
 =head2 wait
158 175
 
176
+  my $arg  = $delay->wait;
159 177
   my @args = $delay->wait;
160 178
 
161
-Start C<ioloop> and stop it again once the C<finish> event gets emitted, only
162
-works when C<ioloop> is not running already.
179
+Start L</"ioloop"> and stop it again once an L</"error"> or L</"finish"> event
180
+gets emitted, only works when L</"ioloop"> is not running already.
163 181
 
164 182
   # Use the "finish" event to synchronize portably
165 183
   $delay->on(finish => sub {
+62 -27
mojo/lib/Mojo/IOLoop/Server.pm
... ...
@@ -34,11 +34,17 @@ has reactor      => sub {
34 34
 sub DESTROY {
35 35
   my $self = shift;
36 36
   if (my $port = $self->{port}) { $ENV{MOJO_REUSE} =~ s/(?:^|\,)${port}:\d+// }
37
-  return unless my $reactor = $self->{reactor};
37
+  return unless my $reactor = $self->reactor;
38 38
   $self->stop if $self->{handle};
39 39
   $reactor->remove($_) for values %{$self->{handles}};
40 40
 }
41 41
 
42
+sub generate_port {
43
+  IO::Socket::INET->new(Listen => 5, LocalAddr => '127.0.0.1')->sockport;
44
+}
45
+
46
+sub handle { shift->{handle} }
47
+
42 48
 sub listen {
43 49
   my $self = shift;
44 50
   my $args = ref $_[0] ? $_[0] : {@_};
... ...
@@ -56,8 +62,8 @@ sub listen {
56 62
   my $handle;
57 63
   my $class = IPV6 ? 'IO::Socket::IP' : 'IO::Socket::INET';
58 64
   if (defined $fd) {
59
-    $handle = $class->new;
60
-    $handle->fdopen($fd, 'r') or croak "Can't open file descriptor $fd: $!";
65
+    $handle = $class->new_from_fd($fd, 'r')
66
+      or croak "Can't open file descriptor $fd: $!";
61 67
   }
62 68
 
63 69
   # New socket
... ...
@@ -66,12 +72,12 @@ sub listen {
66 72
       Listen => defined $args->{backlog} ? $args->{backlog} : SOMAXCONN,
67 73
       LocalAddr => $args->{address} || '0.0.0.0',
68 74
       LocalPort => $port,
69
-      Proto     => 'tcp',
70 75
       ReuseAddr => 1,
76
+      ReusePort => $args->{reuse},
71 77
       Type      => SOCK_STREAM
72 78
     );
73 79
     $options{LocalAddr} =~ s/[\[\]]//g;
74
-    $handle = $class->new(%options) or croak "Can't create listen socket: $!";
80
+    $handle = $class->new(%options) or croak "Can't create listen socket: $@";
75 81
     $fd = fileno $handle;
76 82
     $ENV{MOJO_REUSE} .= length $ENV{MOJO_REUSE} ? ",$reuse:$fd" : "$reuse:$fd";
77 83
   }
... ...
@@ -81,25 +87,18 @@ sub listen {
81 87
   return unless $args->{tls};
82 88
   croak "IO::Socket::SSL 1.75 required for TLS support" unless TLS;
83 89
 
84
-  # Options (Prioritize RC4 to mitigate BEAST attack)
85
-  my $options = $self->{tls} = {
90
+  # Prioritize RC4 to mitigate BEAST attack
91
+  $self->{tls} = {
92
+    SSL_ca_file => $args->{tls_ca}
93
+      && -T $args->{tls_ca} ? $args->{tls_ca} : undef,
86 94
     SSL_cert_file => $args->{tls_cert} || $CERT,
87
-    SSL_cipher_list =>
88
-      '!aNULL:!eNULL:!EXPORT:!DSS:!DES:!SSLv2:!LOW:RC4-SHA:RC4-MD5:ALL',
95
+    SSL_cipher_list => defined $args->{tls_ciphers} ? $args->{tls_ciphers}
96
+      : 'ECDHE-RSA-AES128-SHA256:AES128-GCM-SHA256:RC4:HIGH:!MD5:!aNULL:!EDH',
89 97
     SSL_honor_cipher_order => 1,
90 98
     SSL_key_file           => $args->{tls_key} || $KEY,
91 99
     SSL_startHandshake     => 0,
92
-    SSL_verify_mode        => 0x00
100
+    SSL_verify_mode => defined $args->{tls_verify} ? $args->{tls_verify} : $args->{tls_ca} ? 0x03 : 0x00
93 101
   };
94
-  return unless $args->{tls_ca};
95
-  $options->{SSL_ca_file} = -T $args->{tls_ca} ? $args->{tls_ca} : undef;
96
-  $options->{SSL_verify_mode}
97
-    = defined $args->{tls_verify} ? $args->{tls_verify} : 0x03;
98
-}
99
-
100
-sub generate_port {
101
-  IO::Socket::INET->new(Listen => 5, LocalAddr => '127.0.0.1', Proto => 'tcp')
102
-    ->sockport;
103 102
 }
104 103
 
105 104
 sub start {
... ...
@@ -139,8 +138,7 @@ sub _tls {
139 138
   # Accepted
140 139
   if ($handle->accept_SSL) {
141 140
     $self->reactor->remove($handle);
142
-    delete $self->{handles}{$handle};
143
-    return $self->emit_safe(accept => $handle);
141
+    return $self->emit_safe(accept => delete $self->{handles}{$handle});
144 142
   }
145 143
 
146 144
   # Switch between reading and writing
... ...
@@ -151,6 +149,8 @@ sub _tls {
151 149
 
152 150
 1;
153 151
 
152
+=encoding utf8
153
+
154 154
 =head1 NAME
155 155
 
156 156
 Mojo::IOLoop::Server - Non-blocking TCP server
... ...
@@ -216,6 +216,18 @@ global L<Mojo::IOLoop> singleton.
216 216
 L<Mojo::IOLoop::Server> inherits all methods from L<Mojo::EventEmitter> and
217 217
 implements the following new ones.
218 218
 
219
+=head2 generate_port
220
+
221
+  my $port = $server->generate_port;
222
+
223
+Find a free TCP port, this is a utility function primarily used for tests.
224
+
225
+=head2 handle
226
+
227
+  my $handle = $server->handle;
228
+
229
+Get handle for server.
230
+
219 231
 =head2 listen
220 232
 
221 233
   $server->listen(port => 3000);
... ...
@@ -229,44 +241,67 @@ These options are currently available:
229 241
 
230 242
 =item address
231 243
 
244
+  address => '127.0.0.1'
245
+
232 246
 Local address to listen on, defaults to all.
233 247
 
234 248
 =item backlog
235 249
 
250
+  backlog => 128
251
+
236 252
 Maximum backlog size, defaults to C<SOMAXCONN>.
237 253
 
238 254
 =item port
239 255
 
256
+  port => 80
257
+
240 258
 Port to listen on.
241 259
 
260
+=item reuse
261
+
262
+  reuse => 1
263
+
264
+Allow multiple servers to use the same port with the C<SO_REUSEPORT> socket
265
+option.
266
+
242 267
 =item tls
243 268
 
269
+  tls => 1
270
+
244 271
 Enable TLS.
245 272
 
246 273
 =item tls_ca
247 274
 
275
+  tls_ca => '/etc/tls/ca.crt'
276
+
248 277
 Path to TLS certificate authority file.
249 278
 
250 279
 =item tls_cert
251 280
 
281
+  tls_cert => '/etc/tls/server.crt'
282
+
252 283
 Path to the TLS cert file, defaults to a built-in test certificate.
253 284
 
285
+=item tls_ciphers
286
+
287
+  tls_ciphers => 'AES128-GCM-SHA256:RC4:HIGH:!MD5:!aNULL:!EDH'
288
+
289
+Cipher specification string.
290
+
254 291
 =item tls_key
255 292
 
293
+  tls_key => '/etc/tls/server.key'
294
+
256 295
 Path to the TLS key file, defaults to a built-in test key.
257 296
 
258 297
 =item tls_verify
259 298
 
299
+  tls_verify => 0x00
300
+
260 301
 TLS verification mode, defaults to C<0x03>.
261 302
 
262 303
 =back
263 304
 
264
-=head2 generate_port
265
-
266
-  my $port = $server->generate_port;
267
-
268
-Find a free TCP port, this is a utility function primarily used for tests.
269
-
270 305
 =head2 start
271 306
 
272 307
   $server->start;
+14 -14
mojo/lib/Mojo/IOLoop/Stream.pm
... ...
@@ -11,16 +11,14 @@ has reactor => sub {
11 11
 
12 12
 sub DESTROY { shift->close }
13 13
 
14
-sub new { shift->SUPER::new(handle => shift, buffer => '') }
14
+sub new { shift->SUPER::new(handle => shift, buffer => '', timeout => 15) }
15 15
 
16 16
 sub close {
17 17
   my $self = shift;
18 18
 
19
-  # Cleanup
20
-  return unless my $reactor = $self->{reactor};
19
+  return unless my $reactor = $self->reactor;
21 20
   return unless my $handle  = delete $self->timeout(0)->{handle};
22 21
   $reactor->remove($handle);
23
-
24 22
   close $handle;
25 23
   $self->emit_safe('close');
26 24
 }
... ...
@@ -48,14 +46,14 @@ sub is_writing {
48 46
 sub start {
49 47
   my $self = shift;
50 48
 
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 49
   # Resume
57
-  $reactor->watch($self->{handle}, 1, $self->is_writing)
50
+  my $reactor = $self->reactor;
51
+  return $reactor->watch($self->{handle}, 1, $self->is_writing)
58 52
     if delete $self->{paused};
53
+
54
+  weaken $self;
55
+  my $cb = sub { pop() ? $self->_write : $self->_read };
56
+  $reactor->io($self->timeout($self->{timeout})->{handle} => $cb);
59 57
 }
60 58
 
61 59
 sub stop {
... ...
@@ -109,7 +107,7 @@ sub _error {
109 107
   return $self->close if $! == ECONNRESET || $! == EPIPE;
110 108
 
111 109
   # Error
112
-  $self->emit_safe(error => $!)->close;
110
+  $self->emit(error => $!)->close;
113 111
 }
114 112
 
115 113
 sub _read {
... ...
@@ -139,6 +137,8 @@ sub _write {
139 137
 
140 138
 1;
141 139
 
140
+=encoding utf8
141
+
142 142
 =head1 NAME
143 143
 
144 144
 Mojo::IOLoop::Stream - Non-blocking I/O stream
... ...
@@ -204,7 +204,7 @@ Emitted safely once all data has been written.
204 204
     ...
205 205
   });
206 206
 
207
-Emitted safely if an error occurs on the stream.
207
+Emitted if an error occurs on the stream, fatal if unhandled.
208 208
 
209 209
 =head2 read
210 210
 
... ...
@@ -277,14 +277,14 @@ Get handle for stream.
277 277
 
278 278
 =head2 is_readable
279 279
 
280
-  my $success = $stream->is_readable;
280
+  my $bool = $stream->is_readable;
281 281
 
282 282
 Quick non-blocking check if stream is readable, useful for identifying tainted
283 283
 sockets.
284 284
 
285 285
 =head2 is_writing
286 286
 
287
-  my $success = $stream->is_writing;
287
+  my $bool = $stream->is_writing;
288 288
 
289 289
 Check if stream is writing.
290 290
 
+32 -22
mojo/lib/Mojo/JSON.pm
... ...
@@ -19,23 +19,23 @@ my %ESCAPE = (
19 19
   '"'     => '"',
20 20
   '\\'    => '\\',
21 21
   '/'     => '/',
22
-  'b'     => "\x07",
23
-  'f'     => "\x0C",
24
-  'n'     => "\x0A",
25
-  'r'     => "\x0D",
22
+  'b'     => "\x08",
23
+  'f'     => "\x0c",
24
+  'n'     => "\x0a",
25
+  'r'     => "\x0d",
26 26
   't'     => "\x09",
27 27
   'u2028' => "\x{2028}",
28 28
   'u2029' => "\x{2029}"
29 29
 );
30 30
 my %REVERSE = map { $ESCAPE{$_} => "\\$_" } keys %ESCAPE;
31
-for (0x00 .. 0x1F, 0x7F) { $REVERSE{pack 'C', $_} = do {my $tmp = $REVERSE{pack 'C', $_}; defined $tmp ? $tmp : sprintf '\u%.4X', $_} }
31
+for (0x00 .. 0x1f, 0x7f) {$REVERSE{pack 'C', $_} = defined $REVERSE{pack 'C', $_} ? $REVERSE{pack 'C', $_} : sprintf '\u%.4X', $_}
32 32
 
33 33
 # Unicode encoding detection
34 34
 my $UTF_PATTERNS = {
35
-  'UTF-32BE' => qr/^\0\0\0[^\0]/,
36
-  'UTF-16BE' => qr/^\0[^\0]\0[^\0]/,
37
-  'UTF-32LE' => qr/^[^\0]\0\0\0/,
38
-  'UTF-16LE' => qr/^[^\0]\0[^\0]\0/
35
+  'UTF-32BE' => qr/^\x00{3}[^\x00]/,
36
+  'UTF-32LE' => qr/^[^\x00]\x00{3}/,
37
+  'UTF-16BE' => qr/^(?:\x00[^\x00]){2}/,
38
+  'UTF-16LE' => qr/^(?:[^\x00]\x00){2}/
39 39
 };
40 40
 
41 41
 my $WHITESPACE_RE = qr/[\x20\x09\x0a\x0d]*/;
... ...
@@ -75,7 +75,7 @@ sub decode {
75 75
     # Object
76 76
     elsif (m/\G\{/gc) { $ref = _decode_object() }
77 77
 
78
-    # Unexpected
78
+    # Invalid character
79 79
     else { _exception('Expected array or object') }
80 80
 
81 81
     # Leftover data
... ...
@@ -166,13 +166,13 @@ sub _decode_string {
166 166
   my $pos = pos;
167 167
 
168 168
   # Extract string with escaped characters
169
-  m#\G(((?:[^\x00-\x1F\\"]|\\(?:["\\/bfnrt]|u[[:xdigit:]]{4})){0,32766})*)#gc;
169
+  m!\G((?:(?:[^\x00-\x1f\\"]|\\(?:["\\/bfnrt]|u[0-9a-fA-F]{4})){0,32766})*)!gc;
170 170
   my $str = $1;
171 171
 
172
-  # Missing quote
172
+  # Invalid character
173 173
   unless (m/\G"/gc) {
174 174
     _exception('Unexpected character or invalid escape while parsing string')
175
-      if m/\G[\x00-\x1F\\]/;
175
+      if m/\G[\x00-\x1f\\]/;
176 176
     _exception('Unterminated string');
177 177
   }
178 178
 
... ...
@@ -195,18 +195,17 @@ sub _decode_string {
195 195
       my $ord = hex $3;
196 196
 
197 197
       # Surrogate pair
198
-      if (($ord & 0xF800) == 0xD800) {
198
+      if (($ord & 0xf800) == 0xd800) {
199 199
 
200 200
         # High surrogate
201
-        ($ord & 0xFC00) == 0xD800
201
+        ($ord & 0xfc00) == 0xd800
202 202
           or pos($_) = $pos + pos($str), _exception('Missing high-surrogate');
203 203
 
204 204
         # Low surrogate
205 205
         $str =~ m/\G\\u([Dd][C-Fc-f]..)/gc
206 206
           or pos($_) = $pos + pos($str), _exception('Missing low-surrogate');
207 207
 
208
-        # Pair
209
-        $ord = 0x10000 + ($ord - 0xD800) * 0x400 + (hex($1) - 0xDC00);
208
+        $ord = 0x10000 + ($ord - 0xd800) * 0x400 + (hex($1) - 0xdc00);
210 209
       }
211 210
 
212 211
       # Character
... ...
@@ -245,7 +244,7 @@ sub _decode_value {
245 244
   # Null
246 245
   return undef if m/\Gnull/gc;
247 246
 
248
-  # Invalid data
247
+  # Invalid character
249 248
   _exception('Expected string, array, object, number, boolean or null');
250 249
 }
251 250
 
... ...
@@ -263,7 +262,7 @@ sub _encode_object {
263 262
 
264 263
 sub _encode_string {
265 264
   my $str = shift;
266
-  $str =~ s!([\x00-\x1F\x7F\x{2028}\x{2029}\\"/\b\f\n\r\t])!$REVERSE{$1}!gs;
265
+  $str =~ s!([\x00-\x1f\x7f\x{2028}\x{2029}\\"/\b\f\n\r\t])!$REVERSE{$1}!gs;
267 266
   return "\"$str\"";
268 267
 }
269 268
 
... ...
@@ -322,6 +321,8 @@ use overload '0+' => sub { ${$_[0]} }, '""' => sub { ${$_[0]} }, fallback => 1;
322 321
 
323 322
 1;
324 323
 
324
+=encoding utf8
325
+
325 326
 =head1 NAME
326 327
 
327 328
 Mojo::JSON - Minimalistic JSON
... ...
@@ -352,19 +353,28 @@ it for validation.
352 353
 
353 354
 It supports normal Perl data types like C<Scalar>, C<Array> reference, C<Hash>
354 355
 reference and will try to call the C<TO_JSON> method on blessed references, or
355
-stringify them if it doesn't exist.
356
+stringify them if it doesn't exist. Differentiating between strings and
357
+numbers in Perl is hard, depending on how it has been used, a C<Scalar> can be
358
+both at the same time. Since numeric comparisons on strings are very unlikely
359
+to happen intentionally, the numeric value always gets priority, so any
360
+C<Scalar> that has been used in numeric context is considered a number.
356 361
 
357 362
   [1, -2, 3]     -> [1, -2, 3]
358 363
   {"foo": "bar"} -> {foo => 'bar'}
359 364
 
360 365
 Literal names will be translated to and from L<Mojo::JSON> constants or a
361
-similar native Perl value. In addition C<Scalar> references will be used to
362
-generate booleans, based on if their values are true or false.
366
+similar native Perl value.
363 367
 
364 368
   true  -> Mojo::JSON->true
365 369
   false -> Mojo::JSON->false
366 370
   null  -> undef
367 371
 
372
+In addition C<Scalar> references will be used to generate booleans, based on
373
+if their values are true or false.
374
+
375
+  \1 -> true
376
+  \0 -> false
377
+
368 378
 Decoding UTF-16 (LE/BE) and UTF-32 (LE/BE) will be handled transparently,
369 379
 encoding will only generate UTF-8. The two Unicode whitespace characters
370 380
 C<u2028> and C<u2029> will always be escaped to make JSONP easier.
+1 -1
mojo/lib/Mojo/JSON/Pointer.pm
... ...
@@ -53,7 +53,7 @@ L<Mojo::JSON::Pointer> is a relaxed implementation of RFC 6901.
53 53
 
54 54
 =head2 contains
55 55
 
56
-  my $success = $pointer->contains($data, '/foo/1');
56
+  my $bool = $pointer->contains($data, '/foo/1');
57 57
 
58 58
 Check if data structure contains a value that can be identified with the given
59 59
 JSON Pointer.
+23 -20
mojo/lib/Mojo/Loader.pm
... ...
@@ -6,12 +6,11 @@ use File::Spec::Functions qw(catdir catfile splitdir);
6 6
 use Mojo::Exception;
7 7
 use Mojo::Util qw(b64_decode class_to_path);
8 8
 
9
-my %CACHE;
9
+my (%BIN, %CACHE);
10 10
 
11
-sub data {
12
-  my ($self, $class, $data) = @_;
13
-  return $class ? $data ? _all($class)->{$data} : _all($class) : undef;
14
-}
11
+sub data { $_[1] ? $_[2] ? _all($_[1])->{$_[2]} : _all($_[1]) : undef }
12
+
13
+sub is_binary { keys %{_all($_[1])} ? !!$BIN{$_[1]}{$_[2]} : undef }
15 14
 
16 15
 sub load {
17 16
   my ($self, $module) = @_;
... ...
@@ -23,8 +22,7 @@ sub load {
23 22
   return undef if $module->can('new') || eval "require $module; 1";
24 23
 
25 24
   # Exists
26
-  my $path = class_to_path $module;
27
-  return 1 if $@ =~ /^Can't locate $path in \@INC/;
25
+  return 1 if $@ =~ /^Can't locate \Q@{[class_to_path $module]}\E in \@INC/;
28 26
 
29 27
   # Real error
30 28
   return Mojo::Exception->new($@);
... ...
@@ -52,29 +50,26 @@ sub search {
52 50
 sub _all {
53 51
   my $class = shift;
54 52
 
55
-  # Refresh or use cached data
56 53
   my $handle = do { no strict 'refs'; \*{"${class}::DATA"} };
57
-  return $CACHE{$class} || {} unless fileno $handle;
54
+  return $CACHE{$class} || {} if $CACHE{$class} || !fileno $handle;
58 55
   seek $handle, 0, 0;
59
-  my $content = join '', <$handle>;
60
-  close $handle;
56
+  my $data = join '', <$handle>;
61 57
 
62 58
   # Ignore everything before __DATA__ (Windows will seek to start of file)
63
-  $content =~ s/^.*\n__DATA__\r?\n/\n/s;
59
+  $data =~ s/^.*\n__DATA__\r?\n/\n/s;
64 60
 
65 61
   # Ignore everything after __END__
66
-  $content =~ s/\n__END__\r?\n.*$/\n/s;
62
+  $data =~ s/\n__END__\r?\n.*$/\n/s;
67 63
 
68 64
   # Split files
69
-  my @data = split /^@@\s*(.+?)\s*\r?\n/m, $content;
70
-  shift @data;
65
+  (undef, my @files) = split /^@@\s*(.+?)\s*\r?\n/m, $data;
71 66
 
72 67
   # Find data
73 68
   my $all = $CACHE{$class} = {};
74
-  while (@data) {
75
-    my ($name, $content) = splice @data, 0, 2;
76
-    $content = b64_decode $content if $name =~ s/\s*\(\s*base64\s*\)$//;
77
-    $all->{$name} = $content;
69
+  while (@files) {
70
+    my ($name, $data) = splice @files, 0, 2;
71
+    $all->{$name} = $name =~ s/\s*\(\s*base64\s*\)$//
72
+      && ++$BIN{$class}{$name} ? b64_decode($data) : $data;
78 73
   }
79 74
 
80 75
   return $all;
... ...
@@ -82,6 +77,8 @@ sub _all {
82 77
 
83 78
 1;
84 79
 
80
+=encoding utf8
81
+
85 82
 =head1 NAME
86 83
 
87 84
 Mojo::Loader - Loader
... ...
@@ -120,6 +117,12 @@ Extract embedded file from the C<DATA> section of a class.
120 117
 
121 118
   say for keys %{$loader->data('Foo::Bar')};
122 119
 
120
+=head2 is_binary
121
+
122
+  my $bool = $loader->is_binary('Foo::Bar', 'test.png');
123
+
124
+Check if embedded file from the C<DATA> section of a class was Base64 encoded.
125
+
123 126
 =head2 load
124 127
 
125 128
   my $e = $loader->load('Foo::Bar');
... ...
@@ -128,7 +131,7 @@ Load a class and catch exceptions. Note that classes are checked for a C<new>
128 131
 method to see if they are already loaded.
129 132
 
130 133
   if (my $e = $loader->load('Foo::Bar')) {
131
-    die ref $e ? "Exception: $e" : 'Already loaded!';
134
+    die ref $e ? "Exception: $e" : 'Not found!';
132 135
   }
133 136
 
134 137
 =head2 search
+32 -39
mojo/lib/Mojo/Log.pm
... ...
@@ -35,7 +35,8 @@ sub fatal { shift->log(fatal => @_) }
35 35
 
36 36
 sub format {
37 37
   my ($self, $level, @lines) = @_;
38
-  return '[' . localtime(time) . "] [$level] " . join("\n", @lines) . "\n";
38
+  return encode 'UTF-8',
39
+    '[' . localtime(time) . "] [$level] " . join("\n", @lines, '');
39 40
 }
40 41
 
41 42
 sub info { shift->log(info => @_) }
... ...
@@ -57,18 +58,19 @@ sub log { shift->emit('message', lc(shift), @_) }
57 58
 sub warn { shift->log(warn => @_) }
58 59
 
59 60
 sub _message {
60
-  my ($self, $level, @lines) = @_;
61
+  my ($self, $level) = (shift, shift);
61 62
 
62 63
   return unless $self->is_level($level) && (my $handle = $self->handle);
63 64
 
64 65
   flock $handle, LOCK_EX;
65
-  croak "Can't write to log: $!"
66
-    unless $handle->print(encode 'UTF-8', $self->format($level, @lines));
66
+  $handle->print($self->format($level, @_)) or croak "Can't write to log: $!";
67 67
   flock $handle, LOCK_UN;
68 68
 }
69 69
 
70 70
 1;
71 71
 
72
+=encoding utf8
73
+
72 74
 =head1 NAME
73 75
 
74 76
 Mojo::Log - Simple logger
... ...
@@ -123,39 +125,24 @@ L<Mojo::Log> implements the following attributes.
123 125
   my $handle = $log->handle;
124 126
   $log       = $log->handle(IO::Handle->new);
125 127
 
126
-Log file handle used by default C<message> event, defaults to opening C<path>
127
-or C<STDERR>.
128
+Log filehandle used by default L</"message"> event, defaults to opening
129
+L</"path"> or C<STDERR>.
128 130
 
129 131
 =head2 level
130 132
 
131 133
   my $level = $log->level;
132 134
   $log      = $log->level('debug');
133 135
 
134
-Active log level, defaults to C<debug>. Note that the MOJO_LOG_LEVEL
135
-environment variable can override this value.
136
-
137
-These levels are currently available:
138
-
139
-=over 2
140
-
141
-=item debug
142
-
143
-=item info
144
-
145
-=item warn
146
-
147
-=item error
148
-
149
-=item fatal
150
-
151
-=back
136
+Active log level, defaults to C<debug>. Available log levels are C<debug>,
137
+C<info>, C<warn>, C<error> and C<fatal>, in that order. Note that the
138
+MOJO_LOG_LEVEL environment variable can override this value.
152 139
 
153 140
 =head2 path
154 141
 
155 142
   my $path = $log->path
156 143
   $log     = $log->path('/var/log/mojo.log');
157 144
 
158
-Log file path used by C<handle>.
145
+Log file path used by L</"handle">.
159 146
 
160 147
 =head1 METHODS
161 148
 
... ...
@@ -166,85 +153,91 @@ the following new ones.
166 153
 
167 154
   my $log = Mojo::Log->new;
168 155
 
169
-Construct a new L<Mojo::Log> object and subscribe to C<message> event with
156
+Construct a new L<Mojo::Log> object and subscribe to L</"message"> event with
170 157
 default logger.
171 158
 
172 159
 =head2 debug
173 160
 
174
-  $log = $log->debug('You screwed up, but that is ok');
161
+  $log = $log->debug('You screwed up, but that is ok.');
162
+  $log = $log->debug('All', 'cool!');
175 163
 
176 164
 Log debug message.
177 165
 
178 166
 =head2 error
179 167
 
180
-  $log = $log->error('You really screwed up this time');
168
+  $log = $log->error('You really screwed up this time.');
169
+  $log = $log->error('Wow', 'seriously!');
181 170
 
182 171
 Log error message.
183 172
 
184 173
 =head2 fatal
185 174
 
186 175
   $log = $log->fatal('Its over...');
176
+  $log = $log->fatal('Bye', 'bye!');
187 177
 
188 178
 Log fatal message.
189 179
 
190 180
 =head2 format
191 181
 
192
-  my $msg = $log->format('debug', 'Hi there!');
193
-  my $msg = $log->format('debug', 'Hi', 'there!');
182
+  my $msg = $log->format(debug => 'Hi there!');
183
+  my $msg = $log->format(debug => 'Hi', 'there!');
194 184
 
195 185
 Format log message.
196 186
 
197 187
 =head2 info
198 188
 
199
-  $log = $log->info('You are bad, but you prolly know already');
189
+  $log = $log->info('You are bad, but you prolly know already.');
190
+  $log = $log->info('Ok', 'then!');
200 191
 
201 192
 Log info message.
202 193
 
203 194
 =head2 is_level
204 195
 
205
-  my $success = $log->is_level('debug');
196
+  my $bool = $log->is_level('debug');
206 197
 
207 198
 Check log level.
208 199
 
209 200
 =head2 is_debug
210 201
 
211
-  my $success = $log->is_debug;
202
+  my $bool = $log->is_debug;
212 203
 
213 204
 Check for debug log level.
214 205
 
215 206
 =head2 is_error
216 207
 
217
-  my $success = $log->is_error;
208
+  my $bool = $log->is_error;
218 209
 
219 210
 Check for error log level.
220 211
 
221 212
 =head2 is_fatal
222 213
 
223
-  my $success = $log->is_fatal;
214
+  my $bool = $log->is_fatal;
224 215
 
225 216
 Check for fatal log level.
226 217
 
227 218
 =head2 is_info
228 219
 
229
-  my $success = $log->is_info;
220
+  my $bool = $log->is_info;
230 221
 
231 222
 Check for info log level.
232 223
 
233 224
 =head2 is_warn
234 225
 
235
-  my $success = $log->is_warn;
226
+  my $bool = $log->is_warn;
236 227
 
237 228
 Check for warn log level.
238 229
 
239 230
 =head2 log
240 231
 
241
-  $log = $log->log(debug => 'This should work');
232
+  $log = $log->log(debug => 'This should work.');
233
+  $log = $log->log(debug => 'This', 'too!');
242 234
 
243
-Emit C<message> event.
235
+Emit L</"message"> event.
244 236
 
245 237
 =head2 warn
246 238
 
247 239
   $log = $log->warn('Dont do that Dave...');
240
+  $log = $log->warn('No', 'really!');
248 241
 
249 242
 Log warn message.
250 243
 
+67 -56
mojo/lib/Mojo/Message.pm
... ...
@@ -14,7 +14,7 @@ use Mojo::Util 'decode';
14 14
 has content => sub { Mojo::Content::Single->new };
15 15
 has default_charset  => 'UTF-8';
16 16
 has max_line_size    => sub { $ENV{MOJO_MAX_LINE_SIZE} || 10240 };
17
-has max_message_size => sub { $ENV{MOJO_MAX_MESSAGE_SIZE} || 5242880 };
17
+has max_message_size => sub { defined $ENV{MOJO_MAX_MESSAGE_SIZE} ? $ENV{MOJO_MAX_MESSAGE_SIZE} : 10485760 };
18 18
 has version          => '1.1';
19 19
 
20 20
 sub body {
... ...
@@ -28,7 +28,7 @@ sub body {
28 28
   # Get
29 29
   return $content->asset->slurp unless @_;
30 30
 
31
-  # Set raw content
31
+  # Set
32 32
   $content->asset(Mojo::Asset::Memory->new->add_chunk(@_));
33 33
 
34 34
   return $self;
... ...
@@ -41,17 +41,15 @@ sub body_params {
41 41
   my $params = $self->{body_params} = Mojo::Parameters->new;
42 42
   $params->charset($self->content->charset || $self->default_charset);
43 43
 
44
-  # "x-application-urlencoded" and "application/x-www-form-urlencoded"
44
+  # "application/x-www-form-urlencoded"
45 45
   my $type = defined $self->headers->content_type ? $self->headers->content_type : '';
46
-  if ($type =~ m!(?:x-application|application/x-www-form)-urlencoded!i) {
46
+  if ($type =~ m!application/x-www-form-urlencoded!i) {
47 47
     $params->parse($self->content->asset->slurp);
48 48
   }
49 49
 
50
-  # "multipart/formdata"
50
+  # "multipart/form-data"
51 51
   elsif ($type =~ m!multipart/form-data!i) {
52
-    for my $data (@{$self->_parse_formdata}) {
53
-      $params->append($data->[0], $data->[2]) unless defined $data->[1];
54
-    }
52
+    $params->append(@$_[0, 1]) for @{$self->_parse_formdata};
55 53
   }
56 54
 
57 55
   return $params;
... ...
@@ -69,13 +67,8 @@ sub cookies { croak 'Method "cookies" not implemented by subclass' }
69 67
 
70 68
 sub dom {
71 69
   my $self = shift;
72
-
73 70
   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);
78
-
71
+  my $dom = $self->{dom} ||= Mojo::DOM->new($self->text);
79 72
   return @_ ? $dom->find(@_) : $dom;
80 73
 }
81 74
 
... ...
@@ -160,8 +153,9 @@ sub parse {
160 153
   my ($self, $chunk) = @_;
161 154
 
162 155
   # Check message size
156
+  my $max = $self->max_message_size;
163 157
   return $self->_limit('Maximum message size exceeded', 413)
164
-    if ($self->{raw_size} += length($chunk = defined $chunk ? $chunk : '')) > $self->max_message_size;
158
+    if $max && ($self->{raw_size} += length($chunk = defined $chunk ? $chunk : '')) > $max;
165 159
 
166 160
   $self->{buffer} .= $chunk;
167 161
 
... ...
@@ -195,6 +189,13 @@ sub parse {
195 189
 
196 190
 sub start_line_size { length shift->build_start_line }
197 191
 
192
+sub text {
193
+  my $self    = shift;
194
+  my $body    = $self->body;
195
+  my $charset = $self->content->charset;
196
+  return $charset ? do {my $decoded = decode($charset, $body); defined $decoded ? $decoded : $body} : $body;
197
+}
198
+
198 199
 sub to_string {
199 200
   my $self = shift;
200 201
   return $self->build_start_line . $self->build_headers . $self->build_body;
... ...
@@ -206,17 +207,12 @@ sub uploads {
206 207
   my $self = shift;
207 208
 
208 209
   my @uploads;
209
-  for my $data (@{$self->_parse_formdata}) {
210
-
211
-    # Just a form value
212
-    next unless defined $data->[1];
213
-
214
-    # Uploaded file
210
+  for my $data (@{$self->_parse_formdata(1)}) {
215 211
     my $upload = Mojo::Upload->new(
216 212
       name     => $data->[0],
217
-      filename => $data->[1],
218
-      asset    => $data->[2]->asset,
219
-      headers  => $data->[2]->headers
213
+      filename => $data->[2],
214
+      asset    => $data->[1]->asset,
215
+      headers  => $data->[1]->headers
220 216
     );
221 217
     push @uploads, $upload;
222 218
   }
... ...
@@ -264,41 +260,37 @@ sub _limit {
264 260
 }
265 261
 
266 262
 sub _parse_formdata {
267
-  my $self = shift;
263
+  my ($self, $upload) = @_;
268 264
 
269
-  # Check for multipart content
270 265
   my @formdata;
271 266
   my $content = $self->content;
272 267
   return \@formdata unless $content->is_multipart;
273 268
   my $charset = $content->charset || $self->default_charset;
274 269
 
275
-  # Check all parts for form data
270
+  # Check all parts recursively
276 271
   my @parts = ($content);
277 272
   while (my $part = shift @parts) {
278 273
 
279
-    # Nested multipart content
280 274
     if ($part->is_multipart) {
281 275
       unshift @parts, @{$part->parts};
282 276
       next;
283 277
     }
284 278
 
285
-    # Extract information from Content-Disposition header
286 279
     next unless my $disposition = $part->headers->content_disposition;
287
-    my ($name)     = $disposition =~ /[; ]name="?([^";]+)"?/;
288
-    my ($filename) = $disposition =~ /[; ]filename="?([^"]*)"?/;
280
+    my ($filename) = $disposition =~ /[; ]filename\s*=\s*"?((?:\\"|[^"])*)"?/i;
281
+    next if ($upload && !defined $filename) || (!$upload && defined $filename);
282
+    my ($name) = $disposition =~ /[; ]name\s*=\s*"?((?:\\"|[^";])+)"?/i;
289 283
     if ($charset) {
290 284
       $name     = do {my $tmp = decode($charset, $name); defined $tmp ? $tmp : $name} if $name;
291 285
       $filename = do {my $tmp = decode($charset, $filename); defined $tmp ? $tmp : $filename} if $filename;
292 286
     }
293 287
 
294
-    # Check for file upload
295
-    my $value = $part;
296
-    unless (defined $filename) {
297
-      $value = $part->asset->slurp;
298
-      $value = do {my $tmp = decode($charset, $value); defined $tmp ? $tmp : $value} if $charset;
288
+    unless ($upload) {
289
+      $part = $part->asset->slurp;
290
+      $part = do {my $decoded = decode($charset, $part); defined $decoded ? $decoded : $part} if $charset;
299 291
     }
300 292
 
301
-    push @formdata, [$name, $filename, $value];
293
+    push @formdata, [$name, $part, $filename];
302 294
   }
303 295
 
304 296
   return \@formdata;
... ...
@@ -306,6 +298,8 @@ sub _parse_formdata {
306 298
 
307 299
 1;
308 300
 
301
+=encoding utf8
302
+
309 303
 =head1 NAME
310 304
 
311 305
 Mojo::Message - HTTP message base class
... ...
@@ -383,7 +377,7 @@ Message content, defaults to a L<Mojo::Content::Single> object.
383 377
   my $charset = $msg->default_charset;
384 378
   $msg        = $msg->default_charset('UTF-8');
385 379
 
386
-Default charset used for form data parsing, defaults to C<UTF-8>.
380
+Default charset used for form-data parsing, defaults to C<UTF-8>.
387 381
 
388 382
 =head2 max_line_size
389 383
 
... ...
@@ -399,10 +393,11 @@ MOJO_MAX_LINE_SIZE environment variable or C<10240>.
399 393
   $msg     = $msg->max_message_size(1024);
400 394
 
401 395
 Maximum message size in bytes, defaults to the value of the
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.
396
+MOJO_MAX_MESSAGE_SIZE environment variable or C<10485760>. Setting the value
397
+to C<0> will allow messages of indefinite size. Note that increasing this
398
+value can also drastically increase memory usage, should you for example
399
+attempt to parse an excessively large message body with the L</"body_params">,
400
+L</"dom"> or L</"json"> methods.
406 401
 
407 402
 =head2 version
408 403
 
... ...
@@ -421,16 +416,19 @@ implements the following new ones.
421 416
   my $bytes = $msg->body;
422 417
   $msg      = $msg->body('Hello!');
423 418
 
424
-Slurp or replace C<content>.
419
+Slurp or replace L</"content">, L<Mojo::Content::MultiPart> will be
420
+automatically downgraded to L<Mojo::Content::Single>.
425 421
 
426 422
 =head2 body_params
427 423
 
428 424
   my $params = $msg->body_params;
429 425
 
430
-C<POST> parameters extracted from C<x-application-urlencoded>,
431
-C<application/x-www-form-urlencoded> or C<multipart/form-data> message body,
432
-usually a L<Mojo::Parameters> object. Note that this method caches all data,
433
-so it should not be called before the entire message body has been received.
426
+POST parameters extracted from C<application/x-www-form-urlencoded> or
427
+C<multipart/form-data> message body, usually a L<Mojo::Parameters> object.
428
+Note that this method caches all data, so it should not be called before the
429
+entire message body has been received. Parts of the message body need to be
430
+loaded into memory to parse POST parameters, so you have to make sure it is
431
+not excessively large.
434 432
 
435 433
   # Get POST parameter value
436 434
   say $msg->body_params->param('foo');
... ...
@@ -485,14 +483,16 @@ Access message cookies. Meant to be overloaded in a subclass.
485 483
 Turns message body into a L<Mojo::DOM> object and takes an optional selector
486 484
 to perform a C<find> on it right away, which returns a L<Mojo::Collection>
487 485
 object. Note that this method caches all data, so it should not be called
488
-before the entire message body has been received.
486
+before the entire message body has been received. The whole message body needs
487
+to be loaded into memory to parse it, so you have to make sure it is not
488
+excessively large.
489 489
 
490 490
   # Perform "find" right away
491
-  say $msg->dom('h1, h2, h3')->pluck('text');
491
+  say $msg->dom('h1, h2, h3')->text;
492 492
 
493 493
   # Use everything else Mojo::DOM has to offer
494 494
   say $msg->dom->at('title')->text;
495
-  say $msg->dom->html->body->children->pluck('type')->uniq;
495
+  say $msg->dom->html->body->children->type->uniq;
496 496
 
497 497
 =head2 error
498 498
 
... ...
@@ -505,7 +505,7 @@ Error and code.
505 505
 
506 506
 =head2 extract_start_line
507 507
 
508
-  my $success = $msg->extract_start_line(\$str);
508
+  my $bool = $msg->extract_start_line(\$str);
509 509
 
510 510
 Extract start line from string. Meant to be overloaded in a subclass.
511 511
 
... ...
@@ -554,15 +554,15 @@ Message headers, usually a L<Mojo::Headers> object.
554 554
 
555 555
 =head2 is_finished
556 556
 
557
-  my $success = $msg->is_finished;
557
+  my $bool = $msg->is_finished;
558 558
 
559 559
 Check if message parser/generator is finished.
560 560
 
561 561
 =head2 is_limit_exceeded
562 562
 
563
-  my $success = $msg->is_limit_exceeded;
563
+  my $bool = $msg->is_limit_exceeded;
564 564
 
565
-Check if message has exceeded C<max_line_size> or C<max_message_size>.
565
+Check if message has exceeded L</"max_line_size"> or L</"max_message_size">.
566 566
 
567 567
 =head2 json
568 568
 
... ...
@@ -574,6 +574,8 @@ Decode JSON message body directly using L<Mojo::JSON> if possible, returns
574 574
 C<undef> otherwise. An optional JSON Pointer can be used to extract a specific
575 575
 value with L<Mojo::JSON::Pointer>. Note that this method caches all data, so
576 576
 it should not be called before the entire message body has been received.
577
+The whole message body needs to be loaded into memory to parse it, so you have
578
+to make sure it is not excessively large.
577 579
 
578 580
   # Extract JSON values
579 581
   say $msg->json->{foo}{bar}[23];
... ...
@@ -585,8 +587,10 @@ it should not be called before the entire message body has been received.
585 587
   my $foo   = $msg->param('foo');
586 588
   my @foo   = $msg->param('foo');
587 589
 
588
-Access C<POST> parameters. Note that this method caches all data, so it should
589
-not be called before the entire message body has been received.
590
+Access POST parameters. Note that this method caches all data, so it should
591
+not be called before the entire message body has been received. Parts of the
592
+message body need to be loaded into memory to parse POST parameters, so you
593
+have to make sure it is not excessively large.
590 594
 
591 595
 =head2 parse
592 596
 
... ...
@@ -600,6 +604,13 @@ Parse message chunk.
600 604
 
601 605
 Size of the start line in bytes.
602 606
 
607
+=head2 text
608
+
609
+  my $str = $msg->text;
610
+
611
+Retrieve L</"body"> and try to decode it if a charset could be extracted with
612
+L<Mojo::Content/"charset">.
613
+
603 614
 =head2 to_string
604 615
 
605 616
   my $str = $msg->to_string;
+23 -17
mojo/lib/Mojo/Message/Request.pm
... ...
@@ -9,14 +9,14 @@ has env => sub { {} };
9 9
 has method => 'GET';
10 10
 has url => sub { Mojo::URL->new };
11 11
 
12
-my $START_LINE_RE = qr|
12
+my $START_LINE_RE = qr/
13 13
   ^
14
-  ([a-zA-Z]+)                                  # Method
14
+  ([a-zA-Z]+)                                            # Method
15 15
   \s+
16
-  ([0-9a-zA-Z\-._~:/?#[\]\@!\$&'()*+,;=\%]+)   # Path
17
-  (?:\s+HTTP/(\d\.\d))?                        # Version
16
+  ([0-9a-zA-Z!#\$\%&'()*+,\-.\/:;=?\@[\\\]^_`\{|\}~]+)   # URL
17
+  (?:\s+HTTP\/(\d\.\d))?                                 # Version
18 18
   $
19
-|x;
19
+/x;
20 20
 
21 21
 sub clone {
22 22
   my $self = shift;
... ...
@@ -260,6 +260,8 @@ sub _parse_env {
260 260
 
261 261
 1;
262 262
 
263
+=encoding utf8
264
+
263 265
 =head1 NAME
264 266
 
265 267
 Mojo::Message::Request - HTTP request
... ...
@@ -270,9 +272,9 @@ Mojo::Message::Request - HTTP request
270 272
 
271 273
   # Parse
272 274
   my $req = Mojo::Message::Request->new;
273
-  $req->parse("GET /foo HTTP/1.0\x0a\x0d");
274
-  $req->parse("Content-Length: 12\x0a\x0d\x0a\x0d");
275
-  $req->parse("Content-Type: text/plain\x0a\x0d\x0a\x0d");
275
+  $req->parse("GET /foo HTTP/1.0\x0d\x0a");
276
+  $req->parse("Content-Length: 12\x0d\x0a");
277
+  $req->parse("Content-Type: text/plain\x0d\x0a\x0d\x0a");
276 278
   $req->parse('Hello World!');
277 279
   say $req->method;
278 280
   say $req->headers->content_type;
... ...
@@ -351,7 +353,7 @@ Access request cookies, usually L<Mojo::Cookie::Request> objects.
351 353
 
352 354
 =head2 extract_start_line
353 355
 
354
-  my $success = $req->extract_start_line(\$str);
356
+  my $bool = $req->extract_start_line(\$str);
355 357
 
356 358
 Extract request line from string.
357 359
 
... ...
@@ -369,13 +371,13 @@ Get a chunk of request line data starting from a specific position.
369 371
 
370 372
 =head2 is_secure
371 373
 
372
-  my $success = $req->is_secure;
374
+  my $bool = $req->is_secure;
373 375
 
374 376
 Check if connection is secure.
375 377
 
376 378
 =head2 is_xhr
377 379
 
378
-  my $success = $req->is_xhr;
380
+  my $bool = $req->is_xhr;
379 381
 
380 382
 Check C<X-Requested-With> header for C<XMLHttpRequest> value.
381 383
 
... ...
@@ -385,16 +387,20 @@ Check C<X-Requested-With> header for C<XMLHttpRequest> value.
385 387
   my $foo   = $req->param('foo');
386 388
   my @foo   = $req->param('foo');
387 389
 
388
-Access C<GET> and C<POST> parameters. Note that this method caches all data,
389
-so it should not be called before the entire request body has been received.
390
+Access GET and POST parameters. Note that this method caches all data, so it
391
+should not be called before the entire request body has been received. Parts
392
+of the request body need to be loaded into memory to parse POST parameters, so
393
+you have to make sure it is not excessively large.
390 394
 
391 395
 =head2 params
392 396
 
393 397
   my $params = $req->params;
394 398
 
395
-All C<GET> and C<POST> parameters, usually a L<Mojo::Parameters> object. Note
396
-that this method caches all data, so it should not be called before the entire
397
-request body has been received.
399
+All GET and POST parameters, usually a L<Mojo::Parameters> object. Note that
400
+this method caches all data, so it should not be called before the entire
401
+request body has been received. Parts of the request body need to be loaded
402
+into memory to parse POST parameters, so you have to make sure it is not
403
+excessively large.
398 404
 
399 405
   # Get parameter value
400 406
   say $req->params->param('foo');
... ...
@@ -422,7 +428,7 @@ Proxy URL for request.
422 428
 
423 429
   my $params = $req->query_params;
424 430
 
425
-All C<GET> parameters, usually a L<Mojo::Parameters> object.
431
+All GET parameters, usually a L<Mojo::Parameters> object.
426 432
 
427 433
   # Turn GET parameters to hash and extract value
428 434
   say $req->query_params->to_hash->{foo};
+9 -7
mojo/lib/Mojo/Message/Response.pm
... ...
@@ -140,6 +140,8 @@ sub is_status_class {
140 140
 
141 141
 1;
142 142
 
143
+=encoding utf8
144
+
143 145
 =head1 NAME
144 146
 
145 147
 Mojo::Message::Response - HTTP response
... ...
@@ -149,10 +151,10 @@ Mojo::Message::Response - HTTP response
149 151
   use Mojo::Message::Response;
150 152
 
151 153
   # Parse
152
-  my $res = Mojo::Message::Reponse->new;
153
-  $res->parse("HTTP/1.0 200 OK\x0a\x0d");
154
-  $res->parse("Content-Length: 12\x0a\x0d\x0a\x0d");
155
-  $res->parse("Content-Type: text/plain\x0a\x0d\x0a\x0d");
154
+  my $res = Mojo::Message::Response->new;
155
+  $res->parse("HTTP/1.0 200 OK\x0d\x0a");
156
+  $res->parse("Content-Length: 12\x0d\x0a");
157
+  $res->parse("Content-Type: text/plain\x0d\x0a\x0d\x0a");
156 158
   $res->parse('Hello World!');
157 159
   say $res->code;
158 160
   say $res->headers->content_type;
... ...
@@ -214,7 +216,7 @@ Generate default response message for code.
214 216
 
215 217
 =head2 extract_start_line
216 218
 
217
-  my $success = $res->extract_start_line(\$str);
219
+  my $bool = $res->extract_start_line(\$str);
218 220
 
219 221
 Extract status line from string.
220 222
 
... ...
@@ -232,13 +234,13 @@ Get a chunk of status line data starting from a specific position.
232 234
 
233 235
 =head2 is_empty
234 236
 
235
-  my $success = $res->is_empty;
237
+  my $bool = $res->is_empty;
236 238
 
237 239
 Check if this is a C<1xx>, C<204> or C<304> response.
238 240
 
239 241
 =head2 is_status_class
240 242
 
241
-  my $success = $res->is_status_class(200);
243
+  my $bool = $res->is_status_class(200);
242 244
 
243 245
 Check response status class.
244 246
 
+2 -2
mojo/lib/Mojo/Parameters.pm
... ...
@@ -2,7 +2,7 @@ package Mojo::Parameters;
2 2
 use Mojo::Base -base;
3 3
 use overload
4 4
   '@{}'    => sub { shift->params },
5
-  'bool'   => sub {1},
5
+  bool     => sub {1},
6 6
   '""'     => sub { shift->to_string },
7 7
   fallback => 1;
8 8
 
... ...
@@ -230,7 +230,7 @@ following new ones.
230 230
   my $params = Mojo::Parameters->new(foo => ['ba;r', 'b;az']);
231 231
   my $params = Mojo::Parameters->new(foo => ['ba;r', 'b;az'], bar => 23);
232 232
 
233
-Construct a new L<Mojo::Parameters> object and C<parse> parameters if
233
+Construct a new L<Mojo::Parameters> object and L</"parse"> parameters if
234 234
 necessary.
235 235
 
236 236
 =head2 append
+16 -13
mojo/lib/Mojo/Path.pm
... ...
@@ -2,7 +2,7 @@ package Mojo::Path;
2 2
 use Mojo::Base -base;
3 3
 use overload
4 4
   '@{}'    => sub { shift->parts },
5
-  'bool'   => sub {1},
5
+  bool     => sub {1},
6 6
   '""'     => sub { shift->to_string },
7 7
   fallback => 1;
8 8
 
... ...
@@ -67,7 +67,7 @@ sub merge {
67 67
 sub parse {
68 68
   my $self = shift;
69 69
   $self->{path} = shift;
70
-  delete $self->{$_} for qw(leading_slash parts trailing_slash);
70
+  delete @$self{qw(leading_slash parts trailing_slash)};
71 71
   return $self;
72 72
 }
73 73
 
... ...
@@ -81,7 +81,7 @@ sub to_abs_string {
81 81
 sub to_dir {
82 82
   my $clone = shift->clone;
83 83
   pop @{$clone->parts} unless $clone->trailing_slash;
84
-  return $clone->trailing_slash(@{$clone->parts} ? 1 : 0);
84
+  return $clone->trailing_slash(!!@{$clone->parts});
85 85
 }
86 86
 
87 87
 sub to_route {
... ...
@@ -118,10 +118,10 @@ sub _parse {
118 118
   unless ($self->{parts}) {
119 119
     my $path = url_unescape do { my $tmp = delete($self->{path}); defined $tmp ? $tmp : '' };
120 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];
121
+    $path = do {my $decoded = decode($charset, $path); defined $decoded ? $decoded : $path} if $charset;
122
+    $self->{leading_slash}  = $path =~ s!^/!!;
123
+    $self->{trailing_slash} = $path =~ s!/$!!;
124
+    $self->{parts}          = [split '/', $path, -1];
125 125
   }
126 126
 
127 127
   return $self->{$name} unless @_;
... ...
@@ -178,7 +178,7 @@ following new ones.
178 178
   my $path = Mojo::Path->new;
179 179
   my $path = Mojo::Path->new('/foo%2Fbar%3B/baz.html');
180 180
 
181
-Construct a new L<Mojo::Path> object and C<parse> path if necessary.
181
+Construct a new L<Mojo::Path> object and L</"parse"> path if necessary.
182 182
 
183 183
 =head2 canonicalize
184 184
 
... ...
@@ -189,6 +189,9 @@ Canonicalize path.
189 189
   # "/foo/baz"
190 190
   Mojo::Path->new('/foo/./bar/../baz')->canonicalize;
191 191
 
192
+  # "/../baz"
193
+  Mojo::Path->new('/foo/../bar/../../baz')->canonicalize;
194
+
192 195
 =head2 clone
193 196
 
194 197
   my $clone = $path->clone;
... ...
@@ -197,7 +200,7 @@ Clone path.
197 200
 
198 201
 =head2 contains
199 202
 
200
-  my $success = $path->contains('/i/♥/mojolicious');
203
+  my $bool = $path->contains('/i/♥/mojolicious');
201 204
 
202 205
 Check if path contains given prefix.
203 206
 
... ...
@@ -213,8 +216,8 @@ Check if path contains given prefix.
213 216
 
214 217
 =head2 leading_slash
215 218
 
216
-  my $slash = $path->leading_slash;
217
-  $path     = $path->leading_slash(1);
219
+  my $bool = $path->leading_slash;
220
+  $path    = $path->leading_slash($bool);
218 221
 
219 222
 Path has a leading slash. Note that this method will normalize the path and
220 223
 that C<%2F> will be treated as C</> for security reasons.
... ...
@@ -301,8 +304,8 @@ Turn path into a string.
301 304
 
302 305
 =head2 trailing_slash
303 306
 
304
-  my $slash = $path->trailing_slash;
305
-  $path     = $path->trailing_slash(1);
307
+  my $bool = $path->trailing_slash;
308
+  $path    = $path->trailing_slash($bool);
306 309
 
307 310
 Path has a trailing slash. Note that this method will normalize the path and
308 311
 that C<%2F> will be treated as C</> for security reasons.
+10 -6
mojo/lib/Mojo/Reactor.pm
... ...
@@ -37,6 +37,8 @@ sub watch      { croak 'Method "watch" not implemented by subclass' }
37 37
 
38 38
 1;
39 39
 
40
+=encoding utf8
41
+
40 42
 =head1 NAME
41 43
 
42 44
 Mojo::Reactor - Low level event reactor base class
... ...
@@ -75,7 +77,9 @@ the following new ones.
75 77
     ...
76 78
   });
77 79
 
78
-Emitted safely for exceptions caught in callbacks.
80
+Emitted for exceptions caught in callbacks, fatal if unhandled. Note that if
81
+this event is unhandled or fails it might kill your program, so you need to be
82
+careful.
79 83
 
80 84
   $reactor->on(error => sub {
81 85
     my ($reactor, $err) = @_;
... ...
@@ -119,14 +123,14 @@ readable or writable. Meant to be overloaded in a subclass.
119 123
 
120 124
 =head2 is_readable
121 125
 
122
-  my $success = $reactor->is_readable($handle);
126
+  my $bool = $reactor->is_readable($handle);
123 127
 
124 128
 Quick non-blocking check if a handle is readable, useful for identifying
125 129
 tainted sockets.
126 130
 
127 131
 =head2 is_running
128 132
 
129
-  my $success = $reactor->is_running;
133
+  my $bool = $reactor->is_running;
130 134
 
131 135
 Check if reactor is running. Meant to be overloaded in a subclass.
132 136
 
... ...
@@ -154,8 +158,8 @@ amount of time in seconds. Meant to be overloaded in a subclass.
154 158
 
155 159
 =head2 remove
156 160
 
157
-  my $success = $reactor->remove($handle);
158
-  my $success = $reactor->remove($id);
161
+  my $bool = $reactor->remove($handle);
162
+  my $bool = $reactor->remove($id);
159 163
 
160 164
 Remove handle or timer. Meant to be overloaded in a subclass.
161 165
 
... ...
@@ -163,7 +167,7 @@ Remove handle or timer. Meant to be overloaded in a subclass.
163 167
 
164 168
   $reactor->start;
165 169
 
166
-Start watching for I/O and timer events, this will block until C<stop> is
170
+Start watching for I/O and timer events, this will block until L</"stop"> is
167 171
 called. Note that some reactors stop automatically if there are no events
168 172
 being watched anymore. Meant to be overloaded in a subclass.
169 173
 
+4 -2
mojo/lib/Mojo/Reactor/EV.pm
... ...
@@ -72,6 +72,8 @@ sub _timer {
72 72
 
73 73
 1;
74 74
 
75
+=encoding utf8
76
+
75 77
 =head1 NAME
76 78
 
77 79
 Mojo::Reactor::EV - Low level event reactor with libev support
... ...
@@ -127,7 +129,7 @@ Restart active timer.
127 129
 
128 130
 =head2 is_running
129 131
 
130
-  my $success = $reactor->is_running;
132
+  my $bool = $reactor->is_running;
131 133
 
132 134
 Check if reactor is running.
133 135
 
... ...
@@ -149,7 +151,7 @@ amount of time in seconds.
149 151
 
150 152
   $reactor->start;
151 153
 
152
-Start watching for I/O and timer events, this will block until C<stop> is
154
+Start watching for I/O and timer events, this will block until L</"stop"> is
153 155
 called or no events are being watched anymore.
154 156
 
155 157
 =head2 stop
+8 -6
mojo/lib/Mojo/Reactor/Poll.pm
... ...
@@ -105,8 +105,8 @@ sub watch {
105 105
 sub _poll { shift->{poll} ||= IO::Poll->new }
106 106
 
107 107
 sub _sandbox {
108
-  my ($self, $desc, $cb) = (shift, shift, shift);
109
-  eval { $self->$cb(@_); 1 } or $self->emit_safe(error => "$desc failed: $@");
108
+  my ($self, $event, $cb) = (shift, shift, shift);
109
+  eval { $self->$cb(@_); 1 } or $self->emit(error => "$event failed: $@");
110 110
 }
111 111
 
112 112
 sub _timer {
... ...
@@ -124,6 +124,8 @@ sub _timer {
124 124
 
125 125
 1;
126 126
 
127
+=encoding utf8
128
+
127 129
 =head1 NAME
128 130
 
129 131
 Mojo::Reactor::Poll - Low level event reactor with poll support
... ...
@@ -180,7 +182,7 @@ readable or writable.
180 182
 
181 183
 =head2 is_running
182 184
 
183
-  my $success = $reactor->is_running;
185
+  my $bool = $reactor->is_running;
184 186
 
185 187
 Check if reactor is running.
186 188
 
... ...
@@ -200,8 +202,8 @@ amount of time in seconds.
200 202
 
201 203
 =head2 remove
202 204
 
203
-  my $success = $reactor->remove($handle);
204
-  my $success = $reactor->remove($id);
205
+  my $bool = $reactor->remove($handle);
206
+  my $bool = $reactor->remove($id);
205 207
 
206 208
 Remove handle or timer.
207 209
 
... ...
@@ -209,7 +211,7 @@ Remove handle or timer.
209 211
 
210 212
   $reactor->start;
211 213
 
212
-Start watching for I/O and timer events, this will block until C<stop> is
214
+Start watching for I/O and timer events, this will block until L</"stop"> is
213 215
 called or no events are being watched anymore.
214 216
 
215 217
 =head2 stop
+6 -4
mojo/lib/Mojo/Server.pm
... ...
@@ -2,7 +2,6 @@ package Mojo::Server;
2 2
 use Mojo::Base 'Mojo::EventEmitter';
3 3
 
4 4
 use Carp 'croak';
5
-use FindBin;
6 5
 use Mojo::Loader;
7 6
 use Mojo::Util 'md5_sum';
8 7
 use Scalar::Util 'blessed';
... ...
@@ -27,9 +26,10 @@ sub build_tx { shift->app->build_tx }
27 26
 sub load_app {
28 27
   my ($self, $path) = @_;
29 28
 
30
-  # Clean environment (reset FindBin)
29
+  # Clean environment (reset FindBin defensively)
31 30
   {
32 31
     local $0 = $path;
32
+    require FindBin;
33 33
     FindBin->again;
34 34
     local $ENV{MOJO_APP_LOADER} = 1;
35 35
     local $ENV{MOJO_EXE};
... ...
@@ -55,6 +55,8 @@ sub run { croak 'Method "run" not implemented by subclass' }
55 55
 
56 56
 1;
57 57
 
58
+=encoding utf8
59
+
58 60
 =head1 NAME
59 61
 
60 62
 Mojo::Server - HTTP server base class
... ...
@@ -121,8 +123,8 @@ the following new ones.
121 123
 
122 124
   my $server = Mojo::Server->new;
123 125
 
124
-Construct a new L<Mojo::Server> object and subscribe to C<request> event with
125
-default request handling.
126
+Construct a new L<Mojo::Server> object and subscribe to L</"request"> event
127
+with default request handling.
126 128
 
127 129
 =head2 build_app
128 130
 
+9 -4
mojo/lib/Mojo/Server/CGI.pm
... ...
@@ -10,11 +10,14 @@ sub run {
10 10
   my $req = $tx->req->parse(\%ENV);
11 11
   $tx->local_port($ENV{SERVER_PORT})->remote_address($ENV{REMOTE_ADDR});
12 12
 
13
-  # Request body
13
+  # Request body (may block if we try to read too much)
14 14
   binmode STDIN;
15
+  my $len = $req->headers->content_length;
15 16
   until ($req->is_finished) {
16
-    last unless my $read = STDIN->read(my $buffer, 131072, 0);
17
+    my $chunk = ($len && $len < 131072) ? $len : 131072;
18
+    last unless my $read = STDIN->read(my $buffer, $chunk, 0);
17 19
     $req->parse($buffer);
20
+    last if ($len -= $read) <= 0;
18 21
   }
19 22
 
20 23
   # Handle request
... ...
@@ -65,6 +68,8 @@ sub _write {
65 68
 
66 69
 1;
67 70
 
71
+=encoding utf8
72
+
68 73
 =head1 NAME
69 74
 
70 75
 Mojo::Server::CGI - CGI server
... ...
@@ -109,8 +114,8 @@ implements the following new ones.
109 114
 
110 115
 =head2 nph
111 116
 
112
-  my $nph = $cgi->nph;
113
-  $cgi    = $cgi->nph(1);
117
+  my $bool = $cgi->nph;
118
+  $cgi     = $cgi->nph($bool);
114 119
 
115 120
 Activate non-parsed header mode.
116 121
 
+61 -27
mojo/lib/Mojo/Server/Daemon.pm
... ...
@@ -9,6 +9,7 @@ use Scalar::Util 'weaken';
9 9
 
10 10
 use constant DEBUG => $ENV{MOJO_DAEMON_DEBUG} || 0;
11 11
 
12
+has acceptors => sub { [] };
12 13
 has [qw(backlog group silent user)];
13 14
 has inactivity_timeout => sub { defined $ENV{MOJO_INACTIVITY_TIMEOUT} ? $ENV{MOJO_INACTIVITY_TIMEOUT} : 15 };
14 15
 has ioloop => sub { Mojo::IOLoop->singleton };
... ...
@@ -20,7 +21,7 @@ sub DESTROY {
20 21
   my $self = shift;
21 22
   return unless my $loop = $self->ioloop;
22 23
   $self->_remove($_) for keys %{$self->{connections} || {}};
23
-  $loop->remove($_) for @{$self->{acceptors} || []};
24
+  $loop->remove($_) for @{$self->acceptors};
24 25
 }
25 26
 
26 27
 sub run {
... ...
@@ -54,9 +55,9 @@ sub start {
54 55
 
55 56
   # Resume accepting connections
56 57
   my $loop = $self->ioloop;
57
-  if (my $acceptors = $self->{acceptors}) {
58
-    push @$acceptors, $loop->acceptor(delete $self->{servers}{$_})
59
-      for keys %{$self->{servers}};
58
+  if (my $servers = $self->{servers}) {
59
+    push @{$self->acceptors}, $loop->acceptor(delete $servers->{$_})
60
+      for keys %$servers;
60 61
   }
61 62
 
62 63
   # Start listening
... ...
@@ -71,7 +72,7 @@ sub stop {
71 72
 
72 73
   # Suspend accepting connections but keep listen sockets open
73 74
   my $loop = $self->ioloop;
74
-  while (my $id = shift @{$self->{acceptors}}) {
75
+  while (my $id = shift @{$self->acceptors}) {
75 76
     my $server = $self->{servers}{$id} = $loop->acceptor($id);
76 77
     $loop->remove($id);
77 78
     $server->stop;
... ...
@@ -162,20 +163,19 @@ sub _listen {
162 163
   my $url     = Mojo::URL->new($listen);
163 164
   my $query   = $url->query;
164 165
   my $options = {
165
-    address  => $url->host,
166
-    backlog  => $self->backlog,
167
-    port     => $url->port,
168
-    tls_ca   => scalar $query->param('ca'),
169
-    tls_cert => scalar $query->param('cert'),
170
-    tls_key  => scalar $query->param('key')
166
+    address => $url->host,
167
+    backlog => $self->backlog,
168
+    port    => $url->port,
169
+    reuse   => scalar $query->param('reuse'),
171 170
   };
171
+  $options->{"tls_$_"} = scalar $query->param($_) for qw(ca cert ciphers key);
172 172
   my $verify = $query->param('verify');
173 173
   $options->{tls_verify} = hex $verify if defined $verify;
174 174
   delete $options->{address} if $options->{address} eq '*';
175
-  my $tls = $options->{tls} = $url->protocol eq 'https' ? 1 : undef;
175
+  my $tls = $options->{tls} = $url->protocol eq 'https';
176 176
 
177 177
   weaken $self;
178
-  my $id = $self->ioloop->server(
178
+  push @{$self->acceptors}, $self->ioloop->server(
179 179
     $options => sub {
180 180
       my ($loop, $stream, $id) = @_;
181 181
 
... ...
@@ -196,12 +196,12 @@ sub _listen {
196 196
           sub { $self->app->log->debug('Inactivity timeout.') if $c->{tx} });
197 197
     }
198 198
   );
199
-  push @{$self->{acceptors} ||= []}, $id;
200 199
 
201 200
   return if $self->silent;
202
-  $self->app->log->info(qq{Listening at "$listen".});
203
-  $listen =~ s!//\*!//127.0.0.1!i;
204
-  say "Server available at $listen.";
201
+  $self->app->log->info(qq{Listening at "$url".});
202
+  $query->params([]);
203
+  $url->host('127.0.0.1') if $url->host eq '*';
204
+  say "Server available at $url.";
205 205
 }
206 206
 
207 207
 sub _read {
... ...
@@ -260,6 +260,8 @@ sub _write {
260 260
 
261 261
 1;
262 262
 
263
+=encoding utf8
264
+
263 265
 =head1 NAME
264 266
 
265 267
 Mojo::Server::Daemon - Non-blocking I/O HTTP and WebSocket server
... ...
@@ -290,14 +292,15 @@ Mojo::Server::Daemon - Non-blocking I/O HTTP and WebSocket server
290 292
 =head1 DESCRIPTION
291 293
 
292 294
 L<Mojo::Server::Daemon> is a full featured, highly portable non-blocking I/O
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.
295
+HTTP and WebSocket server, with IPv6, TLS, Comet (long polling), keep-alive,
296
+connection pooling, timeout, cookie, multipart and multiple event loop
297
+support.
296 298
 
297
-Optional modules L<EV> (4.0+), L<IO::Socket::IP> (0.16+) and
298
-L<IO::Socket::SSL> (1.75+) are supported transparently through
299
-L<Mojo::IOLoop>, and used if installed. Individual features can also be
300
-disabled with the MOJO_NO_IPV6 and MOJO_NO_TLS environment variables.
299
+For better scalability (epoll, kqueue) and to provide IPv6 as well as TLS
300
+support, the optional modules L<EV> (4.0+), L<IO::Socket::IP> (0.16+) and
301
+L<IO::Socket::SSL> (1.75+) will be used automatically by L<Mojo::IOLoop> if
302
+they are installed. Individual features can also be disabled with the
303
+MOJO_NO_IPV6 and MOJO_NO_TLS environment variables.
301 304
 
302 305
 See L<Mojolicious::Guides::Cookbook> for more.
303 306
 
... ...
@@ -310,6 +313,13 @@ L<Mojo::Server::Daemon> inherits all events from L<Mojo::Server>.
310 313
 L<Mojo::Server::Daemon> inherits all attributes from L<Mojo::Server> and
311 314
 implements the following new ones.
312 315
 
316
+=head2 acceptors
317
+
318
+  my $acceptors = $daemon->acceptors;
319
+  $daemon       = $daemon->acceptors([]);
320
+
321
+Active acceptors.
322
+
313 323
 =head2 backlog
314 324
 
315 325
   my $backlog = $daemon->backlog;
... ...
@@ -350,6 +360,9 @@ L<Mojo::IOLoop> singleton.
350 360
 List of one or more locations to listen on, defaults to the value of the
351 361
 MOJO_LISTEN environment variable or C<http://*:3000>.
352 362
 
363
+  # Allow multiple servers to use the same port (SO_REUSEPORT)
364
+  $daemon->listen(['http://*:8080?reuse=1']);
365
+
353 366
   # Listen on IPv6 interface
354 367
   $daemon->listen(['http://[::1]:4000']);
355 368
 
... ...
@@ -365,22 +378,43 @@ MOJO_LISTEN environment variable or C<http://*:3000>.
365 378
 
366 379
 These parameters are currently available:
367 380
 
368
-=over 4
381
+=over 2
369 382
 
370 383
 =item ca
371 384
 
385
+  ca=/etc/tls/ca.crt
386
+
372 387
 Path to TLS certificate authority file.
373 388
 
374 389
 =item cert
375 390
 
391
+  cert=/etc/tls/server.crt
392
+
376 393
 Path to the TLS cert file, defaults to a built-in test certificate.
377 394
 
395
+=item ciphers
396
+
397
+  ciphers=AES128-GCM-SHA256:RC4:HIGH:!MD5:!aNULL:!EDH
398
+
399
+Cipher specification string.
400
+
378 401
 =item key
379 402
 
403
+  key=/etc/tls/server.key
404
+
380 405
 Path to the TLS key file, defaults to a built-in test key.
381 406
 
407
+=item reuse
408
+
409
+  reuse=1
410
+
411
+Allow multiple servers to use the same port with the C<SO_REUSEPORT> socket
412
+option.
413
+
382 414
 =item verify
383 415
 
416
+  verify=0x00
417
+
384 418
 TLS verification mode, defaults to C<0x03>.
385 419
 
386 420
 =back
... ...
@@ -401,8 +435,8 @@ Maximum number of keep-alive requests per connection, defaults to C<25>.
401 435
 
402 436
 =head2 silent
403 437
 
404
-  my $silent = $daemon->silent;
405
-  $daemon    = $daemon->silent(1);
438
+  my $bool = $daemon->silent;
439
+  $daemon  = $daemon->silent($bool);
406 440
 
407 441
 Disable console messages.
408 442
 
+35 -37
mojo/lib/Mojo/Server/Hypnotoad.pm
... ...
@@ -56,7 +56,7 @@ sub run {
56 56
     exit 0 if $pid;
57 57
     setsid or die "Can't start a new session: $!";
58 58
 
59
-    # Close file handles
59
+    # Close filehandles
60 60
     open STDIN,  '</dev/null';
61 61
     open STDOUT, '>/dev/null';
62 62
     open STDERR, '>&STDOUT';
... ...
@@ -134,7 +134,7 @@ sub _reap {
134 134
   # Clean up failed upgrade
135 135
   return unless ($self->{new} || '') eq $pid;
136 136
   $self->{prefork}->app->log->info('Zero downtime software upgrade failed.');
137
-  delete $self->{$_} for qw(new upgrade);
137
+  delete @$self{qw(new upgrade)};
138 138
 }
139 139
 
140 140
 sub _stop {
... ...
@@ -146,6 +146,8 @@ sub _stop {
146 146
 
147 147
 1;
148 148
 
149
+=encoding utf8
150
+
149 151
 =head1 NAME
150 152
 
151 153
 Mojo::Server::Hypnotoad - ALL GLORY TO THE HYPNOTOAD!
... ...
@@ -161,13 +163,15 @@ Mojo::Server::Hypnotoad - ALL GLORY TO THE HYPNOTOAD!
161 163
 
162 164
 L<Mojo::Server::Hypnotoad> is a full featured, UNIX optimized, preforking
163 165
 non-blocking I/O HTTP and WebSocket server, built around the very well tested
164
-and reliable L<Mojo::Server::Prefork>, with C<IPv6>, C<TLS>, C<Comet> (long
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.
169
-
170
-To start applications with it you can use the L<hypnotoad> script.
166
+and reliable L<Mojo::Server::Prefork>, with IPv6, TLS, Comet (long polling),
167
+keep-alive, connection pooling, timeout, cookie, multipart, multiple event
168
+loop and hot deployment support that just works. Note that the server uses
169
+signals for process management, so you should avoid modifying signal handlers
170
+in your applications.
171
+
172
+To start applications with it you can use the L<hypnotoad> script, for
173
+L<Mojolicious> and L<Mojolicious::Lite> applications it will default to
174
+C<production> mode.
171 175
 
172 176
   $ hypnotoad myapp.pl
173 177
   Server available at http://127.0.0.1:8080.
... ...
@@ -177,42 +181,39 @@ You can run the same command again for automatic hot deployment.
177 181
   $ hypnotoad myapp.pl
178 182
   Starting hot deployment for Hypnotoad server 31841.
179 183
 
180
-For L<Mojolicious> and L<Mojolicious::Lite> applications it will default to
181
-C<production> mode.
184
+This second invocation will load the application again, detect the process id
185
+file with it, and send a L</"USR2"> signal to the already running server.
182 186
 
183
-Optional modules L<EV> (4.0+), L<IO::Socket::IP> (0.16+) and
184
-L<IO::Socket::SSL> (1.75+) are supported transparently through
185
-L<Mojo::IOLoop>, and used if installed. Individual features can also be
186
-disabled with the MOJO_NO_IPV6 and MOJO_NO_TLS environment variables.
187
+For better scalability (epoll, kqueue) and to provide IPv6 as well as TLS
188
+support, the optional modules L<EV> (4.0+), L<IO::Socket::IP> (0.16+) and
189
+L<IO::Socket::SSL> (1.75+) will be used automatically by L<Mojo::IOLoop> if
190
+they are installed. Individual features can also be disabled with the
191
+MOJO_NO_IPV6 and MOJO_NO_TLS environment variables.
187 192
 
188 193
 See L<Mojolicious::Guides::Cookbook> for more.
189 194
 
190
-=head1 SIGNALS
195
+=head1 MANAGER SIGNALS
191 196
 
192
-L<Mojo::Server::Hypnotoad> can be controlled at runtime with the following
193
-signals.
197
+The L<Mojo::Server::Hypnotoad> manager process can be controlled at runtime
198
+with the following signals.
194 199
 
195
-=head2 Manager
196
-
197
-=over 2
198
-
199
-=item INT, TERM
200
+=head2 INT, TERM
200 201
 
201 202
 Shutdown server immediately.
202 203
 
203
-=item QUIT
204
+=head2 QUIT
204 205
 
205 206
 Shutdown server gracefully.
206 207
 
207
-=item TTIN
208
+=head2 TTIN
208 209
 
209 210
 Increase worker pool by one.
210 211
 
211
-=item TTOU
212
+=head2 TTOU
212 213
 
213 214
 Decrease worker pool by one.
214 215
 
215
-=item USR2
216
+=head2 USR2
216 217
 
217 218
 Attempt zero downtime software upgrade (hot deployment) without losing any
218 219
 incoming connections.
... ...
@@ -228,25 +229,22 @@ incoming connections.
228 229
      |- Worker [3]
229 230
      +- Worker [4]
230 231
 
231
-The new manager will automatically send a C<QUIT> signal to the old manager
232
+The new manager will automatically send a L</"QUIT"> signal to the old manager
232 233
 and take over serving requests after starting up successfully.
233 234
 
234
-=back
235
+=head1 WORKER SIGNALS
235 236
 
236
-=head2 Worker
237
+L<Mojo::Server::Hypnotoad> worker processes can be controlled at runtime with
238
+the following signals.
237 239
 
238
-=over 2
239
-
240
-=item INT, TERM
240
+=head2 INT, TERM
241 241
 
242 242
 Stop worker immediately.
243 243
 
244
-=item QUIT
244
+=head2 QUIT
245 245
 
246 246
 Stop worker gracefully.
247 247
 
248
-=back
249
-
250 248
 =head1 SETTINGS
251 249
 
252 250
 L<Mojo::Server::Hypnotoad> can be configured with the following settings, see
... ...
@@ -282,7 +280,7 @@ Listen backlog size, defaults to C<SOMAXCONN>.
282 280
 
283 281
 Maximum number of parallel client connections per worker process, defaults to
284 282
 C<1000>. Note that depending on how much your application may block, you might
285
-want to decrease this value and increase C<workers> instead for better
283
+want to decrease this value and increase L</"workers"> instead for better
286 284
 performance.
287 285
 
288 286
 =head2 graceful_timeout
+12 -9
mojo/lib/Mojo/Server/Morbo.pm
... ...
@@ -100,6 +100,8 @@ sub _spawn {
100 100
 
101 101
 1;
102 102
 
103
+=encoding utf8
104
+
103 105
 =head1 NAME
104 106
 
105 107
 Mojo::Server::Morbo - DOOOOOOOOOOOOOOOOOOM!
... ...
@@ -115,20 +117,21 @@ Mojo::Server::Morbo - DOOOOOOOOOOOOOOOOOOM!
115 117
 
116 118
 L<Mojo::Server::Morbo> is a full featured, self-restart capable non-blocking
117 119
 I/O HTTP and WebSocket server, built around the very well tested and reliable
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.
120
+L<Mojo::Server::Daemon>, with IPv6, TLS, Comet (long polling), keep-alive,
121
+connection pooling, timeout, cookie, multipart and multiple event loop
122
+support. Note that the server uses signals for process management, so you
123
+should avoid modifying signal handlers in your applications.
122 124
 
123 125
 To start applications with it you can use the L<morbo> script.
124 126
 
125 127
   $ morbo myapp.pl
126 128
   Server available at http://127.0.0.1:3000.
127 129
 
128
-Optional modules L<EV> (4.0+), L<IO::Socket::IP> (0.16+) and
129
-L<IO::Socket::SSL> (1.75+) are supported transparently through
130
-L<Mojo::IOLoop>, and used if installed. Individual features can also be
131
-disabled with the MOJO_NO_IPV6 and MOJO_NO_TLS environment variables.
130
+For better scalability (epoll, kqueue) and to provide IPv6 as well as TLS
131
+support, the optional modules L<EV> (4.0+), L<IO::Socket::IP> (0.16+) and
132
+L<IO::Socket::SSL> (1.75+) will be used automatically by L<Mojo::IOLoop> if
133
+they are installed. Individual features can also be disabled with the
134
+MOJO_NO_IPV6 and MOJO_NO_TLS environment variables.
132 135
 
133 136
 See L<Mojolicious::Guides::Cookbook> for more.
134 137
 
... ...
@@ -152,7 +155,7 @@ the following new ones.
152 155
 
153 156
 =head2 check_file
154 157
 
155
-  my $success = $morbo->check_file('/home/sri/lib/MyApp.pm');
158
+  my $bool = $morbo->check_file('/home/sri/lib/MyApp.pm');
156 159
 
157 160
 Check if file has been modified since last check.
158 161
 
+3 -1
mojo/lib/Mojo/Server/PSGI.pm
... ...
@@ -8,7 +8,7 @@ sub run {
8 8
   my $req = $tx->req->parse($env);
9 9
   $tx->local_port($env->{SERVER_PORT})->remote_address($env->{REMOTE_ADDR});
10 10
 
11
-  # Request body
11
+  # Request body (may block if we try to read too much)
12 12
   my $len = $env->{CONTENT_LENGTH};
13 13
   until ($req->is_finished) {
14 14
     my $chunk = ($len && $len < 131072) ? $len : 131072;
... ...
@@ -66,6 +66,8 @@ sub getline {
66 66
 
67 67
 1;
68 68
 
69
+=encoding utf8
70
+
69 71
 =head1 NAME
70 72
 
71 73
 Mojo::Server::PSGI - PSGI server
+37 -46
mojo/lib/Mojo/Server/Prefork.pm
... ...
@@ -64,7 +64,10 @@ sub run {
64 64
   # Clean manager environment
65 65
   local $SIG{INT} = local $SIG{TERM} = sub { $self->_term };
66 66
   local $SIG{CHLD} = sub {
67
-    while ((my $pid = waitpid -1, WNOHANG) > 0) { $self->_reap($pid) }
67
+    while ((my $pid = waitpid -1, WNOHANG) > 0) {
68
+      $self->app->log->debug("Worker $pid stopped.")
69
+        if delete $self->emit(reap => $pid)->{pool}{$pid};
70
+    }
68 71
   };
69 72
   local $SIG{QUIT} = sub { $self->_term(1) };
70 73
   local $SIG{TTIN} = sub { $self->workers($self->workers + 1) };
... ...
@@ -110,7 +113,8 @@ sub _manage {
110 113
   # Manage workers
111 114
   $self->emit('wait')->_heartbeat;
112 115
   my $log = $self->app->log;
113
-  while (my ($pid, $w) = each %{$self->{pool}}) {
116
+  for my $pid (keys %{$self->{pool}}) {
117
+    next unless my $w = $self->{pool}{$pid};
114 118
 
115 119
     # No heartbeat (graceful stop)
116 120
     my $interval = $self->heartbeat_interval;
... ...
@@ -151,14 +155,6 @@ sub _pid_file {
151 155
   print $handle $$;
152 156
 }
153 157
 
154
-sub _reap {
155
-  my ($self, $pid) = @_;
156
-
157
-  # Clean up dead worker
158
-  $self->app->log->debug("Worker $pid stopped.")
159
-    if delete $self->emit(reap => $pid)->{pool}{$pid};
160
-}
161
-
162 158
 sub _spawn {
163 159
   my $self = shift;
164 160
 
... ...
@@ -179,21 +175,21 @@ sub _spawn {
179 175
     sub {
180 176
 
181 177
       # Blocking ("ualarm" can't be imported on Windows)
182
-      my $l;
178
+      my $lock;
183 179
       if ($_[1]) {
184 180
         eval {
185 181
           local $SIG{ALRM} = sub { die "alarm\n" };
186 182
           my $old = Time::HiRes::ualarm $self->lock_timeout * 1000000;
187
-          $l = flock $handle, LOCK_EX;
183
+          $lock = flock $handle, LOCK_EX;
188 184
           Time::HiRes::ualarm $old;
189 185
         };
190
-        if ($@) { $l = $@ eq "alarm\n" ? 0 : die($@) }
186
+        if ($@) { $lock = $@ eq "alarm\n" ? 0 : die($@) }
191 187
       }
192 188
 
193 189
       # Non blocking
194
-      else { $l = flock $handle, LOCK_EX | LOCK_NB }
190
+      else { $lock = flock $handle, LOCK_EX | LOCK_NB }
195 191
 
196
-      return $l;
192
+      return $lock;
197 193
     }
198 194
   );
199 195
   $loop->unlock(sub { flock $handle, LOCK_UN });
... ...
@@ -210,7 +206,7 @@ sub _spawn {
210 206
   # Clean worker environment
211 207
   $SIG{$_} = 'DEFAULT' for qw(INT TERM CHLD TTIN TTOU);
212 208
   $SIG{QUIT} = sub { $loop->max_connections(0) };
213
-  delete $self->{$_} for qw(poll reader);
209
+  delete @$self{qw(poll reader)};
214 210
 
215 211
   $self->app->log->debug("Worker $$ started.");
216 212
   $loop->start;
... ...
@@ -225,6 +221,8 @@ sub _term {
225 221
 
226 222
 1;
227 223
 
224
+=encoding utf8
225
+
228 226
 =head1 NAME
229 227
 
230 228
 Mojo::Server::Prefork - Preforking non-blocking I/O HTTP and WebSocket server
... ...
@@ -256,60 +254,53 @@ Mojo::Server::Prefork - Preforking non-blocking I/O HTTP and WebSocket server
256 254
 
257 255
 L<Mojo::Server::Prefork> is a full featured, UNIX optimized, preforking
258 256
 non-blocking I/O HTTP and WebSocket server, built around the very well tested
259
-and reliable L<Mojo::Server::Daemon>, with C<IPv6>, C<TLS>, C<Comet> (long
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
263
-applications.
257
+and reliable L<Mojo::Server::Daemon>, with IPv6, TLS, Comet (long polling),
258
+keep-alive, connection pooling, timeout, cookie, multipart and multiple event
259
+loop support. Note that the server uses signals for process management, so you
260
+should avoid modifying signal handlers in your applications.
264 261
 
265
-Optional modules L<EV> (4.0+), L<IO::Socket::IP> (0.16+) and
266
-L<IO::Socket::SSL> (1.75+) are supported transparently through
267
-L<Mojo::IOLoop>, and used if installed. Individual features can also be
268
-disabled with the MOJO_NO_IPV6 and MOJO_NO_TLS environment variables.
262
+For better scalability (epoll, kqueue) and to provide IPv6 as well as TLS
263
+support, the optional modules L<EV> (4.0+), L<IO::Socket::IP> (0.16+) and
264
+L<IO::Socket::SSL> (1.75+) will be used automatically by L<Mojo::IOLoop> if
265
+they are installed. Individual features can also be disabled with the
266
+MOJO_NO_IPV6 and MOJO_NO_TLS environment variables.
269 267
 
270 268
 See L<Mojolicious::Guides::Cookbook> for more.
271 269
 
272
-=head1 SIGNALS
270
+=head1 MANAGER SIGNALS
273 271
 
274
-L<Mojo::Server::Prefork> can be controlled at runtime with the following
275
-signals.
272
+The L<Mojo::Server::Prefork> manager process can be controlled at runtime with
273
+the following signals.
276 274
 
277
-=head2 Manager
278
-
279
-=over 2
280
-
281
-=item INT, TERM
275
+=head2 INT, TERM
282 276
 
283 277
 Shutdown server immediately.
284 278
 
285
-=item QUIT
279
+=head2 QUIT
286 280
 
287 281
 Shutdown server gracefully.
288 282
 
289
-=item TTIN
283
+=head2 TTIN
290 284
 
291 285
 Increase worker pool by one.
292 286
 
293
-=item TTOU
287
+=head2 TTOU
294 288
 
295 289
 Decrease worker pool by one.
296 290
 
297
-=back
291
+=head1 WORKER SIGNALS
298 292
 
299
-=head2 Worker
293
+L<Mojo::Server::Prefork> worker processes can be controlled at runtime with
294
+the following signals.
300 295
 
301
-=over 2
302
-
303
-=item INT, TERM
296
+=head2 INT, TERM
304 297
 
305 298
 Stop worker immediately.
306 299
 
307
-=item QUIT
300
+=head2 QUIT
308 301
 
309 302
 Stop worker gracefully.
310 303
 
311
-=back
312
-
313 304
 =head1 EVENTS
314 305
 
315 306
 L<Mojo::Server::Prefork> inherits all events from L<Mojo::Server::Daemon> and
... ...
@@ -482,8 +473,8 @@ implements the following new ones.
482 473
 
483 474
   my $pid = $prefork->check_pid;
484 475
 
485
-Get process id for running server from C<pid_file> or delete it if server is
486
-not running.
476
+Get process id for running server from L</"pid_file"> or delete it if server
477
+is not running.
487 478
 
488 479
   say 'Server is not running' unless $prefork->check_pid;
489 480
 
+6 -4
mojo/lib/Mojo/Template.pm
... ...
@@ -317,6 +317,8 @@ sub _wrap {
317 317
 
318 318
 1;
319 319
 
320
+=encoding utf8
321
+
320 322
 =head1 NAME
321 323
 
322 324
 Mojo::Template - Perl-ish templates!
... ...
@@ -382,8 +384,8 @@ automatically enabled.
382 384
   %# Comment line, useful for debugging
383 385
   %% Replaced with "%", useful for generating templates
384 386
 
385
-Escaping behavior can be reversed with the C<auto_escape> attribute, this is
386
-the default in L<Mojolicious> C<.ep> templates for example.
387
+Escaping behavior can be reversed with the L</"auto_escape"> attribute, this
388
+is the default in L<Mojolicious> C<.ep> templates for example.
387 389
 
388 390
   <%= Perl expression, replaced with XML escaped result %>
389 391
   <%== Perl expression, replaced with result %>
... ...
@@ -452,8 +454,8 @@ L<Mojo::Template> implements the following attributes.
452 454
 
453 455
 =head2 auto_escape
454 456
 
455
-  my $escape = $mt->auto_escape;
456
-  $mt        = $mt->auto_escape(1);
457
+  my $bool = $mt->auto_escape;
458
+  $mt      = $mt->auto_escape($bool);
457 459
 
458 460
 Activate automatic escaping.
459 461
 
+25 -22
mojo/lib/Mojo/Transaction.pm
... ...
@@ -5,13 +5,25 @@ use Carp 'croak';
5 5
 use Mojo::Message::Request;
6 6
 use Mojo::Message::Response;
7 7
 
8
-has [qw(kept_alive local_address local_port previous remote_port)];
8
+has [qw(kept_alive local_address local_port remote_port)];
9 9
 has req => sub { Mojo::Message::Request->new };
10 10
 has res => sub { Mojo::Message::Response->new };
11 11
 
12 12
 sub client_close {
13
-  my $self = shift;
14
-  $self->res->finish;
13
+  my ($self, $close) = @_;
14
+
15
+  # Remove code from parser errors
16
+  my $res = $self->res->finish;
17
+  if (my $err = $res->error) { $res->error($err) }
18
+
19
+  # Premature connection close
20
+  elsif ($close && !$res->code) { $res->error('Premature connection close') }
21
+
22
+  # 400/500
23
+  elsif ($res->is_status_class(400) || $res->is_status_class(500)) {
24
+    $res->error($res->message, $res->code);
25
+  }
26
+
15 27
   return $self->server_close;
16 28
 }
17 29
 
... ...
@@ -73,6 +85,8 @@ sub _state {
73 85
 
74 86
 1;
75 87
 
88
+=encoding utf8
89
+
76 90
 =head1 NAME
77 91
 
78 92
 Mojo::Transaction - Transaction base class
... ...
@@ -148,16 +162,6 @@ Local interface address.
148 162
 
149 163
 Local interface port.
150 164
 
151
-=head2 previous
152
-
153
-  my $previous = $tx->previous;
154
-  $tx          = $tx->previous(Mojo::Transaction->new);
155
-
156
-Previous transaction that triggered this followup transaction.
157
-
158
-  # Path of previous request
159
-  say $tx->previous->req->url->path;
160
-
161 165
 =head2 remote_port
162 166
 
163 167
   my $port = $tx->remote_port;
... ...
@@ -187,8 +191,10 @@ implements the following new ones.
187 191
 =head2 client_close
188 192
 
189 193
   $tx->client_close;
194
+  $tx->client_close(1);
190 195
 
191
-Transaction closed client-side, used to implement user agents.
196
+Transaction closed client-side, no actual connection close is assumed by
197
+default, used to implement user agents.
192 198
 
193 199
 =head2 client_read
194 200
 
... ...
@@ -220,7 +226,7 @@ Error and code.
220 226
 
221 227
 =head2 is_finished
222 228
 
223
-  my $success = $tx->is_finished;
229
+  my $bool = $tx->is_finished;
224 230
 
225 231
 Check if transaction is finished.
226 232
 
... ...
@@ -232,7 +238,7 @@ False.
232 238
 
233 239
 =head2 is_writing
234 240
 
235
-  my $success = $tx->is_writing;
241
+  my $bool = $tx->is_writing;
236 242
 
237 243
 Check if transaction is writing.
238 244
 
... ...
@@ -273,9 +279,9 @@ in a subclass.
273 279
 
274 280
   my $res = $tx->success;
275 281
 
276
-Returns the L<Mojo::Message::Response> object (C<res>) if transaction was
277
-successful or C<undef> otherwise. Connection and parser errors have only a
278
-message in C<error>, 400 and 500 responses also a code.
282
+Returns the L<Mojo::Message::Response> object from L</"res"> if transaction
283
+was successful or C<undef> otherwise. Connection and parser errors have only a
284
+message in L</"error">, 400 and 500 responses also a code.
279 285
 
280 286
   # Sensible exception handling
281 287
   if (my $res = $tx->success) { say $res->body }
... ...
@@ -284,9 +290,6 @@ message in C<error>, 400 and 500 responses also a code.
284 290
     say $code ? "$code response: $err" : "Connection error: $err";
285 291
   }
286 292
 
287
-Error messages can be accessed with the C<error> method of the transaction
288
-object.
289
-
290 293
 =head1 SEE ALSO
291 294
 
292 295
 L<Mojolicious>, L<Mojolicious::Guides>, L<http://mojolicio.us>.
+36 -3
mojo/lib/Mojo/Transaction/HTTP.pm
... ...
@@ -3,6 +3,8 @@ use Mojo::Base 'Mojo::Transaction';
3 3
 
4 4
 use Mojo::Transaction::WebSocket;
5 5
 
6
+has 'previous';
7
+
6 8
 sub client_read {
7 9
   my ($self, $chunk) = @_;
8 10
 
... ...
@@ -40,6 +42,13 @@ sub keep_alive {
40 42
   return !($req->version eq '1.0' || $res->version eq '1.0');
41 43
 }
42 44
 
45
+sub redirects {
46
+  my $previous = shift;
47
+  my @redirects;
48
+  unshift @redirects, $previous while $previous = $previous->previous;
49
+  return \@redirects;
50
+}
51
+
43 52
 sub server_read {
44 53
   my ($self, $chunk) = @_;
45 54
 
... ...
@@ -162,6 +171,8 @@ sub _write {
162 171
 
163 172
 1;
164 173
 
174
+=encoding utf8
175
+
165 176
 =head1 NAME
166 177
 
167 178
 Mojo::Transaction::HTTP - HTTP transaction
... ...
@@ -245,7 +256,19 @@ object.
245 256
 
246 257
 =head1 ATTRIBUTES
247 258
 
248
-L<Mojo::Transaction::HTTP> inherits all attributes from L<Mojo::Transaction>.
259
+L<Mojo::Transaction::HTTP> inherits all attributes from L<Mojo::Transaction>
260
+and implements the following new ones.
261
+
262
+=head2 previous
263
+
264
+  my $previous = $tx->previous;
265
+  $tx          = $tx->previous(Mojo::Transaction->new);
266
+
267
+Previous transaction that triggered this followup transaction.
268
+
269
+  # Paths of previous requests
270
+  say $tx->previous->previous->req->url->path;
271
+  say $tx->previous->req->url->path;
249 272
 
250 273
 =head1 METHODS
251 274
 
... ...
@@ -266,16 +289,26 @@ Write data client-side, used to implement user agents.
266 289
 
267 290
 =head2 is_empty
268 291
 
269
-  my $success = $tx->is_empty;
292
+  my $bool = $tx->is_empty;
270 293
 
271 294
 Check transaction for C<HEAD> request and C<1xx>, C<204> or C<304> response.
272 295
 
273 296
 =head2 keep_alive
274 297
 
275
-  my $success = $tx->keep_alive;
298
+  my $bool = $tx->keep_alive;
276 299
 
277 300
 Check if connection can be kept alive.
278 301
 
302
+=head2 redirects
303
+
304
+  my $redirects = $tx->redirects;
305
+
306
+Return a list of all previous transactions that preceded this followup
307
+transaction.
308
+
309
+  # Paths of all previous requests
310
+  say $_->req->url->path for @{$tx->redirects};
311
+
279 312
 =head2 server_read
280 313
 
281 314
   $tx->server_read($bytes);
+14 -13
mojo/lib/Mojo/Transaction/WebSocket.pm
... ...
@@ -69,12 +69,12 @@ sub build_frame {
69 69
     warn "-- Extended 64bit payload ($len)\n$payload\n" if DEBUG;
70 70
     vec($prefix, 0, 8) = $masked ? (127 | 0b10000000) : 127;
71 71
     $frame .= $prefix;
72
-    $frame .= pack('NN', 0, $len & 0xFFFFFFFF);
72
+    $frame .= pack('NN', 0, $len & 0xffffffff);
73 73
   }
74 74
 
75 75
   # Mask payload
76 76
   if ($masked) {
77
-    my $mask = pack 'N', int(rand 9999999);
77
+    my $mask = pack 'N', int(rand 9 x 7);
78 78
     $payload = $mask . xor_encode($payload, $mask x 128);
79 79
   }
80 80
 
... ...
@@ -95,9 +95,9 @@ sub client_handshake {
95 95
   $headers->connection('Upgrade')     unless $headers->connection;
96 96
   $headers->sec_websocket_version(13) unless $headers->sec_websocket_version;
97 97
 
98
-  # Generate WebSocket challenge
99
-  $headers->sec_websocket_key(b64_encode(pack('N*', int(rand 9999999)), ''))
100
-    unless $headers->sec_websocket_key;
98
+  # Generate 16 byte WebSocket challenge
99
+  my $challenge = b64_encode sprintf('%16u', int(rand 9 x 16)), '';
100
+  $headers->sec_websocket_key($challenge) unless $headers->sec_websocket_key;
101 101
 }
102 102
 
103 103
 sub client_read  { shift->server_read(@_) }
... ...
@@ -211,8 +211,8 @@ sub send {
211 211
       : [1, 0, 0, 0, BINARY, $frame->{binary}];
212 212
   }
213 213
 
214
-  # Text or object (forcing stringification)
215
-  $frame = [1, 0, 0, 0, TEXT, encode('UTF-8', "$frame")]
214
+  # Text
215
+  $frame = [1, 0, 0, 0, TEXT, encode('UTF-8', $frame)]
216 216
     if ref $frame ne 'ARRAY';
217 217
 
218 218
   $self->once(drain => $cb) if $cb;
... ...
@@ -302,6 +302,8 @@ sub _message {
302 302
 
303 303
 1;
304 304
 
305
+=encoding utf8
306
+
305 307
 =head1 NAME
306 308
 
307 309
 Mojo::Transaction::WebSocket - WebSocket transaction
... ...
@@ -451,8 +453,8 @@ object.
451 453
 
452 454
 =head2 masked
453 455
 
454
-  my $masked = $ws->masked;
455
-  $ws        = $ws->masked(1);
456
+  my $bool = $ws->masked;
457
+  $ws      = $ws->masked($bool);
456 458
 
457 459
 Mask outgoing frames with XOR cipher and a random 32bit key.
458 460
 
... ...
@@ -474,7 +476,7 @@ L<Mojo::Transaction> and implements the following new ones.
474 476
   my $ws = Mojo::Transaction::WebSocket->new;
475 477
 
476 478
 Construct a new L<Mojo::Transaction::WebSocket> object and subscribe to
477
-C<frame> event with default message parser, which also handles C<PING> and
479
+L</"frame"> event with default message parser, which also handles C<PING> and
478 480
 C<CLOSE> frames automatically.
479 481
 
480 482
 =head2 build_frame
... ...
@@ -503,7 +505,7 @@ Build WebSocket frame.
503 505
 
504 506
 =head2 client_challenge
505 507
 
506
-  my $success = $ws->client_challenge;
508
+  my $bool = $ws->client_challenge;
507 509
 
508 510
 Check WebSocket handshake challenge client-side, used to implement user
509 511
 agents.
... ...
@@ -607,7 +609,7 @@ Handshake response, usually a L<Mojo::Message::Response> object.
607 609
 
608 610
   $ws = $ws->resume;
609 611
 
610
-Resume C<handshake> transaction.
612
+Resume L</"handshake"> transaction.
611 613
 
612 614
 =head2 send
613 615
 
... ...
@@ -615,7 +617,6 @@ Resume C<handshake> transaction.
615 617
   $ws = $ws->send({text   => $bytes});
616 618
   $ws = $ws->send({json   => {test => [1, 2, 3]}});
617 619
   $ws = $ws->send([$fin, $rsv1, $rsv2, $rsv3, $op, $bytes]);
618
-  $ws = $ws->send(Mojo::ByteStream->new($chars));
619 620
   $ws = $ws->send($chars);
620 621
   $ws = $ws->send($chars => sub {...});
621 622
 
+33 -12
mojo/lib/Mojo/URL.pm
... ...
@@ -1,9 +1,6 @@
1 1
 package Mojo::URL;
2 2
 use Mojo::Base -base;
3
-use overload
4
-  'bool'   => sub {1},
5
-  '""'     => sub { shift->to_string },
6
-  fallback => 1;
3
+use overload bool => sub {1}, '""' => sub { shift->to_string }, fallback => 1;
7 4
 
8 5
 use Mojo::Parameters;
9 6
 use Mojo::Path;
... ...
@@ -179,8 +176,7 @@ sub to_rel {
179 176
   my @base_parts = @{$base_path->parts};
180 177
   pop @base_parts unless $base_path->trailing_slash;
181 178
   while (@parts && @base_parts && $parts[0] eq $base_parts[0]) {
182
-    shift @parts;
183
-    shift @base_parts;
179
+    shift @$_ for \@parts, \@base_parts;
184 180
   }
185 181
   my $path = $rel->path(Mojo::Path->new)->path;
186 182
   $path->leading_slash(1) if $rel->authority;
... ...
@@ -243,7 +239,6 @@ Mojo::URL - Uniform Resource Locator
243 239
   $url->host('example.com');
244 240
   $url->port(3000);
245 241
   $url->path('/foo/bar');
246
-  $url->path('baz');
247 242
   $url->query->param(foo => 'bar');
248 243
   $url->fragment(23);
249 244
   say "$url";
... ...
@@ -309,7 +304,7 @@ following new ones.
309 304
   my $url = Mojo::URL->new;
310 305
   my $url = Mojo::URL->new('http://127.0.0.1:3000/foo?f=b&baz=2#foo');
311 306
 
312
-Construct a new L<Mojo::URL> object and C<parse> URL if necessary.
307
+Construct a new L<Mojo::URL> object and L</"parse"> URL if necessary.
313 308
 
314 309
 =head2 authority
315 310
 
... ...
@@ -336,7 +331,7 @@ Host part of this URL in punycode format.
336 331
 
337 332
 =head2 is_abs
338 333
 
339
-  my $success = $url->is_abs;
334
+  my $bool = $url->is_abs;
340 335
 
341 336
 Check if URL is absolute.
342 337
 
... ...
@@ -378,7 +373,7 @@ defaults to a L<Mojo::Path> object.
378 373
 
379 374
   my $proto = $url->protocol;
380 375
 
381
-Normalized version of C<scheme>.
376
+Normalized version of L</"scheme">.
382 377
 
383 378
   # "http"
384 379
   Mojo::URL->new('HtTp://example.com')->protocol;
... ...
@@ -417,14 +412,40 @@ appended, defaults to a L<Mojo::Parameters> object.
417 412
   my $abs = $url->to_abs;
418 413
   my $abs = $url->to_abs(Mojo::URL->new('http://example.com/foo'));
419 414
 
420
-Clone relative URL and turn it into an absolute one.
415
+Clone relative URL and turn it into an absolute one using L</"base"> or
416
+provided base URL.
417
+
418
+  # "http://example.com/foo/baz.xml?test=123"
419
+  Mojo::URL->new('baz.xml?test=123')
420
+    ->to_abs(Mojo::URL->new('http://example.com/foo/bar.html'));
421
+
422
+  # "http://example.com/baz.xml?test=123"
423
+  Mojo::URL->new('/baz.xml?test=123')
424
+    ->to_abs(Mojo::URL->new('http://example.com/foo/bar.html'));
425
+
426
+  # "http://example.com/foo/baz.xml?test=123"
427
+  Mojo::URL->new('//example.com/foo/baz.xml?test=123')
428
+    ->to_abs(Mojo::URL->new('http://example.com/foo/bar.html'));
421 429
 
422 430
 =head2 to_rel
423 431
 
424 432
   my $rel = $url->to_rel;
425 433
   my $rel = $url->to_rel(Mojo::URL->new('http://example.com/foo'));
426 434
 
427
-Clone absolute URL and turn it into a relative one.
435
+Clone absolute URL and turn it into a relative one using L</"base"> or
436
+provided base URL.
437
+
438
+  # "foo/bar.html?test=123"
439
+  Mojo::URL->new('http://example.com/foo/bar.html?test=123')
440
+    ->to_rel(Mojo::URL->new('http://example.com'));
441
+
442
+  # "bar.html?test=123"
443
+  Mojo::URL->new('http://example.com/foo/bar.html?test=123')
444
+    ->to_rel(Mojo::URL->new('http://example.com/foo/'));
445
+
446
+  # "//example.com/foo/bar.html?test=123"
447
+  Mojo::URL->new('http://example.com/foo/bar.html?test=123')
448
+    ->to_rel(Mojo::URL->new('http://'));
428 449
 
429 450
 =head2 to_string
430 451
 
+2
mojo/lib/Mojo/Upload.pm
... ...
@@ -19,6 +19,8 @@ sub slurp { shift->asset->slurp }
19 19
 
20 20
 1;
21 21
 
22
+=encoding utf8
23
+
22 24
 =head1 NAME
23 25
 
24 26
 Mojo::Upload - Upload
+201 -260
mojo/lib/Mojo/UserAgent.pm
... ...
@@ -4,12 +4,12 @@ use Mojo::Base 'Mojo::EventEmitter';
4 4
 # "Fry: Since when is the Internet about robbing people of their privacy?
5 5
 #  Bender: August 6, 1991."
6 6
 use Carp 'croak';
7
-use List::Util 'first';
8 7
 use Mojo::IOLoop;
9
-use Mojo::Server::Daemon;
10 8
 use Mojo::URL;
11
-use Mojo::Util 'monkey_patch';
9
+use Mojo::Util qw(deprecated monkey_patch);
12 10
 use Mojo::UserAgent::CookieJar;
11
+use Mojo::UserAgent::Proxy;
12
+use Mojo::UserAgent::Server;
13 13
 use Mojo::UserAgent::Transactor;
14 14
 use Scalar::Util 'weaken';
15 15
 
... ...
@@ -19,14 +19,15 @@ has ca              => sub { $ENV{MOJO_CA_FILE} };
19 19
 has cert            => sub { $ENV{MOJO_CERT_FILE} };
20 20
 has connect_timeout => sub { $ENV{MOJO_CONNECT_TIMEOUT} || 10 };
21 21
 has cookie_jar      => sub { Mojo::UserAgent::CookieJar->new };
22
-has [qw(http_proxy https_proxy local_address no_proxy)];
22
+has 'local_address';
23 23
 has inactivity_timeout => sub { defined $ENV{MOJO_INACTIVITY_TIMEOUT} ? $ENV{MOJO_INACTIVITY_TIMEOUT} : 20 };
24 24
 has ioloop             => sub { Mojo::IOLoop->new };
25 25
 has key                => sub { $ENV{MOJO_KEY_FILE} };
26 26
 has max_connections    => 5;
27 27
 has max_redirects => sub { $ENV{MOJO_MAX_REDIRECTS} || 0 };
28
-has name => 'Mojolicious (Perl)';
28
+has proxy => sub { Mojo::UserAgent::Proxy->new };
29 29
 has request_timeout => sub { defined $ENV{MOJO_REQUEST_TIMEOUT} ? $ENV{MOJO_REQUEST_TIMEOUT} : 0 };
30
+has server => sub { Mojo::UserAgent::Server->new(ioloop => shift->ioloop) };
30 31
 has transactor => sub { Mojo::UserAgent::Transactor->new };
31 32
 
32 33
 # Common HTTP methods
... ...
@@ -40,51 +41,89 @@ for my $name (qw(DELETE GET HEAD OPTIONS PATCH POST PUT)) {
40 41
 
41 42
 sub DESTROY { shift->_cleanup }
42 43
 
43
-our $singleton_app;
44
-sub app {
45
-  my ($self, $app) = @_;
46
-
47
-  # Singleton application
48
-  return $singleton_app = $app ? $app : $singleton_app unless ref $self;
49
-
50
-  # Default to singleton application
51
-  return $self->{app} || $singleton_app unless $app;
52
-  $self->{app} = $app;
44
+# DEPRECATED in Top Hat!
45
+sub new {
46
+  my $self = shift->SUPER::new;
47
+  while (my $name = shift) { $self->$name(shift) }
53 48
   return $self;
54 49
 }
55 50
 
51
+# DEPRECATED in Top Hat!
52
+sub app {
53
+  deprecated "Mojo::UserAgent::app is DEPRECATED in favor of"
54
+    . " Mojo::UserAgent::Server::app";
55
+  shift->_delegate('server', 'app', @_);
56
+}
57
+
58
+# DEPRECATED in Top Hat!
56 59
 sub app_url {
57
-  my $self = shift;
58
-  $self->_server(@_);
59
-  return Mojo::URL->new("$self->{proto}://localhost:$self->{port}/");
60
+  deprecated "Mojo::UserAgent::app_url is DEPRECATED in favor of"
61
+    . " Mojo::UserAgent::Server::url";
62
+  shift->_delegate('server', 'url', @_);
60 63
 }
61 64
 
62 65
 sub build_tx           { shift->transactor->tx(@_) }
63 66
 sub build_websocket_tx { shift->transactor->websocket(@_) }
64 67
 
68
+# DEPRECATED in Top Hat!
65 69
 sub detect_proxy {
66
-  my $self = shift;
67
-  $self->http_proxy($ENV{HTTP_PROXY}   || $ENV{http_proxy});
68
-  $self->https_proxy($ENV{HTTPS_PROXY} || $ENV{https_proxy});
69
-  return $self->no_proxy([split /,/, $ENV{NO_PROXY} || $ENV{no_proxy} || '']);
70
+  deprecated "Mojo::UserAgent::detect_proxy is DEPRECATED in favor of"
71
+    . " Mojo::UserAgent::Proxy::detect";
72
+  shift->tap(sub { $_->proxy->detect });
70 73
 }
71 74
 
75
+# DEPRECATED in Top Hat!
76
+sub http_proxy {
77
+  deprecated "Mojo::UserAgent::http_proxy is DEPRECATED in favor of"
78
+    . " Mojo::UserAgent::Proxy::http";
79
+  shift->_delegate('proxy', 'http', @_);
80
+}
81
+
82
+# DEPRECATED in Top Hat!
83
+sub https_proxy {
84
+  deprecated "Mojo::UserAgent::https_proxy is DEPRECATED in favor of"
85
+    . " Mojo::UserAgent::Proxy::https";
86
+  shift->_delegate('proxy', 'https', @_);
87
+}
88
+
89
+# DEPRECATED in Top Hat!
90
+sub name {
91
+  deprecated "Mojo::UserAgent::name is DEPRECATED in favor of"
92
+    . " Mojo::UserAgent::Transactor::name";
93
+  shift->_delegate('transactor', 'name', @_);
94
+}
95
+
96
+# DEPRECATED in Top Hat!
97
+sub no_proxy {
98
+  deprecated "Mojo::UserAgent::no_proxy is DEPRECATED in favor of"
99
+    . " Mojo::UserAgent::Proxy::not";
100
+  shift->_delegate('proxy', 'not', @_);
101
+}
102
+
103
+# DEPRECATED in Top Hat!
72 104
 sub need_proxy {
73
-  my ($self, $host) = @_;
74
-  return !first { $host =~ /\Q$_\E$/ } @{$self->no_proxy || []};
105
+  deprecated "Mojo::UserAgent::need_proxy is DEPRECATED in favor of"
106
+    . " Mojo::UserAgent::Proxy::is_needed";
107
+  shift->proxy->is_needed(@_);
75 108
 }
76 109
 
77 110
 sub start {
78 111
   my ($self, $tx, $cb) = @_;
79 112
 
113
+  # Fork safety
114
+  unless (($self->{pid} = defined $self->{pid} ? $self->{pid} : $$) eq $$) {
115
+    delete $self->_cleanup->{pid};
116
+    $self->server->restart;
117
+  }
118
+
80 119
   # Non-blocking
81 120
   if ($cb) {
82 121
     warn "-- Non-blocking request (@{[$tx->req->url->to_abs]})\n" if DEBUG;
83 122
     unless ($self->{nb}) {
84 123
       croak 'Blocking request in progress' if keys %{$self->{connections}};
85 124
       warn "-- Switching to non-blocking mode\n" if DEBUG;
86
-      $self->_cleanup;
87
-      $self->{nb}++;
125
+      $self->server->ioloop(Mojo::IOLoop->singleton);
126
+      $self->_cleanup->{nb}++;
88 127
     }
89 128
     return $self->_start($tx, $cb);
90 129
   }
... ...
@@ -94,8 +133,8 @@ sub start {
94 133
   if ($self->{nb}) {
95 134
     croak 'Non-blocking requests in progress' if keys %{$self->{connections}};
96 135
     warn "-- Switching to blocking mode\n" if DEBUG;
97
-    $self->_cleanup;
98
-    delete $self->{nb};
136
+    $self->server->ioloop($self->ioloop);
137
+    delete $self->_cleanup->{nb};
99 138
   }
100 139
   $self->_start($tx => sub { shift->ioloop->stop; $tx = shift });
101 140
   $self->ioloop->start;
... ...
@@ -109,50 +148,17 @@ sub websocket {
109 148
   $self->start($self->build_websocket_tx(@_), $cb);
110 149
 }
111 150
 
112
-sub _cache {
113
-  my ($self, $name, $id) = @_;
114
-
115
-  # Enqueue and enforce connection limit
116
-  my $old = $self->{cache} ||= [];
117
-  if ($id) {
118
-    my $max = $self->max_connections;
119
-    $self->_remove(shift(@$old)->[1]) while @$old > $max;
120
-    push @$old, [$name, $id] if $max;
121
-    return undef;
122
-  }
123
-
124
-  # Dequeue
125
-  my $found;
126
-  my $loop = $self->_loop;
127
-  my $new = $self->{cache} = [];
128
-  for my $cached (@$old) {
129
-
130
-    # Search for id/name and remove corrupted connections
131
-    if (!$found && ($cached->[1] eq $name || $cached->[0] eq $name)) {
132
-      my $stream = $loop->stream($cached->[1]);
133
-      if ($stream && !$stream->is_readable) { $found = $cached->[1] }
134
-      else                                  { $loop->remove($cached->[1]) }
135
-    }
136
-
137
-    # Requeue
138
-    else { push @$new, $cached }
139
-  }
140
-
141
-  return $found;
142
-}
143
-
144 151
 sub _cleanup {
145 152
   my $self = shift;
146 153
   return unless my $loop = $self->_loop;
147 154
 
148 155
   # Clean up active connections (by closing them)
149
-  $self->_handle($_ => 1) for keys %{$self->{connections} || {}};
156
+  $self->_handle($_, 1) for keys %{$self->{connections} || {}};
150 157
 
151 158
   # Clean up keep-alive connections
152
-  $loop->remove($_->[1]) for @{delete $self->{cache} || []};
159
+  $loop->remove($_->[1]) for @{delete $self->{queue} || []};
153 160
 
154
-  # Stop server
155
-  delete $self->{server};
161
+  return $self;
156 162
 }
157 163
 
158 164
 sub _connect {
... ...
@@ -166,7 +172,7 @@ sub _connect {
166 172
     local_address => $self->local_address,
167 173
     port          => $port,
168 174
     timeout       => $self->connect_timeout,
169
-    tls           => $proto eq 'https' ? 1 : 0,
175
+    tls           => $proto eq 'https',
170 176
     tls_ca        => $self->ca,
171 177
     tls_cert      => $self->cert,
172 178
     tls_key       => $self->key,
... ...
@@ -178,10 +184,11 @@ sub _connect {
178 184
       return $self->_error($id, $err) if $err;
179 185
 
180 186
       # Connection established
181
-      $stream->on(timeout => sub { $self->_error($id, 'Inactivity timeout') });
182
-      $stream->on(close => sub { $self->_handle($id => 1) });
183
-      $stream->on(error => sub { $self && $self->_error($id, pop, 1) });
184
-      $stream->on(read => sub { $self->_read($id => pop) });
187
+      $stream->on(
188
+        timeout => sub { $self->_error($id, 'Inactivity timeout', 1) });
189
+      $stream->on(close => sub { $self->_handle($id, 1) });
190
+      $stream->on(error => sub { $self && $self->_error($id, pop) });
191
+      $stream->on(read => sub { $self->_read($id, pop) });
185 192
       $cb->();
186 193
     }
187 194
   );
... ...
@@ -196,19 +203,19 @@ sub _connect_proxy {
196 203
     $new => sub {
197 204
       my ($self, $tx) = @_;
198 205
 
199
-      # CONNECT failed
200
-      unless ((defined $tx->res->code ? $tx->res->code : '') eq '200') {
206
+      # CONNECT failed (connection needs to be kept alive)
207
+      unless ($tx->keep_alive && $tx->res->is_status_class(200)) {
201 208
         $old->req->error('Proxy connection failed');
202
-        return $self->_finish($old, $cb);
209
+        return $self->$cb($old);
203 210
       }
204 211
 
205 212
       # Prevent proxy reassignment and start real transaction
206 213
       $old->req->proxy(0);
207
-      return $self->_start($old->connection($tx->connection), $cb)
214
+      my $id = $tx->connection;
215
+      return $self->_start($old->connection($id), $cb)
208 216
         unless $tx->req->url->protocol eq 'https';
209 217
 
210 218
       # TLS upgrade
211
-      return unless my $id = $tx->connection;
212 219
       my $loop   = $self->_loop;
213 220
       my $handle = $loop->stream($id)->steal_handle;
214 221
       my $c      = delete $self->{connections}{$id};
... ...
@@ -245,7 +252,7 @@ sub _connection {
245 252
   # Reuse connection
246 253
   my $id = $tx->connection;
247 254
   my ($proto, $host, $port) = $self->transactor->endpoint($tx);
248
-  $id ||= $self->_cache("$proto:$host:$port");
255
+  $id ||= $self->_dequeue("$proto:$host:$port", 1);
249 256
   if ($id && !ref $id) {
250 257
     warn "-- Reusing connection ($proto:$host:$port)\n" if DEBUG;
251 258
     $self->{connections}{$id} = {cb => $cb, tx => $tx};
... ...
@@ -268,32 +275,47 @@ sub _connection {
268 275
   return $id;
269 276
 }
270 277
 
271
-sub _error {
272
-  my ($self, $id, $err, $emit) = @_;
273
-  if (my $tx = $self->{connections}{$id}{tx}) { $tx->res->error($err) }
274
-  $self->emit(error => $err) if $emit;
275
-  $self->_handle($id => $err);
278
+# DEPRECATED in Top Hat!
279
+sub _delegate {
280
+  my ($self, $attr, $name) = (shift, shift, shift);
281
+  return $self->$attr->$name unless @_;
282
+  $self->$attr->$name(@_);
283
+  return $self;
276 284
 }
277 285
 
278
-sub _finish {
279
-  my ($self, $tx, $cb, $close) = @_;
286
+sub _dequeue {
287
+  my ($self, $name, $test) = @_;
280 288
 
281
-  # Remove code from parser errors
282
-  my $res = $tx->res;
283
-  if (my $err = $res->error) { $res->error($err) }
289
+  my $found;
290
+  my $loop = $self->_loop;
291
+  my $old  = $self->{queue} || [];
292
+  my $new  = $self->{queue} = [];
293
+  for my $queued (@$old) {
294
+    push @$new, $queued and next if $found || !grep { $_ eq $name } @$queued;
295
+
296
+    # Search for id/name and sort out corrupted connections if necessary
297
+    next unless my $stream = $loop->stream($queued->[1]);
298
+    $test && $stream->is_readable ? $stream->close : ($found = $queued->[1]);
299
+  }
284 300
 
285
-  else {
301
+  return $found;
302
+}
286 303
 
287
-    # Premature connection close
288
-    if ($close && !$res->code) { $res->error('Premature connection close') }
304
+sub _enqueue {
305
+  my ($self, $name, $id) = @_;
289 306
 
290
-    # 400/500
291
-    elsif ($res->is_status_class(400) || $res->is_status_class(500)) {
292
-      $res->error($res->message, $res->code);
293
-    }
294
-  }
307
+  # Enforce connection limit
308
+  my $queue = $self->{queue} ||= [];
309
+  my $max = $self->max_connections;
310
+  $self->_remove(shift(@$queue)->[1]) while @$queue > $max;
311
+  push @$queue, [$name, $id] if $max;
312
+}
295 313
 
296
-  $self->$cb($tx);
314
+sub _error {
315
+  my ($self, $id, $err, $timeout) = @_;
316
+  if (my $tx = $self->{connections}{$id}{tx}) { $tx->res->error($err) }
317
+  elsif (!$timeout) { return $self->emit(error => $err) }
318
+  $self->_handle($id, 1);
297 319
 }
298 320
 
299 321
 sub _handle {
... ...
@@ -316,7 +338,7 @@ sub _handle {
316 338
   elsif ($old && (my $new = $self->_upgrade($id))) {
317 339
     if (my $jar = $self->cookie_jar) { $jar->extract($old) }
318 340
     $old->client_close;
319
-    $self->_finish($new, $c->{cb});
341
+    $c->{cb}->($self, $new);
320 342
     $new->client_read($old->res->content->leftovers);
321 343
   }
322 344
 
... ...
@@ -325,11 +347,10 @@ sub _handle {
325 347
     $self->_remove($id, $close);
326 348
     return unless $old;
327 349
     if (my $jar = $self->cookie_jar) { $jar->extract($old) }
328
-    $old->client_close;
350
+    $old->client_close($close);
329 351
 
330 352
     # Handle redirects
331
-    $self->_finish($new || $old, $c->{cb}, $close)
332
-      unless $self->_redirect($c, $old);
353
+    $c->{cb}->($self, $new || $old) unless $self->_redirect($c, $old);
333 354
   }
334 355
 }
335 356
 
... ...
@@ -354,77 +375,34 @@ sub _remove {
354 375
 
355 376
   # Close connection
356 377
   my $tx = (delete($self->{connections}{$id}) || {})->{tx};
357
-  unless (!$close && $tx && $tx->keep_alive && !$tx->error) {
358
-    $self->_cache($id);
378
+  if ($close || !$tx || !$tx->keep_alive || $tx->error) {
379
+    $self->_dequeue($id);
359 380
     return $self->_loop->remove($id);
360 381
   }
361 382
 
362
-  # Keep connection alive
363
-  $self->_cache(join(':', $self->transactor->endpoint($tx)), $id)
364
-    unless uc $tx->req->method eq 'CONNECT' && (defined $tx->res->code ? $tx->res->code : '') eq '200';
383
+  # Keep connection alive (CONNECT requests get upgraded)
384
+  $self->_enqueue(join(':', $self->transactor->endpoint($tx)), $id)
385
+    unless uc $tx->req->method eq 'CONNECT';
365 386
 }
366 387
 
367 388
 sub _redirect {
368 389
   my ($self, $c, $old) = @_;
369
-
370
-  # Follow redirect unless the maximum has been reached already
371 390
   return undef unless my $new = $self->transactor->redirect($old);
372
-  my $redirects = delete $c->{redirects} || 0;
373
-  return undef unless $redirects < $self->max_redirects;
374
-  my $id = $self->_start($new, delete $c->{cb});
375
-
376
-  return $self->{connections}{$id}{redirects} = $redirects + 1;
377
-}
378
-
379
-sub _server {
380
-  my ($self, $proto) = @_;
381
-
382
-  # Reuse server
383
-  return $self->{server} if $self->{server} && !$proto;
384
-
385
-  # Start application server
386
-  my $loop   = $self->_loop;
387
-  my $server = $self->{server}
388
-    = Mojo::Server::Daemon->new(ioloop => $loop, silent => 1);
389
-  my $port = $self->{port} ||= $loop->generate_port;
390
-  die "Couldn't find a free TCP port for application.\n" unless $port;
391
-  $self->{proto} = $proto ||= 'http';
392
-  $server->listen(["$proto://127.0.0.1:$port"])->start;
393
-  warn "-- Application server started ($proto://127.0.0.1:$port)\n" if DEBUG;
394
-  return $server;
391
+  return undef unless @{$old->redirects} < $self->max_redirects;
392
+  return $self->_start($new, delete $c->{cb});
395 393
 }
396 394
 
397 395
 sub _start {
398 396
   my ($self, $tx, $cb) = @_;
399 397
 
400
-  # Embedded server (update application if necessary)
401
-  my $req = $tx->req;
402
-  my $url = $req->url;
403
-  if ($self->{port} || !$url->is_abs) {
404
-    if (my $app = $self->app) { $self->_server->app($app) }
405
-    my $base = $self->app_url;
406
-    $url->scheme($base->scheme)->authority($base->authority)
407
-      unless $url->is_abs;
398
+  # Application server
399
+  my $url = $tx->req->url;
400
+  unless ($url->is_abs) {
401
+    my $base = $self->server->url;
402
+    $url->scheme($base->scheme)->authority($base->authority);
408 403
   }
409 404
 
410
-  # Proxy
411
-  $self->detect_proxy if $ENV{MOJO_PROXY};
412
-  my $proto = $url->protocol;
413
-  if ($self->need_proxy($url->host)) {
414
-
415
-    # HTTP proxy
416
-    my $http = $self->http_proxy;
417
-    $req->proxy($http) if $http && !defined $req->proxy && $proto eq 'http';
418
-
419
-    # HTTPS proxy
420
-    my $https = $self->https_proxy;
421
-    $req->proxy($https) if $https && !defined $req->proxy && $proto eq 'https';
422
-  }
423
-
424
-  # We identify ourselves and accept gzip compression
425
-  my $headers = $req->headers;
426
-  $headers->user_agent($self->name) unless $headers->user_agent;
427
-  $headers->accept_encoding('gzip') if (! $headers->accept_encoding && $Compress::Raw::Zlib::VERSION);
405
+  $self->proxy->inject($tx);
428 406
   if (my $jar = $self->cookie_jar) { $jar->inject($tx) }
429 407
 
430 408
   # Connect and add request timeout if necessary
... ...
@@ -432,7 +410,7 @@ sub _start {
432 410
   if (my $timeout = $self->request_timeout) {
433 411
     weaken $self;
434 412
     $self->{connections}{$id}{timeout} = $self->_loop->timer(
435
-      $timeout => sub { $self->_error($id => 'Request timeout') });
413
+      $timeout => sub { $self->_error($id, 'Request timeout') });
436 414
   }
437 415
 
438 416
   return $id;
... ...
@@ -494,15 +472,14 @@ Mojo::UserAgent - Non-blocking I/O HTTP and WebSocket user agent
494 472
   }
495 473
 
496 474
   # Quick JSON API request with Basic authentication
497
-  say $ua->get('https://sri:s3cret@search.twitter.com/search.json?q=perl')
498
-    ->res->json('/results/0/text');
475
+  say $ua->get('https://sri:s3cret@example.com/search.json?q=perl')
476
+    ->res->json('/results/0/title');
499 477
 
500 478
   # Extract data from HTML and XML resources
501
-  say $ua->get('mojolicio.us')->res->dom->html->head->title->text;
479
+  say $ua->get('www.perl.org')->res->dom->html->head->title->text;
502 480
 
503 481
   # Scrape the latest headlines from a news site
504
-  say $ua->max_redirects(5)->get('www.reddit.com/r/perl/')
505
-    ->res->dom('p.title > a.title')->pluck('text')->shuffle;
482
+  say $ua->get('perlnews.org')->res->dom('h2 > a')->text->shuffle;
506 483
 
507 484
   # IPv6 PUT request with content
508 485
   my $tx
... ...
@@ -514,7 +491,7 @@ Mojo::UserAgent - Non-blocking I/O HTTP and WebSocket user agent
514 491
 
515 492
   # TLS certificate authentication and JSON POST
516 493
   my $tx = $ua->cert('tls.crt')->key('tls.key')
517
-    ->post('https://mojolicio.us' => json => {top => 'secret'});
494
+    ->post('https://example.com' => json => {top => 'secret'});
518 495
 
519 496
   # Blocking parallel requests (does not work inside a running event loop)
520 497
   my $delay = Mojo::IOLoop->delay;
... ...
@@ -557,14 +534,19 @@ Mojo::UserAgent - Non-blocking I/O HTTP and WebSocket user agent
557 534
 =head1 DESCRIPTION
558 535
 
559 536
 L<Mojo::UserAgent> is a full featured non-blocking I/O HTTP and WebSocket user
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>
562
-compression and multiple event loop support.
537
+agent, with IPv6, TLS, SNI, IDNA, Comet (long polling), keep-alive, connection
538
+pooling, timeout, cookie, multipart, proxy, gzip compression and multiple
539
+event loop support.
540
+
541
+All connections will be reset automatically if a new process has been forked,
542
+this allows multiple processes to share the same L<Mojo::UserAgent> object
543
+safely.
563 544
 
564
-Optional modules L<EV> (4.0+), L<IO::Socket::IP> (0.16+) and
565
-L<IO::Socket::SSL> (1.75+) are supported transparently through
566
-L<Mojo::IOLoop>, and used if installed. Individual features can also be
567
-disabled with the MOJO_NO_IPV6 and MOJO_NO_TLS environment variables.
545
+For better scalability (epoll, kqueue) and to provide IPv6 as well as TLS
546
+support, the optional modules L<EV> (4.0+), L<IO::Socket::IP> (0.16+) and
547
+L<IO::Socket::SSL> (1.75+) will be used automatically by L<Mojo::IOLoop> if
548
+they are installed. Individual features can also be disabled with the
549
+MOJO_NO_IPV6 and MOJO_NO_TLS environment variables.
568 550
 
569 551
 See L<Mojolicious::Guides::Cookbook> for more.
570 552
 
... ...
@@ -580,7 +562,8 @@ the following new ones.
580 562
     ...
581 563
   });
582 564
 
583
-Emitted if an error occurs that can't be associated with a transaction.
565
+Emitted if an error occurs that can't be associated with a transaction, fatal
566
+if unhandled.
584 567
 
585 568
   $ua->on(error => sub {
586 569
     my ($ua, $err) = @_;
... ...
@@ -646,20 +629,6 @@ L<Mojo::UserAgent::CookieJar> object.
646 629
   # Disable cookie jar
647 630
   $ua->cookie_jar(0);
648 631
 
649
-=head2 http_proxy
650
-
651
-  my $proxy = $ua->http_proxy;
652
-  $ua       = $ua->http_proxy('http://sri:secret@127.0.0.1:8080');
653
-
654
-Proxy server to use for HTTP and WebSocket requests.
655
-
656
-=head2 https_proxy
657
-
658
-  my $proxy = $ua->https_proxy;
659
-  $ua       = $ua->https_proxy('http://sri:secret@127.0.0.1:8080');
660
-
661
-Proxy server to use for HTTPS and WebSocket requests.
662
-
663 632
 =head2 inactivity_timeout
664 633
 
665 634
   my $timeout = $ua->inactivity_timeout;
... ...
@@ -699,7 +668,7 @@ Local address to bind to.
699 668
   $ua     = $ua->max_connections(5);
700 669
 
701 670
 Maximum number of keep-alive connections that the user agent will retain
702
-before it starts closing the oldest cached ones, defaults to C<5>.
671
+before it starts closing the oldest ones, defaults to C<5>.
703 672
 
704 673
 =head2 max_redirects
705 674
 
... ...
@@ -709,19 +678,15 @@ before it starts closing the oldest cached ones, defaults to C<5>.
709 678
 Maximum number of redirects the user agent will follow before it fails,
710 679
 defaults to the value of the MOJO_MAX_REDIRECTS environment variable or C<0>.
711 680
 
712
-=head2 name
713
-
714
-  my $name = $ua->name;
715
-  $ua      = $ua->name('Mojolicious');
716
-
717
-Value for C<User-Agent> request header, defaults to C<Mojolicious (Perl)>.
681
+=head2 proxy
718 682
 
719
-=head2 no_proxy
683
+  my $proxy = $ua->proxy;
684
+  $ua       = $ua->proxy(Mojo::UserAgent::Proxy->new);
720 685
 
721
-  my $no_proxy = $ua->no_proxy;
722
-  $ua          = $ua->no_proxy([qw(localhost intranet.mojolicio.us)]);
686
+Proxy manager, defaults to a L<Mojo::UserAgent::Proxy> object.
723 687
 
724
-Domains that don't require a proxy server to be used.
688
+  # Detect proxy servers from environment
689
+  $ua->proxy->detect;
725 690
 
726 691
 =head2 request_timeout
727 692
 
... ...
@@ -737,47 +702,37 @@ indefinitely. The timeout will reset for every followed redirect.
737 702
   # Total limit of 5 seconds, of which 3 seconds may be spent connecting
738 703
   $ua->max_redirects(0)->connect_timeout(3)->request_timeout(5);
739 704
 
740
-=head2 transactor
705
+=head2 server
741 706
 
742
-  my $t = $ua->transactor;
743
-  $ua   = $ua->transactor(Mojo::UserAgent::Transactor->new);
707
+  my $server = $ua->server;
708
+  $ua        = $ua->server(Mojo::UserAgent::Server->new);
744 709
 
745
-Transaction builder, defaults to a L<Mojo::UserAgent::Transactor> object.
746
-
747
-=head1 METHODS
748
-
749
-L<Mojo::UserAgent> inherits all methods from L<Mojo::EventEmitter> and
750
-implements the following new ones.
751
-
752
-=head2 app
753
-
754
-  my $app = Mojo::UserAgent->app;
755
-            Mojo::UserAgent->app(MyApp->new);
756
-  my $app = $ua->app;
757
-  $ua     = $ua->app(MyApp->new);
758
-
759
-Application relative URLs will be processed with, instance specific
760
-applications override the global default.
710
+Application server relative URLs will be processed with, defaults to a
711
+L<Mojo::UserAgent::Server> object.
761 712
 
762 713
   # Introspect
763
-  say $ua->app->secret;
714
+  say $ua->server->app->secret;
764 715
 
765 716
   # Change log level
766
-  $ua->app->log->level('fatal');
717
+  $ua->server->app->log->level('fatal');
718
+
719
+  # Port currently used for processing relative URLs
720
+  say $ua->server->url->port;
767 721
 
768
-  # Change application behavior
769
-  $ua->app->defaults(testing => 'oh yea!');
722
+=head2 transactor
770 723
 
771
-=head2 app_url
724
+  my $t = $ua->transactor;
725
+  $ua   = $ua->transactor(Mojo::UserAgent::Transactor->new);
772 726
 
773
-  my $url = $ua->app_url;
774
-  my $url = $ua->app_url('http');
775
-  my $url = $ua->app_url('https');
727
+Transaction builder, defaults to a L<Mojo::UserAgent::Transactor> object.
776 728
 
777
-Get absolute L<Mojo::URL> object for C<app> and switch protocol if necessary.
729
+  # Change name of user agent
730
+  $ua->transactor->name('MyUA 1.0');
778 731
 
779
-  # Port currently used for processing relative URLs
780
-  say $ua->app_url->port;
732
+=head1 METHODS
733
+
734
+L<Mojo::UserAgent> inherits all methods from L<Mojo::EventEmitter> and
735
+implements the following new ones.
781 736
 
782 737
 =head2 build_tx
783 738
 
... ...
@@ -814,7 +769,7 @@ L<Mojo::UserAgent::Transactor/"websocket">.
814 769
   my $tx = $ua->delete(
815 770
     'http://example.com' => {DNT => 1} => json => {a => 'b'});
816 771
 
817
-Perform blocking HTTP C<DELETE> request and return resulting
772
+Perform blocking DELETE request and return resulting
818 773
 L<Mojo::Transaction::HTTP> object, takes the same arguments as
819 774
 L<Mojo::UserAgent::Transactor/"tx"> (except for the method). You can also
820 775
 append a callback to perform requests non-blocking.
... ...
@@ -825,14 +780,6 @@ append a callback to perform requests non-blocking.
825 780
   });
826 781
   Mojo::IOLoop->start unless Mojo::IOLoop->is_running;
827 782
 
828
-=head2 detect_proxy
829
-
830
-  $ua = $ua->detect_proxy;
831
-
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.
835
-
836 783
 =head2 get
837 784
 
838 785
   my $tx = $ua->get('example.com');
... ...
@@ -840,10 +787,10 @@ enabled with the MOJO_PROXY environment variable.
840 787
   my $tx = $ua->get('http://example.com' => {DNT => 1} => form => {a => 'b'});
841 788
   my $tx = $ua->get('http://example.com' => {DNT => 1} => json => {a => 'b'});
842 789
 
843
-Perform blocking HTTP C<GET> request and return resulting
844
-L<Mojo::Transaction::HTTP> object, takes the same arguments as
845
-L<Mojo::UserAgent::Transactor/"tx"> (except for the method). You can also
846
-append a callback to perform requests non-blocking.
790
+Perform blocking GET request and return resulting L<Mojo::Transaction::HTTP>
791
+object, takes the same arguments as L<Mojo::UserAgent::Transactor/"tx">
792
+(except for the method). You can also append a callback to perform requests
793
+non-blocking.
847 794
 
848 795
   $ua->get('http://example.com' => sub {
849 796
     my ($ua, $tx) = @_;
... ...
@@ -860,10 +807,10 @@ append a callback to perform requests non-blocking.
860 807
   my $tx = $ua->head(
861 808
     'http://example.com' => {DNT => 1} => json => {a => 'b'});
862 809
 
863
-Perform blocking HTTP C<HEAD> request and return resulting
864
-L<Mojo::Transaction::HTTP> object, takes the same arguments as
865
-L<Mojo::UserAgent::Transactor/"tx"> (except for the method). You can also
866
-append a callback to perform requests non-blocking.
810
+Perform blocking HEAD request and return resulting L<Mojo::Transaction::HTTP>
811
+object, takes the same arguments as L<Mojo::UserAgent::Transactor/"tx">
812
+(except for the method). You can also append a callback to perform requests
813
+non-blocking.
867 814
 
868 815
   $ua->head('http://example.com' => sub {
869 816
     my ($ua, $tx) = @_;
... ...
@@ -871,12 +818,6 @@ append a callback to perform requests non-blocking.
871 818
   });
872 819
   Mojo::IOLoop->start unless Mojo::IOLoop->is_running;
873 820
 
874
-=head2 need_proxy
875
-
876
-  my $success = $ua->need_proxy('intranet.example.com');
877
-
878
-Check if request for domain would use a proxy server.
879
-
880 821
 =head2 options
881 822
 
882 823
   my $tx = $ua->options('example.com');
... ...
@@ -886,7 +827,7 @@ Check if request for domain would use a proxy server.
886 827
   my $tx = $ua->options(
887 828
     'http://example.com' => {DNT => 1} => json => {a => 'b'});
888 829
 
889
-Perform blocking HTTP C<OPTIONS> request and return resulting
830
+Perform blocking OPTIONS request and return resulting
890 831
 L<Mojo::Transaction::HTTP> object, takes the same arguments as
891 832
 L<Mojo::UserAgent::Transactor/"tx"> (except for the method). You can also
892 833
 append a callback to perform requests non-blocking.
... ...
@@ -906,10 +847,10 @@ append a callback to perform requests non-blocking.
906 847
   my $tx = $ua->patch(
907 848
     'http://example.com' => {DNT => 1} => json => {a => 'b'});
908 849
 
909
-Perform blocking HTTP C<PATCH> request and return resulting
910
-L<Mojo::Transaction::HTTP> object, takes the same arguments as
911
-L<Mojo::UserAgent::Transactor/"tx"> (except for the method). You can also
912
-append a callback to perform requests non-blocking.
850
+Perform blocking PATCH request and return resulting L<Mojo::Transaction::HTTP>
851
+object, takes the same arguments as L<Mojo::UserAgent::Transactor/"tx">
852
+(except for the method). You can also append a callback to perform requests
853
+non-blocking.
913 854
 
914 855
   $ua->patch('http://example.com' => sub {
915 856
     my ($ua, $tx) = @_;
... ...
@@ -926,10 +867,10 @@ append a callback to perform requests non-blocking.
926 867
   my $tx = $ua->post(
927 868
     'http://example.com' => {DNT => 1} => json => {a => 'b'});
928 869
 
929
-Perform blocking HTTP C<POST> request and return resulting
930
-L<Mojo::Transaction::HTTP> object, takes the same arguments as
931
-L<Mojo::UserAgent::Transactor/"tx"> (except for the method). You can also
932
-append a callback to perform requests non-blocking.
870
+Perform blocking POST request and return resulting L<Mojo::Transaction::HTTP>
871
+object, takes the same arguments as L<Mojo::UserAgent::Transactor/"tx">
872
+(except for the method). You can also append a callback to perform requests
873
+non-blocking.
933 874
 
934 875
   $ua->post('http://example.com' => sub {
935 876
     my ($ua, $tx) = @_;
... ...
@@ -944,10 +885,10 @@ append a callback to perform requests non-blocking.
944 885
   my $tx = $ua->put('http://example.com' => {DNT => 1} => form => {a => 'b'});
945 886
   my $tx = $ua->put('http://example.com' => {DNT => 1} => json => {a => 'b'});
946 887
 
947
-Perform blocking HTTP C<PUT> request and return resulting
948
-L<Mojo::Transaction::HTTP> object, takes the same arguments as
949
-L<Mojo::UserAgent::Transactor/"tx"> (except for the method). You can also
950
-append a callback to perform requests non-blocking.
888
+Perform blocking PUT request and return resulting L<Mojo::Transaction::HTTP>
889
+object, takes the same arguments as L<Mojo::UserAgent::Transactor/"tx">
890
+(except for the method). You can also append a callback to perform requests
891
+non-blocking.
951 892
 
952 893
   $ua->put('http://example.com' => sub {
953 894
     my ($ua, $tx) = @_;
+20 -11
mojo/lib/Mojo/UserAgent/CookieJar.pm
... ...
@@ -19,12 +19,13 @@ sub add {
19 19
     next if length(defined $cookie->value ? $cookie->value : '') > $size;
20 20
 
21 21
     # Replace cookie
22
-    my $domain = $cookie->domain;
22
+    my $origin = defined $cookie->origin ? $cookie->origin : '';
23
+    next unless my $domain = lc(defined $cookie->domain ? $cookie->domain : $origin);
23 24
     $domain =~ s/^\.//;
24
-    my $path = $cookie->path;
25
-    my $name = $cookie->name;
26
-    my $jar  = $self->{jar}{$domain} ||= [];
27
-    @$jar = (grep({$_->path ne $path || $_->name ne $name} @$jar), $cookie);
25
+    next unless my $path = $cookie->path;
26
+    next unless length(my $name = defined $cookie->name ? $cookie->name : '');
27
+    my $jar = $self->{jar}{$domain} ||= [];
28
+    @$jar = (grep({_compare($_, $path, $name, $origin)} @$jar), $cookie);
28 29
   }
29 30
 
30 31
   return $self;
... ...
@@ -44,11 +45,10 @@ sub extract {
44 45
 
45 46
     # Validate domain
46 47
     my $host = $url->ihost;
47
-    my $domain = lc(defined $cookie->domain ? $cookie->domain : $host);
48
+    my $domain = lc(defined $cookie->domain ? $cookie->domain : $cookie->origin($host)->origin);
48 49
     $domain =~ s/^\.//;
49 50
     next
50 51
       if $host ne $domain && ($host !~ /\Q.$domain\E$/ || $host =~ /\.\d+$/);
51
-    $cookie->domain($domain);
52 52
 
53 53
     # Validate path
54 54
     my $path = defined $cookie->path ? $cookie->path : $url->path->to_dir->to_abs_string;
... ...
@@ -61,7 +61,7 @@ sub extract {
61 61
 sub find {
62 62
   my ($self, $url) = @_;
63 63
 
64
-  return unless my $domain = $url->ihost;
64
+  return unless my $domain = my $host = $url->ihost;
65 65
   my $path = $url->path->to_abs_string;
66 66
   my @found;
67 67
   while ($domain =~ /[^.]+\.[^.]+|localhost$/) {
... ...
@@ -70,6 +70,7 @@ sub find {
70 70
     # Grab cookies
71 71
     my $new = $self->{jar}{$domain} = [];
72 72
     for my $cookie (@$old) {
73
+      next unless $cookie->domain || $host eq $cookie->origin;
73 74
 
74 75
       # Check if cookie has expired
75 76
       my $expires = $cookie->expires;
... ...
@@ -98,10 +99,18 @@ sub inject {
98 99
   $req->cookies($self->find($req->url));
99 100
 }
100 101
 
102
+sub _compare {
103
+  my ($cookie, $path, $name, $origin) = @_;
104
+  return 1 if $cookie->path ne $path || $cookie->name ne $name;
105
+  return (defined $cookie->origin ? $cookie->origin : '') ne $origin;
106
+}
107
+
101 108
 sub _path { $_[0] eq '/' || $_[0] eq $_[1] || $_[1] =~ m!^\Q$_[0]/! }
102 109
 
103 110
 1;
104 111
 
112
+=encoding utf8
113
+
105 114
 =head1 NAME
106 115
 
107 116
 Mojo::UserAgent::CookieJar - Cookie jar for HTTP user agents
... ...
@@ -169,19 +178,19 @@ Empty the jar.
169 178
 
170 179
 =head2 extract
171 180
 
172
-  $jar->extract($tx);
181
+  $jar->extract(Mojo::Transaction::HTTP->new);
173 182
 
174 183
 Extract response cookies from transaction.
175 184
 
176 185
 =head2 find
177 186
 
178
-  my @cookies = $jar->find($url);
187
+  my @cookies = $jar->find(Mojo::URL->new);
179 188
 
180 189
 Find L<Mojo::Cookie::Request> objects in the jar for L<Mojo::URL> object.
181 190
 
182 191
 =head2 inject
183 192
 
184
-  $jar->inject($tx);
193
+  $jar->inject(Mojo::Transaction::HTTP->new);
185 194
 
186 195
 Inject request cookies into transaction.
187 196
 
+109
mojo/lib/Mojo/UserAgent/Proxy.pm
... ...
@@ -0,0 +1,109 @@
1
+package Mojo::UserAgent::Proxy;
2
+use Mojo::Base -base;
3
+
4
+has [qw(http https not)];
5
+
6
+sub detect {
7
+  my $self = shift;
8
+  $self->http($ENV{HTTP_PROXY}   || $ENV{http_proxy});
9
+  $self->https($ENV{HTTPS_PROXY} || $ENV{https_proxy});
10
+  return $self->not([split /,/, $ENV{NO_PROXY} || $ENV{no_proxy} || '']);
11
+}
12
+
13
+sub inject {
14
+  my ($self, $tx) = @_;
15
+
16
+  $self->detect if $ENV{MOJO_PROXY};
17
+  my $req = $tx->req;
18
+  my $url = $req->url;
19
+  return if !$self->is_needed($url->host) || defined $req->proxy;
20
+
21
+  # HTTP proxy
22
+  my $proto = $url->protocol;
23
+  my $http  = $self->http;
24
+  $req->proxy($http) if $http && $proto eq 'http';
25
+
26
+  # HTTPS proxy
27
+  my $https = $self->https;
28
+  $req->proxy($https) if $https && $proto eq 'https';
29
+}
30
+
31
+sub is_needed {
32
+  !grep { $_[1] =~ /\Q$_\E$/ } @{$_[0]->not || []};
33
+}
34
+
35
+1;
36
+
37
+=encoding utf8
38
+
39
+=head1 NAME
40
+
41
+Mojo::UserAgent::Proxy - User agent proxy manager
42
+
43
+=head1 SYNOPSIS
44
+
45
+  use Mojo::UserAgent::Proxy;
46
+
47
+  my $proxy = Mojo::UserAgent::Proxy->new;
48
+  $proxy->detect;
49
+  say $proxy->http;
50
+
51
+=head1 DESCRIPTION
52
+
53
+L<Mojo::UserAgent::Proxy> manages proxy servers for L<Mojo::UserAgent>.
54
+
55
+=head1 ATTRIBUTES
56
+
57
+L<Mojo::UserAgent::Proxy> implements the following attributes.
58
+
59
+=head2 http
60
+
61
+  my $http = $ua->http;
62
+  $ua      = $ua->http('http://sri:secret@127.0.0.1:8080');
63
+
64
+Proxy server to use for HTTP and WebSocket requests.
65
+
66
+=head2 https
67
+
68
+  my $https = $ua->https;
69
+  $ua       = $ua->https('http://sri:secret@127.0.0.1:8080');
70
+
71
+Proxy server to use for HTTPS and WebSocket requests.
72
+
73
+=head2 not
74
+
75
+  my $not = $proxy->not;
76
+  $ua     = $proxy->not([qw(localhost intranet.mojolicio.us)]);
77
+
78
+Domains that don't require a proxy server to be used.
79
+
80
+=head1 METHODS
81
+
82
+L<Mojo::UserAgent::Proxy> inherits all methods from L<Mojo::Base> and
83
+implements the following new ones.
84
+
85
+=head2 detect
86
+
87
+  $proxy = $proxy->detect;
88
+
89
+Check environment variables HTTP_PROXY, http_proxy, HTTPS_PROXY, https_proxy,
90
+NO_PROXY and no_proxy for proxy information. Automatic proxy detection can be
91
+enabled with the MOJO_PROXY environment variable.
92
+
93
+=head2 inject
94
+
95
+  $proxy->inject(Mojo::Transaction::HTTP->new);
96
+
97
+Inject proxy server information into transaction.
98
+
99
+=head2 is_needed
100
+
101
+  my $bool = $proxy->is_needed('intranet.example.com');
102
+
103
+Check if request for domain would use a proxy server.
104
+
105
+=head1 SEE ALSO
106
+
107
+L<Mojolicious>, L<Mojolicious::Guides>, L<http://mojolicio.us>.
108
+
109
+=cut
+115
mojo/lib/Mojo/UserAgent/Server.pm
... ...
@@ -0,0 +1,115 @@
1
+package Mojo::UserAgent::Server;
2
+use Mojo::Base -base;
3
+
4
+use Mojo::IOLoop;
5
+use Mojo::Server::Daemon;
6
+
7
+has ioloop => sub { Mojo::IOLoop->singleton };
8
+
9
+sub app {
10
+  my ($self, $app) = @_;
11
+
12
+  # Singleton application
13
+  our $state_singleton;
14
+  return $state_singleton = $app ? $app : $state_singleton unless ref $self;
15
+
16
+  # Default to singleton application
17
+  return $self->{app} || $state_singleton unless $app;
18
+  $self->{app} = $app;
19
+  return $self;
20
+}
21
+
22
+sub restart { shift->_restart(1) }
23
+
24
+sub url {
25
+  my $self = shift;
26
+  $self->_restart(0, @_)
27
+    if !$self->{server} || $self->{server}->ioloop ne $self->ioloop || @_;
28
+  return Mojo::URL->new("$self->{proto}://localhost:$self->{port}/");
29
+}
30
+
31
+sub _restart {
32
+  my ($self, $full, $proto) = @_;
33
+
34
+  my $server = $self->{server} = Mojo::Server::Daemon->new(
35
+    app    => $self->app,
36
+    ioloop => $self->ioloop,
37
+    silent => 1
38
+  );
39
+  delete $self->{port} if $full;
40
+  die "Couldn't find a free TCP port for application.\n"
41
+    unless my $port = $self->{port} ||= Mojo::IOLoop->generate_port;
42
+  $self->{proto} = $proto ||= 'http';
43
+  $server->listen(["$proto://127.0.0.1:$port"])->start;
44
+}
45
+
46
+1;
47
+
48
+=encoding utf8
49
+
50
+=head1 NAME
51
+
52
+Mojo::UserAgent::Server - Application server
53
+
54
+=head1 SYNOPSIS
55
+
56
+  use Mojo::UserAgent::Server;
57
+
58
+  my $server = Mojo::UserAgent::Server->new;
59
+  say $server->url;
60
+
61
+=head1 DESCRIPTION
62
+
63
+L<Mojo::UserAgent::Server> is an embedded web server based on
64
+L<Mojo::Server::Daemon> that processes requests for L<Mojo::UserAgent>.
65
+
66
+=head1 ATTRIBUTES
67
+
68
+L<Mojo::UserAgent::Server> implements the following attributes.
69
+
70
+=head2 ioloop
71
+
72
+  my $loop = $server->ioloop;
73
+  $server  = $server->ioloop(Mojo::IOLoop->new);
74
+
75
+Event loop object to use for I/O operations, defaults to the global
76
+L<Mojo::IOLoop> singleton.
77
+
78
+=head1 METHODS
79
+
80
+L<Mojo::UserAgent::Server> inherits all methods from L<Mojo::Base> and
81
+implements the following new ones.
82
+
83
+=head2 app
84
+
85
+  my $app = Mojo::UserAgent::Server->app;
86
+            Mojo::UserAgent::Server->app(MyApp->new);
87
+  my $app = $server->app;
88
+  $server = $server->app(MyApp->new);
89
+
90
+Application this server handles, instance specific applications override the
91
+global default.
92
+
93
+  # Change application behavior
94
+  $server->defaults(testing => 'oh yea!');
95
+
96
+=head2 restart
97
+
98
+  $server->restart;
99
+
100
+Restart server with new port.
101
+
102
+=head2 url
103
+
104
+  my $url = $ua->url;
105
+  my $url = $ua->url('http');
106
+  my $url = $ua->url('https');
107
+
108
+Get absolute L<Mojo::URL> object for L</"app"> and switch protocol if
109
+necessary.
110
+
111
+=head1 SEE ALSO
112
+
113
+L<Mojolicious>, L<Mojolicious::Guides>, L<http://mojolicio.us>.
114
+
115
+=cut
+59 -37
mojo/lib/Mojo/UserAgent/Transactor.pm
... ...
@@ -13,12 +13,8 @@ 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
-}
16
+has generators => sub { {form => \&_form, json => \&_json} };
17
+has name => 'Mojolicious (Perl)';
22 18
 
23 19
 sub add_generator {
24 20
   my ($self, $name, $cb) = @_;
... ...
@@ -107,8 +103,11 @@ sub tx {
107 103
   $url = "http://$url" unless $url =~ m!^/|://!;
108 104
   ref $url ? $req->url($url) : $req->url->parse($url);
109 105
 
110
-  # Headers
111
-  $req->headers->from_hash(shift) if ref $_[0] eq 'HASH';
106
+  # Headers (we identify ourselves and accept gzip compression)
107
+  my $headers = $req->headers;
108
+  $headers->from_hash(shift) if ref $_[0] eq 'HASH';
109
+  $headers->user_agent($self->name) unless $headers->user_agent;
110
+  $headers->accept_encoding('gzip') unless $headers->accept_encoding;
112 111
 
113 112
   # Generator
114 113
   if (@_ > 1) {
... ...
@@ -253,6 +252,8 @@ sub _proxy {
253 252
 
254 253
 1;
255 254
 
255
+=encoding utf8
256
+
256 257
 =head1 NAME
257 258
 
258 259
 Mojo::UserAgent::Transactor - User agent transactor
... ...
@@ -268,7 +269,7 @@ Mojo::UserAgent::Transactor - User agent transactor
268 269
   # PATCH request with "Do Not Track" header and content
269 270
   say $t->tx(PATCH => 'example.com' => {DNT => 1} => 'Hi!')->req->to_string;
270 271
 
271
-  # POST request with form data
272
+  # POST request with form-data
272 273
   say $t->tx(POST => 'example.com' => form => {a => 'b'})->req->to_string;
273 274
 
274 275
   # PUT request with JSON data
... ...
@@ -288,19 +289,21 @@ L<Mojo::UserAgent::Transactor> implements the following attributes.
288 289
   my $generators = $t->generators;
289 290
   $t             = $t->generators({foo => sub {...}});
290 291
 
291
-Registered content generators.
292
+Registered content generators, by default only C<form> and C<json> are already
293
+defined.
292 294
 
293
-=head1 METHODS
295
+=head2 name
294 296
 
295
-L<Mojo::UserAgent::Transactor> inherits all methods from L<Mojo::Base> and
296
-implements the following new ones.
297
+  my $name = $t->name;
298
+  $t       = $t->name('Mojolicious');
297 299
 
298
-=head2 new
300
+Value for C<User-Agent> request header of generated transactions, defaults to
301
+C<Mojolicious (Perl)>.
299 302
 
300
-  my $t = Mojo::UserAgent::Transactor->new;
303
+=head1 METHODS
301 304
 
302
-Construct a new transactor and register C<form> and C<json> content
303
-generators.
305
+L<Mojo::UserAgent::Transactor> inherits all methods from L<Mojo::Base> and
306
+implements the following new ones.
304 307
 
305 308
 =head2 add_generator
306 309
 
... ...
@@ -351,51 +354,70 @@ C<307> or C<308> redirect response if possible.
351 354
 Versatile general purpose L<Mojo::Transaction::HTTP> transaction builder for
352 355
 requests, with support for content generators.
353 356
 
354
-  # Inspect generated request
357
+  # Generate and inspect custom GET request with DNT header and content
355 358
   say $t->tx(GET => 'example.com' => {DNT => 1} => 'Bye!')->req->to_string;
356 359
 
357
-  # Streaming response
360
+  # Use a custom socket for processing this transaction
358 361
   my $tx = $t->tx(GET => 'http://example.com');
359
-  $tx->res->content->unsubscribe('read')->on(read => sub { say $_[1] });
362
+  $tx->connection($sock);
360 363
 
361
-  # Custom socket
364
+  # Stream response content to STDOUT
362 365
   my $tx = $t->tx(GET => 'http://example.com');
363
-  $tx->connection($sock);
366
+  $tx->res->content->unsubscribe('read')->on(read => sub { say $_[1] });
364 367
 
365
-  # Generate query parameters
368
+  # PUT request with content streamed from file
369
+  my $tx = $t->tx(PUT => 'http://example.com');
370
+  $tx->req->content->asset(Mojo::Asset::File->new(path => '/foo.txt'));
371
+
372
+  # GET request with query parameters
366 373
   my $tx = $t->tx(GET => 'http://example.com' => form => {a => 'b'});
367 374
 
368
-  # Use form generator with custom charset
375
+  # POST request with "application/json" content
369 376
   my $tx = $t->tx(
370
-    PUT => 'http://example.com' => form => {a => 'b'} => charset => 'UTF-8');
377
+    POST => 'http://example.com' => json => {a => 'b', c => [1, 2, 3]});
371 378
 
372
-  # Multiple form values with the same name
373
-  my $tx = $t->tx(PUT => 'http://example.com' => form => {a => [qw(b c d)]});
379
+  # POST request with "application/x-www-form-urlencoded" content
380
+  my $tx = $t->tx(
381
+    POST => 'http://example.com' => form => {a => 'b', c => 'd'});
374 382
 
375
-  # Multipart upload streamed from file
383
+  # PUT request with UTF-8 encoded form values
376 384
   my $tx = $t->tx(
377
-    PUT => 'http://example.com' => form => {mytext => {file => '/foo.txt'}});
385
+    PUT => 'http://example.com' => form => {a => 'b'} => charset => 'UTF-8');
386
+
387
+  # POST request with form values sharing the same name
388
+  my $tx = $t->tx(POST => 'http://example.com' => form => {a => [qw(b c d)]});
378 389
 
379
-  # Multipart upload with in-memory content
390
+  # POST request with "multipart/form-data" content
380 391
   my $tx = $t->tx(
381 392
     POST => 'http://example.com' => form => {mytext => {content => 'lala'}});
382 393
 
383
-  # Upload multiple files with same name
394
+  # POST request with upload streamed from file
395
+  my $tx = $t->tx(
396
+    POST => 'http://example.com' => form => {mytext => {file => '/foo.txt'}});
397
+
398
+  # POST request with upload streamed from asset
399
+  my $asset = Mojo::Asset::Memory->new->add_chunk('lalala');
400
+  my $tx    = $t->tx(
401
+    POST => 'http://example.com' => form => {mytext => {file => $asset}});
402
+
403
+  # POST request with multiple files sharing the same name
384 404
   my $tx = $t->tx(POST => 'http://example.com' =>
385 405
     form => {mytext => [{content => 'first'}, {content => 'second'}]});
386 406
 
387
-  # Customized upload with filename and header
407
+  # POST request with form values and customized upload (filename and header)
388 408
   my $tx = $t->tx(POST => 'http://example.com' => form => {
389
-    myzip => {
390
-      file           => Mojo::Asset::Memory->new->add_chunk('lalala'),
391
-      filename       => 'foo.zip',
409
+    a      => 'b',
410
+    c      => 'd',
411
+    mytext => {
412
+      content        => 'lalala',
413
+      filename       => 'foo.txt',
392 414
       'Content-Type' => 'text/plain'
393 415
     }
394 416
   });
395 417
 
396 418
 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
419
+GET/HEAD requests and the "application/x-www-form-urlencoded" content type for
420
+everything else. Both get upgraded automatically to using the
399 421
 "multipart/form-data" content type when necessary or when the header has been
400 422
 set manually.
401 423
 
+108 -78
mojo/lib/Mojo/Util.pm
... ...
@@ -2,8 +2,9 @@ package Mojo::Util;
2 2
 use Mojo::Base 'Exporter';
3 3
 
4 4
 use Carp qw(carp croak);
5
+use Data::Dumper ();
5 6
 use Digest::MD5 qw(md5 md5_hex);
6
-BEGIN {eval {require Digest::SHA; import Digest::SHA qw(sha1 sha1_hex)}}
7
+BEGIN {eval {require Digest::SHA; import Digest::SHA qw(hmac_sha1 sha1 sha1_hex)}}
7 8
 use Encode 'find_encoding';
8 9
 use File::Basename 'dirname';
9 10
 use File::Spec::Functions 'catfile';
... ...
@@ -25,7 +26,7 @@ use constant {
25 26
   PC_INITIAL_N    => 128
26 27
 };
27 28
 
28
-# To update HTML5 entities run this command
29
+# To update HTML entities run this command
29 30
 # perl examples/entities.pl > lib/Mojo/entities.txt
30 31
 my %ENTITIES;
31 32
 for my $line (split "\x0a", slurp(catfile dirname(__FILE__), 'entities.txt')) {
... ...
@@ -38,10 +39,10 @@ my %CACHE;
38 39
 
39 40
 our @EXPORT_OK = (
40 41
   qw(b64_decode b64_encode camelize class_to_file class_to_path decamelize),
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)
42
+  qw(decode deprecated dumper encode get_line hmac_sha1_sum html_unescape),
43
+  qw(md5_bytes md5_sum monkey_patch punycode_decode punycode_encode quote),
44
+  qw(secure_compare sha1_bytes sha1_sum slurp split_header spurt squish),
45
+  qw(steady_time trim unquote url_escape url_unescape xml_escape xor_encode)
45 46
 );
46 47
 
47 48
 sub b64_decode { decode_base64($_[0]) }
... ...
@@ -51,7 +52,7 @@ sub camelize {
51 52
   my $str = shift;
52 53
   return $str if $str =~ /^[A-Z]/;
53 54
 
54
-  # Camel case words
55
+  # CamelCase words
55 56
   return join '::', map {
56 57
     join '', map { ucfirst lc } split /_/, $_
57 58
   } split /-/, $str;
... ...
@@ -74,7 +75,7 @@ sub decamelize {
74 75
   my @parts;
75 76
   for my $part (split /::/, $str) {
76 77
 
77
-    # Snake case words
78
+    # snake_case words
78 79
     my @words;
79 80
     push @words, lc $1 while $part =~ s/([A-Z]{1}[^A-Z]*)//;
80 81
     push @parts, join '_', @words;
... ...
@@ -95,6 +96,8 @@ sub deprecated {
95 96
   $ENV{MOJO_FATAL_DEPRECATIONS} ? croak(@_) : carp(@_);
96 97
 }
97 98
 
99
+sub dumper { Data::Dumper->new([@_])->Indent(1)->Sortkeys(1)->Terse(1)->Dump }
100
+
98 101
 sub encode { _encoding($_[0])->encode("$_[1]") }
99 102
 
100 103
 sub get_line {
... ...
@@ -109,21 +112,12 @@ sub get_line {
109 112
   return $line;
110 113
 }
111 114
 
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));
120
-}
115
+sub hmac_sha1_sum { unpack 'H*', hmac_sha1(@_) }
121 116
 
122 117
 sub html_unescape {
123 118
   my $str = shift;
124 119
   return $str if index($str, '&') == -1;
125
-  $str
126
-    =~ s/&(?:\#((?:\d{1,7}|x[[:xdigit:]]{1,6}));|(\w+;?))/_decode($1, $2)/ge;
120
+  $str =~ s/&(?:\#((?:\d{1,7}|x[0-9a-fA-F]{1,6}));|(\w+;?))/_decode($1, $2)/ge;
127 121
   return $str;
128 122
 }
129 123
 
... ...
@@ -142,36 +136,32 @@ sub punycode_decode {
142 136
   my $input = shift;
143 137
   use integer;
144 138
 
145
-  # Delimiter
146
-  my @output;
147
-  push @output, split //, $1 if $input =~ s/(.*)\x2d//s;
148
-
149 139
   my $n    = PC_INITIAL_N;
150 140
   my $i    = 0;
151 141
   my $bias = PC_INITIAL_BIAS;
142
+  my @output;
143
+
144
+  # Consume all code points before the last delimiter
145
+  push @output, split //, $1 if $input =~ s/(.*)\x2d//s;
146
+
152 147
   while (length $input) {
153 148
     my $oldi = $i;
154 149
     my $w    = 1;
155 150
 
156 151
     # Base to infinity in steps of base
157 152
     for (my $k = PC_BASE; 1; $k += PC_BASE) {
158
-
159
-      # Digit
160 153
       my $digit = ord substr $input, 0, 1, '';
161 154
       $digit = $digit < 0x40 ? $digit + (26 - 0x30) : ($digit & 0x1f) - 1;
162 155
       $i += $digit * $w;
163 156
       my $t = $k - $bias;
164 157
       $t = $t < PC_TMIN ? PC_TMIN : $t > PC_TMAX ? PC_TMAX : $t;
165 158
       last if $digit < $t;
166
-
167
-      $w *= (PC_BASE - $t);
159
+      $w *= PC_BASE - $t;
168 160
     }
169 161
 
170
-    # Bias
171 162
     $bias = _adapt($i - $oldi, @output + 1, $oldi == 0);
172 163
     $n += $i / (@output + 1);
173 164
     $i = $i % (@output + 1);
174
-
175 165
     splice @output, $i++, 0, chr $n;
176 166
   }
177 167
 
... ...
@@ -183,35 +173,28 @@ sub punycode_encode {
183 173
   my $output = shift;
184 174
   use integer;
185 175
 
186
-  # Split input
176
+  my $n     = PC_INITIAL_N;
177
+  my $delta = 0;
178
+  my $bias  = PC_INITIAL_BIAS;
179
+
180
+  # Extract basic code points
187 181
   my $len   = length $output;
188 182
   my @input = map {ord} split //, $output;
189 183
   my @chars = sort grep { $_ >= PC_INITIAL_N } @input;
190
-
191
-  # Handle non-basic characters
192 184
   $output =~ s/[^\x00-\x7f]+//gs;
193 185
   my $h = my $b = length $output;
194 186
   $output .= "\x2d" if $b > 0;
195 187
 
196
-  my $n     = PC_INITIAL_N;
197
-  my $delta = 0;
198
-  my $bias  = PC_INITIAL_BIAS;
199 188
   for my $m (@chars) {
200
-
201
-    # Basic character
202 189
     next if $m < $n;
203
-
204
-    # Walk all code points in order
205 190
     $delta += ($m - $n) * ($h + 1);
206 191
     $n = $m;
192
+
207 193
     for (my $i = 0; $i < $len; $i++) {
208 194
       my $c = $input[$i];
209 195
 
210
-      # Basic character
211
-      $delta++ if $c < $n;
212
-
213
-      # Non basic character
214
-      if ($c == $n) {
196
+      if ($c < $n) { $delta++ }
197
+      elsif ($c == $n) {
215 198
         my $q = $delta;
216 199
 
217 200
         # Base to infinity in steps of base
... ...
@@ -219,18 +202,12 @@ sub punycode_encode {
219 202
           my $t = $k - $bias;
220 203
           $t = $t < PC_TMIN ? PC_TMIN : $t > PC_TMAX ? PC_TMAX : $t;
221 204
           last if $q < $t;
222
-
223
-          # Code point for digit "t"
224 205
           my $o = $t + (($q - $t) % (PC_BASE - $t));
225 206
           $output .= chr $o + ($o < 26 ? 0x61 : 0x30 - 26);
226
-
227 207
           $q = ($q - $t) / (PC_BASE - $t);
228 208
         }
229 209
 
230
-        # Code point for digit "q"
231 210
         $output .= chr $q + ($q < 26 ? 0x61 : 0x30 - 26);
232
-
233
-        # Bias
234 211
         $bias = _adapt($delta, $h + 1, $h == $b);
235 212
         $delta = 0;
236 213
         $h++;
... ...
@@ -269,6 +246,26 @@ sub slurp {
269 246
   return $content;
270 247
 }
271 248
 
249
+sub split_header {
250
+  my $str = shift;
251
+
252
+  my (@tree, @token);
253
+  while ($str =~ s/^[,;\s]*([^=;, ]+)\s*//) {
254
+    push @token, $1, undef;
255
+    $token[-1] = unquote($1)
256
+      if $str =~ s/^=\s*("(?:\\\\|\\"|[^"])*"|[^;, ]*)\s*//;
257
+
258
+    # Separator
259
+    $str =~ s/^;\s*//;
260
+    next unless $str =~ s/^,\s*//;
261
+    push @tree, [@token];
262
+    @token = ();
263
+  }
264
+
265
+  # Take care of final token
266
+  return [@token ? (@tree, \@token) : @tree];
267
+}
268
+
272 269
 sub spurt {
273 270
   my ($content, $path) = @_;
274 271
   croak qq{Can't open file "$path": $!} unless open my $file, '>', $path;
... ...
@@ -313,7 +310,7 @@ sub url_escape {
313 310
 sub url_unescape {
314 311
   my $str = shift;
315 312
   return $str if index($str, '%') == -1;
316
-  $str =~ s/%([[:xdigit:]]{2})/chr(hex($1))/ge;
313
+  $str =~ s/%([0-9a-fA-F]{2})/chr(hex($1))/ge;
317 314
   return $str;
318 315
 }
319 316
 
... ...
@@ -342,8 +339,8 @@ sub xor_encode {
342 339
 
343 340
 sub _adapt {
344 341
   my ($delta, $numpoints, $firsttime) = @_;
345
-
346 342
   use integer;
343
+
347 344
   $delta = $firsttime ? $delta / PC_DAMP : $delta / 2;
348 345
   $delta += $delta / $numpoints;
349 346
   my $k = 0;
... ...
@@ -376,6 +373,8 @@ sub _encoding {
376 373
 
377 374
 1;
378 375
 
376
+=encoding utf8
377
+
379 378
 =head1 NAME
380 379
 
381 380
 Mojo::Util - Portable utility functions
... ...
@@ -399,22 +398,22 @@ L<Mojo::Util> implements the following functions.
399 398
 
400 399
 =head2 b64_decode
401 400
 
402
-  my $str = b64_decode $b64;
401
+  my $bytes = b64_decode $b64;
403 402
 
404
-Base64 decode string.
403
+Base64 decode bytes.
405 404
 
406 405
 =head2 b64_encode
407 406
 
408
-  my $b64 = b64_encode $str;
409
-  my $b64 = b64_encode $str, "\n";
407
+  my $b64 = b64_encode $bytes;
408
+  my $b64 = b64_encode $bytes, "\n";
410 409
 
411
-Base64 encode string, the line ending defaults to a newline.
410
+Base64 encode bytes, the line ending defaults to a newline.
412 411
 
413 412
 =head2 camelize
414 413
 
415 414
   my $camelcase = camelize $snakecase;
416 415
 
417
-Convert snake case string to camel case and replace C<-> with C<::>.
416
+Convert snake_case string to CamelCase and replace C<-> with C<::>.
418 417
 
419 418
   # "FooBar"
420 419
   camelize 'foo_bar';
... ...
@@ -431,10 +430,17 @@ Convert snake case string to camel case and replace C<-> with C<::>.
431 430
 
432 431
 Convert a class name to a file.
433 432
 
434
-  Foo::Bar -> foo_bar
435
-  FOO::Bar -> foobar
436
-  FooBar   -> foo_bar
437
-  FOOBar   -> foobar
433
+  # "foo_bar"
434
+  class_to_file 'Foo::Bar';
435
+
436
+  # "foobar"
437
+  class_to_file 'FOO::Bar';
438
+
439
+  # "foo_bar"
440
+  class_to_file 'FooBar';
441
+
442
+  # "foobar"
443
+  class_to_file 'FOOBar';
438 444
 
439 445
 =head2 class_to_path
440 446
 
... ...
@@ -442,14 +448,17 @@ Convert a class name to a file.
442 448
 
443 449
 Convert class name to path.
444 450
 
445
-  Foo::Bar -> Foo/Bar.pm
446
-  FooBar   -> FooBar.pm
451
+  # "Foo/Bar.pm"
452
+  class_to_path 'Foo::Bar';
453
+
454
+  # "FooBar.pm"
455
+  class_to_path 'FooBar';
447 456
 
448 457
 =head2 decamelize
449 458
 
450 459
   my $snakecase = decamelize $camelcase;
451 460
 
452
-Convert camel case string to snake case and replace C<::> with C<->.
461
+Convert CamelCase string to snake_case and replace C<::> with C<->.
453 462
 
454 463
   # "foo_bar"
455 464
   decamelize 'FooBar';
... ...
@@ -473,6 +482,12 @@ Decode bytes to characters and return C<undef> if decoding failed.
473 482
 Warn about deprecated feature from perspective of caller. You can also set the
474 483
 MOJO_FATAL_DEPRECATIONS environment variable to make them die instead.
475 484
 
485
+=head2 dumper
486
+
487
+  my $perl = dumper {some => 'data'};
488
+
489
+Dump a Perl data structure with L<Data::Dumper>.
490
+
476 491
 =head2 encode
477 492
 
478 493
   my $bytes = encode 'UTF-8', $chars;
... ...
@@ -488,9 +503,9 @@ with C<0x0d 0x0a> or C<0x0a>.
488 503
 
489 504
 =head2 hmac_sha1_sum
490 505
 
491
-  my $checksum = hmac_sha1_sum $str, 'passw0rd';
506
+  my $checksum = hmac_sha1_sum $bytes, 'passw0rd';
492 507
 
493
-Generate HMAC-SHA1 checksum for string.
508
+Generate HMAC-SHA1 checksum for bytes.
494 509
 
495 510
 =head2 html_unescape
496 511
 
... ...
@@ -500,15 +515,15 @@ Unescape all HTML entities in string.
500 515
 
501 516
 =head2 md5_bytes
502 517
 
503
-  my $checksum = md5_bytes $str;
518
+  my $checksum = md5_bytes $bytes;
504 519
 
505
-Generate binary MD5 checksum for string.
520
+Generate binary MD5 checksum for bytes.
506 521
 
507 522
 =head2 md5_sum
508 523
 
509
-  my $checksum = md5_sum $str;
524
+  my $checksum = md5_sum $bytes;
510 525
 
511
-Generate MD5 checksum for string.
526
+Generate MD5 checksum for bytes.
512 527
 
513 528
 =head2 monkey_patch
514 529
 
... ...
@@ -542,31 +557,46 @@ Quote string.
542 557
 
543 558
 =head2 secure_compare
544 559
 
545
-  my $success = secure_compare $str1, $str2;
560
+  my $bool = secure_compare $str1, $str2;
546 561
 
547 562
 Constant time comparison algorithm to prevent timing attacks.
548 563
 
549 564
 =head2 sha1_bytes
550 565
 
551
-  my $checksum = sha1_bytes $str;
566
+  my $checksum = sha1_bytes $bytes;
552 567
 
553
-Generate binary SHA1 checksum for string.
568
+Generate binary SHA1 checksum for bytes.
554 569
 
555 570
 =head2 sha1_sum
556 571
 
557
-  my $checksum = sha1_sum $str;
572
+  my $checksum = sha1_sum $bytes;
558 573
 
559
-Generate SHA1 checksum for string.
574
+Generate SHA1 checksum for bytes.
560 575
 
561 576
 =head2 slurp
562 577
 
563
-  my $content = slurp '/etc/passwd';
578
+  my $bytes = slurp '/etc/passwd';
564 579
 
565 580
 Read all data at once from file.
566 581
 
582
+=head2 split_header
583
+
584
+   my $tree = split_header 'foo="bar baz"; test=123, yada';
585
+
586
+Split HTTP header value.
587
+
588
+  # "one"
589
+  split_header('one; two="three four", five=six')->[0][0];
590
+
591
+  # "three four"
592
+  split_header('one; two="three four", five=six')->[0][3];
593
+
594
+  # "five"
595
+  split_header('one; two="three four", five=six')->[1][0];
596
+
567 597
 =head2 spurt
568 598
 
569
-  $content = spurt $content, '/etc/passwd';
599
+  $bytes = spurt $bytes, '/etc/passwd';
570 600
 
571 601
 Write all data at once to file.
572 602
 
+181 -150
mojo/lib/Mojolicious.pm
... ...
@@ -4,7 +4,7 @@ use Mojo::Base 'Mojo';
4 4
 # "Fry: Shut up and take my money!"
5 5
 use Carp 'croak';
6 6
 use Mojo::Exception;
7
-use Mojo::Util 'decamelize';
7
+use Mojo::Util qw(decamelize deprecated);
8 8
 use Mojolicious::Commands;
9 9
 use Mojolicious::Controller;
10 10
 use Mojolicious::Plugins;
... ...
@@ -13,6 +13,7 @@ use Mojolicious::Routes;
13 13
 use Mojolicious::Sessions;
14 14
 use Mojolicious::Static;
15 15
 use Mojolicious::Types;
16
+use Mojolicious::Validator;
16 17
 use Scalar::Util qw(blessed weaken);
17 18
 use Time::HiRes 'gettimeofday';
18 19
 
... ...
@@ -36,12 +37,13 @@ has secret   => sub {
36 37
   # Default to moniker
37 38
   return $self->moniker;
38 39
 };
39
-has sessions => sub { Mojolicious::Sessions->new };
40
-has static   => sub { Mojolicious::Static->new };
41
-has types    => sub { Mojolicious::Types->new };
40
+has sessions  => sub { Mojolicious::Sessions->new };
41
+has static    => sub { Mojolicious::Static->new };
42
+has types     => sub { Mojolicious::Types->new };
43
+has validator => sub { Mojolicious::Validator->new };
42 44
 
43 45
 our $CODENAME = 'Top Hat';
44
-our $VERSION  = '4.07';
46
+our $VERSION  = '4.57';
45 47
 
46 48
 sub AUTOLOAD {
47 49
   my $self = shift;
... ...
@@ -69,11 +71,11 @@ sub new {
69 71
   my $r = $self->routes->namespaces([ref $self]);
70 72
 
71 73
   # Hide controller attributes/methods and "handler"
72
-  $r->hide(qw(AUTOLOAD DESTROY app cookie finish flash handler on param));
73
-  $r->hide(qw(redirect_to render render_exception render_maybe));
74
+  $r->hide(qw(app continue cookie finish flash handler match on param));
75
+  $r->hide(qw(redirect_to render render_exception render_later render_maybe));
74 76
   $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');
77
+  $r->hide(qw(send session signed_cookie stash tx url_for validation write));
78
+  $r->hide(qw(write_chunk));
77 79
 
78 80
   # Check if we have a log directory
79 81
   my $mode = $self->mode;
... ...
@@ -89,9 +91,13 @@ sub new {
89 91
   # Reduced log output outside of development mode
90 92
   $self->log->level('info') unless $mode eq 'development';
91 93
 
92
-  # Run mode before startup
93
-  if (my $sub = $self->can("${mode}_mode")) { $self->$sub(@_) }
94
-  $self->startup(@_);
94
+  # DEPRECATED in Top Hat!
95
+  if (my $sub = $self->can("${mode}_mode")) {
96
+    deprecated qq{"sub ${mode}_mode {...}" in application class is DEPRECATED};
97
+    $self->$sub;
98
+  }
99
+
100
+  $self->startup;
95 101
 
96 102
   return $self;
97 103
 }
... ...
@@ -154,6 +160,7 @@ sub handler {
154 160
 
155 161
   # Dispatcher has to be last in the chain
156 162
   ++$self->{dispatch}
163
+    and $self->hook(around_action   => sub { $_[2]->($_[1]) })
157 164
     and $self->hook(around_dispatch => sub { $_[1]->app->dispatch($_[1]) })
158 165
     unless $self->{dispatch};
159 166
 
... ...
@@ -162,7 +169,7 @@ sub handler {
162 169
 
163 170
   # Delayed response
164 171
   $self->log->debug('Nothing has been rendered, expecting delayed response.')
165
-    unless $stash->{'mojo.rendered'} || $tx->is_writing;
172
+    unless $tx->is_writing;
166 173
 }
167 174
 
168 175
 sub helper {
... ...
@@ -193,6 +200,8 @@ sub _exception {
193 200
 
194 201
 1;
195 202
 
203
+=encoding utf8
204
+
196 205
 =head1 NAME
197 206
 
198 207
 Mojolicious - Real-time web framework
... ...
@@ -223,6 +232,131 @@ Mojolicious - Real-time web framework
223 232
 
224 233
 Take a look at our excellent documentation in L<Mojolicious::Guides>!
225 234
 
235
+=head1 HOOKS
236
+
237
+L<Mojolicious> will emit the following hooks in the listed order.
238
+
239
+=head2 after_build_tx
240
+
241
+Emitted right after the transaction is built and before the HTTP request gets
242
+parsed.
243
+
244
+  $app->hook(after_build_tx => sub {
245
+    my ($tx, $app) = @_;
246
+    ...
247
+  });
248
+
249
+This is a very powerful hook and should not be used lightly, it makes some
250
+rather advanced features such as upload progress bars possible. Note that this
251
+hook will not work for embedded applications. (Passed the transaction and
252
+application object)
253
+
254
+=head2 before_dispatch
255
+
256
+Emitted right before the static file server and router start their work.
257
+
258
+  $app->hook(before_dispatch => sub {
259
+    my $c = shift;
260
+    ...
261
+  });
262
+
263
+Very useful for rewriting incoming requests and other preprocessing tasks.
264
+(Passed the default controller object)
265
+
266
+=head2 after_static
267
+
268
+Emitted after a static file response has been generated by the static file
269
+server.
270
+
271
+  $app->hook(after_static => sub {
272
+    my $c = shift;
273
+    ...
274
+  });
275
+
276
+Mostly used for post-processing static file responses. (Passed the default
277
+controller object)
278
+
279
+=head2 before_routes
280
+
281
+Emitted after the static file server determined if a static file should be
282
+served and before the router starts its work.
283
+
284
+  $app->hook(before_routes => sub {
285
+    my $c = shift;
286
+    ...
287
+  });
288
+
289
+Mostly used for custom dispatchers and collecting metrics. (Passed the default
290
+controller object)
291
+
292
+=head2 around_action
293
+
294
+Emitted right before an action gets invoked and wraps around it, so you have
295
+to manually forward to the next hook if you want to continue the chain.
296
+Default action dispatching is the last hook in the chain, yours will run
297
+before it.
298
+
299
+  $app->hook(around_action => sub {
300
+    my ($next, $c, $action, $last) = @_;
301
+    ...
302
+    return $next->();
303
+  });
304
+
305
+This is a very powerful hook and should not be used lightly, it allows you for
306
+example to pass additional arguments to actions or handle return values
307
+differently. (Passed a callback leading to the next hook, the current
308
+controller object, the action callback and a flag indicating if this action is
309
+an endpoint)
310
+
311
+=head2 after_render
312
+
313
+Emitted after content has been generated by the renderer that is not partial.
314
+Note that this hook can trigger out of order due to its dynamic nature, and
315
+with embedded applications will only work for the application that is
316
+rendering.
317
+
318
+  $app->hook(after_render => sub {
319
+    my ($c, $output, $format) = @_;
320
+    ...
321
+  });
322
+
323
+Mostly used for post-processing dynamically generated content. (Passed the
324
+current controller object, a reference to the content and the format)
325
+
326
+=head2 after_dispatch
327
+
328
+Emitted in reverse order after a response has been rendered. Note that this
329
+hook can trigger out of order due to its dynamic nature, and with embedded
330
+applications will only work for the application that is rendering.
331
+
332
+  $app->hook(after_dispatch => sub {
333
+    my $c = shift;
334
+    ...
335
+  });
336
+
337
+Useful for rewriting outgoing responses and other post-processing tasks.
338
+(Passed the current controller object)
339
+
340
+=head2 around_dispatch
341
+
342
+Emitted right before the L</"before_dispatch"> hook and wraps around the whole
343
+dispatch process, so you have to manually forward to the next hook if you want
344
+to continue the chain. Default exception handling with
345
+L<Mojolicious::Controller/"render_exception"> is the first hook in the chain
346
+and a call to L</"dispatch"> the last, yours will be in between.
347
+
348
+  $app->hook(around_dispatch => sub {
349
+    my ($next, $c) = @_;
350
+    ...
351
+    $next->();
352
+    ...
353
+  });
354
+
355
+This is a very powerful hook and should not be used lightly, it allows you for
356
+example to customize application wide exception handling, consider it the
357
+sledgehammer in your toolbox. (Passed a callback leading to the next hook and
358
+the default controller object)
359
+
226 360
 =head1 ATTRIBUTES
227 361
 
228 362
 L<Mojolicious> inherits all attributes from L<Mojo> and implements the
... ...
@@ -253,24 +387,10 @@ L<Mojolicious::Controller>.
253 387
   $app     = $app->mode('production');
254 388
 
255 389
 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>.
260
-
261
-  sub development_mode {
262
-    my $self = shift;
263
-    ...
264
-  }
265
-
266
-  sub production_mode {
267
-    my $self = shift;
268
-    ...
269
-  }
270
-
271
-Right before calling C<startup> and mode specific methods, L<Mojolicious>
272
-will pick up the current mode, name the log file after it and raise the log
273
-level from C<debug> to C<info> if it has a value other than C<development>.
390
+MOJO_MODE and PLACK_ENV environment variables or C<development>. Right before
391
+calling L</"startup">, L<Mojolicious> will pick up the current mode, name the
392
+log file after it and raise the log level from C<debug> to C<info> if it has a
393
+value other than C<development>.
274 394
 
275 395
 =head2 moniker
276 396
 
... ...
@@ -287,7 +407,7 @@ L<Mojo::Util/"decamelize">.
287 407
   $app        = $app->plugins(Mojolicious::Plugins->new);
288 408
 
289 409
 The plugin manager, defaults to a L<Mojolicious::Plugins> object. See the
290
-C<plugin> method below if you want to load a plugin.
410
+L</"plugin"> method below if you want to load a plugin.
291 411
 
292 412
   # Add another namespace to load plugins from
293 413
   push @{$app->plugins->namespaces}, 'MyApp::Plugin';
... ...
@@ -330,8 +450,8 @@ startup method to define the url endpoints for your application.
330 450
   $app       = $app->secret('passw0rd');
331 451
 
332 452
 A secret passphrase used for signed cookies and the like, defaults to the
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
453
+L</"moniker"> of this application, which is not very secure, so you should
454
+change it!!! As long as you are using the insecure default there will be debug
335 455
 messages in the log file reminding you to change your passphrase.
336 456
 
337 457
 =head2 sessions
... ...
@@ -372,6 +492,13 @@ L<Mojolicious::Types> object.
372 492
   # Add custom MIME type
373 493
   $app->types->type(twt => 'text/tweet');
374 494
 
495
+=head2 validator
496
+
497
+  my $validator = $app->validator;
498
+  $app          = $app->validator(Mojolicious::Validator->new);
499
+
500
+Validate form data, defaults to a L<Mojolicious::Validator> object.
501
+
375 502
 =head1 METHODS
376 503
 
377 504
 L<Mojolicious> inherits all methods from L<Mojo> and implements the following
... ...
@@ -382,10 +509,10 @@ new ones.
382 509
   my $app = Mojolicious->new;
383 510
 
384 511
 Construct a new L<Mojolicious> application, calling C<${mode}_mode> and
385
-C<startup> in the process. Will automatically detect your home directory and
386
-set up logging based on your current operating mode. Also sets up the
512
+L</"startup"> in the process. Will automatically detect your home directory
513
+and set up logging based on your current operating mode. Also sets up the
387 514
 renderer, static file server, a default set of plugins and an
388
-C<around_dispatch> hook with the default exception handling.
515
+L</"around_dispatch"> hook with the default exception handling.
389 516
 
390 517
 =head2 build_tx
391 518
 
... ...
@@ -411,9 +538,9 @@ request.
411 538
 
412 539
   $app->dispatch(Mojolicious::Controller->new);
413 540
 
414
-The heart of every Mojolicious application, calls the C<static> and C<routes>
415
-dispatchers for every request and passes them a L<Mojolicious::Controller>
416
-object.
541
+The heart of every L<Mojolicious> application, calls the L</"static"> and
542
+L</"routes"> dispatchers for every request and passes them a
543
+L<Mojolicious::Controller> object.
417 544
 
418 545
 =head2 handler
419 546
 
... ...
@@ -445,7 +572,7 @@ and the application object, as well as a function in C<ep> templates.
445 572
   $app->hook(after_dispatch => sub {...});
446 573
 
447 574
 Extend L<Mojolicious> with hooks, which allow code to be shared with all
448
-requests indiscriminately.
575
+requests indiscriminately, for a full list of available hooks see L</"HOOKS">.
449 576
 
450 577
   # Dispatchers will not run if there's already a response code defined
451 578
   $app->hook(before_dispatch => sub {
... ...
@@ -454,114 +581,6 @@ requests indiscriminately.
454 581
       if $c->req->url->path->to_route =~ /do_not_dispatch/;
455 582
   });
456 583
 
457
-These hooks are currently available and are emitted in the listed order:
458
-
459
-=over 2
460
-
461
-=item after_build_tx
462
-
463
-Emitted right after the transaction is built and before the HTTP request gets
464
-parsed.
465
-
466
-  $app->hook(after_build_tx => sub {
467
-    my ($tx, $app) = @_;
468
-    ...
469
-  });
470
-
471
-This is a very powerful hook and should not be used lightly, it makes some
472
-rather advanced features such as upload progress bars possible. Note that this
473
-hook will not work for embedded applications. (Passed the transaction and
474
-application object)
475
-
476
-=item before_dispatch
477
-
478
-Emitted right before the static file server and router start their work.
479
-
480
-  $app->hook(before_dispatch => sub {
481
-    my $c = shift;
482
-    ...
483
-  });
484
-
485
-Very useful for rewriting incoming requests and other preprocessing tasks.
486
-(Passed the default controller object)
487
-
488
-=item after_static
489
-
490
-Emitted after a static file response has been generated by the static file
491
-server.
492
-
493
-  $app->hook(after_static => sub {
494
-    my $c = shift;
495
-    ...
496
-  });
497
-
498
-Mostly used for post-processing static file responses. (Passed the default
499
-controller object)
500
-
501
-=item before_routes
502
-
503
-Emitted after the static file server determined if a static file should be
504
-served and before the router starts its work.
505
-
506
-  $app->hook(before_routes => sub {
507
-    my $c = shift;
508
-    ...
509
-  });
510
-
511
-Mostly used for custom dispatchers and collecting metrics. (Passed the default
512
-controller object)
513
-
514
-=item after_render
515
-
516
-Emitted after content has been generated by the renderer that is not partial.
517
-Note that this hook can trigger out of order due to its dynamic nature, and
518
-with embedded applications will only work for the application that is
519
-rendering.
520
-
521
-  $app->hook(after_render => sub {
522
-    my ($c, $output, $format) = @_;
523
-    ...
524
-  });
525
-
526
-Mostly used for post-processing dynamically generated content. (Passed the
527
-current controller object, a reference to the content and the format)
528
-
529
-=item after_dispatch
530
-
531
-Emitted in reverse order after a response has been rendered. Note that this
532
-hook can trigger out of order due to its dynamic nature, and with embedded
533
-applications will only work for the application that is rendering.
534
-
535
-  $app->hook(after_dispatch => sub {
536
-    my $c = shift;
537
-    ...
538
-  });
539
-
540
-Useful for rewriting outgoing responses and other post-processing tasks.
541
-(Passed the current controller object)
542
-
543
-=item around_dispatch
544
-
545
-Emitted right before the C<before_dispatch> hook and wraps around the whole
546
-dispatch process, so you have to manually forward to the next hook if you want
547
-to continue the chain. Default exception handling with
548
-L<Mojolicious::Controller/"render_exception"> is the first hook in the chain
549
-and a call to C<dispatch> the last, yours will be in between.
550
-
551
-  $app->hook(around_dispatch => sub {
552
-    my ($next, $c) = @_;
553
-    ...
554
-    $next->();
555
-    ...
556
-  });
557
-
558
-This is a very powerful hook and should not be used lightly, it allows you to
559
-customize application wide exception handling for example, consider it the
560
-sledgehammer in your toolbox. (Passed a callback leading to the next hook and
561
-the default controller object)
562
-
563
-=back
564
-
565 584
 =head2 plugin
566 585
 
567 586
   $app->plugin('some_thing');
... ...
@@ -674,7 +693,7 @@ Sebastian Riedel, C<sri@cpan.org>
674 693
 
675 694
 Current members of the core team in alphabetical order:
676 695
 
677
-=over 4
696
+=over 2
678 697
 
679 698
 Abhijit Menon-Sen, C<ams@cpan.org>
680 699
 
... ...
@@ -698,6 +717,8 @@ Adriano Ferreira
698 717
 
699 718
 Al Newkirk
700 719
 
720
+Alex Efros
721
+
701 722
 Alex Salimon
702 723
 
703 724
 Alexey Likhatskiy
... ...
@@ -734,6 +755,8 @@ Breno G. de Oliveira
734 755
 
735 756
 Brian Duggan
736 757
 
758
+Brian Medley
759
+
737 760
 Burak Gursoy
738 761
 
739 762
 Ch Lamprecht
... ...
@@ -780,10 +803,14 @@ Henry Tang
780 803
 
781 804
 Hideki Yamamura
782 805
 
806
+Ian Goodacre
807
+
783 808
 Ilya Chesnokov
784 809
 
785 810
 James Duncan
786 811
 
812
+Jan Henning Thorsen
813
+
787 814
 Jan Jona Javorsek
788 815
 
789 816
 Jan Schmidt
... ...
@@ -798,6 +825,8 @@ John Kingsley
798 825
 
799 826
 Jonathan Yu
800 827
 
828
+Josh Leder
829
+
801 830
 Kazuhiro Shibuya
802 831
 
803 832
 Kevin Old
... ...
@@ -846,6 +875,8 @@ Paul Evans
846 875
 
847 876
 Paul Tomlin
848 877
 
878
+Pavel Shaydo
879
+
849 880
 Pedro Melo
850 881
 
851 882
 Peter Edwards
+6 -4
mojo/lib/Mojolicious/Command.pm
... ...
@@ -88,13 +88,15 @@ sub write_rel_file {
88 88
 
89 89
 1;
90 90
 
91
+=encoding utf8
92
+
91 93
 =head1 NAME
92 94
 
93 95
 Mojolicious::Command - Command base class
94 96
 
95 97
 =head1 SYNOPSIS
96 98
 
97
-  # Lower case command name
99
+  # Lowercase command name
98 100
   package Mojolicious::Command::mycommand;
99 101
   use Mojo::Base 'Mojolicious::Command';
100 102
 
... ...
@@ -102,7 +104,7 @@ Mojolicious::Command - Command base class
102 104
   has description => "My first Mojo command.\n";
103 105
 
104 106
   # Short usage message
105
-  has usage => <<"EOF";
107
+  has usage => <<EOF;
106 108
   usage: $0 mycommand [OPTIONS]
107 109
 
108 110
   These options are available:
... ...
@@ -145,8 +147,8 @@ Short description of command, used for the command list.
145 147
 
146 148
 =head2 quiet
147 149
 
148
-  my $quiet = $command->quiet;
149
-  $command  = $command->quiet(1);
150
+  my $bool = $command->quiet;
151
+  $command = $command->quiet($bool);
150 152
 
151 153
 Limited command output.
152 154
 
+3 -1
mojo/lib/Mojolicious/Command/cgi.pm
... ...
@@ -5,7 +5,7 @@ use Getopt::Long qw(GetOptionsFromArray :config no_auto_abbrev no_ignore_case);
5 5
 use Mojo::Server::CGI;
6 6
 
7 7
 has description => "Start application with CGI.\n";
8
-has usage       => <<"EOF";
8
+has usage       => <<EOF;
9 9
 usage: $0 cgi [OPTIONS]
10 10
 
11 11
 These options are available:
... ...
@@ -21,6 +21,8 @@ sub run {
21 21
 
22 22
 1;
23 23
 
24
+=encoding utf8
25
+
24 26
 =head1 NAME
25 27
 
26 28
 Mojolicious::Command::cgi - CGI command
+4 -2
mojo/lib/Mojolicious/Command/cpanify.pm
... ...
@@ -6,7 +6,7 @@ use Getopt::Long qw(GetOptionsFromArray :config no_auto_abbrev no_ignore_case);
6 6
 use Mojo::UserAgent;
7 7
 
8 8
 has description => "Upload distribution to CPAN.\n";
9
-has usage       => <<"EOF";
9
+has usage       => <<EOF;
10 10
 usage: $0 cpanify [OPTIONS] [FILE]
11 11
 
12 12
   mojo cpanify -u sri -p secr3t Mojolicious-Plugin-MyPlugin-0.01.tar.gz
... ...
@@ -24,7 +24,7 @@ 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(
27
+  my $tx = Mojo::UserAgent->new->tap(sub { $_->proxy->detect })->post(
28 28
     "https://$user:$password\@pause.perl.org/pause/authenquery" => form => {
29 29
       HIDDENNAME                        => $user,
30 30
       CAN_MULTIPART                     => 1,
... ...
@@ -48,6 +48,8 @@ sub run {
48 48
 
49 49
 1;
50 50
 
51
+=encoding utf8
52
+
51 53
 =head1 NAME
52 54
 
53 55
 Mojolicious::Command::cpanify - Cpanify command
+3 -1
mojo/lib/Mojolicious/Command/daemon.pm
... ...
@@ -5,7 +5,7 @@ use Getopt::Long qw(GetOptionsFromArray :config no_auto_abbrev no_ignore_case);
5 5
 use Mojo::Server::Daemon;
6 6
 
7 7
 has description => "Start application with HTTP and WebSocket server.\n";
8
-has usage       => <<"EOF";
8
+has usage       => <<EOF;
9 9
 usage: $0 daemon [OPTIONS]
10 10
 
11 11
 These options are available:
... ...
@@ -45,6 +45,8 @@ sub run {
45 45
 
46 46
 1;
47 47
 
48
+=encoding utf8
49
+
48 50
 =head1 NAME
49 51
 
50 52
 Mojolicious::Command::daemon - Daemon command
+9 -5
mojo/lib/Mojolicious/Command/eval.pm
... ...
@@ -4,32 +4,36 @@ use Mojo::Base 'Mojolicious::Command';
4 4
 use Getopt::Long qw(GetOptionsFromArray :config no_auto_abbrev no_ignore_case);
5 5
 
6 6
 has description => "Run code against application.\n";
7
-has usage       => <<"EOF";
7
+has usage       => <<EOF;
8 8
 usage: $0 eval [OPTIONS] CODE
9 9
 
10 10
   mojo eval 'say app->ua->get("/")->res->body'
11 11
   mojo eval -v 'app->home'
12
+  mojo eval -V 'app->renderer->paths'
12 13
 
13 14
 These options are available:
14 15
   -v, --verbose   Print return value to STDOUT.
16
+  -V              Print returned data structure to STDOUT.
15 17
 EOF
16 18
 
17 19
 sub run {
18 20
   my ($self, @args) = @_;
19 21
 
20
-  GetOptionsFromArray \@args, 'v|verbose' => \my $verbose;
22
+  GetOptionsFromArray \@args, 'v|verbose' => \my $v1, 'V' => \my $v2;
21 23
   my $code = shift @args || '';
22 24
 
23 25
   # Run code against application
24 26
   my $app = $self->app;
25 27
   no warnings;
26
-  my $result = eval "package main; sub app { \$app }; $code";
27
-  say $result if $verbose && defined $result;
28
-  return $@ ? die $@ : $result;
28
+  my $result = eval "package main; sub app; local *app = sub { \$app }; $code";
29
+  return $@ ? die $@ : $result unless defined $result && ($v1 || $v2);
30
+  $v2 ? print($app->dumper($result)) : say $result;
29 31
 }
30 32
 
31 33
 1;
32 34
 
35
+=encoding utf8
36
+
33 37
 =head1 NAME
34 38
 
35 39
 Mojolicious::Command::eval - Eval command
+4 -2
mojo/lib/Mojolicious/Command/generate.pm
... ...
@@ -2,11 +2,11 @@ package Mojolicious::Command::generate;
2 2
 use Mojo::Base 'Mojolicious::Commands';
3 3
 
4 4
 has description => "Generate files and directories from templates.\n";
5
-has hint        => <<"EOF";
5
+has hint        => <<EOF;
6 6
 
7 7
 See '$0 generate help GENERATOR' for more information on a specific generator.
8 8
 EOF
9
-has message => <<"EOF";
9
+has message => <<EOF;
10 10
 usage: $0 generate GENERATOR [OPTIONS]
11 11
 
12 12
 These generators are currently available:
... ...
@@ -18,6 +18,8 @@ sub help { shift->run(@_) }
18 18
 
19 19
 1;
20 20
 
21
+=encoding utf8
22
+
21 23
 =head1 NAME
22 24
 
23 25
 Mojolicious::Command::generate - Generator command
+7 -5
mojo/lib/Mojolicious/Command/generate/app.pm
... ...
@@ -8,11 +8,11 @@ has usage       => "usage: $0 generate app [NAME]\n";
8 8
 
9 9
 sub run {
10 10
   my ($self, $class) = @_;
11
-  $class ||= 'MyMojoliciousApp';
11
+  $class ||= 'MyApp';
12 12
 
13 13
   # Prevent bad applications
14 14
   die <<EOF unless $class =~ /^[A-Z](?:\w|::)+$/;
15
-Your application name has to be a well formed (camel case) Perl module name
15
+Your application name has to be a well formed (CamelCase) Perl module name
16 16
 like "MyApp".
17 17
 EOF
18 18
 
... ...
@@ -94,8 +94,7 @@ sub welcome {
94 94
   my $self = shift;
95 95
 
96 96
   # Render template "example/welcome.html.ep" with message
97
-  $self->render(
98
-    message => 'Welcome to the Mojolicious real-time web framework!');
97
+  $self->render(msg => 'Welcome to the Mojolicious real-time web framework!');
99 98
 }
100 99
 
101 100
 1;
... ...
@@ -135,13 +134,16 @@ done_testing();
135 134
 @@ welcome
136 135
 %% layout 'default';
137 136
 %% title 'Welcome';
138
-<h2><%%= $message %></h2>
137
+<h2><%%= $msg %></h2>
139 138
 This page was generated from the template "templates/example/welcome.html.ep"
140 139
 and the layout "templates/layouts/default.html.ep",
141 140
 <a href="<%%== url_for %>">click here</a> to reload the page or
142 141
 <a href="/index.html">here</a> to move forward to a static page.
143 142
 
144 143
 __END__
144
+
145
+=encoding utf8
146
+
145 147
 =head1 NAME
146 148
 
147 149
 Mojolicious::Command::generate::app - App generator command
+3
mojo/lib/Mojolicious/Command/generate/lite_app.pm
... ...
@@ -42,6 +42,9 @@ Welcome to the Mojolicious real-time web framework!
42 42
 </html>
43 43
 
44 44
 __END__
45
+
46
+=encoding utf8
47
+
45 48
 =head1 NAME
46 49
 
47 50
 Mojolicious::Command::generate::lite_app - Lite app generator command
+3
mojo/lib/Mojolicious/Command/generate/makefile.pm
... ...
@@ -24,6 +24,9 @@ WriteMakefile(
24 24
 );
25 25
 
26 26
 __END__
27
+
28
+=encoding utf8
29
+
27 30
 =head1 NAME
28 31
 
29 32
 Mojolicious::Command::generate::makefile - Makefile generator command
+5
mojo/lib/Mojolicious/Command/generate/plugin.pm
... ...
@@ -41,6 +41,8 @@ sub register {
41 41
 1;
42 42
 <% %>__END__
43 43
 
44
+<% %>=encoding utf8
45
+
44 46
 <% %>=head1 NAME
45 47
 
46 48
 <%= $class %> - Mojolicious Plugin
... ...
@@ -110,6 +112,9 @@ WriteMakefile(
110 112
 );
111 113
 
112 114
 __END__
115
+
116
+=encoding utf8
117
+
113 118
 =head1 NAME
114 119
 
115 120
 Mojolicious::Command::generate::plugin - Plugin generator command
+6 -4
mojo/lib/Mojolicious/Command/get.pm
... ...
@@ -11,7 +11,7 @@ use Mojo::Util qw(decode encode);
11 11
 use Scalar::Util 'weaken';
12 12
 
13 13
 has description => "Perform HTTP request.\n";
14
-has usage       => <<"EOF";
14
+has usage       => <<EOF;
15 15
 usage: $0 get [OPTIONS] URL [SELECTOR|JSON-POINTER] [COMMANDS]
16 16
 
17 17
   mojo get /
... ...
@@ -24,7 +24,7 @@ usage: $0 get [OPTIONS] URL [SELECTOR|JSON-POINTER] [COMMANDS]
24 24
   mojo get mojolicio.us a attr href
25 25
   mojo get mojolicio.us '*' attr id
26 26
   mojo get mojolicio.us 'h1, h2, h3' 3 text
27
-  mojo get http://search.twitter.com/search.json /error
27
+  mojo get https://api.metacpan.org/v0/author/SRI /name
28 28
 
29 29
 These options are available:
30 30
   -C, --charset <charset>     Charset of HTML/XML content, defaults to auto
... ...
@@ -57,7 +57,7 @@ sub run {
57 57
 
58 58
   # Detect proxy for absolute URLs
59 59
   my $ua = Mojo::UserAgent->new(ioloop => Mojo::IOLoop->singleton);
60
-  $url !~ m!^/! ? $ua->detect_proxy : $ua->app($self->app);
60
+  $url !~ m!^/! ? $ua->proxy->detect : $ua->server->app($self->app);
61 61
   $ua->max_redirects(10) if $redirect;
62 62
 
63 63
   my $buffer = '';
... ...
@@ -135,7 +135,7 @@ sub _select {
135 135
     # Attribute
136 136
     elsif ($command eq 'attr') {
137 137
       next unless my $name = shift @args;
138
-      _say($_->attrs->{$name}) for @$results;
138
+      _say($_->attr->{$name}) for @$results;
139 139
     }
140 140
 
141 141
     # Unknown
... ...
@@ -148,6 +148,8 @@ sub _select {
148 148
 
149 149
 1;
150 150
 
151
+=encoding utf8
152
+
151 153
 =head1 NAME
152 154
 
153 155
 Mojolicious::Command::get - Get command
+12 -6
mojo/lib/Mojolicious/Command/inflate.pm
... ...
@@ -14,19 +14,25 @@ sub run {
14 14
   my %all;
15 15
   my $app    = $self->app;
16 16
   my $loader = Mojo::Loader->new;
17
-  %all = (%{$loader->data($_)}, %all)
18
-    for @{$app->renderer->classes}, @{$app->static->classes};
17
+  for my $class (@{$app->renderer->classes}, @{$app->static->classes}) {
18
+    for my $name (keys %{$loader->data($class)}) {
19
+      my $data = $loader->data($class, $name);
20
+      $all{$name}
21
+        = $loader->is_binary($class, $name) ? $data : encode('UTF-8', $data);
22
+    }
23
+  }
19 24
 
20 25
   # Turn them into real files
21
-  for my $file (keys %all) {
22
-    my $prefix = $file =~ /\.\w+\.\w+$/ ? 'templates' : 'public';
23
-    my $path = $self->rel_file("$prefix/$file");
24
-    $self->write_file($path, encode('UTF-8', $all{$file}));
26
+  for my $name (keys %all) {
27
+    my $prefix = $name =~ /\.\w+\.\w+$/ ? 'templates' : 'public';
28
+    $self->write_file($self->rel_file("$prefix/$name"), $all{$name});
25 29
   }
26 30
 }
27 31
 
28 32
 1;
29 33
 
34
+=encoding utf8
35
+
30 36
 =head1 NAME
31 37
 
32 38
 Mojolicious::Command::inflate - Inflate command
+3 -1
mojo/lib/Mojolicious/Command/prefork.pm
... ...
@@ -6,7 +6,7 @@ use Mojo::Server::Prefork;
6 6
 
7 7
 has description =>
8 8
   "Start application with preforking HTTP and WebSocket server.\n";
9
-has usage => <<"EOF";
9
+has usage => <<EOF;
10 10
 usage: $0 prefork [OPTIONS]
11 11
 
12 12
 These options are available:
... ...
@@ -72,6 +72,8 @@ sub run {
72 72
 
73 73
 1;
74 74
 
75
+=encoding utf8
76
+
75 77
 =head1 NAME
76 78
 
77 79
 Mojolicious::Command::prefork - Prefork command
+2
mojo/lib/Mojolicious/Command/psgi.pm
... ...
@@ -10,6 +10,8 @@ sub run { Mojo::Server::PSGI->new(app => shift->app)->to_psgi_app }
10 10
 
11 11
 1;
12 12
 
13
+=encoding utf8
14
+
13 15
 =head1 NAME
14 16
 
15 17
 Mojolicious::Command::psgi - PSGI command
+5 -2
mojo/lib/Mojolicious/Command/routes.pm
... ...
@@ -6,7 +6,7 @@ use Getopt::Long qw(GetOptionsFromArray :config no_auto_abbrev no_ignore_case);
6 6
 use Mojo::Util 'encode';
7 7
 
8 8
 has description => "Show available routes.\n";
9
-has usage       => <<"EOF";
9
+has usage       => <<EOF;
10 10
 usage: $0 routes [OPTIONS]
11 11
 
12 12
 These options are available:
... ...
@@ -51,7 +51,8 @@ sub _draw {
51 51
     my $format = (regexp_pattern($pattern->format_regex || ''))[0];
52 52
     my $optional
53 53
       = !$pattern->constraints->{format} || $pattern->defaults->{format};
54
-    $regex .= $optional ? "(?:$format)?" : $format if $format;
54
+    $regex .= $optional ? "(?:$format)?" : $format
55
+      if $format && !$node->[0]->partial;
55 56
     push @parts, $regex if $verbose;
56 57
 
57 58
     say encode('UTF-8', join('  ', @parts));
... ...
@@ -76,6 +77,8 @@ sub _walk {
76 77
 
77 78
 1;
78 79
 
80
+=encoding utf8
81
+
79 82
 =head1 NAME
80 83
 
81 84
 Mojolicious::Command::routes - Routes command
+3 -1
mojo/lib/Mojolicious/Command/test.pm
... ...
@@ -8,7 +8,7 @@ use Getopt::Long qw(GetOptionsFromArray :config no_auto_abbrev no_ignore_case);
8 8
 use Mojo::Home;
9 9
 
10 10
 has description => "Run unit tests.\n";
11
-has usage       => <<"EOF";
11
+has usage       => <<EOF;
12 12
 usage: $0 test [OPTIONS] [TESTS]
13 13
 
14 14
 These options are available:
... ...
@@ -42,6 +42,8 @@ sub run {
42 42
 
43 43
 1;
44 44
 
45
+=encoding utf8
46
+
45 47
 =head1 NAME
46 48
 
47 49
 Mojolicious::Command::test - Test command
+5 -2
mojo/lib/Mojolicious/Command/version.pm
... ...
@@ -17,7 +17,7 @@ sub run {
17 17
   my $tls
18 18
     = Mojo::IOLoop::Server::TLS ? $IO::Socket::SSL::VERSION : 'not installed';
19 19
 
20
-  print <<"EOF";
20
+  print <<EOF;
21 21
 CORE
22 22
   Perl        ($^V, $^O)
23 23
   Mojolicious ($Mojolicious::VERSION, $Mojolicious::CODENAME)
... ...
@@ -31,7 +31,8 @@ EOF
31 31
 
32 32
   # Check latest version on CPAN
33 33
   my $latest = eval {
34
-    my $ua = Mojo::UserAgent->new(max_redirects => 10)->detect_proxy;
34
+    my $ua = Mojo::UserAgent->new(max_redirects => 10);
35
+    $ua->proxy->detect;
35 36
     $ua->get('api.metacpan.org/v0/release/Mojolicious')->res->json->{version};
36 37
   };
37 38
 
... ...
@@ -46,6 +47,8 @@ EOF
46 47
 
47 48
 1;
48 49
 
50
+=encoding utf8
51
+
49 52
 =head1 NAME
50 53
 
51 54
 Mojolicious::Command::version - Version command
+6 -4
mojo/lib/Mojolicious/Commands.pm
... ...
@@ -5,18 +5,18 @@ use Getopt::Long 'GetOptions';
5 5
 use List::Util 'max';
6 6
 use Mojo::Server;
7 7
 
8
-has hint => <<"EOF";
8
+has hint => <<EOF;
9 9
 
10 10
 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 of
15
-                        MOJO_MODE/PLACK_ENV or "development".
14
+    -m, --mode <name>   Operating mode for your application, defaults to the
15
+                        value of MOJO_MODE/PLACK_ENV or "development".
16 16
 
17 17
 See '$0 help COMMAND' for more information on a specific command.
18 18
 EOF
19
-has message => <<"EOF";
19
+has message => <<EOF;
20 20
 usage: $0 COMMAND [OPTIONS]
21 21
 
22 22
 Tip: CGI and PSGI environments can be automatically detected very often and
... ...
@@ -117,6 +117,8 @@ sub _command {
117 117
 
118 118
 1;
119 119
 
120
+=encoding utf8
121
+
120 122
 =head1 NAME
121 123
 
122 124
 Mojolicious::Commands - Command line interface
+105 -84
mojo/lib/Mojolicious/Controller.pm
... ...
@@ -39,6 +39,8 @@ sub AUTOLOAD {
39 39
 
40 40
 sub DESTROY { }
41 41
 
42
+sub continue { $_[0]->app->routes->continue($_[0]) }
43
+
42 44
 sub cookie {
43 45
   my ($self, $name) = (shift, shift);
44 46
 
... ...
@@ -374,15 +376,13 @@ sub stash {
374 376
   return $self;
375 377
 }
376 378
 
377
-sub ua { shift->app->ua }
378
-
379 379
 sub url_for {
380 380
   my $self = shift;
381 381
   my $target = shift; $target = defined $target ? $target : '';
382 382
 
383 383
   # Absolute URL
384 384
   return $target if Scalar::Util::blessed $target && $target->isa('Mojo::URL');
385
-  return Mojo::URL->new($target) if $target =~ m!^\w+://!;
385
+  return Mojo::URL->new($target) if $target =~ m!^(?:[^:/?#]+:|//)!;
386 386
 
387 387
   # Base
388 388
   my $url  = Mojo::URL->new;
... ...
@@ -404,12 +404,6 @@ sub url_for {
404 404
   else {
405 405
     my ($generated, $ws) = $self->match->path_for($target, @_);
406 406
     $path->parse($generated) if $generated;
407
-
408
-    # Fix trailing slash
409
-    $path->trailing_slash(1)
410
-      if (!$target || $target eq 'current') && $req->url->path->trailing_slash;
411
-
412
-    # Fix scheme for WebSockets
413 407
     $base->scheme($base->protocol eq 'https' ? 'wss' : 'ws') if $ws;
414 408
   }
415 409
 
... ...
@@ -421,6 +415,12 @@ sub url_for {
421 415
   return $url;
422 416
 }
423 417
 
418
+sub validation {
419
+  my $self = shift;
420
+  return $self->stash->{'mojo.validation'}
421
+    ||= $self->app->validator->validation->input($self->req->params->to_hash);
422
+}
423
+
424 424
 sub write {
425 425
   my ($self, $chunk, $cb) = @_;
426 426
   ($cb, $chunk) = ($chunk, undef) if ref $chunk eq 'CODE';
... ...
@@ -449,7 +449,7 @@ sub _fallbacks {
449 449
   # Inline template
450 450
   my $stash = $self->stash;
451 451
   return undef unless $stash->{format} eq 'html';
452
-  delete $stash->{$_} for qw(extends layout);
452
+  delete @$stash{qw(extends layout)};
453 453
   return $self->render_maybe(%$options, inline => $inline, handler => 'ep');
454 454
 }
455 455
 
... ...
@@ -478,8 +478,8 @@ Mojolicious::Controller - Controller base class
478 478
 =head1 DESCRIPTION
479 479
 
480 480
 L<Mojolicious::Controller> is the base class for your L<Mojolicious>
481
-controllers. It is also the default controller class for L<Mojolicious>
482
-unless you set C<controller_class> in your application.
481
+controllers. It is also the default controller class unless you set
482
+L<Mojolicious/"controller_class">.
483 483
 
484 484
 =head1 ATTRIBUTES
485 485
 
... ...
@@ -497,6 +497,9 @@ defaults to a L<Mojolicious> object.
497 497
   # Use application logger
498 498
   $c->app->log->debug('Hello Mojo!');
499 499
 
500
+  # Generate path
501
+  my $path = $c->app->home->rel_file('templates/foo/bar.html.ep');
502
+
500 503
 =head2 match
501 504
 
502 505
   my $m = $c->match;
... ...
@@ -507,6 +510,7 @@ L<Mojolicious::Routes::Match> object.
507 510
 
508 511
   # Introspect
509 512
   my $foo = $c->match->endpoint->pattern->defaults->{foo};
513
+  my $bar = $c->match->stack->[-1]{bar};
510 514
 
511 515
 =head2 tx
512 516
 
... ...
@@ -514,16 +518,32 @@ L<Mojolicious::Routes::Match> object.
514 518
   $c     = $c->tx(Mojo::Transaction::HTTP->new);
515 519
 
516 520
 The transaction that is currently being processed, usually a
517
-L<Mojo::Transaction::HTTP> or L<Mojo::Transaction::WebSocket> object.
521
+L<Mojo::Transaction::HTTP> or L<Mojo::Transaction::WebSocket> object. Note
522
+that this reference is usually weakened, so the object needs to be referenced
523
+elsewhere as well when you're performing non-blocking operations and the
524
+underlying connection might get closed early.
518 525
 
519 526
   # Check peer information
520 527
   my $address = $c->tx->remote_address;
528
+  my $port    = $c->tx->remote_port;
529
+
530
+  # Perform non-blocking operation without knowing the connection status
531
+  my $tx = $c->tx;
532
+  Mojo::IOLoop->timer(2 => sub {
533
+    $c->app->log->debug($tx->is_finished ? 'Finished.' : 'In progress.');
534
+  });
521 535
 
522 536
 =head1 METHODS
523 537
 
524 538
 L<Mojolicious::Controller> inherits all methods from L<Mojo::Base> and
525 539
 implements the following new ones.
526 540
 
541
+=head2 continue
542
+
543
+  $c->continue;
544
+
545
+Continue dispatch chain.
546
+
527 547
 =head2 cookie
528 548
 
529 549
   my $value  = $c->cookie('foo');
... ...
@@ -551,7 +571,8 @@ Close WebSocket connection or long poll stream gracefully.
551 571
   $c      = $c->flash({foo => 'bar'});
552 572
   $c      = $c->flash(foo => 'bar');
553 573
 
554
-Data storage persistent only for the next request, stored in the C<session>.
574
+Data storage persistent only for the next request, stored in the
575
+L</"session">.
555 576
 
556 577
   # Show message after redirect
557 578
   $c->flash(message => 'User created successfully!');
... ...
@@ -561,8 +582,10 @@ Data storage persistent only for the next request, stored in the C<session>.
561 582
 
562 583
   my $cb = $c->on(finish => sub {...});
563 584
 
564
-Subscribe to events of C<tx>, which is usually a L<Mojo::Transaction::HTTP> or
565
-L<Mojo::Transaction::WebSocket> object.
585
+Subscribe to events of L</"tx">, which is usually a L<Mojo::Transaction::HTTP>
586
+or L<Mojo::Transaction::WebSocket> object. Note that this method will
587
+automatically respond to WebSocket handshake requests with a C<101> response
588
+status.
566 589
 
567 590
   # Do something after the transaction has been finished
568 591
   $c->on(finish => sub {
... ...
@@ -598,10 +621,12 @@ L<Mojo::Transaction::WebSocket> object.
598 621
   $c              = $c->param(foo => 'ba;r');
599 622
   $c              = $c->param(foo => qw(ba;r ba;z));
600 623
 
601
-Access GET/POST parameters, file uploads and route placeholder values that are
602
-not reserved stash values. Note that this method is context sensitive in some
603
-cases and therefore needs to be used with care, there can always be multiple
604
-values, which might have unexpected consequences.
624
+Access route placeholder values that are not reserved stash values, file
625
+uploads and GET/POST parameters, in that order. Note that this method is
626
+context sensitive in some cases and therefore needs to be used with care,
627
+there can always be multiple values, which might have unexpected consequences.
628
+Parts of the request body need to be loaded into memory to parse POST
629
+parameters, so you have to make sure it is not excessively large.
605 630
 
606 631
   # List context is ambiguous and should be avoided
607 632
   my $hash = {foo => $self->param('foo')};
... ...
@@ -625,12 +650,12 @@ For more control you can also access request information directly.
625 650
 
626 651
 =head2 redirect_to
627 652
 
628
-  $c = $c->redirect_to('named');
629 653
   $c = $c->redirect_to('named', foo => 'bar');
630
-  $c = $c->redirect_to('/path');
631
-  $c = $c->redirect_to('http://127.0.0.1/foo/bar');
654
+  $c = $c->redirect_to('named', {foo => 'bar'});
655
+  $c = $c->redirect_to('/perldoc');
656
+  $c = $c->redirect_to('http://mojolicio.us/perldoc');
632 657
 
633
-Prepare a C<302> redirect response, takes the same arguments as C<url_for>.
658
+Prepare a C<302> redirect response, takes the same arguments as L</"url_for">.
634 659
 
635 660
   # Conditional redirect
636 661
   return $c->redirect_to('login') unless $c->session('user');
... ...
@@ -641,21 +666,21 @@ Prepare a C<302> redirect response, takes the same arguments as C<url_for>.
641 666
 
642 667
 =head2 render
643 668
 
644
-  my $success = $c->render;
645
-  my $success = $c->render(controller => 'foo', action => 'bar');
646
-  my $success = $c->render(template => 'foo/index');
647
-  my $success = $c->render(template => 'index', format => 'html');
648
-  my $success = $c->render(data => $bytes);
649
-  my $success = $c->render(text => 'Hello!');
650
-  my $success = $c->render(json => {foo => 'bar'});
651
-  my $success = $c->render(handler => 'something');
652
-  my $success = $c->render('foo/index');
669
+  my $bool    = $c->render;
670
+  my $bool    = $c->render(controller => 'foo', action => 'bar');
671
+  my $bool    = $c->render(template => 'foo/index');
672
+  my $bool    = $c->render(template => 'index', format => 'html');
673
+  my $bool    = $c->render(data => $bytes);
674
+  my $bool    = $c->render(text => 'Hello!');
675
+  my $bool    = $c->render(json => {foo => 'bar'});
676
+  my $bool    = $c->render(handler => 'something');
677
+  my $bool    = $c->render('foo/index');
653 678
   my $output  = $c->render('foo/index', partial => 1);
654 679
 
655
-Render content using L<Mojolicious::Renderer/"render"> and emit
656
-C<after_render> hook unless the result is C<partial>. If no template is
657
-provided a default one based on controller and action or route name will be
658
-generated, all additional values get merged into the C<stash>.
680
+Render content using L<Mojolicious::Renderer/"render"> and emit hook
681
+L<Mojolicious/"after_render"> unless the result is C<partial>. If no template
682
+is provided a default one based on controller and action or route name will be
683
+generated, all additional values get merged into the L</"stash">.
659 684
 
660 685
 =head2 render_exception
661 686
 
... ...
@@ -665,7 +690,7 @@ generated, all additional values get merged into the C<stash>.
665 690
 Render the exception template C<exception.$mode.$format.*> or
666 691
 C<exception.$format.*> and set the response status code to C<500>. Also sets
667 692
 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.
693
+to a copy of the L</"stash"> for use in the templates.
669 694
 
670 695
 =head2 render_later
671 696
 
... ...
@@ -682,12 +707,12 @@ automatic rendering would result in a response.
682 707
 
683 708
 =head2 render_maybe
684 709
 
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');
710
+  my $bool = $c->render_maybe;
711
+  my $bool = $c->render_maybe(controller => 'foo', action => 'bar');
712
+  my $bool = $c->render_maybe('foo/index', format => 'html');
688 713
 
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>.
714
+Try to render content but do not call L</"render_not_found"> if no response
715
+could be generated, takes the same arguments as L</"render">.
691 716
 
692 717
   # Render template "index_local" only if it exists
693 718
   $self->render_maybe('index_local') or $self->render('index');
... ...
@@ -701,8 +726,8 @@ C<not_found.$format.*> and set the response status code to C<404>.
701 726
 
702 727
 =head2 render_static
703 728
 
704
-  my $success = $c->render_static('images/logo.png');
705
-  my $success = $c->render_static('../lib/MyApp.pm');
729
+  my $bool = $c->render_static('images/logo.png');
730
+  my $bool = $c->render_static('../lib/MyApp.pm');
706 731
 
707 732
 Render a static file using L<Mojolicious::Static/"serve">, usually from the
708 733
 C<public> directories or C<DATA> sections of your application. Note that this
... ...
@@ -713,8 +738,8 @@ method does not protect from traversing to parent directories.
713 738
   $c = $c->rendered;
714 739
   $c = $c->rendered(302);
715 740
 
716
-Finalize response and emit C<after_dispatch> hook, defaults to using a C<200>
717
-response code.
741
+Finalize response and emit hook L<Mojolicious/"after_dispatch">, defaults to
742
+using a C<200> response code.
718 743
 
719 744
 =head2 req
720 745
 
... ...
@@ -730,8 +755,11 @@ Get L<Mojo::Message::Request> object from L<Mojo::Transaction/"req">.
730 755
   my $userinfo = $c->req->url->to_abs->userinfo;
731 756
   my $host     = $c->req->url->to_abs->host;
732 757
   my $agent    = $c->req->headers->user_agent;
733
-  my $body     = $c->req->body;
758
+  my $bytes    = $c->req->body;
759
+  my $str      = $c->req->text;
760
+  my $hash     = $c->req->json;
734 761
   my $foo      = $c->req->json('/23/foo');
762
+  my $dom      = $c->req->dom;
735 763
   my $bar      = $c->req->dom('div.bar')->first->text;
736 764
 
737 765
 =head2 res
... ...
@@ -773,12 +801,13 @@ is set to the value C<XMLHttpRequest>.
773 801
   $c = $c->send({text   => $bytes});
774 802
   $c = $c->send({json   => {test => [1, 2, 3]}});
775 803
   $c = $c->send([$fin, $rsv1, $rsv2, $rsv3, $op, $bytes]);
776
-  $c = $c->send(Mojo::ByteStream->new($chars));
777 804
   $c = $c->send($chars);
778 805
   $c = $c->send($chars => sub {...});
779 806
 
780 807
 Send message or frame non-blocking via WebSocket, the optional drain callback
781
-will be invoked once all data has been written.
808
+will be invoked once all data has been written. Note that this method will
809
+automatically respond to WebSocket handshake requests with a C<101> response
810
+status.
782 811
 
783 812
   # Send "Text" message
784 813
   $c->send('I ♥ Mojolicious!');
... ...
@@ -793,6 +822,12 @@ will be invoked once all data has been written.
793 822
   # Send "Ping" frame
794 823
   $c->send([1, 0, 0, 0, 9, 'Hello World!']);
795 824
 
825
+  # Make sure previous message has been written before continuing
826
+  $c->send('First message!' => sub {
827
+    my $c = shift;
828
+    $c->send('Second message!');
829
+  });
830
+
796 831
 For mostly idle WebSockets you might also want to increase the inactivity
797 832
 timeout, which usually defaults to C<15> seconds.
798 833
 
... ...
@@ -843,7 +878,7 @@ discarded.
843 878
   $c       = $c->stash(foo => 'bar');
844 879
 
845 880
 Non persistent data storage and exchange, application wide default values can
846
-be set with L<Mojolicious/"defaults">. Many stash values have a special
881
+be set with L<Mojolicious/"defaults">. Some stash values have a special
847 882
 meaning and are reserved, the full list is currently C<action>, C<app>, C<cb>,
848 883
 C<controller>, C<data>, C<extends>, C<format>, C<handler>, C<json>, C<layout>,
849 884
 C<namespace>, C<partial>, C<path>, C<status>, C<template> and C<text>. Note
... ...
@@ -852,38 +887,6 @@ that all stash values with a C<mojo.*> prefix are reserved for internal use.
852 887
   # Remove value
853 888
   my $foo = delete $c->stash->{foo};
854 889
 
855
-=head2 ua
856
-
857
-  my $ua = $c->ua;
858
-
859
-Get L<Mojo::UserAgent> object from L<Mojo/"ua">.
860
-
861
-  # Longer version
862
-  my $ua = $c->app->ua;
863
-
864
-  # Blocking
865
-  my $tx = $c->ua->get('http://example.com');
866
-  my $tx = $c->ua->post('example.com/login' => form => {user => 'mojo'});
867
-
868
-  # Non-blocking
869
-  $c->ua->get('http://example.com' => sub {
870
-    my ($ua, $tx) = @_;
871
-    $c->render(data => $tx->res->body);
872
-  });
873
-
874
-  # Parallel non-blocking
875
-  my $delay = Mojo::IOLoop->delay(sub {
876
-    my ($delay, @titles) = @_;
877
-    $c->render(json => \@titles);
878
-  });
879
-  for my $url ('http://mojolicio.us', 'https://metacpan.org') {
880
-    my $end = $delay->begin(0);
881
-    $c->ua->get($url => sub {
882
-      my ($ua, $tx) = @_;
883
-      $end->($tx->res->dom->html->head->title->text);
884
-    });
885
-  }
886
-
887 890
 =head2 url_for
888 891
 
889 892
   my $url = $c->url_for;
... ...
@@ -892,10 +895,15 @@ Get L<Mojo::UserAgent> object from L<Mojo/"ua">.
892 895
   my $url = $c->url_for('test', name => 'sebastian');
893 896
   my $url = $c->url_for('test', {name => 'sebastian'});
894 897
   my $url = $c->url_for('/perldoc');
898
+  my $url = $c->url_for('//mojolicio.us/perldoc');
895 899
   my $url = $c->url_for('http://mojolicio.us/perldoc');
900
+  my $url = $c->url_for('mailto:sri@example.com');
896 901
 
897 902
 Generate a portable L<Mojo::URL> object with base for a route, path or URL.
898 903
 
904
+  # "http://127.0.0.1:3000/perldoc" if application has been started with Morbo
905
+  $c->url_for('/perldoc')->to_abs;
906
+
899 907
   # "/perldoc?foo=bar" if application is deployed under "/"
900 908
   $c->url_for('/perldoc')->query(foo => 'bar');
901 909
 
... ...
@@ -908,6 +916,19 @@ to inherit query parameters from the current request.
908 916
   # "/list?q=mojo&page=2" if current request was for "/list?q=mojo&page=1"
909 917
   $c->url_with->query([page => 2]);
910 918
 
919
+=head2 validation
920
+
921
+  my $validation = $c->validation;
922
+
923
+Get L<Mojolicious::Validator::Validation> object for current request to
924
+validate GET/POST parameters. Parts of the request body need to be loaded into
925
+memory to parse POST parameters, so you have to make sure it is not
926
+excessively large.
927
+
928
+  my $validation = $c->validation;
929
+  $validation->required('title')->size(3, 50);
930
+  my $title = $validation->param('title');
931
+
911 932
 =head2 write
912 933
 
913 934
   $c = $c->write;
... ...
@@ -959,7 +980,7 @@ optional drain callback will be invoked once all data has been written.
959 980
     });
960 981
   });
961 982
 
962
-You can call C<finish> at any time to end the stream.
983
+You can call L</"finish"> at any time to end the stream.
963 984
 
964 985
   2
965 986
   He
+16 -7
mojo/lib/Mojolicious/Guides.pod
... ...
@@ -1,4 +1,6 @@
1 1
 
2
+=encoding utf8
3
+
2 4
 =head1 NAME
3 5
 
4 6
 Mojolicious::Guides - Mojolicious guide to the galaxy
... ...
@@ -20,12 +22,6 @@ available in many formats. Both are excellent introductions to the language.
20 22
 For more books and documentation, check out
21 23
 L<learn.perl.org|http://learn.perl.org/>.
22 24
 
23
-=head1 SCREENCASTS
24
-
25
-Before starting with the tutorial below, you should take a look at the
26
-wonderful L<Mojocasts|http://mojocasts.com/e1>, they will give you a general
27
-overview of what L<Mojolicious> is all about.
28
-
29 25
 =head1 TUTORIAL
30 26
 
31 27
 =over 2
... ...
@@ -122,7 +118,20 @@ Test driven development toolkit for web applications.
122 118
 
123 119
 =item L<ojo>
124 120
 
125
-Fun oneliners using everything above.
121
+Fun one-liners using everything above.
122
+
123
+=back
124
+
125
+=head1 SPIN-OFFS
126
+
127
+These modules are not part of the L<Mojolicious> distribution, but have been
128
+designed to be used with it and are being developed under the same umbrella.
129
+
130
+=over 2
131
+
132
+=item L<Mango>
133
+
134
+Pure-Perl non-blocking I/O MongoDB driver.
126 135
 
127 136
 =back
128 137
 
+5 -3
mojo/lib/Mojolicious/Guides/Contributing.pod
... ...
@@ -1,4 +1,6 @@
1 1
 
2
+=encoding utf8
3
+
2 4
 =head1 NAME
3 5
 
4 6
 Mojolicious::Guides::Contributing - Contributing to Mojolicious
... ...
@@ -100,8 +102,8 @@ All components should be reusable in other projects, and in a UNIXish way only
100 102
 loosely coupled.
101 103
 
102 104
 Especially for people new to Perl it should be as easy as possible to install
103
-Mojolicious and get started. Writing web applications can be one of the most
104
-fun ways to learn a language!
105
+L<Mojolicious> and get started. Writing web applications can be one of the
106
+most fun ways to learn a language!
105 107
 
106 108
 For developers of other web frameworks, it should be possible to reuse all the
107 109
 infrastructure and just consider the higher levels of the L<Mojolicious>
... ...
@@ -164,7 +166,7 @@ feature branches for actual development.
164 166
 Code has to be run through L<Perl::Tidy> with the included C<.perltidyrc>, and
165 167
 everything should look like it was written by a single person.
166 168
 
167
-Methods and functions should be as short as possible, no spaghetti code.
169
+Functions and methods should be as short as possible, no spaghetti code.
168 170
 
169 171
 Comments should be correctly capitalized, and funny if possible, punctuation
170 172
 is optional if it doesn't increase readability.
+188 -169
mojo/lib/Mojolicious/Guides/Cookbook.pod
... ...
@@ -1,4 +1,6 @@
1 1
 
2
+=encoding utf8
3
+
2 4
 =head1 NAME
3 5
 
4 6
 Mojolicious::Guides::Cookbook - Cookbook
... ...
@@ -32,7 +34,8 @@ works on.
32 34
 
33 35
 Another huge advantage is that it supports TLS and WebSockets out of the box,
34 36
 a development certificate for testing purposes is built right in, so it just
35
-works.
37
+works, but you can specify all listen locations supported by
38
+L<Mojo::Server::Daemon/"listen">.
36 39
 
37 40
   $ ./script/myapp daemon -l https://*:3000
38 41
   Server available at https://127.0.0.1:3000.
... ...
@@ -51,6 +54,20 @@ concurrent connections each worker is allowed to handle.
51 54
   $ ./script/myapp prefork -m production -w 10 -c 1
52 55
   Server available at http://127.0.0.1:3000.
53 56
 
57
+Your application is preloaded in the manager process during startup, to run
58
+code whenever a new worker process has been forked you can use L<Mojo::IOLoop>
59
+timers.
60
+
61
+  use Mojolicious::Lite;
62
+
63
+  Mojo::IOLoop->timer(0 => sub {
64
+    app->log->info("Worker $$ star...ALL GLORY TO THE HYPNOTOAD!");
65
+  });
66
+
67
+  get '/' => {text => 'Hello Wor...ALL GLORY TO THE HYPNOTOAD!'};
68
+
69
+  app->start;
70
+
54 71
 =head2 Morbo
55 72
 
56 73
 After reading the L<Mojolicious::Lite> tutorial, you should already be
... ...
@@ -85,8 +102,9 @@ environments out of the box.
85 102
   $ hypnotoad script/myapp
86 103
   Server available at http://127.0.0.1:8080.
87 104
 
88
-You can tweak many configuration settings right from within your application,
89
-for a full list see L<Mojo::Server::Hypnotoad/"SETTINGS">.
105
+You can tweak many configuration settings right from within your application
106
+with L<Mojo/"config">, for a full list see
107
+L<Mojo::Server::Hypnotoad/"SETTINGS">.
90 108
 
91 109
   use Mojolicious::Lite;
92 110
 
... ...
@@ -108,9 +126,9 @@ L<Mojolicious::Plugin::JSONConfig> configuration file.
108 126
   };
109 127
 
110 128
 But one of its biggest advantages is the support for effortless zero downtime
111
-software upgrades. That means you can upgrade L<Mojolicious>, Perl or even
112
-system libraries at runtime without ever stopping the server or losing a
113
-single incoming connection, just by running the command above again.
129
+software upgrades (hot deployment). That means you can upgrade L<Mojolicious>,
130
+Perl or even system libraries at runtime without ever stopping the server or
131
+losing a single incoming connection, just by running the command above again.
114 132
 
115 133
   $ hypnotoad script/myapp
116 134
   Starting hot deployment for Hypnotoad server 31841.
... ...
@@ -122,19 +140,25 @@ C<X-Forwarded-For> and C<X-Forwarded-HTTPS> headers.
122 140
   # myapp.conf
123 141
   {hypnotoad => {proxy => 1}};
124 142
 
125
-Your application is preloaded in the manager process during startup, to run
126
-code whenever a new worker process has been forked you can use L<Mojo::IOLoop>
127
-timers.
143
+=head2 Zero downtime software upgrades
128 144
 
129
-  use Mojolicious::Lite;
145
+Hypnotoad makes zero downtime software upgrades (hot deployment) very simple,
146
+as you can see above, but on modern operating systems that support the
147
+C<SO_REUSEPORT> socket option, there is also another method available that
148
+works with all built-in web servers.
130 149
 
131
-  Mojo::IOLoop->timer(0 => sub {
132
-    app->log->info("Worker $$ star...ALL GLORY TO THE HYPNOTOAD!");
133
-  });
150
+  $ ./script/myapp prefork -P /tmp/first.pid -l http://*:8080?reuse=1
151
+  Server available at http://127.0.0.1:8080.
134 152
 
135
-  get '/' => {text => 'Hello Wor...ALL GLORY TO THE HYPNOTOAD!'};
153
+All you have to do is start a second web server listening to the same port and
154
+stop the first web server gracefully afterwards.
136 155
 
137
-  app->start;
156
+  $ ./script/myapp prefork -P /tmp/second.pid -l http://*:8080?reuse=1
157
+  Server available at http://127.0.0.1:8080.
158
+  $ kill -s TERM `cat /tmp/first.pid`
159
+
160
+Just remember that both web servers need to be started with the C<reuse>
161
+parameter.
138 162
 
139 163
 =head2 Nginx
140 164
 
... ...
@@ -242,30 +266,37 @@ But you could even use middleware right in your application.
242 266
 Sometimes you might have to deploy your application in a blackbox environment
243 267
 where you can't just change the server configuration or behind a reverse proxy
244 268
 that passes along additional information with C<X-*> headers. In such cases
245
-you can use a C<before_dispatch> hook to rewrite incoming requests.
269
+you can use the hook L<Mojolicious/"before_dispatch"> to rewrite incoming
270
+requests.
246 271
 
247 272
   # Change scheme if "X-Forwarded-Protocol" header is set to "https"
248 273
   app->hook(before_dispatch => sub {
249
-    my $self = shift;
250
-    $self->req->url->base->scheme('https')
251
-      if $self->req->headers->header('X-Forwarded-Protocol') eq 'https';
274
+    my $c = shift;
275
+    $c->req->url->base->scheme('https')
276
+      if $c->req->headers->header('X-Forwarded-Protocol') eq 'https';
252 277
   });
253 278
 
254 279
 Since reverse proxies generally don't pass along information about path
255 280
 prefixes your application might be deployed under, rewriting the base path of
256 281
 incoming requests is also quite common.
257 282
 
258
-  # Move first part from path to base path in production mode
283
+  # Move first part and slash from path to base path in production mode
259 284
   app->hook(before_dispatch => sub {
260
-    my $self = shift;
261
-    push @{$self->req->url->base->path}, shift @{$self->req->url->path};
285
+    my $c = shift;
286
+    push @{$c->req->url->base->path->trailing_slash(1)},
287
+      shift @{$c->req->url->path->leading_slash(0)};
262 288
   }) if app->mode eq 'production';
263 289
 
290
+L<Mojo::URL> objects are very easy to manipulate, just make sure that the URL
291
+(C<foo/bar?baz=yada>), which represents the routing destination, is always
292
+relative to the base URL (C<http://example.com/myapp/>), which represents the
293
+deployment location of your application.
294
+
264 295
 =head2 Application embedding
265 296
 
266 297
 From time to time you might want to reuse parts of L<Mojolicious> applications
267 298
 like configuration files, database connection or helpers for other scripts,
268
-with this little mock server you can just embed them.
299
+with this little L<Mojo::Server> based mock server you can just embed them.
269 300
 
270 301
   use Mojo::Server;
271 302
 
... ...
@@ -280,8 +311,9 @@ with this little mock server you can just embed them.
280 311
 
281 312
 =head2 Web server embedding
282 313
 
283
-You can also use the built-in web server to embed L<Mojolicious> applications
284
-into alien environments like foreign event loops.
314
+You can also use L<Mojo::IOLoop/"one_tick"> to embed the built-in web server
315
+L<Mojo::Server::Daemon> into alien environments like foreign event loops that
316
+for some reason can't just be integrated with a new reactor backend.
285 317
 
286 318
   use Mojolicious::Lite;
287 319
   use Mojo::IOLoop;
... ...
@@ -316,37 +348,37 @@ latency backend web services.
316 348
 
317 349
   use Mojolicious::Lite;
318 350
 
319
-  # Search Twitter for "perl"
351
+  # Search MetaCPAN for "mojolicious"
320 352
   get '/' => sub {
321 353
     my $self = shift;
322
-    $self->ua->get('http://search.twitter.com/search.json?q=perl' => sub {
354
+    $self->ua->get('api.metacpan.org/v0/module/_search?q=mojolicious' => sub {
323 355
       my ($ua, $tx) = @_;
324
-      $self->render('twitter', results => $tx->res->json->{results});
356
+      $self->render('metacpan', hits => $tx->res->json->{hits}{hits});
325 357
     });
326 358
   };
327 359
 
328 360
   app->start;
329 361
   __DATA__
330 362
 
331
-  @@ twitter.html.ep
363
+  @@ metacpan.html.ep
332 364
   <!DOCTYPE html>
333 365
   <html>
334
-    <head><title>Twitter results for "perl"</title></head>
366
+    <head><title>MetaCPAN results for "mojolicious"</title></head>
335 367
     <body>
336
-      % for my $result (@$results) {
337
-        <p><%= $result->{text} %></p>
368
+      % for my $hit (@$hits) {
369
+        <p><%= $hit->{_source}{release} %></p>
338 370
       % }
339 371
     </body>
340 372
   </html>
341 373
 
342
-Multiple events such as parallel requests can be easily synchronized with a
343
-L<Mojo::IOLoop> delay.
374
+Multiple events such as parallel requests can be easily synchronized with
375
+L<Mojo::IOLoop/"delay">.
344 376
 
345 377
   use Mojolicious::Lite;
346 378
   use Mojo::IOLoop;
347 379
   use Mojo::URL;
348 380
 
349
-  # Search Twitter for "perl" and "python"
381
+  # Search MetaCPAN for "mojo" and "mango"
350 382
   get '/' => sub {
351 383
     my $self = shift;
352 384
 
... ...
@@ -356,17 +388,18 @@ L<Mojo::IOLoop> delay.
356 388
       # Parallel requests
357 389
       sub {
358 390
         my $delay = shift;
359
-        my $url   = Mojo::URL->new('http://search.twitter.com/search.json');
360
-        $self->ua->get($url->clone->query({q => 'perl'})   => $delay->begin);
361
-        $self->ua->get($url->clone->query({q => 'python'}) => $delay->begin);
391
+        my $url   = Mojo::URL->new('api.metacpan.org/v0/module/_search');
392
+        $url->query({sort => 'date:desc'});
393
+        $self->ua->get($url->clone->query({q => 'mojo'})  => $delay->begin);
394
+        $self->ua->get($url->clone->query({q => 'mango'}) => $delay->begin);
362 395
       },
363 396
 
364 397
       # Delayed rendering
365 398
       sub {
366
-        my ($delay, $perl, $python) = @_;
399
+        my ($delay, $mojo, $mango) = @_;
367 400
         $self->render(json => {
368
-          perl   => $perl->res->json('/results/0/text'),
369
-          python => $python->res->json('/results/0/text')
401
+          mojo  => $mojo->res->json('/hits/hits/0/_source/release'),
402
+          mango => $mango->res->json('/hits/hits/0/_source/release')
370 403
         });
371 404
       }
372 405
     );
... ...
@@ -543,11 +576,11 @@ L<Test::Mojo> API to be used.
543 576
 
544 577
 =head2 EventSource web service
545 578
 
546
-EventSource is a special form of long-polling where you can directly send DOM
547
-events from servers to clients. It is uni-directional, that means you will
548
-have to use Ajax requests for sending data from clients to servers, the
549
-advantage however is low infrastructure requirements, since it reuses the HTTP
550
-protocol for transport.
579
+EventSource is a special form of long-polling where you can use
580
+L<Mojolicious::Controller/"write"> to directly send DOM events from servers to
581
+clients. It is uni-directional, that means you will have to use Ajax requests
582
+for sending data from clients to servers, the advantage however is low
583
+infrastructure requirements, since it reuses the HTTP protocol for transport.
551 584
 
552 585
   use Mojolicious::Lite;
553 586
   use Mojo::IOLoop;
... ...
@@ -666,27 +699,7 @@ which can be combined to solve some of hardest problems in web development.
666 699
 
667 700
 Internally the L<Mojo::IOLoop> event loop can use multiple reactor backends,
668 701
 L<EV> for example will be automatically used if installed. Which in turn
669
-allows other event loops like L<IO::Async> to just work.
670
-
671
-  use Mojolicious::Lite;
672
-  use EV;
673
-  use IO::Async::Loop::EV;
674
-  use IO::Async::Timer::Absolute;
675
-
676
-  my $loop = IO::Async::Loop::EV->new;
677
-
678
-  # Wait 3 seconds before rendering a response
679
-  get '/' => sub {
680
-    my $self = shift;
681
-    $loop->add(IO::Async::Timer::Absolute->new(
682
-      time      => time + 3,
683
-      on_expire => sub { $self->render(text => 'Delayed by 3 seconds!') }
684
-    ));
685
-  };
686
-
687
-  app->start;
688
-
689
-Same for L<AnyEvent>.
702
+allows other event loops like L<AnyEvent> to just work.
690 703
 
691 704
   use Mojolicious::Lite;
692 705
   use EV;
... ...
@@ -710,12 +723,12 @@ Who actually controls the event loop backend is not important.
710 723
   use EV;
711 724
   use AnyEvent;
712 725
 
713
-  # Search Twitter for "perl"
726
+  # Search MetaCPAN for "mojolicious"
714 727
   my $cv = AE::cv;
715 728
   my $ua = Mojo::UserAgent->new;
716
-  $ua->get('http://search.twitter.com/search.json?q=perl' => sub {
729
+  $ua->get('api.metacpan.org/v0/module/_search?q=mojolicious' => sub {
717 730
     my ($ua, $tx) = @_;
718
-    $cv->send($tx->res->json('/results/0/text'));
731
+    $cv->send($tx->res->json('/hits/hits/0/_source/release'));
719 732
   });
720 733
   say $cv->recv;
721 734
 
... ...
@@ -745,8 +758,10 @@ When we say L<Mojolicious> is a web framework we actually mean it.
745 758
 =head2 Web scraping
746 759
 
747 760
 Scraping information from web sites has never been this much fun before. The
748
-built-in HTML/XML parser L<Mojo::DOM> supports all CSS selectors that make
749
-sense for a standalone parser.
761
+built-in HTML/XML parser L<Mojo::DOM> is accessible through
762
+L<Mojo::Message/"dom"> and supports all CSS selectors that make sense for a
763
+standalone parser, it can be a very powerful tool especially for unit testing
764
+web application.
750 765
 
751 766
   use Mojo::UserAgent;
752 767
 
... ...
@@ -776,33 +791,26 @@ sense for a standalone parser.
776 791
     print $e->text_after(0) unless $e->next;
777 792
   }
778 793
 
779
-Especially for unit testing your L<Mojolicious> applications this can be a
780
-very powerful tool.
794
+For a full list of available CSS selectors see L<Mojo::DOM::CSS/"SELECTORS">.
781 795
 
782 796
 =head2 JSON web services
783 797
 
784 798
 Most web services these days are based on the JSON data-interchange format.
785 799
 That's why L<Mojolicious> comes with the possibly fastest pure-Perl
786
-implementation L<Mojo::JSON> built right in.
800
+implementation L<Mojo::JSON> built right in, it is accessible through
801
+L<Mojo::Message/"json">.
787 802
 
788 803
   use Mojo::UserAgent;
789
-  use Mojo::Util 'encode';
804
+  use Mojo::URL;
790 805
 
791 806
   # Fresh user agent
792 807
   my $ua = Mojo::UserAgent->new;
793 808
 
794
-  # Fetch the latest news about Mojolicious from Twitter
795
-  my $search = 'http://search.twitter.com/search.json?q=Mojolicious';
796
-  for $tweet (@{$ua->get($search)->res->json->{results}}) {
797
-
798
-    # Tweet text
799
-    my $text = $tweet->{text};
800
-
801
-    # Twitter user
802
-    my $user = $tweet->{from_user};
803
-
804
-    # Show both
805
-    say encode('UTF-8', "$text --$user");
809
+  # Search MetaCPAN for "mojolicious" and list latest releases
810
+  my $url = Mojo::URL->new('http://api.metacpan.org/v0/release/_search');
811
+  $url->query({q => 'mojolicious', sort => 'date:desc'});
812
+  for my $hit (@{$ua->get($url)->res->json->{hits}{hits}}) {
813
+    say "$hit->{_source}{name} ($hit->{_source}{author})";
806 814
   }
807 815
 
808 816
 =head2 Basic authentication
... ...
@@ -840,7 +848,9 @@ This even works for proxy C<CONNECT> requests.
840 848
 
841 849
 =head2 Content generators
842 850
 
843
-Generate the same type of content repeatedly for multiple requests.
851
+Content generators can be registered with
852
+L<Mojo::UserAgent::Transactor/"add_generator"> to generate the same type of
853
+content repeatedly for multiple requests.
844 854
 
845 855
   use Mojo::UserAgent;
846 856
   use Mojo::Asset::File;
... ...
@@ -860,20 +870,58 @@ The C<json> and C<form> content generators are always available.
860 870
 
861 871
   use Mojo::UserAgent;
862 872
 
863
-  # Send JSON content via PATCH
873
+  # Send "application/json" content via PATCH
864 874
   my $ua = Mojo::UserAgent->new;
865 875
   my $tx = $ua->patch('http://api.example.com' => json => {foo => 'bar'});
866 876
 
877
+  # Send query parameters via GET
878
+  my $tx2 = $ua->get('http://search.example.com' => form => {q => 'test'});
879
+
867 880
   # Send "application/x-www-form-urlencoded" content via POST
868
-  my $tx2 = $ua->post('http://search.example.com' => form => {q => 'test'});
881
+  my $tx3 = $ua->post('http://search.example.com' => form => {q => 'test'});
869 882
 
870 883
   # Send "multipart/form-data" content via PUT
871
-  my $tx3 = $ua->put('http://upload.example.com' =>
884
+  my $tx4 = $ua->put('http://upload.example.com' =>
872 885
     form => {test => {content => 'Hello World!'}});
873 886
 
874 887
 For more information about available content generators see also
875 888
 L<Mojo::UserAgent::Transactor/"tx">.
876 889
 
890
+=head2 Large file downloads
891
+
892
+When downloading large files with L<Mojo::UserAgent> you don't have to worry
893
+about memory usage at all, because it will automatically stream everything
894
+above C<250KB> into a temporary file, which can then be moved into a permanent
895
+file with L<Mojo::Asset::File/"move_to">.
896
+
897
+  use Mojo::UserAgent;
898
+
899
+  # Lets fetch the latest Mojolicious tarball
900
+  my $ua = Mojo::UserAgent->new(max_redirects => 5);
901
+  my $tx = $ua->get('latest.mojolicio.us');
902
+  $tx->res->content->asset->move_to('mojo.tar.gz');
903
+
904
+To protect you from excessively large files there is also a limit of C<10MB>
905
+by default, which you can tweak with the MOJO_MAX_MESSAGE_SIZE environment
906
+variable.
907
+
908
+  # Increase limit to 1GB
909
+  $ENV{MOJO_MAX_MESSAGE_SIZE} = 1073741824;
910
+
911
+=head2 Large file upload
912
+
913
+Uploading a large file is even easier.
914
+
915
+  use Mojo::UserAgent;
916
+
917
+  # Upload file via POST and "multipart/form-data"
918
+  my $ua = Mojo::UserAgent->new;
919
+  $ua->post('example.com/upload' =>
920
+    form => {image => {file => '/home/sri/hello.png'}});
921
+
922
+And once again you don't have to worry about memory usage, all data will be
923
+streamed directly from the file.
924
+
877 925
 =head2 Streaming response
878 926
 
879 927
 Receiving a streaming response can be really tricky in most HTTP clients, but
... ...
@@ -885,6 +933,9 @@ L<Mojo::UserAgent> makes it actually easy.
885 933
   my $ua = Mojo::UserAgent->new;
886 934
   my $tx = $ua->build_tx(GET => 'http://example.com');
887 935
 
936
+  # Accept response of indefinite size
937
+  $tx->res->max_message_size(0);
938
+
888 939
   # Replace "read" events to disable default content parser
889 940
   $tx->res->content->unsubscribe('read')->on(read => sub {
890 941
     my ($content, $bytes) = @_;
... ...
@@ -908,60 +959,26 @@ Sending a streaming request is almost just as easy.
908 959
   my $ua = Mojo::UserAgent->new;
909 960
   my $tx = $ua->build_tx(GET => 'http://example.com');
910 961
 
911
-  # Prepare content
912
-  my $content = 'Hello world!';
913
-  $tx->req->headers->content_length(length $content);
962
+  # Prepare body
963
+  my $body = 'Hello world!';
964
+  $tx->req->headers->content_length(length $body);
914 965
 
915 966
   # Start writing directly with a drain callback
916 967
   my $drain;
917 968
   $drain = sub {
918
-    my $req   = shift;
919
-    my $chunk = substr $content, 0, 1, '';
920
-    $drain    = undef unless length $content;
921
-    $req->write($chunk, $drain);
969
+    my $content = shift;
970
+    my $chunk   = substr $body, 0, 1, '';
971
+    $drain      = undef unless length $body;
972
+    $content->write($chunk, $drain);
922 973
   };
923
-  $tx->req->$drain;
974
+  $tx->req->content->$drain;
924 975
 
925 976
   # Process transaction
926 977
   $ua->start($tx);
927 978
 
928
-The drain callback passed to L<Mojo::Message/"write"> will be invoked whenever
979
+The drain callback passed to L<Mojo::Content/"write"> will be invoked whenever
929 980
 the entire previous chunk has actually been written.
930 981
 
931
-=head2 Large file downloads
932
-
933
-When downloading large files with L<Mojo::UserAgent> you don't have to worry
934
-about memory usage at all, because it will automatically stream everything
935
-above C<250KB> into a temporary file.
936
-
937
-  use Mojo::UserAgent;
938
-
939
-  # Lets fetch the latest Mojolicious tarball
940
-  my $ua = Mojo::UserAgent->new(max_redirects => 5);
941
-  my $tx = $ua->get('latest.mojolicio.us');
942
-  $tx->res->content->asset->move_to('mojo.tar.gz');
943
-
944
-To protect you from excessively large files there is also a limit of C<5MB> by
945
-default, which you can tweak with the MOJO_MAX_MESSAGE_SIZE environment
946
-variable.
947
-
948
-  # Increase limit to 1GB
949
-  $ENV{MOJO_MAX_MESSAGE_SIZE} = 1073741824;
950
-
951
-=head2 Large file upload
952
-
953
-Uploading a large file is even easier.
954
-
955
-  use Mojo::UserAgent;
956
-
957
-  # Upload file via POST and "multipart/form-data"
958
-  my $ua = Mojo::UserAgent->new;
959
-  $ua->post('example.com/upload' =>
960
-    form => {image => {file => '/home/sri/hello.png'}});
961
-
962
-And once again you don't have to worry about memory usage, all data will be
963
-streamed directly from the file.
964
-
965 982
 =head2 Non-blocking
966 983
 
967 984
 L<Mojo::UserAgent> has been designed from the ground up to be non-blocking,
... ...
@@ -974,12 +991,12 @@ can keep many parallel connections active at the same time.
974 991
 
975 992
   # Parallel non-blocking requests
976 993
   my $ua = Mojo::UserAgent->new;
977
-  $ua->get('http://mojolicio.us' => sub {
978
-    my ($ua, $tx) = @_;
994
+  $ua->get('http://metacpan.org/search?q=mojo' => sub {
995
+    my ($ua, $mojo) = @_;
979 996
     ...
980 997
   });
981
-  $ua->get('http://mojolicio.us/perldoc' => sub {
982
-    my ($ua, $tx) = @_;
998
+  $ua->get('http://metacpan.org/search?q=mango' => sub {
999
+    my ($ua, $mango) = @_;
983 1000
     ...
984 1001
   });
985 1002
 
... ...
@@ -990,34 +1007,34 @@ You can take full control of the L<Mojo::IOLoop> event loop.
990 1007
 
991 1008
 =head2 Parallel blocking requests
992 1009
 
993
-You can emulate blocking behavior by using a L<Mojo::IOLoop> delay to
994
-synchronize multiple non-blocking requests. Just be aware that the resulting
995
-transactions will be in random order.
1010
+You can emulate blocking behavior by using L<Mojo::IOLoop/"delay"> to
1011
+synchronize multiple non-blocking requests.
996 1012
 
997 1013
   use Mojo::UserAgent;
998 1014
   use Mojo::IOLoop;
999 1015
 
1000
-  # Synchronize non-blocking requests and capture result
1016
+  # Synchronize non-blocking requests and capture results
1001 1017
   my $ua    = Mojo::UserAgent->new;
1002 1018
   my $delay = Mojo::IOLoop->delay;
1003
-  $ua->get('http://mojolicio.us'         => $delay->begin);
1004
-  $ua->get('http://mojolicio.us/perldoc' => $delay->begin);
1005
-  my ($tx, $tx2) = $delay->wait;
1019
+  $ua->get('http://metacpan.org/search?q=mojo'  => $delay->begin);
1020
+  $ua->get('http://metacpan.org/search?q=mango' => $delay->begin);
1021
+  my ($mojo, $mango) = $delay->wait;
1006 1022
 
1007 1023
 The event L<Mojo::IOLoop::Delay/"finish"> can be used for code that needs to
1008
-be able to work standalone as well as inside L<Mojolicious> applications.
1024
+be able to work standalone as well as inside an already running event loop.
1009 1025
 
1010 1026
   use Mojo::UserAgent;
1011 1027
   use Mojo::IOLoop;
1012 1028
 
1013 1029
   # Synchronize non-blocking requests portably
1014 1030
   my $ua    = Mojo::UserAgent->new;
1015
-  my $delay = Mojo::IOLoop->delay(sub {
1016
-    my ($delay, $tx, $tx2) = @_;
1031
+  my $delay = Mojo::IOLoop->delay;
1032
+  $delay->on(finish => sub {
1033
+    my ($delay, $mojo, $mango) = @_;
1017 1034
     ...
1018 1035
   });
1019
-  $ua->get('http://mojolicio.us'         => $delay->begin);
1020
-  $ua->get('http://mojolicio.us/perldoc' => $delay->begin);
1036
+  $ua->get('http://metacpan.org/search?q=mojo'  => $delay->begin);
1037
+  $ua->get('http://metacpan.org/search?q=mango' => $delay->begin);
1021 1038
   $delay->wait unless Mojo::IOLoop->is_running;
1022 1039
 
1023 1040
 =head2 Command line
... ...
@@ -1052,19 +1069,19 @@ The request can be customized as well.
1052 1069
 
1053 1070
 You can follow redirects and view the headers for all messages.
1054 1071
 
1055
-  $ mojo get -r -v http://reddit.com 'head > title'
1072
+  $ mojo get -r -v http://google.com 'head > title'
1056 1073
 
1057 1074
 Extract just the information you really need from JSON data structures.
1058 1075
 
1059
-  $ mojo get http://search.twitter.com/search.json /error
1076
+  $ mojo get https://api.metacpan.org/v0/author/SRI /name
1060 1077
 
1061 1078
 This can be an invaluable tool for testing your applications.
1062 1079
 
1063 1080
   $ ./myapp.pl get /welcome 'head > title'
1064 1081
 
1065
-=head2 Oneliners
1082
+=head2 One-liners
1066 1083
 
1067
-For quick hacks and especially testing, L<ojo> oneliners are also a great
1084
+For quick hacks and especially testing, L<ojo> one-liners are also a great
1068 1085
 choice.
1069 1086
 
1070 1087
   $ perl -Mojo -E 'say g("mojolicio.us")->dom->html->head->title->text'
... ...
@@ -1097,7 +1114,7 @@ that they will be picked up automatically by the command line interface?
1097 1114
 
1098 1115
   1;
1099 1116
 
1100
-There are many more useful methods and attributes in L<Mojolicious::Command>
1117
+There are many more useful attributes and methods in L<Mojolicious::Command>
1101 1118
 that you can use or overload.
1102 1119
 
1103 1120
   $ mojo spy secret
... ...
@@ -1124,32 +1141,34 @@ namespace.
1124 1141
 
1125 1142
 =head2 Running code against your application
1126 1143
 
1127
-Ever thought about running a quick oneliner against your L<Mojolicious>
1144
+Ever thought about running a quick one-liner against your L<Mojolicious>
1128 1145
 application to test something? Thanks to the C<eval> command you can do just
1129 1146
 that, the application object itself can be accessed via C<app>.
1130 1147
 
1131
-  $ mojo generate lite_app
1148
+  $ mojo generate lite_app myapp.pl
1132 1149
   $ ./myapp.pl eval 'say for @{app->static->paths}'
1133 1150
 
1134
-The C<verbose> option will automatically print the return value to C<STDOUT>.
1151
+The C<verbose> options will automatically print the return value or returned
1152
+data structure to C<STDOUT>.
1135 1153
 
1136 1154
   $ ./myapp.pl eval -v 'app->static->paths->[0]'
1155
+  $ ./myapp.pl eval -V 'app->static->paths'
1137 1156
 
1138 1157
 =head2 Making your application installable
1139 1158
 
1140 1159
 Ever thought about releasing your L<Mojolicious> application to CPAN? It's
1141 1160
 actually much easier than you might think.
1142 1161
 
1143
-  $ mojo generate app
1144
-  $ cd my_mojolicious_app
1145
-  $ mv public lib/MyMojoliciousApp/
1146
-  $ mv templates lib/MyMojoliciousApp/
1162
+  $ mojo generate app MyApp
1163
+  $ cd my_app
1164
+  $ mv public lib/MyApp/
1165
+  $ mv templates lib/MyApp/
1147 1166
 
1148 1167
 The trick is to move the C<public> and C<templates> directories so they can
1149 1168
 get automatically installed with the modules.
1150 1169
 
1151 1170
   # Application
1152
-  package MyMojoliciousApp;
1171
+  package MyApp;
1153 1172
   use Mojo::Base 'Mojolicious';
1154 1173
 
1155 1174
   use File::Basename 'dirname';
... ...
@@ -1162,7 +1181,7 @@ get automatically installed with the modules.
1162 1181
     my $self = shift;
1163 1182
 
1164 1183
     # Switch to installable home directory
1165
-    $self->home->parse(catdir(dirname(__FILE__), 'MyMojoliciousApp'));
1184
+    $self->home->parse(catdir(dirname(__FILE__), 'MyApp'));
1166 1185
 
1167 1186
     # Switch to installable "public" directory
1168 1187
     $self->static->paths->[0] = $self->home->rel_dir('public');
... ...
@@ -1181,7 +1200,7 @@ get automatically installed with the modules.
1181 1200
 That's really everything, now you can package your application like any other
1182 1201
 CPAN module.
1183 1202
 
1184
-  $ ./script/my_mojolicious_app generate makefile
1203
+  $ ./script/my_app generate makefile
1185 1204
   $ perl Makefile.PL
1186 1205
   $ make test
1187 1206
   $ make manifest
... ...
@@ -1190,7 +1209,7 @@ CPAN module.
1190 1209
 And if you have a C<PAUSE> account (which can be requested at
1191 1210
 L<http://pause.perl.org>) even upload it.
1192 1211
 
1193
-  $ mojo cpanify -u USER -p PASS MyMojoliciousApp-0.01.tar.gz
1212
+  $ mojo cpanify -u USER -p PASS MyApp-0.01.tar.gz
1194 1213
 
1195 1214
 =head2 Hello World
1196 1215
 
... ...
@@ -1206,10 +1225,10 @@ rendering kicks in even if no actual code gets executed by the router. The
1206 1225
 renderer just picks up the C<text> value from the stash and generates a
1207 1226
 response.
1208 1227
 
1209
-=head2 Hello World oneliners
1228
+=head2 Hello World one-liners
1210 1229
 
1211 1230
 The C<Hello World> example above can get even a little bit shorter in an
1212
-L<ojo> oneliner.
1231
+L<ojo> one-liner.
1213 1232
 
1214 1233
   $ perl -Mojo -E 'a({text => "Hello World!"})->start' daemon
1215 1234
 
+3 -1
mojo/lib/Mojolicious/Guides/FAQ.pod
... ...
@@ -1,4 +1,6 @@
1 1
 
2
+=encoding utf8
3
+
2 4
 =head1 NAME
3 5
 
4 6
 Mojolicious::Guides::FAQ - Frequently Asked Questions
... ...
@@ -62,7 +64,7 @@ which we already have done in the past.
62 64
 To protect your applications from excessively large requests and responses,
63 65
 our HTTP parser has a cap after which it will automatically stop accepting new
64 66
 data, and in most cases force the connection to be closed. This limit is
65
-around C<5MB> by default, you can use the MOJO_MAX_MESSAGE_SIZE environment
67
+around C<10MB> by default, you can use the MOJO_MAX_MESSAGE_SIZE environment
66 68
 variable to change this value.
67 69
 
68 70
 =head2 What does the error "Maximum line size exceeded" mean?
+6 -5
mojo/lib/Mojolicious/Guides/Growing.pod
... ...
@@ -1,4 +1,6 @@
1 1
 
2
+=encoding utf8
3
+
2 4
 =head1 NAME
3 5
 
4 6
 Mojolicious::Guides::Growing - Growing
... ...
@@ -77,9 +79,8 @@ all session state is kept client-side.
77 79
   |         | <-    200 OK        <- |            |
78 80
   +---------+                        +------------+
79 81
 
80
-While HTTP methods such as C<PUT>, C<GET> and C<DELETE> are not directly part
81
-of REST they go very well with it and are commonly used to manipulate
82
-C<resources>.
82
+While HTTP methods such as PUT, GET and DELETE are not directly part of REST
83
+they go very well with it and are commonly used to manipulate C<resources>.
83 84
 
84 85
 =head2 Sessions
85 86
 
... ...
@@ -163,8 +164,8 @@ organized CPAN distribution to maximize maintainability.
163 164
 
164 165
 Both application skeletons can be automatically generated.
165 166
 
166
-  $ mojo generate lite_app
167
-  $ mojo generate app
167
+  $ mojo generate lite_app myapp.pl
168
+  $ mojo generate app MyApp
168 169
 
169 170
 =head2 Foundation
170 171
 
+201 -20
mojo/lib/Mojolicious/Guides/Rendering.pod
... ...
@@ -167,21 +167,37 @@ There is one big difference though, by calling it manually you can make sure
167 167
 that templates use the current controller object, and not the default
168 168
 controller specified with the attribute L<Mojolicious/"controller_class">.
169 169
 
170
+  $self->render_later;
171
+
172
+You can also disable automatic rendering with the method
173
+L<Mojolicious::Controller/"render_later">, which can be very useful to delay
174
+rendering when a non-blocking operation has to be performed first.
175
+
170 176
 =head2 Rendering templates
171 177
 
172
-The renderer will always try to detect the right template but you can also
173
-use the C<template> stash value to render a specific one.
178
+The renderer will always try to detect the right template, but you can also
179
+use the C<template> stash value to render a specific one. Everything before
180
+the last slash will be interpreted as the subdirectory path in which to find
181
+the template.
174 182
 
175
-  $self->render(template => 'foo/bar');
183
+  # foo/bar/baz.*.*
184
+  $self->render(template => 'foo/bar/baz');
176 185
 
177 186
 Choosing a specific C<format> and C<handler> is just as easy.
178 187
 
179
-  $self->render(template => 'foo/bar', format => 'txt', handler => 'epl');
188
+  # foo/bar/baz.txt.epl
189
+  $self->render(template => 'foo/bar/baz', format => 'txt', handler => 'epl');
180 190
 
181 191
 Because rendering a specific template is the most common task it also has a
182 192
 shortcut.
183 193
 
184
-  $self->render('foo/bar');
194
+  $self->render('foo/bar/baz');
195
+
196
+If you're not sure in advance if a template actually exists, you can also use
197
+the method L<Mojolicious::Controller/"render_maybe"> to try multiple
198
+alternatives.
199
+
200
+  $self->render_maybe('localized/baz') or $self->render('foo/bar/baz');
185 201
 
186 202
 =head2 Rendering inline templates
187 203
 
... ...
@@ -199,7 +215,7 @@ too.
199 215
 Characters can be rendered to bytes with the C<text> stash value, the given
200 216
 content will be automatically encoded to bytes.
201 217
 
202
-  $self->render(text => 'Hello Wörld!');
218
+  $self->render(text => 'I ♥ Mojolicious!');
203 219
 
204 220
 =head2 Rendering data
205 221
 
... ...
@@ -226,7 +242,8 @@ C<partial> stash value.
226 242
 No encoding will be performed, making it easy to reuse the result in other
227 243
 templates or to generate binary data.
228 244
 
229
-  $self->render(data => $self->render('pdf_invoice', partial => 1));
245
+  my $pdf = $self->render('invoice', format => 'pdf', partial => 1);
246
+  $self->render(data => $pdf, format => 'pdf');
230 247
 
231 248
 =head2 Status code
232 249
 
... ...
@@ -239,8 +256,12 @@ Response status codes can be changed with the C<status> stash value.
239 256
 The C<Content-Type> header of the response is actually based on the MIME type
240 257
 mapping of the C<format> stash value.
241 258
 
259
+  # Content-Type: text/plain
242 260
   $self->render(text => 'Hello.', format => 'txt');
243 261
 
262
+  # Content-Type: image/png
263
+  $self->render(data => $bytes, format => 'png');
264
+
244 265
 These mappings can be easily extended or changed with L<Mojolicious/"types">.
245 266
 
246 267
   # Application
... ...
@@ -299,12 +320,14 @@ L<Mojolicious::Controller/"render">.
299 320
 
300 321
 The best possible representation will be automatically selected from the
301 322
 C<Accept> request header, C<format> stash value or C<format> GET/POST
302
-parameter.
323
+parameter and stored in the C<format> stash value. To change MIME type
324
+mappings for the C<Accept> request header or the C<Content-Type> response
325
+header you can use L<Mojolicious/"types">.
303 326
 
304 327
   $self->respond_to(
305 328
     json => {json => {hello => 'world'}},
306 329
     html => sub {
307
-      $self->content_for(head => '<meta name="author" content="sri" />');
330
+      $self->content_for(head => '<meta name="author" content="sri">');
308 331
       $self->render(template => 'hello', message => 'world')
309 332
     }
310 333
   );
... ...
@@ -591,6 +614,135 @@ template with named blocks that child templates can override.
591 614
 
592 615
 This chain could go on and on to allow a very high level of template reuse.
593 616
 
617
+=head2 Form validation
618
+
619
+You can use L<Mojolicious::Controller/"validation"> to validate GET/POST
620
+parameters submitted to your application. All unknown fields will be ignored
621
+by default, so you have to decide which should be required or optional before
622
+you can perform checks on their values. Every check is performed right away,
623
+so you can use the results immediately to build more advanced validation logic
624
+with methods like L<Mojolicious::Validator::Validation/"is_valid">.
625
+
626
+  use Mojolicious::Lite;
627
+
628
+  get '/' => sub {
629
+    my $self = shift;
630
+
631
+    # Check if parameters have been submitted
632
+    my $validation = $self->validation;
633
+    return $self->render unless $validation->has_data;
634
+
635
+    # Validate parameters ("pass_again" depends on "pass")
636
+    $validation->required('user')->size(1, 20)->like(qr/^[e-t]+$/);
637
+    $validation->required('pass_again')->equal_to('pass')
638
+      if $validation->optional('pass')->size(7, 500)->is_valid;
639
+
640
+    # Render confirmation if validation was successful
641
+    $self->render('thanks') unless $validation->has_error;
642
+  } => 'index';
643
+
644
+  app->start;
645
+  __DATA__
646
+
647
+  @@ index.html.ep
648
+  <!DOCTYPE html>
649
+  <html>
650
+    <head>
651
+      %= stylesheet begin
652
+        label.field-with-error { color: #dd7e5e }
653
+        input.field-with-error { background-color: #fd9e7e }
654
+      % end
655
+    </head>
656
+    <body>
657
+      %= form_for index => begin
658
+        %= label_for user => 'Username (required, 1-20 characters, only e-t)'
659
+        <br>
660
+        %= text_field 'user'
661
+        %= submit_button
662
+        <br>
663
+        %= label_for pass => 'Password (optional, 7-500 characters)'
664
+        <br>
665
+        %= password_field 'pass'
666
+        <br>
667
+        %= label_for pass_again => 'Password again (equal to the value above)'
668
+        <br>
669
+        %= password_field 'pass_again'
670
+      % end
671
+    </body>
672
+  </html>
673
+
674
+  @@ thanks.html.ep
675
+  <!DOCTYPE html>
676
+  <html><body>Thank you <%= validation->param('user') %>.</body></html>
677
+
678
+Form elements generated with tag helpers from
679
+L<Mojolicious::Plugin::TagHelpers> will automatically remember their previous
680
+values and add the class C<field-with-error> for fields that failed validation
681
+to make styling with CSS easier.
682
+
683
+  <label class="field-with-error" for="user">
684
+    Username (required, only characters e-t)
685
+  </label>
686
+  <input class="field-with-error" type="text" name="user" value="sri" />
687
+
688
+For a full list of available checks see also
689
+L<Mojolicious::Validator/"CHECKS">.
690
+
691
+=head2 Adding form validation checks
692
+
693
+Validation checks can be registered with L<Mojolicious::Validator/"add_check">
694
+and return a false value if they were successful. A true value may be used to
695
+pass along additional information which can then be retrieved with
696
+L<Mojolicious::Validator::Validation/"error">.
697
+
698
+  use Mojolicious::Lite;
699
+
700
+  # Add "range" check
701
+  app->validator->add_check(range => sub {
702
+    my ($validation, $name, $value, $min, $max) = @_;
703
+    return $value < $min || $value > $max;
704
+  });
705
+
706
+  get '/' => 'form';
707
+
708
+  post '/test' => sub {
709
+    my $self = shift;
710
+
711
+    # Validate parameters with custom check
712
+    my $validation = $self->validation;
713
+    $validation->required('number')->range(3, 23);
714
+
715
+    # Render form again if validation failed
716
+    return $self->render('form') if $validation->has_error;
717
+
718
+    # Prevent double submit with redirect
719
+    $self->flash(number => $validation->param('number'));
720
+    $self->redirect_to('form');
721
+  };
722
+
723
+  app->start;
724
+  __DATA__
725
+
726
+  @@ form.html.ep
727
+  <!DOCTYPE html>
728
+  <html>
729
+    <body>
730
+      % if (my $number = flash 'number') {
731
+        <p>Thanks, the number <%= $number %> was valid.</p>
732
+      % }
733
+      %= form_for test => begin
734
+        % if (my $err = validation->error('number')) {
735
+          <p>
736
+            %= 'Value is required.' if $err->[0] eq 'required'
737
+            %= 'Value needs to be between 3 and 23.' if $err->[0] eq 'range'
738
+          </p>
739
+        % }
740
+        %= text_field 'number'
741
+        %= submit_button
742
+      % end
743
+    </html>
744
+  </html>
745
+
594 746
 =head2 Adding helpers
595 747
 
596 748
 Adding and redefining helpers is very easy, you can use them to do pretty much
... ...
@@ -660,7 +812,8 @@ applications, plugins make that very simple.
660 812
 
661 813
   1;
662 814
 
663
-The C<register> method will be called when you load the plugin.
815
+The C<register> method will be called when you load the plugin and to add your
816
+helper to the application you can use L<Mojolicious/"helper">.
664 817
 
665 818
   use Mojolicious::Lite;
666 819
 
... ...
@@ -800,16 +953,17 @@ C<after_render>.
800 953
   use IO::Compress::Gzip 'gzip';
801 954
 
802 955
   hook after_render => sub {
803
-    my ($self, $output, $format) = @_;
956
+    my ($c, $output, $format) = @_;
804 957
 
805 958
     # Check if "gzip => 1" has been set in the stash
806
-    return unless $self->stash->{gzip};
959
+    return unless $c->stash->{gzip};
807 960
 
808 961
     # Check if user agent accepts GZip compression
809
-    return unless ($self->req->headers->accept_encoding // '') =~ /gzip/i;
962
+    return unless ($c->req->headers->accept_encoding // '') =~ /gzip/i;
963
+    $c->res->headers->append(Vary => 'Accept-Encoding');
810 964
 
811 965
     # Compress content with GZip
812
-    $self->res->headers->content_encoding('gzip');
966
+    $c->res->headers->content_encoding('gzip');
813 967
     gzip $output, \my $compressed;
814 968
     $$output = $compressed;
815 969
   };
... ...
@@ -829,10 +983,10 @@ C<after_render>.
829 983
 =head2 Chunked transfer encoding
830 984
 
831 985
 For very dynamic content you might not know the response content length in
832
-advance, that's where the C<chunked> transfer encoding comes in handy. A
833
-common use would be to send the C<head> section of an HTML document to the
834
-browser in advance and speed up preloading of referenced images and
835
-stylesheets.
986
+advance, that's where the C<chunked> transfer encoding and
987
+L<Mojolicious::Controller/"write_chunk"> come in handy. A common use would be
988
+to send the C<head> section of an HTML document to the browser in advance and
989
+speed up preloading of referenced images and stylesheets.
836 990
 
837 991
   $self->write_chunk('<html><head><title>Example</title></head>' => sub {
838 992
     my $self = shift;
... ...
@@ -856,7 +1010,7 @@ might not work perfectly in all deployment environments.
856 1010
 =head2 Encoding
857 1011
 
858 1012
 Templates stored in files are expected to be C<UTF-8> by default, but that can
859
-be easily changed.
1013
+be easily changed with L<Mojolicious::Renderer/"encoding">.
860 1014
 
861 1015
   # Application
862 1016
   package MyApp;
... ...
@@ -931,7 +1085,8 @@ L<Mojo::Template> contains the whole list of available options.
931 1085
 
932 1086
 Maybe you would prefer a different template system than C<ep>, and there is
933 1087
 not already a plugin on CPAN for your favorite one, all you have to do is add
934
-a new C<handler> when C<register> is called.
1088
+a new C<handler> with L<Mojolicious::Renderer/"add_handler"> when C<register>
1089
+is called.
935 1090
 
936 1091
   package Mojolicious::Plugin::MyRenderer;
937 1092
   use Mojo::Base 'Mojolicious::Plugin';
... ...
@@ -983,6 +1138,32 @@ the renderer provides methods to help you with that.
983 1138
   @@ index.html.mine
984 1139
   ...
985 1140
 
1141
+=head2 Adding a handler to generate binary data
1142
+
1143
+By default the renderer assumes that every C<handler> generates characters
1144
+that need to be automatically encoded, but this can be be easily disabled if
1145
+you're generating bytes instead.
1146
+
1147
+  use Mojolicious::Lite;
1148
+  use Mango::BSON ':bson';
1149
+
1150
+  # Add "bson" handler
1151
+  app->renderer->add_handler(bson => sub {
1152
+    my ($renderer, $c, $output, $options) = @_;
1153
+
1154
+    # Disable automatic encoding
1155
+    delete $options->{encoding};
1156
+
1157
+    # Encode BSON data from stash value
1158
+    $$output = bson_encode delete $c->stash->{bson};
1159
+
1160
+    return 1;
1161
+  });
1162
+
1163
+  get '/' => {bson => {i => '♥ mojolicious'}, handler => 'bson'};
1164
+
1165
+  app->start;
1166
+
986 1167
 =head1 MORE
987 1168
 
988 1169
 You can continue with L<Mojolicious::Guides> now or take a look at the
+130 -40
mojo/lib/Mojolicious/Guides/Routing.pod
... ...
@@ -87,10 +87,12 @@ any time.
87 87
   /sebastian -> /:name -> {name => 'sebastian'}
88 88
   {name => 'sebastian'} -> /:name -> /sebastian
89 89
 
90
+Every placeholder has a name, even if it's just an empty string.
91
+
90 92
 =head2 Generic placeholders
91 93
 
92
-Generic placeholders are the simplest form of placeholders and match all
93
-characters except C</> and C<.>.
94
+Generic placeholders are the simplest form of placeholders, they use a colon
95
+prefix and match all characters except C</> and C<.>.
94 96
 
95 97
   /hello              -> /:name/hello -> undef
96 98
   /sebastian/23/hello -> /:name/hello -> undef
... ...
@@ -109,10 +111,15 @@ surrounding text.
109 111
   /sebastian23hello  -> /(:name)hello -> {name => 'sebastian23'}
110 112
   /sebastian 23hello -> /(:name)hello -> {name => 'sebastian 23'}
111 113
 
114
+The colon prefix is optional for generic placeholders that are surrounded by
115
+parentheses.
116
+
117
+  /i♥mojolicious -> /(one)♥(two) -> {one => 'i', two => 'mojolicious'}
118
+
112 119
 =head2 Relaxed placeholders
113 120
 
114
-Relaxed placeholders are just like generic placeholders, but match all
115
-characters except C</>.
121
+Relaxed placeholders are just like generic placeholders, but use a hash prefix
122
+and match all characters except C</>.
116 123
 
117 124
   /hello              -> /#name/hello -> undef
118 125
   /sebastian/23/hello -> /#name/hello -> undef
... ...
@@ -123,8 +130,8 @@ characters except C</>.
123 130
 
124 131
 =head2 Wildcard placeholders
125 132
 
126
-Wildcard placeholders are just like the two placeholders above, but match
127
-absolutely everything, including C</> and C<.>.
133
+Wildcard placeholders are just like the two placeholders above, but use an
134
+asterisk prefix and match absolutely everything, including C</> and C<.>.
128 135
 
129 136
   /hello              -> /*name/hello -> undef
130 137
   /sebastian/23/hello -> /*name/hello -> {name => 'sebastian/23'}
... ...
@@ -139,8 +146,9 @@ Most commonly used features every L<Mojolicious> developer should know about.
139 146
 
140 147
 =head2 Minimal route
141 148
 
142
-Every L<Mojolicious> application has a router object you can use to generate
143
-route structures, that match in the same order in which they were defined.
149
+The attribute L<Mojolicious/"routes"> contains a router you can use to
150
+generate route structures, they match in the same order in which they were
151
+defined.
144 152
 
145 153
   # Application
146 154
   package MyApp;
... ...
@@ -158,8 +166,8 @@ route structures, that match in the same order in which they were defined.
158 166
 
159 167
   1;
160 168
 
161
-The minimal static route above will load and instantiate the class
162
-C<MyApp::Foo> and call its C<welcome> method.
169
+The minimal route above will load and instantiate the class C<MyApp::Foo> and
170
+call its C<welcome> method.
163 171
 
164 172
   # Controller
165 173
   package MyApp::Foo;
... ...
@@ -359,7 +367,17 @@ separated by other characters than C</>.
359 367
     ->to(controller => 'foo', action => 'bar');
360 368
 
361 369
 Special stash values like C<controller> and C<action> can also be
362
-placeholders, this allows for extremely flexible routes constructs.
370
+placeholders, which is very convenient especially during development, but
371
+should only be used very carefully, because every controller method becomes a
372
+potential route. All uppercase methods as well as those starting with an
373
+underscore are automatically hidden from the router and you can use
374
+L<Mojolicious::Routes/"hide"> to add additional ones.
375
+
376
+  # Hide "create" method in all controllers
377
+  $r->hide('create');
378
+
379
+This has already been done for all attributes and methods from
380
+L<Mojolicious::Controller>.
363 381
 
364 382
 =head2 More restrictive placeholders
365 383
 
... ...
@@ -448,6 +466,9 @@ L<Mojolicious::Controller/"url_for"> for this.
448 466
   # Generate URL "/foo/sebastian" for route "test"
449 467
   my $url = $self->url_for('test', name => 'sebastian');
450 468
 
469
+  # Generate URL "http://127.0.0.1:3000/foo/sebastian" for route "test"
470
+  my $url = $self->url_for('test', name => 'sebastian')->to_abs;
471
+
451 472
 Nameless routes get an automatically generated one assigned that is simply
452 473
 equal to the route itself without non-word characters.
453 474
 
... ...
@@ -489,7 +510,7 @@ methods to pass.
489 510
   $r->route('/bye')->via('GET', 'POST')
490 511
     ->to(controller => 'foo', action => 'bye');
491 512
 
492
-With one small exception, C<HEAD> requests are considered equal to C<GET> and
513
+With one small exception, HEAD requests are considered equal to GET and
493 514
 content will not be sent with the response.
494 515
 
495 516
   # GET /test  -> {controller => 'bar', action => 'test'}
... ...
@@ -500,7 +521,7 @@ content will not be sent with the response.
500 521
 =head2 WebSockets
501 522
 
502 523
 With the method L<Mojolicious::Routes::Route/"websocket"> you can restrict
503
-access to WebSocket handshakes, which are normal C<GET> requests with some
524
+access to WebSocket handshakes, which are normal GET requests with some
504 525
 additional information.
505 526
 
506 527
   # /echo (WebSocket handshake)
... ...
@@ -521,11 +542,16 @@ additional information.
521 542
 
522 543
   1;
523 544
 
545
+The connection gets established when you respond to the WebSocket handshake
546
+request with a C<101> response status, which happens automatically if you
547
+subscribe to an event with L<Mojolicious::Controller/"on"> or send a message
548
+with L<Mojolicious::Controller/"send"> right away.
549
+
524 550
 =head2 Bridges
525 551
 
526
-Bridge routes can be used to share code with multiple nested routes, because
527
-unlike normal nested routes, they always match and result in additional
528
-dispatch cycles.
552
+Bridge routes created with the method L<Mojolicious::Routes::Route/"bridge">
553
+can be used to share code with multiple nested routes, because unlike normal
554
+nested routes, they always match and result in additional dispatch cycles.
529 555
 
530 556
   # /foo     -> undef
531 557
   # /foo/bar -> {controller => 'foo', action => 'baz'}
... ...
@@ -551,11 +577,36 @@ be broken, this makes bridges a very powerful tool for authentication.
551 577
   });
552 578
   $foo->route('/bar')->to(controller => 'foo', action => 'bar');
553 579
 
580
+Broken dispatch chains can be continued by calling the method
581
+L<Mojolicious::Controller/"continue">, this allows for example non-blocking
582
+operations to finish before reaching the next dispatch cycle.
583
+
584
+  # /foo     -> undef
585
+  # /foo/bar -> {cb => sub {...}}
586
+  #          -> {controller => 'foo', action => 'bar'}
587
+  my $foo = $r->bridge('/foo')->to(cb => sub {
588
+    my $self = shift;
589
+
590
+    # Wait 3 seconds and then give visitors a 50% chance to continue
591
+    Mojo::IOLoop->timer(3 => sub {
592
+
593
+      # Loser
594
+      return $self->render(text => 'No luck.') unless int rand 2;
595
+
596
+      # Winner
597
+      $self->continue;
598
+    });
599
+
600
+    return undef;
601
+  });
602
+  $foo->route('/bar')->to(controller => 'foo', action => 'bar');
603
+
554 604
 =head2 More convenient routes
555 605
 
556 606
 From the tutorial you should already know L<Mojolicious::Lite> routes, which
557 607
 are in fact just a small convenience layer around everything described above
558
-and also part of the normal router.
608
+and accessible through methods like L<Mojolicious::Routes::Route/"get"> as
609
+part of the normal router.
559 610
 
560 611
   # POST /foo -> {controller => 'foo', action => 'abc'}
561 612
   $r->post('/foo')->to(controller => 'foo', action => 'abc');
... ...
@@ -570,11 +621,13 @@ and also part of the normal router.
570 621
   # * /yada.json -> {controller => 'foo', action => 'yada', format => 'json'}
571 622
   $r->any('/yada' => [format => [qw(txt json)]])->to('foo#yada');
572 623
 
573
-  # GET /foo/bar  -> {controller => 'foo', action => 'bar'}
574
-  # PUT /foo/baz  -> {controller => 'foo', action => 'baz'}
624
+  # GET   /foo/bar  -> {controller => 'foo', action => 'bar'}
625
+  # PUT   /foo/baz  -> {controller => 'foo', action => 'baz'}
626
+  # PATCH /foo      -> {controller => 'foo', action => 'yada'}
575 627
   my $foo = $r->any('/foo')->to('foo#');
576 628
   $foo->get('/bar')->to('#bar');
577 629
   $foo->put('/baz')->to('#baz');
630
+  $foo->patch->to('#yada');
578 631
 
579 632
 This makes the process of growing your L<Mojolicious::Lite> prototypes into
580 633
 full L<Mojolicious> applications very straightforward.
... ...
@@ -585,7 +638,8 @@ full L<Mojolicious> applications very straightforward.
585 638
     $self->render(text => 'Just like a Mojolicious::Lite action.');
586 639
   });
587 640
 
588
-Even the more abstract concepts are available.
641
+Even the more abstract concepts are available with methods like
642
+L<Mojolicious::Routes::Route/"under">.
589 643
 
590 644
   # GET  /yada
591 645
   # POST /yada
... ...
@@ -602,8 +656,9 @@ Even the more abstract concepts are available.
602 656
 =head2 Hooks
603 657
 
604 658
 Hooks operate outside the routing system and allow you to extend
605
-L<Mojolicious> itself by sharing code with all requests indiscriminately,
606
-which makes them a very powerful tool especially for plugins.
659
+the framework itself by sharing code with all requests indiscriminately
660
+through L<Mojolicious/"hook">, which makes them a very powerful tool
661
+especially for plugins.
607 662
 
608 663
   # Application
609 664
   package MyApp;
... ...
@@ -614,9 +669,9 @@ which makes them a very powerful tool especially for plugins.
614 669
 
615 670
     # Check all requests for a "/test" prefix
616 671
     $self->hook(before_dispatch => sub {
617
-      my $self = shift;
618
-      $self->render(text => 'This request did not reach the router.')
619
-        if $self->req->url->path->contains('/test');
672
+      my $c = shift;
673
+      $c->render(text => 'This request did not reach the router.')
674
+        if $c->req->url->path->contains('/test');
620 675
     });
621 676
 
622 677
     # These will not be reached if the hook above renders a response
... ...
@@ -627,29 +682,53 @@ which makes them a very powerful tool especially for plugins.
627 682
 
628 683
   1;
629 684
 
630
-Post-processing tasks such as setting additional response headers are a very
631
-common use.
685
+Post-processing the response to set additional headers is a very common use.
632 686
 
633 687
   # Make sure static files are cached
634 688
   $self->hook(after_static => sub {
635
-    my $self = shift;
636
-    $self->res->headers->cache_control('max-age=3600, must-revalidate');
689
+    my $c = shift;
690
+    $c->res->headers->cache_control('max-age=3600, must-revalidate');
637 691
   });
638 692
 
639
-Same for monitoring tasks.
693
+Same for pre-processing the request.
694
+
695
+  # Allow "_method" query parameter to override request method
696
+  $self->hook(before_dispatch => sub {
697
+    my $c = shift;
698
+    return unless my $method = $c->req->url->query->param('_method');
699
+    $c->req->method($method);
700
+  });
701
+
702
+Or more advanced extensions to add monitoring to your application.
640 703
 
641 704
   # Forward exceptions to a web service
642 705
   $self->hook(after_dispatch => sub {
643
-    my $self = shift;
644
-    return unless my $e = $self->stash('exception');
645
-    $self->ua->post('https://example.com/bugs' => form => {exception => $e});
706
+    my $c = shift;
707
+    return unless my $e = $c->stash('exception');
708
+    $c->ua->post('https://example.com/bugs' => form => {exception => $e});
646 709
   });
647 710
 
648
-For a full list of available hooks see L<Mojolicious/"hook">.
711
+You can even extend much of the core functionality.
712
+
713
+  # Make controller object available to actions as $_
714
+  $self->hook(around_action => sub {
715
+    my ($next, $c, $action, $last) = @_;
716
+    local $_ = $c;
717
+    return $next->();
718
+  });
719
+
720
+  # Pass route name as argument to actions
721
+  $self->hook(around_action => sub {
722
+    my ($next, $c, $action, $last) = @_;
723
+    return $c->$action($c->current_route);
724
+  });
725
+
726
+For a full list of available hooks see L<Mojolicious/"HOOKS">.
649 727
 
650 728
 =head2 Shortcuts
651 729
 
652
-You can also add your own shortcuts to make route generation more expressive.
730
+You can also add your own shortcuts with L<Mojolicious::Routes/"add_shortcut">
731
+to make route generation more expressive.
653 732
 
654 733
   # Simple "resource" shortcut
655 734
   $r->add_shortcut(resource => sub {
... ...
@@ -664,11 +743,19 @@ You can also add your own shortcuts to make route generation more expressive.
664 743
     # Handle GET requests
665 744
     $resource->get->to('#show')->name("show_$name");
666 745
 
746
+    # Handle OPTIONS requests
747
+    $resource->options(sub {
748
+      my $self = shift;
749
+      $self->res->headers->allow('POST, GET, OPTIONS');
750
+      $self->render(data => '', status => 204);
751
+    });
752
+
667 753
     return $resource;
668 754
   });
669 755
 
670
-  # POST /user -> {controller => 'user', action => 'create'}
671
-  # GET  /user -> {controller => 'user', action => 'show'}
756
+  # POST    /user -> {controller => 'user', action => 'create'}
757
+  # GET     /user -> {controller => 'user', action => 'show'}
758
+  # OPTIONS /user
672 759
   $r->resource('user');
673 760
 
674 761
 Shortcuts can lead to anything, routes, bridges or maybe even both. And watch
... ...
@@ -698,8 +785,9 @@ unescaped and decoded from bytes to characters.
698 785
 =head2 Rearranging routes
699 786
 
700 787
 Until the first request has been handled, all routes can still be moved around
701
-or even removed. Especially for rearranging routes created by plugins this can
702
-be very useful.
788
+or even removed with methods like L<Mojolicious::Routes::Route/"add_child">
789
+and L<Mojolicious::Routes::Route/"remove">. Especially for rearranging routes
790
+created by plugins this can be very useful.
703 791
 
704 792
   # GET /example/show -> {controller => 'example', action => 'show'}
705 793
   my $show = $r->get('/show')->to('example#show');
... ...
@@ -709,6 +797,8 @@ be very useful.
709 797
   $r->get('/secrets/show')->to('secrets#show')->name('show_secrets');
710 798
   $r->find('show_secrets')->remove;
711 799
 
800
+To find routes by their name you can use L<Mojolicious::Routes::Route/"find">.
801
+
712 802
 =head2 Conditions
713 803
 
714 804
 Sometimes you might need a little more power, for example to check the
... ...
@@ -756,7 +846,7 @@ You can also package your conditions as reusable plugins.
756 846
     $app->routes->add_condition(werewolf => sub {
757 847
       my ($route, $c, $captures, $days) = @_;
758 848
 
759
-      # Keep the werewolfs out!
849
+      # Keep the werewolves out!
760 850
       return undef if abs(14 - (phase(time))[2]) > ($days / 2);
761 851
 
762 852
       # It's ok, no werewolf
+80 -36
mojo/lib/Mojolicious/Lite.pm
... ...
@@ -4,7 +4,7 @@ use Mojo::Base 'Mojolicious';
4 4
 # "Bender: Bite my shiny metal ass!"
5 5
 use File::Basename qw(basename dirname);
6 6
 use File::Spec::Functions 'catdir';
7
-use Mojo::UserAgent;
7
+use Mojo::UserAgent::Server;
8 8
 use Mojo::Util 'monkey_patch';
9 9
 
10 10
 sub import {
... ...
@@ -20,17 +20,14 @@ sub import {
20 20
   my $caller = caller;
21 21
   no strict 'refs';
22 22
   push @{"${caller}::ISA"}, 'Mojo';
23
-  my $app = shift->new;
24 23
 
25 24
   # Generate moniker based on filename
26 25
   my $moniker = basename $ENV{MOJO_EXE};
27 26
   $moniker =~ s/\.(?:pl|pm|t)$//i;
28
-  $app->moniker($moniker);
27
+  my $app = shift->new(moniker => $moniker);
29 28
 
30 29
   # Initialize routes without namespaces
31 30
   my $routes = $app->routes->namespaces([]);
32
-
33
-  # Default static and template class
34 31
   $app->static->classes->[0] = $app->renderer->classes->[0] = $caller;
35 32
 
36 33
   # The Mojolicious::Lite DSL
... ...
@@ -42,8 +39,8 @@ sub import {
42 39
     for qw(new app);
43 40
   monkey_patch $caller, del => sub { $routes->delete(@_) };
44 41
   monkey_patch $caller, group => sub (&) {
45
-    my $old = $root;
46
-    $_[0]->($root = $routes);
42
+    (my $old, $root) = ($root, $routes);
43
+    shift->();
47 44
     ($routes, $root) = ($root, $old);
48 45
   };
49 46
   monkey_patch $caller,
... ...
@@ -53,7 +50,7 @@ sub import {
53 50
     under  => sub { $routes = $root->under(@_) };
54 51
 
55 52
   # Make sure there's a default application for testing
56
-  Mojo::UserAgent->app($app) unless Mojo::UserAgent->app;
53
+  Mojo::UserAgent::Server->app($app) unless Mojo::UserAgent::Server->app;
57 54
 
58 55
   # Lite apps are strict!
59 56
   Mojo::Base->import(-strict);
... ...
@@ -112,7 +109,7 @@ featured web application.
112 109
 
113 110
 There is also a helper command to generate a small example application.
114 111
 
115
-  $ mojo generate lite_app
112
+  $ mojo generate lite_app myapp.pl
116 113
 
117 114
 =head2 Commands
118 115
 
... ...
@@ -147,6 +144,9 @@ every change.
147 144
   $ morbo myapp.pl
148 145
   Server available at http://127.0.0.1:3000.
149 146
 
147
+For more information about how to deploy your application see also
148
+L<Mojolicious::Guides::Cookbook/"DEPLOYMENT">.
149
+
150 150
 =head2 Routes
151 151
 
152 152
 Routes are basically just fancy paths that can contain different kinds of
... ...
@@ -169,7 +169,7 @@ L<Mojolicious::Controller/"render">, but more about that later.
169 169
 
170 170
 =head2 GET/POST parameters
171 171
 
172
-All C<GET> and C<POST> parameters sent with the request are accessible via
172
+All GET and POST parameters sent with the request are accessible via
173 173
 L<Mojolicious::Controller/"param">.
174 174
 
175 175
   use Mojolicious::Lite;
... ...
@@ -213,15 +213,21 @@ full access to all HTTP features and information.
213 213
 
214 214
   use Mojolicious::Lite;
215 215
 
216
-  # Access request and reponse information
216
+  # Access request information
217 217
   get '/agent' => sub {
218 218
     my $self = shift;
219 219
     my $host = $self->req->url->to_abs->host;
220 220
     my $ua   = $self->req->headers->user_agent;
221
-    $self->res->headers->header('X-Bender' => 'Bite my shiny metal ass!');
222 221
     $self->render(text => "Request by $ua reached $host.");
223 222
   };
224 223
 
224
+  # Echo the request body and send custom header with response
225
+  get '/echo' => sub {
226
+    my $self = shift;
227
+    $self->res->headers->header('X-Bender' => 'Bite my shiny metal ass!');
228
+    $self->render(data => $self->req->body);
229
+  };
230
+
225 231
   app->start;
226 232
 
227 233
 =head2 Route names
... ...
@@ -280,6 +286,9 @@ L<Mojolicious::Plugin::DefaultHelpers/"content">.
280 286
     <body><%= content %></body>
281 287
   </html>
282 288
 
289
+The stash or helpers like L<Mojolicious::Plugin::DefaultHelpers/"title"> can
290
+be used to pass additional data to the layout.
291
+
283 292
 =head2 Blocks
284 293
 
285 294
 Template blocks can be used like normal Perl functions and are always
... ...
@@ -464,7 +473,8 @@ Routes can be restricted to specific request methods with different keywords.
464 473
 
465 474
 =head2 Optional placeholders
466 475
 
467
-Routes allow default values to make placeholders optional.
476
+All placeholders require a value, but by assigning them default values you can
477
+make capturing optional.
468 478
 
469 479
   use Mojolicious::Lite;
470 480
 
... ...
@@ -520,8 +530,8 @@ is fine though.
520 530
 =head2 Under
521 531
 
522 532
 Authentication and code shared between multiple routes can be realized easily
523
-with bridge routes generated by the C<under> statement. All following routes
524
-are only evaluated if the callback returned a true value.
533
+with bridge routes generated by the L</"under"> statement. All following
534
+routes are only evaluated if the callback returned a true value.
525 535
 
526 536
   use Mojolicious::Lite;
527 537
 
... ...
@@ -550,7 +560,7 @@ are only evaluated if the callback returned a true value.
550 560
   @@ index.html.ep
551 561
   Hi Bender.
552 562
 
553
-Prefixing multiple routes is another good use for C<under>.
563
+Prefixing multiple routes is another good use for L</"under">.
554 564
 
555 565
   use Mojolicious::Lite;
556 566
 
... ...
@@ -564,15 +574,15 @@ Prefixing multiple routes is another good use for C<under>.
564 574
   get '/baz' => {text => 'foo baz'};
565 575
 
566 576
   # / (reset)
567
-  under '/' => {message => 'whatever'};
577
+  under '/' => {msg => 'whatever'};
568 578
 
569 579
   # /bar
570
-  get '/bar' => {inline => '<%= $message %> works'};
580
+  get '/bar' => {inline => '<%= $msg %> works'};
571 581
 
572 582
   app->start;
573 583
 
574
-You can also C<group> related routes, which allows nesting of multiple
575
-C<under> statements.
584
+You can also L</"group"> related routes, which allows nesting of multiple
585
+L</"under"> statements.
576 586
 
577 587
   use Mojolicious::Lite;
578 588
 
... ...
@@ -830,8 +840,8 @@ temporary file.
830 840
     </body>
831 841
   </html>
832 842
 
833
-To protect you from excessively large files there is also a limit of C<5MB> by
834
-default, which you can tweak with the MOJO_MAX_MESSAGE_SIZE environment
843
+To protect you from excessively large files there is also a limit of C<10MB>
844
+by default, which you can tweak with the MOJO_MAX_MESSAGE_SIZE environment
835 845
 variable.
836 846
 
837 847
   # Increase limit to 1GB
... ...
@@ -839,21 +849,51 @@ variable.
839 849
 
840 850
 =head2 User agent
841 851
 
842
-With L<Mojolicious::Controller/"ua"> there's a full featured HTTP and
852
+With L<Mojo::UserAgent>, which is available through the helper
853
+L<Mojolicious::Plugin::DefaultHelpers/"ua">, there's a full featured HTTP and
843 854
 WebSocket user agent built right in. Especially in combination with
844 855
 L<Mojo::JSON> and L<Mojo::DOM> this can be a very powerful tool.
845 856
 
846 857
   use Mojolicious::Lite;
847 858
 
859
+  # Blocking
848 860
   get '/headers' => sub {
849 861
     my $self = shift;
850 862
     my $url  = $self->param('url') || 'http://mojolicio.us';
851 863
     my $dom  = $self->ua->get($url)->res->dom;
852
-    $self->render(json => [$dom->find('h1, h2, h3')->pluck('text')->each]);
864
+    $self->render(json => [$dom->find('h1, h2, h3')->text->each]);
865
+  };
866
+
867
+  # Non-blocking
868
+  get '/title' => sub {
869
+    my $self = shift;
870
+    $self->ua->get('mojolicio.us' => sub {
871
+      my ($ua, $tx) = @_;
872
+      $self->render(data => $tx->res->dom->at('title')->text);
873
+    });
874
+  };
875
+
876
+  # Parallel non-blocking
877
+  get '/titles' => sub {
878
+    my $self = shift;
879
+    my $delay = Mojo::IOLoop->delay(sub {
880
+      my ($delay, @titles) = @_;
881
+      $self->render(json => \@titles);
882
+    });
883
+    for my $url ('http://mojolicio.us', 'https://metacpan.org') {
884
+      my $end = $delay->begin(0);
885
+      $self->ua->get($url => sub {
886
+        my ($ua, $tx) = @_;
887
+        $end->($tx->res->dom->html->head->title->text);
888
+      });
889
+    }
853 890
   };
854 891
 
855 892
   app->start;
856 893
 
894
+For more information about the user agent see also
895
+L<Mojolicious::Guides::Cookbook/"USER AGENT">.
896
+
857 897
 =head2 WebSockets
858 898
 
859 899
 WebSocket applications have never been this simple before. Just receive
... ...
@@ -901,14 +941,18 @@ L<Mojolicious::Guides::Cookbook/"REAL-TIME WEB">.
901 941
 
902 942
 You can use the L<Mojo::Log> object from L<Mojo/"log"> to portably collect
903 943
 debug messages and automatically disable them later in a production setup by
904
-changing the L<Mojolicious> operating mode.
944
+changing the L<Mojolicious> operating mode, which can also be retrieved from
945
+the attribute L<Mojolicious/"mode">.
905 946
 
906 947
   use Mojolicious::Lite;
907 948
 
949
+  # Prepare mode specific message during startup
950
+  my $msg = app->mode eq 'development' ? 'Development!' : 'Something else!';
951
+
908 952
   get '/' => sub {
909 953
     my $self = shift;
910
-    $self->app->log->debug('Rendering "Hello World!" message.');
911
-    $self->render(text => 'Hello World!');
954
+    $self->app->log->debug('Rendering mode specific message.');
955
+    $self->render(text => $msg);
912 956
   };
913 957
 
914 958
   app->log->debug('Starting application.');
... ...
@@ -926,7 +970,7 @@ C<log> directory exists.
926 970
 
927 971
   $ mkdir log
928 972
 
929
-Mode changes also affects a few other aspects of the framework, such as mode
973
+Mode changes also affect a few other aspects of the framework, such as mode
930 974
 specific C<exception> and C<not_found> templates.
931 975
 
932 976
 =head2 Testing
... ...
@@ -980,13 +1024,13 @@ The L<Mojolicious::Lite> application.
980 1024
   my $route = del '/:foo' => sub {...};
981 1025
 
982 1026
 Generate route with L<Mojolicious::Routes::Route/"delete">, matching only
983
-C<DELETE> requests. See also the tutorial above for more argument variations.
1027
+DELETE requests. See also the tutorial above for more argument variations.
984 1028
 
985 1029
 =head2 get
986 1030
 
987 1031
   my $route = get '/:foo' => sub {...};
988 1032
 
989
-Generate route with L<Mojolicious::Routes::Route/"get">, matching only C<GET>
1033
+Generate route with L<Mojolicious::Routes::Route/"get">, matching only GET
990 1034
 requests. See also the tutorial above for more argument variations.
991 1035
 
992 1036
 =head2 group
... ...
@@ -1012,7 +1056,7 @@ Share code with L<Mojolicious/"hook">.
1012 1056
   my $route = options '/:foo' => sub {...};
1013 1057
 
1014 1058
 Generate route with L<Mojolicious::Routes::Route/"options">, matching only
1015
-C<OPTIONS> requests. See also the tutorial above for more argument
1059
+OPTIONS requests. See also the tutorial above for more argument
1016 1060
 variations.
1017 1061
 
1018 1062
 =head2 patch
... ...
@@ -1020,7 +1064,7 @@ variations.
1020 1064
   my $route = patch '/:foo' => sub {...};
1021 1065
 
1022 1066
 Generate route with L<Mojolicious::Routes::Route/"patch">, matching only
1023
-C<PATCH> requests. See also the tutorial above for more argument variations.
1067
+PATCH requests. See also the tutorial above for more argument variations.
1024 1068
 
1025 1069
 =head2 plugin
1026 1070
 
... ...
@@ -1033,19 +1077,19 @@ Load a plugin with L<Mojolicious/"plugin">.
1033 1077
   my $route = post '/:foo' => sub {...};
1034 1078
 
1035 1079
 Generate route with L<Mojolicious::Routes::Route/"post">, matching only
1036
-C<POST> requests. See also the tutorial above for more argument variations.
1080
+POST requests. See also the tutorial above for more argument variations.
1037 1081
 
1038 1082
 =head2 put
1039 1083
 
1040 1084
   my $route = put '/:foo' => sub {...};
1041 1085
 
1042
-Generate route with L<Mojolicious::Routes::Route/"put">, matching only C<PUT>
1086
+Generate route with L<Mojolicious::Routes::Route/"put">, matching only PUT
1043 1087
 requests. See also the tutorial above for more argument variations.
1044 1088
 
1045 1089
 =head2 under
1046 1090
 
1047
-  my $route = under sub {...};
1048
-  my $route = under '/:foo';
1091
+  my $bridge = under sub {...};
1092
+  my $bridge = under '/:foo';
1049 1093
 
1050 1094
 Generate bridge route with L<Mojolicious::Routes::Route/"under">, to which all
1051 1095
 following routes are automatically appended. See also the tutorial above for
+3 -1
mojo/lib/Mojolicious/Plugin.pm
... ...
@@ -7,13 +7,15 @@ sub register { croak 'Method "register" not implemented by subclass' }
7 7
 
8 8
 1;
9 9
 
10
+=encoding utf8
11
+
10 12
 =head1 NAME
11 13
 
12 14
 Mojolicious::Plugin - Plugin base class
13 15
 
14 16
 =head1 SYNOPSIS
15 17
 
16
-  # Camel case plugin name
18
+  # CamelCase plugin name
17 19
   package Mojolicious::Plugin::MyPlugin;
18 20
   use Mojo::Base 'Mojolicious::Plugin';
19 21
 
+4 -2
mojo/lib/Mojolicious/Plugin/Charset.pm
... ...
@@ -13,6 +13,8 @@ sub register {
13 13
 
14 14
 1;
15 15
 
16
+=encoding utf8
17
+
16 18
 =head1 NAME
17 19
 
18 20
 Mojolicious::Plugin::Charset - Charset plugin
... ...
@@ -53,8 +55,8 @@ L<Mojolicious::Plugin> and implements the following new ones.
53 55
 
54 56
   $plugin->register(Mojolicious->new, {charset => 'Shift_JIS'});
55 57
 
56
-Register C<before_dispatch> hook in L<Mojolicious> application and change a
57
-few defaults.
58
+Register hook L<Mojolicious/"before_dispatch"> in application and change a few
59
+defaults.
58 60
 
59 61
 =head1 SEE ALSO
60 62
 
+6 -3
mojo/lib/Mojolicious/Plugin/Config.pm
... ...
@@ -14,8 +14,9 @@ sub parse {
14 14
   my ($self, $content, $file, $conf, $app) = @_;
15 15
 
16 16
   # Run Perl code
17
-  my $config = eval 'package Mojolicious::Plugin::Config::Sandbox;'
18
-    . "no warnings; sub app { \$app }; use Mojo::Base -strict; $content";
17
+  my $config
18
+    = eval 'package Mojolicious::Plugin::Config::Sandbox; no warnings;'
19
+    . "sub app; local *app = sub { \$app }; use Mojo::Base -strict; $content";
19 20
   die qq{Couldn't load configuration from file "$file": $@} if !$config && $@;
20 21
   die qq{Config file "$file" did not return a hash reference.\n}
21 22
     unless ref $config eq 'HASH';
... ...
@@ -58,6 +59,8 @@ sub register {
58 59
 
59 60
 1;
60 61
 
62
+=encoding utf8
63
+
61 64
 =head1 NAME
62 65
 
63 66
 Mojolicious::Plugin::Config - Perl-ish configuration plugin
... ...
@@ -137,7 +140,7 @@ L<Mojolicious::Plugin> and implements the following new ones.
137 140
 
138 141
   $plugin->load($file, $conf, $app);
139 142
 
140
-Loads configuration file and passes the content to C<parse>.
143
+Loads configuration file and passes the content to L</"parse">.
141 144
 
142 145
   sub load {
143 146
     my ($self, $file, $conf, $app) = @_;
+34 -22
mojo/lib/Mojolicious/Plugin/DefaultHelpers.pm
... ...
@@ -1,14 +1,14 @@
1 1
 package Mojolicious::Plugin::DefaultHelpers;
2 2
 use Mojo::Base 'Mojolicious::Plugin';
3 3
 
4
-use Data::Dumper ();
5 4
 use Mojo::ByteStream;
5
+use Mojo::Util 'dumper';
6 6
 
7 7
 sub register {
8 8
   my ($self, $app) = @_;
9 9
 
10 10
   # Controller alias helpers
11
-  for my $name (qw(app flash param stash session url_for)) {
11
+  for my $name (qw(app flash param stash session url_for validation)) {
12 12
     $app->helper($name => sub { shift->$name(@_) });
13 13
   }
14 14
 
... ...
@@ -26,13 +26,13 @@ sub register {
26 26
   }
27 27
 
28 28
   $app->helper(config => sub { shift->app->config(@_) });
29
-
30 29
   $app->helper(content       => \&_content);
31 30
   $app->helper(content_for   => \&_content_for);
32 31
   $app->helper(current_route => \&_current_route);
33
-  $app->helper(dumper        => \&_dumper);
32
+  $app->helper(dumper        => sub { shift; dumper(@_) });
34 33
   $app->helper(include       => \&_include);
35
-  $app->helper(url_with      => \&_url_with);
34
+  $app->helper(ua => sub { shift->app->ua });
35
+  $app->helper(url_with => \&_url_with);
36 36
 }
37 37
 
38 38
 sub _content {
... ...
@@ -41,7 +41,7 @@ sub _content {
41 41
 
42 42
   # Set (first come)
43 43
   my $c = $self->stash->{'mojo.content'} ||= {};
44
-  $c->{$name} ||= ref $content eq 'CODE' ? $content->() : $content
44
+  $c->{$name} = defined $c->{$name} ? $c->{$name} : ref $content eq 'CODE' ? $content->() : $content
45 45
     if defined $content;
46 46
 
47 47
   # Get
... ...
@@ -61,16 +61,10 @@ sub _current_route {
61 61
   return $endpoint->name eq shift;
62 62
 }
63 63
 
64
-sub _dumper {
65
-  my $self = shift;
66
-  return Data::Dumper->new([@_])->Indent(1)->Sortkeys(1)->Terse(1)->Dump;
67
-}
68
-
69 64
 sub _include {
70 65
   my $self     = shift;
71 66
   my $template = @_ % 2 ? shift : undef;
72
-  my $args     = {@_};
73
-  $args->{template} = $template if defined $template;
67
+  my $args     = {@_, defined $template ? (template => $template) : ()};
74 68
 
75 69
   # "layout" and "extends" can't be localized
76 70
   my $layout  = delete $args->{layout};
... ...
@@ -80,7 +74,7 @@ sub _include {
80 74
   my @keys = keys %$args;
81 75
   local @{$self->stash}{@keys} = @{$args}{@keys};
82 76
 
83
-  return $self->render(partial => 1, layout => $layout, extend => $extends);
77
+  return $self->render(partial => 1, layout => $layout, extends => $extends);
84 78
 }
85 79
 
86 80
 sub _url_with {
... ...
@@ -90,6 +84,8 @@ sub _url_with {
90 84
 
91 85
 1;
92 86
 
87
+=encoding utf8
88
+
93 89
 =head1 NAME
94 90
 
95 91
 Mojolicious::Plugin::DefaultHelpers - Default helpers plugin
... ...
@@ -136,7 +132,10 @@ Alias for L<Mojo/"config">.
136 132
   %= content 'bar'
137 133
   %= content
138 134
 
139
-Store partial rendered content in named buffer and retrieve it.
135
+Store partial rendered content in named buffer and retrieve it, defaults to
136
+retrieving the named buffer C<content>, which is commonly used for the
137
+renderers C<layout> and C<extends> features. Note that new content will be
138
+ignored if the named buffer is already in use.
140 139
 
141 140
 =head2 content_for
142 141
 
... ...
@@ -145,7 +144,8 @@ Store partial rendered content in named buffer and retrieve it.
145 144
   % end
146 145
   %= content_for 'foo'
147 146
 
148
-Append partial rendered content to named buffer and retrieve it.
147
+Append partial rendered content to named buffer and retrieve it. Note that
148
+named buffers are shared with the L</"content"> helper.
149 149
 
150 150
   % content_for message => begin
151 151
     Hello
... ...
@@ -168,14 +168,14 @@ Check or get name of current route.
168 168
 
169 169
   %= dumper {some => 'data'}
170 170
 
171
-Dump a Perl data structure with L<Data::Dumper>.
171
+Dump a Perl data structure with L<Mojo::Util/"dumper">.
172 172
 
173 173
 =head2 extends
174 174
 
175 175
   % extends 'blue';
176 176
   % extends 'blue', title => 'Blue!';
177 177
 
178
-Extend a template. All additional values get merged into the C<stash>.
178
+Extend a template. All additional values get merged into the L</"stash">.
179 179
 
180 180
 =head2 flash
181 181
 
... ...
@@ -197,7 +197,7 @@ only available in the partial template.
197 197
   % layout 'green', title => 'Green!';
198 198
 
199 199
 Render this template with a layout. All additional values get merged into the
200
-C<stash>.
200
+L</"stash">.
201 201
 
202 202
 =head2 param
203 203
 
... ...
@@ -218,7 +218,7 @@ Alias for L<Mojolicious::Controller/"session">.
218 218
 
219 219
 Alias for L<Mojolicious::Controller/"stash">.
220 220
 
221
-  %= stash 'name' // 'Somebody'
221
+  %= stash('name') // 'Somebody'
222 222
 
223 223
 =head2 title
224 224
 
... ...
@@ -226,7 +226,13 @@ Alias for L<Mojolicious::Controller/"stash">.
226 226
   % title 'Welcome!', foo => 'bar';
227 227
   %= title
228 228
 
229
-Page title. All additional values get merged into the C<stash>.
229
+Page title. All additional values get merged into the L</"stash">.
230
+
231
+=head2 ua
232
+
233
+  %= ua->get('mojolicio.us')->res->dom->at('title')->text
234
+
235
+Alias for L<Mojo/"ua">.
230 236
 
231 237
 =head2 url_for
232 238
 
... ...
@@ -238,11 +244,17 @@ Alias for L<Mojolicious::Controller/"url_for">.
238 244
 
239 245
   %= url_with 'named', controller => 'bar', action => 'baz'
240 246
 
241
-Does the same as C<url_for>, but inherits query parameters from the current
247
+Does the same as L</"url_for">, but inherits query parameters from the current
242 248
 request.
243 249
 
244 250
   %= url_with->query([page => 2])
245 251
 
252
+=head2 validation
253
+
254
+  %= validation->param('foo')
255
+
256
+Alias for L<Mojolicious::Controller/"validation">.
257
+
246 258
 =head1 METHODS
247 259
 
248 260
 L<Mojolicious::Plugin::DefaultHelpers> inherits all methods from
+2
mojo/lib/Mojolicious/Plugin/EPLRenderer.pm
... ...
@@ -64,6 +64,8 @@ sub _epl {
64 64
 
65 65
 1;
66 66
 
67
+=encoding utf8
68
+
67 69
 =head1 NAME
68 70
 
69 71
 Mojolicious::Plugin::EPLRenderer - Embedded Perl Lite renderer plugin
+28 -22
mojo/lib/Mojolicious/Plugin/EPRenderer.pm
... ...
@@ -2,8 +2,7 @@ package Mojolicious::Plugin::EPRenderer;
2 2
 use Mojo::Base 'Mojolicious::Plugin';
3 3
 
4 4
 use Mojo::Template;
5
-use Mojo::Util qw(encode md5_sum);
6
-use Scalar::Util ();
5
+use Mojo::Util qw(encode md5_sum monkey_patch);
7 6
 
8 7
 sub register {
9 8
   my ($self, $app, $conf) = @_;
... ...
@@ -19,43 +18,50 @@ sub register {
19 18
       # Generate name
20 19
       my $path = $options->{inline} || $renderer->template_path($options);
21 20
       return undef unless defined $path;
22
-      my $id = encode 'UTF-8', join(', ', $path, sort keys %{$c->stash});
21
+      my @keys = sort grep {/^\w+$/} keys %{$c->stash};
22
+      my $id = encode 'UTF-8', join(',', $path, @keys);
23 23
       my $key = $options->{cache} = md5_sum $id;
24 24
 
25
-      # Compile helpers and stash values
25
+      # Cache template for "epl" handler
26 26
       my $cache = $renderer->cache;
27
-      unless ($cache->get($key)) {
28
-        my $mt = Mojo::Template->new($template);
27
+      my $mt    = $cache->get($key);
28
+      unless ($mt) {
29
+        $mt = Mojo::Template->new($template);
29 30
 
30
-        # Be a bit more relaxed for helpers
31
-        my $prepend = 'my $self = shift; Scalar::Util::weaken $self;'
32
-          . q[no strict 'refs'; no warnings 'redefine';];
31
+        # Helpers (only once)
32
+        ++$self->{helpers} and _helpers($mt->namespace, $renderer->helpers)
33
+          unless $self->{helpers};
33 34
 
34
-        # Helpers
35
-        $prepend .= 'my $_H = $self->app->renderer->helpers;';
36
-        $prepend .= "sub $_; *$_ = sub { \$_H->{'$_'}->(\$self, \@_) };"
37
-          for grep {/^\w+$/} keys %{$renderer->helpers};
35
+        # Stash values (every time)
36
+        my $prepend = 'my $self = shift; my $_S = $self->stash;';
37
+        $prepend .= " my \$$_ = \$_S->{'$_'};" for @keys;
38 38
 
39
-        # Be less relaxed for everything else
40
-        $prepend .= 'use strict;';
41
-
42
-        # Stash values
43
-        $prepend .= 'my $_S = $self->stash;';
44
-        $prepend .= " my \$$_ = \$_S->{'$_'};"
45
-          for grep {/^\w+$/} keys %{$c->stash};
46
-
47
-        # Cache
48 39
         $cache->set($key => $mt->prepend($prepend . $mt->prepend));
49 40
       }
50 41
 
42
+      # Make current controller available
43
+      no strict 'refs';
44
+      no warnings 'redefine';
45
+      local *{"@{[$mt->namespace]}::_C"} = sub {$c};
46
+
51 47
       # Render with "epl" handler
52 48
       return $renderer->handlers->{epl}->($renderer, $c, $output, $options);
53 49
     }
54 50
   );
55 51
 }
56 52
 
53
+sub _helpers {
54
+  my ($namespace, $helpers) = @_;
55
+  for my $name (grep {/^\w+$/} keys %$helpers) {
56
+    monkey_patch $namespace, $name,
57
+      sub { $helpers->{$name}->($namespace->_C, @_) };
58
+  }
59
+}
60
+
57 61
 1;
58 62
 
63
+=encoding utf8
64
+
59 65
 =head1 NAME
60 66
 
61 67
 Mojolicious::Plugin::EPRenderer - Embedded Perl renderer plugin
+3 -1
mojo/lib/Mojolicious/Plugin/HeaderCondition.pm
... ...
@@ -15,7 +15,7 @@ sub _check {
15 15
   my ($value, $pattern) = @_;
16 16
   return 1
17 17
     if $value && $pattern && ref $pattern eq 'Regexp' && $value =~ $pattern;
18
-  return $value && defined $pattern && $pattern eq $value ? 1 : undef;
18
+  return $value && defined $pattern && $pattern eq $value;
19 19
 }
20 20
 
21 21
 sub _headers {
... ...
@@ -32,6 +32,8 @@ sub _headers {
32 32
 
33 33
 1;
34 34
 
35
+=encoding utf8
36
+
35 37
 =head1 NAME
36 38
 
37 39
 Mojolicious::Plugin::HeaderCondition - Header condition plugin
+4 -2
mojo/lib/Mojolicious/Plugin/JSONConfig.pm
... ...
@@ -24,7 +24,7 @@ sub render {
24 24
 
25 25
   # Application instance and helper
26 26
   my $prepend = q[my $app = shift; no strict 'refs'; no warnings 'redefine';];
27
-  $prepend .= q[sub app; *app = sub { $app }; use Mojo::Base -strict;];
27
+  $prepend .= q[sub app; local *app = sub { $app }; use Mojo::Base -strict;];
28 28
 
29 29
   # Render and encode for JSON decoding
30 30
   my $mt = Mojo::Template->new($conf->{template} || {})->name($file);
... ...
@@ -34,6 +34,8 @@ sub render {
34 34
 
35 35
 1;
36 36
 
37
+=encoding utf8
38
+
37 39
 =head1 NAME
38 40
 
39 41
 Mojolicious::Plugin::JSONConfig - JSON configuration plugin
... ...
@@ -99,7 +101,7 @@ L<Mojolicious::Plugin::Config> and implements the following new ones.
99 101
 
100 102
   $plugin->parse($content, $file, $conf, $app);
101 103
 
102
-Process content with C<render> and parse it with L<Mojo::JSON>.
104
+Process content with L</"render"> and parse it with L<Mojo::JSON>.
103 105
 
104 106
   sub parse {
105 107
     my ($self, $content, $file, $conf, $app) = @_;
+2
mojo/lib/Mojolicious/Plugin/Mount.pm
... ...
@@ -24,6 +24,8 @@ sub register {
24 24
 
25 25
 1;
26 26
 
27
+=encoding utf8
28
+
27 29
 =head1 NAME
28 30
 
29 31
 Mojolicious::Plugin::Mount - Application mount plugin
+53 -60
mojo/lib/Mojolicious/Plugin/PODRenderer.pm
... ...
@@ -4,13 +4,11 @@ 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 qw'slurp url_escape';
7
+use Mojo::URL;
8
+use Mojo::Util qw(slurp url_escape);
8 9
 BEGIN {eval {require Pod::Simple::HTML; import Pod::Simple::HTML}}
9 10
 BEGIN {eval {require Pod::Simple::Search; import Pod::Simple::Search}}
10 11
 
11
-# Paths to search
12
-my @PATHS = map { $_, "$_/pods" } @INC;
13
-
14 12
 sub register {
15 13
   my ($self, $app, $conf) = @_;
16 14
 
... ...
@@ -30,71 +28,50 @@ sub register {
30 28
   $app->helper(pod_to_html => sub { shift; b(_pod_to_html(@_)) });
31 29
 
32 30
   # Perldoc browser
33
-  return if $conf->{no_perldoc};
31
+  return undef if $conf->{no_perldoc};
32
+  my $defaults = {module => 'Mojolicious/Guides', format => 'html'};
34 33
   return $app->routes->any(
35
-    '/perldoc/*module' => {module => 'Mojolicious/Guides'} => \&_perldoc);
34
+    '/perldoc/:module' => $defaults => [module => qr/[^.]+/] => \&_perldoc);
36 35
 }
37 36
 
38
-sub _perldoc {
39
-  my $self = shift;
40
-
41
-  # Find module or redirect to CPAN
42
-  my $module = $self->param('module');
43
-  $module =~ s!/!::!g;
44
-  my $path = Pod::Simple::Search->new->find($module, @PATHS);
45
-  return $self->redirect_to("http://metacpan.org/module/$module")
46
-    unless $path && -r $path;
47
-  my $html = _pod_to_html(slurp $path);
37
+sub _html {
38
+  my ($self, $src) = @_;
48 39
 
49 40
   # Rewrite links
50
-  my $dom     = Mojo::DOM->new("$html");
41
+  my $dom     = Mojo::DOM->new(_pod_to_html($src));
51 42
   my $perldoc = $self->url_for('/perldoc/');
52
-  $dom->find('a[href]')->each(
53
-    sub {
54
-      my $attrs = shift->attrs;
55
-      $attrs->{href} =~ s!%3A%3A!/!gi
56
-        if $attrs->{href} =~ s!^http://search\.cpan\.org/perldoc\?!$perldoc!;
57
-    }
58
-  );
43
+  for my $e ($dom->find('a[href]')->each) {
44
+    my $attrs = $e->attr;
45
+    $attrs->{href} =~ s!%3A%3A!/!gi
46
+      if $attrs->{href} =~ s!^http://search\.cpan\.org/perldoc\?!$perldoc!;
47
+  }
59 48
 
60 49
   # Rewrite code blocks for syntax highlighting
61
-  $dom->find('pre')->each(
62
-    sub {
63
-      my $e = shift;
64
-      return if $e->all_text =~ /^\s*\$\s+/m;
65
-      my $attrs = $e->attrs;
66
-      my $class = $attrs->{class};
67
-      $attrs->{class} = defined $class ? "$class prettyprint" : 'prettyprint';
68
-    }
69
-  );
50
+  for my $e ($dom->find('pre')->each) {
51
+    next if $e->all_text =~ /^\s*\$\s+/m;
52
+    my $attrs = $e->attr;
53
+    my $class = $attrs->{class};
54
+    $attrs->{class} = defined $class ? "$class prettyprint" : 'prettyprint';
55
+  }
70 56
 
71 57
   # Rewrite headers
72
-  my $url = $self->req->url->clone;
58
+  my $toc = Mojo::URL->new->fragment('toc');
73 59
   my (%anchors, @parts);
74
-  $dom->find('h1, h2, h3')->each(
75
-    sub {
76
-      my $e = shift;
77
-
78
-      # Anchor and text
79
-      my $name = my $text = $e->all_text;
80
-      $name =~ s/\s+/_/g;
81
-      $name =~ s/[^\w\-]//g;
82
-      my $anchor = $name;
83
-      my $i      = 1;
84
-      $anchor = $name . $i++ while $anchors{$anchor}++;
85
-
86
-      # Rewrite
87
-      push @parts, [] if $e->type eq 'h1' || !@parts;
88
-      push @{$parts[-1]}, $text, $url->fragment($anchor)->to_abs;
89
-      $e->replace_content(
90
-        $self->link_to(
91
-          $text => $url->fragment('toc')->to_abs,
92
-          class => 'mojoscroll',
93
-          id    => $anchor
94
-        )
95
-      );
96
-    }
97
-  );
60
+  for my $e ($dom->find('h1, h2, h3')->each) {
61
+
62
+    # Anchor and text
63
+    my $name = my $text = $e->all_text;
64
+    $name =~ s/\s+/_/g;
65
+    $name =~ s/[^\w\-]//g;
66
+    my $anchor = $name;
67
+    my $i      = 1;
68
+    $anchor = $name . $i++ while $anchors{$anchor}++;
69
+
70
+    # Rewrite
71
+    push @parts, [] if $e->type eq 'h1' || !@parts;
72
+    push @{$parts[-1]}, $text, Mojo::URL->new->fragment($anchor);
73
+    $e->replace_content($self->link_to($text => $toc, id => $anchor));
74
+  }
98 75
 
99 76
   # Try to find a title
100 77
   my $title = 'Perldoc';
... ...
@@ -104,11 +81,25 @@ sub _perldoc {
104 81
   $self->content_for(perldoc => "$dom");
105 82
   my $template = $self->app->renderer->_bundled('perldoc');
106 83
   $self->render(inline => $template, title => $title, parts => \@parts);
107
-  $self->res->headers->content_type('text/html;charset="UTF-8"');
84
+}
85
+
86
+sub _perldoc {
87
+  my $self = shift;
88
+
89
+  # Find module or redirect to CPAN
90
+  my $module = $self->param('module');
91
+  $module =~ s!/!::!g;
92
+  my $path
93
+    = Pod::Simple::Search->new->find($module, map { $_, "$_/pods" } @INC);
94
+  return $self->redirect_to("http://metacpan.org/module/$module")
95
+    unless $path && -r $path;
96
+
97
+  my $src = slurp $path;
98
+  $self->respond_to(txt => {data => $src}, html => sub { _html($self, $src) });
108 99
 }
109 100
 
110 101
 sub _pod_to_html {
111
-  return undef unless defined(my $pod = shift);
102
+  return '' unless defined(my $pod = shift);
112 103
 
113 104
   # Block
114 105
   $pod = $pod->() if ref $pod eq 'CODE';
... ...
@@ -130,6 +121,8 @@ sub _pod_to_html {
130 121
 
131 122
 1;
132 123
 
124
+=encoding utf8
125
+
133 126
 =head1 NAME
134 127
 
135 128
 Mojolicious::Plugin::PODRenderer - POD renderer plugin
+130 -78
mojo/lib/Mojolicious/Plugin/TagHelpers.pm
... ...
@@ -23,10 +23,10 @@ sub register {
23 23
   $app->helper(image => sub { _tag('img', src => shift->url_for(shift), @_) });
24 24
   $app->helper(input_tag => sub { _input(@_) });
25 25
   $app->helper(javascript => \&_javascript);
26
+  $app->helper(label_for  => \&_label_for);
26 27
   $app->helper(link_to    => \&_link_to);
27 28
 
28
-  $app->helper(password_field =>
29
-      sub { shift; _tag('input', name => shift, @_, type => 'password') });
29
+  $app->helper(password_field => \&_password_field);
30 30
   $app->helper(radio_button =>
31 31
       sub { _input(shift, shift, value => shift, @_, type => 'radio') });
32 32
 
... ...
@@ -37,7 +37,8 @@ sub register {
37 37
   # "t" is just a shortcut for the "tag" helper
38 38
   $app->helper($_ => sub { shift; _tag(@_) }) for qw(t tag);
39 39
 
40
-  $app->helper(text_area => \&_text_area);
40
+  $app->helper(tag_with_error => \&_tag_with_error);
41
+  $app->helper(text_area      => \&_text_area);
41 42
 }
42 43
 
43 44
 sub _form_for {
... ...
@@ -46,7 +47,7 @@ sub _form_for {
46 47
 
47 48
   # POST detection
48 49
   my @post;
49
-  if (my $r = $self->app->routes->find($url[0])) {
50
+  if (my $r = $self->app->routes->lookup($url[0])) {
50 51
     my %methods = (GET => 1, POST => 1);
51 52
     do {
52 53
       my @via = @{$r->via || []};
... ...
@@ -82,12 +83,9 @@ sub _input {
82 83
 
83 84
     # Others
84 85
     else { $attrs{value} = $values[0] }
85
-
86
-    return _tag('input', name => $name, %attrs);
87 86
   }
88 87
 
89
-  # Empty tag
90
-  return _tag('input', name => $name, %attrs);
88
+  return _validation($self, $name, 'input', %attrs, name => $name);
91 89
 }
92 90
 
93 91
 sub _javascript {
... ...
@@ -95,8 +93,7 @@ sub _javascript {
95 93
 
96 94
   # CDATA
97 95
   my $cb = sub {''};
98
-  if (ref $_[-1] eq 'CODE') {
99
-    my $old = pop;
96
+  if (ref $_[-1] eq 'CODE' && (my $old = pop)) {
100 97
     $cb = sub { "//<![CDATA[\n" . $old->() . "\n//]]>" }
101 98
   }
102 99
 
... ...
@@ -106,12 +103,18 @@ sub _javascript {
106 103
   return _tag('script', @_, $src ? (src => $src) : (), $cb);
107 104
 }
108 105
 
106
+sub _label_for {
107
+  my ($self, $name) = (shift, shift);
108
+  my $content = ref $_[-1] eq 'CODE' ? pop : shift;
109
+  return _validation($self, $name, 'label', for => $name, @_, $content);
110
+}
111
+
109 112
 sub _link_to {
110 113
   my ($self, $content) = (shift, shift);
111 114
   my @url = ($content);
112 115
 
113 116
   # Content
114
-  unless (defined $_[-1] && ref $_[-1] eq 'CODE') {
117
+  unless (ref $_[-1] eq 'CODE') {
115 118
     @url = (shift);
116 119
     push @_, $content;
117 120
   }
... ...
@@ -122,47 +125,45 @@ sub _link_to {
122 125
   return _tag('a', href => $self->url_for(@url), @_);
123 126
 }
124 127
 
125
-sub _select_field {
126
-  my ($self, $name, $options, %attrs) = (shift, shift, shift, @_);
128
+sub _option {
129
+  my ($values, $pair) = @_;
130
+  $pair = [$pair => $pair] unless ref $pair eq 'ARRAY';
127 131
 
128
-  # "option" callback
129
-  my %values = map { $_ => 1 } $self->param($name);
130
-  my $option = sub {
131
-
132
-    # Pair
133
-    my $pair = shift;
134
-    $pair = [$pair => $pair] unless ref $pair eq 'ARRAY';
132
+  # Attributes
133
+  my %attrs = (value => $pair->[1]);
134
+  $attrs{selected} = 'selected' if exists $values->{$pair->[1]};
135
+  %attrs = (%attrs, @$pair[2 .. $#$pair]);
135 136
 
136
-    # Attributes
137
-    my %attrs = (value => $pair->[1]);
138
-    $attrs{selected} = 'selected' if exists $values{$pair->[1]};
139
-    %attrs = (%attrs, @$pair[2 .. $#$pair]);
137
+  return _tag('option', %attrs, sub { xml_escape $pair->[0] });
138
+}
140 139
 
141
-    return _tag('option', %attrs, sub { xml_escape $pair->[0] });
142
-  };
140
+sub _password_field {
141
+  my ($self, $name) = (shift, shift);
142
+  return _validation($self, $name, 'input', @_, name => $name,
143
+    type => 'password');
144
+}
143 145
 
144
-  # "optgroup" callback
145
-  my $optgroup = sub {
146
+sub _select_field {
147
+  my ($self, $name, $options, %attrs) = (shift, shift, shift, @_);
146 148
 
147
-    # Parts
148
-    my $parts = '';
149
-    for my $group (@$options) {
149
+  my %values = map { $_ => 1 } $self->param($name);
150 150
 
151
-      # "optgroup" tag
152
-      if (ref $group eq 'HASH') {
153
-        my ($label, $values) = each %$group;
154
-        my $content = join '', map { $option->($_) } @$values;
155
-        $parts .= _tag('optgroup', label => $label, sub {$content});
156
-      }
151
+  my $groups = '';
152
+  for my $group (@$options) {
157 153
 
158
-      # "option" tag
159
-      else { $parts .= $option->($group) }
154
+    # "optgroup" tag
155
+    if (ref $group eq 'HASH') {
156
+      my ($label, $values) = each %$group;
157
+      my $content = join '', map { _option(\%values, $_) } @$values;
158
+      $groups .= _tag('optgroup', label => $label, sub {$content});
160 159
     }
161 160
 
162
-    return $parts;
163
-  };
161
+    # "option" tag
162
+    else { $groups .= _option(\%values, $group) }
163
+  }
164 164
 
165
-  return _tag('select', name => $name, %attrs, $optgroup);
165
+  return _validation($self, $name, 'select', %attrs, name => $name,
166
+    sub {$groups});
166 167
 }
167 168
 
168 169
 sub _stylesheet {
... ...
@@ -170,15 +171,14 @@ sub _stylesheet {
170 171
 
171 172
   # CDATA
172 173
   my $cb;
173
-  if (ref $_[-1] eq 'CODE') {
174
-    my $old = pop;
174
+  if (ref $_[-1] eq 'CODE' && (my $old = pop)) {
175 175
     $cb = sub { "/*<![CDATA[*/\n" . $old->() . "\n/*]]>*/" }
176 176
   }
177 177
 
178 178
   # "link" or "style" tag
179 179
   my $href = @_ % 2 ? $self->url_for(shift) : undef;
180 180
   return $href
181
-    ? _tag('link', rel => 'stylesheet', href => $href, media => 'screen', @_)
181
+    ? _tag('link', rel => 'stylesheet', href => $href, @_)
182 182
     : _tag('style', @_, $cb);
183 183
 }
184 184
 
... ...
@@ -199,39 +199,47 @@ sub _tag {
199 199
 
200 200
   # Attributes
201 201
   my %attrs = @_;
202
-  for my $key (sort keys %attrs) {
203
-    $tag .= qq{ $key="} . xml_escape(defined $attrs{$key} ? $attrs{$key} : '') . '"';
204
-  }
205
-
206
-  # End tag
207
-  if ($cb || defined $content) {
208
-    $tag .= '>' . ($cb ? $cb->() : xml_escape($content)) . "</$name>";
209
-  }
202
+  $tag .= qq{ $_="} . xml_escape(defined $attrs{$_} ? $attrs{$_} : '') . '"' for sort keys %attrs;
210 203
 
211 204
   # Empty element
212
-  else { $tag .= ' />' }
205
+  unless ($cb || defined $content) { $tag .= ' />' }
206
+
207
+  # End tag
208
+  else { $tag .= '>' . ($cb ? $cb->() : xml_escape($content)) . "</$name>" }
213 209
 
214 210
   # Prevent escaping
215 211
   return Mojo::ByteStream->new($tag);
216 212
 }
217 213
 
214
+sub _tag_with_error {
215
+  my ($self, $tag) = (shift, shift);
216
+  my ($content, %attrs) = (@_ % 2 ? pop : undef, @_);
217
+  $attrs{class} .= $attrs{class} ? ' field-with-error' : 'field-with-error';
218
+  return _tag($tag, %attrs, defined $content ? $content : ());
219
+}
220
+
218 221
 sub _text_area {
219 222
   my ($self, $name) = (shift, shift);
220 223
 
221
-  # Content
224
+  # Make sure content is wrapped
222 225
   my $cb = ref $_[-1] eq 'CODE' ? pop : sub {''};
223 226
   my $content = @_ % 2 ? shift : undef;
227
+  $cb = sub { xml_escape $content }
228
+    if defined($content = defined $self->param($name) ? $self->param($name) : $content);
224 229
 
225
-  # Make sure content is wrapped
226
-  if (defined($content = defined $self->param($name) ? $self->param($name) : $content)) {
227
-    $cb = sub { xml_escape $content }
228
-  }
230
+  return _validation($self, $name, 'textarea', @_, name => $name, $cb);
231
+}
229 232
 
230
-  return _tag('textarea', name => $name, @_, $cb);
233
+sub _validation {
234
+  my ($self, $name) = (shift, shift);
235
+  return _tag(@_) unless $self->validation->has_error($name);
236
+  return $self->tag_with_error(@_);
231 237
 }
232 238
 
233 239
 1;
234 240
 
241
+=encoding utf8
242
+
235 243
 =head1 NAME
236 244
 
237 245
 Mojolicious::Plugin::TagHelpers - Tag helpers plugin
... ...
@@ -259,6 +267,12 @@ necessary attributes always be generated automatically.
259 267
   <%= radio_button country => 'france'  %> France
260 268
   <%= radio_button country => 'uk'      %> UK
261 269
 
270
+For fields that failed validation with L<Mojolicious::Controller/"validation">
271
+the C<field-with-error> class will be automatically added through the
272
+C<tag_with_error> helper, to make styling with CSS easier.
273
+
274
+  <input class="field-with-error" name="age" type="text" value="250" />
275
+
262 276
 This is a core plugin, that means it is always enabled and its code a good
263 277
 example for learning how to build new plugins, you're welcome to fork it.
264 278
 
... ...
@@ -358,8 +372,8 @@ Generate file input element.
358 372
     %= submit_button
359 373
   % end
360 374
 
361
-Generate portable form for route, path or URL. For routes that allow C<POST>
362
-but not C<GET>, a C<method> attribute will be automatically added.
375
+Generate portable form tag for route, path or URL. For routes that allow POST
376
+but not GET, a C<method> attribute will be automatically added.
363 377
 
364 378
   <form action="/path/to/login">
365 379
     <input name="first_name" />
... ...
@@ -369,7 +383,7 @@ but not C<GET>, a C<method> attribute will be automatically added.
369 383
     <input name="first_name" />
370 384
     <input value="Ok" type="submit" />
371 385
   </form>
372
-  <form action="/login" method="POST">
386
+  <form action="/path/to/login" method="POST">
373 387
     <input name="first_name" />
374 388
     <input value="Ok" type="submit" />
375 389
   </form>
... ...
@@ -393,10 +407,10 @@ Generate hidden input element.
393 407
   %= image '/images/foo.png'
394 408
   %= image '/images/foo.png', alt => 'Foo'
395 409
 
396
-Generate image tag.
410
+Generate portable img tag.
397 411
 
398
-  <img src="/images/foo.png" />
399
-  <img alt="Foo" src="/images/foo.png" />
412
+  <img src="/path/to/images/foo.png" />
413
+  <img alt="Foo" src="/path/to/images/foo.png" />
400 414
 
401 415
 =head2 input_tag
402 416
 
... ...
@@ -420,21 +434,43 @@ picked up and shown as default.
420 434
 
421 435
 Generate portable script tag for C<Javascript> asset.
422 436
 
423
-  <script src="/script.js" />
437
+  <script src="/path/to/script.js" />
424 438
   <script><![CDATA[
425 439
     var a = 'b';
426 440
   ]]></script>
427 441
 
442
+=head2 label_for
443
+
444
+  %= label_for first_name => 'First name'
445
+  %= label_for first_name => 'First name', class => 'user'
446
+  %= label_for first_name => begin
447
+    First name
448
+  % end
449
+  %= label_for first_name => (class => 'user') => begin
450
+    First name
451
+  % end
452
+
453
+Generate label.
454
+
455
+  <label for="first_name">First name</label>
456
+  <label class="user" for="first_name">First name</label>
457
+  <label for="first_name">
458
+    First name
459
+  </label>
460
+  <label class="user" for="first_name">
461
+    First name
462
+  </label>
463
+
428 464
 =head2 link_to
429 465
 
430 466
   %= link_to Home => 'index'
431
-  %= link_to Home => 'index' => {format => 'txt'} => (class => 'links')
432
-  %= link_to index => {format => 'txt'} => (class => 'links') => begin
467
+  %= link_to Home => 'index' => {format => 'txt'} => (class => 'menu')
468
+  %= link_to index => {format => 'txt'} => (class => 'menu') => begin
433 469
     Home
434 470
   % end
435
-  %= link_to Contact => Mojo::URL->new('mailto:sri@example.com')
471
+  %= link_to Contact => 'mailto:sri@example.com'
436 472
   <%= link_to index => begin %>Home<% end %>
437
-  <%= link_to '/path/to/file' => begin %>File<% end %>
473
+  <%= link_to '/file.txt' => begin %>File<% end %>
438 474
   <%= link_to 'http://mojolicio.us' => begin %>Mojolicious<% end %>
439 475
   <%= link_to url_for->query(foo => 'bar')->to_abs => begin %>Retry<% end %>
440 476
 
... ...
@@ -442,13 +478,13 @@ Generate portable link to route, path or URL, defaults to using the
442 478
 capitalized link target as content.
443 479
 
444 480
   <a href="/path/to/index">Home</a>
445
-  <a class="links" href="/path/to/index.txt">Home</a>
446
-  <a class="links" href="/path/to/index.txt">
481
+  <a class="menu" href="/path/to/index.txt">Home</a>
482
+  <a class="menu" href="/path/to/index.txt">
447 483
     Home
448 484
   </a>
449 485
   <a href="mailto:sri@example.com">Contact</a>
450 486
   <a href="/path/to/index">Home</a>
451
-  <a href="/path/to/file">File</a>
487
+  <a href="/path/to/file.txt">File</a>
452 488
   <a href="http://mojolicio.us">Mojolicious</a>
453 489
   <a href="http://127.0.0.1:3000/current/path?foo=bar">Retry</a>
454 490
 
... ...
@@ -568,7 +604,7 @@ automatically get picked up and shown as default.
568 604
 
569 605
 Generate portable style or link tag for C<CSS> asset.
570 606
 
571
-  <link href="/foo.css" media="screen" rel="stylesheet" />
607
+  <link href="/path/to/foo.css" rel="stylesheet" />
572 608
   <style><![CDATA[
573 609
     body {color: #000}
574 610
   ]]></style>
... ...
@@ -587,7 +623,7 @@ Generate submit input element.
587 623
 
588 624
   %=t div => 'some & content'
589 625
 
590
-Alias for C<tag>.
626
+Alias for L</"tag">.
591 627
 
592 628
   <div>some &amp; content</div>
593 629
 
... ...
@@ -596,14 +632,22 @@ Alias for C<tag>.
596 632
   %= tag 'div'
597 633
   %= tag 'div', id => 'foo'
598 634
   %= tag div => 'some & content'
599
-  <%= tag div => begin %>some & content<% end %>
635
+  %= tag div => (id => 'foo') => 'some & content'
636
+  %= tag div => begin
637
+    some & content
638
+  % end
639
+  <%= tag div => (id => 'foo') => begin %>some & content<% end %>
600 640
 
601 641
 HTML tag generator.
602 642
 
603 643
   <div />
604 644
   <div id="foo" />
605 645
   <div>some &amp; content</div>
606
-  <div>some & content</div>
646
+  <div id="foo">some &amp; content</div>
647
+  <div>
648
+    some & content
649
+  </div>
650
+  <div id="foo">some & content</div>
607 651
 
608 652
 Very useful for reuse in more specific tag helpers.
609 653
 
... ...
@@ -614,6 +658,14 @@ Very useful for reuse in more specific tag helpers.
614 658
 Results are automatically wrapped in L<Mojo::ByteStream> objects to prevent
615 659
 accidental double escaping.
616 660
 
661
+=head2 tag_with_error
662
+
663
+  %= tag_with_error 'input', class => 'foo'
664
+
665
+Same as L</"tag">, but adds the class C<field-with-error>.
666
+
667
+  <input class="foo field-with-error" />
668
+
617 669
 =head2 tel_field
618 670
 
619 671
   %= tel_field 'work'
+6 -5
mojo/lib/Mojolicious/Plugins.pm
... ...
@@ -19,9 +19,8 @@ sub emit_chain {
19 19
     my $next = $wrapper;
20 20
     $wrapper = sub { $cb->($next, @args) };
21 21
   }
22
-  $wrapper->();
23 22
 
24
-  return $self;
23
+  !$wrapper ? return : return $wrapper->();
25 24
 }
26 25
 
27 26
 sub emit_hook_reverse {
... ...
@@ -56,11 +55,13 @@ sub _load {
56 55
   if (my $e = Mojo::Loader->new->load($module)) {
57 56
     ref $e ? die $e : return undef;
58 57
   }
59
-  return $module->isa('Mojolicious::Plugin') ? 1 : undef;
58
+  return $module->isa('Mojolicious::Plugin');
60 59
 }
61 60
 
62 61
 1;
63 62
 
63
+=encoding utf8
64
+
64 65
 =head1 NAME
65 66
 
66 67
 Mojolicious::Plugins - Plugin manager
... ...
@@ -151,8 +152,8 @@ implements the following new ones.
151 152
 
152 153
 =head2 emit_chain
153 154
 
154
-  $plugins = $plugins->emit_chain('foo');
155
-  $plugins = $plugins->emit_chain(foo => 123);
155
+  $plugins->emit_chain('foo');
156
+  $plugins->emit_chain(foo => 123);
156 157
 
157 158
 Emit events as chained hooks.
158 159
 
+21 -24
mojo/lib/Mojolicious/Renderer.pm
... ...
@@ -13,8 +13,15 @@ has classes => sub { ['main'] };
13 13
 has default_format => 'html';
14 14
 has 'default_handler';
15 15
 has encoding => 'UTF-8';
16
-has [qw(handlers helpers)] => sub { {} };
17
-has paths => sub { [] };
16
+has handlers => sub {
17
+  {
18
+    data => sub { ${$_[2]} = $_[3]{data} },
19
+    text => sub { ${$_[2]} = $_[3]{text} },
20
+    json => sub { ${$_[2]} = Mojo::JSON->new->encode($_[3]{json}) }
21
+  };
22
+};
23
+has helpers => sub { {} };
24
+has paths   => sub { [] };
18 25
 
19 26
 # Bundled templates
20 27
 my $HOME = Mojo::Home->new;
... ...
@@ -22,14 +29,6 @@ $HOME->parse(
22 29
   $HOME->parse($HOME->mojo_lib_dir)->rel_dir('Mojolicious/templates'));
23 30
 my %TEMPLATES = map { $_ => slurp $HOME->rel_file($_) } @{$HOME->list_files};
24 31
 
25
-sub new {
26
-  my $self = shift->SUPER::new(@_);
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}) });
31
-}
32
-
33 32
 sub add_handler { shift->_add(handlers => @_) }
34 33
 sub add_helper  { shift->_add(helpers  => @_) }
35 34
 
... ...
@@ -54,11 +53,11 @@ sub render {
54 53
   my ($self, $c, $args) = @_;
55 54
   $args ||= {};
56 55
 
57
-  # Localize "extends" and "layout"
58
-  my $partial = $args->{partial};
59
-  my $stash   = $c->stash;
60
-  local $stash->{layout}  = $partial ? undef : $stash->{layout};
61
-  local $stash->{extends} = $partial ? undef : $stash->{extends};
56
+  # Localize "extends" and "layout" to allow argument overrides
57
+  my $stash = $c->stash;
58
+  local $stash->{layout}  = $stash->{layout}  if exists $stash->{layout};
59
+  local $stash->{extends} = $stash->{extends} if exists $stash->{extends};
60
+  delete @{$stash}{qw(layout extends)} if my $partial = $args->{partial};
62 61
 
63 62
   # Merge stash and arguments
64 63
   @{$stash}{keys %$args} = values %$args;
... ...
@@ -209,6 +208,8 @@ sub _render_template {
209 208
 
210 209
 1;
211 210
 
211
+=encoding utf8
212
+
212 213
 =head1 NAME
213 214
 
214 215
 Mojolicious::Renderer - Generate dynamic content
... ...
@@ -269,14 +270,17 @@ detection doesn't work, like for C<inline> templates.
269 270
   my $encoding = $renderer->encoding;
270 271
   $renderer    = $renderer->encoding('koi8-r');
271 272
 
272
-Will encode the content if set, defaults to C<UTF-8>.
273
+Will encode generated content if set, defaults to C<UTF-8>. Note that many
274
+renderers such as L<Mojolicious::Plugin::EPRenderer> also use this value to
275
+determine if template files should be decoded before processing.
273 276
 
274 277
 =head2 handlers
275 278
 
276 279
   my $handlers = $renderer->handlers;
277 280
   $renderer    = $renderer->handlers({epl => sub {...}});
278 281
 
279
-Registered handlers.
282
+Registered handlers, by default only C<data>, C<text> and C<json> are already
283
+defined.
280 284
 
281 285
 =head2 helpers
282 286
 
... ...
@@ -300,13 +304,6 @@ Directories to look for templates in, first one has the highest precedence.
300 304
 L<Mojolicious::Renderer> inherits all methods from L<Mojo::Base> and
301 305
 implements the following new ones.
302 306
 
303
-=head2 new
304
-
305
-  my $renderer = Mojolicious::Renderer->new;
306
-
307
-Construct a new renderer and register C<data>, C<json> as well as C<text>
308
-handlers.
309
-
310 307
 =head2 add_handler
311 308
 
312 309
   $renderer = $renderer->add_handler(epl => sub {...});
+71 -80
mojo/lib/Mojolicious/Routes.pm
... ...
@@ -24,6 +24,27 @@ sub auto_render {
24 24
   $c->render_maybe or $stash->{'mojo.routed'} or $c->render_not_found;
25 25
 }
26 26
 
27
+sub continue {
28
+  my ($self, $c) = @_;
29
+
30
+  my $match   = $c->match;
31
+  my $stack   = $match->stack;
32
+  my $current = $match->current;
33
+  return $self->auto_render($c) unless my $field = $stack->[$current];
34
+
35
+  # Merge captures into stash
36
+  my @keys  = keys %$field;
37
+  my $stash = $c->stash;
38
+  @{$stash}{@keys} = @{$stash->{'mojo.captures'}}{@keys} = values %$field;
39
+
40
+  my $continue;
41
+  my $last = !$stack->[++$current];
42
+  if (my $cb = $field->{cb}) { $continue = $self->_callback($c, $cb, $last) }
43
+  else { $continue = $self->_controller($c, $field, $last) }
44
+  $match->current($current);
45
+  $self->continue($c) if $last || $continue;
46
+}
47
+
27 48
 sub dispatch {
28 49
   my ($self, $c) = @_;
29 50
 
... ...
@@ -59,9 +80,8 @@ sub dispatch {
59 80
     }
60 81
   }
61 82
 
62
-  # Dispatch
63
-  return undef unless $self->_walk($c);
64
-  $self->auto_render($c);
83
+  return undef unless @{$c->match->stack};
84
+  $self->continue($c);
65 85
   return 1;
66 86
 }
67 87
 
... ...
@@ -69,8 +89,8 @@ sub hide { push @{shift->hidden}, @_ }
69 89
 
70 90
 sub is_hidden {
71 91
   my ($self, $method) = @_;
72
-  my $hiding = $self->{hiding} ||= {map { $_ => 1 } @{$self->hidden}};
73
-  return !!($hiding->{$method} || index($method, '_') == 0);
92
+  my $h = $self->{hiding} ||= {map { $_ => 1 } @{$self->hidden}};
93
+  return !!($h->{$method} || index($method, '_') == 0 || $method !~ /[a-z]/);
74 94
 }
75 95
 
76 96
 sub lookup {
... ...
@@ -85,6 +105,8 @@ sub route {
85 105
   shift->add_child(Mojolicious::Routes::Route->new(@_))->children->[-1];
86 106
 }
87 107
 
108
+sub _action { shift->plugins->emit_chain(around_action => @_) }
109
+
88 110
 sub _add {
89 111
   my ($self, $attr, $name, $cb) = @_;
90 112
   $self->$attr->{$name} = $cb;
... ...
@@ -92,11 +114,11 @@ sub _add {
92 114
 }
93 115
 
94 116
 sub _callback {
95
-  my ($self, $c, $field, $nested) = @_;
96
-  $c->stash->{'mojo.routed'}++;
97
-  $c->app->log->debug('Routing to a callback.');
98
-  my $continue = $field->{cb}->($c);
99
-  return !$nested || $continue ? 1 : undef;
117
+  my ($self, $c, $cb, $last) = @_;
118
+  $c->stash->{'mojo.routed'}++ if $last;
119
+  my $app = $c->app;
120
+  $app->log->debug('Routing to a callback.');
121
+  return _action($app, $c, $cb, $last);
100 122
 }
101 123
 
102 124
 sub _class {
... ...
@@ -131,7 +153,9 @@ sub _class {
131 153
     }
132 154
 
133 155
     # Success
134
-    return $class->new($c);
156
+    my $new = $class->new(%$c);
157
+    weaken $new->{$_} for qw(app tx);
158
+    return $new;
135 159
   }
136 160
 
137 161
   # Nothing found
... ...
@@ -140,43 +164,44 @@ sub _class {
140 164
 }
141 165
 
142 166
 sub _controller {
143
-  my ($self, $c, $field, $nested) = @_;
167
+  my ($self, $old, $field, $last) = @_;
144 168
 
145 169
   # Load and instantiate controller/application
146
-  my $app;
147
-  unless ($app = $self->_class($c, $field)) { return defined $app ? 1 : undef }
170
+  my $new;
171
+  unless ($new = $self->_class($old, $field)) { return !!defined $new }
148 172
 
149 173
   # Application
150
-  my $continue;
151
-  my $class = ref $app;
152
-  my $log   = $c->app->log;
153
-  if (my $sub = $app->can('handler')) {
174
+  my $class = ref $new;
175
+  my $app   = $old->app;
176
+  my $log   = $app->log;
177
+  if (my $sub = $new->can('handler')) {
154 178
     $log->debug(qq{Routing to application "$class".});
155 179
 
156 180
     # Try to connect routes
157
-    if (my $sub = $app->can('routes')) {
158
-      my $r = $app->$sub;
159
-      weaken $r->parent($c->match->endpoint)->{parent} unless $r->parent;
181
+    if (my $sub = $new->can('routes')) {
182
+      my $r = $new->$sub;
183
+      weaken $r->parent($old->match->endpoint)->{parent} unless $r->parent;
160 184
     }
161
-    $app->$sub($c);
162
-    $c->stash->{'mojo.routed'}++;
185
+    $new->$sub($old);
186
+    $old->stash->{'mojo.routed'}++;
163 187
   }
164 188
 
165 189
   # Action
166
-  elsif (my $method = $self->_method($c, $field)) {
167
-    $log->debug(qq{Routing to controller "$class" and action "$method".});
190
+  elsif (my $method = $field->{action}) {
191
+    if (!$self->is_hidden($method)) {
192
+      $log->debug(qq{Routing to controller "$class" and action "$method".});
168 193
 
169
-    # Try to call action
170
-    if (my $sub = $app->can($method)) {
171
-      $c->stash->{'mojo.routed'}++ unless $nested;
172
-      $continue = $app->$sub;
173
-    }
194
+      if (my $sub = $new->can($method)) {
195
+        $old->stash->{'mojo.routed'}++ if $last;
196
+        return 1 if _action($app, $new, $sub, $last);
197
+      }
174 198
 
175
-    # Action not found
176
-    else { $log->debug('Action not found in controller.') }
199
+      else { $log->debug('Action not found in controller.') }
200
+    }
201
+    else { $log->debug(qq{Action "$method" is not allowed.}) }
177 202
   }
178 203
 
179
-  return !$nested || $continue ? 1 : undef;
204
+  return undef;
180 205
 }
181 206
 
182 207
 sub _load {
... ...
@@ -191,50 +216,10 @@ sub _load {
191 216
   return ++$self->{loaded}{$app};
192 217
 }
193 218
 
194
-sub _method {
195
-  my ($self, $c, $field) = @_;
196
-
197
-  # Hidden
198
-  return undef unless my $method = $field->{action};
199
-  $c->app->log->debug(qq{Action "$method" is not allowed.}) and return undef
200
-    if $self->is_hidden($method);
201
-
202
-  # Invalid
203
-  $c->app->log->debug(qq{Action "$method" is invalid.}) and return undef
204
-    unless $method =~ /^[a-zA-Z0-9_:]+$/;
205
-
206
-  return $method;
207
-}
208
-
209
-sub _walk {
210
-  my ($self, $c) = @_;
211
-
212
-  my $stack = $c->match->stack;
213
-  return undef unless my $nested = @$stack;
214
-  my $stash = $c->stash;
215
-  $stash->{'mojo.captures'} ||= {};
216
-  for my $field (@$stack) {
217
-    $nested--;
218
-
219
-    # Merge captures into stash
220
-    my @keys = keys %$field;
221
-    @{$stash}{@keys} = @{$stash->{'mojo.captures'}}{@keys} = values %$field;
222
-
223
-    # Dispatch
224
-    my $continue
225
-      = $field->{cb}
226
-      ? $self->_callback($c, $field, $nested)
227
-      : $self->_controller($c, $field, $nested);
228
-
229
-    # Break the chain
230
-    return undef if $nested && !$continue;
231
-  }
232
-
233
-  return 1;
234
-}
235
-
236 219
 1;
237 220
 
221
+=encoding utf8
222
+
238 223
 =head1 NAME
239 224
 
240 225
 Mojolicious::Routes - Always find your destination with routes!
... ...
@@ -294,7 +279,7 @@ Contains all available conditions.
294 279
   my $hidden = $r->hidden;
295 280
   $r         = $r->hidden([qw(attr has new)]);
296 281
 
297
-Controller methods and attributes that are hidden from router, defaults to
282
+Controller attributes and methods that are hidden from router, defaults to
298 283
 C<attr>, C<has>, C<new> and C<tap>.
299 284
 
300 285
 =head2 namespaces
... ...
@@ -337,9 +322,15 @@ Add a new shortcut.
337 322
 
338 323
 Automatic rendering.
339 324
 
325
+=head2 continue
326
+
327
+  $r->continue(Mojolicious::Controller->new);
328
+
329
+Continue dispatch chain.
330
+
340 331
 =head2 dispatch
341 332
 
342
-  my $success = $r->dispatch(Mojolicious::Controller->new);
333
+  my $bool = $r->dispatch(Mojolicious::Controller->new);
343 334
 
344 335
 Match routes with L<Mojolicious::Routes::Match> and dispatch.
345 336
 
... ...
@@ -347,13 +338,13 @@ Match routes with L<Mojolicious::Routes::Match> and dispatch.
347 338
 
348 339
   $r = $r->hide(qw(foo bar));
349 340
 
350
-Hide controller methods and attributes from router.
341
+Hide controller attributes and methods from router.
351 342
 
352 343
 =head2 is_hidden
353 344
 
354
-  my $success = $r->is_hidden('foo');
345
+  my $bool = $r->is_hidden('foo');
355 346
 
356
-Check if controller method or attribute is hidden from router.
347
+Check if controller attribute or method is hidden from router.
357 348
 
358 349
 =head2 lookup
359 350
 
+13 -2
mojo/lib/Mojolicious/Routes/Match.pm
... ...
@@ -1,6 +1,7 @@
1 1
 package Mojolicious::Routes::Match;
2 2
 use Mojo::Base -base;
3 3
 
4
+has current => 0;
4 5
 has [qw(endpoint root)];
5 6
 has stack => sub { [] };
6 7
 
... ...
@@ -71,7 +72,7 @@ sub _match {
71 72
   if (($endpoint && $empty) || $r->inline) {
72 73
     push @{$self->stack}, {%$captures};
73 74
     return $self->endpoint($r) if $endpoint && $empty;
74
-    delete $captures->{$_} for qw(app cb);
75
+    delete @$captures{qw(app cb)};
75 76
   }
76 77
 
77 78
   # Match children
... ...
@@ -102,6 +103,8 @@ sub _values {
102 103
 
103 104
 1;
104 105
 
106
+=encoding utf8
107
+
105 108
 =head1 NAME
106 109
 
107 110
 Mojolicious::Routes::Match - Find routes
... ...
@@ -137,6 +140,13 @@ structures.
137 140
 
138 141
 L<Mojolicious::Routes::Match> implements the following attributes.
139 142
 
143
+=head2 current
144
+
145
+  my $current = $match->current;
146
+  $match      = $match->current(2);
147
+
148
+Current position on the L</"stack">, defaults to C<0>.
149
+
140 150
 =head2 endpoint
141 151
 
142 152
   my $endpoint = $match->endpoint;
... ...
@@ -167,7 +177,8 @@ implements the following new ones.
167 177
 
168 178
   $match->match(Mojolicious::Controller->new, {method => 'GET', path => '/'});
169 179
 
170
-Match controller and options against C<root> to find appropriate C<endpoint>.
180
+Match controller and options against L</"root"> to find appropriate
181
+L</"endpoint">.
171 182
 
172 183
 =head2 path_for
173 184
 
+9 -13
mojo/lib/Mojolicious/Routes/Pattern.pm
... ...
@@ -28,7 +28,7 @@ sub match_partial {
28 28
 
29 29
   # Match
30 30
   return undef unless my @captures = $$pathref =~ $regex;
31
-  $$pathref =~ s/$regex//;
31
+  $$pathref = pop(@captures);
32 32
 
33 33
   # Merge captures
34 34
   my $captures = {%{$self->defaults}};
... ...
@@ -152,7 +152,7 @@ sub _compile {
152 152
   # Not rooted with a slash
153 153
   $regex = "$block$regex" if $block;
154 154
 
155
-  return $self->regex(qr/^$regex/s)->regex;
155
+  return $self->regex(qr/^$regex(.*)/s)->regex;
156 156
 }
157 157
 
158 158
 sub _compile_format {
... ...
@@ -189,16 +189,14 @@ sub _tokenize {
189 189
   my $pattern = $self->pattern;
190 190
   my $state   = 'text';
191 191
   my (@tree, $quoted);
192
-  while (length(my $char = substr $pattern, 0, 1, '')) {
193
-
194
-    # Inside a placeholder
192
+  for my $char (split '', $pattern) {
195 193
     my $inside = !!grep { $_ eq $state } qw(placeholder relaxed wildcard);
196 194
 
197 195
     # Quote start
198 196
     if ($char eq $quote_start) {
199 197
       $quoted = 1;
200
-      $state  = 'placeholder';
201 198
       push @tree, ['placeholder', ''];
199
+      $state = 'placeholder';
202 200
     }
203 201
 
204 202
     # Placeholder start
... ...
@@ -230,13 +228,9 @@ sub _tokenize {
230 228
 
231 229
     # Text
232 230
     else {
233
-      $state = 'text';
234
-
235
-      # New text element
236 231
       push @tree, ['text', $char] and next unless $tree[-1][0] eq 'text';
237
-
238
-      # More text
239 232
       $tree[-1][-1] .= $char;
233
+      $state = 'text';
240 234
     }
241 235
   }
242 236
 
... ...
@@ -245,6 +239,8 @@ sub _tokenize {
245 239
 
246 240
 1;
247 241
 
242
+=encoding utf8
243
+
248 244
 =head1 NAME
249 245
 
250 246
 Mojolicious::Routes::Pattern - Routes pattern engine
... ...
@@ -365,8 +361,8 @@ implements the following new ones.
365 361
     = Mojolicious::Routes::Pattern->new('/:action', action => qr/\w+/);
366 362
   my $pattern = Mojolicious::Routes::Pattern->new(format => 0);
367 363
 
368
-Construct a new L<Mojolicious::Routes::Pattern> object and C<parse> pattern if
369
-necessary.
364
+Construct a new L<Mojolicious::Routes::Pattern> object and L</"parse"> pattern
365
+if necessary.
370 366
 
371 367
 =head2 match
372 368
 
+29 -26
mojo/lib/Mojolicious/Routes/Route.pm
... ...
@@ -136,7 +136,7 @@ sub render {
136 136
 
137 137
 sub root {
138 138
   my $root = my $parent = shift;
139
-  while ($parent = $parent->parent) { $root = $parent }
139
+  $root = $parent while $parent = $parent->parent;
140 140
   return $root;
141 141
 }
142 142
 
... ...
@@ -249,6 +249,8 @@ sub _generate_route {
249 249
 
250 250
 1;
251 251
 
252
+=encoding utf8
253
+
252 254
 =head1 NAME
253 255
 
254 256
 Mojolicious::Routes::Route - Route
... ...
@@ -277,10 +279,10 @@ The children of this route, used for nesting routes.
277 279
 
278 280
 =head2 inline
279 281
 
280
-  my $inline = $r->inline;
281
-  $r         = $r->inline(1);
282
+  my $bool = $r->inline;
283
+  $r       = $r->inline($bool);
282 284
 
283
-Allow C<bridge> semantics for this route.
285
+Allow L</"bridge"> semantics for this route.
284 286
 
285 287
 =head2 parent
286 288
 
... ...
@@ -291,8 +293,8 @@ The parent of this route, used for nesting routes.
291 293
 
292 294
 =head2 partial
293 295
 
294
-  my $partial = $r->partial;
295
-  $r          = $r->partial(1);
296
+  my $bool = $r->partial;
297
+  $r       = $r->partial($bool);
296 298
 
297 299
 Route has no specific end, remaining characters will be captured in C<path>.
298 300
 
... ...
@@ -343,7 +345,7 @@ also the L<Mojolicious::Lite> tutorial for more argument variations.
343 345
   my $bridge = $r->bridge('/:action', action => qr/\w+/);
344 346
   my $bridge = $r->bridge(format => 0);
345 347
 
346
-Generate bridge route.
348
+Generate bridge route with optional pattern and restrictive placeholders.
347 349
 
348 350
   my $auth = $r->bridge('/user')->to('user#auth');
349 351
   $auth->get('/show')->to('#show');
... ...
@@ -353,7 +355,7 @@ Generate bridge route.
353 355
 
354 356
   my $route = $r->delete('/:foo' => sub {...});
355 357
 
356
-Generate route matching only C<DELETE> requests. See also the
358
+Generate route matching only DELETE requests. See also the
357 359
 L<Mojolicious::Lite> tutorial for more argument variations.
358 360
 
359 361
   $r->delete('/user')->to('user#remove');
... ...
@@ -366,7 +368,7 @@ L<Mojolicious::Lite> tutorial for more argument variations.
366 368
   $r = $r->detour('MyApp', {foo => 'bar'});
367 369
 
368 370
 Set default parameters for this route and allow partial matching to simplify
369
-application embedding, takes the same arguments as C<to>.
371
+application embedding, takes the same arguments as L</"to">.
370 372
 
371 373
 =head2 find
372 374
 
... ...
@@ -381,38 +383,38 @@ generated ones.
381 383
 
382 384
   my $route = $r->get('/:foo' => sub {...});
383 385
 
384
-Generate route matching only C<GET> requests. See also the
385
-L<Mojolicious::Lite> tutorial for more argument variations.
386
+Generate route matching only GET requests. See also the L<Mojolicious::Lite>
387
+tutorial for more argument variations.
386 388
 
387 389
   $r->get('/user')->to('user#show');
388 390
 
389 391
 =head2 has_conditions
390 392
 
391
-  my $success = $r->has_conditions;
393
+  my $bool = $r->has_conditions;
392 394
 
393 395
 Check if this route has active conditions.
394 396
 
395 397
 =head2 has_custom_name
396 398
 
397
-  my $success = $r->has_custom_name;
399
+  my $bool = $r->has_custom_name;
398 400
 
399 401
 Check if this route has a custom name.
400 402
 
401 403
 =head2 has_websocket
402 404
 
403
-  my $success = $r->has_websocket;
405
+  my $bool = $r->has_websocket;
404 406
 
405 407
 Check if this route has a WebSocket ancestor.
406 408
 
407 409
 =head2 is_endpoint
408 410
 
409
-  my $success = $r->is_endpoint;
411
+  my $bool = $r->is_endpoint;
410 412
 
411 413
 Check if this route qualifies as an endpoint.
412 414
 
413 415
 =head2 is_websocket
414 416
 
415
-  my $success = $r->is_websocket;
417
+  my $bool = $r->is_websocket;
416 418
 
417 419
 Check if this route is a WebSocket.
418 420
 
... ...
@@ -431,7 +433,7 @@ the current route.
431 433
 
432 434
   my $route = $r->options('/:foo' => sub {...});
433 435
 
434
-Generate route matching only C<OPTIONS> requests. See also the
436
+Generate route matching only OPTIONS requests. See also the
435 437
 L<Mojolicious::Lite> tutorial for more argument variations.
436 438
 
437 439
   $r->options('/user')->to('user#overview');
... ...
@@ -460,8 +462,8 @@ Parse pattern.
460 462
 
461 463
   my $route = $r->patch('/:foo' => sub {...});
462 464
 
463
-Generate route matching only C<PATCH> requests. See also the
464
-L<Mojolicious::Lite> tutorial for more argument variations.
465
+Generate route matching only PATCH requests. See also the L<Mojolicious::Lite>
466
+tutorial for more argument variations.
465 467
 
466 468
   $r->patch('/user')->to('user#update');
467 469
 
... ...
@@ -469,8 +471,8 @@ L<Mojolicious::Lite> tutorial for more argument variations.
469 471
 
470 472
   my $route = $r->post('/:foo' => sub {...});
471 473
 
472
-Generate route matching only C<POST> requests. See also the
473
-L<Mojolicious::Lite> tutorial for more argument variations.
474
+Generate route matching only POST requests. See also the L<Mojolicious::Lite>
475
+tutorial for more argument variations.
474 476
 
475 477
   $r->post('/user')->to('user#create');
476 478
 
... ...
@@ -478,8 +480,8 @@ L<Mojolicious::Lite> tutorial for more argument variations.
478 480
 
479 481
   my $route = $r->put('/:foo' => sub {...});
480 482
 
481
-Generate route matching only C<PUT> requests. See also the
482
-L<Mojolicious::Lite> tutorial for more argument variations.
483
+Generate route matching only PUT requests. See also the L<Mojolicious::Lite>
484
+tutorial for more argument variations.
483 485
 
484 486
   $r->put('/user')->to('user#replace');
485 487
 
... ...
@@ -517,7 +519,8 @@ The L<Mojolicious::Routes> object this route is an descendent of.
517 519
   my $route = $r->route('/:action', action => qr/\w+/);
518 520
   my $route = $r->route(format => 0);
519 521
 
520
-Generate route matching all HTTP request methods.
522
+Generate route matching all HTTP request methods with optional pattern and
523
+restrictive placeholders.
521 524
 
522 525
 =head2 to
523 526
 
... ...
@@ -544,8 +547,8 @@ Stringify the whole route.
544 547
 
545 548
 =head2 under
546 549
 
547
-  my $route = $r->under(sub {...});
548
-  my $route = $r->under('/:foo');
550
+  my $bridge = $r->under(sub {...});
551
+  my $bridge = $r->under('/:foo');
549 552
 
550 553
 Generate bridge route. See also the L<Mojolicious::Lite> tutorial for more
551 554
 argument variations.
+5 -3
mojo/lib/Mojolicious/Sessions.pm
... ...
@@ -61,6 +61,8 @@ sub store {
61 61
 
62 62
 1;
63 63
 
64
+=encoding utf8
65
+
64 66
 =head1 NAME
65 67
 
66 68
 Mojolicious::Sessions - Signed cookie based session manager
... ...
@@ -127,8 +129,8 @@ C<expiration> and C<expires> session values.
127 129
 
128 130
 =head2 secure
129 131
 
130
-  my $secure = $sessions->secure;
131
-  $sessions  = $sessions->secure(1);
132
+  my $bool  = $sessions->secure;
133
+  $sessions = $sessions->secure($bool);
132 134
 
133 135
 Set the secure flag on all session cookies, so that browsers send them only
134 136
 over HTTPS connections.
... ...
@@ -136,7 +138,7 @@ over HTTPS connections.
136 138
 =head1 METHODS
137 139
 
138 140
 L<Mojolicious::Sessions> inherits all methods from L<Mojo::Base> and
139
-implements the following ones.
141
+implements the following new ones.
140 142
 
141 143
 =head2 load
142 144
 
+11 -5
mojo/lib/Mojolicious/Static.pm
... ...
@@ -121,6 +121,8 @@ sub _get_file {
121 121
 
122 122
 1;
123 123
 
124
+=encoding utf8
125
+
124 126
 =head1 NAME
125 127
 
126 128
 Mojolicious::Static - Serve static files
... ...
@@ -170,24 +172,28 @@ the following new ones.
170 172
 
171 173
 =head2 dispatch
172 174
 
173
-  my $success = $static->dispatch(Mojolicious::Controller->new);
175
+  my $bool = $static->dispatch(Mojolicious::Controller->new);
174 176
 
175 177
 Serve static file for L<Mojolicious::Controller> object.
176 178
 
177 179
 =head2 file
178 180
 
179
-  my $asset = $static->file('foo/bar.html');
181
+  my $asset = $static->file('images/logo.png');
182
+  my $asset = $static->file('../lib/MyApp.pm');
180 183
 
181 184
 Get L<Mojo::Asset::File> or L<Mojo::Asset::Memory> object for a file, relative
182
-to C<paths> or from C<classes>.
185
+to L</"paths"> or from L</"classes">. Note that this method does not protect
186
+from traversing to parent directories.
183 187
 
184 188
   my $content = $static->file('foo/bar.html')->slurp;
185 189
 
186 190
 =head2 serve
187 191
 
188
-  my $success = $static->serve(Mojolicious::Controller->new, 'foo/bar.html');
192
+  my $bool = $static->serve(Mojolicious::Controller->new, 'images/logo.png');
193
+  my $bool = $static->serve(Mojolicious::Controller->new, '../lib/MyApp.pm');
189 194
 
190
-Serve a specific file, relative to C<paths> or from C<classes>.
195
+Serve a specific file, relative to L</"paths"> or from L</"classes">. Note
196
+that this method does not protect from traversing to parent directories.
191 197
 
192 198
 =head2 serve_asset
193 199
 
+5 -3
mojo/lib/Mojolicious/Types.pm
... ...
@@ -24,7 +24,7 @@ has types => sub {
24 24
     png      => ['image/png'],
25 25
     rss      => ['application/rss+xml'],
26 26
     svg      => ['image/svg+xml'],
27
-    txt      => ['text/plain'],
27
+    txt      => ['text/plain;charset=UTF-8'],
28 28
     webm     => ['video/webm'],
29 29
     woff     => ['application/font-woff'],
30 30
     xml      => ['application/xml', 'text/xml'],
... ...
@@ -37,7 +37,7 @@ sub detect {
37 37
 
38 38
   # Extract and prioritize MIME types
39 39
   my %types;
40
-  /^\s*([^,; ]+)(?:\s*\;\s*q=(\d+(?:\.\d+)?))?\s*$/i
40
+  /^\s*([^,; ]+)(?:\s*\;\s*q\s*=\s*(\d+(?:\.\d+)?))?\s*$/i
41 41
     and $types{lc $1} = defined $2 ? $2 : 1
42 42
     for split /,/, defined $accept ? $accept : '';
43 43
   my @detected = sort { $types{$b} <=> $types{$a} } sort keys %types;
... ...
@@ -62,6 +62,8 @@ sub type {
62 62
 
63 63
 1;
64 64
 
65
+=encoding utf8
66
+
65 67
 =head1 NAME
66 68
 
67 69
 Mojolicious::Types - MIME types
... ...
@@ -99,7 +101,7 @@ L<Mojolicious::Types> manages MIME types for L<Mojolicious>.
99 101
   png      -> image/png
100 102
   rss      -> application/rss+xml
101 103
   svg      -> image/svg+xml
102
-  txt      -> text/plain
104
+  txt      -> text/plain;charset=UTF-8
103 105
   webm     -> video/webm
104 106
   woff     -> application/font-woff
105 107
   xml      -> application/xml,text/xml
+128
mojo/lib/Mojolicious/Validator.pm
... ...
@@ -0,0 +1,128 @@
1
+package Mojolicious::Validator;
2
+use Mojo::Base -base;
3
+
4
+use Mojolicious::Validator::Validation;
5
+
6
+has checks => sub {
7
+  {equal_to => \&_equal_to, in => \&_in, like => \&_like, size => \&_size};
8
+};
9
+
10
+sub add_check {
11
+  my ($self, $name, $cb) = @_;
12
+  $self->checks->{$name} = $cb;
13
+  return $self;
14
+}
15
+
16
+sub validation {
17
+  Mojolicious::Validator::Validation->new(validator => shift);
18
+}
19
+
20
+sub _equal_to {
21
+  my ($validation, $name, $value, $to) = @_;
22
+  return 1 unless defined(my $other = $validation->input->{$to});
23
+  return $value ne $other;
24
+}
25
+
26
+sub _in {
27
+  my ($validation, $name, $value) = (shift, shift, shift);
28
+  $value eq $_ && return undef for @_;
29
+  return 1;
30
+}
31
+
32
+sub _like { $_[2] !~ $_[3] }
33
+
34
+sub _size {
35
+  my ($validation, $name, $value, $min, $max) = @_;
36
+  my $len = length $value;
37
+  return $len < $min || $len > $max;
38
+}
39
+
40
+1;
41
+
42
+=encoding utf8
43
+
44
+=head1 NAME
45
+
46
+Mojolicious::Validator - Validate form data
47
+
48
+=head1 SYNOPSIS
49
+
50
+  use Mojolicious::Validator;
51
+
52
+  my $validator  = Mojolicious::Validator->new;
53
+  my $validation = $validator->validation;
54
+  $validation->input({foo => 'bar'});
55
+  $validation->required('foo')->like(qr/ar$/);
56
+  say $validation->param('foo');
57
+
58
+=head1 DESCRIPTION
59
+
60
+L<Mojolicious::Validator> validates form data for L<Mojolicious>.
61
+
62
+=head1 CHECKS
63
+
64
+These validation checks are available by default.
65
+
66
+=head2 equal_to
67
+
68
+  $validation->equal_to('foo');
69
+
70
+Value needs to be equal to the value of another field.
71
+
72
+=head2 in
73
+
74
+  $validation->in(qw(foo bar baz));
75
+
76
+Value needs to match one of the values in the list.
77
+
78
+=head2 like
79
+
80
+  $validation->like(qr/^[A-Z]/);
81
+
82
+Value needs to match the regular expression.
83
+
84
+=head2 size
85
+
86
+  $validation->size(2, 5);
87
+
88
+Value length in characters needs to be between these two values.
89
+
90
+=head1 ATTRIBUTES
91
+
92
+L<Mojolicious::Validator> implements the following attributes.
93
+
94
+=head2 checks
95
+
96
+  my $checks = $validator->checks;
97
+  $validator = $validator->checks({size => sub {...}});
98
+
99
+Registered validation checks, by default only L</"equal_to">, L</"in">,
100
+L</"like"> and L</"size"> are already defined.
101
+
102
+=head1 METHODS
103
+
104
+L<Mojolicious::Validator> inherits all methods from L<Mojo::Base> and
105
+implements the following new ones.
106
+
107
+=head2 add_check
108
+
109
+  $validator = $validator->add_check(size => sub {...});
110
+
111
+Register a new validation check.
112
+
113
+=head2 validation
114
+
115
+  my $validation = $validator->validation;
116
+
117
+Build L<Mojolicious::Validator::Validation> object to perform validations.
118
+
119
+  my $validation = $validator->validation;
120
+  $validation->input({foo => 'bar'});
121
+  $validation->required('foo')->size(1, 5);
122
+  say $validation->param('foo');
123
+
124
+=head1 SEE ALSO
125
+
126
+L<Mojolicious>, L<Mojolicious::Guides>, L<http://mojolicio.us>.
127
+
128
+=cut
+216
mojo/lib/Mojolicious/Validator/Validation.pm
... ...
@@ -0,0 +1,216 @@
1
+package Mojolicious::Validator::Validation;
2
+use Mojo::Base -base;
3
+
4
+use Carp 'croak';
5
+use Scalar::Util 'blessed';
6
+
7
+has [qw(input output)] => sub { {} };
8
+has [qw(topic validator)];
9
+
10
+sub AUTOLOAD {
11
+  my $self = shift;
12
+
13
+  my ($package, $method) = our $AUTOLOAD =~ /^([\w:]+)::(\w+)$/;
14
+  croak "Undefined subroutine &${package}::$method called"
15
+    unless blessed $self && $self->isa(__PACKAGE__);
16
+
17
+  croak qq{Can't locate object method "$method" via package "$package"}
18
+    unless $self->validator->checks->{$method};
19
+  return $self->check($method => @_);
20
+}
21
+
22
+sub DESTROY { }
23
+
24
+sub check {
25
+  my ($self, $check) = (shift, shift);
26
+
27
+  return $self unless $self->is_valid;
28
+
29
+  my $cb    = $self->validator->checks->{$check};
30
+  my $name  = $self->topic;
31
+  my $input = $self->input->{$name};
32
+  for my $value (ref $input eq 'ARRAY' ? @$input : $input) {
33
+    next unless my $result = $self->$cb($name, $value, @_);
34
+    delete $self->output->{$name};
35
+    $self->{error}{$name} = [$check, $result, @_];
36
+    last;
37
+  }
38
+
39
+  return $self;
40
+}
41
+
42
+sub error { shift->{error}{shift()} }
43
+
44
+sub has_data { !!keys %{shift->input} }
45
+
46
+sub has_error { $_[1] ? exists $_[0]{error}{$_[1]} : !!keys %{$_[0]{error}} }
47
+
48
+sub is_valid { exists $_[0]->output->{defined $_[1] ? $_[1] : $_[0]->topic} }
49
+
50
+sub optional {
51
+  my ($self, $name) = @_;
52
+
53
+  my $input = $self->input->{$name};
54
+  my @input = ref $input eq 'ARRAY' ? @$input : $input;
55
+  $self->output->{$name} = $input
56
+    unless grep { !defined($_) || !length($_) } @input;
57
+
58
+  return $self->topic($name);
59
+}
60
+
61
+sub param {
62
+  my ($self, $name) = @_;
63
+
64
+  # Multiple names
65
+  return map { scalar $self->param($_) } @$name if ref $name eq 'ARRAY';
66
+
67
+  # List names
68
+  return sort keys %{$self->output} unless defined $name;
69
+
70
+  my $value = $self->output->{$name};
71
+  my @values = ref $value eq 'ARRAY' ? @$value : ($value);
72
+  return wantarray ? @values : $values[0];
73
+}
74
+
75
+sub required {
76
+  my ($self, $name) = @_;
77
+  $self->{error}{$name} = ['required'] unless $self->optional($name)->is_valid;
78
+  return $self;
79
+}
80
+
81
+1;
82
+
83
+=encoding utf8
84
+
85
+=head1 NAME
86
+
87
+Mojolicious::Validator::Validation - Perform validations
88
+
89
+=head1 SYNOPSIS
90
+
91
+  use Mojolicious::Validator;
92
+  use Mojolicious::Validator::Validation;
93
+
94
+  my $validator = Mojolicious::Validator->new;
95
+  my $validation
96
+    = Mojolicious::Validator::Validation->new(validator => $validator);
97
+  $validation->input({foo => 'bar'});
98
+  $validation->required('foo')->in(qw(bar baz));
99
+  say $validation->param('foo');
100
+
101
+=head1 DESCRIPTION
102
+
103
+L<Mojolicious::Validator::Validation> performs L<Mojolicious::Validator>
104
+validation checks.
105
+
106
+=head1 ATTRIBUTES
107
+
108
+L<Mojolicious::Validator::Validation> implements the following attributes.
109
+
110
+=head2 input
111
+
112
+  my $input   = $validation->input;
113
+  $validation = $validation->input({foo => 'bar', baz => [123, 'yada']});
114
+
115
+Data to be validated.
116
+
117
+=head2 output
118
+
119
+  my $output  = $validation->output;
120
+  $validation = $validation->output({});
121
+
122
+Validated data.
123
+
124
+=head2 topic
125
+
126
+  my $topic   = $validation->topic;
127
+  $validation = $validation->topic('foo');
128
+
129
+Name of field currently being validated.
130
+
131
+=head2 validator
132
+
133
+  my $validator = $validation->validator;
134
+  $validation   = $validation->validator(Mojolicious::Validator->new);
135
+
136
+L<Mojolicious::Validator> object this validation belongs to.
137
+
138
+=head1 METHODS
139
+
140
+L<Mojolicious::Validator::Validation> inherits all methods from L<Mojo::Base>
141
+and implements the following new ones.
142
+
143
+=head2 check
144
+
145
+  $validation = $validation->check('size', 2, 7);
146
+
147
+Perform validation check on all values of the current L</"topic">, no more
148
+checks will be performend on them after the first one failed.
149
+
150
+=head2 error
151
+
152
+  my $err = $validation->error('foo');
153
+
154
+Return details about failed validation check, at any given time there can only
155
+be one per field.
156
+
157
+  my ($check, $result, @args) = @{$validation->error('foo')};
158
+
159
+=head2 has_data
160
+
161
+  my $bool = $validation->has_data;
162
+
163
+Check if L</"input"> is available for validation.
164
+
165
+=head2 has_error
166
+
167
+  my $bool = $validation->has_error;
168
+  my $bool = $validation->has_error('foo');
169
+
170
+Check if validation resulted in errors, defaults to checking all fields.
171
+
172
+=head2 is_valid
173
+
174
+  my $bool = $validation->is_valid;
175
+  my $bool = $validation->is_valid('foo');
176
+
177
+Check if validation was successful and field has a value, defaults to checking
178
+the current L</"topic">.
179
+
180
+=head2 optional
181
+
182
+  $validation = $validation->optional('foo');
183
+
184
+Change validation L</"topic">.
185
+
186
+=head2 param
187
+
188
+  my @names       = $c->param;
189
+  my $foo         = $c->param('foo');
190
+  my @foo         = $c->param('foo');
191
+  my ($foo, $bar) = $c->param(['foo', 'bar']);
192
+
193
+Access validated parameters, similar to L<Mojolicious::Controller/"param">.
194
+
195
+=head2 required
196
+
197
+  $validation = $validation->required('foo');
198
+
199
+Change validation L</"topic"> and make sure a value is present and not an
200
+empty string.
201
+
202
+=head1 CHECKS
203
+
204
+In addition to the methods above, you can also call validation checks provided
205
+by L<Mojolicious::Validator> on L<Mojolicious::Validator::Validation> objects,
206
+similar to L</"check">.
207
+
208
+  $validation->required('foo')->size(2, 5)->like(qr/^[A-Z]/);
209
+  $validation->optional('bar')->equal_to('foo');
210
+  $validation->optional('baz')->in(qw(test 123));
211
+
212
+=head1 SEE ALSO
213
+
214
+L<Mojolicious>, L<Mojolicious::Guides>, L<http://mojolicio.us>.
215
+
216
+=cut
+5 -5
mojo/lib/Mojolicious/public/mojo/jquery/jquery.js
... ...
@@ -1,6 +1,6 @@
1
-/*! jQuery v2.0.1 | (c) 2005, 2013 jQuery Foundation, Inc. | jquery.org/license
2
-//@ sourceMappingURL=jquery-2.0.1.min.map
1
+/*! jQuery v2.0.3 | (c) 2005, 2013 jQuery Foundation, Inc. | jquery.org/license
2
+//@ sourceMappingURL=jquery-2.0.3.min.map
3 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);
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=[],p="2.0.3",f=c.concat,h=c.push,d=c.slice,g=c.indexOf,m=l.toString,y=l.hasOwnProperty,v=p.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:p,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"+(p+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 f.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,p,f,h,d,g,m,y,v="sizzle"+-new Date,b=e.document,w=0,T=0,C=st(),k=st(),N=st(),E=!1,S=function(e,t){return e===t?(E=!0,0):0},j=typeof undefined,D=1<<31,A={}.hasOwnProperty,L=[],q=L.pop,H=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){H.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,f,g,m,x,w;if((t?t.ownerDocument||t:b)!==p&&c(t),t=t||p,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()){f=gt(e),(g=t.getAttribute("id"))?m=g.replace(tt,"\\$&"):t.setAttribute("id",m),m="[id='"+m+"'] ",l=f.length;while(l--)f[l]=m+mt(f[l]);x=U.test(e)&&t.parentNode||t,w=f.join(",")}if(w)try{return O.apply(r,x.querySelectorAll(w)),r}catch(T){}finally{g||t.removeAttribute("id")}}}return kt(e.replace(z,"$1"),t,r,i)}function st(){var e=[];function t(n,r){return e.push(n+=" ")>i.cacheLength&&delete t[e.shift()],t[n]=r}return t}function at(e){return e[v]=!0,e}function ut(e){var t=p.createElement("div");try{return!!e(t)}catch(n){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function lt(e,t){var n=e.split("|"),r=e.length;while(r--)i.attrHandle[n[r]]=t}function ct(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 pt(e){return function(t){var n=t.nodeName.toLowerCase();return"input"===n&&t.type===e}}function ft(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function ht(e){return at(function(t){return t=+t,at(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,r=t.defaultView;return t!==p&&9===t.nodeType&&t.documentElement?(p=t,f=t.documentElement,h=!s(t),r&&r.attachEvent&&r!==r.top&&r.attachEvent("onbeforeunload",function(){c()}),n.attributes=ut(function(e){return e.className="i",!e.getAttribute("className")}),n.getElementsByTagName=ut(function(e){return e.appendChild(t.createComment("")),!e.getElementsByTagName("*").length}),n.getElementsByClassName=ut(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=ut(function(e){return f.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=Q.test(t.querySelectorAll))&&(ut(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")}),ut(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=Q.test(m=f.webkitMatchesSelector||f.mozMatchesSelector||f.oMatchesSelector||f.msMatchesSelector))&&ut(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=Q.test(f.contains)||f.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},S=f.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 ct(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?ct(a[i],u[i]):a[i]===b?-1:u[i]===b?1:0},t):p},ot.matches=function(e,t){return ot(e,null,null,t)},ot.matchesSelector=function(e,t){if((e.ownerDocument||e)!==p&&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,p,null,[e]).length>0},ot.contains=function(e,t){return(e.ownerDocument||e)!==p&&c(e),y(e,t)},ot.attr=function(e,t){(e.ownerDocument||e)!==p&&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:at,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=gt(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,p,f,h,d,g=o!==s?"nextSibling":"previousSibling",m=t.parentNode,y=a&&t.nodeName.toLowerCase(),x=!u&&!a;if(m){if(o){while(g){p=t;while(p=p[g])if(a?p.nodeName.toLowerCase()===y:1===p.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],f=l[0]===w&&l[2],p=h&&m.childNodes[h];while(p=++h&&p&&p[g]||(f=h=0)||d.pop())if(1===p.nodeType&&++f&&p===t){c[e]=[w,h,f];break}}else if(x&&(l=(t[v]||(t[v]={}))[e])&&l[0]===w)f=l[1];else while(p=++h&&p&&p[g]||(f=h=0)||d.pop())if((a?p.nodeName.toLowerCase()===y:1===p.nodeType)&&++f&&(x&&((p[v]||(p[v]={}))[e]=[w,f]),p===t))break;return f-=i,f===r||0===f%r&&f/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())?at(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:at(function(e){var t=[],n=[],r=a(e.replace(z,"$1"));return r[v]?at(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:at(function(e){return function(t){return ot(e,t).length>0}}),contains:at(function(e){return function(t){return(t.textContent||t.innerText||o(t)).indexOf(e)>-1}}),lang:at(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===f},focus:function(e){return e===p.activeElement&&(!p.hasFocus||p.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:ht(function(){return[0]}),last:ht(function(e,t){return[t-1]}),eq:ht(function(e,t,n){return[0>n?n+t:n]}),even:ht(function(e,t){var n=0;for(;t>n;n+=2)e.push(n);return e}),odd:ht(function(e,t){var n=1;for(;t>n;n+=2)e.push(n);return e}),lt:ht(function(e,t,n){var r=0>n?n+t:n;for(;--r>=0;)e.push(r);return e}),gt:ht(function(e,t,n){var r=0>n?n+t:n;for(;t>++r;)e.push(r);return e})}},i.pseudos.nth=i.pseudos.eq;for(t in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})i.pseudos[t]=pt(t);for(t in{submit:!0,reset:!0})i.pseudos[t]=ft(t);function dt(){}dt.prototype=i.filters=i.pseudos,i.setFilters=new dt;function gt(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 mt(e){var t=0,n=e.length,r="";for(;n>t;t++)r+=e[t].value;return r}function yt(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,p=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]===p){if((u=l[1])===!0||u===r)return u===!0}else if(l=c[i]=[p],l[1]=e(t,n,a)||r,l[1]===!0)return!0}}function vt(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 xt(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 bt(e,t,n,r,i,o){return r&&!r[v]&&(r=bt(r)),i&&!i[v]&&(i=bt(i,o)),at(function(o,s,a,u){var l,c,p,f=[],h=[],d=s.length,g=o||Ct(t||"*",a.nodeType?[a]:a,[]),m=!e||!o&&t?g:xt(g,f,e,a,u),y=n?i||(o?e:d||r)?[]:s:m;if(n&&n(m,y,a,u),r){l=xt(y,h),r(l,[],a,u),c=l.length;while(c--)(p=l[c])&&(y[h[c]]=!(m[h[c]]=p))}if(o){if(i||e){if(i){l=[],c=y.length;while(c--)(p=y[c])&&l.push(m[c]=p);i(null,y=[],l,u)}c=y.length;while(c--)(p=y[c])&&(l=i?P.call(o,p):f[c])>-1&&(o[l]=!(s[l]=p))}}else y=xt(y===s?y.splice(d,y.length):y),i?i(null,s,y,u):O.apply(s,y)})}function wt(e){var t,n,r,o=e.length,s=i.relative[e[0].type],a=s||i.relative[" "],l=s?1:0,c=yt(function(e){return e===t},a,!0),p=yt(function(e){return P.call(t,e)>-1},a,!0),f=[function(e,n,r){return!s&&(r||n!==u)||((t=n).nodeType?c(e,n,r):p(e,n,r))}];for(;o>l;l++)if(n=i.relative[e[l].type])f=[yt(vt(f),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 bt(l>1&&vt(f),l>1&&mt(e.slice(0,l-1).concat({value:" "===e[l-2].type?"*":""})).replace(z,"$1"),n,r>l&&wt(e.slice(l,r)),o>r&&wt(e=e.slice(r)),o>r&&mt(e))}f.push(n)}return vt(f)}function Tt(e,t){var n=0,o=t.length>0,s=e.length>0,a=function(a,l,c,f,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!==p&&l,r=n);null!=(d=k[x]);x++){if(s&&d){g=0;while(m=e[g++])if(m(d,l,c)){f.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]=q.call(f));y=xt(y)}O.apply(f,y),T&&!a&&y.length>0&&v+t.length>1&&ot.uniqueSort(f)}return T&&(w=N,u=C),b};return o?at(a):a}a=ot.compile=function(e,t){var n,r=[],i=[],o=N[e+" "];if(!o){t||(t=gt(e)),n=t.length;while(n--)o=wt(t[n]),o[v]?r.push(o):i.push(o);o=N(e,Tt(i,r))}return o};function Ct(e,t,n){var r=0,i=t.length;for(;i>r;r++)ot(e,t[r],n);return n}function kt(e,t,r,o){var s,u,l,c,p,f=gt(e);if(!o&&1===f.length){if(u=f[0]=f[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((p=i.find[c])&&(o=p(l.matches[0].replace(nt,rt),U.test(u[0].type)&&t.parentNode||t))){if(u.splice(s,1),e=o.length&&mt(u),!e)return O.apply(r,o),r;break}}}return a(e,f)(o,t,!h,r,U.test(e)),r}n.sortStable=v.split("").sort(S).join("")===v,n.detectDuplicates=E,c(),n.sortDetached=ut(function(e){return 1&e.compareDocumentPosition(p.createElement("div"))}),ut(function(e){return e.innerHTML="<a href='#'></a>","#"===e.firstChild.getAttribute("href")})||lt("type|href|height|width",function(e,t,n){return n?undefined:e.getAttribute(t,"type"===t.toLowerCase()?1:2)}),n.attributes&&ut(function(e){return e.innerHTML="<input/>",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||lt("value",function(e,t,n){return n||"input"!==e.nodeName.toLowerCase()?undefined:e.defaultValue}),ut(function(e){return null==e.getAttribute("disabled")})||lt(R,function(e,t,n){var r;return n?undefined:(r=e.getAttributeNode(t))&&r.specified?r.value:e[t]===!0?t.toLowerCase():null}),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(p){for(t=e.memory&&p,n=!0,s=i||0,i=0,o=a.length,r=!0;a&&o>s;s++)if(a[s].apply(p[0],p[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!a||n&&!u||(t=t||[],t=[e,t.slice?t.slice():t],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,q,H=/(?:\{[\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){var r;return t===undefined||t&&"string"==typeof t&&n===undefined?(r=this.get(e,t),r!==undefined?r:this.get(e,x.camelCase(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,q=new F,x.extend({acceptData:F.accepts,hasData:function(e){return L.hasData(e)||q.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 q.access(e,t,n)},_removeData:function(e,t){q.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&&!q.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]));q.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:H.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=q.get(e,t),n&&(!r||x.isArray(n)?r=q.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)
5
+};"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,s,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return q.get(e,n)||q.access(e,n,{empty:x.Callbacks("once memory").add(function(){q.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=q.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;return"boolean"==typeof t&&"string"===n?t?this.addClass(e):this.removeClass(e):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 t,i=0,o=x(this),s=e.match(w)||[];while(t=s[i++])o.hasClass(t)?o.removeClass(t):o.addClass(t)}else(n===r||"boolean"===n)&&(this.className&&q.set(this,"__className__",this.className),this.className=this.className||e===!1?"":q.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,p,f,h,d,g,m,y=q.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&&(f=x.event.special[d]||{},d=(o?f.delegateType:f.bindType)||d,f=x.event.special[d]||{},p=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,f.setup&&f.setup.call(e,i,g,a)!==!1||e.addEventListener&&e.addEventListener(d,a,!1)),f.add&&(f.add.call(e,p),p.handler.guid||(p.handler.guid=n.guid)),o?h.splice(h.delegateCount++,0,p):h.push(p),x.event.global[d]=!0);e=null}},remove:function(e,t,n,r,i){var o,s,a,u,l,c,p,f,h,d,g,m=q.hasData(e)&&q.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){p=x.event.special[h]||{},h=(r?p.delegateType:p.bindType)||h,f=u[h]||[],a=a[2]&&RegExp("(^|\\.)"+d.join("\\.(?:.*\\.|)")+"(\\.|$)"),s=o=f.length;while(o--)c=f[o],!i&&g!==c.origType||n&&n.guid!==c.guid||a&&!a.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(f.splice(o,1),c.selector&&f.delegateCount--,p.remove&&p.remove.call(e,c));s&&!f.length&&(p.teardown&&p.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,q.remove(e,"events"))}},trigger:function(t,n,r,i){var s,a,u,l,c,p,f,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]),f=x.event.special[d]||{},i||!f.trigger||f.trigger.apply(r,n)!==!1)){if(!i&&!f.noBubble&&!x.isWindow(r)){for(l=f.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:f.bindType||d,p=(q.get(a,"events")||{})[t.type]&&q.get(a,"handle"),p&&p.apply(a,n),p=c&&a[c],p&&x.acceptData(a)&&p.apply&&p.apply(a,n)===!1&&t.preventDefault();return t.type=d,i||t.isDefaultPrevented()||f._default&&f._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=(q.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 e.contentDocument||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=pt(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=pt(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=f.apply([],e);var r,i,o,s,a,u,l=0,c=this.length,p=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=p.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"),ft),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||"")&&!q.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,p=e.length,f=t.createDocumentFragment(),h=[];for(;p>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||f.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.lastChild;x.merge(h,o.childNodes),o=f.firstChild,o.textContent=""}else h.push(t.createTextNode(i));f.textContent="",c=0;while(i=h[c++])if((!r||-1===x.inArray(i,r))&&(u=x.contains(i.ownerDocument,i),o=mt(f.appendChild(i),"script"),u&&dt(o),n)){l=0;while(i=o[l++])at.test(i.type||"")&&n.push(i)}return f},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[q.expando],o&&(t=q.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);q.cache[o]&&delete q.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 pt(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 ft(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++)q.set(e[r],"globalEval",!t||q.get(t[r],"globalEval"))}function gt(e,t){var n,r,i,o,s,a,u,l;if(1===t.nodeType){if(q.hasData(e)&&(o=q.access(e),s=q.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 qt(t){return e.getComputedStyle(t,null)}function Ht(e,t){var n,r,i,o=[],s=0,a=e.length;for(;a>s;s++)r=e[s],r.style&&(o[s]=q.get(r,"olddisplay"),n=r.style.display,t?(o[s]||"none"!==n||(r.style.display=""),""===r.style.display&&Lt(r)&&(o[s]=q.access(r,"olddisplay",Rt(r.nodeName)))):o[s]||(i=Lt(r),(n&&"none"!==n||!i)&&q.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=qt(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 Ht(this,!0)},hide:function(){return Ht(this)},toggle:function(e){return"boolean"==typeof e?e?this.show():this.hide():this.each(function(){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,order:!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||qt(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=qt(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&&qt(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)
6
+},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)}});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),p=c.context||c,f=c.context&&(p.nodeType||p.jquery)?x(p):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(p,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&&f.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=pn(c,T,o)),b=fn(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(p,[m,C,T]):h.rejectWith(p,[T,C,y]),T.statusCode(g),g=undefined,u&&f.trigger(l?"ajaxSuccess":"ajaxError",[T,c,l?m:y]),d.fireWith(p,[T,C]),u&&(f.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 pn(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 fn(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(p){return{state:"parsererror",error:s?p:"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&&(s=n.start=+s||+r||0,n.unit=o,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={},p=e.style,f=e.nodeType&&Lt(e),h=q.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=[p.overflow,p.overflowX,p.overflowY],"inline"===x.css(e,"display")&&"none"===x.css(e,"float")&&(p.display="inline-block")),n.overflow&&(p.overflow="hidden",l.always(function(){p.overflow=n.overflow[0],p.overflowX=n.overflow[1],p.overflowY=n.overflow[2]}));for(r in t)if(i=t[r],wn.exec(i)){if(delete t[r],o=o||"toggle"===i,i===(f?"hide":"show")){if("show"!==i||!h||h[r]===undefined)continue;f=!0}c[r]=h&&h[r]||x.style(e,r)}if(!x.isEmptyObject(c)){h?"hidden"in h&&(f=h.hidden):h=q.access(e,"fxshow",{}),o&&(h.hidden=!f),f?x(e).show():l.done(function(){x(e).hide()}),l.done(function(){var t;q.remove(e,"fxshow");for(t in c)x.style(e,t,c[t])});for(r in c)s=Sn(f?h[r]:0,r,l),r in h||(h[r]=s.start,f&&(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(qn(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);(i||q.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=q.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=q.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.stop&&i.stop.call(this,!0),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 qn(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:qn("show"),slideUp:qn("hide"),slideToggle:qn("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=Hn(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"),p=x(e),f={};"static"===c&&(e.style.position="relative"),a=p.offset(),o=x.css(e,"top"),u=x.css(e,"left"),l=("absolute"===c||"fixed"===c)&&(o+u).indexOf("auto")>-1,l?(r=p.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&&(f.top=t.top-a.top+s),null!=t.left&&(f.left=t.left-a.left+i),"using"in t?t.using.call(e,f):p.css(f)}},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=Hn(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 Hn(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);
BIN
mojo/lib/Mojolicious/public/mojo/pinstripe-dark.png
BIN
mojo/lib/Mojolicious/public/mojo/pinstripe-light.png
+1
mojo/lib/Mojolicious/public/mojo/prettify/prettify-mojo-dark.css
... ...
@@ -0,0 +1 @@
1
+.str,.atv{color:#9daa7e}.kwd,.tag{color:#d5b57c}.com{color:#726d73}.typ,.atn,.dec{color:#dd7e5e}.lit{color:#fcf0a4}.pun,.opn,.clo{color:#a78353}.pln{color:#889dbc}pre.prettyprint{border:0;padding-bottom:0.75em;padding-top:0.75em}
+1
mojo/lib/Mojolicious/public/mojo/prettify/prettify-mojo-light.css
... ...
@@ -0,0 +1 @@
1
+.str{color:#718c00}.kwd{color:#8959a8}.com{color:#8e908c}.typ,.dec{color:#f5871f}.lit,.atn{color:#eab700}.pun,.opn,.clo,.pln{color:#4d4d4c}.tag,.var,.fun{color:#c82829}.atv{color:#3e999f}pre.prettyprint{border:1px solid #d1d1d1;padding:0;padding-bottom:1.5em;padding-top:1.5em}
BIN
mojo/lib/Mojolicious/public/mojo/stripes.png
+6 -12
mojo/lib/Mojolicious/templates/exception.development.html.ep
... ...
@@ -6,11 +6,11 @@
6 6
     <meta http-equiv="Expires" content="-1">
7 7
     %= javascript '/mojo/jquery/jquery.js'
8 8
     %= javascript '/mojo/prettify/run_prettify.js'
9
-    %= stylesheet '/mojo/prettify/prettify-mojo.css'
9
+    %= stylesheet '/mojo/prettify/prettify-mojo-dark.css'
10 10
     %= stylesheet begin
11 11
       a img { border: 0 }
12 12
       body {
13
-        background-color: #f5f6f8;
13
+        background: url(<%= url_for '/mojo/pinstripe-light.png' %>);
14 14
         color: #445555;
15 15
         font: 0.9em 'Helvetica Neue', Helvetica, sans-serif;
16 16
         font-weight: normal;
... ...
@@ -18,7 +18,7 @@
18 18
         margin: 0;
19 19
       }
20 20
       pre {
21
-        font: 0.8em Consolas, Menlo, Monaco, Courier, monospace;
21
+        font: 0.9em Consolas, Menlo, Monaco, Courier, monospace;
22 22
         margin: 0;
23 23
         white-space: pre-wrap;
24 24
       }
... ...
@@ -31,15 +31,13 @@
31 31
       td { padding: 0.5em }
32 32
       .box {
33 33
         background-color: #fff;
34
-        -moz-box-shadow: 0px 0px 2px #ccc;
35
-        -webkit-box-shadow: 0px 0px 2px #ccc;
36
-        box-shadow: 0px 0px 2px #ccc;
34
+        box-shadow: 0px 0px 2px #999;
37 35
         overflow: hidden;
38 36
         padding: 1em;
39 37
       }
40 38
       .code {
41 39
         background-color: #1a1a1a;
42
-        background: url(<%= url_for '/mojo/pinstripe.gif' %>);
40
+        background: url(<%= url_for '/mojo/pinstripe-dark.png' %>);
43 41
         color: #eee;
44 42
         text-shadow: #333 0 1px 0;
45 43
       }
... ...
@@ -78,16 +76,12 @@
78 76
       }
79 77
       #showcase .key { padding-right: 0 }
80 78
       #more, #trace {
81
-        -moz-border-radius-bottomleft: 5px;
82 79
         border-bottom-left-radius: 5px;
83
-        -moz-border-radius-bottomright: 5px;
84 80
         border-bottom-right-radius: 5px;
85 81
       }
86 82
       #more .tap, #trace .tap { text-shadow: #ddd 0 1px 0 }
87 83
       #request {
88
-        -moz-border-radius-topleft: 5px;
89 84
         border-top-left-radius: 5px;
90
-        -moz-border-radius-topright: 5px;
91 85
         border-top-right-radius: 5px;
92 86
         margin-top: 1em;
93 87
       }
... ...
@@ -193,7 +187,7 @@
193 187
           %= $kv->(Stash => dumper $snapshot)
194 188
           %= $kv->(Session => dumper session)
195 189
           %= $kv->(Version => $req->version)
196
-          % for my $name (@{$self->req->headers->names}) {
190
+          % for my $name (sort @{$self->req->headers->names}) {
197 191
             % my $value = $self->req->headers->header($name);
198 192
             %= $kv->($name, $value)
199 193
           % }
+18 -21
mojo/lib/Mojolicious/templates/mojobar.html.ep
... ...
@@ -3,21 +3,9 @@
3 3
   %= stylesheet scoped => 'scoped', begin
4 4
     #mojobar {
5 5
       background-color: #1a1a1a;
6
-      background: -webkit-gradient(
7
-        linear,
8
-        0% 0%,
9
-        0% 100%,
10
-        color-stop(0%, #2a2a2a),
11
-        color-stop(100%, #000)
12
-      );
13
-      background: -moz-linear-gradient(
14
-        top,
15
-        #2a2a2a 0%,
16
-        #000 100%
17
-      );
6
+      background: -webkit-linear-gradient(top, #2a2a2a 0%, #000 100%);
7
+      background: -moz-linear-gradient(top, #2a2a2a 0%, #000 100%);
18 8
       background: linear-gradient(top, #2a2a2a 0%, #000 100%);
19
-      -moz-box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.6);
20
-      -webkit-box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.6);
21 9
       box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.6);
22 10
       height: 46px;
23 11
       overflow: hidden;
... ...
@@ -37,22 +25,26 @@
37 25
       float: right;
38 26
       height: 60px;
39 27
       margin-right: 5em;
40
-      margin-top: 1em;
28
+      margin-top: 0.8em;
41 29
     }
42 30
     #mojobar-links a {
43 31
       color: #ccc;
44 32
       font: 1em 'Helvetica Neue', Helvetica, sans-serif;
45 33
       font-weight: 300;
46 34
       margin-left: 0.5em;
47
-      padding-bottom: 1em;
48
-      padding-top: 1em;
49 35
       text-decoration: none;
50
-      -webkit-transition: all 200ms ease-in-out;
51
-      -moz-transition: all 200ms ease-in-out;
52
-      -o-transition: all 200ms ease-in-out;
53 36
       transition: all 200ms ease-in-out;
54 37
     }
55 38
     #mojobar-links a:hover { color: #fff }
39
+    #mojobar-links input {
40
+      border: 0;
41
+      border-radius: 10px;
42
+      display: inline;
43
+      margin-left: 1em;
44
+      padding: 3px;
45
+    }
46
+    #mojobar-links input:focus { outline: 0 }
47
+    #mojobar-links form { display: inline }
56 48
   % end
57 49
   <div id="mojobar-logo">
58 50
     %= link_to 'http://mojolicio.us' => begin
... ...
@@ -61,13 +53,17 @@
61 53
   </div>
62 54
   <div id="mojobar-links">
63 55
     %= link_to Documentation => 'http://mojolicio.us/perldoc'
64
-    %= link_to Screencasts => 'http://mojocasts.com'
65 56
     %= link_to Wiki => 'https://github.com/kraih/mojo/wiki'
66 57
     %= link_to GitHub => 'https://github.com/kraih/mojo'
67 58
     %= link_to CPAN => 'http://metacpan.org/release/Mojolicious/'
68 59
     %= link_to MailingList => 'http://groups.google.com/group/mojolicious'
69 60
     %= link_to Blog => 'http://blog.kraih.com'
70 61
     %= link_to Twitter => 'http://twitter.com/kraih'
62
+    %= form_for 'http://google.com/cse' => (target => '_blank') => begin
63
+      %= hidden_field cx => '014527573091551588235:pwfplkjpgbi'
64
+      %= hidden_field ie => 'UTF-8'
65
+      %= search_field 'q', placeholder => 'Search'
66
+    %= end
71 67
   </div>
72 68
 </div>
73 69
 %= javascript begin
... ...
@@ -92,6 +88,7 @@
92 88
     });
93 89
   });
94 90
   $(document).ready(function() {
91
+    $('a[href^="#"]').addClass('mojoscroll');
95 92
     $(".mojoscroll").click(function(e) {
96 93
       e.preventDefault();
97 94
       e.stopPropagation();
+4 -11
mojo/lib/Mojolicious/templates/not_found.development.html.ep
... ...
@@ -2,11 +2,9 @@
2 2
 <html>
3 3
   <head>
4 4
     <title>Page not found</title>
5
-    %= javascript '/mojo/prettify/run_prettify.js'
6
-    %= stylesheet '/mojo/prettify/prettify-mojo.css'
7 5
     %= stylesheet begin
8 6
       body {
9
-        background-color: #f5f6f8;
7
+        background: url(<%= url_for '/mojo/pinstripe-light.png' %>);
10 8
         color: #445555;
11 9
         font: 0.9em 'Helvetica Neue', Helvetica, sans-serif;
12 10
         font-weight: normal;
... ...
@@ -16,10 +14,9 @@
16 14
       code {
17 15
         background-color: #eef9ff;
18 16
         border: solid #cce4ff 1px;
19
-        -moz-border-radius: 5px;
20 17
         border-radius: 5px;
21 18
         color: #333;
22
-        font: 0.8em Consolas, Menlo, Monaco, Courier, monospace;
19
+        font: 0.9em Consolas, Menlo, Monaco, Courier, monospace;
23 20
         padding: 0.4em;
24 21
       }
25 22
       h1 {
... ...
@@ -28,7 +25,7 @@
28 25
         margin: 0;
29 26
       }
30 27
       pre {
31
-        font: 0.8em Consolas, Menlo, Monaco, Courier, monospace;
28
+        font: 0.9em Consolas, Menlo, Monaco, Courier, monospace;
32 29
         margin: 0;
33 30
         white-space: pre-wrap;
34 31
       }
... ...
@@ -55,13 +52,9 @@
55 52
       }
56 53
       #routes {
57 54
         background-color: #fff;
58
-        -moz-border-radius-bottomleft: 5px;
59 55
         border-bottom-left-radius: 5px;
60
-        -moz-border-radius-bottomright: 5px;
61 56
         border-bottom-right-radius: 5px;
62
-        -moz-box-shadow: 0px 0px 2px #ccc;
63
-        -webkit-box-shadow: 0px 0px 2px #ccc;
64
-        box-shadow: 0px 0px 2px #ccc;
57
+        box-shadow: 0px 0px 2px #999;
65 58
         margin-left: 5em;
66 59
         margin-right: 5em;
67 60
         padding: 1em;
+23 -21
mojo/lib/Mojolicious/templates/perldoc.html.ep
... ...
@@ -3,13 +3,13 @@
3 3
   <head>
4 4
     <title><%= $title %></title>
5 5
     %= javascript '/mojo/prettify/run_prettify.js'
6
-    %= stylesheet '/mojo/prettify/prettify-mojo.css'
6
+    %= stylesheet '/mojo/prettify/prettify-mojo-light.css'
7 7
     %= stylesheet begin
8 8
       a { color: inherit }
9 9
       a:hover { color: #2a2a2a }
10 10
       a img { border: 0 }
11 11
       body {
12
-        background-color: #f5f6f8;
12
+        background: url(<%= url_for '/mojo/pinstripe-light.png' %>);
13 13
         color: #445555;
14 14
         font: 0.9em 'Helvetica Neue', Helvetica, sans-serif;
15 15
         font-weight: normal;
... ...
@@ -23,17 +23,16 @@
23 23
       }
24 24
       h1 a, h2 a, h3 a { text-decoration: none }
25 25
       pre {
26
-        background-color: #eee;
27
-        background: url(<%= url_for '/mojo/pinstripe.gif' %>);
28
-        -moz-border-radius: 5px;
29
-        border-radius: 5px;
30
-        color: #eee;
31
-        font: 0.8em Consolas, Menlo, Monaco, Courier, monospace;
32
-        line-height: 1.7em;
33
-        text-align: left;
34
-        text-shadow: #333 0 1px 0;
26
+        background: url(<%= url_for '/mojo/stripes.png' %>);
27
+        border: 1px solid #d1d1d1;
28
+        box-shadow: 0 1px #fff, inset -1px 1px 4px rgba(0, 0, 0, 0.1);
29
+        color: #4d4d4c;
30
+        font: 0.9em Consolas, Menlo, Monaco, Courier, monospace;
31
+        line-height: 1.5em;
35 32
         padding-bottom: 1.5em;
36 33
         padding-top: 1.5em;
34
+        text-align: left;
35
+        text-shadow: #eee 0 1px 0;
37 36
         white-space: pre-wrap;
38 37
       }
39 38
       #footer {
... ...
@@ -42,19 +41,16 @@
42 41
       }
43 42
       #perldoc {
44 43
         background-color: #fff;
45
-        -moz-border-radius-bottomleft: 5px;
46 44
         border-bottom-left-radius: 5px;
47
-        -moz-border-radius-bottomright: 5px;
48 45
         border-bottom-right-radius: 5px;
49
-        -moz-box-shadow: 0px 0px 2px #ccc;
50
-        -webkit-box-shadow: 0px 0px 2px #ccc;
51
-        box-shadow: 0px 0px 2px #ccc;
46
+        box-shadow: 0px 0px 2px #999;
52 47
         margin-left: 5em;
53 48
         margin-right: 5em;
54 49
         padding: 3em;
55 50
         padding-top: 70px;
56 51
       }
57 52
       #perldoc > ul:first-of-type a { text-decoration: none }
53
+      #source { padding-bottom: 1em }
58 54
       #wrapperlicious {
59 55
         max-width: 1000px;
60 56
         margin: 0 auto;
... ...
@@ -63,20 +59,26 @@
63 59
   </head>
64 60
   <body>
65 61
     %= include inline => app->renderer->_bundled('mojobar')
66
-    % my $link = begin
67
-      %= link_to shift, shift, class => "mojoscroll"
68
-    % end
69 62
     <div id="wrapperlicious">
70 63
       <div id="perldoc">
64
+        <div id="source">
65
+          % my $path;
66
+          % for my $part (split '/', $module) {
67
+            %= '::' if $path
68
+            % $path .= "/$part";
69
+            %= link_to $part => url_for("/perldoc$path")
70
+          % }
71
+          (<%= link_to 'source' => url_for("/perldoc$path.txt") %>)
72
+        </div>
71 73
         <h1><a id="toc">TABLE OF CONTENTS</a></h1>
72 74
         <ul>
73 75
           % for my $part (@$parts) {
74 76
             <li>
75
-              %= $link->(splice @$part, 0, 2)
77
+              %= link_to splice(@$part, 0, 2)
76 78
               % if (@$part) {
77 79
                 <ul>
78 80
                   % while (@$part) {
79
-                    <li><%= $link->(splice @$part, 0, 2) %></li>
81
+                    <li><%= link_to splice(@$part, 0, 2) %></li>
80 82
                   % }
81 83
                 </ul>
82 84
               % }
+35 -40
mojo/lib/Test/Mojo.pm
... ...
@@ -30,33 +30,33 @@ sub new {
30 30
 
31 31
 sub app {
32 32
   my ($self, $app) = @_;
33
-  return $self->ua->app unless $app;
34
-  $self->ua->app($app);
33
+  return $self->ua->server->app unless $app;
34
+  $self->ua->server->app($app);
35 35
   return $self;
36 36
 }
37 37
 
38 38
 sub content_is {
39 39
   my ($self, $value, $desc) = @_;
40 40
   $desc ||= 'exact match for content';
41
-  return $self->_test('is', $self->_get_content($self->tx), $value, $desc);
41
+  return $self->_test('is', $self->tx->res->text, $value, $desc);
42 42
 }
43 43
 
44 44
 sub content_isnt {
45 45
   my ($self, $value, $desc) = @_;
46 46
   $desc ||= 'no match for content';
47
-  return $self->_test('isnt', $self->_get_content($self->tx), $value, $desc);
47
+  return $self->_test('isnt', $self->tx->res->text, $value, $desc);
48 48
 }
49 49
 
50 50
 sub content_like {
51 51
   my ($self, $regex, $desc) = @_;
52 52
   $desc ||= 'content is similar';
53
-  return $self->_test('like', $self->_get_content($self->tx), $regex, $desc);
53
+  return $self->_test('like', $self->tx->res->text, $regex, $desc);
54 54
 }
55 55
 
56 56
 sub content_unlike {
57 57
   my ($self, $regex, $desc) = @_;
58 58
   $desc ||= 'content is not similar';
59
-  return $self->_test('unlike', $self->_get_content($self->tx), $regex, $desc);
59
+  return $self->_test('unlike', $self->tx->res->text, $regex, $desc);
60 60
 }
61 61
 
62 62
 sub content_type_is {
... ...
@@ -301,13 +301,6 @@ sub websocket_ok {
301 301
   return $self->_test('ok', $self->tx->res->code eq 101, $desc);
302 302
 }
303 303
 
304
-sub _get_content {
305
-  my ($self, $tx) = @_;
306
-  my $content = $tx->res->body;
307
-  my $charset = $tx->res->content->charset;
308
-  return $charset ? decode($charset, $content) : $content;
309
-}
310
-
311 304
 sub _json {
312 305
   my ($self, $method, $p) = @_;
313 306
   return Mojo::JSON::Pointer->new->$method(
... ...
@@ -442,7 +435,7 @@ User agent used for testing, defaults to a L<Mojo::UserAgent> object.
442 435
   $t->ua->max_redirects(10);
443 436
 
444 437
   # Use absolute URL for request with Basic authentication
445
-  my $url = $t->ua->app_url->userinfo('sri:secr3t')->path('/secrets.json');
438
+  my $url = $t->ua->server->url->userinfo('sri:secr3t')->path('/secrets.json');
446 439
   $t->post_ok($url => json => {limit => 10})
447 440
     ->status_is(200)
448 441
     ->json_is('/1/content', 'Mojo rocks!');
... ...
@@ -482,9 +475,9 @@ Access application with L<Mojo::UserAgent/"app">.
482 475
 
483 476
   # Change application behavior
484 477
   $t->app->hook(before_dispatch => sub {
485
-    my $self = shift;
486
-    $self->render(text => 'This request did not reach the router.')
487
-      if $self->req->url->path->contains('/user');
478
+    my $c = shift;
479
+    $c->render(text => 'This request did not reach the router.')
480
+      if $c->req->url->path->contains('/user');
488 481
   });
489 482
 
490 483
   # Extract additional information
... ...
@@ -496,28 +489,30 @@ Access application with L<Mojo::UserAgent/"app">.
496 489
   $t = $t->content_is('working!');
497 490
   $t = $t->content_is('working!', 'right content');
498 491
 
499
-Check response content for exact match.
492
+Check response content for exact match after retrieving it from
493
+L<Mojo::Message/"text">.
500 494
 
501 495
 =head2 content_isnt
502 496
 
503 497
   $t = $t->content_isnt('working!');
504 498
   $t = $t->content_isnt('working!', 'different content');
505 499
 
506
-Opposite of C<content_is>.
500
+Opposite of L</"content_is">.
507 501
 
508 502
 =head2 content_like
509 503
 
510 504
   $t = $t->content_like(qr/working!/);
511 505
   $t = $t->content_like(qr/working!/, 'right content');
512 506
 
513
-Check response content for similar match.
507
+Check response content for similar match after retrieving it from
508
+L<Mojo::Message/"text">.
514 509
 
515 510
 =head2 content_unlike
516 511
 
517 512
   $t = $t->content_unlike(qr/working!/);
518 513
   $t = $t->content_unlike(qr/working!/, 'different content');
519 514
 
520
-Opposite of C<content_like>.
515
+Opposite of L</"content_like">.
521 516
 
522 517
 =head2 content_type_is
523 518
 
... ...
@@ -531,7 +526,7 @@ Check response C<Content-Type> header for exact match.
531 526
   $t = $t->content_type_isnt('text/html');
532 527
   $t = $t->content_type_isnt('text/html', 'different content type');
533 528
 
534
-Opposite of C<content_type_is>.
529
+Opposite of L</"content_type_is">.
535 530
 
536 531
 =head2 content_type_like
537 532
 
... ...
@@ -545,7 +540,7 @@ Check response C<Content-Type> header for similar match.
545 540
   $t = $t->content_type_unlike(qr/text/);
546 541
   $t = $t->content_type_unlike(qr/text/, 'different content type');
547 542
 
548
-Opposite of C<content_type_like>.
543
+Opposite of L</"content_type_like">.
549 544
 
550 545
 =head2 delete_ok
551 546
 
... ...
@@ -554,7 +549,7 @@ Opposite of C<content_type_like>.
554 549
   $t = $t->delete_ok('/foo' => {DNT => 1} => form => {a => 'b'});
555 550
   $t = $t->delete_ok('/foo' => {DNT => 1} => json => {a => 'b'});
556 551
 
557
-Perform a C<DELETE> request and check for transport errors, takes the same
552
+Perform a DELETE request and check for transport errors, takes the same
558 553
 arguments as L<Mojo::UserAgent/"delete">, except for the callback.
559 554
 
560 555
 =head2 element_exists
... ...
@@ -570,7 +565,7 @@ L<Mojo::DOM>.
570 565
   $t = $t->element_exists_not('div.foo[x=y]');
571 566
   $t = $t->element_exists_not('html head title', 'has no title');
572 567
 
573
-Opposite of C<element_exists>.
568
+Opposite of L</"element_exists">.
574 569
 
575 570
 =head2 finish_ok
576 571
 
... ...
@@ -593,7 +588,7 @@ Wait for WebSocket connection to be closed gracefully and check status.
593 588
   $t = $t->get_ok('/foo' => {DNT => 1} => form => {a => 'b'});
594 589
   $t = $t->get_ok('/foo' => {DNT => 1} => json => {a => 'b'});
595 590
 
596
-Perform a C<GET> request and check for transport errors, takes the same
591
+Perform a GET request and check for transport errors, takes the same
597 592
 arguments as L<Mojo::UserAgent/"get">, except for the callback.
598 593
 
599 594
 =head2 head_ok
... ...
@@ -603,7 +598,7 @@ arguments as L<Mojo::UserAgent/"get">, except for the callback.
603 598
   $t = $t->head_ok('/foo' => {DNT => 1} => form => {a => 'b'});
604 599
   $t = $t->head_ok('/foo' => {DNT => 1} => json => {a => 'b'});
605 600
 
606
-Perform a C<HEAD> request and check for transport errors, takes the same
601
+Perform a HEAD request and check for transport errors, takes the same
607 602
 arguments as L<Mojo::UserAgent/"head">, except for the callback.
608 603
 
609 604
 =head2 header_is
... ...
@@ -618,7 +613,7 @@ Check response header for exact match.
618 613
   $t = $t->header_isnt(Expect => 'fun');
619 614
   $t = $t->header_isnt(Expect => 'fun', 'different header');
620 615
 
621
-Opposite of C<header_is>.
616
+Opposite of L</"header_is">.
622 617
 
623 618
 =head2 header_like
624 619
 
... ...
@@ -632,7 +627,7 @@ Check response header for similar match.
632 627
   $t = $t->header_like(Expect => qr/fun/);
633 628
   $t = $t->header_like(Expect => qr/fun/, 'different header');
634 629
 
635
-Opposite of C<header_like>.
630
+Opposite of L</"header_like">.
636 631
 
637 632
 =head2 json_has
638 633
 
... ...
@@ -647,7 +642,7 @@ JSON Pointer with L<Mojo::JSON::Pointer>.
647 642
   $t = $t->json_hasnt('/foo');
648 643
   $t = $t->json_hasnt('/minibar', 'no minibar');
649 644
 
650
-Opposite of C<json_has>.
645
+Opposite of L</"json_has">.
651 646
 
652 647
 =head2 json_is
653 648
 
... ...
@@ -672,7 +667,7 @@ the given JSON Pointer with L<Mojo::JSON::Pointer>.
672 667
   $t = $t->json_message_hasnt('/foo');
673 668
   $t = $t->json_message_hasnt('/minibar', 'no minibar');
674 669
 
675
-Opposite of C<json_message_has>.
670
+Opposite of L</"json_message_has">.
676 671
 
677 672
 =head2 json_message_is
678 673
 
... ...
@@ -701,7 +696,7 @@ Check WebSocket message for exact match.
701 696
   $t = $t->message_isnt('working!');
702 697
   $t = $t->message_isnt('working!', 'different message');
703 698
 
704
-Opposite of C<message_is>.
699
+Opposite of L</"message_is">.
705 700
 
706 701
 =head2 message_like
707 702
 
... ...
@@ -733,7 +728,7 @@ Wait for next WebSocket message to arrive.
733 728
   $t = $t->message_unlike(qr/working!/);
734 729
   $t = $t->message_unlike(qr/working!/, 'different message');
735 730
 
736
-Opposite of C<message_like>.
731
+Opposite of L</"message_like">.
737 732
 
738 733
 =head2 options_ok
739 734
 
... ...
@@ -742,7 +737,7 @@ Opposite of C<message_like>.
742 737
   $t = $t->options_ok('/foo' => {DNT => 1} => form => {a => 'b'});
743 738
   $t = $t->options_ok('/foo' => {DNT => 1} => json => {a => 'b'});
744 739
 
745
-Perform a C<OPTIONS> request and check for transport errors, takes the same
740
+Perform a OPTIONS request and check for transport errors, takes the same
746 741
 arguments as L<Mojo::UserAgent/"options">, except for the callback.
747 742
 
748 743
 =head2 or
... ...
@@ -762,7 +757,7 @@ Invoke callback if previous test failed.
762 757
   $t = $t->patch_ok('/foo' => {DNT => 1} => form => {a => 'b'});
763 758
   $t = $t->patch_ok('/foo' => {DNT => 1} => json => {a => 'b'});
764 759
 
765
-Perform a C<PATCH> request and check for transport errors, takes the same
760
+Perform a PATCH request and check for transport errors, takes the same
766 761
 arguments as L<Mojo::UserAgent/"patch">, except for the callback.
767 762
 
768 763
 =head2 post_ok
... ...
@@ -772,7 +767,7 @@ arguments as L<Mojo::UserAgent/"patch">, except for the callback.
772 767
   $t = $t->post_ok('/foo' => {DNT => 1} => form => {a => 'b'});
773 768
   $t = $t->post_ok('/foo' => {DNT => 1} => json => {a => 'b'});
774 769
 
775
-Perform a C<POST> request and check for transport errors, takes the same
770
+Perform a POST request and check for transport errors, takes the same
776 771
 arguments as L<Mojo::UserAgent/"post">, except for the callback.
777 772
 
778 773
   # Test file upload
... ...
@@ -791,7 +786,7 @@ arguments as L<Mojo::UserAgent/"post">, except for the callback.
791 786
   $t = $t->put_ok('/foo' => {DNT => 1} => form => {a => 'b'});
792 787
   $t = $t->put_ok('/foo' => {DNT => 1} => json => {a => 'b'});
793 788
 
794
-Perform a C<PUT> request and check for transport errors, takes the same
789
+Perform a PUT request and check for transport errors, takes the same
795 790
 arguments as L<Mojo::UserAgent/"put">, except for the callback.
796 791
 
797 792
 =head2 request_ok
... ...
@@ -841,7 +836,7 @@ Check response status for exact match.
841 836
   $t = $t->status_isnt(200);
842 837
   $t = $t->status_isnt(200, 'different status');
843 838
 
844
-Opposite of C<status_is>.
839
+Opposite of L</"status_is">.
845 840
 
846 841
 =head2 text_is
847 842
 
... ...
@@ -856,7 +851,7 @@ exact match with L<Mojo::DOM>.
856 851
   $t = $t->text_isnt('div.foo[x=y]' => 'Hello!');
857 852
   $t = $t->text_isnt('html head title' => 'Hello!', 'different title');
858 853
 
859
-Opposite of C<text_is>.
854
+Opposite of L</"text_is">.
860 855
 
861 856
 =head2 text_like
862 857
 
... ...
@@ -871,7 +866,7 @@ similar match with L<Mojo::DOM>.
871 866
   $t = $t->text_unlike('div.foo[x=y]' => qr/Hello/);
872 867
   $t = $t->text_unlike('html head title' => qr/Hello/, 'different title');
873 868
 
874
-Opposite of C<text_like>.
869
+Opposite of L</"text_like">.
875 870
 
876 871
 =head2 websocket_ok
877 872
 
+29 -25
mojo/lib/ojo.pm
... ...
@@ -6,12 +6,12 @@ use Mojo::Collection 'c';
6 6
 use Mojo::DOM;
7 7
 use Mojo::JSON 'j';
8 8
 use Mojo::UserAgent;
9
-use Mojo::Util 'monkey_patch';
9
+use Mojo::Util qw(dumper monkey_patch);
10 10
 
11
-# Silent oneliners
11
+# Silent one-liners
12 12
 $ENV{MOJO_LOG_LEVEL} ||= 'fatal';
13 13
 
14
-# Singleton user agent for oneliners
14
+# Singleton user agent for one-liners
15 15
 my $UA = Mojo::UserAgent->new;
16 16
 
17 17
 sub import {
... ...
@@ -19,14 +19,15 @@ sub import {
19 19
   # Mojolicious::Lite
20 20
   my $caller = caller;
21 21
   eval "package $caller; use Mojolicious::Lite;";
22
-  $UA->app($caller->app);
22
+  my $server = $UA->server->app($caller->app);
23
+  $server->app->hook(around_action => sub { local $_ = $_[1]; $_[0]->() });
23 24
 
24 25
   $UA->max_redirects(10) unless defined $ENV{MOJO_MAX_REDIRECTS};
25
-  $UA->detect_proxy unless defined $ENV{MOJO_PROXY};
26
+  $UA->proxy->detect unless defined $ENV{MOJO_PROXY};
26 27
 
27 28
   # The ojo DSL
28 29
   monkey_patch $caller,
29
-    a => sub { $caller->can('any')->(@_) and return $UA->app },
30
+    a => sub { $caller->can('any')->(@_) and return $UA->server->app },
30 31
     b => \&b,
31 32
     c => \&c,
32 33
     d => sub { _request($UA->build_tx(DELETE  => @_)) },
... ...
@@ -35,9 +36,9 @@ sub import {
35 36
     j => \&j,
36 37
     o => sub { _request($UA->build_tx(OPTIONS => @_)) },
37 38
     p => sub { _request($UA->build_tx(POST    => @_)) },
38
-    r => sub { $UA->app->dumper(@_) },
39
-    t => sub { _request($UA->build_tx(PATCH => @_)) },
40
-    u => sub { _request($UA->build_tx(PUT => @_)) },
39
+    r => \&dumper,
40
+    t => sub { _request($UA->build_tx(PATCH   => @_)) },
41
+    u => sub { _request($UA->build_tx(PUT     => @_)) },
41 42
     x => sub { Mojo::DOM->new(@_) };
42 43
 }
43 44
 
... ...
@@ -51,9 +52,11 @@ sub _request {
51 52
 
52 53
 1;
53 54
 
55
+=encoding utf8
56
+
54 57
 =head1 NAME
55 58
 
56
-ojo - Fun oneliners with Mojo!
59
+ojo - Fun one-liners with Mojo!
57 60
 
58 61
 =head1 SYNOPSIS
59 62
 
... ...
@@ -61,7 +64,7 @@ ojo - Fun oneliners with Mojo!
61 64
 
62 65
 =head1 DESCRIPTION
63 66
 
64
-A collection of automatically exported functions for fun Perl oneliners. Ten
67
+A collection of automatically exported functions for fun Perl one-liners. Ten
65 68
 redirects will be followed by default, you can change this behavior with the
66 69
 MOJO_MAX_REDIRECTS environment variable.
67 70
 
... ...
@@ -78,11 +81,12 @@ L<ojo> implements the following functions.
78 81
 
79 82
 =head2 a
80 83
 
81
-  my $app = a('/hello' => sub { shift->render(json => {hello => 'world'}) });
84
+  my $app = a('/hello' => sub { $_->render(json => {hello => 'world'}) });
82 85
 
83 86
 Create a route with L<Mojolicious::Lite/"any"> and return the current
84
-L<Mojolicious::Lite> object. See also the L<Mojolicious::Lite> tutorial for
85
-more argument variations.
87
+L<Mojolicious::Lite> object. The current controller object is also available
88
+to actions as C<$_>. See also the L<Mojolicious::Lite> tutorial for more
89
+argument variations.
86 90
 
87 91
   $ perl -Mojo -E 'a("/hello" => {text => "Hello Mojo!"})->start' daemon
88 92
 
... ...
@@ -105,25 +109,25 @@ Turn list into a L<Mojo::Collection> object.
105 109
   my $res = d('example.com');
106 110
   my $res = d('http://example.com' => {DNT => 1} => 'Hi!');
107 111
 
108
-Perform C<DELETE> request with L<Mojo::UserAgent/"delete"> and return
109
-resulting L<Mojo::Message::Response> object.
112
+Perform DELETE request with L<Mojo::UserAgent/"delete"> and return resulting
113
+L<Mojo::Message::Response> object.
110 114
 
111 115
 =head2 g
112 116
 
113 117
   my $res = g('example.com');
114 118
   my $res = g('http://example.com' => {DNT => 1} => 'Hi!');
115 119
 
116
-Perform C<GET> request with L<Mojo::UserAgent/"get"> and return resulting
120
+Perform GET request with L<Mojo::UserAgent/"get"> and return resulting
117 121
 L<Mojo::Message::Response> object.
118 122
 
119
-  $ perl -Mojo -E 'say g("mojolicio.us")->dom("h1, h2, h3")->pluck("text")'
123
+  $ perl -Mojo -E 'say g("mojolicio.us")->dom("h1, h2, h3")->text'
120 124
 
121 125
 =head2 h
122 126
 
123 127
   my $res = h('example.com');
124 128
   my $res = h('http://example.com' => {DNT => 1} => 'Hi!');
125 129
 
126
-Perform C<HEAD> request with L<Mojo::UserAgent/"head"> and return resulting
130
+Perform HEAD request with L<Mojo::UserAgent/"head"> and return resulting
127 131
 L<Mojo::Message::Response> object.
128 132
 
129 133
 =head2 j
... ...
@@ -141,22 +145,22 @@ Encode Perl data structure or decode JSON with L<Mojo::JSON>.
141 145
   my $res = o('example.com');
142 146
   my $res = o('http://example.com' => {DNT => 1} => 'Hi!');
143 147
 
144
-Perform C<OPTIONS> request with L<Mojo::UserAgent/"options"> and return
145
-resulting L<Mojo::Message::Response> object.
148
+Perform OPTIONS request with L<Mojo::UserAgent/"options"> and return resulting
149
+L<Mojo::Message::Response> object.
146 150
 
147 151
 =head2 p
148 152
 
149 153
   my $res = p('example.com');
150 154
   my $res = p('http://example.com' => {DNT => 1} => 'Hi!');
151 155
 
152
-Perform C<POST> request with L<Mojo::UserAgent/"post"> and return resulting
156
+Perform POST request with L<Mojo::UserAgent/"post"> and return resulting
153 157
 L<Mojo::Message::Response> object.
154 158
 
155 159
 =head2 r
156 160
 
157 161
   my $perl = r({data => 'structure'});
158 162
 
159
-Dump a Perl data structure with L<Data::Dumper>.
163
+Dump a Perl data structure with L<Mojo::Util/"dumper">.
160 164
 
161 165
   perl -Mojo -E 'say r(g("example.com")->headers->to_hash)'
162 166
 
... ...
@@ -165,7 +169,7 @@ Dump a Perl data structure with L<Data::Dumper>.
165 169
   my $res = t('example.com');
166 170
   my $res = t('http://example.com' => {DNT => 1} => 'Hi!');
167 171
 
168
-Perform C<PATCH> request with L<Mojo::UserAgent/"patch"> and return resulting
172
+Perform PATCH request with L<Mojo::UserAgent/"patch"> and return resulting
169 173
 L<Mojo::Message::Response> object.
170 174
 
171 175
 =head2 u
... ...
@@ -173,7 +177,7 @@ L<Mojo::Message::Response> object.
173 177
   my $res = u('example.com');
174 178
   my $res = u('http://example.com' => {DNT => 1} => 'Hi!');
175 179
 
176
-Perform C<PUT> request with L<Mojo::UserAgent/"put"> and return resulting
180
+Perform PUT request with L<Mojo::UserAgent/"put"> and return resulting
177 181
 L<Mojo::Message::Response> object.
178 182
 
179 183
 =head2 x
+5 -4
mojo/script/hypnotoad
... ...
@@ -8,14 +8,13 @@ BEGIN { unshift @INC, "$FindBin::Bin/../lib" }
8 8
 
9 9
 use Getopt::Long qw(GetOptions :config no_auto_abbrev no_ignore_case);
10 10
 
11
-GetOptions(
11
+GetOptions
12 12
   'f|foreground' => sub { $ENV{HYPNOTOAD_FOREGROUND} = 1 },
13 13
   'h|help'       => \my $help,
14 14
   's|stop'       => sub { $ENV{HYPNOTOAD_STOP}       = 1 },
15
-  't|test'       => sub { $ENV{HYPNOTOAD_TEST}       = 1 }
16
-);
15
+  't|test'       => sub { $ENV{HYPNOTOAD_TEST}       = 1 };
17 16
 
18
-die <<"EOF" if $help || !(my $app = shift || $ENV{HYPNOTOAD_APP});
17
+die <<EOF if $help || !(my $app = shift || $ENV{HYPNOTOAD_APP});
19 18
 usage: $0 [OPTIONS] [APPLICATION]
20 19
 
21 20
   hypnotoad script/myapp
... ...
@@ -32,6 +31,8 @@ EOF
32 31
 require Mojo::Server::Hypnotoad;
33 32
 Mojo::Server::Hypnotoad->new->run($app);
34 33
 
34
+=encoding utf8
35
+
35 36
 =head1 NAME
36 37
 
37 38
 hypnotoad - Hypnotoad HTTP and WebSocket server
+2
mojo/script/mojo
... ...
@@ -9,6 +9,8 @@ BEGIN { unshift @INC, "$FindBin::Bin/../lib" }
9 9
 require Mojolicious::Commands;
10 10
 Mojolicious::Commands->start_app('Mojo::HelloWorld');
11 11
 
12
+=encoding utf8
13
+
12 14
 =head1 NAME
13 15
 
14 16
 mojo - The Mojolicious command system
+10 -4
mojo/script/morbo
... ...
@@ -8,18 +8,19 @@ BEGIN { unshift @INC, "$FindBin::Bin/../lib" }
8 8
 
9 9
 use Getopt::Long qw(GetOptions :config no_auto_abbrev no_ignore_case);
10 10
 
11
-GetOptions(
11
+GetOptions
12 12
   'h|help'     => \my $help,
13 13
   'l|listen=s' => \my @listen,
14
+  'm|mode=s'   => sub { $ENV{MOJO_MODE} = $_[1] },
14 15
   'v|verbose'  => sub { $ENV{MORBO_VERBOSE} = 1 },
15
-  'w|watch=s'  => \my @watch
16
-);
16
+  'w|watch=s'  => \my @watch;
17 17
 
18
-die <<"EOF" if $help || !(my $app = shift);
18
+die <<EOF if $help || !(my $app = shift);
19 19
 usage: $0 [OPTIONS] [APPLICATION]
20 20
 
21 21
   morbo script/myapp
22 22
   morbo myapp.pl
23
+  morbo -m production -l https://*:443
23 24
   morbo -w /usr/local/lib -w public myapp.pl
24 25
 
25 26
 These options are available:
... ...
@@ -27,6 +28,9 @@ These options are available:
27 28
   -l, --listen <location>        Set one or more locations you want to listen
28 29
                                  on, defaults to the value of MOJO_LISTEN or
29 30
                                  "http://*:3000".
31
+  -m, --mode <name>              Operating mode for your application, defaults
32
+                                 to the value of MOJO_MODE/PLACK_ENV or
33
+                                 "development".
30 34
   -v, --verbose                  Print details about what files changed to
31 35
                                  STDOUT.
32 36
   -w, --watch <directory/file>   Set one or more directories and files to
... ...
@@ -42,6 +46,8 @@ my $morbo = Mojo::Server::Morbo->new;
42 46
 $morbo->watch(\@watch) if @watch;
43 47
 $morbo->run($app);
44 48
 
49
+=encoding utf8
50
+
45 51
 =head1 NAME
46 52
 
47 53
 morbo - Morbo HTTP and WebSocket development server