# Source code (Python) for Kotbot------------
def doros(sta,sto):
C=F('tclog')[sta:sto+1]; TY=F('tylog'); global g_logcon
for L in C:
cy=row(TY,L[1],2)[1]; g_logcon=L[0]; n=nam(L[0])
tx=wpraw('en',L[0]); iib=iibox(L,cy)
if 'nfobox' in tx:
log('settlement' if 'nfobox settlement'\
in tx else envirs(tx,'nfobox',2,25))
elif 'ategory:Communes in '+cy not in tx or 'Romania' not in tx:
log('*wrong page? '+iib)
elif '{{bot' in tx or '{{nob' in tx or '{{Bot' in tx or '{{Nob' in tx:
log('*bot exclusion '+iib)
else:
x=sf(tx,"'''"+n)
if x<0 or x>100 or "'''"+n in tx[x+3:]:
log('*no place for infobox: '+iib)
else:
ty=tx[:x]+iibox(L,cy)+'\n'+tx[x:]
if '<ref>' in ty and '{{reflist}}' not in ty and \
'<references' not in ty and '{{Reflist}}' not in ty:
if 'eferenc' in ty or 'xternal' in ty or 'Notes' in ty:
log('*cant place reflist')
else:
xx=sf(ty,('\n{{Communes','\n{{communes',
'\n{{DEFAULT','\n[[Category'))
if xx<0:
log('*cant put ref section')
else:
ty=ty[:xx]+'\n==References==\n{{reflist}}\n\n'+\
ty[xx:]
log('*put ref section')
edit('en',L[0],'Force',ty,
'bot adding infobox')
return sta,sto
def iibox(L,cou):
t=('{{Infobox settlement\n|name='+nam(L[0])+
'\n|settlement_type='+
('[[Municipiu|City]]' if I(L,5)=='M' else (u9('[[Orasx|Town]]'+
'') if I(L,5)=='O' else '[[Communes of Romania|Commune]]'))+
'\n|total_type= \n|image_map=\n|map_caption='+
'\n|subdivision_type=Country\n|subdivision_name'+
'={{flag|Romania}}\n|subdivision_type1=[[Counties of Romania|County]]'+
'\n|subdivision_name1=[['+cou+']]\n|population_total='+L[2])
if L[2]!='' and L[3]!='':
t=(t+'\n|population_as_of=2002\n|population_footnotes=<ref>'+
'[http://recensamant.referinte.transindex.ro/?pg=3&id='+
L[3]+' Romanian census data, 2002]; retrieved on March 1, 2010</ref>')
y=a2l(L[4],'|')
if len(y)==6 and y[0]!='':
t=(t+'\n|latd='+y[0]+'|latm='+y[1]+'|lats='+y[2]+'|latNS=N'+
'|longd='+y[3]+'|longm='+y[4]+'|longs='+y[5]+'|longEW=E'+
'\n|pushpin_map=Romania')
t=(t+'\n|timezone=[[Eastern European Time|EET]]|utc_offset=+2'+
'\n|timezone_DST=[[Eastern European Summer Time|EEST]]'+
'|utc_offset_DST=+3\n}}')
return t
def absss():
"""Coords"""
T=F('ttlog')
for L in T:
tx=wpraw('en',L[0])
if 'nfobox' in tx:
ac=''
else:
acm=mgp(r'\{\{(?:C|c)oord(.*)\}',tx); ac=ascoo(acm)
if len(L)==6:
log(L[0],L[1],L[4],L[5],ac,L[2])
else:
log(L+[ac,'**'])
return 9
def oldddoioi():
TY=col(F('tylog'),2)
for L in T:
if len(L)==6:
if '*' in L[0] or L[1] not in TY \
or not isnin(L[4],200,1000000) or not isnin(L[5],1,2951) or \
S[eval(L[5])-1][3:5]!=[L[1],L[4]]:
log('*',L[0])
else:
if len(L)!=4 or L[1] not in TY or L[3]!='*0':
log('*',L[0])
return 9
def abcrc(sta,sto):
"""Get"""
S=F('sulog'); SV=F('svlog'); T=F('tclog'); TY=F('tylog')
for L in T[sta:sto+1]:
na=nam(L[0]); cy=row(TY,L[1],1)[2]
A=rows(S,na,1)
B=rows(A,cy,3)
if len(B)==0:
A=rows(SV,J2j(rom(na)).replace('-',' '),1)
B=rows(A,cy,3)
if len(B)==0:
A=rows(SV,J2j(rom(na)).replace('-',' ').replace('a',''),1)
B=rows(A,cy,3)
if len(B)==1:
log(L[0],cy,'C',B[0][2],B[0][4],B[0][0])
else:
log(L[0],cy,'C','*'+str(len(B)))
return 9
def achch():
ty=F('tylog'); c=F('tclog'); s=F('sulog'); R=['']*len(ty)
for L in c:
i=lf(ty,L[1],1)
if R[i]=='':
M=row(s,L[0],2)
R[i]=I(M,4)
for j in range(len(ty)):
log(ty[j][1],R[j])
return 9
def an2():
g=catcont('en','Communes and villages in Romania')[0]; L=[]
for k in g:
if starts(k,'Communes in ') and ends(k,' County'):
kk=k[12:]
elif starts(k,'Localities in ') and ends(k,' County'):
kk=k[14:]
else:
kk=k
log(kk)
h=catcont('en',k)[1]
for y in h:
L=L+[[y,kk]]
a2fi(L,'blog')
return 9
#Localities in Ilfov County (incl. 9 towns)
def an1():
K=F('sourcelog')
for L in K:
t=L[2]; c='**'
if starts(t,'Municipiul '):
t=t[11:]; c='m'
elif ends(t,' municipiul'):
t=t[:-11]; c='m'
elif starts(t,'Comuna '):
t=t[7:]; c='c'
elif ends(t,' comuna'):
t=t[:-7]; c='c'
elif ends(t,' c.'):
t=t[:-3]; c='c'
elif ends(t,' o.'):
t=t[:-3]; c='o'
elif ends(t,' ora\xc5\x9f'):
t=t[:-6]; c='o'
elif ends(t,' ora\xc5\x9ful'):
t=t[:-8]; c='o'
elif starts(t,'Ora\xc5\x9e '):
t=t[6:]; c='o'
elif starts(t,'Ora\xc5\x9eul '):
t=t[8:]; c='o'
elif starts(t,'Ora\xc5\x9ful '):
t=t[8:]; c='o'
elif ' '!=t:
c='x'
log(L[1],noex(t.replace(' ',' ')),c,L[3],L[4])
return 9
def romget(sta,sto):
for n in range(sta,sto+1):
u='http://recensamant.referinte.transindex.ro/?pg=3&id='+str(n)
t=urlread(u)
nl=mgps('margin-top.+>(.+?)<',t)
pl=mgps('<th>Total.+\n.+>(\d+)<',t)
if len(nl)!=1 or len(pl)!=1 or '>' in nl[0]+pl[0]:
log(str(n)+'>**>'+str(nl+pl))
else:
nj=noex(upto(nam(nl[0]),'/')); ta=tag(nl[0])
na=replaces(nj,[('\xe2','\xc3\xa2'),
('\xe3','\xc4\x83'),
('\xba','\xc5\x9f'),
('\xfe','\xc5\xa3'),
('\xce','\xc3\x8e'),
('\xaa','\xc5\x9e'),
('\xde','\xc5\xa2')])
log(str(n),na,ta,pl[0])
return sta,sto
#****************
global g_uni, g_coo, g_lang, g_logfile, g_logcon
global g_user, g_pass, g_jar, g_loggedon
#Unicode characters: lowercase, uppercase, keyboard, (reduction)
g_uni=(('pl',(('\xC4\x85','\xC4\x84','a'),('\xC4\x87','\xC4\x86','c'),
('\xC4\x99','\xC4\x98','e'),('\xC5\x82','\xC5\x81','l'),
('\xC5\x84','\xC5\x83','n'),('\xC3\xB3','\xC3\x93','o'),
('\xC5\x9B','\xC5\x9A','s'),('\xC5\xBA','\xC5\xB9','x','z'),
('\xC5\xBC','\xC5\xBB','z'))),
('cs',(('\xc3\xa1','\xc3\x81','a'),('\xc4\x8d','\xc4\x8c','c'),
('\xc4\x8f','\xc4\x8e','d'),('\xc3\xa9','\xc3\x89','e'),
('\xc4\x9b','\xc4\x9a','f','e'),('\xc3\xad','\xc3\x8d','i'),
('\xc5\x88','\xc5\x87','n'),('\xc3\xb3','\xc3\x93','o'),
('\xc5\x99','\xc5\x98','r'),('\xc5\xa1','\xc5\xa0','s'),
('\xc5\xa5','\xc5\xa4','t'),('\xc3\xba','\xc3\x9a','u'),
('\xc5\xaf','\xc5\xae','v','u'),('\xc3\xbd','\xc3\x9d','y'),
('\xc5\xbe','\xc5\xbd','z'))),
('ro',(('\xc3\xa2','\xc3\x82','a'),('\xc4\x83','\xc4\xa3','b','a'),
('\xc3\xae','\xc3\x8e','i'),
('\xc5\x9f','\xc5\x9e','s'),
('\xc5\xa3','\xc5\xa2','t'))))
#Max and min degree
g_coo=(('pl',(49,54,14,24)),('cs',(48,51,12,18)),('ro',(43,48,20,29)))
g_lang='ro'
g_logfile='blog.txt'
g_logcon=''
g_jar=0
g_loggedon=[]
def I(x,n,df=''):
"""x[n] if exists else default"""
try:
return x[n]
except:
return df
def lty(a):
"""Returns 2 if a t/list containing t/list(s), 1 if other t/l, else 0"""
if type(a) not in (tuple,list):
return 0
for b in a:
if type(b) in (tuple,list):
return 2
return 1
def l2s(L,sep='>'):
"""Converts list to string, > default separator"""
os=''
for x in L[:-1]:
os=os+str(x)+sep
os=os+str(I(L,-1))
return os
def a2s(a,sep='>'):
"""Converts any to string, > and \n default seps"""
if lty(a)<2:
return str(a) if lty(a)==0 else l2s(a,sep)
s=''
for b in a:
s=s+(str(b) if lty(b)==0 else l2s(b,sep))+'\n'
return s
def a2p(a):
"""If list or tuple, returns tuple. Else returns 1-tuple."""
return tuple(a) if lty(a)>0 else (a,)
def a2pp(a):
"""Makes tuple of tuples"""
if lty(a)<2:
return (a2p(a),)
pp=()
for b in a:
pp=pp+(a2p(b),)
return pp
def a2l(a,seps='>'):
"""Converts any to list, > default sep (can be alternative seps)"""
if lty(a)>0:
return list(a)
s=str(a)
if I(s,-1)=='\n' and '\n' in seps:
s=s[:-1]
if s=='' and '>' not in seps:
return []
l=[]; t=''
for ch in s:
if ch in seps:
l.append(t); t=''
else:
t=t+ch
l.append(t)
return l
def a2ll(a,seps='>'):
"""Converts to list of lists, > and \n default separators"""
if lty(a)>1:
return list(a)
LL=[]
for k in a2l(a,'\n'):
LL.append(a2l(k,seps))
return LL
def reesc(st):
"""Escapes string to regex or removes initial !R"""
import re; s=str(st)
return s[2:] if re.match('!R',s) else re.escape(s)
def a2re(a,get=0):
"""String/tuple to regex: init. !R for no escape, get=1 for ()"""
os='(' if get else '(?:'; p=a2p(a)
if len(p)==1:
return '('+reesc(p[0])+')' if get else reesc(p[0])
for x in p:
os=os+reesc(x)+'|'
return os[:-1]+')'
def mgps(r,s):
"""Returns all matched groups from regex matched to s, or []"""
ol=[]; import re
l=re.search(r,s)
if not l:
return []
for x in l.groups():
if type(x)==str:
ol.append(x)
return ol
def mgp(r,s):
"""First of matched groups, or '' """
return I(mgps(r,s),0)
def newunifile(finame,intro=''):
"""Creates unicode file with intro as first line, if file nonexistent"""
"""Returns 1 if created, else -1"""
full=finame if '.' in finame else finame+'.txt'
try:
fi=open(full)
except:
try:
nf=open(full,'w')
except:
return -1
nf.write('\xef\xbb\xbf'+(intro if intro!='' else finame+' file')+'\n')
nf.close()
return 1
fi.close()
return -1
def fi2l(finame):
"""Gets list of lines; returns -1 if no such file"""
L=[]; fo=finame if 'log' in finame or '/' in finame or\
'.' in finame else 'jdata/'+finame
full=fo if '.' in fo else fo+'.txt'
try:
fi=open(full)
except:
return -1
for line in fi:
L.append(line[:-1] if I(line,-1)=='\n' else line)
fi.close()
return L[1:]
def fi2ll(finame,seps='>'):
"""File with >-sep. lines to list of lists. -1 if no such file"""
a=fi2l(finame)
return -1 if a==-1 else a2ll(a,seps)
def F(*fis):
"""Multiple fi2ll"""
j=()
for fi in fis:
j=j+(fi2ll(fi),)
return j[0] if len(j)==1 else j
def fi2s(finame):
"""Converts file to single string with \n's. -1 if no such file"""
a=fi2l(finame)
return -1 if a==-1 else l2s(a,'\n')+'\n'
def a2fi(A,finame):
"""Writes anything to file"""
if A=='':
return
full=finame if '.' in finame else finame+'.txt'
fi=open(full,'a')
for L in a2pp(A):
fi.write(l2s(L)+'\n')
fi.close()
return 0
def log(*f):
"""Logs g_logcon plus series of items, to g_logfile"""
op=(g_logcon,) if g_logcon else ()
for a in f:
op=op+(a2s(a),)
return a2fi(op,g_logfile)
def allin(a,b):
"""?Are all chars/els of a in b"""
for x in a:
if x not in b:
return False
return True
def reps(L,M=0):
"""List of repetitions in L / things in L also in M"""
OL=[]
for i in range(len(L)):
if L[i] in (M if M!=0 else L[:i]):
OL.append(L[i])
return OL
def replaces(st,L):
"""Does non-reiterated replaces acc. to list of pairs"""
for ab in L:
st=st.replace(ab[0],ab[1])
return st
def subs(st,L):
"""Applies list of regex substitution pairs (triples)"""
import re
for l in L:
st=re.sub(l[0],l[1],st,I(l,2,0))
return st
def has(S,st,wh=0,se=''):
"""?Does S contain a(any of) st (can be !R+regex) (se for start/end)"""
"""If wh>0: +which(2=last non-overlap.)+start+stop(3=how many)"""
import re; of=0; s=str(S); r=a2re(st,1)
if wh>1:
M=re.split(r,s)
if len(M)>1:
of=len(s)-len(M[-1])-len(M[-2]); s=s[of:]
m=re.search(('^' if 's' in se else '')+r+('$' if 'e' in se else ''),s)
if wh==0:
return True if m else False
if m:
return True, m.group(), m.start()+of, m.end()+of if wh<3 else len(M)/2
return False,'',-1,0
def starts(S,st,wh=0):
"""?Does S start with (any of) st (wh=1 also returns which)"""
return has(S,st,wh,'s')
def ends(S,st,wh=0):
"""?Does S end with (any of) st (wh=1 also returns which)"""
return has(S,st,wh,'e')
def isas(S,st,wh=0):
"""?Is S (any of) st (wh=1 also returns which)"""
return has(S,st,wh,'se')
def spl(S,st):
"""Split: if st in S, returns triple, else S,'',''"""
h=has(S,st,1)
return (S[:h[2]],h[1],S[h[3]:]) if h[0] else (S,'','')
def mspl(sl,r,ch):
"""Splits 1st of strings; codes the result (code is !;(ch)(n); )"""
import re
m=re.split('('+r+')',sl[0]); os=''
for n in range(len(m)):
if n%2==0:
os=os+m[n]
else:
sl.append(m[n]); os=os+'!;'+ch+str(len(sl)-1)+';'
return [os]+sl[1:]
def subslist(sl):
"""List for subs use based on sl"""
L=[]
for n in range(1,len(sl)):
L.append([r'!;[^0-9]*'+str(n)+';',sl[n]])
return L
def sf(S,m,st='',fl=''):
"""Finds st in S (or rel. index m), fl=j,l,1. -1 if m=-1 or not found"""
if type(m)!=int:
fl=st; st=m; m=0
if m<0:
return (-1,'') if '1' in fl else -1
K=has(S[m:],st,(2 if 'l' in fl else 1))
if not K[0]:
return (-1,'') if '1' in fl else -1
i=K[3] if 'j' in fl else K[2]
return (i+m,K[1]) if '1' in fl else i+m
def nin(S,st):
"""How many of (non-overlapping) (any of) st in S"""
N=0
if type(S)!=str:
for s in S:
if isas(s,st):
N=N+1
return N
return has(S,st,3)[3]
def compare(a,b):
"""If a, b not identical, returns index and differing items"""
for n in range(max(len(a),len(b))):
if I(a,n)!=I(b,n):
return n,I(a,n),I(b,n)
return -1,'',''
def envirs(S,st,back,forth):
"""Returns all environments (back and forth define how big) of st in S"""
L=[]
for i in range(len(S)):
si,wh=starts(S[i:],st,1)[:2]
if si:
L.append(S[max(0,i-back):i+len(wh)+forth])
return a2s(L).replace('\n','&')
def per(ST,PARM,THIS):
"""Applies st (column of THIS, -1 gives PARM; or eval string)"""
if ST==-1:
return PARM
if ST==-2:
return THIS
if type(ST)==int:
return I(a2p(THIS),ST)
return eval(ST.replace('!!','THIS').replace('!%','PARM'))
def rows(L,st,col=0,rcols=-2,ret=-1):
"""Gets rcols (-2=all, -1=ind.) of ret (-1=all,0=NOT) rows: st match col"""
"""col can be eval string. Single rcol will debracket"""
OL=[]; n=0
while n<len(L) and (ret<1 or len(OL)<ret):
K=L[n]
if isas(per(col,n,K),st)==(ret!=0):
O=[]
for c in a2p(rcols):
O=O+(list(a2p(K)) if c==-2 else [per(c,n,K)])
OL.append(O[0] if type(rcols)==int and rcols>-2 or
type(L[n]) not in (list,tuple) and rcols==-2 else O)
n=n+1
return OL
def row(L,st,col=0,rcols=-2):
"""First of rows, or []"""
return I(rows(L,st,col,rcols,1),0,[])
def lf(L,st,col=0):
"""Index of first of rows, or -1"""
return I(rows(L,st,col,-1,1),0,-1)
def col(L,col):
"""Column(s) from L"""
return rows(L,'a','"a"',col)
def j2J(st,no=0):
"""All to uppercase; no=1 means only initial"""
inil=1
L=[('a','A'),('b','B'),('c','C'),('d','D'),('e','E'),('f','F'),('g','G'),
('h','H'),('i','I'),('j','J'),('k','K'),('l','L'),('m','M'),('n','N'),
('o','O'),('p','P'),('q','Q'),('r','R'),('s','S'),('t','T'),('u','U'),
('v','V'),('w','W'),('x','X'),('y','Y'),('z','Z')]
for k in g_uni:
for a in k[1]:
L.append((a[0],a[1]))
inil=len(a[0]) if st[:len(a[0])]==a[0] else inil
if no==1:
return replaces(st[:inil],L)+st[inil:]
return replaces(st,L)
def st2St(st):
"""Capitalises first character of string"""
return j2J(st,1)
def J2j(st,no=0):
"""All to lower case; no=1 means only initial"""
inil=1
L=[('A','a'),('B','b'),('C','c'),('D','d'),('E','e'),('F','f'),('G','g'),
('H','h'),('I','i'),('J','j'),('K','k'),('L','l'),('M','m'),('N','n'),
('O','o'),('P','p'),('Q','q'),('R','r'),('S','s'),('T','t'),('U','u'),
('V','v'),('W','w'),('X','x'),('Y','y'),('Z','z')]
for k in g_uni:
for a in k[1]:
L.append((a[1],a[0]))
inil=len(a[1]) if st[:len(a[1])]==a[1] else inil
if no==1:
return replaces(st[:inil],L)+st[inil:]
return replaces(st,L)
def St2st(st):
"""Makes first char. lower case"""
return J2j(st,1)
def U(st,la=''):
"""From x+ format to Unicode"""
la=la if la!='' else g_lang; d=row(g_uni,la,0,1)
for a in d:
st=st.replace(a[2]+'+',a[0]).replace(j2J(a[2])+'+',a[1])
return st
def rom(st,la=''):
"""Unicode to reduced format"""
la=la if la!='' else g_lang; d=row(g_uni,la,0,1)
for a in d:
r=I(a,3,a[2])
st=st.replace(a[0],r).replace(a[1],j2J(r))
return st
def rplus(st,la=''):
"""Unicode to x+ format"""
la=la if la!='' else g_lang; d=row(g_uni,la,0,1)
for a in d:
st=st.replace(a[0],a[2]+'+').replace(a[1],j2J(a[2])+'+')
return st
def notrail(s,a):
"""Removes (any of) a from end of string, iteratively"""
t=''; import re
while ends(s,a) and t!=s:
t=s; s=re.sub(a2re(a)+'$','',s)
return s
def noinit(s,a):
"""Removes (any of) a from start of string, iteratively"""
t=''; import re
while starts(s,a) and t!=s:
t=s; s=re.sub('^'+a2re(a),'',s)
return s
def noex(st):
"""Removes spaces and newlines from start and end"""
return notrail(noinit(st,(' ','\n')),(' ','\n'))
def repblank(t):
"""Removes double blank lines from t"""
while '\n\n\n' in t:
t=t.replace('\n\n\n','\n\n')
return t
def upto(s,a):
"""If s contains (any of) a, returns noex of what goes before (else s)"""
return noex(spl(s,a)[0])
def after(s,a):
"""If s contains a, returns what comes after (else '')"""
return spl(s,a)[2]
def insbef(s,a,t,T0='',T2=''):
"""puts t before a in s, T0/T2 logged if not found/found twice"""
K=has(s,a,1)
if not K[0]:
log(T0) if T0!='' else ''; return s
if has(s[K[3]:],a):
log(T2) if T2!='' else ''
return s[:K[2]]+t+s[K[2]:]
def insaft(s,a,t,T0='',T2=''):
"""puts t after a in s, T0/T2 logged if not found/found twice"""
K=has(s,a,1)
if not K[0]:
log(T0) if T0!='' else ''; return s
if has(s[K[3]:],a):
log(T2) if T2!='' else ''
return s[:K[3]]+t+s[K[3]:]
def l2txt(L,sep=', ',lsep=', and ',osep=' and ',do=0):
"""Makes a text list. Normal separator, last, only, operation on items"""
os=''; k=len(L)
for n in range(k):
os=os+per(do,n,L[n])+\
(osep if n==0 and k==2 else (lsep if n==k-2 else (sep if
n<k-1 else '')))
return os
def isn(st):
"""Is st a pure integer?"""
return isas(st,r'!R0|\-?[1-9][0-9]*')
def isnin(st,a,b):
"""Is st a pure int in the range a to b?"""
return isn(st) and eval(st)>=a and eval(st)<=b
def isx(st):
"""Is st a pure English int or decimal?"""
return isas(st,r'!R\-?(0|[1-9][0-9]*)(\.[0-9]+)?')
def no0(s):
"""Removes redundant initial zero from number"""
return s[1:] if I(s,0)=='0' and I(s,1,'X') in '0123456789' else s
def nco(s):
"""Puts commmas into English number string"""
z=spl(s,'.'); import re
return re.sub(r'(?<=[0-9])([0-9]{3})(?=([0-9]{3})*$)',r',\1',
z[0])+z[1]+z[2]
def sround(xs,n=0):
"""Rounds a string number to n dec places, 0 gives an int"""
z=spl(xs,'.')
if not isx(xs) or len(z[2])<=n:
return xs
if z[2][n] in '01234':
az='0' if z[0]=='-0' and z[2][:n]=='0'*n else z[0]
return az+('.' +z[2][:n] if n>0 else '')
zz=str(eval('1'+z[2][:n])+1)
if zz[0]=='1':
return z[0]+('.'+zz[1:] if n>0 else '')
return str(eval(z[0])+(-1 if z[0][0]=='-' else 1))+\
('.'+zz[1:] if n>0 else '')
def nword(nn):
"""Converts to a word if integer 1-9, else just to a string"""
n=eval(nn) if type(nn)==str and isn(nn) else nn
if n in range(1,10):
return ['one','two','three','four','five','six','seven','eight',
'nine'][n-1]
return str(n)
def ifpl(n,plst='s',sst=''):
"""returns s or other pl if n not 1, else empty or other sing"""
return sst if n==1 else plst
def less(x,y):
"""?Is x less than y (nos. by value then strings wo diacritics)"""
x=eval(x) if type(x)==str and isx(x) else x
y=eval(y) if type(y)==str and isx(y) else y
if type(y)==str and type(x)!=str:
return True
if type(x)==str and type(y)!=str:
return False
if type(y)!=str:
return x<y
a=rom(x); b=rom(y); c=J2j(a); d=J2j(b)
if a==b:
return x<y
if c==d:
return a<b
return c<d
def lless(p,q):
"""?Is list p less than q"""
p=a2p(p); q=a2p(q)
for n in range(max(len(p),len(q))):
if n==len(p):
return True
if n==len(q):
return False
if less(p[n],q[n]):
return True
if less(q[n],p[n]):
return False
return False
def rless(p,q,col=-2,m=0,n=0):
"""?Is p less than q by col (m and n: params if col an eval str"""
return lless(per(col,m,p),per(col,n,q))
def ins(L,p,col=-2,cp=-2):
"""Inserts p (changed per cp) in list, in order defined by col"""
m=0; n=len(L); p=per(cp,0,p)
while m!=n:
h=(m+n)/2
if rless(p,L[h],col):
n=h
else:
m=h+1
return L[:n]+[p]+L[n:]
def sort(L,col=-2,cp=-2,topn=0):
"""Returns cp-ed list of lists/tuples sorted by columns cs (top n only)"""
OL=[]; n=len(L) if topn==0 else topn
for p in L:
OL=ins(OL,p,col)[:n]
return OL
def getnos(s,decpts='.,'): #must be some decpts
"""Returns normed nos; number blocks; intervening blocks (ie 1 more)"""
import re
t=re.split(r'((?:[0-9]|['+reesc(decpts)+'](?=[0-9]))+)',s)
p=rows(t,'1','str(!%%2)'); q=rows(t,'0','str(!%%2)'); k=[]
for x in p:
x=no0(x.replace(',','.'))
if isx(x):
k.append(x)
return k,p,q
def normno(st,u,v,U,V,tolog=''):
"""norms a number string (or ''), w warning + error limits"""
s=replaces(st,[(' ',' '),("'",' '),(' ,',' ;'),(' ','')])
k=sf(s,('(','<','{','['))
if k>0:
s=noex(s[:k]); log('*'+tolog+' from '+st+' to: '+s)
if s=='':
return ''
k=sf(s,',')
if k>0:
if '.' in s:
s=s[:k].replace('.','')+'.'+s[k+1:]
log('*'+tolog+' from '+st+' to: '+s)
else:
s=s[:k]+'.'+s[k+1:]
if not isx(s):
log('**'+tolog+' NOT NUMERICAL: '+st); return ''
d=eval(s)
if d<U or d>V:
log('**'+tolog+' OUT OF RANGE: '+s+' ('+str(U)+','+str(V)+')')
return ''
if d<u or d>v:
log('*'+tolog+' outside range?: '+s+' ('+str(u)+','+str(v)+')')
if str(d)!=s:
log('*'+tolog+' from: '+st+' got '+s)
return s
def ascoo(s):
"""Converts string/list to six-coo string, or err/warn"""
p=getnos(a2s(upto(s,('E|','source'))))[0]; g=row(g_coo,g_lang,0,1)
if len(p)==2 and '.' in p[0] and '.' in p[1]:
x=eval(p[0]); m=int(x); mm=int((x-m)*60.0+0.5)
y=eval(p[1]); n=int(y); nn=int((y-n)*60.0+0.5)
r=[str(m),str(mm),'',str(n),str(nn),'']
elif len(p)==4 and '.' not in p[0]+p[2]:
r=[str(p[0]),sround(str(p[1])),'',str(p[2]),sround(str(p[3])),'']
elif len(p)==6 and '.' not in p[0]+p[1]+p[3]+p[4]:
r=[str(p[0]),str(p[1]),sround(str(p[2])),
str(p[3]),str(p[4]),sround(str(p[5]))]
else:
#log('**no coords from: '+s)
return '|||||'
for i in (2,5,1,4):
if r[i]=='60':
#log('*60 in coords: '+s)
r[i]='0'; r[i-1]=str(eval(r[i-1])+1)
if eval(r[0]) not in range(g[0],g[1]+1) or \
eval(r[3]) not in range(g[2],g[3]+1) or \
eval(r[1]) not in range(0,60) or eval(r[4]) not in range(0,60) or \
r[2]!='' and eval(r[2]) not in range(0,60) or \
r[5]!='' and eval(r[5]) not in range(0,60):
log('**strange coords from: '+s)
return '|||||'
return a2s(r,'|')
def coo2xy(c):
"""Pipe-sep coor string to decimals or 0,0"""
d=[]
for k in a2l(c,'|'):
d.append(0 if k=='' else eval(k))
return d[0]+d[1]/60.0+d[2]/3600.0,d[3]+d[4]/60.0+d[5]/3600.0
def kmdir(x,y,X,Y):
"""Returns distance and direction of (x,y) from (X,Y) (within Poland)"""
import math
vx=(x-X)*110.946
vy=(y-Y)*111.319*math.cos(math.radians((x+X)/2))
d=int(math.sqrt(vx*vx+vy*vy))+1
if vx>2.42*abs(vy):
pt='north'
elif -vx>2.42*abs(vy):
pt='south'
elif vy>2.42*abs(vx):
pt='east'
elif -vy>2.42*abs(vx):
pt='west'
else:
pta='north' if vx>0 else 'south'
ptb='east' if vy>0 else 'west'
pt=pta+'-'+ptb
return d,pt
def km(c,d):
"""Distance between coord | strings"""
x,y=coo2xy(c); X,Y=coo2xy(d)
return kmdir(x,y,X,Y)[0]
def kmtxt(dc,dcb,u,v,U,V,abbr,tolog):
"""Makes text e.g. 8 km north, of dc from dcb (warning/error limits)"""
x,y=coo2xy(dc); X,Y=coo2xy(dcb)
d,pt=kmdir(x,y,X,Y)
if d<U or d>V:
log('**'+tolog+' DIST REJECTED: '+str(d)+' ('+str(U)+','+str(V)+')')
return ''
if d<u or d>v:
log('*'+tolog+' distance wrong?: '+str(d)+' ('+str(u)+','+str(v)+')')
return '{{convert|'+str(d)+'|km|mi|0'+('|abbr=on' if abbr else '')+'}} '+pt
def loctxts(name,c,*p):
"""Full text: name, coords, list of coo/name/text/uvUV/pri 8s (V2 16s)"""
L=[]; M=[]; N=[]
for x in p:
if len(x)==16:
A1=km(c,x[0]); A2=km(c,x[8])
A3=km(x[0],x[8]); Ah=max(A1,A2); Ab=min(A1,A2)
X1,X2=(x[:8],x[8:]) if Ab==A1 else (x[8:],x[:8])
L=L+[X1] if 2*(Ah*Ah-Ab*Ab)>A3*A3 else L+[X1,X2]
else:
L.append(x)
for K in L:
if list(K)==sort(rows(L,K[1],1),7)[-1] and K[1]!=name:
M.append(K)
for K in M:
t=kmtxt(c,K[0],K[3],K[4],K[5],K[6],K!=M[0],K[7])
if t=='':
return ''
if not starts(t,'{{convert|1|'):
N.append(t+' of '+K[2])
else:
log('*omitted: '+t+' of '+K[2])
returnstr='approximately '+l2txt(N)
return returnstr if len(N)>0 else ''
def st2date(s):
"""Converts string to proper date"""
w=getnos(s,'@')[0]
if len(w)==1 and isn(w[0]) and eval(w[0]) in range (2000,2010):
return w[0]
if len(w)==3 and isn(w[2]) and eval(w[2]) in range (2000,2010) and\
isn(w[1]) and eval(w[1]) in range(1,13) and\
isn(w[0]) and eval(w[0]) in range(1,30 if w[1]=='2' else (31 if
w[1] in ('4','6','9','11') else 32)):
return w[0]+' '+('January','February','March','April','May','June',
'July','August','September','October','November',
'December')[eval(w[1])-1]+' '+w[2]
return ''
def urlread(url,tries=50):
"""Gets url text"""
import urllib
n=0
while n<tries:
try:
ur=urllib.urlopen(url)
r=ur.read(); ur.close()
return r
except:
n=n+1
return 0/0
def wpraw(la,Art):
return urlread('http://'+la+'.wikipedia.org/w/index.php?title='
+Art.replace(' ','_')+'&action=raw')
def wcraw(Art):
return urlread('http://commons.wikimedia.org/w/index.php?title='+
Art.replace(' ','_')+'&action=raw')
def catcont(la,cat):
"""Returns subcats, members, subckeys, membkeys, sdates, mdates (->500)"""
import re; login(la); SC=[]; M=[]; SCK=[]; MK=[]; SCD=[]; MD=[]
xm=urlread('http://'+la+'.wikipedia.org/w/api.php?cmtitle=Category:'
+cat.replace(' ','_')+'&action=query&list=categorymembers'+
'&cmlimit=500&cmprop=title|sortkey|timestamp')
rg=r'title=\"(.*?)\".*?sortkey=\"(.*?)\".*?'+\
r'timestamp=\"(.*?)\"'
for m in re.findall(rg,xm):
if starts(m[0],'Category:'):
SC.append(m[0][9:]); SCK.append(m[1]); SCD.append(m[2])
else:
M.append(m[0]); MK.append(m[1]); MD.append(m[2])
return SC,M,SCK,MK,SCD,MD
def fullcatcont(la,cat,d=5):
"""Returns all pages below a cat to a depth of d, +cats they're in"""
cs=[[cat,'0']]; ps=[]
for k in range(d+1):
for c in rows(cs,str(k),1,0):
a,b,w,x,y,z=catcont(la,c)
for p in b:
u=lf(ps,p,0)
if u<0:
ps.append([p,c])
else:
ps[u].append(c)
for s in a:
if s not in col(cs,0):
if k<d:
cs.append([s,str(k+1)])
else:
ps.append(['Category:'+s,c])
log([[cat,d]]+ps)
return
def coca():
"""Investigate unmatched categories"""
c=F('colog')[0]
for a in c:
x=catsin(wpraw('en',a)); y=catsin(wpraw('en','Category:'+a))
os=''; ns=''
for p in y:
if p not in x:
if 's ' in p+' ':
os=os+'[[Category:'+p+']]\n'
else:
ns=ns+p+','
log('\n'+a+' ('+ns+')\n'+os)
return 9
def isim(name):
"""?Is ready-trimmed name an image in commons or wp"""
if '.' not in name[1:-1] or sf(name,list('[]{}<>#|'))>-1:
return False
return wcraw('Image:'+name)!='' or wpraw('en','Image:'+name)!=''
def IFim(name):
"""Name if image (or Image: etc.), else empty"""
if isim(name):
return name
if isim(after(name,':')):
return after(name,':')
return ''
def nocomm(text):
"""Removes comments from wikipedia text"""
return subs(text,[(r'\<!--(?:.|\n)*?--\>','')])
def nam(st):
"""Main name part of string, less tag"""
return upto(st,(',','('))
def tag(st):
"""Tag after comma or in brackets"""
return mgp(r', (.*)|\((.*)\)',st)
def essnam(st):
"""Removes generic part of name"""
p=(' ','Gmina','Wojew\xC3\xB3dztwo','Powiat','Park Narodowy',
'Park Krajobrazowy','Okres')
q=(' ','County','Voivodeship','National Park','Landscape Park',
'Park Narodowy','Park Krajobrazowy','District','Region',' kraj')
return notrail(noinit(nam(st),p),q)
def wpl(st):
"""Make WP (piped) link, not displaying the tag"""
name=nam(st)
return '[['+st+']]' if name==st else '[['+st+'|'+name+']]'
def essl(st):
"""Make WP (piped) link, not displaying the tag"""
name=essnam(st)
return '[['+st+']]' if name==st else '[['+st+'|'+name+']]'
def Title(na):
"""Makes WP title, w capital and no underscores"""
return st2St(noex(na.replace('_',' ')))
def targlabel(link):
"""The _T_arget and display text of first wp link (removes extr spaces)"""
m=mgps(r'\[\[(.+?)(?:\|(.*?))?\]\]',link)
if len(m)==0:
return '',link
return Title(m[0]),I(m,1,m[0])
def targ(link):
return targdisp(link)[0]
def label(link):
return targdisp(link)[1]
def redtarg(txt):
"""redirect target in txt or empty string"""
m=mgp(r'^[ \n]*\#(?:REDIRECT|redirect|Redirect)[ ]*(\[\[.*\]\])',nocomm(txt))
return I(m,0)
def targpars(t):
"""Name and list of parameter pairs for a template call"""
import re; m=re.split('\|',subs(t,[('^\{\{',''),('\}\}$','')])); L=[]; n=1
if len(m)==0:
return '',[]
for x in m[1:]:
mm=mgps(r'^(?:[ \n]*(.+?)[ \n]*\=)?[ \n]*((?:.|\n)*?)[ \n]*$',x)
a,b=(mm[0],mm[1]) if len(mm)==2 else (str(n),I(mm,0))
n=n if len(mm)==2 else n+1
L=rows(L,a,0,-2,0)+[[a,b]]
return Title(m[0]),L
def imnam(st):
"""Returns image filename only"""
st2=noinit(st,(' ','[','Image:','image:','grafika:','Grafika:'))
st3=noex(upto(st2,('|',']')))
return st3 if '.' in st3 else ''
def esctext(tx):
"""Converts article text to string structure"""
sl=[tx]
sl=mspl(sl,r'\[\[[^\|\[\]\<\>\{\}\n]+(?:\|.*?)?\]\]','\n')
sl=mspl(sl,r'\[\[(?:Image|image|Grafika|grafika)\:[^\|\[\]\<\>\{\}\n]+'+\
r'(?:\|(?:.|(?<=!;)\n)*?)?\]\]','\n\n')
sl=mspl(sl,r'\{\{[ \n]*[^\|\[\]\<\>\{\}\n]+?[ \n]*(?:\|[^\{\}]*?)?\}\}','')
sl=mspl(sl,r'\{\{[ \n]*[^\|\[\]\<\>\{\}\n]+?[ \n]*(?:\|(?:.|\n)*?)?\}\}','')
return sl
def ansl(sl):
"""Gets lists of links/templates/f values from string structure"""
LL=[]; LT=[]; LF=[]; u=subslist(sl)
for s in sl[1:]:
if I(s,0)=='[':
Q=targlabel(s); LL.append((subs(Q[0],u),subs(Q[1],u),subs(s,u)))
else:
Q,QL=targpars(s); LT.append((Q,subs(s,u)))
for p in QL:
LF.append((Q,p[0],subs(p[1],u)))
return LL,LT,LF
def ant(t):
"""Links (targ,lab,tx), templates (targ,tx), fvals (tem,f,val,tx)"""
return ansl(esctext(t))
def catsin(tx):
"""All categories explicitly in tx"""
k=sf(tx,('[[Category:','[[category:'))
if k<0:
return []
t=tx[max(0,k-10):]; L=[]
for a in ant(t)[0]:
if starts(a[0],'Category:'):
L.append(a[0][9:])
return L
def iwto(tx,la):
"""Target(s$) of iwlink to language la in tx, else empty"""
k=sf(tx,'[['+la+':')
if k<0:
return ''
t=tx[max(0,k-10):]
return I(row(ant(t)[0],'!R'+st2St(la)+':.+',0),0)[3:]
def fv(tx,tem,*f):
"""Named field values"""
L=[]; fl=rows(ant(tx)[2],tem,0)
for x in f:
L.append(I(row(fl,x,1),2))
return L[0] if len(L)==1 else L
def IPA(st):
"""converts Polish string to IPA representation"""
import re; s=' '+rplus(st).replace('-',' ')+' '
if not re.match(r'( [A-PR-UWXZ]?[a-pr-uwxyz\+]+)+ $',s):
return ''
s=subs(J2j(s),[(' w ',' w'),(' z ',' z'),('ch','h'),(r'o\+','u'),
('ia','Ja'),('ie','Je'),('io','Jo'),('iu','Ju'),
('ai','aj'),('ei','ej'),('oi','oj'),('ui','uj'),('au','aL'),
(r'sJ|s\+|s(?=i)','S'),(r'zJ|x\+|z(?=i)','X'),(r'cJ|c\+|c(?=i)','C'),
(r'nJ|n\+','N'),(r'z\+','Z'),(r'l\+','L'),(r'a\+','o9'),(r'e\+','e9'),
('dZ','B'),('dX','D'),('dz','0'),('sz','T'),('cz','1'),('rz','R'),
('9(?=[bp])','m'),('9(?=[tcC1dBD0gk])','n'),('9l','l'),
('(?<=[aeiouy])L(?![aeouy])','U'),('(?<=[aeiouy])j(?![aeou])','I'),
('ji|ii','i')])
L=[]
for n in range(11):
L.append(('bd0BDg'[n]+'(?=[ c1CfhkpstTS4])','ptc1Ck'[n]) if n<6 else\
('wzZXR'[n-6]+'(?=[ c1CfhkpstTS4])|(?<=[c1CfhkpstTS4])'+'wzZXR'[n-6],
'fsTS4'[n-6]))
for n in range(3):
s=subs(s,[(' nad ',' na8d')]+L+[('8d','d '),('8t','t ')])
s=subs(s,[('(((?<= )[^aeiouy ]*|[^aeiouy ]?)([aeiouy][^aeiouy ]*){1,2} )',
r"'\1"),("([bdfghkpsSTtwzZX])'(?=[rR4])",r"'\1"),
("([bfghkpsSTwzZX])'(?=[lL])",r"'\1"),
("([^aeiouy ])'(?=[J])",r"'\1")])
s=s.replace("'",'') if nin(s,"'")==1 and nin(s,list('aeiouy'))<2 else s
s=subs(s,[("'nad ",",nad "),("'nat ",",nat "),('(?<=[SXCDN])e','E'),
("n(?='?[kg])",'5'),('(?<=[^kg])J','j'),('o9','A'),('e9|E9','Y')])
mhl=[(' ','-'),('A',U('a+')),('Y',U('e+')),('B',U('dz+')),('C',U('c+')),
('D',U('dx+')),('E','e' if 'e' in s else 'e1'),('L',U('l+')),
('N',U('n+')),('R',U('z+')),('S',U('s+')),('T','sz'),('X',U('x+')),
('Z',U('z+')),('0','dz'),('1','cz'),('4','sz'),('5','N')]
os='{{IPAc-pl|[]|'
for n in range(1,len(s)-1):
os=os+I(row(mhl,s[n],0),1,s[n])+'|'
if n%28==0 and n<len(s)-2:
os=os[:-1].replace(']','-')+'}}{{IPAc-pl|-]|'
return os[:-1].replace('[]|','')+'}}'
def countystub(p):
pp=p if essnam(p) in ('Opole','Lublin') else essnam(p)
return pp.replace(' ','')+'-geo-stub'
def skey(st):
"""Makes standard category sort key (returns empty if comes to defa)"""
s=rom(st); os=''; import re
for a in re.split(r'[^a-zA-Z]+',s):
os=os+j2J(I(a,0))+J2j(a[1:])+' '
return noex(os)
def expandtem(s):
"""Expands s"""
ur0='http://en.wikipedia.org/wiki/Special:ExpandTemplates'
ht=doreq(ur0,[('contexttitle',''),('input',s),
('removecomments','1'),('generate_xml','0')])
return mup(mgp(r'id\="output".*\>((?:[ .]*?)\</textarea\>',ht))
#
# BOT
#
def Ne(x,y):
return x==y or x==y+'\n' or y==x+'\n'
def formv(form,*ns):
"""Find the given value of a named input in an HTML form"""
L=[]
for nam in ns:
L.append(mgp(r'\<[^\>]*(?:name\="'+nam+r'"[^\>]*value\="(.*?)"'+\
r'|value\="(.*?)"[^\>]*name\="'+nam+r'")',form))
return L[0] if len(L)==1 else L
def mup(html):
"""Marks up &#ref and &ref; chars. in an html string without tags"""
global MuPsTr; MuPsTr=[''] #output string as 1-list
import sgmllib
pa=sgmllib.SGMLParser()
pa.handle_data=writetoMuPsTr #how to handle input
pa.feed(html) #read and handle input
pa.close()
return MuPsTr[0]
def writetoMuPsTr(s):
"""Appends a string to sole element of the global list MuPsTr"""
"""Used in mup() as the data handler"""
MuPsTr[0]=MuPsTr[0]+s
return
def doreq(url,dl=''):
"""Makes an HTTP request and sends it; supplies and extracts cookies"""
"""Returns the response html content, or 'KBerrKB on failure"""
"""dl is the optional data list (of key/value pairs) for a POST"""
"""The global cookie jar is botjar"""
import urllib, urllib2, cookielib
req=urllib2.Request(url) #make Request object
g_jar.add_cookie_header(req) #add relevant cookies
req.add_header('User-agent','Agent.Kotbot') #add User Agent header
if dl!='':
req.add_data(urllib.urlencode(dl)) #add data (changes type to POST)
n=0
while n<50:
try:
u=urllib2.urlopen(req) #send the request
g_jar.extract_cookies(u,req) #extract cookies from response
html=u.read() #get content from response
u.close()
return html
except: #if error, retry
n=n+1
return 'KBerrKB'
def php(la):
"""Returns main part of generic php access string to Wikipedia"""
return 'http://'+la+'.wikipedia.org/w/index.php?title='
def login(la):
"""Initializes global cookiejar, and logs in as the bot"""
"""Languages (las...) can include 'en' and/or 'pl'"""
import cookielib; global g_jar
if g_jar==0:
g_jar=cookielib.CookieJar() #makes global cookie jar
if la not in g_loggedon:
ur0=php(la)+'Special:Userlogin'
doreq(ur0) #get login page
ur1=ur0+'&action=submitlogin&type=login'
dl1=[('wpName',g_user),('wpPassword',g_pass),
('wpRemember','0'),('wpLoginattempt','Log+in')]
rt=doreq(ur1,dl1) #submit form
if rt=='KBerrKB':
log('*FAILEDTOLOGON: '+la)
else:
a2fi('\nLOGGEDON: '+la,'botlog'); g_loggedon.append(la)
return
def edit(la,Art,instr,*params):
"""Edits Wikipedia page according to instruction (and parameters)"""
""" la is the language code, Art is the page name"""
""" instr is the instruction (the function 'edit_'instr will be called)"""
"""Confirms if edit made (adds result to return message)"""
"""Botlogs la:Art:message, returns message and any output"""
global g_logcon; g_logcon=la+':'+Art
login(la); ur0=php(la)+Art.replace(' ','_')+'&action=edit' #edit page url
html=doreq(ur0) #get edit page
if html=='KBerrKB':
log('*NETWORKFAULT1'); return
if g_user not in html:
log('*NOTLOGGEDON'); return
m=mgps(r'name\=\"wpTextbox1\".*?\>((?:.|\n)*?)\<\/textarea\>',html)
if len(m)==0:
log('*BADEDITPAGE'); return
old=mup(m[0]) #existing text or empty string
FUNC=eval('edit_'+instr) #function to be called
#now call the function and get new text, edit summary, message and any output
newtext,summ,mess=FUNC(la,Art,old,*params)
if newtext=='': #end if no new text provided
log(mess) if mess!='' else ''; return
if Ne(newtext,old):
log('*NEWTEXTSAMEASOLD'); return
#now make data list (lp) for POST request
lp=[]; n=sf(html,'id="editform"') #find edit form
for a in ['wpSection','wpStarttime','wpEdittime','wpScrolltop',
'wpEditToken','wpAutoSummary']:
val=formv(html[n:],a) #find each named value on form
lp=lp+[(a,val)] #add key/value pair to list
lp=lp[:4]+[('wpTextbox1',newtext),('wpSummary',summ),
('wpSave','Save page')]+lp[4:]
#now submit the form
ur1=php(la)+Art.replace(' ','_')+'&action=submit' #make the url
htmr=doreq(ur1,lp) #submit the POST request, get response
if htmr=='KBerrKB':
log('*NETWORKFAULT2'); return
#check if the edit was successful
now=wpraw(la,Art) #this is the page text now
conf='[OK]' if Ne(now,newtext) else '[*NOCONFIRM]'
log(mess,conf) if '*' in mess+conf else a2fi((la,Art,mess,conf),'botlog')
return
def qedit(la,Art,instr,*params):
"""As edit, but starts by reading raw"""
global g_logcon; g_logcon=la+':'+Art
exi=wpraw(la,Art); FUNC=eval('edit_'+instr)
newtext,summ,mess=FUNC(la,Art,exi,*params)
if newtext=='': #end if no new text provided
log(mess) if mess!='' else ''; return
if Ne(newtext,exi):
log('*NEWTEXTSAMEASOLD'); return
login(la); ur0=php(la)+Art.replace(' ','_')+'&action=edit' #edit page url
html=doreq(ur0) #get edit page
if html=='KBerrKB':
log('*NETWORKFAULT1'); return
if g_user not in html:
log('*NOTLOGGEDON'); return
m=mgps(r'name\=\"wpTextbox1\".*?\>((?:.|\n)*?)\<\/textarea\>',html)
if len(m)==0:
log('*BADEDITPAGE'); return
old=mup(m[0]) #get and mark up content of text area
if not Ne(old,exi):
log('*UNSTABLEPAGE'); return
#now make data list (lp) for POST request
lp=[]; n=sf(html,'id="editform"') #find edit form
for a in ['wpSection','wpStarttime','wpEdittime','wpScrolltop',
'wpEditToken','wpAutoSummary']:
val=formv(html[n:],a) #find each named value on form
lp=lp+[(a,val)] #add key/value pair to list
lp=lp[:4]+[('wpTextbox1',newtext),('wpSummary',summ),
('wpSave','Save page')]+lp[4:]
#now submit the form
ur1=php(la)+Art.replace(' ','_')+'&action=submit' #make the url
htmr=doreq(ur1,lp) #submit the POST request, get response
if htmr=='KBerrKB':
log('*NETWORKFAULT2'); return
#check if the edit was successful
now=wpraw(la,Art) #this is the page text now
conf='[OK]' if Ne(now,newtext) else '[*NOCONFIRM]'
log(mess,conf) if '*' in mess+conf else a2fi((la,Art,mess,conf),'botlog')
return
#
# BOT EDIT FUNCTIONS
# Each edit_xx function must take as arguments:
# la (lang. code), Art (page name), old (old page text or empty), params...
# It must return:
# new page text (empty=no edit), edit summary, b(ot)log message
#
def edit_New(la,Art,old,text,summ='bot creating page',suppr='!DUMMY!'):
"""text, summary, list to suppress logging of text if art found"""
if not Ne(old,''):
if sf(old,suppr)>-1:
return '','','*ARTEXISTS('+str(len(old))+')'
else:
return '','','*ARTEXISTS('+str(len(old))+') for:\n'+text+'\n'
return text,summ,'CREATED'
def edit_Force(la,Art,old,text,summ='bot: standardizing'):
"""text, summary"""
if Ne(old,''):
log('*HADTOCREATE')
return text,summ,'HADTOCREATE' if Ne(old,'') else 'REPLACEDARTICLE'
def edit_Subst(la,Art,old,lp,summ='bot: standardizing'):
"""list of replace pairs (or 6ples, with min/max, warn min/max)"""
t=old
for p in lp:
k=nin(old,p[0])
if k<I(p,2,0) or k>I(p,3,1000):
print g_logcon, k, I(p,2,0), I(p,3,1000)
return '','','*WRONGNUMBEROF '+p[0]
if k<I(p,4,0) or k>I(p,5,1000):
log(Art+';*NOTE NUMBER OF '+p[0]+':'+str(k))
t=t.replace(p[0],p[1])
return t,summ,'REPLACED'