letztens habe ich mich wieder geärgert, weil ich hier im Forum ein sehr interessantes Programm/Projekt gefunden habe, die zugehörigen, verlinkten Dateien aber aufgrund des Alters des Threads schon nicht mehr funktionierten (also die links waren kaputt).
Das kommt ja immer wieder vor, weil die Hoster, auf denen die Dateien liegen, diese nicht bis in alle Ewigkeiten speichern.
Um das zu umgehen, habe ich ein kleines Tool entwicklet, welches binäre Dateien in einen Base64 Kodierten String wandelt und das ganze mit ein wenig Programmcode aufbereitet, so dass der gesamte String (eigentlich Programmcode) per Copy/Paste in den PB Editor geworfen werden kann und die binäre Datei nach dem Programmstart erzeugt wird.
"Bin to Post" (Bin2Post) habe ich es genannt.
Hier mal ein Beispiel:
Kalle postet sein neusten PB-Programm. Den Quellcode packt er in die bekannten "
Code: Alles auswählen
" Tags hier im Forum.
Was ist aber mit dem Programmicon oder einer anderen binären Datei, die zu dem Programm gehören?
Dazu dropt Kalle seine binäre Datei einfach in das Fenster von Bin2Post und erhält nach kurzer Umwandlungsphase einen Text, der die kodierten Daten und einen PureBasic-Dekoder enthält. Diesen Text kopiert er mit dem Button 'Copy' in die Zwischenablage und kann ihn von dort direkt als zweiten "[CODE ]" Block in seinen Forumspost kopieren.
Interessenten, die sich seinen Post durchlesen, können nun diesen Code aus dem Browser kopieren und in den PureBasic Editor werfen. Dann einfach nur F5 drücken. Es erscheint ein Save-Filerequester, in dem man angibt, wo die Datei gespeichert werden soll. Der Dekoder speichert die Datei im ursprünglichen binären Format auf der Festplatte im ausgewählten Verzeichnis. Fertig.
Das ganze ist umso sinnvoller, je mehr Leute es explizit benutzen. Ich hoffe, dass Euch die Idee gefällt und Bin2Post hier im Forum eingesetzt wird.
Der Code ist gestern Abend entstanden und in puncto Geschwindigkeit sicherlich noch optimierbar, da die Kodierung direkt mit Stringvariablen realisiert wurde. Der Dekoder arbeitet dagegen mit einem Memoryblock... was *whoooooshh* blitzschnell geht (eine Dekodierungszeit ist quasi nicht spürbar).
Generell ist das Tool nicht für riesige Dateien geeignet (wir wollen ja auch nicht den Speicherplatz des Forums mit Hundertmegabyte großen Datazeilen zumüllen). Ich habe ein internes Limit für 500 KB vorgesehen, Dateien über dieser Filegröße werden nicht mehr dekodiert. Da ich aber den Source hier reinstelle, könnt ihr Euch natürlich alles selbst anpassen.
Die wichtigen Parameter in Form von Konstanten sind folgende:
[code]#Rowlen = 100 ; Zeilenbreite der generierten Datazeilen in Zeichen
#MaxEntries = 10000 ; Maximale Anzahl der im Editorgadget angezeigten Zeilen ('Copy text to clipboard' kopiert aber immer den ganzen Text)
#MaxFilelen = 500000 ; Maximale Größe der zu konvertierenden Datei in Bytes
#RefreshRate = 532 ; Anzahl bearbeiteter Bytes bis der Statustext (x von y Bytes) refreshed wird
Edit 05.01.2017: Ich habe das Programm aufgrund der aktuellen Posts in diesem Thread Unicodefähig gemacht. Wer alte, bereits kodierte Daten auch unter PB 5.50+ korrekt dekodiert haben möchte, der tauscht in dem Fall einfach die Dekodier-Routine über den Data-Zeilen gegen die aktuelle Routine aus (z.B. die, die in dem CODE Block mit dem Programmicon zu finden ist, siehe weiter unten hier im Post).
Edit 06.01.2017: Ich habe die Dekoderroutine etwas verkürzen können. Es gibt nun keine Datazeilen und keine DataSection mehr. Daten und Dekoder sind nun allerdings nicht mehr als Blöcke klar getrennt, das ist aber nur ein optischer Aspekt. Die Funktion ist die gleiche wie vorher.
Edit 16.04.2019:
Code: Alles auswählen
1.03 - fix 16.01.2019: Encoder- und Dekoderroutine an aktuelle PB Versionen angepasst. Erfolgreich getestet wurden der Encoder und der Dekoder mit PB 4.31 bis 5.70.
add : Checkbox für eine "Window on Top"-Funktion zugefügt.
add : Nach dem Start wird ein kurzer Hilfetext im Editorgadget angezeigt.
Code: Alles auswählen
;*************************************************************************
;* Bin2Post
;*************************************************************************
;*
;* Programname : Bin2Post
;* Filename : Bin2Post.pb
;* Filetype : Main [Main, Includefile, Datafile]
;* Programming lang. : Purebasic 4.61+
;* String-Format : All [Ascii, Unicode, All]
;* Platform : Windows [Windows, Mac, Linux, All]
;* Processor : x86 [x86, x64]
;* Version : 1.03
;* Date : 16.04.2019
;* Autor : Kurzer
;* -----------------------------------------------------------------------
;* English-Forum : https://www.purebasic.fr/english/viewtopic.php?f=27&t=72656
;* French-Forum :
;* German-Forum : http://www.purebasic.fr/german/viewtopic.php?f=11&t=26298
;* -----------------------------------------------------------------------
;* DESCRIPTION:
;*
;* Wandelt eine binäre Datei in einen Base64-kodierten String um und fügt einen
;* kleinen PureBasic Sourcecode an. Der Sourcecode sorgt dafür, dass der gesamte
;* Base64-kodierte String dekodiert wird und die originale Binärdatei wieder auf
;* einem Laufwerk erzeugt wird. Der Base64-kodierte String (eigentlich ist es
;* Programmcode) kann per Copy/Paste in den PB Editor kopiert und dort gestartet
;* werden. Der User wird mittels SaveRequester gefragt, wo die Datei auf der
;* Festplatte erzeugt werden soll.
;*
;* -----------------------------------------------------------------------
;* Historie:
;* 1.03 - fix 16.01.2019: Encoder- und Dekoderroutine an aktuelle PB Versionen angepasst.
;* Erfolgreich getestet wurden die PB Versionen 4.31 bis 5.70.
;* add : Checkbox für eine "Window on Top"-Funktion zugefügt.
;* add : Nach dem Start wird ein kurzer Hilfetext im Editorgadget angezeigt.
;* 1.02 - add 06.01.2017: Dekoderroutine verkürzt.
;* 1.01 - fix 05.01.2017: Programm Unicodefähig gemacht.
;* 1.00 - rel 22.01.2013: Erste Version.
;*************************************************************************
;* License: MIT License
;*
;* Copyright (c) 2013/17/19 Kurzer
;*
;* Permission is hereby granted, free of charge, to any person obtaining a copy
;* of this software and associated documentation files (the "Software"), to deal
;* in the Software without restriction, including without limitation the rights
;* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
;* copies of the Software, and to permit persons to whom the Software is
;* furnished to do so, subject to the following conditions:
;*
;* The above copyright notice and this permission notice shall be included in all
;* copies or substantial portions of the Software.
;*
;* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
;* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
;* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
;* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
;* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
;* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
;* SOFTWARE.
;*
;* ---------------- German translation of the MIT License ----------------
;*
;* MIT Lizenz:
;*
;* Hiermit wird unentgeltlich jeder Person, die eine Kopie der Software und der
;* zugehörigen Dokumentationen (die "Software") erhält, die Erlaubnis erteilt,
;* sie uneingeschränkt zu nutzen, inklusive und ohne Ausnahme mit dem Recht, sie
;* zu verwenden, zu kopieren, zu verändern, zusammenzufügen, zu veröffentlichen,
;* zu verbreiten, zu unterlizenzieren und/oder zu verkaufen, und Personen, denen
;* diese Software überlassen wird, diese Rechte zu verschaffen, unter den folgenden
;* Bedingungen:
;*
;* Der obige Urheberrechtsvermerk und dieser Erlaubnisvermerk sind in allen Kopien
;* oder Teilkopien der Software beizulegen.
;*
;* DIE SOFTWARE WIRD OHNE JEDE AUSDRÜCKLICHE ODER IMPLIZIERTE GARANTIE BEREITGESTELLT,
;* EINSCHLIEßLICH DER GARANTIE ZUR BENUTZUNG FÜR DEN VORGESEHENEN ODER EINEM BESTIMMTEN
;* ZWECK SOWIE JEGLICHER RECHTSVERLETZUNG, JEDOCH NICHT DARAUF BESCHRÄNKT. IN KEINEM
;* FALL SIND DIE AUTOREN ODER COPYRIGHTINHABER FÜR JEGLICHEN SCHADEN ODER SONSTIGE
;* ANSPRÜCHE HAFTBAR ZU MACHEN, OB INFOLGE DER ERFÜLLUNG EINES VERTRAGES, EINES DELIKTES
;* ODER ANDERS IM ZUSAMMENHANG MIT DER SOFTWARE ODER SONSTIGER VERWENDUNG DER SOFTWARE
;* ENTSTANDEN.
;*************************************************************************
EnableExplicit
Structure Settings
sFilename.s
iFilesize.i
iBase64Size.i
*MemoryBuffer
*Base64Buffer
sText.s
EndStructure
#Version = "V. 1.03 - 16 Apr. 2019"
#WelcomeMsg = "Welome to the Bin2Post Converter (" + #Version + ") by Kurzer" + #LF$ + #LF$ + "This program converts a binary file to a Base64 encoded string and" + #LF$ + "adds a small PureBasic source code to decode the string on a target" + #LF$ + "machine on which PureBasic must be installed. The added source code" + #LF$ + "ensures that the Base64 encoded string is decoded after it has been" + #LF$ + "copied into the PureBasics IDE and executed using the F5 key." + #LF$ + "The original binary file will then be created on your hard disk." + #LF$ + "A file requester pops up to choose a location to create the file on" + #LF$ + "your hard disk." + #LF$ + #LF$ + "Please simply drop a file into this area to encode it to a Base64 string."
#Rowlen = 110 ; Zeilenbreite der generierten Datazeilen in Zeichen
#MaxEntries = 10000 ; Maximale Anzahl der im Editorgadget angezeigten Zeilen
#MaxFilelen = 500000 ; Maximale Größe der zu konvertierenden Datei in Bytes
#RefreshRate = 500 ; Anzahl bearbeiteter Bytes bis die Statusanzeige (x von y Bytes) refreshed wird
Define iEvent.i, iEventGadget.i, iEventType.i, iQuit.i
Global Bin2Post.Settings
;*************************************************************************
;* Procedures
;*************************************************************************
Procedure Convert(sFilename.s)
Protected j.i, iLength.i
iLength = #Rowlen
Bin2Post\sText = ""
Bin2Post\iFilesize = FileSize(sFilename)
If Bin2Post\iFilesize > 0 And Bin2Post\iFilesize <= #MaxFilelen
Bin2Post\MemoryBuffer = AllocateMemory(Bin2Post\iFilesize)
Bin2Post\Base64Buffer = AllocateMemory(Bin2Post\iFilesize * 1.5)
If Bin2Post\MemoryBuffer > 0 And Bin2Post\Base64Buffer > 0
If OpenFile(0, sFilename)
If ReadData(0, Bin2Post\MemoryBuffer, Bin2Post\iFilesize) > 0
SetGadgetText(2, "Converting to Base64 Format")
CompilerIf #PB_Compiler_Version >= 560
Bin2Post\iBase64Size = Base64EncoderBuffer(Bin2Post\MemoryBuffer, Bin2Post\iFilesize, Bin2Post\Base64Buffer, Bin2Post\iFilesize * 1.5)
CompilerElse
Bin2Post\iBase64Size = Base64Encoder(Bin2Post\MemoryBuffer, Bin2Post\iFilesize, Bin2Post\Base64Buffer, Bin2Post\iFilesize * 1.5)
CompilerEndIf
; Header erzeugen
Bin2Post\sText = "; This PureBasic sourcecode was generated by Bin2Post (" + #Version + "), a file converter for sharing binary" + #LF$
Bin2Post\sText + "; files in text based forums. More Information see: www.purebasic.fr/german/viewtopic.php?f=11&t=26298 or see here:" + #LF$
Bin2Post\sText + "; www.purebasic.fr/english/viewtopic.php?f=27&t=72656. Copy/paste this code into your PureBasic IDE and run it via" + #LF$
Bin2Post\sText + "; F5 (PB 4.31 - 5.70 is needed). You'll be asked for a directory where the script creates the original binary file." + #LF$
Bin2Post\sText + "; Filename: " + GetFilePart(sFilename) + " - Binary filesize: " + Str(Bin2Post\iFilesize) + " bytes - Base64 encoded size: " + Str(Bin2Post\iBase64Size) + " chars" + #LF$
Bin2Post\sText + ";" + #LF$
Bin2Post\sText + "Macro D:I$+:EndMacro:L=" + Str(Bin2Post\iBase64Size) + ":" + "F$=SaveFileRequester(" + #DQUOTE$ + "Save file" + #DQUOTE$ +"," + #DQUOTE$ + GetFilePart(sFilename) + #DQUOTE$ + "," + #DQUOTE$ + "All (*.*)|*.*" + #DQUOTE$ + ",0):If F$<>" + #DQUOTE$ + #DQUOTE$ + #LF$
; Datenblock erzeugen
For j = 0 To Bin2Post\iBase64Size Step #Rowlen
If j % #RefreshRate = 0
SetGadgetText(2, "Generating data blocks [" + Str(j) + " / " + Str(Bin2Post\iBase64Size)+ "]")
While WindowEvent() : Wend
EndIf
If j + #Rowlen >= Bin2Post\iBase64Size : iLength = Bin2Post\iBase64Size - j : EndIf
If iLength > 0
Bin2Post\sText + "D" + Chr(34) + PeekS(Bin2Post\Base64Buffer + j, iLength, #PB_Ascii) + Chr(34) + #LF$
EndIf
Next j
; Footer erzeugen
; Bin2Post\sText + "CompilerIf #PB_Compiler_Version >= 560:*O=AllocateMemory(L):OL=Base64Decoder(I$,*O,L):If CreateFile(0,F$)" + #LF$
; Bin2Post\sText + "WriteData(0,*O,OL):CloseFile(0):FreeMemory(*O):CompilerElse:*O=AllocateMemory(L*2):PokeS(*O,PeekS(@I$),-1,#PB_Ascii)" + #LF$
; Bin2Post\sText + "OL=Base64Decoder(*O,L,*O+L,L):If CreateFile(0,F$):WriteData(0,*O+L,OL):FreeMemory(*O):CompilerEndIf:EndIf:EndIf"
Bin2Post\sText + "*O=AllocateMemory(L*2):CompilerIf #PB_Compiler_Version >= 560:OL=Base64Decoder(I$,*O+L,L):CompilerElse" + #LF$
Bin2Post\sText + "PokeS(*O,PeekS(@I$),-1,#PB_Ascii):OL=Base64Decoder(*O,L,*O+L,L):CompilerEndIf:If OL=" + Str(Bin2Post\iFilesize) + " And CreateFile(0,F$)" + #LF$
Bin2Post\sText + "WriteData(0,*O+L,OL):CloseFile(0):EndIf:FreeMemory(*O):EndIf"
If Bin2Post\iBase64Size > #MaxEntries
SetGadgetText(0, Left(Bin2Post\sText, 4096) + #LF$ + "... more lines were encoded. Please use the 'Copy' button to copy the complete encoded string to the clipbard.")
Else
SetGadgetText(0, Bin2Post\sText)
EndIf
SetGadgetText(2, "Conversion finished (" + Str(Bin2Post\iBase64Size) + " Bytes total)")
EndIf
CloseFile(0)
EndIf
FreeMemory(Bin2Post\Base64Buffer)
FreeMemory(Bin2Post\MemoryBuffer)
EndIf
ElseIf Bin2Post\iFilesize > #MaxFilelen
SetGadgetText(2, "Filesize exceed the limit of " + Str(#MaxFilelen) + " Bytes!")
EndIf
EndProcedure
;*************************************************************************
;* Main
;*************************************************************************
If OpenWindow(0, #PB_Ignore, #PB_Ignore, 410, 250, "Bin2Post Converter " + #Version, #PB_Window_ScreenCentered | #PB_Window_SizeGadget | #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget)
SmartWindowRefresh(0, 1)
StickyWindow(0, #True)
EditorGadget(0, 10, 10, WindowWidth(0) - 20, WindowHeight(0) - 45, #PB_Editor_ReadOnly)
SetGadgetColor(0, #PB_Gadget_BackColor, $F2F2F2)
EnableGadgetDrop(0, #PB_Drop_Files, #PB_Drag_Copy)
CheckBoxGadget(1, 10, WindowHeight(0) - 35, 110, 20, "Window on top")
TextGadget(2, 10, WindowHeight(0) - 17, WindowWidth(0) -80, 20, "Drop a file into the light gray area to encode the file.")
ButtonGadget(3, WindowWidth(0) - 70, WindowHeight(0) - 30, 60, 28, "Copy")
SetGadgetText(0, #WelcomeMsg)
SetGadgetState(1, #PB_Checkbox_Checked)
Repeat
iEvent = WaitWindowEvent()
iEventGadget = EventGadget()
iEventType = EventType()
Select iEvent
Case #PB_Event_SizeWindow
ResizeGadget(0, 10, 10, WindowWidth(0) - 20, WindowHeight(0) - 45)
ResizeGadget(1, 10, WindowHeight(0) - 35, 110, 20)
ResizeGadget(2, 10, WindowHeight(0) - 17, WindowWidth(0) - 80, 20)
ResizeGadget(3, WindowWidth(0)- 70, WindowHeight(0) - 30, 60, 28)
Case #PB_Event_GadgetDrop
Select iEventGadget
Case 0
If EventDropType() = #PB_Drop_Files And EventDropAction() = #PB_Drag_Copy
Bin2Post\sFilename = StringField(EventDropFiles() + #LF$, 1, #LF$)
Convert(Bin2Post\sFilename)
EndIf
EndSelect
Case #PB_Event_Gadget
Select iEventGadget
Case 1
StickyWindow(0, GetGadgetState(1) & #PB_Checkbox_Checked)
Case 3
SetClipboardText(Bin2Post\sText)
SetGadgetText(2, "The complete text was copied to clipboard (" + Str(Bin2Post\iBase64Size) + " Bytes total)")
EndSelect
Case #PB_Event_CloseWindow
iQuit = 1
EndSelect
Until iQuit = 1
EndIf
End
Code: Alles auswählen
; This PureBasic sourcecode was generated by Bin2Post (V. 1.03 - 16 Apr. 2019), a file converter for sharing
; binary files in text based forums. More Information: www.purebasic.fr/german/viewtopic.php?f=11&t=26298
; Copy & paste this code into your PureBasic IDE and run it via F5 (PB Version 4.31+ is needed).
; You are prompted for a directory where the script creates the original binary file.
; Filename: Bin2Post.ico - Binary filesize: 3774 bytes - Base64 encoded size: 5032 chars
;
Macro D:I$+:EndMacro:L=5032:F$=SaveFileRequester("Save file","Bin2Post.ico","All (*.*)|*.*",0):If F$<>""
D"AAABAAEAMDAAAAEACACoDgAAFgAAACgAAAAwAAAAYAAAAAEACAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAEAwQAB4N0AJSEdwAOzbYAfIKEAA"
D"ekigBFxa8AEkQyAGRqbAAEg/wAFHK0AASt/ABM6qQABGdKACyEcAAspJEADuXMACRmNAAskmwAM7KLACzClACExsQAZOPMACZlXAAswuwAZMK8"
D"AEnj2QBEwvwAJoTlACrVvgAsXjwALKrUABRWXAAplZQADFY8ACmFgAA1pIkAR9S+ACu0nwAkdGIAnKKZADrEqgAqtfoAzNLUALWFiwBR9t8AKH"
D"NPADe1ogA3xLQALJ68ACyLcQA1lH8ADCgQADV+agAElfcAFGbkAFL0wgAhVDgAVtTEAJaUigArpfAANKSsANfu9wAHk3kANryjACJ07wAsq/AA"
D"JHKEAB5VRgA2rZcAJ2VPAAe1lwBW4soAK31pADjTsADv8ewAKGtRAEymnAAcRTAABHJUADSFbwA84rwATNbkACyM6QArrJYAWOvYADSdjQBJ28"
D"QAUf7sADjMuQBIrugAK5uDADnMpgAkLiwAmJ2TABqaiAA3va0AI33oAETKnABk+twAPNTgABeY9wAhXEgAPNq/APz+3AArjHwAKpP0ADScgwAQ"
D"LkQANKzzAAweBACMbGAAGoXnAEjkyAA1ppYAN7PxAFT85AApnPoAHKKUAAS0/ACc4tQAJmxeACx1YQA0eEwANItzAAQ0IAA0o/kACJyCADnUwg"
D"C0wsQABN7MAGTcvAC0vrwAhP7wAOzm5AA08twAlN7UAJR+oAAEwvwAFGKEAGzO/AAEefUABQM1AAR8YABMTkQARLuqAByEaABsdnQAnMbcAMjm"
D"7AActpwAE+/bALzW5AAcbmAAWMr4ACReXACUe20AfNLMABp1YgB8/uAAlIKkABii8AA3wvEAfM7EABy2/AA0PjwAHHJUAARKLABJ2fEAROL8AD"
D"ri0gBY5vgARrz0ACR+nAA3u4cAZO7EAARu/ABY/sAA/PX0AEzO4AArnY0ACLysADnczAAMDkwAKsa0AESypAAUTkwAFH7kAASNcQAJnu8AWNvD"
D"AB5NNAAcHiQADFqEAASM9wDEhIQAFDUgANTe4ACVi30ABquOAEvr1wAsvKcAIVw8ACx+dgBU68QAROzEADy89wA8zvkANO7cACx98QAUcuQA5P"
D"L4ACz+5ABk/PAAdO7cACTO7AA0rqQAnNLsAJuOpABUxqwAK5SAACyWrAA0hX4AXPPYAJySpAA0ZlQACLaoAFz9+ABFzLYA/P78ADSW7ABU1vwA"
D"R835ACx6TADs9vQASLb0ABx6dAAEu/wAlP78AHzO7AAczrwANGxUADSMfAAEAiQAVK6kAAR+/AAcvrQAHHo8AAReRwCsopwAtIqMABQuHABO3t"
D"oACDokAHR+hAAU9twAw8YCnJycXl5eXl4CxsbGxl5eXl5eApxeOzvGb2+cnAKcnAICxsY7XigoKF7a4NosxseP+Pinl/+Xl5dHj38/x/8QEIKX"
D"P/gQAwMDAP34Dad9x3+8fwVHENR37Qt3d+3gxscuZkZMDqqAgICqYCdJ2IAdMDBZybkwQGBVAH00ACfVWCcyW2sPXPxlPDw8Qu3axsdmvzlJOd"
D"C2WYBZtoBEYB1ZuDAwMLgmYEAtAAD9cWNjYHp8a2sUzax1PDxCPHfgxkdMTEZQNVsagFm4WYCAgFkwuGDJYNhUL5HIAEnfVRbV7ElrayQpsTw8"
D"PG08Qnfaxn9QUEl8M0zQWYC4WR1ZWbgwMMkwMFQPLzBXkVVXvoPnpnxrW1tcVWo8Qm08PHfgAn8yEg4OEkkvgLgwgDBZuFlgyWDY2FRgVDDkWS"
D"XkFhZ16TIkVA/Ns3VCbTw8PHfaAg3hNQ58azNJtjC4MFlkMC/dy3lmeXl5aTAlBjo6r84jDjNbJFQ4rDxtPDw8PHfaOwNbkspGUHwHWSlgWdjL"
D"Rma/OXpJDkk1etwlOjq+vm1MEmskVEpjPDxCPDw8PAvaO7VgWVlZD9y/cskvtERERmZ5UFBJfA5JNWkvGr4WD0Lpa2skVFFVZTxtfh88PAvaO+"
D"JU2NgvyWBg2NgPZnouTDUODlAODiMODg7cVxaDH917a2skVFGzPEJCbTw8PAvgxgNgVCbYL9gPD1Z5RHxJUEkO8mkOfA4OfCMOIVXWKkkOayQP"
D"QAx+PDxtQjw8PAvaAk8wYNgm2A+0MyNODnwO6S5QMg7yDvIOSQ5pSYCiKi58W2skSsh1bUI8bTw8PHfaAo8XWSbYtDNpNXlOUHxMHklWUA4zDl"
D"BJI1AOUCFCzhFQJEUTXJp1QkJtbW08QgvaOwV68S8vVmnLy2bKfC7KRgYySQ5pSctQDlDySTJzohEyExNUSn5CQkJCbR9+bQvgnLzxLmYzISN6"
D"RgdG8hE5uVQ1DlAOUA4ODg5JDkncz0wzRVuuqDxCQkIfbTxCPHfaO38jeidG8np5FwcuScp5QFAOSQ5QIw5p8g7yDg56Ma0yW2trcipCbUJCQk"
D"I8bXfaO+IPW94jenkXyr81ejlADlBJNUlJaVDyaQ4zaTMySZsRRdwyDiHrQkI8Qm1CQnfgXrVWI8tJF0ZGB04zRiTcUA5JSUlQ8g4O8mlpaTLc"
D"fEm/UBNFtHwSom08Qm08QnfaO9C0DssnF0ZGB0ZFM1ZJUEkOSVAjMg7yI/Lc8iMzM1ZQB3pFRdxrVGCiPDxCQnfg4AHyPVB6eRcXxDMPaw5JfF"
D"BJDlAO8mlpDvIOM2ncIdy0M0ZJJBO0Wy9cZG08PHfg+S2efSOZF5tG+y8lDnx8DklQyw4OUA7yy1Bp3PLcM1a0MzOePRIv3ElZJVd1Qu3aiWXu"
D"hb7cujlE+wbcSQ4OSQ4Oyw4ONUkODmkz3N5WclRgyS8yeSNWKWsyUd9tdXfgoLA3Wp/fRZ5OeTAOUFB8Dg4OUA4ODvK0D0VyD3JUQGApWSkhMy"
D"dDW1xJZ8zOPHfaiY1h0tLrVb4wWWB8DmlpNWlQafIzDyRFQEBFMMnJQMlZWVkkazMXIXJnQHFSZe3aoPUcHBxBQVOoRQ568kW0UA7yM2tra95p"
D"M1ZAV83ILchxWXFFDlvyB94a5K5XdXfgifVhHBwc0dFkSUzxMiYwVHJQRl3z846Ot46O8/NsIJ4GyFiRMjMkv0RAZ+QUc3faoPUcHBxTHEIT6U"
D"Yi5CUlckQHustWBlwpMEpcJVxZL3JbDid5ZlAzRk5FcSVMzwvgoPUcHBxT0c9JRr9QLVchZt4ztFYz3CRFRS9ALzBZXDAwSoCARaZGRvtbLd/3"
D"qQvaiQkcU9EccFcRRr9NYHp6VmkO8hJrDw8kQC9AQFzkMFxZWUiAyCmbZjTcdORbzwvgoI0cYVNhda7hvwdFaQ7LMzJFM1YzW2skD0BcWQZZKS"
D"VXV1dIVVUOScQzWMuuKnfaifVhHBxhc65mbrm2MHJFJmBAW2szEiRrRUVA5CUw5CXkV0hIvqpFa3oO44sMPHfgoI1hcBxB6BPKxONjVRpXBpFr"
D"a1tra2skRUUpXCklXDAlJUiAV1dxRUmS48E4QnfaifVhYRxh62I5J+MvL0UpMC8PJNxraVvcE1TkWUDkMClcV1dISEjf5EUudAqxPHfgifVhHB"
D"xwQTjKM1dpaXLkkSVgkTNba2trJC9A5EAlWeQlJVdXvswauKu0LXUqPHfaoPW7HBwcQauSLxrcWw4PkeSRRWvcJFZrJEBAJUAGSiVXV1Fxzahq"
D"PDw8QjxCQu3giQlhHBwcHFOfV0hgRUW0MGAlKdhrM9xrD0BA5FlXVyUduJ1412U8Qn5CfkJtQnfgifVhHBwcHEFqhThXMDC4JtxpMzNWa2szJC"
D"8vKSUp5JZFS7Llc2VCQm1tQkJCQnfgoPVhHBwcU1NhHOhjHdsV9A0B3A5bM1bcJEBAKUBUvE3l5YHllTZCbUJCQm1CQu3goI0cHBxTHFMcHGFq"
D"14ZL5eWjfwUP3NwzVkVFMyR/TeXl5QDlaMJCQkJCQkJtQu3aiY0cHBwcU1NTU1PRu0vlPuXl5YgFX1YP3FZWtF+05eXlBADl5cJtQkJCbUJCQu"
D"3aoPVhHBwcHFNTU1NTHGjlAOXl5eXlyX8PViRyX1/l5eX+AADlaMJCQm1CbUJtQnfgiY0cHBwcU1NTU+ZTjWjlkwDA5eXl5RkFIQ8PAZXl5eoA"
D"AADl771tHzxCbW1CQu3goI1wHBxTHFNTU1NTsD7lhAAApSvl5eV2WzMj7LJL5QAI5eXlNjxCQkJtH0JCQu3aifVhHBwcU1NTU+ZTu3Dl5ZAAXQ"
D"DF5eX2gCVKHcWy5eXl5dO9oR9CQkJCKm1tQnfgifXRHBxTHBxTU1NTanBT0+Xl5eXlPnC9zxoapDZalJjZ672hbTxCQkIfbUJCQu3giY31CQnC"
D"wsI2wjY2NjbCCb2sjJoLwr0LCwsLd3cLCwsLC3ft7e3t7e2K7Xft7YrawywsLCwsLCwsLCwsLCws+iwsLCwsLPosLCws+vr6+iz6+vr6LPr6+v"
D"r6+vr6+vrDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
D"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
D"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
D"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
D"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
*O=AllocateMemory(L*2):CompilerIf #PB_Compiler_Version >= 560:OL=Base64Decoder(I$,*O+L,L):CompilerElse
PokeS(*O,PeekS(@I$),-1,#PB_Ascii):OL=Base64Decoder(*O,L,*O+L,L):CompilerEndIf:If OL=3774 And CreateFile(0,F$)
WriteData(0,*O+L,OL):CloseFile(0):EndIf:FreeMemory(*O):EndIf