package votorola.s.line; // Copyright 2009-2011, Michael Allan. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Votorola Software"), to deal in the Votorola Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicence, and/or sell copies of the Votorola Software, and to permit persons to whom the Votorola Software is furnished to do so, subject to the following conditions: The preceding copyright notice and this permission notice shall be included in all copies or substantial portions of the Votorola Software. THE VOTOROLA SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE VOTOROLA SOFTWARE OR THE USE OR OTHER DEALINGS IN THE VOTOROLA SOFTWARE. import java.io.*; import java.net.*; import java.util.*; import java.util.regex.*; import javax.script.*; import votorola.a.*; import votorola.a.response.line.*; import votorola.g.*; import votorola.g.io.*; import votorola.g.lang.*; import votorola.g.logging.*; import votorola.g.net.*; import votorola.g.option.*; /** Main class of the executable vomir - a slapdash prototype of vote * mirroring that worked against White House 2 servers. It ran until early 2011, when * those servers were shut down. The raw * images have since been frozen in place and are still being counted, as you can see * in the results of poll G/p/edor. Red numeral 1's mark the votes that were mirrored. * * @see vomir */ public @Warning("dead code") final class VOMir { /** Executes from the command line. * * @param argv command line argument array */ public static @ThreadSafe void main( String[] argv ) { LoggerX.i(VOMir.class).info( "vomir is running with arguments " + Arrays.toString( argv )); final Map optionMap = CommandLine.compileBaseOptions(); final int aFirstNonOption = GetoptX.parse( "vomir", argv, optionMap ); if( aFirstNonOption < argv.length ) { System.err.println( GetoptX.createUnexpectedArgWarning( "vomir", argv[aFirstNonOption] )); System.err.println( GetoptX.createHelpPrompt( "vomir" )); System.exit( 1 ); } if( optionMap.get("help").hasOccured() ) { System.out.print ( "Usage: vomir\n" + "Pull remote votes for local mirroring.\n" ); System.exit( 0 ); } try { new VOMir().run(); } catch( RuntimeException x ) { throw x; } catch( Exception x ) { System.err.print( "voter: fatal error" + Votorola.unmessagedDetails(x) + ": " ); x.printStackTrace( System.err ); System.exit( 1 ); } } private VOMir() throws IOException, javax.script.ScriptException, java.sql.SQLException, URISyntaxException {} // ------------------------------------------------------------------------------------ /** The pattern of a precedence section marker in White House 2. The votes are * sectioned by precedence. */ private static @ThreadSafe final Pattern NAT_PRECEDENCE_PATTERN = Pattern.compile( ">Priority #(\\d+)<" ); /** The pattern of a timestamp in White House 2. */ private static @ThreadSafe final Pattern NAT_TIME_PATTERN = Pattern.compile( "\"(\\d\\d\\d\\d-\\d\\d-\\d\\dT\\d\\d:\\d\\d:\\d\\d.+)\"" ); // 2 0 0 9 - 1 2 - 2 5 T 1 0 : 2 8 : 2 7 Z /** The pattern of a user-page link in White House 2. */ private static @ThreadSafe final Pattern NAT_USER_LINK_PATTERN = Pattern.compile( "= 0; --c ) { if( !Character.isWhitespace( s.charAt( c ))) return s; } } } // /** Constructs a new stream reader that is configured to read documents that are // * un-namespaced. // */ // private static @ThreadSafe XMLStreamReader newXMLStreamReader( final Reader reader ) // throws XMLStreamException // { // return VoterInputTable.newXMLStreamReader( reader ); // } private final VoteServer.Run vsRun; { vsRun = new VoteServer( System.getProperty( "user.name" )).new Run( /*isSingleThreaded*/true ); vsRun.singleServiceLock().lock(); // no need to unlock, single access } /** Attempts to pull from a White House 2 vote-server. Creates a new source snap * directory in the process, and sets it as the current one. If the attempt fails, * the previous snap directory is left current. */ private void pullWH1_server( final String siteLoc, final String sourceMnemonic, final HashMap pollMap, final HashMap uidMap ) { final File sourceDirectory = new File( vsRun.voteServer().inDirectory(), "vomir" + File.separator + sourceMnemonic ); try { final File snapDirectory = OutputStore.mkdirsY4MDS( sourceDirectory, "snap" ); final String pollName = "G/p/edor"; final String priorityS = pollMap.get( pollName ); // To allow multiple priorities (proposals) per poll in future, prune // duplicate votes based on the voter's ranking of the priority (vote // precedence). if( priorityS == null ) LoggerX.i(getClass()).config( "no '" + sourceMnemonic + "' priority page mapped to poll: " + pollName ); final File file = new File( snapDirectory, pollName + ".xml" ); FileX.ensuredirs( file.getParentFile() ); boolean isFileCleanlyTerminated = false; final BufferedWriter o = new BufferedWriter( new OutputStreamWriter( new FileOutputStream( file ), "UTF-8" )); try { o.append( " \n" + "\n" ); pullWH2_poll( siteLoc, uidMap, priorityS, /*toPullEndorsers*/true, sourceDirectory, o ); pullWH2_poll( siteLoc, uidMap, priorityS, /*toPullEndorsers*/false, sourceDirectory, o ); o.append( " \n" ); isFileCleanlyTerminated = true; } finally { o.close(); if( !isFileCleanlyTerminated ) file.delete(); } final File snapLink = new File( sourceDirectory, "_snap_current" ); FileX.symlink( snapDirectory.getName(), snapLink.getPath() ); } catch( IOException x ) { LoggerX.i(getClass()).log( LoggerX.INFO, /*message*/"unable to complete pull from site " + siteLoc + ":" + Votorola.unmessagedDetails(x), x ); } } /** Pulls from a White House 2 poll (priority). */ private void pullWH2_poll( final String siteLoc, HashMap uidMap, final String priorityS, final boolean toPullEndorsers, final File sourceDirectory, final BufferedWriter o ) throws IOException { final String priorityLoc = siteLoc + "/priorities/" + priorityS; final String sourceMnemonic = sourceDirectory.getName(); final String candidateMailLoc = (toPullEndorsers? "x-":"o-") + sourceMnemonic + "-" + priorityS; final String docLoc = toPullEndorsers? priorityLoc: priorityLoc + "/opposers"; o.append( " \n" + " \n" + " \n" + " \n" ); final HttpURLConnection http; { final URL url = new URL( priorityLoc + "/" + (toPullEndorsers? "endorsers":"opposers") ); LoggerX.i(getClass()).fine( "requesting page " + url ); http = (HttpURLConnection)( url.openConnection() ); } URLConnectionX.connect( http ); try { final BufferedReader in = new BufferedReader( new InputStreamReader( http.getInputStream(), "UTF-8" )); try { // final XMLStreamReader r = newXMLStreamReader( /*systemId*/priorityLoc, in ); //// not well formed, so parse it by pattern matching: Matcher m = null; String precedence = "1"; // till proven otherwise for( ;; ) { String s = nextSolidLine( in ); if( s == null ) break; m = NAT_PRECEDENCE_PATTERN.matcher( s ); if( m.find() ) { precedence = m.group( 1 ); continue; } m = NAT_USER_LINK_PATTERN.matcher( s ); if( m.find() ) { s = nextSolidLine( in ); if( s == null ) break; final String userNumberS = m.group( 1 ); final MailOb voterMailOb = uidMap.get( userNumberS ); if( voterMailOb == null ) continue; // unregistered m = NAT_TIME_PATTERN.matcher( s ); if( m.find() ) { final String timeS = m.group( 1 ); o.append( " \n" + " \n" + " \n" + " \n" + " \n" + " " + precedence + "\n" + " \n" + " \n" ); } } } } finally{ in.close(); } } finally{ http.disconnect(); } } private void run() { pullWH1_server( "http://www.whitehouse2.org", "natW", pollMap_natW, uidMap_natW ); pullWH1_server( "http://www.parliament2.ca", "natP", pollMap_natP, uidMap_natP ); pullWH1_server( "http://au.nationbuilder.com", "natA", pollMap_natA, uidMap_natA ); } // ` N a t - A ```````````````````````````````````````````````````````````````````````` /** Map of priority number-strings on the Australia2 server, keyed by poll name. */ private final HashMap pollMap_natA; { final HashMap m = new HashMap(); pollMap_natA = m; m.put( "G/p/edor", "72" ); } /** Map of email addresses keyed by user number-strings on the Australia2 server. */ private final HashMap uidMap_natA; { final HashMap m = new HashMap(); uidMap_natA = m; m.put( "136", new MailOb ( "mike", "zelea.com" )); } // ` N a t - P ```````````````````````````````````````````````````````````````````````` /** Map of priority number-strings on the Parliament2 server, keyed by poll name. */ private final HashMap pollMap_natP; { final HashMap m = new HashMap(); pollMap_natP = m; m.put( "G/p/edor", "99" ); } /** Map of email addresses keyed by user number-strings on the Parliament2 server. */ private final HashMap uidMap_natP; { final HashMap m = new HashMap(); uidMap_natP = m; m.put( "1", new MailOb ( "trevor", "canadaka.net" )); m.put( "563", new MailOb ( "mike", "zelea.com" )); m.put( "564", new MailOb ( "ThomasvonderElbe", "gmx.de" )); } // ` N a t - W ```````````````````````````````````````````````````````````````````````` /** Map of priority number-strings on the Whitehouse2 server, keyed by poll name. */ private final HashMap pollMap_natW; { final HashMap m = new HashMap(); pollMap_natW = m; m.put( "G/p/edor", "2365" ); } /** Map of email addresses keyed by user number-strings on the Whitehouse2 server. */ private final HashMap uidMap_natW; { final HashMap m = new HashMap(); uidMap_natW = m; m.put( "1", new MailOb ( "jim", "gilliam.com" )); // though gilliam.com is listed as for sale, he uses this address in lists etc. m.put( "10333", new MailOb ( "mike", "zelea.com" )); m.put( "10346", new MailOb ( "ThomasvonderElbe", "gmx.de" )); } // ==================================================================================== private static final class MailOb { MailOb( final String loc, final String dom ) { this.loc = loc; this.dom = dom; } private final String dom; private final String loc; } }