Sunday, December 23, 2007

The Marauder's Map of Olin

A friend and I have been planning this for a few months. On a laptop, we can find the signal strengths of wireless access points, and use this information to determine location. A few days ago, I sat down and coded it, in time for Expo. My poster probably says it best:

Instead of using triangulation, it simply acquires a lot of data. (Triangulation did not work as well, because of the many walls and windows in our dorm.) The database simply records associations of a set of wireless signals with a name ("AC Room 318") and a point on a map. To look up a position, the server looks for a similar set of values with a distance formula, and returns the closest match. When the program is run, it recieves feedback from users, and every time adds a new association. Over time, the results get better and better. From successful tests, I think room-level precision may be possible.

We were able to figure out the right WMI query to find signal strengths other than the current connection (in Windows). I then wrote a small C# app that runs the query and prints the results to stdout.

A Python program gathers this data, taking the average of three runs, and sends it to the server. A PHP script forms a vector, thinking of each of the 76 access points as an axis, and looks for nearby vectors in the database. The location of the user, and status, is also stored in a centralized database.

Finally, in a web app you can view locations of everyone who is logged in. Hovering over the icons tells you who and where the person is. (Only if you swear that if you are up to no good).

Monday, December 10, 2007

Improbability

I'm in ProbStat this semester. I didn't feel like working so I wrote a quick little program.

Tools like SurfStat are nice, but they aren't quite what I want. So, I wrote a similar web app, Improbability. You can tab through the fields more easily and simply press Return to evaluate. Also, there is a graphical display of the area under the curve (using CSS and transparency).

So far, just the normal distribution until I'm satisfied with the interface, but other distributions will be pretty easy to add. I just wrote this, and am open to suggestions as to making it better.

Friday, December 7, 2007

Math Console

Here's my old Math Console.

Before I had ever used Matlab, I wrote something resembling it (in JavaScript, of all things). I used it at the time for my statistics class, and kept the code kicking around, but never got around to finishing everything that I had planned. (I had wanted to add many more statistics features). One of the factors was JavaScript's lack of support for overloading operators, which kind of stopped things. Also, there isn't really a convenient way to support complex numbers.

Today I made it (somewhat) cross-platform. Since this might be as complete as it will get, I'll call this the last version. Open the page and you can click a link to see a list of features and provided functions.

I still think this is a pretty cool project, and I am just now working on something similar in Python.

Tuesday, November 13, 2007

Tetris Overflow - On Camera

As explained in an earlier post, in the Tetris game from WEP, the score overflows. I was able to repeat this a few times and it happened each time. Now, I've got it on camera (needed a lot of takes, so I have even more practice now).

Video

Look at the score.

Monday, November 12, 2007

201%

(If you don't get it, it's a reference to a song).

Saturday, November 10, 2007

Directory

Last year, I wrote a DHTML app (in 30 minutes) for searching the directory of my college.
I parsed all of the data and wrote a Python script to turn it into a JavaScript array. With all of the student data in one JavaScript file, looking up information is extremely quick because everything is on the client and there is no server round-trip. So, I didn't even make a "Search" button - the results are returned as you type.
You can search by dorm and by floor, and send e-mails.
This year, fellow students built upon this idea and created a Directory with even more features.

Saturday, November 3, 2007

Pyget

I wrote a small program in Python for downloading files. (It is basically an interface for urllib, which does the real work). You can also use it from the command line with wget-like syntax.

It has some convenient features. If you have copied a url in the clipboard, it is automatically placed in the field, saving you a step. In the "Add..." dialog, you can specify a sequence of urls with the syntax "http://test.com/file_[0-4].zip", which expands into "http://test.com/file_0.zip", "http://test.com/file_1.zip", and so on. The most useful feature is downloading links from an html page:

Here's the code. You'll need a recent version Python and the wxPython GUI toolkit.

Friday, November 2, 2007

Quoteboard

I wrote an online quoteboard from scratch. Using only my own code makes it lightweight, and I like being able to customize every detail.
After 30 minutes planning and around 30 minutes of quick PHP/Mysql coding, I had a functional version of the site: Each quote also has a page where you can discuss it. Using xmlhttprequest, I added AJAX voting buttons that don't require a page refresh!
Today, I added some styling, which took a while, but looks nicer:

Thursday, November 1, 2007

Nondeterministic Finite Automata

For an open-ended project in my Computer Science course, I wrote a program which will take any regular expression as an input and generate a NFA for recognizing that language. It can display this NFA graphically as well as generate Prolog code for simulating it and using it to match strings. (So, if you have Prolog, you could use this as an implementation of regular expressions.)

I generate dot format files and call GraphViz to draw the graph. I use the symbol ',' to mean concatenation and enter 'a,a,b,b' instead of the traditional regexp 'aabb'. In the graphs, '.' refers to a null transition. Here are some sample inputs and outputs:

a*,b|c (a|b)* (a|b),(a|b) (Note that my handling of * is slightly incorrect because the expression must be present at least once.) Disjunction uses the '|' symbol, for example 'a|b' means a or b. Unlimited levels of nested parenthesis are supported, thanks to recursion.

I process the expression recursively by at each point dividing the input string into two parts, if possible. The string '(a|b),b' is split into (a|b) and b with the operation ',' , and the first part is then split into a and b with the operation |. If the expression is a or a*, then it will return, and work its way down. To my knowledge all complicated expressions are recognized successfully.

The Python program then will output Prolog code that can be consulted. Once consulted, the predicate parse can be used with a list to see if the string is recognized by the language.

Prolog code generated for (a|b),(a|b)
parse(L) :- start(S), 
    trans(S,L).

trans(X,[A|B]) :-
      delta(X,A,Y),
      write(X),
      write('  '),
      write([A|B]),
      nl,
      trans(Y,B).
      
trans(X,[A|B]) :-
      nulltrans(X,Y),
      trans(Y,[A|B]).
      
trans(X,[]):-
    nulltrans(X,Y),
    trans(Y,[]).
      
trans(X,[]) :- 
      final(X),
      write(X),
      write('  '),
      write([]), nl.

delta(0,a,1).
delta(0,b,2).
delta(3,a,4).
delta(3,b,5).
nulltrans(1,3).
nulltrans(2,3).
nulltrans(4,6).
nulltrans(5,6).
nulltrans(99,99).
start(0).
final(6).

Sample output of this Prolog code recognizing (a|b),(a|b):
| ?- parse([a,b]).
0  [a,b]
3  [b]
6  []

true ?

yes
| ?- parse([b,a]).
0  [b,a]
3  [a]
6  []

true ? 

(15 ms) yes
| ?- parse([b,a,b]).
0  [b,a,b]
3  [a,b]

no
| ?- parse([b]).
0  [b]

Sunday, October 28, 2007

Audio

Unlike most of the projects I've been working on, this one was related to a class. (But it is still thrown-together, undocumented, and uses several list comprehensions to write an audio effects in one complicated line of code). I'm in a course called Engineer's Orchestra where we build instruments and do physics. I was curious about how sound files on a computer work , so I set off learning a lot about digital audio. The first fun part was to learn the insides of a .wav file and write one starting from only bytes. Then, as a project for the class, I wrote a complete audio editor from scratch!

I wrote it in Python, because it would take me the least time to write it. My challenge was to write this without referencing any other code, like Audacity. This made it more fun.

The GUI isn't very good, specifically because there are no other dialogs, but I have most of the important features covered: Add Silence Before, Add Silence After, Chop, Append File, Mix File, Modulate, Make Louder, Make Softer. And, it loads and saves standard wav files (16 bit or 8bit), so it is actually practical for editing things you have recorded.

Then, I added a lot of audio effects. I would read the gist of an effect on Wikipedia and try to code it. This was even more fun, because if I got something wrong, it sometimes played very strange sounds. (I don't have any analog-style effects, like filters yet, but this is something I would really like to learn). In the GUI, you can use the following effects: Reverse, Octave up/down, Change pitch (the most challenging to think of how to write), Vibrato, Flanger, Echo, Reverb, Chorus, and Alien Voice. The alien voice modulates the samples with a sine wave - I came up with it while experimenting and don't know why it sounds strange.

Listen to these (the wavs were generated by my program):
Vibrato
Low
Reverb
Alien Voice

Next, I added code to synthesize sounds. Sine, triangle, square, and sawtooth waves aren't that great by themselves, so I tried combinations of them to get the most interesting voices. The secret to making a sine wave sound better is to quietly mix in frequencies at that are slightly different. Surprisingly, the subtle beat frequencies make it sound expressive and musical. I worked a long time to create an electric organ-like instrument out of sine waves, and finally came up with something.

Here are the results:
Electric Organ
Smooth
Retro
Red Noise
Squarephase

Finally, I put all of the pieces together. I had an audio editor that can modify and arbitrarily change the pitches of sounds. So, I made a sampler! I wrote a command-line interface for a program where you can type in notes and play them. It parses commands like a4 into the note A440, or 4.f#5 into "play a dotted quarter note at F# 5". As an instrument, you can use anything - samples of your voice, a sample of a real instrument, your computer's MIDI, or even the same synthesized instruments like Electric Organ or Smooth.

The program works well (the effects even work in both 16bit and 8bit sounds).

Lest you think this program is polished, I must admit that it is not. This is not a joke, it is actually in the source:

manualsynth(audiodata, nsamples, _extend([[freq, .5*0.9**(8-1)]], [[freq*(i+1),.5*0.1*0.9**((8-1)-i)] for i in range(1,8)],[[freq*1.00606, .5*0.9**(8-1)]], [[freq*1.00606*(i+1),.5*0.1*0.9**((8-1)-i)] for i in range(1,8)]))


I should get around to fixing that sometime.

Saturday, October 27, 2007

Quick Unicode Entry

This project doesn't have any direct use now, but it was fun to write, and might be useful for writing letters in Spanish. I can simply hit Alt-A to get an a with an accent, Alt-Shift-1 to get ¡, and define any other combination I want.

This program is a lightweight text editor intended for writing text in other languages. Most word processors have a "Insert Symbol" option for inserting a character, but this process is too slow. If you do all of your typing in another language, one can set the system language, but this will be a system-wide change and is not very customizable. In this program, on the other hand, it is simple to set up your own keymaps and choose what keys create which characters. One can also conveniently visualize these bindings.

Because some languages require access to more than 26 symbols, this program uses the concept of "modes." For example, the default keymap has a mode called Grave Accent. In this mode, typing a vowel like o will produce o with a grave accent. The program begins in Normal Mode, but you can press Control+L to enter Grave Accent mode. View the available modes for the current keymap by choosing List Modes from the Characters menu.

When you enter a mode, you stay in that mode until you press the key combination, typically Control+Space, to return to Normal mode.

Edit the current keymap by choosing "Edit key bindings" from the Characters menu. (Changes take place when the mode is selected from the Characters menu). Create a new map by creating a .py.js file in the keymaps directory.

The Code. Unzip and run "main.py." Works in Python 2.5. Linux is not yet supported, as it seems the keycodes are different.

I spent some time coming up with good keymaps. It comes with a map for characters in Latin-1 and a very useful Greek map.

Wednesday, October 24, 2007

Interesting Facts in Biology

Did you know?
  • Slugs are gastropods that have white flowers for a specific tissue.
  • This has produced a nuclear matrix secreted into the bird’s plasma membrane.
  • Individuals associate with polar molecules such as that of the worm through the mitochondrial and chloroplast genomes of the urethra.
I wrote a program that will analyze and automatically summarize Biology. (Very useful). It's a web app, but is on Olin's server right now. I compiled a huge amount of Biology information and made a Markov model. I did a lot of work in Python stripping unwanted data. At first, I was putting all of the data in a php file, but this turned out to be inefficient and a heavy load on the server. I ended up with a solution: I divided all of the text into 64 slices, and then created 8 medium-sized files out of shuffled slices (for variety). I then wrote Python code to generate one Markov model for each of the files and save the results as a Javascript object .js file. Then, the php code randomly picks one of the 8 .js files to include whenever the page is loaded. The Markov generation is all client-side, so you can generate many times without needing a page refresh.

Sunday, October 21, 2007

Computer Science + Lolcats

I did some photoshopping last week :)

If you've taken a Computer Science course, you may find this humorous. It's my Powerpoint presentation of Computer Science + Lolcats.

(Feel free to copy these but give me credit).

Saturday, October 13, 2007

Beep

This weekend I thought it would be cool to learn about digital audio. Specifically, I wanted to look inside of audio files and know how they work on the level of bytes. Also, I'm going to do my exploring without looking at other source, like Audacity, to make things more interesting.

It turns out that digital audio files are split up into frames that are typically either 8-bits or 16-bits. So a wave file is essentially list of 8-bit or 16-bit numbers that represent the pressure on the microphone. The frame rate dictates how many of these frames go by per second.

In thirty minutes, I was successfully able to come up with code for creating a .wav file at any frequency:
import wave
import math
import array

#Create a 16 bit wave
width = 2 #16 bits is 2 bytes
maxval = 65535
sample_rate=44100
channels = 1
samples = array.array('h') #Signed short

# Create a sine wav, of frequency fFreq
nSamples = sample_rate*2 #two seconds long
fFreq = 440
w = fFreq*2*math.pi / sample_rate
amplitude = 65535/2 #Loudest amplitude
samples.extend( (amplitude * math.sin(w*x)) for x in xrange(nSamples) )

f = wave.open('c:\\a440.wav', 'wb')
f.setnchannels(channels)
f.setframerate(sample_rate)
f.setsampwidth(width)
f.writeframes(samples.tostring())
f.close()
Some of my ideas: The array type works perfectly for storing the samples - it is far more efficient than a Python list. Note also that I am using a "generator expression", which works similarly to a list comprehension but does not need to actually create the list. In the future I plan on using generators for creating the signals.

It is weird that 16-bit sound is in the "signed short" format, instead of being unsigned.

On a less serious note, I then saw the beep method winsound module, and was amused:
import winsound
# so retro!
winsound.Beep(440,10)
winsound.Beep(600,10)
#bonus stage!
for i in range(40,400,30):
    winsound.Beep(i,90)
There's no way to control the volume, though, so this can get annoying.

Next I'll be writing some sweet audio effects.

Thursday, October 11, 2007

Recursive Shapes v0.2

This project took far longer than half an hour, but it's pretty cool.

While doodling in Bio, I thought of a way to programmatically draw any recursively-defined shape. By this, I mean any shape that contains a scaled-down version of the entire shape. This is a property found in many fractals.

Traditionally, and in all of the fractal-drawing software of this type I've seen, the shapes are defined with turtle-style commands (turn right, draw a line, turn left, and so on). There exists a specific system called L-System that can define recursive pictures, and with a lot of work can probably define everything my program can, with the exception of curves. However, when looking at the shape, I do not always find the long list of turtle instructions or L-System rules to be intuitive. I decided to instead use traditional Euclidean x and y coordinates, and Python code as the rule defining the next iteration. This way, I can sketch out a shape on a piece of paper and enter its code very quickly and clearly. It is much easier to me to enter a shape in terms of x and y.

I had an idea for drawing curved lines that turned out very well. The code actually draws an arc of a circle, but positioned so that the arc passes through the two points. A parameter specifies how much curvature should be given.

Looking at the still images is only half of it: I added an easy way to draw animations! There are a lot of really cool animations defined in the samples. (Play them by removing the # and pressing draw.)

Here is the code (71k). (Requires Python 2.5, cross-platform). All you need to do is unzip the file, open main.py, load a shape from the shapes menu and start playing with it! The argument to the .draw() method is the number of iterations (don't make this too big). You are encouraged to tweak the code or create your own shapes.
I wrote this just for fun, and it's (unfortunately) not connected with anything I'm doing at school.
Planned for the next version:
Drawing images, ellipses, text. Save images as PNG files, anti-alias option. Making variable names consistent... and a revolutionary improvement that is still in the works.

Sunday, October 7, 2007

So Good It's Bad!

I was playing Windows Entertainment Pack Tetris. After the 10th level, it doesn't get any faster (of course it is fast enough) - and so I was playing for a while, when suddenly I noticed that I had a negative score!!! The integer representing my score had overflowed! The Windows Entertainment Pack version of Tetris must display your score as a signed 16-bit integer (I think it's even a 16 bit program). Because of 2s complement, an integer will after being large positive will be large negative. The number still sorted as larger than the other scores, and counted as a high score, though. Cool.

Wednesday, October 3, 2007

Unreadable Python


exec(")))'YLRJHOUVO[`WYLO[VUH',dro(pam,)52+c(rhc:c adbmal(pam,__dda__.rts(ecuder tnirp"[::-1])

Actually, I could have made it a lot worse. But it was still fun. Figured it out? Try this one:

print reduce(str.__add__,map(lambda c:chr(c+25),[(72-sum([ord(c)-74 for c in '=IEVM=LAOVCKPQHBP='][:i])) for i in range(19)]))


Friday, September 28, 2007

Periodic Generator

A few years ago, I saw a t-shirt that spelled "WWU Chemistry" in the style of a periodic table. So, I decided to throw together a DHTML program to spell an arbitrary phrase this way. Today, I cleaned up the code a bit and added sample phrases. The algorithm prefers two-letter combinations to one letter. Unfortunately, a lot of common letters can't be done exactly, so I had to be a bit creative. Here's the link. 2012 Edit: In 2005, only IE could flip text, now Firefox can too, so I'm using css3-style rotation.

Enjoy!

Monday, September 24, 2007

JavaScript and Logic

Two years ago, I was in a logic course at WWU. The class was interesting, but some of the assigned online work was a bit repetitive. I did enjoy proving theorems, but filling out the truth tables was not exciting.

So, after some thinking, I quickly wrote a script called "logic.js" which can evaluate prepositional logic. I thought of how to do this from scratch (looking back on it there are probably better ways to do evaluate infix notation). For compound expressions, the idea was to use regex to find the innermost operation and evaluate it, replacing it with the result. Then this process would be repeated until there was only one value.

I used the engine to Draw Truth Tables and Evaluate Logic.

For fun, I wrote a similar program for a ProbStat course, at around the same time, for Set Diagrams. None of these are "finished" finished, but they work well enough.

C# Is Useful

For throwing together a GUI app, C#.NET is actually pretty handy. Here is my demo proving that C# isn't all bad - that is pretty quick and effective. Note that you don't need to use the visual designer at all, and that is what I would do for a larger scale project.
For larger scale projects, XAML is pretty interesting too. I used it at work this summer.
Why I like it:
  • Compilation step isn't a hindrance - it is fast and catches many mistakes.
  • GUI designer is helpful but it's easy to code your own layout.
  • .NET library comes with a lot.
  • Sweet language features make it feel more flexible and fun than Java.

On the other hand, here are the reasons why I still believe .NET is not the answer:
  • Not really portable to Linux. (Yes, Mono, but still).
  • Requires a huge framework. There isn't a way to "static link" your programs. This means that Joe User might have to download lots of megabytes to even run your program, which I know I would be reluctant to do. And what if he is on dial-up?
  • Memory management and performance - it's pretty good, but watch out for certain things (GC, deep inheritance, reflection, and UI drawing). It is sometimes hard for me to accept that: "My C# program looks and behaves the same as one written in C++. But it is slower and takes more memory." The only answer is developer time. Of course, I am glad that there are simpler languages like C#, and they have benefited me, but this tradeoff is probably partially responsible for today's software bloat.

Thursday, September 20, 2007

Tetris

Bored? Time for Tetris. 1990 Style.
High Score: 25,613 (good)
Favorite Move: The Spear (See it)
Windows Entertainment Pack Tetris is where it's at.

Wednesday, September 19, 2007

TweakUI, RTF

I used to Regedit most of my Windows customizations. But now, the TweakIU program provides a GUI for many common changes. Here are some of my favorites:
Read the "tips." There will be some handy keyboard shortcuts. (Did you know you can hold down Control to select many taskbar items? Also, when confirming file actions, Shift+No will mean "No to All."
Under Internet Explorer, you can set the loading-page animation, which I used to great effect. (When I use IE, now I have a running Mario icon when a page loads). I also changed a registry setting so that "Internet Explorer, brought to you by Mario" is in the title of each window.
Finally, under Templates you can edit the entries in the Windows "New file" menu. (This is under the file extension in HKEY_CLASSES_ROOT). I added a "Rich Text Document RTF" entry by pointing to a new .rtf file on my hard drive. Wordpad can be a good lightweight editor if you want simple formatted text. (And, you can use Paste Special/Unformatted to strip formatting). So I always associate .rtf files with Wordpad.
No, rtfm is not a manual in rtf format. It means something else.

Saturday, September 8, 2007

Pointillism

Facebook has a "Graffiti" application where you can draw pictures on a profile by clicking and dragging. Because art is not my forte, I decided to find a way to paste an actual bitmap image in the space.

First, I made a grayscale image of my face. I wrote a little Python script using the Python Imaging Library to make a list of all pixel coordinates that were white. I then wrote an AutoIt script to simulate mouse-clicks at all of those screen locations (hacktastic).

The results:
Not perfect, but still visible.
AutoIt is a pretty cool program for Windows automation. It can simulate keyboard and mouse events.

The actual reason I did this is that I wanted to learn about image processing in Python. It's usually not trivial in most languages / libraries to get pixel access of a PNG image, but PIL seems to do well. Stay tuned for my upcoming ultimate Image Processing lab.

Tuesday, August 28, 2007

Lame

Not a hack, but when encoding MP3s I've found it's useful to dispense with some GUI and use LAME direcly. Download the LAME mp3 encoder someplace, and it will come with an executable. Then, you can write a batch file (.bat) like:

rem Adapted from a script by Robert Hegemann
@echo off
:processArgs
if %1=="" goto endmark

"C:\path\to\lame.exe" -h --abr 160 --mp3input %1
if errorlevel 1 goto errormark
shift
goto processArgs
:errormark
echo ERROR processing %1
pause
:endmark
pause
Put the batch file someplace accessible. To encode some songs, all you need to do is drag and drop them onto the batch file.

Friday, August 24, 2007

A n00b's RGB song

Written at around 3 am:
(Sung to the tune of "abc"/Twinkle Twinkle Little Star)

"0 1 2 3 4 5 6
7 8 9 A B-C-D-E-F
Sharp o o o o o Black
Red Green Blue White Web Safe hack
Now I know my RGBs
I can be a hacker please?"

Tuesday, August 21, 2007

Speed Reading

Sometime this year, I was discussing speed-reading with some friends at Olin. We were thinking of faster ways to read. I can't remember exactly why, but that night I wrote this very quickly.

Speed read

Change the number to change the delay between words. (I think the idea is to start at a comfortable level and gradually get faster).

I found it today and quickly renamed some of the variables and made it more browser compatible. (Also, in the old version the loop function would call setTimeout on itself with a parameter, but now I realized that it is better to use a global variable, g_nIndex). This is still definitely a thirty minute hack (low quality, questionable usefulness, and really fun).

Python Ostream

Here's a hack I read about in the Python Cookbook. This one's for everyone who dislikes C++ :) The idea is to allow syntax like "cout << x" in Python. I liked the idea so I put together a simpler and cleaner implementation.

This is Python code (!):
cout << "hello, world" << nl
cout << "Tuples:" << (5 , 6, 7) << nl
cout << "Lists:" << [5 , 6, 7] << nl
    
cout << "The number, " << 1+1 << ", bigger than " << 1.0/5.0 << nl
print "The number, %s, bigger than %s" % (1+1, 1.0/5.0)
print "The number," , 1+1 , ", bigger than" , 1.0/5.0
# The 2nd is inelegant in my opinion.
# I currently use the 3rd, but note that it inserts spaces, so it prints something different.
and here is the class (concise, and you can even pass it another stream object):
import sys
class OStream():
  def __init__(self, output=None):
    if output is None: output = sys.stdout
    self.output = output
  def __lshift__(self, obj):
    self.output.write(str(obj))
    return self
cout = OStream()
nl = '\n'
The recipe given in the Cookbook was longer, less clean (endl was an IoModifier object rather than '\n'), and used '%s' % obj instead of str(obj). I prefer my approach. I'm sure you could add all sorts of other "useful" features.

Have you ever thought it is weird that left-shift means print? Actually, cout << "hello" is a lot nicer to type than cout("hello"), to me at least, so I don't really mind. Coming up next: subclassing list so that mylist << 4 does mylist.append(4) ... and mylist >> 0 does mylist.pop(0). (Just kidding).

Friday, August 10, 2007

Change Desktop Pattern

Here's another example of how you can make something really nifty in under thirty minutes. A year ago, I wrote a WSH script to change my desktop pattern on startup. I found the right registry keys to change, but unfortunately, the changes wouldn't take effect until the desktop was refreshed. Then, I found an example of how to refresh the desktop here (I guess someone else had thought of this before me), and so I was ready. Note: I haven't tested this in Vista.
To set it up,
1) Create a folder, and a subfolder named "bgtemp".

2) Enter the following and save it as "go.bat", within the folder:
echo "Change of Wallpaper - Ben Fisher"
@echo off
del bgtemp\*.bmp
cscript /NoLogo changed.wsf
3) Enter the following and save as "changed.wsf". Change the code so that strPath is set to any directory with JPG pictures, and strDestination is set to the "bgtemp" directory.
<job id="ChangeBG">
<script language="JScript">
fs = new ActiveXObject("Scripting.FileSystemObject");
var fso, e, file;
var strName; 
var aNames = [];
var strPath = "C:\\Program Files\\Ben's Fractal Screensaver\\Media";
var strDestination = "C:\\Program Files\\Ben's Fractal Screensaver\\Script\\bgtemp\\";
fso = new ActiveXObject("Scripting.FileSystemObject");
e = new Enumerator(fso.GetFolder(strPath).files);
for (e.moveFirst(); ! e.atEnd(); e.moveNext()) 
{
  file = e.item();
  strName = file.name.toString();
  if (strName.indexOf(".jpg") > 1) 
    aNames.push(strName);
}
var nWhich = Math.floor(Math.random() * aNames.length);
var fullpath = strPath + '\\' + aNames[nWhich];
strDestination += aNames[nWhich] + '.bmp';

//Convert to bitmap
var Converter = WScript.CreateObject("Gfx.Converter");
Converter.ToBitmap( fullpath, strDestination );

// Change registry
var objShell = WScript.CreateObject("Wscript.Shell");
objShell.RegWrite("HKEY_CURRENT_USER\\Software\\Microsoft\\Internet Explorer\\Desktop\\General\\BackUpWallpaper", strDestination);
objShell.RegWrite("HKEY_CURRENT_USER\\Control Panel\\Desktop\\Wallpaper",  strDestination);
objShell.RegWrite("HKEY_CURRENT_USER\\Control Panel\\Desktop\\Wallpaper",  strDestination);

// Refresh, credit to http://www.oreilly.com/pub/h/5091
objShell.Run("%windir%\\System32\\RUNDLL32.EXE user32.dll,UpdatePerUserSystemParameters", 1, false);
</script>
</job>
4) You'll also need the "convert to bitmap" ActiveX control from http://dev.remotenetworktechnology.com/wsh/comwsh.htm. Unzip and register the dll with the command: Regsvr32 GfxConverter.ocx. It is kind of interesting to learn that desktop patterns must be .bmp files - if you choose another file type in the Desktop control panel it is silently converted into bmp.

5) Put a shortcut to "go.bat" in your startup folder. c:\Documents and Settings\(you)\Start Menu\Programs\Startup.
And that's it!

System Sounds!

Here's a great way to make your operating system more fun. First, get little clips from some of your favorite songs - the more distinctive, the better. Audacity is perfect for this. You'll have to export into WAV format, then, in the control panel, set them as your system sounds.
My computer is now Incredibly Awesome!
Start WindowsGloria
Windows LogonBerg - Violin Concerto Mv. III Allegro
Exit WindowsGrandmaster Flash - The Message
Windows LogoffEdgar Winter - Frankenstein
Device ConnectJavanese Bell Excerpt
Device DisconnectJavanese Bell Excerpt
Program ErrorJames Brown - Living in America
Critical StopYes - City of Love
AsteriskJohn Cage - Sonatas and Interludes for Prepared Piano
Default BeepLou Harrison - Concerto for Flute and Percussion Movement II
System NotificationLou Harrison - Concerto for Flute and Percussion Movement II
ExclamationToru Takemitsu - November Steps for Orchestra
I pulled these 2-second clips from songs in my music library, and I also got some good clips from an old copy of Encarta (I love the bells). Because the volumes aren't normalized, things are even more exciting. Feel free to use these!

Chat History Reader

I used Windows Live Messenger quite a bit at work this summer. You can save message logs in an xml format (enable this in Options). There is an xslt to view the logs in IE, but I wanted something cleaner.
So, I put together a quick app in Windows Forms. (You'll need the .NET 2.0 framework). It doesn't do much, but it does have search. The main interest for me was to use the XmlTextReader (a very nice lightweight xml reader built in to .NET, perfect for this task). I was also interested in RTF; instead of the methods for formatting, I set the raw RTF of the RichTextBox. The result is a useful little app, thanks to .NET.
Source and binary (68 k).

Visual Studio Shortcuts

Visual Studio Shortcuts Here are some of the Visual Studio shortcuts I use.

Commands

Visual Studio includes a basic command-line prompt that is very useful for opening files. One way to enter commands is to press control+/, and then type >. You can then start typing a command, like "open", and then part of a filename. The nice part is that this autocompletes, so this is a great way to open any file in your solution quickly. Press enter and the command is run. All of the commands you see in Tools-Options-Keyboard can be entered too, such as "File.CloseSolution" and so on.
There is a "command window" that is dedicated to this. I've mapped Ctrl+Space to View.CommandWindow, which is quicker than Ctrl+/, >. You can set up an alias to any command. For example, to set up an alias to a commonly used file, enter this:
alias m File.OpenFile CommonlyUsedFile.cs
Now, you can press Ctrl+Space,m,Enter to quickly open that file - very useful if you have a large solution. There are many built-in aliases such as "open" for "File.OpenFile". View this list by typing "alias" with no parameters, or remove an alias with the syntax "alias m /delete". I deleted most of the other aliases, as I'd rather type Ctrl+F4 then "close", and so on.
Useful aliases:
sh Tools.Shell
o File.OpenFile
cls Edit.ClearAll
g Debug.Start
bl Debug.Breakpoints
kb Debug.ListCallStack

Macros

Macros are a great idea, but I'm not too impressed with them in VS. VB is such an ugly language, and there is a distracting pause when running a macro. Anyways, I'd thought I'd try my hand. Here's something that will complete all nested parens and end the line. For example, if you type Console.WriteLine(a.ToString( and run the macro, it will add "));" and start the next line. I've mapped this to Control+Enter, and it can be useful if you are too lazy to count how many parens to close.
Sub CompleteLine()
Dim line As String
DTE.ActiveDocument.Selection.StartOfLine(0)
DTE.ActiveDocument.Selection.EndOfLine(True)
line = DTE.ActiveDocument.Selection.Text

Dim nparens As Integer, i As Long
nparens = 0
For i = 1 To Len(line) - 1 Step 1
    If StrComp("(", Mid$(line, i, 1), vbTextCompare) = 0 Then
  nparens = nparens + 1
    ElseIf StrComp(")", Mid$(line, i, 1), vbTextCompare) = 0 Then
  nparens = nparens - 1
    End If
Next

Dim strResult As String
strResult = ""
For i = 1 To nparens Step 1
    strResult &= ")"
Next
strResult &= ";"

DTE.ActiveDocument.Selection.EndOfLine()
DTE.ActiveDocument.Selection.Text = strResult.ToString()
DTE.ActiveDocument.Selection.NewLine()
End Sub
I also have a macro that duplicates the current line, but I'm frustrated by the pause. My wish is to come up with something that could organize my Ctrl-Tab into visual, and not MRU order, but that's a story for another day.

Snippits

Snippits are a great feature of VS 2005. You can easily create your own snippits by creating xml files. There is a nice GUI for creating Snippits called Snippy (A Visual Studio 2005 PowerToy), but it seems to have dissapeared entirely along with gotdotnet.com. So, I've posted it here (378k).
I wrote snippits for creating unit tests, switch statements, and some XAML structures. Most often I used prop and propd for quickly creating properties.

Shortcuts

Finally, here are some keyboard bindings that I find useful:
Ctrl+Space View.CommandWindow
Ctrl+Q Edit.CommentSelection
Ctrl+Shift+Q Edit.UncommentSelection
Ctrl+Alt+, Toggle Bookmark
Ctrl+, Next Bookmark
Ctrl+Shift+, Prev Bookmark
Ctrl+Alt+W Watch Window
Ctrl+Alt+K Call stack
Ctrl+Alt+R Toggle Word wrap
Ctrl+Shift+Alt+W File.CloseSolution
If you happen to have MbUnit (which is cool) or VisualSVN,
Ctrl+T MbUnit – Run Tests
Ctrl+Shift+R VisualSVN-Revert Changes current item
Ctrl+Shift+H VisualSVN- Show current file changes
Ctrl+Shift+Alt+H VisualSVN – Show All Changes

Some of these override standard key bindings, but it’s easy to assign another. I have Ctrl+Shift+Space to be Edit.CompleteWord rather than Ctrl+Space. Anyways, those are some ways to make Visual Studio work for you. The Clipboard ring is nice also.

Tuesday, August 7, 2007

Adding Links to Web Album Generator

Web Album Generator is a great freeware program for creating online photo albums. It is sleek, easy to use, and does things the right way.
The only complaint I have is that it is not very customizeable. I like how in Facebook albums, clicking on the current photo takes you to the next photo, providing a quick way to skim through the pictures without having to find the "next" link. Web Album Generator has no option for this. But, since the output is just normal HTML, I can write a script to make changes to all of the HTML files.
Here's a Python script that will do the trick. If you haven't used Web Album Generator, you should give it a try. After exporting the album, specify the directory (strDirectory) and run the script. (You might want to make a backup copy first.)
# Designed for Web Album Generator 1.8.2 (ornj.net)
import os
import re

strDirectory = r"C:\outputdirectory"
astrFiles = os.listdir(strDirectory)

reNextPicture = re.compile('<a href="([^"]+.html)" title="Next Photograph">Next')
reEndlink = re.compile('(</div>)\s+(<p class=")')

def main():
  for strFilename in astrFiles:
    if strFilename.endswith("html"):
      f = open(st + '\\' + strFilename, 'r')
      strHtml = f.read() #Read entire file
      f.close()
      
      objmatch = re.search(reNextPicture, strHtml)
      if objmatch:
        filenext = objmatch.group(1)
        strHtml = strHtml.replace('<div id="photograph">', '<div id="photograph"><a href="'+filenext + '">',1)
        strHtml = reEndlink.sub('</a> </div> <p class="',strHtml)

        fout = open(strDirectory + '\\' + strFilename, 'w')
        fout.write(html)
        fout.close()
        print "Written:" + strFilename
main()

Monday, August 6, 2007

C#3 Extension Methods

I like some of the new C# 3.0 features. Extension methods are fun to play around with. Isn't this ridiculous:
(4).Square().ToString().Print(); // Prints 16
No performance drawbacks, and so much fun!

On a more useful note, I've written some extension methods that have been serving me well. (We've just upgraded to Orcas at work.)
  internal static class StringExtensions
  {
    public static void Print(this string str)
    {
      Console.WriteLine(str);
    }
    public static void Trace(this string str)
    {
      System.Diagnostics.Trace.WriteLine(str);
    }
    public static string Multiply(this string str, int n)
    {
      StringBuilder sb = new StringBuilder();
      for (int i = 0; i < n; i++)
        sb.Append(str);
      return sb.ToString();
    }
    public static string[] SimpleSplit(this string str, string strDelim)
    {
      return str.Split(new string[] { strDelim }, StringSplitOptions.None);
    }
    public static string SimpleJoin(this string[] astr, string strDelim)
    {
      return String.Join(strDelim, astr);
    }
    public static Boolean IsNullOrEmpty(this string str)
    {
      return String.IsNullOrEmpty(str);
    }
    public static int ToInt(this string str)
    {
      return int.Parse(str);
    }
    public static Boolean Contains<T>(this T[] a, T val)
    {
      return a.IndexOf<T>(val) != -1;
    }
    public static int IndexOf<T>(this T[] a, T val)
    {
      for (int i = 0; i < a.Length; i++)
        if (a[i].Equals(val))
          return i;
      return -1;
    }
    // Just like Python!
    public static TValue Get<TKey, TValue>(this Dictionary<TKey, TValue> dict, TKey keyTry, TValue defaultVal)
    {
      TValue ret;
      return dict.TryGetValue(keyTry, out ret) ? ret : defaultVal;
    }
  }
I wish you could overload operators - I wanted to see "ab" * 3 (ababab) and "word"++ (WORD).

C#3 also has introduced object initializers, which are nice. Still no dictionary initializers, though - I'm disappointed. (See also the BidirectionalDictionary). Here's a workaround - I wish I could have used generics.
Dictionary<int, string> d = new Dictionary<int, string>();
d.AddMany( new object[] {4, "a", 5, "e", 6, "f"} );

public static void AddMany<TKey, TValue>(this Dictionary<TKey, TValue> dict, object[] aIn)
{
  if (aIn.Length % 2 != 0) throw new ArgumentOutOfRangeException();
  for (int i=0; i<aIn.Length; i+=2)
    dict[(TKey) aIn[i]] = (TValue) aIn[i + 1];
}

Friday, August 3, 2007

0xBAADF00D

I made a hexsp33k generator earlier this week. First, I got a large word list that contained inflections. I used agid-4 and wrote a quick python script to eliminate the unsure entries, proper nouns, and other characters. The result was a list of words separated by newline, with inflections delimited by space. Ready to go.

Because Hexsp33k doesn't need strict spelling, my thought was to use a "score" for each mapping of English to hex.

Looser mappings would have a negative score, hopefully eliminating entries that would be hard to read. I add to the score for each letter group. However, it turned out that I got best results when I stuck to only accepting A-F and 0 as O, and 5 as S. The other phonetic transcription ("for" into 4) would need a better algorithm.

Results:
0xCA5CADE5

0xBADA55E5

0xFACE0FF

0xFACADE5

0xDECEA5ED

0xC0FFEE (0xDECAF)

0xAD0BE

0xDEFACED

0xDEC0DED

0xAC1D, 0xD15EA5ED

0xDA7ABA5E 0xACCE55

0xC0C0A

0xBAD 0xF00D! 0xFEED 0xBOA!

0xACCEDED 0xDECADE

FADE, FACE, CAFE

DEAF, DEAD, DEED

0B0E C0DE BEADED B0BBED BAD

DEC0DE, DEFACE, D00D00, D00DAD

FOE, EBBED, FADED

Code:
Tweak the constants until you get something. It doesn't work that well - if I had had more time I would have explored some type of fuzzy matching, to allow creative misspellings. Also, in a 30 minute hack I tend to have inconsistent variable names in Python.
import operator
map = {
'a':['A', 0], 'b':['B', 0], 'c':['C', 0], 'd':['D', 0], 'e':['E', 0], 'f':['F', 0],
'o':['0', 0],  'ox':['0x', 0], 'ocks':['0x', 0], 'oks':['0x', 0], 's':['5', -.11],
#sounds like
#~ 'one':['1', -.4],
#~ 'won':['1', -.4],
#~ 'wun':['1', -.4],
}

def main():
  f = open("agid-4\\infl3np.txt", 'r')
  aResults = []
  for line in f:
    astrWords = line.lower().strip().split()
    for word in astrWords:
      nScore = 0
      strString = ''
      c = 0
      #higher score is better
      while c < len(word):
        if word[c:c+1] in map:
          data = map[word[c]]
          c+= 1
        elif word[c:c+2] in map:
          data = map[word[c:c+2]]
          c+=2
        elif word[c:c+3] in map:
          data = map[word[c:c+3]]
          c+=3
        elif word[c:c+4] in map:
          data = map[word[c:c+4]]
          c+=4
        else:
          nScore -= 200 #bad score
          c+= 1
          continue
          
        strString += data[0]
        nScore += 0.2 + data[1]*4
        
      if nScore > 0.1:
        aResults.append( (nScore, word, strString) )
  f.close()
  
  aResults.sort(key=operator.itemgetter(0))
  aResults.reverse()
  
  for res in aResults[0:5]:
    print res
  #For me, comes up with FACE0FF, EFFACED, DEFACED
  
main()

A Quicker Fox

Last week I gave myself a challenge. I wanted to write a phrase that used the letters from a-z, and to make it as short as possible (a pangram). As a challenge I did not use any help, the internet, or any program. After working for a while, I found some pretty good ones.

Why fold, just vex quick brazen gimp (29)
Why quick gimp just loved brazen FX (29)

Rhythm DJs fling vox, zap web quack (28)
why brazen DJ vex quick golf stamp (28)

I thought "rhythm" was very promising, but could never offset the repeated h. After much trial, I'm pretty sure you can't get shorter than 28 without using abbreviations like DJ.

After comparing with Wikipedia, I found that I had done pretty well. Using a Python program I wrote, I was able to find an even shorter one:
why klutz DJ FX vamp squib conger (27)

I see that I'll have to find a better way to get rid of my q. I'm done for now, but sometime I'll find shorter ones.

Wednesday, August 1, 2007

Drupal PHP Pages

Last year, I created a large Drupal website with many custom extensions. I thought of a good way to add custom pages. It wasn't finished in 30 minutes per se, but it's somewhat of a quick hack, and is very convenient and efficient (if you happen to use Drupal 5).

At the time, I loved Drupal, but slowly I became aware of its disadvantages. The whole system is built for ease of administration; efficiency is secondary. This means that even though it looks and works perfectly on a local test machine, in a real environment the number of database queries and heavy RAM usage will hit the server hard.

When a Drupal page loads it makes an extreme amount of database queries to retrieve configuration, layouts, and even the page you are viewing. To me, it doesn't make sense to hold all of this in a database - it is a needless query. Sure, this way makes it easier to edit your pages as an admin, but it introduces needless inefficiency querying the database and transferring data. Static pages should be files on the server.

My site had several custom pages that had a static structure. The pages had PHP that would look into the Drupal database information manually. At first, I made these Drupal "Pages," which can contain PHP code, but it is very inconvinient to edit PHP code in that little textarea. So, I told Drupal to redirect from certain urls to open a php file on the server. This way I would have the convenience of a nice URL, an easy-to-edit file, and one less database call.

I made the change to index.php, the page that serves all page requests. It should be clear where to merge this.
// Menu status constants are integers; page content is a string.
if (is_int($return)) {
  switch ($return) {
    case MENU_NOT_FOUND:
  
    if ( substr($_GET['q'],0,2) == 'p/')
    {
    //This is a modification by Ben.
    //The idea behind this was to simplify creating normal PHP pages. The URL looks more natural
    //Another benefit is that less database calls are required.
  global $pageargs,$user, $myuserrole;
  $pageurl = substr($_GET['q'], 2);
  $pageargs = explode('/', $pageurl);
  
  $myuserrole = theme_getuser_role($user->roles);
  $purl = '';
  switch ($pageargs[0])
  {
    case 'home': $purl = 'home.inc'; break;
    
    case '_page1': $purl = 'my/page1.inc'; break;
    case '_page2': $purl = 'my/page2.inc'; break;
  }
  if ($purl)
  {
    $content = file_get_contents('pages/'.$purl);
    print theme('page', drupal_eval($content));
   }
   else
   {
    drupal_not_found();
   }
   
   } 
    else
      drupal_not_found();
      break;
    case MENU_ACCESS_DENIED:
      drupal_access_denied();
      break;
    case MENU_SITE_OFFLINE:
      drupal_site_offline();
      break;
  }
}
I didn't have the pretty-urls option enabled, but this should work if is on. In this example, I'm mapping ?q=p/home to the file pages/home.inc. Note that I am not letting any file be opened - only the ones in the switch are accessible. Also, I used the .inc extension because I don't want the file to be accessed individually as a .php file. Nonetheless, any php code will be executed normally, thanks to the drupal_eval function. I store the $myuserrole and $pageargs variables in a global var because they will be useful in those pages.

Monday, July 30, 2007

Connection - A Google Suggest Game

A few days ago I was searching for a string method in Google. As soon as I had typed in "string", Google Suggest popped in with the following suggestions:

string cheese
string theory
string bikini

I was amused. Then I thought, what if there were a game where you had to go from cheese, theory, bikini back to "string"? After finding Google's convinient Suggest API, I wrote it in about 25 minutes. The game picks a common word and displays the suggest results - you have to find the connection between them. It's pretty fun. Here are some examples (find the missing word).

1)
***back machine
***ne state university
*** back into love lyrics
*** back into love
***ne rooney
*** back machine
***back
***ne gretzky
***nes world

2)
***s inn
***s of our lives
***s of our lives spoilers
***ton daily news
***tona beach
*** of the dead
***spring
***light savings time
***s inn hotels

3)
***** map
***** of warcraft
***** clock
***** time
***** war 2
***** weather
***** market
***** series of poker
***** bank

4)
**** zones
**** warner cable
**** warner
**** zone
**** magazine
**** out


Python Code:
I have some ideas for improvements, but this is the half-hour version.
You'll need a word list. The nouns in http://en.wikipedia.org/wiki/Most_common_words_in_English worked well.
Enter q to quit, or n for the next word if you give up.
# Works in Python 2.5, needs internet connection
import urllib
import re
import random

g_restr = re.compile('<suggestion data="([^"]+)"/>')
astrWords = 'fact,child,problem,part,hand,case'.split(',')
# Put another word list, separated by commas,into the above string.

def main():
    random.shuffle(astrWords)
    i =0
    while True:
        res = nextword(astrWords[i])
        if res == False: return
        i+=1
    
def nextword(strWord):
    strUrl = 'http://google.com/complete/search?output=toolbar&q=' + strWord
    f = urllib.urlopen(strUrl)
    strXml = f.read()
    f.close()
    
    strBlank = '*' * len(strWord)
    
    for match in g_restr.findall(strXml):
        print match.replace(strWord, strBlank)
    
    while True:
        strGuess = raw_input(':')
        if strGuess.lower() == strWord.lower():
            print 'Win!'
            return True
        if strGuess == 'q':
            print 'Exiting...'
            return False
        elif strGuess == 'n':
            print 'You gave up.'
            return True
main()
Answers to the examples are "way", "day", "world", and "time." Have fun!

Thursday, July 26, 2007

DHTML Pizza, cooked up in 30 Minutes

Here's an amusing piece of dhtml I put together a while ago (March 2006). I was experimenting with setTimeout callbacks.

The code is ugly, but the results are fun.

Pizza

If you run it in IE, you can click and re-form the pizza. It could stand some improvements, but I don't feel like working on it now. Don't take it too seriously.

Wednesday, July 25, 2007

Preview Webpage Links

Both "Open link in new Window" and "Open link in new tab" are very useful. They make my web surfing experience a LIFO stack. Where would I be without Shift-click and control-click?

However, there are other cases when you need other functionality. For example, many FAQ sites consist of several links to other pages. Or, you're lost in an extensive site map. When you don't know which link you want, it's slow to have to repeatedly open/close new tabs or windows, and especially slow to go back and forth between pages.

So, I wrote a javascript tidbit to redirect all links to open the page in one specific window. It's like "Open link in Window x" instead of "Open link in new window." (It changes the target attribute of the a tag).


javascript:var thehtml = document.body.innerHTML;thehtml = thehtml.replace(/href="([^"]+)"/gi,'href="$1" target="mynew"');document.write(thehtml);

Try it by going to a webpage with some links (like Wikipedia), copying the code, pasting it into the URL bar, and pressing Enter. It probably will make the page look ugly, but all the links will open in the same window, without you even having to press control or shift.

Below is a more fancy version of the same idea. It lets you "preview" the next webpage in an iframe, in the same window. Not pretty, but it's handy!


javascript:var thehtml = document.body.innerHTML;thehtml = thehtml.replace(/href="([^"]+)"/gi,'href="#" onclick="javascript:document.getElementById(\'ifff\').src=\'$1\';return false"');thehtml = '<div style="float:right; width:600px; height:600px"><iframe style="float:right" src ="'+window.location.href+'" id="ifff" width="100%" height="100%" ></iframe></div>' + thehtml;document.write(thehtml);

Tuesday, July 24, 2007

BidirectionalDictionary

Common C# problem: you need a two-way dictionary. In many cases you need to set up a 1-1 mapping. Say you have an enumeration where each value has a corresponding string, and you need to be able to go from the enum value to the string, and vice versa. Wouldn't it be nice if this were handled by one object?

So, today I wrote the BidirectionalDictionary. It wraps two dictionaries (yay generics!). It's not that full-featured, but I put it together in 30 minutes, and it's solid code.

I decided to still label a "key" and "value", because in most cases you are still thinking in terms of a Dictionary, just one you can "reverse" back to the key.

Sample Usage

BidirectionalDict<int, string> map = new BidirectionalDict<int, string>
(
 new int[] { 1, 2, 3, 4 },
 new string[] { "a", "b", "c", "d" }
);
// Wasn't that syntax beautiful? (Much better than .Add, .Add ...)

map.Add(5, "e");
Console.WriteLine(map[1]);
Console.WriteLine(map.ValueToKey("d"));

Dictionary<int, string> a = new Dictionary<int, string>();
foreach(int key in map.Keys())
 Console.WriteLine(key);

foreach (KeyValuePair<int, string> pair in map.Pairs())
 Console.WriteLine(pair.Key.ToString() + "," + pair.Value);

Inspired by Python, I also added a TryKeyToValue(key, defaultValue) that lets you specify a default value if the key is not in the dict.

Note that there might be a slight performance benefit because the dictionaries can be initialized with a length.

Code

class BidirectionalDict<typeKey, typeValue>
{
 private Dictionary<typeKey, typeValue> m_dictKeyToValue;
 private Dictionary<typeValue, typeKey> m_dictValueToKey;

 public BidirectionalDict(typeKey[] arKeys, typeValue[] arValues)
 {
  if (arKeys.Length != arValues.Length)
   throw new FormatException();

  int nLength = arKeys.Length;
  m_dictKeyToValue = new Dictionary<typeKey, typeValue>(nLength);
  m_dictValueToKey = new Dictionary<typeValue, typeKey>(nLength);

  for (int i = 0; i < nLength; i++)
  {
   m_dictKeyToValue.Add(arKeys[i], arValues[i]);
   m_dictValueToKey.Add(arValues[i], arKeys[i]);
  }
 }
 public BidirectionalDict(KeyValuePair<typeKey, typeValue>[] pairs)
 {
  int nLength = pairs.Length;
  m_dictKeyToValue = new Dictionary<typeKey, typeValue>(nLength);
  m_dictValueToKey = new Dictionary<typeValue, typeKey>(nLength);
  foreach (KeyValuePair<typeKey, typeValue> pair in pairs)
  {
   m_dictKeyToValue.Add(pair.Key, pair.Value);
   m_dictValueToKey.Add(pair.Value, pair.Key);
  }
 }
 public void Add(typeKey key, typeValue value)
 {
  m_dictKeyToValue.Add(key, value);
  m_dictValueToKey.Add(value, key);
 }

 public typeValue this[typeKey index]
 {
  get {return m_dictKeyToValue[index]; }
 }
 public typeKey ValueToKey(typeValue value)
 {
  return m_dictValueToKey[value];
 }
 public bool ContainsKey(typeKey key)
 {
  return m_dictKeyToValue.ContainsKey(key);
 }
 public bool ContainsValue(typeValue value)
 {
  return m_dictValueToKey.ContainsKey(value);
 }
 public typeValue TryKeyToValue(typeKey key, typeValue defaultValue)
 {
  typeValue result;
  return m_dictKeyToValue.TryGetValue(key, out result) ? result : defaultValue;
 }
 public typeKey TryValueToKey(typeValue value, typeKey defaultKey)
 {
  typeKey result;
  return m_dictValueToKey.TryGetValue(value, out result) ? result : defaultKey;
 }

 public IEnumerable<typeKey> Keys()
 {
  foreach (typeKey key in m_dictKeyToValue.Keys)
   yield return key;
 }
 public IEnumerable<typeValue> Values()
 {
  foreach (typeValue value in m_dictValueToKey.Keys)
   yield return value;
 }
 public IEnumerable<KeyValuePair<typeKey, typeValue>> Pairs()
 {
  foreach (KeyValuePair<typeKey, typeValue> pair in m_dictKeyToValue)
         yield return pair;
 }
}

Got to go! Comments and criticism welcome.

"Big" Recursion

I was thinking about recursion. The classic example of an elegant recursive algorithm is:

def factorial(n):
 if (n<=1):
  return 1
 else:
  return n * factorial(n-1)

This is an example of a function that calls itself, eventually returning the correct answer.

I thought, why stop at the function level? I want to have "bigger recursion" - how about a whole program that calls itself? Of course, this would be really impractical in terms of memory, but it sounded like fun.

The Hack: "Big" recursion

So, during my lunch at work, I put the following together. (C# 2.0)
If you run the program, it will compute a factorial for you... in a non-standard way.

static void Main(string[] args)
{
 if (args.Length == 0)
 {
  Console.WriteLine("Enter number:");
  string strNum = Console.ReadLine();
  int nInput = int.Parse(strNum);

  string strLoc = System.Reflection.Assembly.GetExecutingAssembly().Location;
  int nReturn = int.Parse(ExecuteAndWait(strLoc, (nInput).ToString()));
  Console.WriteLine("The answer is: "+ nReturn);
 }
 else
 {
  int nInput = int.Parse(args[0]);
  Recurse(nInput);
 }
}

private static void Recurse(int nInput)
{
 if (nInput <= 1)
  Console.Write("1");
 else
 {
  string strLoc = System.Reflection.Assembly.GetExecutingAssembly().Location;
  int nReturn = int.Parse(ExecuteAndWait(strLoc, (nInput - 1).ToString()));
  Console.Write(nInput * nReturn);
 }
}
By renaming variables and methods, this code could be obfuscated pretty nicely.
The ExecuteAndWait method runs an executable and redirects the stdout to a string. See http://forums.hostrocket.com/archive/index.php/t-15099.html.

Although this was fun, it wasn't extreme enough. I wanted something even bigger, more impractical, and more hacky. So, I invented "bigger" recursion. Have fun understanding what this next one does.

"Bigger" Recursion

(Warning: the following code will compile but is not guaranteed to work on your machine. It's extremely fragile, for reasons that should be clear. I used Visual Studio 2005, c# console app.)
Hint 1: The byte 0xE2 is not commonly found in C# executables.
Hint 2: If you change any line of code, it probably won't work.
Hint 3: this is my directory listing after I run the program and find the factorial of 5:
Bigger2.exe
Bigger3.exe
Bigger4.exe
Bigger5.exe
BiggerRecursion.exe
BiggerRecursion.pdb
BiggerRecursion.vshost.exe

using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.ComponentModel;
using System.IO;

namespace BigRecursion
{
 class Program
 {
  static volatile byte s_byteCurrent = 0xE2;
  static volatile byte s_byteBase = 0xE1;
  static void Main(string[] args)
  {
   if (s_byteCurrent == s_byteBase+1)
   {
    int nInput;
    Console.WriteLine("Enter number:");
    string strNum = Console.ReadLine();
    nInput = int.Parse(strNum);

    int nReturn = WriteIt((byte) (nInput + 220));
    Console.WriteLine("The answer is: " + nInput * nReturn);
   }
   else
   {
    Recurse(s_byteCurrent);
   }
  }
  private static void Recurse(byte byteCurrent)
  {
   int nCurrent = byteCurrent - 220;
   if (nCurrent <= 1)
       Console.Write("1");
   else
   {
    int nReturn = WriteIt(byteCurrent);
    Console.Write(nCurrent * nReturn);
   }
  }
  private static int WriteIt(byte byteCurrent)
  {
   int nCurrent = byteCurrent - 220;
   byte bNext = (byte) (nCurrent - 1 + 220);
   string strLoc = System.Reflection.Assembly.GetExecutingAssembly().Location;
   byte[] bExe = File.ReadAllBytes(strLoc);
   Debug.Assert(bExe.Length == 0x4000);
   bExe[0x1292] = bNext;

   string strLoc2 = (Path.GetDirectoryName(strLoc) + "\\Bigger" + nCurrent.ToString() + ".exe");

   File.WriteAllBytes(strLoc2, bExe);
   return int.Parse(ExecuteAndWait(strLoc2));
  }
  private static string ExecuteAndWait(string sFullApplicationPath)
  {
   string stdout = null;
   Process myProcess = new Process();
   try
   {
    myProcess.StartInfo.FileName = sFullApplicationPath;
    myProcess.StartInfo.Verb = "Open";
    //myProcess.StartInfo.Arguments = arguments;
    myProcess.StartInfo.CreateNoWindow = true;
    myProcess.StartInfo.UseShellExecute = false;
    myProcess.StartInfo.RedirectStandardOutput = true;
    myProcess.Start();
    stdout = myProcess.StandardOutput.ReadToEnd();
    myProcess.WaitForExit();
   }
   catch (Win32Exception e)
   {
    if (e.NativeErrorCode == 2) //ERROR_FILE_NOT_FOUND
    {
     throw new Exception(e.Message + ". Check the path: " + myProcess.StartInfo.FileName);
    }
    else if (e.NativeErrorCode == 5) //ERROR_ACCESS_DENIED
    {
     throw new Exception(e.Message + ". Access Denied. File " + myProcess.StartInfo.FileName + " could be in use.");
    }
   }
   return stdout;
  }
 }
}

Saturday, June 30, 2007

Hack 01 (Excel)

Let's discuss the classic spreadsheet program Excel.

The Hack: Magic Bidirectional Formulas

I've often thought it would be cool to have bidirectional formulas in Excel. For example, you should be able to set up a relationship between two cells such that one was three times the other value. You could edit *either* cell, and the other cell would update itself. There may be a built-in way to do this, but I'm not aware of it. I'll have to roll up my sleeves and write a macro.

The goal: Write an Excel macro to convert between minutes / seconds and seconds and vice versa...Converting both directions in the same cells...In thirty minutes or less.

I edited the Worksheet's code by right-clicking on Sheet1.

Add macro code to "Sheet1." I found a way to run code after the worksheet is changed, and to set the value of a certain cell. I'm using Office 2003, but the approach should be compatible with many versions. Click on the image to see the code.


The result: Here's an animated gif of it in action:

Running macros is a security risk, and so many people rightfully turn off macros in Office. But if you are writing your own macros, it's a good way to add productivity.

Another creative way I've used Excel:

Renaming Files

One of the best features of Excel is "pattern extension"; clicking in the lower-right corner of a cell and dragging downwards to fill the cells below it based on a pattern or sequence.

Say I have many files in a directory with different names. I want to assign each file a number. (I want to have 01.txt, 02.txt, 03.txt, and so on.) Here's my unorthodox approach:

In a command-line window, use dir /b to get a list of the files.
Copy this list into Excel. (By default, the way to copy from a command window is a little strange. Right-click, select all, drag the selection rect, and press Enter to copy). Create a new column for the resulting filenames by using the "pattern extension" feature mentioned earlier. For example, to have leading 0s, type the string '01 into the first cell, and '02 into the second cell. Select both cells, click in the lower-right corner of the selection, and drag downwards to fill the cells below.

Next, see the example and add more columns. I've included " because DOS doesn't otherwise take files with spaces in the filename. Again, the fill downwards is very useful.

Now, copy this and paste it into, well for this example, notepad.exe. You'll see many tab characters in the file. Copy one of them, go to Search/replace, and paste the tab character into the search: field. Replace all to removing all tabs. Look, we just created a batch file!

Save the batch file (with the .bat extension) and run it. Now your files are renamed. The same principle can be used in other applications. For example, let's say you have a list of urls to download: dfgdfg.tar.gz
dfgdfgsdf.tar.gz
dfgsdfdsdf.tar.gz
dfsdfsdfg.tar.gz

Assuming you didn't have a download manager, you could copy this list into a text editor and delimit by newlines. Then copy this data into an Excel sheet. Put wget before each of these, eliminate the tabs, and make a batch file. (There is a Windows version of wget).

This method is also good for general file renames, if you need to append onto the name or apply some time of transformation.

Random Information

To enter in formula-like symbols in a cell (like the string "=equals") when you're not trying to write a formula, type a single ' character to "quote" the contents of the cell as literal. Then you can have cells that display as "-> " and so on.

If you don't have your favorite programming language handy, you can use Excel's Data-> Text to Columns as a poor man's split().

In Excel 97 there is the classic flight simulator. That's right, it's probably the most ridiculous easter egg ever made. I've played it. Read more here: http://eeggs.com/items/718.html .

Favorite Keyboard Shortcuts

Alt+Shift+F1 Create new worksheet
Ctrl+Pg Up/Pg Down Switch between worksheets
Alt+O,H,R Rename current sheet
Alt+E,L Delete current sheet
   
Ctrl+Space Select Column
Shift+Space Select Row
   
F2 Edit cell contents
Ctrl+D Fill down (a favorite)
Ctrl+' Fill down and edit
   
Alt+= Formula summing above numbers
   
Ctrl+Shift+Plus Insert row/col
(If you have many cells selected when inserting a row, you create many rows at once).
Ctrl+Minus Delete row/col
   
Ctrl+& Add cell border
Ctrl+_ Remove border
   
Cell Properties Ctrl+1
General number format. Ctrl+Shift+`
Currency format Ctrl+Shift+$
Time format Ctrl+Shift+@
Number format, two places Ctrl+Shift+!