Initial import.
authorJoe Wreschnig <joe.wreschnig@gmail.com>
Tue, 12 Nov 2013 10:52:12 +0000 (11:52 +0100)
committerJoe Wreschnig <joe.wreschnig@gmail.com>
Tue, 12 Nov 2013 10:52:12 +0000 (11:52 +0100)
374 files changed:
LGPL-3 [new file with mode: 0644]
audio/hchord_a2.mp3 [new file with mode: 0644]
audio/hchord_a2.ogg [new file with mode: 0644]
audio/hchord_a2.wav [new file with mode: 0644]
audio/hchord_a3.mp3 [new file with mode: 0644]
audio/hchord_a3.ogg [new file with mode: 0644]
audio/hchord_a3.wav [new file with mode: 0644]
audio/hchord_a4.mp3 [new file with mode: 0644]
audio/hchord_a4.ogg [new file with mode: 0644]
audio/hchord_a4.wav [new file with mode: 0644]
audio/hchord_a5.mp3 [new file with mode: 0644]
audio/hchord_a5.ogg [new file with mode: 0644]
audio/hchord_a5.wav [new file with mode: 0644]
audio/hchord_a6.mp3 [new file with mode: 0644]
audio/hchord_a6.ogg [new file with mode: 0644]
audio/hchord_a6.wav [new file with mode: 0644]
audio/hchord_ab2.mp3 [new file with mode: 0644]
audio/hchord_ab2.ogg [new file with mode: 0644]
audio/hchord_ab2.wav [new file with mode: 0644]
audio/hchord_ab3.mp3 [new file with mode: 0644]
audio/hchord_ab3.ogg [new file with mode: 0644]
audio/hchord_ab3.wav [new file with mode: 0644]
audio/hchord_ab4.mp3 [new file with mode: 0644]
audio/hchord_ab4.ogg [new file with mode: 0644]
audio/hchord_ab4.wav [new file with mode: 0644]
audio/hchord_ab5.mp3 [new file with mode: 0644]
audio/hchord_ab5.ogg [new file with mode: 0644]
audio/hchord_ab5.wav [new file with mode: 0644]
audio/hchord_ab6.mp3 [new file with mode: 0644]
audio/hchord_ab6.ogg [new file with mode: 0644]
audio/hchord_ab6.wav [new file with mode: 0644]
audio/hchord_b2.mp3 [new file with mode: 0644]
audio/hchord_b2.ogg [new file with mode: 0644]
audio/hchord_b2.wav [new file with mode: 0644]
audio/hchord_b3.mp3 [new file with mode: 0644]
audio/hchord_b3.ogg [new file with mode: 0644]
audio/hchord_b3.wav [new file with mode: 0644]
audio/hchord_b4.mp3 [new file with mode: 0644]
audio/hchord_b4.ogg [new file with mode: 0644]
audio/hchord_b4.wav [new file with mode: 0644]
audio/hchord_b5.mp3 [new file with mode: 0644]
audio/hchord_b5.ogg [new file with mode: 0644]
audio/hchord_b5.wav [new file with mode: 0644]
audio/hchord_b6.mp3 [new file with mode: 0644]
audio/hchord_b6.ogg [new file with mode: 0644]
audio/hchord_b6.wav [new file with mode: 0644]
audio/hchord_bb2.mp3 [new file with mode: 0644]
audio/hchord_bb2.ogg [new file with mode: 0644]
audio/hchord_bb2.wav [new file with mode: 0644]
audio/hchord_bb3.mp3 [new file with mode: 0644]
audio/hchord_bb3.ogg [new file with mode: 0644]
audio/hchord_bb3.wav [new file with mode: 0644]
audio/hchord_bb4.mp3 [new file with mode: 0644]
audio/hchord_bb4.ogg [new file with mode: 0644]
audio/hchord_bb4.wav [new file with mode: 0644]
audio/hchord_bb5.mp3 [new file with mode: 0644]
audio/hchord_bb5.ogg [new file with mode: 0644]
audio/hchord_bb5.wav [new file with mode: 0644]
audio/hchord_bb6.mp3 [new file with mode: 0644]
audio/hchord_bb6.ogg [new file with mode: 0644]
audio/hchord_bb6.wav [new file with mode: 0644]
audio/hchord_c3.mp3 [new file with mode: 0644]
audio/hchord_c3.ogg [new file with mode: 0644]
audio/hchord_c3.wav [new file with mode: 0644]
audio/hchord_c4.mp3 [new file with mode: 0644]
audio/hchord_c4.ogg [new file with mode: 0644]
audio/hchord_c4.wav [new file with mode: 0644]
audio/hchord_c5.mp3 [new file with mode: 0644]
audio/hchord_c5.ogg [new file with mode: 0644]
audio/hchord_c5.wav [new file with mode: 0644]
audio/hchord_c6.mp3 [new file with mode: 0644]
audio/hchord_c6.ogg [new file with mode: 0644]
audio/hchord_c6.wav [new file with mode: 0644]
audio/hchord_c7.mp3 [new file with mode: 0644]
audio/hchord_c7.ogg [new file with mode: 0644]
audio/hchord_c7.wav [new file with mode: 0644]
audio/hchord_d3.mp3 [new file with mode: 0644]
audio/hchord_d3.ogg [new file with mode: 0644]
audio/hchord_d3.wav [new file with mode: 0644]
audio/hchord_d4.mp3 [new file with mode: 0644]
audio/hchord_d4.ogg [new file with mode: 0644]
audio/hchord_d4.wav [new file with mode: 0644]
audio/hchord_d5.mp3 [new file with mode: 0644]
audio/hchord_d5.ogg [new file with mode: 0644]
audio/hchord_d5.wav [new file with mode: 0644]
audio/hchord_d6.mp3 [new file with mode: 0644]
audio/hchord_d6.ogg [new file with mode: 0644]
audio/hchord_d6.wav [new file with mode: 0644]
audio/hchord_d7.mp3 [new file with mode: 0644]
audio/hchord_d7.ogg [new file with mode: 0644]
audio/hchord_d7.wav [new file with mode: 0644]
audio/hchord_db3.mp3 [new file with mode: 0644]
audio/hchord_db3.ogg [new file with mode: 0644]
audio/hchord_db3.wav [new file with mode: 0644]
audio/hchord_db4.mp3 [new file with mode: 0644]
audio/hchord_db4.ogg [new file with mode: 0644]
audio/hchord_db4.wav [new file with mode: 0644]
audio/hchord_db5.mp3 [new file with mode: 0644]
audio/hchord_db5.ogg [new file with mode: 0644]
audio/hchord_db5.wav [new file with mode: 0644]
audio/hchord_db6.mp3 [new file with mode: 0644]
audio/hchord_db6.ogg [new file with mode: 0644]
audio/hchord_db6.wav [new file with mode: 0644]
audio/hchord_db7.mp3 [new file with mode: 0644]
audio/hchord_db7.ogg [new file with mode: 0644]
audio/hchord_db7.wav [new file with mode: 0644]
audio/hchord_e3.mp3 [new file with mode: 0644]
audio/hchord_e3.ogg [new file with mode: 0644]
audio/hchord_e3.wav [new file with mode: 0644]
audio/hchord_e4.mp3 [new file with mode: 0644]
audio/hchord_e4.ogg [new file with mode: 0644]
audio/hchord_e4.wav [new file with mode: 0644]
audio/hchord_e5.mp3 [new file with mode: 0644]
audio/hchord_e5.ogg [new file with mode: 0644]
audio/hchord_e5.wav [new file with mode: 0644]
audio/hchord_e6.mp3 [new file with mode: 0644]
audio/hchord_e6.ogg [new file with mode: 0644]
audio/hchord_e6.wav [new file with mode: 0644]
audio/hchord_e7.mp3 [new file with mode: 0644]
audio/hchord_e7.ogg [new file with mode: 0644]
audio/hchord_e7.wav [new file with mode: 0644]
audio/hchord_eb3.mp3 [new file with mode: 0644]
audio/hchord_eb3.ogg [new file with mode: 0644]
audio/hchord_eb3.wav [new file with mode: 0644]
audio/hchord_eb4.mp3 [new file with mode: 0644]
audio/hchord_eb4.ogg [new file with mode: 0644]
audio/hchord_eb4.wav [new file with mode: 0644]
audio/hchord_eb5.mp3 [new file with mode: 0644]
audio/hchord_eb5.ogg [new file with mode: 0644]
audio/hchord_eb5.wav [new file with mode: 0644]
audio/hchord_eb6.mp3 [new file with mode: 0644]
audio/hchord_eb6.ogg [new file with mode: 0644]
audio/hchord_eb6.wav [new file with mode: 0644]
audio/hchord_eb7.mp3 [new file with mode: 0644]
audio/hchord_eb7.ogg [new file with mode: 0644]
audio/hchord_eb7.wav [new file with mode: 0644]
audio/hchord_f2.mp3 [new file with mode: 0644]
audio/hchord_f2.ogg [new file with mode: 0644]
audio/hchord_f2.wav [new file with mode: 0644]
audio/hchord_f3.mp3 [new file with mode: 0644]
audio/hchord_f3.ogg [new file with mode: 0644]
audio/hchord_f3.wav [new file with mode: 0644]
audio/hchord_f4.mp3 [new file with mode: 0644]
audio/hchord_f4.ogg [new file with mode: 0644]
audio/hchord_f4.wav [new file with mode: 0644]
audio/hchord_f5.mp3 [new file with mode: 0644]
audio/hchord_f5.ogg [new file with mode: 0644]
audio/hchord_f5.wav [new file with mode: 0644]
audio/hchord_f6.mp3 [new file with mode: 0644]
audio/hchord_f6.ogg [new file with mode: 0644]
audio/hchord_f6.wav [new file with mode: 0644]
audio/hchord_f7.mp3 [new file with mode: 0644]
audio/hchord_f7.ogg [new file with mode: 0644]
audio/hchord_f7.wav [new file with mode: 0644]
audio/hchord_g2.mp3 [new file with mode: 0644]
audio/hchord_g2.ogg [new file with mode: 0644]
audio/hchord_g2.wav [new file with mode: 0644]
audio/hchord_g3.mp3 [new file with mode: 0644]
audio/hchord_g3.ogg [new file with mode: 0644]
audio/hchord_g3.wav [new file with mode: 0644]
audio/hchord_g4.mp3 [new file with mode: 0644]
audio/hchord_g4.ogg [new file with mode: 0644]
audio/hchord_g4.wav [new file with mode: 0644]
audio/hchord_g5.mp3 [new file with mode: 0644]
audio/hchord_g5.ogg [new file with mode: 0644]
audio/hchord_g5.wav [new file with mode: 0644]
audio/hchord_g6.mp3 [new file with mode: 0644]
audio/hchord_g6.ogg [new file with mode: 0644]
audio/hchord_g6.wav [new file with mode: 0644]
audio/hchord_gb2.mp3 [new file with mode: 0644]
audio/hchord_gb2.ogg [new file with mode: 0644]
audio/hchord_gb2.wav [new file with mode: 0644]
audio/hchord_gb3.mp3 [new file with mode: 0644]
audio/hchord_gb3.ogg [new file with mode: 0644]
audio/hchord_gb3.wav [new file with mode: 0644]
audio/hchord_gb4.mp3 [new file with mode: 0644]
audio/hchord_gb4.ogg [new file with mode: 0644]
audio/hchord_gb4.wav [new file with mode: 0644]
audio/hchord_gb5.mp3 [new file with mode: 0644]
audio/hchord_gb5.ogg [new file with mode: 0644]
audio/hchord_gb5.wav [new file with mode: 0644]
audio/hchord_gb6.mp3 [new file with mode: 0644]
audio/hchord_gb6.ogg [new file with mode: 0644]
audio/hchord_gb6.wav [new file with mode: 0644]
audio/l_hchord_a2.mp3 [new file with mode: 0644]
audio/l_hchord_a2.ogg [new file with mode: 0644]
audio/l_hchord_a2.wav [new file with mode: 0644]
audio/l_hchord_a3.mp3 [new file with mode: 0644]
audio/l_hchord_a3.ogg [new file with mode: 0644]
audio/l_hchord_a3.wav [new file with mode: 0644]
audio/l_hchord_a4.mp3 [new file with mode: 0644]
audio/l_hchord_a4.ogg [new file with mode: 0644]
audio/l_hchord_a4.wav [new file with mode: 0644]
audio/l_hchord_a5.mp3 [new file with mode: 0644]
audio/l_hchord_a5.ogg [new file with mode: 0644]
audio/l_hchord_a5.wav [new file with mode: 0644]
audio/l_hchord_a6.mp3 [new file with mode: 0644]
audio/l_hchord_a6.ogg [new file with mode: 0644]
audio/l_hchord_a6.wav [new file with mode: 0644]
audio/l_hchord_ab2.mp3 [new file with mode: 0644]
audio/l_hchord_ab2.ogg [new file with mode: 0644]
audio/l_hchord_ab2.wav [new file with mode: 0644]
audio/l_hchord_ab3.mp3 [new file with mode: 0644]
audio/l_hchord_ab3.ogg [new file with mode: 0644]
audio/l_hchord_ab3.wav [new file with mode: 0644]
audio/l_hchord_ab4.mp3 [new file with mode: 0644]
audio/l_hchord_ab4.ogg [new file with mode: 0644]
audio/l_hchord_ab4.wav [new file with mode: 0644]
audio/l_hchord_ab5.mp3 [new file with mode: 0644]
audio/l_hchord_ab5.ogg [new file with mode: 0644]
audio/l_hchord_ab5.wav [new file with mode: 0644]
audio/l_hchord_ab6.mp3 [new file with mode: 0644]
audio/l_hchord_ab6.ogg [new file with mode: 0644]
audio/l_hchord_ab6.wav [new file with mode: 0644]
audio/l_hchord_b2.mp3 [new file with mode: 0644]
audio/l_hchord_b2.ogg [new file with mode: 0644]
audio/l_hchord_b2.wav [new file with mode: 0644]
audio/l_hchord_b3.mp3 [new file with mode: 0644]
audio/l_hchord_b3.ogg [new file with mode: 0644]
audio/l_hchord_b3.wav [new file with mode: 0644]
audio/l_hchord_b4.mp3 [new file with mode: 0644]
audio/l_hchord_b4.ogg [new file with mode: 0644]
audio/l_hchord_b4.wav [new file with mode: 0644]
audio/l_hchord_b5.mp3 [new file with mode: 0644]
audio/l_hchord_b5.ogg [new file with mode: 0644]
audio/l_hchord_b5.wav [new file with mode: 0644]
audio/l_hchord_b6.mp3 [new file with mode: 0644]
audio/l_hchord_b6.ogg [new file with mode: 0644]
audio/l_hchord_b6.wav [new file with mode: 0644]
audio/l_hchord_bb2.mp3 [new file with mode: 0644]
audio/l_hchord_bb2.ogg [new file with mode: 0644]
audio/l_hchord_bb2.wav [new file with mode: 0644]
audio/l_hchord_bb3.mp3 [new file with mode: 0644]
audio/l_hchord_bb3.ogg [new file with mode: 0644]
audio/l_hchord_bb3.wav [new file with mode: 0644]
audio/l_hchord_bb4.mp3 [new file with mode: 0644]
audio/l_hchord_bb4.ogg [new file with mode: 0644]
audio/l_hchord_bb4.wav [new file with mode: 0644]
audio/l_hchord_bb5.mp3 [new file with mode: 0644]
audio/l_hchord_bb5.ogg [new file with mode: 0644]
audio/l_hchord_bb5.wav [new file with mode: 0644]
audio/l_hchord_bb6.mp3 [new file with mode: 0644]
audio/l_hchord_bb6.ogg [new file with mode: 0644]
audio/l_hchord_bb6.wav [new file with mode: 0644]
audio/l_hchord_c3.mp3 [new file with mode: 0644]
audio/l_hchord_c3.ogg [new file with mode: 0644]
audio/l_hchord_c3.wav [new file with mode: 0644]
audio/l_hchord_c4.mp3 [new file with mode: 0644]
audio/l_hchord_c4.ogg [new file with mode: 0644]
audio/l_hchord_c4.wav [new file with mode: 0644]
audio/l_hchord_c5.mp3 [new file with mode: 0644]
audio/l_hchord_c5.ogg [new file with mode: 0644]
audio/l_hchord_c5.wav [new file with mode: 0644]
audio/l_hchord_c6.mp3 [new file with mode: 0644]
audio/l_hchord_c6.ogg [new file with mode: 0644]
audio/l_hchord_c6.wav [new file with mode: 0644]
audio/l_hchord_c7.mp3 [new file with mode: 0644]
audio/l_hchord_c7.ogg [new file with mode: 0644]
audio/l_hchord_c7.wav [new file with mode: 0644]
audio/l_hchord_d3.mp3 [new file with mode: 0644]
audio/l_hchord_d3.ogg [new file with mode: 0644]
audio/l_hchord_d3.wav [new file with mode: 0644]
audio/l_hchord_d4.mp3 [new file with mode: 0644]
audio/l_hchord_d4.ogg [new file with mode: 0644]
audio/l_hchord_d4.wav [new file with mode: 0644]
audio/l_hchord_d5.mp3 [new file with mode: 0644]
audio/l_hchord_d5.ogg [new file with mode: 0644]
audio/l_hchord_d5.wav [new file with mode: 0644]
audio/l_hchord_d6.mp3 [new file with mode: 0644]
audio/l_hchord_d6.ogg [new file with mode: 0644]
audio/l_hchord_d6.wav [new file with mode: 0644]
audio/l_hchord_d7.mp3 [new file with mode: 0644]
audio/l_hchord_d7.ogg [new file with mode: 0644]
audio/l_hchord_d7.wav [new file with mode: 0644]
audio/l_hchord_db3.mp3 [new file with mode: 0644]
audio/l_hchord_db3.ogg [new file with mode: 0644]
audio/l_hchord_db3.wav [new file with mode: 0644]
audio/l_hchord_db4.mp3 [new file with mode: 0644]
audio/l_hchord_db4.ogg [new file with mode: 0644]
audio/l_hchord_db4.wav [new file with mode: 0644]
audio/l_hchord_db5.mp3 [new file with mode: 0644]
audio/l_hchord_db5.ogg [new file with mode: 0644]
audio/l_hchord_db5.wav [new file with mode: 0644]
audio/l_hchord_db6.mp3 [new file with mode: 0644]
audio/l_hchord_db6.ogg [new file with mode: 0644]
audio/l_hchord_db6.wav [new file with mode: 0644]
audio/l_hchord_db7.mp3 [new file with mode: 0644]
audio/l_hchord_db7.ogg [new file with mode: 0644]
audio/l_hchord_db7.wav [new file with mode: 0644]
audio/l_hchord_e3.mp3 [new file with mode: 0644]
audio/l_hchord_e3.ogg [new file with mode: 0644]
audio/l_hchord_e3.wav [new file with mode: 0644]
audio/l_hchord_e4.mp3 [new file with mode: 0644]
audio/l_hchord_e4.ogg [new file with mode: 0644]
audio/l_hchord_e4.wav [new file with mode: 0644]
audio/l_hchord_e5.mp3 [new file with mode: 0644]
audio/l_hchord_e5.ogg [new file with mode: 0644]
audio/l_hchord_e5.wav [new file with mode: 0644]
audio/l_hchord_e6.mp3 [new file with mode: 0644]
audio/l_hchord_e6.ogg [new file with mode: 0644]
audio/l_hchord_e6.wav [new file with mode: 0644]
audio/l_hchord_e7.mp3 [new file with mode: 0644]
audio/l_hchord_e7.ogg [new file with mode: 0644]
audio/l_hchord_e7.wav [new file with mode: 0644]
audio/l_hchord_eb3.mp3 [new file with mode: 0644]
audio/l_hchord_eb3.ogg [new file with mode: 0644]
audio/l_hchord_eb3.wav [new file with mode: 0644]
audio/l_hchord_eb4.mp3 [new file with mode: 0644]
audio/l_hchord_eb4.ogg [new file with mode: 0644]
audio/l_hchord_eb4.wav [new file with mode: 0644]
audio/l_hchord_eb5.mp3 [new file with mode: 0644]
audio/l_hchord_eb5.ogg [new file with mode: 0644]
audio/l_hchord_eb5.wav [new file with mode: 0644]
audio/l_hchord_eb6.mp3 [new file with mode: 0644]
audio/l_hchord_eb6.ogg [new file with mode: 0644]
audio/l_hchord_eb6.wav [new file with mode: 0644]
audio/l_hchord_eb7.mp3 [new file with mode: 0644]
audio/l_hchord_eb7.ogg [new file with mode: 0644]
audio/l_hchord_eb7.wav [new file with mode: 0644]
audio/l_hchord_f2.mp3 [new file with mode: 0644]
audio/l_hchord_f2.ogg [new file with mode: 0644]
audio/l_hchord_f2.wav [new file with mode: 0644]
audio/l_hchord_f3.mp3 [new file with mode: 0644]
audio/l_hchord_f3.ogg [new file with mode: 0644]
audio/l_hchord_f3.wav [new file with mode: 0644]
audio/l_hchord_f4.mp3 [new file with mode: 0644]
audio/l_hchord_f4.ogg [new file with mode: 0644]
audio/l_hchord_f4.wav [new file with mode: 0644]
audio/l_hchord_f5.mp3 [new file with mode: 0644]
audio/l_hchord_f5.ogg [new file with mode: 0644]
audio/l_hchord_f5.wav [new file with mode: 0644]
audio/l_hchord_f6.mp3 [new file with mode: 0644]
audio/l_hchord_f6.ogg [new file with mode: 0644]
audio/l_hchord_f6.wav [new file with mode: 0644]
audio/l_hchord_f7.mp3 [new file with mode: 0644]
audio/l_hchord_f7.ogg [new file with mode: 0644]
audio/l_hchord_f7.wav [new file with mode: 0644]
audio/l_hchord_g2.mp3 [new file with mode: 0644]
audio/l_hchord_g2.ogg [new file with mode: 0644]
audio/l_hchord_g2.wav [new file with mode: 0644]
audio/l_hchord_g3.mp3 [new file with mode: 0644]
audio/l_hchord_g3.ogg [new file with mode: 0644]
audio/l_hchord_g3.wav [new file with mode: 0644]
audio/l_hchord_g4.mp3 [new file with mode: 0644]
audio/l_hchord_g4.ogg [new file with mode: 0644]
audio/l_hchord_g4.wav [new file with mode: 0644]
audio/l_hchord_g5.mp3 [new file with mode: 0644]
audio/l_hchord_g5.ogg [new file with mode: 0644]
audio/l_hchord_g5.wav [new file with mode: 0644]
audio/l_hchord_g6.mp3 [new file with mode: 0644]
audio/l_hchord_g6.ogg [new file with mode: 0644]
audio/l_hchord_g6.wav [new file with mode: 0644]
audio/l_hchord_gb2.mp3 [new file with mode: 0644]
audio/l_hchord_gb2.ogg [new file with mode: 0644]
audio/l_hchord_gb2.wav [new file with mode: 0644]
audio/l_hchord_gb3.mp3 [new file with mode: 0644]
audio/l_hchord_gb3.ogg [new file with mode: 0644]
audio/l_hchord_gb3.wav [new file with mode: 0644]
audio/l_hchord_gb4.mp3 [new file with mode: 0644]
audio/l_hchord_gb4.ogg [new file with mode: 0644]
audio/l_hchord_gb4.wav [new file with mode: 0644]
audio/l_hchord_gb5.mp3 [new file with mode: 0644]
audio/l_hchord_gb5.ogg [new file with mode: 0644]
audio/l_hchord_gb5.wav [new file with mode: 0644]
audio/l_hchord_gb6.mp3 [new file with mode: 0644]
audio/l_hchord_gb6.ogg [new file with mode: 0644]
audio/l_hchord_gb6.wav [new file with mode: 0644]
game-noaudio.html [new file with mode: 0644]
game.css [new file with mode: 0644]
game.html [new file with mode: 0644]
game.js [new file with mode: 0644]
noaudio.js [new file with mode: 0644]
ps.css [new file with mode: 0644]
ps2.1.js [new file with mode: 0644]

diff --git a/LGPL-3 b/LGPL-3
new file mode 100644 (file)
index 0000000..65c5ca8
--- /dev/null
+++ b/LGPL-3
@@ -0,0 +1,165 @@
+                   GNU LESSER GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+  This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+  0. Additional Definitions.
+
+  As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+  "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+  An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+  A "Combined Work" is a work produced by combining or linking an
+Application with the Library.  The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+  The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+  The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+  1. Exception to Section 3 of the GNU GPL.
+
+  You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+  2. Conveying Modified Versions.
+
+  If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+   a) under this License, provided that you make a good faith effort to
+   ensure that, in the event an Application does not supply the
+   function or data, the facility still operates, and performs
+   whatever part of its purpose remains meaningful, or
+
+   b) under the GNU GPL, with none of the additional permissions of
+   this License applicable to that copy.
+
+  3. Object Code Incorporating Material from Library Header Files.
+
+  The object code form of an Application may incorporate material from
+a header file that is part of the Library.  You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+   a) Give prominent notice with each copy of the object code that the
+   Library is used in it and that the Library and its use are
+   covered by this License.
+
+   b) Accompany the object code with a copy of the GNU GPL and this license
+   document.
+
+  4. Combined Works.
+
+  You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+   a) Give prominent notice with each copy of the Combined Work that
+   the Library is used in it and that the Library and its use are
+   covered by this License.
+
+   b) Accompany the Combined Work with a copy of the GNU GPL and this license
+   document.
+
+   c) For a Combined Work that displays copyright notices during
+   execution, include the copyright notice for the Library among
+   these notices, as well as a reference directing the user to the
+   copies of the GNU GPL and this license document.
+
+   d) Do one of the following:
+
+       0) Convey the Minimal Corresponding Source under the terms of this
+       License, and the Corresponding Application Code in a form
+       suitable for, and under terms that permit, the user to
+       recombine or relink the Application with a modified version of
+       the Linked Version to produce a modified Combined Work, in the
+       manner specified by section 6 of the GNU GPL for conveying
+       Corresponding Source.
+
+       1) Use a suitable shared library mechanism for linking with the
+       Library.  A suitable mechanism is one that (a) uses at run time
+       a copy of the Library already present on the user's computer
+       system, and (b) will operate properly with a modified version
+       of the Library that is interface-compatible with the Linked
+       Version.
+
+   e) Provide Installation Information, but only if you would otherwise
+   be required to provide such information under section 6 of the
+   GNU GPL, and only to the extent that such information is
+   necessary to install and execute a modified version of the
+   Combined Work produced by recombining or relinking the
+   Application with a modified version of the Linked Version. (If
+   you use option 4d0, the Installation Information must accompany
+   the Minimal Corresponding Source and Corresponding Application
+   Code. If you use option 4d1, you must provide the Installation
+   Information in the manner specified by section 6 of the GNU GPL
+   for conveying Corresponding Source.)
+
+  5. Combined Libraries.
+
+  You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+   a) Accompany the combined library with a copy of the same work based
+   on the Library, uncombined with any other library facilities,
+   conveyed under the terms of this License.
+
+   b) Give prominent notice with the combined library that part of it
+   is a work based on the Library, and explaining where to find the
+   accompanying uncombined form of the same work.
+
+  6. Revised Versions of the GNU Lesser General Public License.
+
+  The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+  Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+  If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
diff --git a/audio/hchord_a2.mp3 b/audio/hchord_a2.mp3
new file mode 100644 (file)
index 0000000..1699b1e
Binary files /dev/null and b/audio/hchord_a2.mp3 differ
diff --git a/audio/hchord_a2.ogg b/audio/hchord_a2.ogg
new file mode 100644 (file)
index 0000000..65ab0b4
Binary files /dev/null and b/audio/hchord_a2.ogg differ
diff --git a/audio/hchord_a2.wav b/audio/hchord_a2.wav
new file mode 100644 (file)
index 0000000..4c05fe4
Binary files /dev/null and b/audio/hchord_a2.wav differ
diff --git a/audio/hchord_a3.mp3 b/audio/hchord_a3.mp3
new file mode 100644 (file)
index 0000000..f0a7742
Binary files /dev/null and b/audio/hchord_a3.mp3 differ
diff --git a/audio/hchord_a3.ogg b/audio/hchord_a3.ogg
new file mode 100644 (file)
index 0000000..477377a
Binary files /dev/null and b/audio/hchord_a3.ogg differ
diff --git a/audio/hchord_a3.wav b/audio/hchord_a3.wav
new file mode 100644 (file)
index 0000000..30533b1
Binary files /dev/null and b/audio/hchord_a3.wav differ
diff --git a/audio/hchord_a4.mp3 b/audio/hchord_a4.mp3
new file mode 100644 (file)
index 0000000..ffa9193
Binary files /dev/null and b/audio/hchord_a4.mp3 differ
diff --git a/audio/hchord_a4.ogg b/audio/hchord_a4.ogg
new file mode 100644 (file)
index 0000000..015a5ce
Binary files /dev/null and b/audio/hchord_a4.ogg differ
diff --git a/audio/hchord_a4.wav b/audio/hchord_a4.wav
new file mode 100644 (file)
index 0000000..4fa3963
Binary files /dev/null and b/audio/hchord_a4.wav differ
diff --git a/audio/hchord_a5.mp3 b/audio/hchord_a5.mp3
new file mode 100644 (file)
index 0000000..d696b14
Binary files /dev/null and b/audio/hchord_a5.mp3 differ
diff --git a/audio/hchord_a5.ogg b/audio/hchord_a5.ogg
new file mode 100644 (file)
index 0000000..ac7bf3e
Binary files /dev/null and b/audio/hchord_a5.ogg differ
diff --git a/audio/hchord_a5.wav b/audio/hchord_a5.wav
new file mode 100644 (file)
index 0000000..fca2572
Binary files /dev/null and b/audio/hchord_a5.wav differ
diff --git a/audio/hchord_a6.mp3 b/audio/hchord_a6.mp3
new file mode 100644 (file)
index 0000000..8702646
Binary files /dev/null and b/audio/hchord_a6.mp3 differ
diff --git a/audio/hchord_a6.ogg b/audio/hchord_a6.ogg
new file mode 100644 (file)
index 0000000..0870c03
Binary files /dev/null and b/audio/hchord_a6.ogg differ
diff --git a/audio/hchord_a6.wav b/audio/hchord_a6.wav
new file mode 100644 (file)
index 0000000..617d0e5
Binary files /dev/null and b/audio/hchord_a6.wav differ
diff --git a/audio/hchord_ab2.mp3 b/audio/hchord_ab2.mp3
new file mode 100644 (file)
index 0000000..b2c5e6e
Binary files /dev/null and b/audio/hchord_ab2.mp3 differ
diff --git a/audio/hchord_ab2.ogg b/audio/hchord_ab2.ogg
new file mode 100644 (file)
index 0000000..097a187
Binary files /dev/null and b/audio/hchord_ab2.ogg differ
diff --git a/audio/hchord_ab2.wav b/audio/hchord_ab2.wav
new file mode 100644 (file)
index 0000000..3347e12
Binary files /dev/null and b/audio/hchord_ab2.wav differ
diff --git a/audio/hchord_ab3.mp3 b/audio/hchord_ab3.mp3
new file mode 100644 (file)
index 0000000..145f751
Binary files /dev/null and b/audio/hchord_ab3.mp3 differ
diff --git a/audio/hchord_ab3.ogg b/audio/hchord_ab3.ogg
new file mode 100644 (file)
index 0000000..7d913f0
Binary files /dev/null and b/audio/hchord_ab3.ogg differ
diff --git a/audio/hchord_ab3.wav b/audio/hchord_ab3.wav
new file mode 100644 (file)
index 0000000..689d11b
Binary files /dev/null and b/audio/hchord_ab3.wav differ
diff --git a/audio/hchord_ab4.mp3 b/audio/hchord_ab4.mp3
new file mode 100644 (file)
index 0000000..3f1fa8b
Binary files /dev/null and b/audio/hchord_ab4.mp3 differ
diff --git a/audio/hchord_ab4.ogg b/audio/hchord_ab4.ogg
new file mode 100644 (file)
index 0000000..c06b962
Binary files /dev/null and b/audio/hchord_ab4.ogg differ
diff --git a/audio/hchord_ab4.wav b/audio/hchord_ab4.wav
new file mode 100644 (file)
index 0000000..68e79d4
Binary files /dev/null and b/audio/hchord_ab4.wav differ
diff --git a/audio/hchord_ab5.mp3 b/audio/hchord_ab5.mp3
new file mode 100644 (file)
index 0000000..f87bab9
Binary files /dev/null and b/audio/hchord_ab5.mp3 differ
diff --git a/audio/hchord_ab5.ogg b/audio/hchord_ab5.ogg
new file mode 100644 (file)
index 0000000..c5787a9
Binary files /dev/null and b/audio/hchord_ab5.ogg differ
diff --git a/audio/hchord_ab5.wav b/audio/hchord_ab5.wav
new file mode 100644 (file)
index 0000000..d0f99b2
Binary files /dev/null and b/audio/hchord_ab5.wav differ
diff --git a/audio/hchord_ab6.mp3 b/audio/hchord_ab6.mp3
new file mode 100644 (file)
index 0000000..aa15858
Binary files /dev/null and b/audio/hchord_ab6.mp3 differ
diff --git a/audio/hchord_ab6.ogg b/audio/hchord_ab6.ogg
new file mode 100644 (file)
index 0000000..1c1ed1f
Binary files /dev/null and b/audio/hchord_ab6.ogg differ
diff --git a/audio/hchord_ab6.wav b/audio/hchord_ab6.wav
new file mode 100644 (file)
index 0000000..a2de7ec
Binary files /dev/null and b/audio/hchord_ab6.wav differ
diff --git a/audio/hchord_b2.mp3 b/audio/hchord_b2.mp3
new file mode 100644 (file)
index 0000000..aa20235
Binary files /dev/null and b/audio/hchord_b2.mp3 differ
diff --git a/audio/hchord_b2.ogg b/audio/hchord_b2.ogg
new file mode 100644 (file)
index 0000000..160d525
Binary files /dev/null and b/audio/hchord_b2.ogg differ
diff --git a/audio/hchord_b2.wav b/audio/hchord_b2.wav
new file mode 100644 (file)
index 0000000..800669b
Binary files /dev/null and b/audio/hchord_b2.wav differ
diff --git a/audio/hchord_b3.mp3 b/audio/hchord_b3.mp3
new file mode 100644 (file)
index 0000000..2f50cc9
Binary files /dev/null and b/audio/hchord_b3.mp3 differ
diff --git a/audio/hchord_b3.ogg b/audio/hchord_b3.ogg
new file mode 100644 (file)
index 0000000..ec2f7a5
Binary files /dev/null and b/audio/hchord_b3.ogg differ
diff --git a/audio/hchord_b3.wav b/audio/hchord_b3.wav
new file mode 100644 (file)
index 0000000..ac4b8bf
Binary files /dev/null and b/audio/hchord_b3.wav differ
diff --git a/audio/hchord_b4.mp3 b/audio/hchord_b4.mp3
new file mode 100644 (file)
index 0000000..c0595b5
Binary files /dev/null and b/audio/hchord_b4.mp3 differ
diff --git a/audio/hchord_b4.ogg b/audio/hchord_b4.ogg
new file mode 100644 (file)
index 0000000..9905ad3
Binary files /dev/null and b/audio/hchord_b4.ogg differ
diff --git a/audio/hchord_b4.wav b/audio/hchord_b4.wav
new file mode 100644 (file)
index 0000000..2db7fb6
Binary files /dev/null and b/audio/hchord_b4.wav differ
diff --git a/audio/hchord_b5.mp3 b/audio/hchord_b5.mp3
new file mode 100644 (file)
index 0000000..53157b1
Binary files /dev/null and b/audio/hchord_b5.mp3 differ
diff --git a/audio/hchord_b5.ogg b/audio/hchord_b5.ogg
new file mode 100644 (file)
index 0000000..6ab0eeb
Binary files /dev/null and b/audio/hchord_b5.ogg differ
diff --git a/audio/hchord_b5.wav b/audio/hchord_b5.wav
new file mode 100644 (file)
index 0000000..5fb61ef
Binary files /dev/null and b/audio/hchord_b5.wav differ
diff --git a/audio/hchord_b6.mp3 b/audio/hchord_b6.mp3
new file mode 100644 (file)
index 0000000..adf37fc
Binary files /dev/null and b/audio/hchord_b6.mp3 differ
diff --git a/audio/hchord_b6.ogg b/audio/hchord_b6.ogg
new file mode 100644 (file)
index 0000000..15af14f
Binary files /dev/null and b/audio/hchord_b6.ogg differ
diff --git a/audio/hchord_b6.wav b/audio/hchord_b6.wav
new file mode 100644 (file)
index 0000000..7be0d88
Binary files /dev/null and b/audio/hchord_b6.wav differ
diff --git a/audio/hchord_bb2.mp3 b/audio/hchord_bb2.mp3
new file mode 100644 (file)
index 0000000..61ea964
Binary files /dev/null and b/audio/hchord_bb2.mp3 differ
diff --git a/audio/hchord_bb2.ogg b/audio/hchord_bb2.ogg
new file mode 100644 (file)
index 0000000..c740527
Binary files /dev/null and b/audio/hchord_bb2.ogg differ
diff --git a/audio/hchord_bb2.wav b/audio/hchord_bb2.wav
new file mode 100644 (file)
index 0000000..34d7182
Binary files /dev/null and b/audio/hchord_bb2.wav differ
diff --git a/audio/hchord_bb3.mp3 b/audio/hchord_bb3.mp3
new file mode 100644 (file)
index 0000000..4061cca
Binary files /dev/null and b/audio/hchord_bb3.mp3 differ
diff --git a/audio/hchord_bb3.ogg b/audio/hchord_bb3.ogg
new file mode 100644 (file)
index 0000000..3e54a55
Binary files /dev/null and b/audio/hchord_bb3.ogg differ
diff --git a/audio/hchord_bb3.wav b/audio/hchord_bb3.wav
new file mode 100644 (file)
index 0000000..f830db6
Binary files /dev/null and b/audio/hchord_bb3.wav differ
diff --git a/audio/hchord_bb4.mp3 b/audio/hchord_bb4.mp3
new file mode 100644 (file)
index 0000000..d4d6b35
Binary files /dev/null and b/audio/hchord_bb4.mp3 differ
diff --git a/audio/hchord_bb4.ogg b/audio/hchord_bb4.ogg
new file mode 100644 (file)
index 0000000..e7b2199
Binary files /dev/null and b/audio/hchord_bb4.ogg differ
diff --git a/audio/hchord_bb4.wav b/audio/hchord_bb4.wav
new file mode 100644 (file)
index 0000000..4d5fb02
Binary files /dev/null and b/audio/hchord_bb4.wav differ
diff --git a/audio/hchord_bb5.mp3 b/audio/hchord_bb5.mp3
new file mode 100644 (file)
index 0000000..7a1d089
Binary files /dev/null and b/audio/hchord_bb5.mp3 differ
diff --git a/audio/hchord_bb5.ogg b/audio/hchord_bb5.ogg
new file mode 100644 (file)
index 0000000..178e810
Binary files /dev/null and b/audio/hchord_bb5.ogg differ
diff --git a/audio/hchord_bb5.wav b/audio/hchord_bb5.wav
new file mode 100644 (file)
index 0000000..0e3a708
Binary files /dev/null and b/audio/hchord_bb5.wav differ
diff --git a/audio/hchord_bb6.mp3 b/audio/hchord_bb6.mp3
new file mode 100644 (file)
index 0000000..1691691
Binary files /dev/null and b/audio/hchord_bb6.mp3 differ
diff --git a/audio/hchord_bb6.ogg b/audio/hchord_bb6.ogg
new file mode 100644 (file)
index 0000000..bada194
Binary files /dev/null and b/audio/hchord_bb6.ogg differ
diff --git a/audio/hchord_bb6.wav b/audio/hchord_bb6.wav
new file mode 100644 (file)
index 0000000..ea260a6
Binary files /dev/null and b/audio/hchord_bb6.wav differ
diff --git a/audio/hchord_c3.mp3 b/audio/hchord_c3.mp3
new file mode 100644 (file)
index 0000000..8c22554
Binary files /dev/null and b/audio/hchord_c3.mp3 differ
diff --git a/audio/hchord_c3.ogg b/audio/hchord_c3.ogg
new file mode 100644 (file)
index 0000000..41728c2
Binary files /dev/null and b/audio/hchord_c3.ogg differ
diff --git a/audio/hchord_c3.wav b/audio/hchord_c3.wav
new file mode 100644 (file)
index 0000000..fc612fa
Binary files /dev/null and b/audio/hchord_c3.wav differ
diff --git a/audio/hchord_c4.mp3 b/audio/hchord_c4.mp3
new file mode 100644 (file)
index 0000000..9c4622c
Binary files /dev/null and b/audio/hchord_c4.mp3 differ
diff --git a/audio/hchord_c4.ogg b/audio/hchord_c4.ogg
new file mode 100644 (file)
index 0000000..eb70bae
Binary files /dev/null and b/audio/hchord_c4.ogg differ
diff --git a/audio/hchord_c4.wav b/audio/hchord_c4.wav
new file mode 100644 (file)
index 0000000..934ec43
Binary files /dev/null and b/audio/hchord_c4.wav differ
diff --git a/audio/hchord_c5.mp3 b/audio/hchord_c5.mp3
new file mode 100644 (file)
index 0000000..4e1f779
Binary files /dev/null and b/audio/hchord_c5.mp3 differ
diff --git a/audio/hchord_c5.ogg b/audio/hchord_c5.ogg
new file mode 100644 (file)
index 0000000..95bec6e
Binary files /dev/null and b/audio/hchord_c5.ogg differ
diff --git a/audio/hchord_c5.wav b/audio/hchord_c5.wav
new file mode 100644 (file)
index 0000000..df15da1
Binary files /dev/null and b/audio/hchord_c5.wav differ
diff --git a/audio/hchord_c6.mp3 b/audio/hchord_c6.mp3
new file mode 100644 (file)
index 0000000..f9dcb41
Binary files /dev/null and b/audio/hchord_c6.mp3 differ
diff --git a/audio/hchord_c6.ogg b/audio/hchord_c6.ogg
new file mode 100644 (file)
index 0000000..4f5f8fe
Binary files /dev/null and b/audio/hchord_c6.ogg differ
diff --git a/audio/hchord_c6.wav b/audio/hchord_c6.wav
new file mode 100644 (file)
index 0000000..d9249c4
Binary files /dev/null and b/audio/hchord_c6.wav differ
diff --git a/audio/hchord_c7.mp3 b/audio/hchord_c7.mp3
new file mode 100644 (file)
index 0000000..1f27384
Binary files /dev/null and b/audio/hchord_c7.mp3 differ
diff --git a/audio/hchord_c7.ogg b/audio/hchord_c7.ogg
new file mode 100644 (file)
index 0000000..af904e6
Binary files /dev/null and b/audio/hchord_c7.ogg differ
diff --git a/audio/hchord_c7.wav b/audio/hchord_c7.wav
new file mode 100644 (file)
index 0000000..9bac426
Binary files /dev/null and b/audio/hchord_c7.wav differ
diff --git a/audio/hchord_d3.mp3 b/audio/hchord_d3.mp3
new file mode 100644 (file)
index 0000000..f41a4c3
Binary files /dev/null and b/audio/hchord_d3.mp3 differ
diff --git a/audio/hchord_d3.ogg b/audio/hchord_d3.ogg
new file mode 100644 (file)
index 0000000..e55d469
Binary files /dev/null and b/audio/hchord_d3.ogg differ
diff --git a/audio/hchord_d3.wav b/audio/hchord_d3.wav
new file mode 100644 (file)
index 0000000..34d582e
Binary files /dev/null and b/audio/hchord_d3.wav differ
diff --git a/audio/hchord_d4.mp3 b/audio/hchord_d4.mp3
new file mode 100644 (file)
index 0000000..5dc8334
Binary files /dev/null and b/audio/hchord_d4.mp3 differ
diff --git a/audio/hchord_d4.ogg b/audio/hchord_d4.ogg
new file mode 100644 (file)
index 0000000..22e1846
Binary files /dev/null and b/audio/hchord_d4.ogg differ
diff --git a/audio/hchord_d4.wav b/audio/hchord_d4.wav
new file mode 100644 (file)
index 0000000..af84d07
Binary files /dev/null and b/audio/hchord_d4.wav differ
diff --git a/audio/hchord_d5.mp3 b/audio/hchord_d5.mp3
new file mode 100644 (file)
index 0000000..aabb048
Binary files /dev/null and b/audio/hchord_d5.mp3 differ
diff --git a/audio/hchord_d5.ogg b/audio/hchord_d5.ogg
new file mode 100644 (file)
index 0000000..39bea66
Binary files /dev/null and b/audio/hchord_d5.ogg differ
diff --git a/audio/hchord_d5.wav b/audio/hchord_d5.wav
new file mode 100644 (file)
index 0000000..7c43858
Binary files /dev/null and b/audio/hchord_d5.wav differ
diff --git a/audio/hchord_d6.mp3 b/audio/hchord_d6.mp3
new file mode 100644 (file)
index 0000000..00296d1
Binary files /dev/null and b/audio/hchord_d6.mp3 differ
diff --git a/audio/hchord_d6.ogg b/audio/hchord_d6.ogg
new file mode 100644 (file)
index 0000000..d8a3d19
Binary files /dev/null and b/audio/hchord_d6.ogg differ
diff --git a/audio/hchord_d6.wav b/audio/hchord_d6.wav
new file mode 100644 (file)
index 0000000..eda281a
Binary files /dev/null and b/audio/hchord_d6.wav differ
diff --git a/audio/hchord_d7.mp3 b/audio/hchord_d7.mp3
new file mode 100644 (file)
index 0000000..9916ed1
Binary files /dev/null and b/audio/hchord_d7.mp3 differ
diff --git a/audio/hchord_d7.ogg b/audio/hchord_d7.ogg
new file mode 100644 (file)
index 0000000..5b31bcf
Binary files /dev/null and b/audio/hchord_d7.ogg differ
diff --git a/audio/hchord_d7.wav b/audio/hchord_d7.wav
new file mode 100644 (file)
index 0000000..2a9d43e
Binary files /dev/null and b/audio/hchord_d7.wav differ
diff --git a/audio/hchord_db3.mp3 b/audio/hchord_db3.mp3
new file mode 100644 (file)
index 0000000..219f7d5
Binary files /dev/null and b/audio/hchord_db3.mp3 differ
diff --git a/audio/hchord_db3.ogg b/audio/hchord_db3.ogg
new file mode 100644 (file)
index 0000000..7ba8c92
Binary files /dev/null and b/audio/hchord_db3.ogg differ
diff --git a/audio/hchord_db3.wav b/audio/hchord_db3.wav
new file mode 100644 (file)
index 0000000..6967986
Binary files /dev/null and b/audio/hchord_db3.wav differ
diff --git a/audio/hchord_db4.mp3 b/audio/hchord_db4.mp3
new file mode 100644 (file)
index 0000000..a37b6e0
Binary files /dev/null and b/audio/hchord_db4.mp3 differ
diff --git a/audio/hchord_db4.ogg b/audio/hchord_db4.ogg
new file mode 100644 (file)
index 0000000..13eb0f3
Binary files /dev/null and b/audio/hchord_db4.ogg differ
diff --git a/audio/hchord_db4.wav b/audio/hchord_db4.wav
new file mode 100644 (file)
index 0000000..94f1275
Binary files /dev/null and b/audio/hchord_db4.wav differ
diff --git a/audio/hchord_db5.mp3 b/audio/hchord_db5.mp3
new file mode 100644 (file)
index 0000000..cfab75a
Binary files /dev/null and b/audio/hchord_db5.mp3 differ
diff --git a/audio/hchord_db5.ogg b/audio/hchord_db5.ogg
new file mode 100644 (file)
index 0000000..99eb152
Binary files /dev/null and b/audio/hchord_db5.ogg differ
diff --git a/audio/hchord_db5.wav b/audio/hchord_db5.wav
new file mode 100644 (file)
index 0000000..de6104b
Binary files /dev/null and b/audio/hchord_db5.wav differ
diff --git a/audio/hchord_db6.mp3 b/audio/hchord_db6.mp3
new file mode 100644 (file)
index 0000000..a3b0d69
Binary files /dev/null and b/audio/hchord_db6.mp3 differ
diff --git a/audio/hchord_db6.ogg b/audio/hchord_db6.ogg
new file mode 100644 (file)
index 0000000..f0aafb8
Binary files /dev/null and b/audio/hchord_db6.ogg differ
diff --git a/audio/hchord_db6.wav b/audio/hchord_db6.wav
new file mode 100644 (file)
index 0000000..c9d921a
Binary files /dev/null and b/audio/hchord_db6.wav differ
diff --git a/audio/hchord_db7.mp3 b/audio/hchord_db7.mp3
new file mode 100644 (file)
index 0000000..cd34047
Binary files /dev/null and b/audio/hchord_db7.mp3 differ
diff --git a/audio/hchord_db7.ogg b/audio/hchord_db7.ogg
new file mode 100644 (file)
index 0000000..875af11
Binary files /dev/null and b/audio/hchord_db7.ogg differ
diff --git a/audio/hchord_db7.wav b/audio/hchord_db7.wav
new file mode 100644 (file)
index 0000000..c63921a
Binary files /dev/null and b/audio/hchord_db7.wav differ
diff --git a/audio/hchord_e3.mp3 b/audio/hchord_e3.mp3
new file mode 100644 (file)
index 0000000..653015d
Binary files /dev/null and b/audio/hchord_e3.mp3 differ
diff --git a/audio/hchord_e3.ogg b/audio/hchord_e3.ogg
new file mode 100644 (file)
index 0000000..56d3327
Binary files /dev/null and b/audio/hchord_e3.ogg differ
diff --git a/audio/hchord_e3.wav b/audio/hchord_e3.wav
new file mode 100644 (file)
index 0000000..8703868
Binary files /dev/null and b/audio/hchord_e3.wav differ
diff --git a/audio/hchord_e4.mp3 b/audio/hchord_e4.mp3
new file mode 100644 (file)
index 0000000..1ba3e05
Binary files /dev/null and b/audio/hchord_e4.mp3 differ
diff --git a/audio/hchord_e4.ogg b/audio/hchord_e4.ogg
new file mode 100644 (file)
index 0000000..d446378
Binary files /dev/null and b/audio/hchord_e4.ogg differ
diff --git a/audio/hchord_e4.wav b/audio/hchord_e4.wav
new file mode 100644 (file)
index 0000000..948fa1b
Binary files /dev/null and b/audio/hchord_e4.wav differ
diff --git a/audio/hchord_e5.mp3 b/audio/hchord_e5.mp3
new file mode 100644 (file)
index 0000000..e274c68
Binary files /dev/null and b/audio/hchord_e5.mp3 differ
diff --git a/audio/hchord_e5.ogg b/audio/hchord_e5.ogg
new file mode 100644 (file)
index 0000000..d5afc44
Binary files /dev/null and b/audio/hchord_e5.ogg differ
diff --git a/audio/hchord_e5.wav b/audio/hchord_e5.wav
new file mode 100644 (file)
index 0000000..8b0c09d
Binary files /dev/null and b/audio/hchord_e5.wav differ
diff --git a/audio/hchord_e6.mp3 b/audio/hchord_e6.mp3
new file mode 100644 (file)
index 0000000..f46ec1c
Binary files /dev/null and b/audio/hchord_e6.mp3 differ
diff --git a/audio/hchord_e6.ogg b/audio/hchord_e6.ogg
new file mode 100644 (file)
index 0000000..161e8d8
Binary files /dev/null and b/audio/hchord_e6.ogg differ
diff --git a/audio/hchord_e6.wav b/audio/hchord_e6.wav
new file mode 100644 (file)
index 0000000..df9fd5d
Binary files /dev/null and b/audio/hchord_e6.wav differ
diff --git a/audio/hchord_e7.mp3 b/audio/hchord_e7.mp3
new file mode 100644 (file)
index 0000000..d77a29c
Binary files /dev/null and b/audio/hchord_e7.mp3 differ
diff --git a/audio/hchord_e7.ogg b/audio/hchord_e7.ogg
new file mode 100644 (file)
index 0000000..8f7c333
Binary files /dev/null and b/audio/hchord_e7.ogg differ
diff --git a/audio/hchord_e7.wav b/audio/hchord_e7.wav
new file mode 100644 (file)
index 0000000..7d647d9
Binary files /dev/null and b/audio/hchord_e7.wav differ
diff --git a/audio/hchord_eb3.mp3 b/audio/hchord_eb3.mp3
new file mode 100644 (file)
index 0000000..a1111a4
Binary files /dev/null and b/audio/hchord_eb3.mp3 differ
diff --git a/audio/hchord_eb3.ogg b/audio/hchord_eb3.ogg
new file mode 100644 (file)
index 0000000..187d3f0
Binary files /dev/null and b/audio/hchord_eb3.ogg differ
diff --git a/audio/hchord_eb3.wav b/audio/hchord_eb3.wav
new file mode 100644 (file)
index 0000000..90d41b6
Binary files /dev/null and b/audio/hchord_eb3.wav differ
diff --git a/audio/hchord_eb4.mp3 b/audio/hchord_eb4.mp3
new file mode 100644 (file)
index 0000000..cf7e0c2
Binary files /dev/null and b/audio/hchord_eb4.mp3 differ
diff --git a/audio/hchord_eb4.ogg b/audio/hchord_eb4.ogg
new file mode 100644 (file)
index 0000000..ae2a0f0
Binary files /dev/null and b/audio/hchord_eb4.ogg differ
diff --git a/audio/hchord_eb4.wav b/audio/hchord_eb4.wav
new file mode 100644 (file)
index 0000000..3520d68
Binary files /dev/null and b/audio/hchord_eb4.wav differ
diff --git a/audio/hchord_eb5.mp3 b/audio/hchord_eb5.mp3
new file mode 100644 (file)
index 0000000..50a23c0
Binary files /dev/null and b/audio/hchord_eb5.mp3 differ
diff --git a/audio/hchord_eb5.ogg b/audio/hchord_eb5.ogg
new file mode 100644 (file)
index 0000000..def6a93
Binary files /dev/null and b/audio/hchord_eb5.ogg differ
diff --git a/audio/hchord_eb5.wav b/audio/hchord_eb5.wav
new file mode 100644 (file)
index 0000000..7049347
Binary files /dev/null and b/audio/hchord_eb5.wav differ
diff --git a/audio/hchord_eb6.mp3 b/audio/hchord_eb6.mp3
new file mode 100644 (file)
index 0000000..649a181
Binary files /dev/null and b/audio/hchord_eb6.mp3 differ
diff --git a/audio/hchord_eb6.ogg b/audio/hchord_eb6.ogg
new file mode 100644 (file)
index 0000000..753dc88
Binary files /dev/null and b/audio/hchord_eb6.ogg differ
diff --git a/audio/hchord_eb6.wav b/audio/hchord_eb6.wav
new file mode 100644 (file)
index 0000000..532f146
Binary files /dev/null and b/audio/hchord_eb6.wav differ
diff --git a/audio/hchord_eb7.mp3 b/audio/hchord_eb7.mp3
new file mode 100644 (file)
index 0000000..ebd49ab
Binary files /dev/null and b/audio/hchord_eb7.mp3 differ
diff --git a/audio/hchord_eb7.ogg b/audio/hchord_eb7.ogg
new file mode 100644 (file)
index 0000000..6d94efd
Binary files /dev/null and b/audio/hchord_eb7.ogg differ
diff --git a/audio/hchord_eb7.wav b/audio/hchord_eb7.wav
new file mode 100644 (file)
index 0000000..da4df55
Binary files /dev/null and b/audio/hchord_eb7.wav differ
diff --git a/audio/hchord_f2.mp3 b/audio/hchord_f2.mp3
new file mode 100644 (file)
index 0000000..1ca1e26
Binary files /dev/null and b/audio/hchord_f2.mp3 differ
diff --git a/audio/hchord_f2.ogg b/audio/hchord_f2.ogg
new file mode 100644 (file)
index 0000000..a7be84e
Binary files /dev/null and b/audio/hchord_f2.ogg differ
diff --git a/audio/hchord_f2.wav b/audio/hchord_f2.wav
new file mode 100644 (file)
index 0000000..6a338c0
Binary files /dev/null and b/audio/hchord_f2.wav differ
diff --git a/audio/hchord_f3.mp3 b/audio/hchord_f3.mp3
new file mode 100644 (file)
index 0000000..901be93
Binary files /dev/null and b/audio/hchord_f3.mp3 differ
diff --git a/audio/hchord_f3.ogg b/audio/hchord_f3.ogg
new file mode 100644 (file)
index 0000000..49168cb
Binary files /dev/null and b/audio/hchord_f3.ogg differ
diff --git a/audio/hchord_f3.wav b/audio/hchord_f3.wav
new file mode 100644 (file)
index 0000000..e29bb56
Binary files /dev/null and b/audio/hchord_f3.wav differ
diff --git a/audio/hchord_f4.mp3 b/audio/hchord_f4.mp3
new file mode 100644 (file)
index 0000000..140e9b6
Binary files /dev/null and b/audio/hchord_f4.mp3 differ
diff --git a/audio/hchord_f4.ogg b/audio/hchord_f4.ogg
new file mode 100644 (file)
index 0000000..3af5e71
Binary files /dev/null and b/audio/hchord_f4.ogg differ
diff --git a/audio/hchord_f4.wav b/audio/hchord_f4.wav
new file mode 100644 (file)
index 0000000..d3ddbba
Binary files /dev/null and b/audio/hchord_f4.wav differ
diff --git a/audio/hchord_f5.mp3 b/audio/hchord_f5.mp3
new file mode 100644 (file)
index 0000000..6738f0b
Binary files /dev/null and b/audio/hchord_f5.mp3 differ
diff --git a/audio/hchord_f5.ogg b/audio/hchord_f5.ogg
new file mode 100644 (file)
index 0000000..583c6fc
Binary files /dev/null and b/audio/hchord_f5.ogg differ
diff --git a/audio/hchord_f5.wav b/audio/hchord_f5.wav
new file mode 100644 (file)
index 0000000..1f0f0de
Binary files /dev/null and b/audio/hchord_f5.wav differ
diff --git a/audio/hchord_f6.mp3 b/audio/hchord_f6.mp3
new file mode 100644 (file)
index 0000000..c72839f
Binary files /dev/null and b/audio/hchord_f6.mp3 differ
diff --git a/audio/hchord_f6.ogg b/audio/hchord_f6.ogg
new file mode 100644 (file)
index 0000000..cc6dc9f
Binary files /dev/null and b/audio/hchord_f6.ogg differ
diff --git a/audio/hchord_f6.wav b/audio/hchord_f6.wav
new file mode 100644 (file)
index 0000000..e67d402
Binary files /dev/null and b/audio/hchord_f6.wav differ
diff --git a/audio/hchord_f7.mp3 b/audio/hchord_f7.mp3
new file mode 100644 (file)
index 0000000..b31fb4c
Binary files /dev/null and b/audio/hchord_f7.mp3 differ
diff --git a/audio/hchord_f7.ogg b/audio/hchord_f7.ogg
new file mode 100644 (file)
index 0000000..2b9de4b
Binary files /dev/null and b/audio/hchord_f7.ogg differ
diff --git a/audio/hchord_f7.wav b/audio/hchord_f7.wav
new file mode 100644 (file)
index 0000000..15186d9
Binary files /dev/null and b/audio/hchord_f7.wav differ
diff --git a/audio/hchord_g2.mp3 b/audio/hchord_g2.mp3
new file mode 100644 (file)
index 0000000..ac86106
Binary files /dev/null and b/audio/hchord_g2.mp3 differ
diff --git a/audio/hchord_g2.ogg b/audio/hchord_g2.ogg
new file mode 100644 (file)
index 0000000..1d37a2b
Binary files /dev/null and b/audio/hchord_g2.ogg differ
diff --git a/audio/hchord_g2.wav b/audio/hchord_g2.wav
new file mode 100644 (file)
index 0000000..fa20562
Binary files /dev/null and b/audio/hchord_g2.wav differ
diff --git a/audio/hchord_g3.mp3 b/audio/hchord_g3.mp3
new file mode 100644 (file)
index 0000000..b1d34cf
Binary files /dev/null and b/audio/hchord_g3.mp3 differ
diff --git a/audio/hchord_g3.ogg b/audio/hchord_g3.ogg
new file mode 100644 (file)
index 0000000..8bf6372
Binary files /dev/null and b/audio/hchord_g3.ogg differ
diff --git a/audio/hchord_g3.wav b/audio/hchord_g3.wav
new file mode 100644 (file)
index 0000000..087de2a
Binary files /dev/null and b/audio/hchord_g3.wav differ
diff --git a/audio/hchord_g4.mp3 b/audio/hchord_g4.mp3
new file mode 100644 (file)
index 0000000..c03f73f
Binary files /dev/null and b/audio/hchord_g4.mp3 differ
diff --git a/audio/hchord_g4.ogg b/audio/hchord_g4.ogg
new file mode 100644 (file)
index 0000000..608909b
Binary files /dev/null and b/audio/hchord_g4.ogg differ
diff --git a/audio/hchord_g4.wav b/audio/hchord_g4.wav
new file mode 100644 (file)
index 0000000..d772db9
Binary files /dev/null and b/audio/hchord_g4.wav differ
diff --git a/audio/hchord_g5.mp3 b/audio/hchord_g5.mp3
new file mode 100644 (file)
index 0000000..5f63bf9
Binary files /dev/null and b/audio/hchord_g5.mp3 differ
diff --git a/audio/hchord_g5.ogg b/audio/hchord_g5.ogg
new file mode 100644 (file)
index 0000000..6ff6902
Binary files /dev/null and b/audio/hchord_g5.ogg differ
diff --git a/audio/hchord_g5.wav b/audio/hchord_g5.wav
new file mode 100644 (file)
index 0000000..2270d6d
Binary files /dev/null and b/audio/hchord_g5.wav differ
diff --git a/audio/hchord_g6.mp3 b/audio/hchord_g6.mp3
new file mode 100644 (file)
index 0000000..13c5881
Binary files /dev/null and b/audio/hchord_g6.mp3 differ
diff --git a/audio/hchord_g6.ogg b/audio/hchord_g6.ogg
new file mode 100644 (file)
index 0000000..684bad7
Binary files /dev/null and b/audio/hchord_g6.ogg differ
diff --git a/audio/hchord_g6.wav b/audio/hchord_g6.wav
new file mode 100644 (file)
index 0000000..e3c2df4
Binary files /dev/null and b/audio/hchord_g6.wav differ
diff --git a/audio/hchord_gb2.mp3 b/audio/hchord_gb2.mp3
new file mode 100644 (file)
index 0000000..b6cdc4a
Binary files /dev/null and b/audio/hchord_gb2.mp3 differ
diff --git a/audio/hchord_gb2.ogg b/audio/hchord_gb2.ogg
new file mode 100644 (file)
index 0000000..0a5414c
Binary files /dev/null and b/audio/hchord_gb2.ogg differ
diff --git a/audio/hchord_gb2.wav b/audio/hchord_gb2.wav
new file mode 100644 (file)
index 0000000..fc7963a
Binary files /dev/null and b/audio/hchord_gb2.wav differ
diff --git a/audio/hchord_gb3.mp3 b/audio/hchord_gb3.mp3
new file mode 100644 (file)
index 0000000..f61de08
Binary files /dev/null and b/audio/hchord_gb3.mp3 differ
diff --git a/audio/hchord_gb3.ogg b/audio/hchord_gb3.ogg
new file mode 100644 (file)
index 0000000..ae6a738
Binary files /dev/null and b/audio/hchord_gb3.ogg differ
diff --git a/audio/hchord_gb3.wav b/audio/hchord_gb3.wav
new file mode 100644 (file)
index 0000000..cee8c56
Binary files /dev/null and b/audio/hchord_gb3.wav differ
diff --git a/audio/hchord_gb4.mp3 b/audio/hchord_gb4.mp3
new file mode 100644 (file)
index 0000000..ab93823
Binary files /dev/null and b/audio/hchord_gb4.mp3 differ
diff --git a/audio/hchord_gb4.ogg b/audio/hchord_gb4.ogg
new file mode 100644 (file)
index 0000000..54e5c4b
Binary files /dev/null and b/audio/hchord_gb4.ogg differ
diff --git a/audio/hchord_gb4.wav b/audio/hchord_gb4.wav
new file mode 100644 (file)
index 0000000..a3823f3
Binary files /dev/null and b/audio/hchord_gb4.wav differ
diff --git a/audio/hchord_gb5.mp3 b/audio/hchord_gb5.mp3
new file mode 100644 (file)
index 0000000..d66d9f4
Binary files /dev/null and b/audio/hchord_gb5.mp3 differ
diff --git a/audio/hchord_gb5.ogg b/audio/hchord_gb5.ogg
new file mode 100644 (file)
index 0000000..8cbb372
Binary files /dev/null and b/audio/hchord_gb5.ogg differ
diff --git a/audio/hchord_gb5.wav b/audio/hchord_gb5.wav
new file mode 100644 (file)
index 0000000..b02af47
Binary files /dev/null and b/audio/hchord_gb5.wav differ
diff --git a/audio/hchord_gb6.mp3 b/audio/hchord_gb6.mp3
new file mode 100644 (file)
index 0000000..9f1fe17
Binary files /dev/null and b/audio/hchord_gb6.mp3 differ
diff --git a/audio/hchord_gb6.ogg b/audio/hchord_gb6.ogg
new file mode 100644 (file)
index 0000000..99d1d06
Binary files /dev/null and b/audio/hchord_gb6.ogg differ
diff --git a/audio/hchord_gb6.wav b/audio/hchord_gb6.wav
new file mode 100644 (file)
index 0000000..13aea1a
Binary files /dev/null and b/audio/hchord_gb6.wav differ
diff --git a/audio/l_hchord_a2.mp3 b/audio/l_hchord_a2.mp3
new file mode 100644 (file)
index 0000000..c7afe54
Binary files /dev/null and b/audio/l_hchord_a2.mp3 differ
diff --git a/audio/l_hchord_a2.ogg b/audio/l_hchord_a2.ogg
new file mode 100644 (file)
index 0000000..b1e762c
Binary files /dev/null and b/audio/l_hchord_a2.ogg differ
diff --git a/audio/l_hchord_a2.wav b/audio/l_hchord_a2.wav
new file mode 100644 (file)
index 0000000..dc32a23
Binary files /dev/null and b/audio/l_hchord_a2.wav differ
diff --git a/audio/l_hchord_a3.mp3 b/audio/l_hchord_a3.mp3
new file mode 100644 (file)
index 0000000..ca9385e
Binary files /dev/null and b/audio/l_hchord_a3.mp3 differ
diff --git a/audio/l_hchord_a3.ogg b/audio/l_hchord_a3.ogg
new file mode 100644 (file)
index 0000000..83720be
Binary files /dev/null and b/audio/l_hchord_a3.ogg differ
diff --git a/audio/l_hchord_a3.wav b/audio/l_hchord_a3.wav
new file mode 100644 (file)
index 0000000..7627d7c
Binary files /dev/null and b/audio/l_hchord_a3.wav differ
diff --git a/audio/l_hchord_a4.mp3 b/audio/l_hchord_a4.mp3
new file mode 100644 (file)
index 0000000..20e4440
Binary files /dev/null and b/audio/l_hchord_a4.mp3 differ
diff --git a/audio/l_hchord_a4.ogg b/audio/l_hchord_a4.ogg
new file mode 100644 (file)
index 0000000..9330b7f
Binary files /dev/null and b/audio/l_hchord_a4.ogg differ
diff --git a/audio/l_hchord_a4.wav b/audio/l_hchord_a4.wav
new file mode 100644 (file)
index 0000000..6d646a6
Binary files /dev/null and b/audio/l_hchord_a4.wav differ
diff --git a/audio/l_hchord_a5.mp3 b/audio/l_hchord_a5.mp3
new file mode 100644 (file)
index 0000000..fb0a47e
Binary files /dev/null and b/audio/l_hchord_a5.mp3 differ
diff --git a/audio/l_hchord_a5.ogg b/audio/l_hchord_a5.ogg
new file mode 100644 (file)
index 0000000..59de0da
Binary files /dev/null and b/audio/l_hchord_a5.ogg differ
diff --git a/audio/l_hchord_a5.wav b/audio/l_hchord_a5.wav
new file mode 100644 (file)
index 0000000..5d2bd4e
Binary files /dev/null and b/audio/l_hchord_a5.wav differ
diff --git a/audio/l_hchord_a6.mp3 b/audio/l_hchord_a6.mp3
new file mode 100644 (file)
index 0000000..177ed9b
Binary files /dev/null and b/audio/l_hchord_a6.mp3 differ
diff --git a/audio/l_hchord_a6.ogg b/audio/l_hchord_a6.ogg
new file mode 100644 (file)
index 0000000..0e46ad0
Binary files /dev/null and b/audio/l_hchord_a6.ogg differ
diff --git a/audio/l_hchord_a6.wav b/audio/l_hchord_a6.wav
new file mode 100644 (file)
index 0000000..f2f43d6
Binary files /dev/null and b/audio/l_hchord_a6.wav differ
diff --git a/audio/l_hchord_ab2.mp3 b/audio/l_hchord_ab2.mp3
new file mode 100644 (file)
index 0000000..157ee0a
Binary files /dev/null and b/audio/l_hchord_ab2.mp3 differ
diff --git a/audio/l_hchord_ab2.ogg b/audio/l_hchord_ab2.ogg
new file mode 100644 (file)
index 0000000..f26c314
Binary files /dev/null and b/audio/l_hchord_ab2.ogg differ
diff --git a/audio/l_hchord_ab2.wav b/audio/l_hchord_ab2.wav
new file mode 100644 (file)
index 0000000..b852d8a
Binary files /dev/null and b/audio/l_hchord_ab2.wav differ
diff --git a/audio/l_hchord_ab3.mp3 b/audio/l_hchord_ab3.mp3
new file mode 100644 (file)
index 0000000..bb4203b
Binary files /dev/null and b/audio/l_hchord_ab3.mp3 differ
diff --git a/audio/l_hchord_ab3.ogg b/audio/l_hchord_ab3.ogg
new file mode 100644 (file)
index 0000000..4baa126
Binary files /dev/null and b/audio/l_hchord_ab3.ogg differ
diff --git a/audio/l_hchord_ab3.wav b/audio/l_hchord_ab3.wav
new file mode 100644 (file)
index 0000000..687c2f9
Binary files /dev/null and b/audio/l_hchord_ab3.wav differ
diff --git a/audio/l_hchord_ab4.mp3 b/audio/l_hchord_ab4.mp3
new file mode 100644 (file)
index 0000000..6b434f4
Binary files /dev/null and b/audio/l_hchord_ab4.mp3 differ
diff --git a/audio/l_hchord_ab4.ogg b/audio/l_hchord_ab4.ogg
new file mode 100644 (file)
index 0000000..69cb3cd
Binary files /dev/null and b/audio/l_hchord_ab4.ogg differ
diff --git a/audio/l_hchord_ab4.wav b/audio/l_hchord_ab4.wav
new file mode 100644 (file)
index 0000000..9b5bdf0
Binary files /dev/null and b/audio/l_hchord_ab4.wav differ
diff --git a/audio/l_hchord_ab5.mp3 b/audio/l_hchord_ab5.mp3
new file mode 100644 (file)
index 0000000..7816068
Binary files /dev/null and b/audio/l_hchord_ab5.mp3 differ
diff --git a/audio/l_hchord_ab5.ogg b/audio/l_hchord_ab5.ogg
new file mode 100644 (file)
index 0000000..e0f98b5
Binary files /dev/null and b/audio/l_hchord_ab5.ogg differ
diff --git a/audio/l_hchord_ab5.wav b/audio/l_hchord_ab5.wav
new file mode 100644 (file)
index 0000000..b90435c
Binary files /dev/null and b/audio/l_hchord_ab5.wav differ
diff --git a/audio/l_hchord_ab6.mp3 b/audio/l_hchord_ab6.mp3
new file mode 100644 (file)
index 0000000..02a475a
Binary files /dev/null and b/audio/l_hchord_ab6.mp3 differ
diff --git a/audio/l_hchord_ab6.ogg b/audio/l_hchord_ab6.ogg
new file mode 100644 (file)
index 0000000..5263758
Binary files /dev/null and b/audio/l_hchord_ab6.ogg differ
diff --git a/audio/l_hchord_ab6.wav b/audio/l_hchord_ab6.wav
new file mode 100644 (file)
index 0000000..616d2ee
Binary files /dev/null and b/audio/l_hchord_ab6.wav differ
diff --git a/audio/l_hchord_b2.mp3 b/audio/l_hchord_b2.mp3
new file mode 100644 (file)
index 0000000..bf8a077
Binary files /dev/null and b/audio/l_hchord_b2.mp3 differ
diff --git a/audio/l_hchord_b2.ogg b/audio/l_hchord_b2.ogg
new file mode 100644 (file)
index 0000000..1bd1ea9
Binary files /dev/null and b/audio/l_hchord_b2.ogg differ
diff --git a/audio/l_hchord_b2.wav b/audio/l_hchord_b2.wav
new file mode 100644 (file)
index 0000000..06db374
Binary files /dev/null and b/audio/l_hchord_b2.wav differ
diff --git a/audio/l_hchord_b3.mp3 b/audio/l_hchord_b3.mp3
new file mode 100644 (file)
index 0000000..42a9025
Binary files /dev/null and b/audio/l_hchord_b3.mp3 differ
diff --git a/audio/l_hchord_b3.ogg b/audio/l_hchord_b3.ogg
new file mode 100644 (file)
index 0000000..5b709f3
Binary files /dev/null and b/audio/l_hchord_b3.ogg differ
diff --git a/audio/l_hchord_b3.wav b/audio/l_hchord_b3.wav
new file mode 100644 (file)
index 0000000..036fd8a
Binary files /dev/null and b/audio/l_hchord_b3.wav differ
diff --git a/audio/l_hchord_b4.mp3 b/audio/l_hchord_b4.mp3
new file mode 100644 (file)
index 0000000..7a6fdfb
Binary files /dev/null and b/audio/l_hchord_b4.mp3 differ
diff --git a/audio/l_hchord_b4.ogg b/audio/l_hchord_b4.ogg
new file mode 100644 (file)
index 0000000..9f828c0
Binary files /dev/null and b/audio/l_hchord_b4.ogg differ
diff --git a/audio/l_hchord_b4.wav b/audio/l_hchord_b4.wav
new file mode 100644 (file)
index 0000000..24ff591
Binary files /dev/null and b/audio/l_hchord_b4.wav differ
diff --git a/audio/l_hchord_b5.mp3 b/audio/l_hchord_b5.mp3
new file mode 100644 (file)
index 0000000..11ee233
Binary files /dev/null and b/audio/l_hchord_b5.mp3 differ
diff --git a/audio/l_hchord_b5.ogg b/audio/l_hchord_b5.ogg
new file mode 100644 (file)
index 0000000..71dbcdc
Binary files /dev/null and b/audio/l_hchord_b5.ogg differ
diff --git a/audio/l_hchord_b5.wav b/audio/l_hchord_b5.wav
new file mode 100644 (file)
index 0000000..8f2ad16
Binary files /dev/null and b/audio/l_hchord_b5.wav differ
diff --git a/audio/l_hchord_b6.mp3 b/audio/l_hchord_b6.mp3
new file mode 100644 (file)
index 0000000..23dbff1
Binary files /dev/null and b/audio/l_hchord_b6.mp3 differ
diff --git a/audio/l_hchord_b6.ogg b/audio/l_hchord_b6.ogg
new file mode 100644 (file)
index 0000000..7a1d1d8
Binary files /dev/null and b/audio/l_hchord_b6.ogg differ
diff --git a/audio/l_hchord_b6.wav b/audio/l_hchord_b6.wav
new file mode 100644 (file)
index 0000000..28b8c10
Binary files /dev/null and b/audio/l_hchord_b6.wav differ
diff --git a/audio/l_hchord_bb2.mp3 b/audio/l_hchord_bb2.mp3
new file mode 100644 (file)
index 0000000..e7b73a7
Binary files /dev/null and b/audio/l_hchord_bb2.mp3 differ
diff --git a/audio/l_hchord_bb2.ogg b/audio/l_hchord_bb2.ogg
new file mode 100644 (file)
index 0000000..448cc43
Binary files /dev/null and b/audio/l_hchord_bb2.ogg differ
diff --git a/audio/l_hchord_bb2.wav b/audio/l_hchord_bb2.wav
new file mode 100644 (file)
index 0000000..206aa16
Binary files /dev/null and b/audio/l_hchord_bb2.wav differ
diff --git a/audio/l_hchord_bb3.mp3 b/audio/l_hchord_bb3.mp3
new file mode 100644 (file)
index 0000000..0fa7b2e
Binary files /dev/null and b/audio/l_hchord_bb3.mp3 differ
diff --git a/audio/l_hchord_bb3.ogg b/audio/l_hchord_bb3.ogg
new file mode 100644 (file)
index 0000000..5c00121
Binary files /dev/null and b/audio/l_hchord_bb3.ogg differ
diff --git a/audio/l_hchord_bb3.wav b/audio/l_hchord_bb3.wav
new file mode 100644 (file)
index 0000000..fc866a9
Binary files /dev/null and b/audio/l_hchord_bb3.wav differ
diff --git a/audio/l_hchord_bb4.mp3 b/audio/l_hchord_bb4.mp3
new file mode 100644 (file)
index 0000000..79e50e0
Binary files /dev/null and b/audio/l_hchord_bb4.mp3 differ
diff --git a/audio/l_hchord_bb4.ogg b/audio/l_hchord_bb4.ogg
new file mode 100644 (file)
index 0000000..9f00c51
Binary files /dev/null and b/audio/l_hchord_bb4.ogg differ
diff --git a/audio/l_hchord_bb4.wav b/audio/l_hchord_bb4.wav
new file mode 100644 (file)
index 0000000..91cfec2
Binary files /dev/null and b/audio/l_hchord_bb4.wav differ
diff --git a/audio/l_hchord_bb5.mp3 b/audio/l_hchord_bb5.mp3
new file mode 100644 (file)
index 0000000..a4b59ef
Binary files /dev/null and b/audio/l_hchord_bb5.mp3 differ
diff --git a/audio/l_hchord_bb5.ogg b/audio/l_hchord_bb5.ogg
new file mode 100644 (file)
index 0000000..9e69af0
Binary files /dev/null and b/audio/l_hchord_bb5.ogg differ
diff --git a/audio/l_hchord_bb5.wav b/audio/l_hchord_bb5.wav
new file mode 100644 (file)
index 0000000..a4fa481
Binary files /dev/null and b/audio/l_hchord_bb5.wav differ
diff --git a/audio/l_hchord_bb6.mp3 b/audio/l_hchord_bb6.mp3
new file mode 100644 (file)
index 0000000..082b0ca
Binary files /dev/null and b/audio/l_hchord_bb6.mp3 differ
diff --git a/audio/l_hchord_bb6.ogg b/audio/l_hchord_bb6.ogg
new file mode 100644 (file)
index 0000000..b976ac2
Binary files /dev/null and b/audio/l_hchord_bb6.ogg differ
diff --git a/audio/l_hchord_bb6.wav b/audio/l_hchord_bb6.wav
new file mode 100644 (file)
index 0000000..1b40579
Binary files /dev/null and b/audio/l_hchord_bb6.wav differ
diff --git a/audio/l_hchord_c3.mp3 b/audio/l_hchord_c3.mp3
new file mode 100644 (file)
index 0000000..91a08c1
Binary files /dev/null and b/audio/l_hchord_c3.mp3 differ
diff --git a/audio/l_hchord_c3.ogg b/audio/l_hchord_c3.ogg
new file mode 100644 (file)
index 0000000..734e3d4
Binary files /dev/null and b/audio/l_hchord_c3.ogg differ
diff --git a/audio/l_hchord_c3.wav b/audio/l_hchord_c3.wav
new file mode 100644 (file)
index 0000000..2201b9b
Binary files /dev/null and b/audio/l_hchord_c3.wav differ
diff --git a/audio/l_hchord_c4.mp3 b/audio/l_hchord_c4.mp3
new file mode 100644 (file)
index 0000000..029bdf2
Binary files /dev/null and b/audio/l_hchord_c4.mp3 differ
diff --git a/audio/l_hchord_c4.ogg b/audio/l_hchord_c4.ogg
new file mode 100644 (file)
index 0000000..a32231e
Binary files /dev/null and b/audio/l_hchord_c4.ogg differ
diff --git a/audio/l_hchord_c4.wav b/audio/l_hchord_c4.wav
new file mode 100644 (file)
index 0000000..a98feae
Binary files /dev/null and b/audio/l_hchord_c4.wav differ
diff --git a/audio/l_hchord_c5.mp3 b/audio/l_hchord_c5.mp3
new file mode 100644 (file)
index 0000000..15f7fc6
Binary files /dev/null and b/audio/l_hchord_c5.mp3 differ
diff --git a/audio/l_hchord_c5.ogg b/audio/l_hchord_c5.ogg
new file mode 100644 (file)
index 0000000..0356eb5
Binary files /dev/null and b/audio/l_hchord_c5.ogg differ
diff --git a/audio/l_hchord_c5.wav b/audio/l_hchord_c5.wav
new file mode 100644 (file)
index 0000000..b39d672
Binary files /dev/null and b/audio/l_hchord_c5.wav differ
diff --git a/audio/l_hchord_c6.mp3 b/audio/l_hchord_c6.mp3
new file mode 100644 (file)
index 0000000..7f18d93
Binary files /dev/null and b/audio/l_hchord_c6.mp3 differ
diff --git a/audio/l_hchord_c6.ogg b/audio/l_hchord_c6.ogg
new file mode 100644 (file)
index 0000000..d133f6a
Binary files /dev/null and b/audio/l_hchord_c6.ogg differ
diff --git a/audio/l_hchord_c6.wav b/audio/l_hchord_c6.wav
new file mode 100644 (file)
index 0000000..15a9012
Binary files /dev/null and b/audio/l_hchord_c6.wav differ
diff --git a/audio/l_hchord_c7.mp3 b/audio/l_hchord_c7.mp3
new file mode 100644 (file)
index 0000000..cfc55ab
Binary files /dev/null and b/audio/l_hchord_c7.mp3 differ
diff --git a/audio/l_hchord_c7.ogg b/audio/l_hchord_c7.ogg
new file mode 100644 (file)
index 0000000..1521e16
Binary files /dev/null and b/audio/l_hchord_c7.ogg differ
diff --git a/audio/l_hchord_c7.wav b/audio/l_hchord_c7.wav
new file mode 100644 (file)
index 0000000..563d80e
Binary files /dev/null and b/audio/l_hchord_c7.wav differ
diff --git a/audio/l_hchord_d3.mp3 b/audio/l_hchord_d3.mp3
new file mode 100644 (file)
index 0000000..2b829c4
Binary files /dev/null and b/audio/l_hchord_d3.mp3 differ
diff --git a/audio/l_hchord_d3.ogg b/audio/l_hchord_d3.ogg
new file mode 100644 (file)
index 0000000..1b61840
Binary files /dev/null and b/audio/l_hchord_d3.ogg differ
diff --git a/audio/l_hchord_d3.wav b/audio/l_hchord_d3.wav
new file mode 100644 (file)
index 0000000..31deca7
Binary files /dev/null and b/audio/l_hchord_d3.wav differ
diff --git a/audio/l_hchord_d4.mp3 b/audio/l_hchord_d4.mp3
new file mode 100644 (file)
index 0000000..b30fd25
Binary files /dev/null and b/audio/l_hchord_d4.mp3 differ
diff --git a/audio/l_hchord_d4.ogg b/audio/l_hchord_d4.ogg
new file mode 100644 (file)
index 0000000..36c82c8
Binary files /dev/null and b/audio/l_hchord_d4.ogg differ
diff --git a/audio/l_hchord_d4.wav b/audio/l_hchord_d4.wav
new file mode 100644 (file)
index 0000000..697fbdc
Binary files /dev/null and b/audio/l_hchord_d4.wav differ
diff --git a/audio/l_hchord_d5.mp3 b/audio/l_hchord_d5.mp3
new file mode 100644 (file)
index 0000000..61bcc50
Binary files /dev/null and b/audio/l_hchord_d5.mp3 differ
diff --git a/audio/l_hchord_d5.ogg b/audio/l_hchord_d5.ogg
new file mode 100644 (file)
index 0000000..317e243
Binary files /dev/null and b/audio/l_hchord_d5.ogg differ
diff --git a/audio/l_hchord_d5.wav b/audio/l_hchord_d5.wav
new file mode 100644 (file)
index 0000000..774d412
Binary files /dev/null and b/audio/l_hchord_d5.wav differ
diff --git a/audio/l_hchord_d6.mp3 b/audio/l_hchord_d6.mp3
new file mode 100644 (file)
index 0000000..dcdced2
Binary files /dev/null and b/audio/l_hchord_d6.mp3 differ
diff --git a/audio/l_hchord_d6.ogg b/audio/l_hchord_d6.ogg
new file mode 100644 (file)
index 0000000..b5d9f2f
Binary files /dev/null and b/audio/l_hchord_d6.ogg differ
diff --git a/audio/l_hchord_d6.wav b/audio/l_hchord_d6.wav
new file mode 100644 (file)
index 0000000..9d33248
Binary files /dev/null and b/audio/l_hchord_d6.wav differ
diff --git a/audio/l_hchord_d7.mp3 b/audio/l_hchord_d7.mp3
new file mode 100644 (file)
index 0000000..50ea67b
Binary files /dev/null and b/audio/l_hchord_d7.mp3 differ
diff --git a/audio/l_hchord_d7.ogg b/audio/l_hchord_d7.ogg
new file mode 100644 (file)
index 0000000..f6e6d6d
Binary files /dev/null and b/audio/l_hchord_d7.ogg differ
diff --git a/audio/l_hchord_d7.wav b/audio/l_hchord_d7.wav
new file mode 100644 (file)
index 0000000..a8d29c6
Binary files /dev/null and b/audio/l_hchord_d7.wav differ
diff --git a/audio/l_hchord_db3.mp3 b/audio/l_hchord_db3.mp3
new file mode 100644 (file)
index 0000000..05ee7b7
Binary files /dev/null and b/audio/l_hchord_db3.mp3 differ
diff --git a/audio/l_hchord_db3.ogg b/audio/l_hchord_db3.ogg
new file mode 100644 (file)
index 0000000..508b9c9
Binary files /dev/null and b/audio/l_hchord_db3.ogg differ
diff --git a/audio/l_hchord_db3.wav b/audio/l_hchord_db3.wav
new file mode 100644 (file)
index 0000000..9d09f88
Binary files /dev/null and b/audio/l_hchord_db3.wav differ
diff --git a/audio/l_hchord_db4.mp3 b/audio/l_hchord_db4.mp3
new file mode 100644 (file)
index 0000000..e917aad
Binary files /dev/null and b/audio/l_hchord_db4.mp3 differ
diff --git a/audio/l_hchord_db4.ogg b/audio/l_hchord_db4.ogg
new file mode 100644 (file)
index 0000000..5d650e3
Binary files /dev/null and b/audio/l_hchord_db4.ogg differ
diff --git a/audio/l_hchord_db4.wav b/audio/l_hchord_db4.wav
new file mode 100644 (file)
index 0000000..9ae928b
Binary files /dev/null and b/audio/l_hchord_db4.wav differ
diff --git a/audio/l_hchord_db5.mp3 b/audio/l_hchord_db5.mp3
new file mode 100644 (file)
index 0000000..043be6b
Binary files /dev/null and b/audio/l_hchord_db5.mp3 differ
diff --git a/audio/l_hchord_db5.ogg b/audio/l_hchord_db5.ogg
new file mode 100644 (file)
index 0000000..d0b3cf9
Binary files /dev/null and b/audio/l_hchord_db5.ogg differ
diff --git a/audio/l_hchord_db5.wav b/audio/l_hchord_db5.wav
new file mode 100644 (file)
index 0000000..6d28eac
Binary files /dev/null and b/audio/l_hchord_db5.wav differ
diff --git a/audio/l_hchord_db6.mp3 b/audio/l_hchord_db6.mp3
new file mode 100644 (file)
index 0000000..d169c25
Binary files /dev/null and b/audio/l_hchord_db6.mp3 differ
diff --git a/audio/l_hchord_db6.ogg b/audio/l_hchord_db6.ogg
new file mode 100644 (file)
index 0000000..35f453d
Binary files /dev/null and b/audio/l_hchord_db6.ogg differ
diff --git a/audio/l_hchord_db6.wav b/audio/l_hchord_db6.wav
new file mode 100644 (file)
index 0000000..33de14d
Binary files /dev/null and b/audio/l_hchord_db6.wav differ
diff --git a/audio/l_hchord_db7.mp3 b/audio/l_hchord_db7.mp3
new file mode 100644 (file)
index 0000000..7296378
Binary files /dev/null and b/audio/l_hchord_db7.mp3 differ
diff --git a/audio/l_hchord_db7.ogg b/audio/l_hchord_db7.ogg
new file mode 100644 (file)
index 0000000..fc21b92
Binary files /dev/null and b/audio/l_hchord_db7.ogg differ
diff --git a/audio/l_hchord_db7.wav b/audio/l_hchord_db7.wav
new file mode 100644 (file)
index 0000000..a49dd52
Binary files /dev/null and b/audio/l_hchord_db7.wav differ
diff --git a/audio/l_hchord_e3.mp3 b/audio/l_hchord_e3.mp3
new file mode 100644 (file)
index 0000000..2913930
Binary files /dev/null and b/audio/l_hchord_e3.mp3 differ
diff --git a/audio/l_hchord_e3.ogg b/audio/l_hchord_e3.ogg
new file mode 100644 (file)
index 0000000..3ab92af
Binary files /dev/null and b/audio/l_hchord_e3.ogg differ
diff --git a/audio/l_hchord_e3.wav b/audio/l_hchord_e3.wav
new file mode 100644 (file)
index 0000000..5c25588
Binary files /dev/null and b/audio/l_hchord_e3.wav differ
diff --git a/audio/l_hchord_e4.mp3 b/audio/l_hchord_e4.mp3
new file mode 100644 (file)
index 0000000..354b40a
Binary files /dev/null and b/audio/l_hchord_e4.mp3 differ
diff --git a/audio/l_hchord_e4.ogg b/audio/l_hchord_e4.ogg
new file mode 100644 (file)
index 0000000..4531469
Binary files /dev/null and b/audio/l_hchord_e4.ogg differ
diff --git a/audio/l_hchord_e4.wav b/audio/l_hchord_e4.wav
new file mode 100644 (file)
index 0000000..70e1237
Binary files /dev/null and b/audio/l_hchord_e4.wav differ
diff --git a/audio/l_hchord_e5.mp3 b/audio/l_hchord_e5.mp3
new file mode 100644 (file)
index 0000000..1a7f50e
Binary files /dev/null and b/audio/l_hchord_e5.mp3 differ
diff --git a/audio/l_hchord_e5.ogg b/audio/l_hchord_e5.ogg
new file mode 100644 (file)
index 0000000..c3f1a27
Binary files /dev/null and b/audio/l_hchord_e5.ogg differ
diff --git a/audio/l_hchord_e5.wav b/audio/l_hchord_e5.wav
new file mode 100644 (file)
index 0000000..b1de021
Binary files /dev/null and b/audio/l_hchord_e5.wav differ
diff --git a/audio/l_hchord_e6.mp3 b/audio/l_hchord_e6.mp3
new file mode 100644 (file)
index 0000000..2831776
Binary files /dev/null and b/audio/l_hchord_e6.mp3 differ
diff --git a/audio/l_hchord_e6.ogg b/audio/l_hchord_e6.ogg
new file mode 100644 (file)
index 0000000..d60bc96
Binary files /dev/null and b/audio/l_hchord_e6.ogg differ
diff --git a/audio/l_hchord_e6.wav b/audio/l_hchord_e6.wav
new file mode 100644 (file)
index 0000000..6c323b0
Binary files /dev/null and b/audio/l_hchord_e6.wav differ
diff --git a/audio/l_hchord_e7.mp3 b/audio/l_hchord_e7.mp3
new file mode 100644 (file)
index 0000000..5a5d556
Binary files /dev/null and b/audio/l_hchord_e7.mp3 differ
diff --git a/audio/l_hchord_e7.ogg b/audio/l_hchord_e7.ogg
new file mode 100644 (file)
index 0000000..d359543
Binary files /dev/null and b/audio/l_hchord_e7.ogg differ
diff --git a/audio/l_hchord_e7.wav b/audio/l_hchord_e7.wav
new file mode 100644 (file)
index 0000000..594b6f8
Binary files /dev/null and b/audio/l_hchord_e7.wav differ
diff --git a/audio/l_hchord_eb3.mp3 b/audio/l_hchord_eb3.mp3
new file mode 100644 (file)
index 0000000..2e29fcf
Binary files /dev/null and b/audio/l_hchord_eb3.mp3 differ
diff --git a/audio/l_hchord_eb3.ogg b/audio/l_hchord_eb3.ogg
new file mode 100644 (file)
index 0000000..1fe7a7a
Binary files /dev/null and b/audio/l_hchord_eb3.ogg differ
diff --git a/audio/l_hchord_eb3.wav b/audio/l_hchord_eb3.wav
new file mode 100644 (file)
index 0000000..65de6bb
Binary files /dev/null and b/audio/l_hchord_eb3.wav differ
diff --git a/audio/l_hchord_eb4.mp3 b/audio/l_hchord_eb4.mp3
new file mode 100644 (file)
index 0000000..d453ede
Binary files /dev/null and b/audio/l_hchord_eb4.mp3 differ
diff --git a/audio/l_hchord_eb4.ogg b/audio/l_hchord_eb4.ogg
new file mode 100644 (file)
index 0000000..7cfa4ca
Binary files /dev/null and b/audio/l_hchord_eb4.ogg differ
diff --git a/audio/l_hchord_eb4.wav b/audio/l_hchord_eb4.wav
new file mode 100644 (file)
index 0000000..453ede6
Binary files /dev/null and b/audio/l_hchord_eb4.wav differ
diff --git a/audio/l_hchord_eb5.mp3 b/audio/l_hchord_eb5.mp3
new file mode 100644 (file)
index 0000000..1d1d934
Binary files /dev/null and b/audio/l_hchord_eb5.mp3 differ
diff --git a/audio/l_hchord_eb5.ogg b/audio/l_hchord_eb5.ogg
new file mode 100644 (file)
index 0000000..ef0557b
Binary files /dev/null and b/audio/l_hchord_eb5.ogg differ
diff --git a/audio/l_hchord_eb5.wav b/audio/l_hchord_eb5.wav
new file mode 100644 (file)
index 0000000..5ddf57a
Binary files /dev/null and b/audio/l_hchord_eb5.wav differ
diff --git a/audio/l_hchord_eb6.mp3 b/audio/l_hchord_eb6.mp3
new file mode 100644 (file)
index 0000000..3393f88
Binary files /dev/null and b/audio/l_hchord_eb6.mp3 differ
diff --git a/audio/l_hchord_eb6.ogg b/audio/l_hchord_eb6.ogg
new file mode 100644 (file)
index 0000000..ddf7318
Binary files /dev/null and b/audio/l_hchord_eb6.ogg differ
diff --git a/audio/l_hchord_eb6.wav b/audio/l_hchord_eb6.wav
new file mode 100644 (file)
index 0000000..3cec816
Binary files /dev/null and b/audio/l_hchord_eb6.wav differ
diff --git a/audio/l_hchord_eb7.mp3 b/audio/l_hchord_eb7.mp3
new file mode 100644 (file)
index 0000000..e42ce72
Binary files /dev/null and b/audio/l_hchord_eb7.mp3 differ
diff --git a/audio/l_hchord_eb7.ogg b/audio/l_hchord_eb7.ogg
new file mode 100644 (file)
index 0000000..0557391
Binary files /dev/null and b/audio/l_hchord_eb7.ogg differ
diff --git a/audio/l_hchord_eb7.wav b/audio/l_hchord_eb7.wav
new file mode 100644 (file)
index 0000000..bfe20ee
Binary files /dev/null and b/audio/l_hchord_eb7.wav differ
diff --git a/audio/l_hchord_f2.mp3 b/audio/l_hchord_f2.mp3
new file mode 100644 (file)
index 0000000..b29723a
Binary files /dev/null and b/audio/l_hchord_f2.mp3 differ
diff --git a/audio/l_hchord_f2.ogg b/audio/l_hchord_f2.ogg
new file mode 100644 (file)
index 0000000..d515d11
Binary files /dev/null and b/audio/l_hchord_f2.ogg differ
diff --git a/audio/l_hchord_f2.wav b/audio/l_hchord_f2.wav
new file mode 100644 (file)
index 0000000..da7d3a5
Binary files /dev/null and b/audio/l_hchord_f2.wav differ
diff --git a/audio/l_hchord_f3.mp3 b/audio/l_hchord_f3.mp3
new file mode 100644 (file)
index 0000000..e5bb303
Binary files /dev/null and b/audio/l_hchord_f3.mp3 differ
diff --git a/audio/l_hchord_f3.ogg b/audio/l_hchord_f3.ogg
new file mode 100644 (file)
index 0000000..d83d0b6
Binary files /dev/null and b/audio/l_hchord_f3.ogg differ
diff --git a/audio/l_hchord_f3.wav b/audio/l_hchord_f3.wav
new file mode 100644 (file)
index 0000000..9dc8d90
Binary files /dev/null and b/audio/l_hchord_f3.wav differ
diff --git a/audio/l_hchord_f4.mp3 b/audio/l_hchord_f4.mp3
new file mode 100644 (file)
index 0000000..ecbf4ac
Binary files /dev/null and b/audio/l_hchord_f4.mp3 differ
diff --git a/audio/l_hchord_f4.ogg b/audio/l_hchord_f4.ogg
new file mode 100644 (file)
index 0000000..c8608b9
Binary files /dev/null and b/audio/l_hchord_f4.ogg differ
diff --git a/audio/l_hchord_f4.wav b/audio/l_hchord_f4.wav
new file mode 100644 (file)
index 0000000..248a440
Binary files /dev/null and b/audio/l_hchord_f4.wav differ
diff --git a/audio/l_hchord_f5.mp3 b/audio/l_hchord_f5.mp3
new file mode 100644 (file)
index 0000000..35c56c4
Binary files /dev/null and b/audio/l_hchord_f5.mp3 differ
diff --git a/audio/l_hchord_f5.ogg b/audio/l_hchord_f5.ogg
new file mode 100644 (file)
index 0000000..6588bfb
Binary files /dev/null and b/audio/l_hchord_f5.ogg differ
diff --git a/audio/l_hchord_f5.wav b/audio/l_hchord_f5.wav
new file mode 100644 (file)
index 0000000..0d71ca5
Binary files /dev/null and b/audio/l_hchord_f5.wav differ
diff --git a/audio/l_hchord_f6.mp3 b/audio/l_hchord_f6.mp3
new file mode 100644 (file)
index 0000000..910a1e1
Binary files /dev/null and b/audio/l_hchord_f6.mp3 differ
diff --git a/audio/l_hchord_f6.ogg b/audio/l_hchord_f6.ogg
new file mode 100644 (file)
index 0000000..3628090
Binary files /dev/null and b/audio/l_hchord_f6.ogg differ
diff --git a/audio/l_hchord_f6.wav b/audio/l_hchord_f6.wav
new file mode 100644 (file)
index 0000000..148f2b0
Binary files /dev/null and b/audio/l_hchord_f6.wav differ
diff --git a/audio/l_hchord_f7.mp3 b/audio/l_hchord_f7.mp3
new file mode 100644 (file)
index 0000000..5bb8466
Binary files /dev/null and b/audio/l_hchord_f7.mp3 differ
diff --git a/audio/l_hchord_f7.ogg b/audio/l_hchord_f7.ogg
new file mode 100644 (file)
index 0000000..345d2a8
Binary files /dev/null and b/audio/l_hchord_f7.ogg differ
diff --git a/audio/l_hchord_f7.wav b/audio/l_hchord_f7.wav
new file mode 100644 (file)
index 0000000..18c776c
Binary files /dev/null and b/audio/l_hchord_f7.wav differ
diff --git a/audio/l_hchord_g2.mp3 b/audio/l_hchord_g2.mp3
new file mode 100644 (file)
index 0000000..aabe84d
Binary files /dev/null and b/audio/l_hchord_g2.mp3 differ
diff --git a/audio/l_hchord_g2.ogg b/audio/l_hchord_g2.ogg
new file mode 100644 (file)
index 0000000..48c5ec4
Binary files /dev/null and b/audio/l_hchord_g2.ogg differ
diff --git a/audio/l_hchord_g2.wav b/audio/l_hchord_g2.wav
new file mode 100644 (file)
index 0000000..65ab126
Binary files /dev/null and b/audio/l_hchord_g2.wav differ
diff --git a/audio/l_hchord_g3.mp3 b/audio/l_hchord_g3.mp3
new file mode 100644 (file)
index 0000000..fd3e83e
Binary files /dev/null and b/audio/l_hchord_g3.mp3 differ
diff --git a/audio/l_hchord_g3.ogg b/audio/l_hchord_g3.ogg
new file mode 100644 (file)
index 0000000..603a076
Binary files /dev/null and b/audio/l_hchord_g3.ogg differ
diff --git a/audio/l_hchord_g3.wav b/audio/l_hchord_g3.wav
new file mode 100644 (file)
index 0000000..04055b6
Binary files /dev/null and b/audio/l_hchord_g3.wav differ
diff --git a/audio/l_hchord_g4.mp3 b/audio/l_hchord_g4.mp3
new file mode 100644 (file)
index 0000000..29655e7
Binary files /dev/null and b/audio/l_hchord_g4.mp3 differ
diff --git a/audio/l_hchord_g4.ogg b/audio/l_hchord_g4.ogg
new file mode 100644 (file)
index 0000000..57a430d
Binary files /dev/null and b/audio/l_hchord_g4.ogg differ
diff --git a/audio/l_hchord_g4.wav b/audio/l_hchord_g4.wav
new file mode 100644 (file)
index 0000000..f152341
Binary files /dev/null and b/audio/l_hchord_g4.wav differ
diff --git a/audio/l_hchord_g5.mp3 b/audio/l_hchord_g5.mp3
new file mode 100644 (file)
index 0000000..bd7e701
Binary files /dev/null and b/audio/l_hchord_g5.mp3 differ
diff --git a/audio/l_hchord_g5.ogg b/audio/l_hchord_g5.ogg
new file mode 100644 (file)
index 0000000..b4b2a3d
Binary files /dev/null and b/audio/l_hchord_g5.ogg differ
diff --git a/audio/l_hchord_g5.wav b/audio/l_hchord_g5.wav
new file mode 100644 (file)
index 0000000..46544cd
Binary files /dev/null and b/audio/l_hchord_g5.wav differ
diff --git a/audio/l_hchord_g6.mp3 b/audio/l_hchord_g6.mp3
new file mode 100644 (file)
index 0000000..54e0469
Binary files /dev/null and b/audio/l_hchord_g6.mp3 differ
diff --git a/audio/l_hchord_g6.ogg b/audio/l_hchord_g6.ogg
new file mode 100644 (file)
index 0000000..ef58105
Binary files /dev/null and b/audio/l_hchord_g6.ogg differ
diff --git a/audio/l_hchord_g6.wav b/audio/l_hchord_g6.wav
new file mode 100644 (file)
index 0000000..f141532
Binary files /dev/null and b/audio/l_hchord_g6.wav differ
diff --git a/audio/l_hchord_gb2.mp3 b/audio/l_hchord_gb2.mp3
new file mode 100644 (file)
index 0000000..5153ef2
Binary files /dev/null and b/audio/l_hchord_gb2.mp3 differ
diff --git a/audio/l_hchord_gb2.ogg b/audio/l_hchord_gb2.ogg
new file mode 100644 (file)
index 0000000..0ea0c31
Binary files /dev/null and b/audio/l_hchord_gb2.ogg differ
diff --git a/audio/l_hchord_gb2.wav b/audio/l_hchord_gb2.wav
new file mode 100644 (file)
index 0000000..214d315
Binary files /dev/null and b/audio/l_hchord_gb2.wav differ
diff --git a/audio/l_hchord_gb3.mp3 b/audio/l_hchord_gb3.mp3
new file mode 100644 (file)
index 0000000..d11457a
Binary files /dev/null and b/audio/l_hchord_gb3.mp3 differ
diff --git a/audio/l_hchord_gb3.ogg b/audio/l_hchord_gb3.ogg
new file mode 100644 (file)
index 0000000..9498791
Binary files /dev/null and b/audio/l_hchord_gb3.ogg differ
diff --git a/audio/l_hchord_gb3.wav b/audio/l_hchord_gb3.wav
new file mode 100644 (file)
index 0000000..d6fd080
Binary files /dev/null and b/audio/l_hchord_gb3.wav differ
diff --git a/audio/l_hchord_gb4.mp3 b/audio/l_hchord_gb4.mp3
new file mode 100644 (file)
index 0000000..5a27d02
Binary files /dev/null and b/audio/l_hchord_gb4.mp3 differ
diff --git a/audio/l_hchord_gb4.ogg b/audio/l_hchord_gb4.ogg
new file mode 100644 (file)
index 0000000..5730339
Binary files /dev/null and b/audio/l_hchord_gb4.ogg differ
diff --git a/audio/l_hchord_gb4.wav b/audio/l_hchord_gb4.wav
new file mode 100644 (file)
index 0000000..10991f4
Binary files /dev/null and b/audio/l_hchord_gb4.wav differ
diff --git a/audio/l_hchord_gb5.mp3 b/audio/l_hchord_gb5.mp3
new file mode 100644 (file)
index 0000000..caae50c
Binary files /dev/null and b/audio/l_hchord_gb5.mp3 differ
diff --git a/audio/l_hchord_gb5.ogg b/audio/l_hchord_gb5.ogg
new file mode 100644 (file)
index 0000000..0bff28e
Binary files /dev/null and b/audio/l_hchord_gb5.ogg differ
diff --git a/audio/l_hchord_gb5.wav b/audio/l_hchord_gb5.wav
new file mode 100644 (file)
index 0000000..e682fa6
Binary files /dev/null and b/audio/l_hchord_gb5.wav differ
diff --git a/audio/l_hchord_gb6.mp3 b/audio/l_hchord_gb6.mp3
new file mode 100644 (file)
index 0000000..c9fd7b1
Binary files /dev/null and b/audio/l_hchord_gb6.mp3 differ
diff --git a/audio/l_hchord_gb6.ogg b/audio/l_hchord_gb6.ogg
new file mode 100644 (file)
index 0000000..c6221e4
Binary files /dev/null and b/audio/l_hchord_gb6.ogg differ
diff --git a/audio/l_hchord_gb6.wav b/audio/l_hchord_gb6.wav
new file mode 100644 (file)
index 0000000..25badcf
Binary files /dev/null and b/audio/l_hchord_gb6.wav differ
diff --git a/game-noaudio.html b/game-noaudio.html
new file mode 100644 (file)
index 0000000..34ca0d7
--- /dev/null
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <title>Matrix Creatrix</title>
+    <meta charset="utf-8" />
+    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
+    <meta name="description" content="Matrix Creatrix - for Ludum Dare 23" />
+    <meta name="author" content="Joe Wreschnig" />
+    <meta name="viewport" content="width=device-width; initial-scale=1.0" />
+    <meta name="author" content="Joe Wreschnig" />
+    <link rel="stylesheet" href="ps.css" type="text/css">
+    <link rel="stylesheet" href="game.css" type="text/css">
+    <script type="text/javascript" src="ps2.1.js"></script>
+  </head>
+  <body onload="PS.Sys();">
+    <div id="main">
+      <input id="status" name="status" type="text" class="noselect" readonly />
+      <canvas id="screen" name="screen" width=480 height=480 class="noselect">
+        This game requires HTML Canvas support.
+      </canvas>
+    </div>
+    <div id="debug" name="debug" style="display: none;">
+      <textarea id="monitor" name="monitor" cols=57 rows=8 wrap=soft readonly=true>
+      </textarea> 
+    </div>
+
+    <script type="text/javascript" src="game.js"></script>
+    <script type="text/javascript" src="noaudio.js"></script>
+
+    <div id="instructions">
+      The job of a goddess is tricky. Gather elements from
+      the <span class="void">void</span> to fashion worlds full
+      of <span class="air">air</span>
+      and <span class="water">water</span>,
+      supporting <span class="life">life</span>. Create as many as you
+      can. Find all <span class="life">life</span> a home to move onto
+      the next plane of existence.
+    </div>
+    <div id="myfooter">
+      An entry
+      in <a href="http://www.ludumdare.com/compo/ludum-dare-23/">Ludum
+      Dare 23</a>.<br /> Made
+      with <a href="http://www.perlenspiel.org/">Perlenspiel</a>.
+    </div>
+  </body>
+</html>
diff --git a/game.css b/game.css
new file mode 100644 (file)
index 0000000..463c552
--- /dev/null
+++ b/game.css
@@ -0,0 +1,36 @@
+/* Public domain. */
+
+div#instructions {
+    color: white;
+    text-align: center;
+    font-family: sans-serif;
+}
+
+div#header {
+    color: #eee;
+    text-align: center;
+    font-family: sans-serif;
+    font-size: 0.7em;
+    margin-bottom: 1em;
+}
+
+div#header a {
+    color: #eee;
+}
+
+div#myfooter {
+    color: #bbb;
+    text-align: center;
+    font-family: sans-serif;
+    font-size: 0.7em;
+    margin-top: 2em;
+}
+
+div#myfooter a {
+    color: #bbb;
+}
+
+span.life { color: #9f9; }
+span.water { color: #99f; }
+span.air { color: #ff9; }
+span.void { color: #f9f; }
diff --git a/game.html b/game.html
new file mode 100644 (file)
index 0000000..86c2736
--- /dev/null
+++ b/game.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <title>Matrix Creatrix</title>
+    <meta charset="utf-8" />
+    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
+    <meta name="description" content="Matrix Creatrix - for Ludum Dare 23" />
+    <meta name="author" content="Joe Wreschnig" />
+    <meta name="viewport" content="width=device-width; initial-scale=1.0" />
+    <meta name="author" content="Joe Wreschnig" />
+    <link rel="stylesheet" href="ps.css" type="text/css">
+    <link rel="stylesheet" href="game.css" type="text/css">
+    <script type="text/javascript" src="ps2.1.js"></script>
+  </head>
+  <body onload="PS.Sys();">
+    <div id="main">
+      <input id="status" name="status" type="text" class="noselect" readonly />
+      <canvas id="screen" name="screen" width=480 height=480 class="noselect">
+        This game requires HTML Canvas support.
+      </canvas>
+    </div>
+    <div id="debug" name="debug" style="display: none;">
+      <textarea id="monitor" name="monitor" cols=57 rows=8 wrap=soft readonly=true>
+      </textarea> 
+    </div>
+
+    <script type="text/javascript" src="game.js"></script>
+
+    <div id="header">
+      "☹ Aw, Snap!"?<br />
+      <a href="game-noaudio.html">Try the audio-free version</a>.
+    </div>
+    <div id="instructions">
+      The job of a goddess is tricky. Gather elements from
+      the <span class="void">void</span> to fashion worlds full
+      of <span class="air">air</span>
+      and <span class="water">water</span>,
+      supporting <span class="life">life</span>. Create as many as you
+      can. Find all <span class="life">life</span> a home to move onto
+      the next plane of existence.
+    </div>
+    <div id="myfooter">
+      An entry
+      in <a href="http://www.ludumdare.com/compo/ludum-dare-23/">Ludum
+      Dare 23</a>.<br /> Made
+      with <a href="http://www.perlenspiel.org/">Perlenspiel</a>.
+    </div>
+  </body>
+</html>
diff --git a/game.js b/game.js
new file mode 100644 (file)
index 0000000..b82aef5
--- /dev/null
+++ b/game.js
@@ -0,0 +1,283 @@
+"use strict";\r
+\r
+/* By Joe Wreschnig\r
+   Placed in the public domain.\r
+\r
+   This code is designed for use with Perlenspiel, by Brian Moriarty,\r
+   which is released under the terms of the GNU LGPL version 3 or\r
+   later.\r
+ */\r
+\r
+\r
+/*global PS */\r
+\r
+var EARTH = 0x00FF00;\r
+var WATER = 0x0000FF;\r
+var FIRE = 0xFF0000;\r
+var WIND = 0xFFFF00;\r
+\r
+var VOID = 0x330033;\r
+\r
+var SELECTED = 0x222222;\r
+\r
+var DISABLE_PROMPT = 3;\r
+\r
+var X_SIZE = 12;\r
+var Y_SIZE = 9;\r
+\r
+var AUDIO_MAX = 57;\r
+var AUDIO_LOUD = 0.7;\r
+var AUDIO_QUIET = 0.4;\r
+\r
+var selecting = false;\r
+var score = 0;\r
+var level = 1;\r
+\r
+var proportions = [\r
+    EARTH,\r
+    WATER, WATER,\r
+    FIRE, FIRE, FIRE,\r
+    WIND, WIND,\r
+    VOID, VOID,\r
+    EARTH,\r
+];\r
+\r
+var level_modifier = [FIRE, VOID];\r
+\r
+function couldFinishWorldSound(score, size) {\r
+    score = PS.Random(score) + score;\r
+    if (score + 18 > AUDIO_MAX)\r
+        score = AUDIO_MAX - 18;\r
+    PS.AudioPlay(PS.Harpsichord(score, false), AUDIO_QUIET);\r
+    PS.AudioPlay(PS.Harpsichord(score + 6, false), AUDIO_QUIET);\r
+    PS.AudioPlay(PS.Harpsichord(score + 18, false), AUDIO_QUIET);\r
+}\r
+\r
+function finishWorldSound(score, size) {\r
+    score = PS.Random(score) + score;\r
+    if (score + 18 > AUDIO_MAX)\r
+        score = AUDIO_MAX - 18;\r
+    PS.AudioPlay(PS.Harpsichord(score, true), AUDIO_LOUD);\r
+    PS.AudioPlay(PS.Harpsichord(score + 6, true), AUDIO_LOUD);\r
+    PS.AudioPlay(PS.Harpsichord(score + 18, true), AUDIO_LOUD);\r
+}\r
+\r
+function levelUpSound(level) {\r
+    if (level + 44 > AUDIO_MAX)\r
+        level = AUDIO_MAX - 44;\r
+    PS.AudioPlay(PS.Harpsichord(20 + level, true), AUDIO_LOUD);\r
+    PS.AudioPlay(PS.Harpsichord(28 + level, true), AUDIO_LOUD);\r
+    PS.AudioPlay(PS.Harpsichord(44 + level, true), AUDIO_LOUD);\r
+}\r
+\r
+function select(x, y) {\r
+    if (PS.BeadBorderColor(x, y) != SELECTED) {\r
+        var invalid = checkInvalidReason();\r
+        PS.BeadBorderColor(x, y, SELECTED);\r
+        PS.BeadBorderWidth(x, y, 4);\r
+        if (invalid && !checkInvalidReason())\r
+            couldFinishWorldSound(score, 0);\r
+    }\r
+}\r
+\r
+function deselect(x, y) {\r
+    PS.BeadBorderColor(x, y, PS.DEFAULT);\r
+    PS.BeadBorderWidth(x, y, PS.DEFAULT);\r
+}\r
+\r
+function shuffle(a) {\r
+    for (var i = a.length - 1; i >= 1; --i) {\r
+        var j = PS.Random(i) - 1;\r
+        var tmp = a[j];\r
+        a[j] = a[i];\r
+        a[i] = tmp;\r
+    }\r
+    return a;\r
+}\r
+\r
+function countBoard(evenUnselected) {\r
+    var b = { fire: 0, earth: 0, water: 0, wind: 0, nothing: 0, total: 0 };\r
+    for (var x = 0; x < X_SIZE; ++x) {\r
+        for (var y = 0; y < Y_SIZE; ++y) {\r
+            if (evenUnselected || isSelected(x, y)) {\r
+                var color = PS.BeadColor(x, y);\r
+                if (color == FIRE) b.fire++;\r
+                if (color == EARTH) b.earth++;\r
+                if (color == WATER) b.water++;\r
+                if (color == WIND) b.wind++;\r
+                if (color == VOID) b.nothing++;\r
+                b.total++;\r
+            }\r
+        }\r
+    }\r
+    return b;\r
+}\r
+\r
+function isSelected(x, y) {\r
+    return (x >= 0 && x < X_SIZE\r
+            && y >= 0 && y < Y_SIZE\r
+            && PS.BeadBorderColor(x, y) == SELECTED);\r
+}\r
+\r
+function onlySelected(x, y) {\r
+    return isSelected(x, y) && countBoard().total == 1;\r
+}\r
+\r
+function checkAdjacent(x, y) {\r
+    return (isSelected(x, y)\r
+            || isSelected(x - 1, y)\r
+            || isSelected(x + 1, y)\r
+            || isSelected(x, y - 1)\r
+            || isSelected(x, y + 1));\r
+}\r
+\r
+function createBoard() {\r
+    var nothing = countBoard(true).nothing;\r
+    var b = [];\r
+    for (var y = 0; y < nothing; ++y) {\r
+        b.push(proportions[y % proportions.length]);\r
+    }\r
+    b = shuffle(b);\r
+    var j = 0;\r
+    for (var x = 0; x < X_SIZE; ++x)\r
+        for (var y = 0; y < Y_SIZE; ++y)\r
+            if (PS.BeadColor(x, y) == VOID)\r
+                PS.BeadColor(x, y, b[j++]);\r
+}\r
+\r
+function checkInvalidReason() {\r
+    var b = countBoard();\r
+    if (b.total == 1 && b.fire) {\r
+        return ["[Fire] Counter its heat with water", 0xFF9999];\r
+    } else if (b.total == 1 && b.earth) {\r
+        return ["[Life] Lifeless worlds are pointless", 0x99FF99];\r
+    } else if (b.total == 1 && b.water) {\r
+        return ["[Water] Quench both thirst and fire", 0x9999FF];\r
+    } else if (b.total == 1 && b.wind) {\r
+        return ["[Air] Habitable worlds need air", 0xFFFF99];\r
+    } else if (b.total == 1 && b.nothing) {\r
+        return ["[Void] Don't use too much...", 0xFF99FF];\r
+    } else if (b.total == 0 && score == 0) {\r
+        return ["Click and drag to make a world", 0xFFFFFF];\r
+    } else if (b.total && b.total < 3 && score < DISABLE_PROMPT) {\r
+        return ["Select more elements to make a world", 0xFFFFFF];\r
+    } else if (b.total < 3) {\r
+        var s = "Worlds created: " + score;\r
+        if (level > 1)\r
+            s = "Plane " + level + " / " + s;\r
+        return [s, 0xFFFFFF];\r
+    }\r
+\r
+    if (b.earth == 0)\r
+        return ["This world wouldn't have any life!", 0x99FF99];\r
+\r
+    if (b.water == 0)\r
+        return ["Life needs water to drink!", 0x9999FF];\r
+\r
+    if (b.wind == 0)\r
+        return ["Life needs air to breathe!", 0xFFFF99];\r
+\r
+    if (b.nothing >= (b.water + b.fire * 2 + b.earth + b.wind))\r
+        return ["Your world has too much nothing!", 0xFF99FF];\r
+\r
+    if (b.water < b.fire)\r
+        return ["Your world is burning!", 0xFF9999];\r
+\r
+    return null;\r
+}\r
+\r
+function statusUpdate() {\r
+    var res = checkInvalidReason();\r
+    if (!res)\r
+        res = ["Click to create a world", 0xFFFFFF];\r
+    PS.StatusText(res[0]);\r
+    PS.StatusColor(res[1]);\r
+}\r
+\r
+PS.Init = function () {\r
+    var path = window.location.href;\r
+    PS.AudioPath(path.substr(0, path.lastIndexOf("/")) + "/audio/");\r
+    PS.Clock(100);\r
+    PS.GridSize(X_SIZE, Y_SIZE);\r
+    PS.GridBGColor(VOID);\r
+    PS.BeadShow(PS.ALL, PS.ALL, true);\r
+    PS.BeadColor(PS.ALL, PS.ALL, VOID);\r
+    createBoard();\r
+    statusUpdate();\r
+};\r
+\r
+PS.Click = function (x, y, data) {\r
+    if (onlySelected(x, y)) {\r
+        deselect(x, y);\r
+    } else if (isSelected(x, y) && !checkInvalidReason()) {\r
+        var size = 0;\r
+        for (var x = 0; x < X_SIZE; ++x) {\r
+            for (var y = 0; y < Y_SIZE; ++y) {\r
+                if (isSelected(x, y)) {\r
+                    PS.BeadColor(x, y, VOID);\r
+                    ++size;\r
+                }\r
+            }\r
+        }\r
+        deselect(PS.ALL, PS.ALL);\r
+        finishWorldSound(++score, size);\r
+    } else if (checkAdjacent(x, y) && !isSelected(x, y)) {\r
+        select(x, y);\r
+        selecting = true;\r
+    } else {\r
+        deselect(PS.ALL, PS.ALL);\r
+        selecting = true;\r
+        select(x, y);\r
+    }\r
+    statusUpdate();\r
+    var b = countBoard(true);\r
+    if (b.earth == 0) {\r
+        proportions.push.apply(proportions, level_modifier);\r
+        createBoard();\r
+        levelUpSound(++level);\r
+\r
+        var b = countBoard(true);\r
+        if (b.earth == 0) {\r
+            PS.StatusText("All life thanks you! Final score: " + score);\r
+        } else {\r
+            PS.StatusText("Now try a more dangerous universe!");\r
+        }\r
+        PS.StatusColor(0xFFFFFF);\r
+    }\r
+};\r
+\r
+PS.Release = function (x, y, data) {\r
+    selecting = false;\r
+};\r
+\r
+PS.Enter = function (x, y, data) {\r
+    if (selecting && checkAdjacent(x, y)) {\r
+        select(x, y);\r
+        statusUpdate();\r
+    } else {\r
+        selecting = false;\r
+    }\r
+};\r
+\r
+PS.Leave = function (x, y, data) {\r
+};\r
+\r
+PS.KeyDown = function (key, shift, ctrl) {\r
+};\r
+\r
+PS.KeyUp = function (key, shift, ctrl) {\r
+};\r
+\r
+PS.Wheel = function (dir) {\r
+};\r
+\r
+// Chrome and Firefox bug out when asked to preload 114 files at once.\r
+var loaded = 0;\r
+PS.Tick = function () {\r
+    if (++loaded <= AUDIO_MAX) {\r
+        PS.AudioLoad(PS.Harpsichord(loaded));\r
+        PS.AudioLoad(PS.Harpsichord(loaded, true));\r
+    } else {\r
+        PS.Clock(0);\r
+    }\r
+};\r
diff --git a/noaudio.js b/noaudio.js
new file mode 100644 (file)
index 0000000..12ac918
--- /dev/null
@@ -0,0 +1,4 @@
+PS.AudioPlay = function() { return null; }
+PS.AudioLoad = function() { return 0; }
+PS.AudioPause = function() { return 0; }
+PS.AudioStop = function() { return 0; }
diff --git a/ps.css b/ps.css
new file mode 100644 (file)
index 0000000..03b757b
--- /dev/null
+++ b/ps.css
@@ -0,0 +1,73 @@
+body
+{
+       color: rgb(0,0,0);
+       background-color: white;
+       width: 512px;
+       margin: 0 auto;
+}
+
+#status
+{
+       width: 480px;
+       font-family: "Arial", San-Serif;
+       font-size: 18pt;
+       text-align: center;
+       border: 0;
+       margin-top: 32px;
+       margin-bottom: 16px;
+}
+
+#inbox
+{
+       text-align: left;
+}
+
+#monitor
+{
+       text-align: left;
+}
+
+#footer
+{
+       color: #000000;
+       width: 480px;
+       font-family: "Arial", San-Serif;
+       font-size: 9pt;
+       text-align: center;
+}
+
+b
+{
+       color: black;
+}
+
+.normal
+{
+       color: gray;
+       font-size: 12pt;
+       font-style: normal;
+}
+
+.large
+{
+       color: gray;
+       font-size: 24pt;
+       font-style: normal;
+}
+
+.tiny
+{
+       color: gray;
+       font-size: 8pt;
+       font-style: normal;
+}
+
+a:link
+{
+       color: rgb(0,0,0);
+}
+
+a:visited
+{
+       color: rgb(0,0,0);
+}
diff --git a/ps2.1.js b/ps2.1.js
new file mode 100644 (file)
index 0000000..b94d801
--- /dev/null
+++ b/ps2.1.js
@@ -0,0 +1,4221 @@
+// ps2.1.js for Perlenspiel 2.1\r
+\r
+/*\r
+Perlenspiel is a scheme by Professor Moriarty (bmoriarty@wpi.edu).\r
+Perlenspiel is Copyright Â© 2009-12 Worcester Polytechnic Institute.\r
+This file is part of Perlenspiel.\r
+\r
+Perlenspiel is free software: you can redistribute it and/or modify\r
+it under the terms of the GNU Lesser General Public License as published\r
+by the Free Software Foundation, either version 3 of the License, or\r
+(at your option) any later version.\r
+\r
+Perlenspiel is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+GNU Lesser General Public License for more details.\r
+\r
+You may have received a copy of the GNU Lesser General Public License\r
+along with Perlenspiel. If not, see <http://www.gnu.org/licenses/>.\r
+*/\r
+\r
+// The following comments are for JSLint\r
+\r
+/*global document, window, Audio, Image */\r
+\r
+// Global namespace variable\r
+\r
+var PS = {\r
+       \r
+       // Constants\r
+       \r
+       VERSION: "2.1.00",\r
+       DEFAULT: -1, // use default value\r
+       CURRENT: -2, // use current value\r
+       ALL: -3, // Use all rows or columns\r
+       ERROR: "*ERROR*", // generic error return value\r
+       CANVAS_SIZE: 480, // max width/height of canvas\r
+       GRID_MAX: 32, // max x/y dimensions of grid\r
+       GRID_DEFAULT_WIDTH: 8,\r
+       GRID_DEFAULT_HEIGHT: 8,\r
+       DEFAULT_BEAD_COLOR: 0x000000,\r
+       DEFAULT_BEAD_RED: 0x00,\r
+       DEFAULT_BEAD_GREEN: 0x00,\r
+       DEFAULT_BEAD_BLUE: 0x00,\r
+       DEFAULT_BG_COLOR: 0xFFFFFF,\r
+       DEFAULT_BG_RED: 0xFF,\r
+       DEFAULT_BG_GREEN: 0xFF,\r
+       DEFAULT_BG_BLUE: 0xFF,\r
+       DEFAULT_BORDER_COLOR: 0x808080,\r
+       DEFAULT_BORDER_RED: 0x80,\r
+       DEFAULT_BORDER_GREEN: 0x80,\r
+       DEFAULT_BORDER_BLUE: 0x80,\r
+       DEFAULT_BORDER_WIDTH: 1,\r
+       BORDER_WIDTH_MAX: 8,\r
+       DEFAULT_GLYPH_COLOR: 0xFFFFFF,\r
+       DEFAULT_GLYPH_RED: 0xFF,\r
+       DEFAULT_GLYPH_GREEN: 0xFF,\r
+       DEFAULT_GLYPH_BLUE: 0xFF,\r
+       DEFAULT_FLASH_COLOR: 0xFFFFFF,\r
+       DEFAULT_FLASH_RED: 0xFF,\r
+       DEFAULT_FLASH_GREEN: 0xFF,\r
+       DEFAULT_FLASH_BLUE: 0xFF,\r
+       DEFAULT_ALPHA: 100, // must be between 0 and 100\r
+       DEFAULT_VOLUME: 1.0, // must be between 0 and 1.0\r
+       DEFAULT_LOOP: false,\r
+       DEFAULT_FPS: 10, // frame rate in milliseconds (1/100 sec)\r
+       REDSHIFT: 256 * 256, // used to decode rgb\r
+       FLASH_STEP: 10, // percent for each flash\r
+       STATUS_FLASH_STEP: 5, // percent for each step\r
+       FLASH_INTERVAL: 5, // number of ticks per flash step\r
+       DEFAULT_TEXT_COLOR: 0x000000,\r
+\r
+       // Color constants\r
+\r
+       COLOR_BLACK: 0x000000,\r
+       COLOR_WHITE: 0xFFFFFF,\r
+       COLOR_GRAY_LIGHT: 0xC0C0C0,\r
+       COLOR_GRAY: 0x808080,\r
+       COLOR_GRAY_DARK: 0x404040,\r
+       COLOR_RED: 0xFF0000,\r
+       COLOR_ORANGE: 0xFF8000,\r
+       COLOR_YELLOW: 0xFFFF00,\r
+       COLOR_GREEN: 0x00FF00,\r
+       COLOR_BLUE: 0x0000FF,\r
+       COLOR_INDIGO: 0x4000FF,\r
+       COLOR_VIOLET: 0x8000FF,\r
+       COLOR_MAGENTA: 0xFF00FF,\r
+       COLOR_CYAN: 0x00FFFF,\r
+\r
+       // Key and mouse wheel constants\r
+\r
+       ARROW_LEFT: 37,\r
+       ARROW_RIGHT: 39,\r
+       ARROW_UP: 38,\r
+       ARROW_DOWN: 40,\r
+       KEYPAD_0: 96,\r
+       KEYPAD_1: 97,\r
+       KEYPAD_2: 98,\r
+       KEYPAD_3: 99,\r
+       KEYPAD_4: 100,\r
+       KEYPAD_5: 101,\r
+       KEYPAD_6: 102,\r
+       KEYPAD_7: 103,\r
+       KEYPAD_8: 104,\r
+       KEYPAD_9: 105,\r
+       F1: 112,\r
+       F2: 113,\r
+       F3: 114,\r
+       F4: 115,\r
+       F5: 116,\r
+       F6: 117,\r
+       F7: 118,\r
+       F8: 119,\r
+       F9: 120,\r
+       F10: 121,\r
+       FORWARD: 1,\r
+       BACKWARD: -1,\r
+\r
+       Grid: null, // main grid\r
+       DebugWindow: null, // debugger window\r
+       ImageCanvas: null, // offscreen canvas for image manipulation\r
+\r
+       // Coordinates of current and previous beads, -1 if none\r
+\r
+       MouseX: -1,\r
+       MouseY: -1,\r
+       LastX: -1,\r
+       LastY: -1,\r
+\r
+       // Delay and clock settings\r
+\r
+       FlashDelay: 0,\r
+       UserDelay: 0,\r
+       UserClock: 0,\r
+\r
+       // Status line\r
+\r
+       Status: "Perlenspiel",\r
+       StatusHue: 0, // target hue\r
+       StatusRed: 0,\r
+       StatusGreen: 0,\r
+       StatusBlue: 0,\r
+       StatusPhase: 0, // 100: done fading\r
+       StatusFading: true\r
+};\r
+\r
+// Improved typeof that distinguishes arrays\r
+\r
+PS.TypeOf = function (value)\r
+{\r
+       "use strict";\r
+       var s;\r
+\r
+    s = typeof value;\r
+    if ( s === "object" )\r
+       {\r
+        if ( value )\r
+        {\r
+            if ( value instanceof Array )\r
+            {\r
+                s = "array";\r
+            }\r
+        }\r
+        else\r
+        {\r
+            s = "null";\r
+        }\r
+    }\r
+    return s;\r
+};\r
+\r
+// Get the canvas context\r
+\r
+PS.Context = function ()\r
+{\r
+       "use strict";\r
+       var cv, ctx;\r
+\r
+       ctx = null;\r
+       cv = document.getElementById("screen");\r
+       if ( cv && cv.getContext )\r
+       {\r
+               ctx = cv.getContext("2d");\r
+       }\r
+\r
+       return ctx;\r
+};\r
+\r
+// Takes a multiplexed rgb value and a function name\r
+// Returns floored rgb value, or -1 if invalid\r
+\r
+PS.ValidRGB = function ( rgb, fn )\r
+{\r
+       "use strict";\r
+\r
+       if ( typeof rgb !== "number" )\r
+       {\r
+               PS.Oops( fn + "rgb parameter not a number" );\r
+               return -1;\r
+       }\r
+       rgb = Math.floor(rgb);\r
+       if ( rgb < 0 )\r
+       {\r
+               PS.Oops( fn + "rgb parameter negative" );\r
+               return -1;\r
+       }\r
+       if ( rgb > 0xFFFFFF )\r
+       {\r
+               PS.Oops( fn + "rgb parameter out of range" );\r
+               return -1;\r
+       }\r
+       return rgb;\r
+};\r
+\r
+// Construct a color string with optional alpha\r
+\r
+PS.RGBString = function (r, g, b, a)\r
+{\r
+       "use strict";\r
+       var str;\r
+\r
+       if ( a === undefined )\r
+       {\r
+               str = "rgb(" + r + "," + g + "," + b + ")";\r
+       }\r
+       else\r
+       {\r
+               str = "rgba(" + r + "," + g + "," + b + "," + a + ")";\r
+       }\r
+       return str;\r
+};\r
+\r
+// Takes a multiplexed rgb value and creates an object with\r
+// separate r, g and b values, or null if error\r
+\r
+PS.UnmakeRGB = function ( rgb )\r
+{\r
+       "use strict";\r
+       var fn, red, green, blue, rval, gval;\r
+\r
+       fn = "[PS.DecodeRGB] ";\r
+\r
+       if ( typeof rgb !== "number" )\r
+       {\r
+               PS.Oops(fn + "RGB parameter not a number");\r
+               return PS.ERROR;\r
+       }\r
+       rgb = Math.floor(rgb);\r
+       if ( rgb < 0 )\r
+       {\r
+               PS.Oops(fn + "RGB parameter negative");\r
+               return PS.ERROR;\r
+       }\r
+       if ( rgb > 0xFFFFFF )\r
+       {\r
+               PS.Oops(fn + "RGB parameter out of range");\r
+               return PS.ERROR;\r
+       }\r
+\r
+       red = rgb / PS.REDSHIFT;\r
+       red = Math.floor(red);\r
+       rval = red * PS.REDSHIFT;\r
+\r
+       green = (rgb - rval) / 256;\r
+       green = Math.floor(green);\r
+       gval = green * 256;\r
+\r
+       blue = rgb - rval - gval;\r
+\r
+       return { r: red, g: green, b: blue };\r
+};\r
+\r
+// PS.Dissolve\r
+// Returns a color that is x% between c1 and c2\r
+\r
+PS.Dissolve = function ( c1, c2, x )\r
+{\r
+       "use strict";\r
+       var delta;\r
+\r
+       if ( c1 > c2 )\r
+       {\r
+               delta = c1 - c2;\r
+               delta = ( x * delta ) / 100;\r
+               delta = Math.floor(delta);\r
+               return ( c1 - delta );\r
+       }\r
+       else\r
+       {\r
+               delta = c2 - c1;\r
+               delta = ( x * delta ) / 100;\r
+               delta = Math.floor(delta);\r
+               return ( c1 + delta );\r
+       }\r
+};\r
+\r
+// Bead constuctor\r
+\r
+PS.InitBead = function (xpos, ypos, size, bgcolor)\r
+{\r
+       "use strict";\r
+       var bead;\r
+\r
+       bead = {};\r
+\r
+       bead.left = xpos;\r
+       bead.right = xpos + size;\r
+       bead.top = ypos;\r
+       bead.bottom = ypos + size;\r
+\r
+       bead.size = size;\r
+\r
+       bead.visible = true;                    // bead visible?\r
+\r
+       // target color\r
+\r
+       bead.dirty = false;                             // bead color touched?\r
+\r
+       // base colors\r
+\r
+       bead.red = PS.DEFAULT_BEAD_RED;\r
+       bead.green = PS.DEFAULT_BEAD_GREEN;\r
+       bead.blue = PS.DEFAULT_BEAD_BLUE;\r
+       bead.color = PS.RGBString (bead.red, bead.green, bead.blue); // default color\r
+       bead.colorNow = bead.color;     // actual color while drawing\r
+\r
+       // pre-calculated alpha colors\r
+\r
+       bead.alpha = PS.DEFAULT_ALPHA;\r
+       bead.alphaRed = PS.DEFAULT_BEAD_RED;\r
+       bead.alphaGreen = PS.DEFAULT_BEAD_GREEN;\r
+       bead.alphaBlue = PS.DEFAULT_BEAD_BLUE;\r
+\r
+       // glyph params\r
+\r
+       bead.glyph = 0;                                 // glyph code (zero if none)\r
+       bead.glyphStr = "";                             // actual string to print\r
+       bead.glyphRed = PS.DEFAULT_GLYPH_RED;\r
+       bead.glyphGreen = PS.DEFAULT_GLYPH_GREEN;\r
+       bead.glyphBlue = PS.DEFAULT_GLYPH_BLUE;\r
+       bead.glyphColor = PS.RGBString (PS.DEFAULT_GLYPH_RED, PS.DEFAULT_GLYPH_GREEN, PS.DEFAULT_GLYPH_BLUE);\r
+\r
+       // flash params\r
+\r
+       bead.flash = true;                              // flashing enabled?\r
+       bead.flashPhase = 0;                    // phase of flash animation\r
+       bead.flashRed = PS.DEFAULT_FLASH_RED;\r
+       bead.flashGreen = PS.DEFAULT_FLASH_GREEN;\r
+       bead.flashBlue = PS.DEFAULT_FLASH_BLUE;\r
+       bead.flashColor = PS.RGBString (PS.DEFAULT_FLASH_RED, PS.DEFAULT_FLASH_GREEN, PS.DEFAULT_FLASH_BLUE);\r
+\r
+       // border params\r
+\r
+       bead.borderWidth = PS.DEFAULT_BORDER_WIDTH; // border width; 0 if none\r
+       bead.borderRed = PS.DEFAULT_BORDER_RED;\r
+       bead.borderGreen = PS.DEFAULT_BORDER_GREEN;\r
+       bead.borderBlue = PS.DEFAULT_BORDER_BLUE;\r
+       bead.borderAlpha = PS.DEFAULT_ALPHA;                    // border alpha\r
+       bead.borderColor = PS.RGBString (PS.DEFAULT_BORDER_RED, PS.DEFAULT_BORDER_GREEN, PS.DEFAULT_BORDER_BLUE);\r
+\r
+       // data, sound, exec params\r
+\r
+       bead.data = 0;                                  // data value\r
+\r
+       bead.audio = null;                                      // sound (null = none)\r
+       bead.volume = PS.DEFAULT_VOLUME;        // volume\r
+       bead.loop = PS.DEFAULT_LOOP;            // loop flag\r
+\r
+       bead.exec = null;                                       // on-click function (null = none)\r
+\r
+       // give each bead its own offscreen canvas and context\r
+\r
+       bead.off = document.createElement("canvas");\r
+       bead.off.width = size;\r
+       bead.off.height = size;\r
+       bead.off.backgroundColor = bgcolor;\r
+       bead.offContext = bead.off.getContext("2d");\r
+\r
+       // set up font info for offscreen context\r
+\r
+       bead.offContext.font = Math.floor(size / 2) + "pt sans-serif";\r
+       bead.offContext.textAlign = "center";\r
+       bead.offContext.textBaseline = "middle";\r
+\r
+       return bead;\r
+};\r
+\r
+// Draws bead [bead] in (optional) context [ctx]\r
+\r
+PS.DrawBead = function (bead, ctx)\r
+{\r
+       "use strict";\r
+       var offctx, left, top, size, width;\r
+\r
+       // get destination context if not provided\r
+\r
+       if ( ctx === undefined )\r
+       {\r
+               ctx = PS.Context();\r
+       }\r
+\r
+       left = 0;\r
+       top = 0;\r
+       size = bead.size;       \r
+\r
+       offctx = bead.offContext; // the offscreen canvas context\r
+\r
+       // draw border if needed\r
+\r
+       width = bead.borderWidth;\r
+       if ( width > 0 )\r
+       {\r
+               offctx.fillStyle = bead.borderColor;\r
+               offctx.fillRect(0, 0, size, size);\r
+\r
+               // adjust position and size of bead rect                \r
+\r
+               left += width;\r
+               top += width;\r
+               size -= (width + width);\r
+       }\r
+\r
+       // draw bead body if dirty (has had color explicitly set)\r
+\r
+       if ( bead.dirty )\r
+       {\r
+               offctx.fillStyle = bead.colorNow;\r
+       }\r
+\r
+       // otherwise fill with background color\r
+\r
+       else\r
+       {\r
+               offctx.fillStyle = PS.Grid.bgColor;\r
+       }\r
+\r
+       offctx.fillRect(left, top, size, size);\r
+\r
+       if ( bead.glyph > 0 )\r
+       {\r
+               offctx.fillStyle = bead.glyphColor;\r
+               offctx.fillText (bead.glyphStr, PS.Grid.glyphX, PS.Grid.glyphY);\r
+       }\r
+\r
+       // blit offscreen canvas to main canvas\r
+\r
+       ctx.drawImage(bead.off, bead.left, bead.top);\r
+};\r
+\r
+// Erase bead [bead] in (optional) context [ctx]\r
+\r
+PS.EraseBead = function (bead, ctx)\r
+{\r
+       "use strict";\r
+       var size, left, top, width;\r
+\r
+       // get destination context if not provided\r
+\r
+       if ( ctx === undefined )\r
+       {\r
+               ctx = PS.Context();\r
+       }\r
+\r
+       left = bead.left;\r
+       top = bead.top;\r
+       size = bead.size;       \r
+\r
+       // draw border if needed\r
+\r
+       width = bead.borderWidth;\r
+       if ( width > 0 )\r
+       {\r
+               ctx.fillStyle = bead.borderColor;\r
+               ctx.fillRect(left, top, size, size);\r
+\r
+               // adjust position and size of bead rect                \r
+\r
+               left += width;\r
+               top += width;\r
+               size -= (width + width);\r
+       }\r
+\r
+       ctx.fillStyle = PS.Grid.bgColor;\r
+       ctx.fillRect(left, top, size, size);\r
+};\r
+\r
+// Grid constructor\r
+// Call with x/y dimensions of grid\r
+// Returns initialized grid object or null if error\r
+\r
+PS.InitGrid = function (x, y)\r
+{\r
+       "use strict";\r
+       var grid, i, j, size, xpos, ypos;\r
+\r
+       grid = {};\r
+\r
+       grid.x = x;                                     // x dimensions of grid\r
+       grid.y = y;                                     // y dimensions of grid\r
+       grid.count = x * y;                     // number of beads in grid\r
+\r
+       // calc size of beads, position/dimensions of centered grid on canvas\r
+\r
+       if ( x >= y )\r
+       {\r
+               grid.beadSize = size = Math.floor(PS.CANVAS_SIZE / x);\r
+               grid.width = size * x;\r
+               grid.height = size * y;\r
+               grid.left = 0;\r
+       }\r
+       else\r
+       {\r
+               grid.beadSize = size = Math.floor(PS.CANVAS_SIZE / y);\r
+               grid.width = size * x;\r
+               grid.height = size * y;\r
+               grid.left = Math.floor( (PS.CANVAS_SIZE - grid.width) / 2 );\r
+       }\r
+       \r
+       grid.top = 0;\r
+\r
+       grid.right = grid.left + grid.width;\r
+       grid.bottom = grid.top + grid.height;\r
+\r
+       grid.bgRed = PS.DEFAULT_BG_RED;\r
+       grid.bgGreen = PS.DEFAULT_BG_GREEN;\r
+       grid.bgBlue = PS.DEFAULT_BG_BLUE;\r
+       grid.bgColor = PS.RGBString (grid.bgRed, grid.bgGreen, grid.bgBlue);\r
+\r
+       grid.borderRed = PS.DEFAULT_BORDER_RED;\r
+       grid.borderGreen = PS.DEFAULT_BORDER_GREEN;\r
+       grid.borderBlue = PS.DEFAULT_BORDER_BLUE;\r
+       grid.borderColor = PS.RGBString (grid.borderRed, grid.borderGreen, grid.borderBlue);\r
+\r
+//     grid.borderWidth = PS.DEFAULT_BORDER_WIDTH;\r
+       grid.borderMax = PS.BORDER_WIDTH_MAX; // for now; should be calculated\r
+\r
+       grid.pointing = -1;                     // bead cursor is pointing at (-1 if none)\r
+\r
+       grid.flash = true;                      // flash globally enabled?\r
+       grid.flashList = [];            // array of currently flashing beads\r
+\r
+       grid.glyphX = Math.floor(size / 2);\r
+       grid.glyphY = Math.floor((size / 7) * 4);\r
+\r
+       // init beads   \r
+\r
+       grid.beads = [];\r
+       ypos = grid.top;\r
+       for ( j = 0; j < y; j += 1 )\r
+       {\r
+               xpos = grid.left;\r
+               for ( i = 0; i < x; i += 1 )\r
+               {\r
+                       grid.beads.push( PS.InitBead(xpos, ypos, size, grid.bgColor) );\r
+                       xpos += size;\r
+               }\r
+               ypos += size;\r
+       }\r
+\r
+       return grid;\r
+};\r
+\r
+PS.DrawGrid = function ()\r
+{\r
+       "use strict";\r
+       var ctx, beads, cnt, i, bead;\r
+\r
+       ctx = PS.Context();\r
+       beads = PS.Grid.beads;\r
+       cnt = PS.Grid.count;\r
+\r
+       for ( i = 0; i < cnt; i += 1 )\r
+       {\r
+               bead = beads[i];\r
+               if ( bead.visible )\r
+               {\r
+                       PS.DrawBead(bead, ctx);\r
+               }\r
+               else\r
+               {\r
+                       PS.EraseBead(bead, ctx);\r
+               }\r
+       }\r
+};\r
+\r
+// Returns true if x parameter is valid, else false\r
+\r
+PS.CheckX = function ( x, fn )\r
+{\r
+       "use strict";\r
+\r
+       if ( typeof x !== "number" )\r
+       {\r
+               PS.Oops(fn + "x parameter not a number");\r
+               return false;\r
+       }\r
+       x = Math.floor(x);\r
+       if ( x < 0 )\r
+       {\r
+               PS.Oops(fn + "x parameter negative");\r
+               return false;\r
+       }\r
+       if ( x >= PS.Grid.x )\r
+       {\r
+               PS.Oops(fn + "x parameter exceeds grid width");\r
+               return false;\r
+       }\r
+\r
+       return true;\r
+};\r
+\r
+// Returns true if y parameter is valid, else false\r
+\r
+PS.CheckY = function ( y, fn )\r
+{\r
+       "use strict";\r
+\r
+       if ( typeof y !== "number" )\r
+       {\r
+               PS.Oops(fn + "y parameter not a number");\r
+               return false;\r
+       }\r
+       y = Math.floor(y);\r
+       if ( y < 0 )\r
+       {\r
+               PS.Oops(fn + "y parameter negative");\r
+               return false;\r
+       }\r
+       if ( y >= PS.Grid.y )\r
+       {\r
+               PS.Oops(fn + "y parameter exceeds grid height");\r
+               return false;\r
+       }\r
+\r
+       return true;\r
+};\r
+\r
+// PS.GetBead(x, y)\r
+// Takes x/y coords of bead and function name\r
+// Returns the bead object at (x, y), or null if error\r
+\r
+PS.GetBead = function (x, y, fn)\r
+{\r
+       "use strict";\r
+       var i;\r
+\r
+       if ( !PS.CheckX( x, fn ) || !PS.CheckY( y, fn ) )\r
+       {\r
+               return null;\r
+       }\r
+\r
+       i = x + (y * PS.Grid.x); // get index of bead\r
+\r
+       return PS.Grid.beads[i];\r
+};\r
+\r
+// API Functions\r
+\r
+PS.GridSize = function (w, h)\r
+{\r
+       "use strict";\r
+       var fn, i, cnt, beads, cv;\r
+\r
+       fn = "[PS.GridSize] ";\r
+\r
+       if ( typeof w !== "number" )\r
+       {\r
+               PS.Oops(fn + "Width param not a number");\r
+               return;\r
+       }\r
+       if ( typeof h !== "number" )\r
+       {\r
+               PS.Oops(fn + "Height param not a number");\r
+               return;\r
+       }\r
+\r
+       w = Math.floor(w);\r
+       if ( w === PS.DEFAULT )\r
+       {\r
+               w = PS.GRID_DEFAULT_WIDTH;\r
+       }\r
+       else if ( w < 1 )\r
+       {\r
+               PS.Oops(fn + "width parameter < 1");\r
+               w = 1;\r
+       }\r
+       else if ( w > PS.GRID_MAX )\r
+       {\r
+               PS.Oops(fn + "width parameter > " + PS.GRID_MAX);\r
+               w = PS.GRID_MAX;\r
+       }\r
+\r
+       h = Math.floor(h);\r
+       if ( h === PS.DEFAULT )\r
+       {\r
+               h = PS.GRID_DEFAULT_HEIGHT;\r
+       }\r
+       else if ( h < 1 )\r
+       {\r
+               PS.Oops(fn + "height parameter < 1");\r
+               h = 1;\r
+       }\r
+       else if ( h > PS.GRID_MAX )\r
+       {\r
+               PS.Oops(fn + "height parameter > " + PS.GRID_MAX);\r
+               h = PS.GRID_MAX;\r
+       }\r
+\r
+       // If a grid already exists, null out its arrays and then itself\r
+\r
+       if ( PS.Grid )\r
+       {\r
+               beads = PS.Grid.beads;\r
+               if ( beads )\r
+               {\r
+                       cnt = PS.Grid.count;\r
+                       for ( i = 0; i < cnt; i += 1 )\r
+                       {\r
+                               beads[i] = null;\r
+                       }\r
+               }\r
+\r
+               PS.Grid.beads = null;\r
+               PS.Grid.flashList = null;\r
+               PS.Grid = null;\r
+       }\r
+\r
+       PS.Grid = PS.InitGrid(w, h);\r
+       \r
+       // Reset mouse coordinates\r
+       \r
+       PS.MouseX = -1;\r
+       PS.MouseY = -1;\r
+       PS.LastX = -1;\r
+       PS.LastY = -1;\r
+\r
+       // Erase the canvas\r
+\r
+       if ( PS.Grid )\r
+       {\r
+               cv = document.getElementById("screen");\r
+               if ( cv )\r
+               {\r
+                       cv.height = PS.Grid.height; // setting height erases canvas\r
+                       PS.DrawGrid();\r
+               }\r
+       }\r
+};\r
+\r
+PS.GridBGColor = function ( rgb )\r
+{\r
+       "use strict";\r
+       var fn, current, colors, e;\r
+\r
+       fn = "[PS.GridBGColor] ";\r
+       current = (PS.Grid.bgRed * PS.REDSHIFT) + (PS.Grid.bgGreen * 256) + PS.Grid.bgBlue;\r
+\r
+       // if param or PS.CURRENT, just return current color\r
+\r
+       if ( (rgb === undefined) || (rgb === PS.CURRENT) )\r
+       {\r
+               return current;\r
+       }\r
+\r
+       if ( rgb === PS.DEFAULT )\r
+       {\r
+               rgb = PS.DEFAULT_BG_COLOR;\r
+       }\r
+       else\r
+       {\r
+               rgb = PS.ValidRGB( rgb, fn );\r
+               if ( rgb < 0 )\r
+               {\r
+                       return PS.ERROR;\r
+               }\r
+       }\r
+\r
+       colors = PS.UnmakeRGB(rgb);\r
+       if ( colors )\r
+       {\r
+               PS.Grid.bgRed = colors.r;\r
+               PS.Grid.bgGreen = colors.g;\r
+               PS.Grid.bgBlue = colors.b;\r
+               PS.Grid.bgColor = PS.RGBString(colors.r, colors.g, colors.b);\r
+\r
+               // Reset browser background\r
+\r
+               e = document.body;\r
+               e.style.backgroundColor = PS.Grid.bgColor;\r
+               \r
+               // reset status line background\r
+\r
+               e = document.getElementById("status");\r
+               if ( e )\r
+               {\r
+                       e.style.backgroundColor = PS.Grid.bgColor;\r
+               }\r
+\r
+               // redraw canvas\r
+\r
+               e = document.getElementById("screen");\r
+               if ( e )\r
+               {\r
+                       e.width = PS.CANVAS_SIZE; // setting width erases\r
+                       PS.DrawGrid();\r
+               }\r
+       }\r
+\r
+       return rgb;\r
+};\r
+\r
+// PS.MakeRGB (r, g, b)\r
+// Takes three colors and returns multiplexed rgb value, or 0 (black) if error\r
+\r
+PS.MakeRGB = function (r, g, b)\r
+{\r
+       "use strict";\r
+       var fn, rgb;\r
+\r
+       fn = "[PS.MakeRGB] ";\r
+\r
+       if ( typeof r !== "number" )\r
+       {\r
+               PS.Oops(fn + "R parameter not a number");\r
+               return PS.ERROR;\r
+       }\r
+       r = Math.floor(r);\r
+       if ( r < 0 )\r
+       {\r
+               r = 0;\r
+       }\r
+       else if ( r > 255 )\r
+       {\r
+               r = 255;\r
+       }\r
+\r
+       if ( typeof g !== "number" )\r
+       {\r
+               PS.Oops(fn + "G parameter not a number");\r
+               return PS.ERROR;\r
+       }\r
+       g = Math.floor(g);\r
+       if ( g < 0 )\r
+       {\r
+               g = 0;\r
+       }\r
+       else if ( g > 255 )\r
+       {\r
+               g = 255;\r
+       }\r
+\r
+       if ( typeof b !== "number" )\r
+       {\r
+               PS.Oops(fn + "B parameter not a number");\r
+               return PS.ERROR;\r
+       }\r
+       b = Math.floor(b);\r
+       if ( b < 0 )\r
+       {\r
+               b = 0;\r
+       }\r
+       else if ( b > 255 )\r
+       {\r
+               b = 255;\r
+       }\r
+\r
+       rgb = (r * PS.REDSHIFT) + (g * 256) + b;\r
+\r
+       return rgb;\r
+};\r
+\r
+// Bead API\r
+\r
+// PS.BeadShow(x, y, flag)\r
+// Returns a bead's display status and optionally changes it\r
+// [x, y] are grid position\r
+// Optional [flag] must be 1/true or 0/false\r
+\r
+PS.DoBeadShow = function (x, y, flag)\r
+{\r
+       "use strict";\r
+       var i, bead;\r
+\r
+       // Assume x/y params are already verified\r
+\r
+       i = x + (y * PS.Grid.x); // get index of bead\r
+       bead = PS.Grid.beads[i];\r
+\r
+       if ( (flag === undefined) || (flag === PS.CURRENT) || (flag === bead.visible) )\r
+       {\r
+               return bead.visible;\r
+       }\r
+\r
+       bead.visible = flag;\r
+       if ( flag )\r
+       {\r
+               if ( PS.Grid.flash && bead.flash )\r
+               {\r
+                       PS.FlashStart(x, y);\r
+               }\r
+               else\r
+               {\r
+                       bead.colorNow = bead.color;\r
+                       PS.DrawBead(bead);\r
+               }\r
+       }\r
+       else\r
+       {\r
+               PS.EraseBead(bead);\r
+       }\r
+\r
+       return flag;\r
+};\r
+\r
+PS.BeadShow = function (x, y, flag)\r
+{\r
+       "use strict";\r
+       var fn, i, j;\r
+\r
+       fn = "[PS.BeadShow] ";\r
+\r
+       // normalize flag value to t/f if defined\r
+\r
+       if ( (flag !== undefined) && (flag !== PS.CURRENT) )\r
+       {\r
+               if ( flag === PS.DEFAULT )\r
+               {\r
+                       flag = true;\r
+               }\r
+               else if ( flag )\r
+               {\r
+                       flag = true;\r
+               }\r
+               else\r
+               {\r
+                       flag = false;\r
+               }\r
+       }\r
+\r
+       if ( x === PS.ALL )\r
+       {\r
+               if ( y === PS.ALL ) // do entire grid\r
+               {\r
+                       for ( j = 0; j < PS.Grid.y; j += 1 )\r
+                       {\r
+                               for ( i = 0; i < PS.Grid.x; i += 1 )\r
+                               {\r
+                                       flag = PS.DoBeadShow( i, j, flag );\r
+                               }\r
+                       }\r
+               }\r
+               else if ( !PS.CheckY( y, fn ) ) // verify y param\r
+               {\r
+                       return PS.ERROR;\r
+               }\r
+               else\r
+               {\r
+                       for ( i = 0; i < PS.Grid.x; i += 1 ) // do entire row\r
+                       {\r
+                               flag = PS.DoBeadShow( i, y, flag );\r
+                       }\r
+               }\r
+       }\r
+       else if ( y === PS.ALL )\r
+       {\r
+               if ( !PS.CheckX( x, fn ) ) // verify x param\r
+               {\r
+                       return PS.ERROR;\r
+               }\r
+               for ( j = 0; j < PS.Grid.y; j += 1 ) // do entire column\r
+               {\r
+                       flag = PS.DoBeadShow( x, j, flag );\r
+               }\r
+       }\r
+       else if ( !PS.CheckX( x, fn ) || !PS.CheckY( y, fn ) ) // verify both params\r
+       {\r
+               return PS.ERROR;\r
+       }\r
+       else\r
+       {\r
+               flag = PS.DoBeadShow( x, y, flag ); // do one bead\r
+       }\r
+\r
+       return flag;\r
+};\r
+\r
+// PS.BeadColor (x, y, rgb)\r
+// Returns and optionally sets a bead's color\r
+// [x, y] are grid position\r
+// Optional [rgb] must be a multiplexed rgb value (0xRRGGBB)\r
+\r
+PS.DoBeadColor = function ( x, y, rgb, r, g, b )\r
+{\r
+       "use strict";\r
+       var i, bead;\r
+\r
+       // Assume x/y params are already verified\r
+\r
+       i = x + (y * PS.Grid.x); // get index of bead\r
+       bead = PS.Grid.beads[i];\r
+\r
+       if ( (rgb === undefined) || (rgb === PS.CURRENT) ) // if no rgb or PS.CURRENT, return current color\r
+       {\r
+               return (bead.red * PS.REDSHIFT) + (bead.green * 256) + bead.blue;\r
+       }\r
+\r
+       bead.dirty = true; // mark this bead as explicitly colored\r
+\r
+       bead.red = r;\r
+       bead.green = g;\r
+       bead.blue = b;\r
+       if ( bead.alpha < PS.DEFAULT_ALPHA ) // Calc new color based on alpha\r
+       {\r
+               bead.alphaRed = PS.Dissolve( PS.Grid.bgRed, r, bead.alpha );\r
+               bead.alphaGreen = PS.Dissolve( PS.Grid.bgGreen, g, bead.alpha );\r
+               bead.alphaBlue = PS.Dissolve( PS.Grid.bgBlue, b, bead.alpha );\r
+               bead.color = PS.RGBString( bead.alphaRed, bead.alphaGreen, bead.alphaBlue );\r
+       }\r
+       else\r
+       {\r
+               bead.alphaRed = r;\r
+               bead.alphaGreen = g;\r
+               bead.alphaBlue = b;\r
+               bead.color = PS.RGBString( r, g, b );\r
+       }\r
+\r
+       if ( bead.visible )\r
+       {\r
+               if ( PS.Grid.flash && bead.flash )\r
+               {\r
+                       PS.FlashStart(x, y);\r
+               }\r
+               else\r
+               {\r
+                       bead.colorNow = bead.color;\r
+                       PS.DrawBead(bead);\r
+               }\r
+       }\r
+\r
+       return rgb;\r
+};\r
+\r
+PS.BeadColor = function (x, y, rgb)\r
+{\r
+       "use strict";\r
+       var fn, colors, r, g, b, i, j;\r
+\r
+       fn = "[PS.BeadColor] ";\r
+\r
+       // if no rgb specified, just return current color\r
+\r
+       if ( rgb === PS.DEFAULT )\r
+       {\r
+               rgb = PS.DEFAULT_BEAD_COLOR;\r
+               r = PS.DEFAULT_BG_RED;\r
+               g = PS.DEFAULT_BG_GREEN;\r
+               b = PS.DEFAULT_BG_BLUE;\r
+       }\r
+       else if ( (rgb !== undefined) && (rgb !== PS.CURRENT) )\r
+       {\r
+               rgb = PS.ValidRGB( rgb, fn );\r
+               if ( rgb < 0 )\r
+               {\r
+                       return PS.ERROR;\r
+               }\r
+               colors = PS.UnmakeRGB( rgb );\r
+               r = colors.r;\r
+               g = colors.g;\r
+               b = colors.b;\r
+       }\r
+\r
+       if ( x === PS.ALL )\r
+       {\r
+               if ( y === PS.ALL ) // do entire grid\r
+               {\r
+                       for ( j = 0; j < PS.Grid.y; j += 1 )\r
+                       {\r
+                               for ( i = 0; i < PS.Grid.x; i += 1 )\r
+                               {\r
+                                       rgb = PS.DoBeadColor( i, j, rgb, r, g, b );\r
+                               }\r
+                       }\r
+               }\r
+               else if ( !PS.CheckY( y, fn ) ) // verify y param\r
+               {\r
+                       return PS.ERROR;\r
+               }\r
+               else\r
+               {\r
+                       for ( i = 0; i < PS.Grid.x; i += 1 ) // do entire row\r
+                       {\r
+                               rgb = PS.DoBeadColor( i, y, rgb, r, g, b );\r
+                       }\r
+               }\r
+       }\r
+       else if ( y === PS.ALL )\r
+       {\r
+               if ( !PS.CheckX( x, fn ) ) // verify x param\r
+               {\r
+                       return PS.ERROR;\r
+               }\r
+               for ( j = 0; j < PS.Grid.y; j += 1 ) // do entire column\r
+               {\r
+                       rgb = PS.DoBeadColor( x, j, rgb, r, g, b );\r
+               }\r
+       }\r
+       else if ( !PS.CheckX( x, fn ) || !PS.CheckY( y, fn ) ) // verify both params\r
+       {\r
+               return PS.ERROR;\r
+       }\r
+       else\r
+       {\r
+               rgb = PS.DoBeadColor( x, y, rgb, r, g, b ); // do one bead\r
+       }\r
+\r
+       return rgb;\r
+};\r
+\r
+// PS.BeadAlpha(x, y, a)\r
+// Returns and optionally sets a bead's alpha\r
+// [x, y] are grid position\r
+// Optional [a] must be a number between 0.0 and 1.0\r
+\r
+PS.DoBeadAlpha = function ( x, y, a )\r
+{\r
+       "use strict";\r
+       var i, bead;\r
+\r
+       // Assume x/y params are already verified\r
+\r
+       i = x + (y * PS.Grid.x); // get index of bead\r
+       bead = PS.Grid.beads[i];\r
+\r
+       if ( (a === undefined) || (a === PS.CURRENT) || (a === bead.alpha) )\r
+       {\r
+               return bead.alpha;\r
+       }\r
+\r
+       // Calc new color between background and base\r
+\r
+       bead.alpha = a;\r
+       bead.dirty = true;\r
+       if ( bead.alpha < PS.DEFAULT_ALPHA ) // Calc new color based on alpha\r
+       {\r
+               bead.alphaRed = PS.Dissolve( PS.Grid.bgRed, bead.red, a );\r
+               bead.alphaGreen = PS.Dissolve( PS.Grid.bgGreen, bead.green, a );\r
+               bead.alphaBlue = PS.Dissolve( PS.Grid.bgBlue, bead.blue, a );\r
+               bead.color = PS.RGBString( bead.alphaRed, bead.alphaGreen, bead.alphaBlue );\r
+       }\r
+       else\r
+       {\r
+               bead.alphaRed = bead.red;\r
+               bead.alphaGreen = bead.green;\r
+               bead.alphaBlue = bead.blue;\r
+               bead.color = PS.RGBString( bead.red, bead.green, bead.blue );\r
+       }\r
+       if ( bead.visible )\r
+       {\r
+               if ( PS.Grid.flash && bead.flash )\r
+               {\r
+                       PS.FlashStart(x, y);\r
+               }\r
+               else\r
+               {\r
+                       bead.colorNow = bead.color;\r
+                       PS.DrawBead(bead);\r
+               }\r
+       }\r
+\r
+       return a;\r
+};\r
+\r
+PS.BeadAlpha = function (x, y, a)\r
+{\r
+       "use strict";\r
+       var fn, i, j;\r
+\r
+       fn = "[PS.BeadAlpha] ";\r
+\r
+       if ( a !== undefined )\r
+       {\r
+               if ( typeof a !== "number" )\r
+               {\r
+                       PS.Oops(fn + "alpha param is not a number");\r
+                       return PS.ERROR;\r
+               }\r
+\r
+               // clamp value\r
+\r
+               a = Math.floor(a);\r
+               if ( a === PS.DEFAULT )\r
+               {\r
+                       a = PS.DEFAULT_ALPHA;\r
+               }\r
+               else if ( a !== PS.CURRENT )\r
+               {\r
+                       if ( a < 0 )\r
+                       {\r
+                               a = 0;\r
+                       }\r
+                       else if ( a > PS.DEFAULT_ALPHA )\r
+                       {\r
+                               a = PS.DEFAULT_ALPHA;\r
+                       }\r
+               }\r
+       }\r
+\r
+       if ( x === PS.ALL )\r
+       {\r
+               if ( y === PS.ALL ) // do entire grid\r
+               {\r
+                       for ( j = 0; j < PS.Grid.y; j += 1 )\r
+                       {\r
+                               for ( i = 0; i < PS.Grid.x; i += 1 )\r
+                               {\r
+                                       a = PS.DoBeadAlpha( i, j, a );\r
+                               }\r
+                       }\r
+               }\r
+               else if ( !PS.CheckY( y, fn ) ) // verify y param\r
+               {\r
+                       return PS.ERROR;\r
+               }\r
+               else\r
+               {\r
+                       for ( i = 0; i < PS.Grid.x; i += 1 ) // do entire row\r
+                       {\r
+                               a = PS.DoBeadAlpha( i, y, a );\r
+                       }\r
+               }\r
+       }\r
+       else if ( y === PS.ALL )\r
+       {\r
+               if ( !PS.CheckX( x, fn ) ) // verify x param\r
+               {\r
+                       return PS.ERROR;\r
+               }\r
+               for ( j = 0; j < PS.Grid.y; j += 1 ) // do entire column\r
+               {\r
+                       a = PS.DoBeadAlpha( x, j, a );\r
+               }\r
+       }\r
+       else if ( !PS.CheckX( x, fn ) || !PS.CheckY( y, fn ) ) // verify both params\r
+       {\r
+               return PS.ERROR;\r
+       }\r
+       else\r
+       {\r
+               a = PS.DoBeadAlpha( x, y, a ); // do one bead\r
+       }\r
+\r
+       return a;\r
+};\r
+\r
+// PS.BeadBorderWidth (x, y, width)\r
+// Returns and optionally sets a bead's border width\r
+// [x, y] are grid position\r
+// Optional [width] must be a number\r
+\r
+PS.DoBeadBorderWidth = function (x, y, width)\r
+{\r
+       "use strict";\r
+       var i, bead;\r
+\r
+       // Assume x/y params are already verified\r
+\r
+       i = x + (y * PS.Grid.x); // get index of bead\r
+       bead = PS.Grid.beads[i];\r
+\r
+       if ( (width === undefined) || (width === PS.CURRENT) ) // if no width or PS.CURRENT, return current width\r
+       {\r
+               return bead.borderWidth;\r
+       }\r
+\r
+       bead.borderWidth = width;\r
+\r
+       if ( bead.visible )\r
+       {\r
+               PS.DrawBead(bead);\r
+       }\r
+\r
+       return width;\r
+};\r
+\r
+PS.BeadBorderWidth = function (x, y, width)\r
+{\r
+       "use strict";\r
+       var fn, i, j;\r
+\r
+       fn = "[PS.BeadBorderWidth] ";\r
+\r
+       if ( width === PS.DEFAULT )\r
+       {\r
+               width = PS.DEFAULT_BORDER_WIDTH;\r
+       }\r
+       else if ( (width !== undefined) && (width !== PS.CURRENT) )\r
+       {\r
+               if ( typeof width !== "number" )\r
+               {\r
+                       PS.Oops(fn + "width param is not a number");\r
+                       return PS.ERROR;\r
+               }\r
+               width = Math.floor(width);\r
+               if ( width < 0 )\r
+               {\r
+                       width = 0;\r
+               }\r
+               else if ( width > PS.BORDER_WIDTH_MAX )\r
+               {\r
+                       width = PS.BORDER_WIDTH_MAX;\r
+               }\r
+       }\r
+\r
+       if ( x === PS.ALL )\r
+       {\r
+               if ( y === PS.ALL ) // do entire grid\r
+               {\r
+                       for ( j = 0; j < PS.Grid.y; j += 1 )\r
+                       {\r
+                               for ( i = 0; i < PS.Grid.x; i += 1 )\r
+                               {\r
+                                       width = PS.DoBeadBorderWidth( i, j, width );\r
+                               }\r
+                       }\r
+               }\r
+               else if ( !PS.CheckY( y, fn ) ) // verify y param\r
+               {\r
+                       return PS.ERROR;\r
+               }\r
+               else\r
+               {\r
+                       for ( i = 0; i < PS.Grid.x; i += 1 ) // do entire row\r
+                       {\r
+                               width = PS.DoBeadBorderWidth( i, y, width );\r
+                       }\r
+               }\r
+       }\r
+       else if ( y === PS.ALL )\r
+       {\r
+               if ( !PS.CheckX( x, fn ) ) // verify x param\r
+               {\r
+                       return PS.ERROR;\r
+               }\r
+               for ( j = 0; j < PS.Grid.y; j += 1 ) // do entire column\r
+               {\r
+                       width = PS.DoBeadBorderWidth( x, j, width );\r
+               }\r
+       }\r
+       else if ( !PS.CheckX( x, fn ) || !PS.CheckY( y, fn ) ) // verify both params\r
+       {\r
+               return PS.ERROR;\r
+       }\r
+       else\r
+       {\r
+               width = PS.DoBeadBorderWidth( x, y, width ); // do one bead\r
+       }\r
+\r
+       return width;\r
+};\r
+\r
+// PS.BeadBorderColor (x, y, rgb)\r
+// Returns and optionally sets a bead's border color\r
+// [x, y] are grid position\r
+// Optional [rgb] must be a multiplexed rgb value (0xRRGGBB)\r
+\r
+PS.DoBeadBorderColor = function (x, y, rgb, r, g, b)\r
+{\r
+       "use strict";\r
+       var i, bead;\r
+\r
+       // Assume x/y params are already verified\r
+\r
+       i = x + (y * PS.Grid.x); // get index of bead\r
+       bead = PS.Grid.beads[i];\r
+\r
+       if ( (rgb === undefined) || (rgb === PS.CURRENT) ) // if no rgb or PS.CURRENT, return current color\r
+       {\r
+               return (bead.borderRed * PS.REDSHIFT) + (bead.borderGreen * 256) + bead.borderBlue;\r
+       }\r
+\r
+       bead.borderRed = r;\r
+       bead.borderGreen = g;\r
+       bead.borderBlue = b;\r
+       if ( bead.borderAlpha < PS.DEFAULT_ALPHA )\r
+       {\r
+               r = PS.Dissolve( PS.Grid.bgRed, r, bead.borderAlpha );\r
+               g = PS.Dissolve( PS.Grid.bgGreen, g, bead.borderAlpha );\r
+               b = PS.Dissolve( PS.Grid.bgBlue, b, bead.borderAlpha );\r
+       }\r
+       bead.borderColor = PS.RGBString( r, g, b );\r
+\r
+       if ( bead.visible )\r
+       {\r
+               PS.DrawBead(bead);\r
+       }\r
+\r
+       return rgb;\r
+};\r
+\r
+PS.BeadBorderColor = function (x, y, rgb)\r
+{\r
+       "use strict";\r
+       var fn, colors, r, g, b, i, j;\r
+\r
+       fn = "[PS.BeadBorderColor] ";\r
+\r
+       if ( rgb === PS.DEFAULT )\r
+       {\r
+               rgb = PS.DEFAULT_BORDER_COLOR;\r
+               r = PS.DEFAULT_BORDER_RED;\r
+               g = PS.DEFAULT_BORDER_GREEN;\r
+               b = PS.DEFAULT_BORDER_BLUE;\r
+       }\r
+       else if ( (rgb !== undefined) && (rgb !== PS.CURRENT) )\r
+       {\r
+               rgb = PS.ValidRGB( rgb, fn );\r
+               if ( rgb < 0 )\r
+               {\r
+                       return PS.ERROR;\r
+               }\r
+               colors = PS.UnmakeRGB( rgb );\r
+               r = colors.r;\r
+               g = colors.g;\r
+               b = colors.b;\r
+       }\r
+\r
+       if ( x === PS.ALL )\r
+       {\r
+               if ( y === PS.ALL ) // do entire grid\r
+               {\r
+                       for ( j = 0; j < PS.Grid.y; j += 1 )\r
+                       {\r
+                               for ( i = 0; i < PS.Grid.x; i += 1 )\r
+                               {\r
+                                       rgb = PS.DoBeadBorderColor( i, j, rgb, r, g, b );\r
+                               }\r
+                       }\r
+               }\r
+               else if ( !PS.CheckY( y, fn ) ) // verify y param\r
+               {\r
+                       return PS.ERROR;\r
+               }\r
+               else\r
+               {\r
+                       for ( i = 0; i < PS.Grid.x; i += 1 ) // do entire row\r
+                       {\r
+                               rgb = PS.DoBeadBorderColor( i, y, rgb, r, g, b );\r
+                       }\r
+               }\r
+       }\r
+       else if ( y === PS.ALL )\r
+       {\r
+               if ( !PS.CheckX( x, fn ) ) // verify x param\r
+               {\r
+                       return PS.ERROR;\r
+               }\r
+               for ( j = 0; j < PS.Grid.y; j += 1 ) // do entire column\r
+               {\r
+                       rgb = PS.DoBeadBorderColor( x, j, rgb, r, g, b );\r
+               }\r
+       }\r
+       else if ( !PS.CheckX( x, fn ) || !PS.CheckY( y, fn ) ) // verify both params\r
+       {\r
+               return PS.ERROR;\r
+       }\r
+       else\r
+       {\r
+               rgb = PS.DoBeadBorderColor( x, y, rgb, r, g, b ); // do one bead\r
+       }\r
+\r
+       return rgb;\r
+};\r
+\r
+// PS.BeadBorderAlpha(x, y, a)\r
+// Returns a bead's border alpha and optionally changes it\r
+// [x, y] are grid position\r
+// Optional [a] must be a number between 0.0 and 1.0\r
+\r
+PS.DoBeadBorderAlpha = function (x, y, a)\r
+{\r
+       "use strict";\r
+       var i, bead, r, g, b;\r
+\r
+       // Assume x/y params are already verified\r
+\r
+       i = x + (y * PS.Grid.x); // get index of bead\r
+       bead = PS.Grid.beads[i];\r
+\r
+       if ( (a === undefined) || (a === PS.CURRENT) || (a === bead.borderAlpha) )\r
+       {\r
+               return bead.borderAlpha;\r
+       }\r
+\r
+       bead.borderAlpha = a;\r
+       if ( a < PS.DEFAULT_ALPHA )\r
+       {\r
+               r = PS.Dissolve( PS.Grid.bgRed, bead.borderRed, a );\r
+               g = PS.Dissolve( PS.Grid.bgGreen, bead.borderGreen, a );\r
+               b = PS.Dissolve( PS.Grid.bgBlue, bead.borderBlue, a );\r
+               bead.borderColor = PS.RGBString( r, g, b );\r
+       }\r
+       else\r
+       {\r
+               bead.borderColor = PS.RGBString( bead.borderRed, bead.borderGreen, bead.borderBlue );\r
+       }\r
+       if ( bead.visible )\r
+       {\r
+               PS.DrawBead(bead);\r
+       }\r
+       return a;\r
+};\r
+\r
+PS.BeadBorderAlpha = function (x, y, a)\r
+{\r
+       "use strict";\r
+       var fn, i, j;\r
+\r
+       fn = "[PS.BeadBorderAlpha] ";\r
+\r
+       if ( a !== undefined )\r
+       {\r
+               if ( typeof a !== "number" )\r
+               {\r
+                       PS.Oops(fn + "alpha param is not a number");\r
+                       return PS.ERROR;\r
+               }\r
+\r
+               // clamp value\r
+\r
+               a = Math.floor(a);\r
+               if ( a === PS.DEFAULT )\r
+               {\r
+                       a = PS.DEFAULT_ALPHA;\r
+               }\r
+               else if ( a !== PS.CURRENT )\r
+               {\r
+                       if ( a < 0 )\r
+                       {\r
+                               a = 0;\r
+                       }\r
+                       else if ( a > PS.DEFAULT_ALPHA )\r
+                       {\r
+                               a = PS.DEFAULT_ALPHA;\r
+                       }\r
+               }\r
+       }\r
+\r
+       if ( x === PS.ALL )\r
+       {\r
+               if ( y === PS.ALL ) // do entire grid\r
+               {\r
+                       for ( j = 0; j < PS.Grid.y; j += 1 )\r
+                       {\r
+                               for ( i = 0; i < PS.Grid.x; i += 1 )\r
+                               {\r
+                                       a = PS.DoBeadBorderAlpha( i, j, a );\r
+                               }\r
+                       }\r
+               }\r
+               else if ( !PS.CheckY( y, fn ) ) // verify y param\r
+               {\r
+                       return PS.ERROR;\r
+               }\r
+               else\r
+               {\r
+                       for ( i = 0; i < PS.Grid.x; i += 1 ) // do entire row\r
+                       {\r
+                               a = PS.DoBeadBorderAlpha( i, y, a );\r
+                       }\r
+               }\r
+       }\r
+       else if ( y === PS.ALL )\r
+       {\r
+               if ( !PS.CheckX( x, fn ) ) // verify x param\r
+               {\r
+                       return PS.ERROR;\r
+               }\r
+               for ( j = 0; j < PS.Grid.y; j += 1 ) // do entire column\r
+               {\r
+                       a = PS.DoBeadBorderAlpha( x, j, a );\r
+               }\r
+       }\r
+       else if ( !PS.CheckX( x, fn ) || !PS.CheckY( y, fn ) ) // verify both params\r
+       {\r
+               return PS.ERROR;\r
+       }\r
+       else\r
+       {\r
+               a = PS.DoBeadBorderAlpha( x, y, a ); // do one bead\r
+       }\r
+\r
+       return a;\r
+};\r
+\r
+// PS.BeadGlyph(x, y, g)\r
+// Returns a bead's glyph and optionally changes it\r
+// [x, y] are grid position\r
+// Optional [g] must be either a string or a number\r
+\r
+PS.DoBeadGlyph = function (x, y, g)\r
+{\r
+       "use strict";\r
+       var i, bead;\r
+\r
+       // Assume x/y params are already verified\r
+\r
+       i = x + (y * PS.Grid.x); // get index of bead\r
+       bead = PS.Grid.beads[i];\r
+\r
+       if ( (g === undefined) || (g === PS.CURRENT) || (g === bead.glyph) )\r
+       {\r
+               return bead.glyph;\r
+       }\r
+\r
+       bead.glyph = g;\r
+       bead.glyphStr = String.fromCharCode(g);\r
+       if ( bead.visible )\r
+       {\r
+               if ( PS.Grid.flash && bead.flash )\r
+               {\r
+                       PS.FlashStart(x, y);\r
+               }\r
+               else\r
+               {\r
+                       bead.colorNow = bead.color;\r
+                       PS.DrawBead(bead);\r
+               }\r
+       }\r
+\r
+       return g;\r
+};\r
+\r
+PS.BeadGlyph = function (x, y, g)\r
+{\r
+       "use strict";\r
+       var fn, type, i, j;\r
+\r
+       fn = "[PS.BeadGlyph] ";\r
+\r
+       // if no glyph specified, just return current border status\r
+\r
+       type = typeof g;\r
+       if ( type !== "undefined" )\r
+       {\r
+               if ( type === "string" )\r
+               {\r
+                       if ( g.length < 1 )\r
+                       {\r
+                               PS.Oops(fn + "glyph param is empty string");\r
+                               return 0;\r
+                       }\r
+                       g = g.charCodeAt(0); // use only first character\r
+               }\r
+               else if ( type === "number" )\r
+               {\r
+                       g = Math.floor(g);\r
+                       if ( g === PS.DEFAULT )\r
+                       {\r
+                               g = 0;\r
+                       }\r
+                       else if ( g !== PS.CURRENT )\r
+                       {\r
+                               if ( g < 0 )\r
+                               {\r
+                                       g = 0;\r
+                               }\r
+                       }\r
+               }\r
+               else\r
+               {\r
+                       PS.Oops(fn + "glyph param not a string or number");\r
+                       return PS.ERROR;\r
+               }\r
+       }\r
+\r
+       if ( x === PS.ALL )\r
+       {\r
+               if ( y === PS.ALL ) // do entire grid\r
+               {\r
+                       for ( j = 0; j < PS.Grid.y; j += 1 )\r
+                       {\r
+                               for ( i = 0; i < PS.Grid.x; i += 1 )\r
+                               {\r
+                                       g = PS.DoBeadGlyph( i, j, g );\r
+                               }\r
+                       }\r
+               }\r
+               else if ( !PS.CheckY( y, fn ) ) // verify y param\r
+               {\r
+                       return PS.ERROR;\r
+               }\r
+               else\r
+               {\r
+                       for ( i = 0; i < PS.Grid.x; i += 1 ) // do entire row\r
+                       {\r
+                               g = PS.DoBeadGlyph( i, y, g );\r
+                       }\r
+               }\r
+       }\r
+       else if ( y === PS.ALL )\r
+       {\r
+               if ( !PS.CheckX( x, fn ) ) // verify x param\r
+               {\r
+                       return PS.ERROR;\r
+               }\r
+               for ( j = 0; j < PS.Grid.y; j += 1 ) // do entire column\r
+               {\r
+                       g = PS.DoBeadGlyph( x, j, g );\r
+               }\r
+       }\r
+       else if ( !PS.CheckX( x, fn ) || !PS.CheckY( y, fn ) ) // verify both params\r
+       {\r
+               return PS.ERROR;\r
+       }\r
+       else\r
+       {\r
+               g = PS.DoBeadGlyph( x, y, g ); // do one bead\r
+       }\r
+\r
+       return g;\r
+};\r
+\r
+// PS.BeadGlyphColor (x, y, rgb)\r
+// Returns and optionally sets a bead's glyph color\r
+// [x, y] are grid position\r
+// Optional [rgb] must be a multiplexed rgb value (0xRRGGBB)\r
+\r
+PS.DoBeadGlyphColor = function (x, y, rgb, r, g, b)\r
+{\r
+       "use strict";\r
+       var i, bead;\r
+\r
+       // Assume x/y params are already verified\r
+\r
+       i = x + (y * PS.Grid.x); // get index of bead\r
+       bead = PS.Grid.beads[i];\r
+\r
+       if ( (rgb === undefined) || (rgb === PS.CURRENT) ) // if no rgb or PS.CURRENT, return current color\r
+       {\r
+               return (bead.glyphRed * PS.REDSHIFT) + (bead.glyphGreen * 256) + bead.glyphBlue;\r
+       }\r
+\r
+       bead.glyphRed = r;\r
+       bead.glyphGreen = g;\r
+       bead.glyphBlue = b;\r
+       if ( bead.alpha < PS.DEFAULT_ALPHA ) // Calc new color based on alpha\r
+       {\r
+               r = PS.Dissolve( PS.Grid.bgRed, r, bead.alpha );\r
+               g = PS.Dissolve( PS.Grid.bgGreen, g, bead.alpha );\r
+               b = PS.Dissolve( PS.Grid.bgBlue, b, bead.alpha );\r
+       }\r
+       bead.glyphColor = PS.RGBString( r, g, b );\r
+\r
+       if ( bead.visible && (bead.glyph > 0) )\r
+       {\r
+               PS.DrawBead(bead);\r
+       }\r
+       return rgb;\r
+};\r
+\r
+PS.BeadGlyphColor = function (x, y, rgb)\r
+{\r
+       "use strict";\r
+       var fn, colors, r, g, b, i, j;\r
+\r
+       fn = "[PS.BeadGlyphColor] ";\r
+\r
+       if ( rgb === PS.DEFAULT )\r
+       {\r
+               rgb = PS.DEFAULT_GLYPH_COLOR;\r
+               r = PS.DEFAULT_GLYPH_RED;\r
+               g = PS.DEFAULT_GLYPH_GREEN;\r
+               b = PS.DEFAULT_GLYPH_BLUE;\r
+       }\r
+       else if ( (rgb !== undefined) && (rgb !== PS.CURRENT) )\r
+       {\r
+               rgb = PS.ValidRGB( rgb, fn );\r
+               if ( rgb < 0 )\r
+               {\r
+                       return PS.ERROR;\r
+               }\r
+               colors = PS.UnmakeRGB( rgb );\r
+               r = colors.r;\r
+               g = colors.g;\r
+               b = colors.b;\r
+       }\r
+\r
+       if ( x === PS.ALL )\r
+       {\r
+               if ( y === PS.ALL ) // do entire grid\r
+               {\r
+                       for ( j = 0; j < PS.Grid.y; j += 1 )\r
+                       {\r
+                               for ( i = 0; i < PS.Grid.x; i += 1 )\r
+                               {\r
+                                       rgb = PS.DoBeadGlyphColor( i, j, rgb, r, g, b );\r
+                               }\r
+                       }\r
+               }\r
+               else if ( !PS.CheckY( y, fn ) ) // verify y param\r
+               {\r
+                       return PS.ERROR;\r
+               }\r
+               else\r
+               {\r
+                       for ( i = 0; i < PS.Grid.x; i += 1 ) // do entire row\r
+                       {\r
+                               rgb = PS.DoBeadGlyphColor( i, y, rgb, r, g, b );\r
+                       }\r
+               }\r
+       }\r
+       else if ( y === PS.ALL )\r
+       {\r
+               if ( !PS.CheckX( x, fn ) ) // verify x param\r
+               {\r
+                       return PS.ERROR;\r
+               }\r
+               for ( j = 0; j < PS.Grid.y; j += 1 ) // do entire column\r
+               {\r
+                       rgb = PS.DoBeadGlyphColor( x, j, rgb, r, g, b );\r
+               }\r
+       }\r
+       else if ( !PS.CheckX( x, fn ) || !PS.CheckY( y, fn ) ) // verify both params\r
+       {\r
+               return PS.ERROR;\r
+       }\r
+       else\r
+       {\r
+               rgb = PS.DoBeadGlyphColor( x, y, rgb, r, g, b ); // do one bead\r
+       }\r
+\r
+       return rgb;\r
+};\r
+\r
+// PS.BeadFlash(x, y, flag)\r
+// Returns a bead's flash status and optionally changes it\r
+// [x, y] are grid position\r
+// Optional [flag] must be 1/true or 0/false\r
+\r
+PS.DoBeadFlash = function (x, y, flag)\r
+{\r
+       "use strict";\r
+       var i, bead;\r
+\r
+       // Assume x/y params are already verified\r
+\r
+       i = x + (y * PS.Grid.x); // get index of bead\r
+       bead = PS.Grid.beads[i];\r
+\r
+       if ( (flag === undefined) || (flag === PS.CURRENT) )\r
+       {\r
+               return bead.flash;\r
+       }\r
+\r
+       bead.flash = flag;\r
+       return flag;\r
+};\r
+\r
+PS.BeadFlash = function (x, y, flag)\r
+{\r
+       "use strict";\r
+       var fn, i, j;\r
+\r
+       fn = "[PS.BeadFlash] ";\r
+\r
+       // normalize flag value to t/f if defined\r
+\r
+       if ( (flag !== undefined) && (flag !== PS.CURRENT) )\r
+       {\r
+               if ( flag === PS.DEFAULT )\r
+               {\r
+                       flag = true;\r
+               }\r
+               else if ( flag )\r
+               {\r
+                       flag = true;\r
+               }\r
+               else\r
+               {\r
+                       flag = false;\r
+               }\r
+       }\r
+\r
+       if ( x === PS.ALL )\r
+       {\r
+               if ( y === PS.ALL ) // do entire grid\r
+               {\r
+                       for ( j = 0; j < PS.Grid.y; j += 1 )\r
+                       {\r
+                               for ( i = 0; i < PS.Grid.x; i += 1 )\r
+                               {\r
+                                       flag = PS.DoBeadFlash( i, j, flag );\r
+                               }\r
+                       }\r
+               }\r
+               else if ( !PS.CheckY( y, fn ) ) // verify y param\r
+               {\r
+                       return PS.ERROR;\r
+               }\r
+               else\r
+               {\r
+                       for ( i = 0; i < PS.Grid.x; i += 1 ) // do entire row\r
+                       {\r
+                               flag = PS.DoBeadFlash( i, y, flag );\r
+                       }\r
+               }\r
+       }\r
+       else if ( y === PS.ALL )\r
+       {\r
+               if ( !PS.CheckX( x, fn ) ) // verify x param\r
+               {\r
+                       return PS.ERROR;\r
+               }\r
+               for ( j = 0; j < PS.Grid.y; j += 1 ) // do entire column\r
+               {\r
+                       flag = PS.DoBeadFlash( x, j, flag );\r
+               }\r
+       }\r
+       else if ( !PS.CheckX( x, fn ) || !PS.CheckY( y, fn ) ) // verify both params\r
+       {\r
+               return PS.ERROR;\r
+       }\r
+       else\r
+       {\r
+               flag = PS.DoBeadFlash( x, y, flag ); // do one bead\r
+       }\r
+\r
+       return flag;\r
+};\r
+\r
+// PS.BeadFlashColor (x, y, rgb)\r
+// Returns and optionally sets a bead's flash color\r
+// [x, y] are grid position\r
+// Optional [rgb] must be a multiplexed rgb value (0xRRGGBB)\r
+\r
+PS.DoBeadFlashColor = function (x, y, rgb, r, g, b)\r
+{\r
+       "use strict";\r
+       var i, bead;\r
+\r
+       // Assume x/y params are already verified\r
+\r
+       i = x + (y * PS.Grid.x); // get index of bead\r
+       bead = PS.Grid.beads[i];\r
+\r
+       if ( (rgb === undefined) || (rgb === PS.CURRENT) ) // if no rgb or PS.CURRENT, return current color\r
+       {\r
+               return (bead.flashRed * PS.REDSHIFT) + (bead.flashGreen * 256) + bead.flashBlue;\r
+       }\r
+\r
+       bead.flashRed = r;\r
+       bead.flashGreen = g;\r
+       bead.flashBlue = b;\r
+       bead.flashColor = PS.RGBString(r, g, b);\r
+\r
+       return rgb;\r
+};\r
+\r
+PS.BeadFlashColor = function (x, y, rgb)\r
+{\r
+       "use strict";\r
+       var fn, r, g, b, colors, i, j;\r
+\r
+       fn = "[PS.BeadFlashColor] ";\r
+\r
+       if ( rgb === PS.DEFAULT )\r
+       {\r
+               rgb = PS.DEFAULT_FLASH_COLOR;\r
+               r = PS.DEFAULT_FLASH_RED;\r
+               g = PS.DEFAULT_FLASH_GREEN;\r
+               b = PS.DEFAULT_FLASH_BLUE;\r
+       }\r
+       else if ( (rgb !== undefined) && (rgb !== PS.CURRENT) )\r
+       {\r
+               rgb = PS.ValidRGB( rgb, fn );\r
+               if ( rgb < 0 )\r
+               {\r
+                       return PS.ERROR;\r
+               }\r
+               colors = PS.UnmakeRGB( rgb );\r
+               r = colors.r;\r
+               g = colors.g;\r
+               b = colors.b;\r
+       }\r
+\r
+       if ( x === PS.ALL )\r
+       {\r
+               if ( y === PS.ALL ) // do entire grid\r
+               {\r
+                       for ( j = 0; j < PS.Grid.y; j += 1 )\r
+                       {\r
+                               for ( i = 0; i < PS.Grid.x; i += 1 )\r
+                               {\r
+                                       rgb = PS.DoBeadFlashColor( i, j, rgb, r, g, b );\r
+                               }\r
+                       }\r
+               }\r
+               else if ( !PS.CheckY( y, fn ) ) // verify y param\r
+               {\r
+                       return PS.ERROR;\r
+               }\r
+               else\r
+               {\r
+                       for ( i = 0; i < PS.Grid.x; i += 1 ) // do entire row\r
+                       {\r
+                               rgb = PS.DoBeadFlashColor( i, y, rgb, r, g, b );\r
+                       }\r
+               }\r
+       }\r
+       else if ( y === PS.ALL )\r
+       {\r
+               if ( !PS.CheckX( x, fn ) ) // verify x param\r
+               {\r
+                       return PS.ERROR;\r
+               }\r
+               for ( j = 0; j < PS.Grid.y; j += 1 ) // do entire column\r
+               {\r
+                       rgb = PS.DoBeadFlashColor( x, j, rgb, r, g, b );\r
+               }\r
+       }\r
+       else if ( !PS.CheckX( x, fn ) || !PS.CheckY( y, fn ) ) // verify both params\r
+       {\r
+               return PS.ERROR;\r
+       }\r
+       else\r
+       {\r
+               rgb = PS.DoBeadFlashColor( x, y, rgb, r, g, b ); // do one bead\r
+       }\r
+\r
+       return rgb;\r
+};\r
+\r
+// PS.BeadData(x, y, data)\r
+// Returns a bead's data and optionally changes it\r
+// [x, y] are grid position\r
+// Optional [data] can be any data type\r
+\r
+PS.DoBeadData = function (x, y, data)\r
+{\r
+       "use strict";\r
+       var i, bead;\r
+\r
+       // Assume x/y params are already verified\r
+\r
+       i = x + (y * PS.Grid.x); // get index of bead\r
+       bead = PS.Grid.beads[i];\r
+\r
+       if ( data !== undefined )\r
+       {\r
+               bead.data = data;\r
+       }\r
+\r
+       return bead.data;\r
+};\r
+\r
+PS.BeadData = function (x, y, data)\r
+{\r
+       "use strict";\r
+       var fn, i, j;\r
+\r
+       fn = "[PS.BeadData] ";\r
+\r
+       if ( x === PS.ALL )\r
+       {\r
+               if ( y === PS.ALL ) // do entire grid\r
+               {\r
+                       for ( j = 0; j < PS.Grid.y; j += 1 )\r
+                       {\r
+                               for ( i = 0; i < PS.Grid.x; i += 1 )\r
+                               {\r
+                                       data = PS.DoBeadData( i, j, data );\r
+                               }\r
+                       }\r
+               }\r
+               else if ( !PS.CheckY( y, fn ) ) // verify y param\r
+               {\r
+                       return PS.ERROR;\r
+               }\r
+               else\r
+               {\r
+                       for ( i = 0; i < PS.Grid.x; i += 1 ) // do entire row\r
+                       {\r
+                               data = PS.DoBeadData( i, y, data );\r
+                       }\r
+               }\r
+       }\r
+       else if ( y === PS.ALL )\r
+       {\r
+               if ( !PS.CheckX( x, fn ) ) // verify x param\r
+               {\r
+                       return PS.ERROR;\r
+               }\r
+               for ( j = 0; j < PS.Grid.y; j += 1 ) // do entire column\r
+               {\r
+                       data = PS.DoBeadData( x, j, data );\r
+               }\r
+       }\r
+       else if ( !PS.CheckX( x, fn ) || !PS.CheckY( y, fn ) ) // verify both params\r
+       {\r
+               return PS.ERROR;\r
+       }\r
+       else\r
+       {\r
+               data = PS.DoBeadData( x, y, data ); // do one bead\r
+       }\r
+\r
+       return data;\r
+};\r
+\r
+// PS.BeadAudio(x, y, audio, volume)\r
+// Returns a bead's audio file and optionally changes it (and its volume)\r
+// [x, y] are grid position\r
+// Optional [audio] must be a string\r
+// Optional [volume] should be between 0 and 100 inclusive\r
+\r
+PS.DoBeadAudio = function (x, y, audio, volume)\r
+{\r
+       "use strict";\r
+       var i, bead;\r
+\r
+       // Assume x/y params are already verified\r
+\r
+       i = x + (y * PS.Grid.x); // get index of bead\r
+       bead = PS.Grid.beads[i];\r
+\r
+       if ( (audio !== undefined) && (audio !== PS.CURRENT) )\r
+       {\r
+               bead.audio = audio;\r
+       }\r
+\r
+       if ( (volume !== undefined) && (volume !== PS.CURRENT) )\r
+       {\r
+               bead.volume = volume;\r
+       }\r
+\r
+       return bead.audio;\r
+};\r
+\r
+PS.BeadAudio = function (x, y, audio, volume)\r
+{\r
+       "use strict";\r
+       var fn, i, j;\r
+\r
+       fn = "[PS.BeadAudio] ";\r
+\r
+       // check audio file param\r
+\r
+       if ( (audio !== undefined) && (audio !== PS.CURRENT) )\r
+       {\r
+               if ( audio === PS.DEFAULT )\r
+               {\r
+                       audio = null;\r
+               }\r
+               else if ( typeof audio !== "string" )\r
+               {\r
+                       PS.Oops(fn + "audio param is not a string");\r
+                       return PS.ERROR;\r
+               }\r
+               else if ( audio.length < 1 )\r
+               {\r
+                       audio = null;\r
+               }\r
+       }\r
+\r
+       // check volume param\r
+\r
+       if ( (volume !== undefined) && (volume !== PS.CURRENT) )\r
+       {\r
+               if ( volume === PS.DEFAULT )\r
+               {\r
+                       volume = PS.DEFAULT_VOLUME;\r
+               }\r
+               else if ( typeof volume !== "number" )\r
+               {\r
+                       PS.Oops(fn + "volume param is not a number");\r
+                       return PS.ERROR;\r
+               }\r
+               else\r
+               {\r
+                       if ( volume < 0 )\r
+                       {\r
+                               volume = 0;\r
+                       }\r
+                       else if ( volume > PS.DEFAULT_VOLUME )\r
+                       {\r
+                               volume = PS.DEFAULT_VOLUME;\r
+                       }\r
+               }\r
+       }\r
+       \r
+       if ( x === PS.ALL )\r
+       {\r
+               if ( y === PS.ALL ) // do entire grid\r
+               {\r
+                       for ( j = 0; j < PS.Grid.y; j += 1 )\r
+                       {\r
+                               for ( i = 0; i < PS.Grid.x; i += 1 )\r
+                               {\r
+                                       audio = PS.DoBeadAudio( i, j, audio, volume );\r
+                               }\r
+                       }\r
+               }\r
+               else if ( !PS.CheckY( y, fn ) ) // verify y param\r
+               {\r
+                       return PS.ERROR;\r
+               }\r
+               else\r
+               {\r
+                       for ( i = 0; i < PS.Grid.x; i += 1 ) // do entire row\r
+                       {\r
+                               audio = PS.DoBeadAudio( i, y, audio, volume );\r
+                       }\r
+               }\r
+       }\r
+       else if ( y === PS.ALL )\r
+       {\r
+               if ( !PS.CheckX( x, fn ) ) // verify x param\r
+               {\r
+                       return PS.ERROR;\r
+               }\r
+               for ( j = 0; j < PS.Grid.y; j += 1 ) // do entire column\r
+               {\r
+                       audio = PS.DoBeadAudio( x, j, audio, volume );\r
+               }\r
+       }\r
+       else if ( !PS.CheckX( x, fn ) || !PS.CheckY( y, fn ) ) // verify both params\r
+       {\r
+               return PS.ERROR;\r
+       }\r
+       else\r
+       {\r
+               audio = PS.DoBeadAudio( x, y, audio, volume ); // do one bead\r
+       }\r
+\r
+       return audio;\r
+};\r
+\r
+// PS.BeadFunction(x, y, func)\r
+// Returns a bead's exec function and optionally changes it\r
+// [x, y] are grid position\r
+// Optional [func] must be a JavaScript function\r
+\r
+PS.DoBeadFunction = function (x, y, exec)\r
+{\r
+       "use strict";\r
+       var i, bead;\r
+\r
+       // Assume x/y params are already verified\r
+\r
+       i = x + (y * PS.Grid.x); // get index of bead\r
+       bead = PS.Grid.beads[i];\r
+\r
+       if ( (exec !== undefined) && (exec !== PS.CURRENT) )\r
+       {\r
+               bead.exec = exec;\r
+       }\r
+\r
+       return bead.exec;\r
+};\r
+\r
+PS.BeadFunction = function (x, y, exec)\r
+{\r
+       "use strict";\r
+       var fn, i, j;\r
+\r
+       fn = "[PS.BeadFunction] ";\r
+\r
+       if ( (exec !== undefined) || (exec !== PS.CURRENT) )\r
+       {\r
+               if ( exec === PS.DEFAULT )\r
+               {\r
+                       exec = null;\r
+               }\r
+               else if ( typeof exec !== "function" )\r
+               {\r
+                       PS.Oops(fn + "exec param not a valid function");\r
+                       return PS.ERROR;\r
+               }\r
+       }\r
+\r
+       if ( x === PS.ALL )\r
+       {\r
+               if ( y === PS.ALL ) // do entire grid\r
+               {\r
+                       for ( j = 0; j < PS.Grid.y; j += 1 )\r
+                       {\r
+                               for ( i = 0; i < PS.Grid.x; i += 1 )\r
+                               {\r
+                                       exec = PS.DoBeadFunction( i, j, exec );\r
+                               }\r
+                       }\r
+               }\r
+               else if ( !PS.CheckY( y, fn ) ) // verify y param\r
+               {\r
+                       return PS.ERROR;\r
+               }\r
+               else\r
+               {\r
+                       for ( i = 0; i < PS.Grid.x; i += 1 ) // do entire row\r
+                       {\r
+                               exec = PS.DoBeadFunction( i, y, exec );\r
+                       }\r
+               }\r
+       }\r
+       else if ( y === PS.ALL )\r
+       {\r
+               if ( !PS.CheckX( x, fn ) ) // verify x param\r
+               {\r
+                       return PS.ERROR;\r
+               }\r
+               for ( j = 0; j < PS.Grid.y; j += 1 ) // do entire column\r
+               {\r
+                       exec = PS.DoBeadFunction( x, j, exec );\r
+               }\r
+       }\r
+       else if ( !PS.CheckX( x, fn ) || !PS.CheckY( y, fn ) ) // verify both params\r
+       {\r
+               return PS.ERROR;\r
+       }\r
+       else\r
+       {\r
+               exec = PS.DoBeadFunction( x, y, exec ); // do one bead\r
+       }\r
+\r
+       return exec;\r
+};\r
+\r
+// PS.BeadTouch(x, y, mask)\r
+// Simulates effect of clicking on a bead\r
+// [x, y] are grid position\r
+\r
+PS.DoBeadTouch = function (x, y)\r
+{\r
+       "use strict";\r
+       var i, bead;\r
+\r
+       // Assume x/y params are already verified\r
+\r
+       i = x + (y * PS.Grid.x); // get index of bead\r
+       bead = PS.Grid.beads[i];\r
+\r
+       // Play bead audio\r
+\r
+       if ( typeof bead.audio === "string" )\r
+       {\r
+               PS.AudioPlay(bead.audio, bead.volume);\r
+       }\r
+\r
+       // Run bead exec\r
+\r
+       if ( typeof bead.exec === "function" )\r
+       {\r
+               bead.exec(x, y, bead.data);\r
+       }\r
+\r
+       // Simulate click\r
+\r
+       PS.Click(x, y, bead.data);\r
+};\r
+\r
+PS.BeadTouch = function (x, y)\r
+{\r
+       "use strict";\r
+       var fn, i, j;\r
+\r
+       fn = "[PS.BeadTouch] ";\r
+\r
+       if ( x === PS.ALL )\r
+       {\r
+               if ( y === PS.ALL ) // do entire grid\r
+               {\r
+                       for ( j = 0; j < PS.Grid.y; j += 1 )\r
+                       {\r
+                               for ( i = 0; i < PS.Grid.x; i += 1 )\r
+                               {\r
+                                       PS.DoBeadTouch( i, j );\r
+                               }\r
+                       }\r
+               }\r
+               else if ( !PS.CheckY( y, fn ) ) // verify y param\r
+               {\r
+                       return;\r
+               }\r
+               else\r
+               {\r
+                       for ( i = 0; i < PS.Grid.x; i += 1 ) // do entire row\r
+                       {\r
+                               PS.DoBeadTouch( i, y );\r
+                       }\r
+               }\r
+       }\r
+       else if ( y === PS.ALL )\r
+       {\r
+               if ( !PS.CheckX( x, fn ) ) // verify x param\r
+               {\r
+                       return;\r
+               }\r
+               for ( j = 0; j < PS.Grid.y; j += 1 ) // do entire column\r
+               {\r
+                       PS.DoBeadTouch( x, j );\r
+               }\r
+       }\r
+       else if ( !PS.CheckX( x, fn ) || !PS.CheckY( y, fn ) ) // verify both params\r
+       {\r
+               return;\r
+       }\r
+       else\r
+       {\r
+               PS.DoBeadTouch( x, y ); // do one bead\r
+       }\r
+};\r
+\r
+// Set message text\r
+\r
+PS.Status = "Perlenspiel";\r
+PS.StatusHue = 0;\r
+\r
+PS.StatusText = function (str)\r
+{\r
+       "use strict";\r
+       var fn, type, e;\r
+\r
+       fn = "[PS.StatusText] ";\r
+\r
+       type = typeof str;\r
+       if ( type !== "undefined" )\r
+       {\r
+               if ( type !== "string" )\r
+               {\r
+                       PS.Oops(fn + "Parameter is not a string");\r
+               }\r
+               else\r
+               {\r
+                       e = document.getElementById("status");\r
+                       if ( e )\r
+                       {\r
+                               if ( PS.StatusFading ) // start the fade\r
+                               {\r
+                                       e.style.color = PS.Grid.bgColor;\r
+                                       PS.StatusPhase = 0;\r
+                               }\r
+                               e.value = str;                                                  \r
+                       }\r
+                       PS.Status = str;\r
+               }\r
+       }\r
+       return PS.Status;\r
+};\r
+\r
+PS.StatusColor = function (rgb)\r
+{\r
+       "use strict";\r
+       var fn, colors, e;\r
+\r
+       fn = "[PS.StatusText] ";\r
+\r
+       if ( (rgb !== undefined) && (rgb !== PS.CURRENT) )\r
+       {\r
+               rgb = PS.ValidRGB( rgb, fn );\r
+               if ( rgb < 0 )\r
+               {\r
+                       return PS.ERROR;\r
+               }\r
+               if ( rgb === PS.DEFAULT )\r
+               {\r
+                       rgb = PS.DEFAULT_TEXT_COLOR;\r
+               }\r
+               colors = PS.UnmakeRGB(rgb);\r
+               PS.StatusRed = colors.r;\r
+               PS.StatusGreen = colors.g;\r
+               PS.StatusBlue = colors.b;\r
+               PS.StatusHue = PS.RGBString(colors.r, colors.g, colors.b);\r
+               PS.StatusPhase = 100; // stops fades in progress\r
+               \r
+               e = document.getElementById("status");\r
+               if ( e )\r
+               {\r
+                       e.style.color = PS.StatusHue;\r
+               }\r
+               e = document.getElementById("footer");\r
+               if ( e )\r
+               {\r
+                       e.style.color = PS.StatusHue;\r
+               }\r
+       }\r
+\r
+       return PS.StatusHue;\r
+};\r
+\r
+// Turn status line fading on and off\r
+\r
+PS.StatusFade = function (flag)\r
+{\r
+       "use strict";\r
+       var fn, e;\r
+\r
+       fn = "[PS.StatusFade] ";\r
+\r
+       if ( (flag !== undefined) && (flag !== PS.CURRENT) )\r
+       {\r
+               if ( flag || (flag === PS.DEFAULT) )\r
+               {\r
+                       flag = true;\r
+               }\r
+               else\r
+               {\r
+                       flag = false;\r
+                       PS.StatusPhase = 100;\r
+                       e = document.getElementById("status");\r
+                       if ( e )\r
+                       {\r
+                               e.style.color = PS.StatusHue;\r
+                       }                       \r
+               }\r
+               PS.StatusFading = flag;\r
+       }\r
+\r
+       return PS.StatusFading;\r
+};\r
+\r
+// Debugger API\r
+\r
+// Open debugger if not already open\r
+\r
+PS.DebugOpen = function ()\r
+{\r
+       "use strict";\r
+       var div, e;\r
+\r
+       if ( !PS.DebugWindow )\r
+       {\r
+               div = document.getElementById("debug");\r
+               div.style.display = "inline";\r
+\r
+               // clear it\r
+\r
+               e = document.getElementById("monitor");\r
+               if ( e )\r
+               {\r
+                       e.value = "";\r
+               }\r
+\r
+               PS.DebugWindow = true;\r
+       }\r
+};\r
+\r
+// Close debugger if not already closed\r
+\r
+PS.DebugClose = function ()\r
+{\r
+       "use strict";\r
+       var e;\r
+\r
+       if ( PS.DebugWindow )\r
+       {\r
+               e = document.getElementById("debug");\r
+               e.style.display = "none";\r
+               PS.DebugWindow = false;\r
+       }\r
+};\r
+\r
+// Add line to debugger (does not include CR)\r
+\r
+PS.Debug = function (str)\r
+{\r
+       "use strict";\r
+       var e;\r
+\r
+       if ( typeof str !== "string" )\r
+       {\r
+               return;\r
+       }\r
+\r
+       PS.DebugOpen();\r
+\r
+       e = document.getElementById("monitor");\r
+       if ( e )\r
+       {\r
+               e.value += str; // add it\r
+               e.scrollTop = e.scrollHeight; // keep it scrolled down\r
+       }\r
+};\r
+\r
+// Clear footer and debugger\r
+\r
+PS.DebugClear = function ()\r
+{\r
+       "use strict";\r
+       var e;\r
+\r
+       e = document.getElementById("footer");\r
+       if ( e )\r
+       {\r
+               e.style.color="#000000"; // change to black\r
+               e.innerHTML = "Version 2.0.0";\r
+       }\r
+\r
+       if ( PS.DebugWindow )\r
+       {\r
+               e = document.getElementById("monitor");\r
+               if ( e )\r
+               {\r
+                       e.value = "";\r
+               }\r
+       }\r
+};\r
+\r
+// Send error message to footer and debugger if open (includes CR)\r
+\r
+PS.Oops = function (str)\r
+{\r
+       "use strict";\r
+       var e;\r
+\r
+       if ( typeof str !== "string" )\r
+       {\r
+               return;\r
+       }\r
+\r
+       e = document.getElementById("footer");\r
+       if ( e )\r
+       {\r
+               e.innerHTML = str;\r
+       }\r
+\r
+       // Also display on debugger if open\r
+\r
+//     if ( PS.DebugWindow )\r
+//     {\r
+//             e = document.getElementById("monitor");\r
+//             if ( e )\r
+//             {\r
+//                     e.value += ("ERROR: " + str + "\n");\r
+//                     e.scrollTop = e.scrollHeight; // keep it scrolled down                  \r
+//             }\r
+//     }\r
+\r
+       PS.Debug( "ERROR: " + str + "\n" );\r
+\r
+       PS.AudioPlay("fx_uhoh");\r
+};\r
+\r
+// Set up user clock\r
+\r
+PS.Clock = function ( ticks )\r
+{\r
+       "use strict";\r
+       var fn;\r
+\r
+       fn = "[PS.Clock] ";\r
+\r
+       if ( ticks !== undefined )\r
+       {\r
+               if ( typeof ticks !== "number" )\r
+               {\r
+                       PS.Oops(fn + "ticks parameter not a number");\r
+                       return PS.ERROR;\r
+               }\r
+               ticks = Math.floor(ticks);\r
+               if ( ticks < 1 )\r
+               {\r
+                       PS.UserClock = 0;\r
+               }\r
+               else if ( typeof PS.Tick !== "function" )\r
+               {\r
+                       PS.Oops(fn + "PS.Tick function undefined");\r
+               }\r
+               else\r
+               {\r
+                       PS.UserDelay = 0;\r
+                       PS.UserClock = ticks;\r
+               }\r
+       }\r
+\r
+       return PS.UserClock;\r
+};\r
+\r
+// General system timer\r
+\r
+PS.Timer = function ()\r
+{\r
+       "use strict";\r
+       var phase, hue, r, g, b, e;\r
+\r
+       // Handle bead flashing and status text fading\r
+\r
+       PS.FlashDelay += 1;\r
+       if ( PS.FlashDelay >= PS.FLASH_INTERVAL )\r
+       {\r
+               PS.FlashDelay = 0;\r
+               PS.FlashNext();\r
+               \r
+               // Handle status text fading\r
+               \r
+               if ( PS.StatusFading && (PS.StatusPhase < 100) )\r
+               {\r
+                       phase = PS.StatusPhase + PS.STATUS_FLASH_STEP;\r
+\r
+                       if ( phase >= 100 )\r
+                       {\r
+                               phase = 100;\r
+                               hue = PS.StatusHue;\r
+                       }\r
+                       else\r
+                       {                               \r
+                               r = PS.Dissolve( PS.Grid.bgRed, PS.StatusRed, phase );\r
+                               g = PS.Dissolve( PS.Grid.bgGreen, PS.StatusGreen, phase );\r
+                               b = PS.Dissolve( PS.Grid.bgBlue, PS.StatusBlue, phase );\r
+                               hue = PS.RGBString(r, g, b);\r
+                       }\r
+                       PS.StatusPhase = phase;                 \r
+                       e = document.getElementById("status");\r
+                       if ( e )\r
+                       {\r
+                               e.style.color = hue;\r
+                       }\r
+               }\r
+       }\r
+\r
+       // Handle user clock\r
+\r
+       if ( PS.UserClock > 0 )\r
+       {\r
+               PS.UserDelay += 1;\r
+               if ( PS.UserDelay >= PS.UserClock )\r
+               {\r
+                       PS.UserDelay = 0;\r
+                       if ( PS.Tick )\r
+                       {\r
+                               try\r
+                               {\r
+                                       PS.Tick(); // call user function\r
+                               }\r
+                               catch (err)\r
+                               {\r
+                                       PS.Oops("PS.Tick() failed [" + err.message + "]" );\r
+                                       PS.UserClock = 0; // stop the timer\r
+                               }                               \r
+                       }\r
+               }\r
+       }\r
+};\r
+\r
+// PS.StartFlash(bead)\r
+// Initiates flashing of bead\r
+\r
+PS.FlashStart = function (x, y)\r
+{\r
+       "use strict";\r
+       var which, bead, i, len;\r
+\r
+       which = x + (y * PS.Grid.x); // index of bead\r
+\r
+       bead = PS.Grid.beads[which];\r
+\r
+       bead.flashPhase = 0; // init flash step\r
+\r
+       // draw first step\r
+\r
+       bead.colorNow = bead.flashColor;\r
+       PS.DrawBead(bead);\r
+\r
+       // if this bead is already in flash queue, exit\r
+\r
+       len = PS.Grid.flashList.length;\r
+       for ( i = 0; i < len; i += 1 )\r
+       {\r
+               if ( PS.Grid.flashList[i] === which )\r
+               {\r
+                       return;\r
+               }\r
+       }\r
+\r
+       // else add this bead to queue\r
+\r
+       PS.Grid.flashList.push(which);\r
+};\r
+\r
+// PS.NextFlash(bead)\r
+// Flash all beads in queue\r
+\r
+PS.FlashNext = function ()\r
+{\r
+       "use strict";\r
+       var ctx, len, i, which, bead, phase, r, g, b;\r
+\r
+       ctx = PS.Context();\r
+       len = PS.Grid.flashList.length;\r
+       i = 0;\r
+       while ( i < len )\r
+       {\r
+               which = PS.Grid.flashList[i];\r
+               bead = PS.Grid.beads[which];\r
+               phase = bead.flashPhase + PS.FLASH_STEP;\r
+\r
+               // If flash is done, set normal color and remove bead from queue\r
+\r
+               if ( phase >= 100 )\r
+               {\r
+                       bead.colorNow = bead.color;\r
+                       bead.flashPhase = 0;\r
+                       PS.Grid.flashList.splice(i, 1);\r
+                       len -= 1;\r
+               }\r
+               else\r
+               {\r
+                       bead.flashPhase = phase;\r
+                       r = PS.Dissolve( bead.flashRed, bead.alphaRed, phase );\r
+                       g = PS.Dissolve( bead.flashGreen, bead.alphaGreen, phase );\r
+                       b = PS.Dissolve( bead.flashBlue, bead.alphaBlue, phase );\r
+                       bead.colorNow = PS.RGBString(r, g, b);\r
+                       i += 1;\r
+               }\r
+               PS.DrawBead(bead, ctx);\r
+       }\r
+};\r
+\r
+// System initialization\r
+\r
+// Records the x/y of mouse over grid, -1 if not over grid\r
+\r
+PS.MouseXY = function (event)\r
+{\r
+       "use strict";\r
+       var canvas, x, y, beads, bead, row, col, i;\r
+\r
+       if ( PS.Grid )\r
+       {\r
+               canvas = document.getElementById("screen");\r
+\r
+           if ( event.x && event.y )\r
+           {\r
+                       x = event.x;\r
+                       y = event.y;\r
+               }\r
+               else // Firefox method to get the position\r
+               {\r
+                       x = event.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;\r
+                       y = event.clientY + document.body.scrollTop + document.documentElement.scrollTop;\r
+               }\r
+\r
+               x -= canvas.offsetLeft;\r
+               y -= canvas.offsetTop;\r
+\r
+               // Over the grid?\r
+\r
+               if ( (x >= PS.Grid.left) && (x < PS.Grid.right) && (y >= PS.Grid.top) && (y < PS.Grid.bottom) )\r
+               {\r
+                       // Which bead are we over?\r
+\r
+                       beads = PS.Grid.beads;\r
+                       i = 0; // init index\r
+                       for ( row = 0; row < PS.Grid.y; row += 1 )\r
+                       {\r
+                               bead = beads[i]; // get the first bead in this row\r
+\r
+                               // Is mouse over this row?\r
+\r
+                               if ( (y >= bead.top) && (y < bead.bottom) )\r
+                               {\r
+                                       // Find column\r
+\r
+                                       for ( col = 0; col < PS.Grid.x; col += 1 )\r
+                                       {\r
+                                               bead = beads[i];\r
+                                               if ( (x >= bead.left) && (x < bead.right) )\r
+                                               {\r
+                                                       PS.MouseX = col;\r
+                                                       PS.MouseY = row;\r
+                                                       return;\r
+                                               }\r
+                                               i += 1;\r
+                                       }\r
+                               }\r
+                               else\r
+                               {\r
+                                       i += PS.Grid.x; // try next row \r
+                               }\r
+                       }\r
+               }\r
+       }\r
+\r
+       PS.MouseX = -1;\r
+       PS.MouseY = -1;\r
+};\r
+\r
+// Called when mouse is clicked over canvas\r
+\r
+PS.MouseDown = function (event)\r
+{\r
+       "use strict";\r
+       var bead;\r
+\r
+       PS.MouseXY(event);\r
+       if ( PS.MouseX >= 0 )\r
+       {\r
+               bead = PS.Grid.beads[PS.MouseX + (PS.MouseY * PS.Grid.x)];\r
+\r
+               // play audio if assigned to bead\r
+\r
+               if ( bead.audio )\r
+               {\r
+                       PS.AudioPlay(bead.audio, bead.volume);\r
+               }\r
+\r
+               // Call function if assigned to bead\r
+\r
+               if ( typeof bead.exec === "function" )\r
+               {                       \r
+                       try\r
+                       {\r
+                               bead.exec(PS.MouseX, PS.MouseY, bead.data);             \r
+                       }\r
+                       catch (err1)\r
+                       {\r
+                               PS.Oops("Bead " + PS.MouseX + ", " + PS.MouseY + " function failed [" + err1.message + "]" );\r
+                       }                       \r
+               }\r
+\r
+               if ( PS.Click ) // only if function exists\r
+               {                       \r
+                       try\r
+                       {\r
+                               PS.Click(PS.MouseX, PS.MouseY, bead.data);              \r
+                       }\r
+                       catch (err2)\r
+                       {\r
+                               PS.Oops("PS.Click() failed [" + err2.message + "]" );\r
+                       }                       \r
+               }\r
+       }\r
+};\r
+\r
+// Called when mouse is released over canvas\r
+\r
+PS.MouseUp = function (event)\r
+{\r
+       "use strict";\r
+       var bead;\r
+\r
+       if ( PS.Grid && PS.Release ) // only if grid and function exist\r
+       {\r
+               PS.MouseXY(event);\r
+               if ( PS.MouseX >= 0 )\r
+               {\r
+                       bead = PS.Grid.beads[PS.MouseX + (PS.MouseY * PS.Grid.x)];                      \r
+                       try\r
+                       {\r
+                               PS.Release(PS.MouseX, PS.MouseY, bead.data);            \r
+                       }\r
+                       catch (err)\r
+                       {\r
+                               PS.Oops("PS.Release() failed [" + err.message + "]" );\r
+                       }                       \r
+               }\r
+       }\r
+};\r
+\r
+// Called when mouse moves over canvas\r
+\r
+PS.MouseMove = function (event)\r
+{\r
+       "use strict";\r
+       var bead, last;\r
+\r
+       PS.MouseXY(event);\r
+\r
+       if ( PS.MouseX >= 0 )\r
+       {\r
+               bead = PS.Grid.beads[PS.MouseX + (PS.MouseY * PS.Grid.x)];\r
+               if ( (PS.MouseX !== PS.LastX) || (PS.MouseY !== PS.LastY) )\r
+               {\r
+                       if ( PS.Leave ) // only if function exists\r
+                       {\r
+                               if ( PS.LastX >= 0 )\r
+                               {\r
+                                       last = PS.Grid.beads[PS.LastX + (PS.LastY * PS.Grid.x)];                        \r
+                                       try\r
+                                       {\r
+                                               PS.Leave(PS.LastX, PS.LastY, last.data);                \r
+                                       }\r
+                                       catch (err1)\r
+                                       {\r
+                                               PS.Oops("PS.Leave() failed [" + err1.message + "]" );\r
+                                       }                                       \r
+                               }\r
+                       }\r
+                       if ( PS.Enter ) // only if function exists\r
+                       {                       \r
+                               try\r
+                               {\r
+                                       PS.Enter(PS.MouseX, PS.MouseY, bead.data);      \r
+                               }\r
+                               catch (err2)\r
+                               {\r
+                                       PS.Oops("PS.Enter() failed [" + err2.message + "]" );\r
+                               }                               \r
+                       }\r
+                       PS.LastX = PS.MouseX;\r
+                       PS.LastY = PS.MouseY;\r
+               }\r
+       }\r
+       else if ( PS.LastX >= 0 )\r
+       {\r
+               if ( PS.Leave ) // only if function exists\r
+               {\r
+                       last = PS.Grid.beads[PS.LastX + (PS.LastY * PS.Grid.x)];                        \r
+                       try\r
+                       {\r
+                               PS.Leave(PS.LastX, PS.LastY, last.data);                \r
+                       }\r
+                       catch (err3)\r
+                       {\r
+                               PS.Oops("PS.Leave() failed [" + err3.message + "]" );\r
+                       }                       \r
+               }\r
+               PS.LastX = -1;\r
+               PS.LastY = -1;\r
+       }\r
+};\r
+\r
+// Called when mouse leaves canvas\r
+\r
+PS.MouseOut = function (event)\r
+{\r
+       "use strict";\r
+       var last;\r
+\r
+       PS.MouseBead = -1;\r
+       if ( PS.Grid && PS.Leave ) // only if grid and function exist\r
+       {\r
+               if ( PS.LastBead >= 0 )\r
+               {\r
+                       last = PS.Grid.beads[PS.LastBead];                      \r
+                       try\r
+                       {\r
+                               PS.Leave(last.x, last.y, last.data);            \r
+                       }\r
+                       catch (err)\r
+                       {\r
+                               PS.Oops("PS.Leave() failed [" + err.message + "]" );\r
+                       }                       \r
+               }\r
+       }\r
+       PS.LastBead = -1;\r
+};\r
+\r
+PS.KeyFilter = function (key, shift)\r
+{\r
+       "use strict";\r
+       \r
+       // convert lower-case alpha to upper-case if shift key is down\r
+       \r
+       if ( (key >= 65) && (key <= 90) )\r
+       {\r
+               if ( shift )\r
+               {\r
+                       key += 32; \r
+               }\r
+               return key;\r
+       }\r
+       \r
+       // Convert weird keycodes to ASCII\r
+       \r
+       switch ( key )\r
+       {\r
+               case 188:\r
+                       key = 44; // ,\r
+                       break;\r
+               case 190:\r
+                       key = 46; // .\r
+                       break;\r
+               case 191:\r
+                       key = 47; // /\r
+                       break;\r
+               case 222:\r
+                       key = 39; // '\r
+                       break;\r
+               case 219:\r
+                       key = 91; // [\r
+                       break;\r
+               case 221:\r
+                       key = 93; // ]\r
+                       break;\r
+               case 220:\r
+                       key = 92; // \\r
+                       break;\r
+               default:\r
+                       break;\r
+       }\r
+               \r
+       // Translate shifted keys\r
+                       \r
+       if ( shift )\r
+       {\r
+               switch ( key )\r
+               {\r
+                       case 96: // `\r
+                               key = 126; // ~\r
+                               break;\r
+                       case 49: // 1\r
+                               key = 33; // !\r
+                               break;\r
+                       case 50: // 2\r
+                               key = 64; // @\r
+                               break;\r
+                       case 51: // 3\r
+                               key = 35; // #\r
+                               break;\r
+                       case 52: // 4\r
+                               key = 36; // !\r
+                               break;\r
+                       case 53: // 5\r
+                               key = 37; // %\r
+                               break;\r
+                       case 54: // 6\r
+                               key = 94; // ^\r
+                               break;\r
+                       case 55: // 7\r
+                               key = 38; // &\r
+                               break;\r
+                       case 56: // 8\r
+                               key = 42; // *\r
+                               break;\r
+                       case 57: // 9\r
+                               key = 40; // (\r
+                               break;\r
+                       case 48: // 0\r
+                               key = 41; // )\r
+                               break;\r
+                       case 45: // -\r
+                               key = 95; // _\r
+                               break;\r
+                       case 61: // =\r
+                               key = 43; // +\r
+                               break;                                  \r
+                       case 91: // [\r
+                               key = 123; // {\r
+                               break;\r
+                       case 93: // ]\r
+                               key = 125; // }\r
+                               break;\r
+                       case 92: // \\r
+                               key = 124; // |\r
+                               break;                                  \r
+                       case 59: // ;\r
+                               key = 58; // :\r
+                               break;\r
+                       case 39: // '\r
+                               key = 34; // "\r
+                               break;                                  \r
+                       case 44: // ,\r
+                               key = 60; // <\r
+                               break;\r
+                       case 46: // .\r
+                               key = 62; // >\r
+                               break;\r
+                       case 47: // /\r
+                               key = 63; // ?\r
+                               break;\r
+                       default:\r
+                               break;\r
+               }               \r
+       }\r
+\r
+       return key;\r
+};\r
+\r
+// Called when a key is pressed\r
+\r
+PS.SysKeyDown = function (event)\r
+{\r
+       "use strict";\r
+       var key;\r
+\r
+       if ( PS.KeyDown ) // only if function exists\r
+       {\r
+               if ( event.which === null )\r
+               {\r
+                       key = event.keyCode;    // IE\r
+               }\r
+               else\r
+               {\r
+                       key = event.which;        // Others\r
+               }\r
+               key = PS.KeyFilter(key, event.shiftKey);\r
+               try\r
+               {\r
+                       PS.KeyDown(key, event.shiftKey, event.ctrlKey);         \r
+               }\r
+               catch (err)\r
+               {\r
+                       PS.Oops("PS.KeyDown() failed [" + err.message + "]" );\r
+               }\r
+       }\r
+       return false;\r
+};\r
+\r
+// Called when a key is released\r
+\r
+PS.SysKeyUp = function (event)\r
+{\r
+       "use strict";\r
+       var key;\r
+\r
+       if ( PS.KeyUp ) // only if function exists\r
+       {\r
+               if ( event.which === null )\r
+               {\r
+                       key = event.keyCode;    // IE\r
+               }\r
+               else\r
+               {\r
+                       key = event.which;        // Others\r
+               }\r
+               key = PS.KeyFilter(key, event.shiftKey);\r
+               try\r
+               {\r
+                       PS.KeyUp(key, event.shiftKey, event.ctrlKey);           \r
+               }\r
+               catch (err)\r
+               {\r
+                       PS.Oops("PS.KeyUp() failed [" + err.message + "]" );\r
+               }\r
+       }\r
+       return false;\r
+};\r
+\r
+// Called when mouse wheel is moved\r
+\r
+PS.SysWheel = function (event)\r
+{\r
+       "use strict";\r
+       var delta;\r
+\r
+       if ( PS.Wheel ) // only if function exists\r
+       {\r
+               delta = 0;\r
+\r
+               // for IE\r
+\r
+               if ( !event )\r
+               {\r
+                       event = window.event;\r
+               }\r
+\r
+               // IE and Opera\r
+\r
+               if ( event.wheelDelta )\r
+               {\r
+                       delta = event.wheelDelta / 120;\r
+               if ( window.opera )\r
+               {\r
+                               delta = -delta;\r
+               }\r
+               }\r
+\r
+               // Firefox and Chrome?\r
+\r
+               else if ( event.detail )\r
+               {\r
+                       delta = -( event.detail / 3 );\r
+               }\r
+\r
+               if ( event.preventDefault )\r
+               {\r
+                       event.preventDefault();\r
+               }\r
+\r
+               // clamp\r
+               \r
+               if ( delta >= PS.FORWARD )\r
+               {\r
+                       delta = PS.FORWARD;\r
+               }\r
+               else\r
+               {\r
+                       delta = PS.BACKWARD;\r
+               }\r
+               \r
+               // Send delta to user\r
+               \r
+               try\r
+               {\r
+                       PS.Wheel (delta);\r
+               }\r
+               catch (err)\r
+               {\r
+                       PS.Oops("PS.Wheel() failed [" + err.message + "]" );\r
+               }\r
+       }\r
+\r
+       event.returnValue = false;\r
+};\r
+\r
+// Initialization\r
+\r
+PS.Sys = function ()\r
+{\r
+       "use strict";\r
+       var fn, e;\r
+\r
+       fn = "[PS.Sys] ";\r
+\r
+       // Init audio support, preload error sound\r
+\r
+       PS.AudioInit();\r
+       PS.AudioLoad("fx_uhoh");\r
+\r
+       // Make sure all required game functions exist\r
+\r
+       if ( typeof PS.Init !== "function" )\r
+       {\r
+               PS.Init = null;\r
+               PS.Oops(fn + "WARNING: PS.Init function undefined");\r
+       }\r
+\r
+       if ( typeof PS.Click !== "function" )\r
+       {\r
+               PS.Click = null;\r
+               PS.Oops(fn + "WARNING: PS.Click function undefined");\r
+       }\r
+\r
+       if ( typeof PS.Release !== "function" )\r
+       {\r
+               PS.Release = null;\r
+               PS.Oops(fn + "WARNING: PS.Release function undefined");\r
+       }\r
+\r
+       if ( typeof PS.Enter !== "function" )\r
+       {\r
+               PS.Enter = null;\r
+               PS.Oops(fn + "WARNING: PS.Enter function undefined");\r
+       }\r
+\r
+       if ( typeof PS.Leave !== "function" )\r
+       {\r
+               PS.Leave = null;\r
+               PS.Oops(fn + "WARNING: PS.Leave function undefined");\r
+       }\r
+\r
+       if ( typeof PS.KeyDown !== "function" )\r
+       {\r
+               PS.KeyDown = null;\r
+               PS.Oops(fn + "WARNING: PS.KeyDown function undefined");\r
+       }\r
+\r
+       if ( typeof PS.KeyUp !== "function" )\r
+       {\r
+               PS.KeyUp = null;\r
+               PS.Oops(fn + "WARNING: PS.KeyUp function undefined");\r
+       }\r
+\r
+       if ( typeof PS.Wheel !== "function" )\r
+       {\r
+               PS.Wheel = null;\r
+               PS.Oops(fn + "WARNING: PS.Wheel function undefined");\r
+       }\r
+\r
+       // Set up mouse/keyboard events\r
+\r
+       e = document.getElementById("screen");\r
+       if ( e )\r
+       {\r
+           e.addEventListener("mousedown", PS.MouseDown, false);\r
+           e.addEventListener("mouseup", PS.MouseUp, false);\r
+           e.addEventListener("mouseout", PS.MouseOut, false);\r
+           e.addEventListener("mousemove", PS.MouseMove, false);\r
+   }\r
+\r
+    // Set up mouse wheel events\r
+\r
+    if ( window.addEventListener )\r
+    {\r
+               window.addEventListener('DOMMouseScroll', PS.SysWheel, false); // for Firefox\r
+               window.addEventListener('mousewheel', PS.SysWheel, false); // for others\r
+       }\r
+       else\r
+       {\r
+               window.onmousewheel = document.onmousewheel = PS.SysWheel; // for IE, maybe\r
+       }\r
+       \r
+       // Setup offscreen canvas for image manipulation\r
+       \r
+       PS.ImageCanvas = document.createElement("canvas");\r
+       PS.ImageCanvas.width = PS.GRID_MAX;\r
+       PS.ImageCanvas.height = PS.GRID_MAX;\r
+\r
+       // Start the timer\r
+\r
+       window.setInterval (PS.Timer, PS.DEFAULT_FPS);\r
+\r
+       // Print version number\r
+\r
+       e = document.getElementById("footer");\r
+       if ( e )\r
+       {\r
+               e.innerHTML = "Version " + PS.VERSION;\r
+       }\r
+\r
+       if ( PS.Init )\r
+       {\r
+               try\r
+               {\r
+                       PS.Init(); // call user initializer\r
+               }\r
+               catch (err)\r
+               {\r
+                       PS.Oops("PS.Init() failed [" + err.message + "]" );\r
+               }               \r
+       }\r
+       else\r
+       {\r
+               PS.GridSize(PS.GRID_DEFAULT_WIDTH, PS.GRID_DEFAULT_HEIGHT);\r
+       }\r
+};\r
+\r
+// Library stuff\r
+\r
+PS.Random = function (val)\r
+{\r
+       "use strict";\r
+       var fn;\r
+\r
+       fn = "[PS.Random] ";\r
+       if ( typeof val !== "number" )\r
+       {\r
+               PS.Oops(fn + "Parameter is not a number");\r
+               return PS.ERROR;\r
+       }       \r
+       val = Math.floor(val);\r
+       if ( val < 2 )\r
+       {\r
+               return 1;\r
+       }\r
+\r
+       val = Math.random() * val;\r
+       val = Math.floor(val) + 1;\r
+       return val;\r
+};\r
+\r
+PS.PianoFiles = [\r
+       "a0", "bb0", "b0",\r
+       "c1", "db1", "d1", "eb1", "e1", "f1", "gb1", "g1", "ab1", "a1", "bb1", "b1",\r
+       "c2", "db2", "d2", "eb2", "e2", "f2", "gb2", "g2", "ab2", "a2", "bb2", "b2",\r
+       "c3", "db3", "d3", "eb3", "e3", "f3", "gb3", "g3", "ab3", "a3", "bb3", "b3",\r
+       "c4", "db4", "d4", "eb4", "e4", "f4", "gb4", "g4", "ab4", "a4", "bb4", "b4",\r
+       "c5", "db5", "d5", "eb5", "e5", "f5", "gb5", "g5", "ab5", "a5", "bb5", "b5",\r
+       "c6", "db6", "d6", "eb6", "e6", "f6", "gb6", "g6", "ab6", "a6", "bb6", "b6",\r
+       "c7", "db7", "d7", "eb7", "e7", "f7", "gb7", "g7", "ab7", "a7", "bb7", "b7",\r
+       "c8"\r
+];\r
+\r
+PS.Piano = function ( val, flag )\r
+{\r
+       "use strict";\r
+       var fn, str;\r
+\r
+       fn = "[PS.Piano] ";\r
+\r
+       if ( typeof val !== "number" )\r
+       {\r
+               PS.Oops(fn + "Parameter is not a number");\r
+               return PS.ERROR;\r
+       }\r
+       val = Math.floor(val);\r
+       if ( val < 1 )\r
+       {\r
+               val = 1;\r
+       }\r
+       else if ( val > 88 )\r
+       {\r
+               val = 88;\r
+       }\r
+\r
+       str = "piano_" + PS.PianoFiles[val - 1];\r
+       if ( flag )\r
+       {\r
+               str = "l_" + str;\r
+       }\r
+       return str;\r
+};\r
+\r
+PS.HchordFiles = [\r
+       "a2", "bb2", "b2",\r
+       "c3", "db3", "d3", "eb3", "e3", "f3", "gb3", "g3", "ab3", "a3", "bb3", "b3",\r
+       "c4", "db4", "d4", "eb4", "e4", "f4", "gb4", "g4", "ab4", "a4", "bb4", "b4",\r
+       "c5", "db5", "d5", "eb5", "e5", "f5", "gb5", "g5", "ab5", "a5", "bb5", "b5",\r
+       "c6", "db6", "d6", "eb6", "e6", "f6", "gb6", "g6", "ab6", "a6", "bb6", "b6",\r
+       "c7", "db7", "d7", "eb7", "e7", "f7"\r
+];\r
+\r
+PS.Harpsichord = function ( val, flag )\r
+{\r
+       "use strict";\r
+       var fn, str;\r
+\r
+       fn = "[PS.Harpsichord] ";\r
+\r
+       if ( typeof val !== "number" )\r
+       {\r
+               PS.Oops(fn + "Parameter is not a number");\r
+               return PS.ERROR;\r
+       }\r
+       val = Math.floor(val);\r
+       if ( val < 1 )\r
+       {\r
+               val = 1;\r
+       }\r
+       else if ( val > 57 )\r
+       {\r
+               val = 57;\r
+       }\r
+\r
+       str = "hchord_" + PS.HchordFiles[val - 1];\r
+       if ( flag )\r
+       {\r
+               str = "l_" + str;\r
+       }\r
+       return str;\r
+};\r
+\r
+PS.XyloFiles = [\r
+       "a4", "bb4", "b4",\r
+       "c5", "db5", "d5", "eb5", "e5", "f5", "gb5", "g5", "ab5", "a5", "bb5", "b5",\r
+       "c6", "db6", "d6", "eb6", "e6", "f6", "gb6", "g6", "ab6", "a6", "bb6", "b6",\r
+       "c7", "db7", "d7", "eb7", "e7", "f7", "gb7", "g7", "ab7", "a7", "bb7", "b7"\r
+];\r
+\r
+PS.Xylophone = function ( val )\r
+{\r
+       "use strict";\r
+       var fn, str;\r
+\r
+       fn = "[PS.Xylophone] ";\r
+\r
+       if ( typeof val !== "number" )\r
+       {\r
+               PS.Oops(fn + "Parameter is not a number");\r
+               return PS.ERROR;\r
+       }\r
+       val = Math.floor(val);\r
+       if ( val < 1 )\r
+       {\r
+               val = 1;\r
+       }\r
+       else if ( val > 39 )\r
+       {\r
+               val = 39;\r
+       }\r
+\r
+       str = "xylo_" + PS.XyloFiles[val - 1];\r
+       return str;\r
+};\r
+\r
+// Audio functions\r
+\r
+PS.AUDIO_PATH_DEFAULT = "http://users.wpi.edu/~bmoriarty/ps/audio/"; // case sensitive!\r
+PS.AUDIO_PATH = PS.AUDIO_PATH_DEFAULT;\r
+PS.AUDIO_MAX_CHANNELS = 32;\r
+PS.AudioChannels = [];\r
+\r
+PS.AudioInit = function ()\r
+{\r
+       "use strict";\r
+       var i;\r
+\r
+       for ( i = 0; i < PS.AUDIO_MAX_CHANNELS; i += 1 )\r
+       {\r
+               PS.AudioChannels[i] = {};\r
+               PS.AudioChannels[i].audio = new Audio();\r
+               PS.AudioChannels[i].done = -1;\r
+               PS.AudioChannels[i].id = "";\r
+       }\r
+};\r
+\r
+PS.AudioError = function (obj)\r
+{\r
+       "use strict";\r
+       var c, str;\r
+\r
+       c = obj.error.code;\r
+       switch ( c )\r
+    {\r
+               case 1:\r
+                       str = "MEDIA_ERR_ABORTED";\r
+                       break;\r
+               case 2:\r
+                       str = "MEDIA_ERR_NETWORK";\r
+                       break;\r
+               case 3:\r
+                       str = "MEDIA_ERR_DECODE";\r
+                       break;\r
+               case 4:\r
+                       str = "MEDIA_ERR_SRC_NOT_SUPPORTED";\r
+                       break;\r
+               default:\r
+                       str = "UNKNOWN";\r
+                       break;\r
+    }\r
+\r
+       PS.Oops("[Audio Error: " + str + "]\n");        \r
+};\r
+\r
+PS.AudioPath = function (path)\r
+{\r
+       "use strict";\r
+       var fn;\r
+       \r
+       fn = "[PS.AudioPath] ";\r
+\r
+       if ( path === PS.DEFAULT )\r
+       {\r
+               PS.AUDIO_PATH = PS.AUDIO_PATH_DEFAULT;\r
+       }\r
+       else if ( typeof path !== "string" )\r
+       {\r
+               PS.Oops(fn + "path parameter is not a string");\r
+               return PS.ERROR;                \r
+       }\r
+       else\r
+       {\r
+               PS.AUDIO_PATH = path;   \r
+       }\r
+       \r
+       return PS.AUDIO_PATH;\r
+};\r
+\r
+PS.AudioLoad = function (id, path)\r
+{\r
+       "use strict";\r
+       var fn, snd;\r
+\r
+       fn = "[PS.AudioLoad] ";\r
+\r
+       if ( typeof id !== "string" )\r
+       {\r
+               PS.Oops(fn + "id parameter is not a string");\r
+               return PS.ERROR;                \r
+       }\r
+       if ( id.length < 1 )\r
+       {\r
+               PS.Oops(fn + "id parameter is an empty string");\r
+               return PS.ERROR;                        \r
+       }\r
+\r
+       if ( path === undefined )\r
+       {\r
+               path = PS.AUDIO_PATH;\r
+       }\r
+       else if ( path === PS.DEFAULT )\r
+       {\r
+               path = PS.AUDIO_PATH_DEFAULT;   \r
+       }\r
+       else if ( typeof path !== "string" )\r
+       {\r
+               PS.Oops(fn + "path parameter is not a string");\r
+               return PS.ERROR;                \r
+       }\r
+\r
+       // Already got this? Clone it\r
+\r
+       snd = document.getElementById(id);\r
+       if ( snd )\r
+       {\r
+               return snd;\r
+       }\r
+\r
+       path = path + id + ".wav";\r
+\r
+       snd = document.createElement("audio");\r
+       snd.setAttribute("src", path);\r
+       snd.setAttribute("id", id);     \r
+       snd.setAttribute("preload", "auto");\r
+       snd.setAttribute("onerror", "PS.AudioError(this)");\r
+\r
+//     src = document.createElement("source");\r
+//     src.setAttribute("src", path + ".ogg");\r
+//     src.setAttribute("type", "audio/ogg");\r
+//     snd.appendChild(src);\r
+       \r
+//     src = document.createElement("source");\r
+//     src.setAttribute("src", path + ".mp3");\r
+//     src.setAttribute("type", "audio/mpeg");\r
+//     src.setAttribute("onerror", "PS.AudioError()");\r
+//     snd.appendChild(src);\r
+\r
+//     src = document.createElement("source");\r
+//     src.setAttribute("src", path + ".wav");\r
+//     src.setAttribute("type", "audio/x-wav");\r
+//     snd.appendChild(src);\r
+\r
+       document.body.appendChild(snd);\r
+       snd.load();\r
+\r
+       return snd;\r
+};\r
+\r
+// Returns a channel number\r
+\r
+PS.AudioPlay = function (id, volume, func, path)\r
+{\r
+       "use strict";\r
+       var fn, i, snd, d, t, channel;\r
+\r
+       fn = "[PS.AudioPlay] ";\r
+\r
+       if ( (volume === undefined) || (volume === PS.DEFAULT) )\r
+       {\r
+               volume = PS.DEFAULT_VOLUME;\r
+       }\r
+       else if ( typeof volume !== "number" )\r
+       {\r
+               PS.Oops(fn + "volume parameter is not a number");\r
+               return PS.ERROR;        \r
+       }\r
+       else if ( volume < 0 )\r
+       {\r
+               volume = 0;\r
+       }\r
+       else if ( volume > PS.DEFAULT_VOLUME )\r
+       {\r
+               volume = PS.DEFAULT_VOLUME;\r
+       }\r
+       \r
+       if ( (func !== undefined) && (typeof func !== "function") )\r
+       {\r
+               PS.Oops(fn + "func parameter is not a function");\r
+               return PS.ERROR;                        \r
+       }       \r
+\r
+       snd = PS.AudioLoad(id, path);\r
+       if ( snd !== PS.ERROR )\r
+       {                       \r
+               snd.volume = volume;\r
+               if ( func !== undefined )\r
+               {\r
+                       snd.addEventListener("ended", func);\r
+               }\r
+               for ( i = 0; i < PS.AUDIO_MAX_CHANNELS; i += 1 )\r
+               {\r
+                       d = new Date();\r
+                       t = d.getTime();\r
+                       channel = PS.AudioChannels[i];\r
+                       if ( channel.done < t )\r
+                       {\r
+                               channel.done = t + ( snd.duration * 1000 );\r
+                               channel.audio = snd;\r
+                               channel.id = id;\r
+                               snd.load(); // WHY???\r
+                               snd.play();\r
+                               return i + 1; // channel id\r
+                       }\r
+               }\r
+       }\r
+\r
+       return PS.ERROR; // error\r
+};\r
+\r
+// Stops playback of channel number\r
+\r
+PS.AudioStop = function (c)\r
+{\r
+       "use strict";\r
+       var fn, d, t, channel;\r
+\r
+       fn = "[PS.AudioStop] ";\r
+\r
+       if ( typeof c !== "number" )\r
+       {\r
+               PS.Oops(fn + "Parameter is not a number");\r
+               return PS.ERROR;                \r
+       }\r
+       c = Math.floor(c);\r
+       if ( (c < 1) || (c > PS.AUDIO_MAX_CHANNELS) )\r
+       {\r
+               PS.Oops(fn + "Invalid channel id");\r
+               return PS.ERROR;                        \r
+       }\r
+\r
+       channel = PS.AudioChannels[c - 1];\r
+       d = new Date();\r
+       t = d.getTime();                        \r
+\r
+       channel.done = t; // mark as done playing\r
+       channel.audio.pause();\r
+       channel.audio.currentTime = 0;\r
+\r
+       return c;\r
+};\r
+\r
+// Pauses/unpauses playback of channel number\r
+\r
+PS.AudioPause = function (c)\r
+{\r
+       "use strict";\r
+       var fn, channel, audio;\r
+\r
+       fn = "[PS.AudioPause] ";\r
+\r
+       if ( typeof c !== "number" )\r
+       {\r
+               PS.Oops(fn + "Parameter is not a number");\r
+               return PS.ERROR;                \r
+       }\r
+       c = Math.floor(c);\r
+       if ( (c < 1) || (c > PS.AUDIO_MAX_CHANNELS) )\r
+       {\r
+               PS.Oops(fn + "Invalid channel id");\r
+               return PS.ERROR;                        \r
+       }\r
+\r
+       channel = PS.AudioChannels[c - 1];\r
+       audio = channel.audio;  \r
+       if ( audio.paused )\r
+       {\r
+               audio.play();\r
+       }\r
+       else\r
+       {\r
+               audio.pause();\r
+       }\r
+\r
+       return c;\r
+};\r
+\r
+// Image functions\r
+\r
+PS.ImageLoad = function ( file, func )\r
+{\r
+       "use strict";\r
+       var fn, img;\r
+       \r
+       fn = "[PS.ImageLoad] ";\r
+       \r
+       if ( typeof file !== "string" )\r
+       {\r
+               PS.Oops(fn + "Parameter 1 is not a string");\r
+               return PS.ERROR;\r
+       }\r
+       if ( file.length < 1 )\r
+       {\r
+               PS.Oops(fn + "Parameter 1 is an empty string");\r
+               return PS.ERROR;        \r
+       }\r
+       if ( (func !== undefined) && (typeof func !== "function") )\r
+       {\r
+               PS.Oops(fn + "Parameter 2 is not a function");\r
+               return PS.ERROR;                \r
+       }       \r
+       try\r
+       {\r
+               img = new Image();\r
+               if ( func !== undefined )\r
+               {\r
+                       img.onload = func;\r
+               }\r
+               img.src = file;\r
+               return img;\r
+       }\r
+       catch (err)\r
+       {\r
+               PS.Oops(fn + "failed [" + err.message + "]");\r
+               return PS.ERROR;\r
+       }\r
+};\r
+\r
+// Extract an imageData table from an image file\r
+// optional [alpha] determines if alpha data if included\r
+\r
+PS.ImageData = function ( img, alpha )\r
+{\r
+       "use strict";\r
+       var fn, w, h, ctx, imgData, imgData2, i, j, len, d1, d2;\r
+       \r
+       fn = "[PS.ImageMap] ";\r
+       if ( (alpha === undefined) || !alpha )\r
+       {\r
+               alpha = false;  \r
+       }\r
+       else\r
+       {\r
+               alpha = true;\r
+       }\r
+       \r
+       w = img.width;\r
+       if ( (typeof w !== "number") || (w < 0) )\r
+       {\r
+               PS.Oops(fn + "Invalid width parameter");\r
+               return PS.ERROR;                \r
+       }\r
+       w = Math.floor(w);\r
+       if ( w > PS.GRID_MAX )\r
+       {\r
+               w = PS.GRID_MAX;\r
+       }\r
+       \r
+       h = img.height;\r
+       if ( (typeof h !== "number") || (h < 0) )\r
+       {\r
+               PS.Oops(fn + "Invalid height parameter");\r
+               return PS.ERROR;                \r
+       }\r
+       h = Math.floor(h);\r
+       if ( h > PS.GRID_MAX )\r
+       {\r
+               h = PS.GRID_MAX;\r
+       }\r
+\r
+       // draw the image onto the offscreen canvas\r
+\r
+       try\r
+       {\r
+               ctx = PS.ImageCanvas.getContext("2d");\r
+               ctx.drawImage(img, 0, 0);\r
+       }\r
+       catch (err)\r
+       {\r
+               PS.Oops(fn + "failed @ 1 [" + err.message + "]");\r
+               return PS.ERROR;\r
+       }       \r
+                       \r
+       // fetch the data and return it\r
+\r
+       try\r
+       {\r
+               imgData = ctx.getImageData(0, 0, w, h);\r
+       }\r
+       catch (err2)\r
+       {\r
+               PS.Oops(fn + "failed @ 2 [" + err2.message + "]");\r
+               return PS.ERROR;\r
+       }\r
+       \r
+       // imgData is read-only for some reason\r
+       // so make a copy of it\r
+       \r
+       imgData2 = {};\r
+       imgData2.width = imgData.width;\r
+       imgData2.height = imgData.height;\r
+       \r
+       d1 = imgData.data;\r
+       len = d1.length;\r
+       d2 = []; // new data array\r
+       i = 0;\r
+       j = 0;  \r
+       \r
+       // if alpha data is not wanted, remove it\r
+       \r
+       if ( !alpha )\r
+       {               \r
+               d2.length = (len / 4) * 3;\r
+               while ( i < len )\r
+               {\r
+                       d2[j] = d1[i];\r
+                       i += 1;\r
+                       j += 1;\r
+                       d2[j] = d1[i];\r
+                       i += 1;\r
+                       j += 1;\r
+                       d2[j] = d1[i];\r
+                       i += 2; // skip alpha\r
+                       j += 1;                 \r
+               }\r
+               imgData2.pixelSize = 3;         \r
+       }\r
+       else\r
+       {\r
+               d2.length = len;\r
+               while ( i < len )\r
+               {\r
+                       d2[j] = d1[i];\r
+                       i += 1;\r
+                       j += 1;\r
+                       d2[j] = d1[i];\r
+                       i += 1;\r
+                       j += 1;\r
+                       d2[j] = d1[i];\r
+                       i += 1;\r
+                       j += 1;\r
+                       d2[j] = d1[i];\r
+                       i += 1;\r
+                       j += 1;                 \r
+               }                       \r
+               imgData2.pixelSize = 4;\r
+       }\r
+       \r
+       imgData2.data = d2;\r
+       return imgData2;        \r
+};\r
+\r
+PS.ImageBlit = function ( imgdata, xpos, ypos )\r
+{\r
+       "use strict";\r
+       var fn, size, bytes, w, h, pixsize, ptr, drawx, drawy, i, j, r, g, b, a, k, bead;\r
+\r
+       fn = "[PS.ImageBlit] ";\r
+\r
+       // verify data format\r
+\r
+       if ( typeof imgdata !== "object" )\r
+       {\r
+               PS.Oops(fn + "parameter 1 is not a table");\r
+               return PS.ERROR;\r
+       }\r
+       \r
+       bytes = imgdata.data; // check this?\r
+       \r
+       w = imgdata.width;\r
+       if ( typeof w !== "number" )\r
+       {\r
+               PS.Oops(fn + "imgdata.width is not a number");\r
+               return PS.ERROR;                \r
+       }\r
+       w = Math.floor(w);\r
+       if ( w < 1 )\r
+       {\r
+               PS.Oops(fn + "imgdata.width < 1");\r
+               return PS.ERROR;                \r
+       }\r
+\r
+       h = imgdata.height;\r
+       if ( typeof h !== "number" )\r
+       {\r
+               PS.Oops(fn + "imgdata.height is not a number");\r
+               return PS.ERROR;                \r
+       }\r
+       h = Math.floor(h);\r
+       if ( h < 1 )\r
+       {\r
+               PS.Oops(fn + "imgdata.height < 1");\r
+               return PS.ERROR;                \r
+       }\r
+       \r
+       pixsize = imgdata.pixelSize;\r
+       if ( (pixsize !== 3) && (pixsize !== 4) )\r
+       {\r
+               PS.Oops(fn + "invalid pixelSize");\r
+               return PS.ERROR;                                \r
+       }\r
+       \r
+       size = w * h * pixsize;\r
+       if ( bytes.length !== size )\r
+       {\r
+               PS.Oops(fn + "invalid data length [" + imgdata.data.length + "]");\r
+               return PS.ERROR;                \r
+       }\r
+       \r
+       if ( (xpos === undefined) || (xpos === PS.DEFAULT) )\r
+       {\r
+               xpos = 0;\r
+       }\r
+       else if ( typeof xpos !== "number" )\r
+       {\r
+               PS.Oops(fn + "parameter 2 is not a number");\r
+               return PS.ERROR;                \r
+       }\r
+       else\r
+       {\r
+               xpos = Math.floor(xpos);\r
+\r
+               // exit if drawing off grid\r
+\r
+               if ( (xpos >= PS.Grid.x) || ((xpos + w) < 1) ) \r
+               {\r
+                       return true;\r
+               }\r
+       }\r
+\r
+       if ( (ypos === undefined) || (ypos === PS.DEFAULT) )\r
+       {\r
+               ypos = 0;\r
+       }\r
+       else if ( typeof ypos !== "number" )\r
+       {\r
+               PS.Oops(fn + "parameter 3 is not a number");\r
+               return PS.ERROR;                \r
+       }\r
+       else\r
+       {\r
+               ypos = Math.floor(ypos);\r
+               \r
+               // exit if drawing off grid\r
+               \r
+               if ( (ypos >= PS.Grid.y) || ((ypos + h) < 1) ) \r
+               {\r
+                       return true;\r
+               }\r
+       }\r
+       \r
+       ptr = 0;        \r
+       drawy = ypos;\r
+       for ( j = 0; j < h; j += 1 )\r
+       {\r
+               drawx = xpos;\r
+               if ( drawy >= PS.Grid.y ) // exit if off bottom of grid\r
+               {\r
+                       break;\r
+               }\r
+               if ( drawy >= 0 ) // is this row visible?\r
+               {\r
+                       for ( i = 0; i < w; i += 1 )\r
+                       {\r
+                               if ( (drawx >= 0) && (drawx < PS.Grid.x) )\r
+                               {\r
+                                       r = bytes[ptr];\r
+                                       if ( typeof r !== "number" )\r
+                                       {\r
+                                               PS.Oops(fn + "non-numeric red at position " + ptr);\r
+                                               return PS.ERROR;\r
+                                       }\r
+                                       r = Math.floor(r);\r
+                                       if ( r < 1 )\r
+                                       { \r
+                                               r = 0;\r
+                                       }\r
+                                       else if ( r > 255 )\r
+                                       {\r
+                                               r = 255;\r
+                                       }\r
+                                       \r
+                                       g = bytes[ptr + 1];\r
+                                       if ( typeof g !== "number" )\r
+                                       {\r
+                                               PS.Oops(fn + "non-numeric green at position " + ptr);\r
+                                               return PS.ERROR;\r
+                                       }\r
+                                       g = Math.floor(g);\r
+                                       if ( g < 1 )\r
+                                       { \r
+                                               g = 0;\r
+                                       }\r
+                                       else if ( g > 255 )\r
+                                       {\r
+                                               g = 255;\r
+                                       }\r
+                                       \r
+                                       b = bytes[ptr + 2];\r
+                                       if ( typeof b !== "number" )\r
+                                       {\r
+                                               PS.Oops(fn + "non-numeric blue at position " + ptr);\r
+                                               return PS.ERROR;\r
+                                       }\r
+                                       b = Math.floor(b);\r
+                                       if ( b < 1 )\r
+                                       { \r
+                                               b = 0;\r
+                                       }\r
+                                       else if ( b > 255 )\r
+                                       {\r
+                                               b = 255;\r
+                                       }\r
+                                       \r
+                                       if ( pixsize === 4 )\r
+                                       {\r
+                                               a = bytes[ptr + 3];\r
+                                               if ( typeof a !== "number" )\r
+                                               {\r
+                                                       PS.Oops(fn + "non-numeric alpha at position " + ptr);\r
+                                                       return PS.ERROR;\r
+                                               }\r
+                                               a = Math.floor(a / 2.55); // convert 0-255 range to 0-100\r
+                                               if ( a < 1 )\r
+                                               { \r
+                                                       a = 0;\r
+                                               }\r
+                                               else if ( a > PS.DEFAULT_ALPHA )\r
+                                               {\r
+                                                       a = PS.DEFAULT_ALPHA;\r
+                                               }\r
+                                       }\r
+                                       else\r
+                                       {\r
+                                               a = PS.DEFAULT_ALPHA;   \r
+                                       }\r
+                                       \r
+                                       k = drawx + (drawy * PS.Grid.x); // get index of bead\r
+                                       bead = PS.Grid.beads[k];\r
+                               \r
+                                       bead.dirty = true; // mark this bead as explicitly colored\r
+                                       if ( a < PS.DEFAULT_ALPHA ) // Calc new color based on alpha-adjusted color of existing bead\r
+                                       {\r
+                                               bead.alphaRed = PS.Dissolve( PS.Grid.bgRed, bead.alphaRed, a );\r
+                                               bead.alphaGreen = PS.Dissolve( PS.Grid.bgGreen, bead.alphaGreen, a );\r
+                                               bead.alphaBlue = PS.Dissolve( PS.Grid.bgBlue, bead.alphaBlue, a );\r
+                                               bead.color = PS.RGBString( bead.alphaRed, bead.alphaGreen, bead.alphaBlue );\r
+                                       }\r
+                                       else\r
+                                       {\r
+                                               bead.alphaRed = r;\r
+                                               bead.alphaGreen = g;\r
+                                               bead.alphaBlue = b;\r
+                                               bead.color = PS.RGBString( r, g, b );\r
+                                       }\r
+                                       \r
+                                       // Do NOT change alpha value of existing bead!\r
+                                       \r
+                                       bead.red = r;\r
+                                       bead.green = g;\r
+                                       bead.blue = b;\r
+                               \r
+                                       if ( bead.visible )\r
+                                       {\r
+                                               bead.flashPhase = 100; // stops flash in progress\r
+                                               bead.colorNow = bead.color;\r
+                                               PS.DrawBead(bead);\r
+                                       }                                       \r
+                               }\r
+                               ptr += pixsize;\r
+                               drawx += 1;\r
+                       }\r
+               }\r
+               else\r
+               {\r
+                       ptr += (w * pixsize); // skip this row\r
+               }               \r
+               drawy += 1;             \r
+       }\r
+       \r
+       return true;    \r
+};\r