Changes between my libraries of functions CommonC.ahk and CommonD.ahk
I come back here to discuss with you some months of experience of use, and the direction of changes between my libraries of functions CommonC.ahk and CommonD.ahk.
Before version C all my functions caused exit from the script in case of error even minor.
At version C, there are 2 Xpath functions nxpath, "n" means Normal, with exit if the aim is not found and rxpath ("r" as Recoverable) which accept aim not found giving an other return code : the script is in charge to recover from this error e.g. by re-trying latter or repeating the previous command : I have found that if the area to click does not appear immediately the simplest way to discover its appearance is to try to click on it with rxpath.
At version D, there are more functions of the "r" (Recoverable) family and even 1 of the m (Multiple) family : mxpath is a loop of a given number of xpath (the first ones behave as rxpath and "break" if success, the last as nxpath to give an error if unsuccessful) with a given length sleep between and a test of end of loading between them. You may consider mxpath as an integrated recovery procedure.
Next version will probably have more "m" or "r" functions.
I have also improved the logging of errors by adding in it the URL and the source more often : it ease the understanding of problems and their solutions.
The problems I have encountered are :
1) Errorlevel after "ClipWait, 10 " this occurred frequently with Firefox 3.6.13 that has the reputation to be fast but not before. In the functions that ask with a short-cut to Firefox to put something in the clipboard I had code similar to
Code:
clipboard = ; Start off empty to allow ClipWait to detect when the text has arrived.
Send, AHK_short-cut
ClipWait, 10 ; Wait for the clipboard to contain text.
if ErrorLevel
First I changed 10 s. to 20 s. but without any success. Then I thought that perhaps the Firefox short-cut put its result in the clipboard before Windows had time to empty it (instead of after according the order of instructions) so I added a sleep :
Code:
clipboard = ; Start off empty to allow ClipWait to detect when the text has arrived.
Sleep, 100
Send, AHK_short-cut
ClipWait, 10 ; Wait for the clipboard to contain text.
if ErrorLevel
All the errors disappeared. If this sort of error appears for you, try to increase the sleep duration.
2) strange "NotFound" error with nxpath() : in several scripts but not at each time I had, in the log, the NotFound error message but the right URL and a source of the DOM including the string that should have been found by xpath ! Of course the source has been extracted a short time after the detection of error. What can be the reasons for this paradoxical situation? A bug in the Firefox xpath function ? A wrong detection by fini() of the end of loading when the page was still loading and the aim of nxpath not still here ? 2 steps (redirection ?) loading of the page, each with its end of loading ? Other reasons ? I don't know ! I have written some lines to give a second chance : first an rxpath, if unsuccessful a npath() after sleep and fini() : this suppressed all errors so I coded mxpath() (see above) that, with its default parameters does just this.
3) changing message : you have e.g. "Please wait" that become after some time or external action "Finished". When you take a look at the source both messages are present (that is probably their attribute that change) so you cannot use test on the source, rxpath does not work but I have found that the "find" function of Firefox (short-cut ctrl+f) sees only the visible message so I have created the rslect(x) : its return code tells you if the x message (e.g. "Finished") is visible.
4) redirection : after your action on URL A, you receive and see (or not) during a short time URL B then without action you receive URL C.
If you test only URL C, your script (it is faster than your eye) may exit when it sees URL B ! Solution : a loop that compares the received URL with B to "continue" and C to "break" and gives errors if C is not found before end of loop.
5) Very long loading time of some pages of a site in some cases. First I increased the number of iterations (up to nearly 3 minutes) in the loop of fini(), added a second retry (in case of the loss in the network of the message carrying end of loading) : this was not sufficient. I have seen that areas on which I clicked appeared early in the loading, so I wrote a rfini() that does not give error (just an other return code) if the maximum value of index in the waiting loop is reached. The script tried to click and was is charge of recovering or exiting in case of problems. I don't know if this is just a particular site or a more general case.
6) My personal library (French) is too different from the distributed one (English or bilingual) : if some one request my last improved version and does not understand French a long time is needed for translation. First I moved the short comment line before each function describing it in an external file (see FuncVarD.txt below) and added other informations : this has suppressed the need for most of the comments. The remaining ones are either in English as they come from copying a line from the help either use operators (e.g. = instead of "equal") and words abbreviated to their common part in English and French (e.g. "defau." stands for "default" or "défaut"). I added the English error messages (commented) to my personal version. So now the only difference between CommonD.ahk and my French equivalent is which of the 2 error messages is commented. If you request my last personal edition of the library you will be in charge to comment each French message and uncomment the English ones !
If you have clues on the true causes of all these problems or better solutions, please contribute !
The description of functions and variables in the library is FuncVarD.txt below.
Code:
Functions
- fini() means "loading FINIshed" (En) or "chargement FINI" (Fr), returns time elapsed between start of the function and detection of loading FINIshed, exits in case of errors or time out. If you wish to see the time elapsed in the function, uncomment the MsgBox just before the last line but it is verbose ! NEW : longer timeout (nearly 3 minutes) and maximum number of clipwait with error level.
- rfini() NEW means "Recoverable loading FINIshed" (En) or "chargement FINI Récupérable" (Fr), equivalent to fini() except that it returns 0 in case of time out instead of exiting with error.
- slect(x) means "SeLECT" (En) or "SéLECTe" (Fr), returns 0 and text x selected if found, exit with error in other cases.
- rslect(x) NEW means "Recoverable SeLECT" (En) or "SéLECTe Récupérable" (Fr), returns 0 and text x selected if found, 1 and nothing selected if not found, exit with error in other cases.
- nxpath(x) means "Normal XPATH" (En & Fr), x is the parameters line passed to the FireFoX XPATH function through the clipboard, returns the time elapsed in WClipChange(x), exit if the FireFoX XPATH function has not found or other errors. NEW : use err1s instead of err1.
- rxpath(x) means "Recoverable XPATH" (En) or "XPATH Récupérable" (Fr), equivalent to nxpath(x) except that it returns 0 in case of not found instead of exiting with error.
- mxpath(x,m=2,sl=5000) means "Multiple XPATH" (En) or "XPATH Multiple" (Fr), it is a loop with m (default 2) tries that are recoverable except the last one. If found the loop "break"s else it "continue"s after rfini() and sleep %sl% (default 5000 ms.) instructions. Returns as nxpath(x).
- WClipChange(x) means "Wait till CLIPboard CHANGE" (En), is used (by XPATH) to test when FireFoX has changed the content of clipboard. It returns the time elapsed in WClipChange(x) or exits in case of errors or time out.
- err1(ster,fnErr) normal error procedure : ster and true URL (NEW) are written to the error log (fnErr) and shown in a MsgBox. st is put (purged) in the normal log. (En) or procédure normale d'erreur : ster est écrit dans le log d'erreur et affiché dans une MsgBox. st est mis dans le log normal. (Fr)
- err0(ster,fnErr) (NEW but equal to the old err1 ) normal error procedure without writting URL specialy to the error log (fnErr) because URL is allready included in ster or not available (e.g. Firefox not yet called).
- err1s = err1 + log source of DOM. NEW : URL is added before source.
- errClipW(x) CLIPWait 10 s. with ERRorlevel processing.(En) ClipWait 10 s. avec gestion d'ERRorlevel.(Fr). x is the name of the function calling it, returns 1 which is not used, exit with error if ErrorLevel.
- VerREMatch(x,y) VERify that RegExMatch has found (returned variable x not 0), if not pass y to the error message. (En) or VERifie que RegExMatch a trouvé (variable x retournée n'est pas 0) sinon passe y au message d'erreur. (Fr)
- ErrREMatch(x) ERRor procedure for RegExMatch. (En) procedure d'ERReur pour RegExMatch. (Fr) Exit with error. Use err1s.
- Purgelog() st is put (purged) in the normal log. (En) st est mis (purgé) dans le log normal. (Fr)
- sourc() return normal SOURCe (ctrl u).(En) retourne la SOURCe normale (ctrl u).(Fr) Uses errClipW(x).
- sdom() return Source of DOM.(En) retourne la Source du DOM.(Fr) Uses errClipW(x).
- maxim() MAXIMize (En) MAXIMise (Fr).
- max3q() MAXimize to 3 Quarters (En) MAXimise au 3 Quarts (Fr)
- vertit(x) VERify that TITle contains x.(En) VERifie que le TITre contient x.(Fr)
- versourc(x) VERify that the SOURCe of DOM contains x.(En) VERifie que la SOURCe du DOM contient x.(Fr). Use err1s.
- verURL(x) VERify that the URL is x.(En) VERifie que l'URL est x.(Fr)
- retURL() RETurn URL.(En) RETourne l'URL.(Fr)
- URLcont(x) verify that the URL CONTains x.(En) verifie que l'URL CONTient x.(Fr)
- Dur(x) DURation of script.(En) DURée du script.(Fr) written to the normal log. Replace x by the name of the variable in wich you have saved A_Now at start time of the script. The presence of this duration line at the end of the normal log is a clue that the script has been sucessfull without exit on error.
Variables
- wher name of the string that define WHERe we are in the script, initialized to " ??? " to avoid problems with not initialized variables.
- st name of the string to put in normal log file. Initialized to " ... " to avoid problems with not initialized variables.
- logdir name of the full path of the directory where you put the log files (normal or error). Default %A_ScriptDir%\Log\
- fnErr name of the standard error log file. Default %logdir%Err.log . One is sufficient but should be defined else no errors are logged and debugging is difficult !
I define in each script the normal log file e.g. fnl = %logdir%Blabla%A_YDay%.log where "Blabla" is my choice for this particular script, A_YDay change the name according to the day.
The library is CommonD.ahk below.
Code:
fini()
{
global wher, fnErr, st, fnl
StartTime := A_TickCount
bu = 1
erlv = 0
erlvmax = 16
Loop, 320 ; sleep 100+100+300 = 0.5 s., part. 1 0.5x40=20 s., part. 2 0.5x40=20 s., part. 3 0.5x240=120 s.
{
clipboard = ; Start off empty to allow ClipWait to detect when the text has arrived.
Sleep, 100
Send, {CTRLDOWN}{ALTDOWN}b{ALTUP}{CTRLUP}
Sleep, 100
ClipWait, 10 ; Wait for the clipboard to contain text.
if ErrorLevel
{
erlv++ ; +1
if erlv > %erlvmax%
{
;ster := wher . " * " . %erlv% . " Erreurs ClipWait dans fonction " . A_ThisFunc . " `n "
ster := wher . " * " . %erlv% . " Errors ClipWait in function " . A_ThisFunc . " `n "
rc := err1(ster,fnErr)
}
;MsgBox, The attempt to copy text onto the clipboard failed. %wher%
continue
}
If clipboard = NotBusy
{
bu = 0
break
}
If a_index = 40 ; 20 s.
{
Send, {ESC} ; stop
Sleep, 300
Send, {CTRLDOWN}{SHIFTDOWN}r{SHIFTUP}{CTRLUP} ; Reload (override cache)
Sleep, 300
}
If a_index = 80 ; + 20 s.
{
Send, {ESC} ; stop
Sleep, 300
Send, {CTRLDOWN}r{CTRLUP} ; Reload ( without override cache)
Sleep, 300
}
Sleep, 300
}
ElapsedTime := A_TickCount - StartTime
If bu
{
;ster := wher " * Dépassement temps de chargement " . ElapsedTime . " ms `n "
ster := wher " * Timeout loading " . ElapsedTime . " ms` n "
rc := err1(ster,fnErr)
}
; MsgBox, , , %ElapsedTime% ms. %wher% ,3 ; ....
return ElapsedTime ; >1
}
;--------
rfini()
{
global wher, fnErr, st, fnl
StartTime := A_TickCount
bu = 1
erlv = 0
erlvmax = 20
Loop, 320 ; sleep 100+100+300 = 0.5 s., part. 1 0.5x40=20 s., part. 2 0.5x40=20 s., part. 3 0.5x240=120 s.
{
clipboard = ; Start off empty to allow ClipWait to detect when the text has arrived.
Sleep, 100
Send, {CTRLDOWN}{ALTDOWN}b{ALTUP}{CTRLUP}
Sleep, 100
ClipWait, 10 ; Wait for the clipboard to contain text.
if ErrorLevel
{
erlv++ ; +1
if erlv > %erlvmax%
{
;ster := wher . " * " . %erlv% . " Erreurs ClipWait dans fonction " . A_ThisFunc . " `n "
ster := wher . " * " . %erlv% . " Errors ClipWait in function " . A_ThisFunc . " `n "
rc := err1(ster,fnErr)
}
;MsgBox, The attempt to copy text onto the clipboard failed. %wher%
continue
}
If clipboard = NotBusy
{
bu = 0
break
}
If a_index = 40 ; 20 s.
{
Send, {ESC} ; stop
Sleep, 300
Send, {CTRLDOWN}{SHIFTDOWN}r{SHIFTUP}{CTRLUP} ; Reload (override cache)
Sleep, 300
}
If a_index = 80 ; + 20 s.
{
Send, {ESC} ; stop
Sleep, 300
Send, {CTRLDOWN}r{CTRLUP} ; Reload ( without override cache)
Sleep, 300
}
Sleep, 300
}
ElapsedTime := A_TickCount - StartTime
If bu
{
; Send, {ESC} ; stop
MsgBox, , , %ElapsedTime% ms. %wher% ,4
; ster := wher " * Dépassement temps de chargement " . ElapsedTime . " ms `n "
; rc := err1(ster,fnErr)
}
; MsgBox, , , %ElapsedTime% ms. %wher% ,3 ; ....
return ElapsedTime ; >1
}
;--------
slect(x)
{
global wher, fnErr, st, fnl
Loop, 2
{
Send, {CTRLDOWN}f{CTRLUP}
Sleep, 300
Send, %x%
clipboard = ; Start off empty to allow ClipWait to detect when the text has arrived.
Sleep, 100
Send, {CTRLDOWN}{SHIFTDOWN}f{CTRLUP}{SHIFTUP}
ClipWait, 10 ; Wait for the clipboard to contain text.
if ErrorLevel
{
continue
}
break
}
If clipboard = found
{
rc = 0
} else {
;ster := wher " * Erreur slect(" . x . ") : pas trouvé. `n "
ster := wher " * Error in slect(" . x . ") : not found. `n "
rc := err1(ster,fnErr)
}
Sleep, 100
Send, {ESC}
Sleep, 500
return rc ; rc=0 OK , rc=1 KO x not found or clipwait timeout
}
;--------
rslect(x)
{
global wher, fnErr, st, fnl
Loop, 2
{
Send, {CTRLDOWN}f{CTRLUP}
Sleep, 300
Send, %x%
clipboard = ; Start off empty to allow ClipWait to detect when the text has arrived.
Sleep, 100
Send, {CTRLDOWN}{SHIFTDOWN}f{CTRLUP}{SHIFTUP}
ClipWait, 10 ; Wait for the clipboard to contain text.
if ErrorLevel
{
continue
}
break
}
If clipboard = found
{
rc = 0
} else {
;ster := wher " * Erreur rslect(" . x . ") : pas trouvé. `n "
ster := wher " * Error in rslect(" . x . ") : not found. `n "
If clipboard = not_found
{
rc = 1
} else {
rc := err1(ster,fnErr) ; err. ?, clipwait timeout ?
}
}
Sleep, 100
Send, {ESC}
Sleep, 500
return rc ; rc=0 OK , rc=1 KO x not found
}
;--------
nxpath(x)
{
global wher, fnErr, st, fnl
clipboard := x
Sleep, 100
Send, {CTRLDOWN}q{CTRLUP}
rc := WClipChange(x)
If clipboard <> Found
{
;ster := wher " * Erreur nxpath(" . x . ") `n " . clipboard . " `n "
ster := wher " * Error in nxpath(" . x . ") `n " . clipboard . " `n "
rc := err1s(ster,fnErr)
}
Sleep, 100
return rc ; rc>1 OK
}
;---------
rxpath(x)
{
global wher, fnErr, st, fnl, stertxp
clipboard := x
Sleep, 100
Send, {CTRLDOWN}q{CTRLUP}
rc := WClipChange(x)
If clipboard = Found ; OK
{
return rc ; rc>1 OK
}
;stertxp := wher " * Erreur rxpath(" . x . ") `n " . clipboard . " `n "
stertxp := wher " * Error in rxpath(" . x . ") `n " . clipboard . " `n "
If clipboard = NotFound
{
return 0 ; rc=0 KO <> err.
}else{
rc := err1s(stertxp,fnErr) ; KO = err.
return rc
}
}
;---------
mxpath(x,m=2,sl=5000)
{
global wher, fnErr, st, fnl, stertxp
; m a_index max defau. 2 , sleep sl defau. 5 s.
Loop
{
clipboard := x
Sleep, 100
Send, {CTRLDOWN}q{CTRLUP}
rc := WClipChange(x)
If clipboard = Found ; OK
{
return rc ; rc>1 OK
break ;
}
;stertxp := wher " * Erreur mxpath(" . x . ") `n " . clipboard . " `n "
stertxp := wher " * Error in mxpath(" . x . ") `n " . clipboard . " `n "
If clipboard = NotFound
{
if a_index < %m% ; loop
{
Sleep, %sl%
rc := rfini()
continue ;
}else{
rc := err1s(stertxp,fnErr) ; KO a_index >= %m%
return rc
}
}else{
rc := err1s(stertxp,fnErr) ; KO clipboard <> Found / NotFound
return rc
}
}
}
;---------
WClipChange(x)
{
global wher, fnErr, st, fnl
StartTime := A_TickCount
KO = 1
Loop, 100 ; 10 seconds
{
Sleep, 100
If clipboard <> %x%
{
KO = 0
break
}
}
ElapsedTime := A_TickCount - StartTime
If KO
{
;ster := wher " * Dépassement temps WClipChange " . ElapsedTime . " ms `n "
ster := wher " * Timeout WClipChange " . ElapsedTime . " ms `n "
rc := err1(ster,fnErr)
}
return ElapsedTime ; If OK , rc > 1
}
;--------
err0(x,y)
{
global st, fnl
;MsgBox %x%
MsgBox, , , %x% ,30
ster := " `n **** " . A_Now . " " . A_ScriptName . "`n" . x . " `n "
FileAppend, %ster%, %y%
rc := Purgelog()
Exit
return 1 ; rc=0 OK , rc=1 KO
}
;--------
err1(x,y)
{
global st, fnl
;MsgBox %x%
MsgBox, , , %x% ,30
vURL := retURL()
ster := " `n **** " . A_Now . " " . A_ScriptName . "`n" . x . " `n "
ster .= "`n ******URL = " . vURL . " *** `n"
FileAppend, %ster%, %y%
rc := Purgelog()
Exit
return 1 ; rc=0 OK , rc=1 KO
}
;--------
err1s(x,y)
{
global st, fnl ;, source
;MsgBox %x%
MsgBox, , , %x% ,30
source := sdom()
vURL := retURL()
ster := " `n **** " . A_Now . " " . A_ScriptName . "`n" . x
ster .= "`n ******source " . vURL . " *** `n"
ster .= source . "`n ************ `n"
FileAppend, %ster%, %y%
rc := Purgelog()
Exit ; err1s = err1 + log source
return 1 ; rc=0 OK , rc=1 KO
}
;--------
errClipW(x)
{
global wher, fnErr, st, fnl
ClipWait, 10 ; Wait for the clipboard to contain text.
if ErrorLevel
{
;ster := wher " * Erreur ClipWait dans fonction " . x . " `n "
ster := wher " * Error ClipWait in function " . x . " `n "
rc := err1(ster,fnErr)
}
return 1
}
;--------
VerREMatch(x,y)
{
global wher, fnErr, st, fnl
If x = 0
{
ErrREMatch(y)
}
Sleep, 100
return 0 ; rc=0 OK , rc=1 KO
}
;--------
ErrREMatch(x)
{
global wher, fnErr, st, fnl
;ster := wher " * Erreur RegExMatch pour " . x . " : rien trouvé `n "
ster := wher " * Error RegExMatch for " . x . " : nothing found `n "
rc := err1s(ster,fnErr)
Sleep, 100
return rc ; rc=0 OK , rc=1 KO
}
;--------
Purgelog()
{
global st, fnl
st .= "`n **** Purge " . A_Now . " " . A_ScriptName . "`n"
FileAppend, %st%, %fnl%
return 0 ; rc=0 OK , rc=1 KO
}
;--------
sourc()
{
clipboard = ; Start off empty to allow ClipWait to detect when the text has arrived.
Sleep, 100
Send, {CTRLDOWN}{SHIFTDOWN}u{SHIFTUP}{CTRLUP}
rc := errclipw(A_ThisFunc) ; ClipWait, 10 : 10 s. avec gestion d'ErrorLevel
return clipboard ; source
}
;--------
sdom()
{
clipboard = ; Start off empty to allow ClipWait to detect when the text has arrived.
Sleep, 100
Send, {ALTDOWN}{SHIFTDOWN}u{SHIFTUP}{ALTUP}
errClipW(A_ThisFunc) ; ClipWait, 10 : 10 s. + ErrorLevel
return clipboard ; source DOM
}
;--------
maxim()
{
Send, {CTRLDOWN}{SHIFTDOWN}m{SHIFTUP}{CTRLUP}
Sleep, 200
return 0
}
;--------
max3q()
{
Send, {CTRLDOWN}m{CTRLUP}
Sleep, 200
return 0
}
;--------
vertit(x)
{
global wher, fnErr, Title, st, fnl
WinGetTitle, Title, A
IfNotInString, Title, x
{
;ster := wher " * Erreur titre = " . Title . " `n "
ster := wher " * Error title = " . Title . " `n "
rc := err1(ster,fnErr)
}
return 0 ; rc=0 OK , rc=1 KO
}
;--------
versourc(x)
{
global wher, fnErr, source, st, fnl
source := sdom()
IfNotInString, source, x
{
;ster := wher " * Erreur : source ne contient pas " . x
ster := wher " * Error : source does not contains " . x
rc := err1s(ster,fnErr)
return 1 ; rc=1 KO
}
return 0 ; rc=0 OK
}
;--------
verURL(x)
{
global wher, fnErr, st, fnl, vURL
vURL := retURL()
If vURL = %x%
return 0 ; rc=0 OK
Else
{
;ster := wher " * Erreur : URL = " . vURL . "`n au lieu de " . x
ster := wher " * Error : URL = " . vURL . "`n instead of " . x
rc := err0(ster,fnErr)
return 1 ; rc=1 KO
}
}
;--------
retURL()
{
clipboard = ; Start off empty to allow ClipWait to detect when the text has arrived.
Sleep, 100
Send, {ALTDOWN}{SHIFTDOWN}l{SHIFTUP}{ALTUP}
rc := errclipw(A_ThisFunc) ; ClipWait, 10 : 10 s. + ErrorLevel
Sleep, 100
return clipboard ; URL
}
;--------
URLcont(x)
{
global wher, fnErr, st, fnl
vURL := retURL()
IfInString, vURL, %x%
return 0 ; rc=0 OK , rc=1 KO
Else
{
;ster := wher " * Erreur : URL = " . vURL . "`n ne contient pas " . x
ster := wher " * Error : URL = " . vURL . "`n does not contains " . x
rc := err0(ster,fnErr)
return 1 ; rc=0 OK , rc=1 KO
}
}
;--------
Dur(x)
{
global fnl
y := A_Now
EnvSub, y, %x%, seconds
min := y // 60
sec := mod(y,60)
; FileAppend, ********* %A_Now% %y% s %min% min %sec% s `n, %fnl%
FileAppend, ********* %A_Now% %min% min %sec% s `n, %fnl%
}
;--------variables
wher := " ??? "
st := " ... "
logdir = %A_ScriptDir%\Log\
fnErr = %logdir%Err.log