Jump to content
IGNORED

AspeQt: Yet another SIO2PC/APE clone


cyco130

Recommended Posts

It would be nice if AspeQt always remembers last directory used.

Now it remembers last directory used if you unmount a disk image and then change disk image.

If you change disk image without unmounting it, the program goes to AspeQt directory.

 

Noted.... however, my suggestion to all AspeQt users is to use SOURCEFORGE for submitting and tracking tickets.

otherwise your request may go unnoticed as Sourceforge is where I, and any other developer will track requests and bug fixes.

You need to be logged-in to Sourceforge to create tickets but not need to be a member of AspeQt project group.

 

Thanks for your cooperation.

Edited by atari8warez
Link to comment
Share on other sites

Sorry if I implied that what ATARIDOS.SYS is doing is wrong -- it may rightfully read or write any sector on the disk in random order. What I was referring to was that the order in which SpartaDOS X uses the buffers is no longer LRU when accessing and updating non-file data, at least on a SpartaDOS X filesystem.

 

It is basically LRU. But file system drivers are able to release buffers forcibly if it is assumed that the contents will no longer be needed, or to flush them, when it is the time to update the media. That's probably what makes the trouble here.

Link to comment
Share on other sites

On a whim I took a crack at implementing virtual folders in Altirra, and I think I see now why the modified AspeQt is running into problems. In short, the SDX copy command reads the first data sector twice:

 

That's right, that can be seen on AspeQt log as well, note that sector 66 (first sector of the file) is read twice, once right after DIR sectors are read, and once more after the copy starts. Also note that the DIR sectors are also read twice (!). This happens when copying a file from a Folder Image to a SDX formatted disk only (Other disk formats are OK as i previously noted)

 

[Disk 2] Get status.

[Disk 2] Get PERCOM block (Single density diskette (90k)).

[Disk 2] Read sector 1 (128 bytes).

[Disk 2] Read sector 360 (128 bytes).

[Disk 2] Read sector 361 (128 bytes).

[Disk 2] Read sector 362 (128 bytes).

[Disk 2] Read sector 363 (128 bytes).

[Disk 2] Read sector 364 (128 bytes).

[Disk 2] Read sector 365 (128 bytes).

[Disk 2] Read sector 366 (128 bytes).

[Disk 2] Read sector 367 (128 bytes).

[Disk 2] Read sector 368 (128 bytes).

[Disk 2] Get status.

[Disk 2] Get PERCOM block (Single density diskette (90k)).

[Disk 2] Read sector 1 (128 bytes).

[Disk 2] Read sector 360 (128 bytes).

[Disk 2] Read sector 361 (128 bytes).

[Disk 2] Read sector 362 (128 bytes).

[Disk 2] Read sector 363 (128 bytes).

[Disk 2] Read sector 364 (128 bytes).

[Disk 2] Read sector 365 (128 bytes).

[Disk 2] Read sector 366 (128 bytes).

[Disk 2] Read sector 367 (128 bytes).

[Disk 2] Read sector 368 (128 bytes).

[Disk 2] Read sector 66 (128 bytes).

[Disk 4] Get status.

[Disk 4] Get PERCOM block (65535 sectors double density hard disk (16383k)).

[Disk 4] Read sector 1 (128 bytes).

[Disk 4] Read sector 36 (256 bytes).

[Disk 4] Read sector 37 (256 bytes).

[Disk 4] Read sector 4 (256 bytes).

[Disk 4] Write sector 4 (256 bytes).

[Disk 4] Read sector 1 (128 bytes).

[Disk 4] Write sector 1 (128 bytes).

[Disk 4] Write sector 37 (256 bytes).

[Disk 4] Write sector 64 (256 bytes).

[Disk 2] Read sector 66 (128 bytes).

[Disk 2] Read sector 400 (128 bytes).

[Disk 2] Read sector 401 (128 bytes).

[Disk 2] Read sector 402 (128 bytes).

[Disk 2] Read sector 403 (128 bytes).

 

But if the same file is TYPE ed (it's a text file) from the Folder Image to the screen, instead of being copied to a disk, the behavior is different. The DIR sectors are read only once (as normally expected) and sector 66 is also only read once. In this case the file displays correctly.

 

[Disk 2] Get status.

[Disk 2] Get PERCOM block (Single density diskette (90k)).

[Disk 2] Read sector 1 (128 bytes).

[Disk 2] Read sector 360 (128 bytes).

[Disk 2] Read sector 361 (128 bytes).

[Disk 2] Read sector 362 (128 bytes).

[Disk 2] Read sector 363 (128 bytes).

[Disk 2] Read sector 364 (128 bytes).

[Disk 2] Read sector 365 (128 bytes).

[Disk 2] Read sector 366 (128 bytes).

[Disk 2] Read sector 367 (128 bytes).

[Disk 2] Read sector 368 (128 bytes).

[Disk 2] Read sector 66 (128 bytes).

[Disk 2] Read sector 400 (128 bytes).

[Disk 2] Read sector 401 (128 bytes).

[Disk 2] Read sector 402 (128 bytes).

[Disk 2] Read sector 403 (128 bytes).

 

Strange and confusing for sure, in any case I made a change to my code simply to repeat reading the first sector and returning the same data when the sector number returned to the code is the same as the previous one and that seems to fix the problem. Some more testing with different scenarios are in order before I can say it works for sure.

Link to comment
Share on other sites

@FJC

 

Jon, I tested and looked at your code, it seems like it fixed the cache problem (not exhaustively tested) but I didn't use it.

 

Here are the reasons why:

 

Firstly, the variable AtariFileNo needs to be local not global if I want to add write support for Folder Images. A global variable will cause problems when two or more Folder Images are mounted,

 

Secondly your fix unnecessarily (IMO) increases the code size and the complexity of the code by repeating some of the functionality within the function,

 

Third.... man!.... this is one heck of a complicated statement, took me a while to figure-out what it's exactly doing:

 

atariFiles[AtariFileNo].pos = (125 + ( 125 * ((sector - 68) + (atariFiles[AtariFileNo].pass * 292))));

 

There is absolutely no need to implement a pass number and invent a complicated formula to calculate the next input file position.

All we needed to do was to increase the number of sectors in the circle and add one IF statement and an ELSE statement to make it work.

 

I can now see why your GUI is taking so long to code :P . Well, don't get me wrong everybody has their style of coding, I just like to keep it as simple as I can, especially when the existing code is already undocumented.

 

And lastly and most importantly I wanted to understand what's happening so I couldn't just copy and paste your code or replace the source file, as I will be the one who's going to continue with this project. Hope you understand my position.

 

Anyway, thanks again to everyone who contributed in one way or another in solving this problem.

Edited by atari8warez
Link to comment
Share on other sites

Strange and confusing for sure

 

Confusing maybe, but there is nothing strange in it. When doing a COPY, the dir is scanned twice, because the first one is done while searching for a matching directory entry using FFIRST/FNEXT (which COPY does, because it must be able to copy groups of files), then the next scan is done while OPENing a file that was found. TYPE does not do the first step, it just opens the one file the user has told it to open, and this is why there is only one scan.

 

Why the sector 66 is read twice, I've explained above.

 

And yet more thing: since there is no reliable method of detecting if the user has changed a DOS 2.0 floppy, the SDX does not keep DOS 2.0 directory or VTOC sectors in the cache: every time a file is being OPENed the VTOC and directory is re-read.

Link to comment
Share on other sites

Am I correct that this code only works for one open file at a time? It looks like the sector window is reassigned to whichever file had its initial sector read last. In theory we should be able to handle more than one simultaneous open file, although I haven't gotten around to stress testing my implementation yet.

 

Correct, and correct. Consider it a starting point for someone who knows what they're doing. ;) I needed something which basically worked in a hurry, but I stopped playing with this six weeks ago.

Link to comment
Share on other sites

Version 0.8.5 of AspeQt is now ready for release (release date is Dec 17th, 2012). Here's what has been changed/added:

 

 


+ MainWindow of AspeQt is now fixed and can not be re-sized manually. Minimum screen resolution required
is 800x600 for a proper fit on the display. Use of 1024x768 is recommended. Tooltips are added to display extended
mounted image information.

+ Added option to display/suppress message log window, setting is saved in registry/session file (Ray Ataergin)

+ Increased the supported drive numbers from 8 to 15 for SDX compatibility (Ray Ataergin)

+ Added option to display/suppress additional drives, setting is saved in registry/session file (Ray Ataergin)

+ Fixed SDX incompatibility of Folder Images (Ray Ataergin - Many thanks to Drac0/Phearon/FJC
for their contributions in solving the SDX cache problem)

+ Added browsing capability for Folder Images. This release only allows read-only support with drag & drop
file copying from the Folder Image. Multiple Folder Images can be mounted. (Ray Ataergin)

+ Fixed a bug where AspeQt opened the "application folder" instead of the "Last Image Folder" if the user
wanted to mount a diskimage on a disk that already had an image mounted. (Ray Ataergin)

+ Added German translation (Florian Dingler)

Edited by atari8warez
Link to comment
Share on other sites

I ran into several issues when trying to compile svn trunk r61 on my Debian Wheezy box (amd64, gcc 4.7.2):

 

* i18n.qrc references the non-existing files i18n/aspeqt_cz.qm and i18n/qt_tr.qm (also there are no _de files there?)

This gives an error when running "qmake" and also later when rcc is called from make

 

* mainwindow.cpp includes the non-existent file "windows.h"

 

* serialport-unix.cpp misses an '#include <unistd.h>', which results in compiler errors with gcc4.7 (close, open etc not declared)

 

I've attached a diff to fix these issues (unzip it and apply it with "patch -p0 < aspeqt-r61.diff").

 

I also noticed several warnings, some of them look like they could lead to possible issues:

 

diskimageatx.cpp: In member function 'virtual bool DiskImageAtx::readSector(quint16, QByteArray&)':
diskimageatx.cpp:240:32: warning: ISO C++ says that these are ambiguous, even though the worst conversion for the first is better than the worst conversion for the second: [enabled by default]
In file included from /usr/include/qt4/QtCore/qstring.h:46:0,
			 from /usr/include/qt4/QtCore/qobject.h:48,
			 from /usr/include/qt4/QtCore/qiodevice.h:46,
			 from /usr/include/qt4/QtCore/qfile.h:45,
			 from /usr/include/qt4/QtCore/QFile:1,
			 from diskimage.h:4,
			 from diskimageatx.h:4,
			 from diskimageatx.cpp:4:
/usr/include/qt4/QtCore/qbytearray.h:475:17: note: candidate 1: bool QByteRef::operator==(char) const
diskimageatx.cpp:240:32: note: candidate 2: operator==(int, int) <built-in>

diskimageatx.cpp: In member function 'bool DiskImageAtx::seekToSector(quint16)':
diskimageatx.cpp:144:32: warning: 'trackindex' may be used uninitialized in this function [-Wmaybe-uninitialized]

serialport-unix.cpp: In member function 'virtual QByteArray StandardSerialPortBackend::readDataFrame(uint, bool)':
serialport-unix.cpp:322:16: warning: converting 'false' to pointer type for argument 1 of 'QByteArray::QByteArray(const char*)' [-Wconversion-null]

I guess the latter should just be changed to "return null" instead of "return false".

 

so long,

 

Hias

aspeqt-r61.diff.zip

Link to comment
Share on other sites

I ran into several issues when trying to compile svn trunk r61 on my Debian Wheezy box (amd64, gcc 4.7.2):

 

 

Ok to be more specific:

 

- On release 0.8.4 Czech and German translation files were not complete so some of them were missing despite entries for them in the project

file existed. i have never received the Czech translation so it will be removed from this release. German translation is complete and will be included.

 

- #include windows.h will be removed from mainwindow.cpp as it is not needed.

 

- #include <unistd.h> is now added to serialport-unix.cpp. HIAS please let me know if there are any Unix related unnecessary #includes in that file so that I can remove them.

 

- For the compile errors, I only receive one when I am compiling for Windows, and that's the warning for "trackindex" and I don't think it needs to be initialized as it is one of the input arguments to the function.

 

- You are right, "return false" is not correct for the function type which is actually a QByteArray. My guess is Windows compiler simply converts the Boolean value (True/false) to (1/0) and returns a character instead without complaining. Apparently Linux compiler is more verbose about that. In any case i will change it to "return NULL" which works fine for both compilers.

Edited by atari8warez
Link to comment
Share on other sites

- On release 0.8.4 Czech and German translation files were not complete so some of them were missing despite entries for them in the project

file existed. i have never received the Czech translation so it will be removed from this release. German translation is complete and will be included.

Ah, just noted that r61 is dated Oct 26 - thought it would be your current working version.

 

- #include <unistd.h> is now added to serialport-unix.cpp. HIAS please let me know if there are any Unix related unnecessary #includes in that file so that I can remove them.

stropts.h and sys/types.h don't seem to be needed (i.e. removing them don't result in compile errors). But, without some further investigations on why they were put there, I'd better leave them in place.

 

- For the compile errors, I only receive one when I am compiling for Windows, and that's the warning for "trackindex" and I don't think it needs to be initialized as it is one of the input arguments to the function.

 

- You are right, "return false" is not correct for the function type which is actually a QByteArray. My guess is Windows compiler simply converts the Boolean value (True/false) to (1/0) and returns a character instead without complaining. Apparently Linux compiler is more verbose about that. In any case i will change it to "return NULL" which works fine for both compilers.

gcc has quite a long history of getting more pedantic about violations to the C/C++ standards (which is a good thing, IMO, because it shows possible portability problems).

 

Also some include files (like unistd.h in this case, gcc 4.7) were automatically included (sometimes indirectly via other includes) in previous compiler or libc versions, so a missing include wouldn't show up with earlier versions.

 

As for the trackindex error: in r61, the offending code in diskimageatx.cpp looks like this:

bool DiskImageAtx::seekToSector(quint16 sector)
{
quint8 track, tracksector, trackindex, tracktemp;

if (sector < 1 || sector > m_geometry.sectorCount()) {
 qCritical() << "!e" << tr("[%1] Cannot seek to sector %2: %3")
				 .arg(deviceName())
				 .arg(sector)
	 .arg(tr("Sector number is out of bounds."));
}

track = (sector-1)/18; //m_geometry.sectorsPerTrack();
tracksector = (sector-1)%18; //m_geometry.sectorsPerTrack();

// because we don't calc timings we return first and last sector on each read. KP
for (tracktemp = 0; tracktemp <= 17; tracktemp++) {
 if (atx.tracks[track].sectors[tracktemp].number == (tracksector+1))
 {
 trackindex = tracktemp;
 if (phantomflip)
	 break;
 }
}
phantomflip = !phantomflip;

qint64 pos = (atx.tracks[track].pos + atx.tracks[track].sectors[trackindex].start);
...

trackindex is a local variable and only set in the if inside the for-loop before being used. If for some reason (sector not present in current track, for example) tracksector cannot be found, trackindex will be uninitialized.

 

If you are sure that this can never happen, just set it to some default value to remove the warning.

 

If it's possible that trackindex can't be found, bail out with some error if it's not there.

 

BTW: I'm not sure what this code actually does and how it's beeing called, so I can't say what's the correct way to handle this warning.

 

so long,

 

Hias

Link to comment
Share on other sites

 

trackindex is a local variable......

 

Hias

 

Ooooops, I wasn't carefully looking... Yes you're right it is not an argument to the function, it is a local variable and can be initialized to 0.

Thanks for the correction :). As for the code, I am as unfamiliar as you are, it is part of ATX image handler but since I haven't written it can't comment much about it either.

Link to comment
Share on other sites

@HIAS

 

Just one question, testing AspeQt today with your High Speed OS (on a U1MB board and using SIO /A in CONFIG.SYS), SDX seems to access drives 9-15 always in normal speed (drives 1-8 are accessed in high speed as usual). Using SDX's hi-speed routines (without SIO /A) work fine (all drives are accessed at high-speed) Is there anything in your hi-speed code that may limit drive numbers used to 1-8?, or should i look elsewhere to find out why extra drives are accessed in normal speed.

Edited by atari8warez
Link to comment
Share on other sites

@HIAS

 

One more question... during testing I also noticed that when using your hi-speed patched OS for I/O, disk drive D12 (or DL: in SDX), does not respond and give an error 138 if it is the first drive accessed after SDX is cold booted into the command processor (that only applies to drive 12, other drives respond as expected). But once another drive is accessed D12 becomes accessible. I noticed that the OS sends an incorrect device number to AspeQt (Device $00 - see the attached photo).

 

This does not happen with native SDX SIO handler, only when I boot SDX with SIO /A in the CONFIG.SYS and Hi-Speed OS enabled in U1MB.

Any ideas?

post-15627-0-56949500-1355723228_thumb.png

Link to comment
Share on other sites

Just one question, testing AspeQt today with your High Speed OS (on a U1MB board and using SIO /A in CONFIG.SYS), SDX seems to access drives 9-15 always in normal speed (drives 1-8 are accessed in high speed as usual)

This is normal. My highspeed patch only supports drives 1-8. Everything else (DDEVIC != $31 and DUNIT=0 or DUNIT >=9) uses the original OS SIO code.

 

One more question... during testing I also noticed that when using your hi-speed patched OS for I/O, disk drive D12 (or DL: in SDX), does not respond and give an error 138 if it is the first drive accessed after SDX is cold booted into the command processor (that only applies to drive 12, other drives respond as expected). But once another drive is accessed D12 becomes accessible. I noticed that the OS sends an incorrect device number to AspeQt (Device $00 - see the attached photo).

Now this is strange. I don't know where device $00 could be coming from.

 

Maybe this is an SDX bug? Could you check if this happens with the original OS, too?

 

so long,

 

Hias

Link to comment
Share on other sites

This is normal. My highspeed patch only supports drives 1-8. Everything else (DDEVIC != $31 and DUNIT=0 or DUNIT >=9) uses the original OS SIO code.

 

 

Now this is strange. I don't know where device $00 could be coming from.

 

Maybe this is an SDX bug? Could you check if this happens with the original OS, too?

 

so long,

 

Hias

 

"Original OS" i suppose is the Atari OS. No, I haven't checked that but I will and let you know.....

 

EDIT: I did the test and the problem does not happen with stock OS, only after I switch U1MB to use Hi-Speed OS. In both cases CONFIG.SYS has SIO /A in it.

 

Do you have any plans to update your code to allow disk drives 9-15 to be used in high speed I/O?

Edited by atari8warez
Link to comment
Share on other sites

Some interesting stats about AspeQt:

  • Year to date downloads: 970
  • As expected it is most popular in USA, Poland and Germany (Atari strongholds - 64% of all downloads).
  • 10 top countries account for 85% of all downloads.
  • Downloaded 2709 times since its inception.
  • Known to Atari enthusiasts in all continents (except Greenland) and 51 different countries.
  • Used mostly with Windows OS.

post-15627-0-16928200-1355781390_thumb.png

Edited by atari8warez
Link to comment
Share on other sites

Now this is strange. I don't know where device $00 could be coming from.

 

It might be garbage due to AspeQt having the wrong baud rate set. It isn't possible for the program to sense two baud rates at the same time like a disk drive might, so instead it tries to switch back and forth until it catches the command at the right one, relying on SIO retries to resend the command. An unfortunate issue with the SIO checksum algorithm is that the checksum of all $00 bytes is also $00.

Link to comment
Share on other sites

It might be garbage due to AspeQt having the wrong baud rate set. It isn't possible for the program to sense two baud rates at the same time like a disk drive might, so instead it tries to switch back and forth until it catches the command at the right one, relying on SIO retries to resend the command. An unfortunate issue with the SIO checksum algorithm is that the checksum of all $00 bytes is also $00.

 

I am not sure if i understand this correctly, but AspeQt is not switching back and forth to set a baud rate (which at the time of testing was set at 80982 bps which corresponds to divisor 4). When AspeQt switches baud rates it is always indicated on the log window but in this case there were no speed adjustments.

 

Also this does not happen when SDX operates under it's own SIO code, only when HI-Speed OS is enabled in U1MB setup menu and SDX boots with a CONFIG.SYS that has SIO /A line in it (meaning SDX will use OS routines for SIO, in this case routines provided by the patched OS). Here's a complete AspeQt log (from boot until DIR L: command is issued)

 

Also it is strange that it only happens with drive L: (12), any other drive (like K:, or N: for example) works just fine. The problem goes away once another drive is accessed at least once. :?

 

[Disk 1] Speed poll.

Serial port speed set to 80982.

[Disk 1] Get PERCOM block (DD Diskette (180k)).

[Disk 1] Read sector 1 (128 bytes).

[Disk 1] Read sector 5 (256 bytes).

[Disk 1] Read sector 6 (256 bytes).

[Disk 1] Read sector 5 (256 bytes).

[Disk 1] Read sector 6 (256 bytes).

[Disk 1] Read sector 32 (256 bytes).

[Disk 1] Read sector 33 (256 bytes).

[Disk 1] Get status.

[Disk 1] Get PERCOM block (DD Diskette (180k)).

[Disk 1] Read sector 1 (128 bytes).

[Disk 1] Read sector 5 (256 bytes).

[Disk 1] Read sector 6 (256 bytes).

[Disk 1] Read sector 34 (256 bytes).

[Disk 1] Read sector 35 (256 bytes).

[Device $00] command: $00, aux: $00f8 ignored. [x28]

Edited by atari8warez
Link to comment
Share on other sites

It might be garbage due to AspeQt having the wrong baud rate set.

I had the same idea last night when I was thinking about it, and although the probability of this happening is not too high, it's still possible and I think we just saw an example where baud-rate detection fails.

 

According to Ray's log AspeQt stays at ~81kbit, but the Atari is sending data at 19kbit - this is a factor of ~4.25.

 

If we just look at the first SIO byte, $3C (i.e. "D12:") the transmitted bitstream is 0001111001 (start bit, LSB-MSB, stop bit). The receiving end will interpret the first 3 "0" bits as a "0" byte, although it should report a framing error since the stop-bit is not 1. Then the 4 "1" bits are interpreted as "idle", the next 2 "0" bits are received as another "0" byte (maybe without a framing error).

 

So this would explain the $00 device and $00 command.

 

Haven't checked the other bytes (command, aux, checksum), but it is certainly possible that these bytes get received as $F8, $00, $F8.

 

@Ray: You could add a check for framing errors and breaks to your code, and treat a command frame as invalid if one of these errors occur. This should make the baudrate detection more reliable. I'm not sure how the Win32 comm layer/drivers handle these cases, but you might just get the (wrong) received data when a framing error happens and a "0" byte when a break is received.

 

so long,

 

Hias

Link to comment
Share on other sites

I had the same idea last night when I was thinking about it, and although the probability of this happening is not too high, it's still possible and I think we just saw an example where baud-rate detection fails.

 

According to Ray's log AspeQt stays at ~81kbit, but the Atari is sending data at 19kbit - this is a factor of ~4.25.

 

If we just look at the first SIO byte, $3C (i.e. "D12:") the transmitted bitstream is 0001111001 (start bit, LSB-MSB, stop bit). The receiving end will interpret the first 3 "0" bits as a "0" byte, although it should report a framing error since the stop-bit is not 1. Then the 4 "1" bits are interpreted as "idle", the next 2 "0" bits are received as another "0" byte (maybe without a framing error).

 

So this would explain the $00 device and $00 command.

 

Haven't checked the other bytes (command, aux, checksum), but it is certainly possible that these bytes get received as $F8, $00, $F8.

 

@Ray: You could add a check for framing errors and breaks to your code, and treat a command frame as invalid if one of these errors occur. This should make the baudrate detection more reliable. I'm not sure how the Win32 comm layer/drivers handle these cases, but you might just get the (wrong) received data when a framing error happens and a "0" byte when a break is received.

 

so long,

 

Hias

 

Hias I tested this further and the problem starts at divisor 4, higher divisors work fine. What puzzles me is that it only happens with that particular drive (D12). Anyway I'll take a look at the code and see what I can do about it. By the way, can you suggest a good serial port monitor (sniffer) program which works with Win7 64 bit, has to be freeware though :) .

Link to comment
Share on other sites

Small update/correction to AspeQt English and German manuals. If you recently downloaded version 0.8.5 please replace the manuals with the attached ones.

 

Also, anyone who is interested in downloading the current source from Sourceforge should know that Sourceforge is currently having problems with their Code repository and some of the projects (including AspeQt) which recently migrated to the new Sourceforge system does not show the correct revision number in the SF Code section. They are working on this issue but until it's fixed the latest source for AspeQt may not be available for download.

 

I will make current source available on my website in the interim.

AspeQt User Manual-English.html

AspeQt User Manual-German.html

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

See post #457 above :

MainWindow of AspeQt is now fixed and can not be re-sized manually. Minimum screen resolution required

is 800x600 for a proper fit on the display. Use of 1024x768 is recommended. Tooltips are added to display extended

mounted image information.

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...