The reader had stumbled across something called the "ESPOL Loader Card," which was a one-card binary loader used to bootstrap object programs that were written to punched cards by the ESPOL compiler. This bootstrap is described in a couple of Burroughs documents, notably the B5500 Operation Manual and the B5500 MCP Reference Manual, both available as scanned PDFs from bitsavers.org.
I gave the reader those references, but he came back shortly thereafter with some questions on how the loader worked. This was something I had been curious about myself, so decided to dig into it and try to completely understand that program. It took me a few evenings, but I was finally able to satisfy myself that I understood how this loader worked, and replied back to the reader with my findings.
This turned out to be a very interesting exercise, and I thought that others might also find it interesting, so I have reworked that original correspondence into this blog post. This is a highly technical subject, to say the least, so those not used to low-level bit twiddling may want to shield their eyes. Those who want to follow the workings of the individual instructions can find useful descriptions in the B5500 Reference Manual, and truely gruesome ones in the B5281 Processor Training Manual.
The loader is pretty simple, really, but some of the coding is crafty, and it turns out that you have to know something about how the ESPOL compiler generates card-load program decks. I had seen (but not tried to understand) the code that does that generation while working on porting ESPOL to the ESPOLXEM cross-compiler, so that prior experience turned out to be highly advantageous for this exercise.
Before we begin, there are a few significant things to note about the B5500 architecture when looking at a program like the ESPOL Loader:
- The B5500 could load programs from either punched cards or drum (and later, the Head-per-Track disk). The mode of loading was determined by the Card Load Select switch on the operator's console. When depressed, this switch caused the system to load from cards; in its normal setting, the system loaded from drum or disk. The choice of drum or disk was hardwired in the I/O Units (channels).
- When the Load button was pressed on the console, most system registers were cleared to zero, particularly A, B, F, L, R, and S in the processor. The exception was C, the instruction word address, which was set to @20. I'll use the ESPOL notation of "@" to indicate octal values. The other major registers are:
- A -- the first (top) top-of-stack register.
- B -- the second top-of-stack register.
- S -- the top-of-stack memory address register, pointing to the word in the stack below the one in the B register. In Character Mode, the S register was repurposed as the destination address register, with the M register being used as the source address register.
- F -- the stack frame register, which points to the base of the current procedure stack frame (activation record) in the stack.
- R -- the PRT (Program Reference Table) address register. This pointed to the global environment for a program. In Algol, that would be the outer block; in COBOL, the Working-Storage Section. The R register had only nine bits, with the low-order six bits of the 15-bit PRT address always taken as zero. In Character Mode, R was repurposed as the TALLY register.
- L -- the instruction syllable register. This was a two-bit register that identified the next syllable within a word to be executed in the code stream. That word was held in the P register. Words were loaded into the P register based on the address in the C register.
- Each of the four possible I/O Units had separate I/O Finish interrupt vector addresses (@27-@32) and addresses to store a result descriptor word (@14-@17).
- Subroutine calls worked as follows:
- The program executed a Mark Stack (MKS) instruction which saved a few processor registers (notably R and F) in a Mark Stack Control Word (MSCW) that was pushed into the stack. At completion, F pointed to the MSCW.
- Any parameters for the subroutine were typically evaluated and pushed into the stack at this point.
- The program then executed an Operand Call (OPDC) or Descriptor Call (DESC) that referenced a Program Descriptor word. The PD principally indicated the address of the subroutine entry point, the code segment's presence in memory, and the mode: Character or Word. The call constructed a Return Control Word (RCW), containing the necessary state not already recorded in the MSCW, including the return address and current F register setting (which was pointing to the MSCW) and pushed that into the stack. At completion, F now pointed to the RCW, and the syllable branched to the entry address.
- Parameters were addressed as negative offsets from F, accessing words in the stack below the RCW.
- Upon exit, the processor restored the register state from the RCW, including the return address and F register setting. From the MSCW now pointed to by the restored value of F, the exit syllable moved F to S (the top of stack address register), restored the rest of the state from the MSCW and branched to the return address. By restoring the value of S, the stack used by the subroutine was automatically cut back to its original position.
|20:0||0104||LITC @21||Entry point for the hardware load -- Literal Call: push a literal @21 into the stack (A register) as the absolute address of the card read descriptor|
|20:1||4411||IIO||Initiate the I/O by storing the A register at address @10, signalling Central Control, and setting A to empty. The I/O Unit picks up the descriptor from that stored address and initiates the I/O asynchronously|
|20:2||0020||LITC 4||Push the number of syllables to branch|
|20:3||4231||BFW||Branch forward 4 syllables to 22:0|
|21||(data)||Card read I/O descriptor: card reader #1 (CRA), 10 words (80 characters), alpha mode, address @44. Note that while the hardware load reads one binary card, the ESPOL Loader reads cards in alpha mode, i.e., the way they would normally be encoded by a keypunch machine.|
|22:0||4455||DIA @44||Dial A to bit 28 (numbered 20 in the Handbook word diagrams)|
|22:1||0211||ITI||Interrogate interrupts and branch to the vector address for the highest-priority one outstanding, if any. If no interrupts are outstanding, fall through to the next syllable.|
|22:2||0020||LITC 4||Push branch offset|
|22:3||4131||BBW||Branch back to 22:0 (loop until interrupt occurs)|
|23||(data)||Character mode program descriptor for the subroutine (starting in the next syllable) that will be called from 43:1, present in memory, character mode, F=0, C=@24|
|24:0||0453||RSA||Entry point of character mode subroutine: recall source address at F-4 (four words below the Return Control Word, or RCW, and in this case, three words below the Mark Stack Control Word, or MSCW) into the M and G registers|
|24:1||0304||RDA||Recall destination address at F-3 (two words below the MSCW) into S and K|
|24:2||0243||CRF||Call the repeat field (transfer count) at F-2 (one word below the MSCW)|
|24:3||0005||TRW||Transfer the designated number of words from source to destination addresses|
|25:0||0000||EXC||Exit character mode, in this case returning to 43:2|
|25:1||0065||TRB 0||Transfer zero bits from A to B (effectively a no-op, except that it sets A empty) [I don't think this and the next two instructions are normally executed, but @24 is the interrupt vector location for Keyboard Request from the SPO, and @23 is the location for I/O Busy, so the branch at 25:3 is probably just a trap for spurious interrupts. Undefined opcodes are no-ops on the B5500, so it's likely that a vector to one of the words above would eventually fall through to the next syllable at 25:2]|
|25:2||0100||LITC @20||Push branch offset|
|25:3||4131||BBW||Branch back to 22:0 to continue looping for interrupts|
|26:0||0110||LITC @22||Push branch offset [Don't know of an interrupt that vectors here, but this is also probably a trap for an unexpected vector]|
|26:1||4131||BBW||Branch to 22:0 to continue looping for interrupts|
|26:2||0055||DIA 0||(traditionally used as a no-op)|
|26:3||0055||DIA 0||another no-op|
|27:0||0000||LITC 0||Interrupt vector location for I/O Unit #1 finished: push a zero|
|27:1||0062||OPDC @14||Operand call: Push a copy of the result descriptor (RD) for I/O Unit #1 at R+@14 = @14 absolute. The R register is still zero after being initialized by the Load button|
|27:2||0050||LITC @12||Push branch offset|
|27:3||4231||FBW||Branch to 32:2 to handle interrupt|
|30:0||0000||LITC 0||Interrupt vector location for I/O Unit #2 finished: push a zero|
|30:1||0066||OPDC @15||Operand call: Push a copy of the result descriptor (RD) for I/O Unit #2 at R+@15 = @15 absolute|
|30:2||0030||LITC 6||Push branch offset|
|30:3||4231||BFW||Branch to 32:2 to handle interrupt|
|31:0||0000||LITC 0||Interrupt vector location for I/O Unit #3 finished: push a zero|
|31:1||0072||OPDC @16||Operand call: Push a copy of the result descriptor (RD) for I/O Unit #3 at R+@16 = @16 absolute|
|31:2||0010||LITC 2||Push branch offset|
|31:3||4231||BFW||Branch to 32:2 to handle interrupt|
|32:0||0000||LITC 0||Interrupt vector location for I/O Unit #4 finished: push a zero|
|32:1||0076||OPDC @17||Operand call: Push a copy of the result descriptor (RD) for I/O Unit #4 at R+@17 = @17 absolute into the stack|
|32:2||7561||DIB @75||Common point for handling an I/O finish interrupt -- Dial B to bit 47 (the low-order bit)|
|32:3||0165||TRB 1||Transfer bit 28 from the result descriptor in A (see the DIA at 22:0) to bit 47 in B (which currently holds the zero pushed at each of the interrupt vector entry points) and mark A empty to delete the RD from the stack.|
|33:0||0010||LITC 2||Push branch offset|
|33:1||0231||BFC||Branch Forward Conditional around the endless loop below to 34:0 if the low-order bit in B is 0 (false), i.e., if bit 28 (20 in the Handbook) in the RD was false, indicating no read-check error occurred on the card read. Since we are reading in alpha mode, false means there were no invalid punches on the card that couldn't be translated to internal character codes|
|33:2||0010||LITC 2||Push branch offset|
|33:3||4131||BBW||Branch back to 33:2 -- an endless loop. The reason for the loop is that there was no way to halt the processor in control state. We come to 33:2 if there was a read-check error, so in that case the loader just gives up and spins here until someone manually halts the system.|
|34:0||0004||LITC 1||To here if a successful card read -- push a 1 as an index for the DESC next. This is the beginning of code that builds parameters in the stack for the character-mode procedure that will be called at 43:1.|
|34:1||0107||DESC @21||Descriptor call: push a copy of the word at
R+@21 (@21 absolute) into the stack. Since that word looks
like a present data descriptor with a non-zero length field,
things get really interesting. The descriptor must be
indexed by the value just below it in the stack (the 1 just
pushed there by the LITC). The DESC syllable does that automatically First, the index is checked
against the length field, but 0 <= 1 < length, so
we're okay; otherwise we would get an Invalid Index
interrupt set (if we were in Normal State, that is). Next,
the base address in [33:15] of the descriptor in B is
indexed by adding (modulo 15 bits) the 1 in A to it. The
length field [8:10] in the word is set to zero, indicating
this copy descriptor points to a specific word address
instead of an array of words. This is effectively an
absolute address, and it's left in the stack as the
operation's result. Note that it points to the second word
in the 10-word card read buffer, so I'll refer to it as
Note: This word in the stack becomes the parameter for the source address at F-4 used by the character-mode procedure called at 43:1.
|34:2||2025||DUP||Duplicate the indexed descriptor in the stack.|
|34:3||0044||LITC @11||Push @11 (9) into the stack as an index for the OPDC, next|
|35:0||0106||OPDC @21||Operand call: push another copy of the word at R+@21 into the stack. Since it still looks like a present data descriptor with a non-zero length field, OPDC indexes it by the 9 just below it. Instead of leaving the address in the stack, though, OPDC fetches the word at the indexed address (@44+@11 = @55, the last word in the 10-word buffer) and replaces the descriptor with a copy of that word's contents (I'll refer to this value as BUF). Thus OPDC works somewhat like "load" on other machines and DESC works somewhat like "load address".|
|35:1||2025||DUP||Duplicate the value of BUF|
|35:2||3355||DIA @33||Dial A to bit 21|
|35:3||4061||DIB @40||Dial B to bit 24|
|36:0||2565||TRB @25||Transfer 21 bits from A (the dup of BUF) to B (the original copy of BUF) and delete the dup.|
|36:1||2025||DUP||Duplicate the word just updated|
|36:2||2265||TRB @22||Transfer 18 bits from the dup word to the updated original word and delete the dup. What these next DUP/TRB sequences do is convert 6-bit character codes to 3-bit octal digits to form an absolute memory address in the low-order end of the word. See below for details.|
|36:3||2025||DUP||Duplicate the newly updated word again|
|37:0||1765||TRB @17||Transfer 15 bits from the dup word to the updated original word and delete the dup.|
|37:1||2025||DUP||Duplicate the newly updated word again|
|37:2||1465||TRB @14||Transfer 12 bits from the dup word to the updated original word and delete the dup. This is the last of the octal-to-binary conversion|
|37:3||5355||DIA @53||Dial A to bit 33 (start of the address field in the updated copy of BUF)|
|40:0||5361||DIB @53||Dial B to bit 33 (start of the address field in the dup of the indexed descriptor pointing to BUF)|
|40:1||1765||TRB @17||Transfer the 15-bit address field from the
updated copy of BUF to the dup of the indexed descriptor
referencing BUF and delete the updated copy of BUF.
The resulting descriptor in the top of stack is now pointing to a memory address that was
constructed from fields in BUF.
Note: This word in the stack becomes the parameter for the destination address at F-3 used by the character-mode procedure.
|40:2||0000||LITC 0||Push a zero into the stack to begin constructing the third parameter, the transfer count.|
|40:3||0044||LITC @11||Push another 9 into the stack to be used as an index|
|41:0||0106||OPDC @21||Index the I/O descriptor again and load a copy of BUF into the stack|
|41:1||2025||DUP||Duplicate the copy of BUF|
|41:2||1555||DIA @15||Dial A to bit 11|
|41:3||2261||DIB @22||Dial B to bit 14|
|42:0||0165||TRB 1||Transfer one bit, i.e., B:=B&A[14:11:1] (or equivalently, B.[14:1]:=A.[11:1]), and delete the dup copy of BUF. This is another character-to-octal conversion. There is a two-character count of words on the card in the second and third characters of BUF. The value can't be more than eight, since that's the maximum number of words that fit on a card (see the discussion on ESPOL below), so only the low-order bit of the high-order character can be significant (8=@10).|
|42:1||2255||DIA @22||Dial A to bit 14|
|42:2||7261||DIB @72||Dial B to bit 44|
|42:3||0465||TRB 4||Transfer 4 bits from bit 14 in A (from the
last TRB result) to the low-order 4 bits of B (the zero
pushed at 40:2).
Note: This word in the stack becomes the the parameter for the transfer count at F-2 used by the character-mode procedure.
|43:0||0441||MKS||Construct and push a Mark Stack Control Word (MSCW) in preparation for calling a procedure. On entry to the procedure, this word will be at F-1.|
|43:1||0116||OPDC @23||Construct and push a Return Control Word (RCW) with
a return address of 43:2 and call the Character Mode
procedure using the program descriptor at R+@23 (@23 absolute).
On entry to the procedure, F points to the RCW. Note that
the behavior of OPDC is based primarily on the type of word
it finds at the relative address, not anything in the opcode
it self -- a very B5500 thing to do. Also notice that there
is no code to save or restore register state on entering and
exiting the subroutine -- all of that is completely
That procedure (entry point at 24:0) transfers a number of words from a source address to a destination address. The count of words is in the stack just below the MSCW, the destination address below that, and the source address below that. These will be addressed using negative offsets from F, which points to the RCW pushed by the OPDC procedure-call syllable. Typically parameters are pushed into the stack between the MSCW and RCW, but character-mode routines are unusual in that they sometimes address the stack directly below their stack frame.
|43:2||0500||LITC @120||Push the branch offset|
|43:3||4131||BBW||Branch to 20:0 to read another card|
If you were watching the stack closely, you would have noticed that the parameters for the character-mode procedure are below the MSCW, so they don't get cut back when that procedure exits, as normally happens with parameters that are pushed between the MSCW and RCW. So does the stack just grow? That's problematic, as it starts at address 0, so we'd process only about five cards before the stack ran into our loader routine at @20. This had me puzzled until I recalled that servicing an interrupt (which is what the ITI syllable does, even in control state) unconditionally sets S to @100. Thus, every time we read a card, the top of stack gets reset to address @100.
The reason for the weird sequence of DUPs and TRBs starting at 35:1 has to do with the format of a card load deck. I noticed the code to create this format when I was working on ESPOLXEM, but didn't pay much attention to it. When puzzling over what was going on with BUF, that piece of the compiler popped into my mind, and it provided a major clue.
The hardware load function reads this loader card in binary mode, which can hold up to 20 words. The deck produced by ESPOL is in alpha mode, however, and contains a maximum of eight words per card. The first word (8 characters) of the card are zero and are ignored by the loader (I suspect these could have been used to hold sequence numbers or something similar). The payload is in the next eight words. Word 9 (zero relative) holds a control word, as the relevant snippit from ESPOL compiler below shows, building the value of ELBAT:
This occurs at the very end of code generation for the program. The DO loop in the first five lines writes out the code. Word 9 looks like this:09432000 BEGIN ELBAT~0; I~16; 09433000 DO BEGIN MOVE(8,SAVINFO[I.LINKR,I.LINKC],ELBAT); 09434000 ELBAT~B2D(I+96)&1[11:47:1]&(I+96)[23:35:1]; 09435000 WRITE(DECK,10,ELBAT[*]); 09436000 END UNTIL I~I+8}SAVNDX; 09437000 FILL ELBAT[*] WITH 0, 09438000 OCT7500000000000012, 09439000 OCT0004535530611765, 09440000 OCT7006000404210435, 09441000 OCT7700000000000015, 09442000 OCT0253010477527705, 09443000 OCT0051000004410046, 09444000 OCT0441070001000062, 09445000 OCT0040413100000000, 09446000 OCT0001000000000101; 09447000 WRITE(DECK,10,ELBAT[*]); 09447010 ELBAT ~0&REAL(DECKTOG)[1:19:17]; 09447020 FOR I ~ 0 STEP 1 UNTIL Q DO 09447030 BEGIN K ~ STACKHEAD[I].[23:15]; 09447040 M ~ STACKHEAD[I].[38:10]; 09447050 FOR J ~ 0 STEP 8 UNTIL M DO BEGIN 09447060 MOVE(8,INFO[(J+K).LINKR,(J+K).LINKC], 09447070 ELBAT ); 09447080 ELBAT ~ B2D(J)&"310"[1:31:17]; 09447090 WRITE(DECK,10,ELBAT[*]) END; 09447100 END; 09448000 END END END PROGRAM;
- Bits [24:24] (the low-order 24) are the address+96 where this data should be loaded, as four octal characters. The six-bit character codes for the numeric digits are the same as their binary codes (e.g., "0" = @00, "4" = @04, etc.), so to convert from character codes to binary, all we need to do is remove the high-order 0 digit in each character and pack the low-order digits together.
- Bit [11:1] is set to 1. This appears to be setting the number of words on the card to 8 in the second and third characters of the word, but expressed in octal like the addresses above. "10" = @0100, so just one bit needs to be set.
- Bit [23:1] contains the value of (address+96).[35:1]. This appears to be the 13th bit of the biased address, so the full address (expressed in characters as octal) is probably in [18:30] (i.e., the low-order five characters of the word).
One of the smallest ESPOL programs we have is KERNEL, a bootstrap for the MCP that was stored on disk. I've enclosed at the end an octal dump of the DECK output from a compile of that program using ESPOLXEM, so you can see what the data looks like. You can compare this data to the code listing of the program at bitsavers.org.
What the TRBs starting at 36:0 do is compress the leading zero octades out of the character codes of the address to form a binary number. For example, if the address is @03160, this would be represented on the card as "03160" or @0003010600, and the progression of the DUP/TRB sequences would produce the following successive results (only the low-order 30 bits of the word are shown):
|0003010600||Initially, as read from word  of the card: "03160" in alpha|
|0000301060||After TRB @25 at 36:0|
|0000030160||After TRB @22 at 36:2|
|0000003160||After TRB @17 at 37:0|
|0000003160||After TRB @14 at 37:2 (the high order character is 0, so there's no apparent change).|
The low-order 15 bits of this result are eventually used as the destination address by the character-mode move procedure. That relocates the data from BUF through BUF at memory locations @45-@54 to the address specified by BUF for the number of words also specified by BUF.
It helps to draw little pictures of the stack as you are studying code like this. After 40 years of working with stack machines, I still need to do that for all but the simplest cases, and I certainly did for this one.
The one remaining piece of this puzzle is, how does this program terminate? Thus far, we've seen that a read-check exception will stop it cold, but hopefully that doesn't happen. All other I/O exceptions appear to be ignored, so for example, if the card reader goes not ready (jams or is out of cards), the RD will probably contain a "not ready" exception. The loader ignores that and just keeps on truckin', moving the data from the card read buffer (which hasn't changed) to the appropriate destination address memory (which also hasn't changed), until finally the reader starts working again and the loader sees new data. It's crude, but since the processor does not have any way to idle, it's effective.
I think the answer to termination lies in what the ESPOL compiler outputs after the generated code for the program -- an extra card, as shown starting at line 09437000 in ESPOLXEM. The FILL statement just moves literal values into an array, and the WRITE statement outputs it to the card deck. Those octal constants are interesting -- they are the exactly code for the ESPOL Transfer Card, another one-card loader documented in the MCP Operation and MCP Reference manuals cited above. Note in particular the load address in the last word of the array (and the last word of the octal dump below) -- 8 words at address @11. That means the data on that Transfer Card will overlay locations @11-@20 -- that last being the first word of the code for the ESPOL loader, which will now contain a branch to 16:2.
Thus, after the ESPOL Transfer Card is read from the deck and loaded at @11, the ESPOL Loader blithely branches back to 20:0 to initiate the I/O for the next card, only to find the IIO syllable isn't there anymore, having been replaced by a branch into the Transfer Card's code. Very sneaky.
The Transfer Card program is equally sneaky. It calls two procedures, a word-mode one that constructs an MSCW and stores it at address 1 absolute, and also arranges for F to point to address 1 when the routine exits (this is required for proper stack linkage in the just-loaded program). The second is a character-mode procedure that slides 3969 (63*63) words from address @160 to @20 -- a difference of @140 (96) words, matching the bias the ESPOL compiler added to the addresses in BUF. That second procedure is called from address 17:3, so it returns to address 20:0 -- which was just overlaid by the first word of the 3969-word sliding move. Effectively that second procedure exits into the entry point of the program that had just been loaded and relocated downwards in memory.
The technique of having initialization code exit into the entry point of whatever it's initialized is a common one in the B5500, and continues to be used in the Unisys MCP today.
The remainder of the code emitted by the ESPOL compiler after writing out the ESPOL Transfer Card appears to be some sort of stack initialization code, but it apparently isn't effective in the case of KERNEL, so I can't be sure just what is being output there, or (since it's after the Transfer Card) how it would get loaded.
Finally, here is the octal dump of the DECK output for the KERNEL program. Each line of text represents one 10-word card image:
0000000000000000 0740623100000000 0000000000000000 0211101607302231 0004613100000000 0000000000000000 0014613100000000 0020613100000000 0060202102350000 0001000000010600 0000000000000000 0064202102350000 0070202102350000 0074202102350000 0000000000000000 0050613100000000 0000000000000000 0060613100000000 0064613100000000 0001000000010700 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0001000000020000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0001000000020100 0000000000000000 0000000000000000 0534623100000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0001000000020200 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0001000000020300 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0001000000020400 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0001000000020500 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0001000000020600 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0001000000020700 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0001000000030000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0001000000030100 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0001000000030200 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0001000000030300 0000000000000000 5000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 7660000000000022 7560000000000371 7560000000000400 0001000000030400 0000000000000000 0400001421410230 1003014102301003 0141202111120055 0101102510211003 0141000010250421 0211023010030141 2021111600550225 0024223102301003 0001000000030500 0000000000000000 0141000010250421 0044613100550055 0000000000010000 0000000000070000 0004101441211020 2021062001411003 0141777462551261 1265101004210204 0001000000030600 0000000000000000 1003014110102021 5355304510250421 0204100301412021 1003014102001025 0421021010030141 0064102504210441 1642005502041003 0141202154251032 0001000000030700 0000000000000000 0000442504740231 0224100301410004 1012045510451025 0421020410030141 2021100301411646 0055022410030141 2021745550610265 1025042104411652 0001000000040000 0000000000000000 0055020410030141 2021542510320051 0204100301412021 1003014116560055 0224100301412021 7455506102651025 0421044116520055 0204100301412021 0001000000040100 0000000000000000 5425103200510210 1003014102101003 0141202102241003 0141202100240401 0101102504210204 1003014120211003 0141000010250421 0220100301410441 0001000000040200 0000000000000000 0204100301412021 1662005501411032 1025042102201003 0141202100004425 0024213100041003 0141001010121025 0421021410030141 0004101210250421 0001000000040300 0000000000000000 0210100301412021 1012100304211002 0004100301412021 4125004022310230 1003014116660055 1025042102341003 0141167200551025 0421024010030141 0001000000040400 0000000000000000 1676005510250421 0441170200551032 0051000000140131 0200100301410444 1025042104411706 0055023010030141 2021021510360200 1003014100501025 0001000000040500 0000000000000000 0421044117120055 0230100301412021 0215103602001003 0141000010250421 0441171600550230 1003014120210215 1036023010030141 0230100301412021 0001000000040600 0000000000000000 0200010110250421 0064100301411722 0055102504210070 1003014117260055 1025042100741003 0141173200551025 0421100200100301 1003042110020224 0001000000040700 0000000000000000 1003014120217455 2461026502141003 0141202174552261 0265100304210004 0014214100000010 2141006410030141 4231000401042231 0024413100550055 0001000000050000 0000000000000000 0140004000000000 0000000000004060 0140000100000000 0000000000006060 0140000040100000 3145652143312460 2124245125626260 2646516044234737 0001000000050100 0000000000000000 0740000000000046 0140000047704235 0140000047700473 0140000041200017 0441023201004441 0253010453527705 3705005101002411 0000102642314006 0001000000050200 0000000000000000 0235000000000000 0000700744110220 1003014104411022 1025042102201003 0141202141552345 4004042140060024 0415000044250140 0131400602350000 0001000000050300 0000000000000000 0441100202001003 0141202101017006 5355304544410222 0104106601007006 1003014120210555 1045003402317006 0060715503610565 7004042102201003 0001000000050400 0000000000000000 0141044170061032 1025042102201003 0141202100004425 0100013104350000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0001000000050500 0000000000000000 7500000000000012 0004535530611765 7006000404210435 7700000000000015 0253010477527705 0051000004410046 0441070001000062 0040413100000000 0001000000000101