## dist_zef-masukomi-Time-Duration.md
# NAME

Time::Duration - rounded or exact English expression of durations

# SYNOPSIS

Example use in a program that ends by noting its runtime:

```
  my $start_time = time;
  use Time::Duration;

  # then things that take all that time, and then ends:
  print "Runtime: ", duration(time - $start_time), ".\n";
  # see also duration_exact

```

Example use in a program that reports age of a file:

```
    use Time::Duration;
    my $file = 'that_file';
    my $age_in_seconds = SomeModule::get_modtime($file);
    print "$file was modified ", ago($age_in_seconds);
    # see also ago_exact

```

Example use with more concise output. Simply wrap the output of the other functions as a parameter to `concise`

```
       ago($age_in_seconds);                  # 23 hours and 56 minutes ago
       concise(ago($age_in_seconds));         # 23h56m ago
       concise(duration(time - $start_time)); # 4m8s

```

Example of future time

```
       from_now(120);            # 2 minutes from now
       concise(from_now(86178)); # 23h56m from now
       # see also from_now_exact
       later(86178);             # 23 hours and 56 minutes later
       concise(later(86178));    # 23h56m later

```

And things that happened earlier

```
       earlier(86178);          # 23 hours and 56 minutes earlier
       concise(earlier(86178)); # 23h56m earlier
       # see also earlier_exact

```

# DESCRIPTION

This module provides functions for expressing durations in rounded or exact terms.

In the first example in the Synopsis, using duration($interval\_seconds):

* If the `time - $start_time` is 3 seconds, this prints "Runtime: **3 seconds**.".
* If it's 0 seconds, it's "Runtime: **0 seconds**.".
* If it's 1 second, it's "Runtime: **1 second**.".
* If it's 125 seconds, you get "Runtime: **2 minutes and 5 seconds**.".
* If it's 3820 seconds (which is exactly 1h, 3m, 40s), you get it rounded to fit within two expressed units: "Runtime: **1 hour and 4 minutes**.".
* Using duration\_exact instead would return "Runtime: **1 hour, 3 minutes, and 40 seconds**".

In the second example in the Synopsis, using `ago($interval_seconds)`:

* If the `$age_in_seconds` is 3 seconds, this prints "*file* was modified **3 seconds ago**".
* If it's 0 seconds, it's "*file* was modified **just now**", as a special case.
* If it's 1 second, it's "from **1 second ago**".
* If it's 125 seconds, you get "*file* was modified **2 minutes and 5 seconds ago**".
* If it's 3820 seconds (which is exactly 1h, 3m, 40s), you get it rounded to fit within two expressed units: "*file* was modified **1 hour and 4 minutes ago**".
* Using `ago_exact` instead would return "*file* was modified **1 hour, 3 minutes, and 40 seconds ago**".
* And if the file's modtime is, surprisingly, three seconds into the future, $age is -3, and you'll get the equally and appropriately surprising "*file* was modified **3 seconds from now**."

# FUNCTIONS

This module provides all the following functions, which are all exported by default when you call `use Time::Duration;`.

# over

* duration($seconds)
* duration($seconds, $precision)

Returns English text expressing the approximate time duration of `abs($seconds)`, with at most `$precision || 2` expressed units. (That is, `duration($seconds)` is the same as `duration($seconds,2)`.)

For example, `duration(120)` or `duration(-120)` is "2 minutes". And `duration(0)` is "0 seconds".

The precision figure means that no more than that many units will be used in expressing the time duration. For example, 31,629,659 seconds is a duration of *exactly* 1 year, 1 day, 2 hours, and 59 seconds (assuming 1 year = exactly 365 days, as we do assume in this module). However, if you wanted an approximation of this to at most two expressed (i.e., nonzero) units, it would round it and truncate it to "1 year and 1 day". Max of 3 expressed units would get you "1 year, 1 day, and 2 hours". Max of 4 expressed units would get you "1 year, 1 day, 2 hours, and 59 seconds", which happens to be exactly true. Max of 5 (or more) expressed units would get you the same, since there are only four nonzero units possible in for that duration.

* duration\_exact($seconds)

Same as `duration($seconds)`, except that the returned value is an exact (unrounded) expression of `$seconds`. For example, `duration_exact(31629659)` returns "1 year, 1 day, 2 hours, and 59 seconds later", which is *exactly* true.

* ago($seconds)
* ago($seconds, $precision)

For a positive value of seconds, this prints the same as `duration($seconds, [$precision]) . S<' ago'>`. For example, ago(120) is "2 minutes ago". For a negative value of seconds, this prints the same as `duration($seconds, [$precision]) . S<' from now'>`. For example, ago(-120) is "2 minutes from now". As a special case, ago(0) returns "right now".

* ago\_exact($seconds)

Same as ago($seconds), except that the returned value is an exact (unrounded) expression of $seconds.

* from\_now($seconds)
* from\_now($seconds, $precision)
* from\_now\_exact($seconds)

The same as `ago(-$seconds)`, `ago(-$seconds, $precision)`, `ago_exact(-$seconds)`. For example, `from_now(120)` is "2 minutes from now".

* later($seconds)
* later($seconds, $precision)

For a positive value of seconds, this prints the same as `duration($seconds, [$precision]) . S<' later'>`. For example, ago(120) is "2 minutes later". For a negative value of seconds, this prints the same as `duration($seconds, [$precision]) . S<' earlier'>`. For example, later(-120) is "2 minutes earlier". As a special case, later(0) returns "right then".

* later\_exact($seconds)

Same as later($seconds), except that the returned value is an exact (unrounded) expression of $seconds.

* earlier($seconds)
* earlier($seconds, $precision)
* earlier\_exact($seconds)

The same as later(-$seconds), later(-$seconds, $precision), later\_exact(-$seconds). For example, earlier(120) is "2 minutes earlier".

* concise( *function(* ... ) )

Concise takes the string output of one of the above functions and makes it more concise. For example, `ago(4567)` returns "1 hour and 16 minutes ago", but `concise(ago(4567))` returns "1h16m ago".

# back

# I18N/L10N NOTES

Little of the internals of this module are English-specific. See source and/or contact me if you're interested in making a localized version for some other language than English.

# BACKSTORY

Sean Burke wrote the basic `ago()` function for use in Infobot (`http://www.infobot.org`), because he was tired of this sort of response from the Purl Infobot:

```
me> Purl, seen Woozle?
<Purl> Woozle was last seen on #perl 20 days, 7 hours, 32 minutes
and 40 seconds ago, saying: Wuzzle!

```

He figured if it was 20 days ago, he don't care about the seconds. So once he had written `ago()`, he abstracted the code a bit and got all the other functions.

# CAVEAT

This module calls a durational "year" an interval of exactly 365 days of exactly 24 hours each, with no provision for leap years or monkey business with 23/25 hour days (much less leap seconds!). But since the main work of this module is approximation, that shouldn't be a great problem for most purposes.

# SEE ALSO

Date::Interval, which is similarly named, but does something rather different.

*Star Trek: The Next Generation* (1987-1994), where the character Data would express time durations like "1 year, 20 days, 22 hours, 59 minutes, and 35 seconds" instead of rounding to "1 year and 21 days". This is because no-one ever told him to `use Time::Duration`.

# COPYRIGHT AND DISCLAIMER

Copyright 2006, Sean M. Burke, Copyright 2013, Dagur Valberg Johannsson, Copyright 2023, Kay Rhodes

all rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5 itself.

This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose.

# AUTHOR

* Original Author: Sean M. Burke
* Perl 5 Maintainer: Avi Finkel
* Ported to Perl 6 by: Dagur Valberg Johannsson
* Maintained in Perl 6 by: masukomi (A.K.A. Kay Rhodes)


## dist_github-colomon-Phaser-ATEXIT.md
# Phaser-ATEXIT

Simple implementation of ATEXIT for Perl 6.

```
use Phaser::ATEXIT;

ATEXIT { say "This will be run last" }
ATEXIT { say "This will be run in the middle" }

say "This will be run first";

```


## dist_zef-vrurg-JSON-Class.md
## Chunk 1 of 2
# NAME

`JSON::Class` - general purpose JSON de-/serialization for Raku

# SYNOPSIS

```
use JSON::Class:auth<zef:vrurg>;

role Base is json(:!skip-null) {
    has Num:D $.size is required is json(:name<volume>);
}

class Record is json does Base {
    has Int $.count;
    has Str $.description;
}

say Record.new(:count(42), :description("The Answer"), :size(1.2e0)).to-json;

```

# DESCRIPTION

This module is an alternative to the family of [`JSON::Marshal`](https://raku.land/zef:jonathanstowe/JSON::Marshal), [`JSON::Unmarshal`](https://raku.land/zef:raku-community-modules/JSON::Unmarshal), [`JSON::Class`](https://raku.land/zef:jonathanstowe/JSON::Class) modules. It tries to get rid of their weak points and shifts the locus of control from class' outers to its inners. In other words, the class itself is responsible for its de-/serialization in first place. Though it's perhaps, the primary difference, it's far from being the only one.

* **IMPORTANT!**

  In order to use this module it is mandatory to use `:auth<zef:vrurg>` in your `use` statement:

  ```
  use JSON::Class:auth<zef:vrurg>

  ```

  Otherwise you are likely to accidentally pull in [`JSON::Class:auth<zef:jonathanstowe>`](https://raku.land/zef:jonathanstowe/JSON::Class).

Also, this module tries to follow the standards of [`LibXML::Class`](https://raku.land/zef:vrurg/LibXML::Class) module by adapting them for differing domain of JSON. First of all, they share the same view on the locus of responsibility. Second, they try to implement declarative semantics in first place.

From here on whenever `JSON::Class` name is used it refers to this module unless otherwise stated or implied by the context.

# BASICS

In this section some basic concepts of `JSON::Class` are explained. If you feel like skipping it then skip over to the *QUICK INTRO BY EXAMPLE* section below.

## Basic Or "Complex" Types

Some protocols of `JSON::Class` depend on the kind of type involved. Basic types are considered to be *simple* or *trivially marshalled*. Currently these are [`Mu`](https://docs.raku.org/type/Mu), [`Any`](https://docs.raku.org/type/Any), [`Bool`](https://docs.raku.org/type/Bool), or those consuming [`Numeric`](https://docs.raku.org/type/Numeric), [`Stringy`](https://docs.raku.org/type/Stringy), [`Enumeration`](https://docs.raku.org/type/Enumeration) roles.

A "complex" type is expected to have marshallable attributes.

## Marshalling And JSONification

JSON marshalling requires declaring corresponding entities as JSON-ones, or *JSONification*. Normally this is done by using trait `is json` with classes, roles, or attributes. This is declarative, or explicit, JSONification.

It is also possible that implicit jsonification can be used when necessary or desirable. Normally `JSON::Class` attempts to implement it in a user-transparent way. For example:

```
class Record {...}
class Archive is json {
    has Record:D @.records;
}

my $arch = Archive.new;
... add records to the archive ...
$arch.to-json;

```

The class `Record` above would be implicitly JSONified to produce serialization of a single record. But the JSONified version would never pop on the surface. So, when the archive is deserialized `@.records` will contain instances of the original `Record`.

## Trait

Trait `is json` is used for nearly every declaration of JSON elements. The only other trait we have is `json-wrap`, but it is too early to discuss it.

How something is marshalled is mostly defined by the trait's arguments.

## Declarant

In a context of attribute-related discussion it is the object where the attribute was declared in.

## Config

Marshalling of deep structures often requires sharing of common options, modifying the process. This is implemented by using a *configuration* object. A configuration belongs to a dynamic context of marshalling.

There is also a global configuration singleton used when no other configuration provided.

## JSON Class

A *JSON class* is one which has `is json` trait applied. Sometimes, depending on the context and especially when referring to an instance of the class, another term *JSON object* can be used.

## Laziness

Deserialization of big deeply nested structures could be a long process, no matter if we need an element of the structure right away, or it is going to be requested later, or not used at all. `JSON::Class` attempts to bring some relieve by postponing deserialization for later time.

## Lazy Collections

`JSON::Class` implements two [*collection*](https://en.wikipedia.org/wiki/Collection_(abstract_data_type)) types: sequences and dictionaries, namely *JSON sequences* and *JSON dictionaries*. The first is a [`Postional`](https://docs.raku.org/type/Postional) and [`Iterable`](https://docs.raku.org/type/Iterable), the second is an [`Associative`](https://docs.raku.org/type/Associative).

Both types are primarily defined by these two properties:

* their elements are lazily deserialized on demand
* they do their best to serve as a container for multiple types, including user classes

### JSON Sequence

*JSON sequence* is a class with `is json( :sequence(...) )` trait applied.

Term "sequence" is used here for something that is rather an array and, most definitely, not a sequence ([`Seq`](https://docs.raku.org/type/Seq)) from Raku's point of view. The term was borrowed from [`LibXML::Class`](https://raku.land/zef:vrurg/LibXML::Class), which implements the same concept, and where it was adopted from XML schema definitions.

### JSON Dictionary

*JSON dictionary* is, in a way, similar to JSON sequence in terms of been a lazily deserialized collection. Dictionary is an [`Associative`](https://docs.raku.org/type/Associative) implementation produced with `is json( :dictionary(...) )`.

## Explicit Or Implicit Typeobjects

It could be tedious to marshal a class with many attributes. Most use cases assume that entire object would end up mapped into a JSON structure. Therefore `JSON::Class` defaults to *implicit* declaration where all public or `is built` attributes are JSONified wihout needing explicit `is json` trait. This is the case demoed in the SYNOPSIS.

In explicit mode one has to manually apply the trait to marshallable attributes.

## Declaration

As it was stated earlier, `is json` is the primary and, basically, the only declarator used by the module. The trait accepts various arguments to modify the declaration according to one's needs. For example, an explicit class is to be declared as:

```
class ComplexOne is json(:!implicit) {...}

```

Within the class an attribute for marshalling is to be also marked with `is json`:

```
has SomeType $.st is required is json(:skip-null, :!lazy);

```

## Naming Convention

With only few exceptions, names of all attributes and methods introduced by `JSON::Class` distribution are starting with `json-` prefix. This rule may not be followed by some internal data structures, but is almost 100% true about entities injected into JSONified typeobject as part of their public or private API.

There is a consequence to this rule: implicit JSONification of attributes skips these with `json-`-prefixed names:

* From <examples/json-pfx-attr.raku>

  ```
  class Foo is json(:implicit) {
      has Int $.foo;
      has Str $.json-invisible;
  }

  my $foo = Foo.new(:foo(42), :json-invisible("The Answer"));
  say "JSON      : ", $foo.to-json;
  say "Attribute : ", $foo.json-invisible;

  ```

  Sample output:

  ```
  JSON      : {"foo":42}
  Attribute : The Answer

  ```

## Trait Arguments

### Common For Classes And Roles

* `Bool` **`:implicit`**

  Set typeobject explicit/implicit mode. Omitting this argument assumes that the typeoject is implicit unless at least one attribute has an explicit [`is json` declaration](#Attribute).

  See [*examples/decl-implicit.raku*](examples/decl-implicit.raku).
* `Bool` **`:lazy`**

  Set typeobject lazyness. Depending on its value (or absence of such) attributes with no individually set laziness choose their default mode. See attribute trait `:lazy` argument description below and [*examples/decl-lazy.raku*](examples/decl-lazy.raku).
* `Bool` **`:skip-null`**

  If *True* then attributes of this typeobject are not serialized if their value is undefined. When omitted then value of this parameter is obtained from the configuration object. See [*t/020-json-basics.rakutest*](t/020-json-basics.rakutest), subtest "Undefineds".
* `Hash()` **`:config`**

  This argument lets to specify default configuration options for a typeobject. See [*t/060-config.rakutest*](t/060-config.rakutest), subtest "Config Defaults".

  *Note* that for options, directly supported by the trait (like `:pretty`, for example), values in `:config` has lower priority. I.e. for `is json(:pretty, :config(:!pretty))` the final value would be `:pretty`.
* **`:sequence(...)`**

  This type object is a sequence. See the [Sequences](#Sequences) section.
* **`:dictionary(...)`** or **`:dict(...)`**

  This type object is a dictionary. See the [Dictionaries](#Dictionaries) section.
* **`:is(...)`**, **`:does(...)`**

  These arguments allow to incorporate additional non-JSON parent classes and/or roles. See [Incorporation](#Incorporation) section.

### Class-only

* `Bool` **`:pretty`**, `Bool` **`:sorted-keys`**

  This two arguments set default values for corresponding config parameters but only if the type object is the initiator of serialization. Normally it means that method `to-json` is called on an instance of this typeobject, and that the call is not made inside a dynamic context of another `to-json`-initiated serialization. More practically, it means that dynamic variable `$*JSON-CLASS-CONFIG` is not set.

### Attribute

Parameters set via `is json` trait for attributes are normally overriding these set by its declarant. Moreover, unless the declarant is using `:implicit` or `:!implicit` argument with its `is json` trait then declaring an attribute as JSON-marshallable turns its typeobject into an explicit one.

There is an exception though: adverbs `:skip`, `:build`, and `:aliases`, used in any combination, but with no other arguments, doesn't affect the status of attribute's declarant.

* `Bool` **`:skip`**

  Don't ever marshalize this attribute. Mostly useful for `:implicit` typeobjects when one or more attributes are to be ignored. Negation of this argument makes no sense.
* `Bool` **`:skip-null`**

  Set `skip-null` parameter individually for this attribute, no matter what is set for the declarant.
* `Str` **`:name`**

  Normally key name of a JSON object to which an attribute serializes is given after attribute's name, omitting its sigil and twigil. With `:name` this value can be altered to something different.
* `Array[Str:D]` **`:alias`** or `B<:aliases>`

  This adverb has the same meaning as its counterpart in [`AttrX::Mooish`](https://raku.land/?q=AttrX::Mooish): it allows an attribute to have more than one name. **Note** though that this adverb doesn't affect marshalling where only one JSON key name is allowed.
* `Bool` **`:lazy`**

  Force laziness mode of this attribute. If omitted then the following rules are used to determine attribute's default laziness mode:

  * When attribute has an initializer or default value then it defaults to non-lazy
  * If attribute's declarator laziness mode is set explicitly then it is used for the attribute
  * Otherwise attribute defaults to lazy when its type is a non-basic, and to non-lazy otherwise
* `Bool` **`:serializer(...)`**, `Bool` **`:deserializer(...)`**

  Allowed aliases are `:to-json` and `:from-json`, correspondingly.

  Specify custom marshallers for the attribute. Normally that'd be either a method name on attribute's type, or an explicit code object. For associative and positional attributes additional marshallers for keys and values are available via `:key` and `:value` named arguments. Apparently, only the latter works with positionals:

  ```
  has %.assoc is json(
      :serializer(
          key => { "pfx-" ~ $^key },
          value => { $^value.raku } ),
      :deserializer(
          key => { $^from.substr(4) },
          value => { $^from.EVAL } ));

  ```

  See 'Custom Marshallers' in [`JSON::Class::Details`](docs/md/JSON/Class/Details.md).
* `Bool:D | Str:D | Code:D` **`:build(...)`**

  Lazily build attribute value upon read unless it's been initialized already from other sources like a constructor argument, or a value from JSON structure. Unless you're familiar with [`AttrX::Mooish`](https://raku.land/?q=AttrX::Mooish), then think of this adverb as a kind of [`is default`](https://docs.raku.org/type/Attribute#Trait_is_default) trait but with some specifics.

  Depending on adverb format different ways of building attribute's value are used:

  * **`:build`**

    Attribute base name is taken (i.e. with no sigil or twigil), prepended with *'build-'* prefix and the result is taken as the method name. For example, for `$.foo` the method name would be *"build-foo"*.

    `:!build` is a [NOP](https://en.wikipedia.org/wiki/NOP_(code)).
  * **`:build("method-name")`**

    An explicit method name to use.
  * **`:build(&code)`**

    Particular code object (routine, block, etc.).

  Value returned by either of the above variant is used to initialize the attribute.

  See [*examples/lazy-build.raku*](examples/lazy-build.raku) and subtest "Lazy Build" in [*t/020-json-basics.rakutest*](t/020-json-basics.rakutest).
* `Bool:D | Str:D` **`:clearer(...)`**

  Similar to [`AttrX::Mooish`](https://raku.land/?q=AttrX::Mooish) trait argument of the same name. Clears a lazy attribute and turns it back into uninitialized state. If there is a pending record for lazy deserialization then it is removed too.

  When clearer value is a string (`:clearer<wipe-it>`) then it is treated as helper method name.

  See [*t/020-json-basics.rakutest*](t/020-json-basics.rakutest), subtest "Clearers".
* `Bool:D | Str:D` **`:predicate(...)`**

  Similar to [`AttrX::Mooish`](https://raku.land/?q=AttrX::Mooish)> trait argument of the same name. In its string form it defines predicate helper method name (`:predicate<we-got-it>`). Otherwise `json-has-key-name` name is used, where the *key-name* part is attribute's JSON key.

### Collections

A class is declared as a JSON collection with `:sequence` or `:dictionary` (also aliased as `:dict`) adverbs of the `is json` trait. The adverbs are expected to be a list of declarations where each item of the list either specify a type constraint or a default value. For dictionaries it is possible to type constrain their keys.

A type constraint declaration can be either:

* a plain typeobject

  Int:D:D
* a typeobject with modifiers as a list

  ```
  (Foo, :&serializer, :&deserializer)

  ```
* a [`Pair`](https://docs.raku.org/type/Pair) of a type object and a list of modifiers:

  ```
  (Bar) => (:to-json(&bar2json), :from-json(&json2bar))

  ```

Typeobject modifiers are:

* **`:$serializer`** AKA **`:$to-json`**
* **`:$deserializer`** AKA **`:$from-json`**
* **`:$matcher`**

The last one's meaning is explained below in this section.

The **`:default`** declaration is similar in semantics to the `is default` trait: it sets the value to be used when `Nil` is assigned into a sequence position, or when a non-existing element requested:

```
class JDict is json(:dict(..., :default(42))) {}

say JDict.new.<not-here-yet>; # 42

```

Default is not obliged to be a concrete value.

Whenever a collection is declared with multiple types it is equivalent to declaring an array or a hash with a subset matching all the same types:

```
class JSeq is json(:sequece(Int:D, Str:D, Foo)) {}

```

be like:

```
my subset JSeqOf of Mu where Int:D | Str:D | Foo;
my JSeqOF @jseq;

```

* *Note*

  There is a potential problem with this declaration: assigning a `Nil` will result in a type mismatch because the default value would me [`Mu`](https://docs.raku.org/type/Mu), but it doesn't match the subset. Therefore a safe way to do it would be something like:

  ```
  class JSeq is json(:sequece(Int:D, Str:D, Foo, :default(Foo))) {}

  ```

#### Dictionary Only Declaration

**`:keyof(...)`** declaration can only be used with the `:dictionary` adverb. It's value has the same format as a single type constraint declaration:

```
class JDict is json( :dictionary( ..., :keyof(Foo:D()) ) )

```

```
class JDict is json( :dictionary( ..., :keyof(Foo:D(), :serializer(&foo2json), :deserializer(&json2foo)) ) )

```

#### The Multitype Matching Problem

When a collection is declared with two or more value classes that are not basic types a problem of matching JSON object to a class arises. Apparently, JSON itself lacks any means of distinguishing one JSON object from another *(kids, let's say "Hello!" to JavaScript's OO!)*. In other words, having something like:

```
[
    {"key1": 1, "key2":"a string"},
    {"keyA": 3.1415926, "keyB": "const"}
]

```

One wouldn't be able to tell what classes each JSON object represents. The only way for us to distinguish is to guess. Say, we have:

```
class Foo {
    has Int $.key1;
    has Str $.key2;
}
class Bar {
    has Num $.keyA;
    has Str $.keyB;
}

```

In this case it is obvious that the first JSON object matches `Foo`, whereas the other one matches `Bar`.

This is what `JSON::Class` sequence basically does by default: it compares sets of keys per each class-candidate to the keys of JSON object. So far – so good, until a very rare case pops up where two classes has the same key names. Say:

```
class Book {
    has Str:D $.id is required;
    has Str:D $.name is requried;
}
class Article {
    has Str:D $.id is required;
    has Str:D $.name is required;
}

```

The default matching algorithm would throw here with `JSON::Class::X::Deserialize::SeqItem` or `JSON::Class::X::Deserialize::DictItem` exception, depending on the collection type, due to the unresolvable ambiguity. What can we do to avoid that?

One can work around the problem by introducing extra layers of data, for example:

```
class BookOrArticle is json {
    has Book $.book;
    has Article $.article;
}

```

This approach unreasonably complicates things and not even always possible.

But what if we know that IDs of books and articles are sufficiently different to tell exactly which is is which? For example, book ID could start with *ISBN:*, whereas article ID starts with a date-based *YYYY-MM-DD:* prefix? In this case custom matchers can distinguish one JSON object from another:

* From <examples/book-article-seq.raku>

  ```
  class Book {
      has Str:D $.id is required;
      has Str:D $.name is required;
  }
  class Article {
      has Str:D $.id is required;
      has Str:D $.name is required;

      method is-an-article(%from) {
          ? (%from<id> ~~ /^ \d ** 4 '-' \d ** 2 '-' \d ** 2 ':'/)
      }
  }

  sub is-a-book(%from) { %from<id>.starts-with("ISBN:") }

  class BoxOfPapers is json(:sequence( (Book, :matcher(&is-a-book)), (Article, :matcher<is-an-article>) )) {}

  my $json = q:to/JSON/;
  [
      {"id": "ISBN:1234", "name": "The Guide"},
      {"id": "2006-04-01:the-pop-one", "name":"What's the programmer's most popular book out there?"}
  ]
  JSON

  my $box = BoxOfPapers.from-json($json);
  say $box.map(*.gist).join("\n");

  ```

  Sample output:

  ```
  Book.new(id => "ISBN:1234", name => "The Guide")
  Article.new(id => "2006-04-01:the-pop-one", name => "What's the programmer's most popular book out there?")

  ```

This approach, in essence, is applicable to dictionaries too.

There are other ways of solving this task that involve custom marshalling where we can manipulate with serializable data or keys to inject clues as to what's the source type of JSON object was.

#### Alternative Solutions To Matching

A universal matcher for type can also be set using [`JSON::Class::Config`](docs/md/JSON/Class/Config.md) `set-helpers` method.

Another way is to try overriding `json-guess-descriptor` method of a container class. In this case it would even be possible to base your guess on value's position is a sequence, or its key in a dictionary. But to do so one is better be familiar with the internals of `JSON::Class`.

# DYNAMIC VARIABLES

* `JSON::Class::Config` **`$*JSON-CLASS-CONFIG`**

  Configuration object. When not available it means we're out of the context of `to-json` or `from-json` methods.
* **`$*JSON-CLASS-SELF`**

  The invocant of `json-serialize` or `json-deserialize` methods.
* [`JSON::Class::Descriptor`](docs/md/JSON/Class/Descriptor.md) **`$*JSON-CLASS-DESCRIPTOR`**

  Descriptor of the currently being marshalled attribute or sequence item.

# QUICK INTRO BY EXAMPLE

This section contains a series of working code examples demonstrating different features of this module. The samples are slightly stripped down to keep focus on their functionality and don't bother you with boilerplate. Their full code can be found under *examples/* subdirectory of the distribution.

## Explicit/Implicit

* From <examples/decl-implicit.raku>

  ```
  class Foo is json {
      has $.foo is json(:predicate);
  }

  say "Foo is explicit: ", Foo.^json-is-explicit, "\n",
      " has 'foo' key : ", Foo.^json-has-key('foo');

  class Bar is json {
      has $.bar1;
      has $.bar2 is json;
  }

  say "Bar is explicit: ", Bar.^json-is-explicit, "\n",
      " has 'bar1' key: ", Bar.^json-has-key('bar1'), "\n",
      " has 'bar2' key: ", Bar.^json-has-key('bar2');

  ```

  Sample output:

  ```
  Foo is explicit: False
   has 'foo' key : True
  Bar is explicit: True
   has 'bar1' key: False
   has 'bar2' key: True

  ```

## Inheritance And Role Consumption

* From <examples/simple-inherit.raku>

  ```
  role R is json {
      has Bool $.flag;
  }

  class C1 does R is json {
      has Int $.count;
  }

  class C2 is json is C1 {
      has Str $.what;
  }

  my $obj = C2.new(:count(3), :what("whatever you like"), :flag);
  say $obj.to-json(:pretty, :sorted-keys);

  ```

  Sample output:

  ```
  {
    "count": 3,
    "flag": true,
    "what": "whatever you like"
  }

  ```

## Incorporation

Notice that except for `C3`, all other classes and roles are not JSONified. Only attributes of `C1` and `R1` are serialized.

* From <examples/incorporation.raku>

  ```
  role R1 {
      has Bool $.flag;
  }

  role R2 {
      has Num $.cost;
  }

  class C1 {
      has Int $.count;
  }

  class C2 {
      has Num $.total;
  }

  class C3 is json(:is(C1), :does(R1)) does R2 is C2 {
      has Str $.what;
  }

  my $obj = C3.new(:count(3), :what("whatever you like"), :flag, :cost(1.2e0), :total(1e3));
  say $obj.to-json(:pretty, :sorted-keys);

  ```

  Sample output:

  ```
  {
    "count": 3,
    "flag": true,
    "what": "whatever you like"
  }

  ```

## Lazy Deserialization

* From <examples/decl-lazy.raku>

  ```
  class Item {
      has $.something;
  }

  class Foo is json {
      has Str $.foo;   # Basic types are eager by default
      has Item $.item; # Non-basic types is lazy by default
  }

  say "--- Foo";
  say "    .foo lazy      : ", Foo.^json-get-key("foo").lazy;
  say "    .item lazy     : ", Foo.^json-get-key("item").lazy;

  class Bar is json(:lazy, :implicit) {
      has Str $.bar;
      has Item $.item;
      has Item $.item2 is json(:!lazy);
  }

  say "--- Bar";
  say "    .bar is lazy   : ", Bar.^json-get-key('bar').lazy;
  say "    .item is lazy  : ", Bar.^json-get-key('item').lazy;
  say "    .item2 is lazy : ", Bar.^json-get-key('item2').lazy;

  class Baz is json(:!lazy, :implicit) {
      has Str $.baz;
      has Item $.item;
      has Item $.item2 is json(:lazy);
  }

  say "--- Baz";
  say "    .baz lazy      : ", Baz.^json-get-key("baz").lazy;
  say "    .item lazy     : ", Baz.^json-get-key("item").lazy;
  say "    .item2 lazy    : ", Baz.^json-get-key("item2").lazy;

  ```

  Sample output:

  ```
  --- Foo
      .foo lazy      : False
      .item lazy     : True
  --- Bar
      .bar is lazy   : True
      .item is lazy  : True
      .item2 is lazy : False
  --- Baz
      .baz lazy      : False
      .item lazy     : False
      .item2 lazy    : True

  ```

## Lazy Attribute Build

* From <examples/lazy-build.raku>

  ```
  class LazyRec is json(:lazy) {
      has $.attr1 is json(:build);
      has $.attr2 is json(:build<build-attr1>);
      has @.attr3 is json(:build(-> $ { "π", pi, "the answer", 42 }));
      has %.attr4 is json(:build<new-map>);

      method build-attr1(JSON::Class::Attr:D $descr) {
          say "Builder for attr1 for ", $descr.json-name;
          "for " ~ $descr.name
      }
      method new-map($) { :key<value>, :!flag }
  }

  my $lr = LazyRec.new;
  say "- attr1: ", $lr.attr1;
  say "- attr2: ", $lr.attr2;
  say "- attr3: ", $lr.attr3;
  say "- attr4: ", $lr.attr4;

  ```

  Sample output:

  ```
  Builder for attr1 for attr1
  - attr1: for $!attr1
  Builder for attr1 for attr2
  - attr2: for $!attr2
  - attr3: [π 3.141592653589793 the answer 42]
  - attr4: {flag => False, key => value}

  ```

## Config Defaults

`C1` specify config defaults but they affect the output only when the immediate instance of the class is serialized. Otherwise if a subclass instance is serialized then its defaults are used. This is to preserve the uniformity of serialization.

* From <examples/config-defaults.raku>

  ```
  class C1 is json(:pretty, :sorted-keys) {
      has Int $.count;
      has Str $.what;
  }

  class C2 is C1 is json(:!skip-null) { }

  my $c1 = C1.new(:count(42), :what("The Answer"));
  say "--- C1 serialization:\n", $c1.to-json;
  my $c2 = C2.new(:count(42), :what("The Answer"));
  say "--- C2 serialization:\n", $c2.to-json;

  ```

  Sample output:

  ```
  --- C1 serialization:
  {"count":42,"what":"The Answer"}
  --- C2 serialization:
  {"count":42,"what":"The Answer"}

  ```

## Sequence

This example is a bit verbose from both code and output perspective. It's point is to demonstrate the difference between an array and a JSON Sequence type. The following aspects a worth paying attention to:

* Multi-type support. See *The Multitype Matching Problem* section above.
* Lazy deserialization of individual elements of the sequence. This may come handy when dealing with big arrays of objects where only few of them are actually needed.

Apparently, this example doesn't cover all of `JSON::Class` sequence features.

* From <examples/simple-sequence.raku>

  ```
  class Item1 is json {
      has Str $.id;
      has Int $.quantity;
  }

  class Item2 is json {
      has Str $.section;
      has Str $.chapter;
  }

  class JSeq is json(:sequence(Str:D, Item1:D, Item2:D, :default<removed>)) {
      method json-deserialize-item($idx, \json-value) is raw {
          say "... deserializing [$idx] ...";
          nextsame
      }
  }

  my $jseq = JSeq.new("something", Item2.new(:section<S>, :chapter("22.1")));

  $jseq.push: Item1.new(:id<EBCA-12F>, :quantity(13));
  $jseq.push: "final";

  say "--- Initial    : ", $jseq.to-json;
  say "--- Delete 2nd : ", $jseq[1]:delete;
  say "--- 2nd deleted: ", $jseq.to-json;
  my $deserialized := JSeq.from-json: q<["something",{"quantity":12,"id":"9123-BBB"},"different",{"section":"B","chapter":"2.9b"}]>;
  for ^$deserialized.elems -> $idx {
      say "\n--- $idx ---";
      say "Deserialized before accessing? ", $deserialized[$idx]:has;
      say "Item: ", $deserialized[$idx].raku;
      say "Deserialized after accessing? ", $deserialized[$idx]:has;
  }

  ```

  Sample output:

  ```
  --- Initial    : ["something",{"chapter":"22.1","section":"S"},{"id":"EBCA-12F","quantity":13},"final"]
  --- Delete 2nd : Item2.new(section => "S", chapter => "22.1")
  --- 2nd deleted: ["something","removed",{"quantity":13,"id":"EBCA-12F"},"final"]

  --- 0 ---
  Deserialized before accessing? False
  ... deserializing [0] ...
  Item: "something"
  Deserialized after accessing? True

  --- 1 ---
  Deserialized before accessing? False
  ... deserializing [1] ...
  Item: Item1.new(id => "9123-BBB", quantity => 12)
  Deserialized after accessing? True

  --- 2 ---
  Deserialized before accessing? False
  ... deserializing [2] ...
  Item: "different"
  Deserialized after accessing? True

  --- 3 ---
  Deserialized before accessing? False
  ... deserializing [3] ...
  Item: Item2.new(section => "B", chapter => "2.9b")
  Deserialized after accessing? True

  ```

## Dictionary

* From <examples/simple-dictionary.raku>

  ```
  class Item1 is json {
      has Str $.id;
      has Int $.quantity;
  }

  class Item2 is json {
      has Str $.section;
      has Str $.chapter;
  }

  class JDict
      is json(
          :dictionary( Str:D, Item1:D, Item2:D, :default("<not there>") ) )
  {
      method json-deserialize-item(Mu \key, |) {
          say "... deserializing key '", key, "'";
          nextsame
      }
  }

  #my $jdict = JDict.new;
  my %jdict is JDict =
      "plain" => "string",
      "i1" => Item1.new(:id<AB12-EFZK>, :quantity(2));

  %jdict.push: "i2" => Item2.new(:section<D>, :chapter("66.6"));

  say "--- Initial        : ", %jdict.to-json;
  say "--- Delete i1      : ", %jdict<i1>:delete;
  say "--- Default is     : ", %jdict<this-never-been-here>;
  say "--- JSON without i1: ", %jdict.to-json;

  my $deserialized =
      JDict.from-json(
          q<{"sval":"some string","entry1":{"id":"FROM-JSON","quantity":0},"in":{"section":"DS","chapter":"43.2.1"}}>);

  for $deserialized.keys -> $key {
      say "\n--- Key '$key' ---";
      say "Deserialized before accessing? ", $deserialized{$key}:has;
      say "Value: ", $deserialized{$key};
      say "Deserialized after accessing? ", $deserialized{$key}:has;
  }

  ```

  Sample output:

  ```
  --- Initial        : {"plain":"string","i2":{"section":"D","chapter":"66.6"},"i1":{"id":"AB12-EFZK","quantity":2}}
  --- Delete i1      : Item1.new(id => "AB12-EFZK", quantity => 2)
  --- Default is     : <not there>
  --- JSON without i1: {"i2":{"section":"D","chapter":"66.6"},"plain":"string"}

  --- Key 'in' ---
  Deserialized before accessing? False
  ... deserializing key 'in'
  Value: Item2.new(section => "DS", chapter => "43.2.1")
  Deserialized after accessing? True

  --- Key 'sval' ---
  Deserialized before accessing? False
  ... deserializing key 'sval'
  Value: some string
  Deserialized after accessing? True

  --- Key 'entry1' ---
  Deserialized before accessing? False
  ... deserializing key 'entry1'
  Value: Item1.new(id => "FROM-JSON", quantity => 0)
  Deserialized after accessing? True

  ```

## Array Attributes

* From <examples/typed-array.raku>

  ```
  class Rec {
      has Str:D $.description is required;
  }

  class Struct is json(:implicit) {
      has Array[Real:D](Array:D)


## dist_zef-vrurg-JSON-Class.md
## Chunk 2 of 2
 @.matrix is json(:predicate);
      has Rec:D %.rec is json(:name<records>, :predicate);
  }

  my $struct =
      Struct.new:
          matrix => [
              [1, 2],
              [pi, e],
              [42.12, 13.666, 4321],
          ],
          rec => {
              R1 => Rec.new(:description("test description")),
              R2 => Rec.new(:description("test description 2")),
          };

  say "=== Serializing ===";
  say $struct.to-json(:pretty, :sorted-keys);

  say "=== Deserializing ===";
  my $deserialized =
      Struct.from-json:
          q<{"matrix":[[3,4,5],[3.141592653589793e0,2.718281828459045e0],[42.0,32.16,99]],
             "records":{"R1":{"description":"for the first"},"R2":{"description":"for the second"}}}>;

  say "Has .matrix: ", $deserialized.json-has-matrix;
  say "Has .rec   : ", $deserialized.json-has-records; # JSON key name is used for method name
  say "Matrix     : ", $deserialized.matrix;
  say "Has .matrix: ", $deserialized.json-has-matrix;
  say "Has .rec   : ", $deserialized.json-has-records;
  say "Records    : ", $deserialized.rec;
  say "Has .matrix: ", $deserialized.json-has-matrix;
  say "Has .rec   : ", $deserialized.json-has-records;

  ```

  Sample output:

  ```
  === Serializing ===
  {
    "matrix": [
      [
        1,
        2
      ],
      [
        3.141592653589793e0,
        2.718281828459045e0
      ],
      [
        42.12,
        13.666,
        4321
      ]
    ],
    "records": {
      "R1": {
        "description": "test description"
      },
      "R2": {
        "description": "test description 2"
      }
    }
  }
  === Deserializing ===
  Has .matrix: False
  Has .rec   : False
  Matrix     : [[3 4 5] [3.141592653589793 2.718281828459045] [42 32.16 99]]
  Has .matrix: True
  Has .rec   : False
  Records    : {R1 => Rec.new(description => "for the first"), R2 => Rec.new(description => "for the second")}
  Has .matrix: True
  Has .rec   : True

  ```

## Using Configuration And Type Mapping

These two subjects are tightly bound to each other, hence single example for both subjects.

* From <examples/config-and-type-map.raku>

  ```
  # To set global defaults .global to be invoked as early as possible or otherwise the global config can be vivified
  # somewhere else with standard defaults.
  JSON::Class::Config.global: :pretty, :sorted-keys, :!skip-null;

  class Record is json {
      has Int $.count;
      has Str $.what;
  }

  class Status {
      has Str $.code;
      has Bool $.verified;
      has Str $.notes;
  }

  # Indicate that this class wants to replace Record whenever possible.
  class RecWrapper is json-wrap(Record) {
      has Bool $.available is mooish(:lazy);

      method build-available {
          $.count > 0;
      }
  }

  class StatusTools is Status {
      # Just a mockup of what could be used for accessing some API, for example.
      method update-record {
          "will-update" => $.code
      }
  }

  JSON::Class::Config.map-types: RecWrapper, (Status) => StatusTools;

  class Foo is json {
      has Record:D $.record is required is json(:name<rec>);
      has Status:D $.status is required is json(:name<st>);
  }

  say "--- Using global config with type maps";
  my $foo =
      Foo.from-json:
          q<{"rec":{"count":0,"what":"irrelevant"},"st":{"code":"1A-CD3","verified":false,"notes":"to be done"}}>;

  say ".record attribute type: ", $foo.record.^name;
  say ".status attribute type: ", $foo.status.^name;

  $foo.status.update-record;

  say "Serialization of mapped types:\n", $foo.to-json.indent(2);

  say "--- Using custom config with no type maps";
  my $config = JSON::Class::Config.new;

  $foo = Foo.from-json:
              q<{"rec":{"count":0,"what":"irrelevant"},"st":{"code":"1A-CD3","verified":false,"notes":"to be done"}}>,
              :$config;

  say ".record attribute type: ", $foo.record.^name;
  say ".status attribute type: ", $foo.status.^name;

  try { $foo.status.update-record };
  say "We expect an exception here: ", $!.^name;
  say "Exception message: ", $!.message;

  say "Serialization with custom config using standard defaults:\n", $foo.to-json(:$config).indent(2);

  ```

  Sample output. Notice how different configuration defaults affect serialization output without passing any arguments to the `to-json` method:

  ```
  --- Using global config with type maps
  .record attribute type: RecWrapper
  .status attribute type: StatusTools
  Serialization of mapped types:
    {
      "rec": {
        "count": 0,
        "what": "irrelevant"
      },
      "st": {
        "code": "1A-CD3",
        "notes": "to be done",
        "verified": false
      }
    }
  --- Using custom config with no type maps
  .record attribute type: Record
  .status attribute type: Status
  We expect an exception here: X::Method::NotFound
  Exception message: No such method 'update-record' for invocant of type 'Status'
  Serialization with custom config using standard defaults:
    {"st":{"notes":"to be done","verified":false,"code":"1A-CD3"},"rec":{"what":"irrelevant","count":0}}

  ```

## Custom Serialziers And Deserializers

There are more than we can fit into this example. We can have individual custom marshalling for hash and array values, and hash keys too. We can specify marshallers for sequence elements too.

* From <examples/custom-marshallers.raku>

  ```
  class Record is json {
      has Str $.description is json( :serializer({ "pfx:" ~ $_ }),    # :to-json alias can be used instead
                                     :deserializer({ .substr(4) }) ); # :from-json can be used instead
  }

  class Article is json {
      has Str $.title;

      method serialize {
          %{ "-ttl-" => $!title }
      }
      method deserialize(%p) {
          die "bad profile" unless %p<-ttl->;
          self.new: title => %p<-ttl->;
      }
  }

  class Foo is json {
      has Record:D $.rec is required;
      has Article:D $.article is required;
  }

  my $config = JSON::Class::Config.new(:pretty, :sorted-keys);
  $config.set-helpers: Article, serializer => 'serialize', deserializer => 'deserialize';

  my $foo = Foo.new:
              rec => Record.new(:description("means nothing")),
              article => Article.new(:title("The Deep Thought: Complexity Of The Answer"));

  say "Custom serializers affect JSON:\n", $foo.to-json(:$config).indent(2);
  # "article" key is affected, but "rec" is using attribute's marshallizers.
  say "Serializing with default config:\n", $foo.to-json(:pretty, :sorted-keys).indent(2);

  $foo = Foo.from-json:
          q<{"rec":{"description":"pfx:stuff"},"article":{"-ttl-":"The Deep Thought: Gimme A Bit More Time"}}>,
          :$config;

  say "Custom deserializers handle 'weird' JSON:\n", $foo.raku.indent(2);

  ```

  Sample output:

  ```
  Custom serializers affect JSON:
    {
      "article": {
        "-ttl-": "The Deep Thought: Complexity Of The Answer"
      },
      "rec": {
        "description": "pfx:means nothing"
      }
    }
  Serializing with default config:
    {
      "article": {
        "title": "The Deep Thought: Complexity Of The Answer"
      },
      "rec": {
        "description": "pfx:means nothing"
      }
    }
  Custom deserializers handle 'weird' JSON:
    Foo.new(rec => Record.new(description => "stuff"), article => Article.new(title => "The Deep Thought: Gimme A Bit More Time"))

  ```

## Skipping Custom Marshalling

Here we use custom marshallers too, this time for array values. But there is a trick: serializer and deserializer do not modify every third value. To do so they call `json-I-cant` routine giving up the task to `JSON::Class`

* From <examples/skipping-marshalling.raku>

  ```
  my $skiped-serializations = 0;
  my $skipped-deserializations = 0;

  class Foo is json {
      has Int:D @.counts is json(
          :serializer(
              value => -> $v {
                  if $v % 3 == 0 {
                      ++$skiped-serializations;
                      json-I-cant
                  }
                  $v * 1000
              } ),
          :deserializer(
              value => -> $v {
                  if $v < 1000 {
                      ++$skipped-deserializations;
                      json-I-cant
                  }
                  $v div 1000
              } ));
  }

  my $foo = Foo.new(counts => ^22);

  my $json = $foo.to-json;

  say $json;
  say Foo.from-json($json);
  say "I skipped ", $skiped-serializations, " serializations and ", $skipped-deserializations, " deserializations";

  ```

  Sample output:

  ```
  {"counts":[0,1000,2000,3,4000,5000,6,7000,8000,9,10000,11000,12,13000,14000,15,16000,17000,18,19000,20000,21]}
  Foo.new(counts => Array[Int:D].new(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21))
  I skipped 8 serializations and 8 deserializations

  ```

# METHODS

## JSONified Class

* **`method to-json(:$config, Bool :$raw, Bool :$pretty, Bool :$sorted-keys, Bool :$enums-as-value, UInt :$spacing)`**

  Serialize an instance of JSON class. Arguments:

  * [`JSON::Class::Config:D`](docs/md/JSON/Class/Config.md) **`:$config`**, **`:%config`**

    Either a configuration object or a profile hash which will be used to create one.
  * `Bool` **`:$raw`**

    If *True* then the method will return raw serialization of the object, i.e. a [`Hash`](https://docs.raku.org/type/Hash).
  * `Bool` **`:$pretty`**, `Bool` **`:$sorted-keys`**, `Bool` **`:$enums-as-value`**, `UInt` **`:$spacing`**

    Same as [`JSON::Fast`](https://raku.land/cpan:TIMOTIMO/JSON::Fast) `to-json` arguments.
* **`proto method from-json(|)`**

  * **`method from-json(Str:D $json, :$config, Bool :$allow-jsonc, Bool :$enums-as-value)`**
  * **`method from-json(%json, :$config, Bool :$allow-jsonc, Bool :$enums-as-value)`**
  * **`method from-json(@json, :$config, Bool :$allow-jsonc, Bool :$enums-as-value)`**

  Deserialize JSON class from either a JSON string, or raw hash or array.

  * `Str:d` **`$json`**

    JSON source
  * **`%json`**, **`@json`**

    Deserialize from pre-parsed JSON data. A hash is only making sense for a JSON class. An array can be fed to both JSON class and JSON sequence; each will treat it differently.
  * `JSON::Class::Config:D` **`:$config`**, **`:%config`**

    Either a configuration object or a profile hash which will be used to create one.
  * `Bool` **`:$allow-jsonc`**, `Bool` **`:$enums-as-value`**

    Same as [`JSON::Fast`](https://raku.land/cpan:TIMOTIMO/JSON::Fast) `from-json` arguments.
* **`method json-serialize(JSON::Class::Config :$config)`**

  Implements the actual serialization task.
* **`method json-deserialize($from, JSON::Class::Config:D :$config)`**

  Implements the actual deserialization task. `$from` can be a hash or an array. JSON sequences only accept arrays.
* **`proto method json-serialize-value(|)`**

  Produce a value that can be immediately serialized by the underlying JSON module (think [`JSON::Fast`](https://raku.land/?q=JSON::Fast)). Say, for complex objects it would produce a hash; for an [`Enumeration`](https://docs.raku.org/type/Enumeration) it would return either its symbol name, or value, depending on [`JSON::Class::Config`](docs/md/JSON/Class/Config.md) `enums-as-value` parameter.

  This is a low-level method also used as a fallback when other means of serialization are not possible for whatever reason.

  * **`multi method json-serialize-value(Mu \value, *%nameds)`**

    Tries to serialize any kind of `value`. Any of `%nameds` are passed down the call chain to other candidates.
  * **`multi method json-serialize-value(Mu \target-type, Mu \value, JSON::Class::Config :$config, *%nameds)`**

    There are a few candidates with two-argument signature, responsible for serializing different kinds of `target-type`. These are somewhat specialized to serve `JSON::Class` internals. Yet, it is possible to introduce own candidates in a subclass if necessary.

    Some candidates are using the `$config` named argument. Any unknown arguments are passed down the call chain to other candidates.
* **`proto method json-deserialize-value(Mu \dest-type, Mu \json-value, JSON::Class::Config :$config)`**

  This is a low-level method to produce a `dest-type` object from a `json-value` which is one of [a JSON data type](https://en.wikipedia.org/wiki/JSON#Data_types), returned by `from-json` routine.
* **`method json-create(|)`**

  This method acts almost like `new`, but the difference is in what class it eventually creates. If it belongs to a run-time JSONified class, i.e. to one created by [`JSON::Class::Config`](docs/md/JSON/Class/Config.md) `jsonify` method, then `json-create` would return an instance of the original class, not its JSONification.

  Normally one doesn't need to use this method. But if it comes down to manually instantiating JSON classes then it would be preferred over the standard constructor.
* **`method clone-from(Mu $obj, *%twiddles)`**

  This method allows to create an instance of its class using attribute values of `$obj`. The point is that it makes it possible to have a copy of type different from that of `$obj`. `JSON::Class` uses it to JSONify instances of non-JSON classes, for example.

  *Note* that this is one of few methods whose names don't start with `json-` prefix.
* **`method json-all-set()`**

  Returns *True* if all postponed JSON data have been lazily deserialized.
* **`method json-config-class()`**

  Returns the default configuration class type object. Overridable.
* **`method json-config()`**

  Get the currently active configuration object if invoked within an active configuration context. Otherwise creates a new configuration context using class' defaults and returns its config.
* **`method json-config-context(&code, :$config, *%twiddles)`**

  Creates a new configuration context by pulling in defaults for the config from various sources. Invokes user `&code` with `$*JSON-CLASS-CONFIG` context variable set with a configuration object. [`JSON::Class::Details`](docs/md/JSON/Class/Details.md) has some more information on how configuration context gets built.

# SEE ALSO

* [`JSON::Class::Details`](docs/md/JSON/Class/Details.md)
* [`JSON::Class::Config`](docs/md/JSON/Class/Config.md)
* [`JSON::Class::Descriptor`](docs/md/JSON/Class/Descriptor.md)
* [`JSON::Class::Object`](docs/md/JSON/Class/Object.md)
* [`JSON::Class::Dict`](docs/md/JSON/Class/Dict.md)
* [`JSON::Class::Sequence`](docs/md/JSON/Class/Sequence.md)
* [`JSON::Class::Types`](docs/md/JSON/Class/Types.md)
* [`Changes`](ChangeLog.md)
* [`INDEX`](INDEX.md)

# COPYRIGHT

(c) 2023, Vadim Belman [vrurg@cpan.org](mailto:vrurg@cpan.org)

# LICENSE

Artistic License 2.0

See the [*LICENSE*](LICENSE) file in this distributio


## dist_zef-witawayar-Pyrint.md
## Pyrint

Print like a Pythoneer: a `&pyrint` subroutine with `sep` and `end` keyword arguments which otherwise behaves as `&say`

```
use Pyrint;

# Arguments are separated by a space by default
say    3, 4, 5;  # 345\n
pyrint 3, 4, 5;  # 3 4 5\n

# Can specify how to separate them
pyrint "Id", "Date", "Value", sep => ", ";  # Id, Date, Value\n

# Also what to put at the end (newline by default)
pyrint "Tab", "after", "these", end => "\t";  # Tab after these\t

```

### .WHY, .WHAT

I sometimes find myself frustrated when the arguments to `&say` are printed by concatenating them together, with no space in between (same applies for `&put` and `&print` too). Less often occurs is to customize what to print after the arguments, which is newline by default but I remember needing, e.g., tabs instead. So, to this end, we mimic Python's `print` built-in with its `sep` and `end` keyword arguments to customize separation and ending in printing.

Only one subroutine is exported: `&pyrint`, with signature `(*@args, :$sep = " ", :$end = "\n")`. It is imported by default, i.e., available with `use Pyrint;` but if wanted, can also specify with a tag, i.e., `use Pyrint :pyrint;` to better see in a large program what comes from where. It calls `.gist` on the arguments to print like the built-in `&say`.

#### Installation

Using [pakku](https://github.com/hythm7/Pakku):

```
pakku add Pyrint

```


## dist_github-scmorrison-AWS-Pricing.md
# AWS::Pricing [Build Status](https://travis-ci.org/scmorrison/perl6-aws-pricing)

# Description

Return, and cache, current offers from the AWS Price List API.

# Usage

```
aws-pricing - Pull AWS Pricing data from the AWS Pricing API

USAGE

    aws-pricing services
    aws-pricing service-offers <service_code>;
    aws-pricing service-codes
    aws-pricing regions
    aws-pricing version

COMMANDS

    services           Return Service Offer index
    service-offers     Return Service Offers for specific service code and/or region
    service-codes      List all valid service codes
    regions            List all valid regions
    version            Display aws-pricing version

OPTIONS

    service-offers specific

    --format           json|csv Default json
    --region           Filter AWS region to pull offer data
    --header           Display the CSV header. Disabled by default

FLAGS

    --refresh          Force cache_dir refresh
    --cache_path       Path to cache path service offer files (Default ~/.aws-pricing)
    --quiet            No output, cache only (services, service-offers)

```

# CLI

## List services

```
# Return Service Offer Index
aws-pricing services

# Refresh local cache
aws-pricing --refresh services

# Refresh local cache, no output
aws-pricing --refresh --quiet services

```

## List service offers

```
# Default json format
aws-pricing service-offers AmazonEC2

# Output csv format
aws-pricing --format=csv service-offers AmazonEC2

# Output csv format with headers
aws-pricing --headers --format=csv service-offers AmazonEC2

# Refresh local cache
aws-pricing --refresh --format=csv service-offers AmazonEC2

# Refresh local cache, no output
aws-pricing --refresh --quiet --format=csv service-offers AmazonEC2

```

## List valid Service Codes

```
aws-pricing service-codes

```

## List valid Regions

```
aws-pricing regions

```

## Print aws-pricing version

```
aws-pricing version

```

# Modules and utilities

## AWS::Pricing

```
use AWS::Pricing;

my $config = AWS::Pricing::config(
    refresh    => True,
    cache_path => '~/.aws-pricing'  # Default path
);

# Service Offer Index JSON
AWS::Pricing::services;

# Service Offer Indexes with custom config
AWS::Pricing::services config => $config;

# Service Codes List
AWS::Pricing::service-codes;

# Regions List
AWS::Pricing::regions;

# Service Offers: All regions
AWS::Pricing::service-offers(service_code => 'AmazonEC2');

# Service Offers: Single region
AWS::Pricing::service-offers(
    service_code => 'AmazonEC2',
    region       => 'us-west-1'
);

# Service Offers: Single region, config, csv, region
AWS::Pricing::service-offers(
    config          => $config,
    service_code    => 'AmazonS3',
    format          => 'csv',
    region          => 'eu-west-1',
    display_header  => True
);

```

### Valid service codes:

* AmazonS3
* AmazonGlacier
* AmazonSES
* AmazonRDS
* AmazonSimpleDB
* AmazonDynamoDB
* AmazonEC2
* AmazonRoute53
* AmazonRedshift
* AmazonElastiCache
* AmazonCloudFront
* awskms
* AmazonVPC

### Valid regions

* us-east-1
* us-east-2
* us-west-1
* us-west-2
* eu-west-1
* ap-southeast-1
* ap-southeast-2
* ap-northeast-1
* ap-northeast-2
* sa-east-1
* eu-central-1
* us-gov-west-1
* ap-south-1
* ca-central-1
* eu-west-2

# Installation

Install directly with zef:

```
zef install AWS::Pricing

```

# Testing

To run tests:

```
$ prove -e "perl6 -Ilib"

```

# Todo

* ~~Cache offer files, these are large~~
* Search offers (must cache first)
* Tests

# See also

* <http://docs.aws.amazon.com/awsaccountbilling/latest/aboutv2/price-changes.html>

# Authors

* Sam Morrison

# Copyright and license

Copyright 2015 Sam Morrison

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


## dist_cpan-MELEZHIK-Sparrowform.md
# Synopsis

[Sparrowdo](https://github.com/melezhik/sparrowdo) provision for [Terraform](https://www.terraform.io) backed instances.

[![asciicast](https://asciinema.org/a/158919.png)](https://asciinema.org/a/158919)

# Install

```
$ zef install Sparrowform

```

# Limitations

Currently only ***ssh accessed instances with public IPs are supported*** ( aws ec2 / google compute instances with public IPs ).

Terrafrom resources supported:

* [aws\_instances](https://www.terraform.io/docs/providers/aws/r/instance.html)
* [google\_compute\_instance](https://www.terraform.io/docs/providers/google/r/compute_instance.html)

Ping me if you need more Terraform resourses support.

# Usage

## Write some Terraform scenarios and deploy some instances

```
$ terraform apply

```

## Create Sparrowodo scenarios, one per instance

Scenarios should be named as `$terrafrom-instance-type.$terraform-instance-ID.sparrowfile`

```
$ nano aws_instance.example.sparrowfile
$ nano aws_instance.example2.sparrowfile
$ nano aws_instance.example3.sparrowfile
# ...

```

See also [Sparrowdo one liners option](#using-sparrowdo-one-liners-instead-of-scenarios)
on how to run sparrowdo tasks/modules not scenarios.

## Run Sparrowdo provision

This command will run Sparrowdo scenarios for all instances for which files `$terrafrom-instance-ID.sparrowfile` exist:

```
$ sparrowform

```

## Handling ssh connections

You may pass ssh connection parameters by specifying [sparrowdo cli](https://github.com/melezhik/sparrowdo#sparrowdo-client-command-line-parameters) parameters:

```
$ sparrowform --ssh_user=ec2-user --ssh_private_key=/path/to/ssh.key

```

## Using [sparrowdo one liners](https://github.com/melezhik/sparrowdo#--module_run) instead of scenarios:

```
# install Nginx on all instances:
$ sparrowform --module_run=Nginx

# check if Nginx alive on all instances:
$ sparrowform --task_run=bash@command='"ps uax|grep nginx"'

# install packages
$ sparrowform --task_run=package-generic@list="'nano mc'"

```

## Default Sparrowdo scenario

If you don't want bother with creating scenarios for every instance, you may choose to defined *default* scenario.

Create scenario named `sparrowfile`:

```
$ nano sparrowfile

bash "apt-get update";

```

So, these instances which do not have a related Sparrowdo scenarios files will use this *default* scenario.

## Terraform resources access

Sparrowform exposes nice API to access Terraform internal guts inside Sparrowdo scenarios.

The function `tf-resources` returns Perl6 Array of all Terraform resources.
Each elements consists of two elements, the first one holds resource identificator, the
second one holds resource data, represented as Perl6 Hash.

Here is usage example:

```
$ cat sparrowfile

# let's insert all ec2 instances DNS names into ever instance's /etc/hosts file:

use Sparrowform;

my @hosts = (
  "127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4",
  "::1         localhost localhost.localdomain localhost6 localhost6.localdomain6"
);

for tf-resources() -> $r {
  my $rd = $r[1]; # resource data
  next unless $rd<public_ip>;
  next unless $rd<public_dns>;
  next if $rd<public_ip> eq input_params('Host');
  push @hosts, $rd<public_ip> ~ ' ' ~ $rd<public_dns>;
}

file '/etc/hosts', %(
  action  => 'create',
  content => @hosts.join("\n")
);

```

## Debugging

If something goes awry ... Enable SPF\_DEBUG variable to see internal output:

```
$ SPF_DEBUG=1 sparrowform

```

## Dry run

If you only want to see which instances would be deployed, run with SPG\_DRYRUN enabled:

```
$ SPF_DRYRUN=1 sparrowform

```

# Author

Alexey Melezhik

# See also

* [Sparrowdo](https://github.com/melezhik/sparrowdo)
* [Terraform](https://www.terraform.io)


## uniparse.md
uniparse

Combined from primary sources listed below.

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

See primary documentation
[in context](/type/Str#routine_uniparse)
for **routine uniparse**.

```raku
sub    uniparse(Str:D $names  --> Str:D)
method uniparse(Str:D $names: --> Str:D)
```

Takes string with comma-separated Unicode names of characters and returns a string composed of those characters. Will [`fail`](/routine/fail) if any of the characters' names are empty or not recognized. Whitespace around character names is ignored.

```raku
say "I {uniparse 'TWO HEARTS'} Raku"; # OUTPUT: «I 💕 Raku␤»
'TWO HEARTS, BUTTERFLY'.uniparse.say; # OUTPUT: «💕🦋␤»
```

See [uniname](/routine/uniname) and [uninames](/routine/uninames) for routines that work in the opposite direction with a single codepoint and multiple codepoints respectively.

Note that unlike `\c[...]` construct available in string interpolation, `uniparse` does not accept decimal numerical values. Use [chr](/routine/chr) routine to convert those:

```raku
say "\c[1337]"; # OUTPUT: «Թ␤»
say '1337'.chr; # OUTPUT: «Թ␤»
```

*Note:* before being standardized in 2017.12, this routine was known under its working name of [parse-names](/routine/parse-names). This denomination will be removed in the 6.e version.

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

See primary documentation
[in context](/type/Cool#method_uniparse)
for **method uniparse**.

```raku
method uniparse(Cool:D: --> Str:D)
```

Available as of the 2021.04 release of the Rakudo compiler.

Coerces the invocant to a [`Str`](/type/Str) and then calls the [uniparse](/type/Str#routine_uniparse) on that. This mostly only makes sense for [`Match`](/type/Match) objects.


## dist_cpan-LEONT-Protocol-Postgres.md
[![Actions Status](https://github.com/Leont/protocol-postgres/workflows/test/badge.svg)](https://github.com/Leont/protocol-postgres/actions)

# Name

Protocol::Postgres - a sans-io postgresql client

# Synopsis

```
use v6.d;
use Protocol::Postgres;

my $socket = await IO::Socket::Async.connect($host, $port);
my $client = Protocol::Postgres::Client.new;
$socket.Supply(:bin).act({ $client.incoming-data($^data) });
$client.outbound-data.act({ $socket.write($^data) });

await $client.startup($user, $database, $password);

my $resultset = await $client.query('SELECT * FROM foo WHERE id = $1', [ 42 ]);
react {
	whenever $resultset.hash-rows -> (:$name, :$description, :$id) {
		say "$name is $description";
	}
}

```

# Description

Protocol::Postgres is sans-io implementation of (the client side of) the postgresql protocol. It is typically used through the `Protocol::Postgres::Client` class.

# Client

`Protocol::Postgres::Client` has the following methods

## new(--> Protocol::Postgres::Client)

This creates a new postgres client. It supports one optional named argument:

* TypeMap :$typemap = TypeMap::JSON

  This is the typemap that is used to translate between Raku's and Postgres' typesystem. The default mapping supports common built-in types such as strings, numbers, bools, dates, datetimes, blobs, arrays and hashes. Other options include `TypeMap::Native` if you want arrays to map to postgres' native arrays and `TypeMap::Minimal` if one wants all values to map to strings.

## outgoing-data(--> Supply)

This returns a `Supply` of `Blob`s to be written to the server.

## incoming-data(Blob --> Nil)

This consumes bytes received from the server.

## startup($user, $database?, $password? --> Promise)

This starts the handshake to the server. `$database` may be left undefined, the server will use `$user` as database name. If a `$password` is defined, any of clearnext, md5 or SCRAM-SHA-256 based authentication is supported.

The resulting promise will finish when the connection is ready for queries.

## query($query, @bind-values --> Promise)

This will issue a query with the given bind values, and return a promise to the result.

For fetching queries such as `SELECT` the result in the promise will be a `ResultSet` object, for manipulation (e.g. `INSERT`) and definition (e.g. `CREATE`) queries it will result a string describing the change (e.g. `DELETE 3`). For a `COPY FROM` query it will `Supply` with the data stream, and for `COPY TO` it will be a `Supplier`.

Both the input types and the output types will be typemapped between Raku types and Postgres types using the typemapper.

## query-multiple($query --> Supply[ResultSet])

This will issue a complex query that may contain multiple statements, but can not use bind values. It will return a `Supply` to the results of each query.

## prepare($query, :@input-types --> Promise[PreparedStatement])

This prepares the query, and returns a Promise to the PreparedStatement object. `@input-types` can be used to pass on hints about the types you're passing in during `execute`.

## startTls(--> Blob)

This will return the marker that should be written to the server to start upgrading the connection to use TLS. If the server responds with a single `S` byte the proposal is accepted and the client is expected to initiate the TLS handshake. If the server responds with an `N` it is rejected, and the connection proceeds in cleartext.

## terminate(--> Nil)

This sends a message to the server to terminate the connection

## notifications(--> Supply[Notification])

This returns a supply with all notifications that the current connection is subscribed to. Channels can be subscribed using the `LISTEN` command, and messages can be sent using the `NOTIFY` command.

## disconnected(--> Promise)

This returns a `Promise` that must be be kept or broken to signal the connection is lost.

## process-id(--> Int)

This returns the process id of the backend of this connection. This is useful for debugging purposes and for notifications.

## get-parameter(Str $name --> Str)

This returns various parameters, currently known parameters are: `server_version`, `server_encoding`, `client_encoding`, `application_name`, `default_transaction_read_only`, `in_hot_standby`, `is_superuser`, `session_authorization`, `DateStyle`, `IntervalStyle`, `TimeZone`, `integer_datetimes`, and `standard_conforming_strings`.

# ResultSet

A `Protocol::Postgres::ResultSet` represents the results of a query, if any.

## columns(--> List)

This returns the column names for this resultset.

## rows(--> Supply[List])

This returns a Supply of rows. Each row is a list of values.

## hash-rows(--> Supply[Hash])

This returns a Supply of rows. Each row is a hash with the column names as keys and the row values as values.

# PreparedStatement

A `Protocol::Postgres::PreparedStatement` represents a prepated statement. Its reason of existence is to call `execute` on it.

## execute(@arguments --> Promise[ResultSet])

This runs the prepared statement, much like the `query` method would have done.

## close()

This closes the prepared statement.

## columns()

This returns the columns of the result once executed.

# Notification

`Protocol::Postgres::Notification` has the following methods:

## sender(--> Int)

This is the process-id of the sender

## channel(--> Str)

This is the name of the channel that the notification was sent on

## message(--> Str)

This is the message of the notification

# Author

Leon Timmermans [fawaka@gmail.com](mailto:fawaka@gmail.com)

# Copyright and License

Copyright 2022 Leon Timmermans

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


## dist_cpan-ALOREN-Terminal-Table.md
Advanced table generate module for raku lang

![Build
Status](https://travis-ci.org/araraloren/raku-terminal-table.svg?branch=master)

![Windows Build
Status](https://ci.appveyor.com/api/projects/status/sbgq8vt0775fu1pk/branch/master?svg=true)

# Description

Terminal::Table provides a simple and also a advance way generate table
output in terminals. It support multi line table cell. You can create
your own style for your table, and you can colour your table content.
Also the module has common style pre-defined.

# Usage

[中文帮助](README.zh.adoc)

## Interface

### High Level Interface

The simple way to use `Terminal::Table` is use API below:

These subs want a two-dimension array of string. It uses pre-defined
style. Default is `Style::Default::ASCII`, also you can their low case
name such as 'ascii'.

* print-table(@data, @max-widths = [],
  :$style=Style::Default::ASCII)

  Print table to stdout.
* array-to-table(@data, @max-widths = [],
  :$style=Style::Default::ASCII)

  Return an array contain table data;
* create-generator(@data, :$style=Style::Default::ASCII);

  Return an generator base on the `@data`.

#### Pre-defined Style

```
enum Style::Default  is export <<
    :NONE('none')
    :ASCII('ascii')
    :SPACE('space')
    :DOT('dot')
    :SINGLE('single')
    :DOUBLE('double')
    :ROUND('round')
    :OTHER('other') # other is use for self-defined-style
>>;

```

## Example

### High Level Interface

```
use Terminal::Table;

my @data = [
    [ "Language", "Example" ],
    [ "Chinese",  "你吃饭了吗？\n你好！\n你从哪里来？" ],
    [ "English",  "Nice to meet you!\nWhere are you from?" ],
    [ "Janpanese","ありがとうございます。\nいただきます！"],
    [ "Korean",   "안녕하세요！"],
];

print-table(@data);

```

It will output:

![output for high-level-api](resources/output1.png)

### Low Level Interface

```
#!/usr/bin/env raku

use v6;
use Terminal::Table::Generator;
use Terminal::Table::Style;

my $g = Generator.new(
    style => Style.new(
        corner-style => Style::Corner.double(),
        line-style => Style::Line.double(),
        content-style => Style::Content.space(),
    )
);

$g.add-cell('Language');
$g.add-cell('Example');
$g.add-cell('Country');
$g.end-line;
$g.add-cell('Chinese');
$g.add-cell("你吃饭了吗？\n你好！\n你从哪里来？");
$g.add-cell('China');
$g.end-line;
$g.add-cell('Janpanese');
$g.add-cell('
ありがとうございます。
いただきます！');
$g.add-cell('Janpa');
$g.end-line;
$g.add-cell('English');
$g.add-cell('Nice to meet you!
Are you ok?
Where are you from ?');
$g.add-cell('American、England、Australian .etc');
$g.end-line;
$g.add-cell('Korean');
$g.add-cell('안녕하세요！');
$g.add-cell('Korea');
$g.end-line;
$g.generator().generate().print();

```

It will output:

![output for low-level-api](resources/output2.png)

### Generator join and colour

Terminal::Table use
[Terminal::ANSIColor](https://github.com/tadzik/Terminal-ANSIColor) for
colour process.

```
#!/usr/bin/env raku

use Terminal::Table::Style;
use Terminal::Table::Generator;

my $gl = Generator.new(
    style => Style.new(
        corner-style => Style::Corner.double(),
        line-style   => Style::Line.double(),
        content-style=> Style::Content.space(),
    )
);

for 1 .. 9 -> \x {
    for 1 .. x -> \y {
        $gl.add-cell("{y} x {x} = {x * y}");
    }
    $gl.end-line();
}

my $gr = Generator.new(
    style => Style.new(
        corner-style => Style::Corner.single(),
        line-style   => Style::Line.dot(),
        content-style=> Style::Content.space(),
    )
);

my @data;

for reverse 1 .. 9 -> \x {
    @data.push([ "{.Int} x {x} = {x * .Int}" for 1 .. x ]);
}

$gr.from-array(@data);
$gl.join($gr, :replace-style);

my $g = $gl.generator().generate();

$g.colour(0, 0, Color::String.new(color => <blue bold> ));
$g.colour(8, $_, Color::String.new(color => <red bold> )) for ^9;
$g.colour(9, $_, Color::String.new(color => <green bold> )) for ^9;
$g.print(:coloured);

```

It will output:

![output for join-and-colour](resources/output3.png)

### Irregular shape

```
#!/usr/bin/env raku

use v6;
use Terminal::Table;

constant SIZE = 22;

my $g = create-generator([
    'C' xx SIZE,
    'C' xx SIZE,
    'C' xx SIZE,
    'C' xx SIZE,
    'C' xx SIZE,
    'C' xx SIZE,
    'C' xx SIZE,
]);

$g.generate;

my &hide = -> $x, $y {
    my ($r, $c) = ($g.row-count() * 2, $g.col-count($x) * 2);
    my ($rx, $ry) = ($x * 2, $y * 2);

    my $top = $rx == 0 || $g.is-hidden($rx - 1, $ry + 1);
    my $top-left = ($rx == 0 || $ry == 0) || $g.is-hidden($rx - 1, $ry - 1);
    my $top-right = ($rx == 0 || $ry + 2 == $c) || $g.is-hidden($rx - 1, $ry + 3);
    my $bottom = ($rx + 2 == $r) || $g.is-hidden($rx + 3, $ry + 1);
    my $bottom-left = ($rx + 2 == $r || $ry == 0) || $g.is-hidden($rx + 3, $ry - 1);
    my $bottom-right = ($rx + 2 == $r || $ry + 2 == $c) || $g.is-hidden($rx + 3, $ry + 3);
    my $left = $ry == 0 || $g.is-hidden($rx + 1, $ry - 1);
    my $right = ($ry + 2 == $c) || $g.is-hidden($rx + 1, $ry + 3);

    if $top && $top-left && $left {
        $g.hide($rx, $ry, :replace-with-space);
    }
    if $top {
        $g.hide($rx, $ry + 1, :replace-with-space);
    }
    if $top && $top-right && $right {
        $g.hide($rx, $ry + 2, :replace-with-space);
    }
    if $left {
        $g.hide($rx + 1, $ry, :replace-with-space);
    }
    if $right {
        $g.hide($rx + 1, $ry + 2, :replace-with-space);
    }
    if $left && $bottom-left && $bottom {
        $g.hide($rx + 2, $ry, :replace-with-space);
    }
    if $bottom {
        $g.hide($rx + 2, $ry + 1, :replace-with-space);
    }
    if $right && $bottom-right && $bottom {
        $g.hide($rx + 2, $ry + 2, :replace-with-space);
    }
    $g.hide($rx + 1, $ry + 1, :replace-with-space);
};

&hide(1, 13 + $_) for ^8;
&hide($_, 13) for 2 .. 5;
&hide($_, 14) for 2 .. 5;
&hide(5, 13 + $_) for ^8;
&hide($_, 20) for 3 .. 4;
&hide($_, 19) for 3 .. 4;
&hide(3, 15 + $_) for ^5;

&hide(1, 3 + $_) for ^8;
&hide($_, 3) for 2 .. 5;
&hide($_, 4) for 2 .. 5;
&hide($_, 10) for 2 .. 3;
&hide($_, 9) for 2 .. 3;
&hide(3, 4 + $_) for ^6;
&hide(5, 2 + $_) for ^4;

$g.print;

```

It will output:

![output for irregular shape](resources/output4.png)

### more

For more usage, check out sample or POD document.

# Installation

## From source

```
git clone https://github.com/araraloren/raku-terminal-table

cd raku-terminal-table && git checkout v0.0.1 && zef install .

```

## From zef

```
zef update && zef install Terminal::Table

```

# License

```
The MIT License (MIT).

```

# Author

```
Araraloren. Email: blackcatoverwall@gmail.com

```

# TODO

```
None

```


## dist_github-AlexDaniel-App-OrgSleep.md
# orgsleep

Use Emacs Org-mode to graph your sleeping pattern.

![my graph](https://raw.githubusercontent.com/AlexDaniel/orgsleep/master/examples/graph.png)

## ⚠ Warning ⚠

**This software is alpha-quality!** The script was written to produce
nice graphs for my own org file and it will give garbage if you feed
it less than a few years of data.

The reason for raster images (instead of SVGs) is that it is hard
to render thousands of lines and not have them rendered in a smudgy
way. Raster images on 100% zoom always look perfect, anything else
will typically look bad.

The script does pixel-banging, which is arguably easier than trying to
force matplotlib or gnuplot to render 1-pixel lines. In fact, there
were matplotlib *and* gnuplot versions of orgsleep, but they were only
adequate before I surpassed a 2-year milestone. I'm still looking for a
better solution, please let me know if there's something.

## Usage

This command was used to generate the [example](examples/):

```
bin/orgsleep '--title=Sleeping pattern of an average AlexDaniel' \
             '--subtitle=Sample size: 1'                          \
             '--out=examples/graph.png'                            \
             examples/sleep.org

```

Use your own org file to plot your data.

## Dependencies

You must have `Image::Magick` Perl5 module installed. On Debian-based systems use:

```
sudo apt install libimage-magick-perl

```


## dist_zef-jonathanstowe-Attribute-Lazy.md
# Attribute::Lazy

Lazy attribute initialisation for Raku classes

![Build Status](https://github.com/jonathanstowe/Attribute-Lazy/workflows/CI/badge.svg)

## Synopsis

```

use Attribute::Lazy;

class Foo {
    has $.foo will lazy { "zub" };
}

```

## Description

This is based on an experimental trait that was briefly in the Rakudo core.

Attribute::Lazy provides a single *trait* *will lazy* that will allow
an attribute with a public accessor (that is one defined with the "." twigil,)
to be initialised *the first time it is accessed* by the result of the supplied
block. This might be useful if the value may not be used and may be expensive
to calculate (or various other reasons that haven't been thought of.)

For convenience the block is passed the object instance as a single argument.

## Installation

Assuming you have a working Rakudo Raku installation you should be able to install this with *zef* :

```
# From the source directory

zef install .

# Remote installation

zef install Attribute::Lazy

```

Other install mechanisms may be become available in the future.

## Support

Suggestions/patches are welcomed via github at <https://github.com/jonathanstowe/Attribute-Lazy/issues>

## Licence

Please see the <LICENCE> file in the distribution

© Rakudo Contributors 2015
© Jonathan Stowe 2016-2021


## dist_zef-jjmerelo-Pod-Load.md
[![Build
status](https://ci.appveyor.com/api/projects/status/lq9rqjq6hljdfqw4?svg=true)](https://ci.appveyor.com/project/JJ/p6-pod-load)
[![Test in a Raku container](https://github.com/JJ/p6-pod-load/actions/workflows/test.yaml/badge.svg)](https://github.com/JJ/p6-pod-load/actions/workflows/test.yaml)

# NAME

Pod::Load - Loads and compiles the Pod documentation of an external file

# SYNOPSIS

```
use Pod::Load;
use X::Pod::Load::SourceErrors;

# Try to parse a string
say pod-load(<<EOP).raku;
=head1 Header

=head2 Another header
EOP

# Read a file handle.
my $pod = load("file-with.pod6".IO);
say $pod.raku; # Process it as a Pod

# Or use simply the file name
my @pod = load("file-with.pod6");
say .raku for @pod;

# Or a string
@pod = load("=begin pod\nThis could be a comment with C<code>\n=end pod");

# Or ditch the scaffolding and use the string directly:
@pod = load-pod("This could be a comment with C<code>");

# If there's an error, it will throw X::Pod::Load::SourceErrors

```

# DESCRIPTION

Pod::Load is a module with a simple task: obtain the documentation of an
external file in a standard, straighworward way.

Its mechanism was originally inspired by
[`Pod::To::BigPage`](https://github.com/perl6/perl6-pod-to-bigpage), from where
the code to use the cache was taken from.

### multi sub load

```
multi sub load(
    Str $string
) returns Mu

```

Loads a string, returns a Pod.

### multi sub load

```
multi sub load(
    Str $file where { ... }
) returns Mu

```

If it's an actual filename, loads a file and returns the pod

### multi sub load

```
multi sub load(
    IO::Path $io
) returns Mu

```

Loads a IO::Path, returns a Pod.

## INSTALL

Do the usual:

```
zef install .

```

to install this if you've made any modification.

# AUTHOR

JJ Merelo [jjmerelo@gmail.com](mailto:jjmerelo@gmail.com), with help from [Richard Hainsworth](https://github.com/finanalyst)

# COPYRIGHT AND LICENSE

Copyright 2018, 2019, 2020 JJ Merelo

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


## dist_cpan-LEONT-Auth-SCRAM-Async.md
[![Actions Status](https://github.com/Leont/auth-scram-async/workflows/test/badge.svg)](https://github.com/Leont/auth-scram-async/actions)

# NAME

Auth::SCRAM::Async - Salted Challenge Response Authentication Mechanism

# SYNOPSIS

```
use Auth::SCRAM::Async;

my $client = Auth::SCRAM::Async::Client.new(:$username, :$password, :type(Auth::SCRAM::Async::SHA256));
my $client-first = $client.first-message;
send-message($client-first);

my $server-first = read-response();
with $client.final-message($server-first) -> $client-final {
	send-message($client-final);

	my $server-final = read-response();
	say "success" if $client.validate($server-final);
}

```

# Description

This implements the Salted Challenge Response Authentication Mechanism.

# Client

A client can be found as `Auth::SCRAM::Async::Client`. It has the following methods:

## new

This creates a new Auth::SCRAM::Async::Client object. Every handshake should use a fresh object.

```
* Str :$username

  Authentication identity. This will be normalized with the SASLprep algorithm before being transmitted to the server. This argument is mandatory.

* Str :$password

  Authentication password. This will be normalized with the SASLprep algorithm before being transmitted to the server. This argument is mandatory.

* Str :$authorization-id

  If the authentication identity (username) will act as a different, authorization identity, this attribute provides the authorization identity. It is optional. If not provided, the authentication identity is considered by the server to be the same as the authorization identity.

* Auth::SCRAM::Async::Digest :$digest

  Identifier of a digest function. Valid values are `Auth::SCRAM::Async::SHA1`, `Auth::SCRAM::Async::SHA256`, `Auth::SCRAM::Async::SHA384`, or `Auth::SCRAM::Async::SHA512`. This argument is mandatory.

* Int :$minimum_iteration_count

  If the server requests an iteration count less than this value, the client will reject it. This protects against downgrade attacks. The default is 4096, consistent with recommendations in the RFC.

* Int :$nonce-bits

  Size of the client-generated nonce, in bits. Defaults to `192`. The server-nonce will be appended, so the final nonce size will be substantially larger.

```

## first-message(--> Str)

This will return the opening message of a SCRAM handshake

## final-message(Str $server-first --> Str)

This will process the first response from the server, and will generate the second message from the client.

## validate(Str $server-final --> Bool)

This will validate the final response from the server, validating that they too know the shared secret.

# Todo

* Implement server side SCRAM.
* Implement channel bindings.

# See also

* [RFC5802](https://datatracker.ietf.org/doc/html/rfc5802) - Salted Challenge Response Authentication Mechanism (SCRAM) SASL and GSS-API Mechanisms
* [RFC7677](https://datatracker.ietf.org/doc/html/rfc7677) - SCRAM-SHA-256 and SCRAM-SHA-256-PLUS Simple Authentication and Security Layer (SASL) Mechanisms

# Author

Leon Timmermans [fawaka@gmail.com](mailto:fawaka@gmail.com)

# Copyright and License

Copyright 2022 Leon Timmermans

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


## dist_github-tokuhirom-Test-Base.md
[![Build Status](https://travis-ci.org/tokuhirom/p6-Test-Base.svg?branch=master)](https://travis-ci.org/tokuhirom/p6-Test-Base)

# NAME

Test::Base - Data driven development for Perl6

# SYNOPSIS

```
    use v6;
    use Test;

    use Test::Base;

    for blocks($=finish) {
        is EVAL($_<input>), .expected;
    }

    done-testing;

    =finish

    === simple
    --- input: 3+2
    --- expected: 5

    === more
    --- input: 4+2
    --- expected: 6

```

# DESCRIPTION

Test::Base is a port of ingy's perl5 Test::Base for Perl6.

# FUNCTIONS

* `blocks(Str $src)`

Parse `$src` as a data source and returns test data.

# AUTHOR

Tokuhiro Matsuno [tokuhirom@gmail.com](mailto:tokuhirom@gmail.com)

# COPYRIGHT AND LICENSE

Copyright 2015 Tokuhiro Matsuno

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


## dist_cpan-CTILMES-Gcrypt.md
# Raku Gcrypt - Bindings for GNU Libgcrypt

[![Build Status](https://travis-ci.org/CurtTilmes/raku-libgcrypt.svg)](https://travis-ci.org/CurtTilmes/raku-libgcrypt)

* [Introduction](#introduction)
* [Message Digest (Hash)](#message-digest-hash)
* [Symmetric cryptography ciphers](#symmetric-cryptography-ciphers)
* [Random](#random)
* [Passphrase](#passphrase)
* [libgcrypt versions/features](#libgcrypt-versionsfeatures)
* [Multi-threading](#multi-threading)
* [Installation](#installation)
* [License](#license)

## Introduction

A [Raku](https://raku.org/) interface to
[libgcrypt](https://gnupg.org/software/libgcrypt/).

```
Libgcrypt is a general purpose cryptographic library originally
based on code from GnuPG. It provides functions for all
cryptograhic building blocks: symmetric cipher algorithms (AES,
Arcfour, Blowfish, Camellia, CAST5, ChaCha20 DES, GOST28147,
Salsa20, SEED, Serpent, Twofish) and modes
(ECB,CFB,CBC,OFB,CTR,CCM,GCM,OCB,POLY1305,AESWRAP), hash
algorithms (MD2, MD4, MD5, GOST R 34.11, RIPE-MD160, SHA-1,
SHA2-224, SHA2-256, SHA2-384, SHA2-512, SHA3-224, SHA3-256,
SHA3-384, SHA3-512, SHAKE-128, SHAKE-256, TIGER-192, Whirlpool),
MACs (HMAC for all hash algorithms, CMAC for all cipher
algorithms, GMAC-AES, GMAC-CAMELLIA, GMAC-TWOFISH, GMAC-SERPENT,
GMAC-SEED, Poly1305, Poly1305-AES, Poly1305-CAMELLIA,
Poly1305-TWOFISH, Poly1305-SERPENT, Poly1305-SEED), and
random numbers.

```

**Note, this is still a work in progress, more features may or may not
be forthcoming!! Patches welcome!!**

# Usage

## Message Digest (Hash)

A [message digest or cryptographic hash
function](https://en.wikipedia.org/wiki/Cryptographic_hash_function)
is a function that maps data of arbitrary size to a bit string of
fixed size, the hash or digest.

```
use Gcrypt::Simple :MD5;       # Import routines you specify, or use :ALL for all

say MD5('Some text').hex;      # 9db5682a4d778ca2cb79580bdb67083f

say MD5(slurp).hex;            # print md5sum of STDIN

my $obj = MD5;                 # Get a new object
$obj.write("$_\n") for lines;  # Incremental calculation

say $obj.digest;               # Blob
say $obj.hex;                  # Hex string
say $obj.dec;                  # Decimal
say $obj.hex(:reset);          # Each of these can take :reset to reset the obj

$obj.reset;                    # or call reset to Reuse object on another message

```

Available Hashes:

MD5 SHA1 RIPEMD160 TIGER SHA256 SHA384 SHA512 SHA224 MD4 CRC32
CRC32\_RFC1510 CRC24\_RFC2440 WHIRLPOOL TIGER1 TIGER2 GOSTR3411\_94
STRIBOG256 STRIBOG512 SHA3\_224 SHA3\_256 SHA3\_384 SHA3\_512 SHAKE128
SHAKE256 BLAKE2B\_512 BLAKE2B\_384 BLAKE2B\_256 BLAKE2B\_160 BLAKE2S\_256
BLAKE2S\_224 BLAKE2S\_160 BLAKE2S\_128

See [Available hash algorithms](https://gnupg.org/documentation/manuals/gcrypt/Available-hash-algorithms.html) for more details on each algorithm.

Note that SHAKE128 and SHAKE256 are extendable-output functions (XOF),
and can produce variable amounts of output. Pass in the number of
bytes you want to `digest`, `hex` or `dec`:

```
use Gcrypt::Simple :SHAKE128;
say SHAKE128('Some text').hex(16);

```

## Message Authentication Codes (MAC)

A [message authentication
code](https://en.wikipedia.org/wiki/Message_authentication_code) is a
short code used to authenticate that a message came from the stated
sender (its authenticity) and has not been changed.

To create one, you need a key and the message.

```
use Gcrypt::Simple :HMAC_MD5;       # Select algorithm, or :ALL for all

say HMAC_MD5('mykey', 'my message').hex;
# f50357b6299b741cf6b1c63073e54112

my $obj = HMAC_MD5('mykey');        # Create object
$obj.write('my message');           # Add data
say $obj.MAC;                       # Blob
say $obj.hex;                       # Hex string
say $obj.hex(:reset);               # Can also pass :reset to MAC or hex
$obj.reset;                         # or reset to reuse object on another message

```

Key is truncated or 0 extended to the size for the algorithm.
(`$obj.keylen` will tell you the algorithm's key size).

Available MAC algorithms:

HMAC\_SHA256 HMAC\_SHA224 HMAC\_SHA512 HMAC\_SHA384 HMAC\_SHA1 HMAC\_MD5
HMAC\_MD4 HMAC\_RIPEMD160 HMAC\_TIGER HMAC\_WHIRLPOOL HMAC\_GOSTR3411\_94
HMAC\_STRIBOG256 HMAC\_STRIBOG512 HMAC\_SHA3\_224 HMAC\_SHA3\_256
HMAC\_SHA3\_384 HMAC\_SHA3\_512 CMAC\_AES CMAC\_3DES CMAC\_Camellia
CMAC\_CAST5 CMAC\_Blowfish CMAC\_Twofish CMAC\_Serpent CMAC\_SEED
CMAC\_RFC2268 CMAC\_IDEA CMAC\_GOST28147 GMAC\_AES GMAC\_Camellia
GMAC\_Twofish GMAC\_Serpent GMAC\_SEED POLY1305

See [Available MAC algorithms](https://gnupg.org/documentation/manuals/gcrypt/Available-MAC-algorithms.html) for more details on each algorithm.

## Symmetric cryptography ciphers

```
use Gcrypt::Simple :IDEA;

my $key = 'foobar';
my $encrypted = IDEA($key).encrypt('Some text');
say IDEA($key).decrypt($encrypted);

my $obj = IDEA($key);                       # Create object
my $encrypted = $obj.encrypt('Some text');
$obj.reset;                                 # Reuse object
say $obj.decrypt($encrypted);

```

Available Ciphers:

IDEA DES3 CAST5 Blowfish AES AES192 AES256
Twofish RC4 DES Twofish128 Serpent128 Serpent192
RFC2268\_40 SEED Camellia128 Camellia192 Camellia256
Salsa20 Salsa20R12 GOST28147 ChaCha20

See [Available ciphers](https://gnupg.org/documentation/manuals/gcrypt/Available-ciphers.html) for more details on each algorithm.

## Random

```
use Gcrypt::Random;

my $rand = random(10);
# Buf[uint8].new(148,229,159,236,230,13,154,226,245,23)
my $rand = random(10, :weak);           # actually the same as strong
my $rand = random(10, :strong);         # default
my $rand = random(10, :very-strong);    # stronger
my $rand = nonce(10);                   # Actually weak, but unpredictable

```

Returns a buffer of random bytes.

See [Quality of random numbers](https://gnupg.org/documentation/manuals/gcrypt/Quality-of-random-numbers.html) for more information.

## Passphrase

Derive a key from a string

```
use Gcrypt::Passphrase;

my $passphrase = "This is a long and complicated passphrase.";

my $key = key-from-passphrase($passphrase,
                              keysize => 16,
                              algorithm => 'SIMPLE_S2K',
                              subalgorithm => 'SHA1');

$key = key-from-passphrase($passphrase,
                           keysize => 64,
                           algorithm => 'ITERSALTED_S2K',
                           subalgorithm => 'SHA512',
                           iterations => 12,
                           salt => 'abcdefgh');

```

See [Key Derivation](https://gnupg.org/documentation/manuals/gcrypt/Key-Derivation.html) for more information.

# libgcrypt versions/features

You can check the version by calling `Gcrypt.version` which returns
the version as a string:

```
use Gcrypt;
say Gcrypt.version;   # '1.7.6beta' or '1.8.1' or whatever

```

You can query the library for its capabilities with `Gcrypt.config`:

```
use Gcrypt;
say Gcrypt.config;               # Get all configuration
say Gcrypt.config('ciphers');    # List available ciphers
say Gcrypt.config('digests');    # List available digests

```

NOTE: `config` has a known problem on CentOS and is likely not to work.

# Multi-threading

Most Gcrypt actions are thread-safe.

The error strings use a static memory buffer, so make sure only one
thread is printing out an `Exception` message at a time. You can use
the exception's integer `code` safely.

# Installation

Many distributions already have libgcrypt installed, but if not, get it
first:

* For debian or ubuntu: `apt install libgcrypt20`
* For alpine: `apk add libgcrypt`
* For CentOS: `yum install libgcrypt`

Then `zef install Gcrypt`

# License

This work is subject to the Artistic License 2.0.

See <LICENSE> for more information.


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

# NAME

CLI::Ecosystem - Raku® Programming Language Ecosystem Inspector

# SYNOPSIS

```
$ ecosystem dis Foo --verbose
Distributions that match Foo and their frequency
--------------------------------------------------------------------------------
App::Football (6x)
Foo (3x)
WebService::FootballData (5x)

```

# DEPRECATION NOTICE

This distribution has basically been superseded by the [`App::Ecosystems`](https://raku.land/zef:lizmat/App::Ecosystems) distribution which provides a better user experience by providing a dedicated prompt from which to peruse an ecosystem, thereby being able to keep more state, and thus have less startup time.

# DESCRIPTION

CLI::Ecosystem installs the `ecosystem` CLI script that allows introspection of Raku Programming Language's Ecosystem Content Storage.

Named arguments that are always available:

```
--ecosystem  the Ecosystem Content Storage to be used.
             rea | fez | p6c | cpan, default: rea
--verbose    boolean, show extended information, default: False

```

Named arguments that are available in search and informational queries:

```
--ver   the :ver<>  value to use, default: none
--auth  the :auth<> value to use, default: none
--api   the :api<>  value to use, default: 0
--from  the :from<> value to use, default: Raku

```

Search queries (also looks in description):

```
us  use-target <string>  use targets for optional string
di  distro <string>      distribution names for optional string
i   identity <string>    identities for optional string

```

Informational queries:

```
de  dependencies string          dependencies for given string
re  reverse-dependencies string  reverse dependencies for given string
m   meta string key(s)           META information for given string

```

Other queries:

```
ri  river <--top>          most referenced modules
unr unresolvable <--from>  unresolvable dependencies, include <:from>?
unv unversioned            distributions without valid version

```

All subcommands can be shortened as long as they are unique.

# AUTHOR

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

Source can be located at: <https://github.com/lizmat/CLI-Ecosystem> . 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 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-rawleyfowler-Net-Gemini.md
# Net::Gemini

Client/Server implementation of the Gemini protocol, including an API for creating responses. (No API for requests as they're just strings).

## How to use

#### Client

```
use Net::Gemini;

my $client = Net::Gemini::Client('gemini://gemini.website.space') # Defaults port to 1965, specify port if you want.
react {
    whenever $client {
        say $_; # You'll see the response here!
    }
}

```

#### Server

##### File Server

```
use Net::Gemini;

my $domain = 'www.bob.com';
my $port = 1965; # This is defaulted if not provided
my $cert-file = 'cert.pem'; # TLS is required for Gemini, so you need a cert file and priv-key
my $cert-key-file = 'priv-key.pem';
Net::Gemini::Server.new(:$domain, :$port, :$cert-file, :$cert-key-file).listen;
# This will serve .gmi and .gmni files from $*CWD/public
# If you include index.gmi in the directory you'll see it become available on the root route.

```

##### Custom Handler Server

```
use Net::Gemini;

# Same as file server
my $domain = 'www.bob.com';
my $port = 1965; # This is defaulted if not provided
my $cert-file = 'cert.pem'; # TLS is required for Gemini, so you need a cert file and priv-key
my $cert-key-file = 'priv-key.pem';

# Custom handler for requests.
sub my-handler(Str $request --> Net::Gemini::Response) {
    # There are some generic/pre-built functions for generating responses in
    # Response.rakumod, these help a lot!
    if $request eq ('gemini://www.bob.com/') {
        Net::Gemini::Response::make-generic-redirect-response(31, 'gemini://www.bob.com/redirect');
    } else {
        Net::Gemini::Response::make-resource-response('awesome-page.gmi'); # In this case let's just always serve
    }
}

# Alternatively, if you understand the Gemini protocol you can build response using the Net::Gemini::Response class.

Net::Gemini::Server.new(:$domain, :$port, :$cert-file, :$cert-key-file).listen(&my-handler);

```

## License

This project is available under the Artistic-2.0 license, the same as Raku.