[
    {
        "id": "98",
        "nombre": "The pilot: GPSS-Plus",
        "texto": "<h3>GPSS-Plus: Discrete-Event and Continuous Systems Simulation Engine<\/h3>\r\n<p>GPSS-Plus is a discrete-event and continuous systems simulation engine aimed at modeling and analyzing the behavior of real systems over time. Its purpose is not to program applications, but to <strong>describe how a system works<\/strong> and observe its evolution under different conditions.<\/p>\r\n<p>In essence, it operates as a digital laboratory where a set of entities (customers, products, vehicles, signals, or data packets) flows through a network of processes and resources with defined capacities and delays.<\/p>\r\n<p>The goal is to transform a real-world system description into an executable model: from an industrial production line or a logistics chain, to data traffic in a network or an emergency protocol. By simulating thousands of scenarios in minutes, it enables forecasting, decision optimization, and the design of contingency protocols within a general-purpose simulation environment.<\/p>\r\n<p>There are different approaches to system modeling, depending both on the interface and on the objective.<\/p>\r\n<p><u>Discrete and\/or continuous Drag & Drop based:<\/u><\/p>\r\n<ul>\r\n  <li>DES: Built by connecting graphical blocks.<\/li>\r\n  <li>Continuous modeling: Differential equation systems.<\/li>\r\n  <li>Hybrid graphical + scripting: Combine DES with external code.<\/li>\r\n<\/ul>\r\n<p><u>Discrete language-based approaches (domain-specific or general-purpose):<\/u><\/p>\r\n<ul>\r\n  <li>With a proprietary DSL: Entirely textual languages such as classic GPSS.<\/li>\r\n  <li>On top of general-purpose languages: Through simulation libraries.<\/li>\r\n<\/ul>\r\n<p>Thanks to inheriting the core concepts of classic GPSS, GPSS-Plus sits in both worlds, using its own language to define the model instead of building on general-purpose languages, and reinforcing the role of textual description as the system representation over graphical diagrams.<\/p>\r\n<p>The ultimate goal is that everything can be understood:<\/p>\r\n<pre>\r\nGENERATE 5\r\nADVANCE 10 {From:\"Madrid\", To:\"Paris\"}\r\nTERMINATE\r\n<\/pre>\r\n<p>The main innovations introduced are:<\/p>\r\n<h3>1. Syntax: extended compatibility<\/h3>\r\n<p>The most significant change lies in how block and command parameters are handled. In classic GPSS, parameters A, B, C... offered a fixed and limited syntax.<\/p>\r\n<p>Classic example:<\/p>\r\n<pre>\r\nADVANCE 30,10 ; Wait between 30 and 40 time units\r\n<\/pre>\r\n<p>In GPSS-Plus, this structure is preserved but extended with a JSON-like format, allowing more details to be specified without breaking simplicity:<\/p>\r\n<pre>\r\nADVANCE 30,10 {From:\"Madrid\", To:\"Paris\"}\r\n<\/pre>\r\n<p>This makes it possible to integrate graphical, behavioral, or logical parameters without inventing new syntactic variants for each case.<\/p>\r\n<h3>2. Graphical visualization<\/h3>\r\n<p>GPSS-Plus visually represents entities and blocks using simple graphical elements: small “dots” moving across a canvas, following exactly the model flow. This representation allows observing the system in real time, immediately understanding its dynamics, and facilitating the detection of bottlenecks or unexpected behaviors during execution.<\/p>\r\n<p>This visualization, absent in classic GPSS, introduces a new way of interacting with the model, where direct observation becomes a key validation and comprehension tool.<\/p>\r\n<h3>3. Virtual entities (VE)<\/h3>\r\n<p><b>Virtual entities<\/b> help describe the invisible parts of the model. For those coming from other paradigms, they capture what was previously described externally in another language. For beginners, they are simply another type of entity.<\/p>\r\n<p>In GPSS-Plus, everything that happens in the system unfolds over time and can be observed while it happens. To make this possible, all behaviors are treated the same way: <u>as entities<\/u> that move—abstract, visible, or even just a volume.<\/p>\r\n<p>Virtual entities are not visualized, but <strong>they are complete entities<\/strong> that execute internal logic or system events. They exist to describe behavior using <code>ON_ENTER<\/code>, a <code>TIMER<\/code>, or <code>TIMEOUT<\/code>, and they live within the model itself.<\/p>\r\n<p>Depending on their lifecycle, there are three main types:<\/p>\r\n<ul>\r\n  <li><strong>Reactors<\/strong>, which handle specific events and then disappear.<\/li>\r\n  <li><strong>Agents<\/strong>, which do not die and manage the model universe.<\/li>\r\n  <li><strong>Components<\/strong>, living entities that exist as part of another entity and die with it.<\/li>\r\n<\/ul>\r\n<p>With this approach, the model becomes an <strong>ecosystem of concurrent executions<\/strong>. An entity can wait for a bus while answering a call; an agent can control traffic; the sun can rise and set without any main entity needing to handle it.<\/p>\r\n<p>Many common concepts from procedural or object-oriented programming are reinterpreted: behavior is not encapsulated in hierarchical objects, but explicitly modeled as entities that coexist and act in parallel within the system.<\/p>\r\n<p>There is no this, no parent, no child: everyone is a brother. Functions stop being one-off calls and become living procedures. There is no “this.breathe()” that always breathes the same way, but a person who walks and, at the same time, breathes different air.<\/p>\r\n<h3>4. Model auditing and V&V<\/h3>\r\n<p>By being described entirely as an explicit model, GPSS-Plus allows its behavior to be automatically analyzed, interpreted, and cross-checked. An artificial intelligence or external auditor can reconstruct what the system does, detect internal inconsistencies, and compare the modeler’s intent with the actual execution.<\/p>\r\n<p>This capability introduces a natural evolution of classic verification and validation (V&V) processes, which no longer rely solely on manual review and statistical analysis. Coherence between history (H), model (M), and execution (E) is incorporated, laying the groundwork for a new validation approach.<\/p>\r\n<h3>5. Structured variables<\/h3>\r\n<p>In GPSS-Plus, variables (<code>SAVEVALUE<\/code>, <code>ASSIGN<\/code>) can contain <strong>numbers, strings, arrays, or objects<\/strong>. This allows working with complex data structures directly in the model, without resorting to external languages or losing readability.<\/p>\r\n<pre>\r\nASSIGN DATA, {type:\"Student\", Name:\"Antonio\", Age:22, Grades:[8,5.8,6,8]}\r\n<\/pre>\r\n<h3>6. Hybrid discrete–continuous system<\/h3>\r\n<p>Continuous modeling in GPSS-Plus is based on a simple idea: dividing time into small frames. By executing these steps sequentially within the event queue, continuous behavior naturally emerges.<\/p>\r\n<p><code>INTEGRATE<\/code>, <code>DYNAMIC<\/code>, <code>SOLVE<\/code> are the basic tools that allow defining continuous system structures integrated into the same discrete core. RK4, Jacobian matrices, and Newton–Raphson make it possible to simulate fluids, voltages, or velocities using the same DSL.<\/p>\r\n<h3>7. Sandbox, digital twins, and edge software<\/h3>\r\n<p>Simulation models can pursue three main objectives:<\/p>\r\n<ul>\r\n  <li><b>Sandbox<\/b>, focused on bounded simulation and result generation, with or without historical data preload.<\/li>\r\n  <li><b>Digital twin<\/b>, where the model accompanies a real system for verification, control, or predictive operation.<\/li>\r\n  <li><b>Edge software<\/b>, where the model itself is the system, running permanently as operational logic.<\/li>\r\n<\/ul>\r\n<p>In the latter two cases, the model must interact with the external environment. GPSS-Plus enables this coupling through the <b>BRIDGER<\/b>, which acts as a generic bidirectional channel between the model and real physical systems.<\/p>\r\n<p>From a language perspective, access to external resources is uniform: a database, a file, or a sensor are handled with the same syntax. Opening a relay or storing a data point is expressed with <code>BRIDGE_WRITE<\/code>, and replacing a <code>GENERATE<\/code> that simulates packet input with a subscription to a real motion sensor is almost immediate. The transition from sandbox to digital twin or edge software is therefore transparent.<\/p>\r\n<p>Thanks to <b>Rehydration<\/b>, the model not only connects to the real world but synchronizes with its ongoing state, allowing the simulator to “wake up” in the middle of a process without losing operational continuity after the last stored data, even after the model has been modified.<\/p>\r\n<h3>Other notable extensions:<\/h3>\r\n<p>In addition to these innovations, GPSS-Plus incorporates multiple extensions that enhance expressiveness, modularity, and power:<\/p>\r\n<ul>\r\n  <li><strong>New resources<\/strong>: new blocks such as <code>STOCK<\/code>, <code>RESTROOM<\/code>, <code>CONDITIONS<\/code>, finite state machines that extend the classic palette (<code>STORAGE<\/code>, <code>FACILITY<\/code>...).<\/li>\r\n  <li><strong>Dynamic resource creation<\/strong>: what would require manually dragging hundreds of blocks in Drag & Drop engines is achieved in GPSS-Plus with a simple <code>FOREACH<\/code> loop and a <code>NEWFACILITY<\/code>. This is the key difference between a textual language and classic graphical interfaces.<\/li>\r\n  <li><strong>Statistics<\/strong>: automatic collection of statistics for any resource or sequence, with graphical visualization.<\/li>\r\n  <li><strong>Behavior functions<\/strong>: automatic interpolations built from real or simulated data that encapsulate complex behaviors (e.g., different segments of a road or a machine).<\/li>\r\n  <li><strong>Native functions<\/strong>: tools such as <code>CONCAT<\/code>, <code>MERGE<\/code>, <code>PUSH<\/code> extend the language without relying on external code.<\/li>\r\n  <li><strong>Automatic charts<\/strong>: simply tabulating data generates charts within the simulation environment.<\/li>\r\n  <li><strong>Contexts (<code>CX$<\/code>)<\/strong>: each model can define independent contexts, ideal for creating reusable libraries, modules, or components.<\/li>\r\n  <li><strong>Full debugging<\/strong>: the system allows detailed tracking of the event queue, each entity, resource, or variable, facilitating model analysis and correction.<\/li>\r\n<\/ul>",
        "descripcion": "",
        "parametros": null,
        "parametros_json": "",
        "ejemplo": null,
        "hijos": []
    },
    {
        "id": "132",
        "nombre": "Season 1: Hello World",
        "texto": "",
        "descripcion": "",
        "parametros": null,
        "parametros_json": "",
        "ejemplo": null,
        "hijos": [
            {
                "id": "133",
                "nombre": "A simple example",
                "texto": "<p>We will simulate a basic system where entities (customers) arrive at a resource (service counter), wait if it is busy, are served, and then leave. In this model:<\/p>\r\n<ul>\r\n    <li><strong>Arrivals:<\/strong> Customers arrive every 60 to 70 time units.<\/li>\r\n    <li><strong>Service:<\/strong> Service time at the counter ranges from 60 to 90 time units.<\/li>\r\n    <li><strong>Queues:<\/strong> If the counter is busy, customers wait.<\/li>\r\n    <li><strong>Departure:<\/strong> Customers take 10 time units to move into the queue and another 10 to leave after service.<\/li>\r\n<\/ul>\r\n<p>For those familiar with <b>classic GPSS<\/b>, we would have:<\/p>\r\n<pre>\r\nGENERATE 60,10   ; Entities are generated every 60 to 70 time units.\r\nADVANCE 10       ; Takes 10 time units to move into the counter queue.\r\nSEIZE VENTANILLA ; The entity arrives at the counter queue.\r\nADVANCE 60,30    ; Service time: 60 to 90 time units.\r\nRELEASE VENTANILLA ; Leaves the counter.\r\nADVANCE 10       ; Takes 10 time units to leave.\r\nTERMINATE 1      ; The entity finishes.\r\nSTART 100        ; Executes until 100 entities have been served.\r\n<\/pre>\r\n<p>In <b>GPSS-Plus<\/b>, it is very similar, but with graphical representation. To achieve this, we configure resources and additional parameters:<\/p>\r\n<pre>\r\nFACILITY {NAME:VENTANILLA, X:300, Y:300} ; Define the counter in space.\r\nPOSITION {NAME:SALIDA, X:500, Y:300}    ; Define the exit in space.\r\n\r\nGENERATE 60,10 {NAME:GEN1, X:100, Y:300} ; Position the entity generator.\r\nADVANCE 10 {TO:VENTANILLA}               ; Move towards the counter.\r\nSEIZE VENTANILLA                        ; Assignment of the \"VENTANILLA\" resource.\r\nADVANCE 60,30                           ; Service time: 60 to 90 time units.\r\nRELEASE VENTANILLA                      ; Release of the resource.\r\nADVANCE 10 {TO:SALIDA}                  ; Move towards the exit.\r\nTERMINATE 1                             ; The entity finishes.\r\nSTART 100                               ; Executes until 100 entities have been served.\r\n<\/pre>\r\n<p><b>Final step:<\/b> Press Play and observe the result. The first entity will exit the \"Generate\" block between time 60 and 70.<\/p>\r\n<p>As can be observed, the program has not changed much to add the graphical component. Basically, we have defined the spatial layout of the elements.<\/p>",
                "descripcion": "",
                "parametros": "",
                "parametros_json": "",
                "ejemplo": "",
                "hijos": []
            },
            {
                "id": "137",
                "nombre": "Syntax: Commands and blocks",
                "texto": "<p>In a simulation, there are two main elements at play:<\/p>\r\n<p>1. <b>ENTITIES<\/b>, or transactions, are the elements that change their state during the simulation. They can represent people, boxes, or any kind of item. In GPSS-Plus, they are represented as colored dots. These entities interact with the environment. For example, they enter the system through the <code><b>GENERATE<\/b><\/code> block, move through a circuit using <code>ADVANCE<\/code>, and terminate at a <code><b>TERMINATE<\/b><\/code> block.<\/p>\r\n<p>2. <b>RESOURCES<\/b>, which make up the environment and are used by entities, such as a service counter or a container larger than the entity itself.<\/p>\r\n<p>For example, a person (entity) approaches a service counter (resource). This counter is defined by a <b>COMMAND<\/b>, and a set of <b>BLOCKS<\/b> describe what the person does in relation to that counter.<\/p>\r\n<p>An example of defining a resource as a service counter is the COMMAND:<\/p>\r\n<pre>\r\nFACILITY {name:Ventanilla1, x:100, y:100}\r\n<\/pre>\r\n<p>An example of an instruction for an entity to occupy that counter is the BLOCK:<\/p>\r\n<pre>\r\nSEIZE Ventanilla1\r\n<\/pre>\r\n<p>In summary, the language is based on two main elements: <b>blocks<\/b> and <b>commands<\/b>.<\/p>\r\n<p><b>1. Blocks<\/b> <b>bound to entities<\/b><\/p>\r\n<p>Blocks are instructions that <b>ENTITIES execute directly<\/b> during the simulation. Each block defines a specific action that affects the flow or state of that entity.<\/p>\r\n<p><b>General syntax:<\/b><\/p>\r\n<p>\r\nBLOCK [PARAMETERS A,B,C..] {JSON-LIKE OPTIONS}\r\n<\/p>\r\n<p>Block examples:<\/p>\r\n<pre>\r\nASSIGN variableName,10\r\nTERMINATE 1\r\n<\/pre>\r\n<p>Parameters are named by letters (A, B, C, ...). Depending on the block, they may also include parameters in a JSON-like format, usually defining graphical or advanced aspects.<\/p>\r\n<p>Example:<\/p>\r\n<pre>\r\nMOD {COLOR:#FF0000} ; sets an entity to red color.\r\n<\/pre>\r\n<p>Another example:<\/p>\r\n<pre>\r\nADVANCE 10,5 {TO:Ventanilla1} ; the entity advances in time towards \"Ventanilla1\"\r\n<\/pre>\r\n<p><b>2. Commands<\/b> <b>bound to resources and the engine environment<\/b><\/p>\r\n<p>Commands configure the simulation environment. Unlike blocks, they are not executed directly by entities. Instead, they define resources, graphical positions, and system rules.<\/p>\r\n<p><b>General syntax:<\/b><\/p>\r\n<p>\r\nCOMMAND {NAME:theName, JSON-LIKE OPTIONS}\r\n<\/p>\r\n<p>Example of defining a storage resource:<\/p>\r\n<pre>\r\nSTORAGE {NAME:ALMACEN1, CAPACITY:10, X:270, Y:200}\r\n<\/pre>\r\n<p>This format allows adding additional information such as position (X, Y).<\/p>",
                "descripcion": "",
                "parametros": "",
                "parametros_json": "",
                "ejemplo": "",
                "hijos": []
            },
            {
                "id": "213",
                "nombre": "Variables: Savevalues and Assigns",
                "texto": "<p>In GPSS-Plus, <b>variables<\/b> allow storing information that can be used by entities or to configure elements of the environment. These variables are mainly divided into two types:<\/p>\r\n<p><b>1. SAVEVALUE<\/b> (global variables): Global variables are accessible by any entity and persist throughout the entire simulation. They are useful for storing shared data such as counters, accumulators, or global states.<\/p>\r\n<p><b>Syntax:<\/b><br>\r\n<b>SAVEVALUE variable, value<\/b><\/p>\r\n<p>Example:<\/p>\r\n<pre>\r\nSAVEVALUE TiempoEspera, 8\r\n<\/pre>\r\n<p>This command sets the global variable \"TiempoEspera\" to a value of 8.<\/p>\r\n<p>Once defined, the value can be updated at any time:<\/p>\r\n<pre>\r\nSAVEVALUE TiempoEspera, 10\r\n<\/pre>\r\n<p>The value of \"TiempoEspera\" is now 10.<\/p>\r\n<p>To retrieve the value of a global variable, <b>SNA<\/b> are used, which follow a specific format:<\/p>\r\n<p><b>X$savevalueName<\/b> or <b>X$(savevalueName)<\/b><\/p>\r\n<pre>\r\n; X$TiempoEspera or X$(TiempoEspera)\r\n\r\nIF (X$TiempoEspera > 10)\r\n...\r\n<\/pre>\r\n<p>For example, incrementing the value of a savevalue can be done as follows:<\/p>\r\n<pre>\r\nSAVEVALUE TiempoEspera, X$TiempoEspera + 1\r\n<\/pre>\r\n<p><b>Or through the method:<\/b><\/p>\r\n<pre>\r\nSAVEVALUE.inc TiempoEspera\r\n<\/pre>\r\n<p>In particular, since these variables are used by more than one entity, they have an associated COMMAND for creation and initialization called <code><b>INITIAL<\/b><\/code>.<\/p>\r\n<p>Its syntax is simple:<\/p>\r\n<pre>\r\nINITIAL TiempoEspera,10\r\n<\/pre>\r\n<p>Remember that <code>INITIAL<\/code> is a command. It is used at the beginning of the program for initialization.<\/p>\r\n<p><b>2. ASSIGN<\/b> (entity local variables):<br>\r\nLocal variables belong to a specific entity. Each entity can have its own value for the same variable, which makes them useful for managing entity-specific data.<\/p>\r\n<p><b>Syntax:<\/b><br>\r\n<b>ASSIGN variable, value<\/b><\/p>\r\n<p>Example:<\/p>\r\n<pre>\r\nASSIGN Identificador, 1\r\n<\/pre>\r\n<p>This block assigns the value 1 to the variable \"Identificador\" of the current entity invoking ASSIGN.<\/p>\r\n<p>To retrieve the value of a local variable using its <b>SNA<\/b> format:<\/p>\r\n<p><b>P$assignName<\/b> or <b>P$(assignName)<\/b><\/p>\r\n<pre>\r\n; P$Identificador or P$(Identificador)\r\nif (P$Identificador > 5) ...\r\n<\/pre>\r\n<p><b>P$Identificador<\/b> is the form that allows obtaining the value of a local variable of the entity.<\/p>\r\n<p><b>Key differences between SAVEVALUE and ASSIGN:<\/b><\/p>\r\n<ul>\r\n    <li><b>Scope:<\/b> SAVEVALUE variables are global, while ASSIGN variables are entity-local.<\/li>\r\n    <li><b>Persistence:<\/b> SAVEVALUE variables retain their value at all times, even if no entity uses them. ASSIGN variables only exist while the entity is active.<\/li>\r\n    <li><b>Usage:<\/b> Use SAVEVALUE for shared data, and ASSIGN for entity-specific data.<\/li>\r\n<\/ul>\r\n<p><b>Combined example:<\/b><\/p>\r\n<p>In this example, we combine SAVEVALUE and ASSIGN to calculate the average waiting time at a service counter. If the time is defined by an ADVANCE 15,10, it means it will range between 15 and 25 time units. This should gradually approximate the average to 20.<\/p>\r\n<pre>\r\nINITIAL TiempoTotal, 0\r\nINITIAL NumEntidades, 0\r\nFacility {NAME:Ventanilla,X:354,Y:204}\r\nGraphic {NAME:Text1,Type:TEXT,X:358,Y:321,Text:\"Average\"}\r\nPosition {NAME:Salida,X:577,Y:201}\r\nSTART 50\r\n;---------------------------------\r\n\r\nGenerate 20,0 {NAME:GEN1,X:100,Y:207}\r\nADVANCE 10 {to:Ventanilla}\r\nSEIZE Ventanilla\r\nASSIGN TiempoInicio, AC1$\r\nADVANCE 15,10\r\nASSIGN TiempoFinal, AC1$\r\nRELEASE Ventanilla\r\nADVANCE 15 {to:Salida}\r\nASSIGN TiempoEntidad, (P$TiempoFinal - P$TiempoInicio)\r\nSAVEVALUE NumEntidades, X$NumEntidades + 1\r\nSAVEVALUE TiempoTotal, X$TiempoTotal + P$TiempoEntidad\r\nSAVEVALUE promedio, round(X$TiempoTotal \/ X$NumEntidades,3)\r\nMOVE {NAME:Text1,text:\"Average: X$promedio\"}\r\nTERMINATE 1\r\n<\/pre>\r\n<p>In this code:<br>\r\n- Each entity calculates its waiting time at the service counter.<br>\r\n- Times are accumulated in the global variable \"TiempoTotal\".<br>\r\n- The number of served entities is counted in \"NumEntidades\".<br>\r\n- At the end of the simulation, you can compute the average waiting time:<br>\r\n<b>AverageTime = X$TiempoTotal \/ X$NumEntidades<\/b><\/p>\r\n<p>In this way, <code>SAVEVALUE<\/code> and <code>ASSIGN<\/code> work together to provide efficient data handling within the simulation.<\/p>\r\n<p>Later on, we will see how both BLOCKS support much more than just numerical variables.<\/p>",
                "descripcion": "",
                "parametros": "",
                "parametros_json": "",
                "ejemplo": "",
                "hijos": []
            },
            {
                "id": "134",
                "nombre": "Structure: IF, CALL, PROCEDURE",
                "texto": "<p>In this example, we simulate a system where each entity randomly chooses one of <strong>three service counters<\/strong> to be served. Each counter has its own queue, and the flow is unevenly distributed depending on the service time.<\/p>\r\n<p>The decision logic is resolved exclusively through structured procedures.<\/p>\r\n<pre>\r\nFACILITY {NAME:VENTANILLA1,X:320,Y:450}\r\nFACILITY {NAME:VENTANILLA2,X:320,Y:300}\r\nFACILITY {NAME:VENTANILLA3,X:320,Y:150}\r\n\r\nPOSITION {NAME:POS1,X:160,Y:300}\r\nPOSITION {NAME:POS2,X:497,Y:300}\r\n\r\nSTART 30 ; Executes until 30 entities are completed\r\n\r\nGENERATE 10,0 {NAME:GEN1,X:60,Y:300}\r\nADVANCE 20,0 {TO:POS1}\r\nASSIGN ALEATORIO,RANDOM\r\nIF (P$ALEATORIO < 0.3)\r\n    CALL CAMINO1\r\n    ELSE \r\n       IF (P$ALEATORIO < 0.6)\r\n          CALL CAMINO2\r\n          ELSE\r\n          CALL CAMINO3\r\n       ENDIF\r\nENDIF\r\nADVANCE 20 {TO:POS2}\r\nTERMINATE 1\r\n\r\n;---------------------------------------------\r\n\r\nPROCEDURE CAMINO1\r\nADVANCE 20  {TO:VENTANILLA1}\r\nSEIZE VENTANILLA1\r\nADVANCE 25,10\r\nRELEASE VENTANILLA1\r\nENDPROCEDURE \r\n\r\nPROCEDURE CAMINO2\r\nADVANCE 20 {TO:VENTANILLA2}\r\nSEIZE VENTANILLA2\r\nADVANCE 10,2\r\nRELEASE VENTANILLA2\r\nENDPROCEDURE \r\n\r\nPROCEDURE CAMINO3\r\nADVANCE 20 {TO:VENTANILLA3}\r\nSEIZE VENTANILLA3\r\nADVANCE 10,2\r\nRELEASE VENTANILLA3\r\nENDPROCEDURE\r\n<\/pre>\r\n<p>Compared to the previous example, only a few new BLOCKS are introduced:<\/p>\r\n<pre>\r\nASSIGN ALEATORIO,RANDOM\r\n<\/pre>\r\n<p>This block creates a local variable in the entity (called <code>ALEATORIO<\/code>) and assigns it a random number between 0 and 1, using the <code>RANDOM<\/code> function.<\/p>\r\n<p>These local variables are also called <em>parameters<\/em> and are accessed using the SNA notation:<\/p>\r\n<code>P$ALEATORIO<\/code>\r\n<ul>\r\n    <li>\"P\" because it is a parameter,<\/li>\r\n    <li>\"$\" is the standard separator,<\/li>\r\n    <li>\"ALEATORIO\" is its name.<\/li>\r\n<\/ul>\r\n<pre>\r\nIF (P$ALEATORIO < 0.3)\r\n<\/pre>\r\n<p>This is an \"IF\" control-structure block.<\/p>\r\n<p>As can be seen, it is an \"if\" just like in any other language: a variable is compared against a value.<\/p>\r\n<p>This other control-structure block also needs little introduction. It calls a PROCEDURE:<\/p>\r\n<pre>\r\nCALL CAMINO1\r\n<\/pre>\r\n<p>Finally:<\/p>\r\n<pre>\r\nPROCEDURE CAMINO1\r\n...\r\nENDPROCEDURE 100 ; would produce an ASSIGN in the calling entity named CAMINO1 with value 100\r\n<\/pre>\r\n<p>Which also requires little explanation. PROCEDURE blocks encapsulate a set of actions.<\/p>\r\n<p><code>ENDPROCEDURE<\/code> may include a value in parameter A, which is returned in the same way as if an <code>ASSIGN<\/code> instruction had been generated. It can be retrieved as P$ProcedureName (e.g., P$CAMINO1). In this case, it is not used.<\/p>",
                "descripcion": "<p>In this example, we simulate a system where each entity randomly chooses one of <strong>three service counters<\/strong> to be served. Each counter has its own queue, and the flow is unevenly distributed depending on the service time.<\/p>\r\n<p>The decision logic is resolved exclusively through structured procedures, without the use of jumps or labels.<\/p>\r\n<pre>\r\nFACILITY {NAME:VENTANILLA1,X:320,Y:450}\r\nFACILITY {NAME:VENTANILLA2,X:320,Y:300}\r\nFACILITY {NAME:VENTANILLA3,X:320,Y:150}\r\n\r\nPOSITION {NAME:POS1,X:160,Y:300}\r\nPOSITION {NAME:POS2,X:497,Y:300}\r\n\r\nSTART 30 ; Executes until 30 entities are completed\r\n\r\nGENERATE 10,0 {NAME:GEN1,X:60,Y:300}\r\nADVANCE 20,0 {TO:POS1}\r\nASSIGN ALEATORIO,RANDOM\r\nIF (P$ALEATORIO < 0.3)\r\n    CALL CAMINO1\r\n    ELSE \r\n       IF (P$ALEATORIO < 0.6)\r\n          CALL CAMINO2\r\n          ELSE\r\n          CALL CAMINO3\r\n       ENDIF\r\nENDIF\r\nADVANCE 20 {TO:POS2}\r\nTERMINATE 1\r\n\r\n;---------------------------------------------\r\n\r\nPROCEDURE CAMINO1\r\nADVANCE 20  {TO:VENTANILLA1}\r\nSEIZE VENTANILLA1\r\nADVANCE 25,10\r\nRELEASE VENTANILLA1\r\nENDPROCEDURE \r\n\r\nPROCEDURE CAMINO2\r\nADVANCE 20 {TO:VENTANILLA2}\r\nSEIZE VENTANILLA2\r\nADVANCE 10,2\r\nRELEASE VENTANILLA2\r\nENDPROCEDURE \r\n\r\nPROCEDURE CAMINO3\r\nADVANCE 20 {TO:VENTANILLA3}\r\nSEIZE VENTANILLA3\r\nADVANCE 10,2\r\nRELEASE VENTANILLA3\r\nENDPROCEDURE\r\n<\/pre>\r\n<p>Compared to the previous example, only a few new BLOCKS are introduced:<\/p>\r\n<pre>\r\nASSIGN ALEATORIO,RANDOM\r\n<\/pre>\r\n<p>This block stores, in an entity-specific memory called \"ALEATORIO\", the value computed by \"RANDOM\", which is a random number between 0 and 1.<\/p>\r\n<p>These ASSIGNs are referred to as parameters and are accessed using the <b>SNA<\/b> notation:<\/p>\r\n<code>P$ALEATORIO<\/code>\r\n<ul>\r\n    <li>\"P\" because it is a parameter,<\/li>\r\n    <li>\"$\" is the standard separator,<\/li>\r\n    <li>\"ALEATORIO\" is its name.<\/li>\r\n<\/ul>\r\n<pre>\r\nIF (P$ALEATORIO < 0.3)\r\n<\/pre>\r\n<p>This is an \"IF\" control-structure block.<\/p>\r\n<p>As can be seen, it is an \"if\" just like in any other language: a variable is compared against a number.<\/p>\r\n<pre>\r\nCALL CAMINO1\r\n<\/pre>\r\n<p>This other control-structure block also needs little introduction. It calls a PROCEDURE.<\/p>\r\n<p>Finally:<\/p>\r\n<pre>\r\nPROCEDURE CAMINO1\r\n...\r\nENDPROCEDURE 100 ; would produce an ASSIGN in the calling entity named CAMINO1 with value 100\r\n<\/pre>\r\n<p>Which also requires little explanation. They encapsulate a set of actions (PROCEDURE).<\/p>\r\n<p><code>ENDPROCEDURE<\/code> may include a value in parameter A that will be returned in the same way as if an <code>ASSIGN<\/code> instruction had been generated. It can be retrieved as P$ProcedureName (e.g., P$CAMINO1). In this case, it is not used.<\/p>",
                "parametros": "",
                "parametros_json": "",
                "ejemplo": "",
                "hijos": []
            },
            {
                "id": "248",
                "nombre": "Resources: Storage",
                "texto": "\/* Warehouses: STORAGE\r\nCapacity management and storage usage.\r\n*\/\r\n\r\nINITIAL capacity,40 ; defines a savevalue named capacity with value 40\r\n\r\nSTORAGE {NAME:warehouse1, X:300, Y:200, capacity:X$capacity}\r\n\r\nPOSITION {NAME:EXIT,  X:500, Y:200}\r\n\r\n; Text showing current contents\r\nGRAPHIC {NAME:text1, Type:TEXT, X:320, Y:240, Text:\"Current boxes: 0\"}\r\n\r\nSTART 100\r\n\r\n; Trucks arriving every 10 time units\r\nGENERATE 10,0 {NAME:Truck, X:100, Y:200}\r\n\r\nADVANCE 15 {TO:warehouse1}\r\nENTER warehouse1,(random*15)+1 ; Occupies between 1 and 16 storage units\r\nsavevalue usage,X$capacity - R$(warehouse1,LEFT)\r\nMOVE {name:text1,text:\"Current boxes X$usage : R$(warehouse1,OCCUPIED)\"}\r\nADVANCE 40,10\r\nLEAVE warehouse1 ; Releases the occupied units\r\nsavevalue usage,X$capacity - R$(warehouse1,LEFT)\r\nMOVE {name:text1,text:\"Current boxes X$usage : R$(warehouse1,OCCUPIED)\"}\r\nADVANCE 15 {TO:EXIT}\r\nTERMINATE 1\r\n",
                "descripcion": "<p>One of the classic resources is <code>STORAGE<\/code>.<\/p>\r\n<p><code>FACILITY<\/code> represents things such as a service counter, a machine, or an operator: it can serve only one entity at a time and according to its capacity (with CAPACITY:3, the FACILITY would serve 3 entities). STORAGE, on the other hand, represents something like a warehouse, a tank, or a network that can be used partially.<\/p>\r\n<p>What is a <code>STORAGE<\/code>? A <code>STORAGE<\/code> is a type of resource that is not seized per entity, but by quantity. It is used when an entity must reserve part of a resource without occupying it entirely. For example, a truck can drop 10 boxes into a warehouse that can hold up to 40.<\/p>\r\n<p>How does it work? It is defined with a total capacity, for example 40 units.<\/p>\r\n<pre>\r\nSTORAGE {NAME:warehouse1, X:300, Y:200, capacity:40}\r\n<\/pre>\r\n<p>Entities use the <code>ENTER<\/code> block to occupy a certain amount, and <code>LEAVE<\/code> to give it back.<\/p>\r\n<pre>\r\nENTER warehouse1,5\r\nLEAVE warehouse1\r\n<\/pre>\r\n<p>If an entity tries to occupy more than what is available, it will automatically wait in an internal queue until the <code>STORAGE<\/code> has enough free capacity. You don’t need to program anything additional to manage that wait.<\/p>\r\n<p>In the example: a box warehouse (<code>STORAGE<\/code>) is defined with 40 capacity units. Trucks arrive every 10 time units and deposit between 1 and 16 boxes. After some time, they leave, freeing the occupied space. You will see on-screen text how many boxes are stored at any moment.<\/p>\r\n<p>In addition to calculating it via additions and subtractions, you can also do it directly by querying the corresponding SNA for <code>STORAGE<\/code> occupancy:<\/p>\r\n<pre>\r\nR$(warehouse1,OCCUPIED)  ; Units currently occupied\r\nR$(warehouse1,LEFT)      ; Units available\r\n<\/pre>",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            },
            {
                "id": "307",
                "nombre": "The event queue: the simulation engine",
                "texto": "<p><b>The event queue:<\/b><\/p>\r\n<p>At the heart of any discrete-event simulation lies the <strong>event queue<\/strong>, a structure that defines <strong>how and when<\/strong> entity actions are executed within the model. This <strong>discrete-event<\/strong> approach is what distinguishes it from other programming languages.<\/p>\r\n<p>You can think of it as if each entity had its own program, as you would do in C or Python, but <strong>jumping between entities according to the temporal order<\/strong> dictated by this queue. If we simulate 10 entities, there are 10 programs running “at the same time” (or almost).<\/p>\r\n<p><strong>What is the event queue?<\/strong><\/p>\r\n<p>It is a <strong>time-ordered list of scheduled actions<\/strong>, each associated with a simulated time instant (AC1). The queue ensures actions are executed in the correct order <strong>according to when they must occur<\/strong>.<\/p>\r\n<p>The most important thing: <strong>it is ordered by time<\/strong>. For example:<\/p>\r\n<pre>\r\nTime 15 - Serve entity 14 at step 88\r\nTime 45 - Serve entity 22 at step 16\r\nTime 77 - Serve entity 16 at step 25\r\n<\/pre>\r\n<p><strong>Example: Evolution of the event queue<\/strong><\/p>\r\n<p>Let’s consider the classic case of a bank where customers enter through the door and are served at a counter. Entities are created with <code>GENERATE<\/code> and spend time being served via <code>ADVANCE<\/code>.<\/p>\r\n<p>Imagine we are at instant <code>T = 5<\/code>, with the following queue:<\/p>\r\n<pre>\r\nT 5: Entity 5: Waiting in the counter queue\r\nT 7: GENERATE: Create an item, a customer who will enter through the door\r\nT 8: Entity 9: Heading to the counter queue\r\nT 16: Entity 3: Heading to the counter queue\r\n<\/pre>\r\n<p>Right now, we have one entity—#5—which is next in the queue. We will remove that element from the queue to process it. Now we know that time is 5! Not because time has “passed”, but because our next task is scheduled for T=5.<\/p>\r\n<p>Let’s assume, for example, that Entity 5 is at the “step” (position in its program) that indicates an <code>ADVANCE 10<\/code> to be served.<\/p>\r\n<p>In that case, the solution is to schedule itself in the queue at T=15 (5+10) and pause its execution while it is being served.<\/p>\r\n<p>Now the event queue will look like this:<\/p>\r\n<pre>\r\nT 7: GENERATE: Create an item\r\nT 8: Entity 9: Heading to the counter queue\r\nT 15: Entity 5: Go to the exit\r\nT 16: Entity 3: Heading to the counter queue\r\n<\/pre>\r\n<p>We are now at the next event. Time must be updated again: “AC1” now takes the value 7. As we said, it’s not that time has passed; it’s that the event queue makes time jump because there is nothing to do until T=7.<\/p>\r\n<p>We remove the element from the queue and find a <code>GENERATE 20,5<\/code>. Therefore, we must compute what time is defined by 20,5; something between 20 and 25. Suppose the result is 22. That is, another person will enter in 22 time units. The queue now takes this form after the <code>GENERATE<\/code> advances <b>and performs 2 tasks<\/b>:<\/p>\r\n<p>\r\n1.- The <code>GENERATE<\/code> itself advances 20 (parameter A) (7+20=27).<br>\r\n2.- It creates a new entity (#10) so it can carry out its tasks 22 time units later (7+22=29).\r\n<\/p>\r\n<pre>\r\nT 8: Entity 9: Heading to the counter queue\r\nT 15: Entity 5: Go to the exit\r\nT 16: Entity 3: Heading to the counter queue\r\nT 27: GENERATE: Create an item\r\nT 29: Entity 10: Heading to the counter queue\r\n<\/pre>\r\n<p>Now it would be time to advance system time again and serve the next element: Entity 9.<\/p>\r\n<p>This event queue will remain alive until one of the program-ending conditions is met.<\/p>\r\n<p>In GPSS-Plus, this event queue also has additional characteristics to support tasks in the graphical world and to add “ON_*” type events.<\/p>\r\n<p><b>In the GPSS-Plus event queue, we have 5 types of elements:<\/b><\/p>\r\n<ul>\r\n    <li>GENERATE – Introduce new entities into the system.<\/li>\r\n    <li>Entities – The ones that move through the model and consume resources.<\/li>\r\n    <li>Dead times – Visible pauses that allow step-by-step simulation or speed adjustment.<\/li>\r\n    <li>Virtual entities – Not visible; execute events such as ON_ENTER, ON_TIMER, etc.<\/li>\r\n    <li>System TIMER – Like a GENERATE, but it produces virtual entities at fixed intervals.<\/li>\r\n<\/ul>\r\n<p><b>Resource queues:<\/b><\/p>\r\n<p>Other existing queues are those belonging to resources; each resource can have one or two depending on the case.<\/p>\r\n<p>These lists are ordered by arrival order, and their management depends exclusively on the resource itself.<\/p>\r\n<p>For example, a <code>FACILITY<\/code> has two lists: the list of occupying entities and the list of entities waiting in queue.<\/p>\r\n<p>When an entity attempts to <code>SEIZE<\/code>, if the resource is busy, it moves to the waiting list. If there are no entities in the resource, it will seize it by entering the occupants list.<\/p>\r\n<p>When it performs <code>RELEASE<\/code>, it leaves that list and forces the resource to look for an entity in its pending queue to enter. If there is one, it will move it into the occupants list and schedule its entry into the event queue at that same instant, so that entity will take control of the engine as soon as the departing one stops its activity.<\/p>\r\n<p><strong>Conclusion<\/strong><\/p>\r\n<p>The event queue not only defines the order and time at which actions occur, but also acts as the core of the system. It ensures blocks execute correctly and that the simulation is consistent and accurate. Understanding this concept is essential to design efficient models and fully leverage GPSS-Plus capabilities.<\/p>\r\n<p>In GPSS-Plus it is easy to view this queue: just open the menu window and click the “Event Queue” button.<\/p>",
                "descripcion": "",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            },
            {
                "id": "174",
                "nombre": "Conditions: Waiting for a condition",
                "texto": "\/* Synchronization: CONDITIONS \/ WAITUNTIL\nEntities wait as a group and advance together.\n*\/\n\nPOSITION {NAME:POS1,X:208,Y:222}\nPOSITION {NAME:POS2,X:452,Y:215}\nPOSITION {NAME:POS3,X:752,Y:215}\n\nCONDITIONS {NAME:Conditions1,X:208,Y:317,expression:(X$counter>=5)} ; Holding resource\nINITIAL counter,0\n\nSTART 100\n;*****************************************************\n\nGENERATE 10,2 {NAME:GEN1,X:86,Y:228,ERADIO:10,ECOLOR:#FF9900}\n\nADVANCE 16,0 {TO:POS1}\nSAVEVALUE counter, X$counter + 1\nWAITUNTIL Conditions1\nWAITCHECK Conditions1\nSAVEVALUE counter, 0\nADVANCE 20,0 {TO:POS2} ; ALL entities advance together to the second position\nADVANCE 20,40 {TO:POS3} ; Advance to the third position with random time between 20 and 40, now SPLITTING\n\nENDGENERATE 1 ; Ends the life of the entity — IDENTICAL to TERMINATE 1\n",
                "descripcion": "<p>Imagine a group of people waiting for an automatic door to open. They are not queuing and they are not occupying anything; they are simply waiting for something to happen.<\/p>\n<p>This is exactly what the <code>CONDITIONS<\/code> resource allows: stopping entities until a logical condition is met.<\/p>\n<p>Something similar existed in classic GPSS with the <code>ASSEMBLE<\/code> block for this purpose. In GPSS-Plus, this behavior is replaced by a more general and flexible resource.<\/p>\n<p>The <code>CONDITIONS<\/code> resource allows <strong>holding entities<\/strong> until a condition is satisfied. This condition is defined as an expression that is evaluated each time an entity attempts to pass.<\/p>\n<pre>\nCONDITIONS {NAME:Conditions1,X:208,Y:317,expression:(X$counter>=5)}\n<\/pre>\n<p><code>CONDITIONS<\/code> has additional options that will be covered later.<\/p>\n<p>Its associated block, <code>WAITUNTIL<\/code>, is responsible for validating the condition for the current entity — in this case, whether the counter is greater than or equal to 5.<\/p>\n<p>When the 5th entity arrives, the condition is satisfied and it continues without being held. At that point, the remaining entities are released by checking all retained ones using another associated block: <code>WAITCHECK<\/code>.<\/p>\n<p>It is interesting to observe that all entities leave the <code>CONDITIONS<\/code> resource together in the first segment. In the second one, the randomness of <code>ADVANCE 20,40<\/code> causes them to spread apart.<\/p>\n<p>We also begin using the <code>ENDGENERATE<\/code> block, which is more consistent with the structured approach than <code>TERMINATE<\/code>. They are equivalent, but syntactically it is more appropriate to structure the block using <code>GENERATE<\/code>\/<code>ENDGENERATE<\/code>. This makes it easier to identify which block was generated, especially when multiple <code>GENERATE<\/code> blocks exist in the program.<\/p>",
                "parametros": "",
                "parametros_json": "",
                "ejemplo": "",
                "hijos": []
            },
            {
                "id": "216",
                "nombre": "Second structural step",
                "texto": "\/* Blocks: SWITCH and LOCK\/UNLOCK\nConditional routing and management of lockable resources.\n*\/\n\nFACILITY {NAME:COUNTER1,X:320,Y:450,CAPACITY:3}\nFACILITY {NAME:COUNTER2,X:320,Y:300,CAPACITY:3}\nFACILITY {NAME:COUNTER3,X:320,Y:150}\nFACILITY {NAME:COUNTER4,X:320,Y:50}\n\nPOSITION {NAME:POS1,X:158,Y:301}\nPOSITION {NAME:POS2,X:497,Y:300}\nPOSITION {NAME:POS3,X:627,Y:300,TYPE:TERMINATE,TITLE:END}\n\nGRAPHIC {NAME:Text1,Type:TEXT,X:320,Y:104,Text:\"Unlock\"}\n\nSTART 30\n\nGENERATE 10,0 {NAME:GEN1,X:57,Y:300}\nADVANCE 20,0 {TO:POS1,flow:1}\n\nASSIGN RANDOM_VALUE,(RANDOM)\n\nSWITCH P$RANDOM_VALUE\n    CASE <,0.4\n        CALL PATH1\n    ENDCASE\n\n    CASE <,0.8\n        CALL PATH2\n    ENDCASE\n\n    CASE <,0.92\n        CALL PATH3\n        MOVE {NAME:Text1,text:\"Lock\"}\n        LOCK COUNTER1\n        LOCK COUNTER2\n        LOCK COUNTER3\n    ENDCASE\n\n    DEFAULT\n        CALL PATH4\n        MOVE {NAME:Text1,text:\"Unlock\"}\n        UNLOCK COUNTER1\n        UNLOCK COUNTER2\n        UNLOCK COUNTER3\n    ENDCASE\nENDSWITCH\n\nADVANCE 20,10 {TO:POS2,flow:1,MERGE:\"exit\"}\nADVANCE 20,0 {TO:POS3,flow:1}\n\nENDGENERATE 1\n;****************************************\n\nPROCEDURE PATH1\n    ADVANCE 20  {TO:COUNTER1,flow:1,DECISION:\"start\"}\n    SEIZE COUNTER1\n    ADVANCE 45,10\n    RELEASE COUNTER1\nENDPROCEDURE\n\nPROCEDURE PATH2\n    ADVANCE 20 {TO:COUNTER2,flow:1,DECISION:\"start\"}\n    SEIZE COUNTER2\n    ADVANCE 40,10\n    RELEASE COUNTER2\nENDPROCEDURE\n\nPROCEDURE PATH3\n    ADVANCE 20 {TO:COUNTER3,flow:1,DECISION:\"start\"}\n    SEIZE COUNTER3\n    ADVANCE 40,20\n    RELEASE COUNTER3\nENDPROCEDURE\n\nPROCEDURE PATH4\n    ADVANCE 20 {TO:COUNTER4,flow:1,DECISION:\"start\"}\n    SEIZE COUNTER4\n    ADVANCE 10,2\n    RELEASE COUNTER4\nENDPROCEDURE\n\n;***************************************************************",
                "descripcion": "<p>Now that you already know how to use procedures and simple conditional decisions (<code>IF<\/code>), let’s look at a case where an entity chooses between <strong>multiple possible routes<\/strong>.<\/p>\n<p>For this, we use the <code>SWITCH<\/code> structure, very similar to a “decision menu”.<\/p>\n<p><b>What does this example do?<\/b><\/p>\n<ul>\n    <li>Generates an entity every 10 time units.<\/li>\n    <li>Assigns it a random number (<code>P$RANDOM_VALUE<\/code>).<\/li>\n    <li>Depending on that number, chooses one of four routes (<code>CALL PATH1<\/code> … <code>CALL PATH4<\/code>).<\/li>\n    <li>In two of those routes (PATH3 and PATH4), a <strong>visual block<\/strong> is activated showing “Lock” or “Unlock”, and <strong>resources are locked or unlocked<\/strong>. If an entity enters path 3, the use of resources 1, 2, and 3 is locked, although entities already inside them are allowed to finish their work. When an entity takes path 4, those resources become available again immediately. Locking does not expel entities already using the resources, but prevents new ones from seizing them until they are unlocked.<\/li>\n<\/ul>\n<p>We also define a purely visual aspect: “flow”.<br>\nBy enabling it in <code>ADVANCE<\/code>, we will see a route line that initially runs vertically or horizontally depending on the <code>LAYOUT<\/code>. It may pass through a <code>VIA<\/code> or <code>VIA2<\/code>, and can converge or diverge according to <code>MERGE<\/code> or <code>DECISION<\/code>.<\/p>",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            },
            {
                "id": "306",
                "nombre": "A complete model",
                "texto": "QUEUER {NAME:IN_PARKING,X:413,Y:497}\r\n\r\nFACILITY {NAME:UTILITY_VEHICLES, CAPACITY:4, X:413, Y:390}\r\nSTORAGE {NAME:TRUCKS, CAPACITY:5, X:412, Y:120}\r\n\r\nPOSITION {NAME:POS_ENTRY,X:240,Y:270}\r\nPOSITION {NAME:POS_EXIT,X:557,Y:316,TYPE:DECISION,TITLE:\"END?\"}\r\nPOSITION {NAME:POS_LOOP,X:225,Y:549}\r\nPOSITION {NAME:END,X:730,Y:324,TYPE:TERMINATE}\r\n\r\nSTART 20\r\n\r\n;************************************************************************\r\nGENERATE 20,10,0,10 {NAME:G_UTILITY_VEHICLES,X:80,Y:363,ESUBTITLE:\"P$cycles\/3\"}\r\nASSIGN VEHICLE_TYPE,1\r\nMOD {RADIO:5,COLOR:#000066}\r\nCALL PROC.MAIN\r\nENDGENERATE 1 ; ALIAS OF TERMINATE\r\n;----------------------------\r\nGENERATE 20,10,0,10 {NAME:G_TRUCKS,X:80,Y:199,ESUBTITLE:\"P$cycles\/3\"}\r\n\r\nASSIGN VEHICLE_TYPE,FLOOR(RANDOM * 2 + 2)\r\nMOD {RADIO:10,COLOR:#006600}\r\nCALL PROC.MAIN\r\nENDGENERATE 1  ; ALIAS OF TERMINATE\r\n;************************************************************************\r\n\r\nPROCEDURE PROC.MAIN\r\n\r\nASSIGN cycles,1\r\n\r\nADVANCE0 {TO:POS_ENTRY,flow:1,layout:H}\r\nASSIGN state,\"loop\"\r\n\r\nWHILE (\"P$state\"!=\"EXIT\")\r\n\r\n\tQUEUE IN_PARKING\r\n\r\n\tCALL DECIDE.ROUTE ; return assign:ROUTE\r\n    CALL \"P$(ROUTE)\"\r\n    ADVANCE 20,18 {TO:POS_EXIT,flow:1,MERGE:\"exit\"}\r\n\r\n\tDEPART IN_PARKING\r\n    \r\n    CALL DECIDE.LOOP_OR_END\r\n    ASSIGN state,\"P$(LOOP_OR_END)\"\r\nENDWHILE\r\n\r\nADVANCE 20,0 {TO:END,flow:1}\r\n\r\nENDPROCEDURE\r\n\r\n;*****************************************************\r\n\r\nPROCEDURE DECIDE.ROUTE\r\n    ASSIGN VALUE,\"\"\r\n    SWITCH P$VEHICLE_TYPE\r\n    CASE <=,1\r\n\t    ASSIGN VALUE,\"PROC.UTILITY_VEHICLES\"\r\n    ENDCASE\r\n    DEFAULT\r\n    \tASSIGN VALUE,\"PROC.TRUCKS\"\r\n    ENDCASE\r\n    ENDSWITCH\r\n\t\r\nENDPROCEDURE \"P$VALUE\"\r\n;---------------------------------------------\r\nPROCEDURE DECIDE.LOOP_OR_END\r\n    ASSIGN VALUE,\"loop\"\r\n    ASSIGN cycles,P$cycles + 1\r\n\tIF (P$cycles > 3)\r\n    \tASSIGN VALUE,\"EXIT\"\r\n        MOD {SUBTITLE:\"-EXIT-\"}\r\n    ELSE\r\n        ADVANCE 30 {TO:POS_ENTRY,flow:1,VIA:POS_LOOP,layout:V}\r\n\tENDIF\r\nENDPROCEDURE \"P$VALUE\"\r\n\r\n;---------------------------------------------\r\nPROCEDURE PROC.UTILITY_VEHICLES\r\n    ADVANCE 20 {TO:UTILITY_VEHICLES,flow:1,DECISION:\"resource\"}\r\n    SEIZE UTILITY_VEHICLES\r\n    ADVANCE 55,40\r\n    RELEASE UTILITY_VEHICLES\r\nENDPROCEDURE\r\n\r\nPROCEDURE PROC.TRUCKS\r\n    ADVANCE 20 {TO:TRUCKS,flow:1,DECISION:\"resource\"}\r\n    ENTER TRUCKS, P$VEHICLE_TYPE\r\n    ADVANCE 40,20\r\n    LEAVE TRUCKS\r\nENDPROCEDURE\r\n;----------------------------------\r\n",
                "descripcion": "<p>Now that you know the fundamentals of GPSS-Plus, let’s see how they all come together in a unified example.<\/p>\r\n<p>We’re going to look at a piece of code that is quite a bit longer than what we’ve seen so far—almost 100 lines.<\/p>\r\n<p>This model represents a system with <strong>different vehicle types<\/strong> that move through a work area for several cycles. Each one decides its route, performs tasks, and finishes after completing a number of cycles, entering the utility-vehicle or truck parking area as appropriate—occupying either a <code>FACILITY<\/code> or a <code>STORAGE<\/code> depending on the truck size.<\/p>\r\n<p>This code introduces several new ideas.<\/p>\r\n<p>The first thing we notice is a top-level structure with two <code>GENERATE<\/code> blocks and several <code>PROCEDURE<\/code>s.<\/p>\r\n<p>The generates are visually separated so each one has its own activity, and they mark the entities born from them in a differentiated way.<\/p>\r\n<pre>\r\nGENERATE ... NAME:G_UTILITY_VEHICLES ; generates utility vehicles\r\n   ....\r\n   ASSIGN ...\r\n   ....\r\n   CALL PROC.MAIN\r\nENDGENERATE 1\r\n<\/pre>\r\n<p>And then we have the set of <code>PROCEDURE<\/code>s:<\/p>\r\n<p>Process procedures:<\/p>\r\n<pre>\r\nPROC.MAIN              ; Main process\r\nPROC.UTILITY_VEHICLES\r\nPROC.TRUCKS\r\n<\/pre>\r\n<p>Decision procedures:<\/p>\r\n<pre>\r\nDECIDE.ROUTE\r\nDECIDE.LOOP_OR_END\r\n<\/pre>\r\n<p><b>PROC.MAIN:<\/b><\/p>\r\n<p>All the main logic is concentrated in the PROC.MAIN process, which is typically built around a <code>WHILE<\/code> loop that keeps entities inside until they meet the condition to finish all their tasks.<\/p>\r\n<pre>\r\nWHILE (\"P$state\"!=\"EXIT\")\r\n    ...\r\n    ...\r\n    ASSIGN state, ????\r\nENDWHILE\r\n<\/pre>\r\n<p>Inside it, the decision over the main routes each entity can take is typically a <code>SWITCH<\/code> with options or several nested <code>IF<\/code>s. It is a good practice to place these decisions into <code>PROCEDURE<\/code>s named <code>DECIDE.*<\/code>, so they are easy to recognize and you know in advance they usually return, directly, the name of the <code>PROCEDURE<\/code> to be invoked by the entity:<\/p>\r\n<pre>\r\nENDPROCEDURE \"P$VALUE\" ; Will return 'PROC.UTILITY_VEHICLES' or 'PROC.TRUCKS'\r\n<\/pre>\r\n<p>That is: CALL DECIDE.AAA will return in P$AAA (the part before the dot is omitted) the value 'PROC.BBB', which can be used directly as CALL P$AAA.<\/p>\r\n<pre>\r\nCALL DECIDE.ROUTE           ; Executes decision logic\r\nCALL \"P$(ROUTE)\"            ; Calls the procedure returned by the decision\r\n<\/pre>\r\n<p>Very similar to the decision to exit or continue looping through the cycle.<\/p>\r\n<p>Other new elements are:<\/p>\r\n<pre>\r\nADVANCE0 {TO:POS_ENTRY,flow:1,layout:H}\r\n<\/pre>\r\n<p>Here it is <code>ADVANCE0<\/code> instead of <code>ADVANCE<\/code> because we only want a visual jump, without the entity consuming time by entering and leaving the event queue.<\/p>\r\n<p>The last novelty is the use of another resource with grouping and statistics utility: <code>QUEUER<\/code>.<\/p>\r\n<p>It has unlimited capacity and makes it easy to know how many—and which—entities are in a given zone.<\/p>\r\n<pre>\r\nQUEUE IN_PARKING  ; enter\r\n...\r\n...\r\nDEPART IN_PARKING ; leave\r\n<\/pre>\r\n<p>In summary, the example shows:<\/p>\r\n<ul>\r\n    <li>How to use multiple <code>GENERATE<\/code> blocks with differentiated logic (trucks and utility vehicles).<\/li>\r\n    <li>How entities can <strong>dynamically decide routes<\/strong> (<code>SWITCH<\/code>, <code>CALL<\/code>, <code>PROCEDURE<\/code>).<\/li>\r\n    <li>How an <strong>internal per-entity loop<\/strong> (<code>WHILE<\/code>) is used to simulate iteration.<\/li>\r\n    <li>How to visualize <strong>flow using positions, subtitles, and styles<\/strong>.<\/li>\r\n    <li>How to combine different <strong>resources<\/strong> (<code>FACILITY<\/code>, <code>STORAGE<\/code>, <code>QUEUE<\/code>).<\/li>\r\n    <li>How to work with <strong>dynamic procedure names<\/strong> (<code>P$(ROUTE)<\/code>).<\/li>\r\n<\/ul>\r\n<p>&nbsp;<\/p>",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            }
        ]
    },
    {
        "id": "243",
        "nombre": "Season 2: Virtual Entities (VE)",
        "texto": "",
        "descripcion": "",
        "parametros": null,
        "parametros_json": null,
        "ejemplo": null,
        "hijos": [
            {
                "id": "244",
                "nombre": "Entities and virtual entities (VE)",
                "texto": "\/* Virtual entities:\nInvisible processes operating in the background.\nThe first entity will create a VE after a delay of 30 time units.\nThat VE will create the next one every 3 time units.\nOnly entities are visible, not VEs.\n*\/\n\nPOSITION {NAME:POS1,X:321,Y:332}\nPOSITION {NAME:POS2,X:517,Y:326}\nGRAPHIC {NAME:Text1,Type:TEXT,X:366,Y:454,Text:\"Counter: 0\"}\n\nINITIAL counter,0\n\nSTART 200\n\n;*****************************************************\nGENERATE 20,0 {NAME:GEN1,X:101,Y:332}\nADVANCE 10 {TO:POS1}\n; Launch a virtual entity that will update the counter\nIF (D$N==1)\n\tTIMEOUT updateCounter,30\nENDIF\nADVANCE 10 {TO:POS2}\n\nENDGENERATE 1\n\n;*****************************************************\nPROCEDURE updateCounter\n    SAVEVALUE counter, X$counter + 1\n    MOVE {NAME:Text1, TEXT:\"I am Virtual Entity D$N. Counter: X$counter\"}\n    TIMEOUT updateCounter, 3\n    TERMINATE_VE\nENDPROCEDURE\n",
                "descripcion": "<p>By now we have more than enough clarity on what an entity is: a little dot moving on the screen. We know it is born from a <code>GENERATE<\/code>, it traverses blocks, advances through positions, and can enter resources.<\/p>\n<p><b>So what is a virtual entity?<\/b> An entity that does not move on the screen.<\/p>\n<p>That difference sounds simple, but it is essentially that—while carrying many implications. Imagine an invisible dot that does not occupy space but still executes instructions.<\/p>\n<p>Let’s define them formally:<\/p>\n<ul>\n    <li>Virtual entities are not born from a <code>GENERATE<\/code>. Instead, they are created by COMMANDS such as <code>TIMER<\/code>, <code>PRE_RUN<\/code>, <code>TRIGGER<\/code> (<code>ON_ENTER<\/code>, <code>ON_QUEUE<\/code>, <code>ON_*<\/code>...), or by the block <code>TIMEOUT<\/code>.<\/li>\n    <li>Their identifier (D$N) is not a positive sequential number (1, 2, ... n) but the opposite: (-1, -2, ... -n).<\/li>\n    <li>Their <code>TERMINATE<\/code> does not subtract terminations. In fact, you will see <code>TERMINATE_VE<\/code>, which ends only virtual entities.<\/li>\n    <li>They have no direct visual representation, but they can interact with the graphical layer just like any other entity.<\/li>\n<\/ul>\n<p><b>What are they for?<\/b><\/p>\n<p>They have countless uses.<\/p>\n<p>Even if it may not look like it, they are the reason GPSS-Plus does not rely on secondary languages to program complementary elements such as Python or Java.<\/p>\n<p>You program them in GPSS-Plus like any other subprogram. They take care of all accessory tasks around entity life cycles. For example, if you want a clock, it makes little sense for it to depend on the birth or movement of entities that already have plenty to worry about while entering and leaving resources.<br>\nInstead, a <code>TIMER<\/code> that automatically fires every N instants can do those tasks.<br>\nIf you want control over multiple resources and the state of their queues, you can have a virtual entity acting as a controller each time an entity enters a queue.<\/p>\n<p>Virtual entities work behind the scenes. You don’t see them move, but without them, many processes simply would not happen.<\/p>\n<p><b>In the example:<\/b><\/p>\n<p>A normal entity, number 1 (<code>D$N==1<\/code>), creates a virtual entity that will be born in 30 time units to execute a procedure:<\/p>\n<pre>\nTIMEOUT updateCounter,30\n<\/pre>\n<p>It does not traverse flow positions nor use resources. It only appears after being requested by an entity and, from then on, the virtual entity schedules a new virtual entity every 3 time units.<br>\nIts only job: counting.<br>\nThe first calls the second, which calls the third... all through the <code>TIMEOUT<\/code> block, which only needs the name of the procedure to be executed by the virtual entity and the time at which it will occur.<br>\nYou can see the text changing even though there are no visible entities updating it. That is because a virtual entity does it, working in the background like a small autonomous process.<\/p>\n<p>This example shows how a VE can act as a <strong>recurring process<\/strong> without any human intervention or physical entity. From now on, you will see that many <strong>system decisions, alarms, or statistics<\/strong> will be managed by this type of invisible entity.<\/p>",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            },
            {
                "id": "200",
                "nombre": "Creation of virtual entities (VE)",
                "texto": "\/* Creation of virtual entities *\/\r\n\r\nSYSTEM {TYPE:ON_TIMER, TRIGGER:TIMER1, INTERVAL:53}\r\nSYSTEM {TYPE:PRE_RUN, TRIGGER:PRE_RUN}\r\n\r\nPOSITION {NAME:POS1,X:311,Y:497}\r\nPOSITION {NAME:POS2,X:571,Y:147,TYPE:TERMINATE,TITLE:END}\r\n\r\nFACILITY {NAME:Facility1,X:573,Y:483,ON_RELEASE:on_RELEASE_Facility1}\r\n\r\nGRAPHIC {NAME:Text_Pre_run,Type:TEXT,X:253,Y:196}\r\nGRAPHIC {NAME:Text_TIMER1,Type:TEXT,X:253,Y:158}\r\nGRAPHIC {NAME:Text_Timeout1,Type:TEXT,X:254,Y:252}\r\nGRAPHIC {NAME:Text_on_release,Type:TEXT,X:575,Y:544}\r\n\r\nSTART 40\r\n\r\nGENERATE 30,0 {NAME:GEN1,X:110,Y:510,ECOLOR:#FF3333,ERADIO:8}\r\n\tIF (\"P$PARAM_A\"==\"PRE_RUN\")\r\n    \tMOD {COLOR:magenta,SUBTITLE:pre_run}\r\n    ENDIF\r\n\tIF (\"P$PARAM_A\"==\"TIMER1\")\r\n    \tMOD {COLOR:blue,SUBTITLE:timer1}\r\n    ENDIF\r\n    ADVANCE 30,2 {TO:POS1,flow:1}\r\n    ADVANCE 30,2 {TO:Facility1,flow:1}\r\n    TIMEOUT Timeout1,0,D$N ; pass the entity number as a parameter\r\n    SEIZE Facility1\r\n    ADVANCE 30,30\r\n    RELEASE Facility1\r\n    ADVANCE 30,2 {TO:POS2,flow:1}\r\nENDGENERATE 1\r\n\r\n;******************************************\r\nPROCEDURE PRE_RUN\r\n\tMOVE {NAME:Text_Pre_run,TEXT:\"I am [D$N] PRE_RUN.\\nI create a new entity.\"}\r\n    NEW GEN1,0,\"pre_run\"\r\n    TERMINATE_VE\r\nENDPROCEDURE\r\n;---------------------------------\r\nPROCEDURE TIMER1\r\n\tMOVE {NAME:Text_TIMER1,TEXT:\"I am [D$N] TIMER1.\\nI create a new entity.\"}\r\n    NEW GEN1,0,\"timer1\" ; Generate, time, PARAM_A, PARAM_B...\r\n\tTERMINATE_VE\r\nENDPROCEDURE\r\n;---------------------------------\r\nPROCEDURE Timeout1\r\n\tMOVE {NAME:Text_Timeout1,TEXT:\"I am [D$N] Timeout1.\\nEntity [P$PARAM_A] is about to enter\"}\r\n\tTERMINATE_VE\r\nENDPROCEDURE\r\n\r\nPROCEDURE on_RELEASE_Facility1\r\n\tMOVE {NAME:Text_on_release,TEXT:\"I am [D$N] on_RELEASE.\\nEntity [P$ENTITYNUMBER] leaves Facility1\"}\r\n\tTERMINATE_VE\r\nENDPROCEDURE\r\n\r\n;******************************************\r\n",
                "descripcion": "<p>We have already seen what a virtual entity is: an entity that does not move on the screen but still executes instructions and participates in the simulation engine.<\/p>\r\n<p>Now we will see <strong>how these virtual entities are created<\/strong> and who can create them.<\/p>\r\n<h3>Who creates a VE?<\/h3>\r\n<p>Virtual entities are not born from a <code>GENERATE<\/code> block like normal entities. Instead, they can be created by four different mechanisms:<\/p>\r\n<ul>\r\n    <li><strong>The system<\/strong>, using:\r\n        <ul>\r\n            <li><code>PRE_RUN<\/code> – at the beginning of the simulation, once.<\/li>\r\n            <li><code>TIMER<\/code> – at fixed intervals defined by <code>INTERVAL<\/code>.<\/li>\r\n        <\/ul>\r\n    <\/li>\r\n    <li><strong>An entity<\/strong>, using:\r\n        <ul>\r\n            <li><code>TIMEOUT<\/code> – schedules the execution of a VE X time units in the future.<\/li>\r\n        <\/ul>\r\n    <\/li>\r\n    <li><strong>A resource<\/strong>, using <code>ON_*<\/code> events such as:\r\n        <ul>\r\n            <li><code>ON_SEIZE<\/code>, <code>ON_RELEASE<\/code>, <code>ON_LEAVE<\/code>, etc.<\/li>\r\n        <\/ul>\r\n    <\/li>\r\n<\/ul>\r\n<p><b>What do they all have in common?<\/b><\/p>\r\n<p>All virtual entities execute a <code>PROCEDURE<\/code>, which may be specified as a <code>TRIGGER<\/code> or as a procedure name. That <code>PROCEDURE<\/code> is the “code” executed by the VE. <strong>It must end with <code>TERMINATE<\/code> or <code>TERMINATE_VE<\/code><\/strong>, just like any normal entity.<\/p>\r\n<p><b>About parameters<\/b><\/p>\r\n<p>When using <code>NEW<\/code>, <code>TIMEOUT<\/code>, or <code>CALL<\/code>, we can pass additional parameters. These will be available inside the procedure as <code>P$PARAM_A<\/code>, <code>P$PARAM_B<\/code>, etc., just as we have already seen with <code>CALL<\/code>.<\/p>\r\n<p>This allows a VE to “know” who invoked it or why.<\/p>\r\n<p><b>In the example:<\/b><\/p>\r\n<ul>\r\n    <li><code>PRE_RUN<\/code> creates an entity at the start (magenta color).<\/li>\r\n    <li><code>TIMER1<\/code> creates one every 53 time units (blue color).<\/li>\r\n    <li><code>TIMEOUT<\/code> fires just before entering the resource and leaves a message.<\/li>\r\n    <li><code>ON_RELEASE<\/code> fires when <code>FACILITY1<\/code> is released.<\/li>\r\n<\/ul>\r\n<p>Each time one of these virtual entities is created, a message appears on screen showing its identifier and what it is doing.<\/p>",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            },
            {
                "id": "251",
                "nombre": "Permanent VEs: agents",
                "texto": "\/* Agents: Permanent Virtual Entities\nResource monitoring with an infinite loop.\n*\/\n\nSYSTEM {TYPE:PRE_RUN,TRIGGER:PRE_RUN}\n\nPOSITION {NAME:POS1,X:311,Y:497}\nPOSITION {NAME:POS2,X:571,Y:147,TYPE:TERMINATE,TITLE:END}\n\nFACILITY {NAME:Facility1,X:573,Y:483}\n\nGRAPHIC {NAME:Text_agent,Type:TEXT,X:229,Y:305}\n\nSTART 40\n\nGENERATE 30,0 {NAME:GEN1,X:110,Y:510,ECOLOR:#FF3333,ERADIO:8}\n    ADVANCE 30,2 {TO:POS1,flow:1}\n    ADVANCE 30,2 {TO:Facility1,flow:1}\n    SEIZE Facility1\n    ADVANCE 30,30\n    RELEASE Facility1\n    ADVANCE 30,2 {TO:POS2,flow:1}\nENDGENERATE 1\n\n;******************************************\nPROCEDURE PRE_RUN\n    TIMEOUT AGENT.INIT,0\n    TERMINATE_VE\nENDPROCEDURE\n;---------------------------------\nPROCEDURE AGENT.INIT\n\tSAVEVALUE agentId,D$N\n\tWHILE (1==1)\n \t   MOVE {NAME:Text_agent,TEXT:\"I am agent [D$N].\\nTime AC1$\\nEntities in Facility1: R$(Facility1,IN)\\nEntities in queue: R$(Facility1,QUEUE)\"}\n  \t  ADVANCE 10\n    ENDWHILE\n\tTERMINATE_VE\nENDPROCEDURE\n",
                "descripcion": "<p>A special type of virtual entity is one that <strong>does not die<\/strong> at the end of its procedure.<\/p>\n<p>These <strong>VEs that remain active throughout the entire simulation<\/strong> (or part of it) are called <strong>agents<\/strong>.<\/p>\n<ul>\n    <li>They are like background processes that never terminate.<\/li>\n    <li>They are usually launched from <code>PRE_RUN<\/code> via a <code>TIMEOUT<\/code>.<\/li>\n    <li>They store their <strong>entity number (D$N)<\/strong> in a <code>SAVEVALUE<\/code>, so they can be interacted with or their state can be queried.<\/li>\n<\/ul>\n<p>Later on, we will see that these agents handle <strong>control tasks<\/strong>, <strong>monitoring<\/strong>, or <strong>coordination<\/strong> between resources.<\/p>\n<p>In short, an agent is a VE that does not terminate and stays alive in a loop. This allows it to remain attentive—waiting or watching the environment.<\/p>",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            },
            {
                "id": "370",
                "nombre": "Component entities",
                "texto": "<p>In addition to normal entities and agents, the model supports a third type of entity: <strong>component entities<\/strong>.<br>\nA component entity is an entity that exists to execute a function <em>on behalf<\/em> of another entity. It is not a physical object nor an external resource, but an active part of its behavior—something the entity “does” continuously or in parallel.<\/p>\n<p>This concept makes it possible to model very natural situations:<br>\na diver who breathes and consumes oxygen while moving forward, a vehicle whose wheels wear down while driving, or a person who reads a piece of news and changes their decision while waiting in a bus queue.<\/p>\n<p>Later on, we will see how they are created and how they work together with the main entity. For now, it is enough to understand that they allow an entity to be more than a single sequential thread, becoming instead a small system made up of multiple entities collaborating with each other.<\/p>",
                "descripcion": "",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            }
        ]
    },
    {
        "id": "278",
        "nombre": "Season 3: DSL (Domain-Specific Language)",
        "texto": "",
        "descripcion": "",
        "parametros": null,
        "parametros_json": null,
        "ejemplo": null,
        "hijos": [
            {
                "id": "284",
                "nombre": "DSL philosophy",
                "texto": "\/* Season 3: DSL\nExample of a simple model using the GPSS-Plus DSL.\n*\/\n\nFACILITY {NAME:COUNTER, X:300, Y:300} ; Define the service counter in space.\nPOSITION {NAME:EXIT, X:500, Y:300}    ; Define the exit in space.\n\nSTART 100                               ; Run until 100 entities have been served\n;------------------------------------------------------------------------------------\nGENERATE 60,10 {NAME:GEN1, X:100, Y:300} ; Position the entity generator.\n    ADVANCE 10 {TO:COUNTER}               ; Move to the counter.\n    SEIZE COUNTER                         ; Seize the COUNTER resource.\n    ADVANCE 60,30                         ; Service time: 60 to 90 seconds.\n    RELEASE COUNTER                       ; Release the resource.\n    ADVANCE 10 {TO:EXIT}                  ; Move to the exit.\nTERMINATE 1                              ; The entity finishes.\n",
                "descripcion": "<h3>GPSS-Plus DSL philosophy<\/h3>\n<p>The GPSS-Plus DSL is not intended as a general-purpose programming language, nor as an alternative notation for drawing blocks. It is designed as <strong>the operational language of the simulation engine<\/strong>.<\/p>\n<p>When working with the DSL, the user does not “program”: <strong>they define behaviors, resources, and events that the engine executes over time<\/strong>. They <b>model<\/b>.<\/p>\n<p>To understand it properly, it is useful to think of the DSL as a set of tools organized into four levels.<\/p>\n<hr>\n<h3>1. Visible or physical entities: behavior of the “dots”<\/h3>\n<p>The first level of the DSL is aimed at defining <strong>what the entities that move through the model do<\/strong>.<\/p>\n<p>These entities:<\/p>\n<ul>\n    <li>are born (<code>GENERATE<\/code>),<\/li>\n    <li>advance in time (<code>ADVANCE<\/code>),<\/li>\n    <li>interact with resources (<code>SEIZE<\/code>, <code>ENTER<\/code>, <code>REST<\/code>…),<\/li>\n    <li>make decisions (<code>IF<\/code>, <code>SWITCH<\/code>),<\/li>\n    <li>and eventually die (<code>TERMINATE<\/code>).<\/li>\n<\/ul>\n<p>All their behavior is described <strong>step by step<\/strong>, but that step-by-step is not real sequential execution: it is execution over an event queue.<\/p>\n<p>At this level, the DSL provides:<\/p>\n<ul>\n    <li>flow blocks,<\/li>\n    <li>time control,<\/li>\n    <li>conditional structures and loops,<\/li>\n    <li>procedure calls.<\/li>\n<\/ul>\n<p>This is the most visible level of the model and the one closest to user intuition.<\/p>\n<hr>\n<h3>2. Virtual entities (VE): parallel behavior<\/h3>\n<p>Not all behavior belongs to a visible “dot”.<\/p>\n<p>GPSS-Plus introduces <strong>virtual entities (VE)<\/strong> to model logic that:<\/p>\n<ul>\n    <li>has no graphical representation,<\/li>\n    <li>does not traverse the circuit,<\/li>\n    <li>but <strong>lives inside the simulation engine<\/strong>.<\/li>\n<\/ul>\n<p>VEs make it possible to:<\/p>\n<ul>\n    <li>react to events (<code>ON_SEIZE<\/code>, <code>ON_RELEASE<\/code>, <code>SIGNAL<\/code>),<\/li>\n    <li>execute periodic logic (<code>TIMEOUT<\/code>),<\/li>\n    <li>act as agents, controllers, or even components,<\/li>\n    <li>coordinate other entities without blocking them.<\/li>\n<\/ul>\n<p>From the DSL point of view, <strong>a VE is a complete entity<\/strong>, with its own life cycle, but oriented toward system control or entity coordination.<\/p>\n<hr>\n<h3>3. Resources: the environment entities interact with<\/h3>\n<p>The third level of the DSL defines the <strong>model environment<\/strong>.<\/p>\n<p>Resources represent what entities use, occupy, wait for, or query. They can be:<\/p>\n<ul>\n    <li><strong>physical<\/strong>: <code>FACILITY<\/code>, <code>STORAGE<\/code>, <code>RESTROOM<\/code>, <code>STOCK<\/code><\/li>\n    <li><strong>logical<\/strong>: <code>QUEUER<\/code>, <code>CONDITIONS<\/code>, <code>FSM<\/code><\/li>\n    <li><strong>external<\/strong>: <code>BRIDGER<\/code>, <code>FILE<\/code>, <code>TABLE<\/code>, <code>PLOTTER<\/code><\/li>\n<\/ul>\n<p>Each resource follows the same conceptual pattern:<\/p>\n<ol>\n    <li>it is defined by a <b>COMMAND<\/b>,<\/li>\n    <li>it is used via paired <b>BLOCKS<\/b>,<\/li>\n    <li>it is observed through <b>SNAs<\/b>.<\/li>\n<\/ol>\n<p>The DSL does not hide resource state: <strong>everything can be read, queried, and used in decisions<\/strong>.<\/p>\n<hr>\n<h3>4. The engine: time, events, and system<\/h3>\n<p>Beneath entities and resources lies a fourth, less visible but fundamental level: <strong>the simulation engine<\/strong>.<\/p>\n<p>The DSL allows explicit interaction with it by:<\/p>\n<ul>\n    <li>controlling simulated time,<\/li>\n    <li>scheduling future events (<code>TIMEOUT<\/code>),<\/li>\n    <li>configuring the system (<code>SYSTEM<\/code>),<\/li>\n    <li>accessing the event queue and internal state via SNAs.<\/li>\n<\/ul>\n<p>This enables models where behavior is not just “flow”, but <strong>reaction, synchronization, and planning<\/strong>.<\/p>",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            },
            {
                "id": "283",
                "nombre": "Objects and arrays in ASSIGN and SAVEVALUE",
                "texto": "\/* Structured variables: Arrays and Objects\nDeclaration, access, and modification of complex data.\n*\/\n\nPOSITION {NAME:POS1,X:300,Y:100}\n\nINITIAL posY,400\nGRAPHIC {NAME:Text1,Type:TEXT,X:324,Y:X$posY - 0}\nGRAPHIC {NAME:Text2,Type:TEXT,X:324,Y:X$posY - 20}\nGRAPHIC {NAME:Text3,Type:TEXT,X:324,Y:X$posY - 40}\nGRAPHIC {NAME:Text4,Type:TEXT,X:324,Y:X$posY - 60}\nGRAPHIC {NAME:Text5,Type:TEXT,X:324,Y:X$posY - 80}\nGRAPHIC {NAME:Text6,Type:TEXT,X:324,Y:X$posY - 100}\nGRAPHIC {NAME:Text7,Type:TEXT,X:324,Y:X$posY - 120}\nGRAPHIC {NAME:Text8,Type:TEXT,X:324,Y:X$posY - 140}\nGRAPHIC {NAME:Text9,Type:TEXT,X:324,Y:X$posY - 160}\n\nSTART 1\n\n;*****************************************************************\n\nGENERATE 1,0,0,1 {NAME:GEN1,X:100,Y:100}\n\n; --- Declarations of all types ---\nASSIGN myNumber, 10 * 2\nASSIGN myText, \"Result\"\nASSIGN myArray, [10, 20, 30]\nASSIGN myObject, {key1: 222, key2: 333}\nASSIGN myArrayOfObjects, [10, {key1: 555, key2: (111 * 6)}, 30]\n\n; --- Path-based access ---\nASSIGN sum, P$(myArray.0) + P$(myArray.1)\n\n; --- Path-based modifications ---\nASSIGN myArray.2, 777\nASSIGN myObject.key1, {depth: \"inner value\"}\nASSIGN myObject.key2, V$(myArray.2)\n\n; --- Raw-value copies (entire structures) ---\nASSIGN objectCopy, V$(myObject)\nASSIGN copiedElement, V$(myArrayOfObjects.1)\n\n; --- Length evaluation ---\nASSIGN arraySize, P$(myArrayOfObjects.LENGTH)\n\n; --- Display ---\nMOVE {NAME:Text1, TEXT: \"myNumber = P$myNumber\"}\nMOVE {NAME:Text2, TEXT: \"myText = P$myText\"}\nMOVE {NAME:Text3, TEXT: \"myArray.2 = P$(myArray.2)\"}\nMOVE {NAME:Text4, TEXT: \"myObject.key1.depth = P$(myObject.key1.depth)\"}\nMOVE {NAME:Text5, TEXT: \"myObject.key2 (copied) = P$(myObject.key2)\"}\nMOVE {NAME:Text6, TEXT: \"myArrayOfObjects.1.key2 = P$(myArrayOfObjects.1.key2)\"}\nMOVE {NAME:Text7, TEXT: \"objectCopy.key2 = P$(objectCopy.key2)\"}\nMOVE {NAME:Text8, TEXT: \"copiedElement.key1 = P$(copiedElement.key1)\"}\nMOVE {NAME:Text9, TEXT: \"Array length = P$arraySize\"}\n\nADVANCE 100,0 {TO:POS1}\nENDGENERATE 1\n",
                "descripcion": "<p>As far as the language is concerned, the evolution from classic GPSS to GPSS-Plus has two major turning points:<\/p>\n<ul>\n    <li>The introduction of <b>STACKS<\/b>, which enable loops, nested calls, and complex control structures.<\/li>\n    <li>The expansion of the <code>SAVEVALUE<\/code> and <code>ASSIGN<\/code> variable system, which now stores not only numbers but also <b>strings<\/b>, <b>arrays<\/b>, and <b>objects<\/b>, and allows functions to be executed on them.<\/li>\n<\/ul>\n<p>This second advance makes older elements like <code>MATRIX<\/code> obsolete and allows GPSS-Plus to include native functions found in any modern language such as <code>push<\/code>, <code>concat<\/code>, <code>merge<\/code>, or <code>split<\/code>, all within the simulator’s own logic and without resorting to external programming. What used to be solved with rigid tools can now be done in an expressive, structured, and maintainable way. GPSS-Plus stops being a card-based language with numbers and becomes a <b>full-purpose DSL<\/b>, oriented to event flows and structured data manipulation.<\/p>\n<p>We already know GPSS-Plus lets you declare variables with two scope levels:<\/p>\n<ul>\n    <li><b>ASSIGN<\/b>: entity-local variable.<\/li>\n    <li><b>SAVEVALUE<\/b>: global variable, shared among entities.<\/li>\n<\/ul>\n<p>Their behavior is identical except for visibility. In both cases, variables can hold different data types:<\/p>\n<ul>\n    <li><b>Numbers<\/b>: written as usual: <b>123.4<\/b><\/li>\n    <li><b>Strings<\/b>: always in double quotes: <b>\"Some text\"<\/b><\/li>\n    <li><b>Arrays<\/b>: written in brackets with comma-separated elements: <b>[10,20,\"some text\",\"other text\",30]<\/b><\/li>\n    <li><b>Objects<\/b>: written in braces with key:value pairs: <b>{key1:\"Some text\",key2:123.4,key3:[10,20,30]}<\/b><\/li>\n<\/ul>\n<p>Note that there is no boolean type: 0 is used for false and 1 for true. Examples:<\/p>\n<pre>\nASSIGN myNumber, 10\nASSIGN myText, \"hello\"\nASSIGN myList, [10, 20, 30]\nASSIGN myObject, {key1: 20, key2: \"hello\"}\nASSIGN mixed, [10, {key: \"data\"}, 30]\n<\/pre>\n<p><b>Access via paths in their SNA<\/b><br>\nThe SNA associated with these variables are <code>P$<\/code> (for <code>ASSIGN<\/code>) and <code>X$<\/code> (for <code>SAVEVALUE<\/code>). But since variables can now be more than numbers, SNAs become more versatile so you can access any part of a variable. Access is guided by a path of keys separated by dots, both for arrays and objects:<\/p>\n<pre>\nASSIGN grades, [8,4,5]\nASSIGN avg, (P$(grades.0) + P$(grades.1) + P$(grades.2)) \/ 3\n<\/pre>\n<pre>\nASSIGN grades, {examGrade1:8,examGrade2:4,examGrade3:5}\nASSIGN avg, (P$(grades.examGrade1) + P$(grades.examGrade2) + P$(grades.examGrade3)) \/ 3\n<\/pre>\n<p>And all of this can become as complex as needed by embedding SNAs anywhere in the notation to build the right path:<\/p>\n<pre>\nASSIGN number_0,0\nASSIGN number_1,1\nASSIGN number_2,2\n\nASSIGN grades, {examGrade_0:8,examGrade_1:4,examGrade_2:5}\nASSIGN avg, (P$(grades.examGrade_P$number_0) + P$(grades.examGrade_P$number_1) + P$(grades.examGrade_P$number_2)) \/ 3\n<\/pre>\n<p>Or accessing an array inside an object, or an object inside an array, following the same approach:<\/p>\n<pre>\nASSIGN group, [{name: \"Luis\"}, {name: \"Marta\"}]\nASSIGN firstName, P$(group.0.name)\n<\/pre>\n<p>There is a single reserved word for these paths: <code>LENGTH<\/code><\/p>\n<pre>\nASSIGN length, P$(anArray.LENGTH)\n<\/pre>\n<p><b>Partial modification via paths<\/b><br>\nYou can also modify part of a structure by addressing it directly:<\/p>\n<pre>\nASSIGN anArray.0, {key1: \"text1\"}\n<\/pre>\n<p>turning the first array element into an object.<\/p>\n<p><b>SNA for access without evaluation: <code>V$<\/code><\/b><br>\nWhile <code>P$<\/code> and <code>X$<\/code> evaluate contents to be displayed, <code>V$<\/code> returns the raw content (number, string, object, or array) without any processing. This is necessary to pass a whole array or object through a parameter or to make perfect copies.<\/p>\n<pre>\n; make a copy:\nASSIGN students,[{name:\"Ana\",age:20},{name:\"Alberto\",age:22},{name:\"Antonio\",age:19}]\nASSIGN studentsCopy, V$(students)\n\n; get a specific element\nASSIGN element, V$(anArray.1)\n\n; or pass it as a parameter\nCALL goToClass, V$(anArray.1)\n<\/pre>\n<p>It is important to distinguish <code>P$someText<\/code> from <code>V$someText<\/code>.<\/p>\n<pre>\nASSIGN myName,\"Antonio\"\nMOVE {name:text1,text:\"My name is P$myName\"} ; shows 'My name is Antonio'\nMOVE {name:text1,text:\"My name is V$myName\"} ; shows 'My name is \"Antonio\"'\n<\/pre>\n<p>This difference exists precisely because <code>V$<\/code> retrieves the raw datum, which includes the type declaration—in this case, a string.<br>\n<code>V$<\/code> should not be used directly inside strings. It is reserved for contexts where a structured value is expected.<\/p>\n<p>As a final note, null handling is done with the \"?\" operator, so you can assign a value if it has not been assigned before with:<\/p>\n<pre>\nASSIGN max_value, P$max_value ? P$max_value : 100\n<\/pre>\n<p>&nbsp;<\/p>",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            },
            {
                "id": "281",
                "nombre": "SNA (String Numeric Accessor)",
                "texto": "\/* SNA: System and Resource Attributes\nA virtual entity monitors the queue state of a resource.\n*\/\n\nSYSTEM {TYPE:ON_TIMER, TRIGGER:Timer1, INTERVAL: 5}\n\nFACILITY {NAME:Ventanilla,X:470,Y:308}\nGRAPHIC {NAME:Text1,Type:TEXT,X:471,Y:254}\nGRAPHIC {NAME:Text2,Type:TEXT,X:471,Y:234}\n\nSTART 100\n\nGENERATE 10,0 {NAME:gen1,X:115,Y:307}\n    ADVANCE 20 {TO:Ventanilla}\n    SEIZE Ventanilla\n    ADVANCE 20\n    RELEASE Ventanilla\nENDGENERATE 1\n\n; Display current queue status periodically\n\nPROCEDURE Timer1\n    ASSIGN number, D$N\n    MOVE {NAME:Text1, TEXT:\"I am virtual entity number: P$number\"}\n    MOVE {NAME:Text2, TEXT:\"T: AC1$       Entities in queue: R$(Ventanilla,QUEUE)\"}\n    TERMINATE\nENDPROCEDURE 1",
                "descripcion": "<p>We already know that an <code>ASSIGN<\/code> creates an attribute (variable) associated with each entity or virtual entity, and that a <code>SAVEVALUE<\/code> is a global system value.<br>\nWe have also seen that they are accessed through expressions such as <code>P$name<\/code> or <code>X$name<\/code>.<br>\nThese expressions are called <b>SNA<\/b>, <i>String\/Numeric Accessors<\/i>, and they are a fundamental language mechanism to dynamically access any value in the model.<\/p>\n<ul>\n    <li><code>P$name<\/code> — Returns the content as <b>text<\/b>. Useful for traces, graphic labels, or string concatenation.<\/li>\n    <li><code>V$name<\/code> — Returns the <b>raw value<\/b> (string, number, object, or array), exactly as it was assigned.<\/li>\n    <li><code>X$name<\/code> — Returns the content of a <code>SAVEVALUE<\/code> (global value).<\/li>\n<\/ul>\n<pre>\nASSIGN aVariable, {name:\"Antonio\", age:30}\nCALL fun, V$(aVariable) ; sends the object itself\n<\/pre>\n<p>Additionally, there are specific SNAs to access <b>system data<\/b>:<\/p>\n<ul>\n    <li><code>AC1$<\/code> — Current system time.<\/li>\n    <li><code>TG1$<\/code> — Number of entities pending execution.<\/li>\n<\/ul>\n<p>And also <b>resource properties<\/b>:<\/p>\n<ul>\n    <li><code>R$(resource, property)<\/code> — Returns the requested property value.<\/li>\n    <li><code>R$(storage1, IN)<\/code> — Entries into a <code>STORAGE<\/code>.<\/li>\n    <li><code>R$(facility3, ENTRIES)<\/code> — Number of uses of a <code>FACILITY<\/code>.<\/li>\n    <li><code>R$(market1, QUEUE)<\/code> — Current queue length.<\/li>\n<\/ul>\n<p>SNAs are not instructions; they are expressions.<br>\nThey are evaluated anywhere a value is expected, which makes them an essential tool for decisions, message construction, calculations, or access to complex structures.<\/p>\n<p>In the example, two very representative SNAs are used:<\/p>\n<ul>\n    <li><code>AC1$<\/code>: the current system time.<\/li>\n    <li><code>R$(VENTANILLA,QUEUE)<\/code>: current queue state of the resource.<\/li>\n    <li><code>D$N<\/code>: returns the identifier of the current virtual entity. In this case, it is stored in a variable <code>number<\/code> via <code>ASSIGN<\/code>, and later accessed using <code>P$number<\/code>.<\/li>\n<\/ul>\n<p>This shows how SNAs can be used both to obtain system data and to manipulate entity-specific variables, and how they integrate seamlessly with visual commands such as <code>MOVE<\/code>.<\/p>\n<p>Finally, we have the <code>SYS$<\/code> SNA, which contains basic system variables inside an object, such as date and time information:<\/p>\n<pre>\nASSIGN sys, SYS$\nMOVE {NAME:REALTIME1, TEXT:\"P$(sys.date.year)\/P$(sys.date.month)\/P$(sys.date.day)\"}\nMOVE {NAME:REALTIME2, TEXT:\"P$(sys.date.hour):P$(sys.date.min):P$(sys.date.sec)\"}\n<\/pre>\n<p><b>Direct access to entity data:<\/b><\/p>\n<p>The <strong>D$<\/strong> SNA allows querying internal properties of any entity in the system.<br>\nIts general syntax is:<\/p>\n<pre>\nD$(property)                    ; current entity\nD$(property, entityNumber)      ; specific entity\n<\/pre>\n<p>If the second parameter is omitted, <code>D$N<\/code> (the current entity) is assumed.<\/p>\n<p>All these properties apply both to the current entity and to any other entity if its number is specified:<\/p>\n<ul>\n    <li><b>N<\/b>, <b>ID<\/b> — Entity identifier<\/li>\n    <li><b>M0<\/b>, <b>M1<\/b> — Parameters M0 and M1<\/li>\n    <li><b>BLOCK<\/b> — Current block index<\/li>\n    <li><b>STEP<\/b> — Executed step number<\/li>\n    <li><b>RESOURCETIME<\/b> — Time inside the current FACILITY\/STORAGE<\/li>\n    <li><b>RESOURCENAME<\/b> — Name of the occupied resource<\/li>\n    <li><b>ADVANCESTART<\/b> — Time when the current ADVANCE started<\/li>\n    <li><b>ADVANCELAPSE<\/b> — Remaining duration of the ADVANCE<\/li>\n    <li><b>X<\/b>, <b>Y<\/b>, <b>Z<\/b> — Visual coordinates<\/li>\n    <li><b>T<\/b> — Absolute creation time<\/li>\n    <li><b>CX<\/b> — Entity context<\/li>\n<\/ul>\n<p>It is also possible to check for the existence of an entity using the same <code>D$<\/code> SNA:<\/p>\n<pre>\nIF (D$(EXIST,1000)==1)\n    ; entity 1000 is active\nENDIF\n<\/pre>",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            },
            {
                "id": "289",
                "nombre": "Native Functions",
                "texto": "POSITION {NAME:POS1,X:300,Y:100}\n\nINITIAL posY,500\nGRAPHIC {NAME:Text1,Type:TEXT,X:324,Y:X$posY - 0}\nGRAPHIC {NAME:Text2,Type:TEXT,X:324,Y:X$posY - 20}\nGRAPHIC {NAME:Text3,Type:TEXT,X:324,Y:X$posY - 40}\nGRAPHIC {NAME:Text4,Type:TEXT,X:324,Y:X$posY - 60}\nGRAPHIC {NAME:Text5,Type:TEXT,X:324,Y:X$posY - 80}\nGRAPHIC {NAME:Text6,Type:TEXT,X:324,Y:X$posY - 100}\nGRAPHIC {NAME:Text7,Type:TEXT,X:324,Y:X$posY - 120}\nGRAPHIC {NAME:Text8,Type:TEXT,X:324,Y:X$posY - 140}\nGRAPHIC {NAME:Text9,Type:TEXT,X:324,Y:X$posY - 160}\nGRAPHIC {NAME:Text10,Type:TEXT,X:324,Y:X$posY - 180}\nGRAPHIC {NAME:Text11,Type:TEXT,X:324,Y:X$posY - 200}\nGRAPHIC {NAME:Text12,Type:TEXT,X:324,Y:X$posY - 220}\nGRAPHIC {NAME:Text13,Type:TEXT,X:324,Y:X$posY - 240}\nGRAPHIC {NAME:Text14,Type:TEXT,X:324,Y:X$posY - 260}\n\nSTART 1\n\nGENERATE 1,0,0,1 {NAME:GEN1,X:100,Y:100}\n\n; Base variables\nASSIGN greeting, \"Hello\"\nASSIGN complement, \"world\"\nASSIGN originalMessage, \"   Hello World GPSS+   \"\nASSIGN names, [\"Ana\", \"Luis\", \"Eva\"]\nASSIGN otherNames, [\"Sonia\", \"David\"]\nASSIGN textWithSeparator, \"one,two,three,four,five\"\n\n; Array methods\nASSIGN.PUSH names, \"Ricardo\" ; [\"Ana\", \"Luis\", \"Eva\", \"Ricardo\"]\nASSIGN.UNSHIFT names, \"Laura\" ; [\"Laura\", \"Ana\", \"Luis\", \"Eva\", \"Ricardo\"]\nASSIGN.EXTEND names, V$otherNames ; [\"Laura\", \"Ana\", \"Luis\", \"Eva\", \"Ricardo\", \"Sonia\", \"David\"]\nASSIGN.SLICE names, {START:1,END:6} ; [\"Ana\", \"Luis\", \"Eva\", \"Ricardo\", \"Sonia\"]\n\n; String methods\nASSIGN.JOIN finalMessage, {DATA:[\"P$greeting\", \" \", \"P$complement\", \"!\"]} ; \"Hello world!\"\nASSIGN.JOIN namesText, {DATA:V$names,SEP:\" - \"} ; \"Ana - Luis - Eva\"\nASSIGN.SPLIT words, {DATA:V$textWithSeparator, SEP:\",\"} ; [\"one\",\"two\",\"three\",\"four\",\"five\"]\nASSIGN.TRIM originalMessage ; \"Hello World GPSS+\"\nASSIGN.LENGTH originalMessage, messageLength ; 16\n\n; Objects\nASSIGN data, {name:\"John\", age:25}\nASSIGN newData, {city:\"Madrid\", age:30}\nASSIGN.MERGE data, V$newData\nASSIGN.DELETE data, city\n\n; Numeric\nASSIGN counter, 10\nASSIGN.INC counter,-5\nASSIGN.INC counter\n\n; Keys\nASSIGN students, {ana:{age:20}, luis:{age:25}}\nASSIGN.KEYS students, studentKeys\n\n; Access paths\nASSIGN myObject, {}\nASSIGN myObject.key1, 123\n;ASSIGN myObject.key2.otherLevel, \"error\" -> error because it does not exist\nASSIGN myArray, []\nASSIGN myArray.2, 99\nASSIGN myArray.3, []\nASSIGN.PUSH myArray.3, 199\n\n; Display results\nMOVE {NAME:Text1, TEXT:\"Final message: P$finalMessage\"}\nMOVE {NAME:Text2, TEXT:\"Names (2): P$(names.2) LENGTH: VD$(names,LENGTH)\"}\nMOVE {NAME:Text3, TEXT:\"Names text: P$namesText\"}\nMOVE {NAME:Text4, TEXT:\"Words[1]: P$(words.1)\"}\nMOVE {NAME:Text5, TEXT:\"Trimmed text: P$originalMessage\"}\nMOVE {NAME:Text6, TEXT:\"Message length: P$messageLength\"}\nMOVE {NAME:Text7, TEXT:\"data.age: P$(data.age)\"}\nMOVE {NAME:Text8, TEXT:\"data.city: P$(data.city)\"} ; should be empty\nMOVE {NAME:Text9, TEXT:\"Final counter: P$counter\"}\nMOVE {NAME:Text10, TEXT:\"studentKeys[1]: P$(studentKeys.1)\"}\nMOVE {NAME:Text11, TEXT:\"Type of names: VD$(names,TYPEOF)\"}\nMOVE {NAME:Text12, TEXT:\"Students has luis?: VD$(students,HASKEY,luis)\"}\nMOVE {NAME:Text13, TEXT:\"myObject.key1: P$(myObject.key1)\"}\nMOVE {NAME:Text14, TEXT:\"myArray.3.0: P$(myArray.3.0)\"}\n\nADVANCE 100,0 {TO:POS1}\nENDGENERATE 1",
                "descripcion": "<p>Native functions allow operating directly on the contents of a variable, whether numeric, string, array, or object. Some functions modify the variable in place.<\/p>\n<p>The format is always the same:<\/p>\n<p>ASSIGN.&lt;FUNCTION&gt; targetVariable, parameter [,targetEntityNumber]<br>\nSAVEVALUE.&lt;FUNCTION&gt; targetVariable, parameter<\/p>\n<p>If the variable does not exist, it is created.<\/p>\n<p>It is very important to note that JSON objects and arrays can only be created using these two blocks and the INITIAL command. Any other COMMAND or BLOCK that requires object or array parameters must receive an already-created structure via the SNA V$(variable).<\/p>\n<pre>\nCALL fun, V$(structure)\nCALL fun, P$(variable)\n<strike>CALL fun, {name:\"Antonio\"}<\/strike> ; objects are not interpreted outside ASSIGN, SAVEVALUE or INITIAL\n<strike>CALL fun, [1,2,V$(otherList)]<\/strike> ; objects are not interpreted outside ASSIGN, SAVEVALUE or INITIAL\n<\/pre>\n<h3>Functions:<\/h3>\n<p><b>1. Numeric variables<\/b><\/p>\n<ul>\n    <li><code>.INC value<\/code> – increments the current value, 1 by default. <i>Modifies its contents<\/i>\n    <pre>\nASSIGN.INC counter\nASSIGN.INC counter,10\nASSIGN.INC myObject.score\n<\/pre>\n    <\/li>\n<\/ul>\n<p><b>2. String variables<\/b><\/p>\n<ul>\n    <li><code>.TRIM<\/code> – removes leading and trailing spaces <i>Modifies its contents<\/i>\n    <pre>\nASSIGN.TRIM myString\n<\/pre>\n    <\/li>\n    <li><code>.LENGTH<\/code> – returns the string length <i>Stores the result in another variable<\/i>\n    <pre>\nASSIGN.LENGTH myString, length\n<\/pre>\n    <\/li>\n    <li><code>.JOIN<\/code> – joins elements into a string <i>Returns a new value<\/i>\n    <pre>\nASSIGN.JOIN finalString, {DATA:[\"one\",\"two\",\"three\"], SEP:\" - \"}\nASSIGN.JOIN finalString, {DATA:V$myArray, SEP:\" - \"}\n<\/pre>\n    <\/li>\n<\/ul>\n<p><b>3. Array variables<\/b><\/p>\n<ul>\n    <li><code>.PUSH value<\/code> – adds to the end<br>\n        <code>.UNSHIFT value<\/code> – adds to the beginning<br>\n        <code>.EXTEND array<\/code> – appends elements from another array\n    <\/li>\n    <li><code>.SPLIT<\/code> – splits a string into an array<\/li>\n    <li><code>.SLICE<\/code> – takes a section of an array between START and END (END not included)<\/li>\n<\/ul>\n<p><b>4. Object variables<\/b><\/p>\n<ul>\n    <li><code>.MERGE object<\/code> – merges keys from another object<br>\n        <code>.DELETE path<\/code> – removes a property <i>Modifies contents<\/i>\n    <\/li>\n    <li><code>.KEYS<\/code> – returns a list of key names <i>Stores the result in another variable<\/i><\/li>\n<\/ul>\n<h3>Access paths<\/h3>\n<p>The DSL allows assigning values to internal parts of objects or arrays using dot-separated paths.<\/p>\n<p><b>Object paths<\/b> do not auto-create intermediate levels. If a path does not exist, an error is raised and the simulation stops.<\/p>\n<p><b>Array paths<\/b> allow direct access to any index, even if empty.<\/p>\n<h3>SNA <code>VD$<\/code><\/h3>\n<p>Some data can be accessed directly using the associated SNA for validation and inspection:<\/p>\n<ul>\n    <li><code>VD$(path)<\/code> – raw unprocessed value.<\/li>\n    <li><code>VD$(path,LENGTH)<\/code> – content length.<\/li>\n    <li><code>VD$(path,TYPEOF)<\/code> – data type as text.<\/li>\n    <li><code>VD$(path,ISEMPTY)<\/code> – returns \"1\" if empty, \"0\" otherwise.<\/li>\n    <li><code>VD$(path,EXIST)<\/code> – checks if the full path exists.<\/li>\n    <li><code>VD$(path,HASKEY,key)<\/code> – checks if an object has a given key.<\/li>\n    <li><code>VD$(path,INCLUDES,value)<\/code> – checks if an array or string includes a value.<\/li>\n<\/ul>",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            },
            {
                "id": "288",
                "nombre": "Accessing Variables from Other Entities",
                "texto": "\/* Cross-entity access using P$ and ASSIGN with target entity *\/\n\nPOSITION {NAME:POS_MOD,   X:286, Y:244}\nPOSITION {NAME:POS_END,   X:741, Y:233, type:terminate}\n\nGRAPHIC {NAME:T1, type:TEXT, X:455, Y:300}\nGRAPHIC {NAME:T2, type:TEXT, X:455, Y:188}\n\nSTART 60   ; there will be 6 entities (3 of each type)\n\n\/* --- ENTITY TYPE A --- *\/\nGENERATE 30,0,15 {NAME:GA, X:100, Y:70, ECOLOR:#ff3333, subtitle:\"A\"}\n    ASSIGN miValor, 100\n    MOD {subtitle:\"My value P$miValor\"}\n\n    ADVANCE 20 {to:POS_MOD}\n\n    ; If entity B exists (2, 4, 6...)\n    IF (D$(EXIST, D$N+1)==1)\n        ASSIGN nEntidadDestino, D$N+1\n        ASSIGN miValor, P$(miValor)+10, P$nEntidadDestino   ; A increments B's value\n        MOVE {name:T1, text:\"I change the value of P$nEntidadDestino to: [P$(miValor,P$nEntidadDestino)]\"}\n    ENDIF\n\n    ADVANCE 50 {to:POS_END}\nENDGENERATE 3\n\n\/* --- ENTITY TYPE B --- *\/\nGENERATE 30,0 {NAME:GB, X:103, Y:407, ECOLOR:#3366ff, subtitle:\"B\"}\n    ASSIGN miValor, 200\n    MOD {subtitle:\"My value P$miValor\"}\n\n    ADVANCE 20 {to:POS_MOD}\n\n    ; If entity A exists (1, 3, 5...)\n    IF (D$(EXIST, D$N-1)==1)\n        ASSIGN nEntidadDestino, D$N-1\n        ASSIGN miValor, P$(miValor)-5, P$nEntidadDestino   ; B reduces A's value\n        MOVE {name:T2, text:\"I change the value of P$nEntidadDestino to: [P$(miValor,P$nEntidadDestino)]\"}\n    ENDIF\n\n    ADVANCE 50 {to:POS_END}\nENDGENERATE 3",
                "descripcion": "<h3>Accessing Variables from Other Entities<\/h3>\n<p>In addition to working with local or global variables, GPSS-Plus allows reading and writing <strong>ASSIGN<\/strong> variables from any live entity in the system.<\/p>\n<p><b>Reading via SNA:<\/b><\/p>\n<p>The usual <code>P$<\/code> SNA accepts a second parameter indicating the target entity number:<\/p>\n<pre>\nP$(variableName, entityNumber)\n<\/pre>\n<p>This makes it possible to query internal values from another entity without copying them into a SAVEVALUE.<\/p>\n<pre>\nMOVE {name:text5, text:\"Entity 2 has: P$(aPrivateNumber,2)\"}\n<\/pre>\n<p>This directly accesses the variable <code>aPrivateNumber<\/code> currently active in entity number 2.<\/p>\n<p><b>Writing into another entity:<\/b><\/p>\n<p>By using a third parameter in the <code>ASSIGN<\/code> instruction, data can be stored directly into the target entity:<\/p>\n<pre>\nASSIGN aNumber, 123, 1\n<\/pre>\n<p><b>Checking entity existence:<\/b><\/p>\n<p>The existence of an entity can be verified using the specific SNA:<\/p>\n<pre>\nIF (D$(EXIST,1000)==1)\n<\/pre>",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            },
            {
                "id": "280",
                "nombre": "Control Structures",
                "texto": "\/* Control Structures: FOREACH and REPEAT\nIteration over arrays, objects and resources.\n*\/\n\nPOSITION {NAME:POS1,X:651,Y:480}\nINITIAL posY,400\n\nGRAPHIC {NAME:Text1,Type:TEXT,X:324,Y:X$posY - 0}\nGRAPHIC {NAME:Text2,Type:TEXT,X:324,Y:X$posY - 20}\nGRAPHIC {NAME:Text3,Type:TEXT,X:324,Y:X$posY - 40}\nGRAPHIC {NAME:Text4,Type:TEXT,X:324,Y:X$posY - 60}\nGRAPHIC {NAME:Text5,Type:TEXT,X:324,Y:X$posY - 80}\nGRAPHIC {NAME:Text6,Type:TEXT,X:324,Y:X$posY - 160,color:#000000}\n\nFACILITY {NAME:Facility1,X:382,Y:483,capacity:3}\n\nSTART 100\n\nGENERATE 10,0 {name:GEN1,X:110,Y:477}\n\nASSIGN edad,2\nASSIGN nombre,\"Eva\"\n\n; IF (P$nombre==\"Eva\") -> Incorrect expression, missing quotes\nIF (\"P$nombre\"==\"Eva\")\n    MOVE {name:Text1, text:\"Correct expressions\"}\nENDIF\n\nIF (P$edad > 18 || V$nombre==\"Eva\")\n    MOVE {name:Text1, text:\"Correct expressions\"}\nENDIF\n\nASSIGN intentos, 0\nMOVE {name:Text1, text:\"Current color: P$valor\"}\n\n; FOREACH: iterate through all preferences\nASSIGN gustos_luis,\"\"\nASSIGN persona, {nombre:\"Luis\"\n        , gustos:[\"leer\", \"música\", \"viajar\", \"dormir\"]\n        , ciudad:\"Madrid\"\n        , pais:\"España\"\n        }\nFOREACH gusto, IN, V$(persona.gustos)\n    ASSIGN gustos_luis,\"P$gustos_luis P$gusto\"\nENDFOREACH\nMOVE {name:Text1, text:\"Luis's preferences: P$gustos_luis\"}\n\nASSIGN claves_valores,\"\"\nFOREACH clave, IN_OBJECT, V$(persona)\n    ASSIGN claves_valores,\"P$(claves_valores) \\n P$clave  P$(persona.P$clave)\"\nENDFOREACH\n\nMOVE {name:Text6, text:\"Keys and values of persona:\\n P$(claves_valores)\"}\n\nASSIGN entidades_cola,\"\"\nFOREACH entidad, IN_QUEUE, Facility1\n    ASSIGN entidades_cola,\"P$entidades_cola P$entidad\"\nENDFOREACH\nMOVE {name:Text3, text:\"entities in queue: P$entidades_cola\"}\n\nASSIGN entidades_dentro,\"\"\nFOREACH entidad, IN_RESOURCE, Facility1\n    ASSIGN entidades_dentro,\"P$entidades_dentro P$entidad\"\nENDFOREACH\nMOVE {name:Text4, text:\"entities inside: P$entidades_dentro\"}\n\nASSIGN intento, 0\nASSIGN maximo, 3\n\nASSIGN intentos,\"\"\nREPEAT\n    ASSIGN.INC intento\n    ASSIGN intentos,\"P$intentos P$intento\"\nUNTIL (P$intento >= P$maximo)\nMOVE {name:Text5, text:\"attempts: P$intentos\"}\n\nADVANCE 10,0 {to:Facility1}\nSEIZE Facility1\nADVANCE 20,30\nRELEASE Facility1\n\nADVANCE 100,0 {TO:POS1}\nENDGENERATE 1",
                "descripcion": "<p>Control structures allow entities to make decisions, repeat blocks of code, or iterate over collections. GPSS-Plus incorporates these structures with a simple syntax adapted to the declarative paradigm of the language.<\/p>\n<p><b>1. <code>IF<\/code> \/ <code>ELSE<\/code> \/ <code>ENDIF<\/code><\/b><\/p>\n<p>Evaluates a condition and executes alternative blocks depending on the result.<\/p>\n<pre>\nIF (P$edad > 18 || \"P$nombre\"==\"Eva\")\n    MOVE {name:text1,text:\"Adult or is Eva\"}\nELSE\n    MOVE {name:text1,text:\"Minor or not Eva\"}\nENDIF\n<\/pre>\n<ul>\n    <li>The condition must be enclosed in parentheses.<\/li>\n    <li>Logical operators (<code>&&<\/code>, <code>||<\/code>) and comparisons (<code>==<\/code>, <code>!=<\/code>, <code>&gt;<\/code>, <code>&lt;<\/code>, <code>&gt;=<\/code>, <code>&lt;=<\/code>) can be used.<\/li>\n    <li>The entire condition is evaluated as a single expression.<\/li>\n<\/ul>\n<p><b>2. <code>FOREACH<\/code> \/ <code>ENDFOREACH<\/code><\/b><\/p>\n<pre>\nASSIGN listaAlumnos,[{nombre:\"Ana\"},{nombre:\"Luis\"}]\nFOREACH alumno IN V$listaAlumnos\n    MOVE {name:text1,text:\"Student: P$alumno.nombre\"}\nENDFOREACH\n<\/pre>\n<ul>\n    <li>Iterates over the elements of a collection (array or object).<\/li>\n    <li>The iteration variable must be an ASSIGN.<\/li>\n    <li>Can iterate over arrays or arrays of objects.<\/li>\n    <li>The iteration variable is automatically created if it does not exist.<\/li>\n    <li>The data source must be a valid reference via its SNA <code>V$(route)<\/code>.<\/li>\n<\/ul>\n<h4><strong>Available modes<\/strong><\/h4>\n<ul>\n    <li><strong>IN<\/strong>: Iterates over an array.<\/li>\n    <li><strong>IN_OBJECT<\/strong>: Iterates over the keys of an object.<\/li>\n    <li><strong>IN_RESOURCE<\/strong>: Iterates over entities currently using a resource.<\/li>\n    <li><strong>IN_QUEUE<\/strong>: Iterates over entities waiting in a resource queue.<\/li>\n<\/ul>\n<p><b>3. <code>REPEAT<\/code> \/ <code>UNTIL<\/code><\/b><\/p>\n<pre>\nASSIGN intento, 0\nREPEAT\n    ASSIGN.INC intento\n    MOVE {name:text1,text:\"Attempt number: P$intento\"}\nUNTIL (P$intento >= 3)\n<\/pre>\n<ul>\n    <li>Repeats a block until a condition is met.<\/li>\n    <li>Executes at least once.<\/li>\n    <li>The condition is evaluated after each iteration.<\/li>\n<\/ul>\n<p><b>4. <code>SWITCH<\/code> \/ <code>CASE<\/code> \/ <code>ENDCASE<\/code> \/ <code>ENDSWITCH<\/code><\/b><\/p>\n<p>Allows execution of specific blocks depending on the value of an expression, similar to switch-case in other languages.<\/p>\n<p><b>5. <code>WHILE<\/code> \/ <code>ENDWHILE<\/code><\/b><\/p>\n<p>Executes a block while a condition remains true. Unlike REPEAT, the condition is evaluated before each iteration.<\/p>",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            },
            {
                "id": "286",
                "nombre": "Subprocesses and calls",
                "texto": "<h3><strong>Subprocesses and calls in GPSS-Plus (introduction)<\/strong><\/h3>\n<p>GPSS-Plus incorporates a complete subprocess system that did not exist in classic GPSS, thanks to the introduction of <strong>execution stacks<\/strong>.<br>\nThis allows an entity —or even the system itself— to invoke independent procedures and resume execution in a controlled way.<\/p>\n<p>There are several types of calls, depending on who invokes and <strong>who executes<\/strong> the procedure:<\/p>\n<ul>\n    <li><strong>CALL<\/strong> — Executed by <em>the same entity<\/em> that invokes it.<\/li>\n    <li><strong>SIGNAL<\/strong> — Executed by <em>another entity<\/em>, but only when the current one releases its turn.<\/li>\n    <li><strong>SIGNALNOW<\/strong> — Executed by <em>another entity immediately<\/em>, interrupting the current one.<\/li>\n    <li><strong>TIMEOUT<\/strong> — Executed by <em>a virtual entity (VE)<\/em> at a future time.<\/li>\n    <li><strong>ON_*<\/strong> — Executed by <em>a VE<\/em> when an event occurs on a resource (SEIZE, RELEASE, ENTER...).<\/li>\n    <li><strong>TIMER<\/strong> — Executed by <em>a VE<\/em> periodically.<\/li>\n    <li><strong>PRE_RUN<\/strong> — Executed by <em>a VE<\/em> at the start of the simulation.<\/li>\n<\/ul>\n<p>All of them jump to a <strong>PROCEDURE<\/strong> block, which <strong>must end<\/strong> with <code>ENDPROCEDURE<\/code>.<\/p>\n<h3><strong>Hierarchical names<\/strong><\/h3>\n<p>Procedures can be organized as paths:<\/p>\n<pre>\nagente.abrir\ncliente.saludar\nrobot1.motor.arrancar\n<\/pre>\n<p>The returned value will be automatically stored in a variable whose name matches the last fragment (\"abrir\", \"saludar\", \"arrancar\").<\/p>\n<h3><strong>Parameters and available SNA<\/strong><\/h3>\n<p>Inside a PROCEDURE, the received parameters can be accessed:<\/p>\n<ul>\n    <li><code>P$PARAM_A<\/code> — evaluated value<\/li>\n    <li><code>V$PARAM_A<\/code> — raw value (array, object, number, unevaluated string)<\/li>\n<\/ul>\n<h3><strong>Procedure termination<\/strong><\/h3>\n<p>A procedure can end with:<\/p>\n<ul>\n    <li><strong>RETURN value<\/strong> — Returns to the caller.<\/li>\n    <li><strong>RETURN_RESTORE value<\/strong> — For SIGNAL\/SIGNALNOW: the target entity resumes exactly where it was.<\/li>\n    <li><strong>RETURN_RETRY value<\/strong> — For SIGNAL\/SIGNALNOW: the target entity repeats its current step (typical in resource retries).<\/li>\n<\/ul>",
                "descripcion": "<h3><strong>Subprocesses and calls in GPSS-Plus (introduction)<\/strong><\/h3>\n<p>GPSS-Plus incorporates a complete subprocess system that did not exist in classic GPSS, thanks to the introduction of <strong>execution stacks<\/strong>.<br>\nThis allows an entity —or even the system itself— to invoke independent procedures and resume execution in a controlled way.<\/p>\n<p>There are several types of calls, depending on who invokes and <strong>who executes<\/strong> the procedure:<\/p>\n<ul>\n    <li><strong>CALL<\/strong> — Executed by <em>the same entity<\/em> that invokes it.<\/li>\n    <li><strong>SIGNAL<\/strong> — Executed by <em>another entity<\/em>, but only when the current one releases its turn.<\/li>\n    <li><strong>SIGNALNOW<\/strong> — Executed by <em>another entity immediately<\/em>, interrupting the current one.<\/li>\n    <li><strong>TIMEOUT<\/strong> — Executed by <em>a virtual entity (VE)<\/em> at a future time.<\/li>\n    <li><strong>ON_*<\/strong> — Executed by <em>a VE<\/em> when an event occurs on a resource (SEIZE, RELEASE, ENTER...).<\/li>\n    <li><strong>TIMER<\/strong> — Executed by <em>a VE<\/em> periodically.<\/li>\n    <li><strong>PRE_RUN<\/strong> — Executed by <em>a VE<\/em> at the start of the simulation.<\/li>\n<\/ul>\n<p>All of them jump to a <strong>PROCEDURE<\/strong> block, which <strong>must end<\/strong> with <code>ENDPROCEDURE<\/code>.<\/p>\n<h3><strong>Hierarchical names<\/strong><\/h3>\n<p>Procedures can be organized as paths:<\/p>\n<pre>\nagente.abrir\ncliente.saludar\nrobot1.motor.arrancar\n<\/pre>\n<p>The returned value will be automatically stored in a variable whose name matches the last fragment (\"abrir\", \"saludar\", \"arrancar\").<\/p>\n<h3><strong>Parameters and available SNA<\/strong><\/h3>\n<p>Inside a PROCEDURE, the received parameters can be accessed:<\/p>\n<ul>\n    <li><code>P$PARAM_A<\/code> — evaluated value<\/li>\n    <li><code>V$PARAM_A<\/code> — raw value (array, object, number, unevaluated string)<\/li>\n<\/ul>\n<h3><strong>Procedure termination<\/strong><\/h3>\n<p>A procedure can end with:<\/p>\n<ul>\n    <li><strong>RETURN value<\/strong> — Returns to the caller.<\/li>\n    <li><strong>RETURN_RESTORE value<\/strong> — For SIGNAL\/SIGNALNOW: the target entity resumes exactly where it was.<\/li>\n    <li><strong>RETURN_RETRY value<\/strong> — For SIGNAL\/SIGNALNOW: the target entity repeats its current step (typical in resource retries).<\/li>\n<\/ul>",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": [
                    {
                        "id": "367",
                        "nombre": "CALL",
                        "texto": "\/* CALL *\/\n\nPOSITION {NAME:POS1,   X:286, Y:244}\n\ninitial posY,500\nGraphic {NAME:Text1,Type:TEXT,X:324,Y:X$posY - 0}\nGraphic {NAME:Text2,Type:TEXT,X:324,Y:X$posY - 20}\nGraphic {NAME:Text3,Type:TEXT,X:324,Y:X$posY - 40}\nGraphic {NAME:Text4,Type:TEXT,X:324,Y:X$posY - 60}\nGraphic {NAME:Text5,Type:TEXT,X:324,Y:X$posY - 80}\nGraphic {NAME:Text6,Type:TEXT,X:324,Y:X$posY - 100}\n\nSTART 1\n\nGENERATE 10,0,0,1 {NAME:GA, X:100, Y:70}\n    ASSIGN data, {name:\"Ana\", age:30}\n    ASSIGN number, 123\n    ASSIGN colors, [\"red\",\"green\"]\n\n    CALL process, V$data, V$number, V$colors, 30\n\n    move {name:Text1, text:\"Procedure result: P$(process)\"}\n\n    ADVANCE 10 {to:POS1}\nENDGENERATE 1\n;---------------------------------------\nPROCEDURE process\n    move {name:Text2, text:\"Name: P$(PARAM_A.name)\"}\n    move {name:Text3, text:\"Age: P$(PARAM_A.age)\"}\n    move {name:Text4, text:\"Number: P$PARAM_B\"}\n    move {name:Text5, text:\"First color: P$(PARAM_C.0)\"}\n    move {name:Text6, text:\"Direct value: P$(PARAM_D)\"}\n\n    RETURN \"OK\"\nENDPROCEDURE",
                        "descripcion": "<p>The <strong>CALL<\/strong> command allows the <em>currently active entity<\/em> to jump to a procedure and execute it immediately.<br>When it finishes, the entity returns exactly to the next step after the call.<\/p>\n<p>This is the simplest and most direct behavior of the subprocess system.<\/p>\n<p><b>Syntax:<\/b><\/p>\n<pre>\nCALL procedureName, parameterA, parameterB, ...\n<\/pre>\n<ul>\n    <li>Parameters are received inside the procedure as <code>P$PARAM_A<\/code>, <code>P$PARAM_B<\/code>, etc.<\/li>\n    <li>The value returned by the procedure is automatically stored in a variable named after the <strong>last fragment<\/strong> of the PROCEDURE name.<\/li>\n<\/ul>\n<p>Procedure name → result variable examples:<\/p>\n<pre>\nCALL calculate, 10        →  P$calculate\nCALL client.add, 20,30   →  P$add\nCALL robot.motor.start   →  P$start\n<\/pre>\n<p><b>Procedure termination:<\/b><\/p>\n<p><strong>ENDPROCEDURE value<\/strong><\/p>\n<p>Ends execution and returns the specified value:<\/p>\n<pre>\nENDPROCEDURE 3 ; P$calculate = 3\n<\/pre>\n<p><b>RETURN value<\/b><\/p>\n<p>Does the same thing, but is more explicit and readable:<\/p>\n<pre>\nRETURN 3\nENDPROCEDURE\n<\/pre>\n<p>Both forms are equivalent when using CALL.<\/p>\n<p><b>Accessing parameters:<\/b><\/p>\n<p>Inside the procedure:<\/p>\n<ul>\n    <li><code>P$PARAM_A<\/code> returns the evaluated value.<\/li>\n    <li><code>V$PARAM_A<\/code> returns the raw value (arrays, objects, unevaluated strings).<\/li>\n<\/ul>\n<p>Examples:<\/p>\n<ul>\n    <li><code>P$(PARAM_A.name)<\/code> if you passed an object.<\/li>\n    <li><code>P$(PARAM_B.2)<\/code> if you passed an array.<\/li>\n<\/ul>",
                        "parametros": null,
                        "parametros_json": null,
                        "ejemplo": null,
                        "hijos": []
                    },
                    {
                        "id": "366",
                        "nombre": "SIGNAL and SIGNALNOW",
                        "texto": "\/* SIGNAL and SIGNALNOW in permanent agents *\/\n\nSYSTEM {TYPE:PRE_RUN, TRIGGER:PRE_RUN}\n\nPOSITION {NAME:POS_1,   X:615, Y:398}\n\nGraphic {NAME:T_resultado1, type:TEXT, X:425, Y:281,text:\"result1\"}\nGraphic {NAME:T_resultado2, type:TEXT, X:425, Y:256,text:\"result2\"}\nGraphic {NAME:T2, type:TEXT, X:430, Y:501}\nGraphic {NAME:T3, type:TEXT, X:430, Y:531}\nGraphic {NAME:T4, type:TEXT, X:426, Y:310}\nGraphic {NAME:T5, type:TEXT, X:425, Y:188}\n\nRESTROOM {name:RestRoomSleepingAgent,x:423,y:118}\n\nSTART 200\n\n\/* ---- PRE RUN: Create agents ---- *\/\nPROCEDURE PRE_RUN\n    TIMEOUT aliveAgent.loop, 0\n    TIMEOUT sleepingAgent.loop, 0\n    TERMINATE_VE\nENDPROCEDURE\n\n\/* ---- NORMAL ENTITY GENERATOR ---- *\/\nGENERATE 15,0 {NAME:G1, X:153, Y:411}\n\n    ASSIGN myValue, D$N * 10\n    MOVE {name:T4, text:\"Entity D$N starts with myValue = P$myValue\"}\n\n    ADVANCE 10 {to:POS_1}\n\n    ; Deferred SIGNAL call\n    SIGNAL aliveAgent.process, X$nAliveAgent, \"Hello\"\n\n    ; Immediate SIGNALNOW call\n    SIGNALNOW aliveAgent.add, X$nAliveAgent, P$myValue, 5\n    MOVE {name:T_resultado1, text:\"Alive agent result = P$add\"}\n\n    SIGNALNOW sleepingAgent.add, X$nSleepingAgent, P$myValue, 5\n    MOVE {name:T_resultado2, text:\"Sleeping agent result = P$add\"}\n\nENDGENERATE 4\n\n\/* ---- ALIVE AGENT ---- *\/\nPROCEDURE aliveAgent.loop\n    SAVEVALUE nAliveAgent, D$N\n    ASSIGN processing, 0\n    WHILE (1==1)\n        MOVE {name:T3, text:\"Alive agent [P$(nAgent)] active at t = AC1$\"}\n        ADVANCE 2\n    ENDWHILE\n    TERMINATE_VE\nENDPROCEDURE\n\n\/* ---- SLEEPING AGENT ---- *\/\nPROCEDURE sleepingAgent.loop\n    SAVEVALUE nSleepingAgent, D$N\n    ASSIGN processing, 0\n    MOVE {name:T5, text:\"Sleeping agent [P$(nAgent)] active\"}\n    REST RestRoomSleepingAgent\n    TERMINATE_VE\nENDPROCEDURE\n\n\/* ---- PROCEDURES INVOKED BY ENTITIES ---- *\/\n\nPROCEDURE aliveAgent.process\n    IF (P$processing==1)\n        RETURN\n    ENDIF\n    ASSIGN processing, 1\n    MOVE {name:T2, text:\"SIGNAL → agent STARTS processing message: P$PARAM_A\"}\n    ADVANCE 80\n    MOVE {name:T2, text:\"SIGNAL → agent FINISHES processing message: P$PARAM_A\"}\n    ASSIGN processing, 0\n    RETURN\nENDPROCEDURE\n\nPROCEDURE aliveAgent.add\n    ; PARAM_A = base value\n    ; PARAM_B = increment\n    RETURN_RESTORE P$PARAM_A + P$PARAM_B\nENDPROCEDURE\n\nPROCEDURE sleepingAgent.add\n    ; PARAM_A = base value\n    ; PARAM_B = increment\n    RETURN_RESTORE P$PARAM_A + P$PARAM_B\nENDPROCEDURE",
                        "descripcion": "<h3>SIGNAL<\/h3>\n<p><code>SIGNAL<\/code> invokes a <code>PROCEDURE<\/code> to be executed by <strong>another entity<\/strong>, but <strong>does not interrupt<\/strong> the calling entity.<\/p>\n<ul>\n    <li>The execution occurs at the <strong>same simulation time (AC1)<\/strong>.<\/li>\n    <li>It is placed at the <strong>end of the event list<\/strong> for that same time.<\/li>\n    <li>The calling entity <strong>continues normally<\/strong> and finishes its cycle.<\/li>\n    <li>It is a <em>deferred<\/em> call.<\/li>\n<\/ul>\n<blockquote>\n<p><strong>In short:<\/strong> SIGNAL schedules the procedure execution but does not interrupt the caller.<\/p>\n<\/blockquote>\n<h3>SIGNALNOW<\/h3>\n<p><code>SIGNALNOW<\/code> invokes a PROCEDURE to be executed <strong>immediately<\/strong> by another entity, <strong>interrupting<\/strong> the current one.<\/p>\n<ul>\n    <li>The invoked entity takes control <strong>immediately<\/strong>, within the same AC1.<\/li>\n    <li>The calling entity is <strong>suspended<\/strong> and later resumes depending on the return type.<\/li>\n    <li>The signaled entity becomes the <strong>first<\/strong> to execute at that time.<\/li>\n    <li>It is a <strong>preemptive<\/strong> call.<\/li>\n<\/ul>\n<p>Typically, the procedure should end with:<\/p>\n<ul>\n    <li><strong>RETURN_RESTORE<\/strong>: the interrupted entity resumes exactly where it was.<\/li>\n    <li><strong>RETURN_RETRY<\/strong>: the interrupted entity repeats the operation it was performing (common with SEIZE, ENTER, or resources).<\/li>\n<\/ul>\n<p><strong>In summary:<\/strong> <code>SIGNALNOW<\/code> causes an immediate interruption; the target entity executes the procedure without waiting.<\/p>\n<h3>In the example:<\/h3>\n<p>This example demonstrates SIGNAL \/ SIGNALNOW with active and sleeping agents.<\/p>\n<p>The final behavior depends on the state of the receiving agent:<\/p>\n<ul>\n    <li><strong>aliveAgent<\/strong>: continuously active in a loop with <code>ADVANCE<\/code>.<\/li>\n    <li><strong>sleepingAgent<\/strong>: stopped in a <code>REST<\/code> instruction.<\/li>\n<\/ul>\n<p>The example highlights the real differences between <strong>RETURN<\/strong>, <strong>RETURN_RESTORE<\/strong>, and <strong>RETURN_RETRY<\/strong>, and when each one is safe or dangerous depending on the agent state.<\/p>",
                        "parametros": null,
                        "parametros_json": null,
                        "ejemplo": null,
                        "hijos": []
                    },
                    {
                        "id": "365",
                        "nombre": "VE Procedures: TIMER, TIMEOUT, ON_*, PRE_RUN",
                        "texto": "POSITION {NAME:Salida, X:624, Y:199}\n\nGraphic {NAME:T1, type:TEXT, X:493, Y:505}\nGraphic {NAME:T2, type:TEXT, X:493, Y:476}\nGraphic {NAME:T3, type:TEXT, X:492, Y:444}\n\nFacility {NAME:Ventana, ON_RELEASE: cuandoSale, X:249, Y:335 }\n\nSYSTEM {TYPE:PRE_RUN, TRIGGER:PRE_RUN}\n\nSTART 50\n\n;----------------------------------------\nPROCEDURE PRE_RUN\n    move {name:T1, text:\"PRE_RUN executed at t = AC1$\"}\n    TIMEOUT avisoInicial, 10\n    TERMINATE_VE\nENDPROCEDURE\n\n;----------------------------------------\nGENERATE 15,0 {NAME:\"GEN1\", X:100, Y:100}\n\tADVANCE 10 {to:Ventana}\n    SEIZE Ventana\n    ADVANCE 5\n    RELEASE Ventana        ; will trigger ON_RELEASE\n    ADVANCE 10 {to:Salida}\nENDGENERATE 1\n\n;----------------------------------------\nPROCEDURE avisoInicial\n    move {name:T2, text:\"TIMEOUT executed at t = AC1$\"}\n    TERMINATE_VE\nENDPROCEDURE\n\nPROCEDURE cuandoSale\n    move {name:T3, text:\"ON_RELEASE executed at t = AC1$\"}\n    TERMINATE_VE\nENDPROCEDURE",
                        "descripcion": "<p><b>TIMEOUT<\/b> \/ <b>ON_* \/ PRE_RUN \/ TIMER<\/b><\/p>\n<p>These procedures are executed by newly created virtual entities (<strong>VE<\/strong>).<br>\nVEs must terminate like any other entity using <code>TERMINATE<\/code> or <code>TERMINATE_VE<\/code>. The difference between both BLOCKS is that the former terminates any entity, while the latter only terminates virtual entities. By using the <code>TERMINATE_VE<\/code> block, the <code>PROCEDURE<\/code> can be invoked to be executed by both types of entities.<br>\nIt is important to note that they must be terminated explicitly, because if execution reaches <code>ENDPROCEDURE<\/code> the system would not know where to return.<\/p>\n<pre>\nTIMEOUT abrirRecurso, 50, P$valor, V$Objeto\n\nPROCEDURE abrirRecurso\n  move {name:text1, text:\"Executed at t=AC1$\"}\n  TERMINATE_VE\nENDPROCEDURE<\/pre>",
                        "parametros": null,
                        "parametros_json": null,
                        "ejemplo": null,
                        "hijos": []
                    },
                    {
                        "id": "368",
                        "nombre": "SCAPE \/ LOAD \/ UNLOAD",
                        "texto": "POSITION {NAME:Exit, X:178, Y:39}\nPOSITION {NAME:RoadStart, X:150, Y:313}\nPOSITION {NAME:RoadEnd, X:514, Y:314}\n\nFacility {NAME:Museum, capacity:50, X:534, Y:77 }\n\nRestroom {NAME:CityBusStop, X:68, Y:321 }\nRestroom {NAME:MuseumBusStop, X:588, Y:312 }\n\nSTART 500\n\n;----------------------------------------\nGENERATE 15,0 {NAME:\"GenUsers\", X:100, Y:100 }\n\n\tif (P$museumVisited==1)\n\t\tadvance 100,50 {from:RoadStart ,to:Exit}\n\t\tterminate 1\n\tendif\n\t\n\tASSIGN MODE,0 ; PRIVATE VEHICLE\n\tif (RANDOM > 0.2)\n\t\tASSIGN MODE,1 ; BUS\n\tendif\n\tadvance 10 {to:RoadStart}\n\tif (P$MODE==1)\n\t\tREST CityBusStop\n\tendif\n\tadvance 50,10 {to:RoadEnd}\n\tSCAPE GenMuseum\nENDGENERATE 1\n\n;----------------------------------------\nGENERATE 0,0,0,0 {NAME:\"GenMuseum\", X:600, Y:160 }\n\tadvance 20,30 {from:RoadEnd,to:Museum}\n\tseize Museum\n\tadvance 30,50\n\tassign museumVisited,1\n\tmod {color:green}\n\trelease Museum\n\t\n\tadvance 10 {to:RoadEnd}\n\n\tif (P$MODE==1)\n\t\tREST MuseumBusStop\n\tendif\n\tadvance 50 {to:RoadStart}\n\tSCAPE GenUsers\nENDGENERATE 1\n\n;----------------------------------------\n\n;----------------------------------------\nGENERATE 50,0,0,2 {NAME:\"GenBuses\", X:300, Y:460,ecolor:red,eradio:10,visible:0 }\n\tadvance 50 {to:RoadStart}\n\twhile (1==1)\n\t\tload outboundBackpack, CityBusStop\n\t\tmod {subtitle:\"Passengers P$(outboundBackpack.LENGTH)\"}\n\t\tadvance 80,10 {to:RoadEnd}\n\t\tunload outboundBackpack, GenMuseum\n\t\tadvance 10\n\t\tload returnBackpack, MuseumBusStop\n\t\tmod {subtitle:\"Passengers P$(returnBackpack.LENGTH)\"}\n\t\tadvance 80,10 {to:RoadStart}\n\t\tunload returnBackpack, GenUsers\n\t\tadvance 10\n\tendwhile\nENDGENERATE 0",
                        "descripcion": "<p><b>SCAPE<\/b><\/p><p>It is a special call whose destination is a <code>GENERATE<\/code>.<\/p><p><code>SCAPE<\/code> is used when an entity must completely abandon its current flow and start a new one. This is useful when a condition requires restarting, changing behavior, or irreversibly branching the flow.<\/p><p>The <code>SCAPE<\/code> jump leads to the only clean, stack-safe entry points: the <code>GENERATE<\/code> blocks. All ASSIGN values are preserved.<\/p><pre>SCAPE generateName, 50, P$value, V$object<\/pre><p><b>BACKPACK (LOAD \/ UNLOAD)<\/b><\/p><p>An entity can only be loaded (<code>LOAD<\/code>) if it is in <code>REST<\/code>, because it is asleep, does not consume simulation cycles, cannot wake itself up, and is safe to manipulate.<\/p><p>That is why BACKPACK is a logistics tool, not a flow-control mechanism.<\/p><p><b>In the example:<\/b> A city and a museum are connected by a road. Citizens may travel by private vehicle or by bus. Buses load sleeping citizens, transport them, and unload them at a new <code>GENERATE<\/code>, where each continues its own life flow.<\/p>",
                        "parametros": null,
                        "parametros_json": null,
                        "ejemplo": null,
                        "hijos": []
                    }
                ]
            },
            {
                "id": "295",
                "nombre": "Holding Resources",
                "texto": "",
                "descripcion": "",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": [
                    {
                        "id": "297",
                        "nombre": "Generalities",
                        "texto": "POSITION {NAME:Exit,X:615,Y:388}\n\ninitial posY,500\nGraphic {NAME:Text1,Type:TEXT,X:324,Y:X$posY - 0}\nGraphic {NAME:Text2,Type:TEXT,X:324,Y:X$posY - 20}\nGraphic {NAME:Text3,Type:TEXT,X:324,Y:X$posY - 40}\nGraphic {NAME:Text4,Type:TEXT,X:324,Y:X$posY - 60}\nGraphic {NAME:Text5,Type:TEXT,X:324,Y:X$posY - 140}\nGraphic {NAME:Text6,Type:TEXT,X:324,Y:X$posY - 160}\nGraphic {NAME:Text7,Type:TEXT,X:324,Y:X$posY - 180}\nGraphic {NAME:Text8,Type:TEXT,X:324,Y:X$posY - 200}\n\nFacility {NAME:Facility1,X:324,Y:560\n\t,capacity:3\n\t,ON_ATTEMPT:FACILITY1_attempt\n\t,ON_SEIZE:FACILITY1_seize\n\t,ON_RELEASE:FACILITY1_release\n\t,ON_QUEUE:FACILITY1_queue\n    }\n\nStorage {NAME:Storage1,X:324,Y:235\n\t,capacity:30\n\t,ON_ATTEMPT:STORAGE1_attempt\n\t,ON_ENTER:STORAGE1_enter\n\t,ON_LEAVE:STORAGE1_leave\n\t,ON_QUEUE:STORAGE1_queue\n    }\n\n\n\nSTART 1000\n\n;-------------------------------\n\nGENERATE 10,0 {NAME:GEN1,X:62,Y:396}\n\nif (D$N%2==1)\n\n    advance 10 {to:Facility1}\n    seize Facility1\n    advance 55,10\n    release Facility1\nelse\n    advance 10 {to:Storage1}\n    enter Storage1,random * 25 + 1\n    advance 35,10\n    leave Storage1\nendif\n\n\nadvance 10 {to:Exit}\n\nENDGENERATE 1\n;-------------------------------\n\nPROCEDURE FACILITY1_release\n\tmove {name:Text1,text:\"AC1$ I am the VE [D$N] of ON_RELEASE for entity P$ENTITYNUMBER\"}\n    TERMINATE_VE\nendprocedure \nPROCEDURE FACILITY1_queue\n\tmove {name:Text2,text:\"AC1$ I am the VE [D$N] of ON_QUEUE for entity P$ENTITYNUMBER\"}\n    TERMINATE_VE\nendprocedure \nPROCEDURE FACILITY1_seize\n\tmove {name:Text3,text:\"AC1$ I am the VE [D$N] of ON_SEIZE for entity P$ENTITYNUMBER\"}\n    TERMINATE_VE\nendprocedure \nPROCEDURE FACILITY1_attempt\n\tmove {name:Text4,text:\"AC1$ I am the VE [D$N] of ON_ATTEMPT for entity P$ENTITYNUMBER\"}\n    TERMINATE_VE\nendprocedure \n;-------------------------------\n\nPROCEDURE STORAGE1_leave\n\tmove {name:Text5,text:\"AC1$ I am the VE [D$N] of ON_LEAVE for entity P$ENTITYNUMBER\"}\n    TERMINATE_VE\nendprocedure \nPROCEDURE STORAGE1_queue\n\tmove {name:Text6,text:\"AC1$ I am the VE [D$N] of ON_QUEUE for entity P$ENTITYNUMBER\"}\n    TERMINATE_VE\nendprocedure \nPROCEDURE STORAGE1_enter\n\tmove {name:Text7,text:\"AC1$ I am the VE [D$N] of ON_ENTER for entity P$ENTITYNUMBER\"}\n    TERMINATE_VE\nendprocedure \nPROCEDURE STORAGE1_attempt\n\tmove {name:Text8,text:\"AC1$ I am the VE [D$N] of ON_ATTEMPT for entity P$ENTITYNUMBER\"}\n    TERMINATE_VE\nendprocedure",
                        "descripcion": "<p><b>Types of resources available in GPSS-Plus:<\/b><\/p><ul><li><b>Facility<\/b> → Exclusive resource with capacity. Example: machine, server.<\/li><li><b>Storage<\/b> → Accumulative resource. Example: warehouse, tank.<\/li><li><b>Restroom<\/b> → Holding resource. Entities wait to be released.<\/li><li><b>Conditions<\/b> → Conditional holding resource. Passage based on logic.<\/li><li><b>Stock<\/b> → Intelligent warehouse of tagged products.<\/li><li><b>Stater<\/b> → Finite state machine. Process control.<\/li><li><b>Queuer<\/b> → Open resource. For counting, grouping or analysis.<\/li><\/ul><p>They allow modeling shared capacities, physical spaces, warehouses, synchronization points, etc. Each resource type defines its own usage logic, but all can be connected to procedures through event hooks such as <code>ON_SEIZE<\/code>, <code>ON_LEAVE<\/code>, etc.<\/p><p><b>Automatic histograms:<\/b><\/p><p>All resources can generate automatic histograms of their usage by defining binning:<\/p><p><b>R_BIN_*<\/b>: Tabulates resource occupancy.<\/p><pre>R_BIN_START:0,R_BIN_SIZE:1,R_BIN_COUNT:40<\/pre><p><b>E_BIN_*<\/b>: Tabulates entity occupation times.<\/p><pre>E_BIN_START:0,E_BIN_SIZE:1,E_BIN_COUNT:40<\/pre><p><b>Associated SNA:<\/b><\/p><p>Using <code>R$(resourceName,property)<\/code> you can query in real time:<\/p><ul><li><code>X, Y<\/code> → Graphic position<\/li><li><code>LEFT, IN, QUEUE, ENTRIES, CAPACITY<\/code> → Operational state<\/li><li><code>LOCK<\/code> → 0 or 1 depending on whether entry is blocked<\/li><li><code>OCCUPIED<\/code> → (STORAGE only) current occupied amount<\/li><\/ul><pre>R$(Fac1,LEFT)\nR$(Fac1,QUEUE)\nR$(Fac1,LOCK)<\/pre><p><b>Hooks<\/b><\/p><p>Depending on the specific resource, certain hooks may be available and handled by procedures executed by virtual entities (VE). Virtual entities are created that traverse the trigger and are born with the <code>ENTITYNUMBER<\/code> assign.<\/p>",
                        "parametros": null,
                        "parametros_json": null,
                        "ejemplo": null,
                        "hijos": []
                    },
                    {
                        "id": "298",
                        "nombre": "Facility",
                        "texto": "\/*\n\nResources. Facility\n\n\n*\/\n\nPOSITION {NAME:Exit,X:615,Y:388}\n\ninitial posY,500\nGraphic {NAME:Text1,Type:TEXT,X:324,Y:X$posY - 0}\nGraphic {NAME:Text2,Type:TEXT,X:324,Y:X$posY - 20}\nGraphic {NAME:Text3,Type:TEXT,X:324,Y:X$posY - 40}\nGraphic {NAME:Text4,Type:TEXT,X:324,Y:X$posY - 60}\nGraphic {NAME:Text5,Type:TEXT,X:324,Y:X$posY - 140}\nGraphic {NAME:Text6,Type:TEXT,X:324,Y:X$posY - 160}\nGraphic {NAME:Text7,Type:TEXT,X:324,Y:X$posY - 180}\nGraphic {NAME:Text8,Type:TEXT,X:324,Y:X$posY - 200}\n\nFacility {NAME:Facility1,X:324,Y:160\n\t,capacity:3\n\t,ON_ATTEMPT:FACILITY1_ATTEMPT\n\t,ON_SEIZE:FACILITY1_SEIZE\n\t,ON_RELEASE:FACILITY1_RELEASE\n\t,ON_QUEUE:FACILITY1_QUEUE\n    ,R_BIN_SIZE:1,R_BIN_COUNT:10\n    ,E_BIN_SIZE:1,E_BIN_COUNT:10\n    }\n\n\nSTART 1000\n\n;-------------------------------\n\nGENERATE 10,0 {NAME:GEN1,X:62,Y:396}\n\nadvance 10 {to:Facility1}\nseize Facility1\nadvance 55,10\nrelease Facility1\nadvance 10 {to:Exit}\n\nENDGENERATE 1\n;-------------------------------\n\nPROCEDURE FACILITY1_RELEASE\n\tmove {name:Text1,text:\"AC1$ I am the VE [D$N] of ON_RELEASE for entity P$ENTITYNUMBER\"}\n    TERMINATE_VE\nendprocedure \nPROCEDURE FACILITY1_QUEUE\n\tmove {name:Text2,text:\"AC1$ I am the VE [D$N] of ON_QUEUE for entity P$ENTITYNUMBER\"}\n    TERMINATE_VE\nendprocedure \nPROCEDURE FACILITY1_SEIZE\n\tmove {name:Text3,text:\"AC1$ I am the VE [D$N] of ON_SEIZE for entity P$ENTITYNUMBER\"}\n    TERMINATE_VE\nendprocedure \nPROCEDURE FACILITY1_ATTEMPT\n\tmove {name:Text4,text:\"AC1$ I am the VE [D$N] of ON_ATTEMPT for entity P$ENTITYNUMBER\"}\n    TERMINATE_VE\nendprocedure",
                        "descripcion": "<p><strong>FACILITY<\/strong><\/p><p>Models an exclusive resource (such as a machine, an operator, or a booth).<br>It allows multiple entities depending on its <code>capacity<\/code>, and queues them if it is busy.<br>Internally it manages two lists: entities occupying the resource and entities waiting.<\/p><p>It supports multiple selection methods for choosing the next entity to enter via the <code>METHOD<\/code> parameter:<\/p><ul><li>\"FIFO\" &nbsp;&nbsp; First in, first out. Takes the first item in the list (arrival order).<\/li><li>\"LIFO\" &nbsp;&nbsp; Last in, first out. Traverses to the last node in the list.<\/li><li>default &nbsp;&nbsp; Equivalent to \"FIFO\" if no method is specified.<\/li><\/ul><p>Associated blocks:<\/p><ul><li><b>SEIZE<\/b> resourceName ; Tries to seize the resource if capacity is available. Otherwise, the entity is queued.<\/li><li><b>RELEASE<\/b> resourceName; Releases the resource and allows another entity to enter.<\/li><\/ul><p>Available events: <code>ON_ATTEMPT<\/code>, <code>ON_QUEUE<\/code>, <code>ON_SEIZE<\/code>, <code>ON_RELEASE<\/code><\/p><pre>Facility {NAME:Fac1, CAPACITY:3, X:100, Y:100}\nFacility {NAME:Fac2, CAPACITY:3, X:100, Y:100, ON_ATTEMPT:Fac1_attempt, E_BIN_START:0,E_BIN_SIZE:1,E_BIN_COUNT:40 }\n;------------------------\nSEIZE Fac1\nADVANCE 10\nRELEASE Fac1<\/pre>",
                        "parametros": null,
                        "parametros_json": null,
                        "ejemplo": null,
                        "hijos": []
                    },
                    {
                        "id": "299",
                        "nombre": "Storage",
                        "texto": "\/*\n\nResources. Storage\n\n\n*\/\n\nPOSITION {NAME:Exit,X:615,Y:388}\n\ninitial posY,500\nGraphic {NAME:Text1,Type:TEXT,X:324,Y:X$posY - 0}\nGraphic {NAME:Text2,Type:TEXT,X:324,Y:X$posY - 20}\nGraphic {NAME:Text3,Type:TEXT,X:324,Y:X$posY - 40}\nGraphic {NAME:Text4,Type:TEXT,X:324,Y:X$posY - 60}\nGraphic {NAME:Text5,Type:TEXT,X:324,Y:X$posY - 140}\nGraphic {NAME:Text6,Type:TEXT,X:324,Y:X$posY - 160}\nGraphic {NAME:Text7,Type:TEXT,X:324,Y:X$posY - 180}\nGraphic {NAME:Text8,Type:TEXT,X:324,Y:X$posY - 200}\n\nStorage {NAME:Storage1,X:324,Y:235\n\t,capacity:30\n\t,ON_ATTEMPT:STORAGE1_attempt\n\t,ON_ENTER:STORAGE1_enter\n\t,ON_LEAVE:STORAGE1_leave\n\t,ON_QUEUE:STORAGE1_queue\n    ,E_BIN_START:34,E_BIN_SIZE:1,E_BIN_COUNT:12\n    ,R_BIN_SIZE:1,R_BIN_COUNT:10\n    ,EQ_BIN_START:34,EQ_BIN_SIZE:1,EQ_BIN_COUNT:12\n    ,RQ_BIN_START:0,RQ_BIN_SIZE:1,RQ_BIN_COUNT:32\n    }\n\n\nSTART 1000\n\n;-------------------------------\n\nGENERATE 10,0 {NAME:GEN1,X:62,Y:396}\n\n\nadvance 10 {to:Storage1}\nenter Storage1,random * 25 + 1\nadvance 35,10\nleave Storage1\n\n\n\nadvance 10 {to:Exit}\n\nENDGENERATE 1\n;-------------------------------\n\nPROCEDURE STORAGE1_leave\n\tmove {name:Text5,text:\"AC1$ I am the VE [D$N] of ON_LEAVE for entity P$ENTITYNUMBER\"}\n    TERMINATE_VE\nendprocedure \nPROCEDURE STORAGE1_queue\n\tmove {name:Text6,text:\"AC1$ I am the VE [D$N] of ON_QUEUE for entity P$ENTITYNUMBER\"}\n    TERMINATE_VE\nendprocedure \nPROCEDURE STORAGE1_enter\n\tmove {name:Text7,text:\"AC1$ I am the VE [D$N] of ON_ENTER for entity P$ENTITYNUMBER\"}\n    TERMINATE_VE\nendprocedure \nPROCEDURE STORAGE1_attempt\n\tmove {name:Text8,text:\"AC1$ I am the VE [D$N] of ON_ATTEMPT for entity P$ENTITYNUMBER\"}\n    TERMINATE_VE\nendprocedure",
                        "descripcion": "<p><strong>STORAGE<\/strong><\/p><p>Models a warehouse-type exclusive resource where occupancy is defined by the amount contributed by each entity.<br>It supports multiple occupants up to its <code>capacity<\/code>, and queues entities if there is not enough free space.<br>Internally it manages two lists: occupying entities with their load, and waiting entities.<\/p><p>It supports several entry-selection logics through the optional <code>METHOD<\/code> parameter.<\/p><p>Associated blocks:<\/p><ul><li><b>ENTER<\/b> resourceName, amount ; Tries to occupy the resource if capacity is available. Otherwise, the entity is queued.<\/li><li><b>LEAVE<\/b> resourceName; Releases the resource by the amount contributed and allows another entity to enter.<\/li><\/ul><p>Available events: <code>ON_ATTEMPT<\/code>, <code>ON_QUEUE<\/code>, <code>ON_ENTER<\/code>, <code>ON_LEAVE<\/code><\/p><p>It supports multiple selection methods for choosing the next entity to enter via the <code>METHOD<\/code> parameter:<\/p><ul><li>\"FIFO\" &nbsp;&nbsp; First in, first out. Takes the first item in the list (arrival order).<\/li><li>\"LIFO\" &nbsp;&nbsp; Last in, first out. Traverses to the last node in the list.<\/li><li>\"MIN_SPACE\" &nbsp;&nbsp; Chooses the entity that needs the least space (and fits in what is available).<\/li><li>\"MAX_SPACE\" &nbsp;&nbsp; Chooses the entity that needs the most space (within the available space).<\/li><li>default &nbsp;&nbsp; Equivalent to \"FIFO\" if no method is specified.<\/li><\/ul><p><b>Additional statistics:<\/b> EQ_BIN_* and RQ_BIN_* tabulate by used capacity.<\/p><pre>Storage {NAME:Sto1, CAPACITY:3, X:100, Y:100,METHOD:MIN_SPACE}\nStorage {NAME:Sto2, CAPACITY:3, X:100, Y:100, ON_ATTEMPT:Fac1_attempt, E_BIN_START:0,E_BIN_SIZE:1,E_BIN_COUNT:40 }\n;------------------------\nEnter Sto2,6\nADVANCE 10\nRELEASE Sto2<\/pre><p>&nbsp;<\/p>",
                        "parametros": null,
                        "parametros_json": null,
                        "ejemplo": null,
                        "hijos": []
                    },
                    {
                        "id": "300",
                        "nombre": "Restroom",
                        "texto": "\/*\n\nResources. Restroom\n\n\n*\/\nSYSTEM {TYPE:PRE_RUN,TRIGGER:PRE_RUN}\n;SYSTEM {TYPE:OPTIONS,Speed:8}\n\nRestroom {NAME:Restroom_agents,X:100,Y:100}\n\n\nPOSITION {NAME:POS1,X:237,Y:449}\nPOSITION {NAME:POS2,X:269,Y:334}\nPOSITION {NAME:POS3,X:272,Y:202,type:terminate,title:end}\n\nGraphic {NAME:textAgent,Type:TEXT,X:430,Y:471,Text:\"Agent\"}\nGraphic {NAME:Text2,Type:TEXT,X:431,Y:523,Text:\"Entity\"}\n\ninitial count,0\ninitial nAgent,0\nSTART 500\n;*****************************************************\nPROCEDURE PRE_RUN\n\ttimeout agent.main,1\n\tTERMINATE_VE \nENDPROCEDURE\n\n;*****************************************************\nGENERATE 10,0,0,0 {NAME:GEN1,X:43,Y:300}\nADVANCE 20,0 {TO:POS1}\nif (D$N%4==2)\n    signalnow agent.Add,X$nAgent\n    signalnow agent.Subtract,X$nAgent\n    savevalue result,P$(agentData,X$nAgent)\n    move {name:Text2,text:\"I am Entity D$N : result X$result\"}\nendif\nADVANCE 20,0 {TO:POS2}\nADVANCE 20,0 {TO:POS3}\nENDGENERATE 1\n\n;*******************************\nprocedure agent.main\n\tsavevalue nAgent,D$N\n    assign agentData,10\n    while (1==1)\n    move {name:textAgent,text:\"I am Agent X$nAgent [AC1: AC1$]\"}\n    REST Restroom_agents\n    endwhile\nendprocedure\n;**********************************\nprocedure agent.Add\n    ASSIGN agentData,P$agentData + 2\n    return_restore\nendprocedure\n;**********************************\n\nprocedure agent.Subtract\n    ASSIGN agentData,P$agentData - 1\n    return_restore\nendprocedure",
                        "descripcion": "<p><strong>RESTROOM<\/strong><\/p><p>Models a holding resource.<br>Entities enter and are automatically held, waiting until another entity releases them.<br>Internally it manages a single list: occupying entities.<br>This resource is especially useful to “sleep” agents or keep entities in passive (non-active) waiting.<\/p><p>Associated blocks:<\/p><ul><li><b>REST<\/b> resourceName ; The entity is held.<\/li><li><b>WAKE<\/b> resourceName[,number of entities to release][,entity number to release]; Releases the specified entities if provided (0 or -1 if it is by entity number) or releases only the given entity number if specified.<\/li><\/ul><p>Available events: <code>ON_REST<\/code>, <code>ON_WAKE<\/code><\/p><pre>Restroom {NAME:Agents, X:100, Y:100, ON_REST:Restroom1_onrest, E_BIN_START:0,E_BIN_SIZE:1,E_BIN_COUNT:40 }\n;------------------------\nREST Agents ; the agent becomes inactive\n;------------------------\nWAKE Agents ; wakes all agents\nWAKE Agents,0,X$nAgent ; wakes one specific agent<\/pre><p>&nbsp;<\/p>",
                        "parametros": null,
                        "parametros_json": null,
                        "ejemplo": null,
                        "hijos": []
                    },
                    {
                        "id": "302",
                        "nombre": "Conditions",
                        "texto": "\/*\n\nResources. Conditions\n\n\n*\/\nSYSTEM {TYPE:ON_TIMER, TRIGGER:TIMER1, INTERVAL: 350}\nSYSTEM {TYPE:ON_TIMER, TRIGGER:TIMER2, INTERVAL: 650}\n\nPOSITION {NAME:Exit,X:615,Y:388}\n\ninitial posY,500\nGraphic {NAME:Text1,Type:TEXT,X:324,Y:X$posY - 0}\nGraphic {NAME:Text2,Type:TEXT,X:324,Y:X$posY - 20}\nGraphic {NAME:Text3,Type:TEXT,X:324,Y:X$posY - 40}\nGraphic {NAME:Text4,Type:TEXT,X:324,Y:X$posY - 60}\nGraphic {NAME:Text5,Type:TEXT,X:324,Y:X$posY - 80}\nGraphic {NAME:Text6,Type:TEXT,X:324,Y:X$posY - 100}\nGraphic {NAME:Text7,Type:TEXT,X:324,Y:X$posY - 120}\nGraphic {NAME:Text8,Type:TEXT,X:324,Y:X$posY - 140}\n\nConditions {NAME:Conditions1,X:324,Y:160\n\t,expression:(D$N % 3 == 0)\n\t,ON_ATTEMPT:Conditions1_ATTEMPT\n\t,ON_CHECK:Conditions1_CHECK\n\t,ON_QUEUE:Conditions1_QUEUE\n    }\n\n\nSTART 100\n\n;-------------------------------\n\nGENERATE 20,0 {NAME:GEN1,X:62,Y:396}\n\nadvance 10 {to:Conditions1}\n\nwaituntil Conditions1,(D$N!=3)\n\nmove {name:Text1,text:\"AC1$ I am Entity [D$N] and I move on\"}\nadvance 100,50 {to:Exit}\n\nendgenerate 1\n;-------------------------------\nPROCEDURE TIMER1\n\twaitcheck Conditions1,(D$N%2==1)\n\tmove {name:Text6,text:\"AC1$ I am TIMER [D$N] WAITCHECK the odd ones\"}\n\tTERMINATE_VE \nENDPROCEDURE \n\nPROCEDURE TIMER2\n\twaitcheck Conditions1,(1==1)\n\tmove {name:Text7,text:\"AC1$ I am TIMER [D$N] WAITCHECK ALL\"}\n\tTERMINATE_VE \nENDPROCEDURE \n\nPROCEDURE Conditions1_QUEUE\n\tmove {name:Text3,text:\"AC1$ I am the VE [D$N] from ON_QUEUE for entity P$ENTITYNUMBER\"}\n    TERMINATE_VE\nendprocedure \nPROCEDURE Conditions1_CHECK\n\tmove {name:Text4,text:\"AC1$ I am the VE [D$N] from ON_CHECK for entity P$ENTITYNUMBER\"}\n    TERMINATE_VE\nendprocedure \nPROCEDURE Conditions1_ATTEMPT\n\tmove {name:Text5,text:\"AC1$ I am the VE [D$N] from ON_ATTEMPT for entity P$ENTITYNUMBER\"}\n    TERMINATE_VE\nendprocedure \n;-------------------------------\n",
                        "descripcion": "<p><strong>Conditions<\/strong><\/p><p>Models a conditional holding resource.<br>An entity may pass through immediately or be held depending on whether certain logical conditions are met, both general and entity-specific.<\/p><p><b>Holding logic<\/b>:<\/p><p>The resource evaluates three types of conditions:<\/p><ul><li><p><strong>GENERAL EXPRESSION<\/strong> (<code>EXPRESSION<\/code>)<br>Defined on the resource itself (affects all entities).<\/p><\/li><li><p><strong>ENTITY-SPECIFIC EXPRESSION<\/strong><br>Specified in the <code>WAITUNTIL<\/code> block for a specific entity.<\/p><\/li><li><p><strong>ABSOLUTE EXPRESSION<\/strong><br>Provided in <code>WAITCHECK<\/code>, and overrides the others. If it is true, it releases entities.<\/p><\/li><\/ul><p>For an entity to continue, <strong>both expressions<\/strong> (GENERAL and ENTITY-SPECIFIC) must be true, unless an ABSOLUTE EXPRESSION is used, which becomes the only releasing condition.<\/p><p>Releasing (or allowing passage) happens through a check. This check occurs whenever an entity is released or when explicitly requested.<br><br>Expressions are always written in parentheses.<br><br>Internally it manages one list: occupying entities.<br>This resource is especially useful as a general multi-traffic-light or a shared waiting room for multiple resources together.<br>Checking can happen every tick or at a fixed interval via a TIMER.<br>Typically, checks are triggered from the HOOKs of the involved resources.<\/p><p>Associated blocks:<\/p><ul><li><b>WAITUNTIL<\/b> resourceName[,(entitySpecificExpression)] ; The entity is held if it does not satisfy the ABSOLUTE expression or the ENTITY-SPECIFIC one (if defined).<\/li><li><b>WAITCHECK<\/b> resourceName[,(absoluteExpression)]; Checks all held entities. If an ABSOLUTE expression is provided, it becomes the only releasing criterion.<\/li><\/ul><p>Available events: <code>ON_ATTEPMT<\/code>, <code>ON_CHECK<\/code>, <code>ON_QUEUE<\/code><\/p><pre>Conditions {NAME:semaphore, EXPRESSION:(D$N %2 == 1) X:100, Y:100, ON_CHECK:semaphore_check}\n;------------------------\nWAITUNTIL semaphore; The entity continues if it is odd; (The entity is held if its number is even.)\nWAITUNTIL semaphore,(D$N %3 == 0); The entity continues if it is odd and a multiple of 3. (3,9,15...)\n;------------------------\nWAITCHECK semaphore; Checks all held entities\nWAITCHECK semaphore,(1==1) ; Releases all held entities\nWAITCHECK semaphore,(D$N %2 == 0) ; Releases all even entities<\/pre>",
                        "parametros": null,
                        "parametros_json": null,
                        "ejemplo": null,
                        "hijos": []
                    },
                    {
                        "id": "301",
                        "nombre": "Stock",
                        "texto": "\/*\r\n\r\nResources. Stock\r\n\r\n\r\n*\/\r\nSYSTEM {TYPE:ON_TIMER, TRIGGER:MARKET1_TIMER, INTERVAL: 20}\r\n\r\n\r\nSTOCK {NAME:MARKET1,X:331,Y:210\r\n\t ,ON_QUEUE:MARKET1_QUEUE\r\n \t ,ON_STOCKIN:MARKET1_STOCKIN\r\n     ,ON_STOCKOUT:MARKET1_STOCKOUT\r\n     ,ON_ATTEMPT:MARKET1_ATTEMPT\r\n     ,R_BIN_START:0,R_BIN_SIZE:1,R_BIN_COUNT:20\r\n     ,E_BIN_START:0,E_BIN_SIZE:1,E_BIN_COUNT:100\r\n     }\r\n\r\nPOSITION {NAME:POS1,X:70,Y:113}\r\nPOSITION {NAME:POS2,X:595,Y:283}\r\n\r\ninitial posY,500\r\nGraphic {NAME:Text1,Type:TEXT,X:324,Y:X$posY - 0}\r\nGraphic {NAME:Text2,Type:TEXT,X:324,Y:X$posY - 20}\r\nGraphic {NAME:Text3,Type:TEXT,X:324,Y:X$posY - 40}\r\nGraphic {NAME:Text4,Type:TEXT,X:324,Y:X$posY - 60}\r\nGraphic {NAME:Text5,Type:TEXT,X:324,Y:X$posY - 140}\r\nGraphic {NAME:Text6,Type:TEXT,X:324,Y:X$posY - 160}\r\nGraphic {NAME:Text7,Type:TEXT,X:324,Y:X$posY - 180}\r\nGraphic {NAME:Text8,Type:TEXT,X:324,Y:X$posY - 200}\r\n\r\nSTART 300 \r\n;*****************************************************************\r\n; SUPPLIERS: Generate products to add into the STOCK\r\nGENERATE 115,0 {NAME:SUPPLIERS,X:619,Y:194,ECOLOR:#006666,ERADIO:15}\r\n\r\n\r\n\r\nADVANCE 20,0 {TO:MARKET1}\r\n\r\nassign table,ROUND(RANDOM * 30)\r\nassign chair,round(random * 100)\r\nassign wardrobe,round(random * 5)\r\nassign lamp,round(random * 5)\r\n\r\n\r\nassign truck,{table:P$table,chair:P$chair,wardrobe:P$wardrobe}\r\nassign.merge truck,{lamp:P$lamp}\r\nSTOCKIN MARKET1, V$truck\r\n\r\nMOD {RADIO:5}\r\nADVANCE 20,0 {TO:POS2}\r\nTERMINATE 1\r\n\r\n;*****************************************************************\r\n; CUSTOMERS: Consume products from the STOCK\r\nGENERATE 20,2 {NAME:CUSTOMERS,X:81,Y:207,ECOLOR:#666666}\r\n\r\nassign cart,{}\r\nassign.merge cart,{table:2}\r\nassign.merge cart,{chair:4}\r\n\r\nif (SC$(MARKET1,cart)==0)\r\nmove {name:Text1,text:\"OUT OF STOCK\"}\r\nelse\r\nmove {name:Text1,text:\"ENOUGH STOCK\"}\r\nendif\r\n\r\nADVANCE 10,0 {TO:MARKET1}\r\n\r\nSTOCKOUT MARKET1, V$cart\r\nMOD {RADIO:8}\r\nADVANCE 50,50 {TO:POS1}\r\nTERMINATE 1\r\n\r\n;-------------------------------\r\n\r\nPROCEDURE MARKET1_STOCKOUT\r\n\t; MAPPER is an object {table:N,chair:N}\r\n    move {name:Text2,text:\"ON_STOCKOUT Tables: P$(MAPPER.table) Chairs: P$(MAPPER.chair)\"}\r\n    TERMINATE_VE\r\nendprocedure \r\n\r\nPROCEDURE MARKET1_STOCKIN\r\n\t; MAPPER is an object {table:N,chair:N}\r\n    move {name:Text3,text:\"ON_STOCKIN Tables: P$(MAPPER.table) Chairs: P$(MAPPER.chair)\"}\r\n    TERMINATE_VE\r\nendprocedure \r\n\r\nPROCEDURE MARKET1_ATTEMPT\r\n\t; MAPPER is an object {table:N,chair:N}\r\n    move {name:Text4,text:\"ON_ATTEMPT Tables: P$(MAPPER.table) Chairs: P$(MAPPER.chair)\"}\r\n    TERMINATE_VE\r\nendprocedure \r\n\r\nPROCEDURE MARKET1_QUEUE\r\n\t; MAPPER is an object {table:N,chair:N}\r\n    move {name:Text5,text:\"ON_QUEUE Tables: P$(MAPPER.table) Chairs: P$(MAPPER.chair)\"}\r\n    TERMINATE_VE\r\nendprocedure \r\n;-------------------------------\r\nPROCEDURE MARKET1_TIMER\r\n\tassign tmp,VS$(MARKET1)\r\n\tassign txt,\"\"\r\n\tforeach key,IN_OBJECT,V$(tmp) \r\n       assign txt,\"P$(txt) | P$(key) : P$(tmp.P$(key))\"\r\n    endforeach\r\n    move {name:Text6,text:\"AC1$ ON_TIMER [P$txt]\"}\r\n    TERMINATE_VE\r\nendprocedure \r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n",
                        "descripcion": "<p><strong data-start=\"678\" data-end=\"690\">STOCK<\/strong><\/p>\r\n<p>STOCK models an intelligent warehouse of labeled products. It supports stock-in and stock-out operations by item type and quantity. It allows multiple simultaneous operations, availability checks, and events (hooks) that can be connected to external logic.<br>\r\n<br>\r\nIt is ideal for modeling inventories, markets, component warehouses, etc.<\/p>\r\n<p><br>\r\n<b>Structure and behavior<\/b><br>\r\nThe resource stores products as objects of the form {key: quantity}, internally organized by product type (key).<br>\r\nIt supports multiple simultaneous load\/unload operations, accumulating quantities per product.<\/p>\r\n<p>Associated blocks:<\/p>\r\n<ul>\r\n    <li><b>STOCKIN<\/b> resourceName, variableName ; Adds products into the Stock. The variable must be an object like <code data-start=\"1109\" data-end=\"1128\">{key1: qty1 , key2: qty2}<\/code>.<\/li>\r\n    <li><b>STOCKOUT<\/b> resourceName, variableName ; Removes products from the STOCK if there is enough availability.<br>\r\n    The variable must be an object like <code data-start=\"1109\" data-end=\"1128\">{key1: qty1 , key2: qty2}<\/code>.<\/li>\r\n<\/ul>\r\n<p><b>Associated SNAs:<\/b><br>\r\n<code>SC$(resource, object)<\/code> returns 0 or 1 depending on whether the resource has enough quantities of the object to perform STOCKOUT.<\/p>\r\n<p><code>R$(name,STOCK,key)<\/code> returns the current stock for a specific type.<br>\r\n<br>\r\n<code>VS$(name)<\/code> &rarr; returns the full stock as an object {key1: qty1 , key2: qty2, ...}.<\/p>\r\n<p><br>\r\n<b>Available events:<\/b> <code>ON_ATTEMPT<\/code>, <code>ON_STOCKIN<\/code>, <code>ON_STOCKOUT<\/code>, <code>ON_QUEUE<\/code><\/p>\r\n<pre>\r\nSTOCK {NAME:MARKET1,X:331,Y:210\r\n     ,ON_QUEUE:MARKET1_QUEUE\r\n     ,ON_STOCKIN:MARKET1_STOCKIN\r\n     ,ON_STOCKOUT:MARKET1_STOCKOUT\r\n     ,ON_ATTEMPT:MARKET1_ATTEMPT\r\n     ,R_BIN_START:0,R_BIN_SIZE:1,R_BIN_COUNT:20\r\n     ,E_BIN_START:0,E_BIN_SIZE:1,E_BIN_COUNT:100\r\n     }\r\n;------------------------\r\nassign table,round(random * 30)\r\nassign chair,round(random * 100)\r\nassign wardrobe,round(random * 5)\r\nassign lamp,round(random * 5)\r\nassign truck,{table:P$table,chair:P$chair,wardrobe:P$wardrobe}\r\nassign.merge truck,{lamp:P$lamp}\r\nSTOCKIN MARKET1, TRUCK\r\n;------------------------\r\n\r\n<\/pre>\r\n<p>&nbsp;<\/p>",
                        "parametros": null,
                        "parametros_json": null,
                        "ejemplo": null,
                        "hijos": []
                    },
                    {
                        "id": "347",
                        "nombre": "Backpack",
                        "texto": "RESTROOM {NAME:receiverWarehouse1,X:220,Y:348,E_BIN_SIZE:1,E_BIN_COUNT:10}\r\nRESTROOM {NAME:receiverWarehouse2,X:217,Y:182,E_BIN_SIZE:1,E_BIN_COUNT:10}\r\nRESTROOM {NAME:distributionWarehouse,X:662,Y:93}\r\n\r\nGraphic {NAME:Text1,Type:TEXT,X:100,Y:100,Text:\"Finished: NO\",font:\"20\",color:red}\r\n\r\n\r\nSTART 1000\r\n;************************************************************************\r\n\r\nGENERATE 8,3 {NAME:Reception1,X:66,Y:356}\r\nADVANCE 20,0 {TO:receiverWarehouse1}\r\nrest receiverWarehouse1\r\nterminate 1\r\n\r\n;************************************************************************\r\n\r\nGENERATE 5,3 {NAME:Reception2,X:65,Y:181}\r\nADVANCE 20,0 {TO:receiverWarehouse2}\r\nrest receiverWarehouse2\r\nterminate 1\r\n\r\n;************************************************************************\r\n\r\nGENERATE 40,0,0,1 {NAME:Vans,X:40,Y:567\r\n\t\t,eradio:16,ecolor:red,visible:0\r\n\t\t,esubtitle:\"P$(backpack1.LENGTH)\"}\r\nADVANCE0 {TO:DistributionPoint}\r\nwhile (1==1)\r\n    ADVANCE 20,30 {TO:receiverWarehouse1}\r\n    load backpack1,receiverWarehouse1\r\n    ADVANCE 20,30 {TO:receiverWarehouse2}\r\n    load backpack1,receiverWarehouse2\r\n\r\n\tADVANCE 20,30 {TO:DistributionPoint}\r\n    unload backpack1,DistributionPoint\r\nendwhile\r\nterminate 1\r\n\r\n;************************************************************************\r\n\r\nGENERATE 0,0,0,0 {NAME:DistributionPoint,X:669,Y:434}\r\nADVANCE0 {TO:DistributionPoint}\r\n\r\nADVANCE 20,50 {TO:distributionWarehouse}\r\nif (D$N>1000)\r\nmove {name:Text1,text:\"FINISHED: YES\",color:green}\r\nstop\r\nendif\r\nrest distributionWarehouse\r\n\r\nterminate 1\r\n\r\n\r\n\r\n",
                        "descripcion": "<p>Backpack is not a resource as such because it does not perform internal logic; it is more of an entity-transport tool, although it does retain entities.<\/p>\r\n<p>To move entities from one point to another in the simulation (for example, a van carrying packages), you need something that tells the system those entities are no longer available in the event chain nor in any other queue.<\/p>\r\n<p>This concept can be thought of as a backpack where one entity can carry other entities. There are two limitations:<\/p>\r\n<p>You can only load from a <code>RESTROOM<\/code> because it is a holding resource where entities do not leave on their own, and you can only unload into a <code>GENERATE<\/code> because it is the only safe point with respect to the entity call\/return stack (see <code>SCAPE<\/code>).<\/p>\r\n<p>It has two associated blocks:<\/p>\r\n<ul>\r\n    <li><code>LOAD<\/code> backpackName, restroomName[, entityNumber]<\/li>\r\n    <li><code>UNLOAD<\/code> backpackName, generateName[, entityNumber]<\/li>\r\n<\/ul>\r\n<p>The first loads into the backpack either all the contents of a Restroom or the specific entity with that number, and the second is the inverse operation at the <code>GENERATE<\/code>.<\/p>\r\n<p>The entities inside the backpack can be obtained through the <code>ASSIGN<\/code> created with the same name as the backpack. It is an array containing the entity numbers.<\/p>\r\n<p>The example shows a van route that stops at two pickup points and carries the packages to the distribution point.<\/p>",
                        "parametros": null,
                        "parametros_json": null,
                        "ejemplo": null,
                        "hijos": []
                    }
                ]
            },
            {
                "id": "345",
                "nombre": "Logical Resources",
                "texto": "",
                "descripcion": "",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": [
                    {
                        "id": "372",
                        "nombre": "Table",
                        "texto": "FACILITY {NAME:WINDOW1,X:380,Y:348,capacity:4}\r\nPOSITION {NAME:POS1,X:218,Y:437}\r\nPOSITION {NAME:POS2,X:591,Y:429}\r\nPOSITION {NAME:POS3,X:713,Y:329}\r\n\r\nGraphic {NAME:Line1,Type:L,color:#FF0000, X1:218,Y1:500,X2:592,Y2:500}\r\nGraphic {NAME:Text1,Type:T,X:410,Y:527,Text:\"Statistics section\"}\r\n\r\nTABLE {name: TABLE1,E_BIN_START:0,E_BIN_SIZE:1,E_BIN_COUNT:100,EXPRESSION:(M1$ - P$STARTTIME)}\r\n\r\nSTART 100 \r\n\r\n;***************************************************************\r\n\r\n\r\nGENERATE 8,3 {NAME:GEN1,X:66,Y:350}\r\n\r\nADVANCE 30,0 {TO:POS1}\r\nASSIGN STARTTIME,M1$\r\nADVANCE 20,0 {TO:WINDOW1}\r\n\r\nSEIZE WINDOW1\r\nADVANCE 20,20\r\nRELEASE WINDOW1\r\n\r\n\r\nADVANCE 20,0 {TO:POS2}\r\nTABULATE TABLE1\r\nADVANCE 20,0 {TO:POS3}\r\n\r\nTERMINATE 1\r\n\r\n;***************************************************************",
                        "descripcion": "",
                        "parametros": null,
                        "parametros_json": null,
                        "ejemplo": null,
                        "hijos": []
                    },
                    {
                        "id": "304",
                        "nombre": "FSM - Finite State Machine",
                        "texto": "POSITION {NAME:Exit,X:648,Y:383}\r\n\r\n\r\ninitial posY,500\r\ninitial logic, { STATES: [\"open\", \"close\"],\r\n    TRANSITIONS: [\r\n        {FROM: \"open\", INPUT: \"close\", TO: \"close\", TRIGGER: \"doorOpened\"},\r\n        {FROM: \"close\", INPUT: \"open\", TO: \"open\"},\r\n        {FROM: \"close\", INPUT: \"switch\", TO: \"open\"},\r\n        {FROM: \"open\", INPUT: \"switch\", TO: \"close\"}\r\n    ],\r\n    INITIAL: \"open\"\r\n    }\r\n\r\nFSM {NAME:FSM1,X:434,Y:540, LOGIC:V$(logic)}\r\n\r\n\r\n\r\n\r\nGraphic {NAME:Text1,Type:TEXT,X:324,Y:X$posY - 0}\r\nGraphic {NAME:Text2,Type:TEXT,X:324,Y:X$posY - 20}\r\nGraphic {NAME:Text3,Type:TEXT,X:324,Y:X$posY - 40}\r\nGraphic {NAME:Text4,Type:TEXT,X:324,Y:X$posY - 60}\r\nGraphic {NAME:Text5,Type:TEXT,X:324,Y:X$posY - 80}\r\nGraphic {NAME:Text6,Type:TEXT,X:324,Y:X$posY - 100}\r\nGraphic {NAME:Text7,Type:TEXT,X:324,Y:X$posY - 120}\r\nGraphic {NAME:Text8,Type:TEXT,X:324,Y:X$posY - 140}\r\n\r\nConditions {NAME:Conditions1,X:317,Y:539,\r\n    expression:(\"R$(FSM1,IN_AFTER,close)\"==\"open\"),\r\n    ON_ATTEMPT:Conditions1_ATTEMPT,\r\n    ON_CHECK:Conditions1_CHECK,\r\n    ON_QUEUE:Conditions1_QUEUE\r\n    }\r\n\r\n\r\nSTART 100\r\n\r\n;-------------------------------\r\n\r\nGENERATE 20,0 {NAME:GEN1,X:62,Y:396}\r\n    advance 10 {to:Conditions1}\r\n    waituntil Conditions1\r\n    advance 15,25 {to:Exit}\r\n    STATE FSM1,\"open\"\r\n    waitcheck Conditions1\r\nterminate 1\r\n;-------------------------------\r\nPROCEDURE Conditions1_QUEUE\r\n\tmove {name:Text3,text:\"AC1$ I am the VE [D$N] from ON_QUEUE, entity P$ENTITYNUMBER\"}\r\n    TERMINATE_VE\r\nendprocedure 1\r\nPROCEDURE Conditions1_CHECK\r\n\tmove {name:Text4,text:\"AC1$ I am the VE [D$N] from ON_CHECK, entity P$ENTITYNUMBER\"}\r\n    TERMINATE_VE\r\nendprocedure 1\r\nPROCEDURE Conditions1_ATTEMPT\r\n\tmove {name:Text5,text:\"AC1$ I am the VE [D$N] from ON_ATTEMPT, entity P$ENTITYNUMBER\"}\r\n    TERMINATE_VE\r\nendprocedure 1\r\n;-------------------------------\r\nPROCEDURE doorOpened\r\n\tmove {name:Text7,text:\"Entity P$ENTITYNUMBER has opened the door\"}\r\n    TERMINATE_VE\r\nendprocedure 1\r\n;-------------------------------\r\n\r\n\r\n",
                        "descripcion": "<p><strong data-start=\"678\" data-end=\"690\">FSM - Finite State Machine<\/strong><\/p>\r\n<p data-start=\"231\" data-end=\"434\">The <code data-start=\"241\" data-end=\"249\">FSM<\/code> block lets you model a <strong data-start=\"270\" data-end=\"300\">Finite State Machine<\/strong>. It is a resource that manages internal states defined by a transition table, triggered by inputs (<code>INPUT<\/code>).<\/p>\r\n<p data-start=\"436\" data-end=\"524\">The behavior is defined with a JSON object with these fields:<\/p>\r\n<ul>\r\n    <li><code data-start=\"528\" data-end=\"536\">STATES<\/code>: List of possible states (optional if <code>EVAL<\/code><code data-start=\"584\" data-end=\"593\">: 1<\/code> is used)<\/li>\r\n    <li><code data-start=\"597\" data-end=\"610\">TRANSITIONS<\/code>: List of transitions between states<\/li>\r\n    <li><code data-start=\"650\" data-end=\"659\">INITIAL<\/code>: Initial state (*only for LOCAL:0)<\/li>\r\n    <li><code data-start=\"678\" data-end=\"684\">EVAL<\/code>: (optional) If it is <code data-start=\"703\" data-end=\"706\">1<\/code>, it allows mathematical expressions in <code>TO<\/code><code data-start=\"748\" data-end=\"752\">.<\/code><\/li>\r\n<\/ul>\r\n<p data-start=\"436\" data-end=\"524\">Each transition can contain:<\/p>\r\n<ul>\r\n    <li><b>FROM<\/b>: previous state. If it is <code>\"\"<\/code> it works as a wildcard (accepts any state).<\/li>\r\n    <li><b>INPUT<\/b>: input name. <code data-start=\"979\" data-end=\"983\">\"\"<\/code> works as a wildcard.<\/li>\r\n    <li><b>TO<\/b>: new state (direct value or expression if <code>EVAL:1<\/code>).<\/li>\r\n    <li><b>TRIGGER<\/b>: <em data-start=\"1067\" data-end=\"1079\">(optional)<\/em> procedure fired when the transition happens.<\/li>\r\n<\/ul>\r\n<pre>\r\n; BASIC EXAMPLE\r\ninitial logic, { STATES: [\"open\", \"close\"],\r\n    TRANSITIONS: [\r\n        {FROM: \"open\", INPUT: \"close\", TO: \"close\", TRIGGER: \"doorOpened\"},\r\n        {FROM: \"close\", INPUT: \"open\", TO: \"open\"},\r\n        {FROM: \"close\", INPUT: \"switch\", TO: \"open\"},\r\n        {FROM: \"open\", INPUT: \"switch\", TO: \"close\"}\r\n    ],\r\n    INITIAL: \"open\"\r\n    }\r\n\r\nFSM {NAME:FSM1,X:434,Y:540, LOGIC:V$(logic)}\r\n\r\n\r\n; CYCLIC EXAMPLE\r\ninitial logic2, { states: [\"one\", \"two\", \"three\"],\r\n    TRANSITIONS: [\r\n        {FROM: \"one\", INPUT: \"next\", TO: \"two\"},\r\n        {FROM: \"two\", INPUT: \"next\", TO: \"three\"},\r\n        {FROM: \"three\", INPUT: \"next\", TO: \"one\", TRIGGER: \"reset\"}\r\n    ],\r\n    INITIAL: \"open\"\r\n    }\r\nFSM {NAME:FSM2,X:134,Y:140, LOGIC:V$(logic2)}\r\n\r\n\r\n; EVALUATED LOGIC EXAMPLE\r\n; In this mode (<code data-start=\"1592\" data-end=\"1601\">eval: 1<\/code>), states and transitions can be evaluated as dynamic mathematical expressions.\r\n\r\ninitial logicTemp3, {\r\n  TRANSITIONS: [\r\n    {FROM: \"\", INPUT: \"up\", TO: \"(X + 1 <= 24 ? X + 1.5 : X)\"},\r\n    {FROM: \"\", INPUT: \"down\", TO: \"(X - 1 >= 18 ? X - 1.5 : X)\"},\r\n    {FROM: \"\", INPUT: \"reset\", TO: \"21\"}\r\n  ],\r\n  EVAL: 1,\r\n  INITIAL: 21\r\n}\r\n\r\nFSM {NAME:Stater3, X:434, Y:540, LOGIC:V$(logicTemp3)}\r\n\r\n\r\n; EVALUATED LOGIC EXAMPLE WITH EXTRA PARAMETER Y\r\n; YOU CAN ADD PARAMETERS Y, Z TO THE FUNCTIONS\r\n\r\ninitial logicTemp4, {\r\n  TRANSITIONS: [\r\n    {FROM: \"\", INPUT: \"up\", TO: \"(X + 1 <= 24 ? X + Y : X)\"},\r\n    {FROM: \"\", INPUT: \"down\", TO: \"(X - 1 >= 18 ? X - Y : X)\"},\r\n    {FROM: \"\", INPUT: \"reset\", TO: \"21\"}\r\n  ],\r\n  EVAL: 1,\r\n  INITIAL: 21\r\n}\r\n\r\nFSM {NAME:Stater4, X:434, Y:540, LOGIC:V$(logicTemp4)}\r\n<\/pre>\r\n<p><b>Associated blocks:<\/b><\/p>\r\n<ul>\r\n    <li><b>FSM<\/b> resourceName,input[, paramY [,paramZ]] ; Executes a state transition according to the defined logic.<\/li>\r\n<\/ul>\r\n<pre>\r\nFSM Fsm1,\"OPEN\" ; moves to state \"CLOSE\"\r\nFSM Fsm1,\"SWITCH\" ; if it was \"OPEN\" it goes to \"CLOSE\" and vice versa.\r\n\r\nFSM Fsm2,\"next\" ; if it was \"TWO\" it goes to \"THREE\", ...\r\n\r\nFSM Fsm4,\"up\",10 ; increments the state by 10\r\n<\/pre>\r\n<p><b>SNA:<\/b><\/p>\r\n<p>FSM is the only resource that offers an <b>atomic read-and-update operation for the state<\/b>.<\/p>\r\n<ul>\r\n    <li>R$(staterName,STATE) Returns the current state.<\/li>\r\n    <li>R$(staterName,IN_AFTER,input) Returns the current state and applies the input in an <b>ATOMIC OPERATION<\/b>.<\/li>\r\n    <li>R$(staterName,IN_BEFORE,input) Applies the input and returns the current state in an <b>ATOMIC OPERATION<\/b>.<\/li>\r\n    <li>R$(staterName,IN_BEFORE,input,Y,Z) Applies the input with Y,Z parameters for EVAL:1 FSM and returns the current state in an <b>ATOMIC OPERATION<\/b>.<\/li>\r\n<\/ul>\r\n<p>This lets you model <strong data-start=\"2079\" data-end=\"2140\">critical sections, traffic lights, and synchronization between processes<\/strong>.<\/p>\r\n<p><b>Typical uses<\/b><\/p>\r\n<ul>\r\n    <li>Critical-section control<\/li>\r\n    <li>Semaphores<\/li>\r\n    <li>Mutual exclusion<\/li>\r\n    <li>Process synchronization<\/li>\r\n    <li>Stateful math functions with parameters<\/li>\r\n<\/ul>\r\n<pre>\r\nwaituntil Conditions1,(\"R$(Fsm1,IN_AFTER,close)\"==\"open\") ; one entity passes and blocks the next ones\r\n...\r\nFSM Fsm1,\"open\" ; ends the mutual-exclusion zone\r\nwaitcheck Conditions1 ; lets the next one pass\r\n<\/pre>\r\n<p>And as a store of mathematical functions with two extra input parameters:<\/p>\r\n<pre>\r\n{ FROM: \"\", INPUT: \"incr\", TO: \"(X + Y * Z)\" } ; X: current state, Y,Z: extra input parameters\r\n\r\n<\/pre>\r\n<p><b>Available events:<\/b> TRIGGER<\/p>\r\n<p>Each transition can include a trigger that will call a <code>PROCEDURE<\/code>:<\/p>\r\n<pre>\r\nPROCEDURE doorOpened\r\n    move {name:text7,text:\"Entity P$ENTITYNUMBER has opened the door\"}\r\n    TERMINATE_VE\r\nendprocedure\r\n<\/pre>\r\n<p><b>Storage modes:<\/b><\/p>\r\n<p>Default mode is global (one state per <code>STATER<\/code>), but if you set:<\/p>\r\n<p><code>LOCAL:1<\/code><\/p>\r\n<p>Then it becomes one state per entity. Great as a path discriminator that avoids nested <code>SWITCH<\/code>.<\/p>\r\n<p>Since it is not assigned initially, it can be set through the associated assign directly:<\/p>\r\n<pre>\r\nassign Fsm1,10\r\n<\/pre>\r\n<p>&nbsp;<\/p>",
                        "parametros": null,
                        "parametros_json": null,
                        "ejemplo": null,
                        "hijos": []
                    },
                    {
                        "id": "303",
                        "nombre": "Queuer",
                        "texto": "\/*\r\n\r\nResources. Queuer\r\n\r\n*\/\r\n;SYSTEM {TYPE:OPTIONS,Speed:50,Pause:0}\r\nPOSITION {NAME:POS1,X:620,Y:360}\r\n\r\nQUEUER {NAME:Qventanilla1,X:374,Y:424\r\n\t,R_BIN_START:0,R_BIN_SIZE:1,R_BIN_COUNT:20 \r\n    ,E_BIN_START:0,E_BIN_SIZE:1,E_BIN_COUNT:20}\r\n\r\nFacility {NAME:counter1,X:373,Y:365,capacity:5}\r\nSTART 200\r\n\r\n;*****************************************************\r\nGENERATE 5,3,0,0 {NAME:GEN1,X:111,Y:366}\r\nADVANCE 10 {TO:counter1}\r\n\r\nqueue Qventanilla1\r\nseize counter1\r\ndepart Qventanilla1\r\nADVANCE 20,10\r\nrelease counter1\r\n\r\nADVANCE 10 {TO:POS1}\r\nENDGENERATE 1\r\n",
                        "descripcion": "<p><strong data-start=\"678\" data-end=\"690\">QUEUER<\/strong><\/p>\r\n<p>Models an open resource.<br data-start=\"769\" data-end=\"772\">\r\nIt allows multiple entities with no selection criteria.<br>\r\nInternally it manages a list of entities inside the resource.<br>\r\n<br>\r\nIts main use is statistical or as an entity grouper.<\/p>\r\n<p>Associated blocks:<\/p>\r\n<ul>\r\n    <li><b>QUEUE<\/b> resourceName ; Adds the entity to the queuer.<\/li>\r\n    <li><b>DEPART<\/b> resourceName ; Removes the entity from the queuer.<\/li>\r\n<\/ul>\r\n<p>Available events: <code>ON_QUEUE<\/code>, <code>ON_DEPART<\/code><\/p>\r\n<pre>\r\nQUEUER {NAME:Qventanilla1,X:374,Y:424\r\n    ,R_BIN_START:0,R_BIN_SIZE:1,R_BIN_COUNT:20 \r\n    ,E_BIN_START:0,E_BIN_SIZE:1,E_BIN_COUNT:20}\r\n;------------------------\r\nqueue Qventanilla1\r\nseize counter1\r\ndepart Qventanilla1\r\n<\/pre>\r\n<p>&nbsp;<\/p>",
                        "parametros": null,
                        "parametros_json": null,
                        "ejemplo": null,
                        "hijos": []
                    },
                    {
                        "id": "346",
                        "nombre": "",
                        "texto": "",
                        "descripcion": "",
                        "parametros": null,
                        "parametros_json": null,
                        "ejemplo": null,
                        "hijos": []
                    }
                ]
            },
            {
                "id": "294",
                "nombre": "System configuration",
                "texto": "SYSTEM {TYPE:OPTIONS, SPEED:5, TIME_DECIMALS:1, SHOW_BASICS:0}\r\nSYSTEM {TYPE:ON_TIMER, TRIGGER:updateGraphics, INTERVAL:0.5}\r\n\r\nPROCEDURE updateGraphics\r\n   move {name:text1:text: \"Text updated at AC1$\"}\r\n   TERMINATE_VE\r\nENDPROCEDURE",
                "descripcion": "<p>The <code>SYSTEM<\/code> command allows configuring different aspects of the simulation engine. Its basic syntax is:<\/p>\r\n<pre>\r\nSYSTEM {TYPE:..., ...}\r\n\r\n<\/pre>\r\n<p><b>Simulation parameters (speed, precision...)<\/b><br>\r\nYou can control the simulation speed, temporal precision, and time decimal precision:<\/p>\r\n<pre>\r\nSYSTEM {TYPE:OPTIONS, SPEED:3}\r\nSYSTEM {TYPE:OPTIONS, TIME_DECIMALS:2}\r\nSYSTEM {TYPE:OPTIONS, width:1400, height:1400}\r\nSYSTEM {TYPE:OPTIONS, SEED:1400}\r\n<\/pre>\r\n<ul>\r\n    <li><code>SPEED<\/code>: Initial playback speed (default: <code>5<\/code>).<\/li>\r\n    <li><code>TIME_DECIMALS<\/code>: Allows AC1 time to have decimal values like 3.14 instead of integers (default: <code>0<\/code>).<\/li>\r\n    <li><code>WIDTH<\/code>: Width of the simulation canvas. Default 800.<\/li>\r\n    <li><code>HEIGHT<\/code>: Height of the simulation canvas. Default 600.<\/li>\r\n    <li><code>SEED<\/code>: Generates the random number sequence using Xorshift128+.<\/li>\r\n    <li><code>TRACE_ROUTES<\/code>: Generates traces for V&amp;V.<\/li>\r\n<\/ul>\r\n<p><b>2.- Show basic system information<\/b><\/p>\r\n<p>You can enable or disable the display of key engine elements:<\/p>\r\n<pre>\r\nSYSTEM {TYPE:OPTIONS, SHOW_BASICS:1}<\/pre>\r\n<p>This will display at the bottom:<\/p>\r\n<ul>\r\n    <li><code>TG1<\/code>: Initial global time<\/li>\r\n    <li><code>AC1<\/code>: Current time<\/li>\r\n    <li><code>SPEED<\/code>: Simulation speed<\/li>\r\n<\/ul>\r\n<p><b>3.- Timers (TIMER)<\/b><\/p>\r\n<p>Timers allow procedures to be executed periodically, without entity intervention:<\/p>\r\n<pre>\r\nSYSTEM {TYPE:ON_TIMER, TRIGGER:fill, INTERVAL:0.1}\r\n<\/pre>\r\n<ul>\r\n    <li><code>TRIGGER<\/code>: Name of the procedure to execute.<\/li>\r\n    <li><code>INTERVAL<\/code>: Time interval (in simulation units) between executions.<\/li>\r\n<\/ul>\r\n<p>This is useful for monitoring tasks, logging, periodic loads, etc.<\/p>",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            },
            {
                "id": "285",
                "nombre": "Monitoring, reporting and debugging",
                "texto": "",
                "descripcion": "<p>The platform includes visual and technical tools that allow detailed tracking of the simulation, both at execution level and in terms of results.<\/p>\r\n<p><b>Debug panel<\/b><\/p>\r\n<p>From the third panel (playback canvas, tracking and debug, code editor), you can access:<\/p>\r\n<ul>\r\n    <li>\r\n    <p><strong>Event queue<\/strong><br>\r\n    Shows in real time which entities are scheduled, their temporal position (<code>TG1<\/code>) and which program step they are currently in.<\/p>\r\n    <\/li>\r\n    <li>\r\n    <p><strong>Resources<\/strong><br>\r\n    Details the occupying entities, those waiting (queue), and the capacity of each resource.<\/p>\r\n    <\/li>\r\n    <li>\r\n    <p><strong>Entities<\/strong><br>\r\n    Displays the state of each entity: variables, position, current step, delay, etc.<\/p>\r\n    <\/li>\r\n    <li>\r\n    <p><strong>Files<\/strong><br>\r\n    Displays all files created using the <code>FILE<\/code> command and the <code>WRITE<\/code> block.<br>\r\n    It also includes the special <code>DEBUG<\/code> file, which is automatically generated when instructions are marked with <code>{debug:1}<\/code> or <code>{debug:2}<\/code>.<\/p>\r\n    <ul>\r\n        <li>\r\n        <p><code>{debug:1}<\/code> records general information about the execution of the line.<\/p>\r\n        <\/li>\r\n        <li>\r\n        <p><code>{debug:2}<\/code> includes evaluated variable values and detailed results.<\/p>\r\n        <\/li>\r\n    <\/ul>\r\n    <\/li>\r\n<\/ul>\r\n<pre>\r\nif (P$variable == 1) {debug:1}\r\nassign P$variable, X$source {debug:2}\r\n<\/pre>\r\n<p>&nbsp;<\/p>\r\n<h3>Report button<\/h3>\r\n<p>Using the <strong>Report<\/strong> button, a complete statistical overview of the simulation is generated:<\/p>\r\n<ul>\r\n    <li>General simulation information, final time (<code>AC1<\/code>), number of processed entities, etc.<\/li>\r\n    <li>Status and history of each <strong>resource and its charts<\/strong>.<\/li>\r\n    <li>Information about the <strong>PLOTTER<\/strong> elements and their charts.<\/li>\r\n<\/ul>",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            }
        ]
    },
    {
        "id": "217",
        "nombre": "Season 4: Resource and Queue Control",
        "texto": "",
        "descripcion": "",
        "parametros": null,
        "parametros_json": null,
        "ejemplo": null,
        "hijos": [
            {
                "id": "173",
                "nombre": "Accessing and measuring a resource",
                "texto": "\/*\r\n\r\n Accessing and measuring a resource\r\n\r\n*\/\r\nSTORAGE {NAME: WAREHOUSE1, CAPACITY:40, X:316,Y:401}\r\n\r\nSYSTEM {TYPE:ON_TIMER,INTERVAL:50,TRIGGER:PROCTIMER}\r\n\r\nGRAPHIC {NAME:BANNER1,TYPE:TEXT,X:184,Y:343,TEXT:RANDOM.}\r\nGRAPHIC {NAME:BANNER2,TYPE:TEXT,X:305,Y:283,TEXT:SUM}\r\nGRAPHIC {NAME:BANNER3,TYPE:TEXT,X:306,Y:241,TEXT:DIRECT}\r\n\r\nPOSITION {NAME:POS1,X:176,Y:296}\r\nPOSITION {NAME:POS2,X:452,Y:300}\r\nPOSITION {NAME:POS3,X:559,Y:299}\r\n\r\nSTART 100\r\n\r\n;******************************************************\r\n\r\nGENERATE 30,10 {NAME:GEN1,X:61,Y:297}\r\n\r\n    ASSIGN RANDOM,FLOOR(RANDOM * 9 + 1) {debug:1}\r\n\r\n    MOVE {NAME:BANNER1,TEXT:\"RANDOM: P$RANDOM\"}\r\n    ADVANCE 20 {TO:POS1}\r\n    ADVANCE 20 {TO:WAREHOUSE1}\r\n    ENTER WAREHOUSE1  ,P$RANDOM\r\n    ADVANCE 110,90\r\n    LEAVE WAREHOUSE1 \r\n    ADVANCE 20 {TO:POS2}\r\n    ADVANCE 20,0 {TO:POS3}\r\nENDGENERATE 1\r\n\r\n;*****************************************************\r\nPROCEDURE PROCTIMER\r\n\r\n    ASSIGN SUM,0\r\n\r\n    FOREACH NUMBER,IN_RESOURCE,WAREHOUSE1\r\n      ASSIGN SUM,(P$(RANDOM,P$NUMBER) + P$SUM)\r\n    ENDFOREACH\r\n\r\n    MOVE {NAME:BANNER2,TEXT:\"SUM OF RANDOMS: P$SUM\"}\r\n    ASSIGN DIRECT,40-R$(WAREHOUSE1,LEFT)\r\n    MOVE {NAME:BANNER3,TEXT:\"DIRECT: P$DIRECT\"}\r\n    TERMINATE_VE\r\nENDPROCEDURE\r\n;*****************************************************\r\n",
                "descripcion": "<p data-start=\"149\" data-end=\"376\">This example shows the basic use of a <code data-start=\"204\" data-end=\"213\">STORAGE<\/code> resource, useful to model inventories, warehouses, or capacity-limited areas. Entities consume a random number of units from the resource, representing a variable load.<\/p>\r\n<p data-start=\"378\" data-end=\"493\">The interesting part of the example is how to obtain the resource contents in real time using <strong data-start=\"466\" data-end=\"492\">two different methods<\/strong>:<\/p>\r\n<ul data-start=\"495\" data-end=\"825\">\r\n    <li data-start=\"495\" data-end=\"677\">\r\n    <p data-start=\"497\" data-end=\"677\"><strong data-start=\"497\" data-end=\"528\">Sum of individual data:<\/strong> using <code data-start=\"536\" data-end=\"545\">FOREACH<\/code>, you iterate over each entity occupying the resource and add up its associated values (in this case, the number of units it took).<\/p>\r\n    <\/li>\r\n    <li data-start=\"678\" data-end=\"825\">\r\n    <p data-start=\"680\" data-end=\"825\"><strong data-start=\"680\" data-end=\"701\">Direct query:<\/strong> with <code data-start=\"711\" data-end=\"730\">R$(WAREHOUSE1,LEFT)<\/code> you get the number of <strong data-start=\"764\" data-end=\"774\">free<\/strong> units, so the total occupied is <code data-start=\"807\" data-end=\"824\">CAPACITY - LEFT<\/code>.<\/p>\r\n    <\/li>\r\n<\/ul>\r\n<p data-start=\"827\" data-end=\"994\">Both approaches let you cross-check and validate the information, and can be applied to statistical calculations, inventory control, or saturation alerts.<\/p>\r\n<p data-start=\"996\" data-end=\"1123\">The <code data-start=\"999\" data-end=\"1006\">TIMER<\/code> periodically updates the on-screen information, providing a continuous view of the resource state.<\/p>",
                "parametros": null,
                "parametros_json": "",
                "ejemplo": null,
                "hijos": []
            },
            {
                "id": "310",
                "nombre": "Managing service time",
                "texto": "\/*\r\n\r\n Managing service time\r\n\r\n*\/\r\nFacility {NAME:Facility_1,X:400,Y:84,capacity:3,E_BIN_SIZE:1,E_BIN_COUNT:200}\r\nFacility {NAME:Facility_2,X:400,Y:282,capacity:3,E_BIN_SIZE:1,E_BIN_COUNT:200}\r\nFacility {NAME:Facility_3,X:400,Y:471,capacity:3,E_BIN_SIZE:1,E_BIN_COUNT:200}\r\n\r\nQueuer {NAME:Queuer_1,X:400,Y:174,R_BIN_SIZE:1,R_BIN_COUNT:30}\r\nQueuer {NAME:Queuer_2,X:400,Y:363,R_BIN_SIZE:1,R_BIN_COUNT:30}\r\nQueuer {NAME:Queuer_3,X:400,Y:557,R_BIN_SIZE:1,R_BIN_COUNT:30}\r\n\r\n\r\n\r\nGraphic {NAME:Text_1,Type:TEXT,X:400,Y:132}\r\nGraphic {NAME:Text_2,Type:TEXT,X:400,Y:323}\r\nGraphic {NAME:Text_3,Type:TEXT,X:400,Y:512}\r\n\r\nPOSITION {NAME:POS_1,X:700,Y:137}\r\nPOSITION {NAME:POS_2,X:700,Y:328}\r\nPOSITION {NAME:POS_3,X:700,Y:506}\r\n\r\nSTART 1000\r\n\r\n;*********************************************************\r\n\r\nGENERATE 10,0 {NAME:GEN1,X:100,Y:126}\r\n    CALL counterPath,1\r\nENDGENERATE 1\r\n\r\nGENERATE 15,0 {NAME:GEN2,X:100,Y:319}\r\n    CALL counterPath,2\r\nENDGENERATE 1\r\n\r\nGENERATE 20,0 {NAME:GEN3,X:100,Y:492}\r\n    CALL counterPath,3\r\nENDGENERATE 1\r\n;----------------------------------\r\nPROCEDURE counterPath\r\n\tassign counter,\"Facility_P$PARAM_A\"\r\n\tassign queue,\"Queuer_P$PARAM_A\" {debug:1}\r\n\tassign counterId,\"P$PARAM_A\"\r\n    ADVANCE 20 {TO:\"P$counter\"}\r\n    CALL computeTime , \"P$counter\",P$counterId\r\n\tQUEUE P$queue\r\n\tSEIZE P$counter\r\n\tDEPART P$queue\r\n    ADVANCE P$computeTime\r\n    RELEASE P$counter\r\n    ADVANCE 20 {TO:\"POS_P$counterId\"}\r\nENDPROCEDURE\r\n;----------------------------------\r\nPROCEDURE computeTime\r\n\tassign counter,\"P$PARAM_A\"\r\n\tassign counterId,P$PARAM_B\r\n    assign queueSize,R$(P$counter,QUEUE) + 1\r\n    \r\n    ;ASSIGN serviceTime, round(max(2, 120 \/ P$queueSize))\r\n    ;ASSIGN serviceTime, round(max(2, 120 \/ sqrt(P$queueSize)))\r\n    ASSIGN serviceTime, round(120 \/ log(P$queueSize + 1))\r\n    move {name:\"Text_P$counterId\",text:\"service time: P$serviceTime\"}\r\n\tRETURN P$serviceTime  \r\nENDPROCEDURE\r\n\r\n",
                "descripcion": "<p data-start=\"316\" data-end=\"591\">Not all resources must serve every entity for the same duration. In some scenarios—such as customer service, healthcare triage, or processing stations—it can be reasonable to adapt the <strong data-start=\"529\" data-end=\"551\">service time<\/strong> based on the <strong data-start=\"569\" data-end=\"590\">system load<\/strong>.<\/p>\r\n<p data-start=\"593\" data-end=\"823\">In this example, three counters (<code data-start=\"628\" data-end=\"640\">Facility_1<\/code>, <code data-start=\"642\" data-end=\"654\">Facility_2<\/code>, <code data-start=\"656\" data-end=\"668\">Facility_3<\/code>) receive entity flows of different intensities. Each one is paired with a <code data-start=\"755\" data-end=\"763\">Queuer<\/code>, which lets you measure and record the current queue size.<\/p>\r\n<p data-start=\"825\" data-end=\"992\">Before being served, each entity calls a procedure that dynamically computes its <strong data-start=\"915\" data-end=\"937\">service time<\/strong>, based on the current queue size of the resource.<\/p>\r\n<p>The logic used here is one of the following:<\/p>\r\n<pre>\r\nassign queueSize,R$(P$counter,QUEUE) + 1\r\n    \r\nASSIGN serviceTime, round(max(2, 120 \/ P$queueSize))\r\nASSIGN serviceTime, round(max(2, 120 \/ sqrt(P$queueSize)))\r\nASSIGN serviceTime, round(120 \/ log(P$queueSize + 1))\r\n<\/pre>\r\n<p data-start=\"1096\" data-end=\"1115\">This means:<\/p>\r\n<ul data-start=\"1116\" data-end=\"1261\">\r\n    <li data-start=\"1116\" data-end=\"1182\">\r\n    <p data-start=\"1118\" data-end=\"1182\">With a larger queue, <strong data-start=\"1132\" data-end=\"1160\">service time becomes shorter<\/strong>, prioritizing throughput.<\/p>\r\n    <\/li>\r\n    <li data-start=\"1183\" data-end=\"1261\">\r\n    <p data-start=\"1185\" data-end=\"1261\">With a smaller queue, <strong data-start=\"1199\" data-end=\"1225\">more time is spent per entity<\/strong>, improving service quality.<\/p>\r\n    <\/li>\r\n<\/ul>\r\n<p data-start=\"1263\" data-end=\"1336\">It is an <strong data-start=\"1284\" data-end=\"1335\">automatic balancing strategy between quality and performance<\/strong>.<\/p>\r\n<p data-start=\"1338\" data-end=\"1361\">This technique demonstrates:<\/p>\r\n<ul data-start=\"1362\" data-end=\"1577\">\r\n    <li data-start=\"1362\" data-end=\"1422\">\r\n    <p data-start=\"1364\" data-end=\"1422\">How to couple a resource with its <code data-start=\"1396\" data-end=\"1404\">Queuer<\/code> to measure load.<\/p>\r\n    <\/li>\r\n    <li data-start=\"1423\" data-end=\"1499\">\r\n    <p data-start=\"1425\" data-end=\"1499\">How to use mathematical functions to adapt <code data-start=\"1489\" data-end=\"1498\">ADVANCE<\/code> durations.<\/p>\r\n    <\/li>\r\n    <li data-start=\"1500\" data-end=\"1577\">\r\n    <p data-start=\"1502\" data-end=\"1577\">How to keep queue size under control without sacrificing attention.<\/p>\r\n    <\/li>\r\n<\/ul>\r\n<p data-start=\"1579\" data-end=\"1623\">The example can easily be extended to:<\/p>\r\n<ul data-start=\"1624\" data-end=\"1753\">\r\n    <li data-start=\"1624\" data-end=\"1662\">\r\n    <p data-start=\"1626\" data-end=\"1662\">More complex service-time functions.<\/p>\r\n    <\/li>\r\n    <li data-start=\"1663\" data-end=\"1702\">\r\n    <p data-start=\"1665\" data-end=\"1702\">Decision-making about which counter to choose.<\/p>\r\n    <\/li>\r\n    <li data-start=\"1703\" data-end=\"1753\">\r\n    <p data-start=\"1705\" data-end=\"1753\">Global system performance optimization.<\/p>\r\n    <\/li>\r\n<\/ul>\r\n<p>&nbsp;<\/p>\r\n<p>&nbsp;<\/p>",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            },
            {
                "id": "177",
                "nombre": "Rerouting queues",
                "texto": "\/*\r\n\r\n Rerouting queues\r\n\r\n*\/\r\nFACILITY {NAME:COUNTER1,X:320,Y:450,capacity:3}\r\nFACILITY {NAME:COUNTER2,X:320,Y:300,capacity:1}\r\nFACILITY {NAME:COUNTER3,X:320,Y:150,capacity:2}\r\n\r\nPOSITION {NAME:POS1,X:152,Y:300}\r\nPOSITION {NAME:POS2,X:497,Y:300}\r\n\r\nGraphic {NAME:Text1,Type:TEXT,X:100,Y:100}\r\n\r\nSTART 200 \r\n;*************************************************************************\r\nGENERATE 6,0 {NAME:GEN1,X:54,Y:300}\r\nADVANCE 20,0 {TO:POS1,flow:1}\r\n\r\nCALL DECIDE.SELECT ; returns strings: \"PATH1\", \"PATH2\" or \"PATH3\", creating an ASSIGN named P$SELECT\r\nCALL P$SELECT\r\n\r\nADVANCE 20 {TO:POS2,flow:1,merge:\"path\"}\r\n\r\nENDGENERATE 1\r\n\r\n;*************************************************************************\r\nPROCEDURE DECIDE.SELECT\r\n\r\nassign myMap, [  \r\n{queue:\"PATH1\",inQueue: R$(COUNTER1,QUEUE)}, \r\n{queue:\"PATH2\",inQueue: R$(COUNTER2,QUEUE)},  \r\n{queue:\"PATH3\",inQueue: R$(COUNTER3,QUEUE)}\r\n]\r\n\r\nASSIGN MINKEY,\"PATH1\"; initialize selected KEY\r\nASSIGN MINVAL,100000 ; initialize the minimum value for comparisons\r\n\r\nFOREACH tmp,IN,V$myMap\r\n\r\n  IF (P$(tmp.inQueue) < P$MINVAL)\r\n    ASSIGN MINKEY,\"P$(tmp.queue)\" \r\n    ASSIGN MINVAL,P$(tmp.inQueue)\r\n    move {name:Text1,Text:\"Decision: P$(MINKEY) Queue: P$(MINVAL)\"}\r\n  ENDIF\r\nENDFOREACH\r\n\r\n\r\nENDPROCEDURE \"P$MINKEY\" ; will return, for example, \"PATH1\"\r\n\r\n;**************************************************************************\r\n\r\nPROCEDURE PATH1\r\nADVANCE 20  {TO:COUNTER1,flow:1,decision:\"path\"}\r\nSEIZE COUNTER1\r\nADVANCE 25,10\r\nRELEASE COUNTER1\r\nENDPROCEDURE\r\n\r\nPROCEDURE PATH2\r\nADVANCE 20 {TO:COUNTER2,flow:1,decision:\"path\"}\r\nSEIZE COUNTER2\r\nADVANCE 80,70\r\nRELEASE COUNTER2\r\nENDPROCEDURE\r\n\r\nPROCEDURE PATH3\r\nADVANCE 20 {TO:COUNTER3,flow:1,decision:\"path\"}\r\nSEIZE COUNTER3\r\nADVANCE 30,20\r\nRELEASE COUNTER3\r\nENDPROCEDURE\r\n\r\n;***************************************************************\r\n\r\n\r\n\r\n\r\n\r\n\r\n",
                "descripcion": "<p data-start=\"134\" data-end=\"508\">In this example, entities must decide which of three paths to take, each one associated with a counter that has its own queue (<code data-start=\"268\" data-end=\"278\">FACILITY<\/code> with different capacity). The decision is made in <code data-start=\"338\" data-end=\"357\">DECIDE.SELECT<\/code>, which iterates a list containing the path names and the current size of their queues (<code data-start=\"445\" data-end=\"452\">QUEUE<\/code>). The result is the name of the path with the least load.<\/p>\r\n<p data-start=\"510\" data-end=\"804\">That value is a <code data-start=\"526\" data-end=\"534\">STRING<\/code> returned with <code data-start=\"555\" data-end=\"569\">ENDPROCEDURE<\/code> and is automatically stored in the variable <code data-start=\"615\" data-end=\"629\">P$SELECT<\/code>, which is then used directly as a call: <code data-start=\"675\" data-end=\"694\">CALL P$SELECT<\/code>. This mechanism enables dynamic selection without conditionals or multiple explicit calls.<\/p>\r\n<p data-start=\"806\" data-end=\"918\" data-is-last-node=\"\" data-is-only-node=\"\">The <code data-start=\"711\" data-end=\"720\">.decide<\/code> structures are used to directly return the name of the procedure to execute, saving the programmer from having to write a <code data-start=\"850\" data-end=\"858\">SWITCH<\/code> or a cascade of <code data-start=\"876\" data-end=\"880\">IF<\/code>.<\/p>\r\n<p data-start=\"806\" data-end=\"918\" data-is-last-node=\"\" data-is-only-node=\"\">This greatly simplifies the decision logic, because simply:<\/p>\r\n<pre>\r\nCALL DECIDE.SELECT\r\nCALL P$SELECT\r\n<\/pre>\r\n<p data-start=\"806\" data-end=\"918\" data-is-last-node=\"\" data-is-only-node=\"\">replaces:<\/p>\r\n<pre>\r\nCALL DECIDE.SELECT\r\nSWITCH P$SELECT\r\n  CASE ==, \"PATH1\"\r\n    CALL PATH1\r\n  CASE ==, \"PATH2\"\r\n    CALL PATH2\r\n  ...\r\nENDSWITCH\r\n<\/pre>",
                "parametros": null,
                "parametros_json": "",
                "ejemplo": null,
                "hijos": []
            },
            {
                "id": "202",
                "nombre": "Updating the event queue: UPDATE",
                "texto": "\/*\r\n\r\n Updating the event queue: UPDATE\r\n\r\n*\/\r\nSYSTEM {TYPE:ON_TIMER, TRIGGER:TIMER1, INTERVAL: 100}\r\n\r\nQueuer {NAME:Queuer1,X:350,Y:324}\r\nGraphic {NAME:Text1,Type:TEXT,X:352,Y:381}\r\n\r\nPOSITION {NAME:POS1,X:90,Y:513}\r\nPOSITION {NAME:POS2,X:638,Y:512}\r\nPOSITION {NAME:POS3,X:635,Y:322}\r\n\r\nSTART 100\r\n\r\n;*********************************************************\r\nINITIAL defaultTime,100\r\nINITIAL conditions,1.0\r\n;*********************************************************\r\nPROCEDURE TIMER1\r\n\tsavevalue oldConditions,X$conditions\r\n\tsavevalue conditions,round(random + 0.5,2)\r\n    MOVE {NAME:Text1,TEXT:\"Old Conditions: X$oldConditions \\nNew conditions: X$conditions\"}\r\n    FOREACH number,IN_RESOURCE,Queuer1\r\n    \r\n    assign myConditions,X$conditions,P$number\r\n\r\n    ASSIGN from, D$(ADVANCESTART, P$number)\r\n    ASSIGN lapse, D$(ADVANCELAPSE, P$number)\r\n    \r\n    ASSIGN completedRatio , (AC1$ - P$from) \/ P$lapse\r\n\tASSIGN remainingRatio , 1 - P$completedRatio \r\n\r\n\tASSIGN adjustedRemainingTime , P$remainingRatio  * X$defaultTime * X$conditions\r\n\tASSIGN newTime, AC1$ + P$adjustedRemainingTime \r\n\r\n      if (X$conditions<1)\r\n     \t MOD {number:P$number,color:#00DD00}\r\n      else\r\n      \tMOD {number:P$number,color:#000000}\r\n      endif\r\n      if (P$newTime < AC1$)\r\n     \t assign newTime,AC1$\r\n      endif\r\n      Update P$number,P$newTime\r\n    ENDFOREACH\r\n\r\n    \r\n\r\n    TERMINATE_VE\r\nENDPROCEDURE\r\n;*********************************************************\r\n\r\n\r\nGENERATE 20,0 {NAME:GEN1,X:102,Y:203, ECOLOR:#FF3333, ERADIO:8,esubtitle:P$myConditions}\r\n    ADVANCE 16,5 {TO:POS1}\r\n    assign myTime,X$defaultTime * X$conditions\r\n    assign myConditions,X$conditions\r\n    Queue Queuer1\r\n    ADVANCE P$myTime,0 {TO:POS2}\r\n    Depart Queuer1\r\n    MOD {color:#FF3333}\r\n    ADVANCE 16,5 {TO:POS3}\r\nENDGENERATE 1\r\n\r\n\r\n\r\n\r\n\r\n",
                "descripcion": "<p>We previously saw the <code data-start=\"915\" data-end=\"924\">ADVANCE<\/code> block as something that seemed immutable. For example:<\/p>\r\n<pre>\r\nADVANCE 20,10\r\n<\/pre>\r\n<p><b>The role of <code data-start=\"871\" data-end=\"879\">UPDATE<\/code><\/b><\/p>\r\n<p data-start=\"881\" data-end=\"1154\">An entity that is inside an <code data-start=\"915\" data-end=\"924\">ADVANCE<\/code> cannot modify its own wake-up time, because it is inactive. Therefore, another entity (usually a <strong data-start=\"1049\" data-end=\"1068\">virtual entity<\/strong>, triggered by a <code data-start=\"1086\" data-end=\"1093\">TIMER<\/code> or a <code data-start=\"1099\" data-end=\"1105\">HOOK<\/code>) must execute <code data-start=\"1122\" data-end=\"1130\">UPDATE<\/code> to adjust its time.<\/p>\r\n<p>Technically, UPDATE does not modify an ADVANCE: it modifies the event queue.<br>\r\nIt removes the entity from its future activation and reschedules it at a new absolute time.<br>\r\nThe engine does not interpret the change: it only keeps the queue ordered.<\/p>\r\n<p>&nbsp;<\/p>\r\n<p><b>Scenario:<\/b> Changing conditions on a road segment<\/p>\r\n<p data-start=\"1216\" data-end=\"1316\">We simulate a road segment under conditions stored in the <code data-start=\"1291\" data-end=\"1302\">SAVEVALUE<\/code> <code data-start=\"1303\" data-end=\"1315\">conditions<\/code>.<\/p>\r\n<ul data-start=\"1318\" data-end=\"1678\">\r\n    <li data-start=\"1318\" data-end=\"1408\">\r\n    <p data-start=\"1320\" data-end=\"1408\">Under normal conditions (<code data-start=\"1345\" data-end=\"1363\">conditions = 1.0<\/code>), it takes 100 time units to cross.<\/p>\r\n    <\/li>\r\n    <li data-start=\"1409\" data-end=\"1474\">\r\n    <p data-start=\"1411\" data-end=\"1474\">If <code data-start=\"1414\" data-end=\"1432\">conditions = 1.5<\/code>, the trip takes 150 time units.<\/p>\r\n    <\/li>\r\n    <li data-start=\"1475\" data-end=\"1542\">\r\n    <p data-start=\"1477\" data-end=\"1542\">An entity computes its travel time when it enters the segment.<\/p>\r\n    <\/li>\r\n    <li data-start=\"1543\" data-end=\"1678\">\r\n    <p data-start=\"1545\" data-end=\"1678\">If conditions change while an entity is on the way, we want to <strong data-start=\"1618\" data-end=\"1650\">adjust its arrival time<\/strong> to reflect that change.<\/p>\r\n    <\/li>\r\n<\/ul>\r\n<p><b>How is it computed?<\/b><\/p>\r\n<p data-start=\"1707\" data-end=\"1965\">Imagine an entity entered when <code data-start=\"1744\" data-end=\"1762\">conditions = 1.2<\/code> (travel time = 120), but now conditions improve to <code data-start=\"1829\" data-end=\"1834\">1.0<\/code>. If it has already completed 50%, it would have 50 units left under the new conditions. In total, it would take 110 instead of 120.<\/p>\r\n<p><b>The <code data-start=\"1985\" data-end=\"1993\">UPDATE<\/code> command<\/b><\/p>\r\n<pre>\r\nUPDATE entityID, newTime\r\n<\/pre>\r\n<p>This command reschedules an entity with a new activation time, as long as that time is &ge; <code data-start=\"2142\" data-end=\"2148\">AC1$<\/code> (the current simulation time).<\/p>\r\n<p><b>What this example demonstrates:<\/b><\/p>\r\n<ul data-start=\"2221\" data-end=\"2537\">\r\n    <li data-start=\"2221\" data-end=\"2319\">\r\n    <p data-start=\"2223\" data-end=\"2319\">That an entity’s behavior <strong data-start=\"2262\" data-end=\"2318\">can be modified even while it is in progress<\/strong>.<\/p>\r\n    <\/li>\r\n    <li data-start=\"2320\" data-end=\"2415\">\r\n    <p data-start=\"2322\" data-end=\"2415\">That <code data-start=\"2326\" data-end=\"2352\">TIMER + FOREACH + UPDATE<\/code> is a powerful combination to react dynamically.<\/p>\r\n    <\/li>\r\n    <li data-start=\"2416\" data-end=\"2537\">\r\n    <p data-start=\"2418\" data-end=\"2537\">That it enables representing real-world scenarios where conditions change and the system must adapt.<\/p>\r\n    <\/li>\r\n<\/ul>\r\n<p>&nbsp;<\/p>",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            }
        ]
    },
    {
        "id": "249",
        "nombre": "Season 5: Graphics",
        "texto": "",
        "descripcion": "",
        "parametros": null,
        "parametros_json": null,
        "ejemplo": null,
        "hijos": [
            {
                "id": "272",
                "nombre": "Create and modify",
                "texto": "\/*\r\n\r\n Create and modify graphics\r\n\r\n*\/\r\nSYSTEM {TYPE:OPTIONS, SPEED:8, TIME_DECIMALS:1}\r\n\r\n;==============================\r\n; DYNAMIC VARIABLES\r\n;==============================\r\nINITIAL GRADO, 0\r\nINITIAL ALTURA, 80\r\nINITIAL ESCALA, 100\r\nINITIAL CRECIENDO, 1\r\n\r\n;==============================\r\n; GRAPHIC ELEMENTS\r\n;==============================\r\n\r\nGRAPHIC {NAME:txt, TYPE:TEXT, X:300, Y:50,text:\"--test--\"}\r\n\r\n\r\nGRAPHIC {NAME:radarGrupo, TYPE:GROUP, X:300, Y:400}\r\n\r\nGRAPHIC {\r\n  GROUP:radarGrupo,\r\n  NAME:radarTexto,\r\n  TYPE:TEXT,\r\n  TEXT:\"GRADO: X$GRADO\",\r\n  COLOR:#00AAFF,\r\n  X:0, Y:-50\r\n}\r\n\r\nGRAPHIC {\r\n  GROUP:radarGrupo,\r\n  NAME:radarImagen,\r\n  TYPE:IMAGE,\r\n  SRC:\"DOOR\",\r\n  X:100, Y:100,\r\n  OPACITY:0.9,\r\n  ROTATE:0\r\n}\r\n\r\nGRAPHIC {\r\n  GROUP:radarGrupo,\r\n  NAME:ondaVisual,\r\n  TYPE:CURVE,\r\n  POINTS:\"[0,0],[40,X$ALTURA],[80,0]\",\r\n  COLOR:red,\r\n  WIDTH:2,\r\n  OPACITY:0.6\r\n}\r\n\r\nGRAPHIC {\r\n  NAME:puerta,\r\n  TYPE:IMAGE,\r\n  SRC:\"DOOR\",\r\n  X:400, Y:100,\r\n  OPACITY:0.9,\r\n  ROTATE:0\r\n}\r\n\r\n\r\nGRAPHIC {\r\n  NAME:barreraCircular,\r\n  TYPE:ARC,\r\n  X:100, Y:400,\r\n  COLOR:#FFAA00,\r\n  RADIUS:60,\r\n  START_ANGLE:0,\r\n  END_ANGLE:X$GRADO,\r\n  OPACITY:1,\r\n  CLOSE:0\r\n}\r\n\r\n\r\n;==============================\r\n; MAIN ENTITY\r\n;==============================\r\nGENERATE 5, 0 {NAME:GEN1, X:50, Y:200}\r\n\r\n;move {name:txt,text:\"Pos X GD$(barreraCircular,X)\"}\r\n; Increase angle (rotation)\r\nSAVEVALUE GRADO, (X$GRADO + 15) % 360\r\n\r\n; Raise\/lower the wave\r\nIF ((X$GRADO % 180) < 90)\r\n  SAVEVALUE ALTURA, X$ALTURA + 4\r\nELSE\r\n  SAVEVALUE ALTURA, X$ALTURA - 4\r\nENDIF\r\n\r\n; Animate size\r\nIF (X$CRECIENDO == 1)\r\n  SAVEVALUE ESCALA, X$ESCALA + 5\r\n  IF (X$ESCALA >= 140)\r\n    SAVEVALUE CRECIENDO, 0\r\n  ENDIF\r\nELSE\r\n  SAVEVALUE ESCALA, X$ESCALA - 5\r\n  IF (X$ESCALA <= 100)\r\n    SAVEVALUE CRECIENDO, 1\r\n  ENDIF\r\nENDIF\r\n\r\nADVANCE 5, 0\r\n\r\n;==============================\r\n; VISUAL UPDATES\r\n;==============================\r\n\r\nMOVE {NAME:radarTexto, TEXT:\"Degree: X$GRADO\"}\r\nMOVE {NAME:radarImagen, ROTATE:X$GRADO}\r\nMOVE {NAME:radarImagen, RESIZE:X$ESCALA}\r\nMOVE {NAME:ondaVisual, Y2:X$ALTURA}\r\n\r\n\r\nMOVE {NAME:radarGrupo, Y:(GD$(radarGrupo,Y)+(RANDOM*10)-5)}\r\n\r\nMOVE {NAME:puerta, RESIZE_X:X$ESCALA * 2}\r\nMOVE {NAME:barreraCircular, END_ANGLE:X$GRADO}\r\n\r\n\r\nTERMINATE 1\r\n\r\nSTART 500\r\n",
                "descripcion": "<h3>Create and modify<\/h3>\r\n<p>GPSS-Plus lets you define graphic elements that can be moved, transformed, and updated during the simulation. These objects can be <b>texts, curves, images, arcs, or lines<\/b>, and they can be grouped to form complete visual units.<\/p>\r\n<p>Graphics can be moved individually or as a group, and you can modify properties such as:<\/p>\r\n<ul>\r\n    <li>Position (<code>X<\/code>, <code>Y<\/code>)<\/li>\r\n    <li>Rotation (<code>ROTATE<\/code>)<\/li>\r\n    <li>Size (<code>RESIZE<\/code>)<\/li>\r\n    <li>Opacity (<code>OPACITY<\/code>)<\/li>\r\n    <li>Text content (<code>TEXT<\/code>)<\/li>\r\n    <li>Color and angles, for shapes like <code>ARC<\/code> or <code>LINE<\/code><\/li>\r\n<\/ul>\r\n<p>The <code>MOVE<\/code> commands allow:<\/p>\r\n<ul>\r\n    <li>Absolute values, like <code>X:100<\/code><\/li>\r\n    <li>Relative values, reading the current value via <code>GD$<\/code>, for example: <code>X:GD$(object,X) + 10<\/code><\/li>\r\n<\/ul>\r\n<p>This example shows how an entity, across its steps, updates internal variables (<code>SAVEVALUE<\/code>) and uses those variables to refresh graphic objects on each advance.<\/p>\r\n<p>It illustrates the use of graphics of type <code>TEXT<\/code>, <code>CURVE3<\/code>, <code>CURVE<\/code>, <code>ARC<\/code>, <code>IMAGE<\/code>, and <code>GROUP<\/code>, as well as the combined use of relative animations, scaling, and rotation.<\/p>\r\n<h3>About curves and filling<\/h3>\r\n<p>GPSS-Plus supports two curve types:<\/p>\r\n<ul>\r\n    <li><b>CURVE3<\/b>: three-point curve (simple Bezier), declared with direct coordinates <code>X1<\/code>, <code>Y1<\/code>, <code>X2<\/code>, <code>Y2<\/code>, <code>X3<\/code>, <code>Y3<\/code><\/li>\r\n    <li><b>CURVE<\/b>: Catmull-Rom smoothed curve, defined with a list of points<\/li>\r\n<\/ul>\r\n<p>To declare points, there are two equivalent forms:<\/p>\r\n<ul>\r\n    <li><b>Compact syntax<\/b>: <code>POINTS:\"[x1,y1],[x2,y2],[x3,y3],...\"<\/code><\/li>\r\n    <li><b>Direct pair syntax<\/b>: <code>X1:1,Y1:2, X2:3,Y2:4, X3:5,Y3:6<\/code><\/li>\r\n<\/ul>\r\n<p>Curves, lines, or arcs can be <b>open or closed<\/b>. To render them as closed shapes with fill, you must set:<\/p>\r\n<ul>\r\n    <li><code>CLOSE:1<\/code><\/li>\r\n    <li><code>FCOLOR:<\/code> for the fill color<\/li>\r\n<\/ul>",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            },
            {
                "id": "273",
                "nombre": "Procedure-based modification",
                "texto": "\/*\r\n\r\n Graphics. Procedure-based modification\r\n \r\n*\/\r\nSYSTEM {TYPE:PRE_RUN,TRIGGER:PRE_RUN}\r\n\r\n\r\n;==============================\r\n; TANK CONFIGURATION\r\n;==============================\r\nINITIAL config, {deposito_coords:[0, 0, 20, 200],deposito_position:[180,180]} \r\n\r\n;==============================\r\n; GRAPHICS\r\n;==============================\r\nGRAPHIC {NAME:Deposito, TYPE:GROUP, X:0, Y:0}\r\n\r\n; Outer frame\r\nGRAPHIC {\r\n  NAME:Marco,\r\n  GROUP:Deposito,\r\n  TYPE:LINE,\r\n  POINTS:\"[0,0],[0,10],[10,10],[10,10]\",\r\n  COLOR:#555555,\r\n  CLOSE:1\r\n}\r\n\r\n; Inner level (fill)\r\nGRAPHIC {\r\n  NAME:Nivel,\r\n  GROUP:Deposito,\r\n  TYPE:LINE,\r\n  POINTS:\"[0,300],[0,300],[40,300],[40,300]\",\r\n  COLOR:#3399FF,\r\n  FCOLOR:#99CCFF,\r\n  CLOSE:1\r\n}\r\n\r\n; Percentage text\r\nGRAPHIC {\r\n  NAME:TextoNivel,\r\n  GROUP:Deposito,\r\n  TYPE:TEXT,\r\n  X:0, Y:0,\r\n  TEXT:\"Level: 0%\",\r\n  COLOR:#000000\r\n}\r\nSTART 100\r\n\r\n\r\nPROCEDURE PRE_RUN\r\n\ttimeout nivel_init,0\r\n\tTERMINATE \r\nENDPROCEDURE 1\r\n\r\n;==============================\r\n; UPDATE PROCEDURE\r\n;==============================\r\nPROCEDURE nivel_init\r\nmove {name:Marco\r\n\t,X1:X$(config.deposito_coords.0)-4,Y1:X$(config.deposito_coords.1)-4\r\n\t,X2:X$(config.deposito_coords.2)+4,Y2:X$(config.deposito_coords.1)-4\r\n\t,X3:X$(config.deposito_coords.2)+4,Y3:X$(config.deposito_coords.3)+4\r\n\t,X4:X$(config.deposito_coords.0)-4,Y4:X$(config.deposito_coords.3)+4\r\n\t}\r\n\r\nmove {name:Nivel\r\n\t,X1:X$(config.deposito_coords.0),Y1:X$(config.deposito_coords.1)\r\n\t,X2:X$(config.deposito_coords.2),Y2:X$(config.deposito_coords.1)\r\n\t,X3:X$(config.deposito_coords.2),Y3:X$(config.deposito_coords.3)\r\n\t,X4:X$(config.deposito_coords.0),Y4:X$(config.deposito_coords.3)\r\n\t}\r\n\r\nMOVE {NAME:TextoNivel\r\n\t\t, x:(GD$(Marco,X1) + GD$(Marco,X2))\/ 2\r\n\t\t, y:X$(config.deposito_coords.1)-14, TEXT:\"Level: PP$A%\"}\r\n\r\nMOVE {NAME:Deposito\r\n\t\t, x:X$(config.deposito_position.0)\r\n\t\t, y:X$(config.deposito_position.1)}   \r\nterminate\r\nendprocedure 1\r\n\r\n\r\nPROCEDURE deposito_set\r\n\r\n; PP$A = desired percentage (0 to 100)\r\n\r\nASSIGN yBase, X$(config.deposito_coords.1) ; bottom y\r\nASSIGN yTop, X$(config.deposito_coords.3)  ; top y\r\n\r\nASSIGN alturaMaxima, P$yBase - P$yTop\r\nASSIGN alturaNivel, P$alturaMaxima * P$PARAM_A \/ 100\r\nASSIGN yActual, P$yBase - P$alturaNivel\r\n\r\n; Move the level vertices\r\nMOVE {\r\n  NAME:Nivel,\r\n  Y3:P$yActual,\r\n  Y4:P$yActual\r\n}\r\nMOVE {NAME:TextoNivel,TEXT:\"Level: P$PARAM_A%\"}\r\n\r\nENDPROCEDURE 1\r\n\r\nPROCEDURE deposito_locate\r\n\r\nMOVE {NAME:Deposito\r\n\t\t, x:P$PARAM_A\r\n\t\t, y:P$PARAM_B}   \r\n        \r\nENDPROCEDURE 1\r\n\r\n;==============================\r\n; ENTITY THAT USES IT\r\n;==============================\r\nGENERATE 25,0 {NAME:Gen1}\r\n\r\nCALL deposito_set, 25\r\nADVANCE 5\r\n\r\nCALL deposito_set, 50\r\nADVANCE 5\r\n\r\nCALL deposito_set, 75\r\nADVANCE 5\r\n\r\nCALL deposito_set, 90\r\nADVANCE 5\r\n\r\nCALL deposito_set, 10\r\nADVANCE 5\r\nCALL deposito_locate, GD$(Deposito,X)+4,GD$(Deposito,Y)+4\r\n\r\nTERMINATE 1\r\n",
                "descripcion": "<p>Before introducing the <code>CX$<\/code> context system to instantiate reusable graphic components in <strong>independent libraries<\/strong>, it is important to understand how a visual component can be built <strong>manually<\/strong>, step by step, using procedures (<code>PROCEDURE<\/code>) and configuration structures (<code>INITIAL<\/code>).<\/p>\r\n<p>This example <strong>does not represent the optimal or recommended way<\/strong> to implement reusable graphic components, but it plays an essential role in learning:<\/p>\r\n<ul>\r\n    <li>It helps you understand how grouped graphics are declared (<code>GROUP<\/code>).<\/li>\r\n    <li>It shows how to parameterize geometry and position using dictionaries (<code>INITIAL<\/code>).<\/li>\r\n    <li>It teaches how to encapsulate visual transformations inside procedures.<\/li>\r\n    <li>It introduces calling “visual functions” from entities using <code>CALL<\/code>.<\/li>\r\n<\/ul>\r\n<p>This approach will later be replaced by using <code>CX$<\/code> contexts, but it’s worth mastering this “manual” level first to understand in depth how GPSS-Plus turns procedures into autonomous, reusable visual components.<\/p>\r\n<p>In this example, we render a <strong>tank with a visual level<\/strong>, made of a <code>GROUP<\/code> that contains:<\/p>\r\n<ul>\r\n    <li>an outer frame (closed <code>LINE<\/code>)<\/li>\r\n    <li>a fill level (closed <code>LINE<\/code>, with variable height)<\/li>\r\n    <li>a text showing the visible fill percentage<\/li>\r\n<\/ul>\r\n<p>All the tank’s geometry and position are defined via a configuration structure (<code>config<\/code>) and applied directly to graphics with fixed names. Although this simulates a form of parameterization, it is <strong>not reusable<\/strong> as-is: the graphic object names are hard-coded, which prevents instantiating multiple tanks without conflicts.<\/p>\r\n<p>This limitation will be solved later with <strong><code>CX$<\/code> contexts and libraries<\/strong>, which will allow creating multiple visual instances of the same component, each with its own state and configuration.<\/p>\r\n<p>The <code>nivel_init<\/code> procedure generates the graphic vertices at startup (<code>PRE_RUN<\/code>), and <code>deposito_set<\/code> visually updates the fill level based on a percentage (<code>P$PARAM_A<\/code>).<\/p>\r\n<p><code>deposito_locate<\/code> is also included, allowing you to move the whole group to a new position.<\/p>",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            },
            {
                "id": "194",
                "nombre": "Example: Animated analog clock",
                "texto": "\/*\r\n\r\n Graphics. Animated analog clock\r\n \r\n*\/\r\nSYSTEM {type:OPTIONS, TIME_DECIMALS:0, SPEED:7}   \r\nSYSTEM {TYPE:PRE_RUN,TRIGGER:PRE_RUN}\r\nSYSTEM {TYPE:ON_TIMER, TRIGGER:TIMER1, INTERVAL: 10}\r\n\r\n\r\n; ANALOG CLOCK\r\nGRAPHIC {NAME:OUT,TYPE:ARC,X:0,Y:0,COLOR:#FFFF99,RADIUS:200,START_ANGLE:0,END_ANGLE:360,CLOSE:0}\r\nGRAPHIC {NAME:AT12,TYPE:TEXT,X:300,Y:500,TEXT:\"12\"}\r\nGRAPHIC {NAME:AT3,TYPE:TEXT,X:500,Y:300,TEXT:\"3\"}\r\nGRAPHIC {NAME:AT6,TYPE:TEXT,X:300,Y:100,TEXT:\"6\"}\r\nGRAPHIC {NAME:AT9,TYPE:TEXT,X:100,Y:300,TEXT:\"9\"}\r\n\r\nGRAPHIC {NAME:MINLINE,TYPE:LINE,COLOR:#F00,X1:268,Y1:361,X2:265,Y2:332}\r\nGRAPHIC {NAME:HOURLINE,TYPE:LINE,COLOR:#000,X1:240,Y1:361,X2:233,Y2:328}\r\n; DIGITAL CLOCK\r\nGRAPHIC {NAME:TIME,TYPE:TEXT,X:300,Y:536,TEXT:\"IT'S.. \",FONT:\"26PX\"}\r\nGRAPHIC {NAME:REALTIME1,TYPE:TEXT,X:575,Y:536,TEXT:\"REALTIME.. \",FONT:\"14PX\"}\r\nGRAPHIC {NAME:REALTIME2,TYPE:TEXT,X:575,Y:516,TEXT:\"REALTIME.. \",FONT:\"14PX\"}\r\n\r\nSTART 1\r\n\r\n; THE CLOCK\r\n\r\nGENERATE 100,0 {NAME:GEN1,VISIBLE:0,EVISIBLE:0,X:647,Y:99}\r\n\r\nTERMINATE 0\r\n\r\n\r\nPROCEDURE PRE_RUN\r\n\tSAVEVALUE MIN,0\r\n    SAVEVALUE A,0\r\n    SAVEVALUE B,0\r\n    SAVEVALUE CENTROX,300\r\n    SAVEVALUE CENTROY,300\r\n    SAVEVALUE RADIOM,180\r\n    SAVEVALUE RADIOH,120\r\n    MOVE {NAME:OUT,X:X$CENTROX,Y:X$CENTROY}\r\n    MOVE {NAME:MINLINE,x1:0,y1:0,x2:0,y2:0}\r\n\tMOVE {NAME:HOURLINE,x1:0,y1:0,x2:0,y2:0}\r\n\tTERMINATE_VE \r\nENDPROCEDURE \r\n\r\nPROCEDURE TIMER1\r\n\r\n\tassign sys,SYS$\r\n    \r\n    ASSIGN sys, SYS$\r\n  \tMOVE {name: REALTIME1, text:\"P$(sys.date.year)\/P$(sys.date.month)\/P$(sys.date.day)\"}\r\n  \tMOVE {name: REALTIME2, text:\"P$(sys.date.hour):P$(sys.date.min):P$(sys.date.sec)\"}\r\n  \r\n\r\n\tMOVE {NAME:TIME,TEXT:\"[X$HOR:X$MIN2]\"}\r\n    MOVE {NAME:MINLINE\r\n    \t\t,X1: (X$CENTROX)\r\n    \t\t,Y1:(X$CENTROY)\r\n            ,X2:(X$CENTROX+SIN(X$A)*X$RADIOM)\r\n            ,Y2:(X$CENTROY+COS(X$A)*X$RADIOM)}\r\n    MOVE {NAME:HOURLINE\r\n    \t\t,X1:(X$CENTROX)\r\n    \t\t,Y1:(X$CENTROY)\r\n            ,X2:(X$CENTROX+SIN(X$B)*X$RADIOH)\r\n            ,Y2:(X$CENTROY+COS(X$B)*X$RADIOH)}\r\n\r\n    SAVEVALUE MIN, (X$MIN+1)\r\n    SAVEVALUE MIN2,(X$MIN %60)\r\n    SAVEVALUE HOR, (FLOOR(X$MIN\/60))\r\n    SAVEVALUE A, (MODULO(X$MIN,60) *2*PI)\/60\r\n    SAVEVALUE B, (MODULO(X$MIN,720) *2*PI)\/720\r\n\tTERMINATE_VE \r\nENDPROCEDURE\r\n",
                "descripcion": "<p>This example renders a traditional analog clock using graphic primitives. A <code>PROCEDURE<\/code> initializes the scene with a background arc, hour markers (<code>TEXT<\/code>), and the two hands (<code>LINE<\/code>). A virtual entity (<code>TIMER<\/code>) is generated periodically and updates the hand positions using trigonometry and time variables (<code>SAVEVALUE<\/code>).<\/p>\r\n<p>It combines:<\/p>\r\n<ul>\r\n    <li><code>ARC<\/code> for the main circle.<\/li>\r\n    <li><code>TEXT<\/code> for the numbers and the digital clock.<\/li>\r\n    <li><code>LINE<\/code> to represent the hands.<\/li>\r\n<\/ul>\r\n<p>This is a clear case where <strong>the animation does not come from moving entities<\/strong>, but from <strong>programmed visual transformations<\/strong>.<\/p>\r\n<p>You can observe playback speed: with a value around <code>SPEED: 5<\/code>, <code>AC1<\/code> would roughly match the second hand.<\/p>",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            },
            {
                "id": "327",
                "nombre": "In 3D",
                "texto": "\/*\r\n\r\n Graphics. 3D\r\n \r\n*\/\r\nSYSTEM {TYPE:PRE_RUN, TRIGGER:PRE_RUN}\r\nSYSTEM {TYPE:VISUAL, MODE:3D, V_WIDTH:40, V_HEIGHT:20, CAMERA:0}\r\nSYSTEM {TYPE:OPTIONS, TIME_DECIMALS:1, SPEED:5}\r\n\r\nGRAPHIC {NAME:floor, TYPE:PLANE, X:25, POINTS:\"[0,0,0],[0,0,40],[40,0,0]\", color:#fabada}\r\n\r\nGRAPHIC {NAME:nut, TYPE:OBJECT, src:NUT, X:0, Y:0, Z:0,WIDTH:20, HEIGHT:20, DEPTH:20,rotate_x:90,opacity:0.9}\r\n\r\nGraphic {NAME:axis1,Type:LINE,X1:0,Y1:0,X2:0,Y2:500}\r\nGraphic {NAME:axis2,Type:LINE,X1:0,Y1:0,X2:500,Y2:0}\r\nGraphic {NAME:axis3,Type:LINE,X1:0,Y1:0,X2:0,Y2:0,Z2:500}\r\n\r\n\r\nGraphic {NAME:line4,Type:LINE,POINTS:\"[10,0,10],[150,150,150]\",color:red}\r\nGraphic {NAME:Text1,Type:TEXT,X:20,Y:20,text:\"sss\",font:\"2px\"}\r\n\r\n\r\n\r\nSTART 1\r\n;===========================\r\n; PROCEDURES\r\n;===========================\r\n\r\nPROCEDURE agent.init\r\n\r\nsavevalue DT,0.1\r\nsavevalue speed,1\r\nsavevalue X,4\r\nsavevalue state,0\r\n\r\n  WHILE (1==1)\r\n\r\n\tif (X$state==0)\r\n    savevalue X,X$X + X$DT * X$speed\r\n\telse \r\n    savevalue X,X$X - X$DT * X$speed\r\n\tendif\r\n    \r\n    if (X$X>10)\r\n    savevalue state,1\r\n    endif\r\n    if (X$X<4)\r\n    savevalue state,0\r\n    endif\r\n   \r\n    assign height, round(X$X,3)\r\n\tmove {name:Text1,text:\"Height: P$height\"}\r\n    ; The nut is positioned and rotated around its axis\r\n    MOVE {name:nut, MOVE_BETWEEN:\"[10,0,10],[150,150,150]\", rotate_y:P$height * 60,y:P$height}\r\n\r\n    ADVANCE 1, 0\r\n\r\n  ENDWHILE\r\n\r\nSTOP\r\nENDPROCEDURE\r\n;===========================\r\nPROCEDURE PRE_RUN\r\n\r\n  TIMEOUT agent.init, 0\r\n\r\n  TERMINATE_VE\r\n\r\nENDPROCEDURE\r\n",
                "descripcion": "<p>Although everything can be represented in 2D, in some simulations—especially mechanical ones or those with a strong visual focus—it may be desirable to use 3D representations.<\/p>\r\n<p>GPSS-Plus is not intended to be a 3D modeling tool; the focus is on enabling visually effective simulations that are easy to implement. Therefore, 3D content can come from two sources:<\/p>\r\n<ul>\r\n    <li>External <code>.GLB<\/code> files<\/li>\r\n    <li>Built-in geometric primitives<\/li>\r\n<\/ul>\r\n<p>&nbsp;<\/p>\r\n<h4>Available 3D primitives<\/h4>\r\n<div class=\"_tableContainer_80l1q_1\">\r\n<div tabindex=\"-1\" class=\"_tableWrapper_80l1q_14 group flex w-fit flex-col-reverse\">\r\n<table class=\"w-fit min-w-(--thread-content-width)\">\r\n    <thead>\r\n        <tr>\r\n            <th data-col-size=\"sm\">Type<\/th>\r\n            <th data-col-size=\"md\">Description<\/th>\r\n        <\/tr>\r\n    <\/thead>\r\n    <tbody>\r\n        <tr>\r\n            <td data-col-size=\"sm\"><code>BOX<\/code><\/td>\r\n            <td data-col-size=\"md\">3D box with <code>WIDTH<\/code>, <code>HEIGHT<\/code>, <code>DEPTH<\/code><\/td>\r\n        <\/tr>\r\n        <tr>\r\n            <td data-col-size=\"sm\"><code>SPHERE<\/code><\/td>\r\n            <td data-col-size=\"md\">Sphere with <code>RADIUS<\/code> and optional <code>SEGMENTS<\/code><\/td>\r\n        <\/tr>\r\n        <tr>\r\n            <td data-col-size=\"sm\"><code>TRIANGLE<\/code><\/td>\r\n            <td data-col-size=\"md\">Triangle<\/td>\r\n        <\/tr>\r\n        <tr>\r\n            <td data-col-size=\"sm\"><code>PLANE<\/code><\/td>\r\n            <td data-col-size=\"md\">Plane made of two triangles sharing an edge<\/td>\r\n        <\/tr>\r\n        <tr>\r\n            <td data-col-size=\"sm\"><code>PRISM<\/code><\/td>\r\n            <td data-col-size=\"md\">Regular prism between two points, with <code>SIDES<\/code> sides<\/td>\r\n        <\/tr>\r\n        <tr>\r\n            <td data-col-size=\"sm\"><code>OBJECT<\/code><\/td>\r\n            <td data-col-size=\"md\">External object in <code>.GLB<\/code> format<\/td>\r\n        <\/tr>\r\n    <\/tbody>\r\n<\/table>\r\n<\/div>\r\n<\/div>\r\n<p>&nbsp;<\/p>\r\n<h4>Permanent transforms (at creation time)<\/h4>\r\n<div class=\"_tableContainer_80l1q_1\">\r\n<div tabindex=\"-1\" class=\"_tableWrapper_80l1q_14 group flex w-fit flex-col-reverse\">\r\n<table class=\"w-fit min-w-(--thread-content-width)\">\r\n    <thead>\r\n        <tr>\r\n            <th data-col-size=\"sm\">Property<\/th>\r\n            <th data-col-size=\"sm\">Applies<\/th>\r\n            <th data-col-size=\"md\">Description<\/th>\r\n        <\/tr>\r\n    <\/thead>\r\n    <tbody>\r\n        <tr>\r\n            <td data-col-size=\"sm\"><code>WIDTH<\/code>, <code>HEIGHT<\/code>, <code>DEPTH<\/code><\/td>\r\n            <td data-col-size=\"sm\">Permanent<\/td>\r\n            <td data-col-size=\"md\">Resizes the base geometry<\/td>\r\n        <\/tr>\r\n        <tr>\r\n            <td data-col-size=\"sm\"><code>displace_x\/y\/z<\/code><\/td>\r\n            <td data-col-size=\"sm\">Permanent<\/td>\r\n            <td data-col-size=\"md\">Offsets the model relative to its internal pivot<\/td>\r\n        <\/tr>\r\n        <tr>\r\n            <td data-col-size=\"sm\"><code>rotate_x\/y\/z<\/code><\/td>\r\n            <td data-col-size=\"sm\">Permanent<\/td>\r\n            <td data-col-size=\"md\">Rotates the model around its internal pivot<\/td>\r\n        <\/tr>\r\n    <\/tbody>\r\n<\/table>\r\n<\/div>\r\n<\/div>\r\n<h4>Dynamic transforms (in MOVE)<\/h4>\r\n<div class=\"_tableContainer_80l1q_1\">\r\n<div tabindex=\"-1\" class=\"_tableWrapper_80l1q_14 group flex w-fit flex-col-reverse\">\r\n<table class=\"w-fit min-w-(--thread-content-width)\">\r\n    <thead>\r\n        <tr>\r\n            <th data-col-size=\"sm\">Action<\/th>\r\n            <th data-col-size=\"md\">Description<\/th>\r\n        <\/tr>\r\n    <\/thead>\r\n    <tbody>\r\n        <tr>\r\n            <td data-col-size=\"sm\"><code>MOVE_BETWEEN<\/code><\/td>\r\n            <td data-col-size=\"md\">Positions the object between two points while keeping its size<\/td>\r\n        <\/tr>\r\n        <tr>\r\n            <td data-col-size=\"sm\"><code>STRETCH_BETWEEN<\/code><\/td>\r\n            <td data-col-size=\"md\">Scales the object in Y to fit between two points<\/td>\r\n        <\/tr>\r\n        <tr>\r\n            <td data-col-size=\"sm\"><code>rotate_y<\/code><\/td>\r\n            <td data-col-size=\"md\">Adds extra rotation around its Y axis, useful for screws or gears<\/td>\r\n        <\/tr>\r\n        <tr>\r\n            <td data-col-size=\"sm\"><code>y<\/code><\/td>\r\n            <td data-col-size=\"md\">With <code>MOVE_BETWEEN<\/code>, allows sliding along the line<\/td>\r\n        <\/tr>\r\n    <\/tbody>\r\n<\/table>\r\n<\/div>\r\n<\/div>\r\n<p><i>These actions are analogous to <strong>PRISMATIC<\/strong> and <strong>REVOLUTE<\/strong> joints in mechanical systems, but applied directly from the mathematical knowledge of the object's position.<\/i><\/p>\r\n<p><b>Examples<\/b><\/p>\r\n<pre>\r\n; Places a spring described in a file between two defined points\r\nMOVE {name:spring, STRETCH_BETWEEN:\"[0,0,0],[0,P$x_mass,0]\"}\r\n\r\n; Places a piston or telescopic segment along a segment at position \"X\" relative to its center point\r\nMOVE {name:shock_absorber, MOVE_BETWEEN:\"[0,0,0],[0,P$x_mass,0]\",y:P$x_mass -10}\r\n<\/pre>\r\n<p><b>Enable 3D mode<\/b><\/p>\r\n<pre>\r\nSYSTEM {TYPE:VISUAL, MODE:3D, V_WIDTH:70, V_HEIGHT:30, CAMERA:1}\r\n<\/pre>\r\n<p><code>V_WIDTH<\/code>, <code>V_HEIGHT<\/code>: area the objects will occupy in internal units<br>\r\n<code>CAMERA<\/code>: camera preset (1 = isometric, 2 = top-down, etc.)<\/p>\r\n<p><b>The example<\/b><\/p>\r\n<p>In this example, two points are used to rotate a nut around that same axis.<\/p>",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            }
        ]
    },
    {
        "id": "252",
        "nombre": "Season 6: Agents and Components",
        "texto": "",
        "descripcion": "",
        "parametros": null,
        "parametros_json": null,
        "ejemplo": null,
        "hijos": [
            {
                "id": "247",
                "nombre": "Persistent virtual entity. The agent",
                "texto": "\/*\r\n\r\n Persistent virtual entity. The agent\r\n \r\n*\/\r\nSYSTEM {TYPE:PRE_RUN,TRIGGER:PRE_RUN}\r\nSTART 100\r\n\r\n\r\n;===> Resource and position setup\r\nRestroom {NAME:Restroom1, X:337, Y:344}\r\nRestroom {NAME:Restroom2, X:337, Y:258}\r\nRestroom {NAME:Restroom_AGENT2, X:567, Y:104}\r\n\r\nPOSITION {NAME:ENTRY, X:179, Y:301}\r\nPOSITION {NAME:EXIT, X:559, Y:299}\r\n\r\nGRAPHIC {NAME:INFO1, TYPE:TEXT, X:335, Y:178, TEXT:\"Agent1\"}\r\nGRAPHIC {NAME:INFO2, TYPE:TEXT, X:569, Y:62, TEXT:\"Agent2\"}\r\nINITIAL counter,0\r\n\r\n\r\n\r\n;*****************************************************\r\n;===> Agent initialization\r\nPROCEDURE PRE_RUN\r\n\ttimeout agent1.main,0\r\n\ttimeout agent2.main,0\r\n\tTERMINATE_VE \r\nENDPROCEDURE\r\n\r\n;*****************************************************\r\n;===> Main flow of entities\r\nGENERATE 15,5 {NAME:GEN1, X:50, Y:300}\r\nADVANCE 10 {TO:ENTRY}\r\n\r\nASSIGN randomChoice, FLOOR(RANDOM * 2) + 1\r\nIF (P$randomChoice==1)\r\n\tMOD {color:#990000}\r\n    ADVANCE 10 {TO:Restroom1}\r\n    REST Restroom1\r\nELSE\r\n    MOD {color:#999900}\r\n    ADVANCE 10 {TO:Restroom2}\r\n    REST Restroom2\r\nENDIF\r\n\r\n\r\n\r\nADVANCE 30,30 {TO:EXIT}\r\n\r\nif (D$N %20 == 0)\r\n\tSIGNAL agent2.full_release,X$nAgent2\r\nendif\r\n\r\nENDGENERATE 1\r\n\r\n;*******************************\r\nprocedure agent2.main\r\n    ; Save its unique id as a variable if needed\r\n    SAVEVALUE nAgent2,D$N\r\n    MOVE {NAME:INFO2, TEXT:\"Agent 1 active\"}\r\n\r\n    WHILE (1==1) ; useless if RETURN_RESTORE is always used\r\n        REST Restroom_AGENT2\r\n    ENDWHILE\r\n\r\n    TERMINATE_VE ; Will never be reached\r\nENDPROCEDURE\r\n\r\n;*******************************\r\nprocedure agent2.full_release\r\n    MOVE {NAME:INFO2, TEXT:\"T= AC1$ Agent 2 releasing everything\"}\r\n\tWAKE Restroom1\r\n\tWAKE Restroom2\r\n\tRETURN_RESTORE\r\nENDPROCEDURE\r\n\r\n;**********************************\r\n\r\n\r\nPROCEDURE agent1.main\r\n    ; Save its unique id as a variable if needed\r\n    SAVEVALUE nAgent1,D$N\r\n    MOVE {NAME:INFO1, TEXT:\"Agent 2 active\"}\r\n\r\n    WHILE (1==1)\r\n        ADVANCE 50 ; The agent checks every 50 units\r\n\r\n        SAVEVALUE counter, X$counter + 1\r\n        MOVE {NAME:INFO1, TEXT:\"Agent: X$counter\"}\r\n\r\n        IF (X$counter % 3==0)\r\n        \tassign toRelease,R$(Restroom1,IN)\r\n            MOVE {NAME:INFO1, TEXT:\"Releasing Restroom 1 (P$toRelease OF R$(Restroom1,IN))\"}\r\n            WAKE Restroom1\r\n        ENDIF\r\n\r\n        IF (X$counter % 5 ==0)\r\n        \tassign toRelease,round(R$(Restroom2,IN) * 2 \/ 3)\r\n            MOVE {NAME:INFO1, TEXT:\"Releasing Restroom 2 (P$toRelease OF R$(Restroom2,IN))\"}\r\n            WAKE Restroom2,P$toRelease\r\n            \r\n        ENDIF\r\n\r\n    ENDWHILE\r\n\r\n    TERMINATE_VE ; Will never be reached\r\nENDPROCEDURE\r\n;**********************************\r\n",
                "descripcion": "<p>In GPSS-Plus, a <strong>virtual entity (VE)<\/strong> is usually short-lived: it is created, executes a sequence of blocks, and ends. However, some models require <strong>permanent<\/strong> processes that can act as <em>controllers<\/em>, <em>managers<\/em>, or <em>passive processes<\/em> that wait for orders. We call these special VEs <strong>agents<\/strong>.<\/p>\r\n<h3>What an agent is<\/h3>\r\n<p>An <strong>agent<\/strong> is simply a virtual entity that never finishes its execution. To do this, it is initialized with the <code>TIMEOUT<\/code> block (outside of <code>GENERATE<\/code> blocks), which makes it start without depending on any arrival stream.<\/p>\r\n<p>Once created, an agent can behave in two main ways:<\/p>\r\n<ol>\r\n    <li><p><strong>Active<\/strong>: it runs cycles continuously (for example, using <code>ADVANCE<\/code>) to check and make decisions. Like a TIMER that is always the same entity.<\/p><\/li>\r\n    <li><p><strong>Passive<\/strong>: it waits using <code>HOLD<\/code> and stays there until it is ordered to do something else.<\/p><\/li>\r\n<\/ol>\r\n<h3>How it is created<\/h3>\r\n<p>In <code>PRE_RUN<\/code> we call its initializer <code>PROCEDURE<\/code>:<\/p>\r\n<pre>\r\ntimeout agent1.main,0 ; Will execute at time 0.\r\n<\/pre>\r\n<p>By convention, it is named <code>.main<\/code>.<\/p>\r\n<p>This <code>PROCEDURE<\/code> stores its identifier in a SAVEVALUE so that any entity can access it, and then enters an infinite loop with active or passive waiting:<\/p>\r\n<pre>\r\nPROCEDURE agent1.main\r\n    SAVEVALUE nAgent1,D$N\r\n    WHILE (1==1)\r\n    ADVANCE 100\r\n    ... ; Periodic actions\r\n    ENDWHILE\r\n    TERMINATE_VE ; Will never be reached\r\nENDPROCEDURE\r\n\r\n;----------------------------------------\r\n\r\nPROCEDURE agent2.main\r\n    SAVEVALUE nAgent2,D$N\r\n    HOLD HOLDER_AGENTS\r\n    TERMINATE_VE ; Will never be reached\r\nENDPROCEDURE\r\n<\/pre>\r\n<p>Its associated methods (PROCEDUREs) follow the convention <code>agent.method<\/code>, for example:<\/p>\r\n<pre>\r\nprocedure agent2.full_release\r\n    MOVE {NAME:INFO2, TEXT:\"T= AC1$ Agent 2 releasing everything\"}\r\n    UNHOLD HOLDER1\r\n    UNHOLD HOLDER2\r\n    RETURN_RESTORE ; Returns exactly to the previous state\r\nENDPROCEDURE\r\n<\/pre>\r\n<p>The most important part to highlight is its special termination: <code><b>RETURN_RESTORE<\/b><\/code>.<\/p>\r\n<p>This block returns the agent to the exact situation it was in when it was interrupted via <code>SIGNAL<\/code>\/<code>SIGNALNOW<\/code>.<br>\r\nIf it was in an <code>ADVANCE<\/code>, it resumes with the remaining time properly adjusted.<br>\r\nIf it was waiting in a resource queue, its situation is not altered.<\/p>\r\n<p>Note that if <code>RETURN<\/code> or <code>ENDPROCEDURE<\/code> were used, execution would continue to the next line of code. That can be useful if the agent is using active waiting and you want to restart its periodic action timer.<\/p>\r\n<p><b>In the example:<\/b><\/p>\r\n<p>We see two agents of both types releasing entities from two HOLDERS in arbitrary ways.<br>\r\nThe second one, every 20 entities that complete the route, releases all those trapped.<\/p>",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            },
            {
                "id": "312",
                "nombre": "Agent as a controller",
                "texto": "\/*\r\n\r\n  \tAgent as a controller\r\n \r\n*\/\r\nSYSTEM {TYPE:PRE_RUN,TRIGGER:PRE_RUN}\r\n\r\nQueuer {NAME:sensor,X:403,Y:575}\r\n\r\nPOSITION {NAME:POS1,X:265,Y:454}\r\nPOSITION {NAME:POS2,X:523,Y:449}\r\nPOSITION {NAME:POS3,X:720,Y:450}\r\n\r\nGraphic {NAME:Line1,Type:LINE,color:#FF0000, X1:418,Y1:370,X2:413,Y2:383,X3:387,Y3:383,X4:381,Y4:370}\r\nGraphic {NAME:Line2,Type:LINE,color:#FF0000, X1:422,Y1:509,X2:414,Y2:486,X3:387,Y3:486,X4:382,Y4:508}\r\n\r\nGraphic {NAME:Text1,Type:TEXT,X:431,Y:262,Text:\" \"}\r\n\r\ninitial nAgent,0\r\nSTART 200\r\n\r\n;*****************************************************\r\n\r\nPROCEDURE PRE_RUN\r\n\ttimeout agent.main,0\r\n\tTERMINATE_VE\r\nENDPROCEDURE 1\r\n\r\n;*****************************************************\r\nGENERATE 30,50 {NAME:GEN1,X:86,Y:450}\r\n\r\n\tADVANCE 20,0 {TO:POS1}\r\n\tqueue sensor\r\n\tADVANCE 20,0 {TO:POS2}\r\n\tdepart sensor\r\n\tADVANCE 20,0 {TO:POS3}\r\n\r\nENDGENERATE 1\r\n\r\n\r\n;*******************************\r\nprocedure agent.main\r\n\tsavevalue nAgent,D$N\r\n    assign users,0\r\n    assign state,100\r\n    assign posY2,GD$(Line1,Y2)\r\n    while (1==1)\r\n    \tadvance 1\r\n        call agent.moveDoor\r\n    endwhile\r\n    terminate_ve\r\nendprocedure\r\n\r\n\r\nprocedure agent.moveDoor\r\n    IF (R$(sensor,IN)<=0)\r\n    assign state,P$state + 5\r\n    assign state,MIN(100,P$state)\r\n    else \r\n    assign state,P$state -5\r\n    assign state,MAX(10,P$state)\r\n    ENDIF\r\n\r\nmove {name:Line1,Y2:P$state + P$posY2,Y3:P$state + P$posY2}\r\n;move {name:Text1,TEXT:\"p$users P$state | P$posY1\"}\r\n\r\nendprocedure\r\n",
                "descripcion": "<p>In this chapter we explore how an agent can act as an <strong>autonomous visual controller<\/strong> that reacts to changes in its environment and produces animated effects. We will see a typical example: an <strong>automatic door<\/strong> that opens when it detects entities nearby and closes when nobody is around.<\/p>\r\n<p><b>Core idea<\/b><\/p>\r\n<p>The agent is a VE that <strong>never ends<\/strong> and repeatedly executes one task: check whether there are entities in a given area (simulated with a <code>QUEUER<\/code>) and move the door accordingly.<\/p>\r\n<p>This kind of logic is ideal for animated behaviors, sensors, traffic lights, or any visual object that acts based on its surroundings.<\/p>",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            },
            {
                "id": "250",
                "nombre": "SIGNAL vs SIGNALNOW",
                "texto": "\/*\r\n\r\n  \tSIGNAL vs SIGNALNOW\r\n \r\n*\/\r\nSYSTEM {TYPE:PRE_RUN,TRIGGER:PRE_RUN}\r\n\r\nRestroom {NAME:RestroomAgents,X:252,Y:60,visible:1}\r\n\r\nPOSITION {NAME:POS1,X:552,Y:194}\r\nPOSITION {NAME:POS2,X:552,Y:394}\r\n\r\nGraphic {NAME:Text1,Type:TEXT,X:313,Y:252,Text:\"Entity\"}\r\nGraphic {NAME:Text2,Type:TEXT,X:313,Y:232,Text:\"Entity\"}\r\nGraphic {NAME:Text3,Type:TEXT,X:326,Y:444,Text:\"Entity\"}\r\nGraphic {NAME:TextAgent,Type:TEXT,X:311,Y:325,Text:\"---\",color:#ff3333}\r\n\r\ninitial nAgent,0\r\nSTART 2\r\n\r\n;*****************************************************\r\n\r\nPROCEDURE PRE_RUN\r\n\ttimeout agent.main,0\r\n\tTERMINATE_VE\r\nENDPROCEDURE 1\r\n\r\n;*****************************************************\r\nGENERATE 10,0,0,1 {NAME:GEN1,X:100,Y:200}\r\n\t\r\n    assign result,0,X$nAgent\r\n\tSIGNAL agent.add2,X$nAgent\r\n\tSIGNAL agent.multiply10,X$nAgent\r\n\tSIGNAL agent.add4,X$nAgent\r\n\tmove {name:Text1,TEXT:\"SIGNAL Before: P$(result,X$nAgent)\"}\r\n    advance 0\r\n\tmove {name:Text2,TEXT:\"SIGNAL Result: P$(result,X$nAgent)\"}\r\n\t\r\n\tADVANCE 20,0 {TO:POS1}\r\n    \r\nENDGENERATE 1\r\n\r\nGENERATE 60,0,0,1 {NAME:GEN2,X:100,Y:400}\r\n\r\n\tassign result,0,X$nAgent\r\n\tSIGNALNOW agent.add2,X$nAgent\r\n\tSIGNALNOW agent.multiply10,X$nAgent\r\n\tSIGNALNOW agent.add4,X$nAgent\r\n\tmove {name:Text3,TEXT:\"SIGNALNOW Result: P$(result,X$nAgent)\"}\r\n\t\r\n\tADVANCE 20,60 {TO:POS2}\r\n    \r\nENDGENERATE 1\r\n\r\n\r\n;*******************************\r\nprocedure agent.main\r\n\tsavevalue nAgent,D$N\r\n    assign result,0\r\n    REST RestroomAgents\r\n    terminate_ve\r\nendprocedure\r\n\r\nprocedure agent.add2\r\n    assign result,P$result + 2\r\n    \tmove {name:TextAgent,TEXT:\"Result ADD2: P$result T= AC1$\"}\r\n    RETURN_RESTORE\r\nendprocedure\r\nprocedure agent.add4\r\n    assign result,P$result + 4\r\n    \tmove {name:TextAgent,TEXT:\"Result ADD4: P$result T= AC1$\"}\r\n    RETURN_RESTORE\r\nendprocedure\r\nprocedure agent.multiply10\r\n    assign result,P$result * 10\r\n    move {name:TextAgent,TEXT:\"Result MULTIPLY10: P$result T= AC1$\"}\r\n    RETURN_RESTORE\r\nendprocedure\r\n",
                "descripcion": "<p>This chapter breaks down the combined behavior of the <strong>event queue<\/strong> and the <strong>context stack<\/strong> inside GPSS-Plus, and how they affect asynchronous behavior with <code>SIGNAL<\/code> and synchronous behavior with <code>SIGNALNOW<\/code>.<\/p>\r\n<h4>The event queue<\/h4>\r\n<p>When an entity executes an <code>ADVANCE<\/code> block, it is placed into the <strong>event queue<\/strong>, which is ordered chronologically. If multiple events share the same time, the entity that entered first has priority (FIFO). The queue only stores the execution time, a reference to the entity, and the element type.<\/p>\r\n<h4>The context stack<\/h4>\r\n<p>Each entity has its own private <strong>context stack<\/strong>, used to resume execution after jumps such as <code>CALL<\/code> or <code>FOREACH<\/code>. This stack is LIFO: the last context pushed is the first popped.<\/p>\r\n<p>When calling other entities (agents) via <code>SIGNAL<\/code> or <code>SIGNALNOW<\/code>, the current execution state is saved on this stack so it can be resumed afterward.<\/p>\r\n<h4>What happens with SIGNAL?<\/h4>\r\n<p><code>SIGNAL<\/code> is <strong>asynchronous<\/strong>. The sending entity does not stop; it merely schedules the execution of a procedure in another agent. If three SIGNALs are sent in sequence to the same agent, the sender continues immediately, while the receiving agent is scheduled three times in the event queue.<\/p>\r\n<p>When the agent runs, it executes the pending procedures using its stack. Because the stack is LIFO, execution happens in reverse order, producing results such as: (((0 + 4) * 10) + 2) = 42.<\/p>\r\n<h4>What about SIGNALNOW?<\/h4>\r\n<p><code>SIGNALNOW<\/code> is <strong>synchronous<\/strong>. It temporarily pauses the calling entity, immediately executes the agent procedure, and then resumes execution. Calls therefore run in the written order, yielding: (((0 + 2) * 10) + 4) = 24.<\/p>\r\n<h4>Example in action<\/h4>\r\n<p>This model defines an agent with three methods (<code>add2<\/code>, <code>multiply10<\/code>, <code>add4<\/code>). Two entities invoke it: one using <code>SIGNAL<\/code> and the other using <code>SIGNALNOW<\/code>. On screen, the different results clearly show the behavioral difference.<\/p>\r\n<p>With <code>SIGNAL<\/code>, the result remains unchanged at first because the calls have not yet executed. A simple <code>ADVANCE 0<\/code> (re-scheduling the entity in the event queue) allows the agent calls to run, after which the result becomes available.<\/p>",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            },
            {
                "id": "253",
                "nombre": "Message queues",
                "texto": "\/*\r\n\r\n  \t \tMessage queues\r\n \r\n*\/\r\nSYSTEM {TYPE:PRE_RUN,TRIGGER:PRE_RUN}\r\nSTART 1000\r\n\r\nFacility {NAME:tables,X:221,Y:60,capacity:7}\r\nRestroom {NAME:waitToServe,X:323,Y:60}\r\nRestroom {NAME:sleepingAgents,X:348,Y:357}\r\n\r\nPOSITION {NAME:EATING, X:579, Y:46}\r\n\r\nGRAPHIC {NAME:INFOA_1, TYPE:TEXT, X:149, Y:296, TEXT:\"Agent1 ready\"}\r\nGRAPHIC {NAME:INFOB_1, TYPE:TEXT, X:147, Y:237, TEXT:\"infoB1\"}\r\nGRAPHIC {NAME:INFOC_1, TYPE:TEXT, X:147, Y:268, TEXT:\"infoC1\"}\r\n\r\nGRAPHIC {NAME:INFOA_2, TYPE:TEXT, X:577, Y:292, TEXT:\"Agent2 ready\"}\r\nGRAPHIC {NAME:INFOB_2, TYPE:TEXT, X:576, Y:238, TEXT:\"infoB2\"}\r\nGRAPHIC {NAME:INFOC_2, TYPE:TEXT, X:576, Y:266, TEXT:\"infoC2\"}\r\n\r\nGraphic {NAME:TextOrder,Type:TEXT,X:270,Y:132,Text:\"Order\"}\r\nGraphic {NAME:TextA,Type:TEXT,X:271,Y:102,Text:\"Not served\"}\r\nGraphic {NAME:TextB,Type:TEXT,X:469,Y:84,Text:\"Eating\"}\r\n\r\n;--------------------------------\r\n;\t\tCLIENTS\r\n;--------------------------------\r\nGENERATE 8,5,0,8 {NAME:Clients, X:53, Y:61}\r\n    ADVANCE 3 {TO:tables,FLOW:1}\r\n    seize tables\r\n    call add_order\r\n    rest waitToServe\r\n    ADVANCE 120,30 {FROM:waitToServe,TO:EATING,FLOW:1} ; eating\r\n    release tables\r\n    if (R$(tables,IN)<=0)\r\n\t    stop\r\n    endif\r\nENDGENERATE 1\r\n\r\n;**********************************\r\nprocedure add_order\r\n\r\n    ASSIGN cOven, FLOOR(RANDOM * 4)\r\n    ASSIGN cStove, FLOOR(RANDOM * 6)\r\n    ASSIGN cFryer, FLOOR(RANDOM * 3)\r\n    \r\n    ASSIGN pendingDishes, P$cOven + P$cStove + P$cFryer\r\n\r\n    savevalue.push orders, [1,D$N,P$cOven,P$cStove,P$cFryer]\r\n    MOVE {name:TextOrder,text:\"Oven: P$cOven ; Stove: P$cStove ; Fryer: P$cFryer\"}\r\n    \r\n\t; wake up kitchen staff, the first to arrive will take the order\r\n    wake sleepingAgents\r\n\r\nENDPROCEDURE\r\n\r\n;--------------------------------\r\n;\t\tCOOKS \/ AGENTS\r\n;--------------------------------\r\n\r\nPROCEDURE PRE_RUN\r\n\ttimeout agent.main,0,1\r\n\ttimeout agent.main,0,2\r\n\tTERMINATE_VE \r\nENDPROCEDURE\r\n\r\nprocedure agent.main\r\n    if (P$PARAM_A==1)\r\n        savevalue nAgent1,D$N\r\n        assign nAgent,1\r\n    else\r\n        savevalue nAgent2,D$N\r\n        assign nAgent,2\r\n    endif\r\n    \r\n    MOVE {NAME:\"INFOA_P$nAgent\", TEXT:\"Agent active P$PARAM_A\"}\r\n\tsavevalue orders, []\r\n    assign taskInProgress,0\r\n\r\n\tWHILE (1==1)\r\n        if (VD$(orders,LENGTH)<=0)\r\n        \tMOVE {NAME:\"INFOA_P$nAgent\", TEXT:\"T: AC1$ Cook P$nAgent : SLEEPING...\", color:red}\r\n            rest sleepingAgents\r\n        endif\r\n\t\tassign nTasks,VD$(orders,LENGTH)\r\n\t\tMOVE {NAME:\"INFOA_P$nAgent\", TEXT:\"Cook: I have P$nTasks tasks, Awake\", color:green}\r\n  \r\n    \tsavevalue.pop orders,order\r\n\t\tassign taskInProgress,P$(order.0)\r\n\t\tassign nEntity,P$(order.1)\r\n\t\tassign cOven,P$(order.2)\r\n\t\tassign cStove,P$(order.3)\r\n\t\tassign cFryer,P$(order.4)\r\n  \r\n\t\tif (P$taskInProgress > 0)\r\n        MOVE {NAME:\"INFOB_P$nAgent\", TEXT:\"Processing client P$nEntity\"}\r\n        MOVE {NAME:\"INFOC_P$nAgent\", TEXT:\"Oven: P$cOven ; Stove: P$cStove ; Fryer: P$cFryer\"}\r\n\r\n\t\tassign counter,0\r\n        while (P$counter<P$cOven)\r\n            assign counter,P$counter + 1\r\n            MOVE {NAME:\"INFOB_P$nAgent\", TEXT:\"sending OVEN dish P$counter of P$cOven\"}\r\n            advance 8,10\r\n            NEW dishes,0,P$nEntity,\"Oven\"\r\n        endwhile\r\n\r\n\t\tassign counter,0\r\n        while (P$counter<P$cStove)\r\n            assign counter,P$counter + 1\r\n            MOVE {NAME:\"INFOB_P$nAgent\", TEXT:\"sending STOVE dish P$counter of P$cStove\"}\r\n            advance 8,10\r\n            NEW dishes,0,P$nEntity,\"Stove\"\r\n        endwhile\r\n\r\n\t\tassign counter,0\r\n        while (P$counter<P$cFryer)\r\n            assign counter,P$counter + 1\r\n            MOVE {NAME:\"INFOB_P$nAgent\", TEXT:\"sending FRYER dish P$counter of P$cFryer\"}\r\n            advance 5,5\r\n            NEW dishes,0,P$nEntity,\"Fryer\"\r\n        endwhile 3\r\n\r\n\t\tMOVE {NAME:\"INFOC_P$nAgent\", TEXT:\" \"}\r\n\t\tMOVE {NAME:\"INFOB_P$nAgent\", TEXT:\"finished\"}\r\n        assign taskInProgress,0\r\n    \tendif\r\n    ENDWHILE\r\n\r\n    TERMINATE\r\nENDPROCEDURE\r\n\r\n;--------------------------------\r\n;\t\tKITCHEN\r\n;--------------------------------\r\n\r\nFacility {NAME:Oven,X:348,Y:566,capacity:2}\r\nFacility {NAME:Stove,X:347,Y:499,capacity:4}\r\nFacility {NAME:Fryer,X:347,Y:437,capacity:3}\r\n\r\nGraphic {NAME:TextDishes1,Type:TEXT,X:160,Y:579,Text:\"Dishes...\"}\r\nGraphic {NAME:TextDishes2,Type:TEXT,X:533,Y:578,Text:\"Dishes2...\"}\r\n\r\nPOSITION {NAME:ENDKITCHEN, X:649, Y:509}\r\n\r\nGENERATE 0,0,0,0,0 {NAME:dishes, X:69, Y:508}\r\nmove {name:TextDishes1,text:\"Preparing dish for P$PARAM_A type P$PARAM_B\"}\r\nassign targetEntity,P$PARAM_A\r\nassign orderType,\"P$PARAM_B\"\r\n\r\nswitch \"P$orderType\"\r\ncase ==,\"Oven\"\r\n\tADVANCE 4 {TO:Oven,FLOW:1,DECISION:KITCHEN}\r\n    seize Oven\r\n    ADVANCE 40,5\r\n    release Oven\r\nendcase\r\n\r\ncase ==,\"Stove\"\r\n\tADVANCE 4 {TO:Stove,FLOW:1,DECISION:KITCHEN}\r\n    seize Stove\r\n    ADVANCE 30,5\r\n    release Stove\r\nendcase\r\n\r\ncase ==,\"Fryer\"\r\n\tADVANCE 4 {TO:Fryer,FLOW:1,DECISION:KITCHEN}\r\n    seize Fryer\r\n    ADVANCE 22,3\r\n    release Fryer\r\nendcase\r\n\r\nendswitch\r\n\r\nADVANCE 5 {TO:ENDKITCHEN,FLOW:1,MERGE:KITCHEN}\r\nmove {name:TextDishes2,text:\"Finished dish for P$targetEntity type P$orderType\"}\r\n\r\nassign pendingDishes, P$(pendingDishes,P$targetEntity) - 1,P$targetEntity\r\n\r\nif (P$(pendingDishes,P$targetEntity)<=0)\r\n\twake waitToServe,0,P$targetEntity\r\nendif\r\n\r\nENDGENERATE 0\r\n",
                "descripcion": "This example shows a model with a complex narrative that becomes natural to express in GPSS-Plus thanks to its primitives for agents, task lists, and event-based synchronization.\n\nThe simulation represents a simplified restaurant: clients arrive, take a table, place an order, and wait to be served. Cooks (agents) wake up if they were sleeping, take an order from a shared list, and generate dish entities for each task. When all dishes for a client are ready, the client can start eating.\n\nAll coordination is handled through a shared FIFO task list (using savevalue.push \/ pop) and a common RESTROOM that regulates sleeping and waking of agents. No SIGNAL, ON_QUEUE, or ON_RELEASE blocks are required, yet the system flows correctly.\n\nThis model demonstrates how agents can self-manage their workload without external interruptions, simply by polling a shared work queue. Here, the RESTROOM acts as a sleep lock: the first agent to wake up handles the task, while the others continue waiting.",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            },
            {
                "id": "311",
                "nombre": "Entity management",
                "texto": "\/*\r\n\r\n  \t \tEntity management\r\n \r\n*\/\r\nSYSTEM {TYPE:PRE_RUN,TRIGGER:PRE_RUN}\r\n\r\nRestroom {NAME:RestroomAgents,X:100,Y:121,visible:1}\r\nQueuer {NAME:Queuer1,X:321,Y:123,on_queue:Queuer1on_queue,on_depart:Queuer1on_depart}\r\n\r\nPOSITION {NAME:POS1,X:251,Y:335}\r\nPOSITION {NAME:POS2,X:469,Y:341}\r\n\r\nGraphic {NAME:Text1,Type:TEXT,X:425,Y:514,Text:\"Entity\"}\r\nGraphic {NAME:TextAgent1,Type:TEXT,X:433,Y:462,Text:\"---\"}\r\nGraphic {NAME:TextAgent2,Type:TEXT,X:433,Y:416,Text:\"---\"}\r\n\r\ninitial nAgent,0\r\nSTART 500\r\n\r\n;*****************************************************\r\nPROCEDURE PRE_RUN\r\n\ttimeout agent.main,0\r\n\tTERMINATE_VE\r\nENDPROCEDURE 1\r\n\r\n;*****************************************************\r\nGENERATE 10,0 {NAME:GEN1,X:43,Y:300}\r\n\r\n\tmove {name:Text1,TEXT:\"Entity result P$(result,X$nAgent) AC1$\"}\r\n\t\r\n\tADVANCE 20,0 {TO:POS1}\r\n\tqueue Queuer1\r\n\tADVANCE 20,60 {TO:POS2}\r\n\tdepart Queuer1\r\n\r\nENDGENERATE 1\r\n\r\n;*******************************\r\nprocedure agent.main\r\n\tsavevalue nAgent,D$N\r\n    assign data,{}\r\n    assign result,0\r\n    assign average,0\r\n    assign nEntities,0\r\n    assign totalTime,0\r\n    while (1==1)\r\n        REST RestroomAgents\r\n    endwhile\r\n    terminate_ve\r\nendprocedure\r\n\r\n;**********************************\r\nprocedure agent.IN\r\n    assign data.entity_P$PARAM_A,P$PARAM_B\r\n    move {name:TextAgent1,TEXT:\"IN Entity P$PARAM_A : Start time: P$(data.entity_P$PARAM_A)\"}\r\n    RETURN_RESTORE\r\nendprocedure\r\n\r\n;**********************************\r\nprocedure agent.OUT\r\n    assign nEntities,P$nEntities + 1\r\n    assign startTime,P$(data.entity_P$PARAM_A)\r\n    assign endTime,P$PARAM_B\r\n    assign totalTime,P$totalTime + P$endTime - P$startTime\r\n    assign average,P$totalTime \/ P$nEntities\r\n    move {name:TextAgent2,TEXT:\"OUT Entity: P$PARAM_A Total time: P$totalTime Average: P$average\"}\r\n    ASSIGN.DELETE data,entity_P$PARAM_A\r\n    RETURN_RESTORE\r\nendprocedure\r\n\r\nprocedure Queuer1on_queue\r\n\tSIGNAL agent.IN,X$nAgent,P$ENTITYNUMBER,AC1$\r\n    TERMINATE_VE\r\nendprocedure\r\n\r\nprocedure Queuer1on_depart\r\n    SIGNAL agent.OUT,X$nAgent,P$ENTITYNUMBER,AC1$\r\n\tTERMINATE_VE\r\nendprocedure\r\n",
                "descripcion": "In this chapter we explore how an agent can be responsible for monitoring the passage of entities through a zone of the model and computing global metrics such as total usage time or average residence time.\n\nThe agent does not act directly on the entities; instead, it listens to events automatically generated by a QUEUER (through its ON_QUEUE and ON_DEPART hooks) and, based on those events, records when entities enter and leave.\n\nTo do this, the agent maintains a data structure (associative array) where it stores entry times and later computes differences upon exit. This allows full tracking without interfering with the logical flow of the rest of the model.\n\nThis kind of logic is useful for implementing custom statistics, usage auditing, alerts, or any control that depends on external events and entity history.",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            },
            {
                "id": "262",
                "nombre": "Resource manager",
                "texto": "\/*\r\n\r\n  \t \tResource manager\r\n \r\n*\/\r\nSYSTEM {TYPE:PRE_RUN,TRIGGER:PRE_RUN}\r\n\r\nINITIAL tramos,  [\r\n    { tiempo: 10, color: \"#009900\", nInicio: \"InicioN\", nFin: \"FinN\", nCentro: \"CentroN\", nRestroom: \"RestroomN\", nSemaforo: \"SemaforoN\", nTexto: \"TextN\" },\r\n    { tiempo: 20, color: \"#FF0099\", nInicio: \"InicioS\", nFin: \"FinS\", nCentro: \"CentroS\", nRestroom: \"RestroomS\", nSemaforo: \"SemaforoS\", nTexto: \"TextS\" },\r\n    { tiempo: 30, color: \"#000099\", nInicio: \"InicioE\", nFin: \"FinE\", nCentro: \"CentroE\", nRestroom: \"RestroomE\", nSemaforo: \"SemaforoE\", nTexto: \"TextE\" },\r\n    { tiempo: 40, color: \"#0099FF\", nInicio: \"InicioO\", nFin: \"FinO\", nCentro: \"CentroO\", nRestroom: \"RestroomO\", nSemaforo: \"SemaforoO\", nTexto: \"TextO\" }\r\n  ]\r\n\r\nPOSITION {NAME:InicioN,X:368,Y:541}\r\nPOSITION {NAME:InicioS,X:393,Y:30}\r\nPOSITION {NAME:InicioE,X:756,Y:270}\r\nPOSITION {NAME:InicioO,X:41,Y:269}\r\n\r\nPOSITION {NAME:FinN,X:398,Y:540}\r\nPOSITION {NAME:FinS,X:416,Y:31}\r\nPOSITION {NAME:FinE,X:754,Y:298}\r\nPOSITION {NAME:FinO,X:40,Y:301}\r\n\r\nPOSITION {NAME:CentroN,X:381,Y:347}\r\nPOSITION {NAME:CentroS,X:393,Y:249}\r\nPOSITION {NAME:CentroE,X:447,Y:294}\r\nPOSITION {NAME:CentroO,X:325,Y:290}\r\n\r\nGraphic {NAME:SemaforoN,TYPE:ARC,X:413,Y:346,FCOLOR:\"red\",RADIUS:16,START_ANGLE:0,END_ANGLE:360,CLOSE:1}\r\nGraphic {NAME:SemaforoS,TYPE:ARC,X:363,Y:246,FCOLOR:\"red\",RADIUS:16,START_ANGLE:0,END_ANGLE:360,CLOSE:1}\r\nGraphic {NAME:SemaforoE,TYPE:ARC,X:453,Y:263,FCOLOR:\"red\",RADIUS:16,START_ANGLE:0,END_ANGLE:360,CLOSE:1}\r\nGraphic {NAME:SemaforoO,TYPE:ARC,X:326,Y:320,FCOLOR:\"red\",RADIUS:16,START_ANGLE:0,END_ANGLE:360,CLOSE:1}\r\n\r\nRestroom {NAME:RestroomN,X:713,Y:570,on_rest:actualiza}\r\nRestroom {NAME:RestroomS,X:713,Y:473,on_rest:actualiza}\r\nRestroom {NAME:RestroomE,X:713,Y:521,on_rest:actualiza}\r\nRestroom {NAME:RestroomO,X:713,Y:422,on_rest:actualiza}\r\n\r\nGraphic {NAME:TextN,Type:TEXT,X:412,Y:347,Text:\"N\",font:\"18px\",color:#ffffff}\r\nGraphic {NAME:TextS,Type:TEXT,X:363,Y:247,Text:\"S\",font:\"18px\",color:#ffffff}\r\nGraphic {NAME:TextE,Type:TEXT,X:453,Y:263,Text:\"E\",font:\"18px\",color:#ffffff}\r\nGraphic {NAME:TextO,Type:TEXT,X:326,Y:320,Text:\"O\",font:\"18px\",color:#ffffff}\r\n\r\nGraphic {NAME:textSem,Type:TEXT,X:165,Y:381,Text:\"Semaphore\",font:\"18px\",color:#000000}\r\n\r\nSTART 3000\r\n\r\n;----------------------------- MAIN MOVEMENT PROCEDURE\r\nprocedure toSemaphore ; P$PARAM_A = origin, P$PARAM_B = destination\r\n\r\nADVANCE X$(tramos.P$(PARAM_A).tiempo),10 {from:X$(tramos.P$(PARAM_A).nInicio), to:X$(tramos.P$PARAM_A.nCentro)}\r\n\r\nif (X$openSemaphore!=P$PARAM_A)\r\n    rest X$(tramos.P$(PARAM_A).nRestroom)\r\nendif\r\n\r\nADVANCE 10,3 {to:X$(tramos.P$PARAM_B.nCentro)}\r\nADVANCE X$(tramos.P$(PARAM_B).tiempo),10 {to:X$(tramos.P$(PARAM_B).nFin)}\r\n\r\nendprocedure\r\n\r\n;----------------------------- SEMAPHORE AGENT\r\nprocedure semaphoreAgent.main\r\n\r\nsavevalue openSemaphore,0\r\n\r\nwhile (1==1)\r\n    savevalue prevOpenSemaphore, X$openSemaphore\r\n    move {name:X$(tramos.X$(openSemaphore).nSemaforo),FCOLOR:yellow}\r\n\r\n    savevalue openSemaphore,-1\r\n    advance 50\r\n\r\n    call calculateDestination,X$prevOpenSemaphore\r\n\r\n    move {name:X$(tramos.X$(prevOpenSemaphore).nSemaforo),FCOLOR:red}\r\n    savevalue openSemaphore,P$calculateDestination\r\n    move {name:textSem,text:\"Open semaphore: X$openSemaphore\"}\r\n\r\n    move {name:X$(tramos.X$(openSemaphore).nSemaforo),FCOLOR:green}\r\n    wake X$(tramos.X$(openSemaphore).nRestroom)\r\n\r\n    advance 200\r\nendwhile\r\n\r\nendprocedure\r\n\r\n;----------------------------- DESTINATION SELECTION PROCEDURE\r\nprocedure calculateDestination ; P$PARAM_A origin\r\nassign tmp, (P$PARAM_A + 1 + floor(random*3)) % 4\r\nendprocedure P$tmp\r\n\r\n;----------------------------- UI UPDATE PROCEDURE\r\nprocedure actualiza\r\n\r\nmove {name:X$(tramos.0.nTexto),text:\"R$(X$(tramos.0.nRestroom),IN)\"}\r\nmove {name:X$(tramos.1.nTexto),text:\"R$(X$(tramos.1.nRestroom),IN)\"}\r\nmove {name:X$(tramos.2.nTexto),text:\"R$(X$(tramos.2.nRestroom),IN)\"}\r\nmove {name:X$(tramos.3.nTexto),text:\"R$(X$(tramos.3.nRestroom),IN)\"}\r\n\r\nterminate\r\n\r\nendprocedure\r\n\r\n;----------------------------- ENTITY GENERATOR\r\nGENERATE 10,5 {NAME:GEN,X:577,Y:575,ERADIO:10}\r\n\r\nassign origin,floor(random*4)\r\nmod {color:X$(tramos.P$origin.color)}\r\n\r\ncall calculateDestination,P$origin\r\ncall toSemaphore,P$origin,P$calculateDestination\r\n\r\nENDGENERATE 1\r\n\r\n;----------------------------- AGENT STARTUP\r\nPROCEDURE PRE_RUN\r\n    TIMEOUT semaphoreAgent.main, 0\r\n    TERMINATE_VE\r\nENDPROCEDURE",
                "descripcion": "In this chapter we present an agent that acts as an intelligent manager of a shared resource: a traffic light (semaphore).\n\nThe goal is to allow entities to pass from different origins to different destinations, but only one direction at a time, in a controlled manner. This simulates an intersection where the semaphore changes direction periodically, enabling one of four possible paths.\n\nGeneral structure:\n- An INITIAL block defines the tramos table, which contains the configuration for each direction (positions, restrooms, colors, graphics, etc.).\n- Entities wait in a Restroom if their direction is not currently enabled and proceed when it becomes active.\n- The semaphoreAgent.main agent:\n  * Switches the current semaphore to yellow and then red.\n  * Selects the next open direction randomly.\n  * Updates colors and on-screen text.\n  * Wakes the entities waiting for the newly opened direction.\n\nKey learning:\nThe agent behaves as both a visual and operational scheduler, showing how a permanent control loop can govern multiple entity flows simply by deciding when to allow progress. This pattern is useful for exclusive zones, turn-based access, shared resources, or alternating flows.",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            },
            {
                "id": "371",
                "nombre": "Component entity",
                "texto": "\/*\r\n\r\nComponent\r\n\r\n*\/\r\nSYSTEM {TYPE:PRE_RUN,TRIGGER:PRE_RUN}\r\n;SYSTEM {TYPE:OPTIONS,Speed:8}\r\n\r\nRestroom {NAME:Restroom_bus,X:333,Y:282}\r\nPOSITION {NAME:URGENT_EXIT,X:335,Y:119}\r\nPOSITION {NAME:EXIT,X:615,Y:286,type:terminate,title:end}\r\n\r\nGraphic {NAME:textAgent,Type:TEXT,X:494,Y:336,Text:\"Group\"}\r\nGraphic {NAME:Text2,Type:TEXT,X:331,Y:76,Text:\"Urgency\"}\r\n\r\nSTART 500\r\n;*****************************************************\r\nPROCEDURE PRE_RUN\r\n\ttimeout check_queue,1\r\n\tTERMINATE_VE \r\nENDPROCEDURE\r\n\r\n;*****************************************************\r\nGENERATE 10,0,0,0 {NAME:GEN1,X:61,Y:288}\r\n\r\nASSIGN urgentExit,0\r\ntimeout component_check_phone,0,D$N\r\nADVANCE 20,0 {TO:Restroom_bus}\r\nREST Restroom_bus\r\n\r\nif (P$urgentExit == 1)\r\nADVANCE 20,10 {TO:URGENT_EXIT}\r\nelse\r\nADVANCE 20,10 {TO:EXIT}\r\nendif\r\nENDGENERATE 1\r\n\r\n;*******************************\r\nprocedure check_queue\r\n    while (1==1)\r\n        advance 5\r\n        if (R$(Restroom_bus,OCCUPIED) > 5)\r\n        move {name:textAgent,text:\"Releasing [AC1: AC1$]\"}\r\n        WAKE Restroom_bus ; all leave\r\n        endif\r\n    endwhile\r\nendprocedure\r\n;**********************************\r\n\r\nprocedure component_check_phone\r\n\tassign myEntity,P$PARAM_A\r\n    while (D$(EXIST,P$myEntity)==1)\r\n        advance 5\r\n        if (R$(Restroom_bus,IS_OCCUPIED_BY,P$myEntity) == 1 && RANDOM < 0.02)\r\n        move {name:Text2,text:\"Releasing entity P$myEntity [AC1: AC1$]\"}\r\n        assign urgentExit,1,P$myEntity\r\n        mod {number:P$myEntity, color:red}\r\n        WAKE Restroom_bus,-1,P$myEntity ; only this entity leaves\r\n        endif\r\n    endwhile\r\n    terminate_ve\r\nendprocedure\r\n;**********************************",
                "descripcion": "In a discrete-event simulation engine, an entity is usually a single execution thread: a sequential flow that advances, blocks, and resumes according to the model.\n\nThis works, but it does not fully match real behavior in many situations.\n\nA person waiting at a bus stop does not just wait: they breathe, check their phone, think, get distracted, and may change their mind.\n\nA moving vehicle also acts in parallel: it consumes energy, wears down, receives signals, and adjusts its route.\n\nModeling all of this with a single linear flow is an excessive simplification.\n\nComponent entities: simultaneity inside the entity\n\nWe therefore extend the way we think about an entity so that it can have several functions running in parallel.\n\nA component entity is a virtual entity that executes a function on behalf of another main entity. Its existence depends on the main entity, but it has its own execution flow.\n\nThis allows a main entity to have multiple active behaviors simultaneously, each represented by an independent component entity.\n\nKey characteristics:\n- The component entity is created when the main entity is created.\n- It runs its logic in parallel, without blocking the main flow.\n- It can read and modify attributes of the main entity.\n- It can wake it, change its state, or trigger decisions.\n- It automatically ends when the main entity ceases to exist.\n\nIt is not a “child” in an OOP sense, nor an object or a property. It is a living behavior, modeled as an entity.\n\nThe event queue remains strictly sequential, but the entity is no longer monolithic: it no longer represents a single flow, but a small system composed of several cooperating entities that model the main entity more deeply.\n\nThis makes it possible to model natural simultaneity phenomena without threads, semaphores, or external programming.\n\nLifecycle of a component entity:\n1. The main entity is created.\n2. A component entity is immediately created, receiving the main entity’s identifier.\n3. The component entity runs its logic in a WHILE loop as long as D$(EXIST, mainEntityId) == 1.\n4. It may influence the main entity by assigning values, modifying state, or waking it.\n5. When the main entity disappears, the component entity automatically terminates.\n\nIn the example, people arrive at a simplified bus stop. When more than six accumulate, everyone leaves while they are resting outside the event queue. Meanwhile, the entities are also checking their phones, and some may decide to leave urgently.\n\nWhen a component entity decides the queue must be abandoned, it executes the required actions while the main entity is still sleeping in the RESTROOM.",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            }
        ]
    },
    {
        "id": "351",
        "nombre": "Season 7: Contexts (CX$) and Modules (.mod)",
        "texto": "",
        "descripcion": "",
        "parametros": null,
        "parametros_json": null,
        "ejemplo": null,
        "hijos": [
            {
                "id": "349",
                "nombre": "Dynamic resource creation 1",
                "texto": "\/*\n\nContexts and modules. Dynamic creation 1\n\n\n*\/\nSYSTEM {TYPE:OPTIONS, SPEED:5}\nSYSTEM {TYPE:PRE_RUN,TRIGGER:PRE_RUN}\nPosition {NAME:pos_exit,X:581,Y:407}\n\n; --- Facility defined in the classic way ---\nFACILITY {NAME:resource_static, CAPACITY:1,  X:496, Y:164}\n\nSTART 200\n\nPROCEDURE PRE_RUN\n    ; Create a second dynamic facility at startup\n    NEWFACILITY {NAME:resource_dynamic, CAPACITY:1,  X:300, Y:400}\n    TERMINATE_VE\nENDPROCEDURE\n\n;------------------------------------------------------\n; --- Entity flow ---\nGENERATE 10,0 {NAME:GEN1}     ; one entity every 10 ticks\nadvance 15 {to:resource_static}\n\nSEIZE resource_static\nADVANCE 15\nRELEASE resource_static\n\nadvance 15 {to:resource_dynamic}\n\nSEIZE resource_dynamic\nADVANCE 17\nRELEASE resource_dynamic\n\nadvance 15 {to:pos_exit}\n\nTERMINATE 1",
                "descripcion": "Before starting with contexts, we must take into account a specific characteristic of GPSS-Plus.\n\nIn general, drag-and-drop based engines allow resources to be easily placed on the canvas and immediately used. In GPSS-Plus this works differently: the resource must be defined by writing its command.\n\nOn the other hand, this drag-and-drop approach makes runtime resource creation very difficult. In GPSS-Plus this is solved by simply replacing the FACILITY command with the NEWFACILITY block.\n\nThe only requirement is that the resource must exist before being used, which is why this is typically done in PRE_RUN.",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            },
            {
                "id": "348",
                "nombre": "Dynamic resource creation 2",
                "texto": "SYSTEM {TYPE:OPTIONS, SPEED:5}\nSYSTEM {TYPE:PRE_RUN,TRIGGER:PRE_RUN}\nPosition {NAME:POS1,X:147,Y:311}\nPosition {NAME:POS2,X:542,Y:327}\nPosition {NAME:POS3,X:756,Y:322}\n\n\nGraphic {NAME:Text1,Type:TEXT,X:305,Y:571,Text:\"Hello\"}\n\n; --- Facility defined in the classic way ---\nFACILITY {NAME:f_static, CAPACITY:4, X:657, Y:325,color:blue}\n\nSTART 200\n\nPROCEDURE PRE_RUN\n    ; Create a second dynamic facility at startup\n\tassign t,0\n    \n    while (P$t < 5) \n        assign t,P$t+1\n        assign pos_y,(P$t * 80 + 20)\n        assign nombre,\"f_dynamic_P$t\"\n        NEWFACILITY {NAME:P$nombre, CAPACITY:1, X:300, Y:(P$pos_y)}\n        NEWPOSITION {NAME:pos_P$nombre, X:200, Y:(P$pos_y)}\n    endwhile\n   \n    TERMINATE_VE\nENDPROCEDURE\n\n;------------------------------------------------------\n; --- Entity flow ---\nGENERATE 6,0 {NAME:GEN1,x:58,y:310} \n\nadvance 15,0 {to:POS1,flow:1}\n\nASSIGN MINKEY,0 \nASSIGN MINVAL,100000\n\nassign t,0\nwhile (P$t < 5) \n    assign t,P$t+1\n    assign nombre,\"f_dynamic_P$t\"\n    if (R$(P$nombre,QUEUE) < P$MINVAL)\n        ASSIGN MINKEY,P$t \n\t\tASSIGN MINVAL,R$(P$nombre,QUEUE)\n    endif\nendwhile\n\nassign siguiente_recurso,\"f_dynamic_P$MINKEY\"\n\nmove {name:Text1,text:\"Entity D$N query: P$(siguiente_recurso) Queue: R$(P$siguiente_recurso,QUEUE)\"}\n\n\n\n\nadvance 15,0 {to:\"pos_P$siguiente_recurso\",flow:1,DECISION:\"inicio\"}\nadvance 15,0 {to:\"P$siguiente_recurso\",flow:1}\n\n\nSEIZE P$siguiente_recurso   \nADVANCE 25,15   \nRELEASE P$siguiente_recurso\n\nadvance 15 {to:POS2,flow:1,MERGE:\"salida\"}\n\nadvance 15 {to:f_static,flow:1}\n\nSEIZE f_static  \nADVANCE 7,8        \nRELEASE f_static\n\nadvance 15 {to:POS3,flow:1}\n\nTERMINATE 1",
                "descripcion": "Now that we know resources can be created at runtime, let’s look at their most obvious use: creating many of them using an iterator.\n\nWe only need to keep track of the names assigned in order to use them later.\n\nIn GPSS-Plus, resource names are real strings, which means they can be dynamically constructed and directly used in SEIZE, RELEASE, R$(), and similar commands.",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            },
            {
                "id": "350",
                "nombre": "Dynamic resource creation 3",
                "texto": "\/*\r\n\r\nContexts and modules. Dynamic creation 3\r\n\r\n\r\n*\/\r\nSYSTEM {TYPE:OPTIONS, SPEED:5}\r\nPosition {NAME:pos_exit,X:581,Y:407}\r\n\r\n; --- Facility defined in the classic way ---\r\nFACILITY {NAME:resource_static, CAPACITY:1,  X:496, Y:164}\r\n\r\nSTART 200\r\n\r\n\r\n;------------------------------------------------------\r\n; --- Entity flow ---\r\nGENERATE 10,0 {NAME:GEN1}\r\nadvance 15 {to:resource_static}\r\n\r\nSEIZE resource_static      \r\nADVANCE 15        \r\nRELEASE resource_static\r\n\r\nif (R$(resource_dynamic,EXIST)==0)\r\n\tNEWFACILITY {NAME:resource_dynamic, CAPACITY:1,  X:300, Y:400}\r\nendif\r\n\r\nadvance 15 {to:resource_dynamic}\r\n\r\nSEIZE resource_dynamic    \r\nADVANCE 17          \r\nRELEASE resource_dynamic\r\n\r\nadvance 15 {to:pos_exit}\r\n\r\nTERMINATE 1\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n",
                "descripcion": "<p>And finally, they can also be created if the need arises.<\/p>\r\n<p>You just need to keep in mind that a resource cannot be modified once it is created; it can only be blocked with the <code>LOCK<\/code> block.<\/p>",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            },
            {
                "id": "275",
                "nombre": "Code reuse. CX$",
                "texto": "\/*\r\n\r\nContexts and modules. Graphic libraries\r\n\r\n\r\n*\/\r\n\r\nSYSTEM {TYPE:PRE_RUN,TRIGGER:PRE_RUN}\r\nGraphic {NAME:Text1,Type:TEXT,X:100,Y:319,Text:\"Current value\"}\r\nGraphic {NAME:Text2,Type:TEXT,X:300,Y:312,Text:\"Current value\"}\r\n\r\nSTART 100\r\n\r\ninclude .\/library_graphics\/tank.lib\r\n\r\n;-----------------------------------------------------------\r\n; We instantiate two tanks with different parameters\r\n; Each one is generated in its own context: aaa and bbb\r\n; The procedures will be the same, but data and graphics will be independent\r\nPROCEDURE PRE_RUN\r\n\tassign config,{title:\"tank\"\r\n    \t\t,x:100,y:100 \r\n            ,width:50 ,height:180\r\n            ,value:88\r\n            ,max_value:100\r\n            ,\"color\":\"#ff0000\"}\r\n\tcall aaa.tank.init,V$config\r\n\r\n\tassign config2,{title:\"tank\"\r\n    \t\t,x:300,y:100 \r\n            ,width:50 ,height:180\r\n            ,value:88\r\n            ,max_value:100\r\n            ,\"color\":\"#ff00ff\"}\r\n            \r\n\tcall bbb.tank.init,V$config2\r\n\r\n\tTERMINATE_VE \r\nENDPROCEDURE\r\n\r\n\r\n;============================================================\r\nGENERATE 25,0 {NAME:Gen1,x:100,y:400}\r\n\r\n\r\nCALL aaa.tank.set, 25\r\nCALL bbb.tank.set, 35\r\nADVANCE 5\r\n\r\nCALL aaa.tank.set, 52\r\nCALL bbb.tank.setcolor, \"blue\"\r\nADVANCE 5\r\n\r\nCALL aaa.tank.get\r\nMOVE {NAME:Text1, TEXT:\"Current value aaa: P$(get)\"}\r\n\r\nCALL bbb.tank.get\r\nMOVE {NAME:Text2, TEXT:\"Current value bbb: P$(get)\"}\r\n\r\nCALL aaa.tank.set, 75\r\nCALL bbb.tank.set, 10\r\nADVANCE 5\r\nCALL aaa.tank.set, 90\r\nADVANCE 5\r\n\r\nCALL aaa.tank.set, 10\r\nADVANCE 5\r\n\r\nENDGENERATE 1\r\n\r\n",
                "descripcion": "<p>By now you have probably realized what it can mean to build logic that simulates an entire workshop.<br>And we can go crazy if we are told there are two workshops. And then 10.<\/p>\r\n<p>It seems that we should give up at that point, but no — that is exactly what GPSS-Plus contexts are for.<br>They are not classes, because in a discrete-event environment that concept does not really make sense, but we will see that they are very similar. They are more like a namespace, and everything becomes much simpler.<\/p>\r\n<p>Let’s imagine a more trivial case: a graphic showing the level of a tank.<br>We draw the lines, colors and text, and then we want to reuse it.<br>That is where the problems begin: that object, class, drawing, element — whatever you want to call it — has its parameters so deeply embedded that it becomes overwhelming to work with.<br>And not only that: if we have two tanks, the work is not just double; we must also be very careful not to overwrite variables and to create as many <code>LINE<\/code> elements as needed.<\/p>\r\n<p>This is the problem we are going to solve.<\/p>\r\n<p>By analogy, it may look like classes with methods, local variables and instantiation, but it is not. It will be solved with a simple <u>string-type variable<\/u>.<\/p>\r\n<p>Until now, to move a graphic we could do:<\/p>\r\n<pre>CALL grafico_set,75<\/pre>\r\n<p>And if our <code>procedure<\/code> was correct, it would redraw a given graphic to show that 75% fill level.<br>Graphics that we previously had to create.<\/p>\r\n<p>Now we are going to do it differently, in such a way that everything we are about to see can be moved to another file that no longer gets in our way, and call it using <code>INCLUDE<\/code>.<\/p>\r\n<h3>First step: create a descriptive method<\/h3>\r\n<p>If our object is a tank, we will create a procedure called:<\/p>\r\n<pre>PROCEDURE deposito.init<\/pre>\r\n<p>This procedure will normally be invoked by an <code>EV<\/code> from <code>PRE_RUN<\/code> \/ <code>CALL<\/code>, and it will be responsible for creating all the graphics — instead of using <code>GRAPHIC<\/code> commands, it will use <code>NEWGRAPHIC<\/code> blocks.<\/p>\r\n<p>Like all calls, it can receive parameters to be executed, for example:<\/p>\r\n<pre>call deposito.init, 20, 130,120, 100,\"Carga\",\"#ff0000\"<\/pre>\r\n<p>…where <code>deposito.init<\/code> is the procedure and the rest are: width, height, X, Y, name and color. It can also be done more conveniently by defining an object with all the characteristics beforehand.<\/p>\r\n<p>And with this we can start drawing our tank based on those parameters:<\/p>\r\n<pre>NEWGRAPHIC { NAME:TextoNivel, GROUP:Deposito, TYPE:TEXT, X:0, Y:0, TEXT:\"Level: 0% \", COLOR:#000000 }<\/pre>\r\n<p>And so on with everything we want to add to our graphic.<\/p>\r\n<p>Then we only need to add some methods to manage it:<\/p>\r\n<pre>PROCEDURE deposito.move\r\n    MOVE {NAME:Deposito, x:P$PARAM_A, y:P$PARAM_B}\r\nENDPROCEDURE<\/pre>\r\n<p><b>With this we will have a graphic… but only one!<\/b><\/p>\r\n<p>That is the problem.<\/p>\r\n<p>The solution comes from something we mentioned regarding the separator point in the procedure name.<\/p>\r\n<p>To call this procedure <code>init<\/code> or <code>locate<\/code>, we can call it in as many ways as instances we want:<\/p>\r\n<pre>CALL aaa.deposito.init, 20, 130,120, 100,\"Carga\",\"#ff0000\"\r\nCALL bbb.deposito.init, 20, 80,420, 100,\"Nivel\",\"#ffff00\"\r\nCALL ccc.deposito.init, 20, 180,320, 100,\"Nivel\",\"#ff00ff\"\r\n...\r\nCALL aaa.deposito.locate,100,200\r\nCALL bbb.deposito.locate,200,100\r\nCALL ccc.deposito.locate,300,200<\/pre>\r\n<p>What we do is add another separator point to the instance name of that object.<\/p>\r\n<h3>And from here we must introduce the critical point: the value of the context <u>string<\/u> <code>CX$<\/code><\/h3>\r\n<p>Calling a procedure <code>\"aaa.deposito.locate\"<\/code> means that:<\/p>\r\n<ol>\r\n<li>The real name of the procedure is <code>\"deposito.locate\"<\/code><\/li>\r\n<li>The context (<code>CX$<\/code>) is the <u>string<\/u> <code>\"aaa\"<\/code><\/li>\r\n<\/ol>\r\n<p>And this must be very clear and always kept in mind.<\/p>\r\n<p>When an entity enters a <code>PROCEDURE<\/code> whose call is made with separator points, the activity will be executed under that <code>CX$<\/code> value.<\/p>\r\n<p>And this is enough to avoid overwriting variables or resources between instances.<\/p>\r\n<p>For example:<\/p>\r\n<pre>SAVEVALUE CX$_altura , 100<\/pre>\r\n<p>…will actually create:<\/p>\r\n<pre>SAVEVALUE aaa_altura , 100<\/pre>\r\n<p>Or:<\/p>\r\n<pre>NEWGRAPHIC {NAME:CX$_Deposito, TYPE:GROUP, X:0, Y:0}<\/pre>\r\n<p>…will really be:<\/p>\r\n<pre>NEWGRAPHIC {NAME:aaa_Deposito, TYPE:GROUP, X:0, Y:0}<\/pre>\r\n<p>Therefore, as many <code>SAVEVALUE<\/code>, <code>ASSIGN<\/code>, <code>NEWGRAPHIC<\/code>, <code>NEWRESTROOM<\/code> elements will be generated as there are ways to call the <code>init<\/code> of each class.<\/p>\r\n<p>So we only need to rename our internal <code>ASSIGN<\/code>s, <code>SAVEVALUE<\/code>s and <code>NAME<\/code>s… prefixing them with <code>\"CX$_\"<\/code>.<br>And when we want to access those same parameters, we must do so using parentheses, again avoiding unwanted nesting.<\/p>\r\n<p>For example:<\/p>\r\n<pre>savevalue CX$_ALTO, 100<\/pre>\r\n<p>…is retrieved with the <code>SNA<\/code>:<\/p>\r\n<pre>X$(CX$_ALTO)<\/pre>\r\n<h3>And with this, we will be able to create and move as many tank instances as we want<\/h3>\r\n<p>All this material is placed in a separate file and included from the main program using <code>include<\/code>.<\/p>\r\n<h3>Summary of key concepts of this technique:<\/h3>\r\n<p>The dot separation in a CALL of the form aaa.bbb.ccc is interpreted as follows:<br><br>- The context (CX$) is \"aaa\"<br><br>- The real name of the executed procedure is bbb.ccc<br><br>- CX$ is a key SNA that represents the current call context and can be used to build dynamic names.<br><br>- Variables (ASSIGN or SAVEVALUE) are overwritten if they are not inside the context. Always use:<\/p>\r\n<pre>ASSIGN CX$_name, value<\/pre>\r\n<p>…to avoid collisions between instances.<\/p>\r\n<p>- If the method needs to return a value (like a \"get\"), you can do:<\/p>\r\n<pre>CALL aaa.bbb.get<\/pre>\r\n<p>…and then obtain the return with:<\/p>\r\n<pre>P$(get)<\/pre>\r\n<p>- All internal <code>SAVEVALUE<\/code>s should use <code>CX$_<\/code> to be private to each instance.<br>Example:<\/p>\r\n<pre>SAVEVALUE CX$_estado, 1<\/pre>\r\n<p><strong>IMPORTANT<\/strong>: EVs created with <code>SIGNAL<\/code> or <code>TIMEOUT<\/code> die when the procedure finishes, and their <code>ASSIGN<\/code>s disappear.<br>Only <code>CALL<\/code> uses a real entity that keeps its variables.<\/p>\r\n<p>- For consistency and encapsulation, everything that is used from outside a \"class\" should be accessed through its methods:<\/p>\r\n<pre>CALL instance.object.method,...<\/pre>\r\n<p>…and <strong>not<\/strong> by directly accessing the internal names of graphics, variables or resources.<\/p>\r\n<h3>In the example:<\/h3>\r\n<p>There are two files: the main one and a library called <b>.\/library_graphics\/tank.lib<\/b>.<\/p>\r\n<p>You can view the code by opening it from the \"OPEN\" menu.<\/p>\r\n<p>The most interesting part is that the library is configured from the main program in PRE_RUN:<\/p>\r\n<pre>assign config,{title:\"deposito\"\r\n        ,x:100,y:100\r\n        ,width:50 ,height:180\r\n        ,value:88\r\n        ,\"color\":\"#ff0000\"}\r\n\r\ncall aaa.tank.init,V$config<\/pre>\r\n<p>And then used directly from the program with <code>CALL<\/code>:<\/p>\r\n<pre>CALL aaa.tank.set, 10\r\n\r\nCALL aaa.tank.get\r\nMOVE {NAME:Text1, TEXT:\"Current value aaa: P$(get)\"}<\/pre>",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            },
            {
                "id": "358",
                "nombre": "Modules",
                "texto": "\/*\r\n\r\nContexts and modules. Simple module\r\n\r\n\r\n*\/\r\nSYSTEM {TYPE:OPTIONS, SPEED:5}\r\nSYSTEM {TYPE:PRE_RUN,TRIGGER:PRE_RUN}\r\nPosition {NAME:POS1,X:147,Y:311}\r\n\r\nSTART 200\r\n\r\ninclude \".\/manual_es\/Season_07_Contextos_y_modulos\/modulo.mod\"\r\n\r\nPROCEDURE PRE_RUN\r\n\r\n\tassign config,{title:\"Plant_A\"\r\n    \t\t,x:350,y:500\r\n            }\r\n\tCALL plantaA.plantaReciclaje.init,V$config\r\n\t\r\n\tassign config,{title:\"Plant B\"\r\n    \t\t,x:350,y:100\r\n            }\r\n\tCALL plantaB.plantaReciclaje.init,V$config\r\n\r\n    TERMINATE_VE\r\nENDPROCEDURE\r\n\r\n;------------------------------------------------------\r\n; --- Entity flow ---\r\nGENERATE 6,0 {NAME:GEN1,x:58,y:310} \r\n\r\nadvance 15,0 {to:POS1}\r\n\r\nif (RANDOM > 0.5)\r\nscape plantaReciclaje {cx:\"plantaA\"}\r\nelse\r\nscape plantaReciclaje {cx:\"plantaB\"}\r\nendif\r\n\r\nTERMINATE 1\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n",
                "descripcion": "<p>We have already seen contexts <code>CX$<\/code>, which—very roughly—are a special assign of type string used so that variable names do not collide, and which is inherited from caller to callee. That is, if we do <code>TIMEOUT<\/code>, the VE that executes the <code>PROCEDURE<\/code> will do so with the same <code>CX$<\/code> value as the one that called it.<\/p>\r\n<p>It can also be set with the <code>CX<\/code> BLOCK:<\/p>\r\n<pre>\r\nCX \"sevilla\"<\/pre>\r\n<p>And from that point on, the SNA <code>CX$<\/code> will have that value.<\/p>\r\n<p>Now that we know how to create graphic elements with <code>NEWGRAPHIC<\/code> passing the context, let’s see how to create a complete module with the same system.<\/p>\r\n<p>A module is a set of GENERATEs, NEWFACILITYs, PROCEDUREs... that would work on their own, normally under a context, and that usually contain at least one <code>GENERATE<\/code>. All of this goes into a single file that we will call with the \".mod\" extension.<\/p>\r\n<p>The most distinctive thing about these modules is that they are used with an <code>INCLUDE<\/code>, and the parameters will affect what is in the block area, but not what is a <code>GENERATE<\/code>&nbsp;because it is the BLOCK\/COMMAND that is not exactly a BLOCK, but is also a <u>program point<\/u> that creates entities and is the safe place to send an entity with <code>SCAPE<\/code> or <code>UNLOAD<\/code>.<\/p>\r\n<p>So it makes no sense to do something like:<\/p>\r\n<pre><strike>GENERATE {name: CX$_gen,x:100,y:200}<\/strike><\/pre>\r\n<p>because a virtual entity is not going to pass through it to create the GENERATE, nor will it be able to perform a <strike>NEWGENERATE<\/strike>.<\/p>\r\n<p>This <em>is<\/em> what a <code>GENERATE<\/code> looks like inside a module:<\/p>\r\n<pre>\r\nGENERATE 0,0,0,0 {name:hub,visible:0,x:700,y:100}\r\n    advance 10,30 {from: hub , to:\"CX$_posicion\"}\r\nENDGENERATE\r\n;-------------------------------------------\r\nPROCEDURE hub.init\r\n;... resource creation\r\nENDPROCEDURE<\/pre>\r\n<p>When <code>INCLUDE<\/code> is executed, the only thing that happens is that this file becomes part of the general code. The GPSS-Plus code texts are concatenated as-is.<\/p>\r\n<p>So the code will now have a new <code>GENERATE<\/code> called \"hub\", which can be the landing point for any entity that arrives via <code>SCAPE<\/code> or <code>UNLOAD<\/code>. The important thing is that those entities land with the correct <code>CX$<\/code>.<\/p>\r\n<p>For this reason, a module without a GENERATE cannot receive entities from outside, so it cannot work as an autonomous subsystem. In this example, \"hub\" is the reference to the program point.<\/p>\r\n<p>In short, what we will normally have in a module is one or several GENERATEs that will process entities coming from other contexts or modules, or from the main program, with access to resources under that same context.<\/p>\r\n<p>In the example we will see a basic system.<\/p>\r\n<p>From the main GENERATE, entities branch out to end up in a set of resources that, as a whole, are a module called \"plantaReciclaje\".<\/p>\r\n<p>This module has, in addition to an \".init\" similar to the initialization of any library with NewGraphic, NewFacility... the <code>GENERATE<\/code> so that entities can reach it from the main program through <code>SCAPE<\/code>:<\/p>\r\n<pre>\r\nscape plantaReciclaje {cx:\"plantaA\"}<\/pre>\r\n<p>And it will make each entity arrive at the \"plantaReciclaje\" generate with an empty return-address stack but all assigns intact and the context value set.<\/p>\r\n<pre>\r\ngenerate 0,0,0,0 {name:plantaReciclaje,visible:0}\r\n    call procesar\r\n    terminate 1\r\nendgenerate\r\n\r\nprocedure procesar\r\n    advance 10,10 {to:CX$_pos_in}\r\n    advance 10,10 {to:CX$_fac1}\r\n    seize CX$_fac1\r\n    advance 10,10\r\n    release CX$_fac1\r\n    advance 10,10 {to:CX$_pos_out}\r\nendprocedure<\/pre>\r\n<p>&nbsp;In a way, it is somewhat like the classic \"GOTO\" instruction, but where the jump is only allowed to a safe program point, which is the <code>GENERATE<\/code>.<\/p>\r\n<p>&nbsp;<\/p>",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            },
            {
                "id": "352",
                "nombre": "Modules. Complete example",
                "texto": "SYSTEM {TYPE:OPTIONS, SPEED:5}\r\nSYSTEM {TYPE:VISUAL,  WIDTH:900,HEIGHT:600}\r\nSYSTEM {TYPE:PRE_RUN,TRIGGER:PRE_RUN}\r\n\r\nSTART 1\r\n\r\ninclude .\/logistica\/namespace.mod\r\ninclude .\/logistica\/punto_distribucion.mod\r\ninclude .\/logistica\/hub_distribucion.mod\r\ninclude .\/logistica\/transportes.mod\r\n\r\nPROCEDURE PRE_RUN\r\n\tCALL crear_puntos_de_distribucion\r\n    CALL hub_distribucion.init\r\n    TERMINATE_VE\r\nENDPROCEDURE\r\n\r\n;------------------------------------------------------\r\nprocedure crear_puntos_de_distribucion\r\n\r\n\r\n    FOREACH ciudad, IN_OBJECT, V$(aCiudades)\r\n        assign datosCiudad, V$(aCiudades.P$ciudad)\r\n        \r\n        assign config,{\r\n    \t\ttitle:\"P$(ciudad)\"\r\n    \t\t,x:P$(datosCiudad.x)\r\n            ,y:P$(datosCiudad.y) \r\n            }\r\n\tcall P$ciudad.punto_distribucion.init,V$config\r\n        \r\n    ENDFOREACH\r\nendprocedure\r\n\r\n",
                "descripcion": "<p>Let’s look at an example of a logistics control system.<\/p>\r\n<p>Each module is loaded through an <code>INCLUDE<\/code> that specializes in a specific responsibility.<\/p>\r\n<p>A JSON containing data for several cities will be the starting point to create the sets of resources in a way analogous to what we have already seen.<\/p>\r\n<p>Packages are generated at each <code>punto_distribucion<\/code> and stored in a <code>RESTROOM<\/code> specific to that point.<\/p>\r\n<p>A van travels through the distribution points, loading packages into its BACKPACK from the corresponding <code>RESTROOM<\/code>. BACKPACKs and <code>RESTROOM<\/code>s are compatible with each other; it is not possible to place entities from any other resource into a backpack.<\/p>\r\n<p>The van unloads all entities at the safe <code>GENERATE<\/code> point called <code>hub_distribucion<\/code>, which is responsible for classifying the packages into different <code>RESTROOM<\/code>s. After that, the van loads each already-classified sack and makes the route again, delivering the packages to their destination.<\/p>\r\n<p>In the end, this is a small example—about 150 lines of code—to implement something that appears complex.<\/p>\r\n<p>&nbsp;<\/p>",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            },
            {
                "id": "373",
                "nombre": "Rehydration",
                "texto": "SYSTEM {TYPE:PRE_RUN,TRIGGER:PRE_RUN}\r\n\r\nPOSITION {NAME:Pos1,X:368,Y:429}\r\nPOSITION {NAME:Pos2,X:634,Y:452}\r\nPOSITION {NAME:Pos3,X:592,Y:164}\r\nPOSITION {NAME:Pos4,X:343,Y:217}\r\n\r\ninitial fsm_camion_logic, {\r\n    STATES: [\r\n        \"F1\", \"F2\", \"F3\", \"F4\"\r\n    ],\r\n\r\n    TRANSITIONS: [\r\n        {FROM:\"F1\", INPUT:\"tick\", TO:\"F2\"},\r\n        {FROM:\"F2\", INPUT:\"tick\", TO:\"F3\"},\r\n        {FROM:\"F3\", INPUT:\"tick\", TO:\"F4\"},\r\n        {FROM:\"F4\", INPUT:\"tick\", TO:\"F1\"}\r\n    ],\r\n\r\n    INITIAL: \"F1\"\r\n}\r\n\r\nFSM {NAME:FSM_CAMION, LOCAL:1, LOGIC:V$(fsm_camion_logic)}\r\nFACILITY {NAME:Fac1,X:633,Y:385}\r\nGraphic {NAME:Text1,Type:TEXT,X:324,Y:100}\r\n\r\nSTART 100\r\n;-------------------------------\r\nPROCEDURE PRE_RUN \r\n  FORWARD_AC1 105\r\n    assign params,{status:\"F2\",tiempoIni:90,tiempo:110,matricula:\"1111\"}\r\n\tnew GEN1,0,V$params\r\n    assign params,{status:\"F3\",tiempoIni:88,tiempo:108,matricula:\"2222\"}\r\n\tnew GEN1,0,V$params\r\n    assign params,{status:\"F2\",tiempoIni:89,tiempo:109,matricula:\"3333\"}\r\n\tnew GEN1,0,V$params\r\n    assign params,{status:\"F2\",tiempoIni:104,tiempo:124,matricula:\"4444\"}\r\n\tnew GEN1,0,V$params\r\n\tTERMINATE_VE \r\nENDPROCEDURE\r\n\r\n;-------------------------------\r\nPROCEDURE camion_update\r\n\t; PARAM_A -> Numero entidad\r\n\t; PARAM_B -> tiempo final\r\n\t; PARAM_C -> tiempo inicial\r\n\tmove {name:Text1,text:\"camion_update P$(FSM_CAMION,P$PARAM_A) P$PARAM_C\"}\r\n    if (D$(IN_ADVANCE,P$PARAM_A)==1)\r\n    \tupdate P$PARAM_A, P$PARAM_B, P$PARAM_C\r\n    endif\r\n    TERMINATE_VE\r\nendprocedure 1\r\n;-------------------------------\r\n\r\nGENERATE 0,0,0,0 {NAME:GEN1,X:62,Y:396}\r\n    assign params,V$PARAM_A\r\n    assign FSM_CAMION,\"P$(params.status)\"\r\n    mod {subtitle:\"P$(params.matricula)\"}\r\n    ; debe ser una VE y que se ejecute una vez hayan arrancado los advance.\r\n    timeout camion_update,0,D$N,P$(params.tiempo),P$(params.tiempoIni)\r\n\t\r\n   ; move {name:Text1,text:\"Camión inicializado P$PARAM_C R$(FSM_CAMION,STATE) P$FSM_CAMION\"}\r\n\twhile (1==1)\r\n    \tSTATE FSM_CAMION,\"tick\"\r\n        \r\n    \tswitch \"R$(FSM_CAMION,STATE)\"\r\n\t    case ==,\"F1\"\r\n\t        advance 20 {from:Pos4, to:Pos1}\r\n        endcase\r\n\t    case ==,\"F2\"\r\n        \t advance 20 {from:Pos1, to:Pos2}\r\n        endcase\r\n\t    case ==,\"F3\"\r\n            seize Fac1\r\n  \t        advance 40 {from:Pos2, to:Pos3}\r\n            release Fac1\r\n        endcase\r\n\t    case ==,\"F4\"\r\n\t        advance 20 {from:Pos3, to:Pos4}\r\n        endcase\r\n\r\n        endswitch\r\n    endwhile\r\n\r\nendgenerate 1\r\n;-------------------------------\r\n\r\n\r\n",
                "descripcion": "<p>An advanced and complex concept as the system grows is <b>rehydration<\/b>.<\/p>\r\n<p>Rehydration means <strong>loading the system state not from the beginning, but from a later point in time<\/strong>, rebuilding the simulation exactly as it was at that instant.<br>\r\nIn the logistics example this is fundamental: it is not the same to “start simulating packages” as it is to <strong>load the real state from an ERP<\/strong> and continue the simulation from there.<\/p>\r\n<p>In this approach, the modeler becomes responsible for storing everything they want to be able to restore later.<\/p>\r\n<p>&nbsp;<\/p>\r\n<p>This process implies solving <strong>three deep problems<\/strong>:<\/p>\r\n<p>&nbsp;<\/p>\r\n<ol>\r\n    <li>The global simulated time (AC1) must advance to the saved instant.<\/li>\r\n    <li>Entities must reschedule their internal times, which must always be later than the new AC1.<\/li>\r\n    <li><b>The way of modeling changes radically<\/b>: it is no longer enough to describe processes; now you must reconstruct them.<\/li>\r\n<\/ol>\r\n<p>At this stage, more than modeling, we are <strong>programming<\/strong>. Rehydration is a technical problem, not a declarative one.<\/p>\r\n<p><b>In the example:<\/b><\/p>\r\n<p>So suppose what we have stored is that 4 trucks were looping around a circuit with 4 positions. The last saved data are:<\/p>\r\n<ul>\r\n    <li>System time: 105<\/li>\r\n    <li>Truck 1: it went through phase F3 and would arrive at its destination at 110<\/li>\r\n    <li>Truck 2: it went through phase F1 and would arrive at its destination at 108<\/li>\r\n    <li>Truck 3: it went through phase F3 and would arrive at its destination at 109<\/li>\r\n    <li>Truck 4: it went through phase F2 and would arrive at its destination at 109<\/li>\r\n<\/ul>\r\n<p>To rebuild (rehydrate) this state we need to solve the three problems above.<\/p>\r\n<p><strong><\/strong><\/p>\r\n<p><strong>1. Advance global time<\/strong><\/p>\r\n<p>The <code>FORWARD_AC1<\/code> block allows moving the simulated clock forward.<br>\r\nTypically you place it as the <strong>first instruction of <code>PRE_RUN<\/code><\/strong>, so the model starts directly at the desired instant.<\/p>\r\n<p><strong><\/strong><\/p>\r\n<p><strong>2. Reschedule entity times<\/strong><\/p>\r\n<p>Once AC1 has advanced, all entities must have times <strong>after<\/strong> the new AC1.<br>\r\nThis is achieved with <code>UPDATE<\/code>, which reschedules the end of an <code>ADVANCE<\/code>. In this case, we also provide the start time so that visualization begins where it left off.<\/p>\r\n<p>The only condition is critical:<\/p>\r\n<p><strong>UPDATE must be executed by a VE when the entity is already inside an ADVANCE.<\/strong><br>\r\nThat is why rehydration requires a small temporal choreography: first we put it into the corresponding queue and then we update its times through an immediate <code>TIMEOUT<\/code>.<\/p>\r\n<p><strong><\/strong><\/p>\r\n<p><strong>3. Rebuild the program point<\/strong><\/p>\r\n<p>This is the most complex problem.<br>\r\nIf there were a <code>GOTO<\/code>, it would be trivial: we would jump to the exact point where each entity was.<br>\r\nBut it does not exist, and it must not exist.<\/p>\r\n<p>The correct solution is:<\/p>\r\n<p><strong>Create a local finite-state machine (FSM) for each entity.<\/strong><\/p>\r\n<p>The FSM state represents <strong>which point in the program the entity was at<\/strong> when the system was saved.<br>\r\nThe model logic is rewritten so that each entity advances according to its state.<\/p>\r\n<p>This turns the program flow into an <strong>explicit automaton<\/strong>, perfectly restorable.<\/p>\r\n<p>&nbsp;<strong><\/strong><\/p>\r\n<p><strong>4. The key detail: every entity always ends up in a queue<\/strong><\/p>\r\n<p>In a DES engine, the “last state” of an entity is always one of these:<\/p>\r\n<ul>\r\n    <li><strong>The event chain<\/strong>, if it is in an <code>ADVANCE<\/code>.<\/li>\r\n    <li><strong>A resource queue<\/strong>, if it is in a <code>SEIZE<\/code>.<\/li>\r\n    <li><strong>An explicit queue<\/strong>, if it is waiting.<\/li>\r\n<\/ul>\r\n<p>Therefore:<\/p>\r\n<p>&nbsp;<\/p>\r\n<p><strong>The FSM states must correspond to these queues.<\/strong><\/p>\r\n<p>&nbsp;<\/p>\r\n<p>We do not need to reconstruct internal queues or manipulate hidden structures:<br>\r\nit is enough to reinsert entities at the correct program point, and the engine rebuilds the rest automatically.<\/p>\r\n<p>&nbsp;<\/p>",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            }
        ]
    },
    {
        "id": "236",
        "nombre": "Season 8: Statistics",
        "texto": "",
        "descripcion": "",
        "parametros": null,
        "parametros_json": null,
        "ejemplo": null,
        "hijos": [
            {
                "id": "234",
                "nombre": "Accumulating data in tables",
                "texto": "\/*\r\n\r\n  \t \tAccumulating data in tables\r\n \r\n*\/\r\nFACILITY {NAME:VENTANILLA1,X:380,Y:348,capacity:4}\r\nPOSITION {NAME:POS1,X:218,Y:437}\r\nPOSITION {NAME:POS2,X:591,Y:429}\r\nPOSITION {NAME:POS3,X:713,Y:329}\r\n\r\nGraphic {NAME:Line1,Type:LINE,color:#FF0000, X1:218,Y1:500,X2:592,Y2:500}\r\nGraphic {NAME:Text1,Type:TEXT,X:410,Y:527,Text:\"Statistics section\"}\r\n\r\nTABLE {name: TABLA1,E_BIN_START:50,E_BIN_SIZE:1,E_BIN_COUNT:60,EXPRESSION:(AC1$ - P$TIEMPOINICIO)}\r\n;TABLE {name: TABLA1,E_BIN_START:0,E_BIN_SIZE:1,E_BIN_COUNT:160,EXPRESSION:(AC1$ - D$M0)}\r\n\r\nSTART 500 \r\n\r\n;***************************************************************\r\n\r\nGENERATE 8,3 {NAME:GEN1,X:66,Y:350}\r\n\r\n    ADVANCE 40,0 {TO:POS1}\r\n    ASSIGN TIEMPOINICIO,AC1$\r\n    ADVANCE 20,0 {TO:VENTANILLA1}\r\n\r\n    SEIZE VENTANILLA1\r\n    ADVANCE 20,20\r\n    RELEASE VENTANILLA1\r\n\r\n    ADVANCE 20,0 {TO:POS2}\r\n    TABULATE TABLA1\r\n    ADVANCE 20,0 {TO:POS3}\r\n\r\nENDGENERATE 1\r\n\r\n;***************************************************************\r\n",
                "descripcion": "<p data-start=\"385\" data-end=\"574\">Simulation and statistics go hand in hand. We can do very little if some basic concepts are not clear. In GPSS-Plus, statistical calculations are divided into three major groups:<\/p>\r\n<ol data-start=\"576\" data-end=\"823\">\r\n    <li data-start=\"576\" data-end=\"658\">\r\n    <p data-start=\"579\" data-end=\"658\"><strong data-start=\"579\" data-end=\"630\">Times an entity remains in a resource<\/strong> (entity-oriented).<\/p>\r\n    <\/li>\r\n    <li data-start=\"659\" data-end=\"741\">\r\n    <p data-start=\"662\" data-end=\"741\"><strong data-start=\"662\" data-end=\"715\">Times a number of entities occupy a resource<\/strong> (resource-oriented).<\/p>\r\n    <\/li>\r\n    <li data-start=\"742\" data-end=\"823\">\r\n    <p data-start=\"745\" data-end=\"823\"><strong data-start=\"745\" data-end=\"782\">Any other custom data<\/strong> you want to measure (model-oriented).<\/p>\r\n    <\/li>\r\n<\/ol>\r\n<p data-start=\"825\" data-end=\"975\">In this first example, we work with <strong data-start=\"1035\" data-end=\"1045\">case 3<\/strong>, where we want to measure the <strong data-start=\"1071\" data-end=\"1132\">time an entity remains in a section of the circuit<\/strong>, including a resource (a <code data-start=\"1161\" data-end=\"1171\">FACILITY<\/code>) and its surrounding area.<\/p>\r\n<h4 data-start=\"977\" data-end=\"1032\">Using TABLE to record residence times:<\/h4>\r\n<p data-start=\"1034\" data-end=\"1189\">GPSS-Plus automates much of the work. You only need to create a <code data-start=\"1152\" data-end=\"1159\">TABLE<\/code> with the appropriate parameters:<\/p>\r\n<pre>\r\nTABLE {name: TABLA1, E_BIN_START:0, E_BIN_SIZE:1, E_BIN_COUNT:100, EXPRESSION:(AC1$ - P$TIEMPOINICIO)}\r\n<\/pre>\r\n<p data-start=\"1306\" data-end=\"1550\">This configures a table with 100 bins of width 1, starting at 0. Each time <code data-start=\"1409\" data-end=\"1426\">TABULATE TABLA1<\/code> is executed, the <b>EXPRESSION<\/b> is evaluated:<\/p>\r\n<pre><b>(AC1$ - P$TIEMPOINICIO)<\/b><\/pre>\r\n<p data-start=\"1306\" data-end=\"1550\">which computes the difference between the current time (<code data-start=\"1479\" data-end=\"1485\">AC1$<\/code>) and a previously stored instant (<code data-start=\"1511\" data-end=\"1527\">P$TIEMPOINICIO<\/code>).<\/p>\r\n<p data-start=\"1552\" data-end=\"1664\">This value, representing the entity’s residence time within the modeled zone, is accumulated in the corresponding bin.<\/p>\r\n<h4 data-start=\"1666\" data-end=\"1688\">A basic example<\/h4>\r\n<p data-start=\"1690\" data-end=\"1844\">We create entities that move <b>FROM ONE POINT<\/b>, pass through a <code data-start=\"1730\" data-end=\"1740\">FACILITY<\/code>, and reach <b>ANOTHER POINT<\/b>, then tabulate the duration:<\/p>\r\n<pre>\r\nGENERATE 8,3\r\n    ADVANCE 30,0 {TO:POS1}\r\n    ASSIGN TIEMPOINICIO,AC1$      ; Start timing\r\n    ADVANCE 20,0 {TO:VENTANILLA1}\r\n\r\n    SEIZE VENTANILLA1\r\n    ADVANCE 20,20                 ; +20 to +40 (random) + queue time\r\n    RELEASE VENTANILLA1\r\n\r\n    ADVANCE 20,0 {TO:POS2}\r\n    TABULATE TABLA1               ; End timing\r\n    ADVANCE 20,0 {TO:POS3}\r\n\r\nENDGENERATE\r\n<\/pre>\r\n<h4 data-start=\"2026\" data-end=\"2050\">What does the table measure?<\/h4>\r\n<p data-start=\"2052\" data-end=\"2282\">If you inspect the report output, you will see a <strong data-start=\"2129\" data-end=\"2157\">rectangular (uniform) distribution<\/strong> between 60 and 80, <b>with some higher values for entities that spent time waiting in the queue<\/b>. That is, all entities remained within that expected range.<\/p>\r\n<p data-start=\"2284\" data-end=\"2397\">This is a solid starting point for analyzing internal model behavior using objective data.<\/p>",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            },
            {
                "id": "357",
                "nombre": "Entity time",
                "texto": "\/*\r\n\r\n  \t \tEntity time\r\n \r\n*\/\r\nSYSTEM {TYPE:OPTIONS,Speed:7}\r\nPOSITION {NAME:POS1,X:620,Y:360}\r\nFacility {NAME:ventanilla1,X:377,Y:362,capacity:10,E_BIN_START:18,E_BIN_SIZE:1,E_BIN_COUNT:14}\r\nSTART 200\r\n\r\n;*****************************************************\r\nGENERATE 8,0,0,0 {NAME:GEN1,X:111,Y:366}\r\nADVANCE 10 {TO:ventanilla1}\r\n\r\nseize ventanilla1\r\nADVANCE 20,10\r\nrelease ventanilla1\r\n\r\nADVANCE 10 {TO:POS1}\r\nTERMINATE 1\r\n\r\n\r\n",
                "descripcion": "<p data-start=\"214\" data-end=\"355\">We now move on to statistics focused on the <strong>time entities spend in a resource<\/strong>.<\/p>\r\n<p data-start=\"214\" data-end=\"355\">Statistics calculated on a single resource are computed automatically by GPSS-Plus:<\/p>\r\n<pre>\r\nFacility {NAME:ventanilla1,X:377,Y:362,capacity:10\r\n     ,E_BIN_START:18,E_BIN_SIZE:1,E_BIN_COUNT:14\r\n     }<\/pre>\r\n<p data-start=\"357\" data-end=\"556\">We measure the time that an entity (E) remains in the resource using the <code data-start=\"448\" data-end=\"457\">E_BIN_*<\/code> parameters, which have the same meaning as in the <code>TABLE<\/code> block.<\/p>\r\n<p data-start=\"722\" data-end=\"948\">In the following example, entities are generated at a constant rate, and the <code data-start=\"795\" data-end=\"805\">FACILITY<\/code> contains an ADVANCE 20,10, meaning the statistical results will fall between 20 and 30.<\/p>",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            },
            {
                "id": "237",
                "nombre": "Resource usage",
                "texto": "\/*\r\n\r\n  \t \tResource usage\r\n \r\n*\/\r\nSYSTEM {TYPE:OPTIONS,Speed:7}\r\nPOSITION {NAME:POS1,X:620,Y:360}\r\nFacility {NAME:ventanilla1,X:377,Y:362,capacity:10,R_BIN_START:0,R_BIN_SIZE:1,R_BIN_COUNT:11}\r\nSTART 200\r\n\r\n;*****************************************************\r\nGENERATE 5,3,0,0 {NAME:GEN1,X:111,Y:366}\r\nADVANCE 10 {TO:ventanilla1}\r\n\r\nseize ventanilla1\r\nADVANCE 20,10\r\nrelease ventanilla1\r\n\r\nADVANCE 10 {TO:POS1}\r\nENDGENERATE 1\r\n\r\n",
                "descripcion": "<p data-start=\"214\" data-end=\"355\">We now move on to statistics focused on the <strong data-start=\"263\" data-end=\"284\">usage of a resource<\/strong>, that is, how much time it has been occupied by one or more entities.<\/p>\r\n<p data-start=\"357\" data-end=\"556\">If previously we measured the time an entity (E) remains in the resource using the <code data-start=\"448\" data-end=\"457\">E_BIN_*<\/code> parameters, now, to observe <strong data-start=\"480\" data-end=\"537\">how busy the resource has been at each moment<\/strong>, we use <code data-start=\"546\" data-end=\"555\">R_BIN_*<\/code>.<\/p>\r\n<p data-start=\"558\" data-end=\"720\">The table created with <code data-start=\"578\" data-end=\"587\">R_BIN_*<\/code> indicates, for each occupancy level (0, 1, 2, ...), <strong data-start=\"645\" data-end=\"662\">how long<\/strong> the resource has been exactly at that level of usage.<\/p>\r\n<p data-start=\"722\" data-end=\"948\">In the following example, entities are generated at a constant rate, and the <code data-start=\"795\" data-end=\"805\">FACILITY<\/code> tends to have <strong data-start=\"821\" data-end=\"854\">between 4 and 6 units occupied<\/strong>, which will appear as a peak in that range in the automatically generated chart.<\/p>\r\n<p data-start=\"950\" data-end=\"1122\">Of course, nothing prevents you from using both <code data-start=\"994\" data-end=\"1003\">E_BIN_*<\/code> and <code data-start=\"1006\" data-end=\"1015\">R_BIN_*<\/code> on the same resource if you want a view from both perspectives: the entity’s and the resource’s.<\/p>\r\n<p>&nbsp;<\/p>",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            },
            {
                "id": "238",
                "nombre": "Queues",
                "texto": "\/*\r\n\r\n  \t \tQueues\r\n \r\n*\/\r\nSYSTEM {TYPE:OPTIONS,Speed:7}\r\nPOSITION {NAME:POS1,X:620,Y:360}\r\n\r\nQUEUER {NAME:Qventanilla1,X:374,Y:424\r\n\t,R_BIN_START:0,R_BIN_SIZE:1,R_BIN_COUNT:20 \r\n    ,E_BIN_START:0,E_BIN_SIZE:1,E_BIN_COUNT:20\r\n    }\r\n\r\nFacility {NAME:ventanilla1,X:373,Y:365,capacity:5}\r\nSTART 200\r\n\r\n;*****************************************************\r\nGENERATE 5,3,0,0 {NAME:GEN1,X:111,Y:366}\r\nADVANCE 10 {TO:ventanilla1}\r\n\r\nqueue Qventanilla1\r\nseize ventanilla1\r\ndepart Qventanilla1\r\nADVANCE 20,10\r\nrelease ventanilla1\r\n\r\nADVANCE 10 {TO:POS1}\r\nENDGENERATE 1\r\n",
                "descripcion": "<p data-start=\"228\" data-end=\"449\">Queues can also be analyzed statistically. In GPSS-Plus, they behave exactly like resources, but they are managed separately through specific structures called <code data-start=\"427\" data-end=\"435\">QUEUER<\/code>.<\/p>\r\n<p data-start=\"451\" data-end=\"556\">To enable statistics collection, it is enough to wrap access to the resource with <code data-start=\"537\" data-end=\"544\">QUEUE<\/code> and <code data-start=\"547\" data-end=\"555\">DEPART<\/code>:<\/p>\r\n<pre>\r\nqueue Qventanilla1\r\nseize ventanilla1\r\ndepart Qventanilla1<\/pre>\r\n<p data-start=\"628\" data-end=\"667\">This enables the automatic calculation of:<\/p>\r\n<ul data-start=\"669\" data-end=\"807\">\r\n    <li data-start=\"669\" data-end=\"739\">\r\n    <p data-start=\"671\" data-end=\"739\"><strong data-start=\"671\" data-end=\"705\">The number of entities in the queue<\/strong> over time (<code data-start=\"729\" data-end=\"738\">R_BIN_*<\/code>)<\/p>\r\n    <\/li>\r\n    <li data-start=\"740\" data-end=\"807\">\r\n    <p data-start=\"742\" data-end=\"807\"><strong data-start=\"742\" data-end=\"765\">The waiting time<\/strong> each entity spends in the queue (<code data-start=\"797\" data-end=\"806\">E_BIN_*<\/code>)<\/p>\r\n    <\/li>\r\n<\/ul>\r\n<p data-start=\"809\" data-end=\"989\">In the report, you can visualize graphically how the queue behaved: when it formed, how long entities waited, and whether the resource sizing was sufficient.<\/p>\r\n<p data-start=\"991\" data-end=\"1153\">The following example shows a <code data-start=\"1024\" data-end=\"1034\">FACILITY<\/code> with frequent queues. By applying <code data-start=\"1068\" data-end=\"1075\">QUEUE<\/code>\/<code data-start=\"1076\" data-end=\"1084\">DEPART<\/code>, the system captures all the statistics with no additional code.<\/p>\r\n<p data-start=\"451\" data-end=\"556\">&nbsp;<\/p>\r\n<p>&nbsp;<\/p>",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            },
            {
                "id": "239",
                "nombre": "Storages",
                "texto": "\/*\r\n\r\n  \t \tStorages\r\n \r\n*\/\r\nSYSTEM {TYPE:OPTIONS,Speed:7}\r\nPOSITION {NAME:POS1,X:620,Y:360}\r\nSTORAGE {NAME:almacen1,X:377,Y:362,capacity:14\r\n\t,EQ_BIN_START:18,EQ_BIN_SIZE:1,EQ_BIN_COUNT:14 \r\n    ,RQ_BIN_START:0,RQ_BIN_SIZE:1,RQ_BIN_COUNT:18\r\n    }\r\nSTART 200\r\n\r\n;*****************************************************\r\nGENERATE 8,0,0,0 {NAME:GEN1,X:111,Y:366}\r\nADVANCE 10 {TO:almacen1}\r\n\r\nENTER almacen1,(RANDOM*5)+1\r\nADVANCE 20,10\r\nLEAVE almacen1\r\n\r\nADVANCE 10 {TO:POS1}\r\nENDGENERATE 1\r\n",
                "descripcion": "<p data-start=\"231\" data-end=\"446\"><code data-start=\"235\" data-end=\"244\">STORAGE<\/code> resources are a special type of resource. Unlike <code data-start=\"298\" data-end=\"308\">FACILITY<\/code>, which manage entities individually, a <code data-start=\"358\" data-end=\"367\">STORAGE<\/code> manages <strong data-start=\"377\" data-end=\"401\">variable quantities<\/strong> that an entity can put in or take out.<\/p>\r\n<p data-start=\"448\" data-end=\"684\">For example, an entity can represent a truck that drops 10 units into a depot. Therefore, the system does not analyze how many entities went through the storage, but <strong data-start=\"621\" data-end=\"641\">how many units<\/strong> were stored and for how long.<\/p>\r\n<h4 data-start=\"686\" data-end=\"704\">What is measured?<\/h4>\r\n<p data-start=\"706\" data-end=\"743\">Two types of statistics are collected:<\/p>\r\n<ul data-start=\"745\" data-end=\"934\">\r\n    <li data-start=\"745\" data-end=\"848\">\r\n    <p data-start=\"747\" data-end=\"848\"><strong data-start=\"747\" data-end=\"758\">EQ_BIN_<\/strong>*: Time each unit remains in storage (occupancy time per unit).<\/p>\r\n    <\/li>\r\n    <li data-start=\"849\" data-end=\"934\">\r\n    <p data-start=\"851\" data-end=\"934\"><strong data-start=\"851\" data-end=\"862\">RQ_BIN_<\/strong>*: Storage occupancy level at each moment (by quantity).<\/p>\r\n    <\/li>\r\n<\/ul>\r\n<p data-start=\"936\" data-end=\"1091\">This behavior is enabled the same way as with other resources, but using the <code data-start=\"1022\" data-end=\"1032\">EQ_BIN_*<\/code> and <code data-start=\"1035\" data-end=\"1045\">RQ_BIN_*<\/code> parameters to configure the table intervals.<\/p>\r\n<h4 data-start=\"1093\" data-end=\"1117\">A practical example<\/h4>\r\n<p data-start=\"1119\" data-end=\"1418\">The following code shows a storage (<code data-start=\"1166\" data-end=\"1175\">STORAGE<\/code>) with a capacity of 14 units. Incoming entities occupy a random amount (between 1 and 5 units). The resulting statistics will indicate how long those units stayed stored and how the storage occupancy level varied over time:<\/p>\r\n<pre>\r\nSTORAGE {NAME:almacen1,X:377,Y:362,capacity:14,\r\n         EQ_BIN_START:18,EQ_BIN_SIZE:1,EQ_BIN_COUNT:14,\r\n         RQ_BIN_START:0, RQ_BIN_SIZE:1, RQ_BIN_COUNT:18}\r\n\r\nGENERATE 8,0,0,0\r\n    ADVANCE 10 {TO:almacen1}\r\n    ENTER almacen1,(RANDOM*5)+1\r\n    ADVANCE 20,10\r\n    LEAVE almacen1\r\n    ADVANCE 10 {TO:pos1}\r\nENDGENERATE 1<\/pre>\r\n<h4 data-start=\"1747\" data-end=\"1766\">What to look at?<\/h4>\r\n<p data-start=\"1768\" data-end=\"1811\">In the report, you will see two different tables:<\/p>\r\n<ul data-start=\"1813\" data-end=\"2088\">\r\n    <li data-start=\"1813\" data-end=\"1954\">\r\n    <p data-start=\"1815\" data-end=\"1954\">One with the ranges of <strong data-start=\"1837\" data-end=\"1869\">time per stored unit<\/strong> (<code data-start=\"1871\" data-end=\"1875\">EQ<\/code>), which tells you whether units stayed for a short or long time in the storage.<\/p>\r\n    <\/li>\r\n    <li data-start=\"1955\" data-end=\"2088\">\r\n    <p data-start=\"1957\" data-end=\"2088\">Another with the <strong data-start=\"1981\" data-end=\"2006\">storage occupancy levels<\/strong> (<code data-start=\"2008\" data-end=\"2012\">RQ<\/code>), where you can see how many units were simultaneously present at each moment.<\/p>\r\n    <\/li>\r\n<\/ul>\r\n<p data-start=\"2090\" data-end=\"2209\">This type of analysis is essential in logistics, inventory, or any system with variable storage.<\/p>\r\n<p data-start=\"1119\" data-end=\"1418\">&nbsp;<\/p>\r\n<p>&nbsp;<\/p>",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            },
            {
                "id": "240",
                "nombre": "Summary",
                "texto": "",
                "descripcion": "<p data-start=\"182\" data-end=\"366\">In GPSS-Plus, statistics are accumulated automatically if tables are defined with the appropriate parameters. There are several types of statistics, classified by what is being measured:<\/p>\r\n<h4 data-start=\"368\" data-end=\"412\">Entity-based statistics (<code data-start=\"402\" data-end=\"411\">E_BIN_*<\/code>)<\/h4>\r\n<p data-start=\"413\" data-end=\"474\">They measure how long each entity has remained in a resource.<\/p>\r\n<ul data-start=\"476\" data-end=\"629\">\r\n    <li data-start=\"476\" data-end=\"552\">\r\n    <p data-start=\"478\" data-end=\"552\"><strong data-start=\"478\" data-end=\"493\">Applicable to<\/strong>: All resources (<code data-start=\"515\" data-end=\"525\">FACILITY<\/code>, <code data-start=\"527\" data-end=\"536\">STORAGE<\/code>, <code data-start=\"538\" data-end=\"545\">QUEUE<\/code>, etc.)<\/p>\r\n    <\/li>\r\n    <li data-start=\"553\" data-end=\"629\">\r\n    <p data-start=\"555\" data-end=\"629\"><strong data-start=\"555\" data-end=\"566\">Example<\/strong>: An entity spends 40 time units → 1 is added to bin 40.<\/p>\r\n    <\/li>\r\n<\/ul>\r\n<h4 data-start=\"631\" data-end=\"675\">Resource-based statistics (<code data-start=\"665\" data-end=\"674\">R_BIN_*<\/code>)<\/h4>\r\n<p data-start=\"676\" data-end=\"759\">They measure how long a resource has had a specific number of active entities.<\/p>\r\n<ul data-start=\"761\" data-end=\"885\">\r\n    <li data-start=\"761\" data-end=\"798\">\r\n    <p data-start=\"763\" data-end=\"798\"><strong data-start=\"763\" data-end=\"778\">Applicable to<\/strong>: All resources<\/p>\r\n    <\/li>\r\n    <li data-start=\"799\" data-end=\"885\">\r\n    <p data-start=\"801\" data-end=\"885\"><strong data-start=\"801\" data-end=\"812\">Example<\/strong>: The resource has 3 entities for 10 time units → 10 is added to bin 3.<\/p>\r\n    <\/li>\r\n<\/ul>\r\n<h4 data-start=\"887\" data-end=\"942\">Statistics per stored unit (<code data-start=\"931\" data-end=\"941\">EQ_BIN_*<\/code>)<\/h4>\r\n<p data-start=\"943\" data-end=\"1007\">They measure how long each unit remains inside a <code data-start=\"997\" data-end=\"1006\">STORAGE<\/code>.<\/p>\r\n<ul data-start=\"1009\" data-end=\"1126\">\r\n    <li data-start=\"1009\" data-end=\"1042\">\r\n    <p data-start=\"1011\" data-end=\"1042\"><strong data-start=\"1011\" data-end=\"1026\">Applicable to<\/strong>: Only <code data-start=\"1033\" data-end=\"1042\">STORAGE<\/code><\/p>\r\n    <\/li>\r\n    <li data-start=\"1043\" data-end=\"1126\">\r\n    <p data-start=\"1045\" data-end=\"1126\"><strong data-start=\"1045\" data-end=\"1056\">Example<\/strong>: A truck with 5 units stays 40 time units → 5 is added to bin 40.<\/p>\r\n    <\/li>\r\n<\/ul>\r\n<h4 data-start=\"1128\" data-end=\"1192\">Statistics by storage quantity (<code data-start=\"1181\" data-end=\"1191\">RQ_BIN_*<\/code>)<\/h4>\r\n<p data-start=\"1193\" data-end=\"1268\">They measure how long a <code data-start=\"1215\" data-end=\"1224\">STORAGE<\/code> contains a certain total quantity of units.<\/p>\r\n<ul data-start=\"1270\" data-end=\"1371\">\r\n    <li data-start=\"1270\" data-end=\"1303\">\r\n    <p data-start=\"1272\" data-end=\"1303\"><strong data-start=\"1272\" data-end=\"1287\">Applicable to<\/strong>: Only <code data-start=\"1294\" data-end=\"1303\">STORAGE<\/code><\/p>\r\n    <\/li>\r\n    <li data-start=\"1304\" data-end=\"1371\">\r\n    <p data-start=\"1306\" data-end=\"1371\"><strong data-start=\"1306\" data-end=\"1317\">Example<\/strong>: 3 units for 10 time units → 30 is added to bin 3.<\/p>\r\n    <\/li>\r\n<\/ul>\r\n<p><b><\/b><\/p>\r\n<p><b>Queues (QUEUER)<\/b><\/p>\r\n<p data-start=\"1398\" data-end=\"1493\">Queues have their own statistics table if a <code data-start=\"1464\" data-end=\"1472\">QUEUER<\/code> is declared. To collect data:<\/p>\r\n<pre>\r\nqueue Queue1\r\nseize Resource1\r\ndepart Queue1\r\nADVANCE ...\r\nrelease Resource1<\/pre>\r\n<p data-start=\"1575\" data-end=\"1590\">You can apply:<\/p>\r\n<ul data-start=\"1592\" data-end=\"1702\">\r\n    <li data-start=\"1592\" data-end=\"1642\">\r\n    <p data-start=\"1594\" data-end=\"1642\"><code data-start=\"1594\" data-end=\"1603\">E_BIN_*<\/code>: Time each entity spent in the queue.<\/p>\r\n    <\/li>\r\n    <li data-start=\"1643\" data-end=\"1702\">\r\n    <p data-start=\"1645\" data-end=\"1702\"><code data-start=\"1645\" data-end=\"1654\">R_BIN_*<\/code>: Time the queue had X entities waiting.<\/p>\r\n    <\/li>\r\n<\/ul>\r\n<h3 data-start=\"1709\" data-end=\"1756\">Full customization: <code data-start=\"1736\" data-end=\"1743\">TABLE<\/code> + <code data-start=\"1746\" data-end=\"1756\">TABULATE<\/code><\/h3>\r\n<p data-start=\"1758\" data-end=\"1791\">To record arbitrary data:<\/p>\r\n<pre>\r\nTABLE {name:TABLA1, E_BIN_START:0, E_BIN_SIZE:1, E_BIN_COUNT:100, EXPRESSION:(AC1$ - P$TIEMPOINICIO)}\r\nTABULATE TABLA1<\/pre>\r\n<p data-start=\"1758\" data-end=\"1791\">This allows you to measure anything defined by a mathematical expression.<\/p>\r\n<p data-start=\"1758\" data-end=\"1791\">&nbsp;<\/p>\r\n<p data-start=\"1398\" data-end=\"1493\">&nbsp;<\/p>\r\n<p data-start=\"1398\" data-end=\"1493\">&nbsp;<\/p>",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            }
        ]
    },
    {
        "id": "218",
        "nombre": "Season 9: Functions",
        "texto": "",
        "descripcion": "",
        "parametros": null,
        "parametros_json": null,
        "ejemplo": null,
        "hijos": [
            {
                "id": "224",
                "nombre": "Defining functions",
                "texto": "\/*\r\n\r\n  \t \tDefining functions\r\n \r\n*\/\r\nSYSTEM {TYPE:OPTIONS,Speed:5}\r\n\r\nFacility {NAME:VENTANILLA1,X:165,Y:184,E_BIN_start:16,E_BIN_SIZE:1,E_BIN_COUNT:40,capacity:3}\r\n\r\nFacility {NAME:VENTANILLA2,X:384,Y:186,E_BIN_start:16,E_BIN_SIZE:1,E_BIN_COUNT:40,capacity:3}\r\n\r\n\r\nPOSITION {NAME:POS1,X:278,Y:381}\r\nPOSITION {NAME:POS2,X:482,Y:380}\r\n\r\nFunction {name:funGauss, type:\"GAUSS\", a:1, b:30, sigma1:3.3, sigma2:3.3,intervals:100 }\r\n\r\nFunction {NAME:funValues,type:\"VALUES\",expression:\"RANDOM\",VALUES:\"\r\n0.0001,0.0000\/0.0002,0.0101\/0.0004,0.0202\/0.0006,0.0303\/0.0008,0.0404\/\r\n0.0011,0.0505\/0.0015,0.0606\/0.0020,0.0707\/0.0025,0.0808\/0.0032,0.0909\/\r\n0.0039,0.1010\/0.0049,0.1111\/0.0060,0.1212\/0.0073,0.1313\/0.0088,0.1414\/\r\n0.0106,0.1515\/0.0128,0.1616\/0.0152,0.1717\/0.0180,0.1818\/0.0213,0.1919\/\r\n0.0250,0.2020\/0.0293,0.2121\/0.0341,0.2222\/0.0396,0.2323\/0.0458,0.2424\/\r\n0.0527,0.2525\/0.0603,0.2626\/0.0689,0.2727\/0.0783,0.2828\/0.0887,0.2929\/\r\n0.1000,0.3030\/0.1124,0.3131\/0.1258,0.3232\/0.1403,0.3333\/0.1559,0.3434\/\r\n0.1726,0.3535\/0.1904,0.3636\/0.2093,0.3737\/0.2292,0.3838\/0.2501,0.3939\/\r\n0.2720,0.4040\/0.2948,0.4141\/0.3185,0.4242\/0.3429,0.4343\/0.3680,0.4444\/\r\n0.3937,0.4545\/0.4199,0.4646\/0.4464,0.4747\/0.4731,0.4848\/0.5000,0.4949\/\r\n0.5269,0.5051\/0.5536,0.5152\/0.5801,0.5253\/0.6063,0.5354\/0.6320,0.5455\/\r\n0.6571,0.5556\/0.6815,0.5657\/0.7052,0.5758\/0.7280,0.5859\/0.7499,0.5960\/\r\n0.7708,0.6061\/0.7907,0.6162\/0.8096,0.6263\/0.8274,0.6364\/0.8441,0.6465\/\r\n0.8597,0.6566\/0.8742,0.6667\/0.8876,0.6768\/0.9000,0.6869\/0.9113,0.6970\/\r\n0.9217,0.7071\/0.9311,0.7172\/0.9397,0.7273\/0.9473,0.7374\/0.9542,0.7475\/\r\n0.9604,0.7576\/0.9659,0.7677\/0.9707,0.7778\/0.9750,0.7879\/0.9787,0.7980\/\r\n0.9820,0.8081\/0.9848,0.8182\/0.9872,0.8283\/0.9894,0.8384\/0.9912,0.8485\/\r\n0.9927,0.8586\/0.9940,0.8687\/0.9951,0.8788\/0.9961,0.8889\/0.9968,0.8990\/\r\n0.9975,0.9091\/0.9980,0.9192\/0.9985,0.9293\/0.9989,0.9394\/0.9992,0.9495\/\r\n0.9994,0.9596\/0.9996,0.9697\/0.9998,0.9798\/0.9999,0.9899\/1.0000,1.0000\/\r\n\"}\r\n\r\nSTART 500\r\n\r\n\r\n;*****************************************************\r\nGENERATE 10,0,0,0 {NAME:GEN1,X:91,Y:383}\r\n\r\nADVANCE 20,4 {TO:VENTANILLA1}\r\nSEIZE VENTANILLA1\r\nADVANCE 20  + (FN$funValues * 20) ; classic definition\r\nRELEASE VENTANILLA1\r\nADVANCE 20,0 {TO:POS1}\r\n\r\nADVANCE 20,0 {TO:VENTANILLA2}\r\n\r\nSEIZE VENTANILLA2\r\nADVANCE FN$funGauss ; parameter-based definition\r\n;ADVANCE 2 ; parameter-based definition\r\nRELEASE VENTANILLA2\r\nADVANCE 20,0 {TO:POS2}\r\n\r\nENDGENERATE 1\r\n",
                "descripcion": "<h3>What is a function?<\/h3>\r\n<p data-start=\"487\" data-end=\"732\">A <strong data-start=\"505\" data-end=\"516\">function<\/strong> is a component that produces a <strong data-start=\"549\" data-end=\"567\">numeric value<\/strong> from an input. That value can represent <strong data-start=\"621\" data-end=\"632\">times<\/strong>, <strong data-start=\"634\" data-end=\"648\">quantities<\/strong>, <strong data-start=\"650\" data-end=\"660\">costs<\/strong>, or any other variable parameter we want to incorporate into the model.<\/p>\r\n<p data-start=\"487\" data-end=\"732\">In mathematical terms, we could write something like:<\/p>\r\n<pre>\r\nf(x) = 10 + (x * 5)<\/pre>\r\n<p data-start=\"487\" data-end=\"732\">If <code data-start=\"625\" data-end=\"628\">x<\/code> takes values between 0 and 1, then <code data-start=\"664\" data-end=\"670\">f(x)<\/code> will take values between 10 and 15.<\/p>\r\n<p data-start=\"734\" data-end=\"746\">In GPSS-Plus, when we use:<\/p>\r\n<pre>\r\nADVANCE 10,5<\/pre>\r\n<p data-start=\"245\" data-end=\"533\">we are using that implicit function: it generates a random value between 0 and 1, multiplies it, and resolves a value between 10 and 15.<\/p>\r\n<p data-start=\"245\" data-end=\"533\">In statistical terms, this is a <strong data-start=\"1021\" data-end=\"1046\">uniform distribution<\/strong> between 10 and 15, meaning that <strong data-start=\"1072\" data-end=\"1139\">all values within the range have the same probability<\/strong> of occurring.<\/p>\r\n<h3>Using functions:<\/h3>\r\n<p data-start=\"1194\" data-end=\"1248\">In many cases, <strong data-start=\"1217\" data-end=\"1247\">reality is not uniform<\/strong>.<\/p>\r\n<p data-start=\"1250\" data-end=\"1453\">If we measure how long 1000 vehicles take to travel 100 km, most will take close to 1 hour. Some will take a bit less, others a bit more. But almost none will do it in 30 minutes or in 2 hours.<\/p>\r\n<p data-start=\"1455\" data-end=\"1565\">That is <strong data-start=\"1459\" data-end=\"1465\">not<\/strong> a uniform distribution. It is what is known as a <strong data-start=\"1525\" data-end=\"1548\">normal distribution<\/strong> or <strong data-start=\"1551\" data-end=\"1564\">Gaussian<\/strong>.<\/p>\r\n<p data-start=\"826\" data-end=\"964\">That is why GPSS-Plus allows defining functions that more accurately model behaviors like these. There are two ways to do it:<\/p>\r\n<h3 data-start=\"971\" data-end=\"1020\"><strong>1. FUNCTION of type <code>VALUES<\/code><\/strong><\/h3>\r\n<p data-start=\"1022\" data-end=\"1121\">With this method, we manually define a function based on a cumulative probability table.<\/p>\r\n<pre>\r\nFunction {\r\n  NAME: funValues,\r\n  TYPE: \"VALUES\",\r\n  EXPRESSION: \"RANDOM\",\r\n  VALUES: \"0.0001,0.0000\/0.0002,0.0101\/...\/1.0000,1.0000\/\"\r\n}<\/pre>\r\n<p data-start=\"826\" data-end=\"964\">This table associates keys (cumulative probabilities between 0 and 1 using <code>EXPRESSION: \"RANDOM\"<\/code>) with result values. If the generated random value is 0.33, the function finds the corresponding interval and returns the associated value, representing a bell-shaped (Gaussian) distribution, where extreme values are less likely than central ones.<\/p>\r\n<p data-start=\"826\" data-end=\"964\">So an instruction like:<\/p>\r\n<pre>\r\nADVANCE 20 + (FN$funValues * 20)<\/pre>\r\n<p data-start=\"826\" data-end=\"964\">will generate values between 20 and 40, concentrated around 30.<\/p>\r\n<h3 data-start=\"1833\" data-end=\"1881\"><strong>2. FUNCTION of type <code>GAUSS<\/code><\/strong><\/h3>\r\n<p data-start=\"1883\" data-end=\"1991\">This method allows defining a Gaussian distribution directly through its characteristic parameters:<\/p>\r\n<pre>\r\nFunction {\r\n  NAME: funGauss,\r\n  TYPE: \"GAUSS\",\r\n  A: 1,\r\n  B: 30,\r\n  SIGMA1: 3.3,\r\n  SIGMA2: 3.3,\r\n  INTERVALS: 100\r\n}<\/pre>\r\n<ul>\r\n    <li><code>A<\/code>: curve height (visual only, does not affect the result)<\/li>\r\n    <li><code>B<\/code>: central value (mean)<\/li>\r\n    <li><code>SIGMA1<\/code>, <code>SIGMA2<\/code>: left and right standard deviations<\/li>\r\n    <li><code>INTERVALS<\/code>: number of divisions for the function<\/li>\r\n<\/ul>\r\n<p>With this function, we simply use:<\/p>\r\n<pre>\r\nADVANCE FN$funGauss<\/pre>\r\n<p>Both techniques will produce a distribution of times around the value 30, but using different methods: a predefined table versus an automatically constructed curve.<\/p>\r\n<h3 data-start=\"2590\" data-end=\"2624\"><strong>Visualization and validation<\/strong><\/h3>\r\n<p data-start=\"2626\" data-end=\"2661\">Facilities with parameters such as:<\/p>\r\n<pre>\r\nE_BIN_START:16, E_BIN_SIZE:1, E_BIN_COUNT:40<\/pre>\r\n<p data-start=\"2726\" data-end=\"2930\">automatically record statistics about how long each entity has remained in the resource. These statistics are shown in the report and allow checking how the function actually behaves.<\/p>\r\n<p data-start=\"2932\" data-end=\"3123\">We will see that, in both cases, the resulting graph is a <strong data-start=\"2988\" data-end=\"3014\">Gaussian distribution<\/strong>. This allows validating that both the manual table and the generated function provide coherent behaviors.<\/p>\r\n<p><img src=\"..\/imgfront\/informe.png\" width=\"50%'\" alt=\"Report image\"><\/p>",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            },
            {
                "id": "225",
                "nombre": "Types of distribution functions",
                "texto": "Function {name:funGauss, type:\"GAUSS\", a:1, b:30, sigma1:3.3, sigma2:3.3,intervals:100 }\r\n\r\nFunction {name:funExp, type:\"EXP\", b:0, lambda:0.15, intervals:100}\r\n\r\nFunction {name:funUni, type:\"UNIFORM\", min:20, max:40, intervals:100}\r\n\r\nFunction {name:funTri, type:\"TRIANGULAR\", min:20, max:40, mode:30, intervals:100}\r\n\r\nFunction {name:funLog, type:\"LOGNORMAL\", mu:3.4, sigma:0.3, intervals:100}\r\nFunction {name:funLog2, type:\"LOGNORMAL\", b:30, spread:5, intervals:100}\r\n\r\nFunction {name:funCus, type:\"FDISTRIBUTION\", function:\"A * Math.sin(B * x)\", a:10, b:0.5, min:0, max:10, intervals:100}\r\n\r\n\r\nFunction {name:funPoi, type:\"POISSON\", lambda:3.5}\r\n\r\nFunction {Name:math1, type: math, EXPRESSION:\"A * 2 + B\"}\r\n",
                "descripcion": "<p data-start=\"237\" data-end=\"606\">The <code data-start=\"248\" data-end=\"258\">FUNCTION<\/code> command allows you to define functions that return numeric values, either through direct calculations or through precomputed distribution tables. These functions are used to simulate variable and realistic behavior in operations such as <code data-start=\"503\" data-end=\"512\">ADVANCE<\/code>, <code data-start=\"514\" data-end=\"522\">ASSIGN<\/code>, <code data-start=\"524\" data-end=\"534\">TABULATE<\/code>, etc., and they represent times, quantities, costs, probabilities, and more.<\/p>\r\n<p data-start=\"608\" data-end=\"678\">In GPSS-Plus, functions can be classified into two broad groups:<\/p>\r\n<p data-start=\"246\" data-end=\"540\">&nbsp;<\/p>\r\n<h4 data-start=\"680\" data-end=\"765\">1. <strong data-start=\"688\" data-end=\"763\">Functions based on statistical distributions (with a value table)<\/strong><\/h4>\r\n<p data-start=\"766\" data-end=\"1015\">These functions pre-generate an internal table with a configurable number of points (intervals) and interpolate the result over it. They are ideal for representing random behavior with known patterns. Available types are:<\/p>\r\n<ul data-start=\"1017\" data-end=\"1390\">\r\n    <li data-start=\"1017\" data-end=\"1067\">\r\n    <p data-start=\"1019\" data-end=\"1067\"><code data-start=\"1019\" data-end=\"1026\">GAUSS<\/code>: Normal distribution (Gaussian bell curve).<\/p>\r\n    <\/li>\r\n    <li data-start=\"1068\" data-end=\"1114\">\r\n    <p data-start=\"1070\" data-end=\"1114\"><code data-start=\"1070\" data-end=\"1075\">EXP<\/code>: Decreasing exponential distribution.<\/p>\r\n    <\/li>\r\n    <li data-start=\"1115\" data-end=\"1164\">\r\n    <p data-start=\"1117\" data-end=\"1164\"><code data-start=\"1117\" data-end=\"1126\">UNIFORM<\/code>: Uniform (rectangular) distribution.<\/p>\r\n    <\/li>\r\n    <li data-start=\"1165\" data-end=\"1205\">\r\n    <p data-start=\"1167\" data-end=\"1205\"><code data-start=\"1167\" data-end=\"1179\">TRIANGULAR<\/code>: Triangular distribution.<\/p>\r\n    <\/li>\r\n    <li data-start=\"1206\" data-end=\"1274\">\r\n    <p data-start=\"1208\" data-end=\"1274\"><code data-start=\"1208\" data-end=\"1219\">LOGNORMAL<\/code>: Log-normal distribution, right-skewed.<\/p>\r\n    <\/li>\r\n    <li data-start=\"1275\" data-end=\"1390\">\r\n    <p data-start=\"1277\" data-end=\"1390\"><code data-start=\"1277\" data-end=\"1292\">FDISTRIBUTION<\/code>: Lets you define a custom distribution function using a mathematical formula.<\/p>\r\n    <\/li>\r\n<\/ul>\r\n<p>&nbsp;<\/p>\r\n<h4 data-start=\"1392\" data-end=\"1446\">2. <strong data-start=\"1400\" data-end=\"1444\">Direct-calculation functions (no table)<\/strong><\/h4>\r\n<p data-start=\"1447\" data-end=\"1645\">These functions evaluate the result directly, without generating or consulting a table. They are more flexible when you want to work with formulas or with discrete event-count models. They include:<\/p>\r\n<ul data-start=\"1647\" data-end=\"1906\">\r\n    <li data-start=\"1647\" data-end=\"1761\">\r\n    <p data-start=\"1649\" data-end=\"1761\"><code data-start=\"1649\" data-end=\"1658\">POISSON<\/code>: Generates a random integer according to a Poisson distribution (number of events per interval).<\/p>\r\n    <\/li>\r\n    <li data-start=\"1762\" data-end=\"1906\">\r\n    <p data-start=\"1764\" data-end=\"1906\"><code data-start=\"1764\" data-end=\"1770\">MATH<\/code>: Directly evaluates a mathematical expression. It accepts multiple parameters that are substituted by letters (<code data-start=\"1876\" data-end=\"1879\">A<\/code>, <code data-start=\"1881\" data-end=\"1884\">B<\/code>, <code data-start=\"1886\" data-end=\"1889\">C<\/code>, etc.) in order.<\/p>\r\n    <\/li>\r\n<\/ul>",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            },
            {
                "id": "227",
                "nombre": "Gaussian function",
                "texto": "\/*\r\n\r\n  \t \tGauss\r\n \r\n*\/\r\nSYSTEM {TYPE:OPTIONS,Speed:5}\r\n\r\nFacility {NAME:VENTANILLA1,X:165,Y:184,E_BIN_start:5,E_BIN_SIZE:1,E_BIN_COUNT:80,capacity:10}\r\n\r\nFacility {NAME:VENTANILLA2,X:343,Y:185,E_BIN_start:5,E_BIN_SIZE:1,E_BIN_COUNT:80,capacity:10}\r\n\r\nFacility {NAME:VENTANILLA3,X:535,Y:183,E_BIN_start:5,E_BIN_SIZE:1,E_BIN_COUNT:80,capacity:10}\r\n\r\n\r\nPOSITION {NAME:POS1,X:250,Y:381}\r\nPOSITION {NAME:POS2,X:423,Y:383}\r\nPOSITION {NAME:POS3,X:566,Y:384}\r\n\r\nFunction {name:gfun1, TYPE:GAUSS, a:1, b:50, sigma1:3.3, sigma2:3.3,intervals:100 }\r\nFunction {name:gfun2, TYPE:GAUSS, a:1, b:50, sigma1:1.0, sigma2:10.0,intervals:100 }\r\nFunction {name:gfun3, TYPE:GAUSS, a:1, b:50, sigma1:10.0, sigma2:1.0,intervals:100 }\r\n\r\n\r\nSTART 500\r\n\r\n\r\n;*****************************************************\r\nGENERATE 10,0,0,0 {NAME:GEN1,X:91,Y:383}\r\n\r\nADVANCE 20,4 {TO:VENTANILLA1}\r\nSEIZE VENTANILLA1\r\nADVANCE FN$gfun1\r\nRELEASE VENTANILLA1\r\nADVANCE 20,0 {TO:POS1}\r\n\r\nADVANCE 20,0 {TO:VENTANILLA2}\r\n\r\nSEIZE VENTANILLA2\r\nADVANCE FN$gfun2\r\nRELEASE VENTANILLA2\r\nADVANCE 20,0 {TO:POS2}\r\n\r\nADVANCE 20,0 {TO:VENTANILLA3}\r\n\r\nSEIZE VENTANILLA3\r\nADVANCE FN$gfun3\r\nRELEASE VENTANILLA3\r\nADVANCE 20,0 {TO:POS3}\r\n\r\n\r\nENDGENERATE 1",
                "descripcion": "<p>The <strong data-start=\"213\" data-end=\"226\">Gaussian<\/strong> (or normal) distribution represents a <strong data-start=\"253\" data-end=\"282\">bell-shaped curve<\/strong>, where the most likely values are near a central value and extremes are less likely. It is ideal for modeling natural phenomena such as <strong data-start=\"437\" data-end=\"504\">service times, measurement errors, or process durations<\/strong>, where most cases cluster around a mean.<\/p>\r\n<p><b>Parameters:<\/b><\/p>\r\n<ul>\r\n    <li>a: Curve height (visualization only; it does not affect the calculation).<\/li>\r\n    <li>b: Central value or expected mean of the process.<\/li>\r\n    <li>sigma1: Spread (standard deviation) to the left of the center.<\/li>\r\n    <li>sigma2: Spread to the right of the center. It can differ from sigma1 to create asymmetry.<\/li>\r\n    <li>intervals: Number of segments used to divide the curve. The higher the number, the more precise.<\/li>\r\n<\/ul>\r\n<p>By construction, the distribution will take values approximately between <code data-start=\"358\" data-end=\"374\">b - sigma1 * 3<\/code> and <code data-start=\"377\" data-end=\"393\">b + sigma2 * 3<\/code>.<\/p>\r\n<p>This example shows how three service windows with different Gaussian functions produce different distributions of service times:<\/p>\r\n<pre>\r\nADVANCE FN$gfun1 ; symmetric\r\nADVANCE FN$gfun2 ; right spread\r\nADVANCE FN$gfun3 ; left spread\r\n<\/pre>\r\n<p>&nbsp;<\/p>\r\n<p>&nbsp;<\/p>\r\n<p><img src=\"..\/imgfront\/gfunction.svg\" width=\"50%'\" alt=\"\"><\/p>",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            },
            {
                "id": "228",
                "nombre": "Exponential function",
                "texto": "\/*\r\n\r\n  \t \tExponential\r\n \r\n*\/\r\nSYSTEM {TYPE:OPTIONS, Speed:5}\r\n\r\n;=== Facilities with statistical tracking ===\r\nFacility {NAME:VENTANILLA1,X:165,Y:184,E_BIN_start:5,E_BIN_SIZE:1,E_BIN_COUNT:80,capacity:10}\r\n\r\nFacility {NAME:VENTANILLA2,X:343,Y:185,E_BIN_start:5,E_BIN_SIZE:1,E_BIN_COUNT:80,capacity:10}\r\n\r\nFacility {NAME:VENTANILLA3,X:535,Y:183,E_BIN_start:5,E_BIN_SIZE:1,E_BIN_COUNT:80,capacity:10}\r\n\r\n;=== Final positions for visualization ===\r\nPOSITION {NAME:POS1, X:250, Y:381}\r\nPOSITION {NAME:POS2, X:423, Y:383}\r\nPOSITION {NAME:POS3, X:566, Y:384}\r\n\r\n;=== EFunctions with different decay rates ===\r\nFunction {Name:efun1, TYPE:EXP, a:100, b:20, Lambda:0.3, Intervals:70}\r\nFunction {Name:efun2, TYPE:EXP, a:100, b:20, Lambda:0.6, Intervals:70}\r\nFunction {Name:efun3, TYPE:EXP, a:100, b:20, Lambda:1.0, Intervals:70}\r\n\r\n;=== Simulation start ===\r\nSTART 500\r\n\r\n;=== Entity flow through the three service windows ===\r\nGENERATE 10,0,0,0 {NAME:GEN1, X:91, Y:383}\r\n\r\n; WINDOW 1 – Slow decay\r\nADVANCE 20,4 {TO:VENTANILLA1}\r\nSEIZE VENTANILLA1\r\nADVANCE FN$efun1\r\nRELEASE VENTANILLA1\r\nADVANCE 20,0 {TO:POS1}\r\n\r\n; WINDOW 2 – Medium decay\r\nADVANCE 20,0 {TO:VENTANILLA2}\r\nSEIZE VENTANILLA2\r\nADVANCE FN$efun2\r\nRELEASE VENTANILLA2\r\nADVANCE 20,0 {TO:POS2}\r\n\r\n; WINDOW 3 – Fast decay\r\nADVANCE 20,0 {TO:VENTANILLA3}\r\nSEIZE VENTANILLA3\r\nADVANCE FN$efun3\r\nRELEASE VENTANILLA3\r\nADVANCE 20,0 {TO:POS3}\r\n\r\nENDGENERATE 1\r\n",
                "descripcion": "<p data-start=\"224\" data-end=\"557\">The exponential distribution is used to model events that occur randomly but with a <strong data-start=\"329\" data-end=\"370\">decreasing probability over time<\/strong>. It is ideal for situations such as waiting times, system failures, or random arrivals where something is most likely to occur early, and becomes less likely the longer it takes.<\/p>\r\n<p data-start=\"559\" data-end=\"580\">A classic example: <i>\"If you are waiting to be served, it is more likely to happen soon; and each additional minute reduces that probability.\"<\/i><\/p>\r\n<p>This <strong data-start=\"710\" data-end=\"735\">is not well represented<\/strong> by a uniform distribution (such as <code data-start=\"768\" data-end=\"782\">ADVANCE 10,5<\/code>), but it is by an exponential function, defined with the type:<\/p>\r\n<pre>\r\nFunction {name:efun1, type:\"EXP\", a:100, b:20, lambda:0.3, intervals:100}\r\n<\/pre>\r\n<h3 data-start=\"923\" data-end=\"937\">Parameters<\/h3>\r\n<ul data-start=\"939\" data-end=\"1264\">\r\n    <li data-start=\"939\" data-end=\"1015\"><p data-start=\"941\" data-end=\"1015\"><strong>a<\/strong>: Curve height (visual only; it does not affect the calculation).<\/p><\/li>\r\n    <li data-start=\"1016\" data-end=\"1095\"><p data-start=\"1018\" data-end=\"1095\"><strong>b<\/strong>: Base minimum value. This is the point from which the distribution starts.<\/p><\/li>\r\n    <li data-start=\"1096\" data-end=\"1172\"><p data-start=\"1098\" data-end=\"1172\"><strong>lambda<\/strong>: Decay rate. The higher the lambda, the faster the decay.<\/p><\/li>\r\n    <li data-start=\"1173\" data-end=\"1264\"><p data-start=\"1175\" data-end=\"1264\"><strong>intervals<\/strong>: Number of segments into which the curve is divided (the more, the more precise).<\/p><\/li>\r\n<\/ul>\r\n<p data-start=\"1268\" data-end=\"1334\">Approximately, 99.9% of the values will lie within the range:<\/p>\r\n<ul data-start=\"1339\" data-end=\"1427\">\r\n    <li><p>&lambda; = 1 → from b to b + 6.91<\/p><\/li>\r\n    <li><p>&lambda; = 0.5 → from b to b + 13.82<\/p><\/li>\r\n    <li><p>&lambda; = 2 → from b to b + 3.45<\/p><\/li>\r\n<\/ul>\r\n<p><b>Comparative usage example:<\/b><\/p>\r\n<pre>\r\nFunction {Name:efun1, type:\"EXP\", a:100, b:20, lambda:0.3, intervals:70}\r\nFunction {Name:efun2, type:\"EXP\", a:100, b:20, lambda:0.6, intervals:70}\r\nFunction {Name:efun3, type:\"EXP\", a:100, b:20, lambda:1.0, intervals:70}\r\n\r\nADVANCE FN$efun1 ; slow decay\r\nADVANCE FN$efun2 ; medium decay\r\nADVANCE FN$efun3 ; fast decay\r\n<\/pre>\r\n<p>&nbsp;<\/p>\r\n<p><img src=\"..\/imgfront\/efunction.svg\" width=\"50%'\" alt=\"Graph\"><\/p>",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            },
            {
                "id": "231",
                "nombre": "Log-normal function",
                "texto": "\/*\r\n\r\n  \t \tLog-normal\r\n \r\n*\/\r\nSYSTEM {TYPE:OPTIONS, Speed:5}\r\n\r\nFacility {NAME:VENTANILLA1,X:165,Y:184,E_BIN_start:0,E_BIN_SIZE:1,E_BIN_COUNT:100,capacity:10}\r\n\r\nFacility {NAME:VENTANILLA2,X:343,Y:185,E_BIN_start:0,E_BIN_SIZE:1,E_BIN_COUNT:100,capacity:10}\r\n\r\nFacility {NAME:VENTANILLA3,X:535,Y:183,E_BIN_start:0,E_BIN_SIZE:1,E_BIN_COUNT:100,capacity:10}\r\n\r\nPOSITION {NAME:POS1, X:250, Y:381}\r\nPOSITION {NAME:POS2, X:423, Y:383}\r\nPOSITION {NAME:POS3, X:566, Y:384}\r\n\r\nFunction {Name:lfunc1, Type: LOGNORMAL, b:30, sigma:0.1}\r\nFunction {Name:lfunc2, Type: LOGNORMAL, b:20, sigma:0.15}\r\nFunction {Name:lfunc3, Type: LOGNORMAL, b:40, sigma:0.2}\r\n\r\n\r\nSTART 500\r\n\r\nGENERATE 10,0,0,0 {NAME:GEN1, X:91, Y:383}\r\n\r\n; WINDOW 1 – Small dispersion\r\nADVANCE 20,4 {TO:VENTANILLA1}\r\nSEIZE VENTANILLA1\r\nADVANCE FN$lfunc1\r\nRELEASE VENTANILLA1\r\nADVANCE 20,0 {TO:POS1}\r\n\r\n; WINDOW 2 – Medium dispersion\r\nADVANCE 20,0 {TO:VENTANILLA2}\r\nSEIZE VENTANILLA2\r\nADVANCE FN$lfunc2\r\nRELEASE VENTANILLA2\r\nADVANCE 20,0 {TO:POS2}\r\n\r\n; WINDOW 3 – Large dispersion (long tail)\r\nADVANCE 20,0 {TO:VENTANILLA3}\r\nSEIZE VENTANILLA3\r\nADVANCE FN$lfunc3\r\nRELEASE VENTANILLA3\r\nADVANCE 20,0 {TO:POS3}\r\n\r\nENDGENERATE 1\r\n\r\n",
                "descripcion": "<p>What is the log-normal distribution?<\/p>\r\n<p>A variable follows a <strong data-start=\"338\" data-end=\"365\">log-normal distribution<\/strong> if the logarithm of that variable has a <strong data-start=\"408\" data-end=\"431\">normal distribution<\/strong>. In other words:<\/p>\r\n<p><i>“Many small events occur frequently, but it is also possible for some events with very large values to appear, although with low probability.”<\/i><\/p>\r\n<h3 data-start=\"620\" data-end=\"641\">Typical cases:<\/h3>\r\n<ul data-start=\"642\" data-end=\"788\">\r\n    <li data-start=\"642\" data-end=\"680\"><p data-start=\"644\" data-end=\"680\">Machine repair time.<\/p><\/li>\r\n    <li data-start=\"681\" data-end=\"718\"><p data-start=\"683\" data-end=\"718\">Duration of a phone call.<\/p><\/li>\r\n    <li data-start=\"719\" data-end=\"788\"><p data-start=\"721\" data-end=\"788\">Income (most people earn little, a few earn a lot).<\/p><\/li>\r\n<\/ul>\r\n<pre>\r\nFunction {Name:lfunc1, Type:LOGNORMAL, b:30, sigma:0.1}\r\n<\/pre>\r\n<p><b>Parameters:<\/b><\/p>\r\n<ul>\r\n    <li><code data-start=\"898\" data-end=\"901\">b<\/code>: The function’s <strong data-start=\"909\" data-end=\"925\">most likely<\/strong> value (the peak of the curve).<\/li>\r\n    <li><code data-start=\"965\" data-end=\"972\">sigma<\/code>: Controls the <strong data-start=\"986\" data-end=\"1000\">spread<\/strong> of values to the right. The larger the sigma, the wider the distribution’s “tail”.<\/li>\r\n<\/ul>\r\n<p>GPSS-Plus automatically converts these values into the mathematical parameters <code data-start=\"1175\" data-end=\"1178\">&mu;<\/code> (log-mean) and <code data-start=\"1201\" data-end=\"1204\">&sigma;<\/code> (standard deviation) to build the log-normal curve.<\/p>\r\n<p>Unlike the Gaussian, the log-normal <strong data-start=\"1333\" data-end=\"1352\">is not symmetric<\/strong>. It has a long “tail” toward higher values. This behavior matches well with phenomena where extreme values are rare, but possible.<\/p>\r\n<p>This example shows three log-normal functions with the same curve type, but different dispersion.<\/p>\r\n<pre>\r\nFunction {Name:lfunc1, Type:LOGNORMAL, b:30, sigma:0.1}   ; narrow curve\r\nFunction {Name:lfunc2, Type:LOGNORMAL, b:20, sigma:0.15}  ; medium dispersion\r\nFunction {Name:lfunc3, Type:LOGNORMAL, b:40, sigma:0.2}   ; long tail\r\n<\/pre>\r\n<p>&nbsp;<\/p>\r\n<p><img src=\"..\/imgfront\/lfunction.svg\" width=\"50%'\" alt=\"Graph\"><\/p>",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            },
            {
                "id": "229",
                "nombre": "Uniform function",
                "texto": "\/*\r\n\r\n  \t \tUniforme\r\n \r\n*\/\r\nSYSTEM {TYPE:OPTIONS, Speed:5}\r\n\r\nFacility {NAME:VENTANILLA1,X:165,Y:184,E_BIN_start:5,E_BIN_SIZE:1,E_BIN_COUNT:80,capacity:10}\r\n\r\nFacility {NAME:VENTANILLA2,X:343,Y:185,E_BIN_start:5,E_BIN_SIZE:1,E_BIN_COUNT:80,capacity:10}\r\n\r\nFacility {NAME:VENTANILLA3,X:535,Y:183,E_BIN_start:5,E_BIN_SIZE:1,E_BIN_COUNT:80,capacity:10}\r\n\r\nPOSITION {NAME:POS1, X:250, Y:381}\r\nPOSITION {NAME:POS2, X:423, Y:383}\r\nPOSITION {NAME:POS3, X:566, Y:384}\r\n\r\nFunction {Name:ufun1, TYPE:UNIFORM, Min:20, Max:40}\r\nFunction {Name:ufun2, TYPE:UNIFORM, Min:20, Max:60}\r\nFunction {Name:ufun3, TYPE:UNIFORM, Min:30, Max:50}\r\n\r\nSTART 500\r\n\r\nGENERATE 10,0,0,0 {NAME:GEN1, X:91, Y:383}\r\n\r\n; WINDOW 1 – Uniform from 20 to 40\r\nADVANCE 20,4 {TO:VENTANILLA1}\r\nSEIZE VENTANILLA1\r\nADVANCE FN$ufun1\r\nRELEASE VENTANILLA1\r\nADVANCE 20,0 {TO:POS1}\r\n\r\n; WINDOW 2 – Uniform from 20 to 60\r\nADVANCE 20,0 {TO:VENTANILLA2}\r\nSEIZE VENTANILLA2\r\nADVANCE FN$ufun2\r\nRELEASE VENTANILLA2\r\nADVANCE 20,0 {TO:POS2}\r\n\r\n; WINDOW 3 – Uniform from 30 to 50\r\nADVANCE 20,0 {TO:VENTANILLA3}\r\nSEIZE VENTANILLA3\r\nADVANCE FN$ufun3\r\nRELEASE VENTANILLA3\r\nADVANCE 20,0 {TO:POS3}\r\n\r\nTERMINATE 1\r\n\r\n\r\n",
                "descripcion": "<p>The <strong data-start=\"229\" data-end=\"254\">uniform distribution<\/strong> represents maximum uncertainty: <strong data-start=\"291\" data-end=\"372\">all values within a range have exactly the same probability<\/strong>.<\/p>\r\n<p><i>\"It’s like rolling a perfect die: no number is more likely than another.\"<\/i><\/p>\r\n<p>This type of distribution is useful when <strong data-start=\"528\" data-end=\"604\">there is no reason to believe some values are more likely than others<\/strong>.<img src=\"..\/imagenes\/ufunction.svg\" width=\"50%'\" alt=\"\"><\/p>\r\n<p>Parameters<\/p>\r\n<pre>\r\nFunction {Name:ufun1, TYPE:UNIFORM, Min:20, Max:40}\r\n<\/pre>\r\n<ul data-start=\"865\" data-end=\"964\">\r\n    <li data-start=\"865\" data-end=\"914\">\r\n    <p data-start=\"867\" data-end=\"914\"><code data-start=\"867\" data-end=\"872\">Min<\/code>: minimum value the function can take.<\/p>\r\n    <\/li>\r\n    <li data-start=\"915\" data-end=\"964\">\r\n    <p data-start=\"917\" data-end=\"964\"><code data-start=\"917\" data-end=\"922\">Max<\/code>: maximum value the function can take.<\/p>\r\n    <\/li>\r\n<\/ul>\r\n<p data-start=\"966\" data-end=\"1029\">All values between Min and Max have the same probability.<\/p>\r\n<p>In the report chart, the curve has the shape of a <strong data-start=\"1108\" data-end=\"1128\">flat rectangle<\/strong>. The <strong data-start=\"1137\" data-end=\"1159\">wider the range<\/strong>, the more spread out the distribution will be.<\/p>\r\n<p>This example compares three uniform distributions with different ranges. All have a rectangular shape, but differ in width and position:<\/p>\r\n<pre>\r\nFunction {Name:ufun1, TYPE:UNIFORM, Min:20, Max:40}   ; Small range\r\nFunction {Name:ufun2, TYPE:UNIFORM, Min:20, Max:60}   ; Wide range\r\nFunction {Name:ufun3, TYPE:UNIFORM, Min:30, Max:50}   ; Shifted range\r\n<\/pre>\r\n<p>&nbsp;<\/p>\r\n<p><img src=\"..\/imgfront\/ufunction.svg\" width=\"50%'\" alt=\"Graph\"><\/p>",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            },
            {
                "id": "230",
                "nombre": "Triangular function",
                "texto": "\/*\r\n\r\n  \t \tTriangular\r\n \r\n*\/\r\nSYSTEM {TYPE:OPTIONS, Speed:5}\r\n\r\nFacility {NAME:VENTANILLA1,X:165,Y:184,E_BIN_start:0,E_BIN_SIZE:1,E_BIN_COUNT:80,capacity:10}\r\n\r\nFacility {NAME:VENTANILLA2,X:343,Y:185,E_BIN_start:0,E_BIN_SIZE:1,E_BIN_COUNT:80,capacity:10}\r\n\r\nFacility {NAME:VENTANILLA3,X:535,Y:183,E_BIN_start:0,E_BIN_SIZE:1,E_BIN_COUNT:80,capacity:10}\r\n\r\nPOSITION {NAME:POS1, X:250, Y:381}\r\nPOSITION {NAME:POS2, X:423, Y:383}\r\nPOSITION {NAME:POS3, X:566, Y:384}\r\n\r\nFunction {Name:tfun1, TYPE:TRIANGULAR, Min:20, Max:40, Mode:30}\r\nFunction {Name:tfun2, TYPE:TRIANGULAR, Min:20, Max:40, Mode:25}\r\nFunction {Name:tfun3, TYPE:TRIANGULAR, Min:20, Max:40, Mode:35}\r\n\r\nSTART 500\r\n\r\nGENERATE 10,0,0,0 {NAME:GEN1, X:91, Y:383}\r\n\r\n; WINDOW 1 – Centered triangle\r\nADVANCE 20,4 {TO:VENTANILLA1}\r\nSEIZE VENTANILLA1\r\nADVANCE FN$tfun1\r\nRELEASE VENTANILLA1\r\nADVANCE 20,0 {TO:POS1}\r\n\r\n; WINDOW 2 – Triangle with the peak to the left\r\nADVANCE 20,0 {TO:VENTANILLA2}\r\nSEIZE VENTANILLA2\r\nADVANCE FN$tfun2\r\nRELEASE VENTANILLA2\r\nADVANCE 20,0 {TO:POS2}\r\n\r\n; WINDOW 3 – Triangle with the peak to the right\r\nADVANCE 20,0 {TO:VENTANILLA3}\r\nSEIZE VENTANILLA3\r\nADVANCE FN$tfun3\r\nRELEASE VENTANILLA3\r\nADVANCE 20,0 {TO:POS3}\r\n\r\nENDGENERATE 1\r\n\r\n\r\n\r\n",
                "descripcion": "<p>The <strong data-start=\"281\" data-end=\"308\">triangular distribution<\/strong> lets you define a value’s <strong data-start=\"340\" data-end=\"373\">minimum, maximum, and most likely<\/strong> (mode). It has a triangular shape, where the <strong data-start=\"439\" data-end=\"447\">mode<\/strong> is the most frequent value and the extremes are less likely.<\/p>\r\n<p>It’s useful when you have an <strong data-start=\"533\" data-end=\"552\">approximate idea<\/strong> of how a process behaves, but not enough data to justify a more complex distribution.<\/p>\r\n<p><i>“A delivery usually takes 3 days, but it could take 2 or 5.”<\/i><\/p>\r\n<p>That kind of uncertainty is ideal for a <strong data-start=\"806\" data-end=\"833\">triangular distribution<\/strong>.<\/p>\r\n<p><b>Parameters<\/b><\/p>\r\n<pre>\r\nFunction {Name:tfun1, TYPE:TRIANGULAR, Min:20, Max:40, Mode:30}\r\n<\/pre>\r\n<p>&nbsp;<\/p>\r\n<ul>\r\n    <li><code data-start=\"952\" data-end=\"957\">Min<\/code>: Minimum possible value.<\/li>\r\n    <li><code data-start=\"983\" data-end=\"988\">Max<\/code>: Maximum possible value.<\/li>\r\n    <li><code data-start=\"1014\" data-end=\"1020\">Mode<\/code>: Most likely value (peak of the distribution).<\/li>\r\n<\/ul>\r\n<p>This example compares three triangular functions with different peak positions. All share the same range, but produce different distributions:<\/p>\r\n<p>&nbsp;<\/p>\r\n<pre>\r\nFunction {Name:tfun1, TYPE:TRIANGULAR, Min:20, Max:40, Mode:30} ; Centered peak\r\nFunction {Name:tfun2, TYPE:TRIANGULAR, Min:20, Max:40, Mode:25} ; Left-skewed peak\r\nFunction {Name:tfun3, TYPE:TRIANGULAR, Min:20, Max:40, Mode:35} ; Right-skewed peak\r\n<\/pre>\r\n<p>&nbsp;<\/p>\r\n<p><img src=\"..\/imgfront\/tfunction.svg\" width=\"50%'\" alt=\"Graph\"><\/p>",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            },
            {
                "id": "232",
                "nombre": "Poisson function",
                "texto": "\/*\r\n\r\n  \t \tPoisson\r\n \r\n*\/\r\nSYSTEM {TYPE:OPTIONS,Speed:5}\r\n\r\nGraphic {NAME:pText1,Type:TEXT,X:309,Y:281,Text:\"Mean1\"}\r\nGraphic {NAME:pText2,Type:TEXT,X:309,Y:238,Text:\"Mean2\"}\r\nGraphic {NAME:pText3,Type:TEXT,X:308,Y:198,Text:\"Mean3\"}\r\n\r\nGraphic {NAME:eText1,Type:TEXT,X:506,Y:280,Text:\"Exp1\"}\r\nGraphic {NAME:eText2,Type:TEXT,X:506,Y:238,Text:\"Exp2\"}\r\nGraphic {NAME:eText3,Type:TEXT,X:504,Y:196,Text:\"Exp3\"}\r\n\r\n\r\n\r\nPOSITION {NAME:POS1,X:598,Y:395}\r\nINITIAL contador,0\r\n\r\nINITIAL LAMBDA1,1\/4\r\nINITIAL iLAMBDA1,round(1\/X$LAMBDA1,3)\r\nINITIAL pTotal1,0\r\nINITIAL eTotal1,0\r\n\r\nINITIAL LAMBDA2,3\/4\r\nINITIAL iLAMBDA2,round(1\/X$LAMBDA2,3)\r\nINITIAL pTotal2,0\r\nINITIAL eTotal2,0\r\n\r\nINITIAL LAMBDA3,3\r\nINITIAL iLAMBDA3,round(1\/X$LAMBDA3,3)\r\nINITIAL pTotal3,0\r\nINITIAL eTotal3,0\r\n\r\n\r\n\r\nFunction {Name:fPoisson1, TYPE:POISSON, LAMBDA:X$LAMBDA1}\r\nFunction {Name:fPoisson2, TYPE:POISSON, LAMBDA:X$LAMBDA2}\r\nFunction {Name:fPoisson3, TYPE:POISSON, LAMBDA:X$LAMBDA3}\r\n\r\nFunction {Name:fexp1, TYPE:EXP, LAMBDA:X$LAMBDA1, b:0}\r\nFunction {Name:fexp2, TYPE:EXP, LAMBDA:X$LAMBDA2, b:0}\r\nFunction {Name:fexp3, TYPE:EXP, LAMBDA:X$LAMBDA3, b:0}\r\n\r\nSTART 2000\r\n\r\n;*****************************************************\r\nGENERATE 2,0,0,0 {NAME:GEN1,X:218,Y:395}\r\n\r\nSAVEVALUE contador,X$contador + 1\r\n\r\n; --- Accumulation Poisson ---\r\nSAVEVALUE pTotal1,X$pTotal1 + FN$fPoisson1\r\nSAVEVALUE pMedia1, X$pTotal1 \/ X$contador\r\nSAVEVALUE pMediaRound1, round(X$pMedia1,3)\r\n\r\nSAVEVALUE pTotal2,X$pTotal2 + FN$fPoisson2\r\nSAVEVALUE pMedia2, X$pTotal2 \/ X$contador\r\nSAVEVALUE pMediaRound2, round(X$pMedia2,3)\r\n\r\nSAVEVALUE pTotal3,X$pTotal3 + FN$fPoisson3\r\nSAVEVALUE pMedia3, X$pTotal3 \/ X$contador\r\nSAVEVALUE pMediaRound3, round(X$pMedia3,3)\r\n\r\n; --- Accumulation Exponential ---\r\n\r\nSAVEVALUE eTotal1,X$eTotal1 + FN$fexp1\r\nSAVEVALUE eMedia1, X$eTotal1 \/ X$contador\r\nSAVEVALUE eMediaRound1, round(X$eMedia1,3)\r\n\r\nSAVEVALUE eTotal2,X$eTotal2 + FN$fexp2\r\nSAVEVALUE eMedia2, X$eTotal2 \/ X$contador\r\nSAVEVALUE eMediaRound2, round(X$eMedia2,3)\r\n\r\nSAVEVALUE eTotal3,X$eTotal3 + FN$fexp3\r\nSAVEVALUE eMedia3, X$eTotal3 \/ X$contador\r\nSAVEVALUE eMediaRound3, round(X$eMedia3,3)\r\n\r\n\r\nmove {name:pText1,text:\"Converges to Lambda = X$LAMBDA1  -->  X$pMediaRound1\"}\r\nmove {name:pText2,text:\"Converges to Lambda = X$LAMBDA2  -->  X$pMediaRound2\"}\r\nmove {name:pText3,text:\"Converges to Lambda = X$LAMBDA3  -->  X$pMediaRound3\"}\r\n\r\nmove {name:eText1,text:\"Exp = 1\/X$LAMBDA1 = X$iLAMBDA1 -->  X$eMediaRound1\"}\r\nmove {name:eText2,text:\"Exp = 1\/X$LAMBDA2 = X$iLAMBDA2 -->  X$eMediaRound2\"}\r\nmove {name:eText3,text:\"Exp = 1\/X$LAMBDA3 = X$iLAMBDA3 -->  X$eMediaRound3\"}\r\n\r\n\r\nADVANCE 30,10 {TO:POS1}\r\n\r\n\r\nENDGENERATE 1\r\n\r\n\r\n\r\n\r\n\r\n",
                "descripcion": "<p data-start=\"315\" data-end=\"433\">The <strong data-start=\"331\" data-end=\"342\">Poisson<\/strong> distribution models the <strong data-start=\"353\" data-end=\"376\">number of events<\/strong> that occur in a fixed time interval, provided that:<\/p>\r\n<ul data-start=\"435\" data-end=\"532\">\r\n    <li data-start=\"435\" data-end=\"480\">\r\n    <p data-start=\"437\" data-end=\"480\">Events occur <strong data-start=\"457\" data-end=\"479\">independently<\/strong>.<\/p>\r\n    <\/li>\r\n    <li data-start=\"481\" data-end=\"532\">\r\n    <p data-start=\"483\" data-end=\"532\">The average rate of occurrence (<strong data-start=\"512\" data-end=\"517\">&lambda;<\/strong>) is constant.<\/p>\r\n    <\/li>\r\n<\/ul>\r\n<p>&nbsp;<\/p>\r\n<p><b>When should you use Poisson?<\/b><\/p>\r\n<p>&nbsp;<\/p>\r\n<ul data-start=\"569\" data-end=\"690\">\r\n    <li data-start=\"569\" data-end=\"619\">\r\n    <p data-start=\"571\" data-end=\"619\">Number of calls per minute in a call center.<\/p>\r\n    <\/li>\r\n    <li data-start=\"620\" data-end=\"656\">\r\n    <p data-start=\"622\" data-end=\"656\">Customer arrivals to a store.<\/p>\r\n    <\/li>\r\n    <li data-start=\"657\" data-end=\"690\">\r\n    <p data-start=\"659\" data-end=\"690\">Manufacturing defects per day.<\/p>\r\n    <\/li>\r\n<\/ul>\r\n<p><b>Parameter:<\/b><\/p>\r\n<p><code data-start=\"718\" data-end=\"721\">&lambda;<\/code> (lambda): the expected mean number of events per interval.<\/p>\r\n<p>For example, if &lambda; = 3, on average there will be <strong data-start=\"822\" data-end=\"856\">3 events per unit of time<\/strong>, although there can be 2, 4, 0, etc. The variability is part of the distribution.<\/p>\r\n<p>&nbsp;<\/p>\r\n<p><b>Relationship with the exponential distribution<\/b><\/p>\r\n<ul data-start=\"996\" data-end=\"1093\">\r\n    <li data-start=\"996\" data-end=\"1041\">\r\n    <p data-start=\"998\" data-end=\"1041\"><strong data-start=\"998\" data-end=\"1009\">Poisson<\/strong> counts how many events occur.<\/p>\r\n    <\/li>\r\n    <li data-start=\"1042\" data-end=\"1093\">\r\n    <p data-start=\"1044\" data-end=\"1093\"><strong data-start=\"1044\" data-end=\"1059\">Exponential<\/strong> measures the <strong data-start=\"1068\" data-end=\"1092\">time between events<\/strong>.<\/p>\r\n    <\/li>\r\n<\/ul>\r\n<p>&nbsp;<\/p>\r\n<p>Both are controlled by the same parameter <strong data-start=\"1142\" data-end=\"1147\">&lambda;<\/strong>, and they are <strong data-start=\"1155\" data-end=\"1174\">complementary<\/strong>:<\/p>\r\n<p>Poisson(&lambda;):&nbsp;&nbsp;&nbsp; Number of events per interval&nbsp;&nbsp;&nbsp; &lambda;<br>\r\nExponential(&lambda;):&nbsp; Time between consecutive events&nbsp;&nbsp;&nbsp; 1 \/ &lambda;<\/p>\r\n<h3 data-start=\"1484\" data-end=\"1517\">What does this example show?<\/h3>\r\n<p data-start=\"1519\" data-end=\"1592\">A visual comparison of both distributions for 3 different values of &lambda;:<\/p>\r\n<pre>\r\nFunction {Name:fPoisson1, TYPE:POISSON, LAMBDA:X$LAMBDA1}\r\nFunction {Name:fPoisson2, TYPE:POISSON, LAMBDA:X$LAMBDA2}\r\nFunction {Name:fPoisson3, TYPE:POISSON, LAMBDA:X$LAMBDA3}\r\n\r\nFunction {Name:fexp1, TYPE:EXP, LAMBDA:X$LAMBDA1, b:0}\r\nFunction {Name:fexp2, TYPE:EXP, LAMBDA:X$LAMBDA2, b:0}\r\nFunction {Name:fexp3, TYPE:EXP, LAMBDA:X$LAMBDA3, b:0}\r\n<\/pre>\r\n<p data-start=\"1519\" data-end=\"1592\">The results are shown as dynamic text using the <strong data-start=\"1999\" data-end=\"2018\">running mean<\/strong>:<\/p>\r\n<pre>\r\nConverges to &lambda; = 3.0 → Mean ≈ 3.0\r\nConverges to &lambda; = 0.25 → Mean ≈ 0.25\r\n\r\nExp = 1 \/ &lambda; = 0.333 → Mean ≈ 0.333\r\n<\/pre>\r\n<p data-start=\"2161\" data-end=\"2217\">This simulation helps you see how:<\/p>\r\n<ul data-start=\"2219\" data-end=\"2339\">\r\n    <li data-start=\"2219\" data-end=\"2273\">\r\n    <p data-start=\"2221\" data-end=\"2273\"><strong data-start=\"2221\" data-end=\"2232\">Poisson<\/strong> stabilizes the event count toward &lambda;.<\/p>\r\n    <\/li>\r\n    <li data-start=\"2274\" data-end=\"2339\">\r\n    <p data-start=\"2276\" data-end=\"2339\"><strong data-start=\"2276\" data-end=\"2291\">Exponential<\/strong> stabilizes the time between events toward 1 \/ &lambda;.<\/p>\r\n    <\/li>\r\n<\/ul>\r\n<p data-start=\"1519\" data-end=\"1592\">&nbsp;<\/p>\r\n<p><img src=\"..\/imgfront\/pfunction.svg\" width=\"50%'\" alt=\"Graph\"><\/p>\r\n<p>&nbsp;<\/p>\r\n<p>&nbsp;<\/p>\r\n<p>&nbsp;<\/p>\r\n<p>&nbsp;<\/p>",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            },
            {
                "id": "314",
                "nombre": "FDISTRIBUTION functions",
                "texto": "\/*\r\n\r\n  \t \tFDistribution\r\n \r\n*\/\r\nSYSTEM {TYPE:OPTIONS,Speed:5}\r\n\r\nFacility {NAME:VENTANILLA1,X:244,Y:190,E_BIN_start:5,E_BIN_SIZE:1,E_BIN_COUNT:80,capacity:20}\r\n\r\nFacility {NAME:VENTANILLA2,X:412,Y:188,E_BIN_start:5,E_BIN_SIZE:1,E_BIN_COUNT:80,capacity:20}\r\n\r\nPOSITION {NAME:POS1,X:200,Y:387}\r\nPOSITION {NAME:POS2,X:341,Y:381}\r\nPOSITION {NAME:POS3,X:507,Y:380}\r\n\r\n;GAUSSIAN\r\nFunction {Name:tName1, type: FDISTRIBUTION, EXPRESSION:\"(1 \/ (A * SQRT(2 * PI))) * EXP(-0.5 * ((X - B) \/ A)^2)\", b:30,  a: 2.3, min:B - (3 * A), max:B + (3 * A),intervals:100}\r\n\r\n; TRIANGULAR B: center of the range C: total width of the range\r\nFunction {Name:tName2, A:0, B:25, C:30, D:0, type: FDISTRIBUTION, EXPRESSION:\"(1 \/ C) * (1 - ABS((X - B) \/ (C \/ 2)))\", min:B - C\/2, max:B + C\/2, intervals:100} \r\n\r\nSTART 1000\r\n\r\n\r\n;*****************************************************\r\nGENERATE 2,0,0,0 {NAME:GEN1,X:56,Y:319}\r\n\r\nADVANCE 20,0 {TO:POS1}\r\n\r\nADVANCE 30,10 {TO:VENTANILLA1}\r\n\r\nSEIZE VENTANILLA1\r\nADVANCE FN$tName1\r\nRELEASE VENTANILLA1\r\n\r\nADVANCE 20,0 {TO:POS2}\r\n\r\nADVANCE 20,10 {TO:VENTANILLA2}\r\n\r\nSEIZE VENTANILLA2\r\nADVANCE FN$tName2\r\nRELEASE VENTANILLA2\r\n\r\nADVANCE 20,0 {TO:POS3}\r\n\r\n\r\nENDGENERATE 1\r\n\r\n\r\n\r\n\r\n\r\n",
                "descripcion": "<h3>Custom distributions<\/h3>\r\n<p data-start=\"422\" data-end=\"633\">The <code data-start=\"430\" data-end=\"445\">FDISTRIBUTION<\/code> type lets you define <strong data-start=\"488\" data-end=\"520\">fully customized<\/strong> distribution functions using a <strong data-start=\"534\" data-end=\"558\">mathematical expression<\/strong>, without being limited to predefined formulas such as <code data-start=\"603\" data-end=\"610\">GAUSS<\/code>, <code data-start=\"612\" data-end=\"617\">EXP<\/code> or <code data-start=\"620\" data-end=\"632\">TRIANGULAR<\/code>.<\/p>\r\n<p data-start=\"635\" data-end=\"844\">These functions <strong data-start=\"651\" data-end=\"701\">internally generate a distribution table<\/strong> by evaluating a mathematical expression over a given range. This is ideal for representing non-standard distributions or variants of the classic ones.<\/p>\r\n<p data-start=\"187\" data-end=\"477\">&nbsp;<\/p>\r\n<p data-start=\"479\" data-end=\"643\">How does it work?<\/p>\r\n<p data-start=\"872\" data-end=\"928\">GPSS-Plus builds a distribution table based on:<\/p>\r\n<ul data-start=\"930\" data-end=\"1247\">\r\n    <li data-start=\"930\" data-end=\"1033\">\r\n    <p data-start=\"932\" data-end=\"1033\">A <strong data-start=\"936\" data-end=\"960\">mathematical expression<\/strong> that defines the shape of the function (a bell, a triangle, etc.)<\/p>\r\n    <\/li>\r\n    <li data-start=\"1034\" data-end=\"1100\">\r\n    <p data-start=\"1036\" data-end=\"1100\">A value range (<code data-start=\"1057\" data-end=\"1062\">min<\/code>, <code data-start=\"1064\" data-end=\"1069\">max<\/code>) over which that function is evaluated<\/p>\r\n    <\/li>\r\n    <li data-start=\"1101\" data-end=\"1167\">\r\n    <p data-start=\"1103\" data-end=\"1167\">A number of <code data-start=\"1116\" data-end=\"1127\">intervals<\/code> that determines the table resolution<\/p>\r\n    <\/li>\r\n    <li data-start=\"1168\" data-end=\"1247\">\r\n    <p data-start=\"1170\" data-end=\"1247\">Optional parameters (<code data-start=\"1193\" data-end=\"1196\">A<\/code>, <code data-start=\"1198\" data-end=\"1201\">B<\/code>, <code data-start=\"1203\" data-end=\"1206\">C<\/code>...) that you can use inside the formula<\/p>\r\n    <\/li>\r\n<\/ul>\r\n<p data-start=\"1249\" data-end=\"1421\">Once the table is built, the function behaves like any other distribution: a random value is drawn, the table is consulted, and the corresponding result is returned.<\/p>\r\n<p data-start=\"1249\" data-end=\"1421\"><b>Syntax:<\/b><\/p>\r\n<pre>\r\nFunction {\r\n  Name: name,\r\n  Type: FDISTRIBUTION,\r\n  Expression: \"formula\",\r\n  min: minValue,\r\n  max: maxValue,\r\n  intervals: count,\r\n  A: value, B: value, ...\r\n}\r\n<\/pre>\r\n<p><b>Example 1: Custom Gaussian distribution<\/b><\/p>\r\n<pre>\r\nFunction {\r\n  Name:gauss1,\r\n  Type: FDISTRIBUTION,\r\n  EXPRESSION: \"(1 \/ (A * SQRT(2 * PI))) * EXP(-0.5 * ((X - B) \/ A)^2)\",\r\n  A: 2.3,\r\n  B: 30,\r\n  min: B - (3 * A),\r\n  max: B + (3 * A),\r\n  intervals: 100\r\n}\r\n<\/pre>\r\n<p>This example creates a bell-shaped function centered at <strong data-start=\"1965\" data-end=\"1971\">30<\/strong>, with dispersion <strong data-start=\"1988\" data-end=\"1995\">2.3<\/strong>. It is equivalent to a classic Gaussian, but fully configurable.<\/p>\r\n<p><b>Example 2: Triangular distribution defined by formula<\/b><\/p>\r\n<pre>\r\nFunction {\r\n  Name:tri1,\r\n  Type: FDISTRIBUTION,\r\n  EXPRESSION: \"(1 \/ C) * (1 - ABS((X - B) \/ (C \/ 2)))\",\r\n  B: 25, C: 30,\r\n  min: B - C \/ 2,\r\n  max: B + C \/ 2,\r\n  intervals: 100\r\n}\r\n<\/pre>\r\n<p>This function generates a triangular distribution with its peak at <strong data-start=\"2386\" data-end=\"2392\">25<\/strong>, total width <strong data-start=\"2411\" data-end=\"2417\">30<\/strong>, and base <strong data-start=\"2429\" data-end=\"2441\">[10, 40]<\/strong>.<\/p>\r\n<h3 data-start=\"2449\" data-end=\"2471\">Technical details:<\/h3>\r\n<ul data-start=\"2473\" data-end=\"2736\">\r\n    <li data-start=\"2473\" data-end=\"2522\">\r\n    <p data-start=\"2475\" data-end=\"2522\">The variable <code data-start=\"2487\" data-end=\"2490\">X<\/code> is the horizontal axis (domain).<\/p>\r\n    <\/li>\r\n    <li data-start=\"2523\" data-end=\"2584\">\r\n    <p data-start=\"2525\" data-end=\"2584\">The function is evaluated <code data-start=\"2546\" data-end=\"2557\">intervals<\/code> times between <code data-start=\"2570\" data-end=\"2575\">min<\/code> and <code data-start=\"2578\" data-end=\"2583\">max<\/code>.<\/p>\r\n    <\/li>\r\n    <li data-start=\"2585\" data-end=\"2667\">\r\n    <p data-start=\"2587\" data-end=\"2667\">The integral is automatically normalized so it behaves like a probability distribution.<\/p>\r\n    <\/li>\r\n    <li data-start=\"2668\" data-end=\"2736\">\r\n    <p data-start=\"2670\" data-end=\"2736\">All parameters (<code data-start=\"2692\" data-end=\"2695\">A<\/code>, <code data-start=\"2697\" data-end=\"2700\">B<\/code>, <code data-start=\"2702\" data-end=\"2705\">C<\/code>, etc.) can be expressions.<\/p>\r\n    <\/li>\r\n<\/ul>\r\n<p>&nbsp;<\/p>\r\n<p>&nbsp;<\/p>",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            },
            {
                "id": "313",
                "nombre": "MATH functions",
                "texto": "\/*\r\n\r\n  \t \tMath\r\n \r\n*\/\r\nGraphic {NAME:Text1,Type:TEXT,X:370,Y:312,Text:\"Hello\"}\r\n\r\nFunction {Name:math1, type: MATH, EXPRESSION:\"A * 2 + B\"}\r\n\r\nSTART 1\r\n;*****************************************************\r\nGENERATE 1,0,0,1 {NAME:GEN1,X:56,Y:319}\r\n\r\nassign AAA,4\r\nassign BBB,6\r\n\r\nmove {name:Text1,text:\"Result: FN$(math1,P$AAA,P$BBB)\"}\r\n\r\nENDGENERATE 1\r\n\r\n\r\n\r\n\r\n\r\n\r\n",
                "descripcion": "<h3>Custom mathematical formulas<\/h3>\r\n<p data-start=\"231\" data-end=\"521\">The <code data-start=\"239\" data-end=\"245\">MATH<\/code> type lets you define functions that are evaluated as <strong data-start=\"292\" data-end=\"325\">direct mathematical formulas<\/strong>, without using distributions or precomputed value tables. They are useful when the value we need <strong data-start=\"434\" data-end=\"520\">depends on variables deterministically, or on an algebraic expression<\/strong>.<\/p>\r\n<p data-start=\"523\" data-end=\"678\">This type of function <strong data-start=\"544\" data-end=\"570\">does not generate randomness<\/strong>. It simply takes the parameters in order, substitutes them into the expression, and returns the result.<\/p>\r\n<p>Syntax:<\/p>\r\n<pre>\r\nFunction {Name:name, Type:MATH, Expression:\"A + B * C\"}\r\n<\/pre>\r\n<p>&nbsp;<\/p>\r\n<ul>\r\n    <li><code data-start=\"771\" data-end=\"777\">Name<\/code>: identifier name of the function.<\/li>\r\n    <li><code data-start=\"817\" data-end=\"823\">Type<\/code>: must be <code data-start=\"834\" data-end=\"840\">MATH<\/code>.<\/li>\r\n    <li><code data-start=\"844\" data-end=\"856\">Expression<\/code>: formula to evaluate, using uppercase letters as variables (A, B, C...). These letters represent the parameters passed in order.<\/li>\r\n<\/ul>\r\n<p><b>How do you call a <code data-start=\"1032\" data-end=\"1038\">MATH<\/code> function?<\/b><\/p>\r\n<p>It is used like any <code data-start=\"1075\" data-end=\"1080\">FN$<\/code> function, but with parameters in parentheses:<\/p>\r\n<pre>\r\nFN$(name, value_A, value_B, ...)\r\n<\/pre>\r\n<p>&nbsp;<\/p>\r\n<p>&nbsp;<\/p>\r\n<p>&nbsp;<\/p>\r\n<p>&nbsp;<\/p>",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            }
        ]
    },
    {
        "id": "264",
        "nombre": "Season 10: Continuous Systems",
        "texto": "",
        "descripcion": "",
        "parametros": null,
        "parametros_json": null,
        "ejemplo": null,
        "hijos": [
            {
                "id": "267",
                "nombre": "Continuous system within the discrete",
                "texto": "\/*\r\n\r\n Continuous system within the discrete\r\n \r\n*\/\r\nSYSTEM {TYPE:PRE_RUN,TRIGGER:PRE_RUN}\r\nSYSTEM {type:OPTIONS, TIME_DECIMALS:1, SPEED:5}\r\nSYSTEM {TYPE:ON_TIMER, TRIGGER:filling, INTERVAL: 0.1}\r\n\r\nGraphic {NAME:alert,Type:TEXT,X:291,Y:342,Text:\"alert\"}\r\n\r\nFunction {Name:fcFlow, Type:Math, Expression:\"0.6 + SIN(A) * 4\"}\r\n\r\nINITIAL level, 0\r\nINITIAL flow, 1.2\r\nINITIAL phase, 0\r\nINITIAL constant, 0.6\r\n\r\ninclude .\/library_graphics\/speedometer.lib\r\n\r\nSTART 100\r\n\r\nPROCEDURE PRE_RUN\r\n\tassign config,{title:\"Tank\"\r\n    \t\t,x:100,y:60 \r\n            ,width:100 ,height:180\r\n\t       \t,min_value: 0\r\n    \t\t,max_value: 100\r\n            ,\"color\":\"#ff0000\"}\r\n            \r\n\tcall tank.speedometer.init,V$config\r\n\r\n\tassign config,{title:\"Flow Rate\"\r\n    \t\t,x:300,y:60 \r\n            ,width:100 ,height:180\r\n\t       \t,min_value: -10\r\n    \t\t,max_value: 10\r\n            ,\"color\":\"orange\"}\r\n            \r\n\tcall flow.speedometer.init,V$config\r\n\r\nTERMINATE_VE \r\nENDPROCEDURE\r\n\r\nPROCEDURE filling\r\n    ; Oscillate flow rate as a function of simulated time\r\n    SAVEVALUE flow, FN$(fcFlow,X$fase)\r\n\r\n    ; Increment the phase smoothly\r\n    SAVEVALUE phase, X$fase + 0.1\r\n\r\n    ; Add flow to the level, according to the time interval\r\n    SAVEVALUE level, X$level + X$flow * 0.1\r\n\r\n    ; Rounded values for display\r\n    ASSIGN tFlow, round(X$flow, 2)\r\n    ASSIGN tLevel, round(X$level, 2)\r\n\tCALL tank.speedometer.set, P$tLevel\r\n\tCALL flow.speedometer.set, P$tFlow\r\n    \r\n    ; Status visualization\r\n    IF (X$level>=100)\r\n        MOVE {name:alert, text:\"TANK FULL!\"}\r\n        STOP\r\n    ELSE\r\n        MOVE {name:alert, text:\"Level: P$tLevel - Flow: P$tFlow\"}\r\n    ENDIF\r\nTERMINATE\r\nENDPROCEDURE 1\r\n",
                "descripcion": "<p>So far we have seen how <strong data-start=\"245\" data-end=\"258\">GPSS-Plus<\/strong> is, in its essence, a <strong data-start=\"312\" data-end=\"325\">discrete<\/strong> event simulation engine. However, it is also capable of simulating <strong data-start=\"369\" data-end=\"382\">continuous<\/strong> systems—those in which changes occur gradually over time.<\/p>\r\n<h3 data-start=\"475\" data-end=\"510\">What is a continuous system?<\/h3>\r\n<p data-start=\"512\" data-end=\"603\">A continuous system is one where values change without interruptions. For example:<\/p>\r\n<ul data-start=\"605\" data-end=\"746\">\r\n    <li>The level of a tank being filled.<\/li>\r\n    <li>The temperature of a furnace being heated.<\/li>\r\n    <li>The velocity of a car accelerating smoothly.<\/li>\r\n<\/ul>\r\n<p data-start=\"748\" data-end=\"878\">In these cases, there are no discrete \"jumps\" like those in a queue or a customer entering or leaving. The change happens progressively.<\/p>\r\n<h3 data-start=\"880\" data-end=\"930\">How to simulate that in a discrete environment?<\/h3>\r\n<p data-start=\"932\" data-end=\"1266\">The answer is: <strong data-start=\"949\" data-end=\"995\">cheating, but intelligently<\/strong>. Instead of simulating a constant and fluid change, we divide it into <strong>small<\/strong> <strong data-start=\"1063\" data-end=\"1096\">time steps<\/strong>, fast enough so that it <strong data-start=\"1132\" data-end=\"1152\">looks continuous<\/strong>.<br>\r\nIt is like cinema: each frame is a static image, but when played at 24 frames per second, we perceive motion.<\/p>\r\n<h3 data-start=\"1268\" data-end=\"1308\">How is this done in GPSS-Plus?<\/h3>\r\n<p data-start=\"1310\" data-end=\"1332\">With key adjustments:<\/p>\r\n<pre>\r\nSYSTEM {type:OPTIONS, TIME_DECIMALS:1, SPEED:5}\r\n<\/pre>\r\n<p>&nbsp;<\/p>\r\n<ul>\r\n    <li><code data-start=\"1404\" data-end=\"1421\">TIME_DECIMALS:1<\/code> indicates that time is measured with one decimal place (0.1).<\/li>\r\n    <li><code data-start=\"1479\" data-end=\"1490\">SPEED:5<\/code> sets the system update to a medium speed. From 0 (pause) to 10 (maximum speed). <b>A medium speed (5) means that 10 AC1 instants take approximately 1 second. With <code>SPEED:2<\/code>, 1 second is roughly equivalent to 1 AC1.<\/b><\/li>\r\n<\/ul>\r\n<p>The engine remains discrete. Time <em data-start=\"1659\" data-end=\"1682\">does not advance on its own<\/em>; it advances when an entity is serviced or an event is triggered. What we do is generate many small events in rapid succession.<\/p>\r\n<p>&nbsp;<\/p>\r\n<p><b>Example: Filling a tank<\/b><\/p>\r\n<p>We are going to fill a tank with a <strong data-start=\"1889\" data-end=\"1908\">variable flow rate<\/strong> (for example, following a sine function to make it more dynamic).<\/p>\r\n<p>To do this, we use a <strong data-start=\"2000\" data-end=\"2009\">timer<\/strong>, which launches a block of code every 0.1 units of time. It does not generate transactions or statistics: it just executes.<\/p>\r\n<pre>\r\nSYSTEM {TYPE:ON_TIMER, TRIGGER:filling, INTERVAL: 0.1}<\/pre>\r\n<p>Each time the <code data-start=\"2225\" data-end=\"2236\">PROCEDURE<\/code> is triggered, we will:<\/p>\r\n<ol>\r\n    <li>Calculate a flow rate based on an oscillating function, previously defined with <code data-start=\"522\" data-end=\"542\">FUNCTION TYPE:MATH<\/code>.<\/li>\r\n    <li>Add that flow to the current tank level.<\/li>\r\n    <li>Visually update the level.<\/li>\r\n    <li>Display the value on the screen.<\/li>\r\n    <li>Stop the simulation if the tank becomes full.<\/li>\r\n<\/ol>\r\n<p>&nbsp;<\/p>\r\n<p>In this case, each cycle calculated the <strong data-start=\"1020\" data-end=\"1030\">flow rate<\/strong> and added it to the <strong data-start=\"1046\" data-end=\"1055\">level<\/strong> using a simple formula:<\/p>\r\n<pre>\r\nSAVEVALUE level, X$level + X$flow * 0.1\r\n<\/pre>\r\n<p>This method is called the <strong data-start=\"1159\" data-end=\"1178\">Euler method<\/strong>, and it is the simplest form of <b>numerical integration<\/b>.<\/p>\r\n<p>It estimates that during the time interval between AC1$ and AC1$ + 0.1, the tank will fill by an amount equal to the flow rate at instant AC1$ multiplied by the 0.1 interval.<\/p>\r\n<p>In the next step, it will perform the same calculation again using the new flow rate value at that instant. And so on, adding small amounts as if it were a sum of rectangles: that is, in essence, an <strong data-start=\"924\" data-end=\"936\">integral<\/strong>.<\/p>",
                "parametros": "",
                "parametros_json": "",
                "ejemplo": "",
                "hijos": []
            },
            {
                "id": "266",
                "nombre": "PLOT data collection",
                "texto": "\/*\r\n\r\n PLOT data collection\r\n \r\n*\/\r\nSYSTEM {TYPE:PRE_RUN,TRIGGER:PRE_RUN}\r\n\r\nSYSTEM {type:OPTIONS, TIME_DECIMALS:1, SPEED:5}\r\nSYSTEM {TYPE:ON_TIMER, TRIGGER:filling, INTERVAL: 0.1}\r\n\r\nPLOTTER {NAME:thePlot, Y_0:level, Y_1:flow, X:TIME_AC1}\r\n\r\nGraphic {NAME:warning,Type:TEXT,X:291,Y:342,Text:\"warning\"}\r\n\r\nFunction {Name:fcFlow, Type:Math, Expression:\"0.6 + SIN(A) * 4\"}\r\n\r\nINITIAL level, 0\r\nINITIAL flow, 1.2\r\nINITIAL phase, 0\r\n\r\ninclude .\/library_graphics\/speedometer.lib\r\n\r\nSTART 100\r\n\r\nPROCEDURE PRE_RUN\r\n\tassign config,{title:\"Tank\"\r\n    \t\t,x:100,y:60 \r\n            ,width:100 ,height:180\r\n\t       \t,min_value: 0\r\n    \t\t,max_value: 100\r\n            ,\"color\":\"#ff0000\"}\r\n            \r\n\tcall tank.speedometer.init,V$config\r\n\r\n\tassign config,{title:\"Flow\"\r\n    \t\t,x:300,y:60 \r\n            ,width:100 ,height:180\r\n\t       \t,min_value: -10\r\n    \t\t,max_value: 10\r\n            ,\"color\":\"orange\"}\r\n            \r\n\tcall flow.speedometer.init,V$config\r\n\r\nTERMINATE_VE \r\nENDPROCEDURE\r\n\r\nPROCEDURE filling\r\n    ; Oscillate flow as a function of simulated time\r\n    SAVEVALUE flow, FN$(fcFlow,X$phase)\r\n\r\n    ; Increase phase\r\n    SAVEVALUE phase, X$phase + 0.1\r\n\r\n    ; Add flow to the level\r\n    SAVEVALUE level, X$level + X$flow * 0.1\r\n\r\n    ; Record data into the plotter\r\n    PLOT thePlot, X$level, X$flow\r\n\r\n    ; Display rounded values\r\n    ASSIGN tFlow, round(X$flow, 2)\r\n    ASSIGN tLevel, round(X$level, 2)\r\n\r\n    ; Update visual indicators\r\n\tCALL tank.speedometer.set, P$tLevel\r\n\tCALL flow.speedometer.set, P$tFlow\r\n\r\n\tIF (X$level>=100)\r\n        MOVE {name:warning, text:\"TANK FULL!\"}\r\n        STOP\r\n    ELSE\r\n        MOVE {name:warning, text:\"Level: P$tLevel - Flow: P$tFlow\"}\r\n    ENDIF\r\nTERMINATE\r\nENDPROCEDURE 1\r\n",
                "descripcion": "<p>In the previous chapter we saw how GPSS-Plus can simulate <em>apparently continuous<\/em> behaviors by using <code>TIMERs<\/code> and very small time steps. We observed, for example, how a tank was filled on screen, simulating a constant process.<\/p>\r\n<p>Now we go one step further:<br>\r\nWe are not only going to <strong>see<\/strong> what happens… we are going to <strong>record it and automatically plot it<\/strong> for later analysis.<\/p>\r\n<p>Because in many cases, <strong>observing motion is not enough<\/strong>: we need a curve, a graph, a historical record of the behavior.<br>\r\nFor that purpose, GPSS-Plus provides a data tracing system:<\/p>\r\n<h3><code>PLOTTER<\/code> and <code>PLOT<\/code><\/h3>\r\n<ul>\r\n    <li><code>PLOTTER {}<\/code>: declares a graphical table where values will be stored.<\/li>\r\n    <li><code>PLOT<\/code>: adds a point to that table, using the current time or another variable as the X axis.<\/li>\r\n<\/ul>\r\n<p>Each added point is like a system “frame”, and when the simulation ends, GPSS-Plus draws a <strong>curve<\/strong> using all recorded points.<\/p>\r\n<h3>Usage example<\/h3>\r\n<p>In our case, we will record:<\/p>\r\n<pre>\r\nPLOTTER {NAME:thePlot, Y_0:level, Y_1:flow, X:TIME_AC1}\r\n<\/pre>\r\n<p>This means:<\/p>\r\n<ul>\r\n    <li>We will plot two value series: <code>level<\/code> and <code>flow<\/code>.<\/li>\r\n    <li>The horizontal axis (X) will be time (<code>AC1$<\/code>), referenced as <code>TIME_AC1<\/code>.<\/li>\r\n<\/ul>\r\n<p>To add points at each instant:<\/p>\r\n<pre>\r\nPLOT thePlot, X$level, X$flow\r\n<\/pre>\r\n<p>This is executed inside the <code>PROCEDURE<\/code>, on every call, gradually building the process history.<\/p>\r\n<p><em>“LEVEL is obtained by accumulating FLOW. The system simulates a continuous integration.”<\/em><br>\r\n<em>“Each point corresponds to an instant automatically generated by the TIMER.”<\/em><\/p>",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            },
            {
                "id": "265",
                "nombre": "Improving results with INTEGRATE",
                "texto": "\/*\r\n\r\n Improving results with INTEGRATE\r\n \r\n*\/\r\nSYSTEM {type:OPTIONS, TIME_DECIMALS:1, SPEED:5}\r\nSYSTEM {TYPE:ON_TIMER, TRIGGER:filling, INTERVAL: 0.1}\r\n\r\nPLOTTER {NAME:thePlot, Y_0:level, Y_1:flow,X:TIME_AC1}\r\nPLOTTER {NAME:thePlot_RK4, Y_0:level, Y_1:flow,X:TIME_AC1}\r\nPLOTTER {NAME:thePlot_ALL, Y_0:level, Y_1:flow, Y_2:level_RK4, Y_3:flow_RK4,X:TIME_AC1}\r\n\r\nGraphic {NAME:warning,Type:TEXT,X:291,Y:342,Text:\"warning\"}\r\nGraphic {NAME:warning_RK4,Type:TEXT,X:291,Y:302,Text:\"Warning2\"}\r\n\r\nGraphic {NAME:Cube1,Type:LINE,POINTS:\"[100,100],[100,500],[200,500],[200,100]\"\r\n\t, Close:1\r\n    , color:#00FFFF\r\n    , Fcolor:#FFFFFF}\r\nGraphic {NAME:Line1,Type:LINE,fcolor:#FF6666, X1:102,Y1:100,X2:198,Y2:100}\r\n\r\nGraphic {NAME:Line_RK4,Type:LINE,color:#333300, X1:98,Y1:100,X2:202,Y2:100}\r\n\r\nINITIAL level, 0\r\nINITIAL flow, 1.2\r\nINITIAL level_RK4, 0\r\nINITIAL flow_RK4, 1.2\r\nINITIAL phase, 0\r\nINITIAL constant, 0.6\r\n\r\nSTART 100\r\n\r\n;*****************************************************\r\nPROCEDURE filling\r\n    ; Oscillate flow as a function of simulated time\r\n    SAVEVALUE flow, X$constant + SIN(X$phase) * 4\r\n    ; Smoothly increase the phase\r\n    SAVEVALUE phase, X$phase + 0.1\r\n    ; Continuous integration of the level\r\n   \r\n    INTEGRATE  { EXPRESSION: \"X$constant + SIN(T) * 4\", METHOD: RK4, DT: 0.1, SAVEVALUE: flow_RK4 }\r\n    \r\n    SAVEVALUE level, X$level + X$flow * 0.1\r\n    SAVEVALUE level_RK4, X$level_RK4 + X$flow_RK4 * 0.1\r\n\r\n\tPLOT thePlot,X$level,X$flow\r\n\tPLOT thePlot_RK4,X$level_RK4,X$flow_RK4\r\n\tPLOT thePlot_ALL,X$level,X$flow,X$level_RK4,X$flow_RK4\r\n\r\n\tMOVE {NAME:Line1, X1:98,Y1:(100+X$level*4) ,X2:202,Y2:(100+X$level*4)}\r\n\tMOVE {NAME:Line_RK4, X1:98,Y1:(100+X$level_RK4*4) ,X2:202,Y2:(100+X$level_RK4*4)}\r\n\r\n    ASSIGN tFlow, round(X$flow, 2)\r\n    ASSIGN tLevel, round(X$level, 2)\r\n\r\n\tASSIGN tFlow_RK4, round(X$flow_RK4, 2)\r\n    ASSIGN tLevel_RK4, round(X$level_RK4, 2)\r\n    \r\n    ; State display\r\n    IF (X$level>=100)\r\n        MOVE {name:warning, text:\"TANK FULL!\"}\r\n        stop\r\n    ELSE\r\n        MOVE {name:warning, text:\"Level: P$tLevel - Flow: P$tFlow\"}\r\n        MOVE {name:warning_RK4, text:\"Level: P$tLevel_RK4 - Flow: P$tFlow_RK4\"}\r\n    ENDIF\r\nTERMINATE\r\nENDPROCEDURE 1\r\n\r\n\r\n\r\n\r\n",
                "descripcion": "<p data-start=\"206\" data-end=\"473\">In previous chapters we saw how GPSS-Plus can simulate systems with an apparently continuous behavior thanks to frequent execution of timed procedures (<code data-start=\"387\" data-end=\"394\">TIMER<\/code>) and the use of <code data-start=\"408\" data-end=\"419\">SAVEVALUE<\/code> to accumulate values such as filling a tank.<\/p>\r\n<p data-start=\"475\" data-end=\"539\">Up to now we used a simple formula to simulate the filling:<\/p>\r\n<pre>\r\nSAVEVALUE level, X$level + X$flow * 0.1<\/pre>\r\n<p data-start=\"475\" data-end=\"539\">This method is effective, but basic. It assumes the flow is constant during each time interval, which is not entirely true if the flow changes rapidly, for example with a sine function as in this case.<\/p>\r\n<p data-start=\"475\" data-end=\"539\">And when we talk about interval, here we are talking about that \"0.1\". SIN(0) is not the same as SIN(0.1). And if we want a <strong data-start=\"725\" data-end=\"756\">more accurate estimate of the average value<\/strong>, it would probably be better to use <code data-start=\"789\" data-end=\"800\">SIN(0.05)<\/code>, i.e., the <strong data-start=\"821\" data-end=\"832\">midpoint<\/strong> of the interval.<\/p>\r\n<h3 data-start=\"820\" data-end=\"883\">What happens if the flow varies during the time step?<\/h3>\r\n<p data-start=\"885\" data-end=\"1048\">When the value you are accumulating changes within the same interval, the system is not perfectly exact: you are adding an approximate average value, not the real one.<\/p>\r\n<p data-start=\"1050\" data-end=\"1251\">To improve this, GPSS-Plus includes the <code data-start=\"1099\" data-end=\"1110\">INTEGRATE<\/code> block, which uses a numerical integration method called <strong data-start=\"1166\" data-end=\"1203\">fourth-order Runge-Kutta (RK4)<\/strong> to compute a much more accurate estimate.<\/p>\r\n<h3>What does INTEGRATE do?<\/h3>\r\n<pre>\r\nINTEGRATE { EXPRESSION: \"SIN(T) + 2\", DT: 0.1, SAVEVALUE: flow_RK4 }<\/pre>\r\n<p data-start=\"1371\" data-end=\"1383\">This block:<\/p>\r\n<ul>\r\n    <li>\r\n    <p data-start=\"826\" data-end=\"967\">Evaluates the expression at four key points of the interval: at the start (<code data-start=\"895\" data-end=\"898\">X<\/code>), twice at the midpoint (<code data-start=\"930\" data-end=\"940\">X + DT\/2<\/code>), and at the end (<code data-start=\"955\" data-end=\"963\">X + DT<\/code>).<\/p>\r\n    <\/li>\r\n    <li>\r\n    <p data-start=\"970\" data-end=\"1140\">Applies the fourth-order Runge-Kutta (RK4) method, combining those values with specific weights to accurately estimate how the function varies over that segment.<\/p>\r\n    <\/li>\r\n    <li>\r\n    <p data-start=\"1143\" data-end=\"1262\">Stores the result in the indicated <code data-start=\"1169\" data-end=\"1180\">SAVEVALUE<\/code>, as a better estimate of the average value of the expression over that interval.<\/p>\r\n    <\/li>\r\n<\/ul>\r\n<p>The resulting value will be a <strong data-start=\"1639\" data-end=\"1676\">better estimate of the mean flow<\/strong> in that time interval, and we can use it to fill the tank more accurately.<\/p>\r\n<p>&nbsp;<\/p>\r\n<h3>Comparing the traditional method (Euler) and RK4<\/h3>\r\n<p data-start=\"1826\" data-end=\"1897\">We will build an example that uses <strong data-start=\"1867\" data-end=\"1896\">both methods in parallel<\/strong>:<\/p>\r\n<ul data-start=\"1899\" data-end=\"2068\">\r\n    <li data-start=\"1899\" data-end=\"1934\"><p data-start=\"1901\" data-end=\"1934\"><code data-start=\"1901\" data-end=\"1909\">flow<\/code>: using the simple method<\/p><\/li>\r\n    <li data-start=\"1935\" data-end=\"1982\"><p data-start=\"1937\" data-end=\"1982\"><code data-start=\"1937\" data-end=\"1949\">flow_RK4<\/code>: using RK4 numerical integration<\/p><\/li>\r\n    <li data-start=\"1983\" data-end=\"2025\"><p data-start=\"1985\" data-end=\"2025\"><code data-start=\"1985\" data-end=\"1992\">level<\/code>: accumulated with the classic flow<\/p><\/li>\r\n    <li data-start=\"2026\" data-end=\"2068\"><p data-start=\"2028\" data-end=\"2068\"><code data-start=\"2028\" data-end=\"2039\">level_RK4<\/code>: accumulated with the RK4 flow<\/p><\/li>\r\n<\/ul>\r\n<p data-start=\"2070\" data-end=\"2162\">In addition, we will plot the 4 curves using <code data-start=\"2111\" data-end=\"2120\">PLOTTER<\/code> to visually compare the results.<\/p>\r\n<h3 data-start=\"2169\" data-end=\"2201\">What will you see in the plot?<\/h3>\r\n<ul data-start=\"2203\" data-end=\"2530\">\r\n    <li data-start=\"2203\" data-end=\"2339\"><p data-start=\"2205\" data-end=\"2339\"><code data-start=\"2205\" data-end=\"2216\">level_RK4<\/code> rises slightly more smoothly and a bit faster than <code data-start=\"2266\" data-end=\"2273\">level<\/code>, because it accounts for the fact that the flow grows within the interval.<\/p><\/li>\r\n    <li data-start=\"2340\" data-end=\"2432\"><p data-start=\"2342\" data-end=\"2432\"><code data-start=\"2342\" data-end=\"2354\">flow_RK4<\/code> matches peaks and valleys better than <code data-start=\"2396\" data-end=\"2404\">flow<\/code>, which only evaluates a single point.<\/p><\/li>\r\n    <li data-start=\"2433\" data-end=\"2530\"><p data-start=\"2435\" data-end=\"2530\">The white line on screen (RK4 level) goes a bit ahead of the blue line (simple level).<\/p><\/li>\r\n<\/ul>\r\n<h3 data-start=\"2537\" data-end=\"2583\">When is it valid to use RK4?<\/h3>\r\n<p data-start=\"2585\" data-end=\"2781\">The <strong data-start=\"2595\" data-end=\"2632\">fourth-order Runge-Kutta (RK4)<\/strong> method, implemented by the <code data-start=\"2659\" data-end=\"2670\">INTEGRATE<\/code> block in GPSS-Plus, is a numerical algorithm designed to solve ordinary differential equations of the form:<\/p>\r\n<pre>\r\ndy\/dt = f(t)<\/pre>\r\n<p data-start=\"475\" data-end=\"539\">And it does so assuming that the function <code data-start=\"2845\" data-end=\"2851\">f(t)<\/code> is continuous and smooth over the interval being integrated.<\/p>\r\n<h3 data-start=\"2918\" data-end=\"2974\">But… GPSS-Plus is a discrete-event system<\/h3>\r\n<p data-start=\"2976\" data-end=\"3134\">This means there are many variables (<code data-start=\"3017\" data-end=\"3026\">X$level<\/code>, <code data-start=\"3028\" data-end=\"3047\">X$entitiesInQueue<\/code>, <code data-start=\"3049\" data-end=\"3062\">X$facility<\/code>, etc.) that can change <strong data-start=\"3089\" data-end=\"3104\">abruptly<\/strong>, without continuity or smoothness.<\/p>\r\n<p data-start=\"3136\" data-end=\"3246\">Those changes depend on events that fire when other entities arrive, seize resources, or finish.<\/p>\r\n<p data-start=\"3248\" data-end=\"3258\">Therefore:<\/p>\r\n<p data-start=\"3260\" data-end=\"3356\"><strong data-start=\"3263\" data-end=\"3356\">You should not use INTEGRATE with expressions that depend on discrete system elements.<\/strong><\/p>\r\n<p data-start=\"3358\" data-end=\"3479\"><strong data-start=\"3360\" data-end=\"3479\">INTEGRATE with RK4 is a powerful and accurate tool, as long as it is used with purely mathematical functions.<\/strong> It is not a magical simulation of the future: it is an intelligent estimator for a well-defined function.<\/p>\r\n<p data-start=\"3248\" data-end=\"3258\">&nbsp;<\/p>\r\n<p data-start=\"475\" data-end=\"539\">&nbsp;<\/p>",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            },
            {
                "id": "315",
                "nombre": "Constant acceleration motion",
                "texto": "\/*\r\n\r\n Constant acceleration motion\r\n \r\n*\/\r\nSYSTEM {type:OPTIONS, TIME_DECIMALS:2, SPEED:5}\r\nSYSTEM {TYPE:ON_TIMER, TRIGGER:moverCoche, INTERVAL: 0.01}\r\n\r\n; --- Initial variables ---\r\nINITIAL velocidad, 0.0            ; Angular velocity\r\nINITIAL angulo, 0               ; Angular position (radians)\r\nINITIAL aceleracion, 0.01       ; Constant angular acceleration\r\nINITIAL radio, 200              ; Circular track radius\r\n\r\n; --- Graphic elements ---\r\nGraphic {NAME:txtVel, Type:TEXT, X:510, Y:120, TEXT:\"Velocity:\"}\r\nGraphic {NAME:coche, Type:LINE, X1:-10, Y1:-10,  X2:-10, Y2:10,  X3:10, Y3:10,  X4:10, Y4:-10,  COLOR:#FF0000, close:1}\r\nGraphic {NAME:pista, Type:ARC, X:300, Y:300, RADIUS:X$radio, CLOSE:0, COLOR:#999999}\r\n\r\n; --- Evolution plot ---\r\nPLOTTER {NAME:curva, Y_0:aceleracion, Y_1:velocidad, X:TIME}\r\n\r\nSTART 500\r\n\r\n; --- Motion procedure ---\r\nPROCEDURE moverCoche\r\n    IF (X$velocidad >= 4)\r\n        SAVEVALUE aceleracion, -0.1  ; Start braking\r\n    ENDIF\r\n    IF (X$velocidad <= 0.2)\r\n        SAVEVALUE aceleracion, 0.1   ; Accelerate again\r\n    ENDIF\r\n\r\n    ; Compute velocity increment\r\n    INTEGRATE {EXPRESSION: X$aceleracion, DT: 0.01, SAVEVALUE: deltaVel}\r\n\r\n    ; Accumulate velocity\r\n    SAVEVALUE velocidad, X$velocidad + X$deltaVel\r\n\r\n    ; Advance angle using velocity\r\n    SAVEVALUE angulo, X$angulo + X$velocidad * 0.05\r\n\r\n    ; Compute position\r\n    ASSIGN rad, X$angulo\r\n    ASSIGN posX, 300 + X$radio * COS(P$rad)\r\n    ASSIGN posY, 300 + X$radio * SIN(P$rad)\r\n\r\n    MOVE {NAME:coche, X:P$posX, Y:P$posY}\r\n\r\n    ASSIGN tVel, round(X$velocidad, 2)\r\n    MOVE {NAME:txtVel, TEXT: \"Velocity: P$tVel rad\/s\"}\r\n\r\n    PLOT curva, X$aceleracion, X$velocidad\r\nTERMINATE\r\nENDPROCEDURE\r\n",
                "descripcion": "<p>This example shows how to simulate the motion of a vehicle on a circular track using constant acceleration. It is a first step toward building simple physical models, such as those used in basic game engines or mechanical simulations.<\/p>\r\n<h3>What is being simulated?<\/h3>\r\n<ul>\r\n  <li>The car starts from rest (velocity 0).<\/li>\r\n  <li>A constant positive acceleration is applied until a maximum speed is reached (4 radians per second).<\/li>\r\n  <li>Once this limit is reached, acceleration is reversed so the car decelerates smoothly down to a minimum speed (0.2 rad\/s).<\/li>\r\n  <li>Then it accelerates again, repeating the cycle.<\/li>\r\n<\/ul>\r\n<h3>How is it calculated?<\/h3>\r\n<p>The <code>INTEGRATE<\/code> block is used to accumulate acceleration over time:<\/p>\r\n<pre>\r\nINTEGRATE {EXPRESSION: X$aceleracion, DT: 0.01, SAVEVALUE: deltaVel}\r\n<\/pre>\r\n<p>Since acceleration is constant:<\/p>\r\n<pre>\r\ndeltaVel = X$aceleracion * 0.01\r\n<\/pre>\r\n<p>This increment is then accumulated into the velocity:<\/p>\r\n<pre>\r\nSAVEVALUE velocidad, X$velocidad + X$deltaVel\r\n<\/pre>\r\n<h3>Visual and graphical result<\/h3>\r\n<ul>\r\n  <li>The car moves smoothly around the circular track, accelerating and braking.<\/li>\r\n  <li>The resulting plot (<code>PLOTTER<\/code>) shows two curves:\r\n    <ul>\r\n      <li><strong>Acceleration<\/strong>: a square wave switching between positive and negative values.<\/li>\r\n      <li><strong>Velocity<\/strong>: a triangular wave responding to the acceleration.<\/li>\r\n    <\/ul>\r\n  <\/li>\r\n<\/ul>\r\n<p>This behavior is typical of a basic speed control system and serves as a foundation for variable acceleration, friction, or adaptive control models.<\/p>",
                "parametros": "",
                "parametros_json": "",
                "ejemplo": "",
                "hijos": []
            },
            {
                "id": "316",
                "nombre": "Variable acceleration motion",
                "texto": "\/*\r\n\r\n Variable acceleration motion\r\n \r\n*\/\r\nSYSTEM {type:OPTIONS, TIME_DECIMALS:2, SPEED:6}\r\nSYSTEM {TYPE:ON_TIMER, TRIGGER:moverCar, INTERVAL: 0.1}\r\n\r\n; --- Initial variables ---\r\nINITIAL velocity, 0.0            ; Angular velocity\r\nINITIAL angle, 0                ; Angular position (radians)\r\nINITIAL acceleration, 0.01      ; Angular acceleration\r\nINITIAL radius, 200             ; Circular track radius\r\nINITIAL deltaA, 0.0002\r\n\r\n; --- Graphics ---\r\nGraphic {NAME:txtVel, Type:TEXT, X:510, Y:120, TEXT:\"Velocity:\"}\r\nGraphic {NAME:car, Type:LINE, X1:-10, Y1:-10, X2:-10, Y2:10, X3:10, Y3:10, X4:10, Y4:-10, COLOR:green, close:1}\r\nGraphic {NAME:track, Type:ARC, X:300, Y:300, RADIUS:X$radius, CLOSE:0, COLOR:#999999}\r\n\r\n; --- Evolution plot ---\r\nPLOTTER {NAME:curve, Y_0:acceleration, Y_1:velocity, X:TIME}\r\n\r\nSTART 500\r\n\r\nPROCEDURE moverCar\r\n    ;-------------------------------\r\n    ; SMOOTH ACCELERATION CONTROL\r\n    ;-------------------------------\r\n\r\n    ; If acceleration is too high, reduce it smoothly\r\n    IF (X$acceleration > 0.04)\r\n        SAVEVALUE deltaA, -0.003\r\n        SAVEVALUE acceleration, 0.04\r\n        MOVE {name:car, color:red}\r\n    ENDIF\r\n\r\n    ; If velocity reaches zero, reset and start accelerating again\r\n    IF (X$velocity <= 0.0)\r\n        SAVEVALUE deltaA, 0.0002\r\n        SAVEVALUE acceleration, 0\r\n        SAVEVALUE velocity, 0.0\r\n        MOVE {name:car, color:green}\r\n    ENDIF\r\n\r\n    ;---------------------------------\r\n    ; UPDATE VELOCITY AND POSITION\r\n    ;---------------------------------\r\n\r\n    ; Gradually modify acceleration\r\n    SAVEVALUE acceleration, X$acceleration + X$deltaA\r\n\r\n    ; Integrate acceleration to obtain velocity increment\r\n    INTEGRATE {EXPRESSION: X$acceleration, DT: 0.1, SAVEVALUE: deltaVel}\r\n    SAVEVALUE velocity, X$velocity + X$deltaVel\r\n\r\n    ; Update angular position\r\n    SAVEVALUE angle, X$angle + X$velocity * 0.1\r\n\r\n    ;--------------------------------\r\n    ; COMPUTE POSITION AND MOVE CAR\r\n    ;--------------------------------\r\n\r\n    ASSIGN rad, X$angle\r\n    ASSIGN posX, 300 + X$radius * COS(P$rad)\r\n    ASSIGN posY, 300 + X$radius * SIN(P$rad)\r\n    MOVE {NAME:car, X:P$posX, Y:P$posY}\r\n\r\n    ;--------------------------\r\n    ; DISPLAY STATE AND PLOTS\r\n    ;--------------------------\r\n\r\n    ASSIGN tVel, round(X$velocity, 2)\r\n    ASSIGN tAcc, round(X$acceleration, 4)\r\n    MOVE {NAME:txtVel, TEXT:\"Velocity: P$tVel rad\/s\\nAcceleration: P$tAcc\"}\r\n\r\n    ; Plot data for analysis\r\n    PLOT curve, X$acceleration, X$velocity\r\nTERMINATE\r\nENDPROCEDURE\r\n",
                "descripcion": "<p>This example extends the circular motion simulation by allowing the <strong>vehicle acceleration to evolve dynamically over time<\/strong>.<\/p>\r\n<p>Instead of switching abruptly between fixed acceleration values, the system now adjusts acceleration gradually, producing behavior closer to real vehicles: <strong>slow acceleration<\/strong> and <strong>sharper braking<\/strong>.<\/p>\r\n<h3>What is modeled?<\/h3>\r\n<ul>\r\n  <li>Progressive acceleration when starting from rest.<\/li>\r\n  <li>Stronger braking at higher speeds.<\/li>\r\n  <li>Continuous circular motion.<\/li>\r\n  <li>Real-time visualization of position and velocity.<\/li>\r\n  <li>Plots showing the evolution of acceleration and velocity.<\/li>\r\n<\/ul>\r\n<h3>Key components<\/h3>\r\n<ul>\r\n  <li><code>acceleration<\/code>: current angular acceleration.<\/li>\r\n  <li><code>deltaA<\/code>: incremental change applied to acceleration.<\/li>\r\n  <li><code>INTEGRATE<\/code>: computes velocity change from acceleration.<\/li>\r\n  <li><code>velocity<\/code>: smoothly varying angular speed.<\/li>\r\n  <li><code>angle<\/code>: angular position driving the motion.<\/li>\r\n  <li><code>PLOTTER<\/code>: records acceleration and velocity over time.<\/li>\r\n<\/ul>\r\n<h3>Acceleration control logic<\/h3>\r\n<ol>\r\n  <li>Acceleration increases slowly while speed is low.<\/li>\r\n  <li>When acceleration exceeds a threshold, its growth reverses, producing braking.<\/li>\r\n  <li>Once velocity reaches zero, the system resets and accelerates again.<\/li>\r\n<\/ol>\r\n<p>The resulting motion resembles a realistic drive cycle with <strong>smooth acceleration and sharper deceleration<\/strong>.<\/p>\r\n<h3>Visual outcome<\/h3>\r\n<ul>\r\n  <li>Acceleration follows a sawtooth-like pattern.<\/li>\r\n  <li>Velocity exhibits smooth oscillations.<\/li>\r\n  <li>The car changes color: green while accelerating, red while braking.<\/li>\r\n<\/ul>",
                "parametros": "",
                "parametros_json": "",
                "ejemplo": "",
                "hijos": []
            },
            {
                "id": "268",
                "nombre": "Hybrid simulation",
                "texto": "\/*\r\n\r\n Hybrid simulation\r\n \r\n*\/\r\nSYSTEM {type:OPTIONS, TIME_DECIMALS:0, SPEED:5}                 ; Integer time units (no decimals) and slow visual simulation\r\nSYSTEM {TYPE:ON_TIMER, TRIGGER:solarCycle, INTERVAL: 1}         ; Run procedure 'solarCycle' every 1 time unit\r\n\r\n;--- Result plots ---\r\nPLOTTER {NAME:batteryPlot, Y_0:batteryLevel, Y_1:solarFlow, X:TIME_AC1}      ; Curves: battery level and solar flow\r\n\r\n;--- Random user decision function ---\r\nFunction {Name:chargeDecision, TYPE:POISSON, LAMBDA:1\/4}                    ; Probability of deciding to charge\r\n\r\n;--- Graphic positions ---\r\nPosition {NAME:PosIn, X:431, Y:511}                                         ; Entry to the charging area\r\nPosition {NAME:PosOut, X:690, Y:510}                                        ; Exit\r\nPosition {NAME:PosCharge, X:578, Y:173}                                     ; Charging point (visual)\r\n\r\n;--- User charging resource ---\r\nRestroom {NAME:Charger, X:555, Y:360, R_BIN_SIZE:1, R_BIN_COUNT:40}         ; Allows 40 concurrent charging \"slots\"\r\n\r\n;--- Visual indicators ---\r\nGraphic {NAME:txtBattery, Type:TEXT, X:329, Y:305, Text:\"Battery\"}          ; Text: battery level\r\nGraphic {NAME:gSolarArc, TYPE:ARC, X:411, Y:173,\r\n  fCOLOR:#FFFF99, RADIUS:50, START_ANGLE:0, END_ANGLE:45, CLOSE:1}          ; Arc: solar intensity\r\nGraphic {NAME:txtSolar, Type:TEXT, X:411, Y:173, Text:\"Solar\"}              ; Text: solar flow\r\nGraphic {NAME:Box1, Type:LINE,\r\n  POINTS:\"[100,100],[100,500],[200,500],[200,100]\",\r\n  Close:1, fcolor:#666666}                                                  ; Battery tank\r\nGraphic {NAME:LevelLine, Type:LINE, color:#00FFFF, X1:98, Y1:100, X2:202, Y2:100} ; Battery level line\r\n\r\n;--- Initial variables ---\r\nINITIAL batteryLevel, 50\r\nINITIAL solarFlow, 0\r\nINITIAL requiredCharge, 15\r\n\r\nSTART 2000\r\n\r\n;==============================\r\n; SOLAR CYCLE PROCEDURE\r\n;==============================\r\nPROCEDURE solarCycle\r\n    ; Solar flow: normalized sinusoid between 0 and 1.5 over a 24h cycle (1440 minutes)\r\n    INTEGRATE { EXPRESSION: \"0.75 + 0.75 * SIN((T \/ 1440) * 6.2832)\", DT: 1, SAVEVALUE: solarFlow }\r\n\r\n    ; Increase battery (cap at 100)\r\n    SAVEVALUE batteryLevel, MIN(100, X$batteryLevel + X$solarFlow)\r\n\r\n    ; Iterate entities currently inside the Charger resource\r\n    FOREACH NUMBER, IN_RESOURCE, Charger\r\n        if (X$batteryLevel > 1)\r\n            ; Increase user's internal battery\r\n            assign current, P$(battery, P$NUMBER) + 0.5\r\n            assign battery, P$current, P$NUMBER\r\n\r\n            ; Decrease system battery\r\n            savevalue batteryLevel, X$batteryLevel - 0.5\r\n\r\n            ; If user has enough charge, release them\r\n            if (P$current > X$requiredCharge)\r\n                wake Charger, 0, P$NUMBER\r\n            endif\r\n        endif\r\n    ENDFOREACH\r\n\r\n    ; Solar arc: proportional to current flow\r\n    ASSIGN sunAngle, round((X$solarFlow \/ 1.5) * 360, 1)\r\n    MOVE {NAME:gSolarArc, END_ANGLE:P$sunAngle}\r\n\r\n    ; Update battery level line\r\n    MOVE {NAME:LevelLine, X1:98, Y1:(100 + X$batteryLevel * 4), X2:202, Y2:(100 + X$batteryLevel * 4)}\r\n\r\n    ; Show rounded values\r\n    assign tBatteryRound, round(X$batteryLevel, 2)\r\n    assign tSolarRound, round(X$solarFlow, 2)\r\n    move {name:txtBattery, text:\"Current level: P$tBatteryRound\"}\r\n    move {name:txtSolar, text:\"Solar flow: P$tSolarRound \/ 1.5\"}\r\n\r\n    ; Store data for report\r\n    PLOT batteryPlot, X$batteryLevel, X$solarFlow\r\nTERMINATE\r\nENDPROCEDURE 1\r\n\r\n;==============================\r\n; USERS\r\n;==============================\r\nGENERATE 5,5 {NAME:userGen, X:294, Y:514, ECOLOR:#000000}                   ; One user every ~5 time units\r\n\r\nassign battery, X$requiredCharge                                             ; Required energy for this user\r\n\r\nASSIGN decision, FN$chargeDecision                                            ; Decide whether they need to charge (Poisson)\r\nADVANCE 10 {to:PosIn}                                                        ; Connection \/ approach time\r\n\r\nIF (P$decision >= 1)\r\n    assign battery, 0                                                        ; Start charging counter\r\n    ADVANCE 10 {to:Charger}                                                   ; Move to charger\r\n    rest Charger                                                             ; Wait until fully charged (released by WAKE)\r\nENDIF\r\n\r\nADVANCE 10 {to:PosOut}                                                       ; Exit\r\nTERMINATE 1\r\n",
                "descripcion": "<p>In the previous chapters we simulated a tank fill using continuous functions, recorded its evolution with <code>PLOTTER<\/code>, and improved accuracy with numerical integration (<code>INTEGRATE<\/code>, RK4). Now we combine all of that into a <strong>realistic hybrid system<\/strong> where continuous and discrete logic coexist.<\/p>\r\n<h4>Example: solar station with users connected<\/h4>\r\n<p>This model represents a <strong>hybrid system<\/strong> where:<\/p>\r\n<ul>\r\n  <li>There is a <strong>solar energy source<\/strong> (continuous model)<\/li>\r\n  <li>There are <strong>discrete users<\/strong> who arrive, decide whether they need to charge, and connect if needed<\/li>\r\n<\/ul>\r\n<h3>Continuous part: solar generation<\/h3>\r\n<p>Solar input is modeled as a sinusoid that simulates the day cycle: it oscillates smoothly from 0 to 1.5 over 1440 minutes (24 hours). Each time unit represents one minute, and each timer tick adds energy to the system battery.<\/p>\r\n<pre>\r\nINTEGRATE {\r\n  EXPRESSION: \"0.75 + 0.75 * SIN((T \/ 1440) * 6.2832)\",\r\n  DT: 1,\r\n  SAVEVALUE: solarFlow\r\n}\r\n<\/pre>\r\n<p>The result is accumulated into <code>batteryLevel<\/code> with a maximum cap of 100. A <code>PLOTTER<\/code> records both battery level and solar flow every cycle, producing a full-day evolution curve in the report.<\/p>\r\n<h3>Discrete part: users requesting charge<\/h3>\r\n<p>Users arrive using <code>GENERATE<\/code>. Each one decides whether to charge using a Poisson-based decision function:<\/p>\r\n<pre>\r\nFunction {Name:chargeDecision, TYPE:POISSON, LAMBDA:1\/4}\r\n<\/pre>\r\n<p>If they decide to charge, they move to the charger resource (<code>RESTROOM<\/code>), wait there, and are released automatically via <code>WAKE<\/code> once they reach the required charge level (<code>requiredCharge<\/code>).<\/p>\r\n<h3>How both worlds are coordinated<\/h3>\r\n<p>Every time <code>solarCycle<\/code> runs:<\/p>\r\n<ul>\r\n  <li>Solar flow is updated (continuous)<\/li>\r\n  <li>The system battery is recharged with that flow<\/li>\r\n  <li>All users currently connected to the charger are iterated (<code>FOREACH ... IN_RESOURCE<\/code>) and receive energy if available<\/li>\r\n  <li>Fully charged users are released using <code>WAKE<\/code><\/li>\r\n<\/ul>\r\n<p>Visually, the model shows a battery tank level, an arc representing current solar intensity, and a plot of the recorded evolution.<\/p>\r\n<h3>Conclusion<\/h3>\r\n<p>This is a <strong>continuous\/discrete hybrid model<\/strong>: a continuous environmental evolution (solar generation) combined with discrete arrivals, decisions, and resource occupancy (users charging). This structure is typical in energy systems, shared infrastructure, and any scenario with intermittent production and variable demand.<\/p>",
                "parametros": "",
                "parametros_json": "",
                "ejemplo": "",
                "hijos": []
            }
        ]
    },
    {
        "id": "377",
        "nombre": "Season 11: Non-Linear Systems",
        "texto": "",
        "descripcion": "",
        "parametros": null,
        "parametros_json": null,
        "ejemplo": null,
        "hijos": [
            {
                "id": "317",
                "nombre": "Nonlinear systems",
                "texto": "",
                "descripcion": "",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": [
                    {
                        "id": "318",
                        "nombre": "Nonlinear systems",
                        "texto": "\/*\r\n\r\n Nonlinear systems\r\n \r\n*\/\r\nSYSTEM {TYPE:PRE_RUN, TRIGGER:PRE_RUN}\r\nSYSTEM {type:OPTIONS, TIME_DECIMALS:1, SPEED:5}\r\n\r\nPLOTTER {NAME:pressures, Y_0:tank1, Y_1:tank2, X:TIME_AC1}\r\nPLOTTER {NAME:flowPlot, Y_0:flow, X:TIME_AC1}\r\n\r\nGraphic {NAME:txtStatus, Type:TEXT, X:327, Y:486, Text:\"txt\"}   ; Status text\r\n\r\nINITIAL TANK1_PRESSURE, 10\r\nINITIAL TANK2_PRESSURE, 1\r\nINITIAL K, 0.1\r\n\r\nINITIAL dynamic_config, {\r\n  EXPRESSIONS: [\r\n    \"PIPE_FLOW + PIPE_K * (TANK1_PRESSURE - TANK2_PRESSURE)\",\r\n    \"TANK1_PRESSURE - TANK1_PRESSURE_PREV - PIPE_FLOW * DT\",\r\n    \"TANK2_PRESSURE - TANK2_PRESSURE_PREV + PIPE_FLOW * DT\"\r\n  ],\r\n  STATES: [\"PIPE_FLOW\", \"TANK1_PRESSURE\", \"TANK2_PRESSURE\"],\r\n  VARIABLES: [\"PIPE_K\", \"TANK1_PRESSURE_PREV\", \"TANK2_PRESSURE_PREV\"]\r\n}\r\n\r\nINITIAL dynamic_values, {\r\n  PIPE_K: X$K,\r\n  TANK1_PRESSURE_PREV: X$TANK1_PRESSURE,\r\n  TANK2_PRESSURE_PREV: X$TANK2_PRESSURE\r\n}\r\n\r\nDYNAMIC {name:sys,\r\n  CONFIG:V$dynamic_config,\r\n  VALUES:V$dynamic_values,\r\n  X:300, Y:300,\r\n  TOLERANCE: 1e-6, MAX_ITER: 10\r\n}\r\n\r\nSTART 1000\r\n\r\ninclude .\/library_graphics\/tank.lib\r\n\r\n;==============================================================\r\n\r\nPROCEDURE agent.init\r\n\r\n  timeout change_tank, 10\r\n  advance 0.1\r\n\r\n  while (1==1)\r\n\r\n    SOLVE {name:\"sys\", DT:0.1, SAVEVALUE:\"result\"}\r\n\r\n    SAVEVALUE TANK1_PRESSURE, X$(result.TANK1_PRESSURE)\r\n    SAVEVALUE TANK2_PRESSURE, X$(result.TANK2_PRESSURE)\r\n    SAVEVALUE PIPE_FLOW,      X$(result.PIPE_FLOW)\r\n\r\n    PLOT pressures, X$TANK1_PRESSURE, X$TANK2_PRESSURE\r\n    PLOT flowPlot,  X$PIPE_FLOW\r\n\r\n    assign rFlow, round(X$PIPE_FLOW, 3)\r\n    assign rH1,   round(X$TANK1_PRESSURE, 3)\r\n    assign rH2,   round(X$TANK2_PRESSURE, 3)\r\n\r\n    move {name:txtStatus, text:\"flow: P$rFlow  T1: P$rH1  T2: P$rH2\"}\r\n\r\n    CALL tank1.tank.set, P$rH1\r\n    CALL tank2.tank.set, P$rH2\r\n\r\n    IF (ABS(X$PIPE_FLOW) < 0.001)\r\n      stop\r\n    ENDIF\r\n\r\n    advance 0.1,0\r\n  endwhile\r\n\r\n  stop\r\nENDPROCEDURE\r\n\r\n;====================================================================\r\n\r\nPROCEDURE PRE_RUN\r\n  call create_tanks\r\n  TIMEOUT agent.init, 0\r\n  TERMINATE_VE\r\nENDPROCEDURE\r\n\r\n;=================================================\r\n\r\nPROCEDURE create_tanks\r\n\r\n  assign config,{title:\"TANK 1\",\r\n    x:100, y:50,\r\n    width:50, height:180,\r\n    value:0,\r\n    max_value:10,\r\n    \"color\":\"#ff0000\"}\r\n\r\n  timeout tank1.tank.init, 0, V$config\r\n\r\n  assign config,{title:\"TANK 2\",\r\n    x:400, y:50,\r\n    width:50, height:180,\r\n    value:0,\r\n    max_value:10,\r\n    \"color\":\"#ff0000\"}\r\n\r\n  timeout tank2.tank.init, 0, V$config\r\n\r\nENDPROCEDURE\r\n\r\n;=================================================\r\n\r\nPROCEDURE change_tank\r\n  assign newParams, {TANK2_PRESSURE_PREV:10}\r\n  dynamic_set sys, V$newParams\r\n  TERMINATE_VE\r\nENDPROCEDURE\r\n",
                        "descripcion": "<h3>What is a nonlinear system?<\/h3>\r\n<p>Linear systems can be solved with direct proportional equations: if you double the input, the output doubles. They can typically be resolved step by step.<\/p>\r\n<p>In many real scenarios, systems are <strong>nonlinear<\/strong>: the variables are so interdependent that you cannot solve them independently. You must solve them <strong>simultaneously<\/strong>.<\/p>\r\n<p><b>Example: two water tanks connected by a pipe<\/b><\/p>\r\n<p>If two tanks are connected by a pipe, the flow depends on the pressure difference, and each tank’s pressure depends on that same flow. That coupling makes the equations interdependent.<\/p>\r\n<pre>\r\nA_new = A - flow * DT\r\nB_new = B + flow * DT\r\nflow  = K * (A - B)\r\n<\/pre>\r\n<p>This may look manageable for two tanks, but once you extend the system (e.g., add a third tank), naive sequential updates can produce incorrect behavior because the equations are coupled.<\/p>\r\n<h3>Solving nonlinear coupled systems<\/h3>\r\n<p>GPSS-Plus provides the <code>DYNAMIC<\/code> resource to define a set of coupled equations (<code>EXPRESSIONS<\/code>) and the unknowns you want to solve for (<code>STATES<\/code>), along with helper parameters and previous-step values (<code>VARIABLES<\/code>).<\/p>\r\n<p>Internally, this is solved iteratively (Newton-Raphson style) using Jacobians to converge on a solution at each time step.<\/p>\r\n<h3>Typical declaration<\/h3>\r\n<p>You define:<\/p>\r\n<ul>\r\n  <li><code>EXPRESSIONS<\/code>: the equations of the system<\/li>\r\n  <li><code>STATES<\/code>: the unknown variables to solve<\/li>\r\n  <li><code>VARIABLES<\/code>: constants and previous-step values (e.g. <code>_PREV<\/code>)<\/li>\r\n<\/ul>\r\n<p>Then, on every cycle, you call:<\/p>\r\n<pre>\r\nSOLVE {name:\"sys\", DT:0.1, SAVEVALUE:\"result\"}\r\n<\/pre>\r\n<p>and copy solved states back into <code>SAVEVALUE<\/code>s for plotting and visualization.<\/p>\r\n<h3>Changing parameters during runtime<\/h3>\r\n<p>You can alter values in <code>VARIABLES<\/code> at runtime using <code>DYNAMIC_SET<\/code>, for example changing the previous pressure of tank 2 to force a new equilibrium.<\/p>\r\n<h3>Summary<\/h3>\r\n<ul>\r\n  <li>Coupled systems require simultaneous solving.<\/li>\r\n  <li><code>DYNAMIC<\/code> models coupled physics with simple expressions.<\/li>\r\n  <li><code>SOLVE<\/code> advances the system over time with convergence control.<\/li>\r\n<\/ul>",
                        "parametros": "",
                        "parametros_json": "",
                        "ejemplo": "",
                        "hijos": []
                    },
                    {
                        "id": "323",
                        "nombre": "Classic mass-spring-damper",
                        "texto": "\/*\r\n\r\n Mass-spring-damper\r\n \r\n*\/\r\nSYSTEM {TYPE:OPTIONS, REAL_TIME:1}\r\nSYSTEM {TYPE:PRE_RUN,TRIGGER:PRE_RUN}\r\nSYSTEM {TYPE:VISUAL, MODE:3D, V_WIDTH:70, V_HEIGHT:30, CAMERA:0}\r\nUI {TYPE: BUTTON, id:buttonA,TEXT: \"Press\", LABEL: \"Press\", TRIGGER: Press}\r\nUI {\r\n  TYPE: SLIDER, ID: aSlider, LABEL: \"Speed\",\r\n  VALUE: 15, MIN: 1, MAX: 50, STEP: 1,\r\n  TRIGGER: captureSpeed\r\n}\r\n\r\nPLOTTER {NAME:V_X, Y_0:V,  Y_1:X,  X:TIME_AC1}   \r\n\r\nGraphic {NAME:line1,Type:LINE,X1:0,Y1:0,X2:0,Y2:500}\r\nGraphic {NAME:line2,Type:LINE,X1:0,Y1:0,X2:500,Y2:0}\r\nGraphic {NAME:line3,Type:LINE,X1:0,Y1:0,X2:0,Y2:0,Z2:500}\r\n\r\nGraphic {NAME:tText,Type:TEXT,X:327,Y:486,Text:\"tText\"} \r\nGRAPHIC {NAME:spring, TYPE:OBJECT, src:SPRING, X:0, Y:15, Z:0, DEPTH:10, width:10, height:10, opacity:0.6}\r\n\r\n\r\nGRAPHIC {NAME:mass, TYPE:SPHERE, X:0, Y:3, Z:0, radius:3, color:red}\r\n\r\nGRAPHIC {NAME:damper, TYPE:BOX, X:0, Y:0, Z:0, WIDTH:2, HEIGHT:20, DEPTH:2, color:blue}\r\nGRAPHIC {NAME:damperB, TYPE:BOX, X:0, Y:10, Z:0, WIDTH:1.6, HEIGHT:20, DEPTH:1.6, color:cyan}\r\n; Lower FIXTURE (visual)\r\nGRAPHIC {NAME:support, TYPE:BOX, X:0, Y:-1, Z:0, WIDTH:20, HEIGHT:2, DEPTH:20, color:yellow}\r\n\r\n\r\n\r\nINITIAL mech_config, {\r\n  EXPRESSIONS: [\r\n    \"F_spring + F_damper + F_inertial\",       ; sum of forces = 0 (dynamic equilibrium)\r\n\r\n    \"F_spring - K * X\",                       ; spring\r\n    \"F_damper - C * V\",                       ; damper\r\n    \"F_inertial - M * (V - V_PREV) \/ DT\",     ; inertial force (acceleration)\r\n    \r\n    \"X - X_PREV - DT * V\"                     ; explicit integration: position\r\n  ],\r\n  STATES: [\r\n    \"X\",           ; position\r\n    \"V\",           ; velocity\r\n    \"F_spring\",    ; spring force\r\n    \"F_damper\",    ; damping force\r\n    \"F_inertial\"   ; inertial force\r\n  ],\r\n  VARIABLES: [\r\n    \"K\", \"C\", \"M\", \"X_PREV\", \"V_PREV\"\r\n  ]\r\n}\r\n\r\nINITIAL mech_values, {\r\n  K: 20,          ; spring constant\r\n  C: 0.005,         ; damping coeff.\r\n  M: 1,           ; mass\r\n  X_PREV: 0,      ; initial position\r\n  V_PREV: 30       ; initial velocity\r\n}\r\n\r\nDYNAMIC {\r\n  name: sys,\r\n  CONFIG: V$mech_config,\r\n  VALUES: V$mech_values,\r\n  X: 300,\r\n  Y: 300,\r\n  TOLERANCE: 1e-6,\r\n  MAX_ITER: 10\r\n}\r\n\r\n\r\nSTART 1000 \r\n\r\ninclude .\/library_graphics\/speedometer.lib\r\n\r\n;==============================================================\r\n\r\nPROCEDURE agent.init\r\n    \r\nwhile (1==1)\r\n\r\n    SOLVE {  name:\"sys\",  DT: 0.05,  SAVEVALUE: \"result\"}\r\n\r\n    SAVEVALUE V, X$(result.V)\r\n    SAVEVALUE X, X$(result.X)\r\n    SAVEVALUE I_cap ,  X$(result.I_cap)\r\n\r\n    assign x_mass,30 + X$X\r\n    ; === Mass position\r\n    MOVE {name:mass, Y:P$x_mass}\r\n\r\n    ; === Stretch spring from base [0,0,0] to the mass\r\n    MOVE {name:spring, STRETCH_BETWEEN:\"[0,0,0],[0,P$x_mass,0]\",rotate_y:P$x_mass*200}\r\n\r\n    ; === Stretch damper from base as well\r\n    MOVE {name:damper, MOVE_BETWEEN:\"[0,0,0],[0,P$x_mass,0]\",y:P$x_mass -10}\r\n\r\n\r\n    PLOT V_X, X$V, X$X\r\n\r\n\tassign rX,round(X$X,3)\r\n\tassign rV,round(X$V,3)\r\n    \r\n\tCALL tank1.speedometer.set, P$rV\r\n\tCALL tank2.speedometer.set, P$rX\r\n\r\n\r\n    IF (ABS(X$V) < 0.001)\r\n        stop\r\n    ENDIF\r\n\r\nadvance 0.05,0\r\n\r\nendwhile\r\n\r\nstop\r\nENDPROCEDURE\r\n;====================================================================\r\n\r\nPROCEDURE PRE_RUN\r\n\r\n    CALL create_indicators\r\n    \r\n    TIMEOUT agent.init,0\r\n\r\n\tTERMINATE_VE \r\nENDPROCEDURE\r\n;=================================================\r\nPROCEDURE create_indicators\r\n\r\n\tassign config,{title:\"V\"\r\n\t\t,x:20,y:15 \r\n            ,width:5 ,height:18\r\n            ,value:0\r\n            ,min_value:-30\r\n            ,max_value:30\r\n            ,\"color\":\"#ff0000\"\r\n            ,font:\"4px\"}\r\n            \r\n\tcall tank1.speedometer.init,V$config\r\n\r\n\tassign config,{title:\"X\"\r\n\t\t,x:50,y:15 \r\n            ,width:5 ,height:18\r\n            ,value:0\r\n            ,min_value:-10\r\n            ,max_value:10\r\n            ,\"color\":\"blue\"\r\n            ,font:\"4px\"}\r\n            \r\n\tcall tank2.speedometer.init,V$config\r\n\r\n\t\r\nENDPROCEDURE\r\n\r\n;=================================================\r\n\r\nPROCEDURE Press\r\n\tsavevalue speed_ui,max(X$speed_ui,15)\r\n    assign newParams,{V_PREV:-X$speed_ui}\r\n    dynamic_set sys,V$newParams\r\n\r\n    TERMINATE_VE\r\nENDPROCEDURE\r\n\r\nPROCEDURE captureSpeed\r\n\r\n    savevalue speed_ui,P$PARAM_B\r\n\r\n    TERMINATE_VE\r\nENDPROCEDURE\r\n\r\n\r\n\r\n",
                        "descripcion": "<p>We will see how this classic is resolved, which only requires the equations and correctly positioning the mass with respect to the components.<\/p>\r\n<p>The example shows how to use 3D graphics.<\/p>",
                        "parametros": null,
                        "parametros_json": null,
                        "ejemplo": null,
                        "hijos": []
                    }
                ]
            },
            {
                "id": "374",
                "nombre": "Non-Linear Components",
                "texto": "",
                "descripcion": "",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": [
                    {
                        "id": "319",
                        "nombre": "By components: COMPOSITOR",
                        "texto": "\/*\r\n\r\n By components: COMPOSITOR\r\n \r\n*\/\r\nSYSTEM {TYPE:PRE_RUN,TRIGGER:PRE_RUN}\r\nSYSTEM {type:OPTIONS, TIME_DECIMALS:2, SPEED:5}     \r\nPLOTTER {NAME:pressures, Y_0:tank1,  Y_1:tank2,  Y_2:tank3,  X:TIME_AC1}   \r\nPLOTTER {NAME:flow, Y_0:flow, X:TIME_AC1}   \r\n\r\nGraphic {NAME:tText,Type:TEXT,X:376,Y:579,Text:\"tText\"}   ; Text: battery level\r\n\r\ninclude .\/library_componets_liquid\/liquid.lib\r\n\r\nINITIAL PIPE12_VALUES, { K: 0.1 }\r\nINITIAL PIPE23_VALUES, { K: 0.1 }\r\nINITIAL TANK1_VALUES, { Presion_PREV: 10 }\r\nINITIAL TANK2_VALUES, { PresionA_PREV: 0 }\r\nINITIAL TANK3_VALUES, { Presion_PREV: 3 }\r\n\r\n\r\nDYNAMIC {name:tank1,  config:V$TANK_CONFIG,         VALUES:V$TANK1_VALUES, X:113, Y:491}\r\nDYNAMIC {name:tank2,  config:V$TANK_2_PORTS_CONFIG, VALUES:V$TANK2_VALUES, X:396, Y:389}\r\nDYNAMIC {name:tank3,  config:V$TANK_CONFIG,         VALUES:V$TANK3_VALUES, X:696, Y:342}\r\nDYNAMIC {name:pipe12,  config:V$PIPE_CONFIG,        VALUES:V$PIPE12_VALUES, X:189, Y:333}\r\nDYNAMIC {name:pipe23,  config:V$PIPE_CONFIG,        VALUES:V$PIPE23_VALUES, X:603, Y:512}\r\n\r\n\r\nINITIAL LIQUID_SYSTEM, {\r\n  COMPONENTS: [\"pipe12\", \"pipe23\", \"tank1\", \"tank2\", \"tank3\"],\r\n  CONNECTIONS: [\r\n    { NODE: \"n1\", CONNECTIONS: [\"tank1.A\",\"pipe12.A\"] },\r\n    { NODE: \"n2\", CONNECTIONS: [\"pipe12.B\", \"tank2.A\"] },\r\n    { NODE: \"n3\", CONNECTIONS: [\"pipe23.A\", \"tank2.B\"] },\r\n    { NODE: \"n4\", CONNECTIONS: [\"pipe23.B\", \"tank3.A\"] }\r\n  ]\r\n}\r\n\r\nDYNAMIC {name:sys, compositor:V$LIQUID_SYSTEM, X:712, Y:54}\r\n\r\nSTART 1000 \r\n\r\ninclude .\/library_graphics\/tank.lib\r\n\r\n;==============================================================\r\n\r\nPROCEDURE agent.init\r\n\r\ntimeout change_tank,2\r\n    advance 0.1\r\nwhile (1==1)\r\n\r\n    SOLVE {  name:\"sys\",  DT: 0.01,  SAVEVALUE: \"result\"}\r\n\r\n    \r\n    SAVEVALUE TANK1_PRESSURE, X$(result.tank1_Presion)\r\n    SAVEVALUE TANK2_PRESSURE, X$(result.tank2_PresionA)\r\n    SAVEVALUE TANK3_PRESSURE, X$(result.tank3_Presion)\r\n    SAVEVALUE PIPE12,  X$(result.pipe12_QA)\r\n    SAVEVALUE PIPE23,  X$(result.pipe23_QA)\r\n\r\n    PLOT pressures, X$TANK1_PRESSURE, X$TANK2_PRESSURE, X$TANK3_PRESSURE\r\n    PLOT flow, X$PIPE_FLOW\r\n\r\n\tassign rFlow12,round(X$PIPE12,3)\r\n\tassign rFlow23,round(X$PIPE23,3)\r\n\tassign rH1,round(X$TANK1_PRESSURE,3)\r\n\tassign rH2,round(X$TANK2_PRESSURE,3)\r\n\tassign rH3,round(X$TANK3_PRESSURE,3)\r\n    \r\n    move {name:tText, text:\"AC1$ flows: P$rFlow12 ----- P$rFlow23 \"}\r\n\r\n\tCALL tank1.tank.set, P$rH1\r\n\tCALL tank2.tank.set, P$rH2\r\n\tCALL tank3.tank.set, P$rH3\r\n\r\n\r\n    IF (ABS(X$PIPE_FLOW) < 0.001)\r\n        ;stop\r\n    ENDIF\r\n\r\nadvance 0.01,0\r\n\r\nendwhile\r\n\r\nstop\r\nENDPROCEDURE\r\n;====================================================================\r\n\r\nPROCEDURE PRE_RUN\r\n\r\n    CALL create_tanks\r\n    \r\n    TIMEOUT agent.init,0\r\n\r\n\tTERMINATE_VE \r\nENDPROCEDURE\r\n;=================================================\r\nPROCEDURE create_tanks\r\n\r\n\tassign config,{title:\"TANK 1\"\r\n\t\t,x:100,y:50 \r\n            ,width:50 ,height:180\r\n            ,value:0\r\n            ,max_value:10\r\n            ,\"color\":\"#ff0000\"}\r\n            \r\n\ttimeout tank1.tank.init,0,V$config\r\n\r\n\tassign config,{title:\"TANK 2\"\r\n\t\t,x:300,y:50 \r\n            ,width:50 ,height:180\r\n            ,value:0\r\n            ,max_value:10\r\n            ,\"color\":\"#ff0000\"}\r\n            \r\n\ttimeout tank2.tank.init,0,V$config\r\n\r\n\tassign config,{title:\"TANK 3\"\r\n\t\t,x:500,y:50 \r\n            ,width:50 ,height:180\r\n            ,value:0\r\n            ,max_value:10\r\n            ,\"color\":\"#ff0000\"}\r\n            \r\n\ttimeout tank3.tank.init,0,V$config\r\n\r\n\t\r\nENDPROCEDURE\r\n\r\n;=================================================\r\n\r\nPROCEDURE change_tank\r\n\r\n    assign newParams,{tank3_Presion_PREV:10}\r\n    dynamic_set sys,V$newParams\r\n\r\n    TERMINATE_VE\r\nENDPROCEDURE\r\n\r\n\r\n",
                        "descripcion": "<p data-start=\"259\" data-end=\"591\">In complex simulations, we often need to model systems formed by multiple interacting components, such as tanks connected by pipes, electrical circuits, or coupled mechanical systems. To this end, GPSS-Plus uses the concept of <strong data-start=\"522\" data-end=\"549\">system composition<\/strong> via the COMPOSITOR.<\/p>\r\n<h3 data-start=\"670\" data-end=\"699\">What does the composition do?<\/h3>\r\n<p data-start=\"701\" data-end=\"946\">The composition allows for <strong data-start=\"724\" data-end=\"767\">merging multiple individual DYNAMICs<\/strong> into a single dynamic system. This merger is performed by connecting their variables according to a common node scheme and solving all internal equations <strong data-start=\"892\" data-end=\"915\">simultaneously<\/strong>.<\/p>\r\n<p data-start=\"593\" data-end=\"796\">&nbsp;<\/p>\r\n<h3>Structure of a composite system<\/h3>\r\n<p data-start=\"593\" data-end=\"796\">Let's look at a practical example: three tanks connected by two pipes, where the central tank has two inlets. The layout would be:<\/p>\r\n<pre>\r\nTANK1 --- PIPE12 --- TANK2 --- PIPE23 --- TANK3<\/pre>\r\n<p data-start=\"593\" data-end=\"796\">This system is defined as follows:<\/p>\r\n<pre>\r\nINITIAL LIQUID_SYSTEM, {\r\n&nbsp; COMPONENTS: [&quot;pipe12&quot;, &quot;pipe23&quot;, &quot;tank1&quot;, &quot;tank2&quot;, &quot;tank3&quot;],\r\n&nbsp; CONNECTIONS: [\r\n&nbsp; &nbsp; { NODE: &quot;n1&quot;, CONNECTIONS: [&quot;tank1.A&quot;,&quot;pipe12.A&quot;] },\r\n&nbsp; &nbsp; { NODE: &quot;n2&quot;, CONNECTIONS: [&quot;pipe12.B&quot;, &quot;tank2.A&quot;] },\r\n&nbsp; &nbsp; { NODE: &quot;n3&quot;, CONNECTIONS: [&quot;pipe23.A&quot;, &quot;tank2.B&quot;] },\r\n&nbsp; &nbsp; { NODE: &quot;n4&quot;, CONNECTIONS: [&quot;pipe23.B&quot;, &quot;tank3.A&quot;] }\r\n&nbsp; ]\r\n}<\/pre>\r\n<p data-start=\"593\" data-end=\"796\">Each <code>NODE <\/code>indicates a physical connection point between one or more components. Each <code>NODE <\/code>is assigned a <strong data-start=\"1672\" data-end=\"1707\">shared effort variable<\/strong> (such as pressure or voltage), and each component contributes its own internal and flow equations.<\/p>\r\n<h3>Defining the components<\/h3>\r\n<p data-start=\"593\" data-end=\"796\">Pipe (PIPE):<\/p>\r\n<pre>\r\nINITIAL PIPE_CONFIG, {\r\n  EFFORTS: {\r\n    A: { NAME: &quot;PressureA&quot;, UNIT: &quot;Pa&quot; },\r\n    B: { NAME: &quot;PressureB&quot;, UNIT: &quot;Pa&quot; }\r\n  },\r\n  ROLES: {\r\n    QA: { ROLE: &quot;FLOW&quot;, EXPOSED: [&quot;A&quot;] },\r\n    QB: { ROLE: &quot;FLOW&quot;, EXPOSED: [&quot;B&quot;] },\r\n    K: { ROLE: &quot;CONST&quot; }\r\n  },\r\n  EXPRESSIONS: [\r\n    &quot;QA + K * (PressureA - PressureB)&quot;,     ; Flow from A to B\r\n    &quot;QA + QB&quot;                             ; Internal flow conservation\r\n  ]\r\n}<\/pre>\r\n<p data-start=\"618\" data-end=\"821\">Each and every variable appearing in EXPRESSIONS must be clearly defined in one of the two groups.<\/p>\r\n<ul>\r\n    <li><b>EFFORT<\/b>: A: { NAME: &quot;PressureA&quot;, UNIT: &quot;Pa&quot; } :&nbsp;Defines which effort variables will be equalized with other components connected at the same node. For example, a tank will have a pressure at that node, which will be equalized with all pressures at that same node. The unit must be specified to ensure compatibility. In this case, Pascals (Pa).&nbsp;<\/li>\r\n    <li><b>ROLES<\/b>: QA: { ROLE: &quot;FLOW&quot;, EXPOSED: [&quot;A&quot;] }: Defines the <code>ROLE <\/code>assigned to the rest of the system variables.\r\n    <ul>\r\n        <li><b>FLOW<\/b>: Flow variables moving inside each component and the port where they are exposed. <code data-start=\"2471\" data-end=\"2477\">FLOW<\/code> can be exposed at one port (a single mesh) or two (creating two distinct meshes and a conservation equation).<\/li>\r\n        <li><b>CONST<\/b>: System constant with a numerical value.<\/li>\r\n        <li><b>STATE<\/b>: Variable required to be calculated by the system.<\/li>\r\n    <\/ul>\r\n    <\/li>\r\n<\/ul>\r\n<p data-start=\"618\" data-end=\"821\">&nbsp;<\/p>\r\n<p data-start=\"618\" data-end=\"821\">Two-port tank:<\/p>\r\n<pre>\r\nINITIAL TANK_2_PORTS_CONFIG, {&quot;EFFORTS&quot;: {\r\n  &quot;A&quot;: { &quot;NAME&quot;: &quot;PressureA&quot;, &quot;UNIT&quot;: &quot;Pa&quot; },\r\n  &quot;B&quot;: { &quot;NAME&quot;: &quot;PressureB&quot;, &quot;UNIT&quot;: &quot;Pa&quot; }\r\n},\r\n&quot;ROLES&quot;: {\r\n  &quot;PressureA_PREV&quot;: { &quot;ROLE&quot;: &quot;const&quot;, &quot;UNIT&quot;: &quot;Pa&quot; },\r\n  &quot;IN1&quot;: { &quot;ROLE&quot;: &quot;flow&quot;, &quot;EXPOSED&quot;: [&quot;A&quot;] },\r\n  &quot;IN2&quot;: { &quot;ROLE&quot;: &quot;flow&quot;, &quot;EXPOSED&quot;: [&quot;B&quot;] }\r\n},\r\n&quot;EXPRESSIONS&quot;: [\r\n  &quot;PressureA - PressureA_PREV - (IN1 + IN2) * DT&quot;,  ; Mass\/volume conservation\r\n  &quot;PressureA - PressureB&quot;                           ; Same pressure at both ports\r\n]\r\n}<\/pre>\r\n<h3>Final system composition<\/h3>\r\n<p data-start=\"618\" data-end=\"821\">After declaring components and connections, it is simply used in the COMMAND:<\/p>\r\n<pre>\r\nDYNAMIC {name:sys, compositor:V$LIQUID_SYSTEM, X:712, Y:54}<\/pre>\r\n<p data-start=\"3282\" data-end=\"3363\">This <code data-start=\"3287\" data-end=\"3296\">DYNAMIC<\/code> automatically generates all necessary equations by combining:<\/p>\r\n<ul data-start=\"3365\" data-end=\"3509\">\r\n    <li data-start=\"3365\" data-end=\"3412\">\r\n    <p data-start=\"3367\" data-end=\"3412\"><strong data-start=\"3380\" data-end=\"3390\">Effort<\/strong> variables shared per node.<\/p>\r\n    <\/li>\r\n    <li data-start=\"3413\" data-end=\"3459\">\r\n    <p data-start=\"3415\" data-end=\"3459\"><strong data-start=\"3428\" data-end=\"3436\">Flow<\/strong> variables connected per port.<\/p>\r\n    <\/li>\r\n    <li data-start=\"3460\" data-end=\"3509\">\r\n    <p data-start=\"3462\" data-end=\"3509\">Conservation rules (mass, energy, etc.).<\/p>\r\n    <\/li>\r\n<\/ul>\r\n<p data-start=\"618\" data-end=\"821\">The result visible in the debug area would be:<\/p>\r\n<pre><b>EXPRESSIONS:<\/b> \r\n1: FLOW_1 + PIPE12_K * (PA_N1 - PA_N2) \r\n2: FLOW_1 + FLOW_2 \r\n3: FLOW_3 + PIPE23_K * (PA_N3 - PA_N4) \r\n4: FLOW_3 + FLOW_4 \r\n5: PA_N1 - TANK1_PRESSURE_PREV - FLOW_1 * DT \r\n6: PA_N2 - TANK2_PRESSUREA_PREV - (FLOW_2 + FLOW_3) * DT \r\n7: PA_N2 - PA_N3 \r\n8: PA_N4 - TANK3_PRESSURE_PREV - FLOW_4 * DT<\/pre>\r\n<p data-start=\"618\" data-end=\"821\">Where we see that effort variables have been equalized with one for each node and flow variables have been numbered by mesh.<\/p>\r\n<p>&nbsp;<\/p>\r\n<h2 data-start=\"4104\" data-end=\"4128\">Final observations<\/h2>\r\n<ul data-start=\"4130\" data-end=\"4446\">\r\n    <li data-start=\"4130\" data-end=\"4200\">\r\n    <p data-start=\"4132\" data-end=\"4200\">Each component can be easily reused with different values.<\/p>\r\n    <\/li>\r\n    <li data-start=\"4201\" data-end=\"4344\">\r\n    <p data-start=\"4203\" data-end=\"4344\">It is possible to build complete component libraries (<code data-start=\"4262\" data-end=\"4268\">.lib<\/code>) and combine them to build complex models without rewriting expressions.<\/p>\r\n    <\/li>\r\n    <li data-start=\"4345\" data-end=\"4446\">\r\n    <p data-start=\"4347\" data-end=\"4446\">The system automatically handles previous values (_PREV), unified names, and internal meshes.<\/p>\r\n    <\/li>\r\n<\/ul>",
                        "parametros": null,
                        "parametros_json": null,
                        "ejemplo": null,
                        "hijos": []
                    },
                    {
                        "id": "320",
                        "nombre": "Component Libraries",
                        "texto": "SYSTEM {TYPE:PRE_RUN,TRIGGER:PRE_RUN}\r\nSYSTEM {type:OPTIONS, TIME_DECIMALS:3, SPEED:1,pause:0}     \r\n\r\nPLOTTER {NAME:movement, Y_0:tank1,  Y_1:tank2,  X:TIME_AC1}   \r\nGraphic {NAME:tText,Type:TEXT,X:327,Y:486,Text:\"tText\"} \r\n\r\n\r\ninclude .\/library_componets_liquid\/liquid.lib\r\n\r\nINITIAL pipe1_DATA, { K: 0.1 }\r\nDYNAMIC {name:pipe1,config:V$pipe_CONFIG,VALUES:V$pipe1_DATA,X:373,Y:418}\r\n\r\nINITIAL tank1_DATA, { PRESSURE_PREV: 10 }\r\nDYNAMIC {name:tank1,config:V$tank_CONFIG,VALUES:V$tank1_DATA,X:123,Y:357}\r\n\r\nINITIAL tank2_DATA, { PRESSURE_PREV: 1 }\r\nDYNAMIC {name:tank2,config:V$tank_CONFIG,VALUES:V$tank2_DATA,X:624,Y:347}\r\n\r\ninitial COMPOSITOR, {\r\n   COMPONENTS: [ \"pipe1\",\"tank1\",\"tank2\"],\r\n   CONNECTIONS: [ \"TANK1.A=PIPE1.A\", \"TANK2.A=PIPE1.B\"]\r\n   }\r\n\r\nDYNAMIC {name:sys,compositor:V$COMPOSITOR,X:347,Y:164}\r\n\r\n\r\nSTART 1\r\n\r\ninclude .\/library_graphics\/tank.lib\r\n\r\n;==============================================================\r\n\r\nPROCEDURE agent.init\r\n\r\ntimeout change_tank,100\r\ntimeout change_tank2,200\r\n    \r\nwhile (1==1)\r\n\r\n\r\nSOLVE {  name:\"sys\",  DT: 0.1,  SAVEVALUE: \"result\"}\r\n\r\n\r\n\r\nSAVEVALUE TANK1_PRESSURE, X$(result.TANK1_PRESION)\r\nSAVEVALUE TANK2_PRESSURE, X$(result.TANK2_PRESION)\r\nSAVEVALUE PIPE1_FLOW,  X$(result.PIPE1_FLUJO)\r\n\r\nPLOT movement, X$TANK1_PRESSURE, X$TANK2_PRESSURE\r\n\r\n\tassign rFlow,round(X$PIPE_FLOW,5)\r\n\tassign rH1,round(X$TANK1_PRESSURE,5)\r\n\tassign rH2,round(X$TANK2_PRESSURE,5)\r\n    \r\n    move {name:tText, text:\"flow:\\n P$rFlow Tot: P$rH1 P$rH2 \"}\r\n\r\n\tCALL tank1.tank.set, X$TANK1_PRESSURE\r\n\tCALL tank2.tank.set, X$TANK2_PRESSURE\r\n\r\n\r\n    IF (ABS(X$PIPE1_FLOW) < 0.001)\r\n        stop\r\n    ENDIF\r\n\r\nadvance 1,0\r\n\r\nendwhile\r\n\r\nstop\r\nENDPROCEDURE\r\n;====================================================================\r\n\r\nPROCEDURE PRE_RUN\r\n\r\n    CALL create_tanks\r\n    \r\n    TIMEOUT agent.init,0\r\n\r\n\tTERMINATE_VE \r\nENDPROCEDURE\r\n;=================================================\r\nPROCEDURE create_tanks\r\n\r\n\tassign config,{title:\"TANK 1\"\r\n\t\t,x:100,y:100 \r\n            ,width:50 ,height:180\r\n            ,value:X$TANK1_PRESSURE\r\n            ,max_value:10\r\n            ,\"color\":\"#ff0000\"}\r\n            \r\n\tcall tank1.tank.init,V$config\r\n\r\n\tassign config,{title:\"TANK 2\"\r\n\t\t,x:500,y:100 \r\n            ,width:50 ,height:180\r\n            ,value:X$TANK2_PRESSURE\r\n            ,max_value:10\r\n            ,\"color\":\"#ff0000\"}\r\n            \r\n\tcall tank2.tank.init,V$config\r\n\t\r\nENDPROCEDURE\r\n\r\n;=================================================\r\n\r\nPROCEDURE change_tank\r\n    assign newParams,{PIPE1_K:0.3}\r\n    dynamic_set sys,V$newParams\r\n    TERMINATE_VE\r\nENDPROCEDURE\r\n\r\nPROCEDURE change_tank2\r\n    assign newParams,{TANK2_PRESION_PREV:10}\r\n    dynamic_set sys,V$newParams\r\n    TERMINATE_VE\r\nENDPROCEDURE\r\n\r\n\r\n\r\n",
                        "descripcion": "<h3 data-start=\"257\" data-end=\"282\">What is a library?<\/h3>\r\n<p data-start=\"284\" data-end=\"510\">A library is a set of predefined components with their configurations and mathematical behaviors ready to use. In the case of GPSS-Plus components, it is limited to storing the <b>CONFIG<\/b> for each element. For example:<\/p>\r\n<pre>\r\ninitial PIPE_CONFIG, {\r\n&nbsp; TYPE: &quot;PIPE&quot;,\r\n&nbsp; EXPRESSIONS: [ &quot;FLOW + K * (PRESSURE_A - PRESSURE_B)&quot; ],\r\n&nbsp; STATES: [&quot;FLOW&quot;],\r\n&nbsp; VARIABLES: [&quot;K&quot;],\r\n&nbsp; OWNED_VARS: { A: [&quot;FLOW&quot;], B: [&quot;-FLOW&quot;] },\r\n&nbsp; REQUIRED_VARS: { A: [&quot;PRESSURE_A&quot;], B: [&quot;PRESSURE_B&quot;] }\r\n}<\/pre>\r\n<p><b>We only need to perform an <code>INCLUDE<\/code> of the file containing it:<\/b><\/p>\r\n<pre><b>include .\/library_componets_liquid\/liquid.lib<\/b>\r\n<\/pre>\r\n<p data-start=\"1238\" data-end=\"1312\">And we use those configs as if we had written them in the main code.<\/p>\r\n<pre>\r\ninitial pipe1_data, { K: 0.1 }\r\ndynamic { name: pipe1, config: V$PIPE_CONFIG, values: V$pipe1_data, x: 100, y: 300 }\r\n\r\ninitial tank1_data, { PRESSURE_PREV: 10 }\r\ndynamic { name: tank1, config: V$TANK_CONFIG, values: V$tank1_data, x: 50, y: 400 }\r\n\r\ninitial tank2_data, { PRESSURE_PREV: 5 }\r\ndynamic { name: tank2, config: V$TANK_CONFIG, values: V$tank2_data, x: 200, y: 400 }\r\n\r\n<\/pre>\r\n<h3 data-start=\"2390\" data-end=\"2420\">Advantages of using libraries<\/h3>\r\n<ul data-start=\"2422\" data-end=\"2523\">\r\n    <li data-start=\"2422\" data-end=\"2456\">\r\n    <p data-start=\"2424\" data-end=\"2456\">Reuse and standardization.<\/p>\r\n    <\/li>\r\n    <li data-start=\"2457\" data-end=\"2480\">\r\n    <p data-start=\"2459\" data-end=\"2480\">Error reduction.<\/p>\r\n    <\/li>\r\n    <li data-start=\"2481\" data-end=\"2523\">\r\n    <p data-start=\"2483\" data-end=\"2523\">Faster modeling with higher quality.<\/p>\r\n    <\/li>\r\n<\/ul>\r\n<p>&nbsp;<\/p>",
                        "parametros": null,
                        "parametros_json": null,
                        "ejemplo": null,
                        "hijos": []
                    }
                ]
            },
            {
                "id": "375",
                "nombre": "Non-Linear Restrictions",
                "texto": "",
                "descripcion": "",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": [
                    {
                        "id": "376",
                        "nombre": "Introduction to Constraints",
                        "texto": "SYSTEM {TYPE:PRE_RUN,TRIGGER:PRE_RUN}\r\nSYSTEM {TYPE:VISUAL, MODE:3D, V_WIDTH:70, V_HEIGHT:50, CAMERA:0}\r\n\r\nSYSTEM {type:OPTIONS, TIME_DECIMALS:1, SPEED:5}     \r\n;SYSTEM {TYPE:OPTIONS, REAL_TIME:1}\r\n\r\n\r\nGraphic {NAME:line1,Type:LINE,X1:0,Y1:0,X2:0,Y2:500}\r\nGraphic {NAME:line2,Type:LINE,X1:0,Y1:0,X2:500,Y2:0}\r\nGraphic {NAME:line3,Type:LINE,X1:0,Y1:0,X2:0,Y2:0,Z2:500}\r\n\r\nGRAPHIC {NAME:mass, TYPE:SPHERE, X:0, Y:3, Z:0, radius:3, color:red}\r\n\r\nGRAPHIC {NAME:supportLeft, TYPE:BOX, X:-1, Y:30, Z:0, WIDTH:2, HEIGHT:60, DEPTH:20, color:yellow}\r\nGRAPHIC {NAME:supportRight, TYPE:BOX, X:31, Y:30, Z:0, WIDTH:2, HEIGHT:60, DEPTH:20, color:yellow}\r\nGRAPHIC {NAME:supportTop, TYPE:BOX, X:15, Y:61, Z:0, WIDTH:30, HEIGHT:2, DEPTH:20, color:yellow}\r\nGRAPHIC {NAME:supportBottom, TYPE:BOX, X:15, Y:-1, Z:0, WIDTH:30, HEIGHT:2, DEPTH:20, color:yellow}\r\n\r\n\r\n\r\nINITIAL ball2D_config, {\r\n  EXPRESSIONS: [\r\n    ; constant velocity (no forces)\r\n    \"VX - VX_PREV\",\r\n    \"VY - VY_PREV\",\r\n\r\n    ; explicit integration\r\n    \"X - X_PREV - DT * VX\",\r\n    \"Y - Y_PREV - DT * VY\"\r\n  ],\r\n  STATES: [\r\n    \"X\",\"Y\",\"VX\",\"VY\"\r\n  ],\r\n  VARIABLES: [\r\n    \"X_PREV\",\"Y_PREV\",\"VX_PREV\",\"VY_PREV\",\r\n    \"R\",\"E\",\r\n    \"MINX\",\"MAXX\",\"MINY\",\"MAXY\"\r\n  ],\r\n  \r\n  ; CONDITIONS correct the state after the free step (move → correct).\r\n  \r\n  CONDITIONS: [\r\n    ; --- left\/right wall ---\r\n    {\r\n      \"VARIABLE\":\"VX_PREV\",\r\n      \"EXPRESSION\":\"(X <= (MINX+R) and VX < 0) ? -VX*E : ((X >= (MAXX-R) and VX > 0) ? -VX*E : VX)\"\r\n    },\r\n    {\r\n      \"VARIABLE\":\"X_PREV\",\r\n      \"EXPRESSION\":\"(X <= (MINX+R) and VX < 0) ? (MINX+R) : ((X >= (MAXX-R) and VX > 0) ? (MAXX-R) : X)\"\r\n    },\r\n\r\n    ; --- bottom\/top wall ---\r\n    {\r\n      \"VARIABLE\":\"VY_PREV\",\r\n      \"EXPRESSION\":\"(Y <= (MINY+R) and VY < 0) ? -VY*E : ((Y >= (MAXY-R) and VY > 0) ? -VY*E : VY)\"\r\n    },\r\n    {\r\n      \"VARIABLE\":\"Y_PREV\",\r\n      \"EXPRESSION\":\"(Y <= (MINY+R) and VY < 0) ? (MINY+R) : ((Y >= (MAXY-R) and VY > 0) ? (MAXY-R) : Y)\"\r\n    }\r\n  ]\r\n}\r\n\r\nINITIAL ball2D_values, {\r\n  R: 3,\r\n  E: 0.8,\r\n\r\n  MINX: 0,  MAXX: 30,\r\n  MINY: 0,  MAXY: 60,\r\n\r\n  X_PREV: 20,\r\n  Y_PREV: 20,\r\n  VX_PREV: 12,\r\n  VY_PREV: 7\r\n}\r\n\r\nDYNAMIC {\r\n  name: box2d,\r\n  CONFIG: V$ball2D_config,\r\n  VALUES: V$ball2D_values,\r\n  X: 200,\r\n  Y: 200\r\n}\r\n\r\n\r\nSTART 1000 \r\n\r\ninclude .\/library_graphics\/speedometer.lib\r\n\r\n;==============================================================\r\n\r\nPROCEDURE agent.init\r\n\r\n   \r\nwhile (1==1)\r\n\r\n    SOLVE {  name:\"box2d\",  DT: 0.1,  SAVEVALUE: \"result\"}\r\n\r\n    SAVEVALUE X, X$(result.X)\r\n    SAVEVALUE Y, X$(result.Y)\r\n\r\n    ; === Mass position\r\n    MOVE {name:mass, X:X$X , Y:X$Y}\r\n\r\n\tassign vx,round(X$(result.VX),3)\r\n\tassign vy,round(X$(result.VY),3)\r\n\r\n\tCALL ind1.speedometer.set, P$vx\r\n\tCALL ind2.speedometer.set, P$vy\r\n\r\n\t; STOP CONDITION\r\n    ; IF (ABS(P$vx) < 0.001)\r\n    ;    stop\r\n    ; ENDIF\r\n\r\nadvance 0.1,0\r\n\r\nendwhile\r\n\r\n\r\nENDPROCEDURE\r\n;====================================================================\r\n\r\nPROCEDURE PRE_RUN\r\n\r\n    CALL create_indicators\r\n    \r\n    TIMEOUT agent.init,0\r\n\r\n\tTERMINATE_VE \r\nENDPROCEDURE\r\n;=================================================\r\nPROCEDURE create_indicators\r\n\r\n\tassign config,{title:\"VX\"\r\n\t\t,x:50,y:15 \r\n            ,width:5 ,height:18\r\n            ,value:0\r\n            ,min_value:-15\r\n            ,max_value:15\r\n            ,\"color\":\"#ff0000\"\r\n            ,font:\"3px\"}\r\n            \r\n\tcall ind1.speedometer.init,V$config\r\n\r\n\tassign config,{title:\"VY\"\r\n\t\t,x:80,y:15 \r\n            ,width:5 ,height:18\r\n            ,value:0\r\n            ,min_value:-15\r\n            ,max_value:15\r\n            ,\"color\":\"blue\"\r\n            ,font:\"3px\"}\r\n            \r\n\tcall ind2.speedometer.init,V$config\r\n\r\n\t\r\nENDPROCEDURE\r\n\r\n;=================================================\r\n\r\n\r\n",
                        "descripcion": "<p>We have seen various physical, electrical, and fluid formulas described in DYNAMIC evolve within the SOLVE.<br>\r\n<br>\r\nIn summary, we introduced all the formulas that a system had to satisfy to be solved simultaneously. This allowed us to solve, for example, the problem of 3 connected liquid tanks.<br>\r\n<br>\r\nNow we will see a way to use that same resource to solve physics with constraints, which is nothing more than what we see in video games when two objects collide. Similarly, we can simulate multiple objects moving among themselves with certain rotation or distance constraints.<br>\r\nWe are not introducing a new type of simulation, but a different way to describe another problem.<br>\r\n<br>\r\nTo get an idea of how it works, it is like any other simulation: we must observe what happens in the real world and then describe it as it is.<br>\r\nThe steps are usually as follows:<br>\r\n<br>\r\n1.- The object or objects. To simplify, we will use perfect spheres and cubes. They can have a weight and radius. They are placed in a location in space.<br>\r\n<br>\r\n2.- Its point velocity. We must know if it is static, moving with a certain free velocity, or subjected to a force that gives it acceleration. That is:<br>\r\n<br>\r\nWe will integrate the position:<br>\r\nx = x + vΔt<br>\r\n<br>\r\nAnd if forces are involved, they also come into play:<br>\r\nv = v + aΔt<br>\r\n<br>\r\n<br>\r\n3.- Constraint detection. If we are talking about an object hitting a wall, we must know this before effecting any consequence. Therefore, we check if we are violating any constraints.<br>\r\n<br>\r\nIf our object were a sphere, we check if it hits or invades the space of:<br>\r\nWall: compare coordinates<br>\r\nSphere: distance between centers<br>\r\nBox: compare intervals (AABB)<br>\r\nComplex shapes: more geometry<br>\r\n<br>\r\n<br>\r\n4.- Constraints. While we have discussed position and velocity, a constraint, whatever it may be, must modify both characteristics. If the object hits a wall, the increment of x will go in the opposite direction and the velocity will change sign. A constraint does not \"prevent,\" it corrects.<br>\r\n<br>\r\nThis doesn't exclude the possibility of a constraint being, for example, not exceeding a certain speed.<br>\r\n<br>\r\n5.- Scaling. When there are many objects, it becomes unfeasible to put thousands of objects into the system at once, so it is done in parts.<br>\r\nFiltering candidates using grid or tree methods is required...<\/p>\r\n<p>&nbsp;<\/p>\r\n<p><b>The Example:<\/b><\/p>\r\n<p>A single spherical mass bouncing against the walls that enclose it.<\/p>\r\n<p>We show the formulas for constant velocities and their integrals to obtain the positions.<\/p>\r\n<p>The states are the 4 mentioned: Position (x,y) and velocities (vx,vy).<\/p>\r\n<p>And following this, the constraints. Let's look at the first one:<\/p>\r\n<pre>\r\n{\r\n&nbsp; &quot;VARIABLE&quot;:&quot;VX_PREV&quot;,\r\n&nbsp; &quot;EXPRESSION&quot;:&quot;(X &lt;= (MINX+R) and VX &lt; 0) ? -VX*E : ((X &gt;= (MAXX-R) and VX &gt; 0) ? -VX*E : VX)&quot;\r\n}\r\n<\/pre>\r\n<p><br>\r\nThis indicates what we will do with a specific variable if certain conditions occur. In this case, what will happen to the variable \"VX_PREV\", which is one of the states passed to the next solver iteration.<\/p>\r\n<p>The <code data-start=\"1305\" data-end=\"1313\">*_PREV<\/code> variables represent the state that the next <code data-start=\"1370\" data-end=\"1377\">SOLVE<\/code> step \"inherits\".<br>\r\n<br>\r\nThe result will either be leaving it as it currently is (VX) or modifying it if the established conditions are met.<br>\r\nIf we are moving left and have passed the left boundary, VX_PREV will be -VX*E.<br>\r\nOtherwise, we check the right boundary, setting VX_PREV = -VX*E again.<br>\r\nAnd as mentioned, if no constraints apply, VX_PREV will be VX.<\/p>\r\n<p>Note that \"E\" is the velocity coefficient conserved after each bounce (restitution), so it is used as a multiplier to reduce speed. If E were 0, it would be a dead stop.<\/p>",
                        "parametros": null,
                        "parametros_json": null,
                        "ejemplo": null,
                        "hijos": []
                    },
                    {
                        "id": "326",
                        "nombre": "Constraints in Dynamic Systems",
                        "texto": "\/*\r\n\r\n Constraints in Dynamic Systems\r\n \r\n*\/\r\n\r\nSYSTEM {TYPE:PRE_RUN,TRIGGER:PRE_RUN}\r\nSYSTEM {type:OPTIONS, TIME_DECIMALS:1, SPEED:5}     \r\n\r\nPLOTTER {NAME:positions, Y_0:X1,  Y_1:X2,  X:TIME_AC1}   \r\n\r\nGraphic {NAME:tText,Type:TEXT,X:327,Y:486,Text:\"tText\"}\r\n\r\n\r\n\r\nINITIAL mech_config, {\r\n  EXPRESSIONS: [\r\n    \"F1 - M1 * (V1 - V1_PREV) \/ DT\",\r\n    \"FD1 - C1 * V1\",\r\n    \"F_spring1 - K1 * X1\",\r\n\r\n    \"F_spring2 - K2 * (X2 - X1)\",\r\n    \"FD2 - C2 * V2\",\r\n    \"F2 - M2 * (V2 - V2_PREV) \/ DT\",\r\n\r\n    \"F_restriction + Lambda\",  ; constraint force (with sign)\r\n\r\n    \"F1 + F_spring1 + FD1 - F_spring2 - F_restriction\",\r\n    \"F2 + F_spring2 + FD2 + F_restriction\",\r\n\r\n    \"X1 - X1_PREV - DT * V1\",\r\n    \"X2 - X2_PREV - DT * V2\",\r\n\r\n    \"X2 - X1 - L\"  ; geometric constraint\r\n  ],\r\n\r\n  STATES: [\r\n    \"X1\", \"X2\",\r\n    \"V1\", \"V2\",\r\n    \"F1\", \"F2\",\r\n    \"FD1\", \"FD2\",\r\n    \"F_spring1\", \"F_spring2\",\r\n    \"F_restriction\",\r\n    \"Lambda\"\r\n  ],\r\n\r\n  VARIABLES: [\r\n    \"M1\", \"M2\",\r\n    \"K1\", \"K2\",\r\n    \"C1\", \"C2\",\r\n    \"L\",\r\n    \"X1_PREV\", \"X2_PREV\",\r\n    \"V1_PREV\", \"V2_PREV\"\r\n  ]\r\n}\r\n\r\n\r\n\r\n\r\nINITIAL mech_values, {\r\n  M1: 1.5,\r\n  M2: 1.5,\r\n\r\n  K1: 5,\r\n  K2: 8,\r\n\r\n  C1: 0.1,\r\n  C2: 0.1,\r\n\r\n  X1_PREV: 1.5,\r\n  V1_PREV: 2,\r\n\r\n  X2_PREV: 3.5,\r\n  V2_PREV: -1,\r\n\r\n  L: 2    ; distance constraint between masses\r\n}\r\n\r\n\r\n\r\n\r\n\r\n\r\nDYNAMIC {\r\n  name: sys,\r\n  CONFIG: V$mech_config,\r\n  VALUES: V$mech_values,\r\n  X: 300,\r\n  Y: 300,\r\n  TOLERANCE: 1e-6,\r\n  MAX_ITER: 10\r\n}\r\n\r\n\r\nSTART 1000 \r\n\r\ninclude .\/library_graphics\/speedometer.lib\r\n\r\n;==============================================================\r\n\r\nPROCEDURE agent.init\r\n\r\n    \r\nwhile (1==1)\r\n\r\n    SOLVE {  name:\"sys\",  DT: 0.1,  SAVEVALUE: \"result\"}\r\n\r\n    SAVEVALUE X1, X$(result.X1)\r\n    SAVEVALUE X2, X$(result.X2)\r\n    SAVEVALUE V1, X$(result.V1)\r\n\r\n    PLOT positions, X$X1, X$X2\r\n\r\n\tassign rX1,round(X$X1,5)\r\n\tassign rX2,round(X$X2,5)\r\n    \r\n\tCALL tank1.speedometer.set, P$rX1\r\n\tCALL tank2.speedometer.set, P$rX2\r\n\r\n    IF (ABS(X$V1) < 0.00001)\r\n        stop\r\n    ENDIF\r\n\r\nadvance 0.1,0\r\n\r\nendwhile\r\n\r\nstop\r\nENDPROCEDURE\r\n;====================================================================\r\n\r\nPROCEDURE PRE_RUN\r\n\r\n    CALL create_indicators\r\n    \r\n    TIMEOUT agent.init,0\r\n\r\n\tTERMINATE_VE \r\nENDPROCEDURE\r\n;=================================================\r\nPROCEDURE create_indicators\r\n\r\n\tassign config,{title:\"X1\"\r\n\t\t,x:100,y:50 \r\n            ,width:50 ,height:180\r\n            ,value:0\r\n            ,min_value:-5\r\n            ,max_value:5\r\n            ,\"color\":\"#ff0000\"}\r\n            \r\n\tcall tank1.speedometer.init,V$config\r\n\r\n\tassign config,{title:\"X2\"\r\n\t\t,x:400,y:50 \r\n            ,width:50 ,height:180\r\n            ,value:0\r\n            ,min_value:-5\r\n            ,max_value:5\r\n            ,\"color\":\"purple\"}\r\n            \r\n\tcall tank2.speedometer.init,V$config\r\n\r\n\t\r\nENDPROCEDURE\r\n\r\n;=================================================\r\n\r\n\r\n\r\n",
                        "descripcion": "<h3 data-start=\"275\" data-end=\"303\">What is a constraint?<\/h3>\r\n<p data-start=\"305\" data-end=\"653\">In system dynamics, a <strong>constraint<\/strong> is a condition that must be met <strong>at all times<\/strong> during the simulation. Unlike an expression derived from the natural behavior of a component, a constraint <strong>does not change over time<\/strong> (it does not depend on the evolution of variables), but rather <strong>imposes a fixed relationship<\/strong> between them.<\/p>\r\n<p data-start=\"655\" data-end=\"797\">This is also known as an <strong>algebraic constraint<\/strong> and turns the system into a system of Differential-Algebraic Equations (<strong>DAE<\/strong>).<\/p>\r\n<h3>Example: Two masses joined by a rigid rod<\/h3>\r\n<p data-start=\"858\" data-end=\"1012\">Suppose two masses are connected by springs and dampers, but also joined by a <strong>rigid bar<\/strong> that maintains a constant distance between them.<\/p>\r\n<p data-start=\"1014\" data-end=\"1051\">This condition can be expressed as:<\/p>\r\n<pre>\r\nX2 - X1 = L<\/pre>\r\n<p data-start=\"1076\" data-end=\"1082\">Where:<\/p>\r\n<ul>\r\n    <li><code>X1<\/code> and <code>X2<\/code> are the positions of the masses<\/li>\r\n    <li><code>L<\/code> is the length of the bar<\/li>\r\n<\/ul>\r\n<p data-start=\"1164\" data-end=\"1382\">This equality must be maintained throughout the simulation. To achieve this, a <strong>constraint force<\/strong> is introduced, calculated using a <strong>Lagrange multiplier<\/strong> (<code>Lambda<\/code>) which is added to the system's equations.<\/p>\r\n<h3>System Configuration<\/h3>\r\n<pre>\r\nINITIAL mech_config, {\r\n  EXPRESSIONS: [\r\n\r\n    ; Newton's laws for each mass\r\n    \"F1 - M1 * (V1 - V1_prev) \/ DT\",\r\n    \"F2 - M2 * (V2 - V2_prev) \/ DT\",\r\n\r\n    ; Internal forces: spring and damper\r\n    \"FD1 - C1 * V1\",\r\n    \"F_spring1 - K1 * X1\",\r\n    \"FD2 - C2 * V2\",\r\n    \"F_spring2 - K2 * (X2 - X1)\",\r\n\r\n    ; Constraint force imposed by Lagrange\r\n    \"F_restriction + Lambda\",\r\n\r\n    ; Sum of forces on each mass\r\n    \"F1 + F_spring1 + FD1 - F_spring2 - F_restriction\",\r\n    \"F2 + F_spring2 + FD2 + F_restriction\",\r\n\r\n    ; Position integration\r\n    \"X1 - X1_prev - DT * V1\",\r\n    \"X2 - X2_prev - DT * V2\",\r\n\r\n    ; ***** Geometric constraint *****\r\n    \"X2 - X1 - L\"\r\n  ],\r\n\r\n  STATES: [\r\n    \"X1\", \"X2\",\r\n    \"V1\", \"V2\",\r\n    \"F1\", \"F2\",\r\n    \"FD1\", \"FD2\",\r\n    \"F_spring1\", \"F_spring2\",\r\n    \"F_restriction\",\r\n    \"Lambda\"  ; Lagrange variable\r\n  ],\r\n\r\n  VARIABLES: [\r\n    \"M1\", \"M2\",\r\n    \"K1\", \"K2\",\r\n    \"C1\", \"C2\",\r\n    \"L\",\r\n    \"X1_prev\", \"X2_prev\",\r\n    \"V1_prev\", \"V2_prev\"\r\n  ]\r\n}\r\n\r\n<\/pre>\r\n<h3 data-start=\"2407\" data-end=\"2436\">How the constraint acts<\/h3>\r\n<p data-start=\"2438\" data-end=\"2501\">The equation <code>\"X2 - X1 - L\"<\/code> is a <strong>constraint equation<\/strong>.<\/p>\r\n<p data-start=\"2503\" data-end=\"2731\">The system must solve all equations simultaneously (including the constraint). To do this, it introduces <code>Lambda<\/code>, an internal variable representing the <strong>necessary force<\/strong> to maintain that condition at every instant.<\/p>\r\n<p data-start=\"2733\" data-end=\"2815\">This force is then added (or subtracted) to the total force equations for each mass:<\/p>\r\n<pre>\r\n\"F1 + ... - F_restriction\"\r\n\"F2 + ... + F_restriction\"<\/pre>\r\n<p>This ensures that if the system tends to violate the constraint (due to acceleration, for example), the constraint force reacts immediately to maintain it.<\/p>\r\n<h3 data-start=\"3053\" data-end=\"3081\">What does GPSS-Plus solve?<\/h3>\r\n<p data-start=\"3083\" data-end=\"3330\">All of this is resolved within the <code>DYNAMIC<\/code> block, through the internal use of the <strong>Newton-Raphson<\/strong> method and Jacobian matrices. These allow for solving both <strong>dynamic variables<\/strong> (<code>X1<\/code>, <code>V1<\/code>, etc.) and <strong>algebraic variables<\/strong> (<code>Lambda<\/code>) in the same system.<\/p>\r\n<h2 data-start=\"3657\" data-end=\"3670\">Conclusion<\/h2>\r\n<p data-start=\"3672\" data-end=\"3755\"><strong>Constraints<\/strong> allow for the simulation of realistic and complex behaviors, such as:<\/p>\r\n<ul data-start=\"3757\" data-end=\"3893\">\r\n    <li data-start=\"3757\" data-end=\"3773\">\r\n    <p data-start=\"3759\" data-end=\"3773\">Rigid bars<\/p>\r\n    <\/li>\r\n    <li data-start=\"3774\" data-end=\"3818\">\r\n    <p data-start=\"3776\" data-end=\"3818\">Hydraulic pistons with constant volume<\/p>\r\n    <\/li>\r\n    <li data-start=\"3819\" data-end=\"3857\">\r\n    <p data-start=\"3821\" data-end=\"3857\">Geometric relationships in mechanisms<\/p>\r\n    <\/li>\r\n    <li data-start=\"3858\" data-end=\"3893\">\r\n    <p data-start=\"3860\" data-end=\"3893\">Conservation of energy or momentum<\/p>\r\n    <\/li>\r\n<\/ul>\r\n<p data-start=\"3895\" data-end=\"4051\">The use of <strong><code>Lambda<\/code><\/strong> as a Lagrange multiplier is a key tool for introducing them explicitly and in a controlled manner into your dynamic systems.<\/p>\r\n<p>&nbsp;<\/p>\r\n<p>&nbsp;<\/p>",
                        "parametros": null,
                        "parametros_json": null,
                        "ejemplo": null,
                        "hijos": []
                    }
                ]
            }
        ]
    },
    {
        "id": "328",
        "nombre": "Season 12: Physical and Real-World Coupling",
        "texto": "",
        "descripcion": "",
        "parametros": null,
        "parametros_json": null,
        "ejemplo": null,
        "hijos": [
            {
                "id": "330",
                "nombre": "Coupling with the Real World",
                "texto": "",
                "descripcion": "<p data-start=\"330\" data-end=\"616\">Until now, we have worked by building models that operated within a closed and controlled universe inside the GPSS-Plus engine. The simulation engine decided when time advanced, what happened at each moment, and how the system elements behaved. It was a logical, deterministic, and autonomous environment.<\/p>\r\n<p data-start=\"618\" data-end=\"848\">We are going to break away from all that with the introduction of the <b>real world<\/b>. Nothing will be the same: the engine's focus changes, entities will live according to other patterns, and flows will no longer be solely under our control.<\/p>\r\n<p data-start=\"1217\" data-end=\"1344\">Entities should not advance because a random number decides so, but because a physical sensor has detected their presence.<\/p>\r\n<p><b>Time<\/b><\/p>\r\n<p data-start=\"1366\" data-end=\"1472\">One of the first consequences of this opening to the outside is that <strong>time no longer belongs to us<\/strong>.<\/p>\r\n<p data-start=\"1474\" data-end=\"1776\">We can no longer arbitrarily accelerate or pause it. If the engine wants to read from a sensor, it must wait as long as that sensor takes to respond. If reading a file is delayed, the simulation will be as well. Therefore, when working with the real world, <strong>execution must be in real-time<\/strong>.<\/p>\r\n<p data-start=\"1778\" data-end=\"1886\">What was previously just a \"moment\" is now strictly one second on the system clock. It is declared as follows:<\/p>\r\n<pre>\r\nSYSTEM {TYPE:OPTIONS, REAL_TIME:1}<\/pre>\r\n<p data-pm-slice=\"1 1 []\">An <code>ADVANCE 10<\/code> means exactly a wait of 10 <b>real<\/b> seconds.<\/p>\r\n<p data-pm-slice=\"1 1 []\">From there, there is no turning back: everything happens at the rhythm of the physical world, and the simulation becomes a subordinate part of reality.<br>\r\nThe engine ceases to be a pure simulator and starts behaving as an <strong>orchestrator of real processes<\/strong>.<\/p>\r\n<p data-pm-slice=\"1 1 []\"><b>The New System Architecture<\/b><\/p>\r\n<p data-start=\"1769\" data-end=\"2296\">We can now identify three major components of the system:<\/p>\r\n<ul>\r\n    <li><b>GPSS-Plus and the BRIDGER resource<\/b>, which entities will use to issue and receive commands.<\/li>\r\n    <li><b>The Outside World<\/b>, which can include sensors, databases, file systems, or physical\/virtual devices. Even other simulation engines.<\/li>\r\n    <li><b>The middleware.js<\/b>, which is a new bidirectional software that knows how to communicate with the <code>BRIDGER<\/code> and any element of the <b>outside world<\/b>.<\/li>\r\n<\/ul>\r\n<p data-start=\"1769\" data-end=\"2296\"><b>THE BRIDGER:<\/b><\/p>\r\n<p>From an entity's point of view, in addition to the <code>BRIDGER<\/code> COMMAND, it only has 5 BLOCKS:<\/p>\r\n<ul>\r\n    <li>BRIDGE_READ<\/li>\r\n    <li>BRIDGE_WRITE<\/li>\r\n    <li>BRIDGE_SUBSCRIBE<\/li>\r\n    <li>BRIDGE_BROWSE<\/li>\r\n    <li>BRIDGE_CALL<\/li>\r\n<\/ul>\r\n<p data-start=\"1769\" data-end=\"2296\">These BLOCKS are the ones that communicate with <b>middleware.js<\/b>.<\/p>\r\n<p data-start=\"1769\" data-end=\"2296\">&nbsp;<\/p>\r\n<p data-start=\"1769\" data-end=\"2296\"><b>THE MIDDLEWARE.js<\/b><\/p>\r\n<p>Available in the downloads chapter.<\/p>\r\n<p>It is a set of JavaScript files to run in a node.js environment that receives instructions from the <code>BRIDGER<\/code> and retransmits them to the external device and vice versa.<\/p>\r\n<p>In summary, <strong><em>middleware.js<\/em> functions as an exchange layer between protocols<\/strong>, transforming the five blocks defined in GPSS-Plus into messages compatible with <strong>MQTT<\/strong> (the most widely used, based on <em>topics<\/em>) and <strong>OPC-UA<\/strong> (the most complete, with hierarchical structures and defined data types).<\/p>\r\n<p>For initial testing, there is an operational public service at:<\/p>\r\n<p>wss:\/\/bridger.gpss-plus.com:3000<\/p>\r\n<p>&nbsp;<\/p>\r\n<p data-start=\"1769\" data-end=\"2296\"><b>The Outside World<\/b><\/p>\r\n<p>These are all the sensors, actuators, devices, and external resources.<\/p>\r\n<p>For testing, you have a <strong>virtual OPC-UA client<\/strong> that represents a set of simulated sensors and services.<\/p>\r\n<p>Its address is: opc.tcp:\/\/opcua.gpss-plus.com:4840<\/p>\r\n<p>It contains a scale, a door sensor, distance sensors, PID control, file reading and writing, and even background program execution.<\/p>\r\n<p>Naturally, you can <strong>modify and expand the code<\/strong> to add your own services.<\/p>\r\n<p><b>The Topology:<\/b><\/p>\r\n<p>These three elements are distributed as follows:<\/p>\r\n<pre>\r\ngpss-plus           192.168.x.x           192.168.n.m\r\nBRIDGER       <->  middleware.js    <->  Temperature Sensor \r\n192.168.a.b    |                         File System\r\n(The browser)  |                         MySQL Database\r\n               |\r\n               |                         192.168.n.m\r\n               |   192.168.y.y           Random number generator\r\n              <->  middleware.js    <->  Neural network\r\n               |                         OPC-UA Motion detector\r\n               |\r\n               |\r\n               |   192.168.z.z           192.168.n.m\r\n              <->  middleware.js    <->  Inter-system semaphore\r\n                                     <\/pre>\r\n<p>In summary, the <strong>browser<\/strong> running GPSS-Plus must be able to access the IP where <strong>middleware.js<\/strong> is installed, and this, in turn, must access the external device or service.<br data-start=\"4932\" data-end=\"4935\">\r\nThe most stable configuration is to have <strong>middleware.js on the same network as the sensors<\/strong>.<\/p>\r\n<p>In the following chapters, we will see <strong>how to handle the BRIDGER step by step<\/strong> and we will build <strong>our own physical devices<\/strong>.<\/p>\r\n<p>&nbsp;<\/p>",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            },
            {
                "id": "336",
                "nombre": "External Resources",
                "texto": "<p>In <strong>GPSS-Plus<\/strong>, we call an <em>external resource<\/em> any element of the system that is <strong>not directly part of the simulation engine<\/strong>, but with which entities can interact.<br>\r\nThese resources can act as <strong>data sources<\/strong> or as <strong>real actuators<\/strong> within the physical or digital environment.<\/p>\r\n<h4 data-start=\"683\" data-end=\"724\">What counts as an external resource?<\/h4>\r\n<p data-start=\"747\" data-end=\"773\">Typical examples include:<\/p>\r\n<ul data-start=\"775\" data-end=\"1166\">\r\n    <li>\r\n    <p>A <strong>file<\/strong> in the file system (FS).<\/p>\r\n    <\/li>\r\n    <li>\r\n    <p>A <strong>MySQL table<\/strong> or any database accessible via the network.<\/p>\r\n    <\/li>\r\n    <li>\r\n    <p>A <strong>physical sensor<\/strong>, such as a temperature or motion detector, connected via <strong>OPC-UA<\/strong> or <strong>MQTT<\/strong>.<\/p>\r\n    <\/li>\r\n    <li>\r\n    <p>A <strong>REST API<\/strong> that returns states or accepts commands.<\/p>\r\n    <\/li>\r\n    <li>\r\n    <p>An <strong>industrial or electronic device<\/strong>, such as a scale, a motor, or a load cell.<\/p>\r\n    <\/li>\r\n<\/ul>\r\n<p>In short, <strong>everything that lives outside the engine but can influence it<\/strong> is considered an external resource.<\/p>\r\n<h3>One single mechanism for all<\/h3>\r\n<p>GPSS-Plus does not differentiate between a sensor and a database.<br>\r\nBoth are treated uniformly through the <code><strong>BRIDGER<\/strong><\/code> resource, which acts as a universal access interface.<\/p>\r\n<p>This enormously simplifies the mental model:<br>\r\nyou can replace a real sensor with a MySQL table, or a local file, <strong>without rewriting your model<\/strong>, simply by changing the <code>BRIDGER<\/code> configuration.<\/p>\r\n<h3>Example sensor: OPC-UA Virtual Device<\/h3>\r\n<p><strong>OPC-UA (Open Platform Communications – Unified Architecture)<\/strong> is an industrial standard for structured communication between devices and systems.<br>\r\nIt allows for the exchange of <strong>nodes, attributes, and events<\/strong> in a secure, hierarchical, and extensible manner.<\/p>\r\n<p>In GPSS-Plus, you can connect to both a <strong>real OPC-UA server<\/strong> and the <strong>included virtual device<\/strong> for testing and development without physical hardware.<\/p>\r\n<p>This virtual device exposes simulated nodes such as:<\/p>\r\n<ul>\r\n    <li><code>Sensor_Temp_1<\/code><\/li>\r\n    <li><code>Motor_X.Status<\/code><\/li>\r\n    <li><code>Contador_Piezas<\/code> (Part_Counter)<\/li>\r\n    <li><code>Puerta_Acceso_A.IsOpen<\/code> (Access_Door_A.IsOpen)<\/li>\r\n<\/ul>\r\n<p>You will be able to <strong>read, write, or subscribe to their changes<\/strong> using the same <code>BRIDGER<\/code> mechanism.<\/p>\r\n<p>In the following chapters, we will see how to:<\/p>\r\n<ul>\r\n    <li>Detect events, such as the opening of a simulated door.<\/li>\r\n    <li>Access file systems or read-only online services.<\/li>\r\n    <li>Execute remote applications or scripts.<\/li>\r\n<\/ul>\r\n<p>Both the <strong>virtual OPC-UA device<\/strong> and <strong>middleware.js<\/strong> can be freely downloaded and modified to suit your own needs or real hardware.<\/p>",
                "descripcion": "",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            },
            {
                "id": "353",
                "nombre": "BRIDGE_SUBSCRIPTION: Obtaining Real-Time Data",
                "texto": "SYSTEM {TYPE:PRE_RUN,TRIGGER:PRE_RUN}\r\nSYSTEM {TYPE:OPTIONS, REAL_TIME:1}\r\n\r\nFacility {NAME:facility1,X:446,Y:514}\r\n\r\nGraphic {Type:TEXT,Name:Text1,X:376,Y:358}\r\nGraphic {Type:TEXT,Name:TextError,X:376,Y:330,Text:\"On error....\"}\r\n\r\nInitial options,{user:\"user\", pass:\"1234\"}\r\n\r\nBRIDGER {NAME:bridge1,X:375,Y:398\r\n\t,SERVER:\"wss:\/\/bridger.gpss-plus.com:3000\"\r\n\t,CLIENT:\"opc.tcp:\/\/opcua.gpss-plus.com:4840\"\r\n    ,OPTIONS:V$options\r\n    ,on_error:bridge1_on_error\r\n    }\r\n\r\n\r\nPOSITION {NAME:POS1,X:264,Y:511}\r\n\r\nPOSITION {NAME:POS2,X:658,Y:509}\r\n\r\n\r\nSTART 100\r\n\r\n;*****************************************************\r\n\r\nPROCEDURE PRE_RUN\r\n    BRIDGE_SUBSCRIPTION { NAME: bridge1\r\n\t, VARIABLE: \"Sensor_Door_IsOpen\"\r\n    , TRIGGER: on_open \r\n    }\r\n\r\n\tTERMINATE_VE\r\nENDPROCEDURE\r\n\r\n;*****************************************************\r\nGENERATE 0,0,0,0 {NAME:GEN1,X:141,Y:351}\r\n    ADVANCE 5,0 {TO:POS1}\r\n    ADVANCE 5,0 {TO:facility1}\r\n    SEIZE facility1\r\n    advance 10,10\r\n    RELEASE facility1\r\n    ADVANCE 10,0 {TO:POS2}\r\nENDGENERATE 1\r\n;----------------------------------------------------------------------------\r\nprocedure on_open\r\n        move {name:Text1,TEXT:\"DOOR P$(PARAM_A.VALUE)\"}\r\n        if (P$(PARAM_A.VALUE.EXIST) && P$(PARAM_A.VALUE)==1)\r\n    \tNEW GEN1\r\n    \tendif\r\n\tTERMINATE_VE\r\nendprocedure\r\n;----------------------------------------------------------------------------\r\nprocedure bridge1_on_error\r\n        move {name:TextError,TEXT:\"P$PARAM_A\"}\r\n\tTERMINATE_VE\r\nendprocedure\r\n",
                "descripcion": "<p>Let's look at a concrete example to understand how information flows between <strong>GPSS-Plus<\/strong>, <strong>middleware.js<\/strong>, and the <strong>OPC-UA server<\/strong>.<\/p>\r\n<p>We are going to modify the behavior of a <strong>GENERATE<\/strong> block so that <strong>entities are created when a physical (simulated) sensor<\/strong> detects a door opening —instead of doing it by time or probability parameters.<\/p>\r\n<h3><strong>Creating the Communication Bridge<\/strong><\/h3>\r\n<p>The first step is to define the <strong>BRIDGER<\/strong>, which will be the link to the outside world:<\/p>\r\n<pre>\r\nInitial options,{user:\"user\", pass:\"1234\"}\r\n\r\nBRIDGER {NAME:bridge1,X:333,Y:444\r\n    ,SERVER:\"wss:\/\/bridger.gpss-plus.com:3000\"\r\n    ,CLIENT:\"opc.tcp:\/\/opcua.gpss-plus.com:4840\"\r\n    ,OPTIONS:V$options\r\n    ,ON_ERROR:bridge1_on_error\r\n    }<\/pre>\r\n<p>The main parameters are:<\/p>\r\n<ul>\r\n    <li><strong>NAME<\/strong>: Internal identifier for the BRIDGER (e.g., <code>bridge1<\/code>).<\/li>\r\n    <li><strong>SERVER<\/strong>: The secure WebSocket address where <code>middleware.js<\/code> is listening.<\/li>\r\n    <li><strong>CLIENT<\/strong>: The address of the OPC-UA server (usually on the same network as the middleware).<\/li>\r\n    <li><strong>OPTIONS<\/strong>: Additional parameters (such as username and password) required for the connection.<\/li>\r\n    <li><strong>ON_ERROR<\/strong>: A <em>trigger<\/em> that will execute if a communication error occurs.<\/li>\r\n<\/ul>\r\n<h3><strong>Subscribing to a Sensor<\/strong><\/h3>\r\n<p>Once the bridge is defined, we must <strong>start the connection<\/strong> within the model's <code>PRE_RUN<\/code> and <strong>subscribe<\/strong> to the variable representing the door's state:<\/p>\r\n<pre>\r\n    BRIDGE_SUBSCRIPTION { NAME: bridge1\r\n      , VARIABLE: \"Sensor_Door_IsOpen\"\r\n    , TRIGGER: on_open \r\n    }<\/pre>\r\n<p>This instruction keeps a channel open with the sensor to receive <strong>automatic notifications<\/strong> every time its value changes.<\/p>\r\n<p>The parameters are minimal:<\/p>\r\n<ul>\r\n    <li><strong>NAME<\/strong>: The name of the BRIDGER that will manage the communication.<\/li>\r\n    <li><strong>VARIABLE<\/strong>: The exact name of the variable published by the sensor.<\/li>\r\n    <li><strong>TRIGGER<\/strong>: The procedure that will process each received update.<\/li>\r\n<\/ul>\r\n<p>Subscriptions allow receiving data in real-time without the need to perform periodic polling (reads).<\/p>\r\n<h3><strong>The Associated Procedure<\/strong><\/h3>\r\n<p>Each time a new value is received, the specified <em>trigger<\/em> is executed.<br>\r\nThe parameter <code>P$(PARAM_A.VALUE)<\/code> will contain the current value of the sensor (0 or 1 in this case). <code>PARAM_B<\/code> contains the calling entity's number and <code>PARAM_C<\/code> the timestamp.<\/p>\r\n<pre>\r\nprocedure on_open\r\n   move {name:Text1,TEXT:\"DOOR P$(PARAM_A.VALUE)\"}\r\n     if (P$(PARAM_A.VALUE.EXIST) && P$(PARAM_A.VALUE)==1)\r\n        NEW GEN1\r\n     endif\r\n   TERMINATE_VE\r\nendprocedure\r\n<\/pre>\r\n<p>In this example, <strong>every time the sensor detects that the door opens (value = 1)<\/strong>, the system <strong>creates a new GEN1 entity<\/strong>, simulating a person entering the system.<\/p>",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            },
            {
                "id": "354",
                "nombre": "BRIDGE_BROWSE: Device View",
                "texto": "SYSTEM {TYPE:PRE_RUN,TRIGGER:PRE_RUN}\r\nSYSTEM {TYPE:OPTIONS, REAL_TIME:1}\r\n\r\nGraphic {Type:TEXT,Name:Text1,X:653,Y:294}\r\nGraphic {Type:TEXT,Name:TextError,X:440,Y:329,Text:\"On error....\"}\r\n\r\nInitial options,{user:\"user\", pass:\"1234\"}\r\n\r\nBRIDGER {NAME:bridge1,X:443,Y:405\r\n\t,SERVER:\"wss:\/\/bridger.gpss-plus.com:3000\"\r\n\t,CLIENT:\"opc.tcp:\/\/opcua.gpss-plus.com:4840\"\r\n    ,OPTIONS:V$options\r\n    ,on_error:bridge1_on_error\r\n    }\r\n\r\n\r\nPOSITION {NAME:POS1,X:209,Y:347}\r\n\r\nSTART 1\r\n\r\n;*****************************************************\r\n\r\nPROCEDURE PRE_RUN\r\n    BRIDGE_BROWSE { NAME: bridge1\r\n    , TRIGGER: on_browse \r\n    }\r\n\r\n\tTERMINATE_VE\r\nENDPROCEDURE\r\n\r\n;*****************************************************\r\nGENERATE 10,0,0,1 {NAME:GEN1,X:141,Y:351}\r\n    ADVANCE 5,0 {TO:POS1}\r\nENDGENERATE 1\r\n;----------------------------------------------------------------------------\r\nprocedure on_browse\r\n        move {name:Text1,TEXT:\"BROWSE P$(PARAM_A)\"}\r\n\tTERMINATE_VE\r\nendprocedure\r\n;----------------------------------------------------------------------------\r\nprocedure bridge1_on_error\r\n    move {name:TextError,TEXT:\"P$PARAM_A\"}\r\n    TERMINATE_VE\r\nendprocedure\r\n",
                "descripcion": "<p>We have seen that in the virtual OPC-UA device we could repeatedly read the values of the variable \"Sensor_Door_IsOpen\".<\/p>\r\n<p>However, <strong>we will not always know which variables or methods exist<\/strong> within a device. For example, a file service might list directories, or a database might expose tables whose names change.<\/p>\r\n<p>For this purpose, the <strong><code>BRIDGE_BROWSE<\/code><\/strong> block exists, allowing you to <strong>query the internal structure<\/strong> of the connected device or service.<\/p>\r\n<p><strong>Why use BRIDGE_BROWSE?<\/strong><\/p>\r\n<p>The <code>BRIDGE_BROWSE<\/code> command is used to discover:<\/p>\r\n<ul>\r\n    <li>Which <strong>variables<\/strong> are available.<\/li>\r\n    <li>What data type each one has (Boolean, Double, String, etc.).<\/li>\r\n    <li>Whether they are <strong>read-only<\/strong>, <strong>writable<\/strong>, or both.<\/li>\r\n    <li>What <strong>methods<\/strong> or operations are exposed.<\/li>\r\n<\/ul>\r\n<p>In other words, it is the <strong>capability map of the device<\/strong>.<\/p>\r\n<p>Out of the 5 <code>BRIDGER<\/code> blocks, let's see what is obtained from <code>BRIDGE_BROWSE<\/code>:<\/p>\r\n<ul>\r\n    <li>BRIDGE_READ<\/li>\r\n    <li>BRIDGE_WRITE<\/li>\r\n    <li>BRIDGE_SUBSCRIBE<\/li>\r\n    <li><strong>BRIDGE_BROWSE<\/strong><\/li>\r\n    <li>BRIDGE_CALL<\/li>\r\n<\/ul>\r\n<p><code>BRIDGE_BROWSE<\/code> runs <strong>automatically during the first connection<\/strong>, but it can also be <strong>invoked manually<\/strong> if you wish to explore a new device or verify what has changed.<\/p>\r\n<h3><strong>Example Output (Debug or Canvas)<\/strong><\/h3>\r\n<p>When executing <code>BRIDGE_BROWSE<\/code>, the middleware returns a hierarchical list of accessible variables:<\/p>\r\n<pre>\r\nSensor_Motion_Detected: ns=1;i=1000 [Boolean] \r\nSensor_Door_IsOpen: ns=1;i=1001 [Boolean] \r\nPIDControl_CurrentTemperature: ns=1;i=1002 [Double] \r\nPIDControl_Setpoint: ns=1;i=1003 [Double] (writable) \r\nPIDControl_PIDOutput: ns=1;i=1004 [Double] \r\nDevice_Motor_Enabled: ns=1;i=1005 [Boolean] (writable) \r\nSystem_Battery_BatteryLevel: ns=1;i=1006 [Double] \r\nDevice_Scale_Weight: ns=1;i=1007 [Double] \r\nDevice_Scale_Trigger: ns=1;i=1008 [Boolean] (writable) \r\nDevice_Piston_IsExtended: ns=1;i=1009 [Boolean] \r\nDevice_Piston_Trigger: ns=1;i=1010 [Boolean] (writable)\r\n...\r\n<\/pre>\r\n<p>Each line shows:<\/p>\r\n<ul>\r\n    <li>The <strong>variable name<\/strong>.<\/li>\r\n    <li>Its <strong>internal identifier<\/strong> (<code>ns=1;i=1000<\/code>, typical in OPC-UA).<\/li>\r\n    <li>The <strong>data type<\/strong>.<\/li>\r\n    <li>Whether it is <strong>writable<\/strong> (<code>(writable)<\/code>).<\/li>\r\n    <li>Whether it is an executable method.<\/li>\r\n<\/ul>\r\n<h3><strong>Using BRIDGE_BROWSE Manually<\/strong><\/h3>\r\n<p>Before interacting with a new device, run <code>BRIDGE_BROWSE<\/code> once to understand its structure.<br>\r\nAfterward, you can use <code>BRIDGE_READ<\/code>, <code>BRIDGE_WRITE<\/code>, or <code>BRIDGE_SUBSCRIBE<\/code> accurately on the variables you have identified.<\/p>",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            },
            {
                "id": "355",
                "nombre": "BRIDGE_WRITE & BRIDGE_READ: The Actuator",
                "texto": "SYSTEM {TYPE:OPTIONS, REAL_TIME:1}\r\n\r\nGraphic {Type:TEXT,Name:Text1,X:653,Y:294}\r\nGraphic {Type:TEXT,Name:Text2,X:653,Y:194}\r\nGraphic {Type:TEXT,Name:TextError,X:440,Y:329,Text:\"On error....\"}\r\n\r\nInitial options,{user:\"user\", pass:\"1234\"}\r\n\r\nBRIDGER {NAME:bridge1,X:443,Y:405\r\n\t,SERVER:\"wss:\/\/bridger.gpss-plus.com:3000\"\r\n\t,CLIENT:\"opc.tcp:\/\/opcua.gpss-plus.com:4840\"\r\n    ,OPTIONS:V$options\r\n    ,on_error:bridge1_on_error\r\n    }\r\n\r\n\r\nPOSITION {NAME:POS1,X:209,Y:347}\r\nPOSITION {NAME:POS2,X:409,Y:347}\r\n\r\nSTART 100\r\n\r\n;*****************************************************\r\nGENERATE 3,0,0,10 {NAME:GEN1,X:141,Y:351}\r\n\r\n\tASSIGN values, [\"Device_Motor_Enabled\"]\r\n\tBRIDGE_READ {name:bridge1, trigger:on_read, VALUES:V$values}\r\n\tADVANCE 5,0 {TO:POS1}\r\n\r\n\tif (D$N %2 == 0 )\r\n    ASSIGN values, { Device_Motor_Enabled: 0 }\r\n\tBRIDGE_WRITE { name:bridge1, VALUES:V$values ,TRIGGER:on_write}\r\n    else\r\n    ASSIGN values, { Device_Motor_Enabled: 1 }\r\n\tBRIDGE_WRITE { name:bridge1, VALUES:V$values ,TRIGGER:on_write}\r\n    endif\r\n    \r\n\tADVANCE 5,0 {TO:POS2}\r\nENDGENERATE 1\r\n;----------------------------------------------------------------------------\r\nprocedure on_write\r\n        move {name:Text1,TEXT:\"AC1$ WRITE P$(PARAM_A)\"}\r\n\tTERMINATE_VE\r\nendprocedure\r\n;----------------------------------------------------------------------------\r\nprocedure on_read\r\n        move {name:Text2,TEXT:\"AC1$ READ P$(PARAM_A)  \\n::  Value: P$(PARAM_A.Device_Motor_Enabled)\"}\r\n\tTERMINATE_VE\r\nendprocedure\r\n;----------------------------------------------------------------------------\r\nprocedure bridge1_on_error\r\n    move {name:TextError,TEXT:\"AC1$ P$PARAM_A\"}\r\n   TERMINATE_VE\r\nendprocedure\r\n",
                "descripcion": "<p>Until now, we have received data from the outside world.<br>\r\nNow we will learn to <strong>send instructions<\/strong> and <strong>read specific values<\/strong> from GPSS-Plus to an OPC-UA, MQTT, or any other device connected through <code>middleware.js<\/code>.<\/p>\r\n<h3 data-start=\"725\" data-end=\"759\"><strong>Writing to a Device<\/strong><\/h3>\r\n<p data-start=\"761\" data-end=\"836\">Giving a command to an actuator is as simple as assigning a value and sending it:<\/p>\r\n<pre>\r\n    ASSIGN values, { Device_Motor_Enabled: 1 }\r\n    BRIDGE_WRITE { name:bridge1, VALUES:V$values ,TRIGGER:on_write}<\/pre>\r\n<p>This writes to the <code>Device_Motor_Enabled<\/code> variable of the device, turning the motor on (1 = ON, 0 = OFF).<br>\r\nThe structure of the command is always the same:<\/p>\r\n<ul>\r\n    <li><strong>VALUES:<\/strong> A key-value set with the variables to be modified.<\/li>\r\n    <li><strong>TRIGGER:<\/strong> The procedure that will execute when the middleware confirms delivery.<\/li>\r\n<\/ul>\r\n<h3><strong>Reading a Variable State<\/strong><\/h3>\r\n<p>Reading is performed in an analogous way:<\/p>\r\n<pre>\r\n    ASSIGN values, [\"Device_Motor_Enabled\"]\r\n    BRIDGE_READ {name:bridge1, trigger:on_read, VALUES:V$values}<\/pre>\r\n<p>In this case, the list <code>[\"Device_Motor_Enabled\"]<\/code> indicates which variables we want to query.<br>\r\nThe value will arrive <strong>asynchronously<\/strong>, and will be received within the corresponding <em>trigger<\/em> (<code>on_read<\/code>).<\/p>\r\n<h3><strong>Asynchronous vs. Synchronous Execution<\/strong><\/h3>\r\n<p>By default, <strong>READ<\/strong> and <strong>WRITE<\/strong> operations are <strong>asynchronous<\/strong>:<br>\r\nthe GPSS-Plus engine continues its execution without stopping to wait for the device's response.<\/p>\r\n<p>This is standard for physical systems, where communication can take several hundred milliseconds.<\/p>\r\n<p>If the resource is <strong>immediate<\/strong> (e.g., a local file or an internal database), you can force a <strong>synchronous<\/strong> operation with:<\/p>\r\n<pre>\r\n BRIDGE_READ { name:bridge1, VALUES:V$values, SYNC:1, trigger:on_read }<\/pre>\r\n<p>In this mode, the entity and the engine <strong>block<\/strong> until the response is received.<br>\r\nThis should only be used in controlled contexts, as stopping the simulator's time affects the entire system.<\/p>",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            },
            {
                "id": "338",
                "nombre": "Complete Example: Weighing Control and Classification",
                "texto": "SYSTEM {TYPE:PRE_RUN,TRIGGER:PRE_RUN}\r\nSYSTEM {TYPE:OPTIONS, REAL_TIME:1}\r\n\r\nRestroom {NAME:LiberadorUnitario,X:155,Y:332}\r\n\r\nQueuer {NAME:zonaBascula,X:163,Y:32}\r\nGraphic {NAME:lineZonaBascula,Type:LINE,color:#FF0000, X1:82,Y1:64,X2:260,Y2:65}\r\n\r\nRestroom {NAME:RestroomBascula,X:226,Y:110}\r\n\r\ninitial pesoLimite,8\r\n\r\nInitial options,{user:\"user\", pass:\"1234\"}\r\n\r\nBRIDGER {NAME:bridge1,X:733,Y:556\r\n\t,SERVER:\"wss:\/\/bridger.gpss-plus.com:3000\"\r\n\t,CLIENT:\"opc.tcp:\/\/opcua.gpss-plus.com:4840\"\r\n    ,OPTIONS:V$options\r\n    ,on_error:bridge1_on_error\r\n    }\r\n\r\n\r\nPOSITION {NAME:POS1,X:97,Y:437}\r\nPOSITION {NAME:POS2,X:95,Y:183}\r\n\r\nPOSITION {NAME:PosBascula,X:225,Y:199}\r\nPOSITION {NAME:PosSeparador,X:387,Y:201}\r\nPOSITION {NAME:PosPesados,X:513,Y:302}\r\nPOSITION {NAME:PosPesados2,X:594,Y:302}\r\nPOSITION {NAME:PosLigeros,X:511,Y:197}\r\nPOSITION {NAME:PosLigeros2,X:592,Y:197}\r\n\r\nGraphic {NAME:Text1,Type:TEXT,X:167,Y:484,Text:\"On OPEN\"}\r\nGraphic {NAME:TextError,Type:TEXT,X:424,Y:582,Text:\"Error\"}\r\n\r\nGraphic {NAME:lineBascula,Type:LINE,color:#FF0000, X1:191,Y1:176,X2:263,Y2:176}\r\nGraphic {NAME:txtBascula,Type:TEXT,X:226,Y:156,Text:\"bascula\"}\r\n\r\nGraphic {NAME:lineSeparador,Type:LINE,color:#FF0000, X1:363,Y1:201,X2:432,Y2:201}\r\nGraphic {NAME:txtSeparador,Type:TEXT,X:394,Y:143,Text:\"separador\"}\r\n\r\nSTART 10\r\n\r\n;*****************************************************\r\n\r\nPROCEDURE PRE_RUN\r\n    BRIDGE_SUBSCRIPTION { NAME: bridge1\r\n\t, VARIABLE: \"Sensor_Door_IsOpen\"\r\n    , TRIGGER: on_open \r\n    }\r\nsavevalue pesoActual,0\r\nsavevalue pesoAnterior,X$pesoActual\r\n\r\n\tBRIDGE_SUBSCRIPTION { NAME: bridge1\r\n        , VARIABLE: \"Device_Scale_Weight\"\r\n        , TRIGGER: on_subscription_bascula \r\n        }\r\n\tBRIDGE_SUBSCRIPTION { NAME: bridge1\r\n        , VARIABLE: \"Device_Piston_IsExtended\"\r\n        , TRIGGER: on_subscription_piston \r\n        }\r\n\r\nASSIGN values, { Device_Scale_Trigger: 0 }\r\nBRIDGE_WRITE { name:bridge1, VALUES:V$values ,TRIGGER:on_write}\r\n \r\n\tTERMINATE_VE\r\nENDPROCEDURE\r\n\r\n;*****************************************************\r\nGENERATE 0,0,0,0 {NAME:GEN1,X:91,Y:547}\r\n\r\nADVANCE 5,0 {TO:POS1,flow:1}\r\nADVANCE 5,0 {TO:LiberadorUnitario,flow:1}\r\nif (R$(zonaBascula,in)>0)\r\n\trest LiberadorUnitario\r\nendif\r\nqueue zonaBascula\r\n\r\nADVANCE 5,0 {TO:POS2,flow:1}\r\nADVANCE 5,0 {TO:PosBascula,flow:1}\r\n\r\nASSIGN values, { Device_Scale_Trigger: 1 }\r\nBRIDGE_WRITE { name:bridge1, VALUES:V$values ,TRIGGER:on_write}\r\n\r\nrest RestroomBascula\r\ndepart zonaBascula\r\ncall liberarRestroomBascula\r\n\r\nADVANCE 2\r\nmod {subtitle:\"P$peso Kg\"}\r\nif (P$peso > X$pesoLimite)\r\n    mod {color:\"red\"}\r\nelse\r\n    mod {color:\"green\"}\r\nendif\r\n\r\nASSIGN values, { Device_Scale_Trigger: 0 }\r\nBRIDGE_WRITE { name:bridge1, VALUES:V$values ,TRIGGER:on_write}\r\n\r\ntimeout moverPiston,4.3,P$peso\r\n\r\nADVANCE 5,0 {TO:PosSeparador,flow:1}\r\n\r\nif (P$peso > X$pesoLimite)\r\n    ADVANCE 3,0 {TO:PosPesados}\r\n\tADVANCE 3,0 {TO:PosPesados2,flow:1}\r\nelse\r\n    ADVANCE 3,0 {TO:PosLigeros}\r\n \tADVANCE 3,0 {TO:PosLigeros2,flow:1}\r\nendif\r\n\r\nENDGENERATE 1\r\n;----------------------------------------------------------------------------\r\n\r\nprocedure on_open\r\n       move {name:Text1,TEXT:\"DOOR P$(PARAM_A.VALUE)\"}\r\n       if (P$(PARAM_A.VALUE.EXIST))\r\n       if (P$(PARAM_A.VALUE)==1)\r\n    \tNEW GEN1\r\n    \tendif\r\n       endif\r\n\tTERMINATE_VE\r\nendprocedure\r\n\r\nprocedure bridge1_on_error\r\n    move {name:TextError,TEXT:\"P$PARAM_A\"}\r\n\tTERMINATE_VE\r\nendprocedure\r\n;-------------------------\r\nprocedure on_subscription_bascula\r\n\tsavevalue pesoActual,P$(PARAM_A.VALUE)\r\n    move {name:txtBascula,TEXT:\"X$pesoActual Kg\"}\r\n    if (ABS(X$pesoAnterior-X$pesoActual)<=0.1 && X$pesoActual>1)\r\n\t    FOREACH entidad, IN_RESOURCE, RestroomBascula\r\n\t    \tassign peso,round(X$pesoActual,1), P$entidad\r\n\t\tENDFOREACH\r\n    \r\n\t    wake RestroomBascula\r\n    endif\r\n\tsavevalue pesoAnterior,X$pesoActual\r\n\r\n\tTERMINATE_VE\r\nendprocedure\r\n;-------------------------\r\nprocedure on_write\r\n\tTERMINATE_VE\r\nendprocedure\r\n\r\nprocedure on_subscription_piston\r\n\tif (P$(PARAM_A.VALUE)==1)\r\n    move {name:lineSeparador,Y2:220}\r\n    else\r\n    move {name:lineSeparador,Y2:200}\r\n    endif\r\n\tmove {name:txtSeparador,text:\"Piston P$(PARAM_A.VALUE)\"}\r\n\tTERMINATE_VE\r\nendprocedure\r\n\r\nprocedure liberarRestroomBascula\r\n\tassign hecho,0\r\n\t    FOREACH entidad, IN_RESOURCE, zonaBascula\r\n            if (P$hecho==0)\r\n\t    \twake RestroomBascula,P$entidad\r\n            endif\r\n            assign hecho,1\r\n\t\tENDFOREACH\r\nendprocedure\r\n\r\nprocedure moverPiston\r\n    if (P$PARAM_A>X$pesoLimite)\r\n     ASSIGN values, { Device_Piston_Trigger: 1 }\r\n     BRIDGE_WRITE { name:bridge1, VALUES:V$values, TRIGGER:on_write }\r\n\tassign tmp,\"heavy\"\r\n    else \r\n    assign tmp,\"light\"\r\n    endif\r\n\tTERMINATE_VE\r\nendprocedure",
                "descripcion": "<p>In this example, we will see <strong>all the system elements in operation<\/strong>.<\/p>\r\n<p>The model represents an <strong>automated production line<\/strong> where packages arrive one by one, are weighed on a scale, and based on their weight, are diverted to one path or another using a pneumatic piston.<\/p>\r\n<h3><strong>Process Description<\/strong><\/h3>\r\n<ol>\r\n    <li>\r\n    <p><strong>Entry Detection<\/strong><br>\r\n    A door sensor detects the arrival of a new package (symbolizing a product entering the zone).<br>\r\n    Each detection generates a new entity in GPSS-Plus.<\/p>\r\n    <\/li>\r\n    <li>\r\n    <p><strong>Unitary Flow Control<\/strong><br>\r\n    A <em>restroom<\/em> acts as a <strong>unitary releaser<\/strong>, allowing packages to pass one at a time toward the scale.<br>\r\n    The next package only advances once the previous one has finished weighing.<\/p>\r\n    <\/li>\r\n    <li>\r\n    <p><strong>Weighing<\/strong><br>\r\n    Upon reaching the scale, the entity activates the sensor (<code>Device_Scale_Trigger = 1<\/code>).<br>\r\n    When the weight stabilizes, the system assigns the read value to the entity.<\/p>\r\n    <\/li>\r\n    <li>\r\n    <p><strong>Classification<\/strong><br>\r\n    If the weight exceeds a threshold (<code>pesoLimite<\/code>), the piston is activated (<code>Device_Piston_Trigger = 1<\/code>), diverting the package to the heavy zone.<br>\r\n    If not, it continues straight to the light zone.<\/p>\r\n    <\/li>\r\n    <li>\r\n    <p><strong>Synchronization with Physical Actuators<\/strong><br>\r\n    The piston retracts automatically.<br>\r\n    GPSS-Plus <strong>subscribes to the piston state (<code>Device_Piston_IsExtended<\/code>)<\/strong> to know when it is ready for the next cycle.<\/p>\r\n    <\/li>\r\n<\/ol>\r\n<p><b>System Architecture:<\/b><\/p>\r\n<pre>\r\n[Door Sensor]  -> generates entity\r\n         ↓\r\n [Unitary Releaser]\r\n         ↓\r\n       [Scale]  <-> OPC-UA Device_Scale_Weight\r\n         ↓\r\n   [Separator \/ Piston]\r\n         ↓\r\n [Light Exit] \/ [Heavy Exit]\r\n<\/pre>",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            },
            {
                "id": "356",
                "nombre": "Downloads and Installation of BRIDGER Components",
                "texto": "<p>To run the most advanced examples and connect GPSS-Plus with the real world, you will need to <strong>install your own middleware.js<\/strong> and, optionally, the <strong>virtual OPC-UA device<\/strong> and <strong>microcontroller firmwares<\/strong>.<\/p>\r\n<hr>\r\n<p><a href=\"https:\/\/gpss-plus.com\/BRIDGER\/middleware_v_1.03.zip\"><b>middleware.js<\/b><\/a><b>&nbsp;: Version 1.03<\/b><\/p>\r\n<p>The <em>middleware<\/em> acts as an intermediate layer between GPSS-Plus and physical sensors or actuators.<br>\r\nIt must run in a <strong>Node.js<\/strong> environment with secure communication (<strong>HTTPS \/ WSS<\/strong>).<\/p>\r\n<h4><strong>Prerequisites<\/strong><\/h4>\r\n<ul>\r\n    <li>Node.js version 18 or higher.<\/li>\r\n    <li>Valid SSL certificates (required for the secure channel).<\/li>\r\n    <li>Network connectivity between GPSS-Plus and the OPC-UA or MQTT devices.<\/li>\r\n<\/ul>\r\n<p><b>Certificate Installation<\/b><\/p>\r\n<p>Depending on whether you run it on a private network or a public domain, there are two options:<\/p>\r\n<h4><strong>a) Local Environment – using mkcert<\/strong><\/h4>\r\n<p>Ideal for testing on internal networks.<\/p>\r\n<p>Example for mkcert on Debian:<\/p>\r\n<pre>\r\n# Create a DNS entry in your domain pointing to your local IP. Example:\r\nip11.yourdomain.com -> 192.168.1.11\r\n\r\n# Install the libnss3-tools package\r\nsudo apt install libnss3-tools\r\n\r\n# Download mkcert\r\nwget https:\/\/github.com\/FiloSottile\/mkcert\/releases\/latest\/download\/mkcert-v1.4.4-linux-arm\r\n\r\nmv mkcert-v1.4.4-linux-arm \/usr\/local\/bin\/mkcert\r\nchmod +x \/usr\/local\/bin\/mkcert\r\n\r\n# Install the root certificate\r\nmkcert -install\r\n\r\n# Create the certificate for your specific subdomain:\r\nmkcert ip11.yourdomain.com 192.168.1.11\r\n\r\n# Move certificates to a standard location:\r\nmkdir -p \/etc\/ssl\/localcerts\r\nmv ip11.yourdomain.com+1.pem \/etc\/ssl\/localcerts\/\r\nmv ip11.yourdomain.com+1-key.pem \/etc\/ssl\/localcerts\/\r\n<\/pre>\r\n<h4><strong>b) Public Server – using Let’s Encrypt<\/strong><\/h4>\r\n<p>On servers accessible from the Internet, use real certificates from Let's Encrypt.<\/p>\r\n<p><b>Edit middleware.js<\/b><\/p>\r\n<p>Edit the <b>middleware.js<\/b> file to include the certificate paths:<\/p>\r\n<pre>\r\nconst certOptions = {\r\n    cert: fs.readFileSync(\"\/etc\/letsencrypt\/live\/PATH_CHAIN\/fullchain.pem\"),\r\n    key: fs.readFileSync(\"\/etc\/letsencrypt\/live\/PATH_PRIVKEY\/privkey.pem\")\r\n};<\/pre>\r\n<p>Run the installation of required libraries and start the service:<\/p>\r\n<pre>\r\nnpm install express ws cors aedes node-opcua mysql2 serialport mqtt\r\nnode middleware.js<\/pre>\r\n<hr>\r\n<p><a href=\"https:\/\/gpss-plus.com\/BRIDGER\/OPC-UA-virtual_v_1.0.zip\">Virtual OPC-UA<\/a> : Version 1.0<\/p>\r\n<p>This virtual OPC-UA server simulates a set of sensors and actuators, ideal for development and testing without physical hardware.<\/p>\r\n<pre>\r\nnpm install\r\nnode index.js<\/pre>\r\n<p>Expected output: <code>OPC-UA running: opc.tcp:\/\/your.domain:4840<\/code><\/p>\r\n<hr>\r\n<p><a href=\"https:\/\/gpss-plus.com\/BRIDGER\/firmware_ESP32.c\">Firmware for ESP32<\/a> :&nbsp;Version 1.0<\/p>\r\n<p>Basic firmware for <strong>ESP32<\/strong> microcontrollers, designed to send temperature and humidity via <strong>MQTT<\/strong>.<\/p>\r\n<ul>\r\n    <li>DHT11 \/ DHT22 sensor reading.<\/li>\r\n    <li>Periodic publication to MQTT topics.<\/li>\r\n    <li>Compatible with the middleware.js <em>broker<\/em>.<\/li>\r\n<\/ul>\r\n<hr>\r\n<p><a href=\"https:\/\/gpss-plus.com\/BRIDGER\/firmware_ESP8266.c\">Firmware for ESP8266<\/a> :&nbsp;Version 1.0<\/p>\r\n<p>Alternative simpler firmware that allows toggling an LED and reading DHT sensors via MQTT.<\/p>",
                "descripcion": "",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            },
            {
                "id": "378",
                "nombre": "BRIDGE_CALL: Remote Method Execution",
                "texto": "SYSTEM {TYPE:OPTIONS, REAL_TIME:1}\r\nSYSTEM {TYPE:PRE_RUN,TRIGGER:PRE_RUN}\r\n\r\ninitial txt_error,\" \"\r\n\r\nGraphic {Type:TEXT,Name:Text1,X:295,Y:123}\r\nGraphic {Type:TEXT,Name:Text2,X:295,Y:95}\r\nGraphic {Type:TEXT,Name:Text3,X:295,Y:66}\r\nGraphic {Type:TEXT,Name:Text4,X:295,Y:35}\r\nGraphic {Type:TEXT,Name:TextError,X:192,Y:478,Text:\"On error....\"}\r\n\r\nRestRoom {name:esperaCall,x:543,y:488}\r\n\r\nInitial options,{user:\"user\", pass:\"1234\"}\r\n\r\nBRIDGER {NAME:bridge1,X:542,Y:434\r\n\t,SERVER:\"wss:\/\/your-domain.com:3000\"\r\n\t,CLIENT:\"opc.tcp:\/\/your-domain.com:4840\"\r\n    ,OPTIONS:V$options\r\n    ,on_error:bridge1_on_error\r\n    }\r\n\r\nPOSITION {NAME:POS1,X:183,Y:300}\r\nPOSITION {NAME:POS2,X:422,Y:300}\r\nPOSITION {NAME:POS3,X:704,Y:300}\r\n\r\nSTART 10\r\n\r\nPROCEDURE PRE_RUN\r\n    ; Subscriptions to monitor network or system errors\r\n\tBRIDGE_SUBSCRIPTION { NAME: bridge1, VARIABLE: \"HTTP_Request_Error\", TRIGGER: bridge1_on_error }\r\n\tBRIDGE_SUBSCRIPTION { NAME: bridge1, VARIABLE: \"Topics_CurrentTime\", TRIGGER: on_clock }\r\n\r\n    ; Reading a file from the remote File System (FS)\r\n \tASSIGN params, [{}] \r\n\tBRIDGE_CALL {name:bridge1, trigger:on_read_file, params:V$params, method:\"Methods_FS_Read\"}\r\n\r\n    ; External API request via HTTP\r\n    ASSIGN params, [{ \"method\": \"GET\", \"params\": { \"name\": \"Antonio\" } }]\r\n    BRIDGE_CALL { name:bridge1, trigger:on_http, params:V$params, method:\"Methods_HTTP_Request\" }\r\n\r\n\tTERMINATE_VE\r\nENDPROCEDURE 1\r\n\r\nGENERATE 3,0,0,10 {NAME:GEN1,X:59,Y:300}\r\n\tADVANCE 3,0 {TO:POS1}\r\n    ; Call a calculation method (Sum) on the server\r\n\tASSIGN params, [{ \"Num1\": (D$N), \"Num2\": (0) }]\r\n\tBRIDGE_CALL {name:bridge1, trigger:on_call, params:V$params, method:\"Methods_Do_Sum\"}\r\n    \r\n    ; Asynchronous synchronization: the entity waits for the response\r\n    rest esperaCall\r\n    mod {subtitle:\"Sum: P$(suma)\"}\r\n\t\r\n    ADVANCE 4,4 {TO:POS2}\r\n\tASSIGN params, [{ \"Num1\": (D$N), \"Num2\": (D$N) }]\r\n\tBRIDGE_CALL {name:bridge1, trigger:on_call, params:V$params, method:\"Methods_Do_Sum\"}\r\n    rest esperaCall\r\n    mod {subtitle:\"Sum2: P$(suma)\"}\r\n    ADVANCE 4,4 {TO:POS3}\r\nENDGENERATE 1\r\n\r\n; --- Callback Procedures ---\r\nprocedure on_clock\r\n    move {name:Text2,TEXT:\"Server Time: P$(PARAM_A.VALUE)\"}\r\n\tTERMINATE_VE\r\nendprocedure\r\n\r\nprocedure on_read_file\r\n    move {name:Text3,TEXT:\"File Content: P$(PARAM_A.VALUE)\"}\r\n\tTERMINATE_VE\r\nendprocedure\r\n\r\nprocedure on_http\r\n    move {name:Text4,TEXT:\"HTTP Response: P$(PARAM_A.VALUE.message)\"}\r\n\tTERMINATE_VE\r\nendprocedure\r\n\r\nprocedure on_call\r\n\tmove {name:Text1,TEXT:\"Remote Sum: P$(PARAM_A.sum) Entity: P$(PARAM_B)\"}\r\n\tassign suma,P$(PARAM_A.sum),P$(PARAM_B)\r\n    ; Wake the specific entity that made the call\r\n    wake esperaCall,-1,P$(PARAM_B)\r\n\tTERMINATE_VE\r\nendprocedure\r\n\r\nprocedure bridge1_on_error\r\n\tsavevalue txt_error,\"X$txt_error\\nP$(PARAM_A.VALUE)\"\r\n    move {name:TextError,TEXT:\"X$txt_error\"}\r\n\tTERMINATE_VE\r\nendprocedure",
                "descripcion": "<p>While <code>BRIDGE_READ<\/code> and <code>BRIDGE_WRITE<\/code> are limited to handling simple data variables, <code>BRIDGE_CALL<\/code> allows GPSS-Plus to execute <strong>remote methods or functions<\/strong> defined in the middleware or industrial devices.<\/p>\r\n<p>This capability is essential for tasks that go beyond pure simulation, such as:<\/p>\r\n<ul>\r\n    <li>Accessing external databases or the server's File System (FS).<\/li>\r\n    <li>Making HTTP requests to third-party APIs (checking weather, prices, real-time stock).<\/li>\r\n    <li>Executing complex algorithms or heavy mathematical operations outside the simulation engine.<\/li>\r\n<\/ul>\r\n<h3><strong>Asynchronous Synchronization (Rest\/Wake Pattern)<\/strong><\/h3>\r\n<p>Since these calls occur over the network, the response is not instantaneous. To prevent an entity from proceeding before receiving the result, the <strong>Rest\/Wake<\/strong> pattern is used:<\/p>\r\n<ol>\r\n    <li>The entity triggers <code>BRIDGE_CALL<\/code>.<\/li>\r\n    <li>Immediately after, it enters a wait state using <code>rest esperaCall<\/code>.<\/li>\r\n    <li>When the <code>trigger<\/code> procedure receives the server's response, it identifies the entity via <code>P$(PARAM_B)<\/code> and releases it with <code>wake<\/code>.<\/li>\r\n<\/ol>\r\n<p>This mechanism allows for realistic modeling of <strong>network latencies<\/strong> and asynchronous processing in industrial systems.<\/p>",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            },
            {
                "id": "339",
                "nombre": "IoT with MQTT",
                "texto": "SYSTEM {TYPE:PRE_RUN,TRIGGER:PRE_RUN}\r\nSYSTEM {TYPE:OPTIONS, REAL_TIME:1}\r\n\r\n\r\nInitial options,{  }\r\n\r\nBRIDGER {NAME:bridge1,X:733,Y:556\r\n\t,SERVER:\"wss:\/\/yourdomain.com:3000\"\r\n\t,CLIENT:\"mqtt:\/\/localhost\"\r\n    ,OPTIONS:V$options\r\n    ,on_error:bridge1_on_error\r\n    }\r\n\r\n\r\nPOSITION {NAME:POS1,X:101,Y:378}\r\n\r\nPOSITION {NAME:POS2,X:143,Y:115}\r\n\r\n\r\nGraphic {NAME:txtSubscribeL,Type:TEXT,X:394,Y:465,Text:\"On SUBS\"}\r\nGraphic {NAME:txtSubscribeH,Type:TEXT,X:394,Y:435,Text:\"On SUBS\"}\r\nGraphic {NAME:txtSubscribeT,Type:TEXT,X:394,Y:405,Text:\"On SUBS\"}\r\nGraphic {NAME:txtSubscribeS,Type:TEXT,X:394,Y:375,Text:\"On SUBS\"}\r\n\r\nGraphic {NAME:TextBrowse,Type:TEXT,X:116,Y:283,Text:\"On Browse\"}\r\nGraphic {NAME:TextWrite,Type:TEXT,X:391,Y:59,Text:\"On Write\"}\r\nGraphic {NAME:TextError,Type:TEXT,X:424,Y:582,Text:\"Error\"}\r\n\r\n\r\nSTART 10\r\n\r\n;*****************************************************\r\n\r\nPROCEDURE PRE_RUN\r\n    BRIDGE_SUBSCRIPTION { NAME: bridge1\r\n\t, VARIABLE: \"devices\/elprimero\/sensor\/humidity\"\r\n    , TRIGGER: on_humidity \r\n    }\r\n    BRIDGE_SUBSCRIPTION { NAME: bridge1\r\n\t, VARIABLE: \"devices\/elprimero\/sensor\/lux\"\r\n    , TRIGGER: on_luz \r\n    }\r\n    BRIDGE_SUBSCRIPTION { NAME: bridge1\r\n\t, VARIABLE: \"devices\/elprimero\/sensor\/temperature\"\r\n    , TRIGGER: on_temperature \r\n    }\r\n    BRIDGE_SUBSCRIPTION { NAME: bridge1\r\n\t, VARIABLE: \"devices\/elprimero\/status\"\r\n    , TRIGGER: on_status \r\n    }\r\n\r\n; No output for MQTT\r\nBRIDGE_BROWSE {name:bridge1, trigger:on_BROWSE }\r\n\r\n\r\n \r\n\tTERMINATE_VE\r\nENDPROCEDURE\r\n\r\n;*****************************************************\r\nGENERATE 5,0 {NAME:GEN1,X:91,Y:547}\r\n\r\nADVANCE 5,0 {TO:POS1,flow:1}\r\n\r\n\r\nif (D$N% 2== 1)\r\nASSIGN values, {\"devices\/elprimero\/commands\/led\": \"on\"}\r\nBRIDGE_WRITE { name:bridge1, VALUES:V$values ,TRIGGER:on_write}\r\nelse\r\nASSIGN values, {\"devices\/elprimero\/commands\/led\": \"off\"}\r\nBRIDGE_WRITE { name:bridge1, VALUES:V$values ,TRIGGER:on_write}\r\nendif\r\n\r\nADVANCE 5,0 {TO:POS2,flow:1}\r\n\r\nENDGENERATE 1\r\n;----------------------------------------------------------------------------\r\nprocedure on_read\r\n    move {name:TextRead,TEXT:\"WIFI: P$(PARAM_A)\"}\r\n\tTERMINATE_VE\r\nendprocedure\r\n\r\nprocedure bridge1_on_error\r\n    move {name:TextError,TEXT:\"P$PARAM_A\"}\r\n\tTERMINATE_VE\r\nendprocedure\r\n;-------------------------\r\nprocedure on_write\r\nmove {name:TextWrite,TEXT:\"WRITE T:AC1$: P$(PARAM_A.devices\/elprimero\/commands\/led)\"}\r\n\tTERMINATE_VE\r\nendprocedure\r\n\r\n\r\n\r\nprocedure on_luz\r\n\tmove {name:txtSubscribeL,text:\"Subs LUX P$(PARAM_A.VALUE)\"}\r\n\tTERMINATE_VE\r\nendprocedure\r\n\r\nprocedure on_humidity\r\n\tmove {name:txtSubscribeH,text:\"Subs HUM P$(PARAM_A.VALUE)\"}\r\n\tTERMINATE_VE\r\nendprocedure\r\n\r\nprocedure on_temperature\r\n\tmove {name:txtSubscribeT,text:\"Subs TEM P$(PARAM_A.VALUE)\"}\r\n\tTERMINATE_VE\r\nendprocedure\r\n\r\n\r\n\r\nprocedure on_status\r\n\tmove {name:txtSubscribeS,text:\"Subs STA P$(PARAM_A.VALUE)\"}\r\n\tTERMINATE_VE\r\nendprocedure\r\n\r\n\r\n\r\n\r\n\r\n\r\nprocedure on_BROWSE\r\n   move {name:TextBrowse,text:\"on_BROWSE P$(PARAM_A)\"}\r\n\tTERMINATE_VE\r\nendprocedure\r\n",
                "descripcion": "<p>The MQTT communication protocol is a standard for IoT devices.<\/p>\r\n<p>It works through \"topics\", similar to social media tags. A device like a thermometer sends the obtained temperature without knowing who will request or read it.<\/p>\r\n<p>Therefore, an \"MQTT broker\" is required to constantly listen to what the sensors send and be ready to transmit it to whoever needs it.<\/p>\r\n<p>While a standard broker is Mosquitto, <b>middleware.js<\/b> incorporates a very similar functionality.<\/p>\r\n<p>So we return to the same system architecture:<\/p>\r\n<p>GPSS-Plus &lt;-&gt; (middleware.js + MQTT broker) &lt;-&gt; device<\/p>\r\n<p><b>At this point, we move on to programming and using extra hardware.<\/b><\/p>\r\n<p>Don't worry too much; it would be advisable to have some basic knowledge of C programming, but in general, it is enough to ask your favorite AI to build what you need.<\/p>\r\n<p>We are going to program an ESP8266 microcontroller with WIFI to manage:<\/p>\r\n<ul>\r\n    <li>A BH1750 light sensor<\/li>\r\n    <li>A DHT22 humidity and temperature sensor<\/li>\r\n    <li>Turning an LED on and off (protected by a resistor).<\/li>\r\n<\/ul>\r\n<p>For this, we will use these hardware elements and software to flash the ESP8266 firmware.<\/p>\r\n<p>A simple one is \"Arduino IDE\", which contains all the necessary libraries.<\/p>\r\n<p>A quick roadmap to follow is:<\/p>\r\n<ul>\r\n    <li>1.- Obtain the hardware.<\/li>\r\n    <li>2.- Download Arduino IDE.<\/li>\r\n    <li>3.- Install the necessary driver to connect your device via USB simulating a serial port.<\/li>\r\n    <li>4.- Compile the firmware's C code in Arduino IDE (available in the downloads chapter).<\/li>\r\n    <li>5.- Upload it to the device through Arduino IDE.<\/li>\r\n    <li>6.- Send your WIFI credentials and the broker's IP through the serial console.<\/li>\r\n    <li>7.- Run GPSS-Plus and watch the real temperature and humidity data while toggling the LED.<\/li>\r\n<\/ul>\r\n<p>In the example, we can see how the three standard MQTT options are performed:<\/p>\r\n<ul>\r\n    <li>Subscribing to a sensor (reading humidity).<\/li>\r\n    <li>Writing to a command (turning on an LED).<\/li>\r\n    <li>Checking status (Last Will and Testament - LWT).<\/li>\r\n<\/ul>\r\n<p>Note: The WRITE check (\"OK\" response) is something reported by the BRIDGER at the network layer, not the end device itself.<\/p>",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            },
            {
                "id": "329",
                "nombre": "Virtual OPC-UA Device Reference",
                "texto": "SYSTEM {TYPE:PRE_RUN,TRIGGER:PRE_RUN}\r\n\r\nOPC {NAME:opc1,X:100,Y:121,visible:1, TYPE:REAL,\r\n    CLIENT:\"opc.tcp:\/\/192.168.1.10:4840\"}\r\n\r\nPOSITION {NAME:POS1,X:251,Y:335}\r\nPOSITION {NAME:POS2,X:469,Y:341}\r\n\r\nGraphic {NAME:Text1,Type:TEXT,X:425,Y:314,Text:\"Entity\"}\r\nGraphic {NAME:Text2,Type:TEXT,X:424,Y:124,Text:\"Data\"}\r\nGraphic {NAME:Text3,Type:TEXT,X:425,Y:514,Text:\"Write Status\"}\r\nGraphic {NAME:Text4,Type:TEXT,X:115,Y:398,Text:\"Door Sensor\"}\r\n\r\ninitial nAgente,0\r\nSTART 500\r\n\r\n;*****************************************************\r\n\r\nPROCEDURE PRE_RUN\r\n    OPC_SUBSCRIPTION { NAME: opc1\r\n        , VARIABLE: \"PIDControl_CurrentTemperature\"\r\n        , TRIGGER: on_subscription \r\n        }\r\n    OPC_SUBSCRIPTION { NAME: opc1\r\n        , VARIABLE: \"Sensor_Door_IsOpen\"\r\n        , TRIGGER: door_opened \r\n        }\r\n\tTERMINATE_VE\r\nENDPROCEDURE 1\r\n\r\n;*****************************************************\r\nGENERATE 0,0,0,0 {NAME:GEN1,X:43,Y:300}\r\n\r\nif (D$N==1)\r\n    ASSIGN values, { PIDCONTROL_SETPOINT: 10 }\r\n    OPC_WRITE { NAME: opc1, VALUES: V$values ,async:1,trigger:on_write}\r\nendif\r\n\r\nOPC_READ {name:opc1, savevalue:temperature  }\r\n\r\nmove {name:Text1,TEXT:\"READ Result: X$(temperature.Sensor_Proximity_DistanceInCm)\"}\r\n\t\r\nADVANCE 20,0 {TO:pos1}\r\n\t\r\nENDGENERATE 1\r\n\r\nprocedure on_subscription\r\n    move {name:Text2,TEXT:\"Subscription AC1$:\\n P$PARAM_A \\N P$PARAM_B P$PARAM_C\"}\r\n    TERMINATE_VE\r\nendprocedure\r\n\r\nprocedure on_write\r\n    move {name:Text3,TEXT:\"Write AC1$:\\n P$PARAM_A \\N P$PARAM_B P$PARAM_C\"}\r\n\tTERMINATE_VE\r\nendprocedure\r\n\r\nprocedure door_opened\r\n    move {name:Text4,TEXT:\"DOOR AC1$ ; P$PARAM_A\"}\r\n    if (P$(PARAM_A.value)==1)\r\n    \tNEW GEN1\r\n    endif\r\n\tTERMINATE_VE\r\nendprocedure",
                "descripcion": "<h3>OPC-UA Virtual Device Manual<\/h3>\r\n<p>This document describes the virtual devices and sensors simulated by the <strong>Virtual OPC-UA Plant<\/strong> server. This server is ideal for testing logic before deploying to real industrial PLCs.<\/p>\r\n\r\n<h2>1. PIDControl<\/h2>\r\n<p>Simulates a PID temperature control loop. Useful for testing <code>OPC_WRITE<\/code> by changing setpoints.<\/p>\r\n<ul>\r\n    <li><code>PIDControl_CurrentTemperature<\/code>: Current temperature (read-only)<\/li>\r\n    <li><code>PIDControl_Setpoint<\/code>: Target temperature (read-write)<\/li>\r\n    <li><code>PIDControl_PIDOutput<\/code>: PID output signal (read-only)<\/li>\r\n<\/ul>\r\n\r\n<h2>2. Sensor_Door & Motion<\/h2>\r\n<p>Simulates physical access sensors.<\/p>\r\n<ul>\r\n    <li><code>Sensor_Motion_Detected<\/code>: Boolean indicating motion (read-only)<\/li>\r\n    <li><code>Sensor_Door_IsOpen<\/code>: Boolean indicating if the door is open (read-write)<\/li>\r\n<\/ul>\r\n\r\n<h2>3. Environmental & Proximity Sensors<\/h2>\r\n<p>A collection of read-only sensors for monitoring conditions.<\/p>\r\n<ul>\r\n    <li><code>Sensor_Humidity_Value<\/code>: Humidity level in %<\/li>\r\n    <li><code>Sensor_Proximity_Distance<\/code>: Distance to object in cm<\/li>\r\n    <li><code>Sensor_Light_Lux<\/code>: Light level in lux<\/li>\r\n    <li><code>Sensor_Gas_Concentration<\/code>: Gas concentration in ppm<\/li>\r\n    <li><code>Sensor_Vibration_Level<\/code>: Vibration intensity<\/li>\r\n    <li><code>Sensor_Smoke_Detected<\/code>: Boolean presence of smoke<\/li>\r\n<\/ul>\r\n\r\n<h2>4. System Status<\/h2>\r\n<ul>\r\n    <li><code>Sensor_Battery_Level<\/code>: Battery level in %<\/li>\r\n    <li><code>Sensor_Network_Strength<\/code>: Signal strength (0-100)<\/li>\r\n    <li><code>System_PowerStatus_IsPowered<\/code>: Boolean power status<\/li>\r\n<\/ul>\r\n<hr>\r\n<p><strong>Note:<\/strong> Writable variables are intended for use with commands such as <code>OPC_WRITE<\/code>. Changes in these variables may trigger logic updates in the virtual plant simulation.<\/p>",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            }
        ]
    },
    {
        "id": "399",
        "nombre": "",
        "texto": "",
        "descripcion": "",
        "parametros": null,
        "parametros_json": null,
        "ejemplo": null,
        "hijos": [
            {
                "id": "400",
                "nombre": "",
                "texto": "",
                "descripcion": "",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            },
            {
                "id": "401",
                "nombre": "",
                "texto": "",
                "descripcion": "",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            },
            {
                "id": "402",
                "nombre": "",
                "texto": "",
                "descripcion": "",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            },
            {
                "id": "403",
                "nombre": "",
                "texto": "",
                "descripcion": "",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            },
            {
                "id": "404",
                "nombre": "",
                "texto": "",
                "descripcion": "",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            },
            {
                "id": "405",
                "nombre": "",
                "texto": "",
                "descripcion": "",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": []
            }
        ]
    },
    {
        "id": "308",
        "nombre": "Spin-offs",
        "texto": "",
        "descripcion": "",
        "parametros": null,
        "parametros_json": null,
        "ejemplo": null,
        "hijos": [
            {
                "id": "270",
                "nombre": "User Interface-Model UI",
                "texto": "",
                "descripcion": "",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": [
                    {
                        "id": "271",
                        "nombre": "Interactive UI: Declarative Interface Example",
                        "texto": ";========== DECLARATIVE UI ==========\r\nUI {TYPE: BUTTON, id:botonA, TEXT: \"Launch Entity A\", LABEL: \"Button A\", TRIGGER: lanzarA}\r\nUI {TYPE: BUTTON, id:botonB, TEXT: \"Launch Entity B\", LABEL: \"Factory Reset\", TRIGGER: lanzarB}\r\n\r\nUI {TYPE: INPUT, ID: unInput, LABEL: \"Name\", VALUE: \"Alice\", TRIGGER: capturarInput}\r\nUI {\r\n  TYPE: SLIDER, ID: unSlider, LABEL: \"Speed\",\r\n  VALUE: 1, MIN: 0.1, MAX: 2, STEP: 0.1,\r\n  TRIGGER: capturarInput\r\n}\r\nUI {TYPE: SELECT, id:unSelect, LABEL: \"Mode\", OPTIONS: \"Normal,Advanced,Turbo\", TRIGGER: capturarInput}\r\nUI {TYPE: CHECKBOX, id:unCheck, LABEL: \"Activate Turbo\", VALUE: 1, TRIGGER: capturarInput}\r\nUI {TYPE: RADIO, id:unRadio, LABEL: \"Color\", OPTIONS: \"Red,Green,Blue\", TRIGGER: capturarInput}\r\n\r\n;========== GRAPHICS ==========\r\nGRAPHIC {NAME:infoTexto, TYPE:TEXT, X:400, Y:100, TEXT:\"Waiting...\"}\r\nGRAPHIC {NAME:infoDato, TYPE:TEXT, X:400, Y:130, TEXT:\"No value yet\"}\r\n\r\n;========== POSITIONS AND ANIMATION ==========\r\nPOSITION {NAME:ENTRADA, X:200, Y:220}\r\nPOSITION {NAME:SALIDA, X:500, Y:220}\r\n\r\nSTART 100\r\n;-----------------------------------------------------------------\r\n\r\nGENERATE 0,0,0,0 {NAME:GEN_A, X:102,Y:161,ECOLOR:#0099ff}\r\nADVANCE 10,0 {TO:ENTRADA}\r\nADVANCE 10,0 {TO:SALIDA}\r\nTERMINATE 1\r\n\r\nGENERATE 0,0,0,0 {NAME:GEN_B, X:104,Y:406,ECOLOR:#ff9900}\r\nADVANCE 10,0 {TO:ENTRADA}\r\nADVANCE 10,0 {TO:SALIDA}\r\nSET_UI unSlider, 1.5\r\nSET_UI unInput, \"Path B Finished\"\r\nSET_UI unSelect, \"Turbo\"\r\nSET_UI unRadio, \"Blue\"\r\nSET_UI unCheck, 1\r\n\r\nTERMINATE 1\r\n\r\n;========== PROCEDURES ==========\r\nPROCEDURE lanzarA\r\n  NEW GEN_A\r\n  TERMINATE\r\nENDPROCEDURE 1\r\n\r\nPROCEDURE lanzarB\r\n  NEW GEN_B\r\n  TERMINATE\r\nENDPROCEDURE 1\r\n\r\nPROCEDURE capturarInput\r\n  MOVE {NAME:infoTexto, TEXT:\"ID = PP$A\"}\r\n  MOVE {NAME:infoDato, TEXT:\"VALUE = PP$B\"}\r\n\r\n  ; Example: if specific ID is interacted with, update UI from GPSS\r\n  IF \"botonA\",==,\"PP$A\"\r\n    SET_UI velSlider, 1.5\r\n  ENDIF\r\n\r\n  TERMINATE\r\nENDPROCEDURE 1",
                        "descripcion": "<p>This example demonstrates the use of all available UI element types in GPSS-Plus.<\/p>\r\n<p>By declaring <strong>UI blocks<\/strong>, a floating window is automatically created containing the defined controls (buttons, inputs, sliders, etc.). Each control has a <strong>TRIGGER<\/strong>, which executes when the user interacts with it. The trigger launches a virtual entity that carries the interaction data and can act upon the model.<\/p>\r\n<p>Additionally, GPSS can modify control values in real-time using the <strong>SET_UI<\/strong> command, allowing for two-way synchronization between the simulation state and the user interface.<\/p>\r\n<p><strong>Key Features:<\/strong><\/p>\r\n<ul>\r\n  <li><strong>Declarative Design:<\/strong> No complex coding required to build control panels.<\/li>\r\n  <li><strong>Interactive Triggers:<\/strong> Use <code>PP$A<\/code> to get the element ID and <code>PP$B<\/code> for its value.<\/li>\r\n  <li><strong>Dynamic Feedback:<\/strong> Update the UI from within the simulation logic to show status changes.<\/li>\r\n<\/ul>",
                        "parametros": null,
                        "parametros_json": null,
                        "ejemplo": null,
                        "hijos": []
                    }
                ]
            },
            {
                "id": "226",
                "nombre": "Behavior Functions",
                "texto": "",
                "descripcion": "",
                "parametros": null,
                "parametros_json": null,
                "ejemplo": null,
                "hijos": [
                    {
                        "id": "255",
                        "nombre": "Behavior Functions: The Power of Interpolation",
                        "texto": "",
                        "descripcion": "<h3>Behavior Functions: High-Level Abstraction<\/h3>\r\n<p>Behavior Functions (BF) represent a leap in simulation efficiency, allowing you to model complex systems (like an entire factory or workshop) as a single mathematical entity based on previously obtained knowledge.<\/p>\r\n\r\n<h4>The Problem: The Simulation Collapse<\/h4>\r\n<p>Imagine you have simulated 'Workshop X' (5 employees, 2 lifts) and 'Workshop Y' (8 employees, 3 lifts) thousands of times to understand their exit rates. Now you are asked to simulate a network of 100 workshops, each with different configurations. Simulating every single internal process for all 100 workshops would cause a computational collapse.<\/p>\r\n\r\n<h4>The Solution: Behavior Functions<\/h4>\r\n<p>Instead of re-simulating the internal logic, we use the results of our previous simulations to define a <b>Behavior Pattern<\/b>. GPSS-Plus can then interpolate between known data points to predict the behavior of a configuration you haven't even simulated yet.<\/p>\r\n\r\n<h4>Implementation Example:<\/h4>\r\n<p>First, we define known data points for our behavior (e.g., employees, lifts, customers -> mean time, sigma):<\/p>\r\n<code>GFunction {behavior: BF_Workshops, Name:fW1, p0:5, p1:2, p2:10, a:1, b:22, Sigma1:2.2, Sigma2:3.2}<\/code>\r\n<code>GFunction {behavior: BF_Workshops, Name:fW2, p0:6, p1:2, p2:10, a:1, b:19, Sigma1:2.2, Sigma2:3.1}<\/code>\r\n\r\n<p>Now, to simulate a new workshop with <b>4 employees, 2 lifts, and 4 customers<\/b>, we simply call:<\/p>\r\n<code>ADVANCE BF$(BF_Workshops, 4, 2, 4)<\/code>\r\n\r\n<p>GPSS-Plus will automatically:<\/p>\r\n<ol>\r\n    <li>Search for the closest behavior definitions.<\/li>\r\n    <li>Interpolate the parameters (mean, sigma).<\/li>\r\n    <li>Dynamically generate a customized Gaussian function for that specific entity.<\/li>\r\n<\/ol>\r\n\r\n<h4>Key Benefits:<\/h4>\r\n<ul>\r\n    <li><b>Computational Efficiency:<\/b> Simulate large-scale networks without the overhead of micro-simulations.<\/li>\r\n    <li><b>Knowledge Reuse:<\/b> Turn previous simulation reports into active, reusable code.<\/li>\r\n    <li><b>Versatility:<\/b> Applicable to times, costs, failure rates, or any analyzed metric.<\/li>\r\n<\/ul>",
                        "parametros": null,
                        "parametros_json": null,
                        "ejemplo": null,
                        "hijos": []
                    },
                    {
                        "id": "257",
                        "nombre": "First Application: Behavior Functions in Action",
                        "texto": "SYSTEM {TYPE:OPTIONS,Speed:5}\r\n\r\nGraphic {NAME:Text1,Type:TEXT,X:230,Y:496,Text:\"FN$gName1: b=20 \/ sigma1=2.5 \/ sigma2=2.5\"}\r\n\r\nGraphic {NAME:Text2,Type:TEXT,X:349,Y:100,Text:\"BF$(tramo1D 30): b=60 \/ sigma1=3.5 \/ sigma2=4.5 (interpolated)\"}\r\n\r\nGraphic {NAME:Text3,Type:TEXT,X:523,Y:397,Text:\"BF$(tramo1D 15): b=30 \/ sigma1=2.75 \/ sigma2=3 (interpolated)\"}\r\n\r\nFacility {NAME:VENTANILLA1,X:233,Y:444,E_BIN_start:0,E_BIN_SIZE:1,E_BIN_COUNT:80,capacity:30}\r\nFacility {NAME:VENTANILLA2,X:352,Y:152,E_BIN_start:0,E_BIN_SIZE:1,E_BIN_COUNT:80,capacity:30}\r\nFacility {NAME:VENTANILLA3,X:523,Y:354,E_BIN_start:0,E_BIN_SIZE:1,E_BIN_COUNT:80,capacity:30}\r\n\r\nPOSITION {NAME:POS1,X:708,Y:268}\r\n\r\n; Behavior definitions: P0 represents the configuration parameter (e.g., number of workers)\r\nFunction {behavior: tramo1D, type: GAUSS, p0:10, Name:gName1, a:1, b:20, Sigma1:2.5, Sigma2:2.5}\r\nFunction {behavior: tramo1D, type: GAUSS, p0:20, Name:gName2, a:1, b:40, Sigma1:3.0, Sigma2:3.5}\r\n\r\nSTART 2000\r\n\r\n;*****************************************************\r\nGENERATE 2,0,0,0 {NAME:GEN1,X:56,Y:319}\r\n\r\nADVANCE 30,10 {TO:VENTANILLA1}\r\n\r\nSEIZE VENTANILLA1\r\nADVANCE FN$gName1           ; Traditional fixed function call\r\nRELEASE VENTANILLA1\r\n\r\nADVANCE 20,10 {TO:VENTANILLA2}\r\n\r\nSEIZE VENTANILLA2\r\nADVANCE BF$(tramo1D,30)      ; Dynamic call: P0=30 (extrapolated)\r\nRELEASE VENTANILLA2\r\n\r\nADVANCE 20,10 {TO:VENTANILLA3}\r\n\r\nSEIZE VENTANILLA3\r\nADVANCE BF$(tramo1D,15)      ; Dynamic call: P0=15 (interpolated)\r\nRELEASE VENTANILLA3\r\n\r\nADVANCE 20,0 {TO:POS1}\r\n\r\nTERMINATE 1",
                        "descripcion": "<p>In this first practical example, we apply the <strong>Behavior Functions (BF$)<\/strong> concept in its simplest form: a single dimension of interpolation.<\/p>\r\n<p>Instead of defining an exact function for every possible scenario, we define a few known behavior points and let GPSS-Plus calculate the rest.<\/p>\r\n\r\n<h4>The Behavior Logic: \"tramo1D\"<\/h4>\r\n<p>We have two studied cases mapped to the behavior name \"tramo1D\":<\/p>\r\n<ul>\r\n    <li><strong>Case P0=10:<\/strong> Resulted in <code>b:20, Sigma1:2.5, Sigma2:2.5<\/code><\/li>\r\n    <li><strong>Case P0=20:<\/strong> Resulted in <code>b:40, Sigma1:3.0, Sigma2:3.5<\/code><\/li>\r\n<\/ul>\r\n<p>Imagine P0 is the number of employees. If we want to simulate a workshop with <b>15 employees<\/b> (P0=15), GPSS-Plus performs a linear interpolation. Since 15 is exactly between 10 and 20, the resulting Gaussian parameters will be <code>b=30, sigma1=2.75, sigma2=3<\/code>.<\/p>\r\n\r\n<h4>Implementation in the Model:<\/h4>\r\n<ol>\r\n    <li><strong>Fixed Call:<\/strong> <code>ADVANCE FN$gName1<\/code> uses the standard static definition.<\/li>\r\n    <li><strong>Interpolated Call:<\/strong> <code>ADVANCE BF$(tramo1D, 15)<\/code> creates a dynamic distribution based on the midpoint.<\/li>\r\n    <li><strong>Extrapolated Call:<\/strong> <code>ADVANCE BF$(tramo1D, 30)<\/code> projects the behavior beyond the original samples.<\/li>\r\n<\/ol>\r\n<p>The resulting statistical reports will show service curves centered exactly at 20, 30, and 60 respectively, proving the mathematical accuracy of the dynamic generator.<\/p>",
                        "parametros": null,
                        "parametros_json": null,
                        "ejemplo": null,
                        "hijos": []
                    },
                    {
                        "id": "259",
                        "nombre": "Multi-Parameter Interpolation (2D\/3D Surfaces)",
                        "texto": "SYSTEM {TYPE:OPTIONS,Speed:5}\r\n\r\nQUEUER {NAME:TRAMO1,X:66,Y:350,E_BIN_start:0,E_BIN_SIZE:1,E_BIN_COUNT:180}\r\nQUEUER {NAME:TRAMO2,X:276,Y:554,E_BIN_start:0,E_BIN_SIZE:1,E_BIN_COUNT:180}\r\nQUEUER {NAME:TRAMO3,X:664,Y:360,E_BIN_start:0,E_BIN_SIZE:1,E_BIN_COUNT:180}\r\n\r\nPOSITION {NAME:POS1,X:115,Y:92}\r\nPOSITION {NAME:POS2,X:146,Y:449}\r\nPOSITION {NAME:POS3,X:432,Y:506}\r\nPOSITION {NAME:POS4,X:756,Y:33}\r\n\r\n; Behavior definitions (Multi-parameter)\r\n; P0: Distance (km) | P1: Weather (0=Good, 1=Bad)\r\nFunction {behavior: tramo2D, type:GAUSS, p0:50, p1:0, Name:gName1, a:1, b:40, Sigma1:3.0, Sigma2:3.0}\r\nFunction {behavior: tramo2D, type:GAUSS, p0:50, p1:1, Name:gName2, a:1, b:60, Sigma1:5.0, Sigma2:5.0}\r\nFunction {behavior: tramo2D, type:GAUSS, p0:100, p1:0, Name:gName3, a:1, b:80, Sigma1:5.0, Sigma2:5.0}\r\nFunction {behavior: tramo2D, type:GAUSS, p0:100, p1:1, Name:gName4, a:1, b:120, Sigma1:10.0, Sigma2:10.0}\r\n\r\nSTART 2000\r\n\r\n;*****************************************************\r\nGENERATE 2,0,0,0 {NAME:GEN1,X:55,Y:41}\r\n\r\nADVANCE 30,10 {TO:POS1}\r\n\r\nqueue TRAMO1\r\n; Distance: 60km, Weather: 0.5 (Mixed)\r\nADVANCE BF$(tramo2D, 60, 0.5) {TO:POS2}\r\ndepart TRAMO1\r\n\r\nqueue TRAMO2\r\n; Distance: 55km, Weather: 0.5\r\nADVANCE BF$(tramo2D, 55, 0.5) {TO:POS3}\r\ndepart TRAMO2\r\n\r\nqueue TRAMO3\r\n; Distance: 90km, Weather: 0.5\r\nADVANCE BF$(tramo2D, 90, 0.5) {TO:POS4}\r\ndepart TRAMO3\r\n\r\nTERMINATE 1",
                        "descripcion": "<p>While the previous example used a single parameter, we now move to <strong>multi-dimensional modeling<\/strong>. This allows us to represent much richer and more flexible scenarios.<\/p>\r\n<p>In this case, we simulate three road sections where transit time depends on two variables: <strong>Section Length (P0)<\/strong> and <strong>Weather Conditions (P1)<\/strong>.<\/p>\r\n\r\n<h4>Spatial Interpolation (IDW)<\/h4>\r\n<p>When using multiple parameters, mathematical interpolation is no longer a simple line; it becomes a multidimensional space. GPSS-Plus uses <strong>IDW (Inverse Distance Weighting)<\/strong> techniques to calculate the resulting Gaussian function.<\/p>\r\n<p>This means that for any combination of distance and weather within the pre-calculated margins, GPSS-Plus will automatically generate a tailored time distribution function.<\/p>\r\n\r\n<h4>Why use QUEUERs?<\/h4>\r\n<p>In this model, we don't use FACILITYs (individual resources). Instead, we use <code>ADVANCE<\/code> with <code>QUEUERs<\/code> to collect statistics on the time spent in each section. This approach is ideal for modeling continuous flows like traffic or assembly lines where capacity isn't the primary bottleneck, but environmental conditions are.<\/p>\r\n\r\n<h4>Key Takeaways:<\/h4>\r\n<ul>\r\n    <li><strong>Scalability:<\/strong> You can define as many parameters as needed (P0, P1, P2...).<\/li>\r\n    <li><strong>Non-Linearity:<\/strong> The system predicts complex interactions between variables.<\/li>\r\n    <li><strong>Dynamic Integration:<\/strong> Parameters like 'Weather' could be changed in real-time by a Global Timer or an external API via Bridger.<\/li>\r\n<\/ul>",
                        "parametros": null,
                        "parametros_json": null,
                        "ejemplo": null,
                        "hijos": []
                    },
                    {
                        "id": "256",
                        "nombre": "Behavior Procedures: Encapsulating Complex Logic",
                        "texto": ";SYSTEM {TYPE:OPTIONS,Speed:5}\r\n\r\ninitial tramos, [\r\n\t{ origen:1, destino:2, Km:90, Meteo:0.6 },\r\n\t{ origen:2, destino:3, Km:100, Meteo:0.8 },\r\n\t{ origen:3, destino:4, Km:50, Meteo:1.0 }\r\n]\r\n\r\nGraphic {NAME:Text_0,Type:TEXT,X:219,Y:178,Text:\"Text_0\"}\r\nGraphic {NAME:Text_1,Type:TEXT,X:246,Y:454,Text:\"Text_1\"}\r\nGraphic {NAME:Text_2,Type:TEXT,X:429,Y:354,Text:\"Text_2\"}\r\n\r\nQUEUER {NAME:TRAMO_0,X:66,Y:350,E_BIN_start:0,E_BIN_SIZE:1,E_BIN_COUNT:180}\r\nQUEUER {NAME:TRAMO_1,X:276,Y:554,E_BIN_start:0,E_BIN_SIZE:1,E_BIN_COUNT:180}\r\nQUEUER {NAME:TRAMO_2,X:664,Y:360,E_BIN_start:0,E_BIN_SIZE:1,E_BIN_COUNT:180}\r\n\r\nFacility {NAME:Gas_0,X:215,Y:125,capacity:10,R_BIN_start:0,R_BIN_SIZE:1,R_BIN_COUNT:10}\r\nFacility {NAME:Gas_1,X:245,Y:406,capacity:10,R_BIN_start:0,R_BIN_SIZE:1,R_BIN_COUNT:10}\r\nFacility {NAME:Gas_2,X:434,Y:405,capacity:10,R_BIN_start:0,R_BIN_SIZE:1,R_BIN_COUNT:10}\r\n\r\nPOSITION {NAME:POS_0,X:115,Y:92}\r\nPOSITION {NAME:POS_1,X:146,Y:449}\r\nPOSITION {NAME:POS_2,X:432,Y:506}\r\nPOSITION {NAME:POS_3,X:756,Y:33}\r\n\r\nFunction {behavior: bTramoTiempo, type:GAUSS, p0:50, p1:0, Name:gName1, a:1, b:40, Sigma1:3.0, Sigma2:3.0}\r\nFunction {behavior: bTramoTiempo, type:GAUSS, p0:100, p1:1, Name:gName4, a:1, b:120, Sigma1:10.0, Sigma2:10.0}\r\n\r\nFunction {behavior: bTramoGas, type:POISSON, p0:100, Name:fPoisson1, LAMBDA:0.125} ; 1\/8\r\nFunction {behavior: bTramoGas, type:POISSON, p0:50, Name:fPoisson2, LAMBDA:0.05}   ; 1\/20\r\n\r\nSTART 2000\r\n\r\n;*****************************************************\r\nPROCEDURE TRAMO_BEHAVIOR\r\n    assign nQueuer, \"TRAMO_P$PARAM_A\"\r\n    assign nText, \"Text_P$PARAM_A\"\r\n    assign nGas, \"Gas_P$PARAM_A\"\r\n\r\n    assign Km,X$(tramos.P$PARAM_A.Km)\r\n    assign Meteo,X$(tramos.P$PARAM_A.Meteo)\r\n\r\n    ; Determine if refueling is needed based on Poisson behavior\r\n    assign forceGas,BF$(bTramoGas,P$Km) \r\n    if (P$forceGas>=1)\r\n        move {name:P$nText,text:\"REFUELING P$Km \/ P$Meteo\"}\r\n        ADVANCE 10 {TO:P$nGas}\r\n        seize P$nGas\r\n        ADVANCE 30,0\r\n        release P$nGas\r\n        ADVANCE 10 {TO:\"POS_P$PARAM_A\"}\r\n        move {name:P$nText,text:\" \"}\r\n    endif\r\n\r\n    queue P$nQueuer\r\n    ADVANCE BF$(bTramoTiempo,P$Km,P$Meteo) {TO:\"POS_P$PARAM_B\"}\r\n    depart P$nQueuer\r\nENDPROCEDURE 1\r\n\r\n;*****************************************************\r\nGENERATE 2,0,0,0 {NAME:GEN1,X:55,Y:41,enumber:0}\r\n    ADVANCE 10,2 {TO:POS_0}\r\n    ; Unified calls: logic is hidden inside the procedure\r\n    CALL TRAMO_BEHAVIOR,0,1\r\n    CALL TRAMO_BEHAVIOR,1,2\r\n    CALL TRAMO_BEHAVIOR,2,3\r\nTERMINATE 1",
                        "descripcion": "<p>Behavior Procedures allow you to encapsulate both internal entity behavior (processing times) and external events (machine failures, accidents, refueling) into a single modular block.<\/p>\r\n\r\n<h4>The Logic of the Example<\/h4>\r\n<p>We simulate a road trip divided into sections. For each section, two distinct behaviors are modeled:<\/p>\r\n<ul>\r\n    <li><strong>Main Behavior (Gaussian):<\/strong> The travel time depends on distance (Km) and weather conditions (Meteo).<\/li>\r\n    <li><strong>Secondary Event (Poisson):<\/strong> The probability of needing to refuel depends on the distance traveled. A Poisson lambda of 1\/10 means that, on average, 1 out of 10 vehicles will stop at the gas station.<\/li>\r\n<\/ul>\r\n\r\n<h4>Encapsulation via CALL<\/h4>\r\n<p>By using <code>CALL TRAMO_BEHAVIOR, origin, destination<\/code>, the model remains clean and readable. The procedure automatically:<\/p>\r\n<ol>\r\n    <li>Retrieves section data from the <code>SAVEVALUE<\/code> array.<\/li>\r\n    <li>Calculates if a refueling event occurs using <code>BF$(bTramoGas)<\/code>.<\/li>\r\n    <li>Manages the resources (Gas Stations) and statistics (Queuers) dynamically.<\/li>\r\n    <li>Applies the interpolated travel time using <code>BF$(bTramoTiempo)<\/code>.<\/li>\r\n<\/ol>\r\n<p>This approach is perfect for building large-scale digital twins where specific components (like workshops, road sections, or machines) have complex but repeatable behaviors.<\/p>",
                        "parametros": null,
                        "parametros_json": null,
                        "ejemplo": null,
                        "hijos": []
                    }
                ]
            }
        ]
    },
    {
        "id": "363",
        "nombre": "Acknowledgments",
        "texto": "<h3 data-path-to-node=\"3\"><b data-path-to-node=\"3\" data-index-in-node=\"0\">Acknowledgments<\/b><\/h3>\r\n<p data-path-to-node=\"4\">This project would not have been possible without countless collaborators. My most sincere thanks to:<\/p>\r\n<ul>\r\n    <li>Geoffrey Gordon (Classic GPSS): The genius behind the General Purpose Simulation System. Thank you for laying the foundations of discrete event simulation and for teaching us that the world can be understood through blocks, transactions, and pure logic. This evolution has been carried out with utmost respect and admiration.<\/li>\r\n    <li>Math.js: The engine within the engine. Without its computational power, there would be no solver, no mathematical translator, no derivatives, and no SNAs... It is truly impressive to see such a selfless display of genius. It is the mathematical soul of this entire project.<\/li>\r\n    <li>Bootstrap, CodeMirror, three.js: For forming the interface; providing the visual structure and an intuitive, readable experience.<\/li>\r\n    <li>The AIs: For acting as those \"interns\" with inexhaustible capacity and amazing precision. They have been the perfect co-pilot throughout the entire development, proving that artificial intelligence is an impressive force multiplier.<\/li>\r\n    <li>Those who put up with us: For always being by our side while we lock ourselves away in front of the screen or tell them theories they don't understand as if they were interested.<\/li>\r\n<\/ul>\r\n<p data-path-to-node=\"5,3,0\">Antonio S&aacute;nchez and the rest of the team. January 2026<\/p>",
        "descripcion": "",
        "parametros": "",
        "parametros_json": "",
        "ejemplo": "",
        "hijos": []
    }
]