Rossman Posted October 24, 2017 Share Posted October 24, 2017 I'm programming a little card game in Pascal. Card games in Pascal are fun programming exercises but are generally not visually interesting. I'm looking at changing up the UI to show cards being dealt, presented, flipped. I looked into turtlegraphics, but I'm thinking I'll use sprites. If for no other reason than because I have access to far more documentation on sprites than turtlegraphics. Sprites will make it a non-portable Pascal program, but my goal in doing this wasn't to create a portable Pascal program. The current text UI version of the code is portable to any UCSD system, save for the random number generator. I found some pseudo-random-number generators that I believe could be easily implemented, so that's likely a problem easily solve-able. I'm just going for a little visual improvement. With all of that as a preamble, here's my question. It's been a long time since I coded sprites, so I'm creating some test cases to model out the things I'll need to do for this to work. My test moves a double-sized sprite (not magnified) from (y=95,x=128) at velocity (y=-8, x=0) for a countdown of 64, then a velocity of (y=-4,x=0) for a countdown of 64. Then it holds position. I'm just experimenting with showing a card come out fast, then slow down, then stop. (Inspired by the truly beautiful motion of the Q*Bert demo we saw at the Evanston meet-up a few weeks ago!) I'd expect the sprite to end up at 95 + ((-8/32*64) + (-4/32*64)), or y=71, x=128. It isn't. It's ending up at double the distance: y=47, x=128. The velocity/32 every 60th of a second math comes from page 145 of the Pascal Compiler manual. This suggests a sprite travels just about 2 pixels every 60th of a second. Or, assuming it's an octal and not a decimal clock, 1 / 32 * 64 == 2. The Editor/Assembler manual has a different description on sprite motion. Page 341 says, that a velocity of >01 causes a sprite to move one pixel every 16/60th. Assuming that the velocity is the same, it seems to me that the assembler manual says we get 4 pixel moves every (roughly) 60th of a second. Back to our octal clock, 16/64 == 4. If I'm reading this right, the sprite speed in the assembler manual would describe the 2x difference in velocity that I'm seeing with where my sprite is ending up. I haven't run all possible tests yet to figure out if I'm just thick-headed. I haven't coded sprites in assembly or XB routines to time comparisons, I haven't re-timed using a standard sized sprite, etc. But anyone who is familiar with sprite motion who knows the velocity I should expect, I would appreciate it. Best regards, R. 1 Quote Link to comment Share on other sites More sharing options...
apersson850 Posted October 24, 2017 Share Posted October 24, 2017 (edited) Unfortunately I don't remember the velocity you should expect in Pascal. I've not used sprites much in Pascal on the 99/4A, but mainly written software that are either text only or system oriented. However, after deep dives into the p-system implementation on the TI 99/4A, I can at least say for sure that the sprite automotion logic described in the Editor/Assembler manual is the one that's built-in into the console ROM in the computer. That code presumes a certain VDP RAM table setup, or it will modify the wrong items in VDP memory. But the p-system has a different memory setup, so it also has its own sprite movement code. Thus it's not unexpected at all if you get contradictionary information about sprite speeds when comparing the E/A manual with the Pascal compiler manual's descripion of the sprite handling unit. I can also add that the p-system's automatic motion routines handle the sprites in two blocks. If you use automatic motion, you get better performance if all sprites using it are in group 0-15 or group 16-31. The logic will skip half of the motion code if only one of these groups contain moving sprites. Even if you only use two sprites with motion, you'll suffer a speed penalty if they belong to different groups. Edited October 24, 2017 by apersson850 1 1 Quote Link to comment Share on other sites More sharing options...
Rossman Posted October 24, 2017 Author Share Posted October 24, 2017 Wow, I didnt realize the p-system had its own sprite movement. Thats good to know. I probably need to spend a little more time just becoming familiar with the p-system. Im making assumptions about what it does and does not do. Great tip on the movement and blocks. Thank you. Ive only been experimenting with sprites on Pascal for a few days now, but it strikes me a little bit like its not as complete an implementation as in other languages on the TI. So far, it does everything I need it to do (and Im really not doing all that much). Not that its incomplete, and maybe its just the implementation style, but my first impression is that sprite implementation under Pascal has fewer helper methods as in other languages. 1 Quote Link to comment Share on other sites More sharing options...
+TheBF Posted October 24, 2017 Share Posted October 24, 2017 There are Sprites in the air it seems. I stayed up late last night trying to grok the ISR code for Sprite motion. My homemade sprite auto-motion system is wrong, but I don't understand exactly how. I was taking a velocity(x,y) (+ or - ) from an array and simply adding it to the current sprite position. This gave very ragged motion. I checked XB and the sprites are only moved 1 pixel at a time from what I can see regardless of the velocity used. (Classic99 debugger) So if anybody can explain what's going on with this ROM code I would be all ears. Like what is this auxiliary data in the motion table? This is from TI Intern, but I have added some my own comments to help me stay on track 093A C002 MOV 2,0 093C C0A2 MOV @>0002(2),2 Fetch INT address 093E 0002 0940 0692 BL *2 And execute 0942 C090 MOV *0,2 Next Int routine 0944 10F9 JMP >0938 0946 0460 B @>0AB8 End interrupt from CRU 0948 0AB8 094A 1D02 SBO >0002 Clear VDP interrupt 094C D060 MOVB @>83C2,1 Fetch interrupt flag byte 094E 83C2 0950 0A11 SLA 1,1 No interrupt permitted 0952 1702 JNC >0958 0954 0460 B @>0A84 then jump 0956 0A84 0958 0A11 SLA 1,1 095A 1846 JOC >09E8 No sprite move permitted, then jump 095C D320 MOVB @>837A,12 Number sprites -> R12 095E 837A 0960 1343 JEQ >09E8 IF sprite_cnt=0 then skip all this 0962 098C SRL 12,8 Move sprite count to other byte 0964 0202 LI 2,>8800 VDP RD -> R2 0966 8800 0968 0203 LI 3,>8C00 VDP WD -> R3 096A 8C00 096C 0208 LI 8,>0780 Sprite motion table -> R8 096E 0780 * begin loop for each sprite 0970 D7E0 MOVB @>83F1,*15 Write address motion table 0972 83F1 0974 D7C8 MOVB 8,*15 load Spr motion table to VDP Write address *===================================================== 0976 04C4 CLR 4 0978 D112 MOVB *2,4 read Motion table Y velocity ->R4 097A 04C6 CLR 6 097C D192 MOVB *2,6 read Motion table X X velocity->R6 097E 0844 SRA 4,4 ?? shift Y velocity right 4 0980 D152 MOVB *2,5 read Y Auxiliary sprite data->R5 0982 0845 SRA 5,4 shift Aux data 4 right (16/) 0984 A144 A 4,5 ADD R4->R5 *==================================================== 0986 D1D2 MOVB *2,7 Read Y Auxiliary sprite data-> R7 0988 0846 SRA 6,4 Shift X motion by 4 right 098A 0847 SRA 7,4 Shift X aux data 4 right 098C A1C6 A 6,7 Add R6->R7 098E 0228 AI 8,>FB80 Address sprite descriptor table 0990 FB80 0992 D7E0 MOVB @>83F1,*15 Write address 0994 83F1 0996 D7C8 MOVB 8,*15 ==================================================== 0998 04C4 CLR 4 099A D112 MOVB *2,4 Fetch Y position->R4 099C A105 A 5,4 add Y motion+aux+Ypos->R4 099E 0284 CI 4,>C0FF are we at X,Y limits (192,256) 09A0 C0FF 09A2 1209 JLE >09B6 if not off screen, goto 9B6 09A4 0284 CI 4,>E000 are we at start of screen ( 224,00) 09A6 E000 09A8 1B06 JH >09B6 if HI goto 9b6 09AA C145 MOV 5,5 else test for 0 09AC 1502 JGT >09B2 if R5>0 goto 09B2 09AE 0224 AI 4,>C000 ?? what is this for 09B0 C000 09B2 0224 AI 4,>2000 ?? and why add this 09B4 2000 09B6 04C6 CLR 6 *screen limit tests 09B8 D192 MOVB *2,6 09BA A187 A 7,6 09BC 0268 ORI 8,>4000 setup VDP address for writing 09BE 4000 09C0 D7E0 MOVB @>83F1,*15 09C2 83F1 09C4 D7C8 MOVB 8,*15 09C6 D4C4 MOVB 4,*3 Write X,Y positions to Spr. desc. table 09C8 0228 AI 8,>0482 ? 09CA 0482 09CC D4C6 MOVB 6,*3 09CE 06C5 SWPB 5 09D0 D7E0 MOVB @>83F1,*15 Write address motion table 09D2 83F1 09D4 D7C8 MOVB 8,*15 09D6 0945 SRL 5,4 09D8 D4C5 MOVB 5,*3 Write auxiliary values 09DA 06C7 SWPB 7 09DC 0947 SRL 7,4 09DE D4C7 MOVB 7,*3 09E0 0228 AI 8,>C002 New address motion table 09E2 C002 09E4 060C DEC 12 Last sprite? 09E6 15C4 JGT >0970 No, once again * end sprite loop 09E8 0A11 SLA 1,1 START of sound processing... Quote Link to comment Share on other sites More sharing options...
+adamantyr Posted October 24, 2017 Share Posted October 24, 2017 I've done a lot of sprite work in assembly language. I never use auto-motion; using VDP RAM at a specific place in memory for what is essentially just a velocity table array is silly when you can just store that (and more besides) in CPU RAM. All sprites move one pixel at a time, the difference is how many "ticks" of the VDP interrupt pass between movements. Your best bet is to just play with the numbers until you get the effect you want, I've done this myself with character movement and shot speed for my Gauntlet clone. 2 1 Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted October 24, 2017 Share Posted October 24, 2017 There are Sprites in the air it seems. I stayed up late last night trying to grok the ISR code for Sprite motion. ... Compare the TI Intern listing with ROM-4A.lst in the ZIP file at the end of post #1 of The TI-99/4A Operating System. It contains the comments of the original TI authors and might offer more insight. ...lee 1 Quote Link to comment Share on other sites More sharing options...
+TheBF Posted October 24, 2017 Share Posted October 24, 2017 Thanks Lee. That's a much nicer looking listing! Quote Link to comment Share on other sites More sharing options...
Rossman Posted October 25, 2017 Author Share Posted October 25, 2017 Amusing moment for the day when the sprites developed a mind of their own. This is not a complaint or a criticism or a confusion, just one of those moments when I realize I have to be precise in communicating my intentions via code. I'm working in a test bed just to familiarize myself with sprites in Pascal and how it will relate to my code. I mocked up a 10 of Hearts in a multiplied sprite, visually represented as a number (10) over the suite (heart), bitmapped. It looks crisp. If you're playing the game, you know you were dealt a 10 of Hearts, and not an eleventy-leven of blobulas. I setup a second card deal in my test code, which was largely a duplication of my first set of code (yes, shame!), to figure out multiple sprite motion. I am using two sprites for every card. Because the background color is always transparent on a sprite in Pascal, if you want some color for the background other than the screen background color, you need some other color wherever the sprite lands. So for convenience, I'm using a second sprite mapped to the x,y coordinate of where the first sprite will land. All I do is have a second sprite (of lower priority) waiting in that location with its color set to transparent, and at the moment the first sprite lands the second sprite changes is color from transparent to the color that I want (in this case, color 15). So I have a green background screen color, a white card background and a red or black foreground. It worked very nicely on the first sprite pair. And it worked on the second sprite pair. But then, after a second, the second sprite pair just ... took off, at different velocities, on the x axis. I don't know why the second pair choose to go in motion. Maybe they need to sow their wild oats. But I can't hang this on the p-code card. It was sloppy programming on my part. I had a countdown := 64 in the final packet declaration of both the first and second sprite pair. It didn't affect the first pair, but it did the second. I set the countdown to 0 on the foreground and background sprites, and they are staying put. I don't know why only the second pair was affected, but I'm not as concerned about it. I learned today via the early post from apersson850 that the p-code card has its own sprite movement code. And I am reminded that I need to be explicit in my intent. But it was kinda funny to see two sprites act on their own, goin' up the country. 1 1 Quote Link to comment Share on other sites More sharing options...
apersson850 Posted October 25, 2017 Share Posted October 25, 2017 I'd say that the p-system rather has more sprite support than most other languages/operating systems for the TI. It's the only system I know of that implements the ability to declare linked lists of sprite appearance, position and motion, and which will then execute these lists in parallel to what your program is doing. 1 Quote Link to comment Share on other sites More sharing options...
Rossman Posted October 25, 2017 Author Share Posted October 25, 2017 Well, my inexperience with sprites (especially of late - I havent coded a sprite in over 30 years) really came through in my earlier post! I will look up the specific helper methods I thought I saw in other languages to figure out why I got this impression. Quote Link to comment Share on other sites More sharing options...
Rossman Posted October 26, 2017 Author Share Posted October 26, 2017 I worked on the card flip logic tonight. Card is dealt via sprite from a (currently mythical) shoe, it arrives to the player, and it flips over to reveal it is a Hook of Clubs or a duck of Diamonds. I can integrate the card flip motion with a timed sprite motion so it looks like a fluid action. Just need to define a lot of runway for the motion. I've been working in the Classic99 emulator. Maximum props to @Tursi for this. I have no complaints or criticisms. I've learned more, faster, because of the emulator. I know what it was like to learn this 30 odd years ago. Humans were faster than the hardware when it came to asking, "why". I have noticed a few bad behaviors. I don't know if these are unique to the emulator or if I would encounter these on real iron with the p-code. This is just observation. One is that when I have a compile error in my sprite code - some overlooked typo on my part but always in a code block of... (linkname)^.packet : [something .. something] with (linkname)^ do begin .. code .. end; What I've found is that I'm more prone to ***STACK OVERFLOW*** errors. I didn't get any with my bog standard Pascal for developing the card logic. But I seem to be running into these more frequently when working with Sprites under Pascal. It's a minor inconvenience, but it is a definite change in the behavior of the compiler. Maybe it's just the compiler's way of telling me my code sucks big time. Maybe standard UCSD Pascal wouldn't do that, but some clever TI engineer figured out - temporally shifted, of course - it was time to let me know. Another is - and I don't have a great accounting for this - that sometimes in the Pascal editor in D)elete mode, the cursor occasionally moves backwards rather than forward when I delete using the spacebar! Easily adjusted to, sometimes only requires an exit - re-entry of the editor and never more than a warm reboot. Neither are complaints, just observations. It goes back to @apersson850 telling me that that the p-code is a world unto itself. But a craftsman never blames his tools. Both are reflections on my cave-man coding. 1 Quote Link to comment Share on other sites More sharing options...
Tursi Posted October 26, 2017 Share Posted October 26, 2017 Sadly I can't offer much insight as to whether p-Code card behaviors are emulation artifacts or not - I never used one in real life. This is one of the rare cases where I'd say compare to other emulators and see if they do it too - at least if it's easy to reproduce. Since Pascal is pure software I'd /expect/ the behavior to be correct, but it's amazing what subtle bugs one never considered can do. 1 Quote Link to comment Share on other sites More sharing options...
Rossman Posted October 26, 2017 Author Share Posted October 26, 2017 @Tursi, if I was a little more careful in my code I wouldn't have the exceptions in the first place. The offending s/w in question is entirely mine. It's naive on my part, but I never really thought much about how the p-code card is a world until @apersson850's post. I assumed more pass-through, but in making that assumption I'm not showing enough respect for it. And none of this is an obstacle to my little stick man card game. 1 Quote Link to comment Share on other sites More sharing options...
+mizapf Posted October 26, 2017 Share Posted October 26, 2017 @Rossman: MAME also has a complete P-system support, so you could give it a try, just for comparing. I can give you a quick summary how to get it going. 1 Quote Link to comment Share on other sites More sharing options...
unhuman Posted October 27, 2017 Share Posted October 27, 2017 (edited) Wait a minute!!! Gauntlet clone? I'm not going to let that slide. All sprites move one pixel at a time, the difference is how many "ticks" of the VDP interrupt pass between movements. Your best bet is to just play with the numbers until you get the effect you want, I've done this myself with character movement and shot speed for my Gauntlet clone. Edited October 27, 2017 by unhuman 2 Quote Link to comment Share on other sites More sharing options...
+TheBF Posted October 27, 2017 Share Posted October 27, 2017 (edited) I've done a lot of sprite work in assembly language. I never use auto-motion; using VDP RAM at a specific place in memory for what is essentially just a velocity table array is silly when you can just store that (and more besides) in CPU RAM. All sprites move one pixel at a time, the difference is how many "ticks" of the VDP interrupt pass between movements. Your best bet is to just play with the numbers until you get the effect you want, I've done this myself with character movement and shot speed for my Gauntlet clone. Thanks for this. Apologies for not replying faster. You are correct, I could play with the numbers to get what I want. I have been using a multi-tasking system for my Forth system and I re-created the ISR in a little task. Forth handles all this stuff like Assembler so I too use CPU RAM for my position and motion tables and the write the block of sprite positions to VDP RAM all at once. So I am on the right track there at least. :-) I have been reviewing the ISR code and looking at the debugger to see how it works. Here is what I think I see: 1. The Motion values are signed bytes. Positive: 0 to 7F, Negative: 80 to FF 2. The Aux values, beside each motion pair, are incremented every tick of the interrupt, by the amount in the motion value These are the little counters that run for each sprite's X and Y value. 3. When the AUX value rolls over the sprite is moved 1 pixel. So bigger values of Motion cause the AUX register to rollover faster of course therefore those sprite moves faster. So at this stage I am debating how best to handle this in Forth just to see what I can do without writing an ASM version. Forth deals with ints better than bytes so I am thinking that I will use 16 bit tables for motion and timers (AUX) and just shift the motion values to upper byte. Since everything is multiplied by >100 it will all count the same speed as using bytes, but my Forth operators will be faster for 16 bit values. That's all I have at this time. Thanks again for confirming my thoughts on the matter. Edited October 27, 2017 by TheBF 1 Quote Link to comment Share on other sites More sharing options...
Rossman Posted October 27, 2017 Author Share Posted October 27, 2017 @Rossman: MAME also has a complete P-system support, so you could give it a try, just for comparing. I can give you a quick summary how to get it going. Thank you @mizapf, at some point I will want to set up MAME just to do it. Classic99 is doing the job for me. Zero stack overflow errors tonight directly correlates to zero unforced errors in my code. For now, I want to concentrate on code, not infrastructure. I do not have an infrastructure problem. I did a simple lane change mock-up to show cards coming from the same shoe. It's just a math problem, but I did it because I wanted the satisfaction of doing it. #octalmath #base8rules #decimaldinosaurs I really need to be working on implementing the stick-man sprite visualizations with the game logic. What I've learned from the visualization tests is that it will significantly increase the size of the code base. Which tells me I really should refactor the game logic first, as it is plagued by the characteristics of someone re-learning structured programming. Thanks to everyone for your insights on sprites, they have changed the trajectory of how I see my path of re-learning Pascal progressing. 1 Quote Link to comment Share on other sites More sharing options...
+adamantyr Posted October 27, 2017 Share Posted October 27, 2017 Wait a minute!!! Gauntlet clone? I'm not going to let that slide. Oh, I wouldn't dare hijack the thread with such a thing! You'll just have to wait and see. Fair warning, I want to get the CRPG done first, which I'm aiming to do so in 2018, boom or bust. 1 Quote Link to comment Share on other sites More sharing options...
+mizapf Posted October 27, 2017 Share Posted October 27, 2017 Thank you @mizapf, at some point I will want to set up MAME just to do it. Classic99 is doing the job for me. Zero stack overflow errors tonight directly correlates to zero unforced errors in my code. For now, I want to concentrate on code, not infrastructure. I do not have an infrastructure problem. As you like. I did not want you to change the infrastructure, but just have a means of ruling out such issues. I think many of you still overestimate the efforts of installing MAME; it usually sounds like "when I have some free days" or "going to retire next year, mayby then". 1 1 Quote Link to comment Share on other sites More sharing options...
Rossman Posted October 27, 2017 Author Share Posted October 27, 2017 @mizapf Hahaha. Well said. I try to spend 2 hours a night coding, so it is just a question of making it a priority. It is something I want to do, though. Quote Link to comment Share on other sites More sharing options...
Rossman Posted October 28, 2017 Author Share Posted October 28, 2017 @mizapf I think I'll take you up on that MAME offer sooner rather than later. I went to add just one more sprite tonight to my test code, for the shoe. I was hoping to have a sprite in the foreground from which I could dispense a card (the background transparency should have made it look pretty good), move it due west (out of the shoe), then due north (direction of my test deal). This is the same routine as I've been through every night for the past week: these are just math problems. Only, the code won't compile. There's nothing obviously wrong, but I am encountering a **STACK OVERFLOW** mid-procedure that will otherwise compile when my additional code - mostly a few type declarations and what not - are commented out. This isn't an accusation about the emulator, but I need a comparison environment to isolate the source of the problem. It is entirely possible that the source of the problem is something I coded that is setting this off. Incremental code additions have yielded a STACK OVERFLOW mid-compile, for no obvious reason. But "no obvious reason" starts with me. I may have an errant instruction that is obvious to the compiler even if it isn't obvious to me. Also, this is test code that has grown recklessly. I may need to tighten the code so I can test the situation better. Still, having a MAME enviro might be an advantage. Quote Link to comment Share on other sites More sharing options...
Rossman Posted October 29, 2017 Author Share Posted October 29, 2017 I believe I have found the source of the problem. It has to do with how I structured my code. I couldn't understand why I was experiencing **STACK OVERFLOW** errors during compile. If I got this during runtime, I'd get it. But stack overflow during compile? Seems odd. This sprite code is experimentation code for me. I am modeling things that I want to try. This isn't production code, and I am not going to harvest anything but experience from this. So it isn't clean, it isn't modular, it isn't efficient. For example, I have a lot of separate string variables when I should have arrays. So in that regard, it's a bit caveman. Refactoring it was never important because I've just about completed my experiments. Only, as I neared my destination, I kept running into stack overflow. All of my sprites are double-sized, meaning they use 4 different character definitions. For reasons of convenience, I was declaring my sprite patterns as constants. For example: const crda = '3F20242C24242E20'; crdb = '202227272321203F'; crdc = 'F80848A8A8A84808'; crdd = '0888C8C8880808F8'; Yes, this should be an array, probably a packed array. But in my test code I only have one card face defined (just the 10 of hearts, not all 52 cards, this is experimental code!). But in addition to the card, I do have a background pattern, and a card flip sequence, and some other things. In all, I had 19 x 8 character string sprites defined. And that, I think, was what was causing all my stack overflow errors. So with that as my hypothesis, I eliminated the constant definition and moved the character pattern to the SET_PATTERN statement. No stack overflow errors at odd times during compile. It works just fine. It seems there is something I have to learn about limitations on constants. Maybe a memory limitation on how constants are treated. I wasn't creating highly modularized code here either, so maybe more to the point, I need to do better at creating modular code that is memory efficient. Well, and obviously, the converse is true: there is never an excuse for writing sloppy code. Which I did. My experiments need more discipline. 1 Quote Link to comment Share on other sites More sharing options...
apersson850 Posted November 7, 2017 Share Posted November 7, 2017 I've never suffered stack overflow during compile time on my 99/4A. But I do know that the handling of string constants is a bit peculiar in UCSD Pascal, so maybe you've run into something the system can't handle, even if it actually ought to. Quote Link to comment Share on other sites More sharing options...
Rossman Posted November 8, 2017 Author Share Posted November 8, 2017 I've never suffered stack overflow during compile time on my 99/4A. But I do know that the handling of string constants is a bit peculiar in UCSD Pascal, so maybe you've run into something the system can't handle, even if it actually ought to. I'm really glad you posted this. When I started coding my little game a few weeks ago, I expected that I would have to implement strings as packed arrays of type char. In reading my (old) 70's era Pascal academic books, it seems like string type was not indigenous to Pascal. I was pleasantly surprised to see that there is a native string type in UCSD on the TI. Do I understand this correctly? Were strings a later addition to Pascal? Quote Link to comment Share on other sites More sharing options...
apersson850 Posted November 8, 2017 Share Posted November 8, 2017 The data type string, which is different from a packed array of char in that the string also has a current length, is one of the extensions to standard Pascal (whatever that is) that you'll find in UCSD Pascal. The same design was used by Turbo Pascal 4.0, for example. That Turbo Pascal edition borrowed quite a lot from UCSD Pascal. Like the unit concept, too. I noticed another compiler thing you wrote about. If we assume this var a: array[0..3] of integer; b: array[0..3] of integer; Then they are frequently not considered to be of the same basic type. But if you do like this type arraytype = array[0..3] of integer; var a, b: arraytype; Then they are considered the same by the compiler. This works too var a: arraytype; b: arraytype; The type declaration makes the compiler consider them to be of the same basic type. Quote Link to comment Share on other sites More sharing options...
Recommended Posts
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.