<commit_before>package Mojo::URL;
use Mojo::Base -base;
use overload bool => sub {1}, '""' => sub { shift->to_string }, fallback => 1;

use Mojo::Parameters;
use Mojo::Path;
use Mojo::Util qw(punycode_decode punycode_encode url_escape url_unescape);

has base => sub { Mojo::URL->new };
has [qw(fragment host port scheme userinfo)];

sub authority {
  my $self = shift;

  # New authority
  if (@_) {
    return $self unless defined(my $authority = shift);

    # Userinfo
    $authority =~ s/^([^\@]+)\@// and $self->userinfo(url_unescape $1);

    # Port
    $authority =~ s/:(\d+)$// and $self->port($1);

    # Host
    my $host = url_unescape $authority;
    return $host =~ /[^\x00-\x7f]/ ? $self->ihost($host) : $self->host($host);
  }

  # Build authority
  return undef unless defined(my $authority = $self->host_port);
  return $authority unless my $info = $self->userinfo;
  return url_escape($info, '^A-Za-z0-9\-._~!$&\'()*+,;=:') . '@' . $authority;
}

sub host_port {
  my $self = shift;
  return undef unless defined(my $host = $self->ihost);
  return $host unless my $port = $self->port;
  return "$host:$port";
}

sub clone {
  my $self = shift;

  my $clone = $self->new;
  map { $clone->{$_} = $self->{$_} } qw(scheme userinfo host port fragment);
  $clone->{path}  = $self->path->clone;
  $clone->{query} = $self->query->clone;
  if (my $base = $self->{base}) { $clone->{base} = $base->clone }

  return $clone;
}

sub ihost {
  my $self = shift;

  # Decode
  return $self->host(join '.',
    map { /^xn--(.+)$/ ? punycode_decode($_) : $_ } split /\./, shift)
    if @_;

  # Check if host needs to be encoded
  return undef unless defined(my $host = $self->host);
  return lc $host unless $host =~ /[^\x00-\x7f]/;

  # Encode
  return lc join '.',
    map { /[^\x00-\x7f]/ ? ('xn--' . punycode_encode $_) : $_ } split /\./,
    $host;
}

sub is_abs { !!shift->scheme }

sub new { @_ > 1 ? shift->SUPER::new->parse(@_) : shift->SUPER::new }

sub parse {
  my ($self, $url) = @_;

  # Official regex from RFC 3986
  $url =~ m!^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?!;<commit_msg>clone Mojo::URL a little faster<commit_after>package Mojo::URL;
use Mojo::Base -base;
use overload bool => sub {1}, '""' => sub { shift->to_string }, fallback => 1;

use Mojo::Parameters;
use Mojo::Path;
use Mojo::Util qw(punycode_decode punycode_encode url_escape url_unescape);

has base => sub { Mojo::URL->new };
has [qw(fragment host port scheme userinfo)];

sub authority {
  my $self = shift;

  # New authority
  if (@_) {
    return $self unless defined(my $authority = shift);

    # Userinfo
    $authority =~ s/^([^\@]+)\@// and $self->userinfo(url_unescape $1);

    # Port
    $authority =~ s/:(\d+)$// and $self->port($1);

    # Host
    my $host = url_unescape $authority;
    return $host =~ /[^\x00-\x7f]/ ? $self->ihost($host) : $self->host($host);
  }

  # Build authority
  return undef unless defined(my $authority = $self->host_port);
  return $authority unless my $info = $self->userinfo;
  return url_escape($info, '^A-Za-z0-9\-._~!$&\'()*+,;=:') . '@' . $authority;
}

sub host_port {
  my $self = shift;
  return undef unless defined(my $host = $self->ihost);
  return $host unless my $port = $self->port;
  return "$host:$port";
}

sub clone {
  my $self  = shift;
  my $clone = $self->new;
  @$clone{keys %$self} = values %$self;
  $clone->{$_} && ($clone->{$_} = $clone->{$_}->clone) for qw(base path query);
  return $clone;
}

sub ihost {
  my $self = shift;

  # Decode
  return $self->host(join '.',
    map { /^xn--(.+)$/ ? punycode_decode($_) : $_ } split /\./, shift)
    if @_;

  # Check if host needs to be encoded
  return undef unless defined(my $host = $self->host);
  return lc $host unless $host =~ /[^\x00-\x7f]/;

  # Encode
  return lc join '.',
    map { /[^\x00-\x7f]/ ? ('xn--' . punycode_encode $_) : $_ } split /\./,
    $host;
}

sub is_abs { !!shift->scheme }

sub new { @_ > 1 ? shift->SUPER::new->parse(@_) : shift->SUPER::new }

sub parse {
  my ($self, $url) = @_;

  # Official regex from RFC 3986
  $url =~ m!^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?!;
{'fraction_non_alphanumeric': 0.23149264528574873, 'fraction_numerical': 0.009645526886906198, 'mean_word_length': 3.245649948822927, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 62, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1303431', 'n_tokens_mistral': 1671, 'n_tokens_neox': 1605, 'n_words': 390}