PureBasic, OGRE und Shaderprogrammierung

Hier kannst du häufig gestellte Fragen/Antworten und Tutorials lesen und schreiben.
DarkDragon
Beiträge: 6267
Registriert: 29.08.2004 08:37
Computerausstattung: Hoffentlich bald keine mehr
Kontaktdaten:

PureBasic, OGRE und Shaderprogrammierung

Beitrag von DarkDragon »

Vorab: Ich bin es nicht gewohnt lange Texte zu schreiben! Dieser Beitrag ist wohl einer der längsten, die ich hier im Forum und in den früheren Foren jemals verfasst habe. :oops:

Wie in einem anderen Thema schon angekündigt habe ich eine kurze Einführung zum Thema "Shader und PureBasic" geschrieben. Sie deckt natürlich nicht alles ab, da das Thema ziemlich komplex ist und ich neben dem Studium kaum Zeit hierfür finde. So wird HLSL nicht allzu genau erklärt, aber die Zusammenhänge zwischen den Material-Skripte, PureBasic und OGRE sollten daraus ersichtlicher werden. Am Ende wird man ein Programm haben, welches durch einen Shader eine animierte Textur auf der Oberfläche eines Würfels generiert. Einige Erklärungen habe ich in die Kommentare innerhalb der Quelltexte geschrieben, da dort die Zusammenhänge besser ersichtlich sind.

Download Version


Einführend: Wie funktionieren Shader?

Es gibt drei Arten von Shadern: Geometrie-, Vertex- und Fragmentshader. Geometrieshader erzeugen globale Geometriekomplexe und können beispielsweise zum Instanzieren von Modellen verwendet werden. Auf sie werden wir in diesem Tutorial nicht genauer eingehen. Vertexshader betrachten immer nur einen Eckpunkt (Vertex) in der Szene und können keine neuen Eckpunkte oder Flächen entstehen lassen. Sie sind sozusagen ein Callback, der alle Vertexattribute (Position, Texturkoordinaten, Normalen, Tangenten, Materialeigenschaften, ...) entgegennimmt und dann etwas relativ Entwickler-abhängiges zurückgibt. Diese Rückgabe wird ganz allgemein zwischen den Eckpunkten durch baryzentrische Koordinaten interpoliert und es entstehen sogenannte Fragmente. Ein Fragment beschreibt einen Bildpunkt hinsichtlich mehrerer Aspekte, nicht nur die Farbe. Diese werden dem Fragmentshader übergeben und es wird eigentlich wieder ein Fragment ausgegeben (bestehend aus Tiefenwert und Farbe), doch wir beschränken uns auf die Farbe. Ursprünglich konnten nur Fragmentshader auf Texturen zugreifen, aber mittlerweile können Vertexshader das auch. Shader ersetzen die Fixed-Function Pipeline. D.h. die Beleuchtung, Nebel, materielle Einflüsse, ... werden nurnoch über die Shader berechnet. Will man teile der Fixed-Function Pipeline darin haben, so muss man diese selbst berechnen.
Bild


Shader in PureBasic

PureBasic hat leider keine eigenen Funktionen Shader direkt in ein Material einzubinden. Jedoch gibt es ja noch die Material-Skripte (Endung: ".material"; Kann mit einem Texteditor geöffnet werden). Hierzu empfehle ich das OGRE-Manual. Einige Modelleditoren erstellen auch schon ein Grundgerüst für ein OGRE-Material-Skript. Das Modell muss auf jeden Fall mit dem Material-Skript in Verbindung gebracht werden. Dies geschieht über den Namen des Materials. Nicht der Dateiname ist wichtig, sondern der Name in der Definition des Materials:
material Materialname
{
...
}
Dieser Name steht dann auch irgendwo in der Modelldatei (Endung: ".mesh") und sofern man dem Entity kein anderes Material zuweist und es mit CreateEntity(..., ..., #PB_Material_None) erstellt wird dieses Material verwendet. Vor PB 4.60 gab es aber keine Möglichkeit einem Entity ein anderes Material zuzuweisen, welches in einem Skript definiert wurde, sondern lediglich die PureBasic Standardmaterialien. Seit PB 4.60 gibt es jedoch GetScriptMaterial(), welches hierbei Abhilfe schaffen soll.
Zum ersten Test habe ich einen einfachen Würfel mit einem Material und einer Textur mit Milkshape3D erstellt. Man sollte darauf achten "Export Materials" anzukreuzen beim Exportieren ins OGRE Mesh Format.
Bild
Mein Material heißt "CubeMaterial". Die ".mesh" und ".material" Datei packen wir in unser 3D-Archiv, welches wir im PureBasic Code bestimmen (Ich nehme den Unterordner "data/"). Das anfängliche Material-Skript sollte ungefähr so aussehen:

Code: Alles auswählen

material CubeMaterial
{
  technique
  {
    pass
    {
      ambient 0.2 0.2 0.2 1
      diffuse 0.8 0.8 0.8 1

      texture_unit
      {
        texture font.png -1
      }
    }
  }
}

PureBasic Code

Wenn wir nun das ganze mit PureBasic OGRE anzeigen wollen brauchen wir einen Code ähnlich diesem:

Code: Alles auswählen

; Einfaches Check-Makro
Macro Check(Status, Error, EndProgram = 1)
  If Not Status
    MessageRequester("ERROR", Error)
    CompilerIf EndProgram
      End
    CompilerEndIf
  EndIf
EndMacro

; Initialisiere die 3D Engine, die Sprite-Library und die Tastatursteuerung
Check(InitEngine3D(), "InitEngine3D failed.")
Check(InitSprite(), "InitSprite failed.")
Check(InitKeyboard(), "InitKeyboard failed.")

; Wir nehmen den ersten Desktop zur Bestimmung der Auflösung
Check(ExamineDesktops(), "ExamineDesktops failed.")

; Der Unterordner "data" soll all unsere Modelle, Texturen, Material-Skripte, ... enthalten.
Add3DArchive("data", #PB_3DArchive_FileSystem)

; Öffne den Screen
Check(OpenScreen(DesktopWidth(0), DesktopHeight(0), 32, "Shadertest"), "OpenScreen failed.")

; Lade alle Material-Skripte
Parse3DScripts()

; Lade den Würfel
Check(LoadMesh(0, "Cube.mesh"), "LoadMesh failed")

; Erzeuge ein Entity von dem Würfel und nimm das entsprechende Materialskript
Check(CreateEntity(0, MeshID(0), #PB_Material_None), "CreateEntity failed")

; Hier bitte eigene Werte verwenden, dass der Würfel korrekt angezeigt wird
ScaleEntity(0, 0.1, 0.1, 0.1)
RotateEntity(0, 90.0, 0.0, 180.0)

; Erstelle eine Kamera
Check(CreateCamera(0, 0, 0, 100, 100), "CreateCamera failed")

; Verschiebe sie, aber lasse sie zur Nullposition schauen
CameraLocate(0, -5, 5, -10)
CameraLookAt(0, 0, 0, 0)

; Hauptschleife
Repeat
  ClearScreen(0)
  RenderWorld() ; rendert alles
  FlipBuffers()
  
  ; Prüfe auf Tastatureingaben
  ExamineKeyboard()
Until KeyboardPushed(#PB_Key_Escape)
End
Weiter werde ich auf diesen Code nicht eingehen, da er ziemlich einfach gehalten ist.


Material-Skript bearbeiten

Um einen HLSL Shader mit dem Material zu verknüpfen muss das Material-Skript etwas angepasst werden. Zunächst deklarieren wir den Vertexshader völlig unabhängig vom Material an sich. Deshalb muss dieser auch außerhalb vom Material-Block stehen. Wir starten mit dem Block-Schlüsselwort "vertex_program", gefolgt von einem Namen des Shaders und dem Typ. In diesem Block muss auf jeden Fall der Dateiname (Schlüsselwort: "source") des Shaders stehen, der Einsprungspunkt (Schlüsselwort: "entry_point", nur HLSL) und die Shaderversion (Schlüsselwort: "target"). Später werden wir im Shaderquelltext allerdings noch die finale Transformationsmatrix benötigen. Sonst bleiben die Vertizen genau so wie im Modell gespeichert und rühren sich nie vom Fleck, egal welche Befehle (ScaleEntity, MoveEntity, RotateEntity, EntityLocate, CameraLocate, ...) verwendet werden um das Objekt zu bewegen. Aus diesem Grund definieren wir mit dem Block-Schlüsselwort "default_params" und dem Schlüsselwort "param_named_auto" darin noch einen Parameter für den Shader, der automatisch von OGRE ausgefüllt wird. Die Parameter, die dort definiert werden könnte man auch durch PureBasic beeinflussen, doch bis zum heutigen Tag fehlen immernoch die nötigen Funktionen dazu.

Code: Alles auswählen

// Vertexshader
// Name: cubeTestVS
// Typ:  hlsl
vertex_program cubeTestVS hlsl
{
  // Datei: cubetest_vs.hlsl enthält den Quelltext des Vertexshaders
  source cubetest_vs.hlsl

  // Funktion, die zuerst aufgerufen wird: main
  entry_point main

  // Shaderversion
  target vs_3_0
  
  default_params
  {
    // Vertexshader sind auch für die korrekte Transformation der Vertizen zuständig.
    // Aus diesem Grund benötigen wir die WorldViewProj-Matrix.
    
    param_named_auto worldViewProj      worldviewproj_matrix
  }
}
Beim Fragmentshader sieht es fast gleich aus. Nur das Schlüsselwort "vertex_program" ist nun "fragment_program" und in "default_params" wird ein anderer Parameter definiert:

Code: Alles auswählen

// Fragmentshader
// Name: cubeTestPS
// Typ:  hlsl
fragment_program cubeTestPS hlsl
{
  // Datei: cubetest_ps.hlsl enthält den Quelltext des Fragmentshaders
  source cubetest_ps.hlsl
  
  // Funktion, die zuerst aufgerufen wird:
  entry_point main

  // Shaderversion
  target ps_3_0
  
  default_params
  {
    // Die Variable currentTime ist im Shader und enthält den OGRE eigenen Zeitwert
    param_named_auto currentTime time
  }
}
Die Variable "currentTime" im Fragmentshader-Quelltext wird dann eine Zeitangabe enthalten. Um diese 2 Blöcke, die außerhalb vom "material"-Block stehen mit dem "material"-Block zu verknüpfen müssen nun zwei weitere Schlüsselwörter her: "vertex_program_ref" und "fragment_program_ref". Beide werden gefolgt von dem Shader-Namen, also "cubeTestVS" und "cubeTestPS". Hier das komplette Material-Skript:

Code: Alles auswählen

// Vertexshader
// Name: cubeTestVS
// Typ:  hlsl
vertex_program cubeTestVS hlsl
{
  // Datei: cubetest_vs.hlsl enthält den Quelltext des Vertexshaders
  source cubetest_vs.hlsl

  // Funktion, die zuerst aufgerufen wird: main
  entry_point main

  // Shaderversion
  target vs_3_0
  
  default_params
  {
    // Vertexshader sind auch für die korrekte Transformation der Vertizen zuständig.
    // Aus diesem Grund benötigen wir die WorldViewProj-Matrix.
    
    param_named_auto worldViewProj      worldviewproj_matrix
  }
}

// Fragmentshader
// Name: cubeTestPS
// Typ:  hlsl
fragment_program cubeTestPS hlsl
{
  // Datei: cubetest_ps.hlsl enthält den Quelltext des Fragmentshaders
  source cubetest_ps.hlsl
  
  // Funktion, die zuerst aufgerufen wird:
  entry_point main

  // Shaderversion
  target ps_3_0
  
  default_params
  {
    // Die Variable currentTime ist im Shader und enthält den OGRE eigenen Zeitwert
    param_named_auto currentTime time
  }
}

material CubeMaterial
{
  technique
  {
    pass
    {
      ambient 0.2 0.2 0.2 1
      diffuse 0.8 0.8 0.8 1

      texture_unit
      {
        texture font.png -1
      }

      // Ein Verweis auf die 2 Shaderprogramme:
      vertex_program_ref cubeTestVS
      {
      }

      fragment_program_ref cubeTestPS
      {
      }
    }
  }
}

Vertex-Shader:

Zu HLSL gibt es genügend eigene Tutorials für den Einstieg. Die wichtigste Information ist: die Vertexattributeingabe erfolgt durch Parameter der Einsprungsfunktion und Konstanten (Uniforms), die vom Material-Skript oder später vllt. auch PureBasic Code gesetzt werden können, müssen als solche mit dem "uniform" Schlüsselwort definiert werden. Die Datentypen umfassen Skalare (float, int, ...), Vektoren (float2, float3, ..., auch Farbwerte sind als Vektoren gegeben mit dem komponentenweisen Definitionsbereich 0.0 bis 1.0), Matrizen (float3x3, ...) und Texturen (sampler). Alles, was der Vertexshader zurückgibt wird automatisch auf der Polygonoberfläche interpoliert und an den Fragmentshader übergeben (vgl. Phong vs. Gouraud Schattierung). Die Rückgabe erfolgt über das TEXCOORD0..n Register in HLSL (vgl. GLSL über varyings). Außerdem muss auf jeden Fall die projizierte Position des aktuellen Vertex zurückgegeben werden.
Zunächst benötigen wir eine Struktur, die den Aufbau unseres Rückgabewerts aus der "main" Einsprungsfunktion definiert:

Code: Alles auswählen

struct VS_RESULT {
  float2 texCoord:  TEXCOORD0;
  float4 pos:       POSITION;
};
Wir werden also die Texturkoordinate und die projizierte Position zurückgeben. Als Eingabewerte wollen wir die Position des aktuellen Vertex (roh, d.h. ohne Vorverarbeitung) und die Texturkoordinate. Folglich sieht unser Funktionskopf so aus:

Code: Alles auswählen

VS_RESULT main(float4 pos: POSITION,
               float2 texCoord0: TEXCOORD0
              )
Um die Position des Vertex aber mit den Transformationen und Projektionen zu verrechnen benötigen wir noch die WorldViewProjection-Matrix von OGRE. Diese haben wir so im OGRE Material-Skript deklariert:
param_named_auto worldViewProj worldviewproj_matrix
und genau so ("worldViewProj") muss die Variable auch im Shader heißen. Uniform-Variablen werden außerhalb von Funktionen deklariert. Wir schreiben also

Code: Alles auswählen

uniform float4x4 worldViewProj;
vor die "main"-Funktion. Nun zum Inhalt der "main"-Funktion. Wir werden die WorldViewProj-Matrix auf die Vertexposition multiplizieren (Funktion: mul), und das Resultat davon mit der Texturkoordinate weitergeben. Folglich sieht unser Code so aus:

Code: Alles auswählen

struct VS_RESULT {
  float2 texCoord:  TEXCOORD0;
  float4 pos:       POSITION;
};

uniform float4x4 worldViewProj;

VS_RESULT main(float4 pos: POSITION,
               float2 texCoord0: TEXCOORD0
              )
{
   VS_RESULT result;

   result.pos        = mul(worldViewProj, pos);
   result.texCoord   = texCoord0;
   
   return result;
}

Fragment-Shader:

Da nach einfachen Zeichnen-Befehlen gefragt wurde muss ich leider etwas Vektor-Rechnung (z.B. Lotfußpunkt zwischen Punkt und Gerade) Voraussetzen. Zunächst definieren wir unsere Konstanten. Neben unserer Zeitangabe finden wir hier auch die Zeichensatztextur:

Code: Alles auswählen

sampler fontTexture: register(s0);
uniform float currentTime;
Die Textur wird aus dem Register s0 gelesen, was soviel bedeutet wie der erste Texturlayer in der Menge aller verwendetenen Texturen. Die Zeit wird als float geliefert. Nun werden wir ein paar Funktionen benötigen, die uns etwas arbeit abnehmen. Da wir jedes Fragment unseres Objektes auf dem Bildschirm einzeln berechnen müssen, benötigen wir also eine Feststellung, welche Farbe unser Fragment annehmen soll unter der Bedingung, dass ein bestimmter Text an einer bestimmten Position auf dem Objekt erscheinen soll. Hierzu stehen uns beispielsweise die Texturkoordinaten des aktuellen Fragments auf dem Objekt zur Verfügung. Die genauere Vorgehensweise verdeutlichen die Kommentare im Code sowie dieses Bild:
Bild
Die dazugehörige Funktion lautet also

Code: Alles auswählen

float4 drawChar(float2 texCoord, int character, float2 coords, float2 size)
{
  // Wir setzen den Standard-Rückgabewert auf Schwarz.
  float4 result = float4(0.0f, 0.0f, 0.0f, 1.0f);
  
  // Das Argument texCoord ist die Texturkoordinate unseres aktuellen Fragments,
  // coords die Position unseres Zeichens auf dem Objekt
  // und size die größe des darzustellenden Zeichens.
  // Nun wird texCoord relativ zu dem Bereich gesehen:
  float2 normalizedTexCoord = (texCoord - coords) / size;
  
  // nur wenn normalizedTexCoord im Bereich 0..1 liegt ist das Fragment im Bereich des darzustellenden Zeichens auf dem Objekt.
  if(normalizedTexCoord.x >= 0.0f && normalizedTexCoord.y >= 0.0f && normalizedTexCoord.x < 1.0f && normalizedTexCoord.y < 1.0f)
  {
    // wir haben einen Zeichensatz, der bei 32 (Leerzeichen) anfängt. Daher subtrahiere erstmal die 32 von dem Zeichen
    character -= 32;
    
    // finde die entsprechende Texturkoordinate auf unserem Zeichensatz
    float2 charCoord;

    // 32 Zeichen pro Zeile, 3 Zeilen insgesamt
    charCoord.y = float(character / 32);
    charCoord.x = float(character) - charCoord.y * 32.0f;
    
    charCoord += normalizedTexCoord;
    charCoord *= float2(1.0f / 32.0f, 1.0f / 3.0f);
    
    // gebe den Texturwert zurück
    result = tex2D(fontTexture, charCoord);
  }
  
  return result;
}
Als nächstes wollen wir einen Kreis zeichnen. Hierfür reicht ein Test, ob die Fragment-Texturkoordinate innerhalb des Kreises ist. Wenn ja, gebe Weiß zurück, ansonsten Schwarz:

Code: Alles auswählen

float4 drawCircle(float2 texCoord, float2 center, float radius)
{
  float4 result = float4(0.0f, 0.0f, 0.0f, 1.0f);
  
  // Abstand Texturkoordinate vom Kreiszentrum < Kreisradius?
  if(length(texCoord - center) <= radius)
  {
    result = float4(1.0f, 1.0f, 1.0f, 1.0f);
  }
  return result;
}
Und nun fehlt nurnoch das Zeichnen einer Linie. Hierzu benötigen wir den sogenannten Lotfußpunkt. Das ist der Punkt, mit der kleinsten Euklidschen Distanz des Prüfpunktes zur Geraden und der Vektor zwischen dem Lotfußpunkt und unserem Prüfpunkt ist Senkrecht auf der Geraden. Die Funktion sieht dementsprechend so aus:

Code: Alles auswählen

float4 drawLine(float2 texCoord, float2 start, float2 end, float width)
{
  float4 result = float4(0.0f, 0.0f, 0.0f, 1.0f);

  // Richtung der Geraden
  float2 dir = end - start;
  
  // Verschiebe alles, sodass texCoord auf dem Ursprung liegt
  start -= texCoord;
  
  // Berechne das Lambda der Geradengleichung v = start + lambda * dir, sodass v der [url=http://mathworld.wolfram.com/PerpendicularFoot.html]Lotfußpunkt[/url] ist.
  // Es soll aber immer auf der Geraden bleiben, deshalb darf lambda nur im Bereich 0..1 bleiben.
  
  float lambda = clamp(-1.0f * (start.x*dir.x + start.y*dir.y) / (dir.x * dir.x + dir.y * dir.y), 0.0f, 1.0f);
  
  // Wenn der Abstand des Punktes zu unserer texCoord (nun der Ursprung) kleiner als die Geradenbreite ist, gebe Weiß zurück.
  if(length(start + lambda * dir) <= width)
  {
    result = float4(1.0f, 1.0f, 1.0f, 1.0f);
  }
  return result;
}
Zum Schluss folgt nurnoch der Einsprungspunkt. Hier werden die ganzen Funktionen verwendet, um das komplette Bild auf dem Objekt zusammenzusetzen.

Code: Alles auswählen

// Eingabe: Fragment-Texturkoordinate und Fragment-Position
float4 main(float2 texCoord: TEXCOORD0,
            float4 pos: POSITION
            ) : COLOR0
{
  float weight;
  
  // Hintergrundfarbe: Dunkelblau.
  float4 result = float4(0.0f, 0.0f, 0.1f, 1.0f);
  
  // Wir addieren zunächst die Farbwerte des Kreises, den wir zentriert Zeichnen wollen multipliziert mit Gelb,
  // d.h. wenn drawCircle Weiß zurückgibt wird 100% Gelb daraus und bei Schwarz bleibt es Schwarz.
  result += drawCircle(texCoord, float2(0.5f, 0.5f), 0.3f) * float4(1.0f, 1.0f, 0.0f, 1.0f);
  
  // Für unsere Linie wollen wir nicht die Farbe multipliziert mit Blau addieren,
  // sonst würde Gelb vom Kreis + Blau von der Linie = Weiß ergeben. Wir wollen
  // die Linie komplett in Blau haben.
  // Deshalb nehmen wir die Länge des Farbvektors (außer alpha) als Gewichtung.
  // Das Anhängsel .xyz erstellt aus dem float4 einfach einen float3 Vektor mit
  // den x, y und z Komponenten des ursprünglichen float4 Vektors und schließt
  // somit den Alpha-Wert aus.
  // Die Linie soll im Zentrum anfangen und durch den currentTime-Wert rotieren.
  weight = length(drawLine(texCoord, float2(0.5f, 0.5f), float2(0.5f, 0.5f) + float2(cos(currentTime), sin(currentTime)) * 0.5f, 0.01f).xyz) * 0.5f;
  
  // Wir Gewichten nun Dunkelblau mit weight und den alten result-Wert mit (1.0 - weight)
  result = weight * float4(0.0f, 0.0f, 0.4f, 1.0f) + (1.0 - weight) * result;
  
  // Da wir wissen, dass sich der Text nicht überschneidet, addieren wir
  // einfach die einzelnen Werte von den jeweiligen Zeichen an ihrer
  // jeweiligen Position:
  float4 text = float4(0.0f, 0.0f, 0.0f, 1.0f);
  
  float2 charSize = float2(0.05f, 0.05f);
  
  texCoord -= float2(0.2f, 0.2f);

  text += drawChar(texCoord, 'H', float2(0.00f, 0.0f), charSize);
  text += drawChar(texCoord, 'a', float2(0.05f, 0.0f), charSize);
  text += drawChar(texCoord, 'l', float2(0.10f, 0.0f), charSize);
  text += drawChar(texCoord, 'l', float2(0.15f, 0.0f), charSize);
  text += drawChar(texCoord, 'o', float2(0.20f, 0.0f), charSize);
  text += drawChar(texCoord, ',', float2(0.25f, 0.0f), charSize);
  
  text += drawChar(texCoord, 'P', float2(0.35f, 0.0f), charSize);
  text += drawChar(texCoord, 'B', float2(0.40f, 0.0f), charSize);
  text += drawChar(texCoord, '!', float2(0.45f, 0.0f), charSize);

  // Erstelle wieder einen Gewichtungswert aus text.xyz wie bei der Linie auch:
  weight = length(text.xyz) * 0.5f;
  
  // Und gewichte exakt wie bei der Linie, nur mit Rot statt Dunkelblau:
  result = weight * float4(1.0f, 0.0f, 0.0f, 1.0f) + (1.0 - weight) * result;
  
  // Gebe den Farbwert zurück
  return result;
}
Hier der gesamte Code für den Fragmentshader:

Code: Alles auswählen

sampler fontTexture: register(s0);

uniform float currentTime;

float4 drawChar(float2 texCoord, int character, float2 coords, float2 size)
{
  // Wir setzen den Standard-Rückgabewert auf Schwarz.
  float4 result = float4(0.0f, 0.0f, 0.0f, 1.0f);
  
  // Das Argument texCoord ist die Texturkoordinate unseres aktuellen Fragments,
  // coords die Position unseres Zeichens auf dem Objekt
  // und size die größe des darzustellenden Zeichens.
  // Nun wird texCoord relativ zu dem Bereich gesehen:
  float2 normalizedTexCoord = (texCoord - coords) / size;
  
  // nur wenn normalizedTexCoord im Bereich 0..1 liegt ist das Fragment im Bereich des darzustellenden Zeichens auf dem Objekt.
  if(normalizedTexCoord.x >= 0.0f && normalizedTexCoord.y >= 0.0f && normalizedTexCoord.x < 1.0f && normalizedTexCoord.y < 1.0f)
  {
    // wir haben einen Zeichensatz, der bei 32 (Leerzeichen) anfängt. Daher subtrahiere erstmal die 32 von dem Zeichen
    character -= 32;
    
    // finde die entsprechende Texturkoordinate auf unserem Zeichensatz
    float2 charCoord;

    // 32 Zeichen pro Zeile, 3 Zeilen insgesamt
    charCoord.y = float(character / 32);
    charCoord.x = float(character) - charCoord.y * 32.0f;
    
    charCoord += normalizedTexCoord;
    charCoord *= float2(1.0f / 32.0f, 1.0f / 3.0f);
    
    // gebe den Texturwert zurück
    result = tex2D(fontTexture, charCoord);
  }
  
  return result;
}

float4 drawCircle(float2 texCoord, float2 center, float radius)
{
  float4 result = float4(0.0f, 0.0f, 0.0f, 1.0f);
  
  // Abstand Texturkoordinate vom Kreiszentrum < Kreisradius?
  if(length(texCoord - center) <= radius)
  {
    result = float4(1.0f, 1.0f, 1.0f, 1.0f);
  }
  return result;
}

float4 drawLine(float2 texCoord, float2 start, float2 end, float width)
{
  float4 result = float4(0.0f, 0.0f, 0.0f, 1.0f);

  // Richtung der Geraden
  float2 dir = end - start;
  
  // Verschiebe alles, sodass texCoord auf dem Ursprung liegt
  start -= texCoord;
  
  // Berechne das Lambda der Geradengleichung v = start + lambda * dir, sodass v der [url=http://mathworld.wolfram.com/PerpendicularFoot.html]Lotfußpunkt[/url] ist.
  // Es soll aber immer auf der Geraden bleiben, deshalb darf lambda nur im Bereich 0..1 bleiben.
  
  float lambda = clamp(-1.0f * (start.x*dir.x + start.y*dir.y) / (dir.x * dir.x + dir.y * dir.y), 0.0f, 1.0f);
  
  // Wenn der Abstand des Punktes zu unserer texCoord (nun der Ursprung) kleiner als die Geradenbreite ist, gebe Weiß zurück.
  if(length(start + lambda * dir) <= width)
  {
    result = float4(1.0f, 1.0f, 1.0f, 1.0f);
  }
  return result;
}

// Eingabe: Fragment-Texturkoordinate und Fragment-Position
float4 main(float2 texCoord: TEXCOORD0,
            float4 pos: POSITION
            ) : COLOR0
{
  float weight;
  
  // Hintergrundfarbe: Schwarz.
  float4 result = float4(0.0f, 0.0f, 0.1f, 1.0f);
  
  // Wir addieren zunächst die Farbwerte des Kreises, den wir zentriert Zeichnen wollen multipliziert mit Gelb,
  // d.h. wenn drawCircle Weiß zurückgibt wird 100% Gelb daraus und bei Schwarz bleibt es Schwarz.
  result += drawCircle(texCoord, float2(0.5f, 0.5f), 0.3f) * float4(1.0f, 1.0f, 0.0f, 1.0f);
  
  // Für unsere Linie wollen wir nicht die Farbe multipliziert mit Blau addieren,
  // sonst würde Gelb vom Kreis + Blau von der Linie = Weiß ergeben. Wir wollen
  // die Linie komplett in Blau haben.
  // Deshalb nehmen wir die Länge des Farbvektors (außer alpha) als Gewichtung.
  // Das Anhängsel .xyz erstellt aus dem float4 einfach einen float3 Vektor mit
  // den x, y und z Komponenten des ursprünglichen float4 Vektors und schließt
  // somit den Alpha-Wert aus.
  // Die Linie soll im Zentrum anfangen und durch den currentTime-Wert rotieren.
  weight = length(drawLine(texCoord, float2(0.5f, 0.5f), float2(0.5f, 0.5f) + float2(cos(currentTime), sin(currentTime)) * 0.5f, 0.01f).xyz) * 0.5f;
  
  // Wir Gewichten nun Dunkelblau mit weight und den alten result-Wert mit (1.0 - weight)
  result = weight * float4(0.0f, 0.0f, 0.4f, 1.0f) + (1.0 - weight) * result;
  
  // Da wir wissen, dass sich der Text nicht überschneidet, addieren wir
  // einfach die einzelnen Werte von den jeweiligen Zeichen an ihrer
  // jeweiligen Position:
  float4 text = float4(0.0f, 0.0f, 0.0f, 1.0f);
  
  float2 charSize = float2(0.05f, 0.05f);
  
  texCoord -= float2(0.2f, 0.2f);

  text += drawChar(texCoord, 'H', float2(0.00f, 0.0f), charSize);
  text += drawChar(texCoord, 'a', float2(0.05f, 0.0f), charSize);
  text += drawChar(texCoord, 'l', float2(0.10f, 0.0f), charSize);
  text += drawChar(texCoord, 'l', float2(0.15f, 0.0f), charSize);
  text += drawChar(texCoord, 'o', float2(0.20f, 0.0f), charSize);
  text += drawChar(texCoord, ',', float2(0.25f, 0.0f), charSize);
  
  text += drawChar(texCoord, 'P', float2(0.35f, 0.0f), charSize);
  text += drawChar(texCoord, 'B', float2(0.40f, 0.0f), charSize);
  text += drawChar(texCoord, '!', float2(0.45f, 0.0f), charSize);

  // Erstelle wieder einen Gewichtungswert aus text.xyz wie bei der Linie auch:
  weight = length(text.xyz) * 0.5f;
  
  // Und gewichte exakt wie bei der Linie, nur mit Rot statt Dunkelblau:
  result = weight * float4(1.0f, 0.0f, 0.0f, 1.0f) + (1.0 - weight) * result;
  
  // Gebe den Farbwert zurück
  return result;
}

Ergebnis

Bild


Erweitertes Thema: Kommunikation zwischen PureBasic und dem Shader

Da PureBasic keine direkten Funktionen zur Verfügung stellt um die Uniform-Variablen zu ändern müssen wir leider einen Umweg über sowas wie Lichtquellen gehen.

Änderungen im PureBasic Code
Wir werden dem Shader die Zeitangabe über die X Position einer Lichtquelle übergeben. Hierzu benötigen wir erstmal eine Lichquelle, die irgendwo am Anfang erstellt wird.

Code: Alles auswählen

; Erstelle eine Lichtquelle zur Kommunikation mit dem Shader (Zeit wird als X-Position übergeben):
Define Time.f

CreateLight(0, 0, Time, 0.0, 0.0)
Unsere Hauptschleife ändern wir wie folgt ab um Interaktion mit ins Spiel zu bekommen:

Code: Alles auswählen

; Hauptschleife
Repeat
  ClearScreen(0)
  RenderWorld() ; rendert alles
  FlipBuffers()
  
  ; Prüfe auf Tastatureingaben
  ExamineKeyboard()
  If KeyboardPushed(#PB_Key_Left)
    Time - 0.025
    LightLocate(0, Time, 0.0, 0.0)
  ElseIf KeyboardPushed(#PB_Key_Right)
    Time + 0.025
    LightLocate(0, Time, 0.0, 0.0)
  EndIf
Until KeyboardPushed(#PB_Key_Escape)
Es findet also lediglich eine Neupositionierung des Lichtes statt um die Variable für den Shader zu ändern.

Änderungen im Material
Die einzige Änderung die wir im Material nun benötigen ist die Quelle für den Wert unserer currentTime Shadervariable:

Code: Alles auswählen

    param_named_auto currentTime light_position 0
Hier wird allerdings nun ein float4 Vektor übergeben bei dem wir nur die erste Komponente benötigen. Aus diesem Grund wird es auch Änderungen am Shader-Quelltext geben.

Änderungen im Shader-Quelltext
Die Variable "currentTime" muss nun als float4 deklariert werden, da die Lichtposition nunmal ein Vektor ist:

Code: Alles auswählen

uniform float4 currentTime;
Eine weitere Änderung betrifft den Zugriff auf die Variable. Statt "currentTime" schreiben wir dort nun "currentTime.x", da wir nur die X-Komponente benötigen:

Code: Alles auswählen

  weight = length(drawLine(texCoord, float2(0.5f, 0.5f), float2(0.5f, 0.5f) + float2(cos(currentTime.x), sin(currentTime.x)) * 0.5f, 0.01f).xyz) * 0.5f;
Das wars auch schon.


-------------------------------------------------------------

Links zum Thema:

HLSL Dokumentation - http://msdn.microsoft.com/en-us/library ... S.85).aspx (14.08.2011)
Writing HLSL Shaders in DirectX9 - http://msdn.microsoft.com/en-us/library ... s.85).aspx (14.08.2011)
OgreManual Inhaltsverzeichnis - http://www.ogre3d.org/docs/manual/manua ... C_Contents (09.08.2011)
OgreManual Material-Skripte - http://www.ogre3d.org/docs/manual/manual_14.html#SEC23 (09.08.2011)
OgreManual Declaring Vertex/Fragment Shaders - http://www.ogre3d.org/docs/manual/manual_18.html#SEC104 (09.08.2011)
Baryzentrische Koordinaten - http://math.fau.edu/Yiu/barycentricpaper.pdf (09.08.2011)
Lotfußpunkt - http://mathworld.wolfram.com/PerpendicularFoot.html (14.08.2011)
Zuletzt geändert von DarkDragon am 25.11.2011 15:26, insgesamt 5-mal geändert.
DarkDragon
Beiträge: 6267
Registriert: 29.08.2004 08:37
Computerausstattung: Hoffentlich bald keine mehr
Kontaktdaten:

Re: PureBasic, OGRE und Shaderprogrammierung

Beitrag von DarkDragon »

Da ich nicht weiß wie lange mein Webspace die Dateien aufbewahren kann habe ich hier alle Dateien mal in einen Selbstextrahierungs-Code verfrachtet:

Code: Alles auswählen

CompilerIf #PB_Unicode = 1
  CompilerError "Please compile in ASCII-mode."
CompilerEndIf

Procedure WriteBase64File(Filename.s, Content.s)
  Protected *Buffer.i
  Protected Size.i
  Protected File.i
  
  File = CreateFile(#PB_Any, Filename)
  If File
    *Buffer = AllocateMemory(Len(Content))
    If *Buffer
      Size = Base64Decoder(@Content, Len(Content), *Buffer, MemorySize(*Buffer))
      
      WriteData(File, *Buffer, Size)
      
      FreeMemory(*Buffer)
    EndIf
    CloseFile(File)
  EndIf
EndProcedure

Procedure.s EnsureEndingSlash(Path.s)
  If Right(Path, 1) <> "/"
    Path + "/"
  EndIf
  
  ProcedureReturn Path
EndProcedure

Define Path.s

Path = ReplaceString(PathRequester("Select an extraction path", ""), "\", "/")

If Path = "" Or MessageRequester("Sure?", "I may overwrite some files or directories inside this folder. Shall I continue?" + #LF$ + Path, #PB_MessageRequester_YesNo) = #PB_MessageRequester_No
  End
EndIf

Path = EnsureEndingSlash(Path)

SetCurrentDirectory(Path)

CreateDirectory(Path + "data")

Define Filename.s
Define FileContent.s
Define ContentBlock.s
Define Blocks.l
Define K.i

Restore FileList

Repeat
  Read.s Filename
  Read.l Blocks
  
  If Filename = "" Or Blocks <= 0
    Break
  EndIf
  
  FileContent = ""
  For K = 1 To Blocks
    Read.s ContentBlock
    FileContent + ContentBlock
  Next K
  
  WriteBase64File(Filename, FileContent)
ForEver

End

DataSection
  FileList:
  
  TestPB:
    Data.s "Test.pb"
    Data.l 24
    Data.s "OyBFaW5mYWNoZXMgQ2hlY2stTWFrcm8NCk1hY3JvIENoZWNrKFN0YXR1cywgRXJyb3IsIEVuZFByb2dyYW0gPSAxKQ0KICBJZiBO"
    Data.s "b3QgU3RhdHVzDQogICAgTWVzc2FnZVJlcXVlc3RlcigiRVJST1IiLCBFcnJvcikNCiAgICBDb21waWxlcklmIEVuZFByb2dyYW0N"
    Data.s "CiAgICAgIEVuZA0KICAgIENvbXBpbGVyRW5kSWYNCiAgRW5kSWYNCkVuZE1hY3JvDQoNCjsgSW5pdGlhbGlzaWVyZSBkaWUgM0Qg"
    Data.s "RW5naW5lLCBkaWUgU3ByaXRlLUxpYnJhcnkgdW5kIGRpZSBUYXN0YXR1cnN0ZXVlcnVuZw0KQ2hlY2soSW5pdEVuZ2luZTNEKCks"
    Data.s "ICJJbml0RW5naW5lM0QgZmFpbGVkLiIpDQpDaGVjayhJbml0U3ByaXRlKCksICJJbml0U3ByaXRlIGZhaWxlZC4iKQ0KQ2hlY2so"
    Data.s "SW5pdEtleWJvYXJkKCksICJJbml0S2V5Ym9hcmQgZmFpbGVkLiIpDQoNCjsgV2lyIG5laG1lbiBkZW4gZXJzdGVuIERlc2t0b3Ag"
    Data.s "enVyIEJlc3RpbW11bmcgZGVyIEF1Zmz2c3VuZw0KQ2hlY2soRXhhbWluZURlc2t0b3BzKCksICJFeGFtaW5lRGVza3RvcHMgZmFp"
    Data.s "bGVkLiIpDQoNCjsgRGVyIFVudGVyb3JkbmVyICJkYXRhIiBzb2xsIGFsbCB1bnNlcmUgTW9kZWxsZSwgVGV4dHVyZW4sIE1hdGVy"
    Data.s "aWFsLVNrcmlwdGUsIC4uLiBlbnRoYWx0ZW4uDQpBZGQzREFyY2hpdmUoImRhdGEiLCAjUEJfM0RBcmNoaXZlX0ZpbGVTeXN0ZW0p"
    Data.s "DQoNCjsg1mZmbmUgZGVuIFNjcmVlbg0KQ2hlY2soT3BlblNjcmVlbihEZXNrdG9wV2lkdGgoMCksIERlc2t0b3BIZWlnaHQoMCks"
    Data.s "IDMyLCAiU2hhZGVydGVzdCIpLCAiT3BlblNjcmVlbiBmYWlsZWQuIikNCg0KOyBMYWRlIGFsbGUgTWF0ZXJpYWwtU2tyaXB0ZQ0K"
    Data.s "UGFyc2UzRFNjcmlwdHMoKQ0KDQo7IExhZGUgZGVuIFf8cmZlbA0KQ2hlY2soTG9hZE1lc2goMCwgIkN1YmUubWVzaCIpLCAiTG9h"
    Data.s "ZE1lc2ggZmFpbGVkIikNCg0KOyBFcnpldWdlIGVpbiBFbnRpdHkgdm9uIGRlbSBX/HJmZWwgdW5kIG5pbW0gZGFzIGVudHNwcmVj"
    Data.s "aGVuZGUgTWF0ZXJpYWxza3JpcHQNCkNoZWNrKENyZWF0ZUVudGl0eSgwLCBNZXNoSUQoMCksICNQQl9NYXRlcmlhbF9Ob25lKSwg"
    Data.s "IkNyZWF0ZUVudGl0eSBmYWlsZWQiKQ0KDQo7IEhpZXIgYml0dGUgZWlnZW5lIFdlcnRlIHZlcndlbmRlbiwgZGFzcyBkZXIgV/xy"
    Data.s "ZmVsIGtvcnJla3QgYW5nZXplaWd0IHdpcmQNClNjYWxlRW50aXR5KDAsIDAuMSwgMC4xLCAwLjEpDQpSb3RhdGVFbnRpdHkoMCwg"
    Data.s "OTAuMCwgMC4wLCAxODAuMCkNCg0KOyBFcnN0ZWxsZSBlaW5lIEthbWVyYQ0KQ2hlY2soQ3JlYXRlQ2FtZXJhKDAsIDAsIDAsIDEw"
    Data.s "MCwgMTAwKSwgIkNyZWF0ZUNhbWVyYSBmYWlsZWQiKQ0KDQo7IFZlcnNjaGllYmUgc2llLCBhYmVyIGxhc3NlIHNpZSB6dXIgTnVs"
    Data.s "bHBvc2l0aW9uIHNjaGF1ZW4NCkNhbWVyYUxvY2F0ZSgwLCAtNSwgNSwgLTEwKQ0KQ2FtZXJhTG9va0F0KDAsIDAsIDAsIDApDQoN"
    Data.s "CjsgSGF1cHRzY2hsZWlmZQ0KUmVwZWF0DQogIENsZWFyU2NyZWVuKDApDQogIFJlbmRlcldvcmxkKCkgOyByZW5kZXJ0IGFsbGVz"
    Data.s "DQogIEZsaXBCdWZmZXJzKCkNCiAgDQogIDsgUHL8ZmUgYXVmIFRhc3RhdHVyZWluZ2FiZW4NCiAgRXhhbWluZUtleWJvYXJkKCkN"
    Data.s "ClVudGlsIEtleWJvYXJkUHVzaGVkKCNQQl9LZXlfRXNjYXBlKQ0KRW5kDQo7IElERSBPcHRpb25zID0gUHVyZUJhc2ljIDQuNjAg"
    Data.s "QmV0YSAzIChXaW5kb3dzIC0geDY0KQ0KOyBDdXJzb3JQb3NpdGlvbiA9IDUzDQo7IEZvbGRpbmcgPSAtDQo7IEVuYWJsZVhQDQo7"
    Data.s "IEV4ZWN1dGFibGUgPSBUZXN0LmV4ZQ=="

    
  CubeMESH:
    Data.s "data/Cube.mesh"
    Data.l 23
    Data.s "ABBbTWVzaFNlcmlhbGl6ZXJfdjEuNDBdCgAwEwYAAAAAQNMBAABDdWJlTWF0ZXJpYWwKACQAAAAAAAABAAIAAQADAAIAAgADAAQA"
    Data.s "AwAFAAQABAAFAAYABQAHAAYABgAHAAAABwABAAAABgAAAAQAAAACAAQAAQAHAAMABwAFAAMAAFDAAQAACAAAAABRRgAAABBREAAA"
    Data.s "AAAAAgABAAAAAAAQURAAAAAAAAIABAAMAAAAEFEQAAAAAAABAAcAGAAAABBREAAAAAAAAgAJACAAAAAAUnABAAAAACwAEFJmAQAA"
    Data.s "AACgwQAAoEEAAKBBAAAAAAAAgD8AAAAAAAAAAAAAgD8AAIA/AAAAAAAAAAAAAKDBAACgwQAAoEEAAAAAAACAvwAAAAAAAAAAAAAA"
    Data.s "AA8seT8AAAAA9etqvgAAoEEAAKBBAACgQQAAAAAAAIA/AAAAAAAAgD8AAIA/Dyx5PwAAAAD162o+AACgQQAAoMEAAKBBAAAAAAAA"
    Data.s "gL8AAAAAAACAPwAAAAAAAIA/AAAAAAAAAAAAAKBBAACgQQAAoMEAAAAAAACAPwAAAAAAAIA/AAAAAAAAgD8AAAAAAAAAAAAAoEEA"
    Data.s "AKDBAACgwQAAAAAAAIC/AAAAAAAAgD8AAIA/Dyx5PwAAAAD162q+AACgwQAAoEEAAKDBAAAAAAAAgD8AAAAAAAAAAAAAAAAPLHk/"
    Data.s "AAAAAPXraj4AAKDBAACgwQAAoMEAAAAAAACAvwAAAAAAAAAAAACAPwAAgD8AAAAAAAAAABBACAAAAAQAAJAiAAAAAACgwQAAoMEA"
    Data.s "AKDBAACgQQAAoEEAAKBBZ5AKQgCgBgAAAACwMAQAAACxKgQAAAAAAAEMAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAACAAAAAAAAAAEA"
    Data.s "AAACAAAAAAAAgAAAAAAAAMhEAAD6xgAAAAAAAAAAAQAAAAMAAAACAAAAAQAAAAMAAAACAAAAAAAAAAAAAAAAAMhEAAD6xgAAAAAA"
    Data.s "AAAAAgAAAAMAAAAEAAAAAgAAAAMAAAAEAAAAAADIRAAAAAAAAAAAAAD6xgAAAAAAAAAAAwAAAAUAAAAEAAAAAwAAAAUAAAAEAAAA"
    Data.s "AADIRAAAAAAAAAAAAAD6xgAAAAAAAAAABAAAAAUAAAAGAAAABAAAAAUAAAAGAAAAAAAAgAAAAIAAAMjEAAD6xgAAAAAAAAAABQAA"
    Data.s "AAcAAAAGAAAABQAAAAcAAAAGAAAAAAAAAAAAAAAAAMjEAAD6xgAAAAAAAAAABgAAAAcAAAAAAAAABgAAAAcAAAAAAAAAAADIxAAA"
    Data.s "AAAAAAAAAAD6xgAAAAAAAAAABwAAAAEAAAAAAAAABwAAAAEAAAAAAAAAAADIxAAAAAAAAAAAAAD6xgAAAAAAAAAABgAAAAAAAAAE"
    Data.s "AAAABgAAAAAAAAAEAAAAAAAAAAAAyEQAAAAAAAD6xgAAAAAAAAAAAAAAAAIAAAAEAAAAAAAAAAIAAAAEAAAAAAAAgAAAyEQAAAAA"
    Data.s "AAD6xgAAAAAAAAAAAQAAAAcAAAADAAAAAQAAAAcAAAADAAAAAAAAAAAAyMQAAAAAAAD6xgAAAAAAAAAABwAAAAUAAAADAAAABwAA"
    Data.s "AAUAAAADAAAAAAAAAAAAyMQAAAAAAAD6xhCx2AEAAAAAAAAAAAAADAAAABIAAAAAAAAABwAAAAAAAAABAAAAAAAAAAEAAAAAAAAA"
    Data.s "AAEAAAABAAAAAgAAAAEAAAACAAAAAAAAAAAJAAAAAgAAAAAAAAACAAAAAAAAAAABAAAACgAAAAEAAAADAAAAAQAAAAMAAAAAAQAA"
    Data.s "AAIAAAADAAAAAgAAAAMAAAACAAAAAAIAAAADAAAAAwAAAAQAAAADAAAABAAAAAACAAAACQAAAAQAAAACAAAABAAAAAIAAAAAAwAA"
    Data.s "AAsAAAADAAAABQAAAAMAAAAFAAAAAAMAAAAEAAAABQAAAAQAAAAFAAAABAAAAAAEAAAABQAAAAUAAAAGAAAABQAAAAYAAAAABAAA"
    Data.s "AAgAAAAGAAAABAAAAAYAAAAEAAAAAAUAAAALAAAABQAAAAcAAAAFAAAABwAAAAAFAAAABgAAAAcAAAAGAAAABwAAAAYAAAAABgAA"
    Data.s "AAcAAAAHAAAAAAAAAAcAAAAAAAAAAAYAAAAIAAAAAAAAAAYAAAAAAAAABgAAAAAHAAAACgAAAAcAAAABAAAABwAAAAEAAAAACAAA"
    Data.s "AAkAAAAAAAAABAAAAAAAAAAEAAAAAAoAAAALAAAABwAAAAMAAAAHAAAAAwAAAAA="
    
  CubeMaterialMATERIAL:
    Data.s "data/CubeMaterial.material"
    Data.l 19
    Data.s "Ly8gVmVydGV4c2hhZGVyDQovLyBOYW1lOiBjdWJlVGVzdFZTDQovLyBUeXA6ICBobHNsDQp2ZXJ0ZXhfcHJvZ3JhbSBjdWJlVGVz"
    Data.s "dFZTIGhsc2wNCnsNCiAgLy8gRGF0ZWk6IGN1YmV0ZXN0X3ZzLmhsc2wgZW50aORsdCBkZW4gUXVlbGx0ZXh0IGRlcyBWZXJ0ZXhz"
    Data.s "aGFkZXJzDQogIHNvdXJjZSBjdWJldGVzdF92cy5obHNsDQoNCiAgLy8gRnVua3Rpb24sIGRpZSB6dWVyc3QgYXVmZ2VydWZlbiB3"
    Data.s "aXJkOiBtYWluDQogIGVudHJ5X3BvaW50IG1haW4NCg0KICAvLyBTaGFkZXJ2ZXJzaW9uDQogIHRhcmdldCB2c18zXzANCiAgDQog"
    Data.s "IGRlZmF1bHRfcGFyYW1zDQogIHsNCiAgICAvLyBWZXJ0ZXhzaGFkZXIgc2luZCBhdWNoIGb8ciBkaWUga29ycmVrdGUgVHJhbnNm"
    Data.s "b3JtYXRpb24gZGVyIFZlcnRpemVuIHp1c3TkbmRpZy4NCiAgICAvLyBBdXMgZGllc2VtIEdydW5kIGJlbvZ0aWdlbiB3aXIgZGll"
    Data.s "IFdvcmxkVmlld1Byb2otTWF0cml4Lg0KICAgIA0KICAgIHBhcmFtX25hbWVkX2F1dG8gd29ybGRWaWV3UHJvaiAgICAgIHdvcmxk"
    Data.s "dmlld3Byb2pfbWF0cml4DQogIH0NCn0NCg0KLy8gRnJhZ21lbnRzaGFkZXINCi8vIE5hbWU6IGN1YmVUZXN0UFMNCi8vIFR5cDog"
    Data.s "IGhsc2wNCmZyYWdtZW50X3Byb2dyYW0gY3ViZVRlc3RQUyBobHNsDQp7DQogIC8vIERhdGVpOiBjdWJldGVzdF9wcy5obHNsIGVu"
    Data.s "dGjkbHQgZGVuIFF1ZWxsdGV4dCBkZXMgRnJhZ21lbnRzaGFkZXJzDQogIHNvdXJjZSBjdWJldGVzdF9wcy5obHNsDQogIA0KICAv"
    Data.s "LyBGdW5rdGlvbiwgZGllIHp1ZXJzdCBhdWZnZXJ1ZmVuIHdpcmQ6DQogIGVudHJ5X3BvaW50IG1haW4NCg0KICAvLyBTaGFkZXJ2"
    Data.s "ZXJzaW9uDQogIHRhcmdldCBwc18zXzANCiAgDQogIGRlZmF1bHRfcGFyYW1zDQogIHsNCiAgICAvLyBEaWUgVmFyaWFibGUgY3Vy"
    Data.s "cmVudFRpbWUgaXN0IGltIFNoYWRlciB1bmQgZW50aORsdCBkZW4gT0dSRSBlaWdlbmVuIFplaXR3ZXJ0DQogICAgcGFyYW1fbmFt"
    Data.s "ZWRfYXV0byBjdXJyZW50VGltZSB0aW1lDQogIH0NCn0NCg0KbWF0ZXJpYWwgQ3ViZU1hdGVyaWFsDQp7DQogIHRlY2huaXF1ZQ0K"
    Data.s "ICB7DQogICAgcGFzcw0KICAgIHsNCiAgICAgIGFtYmllbnQgMC4yIDAuMiAwLjIgMQ0KICAgICAgZGlmZnVzZSAwLjggMC44IDAu"
    Data.s "OCAxDQoNCiAgICAgIHRleHR1cmVfdW5pdA0KICAgICAgew0KICAgICAgICB0ZXh0dXJlIGZvbnQucG5nIC0xDQogICAgICB9DQoN"
    Data.s "CiAgICAgIC8vIEVpbiBWZXJ3ZWlzIGF1ZiBkaWUgMiBTaGFkZXJwcm9ncmFtbWU6DQogICAgICB2ZXJ0ZXhfcHJvZ3JhbV9yZWYg"
    Data.s "Y3ViZVRlc3RWUw0KICAgICAgew0KICAgICAgfQ0KDQogICAgICBmcmFnbWVudF9wcm9ncmFtX3JlZiBjdWJlVGVzdFBTDQogICAg"
    Data.s "ICB7DQogICAgICB9DQogICAgfQ0KICB9DQp9"
    
  cubetest_psHLSL:
    Data.s "data/cubetest_ps.hlsl"
    Data.l 71
    Data.s "c2FtcGxlciBmb250VGV4dHVyZTogcmVnaXN0ZXIoczApOw0KDQp1bmlmb3JtIGZsb2F0IGN1cnJlbnRUaW1lOw0KDQpmbG9hdDQg"
    Data.s "ZHJhd0NoYXIoZmxvYXQyIHRleENvb3JkLCBpbnQgY2hhcmFjdGVyLCBmbG9hdDIgY29vcmRzLCBmbG9hdDIgc2l6ZSkNCnsNCiAg"
    Data.s "Ly8gV2lyIHNldHplbiBkZW4gU3RhbmRhcmQtUvxja2dhYmV3ZXJ0IGF1ZiBTY2h3YXJ6Lg0KICBmbG9hdDQgcmVzdWx0ID0gZmxv"
    Data.s "YXQ0KDAuMGYsIDAuMGYsIDAuMGYsIDEuMGYpOw0KICANCiAgLy8gRGFzIEFyZ3VtZW50IHRleENvb3JkIGlzdCBkaWUgVGV4dHVy"
    Data.s "a29vcmRpbmF0ZSB1bnNlcmVzIGFrdHVlbGxlbiBGcmFnbWVudHMsDQogIC8vIGNvb3JkcyBkaWUgUG9zaXRpb24gdW5zZXJlcyBa"
    Data.s "ZWljaGVucyBhdWYgZGVtIE9iamVrdA0KICAvLyB1bmQgc2l6ZSBkaWUgZ3L232UgZGVzIGRhcnp1c3RlbGxlbmRlbiBaZWljaGVu"
    Data.s "cy4NCiAgLy8gTnVuIHdpcmQgdGV4Q29vcmQgcmVsYXRpdiB6dSBkZW0gQmVyZWljaCBnZXNlaGVuOg0KICBmbG9hdDIgbm9ybWFs"
    Data.s "aXplZFRleENvb3JkID0gKHRleENvb3JkIC0gY29vcmRzKSAvIHNpemU7DQogIA0KICAvLyBudXIgd2VubiBub3JtYWxpemVkVGV4"
    Data.s "Q29vcmQgaW0gQmVyZWljaCAwLi4xIGxpZWd0IGlzdCBkYXMgRnJhZ21lbnQgaW0gQmVyZWljaCBkZXMgZGFyenVzdGVsbGVuZGVu"
    Data.s "IFplaWNoZW5zIGF1ZiBkZW0gT2JqZWt0Lg0KICBpZihub3JtYWxpemVkVGV4Q29vcmQueCA+PSAwLjBmICYmIG5vcm1hbGl6ZWRU"
    Data.s "ZXhDb29yZC55ID49IDAuMGYgJiYgbm9ybWFsaXplZFRleENvb3JkLnggPCAxLjBmICYmIG5vcm1hbGl6ZWRUZXhDb29yZC55IDwg"
    Data.s "MS4wZikNCiAgew0KICAgIC8vIHdpciBoYWJlbiBlaW5lbiBaZWljaGVuc2F0eiwgZGVyIGJlaSAzMiAoTGVlcnplaWNoZW4pIGFu"
    Data.s "ZuRuZ3QuIERhaGVyIHN1YnRyYWhpZXJlIGVyc3RtYWwgZGllIDMyIHZvbiBkZW0gWmVpY2hlbg0KICAgIGNoYXJhY3RlciAtPSAz"
    Data.s "MjsNCiAgICANCiAgICAvLyBmaW5kZSBkaWUgZW50c3ByZWNoZW5kZSBUZXh0dXJrb29yZGluYXRlIGF1ZiB1bnNlcmVtIFplaWNo"
    Data.s "ZW5zYXR6DQogICAgZmxvYXQyIGNoYXJDb29yZDsNCg0KICAgIC8vIDMyIFplaWNoZW4gcHJvIFplaWxlLCAzIFplaWxlbiBpbnNn"
    Data.s "ZXNhbXQNCiAgICBjaGFyQ29vcmQueSA9IGZsb2F0KGNoYXJhY3RlciAvIDMyKTsNCiAgICBjaGFyQ29vcmQueCA9IGZsb2F0KGNo"
    Data.s "YXJhY3RlcikgLSBjaGFyQ29vcmQueSAqIDMyLjBmOw0KICAgIA0KICAgIGNoYXJDb29yZCArPSBub3JtYWxpemVkVGV4Q29vcmQ7"
    Data.s "DQogICAgY2hhckNvb3JkICo9IGZsb2F0MigxLjBmIC8gMzIuMGYsIDEuMGYgLyAzLjBmKTsNCiAgICANCiAgICAvLyBnZWJlIGRl"
    Data.s "biBUZXh0dXJ3ZXJ0IHp1cvxjaw0KICAgIHJlc3VsdCA9IHRleDJEKGZvbnRUZXh0dXJlLCBjaGFyQ29vcmQpOw0KICB9DQogIA0K"
    Data.s "ICByZXR1cm4gcmVzdWx0Ow0KfQ0KDQpmbG9hdDQgZHJhd0NpcmNsZShmbG9hdDIgdGV4Q29vcmQsIGZsb2F0MiBjZW50ZXIsIGZs"
    Data.s "b2F0IHJhZGl1cykNCnsNCiAgZmxvYXQ0IHJlc3VsdCA9IGZsb2F0NCgwLjBmLCAwLjBmLCAwLjBmLCAxLjBmKTsNCiAgDQogIC8v"
    Data.s "IEFic3RhbmQgVGV4dHVya29vcmRpbmF0ZSB2b20gS3JlaXN6ZW50cnVtIDwgS3JlaXNyYWRpdXM/DQogIGlmKGxlbmd0aCh0ZXhD"
    Data.s "b29yZCAtIGNlbnRlcikgPD0gcmFkaXVzKQ0KICB7DQogICAgcmVzdWx0ID0gZmxvYXQ0KDEuMGYsIDEuMGYsIDEuMGYsIDEuMGYp"
    Data.s "Ow0KICB9DQogIHJldHVybiByZXN1bHQ7DQp9DQoNCmZsb2F0NCBkcmF3TGluZShmbG9hdDIgdGV4Q29vcmQsIGZsb2F0MiBzdGFy"
    Data.s "dCwgZmxvYXQyIGVuZCwgZmxvYXQgd2lkdGgpDQp7DQogIGZsb2F0NCByZXN1bHQgPSBmbG9hdDQoMC4wZiwgMC4wZiwgMC4wZiwg"
    Data.s "MS4wZik7DQoNCiAgLy8gUmljaHR1bmcgZGVyIEdlcmFkZW4NCiAgZmxvYXQyIGRpciA9IGVuZCAtIHN0YXJ0Ow0KICANCiAgLy8g"
    Data.s "VmVyc2NoaWViZSBhbGxlcywgc29kYXNzIHRleENvb3JkIGF1ZiBkZW0gVXJzcHJ1bmcgbGllZ3QNCiAgc3RhcnQgLT0gdGV4Q29v"
    Data.s "cmQ7DQogIA0KICAvLyBCZXJlY2huZSBkYXMgTGFtYmRhIGRlciBHZXJhZGVuZ2xlaWNodW5nIHYgPSBzdGFydCArIGxhbWJkYSAq"
    Data.s "IGRpciwgc29kYXNzIHYgZGVyIExvdGZ133B1bmt0IGlzdC4NCiAgLy8gRXMgc29sbCBhYmVyIGltbWVyIGF1ZiBkZXIgR2VyYWRl"
    Data.s "biBibGVpYmVuLCBkZXNoYWxiIGRhcmYgbGFtYmRhIG51ciBpbSBCZXJlaWNoIDAuLjEgYmxlaWJlbi4NCiAgDQogIGZsb2F0IGxh"
    Data.s "bWJkYSA9IGNsYW1wKC0xLjBmICogKHN0YXJ0LngqZGlyLnggKyBzdGFydC55KmRpci55KSAvIChkaXIueCAqIGRpci54ICsgZGly"
    Data.s "LnkgKiBkaXIueSksIDAuMGYsIDEuMGYpOw0KICANCiAgLy8gV2VubiBkZXIgQWJzdGFuZCBkZXMgUHVua3RlcyB6dSB1bnNlcmVy"
    Data.s "IHRleENvb3JkIChudW4gZGVyIFVyc3BydW5nKSBrbGVpbmVyIGFscyBkaWUgR2VyYWRlbmJyZWl0ZSBpc3QsIGdlYmUgV2Vp3yB6"
    Data.s "dXL8Y2suDQogIGlmKGxlbmd0aChzdGFydCArIGxhbWJkYSAqIGRpcikgPD0gd2lkdGgpDQogIHsNCiAgICByZXN1bHQgPSBmbG9h"
    Data.s "dDQoMS4wZiwgMS4wZiwgMS4wZiwgMS4wZik7DQogIH0NCiAgcmV0dXJuIHJlc3VsdDsNCn0NCg0KLy8gRWluZ2FiZTogRnJhZ21l"
    Data.s "bnQtVGV4dHVya29vcmRpbmF0ZSB1bmQgRnJhZ21lbnQtUG9zaXRpb24NCmZsb2F0NCBtYWluKGZsb2F0MiB0ZXhDb29yZDogVEVY"
    Data.s "Q09PUkQwLA0KICAgICAgICAgICAgZmxvYXQ0IHBvczogUE9TSVRJT04NCiAgICAgICAgICAgICkgOiBDT0xPUjANCnsNCiAgZmxv"
    Data.s "YXQgd2VpZ2h0Ow0KICANCiAgLy8gSGludGVyZ3J1bmRmYXJiZTogU2Nod2Fyei4NCiAgZmxvYXQ0IHJlc3VsdCA9IGZsb2F0NCgw"
    Data.s "LjBmLCAwLjBmLCAwLjFmLCAxLjBmKTsNCiAgDQogIC8vIFdpciBhZGRpZXJlbiB6dW7kY2hzdCBkaWUgRmFyYndlcnRlIGRlcyBL"
    Data.s "cmVpc2VzLCBkZW4gd2lyIHplbnRyaWVydCBaZWljaG5lbiB3b2xsZW4gbXVsdGlwbGl6aWVydCBtaXQgR2VsYiwNCiAgLy8gZC5o"
    Data.s "LiB3ZW5uIGRyYXdDaXJjbGUgV2Vp3yB6dXL8Y2tnaWJ0IHdpcmQgMTAwJSBHZWxiIGRhcmF1cyB1bmQgYmVpIFNjaHdhcnogYmxl"
    Data.s "aWJ0IGVzIFNjaHdhcnouDQogIHJlc3VsdCArPSBkcmF3Q2lyY2xlKHRleENvb3JkLCBmbG9hdDIoMC41ZiwgMC41ZiksIDAuM2Yp"
    Data.s "ICogZmxvYXQ0KDEuMGYsIDEuMGYsIDAuMGYsIDEuMGYpOw0KICANCiAgLy8gRvxyIHVuc2VyZSBMaW5pZSB3b2xsZW4gd2lyIG5p"
    Data.s "Y2h0IGRpZSBGYXJiZSBtdWx0aXBsaXppZXJ0IG1pdCBCbGF1IGFkZGllcmVuLA0KICAvLyBzb25zdCB3/HJkZSBHZWxiIHZvbSBL"
    Data.s "cmVpcyArIEJsYXUgdm9uIGRlciBMaW5pZSA9IFdlad8gZXJnZWJlbi4gV2lyIHdvbGxlbg0KICAvLyBkaWUgTGluaWUga29tcGxl"
    Data.s "dHQgaW4gQmxhdSBoYWJlbi4NCiAgLy8gRGVzaGFsYiBuZWhtZW4gd2lyIGRpZSBM5G5nZSBkZXMgRmFyYnZla3RvcnMgKGF132Vy"
    Data.s "IGFscGhhKSBhbHMgR2V3aWNodHVuZy4NCiAgLy8gRGFzIEFuaORuZ3NlbCAueHl6IGVyc3RlbGx0IGF1cyBkZW0gZmxvYXQ0IGVp"
    Data.s "bmZhY2ggZWluZW4gZmxvYXQzIFZla3RvciBtaXQNCiAgLy8gZGVuIHgsIHkgdW5kIHogS29tcG9uZW50ZW4gZGVzIHVyc3By/G5n"
    Data.s "bGljaGVuIGZsb2F0NCBWZWt0b3JzIHVuZCBzY2hsaWXfdA0KICAvLyBzb21pdCBkZW4gQWxwaGEtV2VydCBhdXMuDQogIC8vIERp"
    Data.s "ZSBMaW5pZSBzb2xsIGltIFplbnRydW0gYW5mYW5nZW4gdW5kIGR1cmNoIGRlbiBjdXJyZW50VGltZS1XZXJ0IHJvdGllcmVuLg0K"
    Data.s "ICB3ZWlnaHQgPSBsZW5ndGgoZHJhd0xpbmUodGV4Q29vcmQsIGZsb2F0MigwLjVmLCAwLjVmKSwgZmxvYXQyKDAuNWYsIDAuNWYp"
    Data.s "ICsgZmxvYXQyKGNvcyhjdXJyZW50VGltZSksIHNpbihjdXJyZW50VGltZSkpICogMC41ZiwgMC4wMWYpLnh5eikgKiAwLjVmOw0K"
    Data.s "ICANCiAgLy8gV2lyIEdld2ljaHRlbiBudW4gRHVua2VsYmxhdSBtaXQgd2VpZ2h0IHVuZCBkZW4gYWx0ZW4gcmVzdWx0LVdlcnQg"
    Data.s "bWl0ICgxLjAgLSB3ZWlnaHQpDQogIHJlc3VsdCA9IHdlaWdodCAqIGZsb2F0NCgwLjBmLCAwLjBmLCAwLjRmLCAxLjBmKSArICgx"
    Data.s "LjAgLSB3ZWlnaHQpICogcmVzdWx0Ow0KICANCiAgLy8gRGEgd2lyIHdpc3NlbiwgZGFzcyBzaWNoIGRlciBUZXh0IG5pY2h0IPxi"
    Data.s "ZXJzY2huZWlkZXQsIGFkZGllcmVuIHdpcg0KICAvLyBlaW5mYWNoIGRpZSBlaW56ZWxuZW4gV2VydGUgdm9uIGRlbiBqZXdlaWxp"
    Data.s "Z2VuIFplaWNoZW4gYW4gaWhyZXINCiAgLy8gamV3ZWlsaWdlbiBQb3NpdGlvbjoNCiAgZmxvYXQ0IHRleHQgPSBmbG9hdDQoMC4w"
    Data.s "ZiwgMC4wZiwgMC4wZiwgMS4wZik7DQogIA0KICBmbG9hdDIgY2hhclNpemUgPSBmbG9hdDIoMC4wNWYsIDAuMDVmKTsNCiAgDQog"
    Data.s "IHRleENvb3JkIC09IGZsb2F0MigwLjJmLCAwLjJmKTsNCg0KICB0ZXh0ICs9IGRyYXdDaGFyKHRleENvb3JkLCAnSCcsIGZsb2F0"
    Data.s "MigwLjAwZiwgMC4wZiksIGNoYXJTaXplKTsNCiAgdGV4dCArPSBkcmF3Q2hhcih0ZXhDb29yZCwgJ2EnLCBmbG9hdDIoMC4wNWYs"
    Data.s "IDAuMGYpLCBjaGFyU2l6ZSk7DQogIHRleHQgKz0gZHJhd0NoYXIodGV4Q29vcmQsICdsJywgZmxvYXQyKDAuMTBmLCAwLjBmKSwg"
    Data.s "Y2hhclNpemUpOw0KICB0ZXh0ICs9IGRyYXdDaGFyKHRleENvb3JkLCAnbCcsIGZsb2F0MigwLjE1ZiwgMC4wZiksIGNoYXJTaXpl"
    Data.s "KTsNCiAgdGV4dCArPSBkcmF3Q2hhcih0ZXhDb29yZCwgJ28nLCBmbG9hdDIoMC4yMGYsIDAuMGYpLCBjaGFyU2l6ZSk7DQogIHRl"
    Data.s "eHQgKz0gZHJhd0NoYXIodGV4Q29vcmQsICcsJywgZmxvYXQyKDAuMjVmLCAwLjBmKSwgY2hhclNpemUpOw0KICANCiAgdGV4dCAr"
    Data.s "PSBkcmF3Q2hhcih0ZXhDb29yZCwgJ1AnLCBmbG9hdDIoMC4zNWYsIDAuMGYpLCBjaGFyU2l6ZSk7DQogIHRleHQgKz0gZHJhd0No"
    Data.s "YXIodGV4Q29vcmQsICdCJywgZmxvYXQyKDAuNDBmLCAwLjBmKSwgY2hhclNpemUpOw0KICB0ZXh0ICs9IGRyYXdDaGFyKHRleENv"
    Data.s "b3JkLCAnIScsIGZsb2F0MigwLjQ1ZiwgMC4wZiksIGNoYXJTaXplKTsNCg0KICAvLyBFcnN0ZWxsZSB3aWVkZXIgZWluZW4gR2V3"
    Data.s "aWNodHVuZ3N3ZXJ0IGF1cyB0ZXh0Lnh5eiB3aWUgYmVpIGRlciBMaW5pZSBhdWNoOg0KICB3ZWlnaHQgPSBsZW5ndGgodGV4dC54"
    Data.s "eXopICogMC41ZjsNCiAgDQogIC8vIFVuZCBnZXdpY2h0ZSBleGFrdCB3aWUgYmVpIGRlciBMaW5pZSwgbnVyIG1pdCBSb3Qgc3Rh"
    Data.s "dHQgRHVua2VsYmxhdToNCiAgcmVzdWx0ID0gd2VpZ2h0ICogZmxvYXQ0KDEuMGYsIDAuMGYsIDAuMGYsIDEuMGYpICsgKDEuMCAt"
    Data.s "IHdlaWdodCkgKiByZXN1bHQ7DQogIA0KICAvLyBHZWJlIGRlbiBGYXJid2VydCB6dXL8Y2sNCiAgcmV0dXJuIHJlc3VsdDsNCn0="
    
  cubetest_vsHLSL:
    Data.s "data/cubetest_vs.hlsl"
    Data.l 5
    Data.s "c3RydWN0IFZTX1JFU1VMVCB7DQogIGZsb2F0MiB0ZXhDb29yZDogIFRFWENPT1JEMDsNCiAgZmxvYXQ0IHBvczogICAgICAgUE9T"
    Data.s "SVRJT047DQp9Ow0KDQp1bmlmb3JtIGZsb2F0NHg0IHdvcmxkVmlld1Byb2o7DQoNClZTX1JFU1VMVCBtYWluKGZsb2F0NCBwb3M6"
    Data.s "IFBPU0lUSU9OLA0KICAgICAgICAgICAgICAgZmxvYXQyIHRleENvb3JkMDogVEVYQ09PUkQwDQogICAgICAgICAgICAgICkNCnsN"
    Data.s "CiAgIFZTX1JFU1VMVCByZXN1bHQ7DQoNCiAgIHJlc3VsdC5wb3MgICAgICAgID0gbXVsKHdvcmxkVmlld1Byb2osIHBvcyk7DQog"
    Data.s "ICByZXN1bHQudGV4Q29vcmQgICA9IHRleENvb3JkMDsNCiAgIA0KICAgcmV0dXJuIHJlc3VsdDsNCn0="
    
  fontPNG:
    Data.s "data/font.png"
    Data.l 213
    Data.s "iVBORw0KGgoAAAANSUhEUgAAAgAAAABACAYAAABsv8+/AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQA"
    Data.s "AA7EAZUrDhsAAD3hSURBVHhe7d0J2HZdNTjw0xeJkDI1mIeQhJRIShmiFJEiVFRfVEoD+RJ9hlDGMkRp0Ch9DXzJLESJKEQTGZM5"
    Data.s "88z5r9++/vt2nvOec/be5zzP875v71nXdV/v+9z32dM6a6+9pr3WFbqu6+Ozw46BHQM7BnYM7BjYMXABYeCiC2it+1J3DOwY2DGw"
    Data.s "Y2DHwI6B/4+BXQDYSWHHwI6BHQM7BnYMXIAYOBYB4KKLLuqucpWrdFe84hWbUajN273d26V2V7jCFVI//l0Db/u2b9u91Vu91aHp"
    Data.s "+O9Sn1e72tW6P/zDP+w+5EM+pPToGb8b6+3f/u07/47hSle60mGNSx3DxZWvfOX0eeu3fuuqOcAV/K3B/XiAt3mbt6ked9jWmte+"
    Data.s "s9yP9Rp/h/UY2PIevL9Me1M03DIr9NhKD3iIcdGAeQz3ce3YxzX/vKdqx/Vcnrd/h/9f00fL+s0V3rTJY+d/fV/LFzL+9bP2/R8X"
    Data.s "/ltwtj/7fxjI+G85P7QWA7Dpc/HFF/fgQQ96UHM/97rXvVLbT/iET+g/+7M/O/3/Ez/xE5v7+eAP/uD+b//2b/sHPvCBqe11r3vd"
    Data.s "/u///u/7e9/73sW+guD7H/iBH0hjZ3jRi17Ux8FdbGusm9/85v1//dd/Hdpe4xrXONLuJS95Sf+bv/mbi33FBuyf9rSnHfr4vd/7"
    Data.s "vf6d3umdiuPf7GY3S228gy3vMYim/6Vf+qX+fve7X1M/ITT1v/3bv91/7ud+blO78Vwf+9jH9s997nP7YPyb+tmCg/O57Yd+6If2"
    Data.s "f/mXf5nofs06Lr300iP0f9vb3nZVP9e61rVSP5/0SZ9U3d4+m9p/aLJ2LV/3dV93ZP4PfehDq9uOx/j6r//61NeHf/iHV/XxgR/4"
    Data.s "gf0b3/jGI+P74w1veEP/Pu/zPlV9fMZnfMaR9j/3cz/Xh1BcbPvxH//xZ4w7/MJaSjgMgaH//u///iP9XHLJJcV2uV+86zjxX5rv"
    Data.s "/vuZ5/UY/84PvLkCV9sOfwN8/ud/fiIeh3nFgEeeuctd7tL/4z/+Y/8xH/Mx/a1vfevUz01vetPmfmyE3/qt3+o/4AM+ILV1KP/6"
    Data.s "r/96H9r8Yl+Yj4MH/NVf/VX/3//93/2b3vSm9PcLX/jCvsSEQuvvf+d3fqd/ylOeksb55V/+5f7Xfu3XDmPe5CY36f/u7/6u/7iP"
    Data.s "+7jFeXzN13xNGhMT/7M/+7P0/2c/+9nFA/HGN75x/x//8R/9F3zBFzTjbPiuvuRLvqT/jd/4jVqiOTIWwe9nfuZn+nd+53dunkNo"
    Data.s "i/37vd/79Y9+9KP77/qu7+ox03d7t3dr7qeV7t7SnrcHX/GKV/Rj4bNmnfYg+Kd/+qf+T/7kT/p///d/T/ugRLPjvq95zWseDsKP"
    Data.s "/diPrXqHoaH23/u935vG/4u/+IvUPh+m9m8NLRBawZvf/Ob+T//0T/u/+Zu/SX+3HGJ5LfYr+PM///Mi78htPvIjPzLxDnzM3jV/"
    Data.s "c3j+85/fw0npHWT++Q//8A9p/vAAnvzkJxfbfsRHfESaK56Vcecd/ud//mfqo6QAhQWhf8xjHpOe/eu//uv0/s0DfMVXfEVxfO/v"
    Data.s "e77ne9Lz1m/+cAG+9mu/tti+hJv99/L5TOkd0v9w/xDICzgsD1B6CVsEAJqjjXvDG96w/5RP+ZS0EIdaacz8+/u///v37/me75k0"
    Data.s "19/93d9NgsR7vMd79F/+5V+eGGKJEREQwC/+4i/27/Iu79LT/Gmh97nPfZLWXtICaFwY5/3vf/80Zwfpv/7rv/YEA3//4A/+YP9D"
    Data.s "P/RDi+sx7i/8wi/0r3vd6w7PvfzlL+9f9apX9e/93u+92PZGN7pR/8///M+bNPB3f/d371/60pf2D3/4w6vxPnw/H/RBH5SEr0//"
    Data.s "9E9vbn/HO94xHTisN4Qf/3/605/e3I/5YEYEiHd4h3dY1b6W5s7F5x72sIf1L3jBC/p3fMd3bFo7OkXnmDdasrZb3epWaU/8yI/8"
    Data.s "SFEA9TwLGmHh9a9/fWoHSvsu4/B617teep4GOsSrwwd85md+5uJ6rNe+d3DZ9/ogVDoA7Sl7q/Z9UQZe9rKX9f/7v/+bDtSS8pD7"
    Data.s "ZS1Bv5SO2rHyc+HyTAoEK9rw3f3+7/9+eietQlju19p/9md/tkgP3r+Dn9KSeRaeBp761KcW3z/La8YXHp7Hx8sIEhSzVpycK89T"
    Data.s "aK5+9auf6PwpmM6vtWt+13d913TehOv6QP/6+smf/Mn0Dr/0S790se9jiQHI/r5Wv19MtAszWRebpwsi7P74j/84/Z8fvhZio3Sx"
    Data.s "+bvQILsg3C4Osi6k0O47v/M7u5COuzBrd3FAzXbHbx8E3D3rWc/qQmpPMQhxIHahlXQ3uMENujjYFqeiPf91aPnpuTh8kj8uNnN3"
    Data.s "netcJ/URG2mxj2BWXRziXTDQgx88GEL67t/+7d8W28JXaB1dCFG1KDvjuTAfJ79faCyr+giJM72zz/u8z2uOIYhDpotN1sUh1Okn"
    Data.s "CLoLgXLVPOIA6ILxdCFUrGp/vjZCa6GFdqExd3FoNC0DzoKJd2F9Se3BT/3UT3XPec5zuhB+u2BOxf7uete7dmH5Su/+EY94RHq+"
    Data.s "lhfw9cfhk8YbQpjAu3/5l39Z3LueDyadaP8hD3lI2gcgGGIXAnSKyWmJJQiloYMPvKPFDx5afvc///M/Xbgci7gaPxACa+fzwz/8"
    Data.s "w0fe3ed8zud0eEDw8OY+v+zLvqwLYSS90xI96D8O6jQWfgPCfNyF27ILa1Ixdskz3nVo+wnnGe52t7slPognL4G2YbXt3vd937cT"
    Data.s "h9AKW9tPjecMCMGre+Yzn9mFILo4JXTinLn+9a9/xsf+wc+WIATlLiyvXVi/u7B2tS4/0asz8Ku+6qsO9K+TO93pTukctD+WoB3j"
    Data.s "E72F/zt9m/9tWUVofV1o3WkDOcwuu+yyLjTq6i5C0ule+cpXJiK2YALAr/7qr3ahSXZhGut+7Md+7EDYU51iGn/0R3/UhdbThT89"
    Data.s "MY3SoTvsJzSFxICykOGlG9fHQeZQy4x1blE2KaaLCMKN0oUm3d3+9rfvHve4x3VhTlvERZgLE/5KG32uExsIs7EG+FsDGAeG8Wmf"
    Data.s "9mlVB8Z4jLC2JEYH7wSvtRBm64SHlve3dqxzqR0m/F7v9V5FYXVqztpiYgTwIRCkCMIlBqaNPUTIJfCGO60JNfZuWPy6cCEdaWde"
    Data.s "BPMSTRI8w2WYmHXEzCSBO9xh3Yd92Id14Zbr7I8aCMthYqIPfvCDEz8RuFsL4cJK+xQDDy24w9QdaDVgXIKO/U/Y0tbHvK3LvmoB"
    Data.s "DP9bv/Vb03sIi1CxKT758z//891nfdZndfe4xz06ykC4TrpwhaQ5lfhKPrSsYQj4Hp5COFoCQsKP//iPdxH/lJSnVtjafjheWIvS"
    Data.s "YU6ZJNCioZIC6H2HpTk9N/6go7BMLy7J+eHcg4Of+Imf6MIK3qGnWjA24YMCO4SP+qiPSgJYVkyX+lttfohODyZDPi9BfPm70/yX"
    Data.s "H4u/7Qu/8AsP4/Nn1wamMdszPWeIA7HnW6tZg7HjoE6mw9CEkimG75EvNiwa/T3vec+qfphCPZ9BUFbN+FufYYJiAg4NpBjvsDQW"
    Data.s "szFXRMlkO+5DoBMzlbgP7ha4XLsm5jrupLNFh2vnvbUd07N3yBfd2hea5e+PA+BIW/E8IUj1n/zJn9zUp2BewJfeOpfh88EQk0uo"
    Data.s "dh9qm4ORjc8EWusKEgSH/gXr5n6svcYFkIN3BfwN9y+XWE17rhvuA/geto/Dow8hohmH4mjALW95y+q23IziCIbAJVrz/rwf8H3f"
    Data.s "933JBZfbhDCRvhcfsBRM7Tdz/oZv+IbkuqkZc/jM1vb64vrgasmxYNyvz3ve86reHxcId4sP93H++BsOuThLa7KG7/7u7+5DcU04"
    Data.s "487CD0OoL7ad6juE4OSOcyZlt9jCHLbHANziFrdIm7VmsSVkrPkdAfNhiyHQXuCQDVnrh9Tmdre7XWIaOQBGVL/vbPDSnIwXGkhv"
    Data.s "0wpo8nxoEsm35yXaJGGSSf1NBcrxofJ55uCf2s1XmlfN7+Zj83/Lt3xLcZ1L/Vkjv6l114x7XM9c9apXTbEHn/qpn9oLZiOEPOpR"
    Data.s "j0o3SeCbP5OQdlzjnYv9hMk3BWGu8VcSmt2WcXAP1wZ39kJLNL/2xyEAEAhB640UQszll1/ehyaV/KKYOPoovTN0I3DtNre5TXpW"
    Data.s "4FytAGDv2ufALRpxGD72lNiEUgzPV37lV6a2xhP0aP6EHwqV/loCa63VuHz/pTXn38U7EULsm1/5lV/pf/RHfzT9SyGqEaTFD4lV"
    Data.s "AmFBSfRCCcDLxAYIMKy9TVU75+N8Ds7wPu8qLB6Jdxxn/619hRs1BZ+LyQi3WB9Wtab5CDq1b8V1VJ5/2wUAmttrX/vaxHBbF7z1"
    Data.s "eTcHaNxhxu+/+qu/Om1iUZH5SiDNVKBN7TgkONfxBOXYTMPAlto+MAXCgOh4EuIf/MEfpBfqgHzkIx95hlBB2/fSCA/5CpL/2zgY"
    Data.s "aos0XzvH/BwCc0sBI2ptO3weo2P9sL4t/bS2LV2DcjujdJOjdczh8wIgBcGyGtm8WzXf1rkQUGlfT3ziE1cxWoefw8c+Go5tTQ6F"
    Data.s "07YAhOsrHSauBW45ODB1cOc733mRHt1AoS2F3//w3N3vfvc+TNpVV/jQ1uMf//h0iA7xRyjVB5pYeqcOTYBOWSLys1kIKrUf9p2D"
    Data.s "N8P/Xr0HHRKA9pvxbR6vec1r0sEOPyWaDNdfiv4fAppkBfn2b//2I5aBUl+n/Tv+TPDy/ikNORC2dh6u2lF87f/xx/etB7hro4Qo"
    Data.s "VmlnSK0VO8/3p3/6p9OtMNdKK9ewXQBgcvCy10asVk50ckFHqG7iD1IoJl0zBnM0848NwCRPi6Bd1bQdPnOHO9yhf/WrX92L0HQL"
    Data.s "gDXC75gqS8mQyESAukUw1MBJooD0TDDg3midQ+3zrk0SljCi2jZTzyFcQtg3f/M3b+qndQ7MpKKV3bRwbZLl5sUvfnE6EJ/xjGck"
    Data.s "nJ9kboEIejtCdbS21jVseV6UO5rFMNb0Q2gHTLbD9q6lEgBao7jXWgAI6fnQY03bKrRh7CwblIIlvLiqhkcQwjFsH7SEiTrUuVVq"
    Data.s "rIDjMZheXQmEx6XxH/CAByQBXB6H4XP+rpn/sE34/pPQ0ULvhAU3JljQxgIgKwChooauWIHtQ++ONdO+xFdarTg1Yx33M+bqymW+"
    Data.s "PvrFX/zFiQ5qrC8lBYRrozRfFkpClKvcBC8QPv2DRarUPv8efv/E/77t276tOGZucyxBgIKvYs5NgTMxgWOBkDC7sD50gbgutIYU"
    Data.s "wSuAJkw6KaAsNNIUZDEHIqCD8aQAHEGMguJEVQsqFNgSJqLmeQokEtWrDxGuOZBHpDs8CS7JYFxBWCFtH76LuIEuBIhONK+I1Lgi"
    Data.s "1TyH2gbW62NeW0B7nzWRvFvGFQQWZuxOJLrIYwGkYcbrYhN3of11caWwQ58nBeGuSQFwaC+YSBrvNCHu+aZbFKK41wD8oXsBf0MQ"
    Data.s "iJRv56zpt7WNCPzQGlPgmtskgtNqQLCg/TvcU9oJKq557x/90R+d6D+uwKZAKp+wiiReFsy7iwN6ka/NjS+gza2IHFk/txa3oMxV"
    Data.s "wNYQ3AzyXmr3JZ4leNCtp5p157H0b3yfIRjbd6XxBV7ad25i2YfenSDE0KYTXQqGPtfBHrCGEIYTDYbQmOjAWVLKCmvdgrV98ID8"
    Data.s "8XdYhtL7WAI4CqtvF2b/LpTFtI/DApWi+AUGtoCzzK0XQeEtUC0tRKeTzwq24ePecp9xru+a72nZ3/RN33SYm2CKWo2WywBkzZX/"
    Data.s "S1AIzYE0RRqsmUN+hsRMa+cb4woQDEIb9Tt/NF/jMDCQ+wTQOoZBNExSQFBbqxmpZb58RqwSNRnDlvq1Ni6TsSm0ZS5bn732ta+d"
    Data.s "cF8y+24d51xqb99xV7E2rZlXjpeRwAr+9CG3BpoQV9CaV2CNBcB+4DMe5wKoWU/O4/GEJzzhyPrlAWHBK9GCGAjutu/4ju9IH5Y4"
    Data.s "WfgERspH4Y7/cF+O5zQ3Pm0OLZYyKjKxm2eOHcr9yyvCMsEdUYMHFksuxrgOWfV87pO5GUjElb9j8RAPpb+SCxTPD0Eh5YzIeLIm"
    Data.s "NMkPzTpcM/9z6ZkQJvsnPelJiZ+x8J3k3ATwApaTrS50tCgjYN7HlfPe7gIwsOAviKsc9Niew/gk/MmmJulzbbyaABZz9Txfi6Qb"
    Data.s "TCciMJnSMAA+babEljUxxxJItGGKE13MHeDvHBwzdJXwIQn6s9lFzNrAhI9hRDAXAKbcMo/aZ5la+foQfIvpcNw/RkK42UrEtfOe"
    Data.s "ek7AJWjxgWJa/OD8d1t8zmvnvXV8h5agobXja5f95YKOmKSzC6r28BmO3SoAyFTmoLHf+IvFzaB/giTzucReS2tjPuXqYUYXwEXw"
    Data.s "19bh4yCvMeOO+0c/3B8VEdQpwHQ8vvlzidYkIsrt0S2/uf2f529f1qYStv/wvdZAbEFw+A/Af/BxEemAUFXaE4QFgpL3p/2QfrzP"
    Data.s "YVzD1HvcSv9b2y/RlviXNcmdWvYinjV2v7W0Hz5L8OKybswGul0A4H8ENakj1y5urh1/Ol8Vv7tnsk+m5fqQIDsbdggEAQf2kvQ/"
    Data.s "npM5ANJ4/g1DFCAjyEe0MOFgvClI2a4tDoEETntxMIOW7IgtOLY+vjtXRmrSls71jfDknz5bViDzYonCwMb+1CV8sNKIAHZY1F4b"
    Data.s "a8Fv6VnjC6BleaqJWB/3B+dbAy9pDCLnh0CwWHMtC9MEtYzzi77oi46MO/6jxoeK8QneHYJgqLXaZ06tWqvQTI2Pn9TyIAG0+Qpa"
    Data.s "XoP2LSnRMw9eE4c1xX8if0rKqlmiX7+LIxLkPATCQM1BtJX+z/b+rcHPaT3jSi9oubmj7N425290wE8ieY3EEWt9kdHNKuADjYjH"
    Data.s "5DuUNCQ2Uxfaf/KnlJJYDAeUwEcyIIkb4tBNyTFafSmSekgkMfbZS7Lhe/OR+Y7faAwyuYUgcvhaVr64PdBZn+QQYgpq/aKtiIQv"
    Data.s "/i5+9NY1G4v/MtwcyecpCUsEULVO4aw+z88rAUponylu4zRBtTb4924lAmlNpiWJkncme9sWkMgqAsGSDzF4SNoDa7JLimmRAEsS"
    Data.s "nhr/rz2D7sfJm3JsSmjRKVNaCYbz92xcZ0sZ0tYAXiCTnuQ0NYlUjDEc39zFhpQSgA3nJmGO5F+5MmprewmQJFSKQNiU0bQVxvyn"
    Data.s "FX/Gj0DANCz6wQ9qMiNupX/jnc3924rnk3xeRklxDJJi1ey9PJcqKc97vRA+NKo1ZsPzGTdMndwoa68CiqLl+iCBno94IDFLRkKb"
    Data.s "OB/nv8/5wuBN+3uefs/7/l1P/8dyC+AkpZrT7FsEu5ziF1oqWalcWRxYQKRCboVwc6T866wm5xvQQGihorEvtPd+vr2rfb47BsYY"
    Data.s "2PfvdprYtZ4LxLqxpEHwA7s90Zp4gt88Dv5DNcTzTUsRxCRmoMZfeb6tbZ/ves1ox935gbt9/257T8cSA7BdBtl7OBcwoIAEvy9t"
    Data.s "uBb4/WnQ8i7U+ktr+96f2zGwY2DHwI6Bk8PALgCcHG73nncM7BjYMbBjYMfAOYuBPQbgnH01+8R2DOwY2DGwY2DHwMlhYBcATg63"
    Data.s "e887BnYM7BjYMbBj4JzFwKQAIK+2u+ruobtLyycs37781iWQS5k/2L3WGhB5Lw93ZANLY+VPZMJL96IjOK2mm/QMf3Qk0OnkdjZ3"
    Data.s "n8jwtth+bnx9RFBcJ7/yEsy1H67DnNwNnoKl9uYP9/Jq10JkJevgzvhRnKeLBDep1sAcRFKilL/ee1N3YAjed2QDS33Mzd/z7i9H"
    Data.s "IpDOXeDjALkE5JNwr7UE8BdpnLvLLrusi8I4Rx73W1zv6yLLYqoNMIf/ufalsf3u3naUX037xX3+KVCPQn0KOebHIOc8/EfimjNo"
    Data.s "vRb/uU99Zfr3/tFBpJRdRb/oLhJXHe521+DiOMc3fzh1F9++LgHaRQPa5LXLbVECdTci7fER3jPkQ95bXI89sf3j5oxPXMWdHEOu"
    Data.s "fe80EgVN/p7zlURGuSO/yztiD0VCoTPqJHhW7gj8NTINpvv69vkUf4cfeQXkiJgCue7laRA/NIZI0pbwKtf9HMjbEleIE88e4j3/"
    Data.s "v4T/61//+onPe+9wMeYBpfcvVwP+tRbkS5B/xn6JAOpV3agn4V1ERs4qWl81yEKjwy0Amb+kFVUedAqk21yqGy+trtK3QGrVGLP4"
    Data.s "EcUpB/gcyJAnX3mpL7XAxyUpc5+PfexjZ9uXxoeLnGVwag6l9uYgRedcRbGa9jUlQZX1zHW5x7iU5nguK5qshC996UtTDXM1EIZr"
    Data.s "lJlObXF4XcK/bG4qGq7JQjbVr6yCUovWZPSDP3UUotBSqr8w7E9aVSC16VxWu6X2JZrzuyp2OW2zfO7jdMpSPecsk/K7j/uEfylj"
    Data.s "gQx0a/CvjZS5uZLY+P1Lda3S5Rr6VQ+jhv5K40t5u2Z8a3HLZOldyKQnj8UUoO2lOgnjao5TfSj3Ozf+1v0j4yKQdXRqDLgHoSRN"
    Data.s "/i5/hb0y3nuq+2W4173udaStZ3PqZWNaHxjzOVlW1SlQZXOuOmMu36yq4nD+6E0NFFUVlzIy5loKswdA/CCr4Bz+o5jToamxGvPg"
    Data.s "95dffnlKeVyz16eeUTMjg2qWa/q52c1ulrpQNRa/WNPH2jYHC0Akv0nZ9KIsYcrsprIUiVC1ItK1bHsxuXRPPgrvTFZ9i4Og048s"
    Data.s "RP5fA7HulH1MpTzZtFS1Mo4PiYhWKbvREpBiVQUkRZPC3GU3d9mtSGaRJjOtZwqmxrdmmp3KVnChMtScRWOuvT584IOUSwttGT+3"
    Data.s "J9HSbJZA5bY4BFM2O9WovC/4o91HPvWEC9WmprR485d9bqqCmN98X8pOp2qYZ+bWWEMHw2da+stzzBUpcz/oAP3IvHjJJZekPAVz"
    Data.s "+Nd23L5lzrL4mUekbk30OwT0m7/zzBh8p/IbiDz2XdR8ODxSi3/vn6Zs/6hkhv5VsdQXDUdmO9nBWugP/cOhvanPEv2VxmdNaBmf"
    Data.s "5ptpX4a5nGVuqg/ZO2m8cdAlXGsrg6Y1u6Fy73vfe3b6Kv4Zx37RlrVLZc7cj9/0Pwdb94/8G0BVwilAU/aWzHpTgDe4Cz/WwG9y"
    Data.s "k5skmvcZWwc8q83znve81CXeKRcIvp6tgHgFvLEewtFcFlLWCVYGOIqCYIcpokUZIe0/FuE5UMU188nM8/Arc2aBBZGWeJH+vIMo"
    Data.s "gpN47Rvf+MbFZ8c/hnDcRSKzpjbDh509skZG7YlFK+nSAGiXlcX6S9UHV090pmESAGxyB4VNxtzl5UO+UpauhSEiL8H3/sVQEdgY"
    Data.s "Iqd0egEIhiAxTG27NHH9InJIUM6VScpHOV+b0UG8BMrmehGEDoe1Mr7m7uVGcYx0MDkY52A8vjVLCiP9btQ3SMIO5tzSXh8+rsaV"
    Data.s "UmJOjZ/bK8laOoCZsJjLCWeEHe/LmA6Wb/zGb+yUJ1butfZ9HDeRnXZ/Ui9j/lHfoLvvfe9bLMm6dX7oCxN0WIzL0mIOTJTex1Kp"
    Data.s "ZGbo0FRXmSNDe0yHPTcHJo7+pZ0m/EoPy7zIPWF/TsEc/dtLUSCrY6JcMq2WxlfWlHDKJFw7vpTMaB9jl1p6jjEScq0LXyKE4B/a"
    Data.s "cik6lPCPqMg3+4odbMbxfrTNgmzux28nmSCK64wJHT91AAzBniUYeIaZeQrQjfctBfMQ8L3QbtPHfhiCZ7XRFjiE8Vo8hBAFlMf1"
    Data.s "gcOl9O5wc+mll6bD117LSgazv/fGtbiUGtzhnflk5nl4N55PeMO/uMdK54c2pdLLU31wGxA2nB9rwPrRiHUsuUnn+qZgOrcISvjE"
    Data.s "afPoJADQILxsL0stZ2BCFuVDsuNbRggIArPjpx2CTageAImWVAimhIQ5RGCOBJEhIFIbcimnNwk1TFfJeiEP9hhsLj5YjHAJpsb3"
    Data.s "PD9ijX97rn0tUa1tT5LH4MIEmqwAU6A2gc1Vk1O9dr7n4nMYP1qNqnaJ8UdhqCSZnzSgW0wUkx5q8DRx2laU2k0WhjkGwcdNWOGX"
    Data.s "tf9qYm3ymtA/Pz/6t2fHYP9Gadz09VQMQn5+jv7E/tCOww03icaa8cO1kdqqF9+y/z1LgMYDxrxh2I850FzHVh4KBYFsTvCYmkuu"
    Data.s "QXDSNJP7J4Dgl+gEHx6C+CM+bta7ORDnwbrisMxCWhTnSYe5dj7+zlquZ1hD1Y4Y1iTBIwlqrAEED3zvJS95SReFwoqoUAOGsqSO"
    Data.s "PWsnWqGUPO5xj+vCBVNsP37A/MzHvjGfGlgSrpfaiz/wDvCKtYAHrzn8jUewxbPgWv0HgttpQhIAmPpIT+ErTWMzgw2D55hwHO5R"
    Data.s "sSwFFmGwkX/5ULhCm2zqJFEJPovSsMltUBsMSJLSZgiQwYwfdclnccLUh9FCIIFhCh760IeuluKZo5nH5oJ08nhT8295kWvbk1wx"
    Data.s "Ccw/S/TjceGFdrFkiZiSoGmRczhtWdtpPGv+TGkYjsAhjL9kOTmueWEALF8E5KG2hQljhvbNkntEe4eXYFjAYlMLNfT/ute9Lplh"
    Data.s "a4Iqx+OySqCBucJAxzX+HP0/5jGPSft7qoCWudIu8QeBsoQdgt8Yplwvtfg9jefwLmvE64ZAKCDUOlzngGBJ+HTAZwEgCxJcseiS"
    Data.s "8KSgGMAHHPCEjqFmDkeswKyG9o+/L7744qL1Up/enTNBEKhgQVZT83ryk5+8Cn0vfvGLkxuZYleynq4aYNAIj8A3x26Srf3Wto/q"
    Data.s "mWnvE/4JANe5znWaAxlrx5p6LgSni5Lpnz+ItE9bYIbwN6mGZE0Dp5VgJABDQyj5UORvJDDQQrPEJ7LawVTDdBBQBEIcLA7Z8kBz"
    Data.s "5fvKvqqpBWCwNg+h46TA+t1GmIumn5t/XseS+yBvoKn15024tC7r944IZmuBBMxfl+c7/NeBln3Ua/s/6XaYjY1D2+G7ZbJGe6cF"
    Data.s "9hBmagMbFyMEBJLslyxplkyBGB+aj4Cq5A6oqapYS//cAQ6JOU0aExoL4IR6LgWWIyb1Lftvafyl/cN1Aa/ZVz41BwcXCyXgasj0"
    Data.s "S+iac3ucFm3UjIOfWiN3EWEQeK9RJz5FyI/fy7BPa1QxUcxGthzBmffFBcpaS4FBi4BgzCLA3DwG/PtRj3pU+poGvuS7H7cVi4BP"
    Data.s "E9gIsBG4NymMlfDBmgEH+M6cQlPqo+V3vM++QyctlreWMZaefdjDHpbOVwIPIZdLq3Rz7bjG1s9FNEhmCCahfOAwu2VNBmPAkIAr"
    Data.s "Dxkw2WwWJD0xs9FCsxmOSRLw5WSGuGbizNtz5sc1/a1pc65rEFNrgvfxgY7RvCUCKZ6ARrthyvO3ctCnCcz4mBeNOB865iK41ebO"
    Data.s "jH1uTgQEfURUenokbq4kq8FxBVYu4cIB7PAZ00t2GWW34GniM4/liqRiU0sARwRYOHz0ox99eNTfgiBppOcy0PIJAHe+852TAAMo"
    Data.s "TmiJYFPybVsjHORAQtZaVgUuEB/73neAlcB3U+5APJ0rGCgN3nqlTgxSjuVSorcVWKCvd73rpRgyLrHTAq47vGPpuvRJzYXCkl1U"
    Data.s "BDA0a++fFlyEcJj3mC/5nAgD2RWQJ0HDxiRyIApm6++sFdB6WAFo/ZmJvP71r08HP2bIh7gEEO8+adaS8r8sDPqbuwOrT9KxDbI2"
    Data.s "iKMG0SRmprS5YKC5+ed1iEZfs37t+dGWYG79U9rjXJ1w2idGO8a/v+F+iwBXg9+tz+TDleWK31AwnE2VtZmt/de0d3jbQ6R5wjOc"
    Data.s "0qAxMgy+xkdJ+qetCci69a1vndZQsgLU0j+zsLvWU7c95vyXTP/M0Es+6JbxWemmxp/aPxQJuCzdQBi/GxbMTMcCYsFSFH/Nu615"
    Data.s "JvO9qWdr/MP5EI8reqkL0f9wsBSAl8fynFgX/nd0h9/mOCzPsA7ipawABD1WgamgQoqe5xxAzoK4oliz9MMzeD7Lgj3YCoQfQYSv"
    Data.s "fvWrDwpnax9rn4f7sxGBv3a+x9nuIlIe5uXFuboBxkRHKnPYZ58qImUWRkRMinH/cXZOBADEXAJMYKzpO3RJ9KTiuVgC2hUBQMDh"
    Data.s "OJFNHpNZ1QYdR2iX5uR3UjhGPOeDzH1Mzb+m/63t59bv4B4e6IjcATMHhLxxKWDS6RxOW9ZWenaOQdYwTn0TUGg5JGggGpw5kubn"
    Data.s "ID0NyEKIiGU3YNANmoP31ghhAiN6Yh7075IVoIb+uUfsIQx6ChwaUwI4emDBWIK58b27LPTQZo0/tCCO+xzvH4IHwVuSJbicA3iH"
    Data.s "p6mrfm7+MEc71LJmfdy0kGnUv2NLob/Nj4++BMz1eHBOSoOG8OEpU/24L++A6xUPFHcFl8NYiBwcCp+0fM8SSodwpzvdKfFxt2fg"
    Data.s "Ev8QtGketWCtzoNWhcG8KI8UlHEcRO3YW54jIBFO565ibun7XG97EYmc9GOTZg2XPymDqGZBgvkupmASvik+HkKA3yHOtY+xBsky"
    Data.s "QIMR6FACTG5KO8h3+sf3q3N/5kxIYOKaiqBEXH4TvzB3F1lfc+NbOxdHyaQ817607q2/l9avf4zYO63RQrfOp7W9jQ93w4NaFDC6"
    Data.s "aTF/YzpDxkOb0Z4p0r3wEhzX+yN8sKKxQgii5EdtxTsrAL825iu4bckKUHr/9qRsiOApT3nKLBrWCrBz44siF0DLnJvHz27B0rvw"
    Data.s "u0NTEJr9i9/Mgds9xsBrpuIbshn7pAJC8UB8xeFL0BqC6G68cYnv5Oe9c0Irq5G+xAQx/9cE4ZqDWAECProjELi5lIG5X/+sKSxB"
    Data.s "fh8CHLlKjc4ETAMBqd6fGxw1+6fmnU4945256ofHuk5asnitHWepXb4KyrJdctWdxPhns8+LSF00aAFC/FDMhDaUA0MCERoNzVyA"
    Data.s "oGdcFUFQ+coZnxELQta+houhcRAc3C0d31MdPkdS1gdCFIjBhEXzJDjc5z73SdKs8eeAZkGCEzCIgLU1f+1J1l5sJuypPqbGxxD5"
    Data.s "0V1DEYyyFIg41T4nM/KvQLBabXYNMQiQYi61ftYOa7dp4ZLVg3mQBnQaQTWt88++SEzPvL0rV0xpzjWa09x4aIZQ6rZKyQc89/68"
    Data.s "t7FVpLQ+jFfkMmbGnAn3a5gK14/9g0GWBAjvn6Y4pH8CM2bPBUGQEKXtkDgJGI7vkLF3mOJdT6SdE+4Eh83dZZ+bk2u9oqPlAphL"
    Data.s "1mJNeA8ew3QteJI7Eu07vATgorEcwHzc60c7rBTGdWDDOf7DHC+A0ntYusU0nA8rDNzhVe6Wt5jSabH2PMuJoLYxsJDh5w7YsX+d"
    Data.s "+Z1V17vKwdT2j4PZ/snXOI8bd/rjpmF94K5jbfLuxrzzpIPz4ASNEL6Mf0FBHEx9HOp9+IBTCsIHPehBQdP/B9LIhiR4+CIkyV7q"
    Data.s "Qs/6SIUYBJdSoubvhv+WUlmWUuFKWRlaeDE9olTA4TI4Mvf8R+Q3WJ0KOISjPiwLq9vnOYQbZTYV6lwq2yl8zn0nFXBoGpPrDwk3"
    Data.s "pQmears1lak+t6QCDvNuH8LLkXmjt9Dci+/c2EupfKU2jjvKqe+46bIqFW1cie2lRJ7DuzHQnTTA+RltQASmpe/gODS5PgSRM/qZ"
    Data.s "w791Sf8KpAgt0UIpFe9SKuDjor+wdpxBf9Kzep8RK9CH+bnHb4ZrKaVitq9BJDOaxUH4ts+goTwRaZrDn13E3/DdheBW/bx2UlBL"
    Data.s "pT0FIXj1UqSX3p/fwxLbGxuE4lTVJvcbLtJDOuQQIM5o6zsQwkgfB+rhd2mBQShRZ6T7DWGmj+Dw9HtNWm5psENoTXuuZr2eCYVz"
    Data.s "Em/DL0Oonu0vpwKOBHbVY07NLYLNUyrtUFSb+wnrU6LvUFab29bi6aSeuygQnbR8UhhJkMYrIRBtUfAPMxbJmgmJ74gmSVLNaR+Z"
    Data.s "T5gW50xVolFJnPkaypR0Jb7A3dNcwMe/LBGkUFr80j3Y3B+fVQ66IsW6duTDLbCUClT7qfFJ1AJpuDimEqwM1zHVPq/FOsxjyZTH"
    Data.s "JOcZJre14N3Q9plecyEnfZoH7Vocxxx4Thu0MARmcXigPS1ZMGi8tN01GdOsnd+TpQau0B1fZE0hlzzXOfyxbKFl61uKSp57f/pl"
    Data.s "vp1yTeWx4Yx1Cv1mHNHcaBRDDQ5+aHVTMIV/uJeERV4NeClZkGTuZAaXlAX95wIpNHF7b8kEflz0hzfwIWf60y/tPRfTgaep4l5L"
    Data.s "49vXT3rSk5JvOMcojXGIdqydlYOVwdr9C39cCC2WJLhbSjw29f7QLDcjq439knHP9eFKXu1ddrev3J0X+1RyOY7ngYZZGvw7FWvh"
    Data.s "OzQqAFCWwwyy0KE/gd/jdL/5e4Gec8W0xvNgtWq5kizOIb+zIf/P/4cL7/ekwX613tb4hZOe12n034f/5SDphfn1iIQ4ljwiVqCP"
    Data.s "Az8JaGFuOu8knpOSpPZ+y4WfdhxduDhigYjrhDu/qCiQtu+T+n2SLQC1FsOTwC0LE0v4+WgBUKM2qX0yOLl+xIflWuCtbnWrpHXw"
    Data.s "P9JyaEHu48oNTlNlLShpxqchvexj7BjYMbBjYMfAhYkBN7TE3bBS+7C0LVnsjhtLAn4FerJYin85zTv81uJMnivU5PdcaG+uGJpn"
    Data.s "DlI5Xxpf0JwvndbPvzlXuvIkpKu9z3ppeMfVjqudBnYauJBoIG6BHMIF1pQD3oqrYTngcDWfuoWrGEARD4QLeHZeBwvAUDISEep6"
    Data.s "1tBXJEqfj+lsZgU7bult72/HwI6BHQM7Bs5fDLh6KdbC+ST2JILYq2MujmPVbrewArA6uI4+TMB0HP2X+mD9mCt4xoLvVsk973nP"
    Data.s "2biWSQGgNOj++46BHQM7BnYM7BjYMXB+YyBVA9xhx8COgR0DOwZ2DOwYuLAwsAsAF9b73le7Y2DHwI6BHQM7BhIGrhhJLC51V1j2"
    Data.s "KndgW9KvHgcO+W7cMZWB6SRL+rbOVUYtZRndqx3nzW7tq+Z547lZ4faF8p6nBbKHwT9/kTu3rXCht2/F1/78joEdA8ePAXlpZBDF"
    Data.s "R2URbQFZJu9whzukPAnDuLeaPuSYUfVTlP25mGm1uIYolJHuMEayhV42qWhwqh9ZqSJBSv/4xz/+jCxhpz2X4Xg5c1ZcjzxxfEQK"
    Data.s "5EPGOlGdp7nuSK7SR5KY/tJLL101bmy8FIgaBWzOSvut89/a/jTf1T7W8fOmSNPch+Ddn8Y+39/f8b8/OI0U4n0kizoExLfiOQoo"
    Data.s "pTMoKiU287A8aFyJr8742Dq/pecjBXYfyfv6qNzYWwd6bun/Ihn+5MtWTleu6NMGFgdSlyxy40x0pz2X4XjuVvqcVBGR4ViiSEmR"
    Data.s "ke401WE4TZDTQdGapbukS/MhNYu8zcWiWue+tf3W+W9t37re/flzCwMqIcpWSAPc4fzEgCynqiDK5leq+zG1QsWUnEFr8gewnquP"
    Data.s "o3iTrJOnDWopKOZnbDU/liq+Ts0txQAodIOJt6RwPO2FviWPR/BRkMKVElXszgasFb6kL1U3XMrnNbC1/Zox9zY7BjIGpOiW7Gwu"
    Data.s "TfOOqXMfA4p2ue6mEJpEdacJrv5JoEeRbT18j2Oe0mg7uxU+8/9S4bDxmEkAkKv6CU94QsqitBbufve7p2pkanD7yMvfAvzsysAq"
    Data.s "MywPtiqALaBsqlzc2j7iEY9oaZqeze2tgS9p7m7lXMc3vOEN09zNwfpr61obl9aPgEmvskmtgTx/49sEqtHlMpul/nKmR3UTwhWT"
    Data.s "1lD7/lSKVD9CJsk1sLX91Jjeg8pmU+Vh18xxqQ0NMtwnKSOXqnfe/RB/qqnJDoauvJMxWP8jH/nI1FZFO/Tbgv/c35D+vMMoRFS1"
    Data.s "VEzLfvH+1IzAzLbsP3n773KXu6Tqn7KjsW4tQcQgJeZFAyf81tT9GPcnDkXlPev2adn/7pCH67O73e1ul/ZLa+W5KfpVAdCeoJWW"
    Data.s "QA5+tS+GoCqm9uoLlIDSMHzX/NnqCURxqENTvBmNTYE5en643x/84Aen2gBLFVxzX/g0njUsIY+XhUsw8dQSKC+vlozDO3/Qn3LY"
    Data.s "tZX58C+CHGXibEBW4M7G2A58NCuGb+nwR9tz0OQziE7OeD5cCMmPPIQoLdxHkoZi36oIRpGQPgoSHapZ6Ud/UaO6n6tiNpxHFAzq"
    Data.s "I4DwyPgPechDimPnPsbtVW5TIZFfKIi42I9nchWvPIkwR/U3velNi22DWR2ZtzGncLz03dT6VW0M83ofB8Nif2E66iPQMa3X8xki"
    Data.s "ELGqihofumqDwbyb521NW9ubP5zlamBhzk1LqM3Klduj4Va8e14Miwpol112WaomluHyyy/vwySXaDsDGokD8cg4amvAn6p1w6qb"
    Data.s "tfg3B+8/V23LY8FJTRVN849iLL3xohzrYa6yqq3df2FO7YPh9CpplnzreEQw7iN4ankPqgvGgXFkD/nDvlKpsdTXsKH3EMWKim2G"
    Data.s "fU7Rr6qH+qqpfYA+VMOMcsKHcdVYAfy7pfmrwBjWt0M1VhUnQQg2qS3/uCqhUZhqsq9cDZAP3fOhTaf2UYTqjOqAU3MJwasPBbKX"
    Data.s "RTb/7p2HRtyHUFuc/5j/5feBf6lRU1q/30OI6KOsfR9CZNXz4z7tU+cHXNSMN9VeVUMVWde039JGlcwoPZ3iF8RxzdF8lKyenNvm"
    Data.s "a4D8L7IGirwUNX/LW96yU2GKTyRKLBaFonjhKQJd1T9Vn2gC+pHViWSZqw7OdZQl8Nh0qeoYiZIviFahrkEJmI9ozLn9bW5zm6SB"
    Data.s "0chqQHsmcGMZn5YXjDdVJ/M3yWwJaIbG54NiTqKFt8DU/GkPqq6Rikt+LfinBeaqi9Yf5WG7IKiU47oEfOjG4UdbA1vb5zHFMKi8"
    Data.s "Rovk01UF8DSA6c+HBs0XiOa9T9objUblTP83nygacoav2frFmQSzS5qr96B2ey3+WTlYO2ja1k2jU9kT3emvpIEbX/yN8cRjoF00"
    Data.s "iC4uueSS4v6boj9aeAjgVTE06NMaaPHaoL8WgFPrlaHUDRr4f9azntVFEG8V/VpvHB6pimKUHm62/E3RL3qwJ7j1SsByESWxU/R6"
    Data.s "BpYgFsgos15q3j3taU9LvOtqV7taejZr8rlyogqheJPnpgCt4Rf4ljnQ3M3dHGrigp7//Od3EXjWycmf4W53u1uqiKjvEtD+WVzz"
    Data.s "2WEPAZUdnQE1EIde59Nq/q7pu+YZ49pvrdaj3Ld3puplKBFnWF1Uoy2dIUtz1N75Ovf+td0ktah1TQILs1fqh9RK2gBh2i72TUKl"
    Data.s "/YQA0Yf56vD8Xe9616QRlaRgkmcwkSNR7LQs0uew7vXcOoM5p7kOo+BZJdS0jkOtD4FmcQ25fQSDHHlOVUWaYY1UGObjPjZ8ryZ1"
    Data.s "6/uwThACz6Gt+ZMMafZDyXyqbzW/4wDoo5zwQfuJzZz6DAGsOJ+tGvRxtFe7IkzHSQsOE3avLnktHreOn+k3yvEe8KemOAuWuhkh"
    Data.s "oKa50ArRUwh5R+YWG7RncWJBCHdC+o1GX4t/Gqh+w4V3xFqmMpn9E0FCi7gwf9oPi1UI84dntbevSvtvbv+oO1+zf6w/rlD1z3jG"
    Data.s "M5ojmOFKnnPA4uhGk++CISfLXbgXinQgajoOqz6EtuKzUzQ1RT/eOQsMK0iJDvOzQ/5Dm33Ri15UhQ/rRD94cAjyfZT77V/wghf0"
    Data.s "L3/5y1N7NxxYWJassaxQboFF2e+Ey3BJFOed1xVm+rTvWBByBLr5hxJR3Ufui8aPFuPgT5aLEu7y76x+rE01vHaqz60WgAieT9ZT"
    Data.s "1pDaOefnWFy8qwwsOvksCYE08YsQ7mb7HVsA9BuCe3o+t3cOshJMzW2zBUD8AAmDJKj+Oa0n+35q6ttrS9uQ01jd8wzqoKvLzQKw"
    Data.s "5MsV/UiDGUqbYhle+MIXVt3pFEHpDuewdjsJmMREqy1JldlP5S49LSI2bhcCUHe/+90vSeY0uxLwIxtnTRCJGuziJ0iPGczfPLJ1"
    Data.s "ZWl845L01XnIeQDU52aRGPr1Sms4W79nCwatlbZL6ypZPY5zrpl+w3x+wB96dLMCTaulDvgnfTcG7dHZK17xioPGpUZ6Lf5peNYr"
    Data.s "kHd4Y8V+tH/gZGn/GB+EANO96lWvOkxPe1pcaf/N7R+aXc3+Mb53FodIqjLaCnFoJb7B4oiG8Q3/8sPX3Mu292iwZ6sOvOBDAbTi"
    Data.s "L8zB+2JVYYWswYd3Zv/T9PAbMRUseKwKtHL0gb8NeesYx6GopPilEAQSH22paGfsEN7SDbJwY3QsD+YfReWaXiU++cxnPjO1FTez"
    Data.s "VL1u2DGLn0h4MQ6hxDSNeVwPh4ulE/vCaiKeogXEDrFeODPlFLDfrMVZggZYk1rz0LAqhUv90N55gKdPwWYBwAHssLzFLW6RriIw"
    Data.s "YTLngNLhmSeEiY9NyJmJOoRs0DlgdoGktdf1jK3t+NDAsGsOkrxJbTTuBy/Uy7T5vFgb8yQBfhzgBLEhWFNtUifPhQR9aJ7xCTfn"
    Data.s "OpijoCMHmIMz/NadQKjThExDecxM90MG7rt82I7nBt9DWsv91eAf/ds7YybhUCVwlPaPuUztv9r21mXua/eP8bfsX+Z715+e/exn"
    Data.s "JxcLPsQNKRiTafk0AP6Ge83fNe/O3NBIWIrSAerw5oawd2uLyli/g0/QsUBGrgPKDJ7pO/yHG6rEH/P+p1C0Bs8SugiCrpKbP1y0"
    Data.s "JDOzL1xFJwQpXEOoqwWCHzcwAfxsgfVSOuGgJnBzOE+8+wEPeEASXAle2YXjLPFufVfLx3O/9qJzeNh+ro/NAoAFIxj/ikSm/ZI+"
    Data.s "WgAT4QMcCgwkQQKFqw1LvjSSrWyCJP41oC0tfuxnEdvgu9JGpkGQsDAb87WR+f/53fjhSdYnCTIVRiKhJHkPAT5atJpaYe0k17Km"
    Data.s "b/NGH/IQuA6DFtfcBV4zdm6Dgc0d7rX9rm0veyb6pb0NoXb/aLNl//HTslwRdodQu3+GOKzF1fi5CKTrwmXYhbsraVC3v/3tkzbq"
    Data.s "MKrxn9rjNdr21PxyxbVxxDp+VuIduT8CAAGO8iCWhDXozW9+cxU6zNth6yaDmB30gCeEKTkpYg70Ej92cN3jHvdIgoL3SJNtgTe8"
    Data.s "4Q1JwxSDIYbr6U9/elNEvv3qJoS4jdZbIBdffHEXLo90a6DG2tqyrtpn0Zq4N5aU2tix3Ld3N3w/3r3zgyBACGgRhvSJ59sDte03"
    Data.s "CwAI3QfBSioEsjm9RoPO0rPAEZJ8BpKPfiFkCQQu0QCH0r5D2EbAFErAVUB7FvCUmRjmJRiGdFbaxOaHyXhZTKa0UCYhEhhhiGXg"
    Data.s "JIHmS9pnChvO34ZgRivN/yTndlp9WyNag++XvexliZmMD8TTmstpjxM+33R4CJgNH/iR/UMILGlG+fBzdW/N/hO4SwAb7x9myJr9"
    Data.s "sxVfXD8YL20XLmhi3Bdo36Fc41ajBOA1a4CLx1j2f95/ghDtyVqhghJj7tyIcXOoe+pTn9o0FbxOAJ8ASnsAcA1ILuZAsCeWAA6N"
    Data.s "K5iUK9G15BZ8cLUIvGaBUJ6XKb8WWGzwWkGygslbgfBBAKAAcYGcDcDjXbsU0M3t1wKUxzGdEGidKzVBkPgeGuRK8n/v236obb9Z"
    Data.s "ACA1AiYrUiA/cj70aKYlIEEz9zO585+QXvWBMGh1suMtgcUiHtIuQjQHBC8qtkT4+iVA2HBxBSQJDdo7VP0fAytpZg57wgoG6kUQ"
    Data.s "gsyfCZLZDYGeJNjo7m7bwBgJoskmwFoGdJLzO62+s9nygQ98YBry/ve//2kNfVbHsW/yjRe0mOnP/nH4l/yi6BudsgI4uFjcWvZf"
    Data.s "Hp/5ViKxvP/052As7Z+tyBMpT/Dxb+Y/9iHXB826dDfcHoEzCgj/dw3PGs6Z6dw4rJ8UAGMTRvCiJdfluA88x00MPIcG3QIODO4e"
    Data.s "PC/ncoEPe8L8xu7BYd/Wi35E3Wtj3+inJSMpIRKvpThZc030f56DO/9ohAKHd6G9fAbU5oLRjombxfVsACHTe/P+Txsou/aZvc8C"
    Data.s "1srzNwsAfBeYLl+kjSj4BBHxPzBJ5espc4hBMNqR4gTvkOL0oV+HeukqjQXzoQiY4AvSlxdCEo172VXvQzpHBM9sqj1pXIINm4OJ"
    Data.s "fwkQ3n3ve9/UnikIEZo/086Nb3zjRMwlMAYz3JqgO+PDP4HDfCXvoPkIwqoxTdN+jD28woJx+K7GrTLVvrTe4/x9PL6AKhsR86i5"
    Data.s "hrp1/ujXe4fzfNhN4c9zcDo2FW/FP1y6hoqJ09oy/RGmxaHkIMQlnJsvIVLgFlNyy/7Tr2tk6N/67B/aByvM2C0wNYet+Le/CO80"
    Data.s "oMx/vA9uAFaIEmDcWeMmxNTMedgn/iPJigMf/zE265//1yay0R+coR+8p9b8n+fh0KQIgSwA4L/576X+BK+Zs2uUAL2gJTytZv/k"
    Data.s "OQhaI3ASZKaCXefeQ76qjdfgXWgvnwFDi1aJB/u9NXahRBu1v2cr9tmwtnIXwJcPIZYy3QrNVxdigDPahBk+XUPxr9/DFJH+nnp2"
    Data.s "/J02ru5I6uEqlE/LVS79DdvWjjueh3HNJV9ncRVFvzVr8Eyee+v8rd1Y/q0da+o54+a1h08vXU1xpa/Up7HH+J76bq6flmfHfbiG"
    Data.s "6Ark2kQ8+huPj/ZchawtjLFl/sZHM+OEVXM4nUpstRX/GadD+qulJXiSxEQxEW3QTyv9jsf3tyRCrpfWJNLaiv/MbzL9Zx5Uovv8"
    Data.s "uz2uTWu7Yf9oLvPATBOtPGyKjmrXgK7yNdLMD2vwmnnecBz4kFCmdv9o67oxfjO+Dl2avzXn94b28sf3tfhzFdpVR9feSuNN/b71"
    Data.s "GuDWRERr5nxcbTZbAGIiCUgetPUsgYhMLmnvw7Y0WRJULsJTEz+Q2/t32LZ23GF7/ze2+WczSqsPPc/dvy3zt3ZjtUZ7mjPTv7WL"
    Data.s "njWutYtJkIyFe6DGLGXs8XynvhvjK//d8uy4D2tmedliKh6Pj/amfGsnMf9M++Mo6zmcTkVjb8V/XteQ/lpoCe5pT9qgn1b6HY/v"
    Data.s "b5p9LWyhnzyGd57pv1ULsn+0aW03XJ/xMw/MNNHCA+boqBaH6GqYuMeaavCaed6Yl3IdtJiTXd1j9cgu4dp5w1l+b2gvf3xfiz9u"
    Data.s "K3OtifeonVfLc/bO0ALY0vZsP3tsAsDZXsiFOj6TIZMbF0i+fpSv9EQ62qIP9GzjTdyCA6jmzvbZnus+/o6BHQNHMcBtgu9wIURJ"
    Data.s "3HT74LRBzgyxHvIR1OYPOK454rWyFxJAzkcetgsAx0UJZ6kfxO/e+zj6VECO1MLnA4g8FkG7w46BHQPnFwbEYNDWxR5I5bzW+rpl"
    Data.s "1aycudhRKd/BlnGm2mYrhSvIrdaP457Lmv7+H+NA8Xha0VYNAAAAAElFTkSuQmCC"
  
  EndOfFileList:
    Data.s ""
    Data.l 0
    Data.s ""
EndDataSection
Angenommen es gäbe einen Algorithmus mit imaginärer Laufzeit O(i * n), dann gilt O((i * n)^2) = O(-1 * n^2) d.h. wenn man diesen Algorithmus verschachtelt ist er fertig, bevor er angefangen hat.
DarkDragon
Beiträge: 6267
Registriert: 29.08.2004 08:37
Computerausstattung: Hoffentlich bald keine mehr
Kontaktdaten:

Re: PureBasic, OGRE und Shaderprogrammierung

Beitrag von DarkDragon »

Das ganze noch interaktiv über die Position einer Lichtquelle:

Code: Alles auswählen

CompilerIf #PB_Unicode = 1
  CompilerError "Please compile in ASCII-mode."
CompilerEndIf

Procedure WriteBase64File(Filename.s, Content.s)
  Protected *Buffer.i
  Protected Size.i
  Protected File.i
  
  File = CreateFile(#PB_Any, Filename)
  If File
    *Buffer = AllocateMemory(Len(Content))
    If *Buffer
      Size = Base64Decoder(@Content, Len(Content), *Buffer, MemorySize(*Buffer))
      
      WriteData(File, *Buffer, Size)
      
      FreeMemory(*Buffer)
    EndIf
    CloseFile(File)
  EndIf
EndProcedure

Procedure.s EnsureEndingSlash(Path.s)
  If Right(Path, 1) <> "/"
    Path + "/"
  EndIf
  
  ProcedureReturn Path
EndProcedure

Define Path.s

Path = ReplaceString(PathRequester("Select an extraction path", ""), "\", "/")

If Path = "" Or MessageRequester("Sure?", "I may overwrite some files or directories inside this folder. Shall I continue?" + #LF$ + Path, #PB_MessageRequester_YesNo) = #PB_MessageRequester_No
  End
EndIf

Path = EnsureEndingSlash(Path)

SetCurrentDirectory(Path)

CreateDirectory(Path + "data")

Define Filename.s
Define FileContent.s
Define ContentBlock.s
Define Blocks.l
Define K.i

Restore FileList

Repeat
  Read.s Filename
  Read.l Blocks
  
  If Filename = "" Or Blocks <= 0
    Break
  EndIf
  
  FileContent = ""
  For K = 1 To Blocks
    Read.s ContentBlock
    FileContent + ContentBlock
  Next K
  
  WriteBase64File(Filename, FileContent)
ForEver

End

DataSection
  FileList:
  
  TestPB:
    Data.s "Test.pb"
    Data.l 29
    Data.s "OyBFaW5mYWNoZXMgQ2hlY2stTWFrcm8NCk1hY3JvIENoZWNrKFN0YXR1cywgRXJyb3IsIEVuZFByb2dyYW0gPSAxKQ0KICBJZiBO"
    Data.s "b3QgU3RhdHVzDQogICAgTWVzc2FnZVJlcXVlc3RlcigiRVJST1IiLCBFcnJvcikNCiAgICBDb21waWxlcklmIEVuZFByb2dyYW0N"
    Data.s "CiAgICAgIEVuZA0KICAgIENvbXBpbGVyRW5kSWYNCiAgRW5kSWYNCkVuZE1hY3JvDQoNCjsgSW5pdGlhbGlzaWVyZSBkaWUgM0Qg"
    Data.s "RW5naW5lLCBkaWUgU3ByaXRlLUxpYnJhcnkgdW5kIGRpZSBUYXN0YXR1cnN0ZXVlcnVuZw0KQ2hlY2soSW5pdEVuZ2luZTNEKCks"
    Data.s "ICJJbml0RW5naW5lM0QgZmFpbGVkLiIpDQpDaGVjayhJbml0U3ByaXRlKCksICJJbml0U3ByaXRlIGZhaWxlZC4iKQ0KQ2hlY2so"
    Data.s "SW5pdEtleWJvYXJkKCksICJJbml0S2V5Ym9hcmQgZmFpbGVkLiIpDQoNCjsgV2lyIG5laG1lbiBkZW4gZXJzdGVuIERlc2t0b3Ag"
    Data.s "enVyIEJlc3RpbW11bmcgZGVyIEF1Zmz2c3VuZw0KQ2hlY2soRXhhbWluZURlc2t0b3BzKCksICJFeGFtaW5lRGVza3RvcHMgZmFp"
    Data.s "bGVkLiIpDQoNCjsgRGVyIFVudGVyb3JkbmVyICJkYXRhIiBzb2xsIGFsbCB1bnNlcmUgTW9kZWxsZSwgVGV4dHVyZW4sIE1hdGVy"
    Data.s "aWFsLVNrcmlwdGUsIC4uLiBlbnRoYWx0ZW4uDQpBZGQzREFyY2hpdmUoImRhdGEiLCAjUEJfM0RBcmNoaXZlX0ZpbGVTeXN0ZW0p"
    Data.s "DQoNCjsg1mZmbmUgZGVuIFNjcmVlbg0KQ2hlY2soT3BlblNjcmVlbihEZXNrdG9wV2lkdGgoMCksIERlc2t0b3BIZWlnaHQoMCks"
    Data.s "IDMyLCAiU2hhZGVydGVzdCIpLCAiT3BlblNjcmVlbiBmYWlsZWQuIikNCg0KOyBMYWRlIGFsbGUgTWF0ZXJpYWwtU2tyaXB0ZQ0K"
    Data.s "UGFyc2UzRFNjcmlwdHMoKQ0KDQo7IExhZGUgZGVuIFf8cmZlbA0KQ2hlY2soTG9hZE1lc2goMCwgIkN1YmUubWVzaCIpLCAiTG9h"
    Data.s "ZE1lc2ggZmFpbGVkIikNCg0KOyBFcnpldWdlIGVpbiBFbnRpdHkgdm9uIGRlbSBX/HJmZWwgdW5kIG5pbW0gZGFzIGVudHNwcmVj"
    Data.s "aGVuZGUgTWF0ZXJpYWxza3JpcHQNCkNoZWNrKENyZWF0ZUVudGl0eSgwLCBNZXNoSUQoMCksICNQQl9NYXRlcmlhbF9Ob25lKSwg"
    Data.s "IkNyZWF0ZUVudGl0eSBmYWlsZWQiKQ0KDQo7IEhpZXIgYml0dGUgZWlnZW5lIFdlcnRlIHZlcndlbmRlbiwgZGFzcyBkZXIgV/xy"
    Data.s "ZmVsIGtvcnJla3QgYW5nZXplaWd0IHdpcmQNClNjYWxlRW50aXR5KDAsIDAuMSwgMC4xLCAwLjEpDQpSb3RhdGVFbnRpdHkoMCwg"
    Data.s "OTAuMCwgMC4wLCAxODAuMCkNCg0KOyBFcnN0ZWxsZSBlaW5lIEthbWVyYQ0KQ2hlY2soQ3JlYXRlQ2FtZXJhKDAsIDAsIDAsIDEw"
    Data.s "MCwgMTAwKSwgIkNyZWF0ZUNhbWVyYSBmYWlsZWQiKQ0KDQo7IFZlcnNjaGllYmUgc2llLCBhYmVyIGxhc3NlIHNpZSB6dXIgTnVs"
    Data.s "bHBvc2l0aW9uIHNjaGF1ZW4NCkNhbWVyYUxvY2F0ZSgwLCAtNSwgNSwgLTEwKQ0KQ2FtZXJhTG9va0F0KDAsIDAsIDAsIDApDQoN"
    Data.s "CjsgRXJzdGVsbGUgZWluZSBMaWNodHF1ZWxsZSB6dXIgS29tbXVuaWthdGlvbiBtaXQgZGVtIFNoYWRlciAoWmVpdCB3aXJkIGFs"
    Data.s "cyBYLVBvc2l0aW9uIPxiZXJnZWJlbik6DQpEZWZpbmUgVGltZS5mDQoNCkNyZWF0ZUxpZ2h0KDAsIDAsIFRpbWUsIDAuMCwgMC4w"
    Data.s "KQ0KDQo7IEhhdXB0c2NobGVpZmUNClJlcGVhdA0KICBDbGVhclNjcmVlbigwKQ0KICBSZW5kZXJXb3JsZCgpIDsgcmVuZGVydCBh"
    Data.s "bGxlcw0KICBGbGlwQnVmZmVycygpDQogIA0KICA7IFBy/GZlIGF1ZiBUYXN0YXR1cmVpbmdhYmVuDQogIEV4YW1pbmVLZXlib2Fy"
    Data.s "ZCgpDQogIElmIEtleWJvYXJkUHVzaGVkKCNQQl9LZXlfTGVmdCkNCiAgICBUaW1lIC0gMC4wMjUNCiAgICBMaWdodExvY2F0ZSgw"
    Data.s "LCBUaW1lLCAwLjAsIDAuMCkNCiAgRWxzZUlmIEtleWJvYXJkUHVzaGVkKCNQQl9LZXlfUmlnaHQpDQogICAgVGltZSArIDAuMDI1"
    Data.s "DQogICAgTGlnaHRMb2NhdGUoMCwgVGltZSwgMC4wLCAwLjApDQogIEVuZElmDQpVbnRpbCBLZXlib2FyZFB1c2hlZCgjUEJfS2V5"
    Data.s "X0VzY2FwZSkNCkVuZA0KOyBJREUgT3B0aW9ucyA9IFB1cmVCYXNpYyA0LjYwIEJldGEgMyAoV2luZG93cyAtIHg2NCkNCjsgQ3Vy"
    Data.s "c29yUG9zaXRpb24gPSA1OA0KOyBGaXJzdExpbmUgPSA5DQo7IEZvbGRpbmcgPSAtDQo7IEVuYWJsZVhQDQo7IEV4ZWN1dGFibGUg"
    Data.s "PSBUZXN0LmV4ZQ=="

    
  CubeMESH:
    Data.s "data/Cube.mesh"
    Data.l 23
    Data.s "ABBbTWVzaFNlcmlhbGl6ZXJfdjEuNDBdCgAwEwYAAAAAQNMBAABDdWJlTWF0ZXJpYWwKACQAAAAAAAABAAIAAQADAAIAAgADAAQA"
    Data.s "AwAFAAQABAAFAAYABQAHAAYABgAHAAAABwABAAAABgAAAAQAAAACAAQAAQAHAAMABwAFAAMAAFDAAQAACAAAAABRRgAAABBREAAA"
    Data.s "AAAAAgABAAAAAAAQURAAAAAAAAIABAAMAAAAEFEQAAAAAAABAAcAGAAAABBREAAAAAAAAgAJACAAAAAAUnABAAAAACwAEFJmAQAA"
    Data.s "AACgwQAAoEEAAKBBAAAAAAAAgD8AAAAAAAAAAAAAgD8AAIA/AAAAAAAAAAAAAKDBAACgwQAAoEEAAAAAAACAvwAAAAAAAAAAAAAA"
    Data.s "AA8seT8AAAAA9etqvgAAoEEAAKBBAACgQQAAAAAAAIA/AAAAAAAAgD8AAIA/Dyx5PwAAAAD162o+AACgQQAAoMEAAKBBAAAAAAAA"
    Data.s "gL8AAAAAAACAPwAAAAAAAIA/AAAAAAAAAAAAAKBBAACgQQAAoMEAAAAAAACAPwAAAAAAAIA/AAAAAAAAgD8AAAAAAAAAAAAAoEEA"
    Data.s "AKDBAACgwQAAAAAAAIC/AAAAAAAAgD8AAIA/Dyx5PwAAAAD162q+AACgwQAAoEEAAKDBAAAAAAAAgD8AAAAAAAAAAAAAAAAPLHk/"
    Data.s "AAAAAPXraj4AAKDBAACgwQAAoMEAAAAAAACAvwAAAAAAAAAAAACAPwAAgD8AAAAAAAAAABBACAAAAAQAAJAiAAAAAACgwQAAoMEA"
    Data.s "AKDBAACgQQAAoEEAAKBBZ5AKQgCgBgAAAACwMAQAAACxKgQAAAAAAAEMAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAACAAAAAAAAAAEA"
    Data.s "AAACAAAAAAAAgAAAAAAAAMhEAAD6xgAAAAAAAAAAAQAAAAMAAAACAAAAAQAAAAMAAAACAAAAAAAAAAAAAAAAAMhEAAD6xgAAAAAA"
    Data.s "AAAAAgAAAAMAAAAEAAAAAgAAAAMAAAAEAAAAAADIRAAAAAAAAAAAAAD6xgAAAAAAAAAAAwAAAAUAAAAEAAAAAwAAAAUAAAAEAAAA"
    Data.s "AADIRAAAAAAAAAAAAAD6xgAAAAAAAAAABAAAAAUAAAAGAAAABAAAAAUAAAAGAAAAAAAAgAAAAIAAAMjEAAD6xgAAAAAAAAAABQAA"
    Data.s "AAcAAAAGAAAABQAAAAcAAAAGAAAAAAAAAAAAAAAAAMjEAAD6xgAAAAAAAAAABgAAAAcAAAAAAAAABgAAAAcAAAAAAAAAAADIxAAA"
    Data.s "AAAAAAAAAAD6xgAAAAAAAAAABwAAAAEAAAAAAAAABwAAAAEAAAAAAAAAAADIxAAAAAAAAAAAAAD6xgAAAAAAAAAABgAAAAAAAAAE"
    Data.s "AAAABgAAAAAAAAAEAAAAAAAAAAAAyEQAAAAAAAD6xgAAAAAAAAAAAAAAAAIAAAAEAAAAAAAAAAIAAAAEAAAAAAAAgAAAyEQAAAAA"
    Data.s "AAD6xgAAAAAAAAAAAQAAAAcAAAADAAAAAQAAAAcAAAADAAAAAAAAAAAAyMQAAAAAAAD6xgAAAAAAAAAABwAAAAUAAAADAAAABwAA"
    Data.s "AAUAAAADAAAAAAAAAAAAyMQAAAAAAAD6xhCx2AEAAAAAAAAAAAAADAAAABIAAAAAAAAABwAAAAAAAAABAAAAAAAAAAEAAAAAAAAA"
    Data.s "AAEAAAABAAAAAgAAAAEAAAACAAAAAAAAAAAJAAAAAgAAAAAAAAACAAAAAAAAAAABAAAACgAAAAEAAAADAAAAAQAAAAMAAAAAAQAA"
    Data.s "AAIAAAADAAAAAgAAAAMAAAACAAAAAAIAAAADAAAAAwAAAAQAAAADAAAABAAAAAACAAAACQAAAAQAAAACAAAABAAAAAIAAAAAAwAA"
    Data.s "AAsAAAADAAAABQAAAAMAAAAFAAAAAAMAAAAEAAAABQAAAAQAAAAFAAAABAAAAAAEAAAABQAAAAUAAAAGAAAABQAAAAYAAAAABAAA"
    Data.s "AAgAAAAGAAAABAAAAAYAAAAEAAAAAAUAAAALAAAABQAAAAcAAAAFAAAABwAAAAAFAAAABgAAAAcAAAAGAAAABwAAAAYAAAAABgAA"
    Data.s "AAcAAAAHAAAAAAAAAAcAAAAAAAAAAAYAAAAIAAAAAAAAAAYAAAAAAAAABgAAAAAHAAAACgAAAAcAAAABAAAABwAAAAEAAAAACAAA"
    Data.s "AAkAAAAAAAAABAAAAAAAAAAEAAAAAAoAAAALAAAABwAAAAMAAAAHAAAAAwAAAAA="
    
  CubeMaterialMATERIAL:
    Data.s "data/CubeMaterial.material"
    Data.l 19
    Data.s "Ly8gVmVydGV4c2hhZGVyDQovLyBOYW1lOiBjdWJlVGVzdFZTDQovLyBUeXA6ICBobHNsDQp2ZXJ0ZXhfcHJvZ3JhbSBjdWJlVGVz"
    Data.s "dFZTIGhsc2wNCnsNCiAgLy8gRGF0ZWk6IGN1YmV0ZXN0X3ZzLmhsc2wgZW50aORsdCBkZW4gUXVlbGx0ZXh0IGRlcyBWZXJ0ZXhz"
    Data.s "aGFkZXJzDQogIHNvdXJjZSBjdWJldGVzdF92cy5obHNsDQoNCiAgLy8gRnVua3Rpb24sIGRpZSB6dWVyc3QgYXVmZ2VydWZlbiB3"
    Data.s "aXJkOiBtYWluDQogIGVudHJ5X3BvaW50IG1haW4NCg0KICAvLyBTaGFkZXJ2ZXJzaW9uDQogIHRhcmdldCB2c18zXzANCiAgDQog"
    Data.s "IGRlZmF1bHRfcGFyYW1zDQogIHsNCiAgICAvLyBWZXJ0ZXhzaGFkZXIgc2luZCBhdWNoIGb8ciBkaWUga29ycmVrdGUgVHJhbnNm"
    Data.s "b3JtYXRpb24gZGVyIFZlcnRpemVuIHp1c3TkbmRpZy4NCiAgICAvLyBBdXMgZGllc2VtIEdydW5kIGJlbvZ0aWdlbiB3aXIgZGll"
    Data.s "IFdvcmxkVmlld1Byb2otTWF0cml4Lg0KICAgIA0KICAgIHBhcmFtX25hbWVkX2F1dG8gd29ybGRWaWV3UHJvaiAgICAgIHdvcmxk"
    Data.s "dmlld3Byb2pfbWF0cml4DQogIH0NCn0NCg0KLy8gRnJhZ21lbnRzaGFkZXINCi8vIE5hbWU6IGN1YmVUZXN0UFMNCi8vIFR5cDog"
    Data.s "IGhsc2wNCmZyYWdtZW50X3Byb2dyYW0gY3ViZVRlc3RQUyBobHNsDQp7DQogIC8vIERhdGVpOiBjdWJldGVzdF9wcy5obHNsIGVu"
    Data.s "dGjkbHQgZGVuIFF1ZWxsdGV4dCBkZXMgRnJhZ21lbnRzaGFkZXJzDQogIHNvdXJjZSBjdWJldGVzdF9wcy5obHNsDQogIA0KICAv"
    Data.s "LyBGdW5rdGlvbiwgZGllIHp1ZXJzdCBhdWZnZXJ1ZmVuIHdpcmQ6DQogIGVudHJ5X3BvaW50IG1haW4NCg0KICAvLyBTaGFkZXJ2"
    Data.s "ZXJzaW9uDQogIHRhcmdldCBwc18zXzANCiAgDQogIGRlZmF1bHRfcGFyYW1zDQogIHsNCiAgICAvLyBEaWUgVmFyaWFibGUgY3Vy"
    Data.s "cmVudFRpbWUgaXN0IGltIFNoYWRlciB1bmQgZW50aORsdCBkZW4gT0dSRSBlaWdlbmVuIFplaXR3ZXJ0DQogICAgcGFyYW1fbmFt"
    Data.s "ZWRfYXV0byBjdXJyZW50VGltZSBsaWdodF9wb3NpdGlvbiAwDQogIH0NCn0NCg0KbWF0ZXJpYWwgQ3ViZU1hdGVyaWFsDQp7DQog"
    Data.s "IHRlY2huaXF1ZQ0KICB7DQogICAgcGFzcw0KICAgIHsNCiAgICAgIGFtYmllbnQgMC4yIDAuMiAwLjIgMQ0KICAgICAgZGlmZnVz"
    Data.s "ZSAwLjggMC44IDAuOCAxDQoNCiAgICAgIHRleHR1cmVfdW5pdA0KICAgICAgew0KICAgICAgICB0ZXh0dXJlIGZvbnQucG5nIC0x"
    Data.s "DQogICAgICB9DQoNCiAgICAgIC8vIEVpbiBWZXJ3ZWlzIGF1ZiBkaWUgMiBTaGFkZXJwcm9ncmFtbWU6DQogICAgICB2ZXJ0ZXhf"
    Data.s "cHJvZ3JhbV9yZWYgY3ViZVRlc3RWUw0KICAgICAgew0KICAgICAgfQ0KDQogICAgICBmcmFnbWVudF9wcm9ncmFtX3JlZiBjdWJl"
    Data.s "VGVzdFBTDQogICAgICB7DQogICAgICB9DQogICAgfQ0KICB9DQp9"
    
  cubetest_psHLSL:
    Data.s "data/cubetest_ps.hlsl"
    Data.l 72
    Data.s "c2FtcGxlciBmb250VGV4dHVyZTogcmVnaXN0ZXIoczApOw0KDQp1bmlmb3JtIGZsb2F0NCBjdXJyZW50VGltZTsNCg0KZmxvYXQ0"
    Data.s "IGRyYXdDaGFyKGZsb2F0MiB0ZXhDb29yZCwgaW50IGNoYXJhY3RlciwgZmxvYXQyIGNvb3JkcywgZmxvYXQyIHNpemUpDQp7DQog"
    Data.s "IC8vIFdpciBzZXR6ZW4gZGVuIFN0YW5kYXJkLVL8Y2tnYWJld2VydCBhdWYgU2Nod2Fyei4NCiAgZmxvYXQ0IHJlc3VsdCA9IGZs"
    Data.s "b2F0NCgwLjBmLCAwLjBmLCAwLjBmLCAxLjBmKTsNCiAgDQogIC8vIERhcyBBcmd1bWVudCB0ZXhDb29yZCBpc3QgZGllIFRleHR1"
    Data.s "cmtvb3JkaW5hdGUgdW5zZXJlcyBha3R1ZWxsZW4gRnJhZ21lbnRzLA0KICAvLyBjb29yZHMgZGllIFBvc2l0aW9uIHVuc2VyZXMg"
    Data.s "WmVpY2hlbnMgYXVmIGRlbSBPYmpla3QNCiAgLy8gdW5kIHNpemUgZGllIGdy9t9lIGRlcyBkYXJ6dXN0ZWxsZW5kZW4gWmVpY2hl"
    Data.s "bnMuDQogIC8vIE51biB3aXJkIHRleENvb3JkIHJlbGF0aXYgenUgZGVtIEJlcmVpY2ggZ2VzZWhlbjoNCiAgZmxvYXQyIG5vcm1h"
    Data.s "bGl6ZWRUZXhDb29yZCA9ICh0ZXhDb29yZCAtIGNvb3JkcykgLyBzaXplOw0KICANCiAgLy8gbnVyIHdlbm4gbm9ybWFsaXplZFRl"
    Data.s "eENvb3JkIGltIEJlcmVpY2ggMC4uMSBsaWVndCBpc3QgZGFzIEZyYWdtZW50IGltIEJlcmVpY2ggZGVzIGRhcnp1c3RlbGxlbmRl"
    Data.s "biBaZWljaGVucyBhdWYgZGVtIE9iamVrdC4NCiAgaWYobm9ybWFsaXplZFRleENvb3JkLnggPj0gMC4wZiAmJiBub3JtYWxpemVk"
    Data.s "VGV4Q29vcmQueSA+PSAwLjBmICYmIG5vcm1hbGl6ZWRUZXhDb29yZC54IDwgMS4wZiAmJiBub3JtYWxpemVkVGV4Q29vcmQueSA8"
    Data.s "IDEuMGYpDQogIHsNCiAgICAvLyB3aXIgaGFiZW4gZWluZW4gWmVpY2hlbnNhdHosIGRlciBiZWkgMzIgKExlZXJ6ZWljaGVuKSBh"
    Data.s "bmbkbmd0LiBEYWhlciBzdWJ0cmFoaWVyZSBlcnN0bWFsIGRpZSAzMiB2b24gZGVtIFplaWNoZW4NCiAgICBjaGFyYWN0ZXIgLT0g"
    Data.s "MzI7DQogICAgDQogICAgLy8gZmluZGUgZGllIGVudHNwcmVjaGVuZGUgVGV4dHVya29vcmRpbmF0ZSBhdWYgdW5zZXJlbSBaZWlj"
    Data.s "aGVuc2F0eg0KICAgIGZsb2F0MiBjaGFyQ29vcmQ7DQoNCiAgICAvLyAzMiBaZWljaGVuIHBybyBaZWlsZSwgMyBaZWlsZW4gaW5z"
    Data.s "Z2VzYW10DQogICAgY2hhckNvb3JkLnkgPSBmbG9hdChjaGFyYWN0ZXIgLyAzMik7DQogICAgY2hhckNvb3JkLnggPSBmbG9hdChj"
    Data.s "aGFyYWN0ZXIpIC0gY2hhckNvb3JkLnkgKiAzMi4wZjsNCiAgICANCiAgICBjaGFyQ29vcmQgKz0gbm9ybWFsaXplZFRleENvb3Jk"
    Data.s "Ow0KICAgIGNoYXJDb29yZCAqPSBmbG9hdDIoMS4wZiAvIDMyLjBmLCAxLjBmIC8gMy4wZik7DQogICAgDQogICAgLy8gZ2ViZSBk"
    Data.s "ZW4gVGV4dHVyd2VydCB6dXL8Y2sNCiAgICByZXN1bHQgPSB0ZXgyRChmb250VGV4dHVyZSwgY2hhckNvb3JkKTsNCiAgfQ0KICAN"
    Data.s "CiAgcmV0dXJuIHJlc3VsdDsNCn0NCg0KZmxvYXQ0IGRyYXdDaXJjbGUoZmxvYXQyIHRleENvb3JkLCBmbG9hdDIgY2VudGVyLCBm"
    Data.s "bG9hdCByYWRpdXMpDQp7DQogIGZsb2F0NCByZXN1bHQgPSBmbG9hdDQoMC4wZiwgMC4wZiwgMC4wZiwgMS4wZik7DQogIA0KICAv"
    Data.s "LyBBYnN0YW5kIFRleHR1cmtvb3JkaW5hdGUgdm9tIEtyZWlzemVudHJ1bSA8IEtyZWlzcmFkaXVzPw0KICBpZihsZW5ndGgodGV4"
    Data.s "Q29vcmQgLSBjZW50ZXIpIDw9IHJhZGl1cykNCiAgew0KICAgIHJlc3VsdCA9IGZsb2F0NCgxLjBmLCAxLjBmLCAxLjBmLCAxLjBm"
    Data.s "KTsNCiAgfQ0KICByZXR1cm4gcmVzdWx0Ow0KfQ0KDQpmbG9hdDQgZHJhd0xpbmUoZmxvYXQyIHRleENvb3JkLCBmbG9hdDIgc3Rh"
    Data.s "cnQsIGZsb2F0MiBlbmQsIGZsb2F0IHdpZHRoKQ0Kew0KICBmbG9hdDQgcmVzdWx0ID0gZmxvYXQ0KDAuMGYsIDAuMGYsIDAuMGYs"
    Data.s "IDEuMGYpOw0KDQogIC8vIFJpY2h0dW5nIGRlciBHZXJhZGVuDQogIGZsb2F0MiBkaXIgPSBlbmQgLSBzdGFydDsNCiAgDQogIC8v"
    Data.s "IFZlcnNjaGllYmUgYWxsZXMsIHNvZGFzcyB0ZXhDb29yZCBhdWYgZGVtIFVyc3BydW5nIGxpZWd0DQogIHN0YXJ0IC09IHRleENv"
    Data.s "b3JkOw0KICANCiAgLy8gQmVyZWNobmUgZGFzIExhbWJkYSBkZXIgR2VyYWRlbmdsZWljaHVuZyB2ID0gc3RhcnQgKyBsYW1iZGEg"
    Data.s "KiBkaXIsIHNvZGFzcyB2IGRlciBMb3Rmdd9wdW5rdCBpc3QuDQogIC8vIEVzIHNvbGwgYWJlciBpbW1lciBhdWYgZGVyIEdlcmFk"
    Data.s "ZW4gYmxlaWJlbiwgZGVzaGFsYiBkYXJmIGxhbWJkYSBudXIgaW0gQmVyZWljaCAwLi4xIGJsZWliZW4uDQogIA0KICBmbG9hdCBs"
    Data.s "YW1iZGEgPSBjbGFtcCgtMS4wZiAqIChzdGFydC54KmRpci54ICsgc3RhcnQueSpkaXIueSkgLyAoZGlyLnggKiBkaXIueCArIGRp"
    Data.s "ci55ICogZGlyLnkpLCAwLjBmLCAxLjBmKTsNCiAgDQogIC8vIFdlbm4gZGVyIEFic3RhbmQgZGVzIFB1bmt0ZXMgenUgdW5zZXJl"
    Data.s "ciB0ZXhDb29yZCAobnVuIGRlciBVcnNwcnVuZykga2xlaW5lciBhbHMgZGllIEdlcmFkZW5icmVpdGUgaXN0LCBnZWJlIFdlad8g"
    Data.s "enVy/GNrLg0KICBpZihsZW5ndGgoc3RhcnQgKyBsYW1iZGEgKiBkaXIpIDw9IHdpZHRoKQ0KICB7DQogICAgcmVzdWx0ID0gZmxv"
    Data.s "YXQ0KDEuMGYsIDEuMGYsIDEuMGYsIDEuMGYpOw0KICB9DQogIHJldHVybiByZXN1bHQ7DQp9DQoNCi8vIEVpbmdhYmU6IEZyYWdt"
    Data.s "ZW50LVRleHR1cmtvb3JkaW5hdGUgdW5kIEZyYWdtZW50LVBvc2l0aW9uDQpmbG9hdDQgbWFpbihmbG9hdDIgdGV4Q29vcmQ6IFRF"
    Data.s "WENPT1JEMCwNCiAgICAgICAgICAgIGZsb2F0NCBwb3M6IFBPU0lUSU9ODQogICAgICAgICAgICApIDogQ09MT1IwDQp7DQogIGZs"
    Data.s "b2F0IHdlaWdodDsNCiAgDQogIC8vIEhpbnRlcmdydW5kZmFyYmU6IFNjaHdhcnouDQogIGZsb2F0NCByZXN1bHQgPSBmbG9hdDQo"
    Data.s "MC4wZiwgMC4wZiwgMC4xZiwgMS4wZik7DQogIA0KICAvLyBXaXIgYWRkaWVyZW4genVu5GNoc3QgZGllIEZhcmJ3ZXJ0ZSBkZXMg"
    Data.s "S3JlaXNlcywgZGVuIHdpciB6ZW50cmllcnQgWmVpY2huZW4gd29sbGVuIG11bHRpcGxpemllcnQgbWl0IEdlbGIsDQogIC8vIGQu"
    Data.s "aC4gd2VubiBkcmF3Q2lyY2xlIFdlad8genVy/GNrZ2lidCB3aXJkIDEwMCUgR2VsYiBkYXJhdXMgdW5kIGJlaSBTY2h3YXJ6IGJs"
    Data.s "ZWlidCBlcyBTY2h3YXJ6Lg0KICByZXN1bHQgKz0gZHJhd0NpcmNsZSh0ZXhDb29yZCwgZmxvYXQyKDAuNWYsIDAuNWYpLCAwLjNm"
    Data.s "KSAqIGZsb2F0NCgxLjBmLCAxLjBmLCAwLjBmLCAxLjBmKTsNCiAgDQogIC8vIEb8ciB1bnNlcmUgTGluaWUgd29sbGVuIHdpciBu"
    Data.s "aWNodCBkaWUgRmFyYmUgbXVsdGlwbGl6aWVydCBtaXQgQmxhdSBhZGRpZXJlbiwNCiAgLy8gc29uc3Qgd/xyZGUgR2VsYiB2b20g"
    Data.s "S3JlaXMgKyBCbGF1IHZvbiBkZXIgTGluaWUgPSBXZWnfIGVyZ2ViZW4uIFdpciB3b2xsZW4NCiAgLy8gZGllIExpbmllIGtvbXBs"
    Data.s "ZXR0IGluIEJsYXUgaGFiZW4uDQogIC8vIERlc2hhbGIgbmVobWVuIHdpciBkaWUgTORuZ2UgZGVzIEZhcmJ2ZWt0b3JzIChhdd9l"
    Data.s "ciBhbHBoYSkgYWxzIEdld2ljaHR1bmcuDQogIC8vIERhcyBBbmjkbmdzZWwgLnh5eiBlcnN0ZWxsdCBhdXMgZGVtIGZsb2F0NCBl"
    Data.s "aW5mYWNoIGVpbmVuIGZsb2F0MyBWZWt0b3IgbWl0DQogIC8vIGRlbiB4LCB5IHVuZCB6IEtvbXBvbmVudGVuIGRlcyB1cnNwcvxu"
    Data.s "Z2xpY2hlbiBmbG9hdDQgVmVrdG9ycyB1bmQgc2NobGll33QNCiAgLy8gc29taXQgZGVuIEFscGhhLVdlcnQgYXVzLg0KICAvLyBE"
    Data.s "aWUgTGluaWUgc29sbCBpbSBaZW50cnVtIGFuZmFuZ2VuIHVuZCBkdXJjaCBkZW4gY3VycmVudFRpbWUtV2VydCByb3RpZXJlbi4N"
    Data.s "CiAgd2VpZ2h0ID0gbGVuZ3RoKGRyYXdMaW5lKHRleENvb3JkLCBmbG9hdDIoMC41ZiwgMC41ZiksIGZsb2F0MigwLjVmLCAwLjVm"
    Data.s "KSArIGZsb2F0Mihjb3MoY3VycmVudFRpbWUueCksIHNpbihjdXJyZW50VGltZS54KSkgKiAwLjVmLCAwLjAxZikueHl6KSAqIDAu"
    Data.s "NWY7DQogIA0KICAvLyBXaXIgR2V3aWNodGVuIG51biBEdW5rZWxibGF1IG1pdCB3ZWlnaHQgdW5kIGRlbiBhbHRlbiByZXN1bHQt"
    Data.s "V2VydCBtaXQgKDEuMCAtIHdlaWdodCkNCiAgcmVzdWx0ID0gd2VpZ2h0ICogZmxvYXQ0KDAuMGYsIDAuMGYsIDAuNGYsIDEuMGYp"
    Data.s "ICsgKDEuMCAtIHdlaWdodCkgKiByZXN1bHQ7DQogIA0KICAvLyBEYSB3aXIgd2lzc2VuLCBkYXNzIHNpY2ggZGVyIFRleHQgbmlj"
    Data.s "aHQg/GJlcnNjaG5laWRldCwgYWRkaWVyZW4gd2lyDQogIC8vIGVpbmZhY2ggZGllIGVpbnplbG5lbiBXZXJ0ZSB2b24gZGVuIGpl"
    Data.s "d2VpbGlnZW4gWmVpY2hlbiBhbiBpaHJlcg0KICAvLyBqZXdlaWxpZ2VuIFBvc2l0aW9uOg0KICBmbG9hdDQgdGV4dCA9IGZsb2F0"
    Data.s "NCgwLjBmLCAwLjBmLCAwLjBmLCAxLjBmKTsNCiAgDQogIGZsb2F0MiBjaGFyU2l6ZSA9IGZsb2F0MigwLjA1ZiwgMC4wNWYpOw0K"
    Data.s "ICANCiAgdGV4Q29vcmQgLT0gZmxvYXQyKDAuMmYsIDAuMmYpOw0KDQogIHRleHQgKz0gZHJhd0NoYXIodGV4Q29vcmQsICdIJywg"
    Data.s "ZmxvYXQyKDAuMDBmLCAwLjBmKSwgY2hhclNpemUpOw0KICB0ZXh0ICs9IGRyYXdDaGFyKHRleENvb3JkLCAnYScsIGZsb2F0Migw"
    Data.s "LjA1ZiwgMC4wZiksIGNoYXJTaXplKTsNCiAgdGV4dCArPSBkcmF3Q2hhcih0ZXhDb29yZCwgJ2wnLCBmbG9hdDIoMC4xMGYsIDAu"
    Data.s "MGYpLCBjaGFyU2l6ZSk7DQogIHRleHQgKz0gZHJhd0NoYXIodGV4Q29vcmQsICdsJywgZmxvYXQyKDAuMTVmLCAwLjBmKSwgY2hh"
    Data.s "clNpemUpOw0KICB0ZXh0ICs9IGRyYXdDaGFyKHRleENvb3JkLCAnbycsIGZsb2F0MigwLjIwZiwgMC4wZiksIGNoYXJTaXplKTsN"
    Data.s "CiAgdGV4dCArPSBkcmF3Q2hhcih0ZXhDb29yZCwgJywnLCBmbG9hdDIoMC4yNWYsIDAuMGYpLCBjaGFyU2l6ZSk7DQogIA0KICB0"
    Data.s "ZXh0ICs9IGRyYXdDaGFyKHRleENvb3JkLCAnUCcsIGZsb2F0MigwLjM1ZiwgMC4wZiksIGNoYXJTaXplKTsNCiAgdGV4dCArPSBk"
    Data.s "cmF3Q2hhcih0ZXhDb29yZCwgJ0InLCBmbG9hdDIoMC40MGYsIDAuMGYpLCBjaGFyU2l6ZSk7DQogIHRleHQgKz0gZHJhd0NoYXIo"
    Data.s "dGV4Q29vcmQsICchJywgZmxvYXQyKDAuNDVmLCAwLjBmKSwgY2hhclNpemUpOw0KDQogIC8vIEVyc3RlbGxlIHdpZWRlciBlaW5l"
    Data.s "biBHZXdpY2h0dW5nc3dlcnQgYXVzIHRleHQueHl6IHdpZSBiZWkgZGVyIExpbmllIGF1Y2g6DQogIHdlaWdodCA9IGxlbmd0aCh0"
    Data.s "ZXh0Lnh5eikgKiAwLjVmOw0KICANCiAgLy8gVW5kIGdld2ljaHRlIGV4YWt0IHdpZSBiZWkgZGVyIExpbmllLCBudXIgbWl0IFJv"
    Data.s "dCBzdGF0dCBEdW5rZWxibGF1Og0KICByZXN1bHQgPSB3ZWlnaHQgKiBmbG9hdDQoMS4wZiwgMC4wZiwgMC4wZiwgMS4wZikgKyAo"
    Data.s "MS4wIC0gd2VpZ2h0KSAqIHJlc3VsdDsNCiAgDQogIC8vIEdlYmUgZGVuIEZhcmJ3ZXJ0IHp1cvxjaw0KICByZXR1cm4gcmVzdWx0"
    Data.s "Ow0KfQ=="
    
  cubetest_vsHLSL:
    Data.s "data/cubetest_vs.hlsl"
    Data.l 5
    Data.s "c3RydWN0IFZTX1JFU1VMVCB7DQogIGZsb2F0MiB0ZXhDb29yZDogIFRFWENPT1JEMDsNCiAgZmxvYXQ0IHBvczogICAgICAgUE9T"
    Data.s "SVRJT047DQp9Ow0KDQp1bmlmb3JtIGZsb2F0NHg0IHdvcmxkVmlld1Byb2o7DQoNClZTX1JFU1VMVCBtYWluKGZsb2F0NCBwb3M6"
    Data.s "IFBPU0lUSU9OLA0KICAgICAgICAgICAgICAgZmxvYXQyIHRleENvb3JkMDogVEVYQ09PUkQwDQogICAgICAgICAgICAgICkNCnsN"
    Data.s "CiAgIFZTX1JFU1VMVCByZXN1bHQ7DQoNCiAgIHJlc3VsdC5wb3MgICAgICAgID0gbXVsKHdvcmxkVmlld1Byb2osIHBvcyk7DQog"
    Data.s "ICByZXN1bHQudGV4Q29vcmQgICA9IHRleENvb3JkMDsNCiAgIA0KICAgcmV0dXJuIHJlc3VsdDsNCn0="
    
  fontPNG:
    Data.s "data/font.png"
    Data.l 213
    Data.s "iVBORw0KGgoAAAANSUhEUgAAAgAAAABACAYAAABsv8+/AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQA"
    Data.s "AA7EAZUrDhsAAD3hSURBVHhe7d0J2HZdNTjw0xeJkDI1mIeQhJRIShmiFJEiVFRfVEoD+RJ9hlDGMkRp0Ch9DXzJLESJKEQTGZM5"
    Data.s "88z5r9++/vt2nvOec/be5zzP875v71nXdV/v+9z32dM6a6+9pr3WFbqu6+Ozw46BHQM7BnYM7BjYMXABYeCiC2it+1J3DOwY2DGw"
    Data.s "Y2DHwI6B/4+BXQDYSWHHwI6BHQM7BnYMXIAYOBYB4KKLLuqucpWrdFe84hWbUajN273d26V2V7jCFVI//l0Db/u2b9u91Vu91aHp"
    Data.s "+O9Sn1e72tW6P/zDP+w+5EM+pPToGb8b6+3f/u07/47hSle60mGNSx3DxZWvfOX0eeu3fuuqOcAV/K3B/XiAt3mbt6ked9jWmte+"
    Data.s "s9yP9Rp/h/UY2PIevL9Me1M03DIr9NhKD3iIcdGAeQz3ce3YxzX/vKdqx/Vcnrd/h/9f00fL+s0V3rTJY+d/fV/LFzL+9bP2/R8X"
    Data.s "/ltwtj/7fxjI+G85P7QWA7Dpc/HFF/fgQQ96UHM/97rXvVLbT/iET+g/+7M/O/3/Ez/xE5v7+eAP/uD+b//2b/sHPvCBqe11r3vd"
    Data.s "/u///u/7e9/73sW+guD7H/iBH0hjZ3jRi17Ux8FdbGusm9/85v1//dd/Hdpe4xrXONLuJS95Sf+bv/mbi33FBuyf9rSnHfr4vd/7"
    Data.s "vf6d3umdiuPf7GY3S228gy3vMYim/6Vf+qX+fve7X1M/ITT1v/3bv91/7ud+blO78Vwf+9jH9s997nP7YPyb+tmCg/O57Yd+6If2"
    Data.s "f/mXf5nofs06Lr300iP0f9vb3nZVP9e61rVSP5/0SZ9U3d4+m9p/aLJ2LV/3dV93ZP4PfehDq9uOx/j6r//61NeHf/iHV/XxgR/4"
    Data.s "gf0b3/jGI+P74w1veEP/Pu/zPlV9fMZnfMaR9j/3cz/Xh1BcbPvxH//xZ4w7/MJaSjgMgaH//u///iP9XHLJJcV2uV+86zjxX5rv"
    Data.s "/vuZ5/UY/84PvLkCV9sOfwN8/ud/fiIeh3nFgEeeuctd7tL/4z/+Y/8xH/Mx/a1vfevUz01vetPmfmyE3/qt3+o/4AM+ILV1KP/6"
    Data.s "r/96H9r8Yl+Yj4MH/NVf/VX/3//93/2b3vSm9PcLX/jCvsSEQuvvf+d3fqd/ylOeksb55V/+5f7Xfu3XDmPe5CY36f/u7/6u/7iP"
    Data.s "+7jFeXzN13xNGhMT/7M/+7P0/2c/+9nFA/HGN75x/x//8R/9F3zBFzTjbPiuvuRLvqT/jd/4jVqiOTIWwe9nfuZn+nd+53dunkNo"
    Data.s "i/37vd/79Y9+9KP77/qu7+ox03d7t3dr7qeV7t7SnrcHX/GKV/Rj4bNmnfYg+Kd/+qf+T/7kT/p///d/T/ugRLPjvq95zWseDsKP"
    Data.s "/diPrXqHoaH23/u935vG/4u/+IvUPh+m9m8NLRBawZvf/Ob+T//0T/u/+Zu/SX+3HGJ5LfYr+PM///Mi78htPvIjPzLxDnzM3jV/"
    Data.s "c3j+85/fw0npHWT++Q//8A9p/vAAnvzkJxfbfsRHfESaK56Vcecd/ud//mfqo6QAhQWhf8xjHpOe/eu//uv0/s0DfMVXfEVxfO/v"
    Data.s "e77ne9Lz1m/+cAG+9mu/tti+hJv99/L5TOkd0v9w/xDICzgsD1B6CVsEAJqjjXvDG96w/5RP+ZS0EIdaacz8+/u///v37/me75k0"
    Data.s "19/93d9NgsR7vMd79F/+5V+eGGKJEREQwC/+4i/27/Iu79LT/Gmh97nPfZLWXtICaFwY5/3vf/80Zwfpv/7rv/YEA3//4A/+YP9D"
    Data.s "P/RDi+sx7i/8wi/0r3vd6w7PvfzlL+9f9apX9e/93u+92PZGN7pR/8///M+bNPB3f/d371/60pf2D3/4w6vxPnw/H/RBH5SEr0//"
    Data.s "9E9vbn/HO94xHTisN4Qf/3/605/e3I/5YEYEiHd4h3dY1b6W5s7F5x72sIf1L3jBC/p3fMd3bFo7OkXnmDdasrZb3epWaU/8yI/8"
    Data.s "SFEA9TwLGmHh9a9/fWoHSvsu4/B617teep4GOsSrwwd85md+5uJ6rNe+d3DZ9/ogVDoA7Sl7q/Z9UQZe9rKX9f/7v/+bDtSS8pD7"
    Data.s "ZS1Bv5SO2rHyc+HyTAoEK9rw3f3+7/9+eietQlju19p/9md/tkgP3r+Dn9KSeRaeBp761KcW3z/La8YXHp7Hx8sIEhSzVpycK89T"
    Data.s "aK5+9auf6PwpmM6vtWt+13d913TehOv6QP/6+smf/Mn0Dr/0S790se9jiQHI/r5Wv19MtAszWRebpwsi7P74j/84/Z8fvhZio3Sx"
    Data.s "+bvQILsg3C4Osi6k0O47v/M7u5COuzBrd3FAzXbHbx8E3D3rWc/qQmpPMQhxIHahlXQ3uMENujjYFqeiPf91aPnpuTh8kj8uNnN3"
    Data.s "netcJ/URG2mxj2BWXRziXTDQgx88GEL67t/+7d8W28JXaB1dCFG1KDvjuTAfJ79faCyr+giJM72zz/u8z2uOIYhDpotN1sUh1Okn"
    Data.s "CLoLgXLVPOIA6ILxdCFUrGp/vjZCa6GFdqExd3FoNC0DzoKJd2F9Se3BT/3UT3XPec5zuhB+u2BOxf7uete7dmH5Su/+EY94RHq+"
    Data.s "lhfw9cfhk8YbQpjAu3/5l39Z3LueDyadaP8hD3lI2gcgGGIXAnSKyWmJJQiloYMPvKPFDx5afvc///M/Xbgci7gaPxACa+fzwz/8"
    Data.s "w0fe3ed8zud0eEDw8OY+v+zLvqwLYSS90xI96D8O6jQWfgPCfNyF27ILa1Ixdskz3nVo+wnnGe52t7slPognL4G2YbXt3vd937cT"
    Data.s "h9AKW9tPjecMCMGre+Yzn9mFILo4JXTinLn+9a9/xsf+wc+WIATlLiyvXVi/u7B2tS4/0asz8Ku+6qsO9K+TO93pTukctD+WoB3j"
    Data.s "E72F/zt9m/9tWUVofV1o3WkDOcwuu+yyLjTq6i5C0ule+cpXJiK2YALAr/7qr3ahSXZhGut+7Md+7EDYU51iGn/0R3/UhdbThT89"
    Data.s "MY3SoTvsJzSFxICykOGlG9fHQeZQy4x1blE2KaaLCMKN0oUm3d3+9rfvHve4x3VhTlvERZgLE/5KG32uExsIs7EG+FsDGAeG8Wmf"
    Data.s "9mlVB8Z4jLC2JEYH7wSvtRBm64SHlve3dqxzqR0m/F7v9V5FYXVqztpiYgTwIRCkCMIlBqaNPUTIJfCGO60JNfZuWPy6cCEdaWde"
    Data.s "BPMSTRI8w2WYmHXEzCSBO9xh3Yd92Id14Zbr7I8aCMthYqIPfvCDEz8RuFsL4cJK+xQDDy24w9QdaDVgXIKO/U/Y0tbHvK3LvmoB"
    Data.s "DP9bv/Vb03sIi1CxKT758z//891nfdZndfe4xz06ykC4TrpwhaQ5lfhKPrSsYQj4Hp5COFoCQsKP//iPdxH/lJSnVtjafjheWIvS"
    Data.s "YU6ZJNCioZIC6H2HpTk9N/6go7BMLy7J+eHcg4Of+Imf6MIK3qGnWjA24YMCO4SP+qiPSgJYVkyX+lttfohODyZDPi9BfPm70/yX"
    Data.s "H4u/7Qu/8AsP4/Nn1wamMdszPWeIA7HnW6tZg7HjoE6mw9CEkimG75EvNiwa/T3vec+qfphCPZ9BUFbN+FufYYJiAg4NpBjvsDQW"
    Data.s "szFXRMlkO+5DoBMzlbgP7ha4XLsm5jrupLNFh2vnvbUd07N3yBfd2hea5e+PA+BIW/E8IUj1n/zJn9zUp2BewJfeOpfh88EQk0uo"
    Data.s "dh9qm4ORjc8EWusKEgSH/gXr5n6svcYFkIN3BfwN9y+XWE17rhvuA/geto/Dow8hohmH4mjALW95y+q23IziCIbAJVrz/rwf8H3f"
    Data.s "933JBZfbhDCRvhcfsBRM7Tdz/oZv+IbkuqkZc/jM1vb64vrgasmxYNyvz3ve86reHxcId4sP93H++BsOuThLa7KG7/7u7+5DcU04"
    Data.s "487CD0OoL7ad6juE4OSOcyZlt9jCHLbHANziFrdIm7VmsSVkrPkdAfNhiyHQXuCQDVnrh9Tmdre7XWIaOQBGVL/vbPDSnIwXGkhv"
    Data.s "0wpo8nxoEsm35yXaJGGSSf1NBcrxofJ55uCf2s1XmlfN7+Zj83/Lt3xLcZ1L/Vkjv6l114x7XM9c9apXTbEHn/qpn9oLZiOEPOpR"
    Data.s "j0o3SeCbP5OQdlzjnYv9hMk3BWGu8VcSmt2WcXAP1wZ39kJLNL/2xyEAEAhB640UQszll1/ehyaV/KKYOPoovTN0I3DtNre5TXpW"
    Data.s "4FytAGDv2ufALRpxGD72lNiEUgzPV37lV6a2xhP0aP6EHwqV/loCa63VuHz/pTXn38U7EULsm1/5lV/pf/RHfzT9SyGqEaTFD4lV"
    Data.s "AmFBSfRCCcDLxAYIMKy9TVU75+N8Ds7wPu8qLB6Jdxxn/619hRs1BZ+LyQi3WB9Wtab5CDq1b8V1VJ5/2wUAmttrX/vaxHBbF7z1"
    Data.s "eTcHaNxhxu+/+qu/Om1iUZH5SiDNVKBN7TgkONfxBOXYTMPAlto+MAXCgOh4EuIf/MEfpBfqgHzkIx95hlBB2/fSCA/5CpL/2zgY"
    Data.s "aos0XzvH/BwCc0sBI2ptO3weo2P9sL4t/bS2LV2DcjujdJOjdczh8wIgBcGyGtm8WzXf1rkQUGlfT3ziE1cxWoefw8c+Go5tTQ6F"
    Data.s "07YAhOsrHSauBW45ODB1cOc733mRHt1AoS2F3//w3N3vfvc+TNpVV/jQ1uMf//h0iA7xRyjVB5pYeqcOTYBOWSLys1kIKrUf9p2D"
    Data.s "N8P/Xr0HHRKA9pvxbR6vec1r0sEOPyWaDNdfiv4fAppkBfn2b//2I5aBUl+n/Tv+TPDy/ikNORC2dh6u2lF87f/xx/etB7hro4Qo"
    Data.s "VmlnSK0VO8/3p3/6p9OtMNdKK9ewXQBgcvCy10asVk50ckFHqG7iD1IoJl0zBnM0848NwCRPi6Bd1bQdPnOHO9yhf/WrX92L0HQL"
    Data.s "gDXC75gqS8mQyESAukUw1MBJooD0TDDg3midQ+3zrk0SljCi2jZTzyFcQtg3f/M3b+qndQ7MpKKV3bRwbZLl5sUvfnE6EJ/xjGck"
    Data.s "nJ9kboEIejtCdbS21jVseV6UO5rFMNb0Q2gHTLbD9q6lEgBao7jXWgAI6fnQY03bKrRh7CwblIIlvLiqhkcQwjFsH7SEiTrUuVVq"
    Data.s "rIDjMZheXQmEx6XxH/CAByQBXB6H4XP+rpn/sE34/pPQ0ULvhAU3JljQxgIgKwChooauWIHtQ++ONdO+xFdarTg1Yx33M+bqymW+"
    Data.s "PvrFX/zFiQ5qrC8lBYRrozRfFkpClKvcBC8QPv2DRarUPv8efv/E/77t276tOGZucyxBgIKvYs5NgTMxgWOBkDC7sD50gbgutIYU"
    Data.s "wSuAJkw6KaAsNNIUZDEHIqCD8aQAHEGMguJEVQsqFNgSJqLmeQokEtWrDxGuOZBHpDs8CS7JYFxBWCFtH76LuIEuBIhONK+I1Lgi"
    Data.s "1TyH2gbW62NeW0B7nzWRvFvGFQQWZuxOJLrIYwGkYcbrYhN3of11caWwQ58nBeGuSQFwaC+YSBrvNCHu+aZbFKK41wD8oXsBf0MQ"
    Data.s "iJRv56zpt7WNCPzQGlPgmtskgtNqQLCg/TvcU9oJKq557x/90R+d6D+uwKZAKp+wiiReFsy7iwN6ka/NjS+gza2IHFk/txa3oMxV"
    Data.s "wNYQ3AzyXmr3JZ4leNCtp5p157H0b3yfIRjbd6XxBV7ad25i2YfenSDE0KYTXQqGPtfBHrCGEIYTDYbQmOjAWVLKCmvdgrV98ID8"
    Data.s "8XdYhtL7WAI4CqtvF2b/LpTFtI/DApWi+AUGtoCzzK0XQeEtUC0tRKeTzwq24ePecp9xru+a72nZ3/RN33SYm2CKWo2WywBkzZX/"
    Data.s "S1AIzYE0RRqsmUN+hsRMa+cb4woQDEIb9Tt/NF/jMDCQ+wTQOoZBNExSQFBbqxmpZb58RqwSNRnDlvq1Ni6TsSm0ZS5bn732ta+d"
    Data.s "cF8y+24d51xqb99xV7E2rZlXjpeRwAr+9CG3BpoQV9CaV2CNBcB+4DMe5wKoWU/O4/GEJzzhyPrlAWHBK9GCGAjutu/4ju9IH5Y4"
    Data.s "WfgERspH4Y7/cF+O5zQ3Pm0OLZYyKjKxm2eOHcr9yyvCMsEdUYMHFksuxrgOWfV87pO5GUjElb9j8RAPpb+SCxTPD0Eh5YzIeLIm"
    Data.s "NMkPzTpcM/9z6ZkQJvsnPelJiZ+x8J3k3ATwApaTrS50tCgjYN7HlfPe7gIwsOAviKsc9Niew/gk/MmmJulzbbyaABZz9Txfi6Qb"
    Data.s "TCciMJnSMAA+babEljUxxxJItGGKE13MHeDvHBwzdJXwIQn6s9lFzNrAhI9hRDAXAKbcMo/aZ5la+foQfIvpcNw/RkK42UrEtfOe"
    Data.s "ek7AJWjxgWJa/OD8d1t8zmvnvXV8h5agobXja5f95YKOmKSzC6r28BmO3SoAyFTmoLHf+IvFzaB/giTzucReS2tjPuXqYUYXwEXw"
    Data.s "19bh4yCvMeOO+0c/3B8VEdQpwHQ8vvlzidYkIsrt0S2/uf2f529f1qYStv/wvdZAbEFw+A/Af/BxEemAUFXaE4QFgpL3p/2QfrzP"
    Data.s "YVzD1HvcSv9b2y/RlviXNcmdWvYinjV2v7W0Hz5L8OKybswGul0A4H8ENakj1y5urh1/Ol8Vv7tnsk+m5fqQIDsbdggEAQf2kvQ/"
    Data.s "npM5ANJ4/g1DFCAjyEe0MOFgvClI2a4tDoEETntxMIOW7IgtOLY+vjtXRmrSls71jfDknz5bViDzYonCwMb+1CV8sNKIAHZY1F4b"
    Data.s "a8Fv6VnjC6BleaqJWB/3B+dbAy9pDCLnh0CwWHMtC9MEtYzzi77oi46MO/6jxoeK8QneHYJgqLXaZ06tWqvQTI2Pn9TyIAG0+Qpa"
    Data.s "XoP2LSnRMw9eE4c1xX8if0rKqlmiX7+LIxLkPATCQM1BtJX+z/b+rcHPaT3jSi9oubmj7N425290wE8ieY3EEWt9kdHNKuADjYjH"
    Data.s "5DuUNCQ2Uxfaf/KnlJJYDAeUwEcyIIkb4tBNyTFafSmSekgkMfbZS7Lhe/OR+Y7faAwyuYUgcvhaVr64PdBZn+QQYgpq/aKtiIQv"
    Data.s "/i5+9NY1G4v/MtwcyecpCUsEULVO4aw+z88rAUponylu4zRBtTb4924lAmlNpiWJkncme9sWkMgqAsGSDzF4SNoDa7JLimmRAEsS"
    Data.s "nhr/rz2D7sfJm3JsSmjRKVNaCYbz92xcZ0sZ0tYAXiCTnuQ0NYlUjDEc39zFhpQSgA3nJmGO5F+5MmprewmQJFSKQNiU0bQVxvyn"
    Data.s "FX/Gj0DANCz6wQ9qMiNupX/jnc3924rnk3xeRklxDJJi1ey9PJcqKc97vRA+NKo1ZsPzGTdMndwoa68CiqLl+iCBno94IDFLRkKb"
    Data.s "OB/nv8/5wuBN+3uefs/7/l1P/8dyC+AkpZrT7FsEu5ziF1oqWalcWRxYQKRCboVwc6T866wm5xvQQGihorEvtPd+vr2rfb47BsYY"
    Data.s "2PfvdprYtZ4LxLqxpEHwA7s90Zp4gt88Dv5DNcTzTUsRxCRmoMZfeb6tbZ/ves1ox935gbt9/257T8cSA7BdBtl7OBcwoIAEvy9t"
    Data.s "uBb4/WnQ8i7U+ktr+96f2zGwY2DHwI6Bk8PALgCcHG73nncM7BjYMbBjYMfAOYuBPQbgnH01+8R2DOwY2DGwY2DHwMlhYBcATg63"
    Data.s "e887BnYM7BjYMbBj4JzFwKQAIK+2u+ruobtLyycs37781iWQS5k/2L3WGhB5Lw93ZANLY+VPZMJL96IjOK2mm/QMf3Qk0OnkdjZ3"
    Data.s "n8jwtth+bnx9RFBcJ7/yEsy1H67DnNwNnoKl9uYP9/Jq10JkJevgzvhRnKeLBDep1sAcRFKilL/ee1N3YAjed2QDS33Mzd/z7i9H"
    Data.s "IpDOXeDjALkE5JNwr7UE8BdpnLvLLrusi8I4Rx73W1zv6yLLYqoNMIf/ufalsf3u3naUX037xX3+KVCPQn0KOebHIOc8/EfimjNo"
    Data.s "vRb/uU99Zfr3/tFBpJRdRb/oLhJXHe521+DiOMc3fzh1F9++LgHaRQPa5LXLbVECdTci7fER3jPkQ95bXI89sf3j5oxPXMWdHEOu"
    Data.s "fe80EgVN/p7zlURGuSO/yztiD0VCoTPqJHhW7gj8NTINpvv69vkUf4cfeQXkiJgCue7laRA/NIZI0pbwKtf9HMjbEleIE88e4j3/"
    Data.s "v4T/61//+onPe+9wMeYBpfcvVwP+tRbkS5B/xn6JAOpV3agn4V1ERs4qWl81yEKjwy0Amb+kFVUedAqk21yqGy+trtK3QGrVGLP4"
    Data.s "EcUpB/gcyJAnX3mpL7XAxyUpc5+PfexjZ9uXxoeLnGVwag6l9uYgRedcRbGa9jUlQZX1zHW5x7iU5nguK5qshC996UtTDXM1EIZr"
    Data.s "lJlObXF4XcK/bG4qGq7JQjbVr6yCUovWZPSDP3UUotBSqr8w7E9aVSC16VxWu6X2JZrzuyp2OW2zfO7jdMpSPecsk/K7j/uEfylj"
    Data.s "gQx0a/CvjZS5uZLY+P1Lda3S5Rr6VQ+jhv5K40t5u2Z8a3HLZOldyKQnj8UUoO2lOgnjao5TfSj3Ozf+1v0j4yKQdXRqDLgHoSRN"
    Data.s "/i5/hb0y3nuq+2W4173udaStZ3PqZWNaHxjzOVlW1SlQZXOuOmMu36yq4nD+6E0NFFUVlzIy5loKswdA/CCr4Bz+o5jToamxGvPg"
    Data.s "95dffnlKeVyz16eeUTMjg2qWa/q52c1ulrpQNRa/WNPH2jYHC0Akv0nZ9KIsYcrsprIUiVC1ItK1bHsxuXRPPgrvTFZ9i4Og048s"
    Data.s "RP5fA7HulH1MpTzZtFS1Mo4PiYhWKbvREpBiVQUkRZPC3GU3d9mtSGaRJjOtZwqmxrdmmp3KVnChMtScRWOuvT584IOUSwttGT+3"
    Data.s "J9HSbJZA5bY4BFM2O9WovC/4o91HPvWEC9WmprR485d9bqqCmN98X8pOp2qYZ+bWWEMHw2da+stzzBUpcz/oAP3IvHjJJZekPAVz"
    Data.s "+Nd23L5lzrL4mUekbk30OwT0m7/zzBh8p/IbiDz2XdR8ODxSi3/vn6Zs/6hkhv5VsdQXDUdmO9nBWugP/cOhvanPEv2VxmdNaBmf"
    Data.s "5ptpX4a5nGVuqg/ZO2m8cdAlXGsrg6Y1u6Fy73vfe3b6Kv4Zx37RlrVLZc7cj9/0Pwdb94/8G0BVwilAU/aWzHpTgDe4Cz/WwG9y"
    Data.s "k5skmvcZWwc8q83znve81CXeKRcIvp6tgHgFvLEewtFcFlLWCVYGOIqCYIcpokUZIe0/FuE5UMU188nM8/Arc2aBBZGWeJH+vIMo"
    Data.s "gpN47Rvf+MbFZ8c/hnDcRSKzpjbDh509skZG7YlFK+nSAGiXlcX6S9UHV090pmESAGxyB4VNxtzl5UO+UpauhSEiL8H3/sVQEdgY"
    Data.s "Iqd0egEIhiAxTG27NHH9InJIUM6VScpHOV+b0UG8BMrmehGEDoe1Mr7m7uVGcYx0MDkY52A8vjVLCiP9btQ3SMIO5tzSXh8+rsaV"
    Data.s "UmJOjZ/bK8laOoCZsJjLCWeEHe/LmA6Wb/zGb+yUJ1butfZ9HDeRnXZ/Ui9j/lHfoLvvfe9bLMm6dX7oCxN0WIzL0mIOTJTex1Kp"
    Data.s "ZGbo0FRXmSNDe0yHPTcHJo7+pZ0m/EoPy7zIPWF/TsEc/dtLUSCrY6JcMq2WxlfWlHDKJFw7vpTMaB9jl1p6jjEScq0LXyKE4B/a"
    Data.s "cik6lPCPqMg3+4odbMbxfrTNgmzux28nmSCK64wJHT91AAzBniUYeIaZeQrQjfctBfMQ8L3QbtPHfhiCZ7XRFjiE8Vo8hBAFlMf1"
    Data.s "gcOl9O5wc+mll6bD117LSgazv/fGtbiUGtzhnflk5nl4N55PeMO/uMdK54c2pdLLU31wGxA2nB9rwPrRiHUsuUnn+qZgOrcISvjE"
    Data.s "afPoJADQILxsL0stZ2BCFuVDsuNbRggIArPjpx2CTageAImWVAimhIQ5RGCOBJEhIFIbcimnNwk1TFfJeiEP9hhsLj5YjHAJpsb3"
    Data.s "PD9ijX97rn0tUa1tT5LH4MIEmqwAU6A2gc1Vk1O9dr7n4nMYP1qNqnaJ8UdhqCSZnzSgW0wUkx5q8DRx2laU2k0WhjkGwcdNWOGX"
    Data.s "tf9qYm3ymtA/Pz/6t2fHYP9Gadz09VQMQn5+jv7E/tCOww03icaa8cO1kdqqF9+y/z1LgMYDxrxh2I850FzHVh4KBYFsTvCYmkuu"
    Data.s "QXDSNJP7J4Dgl+gEHx6C+CM+bta7ORDnwbrisMxCWhTnSYe5dj7+zlquZ1hD1Y4Y1iTBIwlqrAEED3zvJS95SReFwoqoUAOGsqSO"
    Data.s "PWsnWqGUPO5xj+vCBVNsP37A/MzHvjGfGlgSrpfaiz/wDvCKtYAHrzn8jUewxbPgWv0HgttpQhIAmPpIT+ErTWMzgw2D55hwHO5R"
    Data.s "sSwFFmGwkX/5ULhCm2zqJFEJPovSsMltUBsMSJLSZgiQwYwfdclnccLUh9FCIIFhCh760IeuluKZo5nH5oJ08nhT8295kWvbk1wx"
    Data.s "Ccw/S/TjceGFdrFkiZiSoGmRczhtWdtpPGv+TGkYjsAhjL9kOTmueWEALF8E5KG2hQljhvbNkntEe4eXYFjAYlMLNfT/ute9Lplh"
    Data.s "a4Iqx+OySqCBucJAxzX+HP0/5jGPSft7qoCWudIu8QeBsoQdgt8Yplwvtfg9jefwLmvE64ZAKCDUOlzngGBJ+HTAZwEgCxJcseiS"
    Data.s "8KSgGMAHHPCEjqFmDkeswKyG9o+/L7744qL1Up/enTNBEKhgQVZT83ryk5+8Cn0vfvGLkxuZYleynq4aYNAIj8A3x26Srf3Wto/q"
    Data.s "mWnvE/4JANe5znWaAxlrx5p6LgSni5Lpnz+ItE9bYIbwN6mGZE0Dp5VgJABDQyj5UORvJDDQQrPEJ7LawVTDdBBQBEIcLA7Z8kBz"
    Data.s "5fvKvqqpBWCwNg+h46TA+t1GmIumn5t/XseS+yBvoKn15024tC7r944IZmuBBMxfl+c7/NeBln3Ua/s/6XaYjY1D2+G7ZbJGe6cF"
    Data.s "9hBmagMbFyMEBJLslyxplkyBGB+aj4Cq5A6oqapYS//cAQ6JOU0aExoL4IR6LgWWIyb1Lftvafyl/cN1Aa/ZVz41BwcXCyXgasj0"
    Data.s "S+iac3ucFm3UjIOfWiN3EWEQeK9RJz5FyI/fy7BPa1QxUcxGthzBmffFBcpaS4FBi4BgzCLA3DwG/PtRj3pU+poGvuS7H7cVi4BP"
    Data.s "E9gIsBG4NymMlfDBmgEH+M6cQlPqo+V3vM++QyctlreWMZaefdjDHpbOVwIPIZdLq3Rz7bjG1s9FNEhmCCahfOAwu2VNBmPAkIAr"
    Data.s "Dxkw2WwWJD0xs9FCsxmOSRLw5WSGuGbizNtz5sc1/a1pc65rEFNrgvfxgY7RvCUCKZ6ARrthyvO3ctCnCcz4mBeNOB865iK41ebO"
    Data.s "jH1uTgQEfURUenokbq4kq8FxBVYu4cIB7PAZ00t2GWW34GniM4/liqRiU0sARwRYOHz0ox99eNTfgiBppOcy0PIJAHe+852TAAMo"
    Data.s "TmiJYFPybVsjHORAQtZaVgUuEB/73neAlcB3U+5APJ0rGCgN3nqlTgxSjuVSorcVWKCvd73rpRgyLrHTAq47vGPpuvRJzYXCkl1U"
    Data.s "BDA0a++fFlyEcJj3mC/5nAgD2RWQJ0HDxiRyIApm6++sFdB6WAFo/ZmJvP71r08HP2bIh7gEEO8+adaS8r8sDPqbuwOrT9KxDbI2"
    Data.s "iKMG0SRmprS5YKC5+ed1iEZfs37t+dGWYG79U9rjXJ1w2idGO8a/v+F+iwBXg9+tz+TDleWK31AwnE2VtZmt/de0d3jbQ6R5wjOc"
    Data.s "0qAxMgy+xkdJ+qetCci69a1vndZQsgLU0j+zsLvWU7c95vyXTP/M0Es+6JbxWemmxp/aPxQJuCzdQBi/GxbMTMcCYsFSFH/Nu615"
    Data.s "JvO9qWdr/MP5EI8reqkL0f9wsBSAl8fynFgX/nd0h9/mOCzPsA7ipawABD1WgamgQoqe5xxAzoK4oliz9MMzeD7Lgj3YCoQfQYSv"
    Data.s "fvWrDwpnax9rn4f7sxGBv3a+x9nuIlIe5uXFuboBxkRHKnPYZ58qImUWRkRMinH/cXZOBADEXAJMYKzpO3RJ9KTiuVgC2hUBQMDh"
    Data.s "OJFNHpNZ1QYdR2iX5uR3UjhGPOeDzH1Mzb+m/63t59bv4B4e6IjcATMHhLxxKWDS6RxOW9ZWenaOQdYwTn0TUGg5JGggGpw5kubn"
    Data.s "ID0NyEKIiGU3YNANmoP31ghhAiN6Yh7075IVoIb+uUfsIQx6ChwaUwI4emDBWIK58b27LPTQZo0/tCCO+xzvH4IHwVuSJbicA3iH"
    Data.s "p6mrfm7+MEc71LJmfdy0kGnUv2NLob/Nj4++BMz1eHBOSoOG8OEpU/24L++A6xUPFHcFl8NYiBwcCp+0fM8SSodwpzvdKfFxt2fg"
    Data.s "Ev8QtGketWCtzoNWhcG8KI8UlHEcRO3YW54jIBFO565ibun7XG97EYmc9GOTZg2XPymDqGZBgvkupmASvik+HkKA3yHOtY+xBsky"
    Data.s "QIMR6FACTG5KO8h3+sf3q3N/5kxIYOKaiqBEXH4TvzB3F1lfc+NbOxdHyaQ817607q2/l9avf4zYO63RQrfOp7W9jQ93w4NaFDC6"
    Data.s "aTF/YzpDxkOb0Z4p0r3wEhzX+yN8sKKxQgii5EdtxTsrAL825iu4bckKUHr/9qRsiOApT3nKLBrWCrBz44siF0DLnJvHz27B0rvw"
    Data.s "u0NTEJr9i9/Mgds9xsBrpuIbshn7pAJC8UB8xeFL0BqC6G68cYnv5Oe9c0Irq5G+xAQx/9cE4ZqDWAECProjELi5lIG5X/+sKSxB"
    Data.s "fh8CHLlKjc4ETAMBqd6fGxw1+6fmnU4945256ofHuk5asnitHWepXb4KyrJdctWdxPhns8+LSF00aAFC/FDMhDaUA0MCERoNzVyA"
    Data.s "oGdcFUFQ+coZnxELQta+houhcRAc3C0d31MdPkdS1gdCFIjBhEXzJDjc5z73SdKs8eeAZkGCEzCIgLU1f+1J1l5sJuypPqbGxxD5"
    Data.s "0V1DEYyyFIg41T4nM/KvQLBabXYNMQiQYi61ftYOa7dp4ZLVg3mQBnQaQTWt88++SEzPvL0rV0xpzjWa09x4aIZQ6rZKyQc89/68"
    Data.s "t7FVpLQ+jFfkMmbGnAn3a5gK14/9g0GWBAjvn6Y4pH8CM2bPBUGQEKXtkDgJGI7vkLF3mOJdT6SdE+4Eh83dZZ+bk2u9oqPlAphL"
    Data.s "1mJNeA8ew3QteJI7Eu07vATgorEcwHzc60c7rBTGdWDDOf7DHC+A0ntYusU0nA8rDNzhVe6Wt5jSabH2PMuJoLYxsJDh5w7YsX+d"
    Data.s "+Z1V17vKwdT2j4PZ/snXOI8bd/rjpmF94K5jbfLuxrzzpIPz4ASNEL6Mf0FBHEx9HOp9+IBTCsIHPehBQdP/B9LIhiR4+CIkyV7q"
    Data.s "Qs/6SIUYBJdSoubvhv+WUlmWUuFKWRlaeDE9olTA4TI4Mvf8R+Q3WJ0KOISjPiwLq9vnOYQbZTYV6lwq2yl8zn0nFXBoGpPrDwk3"
    Data.s "pQmears1lak+t6QCDvNuH8LLkXmjt9Dci+/c2EupfKU2jjvKqe+46bIqFW1cie2lRJ7DuzHQnTTA+RltQASmpe/gODS5PgSRM/qZ"
    Data.s "w791Sf8KpAgt0UIpFe9SKuDjor+wdpxBf9Kzep8RK9CH+bnHb4ZrKaVitq9BJDOaxUH4ts+goTwRaZrDn13E3/DdheBW/bx2UlBL"
    Data.s "pT0FIXj1UqSX3p/fwxLbGxuE4lTVJvcbLtJDOuQQIM5o6zsQwkgfB+rhd2mBQShRZ6T7DWGmj+Dw9HtNWm5psENoTXuuZr2eCYVz"
    Data.s "Em/DL0Oonu0vpwKOBHbVY07NLYLNUyrtUFSb+wnrU6LvUFab29bi6aSeuygQnbR8UhhJkMYrIRBtUfAPMxbJmgmJ74gmSVLNaR+Z"
    Data.s "T5gW50xVolFJnPkaypR0Jb7A3dNcwMe/LBGkUFr80j3Y3B+fVQ66IsW6duTDLbCUClT7qfFJ1AJpuDimEqwM1zHVPq/FOsxjyZTH"
    Data.s "JOcZJre14N3Q9plecyEnfZoH7Vocxxx4Thu0MARmcXigPS1ZMGi8tN01GdOsnd+TpQau0B1fZE0hlzzXOfyxbKFl61uKSp57f/pl"
    Data.s "vp1yTeWx4Yx1Cv1mHNHcaBRDDQ5+aHVTMIV/uJeERV4NeClZkGTuZAaXlAX95wIpNHF7b8kEflz0hzfwIWf60y/tPRfTgaep4l5L"
    Data.s "49vXT3rSk5JvOMcojXGIdqydlYOVwdr9C39cCC2WJLhbSjw29f7QLDcjq439knHP9eFKXu1ddrev3J0X+1RyOY7ngYZZGvw7FWvh"
    Data.s "OzQqAFCWwwyy0KE/gd/jdL/5e4Gec8W0xvNgtWq5kizOIb+zIf/P/4cL7/ekwX613tb4hZOe12n034f/5SDphfn1iIQ4ljwiVqCP"
    Data.s "Az8JaGFuOu8knpOSpPZ+y4WfdhxduDhigYjrhDu/qCiQtu+T+n2SLQC1FsOTwC0LE0v4+WgBUKM2qX0yOLl+xIflWuCtbnWrpHXw"
    Data.s "P9JyaEHu48oNTlNlLShpxqchvexj7BjYMbBjYMfAhYkBN7TE3bBS+7C0LVnsjhtLAn4FerJYin85zTv81uJMnivU5PdcaG+uGJpn"
    Data.s "DlI5Xxpf0JwvndbPvzlXuvIkpKu9z3ppeMfVjqudBnYauJBoIG6BHMIF1pQD3oqrYTngcDWfuoWrGEARD4QLeHZeBwvAUDISEep6"
    Data.s "1tBXJEqfj+lsZgU7bult72/HwI6BHQM7Bs5fDLh6KdbC+ST2JILYq2MujmPVbrewArA6uI4+TMB0HP2X+mD9mCt4xoLvVsk973nP"
    Data.s "2biWSQGgNOj++46BHQM7BnYM7BjYMXB+YyBVA9xhx8COgR0DOwZ2DOwYuLAwsAsAF9b73le7Y2DHwI6BHQM7BhIGrhhJLC51V1j2"
    Data.s "KndgW9KvHgcO+W7cMZWB6SRL+rbOVUYtZRndqx3nzW7tq+Z547lZ4faF8p6nBbKHwT9/kTu3rXCht2/F1/78joEdA8ePAXlpZBDF"
    Data.s "R2URbQFZJu9whzukPAnDuLeaPuSYUfVTlP25mGm1uIYolJHuMEayhV42qWhwqh9ZqSJBSv/4xz/+jCxhpz2X4Xg5c1ZcjzxxfEQK"
    Data.s "5EPGOlGdp7nuSK7SR5KY/tJLL101bmy8FIgaBWzOSvut89/a/jTf1T7W8fOmSNPch+Ddn8Y+39/f8b8/OI0U4n0kizoExLfiOQoo"
    Data.s "pTMoKiU287A8aFyJr8742Dq/pecjBXYfyfv6qNzYWwd6bun/Ihn+5MtWTleu6NMGFgdSlyxy40x0pz2X4XjuVvqcVBGR4ViiSEmR"
    Data.s "ke401WE4TZDTQdGapbukS/MhNYu8zcWiWue+tf3W+W9t37re/flzCwMqIcpWSAPc4fzEgCynqiDK5leq+zG1QsWUnEFr8gewnquP"
    Data.s "o3iTrJOnDWopKOZnbDU/liq+Ts0txQAodIOJt6RwPO2FviWPR/BRkMKVElXszgasFb6kL1U3XMrnNbC1/Zox9zY7BjIGpOiW7Gwu"
    Data.s "TfOOqXMfA4p2ue6mEJpEdacJrv5JoEeRbT18j2Oe0mg7uxU+8/9S4bDxmEkAkKv6CU94QsqitBbufve7p2pkanD7yMvfAvzsysAq"
    Data.s "MywPtiqALaBsqlzc2j7iEY9oaZqeze2tgS9p7m7lXMc3vOEN09zNwfpr61obl9aPgEmvskmtgTx/49sEqtHlMpul/nKmR3UTwhWT"
    Data.s "1lD7/lSKVD9CJsk1sLX91Jjeg8pmU+Vh18xxqQ0NMtwnKSOXqnfe/RB/qqnJDoauvJMxWP8jH/nI1FZFO/Tbgv/c35D+vMMoRFS1"
    Data.s "VEzLfvH+1IzAzLbsP3n773KXu6Tqn7KjsW4tQcQgJeZFAyf81tT9GPcnDkXlPev2adn/7pCH67O73e1ul/ZLa+W5KfpVAdCeoJWW"
    Data.s "QA5+tS+GoCqm9uoLlIDSMHzX/NnqCURxqENTvBmNTYE5en643x/84Aen2gBLFVxzX/g0njUsIY+XhUsw8dQSKC+vlozDO3/Qn3LY"
    Data.s "tZX58C+CHGXibEBW4M7G2A58NCuGb+nwR9tz0OQziE7OeD5cCMmPPIQoLdxHkoZi36oIRpGQPgoSHapZ6Ud/UaO6n6tiNpxHFAzq"
    Data.s "I4DwyPgPechDimPnPsbtVW5TIZFfKIi42I9nchWvPIkwR/U3velNi22DWR2ZtzGncLz03dT6VW0M83ofB8Nif2E66iPQMa3X8xki"
    Data.s "ELGqihofumqDwbyb521NW9ubP5zlamBhzk1LqM3Klduj4Va8e14Miwpol112WaomluHyyy/vwySXaDsDGokD8cg4amvAn6p1w6qb"
    Data.s "tfg3B+8/V23LY8FJTRVN849iLL3xohzrYa6yqq3df2FO7YPh9CpplnzreEQw7iN4ankPqgvGgXFkD/nDvlKpsdTXsKH3EMWKim2G"
    Data.s "fU7Rr6qH+qqpfYA+VMOMcsKHcdVYAfy7pfmrwBjWt0M1VhUnQQg2qS3/uCqhUZhqsq9cDZAP3fOhTaf2UYTqjOqAU3MJwasPBbKX"
    Data.s "RTb/7p2HRtyHUFuc/5j/5feBf6lRU1q/30OI6KOsfR9CZNXz4z7tU+cHXNSMN9VeVUMVWde039JGlcwoPZ3iF8RxzdF8lKyenNvm"
    Data.s "a4D8L7IGirwUNX/LW96yU2GKTyRKLBaFonjhKQJd1T9Vn2gC+pHViWSZqw7OdZQl8Nh0qeoYiZIviFahrkEJmI9ozLn9bW5zm6SB"
    Data.s "0chqQHsmcGMZn5YXjDdVJ/M3yWwJaIbG54NiTqKFt8DU/GkPqq6Rikt+LfinBeaqi9Yf5WG7IKiU47oEfOjG4UdbA1vb5zHFMKi8"
    Data.s "Rovk01UF8DSA6c+HBs0XiOa9T9objUblTP83nygacoav2frFmQSzS5qr96B2ey3+WTlYO2ja1k2jU9kT3emvpIEbX/yN8cRjoF00"
    Data.s "iC4uueSS4v6boj9aeAjgVTE06NMaaPHaoL8WgFPrlaHUDRr4f9azntVFEG8V/VpvHB6pimKUHm62/E3RL3qwJ7j1SsByESWxU/R6"
    Data.s "BpYgFsgos15q3j3taU9LvOtqV7taejZr8rlyogqheJPnpgCt4Rf4ljnQ3M3dHGrigp7//Od3EXjWycmf4W53u1uqiKjvEtD+WVzz"
    Data.s "2WEPAZUdnQE1EIde59Nq/q7pu+YZ49pvrdaj3Ld3puplKBFnWF1Uoy2dIUtz1N75Ovf+td0ktah1TQILs1fqh9RK2gBh2i72TUKl"
    Data.s "/YQA0Yf56vD8Xe9616QRlaRgkmcwkSNR7LQs0uew7vXcOoM5p7kOo+BZJdS0jkOtD4FmcQ25fQSDHHlOVUWaYY1UGObjPjZ8ryZ1"
    Data.s "6/uwThACz6Gt+ZMMafZDyXyqbzW/4wDoo5zwQfuJzZz6DAGsOJ+tGvRxtFe7IkzHSQsOE3avLnktHreOn+k3yvEe8KemOAuWuhkh"
    Data.s "oKa50ArRUwh5R+YWG7RncWJBCHdC+o1GX4t/Gqh+w4V3xFqmMpn9E0FCi7gwf9oPi1UI84dntbevSvtvbv+oO1+zf6w/rlD1z3jG"
    Data.s "M5ojmOFKnnPA4uhGk++CISfLXbgXinQgajoOqz6EtuKzUzQ1RT/eOQsMK0iJDvOzQ/5Dm33Ri15UhQ/rRD94cAjyfZT77V/wghf0"
    Data.s "L3/5y1N7NxxYWJassaxQboFF2e+Ey3BJFOed1xVm+rTvWBByBLr5hxJR3Ufui8aPFuPgT5aLEu7y76x+rE01vHaqz60WgAieT9ZT"
    Data.s "1pDaOefnWFy8qwwsOvksCYE08YsQ7mb7HVsA9BuCe3o+t3cOshJMzW2zBUD8AAmDJKj+Oa0n+35q6ttrS9uQ01jd8wzqoKvLzQKw"
    Data.s "5MsV/UiDGUqbYhle+MIXVt3pFEHpDuewdjsJmMREqy1JldlP5S49LSI2bhcCUHe/+90vSeY0uxLwIxtnTRCJGuziJ0iPGczfPLJ1"
    Data.s "ZWl845L01XnIeQDU52aRGPr1Sms4W79nCwatlbZL6ypZPY5zrpl+w3x+wB96dLMCTaulDvgnfTcG7dHZK17xioPGpUZ6Lf5peNYr"
    Data.s "kHd4Y8V+tH/gZGn/GB+EANO96lWvOkxPe1pcaf/N7R+aXc3+Mb53FodIqjLaCnFoJb7B4oiG8Q3/8sPX3Mu292iwZ6sOvOBDAbTi"
    Data.s "L8zB+2JVYYWswYd3Zv/T9PAbMRUseKwKtHL0gb8NeesYx6GopPilEAQSH22paGfsEN7SDbJwY3QsD+YfReWaXiU++cxnPjO1FTez"
    Data.s "VL1u2DGLn0h4MQ6hxDSNeVwPh4ulE/vCaiKeogXEDrFeODPlFLDfrMVZggZYk1rz0LAqhUv90N55gKdPwWYBwAHssLzFLW6RriIw"
    Data.s "YTLngNLhmSeEiY9NyJmJOoRs0DlgdoGktdf1jK3t+NDAsGsOkrxJbTTuBy/Uy7T5vFgb8yQBfhzgBLEhWFNtUifPhQR9aJ7xCTfn"
    Data.s "OpijoCMHmIMz/NadQKjThExDecxM90MG7rt82I7nBt9DWsv91eAf/ds7YybhUCVwlPaPuUztv9r21mXua/eP8bfsX+Z715+e/exn"
    Data.s "JxcLPsQNKRiTafk0AP6Ge83fNe/O3NBIWIrSAerw5oawd2uLyli/g0/QsUBGrgPKDJ7pO/yHG6rEH/P+p1C0Bs8SugiCrpKbP1y0"
    Data.s "JDOzL1xFJwQpXEOoqwWCHzcwAfxsgfVSOuGgJnBzOE+8+wEPeEASXAle2YXjLPFufVfLx3O/9qJzeNh+ro/NAoAFIxj/ikSm/ZI+"
    Data.s "WgAT4QMcCgwkQQKFqw1LvjSSrWyCJP41oC0tfuxnEdvgu9JGpkGQsDAb87WR+f/53fjhSdYnCTIVRiKhJHkPAT5atJpaYe0k17Km"
    Data.s "b/NGH/IQuA6DFtfcBV4zdm6Dgc0d7rX9rm0veyb6pb0NoXb/aLNl//HTslwRdodQu3+GOKzF1fi5CKTrwmXYhbsraVC3v/3tkzbq"
    Data.s "MKrxn9rjNdr21PxyxbVxxDp+VuIduT8CAAGO8iCWhDXozW9+cxU6zNth6yaDmB30gCeEKTkpYg70Ej92cN3jHvdIgoL3SJNtgTe8"
    Data.s "4Q1JwxSDIYbr6U9/elNEvv3qJoS4jdZbIBdffHEXLo90a6DG2tqyrtpn0Zq4N5aU2tix3Ld3N3w/3r3zgyBACGgRhvSJ59sDte03"
    Data.s "CwAI3QfBSioEsjm9RoPO0rPAEZJ8BpKPfiFkCQQu0QCH0r5D2EbAFErAVUB7FvCUmRjmJRiGdFbaxOaHyXhZTKa0UCYhEhhhiGXg"
    Data.s "JIHmS9pnChvO34ZgRivN/yTndlp9WyNag++XvexliZmMD8TTmstpjxM+33R4CJgNH/iR/UMILGlG+fBzdW/N/hO4SwAb7x9myJr9"
    Data.s "sxVfXD8YL20XLmhi3Bdo36Fc41ajBOA1a4CLx1j2f95/ghDtyVqhghJj7tyIcXOoe+pTn9o0FbxOAJ8ASnsAcA1ILuZAsCeWAA6N"
    Data.s "K5iUK9G15BZ8cLUIvGaBUJ6XKb8WWGzwWkGygslbgfBBAKAAcYGcDcDjXbsU0M3t1wKUxzGdEGidKzVBkPgeGuRK8n/v236obb9Z"
    Data.s "ACA1AiYrUiA/cj70aKYlIEEz9zO585+QXvWBMGh1suMtgcUiHtIuQjQHBC8qtkT4+iVA2HBxBSQJDdo7VP0fAytpZg57wgoG6kUQ"
    Data.s "gsyfCZLZDYGeJNjo7m7bwBgJoskmwFoGdJLzO62+s9nygQ98YBry/ve//2kNfVbHsW/yjRe0mOnP/nH4l/yi6BudsgI4uFjcWvZf"
    Data.s "Hp/5ViKxvP/052As7Z+tyBMpT/Dxb+Y/9iHXB826dDfcHoEzCgj/dw3PGs6Z6dw4rJ8UAGMTRvCiJdfluA88x00MPIcG3QIODO4e"
    Data.s "PC/ncoEPe8L8xu7BYd/Wi35E3Wtj3+inJSMpIRKvpThZc030f56DO/9ohAKHd6G9fAbU5oLRjombxfVsACHTe/P+Txsou/aZvc8C"
    Data.s "1srzNwsAfBeYLl+kjSj4BBHxPzBJ5espc4hBMNqR4gTvkOL0oV+HeukqjQXzoQiY4AvSlxdCEo172VXvQzpHBM9sqj1pXIINm4OJ"
    Data.s "fwkQ3n3ve9/UnikIEZo/086Nb3zjRMwlMAYz3JqgO+PDP4HDfCXvoPkIwqoxTdN+jD28woJx+K7GrTLVvrTe4/x9PL6AKhsR86i5"
    Data.s "hrp1/ujXe4fzfNhN4c9zcDo2FW/FP1y6hoqJ09oy/RGmxaHkIMQlnJsvIVLgFlNyy/7Tr2tk6N/67B/aByvM2C0wNYet+Le/CO80"
    Data.s "oMx/vA9uAFaIEmDcWeMmxNTMedgn/iPJigMf/zE265//1yay0R+coR+8p9b8n+fh0KQIgSwA4L/576X+BK+Zs2uUAL2gJTytZv/k"
    Data.s "OQhaI3ASZKaCXefeQ76qjdfgXWgvnwFDi1aJB/u9NXahRBu1v2cr9tmwtnIXwJcPIZYy3QrNVxdigDPahBk+XUPxr9/DFJH+nnp2"
    Data.s "/J02ru5I6uEqlE/LVS79DdvWjjueh3HNJV9ncRVFvzVr8Eyee+v8rd1Y/q0da+o54+a1h08vXU1xpa/Up7HH+J76bq6flmfHfbiG"
    Data.s "6Ark2kQ8+huPj/ZchawtjLFl/sZHM+OEVXM4nUpstRX/GadD+qulJXiSxEQxEW3QTyv9jsf3tyRCrpfWJNLaiv/MbzL9Zx5Uovv8"
    Data.s "uz2uTWu7Yf9oLvPATBOtPGyKjmrXgK7yNdLMD2vwmnnecBz4kFCmdv9o67oxfjO+Dl2avzXn94b28sf3tfhzFdpVR9feSuNN/b71"
    Data.s "GuDWRERr5nxcbTZbAGIiCUgetPUsgYhMLmnvw7Y0WRJULsJTEz+Q2/t32LZ23GF7/ze2+WczSqsPPc/dvy3zt3ZjtUZ7mjPTv7WL"
    Data.s "njWutYtJkIyFe6DGLGXs8XynvhvjK//d8uy4D2tmedliKh6Pj/amfGsnMf9M++Mo6zmcTkVjb8V/XteQ/lpoCe5pT9qgn1b6HY/v"
    Data.s "b5p9LWyhnzyGd57pv1ULsn+0aW03XJ/xMw/MNNHCA+boqBaH6GqYuMeaavCaed6Yl3IdtJiTXd1j9cgu4dp5w1l+b2gvf3xfiz9u"
    Data.s "K3OtifeonVfLc/bO0ALY0vZsP3tsAsDZXsiFOj6TIZMbF0i+fpSv9EQ62qIP9GzjTdyCA6jmzvbZnus+/o6BHQNHMcBtgu9wIURJ"
    Data.s "3HT74LRBzgyxHvIR1OYPOK454rWyFxJAzkcetgsAx0UJZ6kfxO/e+zj6VECO1MLnA4g8FkG7w46BHQPnFwbEYNDWxR5I5bzW+rpl"
    Data.s "1aycudhRKd/BlnGm2mYrhSvIrdaP457Lmv7+H+NA8Xha0VYNAAAAAElFTkSuQmCC"
  
  EndOfFileList:
    Data.s ""
    Data.l 0
    Data.s ""
EndDataSection
Angenommen es gäbe einen Algorithmus mit imaginärer Laufzeit O(i * n), dann gilt O((i * n)^2) = O(-1 * n^2) d.h. wenn man diesen Algorithmus verschachtelt ist er fertig, bevor er angefangen hat.
Antworten