Jump to content
IGNORED

Created English translation of the Extended Turbo Basic (Turex.com) documentation


markmiller

Recommended Posts

Thanks for your efforts.  Could you tell us anything about where the original German text came from?  This looks like only a small portion of the Turbo Basic XL docs.  I remember that from many years ago, I tried to translate the docs as printed in Happy Computer (magazine), and Google would only translate a small portion.  It behaved as if it would fill its buffer and translate that, but then no more.  I finally gave up.  Just a little while ago, ABBUC published a very nice, new manual in German.  There was an effort to translate it, but I don't think that anything happened.  (It would have been a daunting task.)

Link to comment
Share on other sites

1 hour ago, Larry said:

Could you tell us anything about where the original German text came from?  This looks like only a small portion of the Turbo Basic XL docs.

The translation is of the doc for the TBXL Extension suite, which can be found here: Serious Computerist - Turbo-BASIC XL Extension

The original German doc is on the disk itself.

 

  • Like 3
  • Thanks 3
Link to comment
Share on other sites

4 hours ago, Larry said:

Thanks for your efforts.  Could you tell us anything about where the original German text came from?  This looks like only a small portion of the Turbo Basic XL docs. ...

Just to disambiguate, I am talking about an extension that was made to TBXL, which is called TUREX.COM on disk. I read about it on the AtariWiki, in the page on Turbo Basic. This is not the "expanded Turbo Basic documentation" you're referring to. That's talking about a newer edition of the documentation for Turbo Basic XL itself that has expanded explanations of TBXL's command set.

 

For what I'm talking about, see: Turbo Basic XL where it describes TUREX.COM under the Background heading.

 

It notes:

 

Quote

XTB [eXtended Turbo Basic] had been created by Thorsten Karwoth

 

The way it works is you boot up Turbo Basic 1.5 (that's what I've tested it on, anyway), and then use its BLOAD or BRUN command to dynamically load TUREX.COM into it. It's like a hot patch. It instantly adds more commands to the language, but only in RAM. It does not permanently change your copy of TBXL. Each time you want to use the extension, you have to go through the same procedure (load TBXL, BLOAD TUREX.COM). While the extension is active, it also invalidates/turns off the RAMdisk on the 130XE. This is discussed in the documentation. Though, it also adds commands for storing/accessing data to/from the extended RAM the RAMdisk once occupied.

 

The documentation I posted describes this extension to the language, as translated from the original German documentation that's on the extension disk. You can also get a copy of the extension disk on the AtariWiki page, which contains TUREX.COM.

 

Re. how I used Google Translate, it took some work, because as I said, the documentation only existed on the extension disk. I only use an Atari in emulation these days. Since I use a Mac, I'm using Atari800MacX. It has a feature where you can highlight text that's on the emulated Atari screen, and copy/paste it into another app as plain text. Google Translate has a limit on how much text it will accept at once. Fortunately, I didn't hit that limit, simply because of the 40x24 screen size on the Atari. :) The way I captured the text was by doing a simple Copy operation in DOS from D: to E:, and using Ctrl-1 to pause the screen, capturing the text in sections using the emulator, and copy/pasting it into Google Translate. I took the translated sections, and copy/pasted into TextEdit (a Mac app.), where I saved it to an RTF file.

 

Google Translate did a pretty good job, but I thought some of the word usage was confusing. So, I reworded it in some places, if I thought it would clarify.

 

I did the translation really for myself, because I thought maybe the extension would have some features I could use. (So far, I've only been tempted by commands like ROUND, INC, and DEC). Like with some of the features in TBXL, the extension seemed aimed at video game developers. The extension emphasizes access to graphics functions on the Atari.

Edited by markmiller
  • Like 2
  • Thanks 1
Link to comment
Share on other sites

6 hours ago, markmiller said:

I did the translation really for myself, because I thought maybe the extension would have some features I could use. (So far, I've only been tempted by commands like ROUND, INC, and DEC). Like with some of the features in TBXL, the extension seemed aimed at video game developers. The extension emphasizes access to graphics functions on the Atari.

I messed around with the extensions some years ago. The main problem with them is lack of support in the compiler. So, you're stuck using them in interpreted mode.

 

One of the things I messed around with was the software blitter. Rather unimpressive, in terms of speed; it's also only usable in Gr. 8. I have better ML subroutines I use for the same purpose.

 

Overall, an interesting artifact; but no real practical value for me.

 

  • Like 1
Link to comment
Share on other sites

8 hours ago, MrFish said:

One of the things I messed around with was the software blitter. Rather unimpressive, in terms of speed; it's also only usable in Gr. 8. I have better ML subroutines I use for the same purpose.

 

Overall, an interesting artifact; but no real practical value for me.

 

The extension comes with some demo programs. The ones demonstrating the blitter commands seemed to partly work. I'm not sure if it was the blitter routines in the extension that were buggy, or if the demos just weren't written well.

 

You're right that using the extension means you can't use the compiler, since it doesn't know about the commands the extension adds. However, I've had limited use for the compiler, since it's rather buggy. It works for short, simple programs, but for large programs, it has a bunch of problems that might be possible to get around, but it limits the size of what you can compile. The interpreter works really well, though. I think I've only found one bug in it.

  • Like 1
Link to comment
Share on other sites

9 hours ago, MrFish said:

Here are some videos I made of the tests I did with the blitter before.

 

Some nice looking software sprites you had there. :) I had the thought looking at the first video that it would look better if the animation routine ran as a VBI. That way, you wouldn't be able to see it redraw.

 

I don't imagine it would've been good practice for the extension to use the same technique, because that would limit the use of the VBI vector for programmers to use. Probably would've been better to leave the blitter feature out of the language, and let ML programmers deal with it.

Link to comment
Share on other sites

6 hours ago, markmiller said:

The extension comes with some demo programs. The ones demonstrating the blitter commands seemed to partly work. I'm not sure if it was the blitter routines in the extension that were buggy, or if the demos just weren't written well.

Yeah, I've looked at the demos before; nothing very compelling there. 

  

6 hours ago, markmiller said:

You're right that using the extension means you can't use the compiler, since it doesn't know about the commands the extension adds. However, I've had limited use for the compiler, since it's rather buggy. It works for short, simple programs, but for large programs, it has a bunch of problems that might be possible to get around, but it limits the size of what you can compile. The interpreter works really well, though. I think I've only found one bug in it.

Yes, there are a few annoyances with the compiler; but I don't find them so troublesome as to prevent wanting to use it altogether for larger projects. The speed gains using the compiler are significant over the interpreter. Many programs would nearly be a waste of time to attempt programming, if targeting the interpreter.

 

My current TBXL project in progress stands at 2,737 lines (counting comments) at the moment: Mills Slots

[Note: I'm also coding it in conjunction with the excellent basicParser tool -- and Notepad++ as an editor, with the NppExec extension.]

 

  • Like 2
Link to comment
Share on other sites

5 hours ago, markmiller said:

Some nice looking software sprites you had there. :) I had the thought looking at the first video that it would look better if the animation routine ran as a VBI. That way, you wouldn't be able to see it redraw.

Yes, it has some tearing going on there. There is a way to force it into the VBI in TBXL, using the "Pause 0" command; but that would actually slow things down; and I was most interested in seeing how fast the blitter was, rather that how cleanly it could render. The result being pretty slow, I saw no reason to carry on further.

  

5 hours ago, markmiller said:

I don't imagine it would've been good practice for the extension to use the same technique, because that would limit the use of the VBI vector for programmers to use. Probably would've been better to leave the blitter feature out of the language, and let ML programmers deal with it.

Leaving the blitter off would have saved some memory used by the extensions.

 

Link to comment
Share on other sites

13 hours ago, MrFish said:

My current TBXL project in progress stands at 2,737 lines (counting comments) at the moment: Mills Slots

[Note: I'm also coding it in conjunction with the excellent basicParser tool -- and Notepad++ as an editor, with the NppExec extension.]

 

That's impressive. My current project is more than 1,000 lines. I'm working on a simple assembler and VM, modeling it in Basic, since I'm a beginner at this stuff :). At a couple points, I ran out of variable table and memory space. I don't remember how many lines I got up to (maybe 1,600, including comments). I've been scaling my code back some, reducing the number of variables, reducing comments to "just essentials," reducing my use of labels (except for procedure calls. I'm finding that using line numbers for branches takes up less memory, though). However, I really like using longer, descriptive variable names.

 

basicParser looks interesting, especially the feature that puts in parameters and local variables for procedures. I guess it expands the use of the stack to pull that off?

 

Even though it doesn't help with the number of variables in the name table, I imagine its reduction of variable names to single characters, or zero characters, helps in conserving memory.

 

I've thought about switching to working in a more modern environment, possibly using a different language, and compiling to run on the 8-bit, but I really like the interactive environment for debugging! I'll put up with a lot to stay in that. :) Though, I use TextEdit sometimes to "think out" my code before I enter it in Basic.

Link to comment
Share on other sites

One thing the basicParser will let you do is what you see below. I use that for the little-used equate variables. When processed, no variables are used, as it inserts the numeric values instead. The benefit of variables in your code, without taking up space in the variable name table.

 

..  ----------------------
..        (Equates)
..  ----------------------

..  color registers (shadow)
$define ePCOLR0 = 704
$define ePCOLR1 = 705
$define ePCOLR2 = 706
$define ePCOLR3 = 707
$define eCOLPM2 = 53268

$define eCOLOR0 = 708
$define eCOLOR1 = 709
$define eCOLOR2 = 710
$define eCOLOR3 = 711
$define eCOLOR4 = 712

..  color registers (hardware)
$define eCOLPF1 = 53271

..  player-missile position registers
$define eHPOSP0 = 53248
$define eHPOSP1 = 53249
$define eHPOSP2 = 53250
$define eHPOSP3 = 53251

$define eHPOSM0 = 53252
$define eHPOSM1 = 53253
$define eHPOSM2 = 53254
$define eHPOSM3 = 53255

..  player-missile size registers
$define eSIZEP0 = 53256
$define eSIZEP1 = 53257
$define eSIZEP2 = 53258
$define eSIZEP3 = 53259
$define eSIZEM = 53260

..  player-missile miscellaneous 
$define ePMBASE = 54279
$define eGRACTL = 53277
$define eGPRIOR = 623

..  character set base address (pages, shadow)
$define eCHBAS  = 756

..  character set base address (pages, hardware)
$define eCHBASE = 54281

..	screen pointer
$define eSAVMSCLow = 88

..  top of available RAM (pages)
$define eRAMTOP = 106

..  direct memory access enable
$define eSDMCTL = 559

..  attract mode timer
$define eATRACT = 77

..  non-maskable interrupts enable
$define eNMIEN  = 54286

..  non-maskable display list interrupts vector
..  512 LSB , 513 for MSB ( $200, $201 )
$define eVDSLST = 512

..  starting address of display list
$define eSDLSTL = 560

..  Cursor inhibit, 0 = on, 1 = off
$define eCRSINH = 752

..  Left margin of Graphics 0 Screen
$define eLMARGN = 82

..	Break key
$define eBRKKYLow = 566

 

  • Like 2
Link to comment
Share on other sites

@MrFish - Re. basicParser, I had the thought that this is also probably why you're able to squeeze in more lines of code, since I'm guessing it doesn't transfer comments to the tokenized file (because what would be the point of that?).

 

I'm a little curious what value was seen in creating this, though, because why not use fastbasic, which is a compiled language, if you're going to take the step of writing code outside of an interpreter? However, as I recall, fastbasic doesn't have preprocessor directives. So, most of the code is explicitly compiled into the executable.

 

BTW, thanks for the reference to Serious Computerist. The resources there are really nicely presented.

Edited by markmiller
Link to comment
Share on other sites

6 hours ago, markmiller said:

@MrFish - Re. basicParser, I had the thought that this is also probably why you're able to squeeze in more lines of code, since I'm guessing it doesn't transfer comments to the tokenized file (because what would be the point of that?).

Yes, that's saving some file size. Although if I were keeping comments, I'd just be very sparse with them. In this case, it just means comments can be used liberally, which I do.

 

Comments can easily be eliminated in cross-development without the use of the basicParser, though. They just need to be typed without line numbers, the file listed to disk in ASCII, then loaded with the ENTER command in TBXL; then they'll just disappear whenever the file is loaded, because they'll be entered in immediate mode.

  

6 hours ago, markmiller said:

I'm a little curious what value was seen in creating this, though, because why not use fastbasic, which is a compiled language, if you're going to take the step of writing code outside of an interpreter? However, as I recall, fastbasic doesn't have preprocessor directives. So, most of the code is explicitly compiled into the executable.

Originally, the author had intended to write a cross-compiler for TBXL. The basicParser was initially written before FastBASIC. FastBASIC is what he ended up writing instead of the TBXL compiler. FastBASIC is generally compatible with TBXL.

 

I think I started writing my slot machine program before FastBASIC was available. Also, FastBASIC wasn't as mature as it is now. I was interested in using it before, but I was waiting for things to come along a bit further first. It still doesn't have some features I'd like to see; but it's close to enough to my ideal already. I was actually planning to rewrite my slot machine in FastBASIC; I just haven't got around to it yet. It won't be too difficult; I think the main missing feature I'm using in TBXL is multidimensional arrays.

 

  • Like 2
Link to comment
Share on other sites

  • 6 months later...
5 hours ago, Brad Nelson said:

BLOAD TUREX.COM

 

For what it's worth, at least on the Turbo-BASIC XL Extension disk that I have, type: BRUN "D:TUREX.EXE". BLOAD didn't work. Nor was the file extension "COM".

I found that out recently, as well. It's "COM" in the TB extension disk image I have, but you're right. BRUN is what works, not BLOAD. The AtariWiki documentation said it would work with either command.

 

Also, there should be a way to get the extension loaded automatically, since if you want to distribute something, you don't want people to have to run BRUN "D:TUREX" before loading your program. I've tried putting this command inside of a test program, to see if I can load the extension, and then have the interpreter continue with more commands inside the same program, but the program memory gets erased when this command is executed. So, if you want to autoload an extended TB program, it has to be done in two steps, somehow.

 

The disk I have has an AUTORUN.SYS and an AUTORUN.BAS that BRUN's SW.COM (not sure what that is), and then BRUN's TUREX.COM. Both executables are on the disk, but AUTORUN.BAS doesn't seem to get executed.

  • Like 1
Link to comment
Share on other sites

Mark, I've used the compiler before on a Turbo-BASIC XL program. Repeating to you what is probably obvious to you (but just thinking out loud), the compiled program you create via COMPILER.COM will come out the other end as MYFILE.CTB. There will be a "CTB" extension. If you want it to boot automatically from a disk, the manual says to rename it AUTORUN.CTB. To make it runnable by someone without Turbo-BASIC XL, then you need to copy the RUNTIME.COM file onto the same disk.

 

I've done this (and it seems a bit of an involved and convoluted process...at least to me) and it works. But I've never tried it with a Turbo-BASIC XL file that was created with the TUREX extension. I would have supposed that once you compiled it and all that, you wouldn't need that TUREX file anymore. But it sounds as if you're saying that this is not the case. I may have to experiment with that a little.

  • Like 1
Link to comment
Share on other sites

1 hour ago, Brad Nelson said:

Mark, I've used the compiler before on a Turbo-BASIC XL program. Repeating to you what is probably obvious to you (but just thinking out loud), the compiled program you create via COMPILER.COM will come out the other end as MYFILE.CTB. There will be a "CTB" extension. If you want it to boot automatically from a disk, the manual says to rename it AUTORUN.CTB. To make it runnable by someone without Turbo-BASIC XL, then you need to copy the RUNTIME.COM file onto the same disk.

 

I've done this (and it seems a bit of an involved and convoluted process...at least to me) and it works. But I've never tried it with a Turbo-BASIC XL file that was created with the TUREX extension. I would have supposed that once you compiled it and all that, you wouldn't need that TUREX file anymore. But it sounds as if you're saying that this is not the case. I may have to experiment with that a little.

Thanks for the dynamic load info. I missed that in the manual.

 

To add to what you said, you rename RUNTIME.COM to AUTORUN.SYS. So, what you should have on a bootable disk is AUTORUN.SYS (the runtime), and AUTORUN.CTB (your compiled program). The way it works is DOS loads the runtime, which then loads and runs your AUTORUN.CTB file.

 

I think this helps explain why on my TBXL disk there are two runtime files, RUNTIME.EXE and RUNTIME2.EXE, and why when I run the linker, it says, "loading RUNTIME2.EXE". The first runtime file is for dynamic linking. The second is for static linking.


Using the extension is not compatible with the compiler, because it introduces new commands to the language that the compiler doesn't recognize. The compiler was written by Ostrowski, and published in the same magazine as TB. I'm pretty sure the extension was written after the compiler was published.

 

I mean, the only way I can think that the extension would work with the compiler was if the new commands were written like macros on top of TB, which would generate a bunch of bytecodes in the existing TB language, to simulate the new commands. I highly doubt that's what Karwoth did, since that would make generating program listings (reproducing what you typed in) rather complicated.

 

Also, as you can tell, the extension is written as a hot patch to TB.
 

Edited by markmiller
  • Like 1
Link to comment
Share on other sites

To add to what you said, you rename RUNTIME.COM to AUTORUN.SYS

 

Mark, you are quite right. Sorry that I left out that part. Like I said, to me, this is all a bit convoluted. I'm a "dabbler" programmer. I can do a little here and there. For those who are deep into this kind of stuff, they would consider the steps to make a Turbo-BASIC XL program into an independently bootable program to be trivial.

 

And I've not run into that RUNTIME2.EXE (or .COM) file on any of the disks I have, and I have a few. Nor was I aware that one was for dynamic linking as opposed to static linking (or what the difference would be...not need to explain it...I'll just dabble on).

 

I'm using version 1.5 of Turbo-BASIC XL if that clarifies anything.

 

Using the extension is not compatible with the compiler, because it introduces new commands to the language that the compiler doesn't recognize. The compiler was written by Ostrowski, and published in the same magazine as TB. I'm pretty sure the extension was written after the compiler was published.

 

Yes, that makes perfect sense. And I loved looking through those extended commands. But, frankly, I didn't find a lot that I couldn't live without. But I did like the commands to convert lowercase to uppercase, and vice versa. The INC (increment) and DEC (decrement) commands seem logical and useful as well. Maybe the TXTPOS and WAIT commands as well. And BREAK ON and BREAK OFF to easily turn off or on the break key. And how elegant to quite the TUREX extension with just "GOODBYE."

 

I would love just an extension to bring back "normal" string arrays (as in the Microsoft Basic II that I have and use for the Atari 8-bit machines). :) But Turbo-BASIC XL is really an amazing program, in my opinion. I know that "serious" programmers tend to prefer ACTION! (and for good reason). But that stuff just becomes way too geeky and complex. If I have an idea for something and just want to sort of bash it out, nothing beats Turbo-BASIC XL for that, although Microsoft Basic II is useful as well. And I'm learning SpartaDOS X which makes managing disks a little easier, as well as switching between programs. But that's another story.

Link to comment
Share on other sites

7 hours ago, Brad Nelson said:

I would love just an extension to bring back "normal" string arrays (as in the Microsoft Basic II that I have and use for the Atari 8-bit machines). :) But Turbo-BASIC XL is really an amazing program, in my opinion. I know that "serious" programmers tend to prefer ACTION! (and for good reason). But that stuff just becomes way too geeky and complex. If I have an idea for something and just want to sort of bash it out, nothing beats Turbo-BASIC XL for that, although Microsoft Basic II is useful as well. And I'm learning SpartaDOS X which makes managing disks a little easier, as well as switching between programs. But that's another story.

Re. "normal" string arrays

 

Agree. There is Basic XL, and Basic XE by OSS, which gives you string arrays. These two are written as extensions to the Atari Basic language, and are optimized to run faster. No compiler (to native code), though. In speed comparisons, people still swear by TBXL, since it's faster than these two.

 

Re. TBXL, I've thought that adding parameters and locals to PROC's would've been nice, since as they are, they're just "named gosub's." There is a cross-compiler (to bytecode) for TBXL called basicParser (referenced elsewhere in this thread) that emulates parameters and locals to PROC's, which is nice. :)

 

I like using labels in TB, but the unfortunate thing is they're treated like variables, part of the same name table. So, they take up the same space in your code as a variable, and are subject to the same name table limit (256 variable names for the whole program, but this is twice as large as what Atari Basic allows).

 

I know what you mean re. bashing it out in TBXL. I've done that. What really draws me to it is the interactivity. I'll put up with a lot to have that.

 

I've thought about getting into Action! on the 8-bit, but I figure if I'm going to deal with using the edit-compile-run cycle, I'll use CC65, a C cross-compiler. Though, I've heard there's an Action! cross-compiler, as well.

Edited by markmiller
  • Like 1
Link to comment
Share on other sites

It's interesting reading your perspective on this very fine program.

 

My latest project was writing a five-card draw poker game in Microsoft Basic II. It would deal hands and compare hands. And that was a lot of fun (and work) getting into the nitty gritty of just how complicated it actually is to compare several poker hands with each other (and evaluating each for what it is, of course). It is completely text-based and (for now) hardwired for 3 players. (I wrote it with two fellow poker enthusiasts in mind). Then end result was a gigantic respect for commercial game programmers. This was relatively easy to do via Microsoft BASIC II's more standard string arrays. I'm sure it could be done using Atari's method. I just didn't immediately know how.

 

The funny thing was going to ChatGPT for some pointers. Oh, that was an adventure. But it did give me a few ideas when I got stuck. But it was funny how it would give you entire chunks of code that were completely non-functional...what they call a "hallucination," I guess.

 

Turbo-BASIC XL is worth the price of admission just for being able to access a disk directory, although while studying SpartaDOS X 4.4.9, I found a program that allowed Atari Basic (and, of course, TB) to read directories (when using SpartaDOS X) via a separate runnable BASIC program. I adapted it to read the first 8 drives. That's not as good as it being built in but it can be a quick way to find something and just get the lay of the land. File attached. Simple, but effective, although I can't find a way to trap for a drive being empty. I'd like to incorporate changing directories. And I did find (via an SDX technique using XIO 44) a way to change directories. But I could find no way to program it.

 

I should train myself to use labels more and bring better structure to what is often my spaghetti code. But I like Italian, so what the hey.

CAT2.zip

Edited by Brad Nelson
Link to comment
Share on other sites

1 hour ago, Brad Nelson said:

I found a program that allowed Atari Basic (and, of course, TB) to read directories (when using SpartaDOS X) via a separate runnable BASIC program.

Some issue of Compute! Magazine had "scripts" you could run (immediate mode code) in Atari Basic that would do some DOS functions, like get a disk directory. I used to use these a lot. It turned out they were pretty easy to implement. All of the code for each function fit on a single line. As I remember, you entered the code in DOS, using the Copy function (from E: to D:). The code was entered as text, and saved to a file, like "DIR". You could then be in Basic, and type

EN."D:DIR"

This would ENTER the one line of code from disk, and run it on the spot, giving your disk directory (though, you had to hardcode the drive number it would access. Since I had one disk drive, anyway, this was fine).

 

The structure of these "scripts" was: open a channel, call an XIO function on it, and then close the channel. Maybe some of them DIMensioned a variable, and had an INPUT statement to get some parameter(s) for, say, deleting a file, or renaming a file, which would be passed to the XIO call. I forget.

 

Having DOS functions in TB is nice.

 

It really feels like TB takes some steps toward what Atari Basic should've been. Atari had its reasons for doing what they did, due to the cost of memory when the Atari 400/800 were released. I think they made some good compromises with the language. Once memory costs came down, and Atari computers had more memory, there was room to improve the language. It would've been great if Atari had done that, but thankfully, there were "upgrade" options from third parties.

 

Incidentally, Atari originally wanted Microsoft Basic to be the standard language on the Atari 400/800. They went through a lot of effort to do that, but they also wanted the language to take advantage of the Atari's system features, but they and Microsoft were not able to get it to fit into 8K of ROM. So, Atari went to Shepardson Microsystems, who created Atari Basic. I think they made some good compromises.

 

Atari didn't give up on their version of MS-Basic, but they had to release it as a separate product for the Atari 800, since you needed a minimum of 32K RAM to run it, IIRC.

 

Re. ChatGPT

 

The thing with it is the only thing it's designed to do well is produce correct language form. It doesn't care about the content. It vacuums up content on the internet, and uses a probability model to arrange it in a mostly sensible manner. Factual correctness is not its thing. If you get code that works, or content that's correct, it's really by luck, or skillful prompting. When people use the term "hallucination," they're joking around, or making excuses.

Edited by markmiller
  • Like 2
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...