## dist_zef-finanalyst-Raku-Pod-Render.md
# Generic Pod Renderer

> Transforms POD in a Raku module/pod to other format such as HTML or MarkDown.

## Table of Contents

[Installation](#installation)
[Dependencies](#dependencies)
[Page Components](#page-components)
[TOC](#toc)
[Glossary](#glossary)
[Footnotes](#footnotes)
[Links](#links)
[Meta data](#meta-data)
[RakuClosureTemplates](#rakuclosuretemplates)
[Testing tool](#testing-tool)
[HTML highlighting](#html-highlighting)
[Tests](#tests)
[Tutorial](#tutorial)
[More Information](#more-information)

---

Intended

* to provide a plugin replacement for the original (legacy) Pod::To::HTML and to pass all its tests.
* to use templates for all output (legacy Pod::To::HTML hard codes HTML)
* use the same API for outputting MarkDown and other output formats. Hence simply changing templates will generate new output
* generate Glossary, TOC and Footnote structures for each set of Pod trees.
* to generate HTML and Markdown with raku's --doc flag.
* optionally to highlight Raku code at HTML generation time.

The Renderers, eg., Pod::To::HTML2, will chose the templating engine depending on the templates provided. So far only Template::Mustache and the new RakuClosureTemplates are handled, though other engines can be subclassed in.

# Installation

If highlighting is desired (see [Highlighting](Highlighting.md) below) from the start, an environment variable needs to be set (also see [Dependencies](Dependencies.md)).

```
POD_RENDER_HIGHLIGHTER=1 zef install Raku::Pod::Render

```

Since it is intended that `Raku::Pod::Render` can be used as a dependency for other modules, eg `raku-alt-documentation`, and it cannot be known whether all dependencies are installed, the default must be to prevent highlighting from being installed. If this is desired then,

```
zef install Raku::Pod::Render

```

will install the module without checking or installing a highlighter. If, **after the default installation**, the highlighter is needed and *node & npm are installed*, then it can be installed by running the following in a terminal:

```
raku-render-install-highlighter

```

## Dependencies

The default highlighter at present is a Node based toolstack called **atom-perl-highlighter**. In order to install it automatically, `Raku::Pod::Render` requires an uptodate version of npm. The builder is known not to work with `node.js` > \*\*\*\*v13.0> and `npm` > **v14.15**.

For someone who has not installed `node` or `npm` before, or for whom they are only needed for the highlighter, the installation is ... confusing. It would seem at the time of writing that the easiest method is:

```
# Using Ubuntu
curl -sL https://deb.nodesource.com/setup_14.x | sudo -E bash -
sudo apt-get install -y nodejs

```

# Page Components

A Pod6 source will generate body text and generate information for TOC, Footnotes, Glossaries, Links and Metadata

## TOC

A TOC or Table of Contents contains each Header text and a README.mdtarget within the document. For an HTML or MarkDown file, the target will be an anchor name and will react to a mouse click.

For a dead tree format, or soft equivalent, the pointer will be a page number.

ProcessedPod create as TOC structure that is an array in the order the headers appear, with the lable, destination anchor, return anchor and the level of the header.

## Glossary

A Glossary, or Index, is a list of words or phrases that may be used or defined in multiple places within a document and which the author / editor considers would be useful to the reader when searching. Glossary structures are also useful when creating SEARCH type functions.

The word 'index' is not used because in the HTML world, the file index.html is mostly used as the landing page for a collection of documents and in most cases is a Table of Contents rather than a Glossary.

In a POD file, glossary texts are created with the formatting code.

ProcessedPod creates a structure as a hash of the entry names (a single can have multiple entry names pointing to the same target), the destination anchors, the return anchor, and in the case where anchors are not possible, a location consisting of the most recent header text.

## Footnotes

When an author wishes to give more explanation to a phrase without interupting the logic of the text, the information is included in a footnote. In dead-tree formats, the footnotes tended to be at the end of a page (hence foot note). In HTML for PCs/Laptops, a popular format was to include text to be shown by hovering a mouse. For smartphone applications, hovering is not convenient, and other solutions are being found.

ProcessedPod creates an array in order of footnote creation with the number of the footnote, and target and return anchors.

## Links

Links can be

* internal to the document
* external to the site (eg. on the internet)
* local to the site

Links should be tested. While the data is collected, verifying links is left to other modules.

## Meta data

Pod6 allows for metadata such as AUTHOR or VERSION to be set. These can be included in HTML or other formats.

# RakuClosureTemplates

A new templating system is introduced to speed up the rendering. The Pod::To::HTML2 renderer is now slightly faster than the legacy Pod::To::HTML renderer, whilst achieving considerably more.

## Testing tool

A testing tool is included that will test the array of RakuClosureTemplates, including the possibility of specifying the structure of a custom template and testing it against the template.

# HTML highlighting

Raku code in HTML can be highlighted when HTML is generated. This requires the atom-perl6-highlighter developed by Samantha McVie. In the legacy Pod::To::HTML this is installed separately. This module will automatically install the highlighter unless specifically rejected by setting the POD\_RENDER\_NO\_HIGHLIGHTER=1 environment variable.

The Build Module places the highlighter in the users directory at either (in order of preference)

* .local/lib/raku-pod-render/highlights
* .raku-pod-render/highlights

If the highlighter already exists at one of these locations, further installations of Raku-Pod-Render will not rebuild the stack.

This behaviour can be over-riden by

```
RAKU_POD_RENDER_FORCE_HIGHLIGHTER_REFRESH zef install Raku::Pod::Render

```

# Tests

Only sanity tests are under the `t/` directory. Extensive tests are under `xt/`.

Some tests require an online connection. The tests can be run offline by setting the environment variable TEST\_OFFLINE, eg. `TEST_OFFLINE=1 prove6 -I. xt/`.

# Tutorial

A short tutorial is included to show how a new Format Code can be created. It was written for the Advent Calendar in 2022. See the `tutorial/` directory.

# More Information

See [RenderPod](RenderPod.md) for the generic module and [Pod2HTML](Pod2HTML.md) for information about the HTML specific module `Pod::To::HTML2`. `Pod::To::Markdown2`, see [MarkDown2](MarkDown2.md), follows `Pod::To::HTML2` mostly.

---

Rendered from README at 2023-03-17T10:40:15Z


## dist_zef-jnthn-IO-Socket-Async-SSL.md
# IO::Socket::Async::SSL [Build Status](https://travis-ci.org/jnthn/p6-io-socket-async-ssl)

This module provides a secure sockets implementation with an API very much
like that of the Raku built-in `IO::Socket::Async` class. For the client
case, provided the standard certificate and host verification are sufficient,
it is drop-in replacement. The server case only needs two extra arguments to
`listen`, specifying the server key and certificate.

As with `IO::Socket::Async`, it is safe to have concurrent connections and to
share them across threads.

## Synopsis

Client:

```
use IO::Socket::Async::SSL;

my $conn = await IO::Socket::Async::SSL.connect('www.raku.org', 443);
$conn.print: "GET / HTTP/1.0\r\nHost: www.raku.org\r\n\r\n";
react {
    whenever $conn {
        .print
    }
}
$conn.close;

```

Server (assumes certificate and key files `server-crt.pem` and `server-key.pem`):

```
use IO::Socket::Async::SSL;

react {
    my %ssl-config =
        certificate-file => 'server-crt.pem',
        private-key-file => 'server-key.pem';
    whenever IO::Socket::Async::SSL.listen('localhost', 4433, |%ssl-config) -> $conn {
        my $req = '';
        whenever $conn {
            $req ~= $_;
            if $req.contains("\r\n\r\n") {
                say $req.lines[0];
                await $conn.print(
                    "HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n" ~
                    "<strong>Hello from a Raku HTTP server</strong>\n");
                $conn.close;
            }
        }
    }
}

```

## Client

The `connect` method on `IO::Socket::Async::SSL` is used to establish a SSL
connection to a server. It requies two positional arguments, which specify the
`host` and `port` to connect to. It returns a `Promise`, which will be kept
with an `IO::Socket::Async::SSL` instance when the connection is established
and the SSL handshake completed.

```
my $conn = await IO::Socket::Async::SSL.connect($host, $port);

```

By default, the SSL certificate will be verified, using the default set of
accepted Certificate Authorities. The `Promise` return by `connect` will be
broken if verification fails.

Sometimes it is convenient to create a CA and use it to sign certificates for
internal use, for example to secure communications between a set of services
on an internal network. In this case, the `ca-file` named argument can be
passed to specify the certificate authority certificate file:

```
my $ca-file = '/config/ca-crt.pem';
my $conn = await IO::Socket::Async::SSL.connect('user-service', 443, :$ca-file);

```

Alternatively, a `ca-path` argument can be specified, indicating a directory
where one or more certificates may be found.

It is possible to disable certificate verification by passing the `insecure`
named argument a true value. As the name suggests, **this is not a secure
configuration**, since there is no way for the client to be sure that it is
communicating with the intended server. Therefore, it is vulnerable to
man-in-the-middle attacks.

For control over the ciphers that may be used, pass the `ciphers` argument to
`connect`. It should be a string in [OpenSSL cipher list format](https://www.openssl.org/docs/man1.0.2/apps/ciphers.html).

If wishing to view encrypted traffic with a tool such as Wireshark for debugging
purposes, pass a filename to `ssl-key-log-file`. Session keys will be written to
this log file, and Wireshark can then be configured to introspect the encrypted
traffic (Preferences -> Protocols -> TLS -> (Pre-)-Master-Secret log filename). Note
that this key exposure compromises the security of the session!

## Server

The `listen` method returns a `Supply` that, when tapped, will start an SSL
server. The server can be shut down by closing the tap. Whenever a connection
is made to the server, the `Supply` will emit an `IO::Socket::Async::SSL`
instance. The `listen` method requires two positional arguments, specifying
the `host` and `port` to listen on. Two named arguments are also required,
providing the `certificate-file` and `private-key-file`.

```
my %ssl-config =
    certificate-file => 'server-crt.pem',
    private-key-file => 'server-key.pem';
my $connections = IO::Socket::Async::SSL.listen('localhost', 4433, |%ssl-config);
react {
    my $listener = do whenever $connections -> $conn {
        say "Got a connection!";
        $conn.close;
    }

    whenever signal(SIGINT) {
        say "Shutting down...";
        $listener.close;
        exit;
    }
}

```

For control over the ciphers that may be used, pass the `ciphers` argument to
`connect`. It should be a string in [OpenSSL cipher list format](https://www.openssl.org/docs/man1.0.2/apps/ciphers.html). The following boolean options are also accepted:

* `prefer-server-ciphers` - indicates that the order of the ciphers list as
  configured on the server should be preferred over that of the one presented
  by the client
* `no-compression` - disables compression
* `no-session-resumption-on-renegotiation`

## Common client and server functionality

Both the `connect` and `listen` methods take the following optional named
arguments:

* `enc`, which specifies the encoding to use when the socket is used in
  character mode. Defaults to `utf-8`.
* `scheduler`, which specifies the scheduler to use for processing events from
  the underlying `IO::Socket::Async` instance. The default is `$*SCHEDULER`.
  There is rarely a need to change this.

The `Supply`, `print`, `write`, and `close` methods have the same semantics as
in [IO::Socket::Async](https://docs.raku.org/type/IO$COLON$COLONSocket$COLON$COLONAsync).

## Upgrading connections

Some protocols use [opportunistic TLS](https://en.wikipedia.org/wiki/Opportunistic_TLS),
where the decision to use transport layer security is first negotiated using
a non-encrypted protocol - provided negotiation is successful - a TLS handshake
is then performed. This functionality is provided by the `upgrade-server` and
`upgrade-client` methods. Note that the socket to upgrade must be an instance
of `IO::Socket::Async`. Further, it is important to **stop reading from the
socket before initiating the upgrade**, which will typically entail working with
the `Tap` directly, something not normally needed in `react`/`whenever` blocks.

Here is an example of using `upgrade-server`.

```
react whenever IO::Socket::Async.listen('localhost', TEST_PORT) -> $plain-conn {
    my $plain-tap = do whenever $plain-conn.Supply -> $start {
        if $start eq "Psst, let's talk securely!\n" {
            # Must stop reading...
            $plain-tap.close;
            # ...so the module can take over the socket.
            my $enc-conn-handshake = IO::Socket::Async::SSL.upgrade-server(
                $plain-conn,
                private-key-file => 't/certs-and-keys/server.key',
                certificate-file => 't/certs-and-keys/server-bundle.crt'
            );
            whenever $enc-conn-handshake -> $enc-conn {
                uc-service($enc-conn);
            }
            $plain-conn.print("OK, let's talk securely!\n");
        }
        else {
            $plain-conn.print("OK, let's talk insecurely\n");
            uc-service($plain-conn);
        }
    }

    sub uc-service($conn) {
        whenever $conn -> $crypt-text {
            whenever $conn.print($crypt-text.uc) {
                $conn.close;
            }
        }
    }
}

```

Here's an example using `upgrade-client`; again, take note of the careful handling
of the `Tap`.

```
my $plain-conn = await IO::Socket::Async.connect('localhost', TEST_PORT);
await $plain-conn.print("Psst, let's talk securely!\n");
react {
    my $plain-tap = do whenever $plain-conn -> $msg {
        $plain-tap.close;
        my $enc-conn-handshake = IO::Socket::Async::SSL.upgrade-client(
            $plain-conn,
            host => 'localhost',
            ca-file => 't/certs-and-keys/ca.crt');
        whenever $enc-conn-handshake -> $enc-conn {
            await $enc-conn.print("hello!\n");
            whenever $enc-conn.head -> $got {
                print $got; # HELLO!
                done;
            }
        }
    }
}

```

## Bugs, feature requests, and contributions

Please use [GitHub Issues](https://github.com/jnthn/p6-io-socket-async-ssl/issues)
to file bug reports and feature requests. If you wish to contribute to this
module, please open a GitHub Pull Request, or email a Git patch (produced using
`format-patch`) to [jnthn@jnthn.net](mailto:jnthn@jnthn.net). Please also use
this email address to report security vulnerabilities.


## dist_zef-tbrowder-Bin-Utils.md
[![Actions Status](https://github.com/tbrowder/Bin-Utils/actions/workflows/linux.yml/badge.svg)](https://github.com/tbrowder/Bin-Utils/actions) [![Actions Status](https://github.com/tbrowder/Bin-Utils/actions/workflows/macos.yml/badge.svg)](https://github.com/tbrowder/Bin-Utils/actions) [![Actions Status](https://github.com/tbrowder/Bin-Utils/actions/workflows/windows.yml/badge.svg)](https://github.com/tbrowder/Bin-Utils/actions)

# NAME

**Bin::Utils** - Provides routines to handle 'slurp/spurt' for any file type in read/write directories

# SYNOPSIS

```
use Bin::Utils;
# Get contents of a file of unknown encoding
my $from-path = "some-dir/file";
my $contents = slurp-file $from-path;
# Put contents of 'file' somewhere else
# We don't usually change the basename,
#   but we could at this point
my $basename = $from-path.IO.basename
my $dir = "another-dir/subdir";
spurt-file $contents, :$basename, :$dir";

```

# DESCRIPTION

**Bin::Utils** should be used by any module author who wants to provide the contents of a directory or file to its users. It provides the following routines:

### slurp-file

```
#| Assumes file is binary,
sub slurp-file(
     $path
    ) is export {...}

```

### spurt-file

```
#| Assumes file is binary
#| Returns the new path
sub spurt-file(
    $contents,
    :$basename!,
    :$dir is copy     #= the desired output directory
                      #= default: $*CWD ('.')
    --> IO::Path
    ) is export {...}

```

### bin-cmp

```
#| Compares two files' binary contents
#| using the GNU system utility 'cmp'
sub bin-cmp(
    $file1,
    $file2,
    # cmp options
    :$s = True,  # silent
    :$l = False, # list bytes differing and their values
    :$b = False, # list bytes differing
    :$n = 0,     # list first n bytes (default: 0 - list all)
    :$debug,
    --> List
    ) is export {...}

```

Note the Raku 'slurp' and 'spurt' routines have many other options that a normal user of this simplified library would not need. The treatment of all files as binary blobs has been shown to be usable for files of three different encodings, including 'Str'.

# AUTHOR

Tom Browder [tbrowder@acm.org](mailto:tbrowder@acm.org)

# COPYRIGHT AND LICENSE

© 2024-2025 Tom Browder

This library is free software; you may redistribute it or modify it under the Artistic License 2.0.


## dist_cpan-TYIL-MPD-Client.md
# MPD::Client

[![Build Status](https://travis-ci.org/scriptkitties/p6-MPD-Client.svg?branch=master)](https://travis-ci.org/scriptkitties/p6-MPD-Client)

A perl 6 module to connect to a running MPD instance, and control it.


## dist_zef-sdondley-Directory.md
[![Actions Status](https://github.com/sdondley/Directory/actions/workflows/test.yml/badge.svg)](https://github.com/sdondley/Directory/actions)

# NAME

Directory - an object representing a directory

# SYNOPSIS

```
use Directory;

# OBJECT CONSTRUCTION
my $dir = Directory.new('/some/dir'); # relative paths OK, too
my $dir = Directory.new('~');
my $dir = Directory.new();   # current working directory, '.'

# METHODS
my $bool = Directory.new('/some/dir').exists;
my $bool = Directory.new('/some/dir').is-empty;
my @entries = Directory.new('/some/dir').list;
my $bool = Directory.new('/some/dir').mktree;
my $bool = Directory.new('/some/dir').create;
my $bool = Directory.new('/some/dir').rmtree;
my $bool = Directory.new('/some/dir').empty-directory;
my $path = Directory.new('/some/dir').path;
my $dir = Directory.new('/some/dir').open;
my $sequence = $dir.dir;
$dir.close;

```

# DESCRIPTION

A Directory object wraps an [IO::Dir](https://raku.land/zef:raku-community-modules/IO::Dir) object as well as the the subroutines found in the [File::Directory::Tree](https://raku.land/github:labster/File::Directory::Tree) distribution. The module aims to make working with directories simpler. The primary motivation was for type constraining class attributes representing directories.

# CONSTRUCTION

## new(Str:D $path?)

Creates a new Directory object from the `$path` supplied or with the path to the current working directory if no `$path` is given. An error is thrown if a file already exists at the `$path`. A path beginning with the `~` character is replaced with the value of the `$*HOME`> variable, if it contains a value.

# METHODS

## Built-in methods

### exists

Returns a boolean value of `True` if the directory exists, `False` otherwise.

### is-empty

Returns a boolean value of `True` if the directory is empty, `False` otherwise.

### list(:Str, :absolute)

Returns an array of `IO::Path`s for each file and directory in the Directory object's path. Pass `:Str` to return strings instead and `:absolute` to return absolute paths.

### path

Returns the IO::Path object for the Directory object.

## `IO::Dir` methods

### open

Opens the Directory object with the `open` method from `IO::Dir`. Unlike with the `IO::Dir.open`, no path is passed to the method.

### dir(:Str, :absolute)

Runs the `dir` method from `IO::Dir`, returning a sequence of IO paths for files and directories contained by the Directory object. Pass `:Str` to return strings instead and `:absolute` to return absolute paths.

The Directory object must be opened with the `open` method before running this method.

### close

Closes the Directory object with the `close` method from `IO::Dir`

## `File::Directory::Tree Wrapper` methods

### mktree($mask = 0o777)

A wrapper for the File::Directory::Tree's mktree command.

### create($mask = 0o777)

Synonym for `mktree` method.

### rmtree

A wrapper for the File::Directory::Tree's rmtree command.

### empty-directory

A wrapper for the File::Directory::Tree's empty-directory command.

# AUTHOR

Steve Dondley [s@dondley.com](mailto:s@dondley.com)

# COPYRIGHT AND LICENSE

Copyright 2023 Steve Dondley

This library is free software; you can redistribute it and/or modify it under the Artistic License 2.0.


## dist_zef-antononcube-Math-DistanceFunctions.md
# Math::DistanceFunctions

Raku package with a collection of mathematical distance functions and a corresponding role.

The content of this package was "factored out" from
["ML::Clustering"](https://raku.land/zef:antononcube/ML::Clustering), [AAp1].

Faster versions of these functions are implemented in
["Math::DistanceFunctions::Native"](https://github.com/antononcube/Raku-Math-DistanceFunctions-Native), [AAp2].

A special package has the "edit distance" (aka Damerau-Levenshtein distance) -- see
["Math::DistanceFunctions::Edit"](https://github.com/antononcube/Raku-Math-DistanceFunctions-Edit), [AAp3].

---

## Installation

From Zef ecosystem:

```
zef install Math::DistanceFunctions

```

From GitHub:

```
zef install https://github.com/antononcube/Raku-Math-DistanceFunctions.git

```

---

## Usage examples

```
use Math::DistanceFunctions;

my @v1 = 10.rand xx 10;
my @v2 = 2.rand xx 10;

my @funcs = [
    :&bray-curtis-distance,
    :&canberra-distance,
    :&chessboard-distance,
    :&cosine-distance,
    :&dot-product,
    :&euclidean-distance,
    :&hamming-distance,
    :&manhattan-distance,
    :&squared-euclidean-distance
];

for @funcs -> $p {
    say "{$p.key} : {$p.value.(@v1, @v2)}";
}

```

```
# bray-curtis-distance : 0.6151407918691146
# canberra-distance : 5.824952422823202
# chessboard-distance : 8.570769750374787
# cosine-distance : 0.10484766994026384
# dot-product : 65.06821530189765
# euclidean-distance : 14.296040411329631
# hamming-distance : 10
# manhattan-distance : 38.15520204868512
# squared-euclidean-distance : 204.37677144236991

```

---

## References

[AAp1] Anton Antonov, [ML:Clustering Raku package](https://github.com/antononcube/Raku-ML-Clustering), (2022), [GitHub/antononcube](https://github.com/antononcube).

[AAp2] Anton Antonov,
[Math::DistanceFunctions::Edit Raku package](https://github.com/antononcube/Raku-Math-DistanceFunctions-Edit),
(2024),
[GitHub/antononcube](https://github.com/antononcube).

[AAp3] Anton Antonov,
[Math::DistanceFunctions::Native Raku package](https://github.com/antononcube/Raku-Math-DistanceFunctions-Native),
(2024),
[GitHub/antononcube](https://github.com/antononcube).


## dist_zef-lizmat-uniname-words.md
[![Actions Status](https://github.com/lizmat/uniname-words/actions/workflows/linux.yml/badge.svg)](https://github.com/lizmat/uniname-words/actions) [![Actions Status](https://github.com/lizmat/uniname-words/actions/workflows/macos.yml/badge.svg)](https://github.com/lizmat/uniname-words/actions) [![Actions Status](https://github.com/lizmat/uniname-words/actions/workflows/windows.yml/badge.svg)](https://github.com/lizmat/uniname-words/actions)

# NAME

uniname-words - look for words in unicode character names

# SYNOPSIS

```
use uniname-words;

say uniname-words.elems;  # 262166

say .uniname for uniname-words<love>;
# LOVE HOTEL
# LOVE LETTER
# I LOVE YOU HAND SIGN

say .uniname for uniname-words(<left bracket>);

```

# DESCRIPTION

The `uniname-words` distribution exports a single subroutine: `uniname-words`. When called without a parameter, it returns a `Map` with each word (/w+) from the unicode database (active at installation of the module) as a key (in lowercase), and an `int32` array of the codepoints that have that word in their name, as the value.

All Unicode reserved codepoints are available under the `reserved` key: the rest of the name can be deduced from the codepoint value.

When the `uniname-words` sub is called with one or more arguments, they are considered to be words to return the codepoints of: these can be specified as a `Str` or as a `Regex`. Given words will be automatically lowercased to be checked. An optional `:partial` named argument can be specified to return the codepoints of words that partially match.

By default, if more than one word has been specified, **all** words must occur in the unicode name to be included. An optional `:any` named argument can be specified that **any** of the specified words should occur.

# uw

This module also install a command-line utility `uw`, that takes one or more words, and the `--partial` and `--any` parameters, just like the `uniname-words` sub does, and lists the names of the selected code points on STDOUT. It also additionally takes a `--hex` parameter (to just see the hexadecimal values), a `--name` parameter (to just see the names) and/or a `--char` (to just see a rendition). These 3 parameters can also be mixed in any combination.

# un

This module also install a command-line utility `un`, that takes one or more strings, and lists the names of the code points of these strings on STDOUT. It also additionally takes a `--hex` parameter (to just see the hexadecimal values), a `--name` parameter (to just see the names) and/or a `--char` (to just see a rendition). These 3 parameters can also be mixed in any combination.

# INSTALLATION NOTE

Installing (or running this module for the first time after a runtime update) may take up to a minute (or possibly more on slower machines) because the entire unicode database is *then* checked, allowing it to remain up-to-date across versions of the run-time.

# AUTHOR

Elizabeth Mattijsen [liz@raku.rocks](mailto:liz@raku.rocks)

Source can be located at: <https://github.com/lizmat/uniname-words> . Comments and Pull Requests are welcome.

If you like this module, or what I’m doing more generally, committing to a [small sponsorship](https://github.com/sponsors/lizmat/) would mean a great deal to me!

# COPYRIGHT AND LICENSE

Copyright 2021, 2022, 2023, 2024, 2025 Elizabeth Mattijsen

This library is free software; you can redistribute it and/or modify it under the Artistic License 2.0.


## dist_zef-raku-community-modules-ANTLR4-Grammar.md
# ANTLR4::Grammar

`ANTLR4::Grammar` generates a Raku representation of an ANTLR4 AST.

# Synopsis

```
    use ANTLR4::Grammar;
    my $ag = ANTLR4::Grammar.new;

    say $ag.to-string('grammar Minimal { identifier : [A-Z][A-Za-z]+ ; }');
    say $ag.file-to-string('ECMAScript.g4');

```

# Installation

From the ecosystem using `zef`:

```
    zef install ANTLR4::Grammar

```

# Documentation

In its simplest form, just use the `to-string` method on an existing grammar text to get back its closest Raku representation.

# Extension

Suppose you don't like how the module formats the ANTLR grammar. Subclass this module and override the `to-lines` methods I've provided, or go all the way back to the top level and replace the `to-lines( Grammar $g )` with your own inheritance hierarchy.

Maybe you want to add a way to create a bare-bones action class to go along with your resulting grammar - override the `to-string` method, you've got the `$grammar` value that you can walk through, and do your own thing.

# Author

✝ Jeffrey Goff, DrForr on #raku, <https://github.com/drforr/>

Maintained by the Raku community (2020-2023)

# License

Artistic License 2.0


## dist_zef-p6steve-Dan-Polars.md
*WORK IN PROGRESS*

*So far, I have managed to bring about half of the Polars library into the Raku world with this module. Some track has been laid that may make the rest go faster and easier, but surely there is a lot of refactoring and tidying up to do to.*

*You can see the TODO files here for Query and Expression features and I will be working my way down this list steadily.*

*If you would like to alter the priority, please create an issue (or find an existing one) and hopefully others will upvoat it.*

*Even better would be to work with me to do a PR (I will probbaly need to do a bit of guidance initiallly).*

*p6steve@furnival.net*

*THIS MODULE IS EXPERIMENTAL AND SUBJECT TO CHANGE WITHOUT NOTICE*

[![](https://img.shields.io/badge/License-Artistic%202.0-0298c3.svg)](https://opensource.org/licenses/Artistic-2.0)
[![](https://github.com/p6steve/raku-Dan-Polars/actions/workflows/polars-weekly.yaml/badge.svg)](https://github.com/p6steve/raku-Dan-Polars/actions/workflows/polars-weekly.yaml)

# raku Dan::Polars - WIP

This new module binds Raku [Dan](https://github.com/p6steve/raku-Dan) to Polars via Raku NativeCall / Rust FFI.

The following broad capabilities are included:

* Polars structures (Series & DataFrames)
* Polars lazy queries & expressions
* raku Dan features (accessors, dtypes, base methods)
* broad datatype support
* concurrency

The aim is to emulate the examples in the [Polars User Guide](https://pola-rs.github.io/polars-book/user-guide/dsl/expressions.html)

### Installation

Based on the Dockerfile chain [(1)](https://github.com/p6steve/raku-Dan-Polars/blob/main/Dockerfile) FROM [(2)](https://github.com/p6steve/raku-Dockerfiles/blob/main/rusty-ma/Dockerfile)

* `docker run -it p6steve/raku-dan:polars`
* `cd ~/raku-Dan-Polars/bin` (this repo was cloned to load test\_data)
* `./synopsis-dan-polars.raku` or `./nutshell.raku`

(see bin/setup.raku for manual / development install steps)

*You are welcome to plunder the Dockerfiles for how to set up your own environment.*

---

### Nutshell

```
use Dan;
use Dan::Polars;

sub starwars {
    my \sw = DataFrame.new;
    sw.read_csv("test_data/dfStarwars.csv");
    sw
}

my $obj = starwars;
$obj .= select( [ <species mass height>>>.&col ] ) ;
$obj .= groupby([ <species> ]) ;
$obj .= sort( {$obj[$++]<species>, $obj[$++]<mass>} )[*].reverse^;

$obj.show;

shape: (87, 3)
┌────────────────┬──────┬────────┐
│ species        ┆ mass ┆ height │
│ ---            ┆ ---  ┆ ---    │
│ str            ┆ str  ┆ str    │
╞════════════════╪══════╪════════╡
│ Zabrak         ┆ NA   ┆ 171    │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┤
│ Zabrak         ┆ 80   ┆ 175    │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┤
│ Yoda's species ┆ 17   ┆ 66     │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┤
│ Xexto          ┆ NA   ┆ 122    │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┤
│ ...            ┆ ...  ┆ ...    │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┤
│ Chagrian       ┆ NA   ┆ 196    │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┤
│ Cerean         ┆ 82   ┆ 198    │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┤
│ Besalisk       ┆ 102  ┆ 198    │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┤
│ Aleena         ┆ 15   ┆ 79     │
└────────────────┴──────┴────────┘

#say ~$obj.Dan-DataFrame;       # coerce to a vanilla Dan::DataFrame (e.g. to say all rows)
#say ~$obj.to-dataset;          # or export to a dataset for ad hoc data munging

```

*datasets are used by raku [Data::...](https://raku.land/?q=Data%3A%3A) modules*

### Synopsis

Dan::Polars is a specialization of raku Dan. Checkout the [Dan synopsis](https://github.com/p6steve/raku-Dan/blob/main/README.md#synopsis) for base Series and DataFrame operations. The following covers the additional features that are specific to Dan::Polars.

* Each Dan::Polars object (Series or DataFrame) contains a pointer to its Rust Polars "shadow".
* Polars does not implement indexes, so any attempt to set a row index will be ignored.
* Dan::Polars only exposes the Polars lazy API and quietly calls `.lazy` and `.collect` as needed.

```
use Dan;
use Dan::Polars;

my \df = DataFrame.new;
df.read_csv("../dan/src/iris.csv");

# ---------------------------------------

my $se = df.column("sepal.length");
$se.head;

# a Series...
shape: (5,)
Series: 'sepal.length' [f64]
[
	5.1
	4.9
	4.7
	4.6
	5.0
]

# ---------------------------------------

df.select([col("sepal.length"), col("variety")]).head;

# a DataFrame...
shape: (5, 2)
┌──────────────┬─────────┐
│ sepal.length ┆ variety │
│ ---          ┆ ---     │
│ f64          ┆ str     │
╞══════════════╪═════════╡
│ 5.1          ┆ Setosa  │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤
│ 4.9          ┆ Setosa  │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤
│ 4.7          ┆ Setosa  │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤
│ 4.6          ┆ Setosa  │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤
│ 5.0          ┆ Setosa  │
└──────────────┴─────────┘

# ---------------------------------------

df.groupby(["variety"]).agg([col("petal.length").sum]).head;

# -- or --
my $expr;
$expr  = col("petal.length");
$expr .= sum;
df.groupby(["variety"]).agg([$expr]).head;

# An Expression takes the form Fn(Series --> Series) {} ...

# a DataFrame...
shape: (2, 2)
┌────────────┬──────────────┐
│ variety    ┆ petal.length │
│ ---        ┆ ---          │
│ str        ┆ f64          │
╞════════════╪══════════════╡
│ Versicolor ┆ 141.4        │
├╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
│ Setosa     ┆ 73.1         │
└────────────┴──────────────┘

# ---------------------------------------
# Here are some unary expressions; the ```.alias``` method can be used to rename cols...

my @exprs;
@exprs.push: col("petal.length").sum;
#@exprs.push: col("sepal.length").mean;
#@exprs.push: col("sepal.length").min;
#@exprs.push: col("sepal.length").max;
#@exprs.push: col("sepal.length").first;
#@exprs.push: col("sepal.length").last;
#@exprs.push: col("sepal.length").unique;
#@exprs.push: col("sepal.length").count;
#@exprs.push: col("sepal.length").forward_fill;
#@exprs.push: col("sepal.length").backward_fill;
@exprs.push: col("sepal.length").reverse;
@exprs.push: col("sepal.length").std.alias("std");
#@exprs.push: col("sepal.length").var;
df.groupby(["variety"]).agg(@exprs).head;

shape: (2, 4)
┌────────────┬──────────────┬─────────────────────┬──────────┐
│ variety    ┆ petal.length ┆ sepal.length        ┆ std      │
│ ---        ┆ ---          ┆ ---                 ┆ ---      │
│ str        ┆ f64          ┆ list[f64]           ┆ f64      │
╞════════════╪══════════════╪═════════════════════╪══════════╡
│ Versicolor ┆ 141.4        ┆ [5.8, 5.5, ... 7.0] ┆ 0.539255 │
├╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌┤
│ Setosa     ┆ 73.1         ┆ [5.0, 5.3, ... 5.1] ┆ 0.3524   │
└────────────┴──────────────┴─────────────────────┴──────────┘

# ---------------------------------------
# use col("*") to select all...

df.select([col("*").exclude(["sepal.width"])]).head;
df.select([col("*").sum]).head;

# ---------------------------------------
# Can do Expression math...

df.select([
    col("sepal.length"),
    col("petal.length"),
    (col("petal.length") + (col("sepal.length"))).alias("add"),
    (col("petal.length") - (col("sepal.length"))).alias("sub"),
    (col("petal.length") * (col("sepal.length"))).alias("mul"),
    (col("petal.length") / (col("sepal.length"))).alias("div"),
    (col("petal.length") % (col("sepal.length"))).alias("mod"),
    (col("petal.length") div (col("sepal.length"))).alias("floordiv"),
]).head;

shape: (5, 8)
┌──────────────┬──────────────┬─────┬──────┬──────┬──────────┬─────┬──────────┐
│ sepal.length ┆ petal.length ┆ add ┆ sub  ┆ mul  ┆ div      ┆ mod ┆ floordiv │
│ ---          ┆ ---          ┆ --- ┆ ---  ┆ ---  ┆ ---      ┆ --- ┆ ---      │
│ f64          ┆ f64          ┆ f64 ┆ f64  ┆ f64  ┆ f64      ┆ f64 ┆ f64      │
╞══════════════╪══════════════╪═════╪══════╪══════╪══════════╪═════╪══════════╡
│ 5.1          ┆ 1.4          ┆ 6.5 ┆ -3.7 ┆ 7.14 ┆ 0.2745   ┆ 1.4 ┆ 0.2745   │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌┤
│ 4.9          ┆ 1.4          ┆ 6.3 ┆ -3.5 ┆ 6.86 ┆ 0.285714 ┆ 1.4 ┆ 0.285714 │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌┤
│ 4.7          ┆ 1.3          ┆ 6.0 ┆ -3.4 ┆ 6.11 ┆ 0.276596 ┆ 1.3 ┆ 0.276596 │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌┤
│ 4.6          ┆ 1.5          ┆ 6.1 ┆ -3.1 ┆ 6.9  ┆ 0.326087 ┆ 1.5 ┆ 0.326087 │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌┤
│ 5.0          ┆ 1.4          ┆ 6.4 ┆ -3.6 ┆ 7.0  ┆ 0.28     ┆ 1.4 ┆ 0.28     │
└──────────────┴──────────────┴─────┴──────┴──────┴──────────┴─────┴──────────┘

# ---------------------------------------
# And use literals...

df.select([
    col("sepal.length"),
    col("petal.length"),
    (col("petal.length") + 7).alias("add7"),
    (7 - col("petal.length")).alias("sub7"),
    (col("petal.length") * 2.2).alias("mul"),
    (2.2 / (col("sepal.length"))).alias("div"),
    (col("sepal.length") % 2).alias("mod"),
    (col("sepal.length") div 0.1).alias("floordiv"),
]).head;

shape: (5, 8)
┌──────────────┬──────────────┬──────┬──────┬──────┬──────────┬─────┬──────────┐
│ sepal.length ┆ petal.length ┆ add7 ┆ sub7 ┆ mul  ┆ div      ┆ mod ┆ floordiv │
│ ---          ┆ ---          ┆ ---  ┆ ---  ┆ ---  ┆ ---      ┆ --- ┆ ---      │
│ f64          ┆ f64          ┆ f64  ┆ f64  ┆ f64  ┆ f64      ┆ f64 ┆ f64      │
╞══════════════╪══════════════╪══════╪══════╪══════╪══════════╪═════╪══════════╡
│ 5.1          ┆ 1.4          ┆ 8.4  ┆ 5.6  ┆ 3.08 ┆ 0.431373 ┆ 1.1 ┆ 51.0     │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌┤
│ 4.9          ┆ 1.4          ┆ 8.4  ┆ 5.6  ┆ 3.08 ┆ 0.4489   ┆ 0.9 ┆ 49.0     │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌┤
│ 4.7          ┆ 1.3          ┆ 8.3  ┆ 5.7  ┆ 2.86 ┆ 0.468085 ┆ 0.7 ┆ 47.0     │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌┤
│ 4.6          ┆ 1.5          ┆ 8.5  ┆ 5.5  ┆ 3.3  ┆ 0.478261 ┆ 0.6 ┆ 46.0     │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌┤
│ 5.0          ┆ 1.4          ┆ 8.4  ┆ 5.6  ┆ 3.08 ┆ 0.44     ┆ 1.0 ┆ 50.0     │
└──────────────┴──────────────┴──────┴──────┴──────┴──────────┴─────┴──────────┘

# ---------------------------------------
# There is a variant of with_column (for Series) and with_columns (for Expressions)

df.with_column($se.rename("newcol")).head;
df.with_columns([col("variety").alias("newnew")]).head;

```

Notes:

* Most methods such as queries on the Raku object are applied to the shadow and the data remains on the Rust side for performance reasons. Exceptions are accessors and map operations which require the data to be synched manually to the Raku side using the `.flood` method and, when done, to be sent back Rustwards with `.flush`. Sort & grep methods (in their current incarnations) also implicitly use .flood/.flush to sync.
* On reflection, the vanilla Dan splice & concat methods are not a good fit for Polars which has the simpler Series.append, DataFrame.vstack|.hstack and DataFrame.join methods. The new plan is to implement these Polars methods here (v0.2) and then to replace Dan and Dan::Pandas splice & concat with the Polars equivalent in the forthcoming As::Query role.
* To avoid synching for `say ~df` operations, the `.show` method applies Rust println! to STDOUT.
* For import and export, the `se.Dan-Series` and `df.Dan-DataFrame` methods will coerce to the raku-only Dan equivalent. You can go `Series.new(Dan::Series:D --> Dan::Polars::Series)` and `DataFrame.new(Dan::DataFrame:D --> Dan::Polars::DataFrame)`.
* The method `df.to-dataset` is provided to, err, make a dataset for various raku Data:: library compatibility

---

### Design Notes

1. lazy

Polars implements both lazy and eager APIs, these are functionally similar. For simplicity, Dan::Polars offers only the most efficient: lazy API. It has better query optimisation with low additional overhead.

1. auto-lazy

In Rust & Python Polars, lazy must be explicitly requested with `.lazy .. .collect` methods around expressions. In contrast, Dan::Polars auto-generates the `.lazy .. .collect` quietly for concise syntax.

1. pure

[Polars Expressions](https://pola-rs.github.io/polars-book/user-guide/dsl/intro.html) are a function mapping from a series to a series (or mathematically `Fn(Series) -> Series`). As expressions have a Series as an input and a Series as an output then it is straightforward to do a pipeline of expressions.

1. opaque

In general each raku object (Dan::Polars::Series, Dan::Polars::DataFrame) maintains a unique pointer to a rust container (SeriesC, DataFrameC) and they contain a shadow Rust Polars Struct. Methods invoked on the raku object are then proxied over to the Rust Polars shadow.

1. dynamic lib.so

A connection is made via Raku Nativecall to Rust FFI using a ```lib.so`` dymanic library or equivalent.

1. data transfer

Usually no data needs to be transferred from Raku to Rust (or vice versa). For example, a raku script can command a Rust Polars DataFrame to be read from a csv file, apply expressions and output the result. The data items all remain on the Rust side of the connection.

---

## TODOs

### v0.1

1. Dan API

   * Dan::Series base methods
   * Dan::DataFrame base methods
   * Dan Accessors
   * Dan sort & grep (s3)
2. Polars Structs / Modules

   * Polars::Series base methods
   * Polars::DataFrame base methods
   * .push/.pull (set-new/get-data)
   * better value return
3. Polars Exprs (s2)

   * unary exprs
   * operators
4. Documentation

   * synopsis
   * refactor /bin
5. Test

This will then provide a basis for ...

### v0.2

* Dan splice & concat (s1) as hstack, vstack, join
* drop col
* non-null, etc.

This will then provide a basis for design Dan::As::Query v0.1 for Dan and Dan::Pandas and review Dan API slice & concat, immutability, refactor...

### v0.3...

* datetime
* unique\_stable
* expr arity > 1
* 'over' expr
* clone (then retest h2o-par)
* immutability
* reset @data after load rc (also to Pandas)

### v0.4...

* strip / fold Index
* cross join (aka cross product)
* pivot / cross-tabluate
* map & apply (jit DSL style)
* apply over [multiple cols](https://stackoverflow.com/questions/72372821/how-to-apply-a-function-to-multiple-columns-of-a-polars-dataframe-in-rust)
* ternary if-then-else (Dan::As::Ternary)
* str operations (Dan::As::Str)
* chunked transfer
* serde

(c) Henley Cloud Consulting Ltd.


## dist_github-ramiroencinas-System-Stats-CPUsage.md
# System::Stats::CPUsage

[![Build Status](https://travis-ci.com/ramiroencinas/System-Stats-CPUsage.svg?branch=master)](https://travis-ci.com/github/ramiroencinas/System-Stats-CPUsage)

Raku module - Provides Statistics CPU Usage in percentage.

## OS Supported:

* GNU/Linux by /proc/stat
* Win32 by wmic

## Installing the module

```
zef update
zef install System::Stats::CPUsage

```

## Example Usage:

```
use v6;
use System::Stats::CPUsage;

say "CPUsage%: " ~ CPU_Percentage();

```


## dist_zef-skaji-CPAN-Uploader-Tiny.md
[![Actions Status](https://github.com/skaji/raku-CPAN-Uploader-Tiny/workflows/test/badge.svg)](https://github.com/skaji/raku-CPAN-Uploader-Tiny/actions)

# NAME

CPAN::Uploader::Tiny - Upload tarballs to CPAN

# SYNOPSIS

```
use CPAN::Uploader::Tiny;

my $uploader = CPAN::Uploader::Tiny.new-from-config($*HOME.add: '.pause');
$uploader.upload("Your-Raku-Module-0.0.1.tar.gz");

```

# DESCRIPTION

CPAN::Uploader::Tiny uploads tarballs to CPAN.

# SEE ALSO

<https://github.com/rjbs/CPAN-Uploader>

<https://github.com/Leont/cpan-upload-tiny>

# AUTHOR

Shoichi Kaji [skaji@cpan.org](mailto:skaji@cpan.org)

# COPYRIGHT AND LICENSE

Copyright 2017 Shoichi Kaji

This library is free software; you can redistribute it and/or modify it under the Artistic License 2.0.


## dist_github-whity-Hematite.md
# Hematite

[![test](https://github.com/whity/raku-hematite/actions/workflows/test.yml/badge.svg)](https://github.com/whity/raku-hematite/actions/workflows/test.yml)

## Usage

```
# psgi file
use Hematite;

my $app = Hematite.new;

# middleware
$app.use(sub ($ctx, $next) {
    # some processing...

    # call next
    $next($ctx);

    # some processing...
});

class TestMiddleware does Callable {
    method CALL-ME($ctx, $next) {
        $next($ctx);
    }
}

$app.use(TestMiddleware.new);

# routes (can define any http method)
$app.GET('/', sub ($ctx) { $ctx.render({'route' => '/'}, 'type' => 'json'); });
#$app.POST('/', sub ($ctx) { $ctx.render({'route' => '/'}, 'type' => 'json'); });
#$app.METHOD('get', '/', sub ($ctx) { $ctx.render({'route' => '/'}, 'type' => 'json'); });

# route with middleware
$app.GET(
    '/with-middleware',
    [sub ($ctx, $next) { say 'route middleware'; $next($ctx); }],
    sub ($ctx) { $ctx.render({'route' => '/with-middleware'}, 'type' => 'json'); }
);

# route with placeholders/captures
$app.GET(
    '/captures/:c1',
    sub {
        say({
            'captures' => $ctx.captures,
            'named-captures' => $ctx.named-captures
        });
    }
);

# route rendering json
$app.GET(
    '/json',
    sub ($ctx) {
        $ctx.render-json(
            {'hello' => 'world'},
        );
    }
);

# route rendering template
$app.GET(
    '/template',
    sub ($ctx) {
        $ctx.render(
            'hello',
            data => { name => 'world', }
        );
    }
);

# route rendering inline template/string
$app.GET(
    '/template-inline',
    sub ($ctx) {
        $ctx.render(
            'hello {{ name }}',
            inline => True,
            data => { name => 'world', }
        );
    }
);

# groups
my $group = $app.group('/group');
$group.GET('/', sub ($ctx) { $ctx.render({'group' => 1}); });

$app;

```

### start crust

```
crustup [psgi file]

```

### using a more OO approach

```

class ExampleMiddleware does Hematite::Middleware {
    method CALL-ME {
        say 'example-middleware';
        return self.next;
    }
}

class ExampleAction does Hematite::Action {
    method middleware {
        return [
            ExampleMiddleware.create,
        ];
    }

    method CALL-ME {
        return self.render('example action', inline => True);
    }
}

class App is Hematite::App {
    method startup {
        self.use(ExampleMiddleware.create);

        self.GET('/', ExampleAction.create);
        self.POST('/', 'ExampleAction');
    }
}

```

### context helpers

```
class Middleware does Hematite::Middleware {
    method CALL-ME {
        self.add-helper('xpty', sub ($ctx) {
            # do something...
        });

        self.next;

        self.remove-helper('xpty');
    }
}

my $app = Hematite::App.new;

# register global context helper
$app.context-helper('xpto', sub ($ctx) { say 'helper...'; });

# register context helpers, directly in the context
$app.use(sub ($ctx, $next) {
    $ctx.add-helper('xptz', sub ($ctx) {
        # do something...
    });

    $next($ctx);

    $ctx.remove-helper('xptz');
});

$app.use(Middleware.create);

# just call the helper from the context
$app.GET('/', sub ($ctx) {
    $ctx.xpto;
    $ctx.xptz;
    $ctx.xpty;
});

```

### websockets

```

my $app = Hematite::App.new;

$app.WS('/websocket', sub ($ctx) {
    $ctx.on('ready', sub {
        $ctx.log.info('websocket ready');

        for 1..10 -> $idx {
            $ctx.send('message', "ping {$idx}");
        }

        $ctx.send('close');
    });

    $ctx.on('message', sub ($text) {
        $ctx.log.info('received: ' ~ $text);
    });

    $ctx.on('close', sub {
        $ctx.log.info('websocket closed');
    });
});

# OR

class WSAction does Hematite::Action {
    method CALL-ME {
        self.on('ready', sub {
            self.log.info('websocket ready');

            for 1..10 -> $idx {
                self.send('message', "ping {$idx}");
            }

            self.send('close');
        });

        self.on('message', sub ($text) {
            self.log.info('received: ' ~ $text);
        });

        self.on('close', sub {
            self.log.info('websocket closed');
        });
    }
}

$app.WS('/websocket2', WSAction);

```

## TODO

* better doc
* unit tests
* ...

## Contributing

1. Fork it ( [https://github.com/[your-github-name]/raku-hematite/fork](https://github.com/%5Byour-github-name%5D/raku-hematite/fork) )
2. Create your feature branch (git checkout -b my-new-feature)
3. Commit your changes (git commit -am 'Add some feature')
4. Push to the branch (git push origin my-new-feature)
5. Create a new Pull Request

## Contributors

* whity(<https://github.com/whity>) André Brás - creator, maintainer


## dist_zef-lizmat-IRC-Log-Colabti.md
[![Actions Status](https://github.com/lizmat/IRC-Log-Colabti/actions/workflows/linux.yml/badge.svg)](https://github.com/lizmat/IRC-Log-Colabti/actions) [![Actions Status](https://github.com/lizmat/IRC-Log-Colabti/actions/workflows/macos.yml/badge.svg)](https://github.com/lizmat/IRC-Log-Colabti/actions) [![Actions Status](https://github.com/lizmat/IRC-Log-Colabti/actions/workflows/windows.yml/badge.svg)](https://github.com/lizmat/IRC-Log-Colabti/actions)

# NAME

IRC::Log::Colabti - interface to IRC logs from colabti.org

# SYNOPSIS

```
use IRC::Log::Colabti;

my $log = IRC::Log::Colabti.new($filename.IO);

say "Logs from $log.date()";
.say for $log.entries.List;

my $log = IRC::Log::Colabti.new($text, $date);

```

# DESCRIPTION

IRC::Log::Colabti provides an interface to the IRC logs that are available from colabti.org (raw format). Please see IRC::Log for more information.

# ADDITIONAL METHODS

## merge

```
my $merged = $log.merge($channel);    # merge with Colabti archive of same date

my $merged = $log.merge($slurped);    # merge with another log file of same date

my $merged = $log.merge($other-log);  # merge with log object

my $merged = $log.merge($path.IO);    # merge with log file by IO::Path

```

The `merge` instance method attempts to add entries from another log of the same date that are not present in the entries of the instance. This functionality is intended to fix "holes" in the logs caused by temporary outages of the various loggers.

It takes a single positional argument, which can either be:

* the name of a channel: fetches content from Colabti's website
* a string with the contents of a log file
* another IRC::Log object
* an IO::Path object of the log file to merge with

It either returns `Nil` if no missing entries were found, or a freshly created object of the same type as the invocant.

When merging with Colabti's channel logs, it is possible to specify a `:normalizer` argument to indicate code to normalize the logs obtained from Colabti. By default, this will be the same normalization as used by the `IRC::Client::Plugin::Logger` module.

# AUTHOR

Elizabeth Mattijsen [liz@raku.rocks](mailto:liz@raku.rocks)

Source can be located at: <https://github.com/lizmat/IRC-Log-Colabti> . Comments and Pull Requests are welcome.

If you like this module, or what I'm doing more generally, committing to a [small sponsorship](https://github.com/sponsors/lizmat/) would mean a great deal to me!

# COPYRIGHT AND LICENSE

Copyright 2021, 2022, 2025 Elizabeth Mattijsen

This library is free software; you can redistribute it and/or modify it under the Artistic License 2.0.


## dist_zef-coke-Lingua-EN-Syllable.md
# raku-lingua-en-syllable

Port of perl5 module of same name [1]

This module guesses at the number of syllables in an English word.

[1] <http://search.cpan.org/~gregfast/Lingua-EN-Syllable-0.251/Syllable.pm>
original by Greg Fast


## dist_cpan-ANTONOV-Chemistry-Stoichiometry.md
# Raku Chemistry::Stoichiometry

[![Build Status](https://travis-ci.com/antononcube/Raku-Chemistry-Stoichiometry.svg?branch=main)](https://travis-ci.com/antononcube/Raku-Chemistry-Stoichiometry)

## Introduction

Raku package for Stoichiometry procedures and related data. The primary functionalities are:

* Calculation of molecular masses for chemical compound formulas
* Chemical equations balancing

Here are corresponding examples:

```
use Chemistry::Stoichiometry;

say molecular-mass('SO2');
# 64.058

say balance-chemical-equation('C2H5OH + O2 = H2O + CO2');
# [1*C2H5OH + 3*O2 -> 2*CO2 + 3*H2O]

```

The package has also functions for chemical element data retrieval
and functions that convert between chemical names, symbols/abbreviations, and atomic numbers.

Here are a couple of examples:

```
say atomic-number('actinium');
# 89

say chemical-symbol('ガリウム');
# Ga

```

**Remark:** Multiple languages can be used for the names of the chemical elements.
The corresponding functions automatically detect the language.

**Remark:** At this point the package has standard element names in the languages:
Bulgarian, German, Greek, English, Japanese, Persian, Polish, Russian, and Spanish.
Adding new languages is easily achieved by adding CSV files into the
[resources](./resources) directory.

### Related work

The package
[Chemistry::Elements](https://github.com/briandfoy/perl6-chemistry-elements)
developed by Brian D. Foy, [BF1], also has functions that convert
between chemical names, symbols/abbreviations, and atomic numbers.
(Several languages are supported.)

Mathematica / Wolfram Language (WL) has the function
[`ElementData`](https://reference.wolfram.com/language/ref/ElementData.html), [WRI1].

In 2007 I wrote the original versions of the chemical equation balancing and
molecular functionalities in
[WolframAlpha](https://www.wolframalpha.com).
See for example
[this output](https://www.wolframalpha.com/input/?i=C2H5OH+%2B+O2+%3D+H2O+%2B+CO2).

---

## Installation

To install the package in Raku with [zef installer](https://github.com/ugexe/zef):

```
zef install https://github.com/antononcube/Raku-Chemistry-Stoichiometry.git

```

---

## Element data retrieval

### Element data records

Element data of one or several elements can be obtained with the function `chemical-element-data`:

```
use Chemistry::Stoichiometry;
say chemical-element-data('Cl');
# {Abbreviation => Cl, AtomicNumber => 17, AtomicWeight => 35.45, Block => p, Group => 17, Name => chlorine, Period => 3, Series => Halogen, StandardName => Chlorine}

say chemical-element-data(['H', 'Li', 'Na', 'K', 'Rb', 'Cs', 'Fr']);
# ({Abbreviation => H, AtomicNumber => 1, AtomicWeight => 1.008, Block => s, Group => 1, Name => hydrogen, Period => 1, Series => Nonmetal, StandardName => Hydrogen} {Abbreviation => Li, AtomicNumber => 3, AtomicWeight => 6.94, Block => s, Group => 1, Name => lithium, Period => 2, Series => AlkaliMetal, StandardName => Lithium} {Abbreviation => Na, AtomicNumber => 11, AtomicWeight => 22.98976928, Block => s, Group => 1, Name => sodium, Period => 3, Series => AlkaliMetal, StandardName => Sodium} {Abbreviation => K, AtomicNumber => 19, AtomicWeight => 39.0983, Block => s, Group => 1, Name => potassium, Period => 4, Series => AlkaliMetal, StandardName => Potassium} {Abbreviation => Rb, AtomicNumber => 37, AtomicWeight => 85.4678, Block => s, Group => 1, Name => rubidium, Period => 5, Series => AlkaliMetal, StandardName => Rubidium} {Abbreviation => Cs, AtomicNumber => 55, AtomicWeight => 132.90545196, Block => s, Group => 1, Name => cesium, Period => 6, Series => AlkaliMetal, StandardName => Cesium} {Abbreviation => Fr, AtomicNumber => 87, AtomicWeight => 223.0, Block => s, Group => 1, Name => francium, Period => 7, Series => AlkaliMetal, StandardName => Francium})

```

### Element names

```
say chemical-element('Cl');
# Chlorine

say chemical-element('Cl', 'Russian');
# Хлор

```

Chemical element names can be obtained using the function `chemical-element-data` with the adverbs
`:name` or `:standard-name`:

```
say chemical-element-data('Cl'):name;
# Chlorine

say chemical-element-data('Cl'):standard-name;
# Chlorine

```

### Element symbols / abbreviations

```
say chemical-symbol('oxygen');   # 'O' from English
# O

say chemical-symbol('кислород'); # 'O' from Bulgarian
# O

```

Chemical element abbreviations can be obtained using the function `chemical-element-data` with the adverbs
`:symbol` or `:abbr`:

```
say chemical-element-data('oxygen'):symbol;         # 'O' from English
# O

say chemical-element-data('кислород'):abbr;         # 'O' from Bulgarian
# O

```

Note, that `chemical-element` will automatically detect the language.

### Atomic numbers

```
say atomic-number('Cl');
# 17

say atomic-number('actinium');  # from the English name of Ac
# 89

say atomic-number('берилий');   # from the Bulgarian name of Be
# 4

```

Alternatively, `chemical-element-data` can be used with the adverbs `:number` or `:atomic-number`:

```
say chemical-element-data('Cl'):number;
# 17

say chemical-element-data('Cl'):atomic-number;
# 17

```

### Atomic weights

```
say atomic-weight('Se');
# 78.971

say atomic-weight('ガリウム');  # from the Japanese name of Ga
# 69.723

```

Alternatively, `chemical-element-data` can be used with the adverbs `:weight` or `:atomic-weight`:

```
say chemical-element-data('Cl'):weight;
# 35.45

say chemical-element-data('Cl'):atomic-weight;
# 35.45

```

---

## Stoichiometry procedures

The functions `molecular-mass` and `balance-chemical-equation` are based on a parser
for
[Simplified Molecular-Input Line-Entry System (SMILES)](https://en.wikipedia.org/wiki/Simplified_molecular-input_line-entry_system),
[OS1].

### Molecular mass

Molecular mass for a compound:

```
say molecular-mass('SO2');
# 64.058

```

Molecular masses of the sides of a chemical equation:

```
say molecular-mass('C2H5OH + O2 -> H2O + CO2');
# 78.06700000000001 => 62.024

```

Note that the masses in the output above are different because the equation is not balanced.

### Equation balancing

For a given chemical equation the function `balance-chemical-equation` returns a list of balanced equations.

```
say balance-chemical-equation('C2H5OH + O2 = H2O + CO2');
# [1*C2H5OH + 3*O2 -> 2*CO2 + 3*H2O]

say balance-chemical-equation( 'K4Fe(CN)6 + H2SO4 + H2O = K2SO4 + FeSO4 + (NH4)2SO4 + CO' );
# [6*H2O + 6*H2SO4 + 1*K4Fe(CN)6 -> 3*(NH4)2SO4 + 6*CO + 1*FeSO4 + 2*K2SO4]

```

**Remark:** The result of the balancing is a list because certain chemical equations
can be balanced in several ways corresponding to different reactions.

---

## TODO

In order of importance, most important are first:

1. Extensive tests:

   * Chemical data retrieval
   * Chemical compound formulae parser
   * Molecular mass calculation
   * Chemical equation balancing
2. Chemical element names translation function.
   (Say, from Bulgarian to Persian.)
3. Inverse look-up from atomic weight to chemical element(s).
4. Extensive documentation.
5. Handling of semicolon separated input.

   * For the data functions. E.g. `atomic-weight('Cl; O; Mn')`.
   * For the parser-interpreter functions. E.g. `molecular-mass('FeSO4; H2O; CO2')`.
6. Parsing of (pre-)balanced chemical equations.
7. Recognition of chemical compound names.

   * This requires the development of a separate chemical entities package.
8. Element data in more languages.

---

## References

[BF1] Brian D. Foy,
[Chemistry::Elements Raku package](https://github.com/briandfoy/perl6-chemistry-elements),
(2016-2018),
[GitHub/briandfoy](https://github.com/briandfoy).

[CJ1] Craig A. James,
[OpenSMILES specification](http://opensmiles.org/opensmiles.html),
(2007-2016),
[OpenSMILES.org](http://opensmiles.org).

[WRI1] Wolfram Research,
[ElementData, Wolfram Language function](https://reference.wolfram.com/language/ref/ElementData.html),
(2007), (updated 2014),
[Wolfram Language System Documentation Center](https://reference.wolfram.com).


## dist_github-avuserow-Compress-Snappy.md
# NAME

Compress::Snappy - (de)compress data in Google's Snappy compression format

# INSTALLATION

`libsnappy-dev` or equivalent needs to be installed for this to
work. Issue

```
sudo apt-get install libsnappy-dev

```

or equivalent order in other operatins systems or distros to do so.

# SYNOPSIS

```
my Buf $compressed = Compress::Snappy::compress("hello, world");
my Bool $valid = Compress::Snappy::validate($compressed);
my Buf $decompressed = Compress::Snappy::decompress($compressed);

```

See also examples/test.p6

# DESCRIPTION

This module uses NativeCall to provide bindings to the C API for libsnappy, a
compression library with an emphasis on speed over compression.

# FUNCTIONS

## Compress::Snappy::compress(Blob $uncompressed) returns Buf

Main compression function. Returns a Buf of compressed data.

## Compress::Snappy::compress(Str $uncompressed, Str $encoding = 'utf-8') returns Buf

Convenience function to make a Str to an encoded Blob and compress that.
Encoding defaults to utf-8 if not specified.

## Compress::Snappy::decompress(Blob $compressed, Str $encoding)

Decompress provided data to a Buf. If an optional $encoding is
specified, will decode the Buf and return a Str instead.

## Compress::Snappy::validate(Blob $compressed) returns Bool

Returns if the compressed data is valid, without fully decompressing it.

# SEE ALSO

[Snappy on Google Code](https://code.google.com/p/snappy/)

[Snappy on GitHub](https://github.com/google/snappy)


## compiler.md
compiler

Combined from primary sources listed below.

# [In Raku](#___top "go to top of document")[§](#(Raku)_method_compiler "direct link")

See primary documentation
[in context](/type/Raku#method_compiler)
for **method compiler**.

Instance method returning the [compiler](/routine/compiler) object, of type [`Compiler`](/type/Compiler), associated with the Raku object.


## dist_github-azawawi-Selenium-WebDriver.md
## Selenium::WebDriver

[![Actions
Status](https://github.com/azawawi/raku-selenium-webdriver/workflows/test/badge.svg)](https://github.com/azawawi/raku-selenium-webdriver/actions)

This module provides the [Raku](http://raku.org) bindings for the [Selenium WebDriver Wire Protocol](https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol).

***Note:*** This module is a work in progress. Please see its project status [here](https://github.com/azawawi/perl6-selenium-webdriver/blob/master/README.md#project-status).

## Example

```
use v6;
use Selenium::WebDriver::PhantomJS;

my $driver = Selenium::WebDriver::PhantomJS.new;
$driver.url("http://google.com");
say "Title: "         ~ $driver.title;
say "URL: "           ~ $driver.url;
say "Source length: " ~ $driver.source.chars;
$driver.save-screenshot('test.png');
LEAVE {
  $driver.quit if $driver.defined
};

```

For more examples, please see the <examples> folder.

## PhantomJS Installation

### Linux/Debian

To install phantomjs on Debian, please type the following:

```
$ sudo apt-get install phantomjs

```

**CAUTION**: Also there are [prebuilt binaries](https://bitbucket.org/ariya/phantomjs/downloads) for PhantomJS for Linux if the packaged version is a bit old.

### Mac OS X

To install PhantomJS on Mac OS X, the simplest solution is to use brew:

```
$ brew update
$ brew install phantomjs

```

### Windows

To install PhantomJS on windows, please download a copy from
[Here](http://phantomjs.org/) and then make it available in your PATH environment
variable.

### Travis CI

Travis CI comes with [pre-installed PhantomJS](http://docs.travis-ci.com/user/gui-and-headless-browsers/#Using-PhantomJS).
No special instructions are needed.

## Project Status

| Web Driver | Status |
| --- | --- |
| PhantomJS | **DONE** but needs more tests |
| Firefox | **DONE** |
| Chrome | **DONE** but needs external [chromedriver](https://sites.google.com/a/chromium.org/chromedriver/) |
| Safari | Pending |
| Opera | Pending |
| MSIE | Pending |
| MSEdge | Pending |
| BlackBerry | **DONE** |

## Installation

To install it using zef (a module management tool bundled with Rakudo Star):

```
$ zef install Selenium::WebDriver

```

## Testing

* To run tests:

```
$ prove --ext .rakutest -ve "raku -I."

```

* To run all tests including author tests (Please make sure
  [Test::Meta](https://github.com/jonathanstowe/Test-META) is installed):

```
$ zef install Test::META
$ TEST_AUTHOR=1 prove --ext .rakutest -ve "raku -I."

```

## Author

Ahmad M. Zawawi, [azawawi](https://github.com/azawawi/) on #raku

## License

MIT License


## encoding.md
encoding

Combined from primary sources listed below.

# [In IO::Handle](#___top "go to top of document")[§](#(IO::Handle)_method_encoding "direct link")

See primary documentation
[in context](/type/IO/Handle#method_encoding)
for **method encoding**.

```raku
multi method encoding(IO::Handle:D: --> Str:D)
multi method encoding(IO::Handle:D: $enc --> Str:D)
```

Returns a [`Str`](/type/Str) representing the encoding currently used by the handle, defaulting to `"utf8"`. [`Nil`](/type/Nil) indicates the filehandle is currently in binary mode. Specifying an optional positional `$enc` argument switches the encoding used by the handle; specify [`Nil`](/type/Nil) as encoding to put the handle into binary mode.

The accepted values for encoding are case-insensitive. The available encodings vary by implementation and backend. On Rakudo MoarVM the following are supported:

｢text｣ without highlighting

```

```

utf8
utf16
utf16le
utf16be
utf8-c8
iso-8859-1
windows-1251
windows-1252
windows-932
ascii

```

```

The default encoding is utf8, which undergoes normalization into Unicode [`NFC`](/type/NFC) (normalization form canonical). In some cases you may want to ensure no normalization is done; for this you can use `utf8-c8`. Before using `utf8-c8` please read [Unicode: Filehandles and I/O](/language/unicode#Filehandles_and_I/O) for more information on `utf8-c8` and [`NFC`](/type/NFC).

As of Rakudo 2018.04 [windows-932](https://en.wikipedia.org/wiki/Code_page_932_(Microsoft_Windows)) is also supported which is a variant of ShiftJIS.

Implementation may choose to also provide support for aliases, e.g. Rakudo allows aliases `latin-1` for `iso-8859-1` encoding and dashed utf versions: `utf-8` and `utf-16`.

# [In IO::CatHandle](#___top "go to top of document")[§](#(IO::CatHandle)_method_encoding "direct link")

See primary documentation
[in context](/type/IO/CatHandle#method_encoding)
for **method encoding**.

```raku
multi method encoding(IO::CatHandle:D:)
multi method encoding(IO::CatHandle:D: $new-encoding)
```

Sets the invocant's `$.encoding` attribute to the provided value. Valid values are the same as those accepted by [`IO::Handle.encoding`](/type/IO/Handle#method_encoding) (use value [`Nil`](/type/Nil) to switch to binary mode). All source handles, including the active one will use the provided `$.encoding` value.

```raku
(my $f1 = 'foo'.IO).spurt: 'I ♥ Raku';
(my $f2 = 'bar'.IO).spurt: 'meow';
with IO::CatHandle.new: $f1, $f2 {
    # .encoding is 'utf8' by default:
    .readchars(5).say; # OUTPUT: «I ♥ R␤»

    .encoding: Nil; # switch to binary mode
    .slurp.say; # OUTPUT: «Buf[uint8]:0x<6B 75 6D 65 6F 77>␤»
}

```


## dist_github-ugexe-Base64.md
## Base64

Lazy base64 encoding and decoding routines

## Synopsis

```
use Base64;

# ENCODING

> say encode-base64("g-g-g-g-g unit", :str);
Zy1nLWctZy1nIHVuaXQ=

> say encode-base64("g-g-g-g-g unit").raku;
("Z", "y", "1", "n", "L", "W", "c", "t", "Z", "y", "1", "n", "I", "H", "V", "u", "a", "X", "Q", "=").Seq

> .print for lazy encode-base64("g-g-g-g-g unit")
Zy1nLWctZy1nIHVuaXQ=

# DECODING

> say decode-base64("Zy1nLWctZy1nIHVuaXQ=", :bin).decode
g-g-g-g-g unit

> say decode-base64("Zy1nLWctZy1nIHVuaXQ=", :bin)
Buf:0x<67 2d 67 2d 67 2d 67 2d 67 20 75 6e 69 74>

> say decode-base64("Zy1nLWctZy1nIHVuaXQ=").raku
(103, 45, 103, 45, 103, 45, 103, 45, 103, 32, 117, 110, 105, 116).Seq

```

## Exports

#### encode-base64($encode-me where Blob|Str, :$pad where Bool:D|Str:D, Str:D :@alpha, Bool:D :$str --> Seq|Str)

```
encode-base64($encode-me)                  # Returns a base64 encoded string
encode-base64($encode-me, :str)            # Stringify and return the sequence that would be returned
encode-base64($encode-me, :!pad)           # No padding
encode-base64($encode-me, :pad("*"))       # Alternative padding character
encode-base64($encode-me, :uri)            # Use '-' and '_' for chars 63 and 64
encode-base64($encode-me, :alpha(1..64))   # Set the entire alphabet

```

Takes a `Blob` and applies base64 encoding with the requested options. If passed a `Str` it will be converted to a `Blob` via `.ords` first.

```
> say encode-base64("test", :str)
dGVzdA==

> say encode-base64(Buf.new("test".ords), :str)
dGVzdA==

> say encode-base64("test").raku'
("d", "G", "V", "z", "d", "A", "=", "=").Seq

```

#### decode-base64($decode-me where Blob:D|Str:D, Str:D :@alpha, Bool:D :$bin, Bool:D :$uri --> Seq|Buf)

```
decode-base64($decode-me)                  # Decodes a base64 encoded string to a Buf for further decoding
decode-base64($encode-me, :bin)            # Return a buffer from the sequence that would be returned
decode-base64($decode-me, :uri)            # Use '-' and '_' for chars 63 and 64
decode-base64($decode-me, :alpha(1..64))   # Set the entire alphabet

```

Takes a `Str` and applies base64 decoding with the requested options. If passed a `Blob` it will be converted to a `Str` with `.decode` first.

```
> say decode-base64("YW55IGNhcm5hbCBwbGVhc3VyZS4=", :bin).decode
any carnal pleasure.

> say Buf.new(decode-base64("YW55IGNhcm5hbCBwbGVhc3VyZS4=")).decode('utf-8')
any carnal pleasure.

> say decode-base64("YW55IGNhcm5hbCBwbGVhc3VyZS4=").raku
(97, 110, 121, 32, 99, 97, 114, 110, 97, 108, 32, 112, 108, 101, 97, 115, 117, 114, 101, 46).Seq

```


## dist_zef-jnthn-ECMA262Regex.md
### ECMA262Regex Build Status

This module allows you parsing ECMA262 regex notation and use it in Perl 6.

### SYNOPSIS

```
use v6;
use ECMA262Regex;

say ECMA262Regex.validate('\e'); # False;
say ECMA262Regex.validate('^fo+\n'); # True

# Translate regex into Perl 6 one (string form)
say ECMA262Regex.as-perl6('^fo+\n'); # '^fo+\n'
say ECMA262Regex.as-perl6('[^ab-d]'); # '<-[ab..d]>'

# Compile textual ECMA262 regex into Perl 6 Regex object
my $regex = ECMA262Regex.compile('^fo+\n');

say "foo\n"  ~~ $regex; # Success
say " foo\n" ~~ $regex; # Failure

```


## dist_github-marcoonroad-Coro-Simple.md
# Coro-Simple

[![Build Status](https://travis-ci.org/marcoonroad/Coro-Simple.svg?branch=master)](https://travis-ci.org/marcoonroad/Coro-Simple)

Simple coroutines for Perl 6, inspired by the Lua's coroutines.

This is a module for *stackful asymmetric coroutines*, which suspend
their control flows with **yield** instead of shift the flow to another
coroutine with **transfer** (these are called *symmetric coroutines*).

If you want to know more about coroutines, I suggest you to read this
nice paper: <http://www.inf.puc-rio.br/~roberto/docs/MCC15-04.pdf> ...

### Features and Issues

The **coro** / **yield** functions from this module are implemented using
the **gather** / **take** built-in P6's functions, which has some
interesting features:

* *It has a dynamic scope:* it doesn't care about how many calls down are needed
  to find a **take**.
* *Is a list generator:* useful for list processing with filters and transformers.
* *And also lazy:* delaying the evaluation until you really need the result.

Some p6 programmers argue that the **gather** / **take** itself is like a
coroutine. In fact, the *lazy property* of **gather** / **take** fulfills very well the definitions of Marlin’s doctoral thesis:

> the values of data local to a coroutine persist between successive calls;

And:

> the execution of a coroutine is suspended as control leaves it, only
> to carry on where it left off when control re-enters the coroutine at
> some later stage.

Based on the brief discussion above, the **coro** / **yield** also has some
features:

* The coroutine doesn't care about how many calls down are needed to find a **yield**,
  even inside many other nested function stacks.
* The **yield** generates only one value per cycle, but you can yield an
  anonymous list to avoid it.

But there are some issues too:

* I advise you to not use **gather** / **take** inside any coroutine, even I
  don't know what will happen.
* It doesn't generate the last values with **return** (as is the case of Lua),
  so you must use **yield** again.

You can also yield "nothing" using the **suspend** function (and with none
argument, just for a temporary shift of control). Don't worry about,
it will return internally the **True** value (as a status that the coroutine is alive).

### Description

##### Coroutine: Declaration

So, let's go see some examples.

First and foremost, you declare a coroutine with:

```
coro { ... }; # zero-arity coroutine

```

Or with:

```
coro -> $param1, $param2, $param3 { ... }; # 3-arity coroutine

```

Or even with:

```
coro -> @params {
    for @params -> $param { do-some-thing-with ($param) }
}
# variadic arguments through an array

```

##### Coroutine: Constructor

The **coro** keyword above gives back a constructor, and you may think *"but why it returns a constructor?"*...
Well, for two main reasons:

* *For code reuse:* you can use the coroutine on different places, without declare / return
  again it every time.
* *Recovering to a initial state:* when the coroutine dies, you can just reassign it to the generator.

With Lua, if you want to reuse a coroutine, you will need explicitly return a coroutine that will
reuse the given arguments as a closure:

```
function iter (xs)
  return coroutine.wrap (function ( )
    for _, x in ipairs (xs) do
      coroutine.yield (x)
    end
  end)
end

```

So, I decided implement a different approach...

Some example (an iterator function):

```
my &iter = coro -> $xs {
    for @$xs -> $x { yield $x }
}

```

The **iter** function above will receive an anonymous list and then give back a *generator*
function... generator? Well-minded, now we will see generators.

##### Coroutine: Generator

Note: here, the generator definition is just for a function that returns the next value (every
time that it's called), not as is usually called an *asymmetric coroutine without dedicated stacks*
(which cares about if you will call **yield** out of its block / lexical scope).

Reusing the **iter** example:

```
my $generator = iter [ 1 ... 3 ];

say $generator( ); # >>> 1
say $generator( ); # >>> 2
say $generator( ); # >>> 3
say $generator( ); # >>> False, here, the coroutine is dead.
# Use "$generator = iter [ 1, 2, 3 ];" again if you want...

```

##### Coroutine: More complex examples

Following the "coroutines generalize functions" idea (a function may be thought as a coroutine without any *yield* keywords), we can write **map** / **grep** / **range** functions like coroutines / generators!

```
# map coroutine
my &transform = coro -> &fn, $xs {
    for @$xs -> $x { yield fn($x) }
}

# grep coroutine
my &filter = coro -> &pred, $xs {
    for @$xs -> $x {
        yield $x if pred($x);
    }
}

# range-like coroutine
my &xrange = coro -> $min, $max {
    for ($min ...^ $max) -> $value {
        yield $value;
    }
}

# Usage:
#
# sub incr ($x) { $x + 1 }      # >>> number.
# sub even ($x) { $x % 2 == 0 } # >>> boolean. use "$x %% 2" if you wish a short version
#
# my $generator = ([ @array ] ==> transform &incr);
# my $filtered  = ([ @array ] ==> filter &even);
# my $get-next  = xrange ($x, $y);
#
# :)

```

##### Coroutine: "casting" generator to a lazy list

Thinking in access the values that a generator yields in a nice way? No problem, there's **from** to solve that.
The **from** function does the opposite from **iter** above: rather than taking an array and
mapping it to a generator, it takes a reference to a generator and returns a lazy array to bind.

Some examples:

```
my @lazy-array := from $some-generator;

```

Or, too:

```
my @lazy-array := from some-constructor ($x, $y, $z);

```

Build more complex things with it isn't hard entirely, for instance: "pipelines" running on demand, without
evaluate the whole thing at all (because **map** and **grep** are lazy as well :) ...):

```
my @lazy-array-1 := (from some-constructor($arg1, $arg2, ...)).map: * + 1;

my @lazy-array-2 := (from (coro { ... })(...)).grep: * %% 2;

```

##### Coroutine: Verifying

There's also a function called **ensure** in this module (the other function, called 'assert',
now is deprecated... 'ensure' is the new name for this functionality). Its main purpose is to check a
value, so:

* If given value isn't False, return it.
* Otherwise, runs given block (other argument).

Let's see a small example below:

```
$some-value = $some-generator( );

($some-value ==> ensure {
    warn "Sorry, but your coroutine is dead."
}) ==> say;
# prints $some-value or generates a warning if is false

$some-value = ensure ({ $some-generator = some-constructor( ) }, $some-generator( ));
# reassign to the generator if $some-generator returns False or returns a value

```

##### Coroutine: Implementing symmetric coroutines

The support to a **transfer** function is still experimental. Check the 't/transfer.t' test if
you wish to know more about. There's also a test about tasks...

##### Notes

Pull requests are welcome.

**Happy Hacking using this module!** :)

### Tips and Tricks

Normally, it is possible to build a *enumerator* / *generator* as this case below ('cause **gather** / **take**
has a dynamic scope):

```
# receives many arguments (e.g flattened array) and yields each one
my &iter = coro sub (*@xs) { @xs ==> map &yield }

```

And some short version (which receives an anonymous list) with:

```
my &iter = coro { @$^xs.map: &yield }

```

### TODO

* Insert more examples here (i.e, show the code).
* Document the module with **Perl 6's Pods**.
* Fix the module for the **coro** function accept lazy-lists / streams (infinite-length lists)
  as argument.

EOF


## dist_zef-japhb-TinyFloats.md
[![Actions Status](https://github.com/japhb/TinyFloats/workflows/test/badge.svg)](https://github.com/japhb/TinyFloats/actions)

# NAME

TinyFloats - Convert to/from tiny float formats

# SYNOPSIS

```
use TinyFloats;

my $tf32  = tf32-from-num(1e0);      # 0x5F800
my $num1  = num-from-tf32(0x7FBFF);  # -3.4011621342146535e+38

my $bf16  = bf16-from-num(1e0);      # 0x3F80
my $num2  = num-from-bf16(0xFF7F);   # -3.3895313892515355e+38

my $bin16 = bin16-from-num(1e0);     # 0x3C00
my $num3  = num-from-bin16(0xFBFF);  # -65504e0

my $e5m2  = e5m2-from-num(1e0);      # 0x3C
my $num4  = num-from-e5m2(0xFB);     # -57344e0

```

# DESCRIPTION

TinyFloats is a collection of simple conversion routines to help with storing floating point data in tiny float formats. Raku **cannot** compute with these shorter formats directly; they must first be converted back to native floating point using one of the `num-from-*` routines.

This version supports *only* bidirectional conversion between Raku native floating point numbers (`num`/`num32`/`num64`) and the following shorter floating point storage formats from this table:

Formats and Bit Widths

| Name | Total | Exponent | Mantissa | Max Val | ±Inf? | NaN? | Notes |
| --- | --- | --- | --- | --- | --- | --- | --- |
| num64 | 64 | 11 | 52 | ~2e+308 | Y | Y | Raku native (= num) |
| num32 | 32 | 8 | 23 | ~3e+38 | Y | Y | Raku native |
| tf32 | 19 | 8 | 10 | ~3e+38 | Y | Y | Nvidia TPU internal |
| bf16 | 16 | 8 | 7 | ~3e+38 | Y | Y | bfloat16, truncated num32 |
| bin16 | 16 | 5 | 10 | 65504 | Y | Y | IEEE 754 binary16/half |
| e5m2 | 8 | 5 | 2 | 57344 | Y | Y | FP8, truncated bin16 |

More details on the supported formats:

* `num64`/`num`

IEEE 754 `binary64` ("double precision") format, AKA `double` in C, `float64` in CDDL, and `7.27` in CBOR. Natively handled in Raku; unless specified otherwise, all floating point computation in Raku is done in this format.

* `num32`

IEEE 754 `binary32` ("single precision") format, AKA `float` in C, `float32` in CDDL, and `7.26` in CBOR. Natively handled in Raku, but used in Raku computations only if specifically requested. This is also used as an intermediate format when expanding the shorter formats using one of the `num-from-*` routines.

* `tf32`

Nvidia TensorFloat-32 format, used internally by Nvidia tensor processing hardware, with the 8 bit exponent width of `num32` and `bf16` and the 10 bit mantissa width of `bin16`. This works well for improving performance without as much loss of range or precision as the 16-bit formats. Unfortunately it is a 19-bit format and thus inconvenient to use for storage or interchange; Nvidia TPUs convert from `num32` and back on the fly. This format is provided here for completeness, but is generally just a curiosity if not performing computations on actual Nvidia TPU hardware.

* `bf16`

Google Brain `bfloat16` format, essentially IEEE 754 `binary32` ("single precision") with the least significant 16 bits truncated from the mantissa. `bf16` reduces *only* the mantissa bits, is relatively quick to convert, is used most often in machine learning systems, and is usually supported directly by the ML hardware.

* `bin16`

IEEE 754 `binary16` ("half precision") format, AKA `_Float16` in C, `float16` in CDDL, and `7.25` in CBOR. `bin16` attempts to balance the reduction in exponent and mantissa bits, is fairly slow to convert, is used most often in graphics formats, and is commonly converted to native binary32 internally by modern graphics hardware.

* `e5m2`

Open Compute Project (OCP) OFP8 format, E5M2 variant. Another truncated format, `e5m2` is `bin16` with the least significant 8 bits truncated from the mantissa. Like `bf16`, `e5m2` reduces *only* the mantissa bits from its parent format, and thus maintains most of its available useful range. Unlike the other OFP8 variant (E4M3), `e5m2` still maintains full `Inf`/`NaN` support.

# BUGS AND LIMITATIONS

* There are no routines provided to directly convert between various tiny float formats. To do this, you will need to convert from the source tiny format to a native Raku `num` using the appropriate `num-from-*` routine before converting to the destination tiny format using the appropriate `*-from-num` routine.
* Currently only mantissa truncation (AKA RTZ, Round To Zero) is supported when converting to narrower formats. Recent standardization work requires that format conversions support and default to using IEEE 754 RTNE (Round To Nearest with ties to Even) instead, though truncation is allowed as an option. For now the routines in this module comply with the older and faster truncation-focused rounding.
* There are no routines provided to pack sub-byte formats into a byte buffer (`buf8`); callers will need to do this themselves for now.

# AUTHOR

Geoffrey Broadwell [gjb@sonic.net](mailto:gjb@sonic.net)

# COPYRIGHT AND LICENSE

Copyright 2021,2025 Geoffrey Broadwell

This library is free software; you can redistribute it and/or modify it under the Artistic License 2.0.


## dist_cpan-JNTHN-JSON-Schema.md
# NAME

JSON::Schema - an implementation of the [JSON Schema specification](https://json-schema.org/specification.html)

# SYNOPSIS

```
use JSON::Schema;
my $schema = JSON::Schema.new(
    schema => from-json '{ "type": "string" }'
);

# Validate it and use the result as a boolean.
say so $schema.validate("foo");     # True
say so $schema.validate(42);        # False
say so $schema.validate(Str);       # False

```

# DESCRIPTION

JSON::Schema is a module which allows JSON validation with set of rules described
in JSON Schema format.

# AUTHOR

Alexander Kiryuhin [alexander.kiryuhin@gmail.com](mailto:alexander.kiryuhin@gmail.com)

# COPYRIGHT AND LICENSE

Copyright © Alexander Kiryuhin [alexander.kiryuhin@gmail.com](mailto:alexander.kiryuhin@gmail.com)

This library is free software; you can redistribute it and/or modify it under
the Artistic License 2.0.


## dist_zef-thundergnat-Linux-Joystick.md
[![Actions Status](https://github.com/thundergnat/Linux-Joystick/actions/workflows/test.yml/badge.svg)](https://github.com/thundergnat/Linux-Joystick/actions)

# NAME

Linux::Joystick

# SYNOPSIS

```
use Linux::Joystick;

my $joystick = Linux::Joystick.new(
    :device('/path/to/mydevice'),
    :callback(&optional-callback)
);

```

# DESCRIPTION

Linux::Joystick - a simple interface to the most common Linux joystick driver.

(Also tested and working under Mac OSX.)

Sets up an asynchronous event stream reading events from the joystick in real time. Allows you to provide a callback routine which will execute every time an event is received.

The callback routine is rewritable and may be changed without restarting the joystick driver.

Needs to be initilized with a path to a valid, active joystick or joystick-like device. (An Xbox controller will work.) Optionally takes a callable routine to be executed every time an event is received.

An exported routine: `devices()` can be used to find and list available joystick devices.

Exports two hashes. `$joystick.config` and `$joystick.event`.

`$joystick.config` contains the enumerated inputs and their present value. Assuming your joystick has 12 buttons and 6 axes (Like a Logitech Extreme 3D for instance.) The enumerated button values will be in `$joystick.config<button>[0]` through `$joystick.config<button>[11]`. The enumerated axes will be in `$joystick.config<axis>[0]` through `$joystick.config<axis>[5]` .

You may also access events directly. `$joystick.event` will hold the values from the last event processed.

It holds the values:

* `type` - the type of joystick event it was; 1: button, 2: axis
* `number` - which input emitted the event: one of the enumerated buttons or axes
* `value` - the value associated with the event; button: 0 or 1, axis: -32767 to 32767
* `timestamp` - a millisecond granularity 32 bit time stamp. May be used to detect double-clicks or such. Rolls over every 100 or so hours.

Button values can only be 0 (up) or 1 (pressed). Axis values can (though not necessarily always do) range from -32767 to 32767. In general, even numbered axes operate in the vertical (y) axis with smaller numbers being higher up and larger being further down. Odd numbered axes usually operate in a horizontal (x) axis. Smaller values to the left, larger to the right.

If you end up tapping a SIGINT signal, the joystick stream won't close until it sees one more joystick event, the joystick is unplugged, or you send another different terminate event.

See the [/examples/joystick.p6](https://github.com/thundergnat/Linux-Joystick/blob/master/examples/joystick.p6) script to see how that might be done.

# AUTHOR

Stephen Schulze aka thundergnat

# COPYRIGHT AND LICENSE

Copyright 2020 thundergnat

This library is free software; you can redistribute it and/or modify it under the Artistic License 2.0.


## dist_github-supernovus-Method-Modifiers.md
# Method::Modifiers

## Introduction

Implements before(), after() and around() functions that can be used to
modify class methods similarly to Perl 5's Moose. It uses wrap() internally,
and returns the wrapper handler, so it is easy to .restore() the original.

Has an optional augmentation version that adds the aforementioned functions
as methods to the Any class. Mostly just a candy coating, and not really
recommended. Use the functions, they're straightforward and don't modify
the base classes.

## Examples

See the tests in "t/" for a few good examples.

## Status

The basic function version works. The augment version doesn't due to a
Rakudo bug. That's okay, as I mentioned above, the augment version isn't
really recommended anyway.

## Author

[Timothy Totten](https://github.com/supernovus/)

## License

[Artistic License 2.0](http://www.perlfoundation.org/artistic_license_2_0)


## dist_zef-coke-RakuDoc-Test-Files.md
# Overview

Utility methods for generating lists of files for testing.

By default, `git ls-files` is used to generate the list of files to process.

If files were passed as arguments on the command line, use those.

Finally, if the `TEST_FILES` environment variable is set to a space-separated list of files, use that.

Any files specified manually that don't exist are silently ignored. Each method returning a list of files may have additional criteria.

### method all-files

```
method all-files() returns Bool

```

Are we working with all the files in the repository? See the overview for the rules.

### method files

```
method files() returns Iterable

```

Return list of files to test without filtering by type.

### method pods

```
method pods() returns Iterable

```

Filter list of files to return only C files.

### method documents

```
method documents() returns Iterable

```

Filter list of C to return only C and Markdown.

### method tests

```
method tests() returns Iterable

```

Filter list of files to return only C files.


## dist_zef-titsuki-Algorithm-XGBoost.md
[![Actions Status](https://github.com/titsuki/raku-Algorithm-XGBoost/workflows/test/badge.svg)](https://github.com/titsuki/raku-Algorithm-XGBoost/actions)

# NAME

Algorithm::XGBoost - A Raku bindings for XGBoost ( <https://github.com/dmlc/xgboost> ).

# SYNOPSIS

```
use Algorithm::XGBoost;
use Algorithm::XGBoost::Booster;
use Algorithm::XGBoost::DMatrix;
use Algorithm::XGBoost::Model;

# agaricus.txt.test is here: https://github.com/dmlc/xgboost/tree/master/demo/data
my $dmat = Algorithm::XGBoost::DMatrix.from-file("agaricus.txt.train");
say $dmat.num-row; # 6513
say $dmat.num-col; # 127
my $model = Algorithm::XGBoost.train($dmat, 10);
$model.num-feature.say; # 127

my @test[2;2] = [[0e0,0e0],[0e0,1e0]];
my $test = Algorithm::XGBoost::DMatrix.from-matrix(@test);
say $model.predict($test); # (0.9858561754226685 0.9858561754226685)

```

# DESCRIPTION

Algorithm::XGBoost is a Raku bindings for XGBoost ( <https://github.com/dmlc/xgboost> ).

## METHODS

### train

Defined as:

```
method train(Algorithm::XGBoost::DMatrix $dmat, Int $num-iteration, %param --> Algorithm::XGBoost::Model)

```

Trains a XGBoost model.

* `$dmat` The instance of Algorithm::XGBoost::DMatrix.
* `$num-iteration` The number of iterations for training.
* `%param` The parameter for training.

### version

Defined as:

```
method version(--> Version)

```

Returns the libxgboost version.

### global-config

Defined as:

```
multi method global-config(Str $json-str)
multi method global-config(--> Str)

```

Sets/Gets the global parameters: verbosity and use\_rmm.

* `verbosity` The verbosity of printing messages. Valid values of 0 (silent), 1 (warning), 2 (info), and 3 (debug).
* `use_rmm` Whether to use RAPIDS Memory Manager (RMM) to allocate GPU memory. This option is only applicable when XGBoost is built (compiled) with the RMM plugin enabled. Valid values are true and false.

# AUTHOR

Itsuki Toyota [titsuki@cpan.org](mailto:titsuki@cpan.org)

# COPYRIGHT AND LICENSE

Copyright 2021 Itsuki Toyota

This library is free software; you can redistribute it and/or modify it under the Artistic License 2.0.


## dist_cpan-TYIL-IRC-Client-Plugin-UrlTitle.md
# NAME

IRC::Client::Plugin::UrlTitle

# AUTHOR

Patrick Spek [p.spek@tyil.work](mailto:p.spek@tyil.work)

# VERSION

1.1.2

# Description

Plugin for IRC::Client to report titles of URLs posted in IRC channels.

# Installation

Install this module through [zef](https://github.com/ugexe/zef):

```
zef install IRC::Client::Plugin::UrlTitle

```

Next, you can use it as a plugin in an [`IRC::Client`](https://modules.perl6.org/dist/IRC::Client:github:Zoffix%20Znet) project by adding it in the `:plugins` parameter:

```
use Config;
use IRC::Client;
use IRC::Client::Plugin::UrlTitle;

sub MAIN
{
    .run with IRC::Client.new(
	    :nick("testbot"),
	    :plugins(
		    IRC::Client::Plugin::UrlTitle.new,
	    )
    );
}

```

# License

This module is distributed under the terms of the GPL-3.0.


## dist_cpan-TITSUKI-Algorithm-AhoCorasick.md
[![Build Status](https://travis-ci.org/titsuki/raku-Algorithm-AhoCorasick.svg?branch=master)](https://travis-ci.org/titsuki/raku-Algorithm-AhoCorasick)

# NAME

Algorithm::AhoCorasick - A Raku Aho-Corasick dictionary matching algorithm implementation

# SYNOPSIS

```
use Algorithm::AhoCorasick;
my Algorithm::AhoCorasick $aho-corasick .= new(keywords => ['corasick','sick','algorithm','happy']);
my $matched = $aho-corasick.match('aho-corasick was invented in 1975'); # set("corasick","sick")
my $located = $aho-corasick.locate('aho-corasick was invented in 1975'); # {"corasick" => [4], "sick" => [8]}

```

# DESCRIPTION

Algorithm::AhoCorasick is a implmentation of the Aho-Corasick algorithm (1975). It constructs the finite state machine from a list of keywords offline. By the finite state machine, it can find the keywords within an input text online.

## CONSTRUCTOR

### new

```
my Algorithm::AhoCorasick $aho-corasick .= new(keywords => @keyword-list);

```

Constructs a new finite state machine from a list of keywords.

## METHODS

### match

```
my $matched = $aho-corasick.match($text);

```

Returns elements of a finite set of strings within an input text.

### locate

```
my $located = $aho-corasick.locate($text);

```

Returns elements of a finite set of strings within an input text where each string contains the locations in which it appeared.

# AUTHOR

titsuki [titsuki@cpan.org](mailto:titsuki@cpan.org)

# COPYRIGHT AND LICENSE

Copyright 2016 titsuki

This library is free software; you can redistribute it and/or modify it under the Artistic License 2.0.

The algorithm is from Alfred V. Aho and Margaret J. Corasick, Efficient string matching: an aid to bibliographic search, CACM, 18(6):333-340, June 1975.