| Filename | /Users/ether/.perlbrew/libs/36.0@std/lib/perl5/Mojo/Util.pm |
| Statements | Executed 7779716 statements in 8.21s |
| Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
|---|---|---|---|---|---|
| 829417 | 3 | 2 | 2.25s | 3.25s | Mojo::Util::encode |
| 829417 | 3 | 2 | 2.19s | 3.68s | Mojo::Util::url_escape |
| 185786 | 2 | 2 | 797ms | 2.23s | Mojo::Util::decode |
| 284828 | 3 | 2 | 513ms | 1.28s | Mojo::Util::url_unescape |
| 1015203 | 2 | 1 | 493ms | 493ms | Mojo::Util::_encoding |
| 1114249 | 6 | 5 | 364ms | 1.02s | Mojo::Util::CORE:subst (opcode) |
| 24769 | 3 | 2 | 16.4ms | 16.4ms | Mojo::Util::CORE:substcont (opcode) |
| 1 | 1 | 1 | 6.43ms | 7.17ms | Mojo::Util::BEGIN@11 |
| 1 | 1 | 1 | 5.33ms | 9.04ms | Mojo::Util::BEGIN@5 |
| 1 | 1 | 1 | 4.02ms | 37.7ms | Mojo::Util::BEGIN@17 |
| 1 | 1 | 1 | 2.97ms | 3.13ms | Mojo::Util::BEGIN@10 |
| 1 | 1 | 1 | 2.82ms | 6.61ms | Mojo::Util::BEGIN@21 |
| 1 | 1 | 1 | 2.38ms | 44.5ms | Mojo::Util::BEGIN@12 |
| 1 | 1 | 1 | 2.37ms | 7.34ms | Mojo::Util::BEGIN@18 |
| 1 | 1 | 1 | 2.17ms | 7.44ms | Mojo::Util::BEGIN@22 |
| 1 | 1 | 1 | 1.95ms | 5.71ms | Mojo::Util::BEGIN@6 |
| 1 | 1 | 1 | 1.43ms | 6.94ms | Mojo::Util::BEGIN@7 |
| 2231 | 1 | 1 | 1.41ms | 1.41ms | Mojo::Util::CORE:match (opcode) |
| 1 | 1 | 1 | 1.25ms | 10.1ms | Mojo::Util::BEGIN@14 |
| 1 | 1 | 1 | 1.17ms | 1.17ms | Mojo::Util::CORE:open (opcode) |
| 1 | 1 | 1 | 999µs | 1.07ms | Mojo::Util::BEGIN@13.4 |
| 1 | 1 | 1 | 764µs | 6.22ms | Mojo::Util::BEGIN@16.6 |
| 1 | 1 | 1 | 722µs | 722µs | Mojo::Util::CORE:readline (opcode) |
| 22 | 10 | 2 | 121µs | 187µs | Mojo::Util::monkey_patch |
| 1 | 1 | 1 | 23µs | 71µs | Mojo::Util::BEGIN@19 |
| 1 | 1 | 1 | 18µs | 97µs | Mojo::Util::BEGIN@25 |
| 1 | 1 | 1 | 15µs | 116µs | Mojo::Util::BEGIN@2 |
| 1 | 1 | 1 | 14µs | 22µs | Mojo::Util::BEGIN@203 |
| 1 | 1 | 1 | 12µs | 33µs | Mojo::Util::BEGIN@15.5 |
| 1 | 1 | 1 | 10µs | 37µs | Mojo::Util::BEGIN@20 |
| 1 | 1 | 1 | 8µs | 84µs | Mojo::Util::BEGIN@28 |
| 1 | 1 | 1 | 8µs | 14µs | Mojo::Util::BEGIN@532 |
| 1 | 1 | 1 | 7µs | 9µs | Mojo::Util::BEGIN@232 |
| 4 | 4 | 1 | 7µs | 7µs | Mojo::Util::CORE:qr (opcode) |
| 1 | 1 | 1 | 6µs | 25µs | Mojo::Util::BEGIN@204 |
| 1 | 1 | 1 | 6µs | 43µs | Mojo::Util::BEGIN@4 |
| 1 | 1 | 1 | 6µs | 7µs | Mojo::Util::BEGIN@431 |
| 1 | 1 | 1 | 6µs | 62µs | Mojo::Util::BEGIN@8 |
| 1 | 1 | 1 | 6µs | 121µs | Mojo::Util::_Guard::BEGIN@538 |
| 1 | 1 | 1 | 4µs | 6µs | Mojo::Util::BEGIN@265 |
| 1 | 1 | 1 | 3µs | 8µs | Mojo::Util::BEGIN@9 |
| 0 | 0 | 0 | 0s | 0s | Mojo::Util::_Guard::DESTROY |
| 0 | 0 | 0 | 0s | 0s | Mojo::Util::__ANON__[:89] |
| 0 | 0 | 0 | 0s | 0s | Mojo::Util::_adapt |
| 0 | 0 | 0 | 0s | 0s | Mojo::Util::_entity |
| 0 | 0 | 0 | 0s | 0s | Mojo::Util::_header |
| 0 | 0 | 0 | 0s | 0s | Mojo::Util::_html |
| 0 | 0 | 0 | 0s | 0s | Mojo::Util::_options |
| 0 | 0 | 0 | 0s | 0s | Mojo::Util::_readable |
| 0 | 0 | 0 | 0s | 0s | Mojo::Util::_round |
| 0 | 0 | 0 | 0s | 0s | Mojo::Util::_stash |
| 0 | 0 | 0 | 0s | 0s | Mojo::Util::_teardown |
| 0 | 0 | 0 | 0s | 0s | Mojo::Util::camelize |
| 0 | 0 | 0 | 0s | 0s | Mojo::Util::class_to_file |
| 0 | 0 | 0 | 0s | 0s | Mojo::Util::class_to_path |
| 0 | 0 | 0 | 0s | 0s | Mojo::Util::decamelize |
| 0 | 0 | 0 | 0s | 0s | Mojo::Util::deprecated |
| 0 | 0 | 0 | 0s | 0s | Mojo::Util::dumper |
| 0 | 0 | 0 | 0s | 0s | Mojo::Util::extract_usage |
| 0 | 0 | 0 | 0s | 0s | Mojo::Util::getopt |
| 0 | 0 | 0 | 0s | 0s | Mojo::Util::gunzip |
| 0 | 0 | 0 | 0s | 0s | Mojo::Util::gzip |
| 0 | 0 | 0 | 0s | 0s | Mojo::Util::header_params |
| 0 | 0 | 0 | 0s | 0s | Mojo::Util::html_attr_unescape |
| 0 | 0 | 0 | 0s | 0s | Mojo::Util::html_unescape |
| 0 | 0 | 0 | 0s | 0s | Mojo::Util::humanize_bytes |
| 0 | 0 | 0 | 0s | 0s | Mojo::Util::network_contains |
| 0 | 0 | 0 | 0s | 0s | Mojo::Util::punycode_decode |
| 0 | 0 | 0 | 0s | 0s | Mojo::Util::punycode_encode |
| 0 | 0 | 0 | 0s | 0s | Mojo::Util::quote |
| 0 | 0 | 0 | 0s | 0s | Mojo::Util::scope_guard |
| 0 | 0 | 0 | 0s | 0s | Mojo::Util::secure_compare |
| 0 | 0 | 0 | 0s | 0s | Mojo::Util::slugify |
| 0 | 0 | 0 | 0s | 0s | Mojo::Util::split_cookie_header |
| 0 | 0 | 0 | 0s | 0s | Mojo::Util::split_header |
| 0 | 0 | 0 | 0s | 0s | Mojo::Util::steady_time |
| 0 | 0 | 0 | 0s | 0s | Mojo::Util::tablify |
| 0 | 0 | 0 | 0s | 0s | Mojo::Util::term_escape |
| 0 | 0 | 0 | 0s | 0s | Mojo::Util::trim |
| 0 | 0 | 0 | 0s | 0s | Mojo::Util::unindent |
| 0 | 0 | 0 | 0s | 0s | Mojo::Util::unquote |
| 0 | 0 | 0 | 0s | 0s | Mojo::Util::xml_escape |
| 0 | 0 | 0 | 0s | 0s | Mojo::Util::xor_encode |
| Line | State ments |
Time on line |
Calls | Time in subs |
Code |
|---|---|---|---|---|---|
| 1 | package Mojo::Util; | ||||
| 2 | 2 | 23µs | 2 | 217µs | # spent 116µs (15+101) within Mojo::Util::BEGIN@2 which was called:
# once (15µs+101µs) by Mojo::URL::BEGIN@2 at line 2 # spent 116µs making 1 call to Mojo::Util::BEGIN@2
# spent 101µs making 1 call to Mojo::Base::import |
| 3 | |||||
| 4 | 2 | 16µs | 2 | 80µs | # spent 43µs (6+37) within Mojo::Util::BEGIN@4 which was called:
# once (6µs+37µs) by Mojo::URL::BEGIN@2 at line 4 # spent 43µs making 1 call to Mojo::Util::BEGIN@4
# spent 37µs making 1 call to Exporter::import |
| 5 | 2 | 1.90ms | 1 | 9.04ms | # spent 9.04ms (5.33+3.71) within Mojo::Util::BEGIN@5 which was called:
# once (5.33ms+3.71ms) by Mojo::URL::BEGIN@2 at line 5 # spent 9.04ms making 1 call to Mojo::Util::BEGIN@5 |
| 6 | 2 | 1.16ms | 2 | 5.75ms | # spent 5.71ms (1.95+3.76) within Mojo::Util::BEGIN@6 which was called:
# once (1.95ms+3.76ms) by Mojo::URL::BEGIN@2 at line 6 # spent 5.71ms making 1 call to Mojo::Util::BEGIN@6
# spent 43µs making 1 call to Exporter::import |
| 7 | 2 | 477µs | 2 | 7.03ms | # spent 6.94ms (1.43+5.51) within Mojo::Util::BEGIN@7 which was called:
# once (1.43ms+5.51ms) by Mojo::URL::BEGIN@2 at line 7 # spent 6.94ms making 1 call to Mojo::Util::BEGIN@7
# spent 88µs making 1 call to Exporter::import |
| 8 | 2 | 15µs | 2 | 118µs | # spent 62µs (6+56) within Mojo::Util::BEGIN@8 which was called:
# once (6µs+56µs) by Mojo::URL::BEGIN@2 at line 8 # spent 62µs making 1 call to Mojo::Util::BEGIN@8
# spent 56µs making 1 call to Exporter::import |
| 9 | 2 | 13µs | 2 | 13µs | # spent 8µs (3+5) within Mojo::Util::BEGIN@9 which was called:
# once (3µs+5µs) by Mojo::URL::BEGIN@2 at line 9 # spent 8µs making 1 call to Mojo::Util::BEGIN@9
# spent 5µs making 1 call to Exporter::import |
| 10 | 2 | 1.72ms | 2 | 3.16ms | # spent 3.13ms (2.97+166µs) within Mojo::Util::BEGIN@10 which was called:
# once (2.97ms+166µs) by Mojo::URL::BEGIN@2 at line 10 # spent 3.13ms making 1 call to Mojo::Util::BEGIN@10
# spent 29µs making 1 call to Exporter::import |
| 11 | 2 | 681µs | 2 | 7.27ms | # spent 7.17ms (6.43+733µs) within Mojo::Util::BEGIN@11 which was called:
# once (6.43ms+733µs) by Mojo::URL::BEGIN@2 at line 11 # spent 7.17ms making 1 call to Mojo::Util::BEGIN@11
# spent 107µs making 1 call to Getopt::Long::import |
| 12 | 2 | 1.55ms | 2 | 44.5ms | # spent 44.5ms (2.38+42.1) within Mojo::Util::BEGIN@12 which was called:
# once (2.38ms+42.1ms) by Mojo::URL::BEGIN@2 at line 12 # spent 44.5ms making 1 call to Mojo::Util::BEGIN@12
# spent 13µs making 1 call to Exporter::import |
| 13 | 2 | 653µs | 2 | 1.11ms | # spent 1.07ms (999µs+71µs) within Mojo::Util::BEGIN@13.4 which was called:
# once (999µs+71µs) by Mojo::URL::BEGIN@2 at line 13 # spent 1.07ms making 1 call to Mojo::Util::BEGIN@13.4
# spent 36µs making 1 call to Exporter::import |
| 14 | 2 | 482µs | 2 | 10.1ms | # spent 10.1ms (1.25+8.87) within Mojo::Util::BEGIN@14 which was called:
# once (1.25ms+8.87ms) by Mojo::URL::BEGIN@2 at line 14 # spent 10.1ms making 1 call to Mojo::Util::BEGIN@14
# spent 8µs making 1 call to Exporter::import |
| 15 | 2 | 16µs | 2 | 43µs | # spent 33µs (12+21) within Mojo::Util::BEGIN@15.5 which was called:
# once (12µs+21µs) by Mojo::URL::BEGIN@2 at line 15 # spent 33µs making 1 call to Mojo::Util::BEGIN@15.5
# spent 10µs making 1 call to List::Util::import |
| 16 | 2 | 610µs | 2 | 6.27ms | # spent 6.22ms (764µs+5.46) within Mojo::Util::BEGIN@16.6 which was called:
# once (764µs+5.46ms) by Mojo::URL::BEGIN@2 at line 16 # spent 6.22ms making 1 call to Mojo::Util::BEGIN@16.6
# spent 50µs making 1 call to Exporter::import |
| 17 | 2 | 2.06ms | 2 | 37.7ms | # spent 37.7ms (4.02+33.7) within Mojo::Util::BEGIN@17 which was called:
# once (4.02ms+33.7ms) by Mojo::URL::BEGIN@2 at line 17 # spent 37.7ms making 1 call to Mojo::Util::BEGIN@17
# spent 37µs making 1 call to Exporter::import |
| 18 | 2 | 550µs | 2 | 7.75ms | # spent 7.34ms (2.37+4.97) within Mojo::Util::BEGIN@18 which was called:
# once (2.37ms+4.97ms) by Mojo::URL::BEGIN@2 at line 18 # spent 7.34ms making 1 call to Mojo::Util::BEGIN@18
# spent 406µs making 1 call to Exporter::import |
| 19 | 2 | 41µs | 2 | 119µs | # spent 71µs (23+48) within Mojo::Util::BEGIN@19 which was called:
# once (23µs+48µs) by Mojo::URL::BEGIN@2 at line 19 # spent 71µs making 1 call to Mojo::Util::BEGIN@19
# spent 48µs making 1 call to Exporter::import |
| 20 | 2 | 32µs | 2 | 64µs | # spent 37µs (10+27) within Mojo::Util::BEGIN@20 which was called:
# once (10µs+27µs) by Mojo::URL::BEGIN@2 at line 20 # spent 37µs making 1 call to Mojo::Util::BEGIN@20
# spent 27µs making 1 call to Exporter::import |
| 21 | 2 | 2.39ms | 1 | 6.61ms | # spent 6.61ms (2.82+3.79) within Mojo::Util::BEGIN@21 which was called:
# once (2.82ms+3.79ms) by Mojo::URL::BEGIN@2 at line 21 # spent 6.61ms making 1 call to Mojo::Util::BEGIN@21 |
| 22 | 2 | 1.21ms | 1 | 7.44ms | # spent 7.44ms (2.17+5.27) within Mojo::Util::BEGIN@22 which was called:
# once (2.17ms+5.27ms) by Mojo::URL::BEGIN@2 at line 22 # spent 7.44ms making 1 call to Mojo::Util::BEGIN@22 |
| 23 | |||||
| 24 | # Check for monotonic clock support | ||||
| 25 | 3 | 56µs | 4 | 174µs | # spent 97µs (18+79) within Mojo::Util::BEGIN@25 which was called:
# once (18µs+79µs) by Mojo::URL::BEGIN@2 at line 25 # spent 97µs making 1 call to Mojo::Util::BEGIN@25
# spent 39µs making 1 call to constant::import
# spent 27µs making 1 call to Time::HiRes::AUTOLOAD
# spent 11µs making 1 call to Time::HiRes::clock_gettime |
| 26 | |||||
| 27 | # Punycode bootstring parameters | ||||
| 28 | # spent 84µs (8+76) within Mojo::Util::BEGIN@28 which was called:
# once (8µs+76µs) by Mojo::URL::BEGIN@2 at line 36 | ||||
| 29 | 1 | 0s | 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 | ||||
| 36 | 1 | 1.20ms | 2 | 160µs | }; # spent 84µs making 1 call to Mojo::Util::BEGIN@28
# spent 76µ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 | ||||
| 40 | 1 | 0s | my %ENTITIES; | ||
| 41 | { | ||||
| 42 | # Don't use Mojo::File here due to circular dependencies | ||||
| 43 | 2 | 209µs | 5 | 116µs | my $path = File::Spec->catfile(dirname(__FILE__), 'resources', 'html_entities.txt'); # spent 49µs making 1 call to File::Spec::Unix::catfile
# spent 42µs making 1 call to File::Basename::dirname
# spent 16µs making 2 calls to File::Spec::Unix::canonpath, avg 8µs/call
# spent 9µs making 1 call to File::Spec::Unix::catdir |
| 44 | |||||
| 45 | 1 | 1.18ms | 1 | 1.17ms | open my $file, '<', $path or croak "Unable to open html entities file ($path): $!"; # spent 1.17ms making 1 call to Mojo::Util::CORE:open |
| 46 | 3 | 737µs | 1 | 722µs | my $lines = do { local $/; <$file> }; # spent 722µs making 1 call to Mojo::Util::CORE:readline |
| 47 | |||||
| 48 | 1 | 321µs | for my $line (split /\n/, $lines) { | ||
| 49 | 2231 | 3.29ms | 2231 | 1.41ms | next unless $line =~ /^(\S+)\s+U\+(\S+)(?:\s+U\+(\S+))?/; # spent 1.41ms making 2231 calls to Mojo::Util::CORE:match, avg 632ns/call |
| 50 | 2231 | 2.01ms | $ENTITIES{$1} = defined $3 ? (chr(hex $2) . chr(hex $3)) : chr(hex $2); | ||
| 51 | } | ||||
| 52 | } | ||||
| 53 | |||||
| 54 | # Characters that should be escaped in XML | ||||
| 55 | 1 | 3µs | my %XML = ('&' => '&', '<' => '<', '>' => '>', '"' => '"', '\'' => '''); | ||
| 56 | |||||
| 57 | # "Sun, 06 Nov 1994 08:49:37 GMT" and "Sunday, 06-Nov-94 08:49:37 GMT" | ||||
| 58 | 1 | 10µs | 1 | 4µs | my $EXPIRES_RE = qr/(\w+\W+\d+\W+\w+\W+\d+\W+\d+:\d+:\d+\W*\w+)/; # spent 4µs making 1 call to Mojo::Util::CORE:qr |
| 59 | |||||
| 60 | # Header key/value pairs | ||||
| 61 | 1 | 2µs | 1 | 1µs | my $QUOTED_VALUE_RE = qr/\G=\s*("(?:\\\\|\\"|[^"])*")/; # spent 1µs making 1 call to Mojo::Util::CORE:qr |
| 62 | 1 | 5µs | 1 | 1µs | my $UNQUOTED_VALUE_RE = qr/\G=\s*([^;, ]*)/; # spent 1µs making 1 call to Mojo::Util::CORE:qr |
| 63 | |||||
| 64 | # HTML entities | ||||
| 65 | 1 | 2µs | 1 | 1µs | my $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 | ||||
| 68 | 1 | 1µs | my (%ENCODING, %PATTERN); | ||
| 69 | |||||
| 70 | 1 | 4µs | our @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 | ||||
| 79 | 1 | 3µs | 1 | 18µs | monkey_patch(__PACKAGE__, 'b64_decode', \&decode_base64); # spent 18µs making 1 call to Mojo::Util::monkey_patch |
| 80 | 1 | 1µs | 1 | 6µs | monkey_patch(__PACKAGE__, 'b64_encode', \&encode_base64); # spent 6µs making 1 call to Mojo::Util::monkey_patch |
| 81 | 1 | 0s | 1 | 7µs | monkey_patch(__PACKAGE__, 'hmac_sha1_sum', \&hmac_sha1_hex); # spent 7µs making 1 call to Mojo::Util::monkey_patch |
| 82 | 1 | 2µs | 1 | 6µs | monkey_patch(__PACKAGE__, 'md5_bytes', \&md5); # spent 6µs making 1 call to Mojo::Util::monkey_patch |
| 83 | 1 | 1µs | 1 | 6µs | monkey_patch(__PACKAGE__, 'md5_sum', \&md5_hex); # spent 6µs making 1 call to Mojo::Util::monkey_patch |
| 84 | 1 | 0s | 1 | 11µs | monkey_patch(__PACKAGE__, 'sha1_bytes', \&sha1); # spent 11µs making 1 call to Mojo::Util::monkey_patch |
| 85 | 1 | 1µs | 1 | 4µs | monkey_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 | ||||
| 88 | monkey_patch(__PACKAGE__, 'steady_time', | ||||
| 89 | 1 | 3µs | 1 | 8µs | MONOTONIC ? sub () { Time::HiRes::clock_gettime(Time::HiRes::CLOCK_MONOTONIC()) } : \&Time::HiRes::time); # spent 8µs making 1 call to Mojo::Util::monkey_patch |
| 90 | |||||
| 91 | sub 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 | |||||
| 101 | sub 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 | |||||
| 108 | sub class_to_path { join '.', join('/', split(/::|'/, shift)), 'pm' } | ||||
| 109 | |||||
| 110 | sub 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.23s (797ms+1.43) within Mojo::Util::decode which was called 185786 times, avg 12µs/call:
# 127536 times (542ms+1.17s) by Mojo::Path::_parse at line 107 of Mojo/Path.pm, avg 13µs/call
# 58250 times (255ms+261ms) by Mojo::URL::_decode at line 157 of Mojo/URL.pm, avg 9µs/call | ||||
| 121 | 185786 | 61.1ms | my ($encoding, $bytes) = @_; | ||
| 122 | 557358 | 918ms | 575250 | 1.58s | return undef unless eval { $bytes = _encoding($encoding)->decode("$bytes", 1); 1 }; # spent 700ms making 185786 calls to Encode::utf8::decode, avg 4µs/call
# spent 632ms making 17892 calls to Mojo::Path::__ANON__[Mojo/Path.pm:3], avg 35µs/call
# spent 145ms making 185786 calls to Encode::Encoding::renewed, avg 781ns/call
# spent 100.0ms making 185786 calls to Mojo::Util::_encoding, avg 538ns/call |
| 123 | 185786 | 208ms | return $bytes; | ||
| 124 | } | ||||
| 125 | |||||
| 126 | sub deprecated { | ||||
| 127 | local $Carp::CarpLevel = 1; | ||||
| 128 | $ENV{MOJO_FATAL_DEPRECATIONS} ? croak @_ : carp @_; | ||||
| 129 | } | ||||
| 130 | |||||
| 131 | sub dumper { Data::Dumper->new([@_])->Indent(1)->Sortkeys(1)->Terse(1)->Useqq(1)->Dump } | ||||
| 132 | |||||
| 133 | 829417 | 2.86s | 1658834 | 1.00s | # spent 3.25s (2.25+1.00) within Mojo::Util::encode which was called 829417 times, avg 4µs/call:
# 381988 times (1.12s+503ms) by Mojo::URL::_encode at line 159 of Mojo/URL.pm, avg 4µs/call
# 245195 times (596ms+253ms) by Mojo::Path::to_string at line 92 of Mojo/Path.pm, avg 3µs/call
# 202234 times (538ms+245ms) by Mojo::Path::to_string at line 86 of Mojo/Path.pm, avg 4µs/call # spent 608ms making 829417 calls to Encode::utf8::encode, avg 733ns/call
# spent 393ms making 829417 calls to Mojo::Util::_encoding, avg 474ns/call |
| 134 | |||||
| 135 | sub 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 | |||||
| 146 | sub 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 | |||||
| 156 | sub 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 | |||||
| 163 | sub 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 | |||||
| 169 | sub 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 | |||||
| 186 | sub html_attr_unescape { _html(shift, 1) } | ||||
| 187 | sub html_unescape { _html(shift, 0) } | ||||
| 188 | |||||
| 189 | sub 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 187µs (121+66) within Mojo::Util::monkey_patch which was called 22 times, avg 9µs/call:
# 9 times (43µs+24µs) by Mojo::Base::attr at line 93 of Mojo/Base.pm, avg 7µs/call
# 5 times (37µs+17µs) by Mojo::Base::import at line 136 of Mojo/Base.pm, avg 11µs/call
# once (10µs+8µs) by Mojo::URL::BEGIN@2 at line 79
# once (9µs+2µs) by Mojo::URL::BEGIN@2 at line 84
# once (3µs+5µs) by Mojo::URL::BEGIN@2 at line 89
# once (5µs+2µs) by Mojo::URL::BEGIN@2 at line 81
# once (3µs+3µs) by Mojo::URL::BEGIN@2 at line 82
# once (4µs+2µs) by Mojo::URL::BEGIN@2 at line 83
# once (4µs+2µs) by Mojo::URL::BEGIN@2 at line 80
# once (3µs+1000ns) by Mojo::URL::BEGIN@2 at line 85 | ||||
| 202 | 22 | 13µs | my ($class, %patch) = @_; | ||
| 203 | 2 | 35µs | 2 | 30µs | # spent 22µs (14+8) within Mojo::Util::BEGIN@203 which was called:
# once (14µs+8µs) by Mojo::URL::BEGIN@2 at line 203 # spent 22µs making 1 call to Mojo::Util::BEGIN@203
# spent 8µs making 1 call to strict::unimport |
| 204 | 2 | 166µs | 2 | 44µs | # spent 25µs (6+19) within Mojo::Util::BEGIN@204 which was called:
# once (6µs+19µs) by Mojo::URL::BEGIN@2 at line 204 # spent 25µs making 1 call to Mojo::Util::BEGIN@204
# spent 19µs making 1 call to warnings::unimport |
| 205 | 22 | 189µs | 22 | 66µs | *{"${class}::$_"} = set_subname("${class}::$_", $patch{$_}) for keys %patch; # spent 66µs making 22 calls to Sub::Util::set_subname, avg 3µs/call |
| 206 | } | ||||
| 207 | |||||
| 208 | sub 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 | ||||
| 230 | sub punycode_decode { | ||||
| 231 | my $input = shift; | ||||
| 232 | 2 | 168µs | 2 | 11µs | # spent 9µs (7+2) within Mojo::Util::BEGIN@232 which was called:
# once (7µs+2µs) by Mojo::URL::BEGIN@2 at line 232 # spent 9µs making 1 call to Mojo::Util::BEGIN@232
# spent 2µ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 | ||||
| 263 | sub punycode_encode { | ||||
| 264 | my $output = shift; | ||||
| 265 | 2 | 1.54ms | 2 | 8µs | # spent 6µs (4+2) within Mojo::Util::BEGIN@265 which was called:
# once (4µs+2µs) by Mojo::URL::BEGIN@2 at line 265 # spent 6µ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 | |||||
| 310 | sub quote { | ||||
| 311 | my $str = shift; | ||||
| 312 | $str =~ s/(["\\])/\\$1/g; | ||||
| 313 | return qq{"$str"}; | ||||
| 314 | } | ||||
| 315 | |||||
| 316 | sub scope_guard { Mojo::Util::_Guard->new(cb => shift) } | ||||
| 317 | |||||
| 318 | sub 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 | |||||
| 326 | sub 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 | |||||
| 344 | sub split_cookie_header { _header(shift, 1) } | ||||
| 345 | sub split_header { _header(shift, 0) } | ||||
| 346 | |||||
| 347 | sub 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 | |||||
| 363 | sub 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 | |||||
| 369 | sub trim { | ||||
| 370 | my $str = shift; | ||||
| 371 | $str =~ s/^\s+//; | ||||
| 372 | $str =~ s/\s+$//; | ||||
| 373 | return $str; | ||||
| 374 | } | ||||
| 375 | |||||
| 376 | sub 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 | |||||
| 383 | sub 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 3.68s (2.19+1.49) within Mojo::Util::url_escape which was called 829417 times, avg 4µs/call:
# 381988 times (1.04s+754ms) by Mojo::URL::_encode at line 159 of Mojo/URL.pm, avg 5µs/call
# 245195 times (618ms+384ms) by Mojo::Path::to_string at line 93 of Mojo/Path.pm, avg 4µs/call
# 202234 times (538ms+351ms) by Mojo::Path::to_string at line 87 of Mojo/Path.pm, avg 4µs/call | ||||
| 392 | 829417 | 246ms | my ($str, $pattern) = @_; | ||
| 393 | |||||
| 394 | 829417 | 181ms | if ($pattern) { | ||
| 395 | 829417 | 189ms | unless (exists $PATTERN{$pattern}) { | ||
| 396 | 4 | 39µs | 15 | 16µs | (my $quoted = $pattern) =~ s!([/\$\[])!\\$1!g; # spent 8µs making 4 calls to Mojo::Util::CORE:subst, avg 2µs/call
# spent 8µs making 11 calls to Mojo::Util::CORE:substcont, avg 727ns/call |
| 397 | 4 | 396µs | $PATTERN{$pattern} = eval "sub { \$_[0] =~ s/([$quoted])/sprintf '%%%02X', ord \$1/ge }" or croak $@; # spent 581ms executing statements in string eval # includes 358ms spent executing 235958 calls to 1 sub defined therein. # spent 548ms executing statements in string eval # includes 318ms spent executing 245195 calls to 1 sub defined therein. # spent 480ms executing statements in string eval # includes 286ms spent executing 202234 calls to 1 sub defined therein. # spent 390ms executing statements in string eval # includes 249ms spent executing 146030 calls to 1 sub defined therein. | ||
| 398 | } | ||||
| 399 | 829417 | 639ms | 829417 | 1.49s | $PATTERN{$pattern}->($str); # spent 449ms making 235958 calls to Mojo::Util::__ANON__[(eval 429)[Mojo/Util.pm:397]:1], avg 2µs/call
# spent 384ms making 245195 calls to Mojo::Util::__ANON__[(eval 433)[Mojo/Util.pm:397]:1], avg 2µs/call
# spent 351ms making 202234 calls to Mojo::Util::__ANON__[(eval 430)[Mojo/Util.pm:397]:1], avg 2µs/call
# spent 306ms making 146030 calls to Mojo::Util::__ANON__[(eval 431)[Mojo/Util.pm:397]:1], avg 2µs/call |
| 400 | } | ||||
| 401 | else { $str =~ s/([^A-Za-z0-9\-._~])/sprintf '%%%02X', ord $1/ge } | ||||
| 402 | |||||
| 403 | 829417 | 989ms | return $str; | ||
| 404 | } | ||||
| 405 | |||||
| 406 | # spent 1.28s (513ms+762ms) within Mojo::Util::url_unescape which was called 284828 times, avg 4µs/call:
# 127536 times (217ms+719ms) by Mojo::Path::_parse at line 105 of Mojo/Path.pm, avg 7µs/call
# 99042 times (179ms+19.8ms) by Mojo::URL::host_port at line 25 of Mojo/URL.pm, avg 2µs/call
# 58250 times (117ms+24.0ms) by Mojo::URL::parse at line 60 of Mojo/URL.pm, avg 2µs/call | ||||
| 407 | 284828 | 60.4ms | my $str = shift; | ||
| 408 | 284828 | 375ms | 309230 | 1.42s | $str =~ s/%([0-9a-fA-F]{2})/chr hex $1/ge; # spent 758ms making 284828 calls to Mojo::Util::CORE:subst, avg 3µs/call
# spent 660ms making 17892 calls to Mojo::Path::__ANON__[Mojo/Path.pm:3], avg 37µs/call
# spent 4.65ms making 6510 calls to Mojo::Util::CORE:substcont, avg 714ns/call |
| 409 | 284828 | 349ms | return $str; | ||
| 410 | } | ||||
| 411 | |||||
| 412 | sub 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 | |||||
| 419 | sub 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 | |||||
| 429 | sub _adapt { | ||||
| 430 | my ($delta, $numpoints, $firsttime) = @_; | ||||
| 431 | 2 | 584µs | 2 | 8µs | # spent 7µs (6+1000ns) within Mojo::Util::BEGIN@431 which was called:
# once (6µs+1000ns) by Mojo::URL::BEGIN@2 at line 431 # spent 7µs making 1 call to Mojo::Util::BEGIN@431
# spent 1µ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 | |||||
| 444 | 1015203 | 1.11s | 1 | 25µs | sub _encoding { $ENCODING{$_[0]} //= find_encoding($_[0]) // croak "Unknown encoding '$_[0]'" } # spent 25µs making 1 call to Encode::find_encoding |
| 445 | |||||
| 446 | sub _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 | |||||
| 462 | sub _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 | |||||
| 489 | sub _html { | ||||
| 490 | my ($str, $attr) = @_; | ||||
| 491 | $str =~ s/$ENTITY_RE/_entity($1, $2, $attr)/geo; | ||||
| 492 | return $str; | ||||
| 493 | } | ||||
| 494 | |||||
| 495 | sub _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 | ||||
| 508 | sub _readable { !!(IO::Poll::_poll(@_[0, 1], my $m = POLLIN | POLLPRI) > 0) } | ||||
| 509 | |||||
| 510 | sub _round { $_[0] < 10 ? int($_[0] * 10 + 0.5) / 10 : int($_[0] + 0.5) } | ||||
| 511 | |||||
| 512 | sub _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 | |||||
| 528 | sub _teardown { | ||||
| 529 | return unless my $class = shift; | ||||
| 530 | |||||
| 531 | # @ISA has to be cleared first because of circular references | ||||
| 532 | 2 | 62µs | 2 | 20µs | # spent 14µs (8+6) within Mojo::Util::BEGIN@532 which was called:
# once (8µs+6µs) by Mojo::URL::BEGIN@2 at line 532 # spent 14µs making 1 call to Mojo::Util::BEGIN@532
# spent 6µs making 1 call to strict::unimport |
| 533 | @{"${class}::ISA"} = (); | ||||
| 534 | delete_package $class; | ||||
| 535 | } | ||||
| 536 | |||||
| 537 | package Mojo::Util::_Guard; | ||||
| 538 | 2 | 313µs | 2 | 236µs | # spent 121µs (6+115) within Mojo::Util::_Guard::BEGIN@538 which was called:
# once (6µs+115µs) by Mojo::URL::BEGIN@2 at line 538 # spent 121µs making 1 call to Mojo::Util::_Guard::BEGIN@538
# spent 115µs making 1 call to Mojo::Base::import |
| 539 | |||||
| 540 | sub DESTROY { shift->{cb}() } | ||||
| 541 | |||||
| 542 | 1 | 21µs | 1; | ||
| 543 | |||||
| 544 | =encoding utf8 | ||||
| 545 | |||||
| 546 | =head1 NAME | ||||
| 547 | |||||
| 548 | Mojo::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 | |||||
| 561 | L<Mojo::Util> provides portable utility functions for L<Mojo>. | ||||
| 562 | |||||
| 563 | =head1 FUNCTIONS | ||||
| 564 | |||||
| 565 | L<Mojo::Util> implements the following functions, which can be imported individually. | ||||
| 566 | |||||
| 567 | =head2 b64_decode | ||||
| 568 | |||||
| 569 | my $bytes = b64_decode $b64; | ||||
| 570 | |||||
| 571 | Base64 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 | |||||
| 578 | Base64 encode bytes with L<MIME::Base64>, the line ending defaults to a newline. | ||||
| 579 | |||||
| 580 | =head2 camelize | ||||
| 581 | |||||
| 582 | my $camelcase = camelize $snakecase; | ||||
| 583 | |||||
| 584 | Convert 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 | |||||
| 599 | Convert 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 | |||||
| 617 | Convert 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 | |||||
| 629 | Convert 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 | |||||
| 644 | Decode 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 | |||||
| 650 | Warn about deprecated feature from perspective of caller. You can also set the C<MOJO_FATAL_DEPRECATIONS> environment | ||||
| 651 | variable to make them die instead with L<Carp>. | ||||
| 652 | |||||
| 653 | =head2 dumper | ||||
| 654 | |||||
| 655 | my $perl = dumper {some => 'data'}; | ||||
| 656 | |||||
| 657 | Dump a Perl data structure with L<Data::Dumper>. | ||||
| 658 | |||||
| 659 | =head2 encode | ||||
| 660 | |||||
| 661 | my $bytes = encode 'UTF-8', $chars; | ||||
| 662 | |||||
| 663 | Encode 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 | |||||
| 670 | Extract usage message from the SYNOPSIS section of a file containing POD documentation, defaults to using the file this | ||||
| 671 | function 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 | |||||
| 697 | Extract options from an array reference with L<Getopt::Long>, but without changing its global configuration, defaults | ||||
| 698 | to 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 | |||||
| 708 | Uncompress bytes with L<IO::Compress::Gunzip>. | ||||
| 709 | |||||
| 710 | =head2 gzip | ||||
| 711 | |||||
| 712 | my $compressed = gzip $uncompressed; | ||||
| 713 | |||||
| 714 | Compress 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 | |||||
| 720 | Extract HTTP header field parameters until the first comma according to L<RFC 5987|http://tools.ietf.org/html/rfc5987>. | ||||
| 721 | Note 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 | |||||
| 727 | Generate 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 | |||||
| 736 | Same as L</"html_unescape">, but handles special rules from the L<HTML Living Standard|https://html.spec.whatwg.org> | ||||
| 737 | for HTML attributes. | ||||
| 738 | |||||
| 739 | # "foo=bar<est=baz" | ||||
| 740 | html_attr_unescape 'foo=bar<est=baz'; | ||||
| 741 | |||||
| 742 | # "foo=bar<est=baz" | ||||
| 743 | html_attr_unescape 'foo=bar<est=baz'; | ||||
| 744 | |||||
| 745 | =head2 html_unescape | ||||
| 746 | |||||
| 747 | my $str = html_unescape $escaped; | ||||
| 748 | |||||
| 749 | Unescape all HTML entities in string. | ||||
| 750 | |||||
| 751 | # "<div>" | ||||
| 752 | html_unescape '<div>'; | ||||
| 753 | |||||
| 754 | =head2 humanize_bytes | ||||
| 755 | |||||
| 756 | my $str = humanize_bytes 1234; | ||||
| 757 | |||||
| 758 | Turn 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 | |||||
| 776 | Generate binary MD5 checksum for bytes with L<Digest::MD5>. | ||||
| 777 | |||||
| 778 | =head2 md5_sum | ||||
| 779 | |||||
| 780 | my $checksum = md5_sum $bytes; | ||||
| 781 | |||||
| 782 | Generate 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 | |||||
| 792 | Monkey 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 | |||||
| 803 | Punycode 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 | |||||
| 812 | Check that a given address is contained within a network in CIDR form. If the network is a single address, the | ||||
| 813 | addresses 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 | |||||
| 829 | Punycode 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 | |||||
| 838 | Quote string. | ||||
| 839 | |||||
| 840 | =head2 scope_guard | ||||
| 841 | |||||
| 842 | my $guard = scope_guard sub {...}; | ||||
| 843 | |||||
| 844 | Create 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 | |||||
| 856 | Constant time comparison algorithm to prevent timing attacks. The secret string should be the second argument, to avoid | ||||
| 857 | leaking information about the length of the string. | ||||
| 858 | |||||
| 859 | =head2 sha1_bytes | ||||
| 860 | |||||
| 861 | my $checksum = sha1_bytes $bytes; | ||||
| 862 | |||||
| 863 | Generate binary SHA1 checksum for bytes with L<Digest::SHA>. | ||||
| 864 | |||||
| 865 | =head2 sha1_sum | ||||
| 866 | |||||
| 867 | my $checksum = sha1_sum $bytes; | ||||
| 868 | |||||
| 869 | Generate 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 | |||||
| 879 | Returns a URL slug generated from the input string. Non-word characters are removed, the string is trimmed and | ||||
| 880 | lowercased, and whitespace characters are replaced by a dash. By default, non-ASCII characters are normalized to ASCII | ||||
| 881 | word characters or removed, but if a true value is passed as the second parameter, all word characters will be allowed | ||||
| 882 | in 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 | |||||
| 897 | Same 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 | |||||
| 903 | Split HTTP header value into key/value pairs, each comma separated part gets its own array reference, and keys without | ||||
| 904 | a 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 | |||||
| 925 | High resolution time elapsed from an arbitrary fixed point in the past, resilient to time jumps if a monotonic clock is | ||||
| 926 | available through L<Time::HiRes>. | ||||
| 927 | |||||
| 928 | =head2 tablify | ||||
| 929 | |||||
| 930 | my $table = tablify [['foo', 'bar'], ['baz', 'yada']]; | ||||
| 931 | |||||
| 932 | Row-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 | |||||
| 941 | Escape 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 | |||||
| 950 | Trim 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 | |||||
| 959 | Unindent 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 | |||||
| 968 | Unquote string. | ||||
| 969 | |||||
| 970 | =head2 url_escape | ||||
| 971 | |||||
| 972 | my $escaped = url_escape $str; | ||||
| 973 | my $escaped = url_escape $str, '^A-Za-z0-9\-._~'; | ||||
| 974 | |||||
| 975 | Percent encode unsafe characters in string as described in L<RFC 3986|https://tools.ietf.org/html/rfc3986>, the pattern | ||||
| 976 | used 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 | |||||
| 985 | Decode 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 | |||||
| 994 | Escape unsafe characters C<&>, C<E<lt>>, C<E<gt>>, C<"> and C<'> in string, but do not escape L<Mojo::ByteStream> | ||||
| 995 | objects. | ||||
| 996 | |||||
| 997 | # "<div>" | ||||
| 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 | |||||
| 1008 | XOR encode string with variable length key. | ||||
| 1009 | |||||
| 1010 | =head1 SEE ALSO | ||||
| 1011 | |||||
| 1012 | L<Mojolicious>, L<Mojolicious::Guides>, L<https://mojolicious.org>. | ||||
| 1013 | |||||
| 1014 | =cut | ||||
# spent 1.41ms within Mojo::Util::CORE:match which was called 2231 times, avg 632ns/call:
# 2231 times (1.41ms+0s) by Mojo::URL::BEGIN@2 at line 49, avg 632ns/call | |||||
# spent 1.17ms within Mojo::Util::CORE:open which was called:
# once (1.17ms+0s) by Mojo::URL::BEGIN@2 at line 45 | |||||
sub Mojo::Util::CORE:qr; # opcode | |||||
# spent 722µs within Mojo::Util::CORE:readline which was called:
# once (722µs+0s) by Mojo::URL::BEGIN@2 at line 46 | |||||
# spent 1.02s (364ms+660ms) within Mojo::Util::CORE:subst which was called 1114249 times, avg 919ns/call:
# 284828 times (97.6ms+660ms) by Mojo::Util::url_unescape at line 408, avg 3µs/call
# 245195 times (66.4ms+0s) by Mojo::Util::__ANON__[(eval 433)[/Users/ether/.perlbrew/libs/36.0@std/lib/perl5/Mojo/Util.pm:397]:1] at line 1 of (eval 433)[Mojo/Util.pm:397], avg 271ns/call
# 235958 times (90.6ms+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 384ns/call
# 202234 times (64.3ms+0s) by Mojo::Util::__ANON__[(eval 430)[/Users/ether/.perlbrew/libs/36.0@std/lib/perl5/Mojo/Util.pm:397]:1] at line 1 of (eval 430)[Mojo/Util.pm:397], avg 318ns/call
# 146030 times (44.9ms+0s) by Mojo::Util::__ANON__[(eval 431)[/Users/ether/.perlbrew/libs/36.0@std/lib/perl5/Mojo/Util.pm:397]:1] at line 1 of (eval 431)[Mojo/Util.pm:397], avg 308ns/call
# 4 times (8µs+0s) by Mojo::Util::url_escape at line 396, avg 2µs/call | |||||
# spent 16.4ms within Mojo::Util::CORE:substcont which was called 24769 times, avg 663ns/call:
# 18248 times (11.8ms+0s) by Mojo::Util::__ANON__[(eval 431)[/Users/ether/.perlbrew/libs/36.0@std/lib/perl5/Mojo/Util.pm:397]:1] at line 1 of (eval 431)[Mojo/Util.pm:397], avg 645ns/call
# 6510 times (4.65ms+0s) by Mojo::Util::url_unescape at line 408, avg 714ns/call
# 11 times (8µs+0s) by Mojo::Util::url_escape at line 396, avg 727ns/call |