/** * @author AySz88, Titoxd * @program Remote source reader for Flcelloguy's Tool * @version 4.20d; released April 13, 2006 * @see [[User:Flcelloguy/Tool]] * @docRoot http://en.wikipedia.org/wiki/User:Titoxd/Flcelloguy's_Tool * @copyright Permission is granted to distribute freely, provided attribution is granted. */importjava.io.BufferedInputStream;importjava.io.IOException;importjava.net.MalformedURLException;importjava.net.URL;importjava.util.Calendar;importjava.util.Date;importjava.util.HashMap;publicfinalclassGetContribs{//TODO: return fileReader/bufferedReader-like thingsprivatestaticlongkillbitCacheSaveTime=0;// 0 = the epoch, a few hours before 1970, so killbit expired by a safe margin :pprivatestaticbooleancachedKillValue=true;// initialize to true to avoid loophole from rolling back time to before 1970privatestaticfinalStringKILLURL="http://en.wikipedia.org/w/index.php?title=Wikipedia:WikiProject_edit_counters/Flcelloguy%27s_Tool/Configs&action=raw";privatestaticfinallongCACHETIME=1000*60*10;//10 minutes (arbitrary) in milliseconds// CACHETIME will bug out if > ~35 yrs (see comment next to killbitCacheSaveTime)privatestaticfinalintPARCELSIZE=4096;//arbitrary numberprivatestaticHashMap<URL,CachedPage>cache=newHashMap<URL,CachedPage>();publicstaticvoidmain(String[]args)// testing purposes only{try{//String content =getSource(newURL("http://en.wikipedia.org/"));getSource(newURL("http://en.wikipedia.org/"));// getSource(new URL(// "http://en.wikipedia.org/w/index.php?title=Special:Contributions&target=AySz88&offset=0&limit=5000"));// getSource(new URL(// "http://en.wikipedia.org/wiki/Special:Contributions/Essjay"));// getSource(new URL(// "http://en.wikipedia.org/wiki/Special:Contributions/Titoxd"));//System.out.println(content);}catch(MalformedURLExceptione){e.printStackTrace();}}// different ways to call getSource:publicstaticStringgetSource(URLlocation,booleanoverrideCache)throwsMalformedURLException{if(!killBit())returngetSourceDirect(location,overrideCache);else{System.out.println("Killbit active; Scraper is disabled. Try again later.");return"Killbit active; scraper is disabled. Try again later.";}}publicstaticStringgetSource(URLlocation)throwsMalformedURLException{returngetSource(location,false);}publicstaticStringgetSource(Stringlocation,booleanoverrideCache)throwsMalformedURLException{returngetSource(newURL(location),overrideCache);}publicstaticStringgetSource(Stringlocation)throwsMalformedURLException{returngetSource(newURL(location),false);}//Actual loading of page: privatestaticStringgetSourceDirect(URLlocation,booleanoverrideCache)throwsMalformedURLException//bypasses Killbit{//Simulating Internet disconnection or IO exception://if (!KILLURL.equals(location.toString())) throw new MalformedURLException();if(!overrideCache&&cache.containsKey(location)&&!cache.get(location).isExpired()){CachedPagecp=cache.get(location);System.out.println("Loading "+location.toString()+"\n\tfrom cache at time "+newDate(cache.get(location).time).toString()+"\n\t-ms until cache expired: "+((cp.expire+cp.time)-Calendar.getInstance().getTimeInMillis()));returncache.get(location).source;}try{System.out.println(" Loading -- ");StringBuildercontent=newStringBuilder();// faster: String concatination involves StringBuffers anyway// ...and StringBuilders are even faster than StringBuffersintbytesTotal=0;BufferedInputStreambuffer=newBufferedInputStream(location.openStream());intlengthRead=0;byte[]nextParcel;do{nextParcel=newbyte[PARCELSIZE];/* * Don't try to use buffer.available() instead of PARCELSIZE: * then there's no way to tell when end of stream is reached * without ignoring everything anyway and reading a byte. * * Also, if nextParcel is full (at PARCELSIZE), * content.append(nextParcel) will add an address * into the content (looks something like "[B&1dfc547") * so avoid using content.append(byte[]) directly. */lengthRead=buffer.read(nextParcel);bytesTotal+=lengthRead;//if (lengthRead == PARCELSIZE)//content.append(nextParcel); // would have been faster//elseif(lengthRead>0)content.append(newString(nextParcel).substring(0,lengthRead));// TODO: any better way to append a subset of a byte[]?System.out.println("Bytes loaded: "+bytesTotal);}while(lengthRead!=-1);bytesTotal++;// replace subtracted byte due to lengthRead = -1System.out.println(" -- DONE! Bytes read: "+bytesTotal+"; String length: "+content.length());Stringsource=content.toString();cache.put(location,newCachedPage(location,source,Calendar.getInstance().getTimeInMillis(),CACHETIME));returnsource;}catch(IOExceptione){e.printStackTrace();}returnnull;}// checks the killBitpublicstaticbooleankillBit(){Calendarnow=Calendar.getInstance();if(killbitCacheSaveTime+CACHETIME>now.getTimeInMillis())returncachedKillValue;Stringconfigs=null;try{configs=getSourceDirect(newURL(KILLURL),false);}catch(Exceptione){e.printStackTrace();cacheKillbit(true,now);returntrue;// if killbit cannot be read for any reason, killbit = true}String[]configArray=configs.split("\n");for(Stringsetting:configArray){System.out.println(setting);if(setting.equals("killBit = true;")){cacheKillbit(true,now);returntrue;}}cacheKillbit(false,now);returnfalse;}publicstaticvoidclearKillCache(){killbitCacheSaveTime=0;}publicstaticvoidrestartSession(){killbitCacheSaveTime=0;}privatestaticvoidcacheKillbit(booleanbool,Calendartime){cachedKillValue=bool;killbitCacheSaveTime=time.getTimeInMillis();}}
/** * @author AySz88 * @program Namespace Loader for Flcelloguy's Tool * @version 2.01b; released March 25, 2006 * @see [[User:Flcelloguy/Tool]] * @docRoot http://en.wikipedia.org/wiki/User:Titoxd/Flcelloguy's_Tool * @copyright Permission is granted to distribute freely, provided attribution is granted. */importjava.net.URL;importjava.util.AbstractMap;importjava.util.ArrayList;importjava.util.HashMap;importjava.util.Iterator;importjava.util.TreeMap;importjava.util.TreeSet;//For now, the name of the "main" namespace is interpreted as "Main"// This may be changed as necessary//The index of the main namespace must be 0publicclassNamespace{// data fields and functionsprivateStringenglishName,localName;privateintindexNo;// as shown in the Special:Export// pageprivateTreeSet<Contrib>[][][]countMatrix;privateTreeSet<Contrib>contribSet;publicNamespace(Stringeng,intind,Stringloc){englishName=eng;indexNo=ind;localName=loc;// Two methods to init countMatrix://Type-safe way:countMatrix=createArray(createArray(createArray(newTreeSet<Contrib>(),newTreeSet<Contrib>()),createArray(newTreeSet<Contrib>(),newTreeSet<Contrib>())),createArray(createArray(newTreeSet<Contrib>(),newTreeSet<Contrib>()),createArray(newTreeSet<Contrib>(),newTreeSet<Contrib>())));//Type-unsafe way:// countMatrix = new TreeSet[2][2][2];// // for (int i = 0; i < countMatrix.length; i++)// for (int j = 0; j < countMatrix[i].length; j++)// for (int k = 0; k < countMatrix[i][j].length; k++)// countMatrix[i][j][k] = new TreeSet<Contrib>();contribSet=newTreeSet<Contrib>();//sorts automagically}publicstatic<T>T[]createArray(T...items)//type-safe arrays with arrays of known fixed size{returnitems;}publicbooleanaddContrib(Contribcon){if(contribSet.contains(con))returnfalse;intminor=0,auto=1,manu=1;if(con.minorEdit)minor=1;if(con.autoSummary==null)auto=0;if(con.editSummary==null)manu=0;countMatrix[minor][auto][manu].add(con);contribSet.add(con);returntrue;}publicintgetCount(){returncontribSet.size();}publicintgetMinorCount(){return// minor = 1countMatrix[1][0][0].size()+countMatrix[1][0][1].size()+countMatrix[1][1][0].size()+countMatrix[1][1][1].size();}publicintgetMajorCount(){return// minor = 0countMatrix[0][0][0].size()+countMatrix[0][0][1].size()+countMatrix[0][1][0].size()+countMatrix[0][1][1].size();}publicintgetSummaryCount(){return// auto == 1 || manual == 1countMatrix[0][0][1].size()+countMatrix[0][1][0].size()+countMatrix[0][1][1].size()+countMatrix[1][0][1].size()+countMatrix[1][1][0].size()+countMatrix[1][1][1].size();}publicintgetManualSummaryCount(){return// manual == 1countMatrix[0][0][1].size()+countMatrix[0][1][1].size()+countMatrix[1][0][1].size()+countMatrix[1][1][1].size();}publicintgetAutoSummaryCount(){return// auto == 1countMatrix[0][1][0].size()+countMatrix[0][1][1].size()+countMatrix[1][1][0].size()+countMatrix[1][1][1].size();}publicdoublegetMinorProportion(){return((double)getMinorCount()/(double)getCount());}publicdoublegetSummaryProportion(){return((double)getSummaryCount()/(double)getCount());}publicdoublegetManualSummaryProportion(){return((double)getManualSummaryCount()/(double)getCount());}// public int newArticleCount() {return newArticleArray.size();}// public TreeSet newArticleSet() {return newArticleArray;}// public String[] newArticleArray() {return newArticleArray.toArray(new String[1]);}publicStringgetEnglishName(){returnenglishName;}publicStringgetLocalName(){returnlocalName;}publicintgetMediawikiIndex(){returnindexNo;}staticvoidaddContrib(HashMap<String,Namespace>map,Contribcon){Namespacens;if(con.namespace.equals(""))ns=map.get(MAINSPACENAME);elsens=map.get(con.namespace);ns.addContrib(con);}// static fields and functionspublicstaticfinalStringhead="http://",foot=".wikipedia.org/w/index.php?title=Special:Export//";publicstaticfinalintENDTAGLENGTH="</namespace>".length();// this'll evaluate at compile-time right?publicstaticfinalStringMAINSPACENAME="Main";publicstaticvoidmain(String[]args){/*TreeMap<Integer,Namespace> test =*/getDefaultNamespaceTreeMap();//getNamespaces("ko");getFullMap("ko");}// TODO: allow any two languages to convert to one another (currently one language must be English)publicstaticHashMap<String,Namespace>getFullMap(Stringlocal){TreeMap<Integer,Namespace>localMap=getNamespaceTreeMap(local);Namespace[]engNamespaces=getNamespaces("en");HashMap<String,Namespace>finishedMap=newHashMap<String,Namespace>();for(Namespacex:engNamespaces){Namespacens=localMap.remove(x.indexNo);if(ns==null)System.out.println("The "+local+" wiki does not have the equivalent of English Wikipedia namespace: "+x.localName);elsefinishedMap.put(ns.localName,newNamespace(x.localName,ns.indexNo,ns.localName));}if(!localMap.isEmpty()){System.out.println("The "+local+" wiki has namespaces not seen in the English Wikipedia");for(Iterator<Integer>iter=localMap.keySet().iterator();iter.hasNext();){Namespacens=iter.next();iter.remove();finishedMap.put(ns.localName,newNamespace("Translation Unknown - "+ns.indexNo,ns.indexNo,ns.localName));}}returnfinishedMap;}privatestaticNamespace[]getNamespaces(Stringlocal)//Does NOT populate the english names{try{String[]lineArray=GetContribs.getSource(newURL(head+local+foot)).split("\n");inti=arrayStepPast(lineArray,"<namespaces>");ArrayList<Namespace>nsArray=newArrayList<Namespace>();while(!lineArray[i].trim().equals("</namespaces>")){String[]parts=lineArray[i].trim().split("\"");intnumber=Integer.parseInt(parts[1]);// 2nd partStringname;if(number==0)name=MAINSPACENAME;elsename=parts[2].substring(1,parts[2].length()-ENDTAGLENGTH);nsArray.add(newNamespace("",number,name));System.out.println(number+" "+name);i++;}returnnsArray.toArray(newNamespace[1]);// the Namespace[1] is to convey the type of array to return}catch(Exceptione){e.printStackTrace();returngetDefaultNamespaceTreeMap().values().toArray(newNamespace[1]);}}/* Currently unused private static HashMap<String, Namespace> getNamespaceHashMap(String local) //HashMap uses local names of namespaces as the key //Does NOT populate the english names { try { String[] lineArray = GetContribs.getSource(new URL(head + local + foot)).split("\n"); int i = arrayStepPast(lineArray, "<namespaces>"); HashMap<String, Namespace> nsMap = new HashMap<String, Namespace>(); while (!lineArray[i].trim().equals("</namespaces>")) { String[] parts = lineArray[i].trim().split("\""); int number = Integer.parseInt(parts[1]); // 2nd part String name; if (number == 0) name = MAINSPACENAME; else name = parts[2].substring(1, parts[2].length()-ENDTAGLENGTH); nsMap.put(name, new Namespace("", number, name)); System.out.println(number + " " + name); i++; } return nsMap; } catch (Exception e) { e.printStackTrace(); return null; } }*/privatestaticTreeMap<Integer,Namespace>getNamespaceTreeMap(Stringlocal)//TreeMap uses index numbers as key//Does NOT populate the english names//Just in case we can eventually access data using the index numbers//Also used to match local names to english names{try{String[]lineArray=GetContribs.getSource(newURL(head+local+foot)).split("\n");inti=arrayStepPast(lineArray,"<namespaces>");TreeMap<Integer,Namespace>nsMap=newTreeMap<Integer,Namespace>();while(!lineArray[i].trim().equals("</namespaces>")){String[]parts=lineArray[i].trim().split("\"");intnumber=Integer.parseInt(parts[1]);// 2nd partStringname;if(number==0)name=MAINSPACENAME;elsename=parts[2].substring(1,parts[2].length()-ENDTAGLENGTH);nsMap.put(number,newNamespace("",number,name));System.out.println(number+" "+name);i++;}returnnsMap;}catch(Exceptione){e.printStackTrace();returngetDefaultNamespaceTreeMap();}}privatestaticTreeMap<Integer,Namespace>getDefaultNamespaceTreeMap()//TreeMap uses index numbers as key//Does NOT populate the english names//Just in case we can eventually access data using the index numbers//Also used to match local names to english names{System.out.println("Error encountered - using default namespaces");try{TreeMap<Integer,Namespace>nsMap=newTreeMap<Integer,Namespace>();Stringname="";String[][]inArray=Contrib.NAMESPACE_ARRAY;for(String[]x:inArray){intnumber=Integer.parseInt(x[1]);if(number==0)name=MAINSPACENAME;elsename=x[0];nsMap.put(number,newNamespace("",number,name));System.out.println(number+" "+name);}returnnsMap;}catch(Exceptione){e.printStackTrace();returnnull;}}publicstaticintsumAllCounts(AbstractMap<String,Namespace>map){intsum=0;for(Namespacex:map.values())sum+=x.getCount();returnsum;}publicstaticintsumAllMinorCounts(AbstractMap<String,Namespace>map){intsum=0;for(Namespacex:map.values())sum+=x.getMinorCount();returnsum;}publicstaticintsumAllMajorCounts(AbstractMap<String,Namespace>map){intsum=0;for(Namespacex:map.values())sum+=x.getMajorCount();returnsum;}publicstaticintsumAllSummaryCounts(AbstractMap<String,Namespace>map){intsum=0;for(Namespacex:map.values())sum+=x.getSummaryCount();returnsum;}publicstaticintsumAllManualSummaryCounts(AbstractMap<String,Namespace>map){intsum=0;for(Namespacex:map.values())sum+=x.getManualSummaryCount();returnsum;}publicstaticintsumAllAutoSummaryCounts(AbstractMap<String,Namespace>map){intsum=0;for(Namespacex:map.values())sum+=x.getAutoSummaryCount();returnsum;}privatestaticintarrayStepPast(String[]array,Stringo)// was originally going to allow to use with any Comparable object// currently only works with Strings due to use of trim(){inti=0;// keep the value of i after for loopfor(;i<array.length&&!array[i].trim().equals(o);i++);return++i;// step *past* first, then return}}
/** * @author Flcelloguy et al. * @program Flcelloguy's Tool (Stats.java) * @version 4.10a; released April 17, 2006 * @see [[User:Flcelloguy/Tool]] * @docRoot code from http://en.wikipedia.org/wiki/User:Flcelloguy/Tool * @copyright Permission is granted to distribute freely, provided attribution is granted. * Capabilities: Count edits, break down by namespace, count minor edits and calculate percentage * Please leave this block in. * Note: This new version does not require cut-and-pasting. * Just go to * http://en.wikipedia.org/w/index.php? * title=Special:Contributions&target={{USERNAME}}&offset=0&limit=5000 * where {{USERNAME}} is the name of the user you want to run a check on. */importjavax.swing.JOptionPane;importjava.awt.Component;importjava.io.BufferedReader;//import java.io.BufferedWriter;importjava.io.FileReader;//import java.io.FileWriter;importjava.io.IOException;importjava.net.URL;importjava.util.HashMap;importjava.util.Iterator;importjava.util.TreeMap;//import java.util.FileReader;publicclassStats{// Function added: provides human-readable output//private static HashMap<String, Namespace> cleanMap = Namespace.getFullMap("en");privatestaticHashMap<String,StatBundle>statMap=newHashMap<String,StatBundle>();privatestaticfinalStringCURRENTSTATUS="Current status: \n "+"Editcount \n Breakdown by namespace \n Minor edits usage \n Edit summary usage \n"+"Coming soon: \n "+"User friendly version \n First edit date";protectedStringBuilderconsole;privateComponentframe;publicStats(ComponentinFrame){console=newStringBuilder();frame=inFrame;}/*public void reset() { if (cleanMap == null) cleanMap = Namespace.getFullMap("en"); console = new StringBuilder(); nsMap = cleanMap; }*/publicstaticvoidmain(Stringargs[])throwsIOException{/** * the GUI is too complex to screw up clean, crisp code like this, so * I'm moving it to a separate class. --Titoxd */MainGUI.main(null);}publicvoidmainDownload(StringtargetUser)throwsIOException{if(targetUser==null)targetUser=JOptionPane.showInputDialog("Input file:",targetUser);// JOptionPane// .showMessageDialog(// frame,CURRENTSTATUS,// "Information", JOptionPane.INFORMATION_MESSAGE);URLnextPage=newURL("http://en.wikipedia.org/wiki/Special:Contributions/"+targetUser.replace(" ","_")+"?limit=5000");StatBundlesb;if(statMap.containsKey(targetUser)){sb=statMap.get(targetUser);sb.parseFromConnection(GetContribs.getSource(nextPage));}else{sb=newStatBundle(nextPage,Namespace.getFullMap("en"),frame);statMap.put(sb.username,sb);}buildConsole(sb);System.out.print(console);}publicvoidmainSingle(StringinFile$)throwsIOException{if(inFile$==null)inFile$=JOptionPane.showInputDialog("Input file:",inFile$);// JOptionPane// .showMessageDialog(// frame,CURRENTSTATUS,// "Information", JOptionPane.INFORMATION_MESSAGE);editcount(inFile$);// JOptionPane.showMessageDialog(null, "Number of edits: "// + editcount(inFile$), "Results",// JOptionPane.INFORMATION_MESSAGE);}publicvoidmainMulti(StringinFile$)throwsIOException{// String outFile$ = null;// String inFile$ = null;// // outFile$ = JOptionPane.showInputDialog(frame,// "Enter the filename of the output file:", outFile$,// JOptionPane.QUESTION_MESSAGE);// // FileWriter writer = new FileWriter(outFile$);// BufferedWriter out = new BufferedWriter(writer);// // out.write("<ul>", 0, "<ul>".length());// out.newLine();// if(inFile$==null||inFile$.equals(""))inFile$=JOptionPane.showInputDialog(frame,"Enter the filename of the first contributions file:",inFile$,JOptionPane.QUESTION_MESSAGE);FileReaderreader=newFileReader(inFile$);BufferedReaderin=newBufferedReader(reader);StringinString=in.readLine();StringtargetUser=null;do{if(inString.trim().startsWith(StatBundle.USERNAME_BAR_START))targetUser=PurgeContribs.getUsername(inString);inString=in.readLine();}while(targetUser==null&&inString!=null);if(targetUser==null)thrownewIOException("Malformed file, no username found");while(inFile$!=null){in=newBufferedReader(newFileReader(inFile$));StatBundlesb;if(statMap.containsKey(targetUser)){sb=statMap.get(targetUser);sb.parseFromSingleLocal(in);// should append}else{sb=newStatBundle(targetUser,Namespace.getFullMap("en"),frame);sb.parseFromSingleLocal(in);statMap.put(sb.username,sb);}in.close();buildConsole(sb);inFile$=JOptionPane.showInputDialog(frame,"Enter the filename of the next contributions file:",inFile$,JOptionPane.QUESTION_MESSAGE);}System.out.print(console);// out.write("</ul>", 0, "</ul>".length());// out.newLine();// out.close();// mainSingle(outFile$);}publicvoideditcount(StringinFile$)throwsIOException{// TODO: inFile --> URL --> edit count using other code// need getContribs to return fileReader/bufferedReader-like thingsSystem.out.println("Computing...");FileReaderreader=newFileReader(inFile$);BufferedReaderin=newBufferedReader(reader);// FileWriter writer = new FileWriter(outFile$); //for debugging// BufferedWriter out = new BufferedWriter(writer); //for debuggingStringinString=in.readLine();// Parse out username from fileStringtargetUser=null;do{if(inString.trim().startsWith(StatBundle.USERNAME_BAR_START))targetUser=PurgeContribs.getUsername(inString);inString=in.readLine();}while(targetUser==null&&inString!=null);if(targetUser==null)thrownewIOException("Malformed file, no username found");// Create or look up bundle and parseStatBundlesb;if(statMap.containsKey(targetUser)){sb=statMap.get(targetUser);sb.parseFromSingleLocal(in);}else{sb=newStatBundle(targetUser,Namespace.getFullMap("en"),frame);sb.parseFromSingleLocal(in);statMap.put(sb.username,sb);}in.close();buildConsole(sb);System.out.print(console);}publicvoidbuildConsole(StatBundlesb){console=newStringBuilder();HashMap<String,Namespace>nsMap=sb.getNamespaceMap();if(sb.badUsername){console.append("No such user.\n(Check spelling and capitalization)");return;}console.append("Statistics for: "+sb.username+"\n");if(sb.noEdits){console.append("Account exists, but no edits.\n(Check spelling and capitalization)");return;}console.append("- Total: "+sb.total+" -\n");// Convert arbitrary Name->Namespace HashMapping to// sorted index->Namespace TreeMappingTreeMap<Integer,Namespace>indexNamespaceMap=newTreeMap<Integer,Namespace>();for(Namespacens:nsMap.values()){indexNamespaceMap.put(ns.getMediawikiIndex(),ns);}Iterator<Map.Entry<Integer,Namespace>>iter2=indexNamespaceMap.entrySet().iterator();Map.Entry<Integer,Namespace>next;for(next=iter2.next();next.getKey()<0&&iter2.hasNext();next=iter2.next());// next has the value 0 or larger than 0 here, or hasNext() falsefor(;iter2.hasNext();next=iter2.next();){Namespacens=next.getValue();intcount=ns.getCount();if(count>0)console.append(ns.getEnglishName()+": "+count+"\n");}// still one more after it drops out{Namespacens=next.getValue();intcount=ns.getCount();if(count>0)console.append(ns.getEnglishName()+": "+count+"\n");}console.append("-------------------"+"\n"+"Total edits: "+sb.total+"\n");console.append("Minor edits: "+sb.minor+"\n");console.append("Edits with edit summary: "+sb.summary+"\n");console.append("Edits with manual edit summary: "+sb.manualSummary+"\n");console.append("Percent minor edits: "+((int)((float)(sb.minor*10000)/(float)(sb.total))/100.0)+"% *\n");console.append("Percent edit summary use: "+((int)((float)(sb.summary*10000)/(float)(sb.total))/100.0)+"% *\n");console.append("Percent manual edit summary use: "+((int)((float)(sb.manualSummary*10000)/(float)(sb.total))/100.0)+"% *\n");console.append("-------------------\n");console.append("* - percentages are rounded down to the nearest hundredth.\n");console.append("-------------------\n");//return total;}}
Sample on-screen output
Titoxd at 13:29, 13 April 2006 (UTC)
Statistics for: Titoxd
- Total: 16323 -
Main: 5677
Talk: 648
User: 1088
User talk: 4252
Wikipedia: 3399
Wikipedia talk: 795
Image: 40
Image talk: 2
MediaWiki: 35
MediaWiki talk: 10
Template: 216
Template talk: 59
Help: 7
Category: 18
Category talk: 1
Portal: 61
Portal talk: 15
-------------------
Total edits: 16323
Minor edits: 6352
Edits with edit summary: 16278
Edits with manual edit summary: 15916
Percent minor edits: 38.91% *
Percent edit summary use: 99.72% *
Percent manual edit summary use: 97.5% *
-------------------
* - percentages are rounded down to the nearest hundredth.
-------------------
QueryFrame
/** * @author Titoxd * @program Query Graphical User Interface for Flcelloguy's Tool * @version 3.58a; released April 17, 2006 * @see [[User:Flcelloguy/Tool]] * @docRoot http://en.wikipedia.org/wiki/User:Titoxd/Flcelloguy's_Tool * @copyright Permission is granted to distribute freely, provided attribution is granted. */importjavax.swing.BorderFactory;importjavax.swing.JButton;importjavax.swing.JComboBox;//import javax.swing.JFrame;importjavax.swing.Box;importjavax.swing.BoxLayout;importjavax.swing.JFileChooser;importjavax.swing.JInternalFrame;importjavax.swing.JLabel;importjavax.swing.JPanel;//import javax.swing.JScrollBar;importjavax.swing.JScrollPane;importjavax.swing.JSplitPane;importjavax.swing.JTabbedPane;importjavax.swing.JTextArea;importjavax.swing.JTextField;importjavax.swing.SpringLayout;importjava.awt.event.*;importjava.awt.*;importjava.io.IOException;/* Used by MainGUI.java. */publicclassQueryFrameextendsJInternalFrameimplementsActionListener{staticintopenFrameCount=0;staticfinalintxOffset=10,yOffset=10;staticfinalDimensionMINIMUM_TEXTPANEL_SIZE=newDimension(250,250);privateJLabeltopLabel=newJLabel("Online help"),label=newJLabel("Flcelloguy's Tool: Statistics for editcounters.");privateJTextFieldhelpURL=newJTextField("http://en.wikipedia.org/wiki/WP:WPEC/FT/H"),nameInput=newJTextField();privatestaticfinalStringNA_TEXT="No data available.";privateString[]phases={"Download","Single local (\u22645,000 edits)",// "\u2264" is "?" (less than or equal to sign)"Multiple local (\u22655,000 edits)"// "\u2265" is "?" (greater than or equal to sign)};privateJComboBoxmethodBox=newJComboBox(phases);privateJButtonbutton=newJButton("Proceed");privateCardLayoutlocationOption=newCardLayout();privateJPanelrow3=newJPanel(locationOption);privateJLabelfileChooseDesc=newJLabel();privateJTextFieldfilePathField=newJTextField();privateJFileChooserfc=newJFileChooser();privateJButtonbrowseButton=newJButton("Browse...");privateJTabbedPaneoutputTabs=newJTabbedPane();privateJPaneltextOutputPanel=newJPanel();privateJTextAreatextOutput=newJTextArea(20,20);privateJScrollPaneareaScrollPane=newJScrollPane(textOutput);privateJPanelgraphOutputPanel=newJPanel();privateJPaneltreeOutputPanel=newJPanel();privateStatsstatStorage=newStats(this.getRootPane());publicQueryFrame(){super("New Query "+(++openFrameCount),true,// resizabletrue,// closabletrue,// maximizabletrue);// iconifiable// ...Create the GUI and put it in the window...JPanelpanel=(JPanel)createComponents();panel.setBorder(BorderFactory.createEmptyBorder(20,// top30,// left10,// bottom30)// right);getContentPane().add(panel);// ...Then set the window size or call pack...pack();// Set the window's location.setLocation(xOffset*openFrameCount,yOffset*openFrameCount);}publicComponentcreateComponents(){GridBagConstraintsoptionC=newGridBagConstraints();GridBagConstraintsc=newGridBagConstraints();//label.setLabelFor(button);button.setMnemonic('i');button.addActionListener(this);methodBox.setSelectedIndex(0);methodBox.addActionListener(this);JPanelmainPanel=newJPanel(newBorderLayout());JPaneloptionPanel=newJPanel();optionPanel.setLayout(newGridBagLayout());optionC.gridx=0;optionC.gridy=0;optionC.weightx=1;optionC.weighty=.5;optionC.anchor=GridBagConstraints.WEST;optionC.fill=GridBagConstraints.HORIZONTAL;{JPanelrow1=newJPanel(newGridBagLayout());GridBagConstraintstempC=newGridBagConstraints();tempC.gridx=0;tempC.gridy=0;tempC.weightx=0;row1.add(topLabel,tempC);tempC.gridx++;tempC.weightx=1;tempC.fill=GridBagConstraints.BOTH;row1.add(helpURL,tempC);helpURL.setEditable(false);optionPanel.add(row1,optionC);}{/* JPanel row2 = new JPanel(new GridBagLayout()); GridBagConstraints tempC = new GridBagConstraints(); tempC.gridx = 0; tempC.gridy = 0; tempC.weightx = 0; row2.add(new JLabel("Statistics for:"), tempC); tempC.gridx++; tempC.weightx = 1; tempC.fill = GridBagConstraints.BOTH; row2.add(nameInput, tempC); tempC.fill = GridBagConstraints.NONE; tempC.weightx = 0; tempC.gridx++; JLabel via = new JLabel("via"); via.setBorder(BorderFactory.createEmptyBorder(0, 2, 0, 2)); row2.add(via, tempC); tempC.gridx++; row2.add(methodBox, tempC); tempC.gridx++; row2.add(button, tempC); *//* JPanel row2 = new JPanel(); row2.setLayout(new BoxLayout(row2,BoxLayout.X_AXIS)); row2.add(new JLabel("Statistics for:")); row2.add(nameInput); JLabel via = new JLabel("via"); via.setBorder(BorderFactory.createEmptyBorder(0, 2, 0, 2)); row2.add(via); row2.add(methodBox); row2.add(button); */SpringLayoutlayout=newSpringLayout();JPanelrow2=newJPanel(layout);JLabellineStart=newJLabel("Statistics for:");JLabelvia=newJLabel("via");nameInput.setMinimumSize(newDimension(methodBox.getPreferredSize().width+via.getPreferredSize().width,nameInput.getMinimumSize().height));nameInput.setPreferredSize(nameInput.getMinimumSize());methodBox.setEditable(false);row2.add(lineStart);row2.add(nameInput);row2.add(via);row2.add(methodBox);row2.add(button);row2.add(label);layout.putConstraint(SpringLayout.WEST,lineStart,0,SpringLayout.WEST,row2);layout.putConstraint(SpringLayout.WEST,nameInput,0,SpringLayout.EAST,lineStart);layout.putConstraint(SpringLayout.WEST,via,0,SpringLayout.EAST,lineStart);layout.putConstraint(SpringLayout.WEST,methodBox,2,SpringLayout.EAST,via);layout.putConstraint(SpringLayout.WEST,button,5,SpringLayout.EAST,nameInput);layout.putConstraint(SpringLayout.EAST,row2,2,SpringLayout.EAST,button);layout.putConstraint(SpringLayout.EAST,label,0,SpringLayout.EAST,row2);layout.putConstraint(SpringLayout.NORTH,lineStart,5,SpringLayout.NORTH,row2);layout.putConstraint(SpringLayout.NORTH,nameInput,2,SpringLayout.NORTH,row2);layout.putConstraint(SpringLayout.NORTH,via,7,SpringLayout.SOUTH,nameInput);layout.putConstraint(SpringLayout.NORTH,methodBox,2,SpringLayout.SOUTH,nameInput);layout.putConstraint(SpringLayout.NORTH,button,10,SpringLayout.NORTH,row2);layout.putConstraint(SpringLayout.NORTH,label,0,SpringLayout.SOUTH,methodBox);layout.putConstraint(SpringLayout.SOUTH,row2,0,SpringLayout.SOUTH,label);optionC.gridy++;//optionC.gridwidth = GridBagConstraints.REMAINDER;optionC.fill=GridBagConstraints.HORIZONTAL;optionPanel.add(row2,optionC);optionC.fill=GridBagConstraints.NONE;}/* { JPanel row2a = new JPanel(); row2a.setLayout(new BoxLayout(row2a, BoxLayout.X_AXIS)); row2a.add(Box.createHorizontalGlue(), c); row2a.add(label, c); optionC.gridx = 0; optionC.gridy++; optionC.fill = GridBagConstraints.HORIZONTAL; optionPanel.add(row2a, optionC); optionC.fill = GridBagConstraints.NONE; } */// row3 was already declaredJPanelfilePanel=newJPanel(newGridBagLayout());c.gridx=0;c.gridy=0;c.fill=GridBagConstraints.NONE;c.weightx=0;filePanel.add(fileChooseDesc);c.gridx++;c.weightx=1;c.fill=GridBagConstraints.BOTH;filePanel.add(filePathField);c.fill=GridBagConstraints.NONE;c.weightx=0;c.gridx++;browseButton.addActionListener(this);filePanel.add(browseButton);filePathField.setPreferredSize(newDimension(// FIXME: band-aid150,filePathField.getPreferredSize().height));row3.add(newJLabel("[en.wikipedia.com, es, Wikimedia sites in en, etc.] [New Set]"),phases[0]);//row3.add(filePanel, phases[1]);row3.add(filePanel,phases[2]);locationOption.show(row3,phases[0]);optionC.gridy++;optionC.fill=GridBagConstraints.BOTH;optionC.weightx=1;optionPanel.add(row3,optionC);optionC.fill=GridBagConstraints.NONE;{JPanelrow4=newJPanel(newGridBagLayout());row4.setBorder(BorderFactory.createTitledBorder("Filter by date (inclusive)"));c.gridx=0;c.gridy=0;c.gridheight=1;row4.add(newJLabel("From:"),c);c.gridy++;row4.add(newJLabel("To:"),c);c.gridy=0;c.gridx++;row4.add(newJLabel("[mm/dd/yyyy]"),c);c.gridy++;row4.add(newJLabel("[mm/dd/yyyy]"),c);c.gridy=0;c.gridx++;c.gridheight=2;c.weightx=1;row4.add(Box.createHorizontalGlue());c.weightx=0;c.gridx++;row4.add(newJLabel("or"),c);c.gridx++;c.weightx=1;row4.add(Box.createHorizontalGlue());c.weightx=0;c.gridx++;//c.gridy = 0;c.gridheight=1;row4.add(newJLabel("[n] [days/months/edits]"),c);c.gridy++;row4.add(newJLabel("[before/after] [mm/dd/yyyy]"),c);optionC.gridy++;optionPanel.add(row4,optionC);}{JPanelrow5=newJPanel();row5.setLayout(newBoxLayout(row5,BoxLayout.X_AXIS));JPanelgraphTypes=newJPanel(newGridBagLayout());graphTypes.setBorder(BorderFactory.createTitledBorder("Graph Type"));c.anchor=GridBagConstraints.WEST;c.gridx=0;c.gridy=0;graphTypes.add(newJLabel("O Stacked"),c);c.gridy++;graphTypes.add(newJLabel("O Unstacked"),c);c.gridy++;graphTypes.add(newJLabel("O Proportion"),c);c.gridy++;c.gridwidth=2;c.anchor=GridBagConstraints.CENTER;graphTypes.add(newJLabel("O Pie"),c);c.anchor=GridBagConstraints.WEST;c.gridwidth=1;c.gridx++;c.gridy=0;graphTypes.add(newJLabel("O Line"),c);c.gridy++;graphTypes.add(newJLabel("O Area"),c);c.gridy++;graphTypes.add(newJLabel("O Histogram"),c);row5.add(graphTypes);row5.add(Box.createHorizontalGlue());JPanelgraphAnalyses=newJPanel(newGridBagLayout());graphAnalyses.setBorder(BorderFactory.createTitledBorder("Time Axis"));c.anchor=GridBagConstraints.WEST;c.gridx=0;c.gridy=0;graphAnalyses.add(newJLabel("O Continuous"),c);c.gridy++;graphAnalyses.add(newJLabel("O Sum over week"),c);c.gridy++;graphAnalyses.add(newJLabel("O Sum over day"),c);c.gridy++;graphAnalyses.add(newJLabel("Resolution: [n] [hours/days/edits]"),c);c.gridx=1;row5.add(graphAnalyses);optionC.gridy++;optionPanel.add(row5,optionC);}{JPanelrow6=newJPanel(newGridBagLayout());row6.setBorder(BorderFactory.createTitledBorder("Filters and splits"));c.gridx=0;c.gridy=0;row6.add(newJLabel("O Major/minor split X Only Major X Only Minor"),c);c.gridy++;row6.add(newJLabel("O Namespaces [groups, exceptions, and colors]"),c);c.gridy++;row6.add(newJLabel("X Top [n] [% or articles] edited"),c);c.gridy++;row6.add(newJLabel("X Exclude articles with less than [n] edits"),c);c.gridy++;row6.add(newJLabel("O Edit summary split"),c);optionC.gridy++;optionPanel.add(row6,optionC);}/* { JPanel row7 = new JPanel(); row7.add(new JLabel("O Text")); // use tabs instead? row7.add(new JLabel("O Graph")); row7.add(new JLabel("O Tree")); optionC.gridy++; optionPanel.add(row7, optionC); } */textOutput.setFont(newFont("Ariel",Font.PLAIN,12));textOutput.setLineWrap(true);textOutput.setWrapStyleWord(true);textOutput.setText(NA_TEXT);//textOutput.setPreferredSize(new Dimension(// // textOutput.getPreferredSize().height));areaScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);areaScrollPane.setMinimumSize(MINIMUM_TEXTPANEL_SIZE);textOutputPanel.setLayout(newBorderLayout());textOutputPanel.add(areaScrollPane,BorderLayout.CENTER);outputTabs.addTab("Text",textOutputPanel);outputTabs.addTab("Graph",graphOutputPanel);outputTabs.addTab("Tree",treeOutputPanel);optionC.gridx=1;optionC.gridheight=GridBagConstraints.REMAINDER;optionC.gridy=0;//optionC.gridwidth = GridBagConstraints.REMAINDER;optionC.weightx=1;optionC.weighty=1;optionC.fill=GridBagConstraints.BOTH;//optionPanel.add(outputTabs, optionC);JSplitPanesplitPane=newJSplitPane(JSplitPane.HORIZONTAL_SPLIT,optionPanel,outputTabs);mainPanel.add(splitPane,BorderLayout.CENTER);returnmainPanel;}publicvoidactionPerformed(ActionEventevent){if(event.getSource()==methodBox){if(methodBox.getSelectedItem().equals(phases[0])){locationOption.show(row3,phases[0]);label.setText("Please put the username in the upper-left and the site below");}elseif(methodBox.getSelectedItem().equals(phases[1])){fileChooseDesc.setText("File path:");locationOption.show(row3,phases[2]);// FIXME: "phases[2]" is band-aid fixlabel.setText("Please indicate the file to load below");}elseif(methodBox.getSelectedItem().equals(phases[2])){fileChooseDesc.setText("First file path:");locationOption.show(row3,phases[2]);label.setText("Please indicate the first file to load below");}}elseif("Proceed".equals(event.getActionCommand())){try{setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));//if (statMap.containsKey(nameInput))//statStorage.reset();if(methodBox.getSelectedItem().equals(phases[0])){statStorage.mainDownload(nameInput.getText());}elseif(methodBox.getSelectedItem().equals(phases[1])){statStorage.mainSingle(filePathField.getText());}elseif(methodBox.getSelectedItem().equals(phases[2])){statStorage.mainMulti(filePathField.getText());}setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));textOutput.setText(statStorage.console.toString());textOutput.setCaretPosition(0);//The following didn't work://JScrollBar scroll = areaScrollPane.getVerticalScrollBar();//scroll.setValue(scroll.getMinimum());}catch(IOExceptione){// TODO Auto-generated catch blocke.printStackTrace();}}elseif(event.getSource()==browseButton){if(fc.showOpenDialog(this)==JFileChooser.APPROVE_OPTION){filePathField.setText(fc.getSelectedFile().toString());}}}}
/** * @author Titoxd * @program Contribution class for Flcelloguy's Tool * @version 4.05a; released April 17, 2006 * @see [[User:Flcelloguy/Tool]] * @docRoot http://en.wikipedia.org/wiki/User:Titoxd/Flcelloguy's_Tool * @copyright Permission is granted to distribute freely, provided attribution is granted. */importjava.util.Calendar;importjava.util.GregorianCalendar;importjava.util.HashMap;importjava.util.StringTokenizer;publicclassContribimplementsComparable<Contrib>{protectedStringtimeStamp;protectedStringpageName,namespace,shortName;protectedbooleanminorEdit;protectedStringeditSummary,autoSummary;// editSummary is only the manual partprotectedbooleantopEdit;protectedlongeditID;protectedCalendardate=newGregorianCalendar();protectedstaticfinalString[][]NAMESPACE_ARRAY=setArray();publicContrib(StringinStamp,StringinName,booleaninMin,StringinSummary,StringinAuto,booleaninTop,longinEditID){timeStamp=inStamp;pageName=inName;String[]nameArray=pageName.split(":",2);if(nameArray.length==1){namespace=Namespace.MAINSPACENAME;shortName=pageName;}else{namespace=nameArray[0];shortName=nameArray[1];}minorEdit=inMin;editSummary=inSummary;autoSummary=inAuto;topEdit=inTop;editID=inEditID;setDate(timeStamp);}privatestaticString[][]setArray(){String[]NAMESPACE_ARRAY={"Media","Special","","Talk","User","User talk","Wikipedia","Wikipedia talk","Image","Image talk","MediaWiki","MediaWiki talk","Template","Template talk","Help","Help talk","Category","Category talk","Portal","Portal talk"};int[]INDEX_ARRAY={-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,100,101};String[][]tempArray=newString[NAMESPACE_ARRAY.length][2];for(inti=0;i<NAMESPACE_ARRAY.length;i++){tempArray[i][0]=NAMESPACE_ARRAY[i];tempArray[i][1]=String.valueOf(INDEX_ARRAY[i]);}returntempArray;}/** * Constructor for the internal Calendar object */privatevoidsetDate(StringdateString){StringTokenizerstamp=newStringTokenizer(dateString," :,");inthour=Integer.parseInt(stamp.nextToken());intminute=Integer.parseInt(stamp.nextToken());StringdayOrMonth=stamp.nextToken();intday;Stringmonth;try{day=Integer.parseInt(dayOrMonth);month=stamp.nextToken();}catch(NumberFormatExceptione){month=dayOrMonth;day=Integer.parseInt(stamp.nextToken());}intyear=Integer.parseInt(stamp.nextToken());intmonthNo=0;{if(month.equalsIgnoreCase("January"))monthNo=Calendar.JANUARY;elseif(month.equalsIgnoreCase("February"))monthNo=Calendar.FEBRUARY;elseif(month.equalsIgnoreCase("March"))monthNo=Calendar.MARCH;elseif(month.equalsIgnoreCase("April"))monthNo=Calendar.APRIL;elseif(month.equalsIgnoreCase("May"))monthNo=Calendar.MAY;elseif(month.equalsIgnoreCase("June"))monthNo=Calendar.JUNE;elseif(month.equalsIgnoreCase("July"))monthNo=Calendar.JULY;elseif(month.equalsIgnoreCase("August"))monthNo=Calendar.AUGUST;elseif(month.equalsIgnoreCase("September"))monthNo=Calendar.SEPTEMBER;elseif(month.equalsIgnoreCase("October"))monthNo=Calendar.OCTOBER;elseif(month.equalsIgnoreCase("November"))monthNo=Calendar.NOVEMBER;elseif(month.equalsIgnoreCase("December"))monthNo=Calendar.DECEMBER;elseSystem.out.println("Month doesn't match anything!");}date.set(year,monthNo,day,hour,minute);date.set(Calendar.SECOND,0);//these fields shouldn't be used, so they're zeroed outdate.set(Calendar.MILLISECOND,0);}protectedvoidcheckCorrectNamespace(HashMap<String,Namespace>nsMap){if(!nsMap.containsKey(namespace)){System.out.println("Page: "+namespace+":"+shortName+" set to main namespace.");//for debug purposesnamespace=Namespace.MAINSPACENAME;//set to main namespace by default}}publicintcompareTo(Contribcon)//sorts by editID (same as sorting by date){if(editID>con.editID)return1;if(editID==con.editID)return0;return-1;}publicStringtoString(){StringreturnString="Time: "+timeStamp+"\r"+"Page: "+pageName+" (Namespace: "+namespace+"; Article: "+shortName+")\r"+"Minor edit: "+minorEdit+"\r"+"Edit Summary: "+editSummary+"\r"+"Most recent edit: "+topEdit;returnreturnString;}}
PurgeContribs.java
/** * @author Titoxd * @program HTML -> ContribFile converter for Flcelloguy's Tool * @version 4.10; released April 13, 2006 * @see [[User:Flcelloguy/Tool]] * @docRoot http://en.wikipedia.org/wiki/User:Titoxd/Flcelloguy's_Tool * @copyright Permission is granted to distribute freely, provided attribution is granted. */importjava.io.IOException;importjava.util.StringTokenizer;publicclassPurgeContribs{publicstaticvoidmain(String[]args){try{System.out.println(getNextDiffs("<p>(Newest | <a href=\"/w/index.php?title=Special:"+"Contributions&go=first&limit=5000&target="+"AySz88\">Oldest</a>) View (Newer 5000) (<a href=\""+"/w/index.php?title=Special:Contributions&offset="+"20060329014125&limit=5000&target=AySz88\">Older"+" 5000</a>) (<a href=\"/w/index.php?title=Special:"+"Contributions&limit=20&target=AySz88\">20</a>"+" | <a href=\"/w/index.php?title=Special:Contributions"+"&limit=50&target=AySz88\">50</a> | <a href=\""+"/w/index.php?title=Special:Contributions&limit=100"+"&target=AySz88\">100</a> | <a href=\"/w/index.php?"+"title=Special:Contributions&limit=250&target="+"AySz88\">250</a> | <a href=\"/w/index.php?title=Special"+":Contributions&limit=500&target=AySz88\">500</a>)"+".</p>"));}catch(Exceptione){System.out.println(e);}}/** * @param purgedLine * (input line in raw HTML, leading and trailing whitespace * removed) * @return Contrib class object: for analysis * @throws IOException */publicstaticContribParse(StringpurgedLine)throwsIOException{/**** Take out the <li> tags ****/StringmidString1;StringtimeStamp;StringeditSummary=null;StringautoSummary=null;booleanminorEdit=false;booleannewestEdit=false;//boolean sectionParsed = false;midString1=purgedLine.substring(4,purgedLine.length()-5);/**** Process the time stamp ****/StringTokenizertoken;token=newStringTokenizer(midString1.trim());{Stringtime=token.nextToken();Stringday=token.nextToken();Stringmonth=token.nextToken();Stringyear=token.nextToken();timeStamp=time+" "+day+" "+month+" "+year;}/**** Process the page name ****/Stringdummy=token.nextToken();// get rid of (<a/*String URL =*/token.nextToken();StringBuildertitleBuilder=newStringBuilder();//String pageName = URL.substring(25, URL.length() - 20);///**** Get rid of a few extra tokens ****/// start with the "title" piecewhile(true){dummy=token.nextToken();titleBuilder.append(dummy);titleBuilder.append(" ");if(dummy.lastIndexOf('<')!=-1){if(!dummy.substring(dummy.lastIndexOf('<'),dummy.lastIndexOf('<')+3).equals("</a>"))break;}}Stringtitle=titleBuilder.toString();StringpageName=title.substring(7,title.length()-11);/**** Do the same with the diff link ****/dummy=token.nextToken();// get rid of (<aStringdiffURL=token.nextToken();// this URL is not needed, so it is dummied outStringdiffIDString=diffURL.substring(diffURL.lastIndexOf("=")+1,diffURL.length()-1);// dittolongdiffID=Long.parseLong(diffIDString);while(true){dummy=token.nextToken();if(dummy.lastIndexOf('<')!=-1){if(dummy.substring(dummy.lastIndexOf('<'),dummy.lastIndexOf('<')+3).compareTo("</a>")!=0)break;}}StringdummyPageName;/**** Determine if edit is minor or not ****/dummy=token.nextToken();// get rid of (<spandummy=token.nextToken();// read the next token; it should be class="minor">m</span> if a minor editif(dummy.equals("class=\"minor\">m</span>")){minorEdit=true;dummyPageName=null;}else{minorEdit=false;dummyPageName=dummy;}if(dummyPageName==null)// if it was a minor edit, advance token// cursor to match non-minor edits{dummy=token.nextToken();// get rid of <adummyPageName=token.nextToken();}while(true){dummy=token.nextToken();if(dummy.lastIndexOf('<')!=-1){if(dummy.substring(dummy.lastIndexOf('<'),dummy.lastIndexOf('<')+3).compareTo("</a>")!=0)break;}}/**** flush the StringTokenizer ****/StringBuildertokenDump=newStringBuilder();Stringdump;if(token.hasMoreTokens())// {do{tokenDump.append(token.nextToken());tokenDump.append(' ');}while(token.hasMoreTokens());tokenDump.trimToSize();dump=tokenDump.toString();}else//not top edit, no edit summary{dump=null;}/**** Top edit? ****/if(dump!=null&&dump.contains("<strong> (top)</strong>")){newestEdit=true;dump=dump.substring(0,dump.indexOf("<strong> (top)</strong>"));//truncate to remove rollback links and other garbage dump=dump.trim();}elsenewestEdit=false;/**** Process edit summary ****/String[]summaries=ParseSummary(dump);autoSummary=summaries[0];editSummary=summaries[1];Contribcontrib=newContrib(timeStamp,pageName,minorEdit,editSummary,autoSummary,newestEdit,diffID);returncontrib;}/** * @param dump * @return String[2] array, String[0] is the auto summary, String[1] is the manual summary */privatestaticString[]ParseSummary(Stringdump){// TODO: clean this up/****Check that there is an edit summary to begin with ****/if(dump==null||dump.equals(""))returnnewString[]{null,null};String[]summaryArray=newString[2];if(dump.contains("<span class=\"autocomment\">"))//autocomment present{StringautoSummary=// everything within the <span class="autocomment">dump.substring(dump.indexOf("<span class=\"autocomment\">"),dump.indexOf("</span>")+7);summaryArray[0]=autoSummary.substring(autoSummary.indexOf("<a href="));summaryArray[1]=dump.substring(0,dump.indexOf(autoSummary))+dump.substring(dump.indexOf(autoSummary)+autoSummary.length()).trim();summaryArray[0]=summaryArray[0].substring(0,summaryArray[0].lastIndexOf("<"));summaryArray[0]=summaryArray[0].substring(summaryArray[0].lastIndexOf(">")+1);if(summaryArray[0].endsWith(" -")){summaryArray[0]=summaryArray[0].substring(0,summaryArray[0].length()-1);}}else{if(!dump.equals(""))summaryArray[1]=dump;}if(summaryArray[1]!=null&&summaryArray[1].length()!=0){summaryArray[1]=summaryArray[1].substring(summaryArray[1].indexOf(">")+1,summaryArray[1].lastIndexOf("<"));summaryArray[1]=summaryArray[1].trim();if(summaryArray[1].equals("()"))summaryArray[1]=null;}if(summaryArray[0].equals(""))summaryArray[0]=null;if(summaryArray[1].equals(""))summaryArray[1]=null;//so the edge cases don't trigger exceptionsif(summaryArray[0]!=null)summaryArray[0]=summaryArray[0].trim();returnsummaryArray;}/** * "Next 5000" contributions link parser * @param inLine (<code>String</code> object that contains the raw HTML for the Contributions line * @return String with the relative URL of the link if the link is available, null if it is not */publicstaticStringgetNextDiffs(StringinLine)throwsIOException{// if no such user, it would have been caught alreadyif(inLine.contains("<p>No changes were found matching these criteria."))thrownewIOException(StatBundle.NO_EDITS);StringTokenizermidToken=newStringTokenizer(inLine,"()");StringmidLine[]=newString[midToken.countTokens()];for(inti=0;i<midLine.length;i++){midLine[i]=midToken.nextToken();}StringTokenizertoken=newStringTokenizer(midLine[5],"<>");Stringtag=token.nextToken();Stringlink=null;booleandiffObtained=false;//FIXME: Internationalize this functiondo{if(tag.contains("href=\"/w/index.php?title=Special:Contributions&")){if(tag.contains("limit=5000")){if(token.nextToken().contains("Older"))link=tag.split("\"")[1];link=link.replace("&","&");diffObtained=true;}}if(token.hasMoreTokens()){tag=token.nextToken();}else{diffObtained=true;}}while(!diffObtained);returnlink;}publicstaticStringgetUsername(Stringline)throwsIOException{if(!line.contains("title=\"User:"))thrownewIOException(StatBundle.NO_SUCH_USER);returnline.substring(line.indexOf("title=\"User:")+12,line.indexOf("\">",line.indexOf("title=\"User:")));}}
/** * @author AySz88 * @program Remote source reader for Flcelloguy's Tool * @version 1.20a; released April 17, 2006 * @see [[User:Flcelloguy/Tool]] * @docRoot http://en.wikipedia.org/wiki/User:Titoxd/Flcelloguy's_Tool * @copyright Permission is granted to distribute freely, provided attribution is granted. */importjava.awt.Component;importjava.io.BufferedReader;importjava.io.IOException;importjava.net.URL;importjava.util.HashMap;importjavax.swing.JOptionPane;publicclassStatBundle{protectedstaticfinalStringNAVIGATION_BAR_START="<input type=\"submit\" value=",CONTRIB_LIST_START="<ul>",CONTRIB_LIST_END="</ul>",USERNAME_BAR_START="<div id=\"contentSub\">For";//TODO:InternationalizeprotectedstaticfinalStringNO_SUCH_USER="No such user.",NO_EDITS="No edits from this user.";privateHashMap<String,Namespace>nsMap;protectedinttotal,minor,summary,manualSummary;protectedStringusername;privatebooleanallContribsParsed;privateComponentframe;protectedbooleanbadUsername,noEdits;publicStatBundle(Stringuser,HashMap<String,Namespace>ns,ComponentinFrame){username=user;allContribsParsed=false;nsMap=ns;frame=inFrame;badUsername=false;noEdits=false;}publicStatBundle(URLsomeURL,HashMap<String,Namespace>ns,ComponentinFrame)throwsIOException{allContribsParsed=false;nsMap=ns;frame=inFrame;badUsername=false;noEdits=false;parseFromConnection(GetContribs.getSource(someURL));}publicvoidparseFromConnection(Stringsource)throwsIOException{try{if(allContribsParsed){allContribsParsed=false;URLnextPage=appendFromSource(source);while(nextPage!=null){URLnewURL=nextPage;nextPage=null;intchoice=JOptionPane.showConfirmDialog(frame,"5000 edits loaded. Continue?","Confirmation",JOptionPane.YES_NO_OPTION);if(choice==JOptionPane.YES_OPTION)nextPage=appendFromSource(GetContribs.getSource(newURL));}}else{URLnextPage=parseOverwriteFromSource(source);while(nextPage!=null){URLnewURL=nextPage;nextPage=null;intchoice=JOptionPane.showConfirmDialog(frame,"5000 edits loaded. Continue?","Confirmation",JOptionPane.YES_NO_OPTION);if(choice==JOptionPane.YES_OPTION)nextPage=parseOverwriteFromSource(GetContribs.getSource(newURL));}}}catch(IOExceptione){if(e.getMessage().equals(NO_SUCH_USER)){badUsername=true;username=NO_SUCH_USER;}elseif(e.getMessage().equals(NO_EDITS)){noEdits=true;}elsethrowe;}}privateURLparseOverwriteFromSource(Stringsource)throwsIOException{StringlinkString=null;System.out.println("Computing...");String[]array=source.split("\n");ContriboutContrib;inti=1;for(;i<array.length&&!array[i].trim().equals(CONTRIB_LIST_START);i++){if(array[i].trim().startsWith(USERNAME_BAR_START))username=PurgeContribs.getUsername(array[i]);if(array[i].startsWith(NAVIGATION_BAR_START))linkString=PurgeContribs.getNextDiffs(array[++i]);}// if (!foundURL) // bad username or url or other error// {// System.out.println("StatsBundle: Could not find navigation links, assume bad username");// allContribsParsed = true;// return null;// }i++;// increment pastwhile(i<array.length&&!array[i].trim().equals(CONTRIB_LIST_END)){// then start reading and recordingoutContrib=PurgeContribs.Parse(array[i].trim());addContrib(outContrib);i++;}updateTotals();if(linkString==null)// finished parsing{allContribsParsed=true;returnnull;}returnnewURL("http://en.wikipedia.org"+linkString);}privateURLappendFromSource(Stringsource)throwsIOException{StringlinkString=null;System.out.println("Computing...");String[]array=source.split("\n");ContriboutContrib;inti=1;for(;i<array.length&&!array[i].trim().equals(CONTRIB_LIST_START);i++){if(array[i].trim().startsWith(USERNAME_BAR_START))username=PurgeContribs.getUsername(array[i]);if(array[i].startsWith(NAVIGATION_BAR_START))linkString=PurgeContribs.getNextDiffs(array[++i]);}if(linkString!=null)linkString="http://en.wikipedia.org"+linkString;// TODO:Internationalize//complete URL herei++;// increment pastwhile(i<array.length&&!array[i].trim().equals(CONTRIB_LIST_END)){// then start reading and recordingoutContrib=PurgeContribs.Parse(array[i].trim());booleannewContrib=addContrib(outContrib);if(!newContrib){updateTotals();allContribsParsed=true;returnnull;// all new contribs parsed, exit}i++;}updateTotals();URLreturnURL;if(linkString!=null){returnURL=newURL(linkString);}else{allContribsParsed=true;returnURL=null;}returnreturnURL;}publicvoidparseFromSingleLocal(BufferedReaderin)throwsIOException{StringinString=in.readLine();ContriboutContrib;while(!inString.trim().equals(CONTRIB_LIST_START)&&inString!=null)inString=in.readLine();inString=in.readLine();// increment pastwhile(inString!=null&&!inString.trim().equals(CONTRIB_LIST_END)){// then start reading and recordingoutContrib=PurgeContribs.Parse(inString.trim());addContrib(outContrib);inString=in.readLine();}updateTotals();}publicbooleanaddContrib(Contribcon){con.checkCorrectNamespace(nsMap);returnnsMap.get(con.namespace).addContrib(con);}privatevoidupdateTotals(){total=Namespace.sumAllCounts(nsMap);minor=Namespace.sumAllMinorCounts(nsMap);summary=Namespace.sumAllSummaryCounts(nsMap);manualSummary=Namespace.sumAllManualSummaryCounts(nsMap);}publicHashMap<String,Namespace>getNamespaceMap(){returnnsMap;}}
CachedPage.java
/** * @author AySz88 * @program Remote source reader for Flcelloguy's Tool * @version 1.00b; released February 25, 2006 * @see [[User:Flcelloguy/Tool]] * @docRoot http://en.wikipedia.org/wiki/User:Titoxd/Flcelloguy's_Tool * @copyright Permission is granted to distribute freely, provided attribution is granted. */importjava.net.URL;publicclassCachedPage{protectedURLurl;protectedStringsource;protectedlongtime,expire;publicCachedPage(URLu,Strings,longt){url=u;source=s;time=t;}publicCachedPage(URLu,Strings,longt,longe){url=u;source=s;time=t;expire=e;}/*public CachedPage(URL u, String s) { url = u; source = s; time = System.currentTimeMillis(); }*/publicbooleanisExpired(longnow){returnnow>expire+time;}publicbooleanisExpired(){returnSystem.currentTimeMillis()>expire+time;}}