UmweltDocs
Recipes/The masquerade

The masquerade

Everyone at the ball knows the thief by a different name. Midnight takes the masks off, and dawn takes her title.

Marcocaptain of the guard

Before midnight“the woman in the silver mask”
After the unmaskingLivia Veyalso “the woman in the silver mask”

Nicothe fence, has never met her

Before midnight“the fox”
After the unmasking“the fox”

Gemmaher maid

Before midnightCountess Livia Vey
After the unmaskingCountess Livia Vey

The Dukethe host

Before midnight“the woman in the silver mask”knows her title: Countess
After the unmaskingCountess Livia Veyalso “the woman in the silver mask”

What each guest can call the thief, from entity.asKnownBy at eleven o’clock and at midnight. One entity, one id, four ways of knowing her.

The idea

In a disguise story the same person has many names, and who may use which one is the plot. Umwelt keeps one entity with one id, and treats every name as a claim: canon says what she is called, and each guest holds only the names they were given. Ask for her by any guest, at any hour, and you get the name that guest could say.

You write

  • one entity for the thief
  • the names canon gives her, over time
  • which names each guest learned, and when
  • the decree that takes her title

Umwelt answers

  • her name, title and aliases at any hour
  • what a guest can call her, from their own Holdings
  • whether they have ever met her
  • a title cleared by a negated Fact

The ball

Palazzo Vey, a masquerade. Livia Vey, a countess with debts, has come for the Duke’s emerald. In the thieves’ quarter she is “the fox”. Tonight she is a woman in a silver mask.

At eleven the emerald is gone. At midnight the masks come off in front of the Duke and his captain. At dawn, the Duke strips her of her title.

Names are claims

Three reserved predicates carry names: umwelt:name and umwelt:title, one at a time, and umwelt:alias, as many as you like. Canon states them as Facts; each guest gets Holdings for the names they know, and an Awareness record if they have met her.

palazzo.ts
// Names are claims with reserved predicates: umwelt:name, umwelt:title, umwelt:alias.
const name = (value: string) => claim.value('livia', 'umwelt:name', value);
const title = (value: string, polarity = true) => claim.value('livia', 'umwelt:title', value, { polarity });
const alias = (value: string) => claim.value('livia', 'umwelt:alias', value);
// Meeting her is Awareness: knowing she exists, nothing about her.
const meets = (id: string, holder: string): RecordInput => ({ kind: 'awareness', id, holder, target: 'livia' });

// Before the ball: who she is, and who already knows her by what.
await client.commit({
  projectId, attemptId: 'before',
  event: { id: 'before', type: 'backstory', title: 'Before the ball', position: at(0), participants: ['livia', 'nico', 'gemma', 'duke'], provenance },
  records: [
    fact(name('Livia Vey'), { id: 'canon-name' }),
    fact(title('Countess'), { id: 'canon-title' }),
    fact(alias('the fox'), { id: 'canon-fox' }),
    knows('nico', alias('the fox'), witnessed('before'), { id: 'nico-fox' }),
    knows('gemma', name('Livia Vey'), witnessed('before'), { id: 'gemma-name' }),
    knows('gemma', title('Countess'), witnessed('before'), { id: 'gemma-title' }),
    meets('gemma-met', 'gemma'),
    knows('duke', title('Countess'), witnessed('before'), { id: 'duke-title' }),
    meets('duke-met', 'duke'),
  ],
});
// Arrivals: the guard sees a guest in a silver mask, and that is all he sees.
await client.commit({
  projectId, attemptId: 'arrivals',
  event: { id: 'arrivals', type: 'scene', title: 'The guests arrive', position: at(1), participants: ['livia', 'marco', 'duke'], provenance },
  records: [
    fact(alias('the woman in the silver mask'), { id: 'canon-mask' }),
    knows('marco', alias('the woman in the silver mask'), witnessed('arrivals'), { id: 'marco-mask' }),
    meets('marco-met', 'marco'),
    knows('duke', alias('the woman in the silver mask'), witnessed('arrivals'), { id: 'duke-mask' }),
  ],
});
Program.cs
// Names are claims with reserved predicates: umwelt:name, umwelt:title, umwelt:alias.
Claim Name(string value) => Claim.Value("livia", "umwelt:name", value);
Claim Title(string value, bool polarity = true) => Claim.Value("livia", "umwelt:title", value, polarity);
Claim Alias(string value) => Claim.Value("livia", "umwelt:alias", value);
// Meeting her is Awareness: knowing she exists, nothing about her.
RecordInput Meets(string id, string holder) => new RecordInput.Awareness { Id = id, Holder = holder, Target = "livia" };

// Before the ball: who she is, and who already knows her by what.
engine.Commit(new CommitInput
{
    ProjectId = projectId, AttemptId = "before",
    Event = new EventInput { Id = "before", Type = "backstory", Title = "Before the ball", Position = Position.At(0), Participants = new() { "livia", "nico", "gemma", "duke" }, Provenance = provenance },
    Records = new()
    {
        Records.Fact(Name("Livia Vey"), id: "canon-name"),
        Records.Fact(Title("Countess"), id: "canon-title"),
        Records.Fact(Alias("the fox"), id: "canon-fox"),
        Records.Knows("nico", Alias("the fox"), Acquired.Witnessed("before"), id: "nico-fox"),
        Records.Knows("gemma", Name("Livia Vey"), Acquired.Witnessed("before"), id: "gemma-name"),
        Records.Knows("gemma", Title("Countess"), Acquired.Witnessed("before"), id: "gemma-title"),
        Meets("gemma-met", "gemma"),
        Records.Knows("duke", Title("Countess"), Acquired.Witnessed("before"), id: "duke-title"),
        Meets("duke-met", "duke"),
    },
});
// Arrivals: the guard sees a guest in a silver mask, and that is all he sees.
engine.Commit(new CommitInput
{
    ProjectId = projectId, AttemptId = "arrivals",
    Event = new EventInput { Id = "arrivals", Type = "scene", Title = "The guests arrive", Position = Position.At(1), Participants = new() { "livia", "marco", "duke" }, Provenance = provenance },
    Records = new()
    {
        Records.Fact(Alias("the woman in the silver mask"), id: "canon-mask"),
        Records.Knows("marco", Alias("the woman in the silver mask"), Acquired.Witnessed("arrivals"), id: "marco-mask"),
        Meets("marco-met", "marco"),
        Records.Knows("duke", Alias("the woman in the silver mask"), Acquired.Witnessed("arrivals"), id: "duke-mask"),
    },
});

Midnight and dawn

The unmasking is a witnessed claim: everyone present now holds her name. The decree is a negated title, which clears it.

palazzo.ts
// Eleven o'clock: the emerald goes. Midnight: the masks come off, before the Duke and the guard.
await client.commit({
  projectId, attemptId: 'theft',
  event: { id: 'theft', type: 'scene', title: 'The emerald is gone', position: at(2), participants: ['livia'], provenance },
  records: [fact(claim.entity('livia', 'stole', 'emerald'), { id: 'canon-theft' })],
});
await client.witness({
  projectId, attemptId: 'midnight',
  event: { id: 'midnight', type: 'scene', title: 'Midnight: the masks come off', position: at(3), participants: ['livia', 'marco', 'duke'], provenance },
  claims: [{ claim: name('Livia Vey') }],
  witnesses: [{ holder: 'marco' }, { holder: 'duke' }],
});
// Dawn: stripped of her title. A negated latest title clears it.
await client.commit({
  projectId, attemptId: 'dawn',
  event: { id: 'dawn', type: 'decree', title: 'The Duke’s decree', position: at(4), participants: ['duke'], provenance },
  records: [fact(title('Countess', false), { id: 'canon-stripped' })],
});
Program.cs
// Eleven o'clock: the emerald goes. Midnight: the masks come off, before the Duke and the guard.
engine.Commit(new CommitInput
{
    ProjectId = projectId, AttemptId = "theft",
    Event = new EventInput { Id = "theft", Type = "scene", Title = "The emerald is gone", Position = Position.At(2), Participants = new() { "livia" }, Provenance = provenance },
    Records = new() { Records.Fact(Claim.Entity("livia", "stole", "emerald"), id: "canon-theft") },
});
engine.Witness(new WitnessInput
{
    ProjectId = projectId, AttemptId = "midnight",
    Event = new EventInput { Id = "midnight", Type = "scene", Title = "Midnight: the masks come off", Position = Position.At(3), Participants = new() { "livia", "marco", "duke" }, Provenance = provenance },
    Claims = new() { new WitnessedClaim { Claim = Name("Livia Vey") } },
    Witnesses = new() { new Witness { Holder = "marco" }, new Witness { Holder = "duke" } },
});
// Dawn: stripped of her title. A negated latest title clears it.
engine.Commit(new CommitInput
{
    ProjectId = projectId, AttemptId = "dawn",
    Event = new EventInput { Id = "dawn", Type = "decree", Title = "The Duke’s decree", Position = Position.At(4), Participants = new() { "duke" }, Provenance = provenance },
    Records = new() { Records.Fact(Title("Countess", polarity: false), id: "canon-stripped") },
});

Ask the guests

palazzo.ts
// What each guest can call her, before and after midnight.
const cards: Record<string, unknown[]> = {};
for (const holder of ['marco', 'nico', 'gemma', 'duke']) {
  cards[holder] = [];
  for (const tick of [2, 3]) {
    const known = await client.entityAsKnownBy({ projectId, entityId: 'livia', holder, at: { tick } });
    cards[holder].push({ tick, name: known.name ?? null, title: known.title ?? null, aliases: known.aliases, aware: known.aware });
  }
}
print('cards', cards);

// What canon calls her, at the ball and after the decree.
for (const tick of [1, 4]) {
  const canon = await client.entityAt({ projectId, entityId: 'livia', at: { tick } });
  print(`canon-${tick}`, { name: canon.name, title: canon.title ?? null, aliases: canon.aliases });
}
await client.close();
Program.cs
// What each guest can call her, before and after midnight.
var cards = new Dictionary<string, List<object>>();
foreach (var holder in new[] { "marco", "nico", "gemma", "duke" })
{
    cards[holder] = new();
    foreach (var tick in new long[] { 2, 3 })
    {
        var known = engine.EntityAsKnownBy(new EntityKnownPayload { ProjectId = projectId, EntityId = "livia", Holder = holder, At = new At { Tick = tick } });
        cards[holder].Add(new { tick, name = known.Name, title = known.Title, aliases = known.Aliases, aware = known.Aware });
    }
}
Print("cards", cards);

// What canon calls her, at the ball and after the decree.
foreach (var tick in new long[] { 1, 4 })
{
    var canon = engine.EntityAt(new EntityAtPayload { ProjectId = projectId, EntityId = "livia", At = new At { Tick = tick } });
    Print($"canon-{tick}", new { name = canon.Name, title = canon.Title, aliases = canon.Aliases });
}
What each guest can call her
{
  "marco": [
    {
      "tick": 2,
      "name": null,
      "title": null,
      "aliases": ["the woman in the silver mask"],
      "aware": true
    },
    {
      "tick": 3,
      "name": "Livia Vey",
      "title": null,
      "aliases": ["the woman in the silver mask"],
      "aware": true
    }
  ],
  "nico": [
    {
      "tick": 2,
      "name": null,
      "title": null,
      "aliases": ["the fox"],
      "aware": false
    },
    {
      "tick": 3,
      "name": null,
      "title": null,
      "aliases": ["the fox"],
      "aware": false
    }
  ],
  "gemma": [
    {
      "tick": 2,
      "name": "Livia Vey",
      "title": "Countess",
      "aliases": [],
      "aware": true
    },
    {
      "tick": 3,
      "name": "Livia Vey",
      "title": "Countess",
      "aliases": [],
      "aware": true
    }
  ],
  "duke": [
    {
      "tick": 2,
      "name": null,
      "title": "Countess",
      "aliases": ["the woman in the silver mask"],
      "aware": true
    },
    {
      "tick": 3,
      "name": "Livia Vey",
      "title": "Countess",
      "aliases": ["the woman in the silver mask"],
      "aware": true
    }
  ]
}

Nico knows her as “the fox” and has never met her: aware is false. Gemma knew her name all along. The captain only learns it at midnight.

What canon calls her

entity.at, the ball
{
  "name": "Livia Vey",
  "title": "Countess",
  "aliases": ["the fox", "the woman in the silver mask"]
}
entity.at, after the decree
{
  "name": "Livia Vey",
  "title": null,
  "aliases": ["the fox", "the woman in the silver mask"]
}

Nobody is told a name by canon. Canon calls her Countess Livia Vey from the start. Until midnight the captain still has no name for her, because he holds none.

Try next

A false nameLet her give the captain an alias that canon never uses, with a deceptive transmit.
Dialogue that fitsFill each guest’s lines with the name entity.asKnownBy returns for them.
Your game’s idsRegister the guests with entity.ensureBatch and their ids from your game.
Who suspects herGive the captain a suspects Holding that she stole the emerald, and check what he can accuse her of.

The whole program

One file that builds the world, runs it and prints every answer on this page. The TypeScript program and the .NET one print the same answers: the script that runs them for these pages checks it.

palazzo.ts
import { at, by, claim, createClient, fact, knows, witnessed } from '@kallamo/umwelt';
import type { RecordInput } from '@kallamo/umwelt';
const client = createClient({ file: 'palazzo.umw', create: true });
const projectId = 'palazzo';
const provenance = by.human();
const print = (label: string, value: unknown) => console.log(`@@${label}\n${JSON.stringify(value)}`);

// The engine's own record of Livia is one id and one stored name. What anyone calls her is another matter.
// The world, declared once: sending the same manifest again changes nothing.
await client.worldEnsure({
  project: { id: projectId, name: 'The masquerade at Palazzo Vey', timescale: 'hour' },
  entityTypes: [
    { id: 'person', name: 'Person', kind: 'agent' },
    { id: 'thing', name: 'Thing', kind: 'other' },
  ],
  entities: [
    { id: 'livia', typeId: 'person', name: 'Livia Vey' },
    { id: 'marco', typeId: 'person', name: 'Marco, captain of the guard' },
    { id: 'nico', typeId: 'person', name: 'Nico, the fence' },
    { id: 'gemma', typeId: 'person', name: 'Gemma, her maid' },
    { id: 'duke', typeId: 'person', name: 'The Duke' },
    { id: 'emerald', typeId: 'thing', name: 'The Duke’s emerald' },
  ],
  predicates: [
    { id: 'stole', label: 'stole', object: 'entity', cardinality: 'many' },
  ],
});
// Names are claims with reserved predicates: umwelt:name, umwelt:title, umwelt:alias.
const name = (value: string) => claim.value('livia', 'umwelt:name', value);
const title = (value: string, polarity = true) => claim.value('livia', 'umwelt:title', value, { polarity });
const alias = (value: string) => claim.value('livia', 'umwelt:alias', value);
// Meeting her is Awareness: knowing she exists, nothing about her.
const meets = (id: string, holder: string): RecordInput => ({ kind: 'awareness', id, holder, target: 'livia' });

// Before the ball: who she is, and who already knows her by what.
await client.commit({
  projectId, attemptId: 'before',
  event: { id: 'before', type: 'backstory', title: 'Before the ball', position: at(0), participants: ['livia', 'nico', 'gemma', 'duke'], provenance },
  records: [
    fact(name('Livia Vey'), { id: 'canon-name' }),
    fact(title('Countess'), { id: 'canon-title' }),
    fact(alias('the fox'), { id: 'canon-fox' }),
    knows('nico', alias('the fox'), witnessed('before'), { id: 'nico-fox' }),
    knows('gemma', name('Livia Vey'), witnessed('before'), { id: 'gemma-name' }),
    knows('gemma', title('Countess'), witnessed('before'), { id: 'gemma-title' }),
    meets('gemma-met', 'gemma'),
    knows('duke', title('Countess'), witnessed('before'), { id: 'duke-title' }),
    meets('duke-met', 'duke'),
  ],
});
// Arrivals: the guard sees a guest in a silver mask, and that is all he sees.
await client.commit({
  projectId, attemptId: 'arrivals',
  event: { id: 'arrivals', type: 'scene', title: 'The guests arrive', position: at(1), participants: ['livia', 'marco', 'duke'], provenance },
  records: [
    fact(alias('the woman in the silver mask'), { id: 'canon-mask' }),
    knows('marco', alias('the woman in the silver mask'), witnessed('arrivals'), { id: 'marco-mask' }),
    meets('marco-met', 'marco'),
    knows('duke', alias('the woman in the silver mask'), witnessed('arrivals'), { id: 'duke-mask' }),
  ],
});
// Eleven o'clock: the emerald goes. Midnight: the masks come off, before the Duke and the guard.
await client.commit({
  projectId, attemptId: 'theft',
  event: { id: 'theft', type: 'scene', title: 'The emerald is gone', position: at(2), participants: ['livia'], provenance },
  records: [fact(claim.entity('livia', 'stole', 'emerald'), { id: 'canon-theft' })],
});
await client.witness({
  projectId, attemptId: 'midnight',
  event: { id: 'midnight', type: 'scene', title: 'Midnight: the masks come off', position: at(3), participants: ['livia', 'marco', 'duke'], provenance },
  claims: [{ claim: name('Livia Vey') }],
  witnesses: [{ holder: 'marco' }, { holder: 'duke' }],
});
// Dawn: stripped of her title. A negated latest title clears it.
await client.commit({
  projectId, attemptId: 'dawn',
  event: { id: 'dawn', type: 'decree', title: 'The Duke’s decree', position: at(4), participants: ['duke'], provenance },
  records: [fact(title('Countess', false), { id: 'canon-stripped' })],
});
// What each guest can call her, before and after midnight.
const cards: Record<string, unknown[]> = {};
for (const holder of ['marco', 'nico', 'gemma', 'duke']) {
  cards[holder] = [];
  for (const tick of [2, 3]) {
    const known = await client.entityAsKnownBy({ projectId, entityId: 'livia', holder, at: { tick } });
    cards[holder].push({ tick, name: known.name ?? null, title: known.title ?? null, aliases: known.aliases, aware: known.aware });
  }
}
print('cards', cards);

// What canon calls her, at the ball and after the decree.
for (const tick of [1, 4]) {
  const canon = await client.entityAt({ projectId, entityId: 'livia', at: { tick } });
  print(`canon-${tick}`, { name: canon.name, title: canon.title ?? null, aliases: canon.aliases });
}
await client.close();
Program.cs
using System.Text.Json;
using System.Text.Json.Serialization;
using Kallamo.Umwelt;
using var engine = UmweltEngine.Create("palazzo.umw");
const string projectId = "palazzo";
var provenance = Provenance.Human();
var json = new JsonSerializerOptions
{
    DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
    Converters = { new JsonStringEnumConverter(JsonNamingPolicy.KebabCaseLower) },
};
void Print(string label, object? value) => Console.WriteLine($"@@{label}\n{JsonSerializer.Serialize(value, json)}");

// The engine's own record of Livia is one id and one stored name. What anyone calls her is another matter.
// The world, declared once: sending the same manifest again changes nothing.
engine.WorldEnsure(new EnsureWorldInput
{
    Project = new WorldProject { Id = projectId, Name = "The masquerade at Palazzo Vey", Timescale = "hour" },
    EntityTypes = new()
    {
        new WorldEntityType { Id = "person", Name = "Person", Kind = EntityKind.Agent },
        new WorldEntityType { Id = "thing", Name = "Thing", Kind = EntityKind.Other },
    },
    Entities = new()
    {
        new WorldEntity { Id = "livia", TypeId = "person", Name = "Livia Vey" },
        new WorldEntity { Id = "marco", TypeId = "person", Name = "Marco, captain of the guard" },
        new WorldEntity { Id = "nico", TypeId = "person", Name = "Nico, the fence" },
        new WorldEntity { Id = "gemma", TypeId = "person", Name = "Gemma, her maid" },
        new WorldEntity { Id = "duke", TypeId = "person", Name = "The Duke" },
        new WorldEntity { Id = "emerald", TypeId = "thing", Name = "The Duke’s emerald" },
    },
    Predicates = new()
    {
        new PredicateDef { Id = "stole", Label = "stole", Object = ObjectKind.Entity, Cardinality = Cardinality.Many },
    },
});
// Names are claims with reserved predicates: umwelt:name, umwelt:title, umwelt:alias.
Claim Name(string value) => Claim.Value("livia", "umwelt:name", value);
Claim Title(string value, bool polarity = true) => Claim.Value("livia", "umwelt:title", value, polarity);
Claim Alias(string value) => Claim.Value("livia", "umwelt:alias", value);
// Meeting her is Awareness: knowing she exists, nothing about her.
RecordInput Meets(string id, string holder) => new RecordInput.Awareness { Id = id, Holder = holder, Target = "livia" };

// Before the ball: who she is, and who already knows her by what.
engine.Commit(new CommitInput
{
    ProjectId = projectId, AttemptId = "before",
    Event = new EventInput { Id = "before", Type = "backstory", Title = "Before the ball", Position = Position.At(0), Participants = new() { "livia", "nico", "gemma", "duke" }, Provenance = provenance },
    Records = new()
    {
        Records.Fact(Name("Livia Vey"), id: "canon-name"),
        Records.Fact(Title("Countess"), id: "canon-title"),
        Records.Fact(Alias("the fox"), id: "canon-fox"),
        Records.Knows("nico", Alias("the fox"), Acquired.Witnessed("before"), id: "nico-fox"),
        Records.Knows("gemma", Name("Livia Vey"), Acquired.Witnessed("before"), id: "gemma-name"),
        Records.Knows("gemma", Title("Countess"), Acquired.Witnessed("before"), id: "gemma-title"),
        Meets("gemma-met", "gemma"),
        Records.Knows("duke", Title("Countess"), Acquired.Witnessed("before"), id: "duke-title"),
        Meets("duke-met", "duke"),
    },
});
// Arrivals: the guard sees a guest in a silver mask, and that is all he sees.
engine.Commit(new CommitInput
{
    ProjectId = projectId, AttemptId = "arrivals",
    Event = new EventInput { Id = "arrivals", Type = "scene", Title = "The guests arrive", Position = Position.At(1), Participants = new() { "livia", "marco", "duke" }, Provenance = provenance },
    Records = new()
    {
        Records.Fact(Alias("the woman in the silver mask"), id: "canon-mask"),
        Records.Knows("marco", Alias("the woman in the silver mask"), Acquired.Witnessed("arrivals"), id: "marco-mask"),
        Meets("marco-met", "marco"),
        Records.Knows("duke", Alias("the woman in the silver mask"), Acquired.Witnessed("arrivals"), id: "duke-mask"),
    },
});
// Eleven o'clock: the emerald goes. Midnight: the masks come off, before the Duke and the guard.
engine.Commit(new CommitInput
{
    ProjectId = projectId, AttemptId = "theft",
    Event = new EventInput { Id = "theft", Type = "scene", Title = "The emerald is gone", Position = Position.At(2), Participants = new() { "livia" }, Provenance = provenance },
    Records = new() { Records.Fact(Claim.Entity("livia", "stole", "emerald"), id: "canon-theft") },
});
engine.Witness(new WitnessInput
{
    ProjectId = projectId, AttemptId = "midnight",
    Event = new EventInput { Id = "midnight", Type = "scene", Title = "Midnight: the masks come off", Position = Position.At(3), Participants = new() { "livia", "marco", "duke" }, Provenance = provenance },
    Claims = new() { new WitnessedClaim { Claim = Name("Livia Vey") } },
    Witnesses = new() { new Witness { Holder = "marco" }, new Witness { Holder = "duke" } },
});
// Dawn: stripped of her title. A negated latest title clears it.
engine.Commit(new CommitInput
{
    ProjectId = projectId, AttemptId = "dawn",
    Event = new EventInput { Id = "dawn", Type = "decree", Title = "The Duke’s decree", Position = Position.At(4), Participants = new() { "duke" }, Provenance = provenance },
    Records = new() { Records.Fact(Title("Countess", polarity: false), id: "canon-stripped") },
});
// What each guest can call her, before and after midnight.
var cards = new Dictionary<string, List<object>>();
foreach (var holder in new[] { "marco", "nico", "gemma", "duke" })
{
    cards[holder] = new();
    foreach (var tick in new long[] { 2, 3 })
    {
        var known = engine.EntityAsKnownBy(new EntityKnownPayload { ProjectId = projectId, EntityId = "livia", Holder = holder, At = new At { Tick = tick } });
        cards[holder].Add(new { tick, name = known.Name, title = known.Title, aliases = known.Aliases, aware = known.Aware });
    }
}
Print("cards", cards);

// What canon calls her, at the ball and after the decree.
foreach (var tick in new long[] { 1, 4 })
{
    var canon = engine.EntityAt(new EntityAtPayload { ProjectId = projectId, EntityId = "livia", At = new At { Tick = tick } });
    Print($"canon-{tick}", new { name = canon.Name, title = canon.Title, aliases = canon.Aliases });
}

More recipes

Was this page helpful?