Jump to content
IGNORED

New GUI for the Atari 8-bit


flashjazzcat

Recommended Posts

may be I should publish the BOSS-X 10.4 W.I.P. ... it's been designed to work with Atari-DOS, MyDOS, and BeWe-DOS/SpartaDOS-X from the ground up, but it's not a finished integrated Desktop-System, it's just a framework ...

it also has some critical errors which prevents loading the Device-Driver (ST-Mouse or Joystick).

Link to comment
Share on other sites

may be I should publish the BOSS-X 10.4 W.I.P. ... it's been designed to work with Atari-DOS, MyDOS, and BeWe-DOS/SpartaDOS-X from the ground up, but it's not a finished integrated Desktop-System, it's just a framework ...

it also has some critical errors which prevents loading the Device-Driver (ST-Mouse or Joystick).

I don't think you'll meet with any opposition to that idea. :)

Link to comment
Share on other sites

How do I set up SpartaDOS-X for running with the original version of Turbo-BASIC?

 

I remember, I had it running on my real Atari 800XL with RAM-Disk and SDX on cartridge. But unfortunately that cart doesn't work as it should, so I can't use it.

 

Now, trying this on an Emulator, I cannot get Turbo-BASIC to run (Atari800MacX, 1088kB, SpartaDOS-X 4.42 on Card for Emulators).

 

If this isn't possible, I have to run it on BeWe-DOS, which is slower but uses a SpartaDOS-compatible file-system.

Link to comment
Share on other sites

How do I set up SpartaDOS-X for running with the original version of Turbo-BASIC?

 

I remember, I had it running on my real Atari 800XL with RAM-Disk and SDX on cartridge. But unfortunately that cart doesn't work as it should, so I can't use it.

 

Now, trying this on an Emulator, I cannot get Turbo-BASIC to run (Atari800MacX, 1088kB, SpartaDOS-X 4.42 on Card for Emulators).

 

If this isn't possible, I have to run it on BeWe-DOS, which is slower but uses a SpartaDOS-compatible file-system.

 

The SpartaDOS X Reference Manual has a section on using Turbo BASIC XL with SpartaDOS X

See Appendix C in the SpartaDOS X Reference Manual

 

I know you said "original version of Turbo-BASIC" but thought this may still be helpful.

Link to comment
Share on other sites

Menus are taking a lot longer than I expected, mainly since there's provision for multi-level cascading (which should be working in a day or so). It's very fiddly.

 

post-21964-129512035348_thumb.png

 

Shortcut keys are now right aligned, and the mouse pointer no longer "sticks" when moving along the menu bar if the menus are open. I'll probably implement a mouse hovering pause eventually, so the menus wait a half second or so before they open.

 

guidemo.xex

 

Don't click outside of an open menu yet! ;)

 

This is clearly going to be a huge project, but the API should offer great scope for developers. I just wish there were more hours in the day.

 

Paul: I'll make a version using the alternative system font tomorrow.

Link to comment
Share on other sites

I've taken to re-watching "The Mother of All Demos" several times, now, and there are just so many great ideas in NLS, that never made it out of the Lab.

 

Thanks for that link. Fascinating stuff.

 

You're welcome. You will find a lot of fascinating stuff in that system. Here's a great page, filled with a lot of Augment Documentation. I hope that others get really inspired by Augment, there's so much cool stuff in it, that would be great to use... If only we could use it!

 

 

Link to comment
Share on other sites

I have been thinking about how to implement some features from NLS/Augment on the Atari... particularly the Outline Processor, that allows a user to be able to create collapsible, hierarchical Outline-form Lists, within a document, in a text-editing program.  

 

These are sort of like modifiable drop-down menus that are created as you are typing, and activated by a mouse click.

 

I've taken to re-watching "The Mother of All Demos" several times, now, and there are just so many great ideas in NLS, that never made it out of the Lab. All of the UI metaphors on the SDS 940 are things that an Atari 8-Bit could handle.  

 

Can you give the movie a watch? It may very well give you some great new ideas for "The Last Word", and this GUI. There were so many good ideas... I look at it & just go, "Wow, they had THIS in 1968?!?!", then say, "WHY don't we have this functionality NOW?".

Well, I came downstairs at 3am because my cough was keeping my wife awake and watched The 1968 Demo and I was quite dumbfounded. It really does make you wonder why it took another 25 years or more for many of these features to find their way into mainstream software (although it seems NLS/Augment's downfall was that it was rather difficult to learn). The outline processor is immediately impressive. I don't think Microsoft Word's outline view has all that functionality to this day. Absolutely amazing.

 

I'm sure the Atari could handle some of this stuff. I seem to recall an outline and/or hyperlink text processor on the 8-bit; perhaps someone can remind me what it was.

 

Anyway, thanks for bringing that demo to my attention. It's truly inspirational. If you come up with any good ideas for the outline processor, let me know. Perhaps I could offer some help with the text editing framework.

 

Can you explain how you will be designing the event handler, in technical terms?

Of course. Since I've been too sick with flu to do anything other than sit at the computer this past week, I've been cramming on GUI texts. A good resource is the Hitchhiker's Guide to GEOS found on this page. Since GEOS is a rather powerful (although limited) GUI implementation on a 6502, it made sense to me to try and steal some ideas. GEOS is superbly written and I think the API of the new Atari GUI will be similar to that of GEOS in many respects. Of course I also downloaded heaps of formal texts over the past few months, and more recently the source code of small-scale GUIs on the PC. Dan Winslow has also provided a lot of helpful guidelines, explanations and suggestions.

 

Initially, I was going to gather events in the deferred VBI (just after rendering the mouse pointer in the same interrupt), and pipe them into a queue from which then event handler would then pull events in the main loop. However, simplicity being the watchword, I soon encountered difficulties in processing mouse clicks and user-input states from inside an interrupt, so I moved all the polling into the main-line event handler routine. I may augment this later when it comes to polling the keyboard, but it works well at the moment. Since the mouse sampling and pointer rendering all reliably happens every jiffy, the "get event" routine simply "blocks" and waits for mouse clicks/double-clicks/drags/menu-bar hovering in real-time. It then looks through the visible event regions for all the clickable objects on the screen, and calls the event routine for the relevant object. Mouse actions in other areas of the application workspace will be returned to the application.

 

While the menu system is pretty straight forward, the next major job is coding up the "touch" areas for objects in a way that the event handler can search very quickly when something is clicked. Overlapping objects (may) need consideration, and the dialogue handler will probably require separate tables, since everything outside of the dialogue box will be out of bounds anyway. But the whole thing (such as it is at the moment) is really simple, and works pretty fast. To be honest, optimized raster graphics routines quick enough to work in real time seem more challenging than the event handler right now. The basics are already nailed down and are fast, but I won't know just how practical any of this is until I get a working text editor running which doesn't take five seconds to refresh the screen.

 

Another challenge will be the dialogue handler, but fortunately I learned a lot from writing the text-mode GUI. Scroll-bars will be a pain when attached to drop-lists; they won't be seen as controls in themselves in that context, but simply as a means of returning a vertical offset (transparently) to the list control.

 

Whether I'll run into trouble down the line with the simplistic event handler model, I don't know. If I have to change my mind later on and buffer all the mouse activity, it'll be a pain, but perfectly doable with a bit of thought.

...

 

Glad it helped you get through and evening with a cold... being sick is no fun.

 

While I've followed "The Last Word" threads here, for quite some time, I had never used it. After downloading it, I must commend you on an excellent, well-thought-out piece of software! ...& the Manual is GREAT! very classy work! Excellent attention to detail, beautiful layout, very logical, & complete. You, sir are a one-man army! Fabulous job.

 

I spent a number of days thinking about how to implement the Outline Processor. It would require a great deal of work, to do it from scratch. In all honesty, I think that you are in a better position to be able to implement it, directly into "The Last Word". Specifically, because you already have a fully functional editor, with all of it's niceties, & you already have the "Bookmark Feature" in the code, & you have already coded drop-down menus for the GUI. I mean, you basically have it all, already, you just need to put a few pieces together creatively, and you will have a completely unique word processor, that people, even outside of the Atari community, would be interested in using, because of the historically significant NLS-inspired outline processor.

 

& no, Micro$oft Word only creates an Automatic Outline form, with no collapsibility. 

 

I really think that Collapsibility is the Key Thing. It offers a way to really be able to streamline what you are working on.

 

Aside from lists, it would be great for use when programming... you could easily have procedures & functions collapse or expand, right in the editor... it would be awesome.

 

Here is a link to the Augment Documentation. It fully explains exactly how the system works. You will also find descriptions of treating documents like nodes, here, in the Hyperbola Manual

 

If you are up for trying to make an outline processor work in The Last Word, I would be happy to brainstorm with you, regarding Collapsibility, Expansion, and disappearing text.

 

Ah, yes, GEOS... I remember when my C64 friend had showed that to me, when it came out, back in the day. I was very impressed that the C64 could pull it off. Cool collection of code... you are definitely on the right track, studying that one!

 

Hope that you're feeling better. You are doing amazing stuff with this GUI!

Link to comment
Share on other sites

...guidemo.xex...

Looks good already.

 

However, one question: Do you make use of a ROR(LSR) / ROL(ASL) lookup table? Using it might speed up the "textplot" alike routines for printing fonts in gfx. Unrolling the textplot routines might be another way to speed-it-up.

Edited by analmux
Link to comment
Share on other sites

Feel free to PM me, for any specifics.

Thanks! icon_smile.gif

 

The collapsibility in the outline processor would make it a pretty unique tool. I agree it would be an absolutely superb program text editor. When I get around to looking at that project, we can chat about hidden text, etc. It should be interesting to try and work it into LW's non-linear buffer model. The program already makes healthy use of pointers to gain speed, so I imagine extending that concept somehow to skip large chunks of text would be one way to proceed.

 

Thanks also for the links: more interesting reading.

 

...one question: Do you make use of a ROR(LSR) / ROL(ASL) lookup table? Using it might speed up the "textplot" alike routines for printing fonts in gfx. Unrolling the textplot routines might be another way to speed-it-up.

Good question. All the masking is handled using lookup tables rather than bit shifts. For example:

 

ldx char
lda widthtable,x
tax
lda bitmasks,x

...

bitmasks:
.byte %10000000
.byte %11000000
.byte %11100000
.byte %11110000
.byte %11111000
.byte %11111100
.byte %11111110
.byte %11111111

 

Similarly, when dealing with vertical lines:

 

ldx bit_offset
lda bit_table,x

...

bit_table:
.byte %10000000
.byte %01000000
.byte %00100000
.byte %00010000
.byte %00001000
.byte %00000100
.byte %00000010
.byte %00000001

 

So, with line drawing and block screen copying, etc, there are no bit shifts at all. However, the actual bytes of font data still get shifted and rolled into position across the two bytes of screen RAM. I long ago realized (when coding The Last Word) that an ideal solution would be a complete lookup table for all possible (i.e. 255) bit patterns in a byte, shifted right or left by N places. Unfortunately I was dumbstruck by the potential size of such a table. Of course, there'd be some redundancy which could be used: for example, $08 is $10 shifted right 1 place, and $20 shifted right 2 places, etc.

 

If there's some practical way to code up such a table, it would doubtless save a few cycles. As for loop unrolling, each iteration of the character plot routine is quite lengthy, having to account for underlining, boldface, etc. Also, there'll eventually be a variable number of iterations (depending on the point size of the font). It's possible a super-streamlined version of the font renderer could be used for the menus (which use a fixed point size), but looking at the code, I don't think the efficiency saving would be that dramatic. Getting rid of the remaining bit shifts would be the real killer.

Edited by flashjazzcat
Link to comment
Share on other sites

Menus are taking a lot longer than I expected, mainly since there's provision for multi-level cascading (which should be working in a day or so). It's very fiddly.

 

post-21964-129512035348_thumb.png

 

Shortcut keys are now right aligned, and the mouse pointer no longer "sticks" when moving along the menu bar if the menus are open. I'll probably implement a mouse hovering pause eventually, so the menus wait a half second or so before they open.

 

guidemo.xex

 

Don't click outside of an open menu yet! ;)

 

This is clearly going to be a huge project, but the API should offer great scope for developers. I just wish there were more hours in the day.

 

Paul: I'll make a version using the alternative system font tomorrow.

 

A File Manager to use (and manage) myIde Drives (e.g Atarimax MyIde+Flash) would be a kick a*s tool... Your menu looks so perfect for The A8

Link to comment
Share on other sites

A File Manager to use (and manage) myIde Drives (e.g Atarimax MyIde+Flash) would be a kick a*s tool...

It should work with any SIO-legal drives, but SpartaDOS X will naturally offer the most power (one of the first developmental apps will be a version of the FDISK utility for the SDX MyIDE driver).

 

The pretty menus are nice, but it's time for some hard work now before things go any further: i.e. dynamic a memory manager, proper structures for all the GUI objects, etc. icon_frown.gif

 

It's becoming pretty obvious that a 130XE will be the minimum requirement for practical usability. I figure the stack/heap will go in one 16K bank, icons/bitmaps/other resources in another bank, and fonts in third bank (and occupying several banks if they are available, thus increasing the amount of fonts which can be resident at a given time). The optimal configuration would be to have the GUI core code on a cartridge, occupying one or two 8K banks. The screen display could be in low RAM (below the banking window, at $2000), leaving $8000-$A000 shared between a small resident, RAM-based portion of the GUI library and the application's code. An application can also occupy the 16K banked region, but if it wants to keep its data in extended RAM, it will naturally need to access it via code in the $8000-$A000 area.

 

None of that's cast in stone, but it's something to work with.

Link to comment
Share on other sites

A File Manager to use (and manage) myIde Drives (e.g Atarimax MyIde+Flash) would be a kick a*s tool...

It's becoming pretty obvious that a 130XE will be the minimum requirement for practical usability. I figure the stack/heap will go in one 16K bank, icons/bitmaps/other resources in another bank, and fonts in third bank (and occupying several banks if they are available, thus increasing the amount of fonts which can be resident at a given time). The optimal configuration would be to have the GUI core code on a cartridge, occupying one or two 8K banks.

 

I'm not sure about other add-ons, but if I use the cartridge for MyIde, that would be out of the question. I Remember Steve from AtariMax telling me that If I had the 32-in-1 OS already inside, I couldn't have my internal MyIde.

Now, I hope with vbxe plus 1MB Ultimate , I'm sure people will have more than enough to run... or at least 256kb. I only have 128kb as of now and waiting on my vbxe from candle.

 

Maybe offtopic, but the one add-on that would be nice is a network card... but of course, via the sio2usb from AtariMax I could emulate the connection (I haven't ever done that as of yet) and I'm sure I can emulate the MyIDE as well... then your cartridge idea would be perfect.

Link to comment
Share on other sites

I'm not sure about other add-ons, but if I use the cartridge for MyIde, that would be out of the question. I Remember Steve from AtariMax telling me that If I had the 32-in-1 OS already inside, I couldn't have my internal MyIde.

Now, I hope with vbxe plus 1MB Ultimate , I'm sure people will have more than enough to run... or at least 256kb. I only have 128kb as of now and waiting on my vbxe from candle.

The MyIDE solution is limiting in that respect. A MyIDE/Flash cart is a partial solution (you'd flash the cart with the GUI), but only if you want to use SpartaDOS and have IntSDX (or you have an external IDE ROM inside the machine). It gets pretty complicated.

 

Another option is to run the GUI in the Shadow RAM and temporarily stash the code in an extended bank or dump it to disk when some non-GUI app wants to use the same space. Yet another solution is to run the GUI directly out of an extended bank, although this creates enormous difficulties when the core code wants to use extended banks for font/bitmap/heap/stack storage (which it is likely to do with great frequency).

Link to comment
Share on other sites

...

...one question: Do you make use of a ROR(LSR) / ROL(ASL) lookup table? Using it might speed up the "textplot" alike routines for printing fonts in gfx. Unrolling the textplot routines might be another way to speed-it-up.

Good question. All the masking is handled using lookup tables rather than bit shifts. For example:

 

...

 

Similarly, when dealing with vertical lines:

 

...

 

So, with line drawing and block screen copying, etc, there are no bit shifts at all. However, the actual bytes of font data still get shifted and rolled into position across the two bytes of screen RAM. I long ago realized (when coding The Last Word) that an ideal solution would be a complete lookup table for all possible (i.e. 255) bit patterns in a byte, shifted right or left by N places. Unfortunately I was dumbstruck by the potential size of such a table. Of course, there'd be some redundancy which could be used: for example, $08 is $10 shifted right 1 place, and $20 shifted right 2 places, etc.

Yes, a full table would take 2kB (or 7*256 (= 1792) bytes, as the trivial shift wouldn't need to be computed).

 

OK, I just did some thinking. There might be a few solutions:

 

 

• (1)

 

I assume you're already restricted to 6-bit font width, i.e. there are no symbols wider than 6 bits in the horizontal direction. So, you'd not need a full 256-size lookup table; Only 64. Then the trivial "no shift" wouldn't need a table, so 7 steps needed. Then you're done with 7*64 = 448 bytes.

 

 

• (2)

 

Restrict to only even displacements (I did this myself long ago). Then only 3 steps are needed:

 

- Shift 0 pixels to the left: trivial, thus no table needed.

- Shift 2,4 or 6 pixels to the left, so only 3 tables needed in total.

 

Combining this with solution 1: You'll only need 192 bytes of self-ROR/ROL lookup table. Here self-ROR/ROL is supposed to mean REAL bit rotation of internal bits of a byte. No carry flag involved.

 

....however, this might restrict the desired horizontal width, of each of the symbols (including the blank area) in the font, to even values.

 

 

• (3)

 

Allow a double-step lookup procedure. Then you shouldn't restrict to 64 bytes, but keep the full 256 bytes length. But, only a maximum of 3 tables is needed. Then there's 8 possible choices out of 35 "ways" to choose an ordered trio of distinct numbers out of 7.

 

I checked it, and it's possible to have single-step lookup tables of f.e.

 

1,2,5 bit steps to the left
1,3,4 bit steps to the left
1,5,6 bit steps to the left
2,3,7 bit steps to the left
3,4,5 bit steps to the left
3,6,7 bit steps to the left
4,5,6 bit steps to the left
4,5,7 bit steps to the left

 

(there's a pairwise "mirror"-duality here)

 

So, choose one of these 8 options, f.e. the first option. Then you'd only need to rotate (by self-ROL/ROR) ONE TIME if you need to rotate 1, 2 or 5 bits to the left. Then, in this case:

 

3 bit steps = double step of lookup table 1 & 2

4 bit steps = double step of lookup table 2 with itself

6 bit steps = double step of lookup table 1 & 5

7 bit steps = double step of lookup table 2 & 5

 

Thus

 

If shift of 0 is needed: no action.
If shift is 1: use single step lookup table.
If shift is 2: use single step lookup table.
If shift is 3: do lookup two times (first table of 1 and then of 2 (or vice versa  )).
If shift is 4: do lookup two times (table of 2 repeated 2 times).
If shift is 5: use single step lookup table.
If shift is 6: do lookup two times (first table of 1 and then of 5).
If shift is 7: do lookup two times (first table of 2 and then of 5).

 

Then you can use a double step indexed lookup procedure like this, for example for the 6 bit shift:

 

 ldx #value to shift
ldy shift_table_1,x
lda shift_table_5,y

 

OK, this might be some intermediate solution: less memory usage, somewhat less CPU-time needed.

 

 

 

As for loop unrolling, each iteration of the character plot routine is quite lengthy, having to account for underlining, boldface, etc.

Then I'll take back my advice on that. Then I'd try speeding-it-up using lookup tables.

Link to comment
Share on other sites

Hmmm... I had to re-read that several times before I understood it. icon_smile.gif Very clever ideas...

 

1) We're not strictly limited to 6 bit characters, although no character in the system font is likely to exceed 7 bits (for example, the "M" and "m" in the bold system font are both 7 bits wide). No matter, though: I'd be perfectly happy to devote 1792 bytes to lookup tables if it meant a drastic performance increase). However, there'll be support later for 16 and 24 bit wide characters...

 

2) No-go, since the granularity for the proportional characters needs to be single pixel.

 

3) Nice! Boiling the whole thing down into 1, 2, and 5 bit shifts is extremely nifty. I don't understand the pairwise mirror duality (you'll have to explain that one), but I do grasp what's happening - ultimately - with the two-step lookup. However, a couple of issues present themselves:

 

i) The shift value (say "pixels") is computed as the modulus of "X" divided by 8. This value is natually the value by which I need to shift (right) to get the character data properly positioned in the first byte. However, how might one efficiently choose the right "path" (i.e. whichever lookup/combination lookup) according to the value "pixels" without further computation and branching overhead?

 

ii) The second big problem is that probably half the time, the right-shifted character data spills over into the high-order bits of the right-hand screen byte. For example, %11111100 shifted right four times leaves %00001111 in the left byte and %11000000 in the right hand byte. After some consideration, I suspect twice the amount of lookup data is required (since we should really visualize the bit shifts operating on at least 16 bits, and more than that if we use wider fonts).

Edited by flashjazzcat
Link to comment
Share on other sites

I'm not sure, would have to do the cycle-counts but e.g. shifting 5 bits using 2 x 2 + 1 rotates via lookup might be slower than 2 x 2 shifts + 1 rotate by traditional means.

You can do a quick ROL without carry:

CMP #$80

ROL A

So for a shift 5 pixels right, you could use the "rotate 6 times" table, then that sequence to go back one.

 

Remember - The tables work on rotated data, so what you're doing is getting the value, then you perform 2 mask operations.

 

e.g. bitmap data to write is $6D and has to shift 2 bits, the lookup table gives you $5C. ( 0110 1001 rotated twice = 0101 1010 )

 

You save that value for the second mask operation. First mask operation is AND #$3F - second mask operation is AND #$C0.

 

 

16 bit wide characters - doesn't matter, you can only operate on 8 bits at a time anyhow.

Edited by Rybags
Link to comment
Share on other sites

I suspect I'm approaching the problem from a completely different direction, since I don't get the double masking or how this caters for bits shifting across byte boundaries.

 

Here's the (messy, WIP) character output routine:

 

putchar ;  ; ********************************* character output routine *****************************
and #127
sta char
tay ; index to pointer table
lda font_table_lo,y
sta ptr1
lda font_table_hi,y
sta ptr1+1

jsr set_up_x
;

lda widthtable,y ; get mask
sta charwidth
tay
bit boldflag ; 1 extra pixel width if emboldened
bpl notbold1
iny
inc charwidth
notbold1
lda charmasks,y
; lda charmasks-1,y ; should be charmasks-1 (we need to implement spacing first)
eor #255
sta temp2
lda #255
sta temp2+1
ldx xpix
beq nomaskrot
maskrotlp ; shift background mask into position
sec
ror temp2
ror temp2+1
dex
bne maskrotlp
nomaskrot
lda #0 ; line counter
sta tmp5 ; for height of character
charloop
jsr get_scr
ldy tmp5 ; line #
lda (ptr1),y ; get byte of character data
bit greyflag
bpl nogrey
and chequertab,y
nogrey
sta temp
bit boldflag
bpl notbold2
lsr
ora temp
sta temp
notbold2
bit underline
bpl no_underline
lda tmp5
cmp #7
bne no_underline
ldx charwidth
lda temp
eor charmasks,x
bit greyflag ; look into optimising this
bpl no_grey2
and chequertab+7
no_grey2
sta temp
no_underline
lda #0
sta temp+1
ldx xpix ; pixel offset
beq no_shif
shiflp
lsr temp
ror temp+1
dex
bne shiflp
no_shif
ldy xbyte
lda (scr),y
and temp2 ; mask out bits
ora temp
sta (scr),y
iny
lda (scr),y
and temp2+1
ora temp+1
sta (scr),y
char_nxline
inc linecount
inc tmp5
lda tmp5
cmp #8
bcc charloop
rts

Character width masks and screen background masks are held in tables (although the masks are still shifted into position, and this could immediately be optimized by using another table). Then I step through each byte of the character and mask it against the background.

 

I use a lookup table for ATASCII->Internal conversion. I may suggest to Mr Fish that we actually construct the fonts in ATASCII order to eliminate this computation altogether.

 

 

 

 

 

Edited by flashjazzcat
Link to comment
Share on other sites

...

You can do a quick ROL without carry:

CMP #$80

ROL A

...

If I'm correct this is equivalent to

 ASL A
ADC #$00

[EDIT: corrected]

 

But, how to do this the other direction?

 

So, indeed in 1,2,5 case we really only need 2 tables. The 1-step can be done directly. So, only 512 bytes of LUT needed!

Edited by analmux
Link to comment
Share on other sites

Not sure about quick ROR... I think there might be a way that involves LSR, EOR and ADC.

Otherwise it's just:

lsr a

bcc no_set

ora #$80

no_set ; continue code

 

Cost is one extra cycle if carry set.

 

 

I think we still need that LUT for 6-bit ROR don't we?

Edited by Rybags
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...