{"id":20315228,"url":"https://github.com/sysread/uri-fast","last_synced_at":"2025-04-11T17:25:35.297Z","repository":{"id":48297425,"uuid":"121587565","full_name":"sysread/URI-Fast","owner":"sysread","description":"A fast(er) URI parser for Perl","archived":false,"fork":false,"pushed_at":"2021-09-13T19:43:45.000Z","size":1065,"stargazers_count":6,"open_issues_count":2,"forks_count":3,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-10T09:19:46.844Z","etag":null,"topics":["c","fast","inline","parameter","parser","perl","query","tiny","uri","url","xs"],"latest_commit_sha":null,"homepage":"","language":"Perl","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sysread.png","metadata":{"files":{"readme":"README.pod","changelog":"Changes","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-02-15T03:27:59.000Z","updated_at":"2021-09-13T13:27:42.000Z","dependencies_parsed_at":"2022-09-21T11:11:53.472Z","dependency_job_id":null,"html_url":"https://github.com/sysread/URI-Fast","commit_stats":null,"previous_names":[],"tags_count":75,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sysread%2FURI-Fast","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sysread%2FURI-Fast/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sysread%2FURI-Fast/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sysread%2FURI-Fast/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sysread","download_url":"https://codeload.github.com/sysread/URI-Fast/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248448666,"owners_count":21105338,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["c","fast","inline","parameter","parser","perl","query","tiny","uri","url","xs"],"created_at":"2024-11-14T18:18:23.490Z","updated_at":"2025-04-11T17:25:35.278Z","avatar_url":"https://github.com/sysread.png","language":"Perl","funding_links":[],"categories":[],"sub_categories":[],"readme":"=encoding UTF8\n\n=head1 NAME\n\nURI::Fast - A fast(er) URI parser\n\n=head1 SYNOPSIS\n\n  use URI::Fast qw(uri);\n\n  my $uri = uri 'http://www.example.com/some/path?fnord=slack\u0026foo=bar';\n\n  if ($uri-\u003escheme =~ /http(s)?/) {\n    my @path  = $uri-\u003epath;\n    my $fnord = $uri-\u003eparam('fnord');\n    my $foo   = $uri-\u003eparam('foo');\n  }\n\n  if ($uri-\u003epath =~ /\\/login/ \u0026\u0026 $uri-\u003escheme ne 'https') {\n    $uri-\u003escheme('https');\n    $uri-\u003eparam('upgraded', 1);\n  }\n\n=head1 DESCRIPTION\n\nC\u003cURI::Fast\u003e is a faster alternative to L\u003cURI\u003e. It is written in C and provides\nbasic parsing and modification of a URI.\n\nL\u003cURI\u003e is an excellent module; it is battle-tested, robust, and handles many\nedge cases. As a result, it is rather slower than it would otherwise be for\nmore trivial cases, such as inspecting the path or updating a single query\nparameter.\n\n=head1 EXPORTED SUBROUTINES\n\nSubroutines are exported on demand.\n\n=head2 uri\n\nAccepts a URI string, minimally parses it, and returns a C\u003cURI::Fast\u003e object.\n\nNote: passing a C\u003cURI::Fast\u003e instance to this routine will cause the object to\nbe interpolated into a string (via L\u003c/to_string\u003e), effectively creating a clone\nof the original C\u003cURI::Fast\u003e object.\n\n=head2 iri\n\nSimilar to L\u003c/uri\u003e, but returns a C\u003cURI::Fast::IRI\u003e object. A C\u003cURI::Fast::IRI\u003e\ndiffers from a C\u003cURI::Fast\u003e in that UTF-8 characters are permitted and will not\nbe percent-encoded when modified.\n\n=head2 abs_uri\n\nBuilds a new C\u003cURI::Fast\u003e from a relative URI string and makes it L\u003c/absolute\u003e\nin relation to C\u003c$base\u003e.\n\n  my $uri = abs_uri 'some/path', 'http://www.example.com/fnord';\n  $uri-\u003eto_string; # \"http://www.example.com/fnord/some/path\"\n\n=head2 html_url\n\nParses a URI string, removing whitespace characters ignored in URLs found in\nHTML documents, replacing backslashes with forward slashes, and making the\nURL L\u003c/normalize\u003ed.\n\nIf a base URL is specified, the C\u003cURI::Fast\u003e object returned will be made\nL\u003c/absolute\u003e relative to that base URL.\n\n  # Resulting URL is \"https://www.slashdot.org/recent\"\n  my $url = html_url '//www.slashdot.org\\recent', \"https://www.slashdot.org\";\n\n=head2 uri_split\n\nBehaves (hopefully) identically to L\u003cURI::Split\u003e, but roughly twice as fast.\n\n=head2 encode/decode/uri_encode/uri_decode\n\nSee L\u003c/ENCODING\u003e.\n\n=head1 CONSTRUCTORS\n\n=head2 new\n\nIf desired, both C\u003cURI::Fast\u003e and L\u003cURI::Fast::IRI\u003e may be instantiated using\nthe default OO-flavored constructor, C\u003cnew\u003e.\n\n  my $uri = URI::Fast-\u003enew('http://www.example.com');\n\n=head2 new_abs\n\nOO equivalent to L\u003c/abs_uri\u003e.\n\n=head2 new_html_url\n\nOO equivalent to L\u003c/html_url\u003e.\n\n=head1 ATTRIBUTES\n\nAll attributes serve as full accessors, allowing the URI segment to be both\nretrieved and modified.\n\n=head2 RAW ACCESSORS\n\nEach attribute defines a C\u003craw_*\u003e method, which returns the raw, encoded string\nvalue for that attribute. If a new value is passed, it will set the field to\nthe raw, unchanged value without checking it or changing it in any way.\n\n=head2 CLEARERS\n\nEach attribute further has a matching clearer method (C\u003cclear_*\u003e) which unsets\nits value.\n\n=head2 ACCESSORS\n\nIn general, accessors accept an I\u003cunencoded\u003e string and set their slot value to\nthe I\u003cencoded\u003e value. They return the decoded value. See L\u003c/ENCODING\u003e for an in\ndepth description of their behavior as well as an explanation of the more\ncomplex behavior of compound fields.\n\n=head3 scheme\n\nGets or sets the scheme portion of the URI (e.g. C\u003chttp\u003e), excluding C\u003c://\u003e.\n\n=head3 auth\n\nThe authorization section is composed of the username, password, host name, and\nport number:\n\n  hostname.com\n  someone@hostname.com\n  someone:secret@hostname.com:1234\n\nSetting this field may be done with a string (see the note below about\nL\u003c/ENCODING\u003e) or a hash reference of individual field names (C\u003cusr\u003e, C\u003cpwd\u003e,\nC\u003chost\u003e, and C\u003cport\u003e). In both cases, the existing values are completely\nreplaced by the new values and any values missing from the caller-supplied\ninput are deleted.\n\n=head4 usr\n\nThe username segment of the authorization string. Updating this value alters\nL\u003c/auth\u003e.\n\n=head4 pwd\n\nThe password segment of the authorization string. Updating this value alters\nL\u003c/auth\u003e.\n\n=head4 host\n\nThe host name segment of the authorization string. May be a domain string or an\nIP address. If the host is an IPV6 address, it must be surrounded by square\nbrackets (per spec), which are included in the host string. Updating this value\nalters L\u003c/auth\u003e.\n\n=head4 port\n\nThe port number segment of the authorization string. Updating this value alters\nL\u003c/auth\u003e.\n\n=head3 path\n\nIn scalar context, returns the entire path string. In list context, returns a\nlist of path segments, split by C\u003c/\u003e.\n\n  my $uri = uri '/foo/bar';\n  my $path = $uri-\u003epath;  # \"/foo/bar\"\n  my @path = $uri-\u003epath;  # (\"foo\", \"bar\")\n\nThe path may also be updated using either a string or an array ref of segments:\n\n  $uri-\u003epath('/foo/bar');\n  $uri-\u003epath(['foo', 'bar']);\n\nThis differs from the behavior of L\u003cURI/path_segments\u003e, which considers the\nleading slash separating the path from the authority section to be an\nindividual segment. If this behavior is desired, the lower level\nC\u003csplit_path_compat\u003e is available. C\u003csplit_path_compat\u003e (and its partner,\nC\u003csplit_path\u003e), always return an array reference.\n\n  my $uri = uri '/foo/bar';\n  $uri-\u003esplit_path;         # ['foo', 'bar'];\n  $uri-\u003esplit_path_compat;  # ['', 'foo', 'bar'];\n\n=head3 query\n\nIn scalar context, returns the complete query string, excluding the leading\nC\u003c?\u003e. The query string may be set in several ways.\n\n  $uri-\u003equery(\"foo=bar\u0026baz=bat\"); # note: no percent-encoding performed\n  $uri-\u003equery({foo =\u003e 'bar', baz =\u003e 'bat'}); # foo=bar\u0026baz=bat\n  $uri-\u003equery({foo =\u003e 'bar', baz =\u003e 'bat'}, ';'); # foo=bar;baz=bat\n\nIn list context, returns a hash ref mapping query keys to array refs of their\nvalues (see L\u003c/query_hash\u003e).\n\nBoth '\u0026' and ';' are treated as separators for key/value parameters.\n\n=head3 frag\n\nThe fragment section of the URI, excluding the leading C\u003c#\u003e.\n\n=head3 fragment\n\nAn alias of L\u003c/frag\u003e.\n\n=head1 METHODS\n\n=head2 query_keys\n\nDoes a fast scan of the query string and returns a list of unique parameter\nnames that appear in the query string.\n\nBoth '\u0026' and ';' are treated as separators for key/value parameters.\n\n=head2 query_hash\n\nScans the query string and returns a hash ref of key/value pairs. Values are\nreturned as an array ref, as keys may appear multiple times. Both '\u0026' and ';'\nare treated as separators for key/value parameters.\n\nMay optionally be called with a new hash of parameters to replace the query\nstring with, in which case keys may map to scalar values or arrays of scalar\nvalues. As with all query setter methods, a third parameter may be used to\nexplicitly specify the separator to use when generating the new query string.\n\n=head2 param\n\nGets or sets a parameter value. Setting a parameter value will replace existing\nvalues completely; the L\u003c/query\u003e string will also be updated. Setting a\nparameter to C\u003cundef\u003e deletes the parameter from the URI.\n\n  $uri-\u003eparam('foo', ['bar', 'baz']);\n  $uri-\u003eparam('fnord', 'slack');\n\n  my $value_scalar = $uri-\u003eparam('fnord'); # fnord appears once\n  my @value_list   = $uri-\u003eparam('foo');   # foo appears twice\n  my $value_scalar = $uri-\u003eparam('foo');   # croaks; expected single value but foo has multiple\n\n  # Delete parameter\n  $uri-\u003eparam('foo', undef); # deletes foo\n\n  # Ambiguous cases\n  $uri-\u003eparam('foo', '');  # foo=\n  $uri-\u003eparam('foo', '0'); # foo=0\n  $uri-\u003eparam('foo', ' '); # foo=%20\n\nBoth '\u0026' and ';' are treated as separators for key/value parameters when\nparsing the query string. An optional third parameter explicitly selects the\ncharacter used to separate key/value pairs.\n\n  $uri-\u003eparam('foo', 'bar', ';'); # foo=bar\n  $uri-\u003eparam('baz', 'bat', ';'); # foo=bar;baz=bat\n\nWhen unspecified, '\u0026' is chosen as the default. I\u003cIn either case, all\nseparators in the query string will be normalized to the chosen separator\u003e.\n\n  $uri-\u003eparam('foo', 'bar', ';'); # foo=bar\n  $uri-\u003eparam('baz', 'bat', ';'); # foo=bar;baz=bat\n  $uri-\u003eparam('fnord', 'slack');  # foo=bar\u0026baz=bat\u0026fnord=slack\n\n=head2 add_param\n\nUpdates the query string by adding a new value for the specified key. If the\nkey already exists in the query string, the new value is appended without\naltering the original value.\n\n  $uri-\u003eadd_param('foo', 'bar'); # foo=bar\n  $uri-\u003eadd_param('foo', 'baz'); # foo=bar\u0026foo=baz\n\nThis method is simply sugar for calling:\n\n  $uri-\u003eparam('key', [$uri-\u003eparam('key'), 'new value']);\n\nAs with L\u003c/param\u003e, the separator character may be specified as the final\nparameter. The same caveats apply with regard to normalization of the query\nstring separator.\n\n  $uri-\u003eadd_param('foo', 'bar', ';'); # foo=bar\n  $uri-\u003eadd_param('foo', 'baz', ';'); # foo=bar;foo=baz\n\n=head2 query_keyset\n\nAllows modification of the query string in the manner of a set, using keys\nwithout C\u003c=value\u003e, e.g. C\u003cfoo\u0026bar\u0026baz\u003e. Accepts a hash ref of keys to update.\nA truthy value adds the key, a falsey value removes it. Any keys not mentioned\nin the update hash are left unchanged.\n\n  my $uri = uri '\u0026baz\u0026bat';\n  $uri-\u003equery_keyset({foo =\u003e 1, bar =\u003e 1}); # baz\u0026bat\u0026foo\u0026bar\n  $uri-\u003equery_keyset({baz =\u003e 0, bat =\u003e 0}); # foo\u0026bar\n\nIf there are key-value pairs in the query string as well, the behavior of\nthis method becomes a little more complex. When a key is specified in the\nhash update hash ref, a positive value will leave an existing key/value pair\nuntouched. A negative value will remove the key and value.\n\n  my $uri = uri '\u0026foo=bar\u0026baz\u0026bat';\n  $uri-\u003equery_keyset({foo =\u003e 1, baz =\u003e 0}); # foo=bar\u0026bat\n\nAn optional second parameter may be specified to control the separator\ncharacter used when updating the query string. The same caveats apply with\nregard to normalization of the query string separator.\n\n=head2 append\n\nSerially appends path segments, query strings, and fragments, to the end of the\nURI. Each argument is added in order. If the segment begins with C\u003c?\u003e, it is\nassumed to be a query string and it is appended using L\u003c/add_param\u003e. If the\nsegment begins with C\u003c#\u003e, it is treated as a fragment, replacing any existing\nfragment. Otherwise, the segment is treated as a path fragment and appended to\nthe path.\n\n  my $uri = uri 'http://www.example.com/foo?k=v';\n  $uri-\u003eappend('bar', 'baz/bat', '?k=v1\u0026k=v2', '#fnord', 'slack');\n  # 'http://www.example.com/foo/bar/baz/bat/slack?k=v\u0026k=v1\u0026k=v2#fnord'\n\n\n=head2 to_string\n\n=head2 as_string\n\n=head2 \"$uri\"\n\nStringifies the URI, encoding output as necessary. String interpolation is\noverloaded.\n\n=head2 compare\n\n=head2 $uri eq $other\n\nCompares the URI to another, returning true if the URIs are equivalent.\nOverloads the C\u003ceq\u003e operator.\n\n=head2 clone\n\nSugar for:\n\n  my $uri = uri '...';\n  my $clone = uri $uri;\n\n=head2 absolute\n\nBuilds an absolute URI from a relative URI and a base URI string.\nAdheres as strictly as possible to the rules for resolving a target URI in\nL\u003cRFC3986 section 5.2|https://www.rfc-editor.org/rfc/rfc3986.txt\u003e. Returns a new\nL\u003cURI::Fast\u003e object representing the absolute, merged URI.\n\n  my $uri = uri('some/path')-\u003eabsolute('http://www.example.com/fnord');\n  $uri-\u003eto_string; # \"http://www.example.com/fnord/some/path\"\n\n=head2 abs\n\nAlias of L\u003c/absolute\u003e.\n\n=head2 relative\n\nBuilds a relative URI using a second URI (either a C\u003cURI::Fast\u003e object or a\nstring) as a base. Unlike L\u003cURI/rel\u003e, ignores differences in domain and scheme\nassumes the caller wishes to adopt the base URL's instead. Aside from that difference,\nit's behavior should mimic L\u003cURI/rel\u003e's.\n\n  my $uri = uri('http://example.com/foo/bar')-\u003erelative('http://example.com/foo');\n  $uri-\u003eto_string; # \"foo/bar\"\n\n  my $uri = uri('http://example.com/foo/bar/')-\u003erelative('http://example.com/foo');\n  $uri-\u003eto_string; # \"foo/bar/\"\n\n=head2 rel\n\nAlias of L\u003c/relative\u003e.\n\n=head2 normalize\n\nSimilar to L\u003cURI/canonical\u003e, performs a minimal normalization on the URI. Only\ngeneric normalization described in the rfc is performed; no scheme-specific\nnormalization is done. Specifically, the scheme and host members are converted\nto lower case, dot segments are collapsed in the path, and any percent-encoded\ncharacters in the URI are converted to upper case.\n\n=head2 canonical\n\nAlias of L\u003c/normalize\u003e.\n\n=head1 ENCODING\n\nC\u003cURI::Fast\u003e tries to do the right thing in most cases with regard to reserved\nand non-ASCII characters. C\u003cURI::Fast\u003e will fully encode reserved and non-ASCII\ncharacters when setting I\u003cindividual\u003e values and return their fully decoded\nvalues. However, the \"right thing\" is somewhat ambiguous when it comes to\nsetting compound fields like L\u003c/auth\u003e, L\u003c/path\u003e, and L\u003c/query\u003e.\n\nWhen setting compound fields with a string value, reserved characters are\nexpected to be present, and are therefore accepted as-is. Any non-ASCII\ncharacters will be percent-encoded (since they are unambiguous and there is no\nrisk of double-encoding them). Thus,\n\n  $uri-\u003eauth('someone:secret@Ῥόδος.com:1234');\n  print $uri-\u003eauth; # \"someone:secret@%E1%BF%AC%CF%8C%CE%B4%CE%BF%CF%82.com:1234\"\n\nOn the other hand, when setting these fields with a I\u003creference\u003e value (assumed\nto be a hash ref for L\u003c/auth\u003e and L\u003c/query\u003e or an array ref for L\u003c/path\u003e; see\nindividual methods' docs for details), each field is fully percent-encoded,\njust as if each individual simple slot's setter had been called:\n\n  $uri-\u003eauth({usr =\u003e 'some one', host =\u003e 'somewhere.com'});\n  print $uri-\u003eauth; # \"some%20one@somewhere.com\"\n  print $uri-\u003eusr;; # \"some one\"\n\nThe same goes for return values. For compound fields returning a string,\nnon-ASCII characters are decoded but reserved characters are not. When\nreturning a list or reference of the deconstructed field, individual values are\ndecoded of both reserved and non-ASCII characters.\n\n=head2 '+' vs '%20'\n\nAlthough no longer part of the standard, C\u003c+\u003e is commonly used as the encoded\nspace character (rather than C\u003c%20\u003e); it I\u003cis\u003e still official to the\nC\u003capplication/x-www-form-urlencoded\u003e type, and is treated as a space by\nL\u003c/decode\u003e.\n\n=head2 encode\n\nPercent-encodes a string for use in a URI. By default, both reserved and UTF-8\nchars (C\u003c! * ' ( ) ; : @ \u0026 = + $ , / ? # [ ] %\u003e) are encoded.\n\nA second (optional) parameter provides a string containing any characters the\ncaller does not wish to be encoded. An empty string will result in the default\nbehavior described above.\n\nFor example, to encode all characters in a query-like string I\u003cexcept\u003e for\nthose used by the query:\n\n  my $encoded = URI::Fast::encode($some_string, '?\u0026=');\n\n=head2 decode\n\nDecodes a percent-encoded string.\n\n  my $decoded = URI::Fast::decode($some_string);\n\n=head2 uri_encode\n\n=head2 uri_decode\n\nThese are aliases of L\u003c/encode\u003e and L\u003c/decode\u003e, respectively. They were added\nto make L\u003cBLUEFEET|https://metacpan.org/author/BLUEFEET\u003e happy after he made\nfun of me for naming L\u003c/encode\u003e and L\u003c/decode\u003e too generically.\n\nIn fact, these were originally aliased as C\u003curl_encode\u003e and C\u003curl_decode\u003e, but\ndue to some pedantic whining on the part of\nL\u003cBGRIMM|https://metacpan.org/author/BGRIMM\u003e, they have been renamed to\nC\u003curi_encode\u003e and C\u003curi_decode\u003e.\n\n=head2 escape_tree\n\n=head2 unescape_tree\n\nTraverses a data structure, escaping or unescaping I\u003cdefined\u003e scalar values in\nplace. Accepts a reference to be traversed. Any further parameters are passed\nunchanged to L\u003c/encode\u003e or L\u003c/decode\u003e. Croaks if the input to escape/unescape\nis a non-reference value.\n\n  my $obj = {\n    foo =\u003e ['bar baz', 'bat%fnord'],\n    bar =\u003e {baz =\u003e 'bat%bat'},\n    baz =\u003e undef,\n    bat =\u003e '',\n  };\n\n  URI::Fast::escape_tree($obj);\n\n  # $obj is now:\n  {\n    foo =\u003e ['bar%20baz', 'bat%25fnord'],\n    bar =\u003e {baz =\u003e 'bat%25bat'},\n    baz =\u003e undef,\n    bat =\u003e '',\n  }\n\n  URI::Fast::unescape_tree($obj); # $obj returned to original form\n\n  URI::Fast::escape_tree($obj, '%'); # escape but allow \"%\"\n\n  # $obj is now:\n  {\n    foo =\u003e ['bar%20baz', 'bat%fnord'],\n    bar =\u003e {baz =\u003e 'bat%bat'},\n    baz =\u003e undef,\n    bat =\u003e '',\n  }\n\n=head1 CAVEATS\n\nThis module is designed to parse URIs according to RFC 3986. Browsers parse\nURLs using a different (but similar) algorithm and some strings that are valid\nURLs to browsers are not valid URIs to this module. The L\u003c/html_url\u003e function\nattempts to parse URLs more in line with how browsers do, but no guarantees are\nmade as HTML standards and browser implementations are an ever shifting\nlandscape.\n\n=head1 SPEED\n\nSee L\u003cURI::Fast::Benchmarks\u003e.\n\n=head1 SEE ALSO\n\n=over\n\n=item L\u003cURI\u003e\n\nThe de facto standard.\n\n=item L\u003cRFC 3986|https://www.rfc-editor.org/rfc/rfc3986.txt\u003e\n\nThe official standard.\n\n=back\n\n=head1 ACKNOWLEDGEMENTS\n\nThanks to L\u003cZipRecruiter|https://www.ziprecruiter.com\u003e for encouraging their\nemployees to contribute back to the open source ecosystem. Without their\ndedication to quality software development this distribution would not exist.\n\n=head1 CONTRIBUTORS\n\nThe following people have contributed to this module with patches, bug reports,\nAPI advice, identifying areas where the documentation is unclear, or by making\nfun of me for naming certain methods too generically.\n\n=over\n\n=item Andy Ruder\n\n=item Aran Deltac (BLUEFEET)\n\n=item Ben Grimm (BGRIMM)\n\n=item Dave Hubbard (DAVEH)\n\n=item James Messrie\n\n=item Martin Locklear\n\n=item Randal Schwartz (MERLYN)\n\n=item Sara Siegal (SSIEGAL)\n\n=item Tim Vroom (VROOM)\n\n=item Des Daignault (NAWGLAN)\n\n=item Josh Rosenbaum\n\n=back\n\n=head1 AUTHOR\n\nJeff Ober \u003csysread@fastmail.fm\u003e\n\n=head1 COPYRIGHT AND LICENSE\n\nThis software is copyright (c) 2018 by Jeff Ober. This is free software; you\ncan redistribute it and/or modify it under the same terms as the Perl 5\nprogramming language system itself.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsysread%2Furi-fast","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsysread%2Furi-fast","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsysread%2Furi-fast/lists"}