RFCP logo

REBOL for COBOL programmers

REBOL Personal Patterns

Date written: 17-AUG-2020
Date reviewed:
Date revised:

A large number of programs written by a small number of people
can take on a similar appearance. If you have an understanding
of the similarities, it can help with understanding one of the
programs when you run into it and must work on it.

This document shows many of the patterns you will see when you
look at programs from a particular author.

Contents:

1. The target audience
2. The REBOL header and the halt function
3. Including common data and functions
4. Basic VID GUI
5. VID stylize
6. VID "at" keyword for positioning
7. VID GUI panels
8. VID scroller
9. VID timer
10. Building code with build-markup
11. GO or CANCEL
12. Files in directory
13. Making a context for word isolation
14. Making an object for code isolation
15. Email sending
16. Embedding the user.r function
17. Function definition with refinements and nested function
18. Running a script with a DOS batch file
19. Running a scripts with a Powershell script
20. Two ways to for a script to run other scripts
21. Changing part of a string
22. Reducing and joining
23. Requesting a file name
24. Playing a sound
25. Basic table lookup with select
26. Creating a more advanced lookup table
27. Lookup table creation function
28. Lookup file creation function
29. Multi-block lookup table
30. Multi-category description table
31. Substring to position
32. Substring for length
33. Control break
34. Write CSV file
35. CSV module
36. CSV module demo
37. CSV extraction with Powershell
38. CSV to Excel with powershell
39. Base 64 image
40. Base 64 image in VID layout
41. Compressing an embedded image
42. Compressing a script
43. Compressing scripts into a package
44. Base 64 IMG tag
45. Date and time stamps
46. Calling a Windows executable file
47. CGI reading module
48. CGI form processing
49. Next ID number
50. Find files of a given type
51. Hexadecimal value of a byte
52. Hexadecimal value of a string
53. ODBC submission module
54. ODBC example
55. SQL "as" column headings
56. CSV file from a block of blocks plus headings
57. Parse structured SQL comments
58. SQL query to CSV file
59. Wait for a file
60. Launch Windows File Explorer
61. Recursive file and folder lists
62. Check for safe file name
63. Space or zero fill
64. VID button "click"
65. Add and remove commas in numbers
66. Base fllename
67. Make a filler
68. Pause
69. COBOL-like edit mask
70. Launcher skeleton
71. Customized makedoc2
72. Fixed-format file processing.
73. Fixed-format processing module
74. "Printing" to CSV
75. "Printing" to TXT
76. "Printing" to HTML

1. The target audience

This documentation was written at a particular installation and is aimed at programmers who encounter REBOL programs from a particular author and must understand what they are doing, perhaps for the purpose of modifying them or replacing them with programs in some other more common language.

The best use of this documentation probably would be to just read through it. You will see little bites of how REBOL can do various things. With that background, when you then look at a larger program, you will see these patterns in it and you will understand what it is doing.

There is another possible value in this document, depending on your own learning style. If you were to read the REBOL user guide and look through the function dictionary (which you should do) you will see all the little things that can be done with REBOL, but then you might wonder how to put those parts together to do something you might have in mind. This document works from the opposite direction. This document assumes that many of the things the author has done are things you might like to do as well, so you can use this document to find out how to do them.

A note about the code samples. These "patterns" are the way one particular person writes his REBOL code. The specific feature of note is the use of lower case for REBOL functions and upper case for everything else. This convention was established early as a crutch so to speak when the author was not familiar with all the REBOL functions and wanted a way to differentiate them from other words in the program. You generally will NOT see this convention in other REBOL code.

2. The REBOL header and the halt function

Every REBOL program must start with the word "REBOL" followed by a block, that is, a pair of square brackets. In that block there actually can be anything you want, but there are some items that are officially used, and in that set of all officially-used items there are some that are almost always used, namely, the title and the purpose.

That word REBOL is what the interpreter uses to locate the start of the script. Normally that is the very first thing on the very first line, but it does not have to be. You could put other documenting text lines in front of REBOL and they would be ignored by the interpreter. Normally, in the world of REBOL programming, that is not done, but it could be.

An additional item we must note here is the "halt" function. The "halt" function makes the program stop and produce a command prompt. At the command prompt, you can examine the values inside the program with the "probe" function.

Here is what the header looks like with the two most common items. It is presented in the form of a complete skeleton program that does nothing besides execute the "halt" function. This is a good way to start a script. Type the header and the "halt" function, and then run it to make sure there are no syntax errors. Then start adding code after the header, and at convenient points save and run the script and let it get to the "halt" function. Then probe around inside to make sure things are running as you expect before you go down the wrong rabbit hole as it were with ideas that don't work quite right.

REBOL [
    Title: "Demo program"
    Purpose: {This is a program to demonstrate how to
    code a program header.  Note that the purpose can be a
    multi-line comment and so is enclosed in braces.}
]

print "Done."
halt

Running the script produces a command prompt window, and the "probe" functions shown below show where the title and the purpose can be found.

Done.
>> probe system/script/title
"Demo program"
== "Demo program"
>> probe system/script/header/purpose
{This is a program to demonstrate how to
    code a program header.  Note that the purpose can be a
    multi-line comment and so is enclosed in braces.}
== {This is a program to demonstrate how to
    code a program header.  Note that the purpose can be a
    multi-line comment and s...
>>

If you back up a level and probe the system value called system/script, you can what other item might be expected in the header.

>> probe system/script
make object! [
    title: "Demo program"
    header: make object! [
        Title: "Demo program"
        Date: none
        Name: none
        Version: none
        File: none
        Home: none
        Author: none
        Owner: none
        Rights: none
        Needs: none
        Tabs: none
        Usage: none
        Purpose: {This is a program to demonstrate how to
    code a program header.  Note that the purpose can be a
    multi-line comment and so is enclosed in braces.}
        Comment: none
        History: none
        Language: none
        Type: none
        Content: none
    ]
    parent: make object! [
        title: none
        header: none
        parent: none
        path: %/c/REBOL/
        args: none
        words: none
    ]
    path: %/I/PatternSamples/
    args: none
    words: none
]
>>

3. Including common data and functions

It does not take the writing of many programs for one to realize that one is coding the same things over and over again. A better way of doing that would be to write that code in some more general way so that it could be used as-is, and then put it into every program NOT with copying and pasting, but in some other way so that the code exists in only one place.

A way to accomplish the including of pre-written code parts is to write them in a complete REBOL script, and then "execute" that script in your program, somewhere near the beginning, with the "do" function. If that script that you "do" contains values and functions, those values and functions will become available to your program.

It also does not take the writing of many programs to realize that all those re-usable bits need some sort of organization. Here is one idea. In the example below, the program includes two files. The first one, cob.r, contain values and functions that are specific to the installation that owns the programs. These would be things like logos, definitions of file paths, whatever is specific to the site. The other, glb.r, contains values and functions that are NOT specific to the installation but are used in almost every program, so much so' that we can package them all up into one file and just include it in every program as a standard procedure because it is almost certain that some parts of it will be needed. Here is the sample.

REBOL [
    Title: "Testing shell"
    Purpose: {General testing skeleton for demo programs.}
]

do %/COB-APPS/VOL1/COB_REBOL_MODULES/cob.r
do %/COB-APPS/VOL1/COB_REBOL_MODULES/glb.r
print "Done."
halt

Note that the above "do" functions refer to scripts stored in a particular place, identified by a UNC path. This is just a sample of how do do this. This example was taken from a particular installation, and your locations would be different.

We can run the sample and let it halt, and then see what is inside those common modules.

Done.
>> source GLB-SUBSTRING
GLB-SUBSTRING: func [
    {Return a substring from the start position to the end position}
    INPUT-STRING [series!] "Full input string"
    START-POS [number!] "Starting position of substring"
    END-POS [number!] "Ending position of substring"
][
    if END-POS = -1 [END-POS: length? INPUT-STRING]
    return skip (copy/part INPUT-STRING END-POS) (START-POS - 1)
]
>>

The glb.r module contains assorted functions that are used often. One of them is to extract a substring based on starting and ending character positions. We can "probe" that function, but in the case of a function the appropriate method to examine it is the "source" function as shown.

4. Basic VID GUI

Some people like to plod along in their coding, and find beauty in something that others would consider inelegant. This is an example of a plodding way to start writing a window with the Visual Interface Dialect.

In this case, we use a word to refer to the layout, and later in the program use the "view" function to show that window. This all could be done in one combination of statements, of course, as in "view layout [...]".

The first thing we do is use the "across" keyword to establish the top-to-bottom left-to-right ordering of items on the window. This is just personal preference. This way, we have to use the "return" keyword to go to the next row.

The function to be performed when a button is clicked is contained in the block after the button declaration. This can be a whole bunch of REBOL code or you could put just a function name there and define the function elsewhere in the program.

Note that we include a "Debug" button that will halt the program so we can "probe" around and check things. This button might be taken out once a program became a production program.

REBOL [
    Title: "Testing shell"
    Purpose: {Basic VID GUI.}
]

system/console/prompt: "Use 'probe' to look around: "

MAIN-WINDOW: layout [
    across
    banner "GUI demo"
    return 
    box 50x50 red
    box 50x50 green
    box 50x50 blue
    return
    button 120 "VID documentation"
        [browse http://cobolrebol.com/pages/documentation/VIDforCOBOL.html]
    return
    button "Quit" [quit]
    button "Debug" [halt]
]

view MAIN-WINDOW

5. VID stylize

If you are making a VID layout and are producing a lot of things that are the same, like a lot of buttons of a non-default size, there is a way to reduce the coding. That is with the "sytlize" function where you define words that refer to VID object with certain values. The example below shows a very simple example of defining a new kind of button. You can do a lot with stylize and so the way to make friends with that feature would be to just try it as appropriate and see how far you can push the concept.

REBOL [
    Title: "Testing shell"
    Purpose: {VID stylize.}
]

LOCAL-STYLES: stylize [
    BIGBUTTON: button 128x128 font [size: 14]
]

MAIN-WINDOW: layout/tight [
    styles LOCAL-STYLES
    across
    space 0x0

    at 0x0 BIGBUTTON "Quick help for this window" [alert "Button pressed"]
    at 128x0 BIGBUTTON "Quit" [quit]
]

view center-face MAIN-WINDOW

6. VID "at" keyword for positioning

VID was designed to be simple for simple things, where items will be placed on the window with default positioning. However, you can exercise more control with the "at" keyword that allows you to specify pixel positions for items. The following basic example shows the concept.

REBOL [
    Title: "Testing shell"
    Purpose: {VID AT keyword.}
]

MAIN-WINDOW: layout/tight [

    at 0x0     box 100x100 red
    at 100x0   box 100x100 green
    at 200x0   box 100x100 blue

    at 0x100   box 100x100 beige
    at 100x100 box 100x100 brick
    at 200x100 box 100x100 tan
]

view center-face MAIN-WINDOW

7. VID GUI panels

Sometimes, when making a GUI window, just placing items on the window top-to-bottom left-to-right does not give quite the look you want. It is possible to make "sub-layouts" using the "panel" feature of VID, as shown in this example.

REBOL [
    Title: "Testing shell"
    Purpose: {VID GUI panels.}
]

LEFT-PANE: [
    backcolor tan
    size 200x200 
    button red
    button red
    button red
]
RIGHT-PANE: [
    backcolor beige
    size 200x200
    button green
    button green
    button green
]

MAIN-WINDOW: layout [
    across
    panel 200x200 LEFT-PANE
    panel 200x200 RIGHT-PANE
    return
    button "Quit" [quit] 
]

view center-face MAIN-WINDOW

8. VID scroller

The VID scroller is a fussy little thing that is used a lot, and so that fussing must be done a lot. In the sample below, there is a function for displaying text with a scroller that shows the fussing.

REBOL [
    Title: "Quickhelp"
]

QUICKHELP: func [
    TXT
] [
    QH-WINDOW: layout [
        across
        banner "Quick help"
        return
        QH-TXT: info 300x300 wrap
            font [size: 14 style: 'bold]
        QH-SCROLLER: scroller 20x300 
            [scroll-para QH-TXT QH-SCROLLER]
        return
        button "Close" [hide-popup]
    ]
    QH-TXT/text: TXT
    QH-TXT/line-list: none
    QH-TXT/para/scroll/y: 0
    QH-TXT/user-data: second size-text QH-TXT
    QH-SCROLLER/data: 0
    QH-SCROLLER/redrag QH-TXT/size/y / QH-TXT/user-data
    inform QH-WINDOW
]

HELPTEXT: {Quick help

This is a function to be included in another program, and that will,
when called with a string of documentation, pop up that documentation
in an 'inform' window.

Normally, documentation would not be coded into a program because it
takes space.  This function is meant for a minimum amount of
documentation (or text for any purpose) that is meant to be accessed
quickly, like with a button.

Items worth noting in this program:

When you load up a text area of significant size (we are not able
to more specific on that) you have to set the various values as
shown in the above code sample.  Of particular importance is
settingthe line-list to none. If you do not do that, and if you
later change the text value, you will get little artifacts
of the prior text hanging around in the text area.  This feature
is documented in the official REBOL documentation, but it is
something you have to stumble across.
}
view center-face layout [
    banner "Quickhelp test"
    button "Quickhelp" [QUICKHELP HELPTEXT]
    button "Quit" [quit]
]

9. VID timer

It seems that it is possible to attach a "rate" to any item on a VID window, and then specify the "engage" function of the "look and feel" attributes of that item, and that function will be activated at a time interval specified for the "rate." The following example is offered without comment, other than to say that it does work. You can use it as a model.

REBOL [
    Title: "Testing shell"
    Purpose: {VID timer demo.}
]
TIMER-INTERVAL: 00:30:00
COUNTER: TIMER-INTERVAL
START-TIMING: does [
    COUNTER: TIMER-INTERVAL
    MAIN-COUNTER/text: to-string COUNTER
    show MAIN-COUNTER
]
MAIN-WINDOW: layout [
    origin 0                              
    MAIN-TIME: h1 100 red black (to string! now/time) 
        rate 1                            
        feel [
            engage: [                     
                MAIN-TIME/text: now/time          
                show MAIN-TIME                    
                COUNTER: COUNTER - 00:00:01   
                if COUNTER < 00:00:01 [      
                    COUNTER: TIMER-INTERVAL 
                ]
                MAIN-COUNTER/text: to-string COUNTER 
                show MAIN-COUNTER                    
            ]
        ]
    MAIN-COUNTER: h1 100 (to-string COUNTER)             
    button "Reset" [START-TIMING]         
]
view center-face MAIN-WINDOW

10. Building code with build-markup

REBOL contains a function that looks like it was created specifically for generating HTML code, although it could be used in other situations. If you write a string of HTML code and leave places for various data items marked by the angle-brackets and percent signs, as shown in the example, and then in those places you put REBOL code, then the build-markup function will go throught that string of code and execute the REBOL code inside the markers.

In this example, the places where replacement will be done are just REBOL words, and those words will be replaced with their values. However, the code there could be more complex.

REBOL [
    Title: "Testing shell"
    Purpose: {Building html with build-markup.}
]

HTML: {<html>
<head><title>Demo page</title></head>
<body>
<h1>Report for <% now %></h1>
<p>
Information about <% NAME %> at <% LOCATION %>.
</p>
</body>
</html>
}

NAME: "Steven"
LOCATION: "City of Bloomington"

print build-markup HTML

print "Done."
halt

11. GO or CANCEL

A common situation when running a program is to get to a point where the operator must decide if he should proceed, or if something has happened that would require the program to be canceled. This is a way of coding that.

A seemingly-undocumented feature of the "alert" function is that it can take three arguments. The first is the text to be displayed, and the other two are the texts for two buttons. Clicking the first button will produce a true value, and clicking the second button will produce a false value.

REBOL [
    Title: "Testing shell"
    Purpose: {GO or CANCEL.}
]

GO?: alert [
    "OK to proceed?"
    "OK"
    "Cancel"
]
if not GO? [
    alert "Operation canceled"
    quit
]

print "Done."
halt

12. Files in directory

A very common operation for file management is to find all the files in a folder, usually the current one. Here is how that is done.

When you code "read %." what you get in return is a block, and that block contains all the files in the current directory. In the sample below, we assign a word to that block so we can loop through the block and list the file names, just to show that things worked.

REBOL [
    Title: "Testing shell"
    Purpose: {Files in directory.}
]

FILE-ID-LIST: read %.
foreach FILENAME FILE-ID-LIST [
    print FILENAME
]

print "Done."
halt

13. Making a context for word isolation

In a big program you can start to have problems with a lot of words that mean almost the same thing and so should ideally be the same, but you can't make them the same. REBOL has a way to isolate words in what it refers to as a "context." This is the idea of global and local variables in other languages. This is a simple demo of how that is done. Note that there is a word TEST-STRING in the global context and in the context called ISOLATED-WORDS and those words do not refer to the same things.

REBOL [
    Title: "Testing shell"
    Purpose: {Show idea of context.}
]

ISOLATED-WORDS: context [
    TEST-STRING: "In a Chevrolet"
]

TEST-STRING: "See the USA"
print TEST-STRING
print ISOLATED-WORDS/TEST-STRING
print "Done."
halt

14. Making an object for code isolation

Another way to handle the issue of word "collisions" and to reduce some of the coding you might have to do, is to create objects.

An object is an encapsulation of code and data in such a way that you can make instances of an object (or not; you are not required to use an object by making an instance of it). In the example, there is an object (OBJMODEL) and then we make two copies of it with modifications to what is in the model. Words in one instance are the same as the same words in another, but they are not the same, and are referenced with the "path" notation as shown in the example.

REBOL [
    Title: "Testing shell"
    Purpose: {Making objects.}
]

OBJMODEL: make object! [
    ID: "Objectmodel"
    INFO: does [print ["I am " ID]]
]

OBJ1: make OBJMODEL [ID: "Object 1"]
OBJ2: make OBJMODEL [
    ID: "Object 2"
    NOTIFY: does [print [ID " is running"]]
]

OBJ1/INFO
OBJ2/INFO
OBJ2/NOTIFY 

print "Done."
halt

15. Email sending

This is how to do REBOL's signature operations of sending email. This sample show sending a subject and an attachment.

REBOL [
    Title: "Testing shell"
    Purpose: {Email sending.}
]

ADDRESSES: [
    admin@dummyaddress.com
    techsaur@dummyaddress.com
]
SUBJECT: "File attachment"
ATTACHMENT: %EmailSending.r
MESSAGE: {The attached file in for your reference.
Plese look it over and reply with any questions.
}

send/subject/attach ADDRESSES MESSAGE SUBJECT ATTACHMENT 

print "Done."
halt

16. Embedding the user.r function

When REBOL is installed, and you do those initial settings, a script is created called user.r, and REBOL then runs that script whenever it starts. The script contains information needed to make emailing work. That script goes somewhere (but where?) and normally can be found by REBOL, but if you put the interpreter elsewhere for any reason, sometimes that file can NOT be found. You will know that has happened when emailing does not work.

To fix that situation, one thing you can do is hard-code the contents of user.r into your program, or copy user.r to some place where you know it is, and the "do" user.r in your own scripts. That code would look something like the following example, adjusted for your own situation.

REBOL [
    Title: "Testing shell"
    Purpose: {Embedding the user-dot-r functions.  The email addresses
    below and the smtp server address would be replaced with real values.}
]

set-net [swhite@dummyaddress.com "10.1.0.100" "" none none none swhite@dummyaddress.com none] 
if (not none? system/view) [
    system/view/screen-face/options: none
] set-user-name "Mister White"

print "Done."
halt

17. Function definition with refinements and nested function

Defining functions is something you have to know how to do, so here is an example. This example is a little more complicated than a basic example, but not so much that it can't be followed.

Note that this example shows how to use the refinements (those words after the slashes that you sometimes see in function calls) and that it is allowed to embed a function in a function.

The sample below shows hot to reformat a date, but what the function does is not relevant; this just shows how to code a function.

REBOL [
    Title: "Testing shell"
    Purpose: {Function definitions, with nested function
    and refinements.}
]

to-yyyymmdd: func [when /hyphens /slashes /local stamp add2] [
    add2: func [num] [ ; always create 2 digit number
        num: form num
        if tail? next num [insert num "0"]
        append stamp num
    ]
    stamp: form when/year
    if hyphens [append stamp "-"]
    if slashes [append stamp "/"]
    add2 when/month
    if hyphens [append stamp "-"]
    if slashes [append stamp "/"]
    add2 when/day
    return stamp
]

print to-yyyymmdd/slashes now 

print "Done."
halt

18. Running a script with a DOS batch file

When you set up a program for someone else to run in a production environment, you want to make that operation as smooth as possible. With REBOL, you are allowed to put the interpreter anywhere, and there are run-time switches to run the interpreter without installing it. You can take advantage of those features to make a DOS batch file to run your program.

The example below was taken from a particular installation, so you would change things to match your own situation. Note that the interpreter is on a server accessed by a UNC path, and the script is on a mapped drive. In other words, you are not required to run REBOL from where it is installed on the C: drive (in Windows).

The "-i" swicth runs the interpreter without installing, and the "-s" switch suppresses the security warning you might get if you access files outside the current directory.

start "" \\cob-apps\vol1\REBOL\rebview.exe -i -s --script /I/PatternSamples/LaunchTest.r

19. Running a scripts with a Powershell script

Running a REBOL script from Powershell is about the same as running with a batch file. I the following examle from a particular installation, the REBOL SDK installed on the C: drive is used to run another script on the C: drive. As long as none of the file paths contain spaces, the syntax is easy.

C:\rebol-sdk\tools\rebcmdview.exe -i -s --script C:\COBscripts\Falsealarms\printbills.r

20. Two ways to for a script to run other scripts

Sometimes you will want one of your programs to start another REBOL program. This is very handy if you use REBOL VID to make a little program launcher, where clicking a button starts another program without causing the launcher to quit. In Windows, you can make a DOS batch file as shown above and "call" it as shown in the example below. In any platform, you can use the "launch" function to start another run unit of REBOL to run another script.

REBOL [
    Title: "Testing shell"
    Purpose: {Two ways to launch.}
]

view layout [
    across
    button 200 "Run with launch function" [launch %LaunchTest.r]
    return
    button 200 "Run by calling batch file" [call "LaunchTest.bat"]
]

21. Changing part of a string

Processing text can involve the operation of inserting characters into a string at a specified character position. Here is an example of how that is done.

The goal of the one line of code below is to insert a string of nine characters into a larger staring, starting at the sixth position. The way to do that is to skip five characters into the string, and then change part of the string, nine characters of it, to the new value. That is done with the handy REBOL syntax of stringing functions together.

REBOL [
    Title: "Testing shell"
    Purpose: {General testing skeleton for demo programs.}
]

TEST-STRING: "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
NEWVAL: "123456789"

change/part skip TEST-STRING 5 NEWVAL 9
print TEST-STRING

print "Done."
halt

22. Reducing and joining

There are several ways to string things together in REBOL, but the procedure that seems the most useful is the "rejoin" function. It takes a block of anything and strings all the parts together. The data type of the result is the data type of the first item in the block, as shown in this example. By the way, "rejoin" seems to mean "reduce" and "join" which has the effect of evaluaging the words in the block.

REBOL [
    Title: "Testing shell"
    Purpose: {General testing skeleton for demo programs.}
]

FILE-ID: rejoin [
    what-dir
    now/year
    "-"
    now/month
    "-"
    now/day
    ".txt"
]

print rejoin [
    FILE-ID
    " is a word of type "
    type? FILE-ID
]

print "Done."
halt

23. Requesting a file name

A very common operation is doing something to a file, and asking for the name of the file at run time. There is a function for that.

If you use the "request-file" function with no refinements, you will get a requestor box that will allow you to select several files, and the result will be a block that contains all the selected names. If you used the "request-file" function with no refinements and really wanted just one file name, you will have to refer to the "first" item in the block that was returned. Most of the time, however, you really will want just one file name, so the way to get one file name is to use the "only" refinement as shown in the example.

If the operator uses the "cancel" button on the file requestor window, the "request-file" function will return a false value. You can test for that and then take appropriate action if no file was selected.

In the example below, we assume that most of the time the operator WILL select a file, so we go ahead and assign a word (FILE-ID) to that file name so we can refer to it later.

REBOL [
    Title: "Testing shell"
    Purpose: {Requesting a file name.}
]

if not FILE-ID: request-file/only [
    alert "No file requested."
    quit
]

print "Done."
halt

24. Playing a sound

REBOL can use the sound port on your computer. There is documentation on the REBOL web site for this. What you might find yourself doing is wanting to play a sound and that is all, and you might be happy to find one way to do it and use that over and over again, like the following example.

It seems that REBOL can play only WAV files, and not all kinds. We have seen some failures to play certain WAV files. If you find one that does not play, try another.

REBOL [
    Title: "Testing shell"
    Purpose: {Playing a sound.}
]

SOUND-1: load %complete.wav

wait 0
SOUND-PORT: open sound://
insert SOUND-PORT SOUND-1
wait SOUND-PORT
close SOUND-PORT

print "Done."
halt

25. Basic table lookup with select

REBOL has a function that seems designed for table lookup. If you can create a block of values where you have repetitions of some key value you might want to look up and some attribute value associeated with the key value, you can use the "select" function to find a key value and return the item immediately after the key value. The following example shows a very simple case.

REBOL [
    Title: "Testing shell"
    Purpose: {Basic lookup with select.}
]

STATES: [
    "MN" "Minnesota"
    "WI" "Wisconsin"
    "IA" "Iowa"
]

print select STATES "WI"
print select STATES "MN"
print select STATES "SD"

if not STATENAME: select STATES "ND" [
    STATENAME: "Not found"
]
print STATENAME     

print "Done."
halt

26. Creating a more advanced lookup table

If you need a lookup table where you look up one key value and then need several associated values, you can put the several associated values into a block after the key value and still use the "select" function as shown above. The "select" function will return the block after the key value, or a false value if nothing is found.

Here is an example of a program that will use data that might have come from a database and convert it to a form that works with the "select" function. In this example, the lookup table is saved to a text file for later use. Another program would "load" that file to have access to the lookup table.

REBOL [
    Title: "Testing shell"
    Purpose: {Creating a lookup table.}
]

DATABASE-DATA: [
    [12345 "R" 300000 250000]
    [12346 "R" 300100 250100]
    [12347 "R" 300200 250200]
]

LOOKUPTABLE-ID: %lookuptable.txt
LOOKUPTABLE: []

foreach ROW DATABASE-DATA [
    append LOOKUPTABLE ROW/1
    LOOKUPBLOCK: copy []
    append LOOKUPBLOCK ROW/2
    append LOOKUPBLOCK ROW/3
    append LOOKUPBLOCK ROW/4
    append/only LOOKUPTABLE LOOKUPBLOCK
]
save LOOKUPTABLE-ID LOOKUPTABLE

print "Done."
halt

The above script will produce a text file that looks like this:

12345 ["R" 300000 250000] 12346 ["R" 300100 250100] 12347 ["R" 300200 250200]

Note thay the key values are the five-digit numbers, and when you use the "select" function to look up one of those keys, you will get back the block following the key value. You then would refer to the items in the block with the "first," "second," etc. functions, or with the path notation of (block name)/n notation.

27. Lookup table creation function

Creating tables is done so often, and so often from SQL queries, that we have a function to turn the result of a query into a lookup table. To make this work, you have to be sure that the first column of the result set is the lookup key to the table. Then you can feed that result set to this function.

REBOL [
    Title: "Result-set to lookup table"
    Purpose: {Given an SQL result set, which comes in the form of
    a block of blocks, generate a lookup table where the key is
    the first item of a row and the attribute for the key is a
    block containing the remaining items from the row.}
]

;; [---------------------------------------------------------------------------]
;; [ This is a specialized function for a specific project.  It starts with    ]
;; [ the result set of an SQL query, which is a block of blocks, where each    ]
;; [ sub-block is a row of the result set.  It transforms that data into a     ]
;; [ lookup table where the key to the table is the first item of a row,       ]
;; [ and the attribute of the key is a block containing all the remaining      ]
;; [ items in the row.                                                         ]
;; [---------------------------------------------------------------------------]

LOOKUP-TABLE-OF-RESULT-SET: func [
    ROWBLOCK
    /local LOOKUPTABLE ATTRBLK ROWLGH ROWSUB 
] [
    LOOKUPTABLE: copy []
    foreach ROW ROWBLOCK [
        ROWLGH: length? ROW
        append  LOOKUPTABLE first ROW
        ROWSUB: 2
        ATTRBLK: copy []
        loop (ROWLGH - 1) [
            append ATTRBLK pick ROW ROWSUB
            ROWSUB: ROWSUB + 1
        ]
        append/only LOOKUPTABLE ATTRBLK
    ]
    return LOOKUPTABLE
]

;;Uncomment to test
;TBL1: LOOKUP-TABLE-OF-RESULT-SET [
;    ["AAAA1" "BBBB1" "CCCC1"]
;    ["AAAA2" "BBBB2" "CCCC2"]
;    ["AAAA3" "BBBB3" "CCCC3"]
;    ["AAAA4" "BBBB4" "CCCC4"]
;    ["AAAA5" "BBBB5" "CCCC5"]
;]
;probe TBL1
;halt

28. Lookup file creation function

As a variant of the function just shown, this function allows for a mulit-part key, and will save the lookup table to a file so it can be brought into another program with the "load" function. Documentation in the code.

REBOL [
    Title: "Result-set to lookup table"
    Purpose: {Given an SQL result set, which comes in the form of
    a block of blocks, generate a lookup table and put it into a
    file so it can be loaded by another program.  Make the file
    somewhat nice-looking so it can be scanned visually with a
    text editor.}
]

;; [---------------------------------------------------------------------------]
;; [ This is a specialized function for a specific project.  It starts with    ]
;; [ the result set of an SQL query, which is a block of blocks, where each    ]
;; [ sub-block is a row of the result set.  It transforms that data into a     ]
;; [ lookup table.  The key to the table is formed by combining one or         ]
;; [ more of the columns in a row.  Which columns to use is specified in       ]
;; [ another block passed to the function, a block that contains one or more   ]
;; [ field numbers from the row.  The function will create a lookup key by     ]
;; [ taking the specified fields and concatenating them.                       ]
;; [ For example, if the result set look like this:                            ]
;; [ [                                                                         ]
;; [     [dataname11 dataname12 dataname13 dataname14...]                      ]
;; [     [dataname21 dataname22 dataname23 dataname24...]                      ]
;; [     ...                                                                   ]
;; [ ]                                                                         ]
;; [ and the block of field postions looked like this:                         ]
;; [     [1 3]                                                                 ]
;; [ then the resulting table would look like this:                            ]
;; [ [                                                                         ]
;; [     dataname11-dataname13 [dataname11 dataname12 dataname13 dataname14...]]
;; [     dataname21-dataname23 [dataname21 dataname22 dataname23 dataname24...]]
;; [     ...                                                                   ]
;; [ ]                                                                         ]
;; [ and one would look up an item in the table with the "select" function     ]
;; [ using dataname111dataname13, etc., as a key.                              ]
;; [ An additional argument to the function is a file name, because the        ]
;; [ resulting table will be written to a file with that name.                 ]
;; [ As a final feature, the lookup table will be written to disk with one     ]
;; [ entry per line of text, so it can be scanned visually.                    ]
;; [                                                                           ]
;; [ The expected use of this file is that it will be read by some other       ]
;; [ program using the "load" function, which will bring it in as a block      ]
;; [ that is compatible with the "select" function.                            ]
;; [---------------------------------------------------------------------------]

LOOKUP-FILE-OF-RESULT-SET: func [
    FILEID
    KEYBLOCK
    ROWBLOCK
    /local LOOKUPTABLE TEMPKEY KEYLGH KEYCNT ATTRBLK LINELIST
] [
    LOOKUPTABLE: copy []
    foreach ROW ROWBLOCK [
        ROWLGH: length? ROW
        TEMPKEY: copy ""
        KEYLGH: length? KEYBLOCK
        KEYCNT: 0
        foreach KEYNUM KEYBLOCK [
            KEYCNT: KEYCNT + 1
            append TEMPKEY pick ROW KEYNUM
            if lesser? KEYCNT KEYLGH [
                append TEMPKEY "-"
            ]
        ]
        append LOOKUPTABLE TEMPKEY
        ATTRBLK: copy []
        foreach ITEM ROW [
            append ATTRBLK ITEM
        ]
        append/only LOOKUPTABLE ATTRBLK
    ]
    LINELIST: copy ""
    foreach [KEY VAL] LOOKUPTABLE [
        append LINELIST rejoin [
            mold KEY
            " "
            mold VAL
            newline
        ]        
    ]
    write FILEID LINELIST
]

;;Uncomment to test
;LOOKUP-FILE-OF-RESULT-SET %lookupfile.txt [1 2] [
;    ["AAAA1" "BBBB1" "CCCC1" "DDDD1"]
;    ["AAAA2" "BBBB2" "CCCC2" "DDDD2"]
;    ["AAAA3" "BBBB3" "CCCC3" "DDDD3"]
;    ["AAAA4" "BBBB4" "CCCC4" "DDDD4"]
;    ["AAAA5" "BBBB5" "CCCC5" "DDDD5"]
;]
;TBL: load %lookupfile.txt
;print ["TBL is type" type? TBL]
;print ["First TBL is" mold TBL/1]
;print ["Second TBL is" mold TBL/2]
;print ["Value for AAAA4-BBBB4 is" mold select TBL "AAAA4-BBBB4"]
;halt

29. Multi-block lookup table

Here is another version of the lookup table issue. In this situation, we need a lookup table where the thing you look up is a block that contains sub-blocks. In the original use of this application, the key to the table was a property identifier, and the thing being looked up was a block of one or more garages, and for each garage there were several relevant data items.

REBOL [
    Title: "Multi-block lookup table"
    Purpose: {Provide an object that is a lookup table that has a single
    key value and a block of attributes, but each attribute is itself 
    another block.  Originally written to make a table of properties
    with multiple detached garages.}
]

;; [---------------------------------------------------------------------------]
;; [ This module provides an object for a particular type of lookup table.     ]
;; [ The table has one key value, and a block of attributes.  The block of     ]
;; [ attributes is a block of blocks.  Something like this:                    ]
;; [                                                                           ]
;; [ key1 [ [attr-1-1-1 attr-1-1-2 ...] [attr-1-2-1 attr-1-2-2 ...] ... ]      ]
;; [ key2 [ [attr-2-1-1 attr-2-1-2 ...] [attr-2-2-1 attr-2-2-2 ...] ... ]      ]
;; [ key3 [ [attr-3-1-1 attr-3-1-2 ...] [attr-3-2-1 attr-3-2-2 ...] ... ]      ]
;; [ ...                                                                       ]
;; [                                                                           ]
;; [ Functions are provided for adding new keys, adding new attribute          ]
;; [ sub-blocks to existing attribute blocks.                                  ]
;; [                                                                           ]
;; [ Adding items.                                                             ]
;; [ When we add an item, we would like to have a key, and one of the          ]
;; [ sub-blocks, and get those into the table.  In this situation, the key     ]
;; [ might not be in the table at all, or it might be in there from a          ]
;; [ previous addition.  If it is not there at all, we would want to add       ]
;; [ it with an attribute containing the given sub-block.  If it is there      ]
;; [ from a previous insertion, we would want to find the attribute block      ]
;; [ for the key and add the sub-block to the existing attribute block.        ]
;; [                                                                           ]
;; [ Searching for items.                                                      ]
;; [ Because of the power of REBOL, it is not necessary to write a             ]
;; [ search function.  The caller can use the existing "select"                ]
;; [ function to return the attribute block for a given key.                   ]
;; [                                                                           ]
;; [ Saving and loading.                                                       ]
;; [ The expected use of this module is to create a lookup table and then      ]
;; [ save it to disk for use by some other program.  That other program        ]
;; [ would use this module to load the file for lookups.                       ]
;; [---------------------------------------------------------------------------]

MBLT: make object! [

    FILE-ID: %MBLT.txt
    TBL: []      ;; The whole table
    REC: []      ;; Attribute block for one key

;;  Add an item.
;;  Call the function with a key value and a sub-block
;;  to be added to the attribute block for the key.  
    ADD-ITEM: func [
        KEY
        BLK
        /local INSERTPOINT
    ] [
        TBL: head TBL
        either INSERTPOINT: find TBL KEY [
            INSERTPOINT: next INSERTPOINT
            REC: first INSERTPOINT
            append/only REC BLK
            change/only INSERTPOINT REC
        ] [
            append TBL KEY
            REC: copy []
            append/only REC BLK
            append/only TBL REC
        ]
        TBL: head TBL 
    ]        

;;  Save the table to a file for later loading.
    SAVE-TBL: does [
        save FILE-ID TBL
    ]

;;  Load a saved table.
    LOAD-TBL: does [
        TBL: copy []
        TBL: load FILE-ID
    ]
]

;;Uncomment to test
;MBLT/ADD-ITEM 1 ["1-1-1" "1-1-2"]
;MBLT/ADD-ITEM 2 ["2-1-1" "2-1-2"]
;MBLT/ADD-ITEM 3 ["3-1-1" "3-1-2"]
;MBLT/ADD-ITEM 4 ["4-1-1" "4-1-2"]
;MBLT/ADD-ITEM 2 ["2-2-1" "2-2-2"]
;MBLT/ADD-ITEM 4 ["4-2-1" "4-2-2"]
;MBLT/ADD-ITEM 5 ["5-1-1" "5-1-2"]
;MBLT/ADD-ITEM 2 ["2-3-1" "2-3-2"]
;print "TBL after a few additions:"
;foreach [KEYVAL ATTRBLK] MBLT/TBL [
;    print [KEYVAL ":" mold ATTRBLK]
;]
;print "--------------------------"
;print "Find a few:"
;print ["5:" mold select MBLT/TBL 5]
;print ["2:" mold select MBLT/TBL 2]
;print ["6:" mold select MBLT/TBL 6]
;halt

30. Multi-category description table

Here is yet another lookup table situation. It seems they never end. In this case there was a need for descriptions of codes. The codes were in several categories like a category for wind direction, and then several values for wind direction. We wanted (as an exercise mainly) to put all those codes and descriptions into one structure, and then look up a description based on a category and a code. The script below has functions for doing that, and some documentation.

REBOL [
    Title: "Multi-Category Description Table"
    Purpose: {An object for create a description lookup table
    that can combine several tables into one, with the tables
    identified by a category code.}
]

;; [---------------------------------------------------------------------------]
;; [ This is a module to address a situation that comes up in database work.   ]
;; [ If a database has various codes that represent things, it is nice to      ]
;; [ provide descriptions of those codes in anything produced for human use.   ]
;; [ If the actual code is the description, that can use up space in the       ]
;; [ database, and the description never can change unless one wants to go     ]
;; [ through the entire databse and change any descriptions that already are   ]
;; [ in there.  So it is customary to use codes to represent things, and to    ]
;; [ put the human-readable meaning of the codes in another table.             ]
;; [ If a database has many codes, that can result in many description         ]
;; [ tables, OR, one can find a way to put all such codes and their            ]
;; [ descriptions into one big table.  This module is a way to do that.        ]
;; [                                                                           ]
;; [ The end result of this will be a bunch of description tables, each        ]
;; [ consisting of a bunch of codes with a description for each code.          ]
;; [ Each table will be identified by a category code.                         ]
;; [ So, to find a description for some code, you have to find the table it    ]
;; [ is in by supplying the category code, and also the code for which         ]
;; [ you want the description.  This will be implemented in a big block        ]
;; [ that will look like this:                                                 ]
;; [                                                                           ]
;; [ [                                                                         ]
;; [     category-1 [code-1-1 desc-1-1 code-1-2 desc-1-2 ...]                  ]
;; [     category-2 [code-2-1 desc-2-1 code-2-2 desc-2-2 ...]                  ]
;; [     category-3 [code-3-1 desc-3-1 code-3-2 desc-3-2 ...]                  ]
;; [ ]                                                                         ]
;; [                                                                           ]
;; [ With a structure like this, if we want to find the descripion for a       ]
;; [ certain code in a certain category, we just have to "select" on the       ]
;; [ category to get the table, and then select code to get the description.   ]
;; [ This module provides a function to do that.                               ]
;; [                                                                           ]
;; [ Also, we have to build that multi-category table in the first place.      ]
;; [ A function is provided so you can supply a caegory, a code, and a         ]
;; [ description and they will be put into the table.                          ]
;; [ In case you can get your table data into a block of blocks, perhaps       ]
;; [ as the result of an SQL query, a function is provided to load the         ]
;; [ table from that direction.                                                ]
;; [                                                                           ]
;; [ More specifically:                                                        ]
;; [                                                                           ]
;; [ LOAD-ENTRY category code description                                      ]
;; [ This function is called repeatedly to load codes into the table.          ]
;; [ If you want to save the final table and have it look nice, you could      ]
;; [ provide the items in category-code order, but it is not necessary.        ]
;; [ It should not matter what types of data you use for the category,         ]
;; [ code, and description, but usually these would be strings.                ]
;; [                                                                           ]
;; [ LOAD-RESULTSET resultset                                                  ]
;; [ This function is called with all the table data in a block of blocks,     ]
;; [ where each sub-block contains a category, a code, and a description,      ]
;; [ all of them strings.  The function will call LOAD-ENTRY repeatedly        ]
;; [ for all the sub-blocks in the outer block.                                ]
;; [                                                                           ]
;; [ GET-DESCRIPTION category code                                             ]
;; [ This function returns the description string for the code supplied.       ]
;; [                                                                           ]
;; [ SAVE-TABLE file-id                                                        ]
;; [ This function saves a finished table to a text file.                      ]
;; [                                                                           ]
;; [ LOAD-TABLE file-id                                                        ]
;; [ This function loads a table previously saved with the SAVE-TABLE          ]
;; [ function.                                                                 ]
;; [                                                                           ]
;; [ And finally, all this is packaged into an object so you could have        ]
;; [ several such table in your program, although the purpose of this          ]
;; [ object in the first place is so that you don't need more than one         ]
;; [ table.                                                                    ]
;; [---------------------------------------------------------------------------]

MCDT: make object! [

    DESCRIPTIONS: []

    LOAD-ENTRY: func [
        CATEGORY
        CODE
        DESCRIPTION
        /local LOC BLK
    ] [
        LOC: head DESCRIPTIONS
        LOC: find DESCRIPTIONS CATEGORY
        either LOC [
            BLK: first next LOC ;; a reference, not a copy 
            append BLK CODE
            append BLK DESCRIPTION
        ] [
            BLK: copy []
            append BLK CODE
            append BLK DESCRIPTION
            append DESCRIPTIONS CATEGORY
            append/only DESCRIPTIONS BLK
        ]
    ]

    LOAD-RESULTSET: func [
        RESULTSET
    ] [
        DESCRIPTIONS: copy []
        foreach SUBBLOCK RESULTSET [
            LOAD-ENTRY SUBBLOCK/1 SUBBLOCK/2 SUBBLOCK/3
        ]
    ]

    GET-DESCRIPTION: func [
        CATEGORY
        CODE
    ] [
        either TBL: select DESCRIPTIONS CATEGORY [
            return SELECT TBL CODE
        ] [
            return none
        ]
    ]

    SAVE-TABLE: func [
        FILE-ID
    ] [
;;      save FILE-ID DESCRIPTIONS  ;; Instead, make it look nicer...
        if exists? FILE-ID [
        delete FILE-ID 
        ]
        foreach [CATEGORY TABLE] DESCRIPTIONS [
            write/append FILE-ID rejoin [
                mold CATEGORY
                " ["
                newline
            ]
            foreach [CODE DESC] TABLE [
                write/append FILE-ID rejoin [
                    "    "
                    mold CODE 
                    " "
                    mold DESC
                    newline
                ]
            ]
            write/append FILE-ID rejoin [
                "]"
                newline
            ]
        ]
    ]

    LOAD-TABLE: func [
        FILE-ID
    ] [
        DESCRIPTIONS: copy []
        DESCRIPTIONS: load FILE-ID
    ]
]

;;Uncomment to test
;MCDT/LOAD-ENTRY "WIND-DIR" "1" "North"
;MCDT/LOAD-ENTRY "WIND-DIR" "2" "Northeast"
;MCDT/LOAD-ENTRY "WIND-DIR" "3" "East"
;MCDT/LOAD-ENTRY "WIND-DIR" "4" "Southeast"
;MCDT/LOAD-ENTRY "WIND-DIR" "5" "South"
;MCDT/LOAD-ENTRY "WIND-DIR" "6" "Southwest"
;MCDT/LOAD-ENTRY "WIND-DIR" "7" "West"
;MCDT/LOAD-ENTRY "WIND-DIR" "8" "Northwest"
;MCDT/LOAD-ENTRY "WIND-DIR" "9" "Shifting winds"
;MCDT/LOAD-ENTRY "WIND-DIR" "N" "None/Calm"
;MCDT/LOAD-ENTRY "WIND-DIR" "U" "Undetermined"
;MCDT/LOAD-ENTRY "TAKEN" "0" "Taken to other"
;MCDT/LOAD-ENTRY "TAKEN" "1" "Hospital"
;MCDT/LOAD-ENTRY "TAKEN" "2" "Doctor's office"
;MCDT/LOAD-ENTRY "TAKEN" "3" "Morgue or funeral home"
;MCDT/LOAD-ENTRY "TAKEN" "4" "Residence"
;MCDT/LOAD-ENTRY "TAKEN" "5" "Station or quarters"
;MCDT/LOAD-ENTRY "TAKEN" "6" "Not transported"
;MCDT/LOAD-ENTRY "ACENGINE" "1" "Jet"
;MCDT/LOAD-ENTRY "ACENGINE" "2" "Turbo Prop"
;MCDT/LOAD-ENTRY "ACENGINE" "3" "Propeller"
;MCDT/LOAD-ENTRY "ACENGINE" "4" "None (Glider)"
;foreach [CATEGORY TABLE] MCDT/DESCRIPTIONS [
;    print [CATEGORY mold TABLE]
;]
;print "------------------------------------"
;print ["ACENGINE 2 = " MCDT/GET-DESCRIPTION "ACENGINE" "2"]
;print ["WIND-DIR 6 = " MCDT/GET-DESCRIPTION "WIND0DIR" "6"] ;; error
;print ["WIND-DIR U = " MCDT/GET-DESCRIPTION "WIND-DIR" "U"]
;print ["TAKEN 7 = " MCDT/GET-DESCRIPTION "TAKEN" "7"]
;print "------------------------------------"
;MCDT/SAVE-TABLE %tbltest.txt
;MCDT/LOAD-TABLE %tbltest.txt
;RESULTSET: [
;    ["ACFUEL" "1" "Jet Aviation Fuel"]
;    ["ACFUEL" "2" "Aviation Gasoline"]
;    ["ACFUEL" "3" "Other type of fuel"]
;    ["PAT_STAT" "1" "Improved"]
;    ["PAT_STAT" "2" "Remained Same"]
;    ["PAT_STAT" "3" "Worsened"]
;]
;MCDT/LOAD-RESULTSET RESULTSET
;foreach [CATEGORY TABLE] MCDT/DESCRIPTIONS [
;    print [CATEGORY mold TABLE]
;]
;halt

31. Substring to position

What is a programming language without a good substring function? Actually, REBOL does not need one because other functions do the job, but as an exercise it might be fun to write one anyway. That was done early in REBOL's history and posted on the rebol.org web site, and is shown below. In this version of a substring function, the function returns a substring from a given position up through another given position. An "ending position" of -1 goes to the end of the string and this feature requires a bit of extra coding.

REBOL [
    Title: "Testing shell"
    Purpose: {Substring function.}
]

GLB-SUBSTRING: func [
    "Return a substring from the start position to the end position"
    INPUT-STRING [series!] "Full input string"
    START-POS    [number!] "Starting position of substring"
    END-POS      [number!] "Ending position of substring"
] [
    if END-POS = -1 [END-POS: length? INPUT-STRING]
    return skip (copy/part INPUT-STRING END-POS) (START-POS - 1)
]

TEST-STRING: "ABCDEFGHIJKLMNOPQRSTUVWXYZ"

print GLB-SUBSTRING TEST-STRING 6 6
print GLB-SUBSTRING TEST-STRING 10 20 
print GLB-SUBSTRING TEST-STRING 21 -1

print "Done."
halt

32. Substring for length

A more classic substring function seems to be to obtain a substring from a given position for a given length. Here is where other REBOL functions can handle that without having an official "substring" function. With a starting position and a length, you can "skip" into the main string and the "copy" for the given number of characters, all in one line of code.

REBOL [
    Title: "Testing shell"
    Purpose: {Substring function.}
]

TEST-STRING: "ABCDEFGHIJKLMNOPQRSTUVWXYZ"

print copy/part skip TEST-STRING 5 6

print "Done."
halt

33. Control break

In the world of batch processing, a common operation is to read through a file of data that has been sorted by some key value, and do something with all the records that have the same key value. Probably that would be to add up some numbers. The problem is how to detect when that key value changes, and how to set up things to move on to the next key value.

In the sample below, we start by saving the key value of the first record, in a holding area. We are going to compare the key value of every record to the value in the holding area, and we don't want to detect a change on the very first record.

Then we loop through the data and for each record we compare the key value to the holding area. If they are the same, we just do whatever it we want to do for all records for the same key, which in this case is to add up a number on each record. We want a total for each key value.

When we get a record that has a different key value, we want to add our total for the previous key value to a grand total, and then move the new key value to the holding area.

When we get to the very end, there is not going to be a new key value coming in, so we have to do our control break processing one more time for the key value we were processing up to the end.

This is not the only way of course. You could NOT save the key value of the first record in a holding area, but then the first record would cause a control break, but it would not be a real one, so you would have to program around that. Everythig is choices and trade-offs.

REBOL [
    Title: "Testing shell"
    Purpose: {Control break.}
]

DATA: [
    ["AAA" 1] ["AAA" 2] ["AAA" 3]
    ["BBB" 4] ["BBB" 5] ["BBB" 6]
    ["CCC" 7] ["CCC" 8] ["CCC" 9]
]

CURRENT-KEY: ""
CURRENT-TOTAL: 0 
GRAND-TOTAL: 0

CURRENT-KEY: DATA/1/1

foreach ROW DATA [
    if not-equal? ROW/1 CURRENT-KEY [
        print ["Total for " CURRENT-KEY " = " CURRENT-TOTAL]
        GRAND-TOTAL: GRAND-TOTAL + CURRENT-TOTAL
        CURRENT-KEY: ROW/1
        CURRENT-TOTAL: 0
    ]
    CURRENT-TOTAL: CURRENT-TOTAL + ROW/2
]
print ["Total for " CURRENT-KEY " = " CURRENT-TOTAL]
GRAND-TOTAL: GRAND-TOTAL + CURRENT-TOTAL
print ["Grand total = " GRAND-TOTAL]

print "Done."
halt

34. Write CSV file

A CSV file is almost a standard way of moving data around, so it is likely you will have to make one at some point. There are several ideas floating around, but at the core is appending data items, and commas, to a string and then writing that string to disk.

REBOL [
    Title: "Testing shell"
    Purpose: {Write CSV file.}
]

CSVFILE-ID: %test.csv
CSVFILE-DATA: ""
CSVFILE-HEADER: rejoin [
    "NAME,"
    "ADDRESS,"
    "CITY" newline
]
append CSVFILE-DATA CSVFILE-HEADER

append CSVFILE-DATA rejoin [
    "Steven White" ","
    "1800 W Old Shakopee Rd" ","
    "Bloomington"
    newline
]

write CSVFILE-ID CSVFILE-DATA

editor CSVFILE-ID

35. CSV module

This code sample is not really a pattern, but it shows a concept worth noting. When you do the same things ovef and over again, it does not take long to realize that there must be a better way. One better way is to try to make a generalized version of that thing you are doing and then use that like a layer of abstraction or a black box.

The sample below is code for reading a CSV file and taking it apart. The "pattern" would be parsing the data on the commas into individual data items. But that "pattern" is not something you would want to code fresh every time you had to take apart a file. Instead, it would be nice to encapsulate that pattern of parsing on commas into some sort of function, and then use that function. The sample below does that.

REBOL [
    Title: "Make a csv file easily readable"
]

;; [---------------------------------------------------------------------------]
;; [ This is a module for making it easy to read values in a csv file by       ]
;; [ creating words and values from a csv file.                                ]
;; [ to be more specific, we start with a csv file that has a line of          ]
;; [ headings as the first line.  Each word in the line of headings            ]
;; [ is going to be the name of the corresponding item in each following       ]
;; [ record of the csv file.  For example:                                     ]
;; [     name,address,birthdate                                                ]
;; [     "John Smith","1800 W Old Shakopee Rd",01-JAN-2000                     ]
;; [     "Jane Smith","2100 1ST Ave",01-FEB-1995                               ]
;; [     "Jared Smith",3500 2ND St",01-MAR-1998                                ]
;; [ The above text file is like a little data file.                           ]
;; [ We will "open" the file by performing some function, and then we          ]
;; [ will "read" "records" from the file until the end.                        ]
;; [ Every time we read a record, the words 'name, 'address, 'birthdate        ]
;; [ will have, as values, the values from the record we just read.            ]
;; [ In other words, when we "read" the first record, the following            ]
;; [ situation will exist:                                                     ]
;; [     name = "John Smith"                                                   ]
;; [     address = "1800 W Old Shakopee Rd"                                    ]
;; [     birtdhdate = 01-JAN-2000                                              ]
;; [ Then, when read the next record, those same words of 'name, 'address,     ]
;; [ and 'birthdate will refer to the values from the second record.           ]
;; [ And so on to the end of the file.                                         ]
;; [ Then, when we try to read beyond the end, we will get an indicator        ]
;; [ that we have reached the end of the file.                                 ]
;; [                                                                           ]
;; [ As an additional service, we want to provide the ability to rewrite       ]
;; [ a csv file after we make changes.  So, when we "open" a file, we also     ]
;; [ will copy the headings to an output area just in case we want to          ]
;; [ rewrite the file.  Then, we will provide a "write" procedure that will    ]
;; [ make a csv record out of the current data and append it to the output     ]
;; [ area.  A "close" procedure will write the output area to disk.            ] 
;; [---------------------------------------------------------------------------]

;; [---------------------------------------------------------------------------]
;; [ These are the data items used to get the csv file into memeory,           ]
;; [ pick off the first record of column headings, and so on.                  ]
;; [---------------------------------------------------------------------------]

CSV-FILE: none          ;; Name of the file, will come from caller 
CSV-LINES: none         ;; The entire contents of the file
CSV-HEADINGS: none      ;; Words from the first line as strings
CSV-WORDS: none         ;; The words from the first line as words
CSV-WORDCOUNT: 0        ;; Number of heading words 
CSV-RECORD: none        ;; The current data record, in the CSV-READ procedure
CSV-VALUES: none        ;; The parsed values from a single data line
CSV-EOF: false          ;; End-of-file flag when we "read" beyond last "record"
CSV-LENGTH: 0           ;; Number of lines in the file, including heading line
CSV-COUNTER: 0          ;; Record counter as we move through the file
CSV-VAL-COUNTER: 0      ;; For stepping through values in one record
CSV-OUTPUT-LINES: none  ;; Copy of the input file, with modifications 
CSV-OUTPUT-FILE: none   ;; Name of output file
CSV-OUTPUT-REC: none    ;; One output record
CSV-COMMACOUNT: 0       ;; Used to NOT put comma after last field of record 
CSV-IN-FIELD: false     ;; Used in comma-replacement operation
CSV-COMMA-MARKER: "%C%" ;; Will replace comma temporarily before parsing

;; [---------------------------------------------------------------------------]
;; [ We will need a function to clear the above items so that a calling        ]
;; [ program can read more than one file.                                      ]
;; [---------------------------------------------------------------------------]

CSV-CLEAR-WS: does [
    CSV-FILE: none     
    CSV-LINES: none    
    CSV-HEADINGS: none 
    CSV-WORDS: none    
    CSV-WORDCOUNT: 0 
    CSV-RECORD: none   
    CSV-VALUES: none   
    CSV-EOF: false     
    CSV-LENGTH: 0      
    CSV-COUNTER: 0     
    CSV-VAL-COUNTER: 0 
    CSV-OUTPUT-LINES: copy ""
    CSV-OUTPUT-FILE: none
    CSV-OUTPUT-REC: none 
    CSV-COMMACOUNT: 0 
    CSV-IN-FIELD: false
]

;; [---------------------------------------------------------------------------]
;; [ Procedure to "open" the file.  What does that mean?                       ]
;; [ Read the entire file into memory.  Parse the first line into a block      ]
;; [ of words.  Make a note of the number of lines in the file.                ]
;; [ Set up a counter so we can pick our way through the file and stop         ]
;; [ when we reach the last record.                                            ]
;; [ Since this module is designed for use inside another program,             ]
;; [ this function normally will be called with a file name as argument.       ]
;; [---------------------------------------------------------------------------]
CSV-OPEN: func [
    FILE-TO-OPEN      
] [
    CSV-CLEAR-WS
    CSV-FILE: FILE-TO-OPEN
    CSV-LINES: read/lines CSV-FILE
    CSV-LENGTH: length? CSV-LINES
    append CSV-OUTPUT-LINES first CSV-LINES   ;; preparation for possible writing 
    append CSV-OUTPUT-LINES newline
    CSV-HEADINGS: parse/all first CSV-LINES ","
    CSV-WORDS: copy []
    foreach CSV-HEADING CSV-HEADINGS [
        if not-equal? "" trim CSV-HEADING [
            append CSV-WORDS to-word trim/all/with CSV-HEADING " #"
            CSV-WORDCOUNT: CSV-WORDCOUNT + 1
        ] 
    ]
    CSV-COUNTER: 1 
    CSV-EOF: false
    return CSV-EOF 
]

;; [---------------------------------------------------------------------------]
;; [ The (optional) procedure to "close" the file.  What does that mean?       ]
;; [ To mimic the idea of opening a file I-O, meaning that we can rewrite      ]
;; [ a record after we have read it, we can write the data we have read        ]
;; [ into an output area, which will be a copy of the input file (or at        ]
;; [ least those records we have chosen to write).  The "close" procedure      ]
;; [ will write that file to disk.  You have to specify a file name,           ]
;; [ which may be the same (which will be like "saving" the file) or may       ]
;; [ be different (which will be like "saving as."                             ]
;; [---------------------------------------------------------------------------]

CSV-CLOSE: func [
    FILE-TO-CLOSE
] [ 
    CSV-OUTPUT-FILE: FILE-TO-CLOSE
    write/lines CSV-OUTPUT-FILE CSV-OUTPUT-LINES
] 

;; [---------------------------------------------------------------------------]
;; [ Procedure to "read" the file.  What does this mean?                       ]
;; [ Obtain the next line.  This is determined by "picking" based on the       ]
;; [ record counter.  If the counter becomes bigger than the file size,        ]
;; [ that means we have reached the end of the file.                           ]
;; [ Parse the line into a block of strings.                                   ]
;; [ For each word in the block of column headings, set that word to the       ]
;; [ corresponding item parsed from the data.                                  ]
;; [ We have to be sure to return the value of CSV-EOF so any calling          ]
;; [ procedure can use CSV-EOF to decide when to quit processing.              ]
;; [ There is a special little thing we do with each line before parsing it.   ]
;; [ It is possible that the data could contain commas.  It is customary       ]
;; [ that in such situations the field is enclosed in quotes.                  ]
;; [ We will assume that our data follows this custom, and take steps to       ]
;; [ to handle the possibility of commas in the data.                          ]
;; [ Before we parse a line on commas, we will go through the line one         ]
;; [ character at a time.  When we hit the first quote, we will assume that    ]
;; [ we are entering a fields.  From then on, we will replace commas with      ]
;; [ special place holders.  When we hit the next quote, we will assume        ]
;; [ we have left the field and we will stop replacing commas.                 ]
;; [ The next quote takes us into a field, the next one out, next in, etc.     ]
;; [ When we are done replacing embedded commas, we parse the line on          ]
;; [ commas.  Then, as we load each field, for each string field we check      ]
;; [ for our place holder and replace it with a comma.                         ]
;; [---------------------------------------------------------------------------]

CSV-REPLACE-EMBEDDED-COMMAS: does [
    CSV-IN-FIELD: false
    foreach CHARACTER CSV-RECORD [
        either equal? CHARACTER {"} [
            either CSV-IN-FIELD [
                CSV-IN-FIELD: false
            ] [
                CSV-IN-FIELD: true
            ]
        ] [
            if CSV-IN-FIELD [
                replace CHARACTER "," CSV-COMMA-MARKER
            ] 
        ]
    ]
]

CSV-READ: does [
    CSV-COUNTER: CSV-COUNTER + 1
    if (CSV-COUNTER > CSV-LENGTH) [
        CSV-EOF: true
        return CSV-EOF 
    ]
    CSV-RECORD: pick CSV-LINES CSV-COUNTER
    CSV-REPLACE-EMBEDDED-COMMAS
    CSV-VALUES: parse/all CSV-RECORD ","
    CSV-VAL-COUNTER: 0
    foreach CSV-WORD CSV-WORDS [
        CSV-VAL-COUNTER: CSV-VAL-COUNTER + 1
        TEMP-VAL: pick CSV-VALUES CSV-VAL-COUNTER
        if equal? string! type? TEMP-VAL [
            replace/all TEMP-VAL CSV-COMMA-MARKER ","
        ] 
        either TEMP-VAL [
            set CSV-WORD trim TEMP-VAL                            
        ] [
            set CSV-WORD TEMP-VAL
        ]
    ]
    return CSV-EOF 
]

;; [---------------------------------------------------------------------------]
;; [ Procedure to "write" the file.  What does this mean?                      ]
;; [ We are not really writing the file.  We are formatting the current data   ]
;; [ into a csv record and appending it to an output area.                     ]
;; [ If we do a "write" procedure for every "read" procedure, we will,         ]
;; [ in effect, copy the input file.  If we read the input, and then maybe     ]
;; [ or maybe not write to the output file, we will, in effect, filter the     ]
;; [ input file.  This is not quite like the COBOL operation of opening        ]
;; [ a file for input and output.  In COBOL, you could read a record, and      ]
;; [ then maybe or maybe not rewrite it, and at the end, you would have the    ]
;; [ same number of records in the file and maybe some of them would be        ]
;; [ altered.  Here, if you don't write the file, you don't get a record       ]
;; [ into the file, and when you close it you either write over the input      ]
;; [ file if you use the same name, or make a copy if you close under a        ]
;; [ different name.                                                           ]
;; [ Note that performing this procedure makes no sense if you don't first     ]
;; [ perform CSV-READ to read a record.                                        ]
;; [---------------------------------------------------------------------------]

CSV-WRITE: does [
    CSV-OUTPUT-REC: copy ""
    CSV-COMMACOUNT: 0 
    foreach CSV-WORD CSV-WORDS [
        append CSV-OUTPUT-REC mold get CSV-WORD ;; strings might contain commas
        CSV-COMMACOUNT: CSV-COMMACOUNT + 1 
        if (CSV-COMMACOUNT < CSV-WORDCOUNT) [
            append CSV-OUTPUT-REC ","
        ]    
    ]
    append CSV-OUTPUT-LINES CSV-OUTPUT-REC
    append CSV-OUTPUT-LINES newline
] 

;; [---------------------------------------------------------------------------]
;; [ These are helper functions for reporting selected columns to              ]
;; [ to an html file.                                                          ]
;; [---------------------------------------------------------------------------]

;; [---------------------------------------------------------------------------]
;; [ This function accepts a block of words, which usually are the column      ]
;; [ names from the file but need not be.  It converts each word to a string   ]
;; [ and emits the beginning of an html table with a row of table headers      ]
;; [ consisting of the supplied words.                                         ]
;; [---------------------------------------------------------------------------]

CSV-REPORT-HTML: ""

CSV-REPORT-HEAD: func [
    CSV-REPORT-COL-NAMES
] [
    CSV-REPORT-HTML: copy ""
    append CSV-REPORT-HTML rejoin [
        {<table width="100%" border="1">}
        newline
        "<tr>"
        newline
    ]
    foreach CSV-REPORT-COL CSV-REPORT-COL-NAMES [
        append CSV-REPORT-HTML rejoin [
            "<th>"
            to-string CSV-REPORT-COL
            "</th>"
            newline
        ]
    ]
    append CSV-REPORT-HTML rejoin [
        "</tr>"
        newline
    ]
]

;; [---------------------------------------------------------------------------]
;; [ This function must be performed to close the table that we use for        ]
;; [ the report.  Note that the html string we are creating is only a table    ]
;; [ and not a full html page.  This is by design.                             ]
;; [---------------------------------------------------------------------------]
CSV-REPORT-FOOT: does [
    append CSV-REPORT-HTML rejoin [
        "</table>"
        newline
    ]
] 

;; [---------------------------------------------------------------------------]
;; [ This function accepts a block of words which MUST BE words from the file. ]
;; [ It puts the values of those words into td elements and appends them to    ]
;; [ the html string.                                                          ]
;; [---------------------------------------------------------------------------]

CSV-REPORT-LINE: func [
    CSV-REPORT-COL-NAMES
] [
    append CSV-REPORT-HTML rejoin [
        "<tr>"
        newline
    ]
    foreach CSV-REPORT-COL CSV-REPORT-COL-NAMES [
        append CSV-REPORT-HTML rejoin [
            "<td>"
            get CSV-REPORT-COL
            "</td>"
            newline
        ]
    ]    
    append CSV-REPORT-HTML rejoin [
        "</tr>"
        newline
    ]
]

36. CSV module demo

With the above module for reading CSV files, we can make a "pattern" from that. Assuming the above module has been put into a file called csvfile.r, and we have a test CSV file called CSVdemo.csv that looks like this...

NAME,ADDRESS,CITYSTATE
"White, Steven",1800 W OLD SHAKOPEE RD,BLOOMINGTON MN
"Johnson, John",1801 W OLD SHAKOPEE RD,BLOOMINGTON MN
"Smith, Mister",1802 W OLD SHAKOPEE RD,BLOOMINGTON MN
36 we can show a pattern of using the csvfile.r module that we could use

for many CSV files.

In this sample, we bring in the above module with the "do" function, "open" the file with the function provided, "read" the first record, and then process each record until we hit the end.

REBOL [
    Title: "Testing shell"
    Purpose: {CSV module demo.}
]

do %csvfile.r

CSV-OPEN %CSVdemo.csv

CSV-READ

until [
    print [NAME ":" ADDRESS ":" CITYSTATE]
    CSV-READ ;; Returns true value at EOF
]

print "Done."
halt

37. CSV extraction with Powershell

It seems that there is not a way to use REBOL to get data out of a spreadsheet, but it is possible with Powershell, so if you can use a Powershell script as an intermediary, you can call that script. Here is an example.

################################################################################
# 
# This script seems to save a spreadsheet as a csv file.
# 
# It is slightly generalized to get the name of the spreadsheet and the
# name of the output file as parameters.
#
# Trial and error indicates that the file names specified as the input
# parameters must be full path names.  It appears that quotes around the file
# names are optional.
# 
################################################################################

param ($XLS, $CSV)
#write-host $XLS ## for debugging
#write-host $CSV

$saveascode=6 
$spreadsheetfile=$XLS 
$csvfile=$CSV
$spreadsheet=New-Object -comobject "Excel.Application" 
$workbook=$spreadsheet.workbooks.open($spreadsheetfile)
$worksheet=$workbook.worksheets.item(1) 
$spreadsheet.displayalerts=$False 
$workbook.SaveAs($csvfile,$saveascode) 
$workbook.close()
$spreadsheet.quit() 
if (ps excel) { kill -name excel}

Here is a way to call the above script that works at least in some situations.

;; [---------------------------------------------------------------------------]
;; [ Build the command to run the powershell script that will extract          ]
;; [ data out of the spreadsheet file and into the csv file.                   ]
;; [ And yes, even though XLS-FILE and CSV-FILE are file! datatypes,           ]
;; [ it seems that the to-file function below is necessary.                    ]
;; [---------------------------------------------------------------------------]

CMD-STRING: reduce [
    " powershell -Command ExtractCSV.ps1 "
    to-file XLS-FILE
    " "
    to-file CSV-FILE
]   
call/wait CMD-STRING

38. CSV to Excel with powershell

On the subject of CSV files, it is possible to have a REBOL program produce a spreadsheet, but, it seems, not directly. Here is a way that has worked.

Put the spreadsheet data into CSV files and then call a powershell script to do the dirty work. The has worked on Windows 10 with the "call/shell" function.

The following example was created with some help from the internet and some trial and error. It loads not just one, but three CSV files into three tabs of a spreadsheet. The script was written to be used over and over again on CSV files created from some other application, and differentiated by a "batch ID" as part of the file name. That batch ID is passed to the script so that it can build the file names, thus giving it some generality.

But first, here is a way the powershell script could be called. One would adjust the file path for one's own situation.

;; obtain the batch id from somewhere and name it WS-BATCH
...
CMD-STRING: rejoin [
    " powershell -Command PaymentRecovery.ps1 "
    {"}
    WS-BATCH
    {"}
] 
...
call/shell CMD-STRING

And now here is the powershell script that would be called PaymentRecovery.ps1.

###############################################################################
# This is a script developed by trial and error to load three CSV files
# into three tabs of a single spreadsheet file.  
# This is a sanitized part of a project to recover some payments reports
# from data produced by three SQL queries that put their results into
# three CSV files.  Parts of this script were borrowed from the internet. 
###############################################################################

param ($BATCHID) 

# Three csv files produced by three SQL queried
$FILE1 = "I:\IS_Apps_MyReports\PaymentDetail-$BATCHID.csv"
$FILE2 = "I:\IS_Apps_MyReports\PaymentDistribution-$BATCHID.csv"
$FILE3 = "I:\IS_Apps_MyReports\PaymentPosting-$BATCHID.csv"

# The final spreadsheet file we will create
$OUTFILE = "I:\IS_Apps_MyReports\PaymentRecoveryReports-$BATCHID.xlsx"

# Create a Excel Workspace
$excel = New-Object -ComObject Excel.Application

# make excel visible
$excel.visible = $true

# add a new blank worksheet
$workbook = $excel.Workbooks.add()

# Adding Sheets
$sheet4 = $workbook.Sheets.add()
$sheet4.name = "PaymentDetail"
$sheet5 = $workbook.Sheets.add()
$sheet5.name = "PaymentDistribution"
$sheet6 = $workbook.Sheets.add()
$sheet6.name = "PaymentPosting"

# The default workbook has three sheets, remove them
($s1 = $workbook.sheets | where {$_.name -eq "Sheet1"}).delete() 

#Start row and column
$r = 1
$c = 1
#Begin working through file 1
$file = (GC $FILE1)
ForEach ($f in $file) {
  $arr = ($f).split(',')
  ForEach ($a in $arr) {
    $sheet4.Cells.Item($r,$c) = "$(($a).replace('"',''))"
    $c++
    }
  $c = 1
  $r++    
  }    
#Select all used cells
$range = $sheet4.UsedRange
#Autofit the columns
$range.EntireColumn.Autofit() | out-null 

#Start row and column
$r = 1
$c = 1
#Begin working through file 2
$file = (GC $FILE2)
ForEach ($f in $file) {
  $arr = ($f).split(',')
  ForEach ($a in $arr) {
    $sheet5.Cells.Item($r,$c) = "$(($a).replace('"',''))"
    $c++
    }
  $c = 1
  $r++    
  }    
#Select all used cells
$range = $sheet5.UsedRange
#Autofit the columns
$range.EntireColumn.Autofit() | out-null 

#Start row and column
$r = 1
$c = 1
#Begin working through file 3
$file = (GC $FILE3)
ForEach ($f in $file) {
  $arr = ($f).split(',')
  ForEach ($a in $arr) {
    $sheet6.Cells.Item($r,$c) = "$(($a).replace('"',''))"
    $c++
    }
  $c = 1
  $r++    
  }    
#Select all used cells
$range = $sheet6.UsedRange
#Autofit the columns
$range.EntireColumn.Autofit() | out-null 

#Saving File
$workbook.SaveAs($OUTFILE)

#Close Excel
#$excel.quit()

39. Base 64 image

Something that comes up a lot is embedding images in code. The way to accomplish that seems to be to encode it in base 64 encoding and then put the result into the source code The sample below does that, encapsulated into a function that you could save and use.

REBOL [
    Title: "Testing shell"
    Purpose: {Image string.}
]

IMAGE-STRING: does [
    system/options/binary-base: 64
    IMAGESTRING-FILE: request-file/only
    if not IMAGESTRING-FILE [
        alert "No file specified"
        exit
    ]
    IMAGESTRING-STRING: read/binary IMAGESTRING-FILE
    save clipboard:// IMAGESTRING-STRING
    alert "Hex representation of image is on the clipboard"
]

IMAGE-STRING

print "Done."
halt

40. Base 64 image in VID layout

If you make a base-64 image as shown in the previous example, you can paste it into a script and put it into a VID layout as shown in this example.

This example might not be the most efficient. If you look around on the internet, especially in Nick's documentation, you will see that you can combine functions for converting to string, compressing, uncompressing, converting to binary, and so on, to accomplish this same thing, perhaps more efficiently (that is, in a smaller size at the insignificant cost in more processing). Feel free to experiment.

REBOL [
    Title: "Testing skeleton"
    Purpose: {Show an embedded image.}
]

system/options/binary-base: 64

DEMO-LOGO: load
64#{
iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAIAAACRXR/mAAAABmJLR0QA/wD/AP+g
vaeTAAABzUlEQVRYhdXZzYrCMBAH8HHFJ9h3KgV7Ujyo9erNl/HmO3j1WfYBeigM
1GuhrcwexN1KTTMfiewOOYVCfvwDZZJMvgA+4bmyDE4nmM3gDdW2sN/D5dKfqwAA
AWg40pTqmmJXXVOaDldHJ+sNMofJxwKg5ZKaJoqpaWixcK3rY0XKzJ0TmxVc5jM9
WPO5hxVwN0f37peVZYBlSXnul9kzY+REALTbYVkCIlLXRZexTdR1iAiISERxZRIT
EfVY8WRC04AVQyY3vWKFlalMDlYomdbkZtllBtMoyyKzmXwsncxsYrCkshAmHosv
SxJKEruJzeLLQpgkrCAynknIMsrYJjlLLZOYVCyFTGjSsu6y9Zpl2mykpjvrQ3nm
vF5ZX1YVtK1mCXFazH/mz5B3jvJNlJpUMiFLZ5LLJCyLSShjs+wmiYzHYprynLbb
IDIGS9SrBDoH+FiK/imEbJSl7unMMjfL2GfaZA5WkN7XIHvFCtSPW2QDVkCTQfbM
Cm7SynqsSCaV7MGKapLLEBGwKKKbhDIsij97pfuGnPrFyIxxLx/WxJP9x8eVGDn1
y52ZmxXbNCpDgMmLZ87VCo5HmE415ztp3W5wOMD53J+rAL4B3kFQEgTgjAIAAAAA
SUVORK5CYII=
}
view layout [
    image DEMO-LOGO
    button "Quit" [quit]
]

41. Compressing an embedded image

Look at the previous two examples. In the first example, the image that will eventually be put on a window is brought in with the read/binary function and the saved on the clipboard. In the second example, what is pasted into the program did come from the code in the first example, so we assume that it is binary data. It is put into the DEMO-LOGO word with the "load" function which is the opposite of the "save" function.

That means that what you "load" to make an image must be somthing that is binary.

The code sample below was copied out of Nick's Big Book.

http://business-programming.com/business_programming.html

From the above examples we know that if we want to create an image we have to load something that is binary.

From the REBOL function dictionary, we know that if we want to compress something, the "something" has to be a string.

In the code sample below, the word "picture" refers to a compressed string that was created by reading a file in binary and converting it to a string, and the image was created by decompressing the "picture" string and converting it back to binary, and then "loading" it.

Thank you Nick.

alert "Select a picture from your hard drive:"
system/options/binary-base: 64
editor picture: compress to-string read/binary to-file request-file/only
view layout [image load (to-binary decompress picture)]

; This example embedded image was created with the script above:

logo-pic: load to-binary decompress #{
789C018A0375FC89504E470D0A1A0A0000000D49484452000000640000001808
020000008360CFB90000001374455874536F667477617265005245424F4C2F56
6965778FD916780000033249444154789CD599217402310C86F7CE6227B1481C
1637874362B1382C1687C4A15168240A89C5A2B058ECDEBE47DFFA429276DCEE
10FDCD582F97267FD33F2D7CF47ABDCF32D1ED76E7F3F9ED76FB4EE0743A8D46
A3B6A683A80FFE540562381C1E8FC7144D12DBEDB6951C3B9D4E91648DC7E34C
41B925465D349C14A2CA230BA65EA729E27C3E37CCB43CB228905A3525B1DBED
9A4CED93851C7C193088A0667C0D0603FB5640BFDFB7F648C0D0836B1C41C22E
11D7EBF57038F074BFDF534429BE2693891B4626CE1C59BC7CB95CDC99EEF7FB
66B349F922D65A4B4A8DE0D0B547B9DD85212B6B4CB4D3E994B055FEE8943566
30134626BBDA64052C974BD757A637B1DA2E599959A05EE61F4032D62C55EFBC
6EED01878954188DC80AE714C07126D24F91BBBE6265A129B3D96C2A4085BB64
459FEBF51A1B2692E5A9FA17A428B562EBE595A1F29650AD5C6B9525FD4621E0
A95D73491606F9046C94101A06178B4518E19122023655DA184B03ECA15BE98E
6D9D302E536E8D2C96A5FF0061458FEE9EAA045958720EDCFC82CF145A9E2C7C
52BC6CF0503B8C2B2200DAACD24698A4B710361E6421930E05A85E9484BE51B3
0885AE9727CB22A5591981B73D1AC6A58D2ABD5892DF46C5993DCFF25BC8828E
14538AACEB3390A43C59D890213B5D2AA3D2AC3C59ABD54ACE2E85C29E36DE42
162B8C0AC47F0942B512972CCCF0D91170ED6594ECC130288549ED44744DE52C
771381C571D5AFEDB14B2E79CB022F13C834A056049EFCE35C2A7449877A2B00
2D872635082FEA2D267D8BC047AD910D3875CE9247078A826259FC8234F264E1
9FAD4AAC52015465D973193B3755B611B417FB562A0C66C77EF7001F5463FD83
2CF20F83B2B8E0C22DAE760FA556B32AAF87B86A18C18259CFAA3567C250C7C3
1AE72CD95350531BD93FAE3B6CEADB33188174FCBBD77B7B7A0841DAB6C3EBEE
F13DE8696B6455E222ADCE23F162ECF644064709A47AA8FD3632BFAD78EA5E92
D947500C3BB04CAD419F3D5B05580DC127118E3D2866CAFB8AC6CAFCEB68F895
56796455CF47AAD741F5B957D4D751245980BD569729B723D742A964558FFB4D
EAB6A440BF6ACE54157EB028F7A730B695BDF749D05EA9C1B612C4CF0F396EDC
8E943F5C020000000049454E44AE426082CAEBA2D78A030000
}
view layout [image logo-pic]

42. Compressing a script

Here is a little programming aid that will load the clipboard with a compressed script of your choosing. The idea behind it is that you then would paste the clipboard into your source code if you wanted to embed a script in your code.

REBOL [
    Title: "Script compressor"
    Purpose: {Ask for the name of a script, read it, compress it,
    mold it into a displayable format, and put it on the clipboard.
    This is a coding aid.}
]

if not FILE-ID: request-file/only [
    alert "No file requested."
    quit
] 

system/options/binary-base: 64
write clipboard:// mold compress read FILE-ID

alert "Clipboard loaded."

43. Compressing scripts into a package

One thing you will see a bit of in the REBOL world is documentation that includes a big script, but the big script, instead of being included in the documentation in its "raw" form, is compressed so that you can copy out the compressed script, paste it into an editor, save it and, depending on exactly it is packaged, either decompress it or run it if it is presented as a runnable script.

Here is a sample of how you can use to compress and package a script into another script, such that if you run that other script it will unpack and saved the compressed script.

REBOL [
    Title: "Script packager"
    Purpose: {Package up one or more script (text) files into
    a REBOL script that will unpack them.}
]

PACKAGE-STRING: ""

PACKAGE-HEADER: {REBOL [
    Title: "Script unpacker"
]
}

PACKAGE-FOOTER: {
alert "Done."
}

SCRIPT-HEADER-MODEL: {
write %%OUTPUT-NAME%% decompress 
%%SCRIPT-STRING%%
}
SCRIPT-HEADER: ""

if not FILE-LIST: request-file [
    alert "No files selected"
    quit
]

append PACKAGE-STRING PACKAGE-HEADER

system/options/binary-base: 64
foreach NAME FILE-LIST [
    SCRIPT-HEADER: copy SCRIPT-HEADER-MODEL
    replace SCRIPT-HEADER "%%OUTPUT-NAME%%" mold second split-path NAME
    replace SCRIPT-HEADER "%%SCRIPT-STRING%%" mold compress read NAME
    append PACKAGE-STRING SCRIPT-HEADER
]

append PACKAGE-STRING PACKAGE-FOOTER

write %package.r PACKAGE-STRING

alert "Done."

44. Base 64 IMG tag

It is possible to hard-code an image into a web page, in contrast to linking to an image file. This can be done by encoding the image in base-64 encoding. The code below is a function you could include in a program to create such an image.

REBOL [
    Title: "Make an html img tag from an image file"
    Purpose: {Request an image file, read it, convert it to base 64,
    and put it into an img tag for embedding in a web page.}
]

;; [---------------------------------------------------------------------------]
;; [ It is possible to embed an image into an html document if the image       ]
;; [ can be incoded as base 64, whatever that means.  This function takes      ]
;; [ a file name and a text description, reads the file, converts it to        ]
;; [ base 64, and makes an html img tag.  It uses the passed text description  ]
;; [ as the "alt" attribute for the image.                                     ]
;; [ The function does no checking about the existence of the image file.      ]
;; [ That would more appropriately be done by the caller.                      ]
;; [---------------------------------------------------------------------------]

IMGTAG: func [
    FILENAME
    ALTDESC
] [
    return rejoin [ 
        {<img alt="} ALTDESC {" }
        {src="data:image/}
        at form suffix? FILENAME 2
        {;base64,}
        enbase/base read/binary FILENAME 64
        {">}
    ]
]

;;Uncomment to test, provide your own image called TestImage.png (or jpg). 
;write %imgtagtest.html rejoin [
;{<html>
;<head><title>IMGTAG test</title></head>
;<body>
;<h1>IMGTAG test</h1>
;}
;IMGTAG %TestImage.png "Elbow image"
;{</body>
;</html>
;}
;]
;browse %imgtagtest.html

45. Date and time stamps

Fixed-format dates and times are useful for including in log files and file names. Once you have had to make date or time stamps a few times you will weep at the prospect of doing it again and will want to find a way to ease the pain. The way would be to make a function that could do that for you. Here is a sample that you could include in a program.

REBOL [
    Title: "Date and time 'to' functions"
    Purpose: {Some functions for formatting dates and time in useful ways.}
]

;; [---------------------------------------------------------------------------]
;; [ Some functions borrowed from or inspired by the REBOL cookook for         ]
;; [ putting dates and times into useful formats.                              ]
;; [ The important feature of these functions is that for single-digit         ]
;; [ items (January = 1) the function puts on a leading zero, so that the      ]
;; [ resulting dates and times all are the same length.  This is useful        ]
;; [ in, for example, date and time stamps in file names.                      ]
;; [---------------------------------------------------------------------------]

to-yyyymmdd: func [when /hyphens /slashes /local stamp add2] [
    add2: func [num] [ ; always create 2 digit number
        num: form num
        if tail? next num [insert num "0"]
        append stamp num
    ]
    stamp: form when/year
    if hyphens [append stamp "-"]
    if slashes [append stamp "/"]
    add2 when/month
    if hyphens [append stamp "-"]
    if slashes [append stamp "/"]
    add2 when/day
    return stamp
]

to-hhmmss: func [when /colons /local stamp add2] [
    add2: func [num] [ ; always create 2 digit number
        num: form num
        if tail? next num [insert num "0"]
        append stamp num
    ]
    stamp: copy ""
    add2 when/hour
    if colons [append stamp ":"]
    add2 when/minute
    if colons [append stamp ":"]
    add2 to-integer when/second
    return stamp
]

;;Uncomment to test
;print to-yyyymmdd now/date
;print to-yyyymmdd/hyphens now/date
;print to-yyyymmdd/slashes now/date
;print to-hhmmss now/time
;print to-hhmmss/colons now/time
;halt

46. Calling a Windows executable file

The REBOL "call" function does not always seem to work, but here is an example of something that does work, the calling of a dot-exe file. In this case, voice.exe is a text-to-speech program downloaded from the internet.

REBOL [
    Title: "Testing shell"
    Purpose: {Calling Windows executable.}
]

ANNOUNCE: func [
    NAME
] [
    CMD: copy ""
    CMD: rejoin [
        "voice.exe "
        {"Welcome }
        NAME
        {"}
    ]
    call CMD
]

ANNOUNCE "Steven" 

print "Done."
halt

47. CGI reading module

This example is a complete module that can be used to get the input of a CGI form. The significance of this module is that at some point someone beat his head enough on the coding for CGI forms that he could not take it anymore, and wrote a module to do all that fussing. The next sample will show how the module might be used. For now, here is the CGI module as a background for the next "pattern."

This example also shows how comments can be put in front of the REBOL header.

TITLE
CGI common procedures

SUMMARY
These are common procedure that can be used in CGI programs to make
it easier to write them, without having to remember some of the
technical details of CGI programs.

DOCUMENTATION
Include the module in your program with

do %cgi.r 

If the module is not in the current directory, specify the full name
either with a drive letter or a UNC name in the REBOL syntax.

Usually, your program will be executed by the web server in response
to a request from a web browser.  Also usually, there will be data
availble from some sort of HTML form.  In the HTML form, the INPUT
items will be identified by the "NAME" attribute.  To get your hands
on the data from the form, use this procedure:

CGI-GET-INPUT

This procedure detects the proper source of the input data (GET or
POST) and reads the data, and then assembles it into an object.
Each data item can be referenced using the "path" syntax of

CGI-INPUT/data-name-1  

where "data-name-1" is the name sepecified in the "NAME" attribute.

After processing any input, your program will display some HTML output.
There are two main ways of doing that.

What you are going to do in general is build up a full HTML page in memory
and the "print" it with the "print" function, which will cause the page
to be sent back to the web server and then the web browser.  But before
you do that, you must print some special headers with this function:

CGI-DISPLAY-HEADER.

To build up that HTML page that you will print, there are two ways.  Each way
has the common end point of appending some HTML coding to the end of that
big page in memory.

The first way is to construct HTML in your program.  You can do this a line
at a time, or several lines at a time.  The HTML can contain rebol words,
because it will be reduced.  Build you HTML in a word and then do

CGI-EMIT-HTML data-name-2

Where data-name-2 is that rebol word that contains your HTML line(s).

The second way is to make a separate file of HTML. In this HTML file, you may
embed rebol code inside <% and %> tags.  This code will be evaluated, and the
results of the evaluation will replace the rebol code and its surrounding
tags.  This is sort of what PHP does.  The rebol code can reference words in
your program, so that is how you can get data that is in your program put into
HTML.  Do this:

CGI-EMIT-FILE file-name-1

Where file-name-1 is the name of that file of HTML code with the optional
embedded rebol code.

When you have built up a full HTML page, it is your own responsibility to
send it to the web server with the following command:

print CGI-OUTPUT 

There is another somewhat-related service supplied by this module.
Sometimes a program is written to display HTML not to be interpreted by
a browser, but to be shown as HTML.  That can be done with:

data-name-3: CGI-ENCODE-HTML data-name-4

where data-name-4 is an HTML fragment, and data-name-3 is that same fragment
with the tag markers ("<" and ">") replaced the the code that causes them
to be shown by the browser.

SCRIPT
REBOL [
    Title: "CGI common procedures"
]

;; [---------------------------------------------------------------------------]
;; [ This is a module of common procedures used in a CGI program.              ]
;; [---------------------------------------------------------------------------]

;; [---------------------------------------------------------------------------]
;; [ This procedure is used to gradually build up a string of HTML             ]
;; [ to return to the browser.  When this module is first loaded,              ]
;; [ it makes a string to hold the HTML.  Then, is is called                   ]
;; [ repeatedly with a block of REBOL code and data as a parameter.            ]
;; [ The procedure evaluates any REBOL expressions ("reduces" them)            ]
;; [ and then appends the result to the end of the string we are               ]
;; [ building.  Finally, it puts a line-feed at the end so we don't            ]
;; [ create just one gigantic string as the final result.                      ]
;; [ (This will be appreciated by anyone who tries to view the                 ]
;; [ source of the resulting page with the browser.)                           ]
;; [---------------------------------------------------------------------------]

CGI-OUTPUT: make string! 5000
CGI-EMIT-HTML: func [CGI-OUT-LINE] [
    repend CGI-OUTPUT CGI-OUT-LINE
    append CGI-OUTPUT newline
]

;; [---------------------------------------------------------------------------]
;; [ This little procedure displays the header that is required                ]
;; [ when sending an html page back to the browser.                            ]
;; [ The procedure is separate because, while it must be done,                 ]
;; [ and it must be the first thing done, the caller might be                  ]
;; [ sending back a regular page, or a debugging page, or                      ]
;; [ who-knows-what, so we will let the caller do this when he                 ]
;; [ wants to.  But he must.                                                   ]
;; [---------------------------------------------------------------------------]

CGI-DISPLAY-HEADER: does [
    print "content-type: text/html"
    print ""
    print ""
]

;; [---------------------------------------------------------------------------]
;; [ This procedure uses the above procedure and is an alternate               ]
;; [ way to emit HTML.  This procedure accepts a file name as a                ]
;; [ parameter and reads that file into a string, and then calls               ]
;; [ the above procedure to add the file to the end of the HTML                ]
;; [ string that is being built up by the above procedure.                     ]
;; [ Before this procedure calls the above procedure, it runs the              ]
;; [ build-markup function on the file it read.  That function                 ]
;; [ locates special tags (<% and %>) and runs REBOL code inside               ]
;; [ those tags, similar to what PHP does.  Inside those tags                  ]
;; [ there can be REBOL words to be evaluated.  It is the job of               ]
;; [ the caller of this procedure to make sure that any words                  ]
;; [ used inside the build-markup tags are actually defined in                 ]
;; [ the calling program.                                                      ]
;; [---------------------------------------------------------------------------]

CGI-EMIT-FILE: func [
    CGI-FILE-TO-EMIT [file!]
] [
    CGI-EMIT-HTML build-markup read CGI-FILE-TO-EMIT
] 

;; [---------------------------------------------------------------------------]
;; [ This is a procedure that attempts to do as much as possible               ]
;; [ to help in the processing of CGI data.                                    ]
;; [ The procedure CGI-GET-INPUT reads the CGI data in whatever                ]
;; [ form it is presented                                                      ]
;; [ (POST or GET), and then puts the raw data into a string                   ]
;; [ called CGI-STRING.  Then it uses the decode-cgi command to                ]
;; [ break it apart into name/value pairs.                                     ]
;; [ It passes the name/value pairs to the construct function                  ]
;; [ which makes them into a context called CGI-INPUT.                         ]
;; [ As a context, the data can be referenced as                               ]
;; [ CGI-INPUT/data-name where data-name is a name specified in                ]
;; [ the "name" attribute in the HTML form.                                    ]
;; [                                                                           ]
;; [ The procedure CGI-GET-INPUT seems to hang up on IIS.                      ]
;; [ As a workaround, there is a separate procedure for IIS that returns       ]
;; [ the same CGI-INPUT context, but by different means.                       ]
;; [ The "different means" is to read a fixed amount of data out of            ]
;; [ the system/ports/input port.                                              ]
;; [ These two procedures are mutually exclusive.  Use on or the other.        ]
;; [---------------------------------------------------------------------------]

CGI-STRING: ""
;;  -- Apache version

CGI-GET-INPUT: does [
    CGI-STRING: CGI-READ
    CGI-INPUT: construct decode-cgi CGI-STRING
]
CGI-READ: func [
    "Read CGI data (GET or POST) and return as a string or NONE"
    /limit CGI-MAX-INPUT "Limit input to this number of bytes"
    /local CGI-DATA CGI-BUFFER
] [
    if none? limit [CGI-MAX-INPUT: 100000]
    switch system/options/cgi/request-method [
        "POST" [
            CGI-DATA: make string! 1020
            CGI-BUFFER: make string! 16380
            while [positive? read-io system/ports/input CGI-BUFFER 16380] [
                append CGI-DATA CGI-BUFFER
                clear CGI-BUFFER
                if (length? CGI-DATA) > CGI-MAX-INPUT [
                    print ["aborted - form input too large:"
                        length? CGI-DATA "; limit:" CGI-MAX-INPUT]
                    quit
                ]  
            ]
        ]
        "GET" [
            CGI-DATA: system/options/cgi/query-string
        ]
    ]
    CGI-DATA
]

;;  -- IIS version

CGI-GET-INPUT-IIS: does [
   CGI-STRING: CGI-READ-IIS
   CGI-INPUT: construct decode-cgi CGI-STRING
]
CGI-READ-IIS: func [
] [
    CGI-DATA: make string! 5000
    switch system/options/cgi/request-method [
        "POST" [
            read-io system/ports/input CGI-DATA 5002
        ]
        "GET" [
            GGI-DATA: system/options/cgi/query-string
        ]
    ]
    CGI-DATA
]
;; [---------------------------------------------------------------------------]
;; [ This procedure exists for those cases where a CGI program                 ]
;; [ is going to display HTML code for the purpose of actually                 ]
;; [ displaying the code and not having that code rendered into                ]
;; [ an HTML display.  It accepts a string and replaces the                    ]
;; [ less-than and greater-than signs with the escape sequences                ]
;; [ that will cause a browser to display those signs instead of               ]
;; [ interpreting them.                                                        ]
;; [---------------------------------------------------------------------------]

CGI-ENCODE-HTML: func [
    "Make HTML tags into HTML viewable escapes (for posting code)"
    CGI-TEXT-TO-ENCODE
] [
    foreach [CGI-TAG-CHAR CGI-ESC-SEQ] ["&" "&amp;" "<" "&lt;" ">" "&gt;" ] [
        replace/all CGI-TEXT-TO-ENCODE CGI-TAG-CHAR CGI-ESC-SEQ
    ]
]

;; [---------------------------------------------------------------------------]
;; [ Here is/are some debugging procedure(s) we can use to find                ]
;; [ out where things might be going wrong.  When a CGI program                ]
;; [ doesn't work, many times it doesn't produce any output at                 ]
;; [ all.                                                                      ]
;; [---------------------------------------------------------------------------]

CGI-DEBUG-MESSAGE: ""
CGI-DEBUG-PAGE: {
<HTML>
<HEAD>
<TITLE>CGI debugging page</TITLE>
</HEAD>
<BODY>
<% CGI-DEBUG-MESSAGE %>
</BODY>
</HTML>
}
CGI-DEBUG-DISPLAY: func [
    CGI-DEBUG-BLOCK [block!]
] [
    CGI-DEBUG-MESSAGE: reform CGI-DEBUG-BLOCK
    CGI-EMIT-HTML build-markup CGI-DEBUG-PAGE
    print CGI-OUTPUT
]

48. CGI form processing

With the above CGI module pre-written, we can see a pattern for CGI form processing. The above module would be like black box, and we would call functions in it to get data from a form.

The code snippets below are just an example pulled from a larger program. First, we have the html form taken from a web page. Note that one of the "input" items has been given a name of ENTERPERMIT-NUMBER-KEY.

<form action="http://websitename.gov/cgi-bin/PermitLookup.r" method="post">
<p>
<strong>Enter 7-digit permit number: &nbsp;</strong> 
<input name="ENTERPERMIT-NUMBER-KEY" size="20" type="text" /> 
<input type="submit" value="FIND" />
</p>
</form>

Next we have a snippet from a REBOL program that gets data from that form. Note that we need just a function call to get all the "input" items on the form, and they are named with the same names as they were given on the form.

Another little trick worth noting is that there is a switch in the program called DEBUG. If we set that to true, and run the program, then it will ask for input from the operator and display its output to the screen. This is a way to debug the program if it is not producing the expecte output.

And finally, note that after we get the input field, since we are expecting in this case seven characters, we chop off only seven characters. This prevents an SQL insertion attack. (The GLB-SUBSTRING function is a function written elsewhere that extracts a substring given starting and ending positions.)

;; [---------------------------------------------------------------------------]
;; [ Get the permit number from the input form.                                ]
;; [---------------------------------------------------------------------------]

either DEBUG [
    RAW-INPUT: ask "Enter permit number: "
] [
    CGI-GET-INPUT-IIS
    RAW-INPUT: copy CGI-INPUT/ENTERPERMIT-NUMBER-KEY
]
WS-PERMITNUMBER: GLB-SUBSTRING trim/head RAW-INPUT 1 7

49. Next ID number

In some situations you might want to add records to a database where the key to the record is just a sequential number. Somehow, you have to be able to find the next number to assign. Here is a function that does that by just storing the highest assigned number in a plain text file.

REBOL [
    Title: "Get next ID"
    Purpose: {Get a number one higher than the number stored in
    a specified file, and store the new number back in the 
    specified file.}
]

;; [---------------------------------------------------------------------------]
;; [ This is a function written for the situation where you are assigning      ]
;; [ ID numbers to things (like data records) and want to keep track of        ]
;; [ the highest number you have assigned.  The highest number assigned is     ]
;; [ kept in a one-line file, and the function reads that number, adds 1 to    ]
;; [ it, saves the new number, and returns the new number so you can           ]
;; [ assign it to some new thing.                                              ]
;; [ This is an operation one wants to do with as few instructions as          ]
;; [ possible.                                                                 ]
;; [ Because the name of the file is passed to the function, this same         ]
;; [ function could be used in a program that has several such ID numbers.     ]
;; [ To save the trouble of initialization, if the specified file does         ]
;; [ not exist, we will assume we are starting with ID number 1 and create     ]
;; [ the file with that number in it.                                          ]
;; [---------------------------------------------------------------------------]

GET-NEXT-ID: func [
    FILE-ID
] [
    either exists? FILE-ID [
        save FILE-ID HIGHEST-OPEN: add 1 load FILE-ID
    ] [
        save FILE-ID HIGHEST-OPEN: 1
    ]
    return HIGHEST-OPEN
]

;;Uncomment to test
;print GET-NEXT-ID %HighestOpen.txt
;print GET-NEXT-ID %HighestOpen.txt
;halt

50. Find files of a given type

This is an operation that keeps coming up, to the point where it was necessary, for sanity, to encapsulate it in a function.

The problem is to find all the file names of a given type, in the current directory. Carl showed how to do that in one of his sample programs. The procedure is shown in the function below.

REBOL [
    Title: "Function to get all names of certain file types"
    Purpose: {Generalized version of a function from a program by
    Carl.  Given a block of file types, return a block of all the
    file names in the current directory that are of that type.}
]

;; [---------------------------------------------------------------------------]
;; [ This is a function borrowed from Carl's picture viewer program.           ]
;; [ Pass to it a block of file types, and the program will assemble a list    ]
;; [ of all files in the current directory of those types.  Return the list    ]
;; [ in a block.  For example:                                                 ]
;; [     FILE-LIST: FILES-OF-TYPE [%.jpg %.JPG %.png %.PNG]                    ]
;; [ Note how you can make a function within a function.                       ]
;; [ General procedure is to get a list of all files in the current folder.    ]
;; [ Go through the list.  If a file has the desired suffix, go on to the      ]
;; [ next file.  Otherwise remove it from the list.  At the end, reposition    ]
;; [ to the head of the list and return it to the caller.                      ]
;; [---------------------------------------------------------------------------]

FILES-OF-TYPE: func [
    TYPE-LIST
    /local FILE-ID-LIST
] [
    OF-TYPE?: func [
        FILE-ID 
    ] [
        find TYPE-LIST find/last FILE-ID "."
    ]
    FILE-ID-LIST: copy []
    FILE-ID-LIST: read %.
    while [not tail? FILE-ID-LIST] [
        either OF-TYPE? first FILE-ID-LIST [
            FILE-ID-LIST: next FILE-ID-LIST
        ] [
            remove FILE-ID-LIST
        ]
    ]
    FILE-ID-LIST: head FILE-ID-LIST
    return FILE-ID-LIST
]

;;Uncomment to test
;probe FILES-OF-TYPE [%.txt %.TXT]
;print "-------------------------------"
;probe FILES-OF-TYPE [%.png %.jpg]
;print "-------------------------------"
;probe FILES-OF-TYPE [%.r]
;halt

51. Hexadecimal value of a byte

An operation that is done often enough to be important but not often enough to remember, is getting a printable representation of the hexadecimal value of a single byte. So, once we figured out how to do that, we encapsulated it so we can use it again without having to read the reference manual again.

REBOL [
    Title: "Hex byte"
    Purpose: {Convert a one-character string to a two-character
    display of its hex value, suitable for printing.}
]

;; [---------------------------------------------------------------------------]
;; [ This little function is part of a project to print a string of bytes      ]
;; [ that has some unprintable characters.  It takes one character and         ]
;; [ returns two, that are the hex representation of the byte.                 ]
;; [---------------------------------------------------------------------------]

HEX-BYTE: func [
    BYTE
] [
    return reverse copy/part reverse to-string to-hex to-integer to-binary BYTE 2
]

;;Uncomment to test
;print ["X =" HEX-BYTE "X"]
;print ["7 =" HEX-BYTE "7"]
;print ["! =" HEX-BYTE "!"]
;print ["[ =" HEX-BYTE "["]
;print ["# =" HEX-BYTE "#"]
;halt

52. Hexadecimal value of a string

This is not really a "pattern" in that it is something that we do a lot. It is included here for completeness because it shows the application of the above function to produce the hexadecimal value of a byte in a printable form. Comments are in the code.

REBOL [
    Title: "Hex print"
    Purpose: {Take a string of characters and return it formatted
    in a way that if the result is printed one can have a hex representation
    of the string.}
]

;; [---------------------------------------------------------------------------]
;; [ This is a helper function for a project of printing a string, that could  ]
;; [ contain unprintable characters, in a hexadecimal format.                  ]
;; [ Input to the function is a string.  Output is a block.  The block         ]
;; [ contains strings of up to 60 characters, occurring in pairs.              ]
;; [ The first string of a pair is up to 30 characters of the input string,    ]
;; [ with each character followed by a space.  If the character is             ]
;; [ unprintable, a dot will be returned in its place.                         ]
;; [ The second string of a pair is a hexadecimal representation of the        ]
;; [ same 30 characters.                                                       ]
;; [ If you would print a pair of the returned strings one above the other,    ]
;; [ you would have a "hex dump" of the string.                                ]
;; [ The original goal of the project was to print strings of comments         ]
;; [ from a database text field, to search visually for unprintable junk.      ]
;; [---------------------------------------------------------------------------]

HEX-PRINT: func [
    STR
    /local BLK S1 S2 CNT
] [
    BLK: copy []
    S1: copy ""
    S2: copy ""
    CNT: 0
    foreach BYTE STR [
        either (BYTE < #"^(20)") or (BYTE > #"^(7E)") [
            either ((not-equal? (to-char BYTE) #"^(0D)")   ;; CR
            and (not-equal? (to-char BYTE) #"^(09)")       ;; HT
            and (not-equal? (to-char BYTE) #"^(0A)")) [     ;; LF   
                append S1 "? "
            ] [
                append S1 ". "
            ]
        ] [
            append S1 rejoin [BYTE " "]
        ]
        append S2 reverse copy/part reverse to-string to-hex to-integer to-binary BYTE 2
        CNT: CNT + 1
        if greater? CNT 30 [
            append BLK S1
            append BLK S2
            S1: copy ""
            S2: copy ""
            CNT: 0
        ]
    ]
    append BLK S1
    append BLK S2
    return BLK
]

;;Uncomment to test
;TESTDATA: {
;Abcdef
;123456
;!@#$%^
;}
;DUMP: HEX-PRINT TESTDATA
;foreach [PLAIN HEX] DUMP [
;    print PLAIN
;    print HEX
;]
;halt

53. ODBC submission module

This is another case of encapsulating functions into a black box and using the functions to make a program shorter and its operation clearer.

The module below allows one to make a file of ODBC connection strings for all the commonly-used databases at an installation, and then connect to one of them in a streamlined manner based on the database name. Comments in the code below explain.

REBOL [
    Title:  "General ODBC functions"
    Purpose: {Isolate ODBC connection strings for easy maintenance.
    Store them in a format such that they can be a Python module
    and still be used by a REBOL program.}
]

;; [---------------------------------------------------------------------------]
;; [ This is a generalized module for reading data from databases by ODBC.     ]
;; [ It seems that ODBC needs a "connection string" that identifies the        ]
;; [ server, the database, and a user ID and password.  This string is         ]
;; [ not specific to REBOL but applies to other languages, such as Python.     ]
;; [ It also seems that the Python syntax to define a variable with a value    ]
;; [ of a connection string can be put into a format that is parsable by       ]
;; [ REBOL.  Therefore, if one worked at an installation with several          ]
;; [ databases and wanted to streamline the ODBC access to them, one could     ]
;; [ gather all the connection strings for all the databases into a file,      ]
;; [ code them in a Python syntax, and use that file of connection strings     ]
;; [ in Python and REBOL programs.  There is an example of what those          ]
;; [ strings could be like:                                                    ]
;; [                                                                           ]
;; [ DB1="DRIVER={SQL Server};SERVER={SERVER1};DATABASE=DB1;UID=user1;PWD=pwd1"]
;; [ DB2="DRIVER={SQL Server};SERVER={SERVER2};DATABASE=DB2;UID=user2;PWD=pwd2"]
;; [ DB3="DRIVER={SQL Server};SERVER={SERVER3};DATABASE=DB3;UID=user3;PWD=pwd3"]
;; [ DB4="DRIVER={SQL Server};SERVER={SERVER4};DATABASE=DB4;UID=user4;PWD=pwd4"]
;; [ DB5="DRIVER={SQL Server};SERVER={SERVER5};DATABASE=DB5;UID=user5;PWD=pwd5"]
;; [                                                                           ]
;; [ The function below assume that such a file exists, reads it, and          ]
;; [ parses it into a "select" block of database names and connection          ]
;; [ strings.  There is a function to open a database given a name as          ]
;; [ defined in the file, and a function to submit SQL to that opened          ]
;; [ database. Rounding out the services is a function to close the            ]
;; [ database.                                                                 ]
;; [---------------------------------------------------------------------------]

;; -- Connection strings are stored in this file.
ODBC-CONNECTIONS-FILE: %/SERVERNAME/PYTHON/PYTHON_MODULES/ODBCconnectionstrings.py
ODBC-CONNECTIONS: read/lines ODBC-CONNECTIONS-FILE

;; -- Parse each line on the first "equal" sign, dividing each line into two
;; -- parts.  Append the two parts to the accumulation of connection names
;; -- and strings.  
ODBC-CONNECTIONLIST: copy []
foreach ODBC-LINE ODBC-CONNECTIONS [
    ODBC-NME: copy ""
    ODBC-STR: copy ""
    parse/all ODBC-LINE [
        copy ODBC-NME to "="
        skip
        copy ODBC-STR to end
    ]
    append ODBC-CONNECTIONLIST ODBC-NME
    append ODBC-CONNECTIONLIST trim/with ODBC-STR {"}
]

;; -- Given a connection name, get the connection string and open 
;; -- an ODBC connection.
ODBC-OPEN: func [
    ODBC-CONNECTIONNAME
    /local ODBC-CONNECTSTRING
] [
    ODBC-CONNECTIONSTRING: select ODBC-CONNECTIONLIST ODBC-CONNECTIONNAME
    ODBC-CON: open [
        scheme: 'odbc
        target: ODBC-CONNECTIONSTRING
    ]
    ODBC-CMD: first ODBC-CON
]

;; -- Submit an SQL script and return the result set.
ODBC-EXECUTE: func [
    ODBC-SQL
] [
    insert ODBC-CMD ODBC-SQL
    return copy ODBC-CMD
]

;; -- Close the ODBC connection.
ODBC-CLOSE: does [
    close ODBC-CMD
]

;; -- Test the parsing
;foreach [NAME CONSTRING] ODBC-CONNECTIONLIST [
;    print [mold NAME ":" mold CONSTRING]
;]
;halt

54. ODBC example

Given the above module to encapsulate ODBC operations, here is an example of how easy it can be to get data from an SQL Server database.

Shown below is a generic code snippet. It is assumed that the SQL is in a file in a folder of SQL queries. The SQL could be hard-coded into the program, but if we put the SQL into a file by itself, then we could run the SQL manually if debugging were necessary.

If you are runnint this query just once, you don't have to clear RESULTSET first, so the above module makes it possible to query a database in three lines of code.

Remember that the result of an ODBC query is the result set in a block of blocks, where each sub-block is a row of the result set.

RESULTSET: copy []
ODBC-OPEN "DB1"
RESULTSET: ODBC-EXECUTE read %sql/SQLcommand.sql
ODBC-CLOSE

55. SQL "as" column headings

This script is part of a process of streamlining the processing of an SQL query. It shows what can be done with a little discipline in the coding of a query.

The dccumentation is in the comments, but basically, the script will parse a carefully-written SQL query and locate all the selected column names, and return them in a block.

The purpose of this script might seem a bit obscure, but things will become clear farther down in this documentation.

REBOL [
    Title: "SQL As columns"
    Purpose: {Given a carefully-formatted SQL query where all selected
    columns have the "As" feature specified, extract those column names
    and return them in a block.}
]

;; [---------------------------------------------------------------------------]
;; [ It is possible to do useful things with source code if is is written      ]
;; [ with some discipline.  In this case if one has an SQL query and every     ]
;; [ column in the "select" statement has the "As" feature specified to        ]
;; [ name the column, then it should be possible to extract the column         ]
;; [ names from the SQL.  Any string after the word "As" is a column name,     ]
;; [ and the word "From" indicates the end of the column names.                ]
;; [ This function will make that scan and return the column names as          ]
;; [ a block of strings.  This function was written as part of a larger        ]
;; [ project to automate the running of SQL queries.                           ]
;; [                                                                           ]
;; [ This "markup" of the SQL must follow a particular convention.             ]
;; [ The "As" specification for a column must use the word "As" in this        ]
;; [ manner, that is, upper-case A and lower-case s.  This will distinguish    ]
;; [ the word from "AS" and "as" and let you use "AS" or "as" in the           ]
;; [ query according to your case preferences.  Similarly, the word "From"     ]
;; [ that indicates the first table to select from, must have the upper-case   ]
;; { F and the r-o-m in lower case.  This will distinguish it from a "FROM"    ]
;; [ or "from" that might be used in a sub-query.  This case-insensitivity     ]
;; [ works in SQL Server; I don't know if it works elsewhere.  We are able     ]
;; [ to make this work in REBOL because of the strict-equal? function.         ]
;; [---------------------------------------------------------------------------]

SQL-AS-COLUMNS: func [
    SQL-CMD
    /local COLNAMES WORDS LGH POS TESTWORD
] [
    WORDS: parse SQL-CMD none
    LGH: length? WORDS
    POS: 1
    COLNAMES: copy []
    while [POS < LGH] [
        if strict-equal? "From" pick WORDS POS [
            break
        ]
        either strict-equal? "As" pick WORDS POS [
            POS: POS + 1
            TESTWORD: copy trim/with pick WORDS POS "'()"
            append COLNAMES TESTWORD                       
            POS: POS + 1
        ] [
            POS: POS + 1
        ]
    ]
    return COLNAMES
]

;;Uncomment to test
;SQL-CMD: {
;select 
;cast(COLUMN1 as int) As COLUMN1
;,COLUMN2 As COLUMN2 
;,COLUMN3 As 'COLUMN3'
;,COLUMN4 As 'COLUMN4'
;,(select ITEM1 from TBL1 as T1) As ITEM  
;From TABLE1 as T1
;inner join TABLE2 AS T2
;on T1.COLUMN1 = T2.COLUMN1
;order by COLUMN1
;}
;probe SQL-AS-COLUMNS SQL-CMD
;halt

56. CSV file from a block of blocks plus headings

This is another encapsulation of something that is done a lot. It is a function that takes a file name, a block of heading strings, and a block of data blocks like one might get from an SQL query, and creates a CSV file out of them.

The details of use will be shown just a bit farther down in this document.

REBOL [
    Title: "CSV file from a block"
    Purpose: {Create a CSV file from a block of headings and a block of data.}
]

;; [---------------------------------------------------------------------------]
;; [ This is a piece of a larger problem.                                      ]
;; [ The purpose is to create a CSV file after we have assembled data into     ]
;; [ a specific form.  That form is a block of column headings plus a block    ]
;; [ of sub-blocks where each sub-block is going to be a line in the CSV file. ]
;; [ So to call the function, you must specify a file name for the output      ]
;; [ file, plus a block of heading strings (or words because we will convert   ]
;; [ them to strings to be sure), plus a block of sub-blocks of data.          ]
;; [ For example,                                                              ]
;; [ CSV-FROM-BLOCK %csvfile.csv ["COL1" "COL2" COL3"] [                       ]
;; [     ["A" "B" "C"]                                                         ]
;; [     ["D" "E" "F"]                                                         ]
;; [     ["G" "H" "I"]                                                         ]
;; ] ]                                                                         ]
;; [ The result would be a file called csvfile.csv containing:                 ]
;; [ COL1,COL2,COL3                                                            ]
;; [ A,B,C                                                                     ]
;; [ D,E,F                                                                     ]
;; [ G,H,I                                                                     ]
;; [ Note that you must provide clean data.  The number of heading items       ]
;; [ must match the number of data items in each data sub-block.               ]
;; [---------------------------------------------------------------------------]

CSV-FROM-BLOCK: func [
    FILEID
    HEADERBLOCK
    DATABLOCK
    /local DATAFILE COLS CNT 
] [
    DATAFILE: copy ""
    COLS: length? HEADERBLOCK
    CNT: 0
    foreach HDR HEADERBLOCK [
        CNT: CNT + 1
        append DATAFILE HDR
        if lesser? CNT COLS [
            append DATAFILE ","
        ]
    ]
    append DATAFILE newline
    foreach BLK DATABLOCK [
        CNT: 0
        foreach ITEM BLK [
            CNT: CNT + 1
            append DATAFILE ITEM
            if lesser? CNT COLS [
                append DATAFILE ","
            ]
        ]
        append DATAFILE newline
    ]
    write FILEID DATAFILE
]

;;Uncomment to test
;CSV-FROM-BLOCK %csvfile.csv ["COL1" "COL2" "COL3"] [
;    ["A" "B" "C"] 
;    ["D" "E" "F"] 
;    ["G" "H" "I"]
;]  
;halt

57. Parse structured SQL comments

This is another packaging of a useful thing that can be done with an SQL query if the query is written with a bit of discipline. Documntation is in the comments, but basically, if an SQL query in a file has a structured comment block at the beginning, those comments can be coded to contain useful information.

REBOL [
    Title: "SQL comments"
    Purpose: {Extract structured comments from an SQL script.}
]

;; [---------------------------------------------------------------------------]
;; [ This function is part of a larger project to smooth the running of SQL    ]
;; [ scripts.  It takes an SQL script with a comment block like this:          ]
;; [ /*                                                                        ]
;; [ DATABASE: "database-name"                                                 ]
;; [ AUTHOR: "J Smith"                                                         ]
;; [ DATEWRITTEN: 29-JUN-2017                                                  ]
;; [ KEYWORDS: ["keyword-1" "keyword-2"]                                       ]
;; [ COLUMNS: ["colname-1" "colname-2"]                                        ]
;; [ REMARKS: {Multi-line free-format description of the script.}              ]
;; [ */                                                                        ]
;; [ and returns a block containing the values of DATABASE, AUTHOR,            ]
;; [ DATEWRITTEN, KEYWORDS, COLUMNS, and REMARKS.                              ]
;; [ This comment block must be at the start of the script, where one          ]
;; [ normally would place it.                                                  ]
;; [ The way this is written will cause DATABASE, AUTHOR, DATEWRITTEN,         ]
;; [ KEYWORDS, COLUMNS, and REMARKS to be global words.                        ]
;; [ COLUMNS is an optional list of column name literals that could be used    ]
;; [ by other automated processes to identify the names of the colums          ]
;; [ returned by the SQL.                                                      ]
;; [---------------------------------------------------------------------------]

SQLCOMMENTS: func [
    SCRIPTCODE
    /local COMMENTBLOCK RETURNBLOCK
] [
    COMMENTBLOCK: copy ""
    RETURNBLOCK: none
    parse/case SCRIPTCODE [thru "/*" copy COMMENTBLOCK to "*/"]
    if greater? (length? COMMENTBLOCK) 0 [
        DATABASE: copy ""
        AUTHOR: copy ""
        DATEWRITTEN: none
        KEYWORDS: copy []
        COLUMNS: copy []
        REMARKS: copy ""
        do load COMMENTBLOCK
        RETURNBLOCK: copy []
        append RETURNBLOCK DATABASE
        append RETURNBLOCK AUTHOR
        append RETURNBLOCK DATEWRITTEN
        append/only RETURNBLOCK KEYWORDS
        append/only RETURNBLOCK COLUMNS
        append RETURNBLOCK REMARKS
    ]
    return RETURNBLOCK
]

;;Uncomment to test
;SQL-CMD: {
;/* 
;DATABASE: "database-name"  
;AUTHOR: "J Smith" 
;DATEWRITTEN: 29-JUN-2017 
;KEYWORDS: ["keyword-1" "keyword-2"] 
;COLUMNS: ["col-1" "col-2"]
;REMARKS: {Multi-line free-format description of the script.} 
;*/    
;select * from TABLENAME      
;}
;probe SQLCOMMENTS SQL-CMD 
;halt

58. SQL query to CSV file

With the above three modules, plus the ODBC module shown earlier, we have the pieces of a "pattern," that is, a way of doing things that is so smooth that we do it this way a lot.

The code below is part of a script that runs an SQL query and puts the results into a CSV file. Here is how it does it, using the four code modules we have shown.

Step zero: Code an SQL query according to the standards described above, where column names are specified with the "As" keyword and the first "From" keyword is coded with the upper-case "F."

Step one. Read the script into the program because we will use it several times.

Step two. Parse the comments to get the first comment item, which is the name of the database being queried.

Step three. Use the function shown above to parse out the column names from the SQL script and return the column names in a block.

Step four. Run the SQL query using the ODBC module shown above. Note that you will have had to write and store the appropriate connection string for your database, as explained in the ODBC module comments. This operation will return data in a block of blocks.

Step five. Using the function described previously, pass to it the name of a file, the block of column headings, and the block of blocks from the SQL query, and you will get a CSV file.

Here is a code snippet from a program that does that.

SQLFILE: %sql/LNDcheck.sql 

CSVFILE: %LNDcheck.csv

;; -- Load the SQL into memory because we will use it multiple times.
SQL-CMD: read SQLFILE

;; -- Find the database that this SQL refers to.
DBNAME: first SQLCOMMENTS SQL-CMD

;; -- Get the column names.
COLUMN-NAMES: SQL-AS-COLUMNS SQL-CMD

;; -- Run the SQL.
ODBC-OPEN DBNAME
SQL-RESULT: ODBC-EXECUTE SQL-CMD
ODBC-CLOSE

;; -- Make the final CSV file.
CSV-FROM-BLOCK CSVFILE COLUMN-NAMES SQL-RESULT

;; -- And that should be it.
alert "Done."

59. Wait for a file

Here is an idea for a function to be used in a multi-language job stream, where a REBOL program might execute some other program, and the other program would indicate its completion by creating a file. We would need a way to wait for the file and not proceed until it came into existence, or give up after an appropriate period of time. Here is a function that does that.

REBOL [
    Title: "Wait for a file to exist"
    Purpose: {A function that can be called to loop until a
    file of a given names comes into existence.  Can be used
    for coordinating several programs running as a job.}
]

;; [---------------------------------------------------------------------------]
;; [ This module provides a function that will loop, and in every pass it      ]
;; [ will check for the existence of a file, the name of which was passed      ]
;; [ as an argument.  When the file comes into existence, the function         ]
;; [ will exit with a value of true.  If a certain amount of time passess      ]
;; [ and the file has not appeared, it will pop up an alert box to ask         ]
;; [ if it should continue waiting.  If the response is yes, it will begin     ]
;; [ the waiting process again.  If the response is no, it will exit with      ]
;; [ a return value of false.  The "certain amount of time" is hard-coded      ]
;; [ because a time-out hardly ever will be an issue.  If you want to          ]
;; [ change the time-out, you could just change the value in the code.         ]
;; [---------------------------------------------------------------------------]

WAIT-FOR-FILE: func [
    FILENAME
    /local TIMEOUT TIMER INTERVAL KEEPWAITING 
] [
    TIMEOUT: 00:00:10
    TIMER: 00:00:00
    INTERVAL: 00:00:01
    KEEPWAITING: false
    forever [
        either exists? FILENAME [
            return true
        ] [
            TIMER: TIMER + INTERVAL 
            wait INTERVAL
            if TIMER > TIMEOUT [
                KEEPWAITING: alert [
                    rejoin ["File " FILENAME " has not appeared"]
                    "Wait more"
                    "Give up"
                ]
                either KEEPWAITING [
                    TIMER: 00:00:00
                ] [
                    return false
                ]
            ]
        ]
    ]
]

;; Uncomment to test; create your own file called exists.txt. 
;either WAIT-FOR-FILE %exists.txt [
;    print "File is there"
;] [
;    print "File is not there"
;]
;halt

60. Launch Windows File Explorer

The REBOL VID is very useful for little menu programs, and a common use of little menu programs is to open file explorer windows. Here is how to do that (works on Windows 10).

REBOL [
    Title: "Testing shell"
    Purpose: {Launching File Explorer to a directory.}
]

call {%windir%\explorer.exe "\\servername\vol1\REBOL\"}

print "Done."
halt

61. Recursive file and folder lists

If you use REBOL a lot for little file maintenance tasks, then a common operation will be to find all the files or directories in a given directory. The functions in this sample, borrowed from a now-forgotten location, accomplish that.

REBOL [
    Title: "Recursive folder and file lists"
    Purpose: {Create a block of all the file names in a specified
    directory, recursively into sub-directories.  Do a similar
    thing for all folders in a specified directory.}
]

;; [---------------------------------------------------------------------------]
;; [ I tried to make this into a function that would return a block of         ]
;; [ file or folder names, but could not.  To make it work, I had to put       ]
;; [ the final results into words not local to the functions.                  ]
;; [ This probably is a fault of my lack of understanding of REBOL.            ]
;; [ If you call this more than once in a program you will have to clear       ]
;; [ out the lists or you will get things doubled-up.                          ]
;; [---------------------------------------------------------------------------]

RECURSIVE-FILE-LIST: []
RECURSIVE-FOLDER-LIST: []

FIND-FILES-RECURSE: func [
    FOLDER
] [
    foreach FILE read FOLDER [
        either find FILE "/" [
            FIND-FILES-RECURSE FOLDER/:FILE 
        ][
            append RECURSIVE-FILE-LIST FOLDER/:FILE
        ]
    ]
]

FIND-FOLDERS-RECURSE: func [
    FOLDER
] [
    foreach FILE read FOLDER [
        if find FILE "/" [
            append RECURSIVE-FOLDER-LIST FOLDER/:FILE
            FIND-FOLDERS-RECURSE FOLDER/:FILE 
        ]
    ]
]

;;Uncomment to test
;RECURSIVE-FILE-LIST: copy []
;RECURSIVE-FOLDER-LIST: copy []
;either FOLDER-NAME: request-dir [
;    FIND-FILES-RECURSE FOLDER-NAME
;    FIND-FOLDERS-RECURSE FOLDER-NAME
;    print "------------------- files:"
;    foreach ITEM RECURSIVE-FILE-LIST [print ITEM]
;    print "------------------- folders:"
;    foreach ITEM RECURSIVE-FOLDER-LIST [print ITEM]
;] [
;    print "No folder selected"
;]
;halt

62. Check for safe file name

A common maintenance task is to do things with file names, and people seem to love to put any characters they want into file names regardless of what effects that might have. The function below is used to check a file name and see if it has only letters, numbers, and approved special characters. It is just a true/false check, it does not do anything with a file name that might be a problem.

REBOL [
    Title: "Safe file name"
    Purpose: {Check a file name string for characters that might cause
    problems in certain situation.}
]

;; [---------------------------------------------------------------------------]
;; [ This is a function written for one purpose, to check a file name for      ]
;; [ characters that might cause problems with certain automated procedures.   ]
;; [ A file name that generally will NOT cause problems is one that contains   ]
;; [ only letters, numbers, hyphens, and underscores.  Not that other          ]
;; [ characters WILL cause problems, but they could, so this function just     ]
;; [ checks the file name to see if it MIGHT be a problem.                     ]
;; [===========================================================================]

SAFE-FILENAME: context [
    UPPER: charset [#"A" - #"Z"] 
    LOWER: charset [#"a" - #"z"] 
    DIGIT: charset [#"0" - #"9"]
    SPECIAL: charset "-_."
    OK-FILENAME: [some [UPPER | LOWER | DIGIT | SPECIAL]]
    CHECK: func [
        FILE-ID
    ] [
        return parse/all to-string FILE-ID OK-FILENAME
    ]
]

;;Uncomment to test
;TESTID: %TESTFILE.TXT
;print [TESTID ":" SAFE-FILENAME/CHECK TESTID]
;TESTID: "TEST FILE.TXT"
;print [TESTID ":" SAFE-FILENAME/CHECK TESTID]
;TESTID: to-local-file "TEST FILE (1).TXT"
;print [TESTID ":" SAFE-FILENAME/CHECK TESTID]
;halt

63. Space or zero fill

Formatting data for reporting often involves lining things up in columns. That means that things have to be the same size. Here are functions that padd a string on the right with spaces, or on the left with zeros.

REBOL [
    Title: "Space-fill and zero-fill functions"
    Purpose: {Provide two useful function, in as little
    code as possible, one of which pads a string on the
    right with trailing spaces out to a specified length,
    and the other of which pads a string with leading zeros
    up to a given length.}
]

SPACEFILL: func [
    "Left justify a string, pad with spaces to specified length"
    INPUT-STRING 
    FINAL-LENGTH
] [
    head insert/dup tail copy/part trim INPUT-STRING FINAL-LENGTH #" " 
        max 0 FINAL-LENGTH - length? INPUT-STRING
]

ZEROFILL: func [
    "Add zeros to the front of a string up to a given length"
    INPUT-STRING
    FINAL-LENGTH
] [
    head insert/dup INPUT-STRING #"0" max 0 FINAL-LENGTH - length? INPUT-STRING
]

;;Uncomment to test
;print rejoin ["'" SPACEFILL "  TEST STRING   " 30 "'"]
;print rejoin ["'" SPACEFILL "  TEST STRING THAT IS LONGER THAN 30  " 30 "'"]
;print rejoin ["'" ZEROFILL "123" 6 "'"] 
;print rejoin ["'" ZEROFILL "123456" 6 "'"] 
;halt

64. VID button "click"

A fun feature we tried was to produce a clicking sound when a VID button was clicked. Details in the comments of the following script.

REBOL [
    Title: "Click"
]

;; [---------------------------------------------------------------------------]
;; [ This is a function that will play a particular canned sound.              ]
;; [ It original use was to play a clicking sound when a button was clicked.   ]
;; [ The canned sound was produced on a GNU/Linux computer with a sound        ]
;; [ recording program that would save a sound as a "wav" file.                ]
;; [ The recording procdedure was to place a microphone right next to a        ]
;; [ key on a spring-operated IBM keyboard, then, as fast as possible,         ]
;; [ start recording, press the key, and quit recording.                       ]
;; [ The way to use this procedure is to code the following as part of the     ]
;; [ code for a button or whatever you want to produce a sound:                ]
;; [     attempt [CLICK]                                                       ]
;; [ The use of "attempt" will allow the program to continue running if        ]
;; [ no sound hardware is present and the sound can not play.                  ]
;; [---------------------------------------------------------------------------]

CLICK-DATA:
64#{
UklGRmQFAQBXQVZFZm10IBAAAAABAAIARKwAABCxAgAEABAAZGF0YUAFAQDhB0AG
WQnIBzoMrAppCg0J3w2cDLYNDgw8BMoCXAiYBtYSURGiCRcIOAC6/owNQAy2EkER
HQbEBEkF4AMuDswMIQ2cCy0H2gVlBdoD2wZMBRcLzgkhDMUKbAUsBA0DqgG2DQsM
QRDMDsQBngCLAVsAEhCjDvQKsgmn/XH87QWLBDQP9Q18BzMGTAPwAcgIUAe4CTAI
+gZyBYUFBgQjBKsCXAUWBFkJ2AebBjYFygFSADYIiAapDRQMfwXtA5gF0QNkELYO
2ApcCWIC8wCmDdUL7xAeDwYEpAKIB/EFoBT2EnANBwyeAxYCTQycCsMTVxIuDaUL
hQbhBPEIlQe5DTEMbQ7YDKgIEweYBQ0ETQ6/DCUTcREaBpgEWAEcAHES6RDZFNwT
WAL2ACIBuv9eEgsR6RJhEZgGfAU9BzkGVw7oDLkORw2yCzcKPQkKCPEJlQiNDxsO
vA5wDYUEIwOSBFIDYRHlD04QvA45BL4C3gdyBrkRLhCADC0LIwXnA9sHMwYkC6UJ
QwvICQQJggfdBIgD7geLBj4P/g3hCo8JwQIpAfQIiAc+D/4NfwYTBYsBTwCWCkYJ
CA1pC3IFCgTtBVkEUwu7CbsKYAlTCd4HhQgzB18G+gSfCBcHNwpNCUYF8wNZBf0D
xQySCxEKbwinAVUA1AdyBrwNJwwpBasDqwIvAf4LrArOCD0HQv/D/asGOQVED8IN
UAe0BXIC2gA9CtsI2AxdC7UHaQY5BuoE1AdiBtUJYwifChQJuwVyBPQEkQP7DcUM
CA6vDF8C8wCCBC8DRxHPDxcNqQu0AQ8AjAcNBpAPNA7qB1YGXwMQApwK9AjICz0K
QwbtBBoGvgS4CH8HiQkHCI8IWQd1BBADmAJbAf0HpQYRCZUHLALqADAFxwNKDdIL
0Qc2BrcBYgDICGMHNwvuCXIDFgKVAykC0Qh1B5IGSQU5Bg0FmQlGCH8FJgQGBPAC
2AuDCnMJPQgcAL3+TwUgBO4MfAuVA0ICHP/J/RoKnwjLClwJ1AE4AEIE5wJvCSAI
QwWoA2IE3QJvBwcG3QO+AgMEpALxCW8IzgYwBboBWACcCUAInAsaCkUBMgC6AzwC
wg5gDWYIywZY/gL9Rgb0BDcLywnBAkwB0AJ+Ac4JRghyBiwFkQL8ANQEIAMDBb4D
mwUGBCMGzgTtAJf/EgDA/owJxQfuCGwHJf7f/FgD4wGzDkENqwQ8A6b7O/pgCRoI
RA4eDeb+h/2X/hL9XQwXC10K+gjjAH7/sQRcAw4L2wlDCS0IygRrA1ICCQH9BeEE
+Au4CssGggXj/cb8PAbnBPIQgw/HBWUE1vtq+o8IfAdhEBEPNgIpAQz98vsHCPQG
7gq4CZsEbwMAAgkBCgTQAn8HVgY9CeoHugJSAcD+yf1cCEYHpQsdCvb+cf3y/K37
rAs3CnMM+woMAL3+VQEDAEkJ5AdMBxAGkgQTA5UENgOuA4ECZgYgBW8HKQYZAI7+
CQDs/lMLGgodCmYIwP22/AMCAAHVDHAL/QXHBJ3+tv2LBjwFdgj3BqQBTwCSBE8D
jAkgCJgFNgSFBUkEsgh1B0YEAAN1A08CpQqGCdsHiAYAAKT+EAa0BDQLyAmhApcB
mAOFAqYMZguhBWgEpP5L/egJsghTDBEL8/6X/QYB0/8nDd4LIweYBTL97/tPBe0D
WgwUC0kF2gMMAMr+aAQ5AyMI/Qb0BpgFEwLgACwAwP6MB1MGAQzbCuoBugCH/kX9
QAw0C8kOiQ1e/wb+7/3m/DQLMArYCXkIJf4i/Q8B1v8KCtQI6gfUBogCJgHBAjIB
TAXNA7gGVgWxBDkD1v6k/YsB7f9pCUMIHQXUA+D9p/wTBfcDBArRCBYCqgCE/1j+
9wWhBHUGxwS6ApcB6gLUAdACngFSA0ICYgYpBccEaANIAT8ARgUQBNEHuwZFARkA
JQAc/9EHngY5BvQEIv78/N0B4wCyCJgH7QTHA18BSwD6BOcDrgSOA5sCjgFcBFID
bwQ2A/ACxAF8BV8EPwUTBOYAwP8pBLoC6wlvCDMEzQIl/+/9uwdTBlkKzgjdAHv/
ngFCAAoK8QihBYIEe/9R/jwFygOcCEYHCgR4AuABhAADBIUCeQbqBFkGGQVYARYA
/P66/QMF7QNcB9QFGf90/Xf+L/3OCFYHiwZvBQv7zPkM/9D9jwlJCKsCLAF9+jf5
kQImAasHPAZuAfP/OP/j/Y4EOQMjBtQEAAOXAYQAA/+0AXsAdQXtA08EAwNr/+z9
LADN/rEGeAXhBagEfv4Y/b0BEgAzCOoGcgI/ASX9FfzHA2gC8QaoBRYB1v8///b9
YgI1ARAEygLRBJ4DiwMjAp4AP/8pA70BHQa7BHsCQgGk/17+kgQsA5IGJgXEAXsA
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
GvET8HD3svYS/lT9DP5h/WYHeQYDHPAaVRomGVIFewT+8uTx6OAx4MnmG+acCp8J
ZClXKHUbjhpSAUsApvYE9sUHEAeQ9+j2oTLEMURVO1Tmj3iPFfya+zVFH0QAgACA
OdjH1/9//3+P2dHYvOL+4cg2zjXQK/kqq9lP2euB64F4ALf/dXUNdHmwxa8AgACA
T+qa6QhotWbQKtwpAIAAgFQTbhL/f/9/GLmzuACAAIC/+dz4/3//f1NO20wAgACA
k4k+if9//39lL6QuAIAAgBgQkw//f/9/CN9N3gCAAIAKTd5L/3//f7qjkaMAgACA
zxE4Ef9//39rucm4AIAAgNdgq18ge7h5AIAAgACAAID/f/9//3//f4vYENgLns+d
/3//f8h7gnoAgACAAIAAgP9//3//f/9/ppsXmymnkab/f/9/QE/3TQCAAIAAgACA
HxZRFaJP0k5v2rvZH0HmP/9//38F9yr2AIAAgPgmAiYWSNpGFsCuv7PO5s3/f/9/
/3//f0gAUv8AgACAAIAAgJqPP4/rHi0eFlzwWvBc0FuGJX0kHrTFs02CQ4LHu3S7
D89xzmTjtuK3AgYC7LZUtuK0d7RsTEZLq2F8YA3vOe7hq1yrsekc6UMJXAiC8wHz
VjZGNVtbNVp297z2AIAAgOOPdY/IY39i5X6ifXCyRLIAgACAgbnfuL3++f0lQdw/
/3//fxck/iIAgACAAIAAgFoofSf/f/9//3//f83THNMQlG+T0ItRiwCAAIABhMKD
mVCWT/9//3//f/9//3//f/9//392I58iAIAAgACAAIAAgACA/3//f/9//3+6z+PO
AIAAgACAAIAAgACAAIAAgOc03jMu+3f6AIAAgACAAIAAgACAkb/9vv9//3//f/9/
pqFxoQCAAIAAgACA5fbY9f9//38hUxtSAIAAgACAAIAAgACAAIAAgP9//3//f/9/
SOqe6QCAAIAAgACAAIAAgACAAID/f/9//3//f596dnnPzTTNvgkKCT0iISEAgACA
AIAAgP9//38DdQ10/3//f/9//3//f/9/CFbDVACAAIBc25/aAIAAgACAAID/f/9/
/3//f/9//3//f/9//3//fwCAAIAAgACAAIAAgACAAIA39KXz/3//f/9//3//f/9/
AIAAgACAAIAAgACArJlmmf9//3//f/9//3//f7C4JbgAgACAXYdRhwCAAIDWiKmI
W44vjgCAAIAAgACA3XGKcAyMeosAgACAAIAAgMccDRwwYwFi/3//f9NakVlt+oP5
AIAAgACAAID/f/9//3//fz1RWlBkuu+5AIAAgACAAICy98/2sFlrWHMgqB/s4j7i
AIAAgACAAIAAgACAAIAAgE32j/UAgACAAIAAgPO6d7oAgACALQhsB+1g7V8AgACA
AIAAgACAAIDEwjPC/3//fxBix2AAgACACgRSA74FCgXmjpGOE9rO2ceSiJIAgACA
YMj1x/9//3//f/9/Wd2s3ACAAIDvjMOMLoj7hwKjo6L/f/9//3//f6f92fz/f/9/
ZOXi5ACAAIAlWBVXEWXCY3vU6tNLFDgTyyDFH1qxHrEPt522iXozeVx6Nnkv1ZfU
RsSuw+X5LvlfTGZL/3//f2XWrtUAgACA/3//f/9//38AgACAJPd99gOTq5LDoY2h
/3//f/9//393bXFs9wQjBIOFVIWsJsYl9hM7EwCAAIAAgACAeuHr4EnZqNgAgACA
AIAAgA2XbJaWtA60rgbRBbdZdFjUHfQcXqIJogCAAIAAgACAAIAAgACAAIAAgACA
Gaqeqf9//3+IYllhAIAAgACAAIBPSUZI/3//fwCAAIAAgACAAIAAgP9//3+i2TbZ
AIAAgP9//3//f/9/euQC5AR8mHqnWjJZAIAAgACAAICjPI07/3//f/9//381c/Zx
AIAAgACAAIAAgACA/3//f/9//38nrsutubJgsq+YOpgAgACAUdCaz8iraauKjBWM
AIAAgACAAIBZHIgb/3//f+5+qX17RHtDCyQeI5TSzdEAgACAAIAAgGwfgh5+kCmQ
AIAAgO+flp//f/9//3//f/9//39HfQd83LY7tgCAAID5AEUAFTyyOgCAAIAAgACA
rwq7Cf58c3v/f/9//3//fwCAAIAAgACAKoHxgLO1IbXsQcxA/3//f/9//3//f/9/
7vY99l3GAcbTFy8X0Ld0twCAAIBEEY0Qh21ObFZPIU7/f/9//3//f92PaI8AgACA
AIAAgACAAIDLT6VO/3//f/9//3//f/9/edvU2gCAAIAAgACAOe5v7awP4g4oPyE+
/3//f/9//3//f/9/0grLCQCAAIAAgACAAIAAgDoLbAr/f/9//3//fwJUo1IAgACA
AIAAgACAAIAAgACA0gzYC/9//39hQI0/wxWqFG0mWiXBYLRfdmcnZrs0yzPmLfks
JRJaEZ/xHfHpPfI8DRwZGwCAAIBl6afo/3+DfxxEFUNmew16p1iNVwCAAIAAgACA
juvm6nG3D7deF3QW/3//fw7ieuEAgACAEJLBkQCAAIA5kwaTqB/bHkBlF2T/f9h/
1F6nXaLEX8QAgACA3/xL/P9//3/HQ8BCij1qPP9//395NlM1KJ+Znm3fyN5vBmIF
7b+Cv8kSzxH/f/9//3//f2fNycwAgACAKLXotBDabNmolUmVrdAl0C48Hju4CfcI
YpBikFKQ4I8ZGwkanyCYH13M78v7ODQ4/3//f+g64jl6WHdX/3//f/9//3//f/9/
t0eURvwUHxSOF3gW1uQC5ACAAIDS3jre1mqmaXfR+dAAgACA2YydjACAAIAAgACA
YPS/8wIpCyjUCCoIaawHrACAAIAj7ULs/3//fyQ6FDm3qTypjLEtsXzGDsZHPTQ8
/3//f/9//38pXu1cU7HYsITRvdBpOXw4/3//f/9//3//f/9/nGNcYpOxOrG2tXS1
3elh6dXJo8lLFmQVAU70TKDlH+W55CXk7BXpFACAAIAAgACAqfgu+GH58vhMkT+R
SRm3GM1GzUXIrzevAIAAgAnnmuYeJEAj0dg52CITSBKgEgUSX6gWqPTuRu4dBl8F
rqxfrEwGwQUOf8x9I105XGsruipYE8YSbO8W71/Z19jLrFasRY3cjDHemd2E+236
0dgN2KVfmF7/f/9/JNx82wCAAICl2EzYd40/jYLACsD/f/9//3//f5XWLNY3ODM3
QTpgOUwYnhf/f/9//3//f/9//3//f/9/v2boZX0+tj3/f/9//3//f+QyEzJTTU1M
/3//f1l1A3QV6ITnq8RcxF/UytPm0ZHRH/6B/TRREVD/f/9/lUqhSW7q2ul6+sb5
3h8qH3Ierh2dQ6BC1iwGLG78W/sTG08aDa3UrACAAIBP1YHUrbsluwCAAIAAgACA
CoLugQCAAIAJ6G7n/3//f/9//3/SDPsLAqK5oQDtb+wbPhE9x8FywQCAAIBanjGe
/3//f/9//38zYU9g/3//f/9//3+chNKEAIAAgHqIbYhkQqdBIF4ZXf9//389OGY3
xNR11DkB2gCGmVCZAIAAgACAAIAePBE7/3//f/9//3//f/9//3//f/y3prcAgACA
AIAAgACAAIBHyuvJ0Fa8Vf9//3//f/9/J2cnZgCAAIAAgACAAIAAgACAAICuHgce
/3//f/9//3//f/9/2LJmsgCAAIAAgACAAIAAgNm5H7leLTss/3//f/9//39vMYsw
oq/urniUHZQAgACAAIAAgP9//3//f/9//3//f/9//3//f/9/PXr0eHbEDcQAgACA
AIAAgCqynLGl2yDb/3//f/9//3//f/9/HuOZ4gCAAIAAgACAYYhOiAH2c/VRPVQ8
ljjIN7k9gzwYQPg+8JKrks6tY63eNPozAIAAgOHFdsX/f/9/ZBF9EOsNUA3/f/9/
CUXpQxL8kPtPXxNeKt153FA5djhWY/dhl4tIi9k/0z7/f/9/L0Y1RRcJRghBP0s+
A9gw1wm+p72UK7YqDC8cLiMzJjL/f/9/thPvEiud5ZyiHNcbDNJC0QCAAID/f/9/
/3//f2nC4cH/f/9//3//f52LcYubYphh/3//fz/B18BZXz9e/3//f9GtbK32pKSk
fDOlMiRo22YNB0YG+f01/QdQ0k6SCeQIed/C3nkjvyLsQglCXVN2UqsHAAeMsT2x
wCvmKkdQNE9227va1kDGP/p1p3SfyTTJ8vsu+/9//3+kLXQs4cAzwHdXOFb/f/9/
ahKaEZBUo1P/f/9/jQ+mDhAGPAX/f/9/Avob+XEqwyn/f/9/On/1fTQ8/jqMZFZj
xfJD8mLWtNVK+HP36IeTh0bZi9j/f/9/rA0RDbnlNeX/f/9/TkFkQDWKw4lTCY8I
d0GaQD64JbjWJtwl/3//fzssOysm65fqB/RD8wCAAIAAgACAK+KQ4fTwPfApHWkc
10S3Q+oGSQZp87vycgR4A/70bfSIF7oWJyUnJM7z+/JdD2AOqkOKQuMY4xfoDxEP
CFHxT0A4IDe29+L22REoEYUcxxs27brsqfX+9O8QFRCp+cn4KvGf8HIHtQYF5zjm
8ZnhmTDcnNusxSTFAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACA
AIAAgACAAIAAgACAUaHvoGZ8BHv/f/9//3//f/9//38GFiUVR+Kc4Y8cqBtKUydS
/3//f/9//3//f/9//3//f2ZjUGIkDU0M6wvuCiojHiKGOM43Z2wba8V6RnmkLXEs
odIv0lWk06MAgACAAIAAgGeKQYr2puamvMlHyaoBIgEI9332Xd/l3mfOvM0Yy3rK
ENuu2iLpgeh588XyOiSfI+1GLEZANzo21TmvOLMQ6A9k0QLRh7oSul6hbqEaxILD
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
K+TA47biPuK840Hjs+JB4u7dkt2S2knaldtZ233h2ODW5XHlSOUo5eLhfeEu4Zzg
BuiN593tTO397oXu0e+i76XvFu9c8f3whvgI+J4BDAGlBwoHfwb6BaEDsQK7BA0E
3gtjCyIUhxMsFsoVwxMbExITmhJrFXcUnhgWGHId/RxNINEf2x5GHq4cxxtpHHsb
bx3UHIUfAR/RHvodyhgpGI0RBREFD3oOsBAVEAEMgwvzAzwDbgDT//X7h/sE8ozx
5uhF6D7mzOXp5H3kAd6v3avXSdfK10/Xu9iV2NfTP9NUzuzND9Gz0IzaGto04P7f
Kt/C3tnhTeEA7JjrNPaZ9Qv7ZPrD/Sv94wIvAhcINgeJDI8LkRSqE2MemB3CIN4f
bBu7GrEYCRiJH9sezyj1J1cnrCbnHTkdtxf5Fs0VIhUSFV4UsBT5E9YSFRIHDHAL
sQHmAH377Pqt/DL8tvvA+rz1F/Vv8bjwEO1F7A/pRejK517n/OV65SThkOBm3Srd
YNzC2+vdfN3V3kfeUNyr287aKtpZ3RrdHuJn4RjliuQ75cPkw+V35f/ouuie7Bzs
QPK48Tf5iviQ+Pj3DfOJ8mP1r/QD/zj+5AZWBqgK9An4ClkKJAyiC4APoA44E3oS
ABlVGOocIxyuGeoYQhSjE4QTAhNxFdYUqhUVFRIVsxQSE3cSrw0eDRcIaQeuBQ0F
5AVGBTYDygLG/A/8mffo9oP2+/VQ9Z/0afIg8hbuju3558Dng+Ix4t/fgN9N4Lzf
++Gj4d/ho+Fg3+veEdyi21Da7tlm3C3cJODb3yviyeGX5PjjreZ35nHo/Oeu62Xr
HfC471D0wvMV+3f6PwOUAiAHXAYAB0YG5wgUCHYOzw0yFqcVohzkG0Aezh30HI8c
9BtZG54cExwaHm8dJx/kHvQfbx8XHYIchBbsFeIQPhC8DhgO8gxaDIIJ7ghJBccE
lP///kr5s/hH9NLzrvFD8UzwCvDd7YXtvehL6IPiROKT4WrheuQ75KDjGONR4bzg
+N+v36LfR9+c4FTgsONq43Hp4+jk7Ijskew27ELtDe1W8vTxTvtL+yYEtwOCBg0G
CgahBW8JwgjPDkoOFRKEESUUkBNMGsQZQCCVH+sekh4WG1IaZRr9GSAcdRsmGoUZ
4BZFFmEUURMhEaYQZw3YDLIHBAeLAxwDsQJfAnH/9v40+vL52PYX9lb01fN28u7x
y/FZ8QTyVvGh7j/upOoy6jzrquoQ7Xjsp+tb65TpP+na6Evox+h76DXo0+cJ6qfp
A+577dfuXO7N61vrnulL6eDpi+km7d3ssvEB8Xb03vNw9Q71bfTx83zyI/Kv9FP0
ffsI+4EBAAGhA34DXAWoBE0JjAhjDAEMTQ2ADPIQ/w/WFjgWvhkQGX4a7RkzHWkc
wh+uHnYerh2rGsEZ8BdSF5oX4xbcFDgUqRDSD/4MXQxNCZIIRgWCBAkAh/9d+ZD4
kvIR8mzt5+wZ65vqeOq36cPncee54W3h/tx/3Fbev91N4evgs+Fq4YbhCOEY42Hi
1uZu5ojqAOqo7QPt3vJj8sz4OvhU+sb5l/vp+vABWwGJCvEJfRDiD9MRVBFeE9AS
ihXZFF4VuhQ4FbMUbhanFU4VkRSjEtYR2RAlEEoPYw5wCxcLkgauBRYFVQTkBUwF
DQQgA0L/uv56/SX9OP6U/Uv8tvtq+hL6Avpq+XD5v/iA99j2KvWZ9Gb1+/S292P3
C/em9u7xWfEj7b7s4OuB6wDteOwT7qTtu+6V7hrve+7B7XLtWe3a7CDwuO8H9Y/0
JPlz+A/9lPxFApsBLASoA1wDvgJ1AwkDVgbLBX8I8QdjB7sGQwaLBRcIXwc6Cq8J
PQuDCoYM1QsODawMUAusCg0JeQjYCUMJagyyC8wMUwx2DMULHg59DZYPDg92DOUL
FAmCCHkHxAaeBhoGuwb3Ba4E7QORAtoBxAAyACX6o/mv8zPzafTb8zH3n/Yk91f2
M/Pe8gDvm+677Vzt1+xl7E/r1+o87KrrT+6Y7Qruoe207Bbs5+x77F/tCe1l7ODr
lOwQ7KjwcvC29iH25vo7+of9//wyAY4AYgPXAvADQgP6B2wHoA65DewRKxFRE8YS
URWqFFgXqhbdGE8YUhjEFyIWmhUfFr0VqhYGFgYVWxSgET4RCA6JDSQKkgmYBiYG
IwWYBN0ClAKH/Tv9xvlR+Yr6C/pR+vz5JPfF9nn0GvSZ8zrzTfLO8UnuKe7X7Ivs
5PB/8Hb09PPR8T3x3e1Z7bvwJvBk+Pv3Pv7Z/XH+/P3s+oP6Ffm5+OL5SvkP/0j+
8QU8BcgGZgbjAWgBGP2g/Bv7cfqE/RL9AARVA8gHIAeFBPcDev13/Jr7RPukATUB
QAi7B2kJ8QgNBosFBgRvA+EFXwVJCNsHcwnbCK8LFwumDSQNRwt/Cs4HNgeoCBcI
rAr0CToKqAmSB+cG/QNJA/wAWwCR/+D+9v+B//D+fv6q+z77gPjv9zH2yPWW9CH0
afMw87LyIPL08XLxjPAX8K7tYu3E63Xrvu5Z7rLz+/Jz9MjzAfSZ86X0N/Tb9YP1
evkb+UIAh/+YBAoEbATKA28DsQJcBPcDIwdvBkMLogpHEKwPjRLDEc8Q7A9tDq8N
9Q5dDt8QKxCEEgISahG8EAEMZgszCIUHqAn+CPcJjAmuBRAFUgHdAKf/KP9k/gn+
0/yK/Hr8+fvM/CX8KPua+gv4lvev9Vf13vRp9Kb1N/WA9hf2Kvav9Uf1v/Rp9Pvz
bPP78lbzpfKv9Tr1vPcx96P3Mfdt+Av4evko+Wf4Bfhq+Oj3RfwY/LD/Mv+H/yj/
fv8f/x8BhwB+A/oCLQaVBXYIuAdWCMgHEQljCGANnwy/DwIPiQ62DQsMiQsECUYI
uAdAB0MKpQnPC2kLGgqyCVMHvgYdBagEQgOLAk8CjgGxBSkFZgfEBscBHAH8/EX8
Jf+n/mICDAKhAfAAMv/G/gn9h/yH+//6tvxL/C//xv5F/u/9RPv/+k756Pip+A74
AvmZ+L/5ZPmm+CT4bfXr9MvyhvJd88jyf/P78nD1OvUI+cn4evkL+ST3vPbJ91r3
SPvG+sb8evyH/Rz9ugBPAE8FygTRCBQI9AhpCGkHCgc3CcsIvA5RDsMSSBL/EYAR
eg/rDusOJA4YD6AOoxAxEP8SfRKsECEQaQvSCvEImAgwCK4HUweeBsgHLQc2BrsF
6gBiANn6evpN+Pj35fmm+dX4Ufgd8/vyefE98eL0ifT19sz2UPaW9Yzy7vEQ8fHw
Y/Ye9qD5d/ms9lP2hvbl9Zr7NfvG/pH+eP8y/zwB4wB4AAAAIv+n/s0CpAJyCC0I
uApDCmkK2wnkB38HiAQjBLsGIAYRDI8LBQ5wDa8KGgqrAz8D8P97//cDbwOyCk0K
1Qp2Ch0FfwQ8AtQBiAPnAuoDjgN/BscFbAkNCa4FQwW2/Ej8KPuz+kwC7QH3BnIG
TwS6Ayj///4S+636s/pa+p3/Xv+IBeEEywVPBen+aP5q9gj2vPQw9KD7avunAhkC
xAAyAKD6S/r1+Hf4XvoF+r37kPvc/S/9Mv7j/aD6CPrS+GT4gf0J/UkD2gL3A34D
WP/Z/vz7wPug/l7+rgQDBHwJ2whNDAEMcAzxC/EHUAeRA08DQAbOBS4N1Qx9ELYP
mQ0ODd4KDgrkCU0JQwmVCN4JQAmcCiEKRgioB3UEDQSbAyADdQMDA4gBKQGd/yL/
pP04/TH5qfgB83byfPIN8iH3+Pa2+VT5cPfy9nP0+PM98wHz3vOS8zr10vTi+Jz4
lPxh/Nn7nfv193337/eZ9+P+aP6SBCAEEwTRA54CEAIpBccESQjLB5wKLQqWDTcN
Jw3iDDcKtQkaCLsHdgr+CQUPag4YEHMPLQyfC28H9AZ/BtoFRgiyB+gKfwqpDDoM
JwqCCSkEugPXACIAwQFfAeEFdQWIBhMG9gCaAP/6w/rv+bD5YfwI/Bz+l/3v/WH9
Ff2n/Jr8Jfxx+wj7Tvrf+X36KPpB+536o/s1+9n7nfvG/Rz9VP32/Bv7qfqQ+xL7
yfwo/AX8hPsC/Mb7Yf3s/Nb9VP1b/fn8aP7m/WIB9gBlAR8Bw/5o/jj+8/0MAW4A
+gNMA4gGMwaoCBoIMwnICNEHTAf0Bk8GFwioBwQLhgq/DRsNqQ9HD+8PkA/yDWoN
FwulCp8I9wfbBmwGMwbaBdQGPAbxCF8I4Ql5CTAHogb2AnUCQgHTAEwB0wCEADUA
Iv+H/un9Z/13/dn8ufpe+k33+/bI9m32GPey9lr2C/YO97b2w/p9+of8G/z1+YD5
nPc398P6FfrT/3j/LACt/6r9KP1o/gz+tAImAtsGAwayCScJWQq1CUAHwQYjBKQD
7QWbBbILQAuQEO8PzA9tDxoKmQnqBZsF/QZ5BsIKzgnbCwsLvgcgB64BKQFoAOP/
xAMpA6gF/QSkAkwCrf0l/QX7sPpL/Kr7D/87/gMCdQGYAtQBd/se+4z1GvXV9mD2
d/nc+CT5hvj1+4f7l/0r/Wf8yfslALf/oQLgAWIBrQBlArQB6gBIAFj+3P2nAhYC
qAX0BOcEeATuBl8G6gViBTkBrQDnBG8EOQebBqsELARTCdgIUwrbCVgBmgCrBPoD
uAvICmMHuwZ/CtsJiQ6yDf0BPwEo/Wf8ngTKAzYCZQFfB3wG8hI4EtEJ7gj5/Wv9
fgHHANb8//uN/Az8uwo9CjAIjwed+zH7ZQL5AagF8ASw/Bv8HP2n/A/7sPoU9H/z
O/qz+Xv+2f0u+436HP+n/oD6G/o57sftYPLk8bb7W/vD+iv67/2t/Uj/8/6v9VD1
NPXI9Jf/S/8zBMQDGQSkA4sB/ABF/db8AwK6AawKYApUDswNihAuEHAOPg6rCEMI
IAnCCGoMQAwLDcwMihAhEPUQVxCiCxcLDgqiCbIKHQqlB18HeQfxBo8IAQgDBXUE
ngHwALEAAADd/07/tABrAGX/2f5k+vz52PZg9h30yPPY9UD1S/zf+6T/Cf+K+wX7
GvVt9AHzb/Ll90T3Z/3m/If8Jfw++QL5Mfn/+OL5sPlF/cD8Uwa+BTAIjwcs/3v+
V/ri+dP8O/wyAJH/WQeVBjEOTQ15DKULhQZ1Ba0A/P8J/ZD8AAFuADMJbAhzC68K
LQmVCKsFEAXXACwAO/97/k8AwP/HANr/Jf1b/Nz4NPgL+3f6PAahBRsQHg9tDVAM
1ANMA536Hvrl9IP0avqj+a4GywVQCXwIiwPgAqQAsP9O/rD93P0S/eoBUgGxAR8B
Pv6E/Rn+Pv3j/Tv9H/6d/RMBjgDK/lH+6Pcx9zf3gPb4+nH6d/3m/AACSAE/BJ4D
uv81/wz8oPu6/Gf8K/7Q/b3+Cf4fASIAtAEpAZ4BQgFvBcQE4QlJCXMK0QlsB5gG
8AP9AhMBQgB4AZoAFgUvBPEHPQf9B2wH3QQ8BM0B+QBMAVsA3f5I/g/7h/o4+4r6
hP0S/db8RfzW+tz5Qfhg93P0NPTO83bzAfdE9pb45ffl93P3Dvh69zH4nPf1+mr6
AAAv/2sA0/84/MD7tvgC+AL6O/n5/oH+dQX0BKgIvgeFBcoEJgHqAGgDtAKiBx0H
zggXCDAIhQeYBfcEjgEPAcEDIwN8CcUIAQpjCaUGOQbHADwA0/t0+8b+W/4DBWwE
1ARJBFIAwP9r/q39Xv/s/rEBIgGRAr0BBgFlAJT9DP0++sz5rfsu+8oBJgFpBssF
LQaoBY4D7QLW/3j/s/wY/JD8JfwpAG7/IwJoAcQBPwG3ABYAiv+6/vb/Mv/XAGsA
mgADAMEBPwEvAZEAlvr4+d71N/XJ+i76lAEZAV8BygD/+5D79feQ9y740vfZ+2H7
kQD5/64CXwLQAUUBnf01/ZP7BfvW/kv+OQS+A/oGlQb0BHgERQKhAWsDCQO+B2kH
Jwu1CuILFAsECYwI1ARGBJsE/QOVCNEHJApvCSoHkgb9A5UD6gB4ABkAdP9PA9cC
bAXnBEUC1wHp/Y39k/vv+kT7w/qw/RX9sP5V/or7Ffuv9zT3evfl9gX6O/l6/O/7
CPzM+9z5Svk++cz4cfsl+xz/0/4DApQBtwBFAAX9h/zv/Q/9FgBY/+MASwCuAwAD
KQaSBWUFmwSrBEIE8ASCBIgE8wMHBY4EmAX3BJsDLAObAwkDQgPHAkgA4/+eABkA
jgP9AgYCiAGg/mT+oP0r/RL7qfoh+qD5Yf75/X4B6gBb/8P+dPvf+oP49fdL+6n6
AAFPACwDfgJSAZEAe/8M/0X/Uf7jASYBTAZ4BeEFBwW9ATkBFf8+/n7+2f0cAX4A
ngX3BP0EdQQyAIH/7/w4/GH8nfv8/WH98wA4AD8Ah/8y/KP77Psx+0j+l/3p/xX/
O/9e/iv8wPsS+k75EvxB+9P/+f5uAKT/xAAJAGgA3f+O/rP9zf4r/nsCGQLdA2sD
AwM5AlUDjgKSBP0D1wRVBFwDxAJPAsEBBgJ1AVgDqwK0BRAFfAa4BRMDTAJU/ND7
mfc996D6NPpPAMf/vQH5ABj8o/v09G306/Ij8g75g/hI/63+O/2w/B73ifYH9Inz
yPZQ9or92fxlApsB9gFPAWv9yfzp+m36bv7Z/dQELAQ9CI8HPAbeBeAAWAAv/pH9
WAP2AqwMHgxND+sOiQggCBYBhADmAFsAZgbEBQ4LmQqGCQoJHQRvA7T/Vf/m/kv+
awEJAa4FLAXhBmYGHAGhALz6Ifp3+vz5Ff93/ogBHAHT/zX/tvsL+1T6/Pm9/j7+
UgTdA0MGEAaCAxADqv4C/hL+lP2IARwBlQMgA+cCgQIWAqQBugB1AKT/Tv+n/yL/
OADN/6EAmgAJAI7/qv0y/cD9Tv3m/4f/h/8D/xX+fv1Y/eP8mvwy/NP7gPvQ/U79
6gBVAP0CdQI2A8EC3f9u/3r8/PuU/Aj8kf8J/yAFlQQwCnYJxQgNCKED9gIZAoQB
2gRJBAoIZgdJCcsIZgfEBosE7QMpBXUEzgX9BJUFAAVPBuQFjgQKBE7+pP3c+yL7
lwAvADwEQgMcAlgBwP9Y/9z8W/x9+N/3Qfha92H8pvss/07+oP3W/K37yfqm++L6
DPyd+9/6HvpU+bn4OPu8+jX/pP6hASIBiAHmAFgAw/+RAMr/vQBLAIQApP9FAIH/
9gEJAcoDAwNfBAAEkgT3A6QEMwTXA2IDHAKeATIA1v9lAAYAXAOkAhkEfgPXAGsA
bv0Y/Wf8H/wo/dD8Ev+k/h8AtP9e/cn8Ufrc+ar7SPtb/br8p/0y/V7+Cf6K/Ev8
+/hn+Dv5rPiq/TL9vQD8/8oAHAC9/xL/Qv7D/RL+kf3//lX+ewHmAMcDzQI8AnEB
SwB7/ykBpAA/AngB4AE8AXEA8/8S/3f+SP/8/ub/bv9I/cn8D/yE++D/jv9YA8oC
+QCnAL38PvxO+p35Evu8+l7/5v4QA5gCIwOrAk8A5v8C/of9Cf1x/L3+Mv7gAj8C
BgR1Ax8BhADm/n7+S/8G/z8BrQCkA+cCDQRlA08A8P/j/Jr8fv4i/tQBYgHzASYB
2v8l/wn9yfx9+S759fg6+Bv8ivuz/Sj90/tR+5b5CPmT+O/3CPiT95b5K/ln+9P6
R/qp+fL3XfdK+A74qvwr/LQB+QDnAkwCOADT/63+Ev5h/wz/wQIJArUGMAb3CH8I
XwiyB2IFuwSxAwkDPAalBdgJJwnbCJUI1wYzBlwGuAV4BbcEugP2AkIEqANDBaEE
YgP6AlgB7QDXAF4A8wG3AW8D+gIJAlUBEv53/cn7S/vc+5D7yfte+wL8evsS/nf9
sP4Z/pr8s/up+hX6DPxb+0v+4/2w/yj/tAA/AKoAJQDt/zL/4P84/+oC7QGIBPcD
5wI/Al4A4P9S/3H+sP/A/t0BVQGRAykDqwJYAk8Aof8C/m79kf3c/Pb/SP/gAp4C
iAHXAPn8Qfw0+uX5ufsi++3/Qv8JApEBVQDz/0H97/wu/Nb7pP7m/YsCFgLOBKEE
8wNVA3gBOQE1ALf/WAHNAOcETAQqCLIHQwjRB1wEsQPt/6T/8wB+ANcFlQXnBoIG
IwKbAYH/bv/D/1v/Uf7N/Y396fyt/y//JQB7/5D7Evuj+Ff4OPrD+YT8Jfxh/s39
gf4C/kH9Bf13/O/76fum+/b8jfya/xX/RQK9AYUCFgI8AW4ApwA/AK4CYgKRAwAD
hQJFAiMEXAPHBQcFvgRMBIUEEATtBU8FqwU5BcQDMwPNAUwB4AA1ALcA8//d/0v/
Pv7A/XH8/Pv8+z77Nfu8+lr6GPoS+qb54vmN+Qv6oPmN+hX6evoY+hX60vk4+uz5
5vt3+4f9HP0P/cn8MvzQ+9n9bv0ZALD/PAGXAAwCaAG0AjIC4AJPAsoCRQKLAv0B
cgMNA3wF3QTRBDkEcgK0AS8BgQAJAkwBFgN+AkUDiALXAjYCewHQAPz+Yf50/uP9
1wAsAFICtAHa/1L/mvwF/Dv80PuQ/Pn7nfwS/Ob+dP4fAaQAzf9x/zj+nf0c/6f+
VQEGAU8D7QIDAoEBa/4J/lj/jv76AlUCcgTBA5EDzQIWAlIBiv8M/9b9HP2H/un9
KP+O/jj+S/3f/If8d/u5+ij6cPkC+236avv1+p36z/kY+Zn4CPg994P3G/dO+tn5
sP0v/cP9Jf0r/F77Ev2H/JT/9v4lAHv/ngAAAKECEwLUAk8CkQEMAXICzQEdBaEE
Mwd/BlkH5AaCB+4GOQeSBu4GfAYgB4IG2whACKIJFwmuBi0GpwIyAksA2v+h/yj/
EgCE//AASwCHACUA3f6w/sn8Z/wV+4r6l/sb+2v9vfzc/W79yfxh/Ev9s/zA/UH9
Jf7g/Tv/1v6B//b+8P5+/lH+0P3D/hX+twASACkDvgIsA44C0wCHAD8AwP/tAKcA
JgGaAEICqgGbAxAD4wFFAe/9SP3y/Gr8nf47/vz/W/8iAJf///6d/jL+uv0F/aD8
Nfy5+4H9Ff0c/sD9vfw7/Hf8/Psv/rb9kf9F/4sAPwB7APD/9v94/8cAHwBJApEB
kQMDAwAFtwTkBWkFfwQQBMECawIZAoQBmwPXAhYFlQQsBMQDLAOBAjYDtAI2AqEB
Yf/p/un+wP7Q/6T/lP4P/nf94/zJ/VH9KP7m/cP8ffxU+/L6+fuj+5D8IvxO/Aj8
1vyd/IT99vyE/fn8HP7N/XsA2v9+Ae0ASAAGAPb/fv+nASYBewMzA6gDAAPHAUwB
of8s/1v/4P4cAZQAxwMsA4sE0QN7AqQB5v5F/h/9XvyR/tz9oQDQ/7QA/P9S/7P+
oPzi+z76yfko+4f6SP6g/Z3+Ev5n+xL7nPjr96n4Qfjm+4D7Xv+K/nT/4/4M/X38
Avua+oD7yfpR/tb9ugEyATMDkQL5/z//PvxR+6f9/PwDAz8CkgXUBNQDIAPXADIA
WP7J/dD+KP4JAngBggTtA6sCPAJV//n+5vx3/Jr9Mv1uAK3/MgGeACX/h/7W/DX8
4vt3+2v9yfzm/0L/RQG0AOb/fv9e/Mz7avrW+Rv8nftu/7f+OQF7AGUAe//W/iX+
Pv3D/MD8DPzp/UH9Zf/z/uP/dP8s/93+O/6K/QL+VP2z/vP9Cf9+/of///7w/yL/
SP6H/cb8Mvyt/RL9Ev9+/lj+tv3m/JD88vuA+xX6dPlE+tn5//2z/dcAhAAf/4T+
mvsx+9b7W/vj/ij+VQCh/7EAGQCBAfkAxwEiAbcAAADwAGsA2gIDArQD7QKuAvYB
0wApAJoAAwC6AhkCcgTEA4IDqwLnAgwCHAORAsEB8wAvAFj/5gB1AOYBSAGhAOb/
+f8o/3UAvf/z/x//D/9O/rD+zf0+/of9OP50/dz8cfyg/CL8fv3f/HH9D/0C/Ff7
bft0+hv8h/ua/Ob7qvwr/K39Jf3g/zX/QgGhADwAl//5/kj+5v4y/vP+a/5VAND/
hQLzAVUC5gEPAI7/lP8J/3gA0P/dAO3/vQAvAL3/6f4V/of90P4i/tcAMgA1AdMA
HAFxAE8A0/8+/tn90/wF/Bn/Qv7QAQYBKQGtAH7/Bv9I/3T+xv0M/Xf82fvD/hz+
8wFFAUgBmgA4/63+L/+B/vn/O/+nAN3/JgG3APMBYgGqAeAA8ABPAEwBZQC0AvYB
cgPnAqEB6gBO/5H+9v50/pQAAABfAaEAYgG9AH4BtADW/xz/rf0r/Zf9K/0f/qr9
Ev53/VH9s/zG/E78qvzy+3T9yfwV/5r+FgB4/17/qv7j/mT+fv7G/eb+Nf5VAZEA
8wNlAxwDkQL8/2j/x/9S/4QB4wDqAGsAAAGUAK4CEwIyAacAMv7D/S//wP5lAYsA
GQF1AC//t/7y/If8//uX+wL8evuN/eb8sP4G/mv95vzy+lT6JPnP+FT6AvrD/Dv8
Z/0M/Xf8/Psy/Kb7uftB+5f7KPvA/R/98P+U/0j/vf4V/X38KP7T/c0BZQF1AwAD
wQI2Al8C8wEJA1sC6gMsA7QEAASIBaEESQSOA2UBpADZ/iv+8P5b/vYAaAD5ADgA
jv7N/WH9p/wS/of9Xv22/Nb7GPtb/Nz7l/3M/FT8wPuz+z77iv01/Vj/uv5V/rb9
7Px6/Mn8KPy6/Uj96f5o/tP/Nf8MAFj/cQDm/4gBBgHmAT8BjgDW/3v/w/5L/+z+
0P5R/pH/vf7QAH4AKQBu/3H91vz8+2r73Pso+z795vz//oH+Rf6g/S77z/p6+tL5
Ufy5+3T+7/1r/un9jfzy+wX7S/oi/HH7LP/D/jIBiwDmAVIBOQGLABn/Xv4M/6D+
4AJPAssFIAUTBI4DhwAlAND/Iv8WAboAEANSArQCGQKkAeoAGf+K/mr8JfwC/VT8
Jf+X/pQACQC3/kv+OPu5+v/5gPl3/Mz7Pv6U/SX9sPw4+8b66fqK+pD7Ivun/S/9
QgCw/24A1v+R/Sv9oPs1+2H95vz8AHsA5wJCAvkBYgEDALT/pP8y//MAYgDgAk8C
6gMWAxYCtAHW/3T/0/90/+MBawFJA5QC7QFSAfP+mv4S/br8w/xu/ND9h/1h//z+
Jf/W/or9+fxb/fn8ZP4J/qD+O/4r/tP94/5b/or/HP/g/zj/p/8f/1X/3f4G/3T+
KP+g/sP+Mv4c/3H+9v9o/1IAwP93/hz+yfwM/A/+O/0PAGX/tP9F/8P9cf10/Q/9
Uf72/Q//s/4i/9n+mv4J/of9Tv3W/J38Ff5+/b3/Rf97APP/FgCt/2j/A/8J/5f+
Nf/w/pcAMgAMAX4A8P97//b+W/5e/83+dQAcAE8BAAGxALEAaP8P/6r+ZP4J/9P+
NQCk/wkBsQBiAbcAHACn/1v/Ev/g/zL/4ABVALEASwBx/wz/rf5V/g//dP5O/7D+
KP8P/w//t/6g/jv+H/6K/QL9gfzs/GT8DP5h/SX+qv1I/b38zf1B/VX+8/16/Rj9
mvte+3H7Avvy/Kf8kf5C/or+bv5r/ub93P01/WT96fyX/UX9w/4+/pf/yv63/zL/
EgCU/27/L/90/93+9v+q/7EAUgBiAPb/Xv/j/gkAXv9iAQMBTwLwATIC0AGuATwB
yv8//3v+K/7m/oT+ngASAMAAaABiAO3/bv/2/sb9ZP3c/Dj8CPyN+1v89fte/dn8
vf4+/or+Bv4r/Q/9bvz8+7P8OPwf/sP9uv5o/gn+zf0f/af8Xv0V/fP+d/4sAcoA
oQFlATUApP8J/n79Bv5e/YsAHwA5AvkB+QFIAdD+Nf4f/Mb7s/w1/Dj/vf51AC8A
4P5b/qD7KPs7+tz53PyN/F4ASACkAEsA5v3D/WH79fpX+hX6HP16/DUBjgCLAscB
of8y/y78xvtx+8z6yf1R/UIBpwA8AfYANf+O/kX+2f2X/07/EAKeAe0DbwMcA7QC
kf/p/nr8VPwl/tz9jgEMAVsBMgEG/4T+Mv3//I38Ffxe/MP7cf04/cD+Iv5F/cn8
CPt9+vz6gPpI/fL8Iv/Z/nT+HP4f/dD8Iv2X/PP9oP2h/wb/aAD5/xkBhAChATUB
RQHjABkBlwAWAZoAHwG0AJEBMgH6AsQCTAPdAtABTAFiAPn/8/9o/9D/a/+U/1L/
//53/rD9Ff3m/Dj8UfzT+zj82fvG/Bj8qvzv+4D62fkL+H33WvnV+D79yfxY/rb9
TvzA+1H7ffpk+6P6oPsb+8D9OP3zAFIAlwAyAD79vfz/+337dP4v/iYB1wC6ARwB
vQAfACwAuv9VAM3/wABSAF8BzQAfAZcAa/8f/+b8ZPzW+5f7uv1U/Wv/0P7z/hz+
OP2d/GH82fvp/Az84/2g/VX/dP41/27+cf62/T7+Yf1+/53+LwCH/3gA0/8mAYcA
WwHXAAABUgBiAccAfgEfAbEBLwFrAQwBLAHtAG4B4wD5AW4BSAHQAAP/hP5b/tb9
LP+a/uD+WP7m/VT9a/0S/br8Z/xO+w/73PpO+rD7VPv8+5f77/qK+k77w/pF/Jf7
7/uK+2r71voF+2f6HvuQ+qr8Qfz5/r3+l////i//mv57/9n+0/9e/yIAsP8DAcQA
ZQHgADwAjv/N/27/rQAlAFUBxwDwAEgArf8//1j+Bv6a/Xr9wP5F/vb/fv8DAJ3/
Uf7N/d/7nfuw+1v73P2E/aT/LP+K/gb+oPwY/HT80/tU/b38lP4V/nsA4P8mAbEA
e//w/nr9GP2E/gL+ugBCAHsB/ADmAEUAhP8S/9n+Av5r/6f+RQGkAEwBlAB7//n+
w/4l/iL/WP4yAN3/ngEiAR8BqgBI/tD9evvi+s/6WvrM+4T72fw7/ND9cf3z/Y39
XvwI/E776fpu/O/7xv0+/ez9iv3A/tz90P5x/jL+sP3g/hz+AACK/+P/of8s/47+
2f47/vb+p/6t/1j/bgDm/5QA4P9o/xL/jf1b/WT89fvf/EH8dP8G/x8A4P8+/dz8
w/pU+lf7Bfua/T79Cf+g/uz+hP5x/Qz9UfsF+4D7Ivvj/Zf9jgAPADUB6gDN/07/
cf0c/RL90Pzt/9r/PwIsAnEBJgEv/8D+vf5e/ub/Uv9iAeYASQIMAiYBygCX/g/+
tv1r/Yr/LP+9ATIBOQKnAbD/L/+H+yj7R/rp+cz8dPxl/+n+kf/s/mH+Av4V/dD8
ZPvM+qP7Ffuw/gn+WwDj/0v+H/5B+8P6w/pO+u/93P3mAGUASwDN/+z8qvzc+p36
W/vc+lH9HP3Q/2j/qgAWAGv+2f2a+iv6VPr/+Xr9K/20/1L/D/+g/sD8SPzs+lT6
Avug+p39d/3s/rr+2f16/fL8h/wo/en86f53/uYAiwB1AvMBmwFFAaT/Zf/s/j7+
Bv+R/hkAvf+IAVsBZQLEAbcAOAAM/6D+LACH/2IBrQCRAOP/Vf/G/v/9mv1+/f/8
zf1B/bD+Mv4l/7r+rf0o/fn7VPt9+yj7G/yT+6P8D/w4/fb8D/7D/fn9s/1L/br8
KPyw+1T8+fu9/Vj9SP/Q/rD/Ff+a/ij+WP0r/Vv9mvyX/k7+AwDD/7T/Rf9r/QL9
AvuK+tP6evpY/f/8MgCX/5T/1v7m+4T7xvhz+H35Ifmq/GH8WP/z/jX/s/7m/BL8
0/pn+jX83/sl//n+WwDT/3H/4/4+/e/8mvwi/Ej+wP1YAQABMwOkAl8B/AAC/o39
SP3G/H4A9v+xA1gDqAMQAxYAp//M/Fv8k/tE+7r9O/01AK3/XgC9/wL+fv34+lT6
oPo0+jj9/Pwl/63+W/75/Zf8Ivz4+rP6jfso+5r9Qf2B/yL/nf8y/1j9H/3f+537
nf1I/RwBWADUAYQBcQAiAGj/D/9l/0L/6f+a/4sAVQDHAEIAKQCa/6D+Vf4l/sb9
OP7p/VH+lP01/ZT83Pt3+8D7RPt9/Az8lP0S/cn9Uf0P/cD8G/z8+w/86fu2/Wf9
kf5L/qD9WP0r/Oz73Pt9+6397PyU//z+GQCw/7r/LP+E/+D+Rf/G/kL/w/6h/yj/
hP9L/93+mv5o/u/9w/5r/nUA/P+HACIAs/5o/ij+l/17/lX+1v57/uD+gf6U/0j/
kf9o/8P9rf07/bP8ZP72/Wv/H//W/lX+HP6n/cb+W/4JAEj/LACE/7r/SP+U/yL/
PADW/xkBeADXACkAPwDQ/wAAp/8y/+n+0P6H/tD/DP8ZAKr/Qv+B/un9SP3J/Sv9
qv75/XT//P54//z+oP1U/Qj8nfsi/K37s/1F/VH+0/38/Lb8vPpt+jv6nflq/Aj8
h/5R/qf+Rf5k/Rj9BfyA+177D/t0/Cj8OP8D//n/rf+N/QL9jfsi+8P8gfzZ/rP+
t/9l/wAAgf+9/2j/yv5h/vD+jv7aAF4AAALHASYC9gHdAGIAW//g/sD/Tv/BAXUB
UgIDAvkAsQCO/y//wP6R/nT+Iv6t/kX+sP9I/1IAzf9u/5T+Qv4P/h/+//3//ar9
w/1r/UL+6f1Y/g/+h/0v/en8w/xh/Tj9jv4r/qH/Qv/z/6f/uv9l//P+mv6O/l7+
bv/p/jUADAAZACUAK/7//Y38Z/y6/ZT9pP9h/17/Ev8c/tb9K/wF/KD6VPpk+wj7
4P2n/Rz/4/41/Rz9Z/qH+pn5evn/+u/6Xv1B/VX+L/4Y/db80/t0+wX8+fuB/U79
Vf8v/+MAkQBiAAAA0/29/Yf9rf1VAAMALALEAVsBBgHa/63//P66/qD+e/6K/17/
LwGxAFgB+QDT/5H/7P63/pr/O/8J/wz/Qv4c/vL8rfzM+4T7+fud+739Tv23/jX+
sP16/SL8ufsb+9/63P1u/QkBvQAAAH7/KP3G/KT9Iv0AAHj/ngAiAGsAMgDEAGgA
DP97/qT9cf2d/xX/wQFFAXUBIgHG/jX+cfz/+1T9DP08AMD/iAEyAUX/s/5E+xj7
d/ku+Xr6JfoC/af8P/+n/uD9cf1q+jT6Lvkb+aD7VPuU/jL+e/8l/07+//3i+5P7
h/oL+qP8YfzAAE8APAEGAY7+O/7D/GH8Ff7D/fAAmgBJA9QCrgJPAvz+d/41/ND7
s/xX/E7/2f5CAb0AxABCAOP9Yf2E+yj7GPzZ+0X/yv4WAJ3/l/5b/uP8VPyQ/BX8
OP4J/h8AGQDzAMQAfv8c/2T+Ev5h/xX/sQBiABMCoQGbAi8CbgH5AOP/mv9C/x//
SP8D/14Avf/HAWIBtAFfAe3/dP/A/mH+sP4P/vz9iv1F/q391v8f/93/L//v/XH9
JfzQ+6D8//v5/Ir8ev3m/Gv++f2E/Rj9PvvZ+rb6V/rT/H38mv4f/s3+WP62/UX9
wPxq/HT9GP0l/6r+aADz/3T/+f6k/TX9ZPwY/Cj9mvwP/53+/ACUAOD/of/2/Kr8
S/z/+2f9S/0G/2H+h/8Z/1X+w/04/LP70/pq+rD8ivz5/27/5gCkAFX/yv75/IH8
8vyK/Kr/Gf9FAtQBPwLQAY4ALwAc/73+0/41/iwAgf+uAW4BngHQAN3+pP6d/UX9
Bv5k/Xf+Bv5I/8D+Nf+6/hL+s/1L/ZD8Xv3f/Gj+9v0l/pT9wPwu/DL80/th/fn8
WP4C/vb9l/1O/Rz9//yq/H79H/2t/ij+7f8//+AAPwAJALD/0/04/QX9s/y6/mj+
BgDa//b+WP5L/bb8a/3v/DX+yf0v/8r+vf8v/5r/0/4P/of9hPzv+0H9DP3w/rf+
Tv+k/pf8cfyt+kv6h/si+5f9Nf2O/kj+Tv7T/aD9mv38/Lb8Uf0c/af/bv+qAXEB
4ABCAGv+5v16/TX9Qv/p/scBMgF+AsQBawAsACL+sP0f/vP98P+X/ykBBgGnAXUB
eADg//n9h/1Y/fL8Nf4Z/gz/wP7G/nT+Rf7m/TL9p/xF/Nz7vf32/LD/Rf9PAM3/
hP4S/s39Pv3z/tn+HAC6/xkAof+w/0X/6f9u/zj/0P4c/pT9pP4l/iIAuv9FAA8A
l/8y//D/Xv8ZAHj/gf8M/5r/Gf9V//b+ZP4o/lH9//z8/Hf8ZP32/MD9sP2n/Uj9
mvxI/L37Lvtq+w/7nftB+0j8tvtO/bb87/2g/db9+fw1/cb8O/32/FH+tv23/kX+
4P5V/g//cf7z/oH+8/5V/tP/Vf9PAfMAPwHmABkAp//H/17/jgAWAAkBngBlAc0A
AAJ7AYEBAwGt/zL/e/4P/kj/s/6EAG4Avf9e/63+K/47/uz9kf4S/vz+gf5l///+
kf9L/3T+Cf5B/Z385vxL/Nn9lP2B/1L/AwCt/8D/Xv/s/m7+xv5Y/mj/Ff9xADUA
9gDdAAABxwCxAG4Arf+t/83/cf9IAOn/cQAZAA//4/6U/U79h/xO/IT88vvZ/EX8
W/3f/HH95vzy+5r7ZPvp+lv7Avvi+437V/zf+5f8FfwS/Zf8Rf3J/Pb8ZPzc/J38
KP66/eb+aP4v/+D+CQB7/x8Ap//p/4f/DADH/4gB8wC6ASkB2gBPANb/cf+3AFsA
qgEvASkB3QADAKr/pP9b/83/Uv9b/7r+4P5k/s3/Yf8cAKH/gf4Z/hz98vwZ/q39
vf5O/h/+sP3z/aD9e/4C/lX+yf0i/o39Ev9o/o4AEgBoAPD/nf9L/2j/5v4WAMr/
LwGhAPABNQHBASYBygBeAOz+sP5h/tn90P9r/wABeAB+AOP/Cf6q/cn8//vZ/JD8
vf1b/Xf91vzf/Ev8bvwb/Jr78vqN+wX7s/wu/CX9qvzs/Fv81vxX/L38EvzJ/DX8
sP3s/BX+W/3v/R/9uv4P/s3/Iv+9/2X/4/9+/+D/hP+K/iX+DP6d/cr/Rf/zAHgA
DwCk/9D/9v4vAJr/+f6n/rb9h/2E/gn+Tv/5/rP+Ev7Z/UX9Tv72/cP+S/5V/un9
Pv6N/Vv+5v2B/g/+Uv9x/pr/H/8lANr/ZQDH/27/3f7A/jj+Rf/g/s3/O/9L/6r+
jv8M/wMBtABbAd0ArQBVAB8Aiv+6/1j/gf7A/YT9GP2q/lj+DwCh/17/Ev+w/Sv9
evzp++n7Yftn/DX8Rf0P/fb91v13/i/+6f2z/Qj8qvs1+yX7l/0+/Vv+Cf6U/WT9
5v16/d3+Rf4P/rP9Bv6k/UX/3f4V/xz/Ff7Q/fn9qv1u/wn/nf9+/5r+lP7s/UH9
6fyz/Dj93PxI/tn9vf81/wkAtP9u///+ZP4G/kj+4P1+/zj/hwAAADwAmv+H/xX/
qv8Z/4f/Bv/N/0X/8wBoACIBugCt/1X/Uv84/+ABpAEZA80CDwHaAL3+ZP4C/mf9
dP4+/hIAuv91AfwACQGRAP/+fv5F/CX88vuN+3v+Jf6HABIAkf9O/3v+Bv41/uz9
8/5u/k7/wP7A/1v/L//G/rb9l/1k/eb8e/5I/mgAKQC3ACwApP6K/sn8h/z8/Hf8
P//2/qoBgQHQAIQAuv1h/WH8w/vf+6P7Iv3A/N3+Uf72/37/Vf7s/d/7Tvvy+3f7
0/29/Vv/+f7w/oH+SP7s/XT9Yf3s/TL9P//A/q0A0P/N/1L/cf4G/vn9ZP2t/yz/
RQKqAZ4CVQKhAHUA0/6K/iL+5v2U/pT+6gCOAJgCJgIPAYcADP7J/dP8jfzj/WH9
rf5k/lX+yf2B/B/8gPtL+538SPwi/73+x/+O/yX+5v1b/Cv8SPz/+2H9L/0ZAEL/
ewE8AV4AIgDv/Y39O/wf/JH9Iv20/0j/8wCeAG4A6f8D/7r+h/47/kj/8/6k/zL/
kf53/rP9Xv3f/Hf8Bf2w/MD9nf0c/tP9W/32/Bv8l/tL+yX7dPtB+5r8Nfw+/ez8
9vyq/HT8Avy9/FH8Tv1F/TL+5v2z/qT+4P6R/or+Qv5R/jX+4/6B/qr/OP+3AHEA
mgBiAI4ASAD8AIEADwG0ABYA4/9o//D+h/8v/5H/HP+R/gb+6f1u/ZH+Vf7//nT+
qv1r/eb8d/wv/dz8/P3Q/dD+e/6X/0X/DwB4/27/Iv/p/pr+DP+X/ub/wP9xAeoA
kQH8AJQAZQD5/4r/LwDW/9cASABuAAwALwDK/9r/Vf8s/83+pP9F/1gA/P8WAHH/
4/2a/dD8ZPxr/dn81v1e/Yr+Gf6q/kX+lP0J/VH76fqt+n36qvx6/Dj+D/63/mH+
Mv0c/SL8Avwi/fb8l/5k/n7/Iv/Z/qf+p/2t/VT94/w1/tz91wCUAG4CHALjAKcA
Yf4P/q39VP0l/5r+iwBPAMcASwD2/qf+wPyQ/Cv80/vv/N/8h/4G/pf/aP+k/qD+
a/1U/cb9d/1h/0j/twCLAGgAGQA7//n+bv78/eb+Tv5FALr/+QFVAXUB8ADA/0X/
Gf9h/t3/Tv+3AC8A5gB4AC8Ajv90/hX+uvxe/Ej9Av2a/zL/0ABoAAMAnf8S/rD9
zPx9/On8oPzc/Xf9mv5Y/i//yv5u/wz/Xv4c/iX9zPxh/Qz9lP5L/uD+kf7G/Y39
iv0P/dD9Xv1u/k7+aP+6/m7/Gf97//D+Pv7g/Rz93Py9/Wf9yv9S/0sAw/9O//n+
hP7g/Qz9ivzp+4T7uvw4/Dj+8/0v/3v+oP2E/Zf8Tvxb/Q/9Xv44/lL/5v7K/7f/
0/+H//D+p/69/m7+RQDw/6cBSAHEANcAbv8y/yj/sP57/y//OADQ/0gAHABF/+b+
mv16/VT93PxY/vn95v+K/zwB5gAiAOb/K/3v/AX8qvth/Sv9jv87/z8AEgC9/3v/
Bv/A/uz9vf3z/Zf9Jf/Z/rcAewB7ADIAvf5R/hX+p/2a/kv+nf90/yUA8P/m/0v/
oP5L/qD9h/3s/aT9iv9u/70AcQCO/zL/KP0C/Vf89fvZ/I381v07/SX+7P10/kL+
6f2g/YT83/s1/Mz7p/13/f/+nf5b/vb9ZP3v/On8kPzs/YH92f5r/pH//P6H/0L/
pP84//z+bv4M/7D+SAAGAOAApwBYAOD/KP8G/8r+h/7G/tP+OP8M//z/4P+w/5T/
Qv4f/jL9Ff3//cD9Bv/z/o7/Zf+d/zj/7P6g/hX+7/2O/iv+of9b/5QATwBxACIA
of9I/5H+Pv53/hz+rf8o/0IAAwCH/3T/xv6H/oH+bv44/+z+1v+H/xwA0P9r/wz/
0P2g/Yr9rf2n/hL+4P6g/kL+wP0S/cb8KP2z/M39hP2U/hz+gf4M/mT9Rf3j/Hr8
ivwy/C/9qvw4/uD9/P2z/b38ffxe/PL7/P2N/YH/Iv9u//z+Tv7j/Xr97PxU/dP8
a/7W/UUAkf8iAL3/kf44/jX+wP13/h/+/P7W/jj//P4v/63+iv47/gz+7P3K/nf+
W//w/un/Vf/2/7f/t/5Y/oH9VP1R/un9CQCR/0sA3f9C/+b+8P53/tD+WP7Z/mT+
of8V/73/Yf///nH+bv7s/Tv+yf2t/jL+t/8//2X/H/+g/kL+Iv6n/X7+8/07/4T+
e//j/r3/fv+q/1X/qv5R/iX+yf1F/sn9Gf7p/R/+yf1o/gL+OP7p/br9KP3Z/W79
kf41/lL/Iv+X//b+zf4+/of9OP2k/Vv9Ff7//af+Uf7W/pf+Av7G/Z38W/wP/ND7
SP0l/TL/Gf9V/xn/6f3N/TL95vwC/e/8w/2q/XT/DP81AMP/Bv/G/qf9OP2t/Wv9
hP5V/jj/Ff9o/xz/w/6K/vP9hP0Z/ub94P97/8QAWAD8/1L/l/4M/s39h/1I/sP9
e//2/jwAmv9F/93+Ev7A/fP9S/23/lH+RQDH/0UBpABPAOn/wP5h/nf+//2E//D+
aADp/4sA9v9x/yj/lP4M/qD+Uf54/w//+f+E/+n/p/9S//n+jv4v/oH+D/5l/x//
WwDz/53/aP9F/hz+kf1u/cb9l/0v/rb9oP5I/kv+6f1+/QL9nfw+/IH8O/zA/WT9
gf4f/l7+Gf6a/YH9/Pzv/Gv9DP1o/vP9kf0o/bD8YfyH/dP8Pv6z/ZH+OP7z/mH+
0/5V/l79H/3s/If8ev32/EX+/P23/kL+Nf78/Vv9/Pz//Hr8cf0F/RX+jf3Q/jL+
7P5+/q3+Pv5V/uD99v5+/oH///5Y/9n+Bv+O/nT/5v6d/zj/fv8l/53/Qv97/6T+
sP7//Qz/a/6H/xX/L/+k/iz/s/6k/17/W//8/ub+l/5C/6r+hP8P/xL/pP5b/vn9
7/2K/Z39D/3W/FH88vyN/Kr9HP3D/VT9Tv7T/Wj+H/6t/W79Qf3M/OP9xv3s/dP9
a/1I/Yr9Xv2X/nf+D//A/lv+DP66/Wf9cf0S/YH9KP0r/p39Pv7//br+Mv7Z/m7+
OP7G/R/93Pz//Kr8K/6n/UL+vf2d/Tj9Av4C/pT+Iv6B/g/+WP7j/V7+Av5e/9n+
8P9C/8r/Rf/a/0v/IgDH/8D/kf8//+D+A/+9/rD/Zf9IAO3/mgBPAOYAqgATAboA
awC6/4T/DP/K/3H//P+q/xYAvf/j/73/qv9C/xn/vf5e/gn+Pv4M/ij+H/53/UH9
S/0r/eD9vf13/m7+lP4y/or+L/7//YT9gf0l/TX+pP3W/nH+fv4l/kL+Ff7s/cD9
4/1+/XH+9v2B/xn/bv84/1H+H/4J/cP8Tv3p/PP9jf1V/iX+Pv7p/WT93/y2/GH8
ivzf+9D8S/ya/Dj8Yfzi+2f8KPyz/Fv8K/0P/Yr9Rf2t/TX9W/07/Z39Mv10/UX9
rf1x/YH+8/0S/4H++f50/sb+fv5C/93+rf8M/6T/Tv9VAMr/hAApAPz/fv8o/5r+
O//w/pf/Gf94/wP/DP+d/pT+SP5u/un9Uf4V/pf+SP50///+aP9S/wz+uv19/Fv8
Yf3y/HH/vf7W/zv/t/5Y/tD9pP10/vn9aP4y/rr+9v04/7r+S/8S/7f+Ev6z/WH9
lP7v/bf/of/A/zj/Uf7W/Uj9yfwP/b381v1b/R/+mv3//XT9Tv3A/Ej86fvG+z77
RfyT+4f90/wP/oT9Ev19/C78rfsM/LD7d/xI/AX9zPxL/fb8Xv0c/YT91vxx/f/8
Tv7J/XT/6f50/wP/s/5Y/lX+//2R/i/+Uv/5/kIA0P8PAGX/1v5e/rb9Rf2H/SL9
xv47/lv/4P5x/93+s/4M/gz+3P0i/rD9wP44/mv/0/41/6r+Xv7g/VX+Ev7w/oH+
Zf/T/of/Mv/N/lj+9v2H/en9h/3A/hX+DP+t/hL/0/4M/9P+zf7A/lH+H/4+/hz+
zf5R/gb/kf7d/kj+s/5C/s3+Vf4G/lH9Qf3D/Fv9/Pzs/Vj93P1e/WH9K/3J/YH9
lP1O/Xr9D/1+/QX9nf04/ar9KP1O/Z38iv38/Az+iv1R/ub9Iv7N/TL+Ev5h/jj+
Iv7m/f/9nf2w/hz+LP+6/vD+6f5x/hn+Jf7Q/Vv+//0J/qr9fv75/Tj+2f0+/q39
SP72/Rn+zf07/tP97P6K/i//4P6U/jL+vf50/qT/KP/z/37/4P6X/rr+OP69/1v/
FgDK/x8Avf/5/4T/tP8v/2H/xv5S/5r+dP8G/93/cf/T/zj/Jf+n/r3+Gf4r/tb9
yf10/eb9L/2a/R/9Gf6z/VX+yf0C/kH9Yf3c/EX98vx3/QX9//2X/Sz/dP5I/4r+
OP6w/WH99vzc/HT8l/32/LD+aP63/oH+Ev6E/cP8d/yt/JD8Av6g/br+S/5O/tb9
lPyE/I37KPtb/Pn7cf01/Sv+sP1F/Rz9K/z/+zX7O/ua+x770/yg/On9kf2H/S/9
H/zi+178H/yq/SX9Pv7c/Wv+K/4c/q39Mv3W/Cv97Pxu/jj++f9Y/5T/OP9+/kL+
Bv6U/Uv+mv0y//P+gQDd/14A4P+U/0j/lP5R/tn9fv1x/iL+wP9r/4T/Cf/g/Wv9
Qf3D/Bn+h/0c/73+bv8V/7P+Nf5F/fz8ivwF/K38Nfzz/YH9A/+d/vz+nf5V/uz9
SP38/Hr9GP3z/Yf9Cf7D/Q/+pP3m/bP9Jf7J/RL+zf1h/jj+yf2X/a38Pvya/E78
l/1L/Q/+tv0G/kj99v1+/Yr99vxh/B/8kPz5+4H93/x+/Sv9Xv0S/SL94/zJ/Jr8
uvx9/If9L/3g/YT9Jf3m/I39H/1e/vP9gf4M/p3+Ff6B/hL+gf4G/tP+Jf5b/+b+
vf9F//n/bv+a/wb/l//8/lL/4/4//73+t/8Z/zv/lP5u/tb9hP4i/kj/7P4o/6f+
h/4f/mj+2f1r/gL+KP6k/VH+Cf4c/+P+h/84/xL/xv66/Wf9Rf3G/Az+l/35/mj+
a/41/pr9h/1r/Rj9Qf0C/cb9Yf01/tP9l/4c/kL+9v0C/l79Iv6R/YH+6f26/j7+
1v5o/nT+DP6N/QX9uv0V/Vv+7P2q/jj+Ff7c/X79Ff0P/Y38S/3p/CX+mv0y/gL+
bv0i/db8d/x3/Az8nfzs+0v93Px+/gn+DP9+/ij+4/1k/R/9Ev66/TL/yv7T/1v/
bgD8/2UAHABC//P+ZP7v/VH+Av6U/wb/JQCt/+3/bv8G/4T+sP5e/un+p/5h//z+
sP97/73/dP+U/m7+uv1u/W7+L/6H/27/vf9b/2j+yf07/af8WP3v/On9w/3W/k7+
4/5r/kX+yf2q/SX9lP0V/WH+9v2d/y//mv9r/xz+xv10/fn8iv4v/u3/W//g/1v/
aP+q/uD+WP4o/vP9Mv7N/TL/oP7d/2X/OP/p/kj+yf0+/en85vzM/Kr9Bf38/Yf9
tv01/XT9Cf22/Qz90/1u/Xv+OP7K/kL+0/5+/nH+HP72/W79h/04/dz9kf0G/6T+
eP8V///+qv5u/h/+SP4Z/oH+DP6U/iv+jv4v/sr+h/6X/07/5v+6/3j/2f7K/m7+
8P6B/uP+jv66/i/+8/6K/o7/W/+k/2v/s/5O/qD9Xv1L/dP8HP2j/EX9kPwy/oH9
xv4r/g/+oP1n/eP8jfwl/AL9ffwr/n79qv5V/ub+Mv6H/jL+4/2n/eD9Qf1u/h/+
Rf8S/yL/0P4y/ub9kf1O/Q/+oP2K/hL+nf6B/kX/0P72/or+//2B/W79zPzJ/Z39
HP7G/X79Mv1L/dz8WP0C/S/9xvxY/en89v2w/cP+mv7g/p3+Ff6a/U790Pxn/fb8
OP7G/R//oP4J/7P+Yf7//br9W/2K/Uj9Nf7Z/UX/Jf8MAKT/dP8c/6T+OP6g/kX+
Zf8f/zgA2v/Q/1X/w/5Y/hz+0/1O/uz9t/57/iX/w/4v/63+9v13/Rz9xvyB/RL9
5v6d/rT/lP/W/qr+Yf0M/aD8O/zJ/JD8Qv7s/eP/rf8MAOD/5v6E/qD9OP13/TX9
OP72/V7///7a/7r/S////kv+//1F/hL+wP6d/p3+a/6a/j7+Bv6U/Wv99vx0/S/9
cf4r/iz/8/47///+oP50/sP9cf2R/Y39kf5C/sb+mv5V/vz94P1+/bD9Iv2N/Uv9
dP1U/dz9h/13/vb9Mv7p/bP9bv2U/Uv9gf0M/db9dP0c/2j+LP/Q/vn+gf57/v/9
w/26/dP9ev3Q/or+LP/8/uP+kf4P/qr9yf1r/bD9Tv2t/lj+cf/w/qD+Mv72/YT9
l/0o/Vv+8/0o//P+pP8v//b+sP5L/QL9qvxn/HT+Mv5IAOn/JQCH/6D+WP5r/dz8
Ff3//OP9ZP2w/zX/SwDm///+hP6B/Tv9s/01/d3+lP69/17/0/9I/8r+SP75/ZH9
jv78/Uj/zf6B/yL/Gf+9/rP+OP7p/XH9Qv69/aH/L/8GANb/Jf/s/g/+7P0+/QL9
DP2K/Pb90/2t/zL/tP9L/zX+kf3y/FH8hPxB/OP8gfxe/hL+//6w/nv+HP5k/fz8
oPxk/CX93/yK/lH+0P9l/zj/Cf8y/pT9Ev6R/a3+Vf47/7D++f9S/47/Ff93/uP9
oP04/XT+9v2R/+n+3f9u/1v/xv5F/qD9ev35/Pz9p/0o/73+W/8f/7f+Xv7p/Wv9
cf1L/YH9W/1b/mH++f7N/pr+OP6g/V79bv0C/bP9SP32/sr+HwDN/7D/Uv+6/m7+
uv5V/or/Jf8vAN3/TwAiAL3/cf8M/+z+0P6X/kj/HP9VABIAmgAGAGH/3f5r/Tv9
9vxR/C/+qv3g/2H/+f+q/zX/4P4o/rb9Ev35/EX99vyO/h/+3f7T/lj+e/5u/kv+
7P6H/hn/nf7w/pr+3f5+/oH+Xv50/hn+LP+6/rr/P/9r//n+4P6q/nH+OP72/db9
kf41/rr/LP9l/zv/KP6z/ZT9W/1F/gn+A/9u/jL/hP6q/mv+h/47/tP9Qf3Z/X79
dP4y/gP/wP4c/9b+hP4V/sn9l/3p/bb9sP5L/mH///5C/7r+0P6w/un+sP5o/yL/
uv9h/5T/Qv+X/07/Xv8c/2v/Rf9b//n+D/+d/hL/nf7N/of+d/5u/pf+dP4//yX/
Ff+O/m7+/P3g/Zr9OP7N/Z3+SP4J/53+e/8J/w//zf5V/rP90/1k/Vv+3P1C/9n+
9v8//3H/8P4M/qD9oP07/fP9h/1x/ub9Ff+E/kj/7P7d/mj+/P1+/fb9l/2a/vP9
t/41/rr+Xv5O/v/92f1B/Uj++f1Y/wb/Vf/d/k7+sP3A/V793P1k/V7+//3g/oH+
aP/p/jv///50/ij+Ff7W/Zf+Gf6R/xL/8P+q/7D/OP8v/8P+vf5b/tn+d/5o//D+
Uv8f/3T+Qv5I/uD9DP6k/Uj+7/38/qD+gf/j/iz/xv7W/b39Pv3j/Gj+1v2O/0L/
6f+O/5H/L/+H/vP97/1+/Z3+dP4sABYAxwBxAAMAsP/W/qD+OP4C/kX+3P3s/mT+
BgBr/17/6f5+/SX9yfxx/K39Qf1o/vz9/P3T/V79Nf1b/QX9Yf3p/Nz9Pv07/gL+
2f2N/Uj9D/3A/Ir89vy6/C/+qv10/w//1v6B/nr9+fzv/Hr8Cf6U/Tj/7P4GAHj/
AABb/6H/O//W/uP+Uf4v/gP/zf7t/8f/3f94/4H/Cf9l/93+WP/z/jv/7P72/qf+
6f6n/r3+dP5b/j7+//3D/Yf+Xv7z/sP+w/5h/n7+H/6a/jX+Cf78/V7+aP6R/3v/
TwBrAB8A0/84/xL/nf6d/tn+rf7T/2j/cQASAF4A9v8o/wP/1v5k/ub+fv4v/9n+
Qv/s/gn/l/4Z/rP9ZP07/Vv+5v0o/5H+p/5e/gb+0P0v/Qz9vfyE/A/90/yE/jL+
Iv7m/eP8l/wu/Ob7h/wi/ND9WP1I/gn+1v6H/sD+d/7z/aT9Uf3f/CX+/P10//n+
w/+w/2j/Uv84/9P+0P6w/uz+zf7j/nv+l/5+/iL/0P72/sP+uv5o/qT+Vf53/kX+
//0M/sb9rf3W/a39jv5b/gn/pP57/m7+Uf41/mj+aP7p/qf+3f63/h//8P5e/0L/
tP9+/xn/SP9S/wz/hP/8/hn/9v4G/+P+Uv9O/8f/0P/H/1X/Nf8P/4r/Vf8pALD/
yv9u/xwAiv8cAOb/OP9O/7r+a/44/+b+qv97/wP/0P44/iL+D/7W/fn9wP1+/j7+
yv6R/tP+1v6E/lj+xv1+/dn9rf2E/lv+H//w/uz+2f5u/hz+OP4l/lX+Mv6O/pT+
w/6H/vD+e/7K/rf+l/4f/rr+lP6q/wz/Tv/s/nH+KP5Y/gL+//6n/m7///50/x//
SP8o/9P+oP6H/kX+yv6g/pH/DP8vAK3/vf9o/+n+qv6t/pH+Yf9F/+D/mv9S/yL/
4P6X/vb+s/6K/m7+d/41/t3+zf5I/wz/Iv8Z/wb/s/6w/5T/FgAGAB8AAADN/8P/
9v7T/uP+h/6h/3v/+f/Q/9D/w/9l/wb/Ev+3/vb+uv4y/7f+W//z/lL/D/9x/kv+
7/3c/Tv+H/6n/mT+//6a/lj+Ff5L/QL9mvwr/Dj9yfzG/YT9Av6X/Qb+l/3G/Uv9
Xv3//J39L/2X/v/9xv6E/mH+Ev6K/UH9Gf6d/V7+HP6z/lH+Bv/A/un+p/7d/pT+
4/6g/mj/yv4//8b+W/81/wz/p/4P/gz+W/4C/vD+S/6z/j7+Ff69/Zf9bv2R/Uj9
ev1x/RL+4P3A/jj+8P6n/vn+oP50/lv+7/22/bP+Nf5S/+n++f7W/uD+fv5+/xz/
AACk/0j/3f7Z/m7+eP/2/rT/Mv90/wP/2v9O/+3/e/8D/6f+nf47/rr+Jf69/mv+
jv4r/gb+w/1e/Rj9Rf3y/L39xv35/Yr9yf13/ZH9Rf2g/WT93P2R/Sv+oP1I/ij+
Pv7g/ar9bv2w/V79Ev75/YT+h/7m/sr+aP5u/tP9sP0V/ub9xv57/t3+p/7T/qr+
nf5O/nf+6f2H/oH+Iv/d/vz+uv5O/g/+2f2k/RX+xv38/pr+Tv8P/x//0/5R/tb9
6f1h/WH+Iv4S/7P+SP8D/0L/Bv8s/+P+3f6K/nH/1v5CAPb/hABCAHT/OP+X/nf+
KP/d/t3/e/8SACwAKQAZAIT/O//Q/pH+yv5o/mX/HP+U/2j/A/+z/sD9p/1Y/f/8
Yf5O/gAA8/8fAND/rf5Y/rb9W/3//Z39zf5e/t3/e//W/27/0P6n/qT9a/3s/af9
DP/g/u3/hP/p/4H/qv5r/q39h/0l/hL+Zf/z/pH/A/9Y/vz94P1n/cb9a/07/vP9
Bv+9/kX/8P4r/h/+fv0i/Wf9D/1F/hL+Ev/W/lX/6f5V/qf9p/2E/cD+lP7t/83/
PADH/8r/qv9Y/+b+uv6U/kX/Xv8DAb0AjgGqAbcAeAC6/0j/dP9V//b/zf9bADgA
WwAfAFX/Mv/K/nf+oP4+/tP+yv5O//b+/P6w/o7+Rf6t/VT9hP2U/Zr+W/4l/7f+
xv6E/rD+Yf4D/8b+O//5/tb+bv6B/jL+0/5I/mH/rf5b/+n+HP+a/hn/xv7w/rD+
jv5I/rf+OP7z/oT+3f6H/gb+sP3A/VT9//2k/dP9bv2a/W79W/0Y/e/8kPxX/Ej8
Ff3Q/D79Qf0c/eb8w/yg/Bj95vxU/SX9ev0v/Tv+//2a/k7+Iv6z/RX+nf3K/jj+
P/8S/5H/Nf/5/8P/0/+w/0j/KP/T/2H/OADp/3H/Tv+6/nH+w/5h/kj+OP5V/i/+
xv6q/kL+HP41/Sj9Ff3Z/DL9K/38/db9Uf4C/ij+6f3W/bD92f29/WH+Qv6O/or+
Zf/j/vz+p/6n/mv+1v7D/vD/eP8iAMP/p/8i/yL/gf4V/7P+Zf87/6f/mv+n/1j/
2f6z/rP9fv2K/VH9fv4C/vz+pP6w/lH+wP0l/fL8lPz2/J387P22/XH+Jf7G/ZH9
lP0S/S/93/yX/QX9SP7g/a3+fv6U/mv+p/1b/ZT9Jf1k/hn+cf8M/07/Ff9Y//z+
/P6t/mv+Vf6w/qD+nf97/8r/e/+9/mj+Bv66/e/99v1b/jX+oP5e/k7+Qv5C/gz+
DP7J/XT+Pv4G/7P+LP/s/jv/3f7D/nv+0/57/kj/9v6X/3H/H//8/rf+a/7W/k7+
S//Z/o7/L/8PAI7/vf90/yX/0/7w/rD+s/5b/rP+bv7m/nv+oP5+/uP+kf5b/+n+
P//g/mj+K/78/Z39+f2n/S/+8/1Y/vz9l/5k/rP+Tv4y/sP9SP72/fD+e/5h//n+
7P7W/tD9zf2K/Zf9WP4l/tP+l/4M/+z+0P7Q/lj+SP7v/cb9L/4i/t3+ZP7D/n7+
S/5F/sn9pP1k/UH9Pv4c/sP+lP5C/vn9bv1b/V79Rf3D/YT9WP4i/tD+1v5I//P+
cf5+/vP95v1L/gz+fv5b/un+1v7w/tn+Ev/W/g//1v5I/yj/OP8V/7f+cf5I/jX+
L/4v/oH+ZP69/un+HP/W/n7+a/4o/gn+6f3p/Sj+sP3Z/a39Gf7j/fP+S/5r/k7+
hP4c/sr+lP7p/qr+cf5F/pH+Pv63/1X/8P/t/5T/nf8V/73+4/6K/rr+Rf4M/73+
OP8f/4r/Xv8o/yz/t/6X/hn/sP5C/wb/Uv///hz+7/01/Qn9GP0S/YH9w/01/ij+
iv4+/g/+s/1O/R/9vfyz/L39rf0f//n+LP/p/kj+Bv4P/sP9Qv7z/fz+pP5+/yz/
Tv8P/4r+jv5F/gb+fv4+/hX/8P5b//D+8/66/ij+8/35/Xf9WP7N/af+O/6t/hz+
Nf69/aD9cf10/U798/2g/Sj+yf3s/cD9Z/0y/R/9GP1B/Q/9Cf6g/dn+3f50/mv+
KP7z/XH+Pv6z/or+4/6w/iL/0P57/1v/tP9O/9P/Mv+6/3j/W/9C/7r+fv5C/iv+
+f6a/nv/DP+H/x//zf50/lH9Qf1e/Qz9Nf75/ZH+Xv7c/ZT9Nf0l/cn9p/3K/oT+
Zf9L/37/KP8f/v/93/yg/Lr9Nf17/+n+pwBSAJQAQgA1/6D+d/3y/JT9D/3w/nT+
NQDW/3T/8/7Q/Zf9Rf38/Fj+4P2k/zL/Nf/T/gb+h/2q/Ff8V/wS/Jf9K/1F///+
SwDg/8D+cf50/CL8O/wV/Nb9Xv0D/8P+Xv+z/tD+d/44/hn+Xv4S/gYAlP+tAHUA
x/9o/wn+l/16/Qz9Xv41/p3/eP94AAwAW/81/839a/07/Vv9yf13/R/+yf2O/lv+
KP72/T790PzD/J38Gf4M/gn/KP8f/vn9W/35/HT9WP3z/ZT9l/4i/rr/W/8ZAAYA
h/+B//D+6f7N/pf+Tv/p/vD/zf/g/63/Ff+9/g//pP7w/p3+Vf4S/jL+zf2t/kL+
Gf7Z/WH99vxL/dn87/2X/ez9pP1r/Vj9mv1r/XH9VP1L/RX9l/1h/Sv+4/1C/ub9
Yf53/n7+H/5V/uP9S/4G/uD+l/4M/wP/bv9h/4r/W/+t/nf+d/4f/h//nf5o/wz/
5v6z/sb+rf4Z/wb/rf6B/uz94P0G/pf9mv0C/fn8kPyq/KD8S/0C/Yf9D/1h/fL8
Ev29/Kf8YfyX/If84P2N/cP+fv7j/l7+sP4v/sD+Yf63/oH+x/8V/2sA6f/8/63/
Ev/m/v/+HP/p/7T/0P+X/9n+0/5o/lX+D/7c/Sj+yf1r/lj+vf6H/iv+Jf78/Bz9
UfxL/MD8uvw+/iL+p/5+/lT9HP1L/DL82fxx/KD9dP1O/hz+LP/K/mX/+f4v/s39
s/1r/Zf+Xv5O/wn/bv/p/qD+t/5L/vn9a/4o/jL/6f6H/2H/8P6t/uP90/3s/Pz8
+fzA/Hr9Uf2R/l7+bv5O/uP8sPyz+8D7EvwY/H38YfyQ/Fv8H/3y/Hr9Ev29/K38
//y2/GH9Pv2R/Wv9Av5k/X7+Ff5R/gz+mv6K/tb+s/7N/pr+p/6B/uz+sP5x/zL/
sP6H/rr+a/6n/pT+4P6q/vn+iv4y/hn+Rf0o/Sj98vz2/db9w/5b/lH+Mv7D/X79
OP38/EX95vyz/Zr9sP6K/hz/5v5b/j7+Jf0P/TL9D/1k/hX+Ev/A/vP+xv4i/tP9
7P3Q/UL+Mv6R/nv+5v66/kX/DP+O/kj+ZP32/Kr9ev0D/8D+Iv/s/jv+3P2g/Vj9
HP3m/P/8s/yw/YH9l/47/k7+Av5B/ez8h/xI/PL8bvy2/Yf9vf41/or+KP62/Y39
jf1h/Rn+5v3G/of+Ff/8/qf+gf44/hX+SP7W/T7+4/3G/nv+Jf/8/sP+iv4G/rb9
w/2w/XH+HP4l/7f+Tv8P/zj/+f66/o7+Ff66/fb9yf35/o7+WP8f/yj/A//W/qf+
cf5I/iX+D/7j/qr+fv+E/9D/4/+E/zj/kf5R/hL+6f38/f/9mv44/vP+oP7g/nv+
Mv7p/Zr9kf2R/Wf9OP4P/qT+Vf5V/gz+Uf3y/ND8mvy9/YH9S/4C/qr+cf5F/gb+
Z/0+/QL91vyB/XT9nf5+/vb+h/47/j7+iv1u/YH9W/17/g/+bv/p/pH/9v6a/kj+
bv0o/eb8sPxx/SX9W/4S/vz9s/0P/cb8Bf3c/DL9GP3v/aT9l/4i/s3+Yf7z/cD9
s/yt/KD8VPzW/aD9s/5o/nv+K/5O/v/9Ev7J/Zr+Uf7s/rf+A//K/lL/Ev9O//b+
L/8//3v/SP9Y/0v/Ev/s/rr+gf6K/h/+xv5I/vz+qv66/lX+9v2k/Qb+hP01/vb9
wP2d/ZH9VP1u/Tv9gf0o/VH97PxR/Sv9vf2U/X79iv13/Xr9cf1L/Rz+0/0P/tz9
L/01/SL9w/yk/UH9sP5L/iz/8/4S/wn/hP4r/or9GP0S/fL80P3J/cb+lP6n/pf+
9v3Z/Uj9Av0i/e/8wP2U/Uj+Bv7J/br9O/26/H38SPzy/JT8//2k/ZH+cf5O/tz9
cf0C/XH9GP3T/Yf9+f6E/g//3f7D/tb+Tv7D/fb9nf2O/k7+D/+n/jX/wP7j/m7+
9v6X/kv/7P6k/0v/Gf+9/or+Ev7Z/Y39WP0+/fb91v3D/rD+yv5C/mv9Rf2q/If8
6fz5/Ab+mv2g/lH+hP47/r39ZP1I/Qn9dP0+/RX+7/2E/vz9DP7J/bP9a/0+/Rj9
xv2w/Zr+Vf4i/g/+//zG/Pn8hPzj/a39e/47/lH+Ff7G/XT9l/xq/Bj8tvv8/L38
cf4r/sr+bv7j/Yr90Pyn/LP8gfzm/XH9Nf9S/x//A/8S/v/9Rf0v/XT9L/2k/k7+
vf9e/3j/DP/8/Wv9iv0r/W79Qf1u/gb+Nf/Z/kj/+f63/mv+7P3c/SL+DP6n/qf+
s/53/nf+Vf4v/ub9h/04/TX+7/3Q/rP+wP63/qr+kf4o/8b+Vf/g/g//0/4l/+D+
a/8Z/wz//P6H/lj+s/5r/sb+fv47/jj+Iv5L/vD+s/6R/nT+0P16/VT9Mv29/YT9
Rf4V/mH+Yf4G/rD9+fyz/A/89ftx/EH8bv3v/F7+Ev78/e/9VPw4/GT7MftL/AX8
3P2w/WT+8/0l/sb9kf2U/cz8rfwl/R/9bv47/vz+wP4i/sP9+fzM/BL95vwi/hL+
xv6k/rr+wP69/dP90/yg/Nn8w/x+/V79Tv4i/tP+l/62/ZH9W/wi/CL96fzA/eD9
H/7c/fn9zf3J/Zf92f2R/dn9wP3N/pr+1v+a/6r/eP8G//n+rf5u/nT+cf4c/0X/
FgDj/83/t/9L/0j/w/7m/n7+d/5L/hn+dP4l/un+rf44/hX+a/1b/WT9S/07/Rj9
D/3Z/BL92fyd/UX9Jf3c/CL89ftU/HT85vzj/GT9nf2z/YT9s/2U/Vv9Mv04/dn8
qv1x/SX+Jf5k/kL+nf2H/ez8tvyw/Lb8W/1U/bb9WP1b/Vv9bv1L/V79Av3p/Kr8
+fzj/NP9oP3T/YT9jfxn/GT88vvy/MD8fv0S/Z39Iv04/fz8mvw7/AX9bvzW/VT9
Tv4P/nv+WP5u/jX+Av6K/af9bv2E/lj+vf+H/2X/SP+n/nH+l/6K/gb/8P7N/rf+
t/6R/qD+jv4l/w//Jf/z/iL/Iv8J/+z+h/5o/tP9/P0Z/sn9W/4o/uz+2f6z/oH+
zf2g/ZH9a/0M/sb9l/5C/ij/zf7D/qT+zf3Q/br9l/2R/qf+hP+H/0X/Cf8c/vb9
4/yU/MP8Z/yw/VH9uv57/pf+S/5O/RX9KPzW+0X8+fuR/Wv9Tv72/RL+tv2d/If8
FfzM+9P8nfzg/cD9Uf4v/lH9W/2K/Jr85vzj/GT+H/5+/6T/L/8i/7r9jf0+/SX9
vf1B/a3+WP66/5r/zf9l/yv+Mv72/AL9d/1b/W7+SP4y/+P+H//m/hL+7/2q/Uj9
4P2d/Xv+SP7W/nH+gf5Y/jX+Gf6w/ZT9Gf4l/o7+Yf6H/j7+HP7G/Wj+9v2k/yj/
LwD5/xkAFgBL//P+Ev7G/RX+9v0P/8P+LP/D/hX/lP66/lH+Ff6w/dP9d/0o/v/9
kf47/pf9Rf2E/GT8mvx0/EH9H/2U/WT9oP1O/Sv9wPxL/Cj8Pvw1/CL9L/3W/aD9
0/2w/Zf9l/2N/Vv9rf1r/Rn+7/23/ij+nf4y/jj+H/6X/jv+0P5x/uD+e/7N/mj+
aP41/gz+Cf4o/uD9p/44/uP+nf69/p3+Gf7J/UH9Av16/VH9Ev7J/Qb+4P0P/rr9
9v3D/bD9bv3T/Yf9dP4+/g//w/5r/9n+Cf/2/lv/SP+X/2H/uv+B/xkAyv+0/53/
e/9L/4H/Uv/2/7r/zf+6/73/qv8s/zX/aP4o/g/+3P3G/db9Ff7Z/X7+Qv4f/ub9
xv1u/UX99vyQ/Jr8s/yd/EH9Cf3D/aT97P1r/bP9dP1n/Sv9fv04/br9hP0S/pT9
6f3G/Tj+7P01/gz+OP4G/n7+Uf4M/9b+2f57/hL+vf3c/Y39Nf4c/sP+0/7G/pr+
WP5L/p39gf0S/db8fv1B/TX+Tv6q/lX+9v16/W79H/0J/QX9ZP1U/X7+Yf4y/y//
fv57/jL9Bf0l/B/8SPwV/KD9oP0+/iv+SwAGACkCHAIDAtABVQL2AeMAzQDs/dn9
yfy6/Ob8o/wV/tn9LAAMAPn/t/8f/uD9d/0y/U79Iv1b/i/+eP9F/0X/Ev87/uP9
4/3G/cn9lP3G/X79//3c/dP9dP38/cb9aP8P/6f/S//s/eb9lPy2/MD8bvwV/Z38
cf4C/hkB5gA/AiYCeAEWAW7+cf7G+qP6Qfl9+b37qvtr/TL9KQDz/+0DiAMpAtAB
9v2R/XT5K/kU9Qv1Y/UX9SX7+PquA7EDDgrkCRcIHQgs/yX/v/aT9v7y2/Ky9lf2
sP+K/xMHCgcaBw0HIwLtASX87Psr99v2WvgI+Gv9O/0pAi8CQgQjBCwCKQK9/1v/
7/3N/a38VPyz/FT8V/wV/CX87/uU/E78Mv3A/Jf+Yf4vAMf/cQAPACUA7f8JAOb/
lP5O/oH8RfwV+/z6sPpe+jv8LvyhAKoAjgRPBDYERgTgAL0Aqfqz+iH22/Uh9+v2
Xv2n/RAE8wNTBkkGawM2AwX97/xa+JP4bfiA+Bj7KPtY/Xf9rf13/SL+/P1+/3v/
PAH8ALEB1wH8/vD+zPmw+Y/1YPU39x73pP6R/nIFZQXqB+EHqwSkBCv9K/00+Bj4
Qfgn+Mb6mvrv/br9DAEZAdACxwIcAxYDawI/Aub+s/56+Ur5J/Yx9pn3UPcr/f/8
YgNMA9cFxwUjA8cCKP35/DH4NPic9kr2ffmG+YT/SP+OA1IDggRsBO0C2gL8/pf+
7PrW+oD5Svln+yL7Jf8Z//YA8ABSARMBxwDAANn+Ff/M/Lr8jfvA+0T7D/sF/ND7
Cf4V/qr/fv/N/6r/Uv///k79Jf0S+9P61vp9+uL7sPvJ/MP87/26/Qz+Cf7g/af9
iv1F/dz8yfyH/aD9uv5x/qr+bv6t/Zr9cf0r/Yf9Tv0V/gn+fv8//4H/Vf9Y/i/+
5vy9/KD7jftb/Aj8wP2d/c3+uv6t/07/Tv/Z/j7+yf0G/rb9Jf7Q/cD9lP1Y/Q/9
Tv3m/G79Pv0v/uz9mv5u/h//Gf8lAMD/L/87/0j+1v1V/uP9hP41/pf+Vf7W/4H/
x/+O/73+rf7m/p3+L/4f/vn9Cf7Z/q3+Jf/z/mj+Xv7m/br97/38/Yf+gf72/vz+
Zf84//z+s/4y/d/8Jf2z/FH+Pv75/uz+//7g/or+gf6k/dD9w/2t/fb9+f2U/h/+
W/5V/lT9DP1O/cn8Nf4P/t3+nf47/xz/0P7W/mH9K/1U/UH9h/5b/vn+s/69/qD+
SP5V/gL+tv0c/s39DP/m/sP/Xv9L/xX/Pv4l/gn9DP3G/F78h/4l/qQAeADqAJoA
eP8c/4r9cf1n/H38Uf0P/Q//kf6kAEgA/P/N/1X+Mv50/Sv94/yU/Ev9Ev3W/rP+
rf9x/47/gf/w/hX/Nf7Z/dz8dPwC/YH8DP7W/V7/a/8fAeMADwETAQn/1v4f/e/8
9fsV/Pb8sPyB/nT+dQAWAGUBQgEDAdoAIv/W/i/96fzv+8P7h/s7+8D8ivxO/wP/
1wCXAMoAqgB+/w//KP2X/Dj7qfob+7D6rfwP/Jf+Yf7t/53/gf8c/3H+Mv5k/Q/9
sPxR/Oz8o/zs/Yr9LP/A/gYA0/8sAO3/2v+H/wb/w/75/U797P2n/ar+Yf6O/n7+
qv6d/h//wP4c/93+l/5h/rf+Xv5O/v/9Iv66/Yr9K/2E/TX90/1R/Qz+uv1V/ub9
e/4i/oH+3P26/VH9W/0v/YH9DP2H/U79Rf7v/SL/uv5S/w//dP/Z/uz+rf53/hL+
W/72/UL+5v2X/jv+sP5k/uz+lP4l/+n+L//d/hz/A/9u/h/+vf1b/eP8oPz//On8
fv3//Nb9l/2g/jj+Cf+g/jL+//2g/SX9cf3//Dv97PyK/RL9ZP72/cP+Yf75/tD+
Xv8D/wP/0P6K/Uj9tv0v/Qn+rf0V/qr9Jf+3/l7/+f78/o7+zf5r/lX+sP01/gL+
hP41/lX+D/6H/nH+S/4J/pr+L/7A/mv+gf7p/Y39fv2n/Sj9Ff2z/Lr9a/0v/9b+
Zf8f/47/aP+H/z//Tv/j/mv/8/4V/7r+6f2X/db9WP2k/l7+FgDK/yYBzQBlAEsA
L/4i/nf8RfwS/Nn7hP0y/VX/5v4SAI7/3f+k/zX/wP4S/qT9l/2K/Wv9L/1k/Qz9
pP13/Sj/1v5uAAYAlwAfAAn/xv5Y/Vj9ivxF/Nn8h/wZ/sn9Vf8//73/jv+a/1j/
Ev+a/rD9WP0V/db82fyQ/JT8SPxh/RL9zf6X/m7/1v6w/mH+zf16/b38cfwr/BX8
mvxk/Jf9Jf1h/rD9uv5C/kX/6f4c/63+mv6H/p3+Pv7j/Y39kf1L/aT+bv5uAPP/
BgGaAHgA1v9Y/9n+4/2k/b39Qf0V/vb9hP5o/vP+xv66/mv+tv1h/YT9SP35/Qb+
qv5F/of+bv4y/tD9VP32/Fj9/PwG/n79wP5O/pr/Uv+O/17/qv5o/pT+WP6w/n7+
SP8y/8D/p//Q/3T/lP8y/zL/3f7A/3j/lAA/AAkAp//G/pH+wP1r/cP8Yfx3/VH9
Nf/m/lUADwAPAM3/qv6U/kv8TvxX+/X6BfwI/D79w/xR/j7+W/9C/07/8P6q/nH+
d/0J/S783Psb/NP7Jf3y/Fv/LP/wAPwAHAEPAZoAFgB0/ij+jfyX/EH8//s+/S/9
KP///vMAhwAiAdoA1v9V/5r9Pv3y+4T7Evya+179H/26/qD+iv+O/1j/Bv8C/tb9
/PzA/Nn8kPwS/eb8a/4v/tD/nf8GAKf/hP9b/9n+0P6z/XH9O/3v/Bn+6f1u/1L/
rQCHAEUB9gD5/7T/vf2d/ZT8Rfxk/EX87P2a/dP/bv/QAHEATwA1AJ3+SP72/Jr8
Nfzc+7b8SPy2/WH9dP47/rf+Pv5k/h/+zf2z/cD80/xI/AX8Rfwo/PL8tvxL/hL+
Jf/N/iz//P5h/mT+DP7//Yr9cf01/vb9d/5F/tb+oP4M/8r+0P53/pf+OP78/db9
rf3N/Qz+6f0l/+n+W/9S/47+ZP5r/U79Tv0l/ZH9fv0S/sP9ZP47/tz9oP1h/fn8
0P2B/XH/Jf8PAA8ARQAMAKH/Nf+d/jL+Ev/A/vn+xv7D/pr+fv+a/+D/hP/A/n7+
hP6E/vP/hP/QAJ4A1wCLAGj/cf8C/d/8EvsL+zj85vvz/mj+GQGUAAkBzQAD/8r+
Qf0M/QL+8/2EAA8AAwGtACz/t/53/N/7d/pB+qb7Ivsr/tn9QgC0//z/pP/A/pH+
aP78/T//xv7p/7D/zf6B/iL9wPwP/Mb7H/zJ+wn+vf1rAAYAMgDT/1X+Ev69/FH8
Yfwu/Hv+Ev4WAJ3/O//d/vL83PwI/Mn7bvxe/Jf9Ff1C/s39W/4l/vb9qv2O/gn+
tP94/2gA8/+a/wP/7P2q/YT9L/2H/g/+EgC3//kA3QDp/4H/SP3D/EH7wPpb+7n6
Iv2Q/Kr/Ev/W/3v/sP53/hz+vf2g/k7+D/9e/lv+Mv7s/Z398/2X/Zr+S/5+/0X/
UgAsAK3/SP+U/uz9Qv72/aD+Mv7W/oT+l/5e/tP9oP0F/cn87PzZ/HH+a/6h/0j/
h/9C/4r+a/4c/Q/9Ev2q/BL+pP3m/rr+jv5k/v/98/2w/YT9Tv0V/eP9tv1F/tb9
9vyw/MD7d/vc+6D7bv01/dr/mv8GAeAAKQCX/9D9cf0Y/OL7V/wY/HH9KP1k/jj+
zf6K/l7+K/7v/dz9bv4y/p3+l/4Z/j7+W/1h/a38o/zA/IH81v2k/br+bv5O/gL+
/PyH/MP8XvwV/e/8jf1L/Sj+7P26/lj+gf5I/k7+Pv7K/qD+A/+H/gb/nf6n/lX+
S/4V/mH9DP2K/UH9oP5e/lv/HP8V/+z+SP8c/2v/OP/s/t3+3P3Q/dP8uvwf/af8
l/1k/bf+OP5V/zL/lP8//7r+nf5F/W797/y6/CL9L/38/Z397P22/UX+2f2n/nT+
8/5x/i/+3P0V/fz8ffwu/Lr8p/wS/rP9L/+3/gP/t/6R/lH+Ff7c/UX9xvzv/Lr8
Mv0i/Qz93/wJ/bb80P1U/Qb+w/2n/VT9yfx3/Hf8O/yq/G78Pv0F/TL+0/1k/tn9
1v2E/WH9GP2R/Tj9dP4Z/m7/zf5h/+n+Nf4S/vP9S/3T/V792f10/Qn+p/0v/uz9
8/5h/kX/2f6U/zv/zf7d/kX+//2z/Yf9SP3//M39ev1b//z+ZQAvAHsAFgAy/9b+
Ff6q/aT9K/2X/T79H/7N/Tj/zf6w/4T/Jf8V/6D+aP4f/sP9H/0Y/R/91vx3/Sv9
Pv4f/mT+Gf50/jj+Bv6n/Tv94/y6/J38Yfw4/MP8O/xe/fL8Yf4C/i/+3P2w/Xf9
//zJ/E78JfyK/E78Mv0P/eD9jf1r/kj+h/5C/lv+Gf7T/Zf9GP0i/cP8vfxe/EH8
9vzQ/Fj+Iv5h/2v/l/9C/yv+Bv7p/PL8EvzJ+4D7gPuQ/D78//2d/dD+jv6H/mv+
Xv4C/lH9ev3s/NP83Pyj/Dv9Ev0c/tP9Jf/T/kL/8/7Q/oH+K/7g/dn9wP0y/vn9
8P7g/ub/iv+n/17/7P6H/of+a/4v/hn+Iv7z/eP+d/6a/k7+O/78/VH++f0G/rb9
sP1F/V79Iv2E/RX9L/3m/Bz93Pyk/Tv9zf10/WH9Bf3D/JD8vfxu/Jr8Z/yj/Dj8
H/2H/Pb9Xv0V/tn9Ff69/eP9a/1n/Rz9dP3v/K39ev0i/p39KP7J/ar9S/2k/Tj9
OP0C/Sv96fxu/Tj9fv1F/U79+fzT/H383Pyg/FH9Qf3W/Yf9OP3J/ND8Z/zM/K38
Ff2a/G799vzs/c39cf4S/k7+Iv4P/hL+Cf7z/UX+4/1r/uP9Yf44/ij+1v1b/uD9
1v5R/s3+dP6U/lj+rf6B/n7+Rf4P/qD90P2U/b39l/2t/XH9uv2H/Uj+rf1+/u/9
Cf7J/ar9Qf1b/RL9lPw1/LP8lPx+/SL9nf1O/eb9lP2N/Tj9OP2K/L38UfzD/CL8
KP3G/Hr9O/3W/Vv9/P3A/Qb+xv3p/YT9Tv3Q/IT8H/xq/Aj81vyX/Gv9Nf29/W79
lP01/Zr8hPzW+2T7oPuH+078FfzT/JD8gf0J/Wf9Nf1k/f/8s/x0/Gr8Ivy2/Ir8
xvyn/D792fzQ/W79O/7D/Qb+7P0i/s39uv16/YT9Pv3Q/Vv9HP6a/W7+/P04/rr9
Gf7N/TX+/P1V/tP9Gf7m/Vj+4P3Z/ZT9H/3D/JT9Ev3Z/Xr9D/7c/S/+0P0C/oH9
s/1B/bb9ZP3A/Uv9jf0S/Z39Nf2z/Zf95v2z/WT+Cf7g/nf+pP53/hn+6f16/SX9
L/3Z/Lr9gf1r/vb9gf5V/iX+6f2B/Rj9Jf3Z/Mz8Z/yH/Dj8w/xk/Bj9sPzG/I38
KPzi+078H/x9/Ev8nfwb/Nz8wPw7/QX9S/0C/Vv9Bf2E/Wf9rf2X/eb9p/3T/Wf9
qv0Y/UH9oPx0/TX9iv75/cr+Qv6w/jX+sP1O/dP8l/wJ/Zf8Yf0J/Sj++f3//dz9
S/04/Yf9Uf22/VH90P2E/Qn+rf3g/YT9Nf3s/Oz81vzc/aT9Xv7j/ar+aP6B/m7+
K/4J/nT+Yf6a/p3+7P7A/qf+mv6K/n7+ZP5R/s3+l/6E/2H/mv90/xX/9v7D/oT+
e/4+/jv+8/2E/Z39zf22/WH9bv1B/R/9Gf7g/UX+SP7s/br9Iv3v/PL8wPyj/Jr8
1vx3/E79GP0v/sb9w/2k/Rj9Pv0S/bP8H/0l/VH9Ev3p/Kr8Cf3A/D793Pyg/Yf9
K/4P/rr9w/01/SX9/Pyz/MP8lPwY/ZD8HP7m/cb+gf4Z/un9SP3s/Jf8UfzJ/D78
+fyH/Bz9o/wC/bD8Iv3G/HT9+fyB/Sj9Tv0v/XT9Xv04/d/8Yf3c/An+0P2z/pT+
zf6R/lH+5v2w/W79rf1h/Vv+/P38/sr+bv84/7P+s/6O/lH+bv5F/pH+W/63/nH+
l/4v/tz9pP3v/Yf9h/5F/qf+ZP7j/VT9S/32/FH9xvwy/dz8uv1R/Wj+HP5x/iX+
vf2K/T79Av13/RX9h/01/Yf9Pv13/W79mv0y/XT9Qf35/af9Jf7c/dz9sP2N/br9
O/3j/A/9jfxU/ez8Ev6q/UX+zf01/nT9p/1x/S/98vzc/LD8Iv3c/B/96fwF/en8
SP0c/YT9Xv1+/TL9hP0o/Zf9L/1r/Uv9l/0M/Yr9Qf1k/Wf91v1I/VX+sP1C/vb9
H/7j/fn9yf2E/kL+Yf7//T7+9v1u/lj+Pv4C/sP9W/3c/Z39S/7s/QL+qv0P/uP9
ZP4Z/lj+L/5u/g/+S/4M/lH+Qv6E/hn+sP6k/vn+wP7Z/pf+aP6B/rP+kf6H/j7+
0P16/XT9WP3N/b397P2N/b39Yf0G/rP9DP7p/Z39W/2U/U79zf2X/ar9jf3D/aT9
7P3A/c39iv3T/af9Ev66/db9mv04/dz8mv1R/dD90/35/cD9fv50/uD+gf5u/nf+
D/7p/fn92f3//cD9//2X/Vj+D/5I/uD9gf78/Vv+Gf6B/iL+/P3J/dz9jf3s/aT9
HP7c/VH+D/5x/hL+K/7p/dD9fv2d/TX90P1r/ZT9Nf22/YH9yf1+/W79KP2N/Uv9
zf2N/XT+Iv41/r39L/78/UL+9v1e/tD9Mv7p/VX+Gf6t/jv+a/4l/oH+D/6O/i/+
mv7//Wv++f3v/bP96f2E/TL+0P1o/hn+7/3N/X79OP1+/R/9S/3Z/O/8nfxr/Sj9
pP1r/V79Cf1k/f/8Yf0S/eD9ev0v/u/9L/7g/fP9hP3A/a39vf2H/e/9fv0c/sP9
Iv62/Tj+Gf5x/hX+a/4r/pH+aP4V/tz9h/1L/dn9mv0c/ub9Gf4C/gb+/P29/Yr9
ev0+/Vj9wPxn/e/8SP0Y/Tv9+fyt/Tv94P2t/Tv+w/1u/lH+5v5+/kv+Av6E/Yf9
uv1+/QL+sP1+/kL+5v6a/uP+t/4+/iL+zf3T/eP9l/3W/bP9DP7//Sv+Iv4V/sn9
s/2E/a39l/2g/Vj9Qf3c/DL95vzW/MP89vy9/H79bv3W/YH9iv1L/Sj9DP3j/J38
8vzy/FH9Yf0y/iL+lP5L/hX+9v3z/Y39Av7D/Tv+0P1u/ij+S/4l/mv+HP5C/hz+
Nf7s/SX+5v38/bP9//3W/Qz+1v3Q/eP96f3g/VX+Iv4S/sn94P2k/VH+Jf5e/jL+
Iv7m/VH+4P1x/jj+hP5x/q3+qv7w/t3+5v7K/s3+2f4M/wn/aP/m/j//6f7D/k7+
Tv7m/dD9bv0i/uP9s/53/pr+dP5b/hn+Tv4+/s39/P3z/cn9Av4C/uD9wP2n/Yf9
9v32/UL+8/1e/jX+Qv4C/tz9mv3s/Zf92f3s/f/9D/7G/qT+Jf+9/s3+kf6H/kv+
Mv4c/ub93P3p/ZH9Mv75/Sj+0P01/hX+jv4c/hn+6f2k/Uv9rf1n/ZH9Qf2N/V79
0P10/ez9iv1+/X79xv1U/eD9W/0C/sP9Pv72/Vj+Ev44/gn+SP72/VH+H/41/iX+
hP5b/uz+yv7p/tD+dP5Y/pf+SP6E/nf+cf44/n7+Pv7m/of+5v6H/rr+bv6a/o7+
l/6B/k7+D/4i/tz9HP6z/R/+uv1C/uP9Nf7m/S/+H/4y/sD97P16/db95v3m/bD9
Iv7G/Wj+Uf50/gn+ZP4J/tb+l/4G/83+0/6k/nT+bv6z/oH+Cf+q/sr+e/5e/k7+
ZP4V/qD+aP53/lH+mv5o/m7+L/7p/b39tv1u/Zr9S/3G/YH93P2z/aT9cf1U/WH9
sP2U/SX+oP3Z/aD9+f3Z/cb98/2R/V79/P2w/U7+/P07/kL+Rf4M/qr+qv7G/nT+
gf5O/n7+cf6a/mj+Vf5I/mj+SP5+/k7+kf5I/pf+SP6R/mT+e/47/lX+Cf5o/gz+
K/7Q/eb94/3A/ar9w/1x/cD9iv3Q/ar9Av7p/fP97P0f/iL+Jf7//fb9xv0M/tD9
hP4r/pf+h/75/r3+4P6w/uP+xv6B/k7+O/78/Yf+gf63/n7+gf5L/sP+l/7A/of+
Tv4+/k7+Jf4l/iv+Av6k/Zf9S/3p/cn9Rf72/cn9zf35/fb9ZP5V/hn+7/3g/cD9
Av7p/Sj+vf0l/g/+bv5Y/s3+p/6d/o7+gf4+/j7+7/1F/iv+Mv4r/rD+WP6K/m7+
S/5R/jL+Cf5L/j7+pP5I/sb+l/6K/lX+O/4i/kj+/P1Y/lj+cf5L/kX+DP4+/g/+
K/4+/un96f3N/Y39/P3p/UL+7/0G/h/+4/38/Rn+wP3Q/dP9Bv7z/SL+//0Z/sP9
OP4f/pT+fv5V/hz+Av75/V7+Jf50/kv+Tv4V/iX+Gf5F/kX++f2w/XT9iv3z/eP9
Jf7s/Qz+zf0S/qT97P2w/dP9sP0v/un9a/4G/iv++f04/gL+s/5b/qf+e/5F/un9
dP4c/rf+Iv4l/uP9L/75/br+W/6B/lv+SP4Z/kj+Av4c/hX+HP7v/Uj+Gf5x/h/+
D/4C/hz+Gf4c/vP9D/7Z/Vv+4P2g/k7+fv5b/mj+Qv5x/lj+e/4o/m7+K/5O/h/+
nf4y/rf+kf6w/or+4P6t/rr+S/57/vP9S/5F/kX+L/4i/u/9Ev4M/pf+t/6n/mH+
Vf4f/iL+Jf4o/gn+qv2N/b39dP0P/tn9Ff7c/en91v0P/s39kf2q/Wv9bv3N/aD9
//3A/e/9p/0V/vb9nf4J/gz+4P0V/hL+jv5k/or+hP5k/g/+Jf4f/gL+6f0y/tz9
Jf7Z/Qz+uv3g/br9Bv6U/RX+tv3c/aD97P1h/eD94/2X/aD9lP1I/Tv9//yE/U79
sP16/fb9hP0J/tb95v26/ar9VP3A/Z39Ev7A/Tj+5v2H/ij+uv5x/rD+bv57/jL+
bv4P/lH+8/0J/rr9SP4i/lX+Gf5L/un9OP7m/fb90P2d/ZT9rf2k/bb9p/0M/sn9
6f3G/fP9iv01/vP91v3c/RX+nf38/c39zf2E/Qz+pP1F/vb9W/4G/u/90P0c/vP9
KP4o/kv+cf4+/jv+lP5R/nH+Qv4l/gL+7P3T/aT94/32/db9dP44/kv+//0M/un9
Iv7T/Qn+2f2q/Yr9l/1F/cD9L/3G/c393P3Q/Q/+5v3G/eP9w/2t/Wf9ZP3A/WH9
rf2a/Rz+3P17/h/+W/7//U7+Iv6a/jj+4P53/jX+Iv44/hX+cf4f/lv+DP6w/jj+
l/5e/of+Qv5V/h/+gf5F/pH+K/6k/iv+W/7//Tv++f0v/oT9O/66/Zr+ZP7G/lj+
d/47/iX+1v2B/hz+Mv4S/rf+Iv6O/kj+e/5o/s3+sP7g/r3+wP6w/qr+hP6O/kv+
SP4c/mv+6f1h/kL+lP5C/jL+D/7p/c39K/4Z/mj+9v07/vz9Bv7//SX+5v1k/g/+
a/4f/mH++f17/j7+lP53/lH+//1Y/tb9dP5O/pH+KP5x/lj+WP4M/nT+H/7G/nv+
kf5e/lj+WP6O/of+Yf5O/mv+Xv6E/pH+fv4v/ij+9v0P/vz9H/4G/gL+8/1V/iL+
KP41/vP99v3Q/cP9jf2R/cb9mv0V/vz9Xv75/T7+Cf78/dP92f3A/UX+DP5r/kL+
O/4l/j7+Ff6z/lH++f6E/lj/Ev90///+0/6E/r3+Pv5R/uP9Tv72/Yf+Ev6E/i/+
s/47/m7+/P0P/tP93P2U/ZT9l/3j/cn9rf2k/db9jf3v/a39Ev7//S/+Jf4M/jX+
//0Z/uD92f0J/sb9bv5u/hz/4P4v/8r+4P7D/qD+gf6U/oT+aP5R/rr+sP7//tP+
7P7T/sD+e/4v/hL+Nf7j/VH+L/57/kv+K/4f/jj+7/04/gb+Nf7W/eb9//3Z/Rn+
0/2z/XH9Tv04/Qn9fv1F/f/9wP0G/hX+L/7//f/9vf0J/qr9Gf69/Qb+0/23/jv+
HP+k/un+rf7z/qD+A/+3/iz/6f7Q/qf+l/5L/oT+Qv6B/nf+Nf4f/kj+7P17/iL+
Vf4Z/jj+4/29/Xr9+f2E/Qn+iv04/tP9Tv7//dz9yf0+/s39cf4i/m7+dP5O/h/+
fv44/j7+Nf4r/uz9S/4l/n7+aP7T/or+vf6K/p3+WP5F/vb9K/7m/VX+Iv5L/v/9
S/4S/jv+O/5x/ij+Jf7g/TL+5v0Z/qf92f2n/SX+mv0i/tb9Iv7m/f/9Cf4G/rP9
8/2z/fP98/3v/c39Qv5I/gz+0/1b/jj+oP6n/n7+Mv5C/jj+d/5e/nv+Rf5R/i/+
Qv4v/pr+Xv6k/nf+sP6B/vn+oP5+/kL+Rf7v/ar+Yf7K/pf+l/5h/qf+bv7G/nf+
ZP4f/jv+/P1+/o7+qv5V/kv+2f2z/lv+8/6t/r3+t/6q/or+3f50/n7+WP50/l7+
0P6n/gz/p/4c/8D+1v6K/pf+aP5k/kX+wP6E/s3+Tv6B/kj+uv5x/t3+sP6n/sr+
l/6R/nf+Bv4f/sb9lP1e/ar9Xv1C/u/9/P3J/TL+mv0v/vb9Ff4P/v/9vf3J/Zf9
w/26/eD9wP38/dz9Nf7m/cn9sP0P/rb9Gf4i/rb9zf2w/Zr9oP2B/af9a/1k/R/9
bv38/H79Pv2k/WT9Yf1U/dn9rf26/cn9W/0S/a39bv3c/dP9Bv7c/fP9yf1O/u/9
Yf7//RL++f0r/g/+W/7Z/Q/+0/1x/g/+d/44/vz+SP7//q3+p/6U/l7+cf4v/hn+
iv5C/mj+O/4f/un9/P3m/VH+DP6R/hX+Jf4V/mT+KP5V/mT+S/4f/uz9tv0o/rr9
Vf5R/l7+Uf6O/mH+wP6k/uD+hP6t/m7+Yf5F/mH+O/5x/nf+p/5R/l7+L/7D/rP+
Nf/j/jj+cf4v/hL+a/4c/nf+H/4G/ub9S/7j/TX+sP3J/Wf9rf1U/Z39iv2n/aD9
rf2R/c39p/2d/Z39gf1x/fn90P01/uD9ZP7Z/R/+K/5V/hL+d/5I/kv+Ff5+/ij+
ZP7J/R/+7/10/k7+SP5C/jv+3P10/jX+aP4+/i/+1v38/eb9iv41/mv+//0y/gn+
cf4r/lH+Bv4v/rP9/P2n/SX+Bv4i/tP9w/3G/Rn+4/3W/X79vf2R/Qz+1v0y/tb9
Pv7m/V7+Iv6B/kj+Mv7m/Qn+0/01/tb9Uf7m/RL++f07/jX+Nf4S/kL+Ff53/g/+
a/4l/gb+p/2q/Vj9iv1b/Yr9WP2a/Yf93P2g/en91v3D/c394/3c/eb97P2z/bb9
qv3Q/en93P3m/dn9DP7j/SX+Ff5L/u/9DP62/TX+7P0i/rb96f2k/fP9vf0V/uP9
//3W/Tj+4/0r/kv+Mv5L/pT+W/5V/jL+O/4V/v/94/1x/lX+hP5b/lX+Pv44/g/+
Nf5I/kv+Jf4f/hn+oP5o/qD+e/5Y/j7+Rf4Z/lj+Vf57/nH+Vf4o/nf+cf44/k7+
//3p/Qb+3P0v/vz9Jf4v/nT+H/7m/dD9oP26/dD9tv3J/Yr9/P3W/eD9l/3Q/bD9
Bv7v/cn91v3D/en9//3j/TX+Av7//SL+Gf4v/g/+8/0+/un9Bv7W/RL+wP32/dz9
+f0C/lX+Vf4y/g/++f3j/TX+//1L/ij+0/0C/vn90/1e/vz9Uf4i/gb+0P0i/u/9
Nf4V/tP92f3G/RL+Qv7p/S/+4/0y/gL+S/5L/uD94/0v/vb9Jf4r/iL+Ff4Z/rb9
+f3D/Wv+Mv5x/iL+WP5Y/nv+Iv5I/jj+Vf4r/jX+6f0c/tP9Mv7T/X7+e/5r/iX+
/P3m/RL+0P3z/cP9wP3G/cD9kf2t/ZT90P2a/Yf9Pv2K/Yf9nf16/Y39rf2N/Vj9
WP04/Xf9Iv2d/ZH9pP2d/dn9jf3Z/af9uv3v/Vv9nf1k/Wf9uv2z/c392f2H/aD9
w/2k/bP9qv07/WH9d/10/WT9d/1n/VT9l/1Y/YH9l/2g/Y39Nf1I/aD9dP29/ZT9
qv1b/U79KP07/ez8Rf04/Y39lP0v/sD9//3s/ez9iv3//dP9uv26/bD9ev07/rb9
bv4J/jL+6f3g/dz9OP4M/lj+Nf4l/gn+7P3G/br90P38/dz94P3D/br9wP3//e/9
gf2E/XH9W/16/WT9SP0M/Wf9bv1h/T79cf0c/VT9H/1x/Rz9dP13/Yr9Xv2t/V79
lP1I/W79a/3N/ar96f22/en93P3m/cn9sP2N/Y39iv3g/eP9Qv44/gL+xv26/Z39
2f3j/fn93P2n/VT9p/1e/bb9lP1e/UX9ZP1R/dz9vf3g/cD94/1+/ar9fv2a/ar9
zf3T/eP90P3c/cn93P3//SL+HP4S/vb98/32/Sj+DP6R/nT+jv5C/hz+sP01/g/+
hP5r/nf+S/5k/j7+Pv4i/gb+0/2n/aT9vf2U/UX+7P0C/v/9KP7Q/dz9kf2R/VT9
4P04/Sv+mv0o/rr9yf3A/db9lP3v/ar9Ff7//TL+tv3W/af9Av6q/dP9a/2k/Vj9
3P1k/aT9a/2z/Tj9WP0Y/Qz93/yE/SX9jf2R/Yf9Nf0o/db8S/0J/Tv9Ff38/L38
DP3W/Ej9Av0P/fb8Rf0c/Yf9iv3W/ZT9lP2K/XH9dP3g/WT9ZP01/YT9ZP3D/VT9
zf2d/eP9fv1V/hX+bv4J/uz9uv3G/af9yf2K/fz9p/0C/rb94/0C/vP9Av4S/u/9
0/22/Zr9d/16/X793P2X/eD9a/1n/V792f2R/V7+Mv78/eP9sP29/bb9vf2K/X79
nf13/f/90P0l/vP9wP2k/fz97/1F/mT+KP4v/h/+/P0f/v/9vf2k/ez96f3g/eb9
DP4M/uD9oP3s/a394P2w/YT9jf2a/WT9nf1k/af9Qf13/UX9tv2H/VT9HP1F/VT9
sP22/Z39qv1Y/fn8rf1+/R/+7P3Q/bb9xv2B/UL+/P0o/jv+a/5e/nv+Bv7//ez9
HP7T/Yf+Pv6H/k7+Uf4l/nH+Nf4J/tb9Nf4i/j7+Cf4+/h/+d/5V/kv+KP4Z/ij+
aP4y/jX+Gf5R/vn9Vf5V/m7+Ff4Z/vP9KP7j/fz9//3z/c39Iv78/SL++f01/vz9
H/4c/iv+Nf41/iL+WP4c/of+dP4y/ij+Gf7A/Uv+zf10/jX+a/4y/jX+7P2E/j7+
d/4f/tP9VP3c/Vv90P16/dn90/3A/aT9oP1x/c39cf0C/qf9w/1h/Zf9ZP3T/aD9
8/3A/Rn+4/35/dP9Vf7//WT+Cf57/jL+bv5Y/p3+l/6q/or+aP7z/S/+2f0Z/tD9
8/0S/vz9//1O/hn+SP7T/fz9wP1k/hL+ZP4r/gL+Bv5Y/tP9OP7//e/9w/0o/uP9
O/47/i/+D/4o/v/9jv53/pr+dP6O/lv+h/6R/oH+Rf5C/gb+//3s/Wv+Mv5+/v/9
HP78/W7+Nf50/mv+HP4V/s39sP3j/fb9DP6z/R/+pP0f/tD9DP7Q/fz9yf32/eP9
uv10/V79Tv2t/W79/P3A/fz9yf3c/cn9K/7T/TL+K/4M/uD9Iv62/SX+Cf7T/bb9
7/3T/Vv+Iv5h/lj+H/4S/uz9vf2w/Yr9qv1h/cb9jf0c/ub9+f3N/SL+xv0i/gz+
+f22/fP9w/0r/jv+5v3g/cP9nf0S/sn9Nf66/Tv+Bv6z/mj+5v6X/qT+Yf63/nf+
1v6k/rP+d/6t/lH+pP6E/tb+e/5L/lH+a/5r/pH+Xv4r/kL+K/78/TX+1v07/v/9
O/7N/RX+3P0o/hX+Ff4V/gz+4P0P/g/+Av7z/fn9vf0l/gL+H/7g/Rn+9v2O/jv+
bv7//UL+8/1I/u/9Xv4f/mj+Rf5r/kj+oP6B/j7+8/07/ub9W/4C/j7+H/4l/rb9
OP7z/R/+2f1b/tD9DP7j/Vj+Bv4S/s39xv2N/db9kf2H/XT9hP1I/Zf9dP2N/af9
3P2t/aT9cf2q/ZT93P3A/en9dP0Z/tD9Vf7N/T7+//1k/vn9S/4C/g/+w/01/un9
e/5C/o7+Uf6t/kX+d/5h/lv+Cf6O/ij+d/5I/l7+Ff4Z/tn9K/5I/jj+5v07/vz9
HP4V/pf+ZP6B/lj+Iv7G/Qn+h/0l/uP9aP4f/kv++f2B/vz9p/5C/q3+Nf7A/mv+
0/5u/sD+nf6w/m7+t/5V/nT+Ff5+/mj+9v53/ub+pP6O/kL+nf47/kX+OP5b/gz+
Yf41/g/+w/0P/rb9D/7c/bb9Z/0C/m790P3W/en9vf0C/tn9mv2n/en9uv01/gn+
Cf7z/TX+xv3//a391v2K/a39W/3v/Xr9Nf7Q/QL+sP1k/uz9Jf7G/Vv9VP2w/Wf9
kf1B/XT9Rf16/XH95v2a/Qb+p/0C/pH99v3G/cP9uv3D/Yr9wP2N/eP9sP3g/bP9
OP78/SL+vf01/tP97/2n/fn9qv0+/ub9//3s/f/9oP3j/cn96f3Z/S/+8/3//fP9
S/7z/WT+//2K/j7+mv6g/rr+ZP69/or+pP57/o7+Uf5h/h/+e/5k/k7+Pv5L/ij+
4P6R/sr+kf6z/nf+bv4r/o7+DP53/kX+Rf5R/pT+bv6t/oH+uv6O/tn+pP7g/qD+
mv6z/lX+Iv5+/jj+dP5Y/nT+Cf5R/g/+cf4f/nf+Bv4+/hX+Cf7D/fz9pP3p/aT9
KP4J/vP90/3c/db9Cf7p/db9nf3N/b391v2a/b39ev3T/V79vf2z/UX+//17/jL+
Yf5h/kj+K/7G/cP90P2a/Uv+1v13/jj+ZP5O/l7+D/6R/iv+SP7j/db9qv0y/hz+
9v3J/eb90P3T/aD91v2k/e/9zf0+/iv+KP7//fP9xv3//en94/3g/fb99v3//Zf9
//0G/gb+Bv5+/k7+l/5R/uz+l/7d/pT+vf5r/qT+W/6R/nf+p/5u/un+kf7G/nT+
uv6R/s3+pP7m/nT+Uf5I/jL+4P0i/uP9Av7J/fz95v07/un9Vf7//fz95v2t/aD9
wP3N/a39fv2z/br9K/4M/lj+//1V/sb9jv72/VH+2f32/bb9Ev7m/RL+Bv4+/iX+
S/75/Tv+Cf5o/ij+ZP4J/kv+Jf44/vn9DP7N/eP9zf32/c39//2z/T7+Av5O/hn+
/P2t/Qz++f0v/gn+HP7Q/Tv+Cf4+/v/9Uf4J/l7+Iv6d/mv+qv6E/rP+Uf63/sr+
p/6k/qD+jv6R/kX+yv6n/uz+qv6R/m7+gf5x/uP+h/6a/l7+l/44/nf+O/6E/jL+
H/7z/WH+yf1R/h/+L/5C/jL+//0P/gb+Rf7J/Rz+2f17/jj+Iv4J/gn+zf0c/jj+
a/4v/tD9//0M/gn+kf5o/nH+Rf4i/hz+a/5o/nH+Qv5k/kX+cf5R/mH+Xv4l/qT9
O/6t/Tj++f0G/sn94/3W/UX+6f1L/hz+8/3W/Uv+DP4+/tn9Jf62/fz90P1k/uP9
e/4G/pr+Mv6k/k7+e/44/mj+Mv5Y/iX+O/4G/kL++f2B/jv+1v5I/sP+kf7D/pT+
6f6K/qf+oP6H/i/+bv4c/qT+Pv7K/lj+0/5u/p3+jv5k/kj+xv5O/tb+l/6O/k7+
bv5R/qf+kf72/t3+sP6n/uP+yv4M/7D+1v6R/rD+Uf7W/qT+0/6n/sD+t/7N/pr+
5v6d/mj+aP5e/lH+h/5R/pH+Xv5u/kL+a/5u/mH+e/4+/jv+Jf7//Rn+DP4S/uz9
nf04/cD9qv32/ZT9d/2z/bP9kf22/Xf9lP10/c39jf3Q/bD9mv16/c39sP0P/uP9
Uf4P/l7+/P1C/gb+Nf72/QL+5v3//f/9Uf4C/o7+W/5I/h/+Yf4y/lX+HP5C/v/9
WP4r/h/+Ff4V/tn9Nf4P/jL+Gf4+/gn+Tv44/n7+W/4l/iL+Ff7//VH+aP6z/mH+
nf5V/pT+fv7m/qT+xv6t/h//4P4o/zL///4J/wn/4/4v/8r+LP8c/xX/A/8l/wn/
Rf/Z/g//vf6z/nT+8/6K/sP+zf7T/pf+l/5e/qf+qv5u/vz9Jf7s/SL+Av4i/tb9
Jf4M/hX+K/4M/tn9L/6N/QL+3P0i/v/9Ff7//Tj+H/41/s39Ff7A/Uj+9v2O/i/+
uv5o/oT+DP6B/jX+iv41/nf+//07/kL+Tv4+/vn90/2w/XT9Mv4C/h/+4/0S/vP9
aP5o/oT+WP5u/gL+WP4C/n7+Nf4G/tn9KP7D/WH+Gf5F/lj+dP4S/rf+kf6X/pT+
e/4o/kj+K/5k/kL+Qv4l/kL+Tv5O/lj+e/57/rf+h/5+/n7+Xv4l/jL+KP50/qD+
1v6H/mH+d/6a/of+xv6q/sr+t/6n/l7+wP5e/qf+s/66/nv+jv6X/qr+l/6d/pT+
mv6O/kj+O/5b/lX+Xv5F/l7+Yf6q/nT+2f6k/r3+gf4f/9b+uv5k/oT+W/5r/lX+
Vf7//ar+S/6E/pH+xv53/r3+hP7G/or+qv57/iv+6f0J/uP9Uf75/Uj+L/4v/uz9
Xv5F/n7+ZP5r/k7+jv6O/sr+gf6O/jL+uv5V/un+yv4Z/+P+//69/ub+iv78/tD+
A/8f///+Ff9O/w//Ev/d/vP+l/7g/pf+yv6U/o7+ZP6d/pH+e/6H/qr+e/6g/mv+
pP5I/pH+S/5O/vn9SP4S/lX+Jf5L/vb9hP5e/qf+h/6O/nT+hP5Y/of+mv53/nv+
uv6d/rP+nf6t/pT+8P6t/tn+t/7Z/rD+0/6O/rP+lP7W/rr+kf4r/qD+Yf7G/sb+
rf6B/l7+K/6B/lj+SP44/iv+DP5L/gn+bv53/sD+jv7j/lj+w/6E/vn+zf7g/tn+
wP7A/g//vf4P/+b+LP8Z/3v/KP9r/xL/cf9F/37/Mv9Y/+D+//7p/ij/8/4D/wn/
L/8v/2H/Tv9V/y//Gf+6/qf+e/6O/sb+qv66/rr+qv4P/+D+S//j/gb/8/4v/3H/
KP8f/6f+8/69/s3+a/8y/x//Iv84/xz/eP+K/3v/hP8c/xn/5v7//hL/Qv8G/1X/
5v4Z///+/P63/n7+gf6R/pf+sP7s/qr+Ev+6/pr+kf47/lH+Tv44/jL+S/4+/gb+
9v3z/Q/+zf0l/u/9gf4P/lj+Qv6E/kv+Uf4r/hn+8/2H/jv+mv6X/sr+qv7Q/qD+
4P6d/hz/5v4v/93+Gf/2/ub+2f7g/tb+8/6n/tD+hP6d/kj+5v6K/tP+4P6O/q3+
lP6E/tP+t/6w/rD+dP5e/nf+gf6n/or+8P6a/tP+oP41/93+DP+U/gP/w/4c/+b+
yv7G/sb+w/7Z/tb+D////mj/Tv/g/un+//7p/g//3f7T/s3+Ev/d/un+8P6t/sb+
wP6H/qf+qv5C/iL+d/4l/mv+Xv5b/lj+Xv5L/pH+Pv6U/pH+bv57/p3+dP5h/j7+
HP5C/ij+L/6g/l7+d/5L/nv+a/6O/qD+e/4+/j7+4P04/gn+Uf5L/kL+Mv4o/jv+
SP5o/jv+OP7c/fb9Mv41/sb+p/6a/qT+nf50/qf+pP5r/mj+iv5e/tD+h/6z/nf+
pP5e/rr+l/4P/9n+Qv8D/0j/KP8i/+P+6f6k/r3+iv7d/rf+LP8D/0L/A/8P/yz/
//4l///+Cf///uP+8P69/s3+kf5e/pT+lP6q/sD+4/6w/rf+sP63/sb+2f72/rD+
0/6R/rf+lP7K/qf+0/7G/hX/zf4c/93+yv7D/gz/5v78/tb+t/6g/rr+lP66/pf+
6f6k/qf+e/7D/nT+uv6a/pH+a/6R/j7+iv57/lj+DP53/iv+Xv47/hz+K/4+/gn+
SP44/jv+Vf5F/lv+Nf5V/kj+H/5O/k7+OP4V/lv+Jf5u/kX+W/5u/uP+kf6z/nH+
d/5r/sP+oP6B/nH+ZP50/pf+jv4P/w//L//d/vP+qv7//hX/OP8f/xX/DP8P/wb/
A////v/+7P4V/9b+8P4D//P+5v5h/0X/Cf9I/7P+0/7s/sP+Rf9I/yX/2f4V/yX/
iv+H/07/O/8y/xL/8/75/lj///5I/yj/LP///gP/Cf8V/zX/9v7G/rf+l/50/qD+
cf4+/qT+jv6E/of+cf5b/pH+Yf57/kv+a/4y/mT+2f0l/kL+O/5k/mT+Mv4C/ub9
1v35/Sj+Nf4o/gz+Gf78/Q/+Bv7//fz9/P3Q/Rz+Av5b/jX+Vf5R/pH+Xv63/mH+
qv6E/lX+Vf6X/lX+SP4v/iv+Nf66/n7+Rf4f/lH+e/6k/qr+Vf72/Yf+L/6E/nT+
d/5r/oT+Pv7D/sD++f7D/pf+t/6H/o7+D//j/vD+2f75/v/+5v7p/gP/yv7Z/rP+
Cf/m/hL/P/9C/1L/8P4P/yX/9v72/hX/s/6K/un++f6k/t3+cf6E/qf+p/6O/p3+
e/53/mj+ZP6H/jv+cf5+/h/+Cf4y/sP9Mv4S/jX+Pv4+/jX+W/4v/lX+WP4P/gb+
S/7W/Tj+DP50/lj+dP5O/j7+L/4f/v/9Cf4C/mv+a/5+/jv+bv5C/k7+Ff5R/gn+
Nf5F/n7+SP4f/ij+O/7m/fz9+f0P/iX+bv47/kX+iv6X/pf+KP4S/gz+7/1C/iL+
SP4C/lX+Xv6g/rf+WP/5/vP+4/6a/qT+0/6n/tP+qv6d/or+vf6K/i//Ev8y/yX/
Qv9C/yz/5v6a/s3+uv7W/sP+nf5u/oH+yv5r/iz/wP4J/7P+sP6E/pH+O/5x/i/+
SP4V/oT+Uf53/lv+h/6U/nH+l/7j/rr+yv7A/nT+Yf6R/m7+zf7K/vz+w/7s/qr+
KP8//07/+f78/sP+uv7W/vz+8P7W/tb+3f63/tD+3f63/tb+zf6g/iL/zf4D/9D+
fv5O/lj+Uf5I/vz9HP7m/Wj+OP6k/kL+WP5O/iX+H/5Y/lv+WP44/pr+iv6g/mv+
h/5O/r3+jv7N/n7+zf6a/gz/p/7G/sb+qv5+/tb+h/6a/nv+s/6t/qr+l/66/qT+
l/5o/k7+dP53/i/+HP4J/gz+9v1F/hL+Rf4Z/pH+Tv4+/gL+Rf4f/nf+Bv5L/hn+
Iv4Z/kj+K/6B/n7+Pv47/nH+Ev5C/lX+iv6B/j7+7/0S/gL+W/5o/or+WP6U/n7+
fv5F/lv+L/4v/jv+KP4i/kv+Cf7Z/SX+ZP44/nv+ZP4i/jv+aP5o/l7+Xv5r/hn+
SP7z/U7+Av4y/vP97P29/Qn+wP1u/j7+gf5C/mv+H/5F/iL+S/4G/mH+K/5O/hz+
K/7j/S/+8/1C/jL+fv5k/mj+KP5R/ij+a/41/gz+Ev7c/eb9H/4J/j7+H/5e/lX+
nf6B/jL+Jf4J/sD9D/4J/uz9Cf4l/vb9Uf4r/nH+Tv6K/mT+Vf5o/pT+W/6a/nv+
hP5I/mH+/P2O/lX+fv4y/o7+KP6O/n7+oP53/or+aP6k/m7+fv4v/jj+Gf50/lv+
oP5k/qT+gf6B/jj+a/5F/iL+H/5L/ub9Xv5V/lH+D/4J/vz9H/7s/VH+Mv4y/hL+
W/4c/o7+Xv57/kL+Qv4J/of+Mv7g/p3+mv50/pT+Rf5b/mj+yv66/ub+Xv6K/jv+
pP5h/nH+SP4+/hn+Xv5V/rr+gf6d/mv+kf5b/qD+K/41/h/+aP5I/kL+H/4l/gn+
jv4i/qf+e/5+/jv+oP5R/mv+Iv5x/hn+Rf4y/mj+Tv5b/iv+d/5F/o7+cf7Z/p3+
gf5h/lv+HP4o/g/+7P2w/fz9KP5F/ij+S/7//XT+Rf5V/oH+WP5R/tD9tv3W/Zr9
+f3J/en91v0S/uP9Nf4r/j7+Bv7v/Qb+KP4C/jX+5v1Y/hL+Rf7//X7+K/6w/lX+
qv5r/kj+d/6E/hz+Nf4i/jv+K/4c/tb9S/4G/lX+L/5I/jv+Pv72/fP9zf0G/sn9
2f3v/eP9sP0V/gn+6f3s/cP94P04/vn9Vf4l/kL+HP5h/jj+SP4S/lj+6f07/jj+
OP44/lX+K/6B/kj+hP6K/oT+O/6t/of+nf6k/rf+p/6k/pr+Yf6B/nH+a/69/s3+
iv53/lH+Uf5I/mT+a/6K/k7+W/5r/pf+W/5I/jv+Av4v/g/+yf3T/cb97/0f/iL+
L/4i/hL+0P1C/vz9d/4i/kX+Rf5L/hL+S/75/Sv+Mv4y/iX+h/5o/qf+Yf5F/mj+
Mv4o/tn96f2t/eD9rf2R/dz9rf3m/br92f3Z/Tv+Ff4S/rb9xv2n/VH9Xv1F/SL9
jf1I/cP9mv1e/hL+aP47/hX+Gf7N/cD9vf16/a39jf22/Xr9Gf7//RX+7/01/vP9
Uf5b/or+Tv7D/bD9pP1x/eD9pP3g/a39Ev72/Vj+SP6O/lj+bv47/jX+Mv4P/tn9
Jf78/Sv+Vf5h/nf+WP4+/mH+KP6B/nH+fv4+/gz+D/5r/lj+mv5+/p3+a/6g/nT+
8/6H/vP+wP7s/t3+Mv8G/2X/Ff8M/8b++f6d/uP+4/7A/m7+Iv+k/m7//P5V///+
8P6z/tn+jv7N/oT+mv47/of+KP4y/h/+Xv5r/qf+cf5k/kX+oP5x/k7+S/5k/k7+
Vf5C/jX+Gf7T/v/+s/7j/pr+mv5x/lv+O/4i/gb+//3c/aT9Tv5I/kX+OP4c/gn+
Ff7Z/bD9l/1r/UX9h/1I/a39tv3A/br9uv2U/U7+Bv47/j7++f3//fz96f0v/kv+
Rf7z/UL+Gf5h/pf+s/6R/of+lP7K/tb+t/6R/nf+dP6E/kL+O/5e/iX+K/5O/kj+
lP5+/pf+cf63/qf+0P7Q/of+lP4Z/ij+W/5h/qD+Uf6H/qD+7P7g/jL/KP8P/wP/
8P7Q/tD+yv63/oT+ZP6a/l7+gf7D/qD+sP6a/qT+sP5e/rr+gf50/ij+7P3T/ez9
K/47/l7+WP7N/qT+fv6k/hL+Cf4f/kX+O/5u/i/+O/7v/dn9w/3T/Z390/3g/dn9
6f0C/tb92f16/b39hP1x/Yf9dP1x/Vj9l/2E/cn9wP3D/dP9w/29/db9yf2n/cP9
qv2z/a39pP3D/eD92f3Z/dD97P1V/kX+8/3z/dn9/P0r/kX+8/0P/gL+2f0i/uz9
KP4M/jX+W/4o/jj+Ev78/SL+L/7z/RX+Gf7z/UX+Nf41/jX+Iv4c/m7+KP4l/ij+
e/4o/mv+Vf4P/iL+D/47/oT+W/6H/tn+dP6k/or+WP5b/jj+Ev5R/un9HP44/k7+
d/57/nH+Yf6O/qD+l/6n/mj+Yf5h/kL+SP5o/v/9D/4i/hL+3P3N/Sj+1v1V/jX+
Xv50/ij+9v3m/cD9KP4M/gn+5v0v/tP9H/4G/gn+DP5F/jX+D/7j/Wj+Vf5V/k7+
HP4C/vP9//07/vP9KP4V/gb+Cf5O/iX+WP4Z/mv+SP4y/kv+O/44/of+OP5F/j7+
Xv5x/nf+Uf5k/lH+aP5+/lX+SP5b/i/+WP4P/jX+Iv6U/j7+kf53/o7+cf6a/pT+
a/5e/oH+Yf6U/p3+nf5u/tP+w/44//b+4P7N/kv//P4S/9D+qv7N/qT+nf6B/nT+
yv63/uP+0/7A/rr+qv7z/vb+6f7N/uD+wP7T/pH+w/7Z/rP+4P6k/pH+0P7G/vz+
4/4l/83+9v7D/tD+w/69/sr+rf5k/nT+dP6B/tP+1v72/rP+lP50/pT+d/6w/nv+
a/5O/qr+dP6t/n7+aP5x/n7+bv5b/j7+aP4M/nv+SP50/oT+jv5R/kj+L/5L/hX+
Xv57/pf+p/63/p3+w/6n/o7+mv6K/lH+cf5R/qr+t/72/qD+7P7w/g//2f7s/qf+
wP7d/vn+mv7z/qT+pP6X/rP+dP6k/oH+t/6X/t3+8P7A/sb+qv6U/sD+zf7D/r3+
rf6H/or+oP6q/s3+vf7s/oT+qv6z/rD+9v7W/t3+yv7K/r3+HP/D/gz/7P6n/nv+
p/5r/oT+jv5u/kv+cf5F/nH+Vf6H/nf+h/5u/nv+Rf5+/jL+KP44/j7+L/41/hz+
SP41/lX+Tv6R/mj+hP6H/k7+S/53/ij+s/5k/o7+Mv5+/s39O/7//TL+6f0r/hL+
a/5C/mv+bv6a/oT+hP5R/kX+WP50/j7+S/5C/lH+Ev6w/jv+d/5k/tP+dP69/nf+
4P5k/nT+Iv5L/iv+Tv4l/lH+Qv57/hz+lP5r/rD+d/6U/or+W/47/lj+WP6X/of+
Cf7z/Uv+Ff69/o7+zf6q/gn/0P7s/qr+4P6U/p3+bv5h/kX+W/5C/oH+iv63/pT+
sP5e/pH+oP6O/mT+d/5r/qD+Xv6B/kX+d/4l/pT+Mv6g/qD+wP57/hX/oP7A/pH+
ZP5o/nf+Pv5V/jj+Tv53/of+Gf5+/oH+Pv4S/mH+Nf53/hn+Iv7//dP96f3z/fb9
Bv78/R/+/P0v/vb9cf5O/lH+Iv53/mv+kf6H/of+Xv6B/pH+8/6t/vz+3f6R/mT+
rf6E/pH+aP6n/oT+OP4y/or+Pv72/qf+w/6t/rP+wP7w/uD+uv6O/tb+iv4D/+D+
8P7D/r3+wP7w/pH+Ev+n/gP/jv4V/7f+/P6a/tD+w/7D/pf++f6t/tP+5v7Q/qr+
0P66/r3+wP63/rP+oP6O/rf+ZP6O/n7+WP4o/j7+Ev4y/vb9h/4r/qf+Xv5o/ij+
Vf5F/iL+Rf5k/vn98/26/Tj+Jf5Y/mj+l/5V/qr+OP6d/o7+h/6O/or+e/7T/pr+
mv5R/rD+Vf6B/mv+lP6O/o7+Xv5Y/kj+W/50/mT+ZP5b/kj+dP5L/m7+W/5u/lv+
bv53/q3+zf7p/pT+0P6t/iX/6f41/9n+/P4G/yL/Ev8Z//b+Iv8D/w//1v4c/xz/
Nf8D/yX/9v75/hX/0/7j/sD+w/7W/qT+8/6d/qf+pP7G/nH+w/6w/iX///7Z/tP+
wP7G/tb+l/6k/of+t/6B/s3+lP6a/pH+nf6w/pr+bv6O/kv+bv4r/mj+Bv6q/kL+
xv57/rP+a/4G/8D+wP6X/pH+SP6U/ij+dP5F/tb+ZP72/o7+8/7D/uP+3f63/qr+
wP6a/rD+h/63/nv+l/6t/tP+sP7K/pf+6f7D/qD+zf6B/k7+hP5u/o7+WP7p/rr+
/P78/kj/8P41/7r+/P7d/vz+0/63/oH+2f6g/vb+rf47/93+5v6n/iX/8P4f//b+
0/6K/q3+h/6g/mv+pP5x/n7+jv7A/s3+4/6z/gz/qv7N/nv+t/5O/or+jv6k/mH+
bv5h/qD+bv6k/k7+qv5x/uz+pP6w/qr+Iv5L/gn+Av7v/fn94P2t/e/98/0M/vn9
Rf7m/Vj+WP6O/q3+Xv4+/mj+HP5I/l7+Tv75/WH+OP6H/kL+jv5C/nH+H/5V/kL+
Iv4+/hn+6f35/af97/38/Uv+H/5I/kj+KP7z/fb94/0Z/un9KP5Y/oH+uv63/qf+
Cf84///+4P6E/or+Tv5O/nT+h/4v/n7+S/5O/t3+8P66/r3+xv63/rP+xv6X/rD+
1v7N/rP+d/6g/pr+3f6R/pr+pP7T/qD++f7N/vD+3f7j/vD+Cf/d/t3+iv6n/mH+
6f66/s3+oP6U/lj+sP6a/sP+1v7m/sb+HP+w/vP+Iv/w/uP+mv5Y/r3+rf7W/nv+
0/7G/sD+0/4D/83+1v63/tD+mv7G/sb+s/6B/oH+e/6U/n7+jv5k/mj+aP53/mT+
xv63/p3+jv5L/kL+d/5C/n7+S/7G/sr+w/7A/sb+w/6g/o7+ZP5h/nT+cf66/pH+
mv6t/qf+mv6t/pT+qv57/i//2f7w/q3+4/69/vz+8/7z/tD+zf6z/gb/Ff8V/yL/
Nf/5/gP/yv4Z/wb/OP8//2v/W/+q/0X/e/90/37/Jf+O/w//iv9o/6r/lP9+/4H/
fv+X/5H/fv+q/2H/p/84/1v/OP8//zX/Ev8o/z//A//W/vD+OP/Q/jL/9v7w/vP+
5v6U/t3+p/6z/q3+iv6O/r3+iv7K/sb+5v7K/gb/0P7m/pf+8P7T/sr+jv78/sD+
0P6U/sb+rf6q/s3+LP8S/0j/Iv8P//P+vf7D/rP+S/5h/lj+h/47/or+a/7A/mH+
a/5e/lj+OP7m/fP9Iv7T/S/+KP7z/en9H/7W/VH+KP6R/lj+L/4M/m7+HP6B/or+
hP6O/or+dP7T/r3+A//Z/uP+nf7T/rD+6f7W/hX/2f7G/tP+zf4J/wP/2f4V//D+
6f7W/vP+nf4D/7P+wP6t/vz+yv4M/wn/4P7d/un+0/7K/rr+h/6R/g//oP4f/xn/
5v7z/vz+wP7s/s3+t/6X/s3+3f7A/tb+s/7D/vn+9v7p/uD+4/7//sr+7P7Z/tb+
vf7d/gP/2f7Z/tb+8/7s/vD+Bv/Q/vD+p/6a/qT+ZP6E/pH+nf6R/kj+aP6O/oH+
sP4J/6r+uv6B/o7+Nf5+/lv+Uf4v/oH+Vf5Y/p3+rf6n/un+0P6H/sr+t/6O/p3+
kf6K/of+t/7d/rf+5v7d/qf+zf7K/sP+2f66/kX+ZP6E/mj+pP6U/lj+h/6g/lj+
hP5+/pT+e/50/mj+cf53/mH+Vf5r/pr+rf7d/uD+zf7W/vb+yv7g/nT+fv6R/l7+
hP6a/uD+uv4v/wz/Ev///jL/L/9F/0v/LP/p/vn+3f4f/yL/1v7D/uD+8/4P/wb/
KP8G//b+Bv8c/+n+DP/j/gb/+f7A/sb+xv6q/qT+oP5R/nH+yv6w/hn/Cf8l/wP/
8/7z/gb/qv6R/r3+iv50/s3+0P6a/vn+5v4s//D+Ff8D/yj/L/8s/9P+vf4M/93+
hP6O/q3+l/4G/9b+6f7s/gP/Cf///vz+4P7D/n7+qv50/rr+rf66/rD+t/6X/p3+
rf6w/pT+p/7Q/n7+0P6g/tn+qv6d/mT+sP7A/qD+w/7K/vn+Bv/s/sr+s/7D/tn+
uv53/pr+mv6d/nT+xv66/sD+fv6w/qr+bv50/nv+O/7K/pH+cf6K/rf+l/63/rr+
0P7W/q3+t/6z/pH+2f7z/t3+sP6H/or+l/7s/uD+wP75/qf+Cf/W/lL/L/8i/wz/
L/8G/x//H/8G/9n+L//8/vz+D//z/vD+vf66/uz+rf7m/tn+//7Z/t3+s/7N/uP+
lP63/or+d/6O/rr+oP6n/m7+bv50/pf+hP5k/nT+kf6k/o7+xv6X/pf+cf5x/oH+
bv5R/oT+Uf6K/lv+wP6X/tb+mv63/sb+4/7d/uz+A/8D/7D+rf5+/rD+xv6n/sD+
kf5+/t3+t/6q/pr+aP5x/l7+d/5O/n7+W/6U/kX+Iv47/jj+e/5h/mj+a/6w/pr+
qv7A/qf+oP6t/pT+lP6U/mH+hP5o/nT+mv6t/pT+nf6E/or+0P4M/0v/Mv8i//D+
uv6z/sD+0P7Z/tb+7P4c/wz/2f4V/0v/HP8Z//P+Jf/2/vb+4/7s/iL/DP8D/9b+
wP6n/qD+Xv7j/s3+yv7Z/gb/A//p/sP+1v69/sb+oP63/vD+2f4i//z+D//j/sr+
8P4P/83+Ev8l/yj/O/9C//P+LP/Q/qr+sP6X/pr+pP6H/nv+nf6O/tn+0P6a/p3+
vf6X/pf+oP6q/oT+iv44/k7+W/6R/kL+WP4r/nH+aP5F/kL+kf5V/r3+iv6B/p3+
xv6O/qT+fv6H/oH+zf6n/rf+uv4i/7r+P/8J/w//Iv8c/wz/Jf8J/xL/6f7j/un+
wP6z/s3+rf7j/qf+8/7Q/lL/Jf8f//D+mv5+/q3+e/6k/pT+sP6R/s3+wP4M/xL/
Ff8M//z+Cf8V/yj/LP8f/wb/L/8v/yX/Uv9r/yz/Qv8y/2v/Nf9o/1v/hP9Y/4H/
Yf9h/yj/Uv/Z/un+HP8Z/1j/a//5/vz+6f78/gz/Mv/j/iz/+f4V/xn/L//8/vD+
8P4J/8r+LP/d/iX/7P4J/wn/P/8P/xX/4/4S/8P+Bv8M/wn/3f72/un+Ev8v/2H/
+f4M/zv/Nf/Z/hX/6f7z/vD+w/7W/sP+l/6k/nT+bv5r/rP+yv7g/tP+zf6X/oH+
lP6n/qf+d/4+/nv+hP5L/rr+pP7T/tD+zf66/g//D//w/gb/sP6d/of+jv7Q/sb+
2f7g/hL/Ff8Z//D+Gf8l/+D+/P6w/rP+DP/m/pf+rf7p/tb+Cf8M//P+yv7p/gn/
Ff8c/wz/DP90/o7+p/53/gn/w/4S/7P+O//j/vz+rf72/sD+Iv/2/jj/Ev/p/vP+
Bv/m/sb+9v4G/xL/3f7Z/hn//P5L/17/H//8/vP+Cf8f/xn/Cf/w/un+6f7j/tD+
pP6O/i//4/4G/+P+7P7N/nH+d/6K/oT+Xv5u/kj+Ff44/jL+Nf5b/lX+Cf5L/kj+
L/4c/kv+e/4r/hL+zf3T/db9w/32/e/9iv4Z/lH+Uf6q/nv+e/4P/mv+Mv5o/jj+
Yf5O/lX+lP57/m7+0P6a/qf+jv7N/m7+xv6U/qr+gf50/nf+lP6U/sP+jv6t/q3+
t/6g/rD+t/7g/tP+w/7D/uP+D/9Y/xn/vf7N/sP+7P7D/rr+p/6n/tD+p/4D/47+
rf6n/gz/oP7g/qD+w/6g/rP+jv7A/qT+zf6B/sP+l/7A/q3+uv6X/n7+fv6w/p3+
uv5x/nv+jv5b/k7+Uf5e/of+jv6a/mj+jv6X/oT+Yf4c/jv+Xv41/lv+7P0v/iL+
SP47/n7+jv6t/pH+WP5+/nH+Qv6a/mv+l/5I/rf+h/69/p3+qv6k/p3+h/7K/o7+
0P6U/sr+iv53/mv+mv6w/qf+h/7K/sD+A//W/un+iv63/p3+l/6w/q3+rf6E/nH+
nf6g/gz/Gf8Z/zL/+f5C/yX/Gf8J/yX/dP9O/3H/Rf8s//b+Mv9L/3H/Jf+n/1v/
kf+O/4H/e/9L/xz/uv7A/pT+wP6q/nH+sP7W/tP+A/81/yL///4D/8r+wP63/or+
wP6H/rr+dP6a/j7+0/6n/sP+rf6t/qD+rf6a/tn+DP+6/t3+s/69/rD+oP6k/s3+
yv7z/r3+Gf/Z/rD+pP6t/sD+2f7W/tb+jv4l/83+Jf/W/gn/4P6t/q3+w/7m/vb+
9v7Q/t3+sP7z/tD+D//s/i//DP9V/wn/OP9I/z//Gf8s/xn/9v7Z/ij/4P4D/8r+
LP8i/4H/Uv97/1v/aP9+/17/e/+E/5T/Zf9I/0L/Vf8o/9n+Qv8Z/yz/qv5O//z+
Ev8V/zj/A/8G//n+0P7g/sr+wP7K/r3++f7g/gP/LP8l//z+D//m/tb+9v7G/tD+
6f6K/vz+0P7K/vD+6f66/sr+t/7Q/qf+yv6n/rf+nf5Y/l7+Mv4i/mv+Nf5x/or+
Pv5L/iX+DP5k/mj+hP53/sD+lP57/nf+ZP53/nv+Qv53/ij+Iv47/ij+WP6R/q3+
lP5u/jX+S/5Y/mH+dP5x/mH+WP5Y/m7+cf5h/nv+a/5R/k7+O/5F/nv+Uf5e/k7+
dP5F/or+p/6a/of+pP6H/l7+fv50/qD+iv6U/s3+1v7d/pr+6f7W/tD+DP/K/sb+
yv6k/r3+nf7N/sP+xv7Z/sD+0P7N/qT+yv69/pH+fv6B/nf+l/6K/o7+dP6K/sP+
6f6t/iz/5v5b/0X/Rf9C/93+2f6t/t3+/P7T/vn+DP8y/xz/Bv8D/93+wP7d/uD+
sP6d/r3+nf7d/sD+8/7p/jL/P//W/vP+4P7d/jL/6f7K/uz+7P6w/hn/D/8D/1v/
4P4i/yz/S/9b/3j/Nf9F/+b+//7Z/vz+2f4M/73+xv7z/s3+Iv8o/1L/Iv9L/xX/
Nf8V//P+mv6z/nv++f78/s3+nf78/t3+Gf8S/1j/Qv8G/0j/e/9b/2H/gf/d/vz+
vf78/oT/Xv8v/07/5v4l/2X/O/+k/2X/Tv9Y/zX/P/8v/yX/Yf9h/2X/Tv8Z/xn/
L/9S/1L/KP9b/0L/Nf9h/+z+2f7Q/rf+Ff9L/y//Ff/m/v/+Mv8i/3H/LP8M//b+
8/4l//D+Bv/D/v/+sP4P///+4P7w/gb/kf66/tP+2f4o/w//6f6w/tn+s/7Q/uD+
1v6k/vD+t/4V/w//P/8y/0j/Gf8s/y//8P4S/+D+t/7G/rr+0P7A/qD+nf6R/tb+
3f4M/+n++f7T/t3+oP6k/hL/4/78/vP+9v4P/+b+yv7W/tD+w/7T/s3+1v7Q/vb+
yv6n/ub+4P7m/sb+6f6k/sr+2f7Q/vP+dP6R/mv+zf7Z/tb+0/7w/rr+4/6z/tn+
uv4c/73+/P7K/rf+zf63/gz/9v4S/xX/8/7p/tP+9v7D/s3+t/63/r3+uv7w/tP+
/P72/hn/wP7d/q3+4/66/sr+jv7Q/rf+jv53/nv+kf7N/rD+p/69/q3+fv6O/pf+
cf4+/t3+l/7K/rD+WP5I/kX+L/5R/iv+S/4r/uz9+f0S/vz9Jf4M/jj+2f1C/gz+
L/4r/iL+6f1r/j7+Jf4S/kv+ZP6q/mT+mv6O/oH+e/6n/nT+fv6k/tD+4/63/rP+
sP6k/tP+s/7//g//sP5o/gP/Bv8l/xX///4P/wP/zf75/sb+Ev///hL/HP8M/xL/
9v7s/gz/H/8v//b+Bv8M/zL/OP87/xX/P/8f/yz/Jf8G/xL/Gf/2/lj/L/87/1j/
Mv9I/z//Vf9C/17/Vf9b/2j/Tv9V/yj//P4c//D+4P5L/0v/Rf90/xz/OP87/yL/
8P4M/+P+Cf/5/iz/5v4c/9D+t/7w/sr+Gf/2/g//2f4V/x//O/8y/wn/5v7Q/sb+
vf7W/o7+kf7D/r3+A//z/sP+l/5L/or+cf6w/uD+/P7m/g//p/7K/oT+d/6H/pf+
ZP6t/qT++f7W/sb+8/7N/uz+wP7Q/vb+/P7m/vP++f4Z/xn//P69/sP+pP7Z/vb+
Gf8V/0L/HP9I/1v/h/+q/5T/uv+0/3j/dP+E/4H/aP97/3H/pP+d/8f/qv+E/3H/
h/97/2j/WP8v/wn/H/8i/yz/DP9e/0X/Mv9O/z//SP+R/1L/e/97/4f/Xv9Y/2v/
D/8J/93+Cf8S/2v/Ff9L/4T/bv81/1j/H/8D/wz/3f4f/9n+HP8D//P+2f7m/or+
yv6E/s3+uv6O/qD+5v78/sP+4P4G/wP/zf7p/iL/+f4V/+P+7P7Z/g//yv7m/rD+
DP/d/gb/9v4V/w//1v4l/73+oP4c/xX//P41//b+0/7z/hn/zf66/uz+s/7j/tD+
Ev8P/1L/Zf9x/5H/e/9h/17/S/97/6H/gf90/5H/lP+O/4T/e/+X/17/eP+E/3v/
x//d/37/aP8v/0X/cf9V/x//Nf94/3T/bv9Y/07/eP8o/1X/5v72/h//W/9o/3T/
Qv9V/yX/SP/w/mX/KP8S/3H/W/8Z/zL/W/9b/xn/Vf8Z/yL/Iv8o/z//LP9O/yz/
Xv9L/xz/HP8c/xX/Mv8G///+7P7//ub+Cf/m/i//Rf+w/iL/gf6d/pf+h/6X/m7+
ZP5r/rr+rf7w/uD+pP69/tn+xv4S/83+0P7A/tD+DP/w/tD+s/6a/v/+0/4f/yL/
H/8l/0L/Bv8f/yX/zf72/uz+Ev8i/xz/Cf8f/z//Jf9V/z//Yf9r/z//DP8v/xX/
Ff8P/9b+Iv8f/wP/WP9F/2X/pP9r/1v/O/9Y/4r/h/+K/2j/lP9b/5T/kf+0/6T/
AwDm/1IAFgAGAO3/9v/j//n/rf+w/6T/hP9o/0j/Xv9x/5H/Qv9b/2H/jv94/1X/
fv9x/3j/cf9Y/yL/Qv8l/xz/HP8S//b+Qv8J/2H/Qv97/37/kf9V/3v/Zf9O/w//
Tv8//1X/HP8o/wP/Ff8M/xX/D/8M//P+7P7G/sr+9v7W/hz/Cf8D//b++f7K/gP/
pP7K/qD+vf72/g//L/8y/93+7P7m/vz+4P7z/tD+7P6n/tb+Bv8s/1L/Jf8s/zX/
LP84/0j/Nf+O/5H/Mv+R/0v/mv+H/4T/l/9l/6f/kf94/4H/of+O/73/tP+t/8P/
nf+X/7T/mv9+/4H/S/9F/zj/Iv9L/1X/h/+k/73/vf8sANb/HADd/6r/sP+a/3H/
lP+U/3j/e/94/3T/kf+q/73/t/9L/6H/cf+B/0X/Gf8v/0L/Zf9O/yz/SP8c/+P+
Ev8v/yL/LP9V/0X/Xv9C/4f/a/8v/0j/4/7W/vz+5v4Z/yz/0/4J/z//O/8v//P+
Bv/z/iL/wP7w/vb+wP7N/pr+jv7A/qT+8P6t/hL/4/7p/hL/Bv8G/xn/DP9O/0L/
H/8o/x//HP8//yj/iv9e/7T/qv+R/4f/dP+R/8P/jv+K/37/eP+R/5H/hP8v/3H/
L/84/1L/KP9b/2H/SP8//0j/P/9r/17/Nf8S/yL/1v4M/w//jv9r/6H/WP+d/3T/
rf+H/3j/hP90/6T/t//D//P/uv8pABkAHwD2/wMA7f/z/7r/3f+6/9b/0P+O/3j/
Tv9l/2v/aP9V/zj/WP9V/07/Nf9L/3v/HP8S/0v/HP8s/wb/Gf/s/l7/Cf81/+P+
aP/5/l7/8P5C//z+dP9O/zj/a/9e/yj/Nf8s//z+2f5r/y//P/8P/3H/Ff9l/27/
p/+H/5H/of9C/3j/S/+E/zj/P/9O/27/OP8Z/+z+KP9r/0v/e/8i/17/kf90/6H/
bv9x/2H/a/9I/xL/Qv9r/5T/fv+a/4T/zf8SANP/4/+6/63/lP+a/27/e/+K/7f/
qv/g/47/zf/D/47/tP/K/6r/sP+a/73/Yf+B/4H/e/90/3v/e/9+/37/qv84/2v/
O/84/4H/Tv8//wP/Cf87/w//LP84/0X/KP8l/wn/DP9V/0j/Zf+E/0j/Qv9V/yL/
Nf9r/0j/Uv84/wz/aP84/yz/Mv8c//P+cf9u/zj/Ev9F///+L/8c/1X/Yf9I/0X/
dP8s/2X/SP+B/yj/Xv8y/4r/O/+O/zv/a/9o/5r/cf+t/37/aP8v/xz/Mv9l/0X/
kf9L/5H/tP+6/6f/4P+X/wYA3f+n/9P/fv+a/7f/jv8cAMD/BgC9/+3/x/8vAN3/
GQDH/8P/nf+K/5H/dP94/4T/qv9o/5H/O/9S/1j/iv9L/2j/Ff8v/y//LP9r/27/
Iv87/8b+HP8D/0X/LP8f/07/Nf9Y/3j/hP+a/6r/p/+R/6H/cf9S/07/Qv8o/xL/
Rf8f/yj/Cf8o/xn/Ev8V/9D+2f4D/8b++f7Z/vz+0/7T/sD+xv4P/93+xv4Z//b+
Jf/p/gz/7P75/sb+6f7d/kL/DP8Z/yX/e/9+/4r/cf9x/z//Nf8M/zj/Bv9x/y//
Vf81/2X/Nf9r/zX/kf9S/0j/eP+h/6T/x/+t/zj/Uv+X/2X/l/9I/6T/dP+q/6r/
tP+k/5H/aP9e/0L/Gf9S/xX/a/+h/7D/SP9C/xz/L/9h/1v/Rf81/xL/Zf8D/xX/
Ev8G/wb/L/8V/x//Rf9C/z//Tv9o/1j/LP87/wz/A//8/mH/Uv9I/2H/Cf8//yL/
aP8P/07/Jf8P//z+Cf/g/iz/P/81/y//A//w/jL/8P41/xz/2f7G/s3+0P4P/yz/
DP8c/xn/Tv9r/0X/Yf9V/yL/Ff8l/zj/Uv8v/0L/Zf9C/4T/Qv90/5f/l//T/73/
of/t/8r/qv+X/4r/Zf81/5H/a//A/9D/4//N/8P/of/g/53/0//K/6f/iv94/2X/
Vf9O/37/kf90/4r/gf94/5r/nf/H/53/iv+E/2j/hP9e/2X/of9L/7D/dP+U/6f/
mv97/53/Vf+9/27/mv81/37/OP/D/37/of9x/2X/aP+6/5T/hP9u/0j/Xv+B/0j/
h/9e/3T/Tv+w/6H/pP+B/4r/SP+X/2v/w/9r/2v/Qv9r/2X/Yf84/4r/L/+0/2j/
kf9V/6r/KP8v/xn/Ev/G/v/++f5b/y//gf9e/3j/Zf9x/0L/Ev8S/1X/iv+h/63/
gf9F/6T/p//D/4f/wP+K/6T/sP+n/zL/pP+U/63/h/+O/27/Zf9e/9D/WP/H/5r/
1v9o/6H/Mv+n/1j/x/9x/5r/of/t/wwA4//H/7D/jv+O/5f/6f+q/zIA/P8sAAkA
yv/g//b/4P9IAOD/AAAZAJEARQCUAPz/w//a//z/of/Q/4r/tP/p/+n/4P8iAKH/
0P+h/+3/wP8lAOn/of+a/17/bv+q/1X/iv9h/5f/WP+n/4T/0/+k/9P/0//W/6T/
jv+H/37/a/+n/5H/e/9S/7r/gf+t/37/Yf87/17/OP9V/yL/eP8c/27/Qv87/zL/
e/8i/zj/8P4l/9n+Mv/p/i//5v4i/wb/KP8s/7D/e/97/3T/e/9h/3H/Qv90/xn/
h/9V/4r/iv+R/2v/p/9l/5f/nf/j/5f/8P+q/5f/Xv+q/3T/5v/K/+n/2v/A/6H/
GQDD/xwAIgASAAAA
}

CLICK-SOUND: load CLICK-DATA
CLICK: does [
    wait 0
    SOUND-PORT: open sound://
    insert SOUND-PORT CLICK-SOUND
    wait SOUND-PORT
    close SOUND-PORT
]

65. Add and remove commas in numbers

These are functions used quit a bit in processing spreadsheets, where data come with, or is expected to have on output, commas for the thousands separators. One function takes them out, the other puts them in.

REBOL [
    Title: "Decomma-encomma"
]

;; [---------------------------------------------------------------------------]
;; [ These are little procedures to deal with "numbers" that are present       ]
;; [ as strings of digits separated with commas every three digits,            ]
;; [ a format that REBOL does not recognize.                                   ]
;; [ There also is a procedure to format an integer with those commas,         ]
;; [ for presentation purposes.                                                ]
;; [ Spreadsheets are evil.                                                    ]
;; [---------------------------------------------------------------------------]

DECOMMA: func [
    DC-INPUT [string!]
    /local
        DC-OUTPUT
] [
    DC-OUTPUT: to-integer replace/all copy DC-INPUT "," ""
    return DC-OUTPUT
]

ENCOMMA: func [
    EC-INPUT [integer!]
    /local
        EC-WORK
        EC-LENGTH
        EC-LEFT
        EC-123
        EC-OUTPUT
] [
    EC-WORK: copy ""
    EC-WORK: reverse to-string EC-INPUT  ;; must work from right to left
    EC-LENGTH: length? EC-WORK
    EC-LEFT: EC-LENGTH
    EC-123: 0
    EC-OUTPUT: copy ""
    foreach EC-DIGIT EC-WORK [
        append EC-OUTPUT EC-DIGIT    ;; output one digit
        EC-123: EC-123 + 1           ;; count a group of three
        EC-LEFT: EC-LEFT - 1         ;; note how many are left
        if equal? EC-123 3 [         ;; if we have emitted three digits...
            EC-123: 0
            if greater? EC-LEFT 0 [  ;; ...and there are more to emit...
                append EC-OUTPUT "," ;; ...emit a comma
            ]
        ]
    ]
    EC-OUTPUT: reverse EC-OUTPUT     ;; undo that first reverse 
    return EC-OUTPUT
]

;; -- Un-comment to test:
;X: DECOMMA "123,456,789"
;print [X " is an " type? X]
;Y: ENCOMMA 123456789
;print [Y " is a " type? Y]
;halt

66. Base fllename

This is a function that is used a lot. It does one bit of file name manipulation that seems not to have a REBOL function, and that is to take the suffix off a file name. This is useful if you want to make a new file name that is the same as an existing one but has a different suffix.

;; [---------------------------------------------------------------------------]
;; [ This is a function that accepts a file name (string or file)              ]
;; [ and picks off the extension (the dot followed by stuff) and               ]
;; [ returns everything up to the dot.                                         ]
;; [ This can be done in a one-liner, but I have trouble remembering           ]
;; [ that one line, and also had a little trouble making it work               ]
;; [ at one point, so I made this procedure that works all the time.           ]
;; [---------------------------------------------------------------------------]

GLB-BASE-FILENAME: func [
    "Returns a file name without the extension"
    INPUT-STRING [series! file!] "File name"
    /local FILE-STRING REVERSED-NAME REVERSED-BASE BASE-FILENAME
] [
    FILE-STRING: copy ""
    FILE-STRING: to-string INPUT-STRING
    REVERSED-NAME: reverse FILE-STRING
    REVERSED-BASE: copy ""
    REVERSED-BASE: next find REVERSED-NAME "."
    BASE-FILENAME: copy ""
    BASE-FILENAME: reverse REVERSED-BASE
    return BASE-FILENAME
]

67. Make a filler

This is a function used a lot in formatting fixed files, where things just line up. It returns a string that is a given number of spaces long.

;; [---------------------------------------------------------------------------]
;; [ For use in creating fixed-length lines of text (perhaps for               ]
;; [ printing), this function accepts an integer and returns a                 ]
;; [ string of blanks that many blanks long.  This filler can                  ]
;; [ be joined with other strings to space things out to a certain             ]
;; [ number of characters.  This would be useful mainly when                   ]
;; [ printing in a fixed-width font.                                           ]
;; [---------------------------------------------------------------------------]

GLB-FILLER: func [
    "Return a string of a given number of spaces"
    SPACE-COUNT [integer!]
    /local FILLER 
] [
    FILLER: copy ""
    loop SPACE-COUNT [
        append FILLER " "
    ]
    return FILLER
]

68. Pause

This is a function used in debugging a program that prints output to the console. It starts a loop of "ask" to get operator input which is assumed to be a REBOL command like "probe," and then attempts to "do what was entered.

;; [---------------------------------------------------------------------------]
;; [ This is a function that can be used to pause a program and allow          ]
;; [ commands to be entered at the pause prompt.                               ]
;; [ To use, call GLB-PAUSE with a string parameter.  The string parameter     ]
;; [ will be displayed as a prompt, and the program will wait for input.       ]
;; [ Enter any REBOL command at the prompt, and the function will try          ]
;; [ to execute it.  To display a data value, just type the word whose         ]
;; [ value you want displayed.  To continue with the program, press the        ]
;; [ "enter" key with no input.                                                ]
;; [---------------------------------------------------------------------------]

GLB-PAUSE: func [GLB-PAUSE-PROMPT /local GLB-PAUSE-INPUT][
  GLB-PAUSE-INPUT: "none"
  while ["" <> trim/lines GLB-PAUSE-INPUT][
  GLB-PAUSE-INPUT: ask join GLB-PAUSE-PROMPT " >> "
  attempt [do GLB-PAUSE-INPUT]
  ]
]

69. COBOL-like edit mask

This is a function used often in creating fixed-format reports. It takes a string to be displayed, plus an "edit mask," and returns the input string reformatted according to that mask.

;; [---------------------------------------------------------------------------]
;; [ This is a function for a COBOL-like editing of a data item                ]
;; [ with an "X" picture.                                                      ]
;; [ Call the function with a string and a mask, and the function              ]
;; [ will return a string that has the format of the mask with                 ]
;; [ any character "X" replaced by a character of the input string.            ]
;; [ For example:                                                              ]
;; [ SSN: "111223333"                                                          ]
;; [ GLB-EDIT-X SSN "XXX-XX-XXXX"                                              ]
;; [ and the result will be "111-22-3333".                                     ]
;; [ Note the line of code that compares the character from the mask to        ]
;; [ the letter X.  In REBOL, "X" is a string and #"X" is a character,         ]
;; [ and they are not the same.                                                ]
;; [---------------------------------------------------------------------------]

GLB-EDIT-X: func ["COBOL-like edit of string using mask"
    XSTRING XMASK   
    /local 
        XINPUT   ; trimmed input work area
        XINLGH   ; length of trimmed input
        XINSUB   ; subscript for trimmed input
        XOUTPUT  ; final output area, returned to caller
        XMASKLGH ; length of edit mask from caller
        XMASKSUB ; subscript for mask   
    ] [
    XINPUT: trim XSTRING
    XINLGH: length? XINPUT
    XMASKLGH: length? XMASK
    XINSUB: 1
    XMASKSUB: 1
    XOUTPUT: copy ""
    if equal? XINPUT "" [
        return XOUTPUT
    ]
    while [<= XMASKSUB XMASKLGH] [
        either (XMASK/:XMASKSUB = #"X") [  ;; potential "gotcha" 
            if (XINSUB <= XINLGH) [
                append XOUTPUT XINPUT/:XINSUB
                XINSUB: XINSUB + 1
            ]
        ] [
            append XOUTPUT XMASK/:XMASKSUB
        ]
        XMASKSUB: XMASKSUB + 1 
    ]
    return XOUTPUT 
]

70. Launcher skeleton

We make a lot of little program launchers that look a lot alike. Below is a skeleton that gets copied and modified.

REBOL [
    Title: "Support reminders"
    Purpose: {Gather some links to important resources that must be
    available without fussy searching.}
]

CENTER-PICTURE: load to-binary decompress 
64#{
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
QVaEQUuv/E+WXT638ElVtyMo5Tx3K0VEw8xAHhMbDctXI/s3kQuSDqjufKucyMK6
FGOxxr7Eg8daaxtUu9J7BKhBlJkh/kwk18gxDHjV375R0BbbVS5bLrwu1v6s4BPJ
NmcMQ3u//UWWtcbNVcjOd996V79pvXcdkbLPrdxGsnZ/ldGeungbqpDfZWnfvFWJ
5FiKc727PYn6tyT8N76y2wejTtdfPPCSZHlIt2hf6djuo6kiLl2tc7d/9WwZXXnz
JEuewKlGqyDOaZYAoZ4g6apdnahyaYGYSwdPFCd2NKuOU4dFDL8soytr9R3x6gm6
gLfRlGltdVe6creDYdairL65TXqVu968/WkeCSfqbW8RbcZBPAwDep5/mbSIdxh5
fGCVMWiDATQTejjdxKPBIso+u37a0jfpHxfYt8+8+qYa3ctUM7Nvo5TntH8g/VWc
b61NEq0tSjBocnxhM+Uij8qAc8vMrGVqvJrOJxaXskeSPqU9xRNLyU9y7fdQU9OP
j8f56DZlJ8/fv72przB84KVFYlsx15tur2SxqD1dPJCZZ0MXPW5UlyGhRWLVu6sz
9Oguch96RBIV1NF1lmmqYVfzPDBA6rOnreNghd5AQnvKtC8UHT+BpNufV3zf1sj7
6DEyU/1igXAyjrQ0j7Xy9TKsR0PQHMajzWY71PCoC9UL6QnGksblGeVDktqetvz+
9J2Cx5qK7vPlD6yQbHNFe6KKLBpwNkoqWJ5MVaLL1il7PAwTI1BtNtCYHssgO4jZ
ZNgO6JunuhW00Z2H3Mg3aDNc0K5/e7r5iac1BtimosXQlvvmnyncMh1Tvvmf00pT
zRtczSNSsevOJ9lz1X4+bHh/UHYTT1lHJi9mS3MFuW+Tuu3/heE0LUGJ54u5XbEK
7or2xjl3u+ZrnaySbmGQmiqhQ3t3ebeLmrm+rShbzSn8Gc8ZPeFjdNlqUq3luavS
RGikVSfVKqTTyxPW1Hu6Mpo6R8i4vRil36d9uWxxR/+KzSKnRtHVCyeUJVP47Thp
5w68exmmzOvke0Ts+5lX3En4XGNZTYYl0dI8H/NOrpvhzHxIiu53ldYjILhORZ7Z
MkHdVeOV6y71kiBe48m4/ERABM0ufWw+XzwG5FZvoSwN0Wy5tA7cxyP5rpdnhj7L
/XLAup14paKoTNTW1WXE4FL2+avvxeh4U9eyhH0lVGk0q0sqbeKX+JhSY2lPt3x1
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
QUk96WxNvxivrGw67jEXbmK1842Psz/qeaUbIodDdQXNo2sEk09cLpX0MpKp+Sgm
EI3G3t5+AcNZlnvq3bo3ahlylST1fOv5v3xc/XjHOLaPyH3rvnPp5P9PEckMD87a
jNfnFTlYSL9qJs+5jIha0hHu+f5yJy2oi9S3mjALHgFbdk6oqrn7Nfd1u6dXg/mU
gaGW213IbZLQ3be6gg2t+iuPxlfLJH2C/nD4hFDl6sMPPaiRiayeCcl3Kx28KeVg
f9f1pnUoEBcN6cmMiu+QI21oumFKin3VmebJ66OIo2LR/XHC6OR9asujVq0Pwqjv
a2L5Zr9KNKQgPcco2XbujaX9MrdmkUxVvz9UnT7SONB1Jk8gqS/UeK4I5MDfpGg9
+34stOSrUgguLikZ09/jqdjqW6fC6ru8IrWdNQUipSbUUvSLF1s7VuzM3/DYt90d
6tDAQowY+k/+uGhxlh8bd1Haav3hlY5xIisNI5W4wVeho5zW1wXcYwdu4ciSY7kK
SG/dXVGggVP+sF8h6K89X1PSD6ztMwuC4M9PceIoPGL+jaAz9az/yRmPnBzOOghL
L0cw0elcHq5pDMAWK2/8mHXtgA33gOiL18Zbo7W2tDGcGTTdLNkY6MsEQpSATAQl
ki54OvgtYjxbzF/mrn1xMP2x1hv3dEk2DjF2nx5pyw3SnSBcDzuQbm8g8KlUedA+
45O9472tUwLfMOyt0t2vYH7fzIWFXZWKZ4fG34RWBlt+ZwipfRlBPYJ6DDG+oe4D
InQS45l4Hcb5tdDTSNBRUjdnOyiRYo21wyVOGWUiZvhscUI4ExlksJleWwS+S5lY
uDVMeKG+YrQknZx9SZwVinmKeVOMGOz+8/5QabawMaKgY+5XuqkS7ZbYrPFnI4tI
TpKwRQLL41CWi73JeLqFj9f0135AlIzqx8JT9oXc4Kjy4DFmhI6GwgbnABEJyGRe
9qW9GX3EldmS0aHOuJurTLoRlRhUQMJd9t/hRCDksg1dvglZYrssR2r1yVDs9S0F
dbb6sV8u3DS82fuvItRgzHc7+B3gmZCEhET3bx6gdSKlvRNx5/vGoh6xddsUlS35
/RbBDybUzGzuoZFKwrncibFAm9FqYge3xfFK6KsBPIolsWSabWee1bDEPyFuLfqC
PfNtpTSjpjmd5jw6aMuF3KAJ/XuAdqYUWNDLzRUZh7sqpiXZm/4O3wy9+wNxzMc6
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
}

QUICKHELP: func [
    TXT
] [
    QH-WINDOW: layout [
        across
        banner "Quick help"
        return
        QH-TXT: info 600x480 wrap
            font [size: 14 style: 'bold]
        QH-SCROLLER: scroller 20x480 
            [scroll-para QH-TXT QH-SCROLLER]
        return
        button "Close" [hide-popup]
    ]
    QH-TXT/text: TXT
    QH-TXT/line-list: none
    QH-TXT/para/scroll/y: 0
    QH-TXT/user-data: second size-text QH-TXT
    QH-SCROLLER/data: 0
    QH-SCROLLER/redrag QH-TXT/size/y / QH-TXT/user-data
    inform QH-WINDOW
]

HELP-TEXT: {Launcher program skeleton

This program is an idea for a simple program launcher.
It is an approach that has been used many times and so
we have created this skeleton so we can do a little
copying and pasting when we want to make Yet Another
Program Launcher.

This text in the HELP-TEXT word would be replaced with
appropriate information for this instance of a launcher.

Each button has a function linked to left and right
clicking.  You would code those functions to suit your
goals. 
}

INFOTEXT: {Right-click a button for a summary of its function.}

BUTTON-01-LEFT: does [
    QUICKHELP HELP-TEXT
]
BUTTON-01-RIGHT: does [
    hide CENTER-IMAGE
    set-face CENTER-INFO {This button displays a window
of instructions about using the program.}
]

BUTTON-02-LEFT: does [
    QUIT
]
BUTTON-02-RIGHT: does [
    hide CENTER-IMAGE
    set-face CENTER-INFO {This button closes the program immediately}
]

BUTTON-03-LEFT: does [
    alert "No function for button 03"
]
BUTTON-03-RIGHT: does [
    hide CENTER-IMAGE
    set-face CENTER-INFO {No information on button 03}
]

BUTTON-04-LEFT: does [
    alert "No function for button 04"
]
BUTTON-04-RIGHT: does [
    hide CENTER-IMAGE
    set-face CENTER-INFO {No information on button 04}
]

BUTTON-05-LEFT: does [
    alert "No function for button 05"
]
BUTTON-05-RIGHT: does [    hide CENTER-IMAGE
    set-face CENTER-INFO {No information on button 05}
]

BUTTON-06-LEFT: does [
    alert "No function for button 06"
]
BUTTON-06-RIGHT: does [    hide CENTER-IMAGE
    set-face CENTER-INFO {No information on button 06}
]

BUTTON-07-LEFT: does [
    alert "No function for button 07"
]
BUTTON-07-RIGHT: does [    hide CENTER-IMAGE
    set-face CENTER-INFO {No information on button 07}
]

BUTTON-08-LEFT: does [
    alert "No function for button 08"
]
BUTTON-08-RIGHT: does [    hide CENTER-IMAGE
    set-face CENTER-INFO {No information on button 08}
]
BUTTON-09-LEFT: does [
    alert "No function for button 09"
]
BUTTON-09-RIGHT: does [    hide CENTER-IMAGE
    set-face CENTER-INFO {No information on button 09}
]

BUTTON-10-LEFT: does [
    alert "No function for button 10"
]
BUTTON-10-RIGHT: does [    hide CENTER-IMAGE
    set-face CENTER-INFO {No information on button 10}
]

BUTTON-11-LEFT: does [
    alert "No function for button 11"
]
BUTTON-11-RIGHT: does [    hide CENTER-IMAGE
    set-face CENTER-INFO {No information on button 11}
]

BUTTON-12-LEFT: does [
    alert "No function for button 12"
]
BUTTON-12-RIGHT: does [    hide CENTER-IMAGE
    set-face CENTER-INFO {No information on button 12}
]

LOCAL-STYLES: stylize [
    BIGBUTTON: button 128x128 font [size: 14]
]

MAIN-WINDOW: layout/tight [
    styles LOCAL-STYLES
    across
    space 0x0

    at 0x0 BIGBUTTON green "Quick help for this window" 
        [BUTTON-01-LEFT] [BUTTON-01-RIGHT]
    at 128x0 BIGBUTTON red "Quit" 
        [BUTTON-02-LEFT] [BUTTON-02-RIGHT]
    at 256x0 BIGBUTTON "" 
        [BUTTON-03-LEFT] [BUTTON-03-RIGHT]
    at 384x0 BIGBUTTON "" 
        [BUTTON-04-LEFT] [BUTTON-04-RIGHT]

    at 0x128 BIGBUTTON ""
        [BUTTON-05-LEFT] [BUTTON-05-RIGHT]
    at 0x256 BIGBUTTON ""
        [BUTTON-07-LEFT] [BUTTON-07-RIGHT]
    at 0x384 BIGBUTTON ""
        [BUTTON-09-LEFT] [BUTTON-09-RIGHT]

    at 128x384 BIGBUTTON ""
        [BUTTON-10-LEFT] [BUTTON-10-RIGHT]
    at 256x384 BIGBUTTON ""
        [BUTTON-11-LEFT] [BUTTON-11-RIGHT] 
    at 384x384 BIGBUTTON ""
        [BUTTON-12-LEFT] [BUTTON-12-RIGHT]

    at 384x128 BIGBUTTON ""
        [BUTTON-06-LEFT] [BUTTON-06-RIGHT]
    at 384x256 BIGBUTTON ""
        [BUTTON-08-LEFT] [BUTTON-08-RIGHT]

    at 128X128 CENTER-IMAGE: image 256x256 CENTER-PICTURE 
    at 128x128 CENTER-INFO: info 256x256
at 0x512 info 512 INFOTEXT
]

view center-face MAIN-WINDOW

71. Customized makedoc2

For our documentation, we use a customized version of the program called makedoc2.r from rebol.org. We would like to have our own logo and heading on our documentation, so we modified the source code to accomplish that. Originally, we did this modification by hand, but here is a script that will produce a customized version of makedoc2 with a logo from a file of your choosing.

To create the customized makedoc2, just run this script. When you select a logo file, it will have to be a jpeg or gif, and it is your job to make sure the image is of an appropriate size, like about an inch and a half.

REBOL [
    Title: "Makedoc2 customizer"
    Purpose: {Use an embedded version of makedoc2 from rebol.org and
    customize it with a web site link a custom document heading, and
    a logo created from a file selected by the operator.}
]

system/options/binary-base: 64

;; -- This is a function that takes the name of an image file,
;; -- converts it to base-64 encoding, and creates an IMG tag
;; -- that will embed that image in a web page.
IMGTAG: func [
    FILENAME
    ALTDESC
] [
    return rejoin [ 
        {<img alt="} ALTDESC {" }
        {src="data:image/}
        at form suffix? FILENAME 2
        {;base64,}
        enbase/base read/binary FILENAME 64
        {">}
    ]
]

;; -- This is compressed copy of makedoc2.r from rebol.org,
;; -- with some place holders for a web site name, an h1
;; -- heading, and an embedded base 64 logo.
MAKEDOC-TEMPLATE:
64#{
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
}

MAKEDOC-SCRIPT: decompress MAKEDOC-TEMPLATE

WS-LOGO-FILE: none
SELECT-LOGO-FILE: does [
    if not WS-LOGO-FILE: request-file/only [
        alert "No logo file selected."
        exit
    ]
]

WS-WEBSITE: ""
WS-HEADING: ""
WS-IMAGETAG: ""
GENERATE-MAKEDOC2: does [
    if not WS-LOGO-FILE [
        alert "No logo file available."
        exit
    ]
    WS-WEBSITE: get-face MAIN-WEBSITE
    WS-HEADING: get-face MAIN-HEADING
    WS-IMAGETAG: IMGTAG WS-LOGO-FILE "Logo"
    replace MAKEDOC-SCRIPT "%%CUSTOM-WEBSITE%%" WS-WEBSITE
    replace MAKEDOC-SCRIPT "%%CUSTOM-HEADING%%" WS-HEADING
    replace MAKEDOC-SCRIPT "%%CUSTOM-LOGO%%" WS-IMAGETAG
    write %makedoc2-custom.r MAKEDOC-SCRIPT
    alert "Done."
]

view layout [
    across
    label 200 "Website address under logo"
    MAIN-WEBSITE: field 300
    return
    label 200 "Heading for top of document"
    MAIN-HEADING: field 300
    return
    button 200 "Select logo file" [SELECT-LOGO-FILE]
    MAIN-LOGO: info 300
    return
    button "Quit" [quit]
    button 200 "Generate customized makedoc2" [GENERATE-MAKEDOC2]
]

72. Fixed-format file processing.

Fixed-format files still are "a thing" in the world of data processing. Taking them apart is simple enough because every "field" in a "record" is a substring, and the "copy/part" function can copy parts of a string, thus being a de-facto "substring" function.

The example below is from a program to process a fixed-format NACHA file used for transferring money. The file has different record types, each with a different format, and the records are in a fixed format, meaning that, for example, an account number appears in the same character position in each record that would have an account number.

;WALKTHROUGH:Documentation
TITLE
NACHA file

SUMMARY
This module provides procedures for reading a file in the NACHA format
and taking apart the fixed-format record into its individual data items.

DOCUMENTATION
Include the module in your program with:

do %nacha.r

NACHA-OPEN-INPUT
Perform this procedure first.  It will read the file into memory.
If you don't like the default name of the file (which is meaningless, really,
because it is the name of a NACHA file from the vendor), assign a new value to
NACHA-FILE-ID.

NACHA-READ
Do this proceure until NACHA-EOF is true.
After each call, use NACHA-CURRENT-TYPE to decide what kind of record you
have, and then refer to the appropriate data names (in the code below) to
access the fields in the record.

SCRIPT
REBOL [
    Title: "NACHA file"
]

;; [---------------------------------------------------------------------------]
;; [ Substring function used for extracting parts of a fixed-format record.    ]
;; [---------------------------------------------------------------------------]

GLB-SUBSTRING: func [
    "Return a substring from the start position to the end position"
    INPUT-STRING [series!] "Full input string"
    START-POS    [number!] "Starting position of substring"
    END-POS      [number!] "Ending position of substring"
] [
    if END-POS = -1 [END-POS: length? INPUT-STRING]
    return skip (copy/part INPUT-STRING END-POS) (START-POS - 1)
]

;WALKTHROUGH:Purpose
;; [---------------------------------------------------------------------------]
;; [ This module defines a text file in the NACHA format for                   ]
;; [ getting money electronically from the bank,                               ]
;; [ This is the file that Cogsdale makes and that we send every               ]
;; [ Monday.                                                                   ]
;; [ This file differs slightly from the file we get from the bank             ]
;; [ every DAY with internet payments, but the difference seems                ]
;; [ to be in field uses and not field positions.                              ]     
;; [---------------------------------------------------------------------------]

NACHA-FILE: []                 ;; Holds the whole file in memory
NACHA-FILE-ID: %NATC0001.TXT   ;; Default name of the file
NACHA-EOF: false               ;; End-of-file flag for reading
NACHA-REC: ""                  ;; One record, for reading or writing 
NACHA-REC-COUNT: 0             ;; Counter, upped by 1 as we read or write 

NACHA-CURRENT-TYPE: ""         ;; Type code of record in memory

;WALKTHROUGH:Data fields
;; [---------------------------------------------------------------------------]
;; [ When we read a record, we will take it apart in to its                    ]
;; [ fields and store the fields below.  The CURRENT-TYPE field                ]
;; [ indicates which record we currently have our hands on.                    ]
;; [ For those record that contain numbers or amounts, some of the             ]
;; [ numbers or amounts are converted to appropriate data types                ]
;; [ so they can be used in appropriate ways (currency, for example).          ]
;; [---------------------------------------------------------------------------]

NACHA-1-RECORD-TYPE-CODE: ""
NACHA-1-PRIORITY-CODE: ""
NACHA-1-IMMEDIATE-DESTINATION: ""
NACHA-1-IMMEDIATE-ORIGIN: ""
NACHA-1-TRANSMISSION-DATE: ""
NACHA-1-TRANSMISSION-TIME: ""
NACHA-1-FILE-ID-MODIFIER: ""
NACHA-1-RECORD-SIZE: ""
NACHA-1-BLOCKING-FACTOR: ""
NACHA-1-FORMAT-CODE: ""
NACHA-1-DESTINATION-NAME: ""
NACHA-1-ORIGIN: ""
NACHA-1-REFERENCE-CODE: ""

NACHA-5-RECORD-TYPE-CODE: ""
NACHA-5-SERVICE-CLASS-CODE: ""
NACHA-5-BILLER-NAME: ""
NACHA-5-RESERVED: ""
NACHA-5-BILLER-ID-NUMBER: ""
NACHA-5-ENTRY-CLASS: ""
NACHA-5-ENTRY-DESCRIPTION: ""
NACHA-5-DESCRIPTIVE-DATE: ""
NACHA-5-EFFECTIVE-DATE: ""
NACHA-5-SETTLEMENT-DATE: ""
NACHA-5-CONCENTRATOR-STATUS: ""
NACHA-5-NACHA-ID-NUMBER: ""
NACHA-5-BATCH-NUMBER: ""

NACHA-5-EFFECTIVE-DATE-E: ""

NACHA-6-RECORD-TYPE-CODE: ""
NACHA-6-TRANSACTION-CODE: ""
NACHA-6-NACHA-ID-NUMBER: ""
NACHA-6-MERCHANT-ACCOUNT-NBR: ""
NACHA-6-AMOUNT: ""
NACHA-6-CONSUMER-ACCOUNT-NBR: ""
NACHA-6-CONSUMER-NAME: ""
NACHA-6-NACHA-FLAG: ""
NACHA-6-ADDENDUM-RECORD-IND: ""
NACHA-6-TRACE-NUMBER: ""
NACHA-6-SEQUENCE-NUMBER: ""

NACHA-6-AMOUNT-N: ""

NACHA-8-RECORD-TYPE-CODE: ""
NACHA-8-SERVICE-CLASS-CODE: ""
NACHA-8-ENTRY-ADDENDA-COUNT: ""
NACHA-8-ENTRY-HASH: ""
NACHA-8-TOTAL-DEBIT: ""
NACHA-8-TOTAL-CREDIT: ""
NACHA-8-BILLER-ID-NUMBER: ""
NACHA-8-MAC: ""
NACHA-8-FILLER-1: ""
NACHA-8-NACHA-ID-NUMBER: ""
NACHA-8-BATCH-NUMBER: ""

NACHA-8-TOTAL-DEBIT-N: ""
NACHA-8-TOTAL-CREDIT-N: ""

NACHA-9-RECORD-TYPE-CODE: ""
NACHA-9-BATCH-COUNT: ""
NACHA-9-BLOCK-COUNT: ""
NACHA-9-ENTRY-ADDENDA-COUNT: ""
NACHA-9-ENTRY-HASH: ""
NACHA-9-TOTAL-DEBIT: ""
NACHA-9-TOTAL-CREDIT: ""
NACHA-9-FILLER-1: ""

NACHA-9-TOTAL-DEBIT-N: ""
NACHA-9-TOTAL-CREDIT-N: ""

;WALKTHROUGH:Open-close-read-write
NACHA-OPEN-INPUT: does [
    NACHA-FILE: copy []
    NACHA-FILE: read/lines NACHA-FILE-ID
    NACHA-EOF: false
    NACHA-REC-COUNT: 0
]

NACHA-READ: does [
    NACHA-REC-COUNT: NACHA-REC-COUNT + 1
    NACHA-REC: copy ""
    NACHA-CURRENT-TYPE: copy ""
    if none? NACHA-REC: pick NACHA-FILE NACHA-REC-COUNT [
        NACHA-EOF: true
    ]
    if not NACHA-EOF [
        NACHA-UNSTRING-RECORD
    ]
]

NACHA-CLOSE-INPUT: does [
    NACHA-FILE: copy []
    NACHA-REC: copy ""
]

NACHA-OPEN-OUTPUT: does [
    NACHA-FILE: copy []
    NACHA-REC: copy ""
    NACHA-REC-COUNT: 0
]

NACHA-WRITE: does [
    append NACHA-FILE NACHA-REC
    NACHA-REC-COUNT: NACHA-REC-COUNT + 1
]

NACHA-CLOSE-OUTPUT: does [
    write/lines NACHA-FILE-ID NACHA-FILE
    NACHA-FILE: copy []
    NACHA-REC: copy ""
]

;WALKTHROUGH:Unstringing data
NACHA-UNSTRING-RECORD: does [
    NACHA-CURRENT-TYPE: GLB-SUBSTRING NACHA-REC 1 1
    if = NACHA-CURRENT-TYPE "1" [
        NACHA-UNSTRING-1
    ]
    if = NACHA-CURRENT-TYPE "5" [
        NACHA-UNSTRING-5
    ]
    if = NACHA-CURRENT-TYPE "6" [
        NACHA-UNSTRING-6
    ]
    if = NACHA-CURRENT-TYPE "8" [
        NACHA-UNSTRING-8
    ]
    if = NACHA-CURRENT-TYPE "9" [
        NACHA-UNSTRING-9
    ] 
]

NACHA-UNSTRING-1: does [
    NACHA-1-RECORD-TYPE-CODE: copy ""
    NACHA-1-PRIORITY-CODE: copy ""
    NACHA-1-IMMEDIATE-DESTINATION: copy ""
    NACHA-1-IMMEDIATE-ORIGIN: copy ""
    NACHA-1-TRANSMISSION-DATE: copy ""
    NACHA-1-TRANSMISSION-TIME: copy ""
    NACHA-1-FILE-ID-MODIFIER: copy ""
    NACHA-1-RECORD-SIZE: copy ""
    NACHA-1-BLOCKING-FACTOR: copy ""
    NACHA-1-FORMAT-CODE: copy ""
    NACHA-1-DESTINATION-NAME: copy ""
    NACHA-1-ORIGIN: copy ""
    NACHA-1-REFERENCE-CODE: copy ""
    NACHA-1-RECORD-TYPE-CODE: GLB-SUBSTRING NACHA-REC 1 1
    NACHA-1-PRIORITY-CODE: GLB-SUBSTRING NACHA-REC 2 3
    NACHA-1-IMMEDIATE-DESTINATION: GLB-SUBSTRING NACHA-REC 4 13
    NACHA-1-IMMEDIATE-ORIGIN: GLB-SUBSTRING NACHA-REC 14 23
    NACHA-1-TRANSMISSION-DATE: GLB-SUBSTRING NACHA-REC 24 29
    NACHA-1-TRANSMISSION-TIME: GLB-SUBSTRING NACHA-REC 30 33
    NACHA-1-FILE-ID-MODIFIER: GLB-SUBSTRING NACHA-REC 34 34
    NACHA-1-RECORD-SIZE: GLB-SUBSTRING NACHA-REC 35 37
    NACHA-1-BLOCKING-FACTOR: GLB-SUBSTRING NACHA-REC 38 39
    NACHA-1-FORMAT-CODE: GLB-SUBSTRING NACHA-REC 40 40
    NACHA-1-DESTINATION-NAME: GLB-SUBSTRING NACHA-REC 41 63
    NACHA-1-ORIGIN: GLB-SUBSTRING NACHA-REC 64 86
    NACHA-1-REFERENCE-CODE: GLB-SUBSTRING NACHA-REC 87 94
]

NACHA-UNSTRING-5: does [
    NACHA-5-RECORD-TYPE-CODE: copy ""
    NACHA-5-SERVICE-CLASS-CODE: copy ""
    NACHA-5-BILLER-NAME: copy ""
    NACHA-5-RESERVED: copy ""
    NACHA-5-BILLER-ID-NUMBER: copy ""
    NACHA-5-ENTRY-CLASS: copy ""
    NACHA-5-ENTRY-DESCRIPTION: copy ""
    NACHA-5-DESCRIPTIVE-DATE: copy ""
    NACHA-5-EFFECTIVE-DATE: copy ""
    NACHA-5-SETTLEMENT-DATE: copy ""
    NACHA-5-CONCENTRATOR-STATUS: copy ""
    NACHA-5-NACHA-ID-NUMBER: copy ""
    NACHA-5-BATCH-NUMBER: copy ""
    NACHA-5-RECORD-TYPE-CODE: GLB-SUBSTRING NACHA-REC 1 1
    NACHA-5-SERVICE-CLASS-CODE: GLB-SUBSTRING NACHA-REC 2 4
    NACHA-5-BILLER-NAME: GLB-SUBSTRING NACHA-REC 5 20
    NACHA-5-RESERVED: GLB-SUBSTRING NACHA-REC 21 40
    NACHA-5-BILLER-ID-NUMBER: GLB-SUBSTRING NACHA-REC 41 50
    NACHA-5-ENTRY-CLASS: GLB-SUBSTRING NACHA-REC 51 53
    NACHA-5-ENTRY-DESCRIPTION: GLB-SUBSTRING NACHA-REC 54 63
    NACHA-5-DESCRIPTIVE-DATE: GLB-SUBSTRING NACHA-REC 64 69
    NACHA-5-EFFECTIVE-DATE: GLB-SUBSTRING NACHA-REC 70 75
    NACHA-5-SETTLEMENT-DATE: GLB-SUBSTRING NACHA-REC 76 78
    NACHA-5-CONCENTRATOR-STATUS: GLB-SUBSTRING NACHA-REC 79 79
    NACHA-5-ID-NUMBER: GLB-SUBSTRING NACHA-REC 80 87
    NACHA-5-BATCH-NUMBER: GLB-SUBSTRING NACHA-REC 88 94
    NACHA-5-EFFECTIVE-DATE-E: rejoin [
        GLB-SUBSTRING NACHA-5-EFFECTIVE-DATE 3 4
        "/"
        GLB-SUBSTRING NACHA-5-EFFECTIVE-DATE 5 6
        "/"
        "20"
        GLB-SUBSTRING NACHA-5-EFFECTIVE-DATE 1 2
    ]
]

NACHA-UNSTRING-6: does [
    NACHA-6-RECORD-TYPE-CODE: copy ""
    NACHA-6-TRANSACTION-CODE: copy ""
    NACHA-6-NACHA-ID-NUMBER: copy ""
    NACHA-6-MERCHANT-ACCOUNT-NBR: copy ""
    NACHA-6-AMOUNT: copy ""
    NACHA-6-CONSUMER-ACCOUNT-NBR: copy ""
    NACHA-6-CONSUMER-NAME: copy ""
    NACHA-6-NACHA-FLAG: copy ""
    NACHA-6-ADDENDUM-RECORD-IND: copy ""
    NACHA-6-TRACE-NUMBER: copy ""
    NACHA-6-SEQUENCE-NUMBER: copy ""
    NACHA-6-RECORD-TYPE-CODE: GLB-SUBSTRING NACHA-REC 1 1
    NACHA-6-TRANSACTION-CODE: GLB-SUBSTRING NACHA-REC 2 3
    NACHA-6-NACHA-ID-NUMBER: GLB-SUBSTRING NACHA-REC 4 12
    NACHA-6-MERCHANT-ACCOUNT-NBR: GLB-SUBSTRING NACHA-REC 13 29
    NACHA-6-AMOUNT: GLB-SUBSTRING NACHA-REC 30 39
    NACHA-6-CONSUMER-ACCOUNT-NBR: GLB-SUBSTRING NACHA-REC 40 54
    NACHA-6-CONSUMER-NAME: GLB-SUBSTRING NACHA-REC 55 76
    NACHA-6-NACHA-FLAG: GLB-SUBSTRING NACHA-REC 77 78
    NACHA-6-ADDENDUM-RECORD-IND: GLB-SUBSTRING NACHA-REC 79 79
    NACHA-6-TRACE-NUMBER: GLB-SUBSTRING NACHA-REC 80 87
    NACHA-6-SEQUENCE-NUMBER: GLB-SUBSTRING NACHA-REC 88 94
    NACHA-6-AMOUNT-N: to-money divide to-decimal NACHA-6-AMOUNT 100
]

NACHA-UNSTRING-8: does [
    NACHA-8-RECORD-TYPE-CODE: copy ""
    NACHA-8-SERVICE-CLASS-CODE: copy ""
    NACHA-8-ENTRY-ADDENDA-COUNT: copy ""
    NACHA-8-ENTRY-HASH: copy ""
    NACHA-8-TOTAL-DEBIT: copy ""
    NACHA-8-TOTAL-CREDIT: copy ""
    NACHA-8-BILLER-ID-NUMBER: copy ""
    RPPT-8-MAC: copy ""
    NACHA-8-FILLER-1: copy ""
    NACHA-8-NACHA-ID-NUMBER: copy ""
    NACHA-8-BATCH-NUMBER: copy ""
    NACHA-8-RECORD-TYPE-CODE: GLB-SUBSTRING NACHA-REC 1 1
    NACHA-8-SERVICE-CLASS-CODE: GLB-SUBSTRING NACHA-REC 2 4
    NACHA-8-ENTRY-ADDENDA-COUNT: GLB-SUBSTRING NACHA-REC 5 10
    NACHA-8-ENTRY-HASH: GLB-SUBSTRING NACHA-REC 11 20
    NACHA-8-TOTAL-DEBIT: GLB-SUBSTRING NACHA-REC 21 32
    NACHA-8-TOTAL-CREDIT: GLB-SUBSTRING NACHA-REC 33 44
    NACHA-8-BILLER-ID-NUMBER: GLB-SUBSTRING NACHA-REC 45 54
    NACHA-8-MAC: GLB-SUBSTRING NACHA-REC 55 73
    NACHA-8-FILLER-1: GLB-SUBSTRING NACHA-REC 74 79
    NACHA-8-NACHA-ID-NUMBER: GLB-SUBSTRING NACHA-REC 80 87
    NACHA-8-BATCH-NUMBER: GLB-SUBSTRING NACHA-REC 88 94
    NACHA-8-TOTAL-DEBIT-N: to-money divide to-decimal NACHA-8-TOTAL-DEBIT 100
    NACHA-8-TOTAL-CREDIT-N: to-money divide to-decimal NACHA-8-TOTAL-CREDIT 100  
]

NACHA-UNSTRING-9: does [
    NACHA-9-RECORD-TYPE-CODE: copy "" 
    NACHA-9-BATCH-COUNT: copy "" 
    NACHA-9-BLOCK-COUNT: copy "" 
    NACHA-9-ENTRY-ADDENDA-COUNT: copy "" 
    NACHA-9-ENTRY-HASH: copy "" 
    NACHA-9-TOTAL-DEBIT: copy "" 
    NACHA-9-TOTAL-CREDIT: copy "" 
    NACHA-9-FILLER-1: copy "" 
    NACHA-9-RECORD-TYPE-CODE: GLB-SUBSTRING NACHA-REC 1 1
    NACHA-9-BATCH-COUNT: GLB-SUBSTRING NACHA-REC 2 7
    NACHA-9-BLOCK-COUNT: GLB-SUBSTRING NACHA-REC 8 13
    NACHA-9-ENTRY-ADDENDA-COUNT: GLB-SUBSTRING NACHA-REC 14 21
    NACHA-9-ENTRY-HASH: GLB-SUBSTRING NACHA-REC 22 31
    NACHA-9-TOTAL-DEBIT: GLB-SUBSTRING NACHA-REC 32 43
    NACHA-9-TOTAL-CREDIT: GLB-SUBSTRING NACHA-REC 44 55
    NACHA-9-FILLER-1: GLB-SUBSTRING NACHA-REC 56 94
    NACHA-9-TOTAL-DEBIT-N: to-money divide to-decimal NACHA-9-TOTAL-DEBIT 100
    NACHA-9-TOTAL-CREDIT-N: to-money divide to-decimal NACHA-9-TOTAL-CREDIT 100  
]
;; -------------------------------------------------------------------

73. Fixed-format processing module

The example above is a bit of fussing we would like to avoid if possible. Once you have taken apart a fixed-format record, you will do the same thing for any other and the only difference will be that the record will contain different fields at different locations.

The script below encapsulates some funtions to ease the operations one has to do on fixed-format files. If you can specify the field locations on a record and provide them to these functions, you can access the fields on a record by name, and if you trust the functions enough to consider them a black box, the coding of your own program can be streamlined and thus a bit easier to understand.

REBOL [
    Title: "Fixed Format Text file functions"
    Purpose: {Useful functions for working with a text file
    of fixed-format records.}
]

;; [---------------------------------------------------------------------------]
;; [ This is a bunch of functions for working with a file of fixed-format      ]
;; [ text lines.  It was created originally as the base for a program to       ]
;; [ provide minimal, carefully controlled, editing of such a file by those    ]
;; [ not familiary with text editors.                                          ]
;; [ There will be procedures to open a file, read the next or previous        ]
;; [ record, delete a record, add a new record at the end, and save the        ]
;; [ file under its same name or a new name.                                   ]
;; [ This module is not an independent program.  It will be called by a        ]
;; [ controlling program.                                                      ]
;; [---------------------------------------------------------------------------]

;; [---------------------------------------------------------------------------]
;; [ Items we will use in processing the file.                                 ]
;; [---------------------------------------------------------------------------]

FFTF-FILE-ID: none      ;; File name we will be working on
FFTF-FILE-ID-SAVE: none ;; File name for save-as operation
FFTF-FIELDS: none       ;; Field names and locations in a record
FFTF-DATA: []           ;; Whole file in memory as a block of lines
FFTF-RECORD: ""         ;; One line of the file, the one we are working with
FFTF-RECNO: 0           ;; Index of the record we are positioned at
FFTF-FILE-SIZE: 0       ;; Number of lines in DATA
FFTF-EOF: false         ;; Set to true if we try to read past end
FFTF-FOUND: false       ;; Returned when searching

;; [---------------------------------------------------------------------------]
;; [ Open an existing file.                                                    ]
;; [ This function requires two items.  The first is the name of the file.     ]
;; [ The second is a block.  The block will contain repetitions of a word      ]
;; [ and a pair.  The word will the the name of a field in the fixed-format    ]
;; [ record.  The pair will the the one-relative starting position of the      ]
;; [ field (x) and the length of the field (y).                                ]
;; [ The "open" function will bring the whole file into memory and set up      ]
;; [ various pointers and such for working with the lines in the file.         ]
;; [---------------------------------------------------------------------------]

FFTF-OPEN-INPUT: func [
    FILEID [file!]
    FIELDLIST [block!]
] [
;;  -- Save what was passed to us.
    FFTF-FILE-ID: FILEID
    FFTF-FIELDS: FIELDLIST
;;  -- Read the entire file into memory.  Set various working items.
    FFTF-DATA: copy []
    FFTF-DATA: read/lines FFTF-FILE-ID
    FFTF-FILE-SIZE: length? FFTF-DATA
    FFTF-RECNO: 0
    FFTF-EOF: false
]

;; [---------------------------------------------------------------------------]
;; [ Read a record indicated by FFTF-RECNO.                                    ]
;; [ "Read" means to copy the specified line into the record area and then     ]
;; [ use the field list to set the words in the field list to the data         ]
;; [ indicated by the position-length pair.                                    ]
;; [---------------------------------------------------------------------------]

FFTF-READ-SPECIFIC: does [
    FFTF-EOF: false
    FFTF-RECORD: pick FFTF-DATA FFTF-RECNO
    foreach [FIELDNAME POSITION] FFTF-FIELDS [
        FFTF-RECORD: head FFTF-RECORD
        FFTF-RECORD: skip FFTF-RECORD (POSITION/x - 1)
        set FIELDNAME copy/part FFTF-RECORD POSITION/y
    ]
]

;; [---------------------------------------------------------------------------]
;; [ To read the first/next/previous/last record, we will just adjust the      ]
;; [ RECNO and use the above READ-SPECIFIC function.                           ]
;; [ Notice that we don't let RECNO get out of bounds, just in case we         ]
;; [ misuse these procedures and try to read out of bounds.                    ]
;; [---------------------------------------------------------------------------]

FFTF-READ-FIRST: does [
    FFTF-RECNO: 1
    either (FFTF-RECNO > FFTF-FILE-SIZE) [
        FFTF-RECNO: FFTF-FILE-SIZE
        FFTF-EOF: true
        return FFTF-EOF
    ] [
        FFTF-READ-SPECIFIC
        return FFTF-EOF
    ]
]

FFTF-READ-NEXT: does [
    FFTF-RECNO: FFTF-RECNO + 1
    either (FFTF-RECNO > FFTF-FILE-SIZE) [
        FFTF-RECNO: FFTF-FILE-SIZE
        FFTF-EOF: true
        return FFTF-EOF
    ] [
        FFTF-READ-SPECIFIC
        return FFTF-EOF
    ]
]

FFTF-READ-PREV: does [
    FFTF-RECNO: FFTF-RECNO - 1
    either (FFTF-RECNO < 1) [
        FFTF-RECNO: 1
        FFTF-EOF: true
        return FFTF-EOF
    ] [
        FFTF-READ-SPECIFIC
        return FFTF-EOF
    ]
]

FFTF-READ-LAST: does [
    FFTF-RECNO: FFTF-FILE-SIZE
    either (FFTF-RECNO < 1) [
        FFTF-RECNO: FFTF-FILE-SIZE
        FFTF-EOF: true
        return FFTF-EOF
    ] [
        FFTF-READ-SPECIFIC
        return FFTF-EOF
    ]
]

;; [---------------------------------------------------------------------------]
;; [ Operations for saving the data or making a new file.                      ]
;; [---------------------------------------------------------------------------]

FFTF-SAVE-FILE: does [
    write/lines FFTF-FILE-ID FFTF-DATA
]

FFTF-SAVE-FILE-AS: does [
    FFTF-FILE-ID-SAVE: request-file/only/save
    either FFTF-FILE-ID-SAVE [
        write/lines FFTF-FILE-ID-SAVE FFTF-DATA
    ] [
        alert "No save-as ID requested"
    ]
]

;; [---------------------------------------------------------------------------]
;; [ We are going to have to be able to delete records, and also to update     ]
;; [ them if the values of the fields are changed by some calling program.     ]
;; [---------------------------------------------------------------------------]

;;  -- Build a record using current values of the field names.
FFTF-BUILD-RECORD: does [
    FFTF-RECORD: copy ""
    loop 1024 [append FFTF-RECORD " "]
    foreach [FIELDNAME POSITION] FFTF-FIELDS [
        FFTF-RECORD: head FFTF-RECORD
        FFTF-RECORD: skip FFTF-RECORD (POSITION/x - 1)
        change/part FFTF-RECORD (get FIELDNAME) POSITION/y
    ]    
    FFTF-RECORD: head FFTF-RECORD
    FFTF-RECORD: trim/tail FFTF-RECORD
]

;;  -- Delete the line pointed to by RECNO.
FFTF-DELETE-RECORD: does [
    remove at FFTF-DATA FFTF-RECNO
    FFTF-FILE-SIZE: FFTF-FILE-SIZE - 1
]

;;  -- Add a new record at the end of the file.
FFTF-ADD-RECORD: does [
    FFTF-BUILD-RECORD
    append FFTF-DATA FFTF-RECORD
    FFTF-FILE-SIZE: FFTF-FILE-SIZE + 1 
] 

;;  -- Change the record pointed to by RECNO using the field name values.
FFTF-CHANGE-RECORD: does [
    FFTF-BUILD-RECORD
    poke FFTF-DATA FFTF-RECNO FFTF-RECORD
]

;;  -- Search for the record where the value of a given word is equal
;;  -- to a given value.  Return true or false.
FFTF-SEARCH: func [
    SEARCH-WORD
    SEARCH-VALUE
] [
    FFTF-READ-FIRST
    until [
        if equal? SEARCH-VALUE (get SEARCH-WORD) [
            FFTF-FOUND: true
            return FFTF-FOUND
        ]
        FFTF-READ-NEXT
    ]
    FFTF-FOUND: false
    return FFTF-FOUND
]

;;  -- Search ahead from where we are.
FFTF-SEARCH-NEXT: func [
    SEARCH-WORD
    SEARCH-VALUE
] [
    FFTF-READ-NEXT
    until [
        if equal? SEARCH-VALUE (get SEARCH-WORD) [
            FFTF-FOUND: true
            return FFTF-FOUND
        ]
        FFTF-READ-NEXT
    ]
    FFTF-FOUND: false
    return FFTF-FOUND
]

;;  -- Search backwards from where we are.
FFTF-SEARCH-PREV: func [
    SEARCH-WORD
    SEARCH-VALUE
] [
    FFTF-READ-PREV
    until [
        if equal? SEARCH-VALUE (get SEARCH-WORD) [
            FFTF-FOUND: true
            return FFTF-FOUND
        ]
        FFTF-READ-PREV
    ]
    FFTF-FOUND: false
    return FFTF-FOUND
]

;; Uncomment to test
;FID: %fftf-testdata.txt
;;               123456789*123456789*123456789*123456789*1234
;write/lines FID {11111111 22222222222222222222 3 4 5555555555
;FIELD-1  TWENTY CHARACTERS... X Y 1234567890
;AAAAAAAA BBBBBBBBBBBBBBBBBBBB P Q 0987654321
;CCCCCCCC DDDDDDDDDDDDDDDDDDDD J K **********}
;FFTF-OPEN-INPUT FID [F1 1X8 F2 10X20 F3 31X1 F4 33X1 F5 35X10]
;foreach line FFTF-DATA [
;    print line
;]
;FFTF-READ-NEXT
;print rejoin ["F1 = '" F1 "'"]
;print rejoin ["F2 = '" F2 "'"]
;print rejoin ["F3 = '" F3 "'"]
;print rejoin ["F4 = '" F4 "'"]
;print rejoin ["F5 = '" F5 "'"]
;FFTF-READ-NEXT
;print rejoin ["F1 = '" F1 "'"]
;print rejoin ["F2 = '" F2 "'"]
;print rejoin ["F3 = '" F3 "'"]
;print rejoin ["F4 = '" F4 "'"]
;print rejoin ["F5 = '" F5 "'"]
;either FFTF-SEARCH 'F3 "P" [
;    print "P found"
;] [
;    print "No P found"
;]
;either FFTF-SEARCH 'F1 "FIELD-2" [
;    print "FIELD-2 found"
;] [
;    print "No FIELD-2 found"
;]
;FFTF-READ-FIRST
;F2: copy "New value"
;FFTF-CHANGE-RECORD
;foreach line FFTF-DATA [
;    print line
;]
;halt

74. "Printing" to CSV

It seems that REBOL was not designed for applications where printing on paper is done a lot, because there is nothing in the language that refers to putting things on paper. This is in contrast to a language like COBOL that was created in the days when the primary computer output was lots of paper. In COBOL you can "select" a file and "assign" it to "printer."

But even in these times, one must put things on paper, so how is that done? In REBOL, it is done by letting other applications do it. In this example, we put our desired output into a CSV file, by just stringing them together separated by commas. Then, to get that output on paper, we open the CSV file with any popular spreadsheet program and use the spreadsheet printing function.

One could code that stringing-together fresh each time we want some printed output, and that would not be too big a chore, but we can make the operation easier by writing some general-purpose functions for that. The example below shows that idea. Documentation is in the comments.

REBOL [
    Title: "PRTCSV: Format print lines for a csv file"
]

;; [---------------------------------------------------------------------------]
;; [ This is an object that can be used to define a csv file that will be      ]
;; [ used as a "report."  The general plan of action is that a program can     ]
;; [ use this module to put reportable data into a csv file, and the           ]
;; [ operator of the program then will use a popular spreadsheet program       ]
;; [ to view the file and optionally put it on paper with the spreadsheet      ]
;; [ programs own "print" feature.  In other words, this module is a way to    ]
;; [ handle "printing" in REBOL by ignoring the problem and letting            ]
;; [ someone else (the spreadsheet program) do the work.                       ]
;; [                                                                           ]
;; [ To use:                                                                   ]
;; [                                                                           ]
;; [ Make an instance of this object with:                                     ]
;; [     MYCSVREPORT: make PRTCSV [                                            ]
;; [         FILEID: file-name                                                 ]
;; [         COLUMNS: [column-name-list] ]                                     ]
;; [     ]                                                                     ]
;; [ The reason we make an instance of an object is so that we can use this    ]
;; [ one module to produce more than one report in a single program.           ]
;; [ The column-name-list is a block of words that will become the column      ]
;; [ headings of the csv file as well as words that you may set to values      ]
;; [ to get those values into the output file.                                 ]
;; [                                                                           ]
;; [ For example, say you want to produce a csv file with columns for          ]
;; [ NAME, ADDRESS, and PHONE.  You also want those words to be column         ]
;; [ headings.  (Note that a common way to use a spreadsheet is a little       ]
;; [ "data file" where each row is a record, each column is a field, and       ]
;; [ the first row contains the "field names.")  You also want to create an    ]
;; [ output file called csvreport.csv.                                         ] 
;; [ You would code this:                                                      ]
;; [     CSVREPORT: make PRTCSV [                                              ]
;; [         FILEID: %csvreport.csv                                            ]
;; [         COLUMNS: [                                                        ]
;; [             NAME                                                          ]
;; [             ADDRESS                                                       ]
;; [             PHONE                                                         ]
;; [         ]                                                                 ]
;; [     ]                                                                     ]
;; [ Note that CSVREPORT is a name that you make up, NAME, ADDRESS, and PHONE  ]
;; [ are names that you make up, but PRTCSV is the name of the model           ]
;; [ object, COLUMNS is the name of a data item in that model object,          ]
;; [ and FILEID is a word that specifies the name of the file,                 ]
;; [ so PRTCSV, COLUMNS, and FILEID are words that must be use as they are;    ]
;; [ they are not words that you would make up.  By the way, make sure         ]
;; [ the FILEID is a REBOL file name with the percent sigh in front.           ]
;; [                                                                           ]
;; [ After you have done the above, you must perform a procedure before you    ]
;; [ can "print" anything.  You must call the function:                        ]
;; [     CSVREPORT/OPEN-OUTPUT                                                 ]
;; [ What this procedure will do is initialize some areas, plus create a       ]
;; [ sub-object called RECORD, and inside RECORD will be words that you        ]
;; [ may set to values.  These words are the ones you specified when you       ]
;; [ created the instance of the object.  Using the above example, you will    ]
;; [ have available the following data items:                                  ]
;; [     CSVREPORT/RECORD/NAME                                                 ]
;; [     CSVREPORT/RECORD/ADDRESS                                              ]
;; [     CSVREPORT/RECORD/PHONE                                                ]
;; [ The above words are words you will set to values, for each row that       ]
;; [ you want to put into the output file.                                     ]
;; [                                                                           ]
;; [ When you want to "print" some data, you set the words you created to      ]
;; [ values, and perform a procedure to create a row in the output file.       ]
;; [ That procedure is called:                                                 ]
;; [     CSVREPORT/WRITE-RECORD                                                ]
;; [ Now the obvious question is, what is the data type of each of those       ]
;; [ words, so that I know what kind of values to set them to.                 ]
;; [ The answer is that they all are strings.  Why is that?                    ]
;; [ Reason number one is that this is a basic module and it is easiest to     ]
;; [ just use strings.  There also is another reason.  If we had some          ]
;; [ method of assigning types at the time the words are created, then we      ]
;; [ might end up with some situation where some sort of conversion was        ]
;; [ being done at a low level, and something might not work, and one could    ]
;; [ end up wrestling with this module to make it work.  Generally, we like    ]
;; [ to follow the principle of moving decisions up and moving work down,      ]
;; [ which in practice means that this module will just "do what it is told    ]
;; [ and not ask questions."                                                   ]
;; [                                                                           ]
;; [ When you are done "printing," the data you have "printed" will be in      ]
;; [ memory, so you must put it on disk.  You perform the procedure:           ]
;; [     CSVREPORT/CLOSE-OUTPUT                                                ]
;; [ The result will be that a file called csvreport.csv will come into        ]
;; [ existence.  The first line of the file will contain:                      ]
;; [     NAME,ADDRESS,PHONE                                                    ]
;; [ and the following lines will contain whatever data you specified for      ]
;; [ those fields as many times as you specified it.  The data fields          ]
;; [ will be quoted and separated by commas.                                   ]
;; [                                                                           ]
;; [ Remember that the purpose of this module is NOT to create a data file     ]
;; [ for some sort of data manipulation, but rather to make a report.          ]
;; [---------------------------------------------------------------------------]

PRTCSV: make object! [

;; [---------------------------------------------------------------------------]
;; [ Items the caller must set.                                                ]
;; [---------------------------------------------------------------------------]

    FILEID: %csvreport.csv
    COLUMNS: []

;; [---------------------------------------------------------------------------]
;; [ Working items.                                                            ]
;; [---------------------------------------------------------------------------]

    FILE-DATA: []
    RECORD: none
    COLUMN-COUNT: 0 
    COLUMN-NUMBER: 0

;; [---------------------------------------------------------------------------]
;; [ Open the file.                                                            ]
;; [ Using the supplied column names, construct the first line of the          ]
;; [ output file, and create a record with words that the caller can set       ]
;; [ to values.                                                                ]
;; [---------------------------------------------------------------------------]

    OPEN-OUTPUT: does [  
        COLUMN-NUMBER: length? COLUMNS   
        FILE-DATA: copy []
        HEADING-LINE: copy ""
        COLUMN-COUNT: 0
        RECORD: make object! []
        foreach COLUMN-NAME COLUMNS [
            COLUMN-COUNT: COLUMN-COUNT + 1
            append HEADING-LINE to-string COLUMN-NAME
            if lesser? COLUMN-COUNT COLUMN-NUMBER [
                append HEADING-LINE ","
            ]
            RECORD: make RECORD compose [
                (to-set-word COLUMN-NAME) {""}  
            ]
        ]
        append FILE-DATA HEADING-LINE
    ]

;; [---------------------------------------------------------------------------]
;; [ Close the file.                                                           ]
;; [ Write to disk the lines we have been generating.                          ]
;; [---------------------------------------------------------------------------]
CLOSE-OUTPUT: does [
    write/lines FILEID FILE-DATA
]

;; [---------------------------------------------------------------------------]
;; [ Write a record.                                                           ]
;; [ Generate a text line from the words supplied by the caller.               ]
;; [---------------------------------------------------------------------------]

WRITE-RECORD: does [
    COLUMN-COUNT: 0
    DATA-LINE: copy ""
    foreach COLUMN-NAME COLUMNS [
        append DATA-LINE mold RECORD/:COLUMN-NAME ;; mold adds quotes
        COLUMN-COUNT: COLUMN-COUNT + 1
        if lesser? COLUMN-COUNT COLUMN-NUMBER [
            append DATA-LINE ","
        ]
    ]
    append FILE-DATA DATA-LINE
]
]  ;; End of object.

75. "Printing" to TXT

Another idea for printing, if you have a fixed-format page, is to put the "print lines" into a text file, and then use a text editor to print it. The sample below shows some functions for making this work, and documentation is in the comments.

REBOL [
    Title: "PRTTXT: Format print lines for a text file"
]

;; [---------------------------------------------------------------------------]
;; [ This is an object that can be used to define a fixed-format "report"      ]
;; [ that is basically a text file of fixed-format lines, which when           ]
;; [ completed may be printed through any text editor.                         ]
;; [ This is a solution for making basic columnar reports.  It works as it     ]
;; [ is, but may be used as an example or as a starting point for something    ]
;; [ tailored to your own situation.                                           ]
;; [                                                                           ]
;; [ The object provides basic functions that you would expect to perform      ]
;; [ when printing a basic report.  You will "open" the print file which       ]
;; [ means to generate heading lines and provide instructions about where      ]
;; [ to put data on a fixed-format print line.  You will "close" the print     ]
;; [ file when you are done which means to write your "print lines" to a       ]
;; [ text file.  Between opening and closing, you will "print" lines of        ]
;; [ fixed-format text which means to format those lines based on data         ]
;; [ you have submitted and then add those lines to a block of text that       ]
;; [ represents the whole printed report.                                      ]
;; [                                                                           ]
;; [ To use:                                                                   ]
;; [                                                                           ]
;; [ Make an instance of the object with:                                      ]
;; [     MYPRINTFILE: make PRTTXT []                                           ]
;; [ By using objects, this module lets you put several reports into the       ]
;; [ same program.  Optionally, you can set a line of text at the very         ]
;; [ top of the report, and a line below that, this way:                       ]
;; [     MYPRINTFILE: make PRTTXT [                                            ]
;; [         SITE-NAME: "My Installation Name"                                 ]
;; [         REPORT-TITLE: "Title of this report"                              ]
;; [     ]                                                                     ]
;; [                                                                           ]
;; [ Before you can "print" to the report, you must "open" it.                 ]
;; [ This is just a way to get you to perform a procedure that does some       ]
;; [ setup for you.  You must provide two things to the "open" function.       ]
;; [ You must provide a file name that will be used when you "close" the       ]
;; [ report to write it to disk.  You must provide a block that contains       ]
;; [ repetitions of a word and a pair.  The word will become a word that       ]
;; [ you may set to a value when printing.  The word also will become          ]
;; [ a column heading on the report.  The pair represents the column           ]
;; [ position and the length, where the value of the word will be placed       ]
;; [ on a fixed-format print line.  This will look something like this:        ]
;; [     MYPRINTFILE/OPEN-OUTPUT                                               ]
;; [         %myprintifileid.txt                                               ]
;; [         [word-1 pair-1                                                    ]
;; [          word-2 pair-2                                                    ]
;; [          ...                                                              ]
;; [          word-n pair-n]                                                   ]
;; [ The result of the above procedure will be that there will be an           ]
;; [ object called MYPRINTFILE/RECORD ("MYPRINTFILE" is a name you choose;     ]
;; [ this is just an example) and that object will have words, specifically,   ]
;; [ the words you specified.  You will set these words to values,             ]
;; [ and when you "print" them they will go on the "print line" at the         ]
;; [ spots indicated by the pairs.                                             ]
;; [                                                                           ]
;; [ When you want to "print" data, you set the words you specified to         ]
;; [ values by referring to them in the RECORD object.  For example:           ]
;; [     MYPRINTFILE/RECORD/word-1: value-1                                    ]
;; [     MYPRINTFILE/RECORD/word-2: value-2                                    ]
;; [ When you have set the values you want to print, you perform the           ]
;; [ procedure to put that data into the file:                                 ]
;; [     MYPRINTFILE/WRITE-RECORD                                              ]
;; [                                                                           ]
;; [ When you are done producing the report, you have to get it into a disk    ]
;; [ file with:                                                                ]
;; [     MYPRINTFILE/CLOSE-OUTPUT                                              ]
;; [---------------------------------------------------------------------------]
PRTTXT: make object! [

;; [---------------------------------------------------------------------------]
;; [ Items the caller may override when creating an instance of this object.   ]
;; [---------------------------------------------------------------------------]
REPORT-TITLE: "" ;; Text to put at the top of the report
SITE-NAME: ""    ;; Your installation name at the very top of the report

;; [---------------------------------------------------------------------------]
;; [ Working items                                                             ]
;; [ Note that the SPACEFILL function expects a string.  It is the job of      ]
;; [ the caller to do any necessary conversion.                                ]
;; [---------------------------------------------------------------------------]

FILE-ID: none         ;; Name of a file we will create
FIELDS: none          ;; Fields submitted at open time
FILE-DATA: []         ;; All the data in the above file
RECORD: none          ;; An object we will create for loading data 
PRINT-LINE: none      ;; A formatted line to put into FILE-DATA
HEADING-LINE: none    ;; A line of column headings
HYPHEN-LINE: none     ;; Hyphens under column headings
SPACEFILL: func [
    "Left justify a string, pad with spaces to specified length"
    INPUT-STRING 
    FINAL-LENGTH
] [
    head insert/dup tail copy/part trim INPUT-STRING FINAL-LENGTH #" " max 0 FINAL-LENGTH - length? INPUT-STRING
]
;;  -- Not sure if we want to allow for right-or-left justification. 
SPACEFILL-LEFT: func [
    "Right justify a string, pad with spaces to specified length"
    INPUT-STRING
    FINAL-LENGTH
] [
    trim INPUT-STRING
    either FINAL-LENGTH > length? INPUT-STRING [
        return head insert/dup INPUT-STRING " " FINAL-LENGTH - length? INPUT-STRING
    ] [
        return copy/part INPUT-STRING FINAL-LENGTH
    ]
]
HYPHENS: func [
    "Return a string of a given number of hyphens"
    SPACE-COUNT [integer!]
    /local FILLER 
] [
    FILLER: copy ""
    loop SPACE-COUNT [
        append FILLER "-"
    ]
    return FILLER
]

;; [---------------------------------------------------------------------------]
;; [ Create the RECORD sub-object from words provided.                         ]
;; [ Create a heading line by converting the words to strings and putting      ]
;; [ them into a heading line at the spots indicated by the pairs associated   ]
;; [ with the words.                                                           ]
;; [ Put the SITE-NAME, REPORT-TITLE, and HEADING-LINE into the first lines    ]
;; [ of the output file.                                                       ]
;; [---------------------------------------------------------------------------]

OPEN-OUTPUT: func [
    FILEID [file!]
    FIELDLIST [block!]
] [
;;  -- Save the data from the caller.
    FILE-ID: FILEID
    FIELDS: copy FIELDLIST
;;  -- Initialize the output area.
    FILE-DATA: copy []
;;  -- Make an object (RECORD) that the caller will load with data.
    RECORD: make object! []
    foreach [FIELDNAME POSITION] FIELDS [
        RECORD: make RECORD compose [
            (to-set-word FIELDNAME) {""}
        ]
    ]
;;  -- Build a heading line out of the words from the caller.
    HEADING-LINE: copy ""
    loop 256 [append HEADING-LINE " "]
    foreach [FIELDNAME POSITION] FIELDS [
        HEADING-LINE: head HEADING-LINE
        HEADING-LINE: skip HEADING-LINE (POSITION/x - 1)
        change/part HEADING-LINE SPACEFILL to-string FIELDNAME POSITION/y POSITION/y 
    ]
    HEADING-LINE: head HEADING-LINE
    HEADING-LINE: trim/tail HEADING-LINE 
;;  -- Make a line of hyphens under each column heading.
    HYPHEN-LINE: copy ""
    loop 256 [append HYPHEN-LINE " "]
    foreach [FIELDNAME POSITION] FIELDS [
        HYPHEN-LINE: head HYPHEN-LINE
        HYPHEN-LINE: skip HYPHEN-LINE (POSITION/x - 1) 
        change/part HYPHEN-LINE HYPHENS POSITION/y POSITION/y
    ]
    HYPHEN-LINE: head HYPHEN-LINE
    HYPHEN-LINE: trim/tail HYPHEN-LINE
;;  -- Put heading lines into data area.
    append FILE-DATA SITE-NAME
    append FILE-DATA ""
    append FILE-DATA REPORT-TITLE
    append FILE-DATA ""
    append FILE-DATA HEADING-LINE
    append FILE-DATA HYPHEN-LINE
    append FILE-DATA "" 
]

;; [---------------------------------------------------------------------------]
;; [ Close the file by writing the data block to disk.                         ]
;; [---------------------------------------------------------------------------]

CLOSE-OUTPUT: does [
    WRITE/LINES FILE-ID FILE-DATA
]

;; [---------------------------------------------------------------------------]
;; [ Write a print line.                                                       ]
;; [ The operator has set the words in RECORD to values.                       ]
;; [---------------------------------------------------------------------------]

WRITE-RECORD: does [
    PRINT-LINE: copy ""
    loop 256 [append PRINT-LINE " "]
    foreach [FIELDNAME POSITION] FIELDS [
        PRINT-LINE: head PRINT-LINE
        PRINT-LINE: skip PRINT-LINE (POSITION/x - 1)
        change/part PRINT-LINE SPACEFILL RECORD/:FIELDNAME POSITION/y POSITION/y
    ]
    PRINT-LINE: head PRINT-LINE
    PRINT-LINE: trim/tail PRINT-LINE
    append FILE-DATA PRINT-LINE
]

;; [---------------------------------------------------------------------------]
;; [ Allow for double spacing in case the resulting file is used like a        ]
;; [ report, that is, examined visually (which is the original design goal).   ]
;; [---------------------------------------------------------------------------]
SKIP-LINE: does [
    append FILE-DATA ""
]
]

;; -----------------------------------------------------------------------------

76. "Printing" to HTML

Another way to print is to generate an HTML file and let a web browser print it. That could be a lot of work if you have to output the markup as well as the data. If you are willing to accept restrictions on the look of the output, in other words, if you do not insist on things that look really fancy, you can make some functions that wrap your output in some modest HTML markup and let those functions to the markup, while you worry about only the data. The example below shows that, and the documentation is in the comments.

In this example, the "report" has the look of a fixed-format report. It is the job of the caller to produce a fixed-format "print line." Sending that pre-formatted line to the appropriate function wraps it up in the "pre" tags and other appropriate markup.

REBOL [
    Title: "Printing module using HTML"
    Purpose: {A COBOL-like method for printing basic
    text-oriented business reports in an html file with markup
    such that we can get proper page breaks.}
]

;; [---------------------------------------------------------------------------]
;; [ This is a module for primitive printing.                                  ]
;; [ It puts pre-formatted lines of text into an html file that includes       ]
;; [ markup such that if the html file is printed then requested page          ]
;; [ breaks will ge made correctly.                                            ]
;; [---------------------------------------------------------------------------]

;; [---------------------------------------------------------------------------]
;; [ These items are the ones that would have to adjusted for a particular     ]
;; [ installation.  They could be pulled out into a configuration file         ]
;; [---------------------------------------------------------------------------]

HTMPRT-INSTALLATION-NAME: "INFORMATION SYSTEMS"
HTMPRT-FILE-ID: %printfile.html
HTMPRT-REPORT-ID: ""

;; [---------------------------------------------------------------------------]
;; [ "Printing" is going to mean appending a print line to the end of          ]
;; [ this big string.  When we "close" the print "file," this big string       ]
;; [ will be written to a file. Actually putting it on paper will be done      ]
;; [ by reading the file with a web browser and using the browser to print.    ]
;; [---------------------------------------------------------------------------]

HTMPRT-FILE: ""

;; [---------------------------------------------------------------------------]
;; [ Here are some other important items, defined here so we can keep          ]
;; [ track of them.                                                            ]
;; [---------------------------------------------------------------------------]

HTMPRT-PAGE-SIZE: 57
HTMPRT-LINE-COUNT: 0

;; [---------------------------------------------------------------------------]
;; [ This is the html markup we will need to make this work.                   ]
;; [---------------------------------------------------------------------------]

HTMPRT-HEAD-DOC: {
<html>
<head>
<style>
.break {page-break-before: always;}
</style>
<title> <% HTMPRT-REPORT-ID %> </title>
</head>
<body>
}

HTMPRT-HEAD-FIRSTPAGE: {
<h1 align="center"> <% HTMPRT-INSTALLATION-NAME %> </h1>
<pre>
}

HTMPRT-HEAD-NEXTPAGE: {
</pre>
<h1 align="center" class="break"> <% HTMPRT-INSTALLATION-NAME %> </h1>
<pre>
}

HTMPRT-FOOT-DOC: {
</pre>
</body>
</html>
}

;; [---------------------------------------------------------------------------]
;; [ This procedure "opens" the print "file," which means we will clear        ]
;; [ out the string and put some initial printer control characters            ]
;; [ into it.  In this module, "control characters" means the html markup      ]
;; [ to cause the proper page break before each new heading when we print.     ]
;; [---------------------------------------------------------------------------]

HTMPRT-OPEN: does [
    HTMPRT-FILE: copy ""
    append HTMPRT-FILE build-markup HTMPRT-HEAD-DOC
    append HTMPRT-FILE build-markup HTMPRT-HEAD-FIRSTPAGE
    HTMPRT-LINE-COUNT: 0
]

;; [---------------------------------------------------------------------------]
;; [ This procedure "closes" the print "file," which means we will             ]
;; [ put the appropriate closing markukp at the end of the string and          ]
;; [ write it to a file.                                                       ]
;; [---------------------------------------------------------------------------]
HTMPRT-CLOSE: does [
    append HTMPRT-FILE build-markup HTMPRT-FOOT-DOC
    write HTMPRT-FILE-ID HTMPRT-FILE
]

;; [---------------------------------------------------------------------------]
;; [ This procedure causes a page skip by adding a heading line with the       ]
;; [ "break" class so that if we print the page, the browser will eject        ]
;; [ a page.                                                                   ]
;; [---------------------------------------------------------------------------]

HTMPRT-EJECT: does [
    append HTMPRT-FILE build-markup HTMPRT-HEAD-NEXTPAGE
    HTMPRT-LINE-COUNT: 0
]

;; [---------------------------------------------------------------------------]
;; [ This procedure "prints" a line passed to it, which means we will          ]
;; [ append the passed line to the file, and add a newline.                    ]
;; [ The refinement of "double" puts an extra newline at the end for           ]
;; [ double spacing.                                                           ]
;; [---------------------------------------------------------------------------]

HTMPRT-PRINT: func [
    HTMPRT-PRINT-LINE
    /DOUBLE
] [
    append HTMPRT-FILE HTMPRT-PRINT-LINE
    append HTMPRT-FILE newline
    HTMPRT-LINE-COUNT: HTMPRT-LINE-COUNT + 1
    if DOUBLE [
        append HTMPRT-FILE rejoin [<br> newline]
        HTMPRT-LINE-COUNT: HTMPRT-LINE-COUNT + 1
    ]
]

;; [---------------------------------------------------------------------------]
;; [ The procedures below use the procedures above for printing in a           ]
;; [ classic COBOL manner.  They print headings automatically, checks for      ]
;; [ page skips, and so on.                                                    ]
;; [ The caller of this module should "do" it early in the program to define   ]
;; [ the items below, and then set the following items to desired values:      ]
;; [ LP-PROGRAM:  Name of the program making the report.                       ]
;; [ LP-REPORT:   50-character report description.                             ]
;; [ LP-SUBTITLE: not used until we figure out how to center it.               ] 
;; [ What these procedures are going to give you is a report of text lines     ]
;; [ in a fixed-width font, like the line printer of the COBOL days.           ]
;; [---------------------------------------------------------------------------]

;; -- Items to be loaded before first use
HTMPRT-LP-PROGRAM: ""
HTMPRT-LP-REPORT: ""
HTMPRT-LP-SUBTITLE: ""
HTMPRT-LP-PAGE-COUNT: 1
HTMPRT-LP-TITLE: copy HTMPRT-INSTALLATION-NAME 
HTMPRT-LP-HEADING-1: ""
HTMPRT-LP-HEADING-2: ""
HTMPRT-LP-USER-HEADING-1: ""
HTMPRT-LP-USER-HEADING-2: ""
HTMPRT-LP-USER-HEADING-3: ""
HTMPRT-LP-USER-HEADING-COUNT: 0
HTMPRT-LP-PROG-LGH: 0
HTMPRT-LP-REPT-LGH: 0
HTMPRT-LP-PROG-20: ""
HTMPRT-LP-REPT-50: ""

;; -- Helper functions for the main printing functions
HTMPRT-SUBSTRING: func [
    "Return a substring from the start position to the end position"
    INPUT-STRING [series!] "Full input string"
    START-POS    [number!] "Starting position of substring"
    END-POS      [number!] "Ending position of substring"
] [
    if END-POS = -1 [END-POS: length? INPUT-STRING]
    return skip (copy/part INPUT-STRING END-POS) (START-POS - 1)
]

HTMPRT-FILLER: func [
    "Return a string of a given number of spaces"
    SPACE-COUNT [integer!]
    /local FILLER 
] [
    FILLER: copy ""
    loop SPACE-COUNT [
        append FILLER " "
    ]
    return FILLER
]

HTMPRT-SPACEFILL: func [
    "Left justify a string, pad with spaces to specified length"
    INPUT-STRING
    FINAL-LENGTH
    /local TRIMMED-STRING
           LENGTH-OF-TRIMMED-STRING
           NUMBER-OF-SPACES-TO-ADD
           FINAL-PADDED-STRING
] [
    TRIMMED-STRING: copy ""
    TRIMMED-STRING: trim INPUT-STRING
    LENGTH-OF-TRIMMED-STRING: length? TRIMMED-STRING
    either (LENGTH-OF-TRIMMED-STRING < FINAL-LENGTH) [
        NUMBER-OF-SPACES-TO-ADD: (FINAL-LENGTH - LENGTH-OF-TRIMMED-STRING)
        FINAL-PADDED-STRING: copy TRIMMED-STRING
        loop NUMBER-OF-SPACES-TO-ADD [
            append FINAL-PADDED-STRING " "
        ]
    ] [
        FINAL-PADDED-STRING: COPY ""
        FINAL-PADDED-STRING: HTMPRT-SUBSTRING TRIMMED-STRING 1 FINAL-LENGTH
    ]
]

;; -- Main printing functions 
HTMPRT-LP-PRINT-USER-HEADINGS: does [
    HTMPRT-LP-USER-HEADING-COUNT: 0
    if (HTMPRT-LP-USER-HEADING-1 <> "") [
        HTMPRT-PRINT HTMPRT-LP-USER-HEADING-1
        HTMPRT-LP-USER-HEADING-COUNT: HTMPRT-LP-USER-HEADING-COUNT + 1
    ]
    if (HTMPRT-LP-USER-HEADING-2 <> "") [
        HTMPRT-PRINT HTMPRT-LP-USER-HEADING-2
        HTMPRT-LP-USER-HEADING-COUNT: HTMPRT-LP-USER-HEADING-COUNT + 1
    ]
    if (HTMPRT-LP-USER-HEADING-3 <> "") [
        HTMPRT-PRINT HTMPRT-LP-USER-HEADING-3
        HTMPRT-LP-USER-HEADING-COUNT: HTMPRT-LP-USER-HEADING-COUNT + 1
    ]
    if (HTMPRT-LP-USER-HEADING-COUNT > 0) [
        HTMPRT-PRINT ""
    ]
] 

HTMPRT-LP-OPEN: does [
    HTMPRT-OPEN
    HTMPRT-LP-PAGE-COUNT: 1
    HTMPRT-LP-PROG-LGH: length? HTMPRT-LP-PROGRAM
    either (HTMPRT-LP-PROG-LGH >= 20) [
        HTMPRT-LP-PROG-20: HTMPRT-SUBSTRING HTMPRT-LP-PROGRAM 1 20
    ] [
        HTMPRT-LP-PROG-20: HTMPRT-SPACEFILL HTMPRT-LP-PROGRAM 20
    ]
    HTMPRT-LP-REPT-LGH: length? HTMPRT-LP-REPORT
    either (HTMPRT-LP-REPT-LGH >= 50) [
        HTMPRT-LP-REPT-50: HTMPRT-SUBSTRING HTMPRT-LP-REPORT 1 50
    ] [
        HTMPRT-LP-REPT-50: HTMPRT-SPACEFILL HTMPRT-LP-REPORT 50
    ]
    HTMPRT-LP-HEADING-1: rejoin [
        HTMPRT-LP-PROG-20
        HTMPRT-FILLER 43
        HTMPRT-LP-TITLE
        HTMPRT-FILLER 52
        now/date
    ]
    HTMPRT-LP-HEADING-2: rejoin [
        HTMPRT-LP-REPT-50
        HTMPRT-FILLER 13
        HTMPRT-FILLER 39    ;; subtitle, eventually
        HTMPRT-FILLER 52
        "Page "
        to-string HTMPRT-LP-PAGE-COUNT
    ]
    HTMPRT-PRINT HTMPRT-LP-HEADING-1
    HTMPRT-PRINT/DOUBLE HTMPRT-LP-HEADING-2
    HTMPRT-LP-PRINT-USER-HEADINGS
]

HTMPRT-LP-CLOSE: does [
    HTMPRT-CLOSE
]

HTMPRT-LP-PRINT: func [
    HTMPRT-LP-PRINT-LINE
    /DOUBLE  ;; not used at this time 
] [
    if (HTMPRT-LINE-COUNT >= HTMPRT-PAGE-SIZE) [
        HTMPRT-LINE-COUNT: 0
        HTMPRT-LP-PAGE-COUNT: HTMPRT-LP-PAGE-COUNT + 1
        HTMPRT-LP-HEADING-2: copy ""
        HTMPRT-LP-HEADING-2: rejoin [
            HTMPRT-LP-REPT-50
            HTMPRT-FILLER 13
            HTMPRT-FILLER 39    ;; subtitle, eventually
            HTMPRT-FILLER 52
            "Page "
            to-string HTMPRT-LP-PAGE-COUNT
        ]
        HTMPRT-EJECT
        HTMPRT-PRINT HTMPRT-LP-HEADING-1 
        HTMPRT-PRINT/DOUBLE HTMPRT-LP-HEADING-2
        HTMPRT-LP-PRINT-USER-HEADINGS
    ]
    HTMPRT-PRINT HTMPRT-LP-PRINT-LINE
]