UseVote V2.0a - Usenet News Group Voting Software
by rdippold@qualcomm.com

--------------------------------- LEGAL ----------------------------------

(c)1993 Ron Dippold All Rights Reserved

Distribute freely, use freely, please notify me of any nifty
improvements you make, and please distribute the entire package
including all source code and all docs.  And I'd appreciate it if you
let me know when you run a vote with it, and any comments you have.

Thanks to Dave Cornejo, you can get the latest versions of UseVote
from anonymous ftp at netcom.com under /pub/dnc. Thanks to Christophe
Wolfhugel, you can get the latest versions of UseVote from anonymous
ftp at grasp.insa-lyon.fr under /pub/unix/news/tools.

I think all the bugs are gone because I've tested it extensively on
old votes I've saved.  However, I'm not responsible for anything that
happens when you run this.  You assume all risk.  This paragraph is here
because lawyers can be are scum.


-------------------------- BRIEF DESCRIPTION -----------------------------

UseVote takes a lot of pain out of a painful process - running a
Usenet Newsgroup Vote.  Single item votes aren't all that bad, although
they're a lot of cut and paste, but multiple-item votes are a real bear.
This software, which was written for the comp.sys.ibm.pc.games
reorganization, and later improved for general release as others showed
interest, made the whole process easy and far less error-prone.  It doesn't
abolish all human interaction - you'll still have to do some work.  But
it makes it manageable.  This also works for any yes/no ballot, although
it wasn't designed for that.

The programs in UseVote are all written in very portable C - they compile
on our Sun, which has a very conservative C compiler, and should compile
on almost anything.  Let me know if it doesn't!


------------------------------ FILE LIST  -----------------------------

There should be a bundle of files:

        README          This file - the docs
        WHATSNEW        Version changes
        acktext.txt     Text for acknowledgement letters to voters
        blurb           Basically, a quick summary of UseVote
        convert.c       Convert old results files to new ones
        makefile        The make file for compiling the software
        sample.cfv      A sample CFV for single group ballot
        sample2.cfv     A sample CFV for multiple group ballot
        sampvote        Sample votes that work with included usevote.h
        usevote.h       All the info on your specific vote
        usevote2.h      Example of multiple-item version of usevote.h
        usevote.rul     Voting rules file
        uvack.c         Make voting acknowledgement lists
        uvballot.c      Generate ballot from your vote data
        uvbounce.c      Generate Mail Ack bounce lists
        uvcount.c       Give a total vote count for each group
        uvdup.c         Detect duplicate votes
        uvshell         Unix "sh" script to automate uvvote further!
        uvvote.c        Process votes

---------------------------- CONFIGURATION -------------------------------

The first thing you need to do is edit "usevote.h".  This should contain
everything that you need to configure UseVote for your specific vote.

If you're going to be running a multiple item vote, I suggest you copy
"usevote2.h" to "usevote.h", as it is set up closer to optimum for that.

The comments in the file should be fairly self-explanitory.  I'll just
comment a bit more on VOTEMARK... this will be used in the ballot, and
the text in it should not appear ANYWHERE ELSE in the cfv.  It's
traditional to issue a first CFV, then two more CFVs during the voting
period, because people miss it, procrastinate, whatever.  The '#' in
VOTEMARK will be replaced by the number of the CFV - in this way, you
can see by looking at the returned ballot just which of the CFVs this
vote was returned from.  Just make VOTEMARK some unlikely combo, like
"[RAP-00#]" for rec.arts.prose.  The first two zeros are just for show,
but don't they look impressive?

The next thing to change is "acktext.txt".  You'll need to update it
for your name and address.

The final item to check is "usevote.rul".  If your vote has any special
voting rules, such as that you can only vote on group x if you voted
on group y, or that if you vote yes on any part of a split you must vote
yes on the .misc group, then you will need to read "usevote.rul" and
add your own rules.



----------------------------- COMPILE----------------------------------

Now compile all six uv*.c files. You need to do this any time you change
usevote.h.   The programs are written in very portable C, so they should
compile on almost any machine (cross fingers).

On most Unix machines the compile command is:

       cc -o uvack uvack.c

Repeat for each file...  I've included a "makefile" command which has a
good chance of working under a Unix system.  Just "make".

If they don't compile, you need to mail me and tell me exactly what
happened.  What version, which file, what line, what error message, etc.
Note that some compilers don't like the "#include <stdlib.h>" lines, but
will still work if you remove those lines from all the .c files.

Now you can test your setup by running "uvvote -t"



-------------------------- GENERATE BALLOTS -------------------------------


* FOR SINGLE ITEM VOTES *

Look to the sample.cfv file to see how to do it.  Basically, you tell
the voters to include only one of the following in their return message:

        I vote YES on rec.foo.bar
        I vote NO on rec.foo.bar

This way, they can just uncomment the one they don't want, and as a
bonus, this will handle the situation where some people insist on
placing this information in the Subject: line.  All it needs is the
keyword "vote", the group name, and one of the yes/no/for/against
keywords.


* FOR MULTIPLE ITEM VOTES *

You need to write your CFV and put the ballot in it.  I have included,
in "sample2.cfv", some sample text to be included just before the ballot
itself.  Voters really need to be lead by the hand.

Now, generate the ballot:

        uvballot 1

This generates the ballot for the first cfv.  Later, as you do your 2nd
and 3rd CFVs, you can "uvballot 2" and "uvballot 3".

This will show you what it will look like, a good test of your
configuration.  If things look okay, redirect the output to a file:

        uvballot 1 > temp

Now you can edit this into your cfv.


WARNING: Try to avoid using a group name and any of the keywords
(for,against,yes,no,abstain) in a single line in any text after the
ballot.  There is currently no end of ballot marker, and if some idiot
returns the entire CFV instead of just the ballot, that line could be
treated as a vote.



--------------------------- SAVING BALLOTS --------------------------------

Returning ballots need to be saved to their own file - I use the "copy"
command in my mail reader.  Whenever I see the "comp.sys.ibm.pc.games
reorg" subject I have a macro do a "copy votes" and then delete the
message.  In your mail program it may be "file" instead of copy.

If you're going to be doing a bounce ack list (a list of all mail acks
that have bounced), save those to a separate file, such as "bounce".

Alternatively, you can set up a separate address for the votes.  I don't
like this method, because there are always some bozos who reply like
they're not supposed to and I can intercept them before I save the vote,
but it's up to you.



------------------------ PROCESSING VOTES ------------------------------

Big hint: If you're using Unix and have the "sh" shell available, you
might want to check out uvshell - it'll take care of all this crud!
Otherwise, read on.

So, you've got these votes in a file.  Move the file of votes to a
UNIQUE file name (don't copy over old votes).  Then do a uvvote on the
file:

        move votes votes2
        uvvote votes2 result2 trace

This will take the votes from file "votes2".  All the results will be
placed in the file "result2".  Do NOT give the name of any file that
contains anything useful for the results file, especially any other
voting results.  Anything in result2 will be overwritten.  The "trace"
file is optional.  If you specify it, a helpful dump of relevant info
from the process will be save to that file, and you can look at it for
any strangeness.

If you chose to generate vote acks (and you really should, unless you
have a darn good reason), it will create a series of "ack." files:
"ack.aaa", "ack.aab", "ack.aac", etc.  All the way up to "ack.zzz" if
necessary.  This lets you process 4095 votes in a single go.

It also generates a file called "domail" which will actually mail all
these suckers out.  You may need to change it to an executable type file
with a

        chmod 700 domail

before you can run it. Once you run domail, you can delete it and all
the "ack.???" files.  If you've defined VOTEACKCLEAN in "usevote.h" all
the acks will automatically be cleaned out.

I do this as a separate process so that if something comes up you can
fix it before any acks go out.

Note on "domail": on some systems, every piece of mail sent will
result in a separate mail process being created.  If you have a lot of
acks to send, that's a lot of mail, and can bog down those systems.
Check your "mail" help file, the name of the option is often named
"sendwait."   In most systems it's not a problem, though.

If you get any errors during the processing, usually becuase a ballot
can't be found in a message, the person whose message generated the
message will be sent a "couldn't process your ballot" message.  If you
do not want this to occur in a specific instance, you'll have to remove
them from "domail" before you run it.

Now you have two files - your mail votes file, and your results file.
Save them.  You don't really HAVE to save your votes file, but it's the
safest thing to do, and they don't take up too much space when they're
packed.   Regardless, once you have your results you need to CLEAR your
whatever mail votes file you're using (in case you're COPYing instead of
MOVEing) so the votes won't be recounted again.

I number everything sequentially like this:

   move votes4 done/votes4
   move results4 done/results4
   gzip done/votes4

Whatever you do, DON'T ACCIDENTALLY WRITE OVER YOUR OLD RESULTS FILES!
The results files are what all the other programs operate on - they
contain the name and address of each voter and how they voted.  If you
do accidentally delete or overwrite them, you can "uvvote" on the
mail vote files you saved.  You did save them, right?

So, to summarize:

        * save votes in a file from mail over a period of time
        * move the file to a unique votefile name
        * "uvvote <votefile> <resultfile> <tracefile>"
        * read the trace file
        * "domail"
        * save the votes and results files with unique names.

You can automate most of this if you want.


* ON HANDLING ERRORS IN THE PROCESSING *

With UseVote 1.1, things got a lot more automatic.  It should find most
possible errors and handle them correctly, including sending the correct
mail to the offender.  It will print a list of errors to the display
during processing (which can be redirected elsewhere for saving), and
will print the errors in the trace file as well.  If you really want,
you can run everything damn near on automatic and count on the error
mail to fix any problems.

I used to run UVVOTE on the voting file, then edit the voting file to
correct any correctable errors (such as the bozo deleting the start of
ballot tag), then run UVVOTE again.  It's not a lot of effort.  With
UseVote 2.0, there's the interactive option - see below.

Here are the possible errors UseVote handles:

  * No ballot found in message.
  * Did not vote on any item - this is meaningless, and probably an error.
  * Voted in contradictory ways on a single item.
  * Votes violated your "usevote.rul" rules.



--------------------- INTERACTIVE VOTE PROCESSING ----------------------

UseVote 2.0 added an interactive option to "uvvote".  Invoke it with an
initial "-i" parameter like:

  uvvote -i votes1 results1 trace

When you run it like this, it will still cough up an error message when
it encounters a bad ballot.  However, it will then ask you

  *** C)ontinue, E)xamine [E]?

If you choose "C"ontinue, uvvote will continue as normal and do all the
error processing for the ballot.  If you choose "E"xamine (or just hit
enter), however, you will be taken to the interactive mode.  The top
part of the screen shows the ballot.  The bottom part of the screen
shows what uvvote thinks the name, address, and votes are for this
ballot.

Your options are:

  Q)uit - discard any changes, exit interactive mode
  S)ave - save any changes, exit interactive mode

       In both cases, UseVote will reprocess the ballot and you'll get
       the C)ontinue / E)xamine choice if it's still bad.

  A)ddress - change the address of the voter.  This is useful for when a
     bozo includes an invalid return address or (gasp) UseVote can't parse
     some weird name/address syntax.
  N)ame - change the name of the voter.  Ditto.
  V)ote - change the votes of the voter.  This will show you the current
     vote for each group and will prompt you for Yes, No, or Abstain.
     Mostly useful for when they split the vote and the group name over
     multiple lines. Note: a '!' shown as the vote for a group means
     that there are multiple conflicting votes.

  D)own - move down a page into the vote.  The unshown commands "=" and
     "+" will move you down just one line.
  U)p - move up a page of the vote.  The unshown command "-" backs up
     just one line.


       The [xxx%] shown on the dashed line is an estimate of how much of
       the ballot is displayed.



--------------------------- COMBINED RESULTS ---------------------------

uvack, uvcount, and uvdup need all your results to work on.  So you have
to combine all your result files into one.  I do the following:

        cat result? > results.all

Since I have all my files stored in "result1", "result2", etc., this
concatenates them and saves them in "results.all".  You can also do the
same thing with an editor.

This "results.all" file is what I will use in all the following examples.


------------------------- ELIMINATING DUPLICATES ------------------------

It's going to happen in every vote that you get duplicate votes from the
same address.  Lots of people forget that they voted and vote again
(although doing a mail acknowledgement helps).  Some people change their
minds.  And some people try to cheat by voting multiple times.
Regardless, you have to delete duplicates.   The generally accepted
procedure is to delete the oldest duplicate, on the theory that the
newwer vote represents a change of heart on some issue.

You should run uvdup before any mass acks or vote acks.

The syntax of uvdup is simple:

        uvdup <old results> <new results> (<trace file>)

where <old results> is your current file of all voting results, and <new
results> will be a file that contains the new voting results with
duplicates removed.  THEY SHOULD NOT BE THE SAME FILE.  Whatever file
you give for <new results> will be utterly annihilated.

The same applies for <trace file>, if you choose to give one.  If so, then
a list of all deleted duplicates is saved to <trace file>.  This is helpful
for seeing what was axed.

First, uvdup will sort the votes by address to look for duplicate
addresses.  It has a unique ability to pare addresses down to
organization names when sorting.  For instance, in the following
address:

        rdippold@ren.qualcomm.com

"rdippold" is my username, "ren" is my machine, "qualcomm" is my
organization, and "com" is the organization type.  Well, it's entirely
possible that I move to another machine and vote as

        rdippold@stimpy.qualcomm.com

and a straight compare wouldn't think they were the same person!  So
uvdup cuts them both down to

        rdippold@qualcomm.com

for the purposes of comparing, and declares them equal.

Once it's sorted the votes, it will show you any that it thinks are
duplicates, like this:

        Old vote:
         A: rdippold@ren.qualcomm.com
         N: Ron "Asbestos" Dippold
         D: Thu, 12 Aug 1993 15:42:13 -0600
         C:
         V: NN--YNY

        New Vote:
         A: rdippold@stimpy.qualcomm.com
         N: Ron "Asbestos" Dippold
         D: Thu, 29 Jul 93 07:18:06 PDT
         C:
         V: NN--YYY

And will ask you if you really want to delete the older vote.  In this
case you can see that they are definitely a duplicate vote. Furthermore,
you can see that I've changed my mind on the vote for the 6th group.  So
say "Y" and the old vote will be eliminated.

The reason uvdup asks is because it can be over-paranoid.  It may
occasionally find a duplicate where none exists, though that usually
happens with names instead of addresses.

After you've gone through the addresses, uvdup will sort by name and
perform the same comparisons and questioning.  It will just skip any
votes where no name is known.

Finally, it will write the <new results> file, containing just the
non-duplicate votes.  At this point you'll probably want to save the
<old results> file and rename the <new results> file to whatever the
<old results> file was named.  Maybe not, but you want to do the final
voter list and vote count on the NEW file, not the old one!


NOTE:

Mail gateways can get very tricky.  UseVote will not detect that

        bvr1234%rfpc@wubba.foo.com    and
        bvr1234@bozo.edu

are actually the same voter.  The second address is his more direct
address, in the first he's used another gateway.  If he uses his name
with both accounts it will be picked up in that pass, but otherwise not.
Keep in mind that this can happen.


SPECIAL NOTE:

If you insert a "-y" as the first parameter, as in:

        uvdup -y oldresults newresults tracefile

Then uvdup will not ask you whether or not do delete possible votes
but will do it automatically.  This should NOT be your normal mode of
operation.  This is only provided for some very rare instances of crude
vote checking.




----------------------------- ACKNOWLEDGEMENTS -----------------------------

Acknowledgements have multiple purposes.

1) Generating a list of all voters (without how they voted) so that
everybody can check whether their vote was recorded or not, and whether
or not they voted.  It is expected that when you do your 2nd and 3rd CFV
that you WILL include one of these Mass Acks at the end of your CFV.
However, you may NOT list how anyone voted, or the vote will be
invalidated.  So be careful.

2) Generating a list of all voters and how they voted for your voting
results.  This is not optional.  It should go at the end of the results
posting.

Don't for get to run uvdup to get rid of duplicates, first!  You don't
want someone's vote in error to show up in the error list, even
though they've already mailed in a corrected version.

To generate a list of all voters without how they voted for a Mass Ack
(2nd or 3rd CFV), do a

        uvack results.all

and you'll get an alphabetically sorted list of all the voters and a
separate list of all votes that were rejected. If you like the looks,
then redirect it to a file so you can edit it into your CFV:

        uvack results.all > massack


To generate a list of all voters AND show how they voted for the final
voting post, do a

        uvack -v results.all

and you'll get an alphabetically sorted list.   There's a behavior that
needs to be explained here.  It's traditional in a single-item vote that
you list all the yes voters, then all the no voters, then all the
abstaining voters.  So if your vote only has one item, this is the way
it will be done.

On the other hand, this would be impossible (or huge) with more than one
item, so in this case everything is sorted as usual, but a list of the
votes is placed at the right, like this:

rdippold@qualcomm.com                         Ron "Asbestos" Dippold YYN-N-Y
jbeam@whiskey.daniels.com                                            NNN-YYY

for each voter.  The YN- at the end is that person's vote for each group
in order, one character per vote (Y = yes, N = no, - = abstain ).

Again, redirect this to a file to include in your CFV with

        uvack -v results.all > temp


The built in sort routines of uvack are optimized for low memory usage,
not for speed.  They shouldn't be a slouch, but if you find them too
agonizingly slow, the "-u" option is available, and will leave
everything unsorted.  You will need to sort the addresses with a program
of your own, or people will get on your case.

        uvack -v -u results.all > temp

And finally, for those who dislike the formatting of the names, you can
force a more standard name printing with the "-n" option.  If you do so,
acks will look like this:

rdippold@qualcomm.com (Ron "Asbestos" Dippold)                       YYN-N-Y
jbeam@whiskey.daniels.com                                            NNN-YYY



-------------------------- BOUNCE ACKNOWLEDGEMENTS ----------------------

With the advent of programs that can guarantee that a Mail Ack will go
out to voters when their vote has been tabulated, the use of Mass Acks
is seen by many as wasteful.  If you are going to be sending Mail Acks
for every vote, you may want to consider using a Bounce Ack instead of a
Mass Ack for additional CFVs.

It's fairly simple - just a list of addresses to which your Mail Acks
of VALID VOTES have bounced.  After you mail a Mail Ack off, if for some
reason the mail cannot be delivered, it should be returned to you with
an error message.  Save all these to a separate file, such as "bounce",
just as you did with votes.

Then when you want to generate a bounce list, just run

        uvbounce bounce

And you'll get a sorted list to include with your CFV.  You still need
to use "uvack" for the list of all voters and their votes for the
results posting, but not for the 2nd and 3rd CFVs.

As with uvack, the "-u" option will leave the addresses unsorted.

In case you were wondering, policy is that votes by accounts to whom
Mail Acks vote should be counted.  If a whole slew of acks to a domain
fails, it might be of interest to investigate, but that's about it.


NOTE:

uvbounce looks for the "Voter:" that "uvvote" puts in the Mail Acks.  If
you have changed the uvvote.c code you will need to change uvbounce.c as
well.


----------------------------- COUNTING VOTES ----------------------------

Finally!  You want to count some votes...  run uvcount on your votes:

        uvcount results.all

And you'll get something like this (numbers totally fabricated):


comp.sys.ibm.pc.games reorganization results - 923 votes

 Yes   No : 2/3? >100? : Pass? : Group
---- ---- : ---- ----- : ----- : -------------------------------------------
 123   34 :  Yes    No :    No : comp.sys.ibm.pc.games.misc
 456   92 :  Yes   Yes :   Yes : comp.sys.ibm.pc.games.announce
 789   12 :  Yes   Yes :   Yes : comp.sys.ibm.pc.games.action
 123  155 :   No    No :    No : comp.sys.ibm.pc.games.flight-sim
 532  338 :   No   Yes :    No : comp.sys.ibm.pc.games.strategic
 356  357 :   No    No :    No : comp.sys.ibm.pc.games.adventure
  12  127 :   No    No :    No : comp.sys.ibm.pc.games.rpg

  13 invalid votes

Yes and No are the number of yes and no votes, obviously.  Due to
abstentions, they will probably not add up to the number of votes shown
in the header for any given group.

2/3? indicates whether the group passed the 2/3 popularity test, which
states that 2/3 of the votes must be for the group.

>100? indicates whether the group passed the 100 vote interest test,
which states that there must be 100 more yes votes than no votes.

Pass? indicates if the group passed.  It is Yes if both 2/3? and >100?

The number of invalid votes is the number of votes that were recorded
as being in error.  See acktext.txt for possible errors.

Again, just redirect the output to a temporary file so you can paste it
into the final voting results:

        uvcount results.all > temp

Or, uvcount provides you an instantaneous way to see at any time how the
vote is doing (although as an ethical person you should not start
canvassing for votes if anything is doing badly - the vote will be
invalidated if it becomes public).


---------------------------- OVERALL -----------------------------------

That's it!  Here's a quick hint to help you in overall use:

* Before the CFV
        - Let me know you'll be using it and what version of the
          software you have - I may have a newer version
        - Update usevote.h for your configuration
        - Change acktext.txt for your configuration
        - Change usevote.rul if you need voting rules
        - Compile all the uv*.c files
        - Play around to see that you understand how it works

*  Initial CFV
        - Write CFV
        - Include sample ballot instructions from sample.cfv
        - Compile all the uv*.c files
        - Generate ballot text with "uvballot 1" and include your CFV

*  All during voting period
        - Save votes in separate file.  Do all the following every couple
          days.
        - Save any Mail Ack bounces to a separate file, "bounce".
        - MOVE (not just copy) the file to a unique name, say votes4 for
          the 4th time you've done this
        - Run uvvote on the votes: "uuvote -i votes4 result4 trace"
        - Save the votes file and the results file in a safe place. You
          may want to compress the votes file to save space.

* For the 2nd CFV
        - use "uvballot 2" to generate the 2nd ballot, replace the old
          one in your CFV

        For Bounce Acks:
        - run "uvbounce bounce > temp" to generate a Bounce Ack into the
          file "temp".  Add to the end of your CFV.

        For Mass Acks:
        - concatenate all your results file into one big one,
          results.all
        - use "uvdup results.all results.new" to eliminate duplicates
        - use "uvack results.new > temp" to generate a Mass Ack into the
          file "temp".  Add that to the end of your CFV.

* For the 3rd CFV ( if you have one! )
        - Just like the 2nd, but use "uvballot 3" instead.
        - And delete the old Ack before you include the new one!


* For the final results
        - Delete the old Mass Ack, voting instructions, and ballot from
          your CFV file
        - concatenate all your results file into one big one,
          results.all
        - run uvdup to detect any duplicates:
                "uvdup results.all results.new"
        - run uvcount to count the votes: "uvcount results.new > temp"
          and edit temp into the beginning of your CFV.
        - run uvack to generate a final vote ack with votes:
                "uvack -v results.new > temp"
          and edit the results into the end of your CFV.
        - I suggest you compress all the votes files and result files
          into one file, and back it up to tape or floppy, just in case
          anything ever comes up.


------------------------------- AND.... --------------------------------

                         That's it!
                         Hope this is helpful.

                            -- Ron Dippold
                               rdippold@qualcomm.com
