domingo, 3 de agosto de 2025

UEFN Verse: Sync (Time Flow)

Time flow in the Verse language refers to the concurrency between asynchronous expressions and it is possible to specify how they relate to each other.

Sync is one of the asynchronous structured expressions. It must be used in an asynchronous context that is a function with the suspends specifier, such as the OnBegin() function.

The sync expression executes other expressions simultaneously and only completes when all expressions in its code block complete.

The code below shows a simple example of the sync expression: 

    OnBegin<override>()<suspends>:void=

        sync:
            Trigger1.TriggeredEvent.Await()
            Trigger2.TriggeredEvent.Await()
            Trigger3.TriggeredEvent.Await()
        
        Print("The three Triggers have been activated")

Trigger1, Trigger2 and Trigger3 are instances of trigger_device. The Await() function waits until the event is triggered. The sync expression ends when all three triggers are activated.

Let's create a device in UEFN with this sync example. In any UEFN project, open Verse Explorer, right-click on the project name and choose the Add new Verse file to project option.

In Device Name put sync_device and click the Create Empty button.

Copy the Verse code below into the sync_device file:

using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }

sync_device := class(creative_device):

    @editable
    Explosive : explosive_device = explosive_device{}

    @editable
    Trigger1 : trigger_device = trigger_device{}

    @editable
    Trigger2 : trigger_device = trigger_device{}

    @editable
    Trigger3 : trigger_device = trigger_device{}

    OnBegin<override>()<suspends>:void=

        EventsOutput := sync:
            Trigger1.TriggeredEvent.Await()
            Trigger2.TriggeredEvent.Await()
            Trigger3.TriggeredEvent.Await()
        
        MaybeAgent := EventsOutput(0)

        if(Agent := MaybeAgent?):
            Explosive.Explode(Agent)

This device has references to three trigger_device and one explosive_device. The explosive will detonate when all three triggers are activated.

No exemplo o EventsOutput está sendo usado para armazenar o retorno da expressão sync. O retorno da expressão sync é uma tupla contendo o retorno de cada função.

The Await() function returns an ?agent (option agent) that needs to be converted to an agent to be passed as a parameter to the Explode() function.

Save the file and compile the Verse code using the Verse > Build Verse Code option from the UEFN menu.

Access the Content Drawer and add our sync_device to the level. Also add three Trigger Device and an Explosive Device. Place the explosive device away from the trigger devices or reduce the explosion's range to avoid hitting the player.


Select the sync_device in the level. In the Details tab, add the device references.


Save the level and click the Launch Session button to load the level into Fortnite. Walk over the three triggers to detonate the explosive.


Table of Contents Verse


UEFN Verse: Sync (fluxo de tempo)

Fluxo de tempo na linguagem Verse se refere à concorrência entre as expressões assíncronas sendo possível especificar como elas se relacionam.

Sync é uma das expressões estruturadas assíncronas. Ela tem de ser usada em um contexto assíncrono que é uma função com o especificador suspends como a função OnBegin().

A expressão sync executa outras expressões simultaneamente e só finaliza quando todas as expressões em seu bloco finalizarem.

O código abaixo mostra um exemplo simples da expressão sync: 

    OnBegin<override>()<suspends>:void=

        sync:
            Trigger1.TriggeredEvent.Await()
            Trigger2.TriggeredEvent.Await()
            Trigger3.TriggeredEvent.Await()
        
        Print("Os três Triggers foram ativados")

Trigger1, Trigger2 e Trigger3 são instâncias de trigger_device. A função Await() espera até que o evento seja ativado. A expressão sync finaliza quando os três triggers forem ativados.

Vamos criar um dispositivo no UEFN com este exemplo de syncEm qualquer projeto UEFN, abra o Verse Explorer, clique com o botão-direito no nome do projeto e escolha a opção Add new Verse file to project.

Em Device Name coloque sync_device clique no botão Create Empty.

Copie o código Verse abaixo para o dispositivo sync_device:

using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }

sync_device := class(creative_device):

    @editable
    Explosive : explosive_device = explosive_device{}

    @editable
    Trigger1 : trigger_device = trigger_device{}

    @editable
    Trigger2 : trigger_device = trigger_device{}

    @editable
    Trigger3 : trigger_device = trigger_device{}

    OnBegin<override>()<suspends>:void=

        EventsOutput := sync:
            Trigger1.TriggeredEvent.Await()
            Trigger2.TriggeredEvent.Await()
            Trigger3.TriggeredEvent.Await()
        
        MaybeAgent := EventsOutput(0)

        if(Agent := MaybeAgent?):
            Explosive.Explode(Agent)

Este dispositivo possui referências para três trigger_device e um explosive_device. O explosivo será detonado quando os três triggers forem ativados. 

No exemplo o EventsOutput está sendo usado para armazenar o retorno da expressão sync. O retorno da expressão sync é uma tupla contendo o retorno de cada função.

A função Await() retorna um ?agent (option agent) que precisa ser convertida para um agent para ser passado como parâmetro na função Explode().

Salve o arquivo e compile o código Verse usando a opção Verse > Build Verse Code do menu do UEFN. 

Acesse o Content Drawer e adicione o nosso dispositivo sync_device ao nível. Adicione também três Trigger Device e um Explosive Device. Coloque o Explosive Device longe dos Trigger Device ou diminua o alcance da explosão para evitar que o jogador seja atingido. 


Selecione o sync_device no nível. Na aba Details adicione as referências dos dispositivos.


Salve o nível e clique no botão Launch Session para carregar o nível no Fortnite. Passe por cima dos três triggers para detonar o explosivo.


terça-feira, 15 de julho de 2025

UEFN Verse: Module

A Verse module allows you to organize multiple code elements for reuse across your project. A module can also be distributed for use in other projects.

The first Verse lines of a creative device have the using statement that imports Verse modules from UEFN with the necessary elements.  

using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }

A module is created using the module keyword. A module can contain other modules, classes, constants, functions, and other elements.

A folder within the UEFN project is treated as a module. For example, you can create a folder with your domain to store your modules that can be distributed to the public.

To create a folder that will be used as a module, follow these steps:

  • Open Verse Explorer
  • Right-click on the Content folder.
  • Select the Create Submodule option.
  • Uncheck the Hide Empty Directories so that the new folder is displayed.
  • Right click on the new folder and rename it with the name of your module.

The image below shows the folder I created for my RomeroBlueprints module. My module contains the dice.verse file, which is one of the files we'll create in this article.


As an example, let's create the Dice module. This module contains the following elements:

  • The die class with fields and a method to roll the die.
  • The GenerateDice function that receives as parameters the amount of dice and the number of faces on the dice. The function creates and returns an array of dice (instances of the die class).
  • The SumDice function, which receives an array of dice as a parameter, adds up the values of all the dice and returns the result of the sum.

Right-click on the folder that was created, in my example the folder name is RomeroBlueprints, and choose the Create New Verse File option.

Use the name dice for the file and click the Create Empty button.

Copy the Verse code below into the dice file:

using { /Verse.org/Random }

Dice<public> := module:

    die<public> := class():

        NumFaces<public> : int = 6
        var TopFace<public> : int = 1

        Roll<public>(): int =
            set TopFace = GetRandomInt(1, NumFaces)
            TopFace

    GenerateDice<public>(Amount: int, _NumFaces: int): []die =

        var DiceArray : []die = array{}

        for (Counter := 1..Amount):
            CurrentDie := die{NumFaces:= _NumFaces}
            CurrentDie.Roll()
            set DiceArray += array{CurrentDie}
        
        DiceArray

    SumDice<public>(DiceArray: []die): int =

        var sum : int = 0

        for (Currentdie : DiceArray):
            set sum += Currentdie.TopFace

        sum

Save the file and compile the Verse code using the Verse > Build Verse Code option from the UEFN menu.

To use the Dice module in another Verse file that is in the project's Content folder, you need to import the module with the using statement with the folder name and the module name separated by "." as shown in the line below:

using { RomeroBlueprints.Dice }

This way, the die class and functions from the Dice module will be available to be used in another Verse file.

Let's create a device in UEFN to test the Dice module. In Verse Explorer, right-click on the project name and choose the Add new Verse file to project option.

In Device Name put module_device and click the Create Empty button.

Copy the Verse code below into the module_device file:

using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }

using { RomeroBlueprints.Dice }

module_device := class(creative_device):

    DieInstance : die = die{}

    var DiceArray : []die = array{}

    OnBegin<override>()<suspends>:void=

        DieInstance.Roll()
        Print("DieInstance.TopFace = {DieInstance.TopFace}")

        set DiceArray = GenerateDice(10,6)

        Print("Dice generated:")

        for( CurrentDie : DiceArray):
            Print("{CurrentDie.TopFace}")

        Print("The sum of the dice is { SumDice(DiceArray) }")

The module_device contains an instance of the die class and an array of die instances. The OnBegin method executes the functions available in the Dice module to generate 10 dice and add their values. The results of these functions are written in the log.

Save the file and compile the Verse code using the Verse > Build Verse Code option from the UEFN menu.

Access the Content Drawer and add the module_device to the level.

Click the Launch Session button located in the UEFN toolbar to load the level into Fortnite. 

After starting the session in Fortnite, press the Tab key and select the Log tab to view the log with the messages written by the Print functions.


Table of Contents Verse

UEFN Verse: Modulo (pt-BR)

Um módulo Verse permite a organização de vários elementos de código para serem reutilizados no projeto. Um módulo também pode ser distribuído para ser utilizado em outros projetos.

As primeiras linhas Verse de um dispositivo criativo tem a instrução using que importa módulos Verse do UEFN com os elementos necessários.  

using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }

A criação de um módulo é feito usando a palavra chave module. Um módulo pode conter outros módulos, classes, constantes, funções e outros elementos.

Uma pasta dentro do projeto UEFN é tratada como um módulo. Por exemplo, você pode criar uma pasta com o seu domínio para guardar os seus módulos que poderão ser distribuídos ao público.

Para criar uma pasta que será usada como módulo, siga estes passos:

  • Abra o Verse Explorer
  • Clique com o botão direito na pasta Content.
  • Selecione a opção Create Submodule.
  • Desmarque a opção Hide Empty Directories para que a nova pasta seja exibida.
  • Clique com o botão direito na nova pasta e renomeie com o nome do seu módulo.

A imagem abaixo mostra a pasta que eu criei para o meu módulo RomeroBlueprints. O meu módulo contém o arquivo dice.verse que é um dos arquivos que vamos criar neste artigo.


Como exemplo vamos criar o módulo Dice (dados em inglês). Este módulo contém os seguintes elementos:

  • A classe die (dado em inglês) com campos e um método para rolar o dado.
  • A função GenerateDice que recebe como parâmetro a quantidade de dados e o número de faces dos dados. A função cria e retorna um array de dados (instâncias da classe die).
  • A função SumDice que recebe como parâmetro um array de dados, soma os valores de todos os dados e retorna o resultado da soma.

Clique com o botão direito na pasta que foi criada, no meu exemplo o nome da pasta é RomeroBlueprints, e escolha a opção Create New Verse File

Use o nome dice para o arquivo clique no botão Create Empty.

Copie o código Verse abaixo para o arquivo dice:

using { /Verse.org/Random }

Dice<public> := module:

    die<public> := class():

        NumFaces<public> : int = 6
        var TopFace<public> : int = 1

        Roll<public>(): int =
            set TopFace = GetRandomInt(1, NumFaces)
            TopFace

    GenerateDice<public>(Amount: int, _NumFaces: int): []die =

        var DiceArray : []die = array{}

        for (Counter := 1..Amount):
            CurrentDie := die{NumFaces:= _NumFaces}
            CurrentDie.Roll()
            set DiceArray += array{CurrentDie}
        
        DiceArray

    SumDice<public>(DiceArray: []die): int =

        var sum : int = 0

        for (Currentdie : DiceArray):
            set sum += Currentdie.TopFace

        sum

Salve o arquivo e compile o código Verse usando a opção Verse > Build Verse Code do menu do UEFN.

Para usar o módulo Dice em outro arquivo Verse que está na pasta Content do projeto é preciso importar o módulo com a instrução using com o nome da pasta  e o nome do módulo separados por "." como mostra a linha abaixo:

using { RomeroBlueprints.Dice }

Assim, a classe die e as funções do módulo Dice estarão disponíveis para serem usados em outro arquivo Verse.

Vamos criar um dispositivo no UEFN para testar o módulo Dice. No Verse Explorer, clique com o botão-direito no nome do projeto e escolha a opção Add new Verse file to project.

Em Device Name coloque module_device clique no botão Create Empty.

Copie o código Verse abaixo para o dispositivo module_device:

using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }

using { RomeroBlueprints.Dice }

module_device := class(creative_device):

    DieInstance : die = die{}

    var DiceArray : []die = array{}

    OnBegin<override>()<suspends>:void=

        DieInstance.Roll()
        Print("DieInstance.TopFace = {DieInstance.TopFace}")

        set DiceArray = GenerateDice(10,6)

        Print("Dice generated:")

        for( CurrentDie : DiceArray):
            Print("{CurrentDie.TopFace}")

        Print("The sum of the dice is { SumDice(DiceArray) }")

O module_device possui uma instância da classe die e um array de instâncias da classe die. No método OnBegin são executadas as funções disponíveis no módulo Dice para gerar 10 dados e somar os seus valores. Os resultados das funções são registrados no log.

Salve o arquivo e compile o código Verse usando a opção Verse > Build Verse Code do menu do UEFN. 

Acesse o Content Drawer e adicione o dispositivo Verse module_device ao nível. 

Clique no botão Launch Session localizado na barra de ferramentas do UEFN para carregar o nível no Fortnite. 

Após iniciar a partida no Fortnite, pressione a tecla Tab e selecione a aba Registro para visualizar o log com as mensagens escritas pelas funções Print.


Sumário Verse


domingo, 6 de julho de 2025

UEFN Verse: Access Specifiers

Access specifiers are used to define the visibility of elements in Verse code. They can be used on classes, fields, methods, and other elements.

The <public> specifier indicates that the element is available anywhere in the code.

The <protected> specifier indicates that the element is available in the class itself and in its subclasses.

The <private> specifier indicates that the element is available within the class itself but subclasses cannot access it.

When no access specifier is used, the element uses the default <internal> specifier which indicates that the element is available in the module it is in. The next article will be about modules.

The code below is an example of a class that was created just to show the application of access specifiers in the class, fields and method. 

weapon<public> := class():

    var<protected> ammunition<public>: int = 10

    calibration<private> : float = 0.03	

    Fire<public>(): void =
        if (ammunition > 0):
            set ammunition -= 1 
            Print("Weapon fired")
        else:
            Print("No ammo")

In variables, the specifier used next to var indicates where it can be modified. The specifier used next to the variable name indicates where it can be accessed. In the example above, the variable ammunition can be accessed anywhere but can only be modified within the class itself and its subclasses.

Consider WeaponInstance an instance of the weapon class that is being used inside another class. The following accesses are valid because the elements are <public>:

Print("{WeaponInstance.ammunition}")
WeaponInstance.Fire()

The accesses below are invalid because calibration is <private> and the var of ammunition is <protected>:

Print("{WeaponInstance.calibration}")
set WeaponInstance.ammunition = 15

The code below creates the rifle_grenade subclass using weapon as the superclass. The grenades variable is using the default access specifier which is <internal>.

rifle_grenade<public> := class(weapon):

    var grenades: int = 3

    LaunchGrenade<public>():void =
        if (grenades > 0):
            set grenades -= 1 
            Print("Grenade launched")
        else:
            Print("No grenade")

    RifleStatus<public>():void =
        Print("ammunition: {ammunition} | grenades: {grenades}")

In the RifleStatus() method we can see that the ammunition variable of the weapon superclass is accessible. It can also be modified in the subclass.

The calibration variable is not accessible in the rifle_grenade subclass because it is <private>.

The code below shows these example classes in a single file so you can test them on UEFN. I created a verse device called access_specifiers_device and used this code:

using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }

weapon<public> := class():

    var<protected> ammunition<public>: int = 10

    calibration<private> : float = 0.03	

    Fire<public>(): void =
        if (ammunition > 0):
            set ammunition -= 1 
            Print("Weapon fired")
        else:
            Print("No ammo")

rifle_grenade<public> := class(weapon):

    var grenades: int = 3

    LaunchGrenade<public>():void =
        if (grenades > 0):
            set grenades -= 1 
            Print("Grenade launched")
        else:
            Print("No grenade")

    RifleStatus<public>():void =
        Print("ammunition: {ammunition} | grenades: {grenades}")

access_specifiers_device := class(creative_device):

    RifleGrenade : rifle_grenade = rifle_grenade{}

    OnBegin<override>()<suspends>:void= 

        Print("{RifleGrenade.ammunition}")
        RifleGrenade.Fire()
        RifleGrenade.LaunchGrenade()
        RifleGrenade.RifleStatus()

This Verse device creates an instance of the rifle_grenade class and accesses the ammunition variable and the Fire() method of the weapon superclass and two more methods of the rifle_grenade class.


UEFN Verse: Especificadores de acesso

Os especificadores de acesso são usados para definir a visibilidade de elementos no código Verse. Eles podem ser usados em classes, campos, métodos e outros elementos.

O especificador <public> indica que o elemento está disponível em qualquer parte do código. 

O especificador <protected> indica que o elemento está disponível na própria classe e em suas subclasses.

O especificador <private> indica que o elemento está disponível na própria classe mas as subclasses não conseguem acessar.

Quando não é usado um especificador de acesso, o elemento usa o especificador padrão que é o <internal> que indica que o elemento está disponível no módulo em que ele está. O próximo artigo será sobre módulos. 

O código abaixo é um exemplo de classe que foi criada apenas para mostrar a aplicação dos especificadores de acesso na classe, em campos e no método. 

weapon<public> := class():

    var<protected> ammunition<public>: int = 10

    calibration<private> : float = 0.03	

    Fire<public>(): void =
        if (ammunition > 0):
            set ammunition -= 1 
            Print("Weapon fired")
        else:
            Print("No ammo")

Nas variáveis o especificador usado ao lado de var indica onde ela pode ser modificada. O especificador usado ao lado no nome da variável indica onde ela pode ser acessada. No exemplo acima a variável ammunition pode ser acessada em qualquer lugar mas só pode ser modificada na própria classe e nas subclasses.

Considere WeaponInstance uma instância da classe weapon que está sendo usada dentro de outra classe. Os acessos abaixo são válidos porque os elementos são <public>:

Print("{WeaponInstance.ammunition}")
WeaponInstance.Fire()

Os acessos abaixo são inválidos porque calibration é <private> e o var de ammunition é <protected>:

Print("{WeaponInstance.calibration}")
set WeaponInstance.ammunition = 15

O código abaixo cria a subclasse rifle_grenade usando weapon como superclasseA variável grenades está usando o especificador de acesso default que é o <internal>.

rifle_grenade<public> := class(weapon):

    var grenades: int = 3

    LaunchGrenade<public>():void =
        if (grenades > 0):
            set grenades -= 1 
            Print("Grenade launched")
        else:
            Print("No grenade")

    RifleStatus<public>():void =
        Print("ammunition: {ammunition} | grenades: {grenades}")

No método RifleStatus() podemos ver que a variável ammunition da superclasse weapon é acessível. Ela também pode ser modificada na subclasse.

A variável calibration não é acessível na subclasse rifle_grenade porque ela é <private>.

O código abaixo mostra estas classes de exemplo em um único arquivo para poder testar no UEFN. Eu criei um dispositivo verse chamado access_specifiers_device e usei este código:
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }

weapon<public> := class():

    var<protected> ammunition<public>: int = 10

    calibration<private> : float = 0.03	

    Fire<public>(): void =
        if (ammunition > 0):
            set ammunition -= 1 
            Print("Weapon fired")
        else:
            Print("No ammo")

rifle_grenade<public> := class(weapon):

    var grenades: int = 3

    LaunchGrenade<public>():void =
        if (grenades > 0):
            set grenades -= 1 
            Print("Grenade launched")
        else:
            Print("No grenade")

    RifleStatus<public>():void =
        Print("ammunition: {ammunition} | grenades: {grenades}")

access_specifiers_device := class(creative_device):

    RifleGrenade : rifle_grenade = rifle_grenade{}

    OnBegin<override>()<suspends>:void= 

        Print("{RifleGrenade.ammunition}")
        RifleGrenade.Fire()
        RifleGrenade.LaunchGrenade()
        RifleGrenade.RifleStatus()

Este dispositivo Verse cria uma instância da classe rifle_grenade e acessa a variável ammunition e o método Fire() da superclasse weapon e mais dois métodos da própria classe rifle_grenade.


quarta-feira, 2 de julho de 2025

UEFN Verse: Class Specifiers

Class specifiers are used when creating classes to define behaviors and characteristics. This article will present the main ones.

The <abstract> specifier is used to create superclasses with common fields and methods to be inherited by subclasses.

An abstract class allows the declaration of methods without a body (it has no code) that must be overridden in a subclass.

The code below creates the abstract class base_bonus. The ApplyBonus() method has no body.

base_bonus := class<abstract>():
    BonusId : int
    Name : string 
    BonusValue: int
	
    BonusData(): string =
        "BonusId: {BonusId} | Name: {Name} | BonusValue: {BonusValue}"

    ApplyBonus() : void

It is not possible to create instances of an abstract class. The code below generates a compilation error.

BaseBonus : base_bonus = base_bonus{BonusValue := 20,  Name := "Generic"}


The <concrete> specifier indicates that all fields of the class must have default values, allowing the creation of instances with an empty archetype.

The code below creates the concrete class score_bonus using base_bonus as the superclass. All fields have been given default values ​​and the ApplyBonus() method has been overridden.

score_bonus := class<concrete>(base_bonus):
    BonusId<override> : int = 2
    Name<override> : string = "Score MEDIUM"
    BonusValue<override>: int = 50
	
    ApplyBonus<override>() : void =
        Print("Adding {BonusValue} to SCORE.")

This code creates an instance of score_bonus using an empty archetype {}.

ScoreBonusDefault : score_bonus = score_bonus{}


The <final> specifier is used to indicate that a class cannot have subclasses. This specifier can also be used on fields and methods to indicate that they cannot be overridden.

The code below creates the final class time_bonus using base_bonus as the superclass.

time_bonus := class<final>(base_bonus):
    BonusId<override> : int = 1
	
    ApplyBonus<override>() : void =
        Print("Adding {BonusValue} to TIME.")

The new time_bonus class cannot be used as a superclass. The following code generates a compilation error.

time_bonus_variation := class(time_bonus):


Let's combine these examples into a single file so we can test it on UEFN. I created a verse device called class_specifiers_device and used this code:

using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }

base_bonus := class<abstract>():
    BonusId : int
    Name : string 
    BonusValue: int
	
    BonusData(): string =
        "BonusId: {BonusId} | Name: {Name} | BonusValue: {BonusValue}"

    ApplyBonus() : void

time_bonus := class<final>(base_bonus):
    BonusId<override> : int = 1
	
    ApplyBonus<override>() : void =
        Print("Adding {BonusValue} to TIME.")

score_bonus := class<concrete>(base_bonus):
    BonusId<override> : int = 2
    Name<override> : string = "Score MEDIUM"
    BonusValue<override>: int = 50
	
    ApplyBonus<override>() : void =
        Print("Adding {BonusValue} to SCORE.")		

class_specifiers_device := class(creative_device):

    TimeBonus : time_bonus = time_bonus{BonusValue := 30, Name := "Time MEDIUM"}

    ScoreBonusDefault : score_bonus = score_bonus{}

    OnBegin<override>()<suspends>:void= 

        Print( ScoreBonusDefault.BonusData() )
        ScoreBonusDefault.ApplyBonus()

This Verse device simply executes the two methods of the ScoreBonusDefault instance to write some messages to the log. The device was created to illustrate the use of class specifiers. 


Table of Contents Verse