1Mojolicious(3) User Contributed Perl Documentation Mojolicious(3)
2
3
4
6 Mojolicious - Real-time web framework
7
9 # Application
10 package MyApp;
11 use Mojo::Base 'Mojolicious';
12
13 # Route
14 sub startup {
15 my $self = shift;
16 $self->routes->get('/hello')->to('foo#hello');
17 }
18
19 # Controller
20 package MyApp::Controller::Foo;
21 use Mojo::Base 'Mojolicious::Controller';
22
23 # Action
24 sub hello {
25 my $self = shift;
26 $self->render(text => 'Hello World!');
27 }
28
30 An amazing real-time web framework built on top of the powerful Mojo
31 web development toolkit. With support for RESTful routes, plugins,
32 commands, Perl-ish templates, content negotiation, session management,
33 form validation, testing framework, static file server, "CGI"/"PSGI"
34 detection, first class Unicode support and much more for you to
35 discover.
36
37 Take a look at our excellent documentation in Mojolicious::Guides!
38
40 Mojolicious will emit the following hooks in the listed order.
41
42 before_server_start
43 Emitted right before the application server is started, for web servers
44 that support it, which includes all the built-in ones (except for
45 Mojo::Server::CGI).
46
47 $app->hook(before_server_start => sub {
48 my ($server, $app) = @_;
49 ...
50 });
51
52 Useful for reconfiguring application servers dynamically or collecting
53 server diagnostics information. (Passed the server and application
54 objects)
55
56 after_build_tx
57 Emitted right after the transaction is built and before the HTTP
58 request gets parsed.
59
60 $app->hook(after_build_tx => sub {
61 my ($tx, $app) = @_;
62 ...
63 });
64
65 This is a very powerful hook and should not be used lightly, it makes
66 some rather advanced features such as upload progress bars possible.
67 Note that this hook will not work for embedded applications, because
68 only the host application gets to build transactions. (Passed the
69 transaction and application objects)
70
71 around_dispatch
72 Emitted right after a new request has been received and wraps around
73 the whole dispatch process, so you have to manually forward to the next
74 hook if you want to continue the chain. Default exception handling with
75 "reply->exception" in Mojolicious::Plugin::DefaultHelpers is the first
76 hook in the chain and a call to "dispatch" the last, yours will be in
77 between.
78
79 $app->hook(around_dispatch => sub {
80 my ($next, $c) = @_;
81 ...
82 $next->();
83 ...
84 });
85
86 This is a very powerful hook and should not be used lightly, it allows
87 you to, for example, customize application-wide exception handling,
88 consider it the sledgehammer in your toolbox. (Passed a callback
89 leading to the next hook and the default controller object)
90
91 before_dispatch
92 Emitted right before the static file server and router start their
93 work.
94
95 $app->hook(before_dispatch => sub {
96 my $c = shift;
97 ...
98 });
99
100 Very useful for rewriting incoming requests and other preprocessing
101 tasks. (Passed the default controller object)
102
103 after_static
104 Emitted after a static file response has been generated by the static
105 file server.
106
107 $app->hook(after_static => sub {
108 my $c = shift;
109 ...
110 });
111
112 Mostly used for post-processing static file responses. (Passed the
113 default controller object)
114
115 before_routes
116 Emitted after the static file server determined if a static file should
117 be served and before the router starts its work.
118
119 $app->hook(before_routes => sub {
120 my $c = shift;
121 ...
122 });
123
124 Mostly used for custom dispatchers and collecting metrics. (Passed the
125 default controller object)
126
127 around_action
128 Emitted right before an action gets executed and wraps around it, so
129 you have to manually forward to the next hook if you want to continue
130 the chain. Default action dispatching is the last hook in the chain,
131 yours will run before it.
132
133 $app->hook(around_action => sub {
134 my ($next, $c, $action, $last) = @_;
135 ...
136 return $next->();
137 });
138
139 This is a very powerful hook and should not be used lightly, it allows
140 you for example to pass additional arguments to actions or handle
141 return values differently. Note that this hook can trigger more than
142 once for the same request if there are nested routes. (Passed a
143 callback leading to the next hook, the current controller object, the
144 action callback and a flag indicating if this action is an endpoint)
145
146 before_render
147 Emitted before content is generated by the renderer. Note that this
148 hook can trigger out of order due to its dynamic nature, and with
149 embedded applications will only work for the application that is
150 rendering.
151
152 $app->hook(before_render => sub {
153 my ($c, $args) = @_;
154 ...
155 });
156
157 Mostly used for pre-processing arguments passed to the renderer.
158 (Passed the current controller object and the render arguments)
159
160 after_render
161 Emitted after content has been generated by the renderer that will be
162 assigned to the response. Note that this hook can trigger out of order
163 due to its dynamic nature, and with embedded applications will only
164 work for the application that is rendering.
165
166 $app->hook(after_render => sub {
167 my ($c, $output, $format) = @_;
168 ...
169 });
170
171 Mostly used for post-processing dynamically generated content. (Passed
172 the current controller object, a reference to the content and the
173 format)
174
175 after_dispatch
176 Emitted in reverse order after a response has been generated. Note that
177 this hook can trigger out of order due to its dynamic nature, and with
178 embedded applications will only work for the application that is
179 generating the response.
180
181 $app->hook(after_dispatch => sub {
182 my $c = shift;
183 ...
184 });
185
186 Useful for rewriting outgoing responses and other post-processing
187 tasks. (Passed the current controller object)
188
190 Mojolicious implements the following attributes.
191
192 commands
193 my $commands = $app->commands;
194 $app = $app->commands(Mojolicious::Commands->new);
195
196 Command line interface for your application, defaults to a
197 Mojolicious::Commands object.
198
199 # Add another namespace to load commands from
200 push @{$app->commands->namespaces}, 'MyApp::Command';
201
202 controller_class
203 my $class = $app->controller_class;
204 $app = $app->controller_class('Mojolicious::Controller');
205
206 Class to be used for the default controller, defaults to
207 Mojolicious::Controller. Note that this class needs to have already
208 been loaded before the first request arrives.
209
210 home
211 my $home = $app->home;
212 $app = $app->home(Mojo::Home->new);
213
214 The home directory of your application, defaults to a Mojo::Home object
215 which stringifies to the actual path.
216
217 # Portably generate path relative to home directory
218 my $path = $app->home->child('data', 'important.txt');
219
220 log
221 my $log = $app->log;
222 $app = $app->log(Mojo::Log->new);
223
224 The logging layer of your application, defaults to a Mojo::Log object.
225 The level will default to either the "MOJO_LOG_LEVEL" environment
226 variable, "debug" if the "mode" is "development", or "info" otherwise.
227 All messages will be written to "STDERR", or a "log/$mode.log" file if
228 a "log" directory exists.
229
230 # Log debug message
231 $app->log->debug('It works');
232
233 max_request_size
234 my $max = $app->max_request_size;
235 $app = $app->max_request_size(16777216);
236
237 Maximum request size in bytes, defaults to the value of
238 "max_message_size" in Mojo::Message. Setting the value to 0 will allow
239 requests of indefinite size. Note that increasing this value can also
240 drastically increase memory usage, should you for example attempt to
241 parse an excessively large request body with the methods "dom" in
242 Mojo::Message or "json" in Mojo::Message.
243
244 mode
245 my $mode = $app->mode;
246 $app = $app->mode('production');
247
248 The operating mode for your application, defaults to a value from the
249 "MOJO_MODE" and "PLACK_ENV" environment variables or "development".
250
251 moniker
252 my $moniker = $app->moniker;
253 $app = $app->moniker('foo_bar');
254
255 Moniker of this application, often used as default filename for
256 configuration files and the like, defaults to decamelizing the
257 application class with "decamelize" in Mojo::Util.
258
259 plugins
260 my $plugins = $app->plugins;
261 $app = $app->plugins(Mojolicious::Plugins->new);
262
263 The plugin manager, defaults to a Mojolicious::Plugins object. See the
264 "plugin" method below if you want to load a plugin.
265
266 # Add another namespace to load plugins from
267 push @{$app->plugins->namespaces}, 'MyApp::Plugin';
268
269 renderer
270 my $renderer = $app->renderer;
271 $app = $app->renderer(Mojolicious::Renderer->new);
272
273 Used to render content, defaults to a Mojolicious::Renderer object. For
274 more information about how to generate content see
275 Mojolicious::Guides::Rendering.
276
277 # Enable compression
278 $app->renderer->compress(1);
279
280 # Add another "templates" directory
281 push @{$app->renderer->paths}, '/home/sri/templates';
282
283 # Add another "templates" directory with higher precedence
284 unshift @{$app->renderer->paths}, '/home/sri/themes/blue/templates';
285
286 # Add another class with templates in DATA section
287 push @{$app->renderer->classes}, 'Mojolicious::Plugin::Fun';
288
289 routes
290 my $routes = $app->routes;
291 $app = $app->routes(Mojolicious::Routes->new);
292
293 The router, defaults to a Mojolicious::Routes object. You use this in
294 your startup method to define the url endpoints for your application.
295
296 # Add routes
297 my $r = $app->routes;
298 $r->get('/foo/bar')->to('test#foo', title => 'Hello Mojo!');
299 $r->post('/baz')->to('test#baz');
300
301 # Add another namespace to load controllers from
302 push @{$app->routes->namespaces}, 'MyApp::MyController';
303
304 secrets
305 my $secrets = $app->secrets;
306 $app = $app->secrets([$bytes]);
307
308 Secret passphrases used for signed cookies and the like, defaults to
309 the "moniker" of this application, which is not very secure, so you
310 should change it!!! As long as you are using the insecure default there
311 will be debug messages in the log file reminding you to change your
312 passphrase. Only the first passphrase is used to create new signatures,
313 but all of them for verification. So you can increase security without
314 invalidating all your existing signed cookies by rotating passphrases,
315 just add new ones to the front and remove old ones from the back.
316
317 # Rotate passphrases
318 $app->secrets(['new_passw0rd', 'old_passw0rd', 'very_old_passw0rd']);
319
320 sessions
321 my $sessions = $app->sessions;
322 $app = $app->sessions(Mojolicious::Sessions->new);
323
324 Signed cookie based session manager, defaults to a
325 Mojolicious::Sessions object. You can usually leave this alone, see
326 "session" in Mojolicious::Controller for more information about working
327 with session data.
328
329 # Change name of cookie used for all sessions
330 $app->sessions->cookie_name('mysession');
331
332 # Disable SameSite feature
333 $app->sessions->samesite(undef);
334
335 static
336 my $static = $app->static;
337 $app = $app->static(Mojolicious::Static->new);
338
339 For serving static files from your "public" directories, defaults to a
340 Mojolicious::Static object.
341
342 # Add another "public" directory
343 push @{$app->static->paths}, '/home/sri/public';
344
345 # Add another "public" directory with higher precedence
346 unshift @{$app->static->paths}, '/home/sri/themes/blue/public';
347
348 # Add another class with static files in DATA section
349 push @{$app->static->classes}, 'Mojolicious::Plugin::Fun';
350
351 # Remove built-in favicon
352 delete $app->static->extra->{'favicon.ico'};
353
354 types
355 my $types = $app->types;
356 $app = $app->types(Mojolicious::Types->new);
357
358 Responsible for connecting file extensions with MIME types, defaults to
359 a Mojolicious::Types object.
360
361 # Add custom MIME type
362 $app->types->type(twt => 'text/tweet');
363
364 ua
365 my $ua = $app->ua;
366 $app = $app->ua(Mojo::UserAgent->new);
367
368 A full featured HTTP user agent for use in your applications, defaults
369 to a Mojo::UserAgent object.
370
371 # Perform blocking request
372 say $app->ua->get('example.com')->result->body;
373
374 validator
375 my $validator = $app->validator;
376 $app = $app->validator(Mojolicious::Validator->new);
377
378 Validate values, defaults to a Mojolicious::Validator object.
379
380 # Add validation check
381 $app->validator->add_check(foo => sub {
382 my ($v, $name, $value) = @_;
383 return $value ne 'foo';
384 });
385
386 # Add validation filter
387 $app->validator->add_filter(quotemeta => sub {
388 my ($v, $name, $value) = @_;
389 return quotemeta $value;
390 });
391
393 Mojolicious inherits all methods from Mojo::Base and implements the
394 following new ones.
395
396 build_controller
397 my $c = $app->build_controller;
398 my $c = $app->build_controller(Mojo::Transaction::HTTP->new);
399 my $c = $app->build_controller(Mojolicious::Controller->new);
400
401 Build default controller object with "controller_class".
402
403 # Render template from application
404 my $foo = $app->build_controller->render_to_string(template => 'foo');
405
406 build_tx
407 my $tx = $app->build_tx;
408
409 Build Mojo::Transaction::HTTP object and emit "after_build_tx" hook.
410
411 config
412 my $hash = $app->config;
413 my $foo = $app->config('foo');
414 $app = $app->config({foo => 'bar', baz => 23});
415 $app = $app->config(foo => 'bar', baz => 23);
416
417 Application configuration.
418
419 # Remove value
420 my $foo = delete $app->config->{foo};
421
422 # Assign multiple values at once
423 $app->config(foo => 'test', bar => 23);
424
425 defaults
426 my $hash = $app->defaults;
427 my $foo = $app->defaults('foo');
428 $app = $app->defaults({foo => 'bar', baz => 23});
429 $app = $app->defaults(foo => 'bar', baz => 23);
430
431 Default values for "stash" in Mojolicious::Controller, assigned for
432 every new request.
433
434 # Remove value
435 my $foo = delete $app->defaults->{foo};
436
437 # Assign multiple values at once
438 $app->defaults(foo => 'test', bar => 23);
439
440 dispatch
441 $app->dispatch(Mojolicious::Controller->new);
442
443 The heart of every Mojolicious application, calls the "static" and
444 "routes" dispatchers for every request and passes them a
445 Mojolicious::Controller object.
446
447 handler
448 $app->handler(Mojo::Transaction::HTTP->new);
449 $app->handler(Mojolicious::Controller->new);
450
451 Sets up the default controller and emits the "around_dispatch" hook for
452 every request.
453
454 helper
455 $app->helper(foo => sub {...});
456
457 Add or replace a helper that will be available as a method of the
458 controller object and the application object, as well as a function in
459 "ep" templates. For a full list of helpers that are available by
460 default see Mojolicious::Plugin::DefaultHelpers and
461 Mojolicious::Plugin::TagHelpers.
462
463 # Helper
464 $app->helper(cache => sub { state $cache = {} });
465
466 # Application
467 $app->cache->{foo} = 'bar';
468 my $result = $app->cache->{foo};
469
470 # Controller
471 $c->cache->{foo} = 'bar';
472 my $result = $c->cache->{foo};
473
474 # Template
475 % cache->{foo} = 'bar';
476 %= cache->{foo}
477
478 hook
479 $app->hook(after_dispatch => sub {...});
480
481 Extend Mojolicious with hooks, which allow code to be shared with all
482 requests indiscriminately, for a full list of available hooks see
483 "HOOKS".
484
485 # Dispatchers will not run if there's already a response code defined
486 $app->hook(before_dispatch => sub {
487 my $c = shift;
488 $c->render(text => 'Skipped static file server and router!')
489 if $c->req->url->path->to_route =~ /do_not_dispatch/;
490 });
491
492 new
493 my $app = Mojolicious->new;
494 my $app = Mojolicious->new(moniker => 'foo_bar');
495 my $app = Mojolicious->new({moniker => 'foo_bar'});
496
497 Construct a new Mojolicious application and call "startup". Will
498 automatically detect your home directory. Also sets up the renderer,
499 static file server, a default set of plugins and an "around_dispatch"
500 hook with the default exception handling.
501
502 plugin
503 $app->plugin('some_thing');
504 $app->plugin('some_thing', foo => 23);
505 $app->plugin('some_thing', {foo => 23});
506 $app->plugin('SomeThing');
507 $app->plugin('SomeThing', foo => 23);
508 $app->plugin('SomeThing', {foo => 23});
509 $app->plugin('MyApp::Plugin::SomeThing');
510 $app->plugin('MyApp::Plugin::SomeThing', foo => 23);
511 $app->plugin('MyApp::Plugin::SomeThing', {foo => 23});
512
513 Load a plugin, for a full list of example plugins included in the
514 Mojolicious distribution see "PLUGINS" in Mojolicious::Plugins.
515
516 server
517 $app->server(Mojo::Server->new);
518
519 Emits the "before_server_start" hook.
520
521 start
522 $app->start;
523 $app->start(@ARGV);
524
525 Start the command line interface for your application. For a full list
526 of commands that are available by default see "COMMANDS" in
527 Mojolicious::Commands. Note that the options "-h"/"--help", "--home"
528 and "-m"/"--mode", which are shared by all commands, will be parsed
529 from @ARGV during compile time.
530
531 # Always start daemon
532 $app->start('daemon', '-l', 'http://*:8080');
533
534 startup
535 $app->startup;
536
537 This is your main hook into the application, it will be called at
538 application startup. Meant to be overloaded in a subclass.
539
540 sub startup {
541 my $self = shift;
542 ...
543 }
544
546 In addition to the "ATTRIBUTES" and "METHODS" above you can also call
547 helpers on Mojolicious objects. This includes all helpers from
548 Mojolicious::Plugin::DefaultHelpers and
549 Mojolicious::Plugin::TagHelpers. Note that application helpers are
550 always called with a new default controller object, so they can't
551 depend on or change controller state, which includes request, response
552 and stash.
553
554 # Call helper
555 say $app->dumper({foo => 'bar'});
556
557 # Longer version
558 say $app->build_controller->helpers->dumper({foo => 'bar'});
559
561 The Mojolicious distribution includes a few files with different
562 licenses that have been bundled for internal use.
563
564 Mojolicious Artwork
565 Copyright (C) 2010-2019, Sebastian Riedel.
566
567 Licensed under the CC-SA License, Version 4.0
568 <http://creativecommons.org/licenses/by-sa/4.0>.
569
570 jQuery
571 Copyright (C) jQuery Foundation.
572
573 Licensed under the MIT License,
574 <http://creativecommons.org/licenses/MIT>.
575
576 prettify.js
577 Copyright (C) 2006, 2013 Google Inc..
578
579 Licensed under the Apache License, Version 2.0
580 <http://www.apache.org/licenses/LICENSE-2.0>.
581
583 Every major release of Mojolicious has a code name, these are the ones
584 that have been used in the past.
585
586 8.0, "Supervillain" (U+1F9B9)
587
588 7.0, "Doughnut" (U+1F369)
589
590 6.0, "Clinking Beer Mugs" (U+1F37B)
591
592 5.0, "Tiger Face" (U+1F42F)
593
594 4.0, "Top Hat" (U+1F3A9)
595
596 3.0, "Rainbow" (U+1F308)
597
598 2.0, "Leaf Fluttering In Wind" (U+1F343)
599
600 1.0, "Snowflake" (U+2744)
601
603 · Stix <https://stix.no> sponsored the creation of the Mojolicious logo
604 (designed by Nicolai Graesdal) and transferred its copyright to
605 Sebastian Riedel.
606
607 · Some of the work on this distribution has been sponsored by The Perl
608 Foundation <http://www.perlfoundation.org>.
609
611 Sebastian Riedel, "kraih@mojolicious.org"
612
614 Current members of the core team in alphabetical order:
615
616 Jan Henning Thorsen, "batman@mojolicious.org"
617
618 Joel Berger, "jberger@mojolicious.org"
619
620 Marcus Ramberg, "marcus@mojolicious.org"
621
622 The following members of the core team are currently on hiatus:
623
624 Abhijit Menon-Sen, "ams@cpan.org"
625
626 Glen Hinkle, "tempire@cpan.org"
627
629 In alphabetical order:
630
631 Adam Kennedy
632
633 Adriano Ferreira
634
635 Al Newkirk
636
637 Alex Efros
638
639 Alex Salimon
640
641 Alexander Karelas
642
643 Alexey Likhatskiy
644
645 Anatoly Sharifulin
646
647 Andre Parker
648
649 Andre Vieth
650
651 Andreas Guldstrand
652
653 Andreas Jaekel
654
655 Andreas Koenig
656
657 Andrew Fresh
658
659 Andrew Nugged
660
661 Andrey Khozov
662
663 Andrey Kuzmin
664
665 Andy Grundman
666
667 Aristotle Pagaltzis
668
669 Ashley Dev
670
671 Ask Bjoern Hansen
672
673 Audrey Tang
674
675 Ben Tyler
676
677 Ben van Staveren
678
679 Benjamin Erhart
680
681 Bernhard Graf
682
683 Breno G. de Oliveira
684
685 Brian Duggan
686
687 Brian Medley
688
689 Burak Gursoy
690
691 Ch Lamprecht
692
693 Charlie Brady
694
695 Chas. J. Owens IV
696
697 Chase Whitener
698
699 Christian Hansen
700
701 chromatic
702
703 Curt Tilmes
704
705 Dan Book
706
707 Daniel Kimsey
708
709 Daniel Mantovani
710
711 Danijel Tasov
712
713 Danny Thomas
714
715 David Davis
716
717 David Webb
718
719 Diego Kuperman
720
721 Dmitriy Shalashov
722
723 Dmitry Konstantinov
724
725 Dominik Jarmulowicz
726
727 Dominique Dumont
728
729 Dotan Dimet
730
731 Douglas Christopher Wilson
732
733 Ettore Di Giacinto
734
735 Eugen Konkov
736
737 Eugene Toropov
738
739 Flavio Poletti
740
741 Gisle Aas
742
743 Graham Barr
744
745 Graham Knop
746
747 Henry Tang
748
749 Hideki Yamamura
750
751 Hiroki Toyokawa
752
753 Ian Goodacre
754
755 Ilya Chesnokov
756
757 Ilya Rassadin
758
759 James Duncan
760
761 Jan Jona Javorsek
762
763 Jan Schmidt
764
765 Jaroslav Muhin
766
767 Jesse Vincent
768
769 Johannes Plunien
770
771 John Kingsley
772
773 Jonathan Yu
774
775 Josh Leder
776
777 Kazuhiro Shibuya
778
779 Kevin Old
780
781 Kitamura Akatsuki
782
783 Klaus S. Madsen
784
785 Knut Arne Bjorndal
786
787 Lars Balker Rasmussen
788
789 Lee Johnson
790
791 Leon Brocard
792
793 Magnus Holm
794
795 Maik Fischer
796
797 Mark Fowler
798
799 Mark Grimes
800
801 Mark Stosberg
802
803 Marty Tennison
804
805 Matt S Trout
806
807 Matthew Lineen
808
809 Maksym Komar
810
811 Maxim Vuets
812
813 Michael Gregorowicz
814
815 Michael Harris
816
817 Mike Magowan
818
819 Mirko Westermeier
820
821 Mons Anderson
822
823 Moritz Lenz
824
825 Neil Watkiss
826
827 Nic Sandfield
828
829 Nils Diewald
830
831 Oleg Zhelo
832
833 Olivier Mengue
834
835 Pascal Gaudette
836
837 Paul Evans
838
839 Paul Robins
840
841 Paul Tomlin
842
843 Pavel Shaydo
844
845 Pedro Melo
846
847 Peter Edwards
848
849 Pierre-Yves Ritschard
850
851 Piotr Roszatycki
852
853 Quentin Carbonneaux
854
855 Rafal Pocztarski
856
857 Randal Schwartz
858
859 Richard Elberger
860
861 Rick Delaney
862
863 Robert Hicks
864
865 Robin Lee
866
867 Roland Lammel
868
869 Roy Storey
870
871 Ryan Jendoubi
872
873 Salvador Fandino
874
875 Santiago Zarate
876
877 Sascha Kiefer
878
879 Scott Wiersdorf
880
881 Sergey Zasenko
882
883 Simon Bertrang
884
885 Simone Tampieri
886
887 Shu Cho
888
889 Skye Shaw
890
891 Stanis Trendelenburg
892
893 Stefan Adams
894
895 Steffen Ullrich
896
897 Stephan Kulow
898
899 Stephane Este-Gracias
900
901 Stevan Little
902
903 Steve Atkins
904
905 Tatsuhiko Miyagawa
906
907 Terrence Brannon
908
909 Tianon Gravi
910
911 Tomas Znamenacek
912
913 Tudor Constantin
914
915 Ulrich Habel
916
917 Ulrich Kautz
918
919 Uwe Voelker
920
921 Viacheslav Tykhanovskyi
922
923 Victor Engmark
924
925 Viliam Pucik
926
927 Wes Cravens
928
929 William Lindley
930
931 Yaroslav Korshak
932
933 Yuki Kimoto
934
935 Zak B. Elep
936
937 Zoffix Znet
938
940 Copyright (C) 2008-2019, Sebastian Riedel and others.
941
942 This program is free software, you can redistribute it and/or modify it
943 under the terms of the Artistic License version 2.0.
944
946 <https://github.com/mojolicious/mojo>, Mojolicious::Guides,
947 <https://mojolicious.org>.
948
949
950
951perl v5.28.1 2019-01-02 Mojolicious(3)