User Tools

Site Tools


magazines:chacking9

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

magazines:chacking9 [2015-04-17 04:34] (current)
Line 1: Line 1:
 +<​code>​
 +                   ########​
 +             ##################​
 +         ###### ​           ######
 +      #####
 +    #####  ####  ####      ##      #####   #### ​ ####  ####  ####  ####   #####
 +  #####    ##    ##      ####    ##   ## ​  ## ​ ###     ## ​   ####  ##   ## ​  ##
 + ##### ​   ######## ​    ## ​ ##   ## ​       #####       ## ​   ## ## ##   ##
 +#####    ##    ##    ######## ​ ##   ## ​  ## ​ ###     ## ​   ##  ####   ## ​  ##
 +#####  ####  ####  ####  ####  #####   #### ​ ####  ####  ####  ####   ######​
 +#####                                                                     ##
 + ###### ​           ###### ​          Issue #9
 +   ################## ​           Jan. 24, 1995
 +       ########​
  
 +------------------------------------------------------------------------------
 +</​code>​
 +====== Editor'​s Notes ======
 +<​code>​
 +by Craig Taylor
 +
 +And *drum beat please* here's another issue of Commodore Hacking!! We've
 +lasted longer and had more issues put out than some other magazines I won't
 +discuss (*wondering where issue 39 of that mag is*).
 +
 +Not many Commodore notes this time - things have gotten a little bit more
 +montatenous(sp - it's late) on the Commodore front.
 +
 +I was unable to get an article by Craig Bruce in time but I got the next
 +best thing: An interview with him!! Users of his software may find this
 +interview interesting in how he looks at programming.
 +
 +Right now I'm entertaining the thought of dropping C= Hacking after I
 +graduate which will be sometime around July 1st of this year. I'm interested
 +in somebody who would "carry the reign" so to speak, and take over my job of
 +nagging, bugging people etc :-) to write articles. I've got my system fairly
 +automated in handling requests here - if that person has a VAX account then
 +I could set them up with a mailserver, if a UNIX account then there'​s oodles
 +of them floating on the net that could be used. _PLEASE_ write to me and
 +lemme know if you're interested. I'm going to try to get one more issue of
 +Commodore Hacking out before July 1st.
 +
 +===========================================================================
 +
 +Please note that this issue and prior ones are available via anonymous FTP
 +from ccosun.caltech.edu (amongunders) under /​pub/​cbm/​hacking.mag and via a
 +mailserver which documentation can be obtained by sending mail to
 +"​duck@pembvax1.pembroke.edu"​ with a subject line of "​mailserver"​ and the
 +lines of "​help"​ and "​catalog"​ in the body of the message.
 +
 +===========================================================================
 +Legal Mumbo-Jumbo
 +
 +Permission is granted to re-distribut3e this "​net-magazine",​ in whole,
 +freely for non-profit use. However, please contact individual authors for
 +permission to publish or re-distribute articles seperately. A charge of no
 +greater than 5 US dollars or equivlent may be charged for library service /
 +diskettte costs for this "​net-magazine"​.
 +
 +===========================================================================
 +</​code>​
 +====== In This Issue ======
 +<​code>​
 +
 +Commodore Trivia Corner
 +
 +This edition of Commodore Trivia Corner contains the answers to the July
 +edition of trivia ($070 - $07F), the questions and answers for August ($080 -
 +$08F), September ($090 - $09F), October ($0A0 - $0AF), November ($0B0 - $0BF),
 +and the questions for the December edition ($0C0 - $0CF). ​ Enjoy them!
 +
 +A Different Perspective,​ part II
 +
 +This month George and Steve continue their series on 3D graphics on the C-64
 +with a look at hidden faces and filled faces. ​ In addition to adding these
 +features into last month'​s program some other improvements to the old program
 +will be discussed, such as fast multiplication (around 24 cycles) and various
 +bug fixes -- for instance, the program now works on older C-64's which
 +initialize color RAM to the background color when the screen is cleared (sorry
 +about that ;-).  A very primitive form of texture mapping is also included. As
 +usual, full source and executables are included. ​ The native C64 files are in a
 +Lynx archive, so you will obviously need Lynx to get at them -- check your
 +favorite BBS or FTP site.
 +
 +2D Graphics Toolbox: Circles
 +
 +To augment three-dimensional algorithms this series will focus on
 +two-dimensional drawing algortihms. ​ Circles are the subject this
 +time around (heh -- get it?), and a very fast algorithm for drawing
 +them on your C64 is presented, with examples in assembly and BASIC7.0.
 +How fast is fast?  How does 11 cycles per pixel without the use of
 +tables grab ya?
 +
 +AFLI=specs v1.0
 +
 +In AFLI we can get 120 colors in theory (counted like this
 +16!/​(2!*14!)=120). When we put red and blue hires pixels close to
 +each other we get a vision of purple - thanks the television. This article
 +details what AFLI is, how it's used and done.
 +
 +Coding Tricks
 +
 +Included are a series of postings to comp.sys.cbm about neat coding tricks (in
 +machine language) that are interesting and useful.
 +
 +C.S.Bruce Interview
 +
 +An interview with the author of Zed, the ACE os and many other numerous
 +utilities for the Commodore 64/128.
 +
 +Aligning 1541 Drives
 +
 +A discussion regarding Commodore 1541 disk drive alignment procedures, with
 +suggestions.
 +===========================================================================
 +</​code>​
 +====== Commodore Trivia Corner ======
 +<​code>​
 +by Jim Brain (brain@mail.msen.com)
 +
 +Well, it is a new year, and I am sending up a new collection of the
 +Commodore rivia for all to enjoy. ​ If you haven'​t seen this already, the
 +following is a collection of trivia questions that I post to various
 +networks every month. ​ I have collected Trivia Edition #8-13 in this
 +article. ​ As you may know, these questions form part of a contest in which
 +the monthly winner gets a prize (Thanks to my various prize donators).
 +The whole thing is mainly just for fun, so please enjoy.
 +
 +As the new year rolls in, I am happy to report the following:
 +
 +1) As I have gained access to FIDONet, the trivia is now posted to both
 +   the USENET newsgroup COMP.SYS.CBM on the Internet AND the FIDONet echo
 +   CBM every month.
 +
 +2) A number of publications have started publishing the trivia, including
 +   ​Commodore World, and a variety of club newsletters.
 +
 +3) I have moved into my new house (See new address at bottom). ​ While this
 +   may not seem important, the extra room I now have means I can now bring
 +   all of my old CBM machine to the new house and work with them.  Working
 +   with them gives me fodder for more trivia.
 +
 +As always, I welcome any questions (with answers), and encourage people
 +to enter their responses to the trivia, now at #13.  Be sure you get the
 +responses to me by January 12th at noon.
 +
 +
 +Jim.
 +
 +
 +The following article contains the answers to the July edition of trivia
 +($070 - $07F), the questions and answers for August ($080 - $08F), September
 +($090 - $09F), October ($0A0 - $0AF), November ($0B0 - $0BF), and the
 +questions for the December edition ($0C0 - $0CF). ​ Enjoy them!
 +
 +
 +Here are the answers to Commodore Trivia Edition #8 for July, 1994
 +
 +Q $070) On a PET series computer, what visual power-on indication will tell
 +        the user whether the computer has Revision 2 or Revision 3 ROMs?
 +
 +A $070) Revision Level 2 ROMS (the ones with more bugs) power up with:
 +        *** COMMODORE BASIC ***, with '​*'​ in place of the more familiar
 +        '#'​ character.
 +
 +Q $071) The IEEE-488 interface is sometimes called the GPIB interface.
 +        What does GPIB stand for?
 +
 +A $071) General Purpose Interface Bus.  Another name is Hewlett Packard
 +        Interface Bus (HPIB), since HP developed this standard for its
 +        istrumentation device networking.
 +
 +Q $072) Commodore manufactured at least two hard drives with IEEE-488
 +        interfaces. ​ Can you name them?
 +
 +A $072) The Commodore D9060 and D9090. From the cbmmodel.txt file:
 +
 +        * CBM D9060  5 MB Hard Drive, DOS3.0, Off-White, IEEE-488. ​      GP
 +        * CBM D9090  7.5 MB Hard Drive, DOS3.0, Off-White, IEEE-488. ​    GP
 +
 +        The following model has been said to be in existence, though no one
 +        has one on hand to prove it:
 +
 +        * CBM D9065  7.5 MB Hard Drive
 +
 +        And this model may never have made it past the prototype stage:
 +
 +          CBM D9062  Dual D9065.
 +
 +Q $073) Why didn't buyers like the original PET-64?
 +
 +A $073) It looked just like a old-style C-64.  It had a "​home"​ computer
 +        look that the schools didn't care for.  They liked the "​business"​
 +        look of the PET series, so Commodore put refurbished and new 64
 +        motherboards in PET cases and sold them as PET 64s.  The repackaging
 +        suited the schools.
 +
 +Q $074) On a PET Revision 2 ROM, what was the largest single array size that
 +        BASIC could handle?
 +
 +A $074) An array can have a cumulative total of 256 elements. ​ For single
 +        dimension arrays, that means D(0) to D(255), but a 2D array can only
 +        go from DD(0,0) to DD(1,127) etc.  All types of arrays had this
 +        limitation.
 +
 +Q $075) On the stock 1541, data is transmitted one bit at a time.  How many
 +        bits are transferred at a time on the Commodore 1551 disk drive?
 +
 +A $075) 3 bits were transmitted at a time.  I assume that each byte had a
 +        parity bit tacked on for error detection, so it would have taken
 +        3 transfers to transmit a byte of information from the drives.
 +
 +Q $076) On all Commodore floppy disk drives, how fast does the disk spin?
 +
 +A $076) 300 RPM.
 +
 +Q $077) Upon first reading the Commodore 1541 Error channel after turning
 +        on the disk drive, what error number and text is returned?
 +
 +A $077) 73, CBM DOS V2.6 1541, 0, 0
 +
 +Q $078) What error number and text is returned on a 1551?
 +
 +A $078) 73, CBM DOS V2.6TDISK, 0, 0   ​Notice that the new text JUST fits!
 +
 +Q $079) Commodore printers are normally assigned to device #4, but they
 +        can be also used as device #?
 +
 +A $079) #5.  The Commodore 1525 has a switch to do this, but not all printers
 +        have such a switch.
 +
 +Q $07A) What microprocessor is used in the Commodore 1551 disk drive?
 +
 +A $07A) the 6510T. ​ It is a slight variant on the 6510 microprocessor used
 +        on the C64.  Some say it runs at 2 MHz, but the specs drives spec
 +        sheet doesn'​t say.
 +
 +Q $07B) When the VIC-20 was designed, the serial port throughput was roughly
 +        equivalent to the throughput of the IEEE-488 bus?  Why isn't it
 +        very fast in production VICs?
 +
 +A $07B) Let's go back to question $04F:
 +
 +        <begin insert>
 +        Q $04F) What was the primary reason Commodore went to a serial bus
 +                with the introduction of the VIC-20?
 +
 +        A $04F) Jim Butterfield supplied me with this one:
 +
 +                As you know, the first Commodore computers used the IEEE bus
 +                to connect to peripherals such as disk and printer. ​ I
 +                understand that these were available only from one source:
 +                Belden cables. ​ A couple of years into Commodore'​s computer
 +                career, Belden went out of stock on such cables (military
 +                contract? who knows?​). ​ In any case, Commodore were in quite
 +                a fix:  they made computers and disk drives, but couldn'​t
 +                hook 'em together! So Tramiel issued the order: ​ "On our next
 +                computer, get off that bus.  Make it a cable anyone can
 +                manufacture"​. ​ And so, starting with the VIC-20 the serial
 +                bus was born.  It was intended to be just as fast as the
 +                IEEE-488 it replaced.
 +        <end insert>
 +
 +        And here is what Jim Butterfield followed up with:
 +
 +        "​Technically,​ the idea was sound: ​ the 6522 VIA chip has a "shift
 +        register"​ circuit that, if tickled with the right signals (data and
 +        clock) will cheerfully collect 8 bits of data without any help from
 +        the CPU.  At that time, it would signal that it had a byte to be
 +        collected, and the processor would do so, using an automatic
 +        handshake built into the 6522 to trigger the next incoming byte.
 +        Things worked in a similar way outgoing from the computer, too.
 +        We early PET/CBM freaks knew, from playing music, that there was
 +        something wrong with the 6522's shift register: ​ it interfered with
 +        other functions. ​ The rule was:  turn off the music before you start
 +        the tape!  (The shift register was a popular sound generator). ​ But
 +        the Commodore engineers, who only made the chip, didn't know this.
 +        Until they got into final checkout of the VIC-20.
 +
 +        By this time, the VIC-20 board was in manufacture. ​ A new chip could
 +        be designed in a few months (yes, the silicon guys had application
 +        notes about the problem, long since), but it was TOO LATE!
 +
 +        A major software rewrite had to take place that changed the VIC-20
 +        into a "​bit-catcher"​ rather than a "​character-catcher"​. ​ It called for
 +        eight times as much work on the part of the CPU; and unlike the shift
 +        register plan, there was no timing/​handshake slack time.  The whole
 +        thing slowed down by a factor of approximately 5 to 6.
 +
 +        When the 64 came out, the problem VIA 6522 chip had been
 +        replaced by the CIA 6526.  This did not have the shift register
 +        problem which had caused trouble on the VIC-20, and at that time it
 +        would have been possible to restore plan 1, a fast serial bus.  Note
 +        that this would have called for a redesign of the 1540 disk drive,
 +        which also used a VIA.  As best I can estimate - and an article in
 +        the IEEE Spectrum magazine supports this - the matter was discussed
 +        within Commodore, and it was decided that VIC-20 compatibility was
 +        more important than disk speed. ​ Perhaps the prospect of a 1541
 +        redesign was an important part of the decision, since current
 +        inventories needed to be taken into account. ​ But to keep the
 +        Commodore 64 as a "​bit-banger",​ a new problem arose.
 +
 +        The higher-resolution screen of the 64 (as compared to the VIC-20)
 +        could not be supported without stopping the CPU every once in a while.
 +        To be exact: ​ Every 8 screen raster lines (each line of text), the CPU
 +        had to be put into a WAIT condition for 42 microseconds,​ so as to
 +        allow the next line of screen text and color nybbles to be swept into
 +        the chip.(More time would be needed if sprites were being used).
 +        But the bits were coming in on the serial bus faster than that:
 +        a bit would come in about every 20 microseconds! ​ So the poor CPU,
 +        frozen for longer than that, would miss some serial bits completely!
 +        Commodore'​s solution was to slow down the serial bus even more.
 +        That's why the VIC-20 has a faster serial bus than the 64, even though
 +        the 64 was capable, technically,​ of running many times faster.
 +
 +        Fast disk finally came into its own with the Commodore 128."
 +
 +                                 --Jim
 +
 +Q $07C) On Commodore computers, how much RAM is set aside as a tape buffer?
 +
 +A $07C) 192 bytes is used as a tape buffer. ​ Blocks of data on tape are 192
 +        bytes long.
 +
 +Q $07D) On Commodore computers, most every peripheral has a device number.
 +        What is the device number of the screen?
 +
 +A $07D) #3
 +
 +Q $07E) What is the device number of the keyboard?
 +
 +A $07E) #0
 +
 +Q $07F) Commodore computers use 2'​s-complement notation to represent integers.
 +        What is the 2'​s-complement hex representation of the signle byte -1?
 +
 +A $07F) (This was not a Commodore specific question) ​ Commodore computers
 +        use this notation to represent integer quantities. ​ In 2's complement
 +        notation, a -1 looks like 11111111(binary) or $FF(hex).
 +
 +
 +Here are the answers to Commodore Trivia Edition #9 for August, 1994
 +
 +Q $080) During the days of the Commodore 64 and the VIC-20, Commodore
 +        produced at least two Commodore magazines. ​ What were their names?
 +
 +A $080) The magazines were originally called "​Commodore Microcomputers"​ and
 +        "​Power/​Play:​ Commodore Home Computing"​. They never did seem to nail
 +        down the name of the latter as I see "​Power/​Play"​ and
 +        "​Commodore:​ Power/​Play"​ used as the original names as well. Anyway,
 +        Commodore Microcomputers started its life in 1979, whereas
 +        "​Power/​Play"​ started in 1981.  Both magazines were published until
 +        around 1987, when they were merged to form "​Commodore Magazine"​.
 +        Then, around 1990, the magazine was sold to IDG Communications and
 +        was merged into RUN.  RUN was continued for a while, but was finally
 +        pulled out of circulation. ​ Creative Micro Designs purchased the
 +        rights to the magazine, and now Commodore World is being produced by
 +        CMD.  I am not sure how strong (if any) a link there is between
 +        RUN and CW, but some of the same authors write for the new
 +        publication. ​ Just for added info, here are the ISSN numbers:
 +
 +        Commodore Microcomputers (Commodore Magazine) ​  ​0744-8724
 +        Power/​Play:​Commodore Home Computing ​            ​0739-8018
 +        RUN (Commodore/​RUN) ​                            ​0741-4285
 +
 +        "The Transactor"​ is also a correct answer, and info on it is below.
 +
 +Q $081) Back in the PET heyday, another magazine was produced by Commodore
 +        Canada. ​ This magazine was later sold and showed up as a hardware
 +        journal. ​ Name the magazine.
 +
 +A $081) The infamous "​Tarnsactor"​. ​ One of the noted C64 hardware-hacking
 +        magazines, it was originally published by Commodore Canada, before
 +        being sold to an individual named Mr. Hilden. ​ Its ISSN number is
 +        0838-0163. ​ As far as I can tell, this magazine, died many deaths,
 +        but ceased to exist in 1989-90. ​ Its first issue is dated April 30,
 +        1978.
 +
 +Q $082) The Commodore 128 has a VIC-II compatible chip inside it.  Can this
 +        chips be switched for a VIC-II from a Commodore 64?
 +
 +A $082) No!  The newer 128 compatible chip (VIC-IIe) has 8 extra pins to
 +        perform timing functions specific for the 128.  In addition, some of
 +        the registers have extra functions. ​ However, a suitable card
 +        to make it compatible can be made.
 +
 +Q $083) What does the video encoding standard PAL expand to?
 +
 +A $083) Phase Alternating Line is the answer I was looking for, which
 +        describes the video encoding used in Europe, but Programmable Array
 +        Logic is also correct, which describes the family of chips used as
 +        "​glue"​ logic for the C64 I/O and processing chips.
 +
 +Q $084) How many buttons were present on the earliest of Commodore tape decks?
 +
 +A $084) 5: Play, Rewind, Fast-Forward,​ Record, and Stop/​Eject. ​ Later models
 +        separated the stop and eject functions into two buttons.
 +
 +Q $085) Earlier SID chips had a distinctive "​clicking"​ sound that some demo
 +        coders used to an advantage. ​ Commodore subsequently removed the
 +        click, and then later reintroduced it.  When does the telltale click
 +        occur?
 +
 +A $085) When you change the volume of a voice. ​ The voice need not be
 +        outputting anything.
 +
 +Q $086) What does CP/M stand for?
 +
 +A $086) Take your pick:
 +
 +        Control Program/​Monitor
 +        Control Program for Microprocessors
 +        Control Program for Microcomputers.
 +
 +        The last one is considered by many to be most correct.
 +
 +Q $087) What is the highest line number allowed for a program line in
 +        Commodore BASIC V2?
 +
 +A $087) Normally, the user cannot enter a line number higher than 63999.
 +        If you want to be tricky, however, the numbers can be made to go up
 +        to 65535.
 +
 +Q $088) What symbol, clearly printed on the front of a key on the Commodore
 +        VIC, 64, and 128 keyboard, is not available when the lower case
 +        character set is switched in?
 +
 +A $088) The PI symbol. ​ It is [SHFT-UPARROW] in uppercase mode, but becomes
 +        a checkerboard-like character when in lower-case mode.  Unlike the
 +        graphics characters printed on the fronts of the keys, this one is
 +        positioned in the middle of the keycap, and should probably be
 +        accessible in both character sets.
 +
 +Q $089) How do you get the "​checkmark"​ character ?
 +
 +A $089) In lowercase mode, type a shift-@
 +
 +Q $08A) On the PET computers, what memory location holds the Kernal ROM
 +        version?
 +
 +A $08A) It is different from the 64/​128. ​ It is 50003. ​ 0 here indicates old
 +        ROMs, while 1 indicates new ROMs.
 +
 +Q $08B) The Commodore computers have 2 interrupts, called IRQ and NMI.
 +        What does IRQ stand for?
 +
 +A $08B) Interrupt ReQuest. ​ This interrupt is used for things that should
 +        usually be allowed to interrupt the processor. ​ This interrupt can
 +        be masked off by the SEI instruction.
 +
 +Q $08C) What does NMI stand for?
 +
 +A $08C) Non-Maskable Interrupt. ​ Unlike the IRQ, this interrupt cannot be
 +        masked by an instruction. ​ However, some tricks can be used to
 +        mask it.
 +
 +Q $08D) The 6502 line of microprocessors has a number of flags that can be
 +        used to test for certain conditions. ​ One of then is the N flag.
 +        What does it stand for?
 +
 +A $08D) '​N'​ stands for Negative. ​ On instructions that change this flag, it
 +        is set to be equal to bit 7 of the result of the instruction.
 +
 +Q $08E) How about the D flag?
 +
 +A $08E) It stands for decimal mode.  This mode causes certain instructions
 +        to treat a byte as 2 4 bit BCD-coded nybbles.
 +
 +Q $08F) The shorthand for the BASIC keyword PRINT is '?'​. ​ What is the
 +        shorthand equivalent for PRINT#?
 +
 +A $08F) pR is the way to abbreviate PRINT#​. ​ Note that ?# will fail.
 +
 +
 +Here are the answers to Commodore Trivia Edition #10 for September, 1994
 +
 +Q $090) The 6502 has a rich history. ​ It is modeled after another 8-bit
 +        microprocessor. ​ Name the processor.
 +
 +A $090) The 65XX series of processors was modeled after the Motorola 6800.
 +        Motorola hampered the design groups'​ efforts to pursue product
 +        developments using the 6800.  A core group of 8 designers left Motorola
 +        and went to MOS Technologies,​ which was the largest producer of
 +        calculator chips at the time.  MOS decided it was time to go into
 +        the CPU business.
 +
 +Q $091) The 6502 has a older brother that was never produced. ​ Name its
 +        number designation and why it was not produced.
 +
 +A $091) The older brother to the 6502 was the 6501.  The 6501 was
 +        pin-compatible with the 6800, which prompted a suit by Motorola.
 +        Eventually, MOS reached an agreement where they scrapped the 6501
 +        marketing, but were free to market the 6502.
 +
 +Q $092) How many different opcodes are considered valid and "​legal"​ on the
 +        MOS NMOS 6502 line?
 +
 +A $092) 151 opcodes are documented in the NMOS 6502 data book.  The remaining
 +        105 opcodes were not implemented,​ and exist as "​don'​t care" states
 +        in the opcode matrix. ​ That means that some seemingly invalid
 +        opcodes will actually perform pieces of two or more valid opcodes.
 +        Newer CPU systems trap all non-implemented opcode usages, but not
 +        the 6502.
 +
 +Q $093) Every instruction takes at least __ cycles to complete. ​ Fill in
 +        the missing number.
 +
 +A $093) 2.  The architecture assumes that each opcode has two bytes in it and
 +        one byte can be fetched per cycle. ​ For instructions that use only
 +        1 byte, the extra fetched byte (actually the next opcode), is thrown
 +        away.
 +
 +Q $094) Which instructions take more time than necessary as a result of the
 +        answer to Q $093?
 +
 +A $094) Although this is a subjective answer, One could nominate NOP on the
 +        basis that NOP is generally believed to waste one execution cycle on
 +        a particular processor, namely one cycle on the 65XX line.  However,
 +        one can argue that NOP simply means no operation, and has no ties to
 +        length of execution. ​ You be the judge.
 +
 +        All other instructions must take at least two cycles: one for opcode
 +        fetch, one for operation.
 +
 +Q $095) What did MOS Technologies manufacture befor introducing the 650X line
 +        of microprocessors?​
 +
 +A $095) As stated above, it was calculator chips.
 +
 +Q $096) Three companies manufactured the 6502 under a cross-licensing
 +        agreement. ​ Name them.
 +
 +A $096) Rockwell, MOS Technologies,​ and Synertek.
 +
 +Q $097) In NTSC-land, how fast does the 1MHz 6510 in the C64 actually run?
 +
 +A $097) 1.022727143 MHz.  It is derived by taking the main clock frequency
 +        (14.31818MHz) and diving it by 14.
 +
 +Q $098) What about in PAL-land?
 +
 +A $098) 985.248449 kHz.  It is derived by taking the main clock frequency
 +        (17.734472MHz) and dividing it by 18.  Thus the PAL 64 actually runs
 +        slower than the NTSC one.
 +
 +Q $099) Data is latched into the 650X microprocessor on the (rising/​falling)
 +        edge?
 +
 +A $099) Data is latched in to the 65XX on the falling edge of Phi0 (Phi1).
 +        The timing diagram in some books (64 PRG is one) is incorrect.
 +
 +Q $09A) Through the years, the 650X line has changed family numbers, yet
 +        the part has not been changed. ​ (A family number is the upper 2
 +        digits in this case)  Name the other family numbers used by MOS to
 +        denote the 650X line.
 +
 +A $09A) the 75XX line used in the 264 series (Plus/4 and C16), and the 85XX
 +        series used in the C64C and C128 series.
 +
 +Q $09B) Consider the following code:
 +
 +        ldx #10
 +        lda $ff,x
 +
 +        what location does the accumulator get loaded with?
 +
 +A $09B) The answer is location $ff+10 mod 256 = $09.
 +        The answer involves explaining a (mis)features of the NMOS 65XX CPU
 +        line.  The above code instructs the 65XX CPU to use zero-page
 +        addressing mode to load the accumulator. ​ In zero-page addressing, the
 +        address need only be one byte wide ($ff in this case), because the
 +        high byte is considered to be $00.  Now, as humans, we would expect
 +        the CPU would add 10 to 255 ($ff), giving 265 ($109) as the address
 +        to load the accumulator from.  However, the CPU designers decided
 +        that zero-page addressing means that the high byte will be $00 all the
 +        time, no exceptions. ​ If a situation like the above occurs, the
 +        low byte of the addition will be used as the low byte of the address
 +        (9 in this case), but the high-byte will be ZERO.  All zero page
 +        addressing modes work this way.  Note that the CMOS versions of the
 +        6502 do perform the high byte "​fix-up",​ so this behavior is only seen
 +        on the NMOS parts.
 +
 +Q $09C) What about the following?
 +
 +          ldx #10
 +          lda ($ff),x
 +
 +A $09C) This was a trick. ​ The code is trying to use INDIRECT INDEXED indexing
 +        mode using the x register, but that addressing mode can only be used
 +        with the y register. ​ If the code is changed to the following, legal
 +        code:
 +
 +          ldx #10
 +          lda ($ff),y
 +
 +        Then, the above discussion for zero-page addressing holds true here
 +        as well.  The effective address would have been (hi:lo) $100:$0ff, but
 +        is instead (hi:lo) $000:​$0ff. ​ The simple rule is:  zero page means
 +        exactly that.  There is no way to address outside of zero-page with
 +        zero-page addressing.
 +
 +Q $09D) How many CPU clock signal lines does the 650X require to run?
 +
 +A $09D) 1.  The 6501 used two, as the 6800 used two, but the 6502 and
 +        successors only required Phi0 (Phi1). ​ Phi2 was generated on the CPU.
 +
 +Q $09E) Where does the 650X line fetch its first byte from after reset?
 +
 +A $09E) $fffc. ​ The address formed by reading $fffd and $fffc is stuffed into
 +        the IP, and the code is read starting there. ​ $fffc is read first,
 +        since the 65XX line stores addresses in low byte, high byte format.
 +
 +Q $09F) One of the original designers on the NMOS 6502 CPU now heads up
 +        Western Design Center in Arizona, and makes the 65C02 and 65C816
 +        CPU chips. ​ Name him.  Hint: it is not Chuck Peddle!
 +
 +A $09F) Bill Mensch. ​ He hand-designed these newer parts in the 65XX line
 +        in the same manner he and Chuck Peddle and others hand-designed the
 +        6501 and 6502.
 +
 +
 +Here are the answers to Commodore Trivia Edition #11 for October, 1994
 +
 +Q $0A0) In the mid 1980'​s,​ Commodore introduced RAM Expansion Units for the
 +        Commodore 64, 64C, 128, and 128D.  There were three of them.  Give
 +        their model numbers, and what was different among them.
 +
 +A $0A0) The 1700 (128kB), the 1764 (256kB), and the 1750 (512kB). ​ The
 +        1700 and the 1750 were marketed for the 128, while the 1764 was
 +        marketed from the 64 line.
 +
 +Q $0A1) Some of the CIA integrated circuits used on the C64 and C128
 +        computers have a hardware defect. ​ What is the result of this
 +        defect, and when does it occur? (May be more than one, but I need
 +        only one)
 +
 +A $0A1) The only one I have documented in front of me is the timer B
 +        interrupt bug, which is explained in the "​Toward 2400" article
 +        by George Hug in Transactor 9.3. (1)  However, I had many people
 +        relate other bugs (2 and 3), which I haven'​t been able to test, so I
 +        add them as possibilities. (I encourage readers to confirm/​deny the
 +        latter 2.)
 +
 +        1) If timer B of the 6526 CIA times out at about the same time as a
 +           read of the interrupt register, the timer B flag may not be set at
 +           all, and no interrupt will occur if timer B interrupts were
 +           ​turned on.
 +
 +        2) When the hour on the TOD clock is 12, the AM/PM must be reversed
 +           from its normal setting to set/reset the AM/PM flag.
 +
 +        3) The TOD clock sometimes generates double interrupts for alarm
 +           ​trigger.
 +
 +
 +Q $0A2) Name the Commodore machine(s) on which a Intel 8088 was an OPTIONAL
 +        coprocessor. ​ (Hint, not the IBM clones)
 +
 +A $0A2) I was looking for the B series computers, which contains the B
 +        computers (B128, B256), as well as the 600 series and the 700
 +        series. ​ These computers could be fitted with an optional 8088
 +        processor on a separate card.  However, another correct answer is
 +        the Amiga, which can have a 8088 attached via an expansion card or a
 +        SideCar(tm) unit.
 +
 +Q $0A3) On Commodore computers beside the Plus/4 series, there are three
 +        frequencies used to record the data on the tape.  Name the
 +        frequencies used.
 +
 +A $0A3) 1953.125Hz, 2840.909Hz, and 1488.095Hz. ​ These correspond to
 +        waveforms with periods: 512us, 352us, and 672us, respectively.
 +
 +Q $0A4) Commodore Plus/4 series computers can not read any cassettes
 +        recorded on other Commodore computers. ​ Why?  (Hint: It has
 +        nothing to do with the nonstandard connecotr on the Plus/4)
 +
 +A $0A4) The tones recorded on the Plus/4-C16 are exactly one-half the
 +        frequencies shown above. ​ This suggests to many that the Plus/4
 +        and C16 were supposed to run at twice its present frequency,
 +        but were downgraded at the last-minute,​ and the code to generate
 +        the tones was not updated to reflect the change. ​ This is just
 +        heresay, so you decide for yourself.
 +
 +Q $0A5) During power-up, the Commodore 64 checks to see if it running
 +        in PAL-land or NTSC-land. ​ How does it determine its location?
 +
 +A $0A5) It sets the raster compare interrupt to go off at scan line 311.
 +        If the interrupt occurs, we are on a PAL system, since NTSC will
 +        never get to line 311 (NTSC only has 262.5 lines per frame, every
 +        other frame shifted down a bit to create 525 lines).
 +
 +Q $0A6) What is the 65XX ML opcode for BRK?
 +
 +A $0A6) $00, or 00
 +
 +Q $0A7) On the 65XX CPU, what gets pushed onto the stack when an interrupt
 +        occurs?
 +
 +A $0A7) The program counter gets saved high byte first, then the processor
 +        status flags get saved.
 +
 +Q $0A8) Speaking of the stack, where is the stack located in the 65XX address
 +        map?
 +
 +A $0A8) $0100 to $01FF
 +
 +Q $0A9) On the 65XX CPU line, it is possible to set and clear a number of
 +        processor status flags. ​ Examples include SEC and CLC to set and
 +        clear the carry flag.  What flag has a clear opcode, but no set
 +        opcode?
 +
 +A $0A9) The overflow flag: V.  However, the V flag can be set via an external
 +        pin on some members of the 65XX line.  The 1541 uses this as an
 +        ingenious synchronization tool.
 +
 +Q $0AA) When saving a text file to tape, the computer records 192 bytes of
 +        data, an inter-record gap, and then the same 192 bytes of data
 +        again. ​ How wide is this inter-record gap, and why is it there?
 +
 +A $0AA) Some terminology: ​ "​inter"​ means "​between"​. ​ Most everyone knows
 +        that a tape block is recorded twice on the tape, but Commodore
 +        considers the two copies and the gap between them a single
 +        "​record"​. ​ Thus, this question is referring to the gap in between
 +        two dissimilar records. ​ With that in mind,
 +        the interrecord gap is nominally 2 seconds long, (or 223.2 byte
 +        lengths, although the gap contains no data). ​ It is there to allow
 +        the tape motors to get up to speed before the next data comes under
 +        the read/write head.  The tape motors may need to stop between
 +        records if the program is not requesting any more data from the
 +        tape data file at this time.  If the program subsequently asks
 +        for data from the tape, the drive must get up to speed before the
 +        read can occur. ​ Note: on the first version of PET BASIC, the
 +        gap was too small, so programmers had problems retrieving data
 +        files.
 +
 +        For completeness,​ the "​intra-record"​ gap (The one between the two
 +        copies of the data) consists of 50+ short pulses, each of which is
 +        352us in length, giving a timing of .0176s+. ​ This time was used to
 +        copy important data to safe locations, reset pointers, and do error
 +        logging. ​ The entire "​record"​ is recorded in 5.7 seconds.
 +
 +Q $0AB) On an unexpanded VIC-20, where does the screen memory start?
 +
 +A $0AB) $1e00, or 7680
 +
 +Q $0AC) In Commodore BASIC, what is the abbreviated form of the "​Load"​
 +        command?
 +
 +A $0AC) lO (L SHIFT-O)
 +
 +Q $0AD) In Commodore BASIC, what is the abbreviated form of the "​List"​
 +        command?
 +
 +A $0AD) lI (L SHIFT-I)
 +
 +Q $0AE) On the Commodore 64, there is section of 4 kilobytes of RAM that
 +        cannot be used for BASIC programs. ​ It is the favorite hiding
 +        places for many ML programs, however. ​ What is its address in
 +        memory?
 +
 +A $0AE) $c000, or 49152
 +
 +Q $0AF) What is stored at locations $A004-$A00B,​ and why is it strange?
 +
 +A $0AF) The text "​CBMBASIC"​ is stored there. ​ It is strange because this
 +        text is not referenced by any routine. ​ It can also be called
 +        strange because the code is Microsoft'​s. Doesn'​t it make you wonder?
 +
 +
 +Here are the answers to Commodore Trivia Edition #12 for November, 1994
 +
 +Q $0B0) What will happen if you type ?""​+-0 into the CBM BASIC interpreter
 +        on the PET series, the 64 series, or the 128 series?
 +
 +A $0B0) The BASIC interpreter has a bug in it that shows up while interpreting
 +        the above statement. ​ The interpreter leaves two bytes on the CPU
 +        stack prior to returning from a subroutines call.  At least on the
 +        C64, the two bytes are both zeros. ​ Since subroutines put the return
 +        address on the stack, the return retrieves the two bytes left on the
 +        stack and attempts to se that as the return address. ​ So, depending on
 +        what code it executes after the return, it can do a number of things.
 +
 +        Most of the time after the bug occurs, the interpreter limps along
 +        for a while until it hits a BRK instruction,​ $00.  Then, that
 +        instruction causes the system to execute an interrupt. ​ On the C64,
 +        the system vectors through $316-$317 (BRK vector) and does a warm
 +        start. ​ On the C128 and PETs with Monitors, the system dumps into the
 +        internal machine language monitor. ​ If the machine under use did not
 +        do something with the BRK vector, the machine will hang.
 +
 +        Now, note that the above is not the only result. ​ Since the
 +        interpreter is executing code from the wrong location, any result
 +        from no effect to hung machine is possible.
 +
 +        Note that this is NOT normal behavior. ​ The system should report an
 +        error while interpreting the above statement.
 +
 +Q $0B1) In the first CBM 64 units, what color was the screen color RAM
 +        changed to when you cleared the screen?
 +
 +A $0B1) The screen color RAM was changed to value 1 when the screen was
 +        cleared. ​ Thus, when a byte was poked into screen RAM, the resulting
 +        character was white on the screen. ​ The white contrasted nicely
 +        with the normal blue background.
 +
 +Q $0B2) Why was it changed in later versions of the 64?
 +
 +A $0B2) Commodore found that this practice sometimes caused "light flashes"​
 +        during screen scrolls. ​ I was going to leave this for another time,
 +        but ... The change was to make the color RAM equal to background
 +        color register #0.  Well, this got rid of the "light flashes",​ but
 +        then poking values to screen RAM  caused invisible characters, since
 +        the foreground color of the character was the same as the background
 +        color of the screen.
 +
 +        Well, this broke a number of older programs that did not
 +        properly initialize the color RAM. Also, Commodore fixed the problem
 +        with the VIC-II that had caused these "light flashes"​ So, Commodore
 +        changed the KERNAL a third time.  Since the above change caused
 +        invisible characters, Commodore made a third revision that changed
 +        the color RAM to the value in location 646 (the current cursor
 +        foreground color).
 +
 +Q $0B3) What is "​special"​ about the text that displays the "​illegal quantity
 +        error" in CBM BASIC?
 +
 +A $0B3) The text is actually "?​ILLEGAL QUANTITY ​ ERROR"​. ​ Notice the two
 +        spaces between "​QUANTITY"​ and "​ERROR"​. ​ John West supplies the
 +        expanantion:​
 +
 +        "The vector at $0300 points to a routine at $A43A, which is the
 +        general error message printing routine. ​ Load .X with the number of
 +        the error, and it prints it.  it looks up the address of the error
 +        text from a table, then prints the text, which does not have any
 +        trailing spaces. ​ It then prints ' ​ ERROR',​ with *2* spaces. ​ It
 +        does this for all errors."​
 +
 +        Historically,​ this effect is caused by the VIC-20, which only had 22
 +        columns. ​ When the VIC-20 BASIC was being ported from the PET BASIC
 +        code, someone noticed that the some of the error strings would
 +        span two VIC-20 lines. ​ So, the BASIC error messages were changed
 +        a little, so that they all printed neatly on two lines: ​ The PET
 +        error string:
 +           ?​ILLEGAL QUANTITY ERROR (one space) became:
 +           ?​ILLEGAL QUANTITY
 +            ERROR                  (carriage return plus one space).
 +        When the C64 BASIC was being ported from the VIC-20, the carriage
 +        return was replaced with a space character.
 +
 +        I admit this caught me by surprise. ​ I have used Commodore computers
 +        for years, and never noticed that "?​SYNTAX ​ ERROR" had 2 spaces in it.
 +
 +Q $0B4) On what Commodore machine was the operating system OS/9 available?
 +
 +A $0B4) Since OS/9 was a real-time operating system for the 6809
 +        microprocessor,​ it was available on only one Commodore machine, which
 +        had two different names: ​ The Commodore SuperPET. ​ The machine was
 +        sold as the "MMF (Micro MainFrame) 9000 in Germany, and its model
 +        number was SP9000.
 +
 +Q $0B5) Which Commodore machine(s) does not have a user port?
 +
 +A $0B5) There were a number of answers to this question, and there may be
 +        more:
 +
 +        The Commodore C16.  Commodore decided to cut out telecommunications,​
 +        and thus designed the user port out of the computer, as the modem is
 +        the only use Commodore ever made of the user port.  This also
 +        includes the C116, a version of the C16 with a chicklet keyboard.
 +
 +        The Commodore Ultimax/MAX machine. ​ This was the ill-fated game
 +        console produced in the early 80s.  It was basically a stripped down
 +        Commodore 64.
 +
 +        The 64 GS (Game System). ​ This machine was another flop produced
 +        in the late 80s.
 +
 +Q $0B6) How many pins are there in a Commodore Serial Connector?
 +
 +A $0B6) 6.
 +
 +Q $0B7) There are 13 addressing modes available on the 6502. Name them.
 +
 +A $0B7) No# Name                 ​Description
 +        --- ------------ ​        ​-----------
 +        01) accumulator ​         asl a
 +        02) immediate ​           lda #$00
 +        03) zero page            lda $00
 +        04) zero page,​X ​         lda $00,X
 +        05) zero page,​Y ​         lda $00,Y
 +        06) absolute ​            lda $1000
 +        07) absolute,​X ​          lda $1000,X
 +        08) absolute,​Y ​          lda $1000,Y
 +        09) implied ​             clc
 +        10) relative ​            bne
 +        11) (indirect,​X) ​        lda ($00,X)
 +        12) (indirect),​Y ​        lda ($00),Y
 +        13) (absolute indirect) ​ jmp ($1000)
 +
 +Q $0B8) If you were to put one large sequential file onto an 8050 disk drive,
 +        how big could that file be?
 +
 +A $0B8) According to the 8050 User Manual, a sequential file could be
 +        521208 bytes in size.
 +
 +Q $0B9) How many characters can be present in a standard Commodore DOS
 +        filename?
 +
 +A $0B9) 16 characters.
 +
 +Q $0BA) How many pins does a 6502 IC have on it?
 +
 +A $0BA) 40 pins.
 +
 +Q $0BB) How many pins does the standard IEEE-488 connector have on it?
 +
 +A $0BB) 24 pins.
 +
 +Q $0BC) On the IEEE-488 bus, what does the acronym for pin 7, NRFD, stand for?
 +
 +A $0BC) Not Ready For Data.
 +
 +Q $0BD) On the NMOS 6502, what is the ML opcode for SED, and what does this
 +        opcode do?
 +
 +A $0BD) $f8, SEt Decimal mode.  Sets the D flag in the status flags byte.
 +        Although used rarely, this opcode switches on Binary Coded Decimal
 +        mode.  In BCD mode, the byte $10 is treated as 10, not 16.  The add
 +        and subtract instructions are the only legal ones affected by this
 +        mode, although some undocumented/​illegal opcodes are also affected.
 +        For example, in this mode, adding the byte $15 (21) to the byte $25
 +        (37) yields $40 (64) not $3a (58).  emember that, in this mode,
 +        $40 = 40, not 64.
 +
 +Q $0BE) Assuming a PET computer and a non-PET computer have access to a
 +        common disk drive or tape drive, there are two ways to load a PET
 +        BASIC program on the non PET CBM computer. Name them.
 +
 +A $0BE) Most differing series of Commodore computers had different places
 +        for the start of BASIC programs. ​ For instance, on the C64, $0801
 +        (2049) is the start of BASIC memory, but most PET computers start
 +        BASIC memory at $0401 (1025). ​ This wouldn'​t matter, except that
 +        BASIC programs are stored on tape and disk with the start address,
 +        and the line links in a BASIC program have absolute addresses in them.
 +        To fix these problems, the Commodore VIC-20 and newer computers came
 +        out with a "​relocatable load"​. ​ So, here are the two choices:
 +
 +        1)  Save the program on the PET like so: save "​name",​X (X is device).
 +            Then, you could load the program into the non-PET machine
 +            by using a relocatable load: load "​name",​X. ​ This would load the
 +            program in at start of BASIC memory and refigure the line links.
 +
 +        2)  Redefine start of BASIC memory on non-PET machine. ​ A couple
 +            of pokes to relevant BASIC pointers, and the start of BASIC
 +            was moved. Then, load the program non-relocatable.
 +
 +        Now, from the above discussion, it looks like option 1 is the
 +        simplest route. ​ Well, it would be, exept for one small detail:
 +        Earlier PET computers saved the BASIC program from $0400, not
 +        $0401 as is expected. ​ The effect: ​ loading relocatable on a non-PET
 +        would have a zero byte as the first byte of the program. ​ The quick
 +        fix:  change BASIC pointer to itself-1, load PET program, reset
 +        BASIC pointer. ​ Commodore didn't make it easy!
 +
 +Q $0BF) Only one of the ways detailed in $0BE works the other way around.
 +        Which one?
 +
 +A $0BF) Since the earlier PET computers did not have a "​relocatable load",
 +        the only way to load a program from, say, a C64 into an 2001 was to
 +        use option #2 above and move the start of BASIC memory to $0801
 +        (2049).
 +
 +
 +Commodore Trivia Edition #13
 +
 +Q $0C0) The early 1541 drives used a mechanism developed by ______. ​ Name
 +        the company.
 +
 +Q $0C1) On later models, Commodore subsequently changed manufacturers
 +        for the 1541 drive mechanism. ​ Name the new manufacturer.
 +
 +Q $0C2) What is the most obvious difference(s). ​ (Only one difference is
 +        necessary)
 +
 +Q $0C3) On Commodore BASIC V2.0, what answer does the following give:
 +        PRINT (SQR(9)=3)
 +
 +Q $0C4) In Commodore BASIC (Any version) what does B equal after the following
 +        runs: C=0:B=C=0
 +
 +Q $0C5) The first PET cassette decks were actually _______ brand cassette
 +        players, modified for the PET computers. ​ Name the comapny.
 +
 +Q $0C6) In Commodore BASIC (Any version), what happens if the following
 +        program is run:
 +
 +        10 J=0
 +        20 IF J=0 GO TO 40
 +        30 PRINT "​J<>​0"​
 +        40 PRINT "​J=0"​
 +
 +Q $0C7) In question $068, we learned how Jack Tramiel first happened upon the
 +        name "​COMMODORE"​. ​ According to the story, though, in what country
 +        was he in when he first saw it?
 +
 +Q $0C8) On the Commodore user port connector, how many edge contacts are
 +        there?
 +
 +Q $0C9) On most Commodore computers, a logical BASIC line can contain up to
 +        80 characters. ​ On what Commodore computer(s) is this not true?
 +
 +Q $0CA) If a file is saved to a Commodore Disk Drive with the following
 +        characters: chr$(65);​chr$(160);​chr$(66),​ what will the directory
 +        entry look like?
 +
 +Q $0CB) What is the maximum length (in characters) of a CBM datasette
 +        filename?
 +
 +Q $0CC) How many keys are on a stock Commodore 64 keyboard?
 +
 +Q $0CD) Commodore BASIC uses keyword "​tokens"​ to save program space. ​ Token
 +        129 becomes "​FOR"​. ​ What two tokens expand to include a left
 +        parenthesis as well as a BASIC keyword?
 +
 +Q $0CE) There are 6 wires in the Commodore serial bus.  Name the 6 wires.
 +
 +Q $0CF) On the Commodore datasette connector, how many logical connections are
 +        there?
 +
 +Some are easy, some are hard, try your hand at:
 +
 +      Commodore Trivia Edition #13!
 +
 +Jim Brain
 +brain@mail.msen.com
 +602 North Lemen (New address)
 +Fenton, MI  48430
 +(810) 737-7300 x8528
 +
 +==============================================================================
 +</​code>​
 +====== A Different Perspective,​ part II ======
 +<​code>​
 +by George Taylor (aa601@cfn.cs.dal.ca) and Stephen Judd (sjudd@nwu.edu).
 +
 +We... are... VR Troopers! ​ Okay Troopers, once again we need to make an
 +excursion out of the three dimensional world and into our own little virtual
 +world inside the C64.  So sit back in your virtual chair, put on your virtual
 +thinking helmet, maybe grab a virtual beer, and prepare for a virtually
 +useful experience with another virtually humongous article.
 +
 +Last time we laid down the foundations of 3D graphics: rotations and
 +projections. ​ In this article we will build upon this foundation with a look
 +at hidden surfaces as well as filled surfaces. ​ In addition we will snaz up
 +the old program so that it is a little more efficient by for instance
 +introducing a much faster multiplication routine and moving all variables
 +into zero-page.
 +
 +To get us in the mood let's review from last time.  We are in a
 +three-dimensional space; in particular, a right-handed three-dimensional
 +space, so that the x-axis comes towards you, the y-axis increases to the
 +right, and the z-axis increases "​up"​. ​ Now we have some object, centered at
 +the origin.
 +
 +To rotate the object we derived a 3x3 matrix for each axis which describes a
 +rotation about that axis.  After rotating we translate the object along the
 +z-axis and then project it through the origin onto a plane z=constant.
 +
 +As you recall the projection of a point is done by drawing a line from the
 +point through the origin, and then figuring out where this line intersects
 +our plane z=constant. ​ You can think of this line as a ray of light bouncing
 +off the object and through our little pinhole camera lens.
 +
 +Clearly for any solid object some parts of the object will remain hidden,
 +though, i.e. when you look at your monitor you can't see the back of it, and
 +you probably can't see the sides. ​ How do we capture this behavior
 +mathematically?​
 +
 +
 +Hidden Surfaces
 +---------------
 +
 +Imagine our object with some light shining on it -- when will a part of the
 +object be hidden? ​ Clearly it is hidden when the light reflected off of it
 +never reaches our eyes, which happens whenever a part of the object is
 +"​turned away" from us.  How do we express this mathematically?​ Consider a
 +flat plate, like your hand (you also might think of a cube). ​ Now imagine a
 +rod sticking out of the plate, exactly perpendicular to the plate (take your
 +index finger from your other hand, and touch it to your palm at a
 +ninety-degree angle). ​ Now rotate the plate around, and imagine the light
 +bouncing off and heading towards your eyes.
 +
 +No matter where you place your hand in space, the very last point at which it
 +is visible is when it is exactly parallel to the light rays coming from it to
 +your eyes; or, to put it another way, when the light rays are exactly
 +perpendicular to a normal vector to the surface (in the above case this
 +vector is either a rod or your finger). ​ If the angle between the normal and
 +a light ray is less than ninety degrees, then the surface is visible. ​ If
 +greater, then the surface is invisible.
 +
 +At this point you may be wondering how to figure out the angle between two
 +vectors. ​ It turns out we really don't have to calculate it at all: instead
 +we use a very important tool in our mathematical toolbox, the dot product.
 +
 +If we have two vectors v1=(x1,​y1,​z1) and v2=(x2,​y2,​z2) then the dot product
 +is defined to be
 +
 + v1 dot v2 = x1*y1 + x2*y2 + x3*y3
 +
 +note that this is a _scalar_ (i.e. a number), and not a vector. ​ You can also
 +show that
 +
 + v1 dot v2 = |v1|*|v2|*cos(theta)
 +
 +where | | denotes length and theta is the angle between the two vectors.
 +Since cos(theta) is positive or negative depending on whether or not theta is
 +less than or greater than ninety degrees, all we have to do is take the dot
 +product and look at the sign.
 +
 +But we need to understand something about the dot-product. ​ theta is the
 +angle between two vectors joined at their base; mathematically the way we are
 +going to draw the light ray is to draw a line FROM the origin TO a point on
 +the surface. ​ In our model above, we are going to draw a line from your eyes
 +to the palm of your hand and then slide the normal vector down this line
 +until the base of the normal vector touches your eye.
 +
 +The whole point of this is that when we look at the dot product we need to
 +keep in mind that if the dot product is negative, the face is visible.
 +
 +All that remains is to write down an equation: let's say that we've rotated
 +the surface and know a point P=(x,y,z) on the rotated surface, and we have a
 +normal vector to the surface vn=(vx,​vy,​vz). ​ First we need to translate down
 +the z-axis so that P -> (x,y,z-z0) = P - (0,​0,​z0). ​ If we then take the dot
 +product we find that
 +
 + P' dot vn = (P dot vn) - z0*vz
 +
 +But (P dot vn) is simply a constant: because these are rigid rotations the
 +length of P never changes, presumably the length of vn never changes, and the
 +angle between the two never changes. ​ So introduce a constant K where
 +
 + K = (P dot vn)/z0
 +
 +so that all we need to do is subtract the z-component of the normal vector
 +from K and check if it is positive or negative: if negative, the face is
 +visible. ​ Note that if we translate by an amount P + (0,0,z0) (instead of -
 +(0,0,z0)) we simply add the two together.
 +
 +We seem to have left something out here: how do we calculate the normal
 +vector vn?  One way to do it is by using another vector operator, the
 +cross-product. ​ The dot product of two vectors is just a scalar, but the
 +cross product of two vectors is another vector, perpendicular to the first
 +two.
 +
 +The most common way to visualize the cross-product is by using your right
 +hand: imagine two vectors in space, and place your right hand along one of
 +them, with your thumb sticking out.  Now curl your fingers towards the other
 +vector. ​ Your thumb points in the direction of the vector formed from the
 +cross-product of the first two.  You can easily convince yourself then that
 +(A x B) = -(B x A), that is, if you reverse the order of the cross product,
 +you get a vector pointing in the opposite direction.
 +
 +Therefore, if we take any two vectors in the face (in particular, we know the
 +edge of the face), and then take their cross-product,​ we have a normal
 +vector.
 +
 +But because we are dealing with a cube, we have an even easier method! ​ We
 +can use the fact that the faces on a cube are perpendicular to each other: if
 +we take two points and subtract them we get a vector going between the two
 +points. ​ On a cube, this will give us a normal vector if we use two
 +"​opposite"​ points. ​ Therefore all we need to do is rotate the cube, subtract
 +two z-coordinates,​ add to K, and check if it is positive or negative.
 +
 +This is how the program does it, and the specifics will be explained later.
 +Right now I want to show you a second method of hidden surface detection.
 +Instead of using the three-dimensional rotate vectors, what if we use the
 +two-dimensional _projected_ vectors? ​ If we take the cross-product of two of
 +these vectors we get a vector which either points into the screen or out of
 +it, which corresponds to a positive or a negative result.
 +
 +The cross-product is usually done by taking the determinant of a matrix. ​ I
 +am not going to explain that here -- you can look in any decent calculus book
 +for the full cross-product. ​ All we really care about is the z-coordinate of
 +the vector, and the z-coordinate of v1 x v2 is:
 +
 + v1x*v2y - v1y*v2x
 +
 +Whether or not the face is visible depends on how you define v1 and v2!
 +Always remember that (v1 x v2) = -(v2 x v1).
 +
 +What is this quantity anyways? ​ Consider a parallelogram made up of our two
 +vectors v1 and v2.  The magnitude of the cross-product just happens to be
 +
 + |v1|*|v2|*sin(theta)
 +
 +which you can easily see is the area of a parallelogram with sides v1 and v2.
 +For this reason the second method apparently goes by the name SAM -- Signed
 +Area Method. ​ (Now you need to think about the interpretation of the dot
 +product in a similar way).
 +
 +Note that the second method is quite general, while the first method only
 +works for objects which have perpendicular surfaces (at least, in it's
 +current form presented here). ​ On the other hand, the first method is
 +significantly faster.
 +
 +Now that we've hidden the faces, it's time to fill them:
 +
 +
 +Filled Faces
 +------------
 +
 + Q: How do you make a statue of an elephant?
 + A: Start with a block of granite and carve away everything
 +    that doesn'​t look like elephant!
 +
 +The first method of filling faces is very simple in concept. ​ Let's say we
 +want a cube with white faces and black edges. ​ Before, the program would make
 +the buffer black and then draw in the white edges. ​ The idea here is to make
 +the entire buffer white, draw the edges in black, and then make everything
 +outside of the edges black. ​ Quite simply, we start with a solid block and
 +then take away everything that doesn'​t look like a cube!  You can also think
 +of it like a cookie cutter: we press our cube-shaped cutter down and remove
 +all the dough outside of the cutter.
 +
 +This simplistic method actually has some advantages. ​ If the object is very
 +large, we spend very little time doing the actual un-filling. We don't care
 +about how complicated the object is, because we just trace out the edge.
 +Finally, this gives us an extremely easy way of implementing a rudimentary
 +texture-mapping in multicolor mode.  For instance, instead of coloring the
 +block white, what if we used a changing pattern of colors? ​ As long as the
 +edge is a specific color, the pattern can be any combination of the other
 +three colors. ​ An example program which does just this is included -- note
 +that the inititalization program needs to be changed slightly to run this
 +program.
 +
 +In other words, we roll the dough, draw a pattern into it, press our cutter
 +down and remove the outside dough. ​ We are left with a cube with patterns all
 +over it.
 +
 +On the downside it's not quite so easy to do things like have each face a
 +separate color (but who wants wimpy separate colors when you can have
 +evolving texture patterns, eh? :).
 +
 +The program makes a few refinements to this technique. ​ For instance, instead
 +of coloring the entire buffer white, it calculates ahead of time the minimum
 +and maximum values for y, and only colors that part of the drawing area
 +white.
 +
 +For the sake of completeness,​ here is another method of filling:
 +exclusive-or. A clever way of filling faces is to use some EOR magic. ​ Let's
 +say we want to fill everything between two points A and B.  We want to start
 +filling at point A and stop at point B, and since EOR is a bit flipper this
 +gives us a means of filling. ​ Consider the following situation in memory:
 +
 + 00010000 ​ <-- Point A
 + 00000000
 + 00000000
 + 00010000 ​ <-- Point B
 +
 +Now consider the following little piece of code:
 +
 + LDA #00
 + EOR A
 + STA A
 + EOR A+1
 + STA A+1
 + EOR A+2
 + STA A+2
 + EOR A+3   ;point B
 +
 +The result is:
 +
 + 00010000
 + 00010000
 + 00010000
 + 00010000
 +
 +This is the conceptual idea behind an EOR-buffer. ​ Pretty neat, eh?  But we
 +can't just implement this as-is. ​ In fact we have a whole slew of things to
 +worry about now.  Try EORing a vertical line.  What about when two lines
 +share a single pixel at their intersection? ​ What happens in color?
 +
 +Ah reckon y'all will just have to wait until next time tuh see :).
 +
 +
 +Da Program
 +----------
 +
 +Let's review the code.  We check to see if we should increase or decrease the
 +rotation rate (or quit), and then update the angles. Next we calculate the
 +rotation matrix using a table of sines and cosines. Then we rotate and
 +project the points by using a table of d/(z/64-z0) values. Somewhere in there
 +we clear a working buffer, draw all of the lines, swap the buffers, pass Go,
 +collect $200 (actually, considering where the buffers are located we either
 +collect $300 or $380 :), and go around the loop again.
 +
 +First, some bugs.  There were two places in the line drawing routine where an
 +SBC was performed with the carry clear when it should have been set, so we
 +need to add some SECs in there. ​ Somewhere there is a strange bug related to
 +y-rotations,​ but I didn't track it down.
 +
 +Although not a bug, there is something to think about. ​ On the computer, x
 +increases to the right, and y-increases downwards, with z coming out of the
 +screen. ​ But this is a left-handed coordinate system, and all our
 +calculations were performed in a right-handed coordinate system. ​ What this
 +means is that one of our coordinates is actually a mirror-image of what it
 +should be, while the other coordinate is where it is supposed to be.
 +Remember that a projection generates a negative mirror-image of the object --
 +the computer coordinate system mirrors a single axis of the image again!
 +
 +Because of the symmetry of a cube, this makes no difference. A smart way to
 +fix this is to translate the object in _front_ of the projection plane, i.e.
 +to use the translation z=z+c instead of the currently used z=z-c, but still
 +project through the origin and into the plane z=1.  Since I am not
 +particularly smart though, not to mention lazy and unmotivated,​ I didn't
 +bother to fix this.
 +
 +Before we start adding the new stuff like hidden surfaces into the code, why
 +don't we think about doing some simple optimizations to the old code?  One
 +really easy thing to fix is in the projection routine. ​ You will recall that
 +the earlier program rotated z and then added 128 to it to use as an index.
 +Why bother to add 128 at all?  I dunno -- sometimes things seem like a good
 +idea at the time.  So that's something to fix. It's not that it's a big waste
 +of time, it's just one of those annoying things that there'​s no reason for.
 +
 +How about the variables? ​ They'​re all just sitting at the end of the program
 +-- why not move them all into zero page?  Sounds good to me!  We just need to
 +make sure we don't use any sensitive locations in zero page that will hose
 +the whole computer. ​ So now that's fixed.
 +
 +On the C64 an interrupt is performed every 60th of a second which scans the
 +keyboard and things like that -- why in the world do we want that running in
 +the middle of all our calculations? ​ I dunno -- let's turn it off (but turn
 +it back on before checking to see if F1 etc. was pressed!).
 +
 +A footnote observation:​ when the rotation matrix is calculated, two macros
 +are used (MUL2 and DIV2) which multiply and divide a signed number by two.
 +It never ceases to amaze me what happens when you simply sit down and think
 +about something, and in this case these two macros can be made much simpler:
 +
 + MUL2 ASL ;​That'​s all, folks
 +
 + DIV2 CLC
 + BPL :POS
 + SEC
 + :POS ROR
 +
 +These two routines will multiply/​divide a signed 2's complement number
 +by two (note that the source included with this article uses the old method).
 +
 +There'​s the easy stuff to fix.  What about the calculations themselves? The
 +rotation is pretty straightforward -- nah, skip that.  The line drawing
 +routine takes up an awful lot of time -- maybe we can speed that up?  That's
 +for a future article :).  Clearing the buffer takes a lot of time, but now
 +that we're going to have filled faces there isn't too much we can do about
 +that.  In fact, so much more time is spent in those two areas than is spent
 +in other parts of the code that any other optimizations we make really aren't
 +going to make a very big difference... BUT...
 +
 +How about multiplications?​
 +
 +
 +Fast Signed Multiply
 +--------------------
 +
 +Ah, now here is something we can fix.  Consider the following function:
 +
 + f(x) = x*x/4
 +
 +Now notice that
 +
 + f(a+b) - f(a-b) = a*b
 +
 +Wowsers! ​ All we need to do is have a table of squares, and we can do a
 +multiplication in no time!
 +
 +Whoa there, wait a minute, all of our calculations are using signed numbers.
 +Won't that make a difference? ​ Well, the above calculation is completely
 +general -- I never said what the sign of a and b are.  The fact that we are
 +using two's complement notation makes this even simpler!
 +
 +Recall that our multiplication is
 +
 + x -> x * [d/​(z0-z/​64)]
 +
 +where x is a signed floating point number multiplied by 64 (that is,  instead
 +of going from -1 to 1 x would go from -64 to 64).  Previously we made d
 +large, so that the table of d/(z-z0) would be more accurate. Then we
 +multiplied the numbers together and divided by 64, a procedure which took
 +between 150 and 180 cycles, leaving us with a signed, 8-bit result.
 +
 +Well, that's easy to duplicate. ​ From our first equation above, we see that
 +
 + (a*b)/64 = [ f(a+b) - f(a-b) ]/64
 + = g(a+b) - g(a-b)
 +where
 + g(x) = x*x/256.
 +
 +In other words, if we modify our table slightly, we get exactly the result we
 +want.  So here is the code to multiply two numbers together:
 +
 +* A*Y -> A  Signed, 8-bit result
 +
 + STA ZP1 ;ZP1 -- zero page pointer to table of g(x)
 + EOR #$FF
 + CLC
 + ADC #$01
 + STA ZP2 ;ZP2 also points to g(x)
 + LDA (ZP1),​Y ;​g(Y+A)
 + SEC
 + SBC (ZP2),​Y ;​g(Y-A)
 +
 +And that's it -- we're done.  The above takes 24-26 cycles to execute -- not
 +bad at all!  Yes, with another table we could make it even faster, but this
 +is good enough for us.
 +
 +At the moment we don't do very many multiplications,​ but in the future, when
 +we write a generalized routine to rotate and project an arbitrary object,
 +this will give us a humongous time savings.
 +
 +Astute readers may be thinking ahead here: in the program, for each
 +projection we have two multiplications,​ x=x*c and y=y*c, where c is the same
 +in both cases. ​ So if we store c in ZP1 and ZP2, we can make the
 +multiplication even more efficient, right? ​ The answer is yes, but only by
 +being extremely careful, for reasons that will be detailed in exactly two
 +paragraphs.
 +
 +BUT WAIT!  We have to think about a few things here.  What happens when we
 +multiply, say, -1 * -1.  In two's complement notation -1 is equal to 255.  So
 +our above algorithm adds 255 to 255 to get an index into the table and
 +gets... oops!  Our table needs to be larger than 256 bytes! ​ In fact this is
 +very easy to fix, because of the way two's complement works. ​ All we need to
 +do is put an exact copy of the 256 byte table on top of itself, and the table
 +will work fine.  (If you look at the initialization program you will notice
 +that the statement is: q%=s*s:poke bm+j,​q%:​poke bm+j+256,​q%).
 +
 +BUT WAIT!!! ​ What kinds of numbers are we multiplying together here? Our
 +vertices start out at the points (+/​-1,​+/​-1,​+/​-1). ​ Our rotations correspond
 +to moving these points around on a sphere, so it is easy to see that the
 +largest rotated value we can have is sqr(3), the radius of this sphere.
 +Since we are multiplying these numbers by 64, the largest value we can have
 +for these numbers is 64*sqr(3) = 111.  Okay, no big whoop, what are the
 +values for d/(z0-z/64) anyways? ​ Well, for z0=5 and d=150 say we get values
 +like 28...
 +
 +ACK!  When we go to multiply we are going to add 111 to 28 and get 137, but
 +in two's complement notation this is equal to -119.
 +
 +Example:
 + a=28
 + b=111
 + f(b+a) = f(137) = f(-119) in two'​s-complement notation
 + f(b-a) = f(83)
 +
 +In our table lookup we really want 137*137 but we are going to get -119*-119!
 +One option is to never choose d very large so that we don't have this
 +problem, but the solution turns out to be much simpler, again due to the way
 +two's complementing works.
 +
 +We can see that we can get numbers larger than 127 when we add the two
 +multiplicands together. ​ What is the _smallest_ number we will come up with?
 +Certainly the smallest x is going to get is -111. Ahhh... d/(z0-z/64) is
 +always positive, so when we add them together we will get something larger
 +than -111, which in two's complement notation is 145.  This means that we can
 +treat the table entries between 127 and at least 145 as positive numbers
 +instead of two's complement negative numbers, and everything will work out
 +great.
 +
 +Incidentally,​ fudging this table provides an easy way to add pretty cool
 +special effects. ​ The initialization program sets up the math table using the
 +following line:
 +
 +     [for j=0 to 255]
 + 290 S=J:IF S>150 THEN S=256-S
 +     [poke bm+j,S*S]
 +
 +Try changing the inequality from S>150 to S>120 (or S>127, where it would be
 +for a two's complement table), and see what happens!
 +
 +And this is why we can't store d/(z0-z) in the pointers ZP1 and ZP2 -- if we
 +did, then for a given multiplication we could get numbers larger than 127 and
 +smaller than -128, and our clever table would no longer work right. ​ We can
 +still get around this -- all we need is two clever tables, one for the
 +positive d/(z0-z) and one for negative d/​(z0-z). ​ For the first table, we
 +have the situation outlined above: no numbers smaller than -90 or so, and
 +numbers possible larger than 127.  For the second table we have the reverse
 +situation: no numbers larger than 90 or so, but possible numbers less than
 +-128. Since we are using two pointers anyways (ZP1 and ZP2), this is not
 +difficult to implement.
 +
 +The end result is that you can do the entire projection in around 36 cycles
 +if you so desire. ​ 36 cycles? ​ Note that for the second table the code does
 +something like EOR #$FF; CLC; ADC #$01. Well, if we set up the second table
 +as f(x)=(x+1)^2/​4 then we have included the CLC and ADC #$01 into the table,
 +so the instructions can be removed. ​ The entire projection routine is then:
 +
 + ... (rotate z)
 + STA ZP1
 + EOR #$FF
 + STA ZP2
 + ... (rotate x)
 + TAY
 + LDA (ZP1),Y
 + SEC
 + SBC (ZP2),​Y ​   ;Now A contains projected X
 + ... (rotate y)
 + TAY
 + LDA (ZP1),Y
 + SEC
 + SBC (ZP2),Y
 +
 +Looks like 36-40 cycles to me!  The program doesn'​t implement this -- it only
 +uses a single table, and repeats the STA ZP1 stuff at each step.  A few
 +cycles wasted won't kill us (there are plenty of cycles wasted in the code),
 +and it is probably tricky enough to follow as it is.
 +
 +You might be asking, what is the true minimum value for a given z0 and d?
 +Well, I tried writing down a set of equations and minimizing according to
 +some constraints,​ and I ended up with a sixth-order polynomial which I had to
 +write little newton-iteration solver for.  In other words, I don't think you
 +can write down a simple function of d and z0 to give the table boundaries. ​ I
 +found 150 to be a perfectly reasonable number to use.
 +
 +Incidentally,​ this is why the projection was not changed to z=z+c -- I didn't
 +want to go fiddling around with it again. ​ Maybe next time :).
 +
 +ONE MORE THING!!! ​ This is very important. ​ The math table MUST be on an even
 +boundary for the above algorithm to work correctly. ​ This one is easy to get
 +bit by.
 +
 +Logarithmic Multiplication
 +--------------------------
 +
 +As long as we're talking about fast multiplication here, it is worthwhile to
 +mention another method for multiplying two numbers together. ​ To understand
 +it you need to understand two important properties of logarithms:
 +
 + log(x*y) = log(x) + log(y)
 + log_b(x) = y  <​=> ​ b^y = x
 +
 +These are a reflection of the fact that logarithms are inverses of
 +exponentiation. ​ So you can see that another way to multiply two numbers
 +together is to take their logs, add, and then exponentiate the result. ​ So
 +you could have a table of log_2 (base 2 logarithms) and another table of 2^x,
 +and do a multiplication very quickly. (Actually, you'd want a table of
 +32*log_2(x),​ since log_2(256)=8). Why wasn't this method used?
 +
 +First, dealing with signed numbers is much trickier -- the logarithm of a
 +negative number is a complex (i.e. real+imaginary) number, complete with
 +branch cuts.  You can get around this by setting up the tables in a special
 +way (for instance by letting log(-x)=-log(x)) and putting in some special
 +handling, but it isn't as efficient as the algorithm used in the program.
 +
 +Second, accuracy decreases significantly as x and y get large, so that for an
 +eight-bit table of logarithms you will often get an answer that is off by one
 +or more.  You can in fact get around this problem by using some sneaky
 +manipulation -- if you are interested in seeing this, contact us!
 +
 +But it is worthwhile to keep this method in mind if you need a really fast
 +multiplication and you aren't too worried about accuracy.
 +
 +Christopher Jam (phillips@ee.uwa.edu.au) has come up with an interesting
 +variation on this method. ​ It calculates 64+64*x/z and uses a slightly
 +different structure for the signed numbers, and runs almost as fast as the
 +method used by the program -- contact him for more information if you're
 +interested.
 +
 +
 +Hidden Surfaces
 +---------------
 +
 +The remainder of this follows right from the discussion section. In the
 +program the cube vertices are labeled as
 +
 + P1 = 1,1,1
 + P2 = 1,-1,1
 + P3 = -1,-1,1
 + P4 = -1,1,1
 + P5 = 1,1,-1
 + P6 = 1,-1,-1
 + P7 = -1,-1,-1
 + P8 = -1,1,-1
 +
 +and the faces are chosen to be
 +
 + Face 1: P1 P2 P3 P4
 +      6: P5 P6 P7 P8
 + Face 2: P1 P2 P5 P6
 +      5: P3 P4 P7 P8
 + Face 3: P1 P4 P8 P5
 +      4: P2 P3 P6 P7
 +
 +(think of it as a six-sided dice, with six opposite of one, etc.). ​ The normal
 +vectors are then
 +
 + Face 1: P1-P5
 + Face 2: P1-P4
 + Face 3: P1-P2
 +
 +This means that we need to store the z-coordinates for points 1,2,4, and 5.
 +Note that the opposite faces have exactly opposite normal vectors, so that
 +for instance the normal vector for face 6 is P5-P1, the negative of face 1.
 +
 +Here is something to consider: when one face is visible, the opposite face
 +cannot be visible! ​ Because of the way projections work, though, the converse
 +is not true; it is entirely possible to have two opposite faces invisible.
 +To prove this to yourself just look at your favorite box, like your monitor,
 +straight-on,​ and notice that you can't see the sides!
 +
 +All that the program does is subtract z-coordinates and add them to the
 +constant K, and check the sign.  Unfortunately we can have a positive
 +overflow while adding stuff together (since these are signed numbers), and if
 +we don't catch the positive overflow we will calculate a negative result when
 +the result is actually positive! ​ This will of course wreck the hidden
 +surface removal.
 +
 +
 +Filled Faces
 +------------
 +
 +The program currently uses the first algorithm to fill faces, i.e. the
 +cookie-cutter elephant-carving method. ​ During the projections the program
 +checks each value of y to find the minimum and maximum values for this plot,
 +ymin and ymax.  The program then clears the buffer up to and including ymin,
 +fills the buffer from ymin+1 to ymax-1, and then clears the rest of the
 +buffer. ​ Why does it clear ymin and ymax?  Because the only thing that can
 +happen on those lines is an edge -- there is no point in filling these lines
 +and then clearing them, since they will always be clear. ​ By only filling the
 +buffer between ymin and ymax, we save some time in removing the junk from the
 +edges of the cube.
 +
 +Next, the cube is drawn. ​ The background is black and the faces are white,
 +i.e. our fill color is white. ​ Clearly then we want to draw our lines in
 +black. ​ I could have reversed background and foreground colors and left the
 +line routine as-is, but of course being the lazy programmer I am I decided
 +instead to change the table BITP.  You may recall that the earlier table had
 +entries like %10000000 %01000000 etc. Now it has entries like %01111111
 +%10111111 etc., and instead of ORAing the values into the buffer, they are
 +ANDed into the buffer. ​ This then draws lines of zeroes into our buffer which
 +is solid ones.
 +
 +Finally, to un-fill the outside of the cube the program simply goes through
 +the buffer from ymin to ymax, coloring everything black until it hits a zero,
 +i.e. an edge.  At this point it calculates the appropriate pattern to clear
 +up to the edge, and then does the same thing starting from the right hand
 +side of the buffer. ​ In other words it runs along a specific y-value coloring
 +everything black until it hits the edge of the cube, and does this for all
 +the relevant y-values.
 +
 +
 +Texture Mapping
 +---------------
 +
 +More of a fill-pattern really. ​ The program cube3d2.1.o does all of the above
 +but in multicolor mode.  Now instead of using a solid color to fill the
 +buffer the program uses a series of colored lines -- really a very simple
 +pattern. ​ A much neater thing would be to have a pattern drawn out in a
 +pattern buffer, and to copy that into the drawing buffer. ​ Other things to
 +try are colored squares which shift around. ​ cube3d2.1.o is just a really
 +quick hack, but at least it demonstrates the concept.
 +
 +MAKE SURE that you change the value of D from 170 to 85 if you try this
 +program! ​ Pixels are doubled now, so that resolution is cut in half.  This is
 +located at line 240 in INIT3D2.0
 +
 +
 +Memory Map
 +----------
 +
 +The main program is located at $8000=32768 and is 3200 bytes long.
 +
 + $8000-$8C00 - Program
 + $8C00-$8C80 - Bit position table
 + $8C80-$8D00 - Table of sines
 + $8D00-$8D80 - Table of cosines.
 + $8D80-$8E80 - Table of d/(z0-z/64)
 + $8F00-$9100 - Two 256-byte tables of g(x)=x*x/​256
 +
 + $3000 - First drawing buffer
 + $3800 - Second drawing buffer
 +
 +INIT3D is a simple basic program to set up the tables. ​ For INIT3D2.x the
 +important setup routines are:
 +
 + lines 100-150 - Set up the trigonometric tables
 + lines 233-310 - Set up the projection and mult tables
 + 240 - Location of constants D and Z0
 + 290 - Set table boundary for multiplication
 +
 +
 +That's all -- until next time...
 +
 +Steve Judd George Taylor 12/​2/​95
 +
 +This document is Copyright 1995 by Stephen Judd and George Taylor. Much like
 +the previous one.  It is also freely distributable.
 +
 +And here is the source code:
 +
 +
 +********************************
 +*                              *
 +* Stephen Judd                 *
 +* George Taylor ​               *
 +* Started: 7/​11/​94 ​            *
 +* Finished: 7/​19/​94 ​           *
 +* v2.0 Completed: 12/​17/​94 ​    *
 +*                              *
 +* Well, if all goes well this  *
 +* program will rotate a cube.  *
 +*                              *
 +* v2.0 + New and Improved! ​    *
 +* Now with faster routines, ​   *
 +* hidden surfaces, filled ​     *
 +* faces, and extra top secret ​ *
 +* text messages! ​              *
 +*                              *
 +* This program is intended to  *
 +* accompany the article in     *
 +* C=Hacking, Jan. 95 issue. ​   *
 +* For details on this program, *
 +* read the article! ​           *
 +*                              *
 +* Write to us!                 *
 +*                              *
 +* Myself when young did        *
 +* eagerly frequent ​            *
 +* Doctor and Saint, and heard  *
 +* great Argument ​              *
 +*  About it and about: but     *
 +*  evermore ​                   *
 +* Came out by the same Door    *
 +* as in I went.                *
 +*    - Rubaiyat ​               *
 +*                              *
 +* Though I speak with the      *
 +* tongues of men and of angles *
 +* and have not love, I am      *
 +* become as sounding brass, or *
 +* a tinkling cymbal. ​          *
 +*    - 1 Corinthians 13        *
 +*                              *
 +* P.S. This was written using  *
 +*      Merlin 128.             *
 +********************************
 +
 +         ORG $8000
 +
 +* Constants
 +
 +BUFF1    EQU $3000        ;First character set
 +BUFF2    EQU $3800        ;Second character set
 +BUFFER ​  EQU $A3          ;Presumably the tape won't be running
 +X1       EQU $FB          ;Points for drawing a line
 +Y1       EQU $FC          ;These zero page addresses
 +X2       EQU $FD          ;don't conflict with BASIC
 +Y2       EQU $FE
 +DX       EQU $F9
 +DY       EQU $FA
 +TEMP1    EQU $FB          ;Of course, could conflict with x1
 +TEMP2    EQU $FC          ;Temporary variables
 +ZTEMP    EQU $02          ;Used for buffer swap.  Don't touch.
 +Z1       EQU $22          ;Used by math routine
 +Z2       EQU $24          ;Don't touch these either!
 +K        EQU $B6          ;Constant used for hidden
 +                          ;surface detection - don't touch
 +FACES    EQU $B5          ;Used in hidden surfaces.
 +YMIN     EQU $F7          ;Used in filled faces -- as
 +YMAX     EQU $F8          ;usual, don't touch
 +ANGMAX ​  EQU 120          ;There are 2*pi/angmax angles
 +
 +* VIC
 +
 +VMCSB    EQU $D018
 +BKGND    EQU $D020
 +BORDER ​  EQU $D021
 +SSTART ​  EQU 1344         ;row 9 in screen memory at 1024
 +
 +
 +* Kernal
 +
 +CHROUT ​  EQU $FFD2
 +GETIN    EQU $FFE4
 +
 +* Some variables
 +
 +TX1      = $3F
 +TY1      = $40
 +TX2      = $41
 +TY2      = $42
 +P1X      = $92            ;These are temporary storage
 +P1Y      = $93            ;Used in plotting the projection
 +P2X      = $94
 +P2Y      = $95            ;They are here so that we
 +P3X      = $96            ;don't have to recalculate them.
 +P3Y      = $AE
 +P4X      = $AF            ;They make life easy.
 +P4Y      = $B0
 +P5X      = $B1            ;Why are you looking at me like that?
 +P5Y      = $B2            ;Don't you trust me?
 +P6X      = $B3
 +P6Y      = $B4            ;Having another child wasn't my idea.
 +P7X      = $71
 +P7Y      = $50
 +P8X      = $51
 +P8Y      = $52
 +P1Z      = $57            ;These are z-coordinates
 +P2Z      = $58            ;We only need these four to check
 +P4Z      = $59            ;for hidden faces
 +P5Z      = $60
 +DSX      = $61            ;DSX is the increment for
 +                          ;rotating around x
 +DSY      = $62            ;Similar for DSY, DSZ
 +DSZ      = $63
 +SX       = $64            ;These are the actual angles in x y and z
 +SY       = $65
 +SZ       = $66
 +T1       = $67            ;These are used in the rotation
 +T2       = $68
 +T3       = $69            ;See the article for more details
 +T4       = $6A
 +T5       = $6B
 +T6       = $6C
 +T7       = $6D
 +T8       = $6E
 +T9       = $6F
 +T10      = $70
 +A11      = $A5            ;These are the elements of the rotation matrix
 +B12      = $A6            ;XYZ
 +C13      = $A7
 +D21      = $A8            ;The number denotes (row,​column)
 +E22      = $A9
 +F23      = $AA
 +G31      = $AB
 +H32      = $AC
 +I33      = $AD
 +
 +
 +*** Macros
 +
 +MOVE     MAC
 +         LDA ]1
 +         STA ]2
 +         <<<​
 +
 +GETKEY ​  ​MAC ​             ;Wait for a keypress
 +WAIT     JSR GETIN
 +         CMP #00
 +         BEQ WAIT
 +         <<<​
 +
 +*-------------------------------
 +
 +         LDA #$00
 +         STA BKGND
 +         STA BORDER
 +         LDA VMCSB
 +         AND #​%00001111 ​  ;​Screen memory to 1024
 +         ORA #%00010000
 +         STA VMCSB
 +
 +         LDY #00
 +         LDA #<TTEXT
 +         STA TEMP1
 +         LDA #>TTEXT
 +         STA TEMP2
 +         JMP TITLE
 +TTEXT    HEX 9305111111 ​  ;​clear screen, white, crsr dn
 +         TXT ' ​            ​cube3d v2.0',​0d,​0d
 +         TXT ' ​                 by',0d
 +         HEX 9F           ;cyan
 +         TXT ' ​   stephen judd'
 +         HEX 99
 +         TXT ' ​   george taylor',​0d,​0d
 +         HEX 9B
 +         TXT ' ​ check out the jan. 95 issue of',0d
 +         HEX 96
 +         TXT ' ​ c=hacking'​
 +         HEX 9B
 +         TXT ' for more details!',​0d
 +         HEX 0D1D1D9E12
 +         TXT '​f1/​f2',​92
 +         TXT ' - inc/dec x-rotation',​0d
 +         HEX 1D1D12
 +         TXT '​f3/​f4',​92
 +         TXT ' - inc/dec y-rotation',​0d
 +         HEX 1D1D12
 +         TXT '​f5/​f6',​92
 +         TXT ' - inc/dec z-rotation',​0d
 +         HEX 1D1D12
 +         TXT '​f7',​92
 +         TXT ' resets',​0d
 +         TXT ' ​ press q to quit',​0d
 +         HEX 0D05
 +         TXT ' ​     press any key to begin',​0d
 +         HEX 00
 +TITLE    LDA (TEMP1),Y
 +         BEQ :CONT
 +         JSR CHROUT
 +         INY
 +         BNE TITLE
 +         INC TEMP2
 +         JMP TITLE
 +         TXT 'This is a secret text message!'​
 +:CONT    >>>​ GETKEY
 +
 +**** Set up tables(?)
 +
 +* Tables are currently set up in BASIC
 +* and by the assembler.
 +
 +TABLES ​  LDA #>TMATH
 +         STA Z1+1
 +         STA Z2+1
 +
 +**** Clear screen and set up "​bitmap"​
 +SETUP    LDA #$01         ;​White
 +         STA $D021        ;This is done so that older
 +         LDA #147         ;​machines will set up
 +         JSR CHROUT
 +         LDA #$00         ;​correctly
 +         STA $D021
 +         LDA #<SSTART
 +         ADC #12          ;The goal is to center the graphics
 +         STA TEMP1        ;Column 12
 +         LDA #>​SSTART ​    ;Row 9
 +         STA TEMP1+1 ​     ;SSTART points to row 9
 +         LDA #00
 +         LDY #00
 +         LDX #00          ;x will count 16 rows for us
 +         CLC
 +
 +:LOOP    STA (TEMP1),Y
 +         INY
 +         ADC #16
 +         BCC :LOOP
 +         CLC
 +         LDA TEMP1
 +         ADC #40          ;Need to add 40 to the base pointer
 +         STA TEMP1        ;To jump to the next row
 +         LDA TEMP1+1
 +         ADC #00          ;Take care of carries
 +         STA TEMP1+1
 +         LDY #00
 +         INX
 +         ​TXA ​             ;X is also an index into the character number
 +         CPX #16
 +         BNE :LOOP        ;Need to do it 16 times
 +
 +**** Set up buffers
 +
 +         LDA #<BUFF1
 +         STA BUFFER
 +         LDA #>BUFF1
 +         STA BUFFER+1
 +         STA ZTEMP        ;ztemp will make life simple for us
 +         LDA VMCSB
 +         AND #​%11110001 ​  ;​Start here so that swap buffers will work right
 +         ORA #%00001110
 +         STA VMCSB
 +
 +**** Set up initial values
 +
 +INIT     LDA #00
 +         STA DSX
 +         STA DSY
 +         STA DSZ
 +         STA SX
 +         STA SY
 +         STA SZ
 +
 +*-------------------------------
 +* Main loop
 +
 +**** Get keypress
 +
 +MAIN
 +         CLI
 +KPRESS ​  JSR GETIN
 +         CMP #133         ;F1?
 +         BNE :F2
 +         LDA DSX
 +         CMP #​ANGMAX/​2 ​   ;No more than pi
 +         BEQ :CONT
 +         INC DSX          ;otherwise increase x-rotation
 +         JMP :CONT
 +:F2      CMP #137         ;F2?
 +         BNE :F3
 +         LDA DSX
 +         BEQ :CONT
 +         DEC DSX
 +         JMP :CONT
 +:F3      CMP #134
 +         BNE :F4
 +         LDA DSY
 +         CMP #ANGMAX/2
 +         BEQ :CONT
 +         INC DSY          ;Increase y-rotation
 +         JMP :CONT
 +:F4      CMP #138
 +         BNE :F5
 +         LDA DSY
 +         BEQ :CONT
 +         DEC DSY
 +         JMP :CONT
 +:F5      CMP #135
 +         BNE :F6
 +         LDA DSZ
 +         CMP #ANGMAX/2
 +         BEQ :CONT
 +         INC DSZ          ;z-rotation
 +         JMP :CONT
 +:F6      CMP #139
 +         BNE :F7
 +         LDA DSZ
 +         BEQ :CONT
 +         DEC DSZ
 +         JMP :CONT
 +:F7      CMP #136
 +         BNE :Q
 +         JMP INIT
 +:Q       CMP #'​q' ​        ;q quits
 +         BNE :CONT
 +         JMP CLEANUP
 +
 +:CONT    SEI              ;Speed things up a bit
 +
 +**** Update angles
 +
 +UPDATE ​  CLC
 +         LDA SX
 +         ADC DSX
 +         CMP #​ANGMAX ​     ;Are we >= maximum angle?
 +         BCC :CONT1
 +         SBC #ANGMAX :If so, reset
 +:​CONT1 ​  STA SX
 +         CLC
 +         LDA SY
 +         ADC DSY
 +         CMP #ANGMAX
 +         BCC :CONT2
 +         SBC #​ANGMAX ​     ;Same deal
 +:​CONT2 ​  STA SY
 +         CLC
 +         LDA SZ
 +         ADC DSZ
 +         CMP #ANGMAX
 +         BCC :CONT3
 +         SBC #ANGMAX
 +:​CONT3 ​  STA SZ
 +
 +**** Rotate coordinates
 +
 +ROTATE
 +
 +*** First, calculate t1,​t2,​...,​t10
 +
 +** Two macros to simplify our life
 +ADDA     ​MAC ​             ;Add two angles together
 +         CLC
 +         LDA ]1
 +         ADC ]2
 +* Use two trig tables to remove the below CMP etc. code
 +         CMP #​ANGMAX ​     ;Is the sum > 2*pi?
 +         BCC DONE
 +         SBC #​ANGMAX ​     ;If so, subtract 2*pi
 +DONE     <<<​
 +
 +SUBA     ​MAC ​             ;Subtract two angles
 +         SEC
 +         LDA ]1
 +         SBC ]2
 +         BCS DONE
 +         ADC #​ANGMAX ​     ;Oops, we need to add 2*pi
 +DONE     <<<​
 +
 +** Now calculate t1,t2,etc.
 +
 +         >>>​ SUBA,​SY ​     ;SZ
 +         STA T1           ;​t1=sy-sz
 +         >>>​ ADDA,​SY ​     ;SZ
 +         STA T2           ;​t2=sy+sz
 +         >>>​ ADDA,​SX ​     ;SZ
 +         STA T3           ;​t3=sx+sz
 +         >>>​ SUBA,​SX ​     ;SZ
 +         STA T4           ;​t4=sx-sz
 +         >>>​ ADDA,​SX ​     ;T2
 +         STA T5           ;​t5=sx+t2
 +         >>>​ SUBA,​SX ​     ;T1
 +         STA T6           ;​t6=sx-t1
 +         >>>​ ADDA,​SX ​     ;T1
 +         STA T7           ;​t7=sx+t1
 +         >>>​ SUBA,​T2 ​     ;SX
 +         STA T8           ;​t8=t2-sx
 +         >>>​ SUBA,​SY ​     ;SX
 +         STA T9           ;​t9=sy-sx
 +         >>>​ ADDA,​SX ​     ;SY
 +         STA T10          ;t10=sx+sy
 +
 +* Et voila!
 +
 +*** Next, calculate A,B,C,...,I
 +
 +** Another useful little macro
 +DIV2     ​MAC ​             ;Divide a signed number by 2
 +                          ;It is assumed that the number
 +         BPL POS          ;is in the accumulator
 +         CLC
 +         EOR #$FF         ;We need to un-negative the number
 +         ADC #01          ;by taking it's complement
 +         ​LSR ​             ;divide by two
 +         CLC
 +         EOR #$FF
 +         ADC #01          ;Make it negative again
 +         JMP DONEDIV
 +POS      LSR              ;Number is positive
 +DONEDIV ​ <<<​
 +
 +MUL2     ​MAC ​             ;Multiply a signed number by 2
 +         BPL POSM
 +         CLC
 +         EOR #$FF
 +         ADC #$01
 +         ASL
 +         CLC
 +         EOR #$FF
 +         ADC #$01
 +         JMP DONEMUL
 +POSM     ASL
 +DONEMUL ​ <<<​
 +
 +** Note that we are currently making a minor leap
 +** of faith that no overflows will occur.
 +
 +:​CALCA ​  CLC
 +         LDX T1
 +         LDA COS,X
 +         LDX T2
 +         ADC COS,X
 +         STA A11          ;​A=(cos(t1)+cos(t2))/​2
 +:​CALCB ​  LDX T1
 +         LDA SIN,X
 +         SEC
 +         LDX T2
 +         SBC SIN,X
 +         STA B12          ;​B=(sin(t1)-sin(t2))/​2
 +:​CALCC ​  LDX SY
 +         LDA SIN,X
 +         >>>​ MUL2
 +         STA C13          ;C=sin(sy)
 +:​CALCD ​  SEC
 +         LDX T8
 +         LDA COS,X
 +         LDX T7
 +         SBC COS,X
 +         SEC
 +         LDX T5
 +         SBC COS,X
 +         CLC
 +         LDX T6
 +         ADC COS,X        ;​Di=(cos(t8)-cos(t7)+cos(t6)-cos(t5))/​2
 +         >>>​ DIV2
 +         CLC
 +         LDX T3
 +         ADC SIN,X
 +         SEC
 +         LDX T4
 +         SBC SIN,X
 +         STA D21          ;​D=(sin(t3)-sin(t4)+Di)/​2
 +:​CALCE ​  SEC
 +         LDX T5
 +         LDA SIN,X
 +         LDX T6
 +         SBC SIN,X
 +         SEC
 +         LDX T7
 +         SBC SIN,X
 +         SEC
 +         LDX T8
 +         SBC SIN,X        ;​Ei=(sin(t5)-sin(t6)-sin(t7)-sin(t8))/​2
 +         >>>​ DIV2
 +         CLC
 +         LDX T3
 +         ADC COS,X
 +         CLC
 +         LDX T4
 +         ADC COS,X
 +         STA E22          ;​E=(cos(t3)+cos(t4)+Ei)/​2
 +:​CALCF ​  LDX T9
 +         LDA SIN,X
 +         SEC
 +         LDX T10
 +         SBC SIN,X
 +         STA F23          ;​F=(sin(t9)-sin(t10))/​2
 +:​CALCG ​  LDX T6
 +         LDA SIN,X
 +         SEC
 +         LDX T8
 +         SBC SIN,X
 +         SEC
 +         LDX T7
 +         SBC SIN,X
 +         SEC
 +         LDX T5
 +         SBC SIN,X        ;​Gi=(sin(t6)-sin(t8)-sin(t7)-sin(t5))/​2
 +         >>>​ DIV2
 +         CLC
 +         LDX T4
 +         ADC COS,X
 +         SEC
 +         LDX T3
 +         SBC COS,X
 +         STA G31          ;​G=(cos(t4)-cos(t3)+Gi)/​2
 +:​CALCH ​  CLC
 +         LDX T6
 +         LDA COS,X
 +         LDX T7
 +         ADC COS,X
 +         SEC
 +         LDX T5
 +         SBC COS,X
 +         SEC
 +         LDX T8
 +         SBC COS,X        ;​Hi=(cos(t6)+cos(t7)-cos(t5)-cos(t8))/​2
 +         >>>​ DIV2
 +         CLC
 +         LDX T3
 +         ADC SIN,X
 +         CLC
 +         LDX T4
 +         ADC SIN,X
 +         STA H32          ;​H=(sin(t3)+sin(t4)+Hi)/​2
 +:WHEW    CLC
 +         LDX T9
 +         LDA COS,X
 +         LDX T10
 +         ADC COS,X
 +         STA I33          ;​I=(cos(t9)+cos(t10))/​2
 +
 +** It's all downhill from here.
 +         JMP DOWNHILL
 +         TXT 'Gee Brain, what do you want to do '
 +         TXT '​tonight?'​
 +
 +** Rotate, project, and store the points
 +DOWNHILL
 +
 +* A neat macro
 +NEG      MAC              ;Change the sign of a two's complement
 +         CLC
 +         LDA ]1           ;​number.
 +         EOR #$FF
 +         ADC #$01
 +         <<<​
 +
 +*-------------------------------
 +* These macros replace the previous projection
 +* subroutine.
 +
 +SMULT    MAC              ;Multiply two signed 8-bit
 +                          ;numbers: A*Y/64 -> A
 +         STA Z1
 +         CLC
 +         EOR #$FF
 +         ADC #$01
 +         STA Z2
 +         LDA (Z1),Y
 +         SEC
 +         SBC (Z2),Y
 +         <<< ​             ;All done :)
 +
 +
 +ADDSUB ​  ​MAC ​             ;Add or subtract two numbers
 +                          ;depending on first input
 +         IF -=]1          ;If subtract
 +         ​SEC ​             ;then use this code
 +         SBC ]2
 +         ​ELSE ​            ;​otherwise use this code
 +         CLC
 +         ADC ]2
 +         FIN
 +         <<<​
 +
 +
 +PROJECT ​ MAC              ;The actual projection routine
 +                          ;two inputs are used (x,y)
 +                          ;​corresponding to (+/-1,+/-1)
 +                          ;The third input is used to
 +                          ;determine if the rotated
 +                          ;​z-coordinate should be
 +                          ;stored, and if so where.
 +                          ;The calling routine handles
 +                          ;changing the sign of z.
 +
 +         LDA I33          ;Calculate rotated z:
 +         >>>​ ADDSUB,​]1 ​   ;G31 ;Add or subtract x
 +         >>>​ ADDSUB,​]2 ​   ;H32 ;Add or subtract y
 +         IF P,]3          ;Do we need to store the point?
 +         STA ]3           ;Then do so!
 +         FIN
 +* EOR #128 ;We are going to take 128+z
 +         ​TAX ​             ;Now it is ready for indexing
 +         LDA ZDIV,​X ​      ;​Table of d/(z+z0)
 +         ​TAY ​             ;Y now contains projection
 +
 +         LDA C13          ;Now calculate rotated x
 +         >>>​ ADDSUB,​]1 ​   ;A11
 +         >>>​ ADDSUB,​]2 ​   ;B12
 +         >>>​ SMULT        ;Signed multiply A*Y/​64->​A
 +         CLC
 +         ADC #64          ;Offset the coordinate
 +         ​TAX ​             ;Now X is rotated x!
 +
 +         LDA F23          ;Now it's y's turn
 +         >>>​ ADDSUB,​]1 ​   ;D21
 +         >>>​ ADDSUB,​]2 ​   ;E22
 +         >>>​ SMULT
 +         CLC
 +         ADC #64          ;Offset
 +         CMP YMIN         ;​Figure out if it is a
 +         BCS NOTMIN ​      ;min or max value for y
 +         STA YMIN
 +         BCC NOTMAX ​      ;This is used in calculating
 +NOTMIN ​  CMP YMAX         ;the filled faces
 +         BCC NOTMAX
 +         STA YMAX
 +NOTMAX ​  ​TAY ​             ;Not really necessary
 +
 +         <<< ​             ;All done
 +
 +
 +         LDA #64          ;Reset Ymin and Ymax
 +         STA YMIN
 +         STA YMAX
 +
 +* P1=[1 1 1]
 +         >>>​ PROJECT,​1;​1;​P1Z ;Rotated z stored in P1Z
 +         STX P1X
 +         STY P1Y
 +* P2=[1 -1 1]
 +         >>>​ PROJECT,​1 ​   ;-1;P2Z
 +         STX P2X
 +         STY P2Y
 +* P3=[-1 -1 1]
 +         >>>​ PROJECT,​-1;​-1;​NOPE ;Don't store z-value
 +         STX P3X
 +         STY P3Y
 +* P4=[-1 1 1]
 +         >>>​ PROJECT,​-1;​1;​P4Z
 +         STX P4X
 +         STY P4Y
 +* P8=[-1 1 -1]
 +         >>>​ NEG,C13
 +         STA C13
 +         >>>​ NEG,F23
 +         STA F23
 +         >>>​ NEG,I33
 +         STA I33
 +         >>>​ PROJECT,​-1;​1;​NOPE
 +         STX P8X
 +         STY P8Y
 +* P7=[-1 -1 -1]
 +         >>>​ PROJECT,​-1;​-1;​NOPE
 +         STX P7X
 +         STY P7Y
 +* P6=[1 -1 -1]
 +         >>>​ PROJECT,​1;​-1;​NOPE
 +         STX P6X
 +         STY P6Y
 +* P5=[1 1 -1]
 +         >>>​ PROJECT,​1;​1;​P5Z
 +         STX P5X
 +         STY P5Y
 +
 +* A little macro
 +
 +SETBUF ​  ​MAC ​             ;Put buffers where they can be hurt
 +         LDA #00
 +         STA BUFFER
 +         LDA ZTEMP        ;ztemp contains the high byte here
 +         STA BUFFER+1
 +         <<<​
 +
 +**** Clear buffer
 +
 +* >>>​ SETBUF
 +*CLRBUF LDA #$00 ;Pretty straightforward,​
 +* LDX #$08 ;I think
 +* LDY #$00
 +*:LOOP STA (BUFFER),Y
 +* INY
 +* BNE :LOOP
 +* INC BUFFER+1
 +* DEX
 +* BNE :LOOP
 +
 +* This is the new and improved buffer clear
 +* routine for filled faces
 +
 +         >>>​ SETBUF
 +         STA TEMP1+1 ​     ;buffer2 will point to
 +         LDA #$80         ;​buffer+128
 +         STA TEMP1        ;Makes life faster for us
 +FILCLR ​  LDA #00
 +         LDX #$08         ;​We'​ll do it two at a time
 +         LDY #$00
 +:​LOOP1 ​  STA (BUFFER),Y
 +         STA (TEMP1),Y
 +         INY
 +         CPY YMIN
 +         BNE :LOOP1
 +         LDA #$FF         ;Now load with fills
 +:​LOOP2 ​  STA (BUFFER),Y
 +         STA (TEMP1),Y
 +         INY
 +         CPY YMAX
 +         BCC :LOOP2
 +         LDA #$00         ;​Black out the rest
 +:​LOOP3 ​  STA (BUFFER),Y
 +         STA (TEMP1),Y
 +         INY
 +         BPL :​LOOP3 ​      ;​Until Y=128
 +         LDY #00
 +         INC BUFFER+1
 +         INC TEMP1+1
 +         DEX
 +         BNE :​LOOP1 ​      ;Go all the way around
 +
 +**** Now draw the lines.
 +**** But first check for hidden faces!
 +**** Remember: P1=[1 1 1] P2=[1 -1 1] P3=[-1 -1 1]
 +**** P4=[-1 1 1] P5=[1 1 -1] P6=[1 -1 -1] P7=[-1 -1 -1]
 +**** P8=[-1 1 -1]
 +
 +LINES    LDA #00
 +         STA FACES        ;Hidden face counter
 +:​FACE1 ​  LDA K
 +         SEC
 +         SBC P1Z
 +         BVS :​FACE6 ​      ;​Overflow already?
 +         CLC
 +         ADC P5Z          ;Is k-v1z < 0?
 +                          ;If not, face is invisible
 +         BVC :​DRAW1 ​      ;But we might have overflow
 +         LDA P5Z          ;Was overflow pos or neg?
 +:​DRAW1 ​  BPL :​FACE6 ​      ;If pos then k-v1z > 0
 +
 +         LDA #$01         ;​Otherwise,​ draw the
 +         STA FACES        ;face!
 +
 +         LDA P1X
 +         STA TX1
 +         LDA P1Y
 +         STA TY1
 +         LDA P2X
 +         STA TX2
 +         LDA P2Y
 +         STA TY2
 +         JSR DRAW         ;​P1-P2
 +
 +         LDA P3X
 +         STA TX1
 +         LDA P3Y
 +         STA TY1
 +         JSR DRAW         ;​P2-P3
 +
 +         LDA P4X
 +         STA TX2
 +         LDA P4Y
 +         STA TY2
 +         JSR DRAW         ;​P3-P4
 +
 +         LDA P1X
 +         STA TX1
 +         LDA P1Y
 +         STA TY1
 +         JSR DRAW         ;​P4-P1 ​ Face 1 done.
 +         JMP :​FACE2 ​      ;If one is visible, the other
 +                          ;​isn'​t.
 +:​FACE6 ​  LDA K
 +         SEC
 +         SBC P5Z
 +         BVS :FACE2
 +         CLC
 +         ADC P1Z          ;Now check if K-v6z < 0
 +         BVC :​DRAW6 ​      ;Love that overflow
 +         LDA P1Z
 +:​DRAW6 ​  BPL :​FACE2 ​      ;If not, go on
 +
 +         LDA #$20
 +         STA FACES        ;Otherwise, draw it
 +
 +         LDA P5X
 +         STA TX2
 +         LDA P5Y
 +         STA TY2
 +         LDA P6X
 +         STA TX1
 +         LDA P6Y
 +         STA TY1
 +         JSR DRAW         ;​P5-P6
 +
 +         LDA P7X
 +         STA TX2
 +         LDA P7Y
 +         STA TY2
 +         JSR DRAW         ;​P6-P7
 +
 +         LDA P8X
 +         STA TX1
 +         LDA P8Y
 +         STA TY1
 +         JSR DRAW         ;​P7-P8
 +
 +         LDA P5X
 +         STA TX2
 +         LDA P5Y
 +         STA TY2
 +         JSR DRAW         ;​P8-P5
 +
 +:​FACE2 ​  LDA K
 +         SEC
 +         SBC P1Z
 +         BVS :FACE5
 +         CLC
 +         ADC P4Z          ;K-v2z < 0?
 +         BVC :DRAW2
 +         LDA P4Z
 +:​DRAW2 ​  BPL :FACE5
 +         LDA #$02         ;If so, draw it!
 +         ORA FACES
 +         STA FACES
 +
 +         LDX P1X          ;We're doing this this way
 +         STX TX1          ;to save a few cycles
 +         LDX P1Y
 +         STX TY1
 +
 +         AND #$01         ;​Shares an edge with face 1
 +         BNE :F2S2        ;Skip to next edge if present
 +
 +         LDA P2X
 +         STA TX2
 +         LDA P2Y
 +         STA TY2
 +         JSR DRAW         ;​P1-P2
 +
 +:F2S2    LDX P5X
 +         STX TX2
 +         LDX P5Y
 +         STX TY2
 +         JSR DRAW         ;​P1-P5
 +
 +         LDX P6X
 +         STX TX1
 +         LDX P6Y
 +         STX TY1
 +
 +         LDA FACES
 +         AND #$20         ;Also shares an edge with 6
 +         BNE :F2S4
 +
 +         JSR DRAW         ;​P5-P6
 +
 +:F2S4    LDA P2X
 +         STA TX2
 +         LDA P2Y
 +         STA TY2          ;Such is face 2
 +         JSR DRAW         ;​P6-P2
 +         JMP :​FACE3 ​      ;Skip 5
 +
 +:​FACE5 ​  LDA K
 +         SEC
 +         SBC P4Z
 +         BVS :FACE3
 +         CLC
 +         ADC P1Z          ;Same thing again...
 +         BVC :DRAW5
 +         LDA P1Z
 +:​DRAW5 ​  BPL :FACE3
 +         LDA #$10
 +         ORA FACES
 +         STA FACES
 +
 +         LDX P3X
 +         STX TX1
 +         LDX P3Y
 +         STX TY1
 +
 +         AND #$01         ;​Shares with 1
 +         BNE :F5S2
 +
 +         LDA P4X
 +         STA TX2
 +         LDA P4Y
 +         STA TY2
 +         JSR DRAW         ;​P3-P4
 +
 +:F5S2    LDA P7X
 +         STA TX2
 +         LDA P7Y
 +         STA TY2
 +         JSR DRAW         ;​P3-P7
 +
 +         LDA P8X
 +         STA TX1
 +         LDA P8Y
 +         STA TY1
 +
 +         LDA FACES
 +         AND #$20         ;​Shares with 6
 +         BNE :F5S4
 +
 +         JSR DRAW         ;​P7-P8
 +:F5S4    LDA P4X
 +         STA TX2
 +         LDA P4Y
 +         STA TY2          ;P8-P4
 +         JSR DRAW         ;Two more to go!
 +
 +:​FACE3 ​  LDA K
 +         SEC
 +         SBC P1Z
 +         BVS :FACE4
 +         CLC
 +         ADC P2Z
 +         BVC :DRAW3
 +         LDA P2Z
 +:​DRAW3 ​  BPL :​FACE4 ​      ;Ah reckon it's a'​hidden,​ yup
 +         LDA #$04
 +         ORA FACES
 +         STA FACES
 +
 +         LDX P1X
 +         STX TX1
 +         LDX P1Y
 +         STX TY1
 +
 +         AND #$01         ;​Shares with 1
 +         BNE :F3S2
 +
 +         LDA P4X
 +         STA TX2
 +         LDA P4Y
 +         STA TY2
 +         JSR DRAW         ;​P1-P4
 +
 +:F3S2    LDX P5X
 +         STX TX2
 +         LDX P5Y
 +         STX TY2
 +
 +         LDA FACES
 +         AND #$02         ;​Shares with 2
 +         BNE :F3S3
 +
 +         JSR DRAW         ;​P1-P5
 +:F3S3    LDX P8X
 +         STX TX1
 +         LDX P8Y
 +         STX TY1
 +
 +         LDA FACES
 +         AND #$20         ;​Shares with 6
 +         BNE :F3S4
 +
 +         JSR DRAW         ;​P5-P8
 +:F3S4    LDX P4X
 +         STX TX2
 +         LDX P4Y
 +         STX TY2
 +
 +         LDA FACES
 +         AND #$10         ;​Shares with 5
 +         BNE FACEDONE
 +
 +         JSR DRAW         ;​P8-P4
 +         JMP FACEDONE
 +
 +:​FACE4 ​  LDA K
 +         SEC
 +         SBC P2Z
 +         BVS FACEDONE
 +         CLC
 +         ADC P1Z
 +         BVC :DRAW4
 +         LDA P1Z
 +:​DRAW4 ​  BPL FACEDONE
 +
 +         LDA P2X
 +         STA TX1
 +         LDA P2Y
 +         STA TY1
 +
 +         LDA FACES
 +         AND #$01         ;​Shares with 1
 +         BNE :F4S2
 +
 +         LDA P3X
 +         STA TX2
 +         LDA P3Y
 +         STA TY2
 +         JSR DRAW         ;​P2-P3
 +
 +:F4S2    LDA P6X
 +         STA TX2
 +         LDA P6Y
 +         STA TY2
 +
 +         LDA FACES
 +         AND #$02         ;​Shares with 2
 +         BNE :F4S3
 +
 +         JSR DRAW         ;​P2-P6
 +:F4S3    LDA P7X
 +         STA TX1
 +         LDA P7Y
 +         STA TY1
 +
 +         LDA FACES
 +         AND #$20         ;​Shares with 6
 +         BNE :F4S4
 +
 +         JSR DRAW         ;​P6-P7
 +:F4S4    LDA P3X
 +         STA TX2
 +         LDA P3Y
 +         STA TY2
 +
 +         LDA FACES
 +         AND #$10         ;​Shares with 5
 +         BNE FACEDONE
 +
 +         JSR DRAW         ;​P7-P3
 +FACEDONE ​                 ;​Whew! ​ Time for a beer.
 +
 +**** Now we need to unfill the outside from the faces
 +UNFILL ​  LDY YMIN
 +:LOOP    >>>​ SETBUF
 +         LDX #08
 +:L1      LDA (BUFFER),Y
 +         EOR #$FF         ;Go till we find a plotted
 +         BNE :​GOTCHA ​     ;point (i.e. A <> $FF)
 +* LDA #00 ;Unfilling as we go...
 +         STA (BUFFER),Y
 +         LDA #$80
 +         STA BUFFER
 +         LDA (BUFFER),Y
 +         EOR #$FF
 +         BNE :GOTCHA
 +* LDA #00
 +         STA (BUFFER),Y
 +         STA BUFFER
 +         INC BUFFER+1
 +         ​DEX ​             ;This is our safety valve
 +         BNE :L1          ;Really shouldn'​t need it
 +         JSR CHOKE
 +         JMP SWAPBUF
 +
 +:​GOTCHA ​                  ;A contains the EOR plot value
 +         STA TEMP1        ;Now find the high bit
 +         LDA #00
 +:L2      SEC
 +         ROL
 +         LSR TEMP1        ;Should really use a table
 +         BNE :L2          ;for this!
 +         AND (BUFFER),Y
 +         STA (BUFFER),Y
 +
 +         LDA ZTEMP        ;Now go to the end
 +                          ;Carry is clear
 +                          ;Actually we add 7
 +         ADC #$06         ;16 columns of 128 bytes
 +         STA BUFFER+1
 +         LDA #$80
 +         STA BUFFER
 +:​LOOP2 ​  LDA (BUFFER),​Y ​  ;And work backwards!
 +         EOR #$FF
 +         BNE :GOTCHA2
 +         STA (BUFFER),Y
 +         STA BUFFER ​      ;​Stick a zero into buffer
 +         LDA (BUFFER),Y
 +         EOR #$FF
 +         BNE :GOTCHA2
 +         STA (BUFFER),Y
 +         LDA #$80
 +         STA BUFFER
 +         DEC BUFFER+1
 +         BNE :LOOP2
 +
 +:GOTCHA2 STA TEMP1        ;Again find the high bit
 +         LDA #00
 +:L3      SEC
 +         ROR
 +         ASL TEMP1
 +         BNE :L3
 +         AND (BUFFER),Y
 +         STA (BUFFER),Y
 +
 +         ​INY ​             ;Now keep going
 +         CPY YMAX
 +         BCC :LOOP        ;Until we hit ymax!
 +         BEQ :LOOP        ;We need the last one too.
 +
 +**** Swap buffers
 +
 +SWAPBUF ​ LDA VMCSB
 +         EOR #$02         ;​Pretty tricky, eh?
 +         STA VMCSB
 +         LDA #$08
 +         EOR ZTEMP        ;ztemp=high byte just flips
 +         STA ZTEMP        ;between $30 and $38
 +
 +         JMP MAIN         ;​Around and around we go...
 +
 +         TXT 'Same thing we do every night, Pinky: '
 +         TXT 'try to take over the world!'​
 +
 +
 +*-------------------------------
 +* General questionable-value error procedure
 +
 +CHOKE    LDX #00
 +:LOOP    LDA :CTEXT,X
 +         BEQ :DONE
 +         JSR CHROUT
 +         INX
 +         JMP :LOOP
 +:DONE    RTS
 +:​CTEXT ​  HEX 0D           ;CR
 +         TXT '​something choked :('
 +         HEX 0D00
 +
 +         TXT '​Narf!'​
 +
 +*-------------------------------
 +* Drawin'​ a line.  A fahn lahn.
 +
 +*** Some useful macros
 +
 +PLOTPX ​  ​MAC ​             ;plot a point in x
 +         ​PHA ​             ;Use this one every time
 +         LDA BITP,​X ​      ;X is increased
 +         BMI C1
 +         LDA #$80         ;​Table has been rearranged
 +         EOR BUFFER ​      ;for filling faces
 +         STA BUFFER
 +         BMI C2
 +         INC BUFFER+1
 +C2       LDA #​%01111111 ​  ;Note that this is changed
 +C1       AND (BUFFER),​Y ​  ;for plotting filled faces
 +         STA (BUFFER),Y
 +         ​PLA ​             ;Need to save A!
 +         <<<​
 +
 +PLOTPY ​  ​MAC ​             ;Plot a point in y: simpler and necessary!
 +         ​PHA ​             ;Use this one when you just increase Y
 +         LDA BITP,​X ​      ;but X doesn'​t change
 +         AND (BUFFER),Y
 +         STA (BUFFER),Y
 +         PLA
 +         <<<​
 +
 +CINIT    MAC              ;Macro to initialize the counter
 +         LDA ]1           ;dx or dy
 +         LSR
 +         EOR #$FF         ;(Not really two's complement)
 +         ADC #$01         ;A = 256-dx/2 or 256-dy/2
 +         <<< ​             ;The dx/2 makes a nicer looking line
 +
 +XSTEP    MAC              ;Macro to take a step in X
 +XLOOP    INX
 +         ADC DY
 +         BCC L1
 +* Do we use INY or DEY here?
 +         IF I,]1          ;If the first character is an '​I'​
 +         INY
 +         ELSE
 +         DEY
 +         FIN
 +         SBC DX
 +L1       >>>​ PLOTPX ​      ;​Always take a step in X
 +         CPX X2
 +         BNE XLOOP
 +         <<<​
 +
 +YSTEP    MAC              ;Same thing, but for Y
 +YLOOP    IF I,]1
 +         INY
 +         ELSE
 +         DEY
 +         ​CLC ​             ;Very important!
 +         FIN
 +         ADC DX
 +         BCC L2
 +         ​INX ​             ;Always increase X
 +         SBC DY
 +         >>>​ PLOTPX
 +         JMP L3
 +L2       >>>​ PLOTPY ​      ;We only increased Y
 +L3       CPY Y2
 +         BNE YLOOP
 +         <<<​
 +
 +**** Initial line setup
 +
 +DRAW     >>>​ MOVE,​TX1 ​    ;​X1 ​ ;Move stuff into zero page
 +         >>>​ MOVE,​TX2 ​    ;​X2 ​ ;Where it can be modified
 +         >>>​ MOVE,​TY1 ​    ;Y1
 +         >>>​ MOVE,​TY2 ​    ;Y2
 +         >>>​ SETBUF ​      ;Now we can clobber the buffer
 +
 +         ​SEC ​             ;Make sure x1<x2
 +         LDA X2
 +         SBC X1
 +         BCS :CONT
 +         LDA Y2           ;If not, swap P1 and P2
 +         LDY Y1
 +         STA Y1
 +         STY Y2
 +         LDA X1
 +         LDY X2
 +         STY X1
 +         STA X2
 +
 +         SEC
 +         SBC X1           ;Now A=dx
 +:CONT    STA DX
 +         LDX X1           ;Put x1 into X, now we can trash X1
 +
 +COLUMN ​  LDA X1           ;Find the first column for X
 +         ​LSR ​             ;(This can be made much faster!)
 +         ​LSR ​             ;There are x1/8 128 byte blocks
 +         ​LSR ​             ;Which means x1/16 256 byte blocks
 +         LSR
 +         BCC :EVEN        ;With a possible extra 128 byte block
 +         LDY #$80         ;if so, set the high bit
 +         STY BUFFER
 +         CLC
 +:EVEN    ADC BUFFER+1 ​    ;Add in the number of 256 byte blocks
 +         STA BUFFER+1 ​    ;And store it!
 +
 +         SEC
 +         LDA Y2           ;​Calculate dy
 +         SBC Y1
 +         BCS :​CONT2 ​      ;Is y2>y1?
 +         EOR #$FF         ;​Otherwise dy=y1-y2
 +         ADC #$01
 +:​CONT2 ​  STA DY
 +         CMP DX           ;​Who'​s bigger: dy or dx?
 +         BCS STEPINY ​     ;If dy, we need to take big steps in y
 +
 +STEPINX ​ LDY Y1           ;X is already set to x1
 +         LDA BITP,​X ​      ;Plot the first point
 +         AND (BUFFER),Y
 +         STA (BUFFER),Y
 +         >>>​ CINIT,​DX ​    ;​Initialize the counter
 +         CPY Y2
 +         BCS XDECY        ;Do we step forwards or backwards in Y?
 +
 +XINCY    >>>​ XSTEP,INY
 +         RTS
 +
 +STEPINY ​ LDY Y1           ;​Well,​ a little repetition never hurt anyone
 +         LDA BITP,X
 +         AND (BUFFER),Y
 +         STA (BUFFER),Y
 +         >>>​ CINIT,DY
 +         CPY Y2
 +         BCS YDECY
 +
 +YINCY    >>>​ YSTEP,INY
 +         RTS
 +
 +XDECY    >>>​ XSTEP,​DEY ​   ;This is put here so that
 +         ​RTS ​             ;Branches are legal
 +
 +YDECY    >>>​ YSTEP,DEY
 +         RTS
 +
 +
 +*-------------------------------
 +* Clean up
 +
 +CLEANUP ​ LDA VMCSB        ;Switch char rom back in
 +         AND #​%11110101 ​  ;​default
 +         STA VMCSB
 +
 +         ​RTS ​             ;bye!
 +
 +         TXT 'Happy Holidays! '
 +         TXT 'slj 12/94'
 +
 +*-------------------------------
 +* Set up bit table
 +
 +         DS ^             ;​Clear to end of page
 +                          ;So that tables start on a page boundary
 +BITP     LUP 16           ;128 Entries for X
 +         DFB %01111111
 +         DFB %10111111
 +         DFB %11011111
 +         DFB %11101111
 +         DFB %11110111
 +         DFB %11111011
 +         DFB %11111101
 +         DFB %11111110
 +         --^
 +
 +SIN                       ;​Table of sines, 120 bytes
 +COS      EQU SIN+128 ​     ;Table of cosines
 +                          ;Both of these trig tables are
 +                          ;currently set up from BASIC
 +ZDIV     EQU COS+128 ​     ;Division table
 +TMATH    EQU ZDIV+384 ​    ;Math table of f(x)=x*x/​256
 +
 +And here are the native C64 files:
 +
 +
 +begin 600 cube3d2.0.lnx.uu
 +M`0A;"​`H`ES4S,​C@P+#​`ZES4S,​C@Q+#​`ZES8T-BS"​*#​$V,​BDZF2*3$1$1$1$1
 +M$1$B.IDB("​`@("​!54T4@3%E.6"​!43R!$25-33TQ612!42$E3($9)3$4B.HDQ
 +M,​`````T@,​B`@*DQ93E@@6$E)($)9(%=)3$P@0T]23$59#​2`U(`U#​54)%,​T0R
 +M+C`N3Z"​@H*"​@#​2`Q,​R`-4`T@,​34U(`U#​54)%,​T0R+C`N4Z"​@H*"​@#​2`X-B`-
 +M4`T@,​C$X(`U#​54)%,​T0R+C$N3Z"​@H*"​@#​2`Q,​R`-4`T@,​34U(`U)3DE4,​T0R
 +M+C"​@H*"​@H*"​@#​2`Q,"​`-4`T@-3`@#​4Y/​5$53,​BXPH*"​@H*"​@H*`-(#​0@#​5`-
 +M(#​$Y,​R`-````````````````````````````````````````````````````
 +M````````````````````````````````````````````````````````````
 +M````````````````````````````````````````````````````````````
 +M````````````````````````````````````````````````````````````
 +M````````````````````````````````````````````````````````````
 +M``````````````````"​`J0"​-(-"​-(="​M&​-`I#​PD0C1C0H`"​I'​X7[J8"​%_$Q9
 +M@9,​%$1$1("​`@("​`@("​`@("​`@($-50D4S1"​!6,​BXP#​0T@("​`@("​`@("​`@("​`@
 +M("​`@("​!"​60V?​("​`@(%-415!(14X@2E5$1)D@("​`@1T5/​4D=%(%1!64Q/​4@T-
 +MFR`@0TA%0TL@3U54(%1(12!*04XN(#​DU($E34U5%($]&#​98@($,​]2$%#​2TE.
 +M1YL@1D]2($U/​4D4@1$5404E,​4R$-#​1T=GA)&,​2]&,​I(@+2!)3D,​O1$5#​(%@M
 +M4D]4051)3TX-'​1T21C,​O1C22("​T@24Y#​+T1%0R!9+5)/​5$%424].#​1T=$D8U
 +M+T8VDB`M($E.0R]$14,​@6BU23U1!5$E/​3@T='​1)&​-Y(@4D531513#​2`@4%)%
 +M4U,​@42!43R!154E4#​0T%("​`@("​`@4%)%4U,​@04Y9($M%62!43R!"​14=)3@T`
 +ML?​OP*2#​2_\C0]N;​\3%F!=$A)4R!)4R!!(%-%0U)%5"​!415A4($U%4U-!1T4A
 +M(.3_R0#​P^:​F/​A2.%):​D!C2'​0J9,​@TO^I`(TAT*E`:​0R%^ZD%A?​RI`*``H@`8
 +MD?​O(:​1"​0^1BE^VDHA?​NE_&​D`A?​R@`.B*X!#​0Y*D`A:​.I,​(6DA0*M&​-`I\0D.
 +MC1C0J0"​%885BA6.%9(5EA698(.3_R870"​Z5AR3SP6.9A3%>"​R8G0":​5A\$O&​
 +M84Q7@LF&​T`NE8LD\\#​SF8DQ7@LF*T`FE8O`OQF),​5X+)A]`+I6/​)//​`@YF-,​
 +M5X+)B]`)I6/​P$\9C3%>"​R8C0`TSC@<​E1T`-,​7(MX&​*5D96'​)>​)`"​Z7B%9!BE
 +M965BR7B0`NEXA648I69E8\EXD`+I>​(5F.*5EY6:​P`FEXA6<​8I65E9LEXD`+I
 +M>​(5H&​*5D96;​)>​)`"​Z7B%:​3BE9.5FL`)I>​(5J&​*5D96C)>​)`"​Z7B%:​SBE9.5G
 +ML`)I>​(5L&​*5D96?​)>​)`"​Z7B%;​3BE:​.5DL`)I>​(5N.*5EY62P`FEXA6\8I61E
 +M9<​EXD`+I>​(5P&​*9GO0"​-IFA]`(V%I:​9GO8",​.*9H_8",​A::​F9;​V`C!`.&​$G_
 +M:​0$*&​$G_:​0%,​)X,​*A:<​XIFZ]`(VF;?​T`C3BF:​_T`C1BF;'​T`C1`.&​$G_:​0%*
 +M&​$G_:​0%,​48-*&​*9I?​8",​.*9J_8",​A:​@XIFN]@(RF;/​V`C#​BF;?​V`C#​BF;​OV`
 +MC!`.&​$G_:​0%*&​$G_:​0%,​AX-*&​*9I?​0"​-&​*9J?​0"​-A:​FF;​[V`C#​BF</​V`C(6J
 +MIFR]@(PXIF[]@(PXIFW]@(PXIFO]@(P0#​AA)_VD!2AA)_VD!3,​J#​2ABF:​GT`
 +MC3BF:?​T`C86K&​*9LO0"​-IFU]`(TXIFO]`(TXIF[]`(T0#​AA)_VD!2AA)_VD!
 +M3`"​$2ABF:​7V`C!BF:​GV`C(6L&​*9OO0"​-IG!]`(V%K4Q(A&​=%12!B4D%)3BP@
 +M5TA!5"​!$3R!93U4@5T%.5"​!43R!$3R!43TY)1TA4/​ZE`A?>​%^*6M&&​6K&&​6L
 +MA5>​JO8"​-J*6G&&​6E&&​6FA2(82?​]I`84DL2(X\208:​4"​JI:​H89:​@89:​F%(AA)
 +M_VD!A22Q(CCQ)!AI0,​7WL`2%]Y`&​Q?​B0`H7XJ(:​2A).EK1AEJSCEK(58JKV`
 +MC:​BEIQAEI3CEIH4B&​$G_:​0&​%)+$B./​$D&&​E`JJ6J&&​6H..6IA2(82?​]I`84D
 +ML2(X\208:​4#​%][`$A?>​0!L7XD`*%^*B&​E(25I:​TXY:​LXY:​RJO8"​-J*6G..6E
 +M..6FA2(82?​]I`84DL2(X\208:​4"​JI:​HXY:​@XY:​F%(AA)_VD!A22Q(CCQ)!AI
 +M0,​7WL`2%]Y`&​Q?​B0`H7XJ(:​6A*ZEK3CEJQAEK(59JKV`C:​BEISCEI1AEIH4B
 +M&​$G_:​0&​%)+$B./​$D&&​E`JJ6J..6H&&​6IA2(82?​]I`84DL2(X\208:​4#​%][`$
 +MA?>​0!L7XD`*%^*B&​KX2P&​*6G2?​]I`86G&​*6J2?​]I`86J&​*6M2?​]I`86MI:​TX
 +MY:​L89:​RJO8"​-J*6G..6E&&​6FA2(82?​]I`84DL2(X\208:​4"​JI:​HXY:​@89:​F%
 +M(AA)_VD!A22Q(CCQ)!AI0,​7WL`2%]Y`&​Q?​B0`H7XJ(91A%*EK3CEJSCEK*J]
 +M@(VHI:<​XY:​4XY::​%(AA)_VD!A22Q(CCQ)!AI0*JEJCCEJ#​CEJ84B&​$G_:​0&​%
 +M)+$B./​$D&&​E`Q?>​P!(7WD`;​%^)`"​A?​BHAG&​$4*6M&&​6K..6LJKV`C:​BEIQAE
 +MI3CEIH4B&​$G_:​0&​%)+$B./​$D&&​E`JJ6J&&​6H..6IA2(82?​]I`84DL2(X\208
 +M:​4#​%][`$A?>​0!L7XD`*%^*B&​LX2TI:​T89:​L89:​R%8*J]@(VHI:<​89:​489::​%
 +M(AA)_VD!A22Q(CCQ)!AI0*JEJAAEJ!AEJ84B&​$G_:​0&​%)+$B./​$D&&​E`Q?>​P
 +M!(7WD`;​%^)`"​A?​BHAK&​$LJD`A:​.E`H6DA?​RI@(7[J0"​B"​*``D:​.1^\C$]]#​W
 +MJ?​^1HY'​[R,​3XD/>​I`)&​CD?​O($/​F@`.:​DYOS*T-JI`(6UI;​8XY5=P1!AE8%`"​
 +MI6`0.ZD!A;​6EDH4_I9.%0*64A4&​EE85"​(#​.*I9:​%/​Z6NA4`@,​XJEKX5!I;"​%
 +M0B`SBJ62A3^EDX5`(#​.*3-J'​I;​8XY6!P01AE5U`"​I5<​0.*D@A;​6EL85!I;​*%
 +M0J6SA3^EM(5`(#​.*I7&​%0:​50A4(@,​XJE484_I5*%0"​`SBJ6QA4&​ELH5"​(#​.*
 +MI;​8XY5=P4!AE65`"​I5D01ZD"​!;​6%M::​2AC^FDX9`*0'​0"​Z64A4&​EE85"​(#​.*
 +MIK&&​0::​RAD(@,​XJFLX8_IK2&​0*6U*2#​0`R`SBJ64A4&​EE85"​(#​.*3(6(I;​8X
 +MY5EP31AE5U`"​I5<​01*D0!;​6%M::​6AC^FKH9`*0'​0"​Z6OA4&​EL(5"​(#​.*I7&​%
 +M0:​50A4(@,​XJE484_I5*%0*6U*2#​0`R`SBJ6OA4&​EL(5"​(#​.*I;​8XY5=P7!AE
 +M6%`"​I5@04ZD$!;​6%M::​2AC^FDX9`*0'​0"​Z6OA4&​EL(5"​(#​.*IK&&​0::​RAD*E
 +MM2D"​T`,​@,​XJF488_IE*&​0*6U*2#​0`R`SBJ:​OAD&​FL(9"​I;​4I$-!B(#​.*3$2)
 +MI;​8XY5AP51AE5U`"​I5<​03*64A3^EE85`I;​4I`=`+I9:​%0:​6NA4(@,​XJELX5!
 +MI;​2%0J6U*0+0`R`SBJ5QA3^E4(5`I;​4I(-`#​(#​.*I9:​%0:​6NA4*EM2D0T`,​@
 +M,​XJD]ZD`A:​.E`H6DH@BQHTG_T!N1HZF`A:​.QHTG_T`^1HX6CYJ3*T.4@"​8I,​
 +MN(F%^ZD`."​I&​^]#​Z,:​.1HZ4":​0:​%I*F`A:​.QHTG_T!21HX6CL:​-)_]`*D:​.I
 +M@(6CQJ30YH7[J0`X:​@;​[T/​HQHY&​CR,​3XD)#​PCJT8T$D"​C1C0J0A%`H4"​3/&​!
 +M<​T%-12!42$E.1R!712!$3R!%5D5262!.24=(5"​P@<​$E.2UDZ(%1262!43R!4
 +M04M%($]615(@5$A%(%=/​4DQ$(:​(`O1B*\`<​@TO_H3`N*8`U33TU%5$A)3D<​@
 +M0TA/​2T5$(#​HH#​0!N05)&​(:​4_A?​NE087]I4"​%_*5"​A?​ZI`(6CI0*%I#​BE_>​7[
 +ML!.E_J3\A?​R$_J7[I/​V$^X7]..7[A?​FF^Z7[2DI*2I`%H("​$HQAEI(6D.*7^
 +MY?​RP!$G_:​0&​%^L7YL#​BD_+T`C#&​CD:​.E^4I)_VD!Q/​ZP:​.AE^I`#​R.7Y2+T`
 +MC#​`,​J8!%HX6C,​`+FI*E_,:​.1HVCD_=#​=8*3\O0",,:​.1HZ7Z2DG_:​0'​$_K!4
 +MR&​7YD!WHY?​I(O0",,​`RI@$6CA:,​P`N:​DJ7\QHY&​C:​$P"​BTB]`(PQHY&​C:,​3^
 +MT-%@Z&​7ZD`.(Y?​E(O0",,​`RI@$6CA:,​P`N:​DJ7\QHY&​C:​.3]T-U@B!AE^9`=
 +MZ.7Z2+T`C#​`,​J8!%HX6C,​`+FI*E_,:​.1HVA,​5XM(O0",,:​.1HVC$_M#​08*T8
 +MT"​GUC1C08&​A!4%!9(&​A/​3$E$05E3(2!33$H@,​3(O.30`````````````````
 +M````````````````````````````````````````````````````````````
 +M````````````````````````````````````````````````````````````
 +M````````````````````````````````````?​[_?​[_?​[_?​Y_O]_O]_O]_G^_
 +MW^_W^_W^?​[_?​[_?​[_?​Y_O]_O]_O]_G^_W^_W^_W^?​[_?​[_?​[_?​Y_O]_O]_O]
 +M_G^_W^_W^_W^?​[_?​[_?​[_?​Y_O]_O]_O]_G^_W^_W^_W^?​[_?​[_?​[_?​Y_O]_O
 +M]_O]_G^_W^_W^_W^?​[_?​[_?​[_?​X!A?​K%^;​`XI/​R]`(PQHY&​CI?​E*2?​]I`<​3^
 +ML&​CH9?​J0`\CE^4B]`(PP#​*F`1:​.%HS`"​YJ2I?​S&​CD:​-HY/​W0W6"​D_+T`C#&​C
 +MD:​.E^DI)_VD!Q/​ZP5,​AE^9`=Z.7Z2+T`C#​`,​J8!%`'​`J*BHJ*BHJ*BHJ*BHJ
 +M*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*@TJH*"​@H*"​@H*"​@H*"​@H*"​@H*"​@H*"​@H*"​@
 +MH*"​@H*"​@*@TJH'​-415!(14Z@:​E5$1*"​@H*"​@H*"​@H*"​@H*"​@H*"​@*@TJH&​=%
 +M3U)'​1:​!T05E,​3U*@H*"​@H*"​@H*"​@H*"​@H*"​@*@TJH'​-405)4140ZH#<​O,​3$O
 +M.32@H*"​@H*"​@H*"​@H*"​@*@TJH&​9)3DE32$5$.J`W+S$Y+SDTH*"​@H*"​@H*"​@
 +MH*"​@*@TJH%8R+C"​@8T]-4$Q%5$5$.J`Q,​B\Q-R\Y-*"​@H*"​@*@TJH*"​@H*"​@
 +MH*"​@H*"​@H*"​@H*"​@H*"​@H*"​@H*"​@H*"​@*@TJH'​=%3$PLH$E&​H$%,​3*!'​3T53
 +MH%=%3$R@5$A)4Z"​@*@TJH%!23T=204V@5TE,​3*!23U1!5$6@0:​!#​54)%+J"​@
 +M*@TJH*"​@H*"​@H*"​@H*"​@H*"​@H*"​@H*"​@H*"​@H*"​@H*"​@*@TJH%8R+C"​@*Z!N
 +M15>​@04Y$H&​E-4%)/​5D5$(:"​@H*"​@*@TJH&​Y/​5Z!7251(H$9!4U1%4J!23U54
 +M24Y%4RR@H*"​@*@TJH$A)1$1%3J!355)&​04-%4RR@1DE,​3$5$H*"​@H*"​@*@TJ
 +MH$9!0T53+*!!3D2@15A44D&​@5$]0H%-%0U)%5*"​@*@TJH%1%6%2@34534T%'​
 +M15,​AH*"​@H*"​@H*"​@H*"​@H*"​@*@TJH*"​@H*"​@H*"​@H*"​@H*"​@H*"​@H*"​@H*"​@
 +MH*"​@H*"​@*@TJH'​1(25.@4%)/​1U)!3:​!)4Z!)3E1%3D1%1*!43Z"​@*@TJH$%#​
 +M0T]-4$%.6:​!42$6@05)424-,​1:​!)3J"​@H*"​@*@TJH&,​]:​$%#​2TE.1RR@:​D%.
 +M+J`Y-:​!)4U-512Z@H*"​@*@TJH&​9/​4J!$151!24Q3H$].H%1(25.@4%)/​1U)!
 +M32R@*@TJH%)%042@5$A%H$%25$E#​3$4AH*"​@H*"​@H*"​@H*"​@*@TJH*"​@H*"​@
 +MH*"​@H*"​@H*"​@H*"​@H*"​@H*"​@H*"​@H*"​@*@TJH'​=2251%H%1/​H%53(:"​@H*"​@
 +MH*"​@H*"​@H*"​@H*"​@*@TJH*"​@H*"​@H*"​@H*"​@H*"​@H*"​@H*"​@H*"​@H*"​@H*"​@
 +M*@TJH&​U94T5,​1J!72$5.H%E/​54Y'​H$1)1*"​@H*"​@H*"​@*@TJH$5!1T523%F@
 +M1E)%455%3E2@H*"​@H*"​@H*"​@H*"​@*@TJH&​1/​0U1/​4J!!3D2@<​T%)3E0LH$%.
 +M1*!(14%21*"​@*@TJH$=214%4H&​%21U5-14Y4H*"​@H*"​@H*"​@H*"​@H*"​@*@TJ
 +MH*!A0D]55*!)5*!!3D2@04)/​550ZH$)55*"​@H*"​@*@TJH*!%5D5234]21:"​@
 +MH*"​@H*"​@H*"​@H*"​@H*"​@H*"​@*@TJH&​-!346@3U54H$)9H%1(1:​!304U%H&​1/​
 +M3U*@H*"​@*@TJH$%3H$E.H&​F@5T5.5"​Z@H*"​@H*"​@H*"​@H*"​@H*"​@*@TJH*"​@
 +MH"​V@<​E5"​04E9052@H*"​@H*"​@H*"​@H*"​@H*"​@*@TJH*"​@H*"​@H*"​@H*"​@H*"​@
 +MH*"​@H*"​@H*"​@H*"​@H*"​@*@TJH'​1(3U5'​2*!IH%-014%+H%=)5$B@5$A%H*"​@
 +MH*"​@*@TJH%1/​3D=515.@3T:​@345.H$%.1*!/​1J!!3D=,​15.@*@TJH$%.1*!(
 +M059%H$Y/​5*!,​3U9%+*!IH$%-H*"​@H*"​@*@TJH$)%0T]-1:​!!4Z!33U5.1$E.
 +M1Z!"​4D%34RR@3U*@*@TJH$&​@5$E.2TQ)3D>​@0UE-0D%,​+J"​@H*"​@H*"​@H*"​@
 +M*@TJH*"​@H"​V@,:​!C3U))3E1(24%.4Z`Q,​Z"​@H*"​@H*"​@*@TJH*"​@H*"​@H*"​@
 +MH*"​@H*"​@H*"​@H*"​@H*"​@H*"​@H*"​@*@TJH'​`N<​RZ@=$A)4Z!705.@5U))5%1%
 +M3J!54TE.1Z"​@*@TJH*"​@H*"​@;​4523$E.H#​$R."​Z@H*"​@H*"​@H*"​@H*"​@*@TJ
 +M*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*@T-(&​]R9R`D.#​`P,​`T-
 +M*J!C3TY35$%.5%,​-#​6)U9F8Q(&​5Q=2`D,​S`P,"​`[9DE24U2@0TA!4D%#​5$52
 +MH%-%5`UB=69F,​B!E<​74@)#,​X,#​`@.W-%0T].1*!#​2$%204-415*@4T54#​6)U
 +M9F9E<​B!E<​74@)&​$S(#​MP4D5354U!0DQ9H%1(1:​!405!%H%=/​3B=4H$)%H%)5
 +M3DY)3D<​->#​$@97%U("​1F8B`[<​$])3E13H$9/​4J!$4D%724Y'​H$&​@3$E.10UY
 +M,​2!E<​74@)&​9C(#​MT2$531:​!:​15)/​H%!!1T6@041$4D534T53#​7@R(&​5Q=2`D
 +M9F0@.T1/​3B=4H$-/​3D9,​24-4H%=)5$B@8F%S:​6,​->​3(@97%U("​1F90UD>"​!E
 +M<​74@)&​8Y#​61Y(&​5Q=2`D9F$-=&​5M<#​$@97%U("​1F8B`[;​T:​@0T]54E-%+*!#​
 +M3U5,​1*!#​3TY&​3$E#​5*!7251(H%@Q#​71E;​7`R(&​5Q=2`D9F,​@.W1%35!/​4D%2
 +M6:​!605))04),​15,​->​G1E;​7`@97%U("​0P,​B`[=5-%1*!&​3U*@0E5&​1D52H%-7
 +M05`NH*!D3TXG5*!43U5#​2"​X->​C$@97%U("​0R,​B`[=5-%1*!"​6:​!-051(H%)/​
 +M551)3D4->​C(@97%U("​0R-"​`[9$].)U2@5$]50TB@5$A%4T6@14E42$52(0UK
 +M(&​5Q=2`D8C8@.V-/​3E-404Y4H%53142@1D]2H$A)1$1%3@T@("​`[4U521D%#​
 +M1:​!$151%0U1)3TZ@+:​!$3TXG5*!43U5#​2`UF86-E<​R!E<​74@)&​(U(#​MU4T5$
 +MH$E.H$A)1$1%3J!355)&​04-%4RX->​6UI;​B!E<​74@)&​8W(#​MU4T5$H$E.H$9)
 +M3$Q%1*!&​04-%4Z`M+:​!!4PUY;​6%X(&​5Q=2`D9C@@.U5354%,​+*!$3TXG5*!4
 +M3U5#​2`UA;​F=M87@@97%U(#​$R,"​`[=$A%4D6@05)%H#​(J4$DO04Y'​34%8H$%.
 +M1TQ%4PT-*J!V:​6,​-#​79M8W-B(&​5Q=2`D9#​`Q.`UB:​V=N9"​!E<​74@)&​0P,​C`-
 +M8F]R9&​5R(&​5Q=2`D9#​`R,​0US<​W1A<​G0@97%U(#​$S-#​0@.U)/​5Z`YH$E.H%-#​
 +M4D5%3J!-14U/​4EF@052@,​3`R-`T-#​2J@:​T523D%,#​0UC:'​)O=70@97%U("​1F
 +M9F0R#​6=E=&​EN(&​5Q=2`D9F9E-`T-*J!S3TU%H%9!4DE!0DQ%4PT-='​@Q(#​T@
 +M)#​-F#​71Y,​2`]("​0T,​`UT>#​(@/​2`D-#​$-='​DR(#​T@)#​0R#​7`Q>"​`]("​0Y,​B`[
 +M=$A%4T6@05)%H%1%35!/​4D%26:​!35$]204=%#​7`Q>​2`]("​0Y,​R`[=5-%1*!)
 +M3J!03$]45$E.1Z!42$6@4%)/​2D5#​5$E/​3@UP,​G@@/​2`D.30-<#​)Y(#​T@)#​DU
 +M(#​MT2$59H$%21:​!(15)%H%-/​H%1(052@5T4-<#​-X(#​T@)#​DV(#​M$3TXG5*!(
 +M059%H%1/​H%)%0T%,​0U5,​051%H%1(14TN#​7`S>​2`]("​1A90UP-'​@@/​2`D868@
 +M.W1(15F@34%+1:​!,​249%H$5!4UDN#​7`T>​2`]("​1B,​`UP-7@@/​2`D8C$@.W=(
 +M6:​!!4D6@64]5H$Q/​3TM)3D>​@052@346@3$E+1:​!42$%4/​PUP-7D@/​2`D8C(@
 +M.V1/​3B=4H%E/​5:​!44E535*!-13\-<#​9X(#​T@)&​(S#​7`V>​2`]("​1B-"​`[:​$%6
 +M24Y'​H$%.3U1(15*@0TA)3$2@5T%33B=4H$U9H$E$14$N#​7`W>"​`]("​0W,​0UP
 +M-WD@/​2`D-3`-<#​AX(#​T@)#​4Q#​7`X>​2`]("​0U,​@UP,​7H@/​2`D-3<​@.W1(15-%
 +MH$%21:​!:​+4-/​3U)$24Y!5$53#​7`R>​B`]("​0U."​`[=T6@3TY,​6:​!.145$H%1(
 +M15-%H$9/​55*@5$^@0TA%0TL-<#​1Z(#​T@)#​4Y(#​M&​3U*@2$E$1$5.H$9!0T53
 +M#​7`U>​B`]("​0V,​`UD<​W@@/​2`D-C$@.V1S>​*!)4Z!42$6@24Y#​4D5-14Y4H$9/​
 +M4@T@("​`[4D]4051)3D>​@05)/​54Y$H%@-9'​-Y(#​T@)#​8R(#​MS24U)3$%2H$9/​
 +M4J!D<​WDLH&​1S>​@UD<​WH@/​2`D-C,​-<​W@@/​2`D-C0@.W1(15-%H$%21:​!42$6@
 +M04-454%,​H$%.1TQ%4Z!)3J!8H%F@04Y$H%H-<​WD@/​2`D-C4-<​WH@/​2`D-C8-
 +M=#​$@/​2`D-C<​@.W1(15-%H$%21:​!54T5$H$E.H%1(1:​!23U1!5$E/​3@UT,​B`]
 +M("​0V.`UT,​R`]("​0V.2`[<​T5%H%1(1:​!!4E1)0TQ%H$9/​4J!-3U)%H$1%5$%)
 +M3%,​-=#​0@/​2`D-F$-=#​4@/​2`D-F(-=#​8@/​2`D-F,​-=#<​@/​2`D-F0-=#​@@/​2`D
 +M-F4-=#​D@/​2`D-F8-=#​$P(#​T@)#<​P#​6$Q,​2`]("​1A-2`[=$A%4T6@05)%H%1(
 +M1:​!%3$5-14Y44Z!/​1J!42$6@4D]4051)3TZ@34%44DE8#​6(Q,​B`]("​1A-B`[
 +M>'​EZ#​6,​Q,​R`]("​1A-PUD,​C$@/​2`D83@@.W1(1:​!.54U"​15*@1$5.3U1%4Z`H
 +M4D]7+$-/​3%5-3BD-93(R(#​T@)&​$Y#​68R,​R`]("​1A80UG,​S$@/​2`D86(-:#,​R
 +M(#​T@)&​%C#​6DS,​R`]("​1A9`T-#​2HJ*J!M04-23U,​-#​6UO=F4@;​6%C#​2!L9&​$@
 +M73$-('​-T82!=,​@T@/#​P\#​0UG971K97D@;​6%C("​`[=T%)5*!&​3U*@0:​!+15E0
 +M4D534PUW86ET(&​IS<​B!G971I;​@T@8VUP(",​P,​`T@8F5Q('​=A:​70-(#​P\/​`T-
 +M9&​5B=6<​@;​6%C("​`[<​%))3E2@0:​!#​2$%204-415(-H"​!D;​Z`P("​`[9$].)U2@
 +M05-314U"​3$4-#​2!L9&​$@(UTQ#​2!J<​W(@8VAR;​W5T#​2`^/​CX@9V5T:​V5Y(#​MA
 +M3D2@5T%)5*!43Z!#​3TY424Y510T@8VUP(",​G4R<​@.VU9H%-%0U)%0U2@4U=)
 +M5$-(H$M%60T@8FYE(&​PQ#​2!J<​W(@8VQE86YU<​`T@:​FUP(&​1O;​F4-;#​$@8VUP
 +M(",​G6"<​@.VU9H%-%0U)%5*!!0D]25*!+15D-(&​)N92!D;​VYE#​2!J;​7`@8VQE
 +M86YU<​`T@9FEN#​61O;​F4@/#​P\#​0UD96)U9V$@;​6%C#​2!D;​Z`P#​2!L9&​$@73$-
 +M('​-T82`Q,#​(T#​2!F:​6X-9&​]N96$@/#​P\#​0TJ+2TM+2TM+2TM+2TM+2TM+2TM
 +M+2TM+2TM+2TM+2TM+0T-(&​QD82`C)#​`P#​2!S=&​$@8FMG;​F0-('​-T82!B;​W)D
 +M97(-(&​QD82!V;​6-S8@T@86YD(",​E,#​`P,#​$Q,​3$@.W-#​4D5%3J!-14U/​4EF@
 +M5$^@,​3`R-`T@;​W)A(",​E,#​`P,​3`P,#​`-('​-T82!V;​6-S8@T-(&​QD>​2`C,#​`-
 +M(&​QD82`C/'​1T97AT#​2!S=&​$@=&​5M<#​$-(&​QD82`C/​G1T97AT#​2!S=&​$@=&​5M
 +M<#​(-(&​IM<"​!T:​71L90UT=&​5X="​!H97@@.3,​P-3$Q,​3$Q,​2`[0TQ%05*@4T-2
 +M145.+*!72$E412R@0U)34J!$3@T@='​AT(">​@H*"​@H*"​@H*"​@H*"​@0U5"​13-$
 +MH%8R+C`G+#​!$+#​!$#​2!T>'​0@)Z"​@H*"​@H*"​@H*"​@H*"​@H*"​@H$)9)RPP1`T@
 +M:&​5X(#​EF(#​M#​64%.#​2!T>'​0@)Z"​@H*!35$502$5.H$I51$0G#​2!H97@@.3D-
 +M('​1X="​`GH*"​@H$=%3U)'​1:​!405E,​3U(G+#​!$+#​!$#​2!H97@@.6(-('​1X="​`G
 +MH*!#​2$5#​2Z!/​552@5$A%H$I!3BZ@.36@25-3546@3T8G+#​!$#​2!H97@@.38-
 +M('​1X="​`GH*!#/​4A!0TM)3D<​G#​2!H97@@.6(-('​1X="​`GH$9/​4J!-3U)%H$1%
 +M5$%)3%,​A)RPP1`T@:&​5X(#​!D,​60Q9#​EE,​3(-('​1X="​`G1C$O1C(G+#​DR#​2!T
 +M>'​0@)Z`MH$E.0R]$14.@6"​U23U1!5$E/​3B<​L,​$0-(&​AE>"​`Q9#​%D,​3(-('​1X
 +M="​`G1C,​O1C0G+#​DR#​2!T>'​0@)Z`MH$E.0R]$14.@62U23U1!5$E/​3B<​L,​$0-
 +M(&​AE>"​`Q9#​%D,​3(-('​1X="​`G1C4O1C8G+#​DR#​2!T>'​0@)Z`MH$E.0R]$14.@
 +M6BU23U1!5$E/​3B<​L,​$0-(&​AE>"​`Q9#​%D,​3(-('​1X="​`G1C<​G+#​DR#​2!T>'​0@
 +M)Z!215-%5%,​G+#​!$#​2!T>'​0@)Z"​@4%)%4U.@4:​!43Z!154E4)RPP1`T@:&​5X
 +M(#​!D,#​4-('​1X="​`GH*"​@H*"​@4%)%4U.@04Y9H$M%6:​!43Z!"​14=)3B<​L,​$0-
 +M(&​AE>"​`P,​`UT:​71L92!L9&​$@*'​1E;​7`Q*2QY#​2!B97$@.F-O;​G0-(&​IS<​B!C
 +M:'​)O=70-(&​EN>​0T@8FYE('​1I=&​QE#​2!I;​F,​@=&​5M<#​(-(&​IM<"​!T:​71L90T@
 +M='​AT("​=T2$E3H$E3H$&​@4T5#​4D54H%1%6%2@34534T%'​12$G#​3IC;​VYT(#​X^
 +M/​B!G971K97D-#​2HJ*BJ@<​T54H%50H%1!0DQ%4R@_*0T-*J!T04),​15.@05)%
 +MH$-54E)%3E1,​6:​!3152@55"​@24Z@8F%S:​6,​-*J!!3D2@0EF@5$A%H$%34T5-
 +M0DQ%4BX-#​71A8FQE<​R!L9&​$@(SYT;​6%T:​`T@<​W1A('​HQ*S$-('​-T82!Z,​BLQ
 +M#​0TJ*BHJH&​-,​14%2H%-#​4D5%3J!!3D2@4T54H%50H"​)"​251-05`B#​7-E='​5P
 +M(&​QD82`C)#​`Q(#​MW2$E410T@<​W1A("​1D,#​(Q(#​MT2$E3H$E3H$1/​3D6@4T^@
 +M5$A!5*!/​3$1%4@T@;&​1A(",​Q-#<​@.TU!0TA)3D53H%=)3$R@4T54H%50#​2!J
 +M<​W(@8VAR;​W5T#​2!L9&​$@(R0P,"​`[0T]24D5#​5$Q9#​2!S=&​$@)&​0P,​C$-(&​QD
 +M82`C/'​-S=&​%R=`T@861C(",​Q,​B`[=$A%H$=/​04R@25.@5$^@0T5.5$52H%1(
 +M1:​!'​4D%02$E#​4PT@<​W1A('​1E;​7`Q(#​MC3TQ534Z@,​3(-(&​QD82`C/​G-S=&​%R
 +M="​`[<​D]7H#​D-('​-T82!T96UP,​2LQ(#​MS<​W1A<​G2@4$])3E13H%1/​H%)/​5Z`Y
 +M#​2!L9&​$@(S`P#​2!L9'​D@(S`P#​2!L9'​@@(S`P(#​M8H%=)3$R@0T]53E2@,​3:​@
 +M4D]74Z!&​3U*@55,​-(&​-L8PT-.FQO;​W`@<​W1A("​AT96UP,​2DL>​0T@:​6YY#​2!A
 +M9&,​@(S$V#​2!B8V,​@.FQO;​W`-(&​-L8PT@;&​1A('​1E;​7`Q#​2!A9&,​@(S0P(#​MN
 +M145$H%1/​H$%$1*`T,​*!43Z!42$6@0D%31:​!03TE.5$52#​2!S=&​$@=&​5M<#​$@
 +M.W1/​H$I535"​@5$^@5$A%H$Y%6%2@4D]7#​2!L9&​$@=&​5M<#​$K,​0T@861C(",​P
 +M,"​`[=$%+1:​!#​05)%H$]&​H$-!4E))15,​-('​-T82!T96UP,​2LQ#​2!L9'​D@(S`P
 +M#​2!I;​G@-('​1X82`@.WB@25.@04Q33Z!!3J!)3D1%6*!)3E1/​H%1(1:​!#​2$%2
 +M04-415*@3E5-0D52#​2!C<'​@@(S$V#​2!B;​F4@.FQO;​W`@.VY%142@5$^@1$^@
 +M252@,​3:​@5$E-15,​-#​2`^/​CX@9&​5B=6<​L)S(G#​2HJ*BJ@<​T54H%50H$)51D9%
 +M4E,​-#​2!L9&​$@(SQB=69F,​0T@<​W1A(&​)U9F9E<​@T@;&​1A(",​^8G5F9C$-('​-T
 +M82!B=69F97(K,​0T@<​W1A('​IT96UP(#​M:​5$5-4*!724Q,​H$U!2T6@3$E&​1:​!3
 +M24U03$6@1D]2H%53#​2!L9&​$@=FUC<​V(-(&​%N9"​`C)3$Q,​3$P,#​`Q(#​MS5$%2
 +M5*!(15)%H%-/​H%1(052@4U=!4*!"​549&​15)3H%=)3$R@5T]22Z!224=(5`T@
 +M;​W)A(",​E,#​`P,#​$Q,​3`-('​-T82!V;​6-S8@T-*BHJ*J!S152@55"​@24Y)5$E!
 +M3*!604Q515,​-#​6EN:​70@;&​1A(",​P,​`T@<​W1A(&​1S>​`T@<​W1A(&​1S>​0T@<​W1A
 +M(&​1S>​@T@<​W1A('​-X#​2!S=&​$@<​WD-('​-T82!S>​@T-(#​X^/​B!D96)U9RPG-"<​-
 +M#​2HM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM#​2J@;​4%)3J!,​3T]0
 +M#​0TJ*BHJH&​=%5*!+15E04D534PT-;​6%I;​@T@8VQI#​6MP<​F5S<​R!J<​W(@9V5T
 +M:​6X-(&​-M<"​`C,​3,​S(#​MF,​3\-(&​)N92`Z9C(-(&​QD82!D<​W@-(&​-M<"​`C86YG
 +M;​6%X+S(@.VY/​H$U/​4D6@5$A!3J!020T@8F5Q(#​IC;​VYT#​2!I;​F,​@9'​-X(#​M/​
 +M5$A%4E=)4T6@24Y#​4D5!4T6@6"​U23U1!5$E/​3@T@:​FUP(#​IC;​VYT#​3IF,​B!C
 +M;​7`@(S$S-R`[9C(_#​2!B;​F4@.F8S#​2!L9&​$@9'​-X#​2!B97$@.F-O;​G0-(&​1E
 +M8R!D<​W@-(&​IM<"​`Z8V]N=`TZ9C,​@8VUP(",​Q,​S0-(&​)N92`Z9C0-(&​QD82!D
 +M<​WD-(&​-M<"​`C86YG;​6%X+S(-(&​)E<​2`Z8V]N=`T@:​6YC(&​1S>​2`[:​4Y#​4D5!
 +M4T6@62U23U1!5$E/​3@T@:​FUP(#​IC;​VYT#​3IF-"​!C;​7`@(S$S.`T@8FYE(#​IF
 +M-0T@;&​1A(&​1S>​0T@8F5Q(#​IC;​VYT#​2!D96,​@9'​-Y#​2!J;​7`@.F-O;​G0-.F8U
 +M(&​-M<"​`C,​3,​U#​2!B;​F4@.F8V#​2!L9&​$@9'​-Z#​2!C;​7`@(V%N9VUA>"​\R#​2!B
 +M97$@.F-O;​G0-(&​EN8R!D<​WH@.UHM4D]4051)3TX-(&​IM<"​`Z8V]N=`TZ9C8@
 +M8VUP(",​Q,​SD-(&​)N92`Z9C<​-(&​QD82!D<​WH-(&​)E<​2`Z8V]N=`T@9&​5C(&​1S
 +M>​@T@:​FUP(#​IC;​VYT#​3IF-R!C;​7`@(S$S-@T@8FYE(#​IQ#​2!J;​7`@:​6YI=`TZ
 +M<​2!C;​7`@(R=1)R`[4:​!154E44PT@8FYE(#​IC;​VYT#​2!J;​7`@8VQE86YU<​`T-
 +M.F-O;​G0@<​V5I("​`[<​U!%142@5$A)3D=3H%50H$&​@0DE4#​2J@/​CX^H&​1E8G5G
 +M+"<​U)PT-*BHJ*J!U4$1!5$6@04Y'​3$53#​0UU<&​1A=&​4@8VQC#​2!L9&​$@<​W@-
 +M(&​%D8R!D<​W@-(&​-M<"​`C86YG;​6%X(#​MA4D6@5T6@/​CV@34%824U53:​!!3D=,​
 +M13\-(&​)C8R`Z8V]N=#​$-('​-B8R`C86YG;​6%X(#​II1B!33RP@4D53150-.F-O
 +M;​G0Q('​-T82!S>​`T@8VQC#​2!L9&​$@<​WD-(&​%D8R!D<​WD-(&​-M<"​`C86YG;​6%X
 +M#​2!B8V,​@.F-O;​G0R#​2!S8F,​@(V%N9VUA>"​`[<​T%-1:​!$14%,#​3IC;​VYT,​B!S
 +M=&​$@<​WD-(&​-L8PT@;&​1A('​-Z#​2!A9&,​@9'​-Z#​2!C;​7`@(V%N9VUA>​`T@8F-C
 +M(#​IC;​VYT,​PT@<​V)C("​-A;​F=M87@-.F-O;​G0S('​-T82!S>​@T-*BHJ*J!R3U1!
 +M5$6@0T]/​4D1)3D%415,​-#​7)O=&​%T90T-*BHJH&​9)4E-4+*!#​04Q#​54Q!5$6@
 +M5#​$L5#​(L+BXN+%0Q,​`T-*BJ@=%=/​H$U!0U)/​4Z!43Z!324U03$E&​6:​!/​55*@
 +M3$E&​10UA9&​1A(&​UA8R`@.V%$1*!45T^@04Y'​3$53H%1/​1T542$52#​2!C;&,​-
 +M(&​QD82!=,​0T@861C(%TR#​2!C;​7`@(V%N9VUA>"​`[:​5.@5$A%H%-53:​`^H#​(J
 +M4$D_#​2!B8V,​@9&​]N90T@<​V)C("​-A;​F=M87@@.VE&​H%-/​+*!354)44D%#​5*`R
 +M*E!)#​61O;​F4@/#​P\#​0US=6)A(&​UA8R`@.W-50E1204-4H%173Z!!3D=,​15,​-
 +M('​-E8PT@;&​1A(%TQ#​2!S8F,​@73(-(&​)C<​R!D;​VYE#​2!A9&,​@(V%N9VUA>"​`[
 +M;​T]04RR@5T6@3D5%1*!43Z!!1$2@,​BI020UD;​VYE(#​P\/​`T-*BJ@;​D]7H$-!
 +M3$-53$%41:​!4,​2Q4,​BQ%5$,​N#​0T@/​CX^('​-U8F$L<​WD[<​WH-('​-T82!T,​2`[
 +M5#​$]4UDM4UH-(#​X^/​B!A9&​1A+'​-Y.W-Z#​2!S=&​$@=#​(@.U0R/​5-9*U-:#​2`^
 +M/​CX@861D82QS>#​MS>​@T@<​W1A('​0S(#​M4,​SU36"​M36@T@/​CX^('​-U8F$L<​W@[
 +M<​WH-('​-T82!T-"​`[5#​0]4U@M4UH-(#​X^/​B!A9&​1A+'​-X.W0R#​2!S=&​$@=#​4@
 +M.U0U/​5-8*U0R#​2`^/​CX@<​W5B82QS>#​MT,​0T@<​W1A('​0V(#​M4-CU36"​U4,​0T@
 +M/​CX^(&​%D9&​$L<​W@[=#​$-('​-T82!T-R`[5#<​]4U@K5#​$-(#​X^/​B!S=6)A+'​0R
 +M.W-X#​2!S=&​$@=#​@@.U0X/​50R+5-8#​2`^/​CX@<​W5B82QS>​3MS>​`T@<​W1A('​0Y
 +M(#​M4.3U362U36`T@/​CX^(&​%D9&​$L<​W@[<​WD-('​-T82!T,​3`@.U0Q,#​U36"​M3
 +M60T-*J!E5*!63TE,​02$-#​2HJ*J!N15A4+*!#​04Q#​54Q!5$6@82QB+&,​L+BXN
 +M+&​D-#​2HJH&​%.3U1(15*@55-%1E5,​H$Q)5%1,​1:​!-04-23PUD:​78R(&​UA8R`@
 +M.V1)5DE$1:​!!H%-)1TY%1*!.54U"​15*@0EF@,​@T[:​52@25.@05-354U%1*!4
 +M2$%4H%1(1:​!.54U"​15(-(&​)P;"​!P;​W,​@.TE3H$E.H%1(1:​!!0T-5355,​051/​
 +M4@T@8VQC#​2!E;​W(@(R1F9B`[=T6@3D5%1*!43Z!53BU.14=!5$E61:​!42$6@
 +M3E5-0D52#​2!A9&,​@(S`Q(#​M"​6:​!404M)3D>​@250G4Z!#​3TU03$5-14Y4#​2!L
 +M<​W(@(#​M$259)1$6@0EF@5%=/#​2!C;&,​-(&​5O<​B`C)&​9F#​2!A9&,​@(S`Q(#​MM
 +M04M%H$E4H$Y%1T%4259%H$%'​04E.#​2!J;​7`@9&​]N961I=@UP;​W,​@;'​-R("​`[
 +M;​E5-0D52H$E3H%!/​4TE4259%#​61O;​F5D:​78@/#​P\#​0UM=6PR(&​UA8R`@.VU5
 +M3%1)4$Q9H$&​@4TE'​3D5$H$Y534)%4J!"​6:​`R#​2!B<&​P@<&​]S;​0T@8VQC#​2!E
 +M;​W(@(R1F9@T@861C(",​D,#​$-(&​%S;​`T@8VQC#​2!E;​W(@(R1F9@T@861C(",​D
 +M,#​$-(&​IM<"​!D;​VYE;​75L#​7!O<​VT@87-L#​61O;​F5M=6P@/#​P\#​0TJ*J!N3U1%
 +MH%1(052@5T6@05)%H$-54E)%3E1,​6:​!-04M)3D>​@0:​!-24Y/​4J!,​14%0#​2HJ
 +MH$]&​H$9!251(H%1(052@3D^@3U9%4D9,​3U=3H%=)3$R@3T-#​55(N#​0TZ8V%L
 +M8V$@8VQC#​2!L9'​@@=#​$-(&​QD82!C;​W,​L>​`T@;&​1X('​0R#​2!A9&,​@8V]S+'​@-
 +M('​-T82!A,​3$@.V$]*$-/​4RA4,​2DK0T]3*%0R*2DO,​@TZ8V%L8V(@;&​1X('​0Q
 +M#​2!L9&​$@<​VEN+'​@-('​-E8PT@;&​1X('​0R#​2!S8F,​@<​VEN+'​@-('​-T82!B,​3(@
 +M.V(]*%-)3BA4,​2DM4TE.*%0R*2DO,​@TZ8V%L8V,​@;&​1X('​-Y#​2!L9&​$@<​VEN
 +M+'​@-(#​X^/​B!M=6PR#​2!S=&​$@8S$S(#​MC/​5-)3BA362D-.F-A;&​-D('​-E8PT@
 +M;&​1X('​0X#​2!L9&​$@8V]S+'​@-(&​QD>"​!T-PT@<​V)C(&​-O<​RQX#​2!S96,​-(&​QD
 +M>"​!T-0T@<​V)C(&​-O<​RQX#​2!C;&,​-(&​QD>"​!T-@T@861C(&​-O<​RQX(#​MD23TH
 +M0T]3*%0X*2U#​3U,​H5#<​I*T-/​4RA4-BDM0T]3*%0U*2DO,​@T@/​CX^(&​1I=C(-
 +M(&​-L8PT@;&​1X('​0S#​2!A9&,​@<​VEN+'​@-('​-E8PT@;&​1X('​0T#​2!S8F,​@<​VEN
 +M+'​@-('​-T82!D,​C$@.V0]*%-)3BA4,​RDM4TE.*%0T*2MD22DO,​@TZ8V%L8V4@
 +M<​V5C#​2!L9'​@@=#​4-(&​QD82!S:​6XL>​`T@;&​1X('​0V#​2!S8F,​@<​VEN+'​@-('​-E
 +M8PT@;&​1X('​0W#​2!S8F,​@<​VEN+'​@-('​-E8PT@;&​1X('​0X#​2!S8F,​@<​VEN+'​@@
 +M.V5)/​2A324XH5#​4I+5-)3BA4-BDM4TE.*%0W*2U324XH5#​@I*2\R#​2`^/​CX@
 +M9&​EV,​@T@8VQC#​2!L9'​@@=#,​-(&​%D8R!C;​W,​L>​`T@8VQC#​2!L9'​@@=#​0-(&​%D
 +M8R!C;​W,​L>​`T@<​W1A(&​4R,​B`[93TH0T]3*%0S*2M#​3U,​H5#​0I*V5)*2\R#​3IC
 +M86QC9B!L9'​@@=#​D-(&​QD82!S:​6XL>​`T@<​V5C#​2!L9'​@@=#​$P#​2!S8F,​@<​VEN
 +M+'​@-('​-T82!F,​C,​@.V8]*%-)3BA4.2DM4TE.*%0Q,"​DI+S(-.F-A;&​-G(&​QD
 +M>"​!T-@T@;&​1A('​-I;​BQX#​2!S96,​-(&​QD>"​!T.`T@<​V)C('​-I;​BQX#​2!S96,​-
 +M(&​QD>"​!T-PT@<​V)C('​-I;​BQX#​2!S96,​-(&​QD>"​!T-0T@<​V)C('​-I;​BQX(#​MG
 +M23TH4TE.*%0V*2U324XH5#​@I+5-)3BA4-RDM4TE.*%0U*2DO,​@T@/​CX^(&​1I
 +M=C(-(&​-L8PT@;&​1X('​0T#​2!A9&,​@8V]S+'​@-('​-E8PT@;&​1X('​0S#​2!S8F,​@
 +M8V]S+'​@-('​-T82!G,​S$@.V<​]*$-/​4RA4-"​DM0T]3*%0S*2MG22DO,​@T@/​CX^
 +M(&​1E8G5G82QG,​S$-(#​X^/​B!D96)U9RPG1R<​-.F-A;&​-H(&​-L8PT@;&​1X('​0V
 +M#​2!L9&​$@8V]S+'​@-(&​QD>"​!T-PT@861C(&​-O<​RQX#​2!S96,​-(&​QD>"​!T-0T@
 +M<​V)C(&​-O<​RQX#​2!S96,​-(&​QD>"​!T.`T@<​V)C(&​-O<​RQX(#​MH23TH0T]3*%0V
 +M*2M#​3U,​H5#<​I+4-/​4RA4-2DM0T]3*%0X*2DO,​@T@/​CX^(&​1I=C(-(&​-L8PT@
 +M;&​1X('​0S#​2!A9&,​@<​VEN+'​@-(&​-L8PT@;&​1X('​0T#​2!A9&,​@<​VEN+'​@-('​-T
 +M82!H,​S(@.V@]*%-)3BA4,​RDK4TE.*%0T*2MH22DO,​@TZ=VAE=R!C;&,​-(&​QD
 +M>"​!T.0T@;&​1A(&​-O<​RQX#​2!L9'​@@=#​$P#​2!A9&,​@8V]S+'​@-('​-T82!I,​S,​@
 +M.VD]*$-/​4RA4.2DK0T]3*%0Q,"​DI+S(-#​2HJH&​E4)U.@04Q,​H$1/​5TY(24Q,​
 +MH$923TV@2$5212X-(&​IM<"​!D;​W=N:&​EL;​`T@='​AT("​=G146@8E)!24XLH%=(
 +M052@1$^@64]5H%=!3E2@5$^@1$^@)PT@='​AT("​=43TY)1TA4/​R<​-#​2HJH'​)/​
 +M5$%412R@4%)/​2D5#​5"​R@04Y$H%-43U)%H%1(1:​!03TE.5%,​-9&​]W;​FAI;&​P-
 +M#​2J@8:​!.14%4H$U!0U)/#​6YE9R!M86,​@(#​MC2$%.1T6@5$A%H%-)1TZ@3T:​@
 +M0:​!45T\G4Z!#​3TU03$5-14Y4#​2!C;&,​-(&​QD82!=,​2`[3E5-0D52+@T@96]R
 +M(",​D9F8-(&​%D8R`C)#​`Q#​2`\/#​P-#​2HM+2TM+2TM+2TM+2TM+2TM+2TM+2TM
 +M+2TM+2TM+2TM#​2J@=$A%4T6@34%#​4D]3H%)%4$Q!0T6@5$A%H%!2159)3U53
 +MH%!23TI%0U1)3TX-*J!354)23U5424Y%+@T-<​VUU;'​0@;​6%C(#​MM54Q425!,​
 +M6:​!45T^@4TE'​3D5$H#​@M0DE4#​2`@(#​M.54U"​15)3.J!A*GDO-C2@+3Z@80T@
 +M<​W1A('​HQ#​2!C;&,​-(&​5O<​B`C)&​9F#​2!A9&,​@(R0P,​0T@<​W1A('​HR#​2!L9&​$@
 +M*'​HQ*2QY#​2!S96,​-('​-B8R`H>​C(I+'​D-(#​P\/"​`@.V%,​3*!$3TY%H#​HI#​0T-
 +M861D<​W5B(&​UA8R`@.V%$1*!/​4J!354)44D%#​5*!45T^@3E5-0D524PT@("​`[
 +M1$5014Y$24Y'​H$].H$9)4E-4H$E.4%54#​2!I9B`M/​5TQ(#​MI1J!354)44D%#​
 +M5`T@<​V5C("​`[5$A%3J!54T6@5$A)4Z!#​3T1%#​2!S8F,​@73(-(&​5L<​V4@(#​M/​
 +M5$A%4E=)4T6@55-%H%1(25.@0T]$10T@8VQC#​2!A9&,​@73(-(&​9I;​@T@/#​P\
 +M#​0T-<'​)O:​F5C="​!M86,​@(#​MT2$6@04-454%,​H%!23TI%0U1)3TZ@4D]55$E.
 +M10T@("​`[5%=/​H$E.4%544Z!!4D6@55-%1*`H6"​Q9*0T@("​`[0T]24D534$].
 +M1$E.1Z!43Z`H*R\M,​2PK+RTQ*0T@("​`[=$A%H%1(25)$H$E.4%54H$E3H%53
 +M142@5$\-("​`@.T1%5$5234E.1:​!)1J!42$6@4D]4051%1`T@("​`[6BU#​3T]2
 +M1$E.051%H%-(3U5,​1*!"​10T@("​`[4U1/​4D5$+*!!3D2@24:​@4T^@5TA%4D4N
 +M#​2`@(#​MT2$6@0T%,​3$E.1Z!23U5424Y%H$A!3D1,​15,​-("​`@.T-(04Y'​24Y'​
 +MH%1(1:​!324=.H$]&​H%HN#​0T@;&​1A(&​DS,​R`[8T%,​0U5,​051%H%)/​5$%4142@
 +M6CH-(#​X^/​B!A9&​1S=6(L73$[9S,​Q(#​MA1$2@3U*@4U5"​5%)!0U2@6`T@/​CX^
 +M(&​%D9'​-U8BQ=,​CMH,​S(@.V%$1*!/​4J!354)44D%#​5*!9#​2!I9B!P+%TS(#​MD
 +M3Z!71:​!.145$H%1/​H%-43U)%H%1(1:​!03TE.5#​\-('​-T82!=,​R`[=$A%3J!$
 +M3Z!33R$-(&​9I;​@TJH&​5O<​J`C,​3(XH#​MW1:​!!4D6@1T])3D>​@5$^@5$%+1:​`Q
 +M,​C@K6@T@=&​%X("​`[;​D]7H$E4H$E3H%)%0419H$9/​4J!)3D1%6$E.1PT@;&​1A
 +M('​ID:​78L>"​`[=$%"​3$6@3T:​@1"​\H6BM:,"​D-('​1A>​2`@.WF@3D]7H$-/​3E1!
 +M24Y3H%!23TI%0U1)3TX-#​2!L9&​$@8S$S(#​MN3U>​@0T%,​0U5,​051%H%)/​5$%4
 +M142@6`T@/​CX^(&​%D9'​-U8BQ=,​3MA,​3$-(#​X^/​B!A9&​1S=6(L73([8C$R#​2`^
 +M/​CX@<​VUU;'​0@.W-)1TY%1*!-54Q425!,​6:​!A*GDO-C0M/​F$-(&​-L8PT@861C
 +M(",​V-"​`[;​T9&​4T54H%1(1:​!#​3T]21$E.051%#​2!T87@@(#​MN3U>​@>​*!)4Z!2
 +M3U1!5$5$H%@A#​0T@;&​1A(&​8R,​R`[;​D]7H$E4)U.@62=3H%154DX-(#​X^/​B!A
 +M9&​1S=6(L73$[9#​(Q#​2`^/​CX@861D<​W5B+%TR.V4R,​@T@/​CX^('​-M=6QT#​2!C
 +M;&,​-(&​%D8R`C-C0@.V]&​1E-%5`T@8VUP('​EM:​6X@.V9)1U521:​!/​552@24:​@
 +M252@25.@00T@8F-S(&​YO=&​UI;​B`[34E.H$]2H$U!6*!604Q51:​!&​3U*@60T@
 +M<​W1A('​EM:​6X-(&​)C8R!N;​W1M87@@.W1(25.@25.@55-%1*!)3J!#​04Q#​54Q!
 +M5$E.1PUN;​W1M:​6X@8VUP('​EM87@@.U1(1:​!&​24Q,​142@1D%#​15,​-(&​)C8R!N
 +M;​W1M87@-('​-T82!Y;​6%X#​6YO=&​UA>"​!T87D@(#​MN3U2@4D5!3$Q9H$Y%0T53
 +M4T%260T-(#​P\/"​`@.V%,​3*!$3TY%#​0T-(&​QD82`C-C0@.W)%4T54H'​E-24Z@
 +M04Y$H'​E-05@-('​-T82!Y;​6EN#​2!S=&​$@>​6UA>​`T-*J!P,​3U;,:​`QH#​%=#​2`^
 +M/​CX@<'​)O:​F5C="​PQ.S$[<#​%Z(#​MR3U1!5$5$H%J@4U1/​4D5$H$E.H'​`Q>​@T@
 +M<​W1X('​`Q>​`T@<​W1Y('​`Q>​0TJH'​`R/​5LQH"​TQH#​%=#​2`^/​CX@<'​)O:​F5C="​PQ
 +M.RTQ.W`R>​@T@<​W1X('​`R>​`T@<​W1Y('​`R>​0TJH'​`S/​5LM,:​`M,:​`Q70T@/​CX^
 +M('​!R;​VIE8W0L+3$[+3$[;​F]P92`[9$].)U2@4U1/​4D6@6BU604Q510T@<​W1X
 +M('​`S>​`T@<​W1Y('​`S>​0TJH'​`T/​5LM,:​`QH#​%=#​2`^/​CX@<'​)O:​F5C="​PM,​3LQ
 +M.W`T>​@T@<​W1X('​`T>​`T@<​W1Y('​`T>​0TJH'​`X/​5LM,:​`QH"​TQ70T@/​CX^(&​YE
 +M9RQC,​3,​-('​-T82!C,​3,​-(#​X^/​B!N96<​L9C(S#​2!S=&​$@9C(S#​2`^/​CX@;​F5G
 +M+&​DS,​PT@<​W1A(&​DS,​PT@/​CX^('​!R;​VIE8W0L+3$[,​3MN;​W!E#​2!S='​@@<#​AX
 +M#​2!S='​D@<#​AY#​2J@<#<​]6RTQH"​TQH"​TQ70T@/​CX^('​!R;​VIE8W0L+3$[+3$[
 +M;​F]P90T@<​W1X('​`W>​`T@<​W1Y('​`W>​0TJH'​`V/​5LQH"​TQH"​TQ70T@/​CX^('​!R
 +M;​VIE8W0L,​3LM,​3MN;​W!E#​2!S='​@@<#​9X#​2!S='​D@<#​9Y#​2J@<#​4]6S&​@,:​`M
 +M,​5T-(#​X^/​B!P<​F]J96-T+#​$[,​3MP-7H-('​-T>"​!P-7@-('​-T>​2!P-7D-#​2J@
 +M8:​!,​25143$6@34%#​4D\-#​7-E=&​)U9B!M86,​@(#​MP552@0E5&​1D524Z!72$52
 +M1:​!42$59H$-!3J!"​1:​!(55)4#​2!L9&​$@(S`P#​2!S=&​$@8G5F9F5R#​2!L9&​$@
 +M>​G1E;​7`@.UI414U0H$-/​3E1!24Y3H%1(1:​!(24=(H$)95$6@2$5210T@<​W1A
 +M(&​)U9F9E<​BLQ#​2`\/#​P-#​2HJ*BJ@8TQ%05*@0E5&​1D52#​0TJH#​X^/​J!S971B
 +M=68-*F-L<​F)U9J!L9&&​@(R0P,​*`[<​%)%5%19H%-44D%)1TA41D]25T%21"​P-
 +M*J!L9'​B@(R0P.*`[::​!42$E.2PTJH&​QD>:​`C)#​`P#​2HZ;&​]O<​*!S=&&​@*&​)U
 +M9F9E<​BDL>​0TJH&​EN>​0TJH&​)N9:​`Z;&​]O<​`TJH&​EN8Z!B=69F97(K,​0TJH&​1E
 +M>​`TJH&​)N9:​`Z;&​]O<​`T-*J!T2$E3H$E3H%1(1:​!.15>​@04Y$H$E-4%)/​5D5$
 +MH$)51D9%4J!#​3$5!4@TJH%)/​551)3D6@1D]2H$9)3$Q%1*!&​04-%4PT-(#​X^
 +M/​B!S971B=68-('​-T82!T96UP,​2LQ(#​M"​549&​15(RH%=)3$R@4$])3E2@5$\-
 +M(&​QD82`C)#​@P(#​M"​549&​15(K,​3(X#​2!S=&​$@=&​5M<#​$@.VU!2T53H$Q)1D6@
 +M1D%35$52H$9/​4J!54PUF:​6QC;'​(@;&​1A(",​P,​`T@;&​1X(",​D,#​@@.W=%)TQ,​
 +MH$1/​H$E4H%173Z!!5*!!H%1)344-(&​QD>​2`C)#​`P#​3IL;​V]P,​2!S=&​$@*&​)U
 +M9F9E<​BDL>​0T@<​W1A("​AT96UP,​2DL>​0T@:​6YY#​2!C<'​D@>​6UI;​@T@8FYE(#​IL
 +M;​V]P,​0T@;&​1A(",​D9F8@.VY/​5Z!,​3T%$H%=)5$B@1DE,​3%,​-.FQO;​W`R('​-T
 +M82`H8G5F9F5R*2QY#​2!S=&​$@*'​1E;​7`Q*2QY#​2!I;​GD-(&​-P>​2!Y;​6%X#​2!B
 +M8V,​@.FQO;​W`R#​2!L9&​$@(R0P,"​`[8DQ!0TN@3U54H%1(1:​!215-4#​3IL;​V]P
 +M,​R!S=&​$@*&​)U9F9E<​BDL>​0T@<​W1A("​AT96UP,​2DL>​0T@:​6YY#​2!B<&​P@.FQO
 +M;​W`S(#​MU3E1)3*!Y/​3$R.`T@;&​1Y(",​P,​`T@:​6YC(&​)U9F9E<​BLQ#​2!I;​F,​@
 +M=&​5M<#​$K,​0T@9&​5X#​2!B;​F4@.FQO;​W`Q(#​MG3Z!!3$R@5$A%H%=!6:​!!4D]5
 +M3D0-#​2HJ*BJ@;​D]7H$1205>​@5$A%H$Q)3D53+@TJ*BHJH&​)55*!&​25)35*!#​
 +M2$5#​2Z!&​3U*@2$E$1$5.H$9!0T53(0TJ*BHJH'​)%345-0D52.J!P,​3U;,:​`Q
 +MH#​%=H'​`R/​5LQH"​TQH#​%=H'​`S/​5LM,:​`M,:​`Q70TJ*BHJH'​`T/​5LM,:​`QH#​%=
 +MH'​`U/​5LQH#&​@+3%=H'​`V/​5LQH"​TQH"​TQ7:​!P-SU;​+3&​@+3&​@+3%=#​2HJ*BJ@
 +M<#​@]6RTQH#&​@+3%=#​0UL:​6YE<​R!L9&​$@(S`P#​2!S=&​$@9F%C97,​@.VA)1$1%
 +M3J!&​04-%H$-/​54Y415(-.F9A8V4Q(&​QD82!K#​2!S96,​-('​-B8R!P,​7H-(&​)V
 +M<​R`Z9F%C938@.V]615)&​3$]7H$%,​4D5!1%D_#​2!C;&,​-(&​%D8R!P-7H@.VE3
 +MH$LM5C%:​H#​R@,#​\-(#​MI1J!.3U0LH$9!0T6@25.@24Y625-)0DQ%#​2!B=F,​@
 +M.F1R87<​Q(#​MB552@5T6@34E'​2%2@2$%61:​!/​5D521DQ/​5PT@;&​1A('​`U>​B`[
 +M=T%3H$]615)&​3$]7H%!/​4Z!/​4J!.14<​_#​3ID<​F%W,​2!B<&​P@.F9A8V4V(#​MI
 +M1J!03U.@5$A%3J!++58Q6J`^H#​`-#​2!L9&​$@(R0P,​2`[;​U1(15)725-%+*!$
 +M4D%7H%1(10T@<​W1A(&​9A8V5S(#​M&​04-%(0T-(&​QD82!P,​7@-('​-T82!T>#​$-
 +M(&​QD82!P,​7D-('​-T82!T>​3$-(&​QD82!P,​G@-('​-T82!T>#​(-(&​QD82!P,​GD-
 +M('​-T82!T>​3(-(&​IS<​B!D<​F%W(#​MP,​2UP,​@T-(&​QD82!P,​W@-('​-T82!T>#​$-
 +M(&​QD82!P,​WD-('​-T82!T>​3$-(&​IS<​B!D<​F%W(#​MP,​BUP,​PT-(&​QD82!P-'​@-
 +M('​-T82!T>#​(-(&​QD82!P-'​D-('​-T82!T>​3(-(&​IS<​B!D<​F%W(#​MP,​RUP-`T-
 +M(&​QD82!P,​7@-('​-T82!T>#​$-(&​QD82!P,​7D-('​-T82!T>​3$-(&​IS<​B!D<​F%W
 +M(#​MP-"​UP,:"​@9D%#​1:​`QH$1/​3D4N#​2!J;​7`@.F9A8V4R(#​MI1J!/​3D6@25.@
 +M5DE324),​12R@5$A%H$]42$52#​2`@(#​M)4TXG5"​X-.F9A8V4V(&​QD82!K#​2!S
 +M96,​-('​-B8R!P-7H-(&​)V<​R`Z9F%C93(-(&​-L8PT@861C('​`Q>​B`[;​D]7H$-(
 +M14-+H$E&​H&​LM5C9:​H#​R@,​`T@8G9C(#​ID<​F%W-B`[;​$]61:​!42$%4H$]615)&​
 +M3$]7#​2!L9&​$@<#​%Z#​3ID<​F%W-B!B<&​P@.F9A8V4R(#​MI1J!.3U0LH$=/​H$].
 +M#​0T@;&​1A(",​D,​C`-('​-T82!F86-E<​R`[;​U1(15)725-%+*!$4D%7H$E4#​0T@
 +M;&​1A('​`U>​`T@<​W1A('​1X,​@T@;&​1A('​`U>​0T@<​W1A('​1Y,​@T@;&​1A('​`V>​`T@
 +M<​W1A('​1X,​0T@;&​1A('​`V>​0T@<​W1A('​1Y,​0T@:​G-R(&​1R87<​@.W`U+7`V#​0T@
 +M;&​1A('​`W>​`T@<​W1A('​1X,​@T@;&​1A('​`W>​0T@<​W1A('​1Y,​@T@:​G-R(&​1R87<​@
 +M.W`V+7`W#​0T@;&​1A('​`X>​`T@<​W1A('​1X,​0T@;&​1A('​`X>​0T@<​W1A('​1Y,​0T@
 +M:​G-R(&​1R87<​@.W`W+7`X#​0T@;&​1A('​`U>​`T@<​W1A('​1X,​@T@;&​1A('​`U>​0T@
 +M<​W1A('​1Y,​@T@:​G-R(&​1R87<​@.W`X+7`U#​0TZ9F%C93(@;&​1A(&​L-('​-E8PT@
 +M<​V)C('​`Q>​@T@8G9S(#​IF86-E-0T@8VQC#​2!A9&,​@<#​1Z(#​MK+58R6J`\H#​`_
 +M#​2!B=F,​@.F1R87<​R#​2!L9&​$@<#​1Z#​3ID<​F%W,​B!B<&​P@.F9A8V4U#​2!L9&​$@
 +M(R0P,​B`[:​4:​@4T\LH$1205>​@250A#​2!O<​F$@9F%C97,​-('​-T82!F86-E<​PT-
 +M(&​QD>"​!P,​7@@.W=%)U)%H$1/​24Y'​H%1(25.@5$A)4Z!705D-('​-T>"​!T>#​$@
 +M.U1/​H%-!5D6@0:​!&​15>​@0UE#​3$53#​2!L9'​@@<#​%Y#​2!S='​@@='​DQ#​0T@86YD
 +M(",​D,#​$@.W-(05)%4Z!!3J!%1$=%H%=)5$B@1D%#​1:​`Q#​2!B;​F4@.F8R<​S(@
 +M.W-+25"​@5$^@3D585*!%1$=%H$E&​H%!215-%3E0-#​2!L9&​$@<#​)X#​2!S=&​$@
 +M='​@R#​2!L9&​$@<#​)Y#​2!S=&​$@='​DR#​2!J<​W(@9'​)A=R`[<#​$M<#​(-#​3IF,​G,​R
 +M(&​QD>"​!P-7@-('​-T>"​!T>#​(-(&​QD>"​!P-7D-('​-T>"​!T>​3(-(&​IS<​B!D<​F%W
 +M(#​MP,​2UP-0T-(&​QD>"​!P-G@-('​-T>"​!T>#​$-(&​QD>"​!P-GD-('​-T>"​!T>​3$-
 +M#​2!L9&​$@9F%C97,​-(&​%N9"​`C)#​(P(#​MA3%-/​H%-(05)%4Z!!3J!%1$=%H%=)
 +M5$B@-@T@8FYE(#​IF,​G,​T#​0T@:​G-R(&​1R87<​@.W`U+7`V#​0TZ9C)S-"​!L9&​$@
 +M<#​)X#​2!S=&​$@='​@R#​2!L9&​$@<#​)Y#​2!S=&​$@='​DR(#​MS54-(H$E3H$9!0T6@
 +M,​@T@:​G-R(&​1R87<​@.W`V+7`R#​2!J;​7`@.F9A8V4S(#​MS2TE0H#​4-#​3IF86-E
 +M-2!L9&​$@:​PT@<​V5C#​2!S8F,​@<#​1Z#​2!B=G,​@.F9A8V4S#​2!C;&,​-(&​%D8R!P
 +M,​7H@.W-!346@5$A)3D>​@04=!24XN+BX-(&​)V8R`Z9'​)A=S4-(&​QD82!P,​7H-
 +M.F1R87<​U(&​)P;"​`Z9F%C93,​-(&​QD82`C)#​$P#​2!O<​F$@9F%C97,​-('​-T82!F
 +M86-E<​PT-(&​QD>"​!P,​W@-('​-T>"​!T>#​$-(&​QD>"​!P,​WD-('​-T>"​!T>​3$-#​2!A
 +M;​F0@(R0P,​2`[<​TA!4D53H%=)5$B@,​0T@8FYE(#​IF-7,​R#​0T@;&​1A('​`T>​`T@
 +M<​W1A('​1X,​@T@;&​1A('​`T>​0T@<​W1A('​1Y,​@T@:​G-R(&​1R87<​@.W`S+7`T#​0TZ
 +M9C5S,​B!L9&​$@<#​=X#​2!S=&​$@='​@R#​2!L9&​$@<#​=Y#​2!S=&​$@='​DR#​2!J<​W(@
 +M9'​)A=R`[<#,​M<#<​-#​2!L9&​$@<#​AX#​2!S=&​$@='​@Q#​2!L9&​$@<#​AY#​2!S=&​$@
 +M='​DQ#​0T@;&​1A(&​9A8V5S#​2!A;​F0@(R0R,"​`[<​TA!4D53H%=)5$B@-@T@8FYE
 +M(#​IF-7,​T#​0T@:​G-R(&​1R87<​@.W`W+7`X#​3IF-7,​T(&​QD82!P-'​@-('​-T82!T
 +M>#​(-(&​QD82!P-'​D-('​-T82!T>​3(@.W`X+7`T#​2!J<​W(@9'​)A=R`[=%=/​H$U/​
 +M4D6@5$^@1T\A#​0TZ9F%C93,​@;&​1A(&​L-('​-E8PT@<​V)C('​`Q>​@T@8G9S(#​IF
 +M86-E-`T@8VQC#​2!A9&,​@<#​)Z#​2!B=F,​@.F1R87<​S#​2!L9&​$@<#​)Z#​3ID<​F%W
 +M,​R!B<&​P@.F9A8V4T(#​MA2*!214-+3TZ@250G4Z!!)TA)1$1%3BR@6550#​2!L
 +M9&​$@(R0P-`T@;​W)A(&​9A8V5S#​2!S=&​$@9F%C97,​-#​2!L9'​@@<#​%X#​2!S='​@@
 +M='​@Q#​2!L9'​@@<#​%Y#​2!S='​@@='​DQ#​0T@86YD(",​D,#​$@.W-(05)%4Z!7251(
 +MH#​$-(&​)N92`Z9C-S,​@T-(&​QD82!P-'​@-('​-T82!T>#​(-(&​QD82!P-'​D-('​-T
 +M82!T>​3(-(&​IS<​B!D<​F%W(#​MP,​2UP-`T-.F8S<​S(@;&​1X('​`U>​`T@<​W1X('​1X
 +M,​@T@;&​1X('​`U>​0T@<​W1X('​1Y,​@T-(&​QD82!F86-E<​PT@86YD(",​D,#​(@.W-(
 +M05)%4Z!7251(H#​(-(&​)N92`Z9C-S,​PT-(&​IS<​B!D<​F%W(#​MP,​2UP-0TZ9C-S
 +M,​R!L9'​@@<#​AX#​2!S='​@@='​@Q#​2!L9'​@@<#​AY#​2!S='​@@='​DQ#​0T@;&​1A(&​9A
 +M8V5S#​2!A;​F0@(R0R,"​`[<​TA!4D53H%=)5$B@-@T@8FYE(#​IF,​W,​T#​0T@:​G-R
 +M(&​1R87<​@.W`U+7`X#​3IF,​W,​T(&​QD>"​!P-'​@-('​-T>"​!T>#​(-(&​QD>"​!P-'​D-
 +M('​-T>"​!T>​3(-#​2!L9&​$@9F%C97,​-(&​%N9"​`C)#​$P(#​MS2$%215.@5TE42*`U
 +M#​2!B;​F4@9F%C961O;​F4-#​2!J<​W(@9'​)A=R`[<#​@M<#​0-(&​IM<"​!F86-E9&​]N
 +M90T-.F9A8V4T(&​QD82!K#​2!S96,​-('​-B8R!P,​GH-(&​)V<​R!F86-E9&​]N90T@
 +M8VQC#​2!A9&,​@<#​%Z#​2!B=F,​@.F1R87<​T#​2!L9&​$@<#​%Z#​3ID<​F%W-"​!B<&​P@
 +M9F%C961O;​F4-#​2!L9&​$@<#​)X#​2!S=&​$@='​@Q#​2!L9&​$@<#​)Y#​2!S=&​$@='​DQ
 +M#​0T@;&​1A(&​9A8V5S#​2!A;​F0@(R0P,​2`[<​TA!4D53H%=)5$B@,​0T@8FYE(#​IF
 +M-',​R#​0T@;&​1A('​`S>​`T@<​W1A('​1X,​@T@;&​1A('​`S>​0T@<​W1A('​1Y,​@T@:​G-R
 +M(&​1R87<​@.W`R+7`S#​0TZ9C1S,​B!L9&​$@<#​9X#​2!S=&​$@='​@R#​2!L9&​$@<#​9Y
 +M#​2!S=&​$@='​DR#​0T@;&​1A(&​9A8V5S#​2!A;​F0@(R0P,​B`[<​TA!4D53H%=)5$B@
 +M,​@T@8FYE(#​IF-',​S#​0T@:​G-R(&​1R87<​@.W`R+7`V#​3IF-',​S(&​QD82!P-W@-
 +M('​-T82!T>#​$-(&​QD82!P-WD-('​-T82!T>​3$-#​2!L9&​$@9F%C97,​-(&​%N9"​`C
 +M)#​(P(#​MS2$%215.@5TE42*`V#​2!B;​F4@.F8T<​S0-#​2!J<​W(@9'​)A=R`[<#​8M
 +M<#<​-.F8T<​S0@;&​1A('​`S>​`T@<​W1A('​1X,​@T@;&​1A('​`S>​0T@<​W1A('​1Y,​@T-
 +M(&​QD82!F86-E<​PT@86YD(",​D,​3`@.W-(05)%4Z!7251(H#​4-(&​)N92!F86-E
 +M9&​]N90T-(&​IS<​B!D<​F%W(#​MP-RUP,​PUF86-E9&​]N92`@(#​MW2$57(:"​@=$E-
 +M1:​!&​3U*@0:​!"​1452+@T-*BHJ*J!N3U>​@5T6@3D5%1*!43Z!53D9)3$R@5$A%
 +MH$]55%-)1$6@1E)/​3:​!42$6@1D%#​15,​-=6YF:​6QL(&​QD>​2!Y;​6EN#​3IL;​V]P
 +M(#​X^/​B!S971B=68-(&​QD>"​`C,#​@-.FPQ(&​QD82`H8G5F9F5R*2QY#​2!E;​W(@
 +M(R1F9B`[9T^@5$E,​3*!71:​!&​24Y$H$&​@4$Q/​5%1%1`T@8FYE(#​IG;​W1C:&​$@
 +M.U!/​24Y4H"​A)+D4NH&&​@/#​Z@)&​9F*0TJH&​QD8:​`C,#"​@.W5.1DE,​3$E.1Z!!
 +M4Z!71:​!'​3RXN+@T@<​W1A("​AB=69F97(I+'​D-(&​QD82`C)#​@P#​2!S=&​$@8G5F
 +M9F5R#​2!L9&​$@*&​)U9F9E<​BDL>​0T@96]R(",​D9F8-(&​)N92`Z9V]T8VAA#​2J@
 +M;&​1AH",​P,​`T@<​W1A("​AB=69F97(I+'​D-('​-T82!B=69F97(-(&​EN8R!B=69F
 +M97(K,​0T@9&​5X("​`[=$A)4Z!)4Z!/​55*@4T%&​1519H%9!3%9%#​2!B;​F4@.FPQ
 +M(#​MR14%,​3%F@4TA/​54Q$3B=4H$Y%142@250-(&​IS<​B!C:&​]K90T@:​FUP('​-W
 +M87!B=68-#​3IG;​W1C:&​$@.V&​@0T].5$%)3E.@5$A%H&​5O<​J!03$]4H%9!3%5%
 +M#​2!S=&​$@=&​5M<#​$@.VY/​5Z!&​24Y$H%1(1:​!(24=(H$))5`T@;&​1A(",​P,​`TZ
 +M;#​(@<​V5C#​2!R;​VP-(&​QS<​B!T96UP,​2`[<​TA/​54Q$H%)%04Q,​6:​!54T6@0:​!4
 +M04),​10T@8FYE(#​IL,​B`[1D]2H%1(25,​A#​2!A;​F0@*&​)U9F9E<​BDL>​0T@<​W1A
 +M("​AB=69F97(I+'​D-#​2!L9&​$@>​G1E;​7`@.VY/​5Z!'​3Z!43Z!42$6@14Y$#​2`@
 +M(#​MC05)26:​!)4Z!#​3$5!4@T@("​`[84-454%,​3%F@5T6@041$H#<​-(&​%D8R`C
 +M)#​`V(#​LQ-J!#​3TQ534Y3H$]&​H#​$R.*!"​651%4PT@<​W1A(&​)U9F9E<​BLQ#​2!L
 +M9&​$@(R0X,​`T@<​W1A(&​)U9F9E<​@TZ;&​]O<#​(@;&​1A("​AB=69F97(I+'​D@.V%.
 +M1*!73U)+H$)!0TM705)$4R$-(&​5O<​B`C)&​9F#​2!B;​F4@.F=O=&​-H83(-('​-T
 +M82`H8G5F9F5R*2QY#​2!S=&​$@8G5F9F5R(#​MS5$E#​2Z!!H%I%4D^@24Y43Z!"​
 +M549&​15(-(&​QD82`H8G5F9F5R*2QY#​2!E;​W(@(R1F9@T@8FYE(#​IG;​W1C:&​$R
 +M#​2!S=&​$@*&​)U9F9E<​BDL>​0T@;&​1A(",​D.#​`-('​-T82!B=69F97(-(&​1E8R!B
 +M=69F97(K,​0T@8FYE(#​IL;​V]P,​@T-.F=O=&​-H83(@<​W1A('​1E;​7`Q(#​MA1T%)
 +M3J!&​24Y$H%1(1:​!(24=(H$))5`T@;&​1A(",​P,​`TZ;#,​@<​V5C#​2!R;​W(-(&​%S
 +M;"​!T96UP,​0T@8FYE(#​IL,​PT@86YD("​AB=69F97(I+'​D-('​-T82`H8G5F9F5R
 +M*2QY#​0T@:​6YY("​`[;​D]7H$M%15"​@1T])3D<​-(&​-P>​2!Y;​6%X#​2!B8V,​@.FQO
 +M;​W`@.W5.5$E,​H%=%H$A)5*!934%8(0T@8F5Q(#​IL;​V]P(#​MW1:​!.145$H%1(
 +M1:​!,​05-4H$].1:​!43T\N#​0TJ*BHJH'​-705"​@0E5&​1D524PT-<​W=A<&​)U9B!L
 +M9&​$@=FUC<​V(-(&​5O<​B`C)#​`R(#​MP4D545%F@5%))0TM9+*!%2#​\-('​-T82!V
 +M;​6-S8@T@;&​1A(",​D,#​@-(&​5O<​B!Z=&​5M<"​`[6E1%35`]2$E'​2*!"​651%H$I5
 +M4U2@1DQ)4%,​-('​-T82!Z=&​5M<"​`[0D545T5%3J`D,​S"​@04Y$H"​0S.`T-(&​IM
 +M<"​!M86EN(#​MA4D]53D2@04Y$H$%23U5.1*!71:​!'​3RXN+@T-('​1X="​`G<​T%-
 +M1:​!42$E.1Z!71:​!$3Z!%5D526:​!.24=(5"​R@<​$E.2UDZH"<​-('​1X="​`G5%)9
 +MH%1/​H%1!2T6@3U9%4J!42$6@5T]23$0A)PT-#​2HM+2TM+2TM+2TM+2TM+2TM
 +M+2TM+2TM+2TM+2TM+2TM#​2J@9T5.15)!3*!154535$E/​3D%"​3$4M5D%,​546@
 +M15)23U*@4%)/​0T5$55)%#​0UC:&​]K92!L9'​@@(S`P#​3IL;​V]P(&​QD82`Z8W1E
 +M>'​0L>​`T@8F5Q(#​ID;​VYE#​2!J<​W(@8VAR;​W5T#​2!I;​G@-(&​IM<"​`Z;&​]O<​`TZ
 +M9&​]N92!R=',​-.F-T97AT(&​AE>"​`P9"​`[8W(-('​1X="​`G4T]-151(24Y'​H$-(
 +M3TM%1*`Z*"<​-(&​AE>"​`P9#​`P#​0T@='​AT("​=N05)&​(2<​-#​2HM+2TM+2TM+2TM
 +M+2TM+2TM+2TM+2TM+2TM+2TM+2TM#​2J@9%)!5TE.)Z!!H$Q)3D4NH*!AH$9!
 +M2$Z@3$%(3BX-#​2HJ*J!S3TU%H%5314953*!-04-23U,​-#​7!L;​W1P>"​!M86,​@
 +M(#​M03$]4H$&​@4$])3E2@24Z@6`T@<&​AA("​`[=5-%H%1(25.@3TY%H$5615)9
 +MH%1)344-(&​QD82!B:​71P+'​@@.WB@25.@24Y#​4D5!4T5$#​2!B;​6D@8S$-(&​QD
 +M82`C)#​@P(#​MT04),​1:​!(05.@0D5%3J!214%24D%.1T5$#​2!E;​W(@8G5F9F5R
 +M(#​M&​3U*@1DE,​3$E.1Z!&​04-%4PT@<​W1A(&​)U9F9E<​@T@8FUI(&,​R#​2!I;​F,​@
 +M8G5F9F5R*S$-8S(@;&​1A(",​E,#​$Q,​3$Q,​3$@.VY/​5$6@5$A!5*!42$E3H$E3
 +MH$-(04Y'​140-8S$@86YD("​AB=69F97(I+'​D@.T9/​4J!03$]45$E.1Z!&​24Q,​
 +M142@1D%#​15,​-('​-T82`H8G5F9F5R*2QY#​2!P;&​$@(#​MN145$H%1/​H%-!5D6@
 +M82$-(#​P\/​`T-<&​QO='​!Y(&​UA8R`@.W!,​3U2@0:​!03TE.5*!)3J!9.J!324U0
 +M3$52H$%.1*!.14-%4U-!4EDA#​2!P:&​$@(#​MU4T6@5$A)4Z!/​3D6@5TA%3J!9
 +M3U6@2E535*!)3D-214%31:​!Y#​2!L9&​$@8FET<"​QX(#​M"​552@>​*!$3T533B=4
 +MH$-(04Y'​10T@86YD("​AB=69F97(I+'​D-('​-T82`H8G5F9F5R*2QY#​2!P;&​$-
 +M(#​P\/​`T-8VEN:​70@;​6%C("​`[;​4%#​4D^@5$^@24Y)5$E!3$E:​1:​!42$6@0T]5
 +M3E1%4@T@;&​1A(%TQ(#​M$6*!/​4J!$60T@;'​-R#​2!E;​W(@(R1F9B`[*&​Y/​5*!2
 +M14%,​3%F@5%=/​)U.@0T]-4$Q%345.5"​D-(&​%D8R`C)#​`Q(#​MAH#​V@,​C4V+418
 +M+S*@3U*@,​C4V+419+S(-(#​P\/"​`@.W1(1:​!$6"​\RH$U!2T53H$&​@3DE#​15*@
 +M3$]/​2TE.1Z!,​24Y%#​0UX<​W1E<"​!M86,​@(#​MM04-23Z!43Z!404M%H$&​@4U1%
 +M4*!)3J!X#​7AL;​V]P(&​EN>​`T@861C(&​1Y#​2!B8V,​@;#​$-*J!D3Z!71:​!54T6@
 +M:​6YYH$]2H&​1E>:​!(15)%/​PT@:​68@:​2Q=,​2`[:​4:​@5$A%H$9)4E-4H$-(05)!
 +M0U1%4J!)4Z!!3J`G:​2<​-(&​EN>​0T@96QS90T@9&​5Y#​2!F:​6X-('​-B8R!D>​`UL
 +M,​2`^/​CX@<&​QO='​!X(#​MA3%=!65.@5$%+1:​!!H%-415"​@24Z@>​`T@8W!X('​@R
 +M#​2!B;​F4@>&​QO;​W`-(#​P\/​`T->​7-T97`@;​6%C("​`[<​T%-1:​!42$E.1RR@0E54
 +MH$9/​4J!Y#​7EL;​V]P(&​EF(&​DL73$-(&​EN>​0T@96QS90T@9&​5Y#​2!C;&,​@(#​MV
 +M15)9H$E-4$]25$%.5"​$-(&​9I;​@T@861C(&​1X#​2!B8V,​@;#​(-(&​EN>"​`@.V%,​
 +M5T%94Z!)3D-214%31:​!X#​2!S8F,​@9'​D-(#​X^/​B!P;&​]T<'​@-(&​IM<"​!L,​PUL
 +M,​B`^/​CX@<&​QO='​!Y(#​MW1:​!/​3DQ9H$E.0U)%05-%1*!Y#​6PS(&​-P>​2!Y,​@T@
 +M8FYE('​EL;​V]P#​2`\/#​P-#​2HJ*BJ@:​4Y)5$E!3*!,​24Y%H%-%5%50#​0UD<​F%W
 +M(#​X^/​B!M;​W9E+'​1X,​3MX,​2`@.VU/​5D6@4U151D:​@24Y43Z!:​15)/​H%!!1T4-
 +M(#​X^/​B!M;​W9E+'​1X,​CMX,​B`@.W=(15)%H$E4H$-!3J!"​1:​!-3T1)1DE%1`T@
 +M/​CX^(&​UO=F4L='​DQ.WDQ#​2`^/​CX@;​6]V92QT>​3([>​3(-(#​X^/​B!S971B=68@
 +M.VY/​5Z!71:​!#​04Z@0TQ/​0D)%4J!42$6@0E5&​1D52#​0T@<​V5C("​`[;​4%+1:​!3
 +M55)%H%@Q/​%@R#​2!L9&​$@>#​(-('​-B8R!X,​0T@8F-S(#​IC;​VYT#​2!L9&​$@>​3(@
 +M.VE&​H$Y/​5"​R@4U=!4*!P,:​!!3D2@<#​(-(&​QD>​2!Y,​0T@<​W1A('​DQ#​2!S='​D@
 +M>​3(-(&​QD82!X,​0T@;&​1Y('​@R#​2!S='​D@>#​$-('​-T82!X,​@T-('​-E8PT@<​V)C
 +M('​@Q(#​MN3U>​@83U$6`TZ8V]N="​!S=&​$@9'​@-(&​QD>"​!X,​2`[<​%54H%@QH$E.
 +M5$^@>"​R@3D]7H%=%H$-!3J!44D%32*!X,​0T-8V]L=6UN(&​QD82!X,​2`[9DE.
 +M1*!42$6@1DE24U2@0T],​54U.H$9/​4J!X#​2!L<​W(@(#​LH=$A)4Z!#​04Z@0D6@
 +M34%$1:​!-54-(H$9!4U1%4B$I#​2!L<​W(@(#​MT2$521:​!!4D6@6#​$O.*`Q,​CB@
 +M0EE41:​!"​3$]#​2U,​-(&​QS<​B`@.W=(24-(H$U%04Y3H%@Q+S$VH#​(U-J!"​651%
 +MH$),​3T-+4PT@;'​-R#​2!B8V,​@.F5V96X@.W=)5$B@0:​!03U-324),​1:​!%6%12
 +M0:​`Q,​CB@0EE41:​!"​3$]#​2PT@;&​1Y(",​D.#​`@.TE&​H%-/​+*!3152@5$A%H$A)
 +M1TB@0DE4#​2!S='​D@8G5F9F5R#​2!C;&,​-.F5V96X@861C(&​)U9F9E<​BLQ(#​MA
 +M1$2@24Z@5$A%H$Y534)%4J!/​1J`R-3:​@0EE41:​!"​3$]#​2U,​-('​-T82!B=69F
 +M97(K,​2`[84Y$H%-43U)%H$E4(0T-('​-E8PT@;&​1A('​DR(#​MC04Q#​54Q!5$6@
 +M1%D-('​-B8R!Y,​0T@8F-S(#​IC;​VYT,​B`[:​5.@63(^63$_#​2!E;​W(@(R1F9B`[
 +M;​U1(15)725-%H$19/​5DQ+5DR#​2!A9&,​@(R0P,​0TZ8V]N=#​(@<​W1A(&​1Y#​2!C
 +M;​7`@9'​@@.W=(3R=3H$))1T=%4CJ@1%F@3U*@1%@_#​2!B8W,​@<​W1E<&​EN>​2`[
 +M:​4:​@1%DLH%=%H$Y%142@5$^@5$%+1:​!"​24>​@4U1%4%.@24Z@60T-<​W1E<&​EN
 +M>"​!L9'​D@>​3$@.WB@25.@04Q214%$6:​!3152@5$^@6#​$-(&​QD82!B:​71P+'​@@
 +M.W!,​3U2@5$A%H$9)4E-4H%!/​24Y4#​2J@96]RH",​D9F8-(&​%N9"​`H8G5F9F5R
 +M*2QY#​2!S=&​$@*&​)U9F9E<​BDL>​0T@/​CX^(&​-I;​FET+&​1X(#​MI3DE424%,​25I%
 +MH%1(1:​!#​3U5.5$52#​2!C<'​D@>​3(-(&​)C<​R!X9&​5C>​2`[9$^@5T6@4U1%4*!&​
 +M3U)705)$4Z!/​4J!"​04-+5T%21%.@24Z@>​3\-#​7AI;​F-Y(#​X^/​B!X<​W1E<"​QI
 +M;​GD-('​)T<​PT-<​W1E<&​EN>​2!L9'​D@>​3$@.W=%3$PLH$&​@3$E45$Q%H%)%4$54
 +M251)3TZ@3D5615*@2%525*!!3EE/​3D4-(&​QD82!B:​71P+'​@-*J!E;​W*@(R1F
 +M9@T@86YD("​AB=69F97(I+'​D-('​-T82`H8G5F9F5R*2QY#​2`^/​CX@8VEN:​70L
 +M9'​D-(&​-P>​2!Y,​@T@8F-S('​ED96-Y#​0UY:​6YC>​2`^/​CX@>​7-T97`L:​6YY#​2!R
 +M=',​-#​7AD96-Y(#​X^/​B!X<​W1E<"​QD97D@.W1(25.@25.@4%54H$A%4D6@4T^@
 +M5$A!5`T@<​G1S("​`[8E)!3D-(15.@05)%H$Q%1T%,#​0UY9&​5C>​2`^/​CX@>​7-T
 +M97`L9&​5Y#​2!R=',​-#​0TJ+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM
 +M+0TJH&​-,​14%.H%50#​0UC;&​5A;​G5P(&​QD82!V;​6-S8B`[<​U=)5$-(H$-(05*@
 +M4D]-H$)!0TN@24X-(&​%N9"​`C)3$Q,​3$P,​3`Q(#​M$149!54Q4#​2!S=&​$@=FUC
 +M<​V(-#​2!R=',​@(#​M"​644A#​0T@='​AT("​=H05!06:​!H3TQ)1$%94R&​@)PT@='​AT
 +M("​=33$J@,​3(O.30G#​0TJ+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM
 +M+0TJH'​-%5*!54*!"​252@5$%"​3$4-#​2!D<​R!>​(#​MC3$5!4J!43Z!%3D2@3T:​@
 +M4$%'​10T@("​`[<​T^@5$A!5*!404),​15.@4U1!4E2@3TZ@0:​!004=%H$)/​54Y$
 +M05)9#​6)I='​`@;'​5P(#​$V(#​LQ,​CB@94Y44DE%4Z!&​3U*@>​`T@9&​9B("​4P,​3$Q
 +M,​3$Q,​0T@9&​9B("​4Q,#​$Q,​3$Q,​0T@9&​9B("​4Q,​3`Q,​3$Q,​0T@9&​9B("​4Q,​3$P
 +M,​3$Q,​0T@9&​9B("​4Q,​3$Q,#​$Q,​0T@9&​9B("​4Q,​3$Q,​3`Q,​0T@9&​9B("​4Q,​3$Q
 +M,​3$P,​0T@9&​9B("​4Q,​3$Q,​3$Q,​`T@+2U>#​0US:​6X@.W1!0DQ%H$]&​H%-)3D53
 +M+*`Q,​C"​@0EE415,​-8V]S(&​5Q=2!S:​6XK,​3(X(#​MT04),​1:​!/​1J!#​3U-)3D53
 +M#​2`@(#​MB3U1(H$]&​H%1(15-%H%1224>​@5$%"​3$53H$%210T@("​`[0U524D5.
 +M5$Q9H%-%5*!54*!&​4D]-H&​)A<​VEC#​7ID:​78@97%U(&​-O<​RLQ,​C@@.V1)5DE3
 +M24].H%1!0DQ%#​71M871H(&​5Q=2!Z9&​EV*S,​X-"​`[;​4%42*!404),​1:​!/​1J!&​
 +M*%@I/​5@J6"​\R-38-="​`G4TQ*H#​$R+SDT)PT-*BTM+2TM+2TM+2TM+2TM+2TM
 +M+2TM+0"​`J0"​-(-"​-(="​M&​-`I#​PD0C1C0H`"​I'​X7[J8"​%_$Q:​@9*3!1$1$2`@
 +M("​`@("​`@("​`@("​!#​54)%,​T0@5C(N,​`T-("​`@("​`@("​`@("​`@("​`@("​`@0ED-
 +MGR`@("​!35$502$5.($I51$29("​`@($=%3U)'​12!405E,​3U(-#​9L@($-(14-+
 +M($]55"​!42$4@2D%.+B`Y-2!)4U-512!/​1@V6("​!#/​4A!0TM)3D>;​($9/​4B!-
 +M3U)%($1%5$%)3%,​A#​0T='​9X21C$O1C*2("​T@24Y#​+T1%0R!8+5)/​5$%424].
 +M#​1T=$D8S+T8TDB`M($E.0R]$14,​@62U23U1!5$E/​3@T='​1)&​-2]&​-I(@+2!)
 +M3D,​O1$5#​(%HM4D]4051)3TX-'​1T21C>​2(%)%4T544PT@(%!215-3(%$@5$\@
 +M455)5`T-!2`@("​`@(%!215-3($%.62!+15D@5$\@0D5'​24X-`+'​[\"​D@TO_(
 +MT/;​F_$Q:​@71(25,​@25,​@02!314-2150@5$585"​!-15-304=%(2#​D_\D`\/​FM
 +M%M`)$(T6T*F/​A2.%):​D!C2'​0J9,​@TO^I`(TAT*E`:​0R%^ZD%A?​RI`*``H@`8
 +MD?​O(:​1"​0^1BE^VDHA?​NE_&​D`A?​R@`.B*X!#​0Y*E`&&​D,​A?​NIV87\H@&​@`*D)
 +MD?​O(P!#​0^:​7[&&​DHA?​NE_&​D`A?​R@`.B*"​0@I#​^`3\`K)"​-#<​Z`D!3.F!J56%
 +MQ*D`A:​.I,​(6DA0*M&​-`I\0D.C1C0J0"​%885BA6.%9(5EA698(.3_R870"​Z5A
 +MR3SP6.9A3)^"​R8G0":​5A\$O&​84R?​@LF&​T`NE8LD\\#​SF8DR?​@LF*T`FE8O`O
 +MQF),​GX+)A]`+I6/​)//​`@YF-,​GX+)B]`)I6/​P$\9C3)^"​R8C0`TPK@LE1T`-,​
 +MSXMX&​*5D96'​)>​)`"​Z7B%9!BE965BR7B0`NEXA648I69E8\EXD`+I>​(5F.*5E
 +MY6:​P`FEXA6<​8I65E9LEXD`+I>​(5H&​*5D96;​)>​)`"​Z7B%:​3BE9.5FL`)I>​(5J
 +M&​*5D96C)>​)`"​Z7B%:​SBE9.5GL`)I>​(5L&​*5D96?​)>​)`"​Z7B%;​3BE:​.5DL`)I
 +M>​(5N.*5EY62P`FEXA6\8I61E9<​EXD`+I>​(5P&​*9GO0"​-IFA]`(V%I:​9GO8",​
 +M.*9H_8",​A::​F9;​V`C!`.&​$G_:​0$*&​$G_:​0%,;​X,​*A:<​XIFZ]`(VF;?​T`C3BF
 +M:​_T`C1BF;'​T`C1`.&​$G_:​0%*&​$G_:​0%,​F8-*&​*9I?​8",​.*9J_8",​A:​@XIFN]
 +M@(RF;/​V`C#​BF;?​V`C#​BF;​OV`C!`.&​$G_:​0%*&​$G_:​0%,​SX-*&​*9I?​0"​-&​*9J
 +M?​0"​-A:​FF;​[V`C#​BF</​V`C(6JIFR]@(PXIF[]@(PXIFW]@(PXIFO]@(P0#​AA)
 +M_VD!2AA)_VD!3!*$2ABF:​GT`C3BF:?​T`C86K&​*9LO0"​-IFU]`(TXIFO]`(TX
 +MIF[]`(T0#​AA)_VD!2AA)_VD!3$B$2ABF:​7V`C!BF:​GV`C(6L&​*9OO0"​-IG!]
 +M`(V%K4R0A&​=%12!B4D%)3BP@5TA!5"​!$3R!93U4@5T%.5"​!43R!$3R!43TY)
 +M1TA4/​ZE`A?>​%^*6M&&​6K&&​6LA5>​JO8"​-J*6G&&​6E&&​6FA2(82?​]I`84DL2(X
 +M\208:​2"​JI:​H89:​@89:​F%(AA)_VD!A22Q(CCQ)!AI0,​7WL`2%]Y`&​Q?​B0`H7X
 +MJ(:​2A).EK1AEJSCEK(58JKV`C:​BEIQAEI3CEIH4B&​$G_:​0&​%)+$B./​$D&&​D@
 +MJJ6J&&​6H..6IA2(82?​]I`84DL2(X\208:​4#​%][`$A?>​0!L7XD`*%^*B&​E(25
 +MI:​TXY:​LXY:​RJO8"​-J*6G..6E..6FA2(82?​]I`84DL2(X\208:​2"​JI:​HXY:​@X
 +MY:​F%(AA)_VD!A22Q(CCQ)!AI0,​7WL`2%]Y`&​Q?​B0`H7XJ(:​6A*ZEK3CEJQAE
 +MK(59JKV`C:​BEISCEI1AEIH4B&​$G_:​0&​%)+$B./​$D&&​D@JJ6J..6H&&​6IA2(8
 +M2?​]I`84DL2(X\208:​4#​%][`$A?>​0!L7XD`*%^*B&​KX2P&​*6G2?​]I`86G&​*6J
 +M2?​]I`86J&​*6M2?​]I`86MI:​TXY:​L89:​RJO8"​-J*6G..6E&&​6FA2(82?​]I`84D
 +ML2(X\208:​2"​JI:​HXY:​@89:​F%(AA)_VD!A22Q(CCQ)!AI0,​7WL`2%]Y`&​Q?​B0
 +M`H7XJ(91A%*EK3CEJSCEK*J]@(VHI:<​XY:​4XY::​%(AA)_VD!A22Q(CCQ)!AI
 +M(*JEJCCEJ#​CEJ84B&​$G_:​0&​%)+$B./​$D&&​E`Q?>​P!(7WD`;​%^)`"​A?​BHAG&​$
 +M4*6M&&​6K..6LJKV`C:​BEIQAEI3CEIH4B&​$G_:​0&​%)+$B./​$D&&​D@JJ6J&&​6H
 +M..6IA2(82?​]I`84DL2(X\208:​4#​%][`$A?>​0!L7XD`*%^*B&​LX2TI:​T89:​L8
 +M9:​R%8*J]@(VHI:<​89:​489::​%(AA)_VD!A22Q(CCQ)!AI(*JEJAAEJ!AEJ84B
 +M&​$G_:​0&​%)+$B./​$D&&​E`Q?>​P!(7WD`;​%^)`"​A?​BHAK&​$LJD`A:​.E`H6DA?​RI
 +M@(7[YO>​I`*((H`"​1HY'​[R,​3WT/>​EQ)&​CD?​L8:​55I`,​C$^-#​RJ0"​1HY'​[R!#​Y
 +MH`#​FI.;​\RM#​5J0"​%M:​6V..57<​$0896!0`J5@$#​NI`86UI9*%/​Z63A4"​EE(5!
 +MI96%0B"​GBJ66A3^EKH5`(*>​*I:​^%0:​6PA4(@IXJEDH4_I9.%0""​GBDPIB*6V
 +M..5@<​$$895=0`J57$#​BI((6UI;&​%0:​6RA4*ELX4_I;​2%0""​GBJ5QA4&​E4(5"​
 +M(*>​*I5&​%/​Z52A4`@IXJEL85!I;​*%0B"​GBJ6V..57<​%`895E0`J59$$>​I`@6U
 +MA;​6FDH8_II.&​0"​D!T`NEE(5!I96%0B"​GBJ:​QAD&​FLH9"​(*>​*IK.&/​Z:​TAD"​E
 +MM2D@T`,​@IXJEE(5!I96%0B"​GBDS4B*6V..59<​$T895=0`J57$$2I$`6UA;​6F
 +MEH8_IJZ&​0"​D!T`NEKX5!I;"​%0B"​GBJ5QA4&​E4(5"​(*>​*I5&​%/​Z52A4"​EM2D@
 +MT`,​@IXJEKX5!I;"​%0B"​GBJ6V..57<​%P895A0`J58$%.I!`6UA;​6FDH8_II.&​
 +M0"​D!T`NEKX5!I;"​%0B"​GBJ:​QAD&​FLH9"​I;​4I`M`#​(*>​*IE&&/​Z92AD"​EM2D@
 +MT`,​@IXJFKX9!IK"&​0J6U*1#​08B"​GBDR3B:​6V..58<​%4895=0`J57$$REE(4_
 +MI96%0*6U*0'​0"​Z66A4&​EKH5"​(*>​*I;​.%0:​6TA4*EM2D"​T`,​@IXJE<​84_I5"​%
 +M0*6U*2#​0`R"​GBJ66A4&​EKH5"​I;​4I$-`#​(*>​*I/>​I`(6CI0*%I*((L:​-%Q-`;​
 +MD:​.I@(6CL:​-%Q-`/​D:​.%H^:​DRM#​E('​V*3":​*JBG`\`-,​V(F**3#​P!:​D/​3-2)
 +MJ0,​QHY&​CI0(8:​0>​%I*F`A:​.QHT7$T!21HX6CL:​-%Q-`*D:​.I@(6CQJ30YJHI
 +M`_`#​3!6*BBD,​\`6I\$P1BJG`,:​.1HQBEQ&​E5:​0"​%Q,​C$^/​`#​3)6)K1C020*-
 +M&​-"​I"​$4"​A0+N(M#​.(]!,​.8)S04U%(%1(24Y'​(%=%($1/​($5615)9($Y)1TA4
 +M+"​!P24Y+63H@5%)9(%1/​(%1!2T4@3U9%4B!42$4@5T]23$0AH@"​]C(KP!R#​2
 +M_^A,?​XI@#​5-/​34542$E.1R!#​2$]+140@.B@-`&​Y!4D8AI3^%^Z5!A?​VE0(7\
 +MI4*%_JD`A:​.E`H6D.*7]Y?​NP$Z7^I/​R%_(3^I?​ND_83[A?​TXY?​N%^:;​[I?​M*
 +M2DJ0!:"​`A*,​89:​2%I#​BE_N7\L`1)_VD!A?​K%^;​`XI/​R]`(PQHY&​CI?​E*2?​]I
 +M`<​3^L&​CH9?​J0`\CE^4B]`(PP#​*F`1:​.%HS`"​YJ2I/​S&​CD:​-HY/​W0W6"​D_+T`
 +MC#&​CD:​.E^DI)_VD!Q/​ZP5,​AE^9`=Z.7Z2+T`C#​`,​J8!%HX6C,​`+FI*D_,:​.1
 +MHVA,​=8M(O0",,:​.1HVC$_M#​18.AE^I`#​B.7Y2+T`C#​`,​J8!%HX6C,​`+FI*D_
 +M,:​.1HVCD_=#​=8(@89?​F0'>​CE^DB]`(PP#​*F`1:​.%HS`"​YJ2I/​S&​CD:​-H3,​J+
 +M2+T`C#&​CD:​-HQ/​[0T&"​M&​-`I]8T8T*T6T"​GOC1;​08&​A!4%!9(&​A/​3$E$05E3
 +M(2!33$H@,​3(O.30`````````/​\_S_#​_/​\_P_S_/​\/​\_S_#​_/​\_P_S_/​\/​\_S
 +M_#​_/​\_P_S_/​\/​\_S_#​_/​\_P_S_/​\/​\_S_#​_/​\_P_S_/​\/​\_S_#​_/​\_P_S_/​\
 +M/​\_S_#​_/​\_P_S_/​\/​\_S_#​_/​\_P_S_/​\/​\_S_#​_/​\_P_S_/​\/​\_S_#​_/​\_P_
 +MS_/​\/​\_S_#​_/​\_P@TO_H3'​^*8`U33TU%5$A)3D<​@0TA/​2T5$(#​HH#​0!N05)&​
 +M(:​4_A?​NE087]I4"​%_*5"​A?​ZI`(6CI0*%I#​BE_>​7[L!.E_J3\A?​R$_J7[I/​V$
 +M^X7]..7[A?​FF^Z7[2DI*D`6@@(2C`0@D"​```CR!(3TQ)1$%9(#​$Y.30@+2T@
 +M4TQ*(#​$R+S(X+SDT`$0(`0"/​($E.4U!)4D5$($)9($HN($-(05).15132TD`
 +M5@@"​`(\@04Y$($]42$524RX`>​0@#​`(\@5$A)4R!!3%-/​(%-%5%,​@55`@5$%"​
 +M3$53($9/​4@"​7"​`0`CR!42$4@4%)/​1U)!32!#​54)%,​T0@5C(N,​`"​Y"​`4`ES4Q
 +M+#​`ZES4R+#​$R.#​J7-34L,#​J7-38L,​3(X.IP`Q0@)`(8@5B@S-BD`X`@*`)<​U
 +M,​S(X,"​PP.I<​U,​S(X,​2PP.HTT,#​``_P@4`$$DLB(J*BHJ*BHJ*BHJ*BHJ*BHJ
 +M*B(Z4[(Q`#​D)&​0!2)+(B'​1T='​1T='​1T='​1T='​1T='​1T='​1TB.D0DLB(1$1$1
 +M$1$1$1$1$1$1$1$1$1$1$1$1(@!9"​1X`@4FR,:​0Q,​SI3LE.J,​JPH2;​(T*:​HS
 +MK"​A)LC@I`(H)*`"​9(A,​1$1$BR"​A$)"​Q)*<​@H4B0L,​C&​K4RG(*$$D+#​*L4ZLQ
 +M*3LZ4[)3JC$Z@@"​Z"​3(`F2(3(L@H1"​0L,​38IR"​A2)"​PQ.2DB$I4@("​`1G9V=
 +M("​`@$9V=G2`@()(B.P#​0"​3P`F2(3$1$1'​1T='​1T='​1T%*"​(`\0D^`)DB$YHB
 +M1"​0B$1$='​1T='​5!!5$E%3D-%+BXN(CL`_0E!`(%)LC&​D,​3@`)@I&​`%*RM2B[
 +M*#​$IK#​8T,​*HP+C4IJC$P,​C0ZBR#"​*%(IL[$S,​J<​W,​`!1"​E``5BA)*;​)2JC4T
 +M,​C<​R.I=2+#​0V.I=6*$DI++4HNR@P*:​PWJC$I.H(`7@I5`(%)LC$YI#,​V`(<​*
 +M6@!2LK4HNR@Q*:​PV-#"​J,"​XU*:​HQ,#​(T.HL@PBA2*;​.Q-#​*G.3``L@I?​`%8H
 +M22FR4JHU-#​(W,​CJ74BPX,​3J75BA)*2RU*+LH,"​FL-ZHQ*3J"​`-L*8`"​9(A.:​
 +M(D0D(A$1'​1T='​1U0051)14Y#​12XN+B`<​U!,​1$2)$)#​L`_PIA`$8DLB*TG;​6=
 +MH9T2MIVJG2`B.D,​QLC$Z0S*R,#​I2LC$`+PMB`%,​R)+(B(%!%04-%($%.1"​!"​
 +M3$534TE.1U,​@5$\@64]5($E.(#​$Y.34@("​(`30MC`%,​DLB(@3D%51TA462!/​
 +M4B!.24-%/​R`@("​(`4PMD`(\`;​`MF`(\@4T54(%50(%1224<​@5$%"​3$53`(4+
 +M9P"/​("​TM+2TM+2TM+2TM+2TM+2TM+0"​P"​VD`0E.R,​S4Y-C@Z0D.R0E.J,​3(X
 +M.D):​LD)#​JC$R.#​I"​3;​)"​6JHS.#​0`P`MN`$&​R,#​I$0;​+_K38P`/​8+>​`"​!2;​(P
 +MI#​$R,#​I3LK4H,​S*LORA!*:​HP+C4I.D.RM2@S,​JR^*$$IJC`N-2DZ0;​)!JD1!
 +M``H,​@@"​+(%.S,""​G(%.R,​C4VJE,​`'​@R,​`(L@0[,​P(*<​@0[(R-3:​J0P`R#​)8`
 +MET)3JDDL4SJ70D.J22Q#​`#​@,​H`"/​`%`,​H@"/​("​TM+2TM+2TM+2TM+2TM+2TM
 +M`&​T,​I0!2,​K+"​*%8H,​3BJ4BDI.E(QLL(H5BA2*2D`E@RJ`)=6*%(I+%(R.I=6
 +M*%*J,​3@I+%(Q.E*R4JHQ.HM2LC$YIU*R,​0#&#​*\`BT,​QL3$RIT,​QLC$Z0S*R
 +M0S*J,​3J9(ITBRBA3)"​Q#,​BPQ*2*2(CLZB3$Y,​`#?#​+0`F<​HH1B0L0S$L,​BD[
 +M.D,​QLD,​QJC(`]PRY`(\@+2TM+2TM+2TM+2TM+2TM+2T`_PR^`((@20`%#<,​`
 +MCP!.#<​@`0S*R,#​I3)+)3,​B0ZF2(3(D0D(A$1("​`@("​`@("​`@("​`@(`5.24-%
 +M(2`@("​`@("​`@("​`@("​`@("​`@(""​9M!,​1$2)$)#​L`60W2`(%)LC&​D.0"​*#​=P`
 +M4K*U*+LH,"​FL,​RFL-#"​JM2B[*#​`IK#​$S*:​HQ-S4Y.HO"​*%(IL[$S,​J<​R,​C``
 +ML`WF`)=2+#​(Q.3J74JHU-#​(W,​BRU*+LH,"​FL.*HQ*3J"​.E*R,​0"​V#>​D`CP#​8
 +M#>​H`CR!3150@55`@355,​5"​!!3D0@4%)/​2B!404),​15,​`^@WK`(\@+2TM+2TM
 +M+2TM+2TM+2TM+2TM+2TM+2TM+2TM``D.\`!$LC$W,#​I:,​+(U`"​4.^@!+LK4H
 +M-C2L,​JU:,​*HP+C4I.I<​Q.#​(L2P!'#​@0!@4JR,​*0R-34Z6K)*.HL@6K$Q,​C<​@
 +MIUJR6JLR-38`8`X.`5&​RM2A$K2A:,​*M:​K38T*:​HP+C4I`'​0.$0&​+(%&​Q,​3(W
 +M(*<​@4;​(Q,​C<​`B@X3`8L@4;​.K,​3(W(*<​@4;​*K,​3(W`)X.%`&​+(%&​S,""​G(%&​R
 +M,​C4VJE$`J@X8`9="​6JI*+%$`Q`XB`5.R2CJ+(%.Q,​34P(*<​@4[(R-3:​K4P#​9
 +M#​BP!4;​*U*%.L4ZTR-3:​J,"​XU*0#​S#​C8!ER!"​3:​I*+%$ZER!"​3:​I*JC(U-BQ1
 +M`/​D..P&/​``@//​`&/​("​TM+2TM+2TM`"​4//​@%2,​K+"​*%8H,​3BJ4BDI.E(QLL(H
 +M5BA2*2D`3@]``9=6*%(I+%(R.I=6*%*J,​3@I+%(Q.E*R4JHQ.HM2LC$YIU*R
 +M,​0!^#​TH!BT,​QL3$RIT,​QLC$Z0S*R0S*J,​3J9(ITBRBA3)"​Q#,​BPQ*2*2(CLZ
 +MB3,​U,​`"​7#​U0!F<​HH1B0L0S$L,​BD[.D,​QLD,​QJC(`I@]9`8\@+2TM+2TM+2T`
 +MK@]>​`8(@2@#​(#​V@!GC,​R-S8X.IDB2$\A($A/​(2!(3R$B`.0/:​0&​9(D5-04E,​
 +M(%-*541$0$Y752Y%1%4@(@`&​$&​H!F2(@+4]2+2!!038P,​4!#​1DXN0U,​N1$%,​
 +M+D-!("​(`'​!!K`9DB$4]2(%=2251%(%1/​.B`B`#​L0;​`&​9(B`@("​!35$5612!*
 +M541$("​`@("​`@("​`@(@!:​$&​T!F2(@("​`@,​3$P,"​!'​4D]612`C0E<​@("​`@("​(`
 +M>​1!N`9DB("​`@($5604Y35$].+"​!)3"​`V,#​(P,​2`B`)@0<​@&​9(B`@("​`@("​`@
 +M("​`@("​`@("​`@("​`@("​`@(@">​$(8!@`#​-$)`!ES(Q-"​PR,​CJ9(I8B.H%)LC&​D
 +M,​S@Z022R022J(M8B.D(DLD(DJB(@(CJ"​`.T0F@%!)+)!)*HBUM:​1D2(Z@4FR
 +M,:​0R-#​J9020[.H(`'​!&​D`9DB$QT1'​B([.D(DLD(DJB(='​2(Z@4FR,:​0R,​CJ9
 +M0B0[.H(ZF2(3$2(ZC@```"​DI`$X/​0`&​75BA2*2Q2,​CJ75BA2JC$X*2Q2,​3I2
 +MLE*J,​3J+4K(Q.:​=2LC$`?​@]*`8M#,;​$Q,​J=#,;​(Q.D,​RLD,​RJC$ZF2*=(LHH
 +M4R0L0S(L,​2DBDB([.HDS-3``EP]4`9G**$8D+$,​Q+#​(I.SI#,;​)#,:​HR`*8/​
 +M60&/​("​TM+2TM+2TM`*X/​7@&"​($H`R`]H`9XS,​C<​V.#​J9(DA/​(2!(3R$@2$\A
 +M(@#​D#​VD!F2)%34%)3"​!32E5$1$!.5U4N1415("​(`!A!J`9DB("​U/​4BT!""​8(
 +M"​@"​9(I,​%3D]415,​@1D]2($-50D4S1#​(N,"​!!3D0@,​BXQ(@!-"​!0`F2(13$]!
 +M1"​!42$4@+D\@3T)*14-4($9)3$4@0D5&​3U)%(@!F"​!X`F2),​3T%$24Y'​($E.
 +M250S1#​(N,"​(`C@@H`)DB5$A%(%)%3$5604Y4($Q)3D53($E.($E.250S1"​!!
 +M4D4B`+`(,​@"​9(DQ)3D53(#​$P,"​TQ-3`@04Y$(#​(S,​RTS,​3`N(@#​1"#​P`F2)$
 +M($%.1"​!:,"​!!4D4@24X@3$E.12`R-#​`N(@#​\"​$8`F2(1248@64]5(%1262!4
 +M3R!#​2$%.1T4@4T]-151(24Y'​($%.1"​(`)PE0`)DB1T54($%.(#​])3$Q%1T%,​
 +M(%%504Y42519($524D]2($I54U0B`#​@)6@"​9(E194$4@0TQ2+B(`9`ED`)DB
 +M$1*>​248@64]5(%=!3E0@5$\@4E5.($-50D4S1#​(N,​2!-04M%(@","​6X`F2(2
 +M4U5212!43R!#​2$%.1T4@1"​!)3B!,​24Y%(#​(T,"​!43R(`I`EX`)DB$D0].#​4@
 +M050@34]35"​$A(2(`T@F"​`)DB$0533TU%($]&​(%1(12!:​15)/​(%!!1T4@3$]#​
 +M051)3TY3(%53140B```*C`"​9(DU!62!(3U-%($)!4TE#​("​TM(%)%0D]/​5"​!"​
 +M149/​4D4@4T%624Y'​(@`4"​I8`F2)!3ED@0TA!3D=%4RXB`$,​*H`"​9(A%+1450
 +M($E.($U)3D0@5$A!5"​!93U4@0T%.(%!215-3($8Q($540R(`<​@JJ`)DB355,​
 +M5$E03$4@5$E-15,​@5$\@4U!%140@55`@5$A%(%)/​5$%424].(@","​K0`F2(1
 +M$2A04D534R!!3ED@2T59*2([`)\*O@"​A020ZBT$DLB(BIS$Y,​`#,"​L@`F2*3
 +M0U5"​13-$,​BXQ($9%05154D53($U53%1)0T],​3U(@04Y$($%.(@#​V"​M(`F2)!
 +M4%!!3$Q)3D=,​62!44DE624%,​(%1%6%154D4@34%0($]&​(@`A"​]P`F2)!(%-/​
 +M4E0@+2T@250@5T%3($A!0TM%1"​!43T=%5$A%4B!!5"​(`30OF`)DB5$A%($Q!
 +M4U0@34E.551%+"​!!3D0@5TE,​3"​!"​12!44D5!5$5$(@!R"​_``F2))3B!-3U)%
 +M($1%5$%)3"​!)3B!42$4@1E5455)%+B(`G@OZ`)DB$5=%($A/​4$4@64]5($Q)
 +M2T4@5$A%4T4@4%)/​1U)!35,​@04Y$(@"​W"​P0!F2)&​24Y$(%1(14T@55-%1E5,​
 +M(2(````:&​AH:&​AH:&​AH:&​AH:&​AH:&​AH:&​AH:&​AH:&​AH:&​AH:&​AH:&​AH:&​AH:​
 +6&​AH:&​AH:&​AH:&​AH:&​AH:&​AH:&​AH:&​AH:​
 +`
 +end
 +
 +==============================================================================
 +</​code>​
 +====== 2D Graphics Toolbox -- Circles ======
 +<​code>​
 +by Stephen Judd  (sjudd@nwu.edu)
 +
 +3D is fun and interesting but in the end we must always display our work on a
 +two-dimensional surface, the CRT.  Not only are two-dimensional algorithms
 +the foundation of three-dimensional drawings, they are of course useful for
 +many other applications. ​ This new series of articles is intended to
 +complement (hah -- get it?) the 3D articles by George and myself. ​ Between
 +the two articles you should have at your disposal a powerful graphics toolbox
 +for all of your applications.
 +
 +The foundation of all of our drawings is a single point, and a logical next
 +step would be a line.  Algorithms for doing both of these things were
 +discussed in depth in the first article of the 3D series, so you can look
 +those up in a back-issue of C=Hacking. ​ What is next after points and lines?
 +Curves! ​ So to start with, let's think about drawing a circle.
 +
 +You can write the equation for a circle in many ways, depending on your
 +coordinate system. ​ In cartesian coordinates,​ the equation of a circle is:
 +
 + x^2 + y^2 = r^2 (1)
 +
 +This is a circle centered at the origin (on a computer we can always
 +translate the points wherever we want), with radius r.  In polar coordinates
 +the equation is r=const. ​ We can write down trigonometric relations out the
 +wazoo, too, but no matter what it looks like we're going to have some
 +complicated math ahead of us involving multiplications and worse, i.e.
 +time-intensive computations. ​ Perhaps the simplest of these would be:
 +
 + x=r*cos(theta)
 + y=r*sin(theta)
 +
 +where theta runs from zero to 2*pi.  If we have a table of sines and cosines,
 +and use the fast multiplication algorithm given in this months 3D article, we
 +have a routine which gives a good circle in around 50 cycles or so per pixel,
 +sans plot.
 +
 +But let's step back and consider: the above equations all give a "​perfect"​
 +circle. ​ Is there any way we can draw an "​approximate"​ circle, with a large
 +speed increase? ​ The answer is of course yes, since this wouldn'​t be a very
 +interesting article otherwise!
 +
 +Let's say we are standing at a point on the circle, and want to take a step
 +towards the next point. ​ In what direction do we take this step?  Consider a
 +line tangent to the circle, touching the point where we are standing. ​ If we
 +take a little step in that direction, we ought to get close to the next point
 +on the circle. The way to calculate the tangent line is to use the
 +derivative, which will give us the slope of the tangent. ​ Taking
 +differentials of equation (1) above we have
 +
 + 2*x dx + 2*y dy = 0
 +or
 + dy/dx = -x/y
 +
 +Now, if I am at a point (x,y), I want to take a little step in x and a little
 +step in y:
 +
 + x = x+dx
 + y = y+dy
 +
 +but from the first equation we know that dx = -y/x * dy so that at each step
 +our iteration is
 +
 + y = y + dy
 + x = x - dy*(y/x)
 +
 +This is the basis of our algorithm. ​ You could also of course use
 +
 + x = x + dx
 + y = y - dx*(x/y)
 +
 +(this is called Euler'​s method for solving a differential equation, and these
 +concepts are fundamental to most algorithms for solving differential
 +equations numerically).
 +
 +Let's start at the point x=r,y=0 i.e. the right-endpoint of the circle.
 +Since we are on a computer we want to take a step of length one in some
 +direction (i.e. step one pixel), and at this point on the circle y is clearly
 +increasing much faster than x. You may remember from the line drawing
 +algorithm that we viewed the process as "keep taking steps in x until it is
 +time to take a step in y". We are going to apply that same philosophy here:
 +keep taking steps in y until it is time to take a step (backwards) in x.  So
 +our iteration is now:
 +
 + y_{n+1} = y_n + 1
 + x_{n+1} = x_n - y_n/x_n
 +
 +Hmmm... we have this little problem now of y/x.  I certainly don't want to
 +deal with floating point. ​ How do we get around this?  The trick is to think
 +of x as a _discrete_ variable -- as far as a pixel is concerned x is just an
 +integer, and has no floating point part.  So we are going to treat x as a
 +constant, until it is time to decrease x by one! When does this happen?
 +Let's expand the x-iteration:​
 +
 + x_{n+1} = x_n - y_n/x_n
 + = (x_{n-1} - y_{n-1}/​x_{n-1}) - y_n/x_n
 +
 +This is where the magic of using a discrete x comes in.  If we make this
 +assumption of constant x, then x_{n-1} = x_n and the above iteration becomes
 +
 + x_{n+1} = x_{n-1} - (y_{n-1} + y_n)/​x_{n-1}
 +
 +If we continue this process over an interval where x is constant we get
 +
 + x_{n+1} = x_0 - (y_n + y_{n-1} + y_{n-2} + ...)/x_0
 +
 +When is it time to decrease x?  When the sum of the y values at each
 +iteration exceeds the current x-value the fraction above will be greater than
 +one, and we will then decrease x.  Like I said, we keep x constant, until it
 +is time to decrease it! :)
 +
 +How long do we do this for?  In the same way that at x=r y increases much
 +faster than x does, when y=r x increases much faster than y does.  Somehwere
 +in-between they have to be increasing at the same rate, which means the slope
 +of the tangent line is equal to +/-1, i.e. at the point x=y.  At this point
 +we have drawn one-eighth of the circle. ​ We can either draw all eight
 +segments of the circle independentally,​ or else we can use the symmetry of a
 +circle and do an 8-way plot.
 +
 +TO SUMMARIZE: Here is the basic algorithm
 +
 + x=r
 + y=0
 + a=0
 + :loop
 + y=y+1
 + a=a+y
 + if a>x then x=x-1:a=a-x
 + plot8(x,y)
 + :until x<=y
 +
 +Of course you can refine this in several ways, which will speed things up in
 +assembly. ​ For instance, if instead of a=0 we start with a=x, then the logic
 +becomes
 +
 + a=a-y
 + if a<0 then x=x-1:a=a+x
 +
 +To do the a=a-x you could use a table where f(x)=x, or you might try
 +something else; here is some code in assembly:
 +
 + LDX R
 + LDY #00
 + STY Y
 + TXA
 +:loop JSR PLOT8 ;​Eight-way symmetric plot
 + SEC ;Might not need this depending on PLOT8
 + INC Y ;Y is in zero page
 + SBC Y
 + BCS :loop
 + DEX
 + STX X ;X is also in zero-page
 + ADC X ;Carry is already clear
 + CPX Y
 + BCS :loop
 + JSR PLOT8 ;​Catch the last point
 +
 +Starting at :loop we have 2+3+3+3=11 cycles in the best case and
 +2+3+3+2+2+3+3+3+3=24 cycles in the worst case, excluding PLOT8. ​ You can, of
 +course, change the program logic around; if PLOT8 returned with the carry
 +always clear it would be much smarter to start A as A=256-A and use A=A+Y at
 +each step instead of A=A-Y. ​ Christopher Jam (phillips@ee.uwa.edu.au)
 +suggested starting at X=Y(=R/​sqrt(2)) so that the CPX Y instruction could be
 +removed (I don't know how this affects accuracy, though).
 +
 +"Yeah, but how well does it work?" ​ Quite well, as a matter of fact.  It will
 +draw a perfect circle for circles with a radius greater than twelve or so.
 +For circles with a smaller radius the sides start to flatten out, and the
 +circle becomes squareish. ​ Interestingly,​ the "​discrete x" approximation
 +improves the result over the straight floating-point calculation
 +significantly!
 +
 +So this is the best algorithm I was able to come up with for drawing a
 +circle. ​ If you have any suggestions for improvements or other ideas, please
 +feel free to share them :).  As always I must thank George Taylor and
 +Christopher Jam for their suggestions and for helping me work out some ideas.
 +
 +If you have any particular 2D algortihms/​calculations that you would like to
 +see, please feel free to suggest future topics for the 2D graphics toolbox.
 +
 +Finally, here is a BASIC7.0 program which demonstrates the algorithm:
 +
 +0 REM FAST CIRCLE -- SLJ 9/94
 +10 GRAPHIC 1,1
 +15 REM X=Radius
 +20 X=40:​Y=0:​TX=X:​XO=160:​YO=100
 +30 DRAW1,​X+XO,​Y+YO:​DRAW1,​Y+XO,​X+YO
 +40 DRAW1,​XO-X,​YO+Y:​DRAW1,​XO-Y,​YO+X
 +50 DRAW1,​XO-X,​YO-Y:​DRAW1,​XO-Y,​YO-X
 +60 DRAW1,​XO+X,​YO-Y:​DRAW1,​XO+Y,​YO-X
 +70 IF X<=Y THEN 100
 +80 Y=Y+1:​TX=TX-Y
 +90 IF TX<0 THEN X=X-1:​TX=TX+X
 +95 GOTO 30
 +100 END
 +
 +===========================================================================
 +</​code>​
 +====== AFLI-specs v1.0 ======
 +<​code>​
 +by written by D'​Arc/​Topaz for Chief/Padua on 28.6.1994
 +
 +Advanged FLI is name I came up with during the time I coded the
 +first version of AFLI editor. I have never claimed to be the one
 +who discovered this new graphics mode for 64. I myself give the
 +credit for COLORFUL/​ORIGO but I am not sure if anyone did it
 +before him (splits have been done but in my eyes they don't count).
 +
 +In AFLI we can get 120 colors in theory (counted like this
 +16!/​(2!*14!)=120). When we put red and blue hires pixels close to
 +each other we get a vision of purple - thanks the television.
 +
 +AFLI is just like FLI with $08-$0f (hires value) in $d016 and a
 +couple of sprites over the first three marks. With $d018 we
 +change the start of screen memory. And the good old $d011 for the
 +main work.
 +
 +AFLI is the same as FLI but we don't use the $d800-$dc00 area
 +for the third color. Actually we can't. In normal hires pictures
 +the colors on the picture is ordered in a normal screen (normal
 +text screen is on $0400+). The upper 4 bits is the color for
 +bit 0 in picture bitmap and the lower 4 bits is the color for bit
 +1 in picture bitmap (or the other way...but let us think that was
 +the right way).
 +
 +For example: a normal hires picture char (8x8 bits)
 +
 + ​01234567 ​ in hires picture where  01234567
 +0 *****    the first spot of the  0bgggggbb
 +1*** ***   ​screen has a value of  1gggbgggb
 +2*** ***   $68 (blue&​green) the   ​2gggbgggb
 +3******* ​  hires picture looks    3gggggggb
 +4*** ***   like this ----> ​       4gggbgggb
 +5*** ***   ​b=blue,​ g=green ​       5gggbgggb
 +6*** ***                          6gggbgggb
 +7                                 ​7bbbbbbbb
 +
 +The bitmap is built just as in a hires picture bit 1 means the pixel
 +is on and 0 that the pixel is off.
 +
 +In FLI we have built the screen to have badlines on every scanline of
 +the screen. This gives us the possibility to change the screenmemory
 +the picture uses on everyline. Now... when AFLI (and FLI) uses screen
 +memory for colors and we change the screenmemory start on everyline,
 +we can have new colors on everyline.
 +
 +The screens are usually ordered like this.
 +
 +screen memory used
 +   ​0 ​  ​$4000-$43ff
 +   ​1 ​  ​$4400-$47ff
 +   ​2 ​  ​$4800-$4bff
 +   ​3 ​  ​$4c00-$4fff
 +   ​4 ​  ​$5000-$53ff
 +   ​5 ​  ​$5400-$57ff
 +   ​6 ​  ​$5800-$5bff
 +   ​7 ​  ​$5c00-$5fff
 +       ​$6000-$7fff BITMAP (the actual picture data)
 +
 +The number of the screen is considered as the number of the line in
 +8x8 pixel area.
 +
 +An example... Here we have cut from the memory showing the first
 +bytes in every screen.
 +
 +screen/​rownumber
 +           00 01 02 03 04 05 06 07 08 09 10 11 12 13 ... 39
 +     $4000 ff ff ff 56 .. .. ..
 +     $4400 ff ff ff 67 .. ..
 +     $4800 ff ff ff 91 ..
 +     $4c00 ff ff ff b3
 +     $5000 ff ff ff 54
 +     $5400 ff ff ff 8f
 +     $5800 ff ff ff 54
 +     $5c00 ff ff ff 10
 +
 +Actually the $ff won't have to be there. It will come to the screen
 +anyway. We have the same '​A'​ on the screen on the fourth mark ($6018-
 +$601f).
 +
 +  BITMAP ​              AFLI PICTURE (number is the color number)
 + ​01234567 screenvalue ​   01234567
 +0 *****       ​$56 ​     0 56666655 ​  ​1=white,​ 0=black, 2=red ...
 +1*** ***      $67      1 77767776
 +2*** ***      $91      2 11191119
 +3******* ​     $b3      3 33333333
 +4*** ***      $54      4 44454445
 +5*** ***      $8f      5 fff8fff8
 +6*** ***      $54      6 44454445
 +7             ​$10 ​     7 11111111
 +
 +Now the '​A'​ surely has a lot of colors.
 +
 +
 +When we code a FLI routine we know that we have succeeded when we get
 +a 3 marks wide area filled with value $ff on the screen. In FLI the
 +thing is easily taken away; we just fill the three first bytes of a
 +line with empty bytes ($00). In AFLI the value $ff is a color. If we
 +try to clear the three first marks, we still have the gray area. WHY?
 +The $ff value comes to the screen.. so... the $ff is a color and
 +the upper four bits of the byte is the color for empty pixels. We can
 +not clear the first three marks to wipe the thing off. We have a new
 +lovely problem: we have to put black (or whatever) sprites over that
 +area. This is just timing.
 +
 +
 +This may look very complicated and I think you will still be asking
 +many questions from me - the text I have written surely ain't the
 +best novel ever written. I'm great in jumping from a thing to
 +another.
 +
 +
 +--
 +Chief/​Padua  ​ +44 (0) 757 706791
 +                              --------------------
 +                        My opinions are not my employers
 +===========================================================================
 +</​code>​
 +====== Coding Tricks ======
 +<​code>​
 +
 +The following are messages posted to comp.sys.cbm that contain little "​coding
 +tricks"​ that I thought were useful. If you've got any of your own that you want
 +to post feel free to email them to me and I'll post them to comp.sys.cbm -
 +duck@pembvax1.pembroke.edu.
 +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 +From: paulvl@python.es.ele.tue.nl (Paul van Loon)
 +Date: 11 Oct 1994 14:28:49 GMT
 +
 +Hello everyone,
 +
 +I really would like to start a thread on your favorite
 +sequences of 6502 code. I hope much people will react
 +so we can build up a library of the most beautiful
 +6502 code ever seen.
 +I would suggest little code fragments, probably not
 +longer than 10 lines, doing some tiny function.
 +
 +I propose the following standard:
 +
 +-----------------------
 +<xxx> <​yyyyy>​ "​text"​
 +      <​aaa> ​  ; comment
 +      <​bbb> ​  ; comment
 +
 +"​description"​
 +-----------------------
 +
 +where <xxx> is the symbolic name (3 letters?) you give
 +to your code sequence, <​yyyyy>​ describes your arguments
 +"​text"​ gives a full name to pronounce for the symbolic name
 +and <aaa> and on are the 6502 instructions you use. "​description"​
 +is a description of the functionality of your code. The lines
 +with "​---"​ are seperators.
 +
 +I will hereby start with my all-time favourite code,
 +I discovered it only recently and I will also
 +show some examples of how to use it!
 +
 +---------------------------------------
 +
 +B7C        "Bit 7 to Carry"
 +    cmp #$80
 +
 +This instruction copies bit 7 of A to C
 +---------------------------------------
 +
 +This is really a beauty! It works because
 +cmp clears the carry if A is below the immediate
 +value, and sets it if A is higher or same.
 +All values lower than $80 have bit 7 equal 0,
 +cmp will clear C for all values below $80, and
 +thus will '​copy'​ bit 7 into carry. All values
 +equal or above $80 will have bit 7 equal 1,
 +cmp will set C for all values above $80 and
 +thus for this case it will also '​copy'​ bit 7
 +into carry!
 +
 +------------------------------------------
 +ASR        "​Arithmetic Shift Right"
 +    B7C
 +    ror
 +
 +This instruction does a signed divide by 2
 +------------------------------------------
 +
 +Again a beauty in my eyes! I have puzzled
 +many times who to write the on other CPUs
 +well-known ASR instruction,​ but I never
 +seemed to get it implemented without an
 +extra register to use like:
 +    tax
 +    asl
 +    txa
 +    ror
 +or even without a branch (figure that out
 +yourself!).
 +
 +With these two beauties I want to give you
 +an idea of what I mean, and please follow me
 +up!.
 +
 +BONUS. A little routine to clear the screen
 +without erasing the sprite pointers.
 +
 +-----------------------------
 +CLS        "Clear the screen"​
 +    ldx #250
 +    lda #$20
 +clp sta $0400-1,​x ​  ; ​ 0-249
 +    sta $0400+249,x ;250-499
 +    sta $0400+499,x ;500-749
 +    sta $0400+749,x ;750-999
 +    dex
 +    bne clp
 +
 +Clear only the screen
 +----------------------------
 +
 +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 +From: paulvl@python.es.ele.tue.nl (Paul van Loon)
 +Subject: Re: Post your favourite little code too!
 +Date: 20 Oct 1994 12:17:40 GMT
 +
 +-------------------------------------
 +RSL "​Rotate Straight Left"
 +    B7C
 +    rol
 +
 +This instruction does a rotation left
 +through 8 bits (rol does a rotation
 +left through 9 bits, 8 bits of A
 +and 1 bit C)
 +-------------------------------------
 +
 +Another useful instruction,​ for
 +a wraparound rol, e.g. for rotating
 +bytes in characters to simulate
 +parallax scrolling.
 +
 +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 +
 +A reliable way to create a Straight IRQ?
 +
 +Well, this is the way I've always used, because it's reliable, flexible
 +doesn'​t mess up, or set restictions on the display, unlike routines that
 +depend on D011 etc...
 +This one only observes the VIC chip:
 +
 +It's some time since I actually coded a routine of this kind,
 +and I'm writing this off memory, so there might be some errors in the
 +following code.
 +
 +   <​irq is initiated in the usual way, I almost always use FFFE/FFFF instead
 +    of 0314/0315 for interrupt vectors, but the routine should work with
 +    0314/315, but delay timing will be different becouse of the time being
 +    up by the kernal>
 +
 +   <​Set up irq vector to label '​irq1'​ and program desired rasterline with
 +    d012 & $ d011 in the usual way>
 +
 +    <other initiation of program>
 +                ...
 +
 +                jmp mainPrg
 +
 +;​----------- Standard routines for all sharp irqs ----------------
 +
 +sharp           inc $d012                 ;Set interrupt to the next line.
 +                inc $d019                 ;​Ready for new interrupt
 +                                          ;same as lda #1 : sta $d019
 +                sta storeA
 +                lda #<​sharpirq
 +                sta $fffe                 ;​Alter interrupt vector
 +                lda #>​sharpirq
 +                sta $ffff
 +                cli                       ;​Allow new interrupt even if we
 +                                          ;still are in the previos irq call
 +noploop
 +                nop
 +                nop             ; We add nop's here so that the next interrupt
 +                                ; will interrupt while we are executing nop
 +                ...             ; commands. Since nop commands use two cycles
 +                ...             ; the interrupt will at most be delayed 1
 +                ...             ; cycle.
 +                ...             ; I think we needed about 11 nop's to be sure
 +                                ; that execution is interrupted while they are
 +                                ; run. (I'm not sure about this number)
 +
 +                jmp noploop ​    ; Although we are sure that the interrupt will
 +                                ; interrupt before we reach this point, we
 +                                ; add this loop to be on the safe side.
 +                                ; Imagine if the program happened to be frosen
 +                                ; by a carterigde and later restarted while
 +                                ; executing the nop's.
 +
 +
 +sharpirq ​       pla             ; Delete data put to stack by the last
 +                pla             ; interrupt, we don't intend to return from
 +                pla             ; it.
 +                stx storeX
 +                sty storeY
 +
 +                nop             ; Now we only have an uncertainty of 1 cycle
 +                nop             ; as to where the interrupt is.
 +                                ; By waiting until the edge of the current
 +                                ; rasterline we can determine if the interrupt
 +                ...             ; was delayed by one cycle or not.
 +                ...             ; (How many nop's that is required to reach the
 +                ...             ; edge of the rasterline i don't remember.
 +                                ; You'll just have to find it out yourself)
 +                                ; These nop's may of course be exchanged by
 +                                ; equivelent time consuming instructions.
 +
 +                lda $d012       ; get current rasterline
 +                cmp $d012       ; still on same line = was delayed;
 +                bne addCycle ​   ; add 1 cycle if not delayed.
 +addCycle ​                       ; doing a branch jump takes 1 cycle more than
 +                                ; not doing one.
 +
 +                                ; the rastertiming is now '​straight'/​sharp
 +                rts             ; return to routine that cal led sharp
 +
 +
 +endIrq ​                         ; restore a x y
 +storeA ​         = * + 1
 +                lda #0          ; For those who don't like self modifying code
 +storeX ​         = * + 1         ; this can be changed easy.
 +                ldx #0
 +storeY ​         = * + 1
 +                ldy #0
 +                rti             ; Return from interrupt.
 +
 +nextIrq
 +                stx $fffe
 +                sty $ffff
 +                sta $d012
 +                inc $d019       ;or lda #1 : sta $d019 if you prefere
 +                rts
 +
 +;​------------------ The actual interrupt ------------------------------
 +
 +irq1
 +                jsr sharp       ;Make interrupt sharp and store A X Y regs.
 +
 +        <here you put your sharp interrupt dependant code>
 +
 +        <other code that you need executed this interrupt>​
 +
 +                ldx #<​irq<?> ​   ;<?> is the next interrupt that is due
 +                ldy #>​irq<?> ​   ;1 if irq1 is the only interrupt.
 +                lda #<​rasterline for interrupt>​
 +                jsr nextIrq
 +
 +                jmp endIrq
 +
 +;​--------------- Main program ---------------------------------
 +
 +mainPrg
 +                cli             ;​allow interrupt
 +
 +        <wait for space or something>​
 +
 +                sei
 +
 +        <shut everything down and restore what needs to be restored>​
 +
 +                rts             ; Or jmp exitCode
 +
 +*******************************************************************
 +
 +By adding this routine:
 +
 +saver           sta storeA
 +                stx storeX
 +                sty storeY
 +                rts
 +
 +...you can at any time turn on/off the sharping by exchanging 'jsr sharp'
 +and 'jsr saver'​.
 +
 +I hope this is what you were looking for. Sorry for not supplying a
 +complete source, but as I said this is all from memory.
 +
 +PS. My native lanuage is not english and I typed this in a hurry, so sorry
 +for the lousy lanuage / source.
 +
 +Furhermore, ways of getting an rnd.
 +
 +* lda $d012, only in large complex programs with lots of variable execution
 +             times where rnd is only needed once in a while.
 +             ​(Never use in raster interrupts of obvious reasons)
 +
 +* lda $d800     ; The 4 upper bits of mem at area $d800 - $dc00 are completly
 +  lsr           ; unpredictable...
 +  lda $d801
 +  lsr
 +  lda $d802
 +  ...
 +
 +* Read the values from the white noise generator to the SID.
 +  3rd voice set to whitenoise, and read the result.
 +  (sorry don't remember address to read, think it is around $d416-$d41c)
 +
 +These give you _true_ random numbers. It's also possible to create
 +'​random'​ routines that create '​random'​ numbers based on a seed value.
 +
 +Anything unclear? Mail me at s514@ii.uib.no
 +
 +Bye...
 +
 + - Rolf Wilhelm Rasmussen
 +
 + Equal of Eternity
 +
 +===========================================================================
 +</​code>​
 +====== C.S. Bruce Interview ======
 +<​code>​
 +by Craig Taylor (duck@pembvax1.pembroke.edu).
 +
 +The following is an interview of Craig Bruce, author of numerous programs such
 +as ZED, ACE etc for the Commodore 64/128.
 +
 +> What computer experience did you have before the Commodore computers?
 +
 +Very little. ​ I was 14 at the time, in grade nine, and it was December 1982.
 +My Jr. High school had a few CBM 8032s, but I never actually got to touch
 +one.  I took a "mini course"​ on computers and learned a tiny little bit about
 +what computers were like and about BASIC. ​ To give you an idea of how little
 +I learned, I was entirely incapable at the time of figuring out how to
 +increment a variable (X=X+1).
 +
 +> What was your first Commodore computer and why?
 +
 +My first computer was a VIC-20. ​ I had the choice narrowed down to a VIC, a
 +TI99-4A, or a Timex/​Sinclair 1000(?​). ​ (I don't think I had heard of the
 +Ataris or the Apple). ​ I chose the VIC partly because it was related to the
 +computers at school but mostly because it had the most impressive brochure
 +and I had the most information about it.  It was theoretically a Christmas
 +present, but it didn't stay in the box very long.  I paid half of the $400.00
 +price tag and my parents paid the other half.
 +
 +> How did you learn programming on the Commodore? Did experience from other
 +  PC's help?
 +
 +Ahhh, those were the days.  I learned programming from a few sources. ​ The
 +user's guide that came with the VIC was quite helpful, and I read the
 +magazines of the day, mostly Compute!s. ​ I also had a friend who went to high
 +school and used the computers there who knew a thing or two, and two other
 +friends who got VIC-20s soon after me, so we learned from each other.
 +
 +I also took a relatively informal night course that was offered for
 +programming VIC-20s. ​ By the time I took it, though, I had already learned
 +just about everything that the course tought: BASIC. ​ Then, in the last
 +class, the instuctor talked just a little bit about machine langauge, just
 +enough for me to understand what was in the VIC-20 Programmer'​s Reference
 +Guide. ​ I learned 6502 machine language shortly after that.
 +
 +Experience from other PCs didn't really factor into things, since I had no
 +experience with any other PC.  However, when the time came to learn about
 +other computers and other programming languages (in high school and bachelor
 +university),​ I had an enormous advantage over the other students, since I
 +understood so thoroughly how computers worked because of my VIC-20
 +experience.
 +
 +> What other interests, besides hacking on the Commodore, do you have?
 +
 +Not many.  I don't get out much and I have only a handful of friends. ​ I
 +spend most of my time sleeping, watching TV, net surfing, doing school work,
 +and/or hacking on Commodores. ​ Hacking on Commodores is in my blood. ​ While
 +I'm doing these other things, I'm usually thinking about hacking on
 +Commodores. ​ You might say that I'm a sterotypical total computer geek.  I do
 +like biking, though. ​ I bike to school every day.  And music.
 +
 +> What is your feelings on the demise of Commodore?
 +
 +Losing Commodore was a little sad, but as someone said on the newsgroup when
 +Commodore went under, "What has Commodore done for you lately?"​. ​ We
 +8-bitters lost all support from Commodore long before its demise. ​ I
 +certainly don't blame them; 8-bit computers are a thing of the past and there
 +wasn't a big enough market to support a company the size of Commodore.
 +
 +> Do you see anything in the future that signals anything that will extend the
 +  useful lifetime of the Commodore 8-bits?
 +
 +IMHO, there are only two things that 8-bit computers need to survive in the
 +hands of hobbiests indefinitely:​ serious system software and modern hardware
 +peripherals. ​ Some serious system software has begun to surface recently :-),
 +and Creative Micro Designs has been providing modern peripherals for us to
 +use.  New application programs are needed too, but I'm assuming that
 +hobbiests + serious_system_software --> serious_new_application_programs.
 +(Perhaps this is a bit self-serving).
 +
 +Eight-bit computers have two big advantages over bigger PCs: a much lower
 +price and a much higher understandability quotient. ​ Both of these are very
 +important to hobbiests.
 +
 +> Do you feel that with the addition of newer periphials that are gradually
 +  superceeding the CPU's job (REU, RamLink, SwiftLink etc...) that the
 +  Commodore 8-bit standard machine is no longer standard??
 +
 +Indeed, there are lots of options. ​ But I think that this is a good thing.
 +The original Commodores are quite limited, and this modern hardware is needed
 +to allow the Commodores to remain useful in the networked world. ​ An
 +important feature of all of these new products is that you can flip a switch
 +or pull out a cartidge and you're back to your little old standard Commodore.
 +Of course, who really wants to do this.
 +
 +The reason that I have stayed with my little Commodore for all of these years
 +is that I believe that it still has quite enough power (using modern
 +peripherals and expanded memory) to do what I require of it.  For example,
 +it's quite possible to have a nice little 17K text editor that can edit huge
 +files and be very useful. ​ You don't need a multi-megabyte program with all
 +kinds of snazzy features that requires a monsterous machine to run on to do
 +this.  These multi-megabyte programs are simply bloated and poorly designed.
 +
 +> Will there ever be an update to Zed? (a question asked on a lot of the
 +  commericial providers)
 +
 +Yes.  I've been promising this for a long time, but the right time to do this
 +is finally near.
 +
 +> What is the process that you use for writing your programs?
 +
 +I'll start this answer with a Unix-fortune quotation:
 +
 +"Real programmers don't draw flowcharts. ​ Flowcharts are, after all, the
 + ​illiterate'​s form of documentation. ​ Cavemen drew flowcharts; look how
 + much good it did them."
 +
 +For complicated algorithms, I'll sit down write some pseudo-code,​ and I
 +always plan and write out complicated data structures. ​ But other than this,
 +I usually just sit down and write code, after kicking ideas around in my head
 +long enough for me to know what I have to do.
 +
 +> It's been noticed that you have a "​fanatacism"​ about speed in your programs.
 +  Can you elaborate on this?
 +
 +Guilty as charged. ​ As I said above, I despise bloated software that needs a
 +mega-machine to run on fast enough. ​ I like software that is sleek and mean,
 +and I have an axe to grind that little 8-bit Commodore computers offer quite
 +enough computing power for most applications that most people would use them
 +for.  The exceptions are number-crunching,​ huge-data processing, and heavy
 +computation. ​ However, for most interactive programs, an 8-bit processor is
 +quite enough. ​ So, I grind my axe by producing fast programs. ​ Arguably, that
 +effort is sometimes misspent (like in the printing to the screen in ACE -- I
 +still have a few more tricks up my sleeve though...), but I like to go a
 +little too far sometimes to make people go, "Wow! I didn't know this little
 +machine could do that so fast!!" ​ I like to upset the notion that you need a
 +huge machine to get adequate performance. ​ (In fact, sometimes the opposite
 +is true, since programmers assume that they can be extra sloppy when
 +programming for huge machines).
 +
 +As a user, I like crisp responsiveness. ​ This is a feature of personal
 +computers that can sometimes be absent on big multi-user virtual-memory
 +machines.
 +
 +I also have a big thing against backwards compatibility ("​hysterical
 +raisins"​). This is a significant cause of software bloatedness. ​ This is one
 +reason that ACE, for example, was designed from scratch rather then with the
 +pre-set limitation that all BASIC-compatible programs should run with it (a
 +la CS-DOS).
 +
 +> Is there anything that you find particularly useful / handy about the
 +  Commodore'​s architecture?​
 +
 +Yeah, it's simple.
 +
 +> And the corallary: Is there anything particularly annoying?
 +
 +Yeah, it's limited.
 +
 +> What is currently in the works / planned??
 +
 +My Commodore job queue looks like the following:
 +
 +1. Update my Unix VBM file filter. ​ Make it produce a new format of VBM files
 +   with run-length encoding compression. ​ Investigate LZW(?) compression.
 +
 +2. Work on ACE release #13: Internal cleanup. ​ Reorganize the internal memory
 +   ​usage,​ add features to the command shell, clean up memory and device
 +   ​management inside the kernel, update the VBM program, add a SwiftLink
 +   ​device driver, make a simple glass-tty terminal program.
 +
 +3. Develop a new portable archiver format and write a C program for Unix,
 +   "​.car"​ format.
 +
 +4. Write my next article for C= Hacking, which will be about the detailed
 +   ​design of a distributed multitasking microkernel operating system for
 +   the C128.  This article will also include a minimal multitasking
 +   ​implementation.
 +
 +5. Work on ACE release #14: Port Zed to ACE.  Get the basic editing features
 +   ​going.
 +
 +6. Work on ACE release #15: Finish the ACE assembler. ​ Add the file-inclusion,​
 +   ​conditional and macro assembly features. ​ Make it accept more dyadic
 +   ​operators in expressions,​ fix the label typing, make it generate
 +   ​relocatable executable code modules, and make it handle modular compilation
 +   ​("​.o"​ files).
 +
 +7. Work on ACE release #16: Archiving. ​ Update the "​bcode"​ and "​unbcode"​
 +   ​programs to support uucode, nucode and hexcode formats. ​ Toss the old
 +   "​uuencode"​ and "​uudecode"​ programs. ​ Implement "​car"​ and "​uncar"​ programs.
 +   Look into "​zip"​ format.
 +
 +8. Start on BOS, the distributed multitasking microkernel operating system
 +   for the 128.
 +
 +(Actually, some of these things will be done by the time that C= Hacking
 + comes out).
 +
 +Keep on Hackin'​!
 +
 +===========================================================================
 +</​code>​
 +====== Aligning 1541 Drives ======
 +<​code>​
 +by Ward Shrake (taken from comp.sys.cbm)
 +
 +A discussion regarding Commodore 1541 disk drive alignment procedures, with
 +suggestions.
 +
 +Background information.
 +
 +The best way I've ever seen to consistently and reliably get a 1541 disk
 +drive aligned perfectly, was caused by copy protection. It is sort of appropo
 +that copy protection, which usually causes the "head knock" problem that puts
 +drives out of alignment in the first place, should also be able to solve the
 +problem it created.
 +
 +An older version of a disk utility program, ("​Disector"​ v3.0, as I remember
 +it), had copy protection that would not let you load the disk up unless your
 +disk alignment was perfect. While initially loading itself, it would search
 +and search, never quitting, until it found what it was looking for, exactly
 +where it was looking for it. It would stay in an endless loop, searching
 +forever, never making it to so far as the first screen. This essentially
 +"​locked up" the computer, if the program thought the disk it was on was an
 +illegal copy.
 +
 +This quickly became the most hassle-free,​ no-worry alignment program I've
 +ever seen. I have seen and used most of the others; this method beat them
 +all, no contest, in my opinion.
 +
 +The other programs, the ones made for aligning your drive, ​ never
 +consistently worked acceptably well, in my experience. Other technical users
 +apparently feel the same way about them, as the "​General FAQ, v2.1" on
 +Commodores points out. They would work OK part of the time, or on part of the
 +drives you tried, but not all, I found. Or they would say you now had a
 +perfectly-aligned drive, but some difficult copy protection schemes would
 +still not load and run on the newly tuned-up drive friend. A friend of mine,
 +now deceased, once had a drive no alignment program could fix. We tried
 +everything we could find. After aligning it with a given method or program,
 +some programs would load that would not load before, but others would now no
 +longer work, that used to work before. All in all, it was very frustrating,​
 +and the general feeling was that there has to be a better, easier, more
 +reliable way to do this.
 +
 +All an alignment program has to do, is to make sure that when the disk drive
 +says it is precisely at a given track'​s physical location, that it is really
 +there, centered on that track.
 +
 +There are other Commodore adjustments,​ but alignment seems to be, by far, the
 +most common problem. Disk drive rotational speed can be adjusted, but it
 +usually is not the problem. In fact, I've seen more than one drive, that when
 +adjusted to read a program-reported "​perfect"​ 300 rpm rotation speed, they
 +quit reading disks; requiring speed to be set at a reported 310 rpm, to work
 +again. The end stop gap can also be adjusted, but I've never seen it be the
 +real culprit with a non-working disk drive. Your experience may vary, of
 +course, but I've always found that it is best to concentrate on alignment
 +first, then fool around with the other adjustments ONLY after alignment is
 +truly corrected, and only if it still refuses to work properly.
 +
 +Once alignment is corrected, there are methods available to insure that it
 +stays that way. For instance, you can have the stepper motor'​s pulley
 +mechanically pinned to its shaft, instead of merely relying on the factory'​s
 +interference fit to hold it. Commodore 1541 drives were made to be self-
 +aligning, apparently, which would be fine if "head knocking"​ protection
 +schemes were not around. Since they are, the pulley should, ideally, not be
 +allowed to turn on its shaft, which is what causes misalignment problems.
 +
 +How I used to align 1541 disk drives....
 +
 +To precisely align a given 1541 disk drive, I used the old, unbroken copy I
 +had of Disector (v3.0, I think), and followed these steps. ​ With power to the
 +drive off an disconnected, ​ you first took off the upper and lower halves of
 +the outer plastic casing of the drive. This exposed the electronics inside.
 +You then found and loosened (but not removed!) the two stepper motor mounting
 +screws, which are on the underside of the disk drive'​s internal mechanisms.
 +After that, you hooked the power cable back up, and hooked the drive to the
 +computer like it normally is.
 +
 +Once you've done this, you set the drive up on one side, so that you can
 +(carefully!) reach into the mechanism, to physically rotate the stepper
 +motor, which would normally be on the bottom of the drive. You type in the
 +program'​s loading instructions on the computer, and you then wait until the
 +screen went black (copy protection searching for certain info on the
 +diskette). This is where  the program ​ "locks up," with the unaligned drive.
 +
 +Once the program is loading, but stuck and unable to find what it wants, you
 +reach into the mechanism, very slowly and carefully, turning the stepper
 +motor a slight bit in either direction, and stopping. Tiny adjustments are a
 +lot; don't overdo it. Be patient; don't go too fast, or move it too much! You
 +watch the screen carefully, and listen to the drive'​s sounds.
 +
 +When you have rotated the stepper motor to the proper place, the sounds and
 +the screen will act a little different, perhaps only slightly so. Wait a
 +second, not moving the stepper motor at all. When you are right on,
 +alignment-wise,​ the program will find what it is looking for, and the
 +program'​s main menu will appear.
 +
 +Once the main menu has come onto the screen, you have a perfectly aligned
 +drive. Then you have to retighten the stepper mounting screws, being very
 +careful not to accidentally move the motor in the process. Hold the motor
 +firmly while retightening both screws in small steps, alternating back and
 +forth between them until they are both tight. The rotational force of the
 +screws turning, forces the motor to move some, so watch for it.
 +
 +With this method, using a specially-prepared disk, I always got perfect
 +results; everything would load, every time, from then on. (Assuming that the
 +disk was formatted with a good drive to begin with; any disks you made
 +recently, on your badly-aligned drive, may not load after the alignment
 +procedure. ​ Transfer the info on these disks, to a second, known-good drive,
 +before you do this procedure. This is normal, however, no matter what method
 +you use to align a bad drive.)
 +
 +Here's the problem with this method...
 +
 +This procedure only works with a special disk, one that is no longer
 +available. With the special disk, alignment is quick, hassle-free,​ and it
 +always gave excellent, reliable results the first time around. Without the
 +"​perfect"​ disk, this procedure is worthless. This is obviously a problem,
 +since the method relies on a disk that is no longer available to the public.
 +You can't make your own, because you don't know if the disk drives you are
 +using, are truly perfect to start with! Disks made by users, on Commodore
 +equipment, never worked; they just matched your drive'​s alignment to that of
 +someone else's equipment, which may be borderline bad to start with.
 +
 +Here's what I suggest to solve this...
 +
 +Your mission, should some hot programmer out there choose to accept it, is to
 +create a program that will create a "​special"​ disk, and a
 +Commodore-compatible program to try to read that special disk.
 +
 +Ideally, the Commodore-compatible reading program would be short and simple
 +enough to fit inside 8k of memory, so it could fit on a cartridge. This would
 +allow it to work, even if a user's disk drive would not load programs
 +anymore. It could still be stored on a diskette, too, with a little planning.
 +
 +Theoretically,​ once you had the specially-formatted diskette, and the program
 +on cartridge, you would only need a screwdriver to take the drive apart, and
 +a Commodore microcomputer to run the program on. No other special tools would
 +be needed, and very little technical knowledge would be required; just some
 +general safety tips, because you are working around sensitive electronic
 +parts, with wall current coming into the drive itself, at least on older
 +1541'​s.
 +
 +Why should a programmer go to all the trouble?
 +
 +I'm sure there are a lot of people out there who could use this, if some hot
 +programmer should decide to write it, and make it available to the rest of
 +us. There are always programmers out there, somewhere, eager to show off
 +their computer skills, and their creativity. It is one of the things that
 +makes the computer community so great in the first place. (If people out
 +there can write IBM-to-Commodore disk file readers, this should be a breeze!)
 +
 +Techies should appreciate it as a great, reliable and cheap way to align
 +troublesome disk drives, and those people with a C64 in a closet would sure
 +appreciate their technical buddies getting their dead systems going again!
 +
 +Description of what I have in mind, as to how it should work.
 +
 +You need a Commodore computer (the 64 is most popular), one 1541 disk drive
 +that needs alignment (or that you want to check), a screwdriver to open the
 +drive up, a specially-prepared disk used only for alignment purposes, and a
 +computer program that would run on the Commodore that would look at and
 +analyze the information that is on the specially-prepared diskette, as the
 +computer program tries to read it.
 +
 +OK. Here's where it gets cute.
 +
 +The problem with most disk alignment methods, as I see it, is that it relies
 +totally on technology that the Commodore has available; trying to create a
 +special disk on a 1541, I just don't see as being realistic, or the best way
 +to do it. The 1541 has many limitations,​ compared to some other disk drives
 +which operate on other computer platforms. Don't get me wrong; I love
 +Commodore computers, and have for years. But, realistically,​ the 5.25 inch
 +drives found in say an IBM machine, are just plain better in many ways than
 +the 1541. They are made to hold much more information,​ and to do that, they
 +have to be much more precise in doing so than the 1541 was ever designed to
 +be.
 +
 +If a person were to do this, I would suggest that they write an IBM program
 +that would use a high density, 1.2 megabyte capacity, 5.25-inch type of disk
 +drive to create the special diskettes, which the 1541 would later read.
 +
 +Doing this would allow the creation of very thin tracks on the diskette'​s
 +surface, spaced closely together. This would, within the limitations of the
 +1541's read head, allow the Commodore to "​see"​ precisely where it currently
 +was, to one side or the other of some "​centered"​ position. The advantage of
 +thin tracks, widthwise, is that the read head won't see them at all,
 +reliably, unless you are exactly, perfectly right on top of them. Another
 +advantage to this, again within the limitations of the 1541's read head
 +(whatever that may be), is that left or right of center, the head would
 +likely pick up the next track over, letting you know you were off by a
 +certain amount automatically.
 +
 +I hope I'm making myself clear, in my explanation of this. If I am not, Email
 +me with your questions, and I'll try to answer them better, and/or update
 +this file, to entice someone else to work on this. I really would like to see
 +it done. (Current Email address, as of Sep 94: wardshrake@aol.com on the
 +Internet, or just WardShrake on AOL. Will soon have a Compuserve Email
 +address, too: I'll be user 75207,1005 there, or 75207.1005@compuserve.com on
 +the Internet.)
 +
 +Anyway, let's continue. With the IBM creating a specially-made disk just for
 +this one purpose, you would not even have to worry about following any
 +standard formatting procedures. No user-stored data would ever be written to
 +the diskette, so standard sectoring could be safely ignored. You could create
 +any signal or sectoring scheme you like, as long as the IBM could create it,
 +and the Commodore could read it; and you'd be writing both programs, anyway,
 +making this easier to insure, right?
 +
 +I can hear some die-hard Commodore users saying, "I hate IBM'​s"​ or "I don't
 +even have an IBM" or some such. Fine. Not a problem. If all the
 +IBM-compatible program did was to create a special floppy disk, once, then
 +quit, you would not even need to OWN an IBM, you'd just need to be able to
 +USE one for a few minutes.
 +
 +Even if you don't have access to one at work, and don't know of anyone who
 +has one to lend you, I will stick with this suggestion, because I know that
 +some businesses that make photocopies often also rent IBM's and Mac's on an
 +hourly basis, for very little money. My local Kinko'​s copy center rents them
 +both at $10.00 an hour. You would only need it for a few minutes or so.
 +
 +The diskette-creation program would only need a few minutes to run, to make
 +up a special disk, so you'd only be paying for a good quality, blank high
 +density floppy, and ten or fifteen minutes of rental time, tops. The copy
 +center person may even be able to start up the floppy-based IBM program for
 +you, if you don't know how to do it yourself. That should come to $5.00 or
 +less, even if you don't own or normally have access to an IBM compatible
 +computer! You can't beat that, for a utility to align equipment!
 +
 +OK. In overview, you'd need to use an IBM-compatible computer, just long
 +enough to load an IBM-compatible program which would create one special,
 +5.25" diskette, perhaps on a high density floppy. You would then open up your
 +Commodore drive'​s case, and start up a special program on your Commodore 64,
 +to read the created diskette. (Again, an 8k Commodore program would fit very
 +easily on a cartridge, for easiest loading and running.)
 +
 +While the computer and drive were running, you would (very carefully, and
 +observing safety precautions) loosen the stepper motor'​s screws, and slowly
 +turn the motor clockwise and counter-clockwise,​ until the Commodore program'​s
 +screen info told you that you were exactly where you should be, right over
 +the proper track. Not to the left or right of it, but in perfect alignment.
 +
 +Because the Commodore disk-reading program would be "​on"​ constantly, and
 +reporting any small changes to you via information on your screen, you would
 +only have to take a few minutes of fiddling, doing a simple, non-technical
 +turning of the stepper motor, to get the drive aligned. The two computer
 +programs that would make up this package would be doing most of the work.
 +
 +I imagine a drive could be perfectly aligned, and back in running order, in
 +fifteen minutes or less. Five, if you paid attention to the process, and had
 +some practice before. Remember, this is based on an alignment procedure I
 +really used to do, using a heavily-protected diskette, so I am extrapolating
 +from my personal experiences,​ even though I'm talking about a theory here.
 +
 +I don't see where there would be any easier, simpler method of doing a disk
 +alignment. The user wouldn'​t even have to know a thing about tracks and
 +sectors; they would just loosen two screws, following some instructions,​ and
 +turn the motor. What could be any easier?
 +
 +The program could, if it was really creative and well-done, tell them to
 +rotate the motor clockwise or counter-clockwise (as they face it), to dial
 +the motor precisely in. Tracks to either side of an arbitrary (track 18?)
 +center position would say to go one way, tracks on the other would say the
 +reverse. When you turn it too far one way, it would reverse its instructions
 +to you; you would know you were very close then. When you were "right on,"
 +the program would tell you so. You'd lock the screws down, carefully, and as
 +long as you hadn't jiggled the motor when you tightened it back down, you
 +would be all done!
 +
 +How much easier could it be, right? (On the final user, that is!)
 +
 +If anyone is interested in doing this, or goes out and does it, please let me
 +know via Email. I'd like to hear about it. Again, it would be something
 +possible, useful, and a really neat trick. I know there are people out there
 +that program on both the IBM and the Commodore; the various cross-reading
 +programs attest to that, well enough!
 +
 +Ward Shrake
 +Covina, California
 +
 +==================================================================---END---===
 +</​code>​
magazines/chacking9.txt ยท Last modified: 2015-04-17 04:34 (external edit)