User:Kotbot/Source

# 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=&nbsp;\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,[('&nbsp;',' '),("'",' '),(' ,',' ;'),(' ','')])
    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]+'&nbsp;'+('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=\&quot;(.*?)\&quot;.*?sortkey=\&quot;(.*?)\&quot;.*?'+\
        r'timestamp=\&quot;(.*?)\&quot;'
    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'

Content Disclaimer

Informasi ini disarikan dari Wikipedia dan disajikan kembali untuk tujuan edukasi. Konten tersedia di bawah lisensi CC BY-SA 3.0. Kami tidak bertanggung jawab atas ketidakakuratan data yang bersumber dari kontribusi publik tersebut.

  1. The information displayed on this website is sourced in part or in whole from Wikipedia and has been adapted for the purpose of restating it. We strive to provide accurate and relevant information, however:
  2. There is no guarantee of absolute accuracy. Wikipedia is an open, collaborative project that can be edited by anyone, so information is subject to change.
  3. It is not intended to constitute professional advice. The content displayed is for informational and educational purposes only. For important decisions (e.g., medical, legal, or financial), please consult a professional.
  4. Content copyright. Wikipedia is licensed under the Creative Commons Attribution-ShareAlike License (CC BY-SA). This means that content may be reused with appropriate attribution and shared under a similar license.
  5. Responsible use. Any risk arising from the use of information from this website is entirely the responsibility of the user.