The code
Once you download the .Zip file you must unzip it. For example if you unzipped to the directory c:\NameDrawing
then you would get a folder and file tree that looks like the following:
The root folder only contains one file NameDrawing.sln which is the VS2010 solution file. In that folder, there is a subfolder c:\NameDrawing\NameDrawing
that contains all the project files and project subfolders. One that is of most interest is the folder c:\NameDrawing\NameDrawing\DataFiles_2011.
If you decide to use this project then all the .html files in that folder plus the single .jpg file and the file named Crypt.js
will become the end result of the project. In particular the file named index.html is the file that the participants in the name drawing event will bring up in their web browsers.
Short version
- The project consists of source code for a VS2010 C# Forms Application that writes a client side JavaScript file that contains a function that is executed from the file index.html.
The application uses an XML data file for its input. The sample files: index.html, drawing_names.xml, and Wish-Lists.html are included.
- To use this project in the 'real-world', you would need to:
- compile the C# VS2010 project (producing the executable)
- edit the drawing_names.XML data file (introduce real user names and pass phrases)
- edit the index.html file (introduce real user names)
- edit the 'extra' wishlists.html (introduce real user names)
- run the application (producing the JavaScript)
- publish all the files to some website somewhere
To see a 'working-version' of the result for the 2008 Christmas season, visit: http://papa.poemy.net/2008_Drawing_Names/index.html.
Now that I write all that down it seems like a lot, but given this application is to be used at Christmas time, you have a few months to get it together if you want to use
it for your group of family or friends for the 2012 Christmas season.
Note: I am not an accomplished GUI designer or super-duper OO designer. My real-world talents lie in middleware, communications, and OS internals design and implementation.
The kind of stuff in this project, for me, is pure hobby/fun stuff. This means that 100% of the technology in this project is pure 'hacking', I do not do any of this sort
of stuff for a living. So ... this means, whatever you think about this project --- you are probably correct (good, bad, ugly, other).
Also, I think comments/changes/etc... would be grand and are appreciated and accepted. I think there is also the ability to collaborate when you work
on CodeProject stuff so the absolute best result would be that the app would be interesting enough to stimulate that sort of behavior.
I know I've got a lot of ideas about messing with it. I will post changes and extensions here and perhaps in a new article if they get big enough.
Introduction (Motivation)
As a child in a large family we always picked a single name out of a hat rather than purchase a present for each sibling. Then as adults we continued this tradition and further included our spouses in the event. As time went by, the name drawing event became a Thanksgiving and, on some occasions, a Summer Beach Trip event. There were lots of discussions about not choosing your own name or your spouse’s name and lots of put-backs and redraws, etc. Of course I could not resist the temptation, and decided to write an application that would simulate a random hat draw, keep a history of past draws, and enforce rules of not drawing your own name or your spouse’s name. And as time went on, even 'cheats' could be added when someone just had to draw someone else's name that year. Additionally, the concept of a "Secret Santa" came up where one person gets a second name and gives that person an anonymous present.
Background
The original CodeProject version was done in 2009. Since that time there have been enhancement requests and a bug report so this version in 2011
represents the modifications to implement the changes and fix the bug.
Complexity level
For me something is complex if I've never done it before. If I can get an example that is written in syntax that I understand then I can usually
'noodle-it-out'. I'll look at it, knowing all the pieces of the syntax and knowing what it does and usually say, "Oh yes, I get it."
Or perhaps "Ah ha!" so that's how it is done. If you read through this and get to any point where you think,
"What is he doing here?" then make a comment to this article and I'll try to write a bit about that either as a response
to the comment or even add a section to the entire article. You do not have to be specific, you can ask global questions, and certainly specific questions too.
Using the application
Here is what the application does: It writes a JavaScript named "Crypt.js" that can be referenced by a web page.
A sample of the web page "index.html" and its background .jpg file as well as some sample "Wish List Pages" are included as part of the project.
To use this project you would edit the sample index.html page and sample "Wish List Pages" as needed.
To use the application which actually does the name drawing event, you need to edit the sample
.XML file and insert content that matches up with
the participants that will be engaged in the name drawing activity. You can (if it is available) even add history and even add some 'cheats' to the name drawing event.
Once the .XML file is updated, you execute the application by pressing the buttons in the GUI. To test the results, you load up the
index.html and enter pass phrases and press name buttons.
About the data
The input data to the application is arranged in a .XML file. I actually authored the file before creating the
.XSD file. VS2010 has a nice feature
where it will extract a likely looking .XSD file to go with an XML file. After doing that I would modify the XML and remember to modify the XSD accordingly.
Here is a graphic that illustrates the structure of the XML (the graphic was created by VS2010).
How it all works
The finished object is a web page "index.html" that you publish somewhere on the web along with the supporting script file "Crypt.JS"
and the other supporting .html files (wish lists) and a background .jpg file. You then invite the folks who are participating in the name drawing event to visit the site.
Each person enters his "pass phrase" and then presses his "button". This action sends the pass phrase
to the JavaScript which decrypts two messages for that user. The first message tells the user whose name he drew and the second message tells the user whether
or not he is 'The Secret Santa' and if so who he should get an extra present for.
Additional buttons on the page bring up the "Wish Lists"
for the participants. Of course, before you start all this, you get the participant names and
pass phrases and other information and enter it into the .XML file
and edit the .HTML file accordingly so that each participant's button has his name on it. Additionally as the event goes forward, you can update the "Wish Lists"
.html files associated with each participant as they send you, the administrator, the content of their wish lists (phew... now that's a topic for an application feature,
i.e., make the users do all that on their own).
About the structure of the application
The application was created using the Visual Studio 2008 C# Windows Forms Wizard. What this wizard does is bring up
a blank window onto which you place controls.
This application is designed around the buttons (controls) you can press. What follows is a high level discussion of the application given in terms of the controls
you can manipulate. A more technical discussion of the application follows this high level discussion.
- Load XML File - This action opens a "Folder Browser Dialog" that allows the operator to locate the folder that contains the data files.
Once the folder is located and the browser dialog is dismissed, the .XML file is opened and parsed filling in the data values in the application.
If the check box named "Show results" is checked, the application echoes the values of the data in a list box.
Here is a screenshot of the application just after clicking on the Load XML File button:
- Draw Names - This action is enabled after the "Load XML File" is executed. This action will do the "drawing names"
action described above. Because this action simulates a "random-drawing" it may be the case you can get to the
"bottom-of-the-hat" and you find your own name or another name that you can not use like your spouse's or some name
you drew in years past. So in this case you need to start over. The logic is designed to retry up to 100 times then quit with a failure.
You can put in enough history in the XML file so that no solution is possible. In this case you need to remove some of the history or adjust the cheats/spouse relationship(s).
Note: You can analyze the .xml file to determine if a solution for this year is possible. Such an analysis would be like doing
a 'draw from hat' event without doing any random stuff. One way to do this is to walk through the data (including history and rules) and choose
the first set of name pairings that works. In this, combinatorial, approach you could also get to the 'bottom-of-the-hat' and find that no solution
was possible and in that case the function would just return the value "ADJUST RULES/HISTORY NO SOLUTION POSSIBLE" straight away.
- Write Script - This action is enabled after the "Draw Names" action is executed. This action will go through the data
and encrypt the messages associated with each participant using that participant's "Pass Phrase".
The encryption technique is the only perfect encryption technique that exists, which is to XOR the Pass Phrase with the Clear Text.
An XOR operation is such that if applied twice undoes itself. And if the Pass Phrase is a random string it will reduce the Clear Text to a random string.
In cryptographic terms this is called a "One Time Pad". After all the messages have been encrypted the Write Script action will
create the java script named "Crypt.JS". This script consist of three parts: The top, middle, and bottom. The top is just the opening
statements of the java procedure. The middle is an array of the encrypted text created using XOR encryption. The bottom is the logic of the
Java function.
The java function XORs the pass phrase with the encrypted messages and puts the resulting clear text in the text boxes of the
.htm file.
The pass phrases are not in the java script or in the index.html file so if someone forgets his pass phrase he must appeal to the administrator
to dig it out of the .XML file and send it to him.
- View Page - This action is enabled after the "Write Script" action is executed and opens the
index.html file in a browser control.
You can test the operation of the web page after pressing this button. Here is a screen shot of the
index.html file loaded in a web browser control:
In addition to the main buttons that control the application, there is one more button labeled "Crypt"
and three text boxes associated with the button. You enter the clear text and pass phrase in the correct box and pres the Crypt button and see
the resulting crypt text appear in the third text box. This behavior is independent of the operation of the rest of the application but does call
the same function that the main application calls. If you paste the encrypted text into the clear text box and use the same pass phrase as you did
to encrypt and press the Crypt button the clear text is 'decrypted'. Here is a screen shot of such a test where clear text is encrypted:
Here is the class diagram of the whole application. The class named "publicDATA
" is just used to organize all the public
data into one place. All those members could have been declared public in the main application without encapsulating them in their own class.
Some Technical Details
loadXMLFile_Click
- This is function that loads the XML file (and is set up to validate it) and then parses it filling in parts
of an instance of the publicData
class.
The way the function works is that it falls through a series of while(Reader.read())
loops. Inside the large outer loop are a set
of if/then/else
statements that decode the major elements of the XML file which are
thisYearsSecretSantaMessage
,
thisYearsCheatSheet
, historyLog
, and nameList
. If the display results check box is active this function
also calls displayXMLContent
. Additionally since this is the first function called it initializes the random number generator.
drawNames_Click
- Fills in this year's names and chooses a secret
Santa and the secret Santa target. In order to simulate picking names
at random out of a hat the values are generated from a random set of numbers. The two functions
doTheNameDraw
and doPickSecretSanta
actually choose the values. Since these function could fail given enough history was in the XML file to keep a valid pick from occurring or the more unlikely
event that a long string of random numbers would cause a failure; the drawNames_Click
does cater for such a failure. It will also display the results when that
check box is in the checked state.
Note: The doPickSecretSanta
is done before the doTheNameDraw
because one of the built in rules is that
you can not draw the name of the same person who was picked to be the secret
Santa target, assuming you are this year's secret Santa. Here are all the rules:
- [RULE-1] If you have been the secret Santa in the past you may not be it again.
- [RULE-2] If you have been the secret Santa target in the past you may not be it again.
- [RULE-3] You can not draw your own name (except via a cheat which would amount to you opting out of this year's event).
- [RULE-4] You can not draw your spouse's name (given you have a spouse in the list, no multiple spouses).
- [RULE-5] You can not draw the person's name that you did in years past (except via a cheat).
- [RULE-6] If you are the secret Santa this year you may not draw the same name as the secret
Santa target.
writeScript_Click
- For each message that needs to be encrypted this function calls the
Crypt
function.
After this the function writes the Crypt.JS file.
bViewPage_Click
- Finally once the script has been written you can display the
index.html file and exercise it.
About Crypt.JS and index.html
Crypt.js is a file that contains a single java script function that 'knows' about the structure of its companion index.html.
index.html is an html file that consists of a bunch of buttons (one for each participant) and three text boxes; one for the pass phrase one
for the "Here is the person's name you drew." and one for the "You are (or not) the Secret Santa this year."
There is another set of buttons that 'go-to' the "Wish-List.html" pages.
The index.html web page can be totally modified. And, of course, in the process of actually putting together a 'real-world' version of all this
you would indeed modify the index.html file and the wish-lists.html files. To go along with those edits you would collect from each participant (or assign to each)
a "Pass Phrase".
Once you have everyone's name, pass-phrase, spouse-relationship (or not) you modify the drawing_names.xml data file. You may custom
tailor each
message that is presented when a participant's name is drawn and you may custom
tailor the message that is presented for each person who is NOT the Secret Santa
for the year and you may customize the single Secret Santa message. Note that the special characters '$' and '*' in that string are replaced by the name of the secret
Santa and his/her target, if you forget them then the secret Santa message will not work correctly.
So given you have edited the index.html file the drawing_names.xml file and compiled the application then you run the application, surf to the location
of the .xml data file and read the data file draw names and write the script. The application has a built-in window for viewing the final
index.html file.
Points of Interest
The major motivation for converting the application to a C# app was to convert all the data to a file could be read in, instead of having
to actually edit the source code. And I thought the logical choice for the format of the data file was XML. So I needed to know how to read
an XML file and have the contents populate the data for the application. It turns out that I learned two things that were quite interesting.
The first was: The way you extract information from an XML file using XMLReader
is very simple (the nested loops and select statements).
The second thing was: Apparently .NET 3.5 does not have a clue how to validate XML files from a schema when element attributes are involved.
Note: About .NET 3.5:
- It is busted or
- I'm no setting up the schema and/or schema validation logic correctly.
History