dleigh Posted March 31, 2006 Posted March 31, 2006 I recently discovered AutoIt and am very pleased! My reason for finding it was to figure out a way to automate a specific tedious task in Quicken 2005. I needed to get a whole bunch of "cash transaction" from a cash account and assign them to a "miscellaneous" category in a split transaction in a different account...sometimes with different currencies. Quicken comes up short! I'm listing my code below, not because it's any great code or hugely reusable out of the box. I'm an AutoIt Newbie after all! :"> I'm posting it here so that eventually when other poor Quicken saps like me are looking for some (automation) port in the (Quicken) storm, their search may land them here in AutoIt land, and they might find a snippet that helps them...maybe!Many thanks to all you who have contributed to make AutoIt what it is! expandcollapse popup;This script requires that you be positioned on a split transaction ;that you want to search to see if there are any miscellaneous ;categorized transactions. Opt("WinWaitDelay",250) Opt("WinTitleMatchMode",1) Opt("WinDetectHiddenText",1) Opt("MouseCoordMode",0) Opt("SendKeyDelay", 100) Opt("TrayIconDebug", 1) ;0=no info, 1=debug line info #include <Array.au3> ;URL for getting currency rates from OANDA ;http://www.oanda.com/convert/fxdaily?value=1&date_fmt=us&lang=en&exch=USD&exch2=&expr2=&format=CSV&dest=Get+Table&sel_list=CHF_EUR_GBP&date=03/29/06&redirected=1 ;load the currency table with the data from OANDA in the CSV format from the ;above URL. Add the YEAR and the Quicken currency symbol used in the title of the accounts Dim $CurrTable[1][1] ;12/31/2005 LoadCurrTable("2005,FS,Swiss Franc,CHF,0.7602,1.3159") LoadCurrTable("2005,Euro,Euro,EUR,1.1844,0.8444") LoadCurrTable("2005,£,British Pound,GBP,1.7208,0.5813") ;03/29/2006 LoadCurrTable("2006,FS,Swiss Franc,CHF,0.766,1.3059") LoadCurrTable("2006,Euro,Euro,EUR,1.204,0.8306") LoadCurrTable("2006,£,British Pound,GBP,1.748,0.5722") ReDim $CurrTable[UBound($CurrTable,1)-1][ubound($CurrTable,2)] ;general variable declarations dim $saveAcct, $saveCurr, $splitCat, $winText, $saveMisc, $currAcct, $saveYear dim $thisRef, $QIFFile, $miscLine, $xchngRate, $preDeleteAcct, $cashCurr, $cashAcct ;Quicken account array dim $QckAcctArr[15];this is the list of accounts in the order on the Quicken ;account list screen. It is hard-coded in this application ;because, there are situations (trust me) where you just can't ;be sure that you've arrived at a given account if you don't ;have this list! This has been a REAL PAIN to code around!!! $QckAcctArr[1] = "Cash: Cash Euros" $QckAcctArr[2] = "Cash: Cash Pounds" $QckAcctArr[3] = "Bank Of Scotland Current" $QckAcctArr[4] = "Bank Of Scotland EasyCash" $QckAcctArr[5] = "BNP Paribas" $QckAcctArr[6] = "BNP Paribas Savings" $QckAcctArr[7] = "ECCU Checking" $QckAcctArr[8] = "La Poste" $QckAcctArr[9] = "Société Générale Checking" $QckAcctArr[10] = "Prudential Command Checking" $QckAcctArr[11] = "#Pre-Delete Euro#" $QckAcctArr[12] = "#Pre-Delete FS#" $QckAcctArr[13] = "#Pre-Delete £#" $QckAcctArr[14] = "Cash Dollars" ;constants const $ScriptTitle = "Fill Quicken Misc Split Lines" const $mainScreen = "Quicken 2005 Premier Home & Business" Const $QFileConst = " - QDATA1 - [" const $fillCat = "Groceries";for the small amounts left over const $fillMemo = "Our Bread tab";for the small amounts left over const $mmdd = @MON & @MDAY const $filePath = "C:\Documents and Settings\David\My Documents\Financial Account Activity\" const $fileName = "#MiscTxnsCopied_" & @YEAR & @MON & @MDAY & "_" & @HOUR & @MIN & @SEC & ".qif" ;****************************************************************** ;****************************************************************** ;* MAINLINE PROCESSING ;****************************************************************** ;****************************************************************** ;Allow the user to specify from which account to get the Misc cash ;txns and appropriate exchange rates #include <GUIConstants.au3> ; == GUI generated with Koda == $Form1 = GUICreate("Allocate Cash to Quicken Misc Split Lines", 357, 123, 192, 125) $AcctList = GUICtrlCreateList("", 8, 24, 129, 58, -1, $WS_EX_CLIENTEDGE) GUICtrlSetData(-1, "Cash Euros,Euro|Cash Pounds,£|Cash Swiss Francs,FS","Cash Euros,Euro") GUICtrlCreateLabel("Select Which Cash Account You Want To Use", 8, 8, 227, 17) $OKButton = GUICtrlCreateButton("OK", 8, 88, 43, 25,$BS_DEFPUSHBUTTON ) $CancelButton = GUICtrlCreateButton("Cancel", 64, 88, 75, 25) GUISetState(@SW_SHOW) While 1 $msg = GuiGetMsg() Select Case $msg = $GUI_EVENT_CLOSE MsgBox(0,$ScriptTitle,"Script Execution Canceled at User's Request") Exit Case $msg = $OKButton EstablishExchangeRate(GUICtrlRead($AcctList)) ExitLoop;go on with the rest of the script Case $msg = $CancelButton MsgBox(0,$ScriptTitle,"Script Execution Canceled at User's Request") Exit EndSelect WEnd ;Ok, now that we've started our macro, let's get back to Quicken WinActivate($mainScreen) ;Determine what account and currency we're in so that we can go back to it: $saveAcct = WinGetTitle("") $saveAcct = StringRight($saveAcct,StringLen($saveAcct)-StringInStr($saveAcct,"[")) $saveAcct = StringLeft($saveAcct,StringLen($saveAcct)-1) $saveCurr = StringRight($saveAcct,StringLen($saveAcct)-StringInStr($saveAcct,"(")) $saveCurr = StringLeft($saveCurr,StringLen($saveCurr)-1) $saveAcct = StringLeft($saveAcct,StringInStr($saveAcct,"(")-2) $currAcct = $saveAcct ;save the date of the current transaction to use to find others in the same year send("{TAB}{HOME 2}") $winText = StringSplit(WinGetText($mainScreen),@CRLF) for $i = 0 to UBound($winText) - 1 $dateTest = StringSplit($wintext[$i],"/") if UBound($dateTest) = 4 Then $datetest[3] = StringLeft($datetest[3],4) if $dateTest[1] > 0 and $dateTest[1] < 13 and _ $dateTest[2] > 0 and $dateTest[2] < 32 and _ $dateTest[3] > 1999 then $saveYear = $dateTest[3] $i = UBound($wintext) EndIf EndIf Next ;determine the exchange rate that we will use if $cashCurr = $saveCurr Then $xchngRate = 1 Else ;this will be for if you are going into a dollar account for $i = 0 to UBound($CurrTable) - 1 if $CurrTable[$i][0] = $saveYear and _ $CurrTable[$i][1] = $cashCurr Then $xchngRate = $CurrTable[$i][5] ExitLoop EndIf Next if $saveCurr <> "$" Then ;this will be for if you are going into a non-dollar account for $i = 0 to UBound($CurrTable) - 1 if $CurrTable[$i][0] = $saveYear and _ $CurrTable[$i][1] = $saveCurr Then $xchngRate = $xchngRate / $CurrTable[$i][5] ExitLoop EndIf Next EndIf EndIf ;Go into the "split" screen and search for a "Miscellaneous" entry $miscLine = GetMiscLine() Dim $saveTxn[31 - $miscLine][6];calculate how many open slots we have to fill with ;split transactions. Assume that the "Misc" txn is ;the only one in the SPLIT and that it's the last ;filled in line if $winText[4] <> "Miscellaneous" Then MsgBox(0,$ScriptTitle,"No (more) Miscellaneous category items");No (more) misc category items in this split box Exit Else Send("{TAB 4}");Tab over to the amount column and store it WinWaitActive("Split Transaction") $winText = StringSplit(WinGetText("Split Transaction"),@CRLF) $saveMisc = $winText[4] Send("!O");press the OK button and get out EndIf ;Go to the cash account and find transactions to apply to the misc amount $currAcct = SwitchAccts($currAcct,$cashAcct) ;Make sure the transactions have a unique identifier AssignTxnIds() ;fiter the transactions for payments in the same year FilterTxns($saveYear) ;Save the 1st txn for an "end of file" condition check and ;position to find the largest amount within the same year WinWaitActive($mainScreen) send("!v");show the dropdown menu of how to view the register send("{DOWN 3}");choose the third option send("{ENTER}") send("{HOME 4}");go to the 1st txn in the register SaveTxnDetails(UBound($saveTxn)-1);save the 1st txn to check "end of file" in the register send("{END 4}");go to the end of the register send("{HOME 2}");go to the date field send("{UP}");one up ;loop through the transactions and accumulate enough to offset ;the misc amount $j = 1 Opt("SendKeyDelay", 1) SaveTxnDetails($j) While $j < UBound($saveTxn)-2 if $saveTxn[$j][1] = $saveTxn[UBound($saveTxn)-1][1] Then ExitLoop EndIf ;don't go into negative amounts here If AmountRemaining($saveMisc) < 0 Then $saveTxn[$j][0] = "" $saveTxn[$j][1] = "" $saveTxn[$j][2] = "" $saveTxn[$j][3] = "" $saveTxn[$j][4] = "" $saveTxn[$j][5] = "" else $j = $j + 1 EndIf send("{UP}") SaveTxnDetails($j) WEnd Opt("SendKeyDelay", 100) ;deal with a negative condition or ;the fact that we've taken the "eof" transaction ;(that we need to keep there for positioning purposes) If AmountRemaining($saveMisc) < 0 or _ $saveTxn[$j][1] = $saveTxn[UBound($saveTxn)-1][1] Then $saveTxn[$j][0] = "" $saveTxn[$j][1] = "" $saveTxn[$j][2] = "" $saveTxn[$j][3] = "" $saveTxn[$j][4] = "" $saveTxn[$j][5] = "" EndIf ;confirm with the user if they want to use these transactions $tempstr = "Use up this 'Misc' amount: " & $saveMisc & " with the following:" & @LF & "********************************************" & @lf for $l = 1 to UBound($saveTxn) - 2 if $saveTxn[$l][3] = "" Then ExitLoop EndIf $tempstr = $tempstr & $saveTxn[$l][3] & " - " & $saveTxn[$l][4] & @lf Next $tempstr = $tempstr & "*****************************************" & @LF & "'OK' to transfer the above transactions to the Misc split" & @LF _ & "'CANCEL' to cancel this operation" $prompt = MsgBox(1,$ScriptTitle,$tempstr) ;get out if they pressed cancel if $prompt = 2 Then WinWaitActive($mainScreen) ControlFocus($mainScreen,$currAcct,"Close Filter") WinWaitActive($mainScreen) ControlClick($mainScreen,$currAcct,"Close Filter") WinWaitActive($mainScreen) Exit EndIf ;save the QIF file first $QIFFile = FileOpen ( $filePath & $fileName, 1 ) FileWriteLine($QIFFile, "!Type:Cash") for $m = 1 to UBound($saveTxn) - 2 if $saveTxn[$m][3] = "" then ExitLoop;quit writing at empty transactions FileWriteLine($QIFFile, "D" & $saveTxn[$m][0]) ;date FileWriteLine($QIFFile, "U-" & $saveTxn[$m][3]);amount FileWriteLine($QIFFile, "T-" & $saveTxn[$m][3]);amount again FileWriteLine($QIFFile, "N" & $saveTxn[$m][1]) ;Reference number FileWriteLine($QIFFile, "P" & $saveTxn[$m][2]) ;Payee if $saveTxn[$m][5] > "" then FileWriteLine($QIFFile, "M" & $saveTxn[$m][5]) ;Memo FileWriteLine($QIFFile, "L" & $saveTxn[$m][4]) ;Category FileWriteLine($QIFFile, "^") Next FileClose($QIFFile) ;delete the transactions in the cash window (MOVE TO PRE-DELETE ACCOUNT) WinActivate($mainScreen) $delTxn = $saveTxn;copy the array to another we can modify $deltxn[UBound($delTxn)-1][0] = 0;clean out that "eof" txn at the end $deltxn[UBound($delTxn)-1][1] = 0 $deltxn[UBound($delTxn)-1][2] = 0 $deltxn[UBound($delTxn)-1][3] = 0 $deltxn[UBound($delTxn)-1][4] = 0 $deltxn[UBound($delTxn)-1][5] = 0 send("{END 4}");go to the end of the register send("{HOME 2}");go to the date field send("{UP}");one up while TotalTxns($delTxn) > 0 send("{TAB}");over to the Ref field WinWaitActive($mainScreen) $winText = StringSplit(WinGetText($mainScreen),@CRLF) for $d = 1 to UBound($delTxn) - 1 if string($wintext[16]) == string($delTxn[$d][1]) Then $delTxn[$d][1] = "";for the selected transaction, blank the Ref in the array $delTxn[$d][3] = 0;for the selected transaction, zero the Amt in the array Opt("SendKeyDelay", 50) send("!d") send("o") WinWaitActive("Move Transaction(s)") ControlFocus("Move Transaction(s)","","ComboBox1") ControlCommand("Move Transaction(s)","","ComboBox1","SelectString", $preDeleteAcct) ControlFocus("Move Transaction(s)","","OK") WinWaitActive("Move Transaction(s)") ControlClick("Move Transaction(s)","","OK") ExitLoop endif Next if $wintext[16] = $saveTxn[UBound($saveTxn)-1][1] Then send("{END 4}");go to the end of the register send("{HOME 2}");go to the date field EndIf send("{UP}{HOME 2}");one up WEnd ;turn off the register filtering WinWaitActive($mainScreen) ControlFocus($mainScreen,$currAcct,"Close Filter") WinWaitActive($mainScreen) ControlClick($mainScreen,$currAcct,"Close Filter") WinWaitActive($mainScreen) ;switch back to the other account $currAcct = SwitchAccts($cashAcct,$saveAcct) ;activate the split and find the Misc line GetMiscLine() if $winText[4] <> "Miscellaneous" Then MsgBox(0,$ScriptTitle,"No (more) Miscellaneous category items");No (more) misc category items in this split box Exit EndIf ;loop through the $saveTxn array and load those values into the SPLIT screen Opt("SendKeyDelay", 10) For $i = 1 to UBound($saveTxn) - 2 if $saveTxn[$i][3] > 0 then send($saveTxn[$i][4]);put in the category Send("{TAB}");Tab over if $saveTxn[$i][5] > "" Then send($saveTxn[$i][2] & " - " & $saveTxn[$i][5]);put in the payee/memo Else send($saveTxn[$i][2]);put in the payee EndIf Send("{TAB 2}");Tab over send($saveTxn[$i][3] / $xchngRate);put in the amount Send("{TAB}");Tab over Else ExitLoop endif Next ;see if we have any left over and deal with that if $i < 29 then Send("{TAB 4}") WinWaitActive("Split Transaction") $winText = StringSplit(WinGetText("Split Transaction"),@CRLF) if $wintext[4] > 0 Then Send("{UP}{HOME 2}") Send($fillCat) Send("{TAB}") Send($fillMemo) EndIf EndIf msgbox(0,$ScriptTitle,"When satsified, delete the txns from the #Pre-Delete Euros# account") EXIT ;****************************************************************** ;****************************************************************** ;* FUNCTIONS ;****************************************************************** ;****************************************************************** ;this function takes the Cash account currency which the user has chosen ;in the dialog box and puts them into some variables for use in the ;script. Func EstablishExchangeRate($chosenAcct) $cashArray = StringSplit($chosenAcct,",") $cashAcct = $cashArray[1] $cashCurr = $cashArray[2] $preDeleteAcct = "#Pre-Delete " & $cashCurr & "#" EndFunc ;this function is to load the next row in the currency table Func LoadCurrTable($txtstring) dim $i = UBound($CurrTable) $xArray = StringSplit($txtstring,",") ReDim $CurrTable[$i + 1][UBound($xArray)-1] for $j = 1 to UBound($xArray) - 1 $CurrTable[$i-1][$j-1] = $xArray[$j] Next EndFunc ;this function totals up the amount stored in the $delTxn array Func TotalTxns($tempArray) dim $tempAmt = 0 for $t = 0 to UBound($tempArray) - 1 $tempAmt = $tempAmt + $tempArray[$t][3];add up the amounts Next Return $tempAmt EndFunc ;this function simply activates the SPLIT screen and finds the Misc category line Func GetMiscLine() Send("!S") WinWaitActive("Split Transaction") $winText = StringSplit(WinGetText("Split Transaction"),@CRLF) while $winText[4] <> "Miscellaneous" if $winText[4] = "&OK" Then ExitLoop;Get out if you find an empty line before a "Misc" line Else send("{DOWN}");Keep pressing the down arrow key to find the next line EndIf $winText = StringSplit(WinGetText("Split Transaction"),@CRLF) WEnd EndFunc ;this function calculates the difference between what's in $saveMisc ;and what's in the $saveTxn array and returns that value Func AmountRemaining($tempMisc) dim $k dim $tempAmt = 0 for $k = 1 to UBound($saveTxn)-2 if $saveTxn[$k][3] > 0 then $tempAmt = $tempAmt + $saveTxn[$k][3] else ExitLoop EndIf Next return $tempMisc - ($tempAmt / $xchngRate) EndFunc ;this function stores the current cash account transaction row in to the ;$saveTxn array in the row with the number that's passed to it ;the cursor must be in the date field of a single-line register display Func SaveTxnDetails($rownum) for $i = 0 to 5 WinWaitActive($mainScreen) $winText = StringSplit(WinGetText($mainScreen),@CRLF) ;note: if you start getting nothing in your output as transactions selected, it could be ;because you have transactions "in the future" in your cash account (by accident...date transposition) ;this will cause the position of the text in your register item to be off by one. Uncomment the ;arraydisplay function below to spy on what is being looked at. ;_ArrayDisplay ( $winText, "values in 16 and 17, not 18 - $i=" & $i ) if $i = 3 Then $saveTxn[$rownum][$i] = $winText[17];the amount field is in a different place...annoying Else $saveTxn[$rownum][$i] = $winText[16] EndIf if $saveTxn[$rownum][5] = $saveTxn[$rownum][3] Then $saveTxn[$rownum][5] = "";this means that there is no memo field EndIf send("{TAB}");tab to the next field in the transaction Next send("{HOME}{HOME}");to the beginning of the transaction row EndFunc ;this function filters the transactions to only show payments and only those in the ;same year as the "misc" transaction func FilterTxns($tempYear) WinWaitActive($mainScreen) send("!v");show the dropdown menu of how to view the register send("f");choose the filter display option WinWaitActive($mainScreen) ControlCommand($mainScreen,$currAcct,"ComboBox1","ShowDropDown","") ControlFocus($mainScreen,$currAcct,"ComboBox1") WinWaitActive($mainScreen) Opt("SendKeyDelay", 1) send("p") For $i = 1 to 8 WinWaitActive($mainScreen) ControlCommand($mainScreen,$currAcct,"ComboBox2","ShowDropDown","") ControlFocus($mainScreen,$currAcct,"ComboBox2") WinWaitActive($mainScreen) send("{DOWN}") Next WinWaitActive("Custom Date") send("1{RIGHT}1{RIGHT}" & $saveYear & "{TAB}12{RIGHT}31{RIGHT}" & $saveYear & "{ENTER}") Opt("SendKeyDelay", 100) EndFunc ;this function simply assigns unique (I hope) transaction ids to register ;transactions if they are blank func AssignTxnIds() WinWaitActive($mainScreen) send("!v");show the dropdown menu of how to view the register send("{DOWN 5}");choose the check num option send("{ENTER}") send("{HOME 4}");go to the 1st txn in the register send("{TAB}");Go to the check number field ClipPut("");initialize the clipboard send("^c");copy its contents $thisRef = ClipGet() while $thisRef = "" Opt("SendKeyDelay", 1) send($mmdd & StringLeft(TimerInit(),8)) Opt("SendKeyDelay", 100) send("{ENTER}") send("{HOME 4}");go to the 1st txn in the register send("{TAB}");Go to the check number field send("^c");copy its contents $thisRef = ClipGet() WEnd EndFunc ;Access the Quicken account list screen to move to the account that we want to go to. ;Unfortunately the account list screen doesn't expose the actual account names ;and the window title is our only clue that we've arrived and it doesn't change ;as fast as we'd like. So we rely on the account list array at the beginning of ;the script. Func SwitchAccts($fromAcct,$toAcct) dim $fromNdx, $toNdx For $a = 0 to UBound($QckAcctArr) - 1;loop and find the position of the account we want if StringInStr($QckAcctArr[$a],$toAcct) > 0 Then $toNdx = $a - 1 EndIf Next send("^a");bring up the account list screen while WinWaitActive("Account List", "", 2) = 0 send("^a");bring up the account list screen WEnd Opt("SendKeyDelay", 1);start at the top send("{UP 21}");always start at the top Opt("SendKeyDelay", 10) for $a = 1 to $toNdx send("{DOWN}");go down to the account we want Next Opt("SendKeyDelay", 100) send("!g");go to the account highlited WinWaitActive($mainScreen) EndFunc ;this function is for debugging to help see what is in the $saveTxn array!!! Func SpySaveTxn($myTag) $myTag = "Tag: " & $myTag & @CRLF for $z = 0 to UBound($saveTxn) - 1 for $x = 0 to 5 $myTag = $myTag & @TAB & @TAB & $saveTxn[$z][$x] Next $myTag = $myTag & @CRLF Next msgbox(0,$ScriptTitle,$myTag) EndFunc ;this function is for debugging to help see what is in the $delTxn array!!! Func SpydelTxn($myTag) $myTag = "Tag: " & $myTag & @CRLF for $z = 0 to UBound($delTxn) - 1 for $x = 0 to 5 $myTag = $myTag & @TAB & @TAB & $delTxn[$z][$x] Next $myTag = $myTag & @CRLF Next msgbox(0,$ScriptTitle,$myTag) EndFunc
DickG Posted August 19, 2008 Posted August 19, 2008 I use Quicken 6 along with QuickAccess to grab specific data anywhere in Quicken. This combination doesn't require automating Quicken, but rather reads its database for anything you want. QuickAccess is an Excel add-in that was written by someone (forgot his name) long ago, and I can no longer find him. So you won't find it anywhere anymore. But I have a copy. I have been using it for years. I can't update Quicken to a newer version because Intuit has blocked access to all versions above v6 for making DDE calls, which is how QuickAccess gets the data from Quicken. But it works on all versions up to Quicken 6. It is really amazing what can be done. I create custom Excel reports of all kinds of things. I can then use one of several commands in a cell to have QuickAccess query Quicken in real time and get the value pronto. That can be a summary balance of some specific account, the value of one specific thing, a list of accounts, and just about anything else you can think of. It will give you an accurate list of accounts. The syntax for a command is: =QuickenCommand("Account", "End Date", "Start Date", "Payee", "Category", "Class", "Amount") One quicken command is QuickenBalance. That's the one use 99% of the time. For example, this Excel command retrieves the balance of my Receivables account from the two dates shown, for any Payee, using my "TPS In" category, and any class. The result is the amount. =QuickenBalance("Receivables", "12/31/98", "1/1/98","..", "TPS In", "..") So I create a "Quicken Data" tab in a spreadsheet that contains all the things I want to get. I use a column for each of these properties (Account, End Date, etc) to make it easy to maintain. When I open that file, all values get automatically updated (I have to open Quicken first, of course). I then use a reference to any of the value cells in that tab from other spreadsheets, knowing that I have accurate data. If you are willing to downgrade to Quicken 6 to be able to set up Excel to do anything you want with your Quicken data, let me know and I'll send you a copy of QuickAccess, along with instructions on how to install it, and a sample Excel file showing how to do a query to Quicken. Dick
dleigh Posted September 16, 2008 Author Posted September 16, 2008 QuickAccess is an Excel add-in that was written by someone (forgot his name) long ago, and I can no longer find him. So you won't find it anywhere anymore. But I have a copy.I found some info and docs about it on this site http://www.macgyver.org/software/quickaccess.html
Ahmad Posted September 16, 2008 Posted September 16, 2008 I Would Advise you to Search for curl, curl is a excellent solution for such things and works with php and C and supports a lot of protocols, I Think it's a better idea than sending Keystrokes because a site design may get changed but Script names and their $_GET attributes are getting changed very rarely i hope this helps [center]I want to change the world ...., but I don't have the source code xD[/center]
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now