← Index
NYTProf Performance Profile   « line view »
For ../prof.pl
  Run on Wed Dec 14 15:33:55 2022
Reported on Wed Dec 14 15:40:02 2022

Filename/Users/ether/.perlbrew/libs/36.0@std/lib/perl5/Mojo/Util.pm
StatementsExecuted 9361013 statements in 10.4s
Subroutines
Calls P F Exclusive
Time
Inclusive
Time
Subroutine
1053034323.02s5.25sMojo::Util::::url_escape Mojo::Util::url_escape
1053034322.91s4.38sMojo::Util::::encode Mojo::Util::encode
18728922876ms2.40sMojo::Util::::decode Mojo::Util::decode
124032321690ms690msMojo::Util::::_encoding Mojo::Util::_encoding
28714832562ms1.40sMojo::Util::::url_unescape Mojo::Util::url_unescape
134018665487ms1.21sMojo::Util::::CORE:subst Mojo::Util::CORE:subst (opcode)
332633245.4ms45.4msMojo::Util::::CORE:substcont Mojo::Util::CORE:substcont (opcode)
1119.86ms11.1msMojo::Util::::BEGIN@11 Mojo::Util::BEGIN@11
1116.53ms8.13msMojo::Util::::BEGIN@5 Mojo::Util::BEGIN@5
1113.62ms48.2msMojo::Util::::BEGIN@17 Mojo::Util::BEGIN@17
1113.60ms6.46msMojo::Util::::BEGIN@18 Mojo::Util::BEGIN@18
1112.16ms42.8msMojo::Util::::BEGIN@12 Mojo::Util::BEGIN@12
2231111.94ms1.94msMojo::Util::::CORE:match Mojo::Util::CORE:match (opcode)
1111.92ms2.12msMojo::Util::::BEGIN@10 Mojo::Util::BEGIN@10
1111.89ms3.16msMojo::Util::::BEGIN@6 Mojo::Util::BEGIN@6
1111.80ms3.86msMojo::Util::::BEGIN@22 Mojo::Util::BEGIN@22
1111.72ms14.5msMojo::Util::::BEGIN@14 Mojo::Util::BEGIN@14
1111.39ms4.33msMojo::Util::::BEGIN@7 Mojo::Util::BEGIN@7
1111.28ms1.39msMojo::Util::::BEGIN@13.4 Mojo::Util::BEGIN@13.4
1111.26ms2.40msMojo::Util::::BEGIN@21 Mojo::Util::BEGIN@21
1111.01ms1.01msMojo::Util::::CORE:readline Mojo::Util::CORE:readline (opcode)
111921µs2.25msMojo::Util::::BEGIN@16.6 Mojo::Util::BEGIN@16.6
22102168µs272µsMojo::Util::::monkey_patch Mojo::Util::monkey_patch
11195µs532µsMojo::Util::::BEGIN@2 Mojo::Util::BEGIN@2
11189µs89µsMojo::Util::::CORE:open Mojo::Util::CORE:open (opcode)
11124µs124µsMojo::Util::::BEGIN@25 Mojo::Util::BEGIN@25
11120µs128µsMojo::Util::::BEGIN@4 Mojo::Util::BEGIN@4
11120µs30µsMojo::Util::::BEGIN@532 Mojo::Util::BEGIN@532
11117µs46µsMojo::Util::::BEGIN@15.5 Mojo::Util::BEGIN@15.5
11117µs22µsMojo::Util::::BEGIN@431 Mojo::Util::BEGIN@431
11114µs17µsMojo::Util::::BEGIN@232 Mojo::Util::BEGIN@232
11112µs46µsMojo::Util::::BEGIN@19 Mojo::Util::BEGIN@19
11112µs20µsMojo::Util::::BEGIN@203 Mojo::Util::BEGIN@203
11111µs13µsMojo::Util::::BEGIN@265 Mojo::Util::BEGIN@265
11111µs230µsMojo::Util::_Guard::::BEGIN@538Mojo::Util::_Guard::BEGIN@538
11110µs26µsMojo::Util::::BEGIN@20 Mojo::Util::BEGIN@20
11110µs114µsMojo::Util::::BEGIN@28 Mojo::Util::BEGIN@28
1117µs70µsMojo::Util::::BEGIN@8 Mojo::Util::BEGIN@8
1115µs26µsMojo::Util::::BEGIN@204 Mojo::Util::BEGIN@204
4415µs5µsMojo::Util::::CORE:qr Mojo::Util::CORE:qr (opcode)
1113µs10µsMojo::Util::::BEGIN@9 Mojo::Util::BEGIN@9
0000s0sMojo::Util::_Guard::::DESTROYMojo::Util::_Guard::DESTROY
0000s0sMojo::Util::::__ANON__[:89] Mojo::Util::__ANON__[:89]
0000s0sMojo::Util::::_adapt Mojo::Util::_adapt
0000s0sMojo::Util::::_entity Mojo::Util::_entity
0000s0sMojo::Util::::_header Mojo::Util::_header
0000s0sMojo::Util::::_html Mojo::Util::_html
0000s0sMojo::Util::::_options Mojo::Util::_options
0000s0sMojo::Util::::_readable Mojo::Util::_readable
0000s0sMojo::Util::::_round Mojo::Util::_round
0000s0sMojo::Util::::_stash Mojo::Util::_stash
0000s0sMojo::Util::::_teardown Mojo::Util::_teardown
0000s0sMojo::Util::::camelize Mojo::Util::camelize
0000s0sMojo::Util::::class_to_file Mojo::Util::class_to_file
0000s0sMojo::Util::::class_to_path Mojo::Util::class_to_path
0000s0sMojo::Util::::decamelize Mojo::Util::decamelize
0000s0sMojo::Util::::deprecated Mojo::Util::deprecated
0000s0sMojo::Util::::dumper Mojo::Util::dumper
0000s0sMojo::Util::::extract_usage Mojo::Util::extract_usage
0000s0sMojo::Util::::getopt Mojo::Util::getopt
0000s0sMojo::Util::::gunzip Mojo::Util::gunzip
0000s0sMojo::Util::::gzip Mojo::Util::gzip
0000s0sMojo::Util::::header_params Mojo::Util::header_params
0000s0sMojo::Util::::html_attr_unescape Mojo::Util::html_attr_unescape
0000s0sMojo::Util::::html_unescape Mojo::Util::html_unescape
0000s0sMojo::Util::::humanize_bytes Mojo::Util::humanize_bytes
0000s0sMojo::Util::::network_contains Mojo::Util::network_contains
0000s0sMojo::Util::::punycode_decode Mojo::Util::punycode_decode
0000s0sMojo::Util::::punycode_encode Mojo::Util::punycode_encode
0000s0sMojo::Util::::quote Mojo::Util::quote
0000s0sMojo::Util::::scope_guard Mojo::Util::scope_guard
0000s0sMojo::Util::::secure_compare Mojo::Util::secure_compare
0000s0sMojo::Util::::slugify Mojo::Util::slugify
0000s0sMojo::Util::::split_cookie_header Mojo::Util::split_cookie_header
0000s0sMojo::Util::::split_header Mojo::Util::split_header
0000s0sMojo::Util::::steady_time Mojo::Util::steady_time
0000s0sMojo::Util::::tablify Mojo::Util::tablify
0000s0sMojo::Util::::term_escape Mojo::Util::term_escape
0000s0sMojo::Util::::trim Mojo::Util::trim
0000s0sMojo::Util::::unindent Mojo::Util::unindent
0000s0sMojo::Util::::unquote Mojo::Util::unquote
0000s0sMojo::Util::::xml_escape Mojo::Util::xml_escape
0000s0sMojo::Util::::xor_encode Mojo::Util::xor_encode
Call graph for these subroutines as a Graphviz dot language file.
Line State
ments
Time
on line
Calls Time
in subs
Code
1package Mojo::Util;
22130µs2969µs
# spent 532µs (95+437) within Mojo::Util::BEGIN@2 which was called: # once (95µs+437µs) by Mojo::URL::BEGIN@2 at line 2
use Mojo::Base -strict;
# spent 532µs making 1 call to Mojo::Util::BEGIN@2 # spent 437µs making 1 call to Mojo::Base::import
3
4268µs2236µs
# spent 128µs (20+108) within Mojo::Util::BEGIN@4 which was called: # once (20µs+108µs) by Mojo::URL::BEGIN@2 at line 4
use Carp qw(carp croak);
# spent 128µs making 1 call to Mojo::Util::BEGIN@4 # spent 108µs making 1 call to Exporter::import
521.27ms18.13ms
# spent 8.13ms (6.53+1.60) within Mojo::Util::BEGIN@5 which was called: # once (6.53ms+1.60ms) by Mojo::URL::BEGIN@2 at line 5
use Data::Dumper ();
# spent 8.13ms making 1 call to Mojo::Util::BEGIN@5
621.04ms23.20ms
# spent 3.16ms (1.89+1.28) within Mojo::Util::BEGIN@6 which was called: # once (1.89ms+1.28ms) by Mojo::URL::BEGIN@2 at line 6
use Digest::MD5 qw(md5 md5_hex);
# spent 3.16ms making 1 call to Mojo::Util::BEGIN@6 # spent 35µs making 1 call to Exporter::import
72425µs24.40ms
# spent 4.33ms (1.39+2.94) within Mojo::Util::BEGIN@7 which was called: # once (1.39ms+2.94ms) by Mojo::URL::BEGIN@2 at line 7
use Digest::SHA qw(hmac_sha1_hex sha1 sha1_hex);
# spent 4.33ms making 1 call to Mojo::Util::BEGIN@7 # spent 71µs making 1 call to Exporter::import
8218µs2133µs
# spent 70µs (7+63) within Mojo::Util::BEGIN@8 which was called: # once (7µs+63µs) by Mojo::URL::BEGIN@2 at line 8
use Encode qw(find_encoding);
# spent 70µs making 1 call to Mojo::Util::BEGIN@8 # spent 63µs making 1 call to Exporter::import
9212µs217µs
# spent 10µs (3+7) within Mojo::Util::BEGIN@9 which was called: # once (3µs+7µs) by Mojo::URL::BEGIN@2 at line 9
use Exporter qw(import);
# spent 10µs making 1 call to Mojo::Util::BEGIN@9 # spent 7µs making 1 call to Exporter::import
102644µs22.15ms
# spent 2.12ms (1.92+197µs) within Mojo::Util::BEGIN@10 which was called: # once (1.92ms+197µs) by Mojo::URL::BEGIN@2 at line 10
use File::Basename qw(dirname);
# spent 2.12ms making 1 call to Mojo::Util::BEGIN@10 # spent 39µs making 1 call to Exporter::import
112818µs211.2ms
# spent 11.1ms (9.86+1.22) within Mojo::Util::BEGIN@11 which was called: # once (9.86ms+1.22ms) by Mojo::URL::BEGIN@2 at line 11
use Getopt::Long qw(GetOptionsFromArray);
# spent 11.1ms making 1 call to Mojo::Util::BEGIN@11 # spent 128µs making 1 call to Getopt::Long::import
122946µs242.8ms
# spent 42.8ms (2.16+40.6) within Mojo::Util::BEGIN@12 which was called: # once (2.16ms+40.6ms) by Mojo::URL::BEGIN@2 at line 12
use IO::Compress::Gzip;
# spent 42.8ms making 1 call to Mojo::Util::BEGIN@12 # spent 18µs making 1 call to Exporter::import
132729µs21.44ms
# spent 1.39ms (1.28+112µs) within Mojo::Util::BEGIN@13.4 which was called: # once (1.28ms+112µs) by Mojo::URL::BEGIN@2 at line 13
use IO::Poll qw(POLLIN POLLPRI);
# spent 1.39ms making 1 call to Mojo::Util::BEGIN@13.4 # spent 54µs making 1 call to Exporter::import
142485µs214.5ms
# spent 14.5ms (1.72+12.7) within Mojo::Util::BEGIN@14 which was called: # once (1.72ms+12.7ms) by Mojo::URL::BEGIN@2 at line 14
use IO::Uncompress::Gunzip;
# spent 14.5ms making 1 call to Mojo::Util::BEGIN@14 # spent 14µs making 1 call to Exporter::import
15228µs257µs
# spent 46µs (17+29) within Mojo::Util::BEGIN@15.5 which was called: # once (17µs+29µs) by Mojo::URL::BEGIN@2 at line 15
use List::Util qw(min);
# spent 46µs making 1 call to Mojo::Util::BEGIN@15.5 # spent 11µs making 1 call to List::Util::import
162678µs22.35ms
# spent 2.25ms (921µs+1.33) within Mojo::Util::BEGIN@16.6 which was called: # once (921µs+1.33ms) by Mojo::URL::BEGIN@2 at line 16
use MIME::Base64 qw(decode_base64 encode_base64);
# spent 2.25ms making 1 call to Mojo::Util::BEGIN@16.6 # spent 103µs making 1 call to Exporter::import
172673µs248.3ms
# spent 48.2ms (3.62+44.6) within Mojo::Util::BEGIN@17 which was called: # once (3.62ms+44.6ms) by Mojo::URL::BEGIN@2 at line 17
use Pod::Usage qw(pod2usage);
# spent 48.2ms making 1 call to Mojo::Util::BEGIN@17 # spent 55µs making 1 call to Exporter::import
182721µs27.09ms
# spent 6.46ms (3.60+2.86) within Mojo::Util::BEGIN@18 which was called: # once (3.60ms+2.86ms) by Mojo::URL::BEGIN@2 at line 18
use Socket qw(inet_pton AF_INET6 AF_INET);
# spent 6.46ms making 1 call to Mojo::Util::BEGIN@18 # spent 631µs making 1 call to Exporter::import
19232µs280µs
# spent 46µs (12+34) within Mojo::Util::BEGIN@19 which was called: # once (12µs+34µs) by Mojo::URL::BEGIN@2 at line 19
use Sub::Util qw(set_subname);
# spent 46µs making 1 call to Mojo::Util::BEGIN@19 # spent 34µs making 1 call to Exporter::import
20225µs242µs
# spent 26µs (10+16) within Mojo::Util::BEGIN@20 which was called: # once (10µs+16µs) by Mojo::URL::BEGIN@2 at line 20
use Symbol qw(delete_package);
# spent 26µs making 1 call to Mojo::Util::BEGIN@20 # spent 16µs making 1 call to Exporter::import
212690µs12.40ms
# spent 2.40ms (1.26+1.14) within Mojo::Util::BEGIN@21 which was called: # once (1.26ms+1.14ms) by Mojo::URL::BEGIN@2 at line 21
use Time::HiRes ();
# spent 2.40ms making 1 call to Mojo::Util::BEGIN@21
222682µs13.86ms
# spent 3.86ms (1.80+2.06) within Mojo::Util::BEGIN@22 which was called: # once (1.80ms+2.06ms) by Mojo::URL::BEGIN@2 at line 22
use Unicode::Normalize ();
# spent 3.86ms making 1 call to Mojo::Util::BEGIN@22
23
24# Check for monotonic clock support
25375µs4223µs
# spent 124µs (24+100) within Mojo::Util::BEGIN@25 which was called: # once (24µs+100µs) by Mojo::URL::BEGIN@2 at line 25
use constant MONOTONIC => eval { !!Time::HiRes::clock_gettime(Time::HiRes::CLOCK_MONOTONIC()) };
# spent 124µs making 1 call to Mojo::Util::BEGIN@25 # spent 53µs making 1 call to constant::import # spent 33µs making 1 call to Time::HiRes::AUTOLOAD # spent 13µs making 1 call to Time::HiRes::clock_gettime
26
27# Punycode bootstring parameters
28
# spent 114µs (10+104) within Mojo::Util::BEGIN@28 which was called: # once (10µs+104µs) by Mojo::URL::BEGIN@2 at line 36
use constant {
2911µs PC_BASE => 36,
30 PC_TMIN => 1,
31 PC_TMAX => 26,
32 PC_SKEW => 38,
33 PC_DAMP => 700,
34 PC_INITIAL_BIAS => 72,
35 PC_INITIAL_N => 128
3611.84ms2218µs};
# spent 114µs making 1 call to Mojo::Util::BEGIN@28 # spent 104µs making 1 call to constant::import
37
38# To generate a new HTML entity table run this command
39# perl examples/entities.pl > lib/Mojo/resources/html_entities.txt
4010smy %ENTITIES;
41{
42 # Don't use Mojo::File here due to circular dependencies
432252µs5170µs my $path = File::Spec->catfile(dirname(__FILE__), 'resources', 'html_entities.txt');
# spent 72µs making 1 call to File::Basename::dirname # spent 68µs making 1 call to File::Spec::Unix::catfile # spent 18µs making 2 calls to File::Spec::Unix::canonpath, avg 9µs/call # spent 12µs making 1 call to File::Spec::Unix::catdir
44
45195µs189µs open my $file, '<', $path or croak "Unable to open html entities file ($path): $!";
# spent 89µs making 1 call to Mojo::Util::CORE:open
4631.03ms11.01ms my $lines = do { local $/; <$file> };
# spent 1.01ms making 1 call to Mojo::Util::CORE:readline
47
481441µs for my $line (split /\n/, $lines) {
4922314.49ms22311.94ms next unless $line =~ /^(\S+)\s+U\+(\S+)(?:\s+U\+(\S+))?/;
# spent 1.94ms making 2231 calls to Mojo::Util::CORE:match, avg 869ns/call
5022312.69ms $ENTITIES{$1} = defined $3 ? (chr(hex $2) . chr(hex $3)) : chr(hex $2);
51 }
52}
53
54# Characters that should be escaped in XML
5514µsmy %XML = ('&' => '&amp;', '<' => '&lt;', '>' => '&gt;', '"' => '&quot;', '\'' => '&#39;');
56
57# "Sun, 06 Nov 1994 08:49:37 GMT" and "Sunday, 06-Nov-94 08:49:37 GMT"
58110µs13µsmy $EXPIRES_RE = qr/(\w+\W+\d+\W+\w+\W+\d+\W+\d+:\d+:\d+\W*\w+)/;
# spent 3µs making 1 call to Mojo::Util::CORE:qr
59
60# Header key/value pairs
6112µs11µsmy $QUOTED_VALUE_RE = qr/\G=\s*("(?:\\\\|\\"|[^"])*")/;
# spent 1µs making 1 call to Mojo::Util::CORE:qr
6213µs10smy $UNQUOTED_VALUE_RE = qr/\G=\s*([^;, ]*)/;
# spent 0s making 1 call to Mojo::Util::CORE:qr
63
64# HTML entities
6512µs11µsmy $ENTITY_RE = qr/&(?:\#((?:[0-9]{1,7}|x[0-9a-fA-F]{1,6}));|(\w+[;=]?))/;
# spent 1µs making 1 call to Mojo::Util::CORE:qr
66
67# Encoding and pattern cache
6811µsmy (%ENCODING, %PATTERN);
69
7014µsour @EXPORT_OK = (
71 qw(b64_decode b64_encode camelize class_to_file class_to_path decamelize decode deprecated dumper encode),
72 qw(extract_usage getopt gunzip gzip header_params hmac_sha1_sum html_attr_unescape html_unescape humanize_bytes),
73 qw(md5_bytes md5_sum monkey_patch network_contains punycode_decode punycode_encode quote scope_guard secure_compare),
74 qw(sha1_bytes sha1_sum slugify split_cookie_header split_header steady_time tablify term_escape trim unindent),
75 qw(unquote url_escape url_unescape xml_escape xor_encode)
76);
77
78# Aliases
7914µs121µsmonkey_patch(__PACKAGE__, 'b64_decode', \&decode_base64);
# spent 21µs making 1 call to Mojo::Util::monkey_patch
8012µs17µsmonkey_patch(__PACKAGE__, 'b64_encode', \&encode_base64);
# spent 7µs making 1 call to Mojo::Util::monkey_patch
8112µs17µsmonkey_patch(__PACKAGE__, 'hmac_sha1_sum', \&hmac_sha1_hex);
# spent 7µs making 1 call to Mojo::Util::monkey_patch
8212µs110µsmonkey_patch(__PACKAGE__, 'md5_bytes', \&md5);
# spent 10µs making 1 call to Mojo::Util::monkey_patch
8310s17µsmonkey_patch(__PACKAGE__, 'md5_sum', \&md5_hex);
# spent 7µs making 1 call to Mojo::Util::monkey_patch
8412µs14µsmonkey_patch(__PACKAGE__, 'sha1_bytes', \&sha1);
# spent 4µs making 1 call to Mojo::Util::monkey_patch
8511µs14µsmonkey_patch(__PACKAGE__, 'sha1_sum', \&sha1_hex);
# spent 4µs making 1 call to Mojo::Util::monkey_patch
86
87# Use a monotonic clock if possible
88monkey_patch(__PACKAGE__, 'steady_time',
8913µs17µs MONOTONIC ? sub () { Time::HiRes::clock_gettime(Time::HiRes::CLOCK_MONOTONIC()) } : \&Time::HiRes::time);
# spent 7µs making 1 call to Mojo::Util::monkey_patch
90
91sub camelize {
92 my $str = shift;
93 return $str if $str =~ /^[A-Z]/;
94
95 # CamelCase words
96 return join '::', map {
97 join('', map { ucfirst lc } split /_/)
98 } split /-/, $str;
99}
100
101sub class_to_file {
102 my $class = shift;
103 $class =~ s/::|'//g;
104 $class =~ s/([A-Z])([A-Z]*)/$1 . lc $2/ge;
105 return decamelize($class);
106}
107
108sub class_to_path { join '.', join('/', split(/::|'/, shift)), 'pm' }
109
110sub decamelize {
111 my $str = shift;
112 return $str if $str !~ /^[A-Z]/;
113
114 # snake_case words
115 return join '-', map {
116 join('_', map {lc} grep {length} split /([A-Z]{1}[^A-Z]*)/)
117 } split /::/, $str;
118}
119
120
# spent 2.40s (876ms+1.52) within Mojo::Util::decode which was called 187289 times, avg 13µs/call: # 128616 times (595ms+1.25s) by Mojo::Path::_parse at line 107 of Mojo/Path.pm, avg 14µs/call # 58673 times (281ms+274ms) by Mojo::URL::_decode at line 157 of Mojo/URL.pm, avg 9µs/call
sub decode {
12118728962.8ms my ($encoding, $bytes) = @_;
1225618671.03s5799691.68s return undef unless eval { $bytes = _encoding($encoding)->decode("$bytes", 1); 1 };
# spent 742ms making 187289 calls to Encode::utf8::decode, avg 4µs/call # spent 667ms making 18102 calls to Mojo::Path::__ANON__[Mojo/Path.pm:3], avg 37µs/call # spent 155ms making 187289 calls to Encode::Encoding::renewed, avg 829ns/call # spent 112ms making 187289 calls to Mojo::Util::_encoding, avg 599ns/call
123187289246ms return $bytes;
124}
125
126sub deprecated {
127 local $Carp::CarpLevel = 1;
128 $ENV{MOJO_FATAL_DEPRECATIONS} ? croak @_ : carp @_;
129}
130
131sub dumper { Data::Dumper->new([@_])->Indent(1)->Sortkeys(1)->Terse(1)->Useqq(1)->Dump }
132
13310530343.83s21060681.47s
# spent 4.38s (2.91+1.47) within Mojo::Util::encode which was called 1053034 times, avg 4µs/call: # 529341 times (1.54s+792ms) by Mojo::URL::_encode at line 159 of Mojo/URL.pm, avg 4µs/call # 276110 times (750ms+388ms) by Mojo::Path::to_string at line 86 of Mojo/Path.pm, avg 4µs/call # 247583 times (625ms+291ms) by Mojo::Path::to_string at line 92 of Mojo/Path.pm, avg 4µs/call
sub encode { _encoding($_[0])->encode("$_[1]", 0) }
# spent 894ms making 1053034 calls to Encode::utf8::encode, avg 849ns/call # spent 577ms making 1053034 calls to Mojo::Util::_encoding, avg 548ns/call
134
135sub extract_usage {
136 my $file = @_ ? "$_[0]" : (caller)[1];
137
138 open my $handle, '>', \my $output;
139 pod2usage -exitval => 'noexit', -input => $file, -output => $handle;
140 $output =~ s/^.*\n|\n$//;
141 $output =~ s/\n$//;
142
143 return unindent($output);
144}
145
146sub getopt {
147 my ($array, $opts) = map { ref $_[0] eq 'ARRAY' ? shift : $_ } \@ARGV, [];
148
149 my $save = Getopt::Long::Configure(qw(default no_auto_abbrev no_ignore_case), @$opts);
150 my $result = GetOptionsFromArray $array, @_;
151 Getopt::Long::Configure($save);
152
153 return $result;
154}
155
156sub gunzip {
157 my $compressed = shift;
158 IO::Uncompress::Gunzip::gunzip \$compressed, \my $uncompressed
159 or croak "Couldn't gunzip: $IO::Uncompress::Gunzip::GzipError";
160 return $uncompressed;
161}
162
163sub gzip {
164 my $uncompressed = shift;
165 IO::Compress::Gzip::gzip \$uncompressed, \my $compressed or croak "Couldn't gzip: $IO::Compress::Gzip::GzipError";
166 return $compressed;
167}
168
169sub header_params {
170 my $value = shift;
171
172 my $params = {};
173 while ($value =~ /\G[;\s]*([^=;, ]+)\s*/gc) {
174 my $name = $1;
175
176 # Quoted value
177 if ($value =~ /$QUOTED_VALUE_RE/gco) { $params->{$name} //= unquote($1) }
178
179 # Unquoted value
180 elsif ($value =~ /$UNQUOTED_VALUE_RE/gco) { $params->{$name} //= $1 }
181 }
182
183 return ($params, substr($value, pos($value) // 0));
184}
185
186sub html_attr_unescape { _html(shift, 1) }
187sub html_unescape { _html(shift, 0) }
188
189sub humanize_bytes {
190 my $size = shift;
191
192 my $prefix = $size < 0 ? '-' : '';
193
194 return "$prefix${size}B" if ($size = abs $size) < 1024;
195 return $prefix . _round($size) . 'KiB' if ($size /= 1024) < 1024;
196 return $prefix . _round($size) . 'MiB' if ($size /= 1024) < 1024;
197 return $prefix . _round($size) . 'GiB' if ($size /= 1024) < 1024;
198 return $prefix . _round($size /= 1024) . 'TiB';
199}
200
201
# spent 272µs (168+104) within Mojo::Util::monkey_patch which was called 22 times, avg 12µs/call: # 9 times (79µs+47µs) by Mojo::Base::attr at line 93 of Mojo/Base.pm, avg 14µs/call # 5 times (49µs+30µs) by Mojo::Base::import at line 136 of Mojo/Base.pm, avg 16µs/call # once (12µs+9µs) by Mojo::URL::BEGIN@2 at line 79 # once (8µs+2µs) by Mojo::URL::BEGIN@2 at line 82 # once (4µs+3µs) by Mojo::URL::BEGIN@2 at line 83 # once (4µs+3µs) by Mojo::URL::BEGIN@2 at line 81 # once (4µs+3µs) by Mojo::URL::BEGIN@2 at line 89 # once (5µs+2µs) by Mojo::URL::BEGIN@2 at line 80 # once (1µs+3µs) by Mojo::URL::BEGIN@2 at line 85 # once (2µs+2µs) by Mojo::URL::BEGIN@2 at line 84
sub monkey_patch {
2022222µs my ($class, %patch) = @_;
203233µs228µs
# spent 20µs (12+8) within Mojo::Util::BEGIN@203 which was called: # once (12µs+8µs) by Mojo::URL::BEGIN@2 at line 203
no strict 'refs';
# spent 20µs making 1 call to Mojo::Util::BEGIN@203 # spent 8µs making 1 call to strict::unimport
2042303µs247µs
# spent 26µs (5+21) within Mojo::Util::BEGIN@204 which was called: # once (5µs+21µs) by Mojo::URL::BEGIN@2 at line 204
no warnings 'redefine';
# spent 26µs making 1 call to Mojo::Util::BEGIN@204 # spent 21µs making 1 call to warnings::unimport
20522267µs22104µs *{"${class}::$_"} = set_subname("${class}::$_", $patch{$_}) for keys %patch;
# spent 104µs making 22 calls to Sub::Util::set_subname, avg 5µs/call
206}
207
208sub network_contains {
209 my ($cidr, $addr) = @_;
210 return undef unless length $cidr && length $addr;
211
212 # Parse inputs
213 my ($net, $mask) = split m!/!, $cidr, 2;
214 my $v6 = $net =~ /:/;
215 return undef if $v6 xor $addr =~ /:/;
216
217 # Convert addresses to binary
218 return undef unless $net = inet_pton($v6 ? AF_INET6 : AF_INET, $net);
219 return undef unless $addr = inet_pton($v6 ? AF_INET6 : AF_INET, $addr);
220 my $length = $v6 ? 128 : 32;
221
222 # Apply mask if given
223 $addr &= pack "B$length", '1' x $mask if defined $mask;
224
225 # Compare
226 return 0 == unpack "B$length", ($net ^ $addr);
227}
228
229# Direct translation of RFC 3492
230sub punycode_decode {
231 my $input = shift;
2322245µs220µs
# spent 17µs (14+3) within Mojo::Util::BEGIN@232 which was called: # once (14µs+3µs) by Mojo::URL::BEGIN@2 at line 232
use integer;
# spent 17µs making 1 call to Mojo::Util::BEGIN@232 # spent 3µs making 1 call to integer::import
233
234 my ($n, $i, $bias, @output) = (PC_INITIAL_N, 0, PC_INITIAL_BIAS);
235
236 # Consume all code points before the last delimiter
237 push @output, split(//, $1) if $input =~ s/(.*)\x2d//s;
238
239 while (length $input) {
240 my ($oldi, $w) = ($i, 1);
241
242 # Base to infinity in steps of base
243 for (my $k = PC_BASE; 1; $k += PC_BASE) {
244 my $digit = ord substr $input, 0, 1, '';
245 $digit = $digit < 0x40 ? $digit + (26 - 0x30) : ($digit & 0x1f) - 1;
246 $i += $digit * $w;
247 my $t = $k - $bias;
248 $t = $t < PC_TMIN ? PC_TMIN : $t > PC_TMAX ? PC_TMAX : $t;
249 last if $digit < $t;
250 $w *= PC_BASE - $t;
251 }
252
253 $bias = _adapt($i - $oldi, @output + 1, $oldi == 0);
254 $n += $i / (@output + 1);
255 $i = $i % (@output + 1);
256 splice @output, $i++, 0, chr $n;
257 }
258
259 return join '', @output;
260}
261
262# Direct translation of RFC 3492
263sub punycode_encode {
264 my $output = shift;
26522.49ms215µs
# spent 13µs (11+2) within Mojo::Util::BEGIN@265 which was called: # once (11µs+2µs) by Mojo::URL::BEGIN@2 at line 265
use integer;
# spent 13µs making 1 call to Mojo::Util::BEGIN@265 # spent 2µs making 1 call to integer::import
266
267 my ($n, $delta, $bias) = (PC_INITIAL_N, 0, PC_INITIAL_BIAS);
268
269 # Extract basic code points
270 my @input = map {ord} split //, $output;
271 $output =~ s/[^\x00-\x7f]+//gs;
272 my $h = my $basic = length $output;
273 $output .= "\x2d" if $basic > 0;
274
275 for my $m (sort grep { $_ >= PC_INITIAL_N } @input) {
276 next if $m < $n;
277 $delta += ($m - $n) * ($h + 1);
278 $n = $m;
279
280 for my $c (@input) {
281
282 if ($c < $n) { $delta++ }
283 elsif ($c == $n) {
284 my $q = $delta;
285
286 # Base to infinity in steps of base
287 for (my $k = PC_BASE; 1; $k += PC_BASE) {
288 my $t = $k - $bias;
289 $t = $t < PC_TMIN ? PC_TMIN : $t > PC_TMAX ? PC_TMAX : $t;
290 last if $q < $t;
291 my $o = $t + (($q - $t) % (PC_BASE - $t));
292 $output .= chr $o + ($o < 26 ? 0x61 : 0x30 - 26);
293 $q = ($q - $t) / (PC_BASE - $t);
294 }
295
296 $output .= chr $q + ($q < 26 ? 0x61 : 0x30 - 26);
297 $bias = _adapt($delta, $h + 1, $h == $basic);
298 $delta = 0;
299 $h++;
300 }
301 }
302
303 $delta++;
304 $n++;
305 }
306
307 return $output;
308}
309
310sub quote {
311 my $str = shift;
312 $str =~ s/(["\\])/\\$1/g;
313 return qq{"$str"};
314}
315
316sub scope_guard { Mojo::Util::_Guard->new(cb => shift) }
317
318sub secure_compare {
319 my ($one, $two) = @_;
320 my $r = length $one != length $two;
321 $two = $one if $r;
322 $r |= ord(substr $one, $_) ^ ord(substr $two, $_) for 0 .. length($one) - 1;
323 return $r == 0;
324}
325
326sub slugify {
327 my ($value, $allow_unicode) = @_;
328
329 if ($allow_unicode) {
330
331 # Force unicode semantics by upgrading string
332 utf8::upgrade($value = Unicode::Normalize::NFKC($value));
333 $value =~ s/[^\w\s-]+//g;
334 }
335 else {
336 $value = Unicode::Normalize::NFKD($value);
337 $value =~ s/[^a-zA-Z0-9_\p{PosixSpace}-]+//g;
338 }
339 (my $new = lc trim($value)) =~ s/[-\s]+/-/g;
340
341 return $new;
342}
343
344sub split_cookie_header { _header(shift, 1) }
345sub split_header { _header(shift, 0) }
346
347sub tablify {
348 my $rows = shift;
349
350 my @spec;
351 for my $row (@$rows) {
352 for my $i (0 .. $#$row) {
353 ($row->[$i] //= '') =~ y/\r\n//d;
354 my $len = length $row->[$i];
355 $spec[$i] = $len if $len >= ($spec[$i] // 0);
356 }
357 }
358
359 my @fm = (map({"\%-${_}s"} @spec[0 .. $#spec - 1]), '%s');
360 return join '', map { sprintf join(' ', @fm[0 .. $#$_]) . "\n", @$_ } @$rows;
361}
362
363sub term_escape {
364 my $str = shift;
365 $str =~ s/([\x00-\x09\x0b-\x1f\x7f\x80-\x9f])/sprintf '\\x%02x', ord $1/ge;
366 return $str;
367}
368
369sub trim {
370 my $str = shift;
371 $str =~ s/^\s+//;
372 $str =~ s/\s+$//;
373 return $str;
374}
375
376sub unindent {
377 my $str = shift;
378 my $min = min map { m/^([ \t]*)/; length $1 || () } split /\n/, $str;
379 $str =~ s/^[ \t]{0,$min}//gm if $min;
380 return $str;
381}
382
383sub unquote {
384 my $str = shift;
385 return $str unless $str =~ s/^"(.*)"$/$1/g;
386 $str =~ s/\\\\/\\/g;
387 $str =~ s/\\"/"/g;
388 return $str;
389}
390
391
# spent 5.25s (3.02+2.23) within Mojo::Util::url_escape which was called 1053034 times, avg 5µs/call: # 529341 times (1.53s+1.27s) by Mojo::URL::_encode at line 159 of Mojo/URL.pm, avg 5µs/call # 276110 times (844ms+523ms) by Mojo::Path::to_string at line 87 of Mojo/Path.pm, avg 5µs/call # 247583 times (637ms+436ms) by Mojo::Path::to_string at line 93 of Mojo/Path.pm, avg 4µs/call
sub url_escape {
3921053034315ms my ($str, $pattern) = @_;
393
3941053034239ms if ($pattern) {
3951053034266ms unless (exists $PATTERN{$pattern}) {
396451µs1518µs (my $quoted = $pattern) =~ s!([/\$\[])!\\$1!g;
# spent 12µs making 11 calls to Mojo::Util::CORE:substcont, avg 1µs/call # spent 6µs making 4 calls to Mojo::Util::CORE:subst, avg 2µs/call
3974386µs $PATTERN{$pattern} = eval "sub { \$_[0] =~ s/([$quoted])/sprintf '%%%02X', ord \$1/ge }" or croak $@;
# spent 892ms executing statements in string eval
# includes 581ms spent executing 310114 calls to 1 sub defined therein. # spent 796ms executing statements in string eval
# includes 424ms spent executing 276110 calls to 1 sub defined therein. # spent 717ms executing statements in string eval
# includes 449ms spent executing 219227 calls to 1 sub defined therein. # spent 586ms executing statements in string eval
# includes 361ms spent executing 247583 calls to 1 sub defined therein.
398 }
3991053034867ms10530342.23s $PATTERN{$pattern}->($str);
# spent 712ms making 310114 calls to Mojo::Util::__ANON__[(eval 425)[Mojo/Util.pm:397]:1], avg 2µs/call # spent 560ms making 219227 calls to Mojo::Util::__ANON__[(eval 427)[Mojo/Util.pm:397]:1], avg 3µs/call # spent 523ms making 276110 calls to Mojo::Util::__ANON__[(eval 426)[Mojo/Util.pm:397]:1], avg 2µs/call # spent 436ms making 247583 calls to Mojo::Util::__ANON__[(eval 429)[Mojo/Util.pm:397]:1], avg 2µs/call
400 }
401 else { $str =~ s/([^A-Za-z0-9\-._~])/sprintf '%%%02X', ord $1/ge }
402
40310530341.28s return $str;
404}
405
406
# spent 1.40s (562ms+841ms) within Mojo::Util::url_unescape which was called 287148 times, avg 5µs/call: # 128616 times (254ms+791ms) by Mojo::Path::_parse at line 105 of Mojo/Path.pm, avg 8µs/call # 99859 times (169ms+19.0ms) by Mojo::URL::host_port at line 25 of Mojo/URL.pm, avg 2µs/call # 58673 times (138ms+30.7ms) by Mojo::URL::parse at line 60 of Mojo/URL.pm, avg 3µs/call
sub url_unescape {
40728714867.3ms my $str = shift;
408287148395ms3117661.57s $str =~ s/%([0-9a-fA-F]{2})/chr hex $1/ge;
# spent 837ms making 287148 calls to Mojo::Util::CORE:subst, avg 3µs/call # spent 725ms making 18102 calls to Mojo::Path::__ANON__[Mojo/Path.pm:3], avg 40µs/call # spent 4.58ms making 6516 calls to Mojo::Util::CORE:substcont, avg 702ns/call
409287148401ms return $str;
410}
411
412sub xml_escape {
413 return $_[0] if ref $_[0] && ref $_[0] eq 'Mojo::ByteStream';
414 my $str = shift // '';
415 $str =~ s/([&<>"'])/$XML{$1}/ge;
416 return $str;
417}
418
419sub xor_encode {
420 my ($input, $key) = @_;
421
422 # Encode with variable key length
423 my $len = length $key;
424 my $buffer = my $output = '';
425 $output .= $buffer ^ $key while length($buffer = substr($input, 0, $len, '')) == $len;
426 return $output .= $buffer ^ substr($key, 0, length $buffer, '');
427}
428
429sub _adapt {
430 my ($delta, $numpoints, $firsttime) = @_;
4312980µs227µs
# spent 22µs (17+5) within Mojo::Util::BEGIN@431 which was called: # once (17µs+5µs) by Mojo::URL::BEGIN@2 at line 431
use integer;
# spent 22µs making 1 call to Mojo::Util::BEGIN@431 # spent 5µs making 1 call to integer::import
432
433 $delta = $firsttime ? $delta / PC_DAMP : $delta / 2;
434 $delta += $delta / $numpoints;
435 my $k = 0;
436 while ($delta > ((PC_BASE - PC_TMIN) * PC_TMAX) / 2) {
437 $delta /= PC_BASE - PC_TMIN;
438 $k += PC_BASE;
439 }
440
441 return $k + (((PC_BASE - PC_TMIN + 1) * $delta) / ($delta + PC_SKEW));
442}
443
44412403231.41s126µs
# spent 690ms (690+26µs) within Mojo::Util::_encoding which was called 1240323 times, avg 556ns/call: # 1053034 times (577ms+0s) by Mojo::Util::encode at line 133, avg 548ns/call # 187289 times (112ms+26µs) by Mojo::Util::decode at line 122, avg 599ns/call
sub _encoding { $ENCODING{$_[0]} //= find_encoding($_[0]) // croak "Unknown encoding '$_[0]'" }
# spent 26µs making 1 call to Encode::find_encoding
445
446sub _entity {
447 my ($point, $name, $attr) = @_;
448
449 # Code point
450 return chr($point !~ /^x/ ? $point : hex $point) unless defined $name;
451
452 # Named character reference
453 my $rest = my $last = '';
454 while (length $name) {
455 return $ENTITIES{$name} . reverse $rest
456 if exists $ENTITIES{$name} && (!$attr || $name =~ /;$/ || $last !~ /[A-Za-z0-9=]/);
457 $rest .= $last = chop $name;
458 }
459 return '&' . reverse $rest;
460}
461
462sub _header {
463 my ($str, $cookie) = @_;
464
465 my (@tree, @part);
466 while ($str =~ /\G[,;\s]*([^=;, ]+)\s*/gc) {
467 push @part, $1, undef;
468 my $expires = $cookie && @part > 2 && lc $1 eq 'expires';
469
470 # Special "expires" value
471 if ($expires && $str =~ /\G=\s*$EXPIRES_RE/gco) { $part[-1] = $1 }
472
473 # Quoted value
474 elsif ($str =~ /$QUOTED_VALUE_RE/gco) { $part[-1] = unquote $1 }
475
476 # Unquoted value
477 elsif ($str =~ /$UNQUOTED_VALUE_RE/gco) { $part[-1] = $1 }
478
479 # Separator
480 next unless $str =~ /\G[;\s]*,\s*/gc;
481 push @tree, [@part];
482 @part = ();
483 }
484
485 # Take care of final part
486 return [@part ? (@tree, \@part) : @tree];
487}
488
489sub _html {
490 my ($str, $attr) = @_;
491 $str =~ s/$ENTITY_RE/_entity($1, $2, $attr)/geo;
492 return $str;
493}
494
495sub _options {
496
497 # Hash or name (one)
498 return ref $_[0] eq 'HASH' ? (undef, %{shift()}) : @_ if @_ == 1;
499
500 # Name and values (odd)
501 return shift, @_ if @_ % 2;
502
503 # Name and hash or just values (even)
504 return ref $_[1] eq 'HASH' ? (shift, %{shift()}) : (undef, @_);
505}
506
507# This may break in the future, but is worth it for performance
508sub _readable { !!(IO::Poll::_poll(@_[0, 1], my $m = POLLIN | POLLPRI) > 0) }
509
510sub _round { $_[0] < 10 ? int($_[0] * 10 + 0.5) / 10 : int($_[0] + 0.5) }
511
512sub _stash {
513 my ($name, $object) = (shift, shift);
514
515 # Hash
516 return $object->{$name} //= {} unless @_;
517
518 # Get
519 return $object->{$name}{$_[0]} unless @_ > 1 || ref $_[0];
520
521 # Set
522 my $values = ref $_[0] ? $_[0] : {@_};
523 @{$object->{$name}}{keys %$values} = values %$values;
524
525 return $object;
526}
527
528sub _teardown {
529 return unless my $class = shift;
530
531 # @ISA has to be cleared first because of circular references
5322132µs240µs
# spent 30µs (20+10) within Mojo::Util::BEGIN@532 which was called: # once (20µs+10µs) by Mojo::URL::BEGIN@2 at line 532
no strict 'refs';
# spent 30µs making 1 call to Mojo::Util::BEGIN@532 # spent 10µs making 1 call to strict::unimport
533 @{"${class}::ISA"} = ();
534 delete_package $class;
535}
536
537package Mojo::Util::_Guard;
5382482µs2449µs
# spent 230µs (11+219) within Mojo::Util::_Guard::BEGIN@538 which was called: # once (11µs+219µs) by Mojo::URL::BEGIN@2 at line 538
use Mojo::Base -base;
# spent 230µs making 1 call to Mojo::Util::_Guard::BEGIN@538 # spent 219µs making 1 call to Mojo::Base::import
539
540sub DESTROY { shift->{cb}() }
541
542122µs1;
543
544=encoding utf8
545
546=head1 NAME
547
548Mojo::Util - Portable utility functions
549
550=head1 SYNOPSIS
551
552 use Mojo::Util qw(b64_encode url_escape url_unescape);
553
554 my $str = 'test=23';
555 my $escaped = url_escape $str;
556 say url_unescape $escaped;
557 say b64_encode $escaped, '';
558
559=head1 DESCRIPTION
560
561L<Mojo::Util> provides portable utility functions for L<Mojo>.
562
563=head1 FUNCTIONS
564
565L<Mojo::Util> implements the following functions, which can be imported individually.
566
567=head2 b64_decode
568
569 my $bytes = b64_decode $b64;
570
571Base64 decode bytes with L<MIME::Base64>.
572
573=head2 b64_encode
574
575 my $b64 = b64_encode $bytes;
576 my $b64 = b64_encode $bytes, "\n";
577
578Base64 encode bytes with L<MIME::Base64>, the line ending defaults to a newline.
579
580=head2 camelize
581
582 my $camelcase = camelize $snakecase;
583
584Convert C<snake_case> string to C<CamelCase> and replace C<-> with C<::>.
585
586 # "FooBar"
587 camelize 'foo_bar';
588
589 # "FooBar::Baz"
590 camelize 'foo_bar-baz';
591
592 # "FooBar::Baz"
593 camelize 'FooBar::Baz';
594
595=head2 class_to_file
596
597 my $file = class_to_file 'Foo::Bar';
598
599Convert a class name to a file.
600
601 # "foo_bar"
602 class_to_file 'Foo::Bar';
603
604 # "foobar"
605 class_to_file 'FOO::Bar';
606
607 # "foo_bar"
608 class_to_file 'FooBar';
609
610 # "foobar"
611 class_to_file 'FOOBar';
612
613=head2 class_to_path
614
615 my $path = class_to_path 'Foo::Bar';
616
617Convert class name to path, as used by C<%INC>.
618
619 # "Foo/Bar.pm"
620 class_to_path 'Foo::Bar';
621
622 # "FooBar.pm"
623 class_to_path 'FooBar';
624
625=head2 decamelize
626
627 my $snakecase = decamelize $camelcase;
628
629Convert C<CamelCase> string to C<snake_case> and replace C<::> with C<->.
630
631 # "foo_bar"
632 decamelize 'FooBar';
633
634 # "foo_bar-baz"
635 decamelize 'FooBar::Baz';
636
637 # "foo_bar-baz"
638 decamelize 'foo_bar-baz';
639
640=head2 decode
641
642 my $chars = decode 'UTF-8', $bytes;
643
644Decode bytes to characters with L<Encode>, or return C<undef> if decoding failed.
645
646=head2 deprecated
647
648 deprecated 'foo is DEPRECATED in favor of bar';
649
650Warn about deprecated feature from perspective of caller. You can also set the C<MOJO_FATAL_DEPRECATIONS> environment
651variable to make them die instead with L<Carp>.
652
653=head2 dumper
654
655 my $perl = dumper {some => 'data'};
656
657Dump a Perl data structure with L<Data::Dumper>.
658
659=head2 encode
660
661 my $bytes = encode 'UTF-8', $chars;
662
663Encode characters to bytes with L<Encode>.
664
665=head2 extract_usage
666
667 my $usage = extract_usage;
668 my $usage = extract_usage '/home/sri/foo.pod';
669
670Extract usage message from the SYNOPSIS section of a file containing POD documentation, defaults to using the file this
671function was called from.
672
673 # "Usage: APPLICATION test [OPTIONS]\n"
674 extract_usage;
675
676 =head1 SYNOPSIS
677
678 Usage: APPLICATION test [OPTIONS]
679
680 =cut
681
682=head2 getopt
683
684 getopt
685 'H|headers=s' => \my @headers,
686 't|timeout=i' => \my $timeout,
687 'v|verbose' => \my $verbose;
688 getopt $array,
689 'H|headers=s' => \my @headers,
690 't|timeout=i' => \my $timeout,
691 'v|verbose' => \my $verbose;
692 getopt $array, ['pass_through'],
693 'H|headers=s' => \my @headers,
694 't|timeout=i' => \my $timeout,
695 'v|verbose' => \my $verbose;
696
697Extract options from an array reference with L<Getopt::Long>, but without changing its global configuration, defaults
698to using C<@ARGV>. The configuration options C<no_auto_abbrev> and C<no_ignore_case> are enabled by default.
699
700 # Extract "charset" option
701 getopt ['--charset', 'UTF-8'], 'charset=s' => \my $charset;
702 say $charset;
703
704=head2 gunzip
705
706 my $uncompressed = gunzip $compressed;
707
708Uncompress bytes with L<IO::Compress::Gunzip>.
709
710=head2 gzip
711
712 my $compressed = gzip $uncompressed;
713
714Compress bytes with L<IO::Compress::Gzip>.
715
716=head2 header_params
717
718 my ($params, $remainder) = header_params 'one=foo; two="bar", three=baz';
719
720Extract HTTP header field parameters until the first comma according to L<RFC 5987|http://tools.ietf.org/html/rfc5987>.
721Note that this function is B<EXPERIMENTAL> and might change without warning!
722
723=head2 hmac_sha1_sum
724
725 my $checksum = hmac_sha1_sum $bytes, 'passw0rd';
726
727Generate HMAC-SHA1 checksum for bytes with L<Digest::SHA>.
728
729 # "11cedfd5ec11adc0ec234466d8a0f2a83736aa68"
730 hmac_sha1_sum 'foo', 'passw0rd';
731
732=head2 html_attr_unescape
733
734 my $str = html_attr_unescape $escaped;
735
736Same as L</"html_unescape">, but handles special rules from the L<HTML Living Standard|https://html.spec.whatwg.org>
737for HTML attributes.
738
739 # "foo=bar&ltest=baz"
740 html_attr_unescape 'foo=bar&ltest=baz';
741
742 # "foo=bar<est=baz"
743 html_attr_unescape 'foo=bar&lt;est=baz';
744
745=head2 html_unescape
746
747 my $str = html_unescape $escaped;
748
749Unescape all HTML entities in string.
750
751 # "<div>"
752 html_unescape '&lt;div&gt;';
753
754=head2 humanize_bytes
755
756 my $str = humanize_bytes 1234;
757
758Turn number of bytes into a simplified human readable format.
759
760 # "1B"
761 humanize_bytes 1;
762
763 # "7.5GiB"
764 humanize_bytes 8007188480;
765
766 # "13GiB"
767 humanize_bytes 13443399680;
768
769 # "-685MiB"
770 humanize_bytes -717946880;
771
772=head2 md5_bytes
773
774 my $checksum = md5_bytes $bytes;
775
776Generate binary MD5 checksum for bytes with L<Digest::MD5>.
777
778=head2 md5_sum
779
780 my $checksum = md5_sum $bytes;
781
782Generate MD5 checksum for bytes with L<Digest::MD5>.
783
784 # "acbd18db4cc2f85cedef654fccc4a4d8"
785 md5_sum 'foo';
786
787=head2 monkey_patch
788
789 monkey_patch $package, foo => sub {...};
790 monkey_patch $package, foo => sub {...}, bar => sub {...};
791
792Monkey patch functions into package.
793
794 monkey_patch 'MyApp',
795 one => sub { say 'One!' },
796 two => sub { say 'Two!' },
797 three => sub { say 'Three!' };
798
799=head2 punycode_decode
800
801 my $str = punycode_decode $punycode;
802
803Punycode decode string as described in L<RFC 3492|https://tools.ietf.org/html/rfc3492>.
804
805 # "bücher"
806 punycode_decode 'bcher-kva';
807
808=head2 network_contains
809
810 my $bool = network_contains $network, $address;
811
812Check that a given address is contained within a network in CIDR form. If the network is a single address, the
813addresses must be equivalent.
814
815 # True
816 network_contains('10.0.0.0/8', '10.10.10.10');
817 network_contains('10.10.10.10', '10.10.10.10');
818 network_contains('fc00::/7', 'fc::c0:ff:ee');
819
820 # False
821 network_contains('10.0.0.0/29', '10.10.10.10');
822 network_contains('10.10.10.12', '10.10.10.10');
823 network_contains('fc00::/7', '::1');
824
825=head2 punycode_encode
826
827 my $punycode = punycode_encode $str;
828
829Punycode encode string as described in L<RFC 3492|https://tools.ietf.org/html/rfc3492>.
830
831 # "bcher-kva"
832 punycode_encode 'bücher';
833
834=head2 quote
835
836 my $quoted = quote $str;
837
838Quote string.
839
840=head2 scope_guard
841
842 my $guard = scope_guard sub {...};
843
844Create anonymous scope guard object that will execute the passed callback when the object is destroyed.
845
846 # Execute closure at end of scope
847 {
848 my $guard = scope_guard sub { say "Mojo!" };
849 say "Hello";
850 }
851
852=head2 secure_compare
853
854 my $bool = secure_compare $str1, $str2;
855
856Constant time comparison algorithm to prevent timing attacks. The secret string should be the second argument, to avoid
857leaking information about the length of the string.
858
859=head2 sha1_bytes
860
861 my $checksum = sha1_bytes $bytes;
862
863Generate binary SHA1 checksum for bytes with L<Digest::SHA>.
864
865=head2 sha1_sum
866
867 my $checksum = sha1_sum $bytes;
868
869Generate SHA1 checksum for bytes with L<Digest::SHA>.
870
871 # "0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33"
872 sha1_sum 'foo';
873
874=head2 slugify
875
876 my $slug = slugify $string;
877 my $slug = slugify $string, $bool;
878
879Returns a URL slug generated from the input string. Non-word characters are removed, the string is trimmed and
880lowercased, and whitespace characters are replaced by a dash. By default, non-ASCII characters are normalized to ASCII
881word characters or removed, but if a true value is passed as the second parameter, all word characters will be allowed
882in the result according to unicode semantics.
883
884 # "joel-is-a-slug"
885 slugify 'Joel is a slug';
886
887 # "this-is-my-resume"
888 slugify 'This is: my - résumé! ☃ ';
889
890 # "this-is-my-résumé"
891 slugify 'This is: my - résumé! ☃ ', 1;
892
893=head2 split_cookie_header
894
895 my $tree = split_cookie_header 'a=b; expires=Thu, 07 Aug 2008 07:07:59 GMT';
896
897Same as L</"split_header">, but handles C<expires> values from L<RFC 6265|https://tools.ietf.org/html/rfc6265>.
898
899=head2 split_header
900
901 my $tree = split_header 'foo="bar baz"; test=123, yada';
902
903Split HTTP header value into key/value pairs, each comma separated part gets its own array reference, and keys without
904a value get C<undef> assigned.
905
906 # "one"
907 split_header('one; two="three four", five=six')->[0][0];
908
909 # "two"
910 split_header('one; two="three four", five=six')->[0][2];
911
912 # "three four"
913 split_header('one; two="three four", five=six')->[0][3];
914
915 # "five"
916 split_header('one; two="three four", five=six')->[1][0];
917
918 # "six"
919 split_header('one; two="three four", five=six')->[1][1];
920
921=head2 steady_time
922
923 my $time = steady_time;
924
925High resolution time elapsed from an arbitrary fixed point in the past, resilient to time jumps if a monotonic clock is
926available through L<Time::HiRes>.
927
928=head2 tablify
929
930 my $table = tablify [['foo', 'bar'], ['baz', 'yada']];
931
932Row-oriented generator for text tables.
933
934 # "foo bar\nyada yada\nbaz yada\n"
935 tablify [['foo', 'bar'], ['yada', 'yada'], ['baz', 'yada']];
936
937=head2 term_escape
938
939 my $escaped = term_escape $str;
940
941Escape all POSIX control characters except for C<\n>.
942
943 # "foo\\x09bar\\x0d\n"
944 term_escape "foo\tbar\r\n";
945
946=head2 trim
947
948 my $trimmed = trim $str;
949
950Trim whitespace characters from both ends of string.
951
952 # "foo bar"
953 trim ' foo bar ';
954
955=head2 unindent
956
957 my $unindented = unindent $str;
958
959Unindent multi-line string.
960
961 # "foo\nbar\nbaz\n"
962 unindent " foo\n bar\n baz\n";
963
964=head2 unquote
965
966 my $str = unquote $quoted;
967
968Unquote string.
969
970=head2 url_escape
971
972 my $escaped = url_escape $str;
973 my $escaped = url_escape $str, '^A-Za-z0-9\-._~';
974
975Percent encode unsafe characters in string as described in L<RFC 3986|https://tools.ietf.org/html/rfc3986>, the pattern
976used defaults to C<^A-Za-z0-9\-._~>.
977
978 # "foo%3Bbar"
979 url_escape 'foo;bar';
980
981=head2 url_unescape
982
983 my $str = url_unescape $escaped;
984
985Decode percent encoded characters in string as described in L<RFC 3986|https://tools.ietf.org/html/rfc3986>.
986
987 # "foo;bar"
988 url_unescape 'foo%3Bbar';
989
990=head2 xml_escape
991
992 my $escaped = xml_escape $str;
993
994Escape unsafe characters C<&>, C<E<lt>>, C<E<gt>>, C<"> and C<'> in string, but do not escape L<Mojo::ByteStream>
995objects.
996
997 # "&lt;div&gt;"
998 xml_escape '<div>';
999
1000 # "<div>"
1001 use Mojo::ByteStream qw(b);
1002 xml_escape b('<div>');
1003
1004=head2 xor_encode
1005
1006 my $encoded = xor_encode $str, $key;
1007
1008XOR encode string with variable length key.
1009
1010=head1 SEE ALSO
1011
1012L<Mojolicious>, L<Mojolicious::Guides>, L<https://mojolicious.org>.
1013
1014=cut
 
# spent 1.94ms within Mojo::Util::CORE:match which was called 2231 times, avg 869ns/call: # 2231 times (1.94ms+0s) by Mojo::URL::BEGIN@2 at line 49, avg 869ns/call
sub Mojo::Util::CORE:match; # opcode
# spent 89µs within Mojo::Util::CORE:open which was called: # once (89µs+0s) by Mojo::URL::BEGIN@2 at line 45
sub Mojo::Util::CORE:open; # opcode
# spent 5µs within Mojo::Util::CORE:qr which was called 4 times, avg 1µs/call: # once (3µs+0s) by Mojo::URL::BEGIN@2 at line 58 # once (1µs+0s) by Mojo::URL::BEGIN@2 at line 61 # once (1µs+0s) by Mojo::URL::BEGIN@2 at line 65 # once (0s+0s) by Mojo::URL::BEGIN@2 at line 62
sub Mojo::Util::CORE:qr; # opcode
# spent 1.01ms within Mojo::Util::CORE:readline which was called: # once (1.01ms+0s) by Mojo::URL::BEGIN@2 at line 46
sub Mojo::Util::CORE:readline; # opcode
# spent 1.21s (487ms+725ms) within Mojo::Util::CORE:subst which was called 1340186 times, avg 904ns/call: # 310114 times (131ms+0s) by Mojo::Util::__ANON__[(eval 425)[/Users/ether/.perlbrew/libs/36.0@std/lib/perl5/Mojo/Util.pm:397]:1] at line 1 of (eval 425)[Mojo/Util.pm:397], avg 423ns/call # 287148 times (111ms+725ms) by Mojo::Util::url_unescape at line 408, avg 3µs/call # 276110 times (98.3ms+0s) by Mojo::Util::__ANON__[(eval 426)[/Users/ether/.perlbrew/libs/36.0@std/lib/perl5/Mojo/Util.pm:397]:1] at line 1 of (eval 426)[Mojo/Util.pm:397], avg 356ns/call # 247583 times (75.3ms+0s) by Mojo::Util::__ANON__[(eval 429)[/Users/ether/.perlbrew/libs/36.0@std/lib/perl5/Mojo/Util.pm:397]:1] at line 1 of (eval 429)[Mojo/Util.pm:397], avg 304ns/call # 219227 times (70.3ms+0s) by Mojo::Util::__ANON__[(eval 427)[/Users/ether/.perlbrew/libs/36.0@std/lib/perl5/Mojo/Util.pm:397]:1] at line 1 of (eval 427)[Mojo/Util.pm:397], avg 321ns/call # 4 times (6µs+0s) by Mojo::Util::url_escape at line 396, avg 2µs/call
sub Mojo::Util::CORE:subst; # opcode
# spent 45.4ms within Mojo::Util::CORE:substcont which was called 33263 times, avg 1µs/call: # 26736 times (40.8ms+0s) by Mojo::Util::__ANON__[(eval 427)[/Users/ether/.perlbrew/libs/36.0@std/lib/perl5/Mojo/Util.pm:397]:1] at line 1 of (eval 427)[Mojo/Util.pm:397], avg 2µs/call # 6516 times (4.58ms+0s) by Mojo::Util::url_unescape at line 408, avg 702ns/call # 11 times (12µs+0s) by Mojo::Util::url_escape at line 396, avg 1µs/call
sub Mojo::Util::CORE:substcont; # opcode