The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
Changes 19180
MANIFEST 03
MANIFEST.bak 0351
META.json 57
META.yml 57
Makefile.PL 58
README.md 3727
examples/connect-proxy.pl 41
examples/entities.pl 51
examples/fast.pl 20
examples/hello-template.pl 010
examples/hello.pl 20
examples/microhttpd.pl 41
examples/websocket.pl 20
lib/Mojo/Asset/File.pm 1313
lib/Mojo/Asset/Memory.pm 011
lib/Mojo/Asset.pm 08
lib/Mojo/Base.pm 52
lib/Mojo/ByteStream.pm 11
lib/Mojo/Cache.pm 25
lib/Mojo/Collection.pm 1148
lib/Mojo/Content.pm 65
lib/Mojo/DOM/CSS.pm 167
lib/Mojo/DOM/HTML.pm 22
lib/Mojo/DOM.pm 102159
lib/Mojo/Date.pm 1657
lib/Mojo/EventEmitter.pm 146
lib/Mojo/Headers.pm 614
lib/Mojo/IOLoop/Client.pm 2296
lib/Mojo/IOLoop/Delay.pm 56
lib/Mojo/IOLoop/Server.pm 33
lib/Mojo/IOLoop/Stream.pm 1413
lib/Mojo/IOLoop.pm 56
lib/Mojo/JSON/Pointer.pm 31
lib/Mojo/JSON.pm 43
lib/Mojo/Loader.pm 11
lib/Mojo/Log.pm 85
lib/Mojo/Message/Request.pm 2320
lib/Mojo/Message/Response.pm 21
lib/Mojo/Message.pm 67
lib/Mojo/Parameters.pm 2319
lib/Mojo/Path.pm 1910
lib/Mojo/Reactor/EV.pm 99
lib/Mojo/Reactor/Poll.pm 35
lib/Mojo/Reactor.pm 103
lib/Mojo/Server/CGI.pm 43
lib/Mojo/Server/Daemon.pm 1010
lib/Mojo/Server/Hypnotoad.pm 99
lib/Mojo/Server/Morbo.pm 910
lib/Mojo/Server/PSGI.pm 32
lib/Mojo/Server/Prefork.pm 910
lib/Mojo/Server.pm 84
lib/Mojo/Template.pm 9280
lib/Mojo/Transaction/WebSocket.pm 5241
lib/Mojo/Transaction.pm 1416
lib/Mojo/URL.pm 85
lib/Mojo/UserAgent/CookieJar.pm 012
lib/Mojo/UserAgent/Proxy.pm 55
lib/Mojo/UserAgent/Transactor.pm 2057
lib/Mojo/UserAgent.pm 103107
lib/Mojo/Util.pm 1854
lib/Mojo.pm 224
lib/Mojolicious/Command/cgi.pm 32
lib/Mojolicious/Command/daemon.pm 01
lib/Mojolicious/Command/generate/app.pm 22
lib/Mojolicious/Command/generate/lite_app.pm 11
lib/Mojolicious/Command/get.pm 74
lib/Mojolicious/Command/prefork.pm 01
lib/Mojolicious/Command/routes.pm 96
lib/Mojolicious/Command/test.pm 186
lib/Mojolicious/Command/version.pm 1413
lib/Mojolicious/Command.pm 43
lib/Mojolicious/Commands.pm 1313
lib/Mojolicious/Controller.pm 9250
lib/Mojolicious/Guides/Cookbook.pod 30135
lib/Mojolicious/Guides/FAQ.pod 89
lib/Mojolicious/Guides/Growing.pod 35120
lib/Mojolicious/Guides/Rendering.pod 108222
lib/Mojolicious/Guides/Routing.pod 279245
lib/Mojolicious/Guides.pod 218
lib/Mojolicious/Lite.pm 2545
lib/Mojolicious/Plugin/Config.pm 11
lib/Mojolicious/Plugin/DefaultHelpers.pm 30162
lib/Mojolicious/Plugin/EPLRenderer.pm 137
lib/Mojolicious/Plugin/EPRenderer.pm 2326
lib/Mojolicious/Plugin/JSONConfig.pm 11
lib/Mojolicious/Plugin/Mount.pm 31
lib/Mojolicious/Plugin/PODRenderer.pm 3823
lib/Mojolicious/Plugin/TagHelpers.pm 22
lib/Mojolicious/Plugins.pm 117
lib/Mojolicious/Renderer.pm 3759
lib/Mojolicious/Routes/Match.pm 3530
lib/Mojolicious/Routes/Pattern.pm 5044
lib/Mojolicious/Routes/Route.pm 6746
lib/Mojolicious/Routes.pm 2011
lib/Mojolicious/Sessions.pm 01
lib/Mojolicious/Static.pm 4696
lib/Mojolicious/Validator/Validation.pm 33
lib/Mojolicious/templates/development.html.ep 99
lib/Mojolicious/templates/mojobar.html.ep 11
lib/Mojolicious/templates/perldoc.html.ep 411
lib/Mojolicious.pm 1728
lib/Test/Mojo.pm 2335
lib/ojo.pm 1324
script/hypnotoad 33
script/morbo 23
t/mojo/asset.t 011
t/mojo/cache.t 29
t/mojo/collection.t 29
t/mojo/content.t 11
t/mojo/daemon.t 418
t/mojo/date.t 033
t/mojo/dom.t 047
t/mojo/eventemitter.t 3111
t/mojo/json.t 11
t/mojo/path.t 01
t/mojo/response.t 20
t/mojo/template.t 1543
t/mojo/transactor.t 031
t/mojo/user_agent.t 1516
t/mojo/user_agent_online.t 34
t/mojo/user_agent_socks.t 0172
t/mojo/util.t 213
t/mojo/websocket.t 33
t/mojo/websocket_frames.t 215
t/mojo/websocket_proxy_tls.t 225
t/mojolicious/app.t 535
t/mojolicious/commands.t 118
t/mojolicious/group_lite_app.t 44
t/mojolicious/lib/SingleFileTestApp.pm 11
t/mojolicious/lite_app.t 3626
t/mojolicious/longpolling_lite_app.t 11
t/mojolicious/ojo.t 014
t/mojolicious/pattern.t 318
t/mojolicious/pod_renderer_lite_app.t 56
t/mojolicious/production_app.t 04
t/mojolicious/renderer.t 057
t/mojolicious/routes.t 363
t/mojolicious/static_lite_app.t 296
t/mojolicious/twinkle_lite_app.t 33
t/mojolicious/websocket_lite_app.t 38
t/pod_coverage.t 14
142 files changed (This is a version diff) 21043912
@@ -1,4 +1,166 @@
 
+5.47  2014-09-28
+  - Improved url_for performance.
+
+5.46  2014-09-26
+  - PAUSE lost the previous release.
+
+5.45  2014-09-26
+  - Deprecated Mojolicious::Routes::Route::has_conditions.
+  - Added extracting attribute to Mojo::UserAgent::CookieJar.
+  - Improved performance of next, next_sibling, previous and previous_sibling
+    methods in Mojo::DOM significantly.
+  - Improved Mojo::Cache to allow caching to be disabled. (mvgrimes, sri)
+  - Fixed url_for bug where deeply nested WebSocket routes would not work
+    correctly.
+
+5.44  2014-09-23
+  - Fixed bug in Mojolicious::Renderer that prevented proxy objects from being
+    reused.
+
+5.43  2014-09-22
+  - Updated Makefile.PL for version 2 of the CPAN distribution metadata
+    specification.
+  - Improved get command to not depend on Content-Type headers for
+    differentiating between JSON and HTML/XML.
+
+5.42  2014-09-17
+  - Fixed url_for bug where an unnecessary slash could be rendered before
+    formats.
+
+5.41  2014-09-13
+  - Deprecated Mojolicious::Controller::render_static in favor of
+    reply->static helper.
+  - Added mtime attribute to Mojo::Asset::Memory.
+  - Added mtime method to Mojo::Asset and Mojo::Asset::File.
+  - Added reply->asset and reply->static helpers to
+    Mojolicious::Plugin::DefaultHelpers.
+  - Fixed bug in Mojo::UserAgent where connections would sometimes not get
+    closed correctly.
+
+5.40  2014-09-12
+  - Deprecated Mojo::EventEmitter::emit_safe.
+  - Added reply->exception and reply->not_found helpers to
+    Mojolicious::Plugin::DefaultHelpers.
+  - Improved all events to handle exceptions the same.
+
+5.39  2014-09-07
+  - Improved decamelize performance.
+  - Fixed bug in Mojo::Template where newline characters could get lost.
+
+5.38  2014-09-05
+  - Improved routes command to use new terminology for flags.
+  - Fixed bug in Mojo::Util where tablify could not handle empty columns.
+
+5.37  2014-09-03
+  - Improved Mojo::Template performance slightly.
+  - Fixed .ep template bug where the stash value "c" could no longer be used.
+
+5.36  2014-09-02
+  - Improved Mojo::Template performance.
+
+5.35  2014-08-30
+  - Improved monkey_patch to be able to name generated functions.
+
+5.34  2014-08-29
+  - Added original_remote_address attribute to Mojo::Transaction.
+  - Fixed bug where Mojolicious::Commands would change @ARGV when loaded.
+
+5.33  2014-08-24
+  - Improved Mojo::Date to be able to handle higher precision times.
+  - Improved Mojo::ByteStream performance.
+
+5.32  2014-08-21
+  - Added to_datetime method to Mojo::Date.
+  - Improved Mojo::Date to support RFC 3339.
+
+5.31  2014-08-19
+  - Improved Mojolicious::Static to allow custom content types.
+  - Improved url_for performance.
+
+5.30  2014-08-17
+  - Improved Mojolicious::Static to only handle GET and HEAD requests.
+  - Improved Mojo::URL performance.
+  - Improved url_for performance slightly.
+  - Fixed bug where DATA sections sometimes got corrupted after forking, which
+    caused applications to fail randomly.
+  - Fixed Mojo::IOLoop::Client to use a timeout for every connection.
+
+5.29  2014-08-16
+  - Added helpers method to Mojolicious::Controller.
+  - Improved performance of .ep templates slightly.
+  - Fixed "0" value bug in Mojolicious::Plugin::EPRenderer.
+
+5.28  2014-08-13
+  - Improved performance of nested helpers and helpers in templates
+    significantly.
+  - Improved Mojo::JSON to generate smaller JSON by not escaping the "/"
+    character.
+
+5.27  2014-08-11
+  - Added support for nested helpers.
+  - Added get_helper method to Mojolicious::Renderer.
+  - Added n function to ojo.
+  - Fixed bug in Mojolicious::Routes::Match where placeholder values got
+    merged too early.
+
+5.26  2014-08-09
+  - Improved WebSocket performance.
+  - Fixed proxy exception handling bug in Mojo::UserAgent.
+  - Fixed bug where Mojo::Transaction::WebSocket would build incorrect frames
+    if the FIN bit was not set.
+
+5.25  2014-08-07
+  - Added reduce method to Mojo::Collection. (sri, batman)
+  - Added if_none_match method to Mojo::Headers.
+  - Added is_fresh method to Mojolicious::Static.
+  - Added is_fresh helper to Mojolicious::Plugin::DefaultHelpers.
+  - Improved Mojolicious to use MyApp::Controller namespace by default and
+    encourage its use in the documentation.
+  - Improved sort method in Mojo::Collection to use $a and $b. (batman)
+  - Improved Mojolicious::Static to support ETag and If-None-Match headers.
+  - Improved documentation browser CSS.
+  - Fixed escaping bugs in Mojo::DOM::CSS.
+
+5.24  2014-08-02
+  - Improved url_escape performance slightly.
+  - Fixed memory leak in Mojo::IOLoop::Client.
+  - Fixed bug where ojo would sometimes die silently.
+
+5.23  2014-07-31
+  - Improved router performance.
+  - Improved routes command to show format regular expression separately.
+  - Fixed partial route bug in Mojolicious::Routes::Match.
+  - Fixed format detection bug in Mojolicious::Routes::Pattern.
+
+5.22  2014-07-30
+  - Added SOCKS5 support to Mojo::UserAgent.
+  - Added socks_address, socks_pass, socks_port and socks_user options to
+    Mojo::IOLoop::Client::connect.
+  - Improved documentation browser CSS.
+
+5.21  2014-07-27
+  - Improved handling of Pod::Simple::XHTML 3.09 dependency.
+  - Improved documentation browser CSS.
+
+5.20  2014-07-27
+  - Fixed a few bugs in Mojolicious::Plugin::PODRenderer by switching from
+    Pod::Simple::HTML to Pod::Simple::XHTML.
+  - Fixed Perl 5.18.x compatibility.
+
+5.19  2014-07-26
+  - Improved support for Unicode anchors in Mojolicious::Plugin::PODRenderer.
+  - Fixed is_readable scalability problems in Mojo::Reactor.
+
+5.18  2014-07-25
+  - Improved is_readable performance in Mojo::Reactor.
+
+5.17  2014-07-24
+  - Welcome to the Mojolicious core team Jan Henning Thorsen.
+  - Added val method to Mojo::DOM. (batman, sri)
+  - Improved Mojo::Collection performance.
+  - Fixed support for Unicode anchors in Mojolicious::Plugin::PODRenderer.
+
 5.16  2014-07-21
   - Improved Mojo::Asset::File to allow appending data to existing files.
     (iakuf, sri)
@@ -91,7 +253,7 @@
     invocant.
   - Changed return value of path_for method in Mojolicious::Routes::Match.
   - Changed return value and arguments of error method in Mojo::Message.
-  - Removed deprecated support for "X-Forwarded-HTTPS".
+  - Removed deprecated support for X-Forwarded-HTTPS.
   - Removed return values from wait method in Mojo::IOLoop::Delay.
   - Removed list context support from header method in Mojo::Headers.
   - Removed generate_port method from Mojo::IOLoop.
@@ -129,8 +291,7 @@
   - Improved accept performance in Mojo::IOLoop::Server.
 
 4.97  2014-04-30
-  - Deprecated support for "X-Forwarded-HTTPS" in favor of
-    "X-Forwarded-Proto".
+  - Deprecated support for X-Forwarded-HTTPS in favor of X-Forwarded-Proto.
   - Added multi-name support to param method in Mojo::Parameters.
 
 4.96  2014-04-28
@@ -312,7 +473,7 @@
   - Improved router to allow format detection for bridges.
 
 4.68  2014-01-22
-  - Added Mojo::DOM::Node.
+  - Added module Mojo::DOM::Node.
   - Added contents and node methods to Mojo::DOM.
   - Removed deprecated http_proxy, https_proxy, name and no_proxy attributes
     from Mojo::UserAgent.
@@ -1384,7 +1545,7 @@
 
 2.93  2012-05-05
   - Added remove method to Mojolicious::Routes::Route.
-  - Improved 32bit Perl support of Mojo::Transaction::WebSocket.
+  - Improved 32-bit Perl support of Mojo::Transaction::WebSocket.
     (mikemagowan, sri)
   - Improved exception handling of application and configuration file loaders.
   - Improved exception handling of Mojolicious::Plugin::I18N.
@@ -1539,7 +1700,7 @@
 2.65  2012-03-22
   - Deprecated Mojo::IOLoop::drop in favor of Mojo::IOLoop::remove.
   - Renamed Mojo::Reactor::drop to Mojo::Reactor::remove.
-  - Added Mojo::Reactor::Poll.
+  - Added module Mojo::Reactor::Poll.
   - Added one_tick method to Mojo::Reactor and Mojo::Reactor::EV.
   - Removed experimental status from Mojo::IOLoop::Client.
   - Removed experimental status from Mojo::IOLoop::Server.
@@ -1559,7 +1720,7 @@
 
 2.63  2012-03-20
   - Renamed Mojo::IOWatcher to Mojo::Reactor.
-  - Added Mojolicious::Routes::Route.
+  - Added module Mojolicious::Routes::Route.
   - Added find and root methods to Mojolicious::Routes::Route.
   - Improved form_for helper to automatically add method="POST" attributes
     when necessary.
@@ -2323,7 +2484,7 @@
   - Modernized Mojo::HelloWorld.
   - Improved HTML healing capabilities of Mojo::DOM::HTML.
   - Improved HTML rendering in Mojo::DOM::HTML.
-  - Improved 64bit support in Mojo::Transaction::WebSocket.
+  - Improved 64-bit support in Mojo::Transaction::WebSocket.
   - Fixed memory leak in Mojo::IOLoop::Client.
   - Fixed memory leak in Mojolicious.
   - Fixed small bug in Mojo::IOLoop::Server.
@@ -2568,7 +2729,7 @@
     available.
   - Updated jQuery to version 1.6.
   - Fixed PSGI read error handling.
-  - Fixed 64bit WebSocket message bug.
+  - Fixed 64-bit WebSocket message bug.
   - Fixed small Windows bug.
 
 1.22  2011-05-02
@@ -2601,7 +2762,7 @@
   - Fixed size limits in message parser.
 
 1.18  2011-04-19
-  - Added support for "X-Forwarded-HTTPS" and "X-Forwarded-Host" headers.
+  - Added support for X-Forwarded-HTTPS and X-Forwarded-Host headers.
   - Added argument localization to the include helper. (crab, moritz, sri)
   - Fixed test case.
 
@@ -3131,7 +3292,7 @@
       print $client->get('http://search.cpan.org')->res->body;
       my $tx = $client->post_form('http://kraih.com', {q => 'mojo'});
   - Made plugins much more configurable.
-  - Improved PSGI support and added "psgi" command.
+  - Improved PSGI support and added psgi command.
   - Added automatic environment detection for Plack based servers, there is
     no technical way to detect all PSGI compliant servers yet though. That
     means "plackup myapp.pl" and "plackup script/myapp" should just work.
@@ -3158,8 +3319,8 @@
   - Added I18N support. (vti, memowe)
   - Added template detection again, you can now just mix multiple template
     engines and the renderer will automatically pick the right template. So
-    you don't have to use the "handler" argument anymore, even though it's
-    still available and overrides auto detection.
+    you don't have to use the handler argument anymore, even though it's still
+    available and overrides auto detection.
   - Added Flash Policy Server example. (xantus)
   - Added more reference docs.
   - Added ".gitignore" generator command. (marcus)
@@ -3440,8 +3601,8 @@
   - Merged eplite and epl, this change is not backwards compatible, you will
     have to rename all your eplite templates to epl.
   - Simplified MojoX::Renderer, this change is not backwards compatible!
-    Handler can no longer be detected, that means "default_handler" or the
-    "handler" argument are required. The template argument can no longer
+    Handler can no longer be detected, that means default_handler or the
+    handler argument are required. The template argument can no longer
     contain format or handler.
       $self->render(template => 'foo.html.epl');
     becomes
@@ -3643,7 +3804,7 @@
   - Added layout support to MojoX::Renderer.
   - Made render call optional.
   - Added format support to MojoX::Routes.
-  - Added Mojo::Loader::Exception.
+  - Added module Mojo::Loader::Exception.
   - Added wildcard symbol support to MojoX::Routes and rewrote many routes
     internals.
   - Added Makefile.PL generator.
@@ -3654,7 +3815,7 @@
   - Added encoding support to Mojo::Template and made "utf8" the default.
   - Added HEAD support to Mojo::Server::Daemon. (acajou)
   - Added new relaxed placeholder to MojoX::Routes::Pattern.
-  - Added Mojo::Template::Exception.
+  - Added module Mojo::Template::Exception.
   - Added HEAD support to the Mojo::Transaction state machine and related
     modules. (acajou)
   - Added safe_post option to Mojo::Pipeline. (acajou)
@@ -3695,10 +3856,10 @@
 
 0.9  2008-12-01
   - Added modes to Mojolicious.
-  - Added Mojo::Log and log support for Mojo/Mojolicious.
+  - Added module Mojo::Log and log support for Mojo/Mojolicious.
+  - Added module MojoX::Context.
   - Changed MojoX::Renderer and Mojo::Template API to make catching errors
     easier, we now use a scalar ref for results like most template engines.
-  - Added MojoX::Context.
   - Added multi-level controller class support to Mojolicious.
   - MojoX::Dispatcher::Routes should be able to fail.
   - Added diagnostics functions to Mojo::HelloWorld.
@@ -4,6 +4,7 @@ CONTRIBUTING.md
 examples/connect-proxy.pl
 examples/entities.pl
 examples/fast.pl
+examples/hello-template.pl
 examples/hello.pl
 examples/microhttpd.pl
 examples/websocket.pl
@@ -172,6 +173,7 @@ lib/Test/Mojo.pm
 LICENSE
 Makefile.PL
 MANIFEST			This list of files
+MANIFEST.bak
 MANIFEST.SKIP
 README.md
 script/hypnotoad
@@ -237,6 +239,7 @@ t/mojo/transactor.t
 t/mojo/url.t
 t/mojo/user_agent.t
 t/mojo/user_agent_online.t
+t/mojo/user_agent_socks.t
 t/mojo/user_agent_tls.t
 t/mojo/util.t
 t/mojo/websocket.t
@@ -0,0 +1,351 @@
+.perltidyrc
+Changes
+CONTRIBUTING.md
+examples/connect-proxy.pl
+examples/entities.pl
+examples/fast.pl
+examples/hello-template.pl
+examples/hello.pl
+examples/microhttpd.pl
+examples/websocket.pl
+lib/Mojo.pm
+lib/Mojo/Asset.pm
+lib/Mojo/Asset/File.pm
+lib/Mojo/Asset/Memory.pm
+lib/Mojo/Base.pm
+lib/Mojo/ByteStream.pm
+lib/Mojo/Cache.pm
+lib/Mojo/Collection.pm
+lib/Mojo/Content.pm
+lib/Mojo/Content/MultiPart.pm
+lib/Mojo/Content/Single.pm
+lib/Mojo/Cookie.pm
+lib/Mojo/Cookie/Request.pm
+lib/Mojo/Cookie/Response.pm
+lib/Mojo/Date.pm
+lib/Mojo/DOM.pm
+lib/Mojo/DOM/CSS.pm
+lib/Mojo/DOM/HTML.pm
+lib/Mojo/entities.txt
+lib/Mojo/EventEmitter.pm
+lib/Mojo/Exception.pm
+lib/Mojo/Headers.pm
+lib/Mojo/HelloWorld.pm
+lib/Mojo/Home.pm
+lib/Mojo/IOLoop.pm
+lib/Mojo/IOLoop/Client.pm
+lib/Mojo/IOLoop/Delay.pm
+lib/Mojo/IOLoop/server.crt
+lib/Mojo/IOLoop/server.key
+lib/Mojo/IOLoop/Server.pm
+lib/Mojo/IOLoop/Stream.pm
+lib/Mojo/JSON.pm
+lib/Mojo/JSON/Pointer.pm
+lib/Mojo/Loader.pm
+lib/Mojo/Log.pm
+lib/Mojo/Message.pm
+lib/Mojo/Message/Request.pm
+lib/Mojo/Message/Response.pm
+lib/Mojo/Parameters.pm
+lib/Mojo/Path.pm
+lib/Mojo/Reactor.pm
+lib/Mojo/Reactor/EV.pm
+lib/Mojo/Reactor/Poll.pm
+lib/Mojo/Server.pm
+lib/Mojo/Server/CGI.pm
+lib/Mojo/Server/Daemon.pm
+lib/Mojo/Server/Hypnotoad.pm
+lib/Mojo/Server/Morbo.pm
+lib/Mojo/Server/Prefork.pm
+lib/Mojo/Server/PSGI.pm
+lib/Mojo/Template.pm
+lib/Mojo/Transaction.pm
+lib/Mojo/Transaction/HTTP.pm
+lib/Mojo/Transaction/WebSocket.pm
+lib/Mojo/Upload.pm
+lib/Mojo/URL.pm
+lib/Mojo/UserAgent.pm
+lib/Mojo/UserAgent/CookieJar.pm
+lib/Mojo/UserAgent/Proxy.pm
+lib/Mojo/UserAgent/Server.pm
+lib/Mojo/UserAgent/Transactor.pm
+lib/Mojo/Util.pm
+lib/Mojolicious.pm
+lib/Mojolicious/Command.pm
+lib/Mojolicious/Command/cgi.pm
+lib/Mojolicious/Command/cpanify.pm
+lib/Mojolicious/Command/daemon.pm
+lib/Mojolicious/Command/eval.pm
+lib/Mojolicious/Command/generate.pm
+lib/Mojolicious/Command/generate/app.pm
+lib/Mojolicious/Command/generate/lite_app.pm
+lib/Mojolicious/Command/generate/makefile.pm
+lib/Mojolicious/Command/generate/plugin.pm
+lib/Mojolicious/Command/get.pm
+lib/Mojolicious/Command/inflate.pm
+lib/Mojolicious/Command/prefork.pm
+lib/Mojolicious/Command/psgi.pm
+lib/Mojolicious/Command/routes.pm
+lib/Mojolicious/Command/test.pm
+lib/Mojolicious/Command/version.pm
+lib/Mojolicious/Commands.pm
+lib/Mojolicious/Controller.pm
+lib/Mojolicious/Guides.pod
+lib/Mojolicious/Guides/Contributing.pod
+lib/Mojolicious/Guides/Cookbook.pod
+lib/Mojolicious/Guides/FAQ.pod
+lib/Mojolicious/Guides/Growing.pod
+lib/Mojolicious/Guides/Rendering.pod
+lib/Mojolicious/Guides/Routing.pod
+lib/Mojolicious/Lite.pm
+lib/Mojolicious/Plugin.pm
+lib/Mojolicious/Plugin/Charset.pm
+lib/Mojolicious/Plugin/Config.pm
+lib/Mojolicious/Plugin/DefaultHelpers.pm
+lib/Mojolicious/Plugin/EPLRenderer.pm
+lib/Mojolicious/Plugin/EPRenderer.pm
+lib/Mojolicious/Plugin/HeaderCondition.pm
+lib/Mojolicious/Plugin/JSONConfig.pm
+lib/Mojolicious/Plugin/Mount.pm
+lib/Mojolicious/Plugin/PODRenderer.pm
+lib/Mojolicious/Plugin/TagHelpers.pm
+lib/Mojolicious/Plugins.pm
+lib/Mojolicious/public/favicon.ico
+lib/Mojolicious/public/mojo/failraptor.png
+lib/Mojolicious/public/mojo/jquery/jquery.js
+lib/Mojolicious/public/mojo/logo-black.png
+lib/Mojolicious/public/mojo/logo-white.png
+lib/Mojolicious/public/mojo/noraptor.png
+lib/Mojolicious/public/mojo/notfound.png
+lib/Mojolicious/public/mojo/pinstripe-dark.png
+lib/Mojolicious/public/mojo/pinstripe-light.png
+lib/Mojolicious/public/mojo/prettify/lang-apollo.js
+lib/Mojolicious/public/mojo/prettify/lang-basic.js
+lib/Mojolicious/public/mojo/prettify/lang-clj.js
+lib/Mojolicious/public/mojo/prettify/lang-css.js
+lib/Mojolicious/public/mojo/prettify/lang-dart.js
+lib/Mojolicious/public/mojo/prettify/lang-erlang.js
+lib/Mojolicious/public/mojo/prettify/lang-go.js
+lib/Mojolicious/public/mojo/prettify/lang-hs.js
+lib/Mojolicious/public/mojo/prettify/lang-lisp.js
+lib/Mojolicious/public/mojo/prettify/lang-llvm.js
+lib/Mojolicious/public/mojo/prettify/lang-lua.js
+lib/Mojolicious/public/mojo/prettify/lang-matlab.js
+lib/Mojolicious/public/mojo/prettify/lang-ml.js
+lib/Mojolicious/public/mojo/prettify/lang-mumps.js
+lib/Mojolicious/public/mojo/prettify/lang-n.js
+lib/Mojolicious/public/mojo/prettify/lang-pascal.js
+lib/Mojolicious/public/mojo/prettify/lang-proto.js
+lib/Mojolicious/public/mojo/prettify/lang-r.js
+lib/Mojolicious/public/mojo/prettify/lang-rd.js
+lib/Mojolicious/public/mojo/prettify/lang-scala.js
+lib/Mojolicious/public/mojo/prettify/lang-sql.js
+lib/Mojolicious/public/mojo/prettify/lang-tcl.js
+lib/Mojolicious/public/mojo/prettify/lang-tex.js
+lib/Mojolicious/public/mojo/prettify/lang-vb.js
+lib/Mojolicious/public/mojo/prettify/lang-vhdl.js
+lib/Mojolicious/public/mojo/prettify/lang-wiki.js
+lib/Mojolicious/public/mojo/prettify/lang-xq.js
+lib/Mojolicious/public/mojo/prettify/lang-yaml.js
+lib/Mojolicious/public/mojo/prettify/prettify-mojo-dark.css
+lib/Mojolicious/public/mojo/prettify/prettify-mojo-light.css
+lib/Mojolicious/public/mojo/prettify/prettify.css
+lib/Mojolicious/public/mojo/prettify/prettify.js
+lib/Mojolicious/public/mojo/prettify/run_prettify.js
+lib/Mojolicious/public/mojo/stripes.png
+lib/Mojolicious/Renderer.pm
+lib/Mojolicious/Routes.pm
+lib/Mojolicious/Routes/Match.pm
+lib/Mojolicious/Routes/Pattern.pm
+lib/Mojolicious/Routes/Route.pm
+lib/Mojolicious/Sessions.pm
+lib/Mojolicious/Static.pm
+lib/Mojolicious/templates/development.html.ep
+lib/Mojolicious/templates/exception.html.ep
+lib/Mojolicious/templates/mojobar.html.ep
+lib/Mojolicious/templates/not_found.html.ep
+lib/Mojolicious/templates/perldoc.html.ep
+lib/Mojolicious/Types.pm
+lib/Mojolicious/Validator.pm
+lib/Mojolicious/Validator/Validation.pm
+lib/ojo.pm
+lib/Test/Mojo.pm
+LICENSE
+Makefile.PL
+MANIFEST			This list of files
+MANIFEST.SKIP
+README.md
+script/hypnotoad
+script/mojo
+script/morbo
+t/mojo/asset.t
+t/mojo/base.t
+t/mojo/bytestream.t
+t/mojo/cache.t
+t/mojo/certs/badclient.crt
+t/mojo/certs/badclient.key
+t/mojo/certs/ca.crt
+t/mojo/certs/ca.key
+t/mojo/certs/client.crt
+t/mojo/certs/client.key
+t/mojo/certs/server.crt
+t/mojo/certs/server.key
+t/mojo/cgi.t
+t/mojo/collection.t
+t/mojo/content.t
+t/mojo/cookie.t
+t/mojo/cookiejar.t
+t/mojo/daemon.t
+t/mojo/date.t
+t/mojo/delay.t
+t/mojo/dom.t
+t/mojo/eventemitter.t
+t/mojo/headers.t
+t/mojo/home.t
+t/mojo/hypnotoad.t
+t/mojo/ioloop.t
+t/mojo/ioloop_ipv6.t
+t/mojo/ioloop_tls.t
+t/mojo/json.t
+t/mojo/json_pointer.t
+t/mojo/lib/Mojo/BaseTest/Base1.pm
+t/mojo/lib/Mojo/BaseTest/Base2.pm
+t/mojo/lib/Mojo/BaseTest/Base3.pm
+t/mojo/lib/Mojo/DeprecationTest.pm
+t/mojo/lib/Mojo/LoaderException.pm
+t/mojo/lib/Mojo/LoaderException2.pm
+t/mojo/lib/Mojo/LoaderTest/A.pm
+t/mojo/lib/Mojo/LoaderTest/B.pm
+t/mojo/lib/Mojo/LoaderTest/C.pm
+t/mojo/loader.t
+t/mojo/log.t
+t/mojo/morbo.t
+t/mojo/parameters.t
+t/mojo/path.t
+t/mojo/prefork.t
+t/mojo/proxy.t
+t/mojo/psgi.t
+t/mojo/reactor_ev.t
+t/mojo/reactor_poll.t
+t/mojo/request.t
+t/mojo/request_cgi.t
+t/mojo/response.t
+t/mojo/template.t
+t/mojo/templates/exception.mt
+t/mojo/templates/test.mt
+t/mojo/templates/utf8_exception.mt
+t/mojo/transactor.t
+t/mojo/url.t
+t/mojo/user_agent.t
+t/mojo/user_agent_online.t
+t/mojo/user_agent_socks.t
+t/mojo/user_agent_tls.t
+t/mojo/util.t
+t/mojo/websocket.t
+t/mojo/websocket_frames.t
+t/mojo/websocket_proxy.t
+t/mojo/websocket_proxy_tls.t
+t/mojolicious/app.t
+t/mojolicious/charset_lite_app.t
+t/mojolicious/command.t
+t/mojolicious/commands.t
+t/mojolicious/dispatch.t
+t/mojolicious/dispatcher_lite_app.t
+t/mojolicious/embedded_app.t
+t/mojolicious/embedded_lite_app.json
+t/mojolicious/embedded_lite_app.t
+t/mojolicious/exception_lite_app.t
+t/mojolicious/external/lib/MyApp.pm
+t/mojolicious/external/my_app.conf
+t/mojolicious/external/my_app.testing.conf
+t/mojolicious/external/myapp.conf
+t/mojolicious/external/myapp.pl
+t/mojolicious/external/myapp.testing.conf
+t/mojolicious/external/myapp2.pl
+t/mojolicious/external/public/index.html
+t/mojolicious/external/script/my_app
+t/mojolicious/external/templates/index.html.ep
+t/mojolicious/external_app.t
+t/mojolicious/external_lite_app.t
+t/mojolicious/group_lite_app.t
+t/mojolicious/json_config_lite_app.json
+t/mojolicious/json_config_lite_app.t
+t/mojolicious/json_config_lite_app_abs.development.json
+t/mojolicious/json_config_lite_app_abs.json
+t/mojolicious/json_config_mode_lite_app.json
+t/mojolicious/json_config_mode_lite_app.t
+t/mojolicious/json_config_mode_lite_app.testing.json
+t/mojolicious/layouted_lite_app.t
+t/mojolicious/lib/AroundPlugin.pm
+t/mojolicious/lib/EmbeddedTestApp.pm
+t/mojolicious/lib/MojoliciousConfigTest.pm
+t/mojolicious/lib/MojoliciousTest.pm
+t/mojolicious/lib/MojoliciousTest/Baz.pm
+t/mojolicious/lib/MojoliciousTest/Command/test_command.pm
+t/mojolicious/lib/MojoliciousTest/Exceptional.pm
+t/mojolicious/lib/MojoliciousTest/Foo.pm
+t/mojolicious/lib/MojoliciousTest/Foo/Bar.pm
+t/mojolicious/lib/MojoliciousTest/Plugin/Test/SomePlugin2.pm
+t/mojolicious/lib/MojoliciousTest/Plugin/UPPERCASETestPlugin.pm
+t/mojolicious/lib/MojoliciousTest/SyntaxError.pm
+t/mojolicious/lib/MojoliciousTest2/Foo.pm
+t/mojolicious/lib/MojoliciousTest3/Bar.pm
+t/mojolicious/lib/MojoliciousTest3/Baz.pm
+t/mojolicious/lib/MojoliciousTestController.pm
+t/mojolicious/lib/PluginWithEmbeddedApp.pm
+t/mojolicious/lib/PluginWithTemplate.pm
+t/mojolicious/lib/SingleFileTestApp.pm
+t/mojolicious/lite_app.t
+t/mojolicious/longpolling_lite_app.t
+t/mojolicious/mojolicious_config_test.whatever.conf
+t/mojolicious/multipath_lite_app.t
+t/mojolicious/ojo.t
+t/mojolicious/pattern.t
+t/mojolicious/pod_renderer_lite_app.t
+t/mojolicious/production_app.t
+t/mojolicious/public/hello.txt
+t/mojolicious/public/hello2.txt
+t/mojolicious/public/hello4.txt
+t/mojolicious/public2/hello.txt
+t/mojolicious/public2/hello3.txt
+t/mojolicious/public_dev/another/file
+t/mojolicious/public_dev/hello.txt
+t/mojolicious/rebased_lite_app.t
+t/mojolicious/renderer.t
+t/mojolicious/restful_lite_app.t
+t/mojolicious/routes.t
+t/mojolicious/secret.txt
+t/mojolicious/single_file_test_app.conf
+t/mojolicious/static_lite_app.t
+t/mojolicious/tag_helper_lite_app.t
+t/mojolicious/templates/23.html.epl
+t/mojolicious/templates/dies_too.html.ep
+t/mojolicious/templates/encoding.koi8-r.ep
+t/mojolicious/templates/exception.html.epl
+t/mojolicious/templates/exception.testing.html.ep
+t/mojolicious/templates/foo/bar.rss.ep
+t/mojolicious/templates/foo/bar/index.html.epl
+t/mojolicious/templates/foo/bar/test.html.ep
+t/mojolicious/templates/foo/index.html.xpl
+t/mojolicious/templates/foo/yada.html.ep
+t/mojolicious/templates/layouts/default.html.epl
+t/mojolicious/templates/layouts/green.html.epl
+t/mojolicious/templates/not_found.testing.html.ep
+t/mojolicious/templates/simple.html.pod
+t/mojolicious/templates/syntaxerror.html.epl
+t/mojolicious/templates/withblock.txt.epl
+t/mojolicious/templates/WithGreenLayout.html.epl
+t/mojolicious/templates2/42.html+test.ep
+t/mojolicious/templates2/42.html.ep
+t/mojolicious/templates2/foo/yada.html.epl
+t/mojolicious/testing_app.t
+t/mojolicious/tls_lite_app.t
+t/mojolicious/twinkle_lite_app.conf
+t/mojolicious/twinkle_lite_app.t
+t/mojolicious/types.t
+t/mojolicious/upload_lite_app.t
+t/mojolicious/upload_stream_lite_app.t
+t/mojolicious/validation_lite_app.t
+t/mojolicious/websocket_lite_app.t
+t/pod.t
+t/pod_coverage.t
@@ -4,7 +4,7 @@
       "Sebastian Riedel <sri@cpan.org>"
    ],
    "dynamic_config" : 1,
-   "generated_by" : "ExtUtils::MakeMaker version 6.98, CPAN::Meta::Converter version 2.141520",
+   "generated_by" : "ExtUtils::MakeMaker version 6.98, CPAN::Meta::Converter version 2.142690",
    "license" : [
       "artistic_2"
    ],
@@ -33,6 +33,8 @@
       },
       "runtime" : {
          "requires" : {
+            "Pod::Simple" : "3.09",
+            "Time::Local" : "1.2",
             "perl" : "5.010001"
          }
       }
@@ -40,16 +42,16 @@
    "release_status" : "stable",
    "resources" : {
       "bugtracker" : {
-         "web" : "http://github.com/kraih/mojo/issues"
+         "web" : "https://github.com/kraih/mojo/issues"
       },
       "homepage" : "http://mojolicio.us",
       "license" : [
          "http://www.opensource.org/licenses/artistic-license-2.0"
       ],
       "repository" : {
-         "url" : "http://github.com/kraih/mojo"
+         "url" : "https://github.com/kraih/mojo.git"
       },
-      "x_MailingList" : "http://groups.google.com/group/mojolicious"
+      "x_IRC" : "irc://irc.perl.org/#mojo"
    },
-   "version" : "5.16"
+   "version" : "5.47"
 }
@@ -7,7 +7,7 @@ build_requires:
 configure_requires:
   ExtUtils::MakeMaker: '0'
 dynamic_config: 1
-generated_by: 'ExtUtils::MakeMaker version 6.98, CPAN::Meta::Converter version 2.141520'
+generated_by: 'ExtUtils::MakeMaker version 6.98, CPAN::Meta::Converter version 2.142690'
 license: artistic_2
 meta-spec:
   url: http://module-build.sourceforge.net/META-spec-v1.4.html
@@ -19,11 +19,13 @@ no_index:
     - inc
     - t
 requires:
+  Pod::Simple: '3.09'
+  Time::Local: '1.2'
   perl: '5.010001'
 resources:
-  MailingList: http://groups.google.com/group/mojolicious
-  bugtracker: http://github.com/kraih/mojo/issues
+  IRC: irc://irc.perl.org/#mojo
+  bugtracker: https://github.com/kraih/mojo/issues
   homepage: http://mojolicio.us
   license: http://www.opensource.org/licenses/artistic-license-2.0
-  repository: http://github.com/kraih/mojo
-version: '5.16'
+  repository: https://github.com/kraih/mojo.git
+version: '5.47'
@@ -5,6 +5,8 @@ use warnings;
 
 use ExtUtils::MakeMaker;
 
+# Pod::Simple 3.09 first shipped with Perl 5.11.2
+# Time::Local 1.2 first shipped with Perl 5.13.9
 WriteMakefile(
   NAME         => 'Mojolicious',
   VERSION_FROM => 'lib/Mojolicious.pm',
@@ -14,14 +16,15 @@ WriteMakefile(
   META_MERGE   => {
     requires  => {perl => '5.010001'},
     resources => {
-      homepage    => 'http://mojolicio.us',
-      license     => 'http://www.opensource.org/licenses/artistic-license-2.0',
-      MailingList => 'http://groups.google.com/group/mojolicious',
-      repository  => 'http://github.com/kraih/mojo',
-      bugtracker  => 'http://github.com/kraih/mojo/issues'
+      license    => 'http://www.opensource.org/licenses/artistic-license-2.0',
+      homepage   => 'http://mojolicio.us',
+      bugtracker => 'https://github.com/kraih/mojo/issues',
+      repository => 'https://github.com/kraih/mojo.git',
+      x_IRC      => 'irc://irc.perl.org/#mojo'
     },
     no_index => {directory => ['t']}
   },
+  PREREQ_PM => {'Pod::Simple' => '3.09', 'Time::Local' => '1.2'},
   EXE_FILES => ['script/hypnotoad', 'script/mojo', 'script/morbo'],
   test => {TESTS => 't/*.t t/*/*.t'}
 );
@@ -12,19 +12,17 @@
 ## Features
 
   * An amazing real-time web framework, allowing you to easily grow single
-    file [Mojolicious::Lite](http://mojolicio.us/perldoc/Mojolicious/Lite)
-    prototypes into well structured web applications.
+    file prototypes into well-structured web applications.
     * Powerful out of the box with RESTful routes, plugins, commands, Perl-ish
       templates, content negotiation, session management, form validation,
       testing framework, static file server, first class Unicode support and
       much more for you to discover.
-  * Very clean, portable and Object Oriented pure-Perl API without any hidden
-    magic and no requirements besides Perl 5.10.1 (although 5.18+ is
-    recommended, and optional CPAN modules will be used to provide advanced
-    functionality if they are installed).
+  * Very clean, portable and Object Oriented pure-Perl API with no hidden
+    magic and no requirements besides Perl 5.18.0 (versions as old as 5.10.1
+    can be used too, but may require additional CPAN modules to be installed)
   * Full stack HTTP and WebSocket client/server implementation with IPv6, TLS,
-    SNI, IDNA, Comet (long polling), keep-alive, connection pooling, timeout,
-    cookie, multipart, proxy, and gzip compression support.
+    SNI, IDNA, HTTP/SOCKS5 proxy, Comet (long polling), keep-alive, connection
+    pooling, timeout, cookie, multipart, and gzip compression support.
   * Built-in non-blocking I/O web server, supporting multiple event loops as
     well as optional preforking and hot deployment, perfect for embedding.
   * Automatic CGI and [PSGI](http://plackperl.org) detection.
@@ -47,7 +45,7 @@
 ```perl
 use Mojolicious::Lite;
 
-get '/' => {text => 'Hello World!'};
+get '/' => {text => 'I ♥ Mojolicious!'};
 
 app->start;
 ```
@@ -59,50 +57,42 @@ app->start;
     Server available at http://127.0.0.1:3000.
 
     $ curl http://127.0.0.1:3000/
-    Hello World!
+    I ♥ Mojolicious!
 
 ## Duct tape for the HTML5 web
 
-  Web development for humans, making hard things possible and everything fun.
+  Use all the latest Perl and HTML features in beautiful single file
+  prototypes like this one, and grow them easily into well-structured
+  applications.
 
 ```perl
 use Mojolicious::Lite;
+use 5.20.0;
+use experimental 'signatures';
 
-# Simple plain text response
-get '/' => {text => 'I ♥ Mojolicious!'};
-
-# Route associating "/time" with template in DATA section
-get '/time' => 'clock';
+# Render template "index.html.ep" from the DATA section
+get '/' => {template => 'index'};
 
-# Scrape information from remote sites
-post '/title' => sub {
-  my $c     = shift;
-  my $url   = $c->param('url') || 'http://mojolicio.us';
-  my $title = $c->ua->get($url)->res->dom->at('title')->text;
-  $c->render(json => {url => $url, title => $title});
-};
-
-# WebSocket echo service
-websocket '/echo' => sub {
-  my $c = shift;
-  $c->on(message => sub {
-    my ($c, $msg) = @_;
-    $c->send("echo: $msg");
+# WebSocket service used by the template to extract the title from a web site
+websocket '/title' => sub ($c) {
+  $c->on(message => sub ($c, $msg) {
+    my $title = $c->ua->get($msg)->res->dom->at('title')->text;
+    $c->send($title);
   });
 };
 
 app->start;
 __DATA__
 
-@@ clock.html.ep
-% use Time::Piece;
-% my $now = localtime;
-The time is <%= $now->hms %>.
+@@ index.html.ep
+% my $url = url_for 'title';
+<script>
+  var ws = new WebSocket('<%= $url->to_abs %>');
+  ws.onmessage = function (event) { document.body.innerHTML += event.data };
+  ws.onopen    = function (event) { ws.send('http://mojolicio.us') };
+</script>
 ```
 
-  Single file prototypes like this one can easily grow into well-structured
-  applications.
-
 ## Want to know more?
 
   Take a look at our excellent [documentation](http://mojolicio.us/perldoc>)!
@@ -1,7 +1,4 @@
-use FindBin;
-use lib "$FindBin::Bin/../lib";
 use Mojo::Base -strict;
-
 use Mojo::IOLoop;
 
 # Minimal CONNECT proxy server to test TLS tunneling
@@ -76,7 +73,7 @@ Mojo::IOLoop->server(
       }
     );
   }
-) or die "Couldn't create listen socket!\n";
+);
 
 print <<'EOF';
 Starting CONNECT proxy on port 3000.
@@ -1,13 +1,9 @@
-use FindBin;
-use lib "$FindBin::Bin/../lib";
 use Mojo::Base -strict;
-
 use Mojo::ByteStream 'b';
 use Mojo::UserAgent;
 
 # Extract named character references from HTML spec
-my $tx = Mojo::UserAgent->new->get(
-  'http://www.whatwg.org/specs/web-apps/current-work/');
+my $tx = Mojo::UserAgent->new->get('https://html.spec.whatwg.org');
 b($_->at('td > code')->text . ' ' . $_->children('td')->[1]->text)->trim->say
   for $tx->res->dom('#named-character-references-table tbody > tr')->each;
 
@@ -1,5 +1,3 @@
-use FindBin;
-use lib "$FindBin::Bin/../lib";
 use Mojo::Base 'Mojolicious';
 
 sub handler {
@@ -0,0 +1,10 @@
+use Mojolicious::Lite;
+
+get '/hello';
+
+# Minimal "Hello World" application with template for profiling
+app->start;
+__DATA__
+
+@@ hello.html.ep
+Hello World!
@@ -1,5 +1,3 @@
-use FindBin;
-use lib "$FindBin::Bin/../lib";
 use Mojolicious::Lite;
 
 get '/' => {data => 'Hello World!'};
@@ -1,7 +1,4 @@
-use FindBin;
-use lib "$FindBin::Bin/../lib";
 use Mojo::Base -strict;
-
 use Mojo::IOLoop;
 
 # Minimal ioloop example demonstrating how to cheat at HTTP benchmarks :)
@@ -32,7 +29,7 @@ Mojo::IOLoop->server(
     );
     $stream->on(close => sub { delete $buffer{$id} });
   }
-) or die "Couldn't create listen socket!\n";
+);
 
 print <<'EOF';
 Starting server on port 8080.
@@ -1,5 +1,3 @@
-use FindBin;
-use lib "$FindBin::Bin/../lib";
 use Mojolicious::Lite;
 
 websocket '/test' => sub {
@@ -78,8 +78,7 @@ sub contains {
     # Search window
     my $pos = index $window, $str;
     return $offset + $pos if $pos >= 0;
-    $offset += $read;
-    return -1 if $read == 0 || $offset == $end;
+    return -1 if $read == 0 || ($offset += $read) == $end;
 
     # Resize window
     substr $window, 0, $read, '';
@@ -98,8 +97,7 @@ sub get_chunk {
 
   my $buffer;
   if (defined(my $end = $self->end_range)) {
-    my $chunk = $end + 1 - $offset;
-    return '' if $chunk <= 0;
+    return '' if (my $chunk = $end + 1 - $offset) <= 0;
     $handle->sysread($buffer, $chunk > $max ? $max : $chunk);
   }
   else { $handle->sysread($buffer, $max) }
@@ -122,17 +120,13 @@ sub move_to {
   return $self->path($to)->cleanup(0);
 }
 
-sub size {
-  return 0 unless defined(my $file = shift->path);
-  return -s $file;
-}
+sub mtime { (stat shift->handle)[9] }
+
+sub size { -s shift->handle }
 
 sub slurp {
-  my $handle = shift->handle;
-  $handle->sysseek(0, SEEK_SET);
-  my $content = '';
-  while ($handle->sysread(my $buffer, 131072)) { $content .= $buffer }
-  return $content;
+  return '' unless defined(my $file = shift->path);
+  return Mojo::Util::slurp $file;
 }
 
 1;
@@ -238,6 +232,12 @@ True.
 
 Move asset data into a specific file and disable L</"cleanup">.
 
+=head2 mtime
+
+  my $mtime = $file->mtime;
+
+Modification time of asset.
+
 =head2 size
 
   my $size = $file->size;
@@ -4,8 +4,12 @@ use Mojo::Base 'Mojo::Asset';
 use Mojo::Asset::File;
 use Mojo::Util 'spurt';
 
+# Last modified default
+my $MTIME = time;
+
 has 'auto_upgrade';
 has max_memory_size => sub { $ENV{MOJO_MAX_MEMORY_SIZE} || 262144 };
+has mtime => sub {$MTIME};
 
 sub add_chunk {
   my ($self, $chunk) = @_;
@@ -114,6 +118,13 @@ Maximum size in bytes of data to keep in memory before automatically upgrading
 to a L<Mojo::Asset::File> object, defaults to the value of the
 C<MOJO_MAX_MEMORY_SIZE> environment variable or C<262144> (256KB).
 
+=head2 mtime
+
+  my $mtime = $mem->mtime;
+  $mem      = $mem->mtime(1408567500);
+
+Modification time of asset, defaults to the time this class was loaded.
+
 =head1 METHODS
 
 L<Mojo::Asset::Memory> inherits all methods from L<Mojo::Asset> and implements
@@ -15,6 +15,7 @@ sub is_file {undef}
 sub is_range { !!($_[0]->end_range || $_[0]->start_range) }
 
 sub move_to { croak 'Method "move_to" not implemented by subclass' }
+sub mtime   { croak 'Method "mtime" not implemented by subclass' }
 sub size    { croak 'Method "size" not implemented by subclass' }
 sub slurp   { croak 'Method "slurp" not implemented by subclass' }
 
@@ -35,6 +36,7 @@ Mojo::Asset - HTTP content storage base class
   sub contains  {...}
   sub get_chunk {...}
   sub move_to   {...}
+  sub mtime     {...}
   sub size      {...}
   sub slurp     {...}
 
@@ -108,6 +110,12 @@ Check if asset has a L</"start_range"> or L</"end_range">.
 
 Move asset data into a specific file. Meant to be overloaded in a subclass.
 
+=head2 mtime
+
+  my $mtime = $asset->mtime;
+
+Modification time of asset. Meant to be overloaded in a subclass.
+
 =head2 size
 
   my $size = $asset->size;
@@ -70,11 +70,8 @@ sub attr {
       $code .= ref $default eq 'CODE' ? '$default->($_[0]);' : '$default;';
     }
 
-    # Store value
-    $code .= "\n  }\n  \$_[0]{'$attr'} = \$_[1];\n";
-
-    # Footer (return invocant)
-    $code .= "  \$_[0];\n}";
+    # Footer (store value and return invocant)
+    $code .= "\n  }\n  \$_[0]{'$attr'} = \$_[1];\n  \$_[0];\n}";
 
     warn "-- Attribute $attr in $class\n$code\n\n" if $ENV{MOJO_BASE_DEBUG};
     Carp::croak "Mojo::Base error: $@" unless eval "$code;1";
@@ -1,6 +1,6 @@
 package Mojo::ByteStream;
 use Mojo::Base -strict;
-use overload '""' => sub { shift->to_string }, fallback => 1;
+use overload '""' => sub { ${$_[0]} }, fallback => 1;
 
 use Exporter 'import';
 use Mojo::Collection;
@@ -8,9 +8,11 @@ sub get { (shift->{cache} || {})->{shift()} }
 sub set {
   my ($self, $key, $value) = @_;
 
+  return $self unless (my $max = $self->max_keys) > 0;
+
   my $cache = $self->{cache} ||= {};
   my $queue = $self->{queue} ||= [];
-  delete $cache->{shift @$queue} while @$queue >= $self->max_keys;
+  delete $cache->{shift @$queue} while @$queue >= $max;
   push @$queue, $key unless exists $cache->{$key};
   $cache->{$key} = $value;
 
@@ -46,7 +48,8 @@ L<Mojo::Cache> implements the following attributes.
   my $max = $cache->max_keys;
   $cache  = $cache->max_keys(50);
 
-Maximum number of cache keys, defaults to C<100>.
+Maximum number of cache keys, defaults to C<100>. Setting the value to C<0>
+will disable caching.
 
 =head1 METHODS
 
@@ -15,7 +15,7 @@ our @EXPORT_OK = ('c');
 
 sub AUTOLOAD {
   my $self = shift;
-  my ($package, $method) = split /::(\w+)$/, our $AUTOLOAD;
+  my ($package, $method) = our $AUTOLOAD =~ /^(.+)::(.+)$/;
   croak "Undefined subroutine &${package}::$method called"
     unless blessed $self && $self->isa(__PACKAGE__);
   return $self->pluck($method, @_);
@@ -26,7 +26,7 @@ sub DESTROY { }
 sub c { __PACKAGE__->new(@_) }
 
 sub compact {
-  shift->grep(sub { length($_ // '') });
+  $_[0]->new(grep { defined $_ && (ref $_ || length $_) } @{$_[0]});
 }
 
 sub each {
@@ -70,7 +70,13 @@ sub new {
 
 sub pluck {
   my ($self, $method, @args) = @_;
-  return $self->map(sub { $_->$method(@args) });
+  return $self->new(map { $_->$method(@args) } @$self);
+}
+
+sub reduce {
+  my $self = shift;
+  @_ = (@_, @$self);
+  goto &List::Util::reduce;
 }
 
 sub reverse { $_[0]->new(reverse @{$_[0]}) }
@@ -86,14 +92,23 @@ sub slice {
 
 sub sort {
   my ($self, $cb) = @_;
-  return $self->new($cb ? sort { $a->$cb($b) } @$self : sort @$self);
+
+  return $self->new(sort @$self) unless $cb;
+
+  my $caller = caller;
+  no strict 'refs';
+  my @sorted = sort {
+    local (*{"${caller}::a"}, *{"${caller}::b"}) = (\$a, \$b);
+    $a->$cb($b);
+  } @$self;
+  return $self->new(@sorted);
 }
 
 sub tap { shift->Mojo::Base::tap(@_) }
 
 sub uniq {
   my %seen;
-  return shift->grep(sub { !$seen{$_}++ });
+  return $_[0]->new(grep { !$seen{$_}++ } @{$_[0]});
 }
 
 sub _flatten {
@@ -172,6 +187,7 @@ Evaluate callback for each element in collection or return all elements as a
 list if none has been provided. The element will be the first argument passed
 to the callback and is also available as C<$_>.
 
+  # Make a numbered list
   $collection->each(sub {
     my ($e, $count) = @_;
     say "$count: $e";
@@ -188,7 +204,8 @@ return the first one that matched the regular expression, or for which the
 callback returned true. The element will be the first argument passed to the
 callback and is also available as C<$_>.
 
-  my $five = $collection->first(sub { $_ == 5 });
+  # Find first value that is greater than 5
+  my $greater = $collection->first(sub { $_ > 5 });
 
 =head2 flatten
 
@@ -207,6 +224,7 @@ create a new collection with all elements that matched the regular expression,
 or for which the callback returned true. The element will be the first
 argument passed to the callback and is also available as C<$_>.
 
+  # Find all values that contain the word "mojo"
   my $interesting = $collection->grep(qr/mojo/i);
 
 =head2 join
@@ -216,7 +234,8 @@ argument passed to the callback and is also available as C<$_>.
 
 Turn collection into L<Mojo::ByteStream>.
 
-  $collection->join("\n")->say;
+  # Join all values with commas
+  $collection->join(', ')->say;
 
 =head2 last
 
@@ -232,7 +251,8 @@ Evaluate callback for each element in collection and create a new collection
 from the results. The element will be the first argument passed to the
 callback and is also available as C<$_>.
 
-  my $doubled = $collection->map(sub { $_ * 2 });
+  # Append the word "mojo" to all values
+  my $mojoified = $collection->map(sub { $_ . 'mojo' });
 
 =head2 new
 
@@ -251,6 +271,20 @@ results.
   # Equal to but more convenient than
   my $new = $collection->map(sub { $_->$method(@args) });
 
+=head2 reduce
+
+  my $result = $collection->reduce(sub {...});
+  my $result = $collection->reduce(sub {...}, $initial);
+
+Reduce elements in collection with callback, the first element will be used as
+initial value if none has been provided.
+
+  # Calculate the sum of all values
+  my $sum = $collection->reduce(sub { $a + $b });
+
+  # Count how often each value occurs in collection
+  my $hash = $collection->reduce(sub { $a->{$b}++; $a }, {});
+
 =head2 reverse
 
   my $new = $collection->reverse;
@@ -283,7 +317,8 @@ Number of elements in collection.
 Sort elements based on return value of callback and create a new collection
 from the results.
 
-  my $insensitive = $collection->sort(sub { uc(shift) cmp uc(shift) });
+  # Sort values case insensitive
+  my $insensitive = $collection->sort(sub { uc($a) cmp uc($b) });
 
 =head2 tap
 
@@ -303,8 +338,10 @@ In addition to the L</"METHODS"> above, you can also call methods provided by
 all elements in the collection directly and create a new collection from the
 results, similar to L</"pluck">.
 
-  push @$collection, Mojo::DOM->new("<div><h1>$_</h1></div>") for 1 .. 9;
-  say $collection->find('h1')->type('h2')->prepend_content('Test ')->root;
+  # "<h2>Test1</h2><h2>Test2</h2>"
+  my $collection = Mojo::Collection->new(
+    Mojo::DOM->new("<h1>1</h1>"), Mojo::DOM->new("<h1>2</h1>"));
+  $collection->at('h1')->type('h2')->prepend_content('Test')->join;
 
 =head1 OPERATORS
 
@@ -10,6 +10,9 @@ has headers           => sub { Mojo::Headers->new };
 has max_buffer_size   => sub { $ENV{MOJO_MAX_BUFFER_SIZE} || 262144 };
 has max_leftover_size => sub { $ENV{MOJO_MAX_LEFTOVER_SIZE} || 262144 };
 
+my $BOUNDARY_RE
+  = qr!multipart.*boundary\s*=\s*(?:"([^"]+)"|([\w'(),.:?\-+/]+))!i;
+
 sub body_contains {
   croak 'Method "body_contains" not implemented by subclass';
 }
@@ -17,10 +20,7 @@ sub body_contains {
 sub body_size { croak 'Method "body_size" not implemented by subclass' }
 
 sub boundary {
-  return undef unless my $type = shift->headers->content_type;
-  $type =~ m!multipart.*boundary\s*=\s*(?:"([^"]+)"|([\w'(),.:?\-+/]+))!i
-    and return $1 // $2;
-  return undef;
+  (shift->headers->content_type // '') =~ $BOUNDARY_RE ? $1 // $2 : undef;
 }
 
 sub build_body    { shift->_build('get_body_chunk') }
@@ -179,8 +179,7 @@ sub write_chunk {
 sub _build {
   my ($self, $method) = @_;
 
-  my $buffer = '';
-  my $offset = 0;
+  my ($buffer, $offset) = ('', 0);
   while (1) {
 
     # No chunk yet, try again
@@ -14,13 +14,6 @@ my $ATTR_RE   = qr/
   )?
   \]
 /x;
-my $CLASS_ID_RE = qr/
-  (?:
-    (?:\.((?:\\\.|[^\#.])+))   # Class
-  |
-    (?:\#((?:\\\#|[^.\#])+))   # ID
-  )
-/x;
 my $PSEUDO_CLASS_RE = qr/(?::([\w\-]+)(?:\(((?:\([^)]+\)|[^)])+)\))?)/;
 my $TOKEN_RE        = qr/
   (\s*,\s*)?                         # Separator
@@ -35,8 +28,8 @@ sub match {
   return $tree->[0] ne 'tag' ? undef : _match(_compile(shift), $tree, $tree);
 }
 
-sub select     { shift->_select(0, @_) }
-sub select_one { shift->_select(1, @_) }
+sub select     { _select(0, shift->tree, _compile(@_)) }
+sub select_one { _select(1, shift->tree, _compile(@_)) }
 
 sub _ancestor {
   my ($selectors, $current, $tree) = @_;
@@ -112,9 +105,9 @@ sub _compile {
     push @$selector, ['tag', $tag];
 
     # Class or ID
-    while ($element =~ /$CLASS_ID_RE/go) {
-      push @$selector, ['attr', 'class', _regex('~', $1)] if defined $1;
-      push @$selector, ['attr', 'id',    _regex('',  $2)] if defined $2;
+    while ($element =~ /(?:([.#])((?:\\[.\#]|[^\#.])+))/g) {
+      my ($name, $op) = $1 eq '.' ? ('class', '~') : ('id', '');
+      push @$selector, ['attr', $name, _regex($op, $2)];
     }
 
     # Pseudo classes (":not" contains more selectors)
@@ -232,12 +225,10 @@ sub _regex {
 }
 
 sub _select {
-  my ($self, $one, $selector) = @_;
+  my ($one, $tree, $pattern) = @_;
 
   my @results;
-  my $pattern = _compile($selector);
-  my $tree    = $self->tree;
-  my @queue   = ($tree);
+  my @queue = ($tree);
   while (my $current = shift @queue) {
     my $type = $current->[0];
 
@@ -312,13 +312,13 @@ Mojo::DOM::HTML - HTML/XML engine
 
   # Turn HTML into DOM tree
   my $html = Mojo::DOM::HTML->new;
-  $html->parse('<div><p id="a">A</p><p id="b">B</p></div>');
+  $html->parse('<div><p id="a">Test</p><p id="b">123</p></div>');
   my $tree = $html->tree;
 
 =head1 DESCRIPTION
 
 L<Mojo::DOM::HTML> is the HTML/XML engine used by L<Mojo::DOM> and based on
-the L<HTML Living Standard|http://www.whatwg.org/html> as well as the
+the L<HTML Living Standard|https://html.spec.whatwg.org> as well as the
 L<Extensible Markup Language (XML) 1.0|http://www.w3.org/TR/xml/>.
 
 =head1 ATTRIBUTES
@@ -20,7 +20,7 @@ use Scalar::Util qw(blessed weaken);
 sub AUTOLOAD {
   my $self = shift;
 
-  my ($package, $method) = split /::(\w+)$/, our $AUTOLOAD;
+  my ($package, $method) = our $AUTOLOAD =~ /^(.+)::(.+)$/;
   croak "Undefined subroutine &${package}::$method called"
     unless blessed $self && $self->isa(__PACKAGE__);
 
@@ -45,7 +45,7 @@ sub append_content { shift->_content(1, 0, @_) }
 sub at {
   my $self = shift;
   return undef unless my $result = $self->_css->select_one(@_);
-  return _tag($self, $result, $self->xml);
+  return _build($self, $result, $self->xml);
 }
 
 sub attr {
@@ -60,7 +60,8 @@ sub attr {
   return $attrs->{$_[0]} // '' unless @_ > 1 || ref $_[0];
 
   # Set
-  %$attrs = (%$attrs, %{ref $_[0] ? $_[0] : {@_}});
+  my $values = ref $_[0] ? $_[0] : {@_};
+  @$attrs{keys %$values} = values %$values;
 
   return $self;
 }
@@ -118,15 +119,15 @@ sub new {
   return @_ ? $self->parse(@_) : $self;
 }
 
-sub next { shift->_siblings->[1][0] }
-sub next_sibling { shift->_siblings(0, 1)->[1][0] }
+sub next         { _maybe($_[0], $_[0]->_siblings(1)->[1]) }
+sub next_sibling { _maybe($_[0], $_[0]->_siblings->[1]) }
 
 sub node { shift->tree->[0] }
 
 sub parent {
   my $self = shift;
   return undef if $self->tree->[0] eq 'root';
-  return _tag($self, $self->_parent, $self->xml);
+  return _build($self, $self->_parent, $self->xml);
 }
 
 sub parse { shift->_delegate(parse => shift) }
@@ -135,8 +136,8 @@ sub prepend { shift->_add(0, @_) }
 
 sub prepend_content { shift->_content(0, 0, @_) }
 
-sub previous { shift->_siblings->[0][-1] }
-sub previous_sibling { shift->_siblings(0, 1)->[0][-1] }
+sub previous         { _maybe($_[0], $_[0]->_siblings(1)->[0]) }
+sub previous_sibling { _maybe($_[0], $_[0]->_siblings->[0]) }
 
 sub remove { shift->replace('') }
 
@@ -149,10 +150,10 @@ sub replace {
 sub root {
   my $self = shift;
   return $self unless my $tree = $self->_ancestors(1);
-  return _tag($self, $tree, $self->xml);
+  return _build($self, $tree, $self->xml);
 }
 
-sub siblings { _select(Mojo::Collection->new(@{_siblings($_[0], 1)}), $_[1]) }
+sub siblings { _select($_[0]->_collect(@{_siblings($_[0], 1, 1)}), $_[1]) }
 
 sub strip {
   my $self = shift;
@@ -176,6 +177,24 @@ sub type {
   return $self;
 }
 
+sub val {
+  my $self = shift;
+
+  # "option"
+  my $type = $self->type;
+  return Mojo::Collection->new($self->{value} // $self->text)
+    if $type eq 'option';
+
+  # "select"
+  return $self->find('option[selected]')->val->flatten if $type eq 'select';
+
+  # "textarea"
+  return Mojo::Collection->new($self->text) if $type eq 'textarea';
+
+  # "input" or "button"
+  return Mojo::Collection->new($self->{value} // ());
+}
+
 sub wrap         { shift->_wrap(0, @_) }
 sub wrap_content { shift->_wrap(1, @_) }
 
@@ -222,10 +241,12 @@ sub _ancestors {
   return $root ? $ancestors[-1] : @ancestors[0 .. $#ancestors - 1];
 }
 
+sub _build { shift->new->tree(shift)->xml(shift) }
+
 sub _collect {
   my $self = shift;
   my $xml  = $self->xml;
-  return Mojo::Collection->new(map { _tag($self, $_, $xml) } @_);
+  return Mojo::Collection->new(map { _build($self, $_, $xml) } @_);
 }
 
 sub _content {
@@ -268,6 +289,8 @@ sub _link {
   return @new;
 }
 
+sub _maybe { $_[1] ? _build($_[0], $_[1], $_[0]->xml) : undef }
+
 sub _nodes {
   return unless my $tree = shift;
   return @$tree[_start($tree) .. $#$tree];
@@ -297,25 +320,23 @@ sub _select {
 }
 
 sub _siblings {
-  my ($self, $merge, $all) = @_;
+  my ($self, $tags, $all) = @_;
 
-  return $merge ? [] : [[], []] unless my $parent = $self->parent;
+  return [] unless my $parent = $self->parent;
 
   my $tree = $self->tree;
   my (@before, @after, $match);
-  for my $child ($parent->contents->each) {
-    ++$match and next if $child->tree eq $tree;
-    next unless $all || $child->node eq 'tag';
-    $match ? push @after, $child : push @before, $child;
+  for my $node (_nodes($parent->tree)) {
+    ++$match and next if !$match && $node eq $tree;
+    next if $tags && $node->[0] ne 'tag';
+    $match ? push @after, $node : push @before, $node;
   }
 
-  return $merge ? [@before, @after] : [\@before, \@after];
+  return $all ? [@before, @after] : [$before[-1], $after[0]];
 }
 
 sub _start { $_[0][0] eq 'root' ? 1 : 4 }
 
-sub _tag { shift->new->tree(shift)->xml(shift) }
-
 sub _text {
   my ($nodes, $recurse, $trim) = @_;
 
@@ -391,7 +412,7 @@ Mojo::DOM - Minimalistic HTML/XML DOM parser with CSS selectors
   use Mojo::DOM;
 
   # Parse
-  my $dom = Mojo::DOM->new('<div><p id="a">A</p><p id="b">B</p></div>');
+  my $dom = Mojo::DOM->new('<div><p id="a">Test</p><p id="b">123</p></div>');
 
   # Find
   say $dom->at('#b')->text;
@@ -403,7 +424,7 @@ Mojo::DOM - Minimalistic HTML/XML DOM parser with CSS selectors
   say $dom->div->children('p')->first->{id};
 
   # Iterate
-  $dom->find('p[id]')->each(sub { say $_->{id} });
+  $dom->find('p[id]')->reverse->each(sub { say $_->{id} });
 
   # Loop
   for my $e ($dom->find('p[id]')->each) {
@@ -411,7 +432,7 @@ Mojo::DOM - Minimalistic HTML/XML DOM parser with CSS selectors
   }
 
   # Modify
-  $dom->div->p->last->append('<p id="c">C</p>');
+  $dom->div->p->last->append('<p id="c">456</p>');
   $dom->find(':not(p)')->strip;
 
   # Render
@@ -459,7 +480,7 @@ Return a L<Mojo::Collection> object containing all nodes in DOM structure as
 L<Mojo::DOM> objects.
 
   # "<p><b>123</b></p>"
-  $dom->parse('<p><!-- test --><b>123<!-- 456 --></b></p>')
+  $dom->parse('<p><!-- Test --><b>123<!-- 456 --></b></p>')
     ->all_contents->grep(sub { $_->node eq 'comment' })->remove->first;
 
 =head2 all_text
@@ -494,27 +515,30 @@ All selectors from L<Mojo::DOM::CSS/"SELECTORS"> are supported.
 
 Append HTML/XML fragment to this node.
 
-  # "<div><h1>A</h1><h2>B</h2></div>"
-  $dom->parse('<div><h1>A</h1></div>')->at('h1')->append('<h2>B</h2>')->root;
+  # "<div><h1>Test</h1><h2>123</h2></div>"
+  $dom->parse('<div><h1>Test</h1></div>')->at('h1')
+    ->append('<h2>123</h2>')->root;
 
-  # "<p>test 123</p>"
-  $dom->parse('<p>test</p>')->at('p')->contents->first->append(' 123')->root;
+  # "<p>Test 123</p>"
+  $dom->parse('<p>Test</p>')->at('p')->contents->first->append(' 123')->root;
 
 =head2 append_content
 
   $dom = $dom->append_content('<p>I ♥ Mojolicious!</p>');
 
-Append HTML/XML fragment or raw content (depending on node type) to this
+Append HTML/XML fragment (for C<root> and C<tag> nodes) or raw content to this
 node's content.
 
-  # "<div><h1>AB</h1></div>"
-  $dom->parse('<div><h1>A</h1></div>')->at('h1')->append_content('B')->root;
+  # "<div><h1>Test123</h1></div>"
+  $dom->parse('<div><h1>Test</h1></div>')->at('h1')
+    ->append_content('123')->root;
 
-  # "<!-- A B --><br>"
-  $dom->parse('<!-- A --><br>')->contents->first->append_content('B ')->root;
+  # "<!-- Test 123 --><br>"
+  $dom->parse('<!-- Test --><br>')
+    ->contents->first->append_content('123 ')->root;
 
-  # "<p>A<i>B</i></p>"
-  $dom->parse('<p>A</p>')->at('p')->append_content('<i>B</i>')->root;
+  # "<p>Test<i>123</i></p>"
+  $dom->parse('<p>Test</p>')->at('p')->append_content('<i>123</i>')->root;
 
 =head2 at
 
@@ -529,10 +553,10 @@ from L<Mojo::DOM::CSS/"SELECTORS"> are supported.
 
 =head2 attr
 
-  my $attrs = $dom->attr;
-  my $foo   = $dom->attr('foo');
-  $dom      = $dom->attr({foo => 'bar'});
-  $dom      = $dom->attr(foo => 'bar');
+  my $hash = $dom->attr;
+  my $foo  = $dom->attr('foo');
+  $dom     = $dom->attr({foo => 'bar'});
+  $dom     = $dom->attr(foo => 'bar');
 
 This element's attributes.
 
@@ -556,26 +580,27 @@ All selectors from L<Mojo::DOM::CSS/"SELECTORS"> are supported.
   my $str = $dom->content;
   $dom    = $dom->content('<p>I ♥ Mojolicious!</p>');
 
-Return this node's content or replace it with HTML/XML fragment or raw content
-(depending on node type).
+Return this node's content or replace it with HTML/XML fragment (for C<root>
+and C<tag> nodes) or raw content.
 
-  # "<b>test</b>"
-  $dom->parse('<div><b>test</b></div>')->div->content;
+  # "<b>Test</b>"
+  $dom->parse('<div><b>Test</b></div>')->div->content;
 
-  # "<div><h1>B</h1></div>"
-  $dom->parse('<div><h1>A</h1></div>')->at('h1')->content('B')->root;
+  # "<div><h1>123</h1></div>"
+  $dom->parse('<div><h1>Test</h1></div>')->at('h1')->content('123')->root;
 
-  # "<div><h1></h1></div>"
-  $dom->parse('<div><h1>A</h1></div>')->at('h1')->content('')->root;
+  # "<p><i>123</i></p>"
+  $dom->parse('<p>Test</p>')->at('p')->content('<i>123</i>')->root;
 
-  # " A "
-  $dom->parse('<!-- A --><br>')->contents->first->content;
+  # "<div><h1></h1></div>"
+  $dom->parse('<div><h1>Test</h1></div>')->at('h1')->content('')->root;
 
-  # "<!-- B --><br>"
-  $dom->parse('<!-- A --><br>')->contents->first->content(' B ')->root;
+  # " Test "
+  $dom->parse('<!-- Test --><br>')->contents->first->content;
 
-  # "<p><i>B</i></p>"
-  $dom->parse('<p>A</p>')->at('p')->content('<i>B</i>')->root;
+  # "<div><!-- 123 -->456</div>"
+  $dom->parse('<div><!-- Test -->456</div>')->at('div')
+    ->contents->first->content(' 123 ')->root;
 
 =head2 contents
 
@@ -585,10 +610,10 @@ Return a L<Mojo::Collection> object containing the child nodes of this element
 as L<Mojo::DOM> objects.
 
   # "<p><b>123</b></p>"
-  $dom->parse('<p>test<b>123</b></p>')->at('p')->contents->first->remove;
+  $dom->parse('<p>Test<b>123</b></p>')->at('p')->contents->first->remove;
 
-  # "<!-- test -->"
-  $dom->parse('<!-- test --><b>123</b>')->contents->first;
+  # "<!-- Test -->"
+  $dom->parse('<!-- Test --><b>123</b>')->contents->first;
 
 =head2 find
 
@@ -603,7 +628,12 @@ All selectors from L<Mojo::DOM::CSS/"SELECTORS"> are supported.
 
   # Extract information from multiple elements
   my @headers = $dom->find('h1, h2, h3')->text->each;
-  my @links   = $dom->find('a[href]')->attr('href')->each;
+
+  # Count all the different tags
+  my $hash = $dom->find('*')->type->reduce(sub { $a->{$b}++; $a }, {});
+
+  # Find elements with a class that contains dots
+  my @divs = $dom->find('div.foo\.bar')->each;
 
 =head2 match
 
@@ -640,8 +670,8 @@ fragment if necessary.
 Return L<Mojo::DOM> object for next sibling element or C<undef> if there are
 no more siblings.
 
-  # "<h2>B</h2>"
-  $dom->parse('<div><h1>A</h1><h2>B</h2></div>')->at('h1')->next;
+  # "<h2>123</h2>"
+  $dom->parse('<div><h1>Test</h1><h2>123</h2></div>')->at('h1')->next;
 
 =head2 next_sibling
 
@@ -651,7 +681,7 @@ Return L<Mojo::DOM> object for next sibling node or C<undef> if there are no
 more siblings.
 
   # "456"
-  $dom->parse('<p><b>123</b><!-- test -->456</p>')->at('b')
+  $dom->parse('<p><b>123</b><!-- Test -->456</p>')->at('b')
     ->next_sibling->next_sibling;
 
 =head2 node
@@ -683,27 +713,30 @@ Parse HTML/XML fragment with L<Mojo::DOM::HTML>.
 
 Prepend HTML/XML fragment to this node.
 
-  # "<div><h1>A</h1><h2>B</h2></div>"
-  $dom->parse('<div><h2>B</h2></div>')->at('h2')->prepend('<h1>A</h1>')->root;
+  # "<div><h1>Test</h1><h2>123</h2></div>"
+  $dom->parse('<div><h2>123</h2></div>')->at('h2')
+    ->prepend('<h1>Test</h1>')->root;
 
-  # "<p>test 123</p>"
-  $dom->parse('<p>123</p>')->at('p')->contents->first->prepend('test ')->root;
+  # "<p>Test 123</p>"
+  $dom->parse('<p>123</p>')->at('p')->contents->first->prepend('Test ')->root;
 
 =head2 prepend_content
 
   $dom = $dom->prepend_content('<p>I ♥ Mojolicious!</p>');
 
-Prepend HTML/XML fragment or raw content (depending on node type) to this
-node's content.
+Prepend HTML/XML fragment (for C<root> and C<tag> nodes) or raw content to
+this node's content.
 
-  # "<div><h2>AB</h2></div>"
-  $dom->parse('<div><h2>B</h2></div>')->at('h2')->prepend_content('A')->root;
+  # "<div><h2>Test123</h2></div>"
+  $dom->parse('<div><h2>123</h2></div>')->at('h2')
+    ->prepend_content('Test')->root;
 
-  # "<!-- A B --><br>"
-  $dom->parse('<!-- B --><br>')->contents->first->prepend_content(' A')->root;
+  # "<!-- Test 123 --><br>"
+  $dom->parse('<!-- 123 --><br>')
+    ->contents->first->prepend_content(' Test')->root;
 
-  # "<p><i>B</i>A</p>"
-  $dom->parse('<p>A</p>')->at('p')->prepend_content('<i>B</i>')->root;
+  # "<p><i>123</i>Test</p>"
+  $dom->parse('<p>Test</p>')->at('p')->prepend_content('<i>123</i>')->root;
 
 =head2 previous
 
@@ -712,8 +745,8 @@ node's content.
 Return L<Mojo::DOM> object for previous sibling element or C<undef> if there
 are no more siblings.
 
-  # "<h1>A</h1>"
-  $dom->parse('<div><h1>A</h1><h2>B</h2></div>')->at('h2')->previous;
+  # "<h1>Test</h1>"
+  $dom->parse('<div><h1>Test</h1><h2>123</h2></div>')->at('h2')->previous;
 
 =head2 previous_sibling
 
@@ -723,7 +756,7 @@ Return L<Mojo::DOM> object for previous sibling node or C<undef> if there are
 no more siblings.
 
   # "123"
-  $dom->parse('<p>123<!-- test --><b>456</b></p>')->at('b')
+  $dom->parse('<p>123<!-- Test --><b>456</b></p>')->at('b')
     ->previous_sibling->previous_sibling;
 
 =head2 remove
@@ -733,7 +766,7 @@ no more siblings.
 Remove this node and return L</"parent">.
 
   # "<div></div>"
-  $dom->parse('<div><h1>A</h1></div>')->at('h1')->remove;
+  $dom->parse('<div><h1>Test</h1></div>')->at('h1')->remove;
 
   # "<p><b>456</b></p>"
   $dom->parse('<p>123<b>456</b></p>')->at('p')->contents->first->remove->root;
@@ -744,11 +777,12 @@ Remove this node and return L</"parent">.
 
 Replace this node with HTML/XML fragment and return L</"parent">.
 
-  # "<div><h2>B</h2></div>"
-  $dom->parse('<div><h1>A</h1></div>')->at('h1')->replace('<h2>B</h2>');
+  # "<div><h2>123</h2></div>"
+  $dom->parse('<div><h1>Test</h1></div>')->at('h1')->replace('<h2>123</h2>');
 
-  # "<p><b>B</b></p>"
-  $dom->parse('<p>A</p>')->at('p')->contents->[0]->replace('<b>B</b>')->root;
+  # "<p><b>123</b></p>"
+  $dom->parse('<p>Test</p>')->at('p')
+    ->contents->[0]->replace('<b>123</b>')->root;
 
 =head2 root
 
@@ -774,8 +808,8 @@ All selectors from L<Mojo::DOM::CSS/"SELECTORS"> are supported.
 
 Remove this element while preserving its content and return L</"parent">.
 
-  # "<div>A</div>"
-  $dom->parse('<div><h1>A</h1></div>')->at('h1')->strip;
+  # "<div>Test</div>"
+  $dom->parse('<div><h1>Test</h1></div>')->at('h1')->strip;
 
 =head2 tap
 
@@ -803,8 +837,8 @@ smart whitespace trimming is enabled by default.
 
 Render this node and its content to HTML/XML.
 
-  # "<b>test</b>"
-  $dom->parse('<div><b>test</b></div>')->div->b->to_string;
+  # "<b>Test</b>"
+  $dom->parse('<div><b>Test</b></div>')->div->b->to_string;
 
 =head2 tree
 
@@ -824,6 +858,24 @@ This element's type.
   # List types of child elements
   say $dom->children->type;
 
+=head2 val
+
+  my $collection = $dom->val;
+
+Extract values from C<button>, C<input>, C<option>, C<select> or C<textarea>
+element and return a L<Mojo::Collection> object containing these values. In
+the case of C<select>, find all C<option> elements it contains that have a
+C<selected> attribute and extract their values.
+
+  # "b"
+  $dom->parse('<input name="a" value="b">')->at('input')->val;
+
+  # "c"
+  $dom->parse('<option value="c">Test</option>')->at('option')->val;
+
+  # "d"
+  $dom->parse('<option>d</option>')->at('option')->val;
+
 =head2 wrap
 
   $dom = $dom->wrap('<div></div>');
@@ -831,17 +883,17 @@ This element's type.
 Wrap HTML/XML fragment around this node, placing it as the last child of the
 first innermost element.
 
-  # "<p>B<b>A</b></p>"
-  $dom->parse('<b>A</b>')->at('b')->wrap('<p>B</p>')->root;
+  # "<p>123<b>Test</b></p>"
+  $dom->parse('<b>Test</b>')->at('b')->wrap('<p>123</p>')->root;
 
-  # "<div><p><b>A</b></p>B</div>"
-  $dom->parse('<b>A</b>')->at('b')->wrap('<div><p></p>B</div>')->root;
+  # "<div><p><b>Test</b></p>123</div>"
+  $dom->parse('<b>Test</b>')->at('b')->wrap('<div><p></p>123</div>')->root;
 
-  # "<p><b>A</b></p><p>B</p>"
-  $dom->parse('<b>A</b>')->at('b')->wrap('<p></p><p>B</p>')->root;
+  # "<p><b>Test</b></p><p>123</p>"
+  $dom->parse('<b>Test</b>')->at('b')->wrap('<p></p><p>123</p>')->root;
 
-  # "<p><b>A</b></p>"
-  $dom->parse('<p>A</p>')->at('p')->contents->first->wrap('<b>')->root;
+  # "<p><b>Test</b></p>"
+  $dom->parse('<p>Test</p>')->at('p')->contents->first->wrap('<b>')->root;
 
 =head2 wrap_content
 
@@ -850,11 +902,11 @@ first innermost element.
 Wrap HTML/XML fragment around this node's content, placing it as the last
 children of the first innermost element.
 
-  # "<p><b>BA</b></p>"
-  $dom->parse('<p>A<p>')->at('p')->wrap_content('<b>B</b>')->root;
+  # "<p><b>123Test</b></p>"
+  $dom->parse('<p>Test<p>')->at('p')->wrap_content('<b>123</b>')->root;
 
-  # "<p><b>A</b></p><p>B</p>"
-  $dom->parse('<b>A</b>')->wrap_content('<p></p><p>B</p>');
+  # "<p><b>Test</b></p><p>123</p>"
+  $dom->parse('<b>Test</b>')->wrap_content('<p></p><p>123</p>');
 
 =head2 xml
 
@@ -871,9 +923,14 @@ automatically available as object methods, which return a L<Mojo::DOM> or
 L<Mojo::Collection> object, depending on number of children. For more power
 and consistent results you can also use L</"children">.
 
-  say $dom->p->text;
-  say $dom->div->[23]->text;
-  say $dom->div->text;
+  # "Test"
+  $dom->parse('<p>Test</p>')->p->text;
+
+  # "123"
+  $dom->parse('<div>Test</div><div>123</div>')->div->[2]->text;
+
+  # "Test"
+  $dom->parse('<div>Test</div>')->div->text;
 
 =head1 OPERATORS
 
@@ -885,8 +942,8 @@ L<Mojo::DOM> overloads the following operators.
 
 Alias for L</"contents">.
 
-  # "<!-- test -->"
-  $dom->parse('<!-- test --><b>123</b>')->[0];
+  # "<!-- Test -->"
+  $dom->parse('<!-- Test --><b>123</b>')->[0];
 
 =head2 bool
 
@@ -901,7 +958,7 @@ Always true.
 Alias for L</"attr">.
 
   # "test"
-  $dom->parse('<div id="test">A</div>')->at('div')->{id};
+  $dom->parse('<div id="test">Test</div>')->at('div')->{id};
 
 =head2 stringify
 
@@ -2,9 +2,14 @@ package Mojo::Date;
 use Mojo::Base -base;
 use overload bool => sub {1}, '""' => sub { shift->to_string }, fallback => 1;
 
-use Time::Local 'timegm';
+use Time::Local 1.2 'timegm';
 
-has 'epoch';
+has epoch => sub {time};
+
+my $RFC3339_RE = qr/
+  ^(\d+)-(\d+)-(\d+)T(\d+):(\d+):(\d+(?:\.\d+)?)   # Date and time
+  (?:Z|([+-])(\d+):(\d+))?$                        # Offset
+/xi;
 
 my @DAYS   = qw(Sun Mon Tue Wed Thu Fri Sat);
 my @MONTHS = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
@@ -17,14 +22,21 @@ sub parse {
   my ($self, $date) = @_;
 
   # epoch (784111777)
-  return $self->epoch($date) if $date =~ /^\d+$/;
+  return $self->epoch($date) if $date =~ /^\d+$|^\d+\.\d+$/;
 
   # RFC 822/1123 (Sun, 06 Nov 1994 08:49:37 GMT)
+  my $offset = 0;
   my ($day, $month, $year, $h, $m, $s);
   if ($date =~ /^\w+\,\s+(\d+)\s+(\w+)\s+(\d+)\s+(\d+):(\d+):(\d+)\s+GMT$/) {
     ($day, $month, $year, $h, $m, $s) = ($1, $MONTHS{$2}, $3, $4, $5, $6);
   }
 
+  # RFC 3339 (1994-11-06T08:49:37Z)
+  elsif ($date =~ $RFC3339_RE) {
+    ($year, $month, $day, $h, $m, $s) = ($1, $2 - 1, $3, $4, $5, $6);
+    $offset = (($8 * 3600) + ($9 * 60)) * ($7 eq '+' ? -1 : 1) if $7;
+  }
+
   # RFC 850/1036 (Sunday, 06-Nov-94 08:49:37 GMT)
   elsif ($date =~ /^\w+\,\s+(\d+)-(\w+)-(\d+)\s+(\d+):(\d+):(\d+)\s+GMT$/) {
     ($day, $month, $year, $h, $m, $s) = ($1, $MONTHS{$2}, $3, $4, $5, $6);
@@ -36,18 +48,27 @@ sub parse {
   }
 
   # Invalid
-  else { return $self }
+  else { return $self->epoch(undef) }
 
   # Prevent crash
-  my $epoch = eval { timegm($s, $m, $h, $day, $month, $year) };
-  return defined $epoch && $epoch >= 0 ? $self->epoch($epoch) : $self;
+  my $epoch = eval { timegm $s, $m, $h, $day, $month, $year };
+  return $self->epoch(
+    (defined $epoch && ($epoch += $offset) >= 0) ? $epoch : undef);
+}
+
+sub to_datetime {
+
+  # RFC 3339 (1994-11-06T08:49:37Z)
+  my ($s, $m, $h, $day, $month, $year) = gmtime(my $epoch = shift->epoch);
+  my $str = sprintf '%04d-%02d-%02dT%02d:%02d:%02d', $year + 1900, $month + 1,
+    $day, $h, $m, $s;
+  return $str . ($epoch =~ /(\.\d+)$/ ? "$1Z" : 'Z');
 }
 
 sub to_string {
-  my $self = shift;
 
   # RFC 7231 (Sun, 06 Nov 1994 08:49:37 GMT)
-  my ($s, $m, $h, $mday, $month, $year, $wday) = gmtime($self->epoch // time);
+  my ($s, $m, $h, $mday, $month, $year, $wday) = gmtime shift->epoch;
   return sprintf '%s, %02d %s %04d %02d:%02d:%02d GMT', $DAYS[$wday], $mday,
     $MONTHS[$month], $year + 1900, $h, $m, $s;
 }
@@ -69,18 +90,15 @@ Mojo::Date - HTTP date
   say $date->epoch;
 
   # Build
-  my $date = Mojo::Date->new(time);
+  my $date = Mojo::Date->new(time + 60);
   say "$date";
 
 =head1 DESCRIPTION
 
 L<Mojo::Date> implements HTTP date and time functions based on
-L<RFC 7230|http://tools.ietf.org/html/rfc7230> and
-L<RFC 7231|http://tools.ietf.org/html/rfc7231>.
-
-  Sun, 06 Nov 1994 08:49:37 GMT  ; RFC 822, updated by RFC 1123
-  Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036
-  Sun Nov  6 08:49:37 1994       ; ANSI C's asctime() format
+L<RFC 7230|http://tools.ietf.org/html/rfc7230>,
+L<RFC 7231|http://tools.ietf.org/html/rfc7231> and
+L<RFC 3339|http://tools.ietf.org/html/rfc3339>.
 
 =head1 ATTRIBUTES
 
@@ -91,7 +109,7 @@ L<Mojo::Date> implements the following attributes.
   my $epoch = $date->epoch;
   $date     = $date->epoch(784111777);
 
-Epoch seconds.
+Epoch seconds, defaults to the current time.
 
 =head1 METHODS
 
@@ -113,6 +131,7 @@ Parse date.
 
   # Epoch
   say Mojo::Date->new('784111777')->epoch;
+  say Mojo::Date->new('784111777.21')->epoch;
 
   # RFC 822/1123
   say Mojo::Date->new('Sun, 06 Nov 1994 08:49:37 GMT')->epoch;
@@ -123,12 +142,34 @@ Parse date.
   # Ansi C asctime()
   say Mojo::Date->new('Sun Nov  6 08:49:37 1994')->epoch;
 
+  # RFC 3339
+  say Mojo::Date->new('1994-11-06T08:49:37Z')->epoch;
+  say Mojo::Date->new('1994-11-06T08:49:37')->epoch;
+  say Mojo::Date->new('1994-11-06T08:49:37.21Z')->epoch;
+  say Mojo::Date->new('1994-11-06T08:49:37+01:00')->epoch;
+  say Mojo::Date->new('1994-11-06T08:49:37-01:00')->epoch;
+
+=head2 to_datetime
+
+  my $str = $date->to_datetime;
+
+Render L<RFC 3339|http://tools.ietf.org/html/rfc3339> date and time.
+
+  # "1994-11-06T08:49:37Z"
+  Mojo::Date->new(784111777)->to_datetime;
+
+  # "1994-11-06T08:49:37.21Z"
+  Mojo::Date->new(784111777.21)->to_datetime;
+
 =head2 to_string
 
   my $str = $date->to_string;
 
 Render date suitable for HTTP messages.
 
+  # "Sun, 06 Nov 1994 08:49:37 GMT"
+  Mojo::Date->new(784111777)->to_string;
+
 =head1 OPERATORS
 
 L<Mojo::Date> overloads the following operators.
@@ -1,6 +1,7 @@
 package Mojo::EventEmitter;
 use Mojo::Base -base;
 
+use Mojo::Util 'deprecated';
 use Scalar::Util qw(blessed weaken);
 
 use constant DEBUG => $ENV{MOJO_EVENTEMITTER_DEBUG} || 0;
@@ -22,21 +23,18 @@ sub emit {
   return $self;
 }
 
+# DEPRECATED in Tiger Face!
 sub emit_safe {
+  deprecated 'Mojo::EventEmitter::emit_safe is DEPRECATED';
   my ($self, $name) = (shift, shift);
 
   if (my $s = $self->{events}{$name}) {
-    warn "-- Emit $name in @{[blessed $self]} safely (@{[scalar @$s]})\n"
-      if DEBUG;
     for my $cb (@$s) {
       $self->emit(error => qq{Event "$name" failed: $@})
         unless eval { $self->$cb(@_); 1 };
     }
   }
-  else {
-    warn "-- Emit $name in @{[blessed $self]} safely (0)\n" if DEBUG;
-    die "@{[blessed $self]}: $_[0]" if $name eq 'error';
-  }
+  else { die "@{[blessed $self]}: $_[0]" if $name eq 'error' }
 
   return $self;
 }
@@ -125,7 +123,8 @@ L<Mojo::EventEmitter> can emit the following events.
     ...
   });
 
-Emitted for event errors, fatal if unhandled.
+This is a special event for errors, it will not be emitted directly by this
+class but is fatal if unhandled.
 
   $e->on(error => sub {
     my ($e, $err) = @_;
@@ -153,13 +152,6 @@ Subscribe to L</"error"> event.
 
 Emit event.
 
-=head2 emit_safe
-
-  $e = $e->emit_safe('foo');
-  $e = $e->emit_safe('foo', 123);
-
-Emit event safely and emit L</"error"> event on failure.
-
 =head2 has_subscribers
 
   my $bool = $e->has_subscribers('foo');
@@ -10,11 +10,12 @@ my %NORMALCASE = map { lc($_) => $_ } (
   qw(Accept Accept-Charset Accept-Encoding Accept-Language Accept-Ranges),
   qw(Allow Authorization Cache-Control Connection Content-Disposition),
   qw(Content-Encoding Content-Length Content-Range Content-Type Cookie DNT),
-  qw(Date ETag Expect Expires Host If-Modified-Since Last-Modified Link),
-  qw(Location Origin Proxy-Authenticate Proxy-Authorization Range),
-  qw(Sec-WebSocket-Accept Sec-WebSocket-Extensions Sec-WebSocket-Key),
-  qw(Sec-WebSocket-Protocol Sec-WebSocket-Version Server Set-Cookie Status),
-  qw(TE Trailer Transfer-Encoding Upgrade User-Agent Vary WWW-Authenticate)
+  qw(Date ETag Expect Expires Host If-Modified-Since If-None-Match),
+  qw(Last-Modified Link Location Origin Proxy-Authenticate),
+  qw(Proxy-Authorization Range Sec-WebSocket-Accept Sec-WebSocket-Extensions),
+  qw(Sec-WebSocket-Key Sec-WebSocket-Protocol Sec-WebSocket-Version Server),
+  qw(Set-Cookie Status TE Trailer Transfer-Encoding Upgrade User-Agent Vary),
+  qw(WWW-Authenticate)
 );
 for my $header (values %NORMALCASE) {
   my $name = lc $header;
@@ -341,7 +342,7 @@ but is very commonly used.
 =head2 etag
 
   my $etag = $headers->etag;
-  $headers = $headers->etag('abc321');
+  $headers = $headers->etag('"abc321"');
 
 Shortcut for the C<ETag> header.
 
@@ -389,6 +390,13 @@ Shortcut for the C<Host> header.
 
 Shortcut for the C<If-Modified-Since> header.
 
+=head2 if_none_match
+
+  my $etag = $headers->if_none_match;
+  $headers = $headers->if_none_match('"abc321"');
+
+Shortcut for the C<If-None-Match> header.
+
 =head2 is_finished
 
   my $bool = $headers->is_finished;
@@ -19,6 +19,13 @@ use constant TLS => $ENV{MOJO_NO_TLS}
 use constant TLS_READ  => TLS ? IO::Socket::SSL::SSL_WANT_READ()  : 0;
 use constant TLS_WRITE => TLS ? IO::Socket::SSL::SSL_WANT_WRITE() : 0;
 
+# SOCKS support requires IO::Socket::Socks
+use constant SOCKS => $ENV{MOJO_NO_SOCKS}
+  ? 0
+  : eval 'use IO::Socket::Socks 0.64 (); 1';
+use constant SOCKS_READ  => SOCKS ? IO::Socket::Socks::SOCKS_WANT_READ()  : 0;
+use constant SOCKS_WRITE => SOCKS ? IO::Socket::Socks::SOCKS_WANT_WRITE() : 0;
+
 has reactor => sub { Mojo::IOLoop->singleton->reactor };
 
 sub DESTROY { shift->_cleanup }
@@ -42,28 +49,59 @@ sub _connect {
 
   my $handle;
   my $reactor = $self->reactor;
-  my $address = $args->{address} ||= 'localhost';
+  my $address = $args->{socks_address} || ($args->{address} ||= 'localhost');
+  my $port = $args->{socks_port} || $args->{port} || ($args->{tls} ? 443 : 80);
   unless ($handle = $self->{handle} = $args->{handle}) {
     my %options = (
       Blocking => 0,
       PeerAddr => $address eq 'localhost' ? '127.0.0.1' : $address,
-      PeerPort => $args->{port} || ($args->{tls} ? 443 : 80)
+      PeerPort => $port
     );
     $options{LocalAddr} = $args->{local_address} if $args->{local_address};
     $options{PeerAddr} =~ s/[\[\]]//g if $options{PeerAddr};
     my $class = IPV6 ? 'IO::Socket::IP' : 'IO::Socket::INET';
-    return $self->emit(error => "Couldn't connect: $@")
+    return $self->emit(error => "Can't connect: $@")
       unless $self->{handle} = $handle = $class->new(%options);
-
-    # Timeout
-    $self->{timer} = $reactor->timer($args->{timeout} || 10,
-      sub { $self->emit(error => 'Connect timeout') });
   }
   $handle->blocking(0);
 
+  # Timeout
+  $self->{timer} = $reactor->timer($args->{timeout} || 10,
+    sub { $self->emit(error => 'Connect timeout') });
+
   # Wait for handle to become writable
   weaken $self;
-  $reactor->io($handle => sub { $self->_try($args) })->watch($handle, 0, 1);
+  $reactor->io($handle => sub { $self->_ready($args) })->watch($handle, 0, 1);
+}
+
+sub _ready {
+  my ($self, $args) = @_;
+
+  # Retry or handle exceptions
+  my $handle = $self->{handle};
+  return $! == EINPROGRESS ? undef : $self->emit(error => $!)
+    if $handle->isa('IO::Socket::IP') && !$handle->connect;
+  return $self->emit(error => $! = $handle->sockopt(SO_ERROR))
+    unless $handle->connected;
+
+  # Disable Nagle's algorithm
+  setsockopt $handle, IPPROTO_TCP, TCP_NODELAY, 1;
+
+  $self->_try_socks($args);
+}
+
+sub _socks {
+  my ($self, $args) = @_;
+
+  # Connected
+  my $handle = $self->{handle};
+  return $self->_try_tls($args) if $handle->ready;
+
+  # Switch between reading and writing
+  my $err = $IO::Socket::Socks::SOCKS_ERROR;
+  if    ($err == SOCKS_READ)  { $self->reactor->watch($handle, 1, 0) }
+  elsif ($err == SOCKS_WRITE) { $self->reactor->watch($handle, 1, 1) }
+  else                        { $self->emit(error => $err) }
 }
 
 sub _tls {
@@ -71,8 +109,7 @@ sub _tls {
 
   # Connected
   my $handle = $self->{handle};
-  return $self->_cleanup->emit_safe(connect => $handle)
-    if $handle->connect_SSL;
+  return $self->_cleanup->emit(connect => $handle) if $handle->connect_SSL;
 
   # Switch between reading and writing
   my $err = $IO::Socket::SSL::SSL_ERROR;
@@ -80,20 +117,33 @@ sub _tls {
   elsif ($err == TLS_WRITE) { $self->reactor->watch($handle, 1, 1) }
 }
 
-sub _try {
+sub _try_socks {
   my ($self, $args) = @_;
 
-  # Retry or handle exceptions
   my $handle = $self->{handle};
-  return $! == EINPROGRESS ? undef : $self->emit(error => $!)
-    if $handle->isa('IO::Socket::IP') && !$handle->connect;
-  return $self->emit(error => $! = $handle->sockopt(SO_ERROR))
-    unless $handle->connected;
+  return $self->_try_tls($args) unless $args->{socks_address};
+  return $self->emit(
+    error => 'IO::Socket::Socks 0.64 required for SOCKS support')
+    unless SOCKS;
+
+  my %options
+    = (ConnectAddr => $args->{address}, ConnectPort => $args->{port});
+  @options{qw(AuthType Username Password)}
+    = ('userpass', @$args{qw(socks_user socks_pass)})
+    if $args->{socks_user};
+  my $reactor = $self->reactor;
+  $reactor->remove($handle);
+  return $self->emit(error => 'SOCKS upgrade failed')
+    unless IO::Socket::Socks->start_SOCKS($handle, %options);
+  weaken $self;
+  $reactor->io($handle => sub { $self->_socks($args) })->watch($handle, 0, 1);
+}
 
-  # Disable Nagle's algorithm
-  setsockopt $handle, IPPROTO_TCP, TCP_NODELAY, 1;
+sub _try_tls {
+  my ($self, $args) = @_;
 
-  return $self->_cleanup->emit_safe(connect => $handle)
+  my $handle = $self->{handle};
+  return $self->_cleanup->emit(connect => $handle)
     if !$args->{tls} || $handle->isa('IO::Socket::SSL');
   return $self->emit(error => 'IO::Socket::SSL 1.84 required for TLS support')
     unless TLS;
@@ -104,7 +154,7 @@ sub _try {
     SSL_ca_file => $args->{tls_ca}
       && -T $args->{tls_ca} ? $args->{tls_ca} : undef,
     SSL_cert_file  => $args->{tls_cert},
-    SSL_error_trap => sub { $self->_cleanup->emit(error => $_[1]) },
+    SSL_error_trap => sub { $self->emit(error => $_[1]) },
     SSL_hostname   => IO::Socket::SSL->can_client_sni ? $args->{address} : '',
     SSL_key_file   => $args->{tls_key},
     SSL_startHandshake  => 0,
@@ -115,7 +165,7 @@ sub _try {
   my $reactor = $self->reactor;
   $reactor->remove($handle);
   return $self->emit(error => 'TLS upgrade failed')
-    unless $handle = IO::Socket::SSL->start_SSL($handle, %options);
+    unless IO::Socket::SSL->start_SSL($handle, %options);
   $reactor->io($handle => sub { $self->_tls })->watch($handle, 0, 1);
 }
 
@@ -162,7 +212,7 @@ emit the following new ones.
     ...
   });
 
-Emitted safely once the connection is established.
+Emitted once the connection is established.
 
 =head2 error
 
@@ -225,6 +275,30 @@ Local address to bind to.
 
 Port to connect to, defaults to C<80> or C<443> with C<tls> option.
 
+=item socks_address
+
+  socks_address => '127.0.0.1'
+
+Address or host name of SOCKS5 proxy server to use for connection.
+
+=item socks_pass
+
+  socks_pass => 'secr3t'
+
+Password to use for SOCKS5 authentication.
+
+=item socks_port
+
+  socks_port => 9050
+
+Port of SOCKS5 proxy server to use for connection.
+
+=item socks_user
+
+  socks_user => 'sri'
+
+Username to use for SOCKS5 authentication.
+
 =item timeout
 
   timeout => 15
@@ -1,8 +1,8 @@
 package Mojo::IOLoop::Delay;
 use Mojo::Base 'Mojo::EventEmitter';
 
-use Mojo;
 use Mojo::IOLoop;
+use Mojo::Util;
 use Hash::Util::FieldHash 'fieldhash';
 
 has ioloop => sub { Mojo::IOLoop->singleton };
@@ -16,7 +16,7 @@ sub begin {
   return sub { $self->_step($id, $offset // 1, $len, @_) };
 }
 
-sub data { shift->Mojo::_dict(data => @_) }
+sub data { Mojo::Util::_stash(data => @_) }
 
 sub pass { $_[0]->begin->(@_) }
 
@@ -145,8 +145,8 @@ emit the following new ones.
     ...
   });
 
-Emitted if an error occurs in one of the steps, breaking the chain, fatal if
-unhandled.
+Emitted if an exception gets thrown in one of the steps, breaking the chain,
+fatal if unhandled.
 
 =head2 finish
 
@@ -250,7 +250,8 @@ Sequentialize multiple events, every time the active event counter reaches
 zero a callback will run, the first one automatically runs during the next
 reactor tick unless it is delayed by incrementing the active event counter.
 This chain will continue until there are no more callbacks, a callback does
-not increment the active event counter or an error occurs in a callback.
+not increment the active event counter or an exception gets thrown in a
+callback.
 
 =head2 wait
 
@@ -125,7 +125,7 @@ sub _accept {
     setsockopt $handle, IPPROTO_TCP, TCP_NODELAY, 1;
 
     # Start TLS handshake
-    $self->emit_safe(accept => $handle) and next unless my $tls = $self->{tls};
+    $self->emit(accept => $handle) and next unless my $tls = $self->{tls};
     $self->_handshake($self->{handles}{$handle} = $handle)
       if $handle = IO::Socket::SSL->start_SSL($handle, %$tls, SSL_server => 1);
   }
@@ -143,7 +143,7 @@ sub _tls {
   # Accepted
   if ($handle->accept_SSL) {
     $self->reactor->remove($handle);
-    return $self->emit_safe(accept => delete $self->{handles}{$handle});
+    return $self->emit(accept => delete $self->{handles}{$handle});
   }
 
   # Switch between reading and writing
@@ -195,7 +195,7 @@ emit the following new ones.
     ...
   });
 
-Emitted safely for each accepted connection.
+Emitted for each accepted connection.
 
 =head1 ATTRIBUTES
 
@@ -16,7 +16,7 @@ sub close {
   return unless my $handle  = delete $self->timeout(0)->{handle};
   $reactor->remove($handle);
   close $handle;
-  $self->emit_safe('close');
+  $self->emit('close');
 }
 
 sub close_gracefully {
@@ -76,7 +76,7 @@ sub timeout {
   return $self unless my $timeout = $self->{timeout} = shift;
   weaken $self;
   $self->{timer}
-    = $reactor->timer($timeout => sub { $self->emit_safe('timeout')->close });
+    = $reactor->timer($timeout => sub { $self->emit('timeout')->close });
 
   return $self;
 }
@@ -113,7 +113,7 @@ sub _read {
   my $read = $self->{handle}->sysread(my $buffer, 131072, 0);
   return $self->_error unless defined $read;
   return $self->close if $read == 0;
-  $self->emit_safe(read => $buffer)->_again;
+  $self->emit(read => $buffer)->_again;
 }
 
 sub _write {
@@ -123,13 +123,12 @@ sub _write {
   if (length $self->{buffer}) {
     my $written = $handle->syswrite($self->{buffer});
     return $self->_error unless defined $written;
-    $self->emit_safe(write => substr($self->{buffer}, 0, $written, ''));
-    $self->_again;
+    $self->emit(write => substr($self->{buffer}, 0, $written, ''))->_again;
   }
 
-  $self->emit_safe('drain') if !length $self->{buffer};
-  return                    if $self->is_writing;
-  return $self->close       if $self->{graceful};
+  $self->emit('drain') if !length $self->{buffer};
+  return               if $self->is_writing;
+  return $self->close  if $self->{graceful};
   $self->reactor->watch($handle, !$self->{paused}, 0) if $self->{handle};
 }
 
@@ -184,7 +183,7 @@ emit the following new ones.
     ...
   });
 
-Emitted safely if the stream gets closed.
+Emitted if the stream gets closed.
 
 =head2 drain
 
@@ -193,7 +192,7 @@ Emitted safely if the stream gets closed.
     ...
   });
 
-Emitted safely once all data has been written.
+Emitted once all data has been written.
 
 =head2 error
 
@@ -211,7 +210,7 @@ Emitted if an error occurs on the stream, fatal if unhandled.
     ...
   });
 
-Emitted safely if new data arrives on the stream.
+Emitted if new data arrives on the stream.
 
 =head2 timeout
 
@@ -220,8 +219,8 @@ Emitted safely if new data arrives on the stream.
     ...
   });
 
-Emitted safely if the stream has been inactive for too long and will get
-closed automatically.
+Emitted if the stream has been inactive for too long and will get closed
+automatically.
 
 =head2 write
 
@@ -230,7 +229,7 @@ closed automatically.
     ...
   });
 
-Emitted safely if new data has been written to the stream.
+Emitted if new data has been written to the stream.
 
 =head1 ATTRIBUTES
 
@@ -320,11 +320,12 @@ right in, to make writing test servers as easy as possible. Also note that for
 convenience the C<PIPE> signal will be set to C<IGNORE> when L<Mojo::IOLoop>
 is loaded.
 
-For better scalability (epoll, kqueue) and to provide IPv6 as well as TLS
-support, the optional modules L<EV> (4.0+), L<IO::Socket::IP> (0.20+) and
-L<IO::Socket::SSL> (1.84+) will be used automatically if they are installed.
-Individual features can also be disabled with the C<MOJO_NO_IPV6> and
-C<MOJO_NO_TLS> environment variables.
+For better scalability (epoll, kqueue) and to provide IPv6, SOCKS5 as well as
+TLS support, the optional modules L<EV> (4.0+), L<IO::Socket::IP> (0.20+),
+L<IO::Socket::Socks> (0.64+) and L<IO::Socket::SSL> (1.84+) will be used
+automatically if they are installed. Individual features can also be disabled
+with the C<MOJO_NO_IPV6>, C<MOJO_NO_SOCKS> and C<MOJO_NO_TLS> environment
+variables.
 
 See L<Mojolicious::Guides::Cookbook/"REAL-TIME WEB"> for more.
 
@@ -1,8 +1,6 @@
 package Mojo::JSON::Pointer;
 use Mojo::Base -base;
 
-use Scalar::Util 'looks_like_number';
-
 has 'data';
 
 sub contains { shift->_pointer(1, @_) }
@@ -23,7 +21,7 @@ sub _pointer {
     if (ref $data eq 'HASH' && exists $data->{$p}) { $data = $data->{$p} }
 
     # Array
-    elsif (ref $data eq 'ARRAY' && looks_like_number($p) && @$data > $p) {
+    elsif (ref $data eq 'ARRAY' && $p =~ /^\d+$/ && @$data > $p) {
       $data = $data->[$p];
     }
 
@@ -218,8 +218,7 @@ sub _decode_value {
 }
 
 sub _encode_array {
-  my $array = shift;
-  return '[' . join(',', map { _encode_value($_) } @$array) . ']';
+  '[' . join(',', map { _encode_value($_) } @{$_[0]}) . ']';
 }
 
 sub _encode_object {
@@ -231,7 +230,7 @@ sub _encode_object {
 
 sub _encode_string {
   my $str = shift;
-  $str =~ s!([\x00-\x1f\x{2028}\x{2029}\\"/])!$REVERSE{$1}!gs;
+  $str =~ s!([\x00-\x1f\x{2028}\x{2029}\\"])!$REVERSE{$1}!gs;
   return "\"$str\"";
 }
 
@@ -321,7 +320,7 @@ It supports normal Perl data types like scalar, array reference, hash
 reference and will try to call the C<TO_JSON> method on blessed references, or
 stringify them if it doesn't exist. Differentiating between strings and
 numbers in Perl is hard, depending on how it has been used, a scalar can be
-both at the same time. The string value gets precedence unless both
+both at the same time. The string value has a higher precedence unless both
 representations are equivalent.
 
   [1, -2, 3]     -> [1, -2, 3]
@@ -55,7 +55,7 @@ sub _all {
   seek $handle, 0, 0;
   my $data = join '', <$handle>;
 
-  # Ignore everything before __DATA__ (Windows will seek to start of file)
+  # Ignore everything before __DATA__ (some versions seek to start of file)
   $data =~ s/^.*\n__DATA__\r?\n/\n/s;
 
   # Ignore everything after __END__
@@ -8,15 +8,12 @@ use Mojo::Util 'encode';
 has format => sub { \&_format };
 has handle => sub {
 
-  # File
-  if (my $path = shift->path) {
-    croak qq{Can't open log file "$path": $!}
-      unless open my $file, '>>', $path;
-    return $file;
-  }
-
   # STDERR
-  return \*STDERR;
+  return \*STDERR unless my $path = shift->path;
+
+  # File
+  croak qq{Can't open log file "$path": $!} unless open my $file, '>>', $path;
+  return $file;
 };
 has history => sub { [] };
 has level => 'debug';
@@ -11,11 +11,9 @@ has url => sub { Mojo::URL->new };
 has 'reverse_proxy';
 
 my $START_LINE_RE = qr/
-  ^
-  ([a-zA-Z]+)                                               # Method
+  ^([a-zA-Z]+)                                              # Method
   \s+([0-9a-zA-Z!#\$\%&'()*+,\-.\/:;=?\@[\\\]^_`\{|\}~]+)   # URL
-  \s+HTTP\/(\d\.\d)                                         # Version
-  $
+  \s+HTTP\/(\d\.\d)$                                        # Version
 /x;
 
 sub clone {
@@ -60,8 +58,7 @@ sub extract_start_line {
   return undef unless $$bufref =~ s/^\s*(.*?)\x0d?\x0a//;
 
   # We have a (hopefully) full request line
-  $self->error({message => 'Bad request start line', advice => 400})
-    and return undef
+  return !$self->error({message => 'Bad request start line', advice => 400})
     unless $1 =~ $START_LINE_RE;
   my $url = $self->method($1)->version($3)->url;
   return !!($1 eq 'CONNECT' ? $url->authority($2) : $url->parse($2));
@@ -107,9 +104,8 @@ sub get_start_line_chunk {
     }
 
     # Proxy
-    elsif ($self->proxy) {
-      $path = $url->clone->userinfo(undef)
-        unless $self->is_handshake || $url->protocol eq 'https';
+    elsif ($self->proxy && $url->protocol ne 'https') {
+      $path = $url->clone->userinfo(undef) unless $self->is_handshake;
     }
 
     $self->{start_buffer} = "$method $path HTTP/@{[$self->version]}\x0d\x0a";
@@ -225,10 +221,8 @@ sub _parse_env {
   $self->method($env->{REQUEST_METHOD}) if $env->{REQUEST_METHOD};
 
   # Scheme/Version
-  if (($env->{SERVER_PROTOCOL} // '') =~ m!^([^/]+)/([^/]+)$!) {
-    $base->scheme($1);
-    $self->version($2);
-  }
+  $base->scheme($1) and $self->version($2)
+    if ($env->{SERVER_PROTOCOL} // '') =~ m!^([^/]+)/([^/]+)$!;
 
   # HTTPS
   $base->scheme('https') if uc($env->{HTTPS} // '') eq 'ON';
@@ -400,21 +394,24 @@ Check C<X-Requested-With> header for C<XMLHttpRequest> value.
   my @foo         = $req->param('foo');
   my ($foo, $bar) = $req->param(['foo', 'bar']);
 
-Access C<GET> and C<POST> parameters. Note that this method caches all data,
-so it should not be called before the entire request body has been received.
-Parts of the request body need to be loaded into memory to parse C<POST>
-parameters, so you have to make sure it is not excessively large, there's a
-10MB limit by default.
+Access C<GET> and C<POST> parameters extracted from the query string and
+C<application/x-www-form-urlencoded> or C<multipart/form-data> message body.
+Note that this method caches all data, so it should not be called before the
+entire request body has been received. Parts of the request body need to be
+loaded into memory to parse C<POST> parameters, so you have to make sure it is
+not excessively large, there's a 10MB limit by default.
 
 =head2 params
 
   my $params = $req->params;
 
-All C<GET> and C<POST> parameters, usually a L<Mojo::Parameters> object. Note
-that this method caches all data, so it should not be called before the entire
-request body has been received. Parts of the request body need to be loaded
-into memory to parse C<POST> parameters, so you have to make sure it is not
-excessively large, there's a 10MB limit by default.
+All C<GET> and C<POST> parameters extracted from the query string and
+C<application/x-www-form-urlencoded> or C<multipart/form-data> message body,
+usually a L<Mojo::Parameters> object. Note that this method caches all data,
+so it should not be called before the entire request body has been received.
+Parts of the request body need to be loaded into memory to parse C<POST>
+parameters, so you have to make sure it is not excessively large, there's a
+10MB limit by default.
 
   # Get parameter value
   say $req->params->param('foo');
@@ -56,7 +56,6 @@ my %MESSAGES = (
   428 => 'Precondition Required',              # RFC 6585
   429 => 'Too Many Requests',                  # RFC 6585
   431 => 'Request Header Fields Too Large',    # RFC 6585
-  451 => 'Unavailable For Legal Reasons',      # Draft
   500 => 'Internal Server Error',
   501 => 'Not Implemented',
   502 => 'Bad Gateway',
@@ -95,7 +94,7 @@ sub extract_start_line {
 
   # We have a full response line
   return undef unless $$bufref =~ s/^(.*?)\x0d?\x0a//;
-  $self->error({message => 'Bad response start line'}) and return undef
+  return !$self->error({message => 'Bad response start line'})
     unless $1 =~ m!^\s*HTTP/(\d\.\d)\s+(\d\d\d)\s*(.+)?$!;
 
   my $content = $self->content;
@@ -9,7 +9,7 @@ use Mojo::JSON 'j';
 use Mojo::JSON::Pointer;
 use Mojo::Parameters;
 use Mojo::Upload;
-use Mojo::Util 'decode';
+use Mojo::Util qw(decode split_header);
 
 has content => sub { Mojo::Content::Single->new };
 has default_charset  => 'UTF-8';
@@ -585,11 +585,12 @@ sure it is not excessively large, there's a 10MB limit by default.
   my @foo         = $msg->param('foo');
   my ($foo, $bar) = $msg->param(['foo', 'bar']);
 
-Access C<POST> parameters. Note that this method caches all data, so it should
-not be called before the entire message body has been received. Parts of the
-message body need to be loaded into memory to parse C<POST> parameters, so you
-have to make sure it is not excessively large, there's a 10MB limit by
-default.
+Access C<POST> parameters extracted from C<application/x-www-form-urlencoded>
+or C<multipart/form-data> message body. Note that this method caches all data,
+so it should not be called before the entire message body has been received.
+Parts of the message body need to be loaded into memory to parse C<POST>
+parameters, so you have to make sure it is not excessively large, there's a
+10MB limit by default.
 
 =head2 parse
 
@@ -11,18 +11,16 @@ use Mojo::Util qw(decode encode url_escape url_unescape);
 has charset => 'UTF-8';
 
 sub append {
-  my ($self, @pairs) = @_;
+  my $self = shift;
 
   my $params = $self->params;
-  for (my $i = 0; $i < @pairs; $i += 2) {
-    my $key   = $pairs[$i]     // '';
-    my $value = $pairs[$i + 1] // '';
+  while (my ($name, $value) = splice @_, 0, 2) {
 
     # Single value
-    if (ref $value ne 'ARRAY') { push @$params, $key => $value }
+    if (ref $value ne 'ARRAY') { push @$params, $name => $value }
 
     # Multiple values
-    else { push @$params, $key => (defined $_ ? "$_" : '') for @$value }
+    else { push @$params, $name => (defined $_ ? "$_" : '') for @$value }
   }
 
   return $self;
@@ -31,9 +29,10 @@ sub append {
 sub clone {
   my $self = shift;
 
-  my $clone = $self->new->charset($self->charset);
-  if (defined $self->{string}) { $clone->{string} = $self->{string} }
-  else                         { $clone->params([@{$self->params}]) }
+  my $clone = $self->new;
+  if   (exists $self->{charset}) { $clone->{charset} = $self->{charset} }
+  if   (defined $self->{string}) { $clone->{string}  = $self->{string} }
+  else                           { $clone->{params}  = [@{$self->params}] }
 
   return $clone;
 }
@@ -107,38 +106,35 @@ sub parse {
   my $self = shift;
 
   # Pairs
-  if (@_ > 1) { $self->append(@_) }
+  return $self->append(@_) if @_ > 1;
 
   # String
-  else { $self->{string} = shift }
-
+  $self->{string} = shift;
   return $self;
 }
 
 sub remove {
-  my $self = shift;
-  my $name = shift // '';
+  my ($self, $name) = @_;
 
   my $params = $self->params;
-  for (my $i = 0; $i < @$params;) {
-    if ($params->[$i] eq $name) { splice @$params, $i, 2 }
-    else                        { $i += 2 }
-  }
+  my $i      = 0;
+  $params->[$i] eq $name ? splice @$params, $i, 2 : ($i += 2)
+    while $i < @$params;
 
-  return $self->params($params);
+  return $self;
 }
 
 sub to_hash {
   my $self = shift;
 
-  my $params = $self->params;
   my %hash;
+  my $params = $self->params;
   for (my $i = 0; $i < @$params; $i += 2) {
     my ($name, $value) = @{$params}[$i, $i + 1];
 
     # Array
     if (exists $hash{$name}) {
-      $hash{$name} = [$hash{$name}] unless ref $hash{$name} eq 'ARRAY';
+      $hash{$name} = [$hash{$name}] if ref $hash{$name} ne 'ARRAY';
       push @{$hash{$name}}, $value;
     }
 
@@ -159,7 +155,7 @@ sub to_string {
     return url_escape $str, '^A-Za-z0-9\-._~!$&\'()*+,;=%:@/?';
   }
 
-  # Build pairs;
+  # Build pairs
   my $params = $self->params;
   return '' unless @$params;
   my @pairs;
@@ -204,7 +200,7 @@ Mojo::Parameters - Parameters
 
 L<Mojo::Parameters> is a container for form parameters used by L<Mojo::URL>
 and based on L<RFC 3986|http://tools.ietf.org/html/rfc3986> as well as the
-L<HTML Living Standard|http://www.whatwg.org/html>.
+L<HTML Living Standard|https://html.spec.whatwg.org>.
 
 =head1 ATTRIBUTES
 
@@ -13,26 +13,21 @@ has charset => 'UTF-8';
 sub canonicalize {
   my $self = shift;
 
-  my @parts;
-  for my $part (@{$self->parts}) {
-
-    # ".."
-    if ($part eq '..') {
-      (@parts && $parts[-1] ne '..') ? pop @parts : push @parts, '..';
-    }
-
-    # Something else than "."
-    elsif ($part ne '.' && $part ne '') { push @parts, $part }
+  my $parts = $self->parts;
+  for (my $i = 0; $i <= $#$parts;) {
+    if ($parts->[$i] eq '.' || $parts->[$i] eq '') { splice @$parts, $i, 1 }
+    elsif ($i < 1 || $parts->[$i] ne '..' || $parts->[$i - 1] eq '..') { $i++ }
+    else { splice @$parts, --$i, 2 }
   }
-  $self->trailing_slash(undef) unless @parts;
 
-  return $self->parts(\@parts);
+  return @$parts ? $self : $self->trailing_slash(undef);
 }
 
 sub clone {
   my $self = shift;
 
-  my $clone = $self->new->charset($self->charset);
+  my $clone = $self->new;
+  if (exists $self->{charset}) { $clone->{charset} = $self->{charset} }
   if (my $parts = $self->{parts}) {
     $clone->{$_} = $self->{$_} for qw(leading_slash trailing_slash);
     $clone->{parts} = [@$parts];
@@ -42,10 +37,7 @@ sub clone {
   return $clone;
 }
 
-sub contains {
-  my ($self, $path) = @_;
-  return $path eq '/' || $self->to_route =~ m!^\Q$path\E(?:/|$)!;
-}
+sub contains { $_[1] eq '/' || $_[0]->to_route =~ m!^\Q$_[1]\E(?:/|$)! }
 
 sub leading_slash { shift->_parse(leading_slash => @_) }
 
@@ -86,8 +78,7 @@ sub to_dir {
 
 sub to_route {
   my $clone = shift->clone;
-  my $route = join '/', @{$clone->parts};
-  return "/$route" . ($clone->trailing_slash ? '/' : '');
+  return '/' . join '/', @{$clone->parts}, $clone->trailing_slash ? '' : ();
 }
 
 sub to_string {
@@ -30,15 +30,15 @@ sub timer { shift->_timer(0, @_) }
 sub watch {
   my ($self, $handle, $read, $write) = @_;
 
+  my $mode = 0;
+  $mode |= EV::READ  if $read;
+  $mode |= EV::WRITE if $write;
+
   my $fd = fileno $handle;
   my $io = $self->{io}{$fd};
-  my $mode;
-  if ($read && $write) { $mode = EV::READ | EV::WRITE }
-  elsif ($read)  { $mode = EV::READ }
-  elsif ($write) { $mode = EV::WRITE }
-  else           { delete $io->{watcher} }
-  if (my $w = $io->{watcher}) { $w->set($fd, $mode) }
-  elsif ($mode) {
+  if ($mode == 0) { delete $io->{watcher} }
+  elsif (my $w = $io->{watcher}) { $w->set($fd, $mode) }
+  else {
     weaken $self;
     $io->{watcher} = EV::io($fd, $mode, sub { $self->_io($fd, @_) });
   }
@@ -49,9 +49,9 @@ sub watch {
 sub _io {
   my ($self, $fd, $w, $revents) = @_;
   my $io = $self->{io}{$fd};
-  $self->_sandbox('Read', $io->{cb}, 0) if EV::READ &$revents;
+  $self->_sandbox('Read', $io->{cb}, 0) if EV::READ & $revents;
   $self->_sandbox('Write', $io->{cb}, 1)
-    if EV::WRITE &$revents && $self->{io}{$fd};
+    if EV::WRITE & $revents && $self->{io}{$fd};
 }
 
 sub _timer {
@@ -99,11 +99,13 @@ sub timer { shift->_timer(0, @_) }
 sub watch {
   my ($self, $handle, $read, $write) = @_;
 
+  my $mode = 0;
+  $mode |= POLLIN | POLLPRI if $read;
+  $mode |= POLLOUT if $write;
+
   my $poll = $self->_poll;
   $poll->remove($handle);
-  if ($read && $write) { $poll->mask($handle, POLLIN | POLLPRI | POLLOUT) }
-  elsif ($read)  { $poll->mask($handle, POLLIN | POLLPRI) }
-  elsif ($write) { $poll->mask($handle, POLLOUT) }
+  $poll->mask($handle, $mode) if $mode != 0;
 
   return $self;
 }
@@ -2,7 +2,7 @@ package Mojo::Reactor;
 use Mojo::Base 'Mojo::EventEmitter';
 
 use Carp 'croak';
-use IO::Poll qw(POLLERR POLLHUP POLLIN POLLPRI);
+use IO::Poll qw(POLLIN POLLPRI);
 use Mojo::Loader;
 
 sub again { croak 'Method "again" not implemented by subclass' }
@@ -14,16 +14,9 @@ sub detect {
 
 sub io { croak 'Method "io" not implemented by subclass' }
 
+# This may break at some point in the future, but is worth it for performance
 sub is_readable {
-  my ($self, $handle) = @_;
-
-  my $test = $self->{test} ||= IO::Poll->new;
-  $test->mask($handle, POLLIN | POLLPRI);
-  $test->poll(0);
-  my $result = $test->handles(POLLIN | POLLPRI | POLLERR | POLLHUP);
-  $test->remove($handle);
-
-  return !!$result;
+  !(IO::Poll::_poll(0, fileno(pop), my $dummy = POLLIN | POLLPRI) == 0);
 }
 
 sub is_running { croak 'Method "is_running" not implemented by subclass' }
@@ -26,18 +26,17 @@ sub run {
   # Response start line
   STDOUT->autoflush(1);
   binmode STDOUT;
-  my $res = $tx->res;
+  my $res = $tx->res->fix_headers;
   return undef if $self->nph && !_write($res, 'get_start_line_chunk');
 
   # Response headers
-  $res->fix_headers;
   my $code = $res->code    || 404;
   my $msg  = $res->message || $res->default_message;
   $res->headers->status("$code $msg") unless $self->nph;
   return undef unless _write($res, 'get_header_chunk');
 
   # Response body
-  $tx->is_empty or _write($res, 'get_body_chunk') or return undef;
+  return undef unless $tx->is_empty || _write($res, 'get_body_chunk');
 
   # Finish transaction
   $tx->server_close;
@@ -79,7 +78,7 @@ Mojo::Server::CGI - CGI server
   use Mojo::Server::CGI;
 
   my $cgi = Mojo::Server::CGI->new;
-  $cgi->unsubscribe('request')
+  $cgi->unsubscribe('request');
   $cgi->on(request => sub {
     my ($cgi, $tx) = @_;
 
@@ -160,7 +160,7 @@ sub _listen {
       warn "-- Accept (@{[$stream->handle->peerhost]})\n" if DEBUG;
       $stream->timeout($self->inactivity_timeout);
 
-      $stream->on(close => sub { $self->_close($id) });
+      $stream->on(close => sub { $self && $self->_close($id) });
       $stream->on(error =>
           sub { $self && $self->app->log->error(pop) && $self->_close($id) });
       $stream->on(read => sub { $self->_read($id => pop) });
@@ -261,15 +261,15 @@ Mojo::Server::Daemon - Non-blocking I/O HTTP and WebSocket server
 =head1 DESCRIPTION
 
 L<Mojo::Server::Daemon> is a full featured, highly portable non-blocking I/O
-HTTP and WebSocket server, with IPv6, TLS, Comet (long polling), keep-alive,
-connection pooling, timeout, cookie, multipart and multiple event loop
-support.
-
-For better scalability (epoll, kqueue) and to provide IPv6 as well as TLS
-support, the optional modules L<EV> (4.0+), L<IO::Socket::IP> (0.20+) and
-L<IO::Socket::SSL> (1.84+) will be used automatically by L<Mojo::IOLoop> if
-they are installed. Individual features can also be disabled with the
-C<MOJO_NO_IPV6> and C<MOJO_NO_TLS> environment variables.
+HTTP and WebSocket server, with IPv6, TLS, Comet (long polling), keep-alive
+and multiple event loop support.
+
+For better scalability (epoll, kqueue) and to provide IPv6, SOCKS5 as well as
+TLS support, the optional modules L<EV> (4.0+), L<IO::Socket::IP> (0.20+),
+L<IO::Socket::Socks> (0.64+) and L<IO::Socket::SSL> (1.84+) will be used
+automatically if they are installed. Individual features can also be disabled
+with the C<MOJO_NO_IPV6>, C<MOJO_NO_SOCKS> and C<MOJO_NO_TLS> environment
+variables.
 
 See L<Mojolicious::Guides::Cookbook/"DEPLOYMENT"> for more.
 
@@ -152,10 +152,9 @@ Mojo::Server::Hypnotoad - ALL GLORY TO THE HYPNOTOAD!
 L<Mojo::Server::Hypnotoad> is a full featured, UNIX optimized, preforking
 non-blocking I/O HTTP and WebSocket server, built around the very well tested
 and reliable L<Mojo::Server::Prefork>, with IPv6, TLS, Comet (long polling),
-keep-alive, connection pooling, timeout, cookie, multipart, multiple event
-loop and hot deployment support that just works. Note that the server uses
-signals for process management, so you should avoid modifying signal handlers
-in your applications.
+keep-alive, multiple event loop and hot deployment support that just works.
+Note that the server uses signals for process management, so you should avoid
+modifying signal handlers in your applications.
 
 To start applications with it you can use the L<hypnotoad> script, for
 L<Mojolicious> and L<Mojolicious::Lite> applications it will default to
@@ -172,11 +171,12 @@ You can run the same command again for automatic hot deployment.
 This second invocation will load the application again, detect the process id
 file with it, and send a L</"USR2"> signal to the already running server.
 
-For better scalability (epoll, kqueue) and to provide IPv6 as well as TLS
-support, the optional modules L<EV> (4.0+), L<IO::Socket::IP> (0.20+) and
-L<IO::Socket::SSL> (1.84+) will be used automatically by L<Mojo::IOLoop> if
-they are installed. Individual features can also be disabled with the
-C<MOJO_NO_IPV6> and C<MOJO_NO_TLS> environment variables.
+For better scalability (epoll, kqueue) and to provide IPv6, SOCKS5 as well as
+TLS support, the optional modules L<EV> (4.0+), L<IO::Socket::IP> (0.20+),
+L<IO::Socket::Socks> (0.64+) and L<IO::Socket::SSL> (1.84+) will be used
+automatically if they are installed. Individual features can also be disabled
+with the C<MOJO_NO_IPV6>, C<MOJO_NO_SOCKS> and C<MOJO_NO_TLS> environment
+variables.
 
 See L<Mojolicious::Guides::Cookbook/"DEPLOYMENT"> for more.
 
@@ -120,21 +120,22 @@ Mojo::Server::Morbo - DOOOOOOOOOOOOOOOOOOM!
 
 L<Mojo::Server::Morbo> is a full featured, self-restart capable non-blocking
 I/O HTTP and WebSocket server, built around the very well tested and reliable
-L<Mojo::Server::Daemon>, with IPv6, TLS, Comet (long polling), keep-alive,
-connection pooling, timeout, cookie, multipart and multiple event loop
-support. Note that the server uses signals for process management, so you
-should avoid modifying signal handlers in your applications.
+L<Mojo::Server::Daemon>, with IPv6, TLS, Comet (long polling), keep-alive and
+multiple event loop support. Note that the server uses signals for process
+management, so you should avoid modifying signal handlers in your
+applications.
 
 To start applications with it you can use the L<morbo> script.
 
   $ morbo myapp.pl
   Server available at http://127.0.0.1:3000.
 
-For better scalability (epoll, kqueue) and to provide IPv6 as well as TLS
-support, the optional modules L<EV> (4.0+), L<IO::Socket::IP> (0.20+) and
-L<IO::Socket::SSL> (1.84+) will be used automatically by L<Mojo::IOLoop> if
-they are installed. Individual features can also be disabled with the
-C<MOJO_NO_IPV6> and C<MOJO_NO_TLS> environment variables.
+For better scalability (epoll, kqueue) and to provide IPv6, SOCKS5 as well as
+TLS support, the optional modules L<EV> (4.0+), L<IO::Socket::IP> (0.20+),
+L<IO::Socket::Socks> (0.64+) and L<IO::Socket::SSL> (1.84+) will be used
+automatically if they are installed. Individual features can also be disabled
+with the C<MOJO_NO_IPV6>, C<MOJO_NO_SOCKS> and C<MOJO_NO_TLS> environment
+variables.
 
 See L<Mojolicious::Guides::Cookbook/"DEPLOYMENT"> for more.
 
@@ -21,10 +21,9 @@ sub run {
   $self->emit(request => $tx);
 
   # Response headers
-  my $res     = $tx->res->fix_headers;
-  my $headers = $res->headers;
+  my $res  = $tx->res->fix_headers;
+  my $hash = $res->headers->to_hash(1);
   my @headers;
-  my $hash = $headers->to_hash(1);
   for my $name (keys %$hash) {
     push @headers, map { $name => $_ } @{$hash->{$name}};
   }
@@ -257,15 +257,16 @@ Mojo::Server::Prefork - Preforking non-blocking I/O HTTP and WebSocket server
 L<Mojo::Server::Prefork> is a full featured, UNIX optimized, preforking
 non-blocking I/O HTTP and WebSocket server, built around the very well tested
 and reliable L<Mojo::Server::Daemon>, with IPv6, TLS, Comet (long polling),
-keep-alive, connection pooling, timeout, cookie, multipart and multiple event
-loop support. Note that the server uses signals for process management, so you
-should avoid modifying signal handlers in your applications.
-
-For better scalability (epoll, kqueue) and to provide IPv6 as well as TLS
-support, the optional modules L<EV> (4.0+), L<IO::Socket::IP> (0.20+) and
-L<IO::Socket::SSL> (1.84+) will be used automatically by L<Mojo::IOLoop> if
-they are installed. Individual features can also be disabled with the
-C<MOJO_NO_IPV6> and C<MOJO_NO_TLS> environment variables.
+keep-alive and multiple event loop support. Note that the server uses signals
+for process management, so you should avoid modifying signal handlers in your
+applications.
+
+For better scalability (epoll, kqueue) and to provide IPv6, SOCKS5 as well as
+TLS support, the optional modules L<EV> (4.0+), L<IO::Socket::IP> (0.20+),
+L<IO::Socket::Socks> (0.64+) and L<IO::Socket::SSL> (1.84+) will be used
+automatically if they are installed. Individual features can also be disabled
+with the C<MOJO_NO_IPV6>, C<MOJO_NO_SOCKS> and C<MOJO_NO_TLS> environment
+variables.
 
 See L<Mojolicious::Guides::Cookbook/"DEPLOYMENT"> for more.
 
@@ -15,7 +15,7 @@ sub build_app {
   my ($self, $app) = @_;
   local $ENV{MOJO_EXE};
   return $app->new unless my $e = Mojo::Loader->new->load($app);
-  die ref $e ? $e : qq{Couldn't find application class "$app".\n};
+  die ref $e ? $e : qq{Can't find application class "$app" in \@INC. (@INC)\n};
 }
 
 sub build_tx {
@@ -50,13 +50,9 @@ sub load_app {
     local $ENV{MOJO_EXE};
 
     # Try to load application from script into sandbox
-    my $app = eval sprintf <<'EOF', md5_sum($path . $$);
-package Mojo::Server::SandBox::%s;
-my $app = do $path;
-if (!$app && (my $e = $@ || $!)) { die $e }
-$app;
-EOF
-    die qq{Couldn't load application from file "$path": $@} if !$app && $@;
+    my $app = eval "package Mojo::Server::Sandbox::@{[md5_sum $path]};"
+      . 'return do($path) || die($@ || $!);';
+    die qq{Can't load application from file "$path": $@} if !$app && $@;
     die qq{File "$path" did not return an application object.\n}
       unless blessed $app && $app->isa('Mojo');
     $self->app($app);
@@ -8,8 +8,8 @@ use Mojo::Util qw(decode encode monkey_patch slurp);
 
 use constant DEBUG => $ENV{MOJO_TEMPLATE_DEBUG} || 0;
 
-has [qw(auto_escape compiled)];
 has [qw(append code prepend template)] => '';
+has [qw(auto_escape compiled)];
 has capture_end   => 'end';
 has capture_start => 'begin';
 has comment_mark  => '#';
@@ -26,66 +26,61 @@ has tree      => sub { [] };
 sub build {
   my $self = shift;
 
-  my (@lines, $cpst, $multi);
+  my $tree   = $self->tree;
   my $escape = $self->auto_escape;
-  for my $line (@{$self->tree}) {
-    push @lines, '';
-    for (my $j = 0; $j < @{$line}; $j += 2) {
-      my ($op, $value) = @$line[$j, $j + 1];
-      my $newline = chomp($value //= '');
 
-      # Capture end
-      if ($op eq 'cpen') {
-        $lines[-1] .= 'return Mojo::ByteStream->new($_M) }';
+  my @blocks = ('');
+  my ($i, $capture, $multi);
+  while (++$i <= @$tree && (my $next = $tree->[$i])) {
+    my ($op, $value) = @{$tree->[$i - 1]};
+    push @blocks, '' and next if $op eq 'line';
+    my $newline = chomp($value //= '');
+
+    # Text (quote and fix line ending)
+    if ($op eq 'text') {
+      $value = join "\n", map { quotemeta $_ } split("\n", $value, -1);
+      $value .= '\n' if $newline;
+      $blocks[-1] .= "\$_M .= \"" . $value . "\";" if length $value;
+    }
 
-        # No following code
-        my $next = $line->[$j + 3];
-        $lines[-1] .= ';' if !defined $next || $next =~ /^\s*$/;
-      }
+    # Code or multiline expression
+    elsif ($op eq 'code' || $multi) { $blocks[-1] .= $value }
 
-      # Text (quote and fix line ending)
-      if ($op eq 'text') {
-        $value = $newline ? quotemeta($value) . '\n' : quotemeta $value;
-        $lines[-1] .= "\$_M .= \"" . $value . "\";" if length $value;
-      }
+    # Capture end
+    elsif ($op eq 'cpen') {
+      $blocks[-1] .= 'return Mojo::ByteStream->new($_M) }';
 
-      # Code or multiline expression
-      if ($op eq 'code' || $multi) { $lines[-1] .= "$value" }
+      # No following code
+      $blocks[-1] .= ';' if ($next->[1] // '') =~ /^\s*$/;
+    }
 
-      # Expression
-      if ($op eq 'expr' || $op eq 'escp') {
+    # Expression
+    if ($op eq 'expr' || $op eq 'escp') {
 
-        # Start
-        unless ($multi) {
+      # Escaped
+      if (!$multi && ($op eq 'escp' && !$escape || $op eq 'expr' && $escape)) {
+        $blocks[-1] .= "\$_M .= _escape scalar $value";
+      }
 
-          # Escaped
-          if ($op eq 'escp' && !$escape || $op eq 'expr' && $escape) {
-            $lines[-1] .= "\$_M .= _escape";
-            $lines[-1] .= " scalar $value" if length $value;
-          }
+      # Raw
+      elsif (!$multi) { $blocks[-1] .= "\$_M .= scalar $value" }
 
-          # Raw
-          else { $lines[-1] .= "\$_M .= scalar $value" }
-        }
+      # Multiline
+      $multi = !$next || $next->[0] ne 'text';
 
-        # Multiline
-        $multi = !(($line->[$j + 2] // '') eq 'text'
-          && ($line->[$j + 3] // '') eq '');
-
-        # Append semicolon
-        $lines[-1] .= ';' unless $multi || $cpst;
-      }
+      # Append semicolon
+      $blocks[-1] .= ';' unless $multi || $capture;
+    }
 
-      # Capture start
-      if ($cpst) {
-        $lines[-1] .= $cpst;
-        $cpst = undef;
-      }
-      $cpst = " sub { my \$_M = ''; " if $op eq 'cpst';
+    # Capture start
+    if ($op eq 'cpst') { $capture = 1 }
+    elsif ($capture) {
+      $blocks[-1] .= " sub { my \$_M = ''; ";
+      $capture = 0;
     }
   }
 
-  return $self->code(join "\n", @lines)->tree([]);
+  return $self->code(join "\n", @blocks)->tree([]);
 }
 
 sub compile {
@@ -121,7 +116,7 @@ sub parse {
   my ($self, $template) = @_;
 
   # Clean start
-  my $tree = $self->template($template)->tree([])->tree;
+  $self->template($template)->tree(\my @tree);
 
   my $tag     = $self->tag_start;
   my $replace = $self->replace_mark;
@@ -149,13 +144,12 @@ sub parse {
   my $end_re  = qr/^(?:(\Q$cpst\E)\s*)?(\Q$trim\E)?\Q$end\E$/;
 
   # Split lines
-  my $state = 'text';
-  my ($trimming, @capture_token);
+  my $op = 'text';
+  my ($trimming, $capture);
   for my $line (split "\n", $template) {
-    $trimming = 0 if $state eq 'text';
 
     # Turn Perl line into mixed line
-    if ($state eq 'text' && $line !~ s/^(\s*)\Q$start$replace\E/$1$start/) {
+    if ($op eq 'text' && $line !~ s/^(\s*)\Q$start$replace\E/$1$start/) {
       if ($line =~ s/^(\s*)\Q$start\E(?:(\Q$cmnt\E)|(\Q$expr\E))?//) {
 
         # Comment
@@ -167,63 +161,64 @@ sub parse {
     }
 
     # Escaped line ending
-    $line .= "\n" unless $line =~ s/\\\\$/\\\n/ || $line =~ s/\\$//;
+    $line .= "\n" if $line !~ s/\\\\$/\\\n/ && $line !~ s/\\$//;
 
     # Mixed line
-    my @token;
     for my $token (split $token_re, $line) {
 
       # Capture end
-      @capture_token = ('cpen', undef) if $token =~ s/$cpen_re/$1/;
+      $capture = 1 if $token =~ s/$cpen_re/$1/;
 
       # End
-      if ($state ne 'text' && $token =~ $end_re) {
-        $state = 'text';
+      if ($op ne 'text' && $token =~ $end_re) {
+        $op = 'text';
 
         # Capture start
-        splice @token, -2, 0, 'cpst', undef if $1;
+        splice @tree, -1, 0, ['cpst'] if $1;
 
         # Trim left side
-        if ($2) {
-          $trimming = 1;
-          $self->_trim(\@token);
-        }
+        _trim(\@tree) if ($trimming = $2) && @tree > 1;
 
         # Hint at end
-        push @token, 'text', '';
+        push @tree, ['text', ''];
       }
 
       # Code
-      elsif ($token =~ /^\Q$tag\E$/) { $state = 'code' }
+      elsif ($token =~ /^\Q$tag\E$/) { $op = 'code' }
 
       # Expression
-      elsif ($token =~ /^\Q$tag$expr\E$/) { $state = 'expr' }
+      elsif ($token =~ /^\Q$tag$expr\E$/) { $op = 'expr' }
 
       # Expression that needs to be escaped
-      elsif ($token =~ /^\Q$tag$expr$escp\E$/) { $state = 'escp' }
+      elsif ($token =~ /^\Q$tag$expr$escp\E$/) { $op = 'escp' }
 
       # Comment
-      elsif ($token =~ /^\Q$tag$cmnt\E$/) { $state = 'cmnt' }
+      elsif ($token =~ /^\Q$tag$cmnt\E$/) { $op = 'cmnt' }
 
-      # Text
-      else {
+      # Text (comments are just ignored)
+      elsif ($op ne 'cmnt') {
 
         # Replace
         $token = $tag if $token eq "$tag$replace";
 
         # Trim right side (convert whitespace to line noise)
         if ($trimming && $token =~ s/^(\s+)//) {
-          push @token, 'code', $1;
+          push @tree, ['code', $1];
           $trimming = 0;
         }
 
-        # Comments are ignored
-        next if $state eq 'cmnt';
-        push @token, @capture_token, $state, $token;
-        @capture_token = ();
+        # Token (with optional capture end)
+        push @tree, $capture ? ['cpen'] : (), [$op, $token];
+        $capture = 0;
       }
     }
-    push @$tree, \@token;
+
+    # Optimize successive text lines separated by a newline
+    push @tree, ['line'] and next
+      if $tree[-4] && $tree[-4][0] ne 'line'
+      || (!$tree[-3] || $tree[-3][0] ne 'text' || $tree[-3][1] !~ /\n$/)
+      || ($tree[-2][0] ne 'line' || $tree[-1][0] ne 'text');
+    $tree[-3][1] .= pop(@tree)->[1];
   }
 
   return $self;
@@ -253,23 +248,16 @@ sub _line {
 }
 
 sub _trim {
-  my ($self, $line) = @_;
-
-  # Walk line backwards
-  for (my $j = @$line - 4; $j >= 0; $j -= 2) {
+  my $tree = shift;
 
-    # Skip captures
-    next if $line->[$j] eq 'cpst' || $line->[$j] eq 'cpen';
+  # Skip captures
+  my $i = $tree->[-2][0] eq 'cpst' || $tree->[-2][0] eq 'cpen' ? -3 : -2;
 
-    # Only trim text
-    return unless $line->[$j] eq 'text';
+  # Only trim text
+  return unless $tree->[$i][0] eq 'text';
 
-    # Convert whitespace text to line noise
-    splice @$line, $j, 0, 'code', $1 if $line->[$j + 1] =~ s/(\s+)$//;
-
-    # Text left
-    return if length $line->[$j + 1];
-  }
+  # Convert whitespace text to line noise
+  splice @$tree, $i, 0, ['code', $1] if $tree->[$i][1] =~ s/(\s+)$//;
 }
 
 sub _wrap {
@@ -286,8 +274,8 @@ sub _wrap {
   my $num = () = $code =~ /\n/g;
   my $head = $self->_line(1);
   $head .= "\npackage @{[$self->namespace]}; use Mojo::Base -strict;";
-  $code = "$head sub { my \$_M = ''; @{[$self->prepend]}; do { $code\n";
-  $code .= $self->_line($num + 1) . "\n@{[$self->append]}; \$_M } };";
+  $code = "$head sub { my \$_M = ''; @{[$self->prepend]}; { $code\n";
+  $code .= $self->_line($num + 1) . "\n@{[$self->append]}; } \$_M };";
 
   warn "-- Code for @{[$self->name]}\n@{[encode 'UTF-8', $code]}\n\n" if DEBUG;
   return $code;
@@ -603,7 +591,7 @@ Raw unparsed template.
 =head2 tree
 
   my $tree = $mt->tree;
-  $mt      = $mt->tree([['text', 'foo']]);
+  $mt      = $mt->tree([['text', 'foo'], ['line']]);
 
 Template in parsed form. Note that this structure should only be used very
 carefully since it is very dynamic.
@@ -18,12 +18,12 @@ use constant GUID => '258EAFA5-E914-47DA-95CA-C5AB0DC85B11';
 
 # Opcodes
 use constant {
-  CONTINUATION => 0,
-  TEXT         => 1,
-  BINARY       => 2,
-  CLOSE        => 8,
-  PING         => 9,
-  PONG         => 10
+  CONTINUATION => 0x0,
+  TEXT         => 0x1,
+  BINARY       => 0x2,
+  CLOSE        => 0x8,
+  PING         => 0x9,
+  PONG         => 0xa
 };
 
 has [qw(compressed masked)];
@@ -35,35 +35,30 @@ sub build_frame {
   warn "-- Building frame ($fin, $rsv1, $rsv2, $rsv3, $op)\n" if DEBUG;
 
   # Head
-  my $frame = 0b00000000;
-  vec($frame, 0, 8) = $op | 0b10000000 if $fin;
-  vec($frame, 0, 8) |= 0b01000000 if $rsv1;
-  vec($frame, 0, 8) |= 0b00100000 if $rsv2;
-  vec($frame, 0, 8) |= 0b00010000 if $rsv3;
+  my $head = $op + ($fin ? 128 : 0);
+  $head |= 0b01000000 if $rsv1;
+  $head |= 0b00100000 if $rsv2;
+  $head |= 0b00010000 if $rsv3;
+  my $frame = pack 'C', $head;
 
   # Small payload
   my $len    = length $payload;
-  my $prefix = 0;
   my $masked = $self->masked;
   if ($len < 126) {
     warn "-- Small payload ($len)\n$payload\n" if DEBUG;
-    vec($prefix, 0, 8) = $masked ? ($len | 0b10000000) : $len;
-    $frame .= $prefix;
+    $frame .= pack 'C', $masked ? ($len | 128) : $len;
   }
 
-  # Extended payload (16bit)
+  # Extended payload (16-bit)
   elsif ($len < 65536) {
-    warn "-- Extended 16bit payload ($len)\n$payload\n" if DEBUG;
-    vec($prefix, 0, 8) = $masked ? (126 | 0b10000000) : 126;
-    $frame .= $prefix;
-    $frame .= pack 'n', $len;
+    warn "-- Extended 16-bit payload ($len)\n$payload\n" if DEBUG;
+    $frame .= pack 'Cn', $masked ? (126 | 128) : 126, $len;
   }
 
-  # Extended payload (64bit with 32bit fallback)
+  # Extended payload (64-bit with 32-bit fallback)
   else {
-    warn "-- Extended 64bit payload ($len)\n$payload\n" if DEBUG;
-    vec($prefix, 0, 8) = $masked ? (127 | 0b10000000) : 127;
-    $frame .= $prefix;
+    warn "-- Extended 64-bit payload ($len)\n$payload\n" if DEBUG;
+    $frame .= pack 'C', $masked ? (127 | 128) : 127;
     $frame .= MODERN ? pack('Q>', $len) : pack('NN', 0, $len & 0xffffffff);
   }
 
@@ -160,60 +155,54 @@ sub parse_frame {
   my ($self, $buffer) = @_;
 
   # Head
-  return undef unless length(my $clone = $$buffer) >= 2;
-  my $head = substr $clone, 0, 2;
+  return undef unless length $$buffer >= 2;
+  my ($first, $second) = unpack 'C*', substr($$buffer, 0, 2);
 
   # FIN
-  my $fin = (vec($head, 0, 8) & 0b10000000) == 0b10000000 ? 1 : 0;
+  my $fin = ($first & 0b10000000) == 0b10000000 ? 1 : 0;
 
   # RSV1-3
-  my $rsv1 = (vec($head, 0, 8) & 0b01000000) == 0b01000000 ? 1 : 0;
-  my $rsv2 = (vec($head, 0, 8) & 0b00100000) == 0b00100000 ? 1 : 0;
-  my $rsv3 = (vec($head, 0, 8) & 0b00010000) == 0b00010000 ? 1 : 0;
+  my $rsv1 = ($first & 0b01000000) == 0b01000000 ? 1 : 0;
+  my $rsv2 = ($first & 0b00100000) == 0b00100000 ? 1 : 0;
+  my $rsv3 = ($first & 0b00010000) == 0b00010000 ? 1 : 0;
 
   # Opcode
-  my $op = vec($head, 0, 8) & 0b00001111;
+  my $op = $first & 0b00001111;
   warn "-- Parsing frame ($fin, $rsv1, $rsv2, $rsv3, $op)\n" if DEBUG;
 
   # Small payload
-  my $len = vec($head, 1, 8) & 0b01111111;
-  my $hlen = 2;
+  my ($hlen, $len) = (2, $second & 0b01111111);
   if ($len < 126) { warn "-- Small payload ($len)\n" if DEBUG }
 
-  # Extended payload (16bit)
+  # Extended payload (16-bit)
   elsif ($len == 126) {
-    return undef unless length $clone > 4;
+    return undef unless length $$buffer > 4;
     $hlen = 4;
-    $len = unpack 'n', substr($clone, 2, 2);
-    warn "-- Extended 16bit payload ($len)\n" if DEBUG;
+    $len = unpack 'n', substr($$buffer, 2, 2);
+    warn "-- Extended 16-bit payload ($len)\n" if DEBUG;
   }
 
-  # Extended payload (64bit with 32bit fallback)
+  # Extended payload (64-bit with 32-bit fallback)
   elsif ($len == 127) {
-    return undef unless length $clone > 10;
+    return undef unless length $$buffer > 10;
     $hlen = 10;
-    my $ext = substr $clone, 2, 8;
+    my $ext = substr $$buffer, 2, 8;
     $len = MODERN ? unpack('Q>', $ext) : unpack('N', substr($ext, 4, 4));
-    warn "-- Extended 64bit payload ($len)\n" if DEBUG;
+    warn "-- Extended 64-bit payload ($len)\n" if DEBUG;
   }
 
   # Check message size
   $self->finish(1009) and return undef if $len > $self->max_websocket_size;
 
   # Check if whole packet has arrived
-  my $masked = vec($head, 1, 8) & 0b10000000;
-  return undef if length $clone < ($len + $hlen + ($masked ? 4 : 0));
-  substr $clone, 0, $hlen, '';
+  $len += 4 if my $masked = $second & 0b10000000;
+  return undef if length $$buffer < ($hlen + $len);
+  substr $$buffer, 0, $hlen, '';
 
   # Payload
-  $len += 4 if $masked;
-  return undef if length $clone < $len;
-  my $payload = $len ? substr($clone, 0, $len, '') : '';
-
-  # Unmask payload
+  my $payload = $len ? substr($$buffer, 0, $len, '') : '';
   $payload = xor_encode($payload, substr($payload, 0, 4, '') x 128) if $masked;
   warn "$payload\n" if DEBUG;
-  $$buffer = $clone;
 
   return [$fin, $rsv1, $rsv2, $rsv3, $op, $payload];
 }
@@ -365,8 +354,8 @@ Mojo::Transaction::WebSocket - WebSocket transaction
 =head1 DESCRIPTION
 
 L<Mojo::Transaction::WebSocket> is a container for WebSocket transactions
-based on L<RFC 6455|http://tools.ietf.org/html/rfc6455>. Note that 64bit
-frames require a Perl with support for quads or they are limited to 32bit.
+based on L<RFC 6455|http://tools.ietf.org/html/rfc6455>. Note that 64-bit
+frames require a Perl with support for quads or they are limited to 32-bit.
 
 =head1 EVENTS
 
@@ -501,7 +490,7 @@ object.
   my $bool = $ws->masked;
   $ws      = $ws->masked($bool);
 
-Mask outgoing frames with XOR cipher and a random 32bit key.
+Mask outgoing frames with XOR cipher and a random 32-bit key.
 
 =head2 max_websocket_size
 
@@ -5,7 +5,8 @@ use Carp 'croak';
 use Mojo::Message::Request;
 use Mojo::Message::Response;
 
-has [qw(kept_alive local_address local_port remote_port)];
+has [
+  qw(kept_alive local_address local_port original_remote_address remote_port)];
 has req => sub { Mojo::Message::Request->new };
 has res => sub { Mojo::Message::Response->new };
 
@@ -46,20 +47,12 @@ sub is_writing { (shift->{state} // 'write') eq 'write' }
 sub remote_address {
   my $self = shift;
 
-  # New address
-  if (@_) {
-    $self->{remote_address} = shift;
-    return $self;
-  }
+  return $self->original_remote_address(@_) if @_;
+  return $self->original_remote_address unless $self->req->reverse_proxy;
 
   # Reverse proxy
-  if ($self->req->reverse_proxy) {
-    return $self->{forwarded_for} if $self->{forwarded_for};
-    my $forwarded = $self->req->headers->header('X-Forwarded-For') // '';
-    $forwarded =~ /([^,\s]+)$/ and return $self->{forwarded_for} = $1;
-  }
-
-  return $self->{remote_address};
+  return ($self->req->headers->header('X-Forwarded-For') // '')
+    =~ /([^,\s]+)$/ ? $1 : $self->original_remote_address;
 }
 
 sub resume       { shift->_state(qw(write resume)) }
@@ -155,6 +148,13 @@ Local interface address.
 
 Local interface port.
 
+=head2 original_remote_address
+
+  my $address = $tx->original_remote_address;
+  $tx         = $tx->original_remote_address('127.0.0.1');
+
+Remote interface address.
+
 =head2 remote_port
 
   my $port = $tx->remote_port;
@@ -246,7 +246,9 @@ Resume transaction.
   my $address = $tx->remote_address;
   $tx         = $tx->remote_address('127.0.0.1');
 
-Remote interface address.
+Same as L</"original_remote_address"> or the last value of the
+C<X-Forwarded-For> header if L</"req"> has been performed through a reverse
+proxy.
 
 =head2 server_close
 
@@ -41,13 +41,10 @@ sub host_port {
 }
 
 sub clone {
-  my $self = shift;
-
+  my $self  = shift;
   my $clone = $self->new;
-  $clone->$_($self->$_) for qw(scheme userinfo host port fragment);
-  $clone->path($self->path->clone)->query($self->query->clone);
-  $clone->base($self->base->clone) if $self->{base};
-
+  @$clone{keys %$self} = values %$self;
+  $clone->{$_} && ($clone->{$_} = $clone->{$_}->clone) for qw(base path query);
   return $clone;
 }
 
@@ -296,7 +293,7 @@ Clone this URL.
 
 Normalized version of L</"host"> and L</"port">.
 
-  # "xn--da5b0n.net:8080"
+  # "xn--n3h.net:8080"
   Mojo::URL->new('http://☃.net:8080/test')->host_port;
 
 =head2 ihost
@@ -306,7 +303,7 @@ Normalized version of L</"host"> and L</"port">.
 
 Host part of this URL in punycode format.
 
-  # "xn--da5b0n.net"
+  # "xn--n3h.net"
   Mojo::URL->new('http://☃.net')->ihost;
 
 =head2 is_abs
@@ -4,6 +4,7 @@ use Mojo::Base -base;
 use Mojo::Cookie::Request;
 use Mojo::Path;
 
+has extracting      => 1;
 has max_cookie_size => 4096;
 
 sub add {
@@ -40,6 +41,9 @@ sub empty { delete shift->{jar} }
 
 sub extract {
   my ($self, $tx) = @_;
+
+  return unless $self->extracting;
+
   my $url = $tx->req->url;
   for my $cookie (@{$tx->res->cookies}) {
 
@@ -146,6 +150,14 @@ L<RFC 6265|http://tools.ietf.org/html/rfc6265>.
 
 L<Mojo::UserAgent::CookieJar> implements the following attributes.
 
+=head2 extracting
+
+  my $bool = $jar->extracting;
+  $jar     = $jar->extracting($bool);
+
+Allow L</"extract"> to L</"add"> new cookies to the jar, defaults to a true
+value.
+
 =head2 max_cookie_size
 
   my $size = $jar->max_cookie_size;
@@ -58,22 +58,22 @@ L<Mojo::UserAgent::Proxy> implements the following attributes.
 
 =head2 http
 
-  my $http = $ua->http;
-  $ua      = $ua->http('http://sri:secret@127.0.0.1:8080');
+  my $http = $proxy->http;
+  $proxy   = $proxy->http('socks://sri:secret@127.0.0.1:8080');
 
 Proxy server to use for HTTP and WebSocket requests.
 
 =head2 https
 
-  my $https = $ua->https;
-  $ua       = $ua->https('http://sri:secret@127.0.0.1:8080');
+  my $https = $proxy->https;
+  $proxy    = $proxy->https('http://sri:secret@127.0.0.1:8080');
 
 Proxy server to use for HTTPS and WebSocket requests.
 
 =head2 not
 
   my $not = $proxy->not;
-  $ua     = $proxy->not([qw(localhost intranet.mojolicio.us)]);
+  $proxy  = $proxy->not([qw(localhost intranet.mojolicio.us)]);
 
 Domains that don't require a proxy server to be used.
 
@@ -33,16 +33,15 @@ sub endpoint {
   my $port  = $url->port || ($proto eq 'https' ? 443 : 80);
 
   # Proxy for normal HTTP requests
+  my $socks;
+  if (my $proxy = $req->proxy) { $socks = $proxy->protocol eq 'socks' }
   return $self->_proxy($tx, $proto, $host, $port)
-    if $proto eq 'http' && !$req->is_handshake;
+    if $proto eq 'http' && !$req->is_handshake && !$socks;
 
   return $proto, $host, $port;
 }
 
-sub peer {
-  my ($self, $tx) = @_;
-  return $self->_proxy($tx, $self->endpoint($tx));
-}
+sub peer { $_[0]->_proxy($_[1], $_[0]->endpoint($_[1])) }
 
 sub proxy_connect {
   my ($self, $old) = @_;
@@ -53,6 +52,7 @@ sub proxy_connect {
 
   # No proxy
   return undef unless my $proxy = $req->proxy;
+  return undef if $proxy->protocol eq 'socks';
 
   # WebSocket and/or HTTPS
   my $url = $req->url;
@@ -284,6 +284,23 @@ Mojo::UserAgent::Transactor - User agent transactor
 L<Mojo::UserAgent::Transactor> is the transaction building and manipulation
 framework used by L<Mojo::UserAgent>.
 
+=head1 GENERATORS
+
+These content generators are available by default.
+
+=head2 form
+
+  $t->tx(POST => 'http://example.com' => form => {a => 'b'});
+
+Generate query string, C<application/x-www-form-urlencoded> or
+C<multipart/form-data> content.
+
+=head2 json
+
+  $t->tx(PATCH => 'http://example.com' => json => {a => 'b'});
+
+Generate JSON content with L<Mojo::JSON>.
+
 =head1 ATTRIBUTES
 
 L<Mojo::UserAgent::Transactor> implements the following attributes.
@@ -345,18 +362,18 @@ C<307> or C<308> redirect response if possible.
 
   my $tx = $t->tx(GET  => 'example.com');
   my $tx = $t->tx(POST => 'http://example.com');
-  my $tx = $t->tx(GET  => 'http://example.com' => {DNT => 1});
+  my $tx = $t->tx(GET  => 'http://example.com' => {Accept => '*/*'});
   my $tx = $t->tx(PUT  => 'http://example.com' => 'Hi!');
   my $tx = $t->tx(PUT  => 'http://example.com' => form => {a => 'b'});
   my $tx = $t->tx(PUT  => 'http://example.com' => json => {a => 'b'});
-  my $tx = $t->tx(POST => 'http://example.com' => {DNT => 1} => 'Hi!');
+  my $tx = $t->tx(POST => 'http://example.com' => {Accept => '*/*'} => 'Hi!');
   my $tx = $t->tx(
-    PUT  => 'http://example.com' => {DNT => 1} => form => {a => 'b'});
+    PUT  => 'http://example.com' => {Accept => '*/*'} => form => {a => 'b'});
   my $tx = $t->tx(
-    PUT  => 'http://example.com' => {DNT => 1} => json => {a => 'b'});
+    PUT  => 'http://example.com' => {Accept => '*/*'} => json => {a => 'b'});
 
 Versatile general purpose L<Mojo::Transaction::HTTP> transaction builder for
-requests, with support for content generators.
+requests, with support for L</"GENERATORS">.
 
   # Generate and inspect custom GET request with DNT header and content
   say $t->tx(GET => 'example.com' => {DNT => 1} => 'Bye!')->req->to_string;
@@ -373,28 +390,51 @@ requests, with support for content generators.
   my $tx = $t->tx(PUT => 'http://example.com');
   $tx->req->content->asset(Mojo::Asset::File->new(path => '/foo.txt'));
 
-  # GET request with query parameters
-  my $tx = $t->tx(GET => 'http://example.com' => form => {a => 'b'});
+The C<json> content generator uses L<Mojo::JSON> for encoding and sets the
+content type to C<application/json>.
 
   # POST request with "application/json" content
   my $tx = $t->tx(
     POST => 'http://example.com' => json => {a => 'b', c => [1, 2, 3]});
 
+The C<form> content generator will automatically use query parameters for
+C<GET> and C<HEAD> requests.
+
+  # GET request with query parameters
+  my $tx = $t->tx(GET => 'http://example.com' => form => {a => 'b'});
+
+For all other request methods the C<application/x-www-form-urlencoded> content
+type is used.
+
   # POST request with "application/x-www-form-urlencoded" content
   my $tx = $t->tx(
     POST => 'http://example.com' => form => {a => 'b', c => 'd'});
 
+Parameters may be encoded with the C<charset> option.
+
   # PUT request with Shift_JIS encoded form values
   my $tx = $t->tx(
     PUT => 'example.com' => form => {a => 'b'} => charset => 'Shift_JIS');
 
+An array reference can be used for multiple form values sharing the same name.
+
   # POST request with form values sharing the same name
   my $tx = $t->tx(POST => 'http://example.com' => form => {a => [qw(b c d)]});
 
+A hash reference with a C<content> or C<file> value can be used to switch to
+the C<multipart/form-data> content type for file uploads.
+
   # POST request with "multipart/form-data" content
   my $tx = $t->tx(
     POST => 'http://example.com' => form => {mytext => {content => 'lala'}});
 
+  # POST request with multiple files sharing the same name
+  my $tx = $t->tx(POST => 'http://example.com' =>
+    form => {mytext => [{content => 'first'}, {content => 'second'}]});
+
+The C<file> value should contain the path to the file you want to upload or an
+asset object, like L<Mojo::Asset::File> or L<Mojo::Asset::Memory>.
+
   # POST request with upload streamed from file
   my $tx = $t->tx(
     POST => 'http://example.com' => form => {mytext => {file => '/foo.txt'}});
@@ -404,9 +444,9 @@ requests, with support for content generators.
   my $tx    = $t->tx(
     POST => 'http://example.com' => form => {mytext => {file => $asset}});
 
-  # POST request with multiple files sharing the same name
-  my $tx = $t->tx(POST => 'http://example.com' =>
-    form => {mytext => [{content => 'first'}, {content => 'second'}]});
+A C<filename> value will be generated automatically, but can also be set
+manually if necessary. All remainging values in the hash reference get merged
+into the C<multipart/form-data> content as headers.
 
   # POST request with form values and customized upload (filename and header)
   my $tx = $t->tx(POST => 'http://example.com' => form => {
@@ -419,11 +459,8 @@ requests, with support for content generators.
     }
   });
 
-The C<form> content generator will automatically use query parameters for
-C<GET>/C<HEAD> requests and the C<application/x-www-form-urlencoded> content
-type for everything else. Both get upgraded automatically to using the
-C<multipart/form-data> content type when necessary or when the header has been
-set manually.
+The C<multipart/form-data> content type can also be enforced by setting the
+C<Content-Type> header manually.
 
   # Force "multipart/form-data"
   my $headers = {'Content-Type' => 'multipart/form-data'};
@@ -85,21 +85,33 @@ sub _cleanup {
 }
 
 sub _connect {
-  my ($self, $nb, $proto, $host, $port, $handle, $cb) = @_;
+  my ($self, $nb, $peer, $tx, $handle, $cb) = @_;
+
+  my $t = $self->transactor;
+  my ($proto, $host, $port) = $peer ? $t->peer($tx) : $t->endpoint($tx);
+  my %options
+    = (address => $host, port => $port, timeout => $self->connect_timeout);
+  if (my $local = $self->local_address) { $options{local_address} = $local }
+  $options{handle} = $handle if $handle;
+
+  # SOCKS
+  if ($proto eq 'socks') {
+    @options{qw(socks_address socks_port)} = @options{qw(address port)};
+    ($proto, @options{qw(address port)}) = $t->endpoint($tx);
+    my $req      = $tx->req;
+    my $userinfo = $req->proxy->userinfo;
+    $req->proxy(0);
+    @options{qw(socks_user socks_pass)} = split ':', $userinfo if $userinfo;
+  }
+
+  # TLS
+  map { $options{"tls_$_"} = $self->$_ } qw(ca cert key)
+    if ($options{tls} = $proto eq 'https');
 
   weaken $self;
   my $id;
   return $id = $self->_loop($nb)->client(
-    address       => $host,
-    handle        => $handle,
-    local_address => $self->local_address,
-    port          => $port,
-    timeout       => $self->connect_timeout,
-    tls           => $proto eq 'https',
-    tls_ca        => $self->ca,
-    tls_cert      => $self->cert,
-    tls_key       => $self->key,
-    sub {
+    %options => sub {
       my ($loop, $err, $stream) = @_;
 
       # Connection error
@@ -107,8 +119,7 @@ sub _connect {
       return $self->_error($id, $err) if $err;
 
       # Connection established
-      $stream->on(
-        timeout => sub { $self->_error($id, 'Inactivity timeout', 1) });
+      $stream->on(timeout => sub { $self->_error($id, 'Inactivity timeout') });
       $stream->on(close => sub { $self && $self->_finish($id, 1) });
       $stream->on(error => sub { $self && $self->_error($id, pop) });
       $stream->on(read => sub { $self->_read($id, pop) });
@@ -127,12 +138,11 @@ sub _connect_proxy {
       my ($self, $tx) = @_;
 
       # CONNECT failed (connection needs to be kept alive)
-      unless ($tx->keep_alive && $tx->res->is_status_class(200)) {
-        $old->req->error({message => 'Proxy connection failed'});
-        return $self->$cb($old);
-      }
+      $old->res->error({message => 'Proxy connection failed'})
+        and return $self->$cb($old)
+        if $tx->error || !$tx->res->is_status_class(200) || !$tx->keep_alive;
 
-      # Prevent proxy reassignment and start real transaction
+      # Start real transaction
       $old->req->proxy(0);
       my $id = $tx->connection;
       return $self->_start($nb, $old->connection($id), $cb)
@@ -141,11 +151,10 @@ sub _connect_proxy {
       # TLS upgrade
       my $loop   = $self->_loop($nb);
       my $handle = $loop->stream($id)->steal_handle;
-      my $c      = delete $self->{connections}{$id};
       $loop->remove($id);
-      $id = $self->_connect($nb, $self->transactor->endpoint($old),
-        $handle, sub { shift->_start($nb, $old->connection($id), $cb) });
-      $self->{connections}{$id} = $c;
+      $id = $self->_connect($nb, 0, $old, $handle,
+        sub { shift->_start($nb, $old->connection($id), $cb) });
+      $self->{connections}{$id} = {cb => $cb, nb => $nb, tx => $old};
     }
   );
 }
@@ -190,8 +199,7 @@ sub _connection {
 
   # Connect
   warn "-- Connect ($proto:$host:$port)\n" if DEBUG;
-  ($proto, $host, $port) = $self->transactor->peer($tx);
-  $id = $self->_connect(($nb, $proto, $host, $port, $id) => \&_connected);
+  $id = $self->_connect($nb, 1, $tx, $id, \&_connected);
   $self->{connections}{$id} = {cb => $cb, nb => $nb, tx => $tx};
 
   return $id;
@@ -226,12 +234,9 @@ sub _enqueue {
 }
 
 sub _error {
-  my ($self, $id, $err, $timeout) = @_;
-
-  if (my $tx = $self->{connections}{$id}{tx}) {
-    $tx->res->error({message => $err});
-  }
-  elsif (!$timeout) { return $self->emit(error => $err) }
+  my ($self, $id, $err) = @_;
+  my $tx = $self->{connections}{$id}{tx};
+  $tx->res->error({message => $err}) if $tx;
   $self->_finish($id, 1);
 }
 
@@ -239,7 +244,7 @@ sub _finish {
   my ($self, $id, $close) = @_;
 
   # Remove request timeout
-  my $c = $self->{connections}{$id};
+  return unless my $c    = $self->{connections}{$id};
   return unless my $loop = $self->_loop($c->{nb});
   $loop->remove($c->{timeout}) if $c->{timeout};
 
@@ -293,11 +298,8 @@ sub _remove {
   # Close connection
   my $c = delete $self->{connections}{$id} || {};
   my $tx = $c->{tx};
-  if ($close || !$tx || !$tx->keep_alive || $tx->error) {
-    $self->_dequeue($_, $id) for 1, 0;
-    $self->_loop($_)->remove($id) for 1, 0;
-    return;
-  }
+  return map { $self->_dequeue($_, $id); $self->_loop($_)->remove($id) } 1, 0
+    if $close || !$tx || !$tx->keep_alive || $tx->error;
 
   # Keep connection alive (CONNECT requests get upgraded)
   $self->_enqueue($c->{nb}, join(':', $self->transactor->endpoint($tx)), $id)
@@ -314,8 +316,7 @@ sub _start {
     $url->scheme($base->scheme)->authority($base->authority);
   }
 
-  $self->proxy->inject($tx);
-  if (my $jar = $self->cookie_jar) { $jar->inject($tx) }
+  $_ && $_->inject($tx) for $self->proxy, $self->cookie_jar;
 
   # Connect and add request timeout if necessary
   my $id = $self->emit(start => $tx)->_connection($nb, $tx, $cb);
@@ -382,6 +383,11 @@ Mojo::UserAgent - Non-blocking I/O HTTP and WebSocket user agent
   # Scrape the latest headlines from a news site with CSS selectors
   say $ua->get('blogs.perl.org')->res->dom('h2 > a')->text->shuffle;
 
+  # Search DuckDuckGo anonymously through Tor
+  $ua->proxy->http('socks://127.0.0.1:9050');
+  say $ua->get('api.3g2upl4pq6kufc4m.onion/?q=mojolicious&format=json')
+    ->res->json('/Abstract');
+
   # IPv6 PUT request with content
   my $tx
     = $ua->put('[::1]:3000' => {'Content-Type' => 'text/plain'} => 'Hello!');
@@ -424,19 +430,20 @@ Mojo::UserAgent - Non-blocking I/O HTTP and WebSocket user agent
 =head1 DESCRIPTION
 
 L<Mojo::UserAgent> is a full featured non-blocking I/O HTTP and WebSocket user
-agent, with IPv6, TLS, SNI, IDNA, Comet (long polling), keep-alive, connection
-pooling, timeout, cookie, multipart, proxy, gzip compression and multiple
-event loop support.
+agent, with IPv6, TLS, SNI, IDNA, HTTP/SOCKS5 proxy, Comet (long polling),
+keep-alive, connection pooling, timeout, cookie, multipart, gzip compression
+and multiple event loop support.
 
 All connections will be reset automatically if a new process has been forked,
 this allows multiple processes to share the same L<Mojo::UserAgent> object
 safely.
 
-For better scalability (epoll, kqueue) and to provide IPv6 as well as TLS
-support, the optional modules L<EV> (4.0+), L<IO::Socket::IP> (0.20+) and
-L<IO::Socket::SSL> (1.84+) will be used automatically by L<Mojo::IOLoop> if
-they are installed. Individual features can also be disabled with the
-C<MOJO_NO_IPV6> and C<MOJO_NO_TLS> environment variables.
+For better scalability (epoll, kqueue) and to provide IPv6, SOCKS5 as well as
+TLS support, the optional modules L<EV> (4.0+), L<IO::Socket::IP> (0.20+),
+L<IO::Socket::Socks> (0.64+) and L<IO::Socket::SSL> (1.84+) will be used
+automatically if they are installed. Individual features can also be disabled
+with the C<MOJO_NO_IPV6>, C<MOJO_NO_SOCKS> and C<MOJO_NO_TLS> environment
+variables.
 
 See L<Mojolicious::Guides::Cookbook/"USER AGENT"> for more.
 
@@ -445,21 +452,6 @@ See L<Mojolicious::Guides::Cookbook/"USER AGENT"> for more.
 L<Mojo::UserAgent> inherits all events from L<Mojo::EventEmitter> and can emit
 the following new ones.
 
-=head2 error
-
-  $ua->on(error => sub {
-    my ($ua, $err) = @_;
-    ...
-  });
-
-Emitted if an error occurs that can't be associated with a transaction, fatal
-if unhandled.
-
-  $ua->on(error => sub {
-    my ($ua, $err) = @_;
-    say "This looks bad: $err";
-  });
-
 =head2 start
 
   $ua->on(start => sub {
@@ -513,11 +505,11 @@ environment variable or C<10>.
   my $cookie_jar = $ua->cookie_jar;
   $ua            = $ua->cookie_jar(Mojo::UserAgent::CookieJar->new);
 
-Cookie jar to use for this user agents requests, defaults to a
+Cookie jar to use for requests performed by this user agent, defaults to a
 L<Mojo::UserAgent::CookieJar> object.
 
-  # Disable cookie jar
-  $ua->cookie_jar(0);
+  # Disable extraction of cookies from responses
+  $ua->cookie_jar->extracting(0);
 
 =head2 inactivity_timeout
 
@@ -580,6 +572,12 @@ Proxy manager, defaults to a L<Mojo::UserAgent::Proxy> object.
   # Detect proxy servers from environment
   $ua->proxy->detect;
 
+  # Manually configure HTTP proxy (using CONNECT for HTTPS)
+  $ua->proxy->http('http://127.0.0.1:8080')->https('http://127.0.0.1:8080');
+
+  # Manually configure Tor (SOCKS5)
+  $ua->proxy->http('socks://127.0.0.1:9050')->https('socks://127.0.0.1:9050');
+
 =head2 request_timeout
 
   my $timeout = $ua->request_timeout;
@@ -632,11 +630,12 @@ implements the following new ones.
 =head2 build_tx
 
   my $tx = $ua->build_tx(GET => 'example.com');
-  my $tx = $ua->build_tx(PUT => 'http://example.com' => {DNT => 1} => 'Hi!');
   my $tx = $ua->build_tx(
-    PUT => 'http://example.com' => {DNT => 1} => form => {a => 'b'});
+    PUT => 'http://example.com' => {Accept => '*/*'} => 'Hi!');
+  my $tx = $ua->build_tx(
+    PUT => 'http://example.com' => {Accept => '*/*'} => form => {a => 'b'});
   my $tx = $ua->build_tx(
-    PUT => 'http://example.com' => {DNT => 1} => json => {a => 'b'});
+    PUT => 'http://example.com' => {Accept => '*/*'} => json => {a => 'b'});
 
 Generate L<Mojo::Transaction::HTTP> object with
 L<Mojo::UserAgent::Transactor/"tx">.
@@ -672,16 +671,16 @@ L<Mojo::UserAgent::Transactor/"websocket">.
 =head2 delete
 
   my $tx = $ua->delete('example.com');
-  my $tx = $ua->delete('http://example.com' => {DNT => 1} => 'Hi!');
+  my $tx = $ua->delete('http://example.com' => {Accept => '*/*'} => 'Hi!');
   my $tx = $ua->delete(
-    'http://example.com' => {DNT => 1} => form => {a => 'b'});
+    'http://example.com' => {Accept => '*/*'} => form => {a => 'b'});
   my $tx = $ua->delete(
-    'http://example.com' => {DNT => 1} => json => {a => 'b'});
+    'http://example.com' => {Accept => '*/*'} => json => {a => 'b'});
 
 Perform blocking C<DELETE> request and return resulting
 L<Mojo::Transaction::HTTP> object, takes the same arguments as
-L<Mojo::UserAgent::Transactor/"tx"> (except for the method). You can also
-append a callback to perform requests non-blocking.
+L<Mojo::UserAgent::Transactor/"tx"> (except for the C<DELETE> method, which is
+implied). You can also append a callback to perform requests non-blocking.
 
   $ua->delete('http://example.com' => sub {
     my ($ua, $tx) = @_;
@@ -692,14 +691,16 @@ append a callback to perform requests non-blocking.
 =head2 get
 
   my $tx = $ua->get('example.com');
-  my $tx = $ua->get('http://example.com' => {DNT => 1} => 'Hi!');
-  my $tx = $ua->get('http://example.com' => {DNT => 1} => form => {a => 'b'});
-  my $tx = $ua->get('http://example.com' => {DNT => 1} => json => {a => 'b'});
+  my $tx = $ua->get('http://example.com' => {Accept => '*/*'} => 'Hi!');
+  my $tx = $ua->get(
+    'http://example.com' => {Accept => '*/*'} => form => {a => 'b'});
+  my $tx = $ua->get(
+    'http://example.com' => {Accept => '*/*'} => json => {a => 'b'});
 
 Perform blocking C<GET> request and return resulting
 L<Mojo::Transaction::HTTP> object, takes the same arguments as
-L<Mojo::UserAgent::Transactor/"tx"> (except for the method). You can also
-append a callback to perform requests non-blocking.
+L<Mojo::UserAgent::Transactor/"tx"> (except for the C<GET> method, which is
+implied). You can also append a callback to perform requests non-blocking.
 
   $ua->get('http://example.com' => sub {
     my ($ua, $tx) = @_;
@@ -710,16 +711,16 @@ append a callback to perform requests non-blocking.
 =head2 head
 
   my $tx = $ua->head('example.com');
-  my $tx = $ua->head('http://example.com' => {DNT => 1} => 'Hi!');
+  my $tx = $ua->head('http://example.com' => {Accept => '*/*'} => 'Hi!');
   my $tx = $ua->head(
-    'http://example.com' => {DNT => 1} => form => {a => 'b'});
+    'http://example.com' => {Accept => '*/*'} => form => {a => 'b'});
   my $tx = $ua->head(
-    'http://example.com' => {DNT => 1} => json => {a => 'b'});
+    'http://example.com' => {Accept => '*/*'} => json => {a => 'b'});
 
 Perform blocking C<HEAD> request and return resulting
 L<Mojo::Transaction::HTTP> object, takes the same arguments as
-L<Mojo::UserAgent::Transactor/"tx"> (except for the method). You can also
-append a callback to perform requests non-blocking.
+L<Mojo::UserAgent::Transactor/"tx"> (except for the C<HEAD> method, which is
+implied). You can also append a callback to perform requests non-blocking.
 
   $ua->head('http://example.com' => sub {
     my ($ua, $tx) = @_;
@@ -730,16 +731,16 @@ append a callback to perform requests non-blocking.
 =head2 options
 
   my $tx = $ua->options('example.com');
-  my $tx = $ua->options('http://example.com' => {DNT => 1} => 'Hi!');
+  my $tx = $ua->options('http://example.com' => {Accept => '*/*'} => 'Hi!');
   my $tx = $ua->options(
-    'http://example.com' => {DNT => 1} => form => {a => 'b'});
+    'http://example.com' => {Accept => '*/*'} => form => {a => 'b'});
   my $tx = $ua->options(
-    'http://example.com' => {DNT => 1} => json => {a => 'b'});
+    'http://example.com' => {Accept => '*/*'} => json => {a => 'b'});
 
 Perform blocking C<OPTIONS> request and return resulting
 L<Mojo::Transaction::HTTP> object, takes the same arguments as
-L<Mojo::UserAgent::Transactor/"tx"> (except for the method). You can also
-append a callback to perform requests non-blocking.
+L<Mojo::UserAgent::Transactor/"tx"> (except for the C<OPTIONS> method, which
+is implied). You can also append a callback to perform requests non-blocking.
 
   $ua->options('http://example.com' => sub {
     my ($ua, $tx) = @_;
@@ -750,16 +751,16 @@ append a callback to perform requests non-blocking.
 =head2 patch
 
   my $tx = $ua->patch('example.com');
-  my $tx = $ua->patch('http://example.com' => {DNT => 1} => 'Hi!');
+  my $tx = $ua->patch('http://example.com' => {Accept => '*/*'} => 'Hi!');
   my $tx = $ua->patch(
-    'http://example.com' => {DNT => 1} => form => {a => 'b'});
+    'http://example.com' => {Accept => '*/*'} => form => {a => 'b'});
   my $tx = $ua->patch(
-    'http://example.com' => {DNT => 1} => json => {a => 'b'});
+    'http://example.com' => {Accept => '*/*'} => json => {a => 'b'});
 
 Perform blocking C<PATCH> request and return resulting
 L<Mojo::Transaction::HTTP> object, takes the same arguments as
-L<Mojo::UserAgent::Transactor/"tx"> (except for the method). You can also
-append a callback to perform requests non-blocking.
+L<Mojo::UserAgent::Transactor/"tx"> (except for the C<PATCH> method, which is
+implied). You can also append a callback to perform requests non-blocking.
 
   $ua->patch('http://example.com' => sub {
     my ($ua, $tx) = @_;
@@ -770,16 +771,16 @@ append a callback to perform requests non-blocking.
 =head2 post
 
   my $tx = $ua->post('example.com');
-  my $tx = $ua->post('http://example.com' => {DNT => 1} => 'Hi!');
+  my $tx = $ua->post('http://example.com' => {Accept => '*/*'} => 'Hi!');
   my $tx = $ua->post(
-    'http://example.com' => {DNT => 1} => form => {a => 'b'});
+    'http://example.com' => {Accept => '*/*'} => form => {a => 'b'});
   my $tx = $ua->post(
-    'http://example.com' => {DNT => 1} => json => {a => 'b'});
+    'http://example.com' => {Accept => '*/*'} => json => {a => 'b'});
 
 Perform blocking C<POST> request and return resulting
 L<Mojo::Transaction::HTTP> object, takes the same arguments as
-L<Mojo::UserAgent::Transactor/"tx"> (except for the method). You can also
-append a callback to perform requests non-blocking.
+L<Mojo::UserAgent::Transactor/"tx"> (except for the C<POST> method, which is
+implied). You can also append a callback to perform requests non-blocking.
 
   $ua->post('http://example.com' => sub {
     my ($ua, $tx) = @_;
@@ -790,14 +791,16 @@ append a callback to perform requests non-blocking.
 =head2 put
 
   my $tx = $ua->put('example.com');
-  my $tx = $ua->put('http://example.com' => {DNT => 1} => 'Hi!');
-  my $tx = $ua->put('http://example.com' => {DNT => 1} => form => {a => 'b'});
-  my $tx = $ua->put('http://example.com' => {DNT => 1} => json => {a => 'b'});
+  my $tx = $ua->put('http://example.com' => {Accept => '*/*'} => 'Hi!');
+  my $tx = $ua->put(
+    'http://example.com' => {Accept => '*/*'} => form => {a => 'b'});
+  my $tx = $ua->put(
+    'http://example.com' => {Accept => '*/*'} => json => {a => 'b'});
 
 Perform blocking C<PUT> request and return resulting
 L<Mojo::Transaction::HTTP> object, takes the same arguments as
-L<Mojo::UserAgent::Transactor/"tx"> (except for the method). You can also
-append a callback to perform requests non-blocking.
+L<Mojo::UserAgent::Transactor/"tx"> (except for the C<PUT> method, which is
+implied). You can also append a callback to perform requests non-blocking.
 
   $ua->put('http://example.com' => sub {
     my ($ua, $tx) = @_;
@@ -828,7 +831,8 @@ non-blocking.
 Open a non-blocking WebSocket connection with transparent handshake, takes the
 same arguments as L<Mojo::UserAgent::Transactor/"websocket">. The callback
 will receive either a L<Mojo::Transaction::WebSocket> or
-L<Mojo::Transaction::HTTP> object.
+L<Mojo::Transaction::HTTP> object, depending on if the handshake was
+successful.
 
   $ua->websocket('ws://example.com/echo' => sub {
     my ($ua, $tx) = @_;
@@ -11,6 +11,7 @@ use File::Basename 'dirname';
 use File::Spec::Functions 'catfile';
 use List::Util 'min';
 use MIME::Base64 qw(decode_base64 encode_base64);
+use Symbol 'delete_package';
 use Time::HiRes ();
 
 # Check for monotonic clock support
@@ -28,6 +29,9 @@ use constant {
   PC_INITIAL_N    => 128
 };
 
+# Will be shipping with Perl 5.22
+my $NAME = eval 'use Sub::Util; 1' ? \&Sub::Util::set_subname : sub { $_[1] };
+
 # To update HTML entities run this command
 # perl examples/entities.pl > lib/Mojo/entities.txt
 my %ENTITIES;
@@ -66,7 +70,7 @@ sub camelize {
 
   # CamelCase words
   return join '::', map {
-    join '', map { ucfirst lc } split '_', $_
+    join('', map { ucfirst lc } split '_')
   } split '-', $str;
 }
 
@@ -83,17 +87,10 @@ sub decamelize {
   my $str = shift;
   return $str if $str !~ /^[A-Z]/;
 
-  # Module parts
-  my @parts;
-  for my $part (split '::', $str) {
-
-    # snake_case words
-    my @words;
-    push @words, lc $1 while $part =~ s/([A-Z]{1}[^A-Z]*)//;
-    push @parts, join '_', @words;
-  }
-
-  return join '-', @parts;
+  # snake_case words
+  return join '-', map {
+    join('_', map {lc} grep {length} split /([A-Z]{1}[^A-Z]*)/)
+  } split '::', $str;
 }
 
 sub decode {
@@ -129,7 +126,7 @@ sub monkey_patch {
   my ($class, %patch) = @_;
   no strict 'refs';
   no warnings 'redefine';
-  *{"${class}::$_"} = $patch{$_} for keys %patch;
+  *{"${class}::$_"} = $NAME->("${class}::$_", $patch{$_}) for keys %patch;
 }
 
 # Direct translation of RFC 3492
@@ -295,7 +292,7 @@ sub tablify {
     for my $i (0 .. $#$row) {
       $row->[$i] =~ s/[\r\n]//g;
       my $len = length $row->[$i];
-      $spec[$i] = $len if $len > ($spec[$i] // 0);
+      $spec[$i] = $len if $len >= ($spec[$i] // 0);
     }
   }
 
@@ -327,8 +324,8 @@ sub unquote {
 
 sub url_escape {
   my ($str, $pattern) = @_;
-  $pattern ||= '^A-Za-z0-9\-._~';
-  $str =~ s/([$pattern])/sprintf('%%%02X',ord($1))/ge;
+  if ($pattern) { $str =~ s/([$pattern])/sprintf('%%%02X',ord($1))/ge }
+  else          { $str =~ s/([^A-Za-z0-9\-._~])/sprintf('%%%02X',ord($1))/ge }
   return $str;
 }
 
@@ -389,6 +386,44 @@ sub _encoding {
   $CACHE{$_[0]} //= find_encoding($_[0]) // croak "Unknown encoding '$_[0]'";
 }
 
+sub _options {
+
+  # Hash or name (one)
+  return ref $_[0] eq 'HASH' ? (undef, %{shift()}) : @_ if @_ == 1;
+
+  # Name and values (odd)
+  return shift, @_ if @_ % 2;
+
+  # Name and hash or just values (even)
+  return ref $_[1] eq 'HASH' ? (shift, %{shift()}) : (undef, @_);
+}
+
+sub _stash {
+  my ($name, $object) = (shift, shift);
+
+  # Hash
+  my $dict = $object->{$name} ||= {};
+  return $dict unless @_;
+
+  # Get
+  return $dict->{$_[0]} unless @_ > 1 || ref $_[0];
+
+  # Set
+  my $values = ref $_[0] ? $_[0] : {@_};
+  @$dict{keys %$values} = values %$values;
+
+  return $object;
+}
+
+sub _teardown {
+  return unless my $class = shift;
+
+  # @ISA has to be cleared first because of circular references
+  no strict 'refs';
+  @{"${class}::ISA"} = ();
+  delete_package $class;
+}
+
 1;
 
 =encoding utf8
@@ -625,8 +660,9 @@ consecutive groups of whitespace into one space each.
 
   my $time = steady_time;
 
-High resolution time, resilient to time jumps if a monotonic clock is
-available through L<Time::HiRes>.
+High resolution time elapsed from an arbitrary fixed point in the past,
+resilient to time jumps if a monotonic clock is available through
+L<Time::HiRes>.
 
 =head2 tablify
 
@@ -8,22 +8,20 @@ use Mojo::Home;
 use Mojo::Log;
 use Mojo::Transaction::HTTP;
 use Mojo::UserAgent;
+use Mojo::Util;
 use Scalar::Util 'weaken';
 
 has home => sub { Mojo::Home->new };
 has log  => sub { Mojo::Log->new };
 has ua   => sub {
-  my $self = shift;
-
   my $ua = Mojo::UserAgent->new;
-  weaken $ua->server->app($self)->{app};
-  weaken $self;
-  return $ua->catch(sub { $self->log->error($_[1]) });
+  weaken $ua->server->app(shift)->{app};
+  return $ua;
 };
 
 sub build_tx { Mojo::Transaction::HTTP->new }
 
-sub config { shift->_dict(config => @_) }
+sub config { Mojo::Util::_stash(config => @_) }
 
 sub handler { croak 'Method "handler" not implemented in subclass' }
 
@@ -39,22 +37,6 @@ sub new {
   return $self;
 }
 
-sub _dict {
-  my ($self, $name) = (shift, shift);
-
-  # Hash
-  my $dict = $self->{$name} ||= {};
-  return $dict unless @_;
-
-  # Get
-  return $dict->{$_[0]} unless @_ > 1 || ref $_[0];
-
-  # Set
-  %$dict = (%$dict, %{ref $_[0] ? $_[0] : {@_}});
-
-  return $self;
-}
-
 1;
 
 =encoding utf8
@@ -9,9 +9,8 @@ has usage => sub { shift->extract_usage };
 
 sub run {
   my ($self, @args) = @_;
-  my $cgi = Mojo::Server::CGI->new(app => $self->app);
-  GetOptionsFromArray \@args, nph => sub { $cgi->nph(1) };
-  $cgi->run;
+  GetOptionsFromArray \@args, nph => \(my $nph = 0);
+  Mojo::Server::CGI->new(app => $self->app, nph => $nph)->run;
 }
 
 1;
@@ -39,6 +39,7 @@ Mojolicious::Command::daemon - Daemon command
 
     ./myapp.pl daemon -m production -l http://*:8080
     ./myapp.pl daemon -l http://127.0.0.1:8080 -l https://[::]:8081
+    ./myapp.pl daemon -l 'https://*:443?cert=./server.crt&key=./server.key'
 
   Options:
     -b, --backlog <size>         Listen backlog size, defaults to SOMAXCONN.
@@ -19,14 +19,14 @@ EOF
   # Script
   my $name = class_to_file $class;
   $self->render_to_rel_file('mojo', "$name/script/$name", $class);
-  $self->chmod_file("$name/script/$name", 0744);
+  $self->chmod_rel_file("$name/script/$name", 0744);
 
   # Application class
   my $app = class_to_path $class;
   $self->render_to_rel_file('appclass', "$name/lib/$app", $class);
 
   # Controller
-  my $controller = "${class}::Example";
+  my $controller = "${class}::Controller::Example";
   my $path       = class_to_path $controller;
   $self->render_to_rel_file('controller', "$name/lib/$path", $controller);
 
@@ -8,7 +8,7 @@ sub run {
   my ($self, $name) = @_;
   $name ||= 'myapp.pl';
   $self->render_to_rel_file('liteapp', $name);
-  $self->chmod_file($name, 0744);
+  $self->chmod_rel_file($name, 0744);
 }
 
 1;
@@ -29,8 +29,7 @@ sub run {
   my $selector = shift @args;
 
   # Parse header pairs
-  my %headers;
-  /^\s*([^:]+)\s*:\s*(.+)$/ and $headers{$1} = $2 for @headers;
+  my %headers = map { /^\s*([^:]+)\s*:\s*(.+)$/ ? ($1, $2) : () } @headers;
 
   # Detect proxy for absolute URLs
   my $ua = Mojo::UserAgent->new(ioloop => Mojo::IOLoop->singleton);
@@ -66,14 +65,12 @@ sub run {
   STDOUT->autoflush(1);
   my $tx = $ua->start($ua->build_tx($method, $url, \%headers, $content));
   my $err = $tx->error;
-  $url = encode 'UTF-8', $url;
-  warn qq{Problem loading URL "$url". ($err->{message})\n}
+  warn qq{Problem loading URL "@{[$tx->req->url]}". ($err->{message})\n}
     if $err && !$err->{code};
 
   # JSON Pointer
   return unless defined $selector;
-  my $type = $tx->res->headers->content_type // '';
-  return _json($buffer, $selector) if $type =~ /json/i;
+  return _json($buffer, $selector) if $selector eq '' || $selector =~ m!^/!;
 
   # Selector
   _select($buffer, $selector, $charset // $tx->res->content->charset, @args);
@@ -132,7 +129,7 @@ Mojolicious::Command::get - Get command
     ./myapp.pl get /
     mojo get mojolicio.us
     mojo get -v -r google.com
-    mojo get -v -H 'Host: mojolicious.org' -H 'DNT: 1' mojolicio.us
+    mojo get -v -H 'Host: mojolicious.org' -H 'Accept: */*' mojolicio.us
     mojo get -M POST -c 'trololo' mojolicio.us
     mojo get mojolicio.us 'head > title' text
     mojo get mojolicio.us .footer all
@@ -50,6 +50,7 @@ Mojolicious::Command::prefork - Prefork command
 
     ./myapp.pl prefork -m production -l http://*:8080
     ./myapp.pl prefork -l http://127.0.0.1:8080 -l https://[::]:8081
+    ./myapp.pl prefork -l 'https://*:443?cert=./server.crt&key=./server.key'
 
   Options:
     -A, --accepts <number>               Number of connections for workers to
@@ -28,9 +28,9 @@ sub _walk {
 
   # Flags
   my @flags;
-  push @flags, $route->inline ? 'B' : '.';
   push @flags, @{$route->over || []} ? 'C' : '.';
   push @flags, (my $partial = $route->partial) ? 'D' : '.';
+  push @flags, $route->inline       ? 'U' : '.';
   push @flags, $route->is_websocket ? 'W' : '.';
   push @$row, join('', @flags) if $verbose;
 
@@ -44,13 +44,10 @@ sub _walk {
 
   # Regex (verbose)
   my $pattern = $route->pattern;
-  $pattern->match('/', $route->is_endpoint);
-  my $regex = (regexp_pattern $pattern->regex)[0];
-  my $format = (regexp_pattern($pattern->format_regex || ''))[0];
-  my $optional
-    = !$pattern->constraints->{format} || $pattern->defaults->{format};
-  $regex .= $optional ? "(?:$format)?" : $format if $format && !$partial;
-  push @$row, $regex if $verbose;
+  $pattern->match('/', $route->is_endpoint && !$partial);
+  my $regex  = (regexp_pattern $pattern->regex)[0];
+  my $format = (regexp_pattern($pattern->format_regex))[0];
+  push @$row, $regex, $format ? $format : '' if $verbose;
 
   $depth++;
   _walk($_, $depth, $rows, $verbose) for @{$route->children};
@@ -71,7 +68,7 @@ Mojolicious::Command::routes - Routes command
 
   Options:
     -v, --verbose   Print additional details about routes, flags indicate
-                    B=Bridge, C=Conditions, D=Detour and W=WebSocket.
+                    C=Conditions, D=Detour, U=Under and W=WebSocket.
 
 =head1 DESCRIPTION
 
@@ -1,11 +1,7 @@
 package Mojolicious::Command::test;
 use Mojo::Base 'Mojolicious::Command';
 
-use Cwd 'realpath';
-use FindBin;
-use File::Spec::Functions qw(abs2rel catdir splitdir);
 use Getopt::Long qw(GetOptionsFromArray :config no_auto_abbrev no_ignore_case);
-use Mojo::Home;
 
 has description => 'Run tests.';
 has usage => sub { shift->extract_usage };
@@ -13,21 +9,13 @@ has usage => sub { shift->extract_usage };
 sub run {
   my ($self, @args) = @_;
 
-  GetOptionsFromArray \@args, 'v|verbose' => sub { $ENV{HARNESS_VERBOSE} = 1 };
+  GetOptionsFromArray \@args, 'v|verbose' => \$ENV{HARNESS_VERBOSE};
 
-  unless (@args) {
-    my @base = splitdir(abs2rel $FindBin::Bin);
-
-    # "./t"
-    my $path = catdir @base, 't';
-
-    # "../t"
-    $path = catdir @base, '..', 't' unless -d $path;
-    die "Can't find test directory.\n" unless -d $path;
-
-    my $home = Mojo::Home->new($path);
-    /\.t$/ and push @args, $home->rel_file($_) for @{$home->list_files};
-    say "Running tests from '", realpath($path), "'.";
+  if (!@args && (my $home = $self->app->home)) {
+    die "Can't find test directory.\n" unless -d $home->rel_dir('t');
+    my $files = $home->list_files('t');
+    /\.t$/ and push @args, $home->rel_file("t/$_") for @$files;
+    say qq{Running tests from "}, $home->rel_dir('t') . '".';
   }
 
   $ENV{HARNESS_OPTIONS} //= 'c';
@@ -1,7 +1,7 @@
 package Mojolicious::Command::version;
 use Mojo::Base 'Mojolicious::Command';
 
-use Mojo::IOLoop::Server;
+use Mojo::IOLoop::Client;
 use Mojo::UserAgent;
 use Mojolicious;
 
@@ -11,11 +11,11 @@ has usage => sub { shift->extract_usage };
 sub run {
   my $self = shift;
 
-  my $ev = eval 'use Mojo::Reactor::EV; 1' ? $EV::VERSION : 'not installed';
-  my $ipv6
-    = Mojo::IOLoop::Server::IPV6 ? $IO::Socket::IP::VERSION : 'not installed';
-  my $tls
-    = Mojo::IOLoop::Server::TLS ? $IO::Socket::SSL::VERSION : 'not installed';
+  my $ev    = eval 'use Mojo::Reactor::EV; 1' ? $EV::VERSION : 'not installed';
+  my $class = 'Mojo::IOLoop::Client';
+  my $ipv6  = $class->IPV6 ? $IO::Socket::IP::VERSION : 'not installed';
+  my $socks = $class->SOCKS ? $IO::Socket::Socks::VERSION : 'not installed';
+  my $tls   = $class->TLS ? $IO::Socket::SSL::VERSION : 'not installed';
 
   print <<EOF;
 CORE
@@ -23,20 +23,19 @@ CORE
   Mojolicious ($Mojolicious::VERSION, $Mojolicious::CODENAME)
 
 OPTIONAL
-  EV 4.0+               ($ev)
-  IO::Socket::IP 0.20+  ($ipv6)
-  IO::Socket::SSL 1.84+ ($tls)
+  EV 4.0+                 ($ev)
+  IO::Socket::IP 0.20+    ($ipv6)
+  IO::Socket::Socks 0.64+ ($socks)
+  IO::Socket::SSL 1.84+   ($tls)
 
 EOF
 
   # Check latest version on CPAN
   my $latest = eval {
-    my $ua = Mojo::UserAgent->new(max_redirects => 10);
-    $ua->proxy->detect;
-    $ua->get('api.metacpan.org/v0/release/Mojolicious')->res->json->{version};
-  };
+    Mojo::UserAgent->new(max_redirects => 10)->tap(sub { $_->proxy->detect })
+      ->get('api.metacpan.org/v0/release/Mojolicious')->res->json->{version};
+  } or return;
 
-  return unless $latest;
   my $msg = 'This version is up to date, have fun!';
   $msg = 'Thanks for testing a development release, you are awesome!'
     if $latest < $Mojolicious::VERSION;
@@ -14,14 +14,13 @@ use Pod::Usage 'pod2usage';
 
 has app => sub { Mojo::Server->new->build_app('Mojo::HelloWorld') };
 has description => 'No description.';
-has quiet       => 0;
-has usage       => "Usage: APPLICATION\n";
+has 'quiet';
+has usage => "Usage: APPLICATION\n";
 
 sub chmod_file {
   my ($self, $path, $mod) = @_;
   chmod $mod, $path or croak qq{Can't chmod file "$path": $!};
-  $mod = sprintf '%lo', $mod;
-  say "  [chmod] $path $mod" unless $self->quiet;
+  say "  [chmod] $path " . sprintf('%lo', $mod) unless $self->quiet;
   return $self;
 }
 
@@ -1,7 +1,7 @@
 package Mojolicious::Commands;
 use Mojo::Base 'Mojolicious::Command';
 
-use Getopt::Long 'GetOptions';
+use Getopt::Long 'GetOptionsFromArray';
 use Mojo::Server;
 use Mojo::Util 'tablify';
 
@@ -26,16 +26,18 @@ sub detect {
 }
 
 # Command line options for MOJO_HELP, MOJO_HOME and MOJO_MODE
-BEGIN {
+sub _args {
+  return if __PACKAGE__->detect;
   Getopt::Long::Configure(qw(no_auto_abbrev no_ignore_case pass_through));
-  GetOptions(
-    'h|help'   => sub { $ENV{MOJO_HELP} = 1 },
-    'home=s'   => sub { $ENV{MOJO_HOME} = $_[1] },
-    'm|mode=s' => sub { $ENV{MOJO_MODE} = $_[1] }
-  ) unless __PACKAGE__->detect;
+  GetOptionsFromArray shift,
+    'h|help'   => \$ENV{MOJO_HELP},
+    'home=s'   => \$ENV{MOJO_HOME},
+    'm|mode=s' => \$ENV{MOJO_MODE};
   Getopt::Long::Configure('default');
 }
 
+BEGIN { _args([@ARGV]) }
+
 sub run {
   my ($self, $name, @args) = @_;
 
@@ -59,7 +61,8 @@ sub run {
     die qq{Unknown command "$name", maybe you need to install it?\n}
       unless $module;
 
-    # Run command
+    # Run command (remove options shared by all commands)
+    _args(\@args);
     my $command = $module->new(app => $self->app);
     return $help ? $command->help(@args) : $command->run(@args);
   }
@@ -83,10 +86,7 @@ sub run {
   return print $self->message, tablify(\@rows), $self->hint;
 }
 
-sub start_app {
-  my $self = shift;
-  return Mojo::Server->new->build_app(shift)->start(@_);
-}
+sub start_app { shift; Mojo::Server->new->build_app(shift)->start(@_) }
 
 sub _command {
   my ($module, $fatal) = @_;
@@ -313,7 +313,7 @@ disabled with the C<MOJO_NO_DETECT> environment variable.
   Mojolicious::Commands->start_app('MyApp');
   Mojolicious::Commands->start_app(MyApp => @ARGV);
 
-Load application and start the command line interface for it.
+Load application from class and start the command line interface for it.
 
   # Always start daemon for application and ignore @ARGV
   Mojolicious::Commands->start_app('MyApp', 'daemon', '-l', 'http://*:8080');
@@ -4,7 +4,6 @@ use Mojo::Base -base;
 # No imports, for security reasons!
 use Carp ();
 use Mojo::ByteStream;
-use Mojo::Exception;
 use Mojo::Transaction::HTTP;
 use Mojo::URL;
 use Mojo::Util;
@@ -27,13 +26,13 @@ my %RESERVED = map { $_ => 1 } (
 sub AUTOLOAD {
   my $self = shift;
 
-  my ($package, $method) = split /::(\w+)$/, our $AUTOLOAD;
+  my ($package, $method) = our $AUTOLOAD =~ /^(.+)::(.+)$/;
   Carp::croak "Undefined subroutine &${package}::$method called"
     unless Scalar::Util::blessed $self && $self->isa(__PACKAGE__);
 
   # Call helper with current controller
   Carp::croak qq{Can't locate object method "$method" via package "$package"}
-    unless my $helper = $self->app->renderer->helpers->{$method};
+    unless my $helper = $self->app->renderer->get_helper($method);
   return $self->$helper(@_);
 }
 
@@ -87,12 +86,14 @@ sub flash {
     if @_ == 1 && !ref $_[0];
 
   # Initialize new flash and merge values
-  my $flash = $session->{new_flash} ||= {};
-  %$flash = (%$flash, %{@_ > 1 ? {@_} : $_[0]});
+  my $values = ref $_[0] ? $_[0] : {@_};
+  @{$session->{new_flash} ||= {}}{keys %$values} = values %$values;
 
   return $self;
 }
 
+sub helpers { $_[0]->app->renderer->get_helper('')->($_[0]) }
+
 sub on {
   my ($self, $name, $cb) = @_;
   my $tx = $self->tx;
@@ -170,20 +171,19 @@ sub render {
   return !!$self->rendered($self->stash->{status});
 }
 
-sub render_exception { _development('exception', @_) }
+sub render_exception { shift->helpers->reply->exception(@_) }
 
 sub render_later { shift->stash('mojo.rendered' => 1) }
 
 sub render_maybe { shift->render(@_, 'mojo.maybe' => 1) }
 
-sub render_not_found { _development('not_found', @_) }
+sub render_not_found { shift->helpers->reply->not_found }
 
+# DEPRECATED in Tiger Face!
 sub render_static {
-  my ($self, $file) = @_;
-  my $app = $self->app;
-  return !!$self->rendered if $app->static->serve($self, $file);
-  $app->log->debug(qq{File "$file" not found, public directory missing?});
-  return !$self->render_not_found;
+  Mojo::Util::deprecated 'Mojolicious::Controller::render_static is DEPRECATED'
+    . ' in favor of the reply->static helper';
+  shift->helpers->reply->static(@_);
 }
 
 sub render_to_string { shift->render(@_, 'mojo.to_string' => 1) }
@@ -266,7 +266,8 @@ sub session {
   return $session->{$_[0]} unless @_ > 1 || ref $_[0];
 
   # Set
-  %$session = (%$session, %{ref $_[0] ? $_[0] : {@_}});
+  my $values = ref $_[0] ? $_[0] : {@_};
+  @$session{keys %$values} = values %$values;
 
   return $self;
 }
@@ -311,7 +312,7 @@ sub signed_cookie {
   return wantarray ? @results : $results[0];
 }
 
-sub stash { shift->Mojolicious::_dict(stash => @_) }
+sub stash { Mojo::Util::_stash(stash => @_) }
 
 sub url_for {
   my $self = shift;
@@ -383,50 +384,6 @@ sub write_chunk {
   return $self->rendered;
 }
 
-sub _development {
-  my ($page, $self, $e) = @_;
-
-  my $app = $self->app;
-  $app->log->error($e = Mojo::Exception->new($e)) if $page eq 'exception';
-
-  # Filtered stash snapshot
-  my $stash = $self->stash;
-  my %snapshot = map { $_ => $stash->{$_} }
-    grep { !/^mojo\./ and defined $stash->{$_} } keys %$stash;
-
-  # Render with fallbacks
-  my $mode     = $app->mode;
-  my $renderer = $app->renderer;
-  my $options  = {
-    exception => $page eq 'exception' ? $e : undef,
-    format => $stash->{format} || $renderer->default_format,
-    handler  => undef,
-    snapshot => \%snapshot,
-    status   => $page eq 'exception' ? 500 : 404,
-    template => "$page.$mode"
-  };
-  my $inline = $renderer->_bundled($mode eq 'development' ? $mode : $page);
-  return $self if _fallbacks($self, $options, $page, $inline);
-  _fallbacks($self, {%$options, format => 'html'}, $page, $inline);
-  return $self;
-}
-
-sub _fallbacks {
-  my ($self, $options, $template, $inline) = @_;
-
-  # Mode specific template
-  return 1 if $self->render_maybe(%$options);
-
-  # Normal template
-  return 1 if $self->render_maybe(%$options, template => $template);
-
-  # Inline template
-  my $stash = $self->stash;
-  return undef unless $stash->{format} eq 'html';
-  delete @$stash{qw(extends layout)};
-  return $self->render_maybe(%$options, inline => $inline, handler => 'ep');
-}
-
 1;
 
 =encoding utf8
@@ -438,7 +395,7 @@ Mojolicious::Controller - Controller base class
 =head1 SYNOPSIS
 
   # Controller
-  package MyApp::Foo;
+  package MyApp::Controller::Foo;
   use Mojo::Base 'Mojolicious::Controller';
 
   # Action
@@ -483,8 +440,8 @@ Router results for the current request, defaults to a
 L<Mojolicious::Routes::Match> object.
 
   # Introspect
-  my $foo = $c->match->endpoint->pattern->defaults->{foo};
-  my $bar = $c->match->stack->[-1]{bar};
+  my $controller = $c->match->endpoint->pattern->defaults->{controller};
+  my $action     = $c->match->stack->[-1]{action};
 
 =head2 tx
 
@@ -553,6 +510,17 @@ L</"session">.
   $c->flash(message => 'User created successfully!');
   $c->redirect_to('show_user', id => 23);
 
+=head2 helpers
+
+  my $helpers = $c->helpers;
+
+Return a proxy object containing the current controller object and on which
+helpers provided by L</"app"> can be called. This includes all helpers from
+L<Mojolicious::Plugin::DefaultHelpers> and L<Mojolicious::Plugin::TagHelpers>.
+
+  # Make sure to use the "title" helper and not the controller method
+  $c->helpers->title('Welcome!');
+
 =head2 on
 
   my $cb = $c->on(finish => sub {...});
@@ -598,12 +566,14 @@ status.
   $c              = $c->param(foo => ['ba;r', 'baz']);
 
 Access route placeholder values that are not reserved stash values, file
-uploads and C<GET>/C<POST> parameters, in that order. Note that this method is
-context sensitive in some cases and therefore needs to be used with care,
-there can always be multiple values, which might have unexpected consequences.
-Parts of the request body need to be loaded into memory to parse C<POST>
-parameters, so you have to make sure it is not excessively large, there's a
-10MB limit by default.
+uploads as well as C<GET> and C<POST> parameters extracted from the query
+string and C<application/x-www-form-urlencoded> or C<multipart/form-data>
+message body, in that order. Note that this method is context sensitive in
+some cases and therefore needs to be used with care, there can always be
+multiple values, which might have unexpected consequences. Parts of the
+request body need to be loaded into memory to parse C<POST> parameters, so you
+have to make sure it is not excessively large, there's a 10MB limit by
+default.
 
   # List context is ambiguous and should be avoided, you can get multiple
   # values returned for a query string like "?foo=bar&foo=baz&foo=yada"
@@ -612,7 +582,7 @@ parameters, so you have to make sure it is not excessively large, there's a
   # Better enforce scalar context
   my $hash = {foo => scalar $c->param('foo')};
 
-  # The multi-name form can also be used to enforce scalar context
+  # The multi-name form can also be used to enforce a list with one element
   my $hash = {foo => $c->param(['foo'])};
 
 For more control you can also access request information directly.
@@ -654,7 +624,7 @@ Prepare a C<302> redirect response, takes the same arguments as L</"url_for">.
   my $bool = $c->render(handler => 'something');
   my $bool = $c->render('foo/index');
 
-Render content using L<Mojolicious::Renderer/"render"> and emit hooks
+Render content with L<Mojolicious::Renderer/"render"> and emit hooks
 L<Mojolicious/"before_render"> as well as L<Mojolicious/"after_render">. If no
 template is provided a default one based on controller and action or route
 name will be generated with L<Mojolicious::Renderer/"template_for">, all
@@ -684,10 +654,7 @@ additional pairs get merged into the L</"stash">.
   $c = $c->render_exception('Oops!');
   $c = $c->render_exception(Mojo::Exception->new('Oops!'));
 
-Render the exception template C<exception.$mode.$format.*> or
-C<exception.$format.*> and set the response status code to C<500>. Also sets
-the stash values C<exception> to a L<Mojo::Exception> object and C<snapshot>
-to a copy of the L</"stash"> for use in the templates.
+Alias for L<Mojolicious::Plugin::DefaultHelpers/"reply-E<gt>exception">.
 
 =head2 render_later
 
@@ -708,7 +675,8 @@ automatic rendering would result in a response.
   my $bool = $c->render_maybe(controller => 'foo', action => 'bar');
   my $bool = $c->render_maybe('foo/index', format => 'html');
 
-Try to render content, but do not call L</"render_not_found"> if no response
+Try to render content, but do not call
+L<Mojolicious::Plugin::DefaultHelpers/"reply-E<gt>not_found"> if no response
 could be generated, takes the same arguments as L</"render">.
 
   # Render template "index_local" only if it exists
@@ -718,19 +686,7 @@ could be generated, takes the same arguments as L</"render">.
 
   $c = $c->render_not_found;
 
-Render the not found template C<not_found.$mode.$format.*> or
-C<not_found.$format.*> and set the response status code to C<404>. Also sets
-the stash value C<snapshot> to a copy of the L</"stash"> for use in the
-templates.
-
-=head2 render_static
-
-  my $bool = $c->render_static('images/logo.png');
-  my $bool = $c->render_static('../lib/MyApp.pm');
-
-Render a static file using L<Mojolicious::Static/"serve">, usually from the
-C<public> directories or C<DATA> sections of your application. Note that this
-method does not protect from traversing to parent directories.
+Alias for L<Mojolicious::Plugin::DefaultHelpers/"reply-E<gt>not_found">.
 
 =head2 render_to_string
 
@@ -761,7 +717,7 @@ using a C<200> response code.
 
   my $req = $c->req;
 
-Get L<Mojo::Message::Request> object from L<Mojo::Transaction/"req">.
+Get L<Mojo::Message::Request> object from L</"tx">.
 
   # Longer version
   my $req = $c->tx->req;
@@ -783,7 +739,7 @@ Get L<Mojo::Message::Request> object from L<Mojo::Transaction/"req">.
 
   my $res = $c->res;
 
-Get L<Mojo::Message::Response> object from L<Mojo::Transaction/"res">.
+Get L<Mojo::Message::Response> object from L</"tx">.
 
   # Longer version
   my $res = $c->tx->res;
@@ -945,9 +901,11 @@ to inherit query parameters from the current request.
   my $validation = $c->validation;
 
 Get L<Mojolicious::Validator::Validation> object for current request to
-validate C<GET>/C<POST> parameters. Parts of the request body need to be
-loaded into memory to parse C<POST> parameters, so you have to make sure it is
-not excessively large, there's a 10MB limit by default.
+validate C<GET> and C<POST> parameters extracted from the query string and
+C<application/x-www-form-urlencoded> or C<multipart/form-data> message body.
+Parts of the request body need to be loaded into memory to parse C<POST>
+parameters, so you have to make sure it is not excessively large, there's a
+10MB limit by default.
 
   my $validation = $c->validation;
   $validation->required('title')->size(3, 50);
@@ -108,9 +108,9 @@ environments out of the box.
   $ hypnotoad script/myapp
   Server available at http://127.0.0.1:8080.
 
-You can tweak many configuration settings right from within your application
-with L<Mojo/"config">, for a full list see
-L<Mojo::Server::Hypnotoad/"SETTINGS">.
+It automatically sets the operating mode to C<production> and you can tweak
+many configuration settings right from within your application with
+L<Mojo/"config">, for a full list see L<Mojo::Server::Hypnotoad/"SETTINGS">.
 
   use Mojolicious::Lite;
 
@@ -238,8 +238,8 @@ C<X-Forwarded-For> and C<X-Forwarded-Proto> headers.
 
   $ MOJO_REVERSE_PROXY=1 plackup ./script/myapp
 
-If an older server adapter is not be able to correctly detect the application
-home directory, you can simply use the C<MOJO_HOME> environment variable.
+If an older server adapter is unable to correctly detect the application home
+directory, you can simply use the C<MOJO_HOME> environment variable.
 
   $ MOJO_HOME=/home/sri/myapp plackup ./script/myapp
 
@@ -257,7 +257,22 @@ application logic.
 
   builder {
     enable 'Deflater';
-    require 'myapp.pl';
+    require './script/myapp';
+  };
+
+L<Mojo::Server::PSGI> can be used directly to load and customize applications
+in the wrapper script.
+
+  #!/usr/bin/env plackup -s FCGI
+  use Mojo::Server::PSGI;
+  use Plack::Builder;
+
+  builder {
+    enable 'Deflater';
+    my $server = Mojo::Server::PSGI->new;
+    $server->load_app('./script/myapp');
+    $server->app->config(foo => 'bar');
+    $server->to_psgi_app;
   };
 
 But you could even use middleware right in your application.
@@ -284,7 +299,7 @@ you can use the hook L<Mojolicious/"before_dispatch"> to rewrite incoming
 requests.
 
   # Change scheme if "X-Forwarded-HTTPS" header is set
-  app->hook(before_dispatch => sub {
+  $app->hook(before_dispatch => sub {
     my $c = shift;
     $c->req->url->base->scheme('https')
       if $c->req->headers->header('X-Forwarded-HTTPS');
@@ -295,11 +310,11 @@ prefixes your application might be deployed under, rewriting the base path of
 incoming requests is also quite common.
 
   # Move first part and slash from path to base path in production mode
-  app->hook(before_dispatch => sub {
+  $app->hook(before_dispatch => sub {
     my $c = shift;
     push @{$c->req->url->base->path->trailing_slash(1)},
       shift @{$c->req->url->path->leading_slash(0)};
-  }) if app->mode eq 'production';
+  }) if $app->mode eq 'production';
 
 L<Mojo::URL> objects are very easy to manipulate, just make sure that the URL
 (C<foo/bar?baz=yada>), which represents the routing destination, is always
@@ -404,7 +419,7 @@ style.
   use Mojolicious::Lite;
   use Mojo::URL;
 
-  # Search MetaCPAN for "mojo" and "mango"
+  # Search MetaCPAN for "mojo" and "minion"
   get '/' => sub {
     my $c = shift;
 
@@ -416,16 +431,16 @@ style.
         my $delay = shift;
         my $url   = Mojo::URL->new('api.metacpan.org/v0/module/_search');
         $url->query({sort => 'date:desc'});
-        $c->ua->get($url->clone->query({q => 'mojo'})  => $delay->begin);
-        $c->ua->get($url->clone->query({q => 'mango'}) => $delay->begin);
+        $c->ua->get($url->clone->query({q => 'mojo'})   => $delay->begin);
+        $c->ua->get($url->clone->query({q => 'minion'}) => $delay->begin);
       },
 
       # Delayed rendering
       sub {
-        my ($delay, $mojo, $mango) = @_;
+        my ($delay, $mojo, $minion) = @_;
         $c->render(json => {
-          mojo  => $mojo->res->json('/hits/hits/0/_source/release'),
-          mango => $mango->res->json('/hits/hits/0/_source/release')
+          mojo   => $mojo->res->json('/hits/hits/0/_source/release'),
+          minion => $minion->res->json('/hits/hits/0/_source/release')
         });
       }
     );
@@ -500,9 +515,19 @@ created at startup time.
 
   app->start;
 
-Since timers and other low-level event watchers are also independent from
-applications, errors can't get logged automatically, you can change that by
-subscribing to the event L<Mojo::Reactor/"error">.
+Just remember that all events are processed cooperatively, so your callbacks
+shouldn't block for too long.
+
+=head2 Exceptions in events
+
+Since timers and other non-blocking operations are running solely in the event
+loop, outside of the application, exceptions that get thrown in callbacks
+can't get caught and handled automatically. But you can handle them manually
+by subscribing to the event L<Mojo::Reactor/"error"> or catching them inside
+the callback.
+
+  use Mojolicious::Lite;
+  use Mojo::IOLoop;
 
   # Forward error messages to the application log
   Mojo::IOLoop->singleton->reactor->on(error => sub {
@@ -510,8 +535,33 @@ subscribing to the event L<Mojo::Reactor/"error">.
     app->log->error($err);
   });
 
-Just remember that all events are processed cooperatively, so your callbacks
-shouldn't block for too long.
+  # Exception only gets logged (and connection times out)
+  get '/connection_times_out' => sub {
+    my $c = shift;
+    Mojo::IOLoop->timer(2 => sub {
+      die 'This request will not be getting a response';
+    });
+  };
+
+  # Exception gets caught and handled
+  get '/catch_exception' => sub {
+    my $c = shift;
+    Mojo::IOLoop->timer(2 => sub {
+      eval { die 'This request will be getting a response' };
+      $c->reply->exception($@) if $@;
+    });
+  };
+
+  app->start;
+
+A default subscriber that turns all errors into warnings will usually be added
+by L<Mojo::IOLoop> as a fallback.
+
+  Mojo::IOLoop->singleton->reactor->unsubscribe('error');
+
+During development or for applications where crashing is simply preferable,
+you can also make every exception that gets thrown in a callback fatal by
+removing all of its subscribers.
 
 =head2 WebSocket web service
 
@@ -566,9 +616,7 @@ L<Mojolicious::Controller/"send">.
         };
 
         // Outgoing messages
-        window.setInterval(function() {
-          ws.send('Hello Mojo!');
-        }, 1000);
+        window.setInterval(function () { ws.send('Hello Mojo!') }, 1000);
       </script>
     </body>
   </html>
@@ -899,7 +947,7 @@ content repeatedly for multiple requests.
 
   # Send multiple files streaming via PUT and POST
   $ua->put('http://example.com/upload'  => stream => '/home/sri/mojo.png');
-  $ua->post('http://example.com/upload' => stream => '/home/sri/mango.png');
+  $ua->post('http://example.com/upload' => stream => '/home/sri/minion.png');
 
 The C<json> and C<form> content generators are always available.
 
@@ -1031,8 +1079,8 @@ can keep many concurrent connections active at the same time.
     my ($ua, $mojo) = @_;
     ...
   });
-  $ua->get('http://metacpan.org/search?q=mango' => sub {
-    my ($ua, $mango) = @_;
+  $ua->get('http://metacpan.org/search?q=minion' => sub {
+    my ($ua, $minion) = @_;
     ...
   });
 
@@ -1052,11 +1100,11 @@ synchronize multiple non-blocking requests.
   # Synchronize non-blocking requests
   my $ua    = Mojo::UserAgent->new;
   my $delay = Mojo::IOLoop->delay(sub {
-    my ($delay, $mojo, $mango) = @_;
+    my ($delay, $mojo, $minion) = @_;
     ...
   });
-  $ua->get('http://metacpan.org/search?q=mojo'  => $delay->begin);
-  $ua->get('http://metacpan.org/search?q=mango' => $delay->begin);
+  $ua->get('http://metacpan.org/search?q=mojo'   => $delay->begin);
+  $ua->get('http://metacpan.org/search?q=minion' => $delay->begin);
   $delay->wait;
 
 The call to L<Mojo::IOLoop::Delay/"wait"> makes this code portable, it can now
@@ -1178,7 +1226,7 @@ C<Authorization> header.
 
 This can be combined with TLS for a secure authentication mechanism.
 
-  $ ./myapp.pl daemon -l https://*:3000?cert=./server.crt&key=./server.key
+  $ ./myapp.pl daemon -l 'https://*:3000?cert=./server.crt&key=./server.key'
 
 =head2 Adding a configuration file
 
@@ -1218,6 +1266,52 @@ the helper L<Mojolicious::Plugin::DefaultHelpers/"config">
 Alternatively you can also use configuration files in the JSON format with
 L<Mojolicious::Plugin::JSONConfig>.
 
+=head2 Adding a plugin to your application
+
+To organize your code better and to prevent helpers from cluttering your
+application, you can use application specific plugins.
+
+  $ mkdir -p lib/MyApp/Plugin
+  $ touch lib/MyApp/Plugin/MyHelpers.pm
+
+They work just like normal plugins and are also subclasses of
+L<Mojolicious::Plugin>. Nested helpers with a prefix based on the plugin name
+are an easy way to avoid conflicts.
+
+  package MyApp::Plugin::MyHelpers;
+  use Mojo::Base 'Mojolicious::Plugin';
+
+  sub register {
+    my ($self, $app) = @_;
+    $app->helper('my_helpers.render_with_header' => sub {
+      my ($c, @args) = @_;
+      $c->res->headers->header('X-Mojo' => 'I <3 Mojolicious!');
+      $c->render(@args);
+    });
+  }
+
+  1;
+
+You can have as many application specific plugins as you like, the only
+difference to normal plugins is that you load them using their full class
+name.
+
+  use Mojolicious::Lite;
+
+  use lib 'lib';
+
+  plugin 'MyApp::Plugin::MyHelpers';
+
+  get '/' => sub {
+    my $c = shift;
+    $c->my_helpers->render_with_header(text => 'I ♥ Mojolicious!');
+  };
+
+  app->start;
+
+Of course these plugins can contain more than just helpers, take a look at
+L<Mojolicious::Plugins/"PLUGINS"> for a few ideas.
+
 =head2 Adding commands to Mojolicious
 
 By now you've probably used many of the built-in commands described in
@@ -1235,6 +1329,9 @@ that they will be picked up automatically by the command line interface?
 
     # Leak secret passphrases
     say for @{$self->app->secrets} if $args[0] eq 'secrets';
+
+    # Leak mode
+    say $self->app->mode if $args[0] eq 'mode';
   }
 
   1;
@@ -1265,6 +1362,14 @@ L<Mojolicious::Commands/"namespaces">.
 
   1;
 
+Some options like C<-m> for the operating mode of your application are shared
+by all commands automatically.
+
+  $ ./myapp.pl spy -m production mode
+  production
+
+For a full list of shared options see L<Mojolicious::Commands/"SYNOPSIS">.
+
 =head2 Running code against your application
 
 Ever thought about running a quick one-liner against your L<Mojolicious>
@@ -16,7 +16,7 @@ We hope these answers are to your satisfaction.
 
 =head2 How does Mojolicious compare to other Perl web frameworks?
 
-The short answer is "it doesn't", because we interpret the words
+The short answer is "it doesn't", because we interpret the term
 "web framework" much more literally than others. With the emergence of the
 real-time web and new technologies such as WebSockets, we are facing new
 challenges that go way beyond what commonly used modules like L<LWP> were
@@ -24,8 +24,8 @@ designed for. Because of this, L<Mojolicious> contains a whole new HTTP
 client/server stack called L<Mojo>, which was heavily inspired by the original
 LWPng effort and carefully designed with these new requirements in mind. So
 while some of the higher abstraction layers might look similar to other web
-frameworks, it actually defines a whole new category and could even be the
-foundation for more advanced ones in the future.
+frameworks, it is more of a web toolkit and can even be used as the foundation
+for more advanced web frameworks.
 
 =head2 Why doesn't Mojolicious have any dependencies?
 
@@ -34,8 +34,9 @@ without compromises. While there are no rules in
 L<Mojolicious::Guides::Contributing> that forbid dependencies, we do currently
 discourage adding non-optional ones in favor of a faster and more painless
 installation process. And we do in fact already use several optional CPAN
-modules such as L<EV>, L<IO::Socket::IP>, L<IO::Socket::SSL> and L<Plack> to
-provide advanced functionality if they are installed.
+modules such as L<EV>, L<IO::Socket::IP>, L<IO::Socket::Socks>,
+L<IO::Socket::SSL> and L<Plack> to provide advanced functionality if they are
+installed.
 
 =head2 Why reinvent wheels?
 
@@ -172,11 +173,11 @@ one.
 =head2 What does "Your secret passphrase needs to be changed" mean?
 
 L<Mojolicious> uses secret passphrases for security features such as signed
-cookies. It defaults to using the moniker of your application, which is not
-very secure, so we added this log message as a reminder. You can change the
+cookies. It defaults to using L<Mojolicious/"moniker">, which is not very
+secure, so we added this log message as a reminder. You can change the
 passphrase with the attribute L<Mojolicious/"secrets">.
 
-  app->secrets(['My very secret passphrase.']);
+  $app->secrets(['My very secret passphrase.']);
 
 =head2 What does "Nothing has been rendered, expecting delayed response" mean?
 
@@ -8,7 +8,7 @@ Mojolicious::Guides::Growing - Growing
 =head1 OVERVIEW
 
 This document explains the process of starting a L<Mojolicious::Lite>
-prototype from scratch and growing it into a well structured L<Mojolicious>
+prototype from scratch and growing it into a well-structured L<Mojolicious>
 application.
 
 =head1 CONCEPTS
@@ -149,7 +149,8 @@ organized CPAN distribution to maximize maintainability.
   |- lib                     # Library directory
   |  |- MyApp.pm             # Application class
   |  +- MyApp                # Application namespace
-  |     +- Example.pm        # Controller class
+  |     +- Controller        # Controller namespace
+  |        +- Example.pm     # Controller class
   |- t                       # Test directory
   |  +- basic.t              # Random test
   |- log                     # Log directory
@@ -169,6 +170,9 @@ L<Mojolicious::Command::generate::app>.
   $ mojo generate lite_app myapp.pl
   $ mojo generate app MyApp
 
+Feature-wise both are almost equal, the only real differences are
+organizational, so each one can be gradually transformed into the other.
+
 =head2 Foundation
 
 We start our new application with a single executable Perl script.
@@ -199,20 +203,48 @@ fun thanks to automatic reloading.
 Just save your changes and they will be automatically in effect the next time
 you refresh your browser.
 
+=head2 A birds-eye view
+
+It all starts with an HTTP request like this, sent by your browser.
+
+  GET / HTTP/1.1
+  Host: localhost:3000
+
+Once the request has been received by the web server through the event loop,
+it will be passed on to L<Mojolicious>, where it will be handled in a few
+simple steps.
+
+  1. Check if a static file exists that would meet the requirements.
+  2. Try to find a route that would meet the requirements.
+  3. Dispatch the request to this route, usually reaching one or more actions.
+  4. Process the request, maybe generating a response with the renderer.
+  5. Return control to the web server, and if no response has been generated
+     yet, wait for a non-blocking operation to do so through the event loop.
+
+With our application the router would have found an action in step 2, and
+rendered some text in step 4, resulting in an HTTP response like this being
+sent back to the browser.
+
+  HTTP/1.1 200 OK
+  Content-Length: 12
+  Hello world!
+
 =head2 Model
 
 In L<Mojolicious> we consider web applications simple frontends for existing
-business logic, that means L<Mojolicious> is by design entirely L<model> layer
+business logic, that means L<Mojolicious> is by design entirely I<model> layer
 agnostic and you just use whatever Perl modules you like most.
 
-  $ mkdir lib
-  $ touch lib/MyUsers.pm
-  $ chmod 644 lib/MyUsers.pm
+  $ mkdir -p lib/MyApp/Model
+  $ touch lib/MyApp/Model/Users.pm
+  $ chmod 644 lib/MyApp/Model/Users.pm
 
 Our login manager will simply use a plain old Perl module abstracting away all
-logic related to matching usernames and passwords.
+logic related to matching usernames and passwords. The name
+C<MyApp::Model::Users> is an arbitrary choice, and is simply used to make the
+separation of concerns more visible.
 
-  package MyUsers;
+  package MyApp::Model::Users;
 
   use strict;
   use warnings;
@@ -245,10 +277,10 @@ templates.
   use Mojolicious::Lite;
 
   use lib 'lib';
-  use MyUsers;
+  use MyApp::Model::Users;
 
   # Helper to lazy initialize and store our model object
-  helper users => sub { state $users = MyUsers->new };
+  helper users => sub { state $users = MyApp::Model::Users->new };
 
   # /?user=sri&pass=secr3t
   any '/' => sub {
@@ -355,7 +387,7 @@ using the method L<Mojolicious::Controller/"session">, there is no setup
 required, but we suggest setting a more secure passphrase with
 L<Mojolicious/"secrets">.
 
-  app->secrets(['Mojolicious rocks']);
+  $app->secrets(['Mojolicious rocks']);
 
 This passphrase is used by the HMAC-SHA1 algorithm to make signed cookies
 secure and can be changed at any time to invalidate all existing sessions.
@@ -374,8 +406,9 @@ set an absolute expiration date in the past.
   $c->session(expires => 1);
 
 For data that should only be visible on the next request, like a confirmation
-message after a 302 redirect, you can use the flash, accessible through the
-method L<Mojolicious::Controller/"flash">.
+message after a C<302> redirect performed with
+L<Mojolicious::Controller/"redirect_to">, you can use the flash, accessible
+through the method L<Mojolicious::Controller/"flash">.
 
   $c->flash(message => 'Everything is fine.');
   $c->redirect_to('goodbye');
@@ -393,12 +426,12 @@ this.
   use Mojolicious::Lite;
 
   use lib 'lib';
-  use MyUsers;
+  use MyApp::Model::Users;
 
   # Make signed cookies secure
   app->secrets(['Mojolicious rocks']);
 
-  helper users => sub { state $users = MyUsers->new };
+  helper users => sub { state $users = MyApp::Model::Users->new };
 
   # Main login action
   any '/' => sub {
@@ -479,10 +512,21 @@ this.
     <body><%= content %></body>
   </html>
 
-A list of all built-in helpers can be found in
-L<Mojolicious::Plugin::DefaultHelpers> and L<Mojolicious::Plugin::TagHelpers>.
+And the directory structure should be looking like this now.
+
+  myapp
+  |- myapp.pl
+  |- lib
+  |  +- MyApp
+  |     +- Model
+  |        +- Users.pm
+  +- t
+     +- login.t
+
+Our templates are using quite a few features of the renderer,
+L<Mojolicious::Guides::Rendering> explains them all in great detail.
 
-=head1 WELL STRUCTURED APPLICATION
+=head1 WELL-STRUCTURED APPLICATION
 
 Due to the flexibility of L<Mojolicious> there are many variations of the
 actual growing process, but this should give you a good overview of the
@@ -496,8 +540,8 @@ directories with the command L<Mojolicious::Command::inflate>.
 
   $ ./myapp.pl inflate
 
-Those directories always get priority, so inflating can also be a great way to
-allow your users to customize their applications.
+Those directories have a higher precedence, so inflating can also be a great
+way to allow your users to customize their applications.
 
 =head2 Simplified application class
 
@@ -514,13 +558,13 @@ actual action code needs to be changed.
   package MyApp;
   use Mojo::Base 'Mojolicious';
 
-  use MyUsers;
+  use MyApp::Model::Users;
 
   sub startup {
     my $self = shift;
 
     $self->secrets(['Mojolicious rocks']);
-    $self->helper(users => sub { state $users = MyUsers->new });
+    $self->helper(users => sub { state $users = MyApp::Model::Users->new });
 
     my $r = $self->routes;
 
@@ -573,19 +617,37 @@ allow running tests again.
   # Start command line interface for application
   Mojolicious::Commands->start_app('MyApp');
 
+And the directory structure of our hybrid application should be looking like
+this.
+
+  myapp
+  |- myapp.pl
+  |- lib
+  |  |- MyApp.pm
+  |  +- MyApp
+  |     +- Model
+  |        +- Users.pm
+  |- t
+  |  +- login.t
+  +- templates
+     |- layouts
+     |  +- default.html.ep
+     |- index.html.ep
+     +- protected.html.ep
+
 =head2 Controller class
 
 Hybrid routes are a nice intermediate step, but to maximize maintainability it
 makes sense to split our action code from its routing information.
 
-  $ mkdir lib/MyApp
-  $ touch lib/MyApp/Login.pm
-  $ chmod 644 lib/MyApp/Login.pm
+  $ mkdir lib/MyApp/Controller
+  $ touch lib/MyApp/Controller/Login.pm
+  $ chmod 644 lib/MyApp/Controller/Login.pm
 
 Once again the actual action code does not need to change, we just rename
 C<$c> to C<$self> since the controller is now the invocant.
 
-  package MyApp::Login;
+  package MyApp::Controller::Login;
   use Mojo::Base 'Mojolicious::Controller';
 
   sub index {
@@ -626,30 +688,32 @@ information.
   package MyApp;
   use Mojo::Base 'Mojolicious';
 
-  use MyUsers;
+  use MyApp::Model::Users;
 
   sub startup {
     my $self = shift;
 
     $self->secrets(['Mojolicious rocks']);
-    $self->helper(users => sub { state $users = MyUsers->new });
+    $self->helper(users => sub { state $users = MyApp::Model::Users->new });
 
     my $r = $self->routes;
     $r->any('/')->to('login#index')->name('index');
-    my $logged_in = $r->under->to('login#logged_in');
+
+    my $logged_in = $r->under('/')->to('login#logged_in');
     $logged_in->get('/protected')->to('login#protected');
+
     $r->get('/logout')->to('login#logout');
   }
 
   1;
 
-L<Mojolicious::Routes> allows many route variations, choose whatever you like
-most.
+The router allows many different route variations,
+L<Mojolicious::Guides::Routing> explains them all in great detail.
 
 =head2 Templates
 
-Templates are usually bound to controllers, so they need to be moved into the
-appropriate directories.
+Templates are our views, and usually bound to controllers, so they need to be
+moved into the appropriate directories.
 
   $ mkdir templates/login
   $ mv templates/index.html.ep templates/login/index.html.ep
@@ -681,8 +745,8 @@ without breaking updated dual-life modules.
 
 =head2 Simplified tests
 
-Normal L<Mojolicious> applications are a little easier to test, so
-C<t/login.t> can be simplified.
+Full L<Mojolicious> applications are a little easier to test, so C<t/login.t>
+can be simplified.
 
   use Test::More;
   use Test::Mojo;
@@ -709,6 +773,27 @@ C<t/login.t> can be simplified.
 
   done_testing();
 
+And our final directory structure should be looking like this.
+
+  myapp
+  |- script
+  |  +- myapp
+  |- lib
+  |  |- MyApp.pm
+  |  +- MyApp
+  |     |- Controller
+  |     |  +- Login.pm
+  |     +- Model
+  |        +- Users.pm
+  |- t
+  |  +- login.t
+  +- templates
+     |- layouts
+     |  +- default.html.ep
+     +- login
+        |- index.html.ep
+        +- protected.html.ep
+
 Test-driven development takes a little getting used to, but can be a very
 powerful tool.
 
@@ -24,12 +24,19 @@ utilizing multiple template systems and data encoding modules.
 
 Templates can be automatically detected if enough information is provided by
 the developer or routes. Template names are expected to follow the
-C<name.format.handler> scheme, with C<name> defaulting to C<controller/action>
-or the route name, C<format> defaulting to C<html> and C<handler> to C<ep>.
+C<template.format.handler> scheme, with C<template> defaulting to
+C<controller/action> or the route name, C<format> defaulting to C<html> and
+C<handler> to C<ep>.
 
   {controller => 'users', action => 'list'} -> 'users/list.html.ep'
-  {name => 'foo', format => 'txt'}          -> 'foo.txt.ep'
-  {name => 'foo', handler => 'epl'}         -> 'foo.html.epl'
+  {template => 'foo', format => 'txt'}      -> 'foo.txt.ep'
+  {template => 'foo', handler => 'epl'}     -> 'foo.html.epl'
+
+The C<controller> value gets decamelized using L<Mojo::Util/"decamelize"> and
+C<-> characters replaced with C</>.
+
+  {controller => 'My::Users', action => 'add'} -> 'my/users/add.html.ep'
+  {controller => 'my-users', action => 'show'} -> 'my/users/show.html.ep'
 
 All templates should be in the C<templates> directories of the application,
 which can be customized with L<Mojolicious::Renderer/"paths">, or one of the
@@ -145,6 +152,11 @@ controller object as both C<$self> and C<$c>.
 
   Hello <%= $name %> from <%= $c->tx->remote_address %>.
 
+A prefix like C<myapp.*> is commonly used for stash values that you don't want
+to expose in templates.
+
+  $c->stash('myapp.name' => 'tester');
+
 There are also many helper functions available, but more about that later.
 
   <%= dumper {foo => 'bar'} %>
@@ -295,16 +307,16 @@ These mappings can be easily extended or changed with L<Mojolicious/"types">.
 
 =head2 Stash data
 
-Any of the native Perl data types can be passed to templates through the
-L<Mojolicious::Controller/"stash">.
+Any of the native Perl data types can be passed to templates as references
+through the L<Mojolicious::Controller/"stash">.
 
   $c->stash(author     => 'Sebastian');
   $c->stash(frameworks => [qw(Catalyst Mojolicious)]);
-  $c->stash(examples   => {tweetylicious => 'a microblogging app'});
+  $c->stash(examples   => {convos => 'an IRC app'});
 
   %= $author
   %= $frameworks->[1]
-  %= $examples->{tweetylicious}
+  %= $examples->{convos}
 
 Since everything is just Perl normal control structures just work.
 
@@ -312,10 +324,51 @@ Since everything is just Perl normal control structures just work.
     <%= $framework %> was written by <%= $author %>.
   % }
 
-  % if (my $description = $examples->{tweetylicious}) {
-    Tweetylicious is a <%= $description %>.
+  % if (my $description = $examples->{convos}) {
+    Convos is a <%= $description %>.
   % }
 
+For templates that might get rendered in different ways and where you're not
+sure if a stash value will actually be set, you can just use the helper
+L<Mojolicious::Plugin::DefaultHelpers/"stash">.
+
+  % if (my $examples = stash 'examples') {
+    Convos is <%= $examples->{convos} %>.
+  % }
+
+=head2 Helpers
+
+Helpers are little functions you can use in templates as well as application
+and controller code.
+
+  # Template
+  %= dumper [1, 2, 3]
+
+  # Application
+  my $serialized = $app->dumper([1, 2, 3]);
+
+  # Controller
+  my $serialized = $c->dumper([1, 2, 3]);
+
+The helper L<Mojolicious::Plugin::DefaultHelpers/"dumper"> for example will
+use L<Data::Dumper> to serialize whatever data structure you pass it, this can
+be very useful for debugging. We differentiate between default helpers which
+are more general purpose like C<dumper> and tag helpers, which are template
+specific and mostly used to generate HTML tags.
+
+  %= link_to 'http://mojolicio.us' => begin
+    Mojolicious
+  % end
+
+In controllers you can also use the method
+L<Mojolicious::Controller/"helpers"> to fully qualify helper calls and ensure
+that they don't conflict with existing methods you may already have.
+
+  my $serialized = $c->helpers->dumper([1, 2, 3]);
+
+A list of all built-in helpers can be found in
+L<Mojolicious::Plugin::DefaultHelpers> and L<Mojolicious::Plugin::TagHelpers>.
+
 =head2 Content negotiation
 
 For resources with different representations and that require truly
@@ -392,8 +445,9 @@ By now you've probably already encountered the built-in 404 (Not Found) and
 500 (Server Error) pages, that get rendered automatically when you make a
 mistake. Those are fallbacks for when your own exception handling fails, but
 especially during development they can also be a great help, you can render
-them manually with the methods L<Mojolicious::Controller/"render_exception">
-and L<Mojolicious::Controller/"render_not_found">.
+them manually with the helpers
+L<Mojolicious::Plugin::DefaultHelpers/"reply-E<gt>exception"> and
+L<Mojolicious::Plugin::DefaultHelpers/"reply-E<gt>not_found">.
 
   use Mojolicious::Lite;
   use Scalar::Util 'looks_like_number';
@@ -403,11 +457,11 @@ and L<Mojolicious::Controller/"render_not_found">.
     my ($dividend, $divisor) = $c->param(['dividend', 'divisor']);
 
     # 404
-    return $c->render_not_found
+    return $c->reply->not_found
       unless looks_like_number $dividend && looks_like_number $divisor;
 
     # 500
-    return $c->render_exception('Division by zero!') if $divisor == 0;
+    return $c->reply->exception('Division by zero!') if $divisor == 0;
 
     # 200
     $c->render(text => $dividend / $divisor);
@@ -455,29 +509,6 @@ passed to the renderer.
 
   app->start;
 
-=head2 Helpers
-
-Helpers are little functions you can use in templates and controller code.
-
-  %= dumper [1, 2, 3]
-
-  my $serialized = $c->dumper([1, 2, 3]);
-
-The helper L<Mojolicious::Plugin::DefaultHelpers/"dumper"> for example will
-use L<Data::Dumper> to serialize whatever data structure you pass it, this can
-be very useful for debugging. We differentiate between default helpers which
-are more general purpose like C<dumper> and tag helpers, which are template
-specific and mostly used to generate HTML tags.
-
-  %= javascript '/script.js'
-
-  %= javascript begin
-    var a = 'b';
-  % end
-
-A list of all built-in helpers can be found in
-L<Mojolicious::Plugin::DefaultHelpers> and L<Mojolicious::Plugin::TagHelpers>.
-
 =head2 Layouts
 
 Most of the time when using C<ep> templates you will want to wrap your
@@ -609,6 +640,92 @@ A naive translation to Perl code could look like this.
   }
   return $output;
 
+=head2 Adding helpers
+
+You should always try to keep your actions small and reuse as much code as
+possible. Helpers make this very easy, you can use them to do pretty much
+anything an action could do.
+
+  use Mojolicious::Lite;
+
+  helper debug => sub {
+    my ($c, $str) = @_;
+    $c->app->log->debug($str);
+  };
+
+  get '/' => sub {
+    my $c = shift;
+    $c->debug('Hello from an action!');
+  } => 'index';
+
+  app->start;
+  __DATA__
+
+  @@ index.html.ep
+  % debug 'Hello from a template!';
+
+Helpers can also accept template blocks as last argument, this for example
+allows very pleasant to use tag helpers and filters. Wrapping the helper
+result into a L<Mojo::ByteStream> object can prevent accidental double
+escaping.
+
+  use Mojolicious::Lite;
+  use Mojo::ByteStream;
+
+  helper trim_newline => sub {
+    my ($c, $block) = @_;
+    my $result = $block->();
+    $result =~ s/\n//g;
+    return Mojo::ByteStream->new($result);
+  };
+
+  get '/' => 'index';
+
+  app->start;
+  __DATA__
+
+  @@ index.html.ep
+  %= trim_newline begin
+    Some text.
+    %= 1 + 1
+    More text.
+  % end
+
+Similar to stash values you can use a prefix like C<myapp.*> to keep helpers
+from getting exposed in templates and to organize them into namespaces as your
+application grows. Every prefix automatically becomes a helper that returns a
+proxy object containing the current controller object and on which you can
+call the nested helpers.
+
+  use Mojolicious::Lite;
+
+  helper 'cache_control.no_caching' => sub {
+    my $c = shift;
+    $c->res->headers->cache_control('private, max-age=0, no-cache');
+  };
+
+  helper 'cache_control.five_minutes' => sub {
+    my $c = shift;
+    $c->res->headers->cache_control('public, max-age=300');
+  };
+
+  get '/news' => sub {
+    my $c = shift;
+    $c->cache_control->no_caching;
+    $c->render(text => 'Always up to date.');
+  };
+
+  get '/some_older_story' => sub {
+    my $c = shift;
+    $c->cache_control->five_minutes;
+    $c->render(text => 'This one can be cached for a bit.');
+  };
+
+  app->start;
+
+While helpers can also be redefined, this should only be done very carefully
+to avoid conflicts.
+
 =head2 Content blocks
 
 Blocks and the helper L<Mojolicious::Plugin::DefaultHelpers/"content_for">
@@ -669,12 +786,12 @@ This chain could go on and on to allow a very high level of template reuse.
 
 =head2 Form validation
 
-You can use L<Mojolicious::Controller/"validation"> to validate C<GET>/C<POST>
-parameters submitted to your application. All unknown fields will be ignored
-by default, so you have to decide which should be required or optional before
-you can perform checks on their values. Every check is performed right away,
-so you can use the results immediately to build more advanced validation logic
-with methods like L<Mojolicious::Validator::Validation/"is_valid">.
+You can use L<Mojolicious::Controller/"validation"> to validate C<GET> and
+C<POST> parameters submitted to your application. All unknown fields will be
+ignored by default, so you have to decide which should be required or optional
+before you can perform checks on their values. Every check is performed right
+away, so you can use the results immediately to build more advanced validation
+logic with methods like L<Mojolicious::Validator::Validation/"is_valid">.
 
   use Mojolicious::Lite;
 
@@ -796,6 +913,10 @@ L<Mojolicious::Validator::Validation/"error">.
     </body>
   </html>
 
+The methods L<Mojolicious::Controller/"flash"> and
+L<Mojolicious::Controller/"redirect_to"> are often used together to prevent
+double form submission.
+
 =head2 Cross-site request forgery
 
 CSRF is a very common attack on web applications that trick your logged in
@@ -839,56 +960,59 @@ with L<Mojolicious::Validator::Validation/"csrf_protect">.
 
 The token can also be submitted with the C<X-CSRF-Token> request header.
 
-=head2 Adding helpers
+=head1 ADVANCED
 
-Adding and redefining helpers is very easy, you can use them to do pretty much
-everything.
+Less commonly used and more powerful features.
 
-  use Mojolicious::Lite;
+=head2 Serving static files
 
-  helper debug => sub {
-    my ($c, $str) = @_;
-    $c->app->log->debug($str);
-  };
+Static files are automatically served from your C<DATA> sections and C<public>
+directories, and if that's not enough you can also serve them manually with
+L<Mojolicious::Plugin::DefaultHelpers/"reply-E<gt>static">.
 
-  get '/' => sub {
+  use Mojolicious::Lite;
+
+  get '/some_static_file' => sub {
     my $c = shift;
-    $c->debug('Hello from an action!');
-  } => 'index';
+    $c->res->headers->content_disposition('attachment; filename=bar.png;');
+    $c->reply->static('foo/bar.png');
+  };
 
   app->start;
-  __DATA__
 
-  @@ index.html.ep
-  % debug 'Hello from a template!';
+=head2 Custom responses
 
-Helpers can also accept template blocks as last argument, this for example
-allows very pleasant to use tag helpers and filters.
+Most response content, static as well as dynamic, gets served through
+L<Mojo::Asset::File> and L<Mojo::Asset::Memory> objects. For somewhat static
+content, like cached JSON data or temporary file, you can create your own and
+use the helper L<Mojolicious::Plugin::DefaultHelpers/"reply-E<gt>asset"> to
+serve them while allowing content negotiation to be performed with C<Range>,
+C<If-Modified-Since> and C<If-None-Match> headers.
 
   use Mojolicious::Lite;
-  use Mojo::ByteStream;
 
-  helper trim_newline => sub {
-    my ($c, $block) = @_;
-    my $result = $block->();
-    $result =~ s/\n//g;
-    return Mojo::ByteStream->new($result);
+  get '/leak' => sub {
+    my $c = shift;
+    $c->res->headers->content_type('text/plain');
+    $c->reply->asset(Mojo::Asset::File->new(path => '/etc/passwd'));
   };
 
-  get '/' => 'index';
-
   app->start;
-  __DATA__
 
-  @@ index.html.ep
-  %= trim_newline begin
-    Some text.
-    %= 1 + 1
-    More text.
-  % end
+For even more control you can also just skip the helper and use
+L<Mojolicious::Controller/"rendered"> to tell the renderer when you're done
+generating a response.
 
-Wrapping the helper result into a L<Mojo::ByteStream> object can prevent
-accidental double escaping.
+  use Mojolicious::Lite;
+
+  get '/leak' => sub {
+    my $c = shift;
+    $c->res->headers->content_type('text/plain');
+    $c->res->content->asset(Mojo::Asset::File->new(path => '/etc/passwd'));
+    $c->rendered(200);
+  };
+
+  app->start;
 
 =head2 Helper plugins
 
@@ -1016,29 +1140,6 @@ plugin.
   @@ alertassets.html.ep
   %= javascript "/alertassets.js"
 
-=head1 ADVANCED
-
-Less commonly used and more powerful features.
-
-=head2 Rendering static files
-
-If automatic rendering of static files is not enough, you can also render them
-manually from your C<DATA> sections and C<public> directories with
-L<Mojolicious::Controller/"render_static">.
-
-  $c->res->headers->content_disposition('attachment; filename=bar.png;');
-  $c->render_static('foo/bar.png');
-
-=head2 Custom responses
-
-For entirely custom responses to, for example, stream content directly from
-files, you can use L<Mojolicious::Controller/"rendered"> to tell the renderer
-that a response has been generated.
-
-  $c->res->headers->content_type('text/plain');
-  $c->res->content->asset(Mojo::Asset::File->new(path => '/etc/passwd'));
-  $c->rendered(200);
-
 =head2 Post-processing dynamic content
 
 While post-processing tasks are generally very easy with the hook
@@ -1084,15 +1185,28 @@ L<Mojolicious::Controller/"write_chunk"> come in handy. A common use would be
 to send the C<head> section of an HTML document to the browser in advance and
 speed up preloading of referenced images and stylesheets.
 
-  $c->write_chunk('<html><head><title>Example</title></head>' => sub {
+  use Mojolicious::Lite;
+
+  get '/' => sub {
     my $c = shift;
-    $c->finish('<body>Example</body></html>');
-  });
+    $c->write_chunk('<html><head><title>Example</title></head>' => sub {
+      my $c = shift;
+      $c->finish('<body>Example</body></html>');
+    });
+  };
+
+  app->start;
 
 The optional drain callback ensures that all previous chunks have been
 written before processing continues. An empty chunk or call to
 L<Mojolicious::Controller/"finish"> marks the end of the stream.
 
+  HTTP/1.1 200 OK
+  Connection: keep-alive
+  Date: Sat, 13 Sep 2014 16:48:29 GMT
+  Transfer-Encoding: chunked
+  Server: Mojolicious (Perl)
+
   29
   <html><head><title>Example</title></head>
   1b
@@ -1241,22 +1355,22 @@ that need to be automatically encoded, but this can be easily disabled if
 you're generating bytes instead.
 
   use Mojolicious::Lite;
-  use Mango::BSON ':bson';
+  use Storable 'nfreeze';
 
-  # Add "bson" handler
-  app->renderer->add_handler(bson => sub {
+  # Add "storable" handler
+  app->renderer->add_handler(storable => sub {
     my ($renderer, $c, $output, $options) = @_;
 
     # Disable automatic encoding
     delete $options->{encoding};
 
-    # Encode BSON data from stash value
-    $$output = bson_encode delete $c->stash->{bson};
+    # Encode data from stash value
+    $$output = nfreeze delete $c->stash->{storable};
 
     return 1;
   });
 
-  get '/' => {bson => {i => '♥ mojolicious'}, handler => 'bson'};
+  get '/' => {storable => {i => '♥ mojolicious'}, handler => 'storable'};
 
   app->start;
 
@@ -25,10 +25,10 @@ This black box is usually called a dispatcher. There are many implementations
 using different strategies to establish these connections, but pretty much all
 are based around mapping the requests path to some kind of response generator.
 
-  /user/show/1 -> $c->render(text => 'Sebastian');
-  /user/show/2 -> $c->render(text => 'Sara');
-  /user/show/3 -> $c->render(text => 'Baerbel');
-  /user/show/4 -> $c->render(text => 'Wolfgang');
+  /user/show/2 -> $c->render(text => 'Daniel');
+  /user/show/3 -> $c->render(text => 'Sara');
+  /user/show/4 -> $c->render(text => 'Baerbel');
+  /user/show/5 -> $c->render(text => 'Wolfgang');
 
 While it is very well possible to make all these connections static, it is
 also rather inefficient. That's why regular expressions are commonly used to
@@ -164,16 +164,16 @@ defined.
     my $r = $self->routes;
 
     # Route
-    $r->route('/welcome')->to(controller => 'foo', action => 'welcome');
+    $r->get('/welcome')->to(controller => 'foo', action => 'welcome');
   }
 
   1;
 
-The minimal route above will load and instantiate the class C<MyApp::Foo> and
-call its C<welcome> method.
+The minimal route above will load and instantiate the class
+C<MyApp::Controller::Foo> and call its C<welcome> method.
 
   # Controller
-  package MyApp::Foo;
+  package MyApp::Controller::Foo;
   use Mojo::Base 'Mojolicious::Controller';
 
   # Action
@@ -191,17 +191,54 @@ class, but the router can be accessed from everywhere (even at runtime).
 
 =head2 Routing destination
 
-After you start a new route with the method
-L<Mojolicious::Routes::Route/"route">, you can also give it a destination in
-the form of a hash using the chained method
-L<Mojolicious::Routes::Route/"to">.
+After you start a new route with methods like
+L<Mojolicious::Routes::Route/"get">, you can also give it a destination in the
+form of a hash using the chained method L<Mojolicious::Routes::Route/"to">.
 
   # /welcome -> {controller => 'foo', action => 'welcome'}
-  $r->route('/welcome')->to(controller => 'foo', action => 'welcome');
+  $r->get('/welcome')->to(controller => 'foo', action => 'welcome');
 
 Now if the route matches an incoming request it will use the content of this
 hash to try and find appropriate code to generate a response.
 
+=head2 HTTP methods
+
+There are already shortcuts for the most common HTTP request methods like
+L<Mojolicious::Routes::Route/"post">, and for more control
+L<Mojolicious::Routes::Route/"any"> accepts an optional array reference with
+arbitrary request methods as first argument.
+
+  # PUT /hello  -> undef
+  # GET /hello  -> {controller => 'foo', action => 'hello'}
+  $r->get('/hello')->to(controller => 'foo', action => 'hello');
+
+  # PUT /hello -> {controller => 'foo', action => 'hello'}
+  $r->put('/hello')->to(controller => 'foo', action => 'hello');
+
+  # POST /hello -> {controller => 'foo', action => 'hello'}
+  $r->post('/hello')->to(controller => 'foo', action => 'hello');
+
+  # GET|POST /bye  -> {controller => 'foo', action => 'bye'}
+  $r->any([qw(GET POST)] => '/bye')->to(controller => 'foo', action => 'bye');
+
+  # * /whatever -> {controller => 'foo', action => 'whatever'}
+  $r->any('/whatever')->to(controller => 'foo', action => 'whatever');
+
+There is one small exception, C<HEAD> requests are considered equal to C<GET>,
+but content will not be sent with the response even if it is present.
+
+  # GET /test  -> {controller => 'bar', action => 'test'}
+  # HEAD /test -> {controller => 'bar', action => 'test'}
+  $r->get('/test')->to(controller => 'bar', action => 'test');
+
+=head2 IRIs
+
+IRIs are handled transparently, that means paths are guaranteed to be
+unescaped and decoded from bytes to characters.
+
+  # GET /☃ (unicode snowman) -> {controller => 'foo', action => 'snowman'}
+  $r->get('/☃')->to(controller => 'foo', action => 'snowman');
+
 =head2 Stash
 
 The generated hash of a matching route is actually the center of the whole
@@ -209,7 +246,7 @@ L<Mojolicious> request cycle. We call it the stash, and it persists until a
 response has been generated.
 
   # /bye -> {controller => 'foo', action => 'bye', mymessage => 'Bye'}
-  $r->route('/bye')
+  $r->get('/bye')
     ->to(controller => 'foo', action => 'bye', mymessage => 'Bye');
 
 There are a few stash values with special meaning, such as C<controller> and
@@ -238,30 +275,29 @@ endpoints of these nested routes can.
 
   # /foo     -> undef
   # /foo/bar -> {controller => 'foo', action => 'bar'}
-  my $foo = $r->route('/foo')->to(controller => 'foo');
-  $foo->route('/bar')->to(action => 'bar');
+  my $foo = $r->any('/foo')->to(controller => 'foo');
+  $foo->get('/bar')->to(action => 'bar');
 
 The stash is simply inherited from route to route and newer values override
 old ones.
 
-  # /foo     -> undef
-  # /foo/abc -> undef
   # /foo/bar -> {controller => 'foo', action => 'bar'}
   # /foo/baz -> {controller => 'foo', action => 'baz'}
   # /foo/cde -> {controller => 'foo', action => 'abc'}
-  my $foo = $r->route('/foo')->to(controller => 'foo', action => 'abc');
-  $foo->route('/bar')->to(action => 'bar');
-  $foo->route('/baz')->to(action => 'baz');
-  $foo->route('/cde');
+  my $foo = $r->any('/foo')->to(controller => 'foo', action => 'abc');
+  $foo->get('/bar')->to(action => 'bar');
+  $foo->get('/baz')->to(action => 'baz');
+  $foo->get('/cde');
 
 =head2 Special stash values
 
 When the dispatcher sees C<controller> and C<action> values in the stash it
 will always try to turn them into a class and method to dispatch to. The
 C<controller> value gets camelized using L<Mojo::Util/"camelize"> and
-prefixed with a C<namespace> (defaulting to the applications class). While the
-action value is not changed at all, because of this both values are case
-sensitive.
+appended to one or more namespaces, defaulting to a controller namespace based
+on the application class (C<MyApp::Controller>), as well as the bare
+application class (C<MyApp>), and these namespaces are searched in that order.
+The action value is not changed at all, so both values are case sensitive.
 
   # Application
   package MyApp;
@@ -270,14 +306,14 @@ sensitive.
   sub startup {
     my $self = shift;
 
-    # /bye -> {controller => 'foo', action => 'bye'} -> MyApp::Foo->bye
-    $self->routes->route('/bye')->to(controller => 'foo', action => 'bye');
+    # /bye -> MyApp::Controller::Foo->bye
+    $self->routes->get('/bye')->to(controller => 'foo', action => 'bye');
   }
 
   1;
 
   # Controller
-  package MyApp::Foo;
+  package MyApp::Controller::Foo;
   use Mojo::Base 'Mojolicious::Controller';
 
   # Action
@@ -296,52 +332,107 @@ used ones they also got a special shortcut in the form of
 C<controller#action>.
 
   # /bye -> {controller => 'foo', action => 'bye', mymessage => 'Bye'}
-  $r->route('/bye')->to('foo#bye', mymessage => 'Bye');
+  $r->get('/bye')->to('foo#bye', mymessage => 'Bye');
+
+During camelization C<-> characters get replaced with C<::>, this allows
+multi-level C<controller> hierarchies.
 
-During camelization C<-> gets replaced with C<::>, this allows multi-level
-C<controller> hierarchies.
+  # / -> MyApp::Controller::Foo::Bar->hi
+  $r->get('/')->to('foo-bar#hi');
 
-  # / -> {controller => 'foo-bar', action => 'hi'} -> MyApp::Foo::Bar->hi
-  $r->route('/')->to('foo-bar#hi');
+You can also just specify the C<controller> in CamelCase form instead of
+snake_case.
+
+  # / -> MyApp::Controller::Foo::Bar->hi
+  $r->get('/')->to('Foo::Bar#hi');
 
 For security reasons the dispatcher will always check if the C<controller> is
 actually a subclass of L<Mojolicious::Controller> or L<Mojo> before
 dispatching to it.
 
-=head2 Route to class
+=head2 Namespaces
 
 You can use the C<namespace> stash value to change the namespace of a whole
 route with all its children.
 
-  # /bye -> MyApp::Controller::Foo::Bar->bye
-  $r->route('/bye')
-    ->to(namespace => 'MyApp::Controller::Foo::Bar', action => 'bye');
+  # /bye -> MyApp::MyController::Foo::Bar->bye
+  $r->get('/bye')
+    ->to(namespace => 'MyApp::MyController::Foo::Bar', action => 'bye');
 
-The C<controller> is always appended to the C<namespace> if available.
+The C<controller> is always appended to this C<namespace> if available.
 
-  # /bye -> MyApp::Controller::Foo::Bar->bye
-  $r->route('/bye')->to('foo-bar#bye', namespace => 'MyApp::Controller');
+  # /bye -> MyApp::MyController::Foo::Bar->bye
+  $r->get('/bye')->to('foo-bar#bye', namespace => 'MyApp::MyController');
 
-  # /hey -> MyApp::Controller::Foo::Bar->hey
-  $r->route('/hey')->to('Foo::Bar#hey', namespace => 'MyApp::Controller');
+  # /hey -> MyApp::MyController::Foo::Bar->hey
+  $r->get('/hey')->to('Foo::Bar#hey', namespace => 'MyApp::MyController');
 
 You can also change the default namespaces for all routes in the application
 with the router attribute L<Mojolicious::Routes/"namespaces">.
 
-  $r->namespaces(['MyApp::Controller']);
+  $r->namespaces(['MyApp::MyController']);
 
 =head2 Route to callback
 
 The C<cb> stash value, which won't be inherited by nested routes, can be used
 to bypass controllers and execute a callback instead.
 
-  $r->route('/bye')->to(cb => sub {
+  $r->get('/bye')->to(cb => sub {
     my $c = shift;
     $c->render(text => 'Good bye.');
   });
 
-This technique is the foundation of L<Mojolicious::Lite>, you can learn more
-about it from the included tutorial.
+But just like in L<Mojolicious::Lite> you can also pass the callback directly,
+which usually looks much better.
+
+  $r->get('/bye' => sub {
+    my $c = shift;
+    $c->render(text => 'Good bye.');
+  });
+
+=head2 Named routes
+
+Naming your routes will allow backreferencing in many methods and helpers
+throughout the whole framework, most of them internally rely on
+L<Mojolicious::Controller/"url_for"> for this.
+
+  # /foo/marcus -> {controller => 'foo', action => 'bar', user => 'marcus'}
+  $r->get('/foo/:user')->to('foo#bar')->name('baz');
+
+  # Generate URL "/foo/marcus" for route "baz"
+  my $url = $c->url_for('baz');
+
+  # Generate URL "/foo/jan" for route "baz"
+  my $url = $c->url_for('baz', user => 'jan');
+
+  # Generate URL "http://127.0.0.1:3000/foo/jan" for route "baz"
+  my $url = $c->url_for('baz', user => 'jan')->to_abs;
+
+Nameless routes get an automatically generated one assigned that is simply
+equal to the route itself without non-word characters, custom names have a
+higher precedence though.
+
+  # /foo/bar ("foobar")
+  $r->get('/foo/bar')->to('test#stuff');
+
+  # Generate URL "/foo/bar"
+  my $url = $c->url_for('foobar');
+
+To refer to the current route you can use the reserved name C<current> or no
+name at all.
+
+  # Generate URL for current route
+  my $url = $c->url_for('current');
+  my $url = $c->url_for;
+
+To check or get the name of the current route you can use the helper
+L<Mojolicious::Plugin::DefaultHelpers/"current_route">.
+
+  # Name for current route
+  my $name = $c->current_route;
+
+  # Check route name in code shared by multiple routes
+  $c->stash(button => 'green') if $c->current_route('login');
 
 =head2 Optional placeholders
 
@@ -350,21 +441,18 @@ already exist.
 
   # /bye -> {controller => 'foo', action => 'bar', mymessage => 'bye'}
   # /hey -> {controller => 'foo', action => 'bar', mymessage => 'hey'}
-  $r->route('/:mymessage')
-    ->to(controller => 'foo', action => 'bar', mymessage => 'hi');
+  $r->get('/:mymessage')->to('foo#bar', mymessage => 'hi');
 
 One more interesting effect, a placeholder automatically becomes optional if
 there is already a stash value of the same name present, this works similar to
 the regular expression C<([^/.]+)?>.
 
   # / -> {controller => 'foo', action => 'bar', mymessage => 'hi'}
-  $r->route('/:mymessage')
-    ->to(controller => 'foo', action => 'bar', mymessage => 'hi');
+  $r->get('/:mymessage')->to('foo#bar', mymessage => 'hi');
 
   # /test/123     -> {controller => 'foo', action => 'bar', mymessage => 'hi'}
   # /test/bye/123 -> {controller => 'foo', action => 'bar', mymessage => 'bye'}
-  $r->route('/test/:mymessage/123')
-    ->to(controller => 'foo', action => 'bar', mymessage => 'hi');
+  $r->get('/test/:mymessage/123')->to('foo#bar', mymessage => 'hi');
 
 This is also the case if multiple placeholders are right after another and not
 separated by other characters than C</>.
@@ -372,8 +460,7 @@ separated by other characters than C</>.
   # /           -> {controller => 'foo',   action => 'bar'}
   # /users      -> {controller => 'users', action => 'bar'}
   # /users/list -> {controller => 'users', action => 'list'}
-  $r->route('/:controller/:action')
-    ->to(controller => 'foo', action => 'bar');
+  $r->get('/:controller/:action')->to('foo#bar');
 
 Special stash values like C<controller> and C<action> can also be
 placeholders, which is very convenient especially during development, but
@@ -394,11 +481,10 @@ A very easy way to make placeholders more restrictive are alternatives, you
 just make a list of possible values, which then work similar to the regular
 expression C<(bender|leela)>.
 
+  # /fry    -> undef
   # /bender -> {controller => 'foo', action => 'bar', name => 'bender'}
   # /leela  -> {controller => 'foo', action => 'bar', name => 'leela'}
-  # /fry    -> undef
-  $r->route('/:name', name => [qw(bender leela)])
-    ->to(controller => 'foo', action => 'bar');
+  $r->get('/:name' => [name => [qw(bender leela)]])->to('foo#bar');
 
 You can also adjust the regular expressions behind placeholders directly, just
 make sure not to use C<^> and C<$> or capturing groups C<(...)>, because
@@ -407,17 +493,75 @@ is fine though.
 
   # /23   -> {controller => 'foo', action => 'bar', number => 23}
   # /test -> undef
-  $r->route('/:number', number => qr/\d+/)
-    ->to(controller => 'foo', action => 'bar');
+  $r->get('/:number' => [number => qr/\d+/])->to('foo#bar');
 
   # /23   -> undef
   # /test -> {controller => 'foo', action => 'bar', name => 'test'}
-  $r->route('/:name', name => qr/[a-zA-Z]+/)
-    ->to(controller => 'foo', action => 'bar');
+  $r->get('/:name' => [name => qr/[a-zA-Z]+/])->to('foo#bar');
 
 This way you get easily readable routes and the raw power of regular
 expressions.
 
+=head2 Under
+
+To share code with multiple nested routes you can use
+L<Mojolicious::Routes::Route/"under">, because unlike normal nested routes,
+the routes generated with it have their own intermediate destination and
+result in additional dispatch cycles when they match.
+
+  # /foo     -> undef
+  # /foo/bar -> {controller => 'foo', action => 'baz'}
+  #             {controller => 'foo', action => 'bar'}
+  my $foo = $r->under('/foo')->to('foo#baz');
+  $foo->get('/bar')->to('#bar');
+
+The actual action code for this destination needs to return a true value or
+the dispatch chain will be broken, this can be a very powerful tool for
+authentication.
+
+  # /foo/bar -> {cb => sub {...}}
+  #             {controller => 'foo', action => 'bar'}
+  my $foo = $r->under('/foo' => sub {
+    my $c = shift;
+
+    # Authenticated
+    return 1 if $c->req->headers->header('X-Bender');
+
+    # Not authenticated
+    $c->render(text => "You're not Bender.");
+    return undef;
+  });
+  $foo->get('/bar')->to('foo#bar');
+
+Broken dispatch chains can be continued by calling the method
+L<Mojolicious::Controller/"continue">, this allows for example non-blocking
+operations to finish before reaching the next dispatch cycle.
+
+  my $foo = $r->under('/foo' => sub {
+    my $c = shift;
+
+    # Wait 3 seconds and then give visitors a 50% chance to continue
+    Mojo::IOLoop->timer(3 => sub {
+
+      # Loser
+      return $c->render(text => 'No luck.') unless int rand 2;
+
+      # Winner
+      $c->continue;
+    });
+
+    return undef;
+  });
+  $foo->get('/bar')->to('foo#bar');
+
+Every destination is just a snapshot of the stash at the time the route
+matched, and only the C<format> value is shared by all of them. For a little
+more power you can introspect the preceding and succeeding destinations with
+L<Mojolicious::Controller/"match">.
+
+  # Action of the fourth dispatch cycle
+  my $action = $c->match->stack->[3]{action};
+
 =head2 Formats
 
 File extensions like C<.html> and C<.txt> at the end of a route are
@@ -426,29 +570,23 @@ automatically detected and stored in the stash value C<format>.
   # /foo      -> {controller => 'foo', action => 'bar'}
   # /foo.html -> {controller => 'foo', action => 'bar', format => 'html'}
   # /foo.txt  -> {controller => 'foo', action => 'bar', format => 'txt'}
-  $r->route('/foo')->to(controller => 'foo', action => 'bar');
+  $r->get('/foo')->to('foo#bar');
 
 This for example allows multiple templates in different formats to share the
-same code.
-
-  # /foo      -> {controller => 'foo', action => 'bar'}
-  # /foo.html -> {controller => 'foo', action => 'bar', format => 'html'}
-  $r->route('/foo')->to(controller => 'foo', action => 'bar');
-
-Restrictive placeholders can also be used.
+same action code. Restrictive placeholders can also be used to limit the
+allowed formats.
 
+  # /foo.txt -> undef
   # /foo.rss -> {controller => 'foo', action => 'bar', format => 'rss'}
   # /foo.xml -> {controller => 'foo', action => 'bar', format => 'xml'}
-  # /foo.txt -> undef
-  $r->route('/foo', format => [qw(rss xml)])
-    ->to(controller => 'foo', action => 'bar');
+  $r->get('/foo' => [format => [qw(rss xml)]])->to('foo#bar');
 
 Or you can just disable format detection, which gets inherited by nested
 routes and allows selective re-enabling.
 
   # /foo      -> {controller => 'foo', action => 'bar'}
   # /foo.html -> undef
-  $r->route('/foo', format => 0)->to('foo#bar');
+  $r->get('/foo' => [format => 0])->to('foo#bar');
 
   # /foo      -> {controller => 'foo', action => 'bar'}
   # /foo.html -> undef
@@ -456,77 +594,9 @@ routes and allows selective re-enabling.
   # /baz.txt  -> {controller => 'baz', action => 'yada', format => 'txt'}
   # /baz.html -> {controller => 'baz', action => 'yada', format => 'html'}
   # /baz.xml  -> undef
-  my $inactive = $r->route(format => 0);
-  $inactive->route('/foo')->to('foo#bar');
-  $inactive->route('/baz', format => [qw(txt html)])->to('baz#yada');
-
-=head2 Named routes
-
-Naming your routes will allow backreferencing in many methods and helpers
-throughout the whole framework, most of them internally rely on
-L<Mojolicious::Controller/"url_for"> for this.
-
-  # /foo/abc -> {controller => 'foo', action => 'bar', name => 'abc'}
-  $r->route('/foo/:name')->name('test')
-    ->to(controller => 'foo', action => 'bar');
-
-  # Generate URL "/foo/abc" for route "test"
-  my $url = $c->url_for('test');
-
-  # Generate URL "/foo/sebastian" for route "test"
-  my $url = $c->url_for('test', name => 'sebastian');
-
-  # Generate URL "http://127.0.0.1:3000/foo/sebastian" for route "test"
-  my $url = $c->url_for('test', name => 'sebastian')->to_abs;
-
-Nameless routes get an automatically generated one assigned that is simply
-equal to the route itself without non-word characters.
-
-  # /foo/bar ("foobar")
-  $r->route('/foo/bar')->to('test#stuff');
-
-  # Generate URL "/foo/bar"
-  my $url = $c->url_for('foobar');
-
-To refer to the current route you can use the reserved name C<current> or no
-name at all.
-
-  # Generate URL for current route
-  my $url = $c->url_for('current');
-  my $url = $c->url_for;
-
-To check or get the name of the current route you can use the helper
-L<Mojolicious::Plugin::DefaultHelpers/"current_route">.
-
-  # Name for current route
-  my $name = $c->current_route;
-
-  # Check route name in code shared by multiple routes
-  $c->stash(button => 'green') if $c->current_route('login');
-
-=head2 HTTP methods
-
-The method L<Mojolicious::Routes::Route/"via"> allows only specific HTTP
-methods to pass.
-
-  # GET /bye    -> {controller => 'foo', action => 'bye'}
-  # POST /bye   -> undef
-  # DELETE /bye -> undef
-  $r->route('/bye')->via('GET')->to(controller => 'foo', action => 'bye');
-
-  # GET /bye    -> {controller => 'foo', action => 'bye'}
-  # POST /bye   -> {controller => 'foo', action => 'bye'}
-  # DELETE /bye -> undef
-  $r->route('/bye')->via('GET', 'POST')
-    ->to(controller => 'foo', action => 'bye');
-
-With one small exception, C<HEAD> requests are considered equal to C<GET> and
-content will not be sent with the response.
-
-  # GET /test  -> {controller => 'bar', action => 'test'}
-  # HEAD /test -> {controller => 'bar', action => 'test'}
-  # PUT /test  -> undef
-  $r->route('/test')->via('GET')->to(controller => 'bar', action => 'test');
+  my $inactive = $r->under([format => 0]);
+  $inactive->get('/foo')->to('foo#bar');
+  $inactive->get('/baz' => [format => [qw(txt html)]])->to('baz#yada');
 
 =head2 WebSockets
 
@@ -535,10 +605,10 @@ access to WebSocket handshakes, which are normal C<GET> requests with some
 additional information.
 
   # /echo (WebSocket handshake)
-  $r->websocket('/echo')->to(controller => 'foo', action => 'echo');
+  $r->websocket('/echo')->to('foo#echo');
 
   # Controller
-  package MyApp::Foo;
+  package MyApp::Controller::Foo;
   use Mojo::Base 'Mojolicious::Controller';
 
   # Action
@@ -557,110 +627,17 @@ request with a C<101> response status, which happens automatically if you
 subscribe to an event with L<Mojolicious::Controller/"on"> or send a message
 with L<Mojolicious::Controller/"send"> right away.
 
-=head2 Bridges
-
-Bridge routes created with the method L<Mojolicious::Routes::Route/"bridge">
-can be used to share code with multiple nested routes, because unlike normal
-nested routes, they result in additional dispatch cycles when they match.
-
-  # /foo     -> undef
-  # /foo/bar -> {controller => 'foo', action => 'baz'}
-  #             {controller => 'foo', action => 'bar'}
-  my $foo = $r->bridge('/foo')->to(controller => 'foo', action => 'baz');
-  $foo->route('/bar')->to(action => 'bar');
-
-The actual bridge code needs to return a true value or the dispatch chain will
-be broken, this makes bridges a very powerful tool for authentication.
-
-  # /foo     -> undef
-  # /foo/bar -> {cb => sub {...}}
-  #             {controller => 'foo', action => 'bar'}
-  my $foo = $r->bridge('/foo')->to(cb => sub {
-    my $c = shift;
-
-    # Authenticated
-    return 1 if $c->req->headers->header('X-Bender');
-
-    # Not authenticated
-    $c->render(text => "You're not Bender.");
-    return undef;
-  });
-  $foo->route('/bar')->to(controller => 'foo', action => 'bar');
-
-Broken dispatch chains can be continued by calling the method
-L<Mojolicious::Controller/"continue">, this allows for example non-blocking
-operations to finish before reaching the next dispatch cycle.
-
-  # /foo     -> undef
-  # /foo/bar -> {cb => sub {...}}
-  #          -> {controller => 'foo', action => 'bar'}
-  my $foo = $r->bridge('/foo')->to(cb => sub {
-    my $c = shift;
-
-    # Wait 3 seconds and then give visitors a 50% chance to continue
-    Mojo::IOLoop->timer(3 => sub {
-
-      # Loser
-      return $c->render(text => 'No luck.') unless int rand 2;
-
-      # Winner
-      $c->continue;
-    });
-
-    return undef;
-  });
-  $foo->route('/bar')->to(controller => 'foo', action => 'bar');
-
-=head2 More convenient routes
-
-From the tutorial you should already know L<Mojolicious::Lite> routes, which
-are in fact just a small convenience layer around everything described above
-and accessible through methods like L<Mojolicious::Routes::Route/"get"> and
-L<Mojolicious::Routes::Route/"any"> as part of the normal router.
-
-  # POST /foo -> {controller => 'foo', action => 'abc'}
-  $r->post('/foo')->to(controller => 'foo', action => 'abc');
+=head2 Catch-all route
 
-  # PATCH /bar -> {controller => 'foo', action => 'bar', test => 23}
-  $r->patch('/bar')->to('foo#bar', test => 23);
+Since routes match in the order in which they were defined, you can catch all
+requests that did not match in your last route with an optional wildcard
+placeholder.
 
-  # GET /baz -> {template => 'foo/bar'}
-  $r->get('/baz')->to(template => 'foo/bar');
-
-  # * /yada.txt  -> {controller => 'foo', action => 'yada', format => 'txt'}
-  # * /yada.json -> {controller => 'foo', action => 'yada', format => 'json'}
-  $r->any('/yada' => [format => [qw(txt json)]])->to('foo#yada');
-
-  # GET   /foo/bar  -> {controller => 'foo', action => 'bar'}
-  # PUT   /foo/baz  -> {controller => 'foo', action => 'baz'}
-  # PATCH /foo      -> {controller => 'foo', action => 'yada'}
-  my $foo = $r->any('/foo')->to('foo#');
-  $foo->get('/bar')->to('#bar');
-  $foo->put('/baz')->to('#baz');
-  $foo->patch->to('#yada');
-
-This makes the process of growing your L<Mojolicious::Lite> prototypes into
-full L<Mojolicious> applications very straightforward.
-
-  # POST /bar
-  $r->post('/bar' => sub {
-    my $c = shift;
-    $c->render(text => 'Just like a Mojolicious::Lite action.');
-  });
-
-Even the more abstract concepts are available with methods like
-L<Mojolicious::Routes::Route/"under">.
-
-  # GET  /yada
-  # POST /yada
-  my $yada = $r->under('/yada');
-  $yada->get(sub {
-    my $c = shift;
-    $c->render(text => 'Hello.');
-  });
-  $yada->post(sub {
-    my $c = shift;
-    $c->render(text => 'Go away.');
+  # * /*
+  $r->any('/*whatever' => {whatever => ''} => sub {
+    my $c        = shift;
+    my $whatever = $c->param('whatever');
+    $c->render(text => "/$whatever did not match.", status => 404);
   });
 
 =head2 Hooks
@@ -742,6 +719,22 @@ You can even extend much of the core functionality.
 
 For a full list of available hooks see L<Mojolicious/"HOOKS">.
 
+=head2 Introspection
+
+The command L<Mojolicious::Command::routes> can be used from the command line
+to list all available routes together with name and underlying regular
+expressions.
+
+  $ ./myapp.pl routes -v
+  /foo/:name  ....  POST  fooname  ^/foo/([^/\.]+)  ^/?(?:\.([^/]+))?$
+  /bar        ..U.  *     bar      ^/bar
+    +/baz     ...W  GET   baz      ^/baz            ^/?(?:\.([^/]+))?$
+  /yada       ....  *     yada     ^/yada           ^/?(?:\.([^/]+))?$
+
+=head1 ADVANCED
+
+Less commonly used and more powerful features.
+
 =head2 Shortcuts
 
 You can also add your own shortcuts with L<Mojolicious::Routes/"add_shortcut">
@@ -752,7 +745,7 @@ to make route generation more expressive.
     my ($r, $name) = @_;
 
     # Generate "/$name" route
-    my $resource = $r->route("/$name")->to("$name#");
+    my $resource = $r->any("/$name")->to("$name#");
 
     # Handle POST requests
     $resource->post->to('#create')->name("create_$name");
@@ -772,36 +765,9 @@ to make route generation more expressive.
 
   # POST    /user -> {controller => 'user', action => 'create'}
   # GET     /user -> {controller => 'user', action => 'show'}
-  # OPTIONS /user
+  # OPTIONS /user -> {cb => sub {...}}
   $r->resource('user');
 
-Shortcuts can lead to anything, routes, bridges or maybe even both. And watch
-out for quicksand!
-
-=head2 Introspection
-
-The command L<Mojolicious::Command::routes> can be used from the command line
-to list all available routes together with name and underlying regular
-expressions.
-
-  $ ./myapp.pl routes -v
-  /foo/:name  ....  POST  fooname  ^/foo/([^/\.]+))(?:\.([^/]+)$)?
-  /bar        B...  *     bar      ^/bar
-    +/baz     ...W  GET   baz      ^/baz(?:\.([^/]+)$)?
-  /yada       ....  *     yada     ^/yada(?:\.([^/]+)$)?
-
-=head1 ADVANCED
-
-Less commonly used and more powerful features.
-
-=head2 IRIs
-
-IRIs are handled transparently, that means paths are guaranteed to be
-unescaped and decoded from bytes to characters.
-
-  # GET /☃ (unicode snowman) -> {controller => 'foo', action => 'snowman'}
-  $r->get('/☃')->to('foo#snowman');
-
 =head2 Rearranging routes
 
 Until the first request has been handled, all routes can still be moved around
@@ -904,7 +870,7 @@ controller. This allows for example the use of the L<Mojolicious::Lite> domain
 specific language in normal L<Mojolicious> controllers.
 
   # Controller
-  package MyApp::Bar;
+  package MyApp::Controller::Bar;
   use Mojolicious::Lite;
 
   # /hello
@@ -927,7 +893,7 @@ path will be passed along in the C<path> stash value.
 A minimal embeddable application is nothing more than a subclass of L<Mojo>,
 containing a C<handler> method accepting L<Mojolicious::Controller> objects.
 
-  package MyApp::Bar;
+  package MyApp::Controller::Bar;
   use Mojo::Base 'Mojo';
 
   sub handler {
@@ -8,9 +8,8 @@ Mojolicious::Guides - Mojolicious guide to the galaxy
 =head1 DON'T PANIC!
 
 We are constantly working on new documentation, follow us on
-L<Twitter|http://twitter.com/kraih>, L<GitHub|http://github.com/kraih/mojo>
-or join the official IRC channel C<#mojo> on C<irc.perl.org> to get all the
-latest updates.
+L<GitHub|http://github.com/kraih/mojo> or join the official IRC channel
+C<#mojo> on C<irc.perl.org> to get all the latest updates.
 
 =head1 LEARNING PERL
 
@@ -22,6 +21,11 @@ available in many formats. Both are excellent introductions to the language.
 For more books and documentation, check out
 L<learn.perl.org|http://learn.perl.org/>.
 
+=head1 LEARNING HTML
+
+All web development starts with HTML, to learn the basics we recommend the
+L<Mozilla Developer Network|https://developer.mozilla.org/en-US/learn/html>.
+
 =head1 TUTORIAL
 
 =over 2
@@ -44,7 +48,7 @@ therefore considered a prerequisite, you should definitely take a look!
 =item L<Mojolicious::Guides::Growing>
 
 Starting a L<Mojolicious::Lite> prototype from scratch and growing it into a
-well structured L<Mojolicious> application.
+well-structured L<Mojolicious> application.
 
 =item L<Mojolicious::Guides::Routing>
 
@@ -122,23 +126,6 @@ Fun one-liners using everything above.
 
 =back
 
-=head1 SPIN-OFFS
-
-These modules are not part of the L<Mojolicious> distribution, but have been
-designed to be used with it and are being developed under the same umbrella.
-
-=over 2
-
-=item L<Mango>
-
-Pure-Perl non-blocking I/O MongoDB driver.
-
-=item L<Minion>
-
-Job queue.
-
-=back
-
 =head1 REFERENCE
 
 This is the class hierarchy of the L<Mojolicious> distribution.
@@ -87,15 +87,15 @@ L<Mojolicious>.
 =head1 TUTORIAL
 
 A quick example driven introduction to the wonders of L<Mojolicious::Lite>.
-Most of what you'll learn here also applies to normal L<Mojolicious>
+Most of what you'll learn here also applies to full L<Mojolicious>
 applications.
 
 =head2 Hello World
 
 A simple Hello World application can look like this, L<strict>, L<warnings>,
-L<utf8> and Perl 5.10 features are automatically enabled and a few functions
-imported when you use L<Mojolicious::Lite>, turning your script into a full
-featured web application.
+L<utf8> and Perl 5.10 features are automatically enabled and a few
+L</"FUNCTIONS"> imported when you use L<Mojolicious::Lite>, turning your
+script into a full featured web application.
 
   #!/usr/bin/env perl
   use Mojolicious::Lite;
@@ -262,11 +262,9 @@ only the information you're actually interested in.
 =head2 Route names
 
 All routes can have a name associated with them, this allows automatic
-template detection and back referencing with
-L<Mojolicious::Controller/"url_for"> as well as many helpers like
-L<Mojolicious::Plugin::TagHelpers/"link_to">. Nameless routes get an
-automatically generated one assigned that is simply equal to the route itself
-without non-word characters.
+template detection and backreferencing with
+L<Mojolicious::Controller/"url_for">, on which many methods and helpers like
+L<Mojolicious::Plugin::TagHelpers/"link_to"> rely.
 
   use Mojolicious::Lite;
 
@@ -289,6 +287,9 @@ without non-word characters.
   @@ hello.html.ep
   Hello World!
 
+Nameless routes get an automatically generated one assigned that is simply
+equal to the route itself without non-word characters.
+
 =head2 Layouts
 
 Templates can have layouts too, you just select one with the helper
@@ -347,9 +348,8 @@ many helpers.
 
 =head2 Helpers
 
-You can also extend L<Mojolicious> with your own helpers, a list of all
-built-in ones can be found in L<Mojolicious::Plugin::DefaultHelpers> and
-L<Mojolicious::Plugin::TagHelpers>.
+Helpers are little functions you can reuse throughout your whole application,
+from actions to templates.
 
   use Mojolicious::Lite;
 
@@ -374,6 +374,9 @@ L<Mojolicious::Plugin::TagHelpers>.
   @@ secret.html.ep
   We know who you are <%= whois %>.
 
+A list of all built-in ones can be found in
+L<Mojolicious::Plugin::DefaultHelpers> and L<Mojolicious::Plugin::TagHelpers>.
+
 =head2 Placeholders
 
 Route placeholders allow capturing parts of a request path until a C</> or
@@ -472,8 +475,7 @@ Routes can be restricted to specific request methods with different keywords.
 =head2 Optional placeholders
 
 All placeholders require a value, but by assigning them default values you can
-make capturing optional. Default values that don't belong to a placeholder
-simply get merged into the stash all the time.
+make capturing optional.
 
   use Mojolicious::Lite;
 
@@ -490,6 +492,9 @@ simply get merged into the stash all the time.
   @@ groovy.txt.ep
   My name is <%= $name %> and it is <%= $day %>.
 
+Default values that don't belong to a placeholder simply get merged into the
+stash all the time.
+
 =head2 Restrictive placeholders
 
 The easiest way to make placeholders more restrictive are alternatives, you
@@ -529,8 +534,8 @@ is fine though.
 =head2 Under
 
 Authentication and code shared between multiple routes can be realized easily
-with bridge routes generated by the L</"under"> statement. All following
-routes are only evaluated if the callback returned a true value.
+with routes generated by the L</"under"> statement. All following routes are
+only evaluated if the callback returned a true value.
 
   use Mojolicious::Lite;
 
@@ -615,10 +620,12 @@ L</"under"> statements.
 
 =head2 Formats
 
-Formats can be automatically detected by looking at file extensions.
+Formats can be automatically detected from file extensions, they are used to
+find the right template and generate the correct C<Content-Type> header.
 
   use Mojolicious::Lite;
 
+  # /detection
   # /detection.html
   # /detection.txt
   get '/detection' => sub {
@@ -639,7 +646,8 @@ Formats can be automatically detected by looking at file extensions.
   @@ detected.txt.ep
   TXT was detected.
 
-Restrictive placeholders can also be used.
+The default format is C<html>, restrictive placeholders can be used to limit
+possible values.
 
   use Mojolicious::Lite;
 
@@ -725,7 +733,12 @@ served automatically from a C<public> directory if it exists.
   $ mv something.js public/something.js
   $ mv mojolicious.tar.gz public/mojolicious.tar.gz
 
-Both have a higher precedence than routes.
+Both have a higher precedence than routes for C<GET> and C<HEAD> requests.
+Content negotiation with C<Range>, C<If-None-Match> and C<If-Modified-Since>
+headers is supported as well and can be tested very easily with
+L<Mojolicious::Command::get>.
+
+  $ ./myapp.pl get /something.js -v -H 'Range: bytes=2-4'
 
 =head2 External templates
 
@@ -1013,6 +1026,7 @@ automatically exported.
   my $route = any '/:foo' => {foo => 'bar'} => sub {...};
   my $route = any '/:foo' => [foo => qr/\w+/] => sub {...};
   my $route = any [qw(GET POST)] => '/:foo' => sub {...};
+  my $route = any [qw(GET POST)] => '/:foo' => [foo => qr/\w+/] => sub {...};
 
 Generate route with L<Mojolicious::Routes::Route/"any">, matching any of the
 listed HTTP request methods or all. See also the tutorial above for many more
@@ -1022,7 +1036,12 @@ argument variations.
 
   my $app = app;
 
-The L<Mojolicious::Lite> application.
+Returns the L<Mojolicious::Lite> application object, which is a subclass of
+L<Mojolicious>.
+
+  # Use all the available attributes and methods
+  app->log->level('error');
+  app->defaults(foo => 'bar');
 
 =head2 del
 
@@ -1108,12 +1127,13 @@ requests. See also the tutorial above for many more argument variations.
 
 =head2 under
 
-  my $bridge = under sub {...};
-  my $bridge = under '/:foo' => sub {...};
-  my $bridge = under '/:foo' => [foo => qr/\w+/];
-  my $bridge = under {format => 0};
+  my $route = under sub {...};
+  my $route = under '/:foo' => sub {...};
+  my $route = under '/:foo' => {foo => 'bar'};
+  my $route = under '/:foo' => [foo => qr/\w+/];
+  my $route = under [format => 0];
 
-Generate bridge route with L<Mojolicious::Routes::Route/"under">, to which all
+Generate nested route with L<Mojolicious::Routes::Route/"under">, to which all
 following routes are automatically appended. See also the tutorial above for
 more argument variations.
 
@@ -17,7 +17,7 @@ sub parse {
   my $config
     = eval 'package Mojolicious::Plugin::Config::Sandbox; no warnings;'
     . "sub app; local *app = sub { \$app }; use Mojo::Base -strict; $content";
-  die qq{Couldn't load configuration from file "$file": $@} if !$config && $@;
+  die qq{Can't load configuration from file "$file": $@} if !$config && $@;
   die qq{Configuration file "$file" did not return a hash reference.\n}
     unless ref $config eq 'HASH';
 
@@ -3,6 +3,7 @@ use Mojo::Base 'Mojolicious::Plugin';
 
 use Mojo::ByteStream;
 use Mojo::Collection;
+use Mojo::Exception;
 use Mojo::IOLoop;
 use Mojo::Util qw(dumper sha1_sum steady_time);
 
@@ -16,31 +17,32 @@ sub register {
 
   # Stash key shortcuts (should not generate log messages)
   for my $name (qw(extends layout title)) {
-    $app->helper(
-      $name => sub {
-        my $c     = shift;
-        my $stash = $c->stash;
-        $stash->{$name} = shift if @_;
-        $c->stash(@_) if @_;
-        return $stash->{$name};
-      }
-    );
+    $app->helper($name => sub { shift->stash($name, @_) });
   }
 
-  $app->helper($_ => $self->can("_$_"))
-    for qw(accepts content content_for csrf_token current_route delay),
-    qw(inactivity_timeout url_with);
-  $app->helper(b => sub { shift; Mojo::ByteStream->new(@_) });
-  $app->helper(c => sub { shift; Mojo::Collection->new(@_) });
+  $app->helper(accepts => sub { $_[0]->app->renderer->accepts(@_) });
+  $app->helper(b       => sub { shift; Mojo::ByteStream->new(@_) });
+  $app->helper(c       => sub { shift; Mojo::Collection->new(@_) });
   $app->helper(config  => sub { shift->app->config(@_) });
-  $app->helper(dumper  => sub { shift; dumper(@_) });
+
+  $app->helper($_ => $self->can("_$_"))
+    for qw(content content_for csrf_token current_route delay),
+    qw(inactivity_timeout is_fresh url_with);
+
+  $app->helper(dumper => sub { shift; dumper(@_) });
   $app->helper(include => sub { shift->render_to_string(@_) });
-  $app->helper(ua      => sub { shift->app->ua });
+
+  $app->helper("reply.$_" => $self->can("_$_")) for qw(asset static);
+
+  $app->helper('reply.exception' => sub { _development('exception', @_) });
+  $app->helper('reply.not_found' => sub { _development('not_found', @_) });
+  $app->helper(ua                => sub { shift->app->ua });
 }
 
-sub _accepts {
+sub _asset {
   my $c = shift;
-  return $c->app->renderer->accepts($c, @_);
+  $c->app->static->serve_asset($c, @_);
+  $c->rendered;
 }
 
 sub _content {
@@ -70,16 +72,59 @@ sub _csrf_token {
 }
 
 sub _current_route {
-  return '' unless my $endpoint = shift->match->endpoint;
-  return $endpoint->name unless @_;
-  return $endpoint->name eq shift;
+  return '' unless my $route = shift->match->endpoint;
+  return @_ ? $route->name eq shift : $route->name;
 }
 
 sub _delay {
-  my $self  = shift;
-  my $tx    = $self->render_later->tx;
+  my $c     = shift;
+  my $tx    = $c->render_later->tx;
   my $delay = Mojo::IOLoop->delay(@_);
-  $delay->catch(sub { $self->render_exception(pop) and undef $tx })->wait;
+  $delay->catch(sub { $c->render_exception(pop) and undef $tx })->wait;
+}
+
+sub _development {
+  my ($page, $c, $e) = @_;
+
+  my $app = $c->app;
+  $app->log->error($e = Mojo::Exception->new($e)) if $page eq 'exception';
+
+  # Filtered stash snapshot
+  my $stash = $c->stash;
+  my %snapshot = map { $_ => $stash->{$_} }
+    grep { !/^mojo\./ and defined $stash->{$_} } keys %$stash;
+
+  # Render with fallbacks
+  my $mode     = $app->mode;
+  my $renderer = $app->renderer;
+  my $options  = {
+    exception => $page eq 'exception' ? $e : undef,
+    format => $stash->{format} || $renderer->default_format,
+    handler  => undef,
+    snapshot => \%snapshot,
+    status   => $page eq 'exception' ? 500 : 404,
+    template => "$page.$mode"
+  };
+  my $inline = $renderer->_bundled($mode eq 'development' ? $mode : $page);
+  return $c if _fallbacks($c, $options, $page, $inline);
+  _fallbacks($c, {%$options, format => 'html'}, $page, $inline);
+  return $c;
+}
+
+sub _fallbacks {
+  my ($c, $options, $template, $inline) = @_;
+
+  # Mode specific template
+  return 1 if $c->render_maybe(%$options);
+
+  # Normal template
+  return 1 if $c->render_maybe(%$options, template => $template);
+
+  # Inline template
+  my $stash = $c->stash;
+  return undef unless $stash->{format} eq 'html';
+  delete @$stash{qw(extends layout)};
+  return $c->render_maybe(%$options, inline => $inline, handler => 'ep');
 }
 
 sub _inactivity_timeout {
@@ -87,6 +132,18 @@ sub _inactivity_timeout {
   $stream->timeout(shift);
 }
 
+sub _is_fresh {
+  my ($c, %options) = @_;
+  return $c->app->static->is_fresh($c, \%options);
+}
+
+sub _static {
+  my ($c, $file) = @_;
+  return !!$c->rendered if $c->app->static->serve($c, $file);
+  $c->app->log->debug(qq{File "$file" not found, public directory missing?});
+  return !$c->render_not_found;
+}
+
 sub _url_with {
   my $c = shift;
   return $c->url_for(@_)->query($c->req->url->query->clone);
@@ -110,7 +167,7 @@ Mojolicious::Plugin::DefaultHelpers - Default helpers plugin
 
 =head1 DESCRIPTION
 
-L<Mojolicious::Plugin::DefaultHelpers> is a collection of renderer helpers for
+L<Mojolicious::Plugin::DefaultHelpers> is a collection of helpers for
 L<Mojolicious>.
 
 This is a core plugin, that means it is always enabled and its code a good
@@ -225,13 +282,27 @@ Check or get name of current route.
 Disable automatic rendering and use L<Mojo::IOLoop/"delay"> to manage
 callbacks and control the flow of events, which can help you avoid deep nested
 closures and memory leaks that often result from continuation-passing style.
-Calls L<Mojolicious::Controller/"render_exception"> if an error occured in one
-of the steps, breaking the chain.
+Also keeps a reference to L<Mojolicious::Controller/"tx"> in case the
+underlying connection gets closed early, and calls L</"reply-E<gt>exception">
+if an exception gets thrown in one of the steps, breaking the chain.
 
   # Longer version
   $c->render_later;
+  my $tx    = $c->tx;
   my $delay = Mojo::IOLoop->delay(sub {...}, sub {...});
-  $delay->catch(sub { $c->render_exception(pop) })->wait;
+  $delay->catch(sub { $c->reply->exception(pop) and undef $tx })->wait;
+
+  # Non-blocking request
+  $c->delay(
+    sub {
+      my $delay = shift;
+      $c->ua->get('http://mojolicio.us' => $delay->begin);
+    },
+    sub {
+      my ($delay, $tx) = @_;
+      $c->render(json => {title => $tx->res->dom->at('title')->text});
+    }
+  );
 
 =head2 dumper
 
@@ -270,6 +341,21 @@ timeout if possible.
 
 Alias for C<Mojolicious::Controller/"render_to_string">.
 
+=head2 is_fresh
+
+  my $bool = $c->is_fresh;
+  my $bool = $c->is_fresh(etag => 'abc');
+  my $bool = $c->is_fresh(last_modified => $epoch);
+
+Check freshness of request by comparing the C<If-None-Match> and
+C<If-Modified-Since> request headers to the C<ETag> and C<Last-Modified>
+response headers with L<Mojolicious::Static/"is_fresh">.
+
+  # Add ETag header and check freshness before rendering
+  $c->is_fresh(etag => 'abc')
+    ? $c->rendered(304)
+    : $c->render(text => 'I ♥ Mojolicious!');
+
 =head2 layout
 
   % layout 'green';
@@ -284,6 +370,52 @@ L</"stash">.
 
 Alias for L<Mojolicious::Controller/"param">.
 
+=head2 reply->asset
+
+  $c->reply->asset(Mojo::Asset::File->new);
+
+Reply with a L<Mojo::Asset::File> or L<Mojo::Asset::Memory> object using
+L<Mojolicious::Static/"serve_asset">, and perform content negotiation with
+C<Range>, C<If-Modified-Since> and C<If-None-Match> headers.
+
+  # Serve asset with custom modification time
+  my $asset = Mojo::Asset::Memory->new;
+  $asset->add_chunk('Hello World!')->mtime(784111777);
+  $c->res->headers->content_type('text/plain');
+  $c->reply->asset($asset);
+
+=head2 reply->exception
+
+  $c = $c->reply->exception('Oops!');
+  $c = $c->reply->exception(Mojo::Exception->new('Oops!'));
+
+Render the exception template C<exception.$mode.$format.*> or
+C<exception.$format.*> and set the response status code to C<500>. Also sets
+the stash values C<exception> to a L<Mojo::Exception> object and C<snapshot>
+to a copy of the L</"stash"> for use in the templates.
+
+=head2 reply->not_found
+
+  $c = $c->reply->not_found;
+
+Render the not found template C<not_found.$mode.$format.*> or
+C<not_found.$format.*> and set the response status code to C<404>. Also sets
+the stash value C<snapshot> to a copy of the L</"stash"> for use in the
+templates.
+
+=head2 reply->static
+
+  my $bool = $c->reply->static('images/logo.png');
+  my $bool = $c->reply->static('../lib/MyApp.pm');
+
+Reply with a static file using L<Mojolicious::Static/"serve">, usually from
+the C<public> directories or C<DATA> sections of your application. Note that
+this helper does not protect from traversing to parent directories.
+
+  # Serve file with a custom content type
+  $c->res->headers->content_type('application/myapp');
+  $c->reply->static('foo.txt');
+
 =head2 session
 
   %= session 'foo'
@@ -301,11 +433,11 @@ Alias for L<Mojolicious::Controller/"stash">.
 
 =head2 title
 
+  %= title
   % title 'Welcome!';
   % title 'Welcome!', foo => 'bar';
-  %= title
 
-Set C<title> stash value, all additional pairs get merged into the
+Get of set C<title> stash value, all additional pairs get merged into the
 L</"stash">.
 
 =head2 ua
@@ -9,17 +9,8 @@ sub register { $_[1]->renderer->add_handler(epl => \&_epl) }
 sub _epl {
   my ($renderer, $c, $output, $options) = @_;
 
-  # Template
-  my $name   = $renderer->template_name($options);
-  my $inline = $options->{inline};
-  $name = md5_sum encode('UTF-8', $inline) if defined $inline;
-  return undef unless defined $name;
-
   # Cached
-  my $key   = delete $options->{cache} || $name;
-  my $cache = $renderer->cache;
-  my $mt    = $cache->get($key);
-  $mt ||= $cache->set($key => Mojo::Template->new)->get($key);
+  my $mt = delete $options->{'mojo.template'} || Mojo::Template->new;
   my $log = $c->app->log;
   if ($mt->compiled) {
     $log->debug("Rendering cached @{[$mt->name]}.");
@@ -28,6 +19,9 @@ sub _epl {
 
   # Not cached
   else {
+    my $inline = $options->{inline};
+    my $name = defined $inline ? md5_sum encode('UTF-8', $inline) : undef;
+    return undef unless defined($name //= $renderer->template_name($options));
 
     # Inline
     if (defined $inline) {
@@ -37,7 +31,7 @@ sub _epl {
 
     # File
     else {
-      $mt->encoding($renderer->encoding) if $renderer->encoding;
+      if (my $encoding = $renderer->encoding) { $mt->encoding($encoding) }
 
       # Try template
       if (defined(my $path = $renderer->template_path($options))) {
@@ -79,8 +73,8 @@ Mojolicious::Plugin::EPLRenderer - Embedded Perl Lite renderer plugin
 
 =head1 DESCRIPTION
 
-L<Mojolicious::Plugin::EPLRenderer> is a renderer for C<epl> templates. C<epl>
-templates are pretty much just raw L<Mojo::Template>.
+L<Mojolicious::Plugin::EPLRenderer> is a renderer for C<epl> templates, which
+are pretty much just raw L<Mojo::Template>.
 
 This is a core plugin, that means it is always enabled and its code a good
 example for learning to build new plugins, you're welcome to fork it.
@@ -4,45 +4,47 @@ use Mojo::Base 'Mojolicious::Plugin';
 use Mojo::Template;
 use Mojo::Util qw(encode md5_sum monkey_patch);
 
+sub DESTROY { Mojo::Util::_teardown(shift->{namespace}) }
+
 sub register {
   my ($self, $app, $conf) = @_;
 
   # Auto escape by default to prevent XSS attacks
   my $template = {auto_escape => 1, %{$conf->{template} || {}}};
+  my $ns = $self->{namespace} = $template->{namespace}
+    //= 'Mojo::Template::Sandbox::' . md5_sum "$self";
 
   # Add "ep" handler and make it the default
   $app->renderer->default_handler('ep')->add_handler(
     $conf->{name} || 'ep' => sub {
       my ($renderer, $c, $output, $options) = @_;
 
-      # Generate name
-      my $name = $options->{inline} || $renderer->template_name($options);
+      my $name = $options->{inline} // $renderer->template_name($options);
       return undef unless defined $name;
       my @keys = sort grep {/^\w+$/} keys %{$c->stash};
-      my $id = encode 'UTF-8', join(',', $name, @keys);
-      my $key = $options->{cache} = md5_sum $id;
+      my $key = md5_sum encode 'UTF-8', join(',', $name, @keys);
 
-      # Cache template for "epl" handler
+      # Prepare template for "epl" handler
       my $cache = $renderer->cache;
-      my $mt    = $cache->get($key);
-      unless ($mt) {
-        $mt = Mojo::Template->new($template);
+      unless ($options->{'mojo.template'} = $cache->get($key)) {
+        my $mt = $options->{'mojo.template'} = Mojo::Template->new($template);
 
         # Helpers (only once)
-        ++$self->{helpers} and _helpers($mt->namespace, $renderer->helpers)
+        ++$self->{helpers} and _helpers($ns, $renderer->helpers)
           unless $self->{helpers};
 
         # Stash values (every time)
-        my $prepend = 'my $self = my $c = shift; my $_S = $c->stash;';
-        $prepend .= " my \$$_ = \$_S->{'$_'};" for @keys;
+        my $prepend = 'my $self = my $c = shift; my $_S = $c->stash; {';
+        $prepend .= join '', map {" my \$$_ = \$_S->{'$_'};"} @keys;
+        $mt->prepend($prepend . $mt->prepend)->append('}' . $mt->append);
 
-        $cache->set($key => $mt->prepend($prepend . $mt->prepend));
+        $cache->set($key => $mt);
       }
 
       # Make current controller available
       no strict 'refs';
       no warnings 'redefine';
-      local *{"@{[$mt->namespace]}::_C"} = sub {$c};
+      local *{"${ns}::_C"} = sub {$c};
 
       # Render with "epl" handler
       return $renderer->handlers->{epl}->($renderer, $c, $output, $options);
@@ -51,10 +53,10 @@ sub register {
 }
 
 sub _helpers {
-  my ($ns, $helpers) = @_;
-  for my $name (grep {/^\w+$/} keys %$helpers) {
-    monkey_patch $ns, $name,
-      sub { $ns->_C->app->renderer->helpers->{$name}->($ns->_C, @_) };
+  my ($class, $helpers) = @_;
+  for my $method (grep {/^\w+$/} keys %$helpers) {
+    my $sub = $helpers->{$method};
+    monkey_patch $class, $method, sub { $class->_C->$sub(@_) };
   }
 }
 
@@ -80,13 +82,14 @@ Mojolicious::Plugin::EPRenderer - Embedded Perl renderer plugin
 
 =head1 DESCRIPTION
 
-L<Mojolicious::Plugin::EPRenderer> is a renderer for C<ep> templates.
+L<Mojolicious::Plugin::EPRenderer> is a renderer for C<ep> or C<Embedded Perl>
+templates.
 
-C<ep> or C<Embedded Perl> is a simple template format where you embed perl
-code into documents. It is based on L<Mojo::Template>, but extends it with
-some convenient syntax sugar designed specifically for L<Mojolicious>. It
-supports L<Mojolicious> template helpers and exposes the stash directly as
-Perl variables.
+C<Embedded Perl> is a simple template format where you embed perl code into
+documents. It is based on L<Mojo::Template>, but extends it with some
+convenient syntax sugar designed specifically for L<Mojolicious>. It supports
+L<Mojolicious> template helpers and exposes the stash directly as Perl
+variables.
 
 This is a core plugin, that means it is always enabled and its code a good
 example for learning to build new plugins, you're welcome to fork it.
@@ -11,7 +11,7 @@ sub parse {
   my $json   = Mojo::JSON->new;
   my $config = $json->decode($self->render($content, $file, $conf, $app));
   my $err    = $json->error;
-  die qq{Couldn't parse config "$file": $err} if !$config && $err;
+  die qq{Can't parse config "$file": $err} if !$config && $err;
   die qq{Invalid config "$file"} if !$config || ref $config ne 'HASH';
 
   return $config;
@@ -17,9 +17,7 @@ sub register {
   }
 
   my $route = $app->routes->route($path)->detour(app => $embed);
-  $route->over(host => $host) if $host;
-
-  return $route;
+  return $host ? $route->over(host => $host) : $route;
 }
 
 1;
@@ -6,7 +6,7 @@ use Mojo::ByteStream 'b';
 use Mojo::DOM;
 use Mojo::URL;
 use Mojo::Util qw(slurp unindent url_escape);
-use Pod::Simple::HTML;
+use Pod::Simple::XHTML 3.09;
 use Pod::Simple::Search;
 
 sub register {
@@ -35,19 +35,17 @@ sub register {
 }
 
 sub _html {
-  my ($self, $src) = @_;
+  my ($c, $src) = @_;
 
   # Rewrite links
   my $dom     = Mojo::DOM->new(_pod_to_html($src));
-  my $perldoc = $self->url_for('/perldoc/');
-  for my $e ($dom->find('a[href]')->each) {
-    my $attrs = $e->attr;
-    $attrs->{href} =~ s!%3A%3A!/!gi
-      if $attrs->{href} =~ s!^http://search\.cpan\.org/perldoc\?!$perldoc!;
-  }
+  my $perldoc = $c->url_for('/perldoc/');
+  $_->{href} =~ s!^http://metacpan\.org/pod/!$perldoc!
+    and $_->{href} =~ s!::!/!gi
+    for $dom->find('a[href]')->attr->each;
 
   # Rewrite code blocks for syntax highlighting and correct indentation
-  for my $e ($dom->find('pre')->each) {
+  for my $e ($dom->find('pre > code')->each) {
     $e->content(my $str = unindent $e->content);
     next if $str =~ /^\s*(?:\$|Usage:)\s+/m || $str !~ /[\$\@\%]\w|-&gt;\w/m;
     my $attrs = $e->attr;
@@ -57,23 +55,15 @@ sub _html {
 
   # Rewrite headers
   my $toc = Mojo::URL->new->fragment('toc');
-  my (%anchors, @parts);
+  my @parts;
   for my $e ($dom->find('h1, h2, h3')->each) {
 
-    # Anchor and text
-    my $name = my $text = $e->all_text;
-    $name =~ s/\s+/_/g;
-    $name =~ s/[^\w\-]//g;
-    my $anchor = $name;
-    my $i      = 1;
-    $anchor = $name . $i++ while $anchors{$anchor}++;
-
-    # Rewrite
     push @parts, [] if $e->type eq 'h1' || !@parts;
-    my $link = Mojo::URL->new->fragment($anchor);
-    push @{$parts[-1]}, $text, $link;
-    my $permalink = $self->link_to('#' => $link, class => 'permalink');
-    $e->content($permalink . $self->link_to($text => $toc, id => $anchor));
+    my $anchor = $e->{id};
+    my $link   = Mojo::URL->new->fragment($anchor);
+    push @{$parts[-1]}, my $text = $e->all_text, $link;
+    my $permalink = $c->link_to('#' => $link, class => 'permalink');
+    $e->content($permalink . $c->link_to($text => $toc, id => $anchor));
   }
 
   # Try to find a title
@@ -81,39 +71,34 @@ sub _html {
   $dom->find('h1 + p')->first(sub { $title = shift->text });
 
   # Combine everything to a proper response
-  $self->content_for(perldoc => "$dom");
-  my $template = $self->app->renderer->_bundled('perldoc');
-  $self->render(inline => $template, title => $title, parts => \@parts);
+  $c->content_for(perldoc => "$dom");
+  my $template = $c->app->renderer->_bundled('perldoc');
+  $c->render(inline => $template, title => $title, parts => \@parts);
 }
 
 sub _perldoc {
-  my $self = shift;
+  my $c = shift;
 
   # Find module or redirect to CPAN
-  my $module = $self->param('module');
-  $module =~ s!/!::!g;
+  my $module = join '::', split '/', scalar $c->param('module');
   my $path
     = Pod::Simple::Search->new->find($module, map { $_, "$_/pods" } @INC);
-  return $self->redirect_to("http://metacpan.org/module/$module")
+  return $c->redirect_to("http://metacpan.org/pod/$module")
     unless $path && -r $path;
 
   my $src = slurp $path;
-  $self->respond_to(txt => {data => $src}, html => sub { _html($self, $src) });
+  $c->respond_to(txt => {data => $src}, html => sub { _html($c, $src) });
 }
 
 sub _pod_to_html {
   return '' unless defined(my $pod = ref $_[0] eq 'CODE' ? shift->() : shift);
 
-  my $parser = Pod::Simple::HTML->new;
-  $parser->$_('') for qw(force_title html_header_before_title);
-  $parser->$_('') for qw(html_header_after_title html_footer);
+  my $parser = Pod::Simple::XHTML->new;
+  $parser->perldoc_url_prefix('http://metacpan.org/pod/');
+  $parser->$_('') for qw(html_header html_footer);
   $parser->output_string(\(my $output));
   return $@ unless eval { $parser->parse_string_document("$pod"); 1 };
 
-  # Filter
-  $output =~ s!<a name='___top' class='dummyTopAnchor'\s*?></a>\n!!g;
-  $output =~ s!<a class='u'.*?name=".*?"\s*>(.*?)</a>!$1!sg;
-
   return $output;
 }
 
@@ -45,7 +45,7 @@ sub register {
 
 sub _csrf_field {
   my $c = shift;
-  return _hidden_field($c, csrf_token => $c->csrf_token, @_);
+  return _hidden_field($c, csrf_token => $c->helpers->csrf_token, @_);
 }
 
 sub _form_for {
@@ -246,7 +246,7 @@ sub _text_area {
 sub _validation {
   my ($c, $name) = (shift, shift);
   return _tag(@_) unless $c->validation->has_error($name);
-  return $c->tag_with_error(@_);
+  return $c->helpers->tag_with_error(@_);
 }
 
 1;
@@ -7,7 +7,7 @@ has namespaces => sub { ['Mojolicious::Plugin'] };
 
 sub emit_hook {
   my $self = shift;
-  $_->(@_) for @{$self->subscribers(shift)};
+  for my $cb (@{$self->subscribers(shift)}) { $cb->(@_) }
   return $self;
 }
 
@@ -25,7 +25,7 @@ sub emit_chain {
 
 sub emit_hook_reverse {
   my $self = shift;
-  $_->(@_) for reverse @{$self->subscribers(shift)};
+  for my $cb (reverse @{$self->subscribers(shift)}) { $cb->(@_) }
   return $self;
 }
 
@@ -34,10 +34,7 @@ sub load_plugin {
 
   # Try all namespaces
   my $class = $name =~ /^[a-z]/ ? camelize($name) : $name;
-  for my $ns (@{$self->namespaces}) {
-    my $module = "${ns}::$class";
-    return $module->new if _load($module);
-  }
+  _load($_) and return $_->new for map {"${_}::$class"} @{$self->namespaces};
 
   # Full module name
   return $name->new if _load($name);
@@ -52,10 +49,9 @@ sub register_plugin {
 
 sub _load {
   my $module = shift;
-  if (my $e = Mojo::Loader->new->load($module)) {
-    ref $e ? die $e : return undef;
-  }
-  return $module->isa('Mojolicious::Plugin');
+  return $module->isa('Mojolicious::Plugin')
+    unless my $e = Mojo::Loader->new->load($module);
+  ref $e ? die $e : return undef;
 }
 
 1;
@@ -70,7 +66,7 @@ Mojolicious::Plugins - Plugin manager
 
   use Mojolicious::Plugins;
 
-  my $plugins = Mojolicious::Plugin->new;
+  my $plugins = Mojolicious::Plugins->new;
   push @{$plugins->namespaces}, 'MyApp::Plugin';
 
 =head1 DESCRIPTION
@@ -6,7 +6,7 @@ use Mojo::Cache;
 use Mojo::JSON 'encode_json';
 use Mojo::Home;
 use Mojo::Loader;
-use Mojo::Util qw(decamelize encode slurp);
+use Mojo::Util qw(decamelize encode md5_sum monkey_patch slurp);
 
 has cache   => sub { Mojo::Cache->new };
 has classes => sub { ['main'] };
@@ -29,6 +29,10 @@ $HOME->parse(
   $HOME->parse($HOME->mojo_lib_dir)->rel_dir('Mojolicious/templates'));
 my %TEMPLATES = map { $_ => slurp $HOME->rel_file($_) } @{$HOME->list_files};
 
+my $LOADER = Mojo::Loader->new;
+
+sub DESTROY { Mojo::Util::_teardown($_) for @{shift->{namespaces}} }
+
 sub accepts {
   my ($self, $c) = (shift, shift);
 
@@ -53,23 +57,31 @@ sub add_helper  { shift->_add(helpers  => @_) }
 sub get_data_template {
   my ($self, $options) = @_;
 
-  # Index DATA templates
-  my $loader = Mojo::Loader->new;
-  unless ($self->{index}) {
-    my $index = $self->{index} = {};
-    for my $class (reverse @{$self->classes}) {
-      $index->{$_} = $class for keys %{$loader->data($class)};
-    }
+  # Find template
+  return undef unless my $template = $self->template_name($options);
+  return $LOADER->data($self->{index}{$template}, $template);
+}
+
+sub get_helper {
+  my ($self, $name) = @_;
+
+  if (my $h = $self->{proxy}{$name} || $self->helpers->{$name}) { return $h }
+
+  my $found;
+  my $class = 'Mojolicious::Renderer::Helpers::' . md5_sum "$name:$self";
+  my $re = $name eq '' ? qr/^(([^.]+))/ : qr/^(\Q$name\E\.([^.]+))/;
+  for my $key (keys %{$self->helpers}) {
+    $key =~ $re ? ($found, my $method) = (1, $2) : next;
+    my $sub = $self->get_helper($1);
+    monkey_patch $class, $method => sub { ${shift()}->$sub(@_) };
   }
 
-  # Find template
-  my $template = $self->template_name($options);
-  return $loader->data($self->{index}{$template}, $template);
+  $found ? push @{$self->{namespaces}}, $class : return undef;
+  return $self->{proxy}{$name} = sub { bless \(my $dummy = shift), $class };
 }
 
 sub render {
   my ($self, $c, $args) = @_;
-  $args ||= {};
 
   # Localize "extends" and "layout" to allow argument overrides
   my $stash = $c->stash;
@@ -81,7 +93,7 @@ sub render {
   delete @{$stash}{qw(layout extends)} if $ts;
 
   # Merge stash and arguments
-  %$stash = (%$stash, %$args);
+  @$stash{keys %$args} = values %$args;
 
   my $options = {
     encoding => $self->encoding,
@@ -146,14 +158,15 @@ sub template_for {
     if $controller && $action;
 
   # Try the route name if we don't have controller and action
-  return undef unless my $endpoint = $c->match->endpoint;
-  return $endpoint->name;
+  return undef unless my $route = $c->match->endpoint;
+  return $route->name;
 }
 
 sub template_handler {
   my ($self, $options) = @_;
   return undef unless my $file = $self->template_name($options);
-  return $self->default_handler unless my $handlers = $self->_handlers($file);
+  return $self->default_handler
+    unless my $handlers = $self->{templates}{$file};
   return $handlers->[0];
 }
 
@@ -164,11 +177,13 @@ sub template_name {
   return undef unless my $format   = $options->{format};
   $template .= ".$format";
 
+  $self->_warmup unless $self->{templates};
+
   # Variants
   my $handler = $options->{handler};
   if (defined(my $variant = $options->{variant})) {
     $variant = "$template+$variant";
-    my $handlers = $self->_handlers($variant) // [];
+    my $handlers = $self->{templates}{$variant} // [];
     $template = $variant
       if @$handlers && !defined $handler || grep { $_ eq $handler } @$handlers;
   }
@@ -194,6 +209,7 @@ sub template_path {
 sub _add {
   my ($self, $attr, $name, $cb) = @_;
   $self->$attr->{$name} = $cb;
+  delete $self->{proxy};
   return $self;
 }
 
@@ -206,24 +222,6 @@ sub _extends {
   return delete $stash->{extends};
 }
 
-sub _handlers {
-  my ($self, $file) = @_;
-
-  unless ($self->{templates}) {
-
-    # Templates
-    s/\.(\w+)$// and push @{$self->{templates}{$_}}, $1
-      for map { sort @{Mojo::Home->new($_)->list_files} } @{$self->paths};
-
-    # DATA templates
-    my $loader = Mojo::Loader->new;
-    s/\.(\w+)$// and push @{$self->{templates}{$_}}, $1
-      for map { sort keys %{$loader->data($_)} } @{$self->classes};
-  }
-
-  return $self->{templates}{$file};
-}
-
 sub _render_template {
   my ($self, $c, $output, $options) = @_;
 
@@ -239,6 +237,22 @@ sub _render_template {
   return undef;
 }
 
+sub _warmup {
+  my $self = shift;
+
+  my ($index, $templates) = @$self{qw(index templates)} = ({}, {});
+
+  # Handlers for templates
+  s/\.(\w+)$// and push @{$templates->{$_}}, $1
+    for map { sort @{Mojo::Home->new($_)->list_files} } @{$self->paths};
+
+  # Handlers and classes for DATA templates
+  for my $class (reverse @{$self->classes}) {
+    $index->{$_} = $class for my @keys = sort keys %{$LOADER->data($class)};
+    s/\.(\w+)$// and unshift @{$templates->{$_}}, $1 for reverse @keys;
+  }
+}
+
 1;
 
 =encoding utf8
@@ -252,7 +266,7 @@ Mojolicious::Renderer - Generate dynamic content
   use Mojolicious::Renderer;
 
   my $renderer = Mojolicious::Renderer->new;
-  push @{$renderer->classes}, 'MyApp::Foo';
+  push @{$renderer->classes}, 'MyApp::Controller::Foo';
   push @{$renderer->paths}, '/home/sri/templates';
 
 =head1 DESCRIPTION
@@ -372,9 +386,17 @@ Register a new helper.
 
 Get a C<DATA> section template by name, usually used by handlers.
 
+=head2 get_helper
+
+  my $helper = $renderer->get_helper('url_for');
+
+Get a helper by full name, generate a helper dynamically for a prefix or
+return C<undef> if no helper or prefix could be found. Generated helpers
+return a proxy object containing the current controller object and on which
+nested helpers can be called.
+
 =head2 render
 
-  my ($output, $format) = $renderer->render(Mojolicious::Controller->new);
   my ($output, $format) = $renderer->render(Mojolicious::Controller->new, {
     template => 'foo/bar',
     foo      => 'bar'
@@ -1,7 +1,7 @@
 package Mojolicious::Routes::Match;
 use Mojo::Base -base;
 
-use Mojolicious::Routes::Route;
+use Mojo::Util;
 
 has current => 0;
 has [qw(endpoint root)];
@@ -10,89 +10,84 @@ has stack => sub { [] };
 sub match { $_[0]->_match($_[0]->root, $_[1], $_[2]) }
 
 sub path_for {
-  my ($self, $name, %values)
-    = (shift, Mojolicious::Routes::Route::_values(@_));
+  my ($self, $name, %values) = (shift, Mojo::Util::_options(@_));
 
   # Current route
-  my $endpoint;
-  if ($name && $name eq 'current' || !$name) {
-    return {} unless $endpoint = $self->endpoint;
+  my $route;
+  if (!$name || $name eq 'current') {
+    return {} unless $route = $self->endpoint;
   }
 
   # Find endpoint
-  else { return {path => $name} unless $endpoint = $self->root->lookup($name) }
+  else { return {path => $name} unless $route = $self->root->lookup($name) }
 
   # Merge values (clear format)
   my $captures = $self->stack->[-1] || {};
   %values = (%$captures, format => undef, %values);
-  my $pattern = $endpoint->pattern;
+  my $pattern = $route->pattern;
   $values{format}
     //= defined $captures->{format}
     ? $captures->{format}
     : $pattern->defaults->{format}
     if $pattern->constraints->{format};
 
-  my $path = $endpoint->render('', \%values);
-  return {path => $path, websocket => $endpoint->has_websocket};
+  my $path = $route->render(\%values);
+  return {path => $path, websocket => $route->has_websocket};
 }
 
 sub _match {
   my ($self, $r, $c, $options) = @_;
 
   # Pattern
-  my $path = $options->{path};
-  return
-    unless my $captures = $r->pattern->match_partial(\$path, $r->is_endpoint);
+  my $path    = $options->{path};
+  my $partial = $r->partial;
+  my $detect  = (my $endpoint = $r->is_endpoint) && !$partial;
+  return undef
+    unless my $captures = $r->pattern->match_partial(\$path, $detect);
   local $options->{path} = $path;
-  $captures = $self->{captures} = {%{$self->{captures} || {}}, %$captures};
+  local @{$self->{captures} ||= {}}{keys %$captures} = values %$captures;
+  $captures = $self->{captures};
 
   # Method
   my $methods = $r->via;
-  return if $methods && !grep { $_ eq $options->{method} } @$methods;
+  return undef if $methods && !grep { $_ eq $options->{method} } @$methods;
 
   # Conditions
   if (my $over = $r->over) {
     my $conditions = $self->{conditions} ||= $self->root->conditions;
     for (my $i = 0; $i < @$over; $i += 2) {
-      return unless my $condition = $conditions->{$over->[$i]};
-      return if !$condition->($r, $c, $captures, $over->[$i + 1]);
+      return undef unless my $condition = $conditions->{$over->[$i]};
+      return undef if !$condition->($r, $c, $captures, $over->[$i + 1]);
     }
   }
 
   # WebSocket
-  return if $r->is_websocket && !$options->{websocket};
+  return undef if $r->is_websocket && !$options->{websocket};
 
   # Partial
   my $empty = !length $path || $path eq '/';
-  if ($r->partial) {
+  if ($partial) {
     $captures->{path} = $path;
     $self->endpoint($r);
     $empty = 1;
   }
 
-  # Endpoint (or bridge)
-  my $endpoint = $r->is_endpoint;
+  # Endpoint (or intermediate destination)
   if (($endpoint && $empty) || $r->inline) {
     push @{$self->stack}, {%$captures};
     if ($endpoint && $empty) {
       my $format = $captures->{format};
       if ($format) { $_->{format} = $format for @{$self->stack} }
-      return $self->endpoint($r);
+      return !!$self->endpoint($r);
     }
     delete @$captures{qw(app cb)};
   }
 
   # Match children
-  my $snapshot = [@{$self->stack}];
+  my @snapshot = $r->parent ? ([@{$self->stack}], $captures) : ([], {});
   for my $child (@{$r->children}) {
-    $self->_match($child, $c, $options);
-
-    # Endpoint found
-    return if $self->endpoint;
-
-    # Reset
-    if   ($r->parent) { $self->stack([@$snapshot])->{captures} = $captures }
-    else              { $self->stack([])->{captures}           = {} }
+    return 1 if $self->_match($child, $c, $options);
+    $self->stack([@{$snapshot[0]}])->{captures} = $snapshot[1];
   }
 }
 
@@ -144,11 +139,11 @@ Current position on the L</"stack">, defaults to C<0>.
 
 =head2 endpoint
 
-  my $endpoint = $match->endpoint;
-  $match       = $match->endpoint(Mojolicious::Routes::Route->new);
+  my $route = $match->endpoint;
+  $match    = $match->endpoint(Mojolicious::Routes::Route->new);
 
 The route endpoint that matched, usually a L<Mojolicious::Routes::Route>
-objects.
+object.
 
 =head2 root
 
@@ -160,7 +155,7 @@ The root of the route structure, usually a L<Mojolicious::Routes> object.
 =head2 stack
 
   my $stack = $match->stack;
-  $match    = $match->stack([{foo => 'bar'}]);
+  $match    = $match->stack([{action => 'foo'}, {action => 'bar'}]);
 
 Captured parameters with nesting history.
 
@@ -20,12 +20,11 @@ sub match_partial {
   my ($self, $pathref, $detect) = @_;
 
   # Compile on demand
-  my $regex = $self->regex || $self->_compile;
-  my $format
-    = $detect ? ($self->format_regex || $self->_compile_format) : undef;
+  $self->_compile unless $self->{regex};
+  $self->_compile_format if $detect && !$self->{format_regex};
 
   # Match
-  return undef unless my @captures = $$pathref =~ $regex;
+  return undef unless my @captures = $$pathref =~ $self->regex;
   $$pathref = ${^POSTMATCH};
 
   # Merge captures
@@ -37,11 +36,10 @@ sub match_partial {
   }
 
   # Format
-  my $constraint = $self->constraints->{format};
-  return $captures if !$detect || defined $constraint && !$constraint;
-  if ($$pathref =~ s!^/?$format!!) { $captures->{format} = $1 }
-  elsif ($constraint) { return undef unless $captures->{format} }
-
+  return $captures unless $detect && (my $regex = $self->format_regex);
+  return undef unless $$pathref =~ $regex;
+  $captures->{format} = $1 if defined $1;
+  $$pathref = '';
   return $captures;
 }
 
@@ -59,31 +57,26 @@ sub parse {
 }
 
 sub render {
-  my ($self, $values, $render) = @_;
-
-  # Merge values with defaults
-  my $format = ($values ||= {})->{format};
-  my $defaults = $self->defaults;
-  $values = {%$defaults, %$values};
+  my ($self, $values, $endpoint) = @_;
 
   # Placeholders can only be optional without a format
-  my $optional = !$format;
+  my $optional = !(my $format = $values->{format});
 
   my $str = '';
   for my $token (reverse @{$self->tree}) {
-    my ($op, $value) = @$token[0, 1];
+    my ($op, $value) = @$token;
     my $fragment = '';
 
-    # Slash
-    if ($op eq 'slash') { $fragment = '/' unless $optional }
-
     # Text
-    elsif ($op eq 'text') { ($fragment, $optional) = ($value, 0) }
+    if ($op eq 'text') { ($fragment, $optional) = ($value, 0) }
+
+    # Slash
+    elsif ($op eq 'slash') { $fragment = '/' unless $optional }
 
     # Placeholder
     else {
-      $fragment = $values->{$value} // '';
-      my $default = $defaults->{$value};
+      my $default = $self->defaults->{$value};
+      $fragment = $values->{$value} // $default // '';
       if (!defined $default || ($default ne $fragment)) { $optional = 0 }
       elsif ($optional) { $fragment = '' }
     }
@@ -92,8 +85,7 @@ sub render {
   }
 
   # Format can be optional
-  $str ||= '/';
-  return $render && $format ? "$str.$format" : $str;
+  return $endpoint && $format ? "$str.$format" : $str;
 }
 
 sub _compile {
@@ -106,35 +98,34 @@ sub _compile {
   my $block = my $regex = '';
   my $optional = 1;
   for my $token (reverse @{$self->tree}) {
-    my ($op, $value) = @$token[0, 1];
+    my ($op, $value) = @$token;
     my $fragment = '';
 
+    # Text
+    if ($op eq 'text') { ($fragment, $optional) = (quotemeta $value, 0) }
+
     # Slash
-    if ($op eq 'slash') {
+    elsif ($op eq 'slash') {
       $regex = ($optional ? "(?:/$block)?" : "/$block") . $regex;
       ($block, $optional) = ('', 1);
       next;
     }
 
-    # Text
-    elsif ($op eq 'text') { ($fragment, $optional) = (quotemeta $value, 0) }
-
     # Placeholder
-    elsif ($op eq 'placeholder' || $op eq 'relaxed' || $op eq 'wildcard') {
+    else {
       unshift @$placeholders, $value;
 
       # Placeholder
-      if ($op eq 'placeholder') { $fragment = '([^\/\.]+)' }
+      if ($op eq 'placeholder') { $fragment = '([^/\.]+)' }
 
       # Relaxed
-      elsif ($op eq 'relaxed') { $fragment = '([^\/]+)' }
+      elsif ($op eq 'relaxed') { $fragment = '([^/]+)' }
 
       # Wildcard
-      elsif ($op eq 'wildcard') { $fragment = '(.+)' }
+      else { $fragment = '(.+)' }
 
       # Custom regex
-      my $constraint = $constraints->{$value};
-      $fragment = _compile_req($constraint) if $constraint;
+      if (my $c = $constraints->{$value}) { $fragment = _compile_req($c) }
 
       # Optional placeholder
       exists $defaults->{$value} ? ($fragment .= '?') : ($optional = 0);
@@ -146,23 +137,23 @@ sub _compile {
   # Not rooted with a slash
   $regex = "$block$regex" if $block;
 
-  return $self->regex(qr/^$regex/ps)->regex;
+  $self->regex(qr/^$regex/ps);
 }
 
 sub _compile_format {
   my $self = shift;
 
   # Default regex
-  my $c = $self->constraints;
-  return $self->format_regex(qr!\.([^/]+)$!)->format_regex
-    unless defined $c->{format};
+  my $format = $self->constraints->{format};
+  return $self->format_regex(qr!^/?(?:\.([^/]+))?$!) unless defined $format;
 
   # No regex
-  return undef unless $c->{format};
+  return undef unless $format;
 
   # Compile custom regex
-  my $regex = _compile_req($c->{format});
-  return $self->format_regex(qr!\.$regex$!)->format_regex;
+  my $regex = '\.' . _compile_req($format);
+  $regex = "(?:$regex)?" if $self->defaults->{format};
+  $self->format_regex(qr!^/?$regex$!);
 }
 
 sub _compile_req {
@@ -204,18 +195,21 @@ sub _tokenize {
     # Quote end
     elsif ($char eq $quote_end) { ($inside, $quoted) = (0, 0) }
 
-    # Slash
+    # Slash (first slash is text for optimizations)
     elsif ($char eq '/') {
-      push @tree, ['slash'];
+      push @tree, @tree ? ['slash'] : ['text', '/'];
       $inside = 0;
     }
 
     # Placeholder, relaxed or wildcard
     elsif ($inside) { $tree[-1][-1] .= $char }
 
-    # Text
+    # Text (optimize text followed by slash followed by text)
     elsif ($tree[-1][0] eq 'text') { $tree[-1][-1] .= $char }
-    else                           { push @tree, ['text', $char] }
+    elsif ($tree[-2] && $tree[-2][0] eq 'text' && $tree[-1][0] eq 'slash') {
+      pop @tree && ($tree[-1][-1] .= "/$char");
+    }
+    else { push @tree, ['text', $char] }
   }
 
   return $self->pattern($pattern)->tree(\@tree);
@@ -271,8 +265,8 @@ Compiled regular expression for format matching.
 
 =head2 pattern
 
-  my $pattern = $pattern->pattern;
-  $pattern    = $pattern->pattern('/(foo)/(bar)');
+  my $raw  = $pattern->pattern;
+  $pattern = $pattern->pattern('/(foo)/(bar)');
 
 Raw unparsed pattern.
 
@@ -321,7 +315,7 @@ Character indicating a relaxed placeholder, defaults to C<#>.
 =head2 tree
 
   my $tree = $pattern->tree;
-  $pattern = $pattern->tree([['slash'], ['text', 'foo']]);
+  $pattern = $pattern->tree([['text', '/foo']]);
 
 Pattern in parsed form. Note that this structure should only be used very
 carefully since it is very dynamic.
@@ -2,6 +2,7 @@ package Mojolicious::Routes::Route;
 use Mojo::Base -base;
 
 use Carp 'croak';
+use Mojo::Util;
 use Mojolicious::Routes::Pattern;
 use Scalar::Util qw(blessed weaken);
 
@@ -12,7 +13,7 @@ has pattern    => sub { Mojolicious::Routes::Pattern->new };
 sub AUTOLOAD {
   my $self = shift;
 
-  my ($package, $method) = split /::(\w+)$/, our $AUTOLOAD;
+  my ($package, $method) = our $AUTOLOAD =~ /^(.+)::(.+)$/;
   croak "Undefined subroutine &${package}::$method called"
     unless blessed $self && $self->isa(__PACKAGE__);
 
@@ -57,7 +58,10 @@ sub find {
 
 sub get { shift->_generate_route(GET => @_) }
 
+# DEPRECATED in Tiger Face!
 sub has_conditions {
+  Mojo::Util::deprecated
+    'Mojolicious::Routes::Route::has_conditions is DEPRECATED';
   my $self = shift;
   return 1 if @{$self->over || []};
   return undef unless my $parent = $self->parent;
@@ -68,9 +72,8 @@ sub has_custom_name { !!shift->{custom} }
 
 sub has_websocket {
   my $self = shift;
-  return 1 if $self->is_websocket;
-  return undef unless my $parent = $self->parent;
-  return $parent->is_websocket;
+  return $self->{has_websocket} if exists $self->{has_websocket};
+  return $self->{has_websocket} = grep { $_->is_websocket } @{$self->_chain};
 }
 
 sub is_endpoint { $_[0]->inline ? undef : !@{$_[0]->children} }
@@ -96,7 +99,7 @@ sub over {
   my $conditions = ref $_[0] eq 'ARRAY' ? $_[0] : [@_];
   return $self unless @$conditions;
   $self->{over} = $conditions;
-  $self->root->cache(0);
+  $self->root->cache->max_keys(0);
 
   return $self;
 }
@@ -120,22 +123,13 @@ sub remove {
 }
 
 sub render {
-  my ($self, $path, $values) = @_;
-
-  # Render pattern
-  my $prefix = $self->pattern->render($values, !$path);
-  $path = "$prefix$path" unless $prefix eq '/';
-  $path ||= '/' unless my $parent = $self->parent;
-
-  # Let parent render
-  return $parent ? $parent->render($path, $values) : $path;
+  my ($self, $values) = @_;
+  my $path = join '',
+    map { $_->pattern->render($values, !@{$_->children}) } @{$self->_chain};
+  return $path || '/';
 }
 
-sub root {
-  my $root = my $parent = shift;
-  $root = $parent while $parent = $parent->parent;
-  return $root;
-}
+sub root { shift->_chain->[0] }
 
 sub route {
   my $self   = shift;
@@ -150,7 +144,7 @@ sub to {
 
   my $pattern = $self->pattern;
   return $pattern->defaults unless @_;
-  my ($shortcut, %defaults) = _values(@_);
+  my ($shortcut, %defaults) = Mojo::Util::_options(@_);
 
   if ($shortcut) {
 
@@ -166,16 +160,13 @@ sub to {
     }
   }
 
-  $pattern->defaults({%{$pattern->defaults}, %defaults});
+  @{$pattern->defaults}{keys %defaults} = values %defaults;
 
   return $self;
 }
 
 sub to_string {
-  my $self = shift;
-  my $pattern = $self->parent ? $self->parent->to_string : '';
-  $pattern .= $self->pattern->pattern if $self->pattern->pattern;
-  return $pattern;
+  join '', map { $_->pattern->pattern // '' } @{shift->_chain};
 }
 
 sub under { shift->_generate_route(under => @_) }
@@ -194,6 +185,12 @@ sub websocket {
   return $route;
 }
 
+sub _chain {
+  my @chain = (my $parent = shift);
+  unshift @chain, $parent while $parent = $parent->parent;
+  return \@chain;
+}
+
 sub _generate_route {
   my ($self, $methods, @args) = @_;
 
@@ -219,28 +216,13 @@ sub _generate_route {
     elsif (ref $arg eq 'HASH') { %defaults = (%defaults, %$arg) }
   }
 
-  # Create bridge or route
   my $route
-    = $methods eq 'under'
-    ? $self->bridge($pattern, @constraints)
-    : $self->route($pattern, @constraints)->via($methods);
-  $route->over(\@conditions)->to(\%defaults);
+    = $self->route($pattern, @constraints)->over(\@conditions)->to(\%defaults);
+  $methods eq 'under' ? $route->inline(1) : $route->via($methods);
 
   return defined $name ? $route->name($name) : $route;
 }
 
-sub _values {
-
-  # Hash or name (one)
-  return ref $_[0] eq 'HASH' ? (undef, %{shift()}) : @_ if @_ == 1;
-
-  # Name and values (odd)
-  return shift, @_ if @_ % 2;
-
-  # Name and hash or just values (even)
-  return ref $_[1] eq 'HASH' ? (shift, %{shift()}) : (undef, @_);
-}
-
 1;
 
 =encoding utf8
@@ -276,7 +258,7 @@ The children of this route, used for nesting routes.
   my $bool = $r->inline;
   $r       = $r->inline($bool);
 
-Allow L</"bridge"> semantics for this route.
+Allow L</"under"> semantics for this route.
 
 =head2 parent
 
@@ -321,6 +303,7 @@ current parent if necessary.
   my $route = $r->any('/:foo' => {foo => 'bar'} => sub {...});
   my $route = $r->any('/:foo' => [foo => qr/\w+/] => sub {...});
   my $route = $r->any([qw(GET POST)] => '/:foo' => sub {...});
+  my $route = $r->any([qw(GET POST)] => '/:foo' => [foo => qr/\w+/]);
 
 Generate L<Mojolicious::Routes::Route> object matching any of the listed HTTP
 request methods or all. See also the L<Mojolicious::Lite> tutorial for many
@@ -330,13 +313,13 @@ more argument variations.
 
 =head2 bridge
 
-  my $bridge = $r->bridge;
-  my $bridge = $r->bridge('/:action');
-  my $bridge = $r->bridge('/:action', action => qr/\w+/);
-  my $bridge = $r->bridge(format => 0);
+  my $route = $r->bridge;
+  my $route = $r->bridge('/:action');
+  my $route = $r->bridge('/:action', action => qr/\w+/);
+  my $route = $r->bridge(format => 0);
 
-Low-level generator for bridge routes, returns a L<Mojolicious::Routes::Route>
-object.
+Low-level generator for nested routes with their own intermediate destination,
+returns a L<Mojolicious::Routes::Route> object.
 
   my $auth = $r->bridge('/user')->to('user#auth');
   $auth->get('/show')->to('#show');
@@ -386,12 +369,6 @@ See also the L<Mojolicious::Lite> tutorial for many more argument variations.
 
   $r->get('/user')->to('user#show');
 
-=head2 has_conditions
-
-  my $bool = $r->has_conditions;
-
-Check if this route has active conditions.
-
 =head2 has_custom_name
 
   my $bool = $r->has_custom_name;
@@ -402,7 +379,8 @@ Check if this route has a custom name.
 
   my $bool = $r->has_websocket;
 
-Check if this route has a WebSocket ancestor.
+Check if this route has a WebSocket ancestor and cache the result for future
+checks.
 
 =head2 is_endpoint
 
@@ -518,8 +496,7 @@ Remove route from parent.
 
 =head2 render
 
-  my $path = $r->render($suffix);
-  my $path = $r->render($suffix, {foo => 'bar'});
+  my $path = $r->render({foo => 'bar'});
 
 Render route with parameters into a path.
 
@@ -527,9 +504,7 @@ Render route with parameters into a path.
 
   my $root = $r->root;
 
-The L<Mojolicious::Routes> object this route is an descendent of.
-
-  $r->root->cache(0);
+The L<Mojolicious::Routes> object this route is a descendant of.
 
 =head2 route
 
@@ -566,13 +541,15 @@ Stringify the whole route.
 
 =head2 under
 
-  my $bridge = $r->under(sub {...});
-  my $bridge = $r->under('/:foo' => sub {...});
-  my $bridge = $r->under('/:foo' => [foo => qr/\w+/]);
-  my $bridge = $r->under({format => 0});
+  my $route = $r->under(sub {...});
+  my $route = $r->under('/:foo' => sub {...});
+  my $route = $r->under('/:foo' => {foo => 'bar'});
+  my $route = $r->under('/:foo' => [foo => qr/\w+/]);
+  my $route = $r->under([format => 0]);
 
-Generate L<Mojolicious::Routes::Route> object for bridge route. See also the
-L<Mojolicious::Lite> tutorial for many more argument variations.
+Generate L<Mojolicious::Routes::Route> object for a nested route with its own
+intermediate destination. See also the L<Mojolicious::Lite> tutorial for many
+more argument variations.
 
   my $auth = $r->under('/user')->to('user#auth');
   $auth->get('/show')->to('#show');
@@ -608,11 +585,13 @@ variations.
 In addition to the L</"ATTRIBUTES"> and L</"METHODS"> above you can also call
 shortcuts provided by L</"root"> on L<Mojolicious::Routes::Route> objects.
 
+  # Add a "firefox" shortcut
   $r->root->add_shortcut(firefox => sub {
     my ($r, $path) = @_;
     $r->get($path, agent => qr/Firefox/);
   });
 
+  # Use "firefox" shortcut to generate routes
   $r->firefox('/welcome')->to('firefox#welcome');
   $r->firefox('/bye')->to('firefox#bye');
 
@@ -34,9 +34,8 @@ sub continue {
 
   # Merge captures into stash
   my $stash = $c->stash;
-  my $captures = $stash->{'mojo.captures'} //= {};
-  %$captures = (%$captures, %$field);
-  %$stash    = (%$stash,    %$field);
+  @{$stash->{'mojo.captures'} //= {}}{keys %$field} = values %$field;
+  @$stash{keys %$field} = values %$field;
 
   my $continue;
   my $last = !$stack->[++$current];
@@ -87,17 +86,15 @@ sub match {
   my $match = Mojolicious::Routes::Match->new(root => $self);
   $c->match($match);
   my $cache = $self->cache;
-  my $cached = $cache ? $cache->get("$method:$path:$ws") : undef;
-  return $match->endpoint($cached->{endpoint})->stack($cached->{stack})
-    if $cached;
+  if (my $result = $cache->get("$method:$path:$ws")) {
+    return $match->endpoint($result->{endpoint})->stack($result->{stack});
+  }
 
   # Check routes
   $match->match($c => {method => $method, path => $path, websocket => $ws});
-
-  # Cache routes without conditions
-  return unless $cache && (my $endpoint = $match->endpoint);
-  my $result = {endpoint => $endpoint, stack => $match->stack};
-  $cache->set("$method:$path:$ws" => $result) unless $endpoint->has_conditions;
+  return unless my $route = $match->endpoint;
+  $cache->set(
+    "$method:$path:$ws" => {endpoint => $route, stack => $match->stack});
 }
 
 sub route {
@@ -145,11 +142,8 @@ sub _class {
   for my $class (@classes) {
 
     # Failed
-    unless (my $found = $self->_load($class)) {
-      next unless defined $found;
-      $log->debug(qq{Class "$class" is not a controller.});
-      return undef;
-    }
+    next unless defined(my $found = $self->_load($class));
+    return !$log->debug(qq{Class "$class" is not a controller.}) unless $found;
 
     # Success
     my $new = $class->new(%$c);
@@ -263,9 +257,6 @@ L<Mojolicious::Controller> and L<Mojo>.
 
 Routing cache, defaults to a L<Mojo::Cache> object.
 
-  # Disable caching
-  $r->cache(0);
-
 =head2 conditions
 
   my $conditions = $r->conditions;
@@ -289,7 +280,7 @@ C<attr>, C<has>, C<new> and C<tap>.
 Namespaces to load controllers from.
 
   # Add another namespace to load controllers from
-  push @{$r->namespaces}, 'MyApp::Controller';
+  push @{$r->namespaces}, 'MyApp::MyController';
 
 =head2 shortcuts
 
@@ -14,6 +14,7 @@ has serialize          => sub { \&Mojo::JSON::encode_json };
 sub load {
   my ($self, $c) = @_;
 
+  return unless $c->req->headers->cookie;
   return unless my $value = $c->signed_cookie($self->cookie_name);
   $value =~ y/-/=/;
   return unless my $session = $self->deserialize->(b64_decode $value);
@@ -7,23 +7,28 @@ use Mojo::Asset::Memory;
 use Mojo::Date;
 use Mojo::Home;
 use Mojo::Loader;
+use Mojo::Util 'md5_sum';
 
 has classes => sub { ['main'] };
 has paths   => sub { [] };
 
-# Last modified default
-my $MTIME = time;
-
 # Bundled files
 my $HOME   = Mojo::Home->new;
 my $PUBLIC = $HOME->parse($HOME->mojo_lib_dir)->rel_dir('Mojolicious/public');
 
+my $LOADER = Mojo::Loader->new;
+
 sub dispatch {
   my ($self, $c) = @_;
 
+  # Method (GET or HEAD)
+  my $req    = $c->req;
+  my $method = $req->method;
+  return undef unless $method eq 'GET' || $method eq 'HEAD';
+
   # Canonical path
   my $stash = $c->stash;
-  my $path  = $c->req->url->path;
+  my $path  = $req->url->path;
   $path = $stash->{path} ? $path->new($stash->{path}) : $path->clone;
   return undef unless my @parts = @{$path->canonicalize->parts};
 
@@ -49,69 +54,80 @@ sub file {
   return $self->_get_file(catfile($PUBLIC, split('/', $rel)));
 }
 
+sub is_fresh {
+  my ($self, $c, $options) = @_;
+
+  my $res_headers = $c->res->headers;
+  my ($last, $etag) = @$options{qw(last_modified etag)};
+  $res_headers->last_modified(Mojo::Date->new($last)) if $last;
+  $res_headers->etag($etag = qq{"$etag"}) if $etag;
+
+  # Unconditional
+  my $req_headers = $c->req->headers;
+  my $match       = $req_headers->if_none_match;
+  return undef unless (my $since = $req_headers->if_modified_since) || $match;
+
+  # If-None-Match
+  return undef if $match && ($etag // $res_headers->etag // '') ne $match;
+
+  # If-Modified-Since
+  return !!$match unless ($last //= $res_headers->last_modified) && $since;
+  return _epoch($last) <= (_epoch($since) // 0);
+}
+
 sub serve {
   my ($self, $c, $rel) = @_;
+
   return undef unless my $asset = $self->file($rel);
+  my $headers = $c->res->headers;
+  return !!$self->serve_asset($c, $asset) if $headers->content_type;
+
+  # Content-Type
   my $types = $c->app->types;
   my $type = $rel =~ /\.(\w+)$/ ? $types->type($1) : undef;
-  $c->res->headers->content_type($type || $types->type('txt'));
+  $headers->content_type($type || $types->type('txt'));
   return !!$self->serve_asset($c, $asset);
 }
 
 sub serve_asset {
   my ($self, $c, $asset) = @_;
 
-  # Last modified
-  my $mtime = $asset->is_file ? (stat $asset->path)[9] : $MTIME;
+  # Last-Modified and ETag
   my $res = $c->res;
-  $res->code(200)->headers->last_modified(Mojo::Date->new($mtime))
-    ->accept_ranges('bytes');
-
-  # If modified since
-  my $headers = $c->req->headers;
-  if (my $date = $headers->if_modified_since) {
-    my $since = Mojo::Date->new($date)->epoch;
-    return $res->code(304) if defined $since && $since == $mtime;
-  }
+  $res->code(200)->headers->accept_ranges('bytes');
+  my $mtime = $asset->mtime;
+  my $options = {etag => md5_sum($mtime), last_modified => $mtime};
+  return $res->code(304) if $self->is_fresh($c, $options);
 
   # Range
-  my $size  = $asset->size;
-  my $start = 0;
-  my $end   = $size - 1;
-  if (my $range = $headers->range) {
-
-    # Not satisfiable
-    return $res->code(416) unless $size && $range =~ m/^bytes=(\d+)?-(\d+)?/;
-    $start = $1 if defined $1;
-    $end = $2 if defined $2 && $2 <= $end;
-    return $res->code(416) if $start > $end || $end > ($size - 1);
-
-    # Satisfiable
-    $res->code(206)->headers->content_length($end - $start + 1)
-      ->content_range("bytes $start-$end/$size");
-  }
-
+  return $res->content->asset($asset)
+    unless my $range = $c->req->headers->range;
+
+  # Not satisfiable
+  return $res->code(416) unless my $size = $asset->size;
+  return $res->code(416) unless $range =~ m/^bytes=(\d+)?-(\d+)?/;
+  my ($start, $end) = ($1 // 0, defined $2 && $2 < $size ? $2 : $size - 1);
+  return $res->code(416) if $start > $end;
+
+  # Satisfiable
+  $res->code(206)->headers->content_length($end - $start + 1)
+    ->content_range("bytes $start-$end/$size");
   return $res->content->asset($asset->start_range($start)->end_range($end));
 }
 
+sub _epoch { Mojo::Date->new(shift)->epoch }
+
 sub _get_data_file {
   my ($self, $rel) = @_;
 
   # Protect templates
   return undef if $rel =~ /\.\w+\.\w+$/;
 
-  # Index DATA files
-  my $loader = Mojo::Loader->new;
-  unless ($self->{index}) {
-    my $index = $self->{index} = {};
-    for my $class (reverse @{$self->classes}) {
-      $index->{$_} = $class for keys %{$loader->data($class)};
-    }
-  }
+  $self->_warmup unless $self->{index};
 
   # Find file
   return undef
-    unless defined(my $data = $loader->data($self->{index}{$rel}, $rel));
+    unless defined(my $data = $LOADER->data($self->{index}{$rel}, $rel));
   return Mojo::Asset::Memory->new->add_chunk($data);
 }
 
@@ -121,6 +137,14 @@ sub _get_file {
   return -f $path && -r $path ? Mojo::Asset::File->new(path => $path) : undef;
 }
 
+sub _warmup {
+  my $self = shift;
+  my $index = $self->{index} = {};
+  for my $class (reverse @{$self->classes}) {
+    $index->{$_} = $class for keys %{$LOADER->data($class)};
+  }
+}
+
 1;
 
 =encoding utf8
@@ -134,13 +158,13 @@ Mojolicious::Static - Serve static files
   use Mojolicious::Static;
 
   my $static = Mojolicious::Static->new;
-  push @{$static->classes}, 'MyApp::Foo';
+  push @{$static->classes}, 'MyApp::Controller::Foo';
   push @{$static->paths}, '/home/sri/public';
 
 =head1 DESCRIPTION
 
-L<Mojolicious::Static> is a static file server with C<Range> and
-C<If-Modified-Since> support based on
+L<Mojolicious::Static> is a static file server with C<Range>,
+C<If-Modified-Since> and C<If-None-Match> support based on
 L<RFC 7232|http://tools.ietf.org/html/rfc7232> and
 L<RFC 7233|http://tools.ietf.org/html/rfc7233>.
 
@@ -191,6 +215,32 @@ protect from traversing to parent directories.
 
   my $content = $static->file('foo/bar.html')->slurp;
 
+=head2 is_fresh
+
+  my $bool = $static->is_fresh(Mojolicious::Controller->new, {etag => 'abc'});
+
+Check freshness of request by comparing the C<If-None-Match> and
+C<If-Modified-Since> request headers to the C<ETag> and C<Last-Modified>
+response headers.
+
+These options are currently available:
+
+=over 2
+
+=item etag
+
+  etag => 'abc'
+
+Add C<ETag> header before comparing.
+
+=item last_modified
+
+  last_modified => $epoch
+
+Add C<Last-Modified> header before comparing.
+
+=back
+
 =head2 serve
 
   my $bool = $static->serve(Mojolicious::Controller->new, 'images/logo.png');
@@ -203,8 +253,8 @@ that this method does not protect from traversing to parent directories.
 
   $static->serve_asset(Mojolicious::Controller->new, Mojo::Asset::File->new);
 
-Serve a L<Mojo::Asset::File> or L<Mojo::Asset::Memory> object with C<Range>
-and C<If-Modified-Since> support.
+Serve a L<Mojo::Asset::File> or L<Mojo::Asset::Memory> object with C<Range>,
+C<If-Modified-Since> and C<If-None-Match> support.
 
 =head1 SEE ALSO
 
@@ -10,7 +10,7 @@ has [qw(input output)] => sub { {} };
 sub AUTOLOAD {
   my $self = shift;
 
-  my ($package, $method) = split /::(\w+)$/, our $AUTOLOAD;
+  my ($package, $method) = our $AUTOLOAD =~ /^(.+)::(.+)$/;
   croak "Undefined subroutine &${package}::$method called"
     unless blessed $self && $self->isa(__PACKAGE__);
 
@@ -122,8 +122,8 @@ L<Mojolicious::Validator::Validation> implements the following attributes.
 
 =head2 csrf_token
 
-  my $token   = $validation->token;
-  $validation = $validation->token('fa6a08...');
+  my $token   = $validation->csrf_token;
+  $validation = $validation->csrf_token('fa6a08...');
 
 CSRF token.
 
@@ -117,7 +117,7 @@
     %= include inline => app->renderer->_bundled('mojobar')
     <script>
       function mojoDrawer (handle, drawer) {
-        $(handle).click(function() {
+        $(handle).click(function () {
           $(drawer).slideToggle('slow');
           var text = $(handle + ' div.tap').text();
           text = text == "tap for more" ? "tap for less" : "tap for more";
@@ -125,7 +125,7 @@
         });
         $(drawer).toggle();
       }
-      $(document).ready(function() {
+      $(document).ready(function () {
         mojoDrawer('#trace', '#frames');
         mojoDrawer('#more', '#infos');
       });
@@ -179,8 +179,8 @@
             <div class="tap">tap for more</div>
             <script>
               var current = '#context';
-              $('#showcase').click(function() {
-                $(current).slideToggle('slow', function() {
+              $('#showcase').click(function () {
+                $(current).slideToggle('slow', function () {
                   if (current == '#context') {
                     current = '#insight';
                   }
@@ -216,8 +216,8 @@
           <h1>Page not found... yet!</h1>
           <p>
             None of these routes could generate a response for your
-            <code><%= $self->req->method %></code> request for
-            <code><%= $self->req->url->path->to_route %></code>, maybe you need
+            <code><%= $c->req->method %></code> request for
+            <code><%= $c->req->url->path->to_route %></code>, maybe you need
             to add a new one?
           </p>
           % my $walk = begin
@@ -254,7 +254,7 @@
       % }
       <div id="request" class="box infobox spaced">
         <table>
-          % my $req = $self->req;
+          % my $req = $c->req;
           %= $kv->(Method => $req->method)
           % my $url = $req->url;
           %= $kv->(URL => $url->to_string)
@@ -263,8 +263,8 @@
           %= $kv->(Stash => dumper $snapshot)
           %= $kv->(Session => dumper session)
           %= $kv->(Version => $req->version)
-          % for my $name (sort @{$self->req->headers->names}) {
-            % my $value = $self->req->headers->header($name);
+          % for my $name (sort @{$c->req->headers->names}) {
+            % my $value = $c->req->headers->header($name);
             %= $kv->($name, $value)
           % }
         </table>
@@ -106,7 +106,7 @@
       }
     });
   });
-  $(document).ready(function() {
+  $(document).ready(function () {
     $('a[href^="#"]').addClass('mojoscroll');
     $(".mojoscroll").click(function(e) {
       e.preventDefault();
@@ -16,7 +16,7 @@
         line-height: 1.5em;
         margin: 0;
       }
-      code {
+      :not(pre) > code {
         background-color: rgba(0, 0, 0, 0.04);
         border-radius: 3px;
         font: 0.9em Consolas, Menlo, Monaco, Courier, monospace;
@@ -30,17 +30,24 @@
         position: relative;
       }
       h1 a, h2 a, h3 a { text-decoration: none }
+      li > p {
+        margin-bottom: 0;
+        margin-top: 0;
+      }
       pre {
         background: url(<%= url_for '/mojo/stripes.png' %>);
         border: 1px solid #d1d1d1;
         border-radius: 3px;
         box-shadow: 0 1px #fff, inset -1px 1px 4px rgba(0, 0, 0, 0.1);
-        color: #4d4d4c;
-        font: 0.9em Consolas, Menlo, Monaco, Courier, monospace;
-        line-height: 1.5em;
+        font: 100% Consolas, Menlo, Monaco, Courier, monospace;
         padding: 1em;
         padding-bottom: 1.5em;
         padding-top: 1.5em;
+      }
+      pre > code {
+        color: #4d4d4c;
+        font: 0.9em Consolas, Menlo, Monaco, Courier, monospace;
+        line-height: 1.5em;
         text-align: left;
         text-shadow: #eee 0 1px 0;
         white-space: pre-wrap;
@@ -43,18 +43,18 @@ has types     => sub { Mojolicious::Types->new };
 has validator => sub { Mojolicious::Validator->new };
 
 our $CODENAME = 'Tiger Face';
-our $VERSION  = '5.16';
+our $VERSION  = '5.47';
 
 sub AUTOLOAD {
   my $self = shift;
 
-  my ($package, $method) = split /::(\w+)$/, our $AUTOLOAD;
+  my ($package, $method) = our $AUTOLOAD =~ /^(.+)::(.+)$/;
   croak "Undefined subroutine &${package}::$method called"
     unless blessed $self && $self->isa(__PACKAGE__);
 
   # Call helper with fresh controller
   croak qq{Can't locate object method "$method" via package "$package"}
-    unless my $helper = $self->renderer->helpers->{$method};
+    unless my $helper = $self->renderer->get_helper($method);
   return $self->build_controller->$helper(@_);
 }
 
@@ -68,7 +68,8 @@ sub build_controller {
   $stash->{'mojo.secrets'} //= $self->secrets;
 
   # Build default controller
-  %$stash = (%$stash, %{$self->defaults});
+  my $defaults = $self->defaults;
+  @$stash{keys %$defaults} = values %$defaults;
   my $c
     = $self->controller_class->new(app => $self, stash => $stash, tx => $tx);
   weaken $c->{app};
@@ -83,7 +84,7 @@ sub build_tx {
   return $tx;
 }
 
-sub defaults { shift->_dict(defaults => @_) }
+sub defaults { Mojo::Util::_stash(defaults => @_) }
 
 sub dispatch {
   my ($self, $c) = @_;
@@ -153,16 +154,19 @@ sub new {
   push @{$self->renderer->paths}, $home->rel_dir('templates');
   push @{$self->static->paths},   $home->rel_dir('public');
 
-  # Default to application namespace
-  my $r = $self->routes->namespaces([ref $self]);
+  # Default to controller and application namespace
+  my $r = $self->routes->namespaces(["@{[ref $self]}::Controller", ref $self]);
 
   # Hide controller attributes/methods and "handler"
-  $r->hide(qw(app continue cookie finish flash handler match on param));
-  $r->hide(qw(redirect_to render render_exception render_later render_maybe));
-  $r->hide(qw(render_not_found render_static render_to_string rendered req));
+  $r->hide(qw(app continue cookie finish flash handler helpers match on));
+  $r->hide(qw(param redirect_to render render_exception render_later));
+  $r->hide(qw(render_maybe render_not_found render_to_string rendered req));
   $r->hide(qw(res respond_to send session signed_cookie stash tx url_for));
   $r->hide(qw(validation write write_chunk));
 
+  # DEPRECATED in Tiger Face!
+  $r->hide('render_static');
+
   # Check if we have a log directory
   my $mode = $self->mode;
   $self->log->path($home->rel_file("log/$mode.log"))
@@ -187,7 +191,11 @@ sub plugin {
   $self->plugins->register_plugin(shift, $self, @_);
 }
 
-sub start { shift->commands->run(@_ ? @_ : @ARGV) }
+sub start {
+  my $self = shift;
+  $_->_warmup for $self->static, $self->renderer;
+  return $self->commands->run(@_ ? @_ : @ARGV);
+}
 
 sub startup { }
 
@@ -219,7 +227,7 @@ Mojolicious - Real-time web framework
   }
 
   # Controller
-  package MyApp::Foo;
+  package MyApp::Controller::Foo;
   use Mojo::Base 'Mojolicious::Controller';
 
   # Action
@@ -356,8 +364,9 @@ Useful for rewriting outgoing responses and other post-processing tasks.
 Emitted right before the L</"before_dispatch"> hook and wraps around the whole
 dispatch process, so you have to manually forward to the next hook if you want
 to continue the chain. Default exception handling with
-L<Mojolicious::Controller/"render_exception"> is the first hook in the chain
-and a call to L</"dispatch"> the last, yours will be in between.
+L<Mojolicious::Plugin::DefaultHelpers/"reply-E<gt>exception"> is the first
+hook in the chain and a call to L</"dispatch"> the last, yours will be in
+between.
 
   $app->hook(around_dispatch => sub {
     my ($next, $c) = @_;
@@ -456,7 +465,7 @@ startup method to define the url endpoints for your application.
   $r->post('/baz')->to('test#baz');
 
   # Add another namespace to load controllers from
-  push @{$app->routes->namespaces}, 'MyApp::Controller';
+  push @{$app->routes->namespaces}, 'MyApp::MyController';
 
 =head2 secrets
 
@@ -737,6 +746,8 @@ Abhijit Menon-Sen, C<ams@cpan.org>
 
 Glen Hinkle, C<tempire@cpan.org>
 
+Jan Henning Thorsen, C<jhthorsen@cpan.org>
+
 Joel Berger, C<jberger@cpan.org>
 
 Marcus Ramberg, C<mramberg@cpan.org>
@@ -853,8 +864,6 @@ Ilya Chesnokov
 
 James Duncan
 
-Jan Henning Thorsen
-
 Jan Jona Javorsek
 
 Jan Schmidt
@@ -885,6 +894,8 @@ Magnus Holm
 
 Maik Fischer
 
+Mark Grimes
+
 Mark Stosberg
 
 Marty Tennison
@@ -422,7 +422,8 @@ Test::Mojo - Testing Mojo!
 =head1 DESCRIPTION
 
 L<Test::Mojo> is a collection of testing helpers for everyone developing
-L<Mojo> and L<Mojolicious> applications.
+L<Mojo> and L<Mojolicious> applications, it is usually used together with
+L<Test::More>.
 
 =head1 ATTRIBUTES
 
@@ -433,7 +434,14 @@ L<Test::Mojo> implements the following attributes.
   my $msg = $t->message;
   $t      = $t->message([text => $bytes]);
 
-Current WebSocket message.
+Current WebSocket message represented as an array reference containing the
+frame type and payload.
+
+  # More specific tests
+  use Mojo::JSON 'decode_json';
+  my $hash = decode_json $t->message->[1];
+  is ref $hash, 'HASH', 'right reference';
+  is $hash->{foo}, 'bar', 'right value';
 
   # Test custom message
   $t->message([binary => $bytes])
@@ -591,9 +599,9 @@ Opposite of L</"content_type_like">.
 =head2 delete_ok
 
   $t = $t->delete_ok('/foo');
-  $t = $t->delete_ok('/foo' => {DNT => 1} => 'Hi!');
-  $t = $t->delete_ok('/foo' => {DNT => 1} => form => {a => 'b'});
-  $t = $t->delete_ok('/foo' => {DNT => 1} => json => {a => 'b'});
+  $t = $t->delete_ok('/foo' => {Accept => '*/*'} => 'Hi!');
+  $t = $t->delete_ok('/foo' => {Accept => '*/*'} => form => {a => 'b'});
+  $t = $t->delete_ok('/foo' => {Accept => '*/*'} => json => {a => 'b'});
 
 Perform a C<DELETE> request and check for transport errors, takes the same
 arguments as L<Mojo::UserAgent/"delete">, except for the callback.
@@ -630,9 +638,9 @@ Wait for WebSocket connection to be closed gracefully and check status.
 =head2 get_ok
 
   $t = $t->get_ok('/foo');
-  $t = $t->get_ok('/foo' => {DNT => 1} => 'Hi!');
-  $t = $t->get_ok('/foo' => {DNT => 1} => form => {a => 'b'});
-  $t = $t->get_ok('/foo' => {DNT => 1} => json => {a => 'b'});
+  $t = $t->get_ok('/foo' => {Accept => '*/*'} => 'Hi!');
+  $t = $t->get_ok('/foo' => {Accept => '*/*'} => form => {a => 'b'});
+  $t = $t->get_ok('/foo' => {Accept => '*/*'} => json => {a => 'b'});
 
 Perform a C<GET> request and check for transport errors, takes the same
 arguments as L<Mojo::UserAgent/"get">, except for the callback.
@@ -640,12 +648,16 @@ arguments as L<Mojo::UserAgent/"get">, except for the callback.
   # Run tests against remote host
   $t->get_ok('http://mojolicio.us/perldoc')->status_is(200);
 
+  # Run additional tests on the transaction
+  $t->get_ok('/foo')->status_is(200);
+  is $t->tx->res->dom->at('input')->val, 'whatever', 'right value';
+
 =head2 head_ok
 
   $t = $t->head_ok('/foo');
-  $t = $t->head_ok('/foo' => {DNT => 1} => 'Hi!');
-  $t = $t->head_ok('/foo' => {DNT => 1} => form => {a => 'b'});
-  $t = $t->head_ok('/foo' => {DNT => 1} => json => {a => 'b'});
+  $t = $t->head_ok('/foo' => {Accept => '*/*'} => 'Hi!');
+  $t = $t->head_ok('/foo' => {Accept => '*/*'} => form => {a => 'b'});
+  $t = $t->head_ok('/foo' => {Accept => '*/*'} => json => {a => 'b'});
 
 Perform a C<HEAD> request and check for transport errors, takes the same
 arguments as L<Mojo::UserAgent/"head">, except for the callback.
@@ -818,9 +830,9 @@ Construct a new L<Test::Mojo> object.
 =head2 options_ok
 
   $t = $t->options_ok('/foo');
-  $t = $t->options_ok('/foo' => {DNT => 1} => 'Hi!');
-  $t = $t->options_ok('/foo' => {DNT => 1} => form => {a => 'b'});
-  $t = $t->options_ok('/foo' => {DNT => 1} => json => {a => 'b'});
+  $t = $t->options_ok('/foo' => {Accept => '*/*'} => 'Hi!');
+  $t = $t->options_ok('/foo' => {Accept => '*/*'} => form => {a => 'b'});
+  $t = $t->options_ok('/foo' => {Accept => '*/*'} => json => {a => 'b'});
 
 Perform a C<OPTIONS> request and check for transport errors, takes the same
 arguments as L<Mojo::UserAgent/"options">, except for the callback.
@@ -838,9 +850,9 @@ Invoke callback if the value of L</"success"> is false.
 =head2 patch_ok
 
   $t = $t->patch_ok('/foo');
-  $t = $t->patch_ok('/foo' => {DNT => 1} => 'Hi!');
-  $t = $t->patch_ok('/foo' => {DNT => 1} => form => {a => 'b'});
-  $t = $t->patch_ok('/foo' => {DNT => 1} => json => {a => 'b'});
+  $t = $t->patch_ok('/foo' => {Accept => '*/*'} => 'Hi!');
+  $t = $t->patch_ok('/foo' => {Accept => '*/*'} => form => {a => 'b'});
+  $t = $t->patch_ok('/foo' => {Accept => '*/*'} => json => {a => 'b'});
 
 Perform a C<PATCH> request and check for transport errors, takes the same
 arguments as L<Mojo::UserAgent/"patch">, except for the callback.
@@ -848,9 +860,9 @@ arguments as L<Mojo::UserAgent/"patch">, except for the callback.
 =head2 post_ok
 
   $t = $t->post_ok('/foo');
-  $t = $t->post_ok('/foo' => {DNT => 1} => 'Hi!');
-  $t = $t->post_ok('/foo' => {DNT => 1} => form => {a => 'b'});
-  $t = $t->post_ok('/foo' => {DNT => 1} => json => {a => 'b'});
+  $t = $t->post_ok('/foo' => {Accept => '*/*'} => 'Hi!');
+  $t = $t->post_ok('/foo' => {Accept => '*/*'} => form => {a => 'b'});
+  $t = $t->post_ok('/foo' => {Accept => '*/*'} => json => {a => 'b'});
 
 Perform a C<POST> request and check for transport errors, takes the same
 arguments as L<Mojo::UserAgent/"post">, except for the callback.
@@ -867,9 +879,9 @@ arguments as L<Mojo::UserAgent/"post">, except for the callback.
 =head2 put_ok
 
   $t = $t->put_ok('/foo');
-  $t = $t->put_ok('/foo' => {DNT => 1} => 'Hi!');
-  $t = $t->put_ok('/foo' => {DNT => 1} => form => {a => 'b'});
-  $t = $t->put_ok('/foo' => {DNT => 1} => json => {a => 'b'});
+  $t = $t->put_ok('/foo' => {Accept => '*/*'} => 'Hi!');
+  $t = $t->put_ok('/foo' => {Accept => '*/*'} => form => {a => 'b'});
+  $t = $t->put_ok('/foo' => {Accept => '*/*'} => json => {a => 'b'});
 
 Perform a C<PUT> request and check for transport errors, takes the same
 arguments as L<Mojo::UserAgent/"put">, except for the callback.
@@ -1,6 +1,7 @@
 package ojo;
 use Mojo::Base -strict;
 
+use Benchmark qw(timeit timestr :hireswallclock);
 use Mojo::ByteStream 'b';
 use Mojo::Collection 'c';
 use Mojo::DOM;
@@ -14,7 +15,7 @@ sub import {
 
   # Mojolicious::Lite
   my $caller = caller;
-  eval "package $caller; use Mojolicious::Lite;";
+  eval "package $caller; use Mojolicious::Lite; 1" or die $@;
   my $ua = $caller->app->ua;
   $ua->server->app->hook(around_action => sub { local $_ = $_[1]; $_[0]->() });
 
@@ -26,10 +27,11 @@ sub import {
     a => sub { $caller->can('any')->(@_) and return $ua->server->app },
     b => \&b,
     c => \&c,
-    d => sub { _request($ua, 'DELETE',  @_) },
-    g => sub { _request($ua, 'GET',     @_) },
-    h => sub { _request($ua, 'HEAD',    @_) },
+    d => sub { _request($ua, 'DELETE', @_) },
+    g => sub { _request($ua, 'GET',    @_) },
+    h => sub { _request($ua, 'HEAD',   @_) },
     j => \&j,
+    n => sub (&@) { say STDERR timestr timeit($_[1] // 1, $_[0]) },
     o => sub { _request($ua, 'OPTIONS', @_) },
     p => sub { _request($ua, 'POST',    @_) },
     r => \&dumper,
@@ -43,8 +45,7 @@ sub _request {
 
   my $tx  = $ua->start($ua->build_tx(@_));
   my $err = $tx->error;
-  warn
-    qq/Problem loading URL "@{[$tx->req->url->to_abs]}". ($err->{message})\n/
+  warn qq/Problem loading URL "@{[$tx->req->url]}". ($err->{message})\n/
     if $err && !$err->{code};
 
   return $tx->res;
@@ -111,7 +112,7 @@ Turn list into a L<Mojo::Collection> object.
 =head2 d
 
   my $res = d('example.com');
-  my $res = d('http://example.com' => {DNT => 1} => 'Hi!');
+  my $res = d('http://example.com' => {Accept => '*/*'} => 'Hi!');
 
 Perform C<DELETE> request with L<Mojo::UserAgent/"delete"> and return
 resulting L<Mojo::Message::Response> object.
@@ -119,7 +120,7 @@ resulting L<Mojo::Message::Response> object.
 =head2 g
 
   my $res = g('example.com');
-  my $res = g('http://example.com' => {DNT => 1} => 'Hi!');
+  my $res = g('http://example.com' => {Accept => '*/*'} => 'Hi!');
 
 Perform C<GET> request with L<Mojo::UserAgent/"get"> and return resulting
 L<Mojo::Message::Response> object.
@@ -129,7 +130,7 @@ L<Mojo::Message::Response> object.
 =head2 h
 
   my $res = h('example.com');
-  my $res = h('http://example.com' => {DNT => 1} => 'Hi!');
+  my $res = h('http://example.com' => {Accept => '*/*'} => 'Hi!');
 
 Perform C<HEAD> request with L<Mojo::UserAgent/"head"> and return resulting
 L<Mojo::Message::Response> object.
@@ -144,10 +145,20 @@ Encode Perl data structure or decode JSON with L<Mojo::JSON/"j">.
 
   $ perl -Mojo -E 'b(j({hello => "world!"}))->spurt("hello.json")'
 
+=head2 n
+
+  n {...};
+  n {...} 100;
+
+Benchmark block and print the results to C<STDERR>, with an optional number of
+iterations, which defaults to C<1>.
+
+  $ perl -Mojo -E 'n { say g("mojolicio.us")->code }'
+
 =head2 o
 
   my $res = o('example.com');
-  my $res = o('http://example.com' => {DNT => 1} => 'Hi!');
+  my $res = o('http://example.com' => {Accept => '*/*'} => 'Hi!');
 
 Perform C<OPTIONS> request with L<Mojo::UserAgent/"options"> and return
 resulting L<Mojo::Message::Response> object.
@@ -155,7 +166,7 @@ resulting L<Mojo::Message::Response> object.
 =head2 p
 
   my $res = p('example.com');
-  my $res = p('http://example.com' => {DNT => 1} => 'Hi!');
+  my $res = p('http://example.com' => {Accept => '*/*'} => 'Hi!');
 
 Perform C<POST> request with L<Mojo::UserAgent/"post"> and return resulting
 L<Mojo::Message::Response> object.
@@ -171,7 +182,7 @@ Dump a Perl data structure with L<Mojo::Util/"dumper">.
 =head2 t
 
   my $res = t('example.com');
-  my $res = t('http://example.com' => {DNT => 1} => 'Hi!');
+  my $res = t('http://example.com' => {Accept => '*/*'} => 'Hi!');
 
 Perform C<PATCH> request with L<Mojo::UserAgent/"patch"> and return resulting
 L<Mojo::Message::Response> object.
@@ -179,7 +190,7 @@ L<Mojo::Message::Response> object.
 =head2 u
 
   my $res = u('example.com');
-  my $res = u('http://example.com' => {DNT => 1} => 'Hi!');
+  my $res = u('http://example.com' => {Accept => '*/*'} => 'Hi!');
 
 Perform C<PUT> request with L<Mojo::UserAgent/"put"> and return resulting
 L<Mojo::Message::Response> object.
@@ -9,10 +9,10 @@ BEGIN { unshift @INC, "$FindBin::Bin/../lib" }
 use Getopt::Long qw(GetOptions :config no_auto_abbrev no_ignore_case);
 
 GetOptions
-  'f|foreground' => sub { $ENV{HYPNOTOAD_FOREGROUND} = 1 },
+  'f|foreground' => \$ENV{HYPNOTOAD_FOREGROUND},
   'h|help'       => \my $help,
-  's|stop'       => sub { $ENV{HYPNOTOAD_STOP}       = 1 },
-  't|test'       => sub { $ENV{HYPNOTOAD_TEST}       = 1 };
+  's|stop'       => \$ENV{HYPNOTOAD_STOP},
+  't|test'       => \$ENV{HYPNOTOAD_TEST};
 
 my $app = shift || $ENV{HYPNOTOAD_APP};
 if ($help || !$app) {
@@ -11,8 +11,8 @@ use Getopt::Long qw(GetOptions :config no_auto_abbrev no_ignore_case);
 GetOptions
   'h|help'     => \my $help,
   'l|listen=s' => \my @listen,
-  'm|mode=s'   => sub { $ENV{MOJO_MODE} = $_[1] },
-  'v|verbose'  => sub { $ENV{MORBO_VERBOSE} = 1 },
+  'm|mode=s'   => \$ENV{MOJO_MODE},
+  'v|verbose'  => \$ENV{MORBO_VERBOSE},
   'w|watch=s'  => \my @watch;
 
 my $app = shift;
@@ -40,6 +40,7 @@ morbo - Morbo HTTP and WebSocket development server
     morbo script/myapp
     morbo myapp.pl
     morbo -m production -l https://*:443 -l http://[::]:3000 myapp.pl
+    morbo -l 'https://*:443?cert=./server.crt&key=./server.key'
     morbo -w /usr/local/lib -w public myapp.pl
 
   Options:
@@ -9,10 +9,15 @@ use Mojo::Asset::Memory;
 
 # File asset
 my $file = Mojo::Asset::File->new;
+is $file->size, 0, 'file is empty';
+is $file->mtime, (stat $file->handle)[9], 'right mtime';
+is $file->slurp, '', 'file is empty';
 $file->add_chunk('abc');
 is $file->contains('abc'), 0,  '"abc" at position 0';
 is $file->contains('bc'),  1,  '"bc" at position 1';
 is $file->contains('db'),  -1, 'does not contain "db"';
+is $file->size, 3, 'right size';
+is $file->mtime, (stat $file->handle)[9], 'right mtime';
 
 # Cleanup
 my $path = $file->path;
@@ -26,6 +31,11 @@ $mem->add_chunk('abc');
 is $mem->contains('abc'), 0,  '"abc" at position 0';
 is $mem->contains('bc'),  1,  '"bc" at position 1';
 is $mem->contains('db'),  -1, 'does not contain "db"';
+is $mem->size, 3, 'right size';
+ok $mem->mtime > (time - 100), 'right mtime';
+is $mem->mtime, Mojo::Asset::Memory->new->mtime, 'same mtime';
+my $mtime = $mem->mtime;
+is $mem->mtime($mtime + 23)->mtime, $mtime + 23, 'right mtime';
 
 # Empty file asset
 $file = Mojo::Asset::File->new;
@@ -226,6 +236,7 @@ $file = Mojo::Asset::File->new(cleanup => 0)->add_chunk('test');
 ok $file->is_file, 'stored in file';
 is $file->slurp,   'test', 'right content';
 is $file->size,    4, 'right size';
+is $file->mtime, (stat $file->handle)[9], 'right mtime';
 is $file->contains('es'), 1, '"es" at position 1';
 $path = $file->path;
 undef $file;
@@ -25,8 +25,7 @@ is $cache->get('two'), 2,     'right result';
 
 $cache = Mojo::Cache->new(max_keys => 3);
 is $cache->get('foo'), undef, 'no result';
-$cache->set(foo => 'bar');
-is $cache->get('foo'), 'bar', 'right result';
+is $cache->set(foo => 'bar')->get('foo'), 'bar', 'right result';
 $cache->set(bar => 'baz');
 is $cache->get('foo'), 'bar', 'right result';
 is $cache->get('bar'), 'baz', 'right result';
@@ -40,4 +39,12 @@ is $cache->get('bar'),  'baz',  'right result';
 is $cache->get('baz'),  'yada', 'right result';
 is $cache->get('yada'), 23,     'right result';
 
+$cache = Mojo::Cache->new(max_keys => 0);
+is $cache->get('foo'), undef, 'no result';
+is $cache->set(foo => 'bar')->get('foo'), undef, 'no result';
+$cache = Mojo::Cache->new(max_keys => -1);
+is $cache->get('foo'), undef, 'no result';
+$cache->set(foo => 'bar');
+is $cache->get('foo'), undef, 'no result';
+
 done_testing();
@@ -112,9 +112,17 @@ is $collection->size, 1, 'right size';
 $collection = c(5, 4, 3, 2, 1);
 is $collection->size, 5, 'right size';
 
+# reduce
+$collection = c(2, 5, 4, 1);
+is $collection->reduce(sub { $a + $b }), 12, 'right result';
+is $collection->reduce(sub { $a + $b }, 5), 17, 'right result';
+is c()->reduce(sub { $a + $b }), undef, 'no result';
+
 # sort
 $collection = c(2, 5, 4, 1);
 is_deeply [$collection->sort->each], [1, 2, 4, 5], 'right order';
+is_deeply [$collection->sort(sub { $b cmp $a })->each], [5, 4, 2, 1],
+  'right order';
 is_deeply [$collection->sort(sub { $_[1] cmp $_[0] })->each], [5, 4, 2, 1],
   'right order';
 $collection = c(qw(Test perl Mojo));
@@ -122,8 +130,7 @@ is_deeply [$collection->sort(sub { uc(shift) cmp uc(shift) })->each],
   [qw(Mojo perl Test)], 'right order';
 $collection = c();
 is_deeply [$collection->sort->each], [], 'no elements';
-is_deeply [$collection->sort(sub { $_[1] cmp $_[0] })->each], [],
-  'no elements';
+is_deeply [$collection->sort(sub { $a cmp $b })->each], [], 'no elements';
 
 # slice
 $collection = c(1, 2, 3, 4, 5, 6, 7, 10, 9, 8);
@@ -82,7 +82,7 @@ is $content->charset, 'UTF-8', 'right charset';
 $content->headers->content_type('text/plain; charset  =  "UTF-8"');
 is $content->charset, 'UTF-8', 'right charset';
 
-# Partial content with 128bit content length
+# Partial content with 128-bit content length
 $content = Mojo::Content::Single->new;
 $content->parse(
   "Content-Length: 18446744073709551616\x0d\x0a\x0d\x0aHello World!");
@@ -7,6 +7,7 @@ BEGIN {
 
 use Test::More;
 use File::Spec::Functions 'catdir';
+use FindBin;
 use Mojo;
 use Mojo::IOLoop;
 use Mojo::Log;
@@ -61,6 +62,18 @@ is $app->config({test => 23})->config->{test}, 23, 'right value';
 is_deeply $app->config, {foo => 'bar', baz => 'yada', test => 23},
   'right value';
 
+# Load broken app
+eval {
+  Mojo::Server::Daemon->new->load_app(
+    "$FindBin::Bin/lib/Mojo/LoaderException.pm");
+};
+like $@, qr/^Can't load application/, 'right error';
+
+# Load missing application class
+eval { Mojo::Server::Daemon->new->build_app('Mojo::DoesNotExist') };
+like $@, qr/^Can't find application class "Mojo::DoesNotExist" in \@INC/,
+  'right error';
+
 # Transaction
 isa_ok $app->build_tx, 'Mojo::Transaction::HTTP', 'right class';
 
@@ -186,12 +199,13 @@ is $tx->res->code, 200, 'right status';
 is $tx->res->body, $result, 'right content';
 ok $tx->local_address, 'has local address';
 ok $tx->local_port > 0, 'has local port';
-ok $tx->remote_address, 'has local address';
-ok $tx->remote_port > 0, 'has local port';
+ok $tx->original_remote_address, 'has original remote address';
+ok $tx->remote_address,          'has remote address';
+ok $tx->remote_port > 0, 'has remote port';
 ok $local_address, 'has local address';
 ok $local_port > 0, 'has local port';
-ok $remote_address, 'has local address';
-ok $remote_port > 0, 'has local port';
+ok $remote_address, 'has remote address';
+ok $remote_port > 0, 'has remote port';
 
 # Pipelined
 my $daemon
@@ -9,6 +9,30 @@ is $date->epoch, 784111777, 'right epoch value';
 $date = Mojo::Date->new('Fri, 13 May 2011 10:00:24 GMT');
 is $date->epoch, 1305280824, 'right epoch value';
 
+# RFC 3339
+is(Mojo::Date->new('2014-08-20T20:45:00')->epoch,
+  1408567500, 'right epoch value');
+is(Mojo::Date->new(1408567500)->to_datetime,
+  '2014-08-20T20:45:00Z', 'right format');
+is(Mojo::Date->new('2014-08-20T20:45:00.01')->epoch,
+  1408567500.01, 'right epoch value');
+is(Mojo::Date->new('2014-08-20T20:45:00-00:46')->epoch,
+  1408570260, 'right epoch value');
+is(Mojo::Date->new(1408570260)->to_datetime,
+  '2014-08-20T21:31:00Z', 'right format');
+is(Mojo::Date->new('2014-08-20t20:45:00-01:46')->epoch,
+  1408573860, 'right epoch value');
+is(Mojo::Date->new('2014-08-20t20:45:00+01:46')->epoch,
+  1408561140, 'right epoch value');
+is(Mojo::Date->new(1408561140)->to_datetime,
+  '2014-08-20T18:59:00Z', 'right format');
+is(Mojo::Date->new('1994-11-06T08:49:37Z')->epoch,
+  784111777, 'right epoch value');
+is(Mojo::Date->new('1994-11-06t08:49:37.33z')->epoch,
+  784111777.33, 'right epoch value');
+is(Mojo::Date->new(784111777.33)->to_datetime,
+  '1994-11-06T08:49:37.33Z', 'right format');
+
 # RFC 850/1036
 is(Mojo::Date->new('Sunday, 06-Nov-94 08:49:37 GMT')->epoch,
   784111777, 'right epoch value');
@@ -35,6 +59,8 @@ is(Mojo::Date->new('Sun Nov  6 08:49:37 1994 GARBAGE')->epoch,
   undef, 'no epoch value');
 is(Mojo::Date->new('Fri, 75 May 2011 99:99:99 GMT')->epoch,
   undef, 'no epoch value');
+is(Mojo::Date->new('0000-00-00T00:00:00+01:00')->epoch,
+  undef, 'no epoch value');
 
 # to_string
 $date = Mojo::Date->new(784111777);
@@ -42,6 +68,13 @@ is "$date", 'Sun, 06 Nov 1994 08:49:37 GMT', 'right format';
 $date = Mojo::Date->new(1305280824);
 is $date->to_string, 'Fri, 13 May 2011 10:00:24 GMT', 'right format';
 
+# Current time roundtrips
+my $before = time;
+ok(Mojo::Date->new(Mojo::Date->new->to_string)->epoch >= $before,
+  'successful roundtrip');
+ok(Mojo::Date->new(Mojo::Date->new->to_datetime)->epoch >= $before,
+  'successful roundtrip');
+
 # Zero time checks
 $date = Mojo::Date->new(0);
 is $date->epoch, 0, 'right epoch value';
@@ -2303,12 +2303,59 @@ is $dom->find('div > ul li')->[2], undef, 'no result';
 is $dom->find('div > ul ul')->[0]->text, 'C', 'right text';
 is $dom->find('div > ul ul')->[1], undef, 'no result';
 
+# Form values
+$dom = Mojo::DOM->new(<<EOF);
+<form action="/foo">
+  <p>Test</p>
+  <input type="text" name="a" value="A" />
+  <input type="checkbox" checked name="b" value="B">
+  <input type="radio" checked name="c" value="C">
+  <select name="f">
+    <option value="F">G</option>
+    <optgroup>
+      <option>H</option>
+      <option selected>I</option>
+    </optgroup>
+    <option value="J" selected>K</option>
+  </select>
+  <select name="n"><option>N</option></select>
+  <select name="d"><option selected>D</option></select>
+  <textarea name="m">M</textarea>
+  <button name="o" value="O">No!</button>
+  <input type="submit" name="p" value="P" />
+</form>
+EOF
+is_deeply [$dom->at('p')->val->each], [], 'no values';
+is $dom->at('input')->val->size, 1, 'one value';
+is $dom->at('input')->val,                     'A', 'right value';
+is $dom->at('input:checked')->val,             'B', 'right value';
+is $dom->at('input:checked[type=radio]')->val, 'C', 'right value';
+is $dom->find('select')->first->val->join(':'), 'I:J', 'right value';
+is_deeply [$dom->find('select')->first->val->each], ['I', 'J'], 'right values';
+is $dom->at('select option')->val->size, 1, 'one value';
+is $dom->at('select option')->val,                          'F', 'right value';
+is $dom->at('select optgroup option:not([selected])')->val, 'H', 'right value';
+is $dom->find('select')->[1]->val->size, 0, 'no values';
+is $dom->find('select')->[1]->at('option')->val, 'N', 'right value';
+is $dom->find('select')->last->val, 'D', 'right value';
+is $dom->at('textarea')->val->size, 1,   'one value';
+is $dom->at('textarea')->val, 'M', 'right value';
+is $dom->at('button')->val,   'O', 'right value';
+is $dom->find('form input')->last->val, 'P', 'right value';
+
 # Slash between attributes
 $dom = Mojo::DOM->new('<input /type=checkbox / value="/a/" checked/><br/>');
 is_deeply $dom->at('input')->attr,
   {type => 'checkbox', value => '/a/', checked => undef}, 'right attributes';
 is "$dom", '<input checked type="checkbox" value="/a/"><br>', 'right result';
 
+# Dot and hash in class and id attributes
+$dom = Mojo::DOM->new('<p class="a#b.c">A</p><p id="a#b.c">B</p>');
+is $dom->at('p.a\#b\.c')->text,       'A', 'right text';
+is $dom->at(':not(p.a\#b\.c)')->text, 'B', 'right text';
+is $dom->at('p#a\#b\.c')->text,       'B', 'right text';
+is $dom->at(':not(p#a\#b\.c)')->text, 'A', 'right text';
+
 # Extra whitespace
 $dom = Mojo::DOM->new('< span>a< /span><b >b</b><span >c</ span>');
 is $dom->at('span')->text,     'a', 'right text';
@@ -16,41 +16,21 @@ eval { $e->emit('die') };
 is $@, "works!\n", 'right error';
 
 # Unhandled error event
-eval { $e->emit(error => 'just') };
-like $@, qr/^Mojo::EventEmitter: just/, 'right error';
-eval { $e->emit_safe(error => 'works') };
+eval { $e->emit(error => 'works') };
 like $@, qr/^Mojo::EventEmitter: works/, 'right error';
 
+# Catch
+my $err;
+ok !$e->has_subscribers('foo'), 'no subscribers';
+$e->catch(sub { $err = pop });
+ok $e->has_subscribers('error'), 'has subscribers';
+$e->emit(error => 'just works!');
+is $err, 'just works!', 'right error';
+
 # Exception in error event
 $e->once(error => sub { die "$_[1]entional" });
 eval { $e->emit(error => 'int') };
 like $@, qr/^intentional/, 'right error';
-$e->once(error => sub { die "$_[1]entional" });
-eval { $e->emit_safe(error => 'int') };
-like $@, qr/^Mojo::EventEmitter: Event "error" failed: intentional/,
-  'right error';
-
-# Error fallback
-my ($echo, $err);
-$e->catch(sub { $err = pop })->on(test2 => sub { $echo .= 'echo: ' . pop });
-$e->on(
-  test2 => sub {
-    my ($e, $msg) = @_;
-    die "test2: $msg\n";
-  }
-);
-my $cb = sub { $echo .= 'echo2: ' . pop };
-$e->on(test2 => $cb);
-$e->emit_safe('test2', 'works!');
-is $echo, 'echo: works!echo2: works!', 'right echo';
-is $err, qq{Event "test2" failed: test2: works!\n}, 'right error';
-($echo, $err) = ();
-is scalar @{$e->subscribers('test2')}, 3, 'three subscribers';
-$e->unsubscribe(test2 => $cb);
-is scalar @{$e->subscribers('test2')}, 2, 'two subscribers';
-$e->emit_safe('test2', 'works!');
-is $echo, 'echo: works!', 'right echo';
-is $err, qq{Event "test2" failed: test2: works!\n}, 'right error';
 
 # Normal event again
 $e->emit('test1');
@@ -126,7 +106,7 @@ is $once, 1, 'event was not emitted again';
 # Unsubscribe
 $e = Mojo::EventEmitter->new;
 my $counter;
-$cb = $e->on(foo => sub { $counter++ });
+my $cb = $e->on(foo => sub { $counter++ });
 $e->on(foo => sub { $counter++ });
 $e->on(foo => sub { $counter++ });
 $e->unsubscribe(foo => $e->once(foo => sub { $counter++ }));
@@ -151,7 +131,7 @@ is $buffer, '', 'no result';
 $e->emit(one => $buffer => 'two');
 is $buffer, 'abctwo123two', 'right result';
 $e->once(one => sub { $_[1] .= 'def' });
-$e->emit_safe(one => $buffer => 'three');
+$e->emit(one => $buffer => 'three');
 is $buffer, 'abctwo123twoabcthree123threedef', 'right result';
 $e->emit(one => $buffer => 'x');
 is $buffer, 'abctwo123twoabcthree123threedefabcx123x', 'right result';
@@ -147,7 +147,7 @@ is b($bytes)->decode('UTF-8'), "[\"hello\\u0003\x{0152}world\x{0152}!\"]",
 $bytes = encode_json ["123abc"];
 is $bytes, '["123abc"]', 'encode ["123abc"]';
 $bytes = encode_json ["\x00\x1f \a\b/\f\r"];
-is $bytes, '["\\u0000\\u001F \\u0007\\b\/\f\r"]',
+is $bytes, '["\\u0000\\u001F \\u0007\\b/\f\r"]',
   'encode ["\x00\x1f \a\b/\f\r"]';
 $bytes = encode_json '';
 is $bytes, '""', 'encode ""';
@@ -19,6 +19,7 @@ ok $path->trailing_slash, 'has trailing slash';
 $path = Mojo::Path->new;
 is $path->to_string,     '',  'no path';
 is $path->to_abs_string, '/', 'right absolute path';
+is $path->to_route,      '/', 'right route';
 
 # Advanced
 $path = Mojo::Path->new('/AZaz09-._~!$&\'()*+,;=:@');
@@ -64,8 +64,6 @@ is $res->code(428)->default_message, 'Precondition Required', 'right message';
 is $res->code(429)->default_message, 'Too Many Requests',     'right message';
 is $res->code(431)->default_message, 'Request Header Fields Too Large',
   'right message';
-is $res->code(451)->default_message, 'Unavailable For Legal Reasons',
-  'right message';
 is $res->code(500)->default_message, 'Internal Server Error', 'right message';
 is $res->code(501)->default_message, 'Not Implemented',       'right message';
 is $res->code(502)->default_message, 'Bad Gateway',           'right message';
@@ -79,6 +79,11 @@ $mt     = Mojo::Template->new;
 $output = $mt->render('    <%= "one" =%><%= "two" %>  three');
 is $output, "onetwo  three\n", 'expression tags trimmed';
 
+# Nothing to trim
+$mt     = Mojo::Template->new;
+$output = $mt->render('<% =%>');
+is $output, '', 'nothing trimmed';
+
 # Replace tag
 $mt     = Mojo::Template->new;
 $output = $mt->render('<%% 1 + 1 %>');
@@ -652,7 +657,8 @@ like "$output", qr/ohoh/, 'right result';
 $mt     = Mojo::Template->new;
 $output = $mt->render(<<'EOF');
 test
-123
+123\
+456
  %# This dies
 % die 'oops!';
 %= 1 + 1
@@ -663,21 +669,23 @@ like $output->message, qr/oops!/, 'right message';
 is $output->lines_before->[0][0], 1,               'right number';
 is $output->lines_before->[0][1], 'test',          'right line';
 is $output->lines_before->[1][0], 2,               'right number';
-is $output->lines_before->[1][1], '123',           'right line';
+is $output->lines_before->[1][1], '123\\',         'right line';
 is $output->lines_before->[2][0], 3,               'right number';
-is $output->lines_before->[2][1], ' %# This dies', 'right line';
-is $output->line->[0], 4, 'right number';
+is $output->lines_before->[2][1], '456',           'right line';
+is $output->lines_before->[3][0], 4,               'right number';
+is $output->lines_before->[3][1], ' %# This dies', 'right line';
+is $output->line->[0], 5, 'right number';
 is $output->line->[1], "% die 'oops!';", 'right line';
-is $output->lines_after->[0][0], 5,          'right number';
+is $output->lines_after->[0][0], 6,          'right number';
 is $output->lines_after->[0][1], '%= 1 + 1', 'right line';
-is $output->lines_after->[1][0], 6,          'right number';
+is $output->lines_after->[1][0], 7,          'right number';
 is $output->lines_after->[1][1], 'test',     'right line';
-like "$output", qr/oops! at template line 4/, 'right result';
+like "$output", qr/oops! at template line 5/, 'right result';
 
 # Exception in template (empty perl lines)
 $mt     = Mojo::Template->new;
 $output = $mt->render(<<'EOF');
-test
+test\\
 123
 %
 % die 'oops!';
@@ -689,15 +697,15 @@ test
 EOF
 isa_ok $output, 'Mojo::Exception', 'right exception';
 like $output->message, qr/oops!/, 'right message';
-is $output->lines_before->[0][0], 1,      'right number';
-is $output->lines_before->[0][1], 'test', 'right line';
+is $output->lines_before->[0][0], 1,          'right number';
+is $output->lines_before->[0][1], 'test\\\\', 'right line';
 ok $output->lines_before->[0][2], 'contains code';
-is $output->lines_before->[1][0], 2,      'right number';
-is $output->lines_before->[1][1], '123',  'right line';
+is $output->lines_before->[1][0], 2,          'right number';
+is $output->lines_before->[1][1], '123',      'right line';
 ok $output->lines_before->[1][2], 'contains code';
-is $output->lines_before->[2][0], 3,      'right number';
-is $output->lines_before->[2][1], '%',    'right line';
-is $output->lines_before->[2][2], ' ',    'right code';
+is $output->lines_before->[2][0], 3,          'right number';
+is $output->lines_before->[2][1], '%',        'right line';
+is $output->lines_before->[2][2], ' ',        'right code';
 is $output->line->[0], 4, 'right number';
 is $output->line->[1], "% die 'oops!';", 'right line';
 is $output->lines_after->[0][0], 5,     'right number';
@@ -999,6 +1007,26 @@ $output = $mt->render(<<'EOF');
 EOF
 is $output, "hello world\n", 'escaped multiline expression';
 
+# Empty statement
+$mt     = Mojo::Template->new;
+$output = $mt->render("test\n\n123\n\n<% %>456\n789");
+is $output, "test\n\n123\n\n456\n789\n", 'empty statement';
+
+# Optimize successive text lines ending with newlines
+$mt = Mojo::Template->new;
+$mt->parse(<<'EOF');
+test
+123
+456\
+789\\
+987
+654
+321
+EOF
+is $mt->tree->[0][1], "test\n123\n456", 'optimized text lines';
+$output = $mt->build->compile || $mt->interpret;
+is $output, "test\n123\n456789\\\n987\n654\n321\n", 'just text';
+
 # Scoped scalar
 $mt     = Mojo::Template->new;
 $output = $mt->render(<<'EOF');
@@ -326,6 +326,13 @@ is(($t->endpoint($tx))[0], 'http',      'right scheme');
 is(($t->endpoint($tx))[1], '127.0.0.1', 'right host');
 is(($t->endpoint($tx))[2], 3000,        'right port');
 
+# Simple endpoint with SOCKS proxy
+$tx = $t->tx(GET => 'http://mojolicio.us');
+$tx->req->proxy('socks://127.0.0.1:3000');
+is(($t->endpoint($tx))[0], 'http',         'right scheme');
+is(($t->endpoint($tx))[1], 'mojolicio.us', 'right host');
+is(($t->endpoint($tx))[2], 80,             'right port');
+
 # Simple WebSocket endpoint with proxy
 $tx = $t->websocket('ws://mojolicio.us');
 $tx->req->proxy('http://127.0.0.1:3000');
@@ -346,6 +353,13 @@ is(($t->endpoint($tx))[0], 'https',        'right scheme');
 is(($t->endpoint($tx))[1], 'mojolicio.us', 'right host');
 is(($t->endpoint($tx))[2], 443,            'right port');
 
+# HTTPS endpoint with SOCKS proxy
+$tx = $t->tx(GET => 'https://mojolicio.us');
+$tx->req->proxy('socks://127.0.0.1:3000');
+is(($t->endpoint($tx))[0], 'https',        'right scheme');
+is(($t->endpoint($tx))[1], 'mojolicio.us', 'right host');
+is(($t->endpoint($tx))[2], 443,            'right port');
+
 # TLS WebSocket endpoint with proxy
 $tx = $t->websocket('WSS://mojolicio.us');
 $tx->req->proxy('http://127.0.0.1:3000');
@@ -366,6 +380,13 @@ is(($t->peer($tx))[0], 'http',      'right scheme');
 is(($t->peer($tx))[1], '127.0.0.1', 'right host');
 is(($t->peer($tx))[2], 3000,        'right port');
 
+# Simple peer with SOCKS proxy
+$tx = $t->tx(GET => 'http://mojolicio.us');
+$tx->req->proxy('socks://127.0.0.1:3000');
+is(($t->peer($tx))[0], 'socks',     'right scheme');
+is(($t->peer($tx))[1], '127.0.0.1', 'right host');
+is(($t->peer($tx))[2], 3000,        'right port');
+
 # Simple peer with proxy (no port)
 $tx = $t->tx(GET => 'http://mojolicio.us');
 $tx->req->proxy('http://127.0.0.1');
@@ -400,6 +421,13 @@ is(($t->peer($tx))[0], 'http',      'right scheme');
 is(($t->peer($tx))[1], '127.0.0.1', 'right host');
 is(($t->peer($tx))[2], 3000,        'right port');
 
+# HTTPS peer with SOCKS proxy
+$tx = $t->tx(GET => 'https://mojolicio.us');
+$tx->req->proxy('socks://127.0.0.1:3000');
+is(($t->peer($tx))[0], 'socks',     'right scheme');
+is(($t->peer($tx))[1], '127.0.0.1', 'right host');
+is(($t->peer($tx))[2], 3000,        'right port');
+
 # TLS WebSocket peer with proxy
 $tx = $t->websocket('wss://mojolicio.us');
 $tx->req->proxy('http://127.0.0.1:3000');
@@ -494,6 +522,9 @@ is $tx->req->headers->host, 'mojolicio.us', 'right "Host" header';
 is $t->proxy_connect($tx), undef, 'already a CONNECT request';
 $tx->req->method('Connect');
 is $t->proxy_connect($tx), undef, 'already a CONNECT request';
+$tx = $t->tx(GET => 'https://mojolicio.us');
+$tx->req->proxy('socks://127.0.0.1:3000');
+is $t->proxy_connect($tx), undef, 'using a SOCKS proxy';
 
 # Simple 301 redirect
 $tx = $t->tx(
@@ -1,7 +1,7 @@
 use Mojo::Base -strict;
 
 BEGIN {
-  $ENV{MOJO_NO_IPV6} = $ENV{MOJO_NO_TLS} = 1;
+  $ENV{MOJO_NO_IPV6} = $ENV{MOJO_NO_SOCKS} = $ENV{MOJO_NO_TLS} = 1;
   $ENV{MOJO_REACTOR} = 'Mojo::Reactor::Poll';
 }
 
@@ -125,10 +125,17 @@ ok $success, 'successful';
 is $code,    200, 'right status';
 is $body,    'works!', 'right content';
 
+# SOCKS proxy request without SOCKS support
+$ua = Mojo::UserAgent->new(ioloop => Mojo::IOLoop->singleton);
+my $tx = $ua->build_tx(GET => '/');
+$tx->req->proxy($ua->server->url->scheme('socks'));
+$tx = $ua->start($tx);
+like $tx->error->{message}, qr/IO::Socket::Socks/, 'right error';
+
 # HTTPS request without TLS support
 $ua = Mojo::UserAgent->new(ioloop => Mojo::IOLoop->singleton);
-my $tx = $ua->get($ua->server->url->scheme('https'));
-ok $tx->error, 'has error';
+$tx = $ua->get($ua->server->url->scheme('https'));
+like $tx->error->{message}, qr/IO::Socket::SSL/, 'right error';
 
 # Blocking
 $tx = $ua->get('/');
@@ -172,14 +179,13 @@ is $tx->res->code, 200, 'right status';
 is $tx->res->headers->connection, 'test', 'right "Connection" value';
 is $tx->res->body, 'One!', 'right content';
 
-# Error in callback is logged
-app->ua->once(error => sub { Mojo::IOLoop->stop });
-ok app->ua->has_subscribers('error'), 'has subscribers';
+# Error in callback
+Mojo::IOLoop->singleton->reactor->unsubscribe('error');
 my $err;
-my $msg = app->log->on(message => sub { $err .= pop });
+Mojo::IOLoop->singleton->reactor->once(
+  error => sub { $err .= pop; Mojo::IOLoop->stop });
 app->ua->get('/' => sub { die 'error event works' });
 Mojo::IOLoop->start;
-app->log->unsubscribe(message => $msg);
 like $err, qr/error event works/, 'right error';
 
 # Events
@@ -282,7 +288,7 @@ is $body,    '{"hello":"world"}', 'right content';
 
 # Built-in web server times out
 my $log = '';
-$msg = app->log->on(message => sub { $log .= pop });
+my $msg = app->log->on(message => sub { $log .= pop });
 $tx = $ua->get('/timeout?timeout=0.25');
 app->log->unsubscribe(message => $msg);
 ok !$tx->success, 'not successful';
@@ -307,9 +313,7 @@ ok !$tx->success, 'not successful';
 is $tx->error->{message}, 'Inactivity timeout', 'right error';
 
 # Keep alive connection times out
-my ($fail, $id);
-my $error = $ua->on(error => sub { $fail++ });
-ok $ua->has_subscribers('error'), 'has subscribers';
+my $id;
 $ua->get(
   '/' => sub {
     my ($ua, $tx) = @_;
@@ -319,10 +323,7 @@ $ua->get(
   }
 );
 Mojo::IOLoop->start;
-ok !$fail, 'error event has not been emitted';
 ok !Mojo::IOLoop->stream($id), 'connection timed out';
-$ua->unsubscribe(error => $error);
-ok !$ua->has_subscribers('error'), 'unsubscribed successfully';
 
 # Response exceeding message size limit
 $ua->once(
@@ -87,7 +87,7 @@ ok $tx->error,       'has error';
 $tx = $ua->build_tx(GET => 'http://cdeabcdeffoobarnonexisting.com');
 $ua->start($tx);
 ok $tx->is_finished, 'transaction is finished';
-like $tx->error->{message}, qr/^Couldn't connect/, 'right error';
+like $tx->error->{message}, qr/^Can't connect/, 'right error';
 
 # Fresh user agent again
 $ua = Mojo::UserAgent->new;
@@ -234,8 +234,9 @@ is $tx->res->code,   200,             'right status';
 ok $tx->kept_alive,    'connection was kept alive';
 ok $tx->local_address, 'has local address';
 ok $tx->local_port > 0, 'has local port';
-ok $tx->remote_address, 'has local address';
-ok $tx->remote_port > 0, 'has local port';
+ok $tx->original_remote_address, 'has original remote address';
+ok $tx->remote_address,          'has remote address';
+ok $tx->remote_port > 0, 'has remote port';
 
 # Simple request with redirect
 $ua->max_redirects(3);
@@ -0,0 +1,172 @@
+use Mojo::Base -strict;
+
+BEGIN {
+  $ENV{MOJO_NO_IPV6} = 1;
+  $ENV{MOJO_REACTOR} = 'Mojo::Reactor::Poll';
+}
+
+use Test::More;
+use Mojo::IOLoop::Client;
+
+plan skip_all => 'set TEST_SOCKS to enable this test (developer only!)'
+  unless $ENV{TEST_SOCKS};
+plan skip_all => 'IO::Socket::Socks 0.64 required for this test!'
+  unless Mojo::IOLoop::Client::SOCKS;
+plan skip_all => 'IO::Socket::SSL 1.84 required for this test!'
+  unless Mojo::IOLoop::Server::TLS;
+
+use Mojo::IOLoop;
+use Mojo::IOLoop::Server;
+use Mojo::IOLoop::Stream;
+use Mojo::UserAgent;
+use Mojolicious::Lite;
+use Scalar::Util 'weaken';
+
+# Silence
+app->log->level('fatal');
+
+get '/' => sub {
+  my $c = shift;
+  $c->render(text => $c->tx->remote_port);
+};
+
+websocket '/echo' => sub {
+  my $c = shift;
+  $c->on(
+    message => sub {
+      my $c = shift;
+      $c->send($c->tx->remote_port);
+    }
+  );
+};
+
+get '/secure' => sub {
+  my $c = shift;
+  $c->render(
+    text => $c->req->url->to_abs->protocol . ':' . $c->tx->remote_port);
+};
+
+my $port   = Mojo::IOLoop::Server->generate_port;
+my $server = IO::Socket::Socks->new(
+  Blocking    => 0,
+  Listen      => 10,
+  ProxyAddr   => '127.0.0.1',
+  ProxyPort   => $port,
+  RequireAuth => 1,
+  UserAuth    => sub { $_[0] eq 'foo' && $_[1] eq 'bar' }
+);
+
+# SOCKS proxy server for testing
+my $last;
+Mojo::IOLoop->singleton->reactor->io(
+  $server => sub {
+    my $reactor = shift;
+
+    my $client = $server->accept;
+    $client->blocking(0);
+    my ($address, $port);
+    $reactor->io(
+      $client => sub {
+        my $reactor = shift;
+
+        my $err = $IO::Socket::Socks::SOCKS_ERROR;
+        if ($client->ready) {
+
+          if ($address) {
+            $reactor->remove($client);
+            Mojo::IOLoop->client(
+              {address => $address, port => $port} => sub {
+                my ($loop, $err, $server) = @_;
+                $last = $server->handle->sockport;
+                weaken $server;
+                $client = Mojo::IOLoop::Stream->new($client);
+                Mojo::IOLoop->stream($client);
+                $client->on(read  => sub { $server->write(pop) });
+                $client->on(close => sub { $server && $server->close });
+                $server->on(read  => sub { $client->write(pop) });
+                $server->on(close => sub { $client && $client->close });
+              }
+            );
+          }
+
+          else {
+            ($address, $port) = @{$client->command}[1, 2];
+            $client->command_reply(IO::Socket::Socks::REPLY_SUCCESS(),
+              $address, $port);
+          }
+        }
+        elsif ($err == IO::Socket::Socks::SOCKS_WANT_WRITE()) {
+          $reactor->watch($client, 1, 1);
+        }
+        elsif ($err == IO::Socket::Socks::SOCKS_WANT_READ()) {
+          $reactor->watch($client, 1, 0);
+        }
+      }
+    );
+  }
+);
+
+# Failed authentication with SOCKS proxy
+my $ua = Mojo::UserAgent->new(ioloop => Mojo::IOLoop->singleton);
+$ua->proxy->http("socks://foo:baz\@127.0.0.1:$port");
+my $tx = $ua->get('/');
+ok !$tx->success, 'not successful';
+ok $tx->error, 'has error';
+
+# Simple request with SOCKS proxy
+$ua->proxy->http("socks://foo:bar\@127.0.0.1:$port");
+$tx = $ua->get('/');
+ok $tx->success, 'successful';
+ok !$tx->kept_alive, 'kept connection not alive';
+ok $tx->keep_alive, 'keep connection alive';
+is $tx->res->code, 200, 'right status';
+is $tx->req->headers->proxy_authorization, undef,
+  'no "Proxy-Authorization" value';
+is $tx->res->body, $last, 'right content';
+isnt(Mojo::IOLoop->stream($tx->connection)->handle->sockport,
+  $last, 'different ports');
+
+# Keep alive request with SOCKS proxy
+my $before = $last;
+$tx = $ua->get('/');
+ok $tx->success,    'successful';
+ok $tx->kept_alive, 'kept connection alive';
+ok $tx->keep_alive, 'keep connection alive';
+is $tx->res->code, 200, 'right status';
+is $tx->res->body, $last, 'right content';
+is $before, $last, 'same port';
+isnt(Mojo::IOLoop->stream($tx->connection)->handle->sockport,
+  $last, 'different ports');
+
+# WebSocket with SOCKS proxy
+my ($result, $id);
+$ua->websocket(
+  '/echo' => sub {
+    my ($ua, $tx) = @_;
+    $id = $tx->connection;
+    $tx->on(
+      message => sub {
+        $result = pop;
+        Mojo::IOLoop->stop;
+      }
+    );
+    $tx->send('test');
+  }
+);
+Mojo::IOLoop->start;
+is $result, $last, 'right result';
+isnt(Mojo::IOLoop->stream($id)->handle->sockport, $last, 'different ports');
+
+# HTTPS request with SOCKS proxy
+$ua->proxy->https("socks://foo:bar\@127.0.0.1:$port");
+$ua->server->url('https');
+$tx = $ua->get('/secure');
+ok $tx->success, 'successful';
+ok !$tx->kept_alive, 'kept connection not alive';
+ok $tx->keep_alive, 'keep connection alive';
+is $tx->res->code, 200,           'right status';
+is $tx->res->body, "https:$last", 'right content';
+isnt(Mojo::IOLoop->stream($tx->connection)->handle->sockport,
+  $last, 'different ports');
+
+done_testing();
@@ -67,8 +67,8 @@ is_deeply split_header('f "o" o , ba  r'),
   'right result';
 is_deeply split_header('foo="b,; a\" r\"\\\\"'), [['foo', 'b,; a" r"\\']],
   'right result';
-is_deeply split_header('foo = "b a\" r\"\\\\"'), [['foo', 'b a" r"\\']],
-  'right result';
+is_deeply split_header('foo = "b a\" r\"\\\\"; bar="ba z"'),
+  [['foo', 'b a" r"\\', 'bar', 'ba z']], 'right result';
 my $header = q{</foo/bar>; rel="x"; t*=UTF-8'de'a%20b};
 my $tree = [['</foo/bar>', undef, 'rel', 'x', 't*', 'UTF-8\'de\'a%20b']];
 is_deeply split_header($header), $tree, 'right result';
@@ -408,6 +408,15 @@ is MojoMonkeyTest::yin(), 'yin', 'right result';
 ok !!MojoMonkeyTest->can('yang'), 'function "yang" exists';
 is MojoMonkeyTest::yang(), 'yang', 'right result';
 
+# monkey_patch (with name)
+SKIP: {
+  skip 'Sub::Util required!', 2 unless eval 'use Sub::Util; 1';
+  is Sub::Util::subname(MojoMonkeyTest->can('foo')), 'MojoMonkeyTest::foo',
+    'right name';
+  is Sub::Util::subname(MojoMonkeyTest->can('bar')), 'MojoMonkeyTest::bar',
+    'right name';
+}
+
 # tablify
 is tablify([["f\r\no o\r\n", 'bar']]),     "fo o  bar\n",      'right result';
 is tablify([["  foo",        '  b a r']]), "  foo    b a r\n", 'right result';
@@ -416,6 +425,8 @@ is tablify([['foo', 'yada'], ['yada', 'yada']]), "foo   yada\nyada  yada\n",
   'right result';
 is tablify([['foo', 'bar', 'baz'], ['yada', 'yada', 'yada']]),
   "foo   bar   baz\nyada  yada  yada\n", 'right result';
+is tablify([['a', '', 'b'], ['c', '', 'd']]), "a    b\nc    d\n",
+  'right result';
 
 # deprecated
 {
@@ -382,7 +382,7 @@ $ua->websocket(
 );
 Mojo::IOLoop->start;
 ok $finished, 'transaction is finished';
-ok !$ws, 'no websocket';
+ok !$ws, 'not a websocket';
 is $code, 500, 'right status';
 is $msg, 'Internal Server Error', 'right message';
 
@@ -398,7 +398,7 @@ $ua->websocket(
   }
 );
 Mojo::IOLoop->start;
-ok !$ws, 'no websocket';
+ok !$ws, 'not a websocket';
 is $code, 403,            'right status';
 is $msg,  "i'm a teapot", 'right message';
 
@@ -420,7 +420,7 @@ $ua->websocket(
 Mojo::IOLoop->start;
 is $status, 1006, 'right status';
 
-# 16bit length
+# 16-bit length
 $result = undef;
 $ua->websocket(
   '/echo' => sub {
@@ -29,6 +29,19 @@ is $frame->[4], 1,          'text frame';
 is $frame->[5], 'whatever', 'right payload';
 is $ws->build_frame(1, 1, 1, 1, 1, 'whatever'), $bytes, 'frames are equal';
 
+# Simple text frame roundtrip without FIN bit
+$ws = Mojo::Transaction::WebSocket->new;
+$bytes = $ws->build_frame(0, 0, 0, 0, 1, 'whatever');
+is $bytes, "\x01\x08\x77\x68\x61\x74\x65\x76\x65\x72", 'right frame';
+$frame = $ws->parse_frame(\($dummy = $bytes));
+is $frame->[0], 0,          'fin flag is not set';
+is $frame->[1], 0,          'rsv1 flag is not set';
+is $frame->[2], 0,          'rsv2 flag is not set';
+is $frame->[3], 0,          'rsv3 flag is not set';
+is $frame->[4], 1,          'text frame';
+is $frame->[5], 'whatever', 'right payload';
+is $ws->build_frame(0, 0, 0, 0, 1, 'whatever'), $bytes, 'frames are equal';
+
 # Simple text frame roundtrip with RSV1 flags set
 $ws = Mojo::Transaction::WebSocket->new;
 $bytes = $ws->build_frame(1, 1, 0, 0, 1, 'whatever');
@@ -140,7 +153,7 @@ is $frame->[4], 2,   'binary frame';
 is $frame->[5], 'a', 'right payload';
 is $bytes = $ws->build_frame(1, 0, 0, 0, 2, 'a'), $bytes, 'frames are equal';
 
-# 16bit text frame roundtrip
+# 16-bit text frame roundtrip
 $ws = Mojo::Transaction::WebSocket->new;
 $bytes = $ws->build_frame(1, 0, 0, 0, 1, 'hi' x 10000);
 is $bytes, "\x81\x7e\x4e\x20" . ("\x68\x69" x 10000), 'right frame';
@@ -153,7 +166,7 @@ is $frame->[4], 1, 'text frame';
 is $frame->[5], 'hi' x 10000, 'right payload';
 is $ws->build_frame(1, 0, 0, 0, 1, 'hi' x 10000), $bytes, 'frames are equal';
 
-# 64bit text frame roundtrip
+# 64-bit text frame roundtrip
 $ws = Mojo::Transaction::WebSocket->new(max_websocket_size => 500000);
 $bytes = $ws->build_frame(1, 0, 0, 0, 1, 'hi' x 200000);
 is $bytes, "\x81\x7f\x00\x00\x00\x00\x00\x06\x1a\x80" . ("\x68\x69" x 200000),
@@ -139,6 +139,19 @@ my $id = Mojo::IOLoop->server(
 );
 my $proxy = Mojo::IOLoop->acceptor($id)->handle->sockport;
 
+# Fake server to test failed TLS handshake
+$id = Mojo::IOLoop->server(
+  sub {
+    my ($loop, $stream) = @_;
+    $stream->on(read => sub { shift->close });
+  }
+);
+my $close = Mojo::IOLoop->acceptor($id)->handle->sockport;
+
+# Fake server to test idle connection
+$id = Mojo::IOLoop->server(sub { });
+my $idle = Mojo::IOLoop->acceptor($id)->handle->sockport;
+
 # User agent with valid certificates
 my $ua = Mojo::UserAgent->new(
   ioloop => Mojo::IOLoop->singleton,
@@ -272,7 +285,7 @@ $ua->websocket(
   "wss://localhost:$port2/test" => sub {
     my ($ua, $tx) = @_;
     $success = $tx->success;
-    $err     = $tx->error;
+    $err     = $tx->res->error;
     Mojo::IOLoop->stop;
   }
 );
@@ -280,8 +293,18 @@ Mojo::IOLoop->start;
 ok !$success, 'no success';
 is $err->{message}, 'Proxy connection failed', 'right error';
 
+# Failed TLS handshake through proxy
+$tx = $ua->get("https://localhost:$close");
+is $err->{message}, 'Proxy connection failed', 'right error';
+
+# Idle connection through proxy
+$ua->on(start =>
+    sub { shift->connect_timeout(0.25) if pop->req->method eq 'CONNECT' });
+$tx = $ua->get("https://localhost:$idle");
+is $err->{message}, 'Proxy connection failed', 'right error';
+$ua->connect_timeout(10);
+
 # Blocking proxy request again
-$ua->proxy->https("http://localhost:$proxy");
 $tx = $ua->get("https://localhost:$port/proxy");
 is $tx->res->code, 200, 'right status';
 is $tx->res->body, "https://localhost:$port/proxy", 'right content';
@@ -65,6 +65,8 @@ is $t->app->renderer->template_handler(
 is $t->app->build_controller->req->url, '', 'no URL';
 is $t->app->build_controller->render_to_string('does_not_exist'), undef,
   'no result';
+is $t->app->build_controller->render_to_string(inline => '%= $c', c => 'foo'),
+  "foo\n", 'right result';
 
 # Missing methods and functions (AUTOLOAD)
 eval { $t->app->missing };
@@ -104,6 +106,7 @@ ok $t->app->routes->is_hidden('finish'),           'is hidden';
 ok $t->app->routes->is_hidden('flash'),            'is hidden';
 ok $t->app->routes->is_hidden('handler'),          'is hidden';
 ok $t->app->routes->is_hidden('has'),              'is hidden';
+ok $t->app->routes->is_hidden('helpers'),          'is hidden';
 ok $t->app->routes->is_hidden('match'),            'is hidden';
 ok $t->app->routes->is_hidden('new'),              'is hidden';
 ok $t->app->routes->is_hidden('on'),               'is hidden';
@@ -114,7 +117,6 @@ ok $t->app->routes->is_hidden('render_exception'), 'is hidden';
 ok $t->app->routes->is_hidden('render_later'),     'is hidden';
 ok $t->app->routes->is_hidden('render_maybe'),     'is hidden';
 ok $t->app->routes->is_hidden('render_not_found'), 'is hidden';
-ok $t->app->routes->is_hidden('render_static'),    'is hidden';
 ok $t->app->routes->is_hidden('render_to_string'), 'is hidden';
 ok $t->app->routes->is_hidden('rendered'),         'is hidden';
 ok $t->app->routes->is_hidden('req'),              'is hidden';
@@ -224,8 +226,7 @@ like $log, qr/Rendering template "syntaxerror.html.epl"\./, 'right message';
 like $log, qr/Missing right curly/, 'right message';
 like $log, qr/Template "exception.development.html.ep" not found\./,
   'right message';
-like $log, qr/Rendering cached template "exception.html.epl"\./,
-  'right message';
+like $log, qr/Rendering template "exception.html.epl"\./, 'right message';
 like $log, qr/500 Internal Server Error/, 'right message';
 $t->app->log->unsubscribe(message => $cb);
 
@@ -259,10 +260,16 @@ $t->get_ok('/fun/time' => {'X-Test' => 'Hi there!'})->status_is(200)
 
 # Foo::fun
 $url = $t->ua->server->url;
+$log = '';
+$cb  = $t->app->log->on(message => sub { $log .= pop });
 $url->path('/fun/time');
 $t->get_ok($url => {'X-Test' => 'Hi there!'})->status_is(200)
   ->header_is('X-Bender' => undef)->header_is(Server => 'Mojolicious (Perl)')
   ->content_is('Have fun!');
+like $log,
+  qr!Rendering cached template "foo/fun\.html\.ep" from DATA section\.!,
+  'right message';
+$t->app->log->unsubscribe(message => $cb);
 
 # Foo::fun
 $t->get_ok('/happy/fun/time' => {'X-Test' => 'Hi there!'})->status_is(200)
@@ -374,8 +381,9 @@ my $mtime = Mojo::Date->new((stat $path)[9])->to_string;
 
 # Static file /hello.txt
 $t->get_ok('/hello.txt')->status_is(200)
-  ->header_is(Server => 'Mojolicious (Perl)')
-  ->header_is('Last-Modified' => $mtime)->header_is('Content-Length' => $size)
+  ->header_is(Server           => 'Mojolicious (Perl)')
+  ->header_is('Last-Modified'  => $mtime)->header_like('ETag' => qr/^"\w+"$/)
+  ->header_is('Content-Length' => $size)
   ->content_type_is('text/plain;charset=UTF-8')
   ->content_like(qr/Hello Mojo from a development static file!/);
 
@@ -389,6 +397,28 @@ $t->get_ok('/../../mojolicious/secret.txt')->status_is(404)
 $t->get_ok('/hello.txt' => {'If-Modified-Since' => $mtime})->status_is(304)
   ->header_is(Server => 'Mojolicious (Perl)')->content_is('');
 
+# Check If-None-Match
+my $etag = $t->tx->res->headers->etag;
+$t->get_ok('/hello.txt' => {'If-None-Match' => $etag})->status_is(304)
+  ->header_is(Server => 'Mojolicious (Perl)')->content_is('');
+
+# Check If-None-Match and If-Last-Modified
+$t->get_ok(
+  '/hello.txt' => {'If-None-Match' => $etag, 'If-Last-Modified' => $mtime})
+  ->status_is(304)->header_is(Server => 'Mojolicious (Perl)')->content_is('');
+
+# Bad If-None-Match with correct If-Modified-Since
+$t->get_ok(
+  '/hello.txt' => {'If-None-Match' => '"123"', 'If-Modified-Since' => $mtime})
+  ->status_is(200)->header_is(Server => 'Mojolicious (Perl)')
+  ->content_like(qr/Hello Mojo from a development static file!/);
+
+# Bad If-Modified-Since with correct If-None-Match
+$t->get_ok('/hello.txt' =>
+    {'If-Modified-Since' => Mojo::Date->new(23), 'If-None-Match' => $etag})
+  ->status_is(200)->header_is(Server => 'Mojolicious (Perl)')
+  ->content_like(qr/Hello Mojo from a development static file!/);
+
 # Embedded development static file
 $t->get_ok('/some/static/file.txt')->status_is(200)
   ->header_is(Server => 'Mojolicious (Perl)')
@@ -10,7 +10,14 @@ use Test::More;
 use FindBin;
 use lib "$FindBin::Bin/lib";
 
-use Mojolicious::Commands;
+# Make sure @ARGV is not changed
+{
+  local $ENV{MOJO_MODE};
+  local @ARGV = qw(-m production -x whatever);
+  require Mojolicious::Commands;
+  is $ENV{MOJO_MODE}, 'production', 'right mode';
+  is_deeply \@ARGV, [qw(-m production -x whatever)], 'unchanged';
+}
 
 # Environment detection
 my $commands = Mojolicious::Commands->new;
@@ -55,6 +62,16 @@ is $app->start('test_command'), 'works!', 'right result';
     'works!', 'right result');
 }
 
+# Do not pick up options for detected environments
+{
+  local $ENV{MOJO_MODE};
+  local $ENV{PLACK_ENV} = 'testing';
+  local @ARGV = qw(psgi -m production);
+  is ref Mojolicious::Commands->start_app('MojoliciousTest'), 'CODE',
+    'right reference';
+  is $ENV{MOJO_MODE}, undef, 'no mode';
+}
+
 # mojo
 ok $commands->description, 'has a description';
 like $commands->message,   qr/COMMAND/, 'has a message';
@@ -288,15 +288,15 @@ my $hmac    = $session->clone->hmac_sha1_sum($t->app->secrets->[0]);
 $t->get_ok('/bridge2stash' => {Cookie => "mojolicious=$session--$hmac"})
   ->status_is(200)->content_is("stash too!!!!!!!!\n");
 
-# Without cookie jar
-$t->ua->cookie_jar(0);
+# Not extracting cookies
+$t->reset_session->ua->cookie_jar->extracting(0);
 $t->get_ok('/bridge2stash' => {'X-Flash' => 1})->status_is(200)
   ->content_is("stash too!!!!!!!!\n");
 
-# Again without cookie jar
+# Still not extracting cookies
 $t->get_ok('/bridge2stash' => {'X-Flash' => 1})->status_is(200)
   ->content_is("stash too!!!!!!!!\n");
-$t->reset_session->ua->cookie_jar(Mojo::UserAgent::CookieJar->new);
+$t->ua->cookie_jar->extracting(1);
 
 # Fresh start without cookies, session or flash
 $t->get_ok('/bridge2stash' => {'X-Flash' => 1})->status_is(200)
@@ -63,7 +63,7 @@ sub data_template { shift->render('index') }
 
 sub data_template2 { shift->stash(template => 'too') }
 
-sub data_static { shift->render_static('singlefiletestapp/foo.txt') }
+sub data_static { shift->reply->static('singlefiletestapp/foo.txt') }
 
 sub index {
   shift->stash(template => 'WithGreenLayout', msg => 'works great!');
@@ -38,6 +38,12 @@ is app->test_helper2, 'Mojolicious::Controller', 'right value';
 app->test_helper3->{foo} = 'bar';
 is app->test_helper3->{foo}, 'bar', 'right result';
 
+# Nested helpers
+helper 'test.helper' => sub { shift->app->controller_class };
+is app->test->helper, 'Mojolicious::Controller', 'right value';
+is app->build_controller->test->helper, 'Mojolicious::Controller',
+  'right value';
+
 # Test renderer
 app->renderer->add_handler(dead => sub { die 'renderer works!' });
 
@@ -197,8 +203,9 @@ get '/root' => sub { shift->render(text => 'root fallback!') };
 get '/template.txt' => {template => 'template', format => 'txt'};
 
 get ':number' => [number => qr/0/] => sub {
-  my $c       = shift;
-  my $url     = $c->req->url->to_abs;
+  my $c   = shift;
+  my $url = $c->req->url->to_abs;
+  $c->res->headers->header('X-Original' => $c->tx->original_remote_address);
   my $address = $c->tx->remote_address;
   my $num     = $c->param('number');
   $c->render(text => "$url-$address-$num");
@@ -231,7 +238,7 @@ get '/source' => sub {
   my $c = shift;
   my $file = $c->param('fail') ? 'does_not_exist.txt' : '../lite_app.t';
   $c->render_maybe('this_does_not_ever_exist')
-    or $c->render_static($file)
+    or $c->reply->static($file)
     or $c->res->headers->header('X-Missing' => 1);
 };
 
@@ -369,24 +376,14 @@ get '/subrequest_non_blocking' => sub {
   $c->stash->{nb} = 'success!';
 };
 
-get '/redirect_url' => sub {
-  shift->redirect_to('http://127.0.0.1/foo')->render(text => 'Redirecting!');
-};
+get '/redirect_url' => sub { shift->redirect_to('http://127.0.0.1/foo') };
 
-get '/redirect_path' => sub {
-  shift->redirect_to('/foo/bar?foo=bar')->render(text => 'Redirecting!');
-};
+get '/redirect_path' => sub { shift->redirect_to('/foo/bar?foo=bar') };
 
-get '/redirect_named' => sub {
-  shift->redirect_to('index', format => 'txt')->render(text => 'Redirecting!');
-};
+get '/redirect_named' => sub { shift->redirect_to('index', format => 'txt') };
 
 get '/redirect_twice' => sub { shift->redirect_to('/redirect_named') };
 
-get '/redirect_no_render' => sub {
-  shift->redirect_to('index', {format => 'txt'});
-};
-
 get '/redirect_callback' => sub {
   my $c = shift;
   Mojo::IOLoop->next_tick(
@@ -398,7 +395,7 @@ get '/redirect_callback' => sub {
   );
 };
 
-get '/static_render' => sub { shift->render_static('hello.txt') };
+get '/static' => sub { shift->reply->static('hello.txt') };
 
 app->types->type('koi8-r' => 'text/html; charset=koi8-r');
 get '/koi8-r' => sub {
@@ -474,6 +471,8 @@ is $t->app->build_controller($t->app->ua->build_tx(GET => '/foo'))->req->url,
   '/foo', 'right URL';
 is $t->app->build_controller->render_to_string('index', handler => 'epl'),
   'Just works!', 'right result';
+is $t->app->build_controller->render_to_string(inline => '0'), "0\n",
+  'right result';
 
 # Unicode snowman
 $t->get_ok('/☃')->status_is(200)
@@ -733,7 +732,8 @@ $t->get_ok('/.html')->status_is(200)
   local $ENV{MOJO_REVERSE_PROXY} = 1;
   $t->ua->server->restart;
   $t->get_ok('/0' => {'X-Forwarded-For' => '192.0.2.2, 192.0.2.1'})
-    ->status_is(200)->content_like(qr!http://localhost:\d+/0-192\.0\.2\.1-0$!);
+    ->status_is(200)->header_unlike('X-Original' => qr/192\.0\.2\.1/)
+    ->content_like(qr!http://localhost:\d+/0-192\.0\.2\.1-0$!);
 }
 
 # Reverse proxy with "X-Forwarded-Proto"
@@ -965,22 +965,18 @@ is $nb, 'broken!', 'right text';
 
 # Redirect to URL
 $t->get_ok('/redirect_url')->status_is(302)
-  ->header_is(Server           => 'Mojolicious (Perl)')
-  ->header_is('Content-Length' => 12)
-  ->header_is(Location => 'http://127.0.0.1/foo')->content_is('Redirecting!');
+  ->header_is(Server   => 'Mojolicious (Perl)')
+  ->header_is(Location => 'http://127.0.0.1/foo')->content_is('');
 
 # Redirect to path
 $t->get_ok('/redirect_path')->status_is(302)
-  ->header_is(Server           => 'Mojolicious (Perl)')
-  ->header_is('Content-Length' => 12)
-  ->header_like(Location => qr!/foo/bar\?foo=bar$!)
-  ->content_is('Redirecting!');
+  ->header_is(Server => 'Mojolicious (Perl)')
+  ->header_like(Location => qr!/foo/bar\?foo=bar$!)->content_is('');
 
 # Redirect to named route
 $t->get_ok('/redirect_named')->status_is(302)
-  ->header_is(Server           => 'Mojolicious (Perl)')
-  ->header_is('Content-Length' => 12)
-  ->header_like(Location => qr!/template.txt$!)->content_is('Redirecting!');
+  ->header_is(Server => 'Mojolicious (Perl)')
+  ->header_like(Location => qr!/template.txt$!)->content_is('');
 
 # Redirect twice
 $t->ua->max_redirects(3);
@@ -993,12 +989,6 @@ is $redirects->[0]->req->url->path, '/redirect_twice', 'right path';
 is $redirects->[1]->req->url->path, '/redirect_named', 'right path';
 $t->ua->max_redirects(0);
 
-# Redirect without rendering
-$t->get_ok('/redirect_no_render')->status_is(302)
-  ->header_is(Server           => 'Mojolicious (Perl)')
-  ->header_is('Content-Length' => 0)
-  ->header_like(Location => qr!/template.txt$!)->content_is('');
-
 # Non-blocking redirect
 $t->get_ok('/redirect_callback')->status_is(301)
   ->header_is(Server           => 'Mojolicious (Perl)')
@@ -1006,7 +996,7 @@ $t->get_ok('/redirect_callback')->status_is(301)
   ->header_is(Location => 'http://127.0.0.1/foo')->content_is('Whatever!');
 
 # Static file
-$t->get_ok('/static_render')->status_is(200)
+$t->get_ok('/static')->status_is(200)
   ->header_is(Server           => 'Mojolicious (Perl)')
   ->header_is('Content-Length' => 31)
   ->content_is("Hello Mojo from a static file!\n");
@@ -1022,7 +1012,7 @@ $t->get_ok('/redirect_named')->status_is(200)
 $t->ua->max_redirects(0);
 Test::Mojo->new->tx($t->tx->previous)->status_is(302)
   ->header_is(Server => 'Mojolicious (Perl)')
-  ->header_like(Location => qr!/template.txt$!)->content_is('Redirecting!');
+  ->header_like(Location => qr!/template.txt$!)->content_is('');
 
 # Request with koi8-r content
 my $koi8
@@ -175,7 +175,7 @@ get '/longpoll/static/delayed' => sub {
   $c->on(finish => sub { shift->stash->{finished}++ });
   $c->cookie(bar => 'baz');
   $c->session(foo => 'bar');
-  Mojo::IOLoop->timer(0.25 => sub { $c->render_static('hello.txt') });
+  Mojo::IOLoop->timer(0.25 => sub { $c->reply->static('hello.txt') });
 };
 
 get '/longpoll/dynamic/delayed' => sub {
@@ -49,4 +49,18 @@ is c(1, 2, 3)->join('-'), '1-2-3', 'right result';
 # Dumper
 is r([1, 2]), "[\n  1,\n  2\n]\n", 'right result';
 
+# Benchmark
+{
+  my $buffer = '';
+  open my $handle, '>', \$buffer;
+  local *STDERR = $handle;
+  my $i = 0;
+  n { ++$i };
+  is $i,        1,             'block has been invoked once';
+  like $buffer, qr/wallclock/, 'right output';
+  n { $i++ } 10;
+  is $i, 11, 'block has been invoked ten times';
+  like $buffer, qr/wallclock.*wallclock/s, 'right output';
+}
+
 done_testing();
@@ -4,8 +4,14 @@ use Test::More;
 use Mojo::ByteStream 'b';
 use Mojolicious::Routes::Pattern;
 
+# Text pattern (optimized)
+my $pattern = Mojolicious::Routes::Pattern->new('/test/123');
+is_deeply $pattern->match('/test/123'), {}, 'right structure';
+is_deeply $pattern->match('/test'), undef, 'no result';
+is $pattern->tree->[0][1], '/test/123', 'optimized pattern';
+
 # Normal pattern with text, placeholders and a default value
-my $pattern = Mojolicious::Routes::Pattern->new('/test/(controller)/:action');
+$pattern = Mojolicious::Routes::Pattern->new('/test/(controller)/:action');
 $pattern->defaults({action => 'index'});
 is_deeply $pattern->match('/test/foo/bar', 1),
   {controller => 'foo', action => 'bar'}, 'right structure';
@@ -55,10 +61,12 @@ is $pattern->render({a => 'c', b => 'd'}), '/test/c/123/d/456', 'right result';
 
 # Root
 $pattern = Mojolicious::Routes::Pattern->new('/');
+is $pattern->pattern, undef, 'slash has been optimized away';
 $pattern->defaults({action => 'index'});
 ok !$pattern->match('/test/foo/bar'), 'no result';
 is_deeply $pattern->match('/'), {action => 'index'}, 'right structure';
-is $pattern->render, '/', 'right result';
+is $pattern->render, '', 'right result';
+is $pattern->render({format => 'txt'}, 1), '.txt', 'right result';
 
 # Regex in pattern
 $pattern = Mojolicious::Routes::Pattern->new('/test/(controller)/:action/(id)',
@@ -246,12 +254,19 @@ is $pattern->render($result, 1), '/foo/bar', 'right result';
 $pattern = Mojolicious::Routes::Pattern->new('//');
 $result = $pattern->match('/', 1);
 is_deeply $result, {}, 'right structure';
-is $pattern->render($result, 1), '/', 'right result';
+is $pattern->render($result, 1), '', 'right result';
 $pattern = Mojolicious::Routes::Pattern->new('0');
 $result = $pattern->match('/0', 1);
 is_deeply $result, {}, 'right structure';
 is $pattern->render($result, 1), '/0', 'right result';
 
+# Optional format with constraint
+$pattern                        = Mojolicious::Routes::Pattern->new('/');
+$pattern->defaults->{format}    = 'txt';
+$pattern->constraints->{format} = ['txt'];
+$result                         = $pattern->match('/', 1);
+is_deeply $result, {format => 'txt'}, 'right structure';
+
 # Unicode
 $pattern = Mojolicious::Routes::Pattern->new('/(one)♥(two)');
 $result  = $pattern->match('/i♥mojolicious');
@@ -31,17 +31,18 @@ my $t = Test::Mojo->new;
 
 # Simple POD template
 $t->get_ok('/')->status_is(200)
-  ->content_like(qr|<h1>Test123</h1>\s+<p>It <code>works</code>!</p>|);
+  ->content_like(qr!<h1 id="Test123">Test123</h1>!)
+  ->content_like(qr|<p>It <code>works</code>!</p>|);
 
 # POD helper
-$t->post_ok('/')->status_is(200)
-  ->content_like(qr!test123\s+<h1>A</h1>\s+<h1>B</h1>!)
+$t->post_ok('/')->status_is(200)->content_like(qr!test123<h1 id="A">A</h1>!)
+  ->content_like(qr!<h1 id="B">B</h1>!)
   ->content_like(qr!\s+<p><code>test</code></p>!)->content_like(qr/Gray/);
 
 # POD filter
 $t->post_ok('/block')->status_is(200)
-  ->content_like(qr!test321\s+<h2>lalala</h2>\s+<p><code>test</code></p>!)
-  ->content_like(qr/Gray/);
+  ->content_like(qr!test321<h2 id="lalala">lalala</h2>!)
+  ->content_like(qr!<p><code>test</code></p>!)->content_like(qr/Gray/);
 
 # Empty
 $t->get_ok('/empty')->status_is(200)->content_is('');
@@ -35,6 +35,10 @@ is $t->app->static->file('hello.txt')->slurp,
   "Hello Mojo from a static file!\n", 'right content';
 is $t->app->moniker, 'mojolicious_test', 'right moniker';
 
+# Default namespaces
+is_deeply $t->app->routes->namespaces,
+  ['MojoliciousTest::Controller', 'MojoliciousTest'], 'right namespaces';
+
 # Plugin::Test::SomePlugin2::register (security violation)
 $t->get_ok('/plugin-test-some_plugin2/register')->status_isnt(500)
   ->status_is(404)->header_is(Server => 'Mojolicious (Perl)')
@@ -1,6 +1,7 @@
 use Mojo::Base -strict;
 
 use Test::More;
+use Mojo::Util 'decode';
 use Mojolicious::Controller;
 
 # Partial rendering
@@ -61,4 +62,60 @@ $c->cookie(foo => 'x' x 4097);
 like $log, qr/Cookie "foo" is bigger than 4096 bytes\./, 'right message';
 $c->app->log->unsubscribe(message => $cb);
 
+# Nested helpers
+my $first = Mojolicious::Controller->new;
+$first->helpers->app->log->level('fatal');
+$first->app->helper('myapp.multi_level.test' => sub {'works!'});
+ok $first->app->renderer->get_helper('myapp'),                  'found helper';
+ok $first->app->renderer->get_helper('myapp.multi_level'),      'found helper';
+ok $first->app->renderer->get_helper('myapp.multi_level.test'), 'found helper';
+is $first->myapp->multi_level->test, 'works!', 'right result';
+is $first->helpers->myapp->multi_level->test, 'works!', 'right result';
+$first->app->helper('myapp.defaults' => sub { shift->app->defaults(@_) });
+ok $first->app->renderer->get_helper('myapp.defaults'), 'found helper';
+is $first->app->renderer->get_helper('myap.'),          undef, 'no helper';
+is $first->app->renderer->get_helper('yapp'),           undef, 'no helper';
+$first->myapp->defaults(foo => 'bar');
+is $first->myapp->defaults('foo'), 'bar', 'right result';
+is $first->helpers->myapp->defaults('foo'), 'bar', 'right result';
+is $first->app->myapp->defaults('foo'),     'bar', 'right result';
+my $second = Mojolicious::Controller->new;
+$second->app->log->level('fatal');
+is $second->app->renderer->get_helper('myapp'),          undef, 'no helper';
+is $second->app->renderer->get_helper('myapp.defaults'), undef, 'no helper';
+$second->app->helper('myapp.defaults' => sub {'nothing'});
+my $myapp = $first->myapp;
+is $first->myapp->defaults('foo'),  'bar',     'right result';
+is $second->myapp->defaults('foo'), 'nothing', 'right result';
+is $second->helpers->myapp->defaults('foo'), 'nothing', 'right result';
+is $first->myapp->defaults('foo'), 'bar', 'right result';
+is $first->helpers->myapp->defaults('foo'), 'bar', 'right result';
+
+# Reuse proxy objects
+my $helpers = $first->helpers;
+is $helpers->myapp->multi_level->test, $helpers->myapp->multi_level->test,
+  'same result';
+
+# Missing method (AUTOLOAD)
+my $class = ref $first->myapp;
+eval { $first->myapp->missing };
+like $@, qr/^Can't locate object method "missing" via package "$class"/,
+  'right error';
+eval { $first->app->myapp->missing };
+like $@, qr/^Can't locate object method "missing" via package "$class"/,
+  'right error';
+
+# No leaky namespaces
+my $helper_class = ref $second->myapp;
+is ref $second->myapp, $helper_class, 'same class';
+ok $helper_class->can('defaults'), 'helpers are active';
+my $template_class = decode 'UTF-8',
+  $second->render_to_string(inline => "<%= __PACKAGE__ =%>");
+is decode('UTF-8', $second->render_to_string(inline => "<%= __PACKAGE__ =%>")),
+  $template_class, 'same class';
+ok $template_class->can('stash'), 'helpers are active';
+undef $second;
+ok !$helper_class->can('defaults'), 'helpers have been cleaned up';
+ok !$template_class->can('stash'),  'helpers have been cleaned up';
+
 done_testing();
@@ -180,11 +180,19 @@ $source->route('/second')->to('#second');
 my $third  = $source->route('/third')->to('#third');
 my $target = $r->remove->route('/target')->to('target#');
 my $second = $r->find('second');
-is $second->render('', {}), '/source/second', 'right result';
+is $second->render({}), '/source/second', 'right result';
 $second->remove;
-is $second->render('', {}), '/second', 'right result';
+is $second->render({}), '/second', 'right result';
 $target->add_child($first)->add_child($second);
-is $second->render('', {}), '/target/second', 'right result';
+is $second->render({}), '/target/second', 'right result';
+
+# /websocket
+$r->websocket('/websocket' => {controller => 'ws'})->route('/')
+  ->to(action => 'just')->route->to(works => 1);
+
+# /slash
+$r->route('/slash')->to(controller => 'just')->route('/')
+  ->to(action => 'slash');
 
 # /missing/*/name
 # /missing/too
@@ -194,6 +202,15 @@ $r->route('/missing/*/name')->to('missing#wildcard');
 $r->route('/missing/too/*', '' => ['test'])
   ->to('missing#too', '' => 'missing');
 
+# /partial/*
+$r->route('/partial')->detour('foo#bar');
+
+# GET  /similar/*
+# POST /similar/too
+my $similar = $r->bridge('/similar');
+$similar->route('/:something')->via('GET')->to('similar#get');
+$similar->route('/too')->via('POST')->to('similar#post');
+
 # Cached lookup
 my $fast = $r->route('/fast');
 is $r->find('fast'),   $fast, 'fast route found';
@@ -815,6 +832,26 @@ $m = Mojolicious::Routes::Match->new(root => $r);
 $m->match($c => {method => 'GET', path => '/target/third'});
 is_deeply $m->stack, [], 'empty stack';
 
+# WebSocket
+$m = Mojolicious::Routes::Match->new(root => $r);
+$m->match($c => {method => 'GET', path => '/websocket'});
+is_deeply $m->stack, [], 'empty stack';
+$m->match($c => {method => 'GET', path => '/websocket', websocket => 1});
+is_deeply $m->stack, [{controller => 'ws', action => 'just', works => 1}],
+  'right structure';
+is $m->path_for->{path}, '/websocket', 'right path';
+ok $m->path_for->{websocket}, 'is a websocket';
+
+# Just a slash with a format after a path
+$m = Mojolicious::Routes::Match->new(root => $r);
+$m->match($c => {method => 'GET', path => '/slash.txt'});
+is_deeply $m->stack,
+  [{controller => 'just', action => 'slash', format => 'txt'}],
+  'right structure';
+is $m->path_for->{path}, '/slash', 'right path';
+ok !$m->path_for->{websocket}, 'not a websocket';
+is $m->path_for(format => 'html')->{path}, '/slash.html', 'right path';
+
 # Nameless placeholder
 $m = Mojolicious::Routes::Match->new(root => $r);
 $m->match($c => {method => 'GET', path => '/missing/foo/name'});
@@ -848,4 +885,27 @@ is_deeply $m->stack,
   'right structure';
 is $m->path_for->{path}, '/missing/too', 'right path';
 
+# Partial route
+$m = Mojolicious::Routes::Match->new(root => $r);
+$m->match($c => {method => 'GET', path => '/partial/test'});
+is_deeply $m->stack,
+  [{controller => 'foo', action => 'bar', 'path' => '/test'}],
+  'right structure';
+$m = Mojolicious::Routes::Match->new(root => $r);
+$m->match($c => {method => 'GET', path => '/partial.test'});
+is_deeply $m->stack,
+  [{controller => 'foo', action => 'bar', 'path' => '.test'}],
+  'right structure';
+
+# Similar routes with placeholders
+$m = Mojolicious::Routes::Match->new(root => $r);
+$m->match($c => {method => 'GET', path => '/similar/too'});
+is_deeply $m->stack,
+  [{}, {controller => 'similar', action => 'get', 'something' => 'too'}],
+  'right structure';
+$m = Mojolicious::Routes::Match->new(root => $r);
+$m->match($c => {method => 'POST', path => '/similar/too'});
+is_deeply $m->stack, [{}, {controller => 'similar', action => 'post'}],
+  'right structure';
+
 done_testing();
@@ -6,20 +6,80 @@ BEGIN {
 }
 
 use Test::More;
+use Mojo::Asset::Memory;
 use Mojo::Date;
 use Mojolicious::Lite;
 use Test::Mojo;
 
-get '/hello3.txt' => sub { shift->render_static('hello2.txt') };
+get '/hello3.txt' => sub { shift->reply->static('hello2.txt') };
+
+post '/hello4.txt' => sub {
+  my $c = shift;
+  $c->res->headers->content_type('text/html');
+  $c->reply->static('hello2.txt');
+};
+
+options '/hello.txt' => sub { shift->render(text => 'Options!') };
+
+get '/etag' => sub {
+  my $c = shift;
+  $c->is_fresh(etag => 'abc')
+    ? $c->rendered(304)
+    : $c->render(text => 'I ♥ Mojolicious!');
+};
+
+get '/asset' => sub {
+  my $c   = shift;
+  my $mem = Mojo::Asset::Memory->new->add_chunk('I <3 Assets!');
+  $c->reply->asset($mem);
+};
 
 my $t = Test::Mojo->new;
 
+# Freshness
+my $c = $t->app->build_controller;
+ok !$c->is_fresh, 'content is stale';
+$c->res->headers->etag('"abc"');
+$c->req->headers->if_none_match('"abc"');
+ok $c->is_fresh, 'content is fresh';
+$c = $t->app->build_controller;
+my $date = Mojo::Date->new(23);
+$c->res->headers->last_modified($date);
+$c->req->headers->if_modified_since($date);
+ok $c->is_fresh, 'content is fresh';
+$c = $t->app->build_controller;
+$c->req->headers->if_none_match('"abc"');
+$c->req->headers->if_modified_since($date);
+ok $c->is_fresh(etag => 'abc', last_modified => $date->epoch),
+  'content is fresh';
+is $c->res->headers->etag,          '"abc"', 'right "ETag" value';
+is $c->res->headers->last_modified, "$date", 'right "Last-Modified" value';
+$c = $t->app->build_controller;
+ok !$c->is_fresh(last_modified => $date->epoch), 'content is stale';
+is $c->res->headers->etag,          undef,   'no "ETag" value';
+is $c->res->headers->last_modified, "$date", 'right "Last-Modified" value';
+
 # Static file
 $t->get_ok('/hello.txt')->status_is(200)
   ->header_is(Server => 'Mojolicious (Perl)')
   ->header_is('Accept-Ranges' => 'bytes')->header_is('Content-Length' => 31)
   ->content_is("Hello Mojo from a static file!\n");
 
+# Static file (HEAD)
+$t->head_ok('/hello.txt')->status_is(200)
+  ->header_is(Server => 'Mojolicious (Perl)')
+  ->header_is('Accept-Ranges' => 'bytes')->header_is('Content-Length' => 31)
+  ->content_is('');
+
+# Route for method other than GET and HEAD
+$t->options_ok('/hello.txt')->status_is(200)
+  ->header_is(Server           => 'Mojolicious (Perl)')
+  ->header_is('Content-Length' => 8)->content_is('Options!');
+
+# Unknown method
+$t->put_ok('/hello.txt')->status_is(404)
+  ->header_is(Server => 'Mojolicious (Perl)');
+
 # Partial static file
 $t->get_ok('/hello.txt' => {Range => 'bytes=2-8'})->status_is(206)
   ->header_is(Server          => 'Mojolicious (Perl)')
@@ -57,7 +117,14 @@ $t->get_ok('/hello.txt' => {Range => 'bytes=0-0'})->status_is(206)
   ->header_is('Content-Range' => 'bytes 0-0/31')->content_is('H');
 
 # Partial static file, end outside of range
-$t->get_ok('/hello.txt' => {Range => 'bytes=25-35'})->status_is(206)
+$t->get_ok('/hello.txt' => {Range => 'bytes=25-31'})->status_is(206)
+  ->header_is(Server           => 'Mojolicious (Perl)')
+  ->header_is('Content-Length' => 6)
+  ->header_is('Content-Range'  => 'bytes 25-30/31')
+  ->header_is('Accept-Ranges'  => 'bytes')->content_is("file!\n");
+
+# Partial static file, end way outside of range
+$t->get_ok('/hello.txt' => {Range => 'bytes=25-300'})->status_is(206)
   ->header_is(Server           => 'Mojolicious (Perl)')
   ->header_is('Content-Length' => 6)
   ->header_is('Content-Range'  => 'bytes 25-30/31')
@@ -80,6 +147,33 @@ $t->get_ok('/hello3.txt' => {Range => 'bytes=0-0'})->status_is(206)
   ->header_is('Accept-Ranges' => 'bytes')->header_is('Content-Length' => 1)
   ->header_is('Content-Range' => 'bytes 0-0/1')->content_is('X');
 
+# Render static file with custom content type
+$t->post_ok('/hello4.txt')->status_is(200)
+  ->header_is(Server => 'Mojolicious (Perl)')->content_type_is('text/html')
+  ->header_is('Content-Length' => 1)->content_is('X');
+
+# Fresh content
+$t->get_ok('/etag')->status_is(200)->header_is(Server => 'Mojolicious (Perl)')
+  ->header_is(ETag => '"abc"')->content_is('I ♥ Mojolicious!');
+
+# Stale content
+$t->get_ok('/etag' => {'If-None-Match' => '"abc"'})->status_is(304)
+  ->header_is(Server => 'Mojolicious (Perl)')->header_is(ETag => '"abc"')
+  ->content_is('');
+
+# Fresh asset
+$t->get_ok('/asset')->status_is(200)
+  ->header_is(Server => 'Mojolicious (Perl)')->content_is('I <3 Assets!');
+my $etag = $t->tx->res->headers->etag;
+
+# Stale asset
+$t->get_ok('/asset' => {'If-None-Match' => $etag})->status_is(304)
+  ->header_is(Server => 'Mojolicious (Perl)')->content_is('');
+
+# Partial asset
+$t->get_ok('/asset' => {'Range' => 'bytes=3-5'})->status_is(206)
+  ->header_is(Server => 'Mojolicious (Perl)')->content_is('3 A');
+
 # Empty file
 $t->get_ok('/hello4.txt')->status_is(200)
   ->header_is(Server           => 'Mojolicious (Perl)')
@@ -87,13 +87,13 @@ $t->get_ok('/advanced')->status_is(200)->header_is('X-Append' => 'bar')
   ->content_is("&LT;escape me>\n123423");
 
 # Normal "pod" template
-$t->get_ok('/docs')->status_is(200)->content_like(qr!<h3>snowman</h3>!);
+$t->get_ok('/docs')->status_is(200)->content_like(qr!<h3.*>snowman</h3>!);
 
 # Template in "teapod" format
-$t->get_ok('/docs2')->status_is(200)->content_like(qr!<h2>snowman</h2>!);
+$t->get_ok('/docs2')->status_is(200)->content_like(qr!<h2.*>snowman</h2>!);
 
 # Empty stash value
-$t->get_ok('/docs3')->status_is(200)->content_like(qr!<h3></h3>!);
+$t->get_ok('/docs3')->status_is(200)->content_like(qr!<h3.*></h3>!);
 
 # REST request for "foo" format
 $t->get_ok('/rest')->status_is(200)->header_is('X-Rest' => 1)
@@ -132,12 +132,17 @@ $t->websocket_ok('/echo')->send_ok({binary => 'bytes!'})
   ->send_ok({binary => 'bytes!'})
   ->message_ok->message_isnt({text => 'bytes!'})->finish_ok;
 
+# Bytes in multiple frames
+$t->websocket_ok('/echo')->send_ok([0, 0, 0, 0, 2, 'a'])
+  ->send_ok([0, 0, 0, 0, 0, 'b'])->send_ok([1, 0, 0, 0, 0, 'c'])
+  ->message_ok->message_is({binary => 'abc'})->finish_ok;
+
 # Zero
 $t->websocket_ok('/echo')->send_ok(0)->message_ok->message_is('echo: 0')
   ->send_ok(0)->message_ok->message_like({text => qr/0/})->finish_ok(1000)
   ->finished_ok(1000);
 
-# 64bit binary message (extended limit)
+# 64-bit binary message (extended limit)
 $t->request_ok($t->ua->build_websocket_tx('/echo'));
 is $t->tx->max_websocket_size, 262144, 'right size';
 $t->tx->max_websocket_size(262145);
@@ -145,11 +150,11 @@ $t->send_ok({binary => 'a' x 262145})
   ->message_ok->message_is({binary => 'a' x 262145})
   ->finish_ok->finished_ok(1005);
 
-# 64bit binary message (too large)
+# 64-bit binary message (too large)
 $t->websocket_ok('/echo')->send_ok({binary => 'b' x 262145})
   ->finished_ok(1009);
 
-# Binary message in two 64bit frames without FIN bit (too large)
+# Binary message in two 64-bit frames without FIN bit (too large)
 $t->websocket_ok('/echo')->send_ok([0, 0, 0, 0, 2, 'c' x 100000])
   ->send_ok([0, 0, 0, 0, 0, 'c' x 162146])->finished_ok(1009);
 
@@ -7,5 +7,8 @@ plan skip_all => 'set TEST_POD to enable this test (developer only!)'
 plan skip_all => 'Test::Pod::Coverage 1.04 required for this test!'
   unless eval 'use Test::Pod::Coverage 1.04; 1';
 
+# DEPRECATED in Tiger Face!
+my @tiger = (qw(emit_safe has_conditions render_static));
+
 # False positive constants
-all_pod_coverage_ok({also_private => [qw(IPV6 TLS)]});
+all_pod_coverage_ok({also_private => [qw(IPV6 TLS), @tiger]});