After a bit over a week of heavy-duty Python coding, I'm ready to unveil the first beta of BranchMap, a tool to simplify tracing and debugging program flow in z80 ASM source code. It takes in a plaintext z80 source file, parses it and any files included in that source file, and generates a postscript or (optionally) PDF file containing a detailed representation of the program flow. It can do all of the following and more:

:: Displays all files, labels, and jumps in source file(s)
:: Tracks and tries to determine stack depth of all instructions. Looks for unreachable blocks.
:: Displays easy-to-read color-coded cross-file call/jump references
:: Can optionally track calls and bcalls
:: Can optionally graphically track intra-routine stack manipulation
:: Easy-to-use PS/PDF output files

I've used it pretty thoroughly, testing everything from simple contrived source to Invalid Tangram to the monstrous behemoth that is Doors CS 7-in-progress. Doors CS has the most strange and tricky code, and hence had the most strange interpretations of nonstandard code, but even within the 108-page summary it produced there was a ton of useful information that I will be using to help me develop and debug faster. I humbly request that you give this little program a download, run branchmap.py -h to see what you can do, and try out some of your own z80 ASM programs on it. I look forward to all your comments, criticisms, feedback, suggestions, bug reports, and feature requests.

BranchMap Beta 1 (Direct Download)

Fail with your platform-centric python.

Shebang lines, plzkthx.

Code:
#!/usr/bin/env python


[edit]

And your retarded line endings. Please use \n instead of \r\n. non-Windows Python interpreters don't like \r.

And don't put () around your print's. It spits out a tuple of strings instead of printing multiple separate items.


[edit]


Code:
[thomas@Bombadil] stratcon_dev $ branchmap -c -b -s -r -t stratcon.asm
 --+=====================+--
 --| BranchMap v0.1 beta |--
 --|   by Kerm Martian   |--
 --|   www.Cemetech.net  |--
 --|  admin@cemetech.net |--
 --+=====================+--
**Pass 1: Control Structure Extraction**
Searching through
Searching through dcs6.inc
Traceback (most recent call last):
  File "/Users/thomas/bin/branchmap", line 273, in <module>
    parsefile(rootfile,-1,-1,basepath,1)                #-1 = this is the root parent, [rootfile] has no parent
  File "/Users/thomas/bin/branchmap", line 111, in parsefile
    parsefile(fname, thisfilenum, linenum, abspath, mode)
  File "/Users/thomas/bin/branchmap", line 62, in parsefile
    fh = open(abspath+filename,'r')
IOError: [Errno 2] No such file or directory: 'stratcon.asmdcs6.inc'
elfprince13 wrote:
Fail with your platform-centric python.

Shebang lines, plzkthx.

Code:
#!/usr/bin/env python
Fixed.

elfprince13 wrote:
[edit]

And your retarded line endings. Please use \n instead of \r\n. non-Windows Python interpreters don't like \r.
Fixed.

elfprince13 wrote:
And don't put () around your print's. It spits out a tuple of strings instead of printing multiple separate items.
Can you give me an example of where I do that?

elfprince13 wrote:
[edit]


Code:
[thomas@Bombadil] stratcon_dev $ branchmap -c -b -s -r -t stratcon.asm
 --+=====================+--
 --| BranchMap v0.1 beta |--
 --|   by Kerm Martian   |--
 --|   www.Cemetech.net  |--
 --|  admin@cemetech.net |--
 --+=====================+--
**Pass 1: Control Structure Extraction**
Searching through
Searching through dcs6.inc
Traceback (most recent call last):
  File "/Users/thomas/bin/branchmap", line 273, in <module>
    parsefile(rootfile,-1,-1,basepath,1)                #-1 = this is the root parent, [rootfile] has no parent
  File "/Users/thomas/bin/branchmap", line 111, in parsefile
    parsefile(fname, thisfilenum, linenum, abspath, mode)
  File "/Users/thomas/bin/branchmap", line 62, in parsefile
    fh = open(abspath+filename,'r')
IOError: [Errno 2] No such file or directory: 'stratcon.asmdcs6.inc'
Fixed by using Python os.path library instead of my own path parsing.

Elfprince, I can send you an updated program for continued testing, or you can download it from the front page again, as I have updated that file.
I'll just redownload it. And check out disphelp() for the erroneous printing.


Code:

 --+=====================+--
 --| BranchMap v0.1 beta |--
 --|   by Kerm Martian   |--
 --|   www.Cemetech.net  |--
 --|  admin@cemetech.net |--
 --+=====================+--
**Pass 1: Control Structure Extraction**
Searching through stratcon.asm
Searching through dcs6.inc
-------------------------------
**Pass 1**: Final Summary:
   35 branches
   48 calls
   13 bcalls
   106 labels

**Pass 2: Stack Depth Analysis**
**Pass 2**: Final Summary:
   392 labels/instructions adjusted
   3 stack manipulation warnings

**Pass 3: Postscript Generation**
Traceback (most recent call last):
  File "/Users/thomas/bin/branchmap", line 388, in <module>
    str(labels[labelindex-1][1][2]) + ":) show\n")
TypeError: can't multiply sequence by non-int of type 'float'
Are you using a Python 3 interpreter? Do I have to force that somewhere? Anyway, here's what I get for disphelp():


Code:
C:\Users\Christopher Mitchell\Documents\Calc\BranchMap>branchmap.py -h
 --+=====================+--
 --| BranchMap v0.1 beta |--
 --|   by Kerm Martian   |--
 --|   www.Cemetech.net  |--
 --|  admin@cemetech.net |--
 --+=====================+--

 BranchMap Help Menu:
======================
 branchmap.py [-hcbp] [asmfile]
 -h:     Display this help menu
 -c:     Show calls in map file
 -b:     Show bcalls in map file
 -p:     Use ps2pdf to convert PS to PDF
 -s:     Show push/pop stack manipulation
 -r:     Display breaks between routines (best-guess)
 -t:     Show tabguides
 -a:     Verbose output, equivalent to "-c -b -p -s"
 asmfile: A z80 assembly-language file to parse


Edit: Also, I'm confused why Python would be interpreting the following as a float:


Code:
" "*(4-math.floor(mate h.log10(labels[labelindex-1][1][1])))

Nevertheless, I changed line 386 to this, see if that does the trick for you.


Code:
            " "*int(4-math.floor(math.log10(labels[labelindex-1][1][1]))) + \
KermMartian wrote:
Are you using a Python 3 interpreter? Do I have to force that somewhere? Anyway, here's what I get for disphelp():


Code:
C:\Users\Christopher Mitchell\Documents\Calc\BranchMap>branchmap.py -h
 --+=====================+--
 --| BranchMap v0.1 beta |--
 --|   by Kerm Martian   |--
 --|   www.Cemetech.net  |--
 --|  admin@cemetech.net |--
 --+=====================+--

 BranchMap Help Menu:
======================
 branchmap.py [-hcbp] [asmfile]
 -h:     Display this help menu
 -c:     Show calls in map file
 -b:     Show bcalls in map file
 -p:     Use ps2pdf to convert PS to PDF
 -s:     Show push/pop stack manipulation
 -r:     Display breaks between routines (best-guess)
 -t:     Show tabguides
 -a:     Verbose output, equivalent to "-c -b -p -s"
 asmfile: A z80 assembly-language file to parse


Edit: Also, I'm confused why Python would be interpreting the following as a float:


Code:
" "*(4-math.floor(mate h.log10(labels[labelindex-1][1][1])))

Nevertheless, I changed line 386 to this, see if that does the trick for you.


Code:
            " "*int(4-math.floor(math.log10(labels[labelindex-1][1][1]))) + \


Ah, no I'm not, I only have Python 2.5 installed. You could probably force python 3 with the shebang line somehow, or better yet would be to use sys.version_info and replace your print()s with something like this:

Code:

def safeprint(*args):
 mver = sys.get_info[0]
 if mver == 3:
   print(*args)
 else:
   for i,arg in enumerate(args):
     if i<(len(args)-1):
        print arg,
     else:
        print arg



although that probably isn't python 3 friendly, now that I think about it.
It won't let me use that code, since print[space] is no longer valid code. Any other suggestions?
KermMartian wrote:
It won't let me use that code, since print[space] is no longer valid code. Any other suggestions?
Put it in a string and "exec" it? That way it won't be compiled unless it's in the correct version.
actually, you should be able to use normal print() in python 2.5, as long as its just parentheses and not a tuple. so just use the .version_info to decide whether to print(" ".join([str(arg) for arg in args])) or to print(*args)
elfprince13 wrote:
actually, you should be able to use normal print() in python 2.5, as long as its just parentheses and not a tuple. so just use the .version_info to decide whether to print(" ".join([str(arg) for arg in args])) or to print(*args)
Hey, that did the trick:


Code:
def safeprint(*args):
    mver = sys.version_info[0]
    if mver == 3:
        print(*args)
    else:
        print(" ".join([str(arg) for arg in args]))


Edit: Updated the zip in the archives again. Testing would be much appreciated, and thanks for all your help already, elfprince. Smile
oh. meh. it doesn't work on the Python 2.5 end. I'd recommend just using the join for both, now that I think about it.
elfprince13 wrote:
oh. meh. it doesn't work on the Python 2.5 end. I'd recommend just using the join for both, now that I think about it.
Done and done. Hopefully everything's working cross-platform and cross-version now, so we can work on the actual functionality of the program and where it fails. Smile
hehe.


Code:
**Pass 3: Postscript Generation**
Traceback (most recent call last):
  File "/Users/thomas/bin/branchmap", line 462, in <module>
    "] "+" "*5*(tabs+1))
TypeError: can't multiply sequence by non-int of type 'float'


You might want to consider getting a python 2.5 installation to test this on to expediate the process Wink
Elfy, done and done. I was able to get identical dcs6 outputs on Ubuntu + Python 2.5.2 and Windows 7 + Python 3.1.1.
stratcon.asm


Code:
BranchMap Summary File for stratcon.asm
ASM File List:
1) stratcon.asm
2) dcs6.inc
Project Statistics
Total branches: 35
Total calls: 48
Total bcalls: 13
Total labels: 106
stratcon.asm
   [27] INIT:
   [30]      Start
   [39] filetype:
   [41] Icon:
   [44] IconAP:
   [47] START:
c  [50]      dispttl
b  [51]      _cleargbuf ?????
b  [52]      _ClrLcdf ?????
   [71] rerender:
   [75] stackfix:
   [77]      [!]
    tilemapiloop2
   [78] tilemapdisp:
c  [84]      orLargeSprite
c  [89]      orPutSprite
   [91] tilemapiloop:
   [93] tilemapiloop2:
c  [98]           getMapPixel
  [100]           tilemapiloopdland
  [101] tilemapiloopdwater:
c [105]                h_times_e
c [111]                h_times_e
  [116]           endtilemapiloop2
  [117] tilemapiloopdland:
c [121]                h_times_e
c [127]                h_times_e
  [132] endtilemapiloop2:
c [133]           orPutSprite
  [138]      stackfix
  [139] endtilemapiloop:
  [143]      [!]
    tilemapiloop
  [145] openmap:
  [150]      failopen
  [153]      failopen
  [158]      failopen
  [161]      failopen
  [164]      failopen
b [170]      _cleargbuf ?????
b [171]      _clrlcdfull ?????
c [173]      aploadedmap
  [176] failopen:
  [182] savepwin:
  [192] spwyb:
  [198] spwnb:
  [204] spwcb:
  [210] spwt:
  [215] makesaveprompt:
  [222] setsavey:
  [227] setsaven:
  [231] setsavec:
  [238] addmap:
  [249] mapper:
  [254] maphscroll:
  [260] mapvscroll:
  [266] mapqbuttoni:
  [278] mapqbuttonh:
  [283] scrollup:
  [285] scrolldown:
  [287] scrollright:
  [289] scrollleft:
  [294] loadmap:
b [299]      _cleargbuf ?????
b [300]      _ClrLcdf ?????
c [301]      seed
  [303] aploadedmap:
b [304]      _cleargbuf ?????
c [305]      addmap
c [307]      CloseGUIStack ?????
  [309] mquit:
c [312]      makesaveprompt
  [315] quit:
c [317]      CloseGUIStack ?????
  [319] Apstart:
c [323]           dispttl
b [324]           _cleargbuf ?????
c [329]      aploadedmap
  [335] smloadwin:
  [345] loadmtxt:
  [350] stwin:
  [359] smb:
  [365] openb:
  [371] quitb:
  [377] logo:
  [382] GameType1:
  [388] GameType2:
  [394] GameType3:
  [400] GameType4:
  [406] LevelScroll:
  [413] LevelTxt:
  [418] edittxt:
c [419]      GUIFindFirst ?????
  [421] lgetloop:
c [423]           GUIFindNext ?????
  [425]      lgetloop
c [434]           GUIFindNext ?????
b [439]           _MultAbyE ?????
b [452]      _strcpy ?????
  [455] city:
  [460] tank:
  [469] spr_battleship:
  [471] spr_bomber:
  [473] spr_carrier:
  [475] spr_city:
  [477] spr_destroyer:
  [479] spr_fighter:
  [481] spr_land:
  [483] spr_invert:
  [485] spr_smoke:
  [487] spr_sub:
  [489] spr_tank:
  [491] spr_transport:
  [497] ltxt:
  [509] seed:
c [516]      ionRandom ?????
  [521] seedjump:
c [524]           ionRandom ?????
c [529]           ionRandom ?????
c [535]           getMapPixel
c [538]           popisland
  [540]      seedjump
  [543] popisland:
c [554]      H_Times_E
  [556] islandloop:
c [561]                ionRandom ?????
c [566]           ionRandom ?????
c [573]           ionRandom ?????
c [577]           getMapPixel
  [584]      islandloop
  [588] H_Times_E:
  [592] _loop:
  [594]      _skip
  [596] _skip:
  [597]      _loop
  [600] getMapPixel:
  [620] getPixelLoop:
  [622]      getPixelLoop
  [627] dispttl:
c [631]      DispRLE ?????
c [633]      DispRLE ?????
  [635] CopyAgain:
c [636]      RIGCopyTBLR
  [639] KeyCheck:
  [646]      exttl
  [648]      KeyCheck
  [651] DoDelay:
  [653]       ?????
  [655]      DoDelay
  [658] FixedDelay:
  [662]      FixedDelay
  [664]      CopyAgain
  [666] exttl:
b [668]      _ClrLcdf ?????
b [669]      _HomeUp ?????
b [670]      _GetCSC ?????
  [676] RIGCopyTBLR:
  [687]      RC_SkipHL2
  [689] RC_SkipHL2:
  [693] RC_HLoop:
  [699] RC_Rotate:
  [701] RC_VLoop:
  [706]      RC_Wait
  [710] RC_NotL1:
  [718]      RC_VLoop
  [723] RC_LdA:
  [727]      RC_HLoop
  [729] RC_SP:
  [733] RC_Wait:
  [734]      RC_NotL1
  [737] RLE_Image:
  [784] map_header_bar:
  [797] orPutSprite:
  [814] putSpriteLoop1:
  [815] sl1:
  [819]      putSpriteSkip1
  [820] putSpriteLoop2:
  [824]      putSpriteLoop2
  [825] putSpriteSkip1:
  [836]      putSpriteLoop1
  [838] orLargeSprite:
  [860] largeSpriteLoop1:
  [862] largeSpriteLoop2:
  [867]                largeSpriteSkip1
  [868] largeSpriteLoop3:
  [872]                largeSpriteLoop3
  [873] largeSpriteSkip1:
  [887]                largeSpriteLoop2
  [894]           largeSpriteLoop1
dcs6.inc



ipaint.asm

Code:
BranchMap Summary File for ipaint.asm
ASM File List:
1) ipaint.asm
2) dcs6.inc
Project Statistics
Total branches: 46
Total calls: 29
Total bcalls: 15
Total labels: 100
ipaint.asm
   [54] INIT:
   [57]      Start
   [66] filetype:
   [68] Icon:
   [72] IconAP:
   [75] START:
c  [76]      dispttl
b  [77]      _cleargbuf ?????
b  [78]      _ClrLcdf ?????
   [86] rerender:
   [91] APStart:
c  [93]           dispttl
b  [94]           _cleargbuf ?????
b  [95]           _clrlcdfull ?????
   [97]           OpenHandler2
   [99] OpenHandler:
  [104]      failopen
  [107]      failopen
  [112]      failopen
  [115]      failopen
  [118]      failopen
  [121] OpenHandler2:
  [126] OpenHandler3:
b [127]      _cleargbuf ?????
b [128]      _clrlcdfull ?????
  [133] drerender:
  [136] failopen:
  [141] NewHandler:
b [146]      _memclear ?????
  [147]      OpenHandler3
  [149] PatienceHandler:
  [160] ImportHandler:
  [170] ExpDialog:
c [183]      MakeExpSelPrompt
  [186] AskSave:
c [199]      MakeSavePrompt
  [202] Quit:
  [207] DrawHandler:
  [219]           PixOn
  [221]           PixFlip
  [230]           PixOff
  [240]      DrawQuit
  [242]      PicExport
  [243] DrawCont:
  [245] PixOn:
c [249]      iGetPixel2
c [252]      mouseGetMask
  [255]      DrawCont
  [256] PixOff:
c [260]      iGetPixel2
c [264]      mouseGetMask
  [268]      DrawCont
  [269] PixFlip:
c [273]      iGetPixel2
c [276]      mouseGetMask
  [279]      DrawCont
  [280] DrawQuit:
  [287] PicExport:
  [295] makesaveprompt:
  [303] makeexpselprompt:
  [311] setsavey:
c [316]      FileSaveAs ?????
  [320] setsavec:
  [323]      drerender
  [325] setexpy:
  [327] setexpc:
  [330] hlFastCopy:
  [333] setrow:
  [336]      setrow
  [341] col:
  [343] colwait:
  [346]           colwait
  [351] row:
  [354]           row
  [358]           row
  [366]      col
  [372] iGetPixel2:
  [399] getPixelLoop2:
  [401]      getPixelLoop2
  [405] mouseGetMask:
  [412] mouseGetLoop:
  [414]      mouseGetLoop
  [427] rDetect:
b [428]      _cphlde ?????
  [430]      rDetectContinue
  [433] rDetectContinue:
  [436]           rDetectSkip
  [450]                rDetectNoMove
b [452]                     _memfree ?????
  [456]                rDetectNotEnough
b [461]                               _flashToRam ?????
  [475] rDetectNoMove:
  [485] rDetectCheck:
  [488]                     rDetectFound
  [493]                     rDetectCheck
  [494] rDetectBad:
  [496] rDetectNotEnough:
  [498] rDetectSkip:
  [504] rDetectNameLoop2:
  [506]      rDetectNameLoop2
  [507]      rDetect
  [508] rDetectFound:
  [512]           rDetectInRam
b [516]                          _enoughRam ?????
  [518]                     rDetectBad
b [523]                _flashToRam ?????
  [525] rDetectInRam:
  [531] rDetectNameLoop1:
  [533]      rDetectNameLoop1
  [537] dispttl:
c [541]      DispRLE ?????
c [543]      DispRLE ?????
  [545] CopyAgain:
c [546]      RIGCopyTBLR
  [549] KeyCheck:
  [556]      exttl
  [558]      KeyCheck
  [561] DoDelay:
  [563]       ?????
  [565]      DoDelay
  [568] FixedDelay:
  [572]      FixedDelay
  [574]      CopyAgain
  [576] exttl:
b [578]      _ClrLcdf ?????
b [579]      _HomeUp ?????
b [580]      _GetCSC ?????
  [586] RIGCopyTBLR:
  [597]      RC_SkipHL2
  [599] RC_SkipHL2:
  [603] RC_HLoop:
  [609] RC_Rotate:
  [611] RC_VLoop:
  [616]      RC_Wait
  [620] RC_NotL1:
  [628]      RC_VLoop
  [633] RC_LdA:
  [637]      RC_HLoop
  [639] RC_SP:
  [643] RC_Wait:
  [644]      RC_NotL1
  [647] OpenButton:
  [653] NewButton:
  [659] ImportButton:
  [665] QuitButton:
  [676] PatienceWin:
  [686] PleaseWaitTxt:
  [691] PencilCursor:
  [713] LoelHax:
  [718] ExpHax:
  [723] savepwin:
  [733] spwyb:
  [739] spwnb:
  [745] spwcb:
  [751] spwt:
  [756] ExportSelWin:
  [766] ExpSA:
  [772] ExpCancel:
  [778] ExpBG:
  [784] ExpPic:
  [790] ImportSelWin:
  [801] RLE_Image:
  [802] Layer1:
  [826] Layer2:
  [848] MainMenu:
  [898] Pic1name:
  [900] Pic2name:
  [902] Pic3name:
  [904] Pic4name:
  [906] Pic5name:
  [908] Pic6name:
  [910] Pic7name:
  [912] Pic8name:
  [914] Pic9name:
  [916] Pic0name:
dcs6.inc



aDrive.asm

Code:
BranchMap Summary File for aDrive.asm
ASM File List:
1) aDrive.asm
2) dcs6.inc
3) usb8xspasm.inc
Project Statistics
Total branches: 19
Total calls: 26
Total bcalls: 0
Total labels: 80
aDrive.asm
   [44] INIT:
   [47]      Start
   [53] Icon:
   [56] Start:
   [66]      TI83p
   [69]      TI84p
   [71]      TI83p
   [72] TI84p:
   [74]      NOUSB
   [81]      NOUSB
   [85]      TI83p
   [89]      USBERR
   [91]      USBERR
   [93]      USBERR
c  [96]      quit
   [97] TI83p:
  [103] NOUSB:
  [109] USBERR:
c [117]      MakeErrText
c [121]           StrCpy
c [124]      StrCpy
c [126]      StrByteCount
c [138]      PushGUIStack ?????
  [141] MakeErrText:
  [144]      CSwitch
  [146]      CSwitch
  [148]      CSwitch
  [149] GetErrLabel:
  [163] CSwitch:
  [165]      GetErrLabel
  [167] quit:
  [176] mousequit:
c [178]      quit
  [180] Stub:
  [183] errorwin:
  [193] okbutton:
  [199] ti83ptext:
  [204] usb8xtext:
  [209] GUIBar:
  [222] DCSName:
  [224] USBName:
  [226] DCSPage:
  [228] USBPage:
  [231] ERRLut:
  [279] err0:
  [281] err1:
  [283] err2:
  [285] err3:
  [287] err4:
  [289] err5:
  [291] err6:
  [293] err7:
  [295] err8:
  [297] err9:
  [299] err10:
  [301] err11:
  [303] err12:
  [305] err13:
  [307] err14:
  [309] err15:
  [311] err16:
  [313] err17:
  [315] err18:
  [317] err19:
  [319] err20:
  [321] err21:
  [323] err22:
  [325] err23:
  [327] err24:
  [329] err25:
  [331] err26:
  [333] err27:
  [335] err28:
  [337] err29:
  [339] err30:
  [341] err31:
  [343] err32:
  [345] err33:
  [347] err34:
  [349] err35:
  [351] err36:
  [353] err37:
  [355] err38:
  [357] err39:
  [359] err40:
  [361] err41:
  [363] err42:
  [365] err43:
  [367] err44:
  [369] err45:
  [371] err46:
  [375] StrCpy:
  [380] StrCpyN_Lp:
  [384]                StrCpyN_Lp
  [389] StrLen:
  [391] StrLen_Lp:
  [397]      StrLen_Lp
  [399] StrByteCount:
  [401] StrBC_Lp:
  [407]      StrBC_Lp
dcs6.inc
usb8xspasm.inc
  [343] uuAppName:
  [345] uuDriverCode:
c [349]           uuCall1 ?????
c [351]      USBDriverEntryPoint ?????
  [358] uuCallBack:
c [362]      label ?????
  [369] uuDone:

this was accompanied by the following message
Quote:
**Pass 3: Postscript Generation**
**Pass 3**: Completed. Output written to aDrive.ps
2 jumps/instructions were not rendered. This is likely because they are part of a jump table; BranchMap is unable to correctly determine flow around memory-indexed constructions such as jump tables, so it has likely discarded what it thinks are unreachable jumps. It may have legitimately discarded unreachable code, however.
Total time: 0.0s
That all looks good to me, do you find it to be accurate? The most interesting thing I see there is that it thinks it took 0.0 seconds.
It's pretty darn fast for programs the size of mine. The accuracy seems to be pretty good. I don't see anything obviously amiss, though my memory of the flow of those programs might be pretty shaky.
Oh right, I forgot about making one of these. I had more important things to do, like, uh, watch old episodes of Top Gear.
  
Register to Join the Conversation
Have your own thoughts to add to this or any other topic? Want to ask a question, offer a suggestion, share your own programs and projects, upload a file to the file archives, get help with calculator and computer programming, or simply chat with like-minded coders and tech and calculator enthusiasts via the site-wide AJAX SAX widget? Registration for a free Cemetech account only takes a minute.

» Go to Registration page
Page 1 of 1
» All times are UTC - 5 Hours
 
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

 

Advertisement