Mojolicious(3)
π NAME π
okay bestie, welcome to the Mojolicious(3) manual β yes, thatβs the Mojolicious page from User Contributed Perl Documentation. Itβs literally the real-time web framework. π
β¨ SYNOPSIS β¨
# Application
package MyApp;
use Mojo::Base 'Mojolicious', -signatures;
# Route
sub startup ($self) {
$self->routes->get('/hello')->to('foo#hello');
}
# Controller
package MyApp::Controller::Foo;
use Mojo::Base 'Mojolicious::Controller', -signatures;
# Action
sub hello ($self) {
$self->render(text => 'Hello World!');
}
π¦ DESCRIPTION π¦
Itβs an amazing real-time web framework built on top of the powerful Mojo web development toolkit. No cap, it has support for RESTful routes, plugins, commands, Perl-ish templates, content negotiation, session management, form validation, testing framework, static file server, CGI/PSGI detection, first class Unicode support, and much more for you to discover. π
Take a look at our excellent documentation in Mojolicious::Guides! π«Ά
π HOOKS π
okay so Mojolicious will emit the following hooks in the listed order β do not shuffle them, bestie. π
πΈ before_command πΈ
Emitted right before the application runs a command through the command line interface.
$app->hook(before_command => sub ($command, $args) {...});
Useful for reconfiguring the application before running a command or to modify the behavior of a command. (Passed the command object and the command arguments) β¨
πΈ before_server_start πΈ
Emitted right before the application server is started, for web servers that support it, which includes all the built-in ones.
$app->hook(before_server_start => sub ($server, $app) {...});
Useful for reconfiguring application servers dynamically or collecting server diagnostics information. (Passed the server and application objects) π¦
πΈ after_build_tx πΈ
Emitted right after the transaction is built and before the HTTP request gets parsed.
$app->hook(after_build_tx => sub ($tx, $app) {...});
This is a very powerful hook and should not be used lightly β it makes some rather advanced features such as upload progress bars possible. Note that this hook will not work for embedded applications, because only the host application gets to build transactions. (Passed the transaction and application objects) π
πΈ around_dispatch πΈ
Emitted right after a new request has been received 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 reply->exception in Mojolicious::Plugin::DefaultHelpers is the first hook in the chain and a call to dispatch the last, yours will be in between.
$app->hook(around_dispatch => sub ($next, $c) {
...
$next->();
...
});
This is a very powerful hook and should not be used lightly β it allows you to, for example, customize application-wide exception handling, consider it the sledgehammer in your toolbox. (Passed a callback leading to the next hook and the default controller object) π₯
πΈ before_dispatch πΈ
Emitted right before the static file server and router start their work.
$app->hook(before_dispatch => sub ($c) {...});
Very useful for rewriting incoming requests and other preprocessing tasks. (Passed the default controller object) π
πΈ after_static πΈ
Emitted after a static file response has been generated by the static file server.
$app->hook(after_static => sub ($c) {...});
Mostly used for post-processing static file responses. (Passed the default controller object) π
πΈ before_routes πΈ
Emitted after the static file server determined if a static file should be served and before the router starts its work.
$app->hook(before_routes => sub ($c) {...});
Mostly used for custom dispatchers and collecting metrics. (Passed the default controller object) π
πΈ around_action πΈ
Emitted right before an action gets executed and wraps around it, so you have to manually forward to the next hook if you want to continue the chain. Default action dispatching is the last hook in the chain, yours will run before it.
$app->hook(around_action => sub ($next, $c, $action, $last) {
...
return $next->();
});
This is a very powerful hook and should not be used lightly β it allows you for example to pass additional arguments to actions or handle return values differently. Note that this hook can trigger more than once for the same request if there are nested routes. (Passed a callback leading to the next hook, the current controller object, the action callback and a flag indicating if this action is an endpoint) π
πΈ before_render πΈ
Emitted before content is generated by the renderer. Note that this hook can trigger out of order due to its dynamic nature, and with embedded applications will only work for the application that is rendering.
$app->hook(before_render => sub ($c, $args) {...});
Mostly used for pre-processing arguments passed to the renderer. (Passed the current controller object and the render arguments) π§
πΈ after_render πΈ
Emitted after content has been generated by the renderer that will be assigned to the response. Note that this hook can trigger out of order due to its dynamic nature, and with embedded applications will only work for the application that is rendering.
$app->hook(after_render => sub ($c, $output, $format) {...});
Mostly used for post-processing dynamically generated content. (Passed the current controller object, a reference to the content and the format) β¨
πΈ after_dispatch πΈ
Emitted in reverse order after a response has been generated. Note that this hook can trigger out of order due to its dynamic nature, and with embedded applications will only work for the application that is generating the response.
$app->hook(after_dispatch => sub ($c) {...});
Useful for rewriting outgoing responses and other post-processing tasks. (Passed the current controller object) π
β¨ ATTRIBUTES β¨
okay so Mojolicious implements these attributes, and hereβs the whole lineup, bestie. Every default is included, every snippet is exact, and nothing gets skipped. π
π commands π
my $commands = $app->commands;
$app = $app->commands(Mojolicious::Commands->new);
This is the command line interface for your app, and it defaults to a Mojolicious::Commands object. Cute. If you want it to load commands from another namespace too:
# Add another namespace to load commands from
push @{$app->commands->namespaces}, 'MyApp::Command';
π controller_class π
my $class = $app->controller_class;
$app = $app->controller_class('Mojolicious::Controller');
This is the class used for the default controller, and it defaults to Mojolicious::Controller. Heads up, bestie: this class needs to have already been loaded before the first request arrives. No last-minute glow-ups.
π exception_format π
my $format = $app->exception_format;
$app = $app->exception_format('txt');
This is the format for HTTP exceptions β the valid values are "html", "json", or "txt" β and it defaults to "html". β¨
π home π
my $home = $app->home;
$app = $app->home(Mojo::Home->new);
This is the home directory of your app. It defaults to a Mojo::Home object, which stringifies to the actual path. Obsessed with a path object that knows what it is. If you want a portable path relative to the home directory:
# Portably generate path relative to home directory
my $path = $app->home->child('data', 'important.txt');
π log π
my $log = $app->log;
$app = $app->log(Mojo::Log->new);
This is the logging layer of your app, and it defaults to a Mojo::Log object. The level will default to either the MOJO_LOG_LEVEL environment variable, trace if the mode is development, or info otherwise. All messages will be written to STDERR by default. Hereβs a tiny example:
# Log debug message
$app->log->debug('It works');
π max_request_size π
my $max = $app->max_request_size;
$app = $app->max_request_size(16777216);
Maximum request size in bytes, and it defaults to the value of max_message_size in Mojo::Message. Setting the value to 0 will allow requests of indefinite size. Careful, though: increasing this value can also drastically increase memory usage, should you for example attempt to parse an excessively large request body with the methods dom in Mojo::Message or json in Mojo::Message. π
π mode π
my $mode = $app->mode;
$app = $app->mode('production');
The operating mode for your app, and it defaults to a value from the MOJO_MODE and PLACK_ENV environment variables or development. Main character energy, but make it environment-aware. π
π moniker π
my $moniker = $app->moniker;
$app = $app->moniker('foo_bar');
Moniker of this application, often used as default filename for configuration files and the like. It defaults to decamelizing the application class with decamelize in Mojo::Util. π
π plugins π
my $plugins = $app->plugins;
$app = $app->plugins(Mojolicious::Plugins->new);
This is the plugin manager, and it defaults to a Mojolicious::Plugins object. See the plugin method below if you want to load a plugin. If you need another namespace to load plugins from:
# Add another namespace to load plugins from
push @{$app->plugins->namespaces}, 'MyApp::Plugin';
π preload_namespaces π
my $namespaces = $app->preload_namespaces;
$app = $app->preload_namespaces(['MyApp::Controller']);
These are the namespaces to preload classes from during application startup. Get those classes loaded early, bestie. β
π renderer π
my $renderer = $app->renderer;
$app = $app->renderer(Mojolicious::Renderer->new);
This is used to render content, and it defaults to a Mojolicious::Renderer object. For more information about how to generate content see Mojolicious::Guides::Rendering. Hereβs the whole little example group:
# Enable compression
$app->renderer->compress(1);
# Add another "templates" directory
push @{$app->renderer->paths}, '/home/sri/templates';
# Add another "templates" directory with higher precedence
unshift @{$app->renderer->paths}, '/home/sri/themes/blue/templates';
# Add another class with templates in DATA section
push @{$app->renderer->classes}, 'Mojolicious::Plugin::Fun';
π routes π
my $routes = $app->routes;
$app = $app->routes(Mojolicious::Routes->new);
This is the router, and it defaults to a Mojolicious::Routes object. You use this in your startup method to define the url endpoints for your application. Routes are literally the blueprint of the whole vibe:
# Add routes
my $r = $app->routes;
$r->get('/foo/bar')->to('test#foo', title => 'Hello Mojo!');
$r->post('/baz')->to('test#baz');
# Add another namespace to load controllers from
push @{$app->routes->namespaces}, 'MyApp::MyController';
π secrets π
my $secrets = $app->secrets;
$app = $app->secrets([$bytes]);
Secret passphrases used for signed cookies and the like. They default to the moniker of this application, which is not very secure, so you should change it!!! As long as you are using the insecure default there will be debug messages in the log file reminding you to change your passphrase. Only the first passphrase is used to create new signatures, but all of them for verification. So you can increase security without invalidating all your existing signed cookies by rotating passphrases β just add new ones to the front and remove old ones from the back. Iconic security glow-up.
# Rotate passphrases
$app->secrets(['new_passw0rd', 'old_passw0rd', 'very_old_passw0rd']);
π sessions π
my $sessions = $app->sessions;
$app = $app->sessions(Mojolicious::Sessions->new);
Signed cookie based session manager, and it defaults to a Mojolicious::Sessions object. You can usually leave this alone β see session in Mojolicious::Controller for more information about working with session data. But if you want to tweak the session vibes:
# Enable encrypted sessions
$app->sessions->encrypted(1);
# Change name of cookie used for all sessions
$app->sessions->cookie_name('mysession');
# Disable SameSite feature
$app->sessions->samesite(undef);
π static π
my $static = $app->static;
$app = $app->static(Mojolicious::Static->new);
For serving static files from your public directories, and it defaults to a Mojolicious::Static object. The whole static-files serve:
# Serve static files only with a "/static" prefix
$app->static->prefix('/static');
# Add another "public" directory
push @{$app->static->paths}, '/home/sri/public';
# Add another "public" directory with higher precedence
unshift @{$app->static->paths}, '/home/sri/themes/blue/public';
# Add another class with static files in DATA section
push @{$app->static->classes}, 'Mojolicious::Plugin::Fun';
# Remove built-in favicon
delete $app->static->extra->{'favicon.ico'};
π types π
my $types = $app->types;
$app = $app->types(Mojolicious::Types->new);
Responsible for connecting file extensions with MIME types, and it defaults to a Mojolicious::Types object. Add a custom MIME type like this:
# Add custom MIME type
$app->types->type(twt => 'text/tweet');
π ua π
my $ua = $app->ua;
$app = $app->ua(Mojo::UserAgent->new);
A full featured HTTP user agent for use in your applications, and it defaults to a Mojo::UserAgent object. Blocking request? Say less:
# Perform blocking request
say $app->ua->get('example.com')->result->body;
π validator π
my $validator = $app->validator;
$app = $app->validator(Mojolicious::Validator->new);
Validate values, and it defaults to a Mojolicious::Validator object. Add checks and filters like this:
# Add validation check
$app->validator->add_check(foo => sub ($v, $name, $value) {
return $value ne 'foo';
});
# Add validation filter
$app->validator->add_filter(quotemeta => sub ($v, $name, $value) {
return quotemeta $value;
});
Mojolicious inherits all methods from Mojo::Base and implements the following new ones. π
β¨ build_controller
my $c = $app->build_controller;
my $c = $app->build_controller(Mojo::Transaction::HTTP->new);
my $c = $app->build_controller(Mojolicious::Controller->new);
Builds the default controller object with controller_class, bestie. Itβs giving βcontroller factoryβ energy. π«Ά
# Render template from application
my $foo = $app->build_controller->render_to_string(template => 'foo');
β¨ build_tx
my $tx = $app->build_tx;
Builds a Mojo::Transaction::HTTP object and emits the after_build_tx hook. Transaction icon behavior. π₯
β¨ config
my $hash = $app->config;
my $foo = $app->config('foo');
$app = $app->config({foo => 'bar', baz => 23});
$app = $app->config(foo => 'bar', baz => 23);
Application configuration. Literally the appβs little settings stash. π
# Remove value
my $foo = delete $app->config->{foo};
# Assign multiple values at once
$app->config(foo => 'test', bar => 23);
β¨ defaults
my $hash = $app->defaults;
my $foo = $app->defaults('foo');
$app = $app->defaults({foo => 'bar', baz => 23});
$app = $app->defaults(foo => 'bar', baz => 23);
Default values for stash in Mojolicious::Controller, assigned for every new request. So every request gets the little starter pack. β¨
# Remove value
my $foo = delete $app->defaults->{foo};
# Assign multiple values at once
$app->defaults(foo => 'test', bar => 23);
β¨ dispatch
$app->dispatch(Mojolicious::Controller->new);
The heart of every Mojolicious application, no cap. Calls the static and routes dispatchers for every request and passes them a Mojolicious::Controller object. Main character method fr fr. π
β¨ handler
$app->handler(Mojo::Transaction::HTTP->new);
$app->handler(Mojolicious::Controller->new);
Sets up the default controller and emits the around_dispatch hook for every request. Very βlet me handle thisβ of it. π
β¨ helper
$app->helper(foo => sub {...});
Add or replace a helper that will be available as a method of the controller object and the application object, as well as a function in ep templates. For a full list of helpers that are available by default see Mojolicious::Plugin::DefaultHelpers and Mojolicious::Plugin::TagHelpers. Helper girlies stay winning. π§
# Helper
$app->helper(cache => sub { state $cache = {} });
# Application
$app->cache->{foo} = 'bar';
my $result = $app->cache->{foo};
# Controller
$c->cache->{foo} = 'bar';
my $result = $c->cache->{foo};
# Template
% cache->{foo} = 'bar';
%= cache->{foo}
β¨ hook
$app->hook(after_dispatch => sub {...});
Extend Mojolicious with hooks, which allow code to be shared with all requests indiscriminately, for a full list of available hooks see HOOKS. Hooked on hooks, honestly. πͺ
# Dispatchers will not run if there's already a response code defined
$app->hook(before_dispatch => sub ($c) {
$c->render(text => 'Skipped static file server and router!')
if $c->req->url->path->to_route =~ /do_not_dispatch/;
});
β¨ new
my $app = Mojolicious->new;
my $app = Mojolicious->new(moniker => 'foo_bar');
my $app = Mojolicious->new({moniker => 'foo_bar'});
Construct a new Mojolicious application and call startup. Will automatically detect your home directory. Also sets up the renderer, static file server, a default set of plugins and an around_dispatch hook with the default exception handling. New app smell β¨
β¨ plugin
$app->plugin('some_thing');
$app->plugin('some_thing', foo => 23);
$app->plugin('some_thing', {foo => 23});
$app->plugin('SomeThing');
$app->plugin('SomeThing', foo => 23);
$app->plugin('SomeThing', {foo => 23});
$app->plugin('MyApp::Plugin::SomeThing');
$app->plugin('MyApp::Plugin::SomeThing', foo => 23);
$app->plugin('MyApp::Plugin::SomeThing', {foo => 23});
Load a plugin, for a full list of example plugins included in the Mojolicious distribution see PLUGINS in Mojolicious::Plugins. Plug me in, bestie. π
β¨ server
$app->server(Mojo::Server->new);
Emits the before_server_start hook. Server era incoming. π
β¨ start
$app->start;
$app->start(@ARGV);
Start the command line interface for your application. For a full list of commands that are available by default see COMMANDS in Mojolicious::Commands. Note that the options -h/--help, --home and -m/--mode, which are shared by all commands, will be parsed from @ARGV during compile time. CLI moment fr fr. π»
# Always start daemon
$app->start('daemon', '-l', 'http://*:8080');
β¨ startup
$app->startup;
This is your main hook into the application, it will be called at application startup. Meant to be overloaded in a subclass. Your appβs little βfirst day of schoolβ moment. π
sub startup ($self) {...}
β¨ warmup
$app->warmup;
Preload classes from preload_namespaces for future use. Warming up before the main event, periodt. π₯
π§Έ HELPERS π§Έ
In addition to the ATTRIBUTES and METHODS above you can also call helpers on Mojolicious objects. This includes all helpers from Mojolicious::Plugin::DefaultHelpers and Mojolicious::Plugin::TagHelpers. Note that application helpers are always called with a new default controller object, so they can't depend on or change controller state, which includes request, response and stash. Important little helper lore. π«Ά
# Call helper
say $app->dumper({foo => 'bar'});
# Longer version
say $app->build_controller->helpers->dumper({foo => 'bar'});
π¦ BUNDLED FILES π¦
The Mojolicious distribution includes a few files with different licenses that have been bundled for internal use. License housekeeping, but make it cute. π
π¨ Mojolicious Artwork
Copyright (C) 2010-2025, Sebastian Riedel.
Licensed under the CC-SA License, Version 4.0 <http://creativecommons.org/licenses/by-sa/4.0>.
π¨ highlight.js
Copyright (C) 2006, Ivan Sagalaev.
Licensed under the BSD License, <https://github.com/highlightjs/highlight.js/blob/master/LICENSE>.
π¨ Bootstrap
Copyright 2011-2020 The Bootstrap Authors.
Copyright 2011-2020 Twitter, Inc.
Licensed under the MIT License, <http://creativecommons.org/licenses/MIT>.
π¨ Font Awesome
Licensed under the CC-BY License, Version 4.0 <https://creativecommons.org/licenses/by/4.0/> and SIL OFL, Version 1.1 <https://opensource.org/licenses/OFL-1.1>.
π·οΈ CODE NAMES π·οΈ
Every major release of Mojolicious has a code name, these are the ones that have been used in the past. Little emoji-coded eras, iykyk. β¨
9.0, "Waffle" (U+1F9C7)8.0, "Supervillain" (U+1F9B9)7.0, "Doughnut" (U+1F369)6.0, "Clinking Beer Mugs" (U+1F37B)5.0, "Tiger Face" (U+1F42F)4.0, "Top Hat" (U+1F3A9)3.0, "Rainbow" (U+1F308)2.0, "Leaf Fluttering In Wind" (U+1F343)1.0, "Snowflake" (U+2744)
π SPONSORS π
- Stix
<https://stix.no>sponsored the creation of the Mojolicious logo (designed by Nicolai Graesdal) and transferred its copyright to Sebastian Riedel. Iconic logo behavior. π¨ - Some of the work on this distribution has been sponsored by The Perl Foundation
<https://www.perlfoundation.org>. Shoutout to the sponsors, fr fr. π
π«Ά AUTHORS
Okay bestie, real talk: Mojolicious is an open source project and it runs entirely on the tireless, unpaid, lowkey-heroic support of its contributors. Like, these people did not have to go this hard, and yet. π
π Project Founder
- Sebastian Riedel,
kraih@mojolicious.orgβ the literal founder, the main character of this whole saga π
π Core Developers
The current voting members of the core team, in alphabetical order (no cap, alphabetized and everything):
- CandyAngel,
candyangel@mojolicious.org - Christopher Rasch-Olsen Raa,
christopher@mojolicious.org - Dan Book,
grinnz@mojolicious.org - Jan Henning Thorsen,
batman@mojolicious.org - Joel Berger,
jberger@mojolicious.org - Marcus Ramberg,
marcus@mojolicious.org
And the following members of the core team are currently on hiatus (they're on a little β¨ wellness retreat β¨ from voting duties, not gone forever):
- Abhijit Menon-Sen,
ams@cpan.org - Glen Hinkle,
tempire@cpan.org
π¦ Contributors
In alphabetical order β yes, all of them, I would never do these legends dirty by cutting the list short:
- Adam Kennedy
- Adriano Ferreira
- Al Newkirk
- Alex Efros
- Alex Salimon
- Alexander Karelas
- Alexander Kuehne
- Alexey Likhatskiy
- Anatoly Sharifulin
- Andre Parker
- Andre Vieth
- Andreas Guldstrand
- Andreas Jaekel
- Andreas Koenig
- Andrew Fresh
- Andrew Nugged
- Andrey Khozov
- Andrey Kuzmin
- Andy Grundman
- Andy Lester
- Aristotle Pagaltzis
- Ashley Dev
- Ask Bjoern Hansen
- Audrey Tang
- Ben Tyler
- Ben van Staveren
- Benjamin Erhart
- Bernhard Graf
- Breno G. de Oliveira
- Brett Watson
- Brian Duggan
- Brian Medley
- Burak Gursoy
- Ch Lamprecht
- Charlie Brady
- Chas. J. Owens IV
- Chase Whitener
- Chris Scheller
- Christian Hansen
- chromatic
- Curt Tilmes
- Daniel Kimsey
- Daniel Mantovani
- Danijel Tasov
- Dagfinn Ilmari MannsΓ₯ker
- Danny Thomas
- David Davis
- David Webb
- Diego Kuperman
- Dmitriy Shalashov
- Dmitry Konstantinov
- Dominik Jarmulowicz
- Dominique Dumont
- Dotan Dimet
- Douglas Christopher Wilson
- Elmar S. Heeb
- Ettore Di Giacinto
- Eugen Konkov
- Eugene Toropov
- Flavio Poletti
- Gisle Aas
- Graham Barr
- Graham Knop
- Heiko Jansen
- Henry Tang
- Hernan Lopes
- Hideki Yamamura
- Hiroki Toyokawa
- Ian Goodacre
- Ilya Chesnokov
- Ilya Rassadin
- James Duncan
- Jan Jona Javorsek
- Jan Schmidt
- Jaroslav Muhin
- Jesse Vincent
- Johannes Plunien
- John Kingsley
- Jonathan Yu
- Josh Leder
- Kamen Naydenov
- Karen Etheridge
- Kazuhiro Shibuya
- Kevin Old
- Kitamura Akatsuki
- Klaus S. Madsen
- Knut Arne Bjorndal
- Lars Balker Rasmussen
- Lee Johnson
- Leon Brocard
- Leon Timmermans
- Lukas Mai
- Magnus Holm
- Maik Fischer
- Mark Fowler
- Mark Grimes
- Mark Stosberg
- Martin McGrath
- Marty Tennison
- Matt S Trout
- Matthew Lineen
- Maksym Komar
- Maxim Vuets
- Michael Gregorowicz
- Michael Harris
- Michael Jemmeson
- Mike Magowan
- Mirko Westermeier
- Mons Anderson
- Moritz Lenz
- Neil Watkiss
- Nic Sandfield
- Nils Diewald
- Oleg Zhelo
- Oliver Kurz
- Olivier Mengue
- Pascal Gaudette
- Paul Evans
- Paul Robins
- Paul Tomlin
- Pavel Shaydo
- Pedro Melo
- Peter Edwards
- Pierre-Yves Ritschard
- Piotr Roszatycki
- Quentin Carbonneaux
- Rafal Pocztarski
- Randal Schwartz
- Rawley Fowler
- Richard Elberger
- Rick Delaney
- Robert Hicks
- Robert Rothenberg
- Robin Lee
- Roland Lammel
- Roy Storey
- Ryan Jendoubi
- Salvador Fandino
- Santiago Zarate
- Sascha Kiefer
- Scott Wiersdorf
- Sebastian Paaske Torholm
- Sergey Zasenko
- Simon Bertrang
- Simone Tampieri
- Shoichi Kaji
- Shu Cho
- Skye Shaw
- Stanis Trendelenburg
- Stefan Adams
- Steffen Ullrich
- Stephan Kulow
- Stephane Este-Gracias
- Stevan Little
- Steve Atkins
- Tatsuhiko Miyagawa
- Terrence Brannon
- Tianon Gravi
- Tomas Znamenacek
- Tudor Constantin
- Ulrich Habel
- Ulrich Kautz
- Uwe Voelker
- Veesh Goldman
- Viacheslav Tykhanovskyi
- Victor Engmark
- Viliam Pucik
- Wes Cravens
- William Lindley
- Yaroslav Korshak
- Yuki Kimoto
- Zak B. Elep
- Zoffix Znet
That's a whole community, bestie. Every single one of them ate. π₯
π COPYRIGHT AND LICENSE
Copyright (C) 2008-2025, Sebastian Riedel and others.
This program is free software, you can redistribute it and/or modify it under the terms of the Artistic License version 2.0. So yes, go forth and remix, just keep the license terms intact, iykyk. π
π SEE ALSO
https://github.com/mojolicious/mojoMojolicious::Guideshttps://mojolicious.org
Like, the guides are literally right there and they are so good. Go read them, bestie, I'm begging. π«Ά
And that's a wrap!! β¨π
π¦ This page came to you courtesy of perl v5.42.0, dated 2026-07-15, and it's filed under Mojolicious(3) β iconic, no notes. Now go build something cute. π
π¦ where this page comes from
- opensuse-leap 16.0: perl-Mojolicious 9.480.0-bp160.2.1 Β· Artistic-2.0
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms