Wikipedysta:Olafbot/OlafbotCalendar.java

Z Wikipedii, wolnej encyklopedii

Ten kod dodał strony kalendarium i zmienia tabelki władców. Dokładniejszy opis jest tutaj.

/*                                                        */
/*                Olafbot for Wikipedia                   */
/*                                                        */
/*                   Olaf Matyja 2004                     */
/*                                                        */

//21986 artykulow przed dodaniem dat
//22645 po dodaniu dat

import java.lang.*;
import java.net.*;
import java.io.*;
import java.util.*;
import java.io.Reader.*;

public class OlafBotCalendar {
        final static String dirPath="d:/Olaf/Olafbot";
    
        //polish letters
        final static String a="%C4%85";
        final static String c="%C4%87";
        final static String e="%C4%99";
        final static String l="%C5%82";
        final static String n="%C5%84";
        final static String o="%C3%B3";
        final static String s="%C5%9B";
        final static String x="%C5%BA";
        final static String z="%C5%BC";
        final static String A="%C4%84";
        final static String C="%C4%86";
        final static String E="%C4%98";
        final static String L="%C5%81";
        final static String N="%C5%83";
        final static String O="%C3%93";
        final static String S="%C5%9A";
        final static String X="%C5%B9";
        final static String Z="%C5%BB";
        final static String plus="%2B";
        final static String ampersand="%26";
        
        final static int startCal=5; // 5 AD
        static InetAddress wikipedia=null;
        static String session="800737744ba08333e8d3802105395f51";
        static String editTime="";
        static String interwikiChanged="";
        static boolean calendarSorted=false;
        static boolean astroEventAdded=false;
        
        final static String mianMies[]={
		"Stycze"+n,
		"Luty",
		"Marzec",
		"Kwiecie"+n,
                "Maj",
                "Czerwiec",
		"Lipiec",
		"Sierpie"+n,
		"Wrzesie"+n,
		"Pa"+x+"dziernik",
		"Listopad",
		"Grudzie"+n
	};

	final static String dopMies[]={
		"stycznia",
		"lutego",
		"marca",
		"kwietnia",
                "maja",
                "czerwca",
		"lipca",
		"sierpnia",
		"wrze"+s+"nia",
		"pa"+x+"dziernika",
		"listopada",
		"grudnia"
	};

        final static String mianMiesBezPol[]={
		"Styczen",
		"Luty",
		"Marzec",
		"Kwiecien",
                "Maj",
                "Czerwiec",
		"Lipiec",
		"Sierpien",
		"Wrzesien",
		"Pazdziernik",
		"Listopad",
		"Grudzien"
	};

	final static String dopMiesBezPol[]={
		"stycznia",
		"lutego",
		"marca",
		"kwietnia",
                "maja",
                "czerwca",
		"lipca",
		"sierpnia",
		"wrzesnia",
		"pazdziernika",
		"listopada",
		"grudnia"
	};

        final static String mediaKal[][]={{
            "Kalendarz_od_poniedzia"+l+"ku",
            "Kalendarz_od_wtorku",
            "Kalendarz_od_"+s+"rody",
            "Kalendarz_od_czwartku",
            "Kalendarz_od_pi"+a+"tku",
            "Kalendarz_od_soboty",
            "Kalendarz_od_niedzieli"
        },{
            "Kalendarz_od_poniedzia"+l+"ku_przest"+e+"pny",
            "Kalendarz_od_wtorku_przest"+e+"pny",
            "Kalendarz_od_"+s+"rody_przest"+e+"pny",
            "Kalendarz_od_czwartku_przest"+e+"pny",
            "Kalendarz_od_pi"+a+"tku_przest"+e+"pny",
            "Kalendarz_od_soboty_przest"+e+"pny",
            "Kalendarz_od_niedzieli_przest"+e+"pny"
        }};
            
        
	private static class OlafBotException extends Exception {
		boolean fatal;

		OlafBotException(String comment,boolean fatal) {
			super(comment);
			this.fatal=fatal;
		}
	};

	private static class Sovereign extends Object {
		String domain;
		String name;
		int begin;
		int end;
		//String attr;

		Sovereign(String domain,String name,int begin,int end/*,String attr*/) {
			this.domain=domain.trim();
			this.name=name.trim();
			this.begin=begin;
			this.end=end;
			//this.attr=attr;
		}

		boolean ruled(int year) {
			return year>=begin && year<=end;
		}

		String getNameString(int year) {
			if (name.equals(""))
				return "";
			/*String str="";
			if (year!=begin)
					str=str+"[["+yearName(begin,false)+"|{{msg:BeginOfReign}}]] ";
			str+=name;
			if (year!=end && end<=2003)
				str=str+" [["+yearName(end,false)+"|{{msg:EndOfReign}}]]";*/
                        String str="<table border=\"0\" width=\"100%\"><tr>";
			if (year!=begin)
                                str=str+"<td align=\"left\"><small>[["+yearName(begin,false)+"]]</small></td>";
                        else
                                str=str+"<td align=\"left\"><small>"+yearName(begin,false)+"</small></td>";
			str+="<td align=\"center\">"+name+"</td>";
			if (end<=2003)
                                if (year!=end)
                                        str=str+"<td align=\"right\"><small>[["+yearName(end,false)+"]]</small></td>";
                                else
                                        str=str+"<td align=\"right\"><small>"+yearName(end,false)+"</small></td>";
                        else str=str+"<td></td>";
                        str=str+"</tr></table>";

			return str;
		}
	};

	static Vector /*of Sovereign*/ sovereigns=new Vector();

	private static class Event {
		private int year;
		private int month=0;
		private int day=0;
		private String content;

		private boolean parseDate(String date) {
			date=date.trim();
			if (date.equals(""))
				return false;
			int n=date.indexOf(" ");
			if (n<0) {
				for (int m=1;m<=12;m++)
					if (date.equalsIgnoreCase(mianMies[m-1]) ||
                                            date.equalsIgnoreCase(mianMiesBezPol[m-1])) {
						month=m;
						return true;
					}
                        } else {
				String daystr=date.substring(0,n);
				String monstr=date.substring(n+1).trim();
				for (int m=1;m<=12;m++)
					if (monstr.equalsIgnoreCase(mianMies[m-1]) ||
                                            monstr.equalsIgnoreCase(mianMiesBezPol[m-1]) ||
                                            monstr.equalsIgnoreCase(dopMies[m-1]) ||
                                            monstr.equalsIgnoreCase(dopMiesBezPol[m-1])) {
                                                try {
                                                    day=Integer.parseInt(daystr);
                                                    month=m;
                                                } catch (NumberFormatException ex) {
                                                    day=0;                                                    
                                                }
						return true;
					};
                        }
			return false;						
		}

		Event(String text,int year) throws OlafBotException {
			this.year=year;

			text=text.trim();
			while (text.startsWith("*"))
				text=text.length()>1 ? text.substring(1) : "";
			text=text.trim();
                        /*if (text.startsWith("-"))
                                text=text.length()>1 ? text.substring(1) : "";
    			text=text.trim();*/
			if (text.length()==0 || text.equals("*"))
				throw new OlafBotException("Pusty",false);
			
			if (text.startsWith("[[")) {
				int n=text.indexOf("]]");
				if (n<0)
					if (text.length()>2)
						text=text.substring(2);
					else 
						throw new OlafBotException("Wadliwy",false);
				else
					if (parseDate(text.substring(2,n)))
						text=text.substring(n+2);
			}
			else {
				int n=text.indexOf(" ");
				if (n>=0)
					if (parseDate(text.substring(0,n)))
						text=text.substring(n);
					else {
						n=text.indexOf(" ",n+1);
						if (n>=0)
							if (parseDate(text.substring(0,n)))
								text=text.substring(n);						
					}
			}

			content=text.trim();
		}

		String getText() {
			if (month==0)
				return content;
			if (day==0)
				return "[["+mianMies[month-1].toLowerCase()+"]] "+content;
			return "[["+day+" "+dopMies[month-1]+"]] "+content;
		}

		void save(FileWriter fw) throws IOException {
                        if (!content.startsWith("{{msg:NO"))
                                fw.write(""+year+"."+month/10+""+month%10+"."+day/10+""+day%10+" "+content+"\n");
		}

		boolean shouldBeAfter(Event ev) {
			if (year>ev.year)
				return true;
			if (year<ev.year)
				return false;
			if (ev.month==0 || month==0)
				return false;
			if (month>ev.month)
				return true;
			if (month<ev.month)
				return false;
			if (day>ev.day)
				return true;
                        return false;
		}
                
                boolean identical(Event ev) {
                        return year==ev.year && 
                               month==ev.month && 
                               day==ev.day &&
                               content.equals(ev.content);
                }
	};

	private static class EventBag {
		final static String engMon[]={"Nul","Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};

		private String name;
		private int year;
		private boolean noSort=false;
		private Vector /*of Event*/ events=new Vector();
                private boolean ownEvents;

		EventBag(String name,int year,boolean ownEvents) {
			this.name=name;
			this.year=year;
                        this.ownEvents=ownEvents;
		}

		private void sort() {
                        for (int n=0;n<events.size();n++) {
   			    Event a=(Event)events.elementAt(n);
                            for (int m=n+1;m<events.size();m++) {
				Event b=(Event)events.elementAt(m);
                                if (a.identical(b)) {
				    events.removeElementAt(m);
                                    m--;
                                }
                            }
                        }
                                    
			if (noSort)
				return;

                        //System.out.println("start sort"); //todo debug
			boolean changed=true;
			while (changed) {
				changed=false;
				for (int n=1;n<events.size();n++) {
					Event a=(Event)events.elementAt(n-1);
					Event b=(Event)events.elementAt(n);
					if (a.identical(b)) {
                                                System.out.println("rowne "+(n-1)+" i "+n); //todo debug
						events.removeElementAt(n);
						n--;
						changed=true;
						continue;
					}

					if (a.shouldBeAfter(b)) {
                                                System.out.println("zamiana "+(n-1)+" i "+n); //todo debug
                                                System.out.println(a.getText()); //todo debug
                                                System.out.println(b.getText()); //todo debug
						events.removeElementAt(n-1);
						events.insertElementAt(a,n);
						changed=true;
                                                if (!ownEvents)
                                                    calendarSorted=true;
					}
				}
			}
                        //System.out.println("stop sort"); //todo debug
		}

		void add(String event) {
			try {
				event=event.trim();
				if (event.length()==0 || event.startsWith("{{msg:N") ||
                                    event.endsWith("ziemiach polskich")||
                                    event.endsWith("ziemiach prapolskich"))
					return;
				events.add(new Event(event,year));
				if (!event.startsWith("*"))
					noSort=true;
			} catch (OlafBotException ex) {
				//ignore
			}
		}

		void addEvents(String text,String code) {
			StringTokenizer st=new StringTokenizer(code,",");
			while (st.hasMoreTokens()) {
				String tok=st.nextToken().trim();
				StringTokenizer st2=new StringTokenizer(tok," ");
				int year=Integer.parseInt(st2.nextToken());
				
				String mon=st2.nextToken();
				int month=-1;
				for (int m=0;m<=12;m++)
					if (mon.equals(engMon[m]))
						month=m;
				if (month==-1)
					throw new RuntimeException(mon+" "+tok);

				int day=Integer.parseInt(st2.nextToken());
				if (year==this.year) {
					if (month>0)
						add("* [["+day+" "+dopMies[month-1]+"]] - "+text);
					else
						add("* "+text);
                                        astroEventAdded=true;
                                }
			}
		}

		boolean hasElements() {
			return events.size()>0;
		}

		String getText() {
			sort();
			String text="";
			for (int n=0;n<events.size();n++)
				text=text+"* "+((Event)events.elementAt(n)).getText()+"\n";
			if (text.equals(""))
				text="* {{msg:"+name+"}}\n";
			return text;
		}

		void save(String fileName) throws IOException {
			sort();
			FileWriter fw=new FileWriter(dirPath+"/"+fileName,true);
			for (int n=0;n<events.size();n++)
				((Event)events.elementAt(n)).save(fw);
			fw.close();
		}
	};

    static String replaceAll(String src,String from,String to) {
        int start=0;
        while (true) {
            int n=src.indexOf(from,start);
            if (n<0)
                return src;
            src=(n>0 ? src.substring(0,n) : "")+
                to+
                (n+from.length()<src.length() ? src.substring(n+from.length()) : "");
            start=n+to.length();
        }
    }
        
    //connect with the server
    static String connect(String request,String content) throws Exception {
        Socket socket=null;
        try {
            socket= new Socket(wikipedia,80);
            DataInputStream input = new DataInputStream(socket.getInputStream()); 
            PrintStream output = new PrintStream(socket.getOutputStream(),true);
            
            output.println(
                request+
                "Content-type: application/x-www-form-urlencoded\n"+
                "Accept: */*\n"+
                "User-Agent: OlafBot\n"+
                "Host: pl.wikipedia.org\n"+
                "Connection: Keep-Alive\n"+
                "Cache-Control: no-cache\n"+
                "Cookie: plwikiUserName=Olafbot; "+
                        "plwikiSession="+session+"; "+
                        "plwikiUserID=2189; "+
                        "plwikiPassword=deleted\n"+/*00438755835a8e9f8c50f2aa10bf36e3\n"+*/
                "\n"+
                content
            );

            String text="", inputLine;
            
            while ((inputLine = input.readLine()) != null) {
                //if (inputLine.length()>0)
                //    text=inputLine;
                text+=inputLine.trim()+"\n";
                //System.out.println(inputLine);
            }
            text=replaceAll(text,"&lt;","<");
            text=replaceAll(text,"&gt;",">");
            text=replaceAll(text,"&quot;","\"");
            text=replaceAll(text,"&amp;","&");
            //text=URLDecoder.decode(text);
            //System.out.println(text);

            final String sessStr="Set-Cookie: plwikiSession=";
            int sess=text.indexOf(sessStr);
            if (sess>=0) {
                int end=text.indexOf("; path=",sess);
                if (end<0)
                    throw new RuntimeException("Invalid cookie\n"+text);
                session=text.substring(sess+sessStr.length(),end);
            }
            
            final String editStr=" name=\"wpEdittime\"";
            int edit=text.indexOf(editStr);
            if (edit>=0)
                editTime=text.substring(edit-15,edit-1);

            //System.out.println(text+"\n*************************************************"); //TODO debug
            if (text.indexOf("<strong>Masz <a href=\"/wiki/Dyskusja_wikipedysty:Olafbot\"")>=0) {
                    throw new OlafBotException("Program zatrzymany.",true);
            }
            if (text.toLowerCase().indexOf("konflikt edycji")>=0) {
                    throw new Exception("Konflikt edycji");
            }
            if (content.length()==0) {
                    int start=text.indexOf("wrap=\"virtual\">");
                    int end=text.indexOf("</textarea>");
                    if (start<0 || end<0)
                            throw new Exception("Nie znaleziony tekst\n"+text);
                    text=text.substring(start+15,end);
                    for (int n=0;n<text.length();n++) {
                            int z=(int)text.charAt(n);
                            if (z>127 || z<32 && z!=10 || z==(int)'%') {
                                    text=(n>0 ? text.substring(0,n) : "")+
                                         "%"+Integer.toHexString((int)text.charAt(n)).toUpperCase()+
                                         (n<text.length()-1 ? text.substring(n+1) : "");
                            }
                    }
                    //System.out.println(text);//todo debug
                    return text;
            }
            else
                    return null;
        } finally {
            if (socket!=null)
                socket.close();
        }
    }
    
    static String yearName(int year,boolean encoded) {
            return year>0 ? String.valueOf(year) : String.valueOf(1-year)+(encoded ? "_p.n.e." : " p.n.e.");
    }

    static String addInterwiki(String lang,int min,int max,String AC,String BC,int year,String content) {
            boolean interwikiExists=content.indexOf("[["+lang)>=0 || 
                    (lang.equals("da:") && content.indexOf("[[dk:")>=0);

            if (year<min || year>max) {
                    if (!interwikiExists)
                            return "";
                    if (min>max+1) {
                        interwikiChanged=interwikiChanged+"-"+lang+", ";			
                        return "";
                    }
            }

            if (!interwikiExists)
                    interwikiChanged=interwikiChanged+"%2B"+lang+", ";

            String s=String.valueOf(year>0 ? year : 1-year);
            if (lang.equals("hi:")) {
                    String t="";
                    final String hindiDigits="6789ABCDEF";
                    for (int n=0;n<s.length();n++)
                            t+="%EO%A5%A"+hindiDigits.charAt(n);
                    s=t;
            }

            return "[["+lang+
                    ((year<=0 && BC==null) ? "-" : "")+s+
                    ((year>0 || BC==null) ? (AC!=null ? AC : "") : BC)
                    +"]]";
    }

    static String romanNumber(int n,String I,String V,String X) {
            String tab[]=
                    {"",I,I+I,I+I+I,I+V,V,V+I,V+I+I,V+I+I+I,I+X,X};
            return tab[n];
    }

    static String romanNumber(int n) {
            return 
                    romanNumber(n/1000,"M",null,null)+
                    romanNumber((n/100)%10,"C","D","M")+
                    romanNumber((n/10)%10,"X","L","C")+
                    romanNumber(n%10,"I","V","X");
    }

    final static String hex="0123456789ABCDEF";
    static void loadSovereigns() throws Exception {
            DataInputStream input=null;
//            try {
                    String content=null;
                    while (true)
                        try {
                            System.out.println("Ladowanie wladcow...");
                            content=connect(//TODO:debug
                                    "GET /w/wiki.phtml?title=Wikipedia:Edycja_tabelek_w%C5%82adc%C3%B3w&action=edit HTTP/1.1\n",
                                    ""
                            );
                            break;
                        } catch(Exception ex) {
                            ex.printStackTrace();
                        };
                    content=replaceAll(content,"%25","%");
                    int p=content.indexOf("<pre>");
                    if (p<0)
                        throw new Exception ("Brak <pre>");
                    int k=content.indexOf("</pre>",p);
                    if (k<0)
                        throw new Exception ("Brak </pre>");
                    content=content.substring(p+5,k).trim();

                    //input=new DataInputStream(new FileInputStream(dirPath+"/wladcy.txt")); 
                    //PrintStream out=new PrintStream(new FileOutputStream(dirPath+"/wladcy_wiki.txt")); 

                    /*input.readByte();
                    input.readByte();
                    input.readByte();*/
                    
                    /*out.write(0xEF);
                    out.write(0xBB);
                    out.write(0xBF);*/

                    StringTokenizer st=new StringTokenizer(content,"\n");
                    String inputLine,domain=null,attr="";
                    while (st.hasMoreTokens()) {
                            inputLine=st.nextToken();
                          /*String uni="";
                            for (int n=0;n<inputLine.length()-1;n+=2) {
                                uni+=(char)(inputLine.charAt(n)+inputLine.charAt(n+1)*256);
                            }
                            input.read();
                            inputLine=uni;*/
                            inputLine.trim();
                            /*String str="";
                            for (k=0;k<inputLine.length();k++) {
                                    char z=inputLine.charAt(k);
                                    if (z<' ' || z>0x7f || z=='%')
                                            str=str+"%"+hex.charAt(z>>4)+hex.charAt(z&15);
                                    else
                                            str=str+z;
                            }
                            String oldInp=inputLine;
                            inputLine=str;*/
                            //System.err.println(inputLine);
                            if (inputLine.length()==0)
                                    continue;
                            switch (inputLine.charAt(0)) {
                                    case '>':
                                            domain=inputLine.substring(1);
                                            /*out.println("</table>");
                                            out.println("=="+domain+"==");
                                            out.print("<table><tr><th>Imi");
                                            out.write(0xc4);
                                            out.write(0x99);
                                            out.println("</th><th>Lata panowania</th></tr>");*/
                                            domain.trim();
                                            break;
                                    /*case '%':
                                            attr=inputLine.length()>1 ? " "+inputLine.substring(1) : "";
                                            break;*/
                                    default: {
                                            int n=inputLine.indexOf(' ');
                                            if (n<0) 
                                                    throw new OlafBotException("Brak roku: "+inputLine,true);
                                            int begin=Integer.parseInt(inputLine.substring(0,n));
                                            int m=inputLine.indexOf(' ',n+1);
                                            if (m<0) 
                                                    m=inputLine.length()+1;
                                            int end=Integer.parseInt(m<inputLine.length() ? inputLine.substring(n+1,m) : inputLine.substring(n+1));
                                            if (end<begin) 
                                                    throw new OlafBotException("Zly przedzial: "+inputLine,true);
                                            String name=m<inputLine.length() ? inputLine.substring(m+1) : "";
                                            //String nameUTF=m<oldInp.length() ? oldInp.substring(m+1) : "";
                                            name.trim();
                                            //nameUTF.trim();
                                            /*while (nameUTF.endsWith(" "))
                                                nameUTF=nameUTF.substring(0,nameUTF.length()-1);*/
                                            if (name.indexOf("[[")<0 && name.length()>0) {
                                                    name="[["+name.trim()+"]]";
                                                    //nameUTF="[["+nameUTF.trim()+"]]";
                                            }
                                            /*out.print("<tr><td>");
                                            nameUTF=replaceAll(nameUTF,"<br>", " ");
                                            for (k=0;k<nameUTF.length();k++)
                                                out.write((int)nameUTF.charAt(k));
                                            if (end>begin)
                                                out.println("</td><td align=\"right\">[["+yearName(begin,false)+"]]-[["+yearName(end,false)+"]]</td></tr>");
                                            else
                                                out.println("</td><td align=\"right\">[["+yearName(begin,false)+"]]</td></tr>");*/
                                            int length=end-begin;
                                            if (length>50) {
                                                System.out.print(""+length+" ");
                                                System.out.println(inputLine);
                                            }
                                            if (name.startsWith("[[papie"+z+" ") && name.indexOf("|")<0) {
                                                String nm=name.substring(("[[papie"+z+" ").length(),name.length()-2).trim();
                                                name="[[papie"+z+" "+nm+"|"+nm+"]]";
                                            }
                                            sovereigns.add(new Sovereign(domain,name,begin,end/*,attr*/));
                                    }					
                            }
                    }
                    /*out.println("</table>");
                    out.close();*/
                    System.out.println("Wladcy zaladowani ("+String.valueOf(sovereigns.size())+")");
            /*} finally {
                    if (input!=null)
                            input.close();
            }*/
    }

    static String sovereignTable(int year) {
            Vector rows=new Vector();
            for (int n=0;n<sovereigns.size();n++) {
                    Sovereign s=(Sovereign)sovereigns.elementAt(n);
                    if (s.ruled(year))
                            rows.add(s);
            }
            if (rows.size()==0)
                    return "";

            int cols=1;
            for (int n=0;n<rows.size();n++)
                    if (((Sovereign)rows.elementAt(n)).domain.length()!=0) {
                            cols=2;
                            break;
                    }

            String str="<table border=\"1\" bgcolor=\"#F8FFF8\""+(year>=startCal ? " width=\"100%\"" : "")+">\n";
            for (int n=0;n<rows.size();n++) {
                    Sovereign s=(Sovereign)rows.elementAt(n);
                    str=str+"<tr>\n";

                    if (s.domain.length()!=0)
                            str=str+"<td align=\"center\" bgcolor=\"#E0FFE0\">{{msg:Dominium_"+s.domain+"}}</td><td align=\"center\">";
                    else if (cols==2)
                            str=str+"<td colspan=\"2\" align=\"center\">";
                    else 
                            str=str+"<td align=\"center\">";

                    str=str+s.getNameString(year);
                    while (n+1<rows.size() && ((Sovereign)rows.elementAt(n+1)).domain.equals(s.domain))
                            str=str+"<br>"+((Sovereign)rows.elementAt(++n)).getNameString(year);

                    str=str+"</td></tr>\n";
            }
            str=str+"</table>\n";
            return str;
    }

    /*static int calendarType(int year,int month,int day) {
            if (year<1582)
                    return 1;
            if (year>1582)
                    return 2;
            if (month<10)
                    return 1;
            if (month>10)
                    return 2;
            if (day<=4)
                    return 1;
            if (day>=15)
                    return 2;
            return 0;
    }

    static Date JDToGreg(int jd) {
            int l = jd + 68569
            int n = ( 4 * l ) / 146097
            int l = l - ( 146097 * n + 3 ) / 4
            int i = ( 4000 * ( l + 1 ) ) / 1461001
            int l = l - ( 1461 * i ) / 4 + 31
            int j = ( 80 * l ) / 2447
            int d = l - ( 2447 * j ) / 80
            int l = j / 11
            int m = j + 2 - ( 12 * l )
            int y = 100 * ( n - 49 ) + i + l
            return new Date(y,m,d);
    }

    static int JD(int y,int m,int d, int type) {
            if (type==2)
                    return ( 1461 * ( y + 4800 + ( m - 14 ) / 12 ) ) / 4 +
                     ( 367 * ( m - 2 - 12 * ( ( m - 14 ) / 12 ) ) ) / 12 -
                     ( 3 * ( ( y + 4900 + ( m - 14 ) / 12 ) / 100 ) ) / 4 +
                     d - 32075;
            else {
            }
    }*/

    final static int dlugosci[]={0,31,28,31,30,31,30,31,31,30,31,30,31};

    static boolean czyPrzestepny(int year) {
        return (year%4==0) && (year<1582 || (year%100!=0) || (year % 400==0));
    }

    static String dzienSlownie(boolean przestepny,int rok,int dzien,boolean pelna) {
        for (int m=1;m<=12;m++)	{
                int dlug=m==2 ? (przestepny ? 29 : 28) 
                            : rok==1582 && m==10 ? 21 : dlugosci[m];
                if (dzien<=dlug) {
                        int dzien2=rok==1582 && m==10 && dzien>4 ? dzien+10 : dzien;
                        if (pelna)
                                return ""+dzien2+" "+dopMies[m-1];
                        else
                                return "[["+dzien2+" "+romanNumber(m)+"|"+dzien2+"]]";
                }
                dzien-=dlug;
        }
        throw new RuntimeException("nieistniejacy dzien");
    }

    static int tydzien;
    static String generujMiesiac(int rok,boolean przestepny,int miesiac) {
        String t=
                "<table border=\"1\" bgcolor=\"#F8FFF8\" width=\"100%\"><caption>[["+mianMies[miesiac-1]+"]]</caption>\n"+
                "<tr>\n"+
                "<th width=\"12.5%\" bgcolor=\"#E0FFE0\">"+ampersand+"nbsp</th>\n"+
                "<th width=\"12.5%\" bgcolor=\"#E0FFE0\">[[Poniedzia"+l+"ek|Pn]]</th>\n"+
                "<th width=\"12.5%\" bgcolor=\"#E0FFE0\">[[Wtorek|Wt]]</th>\n"+
                "<th width=\"12.5%\" bgcolor=\"#E0FFE0\">[["+S+"roda|"+S+"r]]</th>\n"+
                "<th width=\"12.5%\" bgcolor=\"#E0FFE0\">[[Czwartek|Cz]]</th>\n"+
                "<th width=\"12.5%\" bgcolor=\"#E0FFE0\">[[Pi"+a+"tek|Pt]]</th>\n"+
                "<th width=\"12.5%\" bgcolor=\"#E0FFE0\">[[Sobota|Sb]]</th>\n"+
                "<th width=\"12.5%\" bgcolor=\"#E0FFE0\">[[Niedziela|Nd]]</th>\n"+
                "</tr>\n";

        int dzien=0;
        for (int m=1;m<miesiac;m++)
                dzien+=m==2 ? (przestepny ? 29 : 28) 
                            : rok==1582 && m==10 ? 21 : dlugosci[m];
        int rok1=rok-1;
        int dzien3=rok1*365+(rok1/4)+(rok1>=1582 || rok1==1582 && miesiac>=11 ? -(rok1/100)+(rok1/400)-1 : 410);
        int dzien2=dzien3+dzien;
        int dlug=miesiac==2 ? (przestepny ? 29 : 28) 
                            : rok==1582 && miesiac==10 ? 21 : dlugosci[miesiac];
        int dzienTyg=(dzien2+1)%7;
        boolean byl=false;
        if (miesiac!=1 && dzienTyg!=0)
                tydzien--;
        for (int d=1-dzienTyg;d<=dlug;d++) {
                if ((dzien2+d)%7==0) {
                        if (byl)
                                t=t+"</tr>\n";
                        t=t+"<tr><td bgcolor=\"#E0FFE0\">''"+(tydzien++)+"''</td>";
                        byl=true;
                }
                if (d>=1)
                        t=t+"<td>"+dzienSlownie(przestepny,rok,dzien+d,false)+"</td>";
                else
                        t=t+"<td></td>";
        }
        t=t+"</tr></table>\n";
        return t;
    }

    static boolean process(int year) throws Exception {
        calendarSorted=false;
        astroEventAdded=false;
        String yname=yearName(year,false);
        String yname2=yearName(year,true);
        System.out.println("czytam "+yname);
        String content=connect(//TODO:debug
                "GET /w/wiki.phtml?title="+yname2+"&action=edit HTTP/1.1\n",
                //"GET /w/wiki.phtml?title=Wikipedysta:Olafbot/test_"+yname2+"&action=edit HTTP/1.1\n",
                ""
        ).trim();

        //System.out.println("*"+content+"*"); //TODO debug
        //if (!content.equals(""))
            //throw new OlafBotException("Strona nie jest pusta\n"+content,false); //TODO debug

        EventBag polska=new EventBag("NOWE_WYDARZENIE_W_POLSCE_DODAJ_PO_GWIAZDCE_ZAMIAST_CA"+L+"EJ_TEJ_LINII",year,false);
        EventBag swiat=new EventBag("NOWE_WYDARZENIE_DODAJ_PO_GWIAZDCE_ZAMIAST_CA"+L+"EJ_TEJ_LINII",year,false);
        //EventBag wojna1=new EventBag("NOWE_WYDARZENIE_DODAJ_PO_GWIAZDCE_ZAMIAST_CA"+L+"EJ_TEJ_LINII",year,false);
        EventBag wojna2=new EventBag("NOWE_WYDARZENIE_DODAJ_PO_GWIAZDCE_ZAMIAST_CA"+L+"EJ_TEJ_LINII",year,false);
        EventBag narodziny=new EventBag("NOWY_WPIS_W_SEKCJI_NARODZIN_DODAJ_PO_GWIAZDCE_ZAMIAST_CA"+L+"EJ_TEJ_LINII",year,false);
        EventBag zmarli=new EventBag("NOWY_WPIS_W_SEKCJI_ZMARLI_DODAJ_PO_GWIAZDCE_ZAMIAST_CA"+L+"EJ_TEJ_LINII",year,false);
        EventBag astronomia=new EventBag("NOWE_ZDARZENIE_ASTRONOMICZNE_DODAJ_PO_GWIAZDCE_ZAMIAST_CA"+L+"EJ_TEJ_LINII",year,true);
        EventBag nobel=new EventBag("NOWY_WPIS_W_SEKCJI_NAGRODY_NOBLA_DODAJ_PO_GWIAZDCE_ZAMIAST_TEJ_LINII",year,false);
        EventBag zobacz=new EventBag("",year,true);
        EventBag bag=null;
        StringTokenizer st=new StringTokenizer(content,"\n");
        boolean bylyLata=false;
        while (st.hasMoreTokens()) {
                String line=st.nextToken();
                line.trim();
                if (line.length()==0) {
                        if (bag!=null)
                                bag.add(line);
                        continue;
                }
                if (line.startsWith("Lata") || 
                    line.startsWith("lata") || 
                    line.startsWith("{{msg:calendar4}}") /*|| 
                    line.endsWith("]]</center>") ||
                    line.endsWith("]] </center>") ||
                    line.endsWith("]]  </center>")*/)
                    bylyLata=true;
                if (line.indexOf("alendar6")>=0 || line.indexOf(" rok]]")>=0)
                    break;
                if (bylyLata && (line.charAt(0)=='=' || line.length()>3 && (line.substring(0,3).equalsIgnoreCase("<b>") ||
                                line.substring(0,3).equals("'''")) || 
                                line.length()>5 && (
                                line.substring(0,5).equals("* '''") || line.substring(0,4).equals("*'''") ||
                                line.substring(0,5).equalsIgnoreCase("* <b>") || line.substring(0,4).equalsIgnoreCase("*<b>")))) {
                        if (line.indexOf("ols")>=0)
                                bag=polska;
                        else if (line.indexOf("stronom")>=0)
                                bag=astronomia;
                        else if (line.indexOf("II wojn")>=0 || line.indexOf("II_wojn")>=0 || line.indexOf("Szczeg"+o+l+"owe")>=0 && year>=1930)
                                bag=wojna2;
                        //else if (line.indexOf("I wojn")>=0 || line.indexOf("I_wojn")>=0 || line.indexOf("Szczeg"+o+l+"owe")>=0 && year<1930)
                        //	bag=wojna1;
                        else if (line.indexOf("darzenia")>=0 || line.indexOf("wiecie")>=0)
                                bag=swiat;
                        else if (line.indexOf("rodzili")>=0)
                                bag=narodziny;
                        else if (line.indexOf("obacz te")>=0 || line.indexOf("obacz_te")>=0)
                                bag=zobacz;
                        else if (line.indexOf("marli")>=0)
                                bag=zmarli;
                        else if (line.indexOf("obla")>=0)
                                bag=nobel;
                        else if (line.indexOf("Kalendarz")>=0 || line.indexOf("msg:Swieta")>=0 || line.indexOf("msg:"+S+"wi"+e+"ta")>=0)
                                break;
                        else throw new OlafBotException("Nieznana sekcja: "+line,false);
                        if (bag.hasElements())
                                throw new OlafBotException("Dwukrotnie ta sama sekcja",false);
                        continue;
                }
                if (line.equalsIgnoreCase("* w Polsce") || //TODO wlaczyc
                    line.equalsIgnoreCase("*w Polsce") || 
                    line.equalsIgnoreCase("* na ziemiach polskich") ||
                    line.equalsIgnoreCase("* na ziemiach prapolskich") ||
                    line.equalsIgnoreCase("*na ziemiach polskich") ||
                    line.equalsIgnoreCase("*na ziemiach prapolskich")
                )
                        bag=polska;
                else if (
                    line.equalsIgnoreCase("* na Swiecie") || line.equalsIgnoreCase("* na "+S+"wiecie") || line.equalsIgnoreCase("* na "+s+"wiecie") ||
                    line.equalsIgnoreCase("*na Swiecie") || line.equalsIgnoreCase("*na "+S+"wiecie") || line.equalsIgnoreCase("*na "+s+"wiecie")                     
                )
                        bag=swiat;
                else if (bag==null) {
                        if (line.charAt(0)=='*')
                                throw new OlafBotException("Wpis przed sekcjami: "+line,false);
                } else  if (line.charAt(0)=='*')
                        bag.add(line);
                else if (line.startsWith("[[") && line.endsWith("]]") && line.indexOf(":")>=0)
                    ; //interwiki na koncu
                else throw new OlafBotException("Wpis bez gwiazdki: "+line,false);
        }

        interwikiChanged="";
        String t=
                //add:
                addInterwiki("af:",1570,2037,"",null,year,content)+
                addInterwiki("en:",-498,2049,""," BC",year,content)+
                addInterwiki("simple:",1,0,null,null,year,content)+
                //addInterwiki("bg:",1800,2009,"",null,year,content)+
                addInterwiki("zh:",1983,2004,"%E5%B9%B4",null,year,content)+
                addInterwiki("zh-cn:",1,0,"%E5%B9%B4",null,year,content)+
                addInterwiki("da:",1194,2004,"",null,year,content)+
                //addInterwiki("nds:",2003,2003,"",null,year,content)+
                addInterwiki("eo:",-349,2010,"",null /*-350*/,year,content)+
                addInterwiki("et:",2002,2004,""," eKr",year,content)+
                addInterwiki("fi:",841,2006,"",null,year,content)+
                addInterwiki("fr:",-499,2008,"",null /*-500*/,year,content)+
                addInterwiki("fy:",2001,2004,"",null,year,content)+
                addInterwiki("gl:",1936,1936,"",null,year,content)+
                addInterwiki("he:",2001,2003,"",null,year,content)+
                addInterwiki("hi:",2001,2003,"",null,year,content)+
                addInterwiki("es:",-499,2005,""," adC",year,content)+
                addInterwiki("nl:",1330,2040,""," v. Chr.",year,content)+
                addInterwiki("ia:",1980,2020,"",null,year,content)+
                addInterwiki("ja:",800,2050,"",null,year,content)+
                addInterwiki("ca:",1,2004 /*2003*/,"",null,year,content)+
                addInterwiki("ko:",1,0,null,null,year,content)+
                addInterwiki("lt:",2003,2003,"",null,year,content)+
                addInterwiki("la:",2003,2004,"",null,year,content)+
                addInterwiki("de:",-399,2015,""," v. Chr.",year,content)+
                addInterwiki("no:",2000,2004,"",null,year,content)+
                addInterwiki("ru:",1,0,null,null,year,content)+
                addInterwiki("ro:",225,2026,"",null,year,content)+
                addInterwiki("sr:",2003,2003,"",null,year,content)+
                addInterwiki("sl:",0,2010,""," pr. n. %C5%A1.",year,content)+
                addInterwiki("sv:",1490,2010,"",null,year,content)+
                addInterwiki("cy:",1950,2020,"",null,year,content)+
                //addInterwiki("walon:",1999,2004,"",null,year,content)+
                addInterwiki("hu:",1996,2003,"",null,year,content)+
                addInterwiki("vi:",2003,2003,"",null,year,content)+
                addInterwiki("it:",990,2004,"",null,year,content)+

                //remove (self-interwiki):
                addInterwiki("pl:",2,0,null,null,year,content)+

                //remove (interwiki doesn't work):
                addInterwiki("bg:",1,0,null,null,year,content)+
                addInterwiki("nds:",1,0,null,null,year,content);

                //remove (no calendar entries):
                /*addInterwiki("ms:",1,0,null,null,year,content)+
                addInterwiki("pt:",1,0,null,null,year,content)+
                addInterwiki("sh:",1,0,null,null,year,content)+
                addInterwiki("eu:",1,0,null,null,year,content)+
                addInterwiki("sq:",1,0,null,null,year,content)+
                addInterwiki("als:",1,0,null,null,year,content)+
                addInterwiki("bs:",1,0,null,null,year,content)+
                addInterwiki("co:",1,0,null,null,year,content)+
                addInterwiki("hr:",1,0,null,null,year,content)+
                addInterwiki("id:",1,0,null,null,year,content)+
                addInterwiki("ga:",1,0,null,null,year,content)+
                addInterwiki("lv:",1,0,null,null,year,content)+
                addInterwiki("nah:",1,0,null,null,year,content)+
                addInterwiki("na:",1,0,null,null,year,content)+
                addInterwiki("oc:",1,0,null,null,year,content)+
                addInterwiki("lr:",1,0,null,null,year,content)+
                addInterwiki("ta:",1,0,null,null,year,content);*/

        t=t+"<font size=\""+plus+"2\"><center>'''{{msg:calendar1}} "+
                yearName(year,false)+
                (year > 0 ? " {{msg:calendar1b}} "+romanNumber(year) : "")+
                "{{msg:calendar1c}}'''</center></font>\n\n";

        String rulers=sovereignTable(year);
        boolean rightCol=year>=startCal || !rulers.equals("");

        if (rightCol)
                t=t+"<table><tr><td valign=\"top\">\n";
        t=t+"<center>{{msg:calendar2}} ";
        int century=year>0 ? (year-1)/100+1 : year/100;
        for (int c=century-1;c<=century+1 && c<=21;c++) {
                if (c!=century-1)
                        t=t+" ~ ";
                if (c==century)
                        t=t+"'''";
                t=t+"[["+romanNumber(c>0 ? c : 1-c)+" wiek";
                if (c<=0)
                        t=t+" p.n.e.";
                t=t+"]]";
                if (c==century)
                        t=t+"'''";
        };

        t=t+"<br>\n";
        if (year>=-675) {
            t=t+"[["+yearName(year-100,false)+"|{{msg:centuryBack}}]]";
            if (year<=1910)
                t=t+" ~ ";
        }
        if (year<=1910)
                t=t+"[["+yearName(year+100,false)+"|{{msg:centuryForward}}]]";

        if (year>=1700) {
            t=t+"{{msg:calendar3}} ";
            int prevMin=1000000;
            for (int y=year-50;y<=year+50 && y<=2020;y++) {
                    int min,max;
                    if (y>0) {
                            min=y-(y%10);
                            max=min+9;
                    } else {
                            max=1-((1-y)-((1-y)%10));
                            min=max-9;
                    };
                    if (min==0)
                            min=1;
                    if (max==1)
                            max=0;
                    if (prevMin==min)
                        continue;
                    prevMin=min;

                    if (min<=year && year<=max)
                            t=t+"'''";
                    if (y<=0)
                            t=t+"[[Lata "+(1-min)+"-"+(1-max)+" p.n.e.|"+(1-min)+"-"+(1-max)+" p.n.e.]]";
                    else {
                            t=t+"[[Lata "+((min%100)<20
                                    ? ""+min+"-"+max
                                    : ""+(min%100)+"-te "+romanNumber(min/100+1)+" wieku");
                            t=t+"|"+min+"-"+max+"]]";
                    }
                    if (min<=year && year<=max)
                            t=t+"'''";
                    t=t+"\n";
            };
            t=t+"\n";
        }
        else
            t=t+"\n";
        t=t+"{{msg:calendar4}}";
        for (int y=year-10;y<=year+10 && y<=2019;y++)
                if (y==year)
                        t=t+" '''"+yearName(y,false)+"'''";
                else
                        t=t+" [["+yearName(y,false)+"]]";
        t=t+"\n";
        t=t+"{{msg:calendar4a}}{{msg:"+romanNumber(century>0 ? century : 1-century)+"_wiek";
        if (century<=0)
                t=t+"_pne";
        t=t+"}}\n";
        t=t+"</center>\n{{msg:calendar5}}\n";

        if (rulers.length()>0 && !rightCol)
                t=t+"<small>"+rulers+"</small>\n";

        //if (wojna1.hasElements()) 
        //	t=t+"\n==={{msg:I_wojna_"+s+"wiatowa}}===\n"+wojna1.getText();
        if (wojna2.hasElements()) 
                t=t+"\n==={{msg:II_wojna_"+s+"wiatowa}}===\n"+wojna2.getText();

        if (year>=2005) {
                t=t+"\n==={{msg:Spodziewane_wydarzenia_w_Polsce}}===\n"+polska.getText();
                t=t+"\n==={{msg:Spodziewane_wydarzenia_na_"+s+"wiecie}}===\n"+swiat.getText();
        }
        else if (/*wojna1.hasElements() || */wojna2.hasElements()) {
                t=t+"\n==={{msg:Pozosta"+l+"e_wydarzenia_w_Polsce}}===\n"+polska.getText();
                t=t+"\n==={{msg:Pozosta"+l+"e_wydarzenia_na_"+s+"wiecie}}===\n"+swiat.getText();
        } else if (year>=960) {
                t=t+"\n==={{msg:Wydarzenia_w_Polsce}}===\n"+polska.getText();
                t=t+"\n==={{msg:Wydarzenia_na_"+s+"wiecie}}===\n"+swiat.getText();
        }
        else {
                if (polska.hasElements())
                        throw new OlafBotException("Wydarzenia w Polsce przed jej powstaniem",false);
                t=t+"\n==={{msg:Wydarzenia}}===\n"+swiat.getText();
        }

        if (year<1994)
                t=t+"\n==={{msg:Urodzili_si"+e+"}}===\n"+narodziny.getText();
        else
                if (narodziny.hasElements())
                        throw new OlafBotException("Narodziny w roku "+String.valueOf(year),false);

        t=t+"\n==={{msg:Zmarli}}===\n"+zmarli.getText();

        if (!astronomia.hasElements()) {
                astronomia.addEvents(
                        "W tym roku [[S³oñce]] osi¹gnê³o lokalne maksimum aktywnoœci.",
                        "1770 Nul 0, 1781 Nul 0, 1791 Nul 0, 1807 Nul 0, 1820 Nul 0, 1835 Nul 0, "+
                        "1841 Nul 0, 1852 Nul 0, 1863 Nul 0, 1876 Nul 0, 1891 Nul 0, 1902 Nul 0, "+
                        "1913 Nul 0, 1924 Nul 0, 1935 Nul 0, 1946 Nul 0, 1957 Nul 0, 1968 Nul 0, 1979 Nul 0, 1990 Nul 0"
                );

                astronomia.addEvents(
                        "widoczna [[kometa Halley'a]].",
                        "-239 Nul 0, -163 Nul 0, -86 Nul 0, -11 Nul 0, 66 Nul 0, 141 Nul 0, 218 Nul 0, 295 Nul 0,"+
                        "374 Nul 0, 451 Nul 0, 530 Nul 0, 607 Nul 0, 684 Nul 0, 760 Nul 0, 837 Nul 0, 912 Nul 0,"+
                        "989 Nul 0, 1066 Nul 0, 1145 Nul 0, 1222 Nul 0, 1301 Nul 0, 1378 Nul 0, 1456 Nul 0,"+
                        "1531 Nul 0, 1607 Nul 0, 1682 Nul 0, 1759 Nul 0, 1835 Nul 0, 1910 Nul 0, 1986 Nul 0"
                );

                astronomia.addEvents(
                        "[[ca³kowite zaæmienie S³oñca]]",
                        "1900 May 28, 1918 Jun 8, 1936 Jun 19, 1954 Jun 30, 1972 Jul 10, 1990 Jul 22,"+
                        "1901 May 18, 1919 May 29, 1937 Jun 8, 1955 Jun 20, 1973 Jun 30, 1991 Jul 11,"+
                        "1956 Jun 8, 1974 Jun 20, 1992 Jun 30,"+
                        "1904 Sep 9, 1922 Sep 21, 1940 Oct 1, 1958 Oct 12, 1976 Oct 23, 1994 Nov 3,"+
                        "1905 Aug 30, 1923 Sep 10, 1941 Sep 21, 1959 Oct 2, 1977 Oct 12, 1995 Oct 24,"+
                        "1907 Jan 14, 1925 Jan 24, 1943 Feb 4, 1961 Feb 15, 1979 Feb 26, 1997 Mar 9,"+
                        "1908 Jan 3, 1926 Jan 14, 1944 Jan 25, 1962 Feb 5, 1980 Feb 16, 1998 Feb 26,"+
                        "1909 Jun 18, 1927 Jun 29, 1945 Jul 9, 1963 Jul 20, 1981 Jul 31, 1999 Aug 11,"+
                        "1911 Apr 28, 1929 May 9, 1947 May 20, 1965 May 30, 1983 Jun 11, 2001 Jun 21,"+
                        "1912 Oct 10, 1930 Oct 21, 1948 Nov 1, 1966 Nov 12, 1984 Nov 22, 2002 Dec 4,"+
                        "1914 Aug 21, 1932 Aug 31, 1950 Sep 12, 1968 Sep 22, 2003 Nov 23,"+
                        "2005 Apr 8,"+
                        "1916 Feb 3, 1934 Feb 14, 1952 Feb 25, 1970 Mar 7, 1988 Mar 18, 2006 Mar 29"
                );


                astronomia.addEvents(
                        "[[czêœciowe zaæmienie S³oñca]]",
                        "1979 Aug 23, 1982 Jan 25, 1982 Jun 21, 1982 Dec 15, 1985 May 19, 1985 Nov 12,"+
                        "1986 Apr 9, 1989 Mar 7, 1989 Aug 31, 1992 Dec 24, 1993 May 21, 1993 Nov 13,"+
                        "1996 Apr 17, 1996 Oct 12, 1997 Sep 2, 2000 Feb 5, 2000 Jul 1, 2000 Jul 31,"+
                        "2000 Dec 25, 2004 Apr 19, 2004 Oct 14, 2007 Mar 19, 2007 Sep 11, 2011 Jan 4,"+
                        "2011 Jun 1, 2011 Nov 25, 2014 Oct 23, 2015 Sep 13, 2018 Feb 15, 2018 Jul 13,"+
                        "2018 Aug 11, 2019 Jan 6"
                );

                astronomia.addEvents(
                        "[[obr¹czkowe zaæmienie S³oñca]]",
                        "1980 Aug 10, 1981 Feb 4, 1983 Dec 4, 1984 May 30, 1986 Oct 3, 1987 Mar 29, 1987 Sep 23,"+
                        "1988 Sep 11, 1990 Jan 26, 1991 Jan 15, 1992 Jan 4, 1994 May 10, 1995 Apr 29, 1998 Aug 22"+
                        "1999 Feb 16, 2001 Dec 14, 2002 Jun 10, 2003 May 31, 2005 Oct 3, 2006 Sep 22, 2008 Feb 7,"+
                        "2009 Jan 26, 2010 Jan 15, 2012 May 20, 2013 May 10, 2014 Apr 29, 2016 Sep 1, 2017 Feb 26,"+
                        "2019 Dec 26, 2020 Jun 21"
                );

                astronomia.addEvents(
                        "[[zaæmienie Ksiê¿yca]]",
                        "1979 Sep 6, 1981 Jul 17, 1982 Jan 9, 1982 Jul 6, 1982 Dec 30, 1983 Jun 25, 1985 May 4,"+
                        "1985 Oct 28, 1986 Apr 24, 1986 Oct 17, 1987 Oct 7, 1988 Mar 3, 1988 Aug 27, 1989 Feb 20,"+
                        "1989 Aug 17, 1990 Feb 9, 1990 Aug 6, 1991 Dec 21, 1992 Jun 15, 1992 Dec 9, 1993 Jun 4,"+
                        "1993 Nov 29, 1994 May 25, 1995 Apr 15, 1996 Apr 4, 1996 Sep 27, 1997 Mar 24, 1997 Sep 16,"+
                        "1999 Jul 28, 2000 Jan 21, 2000 Jul 16, 2001 Jan 9, 2001 Jul 5, 2003 May 16, 2003 Nov 9, "+
                        "2004 May 4, 2004 Oct 28, 2005 Oct 17, 2006 Mar 14, 2006 Sep 7, 2007 Mar 3, 2007 Aug 28, "+
                        "2008 Feb 21, 2008 Aug 16, 2009 Dec 31, 2010 Jun 26, 2010 Dec 21"
                );
        }

        if (astronomia.hasElements())
                t=t+"\n==={{msg:Zdarzenia_astronomiczne}}===\n"+astronomia.getText();

        if (year>=1901)
                t=t+"\n==={{msg:Nagrody_Nobla}}===\n"+nobel.getText();
        else 
                if (nobel.hasElements())
                        throw new OlafBotException("Nobel w roku "+String.valueOf(year),false);

        if (year>=1928 && year<=2004) {
                if (year>=1939 && year<=2002)
                        zobacz.add("* [[Historia informatyki/"+year+"]]");
                if (year>=1928 && year<=2004)
                        zobacz.add("* [[Oskary w roku "+year+"]]");
        }
        if (zobacz.hasElements()) 
                t=t+"\n==={{msg:Zobacz_te"+z+"}}===\n"+zobacz.getText();

        polska.save("Polska.txt");
        //wojna1.save("wojna1.txt");
        wojna2.save("wojna.txt");
        swiat.save("swiat.txt");
        narodziny.save("narodziny.txt");
        zmarli.save("zmarli.txt");
        astronomia.save("astronomia.txt");
        nobel.save("nobel.txt");
        zobacz.save("zobacz.txt");

        boolean przestepny=czyPrzestepny(year);
        if (year>=1583) {
                t=t+"\n==={{msg:"+S+"wi"+e+"ta_ruchome}}===\n";
                int w1=year%19;
                int w2=year/100;
                int w3=year%100;
                int w4=w2/4;
                int w5=w2%4;
                int w6=(w2+8)/25;
                int w7=(w2-w6+1)/3;
                int w8=19*w1+w2-w4-w7+15-30*((19*w1+w2-w4-w7+15)/30);
                int w9=w3/4;
                int w10=w3%4;
                int w11=(32+2*w5+2*w9-w8-w10)%7;
                int w12=(w1+11*w8+22*w11)/451;
                int w13=(w8+w11-7*w12+114)/31;
                int w14=(w8+w11-7*w12+114)%31;

                int wielkanoc=-34+31*w13+w14+1+(przestepny ? 1 : 0);
                t=t+"* [[T"+l+"usty czwartek]]: "+dzienSlownie(przestepny,year,wielkanoc-52,true)+"\n";
                t=t+"* [[Ostatki]]: "+dzienSlownie(przestepny,year,wielkanoc-47,true)+"\n";
                t=t+"* [[Popielec]]: "+dzienSlownie(przestepny,year,wielkanoc-46,true)+"\n";
                t=t+"* [[Niedziela Palmowa]]: "+dzienSlownie(przestepny,year,wielkanoc-7,true)+"\n";
                t=t+"* [[Wielki Czwartek]]: "+dzienSlownie(przestepny,year,wielkanoc-3,true)+"\n";
                t=t+"* [[Wielki Pi"+a+"tek]]: "+dzienSlownie(przestepny,year,wielkanoc-2,true)+"\n";
                t=t+"* [[Wielka Sobota]]: "+dzienSlownie(przestepny,year,wielkanoc-1,true)+"\n";
                t=t+"* [[Wielkanoc]]: "+dzienSlownie(przestepny,year,wielkanoc,true)+"\n";
                t=t+"* [[Poniedzia"+l+"ek Wielkanocny]]: "+dzienSlownie(przestepny,year,wielkanoc+1,true)+"\n";
                t=t+"* [[Wniebowst"+a+"pienie]]: "+dzienSlownie(przestepny,year,wielkanoc+39,true)+"\n";
                t=t+"* [[Zes"+l+"anie Ducha "+S+"wi"+e+"tego]]: "+dzienSlownie(przestepny,year,wielkanoc+49,true)+"\n";
                t=t+"* [[Bo"+z+"e Cia"+l+"o]]: "+dzienSlownie(przestepny,year,wielkanoc+60,true)+"\n";
        }

        t=t+"\n{{msg:calendar6}}\n";
        t=t+"<center>[["+yearName(year-1,false)+"|{{msg:prevYear}}]]";
        t=t+" ~ [["+yearName(year+1,false)+"|{{msg:nextYear}}]]";
        t=t+" ~ [["+yearName(year-100,false)+"|{{msg:centuryBack}}]]";
        if (year<=1910)
                t=t+" ~ [["+yearName(year+100,false)+"|{{msg:centuryForward}}]]";
        t=t+"</center>\n{{msg:calendar7}}\n";

        if (rightCol) {
                t=t+"</td><td width=\"220\" valign=\"top\">\n{{msg:calendar7a}}"+"<small>\n";
                if (!rulers.equals(""))
                    t=t+"{{msg:calendar7b}}"+rulers+"{{msg:calendar7c}}";
                else
                    t=t+"{{msg:calendarNoRulers}}";

                if (year>=startCal) {
                    if (year>=1582 && year<=1927) {
                        int diffJul=10+(year>=1700 ? 1 : 0)+(year>=1800 ? 1 : 0)+(year>=1900 ? 1 : 0);
                        t=t+"{{msg:julian1}} "+diffJul+" {{msg:julian2}}";
                        if (year>=1700 && year<=1712)
                            t=t+" {{msg:sweden1}} "+(diffJul-1)+" {{msg:sweden2}}";
                        t=t+"\n{{msg:calendar8j}}\n";
                    }
                    else t=t+"{{msg:calendar8}}\n";
                    
                    /*tydzien=1;
                    for (int m=1;m<=12;m++)
                            t=t+generujMiesiac(year,przestepny,m);*/
                    if (year==1582)
                        t=t+"{{msg:Kalendarz_na_rok_1582}}\n";
                    else {
                        int rok1=year-1;
                        int dzien=rok1*365+(rok1/4)+(rok1>=1582 ? -(rok1/100)+(rok1/400)-1 : 410);
                        int dzienTyg=(dzien+1)%7;
                        t=t+"{{msg:"+mediaKal[przestepny ? 1 : 0][dzienTyg]+"}}\n";
                    }
                }
                else t=t+"{{msg:calendarNoDaysOfWeek}}";
                t=t+"</small>{{msg:calendar9}}</td></tr></table>{{msg:calendar10}}\n";
        }
        else t=t+"{{msg:calendarNoRulers2}}";


        if (content.indexOf(t)>=0) {
            System.out.println("brak zmian");
            return false;
        }
        
        t=replaceAll(t,"&","%26");
        t=replaceAll(t,"+","%2B");
        
        //System.out.println(t);//todo debug
        System.out.println("zapisuje "+yname);
        String toPost=
                "wpSummary="+(content.equals("") 
                        ? "Nowy rok w kalendarium&" 
                        : (interwikiChanged+
                            "Przeformatowanie (grzebie"+n+//", mniejsze fonty"+
                            (year>=5 ? ", linki w kalendarium dni tygodnia" : "")+
                            (year<1700 ? ", usuni"+e+"cie dziesi"+e+"cioleci" : "")+
                            ")"+
                            /*(year>=startCal && year<1900 ? ", kalendarz" : "")+*/
                            //(year<=1944 ? "Autopoprawka bota" :
                            (year>=1014 ? ", dodani w"+l+"adcy Danii" : "")+
                            //(rulers.length()>0 ? "Zmiana tabelki w"+l+"adc"+o+"w" :  "")+
                            //"Test grzebienia"+
                            (calendarSorted ? ", sortowanie wydarze"+n : "")+
                            /*(astroEventAdded ? ", wydarzenia astronomiczne" : "")+*/
                          "&"))+
                //"+a+c+e+l+o+s+x+z+A+C+E+L+O+S+X+Z+"&"+
                "wpMinoredit=0&"+
                "wpWatchthis=1&"+
                "wpEdittime="+editTime+"&"+
                "wpSection=&"+
                "wpTextbox1="+t+
                "\n";

        //System.out.println("\n*************************************\nTo Post:\n"+toPost+"\n************\n");//TODO debug
        connect(//TODO:debug 
                "POST /w/wiki.phtml?title="+yname2+"&action=submit HTTP/1.1\n"+
                //"POST /w/wiki.phtml?title=Wikipedysta:Olafbot/test_"+yname2+"&action=submit HTTP/1.1\n"+
                "Content-Length: "+String.valueOf(toPost.length())+"\n",
                toPost
        );

        System.out.println("ok");
        return true;
    }

    static void writeLog(int year,Throwable ex) {
        try {
                PrintWriter fw=new PrintWriter(new FileWriter(dirPath+"/Log "+year+".txt",true));
                ex.printStackTrace();
                ex.printStackTrace(fw);
                fw.close();
        } catch (Throwable ex2) {
                ex2.printStackTrace();
                System.exit(0);
        }
    }

    static void processRange(int min,int max) throws Exception {
        for (int year=min;year<=max;year++) {
                boolean wait=true;
                while (true) {
                        try {
                                wait=process(year);
                                //System.out.println("<h1>"+yearName(year,false)+" / "+(year>0 ? romanNumber(year) : "")+"</h1>\n");
                                //System.out.println(sovereignTable(year));
                                break;
                        }
                        catch(OlafBotException ex) {
                                writeLog(year,ex);
                                if (ex.fatal)
                                        System.exit(0);
                                break;
                        }
                        catch(Throwable ex) {
                                if (ex instanceof SocketException)
                                        ex.printStackTrace();
                                else
                                        writeLog(year,ex);
                                Thread.sleep(30000);
                        }
                }
                /*if (wait)
                    Thread.sleep(60000);
                else*/
                    Thread.sleep(30000);
        }
    }

    static void addPage(String page,String text,String summary) throws Exception {
        /*System.out.println("reading "+page);
        connect(
            "GET /w/wiki.phtml?title="+page+"&action=edit HTTP/1.1\n"+
            "Content-type: application/x-www-form-urlencoded\n",
            ""
        );*/

        System.out.println("writing "+page);
        String content=
            "wpSummary="+summary+"&"+
            "wpMinoredit=0&"+
            "wpTextbox1="+text+
            "\n";
        connect(
            "POST /w/wiki.phtml?title="+page+"&action=submit HTTP/1.1\n"+
            "Content-Type: application/x-www-form-urlencoded\n"+
            "Content-Length: "+String.valueOf(content.length())+"\n",
            content
        );

        System.out.println("successful");
    }    

    static void generujMediaWikiKalendarzy(String page,int year,boolean przestepny) throws Exception {
        tydzien=1;
        String t="";
        for (int m=1;m<=12;m++)
                t=t+generujMiesiac(year,przestepny,m);
        addPage(page,t,"Kalendarium dni tygodnia");
    }
    
    static void generujMediaWikiKalendarzy() throws Exception {
        generujMediaWikiKalendarzy("MediaWiki:Kalendarz_od_poniedzia"+l+"ku",2001,false);
        generujMediaWikiKalendarzy("MediaWiki:Kalendarz_od_wtorku",2002,false);
        generujMediaWikiKalendarzy("MediaWiki:Kalendarz_od_"+s+"rody",2003,false);
        generujMediaWikiKalendarzy("MediaWiki:Kalendarz_od_czwartku",1998,false);
        generujMediaWikiKalendarzy("MediaWiki:Kalendarz_od_pi"+a+"tku",1999,false);
        generujMediaWikiKalendarzy("MediaWiki:Kalendarz_od_soboty",1994,false);
        generujMediaWikiKalendarzy("MediaWiki:Kalendarz_od_niedzieli",1995,false);
        generujMediaWikiKalendarzy("MediaWiki:Kalendarz_od_poniedzia"+l+"ku_przest"+e+"pny",1996,true);
        generujMediaWikiKalendarzy("MediaWiki:Kalendarz_od_wtorku_przest"+e+"pny",1980,true);
        generujMediaWikiKalendarzy("MediaWiki:Kalendarz_od_"+s+"rody_przest"+e+"pny",1992,true);
        generujMediaWikiKalendarzy("MediaWiki:Kalendarz_od_czwartku_przest"+e+"pny",2004,true);
        generujMediaWikiKalendarzy("MediaWiki:Kalendarz_od_pi"+a+"tku_przest"+e+"pny",1988,true);
        generujMediaWikiKalendarzy("MediaWiki:Kalendarz_od_soboty_przest"+e+"pny",2000,true);
        generujMediaWikiKalendarzy("MediaWiki:Kalendarz_od_niedzieli_przest"+e+"pny",1984,true);
        generujMediaWikiKalendarzy("MediaWiki:Kalendarz_na_rok_1582",1582,false);
    }

    static void generujMediaWikiStulecia(int nr) throws Exception {
        int nr2=nr>0 ? nr : 1-nr;
        String name=romanNumber(nr2)+" wiek";
        if (nr<=0)
            name+=" p.n.e.";
        
        //String text="<table bgcolor=\"#F8FFF8\"><caption>[["+name+"]]</caption>\n";
        //String text="<div align=\"right\">"+
            /*"<table border=\"1\" bgcolor=\"#F8FFF8\" style=\"margin-left:5px;white-space:nowrap\">\n"+ //id=\"toc\" align=\"right\" 
            "<tr><td>"*///"<small>\n"+
            /*"<center>[["+name+"]]<br>\n";
        int pos=0;
        for (int year=nr*100-99;year<=nr*100;year++) {            
            int y=year>0 ? year : 1-year;            
            //if (pos % 10==0)
            //    text+="<tr>";
            //text+="<td align=\"center\""+(pos<10 ? " width=\"10%%\"" : "")+"><small>";//+y/100;
            //else
              //  text+="<td>";
            String yname=yearName(year,false);
            String rname=""+y;//%100;
            if (yname!=rname)
                text+="[["+yname+"|"+rname+"]]";
            else
                text+="[["+yname+"]]";
            //text+="</small></td>";
            //if (pos % 10==9)
                //text+="</tr>\n";
            //    text+="<br>\n";
            //else
                text+=" ";
            pos++;
        }
        //text+="</table>\n";
        text+="</center></small></div>\n";//</td></tr></table>\n";*/
        
        String text="<table><tr>";
        //String t2="<tr>";
        int pos=0;
        for (int year=nr*100-99;year<=nr*100;year++) {            
            int y=year>0 ? year : 1-year;
            if (pos%10==0) {
                text+="<td><small>";
            }
            text+="[["+yearName(year,false)+"||]]";
            if (pos%10==9) {
                //text+="<td align=\"right\"><small>[["+yearName(year,false)+"]]</small></td>";
                text+="</small></td>";
            }
            pos++;
        }
        text+=/*"</tr>\n"+t2+*/"</tr></table>\n";
        
        String page="MediaWiki:"+replaceAll(replaceAll(name," ","_"),".","");
        System.out.println("writing "+page);
        String content=
            "wpSummary=Tabela stulecia&"+
            "wpMinoredit=0&"+
            "wpTextbox1="+text+
            "\n";
        connect(
            "POST /w/wiki.phtml?title="+page+"&action=submit HTTP/1.1\n"+
            "Content-Type: application/x-www-form-urlencoded\n"+
            "Content-Length: "+String.valueOf(content.length())+"\n",
            content
        );

        System.out.println("successful");
    }

    static void generujMediaWikiStuleci() throws Exception {
        for (int n=-7;n<=0;n++)
            generujMediaWikiStulecia(n);
    }
    
    public static void main(String[] args) throws Exception {
        wikipedia=InetAddress.getByName("pl.wikipedia.org");

        //login
        String toPost=
                "wpName=Olafbot&"+
                "wpLoginattempt=Zaloguj mnie&"+
                "wpPassword=(...)&"+ //haslo wyciete
                "wpRemember=1&"+
                "\n";

        while (true) 
            try {
                System.out.println("Logowanie...");
                connect(
                        "POST /w/wiki.phtml?title=Specjalna:Userlogin&returnto=Specjalna:Userlogout HTTP/1.1\n"+
                        "Content-Length: "+String.valueOf(toPost.length())+"\n",
                        toPost
                );
                break;
            } catch(Exception ex) {
                ex.printStackTrace();
            }
        loadSovereigns();
        //processRange(1173,1173);
        //processRange(-774,-754);
        //processRange(1000,1000);
        //processRange(1204,1261);
        //processRange(-473,-473);
        //processRange(1082,1203);
        //processRange(1262,1266);
        //processRange(1408,1408);
        //processRange(1606,1610);
        //processRange(1691,1691);
        //processRange(1968,1968);
        //processRange(2002,2002);
        //processRange(2006,2020);

        /*processRange(-560,-560); //brakuj?ce daty
        processRange(-556,-556);
        processRange(-501,-501);
        processRange(1316,1322);*/ //Dwóch królów Francji
        /*processRange(1542,1567); //Maria Stuart, Lady Jane Gray i Maria I Tudor
        processRange(1598,1605); //Borys Godunow
        processRange(1610,1613); //W³adys³aw IV Waza
        processRange(1815,1825); *///Aleksander I Paw³owicz
        //processRange(1730,1740); //Anna Iwanowna
        //processRange(1867,2020); //premierzy Kanady
        //processRange(493,553); //-zmiana glupiej nazwy

        /*processRange(-26,-26);
        processRange(-498,737);
        processRange(850,858);
        processRange(886,913);
        processRange(1228,1237);
        processRange(1799,1815);
        processRange(1958,1967);
        processRange(1984,1998);*/
        
        /*processRange(-534,-508);
        processRange(-334,-329);
        processRange(220,297);*/
        /*processRange(-296,-293); //Aleksander V
        processRange(-220,-167); //Filip V, Perseusz
        processRange(-68,-63);*/ //Filip II Seleukida
        //processRange(298,333);
        //processRange(334,419);
        //processRange(420,617);
        /*processRange(340,340);
        processRange(618,651);
        processRange(-355,-322); //Filip i Aleksander Macedo?scy
        processRange(770,781); //Konin
        processRange(1353,1359); *///Iwan II Pi?kny
        //processRange(1462,1480);
        //processRange(1481,1505); //Iwan III Srogi
        //processRange(1881,2020); //Aleksander III Aleksandrowicz, premierzy Japonii
        //processRange(1896,1896);
        //generujMediaWikiKalendarzy();
        //generujMediaWikiStuleci();
        //processRange(2004,2004); //próba nowych kalendarzy
        //processRange(1582,1582); //próba nowych kalendarzy
        //processRange(1,1); //próba nowych kalendarzy
        //processRange(0,0); //próba nowych kalendarzy
        processRange(-765,2020);
    }
};