Index: /gs3-extensions/audioDB/trunk/src/interface/css/demo.css
===================================================================
--- /gs3-extensions/audioDB/trunk/src/interface/css/demo.css	(revision 26291)
+++ /gs3-extensions/audioDB/trunk/src/interface/css/demo.css	(revision 26291)
@@ -0,0 +1,124 @@
+/* 
+ -----------------------------------------------------------------
+ In-page demo CSS for code, documentation etc.
+ See page-player.css for actual playlist-relevant stuff.
+ -----------------------------------------------------------------
+ */
+
+#soundmanager-debug {
+ /* SM2 debug container (optional, makes debug more useable) */
+ position:absolute;position:fixed;*position:absolute;bottom:10px;right:10px;width:50em;height:18em;overflow:auto;background:#fff;margin:1em;padding:1em;border:1px solid #999;font-family:"lucida console",verdana,tahoma,"sans serif";font-size:x-small;line-height:1.5em;opacity:0.9;filter:alpha(opacity=90);z-index:99;
+}
+
+body {
+ font:75% normal verdana,arial,tahoma,"sans serif";
+}
+
+h1, h2, h3 {
+ font:300 3em "Helvetica Neue",georgia,"times new roman","Arial Rounded MT Bold",helvetica,verdana,tahoma,arial,"sans serif";
+ margin-bottom:0px;
+}
+
+h1, h2 {
+ letter-spacing:-1px; /* zomg web x.0! ;) */ 
+}
+
+h1, h2, h3 {
+ float:left;
+ clear:both;
+ border-bottom:1px solid #999;
+ padding-bottom:1px;
+ margin-bottom:0.25em;
+}
+
+h1 {
+ margin-top:0px;
+ margin-bottom:0px;
+ background-color:#666;
+ color:#ccc;
+ margin-left:-5px;
+ padding-left:5px;
+ padding-right:5px;
+}
+
+h1,
+h1 a {
+ color:#fff;
+ text-decoration:none;
+}
+
+h1 a:hover {
+ text-decoration:underline;
+}
+
+h2 {
+ font-size:2em;
+ margin-top:1em;
+ background-color:#aaa;
+ color:#fff;
+ padding:5px;
+ margin-left:-5px;
+ min-width:23em;
+}
+
+h3 {
+ font-size:1.65em;
+ margin-top:0.5em;
+ margin-bottom:0.25em;
+ color:#333;
+ min-width:28em;
+}
+
+h3 a {
+ font-size:small;
+}
+
+h4 {
+ color:#444;
+}
+
+ul.notes {
+ margin-left:0px;
+ padding-left:1.5em;
+}
+
+.note {
+ margin-top:0px;
+ font-style:italic;
+ color:#999;
+}
+
+pre {
+ font-size:1.2em;
+ _font-size:1em;
+}
+
+code {
+ font-family:"lucida console",monaco,courier,system;
+ font-size:1em;
+ color:#003366;
+}
+
+code span {
+ color:#666;
+}
+
+ul,
+p,
+pre {
+ clear:left;
+ max-width:46em;
+}
+
+ul.tight li {
+ max-width:44.5em;
+}
+
+ul.playlist {
+ /* undo the above nonsense */
+ max-width:none;
+}
+
+ul.tight {
+ padding-left:1.5em;
+}
Index: /gs3-extensions/audioDB/trunk/src/interface/css/flashblock.css
===================================================================
--- /gs3-extensions/audioDB/trunk/src/interface/css/flashblock.css	(revision 26291)
+++ /gs3-extensions/audioDB/trunk/src/interface/css/flashblock.css	(revision 26291)
@@ -0,0 +1,129 @@
+/*
+ * SoundManager 2 + useFlashBlock
+ * Flash positioning and flashblock / clicktoflash handling
+*/
+
+#sm2-container {
+ /*
+  * where the SM2 flash movie goes. by default, relative container.
+  * set relative or absolute here, and don't touch it later or bad things will happen (see below comments.)
+ */
+ position: absolute;
+ width: 1px;
+ height: 1px;
+ overflow: hidden;
+ /* screw IE 6, just make it display nice */
+ _overflow: hidden;
+}
+
+#sm2-container object,
+#sm2-container embed {
+ /*
+  * the actual SWF movie bit.
+  * important: The SWF needs to be able to be moved off-screen without display: or position: changes.
+  * changing display: or position: or overflow: here or on parent can cause SWF reload or other weird issues after unblock
+  * e.g., SM2 starts but strange errors, no whileplaying() etc.
+ */
+ width: 48px;
+ height: 48px;
+ /* some flash blockers may also respect this rule */
+ max-width: 48px;
+ max-height: 48px;
+}
+
+#sm2-container.swf_timedout {
+ /* expand to show the timed-out SWF content */
+ position: relative;
+ width: 48px;
+ height: 48px;
+}
+
+#sm2-container.swf_timedout,
+#sm2-container.swf_timedout object,
+#sm2-container.swf_timedout embed {
+ /* 
+  * when SM2 didn't start normally, time-out case. flash blocked, missing SWF, no flash?
+  * 48px square flash placeholder is typically used by blockers.
+ */
+ min-width: 48px;
+ min-height: 48px;
+}
+
+#sm2-container.swf_unblocked {
+ /* SWF unblocked, or was never blocked to begin with; try to collapse container as much as possible. */
+ width: 1px;
+ height: 1px;
+}
+
+#sm2-container.swf_loaded object,
+#sm2-container.swf_loaded embed,
+#sm2-container.swf_unblocked object,
+#sm2-container.swf_unblocked embed {
+ /* hide flash off-screen (relative to container) when it has loaded OK */
+ left: -9999em;
+ top: -9999em;
+}
+
+#sm2-container.swf_error {
+ /* when there is a fatal error (flash loaded, but SM2 failed) */
+ display: none;
+}
+
+#sm2-container.high_performance,
+#sm2-container.high_performance.swf_timeout {
+ /* "high performance" case: keep on-screen at all times */
+ position: absolute;
+ position: fixed;
+}
+
+#sm2-container.high_performance {
+ overflow: hidden;
+ _top: -9999px; /* IE 6 hax, no position:fixed */
+ _left: -9999px;
+ bottom: 0px;
+ left: 0px;
+ /*
+  * special case: show at first with w/h, hide when unblocked.
+  * might be bad/annoying.
+  * try to stay within ClickToFlash "invisible" limits (so it won't be blocked.)
+ */
+ z-index: 99; /* try to stay on top */
+}
+
+#sm2-container.high_performance.swf_loaded,
+#sm2-container.high_performance.swf_unblocked {
+ z-index: auto;
+}
+
+#sm2-container.high_performance.swf_loaded,
+#sm2-container.high_performance.swf_unblocked,
+#sm2-container.high_performance.swf_unblocked object,
+#sm2-container.high_performance.swf_unblocked embed {
+ /*
+  * 8x8px is required minimum to load in fx/win32 in some cases(?)
+  * 6x6+ good for fast performance, even better when on-screen via position:fixed
+  * also, clickToFlash (Safari <5.1) may auto-load "invisible" SWFs at this size
+ */
+ height: 8px;
+ width: 8px;
+}
+
+#sm2-container.high_performance.swf_loaded {
+ /* stay bottom/left */
+ top: auto;
+ bottom: 0px;
+ left: 0px;
+}
+
+#sm2-container.high_performance.swf_loaded object,
+#sm2-container.high_performance.swf_loaded embed,
+#sm2-container.high_performance.swf_unblocked object,
+#sm2-container.high_performance.swf_unblocked embed {
+ /* high-performance case must stay on-screen */
+ left: auto;
+ top: auto;
+}
+
+#sm2-container.high_performance.swf_timedout {
+ z-index: 99; /* try to stay on top */
+}
Index: /gs3-extensions/audioDB/trunk/src/interface/css/optional-annotations.css
===================================================================
--- /gs3-extensions/audioDB/trunk/src/interface/css/optional-annotations.css	(revision 26291)
+++ /gs3-extensions/audioDB/trunk/src/interface/css/optional-annotations.css	(revision 26291)
@@ -0,0 +1,168 @@
+/*
+ ------------------------------------------
+ -- annotations (sub-tracks, notes etc.) --
+ ------------------------------------------
+*/
+
+ul.playlist li a.sm2_link .metadata {
+ display:none; /* hide by default */
+}
+
+ul.playlist li.sm2_paused a.sm2_link .metadata,
+ul.playlist li.sm2_playing a.sm2_link .metadata {
+ display:inline;
+}
+
+ul.playlist li ul {
+ list-style-type:none;
+ margin:0px;
+ padding:0px;
+ position:relative;
+ font-size:small;
+ display:none;
+}
+
+ul.playlist li ul li {
+ position:relative;
+ margin:0px;
+ padding:2px 3px;
+ border:1px solid transparent;
+ -moz-border-radius:6px;
+ -khtml-border-radius:6px;
+ border-radius:6px;
+ margin-right:1em;
+ font-family:helvetica,verdana,tahoma,arial,"sans serif";
+ font-size:x-small;
+ font-weight:300;
+ letter-spacing:0px;
+ background-color:transparent;
+ opacity:0.66;
+}
+
+ul.playlist li ul li:hover {
+ opacity:1;
+ background-color:#fff;
+ border-color:#ccc;
+ color:#666;
+}
+
+ul.playlist li.sm2_playing ul li,
+ul.playlist li.sm2_paused ul li {
+ color:#fff;
+}
+
+ul.playlist li.sm2_playing ul li:hover {
+ background-color:#fff;
+ color:#5588bb;
+ border-color:#336699;
+ opacity:0.9;
+}
+
+ul.playlist li.sm2_paused ul li:hover {
+ background-color:#888;
+}
+
+/* metadata */
+
+ul.playlist li .metadata .duration {
+ /* optional timing data */
+ display:none;
+}
+
+ul.playlist li .metadata ul li p {
+ margin:0px;
+ padding:0px;
+}
+
+ul.playlist li .metadata ul li span {
+ display:none;
+}
+
+ul.playlist li .controls .statusbar .annotation {
+ position:absolute;
+ background-color:transparent;
+ top:0px;
+ color:#666;
+ text-align:right;
+ margin-left:10px;
+ height:0.5em;
+}
+
+ul.playlist li .controls .statusbar .annotation:hover {
+ z-index:12; /* sit on top of note */
+}
+
+ul.playlist li .controls .statusbar .annotation span.bubble {
+ /* using &middot; */
+ display:inline-block;
+ background-color:#fff;
+ border:1px solid #666;
+ border-radius:6px;
+ -moz-border-radius:6px;
+ -webkit-border-radius:6px;
+}
+
+ul.playlist li .controls .statusbar .annotation span {
+ display:block;
+ background:transparent url(../image/divot.png) no-repeat 50% 0px;
+ width:15px;
+ margin-left:-15px;
+ height:12px;
+ text-align:center;
+}
+
+ul.playlist li .controls .statusbar .annotation.alt {
+ top:auto;
+ bottom:0px;
+}
+
+ul.playlist li .controls .statusbar .annotation span:hover {
+ cursor:none; /* Fx3 rules. */
+ margin-top:0.1em;
+}
+
+ul.playlist li .controls .statusbar .annotation.alt span:hover {
+ margin-top:-0.1em;
+}
+
+ul.playlist li .controls .statusbar .annotation.alt span {
+ background:transparent url(../image/divot-bottom.png) no-repeat 50% bottom;
+}
+
+ul.playlist li .note {
+ position:absolute;
+ display:none;
+ left:0px;
+ top:0px;
+ z-index:10;
+ font-size:x-small;
+ padding:2px 4px 2px 4px;
+ width:auto;
+ color:#666;
+ background-color:#fff;
+ border:1px solid #ccc;
+ border-radius:6px;
+ -moz-border-radius:6px;
+ -webkit-border-radius:6px;
+ font-style:normal;
+ font-weight:bold;
+ font-family:arial,tahoma,verdana,"sans serif";
+ letter-spacing:0px;
+ margin-top:1.1em;
+}
+
+ul.playlist li .note.alt {
+ margin-top:-1.32em;
+}
+
+ul.playlist li .note:hover {
+ display:block !important;
+}
+
+ul.playlist li .sm2_divider {
+ font-size:0.75em;
+}
+
+ul.playlist li .sm2_metadata {
+ font-size:0.65em;
+}
Index: /gs3-extensions/audioDB/trunk/src/interface/css/optional-themes.css
===================================================================
--- /gs3-extensions/audioDB/trunk/src/interface/css/optional-themes.css	(revision 26291)
+++ /gs3-extensions/audioDB/trunk/src/interface/css/optional-themes.css	(revision 26291)
@@ -0,0 +1,206 @@
+/* 
+ ---------------------------------
+ -- alternate (optional) themes --
+ ---------------------------------
+*/
+
+ul.playlist.dark li.sm2_playing a {
+ color:#fff;
+}
+
+ul.playlist.dark li.sm2_playing .timing,
+ul.playlist.use-peak.dark li.sm2_playing .peak {
+ color:#999;
+}
+
+ul.playlist.use-spectrum.dark li.sm2_playing .spectrum-container {
+ background-color:#222;
+ border-color:#444;
+}
+
+ul.playlist.use-spectrum.dark li.sm2_playing .spectrum-container .spectrum {
+ background-color:#999;
+}
+
+ul.playlist.dark li.sm2_paused {
+ background-color:#333;
+}
+
+ul.playlist.dark li.sm2_paused a {
+ color:#999;
+}
+
+ul.playlist.dark li.sm2_playing,
+ul.playlist.dark li.sm2_playing:hover {
+ background-color:#333;
+}
+
+ul.playlist.dark li:hover .controls .statusbar {
+ background-color:#666;
+}
+
+ul.playlist.dark li .controls {
+ background-color:#333;
+}
+
+ul.playlist.dark li .controls .statusbar {
+ background-color:#666;
+ border-color:#444;
+}
+
+ul.playlist.dark li .controls .statusbar .position {
+ background-color:#111;
+ border-right:3px solid #111;
+ border-radius:3px;
+ -moz-border-radius:3px;
+ -webkit-border-radius:3px;
+}
+
+ul.playlist.dark li .controls .statusbar .loading {
+ background-color:#444;
+}
+
+ul.playlist.dark li .timing,
+ul.playlist.use-peak.dark li .peak {
+ background-color:#222;
+ border-color:#444;
+}
+
+ul.playlist.dark.use-peak li .peak .l,
+ul.playlist.dark.use-peak li .peak .r {
+ border-color:#444;
+ background-color:#999;
+}
+
+
+/* gold theme */
+
+ul.playlist.gold li.sm2_paused {
+ background-color:#996600;
+}
+
+ul.playlist.gold li.sm2_playing,
+ul.playlist.gold li.sm2_playing:hover {
+ background-color:#cc9900;
+}
+
+ul.playlist.gold li .controls {
+ background-color:transparent;
+}
+
+ul.playlist.gold li .controls .statusbar {
+ background-color:#fff;
+ border-color:#fff;
+}
+
+ul.playlist.gold li .controls .statusbar .position {
+ background-color:#996600;
+ border-right:3px solid #996600;
+ border-radius:3px;
+ -moz-border-radius:3px;
+ -webkit-border-radius:3px;
+}
+
+ul.playlist.gold li .controls .statusbar .loading {
+ background-color:#ffeedd;
+}
+
+ul.playlist.gold li .timing,
+ul.playlist.use-peak.gold li .peak {
+ background-color:#CC9900;
+ border-color:#ffcc33;
+}
+
+ul.playlist.use-spectrum.gold li.sm2_playing .spectrum-container {
+ background-color:#cc9900;
+ border-color:#ffcc33;
+}
+
+ul.playlist.use-spectrum.gold li.sm2_playing .spectrum-container .spectrum {
+ background-color:#fff;
+}
+
+ul.playlist.gold.use-peak li .peak .l,
+ul.playlist.gold.use-peak li .peak .r {
+ border-color:#fff;
+ background-color:#fff;
+}
+
+
+/* ZOMG PONIES!!!ONEONEONE */
+
+ul.playlist.bubblegum li a {
+ font-family:"comic sans ms",verdana,arial,tahoma,"sans serif"; /* heh */
+}
+
+ul.playlist.bubblegum li.sm2_paused,
+ul.playlist.bubblegum li.sm2_paused:hover {
+ background-color:#ffccee;
+}
+
+ul.playlist.bubblegum li.sm2_paused a,
+ul.playlist.bubblegum li.sm2_paused:hover a,
+ul.playlist.bubblegum li.sm2_paused .timing,
+ul.playlist.use-peak.bubblegum li.sm2_paused .peak {
+ color:#ff6699;
+}
+
+ul.playlist.bubblegum li:hover {
+ background-color:#ffddee;
+}
+
+ul.playlist.bubblegum li.sm2_playing,
+ul.playlist.bubblegum li.sm2_playing:hover {
+ background-color:#ff7799;
+}
+
+ul.playlist.bubblegum li .controls {
+ background-color:transparent;
+}
+
+ul.playlist.bubblegum li .controls .statusbar {
+ background-color:#fff;
+ border-color:#fff;
+}
+
+ul.playlist.bubblegum li .controls .statusbar .position {
+ background-color:#ffaacc;
+ border-right:3px solid #ffaacc;
+ border-radius:3px;
+ -moz-border-radius:3px;
+ -webkit-border-radius:3px;
+}
+
+ul.playlist.bubblegum li .controls .statusbar .loading {
+ background-color:#ffeedd;
+}
+
+ul.playlist.bubblegum li .timing,
+ul.playlist.use-peak.bubblegum li .peak {
+ background-color:#ffaacc;
+ border-color:#ffccee;
+}
+
+ul.playlist.use-spectrum.bubblegum li.sm2_playing .spectrum-container {
+ background-color:#ffaacc;
+ border-color:#ffccee;
+}
+
+ul.playlist.use-spectrum.bubblegum li.sm2_playing .spectrum-container .spectrum {
+ background-color:#fff;
+}
+
+ul.playlist.bubblegum.use-peak li .peak .l,
+ul.playlist.bubblegum.use-peak li .peak .r {
+ border-color:#fff;
+ background-color:#fff;
+}
+
+
+ul.playlist.shiny li.sm2_paused,
+ul.playlist.shiny li.sm2_playing {
+ background-image:url(../image/top-highlight.png);
+ background-repeat:repeat-x;
+ background-position:0px -1px;
+ _background-image:none; /* can't be bothered with IE 6. */
+}
Index: /gs3-extensions/audioDB/trunk/src/interface/css/page-player.css
===================================================================
--- /gs3-extensions/audioDB/trunk/src/interface/css/page-player.css	(revision 26291)
+++ /gs3-extensions/audioDB/trunk/src/interface/css/page-player.css	(revision 26291)
@@ -0,0 +1,346 @@
+/*
+
+ SoundManager 2: "page as playlist" example
+ ------------------------------------------
+ http://schillmania.com/projects/soundmanager2/
+
+*/
+
+li.rounded {
+  border-radius: 15px;
+}
+
+
+div.divbuttonon {
+  background-color: #008000;
+  color: white;
+}
+
+div.divbuttonoff {
+  background-color: white;
+  color: black;
+}
+
+span.spanbuttonon {
+  background-color: #008000;
+  color: white;
+}
+
+span.spanbuttonoff {
+  background-color: white;
+  color: black;
+}
+
+
+.spectrum-container {
+ display:none;
+}
+
+ul.use-spectrum li.sm2_playing .spectrum-container {
+ position:absolute;
+ left:0px;
+ top:0px;
+ margin-left:-266px;
+ margin-top:-1px;
+ display:block;
+ background-color:#88bb55;
+ border:1px solid #ccff99;
+ -moz-border-radius:4px;
+ -webkit-border-radius:4px;
+ border-radius:4px;
+}
+
+ul.use-spectrum .spectrum-box {
+ position:relative;
+ width:255px;
+ font-size:1em;
+ padding:2px 0px;
+ height:1.2em;
+ overflow:hidden;
+}
+
+ul.use-spectrum .spectrum-box .spectrum {
+ position:absolute;
+ left:0px;
+ top:-2px;
+ margin-top:20px;
+ display:block;
+ font-size:1px;
+ width:1px;
+ height:1px; /* set to 50px for a thick line, 1px for a thin line, etc. */
+ overflow:hidden;
+ background-color:#fff;
+}
+
+ul.playlist {
+ list-style-type:none;
+ margin:0px;
+ padding:0px;
+
+}
+
+ul.playlist li {
+ /* assume all items will be sounds rather than wait for onload etc. in this example.. may differ for your uses. */
+ position:relative;
+ display:block;
+ width:auto;
+ font-size:1.2em;
+ color:#666;
+ padding:0.25em 0.5em 0.25em 0.5em;
+ border:none;
+ letter-spacing:-1px; /* ZOMG WEB X.0. ;) */
+ background-color:#007900;
+ -webkit-transition-property: hover;
+ -webkit-transition: background-color 0.15s ease-in-out;
+ -moz-transition: background-color 0.15s linear 0s; /* firefox 4 */
+  -o-transition-property: background-color; /* opera 10.5 */
+  -o-transition-duration: 0.15s;
+
+}
+
+ul.playlist li a {
+ display:block;
+ text-decoration:none;
+ font-weight:normal;
+ color:#fff;
+ font-size:100%;
+ outline:none;
+ position:relative;
+ z-index:2;
+}
+
+ul.playlist li.sm2_playing,
+ul.playlist li.sm2_paused,
+ul.playlist li.sm2_playing a {
+ color:#fff;
+ border-radius:3px;
+ -webkit-border-radius:3px;
+ -moz-border-radius:3px;
+}
+
+ul.playlist li:hover {
+ background-color:#00aa00;
+}
+
+ul.playlist li:hover a {
+ color:#fff;
+}
+
+ul.playlist li.sm2_playing,
+ul.playlist li.sm2_playing:hover {
+ background-color:#99cc66;
+}
+
+ul.playlist li.sm2_paused {
+ background-color:#a55;
+}
+
+ul.playlist li.sm2_playing:hover a,
+ul.playlist li.sm2_paused a {
+ color:#fff;
+}
+
+ul.playlist li .controls {
+ display:none;
+}
+
+ul.playlist li .peak,
+ul.playlist.use-peak li .peak {
+ display:none;
+ position:absolute;
+ top:0.55em;
+ right:0.5em;
+}
+
+ul.playlist li.sm2_playing .controls,
+ul.playlist li.sm2_paused .controls {
+ position:relative;
+ display:block;
+}
+
+ul.playlist.use-peak li.sm2_playing .peak,
+ul.playlist.use-peak li.sm2_paused .peak {
+ display:inline;
+ display:inline-block;
+}
+
+ul.playlist.use-peak li .peak {
+ display:none; /* IE 7 */
+}
+
+ul.playlist li.sm2_paused .controls {
+ background-color:#a88;
+}
+
+ul.playlist li:hover .controls .statusbar {
+ position:relative;
+ cursor:ew-resize;
+ cursor:-moz-grab;
+ cursor:grab;
+}
+
+ul.playlist li.sm2_paused .controls .statusbar {
+ background-color:#fcc;
+}
+
+ul.playlist li .controls {
+ position:relative;
+ margin-top:0.25em;
+ margin-bottom:0.25em;
+ background-color:#ccff99;
+}
+
+ul.playlist li .controls .statusbar {
+ position:relative;
+ height:0.5em;
+ background-color:#ddffcc;
+ border:2px solid #fff;
+ border-radius:2px;
+ -moz-border-radius:2px;
+ -webkit-border-radius:2px;
+ overflow:hidden;
+ cursor:-moz-grab;
+ cursor:grab;
+}
+
+ul.playlist li .controls.dragging .statusbar {
+ cursor:-moz-grabbing;
+ cursor:grabbing;
+}
+
+ul.playlist li .controls .statusbar .position,
+ul.playlist li .controls .statusbar .loading,
+ul.playlist li .controls .statusbar .annotation {
+ position:absolute;
+ left:0px;
+ top:0px;
+ height:0.5em;
+}
+
+ul.playlist li .controls .statusbar .position {
+ background-color:#669933;
+ border-right:3px solid #669933;
+ border-radius:3px;
+ -moz-border-radius:3px;
+ -webkit-border-radius:3px;
+}
+
+ul.playlist li.sm2_paused .controls .statusbar .position {
+ background-color:#a88;
+ border-color:#a88;
+}
+
+ul.playlist li .controls .statusbar .loading {
+ background-color:#eee;
+}
+
+ul.playlist li .controls .statusbar .position,
+ul.playlist li .controls .statusbar .loading {
+ width:0px;
+}
+
+ul.playlist li.sm2_playing a.sm2_link,
+ul.playlist li.sm2_paused a.sm2_link {
+ margin-right:4.5em; /* room for timing stuff */
+}
+
+ul.playlist li .timing {
+ position:absolute;
+ display:none;
+ text-align:right;
+ right:1em;
+ top:1em;
+ width:auto;
+ height:1em;
+ padding:3px 5px;
+ background-color:#88bb55;
+ border:1px solid #ccff99;
+ -moz-border-radius:4px;
+ -khtml-border-radius:4px;
+ border-radius:4px;
+ letter-spacing:0px;
+ font:44% monaco,"VT-100","lucida console",courier,system;
+ line-height:1em;
+ vertical-align:middle;
+}
+
+ul.playlist.use-peak li .timing {
+ right:4.25em;
+}
+
+ul.playlist li:hover .timing {
+ z-index:2;
+}
+
+ul.playlist li .timing div.sm2_timing {
+ margin:0px;
+ padding:0px;
+ margin-top:-1em;
+}
+
+ul.playlist li.sm2_playing .timing,
+ul.playlist li.sm2_paused .timing {
+ display:block;
+}
+
+ul.playlist li.sm2_paused .timing .sm2_position {
+ text-decoration:blink; /* hee hee. first actual appropriate use? :D */
+}
+
+ul.playlist li.sm2_paused .timing,
+ul.playlist.use-peak li.sm2_paused .peak {
+ background-color:#caa;
+ border-color:#fcc;
+}
+
+/* peak data */
+
+/* ul.playlist ... */
+
+ul.playlist.use-peak li .peak {
+ display:none;
+ zoom:1;
+ border:1px solid #ccff99;
+ padding:2px;
+ height:0.55em;
+ -moz-border-radius:4px;
+ -khtml-border-radius:4px;
+ border-radius:4px;
+ background-color:#88bb55;
+ width:0.8em;
+ height:0.55em;
+ margin-top:-3px;
+}
+
+ul.playlist.use-peak li .peak-box {
+ position:relative;
+ width:100%;
+ height:0.55em;
+ overflow:hidden;
+}
+
+ul.playlist li .peak .l,
+ul.playlist li .peak .r {
+ position:absolute;
+ left:0px;
+ top:0px;
+ width:7px;
+ height:50px;
+ background:#fff;
+ border:1px solid #fff;
+ -moz-border-radius:1px;
+ -khtml-border-radius:1px;
+ margin-top:1em;
+}
+
+ul.playlist li .peak .l {
+ margin-right:1px;
+}
+
+ul.playlist li .peak .r {
+ left:10px;
+}
+
+#control-template {
+ display:none;
+}
Index: /gs3-extensions/audioDB/trunk/src/interface/js/audioDB-play.js
===================================================================
--- /gs3-extensions/audioDB/trunk/src/interface/js/audioDB-play.js	(revision 26291)
+++ /gs3-extensions/audioDB/trunk/src/interface/js/audioDB-play.js	(revision 26291)
@@ -0,0 +1,74 @@
+
+var SVG_NS ="http://www.w3.org/2000/svg";
+var XLINK_NS = "http://www.w3.org/1999/xlink";
+
+
+
+function svgAudioDBInit() 
+{
+    var segsElem = document.getElementById("svgAudioDBSegments");
+    var mysong = document.getElementById("mysong");
+
+    var barWidth = mysong.getElementWidth();
+
+    var frameOffsetList = frameOffsetStr.split(",");
+    frameOffsetList.sort(function(a,b){return a-b});
+
+    prevOffsetInSecs = 0.0;
+
+    for (i=0; i < frameOffsetList.length; i++) {
+        var frameOffset = frameOffsetList[i];
+        var offsetInSecs=(250*frameOffset)/1000.0;
+
+        if (i > 0) { 
+	  var frameLengthInSecs = frameLength * 250 / 1000;
+
+	  if ((offsetInSecs - prevOffsetInSecs) < frameLengthInSecs)   {
+	      continue;
+	  }
+	}
+
+	var x = barWidth * offsetInSecs / duration;
+	var y = 0;
+
+	var gElem = document.createElementNS(SVG_NS,'g');
+	gElem.setAttribute('transform','translate('+x+','+y+')');
+
+	var rectElem = document.createElementNS(SVG_NS,'rect');
+	rectElem.setAttribute('width',150);
+	rectElem.setAttribute('height','24');
+	rectElem.setAttribute('x','0');
+	rectElem.setAttribute('y','0');
+	rectElem.setAttribute('fill', 'rgb(100%,100%,70%)');
+
+	var playImgElem = document.createElementNS(SVG_NS,"image");
+	playImgElem.setAttributeNS(XLINK_NS, "xlink:href", 
+				   "ext/audioDB/icons/play20.png");
+	playImgElem.setAttribute("x","2");
+	playImgElem.setAttribute("y","2");
+	playImgElem.setAttribute("width","20");
+	playImgElem.setAttribute("height","20");
+
+	var onclick ="playFromOffset('mysong'," + frameOffset + ")";
+	playImgElem.setAttribute("onclick",onclick);
+
+	playImgElem.setAttribute("onmouseover","playHighlightOnSVG(evt.target,20)");
+	playImgElem.setAttribute("onmouseout", "playHighlightOffSVG(evt.target,20)");
+
+	var textElem = document.createElementNS(SVG_NS,'text');
+	textElem.setAttribute('x','24');
+	textElem.setAttribute('y','16');
+	textElem.setAttribute("style","color: black; font-size: 75%;");
+
+	var textNode = document.createTextNode("match @ "+ offsetInSecs + " secs");
+	textElem.appendChild(textNode);
+
+
+	gElem.appendChild(rectElem);
+	gElem.appendChild(playImgElem);
+	gElem.appendChild(textElem);
+	segsElem.appendChild(gElem);
+
+	prevOffsetInSecs = offsetInSecs;
+    }
+}
Index: /gs3-extensions/audioDB/trunk/src/interface/js/similarity-matrix-play.js
===================================================================
--- /gs3-extensions/audioDB/trunk/src/interface/js/similarity-matrix-play.js	(revision 26291)
+++ /gs3-extensions/audioDB/trunk/src/interface/js/similarity-matrix-play.js	(revision 26291)
@@ -0,0 +1,549 @@
+
+// Audio objects
+var baseSong;
+var leftSong;
+var rightSong;
+
+var pannedPlayback = new Audio();
+
+var leftBuffers = [];
+var rightBuffers = [];
+
+var leftStartTimeSecs  = 0.0;
+var rightStartTimeSecs = 0.0;
+var leftStartTimeOffset  = 0;
+var rightStartTimeOffset = 0;
+
+var playTrackerMode = "stopped";
+
+var startPlayX;
+var startPlayY;
+
+var pannedPlayWidth;
+var pannedPlayHeight;
+
+var prevPlayedX = -1;
+var prevPlayedY = -1;
+
+//var prevPlayedOffset = -1;
+
+var preparingDualAudio = 0;
+
+function resetAudioBuffers()
+{
+    //console.log("Panned audio playback buffers initialized/reset");
+
+    pannedPlayback = new Audio();
+    pannedPlayback.mozSetup(2, baseSong.mozSampleRate);
+
+    leftBuffers = [];
+    rightBuffers = [];
+
+    leftStartTimeSecs  = 0.0;
+    rightStartTimeSecs = 0.0;
+    leftStartTimeOffset  = 0;
+    rightStartTimeOffset = 0;
+
+    prevPlayedX = -1;
+    prevPlayedY = -1;
+
+    // prevPlayedOffset = -1;
+}
+
+
+
+function dualPlay(evt) 
+{
+    var mouse_x = evt.pageX;
+    var mouse_y = evt.pageY;
+
+    // display busy/loading cursor
+    var playTrackerBusy = document.getElementById("playtrackerBusy");
+    playTrackerBusy.setAttribute("style","visibility: visible;");
+    preparingDualAudio = 1;
+
+    var selfSimImg = document.getElementById("selfSimImgId");
+    var imgWidth   = selfSimImg.getAttribute("width");
+    var imgHeight  = selfSimImg.getAttribute("height") * yScaleSimImg;
+    
+    //console.log("image w x h = " + imgWidth +"," + imgHeight);
+
+    var img_x = $("#selfSimImgId").offset().left;
+    var img_y = $("#selfSimImgId").offset().top;
+   
+    var x_org = mouse_x - img_x;
+    var y_org = mouse_y - img_y;
+    var adjusted_y_org = imgHeight - y_org;
+    
+    //console.log("img (x y) = (" + img_x + "," + img_y + ")");
+    //console.log("mouse (x y) = (" + mouse_x + "," + mouse_y + ")");
+    //console.log("(x y) = (" + x_org + "," + adjusted_y_org + ")");
+
+    startPlayX = x_org;
+    startPlayY = y_org;
+
+    pannedPlayWidth  = imgWidth - x_org;
+    pannedPlayHeight = y_org;
+
+    resetAudioBuffers();
+
+    var baseSongSrc="sites/localsite/collect/" + collect +"/import/"+source;
+
+    leftStartTimeSecs  = duration * (x_org / imgWidth);
+    rightStartTimeSecs = duration * (adjusted_y_org / imgHeight);
+
+    var sampleMult = baseSong.mozSampleRate * baseSong.mozChannels;
+    leftStartTimeOffset  = leftStartTimeSecs * sampleMult;
+    rightStartTimeOffset = rightStartTimeSecs * sampleMult;
+
+    //leftSong.src  = baseSongSrc + "#t=" + leftStartTimeSecs + ",";
+    //rightSong.src = baseSongSrc + "#t=" + rightStartTimeSecs + ",";
+
+    leftSong.currentTime = leftStartTimeSecs;
+    leftSong.play();
+
+    rightSong.currentTime = rightStartTimeSecs;
+    rightSong.play();
+
+    // console.log("play tracker mode = " + playTrackerMode);
+    if (togglePlayMode.match("pause")) {
+	// i.e. currently displaying the pause button
+	// stop
+	if (playTrackerMode.match("stopped")) {
+	    // => playing through the main play bar
+	    soundManager.stopAll();
+	    togglePlayVisual(document.getElementById("mainPlayButton"));
+	}
+    }
+
+    if (!playTrackerMode.match("playing")) {
+	togglePlayVisual(document.getElementById("mainPlayButton"));
+    }
+}
+
+
+function playTrackerOn(evt) 
+{
+    var playTracker = document.getElementById("playtracker");
+    playTrackerMove(evt);
+    playTracker.setAttribute("style","visibility: visible");
+}
+
+function playTrackerOff(evt) 
+{    
+    var playTracker = document.getElementById("playtracker");
+    playTracker.setAttribute("style","visibility: hidden");
+}
+
+function updateLeftAndRightTimes(cx,cy)
+{
+    var selfSimImg = document.getElementById("selfSimImgId");
+    var imgWidth  = selfSimImg.getAttribute("width");
+    var imgHeight = selfSimImg.getAttribute("height") * yScaleSimImg;
+
+    var adjusted_cy = imgHeight - cy;
+
+    //var mysong = document.getElementById("mysong");
+    //var barWidth = mysong.getElementWidth();
+
+
+    // update L & R times on tracker
+    var currPlayedXInSecs = (cx/imgWidth) * duration;
+    var currPlayedYInSecs = (adjusted_cy/imgHeight) * duration;
+
+    // Deliberately crossed to fit visual playTracker circlea 
+
+    var leftTime = document.getElementById("leftTime");
+    var leftText = "R: " + currPlayedXInSecs.toFixed(0) + " secs"; 
+    // (used to do 1 decimal place)
+
+    leftTextNode = leftTime.childNodes[0];
+    leftTextNode.nodeValue = leftText;
+
+    var rightTime = document.getElementById("rightTime");
+    var rightText = "L: " + currPlayedYInSecs.toFixed(0) + " secs";
+        
+    rightTextNode = rightTime.childNodes[0];
+    rightTextNode.nodeValue = rightText;
+
+    // console.log("left text = " + leftText);
+    // console.log("right text = " + rightext);
+}
+
+
+function playTrackerMove(evt) 
+{
+    if (!playTrackerMode.match("playing")) {
+	var mouse_x = evt.pageX;
+	var mouse_y = evt.pageY;
+
+	var img_x = $("#selfSimImgId").offset().left;
+	var img_y = $("#selfSimImgId").offset().top;
+   
+	var x_org = mouse_x - img_x;
+	var y_org = mouse_y - img_y;
+    
+	updateLeftAndRightTimes(x_org,y_org);
+
+	var playTracker = document.getElementById("playtracker");
+	var transform = "translate("+x_org+","+y_org+")";
+	playTracker.setAttribute("transform",transform);
+    }
+
+}
+
+function svgInitSimilarityPlay() 
+{
+    var mysong = document.getElementById("mysong");
+    var barWidth = mysong.getElementWidth();
+
+    var baseSongSrc="sites/localsite/collect/" + collect +"/import/"+source;
+
+    baseSong = new Audio();
+    baseSong.src = baseSongSrc;
+    baseSong.control = "control";
+
+    baseSong.addEventListener('MozAudioAvailable', audioAvailable, false);
+    baseSong.addEventListener('loadedmetadata', loadedMetadata, false);
+
+    //leftSong = new Audio();
+    leftSong = document.getElementById("leftsong");
+    leftSong.addEventListener('MozAudioAvailable', audioAvailableLeft, false);
+    leftSong.addEventListener('loadedmetadata', loadedMetadataLeft, false);
+
+    //rightSong = new Audio();
+    rightSong = document.getElementById("rightsong")
+    rightSong.addEventListener('MozAudioAvailable', audioAvailableRight, false);
+    rightSong.addEventListener('loadedmetadata', loadedMetadataRight, false);
+
+
+    // Set up self similarity image
+
+    var selfSimImgSrc="sites/localsite/collect/" + collect +"/bordered/line-interlaced/"+self_sim_png;
+    //console.log("self sim img = " + selfSimImgSrc);
+
+    var simPlayLine = document.getElementById("simPlayLineGroup");
+
+    simPlayLine.setAttributeNS(SVG_NS,"transform","scale(1.0,"+yScaleSimImg+")");
+
+    var selfSimImg = document.createElementNS(SVG_NS,"image");
+    selfSimImg.setAttributeNS(XLINK_NS, "xlink:href", selfSimImgSrc);
+
+    var selfSimImgWidth  = barWidth;
+    var selfSimImgHeight = barWidth * (815.0 / 776.0);
+
+    selfSimImg.setAttribute("x",0);
+    selfSimImg.setAttribute("y",0);
+    selfSimImg.setAttribute("id","selfSimImgId");
+    selfSimImg.setAttribute("width",barWidth);
+    selfSimImg.setAttribute("height",selfSimImgHeight);
+    selfSimImg.setAttribute("onclick","dualPlay(evt)");
+    selfSimImg.setAttribute("onmousemove","playTrackerMove(evt)");
+    selfSimImg.setAttribute("onmouseover","playTrackerOn(evt)");
+    //selfSimImg.setAttribute("onmouseout","playTrackerOff(evt)");
+
+    simPlayLine.appendChild(selfSimImg);
+
+    var svgSimilarityPlay = document.getElementById("svgSimilarityPlay");
+    svgSimilarityPlay.setAttribute("height",0 + selfSimImgHeight * yScaleSimImg); // used to be 30 +
+
+
+    // Firefox doesn't seem to like this being initialized statically
+    // in the HTML page generate, so add it dynamically here
+    var playTrackerBusy = document.getElementById("playtrackerBusy");
+    playTrackerBusy.setAttributeNS(XLINK_NS,"xlink:href",
+				   "ext/audioDB/icons/wait30trans.gif");
+
+}
+
+
+
+
+function loadedMetadata() {
+    // Mute baseSong audio.
+    baseSong.volume = 0;
+
+    // Set up a pannedPlayback for baseSong to routed through
+    // console.log("num channels = " + baseSong.mozChannels);
+
+    pannedPlayback.mozSetup(2, baseSong.mozSampleRate);
+}
+
+
+function loadedMetadataLeft() {
+    // Mute baseSong audio.
+    leftSong.volume = 0;
+
+    //leftSong.currentTime = leftStartTimeSecs;
+    //leftSong.play();
+    //console.log("left start time = " + leftStartTimeSecs);
+}
+
+
+function loadedMetadataRight() {
+    // Mute baseSong audio.
+    rightSong.volume = 0;
+
+    //rightSong.currentTime = rightStartTimeSecs;
+    //rightSong.play();
+    //console.log("right start time = " + rightStartTimeSecs);
+
+}
+
+function audioAvailable(event) {
+    // Write the current framebuffer
+    alert("audioAvailable() should no longer be called");
+    var frameBuffer = event.frameBuffer; // frameBuffer is Float32Array
+    //writeAudio(frameBuffer);
+}
+
+function audioAvailableLeft(event) 
+{
+    // Write the current framebuffer
+    var frameBuffer = event.frameBuffer; 
+    writeAudio(frameBuffer,"left");
+
+}
+
+function audioAvailableRight(event) 
+{
+    // Write the current framebuffer
+    var frameBuffer = event.frameBuffer; 
+    writeAudio(frameBuffer,"right");
+}
+
+
+
+
+function activeAudioBuffer(audioBuffer,currentFullBufferSize,startTime) 
+{
+    var buffer;
+    if (currentFullBufferSize < startTime) {
+	// active audio starts at offset within this segment of audioBuffer
+
+	var position = startTime - currentFullBufferSize;
+	buffer = audioBuffer.subarray(position);
+    }
+    else {
+	buffer = audioBuffer;
+    }
+    return buffer;
+}
+
+function panLeftEffect(buffer,s,panned_buffer,d) 
+{
+    panned_buffer[d] = buffer[s];
+    if ((d+1) < panned_buffer.length) {
+	panned_buffer[d+1] = 0;
+    }
+}
+
+function panRightEffect(buffer,s,panned_buffer,d) 
+{
+    panned_buffer[d] = 0;
+    if ((d+1) < panned_buffer.length) {
+	panned_buffer[d+1] = buffer[s];
+    }
+}
+
+function panAudioBuffersHead(buffer,position,panEffect)
+{
+    var remaining_len = buffer.length - position;
+    var panned_buffer;
+    if (baseSong.mozChannels == 1) {
+	panned_buffer = new Float32Array(remaining_len * 2);
+
+	var d=0;
+	for (var s=position; s < buffer.length; s++) {
+	    panEffect(buffer,s,panned_buffer,d);
+	    d += 2;
+	}
+    }
+    else {
+	// assume stereo
+	panned_buffer = new Float32Array(remaining_len);
+      
+	var d=0;
+	for (var s=position; s < buffer.length; s+=2) {
+	    panEffect(buffer,s,panned_buffer,d);
+	    d += 2;
+	}
+    }
+
+    return panned_buffer;
+}
+
+function mergeLeftAndRightPan(leftPannedBuffer,rightPannedBuffer)
+{
+    // left and right buffers guaranteed to be stereo samples
+ 
+    // Deliberately crossed to fit visual playTracker circlea 
+
+    var leftLen  = leftPannedBuffer.length;
+    var rightLen = rightPannedBuffer.length;
+    var maxLen = Math.max(leftLen,rightLen);
+
+    var pannedBuffer = new Float32Array(maxLen);
+
+    for (i=0; i < maxLen; i+=2) {
+
+        if (i < leftLen-1) {
+	    // i+1 actually right pos
+	    pannedBuffer[i+1] = leftPannedBuffer[i];
+	}
+	else {
+	    pannedBuffer[i+1] = 0;
+	}
+
+        if (i < rightLen-1) {
+	    // actually left pos
+	    pannedBuffer[i] = rightPannedBuffer[i+1];
+	}
+	else {
+	    pannedBuffer[i] = 0;
+	}
+    }
+
+    return pannedBuffer;
+
+}
+
+function writeAudio(audioBuffer,channel) 
+{
+
+    var mysong = document.getElementById("mysong");
+    var barWidth = mysong.getElementWidth();
+
+    // audioBuffer is Float32Array
+    var audioBufferLen = audioBuffer.length; 
+
+    if (channel.match("left")) {
+        //var leftBuffer = activeAudioBuffer(audioBuffer,totalFullBufferSize,leftStartTimeOffset);
+	leftBuffers.push({buffer: audioBuffer, position: 0});
+    }
+
+    if (channel.match("right")) {
+        //var rightBuffer = activeAudioBuffer(audioBuffer,totalFullBufferSize,rightStartTimeOffset);
+	rightBuffers.push({buffer: audioBuffer, position: 0});
+    }
+
+
+    // If there's buffered data in both left and right buffers,
+    // then it's time to play something 
+
+    var currPlayedX = null;
+    var currPlayedY = null;
+
+    while ((leftBuffers.length > 0) && (rightBuffers.length > 0)) {
+
+	if (preparingDualAudio) {
+	    var playTrackerBusy= document.getElementById("playtrackerBusy");
+	    playTrackerBusy.setAttribute("style","visibility: hidden;");
+	    preparingDualAudio = 0;
+	}
+
+
+        var leftBuffer = leftBuffers[0].buffer;
+	var leftBufferPos = leftBuffers[0].position;
+        var leftPannedBuffer  = panAudioBuffersHead(leftBuffer,leftBufferPos,panLeftEffect);
+
+        var rightBuffer = rightBuffers[0].buffer;
+	var rightBufferPos = rightBuffers[0].position;
+        var rightPannedBuffer = panAudioBuffersHead(rightBuffer,rightBufferPos,panRightEffect);
+
+        var pannedBuffer = mergeLeftAndRightPan(leftPannedBuffer,rightPannedBuffer);
+
+	// Send something to be played
+	var written = pannedPlayback.mozWriteAudio(pannedBuffer);
+
+	// get current play pos, and plot on selfSimImg
+	var currentPlayedOffset = pannedPlayback.mozCurrentSampleOffset();
+
+	var sampleRate = pannedPlayback.mozSampleRate;
+	var numChannels = pannedPlayback.mozChannels;
+
+	var pannedDurationLeft  = duration - leftStartTimeSecs;
+	var pannedDurationRight = duration - rightStartTimeSecs;
+
+	var totalNumSamplesLeft  = sampleRate * numChannels * pannedDurationLeft;
+	var totalNumSamplesRight = sampleRate * numChannels * pannedDurationRight;
+
+	var currentPlayedPercLeft  = currentPlayedOffset/totalNumSamplesLeft;
+	var currentPlayedPercRight = currentPlayedOffset/totalNumSamplesRight;
+
+
+	var currPlayedXPrecise = startPlayX + (currentPlayedPercLeft*pannedPlayWidth);
+	var currPlayedYPrecise = startPlayY - (currentPlayedPercRight*pannedPlayHeight);
+	currPlayedX = Math.round(currPlayedXPrecise);
+	currPlayedY = Math.round(currPlayedYPrecise);
+
+
+	if ((currPlayedX != prevPlayedX) || (currPlayedY != prevPlayedY)) {
+
+	    updateLeftAndRightTimes(currPlayedXPrecise,currPlayedYPrecise);
+
+	    var playTracker = document.getElementById("playtracker");
+	    var transform = "translate("+currPlayedX+","+currPlayedY+")";
+	    playTracker.setAttribute("transform",transform);
+    	    
+	    if ((prevPlayedX == -1) && (prevPlayedY == -1)) {
+		// notice the first time this happens
+		playTracker.setAttribute("style","visibility: visible");
+		playTrackerMode = "playing";
+	    }
+
+	    prevPlayedX = currPlayedX;
+	    prevPlayedY = currPlayedY;
+	}
+
+	// console.log("currently playing = " + currentPlayedSecs);
+
+
+	// If all data wasn't written, keep it in the buffers:
+	var doBreak = false;
+
+	if (leftBufferPos + written < leftBuffer.length) {
+	    leftBuffers[0].position = leftBufferPos + written;
+	    doBreak = true;
+	}
+	else {
+	    leftBuffers.shift();
+        }
+
+	if (rightBufferPos + written < rightBuffer.length) {
+	    rightBuffers[0].position = rightBufferPos + written;
+	    doBreak = true;
+	}
+	else {
+	    rightBuffers.shift();
+        }
+
+	if (doBreak) {
+	    break;
+	}
+    }
+
+    var currentPlayedOffset = pannedPlayback.mozCurrentSampleOffset();
+
+    //if (currentPlayedOffset == prevPlayedOffset) {
+	// Nothing more is playing
+
+    var exceededX = ((currPlayedX != null) && (currPlayedX>barWidth));
+    var exceededY = ((currPlayedY != null) && (currPlayedY<0));
+
+    if ((exceededX || exceededY) && (!playTrackerMode.match("stopped"))) {
+
+	// console.log("detected stop condition");
+
+	// readed edge of play area
+	playTrackerMode = "stopped";
+	togglePlayVisual(document.getElementById("mainPlayButton"));
+	playTrackerOff(null);
+	    
+	//prevPlayedOffset = -1;
+    }
+    else {
+	//prevPlayedOffset = currentPlayedOffset;
+    }
+
+}
Index: /gs3-extensions/audioDB/trunk/src/interface/js/similarity-matrix-play.js.checkpt1
===================================================================
--- /gs3-extensions/audioDB/trunk/src/interface/js/similarity-matrix-play.js.checkpt1	(revision 26291)
+++ /gs3-extensions/audioDB/trunk/src/interface/js/similarity-matrix-play.js.checkpt1	(revision 26291)
@@ -0,0 +1,340 @@
+
+// Audio objects
+var baseSong;
+var leftSong;
+var rightSong;
+
+var pannedPlayback = new Audio();
+
+var leftBuffers = [];
+var rightBuffers = [];
+
+var leftStartTimeSecs  = 0.0;
+var rightStartTimeSecs = 0.0;
+var leftStartTimeOffset  = 0;
+var rightStartTimeOffset = 0;
+
+var totalFullBufferSize = 0;
+
+function resetAudioBuffers()
+{
+    console.log("Panned audio playback buffers initialized/reset");
+
+    pannedPlayback = new Audio();
+
+    leftBuffers = [];
+    rightBuffers = [];
+
+    leftStartTimeSecs  = 0.0;
+    rightStartTimeSecs = 0.0;
+    leftStartTimeOffset  = 0;
+    rightStartTimeOffset = 0;
+    
+    totalFullBufferSize = 0;
+}
+
+function dualPlay(evt) 
+{
+    //var target = evt.target;
+    //console.log("target = " + target);
+
+    var img_x = $("#selfSimImgId").offset().left;
+    var img_y = $("#selfSimImgId").offset().top;
+
+    var mouse_x = evt.clientX;
+    var mouse_y = evt.clientY;
+    
+    var x_org = mouse_x - img_x;
+    var y_org = mouse_y - img_y;
+    
+    //console.log("mouse (x y) = (" + mouse_x + "," + mouse_y + ")");
+    //console.log("(x y) = (" + x_org + "," + y_org + ")");
+
+    var mysong = document.getElementById("mysong");
+    var barWidth = mysong.getElementWidth();
+
+    var baseSongSrc="sites/localsite/collect/" + collect +"/import/"+source;
+
+    leftStartTimeSecs  = duration * x_org / barWidth;
+    rightStartTimeSecs = duration * y_org / barWidth;
+
+    var sampleMult = * baseSong.mozSampleRate * baseSong.mozChannels;
+    leftStartTimeOffset  = leftStartTimeSecs * sampleMult;
+    rightStartTimeOffset = rightStartTimeSecs * sampleMult;
+
+    leftSong.src  = baseSongSrc;
+    rightSong.src = baseSongSrc;
+
+    resetAudioBuffer();
+}
+
+function svgInitSimilarityPlay() 
+{
+    var mysong = document.getElementById("mysong");
+    var barWidth = mysong.getElementWidth();
+
+    var baseSongSrc="sites/localsite/collect/" + collect +"/import/"+source;
+
+    baseSong = new Audio();
+    baseSong.src = baseSongSrc;
+    baseSong.control = "control";
+
+    baseSong.addEventListener('MozAudioAvailable', audioAvailable, false);
+    baseSong.addEventListener('loadedmetadata', loadedMetadata, false);
+
+    leftSong = new Audio();
+    leftSong.addEventListener('MozAudioAvailable', audioAvailableLeft, false);
+    leftSong.addEventListener('loadedmetadata', loadedMetadataLeft, false);
+
+    rightSong = new Audio();
+    rightSong.addEventListener('MozAudioAvailable', audioAvailableRight, false);
+    rightSong.addEventListener('loadedmetadata', loadedMetadataRight, false);
+
+
+    // Set up self similarity image
+
+    var selfSimImgSrc="sites/localsite/collect/" + collect +"/bordered/"+self_sim_png;
+    console.log("self sim img = " + selfSimImgSrc);
+
+    var simPlayLine = document.getElementById("simPlayLineGroup");
+
+    var selfSimImg = document.createElementNS(SVG_NS,"image");
+    selfSimImg.setAttributeNS(XLINK_NS, "xlink:href", selfSimImgSrc);
+
+    var selfSimImgHeight = barWidth * (815.0 / 776.0);
+
+    selfSimImg.setAttribute("x",0);
+    selfSimImg.setAttribute("y",30);
+    selfSimImg.setAttribute("id","selfSimImgId");
+    selfSimImg.setAttribute("width",barWidth);
+    selfSimImg.setAttribute("height",selfSimImgHeight);
+    selfSimImg.setAttribute("onclick","dualPlay(evt)");
+
+    simPlayLine.appendChild(selfSimImg);
+    /*
+
+                var searchImgElem = document.createElementNS(SVG_NS,'image');
+		searchImgElem.setAttributeNS(XLINK_NS, "xlink:href", 
+		                           "ext/audioDB/icons/search20.png");
+		searchImgElem.setAttribute("x","544");
+	        searchImgElem.setAttribute("y","42");
+	        searchImgElem.setAttribute("width","20");
+	        searchImgElem.setAttribute("height","20");
+		//var onclickSearch ="searchSubmit(100)";
+		var onclickSearch ="dualPlay(evt)";
+	        searchImgElem.setAttribute("onclick",onclickSearch);
+		simPlayLine.appendChild(searchImgElem);
+    */
+
+
+    var svgSimilarityPlay = document.getElementById("svgSimilarityPlay");
+    svgSimilarityPlay.setAttribute("height",30 + selfSimImgHeight);
+
+
+}
+
+
+
+
+function loadedMetadata() {
+    // Mute baseSong audio.
+    baseSong.volume = 0;
+
+    // Set up a pannedPlayback for baseSong to routed through
+    console.log("num channels = " + baseSong.mozChannels);
+
+    pannedPlayback.mozSetup(2, baseSong.mozSampleRate);
+
+}
+
+
+function loadedMetadataLeft() {
+    // Mute baseSong audio.
+    leftSong.volume = 0;
+
+    leftSong.currentTime = leftStartTimeSecs;
+    leftSong.play();
+}
+
+
+function loadedMetadataRigh() {
+    // Mute baseSong audio.
+    rightSong.volume = 0;
+
+    rightSong.currentTime = rightStartTimeSecs;
+    rightSong.play();
+}
+
+function audioAvailable(event) {
+    // Write the current framebuffer
+    alert("audioAvailable() should no longer be called");
+    var frameBuffer = event.frameBuffer; // frameBuffer is Float32Array
+    //writeAudio(frameBuffer);
+}
+
+function audioAvailableLeft(event) 
+{
+    // Write the current framebuffer
+    var frameBuffer = event.frameBuffer; 
+    writeAudio(frameBuffer,"left");
+}
+
+function audioAvailableRight(event) 
+{
+    // Write the current framebuffer
+    var frameBuffer = event.frameBuffer; 
+    writeAudio(frameBuffer,"right");
+}
+
+
+
+
+function activeAudioBuffer(audioBuffer,currentFullBufferSize,startTime) 
+{
+    var buffer;
+    if (currentFullBufferSize < startTime) {
+	// active audio starts at offset within this segment of audioBuffer
+
+	var position = startTime - currentFullBufferSize;
+	buffer = audioBuffer.subarray(position);
+    }
+    else {
+	buffer = audioBuffer;
+    }
+    return buffer;
+}
+
+function panLeftEffect(buffer,s,panned_buffer,d) 
+{
+    panned_buffer[d] = buffer[s];
+    if ((d+1) < panned_buffer.length) {
+	panned_buffer[d+1] = 0;
+    }
+}
+
+function panRightEffect(buffer,s,panned_buffer,d) 
+{
+    panned_buffer[d] = 0;
+    if ((d+1) < panned_buffer.length) {
+	panned_buffer[d+1] = buffer[s];
+    }
+}
+
+function panAudioBuffersHead(buffer,position,panEffect)
+{
+    var remaining_len = buffer.length - position;
+    var panned_buffer;
+    if (baseSong.mozChannels == 1) {
+	panned_buffer = new Float32Array(remaining_len * 2);
+
+	var d=0;
+	for (var s=position; s < buffer.length; s++) {
+	    panEffect(buffer,s,panned_buffer,d);
+	    d += 2;
+	}
+    }
+    else {
+	// assume stereo
+	panned_buffer = new Float32Array(remaining_len);
+      
+	var d=0;
+	for (var s=position; s < buffer.length; s+=2) {
+	    panEffect(buffer,s,panned_buffer,d);
+	    d += 2;
+	}
+    }
+
+    return panned_buffer;
+}
+
+function mergeLeftAndRightPan(leftPannedBuffer,rightPannedBuffer)
+{
+    // left and right buffers guaranteed to be stereo samples
+
+    var leftLen  = leftPannedBuffer.length;
+    var rightLen = rightPannedBuffer.length;
+    var maxLen = Math.max(leftLen,rightLen);
+
+    var pannedBuffer = new Float32Array(maxLen);
+
+    for (i=0; i < maxLen; i+=2) {
+
+        if (i < leftLen) {
+	    pannedBuffer[i] = leftPannedBuffer[i];
+	}
+	else {
+	    pannedBuffer[i] = 0;
+	}
+
+        if (i < leftLen) {
+	    pannedBuffer[i+1] = rightPannedBuffer[i+1];
+	}
+	else {
+	    pannedBuffer[i+1] = 0;
+	}
+    }
+
+    return pannedBuffer;
+
+}
+
+function writeAudio(audioBuffer,channel) {
+
+    // audioBuffer is Float32Array
+    var audioBufferLen = audioBuffer.length; 
+
+    if ((totalFullBufferSize + audioBufferLen) > leftStartTimeOffset) {
+        var leftBuffer = activeAudioBuffer(audioBuffer,totalFullBufferSize,leftStartTime);
+	leftBuffers.push({buffer: leftBuffer, position: 0});
+    }
+
+    if ((totalFullBufferSize + audioBufferLen) > rightStartTimeOffset) {
+        var rightBuffer = activeAudioBuffer(audioBuffer,totalFullBufferSize,rightStartTime);
+	rightBuffers.push({buffer: rightBuffer, position: 0});
+    }
+
+    totalFullBufferSize += audioBufferLen;
+
+
+    // If there's buffered data in both left and right buffers,
+    // then it's time to play something 
+
+    while((leftBuffers.length > 0) && (rightBuffers.length > 0)) {
+
+        var leftBuffer = leftBuffers[0].buffer;
+	var leftBufferPos = leftBuffers[0].position;
+        var leftPannedBuffer  = panAudioBuffersHead(leftBuffer,leftBufferPos,panLeftEffect);
+
+        var rightBuffer = rightBuffers[0].buffer;
+	var rightBufferPos = rightBuffers[0].position;
+        var rightPannedBuffer = panAudioBuffersHead(rightBuffer,rightBufferPos,panRightEffect);
+
+        var pannedBuffer = mergeLeftAndRightPan(leftPannedBuffer,rightPannedBuffer);
+
+	//var written = pannedPlayback.mozWriteAudio(buffer.subarray(position));
+	var written = pannedPlayback.mozWriteAudio(pannedBuffer);
+
+	// // If all data wasn't written, keep it in the buffers:
+	var doBreak = false;
+
+	if (leftBufferPos + written < leftBuffer.length) {
+	    leftBuffers[0].position = leftBufferPos + written;
+	    doBreak = true;
+	}
+	else {
+	    leftBuffers.shift();
+        }
+
+	if (rightBufferPos + written < rightBuffer.length) {
+	    rightBuffers[0].position = rightBufferPos + written;
+	    doBreak = true;
+	}
+	else {
+	    rightBuffers.shift();
+        }
+
+	if (doBreak) {
+	    break;
+	}
+    }
+}
Index: /gs3-extensions/audioDB/trunk/src/interface/js/structured-audio-play.js
===================================================================
--- /gs3-extensions/audioDB/trunk/src/interface/js/structured-audio-play.js	(revision 26291)
+++ /gs3-extensions/audioDB/trunk/src/interface/js/structured-audio-play.js	(revision 26291)
@@ -0,0 +1,276 @@
+
+var SVG_NS ="http://www.w3.org/2000/svg";
+var XLINK_NS = "http://www.w3.org/1999/xlink";
+
+var togglePlayMode = "play";
+
+function distinctColorHSL(sn,numSegs) {
+
+    var Hangle = 360 * sn / numSegs;
+    var Sperc  = 10 + 90 * sn / numSegs;
+    var Vperc  = 40 + 60 * sn / numSegs;
+
+    return 'hsl(' + Hangle + ', ' + Sperc + '%, ' + Vperc + '%)';
+
+}
+
+
+function togglePlayVisual(elem)
+{
+    if (togglePlayMode.match("play")) {
+	// switch to displaying pause
+	elem.src="ext/audioDB/icons/pause32.png";
+	togglePlayMode = "pause";
+    }
+    else {
+	elem.src="ext/audioDB/icons/play32.png";
+	togglePlayMode = "play";
+    }
+}
+
+function togglePlay(event,elem)
+{
+    togglePlayVisual(elem);
+
+    if (event != null) {
+	event.stopPropagation();
+	event.preventDefault();
+    }
+
+    // switching to offering pause (means it was a play button when clicked)
+    if (togglePlayMode.match("pause")) {
+	if (playTrackerMode.match("paused")) {
+	    rightSong.play();
+	    leftSong.play();
+	    pannedPlayback.play();
+	    playTrackerMode = "playing";
+	}
+	else {
+	    var currentPosElem = document.getElementById("mysongCurrentPos");
+	    var offsetInMSecs = currentPosElem.getAttribute("offsetInMSecs");
+	    // console.log("offsetInMSecs = " + offsetInMSecs);
+
+	    if (offsetInMSecs==null) { offsetInMSecs = 0; }
+	    var frameOffset = Math.round(offsetInMSecs/250.0);
+	    playFromOffset("mysong",frameOffset);
+	}
+    }
+    else {
+	// figure out if mysong or dualPlay in operatio, and pause it
+
+	if (playTrackerMode.match("playing")) {
+	    pannedPlayback.pause();
+	    leftSong.pause();
+	    rightSong.pause();
+
+	    playTrackerMode = "paused";
+	}
+	else {
+	    soundManager.pause("mysong");
+	}
+    }
+}
+
+
+
+function playHighlightOn(elem,size)
+{
+    size = (size) ? size : 32;
+ 
+    if (togglePlayMode.match("play")) {
+	elem.setAttribute("src","ext/audioDB/icons/play"+size+"Highlight.png");
+    }
+    else {
+	elem.setAttribute("src","ext/audioDB/icons/pause"+size+"Highlight.png");
+    }
+}
+
+function playHighlightOff(elem,size)
+{
+    size = (size) ? size : 32;
+
+    if (togglePlayMode.match("play")) {
+	elem.setAttribute("src","ext/audioDB/icons/play"+size+".png");
+    }
+    else {
+	elem.setAttribute("src","ext/audioDB/icons/pause"+size+".png");
+    }
+}
+
+function playHighlightOnSVG(elem,size)
+{
+    size = (size) ? size : 32;
+ 
+    elem.setAttributeNS(XLINK_NS,"xlink:href","ext/audioDB/icons/play"+size+"Highlight.png");
+}
+
+function playHighlightOffSVG(elem,size)
+{
+    size = (size) ? size : 32;
+
+    elem.setAttributeNS(XLINK_NS,"xlink:href","ext/audioDB/icons/play"+size+".png");
+
+}
+
+
+function searchHighlightOnSVG(elem,size)
+{
+    size = (size) ? size : 32;
+ 
+    elem.setAttributeNS(XLINK_NS,"xlink:href","ext/audioDB/icons/search"+size+"Highlight.png");
+}
+
+function searchHighlightOffSVG(elem,size)
+{
+    size = (size) ? size : 32;
+
+    elem.setAttributeNS(XLINK_NS,"xlink:href","ext/audioDB/icons/search"+size+".png");
+
+}
+
+
+function raiseSPRect(elem)
+{
+    elem.setAttribute("style","z-index: 5;");
+}
+
+
+function lowerSPRect(elem)
+{
+    elem.setAttribute("style","");
+}
+
+function renderStructuredSegBar(segsElem, segData) 
+{
+    var mysong   = document.getElementById("mysong");
+    var barWidth = mysong.getElementWidth();
+
+    // Count how many different labels we have 
+
+    var segFreq = {};
+    var numLabels = 0;
+
+    for(var i=0; i< segData.length; i++) {
+        var value = segData[i].l;
+        if(value in segFreq) {
+            segFreq[value]++;
+        }
+        else {
+            segFreq[value] = 1;
+	    numLabels++;
+        }
+    }
+
+    var numSegs = segData.length;
+
+    for (i=0; i < numSegs; i++) {
+
+	var offsetInSecs = segData[i].o;
+	var frameOffset = Math.round(offsetInSecs*1000/250.0);
+
+	var label = segData[i].l;
+	var labelOrd = label.charCodeAt(0);
+	var letterBaseOrd = "A".charCodeAt(0);
+	var numberBaseOrd = "0".charCodeAt(0);
+
+	var baseOrd;
+	if ((labelOrd >= numberBaseOrd) && (labelOrd <= "9".charCodeAt(0))) {
+	    baseOrd = numberBaseOrd;
+	}
+	else {
+	    baseOrd = letterBaseOrd;
+	}
+
+	var labelIndex = label.charCodeAt(0) - baseOrd;
+	var labelColor = distinctColorHSL(labelIndex,numLabels);
+
+	var x = barWidth * offsetInSecs / duration;
+	var y = 0;
+
+	var nextOffsetInSecs 
+	    = (i < numSegs-1) ? segData[i+1].o : duration;
+	var nextX = barWidth * nextOffsetInSecs / duration;
+
+	var gElem = document.createElementNS(SVG_NS,'g');
+	gElem.setAttribute('transform','translate('+x+','+y+')');
+	gElem.setAttribute("onmouseover","raiseSPRect(evt.target)");
+	gElem.setAttribute("onmouseout","lowerSPRect(evt.target)");
+
+	var rectElem = document.createElementNS(SVG_NS,'rect');
+	rectElem.setAttribute('width',nextX - x - 1);
+	rectElem.setAttribute('height','24');
+	rectElem.setAttribute('x','0');
+	rectElem.setAttribute('y','0');
+	/* rectElem.setAttribute('stroke-width', '5'); */
+	rectElem.setAttribute('fill', labelColor);
+
+
+	var textElem = document.createElementNS(SVG_NS,'text');
+	textElem.setAttribute('x','5');
+	textElem.setAttribute('y','18');
+
+	var textNode = document.createTextNode(label);
+	textElem.appendChild(textNode);
+
+	var playImgElem = document.createElementNS(SVG_NS,"image");
+	playImgElem.setAttributeNS(XLINK_NS, "xlink:href", 
+				   "ext/audioDB/icons/play20.png");
+	playImgElem.setAttribute("x","20");
+	playImgElem.setAttribute("y","2");
+	playImgElem.setAttribute("width","20");
+	playImgElem.setAttribute("height","20");
+
+	var onclick ="playFromOffset('mysong'," + frameOffset + ")";
+	playImgElem.setAttribute("onclick",onclick);
+
+	playImgElem.setAttribute("onmouseover","playHighlightOnSVG(evt.target,20)");
+	playImgElem.setAttribute("onmouseout", "playHighlightOffSVG(evt.target,20)");
+
+
+	var searchImgElem = document.createElementNS(SVG_NS,'image');
+	searchImgElem.setAttributeNS(XLINK_NS, "xlink:href", 
+				     "ext/audioDB/icons/search20.png");
+	searchImgElem.setAttribute("x","44");
+	searchImgElem.setAttribute("y","2");
+	searchImgElem.setAttribute("width","20");
+	searchImgElem.setAttribute("height","20");
+	var onclickSearch ="searchSubmit("+frameOffset+")";
+	searchImgElem.setAttribute("onclick",onclickSearch);
+
+	searchImgElem.setAttribute("onmouseover","searchHighlightOnSVG(evt.target,20)");
+	searchImgElem.setAttribute("onmouseout", "searchHighlightOffSVG(evt.target,20)");
+
+	gElem.appendChild(rectElem);
+	gElem.appendChild(textElem);
+	gElem.appendChild(playImgElem);
+	gElem.appendChild(searchImgElem);
+	segsElem.appendChild(gElem);
+
+    }
+}
+
+
+function svgGTStructuredInit() 
+{
+    var segDataGT = allData[0]; /* pick out ground truth data */    
+    var segsElemGT = document.getElementById("svgGroundTruthSegments");
+
+    renderStructuredSegBar(segsElemGT,segDataGT);
+}
+
+function svgCAStructuredInit(caPos) 
+{
+    var segsElemCA = document.getElementById("svgContentAnalysisSegments");
+
+    
+    if (caPos == -1) {
+	ssegsElemCA.setAttribute("style","display: none;");
+    }
+    else {
+	var segDataCA = allData[caPos]; /* pick out example content analysis data */ 
+
+	renderStructuredSegBar(segsElemCA,segDataCA);
+	//ssegsElemCA.setAttribute("style","display: block;");
+
+    }
+}
Index: /gs3-extensions/audioDB/trunk/src/interface/script/optional-page-player-metadata.js
===================================================================
--- /gs3-extensions/audioDB/trunk/src/interface/script/optional-page-player-metadata.js	(revision 26291)
+++ /gs3-extensions/audioDB/trunk/src/interface/script/optional-page-player-metadata.js	(revision 26291)
@@ -0,0 +1,142 @@
+// SoundManager 2: Page Player demo, MetaData UI prototype
+
+/*jslint white: false, onevar: true, undef: true, nomen: false, eqeqeq: true, plusplus: false, bitwise: true, newcap: true, immed: true */
+/*global pagePlayer, document, window */
+
+var Metadata = function(oSound) {
+
+  var self = this,
+      pl = pagePlayer,
+      oLI = oSound._data.oLI,
+      o = oLI.getElementsByTagName('ul')[0],
+      oItems = o.getElementsByTagName('li'),
+      oTemplate = document.createElement('div'),
+      oTemplate2 = document.createElement('div'),
+      oTemplate3 = document.createElement('div'),
+      oDuration, i;
+
+  oTemplate.innerHTML = '<span>&nbsp;</span>';
+  oTemplate.className = 'annotation';
+  oTemplate2.innerHTML = '<span>&nbsp;</span>';
+  oTemplate2.className = 'annotation alt';
+  oTemplate3.className = 'note';
+
+  this.totalTime = 0;
+  this.data = [];
+  this.data.givenDuration = null;
+  this.data.currentItem = null;
+  this.data.mainTitle = oSound._data.oLink.innerHTML;
+
+  this.strToTime = function(sTime) {
+    var segments = sTime.split(':'),
+        seconds = 0, i;
+    for (i=segments.length; i--;) {
+      seconds += parseInt(segments[i],10)*Math.pow(60,segments.length-1-i); // hours, minutes
+    }
+    return seconds;
+  };
+
+  // make stuff
+  this.createElements = function() {
+    var oFrag = document.createDocumentFragment(),
+        oNode = null,
+        oNodeSpan = null,
+        oNode2 = null, i;
+    for (i=0; i<self.data.length; i++) {
+      oNode = (i%2===0?oTemplate:oTemplate2).cloneNode(true);
+      oNodeSpan = oNode.getElementsByTagName('span')[0];
+      oNode.rel = i;
+      self.data[i].o = oNode;
+      oNode2 = oTemplate3.cloneNode(true);
+      if (i%2===0) {
+        oNode2.className = 'note alt';
+      }
+      oNode2.innerHTML = this.data[i].title;
+      // evil old-skool event handlers, css:hover-only ideally would be nice excluding IE 6
+      oNode.onmouseover = self.mouseover;
+      oNode.onmouseout = self.mouseout;
+      this.data[i].oNote = oNode2;
+      oSound._data.oControls.appendChild(oNode2);
+      oFrag.appendChild(oNode);
+    }
+    self.refresh();
+    oSound._data.oStatus.appendChild(oFrag);
+  };
+
+  this.refreshMetadata = function(oSound) {
+    // Display info as appropriate
+    var i, j, index = null,
+        now = oSound.position,
+        metadata = oSound._data.metadata.data;
+    for (i=0, j=metadata.length; i<j; i++) {
+      if (now >= metadata[i].startTimeMS && now <= metadata[i].endTimeMS) {
+        index = i;
+        break;
+      }
+    }
+    if (index !== metadata.currentItem) {
+      // update
+      oSound._data.oLink.innerHTML = metadata.mainTitle+' <span class="metadata"><span class="sm2_divider"> | </span><span class="sm2_metadata">'+metadata[index].title+'</span></span>';
+      pl.setPageTitle(metadata[index].title+' | '+metadata.mainTitle);
+      metadata.currentItem = index;
+    }
+  };
+
+  this.refresh = function() {
+    var offset = 0,
+        relWidth = null,
+        duration = (self.data.givenDuration?self.data.givenDuration:oSound.durationEstimate), i;
+    for (i=0; i<self.data.length; i++) {
+      if (duration) {
+        relWidth = (((self.data[i].duration*1000)/duration)*100);
+        self.data[i].o.style.left = (offset?offset+'%':'-2px');
+        self.data[i].oNote.style.left = (offset?offset+'%':'0px');
+        offset += relWidth;
+      }
+    }
+  };
+
+  this.mouseover = function(e) {
+    self.data[this.rel].oNote.style.visibility = 'hidden';
+    self.data[this.rel].oNote.style.display = 'inline-block';
+    self.data[this.rel].oNote.style.marginLeft = -parseInt(self.data[this.rel].oNote.offsetWidth/2,10)+'px';
+    self.data[this.rel].oNote.style.visibility = 'visible';
+  };
+
+  this.mouseout = function() { 
+    self.data[this.rel].oNote.style.display = 'none';
+  };
+
+  // ----
+
+  for (i=0; i<oItems.length; i++) {
+    this.data[i] = {
+      o: null,
+      title: oItems[i].getElementsByTagName('p')[0].innerHTML,
+      startTime: oItems[i].getElementsByTagName('span')[0].innerHTML,
+      startSeconds: self.strToTime(oItems[i].getElementsByTagName('span')[0].innerHTML.replace(/[()]/g,'')),
+      duration: 0,
+      durationMS: null,
+      startTimeMS: null,
+      endTimeMS: null,
+      oNote: null
+    };
+  }
+
+  oDuration = pl.getByClassName('duration','div',oLI);
+  this.data.givenDuration = (oDuration.length?self.strToTime(oDuration[0].innerHTML)*1000:0);
+
+  for (i=0; i<this.data.length; i++) {
+    this.data[i].duration = parseInt(this.data[i+1]?this.data[i+1].startSeconds:(self.data.givenDuration?self.data.givenDuration:oSound.durationEstimate)/1000,10)-this.data[i].startSeconds;
+    this.data[i].startTimeMS = this.data[i].startSeconds*1000;
+    this.data[i].durationMS = this.data[i].duration*1000;
+    this.data[i].endTimeMS = this.data[i].startTimeMS+this.data[i].durationMS;
+    this.totalTime += this.data[i].duration;
+  }
+
+  // ----
+
+  this.createElements();
+  this.refresh();
+  
+}; // MetaData();
Index: /gs3-extensions/audioDB/trunk/src/interface/script/page-player.js
===================================================================
--- /gs3-extensions/audioDB/trunk/src/interface/script/page-player.js	(revision 26291)
+++ /gs3-extensions/audioDB/trunk/src/interface/script/page-player.js	(revision 26291)
@@ -0,0 +1,1089 @@
+/*
+
+  SoundManager 2 Demo: "Page as playlist" UI
+  ----------------------------------------------
+  http://schillmania.com/projects/soundmanager2/
+
+  An example of a Muxtape.com-style UI, where an
+  unordered list of MP3 links becomes a playlist
+
+  Flash 9 "MovieStar" edition supports MPEG4
+  audio as well.
+
+  Requires SoundManager 2 Javascript API.
+
+*/
+
+/*jslint white: false, onevar: true, undef: true, nomen: false, eqeqeq: true, plusplus: false, bitwise: true, newcap: true, immed: true */
+/*global soundManager, window, document, navigator, setTimeout, attachEvent, Metadata, PP_CONFIG */
+
+var pagePlayer = null;
+
+function PagePlayer() {
+
+  var self = this,
+      pl = this,
+      sm = soundManager, // soundManager instance
+      _event,
+      vuDataCanvas = null,
+      controlTemplate = null,
+      _head = document.getElementsByTagName('head')[0],
+      spectrumContainer = null,
+      // sniffing for favicon stuff, IE workarounds and touchy-feely devices
+      ua = navigator.userAgent,
+      supportsFavicon = (ua.match(/(opera|firefox)/i)),
+      isTouchDevice = (ua.match(/ipad|ipod|iphone/i)),
+      cleanup;
+
+  // configuration options
+  // note that if Flash 9 is required, you must set soundManager.flashVersion = 9 in your script before this point.
+
+  this.config = {
+    usePeakData: false,     // [Flash 9 only]: show peak data
+    useWaveformData: false, // [Flash 9 only]: enable sound spectrum (raw waveform data) - WARNING: CPU-INTENSIVE: may set CPUs on fire.
+    useEQData: false,       // [Flash 9 only]: enable sound EQ (frequency spectrum data) - WARNING: Also CPU-intensive.
+    fillGraph: false,       // [Flash 9 only]: draw full lines instead of only top (peak) spectrum points
+    useMovieStar: true,     // [Flash 9 only]: Support for MPEG4 audio formats
+    allowRightClick: true,  // let users right-click MP3 links ("save as...", etc.) or discourage (can't prevent.)
+    useThrottling: true,    // try to rate-limit potentially-expensive calls (eg. dragging position around)
+    autoStart: false,       // begin playing first sound when page loads
+    playNext: true,         // stop after one sound, or play through list until end
+    updatePageTitle: true,  // change the page title while playing sounds
+    emptyTime: '-:--',      // null/undefined timer values (before data is available)
+    useFavIcon: false       // try to show peakData in address bar (Firefox + Opera) - may be too CPU heavy
+  };
+
+  this.css = {              // CSS class names appended to link during various states
+    sDefault: 'sm2_link',   // default state
+    sLoading: 'sm2_loading',
+    sPlaying: 'sm2_playing',
+    sPaused: 'sm2_paused'
+  };
+
+  this.sounds = [];
+  this.soundsByObject = [];
+  this.lastSound = null;
+  this.soundCount = 0;
+  this.strings = [];
+  this.dragActive = false;
+  this.dragExec = new Date();
+  this.dragTimer = null;
+  this.pageTitle = document.title;
+  this.lastWPExec = new Date();
+  this.lastWLExec = new Date();
+  this.vuMeterData = [];
+  this.oControls = null;
+
+  this._mergeObjects = function(oMain,oAdd) {
+    // non-destructive merge
+    var o1 = {}, o2, i, o; // clone o1
+    for (i in oMain) {
+      if (oMain.hasOwnProperty(i)) {
+        o1[i] = oMain[i];
+      }
+    }
+    o2 = (typeof oAdd === 'undefined'?{}:oAdd);
+    for (o in o2) {
+      if (typeof o1[o] === 'undefined') {
+        o1[o] = o2[o];
+      }
+    }
+    return o1;
+  };
+
+  _event = (function() {
+
+    var old = (window.attachEvent && !window.addEventListener),
+    _slice = Array.prototype.slice,
+    evt = {
+      add: (old?'attachEvent':'addEventListener'),
+      remove: (old?'detachEvent':'removeEventListener')
+    };
+
+    function getArgs(oArgs) {
+      var args = _slice.call(oArgs), len = args.length;
+      if (old) {
+        args[1] = 'on' + args[1]; // prefix
+        if (len > 3) {
+          args.pop(); // no capture
+        }
+      } else if (len === 3) {
+        args.push(false);
+      }
+      return args;
+    }
+
+    function apply(args, sType) {
+      var element = args.shift(),
+          method = [evt[sType]];
+      if (old) {
+        element[method](args[0], args[1]);
+      } else {
+        element[method].apply(element, args);
+      }
+    }
+
+    function add() {
+      apply(getArgs(arguments), 'add');
+    }
+
+    function remove() {
+      apply(getArgs(arguments), 'remove');
+    }
+
+    return {
+      'add': add,
+      'remove': remove
+    };
+
+  }());
+
+  this.hasClass = function(o, cStr) {
+    return (typeof(o.className)!=='undefined'?new RegExp('(^|\\s)'+cStr+'(\\s|$)').test(o.className):false);
+  };
+
+  this.addClass = function(o, cStr) {
+    if (!o || !cStr || self.hasClass(o,cStr)) {
+      return false; // safety net
+    }
+    o.className = (o.className?o.className+' ':'')+cStr;
+  };
+
+  this.removeClass = function(o, cStr) {
+    if (!o || !cStr || !self.hasClass(o,cStr)) {
+      return false;
+    }
+    o.className = o.className.replace(new RegExp('( '+cStr+')|('+cStr+')','g'),'');
+  };
+
+  this.select = function(className, oParent) {
+    var result = self.getByClassName(className, 'div', oParent||null);
+    return (result ? result[0] : null);
+  };
+
+  this.getByClassName = (document.querySelectorAll ? function(className, tagNames, oParent) { // tagNames: string or ['div', 'p'] etc.
+
+    var pattern = ('.'+className), qs;
+    if (tagNames) {
+      tagNames = tagNames.split(' ');
+    }
+    qs = (tagNames.length > 1 ? tagNames.join(pattern+', ') : tagNames[0]+pattern);
+    return (oParent?oParent:document).querySelectorAll(qs);
+
+  } : function(className, tagNames, oParent) {
+
+    var node = (oParent?oParent:document), matches = [], i, j, nodes = [];
+    if (tagNames) {
+      tagNames = tagNames.split(' ');
+    }
+    if (tagNames instanceof Array) {
+      for (i=tagNames.length; i--;) {
+        if (!nodes || !nodes[tagNames[i]]) {
+          nodes[tagNames[i]] = node.getElementsByTagName(tagNames[i]);
+        }
+      }
+      for (i=tagNames.length; i--;) {
+        for (j=nodes[tagNames[i]].length; j--;) {
+          if (self.hasClass(nodes[tagNames[i]][j], className)) {
+            matches.push(nodes[tagNames[i]][j]);
+          }
+        }
+      }
+    } else {
+      nodes = node.all||node.getElementsByTagName('*');
+      for (i=0, j=nodes.length; i<j; i++) {
+        if (self.hasClass(nodes[i],className)) {
+          matches.push(nodes[i]);
+        }
+      }
+    }
+    return matches;
+
+  });
+  
+  this.isChildOfClass = function(oChild, oClass) {
+    if (!oChild || !oClass) {
+      return false;
+    }
+    while (oChild.parentNode && !self.hasClass(oChild,oClass)) {
+      oChild = oChild.parentNode;
+    }
+    return (self.hasClass(oChild,oClass));
+  };
+
+  this.getParentByNodeName = function(oChild, sParentNodeName) {
+    if (!oChild || !sParentNodeName) {
+      return false;
+    }
+    sParentNodeName = sParentNodeName.toLowerCase();
+    while (oChild.parentNode && sParentNodeName !== oChild.parentNode.nodeName.toLowerCase()) {
+      oChild = oChild.parentNode;
+    }
+    return (oChild.parentNode && sParentNodeName === oChild.parentNode.nodeName.toLowerCase()?oChild.parentNode:null);
+  };
+
+  this.getOffX = function(o) {
+    // http://www.xs4all.nl/~ppk/js/findpos.html
+    var curleft = 0;
+    if (o.offsetParent) {
+      while (o.offsetParent) {
+        curleft += o.offsetLeft;
+        o = o.offsetParent;
+      }
+    }
+    else if (o.x) {
+      curleft += o.x;
+    }
+    return curleft;
+  };
+
+  this.getTime = function(nMSec, bAsString) {
+    // convert milliseconds to mm:ss, return as object literal or string
+    var nSec = Math.floor(nMSec/1000),
+        min = Math.floor(nSec/60),
+        sec = nSec-(min*60);
+    // if (min === 0 && sec === 0) return null; // return 0:00 as null
+    return (bAsString?(min+':'+(sec<10?'0'+sec:sec)):{'min':min,'sec':sec});
+  };
+
+  this.getSoundByObject = function(o) {
+    return (typeof self.soundsByObject[o.id] !== 'undefined'?self.soundsByObject[o.id]:null);
+  };
+
+  this.getPreviousItem = function(o) {
+    // given <li> playlist item, find previous <li> and then <a>
+    if (o.previousElementSibling) {
+      o = o.previousElementSibling;
+    } else {
+      o = o.previousSibling; // move from original node..
+      while (o && o.previousSibling && o.previousSibling.nodeType !== 1) {
+        o = o.previousSibling;
+      }
+    }
+    if (o.nodeName.toLowerCase() !== 'li') {
+      return null;
+    } else {
+      return o.getElementsByTagName('a')[0];
+    }
+  };
+
+  this.playPrevious = function(oSound) {
+    if (!oSound) {
+      oSound = self.lastSound;
+    }
+    if (!oSound) {
+      return false;
+    }
+    var previousItem = self.getPreviousItem(oSound._data.oLI);
+    if (previousItem) {
+      pl.handleClick({target:previousItem}); // fake a click event - aren't we sneaky. ;)
+    }
+    return previousItem;
+  };
+
+  this.getNextItem = function(o) {
+    // given <li> playlist item, find next <li> and then <a>
+    if (o.nextElementSibling) {
+      o = o.nextElementSibling;
+    } else {
+      o = o.nextSibling; // move from original node..
+      while (o && o.nextSibling && o.nextSibling.nodeType !== 1) {
+        o = o.nextSibling;
+      }
+    }
+    if (o.nodeName.toLowerCase() !== 'li') {
+      return null;
+    } else {
+      return o.getElementsByTagName('a')[0];
+    }
+  };
+
+  this.playNext = function(oSound) {
+    if (!oSound) {
+      oSound = self.lastSound;
+    }
+    if (!oSound) {
+      return false;
+    }
+    var nextItem = self.getNextItem(oSound._data.oLI);
+    if (nextItem) {
+      pl.handleClick({target:nextItem}); // fake a click event - aren't we sneaky. ;)
+    }
+    return nextItem;
+  };
+
+  this.setPageTitle = function(sTitle) {
+    if (!self.config.updatePageTitle) {
+      return false;
+    }
+    try {
+      document.title = (sTitle?sTitle+' - ':'')+self.pageTitle;
+    } catch(e) {
+      // oh well
+      self.setPageTitle = function() {
+        return false;
+      };
+    }
+  };
+
+  this.events = {
+
+    // handlers for sound events as they're started/stopped/played
+
+    play: function() {
+      pl.removeClass(this._data.oLI,this._data.className);
+      this._data.className = pl.css.sPlaying;
+      pl.addClass(this._data.oLI,this._data.className);
+      self.setPageTitle(this._data.originalTitle);
+    },
+
+    stop: function() {
+      pl.removeClass(this._data.oLI,this._data.className);
+      this._data.className = '';
+      this._data.oPosition.style.width = '0px';
+      self.setPageTitle();
+      self.resetPageIcon();
+    },
+
+    pause: function() {
+      if (pl.dragActive) {
+        return false;
+      }
+      pl.removeClass(this._data.oLI,this._data.className);
+      this._data.className = pl.css.sPaused;
+      pl.addClass(this._data.oLI,this._data.className);
+      self.setPageTitle();
+      self.resetPageIcon();
+    },
+
+    resume: function() {
+      if (pl.dragActive) {
+        return false;
+      }
+      pl.removeClass(this._data.oLI,this._data.className);
+      this._data.className = pl.css.sPlaying;
+      pl.addClass(this._data.oLI,this._data.className);
+    },
+
+    finish: function() {
+      pl.removeClass(this._data.oLI,this._data.className);
+      this._data.className = '';
+      this._data.oPosition.style.width = '0px';
+      // play next if applicable
+      if (self.config.playNext) {
+        pl.playNext(this);
+      } else {
+        self.setPageTitle();
+        self.resetPageIcon();
+
+	// Greenstone tweak // ****
+	var mainPlayButton = document.getElementById("mainPlayButton");
+	togglePlayVisual(mainPlayButton); 
+	var currentPosElem = document.getElementById("mysongCurrentPos");
+	var offsetInMSecs = currentPosElem.setAttribute("offsetInMSecs",0);
+      }
+    },
+
+    whileloading: function() {
+      function doWork() {
+        this._data.oLoading.style.width = (((this.bytesLoaded/this.bytesTotal)*100)+'%'); // theoretically, this should work.
+        if (!this._data.didRefresh && this._data.metadata) {
+          this._data.didRefresh = true;
+          this._data.metadata.refresh();
+        }
+      }
+      if (!pl.config.useThrottling) {
+        doWork.apply(this);
+      } else {
+        var d = new Date();
+        if (d && d-self.lastWLExec>30 || this.bytesLoaded === this.bytesTotal) {
+          doWork.apply(this);
+          self.lastWLExec = d;
+        }
+      }
+
+    },
+
+    onload: function() {
+      if (!this.loaded) {
+        var oTemp = this._data.oLI.getElementsByTagName('a')[0],
+            oString = oTemp.innerHTML,
+            oThis = this;
+        oTemp.innerHTML = oString+' <span style="font-size:0.5em"> | Load failed, d\'oh! '+(sm.sandbox.noRemote?' Possible cause: Flash sandbox is denying remote URL access.':(sm.sandbox.noLocal?'Flash denying local filesystem access':'404?'))+'</span>';
+        setTimeout(function(){
+          oTemp.innerHTML = oString;
+          // pl.events.finish.apply(oThis); // load next
+        },5000);
+      } else {
+        if (this._data.metadata) {
+          this._data.metadata.refresh();
+        }
+      }
+    },
+
+    whileplaying: function() {
+      var d = null;
+      if (pl.dragActive || !pl.config.useThrottling) {
+        self.updateTime.apply(this);
+        if (sm.flashVersion >= 9) {
+          if (pl.config.usePeakData && this.instanceOptions.usePeakData) {
+            self.updatePeaks.apply(this);
+          }
+          if (pl.config.useWaveformData && this.instanceOptions.useWaveformData || pl.config.useEQData && this.instanceOptions.useEQData) {
+            self.updateGraph.apply(this);
+          }
+        }
+        if (this._data.metadata) {
+          d = new Date();
+          if (d && d-self.lastWPExec>500) {
+            this._data.metadata.refreshMetadata(this);
+            self.lastWPExec = d;
+          }
+        }
+        this._data.oPosition.style.width = (((this.position/self.getDurationEstimate(this))*100)+'%');
+      } else {
+        d = new Date();
+        if (d-self.lastWPExec>30) {
+          self.updateTime.apply(this);
+          if (sm.flashVersion >= 9) {
+            if (pl.config.usePeakData && this.instanceOptions.usePeakData) {
+              self.updatePeaks.apply(this);
+            }
+            if (pl.config.useWaveformData && this.instanceOptions.useWaveformData || pl.config.useEQData && this.instanceOptions.useEQData) {
+              self.updateGraph.apply(this);
+            }
+          }
+          if (this._data.metadata) {
+            this._data.metadata.refreshMetadata(this);
+          }
+          this._data.oPosition.style.width = (((this.position/self.getDurationEstimate(this))*100)+'%');
+          self.lastWPExec = d;
+        }
+      }
+    }
+
+  }; // events{}
+
+  this.setPageIcon = function(sDataURL) {
+    if (!self.config.useFavIcon || !self.config.usePeakData || !sDataURL) {
+      return false;
+    }
+    var link = document.getElementById('sm2-favicon');
+    if (link) {
+      _head.removeChild(link);
+      link = null;
+    }
+    if (!link) {
+      link = document.createElement('link');
+      link.id = 'sm2-favicon';
+      link.rel = 'shortcut icon';
+      link.type = 'image/png';
+      link.href = sDataURL;
+      document.getElementsByTagName('head')[0].appendChild(link);
+    }
+  };
+
+  this.resetPageIcon = function() {
+    if (!self.config.useFavIcon) {
+      return false;
+    }
+    var link = document.getElementById('favicon');
+    if (link) {
+      link.href = '/favicon.ico';
+    }
+  };
+
+  this.updatePeaks = function() {
+    var o = this._data.oPeak,
+        oSpan = o.getElementsByTagName('span');
+    oSpan[0].style.marginTop = (13-(Math.floor(15*this.peakData.left))+'px');
+    oSpan[1].style.marginTop = (13-(Math.floor(15*this.peakData.right))+'px');
+    if (sm.flashVersion > 8 && self.config.useFavIcon && self.config.usePeakData) {
+      self.setPageIcon(self.vuMeterData[parseInt(16*this.peakData.left,10)][parseInt(16*this.peakData.right,10)]);
+    }
+  };
+  
+  this.updateGraph = function() {
+    if (pl.config.flashVersion < 9 || (!pl.config.useWaveformData && !pl.config.useEQData)) {
+      return false;
+    }
+    var sbC = this._data.oGraph.getElementsByTagName('div'),
+        scale, i, offset;
+    if (pl.config.useWaveformData) {
+      // raw waveform
+      scale = 8; // Y axis (+/- this distance from 0)
+      for (i=255; i--;) {
+        sbC[255-i].style.marginTop = (1+scale+Math.ceil(this.waveformData.left[i]*-scale))+'px';
+      }
+    } else {
+      // eq spectrum
+      offset = 9;
+      for (i=255; i--;) {
+        sbC[255-i].style.marginTop = ((offset*2)-1+Math.ceil(this.eqData[i]*-offset))+'px';
+      }
+    }
+  };
+  
+  this.resetGraph = function() {
+    if (!pl.config.useEQData || pl.config.flashVersion<9) {
+      return false;
+    }
+    var sbC = this._data.oGraph.getElementsByTagName('div'),
+        scale = (!pl.config.useEQData?'9px':'17px'),
+        nHeight = (!pl.config.fillGraph?'1px':'32px'),
+        i;
+    for (i=255; i--;) {
+      sbC[255-i].style.marginTop = scale; // EQ scale
+      sbC[255-i].style.height = nHeight;
+    }
+  };
+  
+  this.updateTime = function() {
+    var str = self.strings.timing.replace('%s1',self.getTime(this.position,true));
+    str = str.replace('%s2',self.getTime(self.getDurationEstimate(this),true));
+    this._data.oTiming.innerHTML = str;
+
+    var startMatchOffset = document.getElementById("mysongCurrentPos");
+    startMatchOffset.innerHTML = self.getTime(this.position,true) + " secs";
+    startMatchOffset.setAttribute("offsetInMSecs",this.position);
+  };
+
+  this.getTheDamnTarget = function(e) {
+    return (e.target||(window.event?window.event.srcElement:null));
+  };
+  
+  this.withinStatusBar = function(o) {
+    return (self.isChildOfClass(o,'controls'));
+  };
+
+  this.handleClick = function(e) {
+
+    // a sound (or something) was clicked - determine what and handle appropriately
+
+    if (e.button === 2) {
+      if (!pl.config.allowRightClick) {
+        pl.stopEvent(e);
+      }
+      return pl.config.allowRightClick; // ignore right-clicks
+    }
+    var o = self.getTheDamnTarget(e),
+        sURL, soundURL, thisSound, oControls, oLI, str;
+    if (!o) {
+      return true;
+    }
+    if (self.dragActive) {
+      self.stopDrag(); // to be safe
+    }
+    if (self.withinStatusBar(o)) {
+      // self.handleStatusClick(e);
+      return false;
+    }
+    if (o.nodeName.toLowerCase() !== 'a') {
+      o = self.getParentByNodeName(o,'a');
+    }
+    if (!o) {
+      // not a link
+      return true;
+    }
+
+    // OK, we're dealing with a link
+
+    sURL = o.getAttribute('href');
+
+    if (!o.href || (!sm.canPlayLink(o) && !self.hasClass(o,'playable')) || self.hasClass(o,'exclude')) {
+
+      // do nothing, don't return anything.
+      return true;
+
+    } else {
+
+      // we have something we're interested in.
+
+      // find and init parent UL, if need be
+      self.initUL(self.getParentByNodeName(o, 'ul'));
+
+      // and decorate the link too, if needed
+      self.initItem(o);
+
+      soundURL = o.href;
+      thisSound = self.getSoundByObject(o);
+
+      if (thisSound) {
+
+        // sound already exists
+        self.setPageTitle(thisSound._data.originalTitle);
+        if (thisSound === self.lastSound) {
+          // ..and was playing (or paused) and isn't in an error state
+          if (thisSound.readyState !== 2) {
+            if (thisSound.playState !== 1) {
+              // not yet playing
+              thisSound.play();
+            } else {
+              thisSound.togglePause();
+            }
+          } else {
+            sm._writeDebug('Warning: sound failed to load (security restrictions, 404 or bad format)',2);
+          }
+        } else {
+          // ..different sound
+          if (self.lastSound) {
+            self.stopSound(self.lastSound);
+          }
+          if (spectrumContainer) {
+            thisSound._data.oTimingBox.appendChild(spectrumContainer);
+          }
+          thisSound.togglePause(); // start playing current
+        }
+
+      } else {
+
+        // create sound
+        thisSound = sm.createSound({
+          id:o.id,
+          url:decodeURI(soundURL),
+          onplay:self.events.play,
+          onstop:self.events.stop,
+          onpause:self.events.pause,
+          onresume:self.events.resume,
+          onfinish:self.events.finish,
+          whileloading:self.events.whileloading,
+          whileplaying:self.events.whileplaying,
+          onmetadata:self.events.metadata,
+          onload:self.events.onload
+        });
+
+        // append control template
+        oControls = self.oControls.cloneNode(true);
+        oLI = o.parentNode;
+        oLI.appendChild(oControls);
+        if (spectrumContainer) {
+          oLI.appendChild(spectrumContainer);
+        }
+        self.soundsByObject[o.id] = thisSound;
+
+        // tack on some custom data
+        thisSound._data = {
+          oLink: o, // DOM reference within SM2 object event handlers
+          oLI: oLI,
+          oControls: self.select('controls',oLI),
+          oStatus: self.select('statusbar',oLI),
+          oLoading: self.select('loading',oLI),
+          oPosition: self.select('position',oLI),
+          oTimingBox: self.select('timing',oLI),
+          oTiming: self.select('timing',oLI).getElementsByTagName('div')[0],
+          oPeak: self.select('peak',oLI),
+          oGraph: self.select('spectrum-box',oLI),
+          className: self.css.sPlaying,
+          originalTitle: o.innerHTML,
+          metadata: null
+        };
+
+        if (spectrumContainer) {
+          thisSound._data.oTimingBox.appendChild(spectrumContainer);
+        }
+
+        // "Metadata"
+        if (thisSound._data.oLI.getElementsByTagName('ul').length) {
+          thisSound._data.metadata = new Metadata(thisSound);
+        }
+
+        // set initial timer stuff (before loading)
+        str = self.strings.timing.replace('%s1',self.config.emptyTime);
+        str = str.replace('%s2',self.config.emptyTime);
+        thisSound._data.oTiming.innerHTML = str;
+        self.sounds.push(thisSound);
+        if (self.lastSound) {
+          self.stopSound(self.lastSound);
+        }
+        self.resetGraph.apply(thisSound);
+        thisSound.play();
+
+      }
+
+      self.lastSound = thisSound; // reference for next call
+      return self.stopEvent(e);
+
+    }
+
+  };
+  
+  this.handleMouseDown = function(e) {
+    // a sound link was clicked
+    if (isTouchDevice && e.touches) {
+      e = e.touches[0];
+    }
+    if (e.button === 2) {
+      if (!pl.config.allowRightClick) {
+        pl.stopEvent(e);
+      }
+      return pl.config.allowRightClick; // ignore right-clicks
+    }
+    var o = self.getTheDamnTarget(e);
+    if (!o) {
+      return true;
+    }
+    if (!self.withinStatusBar(o)) {
+      return true;
+    }
+    self.dragActive = true;
+    self.lastSound.pause();
+    self.setPosition(e);
+    if (!isTouchDevice) {
+      _event.add(document,'mousemove',self.handleMouseMove);
+    } else {
+      _event.add(document,'touchmove',self.handleMouseMove);
+    }
+    self.addClass(self.lastSound._data.oControls,'dragging');
+    return self.stopEvent(e);
+  };
+  
+  this.handleMouseMove = function(e) {
+    if (isTouchDevice && e.touches) {
+      e = e.touches[0];
+    }
+    // set position accordingly
+    if (self.dragActive) {
+      if (self.config.useThrottling) {
+        // be nice to CPU/externalInterface
+        var d = new Date();
+        if (d-self.dragExec>20) {
+          self.setPosition(e);
+        } else {
+          window.clearTimeout(self.dragTimer);
+          self.dragTimer = window.setTimeout(function(){self.setPosition(e);},20);
+        }
+        self.dragExec = d;
+      } else {
+        // oh the hell with it
+        self.setPosition(e);
+      }
+    } else {
+      self.stopDrag();
+    }
+    e.stopPropagation = true;
+    return false;
+  };
+  
+  this.stopDrag = function(e) {
+    if (self.dragActive) {
+      self.removeClass(self.lastSound._data.oControls,'dragging');
+      if (!isTouchDevice) {
+        _event.remove(document,'mousemove',self.handleMouseMove);
+      } else {
+        _event.remove(document,'touchmove',self.handleMouseMove);
+      }
+      if (!pl.hasClass(self.lastSound._data.oLI,self.css.sPaused)) {
+        self.lastSound.resume();
+      }
+      self.dragActive = false;
+      return self.stopEvent(e);
+    }
+  };
+  
+  this.handleStatusClick = function(e) {
+    self.setPosition(e);
+    if (!pl.hasClass(self.lastSound._data.oLI,self.css.sPaused)) {
+      self.resume();
+    }
+    return self.stopEvent(e);
+  };
+  
+  this.stopEvent = function(e) {
+    if (typeof e !== 'undefined') {
+      if (typeof e.preventDefault !== 'undefined') {
+        e.preventDefault();
+      } else {
+        e.stopPropagation = true;
+        e.returnValue = false;
+      }
+    }
+    return false;
+  };
+ 
+  this.setPosition = function(e) {
+    // called from slider control
+    var oThis = self.getTheDamnTarget(e),
+        x, oControl, oSound, nMsecOffset;
+    if (!oThis) {
+      return true;
+    }
+    oControl = oThis;
+    while (!self.hasClass(oControl,'controls') && oControl.parentNode) {
+      oControl = oControl.parentNode;
+    }
+    oSound = self.lastSound;
+    x = parseInt(e.clientX,10);
+    // play sound at this position
+    nMsecOffset = Math.floor((x-self.getOffX(oControl)-4)/(oControl.offsetWidth)*self.getDurationEstimate(oSound));
+    if (!isNaN(nMsecOffset)) {
+      nMsecOffset = Math.min(nMsecOffset,oSound.duration);
+    }
+    if (!isNaN(nMsecOffset)) {
+      oSound.setPosition(nMsecOffset);
+    }
+  };
+
+  this.stopSound = function(oSound) {
+    sm._writeDebug('stopping sound: '+oSound.sID);
+    sm.stop(oSound.sID);
+    if (!isTouchDevice) { // iOS 4.2+ security blocks onfinish() -> playNext() if we set a .src in-between(?)
+      sm.unload(oSound.sID);
+    }
+  };
+
+  this.getDurationEstimate = function(oSound) {
+    if (oSound.instanceOptions.isMovieStar) {
+      return (oSound.duration);
+    } else {
+      return (!oSound._data.metadata || !oSound._data.metadata.data.givenDuration ? (oSound.durationEstimate||0) : oSound._data.metadata.data.givenDuration);
+    }
+  };
+
+  this.createVUData = function() {
+
+    var i=0, j=0,
+      canvas = vuDataCanvas.getContext('2d'),
+      vuGrad = canvas.createLinearGradient(0, 16, 0, 0),
+      bgGrad, outline;
+
+    vuGrad.addColorStop(0,'rgb(0,192,0)');
+    vuGrad.addColorStop(0.30,'rgb(0,255,0)');
+    vuGrad.addColorStop(0.625,'rgb(255,255,0)');
+    vuGrad.addColorStop(0.85,'rgb(255,0,0)');
+    bgGrad = canvas.createLinearGradient(0, 16, 0, 0);
+    outline = 'rgba(0,0,0,0.2)';
+    bgGrad.addColorStop(0,outline);
+    bgGrad.addColorStop(1,'rgba(0,0,0,0.5)');
+    for (i=0; i<16; i++) {
+      self.vuMeterData[i] = [];
+    }
+    for (i=0; i<16; i++) {
+      for (j=0; j<16; j++) {
+        // reset/erase canvas
+        vuDataCanvas.setAttribute('width',16);
+        vuDataCanvas.setAttribute('height',16);
+        // draw new stuffs
+        canvas.fillStyle = bgGrad;
+        canvas.fillRect(0,0,7,15);
+        canvas.fillRect(8,0,7,15);
+        /*
+        // shadow
+        canvas.fillStyle = 'rgba(0,0,0,0.1)';
+        canvas.fillRect(1,15-i,7,17-(17-i));
+        canvas.fillRect(9,15-j,7,17-(17-j));
+        */
+        canvas.fillStyle = vuGrad;
+        canvas.fillRect(0,15-i,7,16-(16-i));
+        canvas.fillRect(8,15-j,7,16-(16-j));
+        // and now, clear out some bits.
+        canvas.clearRect(0,3,16,1);
+        canvas.clearRect(0,7,16,1);
+        canvas.clearRect(0,11,16,1);
+        self.vuMeterData[i][j] = vuDataCanvas.toDataURL('image/png');
+        // for debugging VU images
+        /*
+        var o = document.createElement('img');
+        o.style.marginRight = '5px'; 
+        o.src = self.vuMeterData[i][j];
+        document.documentElement.appendChild(o);
+        */
+      }
+    }
+
+  };
+
+  this.testCanvas = function() {
+    // canvas + toDataURL();
+    var c = document.createElement('canvas'),
+        ctx = null, ok;
+    if (!c || typeof c.getContext === 'undefined') {
+      return null;
+    }
+    ctx = c.getContext('2d');
+    if (!ctx || typeof c.toDataURL !== 'function') {
+        return null;
+    }
+    // just in case..
+    try {
+        ok = c.toDataURL('image/png');
+    } catch(e) {
+      // no canvas or no toDataURL()
+      return null;
+    }
+    // assume we're all good.
+    return c;
+  };
+
+  this.initItem = function(oNode) {
+    if (!oNode.id) {
+      oNode.id = 'pagePlayerMP3Sound'+(self.soundCount++);
+    }
+    self.addClass(oNode,self.css.sDefault); // add default CSS decoration
+  };
+
+  this.initUL = function(oULNode) {
+    // set up graph box stuffs
+    if (sm.flashVersion >= 9) {
+        self.addClass(oULNode,self.cssBase);
+    }
+  };
+
+  this.init = function(oConfig) {
+
+    if (oConfig) {
+      // allow overriding via arguments object
+      sm._writeDebug('pagePlayer.init(): Using custom configuration');
+      this.config = this._mergeObjects(oConfig,this.config);
+    } else {
+      sm._writeDebug('pagePlayer.init(): Using default configuration');
+    }
+
+    var i, spectrumBox, sbC, oF, oClone, oTiming;
+
+    // apply externally-defined override, if applicable
+    this.cssBase = []; // optional features added to ul.playlist
+
+    // apply some items to SM2
+    sm.useFlashBlock = true;
+
+    if (sm.flashVersion >= 9) {
+
+      sm.useMovieStar = this.config.useMovieStar; // enable playing FLV, MP4 etc.
+      sm.defaultOptions.usePeakData = this.config.usePeakData;
+      sm.defaultOptions.useWaveformData = this.config.useWaveformData;
+      sm.defaultOptions.useEQData = this.config.useEQData;
+
+      if (this.config.usePeakData) {
+        this.cssBase.push('use-peak');
+      }
+
+      if (this.config.useWaveformData || this.config.useEQData) {
+        this.cssBase.push('use-spectrum');
+      }
+
+      this.cssBase = this.cssBase.join(' ');
+
+      if (this.config.useFavIcon) {
+        vuDataCanvas = self.testCanvas();
+        if (vuDataCanvas && supportsFavicon) {
+          // these browsers support dynamically-updating the favicon
+          self.createVUData();
+        } else {
+          // browser doesn't support doing this
+          this.config.useFavIcon = false;
+        }
+      }
+
+    } else if (this.config.usePeakData || this.config.useWaveformData || this.config.useEQData) {
+
+      sm._writeDebug('Page player: Note: soundManager.flashVersion = 9 is required for peak/waveform/EQ features.');
+
+    }
+
+    controlTemplate = document.createElement('div');
+
+     controlTemplate.innerHTML = [
+
+      // control markup inserted dynamically after each page player link
+      // if you want to change the UI layout, this is the place to do it.
+
+      '  <div class="controls">',
+      '   <div class="statusbar">',
+      '    <div class="loading"></div>',
+      '    <div class="position"></div>',
+      '   </div>',
+      '  </div>',
+
+      '  <div class="timing">',
+      '   <div id="sm2_timing" class="timing-data">',
+      '    <span class="sm2_position">%s1</span> / <span class="sm2_total">%s2</span>',
+      '   </div>',
+      '  </div>',
+
+      '  <div class="peak">',
+      '   <div class="peak-box"><span class="l"></span><span class="r"></span></div>',
+      '  </div>',
+
+      ' <div class="spectrum-container">',
+      '  <div class="spectrum-box">',
+      '   <div class="spectrum"></div>',
+      '  </div>',
+      ' </div>'
+
+    ].join('\n');
+
+    if (sm.flashVersion >= 9) {
+
+      // create the spectrum box ish
+      spectrumContainer = self.select('spectrum-container',controlTemplate);
+
+      // take out of template, too
+      spectrumContainer = controlTemplate.removeChild(spectrumContainer);
+
+      spectrumBox = self.select('spectrum-box',spectrumContainer);
+
+      sbC = spectrumBox.getElementsByTagName('div')[0];
+      oF = document.createDocumentFragment();
+      oClone = null;
+      for (i=256; i--;) {
+        oClone = sbC.cloneNode(false);
+        oClone.style.left = (i)+'px';
+        oF.appendChild(oClone);
+      }
+      spectrumBox.removeChild(sbC);
+      spectrumBox.appendChild(oF);
+
+    } else {
+
+      // flash 8-only, take out the spectrum container and peak elements
+      controlTemplate.removeChild(self.select('spectrum-container',controlTemplate));
+      controlTemplate.removeChild(self.select('peak',controlTemplate));
+
+    }
+
+    self.oControls = controlTemplate.cloneNode(true);
+
+    oTiming = self.select('timing-data',controlTemplate);
+    self.strings.timing = oTiming.innerHTML;
+    oTiming.innerHTML = '';
+    oTiming.id = '';
+
+    function doEvents(action) { // action: add / remove
+
+      _event[action](document,'click',self.handleClick);
+
+      if (!isTouchDevice) {
+        _event[action](document,'mousedown',self.handleMouseDown);
+        _event[action](document,'mouseup',self.stopDrag);
+      } else {
+        _event[action](document,'touchstart',self.handleMouseDown);
+        _event[action](document,'touchend',self.stopDrag);
+      }
+
+      _event[action](window, 'unload', cleanup);
+
+    }
+
+    cleanup = function() {
+      doEvents('remove');
+    };
+
+    doEvents('add');
+
+    sm._writeDebug('pagePlayer.init(): Ready',1);
+
+    if (self.config.autoStart) {
+      // grab the first ul.playlist link
+      pl.handleClick({target:pl.getByClassName('playlist', 'ul')[0].getElementsByTagName('a')[0]});
+    }
+
+  };
+
+}
+
+soundManager.useFlashBlock = true;
+
+soundManager.onready(function() {
+  pagePlayer = new PagePlayer();
+  pagePlayer.init(typeof PP_CONFIG !== 'undefined' ? PP_CONFIG : null);
+});
Index: /gs3-extensions/audioDB/trunk/src/interface/script/soundmanager2-jsmin.js
===================================================================
--- /gs3-extensions/audioDB/trunk/src/interface/script/soundmanager2-jsmin.js	(revision 26291)
+++ /gs3-extensions/audioDB/trunk/src/interface/script/soundmanager2-jsmin.js	(revision 26291)
@@ -0,0 +1,103 @@
+/** @license
+
+ SoundManager 2: JavaScript Sound for the Web
+ ----------------------------------------------
+ http://schillmania.com/projects/soundmanager2/
+
+ Copyright (c) 2007, Scott Schiller. All rights reserved.
+ Code provided under the BSD License:
+ http://schillmania.com/projects/soundmanager2/license.txt
+
+ V2.97a.20110801
+*/
+(function(S){function T(T,fa){function o(c){return function(a){return!this._t||!this._t._a?(this._t&&this._t.sID?b._wD(l+"ignoring "+a.type+": "+this._t.sID):b._wD(l+"ignoring "+a.type),null):c.call(this,a)}}this.flashVersion=8;this.debugMode=!0;this.debugFlash=!1;this.useConsole=!0;this.waitForWindowLoad=this.consoleOnly=!1;this.nullURL="about:blank";this.allowPolling=!0;this.useFastPolling=!1;this.useMovieStar=!0;this.bgColor="#ffffff";this.useHighPerformance=!1;this.flashPollingInterval=null;this.flashLoadTimeout=
+1E3;this.wmode=null;this.allowScriptAccess="always";this.useFlashBlock=!1;this.useHTML5Audio=!0;this.html5Test=/^(probably|maybe)$/i;this.preferFlash=!0;this.audioFormats={mp3:{type:['audio/mpeg; codecs="mp3"',"audio/mpeg","audio/mp3","audio/MPA","audio/mpa-robust"],required:!0},mp4:{related:["aac","m4a"],type:['audio/mp4; codecs="mp4a.40.2"',"audio/aac","audio/x-m4a","audio/MP4A-LATM","audio/mpeg4-generic"],required:!1},ogg:{type:["audio/ogg; codecs=vorbis"],required:!1},wav:{type:['audio/wav; codecs="1"',
+"audio/wav","audio/wave","audio/x-wav"],required:!1}};this.defaultOptions={autoLoad:!1,stream:!0,autoPlay:!1,loops:1,onid3:null,onload:null,whileloading:null,onplay:null,onpause:null,onresume:null,whileplaying:null,onstop:null,onfailure:null,onfinish:null,onbeforefinish:null,onbeforefinishtime:5E3,onbeforefinishcomplete:null,onjustbeforefinish:null,onjustbeforefinishtime:200,multiShot:!0,multiShotEvents:!1,position:null,pan:0,type:null,usePolicyFile:!1,volume:100};this.flash9Options={isMovieStar:null,
+usePeakData:!1,useWaveformData:!1,useEQData:!1,onbufferchange:null,ondataerror:null};this.movieStarOptions={bufferTime:3,serverURL:null,onconnect:null,duration:null};this.version=null;this.versionNumber="V2.97a.20110801";this.movieURL=null;this.url=T||null;this.altURL=null;this.enabled=this.swfLoaded=!1;this.o=null;this.movieID="sm2-container";this.id=fa||"sm2movie";this.swfCSS={swfBox:"sm2-object-box",swfDefault:"movieContainer",swfError:"swf_error",swfTimedout:"swf_timedout",swfLoaded:"swf_loaded",
+swfUnblocked:"swf_unblocked",sm2Debug:"sm2_debug",highPerf:"high_performance",flashDebug:"flash_debug"};this.oMC=null;this.sounds={};this.soundIDs=[];this.muted=!1;this.debugID="soundmanager-debug";this.debugURLParam=/([#?&])debug=1/i;this.didFlashBlock=this.specialWmodeCase=!1;this.filePattern=null;this.filePatterns={flash8:/\.mp3(\?.*)?$/i,flash9:/\.mp3(\?.*)?$/i};this.baseMimeTypes=/^\s*audio\/(?:x-)?(?:mp(?:eg|3))\s*(?:$|;)/i;this.netStreamMimeTypes=/^\s*audio\/(?:x-)?(?:mp(?:eg|3))\s*(?:$|;)/i;
+this.netStreamTypes=["aac","flv","mov","mp4","m4v","f4v","m4a","mp4v","3gp","3g2"];this.netStreamPattern=RegExp("\\.("+this.netStreamTypes.join("|")+")(\\?.*)?$","i");this.mimePattern=this.baseMimeTypes;this.features={buffering:!1,peakData:!1,waveformData:!1,eqData:!1,movieStar:!1};this.sandbox={type:null,types:{remote:"remote (domain-based) rules",localWithFile:"local with file access (no internet access)",localWithNetwork:"local with network (internet access only, no local access)",localTrusted:"local, trusted (local+internet access)"},
+description:null,noRemote:null,noLocal:null};this.hasHTML5=typeof Audio!=="undefined"&&typeof(new Audio).canPlayType!=="undefined";this.html5={usingFlash:null};this.flash={};this.ignoreFlash=this.html5Only=!1;var wa,b=this,l="HTML5::",r,s=navigator.userAgent,h=S,L=h.location.href.toString(),i=this.flashVersion,g=document,ga,U,z=[],ha=!0,q,M=!1,N=!1,j=!1,v=!1,ia=!1,k,Na=0,O,t,ja,D,E,V,xa,ka,C,W,X,F,la,Y,Z,G,ya,ma,Oa=["log","info","warn","error"],za,$,Aa,P=null,na=null,n,oa,H,Ba,aa,ba,pa,m,ca=!1,qa=
+!1,Ca,Da,w=null,Ea,da,Q,A,ra,Fa,p,Ga=Array.prototype.slice,R=!1,u,ea,Ha,x,Ia,Ja=s.match(/(ipad|iphone|ipod)/i),Pa=s.match(/(mobile|pre\/|xoom)/i)||Ja,y=s.match(/msie/i),Qa=s.match(/webkit/i),I=s.match(/safari/i)&&!s.match(/chrome/i),Ra=s.match(/opera/i),sa=!L.match(/usehtml5audio/i)&&!L.match(/sm2\-ignorebadua/i)&&I&&s.match(/OS X 10_6_([3-7])/i),ta=typeof console!=="undefined"&&typeof console.log!=="undefined",ua=typeof g.hasFocus!=="undefined"?g.hasFocus():null,J=I&&typeof g.hasFocus==="undefined",
+Ka=!J,La=/(mp3|mp4|mpa)/i,K=g.location?g.location.protocol.match(/http/i):null,Ma=!K?"http:":"";this.useAltURL=!K;this._global_a=null;if(Pa&&(b.useHTML5Audio=!0,b.preferFlash=!1,Ja))R=b.ignoreFlash=!0;this.supported=this.ok=function(){return w?j&&!v:b.useHTML5Audio&&b.hasHTML5};this.getMovie=function(b){return y?h[b]:I?r(b)||g[b]:r(b)};this.createSound=function(c){function a(){e=aa(e);b.sounds[d.id]=new wa(d);b.soundIDs.push(d.id);return b.sounds[d.id]}var e=null,f=null,d=null;if(!j||!b.ok())return pa("soundManager.createSound(): "+
+n(!j?"notReady":"notOK")),!1;arguments.length===2&&(c={id:arguments[0],url:arguments[1]});d=e=t(c);d.id.toString().charAt(0).match(/^[0-9]$/)&&b._wD("soundManager.createSound(): "+n("badID",d.id),2);b._wD("soundManager.createSound(): "+d.id+" ("+d.url+")",1);if(m(d.id,!0))return b._wD("soundManager.createSound(): "+d.id+" exists",1),b.sounds[d.id];if(da(d))f=a(),b._wD("Loading sound "+d.id+" via HTML5"),f._setup_html5(d);else{if(i>8&&b.useMovieStar){if(d.isMovieStar===null)d.isMovieStar=d.serverURL||
+d.type&&d.type.match(b.netStreamPattern)||d.url.match(b.netStreamPattern)?!0:!1;d.isMovieStar&&b._wD("soundManager.createSound(): using MovieStar handling");if(d.isMovieStar){if(d.usePeakData)k("noPeak"),d.usePeakData=!1;d.loops>1&&k("noNSLoop")}}d=ba(d,"soundManager.createSound(): ");f=a();if(i===8)b.o._createSound(d.id,d.onjustbeforefinishtime,d.loops||1,d.usePolicyFile);else if(b.o._createSound(d.id,d.url,d.onjustbeforefinishtime,d.usePeakData,d.useWaveformData,d.useEQData,d.isMovieStar,d.isMovieStar?
+d.bufferTime:!1,d.loops||1,d.serverURL,d.duration||null,d.autoPlay,!0,d.autoLoad,d.usePolicyFile),!d.serverURL)f.connected=!0,d.onconnect&&d.onconnect.apply(f);!d.serverURL&&(d.autoLoad||d.autoPlay)&&f.load(d)}!d.serverURL&&d.autoPlay&&f.play();return f};this.destroySound=function(c,a){if(!m(c))return!1;var e=b.sounds[c],f;e._iO={};e.stop();e.unload();for(f=0;f<b.soundIDs.length;f++)if(b.soundIDs[f]===c){b.soundIDs.splice(f,1);break}a||e.destruct(!0);delete b.sounds[c];return!0};this.load=function(c,
+a){return!m(c)?!1:b.sounds[c].load(a)};this.unload=function(c){return!m(c)?!1:b.sounds[c].unload()};this.start=this.play=function(c,a){return!j||!b.ok()?(pa("soundManager.play(): "+n(!j?"notReady":"notOK")),!1):!m(c)?(a instanceof Object||(a={url:a}),a&&a.url?(b._wD('soundManager.play(): attempting to create "'+c+'"',1),a.id=c,b.createSound(a).play()):!1):b.sounds[c].play(a)};this.setPosition=function(c,a){return!m(c)?!1:b.sounds[c].setPosition(a)};this.stop=function(c){if(!m(c))return!1;b._wD("soundManager.stop("+
+c+")",1);return b.sounds[c].stop()};this.stopAll=function(){var c;b._wD("soundManager.stopAll()",1);for(c in b.sounds)b.sounds.hasOwnProperty(c)&&b.sounds[c].stop()};this.pause=function(c){return!m(c)?!1:b.sounds[c].pause()};this.pauseAll=function(){var c;for(c=b.soundIDs.length;c--;)b.sounds[b.soundIDs[c]].pause()};this.resume=function(c){return!m(c)?!1:b.sounds[c].resume()};this.resumeAll=function(){var c;for(c=b.soundIDs.length;c--;)b.sounds[b.soundIDs[c]].resume()};this.togglePause=function(c){return!m(c)?
+!1:b.sounds[c].togglePause()};this.setPan=function(c,a){return!m(c)?!1:b.sounds[c].setPan(a)};this.setVolume=function(c,a){return!m(c)?!1:b.sounds[c].setVolume(a)};this.mute=function(c){var a=0;typeof c!=="string"&&(c=null);if(c){if(!m(c))return!1;b._wD('soundManager.mute(): Muting "'+c+'"');return b.sounds[c].mute()}else{b._wD("soundManager.mute(): Muting all sounds");for(a=b.soundIDs.length;a--;)b.sounds[b.soundIDs[a]].mute();b.muted=!0}return!0};this.muteAll=function(){b.mute()};this.unmute=function(c){typeof c!==
+"string"&&(c=null);if(c){if(!m(c))return!1;b._wD('soundManager.unmute(): Unmuting "'+c+'"');return b.sounds[c].unmute()}else{b._wD("soundManager.unmute(): Unmuting all sounds");for(c=b.soundIDs.length;c--;)b.sounds[b.soundIDs[c]].unmute();b.muted=!1}return!0};this.unmuteAll=function(){b.unmute()};this.toggleMute=function(c){return!m(c)?!1:b.sounds[c].toggleMute()};this.getMemoryUse=function(){var c=0;b.o&&i!==8&&(c=parseInt(b.o._getMemoryUse(),10));return c};this.disable=function(c){var a;typeof c===
+"undefined"&&(c=!1);if(v)return!1;v=!0;k("shutdown",1);for(a=b.soundIDs.length;a--;)za(b.sounds[b.soundIDs[a]]);O(c);p.remove(h,"load",E);return!0};this.canPlayMIME=function(c){var a;b.hasHTML5&&(a=Q({type:c}));return!w||a?a:c?c.match(b.mimePattern)?!0:!1:null};this.canPlayURL=function(c){var a;b.hasHTML5&&(a=Q({url:c}));return!w||a?a:c?c.match(b.filePattern)?!0:!1:null};this.canPlayLink=function(c){return typeof c.type!=="undefined"&&c.type&&b.canPlayMIME(c.type)?!0:b.canPlayURL(c.href)};this.getSoundById=
+function(c,a){if(!c)throw Error("soundManager.getSoundById(): sID is null/undefined");var e=b.sounds[c];!e&&!a&&b._wD('"'+c+'" is an invalid sound ID.',2);return e};this.onready=function(c,a){if(c&&c instanceof Function)return j&&b._wD(n("queue","onready")),a||(a=h),ja("onready",c,a),D(),!0;else throw n("needFunction","onready");};this.ontimeout=function(c,a){if(c&&c instanceof Function)return j&&b._wD(n("queue","ontimeout")),a||(a=h),ja("ontimeout",c,a),D({type:"ontimeout"}),!0;else throw n("needFunction",
+"ontimeout");};this._wD=this._writeDebug=function(c,a,e){var f,d;if(!b.debugMode)return!1;typeof e!=="undefined"&&e&&(c=c+" | "+(new Date).getTime());if(ta&&b.useConsole){e=Oa[a];if(typeof console[e]!=="undefined")console[e](c);else console.log(c);if(b.useConsoleOnly)return!0}try{f=r("soundmanager-debug");if(!f)return!1;d=g.createElement("div");if(++Na%2===0)d.className="sm2-alt";a=typeof a==="undefined"?0:parseInt(a,10);d.appendChild(g.createTextNode(c));if(a){if(a>=2)d.style.fontWeight="bold";if(a===
+3)d.style.color="#ff3333"}f.insertBefore(d,f.firstChild)}catch(B){}return!0};this._debug=function(){var c,a;k("currentObj",1);c=0;for(a=b.soundIDs.length;c<a;c++)b.sounds[b.soundIDs[c]]._debug()};this.reboot=function(){b._wD("soundManager.reboot()");b.soundIDs.length&&b._wD("Destroying "+b.soundIDs.length+" SMSound objects...");var c,a;for(c=b.soundIDs.length;c--;)b.sounds[b.soundIDs[c]].destruct();try{if(y)na=b.o.innerHTML;P=b.o.parentNode.removeChild(b.o);b._wD("Flash movie removed.")}catch(e){k("badRemove",
+2)}na=P=w=null;b.enabled=la=j=ca=qa=M=N=v=b.swfLoaded=!1;b.soundIDs=b.sounds=[];b.o=null;for(c in z)if(z.hasOwnProperty(c))for(a=z[c].length;a--;)z[c][a].fired=!1;b._wD("soundManager: Rebooting...");h.setTimeout(b.beginDelayedInit,20)};this.getMoviePercent=function(){return b.o&&typeof b.o.PercentLoaded!=="undefined"?b.o.PercentLoaded():null};this.beginDelayedInit=function(){ia=!0;F();setTimeout(function(){if(qa)return!1;Z();X();return qa=!0},20);V()};this.destruct=function(){b._wD("soundManager.destruct()");
+b.disable(!0)};x={abort:o(function(){b._wD(l+"abort: "+this._t.sID)}),canplay:o(function(){if(this._t._html5_canplay)return!0;this._t._html5_canplay=!0;b._wD(l+"canplay: "+this._t.sID+", "+this._t.url);this._t._onbufferchange(0);var c=!isNaN(this._t.position)?this._t.position/1E3:null;if(this._t.position&&this.currentTime!==c){b._wD(l+"canplay: setting position to "+c);try{this.currentTime=c}catch(a){b._wD(l+"setting position failed: "+a.message,2)}}}),load:o(function(){this._t.loaded||(this._t._onbufferchange(0),
+this._t._whileloading(this._t.bytesTotal,this._t.bytesTotal,this._t._get_html5_duration()),this._t._onload(!0))}),emptied:o(function(){b._wD(l+"emptied: "+this._t.sID)}),ended:o(function(){b._wD(l+"ended: "+this._t.sID);this._t._onfinish()}),error:o(function(){b._wD(l+"error: "+this.error.code);this._t._onload(!1)}),loadeddata:o(function(){var c=this._t,a=c.bytesTotal||1;b._wD(l+"loadeddata: "+this._t.sID);if(!c._loaded&&!I)c.duration=c._get_html5_duration(),c._whileloading(a,a,c._get_html5_duration()),
+c._onload(!0)}),loadedmetadata:o(function(){b._wD(l+"loadedmetadata: "+this._t.sID)}),loadstart:o(function(){b._wD(l+"loadstart: "+this._t.sID);this._t._onbufferchange(1)}),play:o(function(){b._wD(l+"play: "+this._t.sID+", "+this._t.url);this._t._onbufferchange(0)}),playing:o(function(){b._wD(l+"playing: "+this._t.sID+", "+this._t.url);this._t._onbufferchange(0)}),progress:o(function(c){if(this._t.loaded)return!1;var a,e,f;f=0;var d=c.type==="progress";e=c.target.buffered;var B=c.loaded||0,va=c.total||
+1;if(e&&e.length){for(a=e.length;a--;)f=e.end(a)-e.start(a);B=f/c.target.duration;if(d&&e.length>1){f=[];e=e.length;for(a=0;a<e;a++)f.push(c.target.buffered.start(a)+"-"+c.target.buffered.end(a));b._wD(l+"progress: timeRanges: "+f.join(", "))}d&&!isNaN(B)&&b._wD(l+"progress: "+this._t.sID+": "+Math.floor(B*100)+"% loaded")}isNaN(B)||(this._t._onbufferchange(0),this._t._whileloading(B,va,this._t._get_html5_duration()),B&&va&&B===va&&x.load.call(this,c))}),ratechange:o(function(){b._wD(l+"ratechange: "+
+this._t.sID)}),suspend:o(function(c){b._wD(l+"suspend: "+this._t.sID);x.progress.call(this,c)}),stalled:o(function(){b._wD(l+"stalled: "+this._t.sID)}),timeupdate:o(function(){this._t._onTimer()}),waiting:o(function(){b._wD(l+"waiting: "+this._t.sID);this._t._onbufferchange(1)})};wa=function(c){var a=this,e,f,d;this.sID=c.id;this.url=c.url;this._iO=this.instanceOptions=this.options=t(c);this.pan=this.options.pan;this.volume=this.options.volume;this._lastURL=null;this.isHTML5=!1;this._a=null;this.id3=
+{};this._debug=function(){if(b.debugMode){var c=null,d=[],e,f;for(c in a.options)a.options[c]!==null&&(a.options[c]instanceof Function?(e=a.options[c].toString(),e=e.replace(/\s\s+/g," "),f=e.indexOf("{"),d.push(" "+c+": {"+e.substr(f+1,Math.min(Math.max(e.indexOf("\n")-1,64),64)).replace(/\n/g,"")+"... }")):d.push(" "+c+": "+a.options[c]));b._wD("SMSound() merged options: {\n"+d.join(", \n")+"\n}")}};this._debug();this.load=function(c){var d=null;if(typeof c!=="undefined")a._iO=t(c,a.options),a.instanceOptions=
+a._iO;else if(c=a.options,a._iO=c,a.instanceOptions=a._iO,a._lastURL&&a._lastURL!==a.url)k("manURL"),a._iO.url=a.url,a.url=null;if(!a._iO.url)a._iO.url=a.url;b._wD("SMSound.load(): "+a._iO.url,1);if(a._iO.url===a.url&&a.readyState!==0&&a.readyState!==2)return k("onURL",1),a;a._lastURL=a.url;a.loaded=!1;a.readyState=1;a.playState=0;if(da(a._iO))d=a._setup_html5(a._iO),d._called_load?b._wD(l+"ignoring request to load again: "+a.sID):(b._wD(l+"load: "+a.sID),a._html5_canplay=!1,d.load(),d._called_load=
+!0,a._iO.autoPlay&&a.play());else try{a.isHTML5=!1,a._iO=ba(aa(a._iO)),i===8?b.o._load(a.sID,a._iO.url,a._iO.stream,a._iO.autoPlay,a._iO.whileloading?1:0,a._iO.loops||1,a._iO.usePolicyFile):b.o._load(a.sID,a._iO.url,a._iO.stream?!0:!1,a._iO.autoPlay?!0:!1,a._iO.loops||1,a._iO.autoLoad?!0:!1,a._iO.usePolicyFile)}catch(e){k("smError",2),q("onload",!1),G({type:"SMSOUND_LOAD_JS_EXCEPTION",fatal:!0})}return a};this.unload=function(){if(a.readyState!==0){b._wD('SMSound.unload(): "'+a.sID+'"');if(a.isHTML5){if(f(),
+a._a)a._a.pause(),a._a.src=""}else i===8?b.o._unload(a.sID,b.nullURL):b.o._unload(a.sID);e()}return a};this.destruct=function(c){b._wD('SMSound.destruct(): "'+a.sID+'"');if(a.isHTML5){if(f(),a._a)a._a.pause(),a._a.src="",R||a._remove_html5_events(),a._a._t=null,a._a=null}else a._iO.onfailure=null,b.o._destroySound(a.sID);c||b.destroySound(a.sID,!0)};this.start=this.play=function(c,e){var f,e=e===void 0?!0:e;c||(c={});a._iO=t(c,a._iO);a._iO=t(a._iO,a.options);a.instanceOptions=a._iO;if(a._iO.serverURL&&
+!a.connected)return a.getAutoPlay()||(b._wD("SMSound.play():  Netstream not connected yet - setting autoPlay"),a.setAutoPlay(!0)),a;da(a._iO)&&(a._setup_html5(a._iO),d());if(a.playState===1&&!a.paused)if(f=a._iO.multiShot)b._wD('SMSound.play(): "'+a.sID+'" already playing (multi-shot)',1);else return b._wD('SMSound.play(): "'+a.sID+'" already playing (one-shot)',1),a;if(a.loaded)b._wD('SMSound.play(): "'+a.sID+'"');else if(a.readyState===0){b._wD('SMSound.play(): Attempting to load "'+a.sID+'"',1);
+if(!a.isHTML5)a._iO.autoPlay=!0;a.load(a._iO)}else if(a.readyState===2)return b._wD('SMSound.play(): Could not load "'+a.sID+'" - exiting',2),a;else b._wD('SMSound.play(): "'+a.sID+'" is loading - attempting to play..',1);if(!a.isHTML5&&i===9&&a.position>0&&a.position===a.duration)b._wD('SMSound.play(): "'+a.sID+'": Sound at end, resetting to position:0'),a._iO.position=0;if(a.paused&&a.position&&a.position>0)b._wD('SMSound.play(): "'+a.sID+'" is resuming from paused state',1),a.resume();else{b._wD('SMSound.play(): "'+
+a.sID+'" is starting to play');a.playState=1;a.paused=!1;(!a.instanceCount||a._iO.multiShotEvents||!a.isHTML5&&i>8&&!a.getAutoPlay())&&a.instanceCount++;a.position=typeof a._iO.position!=="undefined"&&!isNaN(a._iO.position)?a._iO.position:0;if(!a.isHTML5)a._iO=ba(aa(a._iO));if(a._iO.onplay&&e)a._iO.onplay.apply(a),a._onplay_called=!0;a.setVolume(a._iO.volume,!0);a.setPan(a._iO.pan,!0);a.isHTML5?(d(),f=a._setup_html5(),a.setPosition(a._iO.position),f.play()):b.o._start(a.sID,a._iO.loops||1,i===9?a._iO.position:
+a._iO.position/1E3)}return a};this.stop=function(c){if(a.playState===1){a._onbufferchange(0);a.resetOnPosition(0);if(!a.isHTML5)a.playState=0;a.paused=!1;a._iO.onstop&&a._iO.onstop.apply(a);if(a.isHTML5){if(a._a)a.setPosition(0),a._a.pause(),a.playState=0,a._onTimer(),f(),a.unload()}else b.o._stop(a.sID,c),a._iO.serverURL&&a.unload();a.instanceCount=0;a._iO={}}return a};this.setAutoPlay=function(c){b._wD("sound "+a.sID+" turned autoplay "+(c?"on":"off"));a._iO.autoPlay=c;a.isHTML5||(b.o._setAutoPlay(a.sID,
+c),c&&!a.instanceCount&&a.readyState===1&&(a.instanceCount++,b._wD("sound "+a.sID+" incremented instance count to "+a.instanceCount)))};this.getAutoPlay=function(){return a._iO.autoPlay};this.setPosition=function(c){c===void 0&&(c=0);var d=a.isHTML5?Math.max(c,0):Math.min(a.duration||a._iO.duration,Math.max(c,0));a.position=d;c=a.position/1E3;a.resetOnPosition(a.position);a._iO.position=d;if(a.isHTML5){if(a._a)if(a._html5_canplay){if(a._a.currentTime!==c){b._wD("setPosition("+c+"): setting position");
+try{a._a.currentTime=c,(a.playState===0||a.paused)&&a._a.pause()}catch(e){b._wD("setPosition("+c+"): setting position failed: "+e.message,2)}}}else b._wD("setPosition("+c+"): delaying, sound not ready")}else c=i===9?a.position:c,a.readyState&&a.readyState!==2&&b.o._setPosition(a.sID,c,a.paused||!a.playState);a.isHTML5&&a.paused&&a._onTimer(!0);return a};this.pause=function(c){if(a.paused||a.playState===0&&a.readyState!==1)return a;b._wD("SMSound.pause()");a.paused=!0;a.isHTML5?(a._setup_html5().pause(),
+f()):(c||c===void 0)&&b.o._pause(a.sID);a._iO.onpause&&a._iO.onpause.apply(a);return a};this.resume=function(){if(!a.paused)return a;b._wD("SMSound.resume()");a.paused=!1;a.playState=1;a.isHTML5?(a._setup_html5().play(),d()):(a._iO.isMovieStar&&a.setPosition(a.position),b.o._pause(a.sID));!a._onplay_called&&a._iO.onplay?(a._iO.onplay.apply(a),a._onplay_called=!0):a._iO.onresume&&a._iO.onresume.apply(a);return a};this.togglePause=function(){b._wD("SMSound.togglePause()");if(a.playState===0)return a.play({position:i===
+9&&!a.isHTML5?a.position:a.position/1E3}),a;a.paused?a.resume():a.pause();return a};this.setPan=function(c,d){typeof c==="undefined"&&(c=0);typeof d==="undefined"&&(d=!1);a.isHTML5||b.o._setPan(a.sID,c);a._iO.pan=c;if(!d)a.pan=c,a.options.pan=c;return a};this.setVolume=function(c,d){typeof c==="undefined"&&(c=100);typeof d==="undefined"&&(d=!1);if(a.isHTML5){if(a._a)a._a.volume=Math.max(0,Math.min(1,c/100))}else b.o._setVolume(a.sID,b.muted&&!a.muted||a.muted?0:c);a._iO.volume=c;if(!d)a.volume=c,
+a.options.volume=c;return a};this.mute=function(){a.muted=!0;if(a.isHTML5){if(a._a)a._a.muted=!0}else b.o._setVolume(a.sID,0);return a};this.unmute=function(){a.muted=!1;var c=typeof a._iO.volume!=="undefined";if(a.isHTML5){if(a._a)a._a.muted=!1}else b.o._setVolume(a.sID,c?a._iO.volume:a.options.volume);return a};this.toggleMute=function(){return a.muted?a.unmute():a.mute()};this.onposition=function(b,c,d){a._onPositionItems.push({position:b,method:c,scope:typeof d!=="undefined"?d:a,fired:!1});return a};
+this.processOnPosition=function(){var c,d;c=a._onPositionItems.length;if(!c||!a.playState||a._onPositionFired>=c)return!1;for(;c--;)if(d=a._onPositionItems[c],!d.fired&&a.position>=d.position)d.method.apply(d.scope,[d.position]),d.fired=!0,b._onPositionFired++;return!0};this.resetOnPosition=function(c){var d,e;d=a._onPositionItems.length;if(!d)return!1;for(;d--;)if(e=a._onPositionItems[d],e.fired&&c<=e.position)e.fired=!1,b._onPositionFired--;return!0};d=function(){a.isHTML5&&Ca(a)};f=function(){a.isHTML5&&
+Da(a)};e=function(){a._onPositionItems=[];a._onPositionFired=0;a._hasTimer=null;a._onplay_called=!1;a._a=null;a._html5_canplay=!1;a.bytesLoaded=null;a.bytesTotal=null;a.position=null;a.duration=a._iO&&a._iO.duration?a._iO.duration:null;a.durationEstimate=null;a.failures=0;a.loaded=!1;a.playState=0;a.paused=!1;a.readyState=0;a.muted=!1;a.didBeforeFinish=!1;a.didJustBeforeFinish=!1;a.isBuffering=!1;a.instanceOptions={};a.instanceCount=0;a.peakData={left:0,right:0};a.waveformData={left:[],right:[]};
+a.eqData=[];a.eqData.left=[];a.eqData.right=[]};e();this._onTimer=function(c){var d={};if(a._hasTimer||c)return a._a&&(c||(a.playState>0||a.readyState===1)&&!a.paused)?(a.duration=a._get_html5_duration(),a.durationEstimate=a.duration,c=a._a.currentTime?a._a.currentTime*1E3:0,a._whileplaying(c,d,d,d,d),!0):(b._wD('_onTimer: Warn for "'+a.sID+'": '+(!a._a?"Could not find element. ":"")+(a.playState===0?"playState bad, 0?":"playState = "+a.playState+", OK")),!1)};this._get_html5_duration=function(){var b=
+a._a?a._a.duration*1E3:a._iO?a._iO.duration:void 0;return b&&!isNaN(b)&&b!==Infinity?b:a._iO?a._iO.duration:null};this._setup_html5=function(c){var c=t(a._iO,c),d=R?b._global_a:a._a,f=decodeURI(c.url),g=d&&d._t?d._t.instanceOptions:null;if(d){if(d._t&&g.url===c.url&&(!a._lastURL||a._lastURL===g.url))return d;b._wD("setting new URL on existing object: "+f+(a._lastURL?", old URL: "+a._lastURL:""));R&&d._t&&d._t.playState&&c.url!==g.url&&d._t.stop();e();d.src=c.url;a.url=c.url;a._lastURL=c.url;d._called_load=
+!1}else if(b._wD("creating HTML5 Audio() element with URL: "+f),d=new Audio(c.url),d._called_load=!1,R)b._global_a=d;a.isHTML5=!0;a._a=d;d._t=a;a._add_html5_events();d.loop=c.loops>1?"loop":"";c.autoLoad||c.autoPlay?(d.autobuffer="auto",d.preload="auto",a.load(),d._called_load=!0):(d.autobuffer=!1,d.preload="none");d.loop=c.loops>1?"loop":"";return d};this._add_html5_events=function(){if(a._a._added_events)return!1;var c;b._wD(l+"adding event listeners: "+a.sID);a._a._added_events=!0;for(c in x)x.hasOwnProperty(c)&&
+a._a&&a._a.addEventListener(c,x[c],!1);return!0};this._remove_html5_events=function(){var c;b._wD(l+"removing event listeners: "+a.sID);a._a._added_events=!1;for(c in x)x.hasOwnProperty(c)&&a._a&&a._a.removeEventListener(c,x[c],!1)};this._onload=function(c){c=c?!0:!1;b._wD('SMSound._onload(): "'+a.sID+'"'+(c?" loaded.":" failed to load? - "+a.url),c?1:2);!c&&!a.isHTML5&&(b.sandbox.noRemote===!0&&b._wD("SMSound._onload(): "+n("noNet"),1),b.sandbox.noLocal===!0&&b._wD("SMSound._onload(): "+n("noLocal"),
+1));a.loaded=c;a.readyState=c?3:2;a._onbufferchange(0);a._iO.onload&&a._iO.onload.apply(a,[c]);return!0};this._onbufferchange=function(c){if(a.playState===0)return!1;if(c&&a.isBuffering||!c&&!a.isBuffering)return!1;a.isBuffering=c===1;a._iO.onbufferchange&&(b._wD("SMSound._onbufferchange(): "+c),a._iO.onbufferchange.apply(a));return!0};this._onfailure=function(c,d,e){a.failures++;b._wD('SMSound._onfailure(): "'+a.sID+'" count '+a.failures);if(a._iO.onfailure&&a.failures===1)a._iO.onfailure(a,c,d,
+e);else b._wD("SMSound._onfailure(): ignoring")};this._onbeforefinish=function(){if(!a.didBeforeFinish)a.didBeforeFinish=!0,a._iO.onbeforefinish&&(b._wD('SMSound._onbeforefinish(): "'+a.sID+'"'),a._iO.onbeforefinish.apply(a))};this._onjustbeforefinish=function(){if(!a.didJustBeforeFinish)a.didJustBeforeFinish=!0,a._iO.onjustbeforefinish&&(b._wD('SMSound._onjustbeforefinish(): "'+a.sID+'"'),a._iO.onjustbeforefinish.apply(a))};this._onfinish=function(){var c=a._iO.onfinish;a._onbufferchange(0);a.resetOnPosition(0);
+a._iO.onbeforefinishcomplete&&a._iO.onbeforefinishcomplete.apply(a);a.didBeforeFinish=!1;a.didJustBeforeFinish=!1;if(a.instanceCount){a.instanceCount--;if(!a.instanceCount)a.playState=0,a.paused=!1,a.instanceCount=0,a.instanceOptions={},a._iO={},f();if((!a.instanceCount||a._iO.multiShotEvents)&&c)b._wD('SMSound._onfinish(): "'+a.sID+'"'),c.apply(a)}};this._whileloading=function(b,c,d,e){a.bytesLoaded=b;a.bytesTotal=c;a.duration=Math.floor(d);a.bufferLength=e;if(a._iO.isMovieStar)a.durationEstimate=
+a.duration;else if(a.durationEstimate=a._iO.duration?a.duration>a._iO.duration?a.duration:a._iO.duration:parseInt(a.bytesTotal/a.bytesLoaded*a.duration,10),a.durationEstimate===void 0)a.durationEstimate=a.duration;a.readyState!==3&&a._iO.whileloading&&a._iO.whileloading.apply(a)};this._whileplaying=function(c,d,e,f,g){if(isNaN(c)||c===null)return!1;a.position=c;a.processOnPosition();if(!a.isHTML5&&i>8){if(a._iO.usePeakData&&typeof d!=="undefined"&&d)a.peakData={left:d.leftPeak,right:d.rightPeak};
+if(a._iO.useWaveformData&&typeof e!=="undefined"&&e)a.waveformData={left:e.split(","),right:f.split(",")};if(a._iO.useEQData&&typeof g!=="undefined"&&g&&g.leftEQ&&(c=g.leftEQ.split(","),a.eqData=c,a.eqData.left=c,typeof g.rightEQ!=="undefined"&&g.rightEQ))a.eqData.right=g.rightEQ.split(",")}a.playState===1&&(!a.isHTML5&&b.flashVersion===8&&!a.position&&a.isBuffering&&a._onbufferchange(0),a._iO.whileplaying&&a._iO.whileplaying.apply(a),(a.loaded||!a.loaded&&a._iO.isMovieStar)&&a._iO.onbeforefinish&&
+a._iO.onbeforefinishtime&&!a.didBeforeFinish&&a.duration-a.position<=a._iO.onbeforefinishtime&&a._onbeforefinish());return!0};this._onid3=function(c,d){b._wD('SMSound._onid3(): "'+this.sID+'" ID3 data received.');var e=[],f,g;f=0;for(g=c.length;f<g;f++)e[c[f]]=d[f];a.id3=t(a.id3,e);a._iO.onid3&&a._iO.onid3.apply(a)};this._onconnect=function(c){c=c===1;b._wD('SMSound._onconnect(): "'+a.sID+'"'+(c?" connected.":" failed to connect? - "+a.url),c?1:2);if(a.connected=c)a.failures=0,m(a.sID)&&(a.getAutoPlay()?
+a.play(void 0,a.getAutoPlay()):a._iO.autoLoad&&a.load()),a._iO.onconnect&&a._iO.onconnect.apply(a,[c])};this._ondataerror=function(c){a.playState>0&&(b._wD("SMSound._ondataerror(): "+c),a._iO.ondataerror&&a._iO.ondataerror.apply(a))}};Y=function(){return g.body||g._docElement||g.getElementsByTagName("div")[0]};r=function(b){return g.getElementById(b)};t=function(c,a){var e={},f,d;for(f in c)c.hasOwnProperty(f)&&(e[f]=c[f]);f=typeof a==="undefined"?b.defaultOptions:a;for(d in f)f.hasOwnProperty(d)&&
+typeof e[d]==="undefined"&&(e[d]=f[d]);return e};p=function(){function b(a){var a=Ga.call(a),c=a.length;e?(a[1]="on"+a[1],c>3&&a.pop()):c===3&&a.push(!1);return a}function a(a,b){var c=a.shift(),g=[f[b]];if(e)c[g](a[0],a[1]);else c[g].apply(c,a)}var e=h.attachEvent,f={add:e?"attachEvent":"addEventListener",remove:e?"detachEvent":"removeEventListener"};return{add:function(){a(b(arguments),"add")},remove:function(){a(b(arguments),"remove")}}}();da=function(c){return!c.serverURL&&(c.type?Q({type:c.type}):
+Q({url:c.url})||b.html5Only)};Q=function(c){function a(a){return b.preferFlash&&u&&!b.ignoreFlash&&typeof b.flash[a]!=="undefined"&&b.flash[a]}if(!b.useHTML5Audio||!b.hasHTML5)return!1;var e=c.url||null,c=c.type||null,f=b.audioFormats,d;if(c&&b.html5[c]!=="undefined")return b.html5[c]&&!a(c);if(!A){A=[];for(d in f)f.hasOwnProperty(d)&&(A.push(d),f[d].related&&(A=A.concat(f[d].related)));A=RegExp("\\.("+A.join("|")+")(\\?.*)?$","i")}d=e?e.toLowerCase().match(A):null;if(!d||!d.length)if(c)e=c.indexOf(";"),
+d=(e!==-1?c.substr(0,e):c).substr(6);else return!1;else d=d[1];return d&&typeof b.html5[d]!=="undefined"?b.html5[d]&&!a(d):(c="audio/"+d,e=b.html5.canPlayType({type:c}),(b.html5[d]=e)&&b.html5[c]&&!a(c))};Fa=function(){function c(c){var d,e,f=!1;if(!a||typeof a.canPlayType!=="function")return!1;if(c instanceof Array){d=0;for(e=c.length;d<e&&!f;d++)if(b.html5[c[d]]||a.canPlayType(c[d]).match(b.html5Test))f=!0,b.html5[c[d]]=!0,b.flash[c[d]]=!(!b.preferFlash||!u||!c[d].match(La));return f}else return c=
+a&&typeof a.canPlayType==="function"?a.canPlayType(c):!1,!(!c||!c.match(b.html5Test))}if(!b.useHTML5Audio||typeof Audio==="undefined")return!1;var a=typeof Audio!=="undefined"?Ra?new Audio(null):new Audio:null,e,f={},d,g;d=b.audioFormats;for(e in d)if(d.hasOwnProperty(e)&&(f[e]=c(d[e].type),f["audio/"+e]=f[e],b.flash[e]=b.preferFlash&&!b.ignoreFlash&&e.match(La)?!0:!1,d[e]&&d[e].related))for(g=d[e].related.length;g--;)f["audio/"+d[e].related[g]]=f[e],b.html5[d[e].related[g]]=f[e],b.flash[d[e].related[g]]=
+f[e];f.canPlayType=a?c:null;b.html5=t(b.html5,f);return!0};W={notReady:"Not loaded yet - wait for soundManager.onload()/onready()",notOK:"Audio support is not available.",domError:"soundManager::createMovie(): appendChild/innerHTML call failed. DOM not ready or other error.",spcWmode:"soundManager::createMovie(): Removing wmode, preventing known SWF loading issue(s)",swf404:"soundManager: Verify that %s is a valid path.",tryDebug:"Try soundManager.debugFlash = true for more security details (output goes to SWF.)",
+checkSWF:"See SWF output for more debug info.",localFail:"soundManager: Non-HTTP page ("+g.location.protocol+" URL?) Review Flash player security settings for this special case:\nhttp://www.macromedia.com/support/documentation/en/flashplayer/help/settings_manager04.html\nMay need to add/allow path, eg. c:/sm2/ or /users/me/sm2/",waitFocus:"soundManager: Special case: Waiting for focus-related event..",waitImpatient:"soundManager: Getting impatient, still waiting for Flash%s...",waitForever:"soundManager: Waiting indefinitely for Flash (will recover if unblocked)...",
+needFunction:"soundManager: Function object expected for %s",badID:'Warning: Sound ID "%s" should be a string, starting with a non-numeric character',noMS:"MovieStar mode not enabled. Exiting.",currentObj:"--- soundManager._debug(): Current sound objects ---",waitEI:"soundManager::initMovie(): Waiting for ExternalInterface call from Flash..",waitOnload:"soundManager: Waiting for window.onload()",docLoaded:"soundManager: Document already loaded",onload:"soundManager::initComplete(): calling soundManager.onload()",
+onloadOK:"soundManager.onload() complete",init:"soundManager::init()",didInit:"soundManager::init(): Already called?",flashJS:"soundManager: Attempting to call Flash from JS..",noPolling:"soundManager: Polling (whileloading()/whileplaying() support) is disabled.",secNote:"Flash security note: Network/internet URLs will not load due to security restrictions. Access can be configured via Flash Player Global Security Settings Page: http://www.macromedia.com/support/documentation/en/flashplayer/help/settings_manager04.html",
+badRemove:"Warning: Failed to remove flash movie.",noPeak:"Warning: peakData features unsupported for movieStar formats",shutdown:"soundManager.disable(): Shutting down",queue:"soundManager: Queueing %s handler",smFail:"soundManager: Failed to initialise.",smError:"SMSound.load(): Exception: JS-Flash communication failed, or JS error.",fbTimeout:"No flash response, applying ."+b.swfCSS.swfTimedout+" CSS..",fbLoaded:"Flash loaded",fbHandler:"soundManager::flashBlockHandler()",manURL:"SMSound.load(): Using manually-assigned URL",
+onURL:"soundManager.load(): current URL already assigned.",badFV:'soundManager.flashVersion must be 8 or 9. "%s" is invalid. Reverting to %s.',as2loop:"Note: Setting stream:false so looping can work (flash 8 limitation)",noNSLoop:"Note: Looping not implemented for MovieStar formats",needfl9:"Note: Switching to flash 9, required for MP4 formats.",mfTimeout:"Setting flashLoadTimeout = 0 (infinite) for off-screen, mobile flash case",mfOn:"mobileFlash::enabling on-screen flash repositioning",policy:"Enabling usePolicyFile for data access"};
+n=function(){var b=Ga.call(arguments),a=b.shift(),a=W&&W[a]?W[a]:"",e,f;if(a&&b&&b.length){e=0;for(f=b.length;e<f;e++)a=a.replace("%s",b[e])}return a};aa=function(b){if(i===8&&b.loops>1&&b.stream)k("as2loop"),b.stream=!1;return b};ba=function(c,a){if(c&&!c.usePolicyFile&&(c.onid3||c.usePeakData||c.useWaveformData||c.useEQData))b._wD((a||"")+n("policy")),c.usePolicyFile=!0;return c};pa=function(c){typeof console!=="undefined"&&typeof console.warn!=="undefined"?console.warn(c):b._wD(c)};ga=function(){return!1};
+za=function(b){for(var a in b)b.hasOwnProperty(a)&&typeof b[a]==="function"&&(b[a]=ga)};$=function(c){typeof c==="undefined"&&(c=!1);if(v||c)k("smFail",2),b.disable(c)};Aa=function(c){var a=null;if(c)if(c.match(/\.swf(\?.*)?$/i)){if(a=c.substr(c.toLowerCase().lastIndexOf(".swf?")+4))return c}else c.lastIndexOf("/")!==c.length-1&&(c+="/");return(c&&c.lastIndexOf("/")!==-1?c.substr(0,c.lastIndexOf("/")+1):"./")+b.movieURL};ka=function(){if(i!==8&&i!==9)b._wD(n("badFV",i,8)),b.flashVersion=8;var c=b.debugMode||
+b.debugFlash?"_debug.swf":".swf";if(b.useHTML5Audio&&!b.html5Only&&b.audioFormats.mp4.required&&b.flashVersion<9)b._wD(n("needfl9")),b.flashVersion=9;i=b.flashVersion;b.version=b.versionNumber+(b.html5Only?" (HTML5-only mode)":i===9?" (AS3/Flash 9)":" (AS2/Flash 8)");if(i>8)b.defaultOptions=t(b.defaultOptions,b.flash9Options),b.features.buffering=!0;i>8&&b.useMovieStar?(b.defaultOptions=t(b.defaultOptions,b.movieStarOptions),b.filePatterns.flash9=RegExp("\\.(mp3|"+b.netStreamTypes.join("|")+")(\\?.*)?$",
+"i"),b.mimePattern=b.netStreamMimeTypes,b.features.movieStar=!0):(b.useMovieStar=!1,b.features.movieStar=!1);b.filePattern=b.filePatterns[i!==8?"flash9":"flash8"];b.movieURL=(i===8?"soundmanager2.swf":"soundmanager2_flash9.swf").replace(".swf",c);b.features.peakData=b.features.waveformData=b.features.eqData=i>8};ya=function(c,a){if(!b.o||!b.allowPolling)return!1;b.o._setPolling(c,a)};ma=function(){if(b.debugURLParam.test(L))b.debugMode=!0;if(r(b.debugID))return!1;var c,a,e,f;if(b.debugMode&&!r(b.debugID)&&
+(!ta||!b.useConsole||b.useConsole&&ta&&!b.consoleOnly)){c=g.createElement("div");c.id=b.debugID+"-toggle";a={position:"fixed",bottom:"0px",right:"0px",width:"1.2em",height:"1.2em",lineHeight:"1.2em",margin:"2px",textAlign:"center",border:"1px solid #999",cursor:"pointer",background:"#fff",color:"#333",zIndex:10001};c.appendChild(g.createTextNode("-"));c.onclick=Ba;c.title="Toggle SM2 debug console";if(s.match(/msie 6/i))c.style.position="absolute",c.style.cursor="hand";for(f in a)a.hasOwnProperty(f)&&
+(c.style[f]=a[f]);a=g.createElement("div");a.id=b.debugID;a.style.display=b.debugMode?"block":"none";if(b.debugMode&&!r(c.id)){try{e=Y(),e.appendChild(c)}catch(d){throw Error(n("domError")+" \n"+d.toString());}e.appendChild(a)}}};m=this.getSoundById;k=function(c,a){return c?b._wD(n(c),a):""};if(L.indexOf("sm2-debug=alert")+1&&b.debugMode)b._wD=function(b){S.alert(b)};Ba=function(){var c=r(b.debugID),a=r(b.debugID+"-toggle");if(!c)return!1;ha?(a.innerHTML="+",c.style.display="none"):(a.innerHTML="-",
+c.style.display="block");ha=!ha};q=function(b,a,e){if(typeof sm2Debugger!=="undefined")try{sm2Debugger.handleEvent(b,a,e)}catch(f){}return!0};H=function(){var c=[];b.debugMode&&c.push(b.swfCSS.sm2Debug);b.debugFlash&&c.push(b.swfCSS.flashDebug);b.useHighPerformance&&c.push(b.swfCSS.highPerf);return c.join(" ")};oa=function(){var c=n("fbHandler"),a=b.getMoviePercent(),e=b.swfCSS,f={type:"FLASHBLOCK"};if(b.html5Only)return!1;if(b.ok()){if(b.didFlashBlock&&b._wD(c+": Unblocked"),b.oMC)b.oMC.className=
+[H(),e.swfDefault,e.swfLoaded+(b.didFlashBlock?" "+e.swfUnblocked:"")].join(" ")}else{if(w)b.oMC.className=H()+" "+e.swfDefault+" "+(a===null?e.swfTimedout:e.swfError),b._wD(c+": "+n("fbTimeout")+(a?" ("+n("fbLoaded")+")":""));b.didFlashBlock=!0;D({type:"ontimeout",ignoreInit:!0,error:f});G(f)}};ja=function(b,a,e){typeof z[b]==="undefined"&&(z[b]=[]);z[b].push({method:a,scope:e||null,fired:!1})};D=function(c){c||(c={type:"onready"});if(!j&&c&&!c.ignoreInit)return!1;if(c.type==="ontimeout"&&b.ok())return!1;
+var a={success:c&&c.ignoreInit?b.ok():!v},e=c&&c.type?z[c.type]||[]:[],f=[],d,g=[a],k=w&&b.useFlashBlock&&!b.ok();if(c.error)g[0].error=c.error;a=0;for(d=e.length;a<d;a++)e[a].fired!==!0&&f.push(e[a]);if(f.length){b._wD("soundManager: Firing "+f.length+" "+c.type+"() item"+(f.length===1?"":"s"));a=0;for(d=f.length;a<d;a++)if(f[a].scope?f[a].method.apply(f[a].scope,g):f[a].method.apply(this,g),!k)f[a].fired=!0}return!0};E=function(){h.setTimeout(function(){b.useFlashBlock&&oa();D();b.onload instanceof
+Function&&(k("onload",1),b.onload.apply(h),k("onloadOK",1));b.waitForWindowLoad&&p.add(h,"load",E)},1)};ea=function(){if(u!==void 0)return u;var b=!1,a=navigator,e=a.plugins,f,d=h.ActiveXObject;if(e&&e.length)(a=a.mimeTypes)&&a["application/x-shockwave-flash"]&&a["application/x-shockwave-flash"].enabledPlugin&&a["application/x-shockwave-flash"].enabledPlugin.description&&(b=!0);else if(typeof d!=="undefined"){try{f=new d("ShockwaveFlash.ShockwaveFlash")}catch(g){}b=!!f}return u=b};Ea=function(){var c,
+a;if(s.match(/iphone os (1|2|3_0|3_1)/i)){b.hasHTML5=!1;b.html5Only=!0;if(b.oMC)b.oMC.style.display="none";return!1}if(b.useHTML5Audio){if(!b.html5||!b.html5.canPlayType)return b._wD("SoundManager: No HTML5 Audio() support detected."),b.hasHTML5=!1,!0;else b.hasHTML5=!0;if(sa&&(b._wD("soundManager::Note: Buggy HTML5 Audio in Safari on this OS X release, see https://bugs.webkit.org/show_bug.cgi?id=32159 - "+(!u?" would use flash fallback for MP3/MP4, but none detected.":"will use flash fallback for MP3/MP4, if available"),
+1),ea()))return!0}else return!0;for(a in b.audioFormats)if(b.audioFormats.hasOwnProperty(a)&&(b.audioFormats[a].required&&!b.html5.canPlayType(b.audioFormats[a].type)||b.flash[a]||b.flash[b.audioFormats[a].type]))c=!0;b.ignoreFlash&&(c=!1);b.html5Only=b.hasHTML5&&b.useHTML5Audio&&!c;return!b.html5Only};Ca=function(b){if(!b._hasTimer)b._hasTimer=!0};Da=function(b){if(b._hasTimer)b._hasTimer=!1};G=function(c){c=typeof c!=="undefined"?c:{};b.onerror instanceof Function&&b.onerror.apply(h,[{type:typeof c.type!==
+"undefined"?c.type:null}]);typeof c.fatal!=="undefined"&&c.fatal&&b.disable()};Ha=function(){if(!sa||!ea())return!1;var c=b.audioFormats,a,e;for(e in c)if(c.hasOwnProperty(e)&&(e==="mp3"||e==="mp4"))if(b._wD("soundManager: Using flash fallback for "+e+" format"),b.html5[e]=!1,c[e]&&c[e].related)for(a=c[e].related.length;a--;)b.html5[c[e].related[a]]=!1};this._setSandboxType=function(c){var a=b.sandbox;a.type=c;a.description=a.types[typeof a.types[c]!=="undefined"?c:"unknown"];b._wD("Flash security sandbox type: "+
+a.type);if(a.type==="localWithFile")a.noRemote=!0,a.noLocal=!1,k("secNote",2);else if(a.type==="localWithNetwork")a.noRemote=!1,a.noLocal=!0;else if(a.type==="localTrusted")a.noRemote=!1,a.noLocal=!1};this._externalInterfaceOK=function(c){if(b.swfLoaded)return!1;var a=(new Date).getTime();b._wD("soundManager::externalInterfaceOK()"+(c?" (~"+(a-c)+" ms)":""));q("swf",!0);q("flashtojs",!0);b.swfLoaded=!0;J=!1;sa&&Ha();y?setTimeout(U,100):U()};Z=function(c,a){function e(){b._wD("-- SoundManager 2 "+
+b.version+(!b.html5Only&&b.useHTML5Audio?b.hasHTML5?" + HTML5 audio":", no HTML5 audio support":"")+(!b.html5Only?(b.useMovieStar?", MovieStar mode":"")+(b.useHighPerformance?", high performance mode, ":", ")+((b.flashPollingInterval?"custom ("+b.flashPollingInterval+"ms)":b.useFastPolling?"fast":"normal")+" polling")+(b.wmode?", wmode: "+b.wmode:"")+(b.debugFlash?", flash debug mode":"")+(b.useFlashBlock?", flashBlock mode":""):"")+" --",1)}function f(a,b){return'<param name="'+a+'" value="'+b+'" />'}
+if(M&&N)return!1;if(b.html5Only)return ka(),e(),b.oMC=r(b.movieID),U(),N=M=!0,!1;var d=a||b.url,l=b.altURL||d,h;h=Y();var i,o,j=H(),m,p=null,p=(p=g.getElementsByTagName("html")[0])&&p.dir&&p.dir.match(/rtl/i),c=typeof c==="undefined"?b.id:c;ka();b.url=Aa(K?d:l);a=b.url;b.wmode=!b.wmode&&b.useHighPerformance&&!b.useMovieStar?"transparent":b.wmode;if(b.wmode!==null&&(s.match(/msie 8/i)||!y&&!b.useHighPerformance)&&navigator.platform.match(/win32|win64/i))b.specialWmodeCase=!0,k("spcWmode"),b.wmode=
+null;h={name:c,id:c,src:a,width:"auto",height:"auto",quality:"high",allowScriptAccess:b.allowScriptAccess,bgcolor:b.bgColor,pluginspage:Ma+"//www.macromedia.com/go/getflashplayer",title:"JS/Flash audio component (SoundManager 2)",type:"application/x-shockwave-flash",wmode:b.wmode,hasPriority:"true"};if(b.debugFlash)h.FlashVars="debug=1";b.wmode||delete h.wmode;if(y)d=g.createElement("div"),o=['<object id="'+c+'" data="'+a+'" type="'+h.type+'" title="'+h.title+'" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="'+
+Ma+'//download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" width="'+h.width+'" height="'+h.height+'">',f("movie",a),f("AllowScriptAccess",b.allowScriptAccess),f("quality",h.quality),b.wmode?f("wmode",b.wmode):"",f("bgcolor",b.bgColor),f("hasPriority","true"),b.debugFlash?f("FlashVars",h.FlashVars):"","</object>"].join("");else for(i in d=g.createElement("embed"),h)h.hasOwnProperty(i)&&d.setAttribute(i,h[i]);ma();j=H();if(h=Y())if(b.oMC=r(b.movieID)||g.createElement("div"),
+b.oMC.id){m=b.oMC.className;b.oMC.className=(m?m+" ":b.swfCSS.swfDefault)+(j?" "+j:"");b.oMC.appendChild(d);if(y)i=b.oMC.appendChild(g.createElement("div")),i.className=b.swfCSS.swfBox,i.innerHTML=o;N=!0}else{b.oMC.id=b.movieID;b.oMC.className=b.swfCSS.swfDefault+" "+j;i=j=null;if(!b.useFlashBlock)if(b.useHighPerformance)j={position:"fixed",width:"8px",height:"8px",bottom:"0px",left:"0px",overflow:"hidden"};else if(j={position:"absolute",width:"6px",height:"6px",top:"-9999px",left:"-9999px"},p)j.left=
+Math.abs(parseInt(j.left,10))+"px";if(Qa)b.oMC.style.zIndex=1E4;if(!b.debugFlash)for(m in j)j.hasOwnProperty(m)&&(b.oMC.style[m]=j[m]);try{y||b.oMC.appendChild(d);h.appendChild(b.oMC);if(y)i=b.oMC.appendChild(g.createElement("div")),i.className=b.swfCSS.swfBox,i.innerHTML=o;N=!0}catch(q){throw Error(n("domError")+" \n"+q.toString());}}M=!0;e();b._wD("soundManager::createMovie(): Trying to load "+a+(!K&&b.altURL?" (alternate URL)":""),1);return!0};X=function(){if(b.html5Only)return Z(),!1;if(b.o)return!1;
+b.o=b.getMovie(b.id);if(!b.o)P?(y?b.oMC.innerHTML=na:b.oMC.appendChild(P),P=null,M=!0):Z(b.id,b.url),b.o=b.getMovie(b.id);b.o&&k("waitEI");b.oninitmovie instanceof Function&&setTimeout(b.oninitmovie,1);return!0};V=function(){setTimeout(xa,1E3)};xa=function(){if(ca)return!1;ca=!0;p.remove(h,"load",V);if(J&&!ua)return k("waitFocus"),!1;var c;j||(c=b.getMoviePercent(),b._wD(n("waitImpatient",c===100?" (SWF loaded)":c>0?" (SWF "+c+"% loaded)":"")));setTimeout(function(){c=b.getMoviePercent();j||(b._wD("soundManager: No Flash response within expected time.\nLikely causes: "+
+(c===0?"Loading "+b.movieURL+" may have failed (and/or Flash "+i+"+ not present?), ":"")+"Flash blocked or JS-Flash security error."+(b.debugFlash?" "+n("checkSWF"):""),2),!K&&c&&(k("localFail",2),b.debugFlash||k("tryDebug",2)),c===0&&b._wD(n("swf404",b.url)),q("flashtojs",!1,": Timed out"+K?" (Check flash security or flash blockers)":" (No plugin/missing SWF?)"));!j&&Ka&&(c===null?b.useFlashBlock||b.flashLoadTimeout===0?(b.useFlashBlock&&oa(),k("waitForever")):$(!0):b.flashLoadTimeout===0?k("waitForever"):
+$(!0))},b.flashLoadTimeout)};C=function(){function c(){p.remove(h,"focus",C);p.remove(h,"load",C)}if(ua||!J)return c(),!0;ua=Ka=!0;b._wD("soundManager::handleFocus()");I&&J&&p.remove(h,"mousemove",C);ca=!1;c();return!0};O=function(c){if(j)return!1;if(b.html5Only)return b._wD("-- SoundManager 2: loaded --"),j=!0,E(),q("onload",!0),!0;var a;if(!b.useFlashBlock||!b.flashLoadTimeout||b.getMoviePercent())j=!0,v&&(a={type:!u&&w?"NO_FLASH":"INIT_TIMEOUT"});b._wD("-- SoundManager 2 "+(v?"failed to load":
+"loaded")+" ("+(v?"security/load error":"OK")+") --",1);if(v||c){if(b.useFlashBlock&&b.oMC)b.oMC.className=H()+" "+(b.getMoviePercent()===null?b.swfCSS.swfTimedout:b.swfCSS.swfError);D({type:"ontimeout",error:a});q("onload",!1);G(a);return!1}else q("onload",!0);p.add(h,"unload",ga);if(b.waitForWindowLoad&&!ia)return k("waitOnload"),p.add(h,"load",E),!1;else b.waitForWindowLoad&&ia&&k("docLoaded"),E();return!0};Ia=function(){var c,a=[];if(b.useHTML5Audio&&b.hasHTML5){for(c in b.audioFormats)b.audioFormats.hasOwnProperty(c)&&
+a.push(c+": "+b.html5[c]+(!b.html5[c]&&u&&b.flash[c]?" (using flash)":b.preferFlash&&b.flash[c]&&u?" (preferring flash)":!b.html5[c]?" ("+(b.audioFormats[c].required?"required, ":"")+"and no flash support)":""));b._wD("-- SoundManager 2: HTML5 support tests ("+b.html5Test+"): "+a.join(", ")+" --",1)}};U=function(){k("init");if(j)return k("didInit"),!1;if(b.html5Only){if(!j)p.remove(h,"load",b.beginDelayedInit),b.enabled=!0,O();return!0}X();try{k("flashJS"),b.o._externalInterfaceTest(!1),b.allowPolling?
+ya(!0,b.flashPollingInterval||(b.useFastPolling?10:50)):k("noPolling",1),b.debugMode||b.o._disableDebug(),b.enabled=!0,q("jstoflash",!0)}catch(c){return b._wD("js/flash exception: "+c.toString()),q("jstoflash",!1),G({type:"JS_TO_FLASH_EXCEPTION",fatal:!0}),$(!0),O(),!1}O();p.remove(h,"load",b.beginDelayedInit);return!0};F=function(){if(la)return!1;la=!0;ma();(function(){var c=L.toLowerCase(),a=null,a=null,e=typeof console!=="undefined"&&typeof console.log!=="undefined";if(c.indexOf("sm2-usehtml5audio=")!==
+-1)a=c.charAt(c.indexOf("sm2-usehtml5audio=")+18)==="1",e&&console.log((a?"Enabling ":"Disabling ")+"useHTML5Audio via URL parameter"),b.useHTML5Audio=a;if(c.indexOf("sm2-preferflash=")!==-1)a=c.charAt(c.indexOf("sm2-preferflash=")+16)==="1",e&&console.log((a?"Enabling ":"Disabling ")+"preferFlash via URL parameter"),b.preferFlash=a})();if(!u&&b.hasHTML5)b._wD("SoundManager: No Flash detected"+(!b.useHTML5Audio?", enabling HTML5.":". Trying HTML5-only mode.")),b.useHTML5Audio=!0,b.preferFlash=!1;
+Fa();b.html5.usingFlash=Ea();w=b.html5.usingFlash;Ia();if(!u&&w)b._wD("SoundManager: Fatal error: Flash is needed to play some required formats, but is not available."),b.flashLoadTimeout=1;g.removeEventListener&&g.removeEventListener("DOMContentLoaded",F,!1);X();return!0};ra=function(){g.readyState==="complete"&&(F(),g.detachEvent("onreadystatechange",ra));return!0};ea();p.add(h,"focus",C);p.add(h,"load",C);p.add(h,"load",V);I&&J&&p.add(h,"mousemove",C);g.addEventListener?g.addEventListener("DOMContentLoaded",
+F,!1):g.attachEvent?g.attachEvent("onreadystatechange",ra):(q("onload",!1),G({type:"NO_DOM2_EVENTS",fatal:!0}));g.readyState==="complete"&&setTimeout(F,100)}var fa=null;if(typeof SM2_DEFER==="undefined"||!SM2_DEFER)fa=new T;S.SoundManager=T;S.soundManager=fa})(window);
Index: /gs3-extensions/audioDB/trunk/src/interface/script/soundmanager2-nodebug-jsmin.js
===================================================================
--- /gs3-extensions/audioDB/trunk/src/interface/script/soundmanager2-nodebug-jsmin.js	(revision 26291)
+++ /gs3-extensions/audioDB/trunk/src/interface/script/soundmanager2-nodebug-jsmin.js	(revision 26291)
@@ -0,0 +1,76 @@
+/** @license
+
+ SoundManager 2: JavaScript Sound for the Web
+ ----------------------------------------------
+ http://schillmania.com/projects/soundmanager2/
+
+ Copyright (c) 2007, Scott Schiller. All rights reserved.
+ Code provided under the BSD License:
+ http://schillmania.com/projects/soundmanager2/license.txt
+
+ V2.97a.20110801
+*/
+(function(Z){function M(M,Y){function l(b){return function(a){return!this._t||!this._t._a?null:b.call(this,a)}}this.flashVersion=8;this.debugFlash=this.debugMode=!1;this.useConsole=!0;this.waitForWindowLoad=this.consoleOnly=!1;this.nullURL="about:blank";this.allowPolling=!0;this.useFastPolling=!1;this.useMovieStar=!0;this.bgColor="#ffffff";this.useHighPerformance=!1;this.flashPollingInterval=null;this.flashLoadTimeout=1E3;this.wmode=null;this.allowScriptAccess="always";this.useFlashBlock=!1;this.useHTML5Audio=
+!0;this.html5Test=/^(probably|maybe)$/i;this.preferFlash=!0;this.audioFormats={mp3:{type:['audio/mpeg; codecs="mp3"',"audio/mpeg","audio/mp3","audio/MPA","audio/mpa-robust"],required:!0},mp4:{related:["aac","m4a"],type:['audio/mp4; codecs="mp4a.40.2"',"audio/aac","audio/x-m4a","audio/MP4A-LATM","audio/mpeg4-generic"],required:!1},ogg:{type:["audio/ogg; codecs=vorbis"],required:!1},wav:{type:['audio/wav; codecs="1"',"audio/wav","audio/wave","audio/x-wav"],required:!1}};this.defaultOptions={autoLoad:!1,
+stream:!0,autoPlay:!1,loops:1,onid3:null,onload:null,whileloading:null,onplay:null,onpause:null,onresume:null,whileplaying:null,onstop:null,onfailure:null,onfinish:null,onbeforefinish:null,onbeforefinishtime:5E3,onbeforefinishcomplete:null,onjustbeforefinish:null,onjustbeforefinishtime:200,multiShot:!0,multiShotEvents:!1,position:null,pan:0,type:null,usePolicyFile:!1,volume:100};this.flash9Options={isMovieStar:null,usePeakData:!1,useWaveformData:!1,useEQData:!1,onbufferchange:null,ondataerror:null};
+this.movieStarOptions={bufferTime:3,serverURL:null,onconnect:null,duration:null};this.version=null;this.versionNumber="V2.97a.20110801";this.movieURL=null;this.url=M||null;this.altURL=null;this.enabled=this.swfLoaded=!1;this.o=null;this.movieID="sm2-container";this.id=Y||"sm2movie";this.swfCSS={swfBox:"sm2-object-box",swfDefault:"movieContainer",swfError:"swf_error",swfTimedout:"swf_timedout",swfLoaded:"swf_loaded",swfUnblocked:"swf_unblocked",sm2Debug:"sm2_debug",highPerf:"high_performance",flashDebug:"flash_debug"};
+this.oMC=null;this.sounds={};this.soundIDs=[];this.muted=!1;this.debugID="soundmanager-debug";this.debugURLParam=/([#?&])debug=1/i;this.didFlashBlock=this.specialWmodeCase=!1;this.filePattern=null;this.filePatterns={flash8:/\.mp3(\?.*)?$/i,flash9:/\.mp3(\?.*)?$/i};this.baseMimeTypes=/^\s*audio\/(?:x-)?(?:mp(?:eg|3))\s*(?:$|;)/i;this.netStreamMimeTypes=/^\s*audio\/(?:x-)?(?:mp(?:eg|3))\s*(?:$|;)/i;this.netStreamTypes=["aac","flv","mov","mp4","m4v","f4v","m4a","mp4v","3gp","3g2"];this.netStreamPattern=
+RegExp("\\.("+this.netStreamTypes.join("|")+")(\\?.*)?$","i");this.mimePattern=this.baseMimeTypes;this.features={buffering:!1,peakData:!1,waveformData:!1,eqData:!1,movieStar:!1};this.sandbox={};this.hasHTML5=typeof Audio!=="undefined"&&typeof(new Audio).canPlayType!=="undefined";this.html5={usingFlash:null};this.flash={};this.ignoreFlash=this.html5Only=!1;var pa,b=this,F,o=navigator.userAgent,h=Z,$=h.location.href.toString(),i=this.flashVersion,g=document,aa,N,t=[],G=!1,H=!1,m=!1,u=!1,qa=!1,I,n,ba,
+y,z,O,ra,ca,w,P,A,da,ea,Q,B,sa,fa,ta,R,ua,J=null,ga=null,x,ha,C,S,T,ia,j,U=!1,ja=!1,va,wa,q=null,xa,V,K,v,ka,ya,k,Fa=Array.prototype.slice,L=!1,p,W,za,r,Aa,Ba=o.match(/(ipad|iphone|ipod)/i),Ga=o.match(/(mobile|pre\/|xoom)/i)||Ba,s=o.match(/msie/i),Ha=o.match(/webkit/i),D=o.match(/safari/i)&&!o.match(/chrome/i),Ia=o.match(/opera/i),la=!$.match(/usehtml5audio/i)&&!$.match(/sm2\-ignorebadua/i)&&D&&o.match(/OS X 10_6_([3-7])/i),ma=typeof g.hasFocus!=="undefined"?g.hasFocus():null,E=D&&typeof g.hasFocus===
+"undefined",Ca=!E,Da=/(mp3|mp4|mpa)/i,na=g.location?g.location.protocol.match(/http/i):null,Ea=!na?"http:":"";this.useAltURL=!na;this._global_a=null;if(Ga&&(b.useHTML5Audio=!0,b.preferFlash=!1,Ba))L=b.ignoreFlash=!0;this.supported=this.ok=function(){return q?m&&!u:b.useHTML5Audio&&b.hasHTML5};this.getMovie=function(b){return s?h[b]:D?F(b)||g[b]:F(b)};this.createSound=function(c){function a(){e=S(e);b.sounds[d.id]=new pa(d);b.soundIDs.push(d.id);return b.sounds[d.id]}var e=null,f=null,d=null;if(!m||
+!b.ok())return ia("soundManager.createSound(): "+x(!m?"notReady":"notOK")),!1;arguments.length===2&&(c={id:arguments[0],url:arguments[1]});d=e=n(c);if(j(d.id,!0))return b.sounds[d.id];if(V(d))f=a(),f._setup_html5(d);else{if(i>8&&b.useMovieStar){if(d.isMovieStar===null)d.isMovieStar=d.serverURL||d.type&&d.type.match(b.netStreamPattern)||d.url.match(b.netStreamPattern)?!0:!1;if(d.isMovieStar&&d.usePeakData)d.usePeakData=!1}d=T(d,"soundManager.createSound(): ");f=a();if(i===8)b.o._createSound(d.id,d.onjustbeforefinishtime,
+d.loops||1,d.usePolicyFile);else if(b.o._createSound(d.id,d.url,d.onjustbeforefinishtime,d.usePeakData,d.useWaveformData,d.useEQData,d.isMovieStar,d.isMovieStar?d.bufferTime:!1,d.loops||1,d.serverURL,d.duration||null,d.autoPlay,!0,d.autoLoad,d.usePolicyFile),!d.serverURL)f.connected=!0,d.onconnect&&d.onconnect.apply(f);!d.serverURL&&(d.autoLoad||d.autoPlay)&&f.load(d)}!d.serverURL&&d.autoPlay&&f.play();return f};this.destroySound=function(c,a){if(!j(c))return!1;var e=b.sounds[c],f;e._iO={};e.stop();
+e.unload();for(f=0;f<b.soundIDs.length;f++)if(b.soundIDs[f]===c){b.soundIDs.splice(f,1);break}a||e.destruct(!0);delete b.sounds[c];return!0};this.load=function(c,a){return!j(c)?!1:b.sounds[c].load(a)};this.unload=function(c){return!j(c)?!1:b.sounds[c].unload()};this.start=this.play=function(c,a){return!m||!b.ok()?(ia("soundManager.play(): "+x(!m?"notReady":"notOK")),!1):!j(c)?(a instanceof Object||(a={url:a}),a&&a.url?(a.id=c,b.createSound(a).play()):!1):b.sounds[c].play(a)};this.setPosition=function(c,
+a){return!j(c)?!1:b.sounds[c].setPosition(a)};this.stop=function(c){return!j(c)?!1:b.sounds[c].stop()};this.stopAll=function(){for(var c in b.sounds)b.sounds.hasOwnProperty(c)&&b.sounds[c].stop()};this.pause=function(c){return!j(c)?!1:b.sounds[c].pause()};this.pauseAll=function(){var c;for(c=b.soundIDs.length;c--;)b.sounds[b.soundIDs[c]].pause()};this.resume=function(c){return!j(c)?!1:b.sounds[c].resume()};this.resumeAll=function(){var c;for(c=b.soundIDs.length;c--;)b.sounds[b.soundIDs[c]].resume()};
+this.togglePause=function(c){return!j(c)?!1:b.sounds[c].togglePause()};this.setPan=function(c,a){return!j(c)?!1:b.sounds[c].setPan(a)};this.setVolume=function(c,a){return!j(c)?!1:b.sounds[c].setVolume(a)};this.mute=function(c){var a=0;typeof c!=="string"&&(c=null);if(c)return!j(c)?!1:b.sounds[c].mute();else{for(a=b.soundIDs.length;a--;)b.sounds[b.soundIDs[a]].mute();b.muted=!0}return!0};this.muteAll=function(){b.mute()};this.unmute=function(c){typeof c!=="string"&&(c=null);if(c)return!j(c)?!1:b.sounds[c].unmute();
+else{for(c=b.soundIDs.length;c--;)b.sounds[b.soundIDs[c]].unmute();b.muted=!1}return!0};this.unmuteAll=function(){b.unmute()};this.toggleMute=function(c){return!j(c)?!1:b.sounds[c].toggleMute()};this.getMemoryUse=function(){var c=0;b.o&&i!==8&&(c=parseInt(b.o._getMemoryUse(),10));return c};this.disable=function(c){var a;typeof c==="undefined"&&(c=!1);if(u)return!1;u=!0;for(a=b.soundIDs.length;a--;)ta(b.sounds[b.soundIDs[a]]);I(c);k.remove(h,"load",z);return!0};this.canPlayMIME=function(c){var a;b.hasHTML5&&
+(a=K({type:c}));return!q||a?a:c?c.match(b.mimePattern)?!0:!1:null};this.canPlayURL=function(c){var a;b.hasHTML5&&(a=K({url:c}));return!q||a?a:c?c.match(b.filePattern)?!0:!1:null};this.canPlayLink=function(c){return typeof c.type!=="undefined"&&c.type&&b.canPlayMIME(c.type)?!0:b.canPlayURL(c.href)};this.getSoundById=function(c){if(!c)throw Error("soundManager.getSoundById(): sID is null/undefined");return b.sounds[c]};this.onready=function(b,a){if(b&&b instanceof Function)return a||(a=h),ba("onready",
+b,a),y(),!0;else throw x("needFunction","onready");};this.ontimeout=function(b,a){if(b&&b instanceof Function)return a||(a=h),ba("ontimeout",b,a),y({type:"ontimeout"}),!0;else throw x("needFunction","ontimeout");};this._wD=this._writeDebug=function(){return!0};this._debug=function(){};this.reboot=function(){var c,a;for(c=b.soundIDs.length;c--;)b.sounds[b.soundIDs[c]].destruct();try{if(s)ga=b.o.innerHTML;J=b.o.parentNode.removeChild(b.o)}catch(e){}ga=J=q=null;b.enabled=da=m=U=ja=G=H=u=b.swfLoaded=
+!1;b.soundIDs=b.sounds=[];b.o=null;for(c in t)if(t.hasOwnProperty(c))for(a=t[c].length;a--;)t[c][a].fired=!1;h.setTimeout(b.beginDelayedInit,20)};this.getMoviePercent=function(){return b.o&&typeof b.o.PercentLoaded!=="undefined"?b.o.PercentLoaded():null};this.beginDelayedInit=function(){qa=!0;A();setTimeout(function(){if(ja)return!1;Q();P();return ja=!0},20);O()};this.destruct=function(){b.disable(!0)};r={abort:l(function(){}),canplay:l(function(){if(this._t._html5_canplay)return!0;this._t._html5_canplay=
+!0;this._t._onbufferchange(0);var b=!isNaN(this._t.position)?this._t.position/1E3:null;if(this._t.position&&this.currentTime!==b)try{this.currentTime=b}catch(a){}}),load:l(function(){this._t.loaded||(this._t._onbufferchange(0),this._t._whileloading(this._t.bytesTotal,this._t.bytesTotal,this._t._get_html5_duration()),this._t._onload(!0))}),emptied:l(function(){}),ended:l(function(){this._t._onfinish()}),error:l(function(){this._t._onload(!1)}),loadeddata:l(function(){var b=this._t,a=b.bytesTotal||
+1;if(!b._loaded&&!D)b.duration=b._get_html5_duration(),b._whileloading(a,a,b._get_html5_duration()),b._onload(!0)}),loadedmetadata:l(function(){}),loadstart:l(function(){this._t._onbufferchange(1)}),play:l(function(){this._t._onbufferchange(0)}),playing:l(function(){this._t._onbufferchange(0)}),progress:l(function(b){if(this._t.loaded)return!1;var a,e=0,f=b.type==="progress",d=b.target.buffered;a=b.loaded||0;var oa=b.total||1;if(d&&d.length){for(a=d.length;a--;)e=d.end(a)-d.start(a);a=e/b.target.duration;
+f&&isNaN(a)}isNaN(a)||(this._t._onbufferchange(0),this._t._whileloading(a,oa,this._t._get_html5_duration()),a&&oa&&a===oa&&r.load.call(this,b))}),ratechange:l(function(){}),suspend:l(function(b){r.progress.call(this,b)}),stalled:l(function(){}),timeupdate:l(function(){this._t._onTimer()}),waiting:l(function(){this._t._onbufferchange(1)})};pa=function(c){var a=this,e,f,d;this.sID=c.id;this.url=c.url;this._iO=this.instanceOptions=this.options=n(c);this.pan=this.options.pan;this.volume=this.options.volume;
+this._lastURL=null;this.isHTML5=!1;this._a=null;this.id3={};this._debug=function(){};this.load=function(c){var d=null;if(typeof c!=="undefined")a._iO=n(c,a.options),a.instanceOptions=a._iO;else if(c=a.options,a._iO=c,a.instanceOptions=a._iO,a._lastURL&&a._lastURL!==a.url)a._iO.url=a.url,a.url=null;if(!a._iO.url)a._iO.url=a.url;if(a._iO.url===a.url&&a.readyState!==0&&a.readyState!==2)return a;a._lastURL=a.url;a.loaded=!1;a.readyState=1;a.playState=0;if(V(a._iO)){if(d=a._setup_html5(a._iO),!d._called_load)a._html5_canplay=
+!1,d.load(),d._called_load=!0,a._iO.autoPlay&&a.play()}else try{a.isHTML5=!1,a._iO=T(S(a._iO)),i===8?b.o._load(a.sID,a._iO.url,a._iO.stream,a._iO.autoPlay,a._iO.whileloading?1:0,a._iO.loops||1,a._iO.usePolicyFile):b.o._load(a.sID,a._iO.url,a._iO.stream?!0:!1,a._iO.autoPlay?!0:!1,a._iO.loops||1,a._iO.autoLoad?!0:!1,a._iO.usePolicyFile)}catch(e){B({type:"SMSOUND_LOAD_JS_EXCEPTION",fatal:!0})}return a};this.unload=function(){if(a.readyState!==0){if(a.isHTML5){if(f(),a._a)a._a.pause(),a._a.src=""}else i===
+8?b.o._unload(a.sID,b.nullURL):b.o._unload(a.sID);e()}return a};this.destruct=function(c){if(a.isHTML5){if(f(),a._a)a._a.pause(),a._a.src="",L||a._remove_html5_events(),a._a._t=null,a._a=null}else a._iO.onfailure=null,b.o._destroySound(a.sID);c||b.destroySound(a.sID,!0)};this.start=this.play=function(c,X){var e,X=X===void 0?!0:X;c||(c={});a._iO=n(c,a._iO);a._iO=n(a._iO,a.options);a.instanceOptions=a._iO;if(a._iO.serverURL&&!a.connected)return a.getAutoPlay()||a.setAutoPlay(!0),a;V(a._iO)&&(a._setup_html5(a._iO),
+d());if(a.playState===1&&!a.paused&&(e=a._iO.multiShot,!e))return a;if(!a.loaded)if(a.readyState===0){if(!a.isHTML5)a._iO.autoPlay=!0;a.load(a._iO)}else if(a.readyState===2)return a;if(!a.isHTML5&&i===9&&a.position>0&&a.position===a.duration)a._iO.position=0;if(a.paused&&a.position&&a.position>0)a.resume();else{a.playState=1;a.paused=!1;(!a.instanceCount||a._iO.multiShotEvents||!a.isHTML5&&i>8&&!a.getAutoPlay())&&a.instanceCount++;a.position=typeof a._iO.position!=="undefined"&&!isNaN(a._iO.position)?
+a._iO.position:0;if(!a.isHTML5)a._iO=T(S(a._iO));if(a._iO.onplay&&X)a._iO.onplay.apply(a),a._onplay_called=!0;a.setVolume(a._iO.volume,!0);a.setPan(a._iO.pan,!0);a.isHTML5?(d(),e=a._setup_html5(),a.setPosition(a._iO.position),e.play()):b.o._start(a.sID,a._iO.loops||1,i===9?a._iO.position:a._iO.position/1E3)}return a};this.stop=function(c){if(a.playState===1){a._onbufferchange(0);a.resetOnPosition(0);if(!a.isHTML5)a.playState=0;a.paused=!1;a._iO.onstop&&a._iO.onstop.apply(a);if(a.isHTML5){if(a._a)a.setPosition(0),
+a._a.pause(),a.playState=0,a._onTimer(),f(),a.unload()}else b.o._stop(a.sID,c),a._iO.serverURL&&a.unload();a.instanceCount=0;a._iO={}}return a};this.setAutoPlay=function(c){a._iO.autoPlay=c;a.isHTML5||(b.o._setAutoPlay(a.sID,c),c&&!a.instanceCount&&a.readyState===1&&a.instanceCount++)};this.getAutoPlay=function(){return a._iO.autoPlay};this.setPosition=function(c){c===void 0&&(c=0);var d=a.isHTML5?Math.max(c,0):Math.min(a.duration||a._iO.duration,Math.max(c,0));a.position=d;c=a.position/1E3;a.resetOnPosition(a.position);
+a._iO.position=d;if(a.isHTML5){if(a._a&&a._html5_canplay&&a._a.currentTime!==c)try{a._a.currentTime=c,(a.playState===0||a.paused)&&a._a.pause()}catch(e){}}else c=i===9?a.position:c,a.readyState&&a.readyState!==2&&b.o._setPosition(a.sID,c,a.paused||!a.playState);a.isHTML5&&a.paused&&a._onTimer(!0);return a};this.pause=function(c){if(a.paused||a.playState===0&&a.readyState!==1)return a;a.paused=!0;a.isHTML5?(a._setup_html5().pause(),f()):(c||c===void 0)&&b.o._pause(a.sID);a._iO.onpause&&a._iO.onpause.apply(a);
+return a};this.resume=function(){if(!a.paused)return a;a.paused=!1;a.playState=1;a.isHTML5?(a._setup_html5().play(),d()):(a._iO.isMovieStar&&a.setPosition(a.position),b.o._pause(a.sID));!a._onplay_called&&a._iO.onplay?(a._iO.onplay.apply(a),a._onplay_called=!0):a._iO.onresume&&a._iO.onresume.apply(a);return a};this.togglePause=function(){if(a.playState===0)return a.play({position:i===9&&!a.isHTML5?a.position:a.position/1E3}),a;a.paused?a.resume():a.pause();return a};this.setPan=function(c,d){typeof c===
+"undefined"&&(c=0);typeof d==="undefined"&&(d=!1);a.isHTML5||b.o._setPan(a.sID,c);a._iO.pan=c;if(!d)a.pan=c,a.options.pan=c;return a};this.setVolume=function(c,d){typeof c==="undefined"&&(c=100);typeof d==="undefined"&&(d=!1);if(a.isHTML5){if(a._a)a._a.volume=Math.max(0,Math.min(1,c/100))}else b.o._setVolume(a.sID,b.muted&&!a.muted||a.muted?0:c);a._iO.volume=c;if(!d)a.volume=c,a.options.volume=c;return a};this.mute=function(){a.muted=!0;if(a.isHTML5){if(a._a)a._a.muted=!0}else b.o._setVolume(a.sID,
+0);return a};this.unmute=function(){a.muted=!1;var c=typeof a._iO.volume!=="undefined";if(a.isHTML5){if(a._a)a._a.muted=!1}else b.o._setVolume(a.sID,c?a._iO.volume:a.options.volume);return a};this.toggleMute=function(){return a.muted?a.unmute():a.mute()};this.onposition=function(b,c,d){a._onPositionItems.push({position:b,method:c,scope:typeof d!=="undefined"?d:a,fired:!1});return a};this.processOnPosition=function(){var c,d;c=a._onPositionItems.length;if(!c||!a.playState||a._onPositionFired>=c)return!1;
+for(;c--;)if(d=a._onPositionItems[c],!d.fired&&a.position>=d.position)d.method.apply(d.scope,[d.position]),d.fired=!0,b._onPositionFired++;return!0};this.resetOnPosition=function(c){var d,e;d=a._onPositionItems.length;if(!d)return!1;for(;d--;)if(e=a._onPositionItems[d],e.fired&&c<=e.position)e.fired=!1,b._onPositionFired--;return!0};d=function(){a.isHTML5&&va(a)};f=function(){a.isHTML5&&wa(a)};e=function(){a._onPositionItems=[];a._onPositionFired=0;a._hasTimer=null;a._onplay_called=!1;a._a=null;a._html5_canplay=
+!1;a.bytesLoaded=null;a.bytesTotal=null;a.position=null;a.duration=a._iO&&a._iO.duration?a._iO.duration:null;a.durationEstimate=null;a.failures=0;a.loaded=!1;a.playState=0;a.paused=!1;a.readyState=0;a.muted=!1;a.didBeforeFinish=!1;a.didJustBeforeFinish=!1;a.isBuffering=!1;a.instanceOptions={};a.instanceCount=0;a.peakData={left:0,right:0};a.waveformData={left:[],right:[]};a.eqData=[];a.eqData.left=[];a.eqData.right=[]};e();this._onTimer=function(b){var c={};if(a._hasTimer||b)return a._a&&(b||(a.playState>
+0||a.readyState===1)&&!a.paused)?(a.duration=a._get_html5_duration(),a.durationEstimate=a.duration,b=a._a.currentTime?a._a.currentTime*1E3:0,a._whileplaying(b,c,c,c,c),!0):!1};this._get_html5_duration=function(){var b=a._a?a._a.duration*1E3:a._iO?a._iO.duration:void 0;return b&&!isNaN(b)&&b!==Infinity?b:a._iO?a._iO.duration:null};this._setup_html5=function(c){var c=n(a._iO,c),d=L?b._global_a:a._a;decodeURI(c.url);var f=d&&d._t?d._t.instanceOptions:null;if(d){if(d._t&&f.url===c.url&&(!a._lastURL||
+a._lastURL===f.url))return d;L&&d._t&&d._t.playState&&c.url!==f.url&&d._t.stop();e();d.src=c.url;a.url=c.url;a._lastURL=c.url;d._called_load=!1}else if(d=new Audio(c.url),d._called_load=!1,L)b._global_a=d;a.isHTML5=!0;a._a=d;d._t=a;a._add_html5_events();d.loop=c.loops>1?"loop":"";c.autoLoad||c.autoPlay?(d.autobuffer="auto",d.preload="auto",a.load(),d._called_load=!0):(d.autobuffer=!1,d.preload="none");d.loop=c.loops>1?"loop":"";return d};this._add_html5_events=function(){if(a._a._added_events)return!1;
+var b;a._a._added_events=!0;for(b in r)r.hasOwnProperty(b)&&a._a&&a._a.addEventListener(b,r[b],!1);return!0};this._remove_html5_events=function(){var b;a._a._added_events=!1;for(b in r)r.hasOwnProperty(b)&&a._a&&a._a.removeEventListener(b,r[b],!1)};this._onload=function(b){b=b?!0:!1;a.loaded=b;a.readyState=b?3:2;a._onbufferchange(0);a._iO.onload&&a._iO.onload.apply(a,[b]);return!0};this._onbufferchange=function(b){if(a.playState===0)return!1;if(b&&a.isBuffering||!b&&!a.isBuffering)return!1;a.isBuffering=
+b===1;a._iO.onbufferchange&&a._iO.onbufferchange.apply(a);return!0};this._onfailure=function(b,c,d){a.failures++;if(a._iO.onfailure&&a.failures===1)a._iO.onfailure(a,b,c,d)};this._onbeforefinish=function(){if(!a.didBeforeFinish)a.didBeforeFinish=!0,a._iO.onbeforefinish&&a._iO.onbeforefinish.apply(a)};this._onjustbeforefinish=function(){if(!a.didJustBeforeFinish)a.didJustBeforeFinish=!0,a._iO.onjustbeforefinish&&a._iO.onjustbeforefinish.apply(a)};this._onfinish=function(){var b=a._iO.onfinish;a._onbufferchange(0);
+a.resetOnPosition(0);a._iO.onbeforefinishcomplete&&a._iO.onbeforefinishcomplete.apply(a);a.didBeforeFinish=!1;a.didJustBeforeFinish=!1;if(a.instanceCount){a.instanceCount--;if(!a.instanceCount)a.playState=0,a.paused=!1,a.instanceCount=0,a.instanceOptions={},a._iO={},f();(!a.instanceCount||a._iO.multiShotEvents)&&b&&b.apply(a)}};this._whileloading=function(b,c,d,e){a.bytesLoaded=b;a.bytesTotal=c;a.duration=Math.floor(d);a.bufferLength=e;if(a._iO.isMovieStar)a.durationEstimate=a.duration;else if(a.durationEstimate=
+a._iO.duration?a.duration>a._iO.duration?a.duration:a._iO.duration:parseInt(a.bytesTotal/a.bytesLoaded*a.duration,10),a.durationEstimate===void 0)a.durationEstimate=a.duration;a.readyState!==3&&a._iO.whileloading&&a._iO.whileloading.apply(a)};this._whileplaying=function(c,d,e,f,g){if(isNaN(c)||c===null)return!1;a.position=c;a.processOnPosition();if(!a.isHTML5&&i>8){if(a._iO.usePeakData&&typeof d!=="undefined"&&d)a.peakData={left:d.leftPeak,right:d.rightPeak};if(a._iO.useWaveformData&&typeof e!=="undefined"&&
+e)a.waveformData={left:e.split(","),right:f.split(",")};if(a._iO.useEQData&&typeof g!=="undefined"&&g&&g.leftEQ&&(c=g.leftEQ.split(","),a.eqData=c,a.eqData.left=c,typeof g.rightEQ!=="undefined"&&g.rightEQ))a.eqData.right=g.rightEQ.split(",")}a.playState===1&&(!a.isHTML5&&b.flashVersion===8&&!a.position&&a.isBuffering&&a._onbufferchange(0),a._iO.whileplaying&&a._iO.whileplaying.apply(a),(a.loaded||!a.loaded&&a._iO.isMovieStar)&&a._iO.onbeforefinish&&a._iO.onbeforefinishtime&&!a.didBeforeFinish&&a.duration-
+a.position<=a._iO.onbeforefinishtime&&a._onbeforefinish());return!0};this._onid3=function(b,c){var d=[],e,f;e=0;for(f=b.length;e<f;e++)d[b[e]]=c[e];a.id3=n(a.id3,d);a._iO.onid3&&a._iO.onid3.apply(a)};this._onconnect=function(b){b=b===1;if(a.connected=b)a.failures=0,j(a.sID)&&(a.getAutoPlay()?a.play(void 0,a.getAutoPlay()):a._iO.autoLoad&&a.load()),a._iO.onconnect&&a._iO.onconnect.apply(a,[b])};this._ondataerror=function(){a.playState>0&&a._iO.ondataerror&&a._iO.ondataerror.apply(a)}};ea=function(){return g.body||
+g._docElement||g.getElementsByTagName("div")[0]};F=function(b){return g.getElementById(b)};n=function(c,a){var e={},f,d;for(f in c)c.hasOwnProperty(f)&&(e[f]=c[f]);f=typeof a==="undefined"?b.defaultOptions:a;for(d in f)f.hasOwnProperty(d)&&typeof e[d]==="undefined"&&(e[d]=f[d]);return e};k=function(){function b(a){var a=Fa.call(a),c=a.length;e?(a[1]="on"+a[1],c>3&&a.pop()):c===3&&a.push(!1);return a}function a(a,b){var c=a.shift(),g=[f[b]];if(e)c[g](a[0],a[1]);else c[g].apply(c,a)}var e=h.attachEvent,
+f={add:e?"attachEvent":"addEventListener",remove:e?"detachEvent":"removeEventListener"};return{add:function(){a(b(arguments),"add")},remove:function(){a(b(arguments),"remove")}}}();V=function(c){return!c.serverURL&&(c.type?K({type:c.type}):K({url:c.url})||b.html5Only)};K=function(c){function a(a){return b.preferFlash&&p&&!b.ignoreFlash&&typeof b.flash[a]!=="undefined"&&b.flash[a]}if(!b.useHTML5Audio||!b.hasHTML5)return!1;var e=c.url||null,c=c.type||null,f=b.audioFormats,d;if(c&&b.html5[c]!=="undefined")return b.html5[c]&&
+!a(c);if(!v){v=[];for(d in f)f.hasOwnProperty(d)&&(v.push(d),f[d].related&&(v=v.concat(f[d].related)));v=RegExp("\\.("+v.join("|")+")(\\?.*)?$","i")}d=e?e.toLowerCase().match(v):null;if(!d||!d.length)if(c)e=c.indexOf(";"),d=(e!==-1?c.substr(0,e):c).substr(6);else return!1;else d=d[1];return d&&typeof b.html5[d]!=="undefined"?b.html5[d]&&!a(d):(c="audio/"+d,e=b.html5.canPlayType({type:c}),(b.html5[d]=e)&&b.html5[c]&&!a(c))};ya=function(){function c(c){var d,e,f=!1;if(!a||typeof a.canPlayType!=="function")return!1;
+if(c instanceof Array){d=0;for(e=c.length;d<e&&!f;d++)if(b.html5[c[d]]||a.canPlayType(c[d]).match(b.html5Test))f=!0,b.html5[c[d]]=!0,b.flash[c[d]]=!(!b.preferFlash||!p||!c[d].match(Da));return f}else return c=a&&typeof a.canPlayType==="function"?a.canPlayType(c):!1,!(!c||!c.match(b.html5Test))}if(!b.useHTML5Audio||typeof Audio==="undefined")return!1;var a=typeof Audio!=="undefined"?Ia?new Audio(null):new Audio:null,e,f={},d,g;d=b.audioFormats;for(e in d)if(d.hasOwnProperty(e)&&(f[e]=c(d[e].type),
+f["audio/"+e]=f[e],b.flash[e]=b.preferFlash&&!b.ignoreFlash&&e.match(Da)?!0:!1,d[e]&&d[e].related))for(g=d[e].related.length;g--;)f["audio/"+d[e].related[g]]=f[e],b.html5[d[e].related[g]]=f[e],b.flash[d[e].related[g]]=f[e];f.canPlayType=a?c:null;b.html5=n(b.html5,f);return!0};x=function(){};S=function(b){if(i===8&&b.loops>1&&b.stream)b.stream=!1;return b};T=function(b){if(b&&!b.usePolicyFile&&(b.onid3||b.usePeakData||b.useWaveformData||b.useEQData))b.usePolicyFile=!0;return b};ia=function(b){typeof console!==
+"undefined"&&typeof console.warn!=="undefined"&&console.warn(b)};aa=function(){return!1};ta=function(b){for(var a in b)b.hasOwnProperty(a)&&typeof b[a]==="function"&&(b[a]=aa)};R=function(c){typeof c==="undefined"&&(c=!1);(u||c)&&b.disable(c)};ua=function(c){var a=null;if(c)if(c.match(/\.swf(\?.*)?$/i)){if(a=c.substr(c.toLowerCase().lastIndexOf(".swf?")+4))return c}else c.lastIndexOf("/")!==c.length-1&&(c+="/");return(c&&c.lastIndexOf("/")!==-1?c.substr(0,c.lastIndexOf("/")+1):"./")+b.movieURL};ca=
+function(){if(i!==8&&i!==9)b.flashVersion=8;var c=b.debugMode||b.debugFlash?"_debug.swf":".swf";if(b.useHTML5Audio&&!b.html5Only&&b.audioFormats.mp4.required&&b.flashVersion<9)b.flashVersion=9;i=b.flashVersion;b.version=b.versionNumber+(b.html5Only?" (HTML5-only mode)":i===9?" (AS3/Flash 9)":" (AS2/Flash 8)");if(i>8)b.defaultOptions=n(b.defaultOptions,b.flash9Options),b.features.buffering=!0;i>8&&b.useMovieStar?(b.defaultOptions=n(b.defaultOptions,b.movieStarOptions),b.filePatterns.flash9=RegExp("\\.(mp3|"+
+b.netStreamTypes.join("|")+")(\\?.*)?$","i"),b.mimePattern=b.netStreamMimeTypes,b.features.movieStar=!0):(b.useMovieStar=!1,b.features.movieStar=!1);b.filePattern=b.filePatterns[i!==8?"flash9":"flash8"];b.movieURL=(i===8?"soundmanager2.swf":"soundmanager2_flash9.swf").replace(".swf",c);b.features.peakData=b.features.waveformData=b.features.eqData=i>8};sa=function(c,a){if(!b.o||!b.allowPolling)return!1;b.o._setPolling(c,a)};fa=function(){if(b.debugURLParam.test($))b.debugMode=!0};j=this.getSoundById;
+C=function(){var c=[];b.debugMode&&c.push(b.swfCSS.sm2Debug);b.debugFlash&&c.push(b.swfCSS.flashDebug);b.useHighPerformance&&c.push(b.swfCSS.highPerf);return c.join(" ")};ha=function(){x("fbHandler");var c=b.getMoviePercent(),a=b.swfCSS,e={type:"FLASHBLOCK"};if(b.html5Only)return!1;if(b.ok()){if(b.oMC)b.oMC.className=[C(),a.swfDefault,a.swfLoaded+(b.didFlashBlock?" "+a.swfUnblocked:"")].join(" ")}else{if(q)b.oMC.className=C()+" "+a.swfDefault+" "+(c===null?a.swfTimedout:a.swfError);b.didFlashBlock=
+!0;y({type:"ontimeout",ignoreInit:!0,error:e});B(e)}};ba=function(b,a,e){typeof t[b]==="undefined"&&(t[b]=[]);t[b].push({method:a,scope:e||null,fired:!1})};y=function(c){c||(c={type:"onready"});if(!m&&c&&!c.ignoreInit)return!1;if(c.type==="ontimeout"&&b.ok())return!1;var a={success:c&&c.ignoreInit?b.ok():!u},e=c&&c.type?t[c.type]||[]:[],f=[],d,a=[a],g=q&&b.useFlashBlock&&!b.ok();if(c.error)a[0].error=c.error;c=0;for(d=e.length;c<d;c++)e[c].fired!==!0&&f.push(e[c]);if(f.length){c=0;for(d=f.length;c<
+d;c++)if(f[c].scope?f[c].method.apply(f[c].scope,a):f[c].method.apply(this,a),!g)f[c].fired=!0}return!0};z=function(){h.setTimeout(function(){b.useFlashBlock&&ha();y();b.onload instanceof Function&&b.onload.apply(h);b.waitForWindowLoad&&k.add(h,"load",z)},1)};W=function(){if(p!==void 0)return p;var b=!1,a=navigator,e=a.plugins,f,d=h.ActiveXObject;if(e&&e.length)(a=a.mimeTypes)&&a["application/x-shockwave-flash"]&&a["application/x-shockwave-flash"].enabledPlugin&&a["application/x-shockwave-flash"].enabledPlugin.description&&
+(b=!0);else if(typeof d!=="undefined"){try{f=new d("ShockwaveFlash.ShockwaveFlash")}catch(g){}b=!!f}return p=b};xa=function(){var c,a;if(o.match(/iphone os (1|2|3_0|3_1)/i)){b.hasHTML5=!1;b.html5Only=!0;if(b.oMC)b.oMC.style.display="none";return!1}if(b.useHTML5Audio){if(!b.html5||!b.html5.canPlayType)return b.hasHTML5=!1,!0;else b.hasHTML5=!0;if(la&&W())return!0}else return!0;for(a in b.audioFormats)if(b.audioFormats.hasOwnProperty(a)&&(b.audioFormats[a].required&&!b.html5.canPlayType(b.audioFormats[a].type)||
+b.flash[a]||b.flash[b.audioFormats[a].type]))c=!0;b.ignoreFlash&&(c=!1);b.html5Only=b.hasHTML5&&b.useHTML5Audio&&!c;return!b.html5Only};va=function(b){if(!b._hasTimer)b._hasTimer=!0};wa=function(b){if(b._hasTimer)b._hasTimer=!1};B=function(c){c=typeof c!=="undefined"?c:{};b.onerror instanceof Function&&b.onerror.apply(h,[{type:typeof c.type!=="undefined"?c.type:null}]);typeof c.fatal!=="undefined"&&c.fatal&&b.disable()};za=function(){if(!la||!W())return!1;var c=b.audioFormats,a,e;for(e in c)if(c.hasOwnProperty(e)&&
+(e==="mp3"||e==="mp4"))if(b.html5[e]=!1,c[e]&&c[e].related)for(a=c[e].related.length;a--;)b.html5[c[e].related[a]]=!1};this._setSandboxType=function(){};this._externalInterfaceOK=function(){if(b.swfLoaded)return!1;(new Date).getTime();b.swfLoaded=!0;E=!1;la&&za();s?setTimeout(N,100):N()};Q=function(c,a){function e(a,b){return'<param name="'+a+'" value="'+b+'" />'}if(G&&H)return!1;if(b.html5Only)return ca(),b.oMC=F(b.movieID),N(),H=G=!0,!1;var f=a||b.url,d=b.altURL||f,h;h=ea();var i,l,j=C(),k,m=null,
+m=(m=g.getElementsByTagName("html")[0])&&m.dir&&m.dir.match(/rtl/i),c=typeof c==="undefined"?b.id:c;ca();b.url=ua(na?f:d);a=b.url;b.wmode=!b.wmode&&b.useHighPerformance&&!b.useMovieStar?"transparent":b.wmode;if(b.wmode!==null&&(o.match(/msie 8/i)||!s&&!b.useHighPerformance)&&navigator.platform.match(/win32|win64/i))b.specialWmodeCase=!0,b.wmode=null;h={name:c,id:c,src:a,width:"auto",height:"auto",quality:"high",allowScriptAccess:b.allowScriptAccess,bgcolor:b.bgColor,pluginspage:Ea+"//www.macromedia.com/go/getflashplayer",
+title:"JS/Flash audio component (SoundManager 2)",type:"application/x-shockwave-flash",wmode:b.wmode,hasPriority:"true"};if(b.debugFlash)h.FlashVars="debug=1";b.wmode||delete h.wmode;if(s)f=g.createElement("div"),l=['<object id="'+c+'" data="'+a+'" type="'+h.type+'" title="'+h.title+'" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="'+Ea+'//download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" width="'+h.width+'" height="'+h.height+'">',e("movie",a),e("AllowScriptAccess",
+b.allowScriptAccess),e("quality",h.quality),b.wmode?e("wmode",b.wmode):"",e("bgcolor",b.bgColor),e("hasPriority","true"),b.debugFlash?e("FlashVars",h.FlashVars):"","</object>"].join("");else for(i in f=g.createElement("embed"),h)h.hasOwnProperty(i)&&f.setAttribute(i,h[i]);fa();j=C();if(h=ea())if(b.oMC=F(b.movieID)||g.createElement("div"),b.oMC.id){k=b.oMC.className;b.oMC.className=(k?k+" ":b.swfCSS.swfDefault)+(j?" "+j:"");b.oMC.appendChild(f);if(s)i=b.oMC.appendChild(g.createElement("div")),i.className=
+b.swfCSS.swfBox,i.innerHTML=l;H=!0}else{b.oMC.id=b.movieID;b.oMC.className=b.swfCSS.swfDefault+" "+j;i=j=null;if(!b.useFlashBlock)if(b.useHighPerformance)j={position:"fixed",width:"8px",height:"8px",bottom:"0px",left:"0px",overflow:"hidden"};else if(j={position:"absolute",width:"6px",height:"6px",top:"-9999px",left:"-9999px"},m)j.left=Math.abs(parseInt(j.left,10))+"px";if(Ha)b.oMC.style.zIndex=1E4;if(!b.debugFlash)for(k in j)j.hasOwnProperty(k)&&(b.oMC.style[k]=j[k]);try{s||b.oMC.appendChild(f);h.appendChild(b.oMC);
+if(s)i=b.oMC.appendChild(g.createElement("div")),i.className=b.swfCSS.swfBox,i.innerHTML=l;H=!0}catch(n){throw Error(x("domError")+" \n"+n.toString());}}return G=!0};P=function(){if(b.html5Only)return Q(),!1;if(b.o)return!1;b.o=b.getMovie(b.id);if(!b.o)J?(s?b.oMC.innerHTML=ga:b.oMC.appendChild(J),J=null,G=!0):Q(b.id,b.url),b.o=b.getMovie(b.id);b.oninitmovie instanceof Function&&setTimeout(b.oninitmovie,1);return!0};O=function(){setTimeout(ra,1E3)};ra=function(){if(U)return!1;U=!0;k.remove(h,"load",
+O);if(E&&!ma)return!1;var c;m||(c=b.getMoviePercent());setTimeout(function(){c=b.getMoviePercent();!m&&Ca&&(c===null?b.useFlashBlock||b.flashLoadTimeout===0?b.useFlashBlock&&ha():R(!0):b.flashLoadTimeout!==0&&R(!0))},b.flashLoadTimeout)};w=function(){function b(){k.remove(h,"focus",w);k.remove(h,"load",w)}if(ma||!E)return b(),!0;ma=Ca=!0;D&&E&&k.remove(h,"mousemove",w);U=!1;b();return!0};I=function(c){if(m)return!1;if(b.html5Only)return m=!0,z(),!0;var a;if(!b.useFlashBlock||!b.flashLoadTimeout||
+b.getMoviePercent())m=!0,u&&(a={type:!p&&q?"NO_FLASH":"INIT_TIMEOUT"});if(u||c){if(b.useFlashBlock&&b.oMC)b.oMC.className=C()+" "+(b.getMoviePercent()===null?b.swfCSS.swfTimedout:b.swfCSS.swfError);y({type:"ontimeout",error:a});B(a);return!1}k.add(h,"unload",aa);if(b.waitForWindowLoad&&!qa)return k.add(h,"load",z),!1;else z();return!0};Aa=function(){var c,a=[];if(b.useHTML5Audio&&b.hasHTML5)for(c in b.audioFormats)b.audioFormats.hasOwnProperty(c)&&a.push(c+": "+b.html5[c]+(!b.html5[c]&&p&&b.flash[c]?
+" (using flash)":b.preferFlash&&b.flash[c]&&p?" (preferring flash)":!b.html5[c]?" ("+(b.audioFormats[c].required?"required, ":"")+"and no flash support)":""))};N=function(){if(m)return!1;if(b.html5Only){if(!m)k.remove(h,"load",b.beginDelayedInit),b.enabled=!0,I();return!0}P();try{b.o._externalInterfaceTest(!1),b.allowPolling&&sa(!0,b.flashPollingInterval||(b.useFastPolling?10:50)),b.debugMode||b.o._disableDebug(),b.enabled=!0}catch(c){return B({type:"JS_TO_FLASH_EXCEPTION",fatal:!0}),R(!0),I(),!1}I();
+k.remove(h,"load",b.beginDelayedInit);return!0};A=function(){if(da)return!1;da=!0;fa();if(!p&&b.hasHTML5)b.useHTML5Audio=!0,b.preferFlash=!1;ya();b.html5.usingFlash=xa();q=b.html5.usingFlash;Aa();if(!p&&q)b.flashLoadTimeout=1;g.removeEventListener&&g.removeEventListener("DOMContentLoaded",A,!1);P();return!0};ka=function(){g.readyState==="complete"&&(A(),g.detachEvent("onreadystatechange",ka));return!0};W();k.add(h,"focus",w);k.add(h,"load",w);k.add(h,"load",O);D&&E&&k.add(h,"mousemove",w);g.addEventListener?
+g.addEventListener("DOMContentLoaded",A,!1):g.attachEvent?g.attachEvent("onreadystatechange",ka):B({type:"NO_DOM2_EVENTS",fatal:!0});g.readyState==="complete"&&setTimeout(A,100)}var Y=null;if(typeof SM2_DEFER==="undefined"||!SM2_DEFER)Y=new M;Z.SoundManager=M;Z.soundManager=Y})(window);
Index: /gs3-extensions/audioDB/trunk/src/interface/script/soundmanager2-nodebug.js
===================================================================
--- /gs3-extensions/audioDB/trunk/src/interface/script/soundmanager2-nodebug.js	(revision 26291)
+++ /gs3-extensions/audioDB/trunk/src/interface/script/soundmanager2-nodebug.js	(revision 26291)
@@ -0,0 +1,3198 @@
+/** @license
+ * SoundManager 2: JavaScript Sound for the Web
+ * ----------------------------------------------
+ * http://schillmania.com/projects/soundmanager2/
+ *
+ * Copyright (c) 2007, Scott Schiller. All rights reserved.
+ * Code provided under the BSD License:
+ * http://schillmania.com/projects/soundmanager2/license.txt
+ *
+ * V2.97a.20110801
+*/
+
+/*global window, SM2_DEFER, sm2Debugger, console, document, navigator, setTimeout, setInterval, clearInterval, Audio */
+/*jslint regexp: true, sloppy: true, white: true, nomen: true, plusplus: true */
+
+(function(window) {
+
+var soundManager = null;
+
+function SoundManager(smURL, smID) {
+
+  this.flashVersion = 8;             // version of flash to require, either 8 or 9. Some API features require Flash 9.
+  this.debugMode = false;             // enable debugging output (div#soundmanager-debug, OR console if available+configured)
+  this.debugFlash = false;           // enable debugging output inside SWF, troubleshoot Flash/browser issues
+  this.useConsole = true;            // use firebug/safari console.log()-type debug console if available
+  this.consoleOnly = false;          // if console is being used, do not create/write to #soundmanager-debug
+  this.waitForWindowLoad = false;    // force SM2 to wait for window.onload() before trying to call soundManager.onload()
+  this.nullURL = 'about:blank';      // path to "null" (empty) MP3 file, used to unload sounds (Flash 8 only)
+  this.allowPolling = true;          // allow flash to poll for status update (required for whileplaying() events, peak, sound spectrum functions to work.)
+  this.useFastPolling = false;       // uses lower flash timer interval for higher callback frequency, best combined with useHighPerformance
+  this.useMovieStar = true;          // enable support for Flash 9.0r115+ (codename "MovieStar") MPEG4 audio formats (AAC, M4V, FLV, MOV etc.)
+  this.bgColor = '#ffffff';          // movie (.swf) background color, eg. '#000000'
+  this.useHighPerformance = false;   // position:fixed flash movie can help increase js/flash speed, minimize lag
+  this.flashPollingInterval = null;  // msec for polling interval. Defaults to 50 unless useFastPolling = true.
+  this.flashLoadTimeout = 1000;      // msec to wait for flash movie to load before failing (0 = infinity)
+  this.wmode = null;                 // string: flash rendering mode - null, transparent, opaque (last two allow layering of HTML on top)
+  this.allowScriptAccess = 'always'; // for scripting the SWF (object/embed property), either 'always' or 'sameDomain'
+  this.useFlashBlock = false;        // *requires flashblock.css, see demos* - allow recovery from flash blockers. Wait indefinitely and apply timeout CSS to SWF, if applicable.
+  this.useHTML5Audio = true;         // Beta feature: Use HTML5 Audio() where API is supported (most Safari, Chrome versions), Firefox (no MP3/MP4.) Ideally, transparent vs. Flash API where possible.
+  this.html5Test = /^(probably|maybe)$/i; // HTML5 Audio() format support test. Use /^probably$/i; if you want to be more conservative.
+  this.preferFlash = true;           // (experimental) if true and flash support present, will try to use flash for MP3/MP4 as needed since HTML5 audio support is still quirky in browsers.
+
+  this.audioFormats = {
+    /*
+     * determines HTML5 support + flash requirements.
+     * if no support for a "required" format, SM2 will fail to start.
+     * flash fallback is used for MP3 or MP4 if HTML5 can't play it (or if preferFlash = true)
+     * multiple MIME types may be tested while trying to get a positive canPlayType() response.
+    */
+    'mp3': {
+      'type': ['audio/mpeg; codecs="mp3"', 'audio/mpeg', 'audio/mp3', 'audio/MPA', 'audio/mpa-robust'],
+      'required': true
+    },
+    'mp4': {
+      'related': ['aac','m4a'], // additional formats under the MP4 container
+      'type': ['audio/mp4; codecs="mp4a.40.2"', 'audio/aac', 'audio/x-m4a', 'audio/MP4A-LATM', 'audio/mpeg4-generic'],
+      'required': false
+    },
+    'ogg': {
+      'type': ['audio/ogg; codecs=vorbis'],
+      'required': false
+    },
+    'wav': {
+      'type': ['audio/wav; codecs="1"', 'audio/wav', 'audio/wave', 'audio/x-wav'],
+      'required': false
+    }
+  };
+
+  this.defaultOptions = {
+    'autoLoad': false,             // enable automatic loading (otherwise .load() will be called on demand with .play(), the latter being nicer on bandwidth - if you want to .load yourself, you also can)
+    'stream': true,                // allows playing before entire file has loaded (recommended)
+    'autoPlay': false,             // enable playing of file as soon as possible (much faster if "stream" is true)
+    'loops': 1,                    // how many times to repeat the sound (position will wrap around to 0, setPosition() will break out of loop when >0)
+    'onid3': null,                 // callback function for "ID3 data is added/available"
+    'onload': null,                // callback function for "load finished"
+    'whileloading': null,          // callback function for "download progress update" (X of Y bytes received)
+    'onplay': null,                // callback for "play" start
+    'onpause': null,               // callback for "pause"
+    'onresume': null,              // callback for "resume" (pause toggle)
+    'whileplaying': null,          // callback during play (position update)
+    'onstop': null,                // callback for "user stop"
+    'onfailure': null,             // callback function for when playing fails
+    'onfinish': null,              // callback function for "sound finished playing"
+    'onbeforefinish': null,        // callback for "before sound finished playing (at [time])"
+    'onbeforefinishtime': 5000,    // offset (milliseconds) before end of sound to trigger beforefinish (eg. 1000 msec = 1 second)
+    'onbeforefinishcomplete': null,// function to call when said sound finishes playing
+    'onjustbeforefinish': null,    // callback for [n] msec before end of current sound
+    'onjustbeforefinishtime': 200, // [n] - if not using, set to 0 (or null handler) and event will not fire.
+    'multiShot': true,             // let sounds "restart" or layer on top of each other when played multiple times, rather than one-shot/one at a time
+    'multiShotEvents': false,      // fire multiple sound events (currently onfinish() only) when multiShot is enabled
+    'position': null,              // offset (milliseconds) to seek to within loaded sound data.
+    'pan': 0,                      // "pan" settings, left-to-right, -100 to 100
+    'type': null,                  // MIME-like hint for file pattern / canPlay() tests, eg. audio/mp3
+    'usePolicyFile': false,        // enable crossdomain.xml request for audio on remote domains (for ID3/waveform access)
+    'volume': 100                  // self-explanatory. 0-100, the latter being the max.
+  };
+
+  this.flash9Options = {      // flash 9-only options, merged into defaultOptions if flash 9 is being used
+    'isMovieStar': null,      // "MovieStar" MPEG4 audio mode. Null (default) = auto detect MP4, AAC etc. based on URL. true = force on, ignore URL
+    'usePeakData': false,     // enable left/right channel peak (level) data
+    'useWaveformData': false, // enable sound spectrum (raw waveform data) - WARNING: CPU-INTENSIVE: may set CPUs on fire.
+    'useEQData': false,       // enable sound EQ (frequency spectrum data) - WARNING: Also CPU-intensive.
+    'onbufferchange': null,   // callback for "isBuffering" property change
+    'ondataerror': null       // callback for waveform/eq data access error (flash playing audio in other tabs/domains)
+  };
+
+  this.movieStarOptions = { // flash 9.0r115+ MPEG4 audio options, merged into defaultOptions if flash 9+movieStar mode is enabled
+    'bufferTime': 3,        // seconds of data to buffer before playback begins (null = flash default of 0.1 seconds - if AAC playback is gappy, try increasing.)
+    'serverURL': null,      // rtmp: FMS or FMIS server to connect to, required when requesting media via RTMP or one of its variants
+    'onconnect': null,      // rtmp: callback for connection to flash media server
+    'duration': null        // rtmp: song duration (msec)
+  };
+
+  this.version = null;
+  this.versionNumber = 'V2.97a.20110801';
+  this.movieURL = null;
+  this.url = (smURL || null);
+  this.altURL = null;
+  this.swfLoaded = false;
+  this.enabled = false;
+  this.o = null;
+  this.movieID = 'sm2-container';
+  this.id = (smID || 'sm2movie');
+  this.swfCSS = {
+    'swfBox': 'sm2-object-box',
+    'swfDefault': 'movieContainer',
+    'swfError': 'swf_error', // SWF loaded, but SM2 couldn't start (other error)
+    'swfTimedout': 'swf_timedout',
+    'swfLoaded': 'swf_loaded',
+    'swfUnblocked': 'swf_unblocked', // or loaded OK
+    'sm2Debug': 'sm2_debug',
+    'highPerf': 'high_performance',
+    'flashDebug': 'flash_debug'
+  };
+  this.oMC = null;
+  this.sounds = {};
+  this.soundIDs = [];
+  this.muted = false;
+  this.debugID = 'soundmanager-debug';
+  this.debugURLParam = /([#?&])debug=1/i;
+  this.specialWmodeCase = false;
+  this.didFlashBlock = false;
+
+  this.filePattern = null;
+  this.filePatterns = {
+    'flash8': /\.mp3(\?.*)?$/i,
+    'flash9': /\.mp3(\?.*)?$/i
+  };
+
+  this.baseMimeTypes = /^\s*audio\/(?:x-)?(?:mp(?:eg|3))\s*(?:$|;)/i; // mp3
+  this.netStreamMimeTypes = /^\s*audio\/(?:x-)?(?:mp(?:eg|3))\s*(?:$|;)/i; // mp3, mp4, aac etc.
+  this.netStreamTypes = ['aac', 'flv', 'mov', 'mp4', 'm4v', 'f4v', 'm4a', 'mp4v', '3gp', '3g2']; // Flash v9.0r115+ "moviestar" formats
+  this.netStreamPattern = new RegExp('\\.(' + this.netStreamTypes.join('|') + ')(\\?.*)?$', 'i');
+  this.mimePattern = this.baseMimeTypes;
+
+  this.features = {
+    'buffering': false,
+    'peakData': false,
+    'waveformData': false,
+    'eqData': false,
+    'movieStar': false
+  };
+
+  this.sandbox = {
+    /*
+    'type': null,
+    'types': {
+      'remote': 'remote (domain-based) rules',
+      'localWithFile': 'local with file access (no internet access)',
+      'localWithNetwork': 'local with network (internet access only, no local access)',
+      'localTrusted': 'local, trusted (local+internet access)'
+    },
+    'description': null,
+    'noRemote': null,
+    'noLocal': null
+    */
+  };
+
+  this.hasHTML5 = (typeof Audio !== 'undefined' && typeof new Audio().canPlayType !== 'undefined'); // switch for handling logic
+
+  // stores canPlayType() results, etc. treat as read-only.
+  this.html5 = {
+    // mp3: boolean
+    // mp4: boolean
+    'usingFlash': null // set if/when flash fallback is needed
+  };
+
+  // format support
+  this.flash = {
+    // mp3: boolean
+    // mp4: boolean
+  };
+
+  this.html5Only = false;   // determined at init time
+  this.ignoreFlash = false; // used for special cases (eg. iPad/iPhone/palm OS?)
+
+  /*
+   * a few private internals
+  */
+
+  var SMSound,
+  _s = this, _sm = 'soundManager', _smc = _sm+'::', _h5 = 'HTML5::', _id, _ua = navigator.userAgent, _win = window, _wl = _win.location.href.toString(), _fV = this.flashVersion, _doc = document, _doNothing, _init, _on_queue = [], _debugOpen = true, _debugTS, _didAppend = false, _appendSuccess = false, _didInit = false, _disabled = false, _windowLoaded = false, _wDS, _wdCount = 0, _initComplete, _mixin, _addOnEvent, _processOnEvents, _initUserOnload, _delayWaitForEI, _waitForEI, _setVersionInfo, _handleFocus, _strings, _initMovie, _dcLoaded, _didDCLoaded, _getDocument, _createMovie, _catchError, _setPolling, _initDebug, _debugLevels = ['log', 'info', 'warn', 'error'], _defaultFlashVersion = 8, _disableObject, _failSafely, _normalizeMovieURL, _oRemoved = null, _oRemovedHTML = null, _str, _flashBlockHandler, _getSWFCSS, _toggleDebug, _loopFix, _policyFix, _complain, _idCheck, _waitingForEI = false, _initPending = false, _smTimer, _onTimer, _startTimer, _stopTimer, _needsFlash = null, _featureCheck, _html5OK, _html5CanPlay, _html5Ext,  _dcIE, _testHTML5, _event, _slice = Array.prototype.slice, _useGlobalHTML5Audio = false, _hasFlash, _detectFlash, _badSafariFix, _html5_events, _showSupport,
+  _is_iDevice = _ua.match(/(ipad|iphone|ipod)/i), _likesHTML5 = (_ua.match(/(mobile|pre\/|xoom)/i) || _is_iDevice), _isIE = _ua.match(/msie/i), _isWebkit = _ua.match(/webkit/i), _isSafari = (_ua.match(/safari/i) && !_ua.match(/chrome/i)), _isOpera = (_ua.match(/opera/i)), 
+  _isBadSafari = (!_wl.match(/usehtml5audio/i) && !_wl.match(/sm2\-ignorebadua/i) && _isSafari && _ua.match(/OS X 10_6_([3-7])/i)), // Safari 4 and 5 occasionally fail to load/play HTML5 audio on Snow Leopard 10.6.3 through 10.6.7 due to bug(s) in QuickTime X and/or other underlying frameworks. :/ Confirmed bug. https://bugs.webkit.org/show_bug.cgi?id=32159
+  _hasConsole = (typeof console !== 'undefined' && typeof console.log !== 'undefined'), _isFocused = (typeof _doc.hasFocus !== 'undefined'?_doc.hasFocus():null), _tryInitOnFocus = (_isSafari && typeof _doc.hasFocus === 'undefined'), _okToDisable = !_tryInitOnFocus, _flashMIME = /(mp3|mp4|mpa)/i,
+  _overHTTP = (_doc.location?_doc.location.protocol.match(/http/i):null),
+  _http = (!_overHTTP ? 'http:' : '');
+
+  this.useAltURL = !_overHTTP; // use altURL if not "online"
+  this._global_a = null;
+
+  if (_likesHTML5) {
+    // prefer HTML5 for mobile + tablet-like devices, probably more reliable vs. flash at this point.
+    _s.useHTML5Audio = true;
+    _s.preferFlash = false;
+    if (_is_iDevice) {
+      // by default, use global feature. iOS onfinish() -> next may fail otherwise.
+      _s.ignoreFlash = true;
+      _useGlobalHTML5Audio = true;
+    }
+  }
+
+  /*
+   * public soundManager API
+  */
+
+  this.ok = function() {
+    return (_needsFlash?(_didInit && !_disabled):(_s.useHTML5Audio && _s.hasHTML5));
+  };
+
+  this.supported = this.ok; // legacy
+
+  this.getMovie = function(smID) {
+    return _isIE?_win[smID]:(_isSafari?_id(smID) || _doc[smID]:_id(smID));
+  };
+
+  this.createSound = function(oOptions) {
+    var _cs = _sm+'.createSound(): ',
+    thisOptions = null, oSound = null, _tO = null;
+    if (!_didInit || !_s.ok()) {
+      _complain(_cs + _str(!_didInit?'notReady':'notOK'));
+      return false;
+    }
+    if (arguments.length === 2) {
+      // function overloading in JS! :) ..assume simple createSound(id,url) use case
+      oOptions = {
+        'id': arguments[0],
+        'url': arguments[1]
+      };
+    }
+    thisOptions = _mixin(oOptions); // inherit from defaultOptions
+    _tO = thisOptions; // alias
+    /*
+    if (_tO.id.toString().charAt(0).match(/^[0-9]$/)) {
+      //_s._wD(_cs + _str('badID', _tO.id), 2);
+    }
+    //_s._wD(_cs + _tO.id + ' (' + _tO.url + ')', 1);
+    */
+    if (_idCheck(_tO.id, true)) {
+      //_s._wD(_cs + _tO.id + ' exists', 1);
+      return _s.sounds[_tO.id];
+    }
+
+    function make() {
+      thisOptions = _loopFix(thisOptions);
+      _s.sounds[_tO.id] = new SMSound(_tO);
+      _s.soundIDs.push(_tO.id);
+      return _s.sounds[_tO.id];
+    }
+
+    if (_html5OK(_tO)) {
+      oSound = make();
+      //_s._wD('Loading sound '+_tO.id+' via HTML5');
+      oSound._setup_html5(_tO);
+    } else {
+      if (_fV > 8 && _s.useMovieStar) {
+        if (_tO.isMovieStar === null) {
+          _tO.isMovieStar = ((_tO.serverURL || (_tO.type?_tO.type.match(_s.netStreamPattern):false)||_tO.url.match(_s.netStreamPattern))?true:false);
+        }
+        if (_tO.isMovieStar) {
+          //_s._wD(_cs + 'using MovieStar handling');
+        }
+        if (_tO.isMovieStar) {
+          if (_tO.usePeakData) {
+            //_wDS('noPeak');
+            _tO.usePeakData = false;
+          }
+          if (_tO.loops > 1) {
+            //_wDS('noNSLoop');
+          }
+        }
+      }
+      _tO = _policyFix(_tO, _cs);
+      oSound = make();
+      if (_fV === 8) {
+        _s.o._createSound(_tO.id, _tO.onjustbeforefinishtime, _tO.loops||1, _tO.usePolicyFile);
+      } else {
+        _s.o._createSound(_tO.id, _tO.url, _tO.onjustbeforefinishtime, _tO.usePeakData, _tO.useWaveformData, _tO.useEQData, _tO.isMovieStar, (_tO.isMovieStar?_tO.bufferTime:false), _tO.loops||1, _tO.serverURL, _tO.duration||null, _tO.autoPlay, true, _tO.autoLoad, _tO.usePolicyFile);
+        if (!_tO.serverURL) {
+          // We are connected immediately
+          oSound.connected = true;
+          if (_tO.onconnect) {
+            _tO.onconnect.apply(oSound);
+          }
+        }
+      }
+
+      if (!_tO.serverURL && (_tO.autoLoad || _tO.autoPlay)) {
+        oSound.load(_tO); // call load for non-rtmp streams
+      }
+    }
+    if (!_tO.serverURL && _tO.autoPlay) { // rtmp will play in onconnect
+      oSound.play();
+    }
+    return oSound;
+  };
+
+  this.destroySound = function(sID, _bFromSound) {
+    // explicitly destroy a sound before normal page unload, etc.
+    if (!_idCheck(sID)) {
+      return false;
+    }
+    var oS = _s.sounds[sID], i;
+    oS._iO = {}; // Disable all callbacks while the sound is being destroyed
+    oS.stop();
+    oS.unload();
+    for (i = 0; i < _s.soundIDs.length; i++) {
+      if (_s.soundIDs[i] === sID) {
+        _s.soundIDs.splice(i, 1);
+        break;
+      }
+    }
+    if (!_bFromSound) {
+      // ignore if being called from SMSound instance
+      oS.destruct(true);
+    }
+    oS = null;
+    delete _s.sounds[sID];
+    return true;
+  };
+
+  this.load = function(sID, oOptions) {
+    if (!_idCheck(sID)) {
+      return false;
+    }
+    return _s.sounds[sID].load(oOptions);
+  };
+
+  this.unload = function(sID) {
+    if (!_idCheck(sID)) {
+      return false;
+    }
+    return _s.sounds[sID].unload();
+  };
+
+  this.play = function(sID, oOptions) {
+    var fN = _sm+'.play(): ';
+    if (!_didInit || !_s.ok()) {
+      _complain(fN + _str(!_didInit?'notReady':'notOK'));
+      return false;
+    }
+    if (!_idCheck(sID)) {
+      if (!(oOptions instanceof Object)) {
+        oOptions = {
+          url: oOptions
+        }; // overloading use case: play('mySound','/path/to/some.mp3');
+      }
+      if (oOptions && oOptions.url) {
+        // overloading use case, create+play: .play('someID',{url:'/path/to.mp3'});
+        //_s._wD(fN + 'attempting to create "' + sID + '"', 1);
+        oOptions.id = sID;
+        return _s.createSound(oOptions).play();
+      } else {
+        return false;
+      }
+    }
+    return _s.sounds[sID].play(oOptions);
+  };
+
+  this.start = this.play; // just for convenience
+
+  this.setPosition = function(sID, nMsecOffset) {
+    if (!_idCheck(sID)) {
+      return false;
+    }
+    return _s.sounds[sID].setPosition(nMsecOffset);
+  };
+
+  this.stop = function(sID) {
+    if (!_idCheck(sID)) {
+      return false;
+    }
+    //_s._wD(_sm+'.stop(' + sID + ')', 1);
+    return _s.sounds[sID].stop();
+  };
+
+  this.stopAll = function() {
+    var oSound;
+    //_s._wD(_sm+'.stopAll()', 1);
+    for (oSound in _s.sounds) {
+      if (_s.sounds.hasOwnProperty(oSound)) {
+        _s.sounds[oSound].stop(); // apply only to sound objects
+      }
+    }
+  };
+
+  this.pause = function(sID) {
+    if (!_idCheck(sID)) {
+      return false;
+    }
+    return _s.sounds[sID].pause();
+  };
+
+  this.pauseAll = function() {
+    var i;
+    for (i = _s.soundIDs.length; i--;) {
+      _s.sounds[_s.soundIDs[i]].pause();
+    }
+  };
+
+  this.resume = function(sID) {
+    if (!_idCheck(sID)) {
+      return false;
+    }
+    return _s.sounds[sID].resume();
+  };
+
+  this.resumeAll = function() {
+    var i;
+    for (i = _s.soundIDs.length; i--;) {
+      _s.sounds[_s.soundIDs[i]].resume();
+    }
+  };
+
+  this.togglePause = function(sID) {
+    if (!_idCheck(sID)) {
+      return false;
+    }
+    return _s.sounds[sID].togglePause();
+  };
+
+  this.setPan = function(sID, nPan) {
+    if (!_idCheck(sID)) {
+      return false;
+    }
+    return _s.sounds[sID].setPan(nPan);
+  };
+
+  this.setVolume = function(sID, nVol) {
+    if (!_idCheck(sID)) {
+      return false;
+    }
+    return _s.sounds[sID].setVolume(nVol);
+  };
+
+  this.mute = function(sID) {
+    var fN = _sm+'.mute(): ',
+    i = 0;
+    if (typeof sID !== 'string') {
+      sID = null;
+    }
+    if (!sID) {
+      //_s._wD(fN + 'Muting all sounds');
+      for (i = _s.soundIDs.length; i--;) {
+        _s.sounds[_s.soundIDs[i]].mute();
+      }
+      _s.muted = true;
+    } else {
+      if (!_idCheck(sID)) {
+        return false;
+      }
+      //_s._wD(fN + 'Muting "' + sID + '"');
+      return _s.sounds[sID].mute();
+    }
+    return true;
+  };
+
+  this.muteAll = function() {
+    _s.mute();
+  };
+
+  this.unmute = function(sID) {
+    var fN = _sm+'.unmute(): ', i;
+    if (typeof sID !== 'string') {
+      sID = null;
+    }
+    if (!sID) {
+      //_s._wD(fN + 'Unmuting all sounds');
+      for (i = _s.soundIDs.length; i--;) {
+        _s.sounds[_s.soundIDs[i]].unmute();
+      }
+      _s.muted = false;
+    } else {
+      if (!_idCheck(sID)) {
+        return false;
+      }
+      //_s._wD(fN + 'Unmuting "' + sID + '"');
+      return _s.sounds[sID].unmute();
+    }
+    return true;
+  };
+
+  this.unmuteAll = function() {
+    _s.unmute();
+  };
+
+  this.toggleMute = function(sID) {
+    if (!_idCheck(sID)) {
+      return false;
+    }
+    return _s.sounds[sID].toggleMute();
+  };
+
+  this.getMemoryUse = function() {
+    // flash-only
+    var ram = 0;
+    if (_s.o && _fV !== 8) {
+      ram = parseInt(_s.o._getMemoryUse(), 10);
+    }
+    return ram;
+  };
+
+  this.disable = function(bNoDisable) {
+    // destroy all functions
+    var i;
+    if (typeof bNoDisable === 'undefined') {
+      bNoDisable = false;
+    }
+    if (_disabled) {
+      return false;
+    }
+    _disabled = true;
+    //_wDS('shutdown', 1);
+    for (i = _s.soundIDs.length; i--;) {
+      _disableObject(_s.sounds[_s.soundIDs[i]]);
+    }
+    _initComplete(bNoDisable); // fire "complete", despite fail
+    _event.remove(_win, 'load', _initUserOnload);
+    return true;
+  };
+
+  this.canPlayMIME = function(sMIME) {
+    var result;
+    if (_s.hasHTML5) {
+      result = _html5CanPlay({type:sMIME});
+    }
+    if (!_needsFlash || result) {
+      // no flash, or OK
+      return result;
+    } else {
+      return (sMIME?(sMIME.match(_s.mimePattern)?true:false):null);
+    }
+  };
+
+  this.canPlayURL = function(sURL) {
+    var result;
+    if (_s.hasHTML5) {
+      result = _html5CanPlay({url: sURL});
+    }
+    if (!_needsFlash || result) {
+      // no flash, or OK
+      return result;
+    } else {
+      return (sURL?(sURL.match(_s.filePattern)?true:false):null);
+    }
+  };
+
+  this.canPlayLink = function(oLink) {
+    if (typeof oLink.type !== 'undefined' && oLink.type) {
+      if (_s.canPlayMIME(oLink.type)) {
+        return true;
+      }
+    }
+    return _s.canPlayURL(oLink.href);
+  };
+
+  this.getSoundById = function(sID, suppressDebug) {
+    if (!sID) {
+      throw new Error(_sm+'.getSoundById(): sID is null/undefined');
+    }
+    var result = _s.sounds[sID];
+    if (!result && !suppressDebug) {
+      //_s._wD('"' + sID + '" is an invalid sound ID.', 2);
+    }
+    return result;
+  };
+
+  this.onready = function(oMethod, oScope) {
+    var sType = 'onready';
+    if (oMethod && oMethod instanceof Function) {
+      if (_didInit) {
+        //_s._wD(_str('queue', sType));
+      }
+      if (!oScope) {
+        oScope = _win;
+      }
+      _addOnEvent(sType, oMethod, oScope);
+      _processOnEvents();
+      return true;
+    } else {
+      throw _str('needFunction', sType);
+    }
+  };
+
+  this.ontimeout = function(oMethod, oScope) {
+    var sType = 'ontimeout';
+    if (oMethod && oMethod instanceof Function) {
+      if (_didInit) {
+        //_s._wD(_str('queue', sType));
+      }
+      if (!oScope) {
+        oScope = _win;
+      }
+      _addOnEvent(sType, oMethod, oScope);
+      _processOnEvents({type:sType});
+      return true;
+    } else {
+      throw _str('needFunction', sType);
+    }
+  };
+
+  this._writeDebug = function(sText, sType, bTimestamp) {
+    // pseudo-private console.log()-style output
+    /*
+    var sDID = 'soundmanager-debug', o, oItem, sMethod;
+    if (!_s.debugMode) {
+      return false;
+    }
+    if (typeof bTimestamp !== 'undefined' && bTimestamp) {
+      sText = sText + ' | ' + new Date().getTime();
+    }
+    if (_hasConsole && _s.useConsole) {
+      sMethod = _debugLevels[sType];
+      if (typeof console[sMethod] !== 'undefined') {
+        console[sMethod](sText);
+      } else {
+        console.log(sText);
+      }
+      if (_s.useConsoleOnly) {
+        return true;
+      }
+    }
+    try {
+      o = _id(sDID);
+      if (!o) {
+        return false;
+      }
+      oItem = _doc.createElement('div');
+      if (++_wdCount % 2 === 0) {
+        oItem.className = 'sm2-alt';
+      }
+      if (typeof sType === 'undefined') {
+        sType = 0;
+      } else {
+        sType = parseInt(sType, 10);
+      }
+      oItem.appendChild(_doc.createTextNode(sText));
+      if (sType) {
+        if (sType >= 2) {
+          oItem.style.fontWeight = 'bold';
+        }
+        if (sType === 3) {
+          oItem.style.color = '#ff3333';
+        }
+      }
+      // o.appendChild(oItem); // top-to-bottom
+      o.insertBefore(oItem, o.firstChild); // bottom-to-top
+    } catch(e) {
+      // oh well
+    }
+    o = null;
+    */
+    return true;
+  };
+  this._wD = this._writeDebug; // alias
+
+  this._debug = function() {
+    /*
+    var i, j;
+    //_wDS('currentObj', 1);
+    for (i = 0, j = _s.soundIDs.length; i < j; i++) {
+      _s.sounds[_s.soundIDs[i]]._debug();
+    }
+    */
+  };
+
+  this.reboot = function() {
+    // attempt to reset and init SM2
+    //_s._wD(_sm+'.reboot()');
+    if (_s.soundIDs.length) {
+      //_s._wD('Destroying ' + _s.soundIDs.length + ' SMSound objects...');
+    }
+    var i, j;
+    for (i = _s.soundIDs.length; i--;) {
+      _s.sounds[_s.soundIDs[i]].destruct();
+    }
+    // trash ze flash
+    try {
+      if (_isIE) {
+        _oRemovedHTML = _s.o.innerHTML;
+      }
+      _oRemoved = _s.o.parentNode.removeChild(_s.o);
+      //_s._wD('Flash movie removed.');
+    } catch(e) {
+      // uh-oh.
+      //_wDS('badRemove', 2);
+    }
+    // actually, force recreate of movie.
+    _oRemovedHTML = _oRemoved = _needsFlash = null;
+    _s.enabled = _didDCLoaded = _didInit = _waitingForEI = _initPending = _didAppend = _appendSuccess = _disabled = _s.swfLoaded = false;
+    _s.soundIDs = _s.sounds = [];
+    _s.o = null;
+    for (i in _on_queue) {
+      if (_on_queue.hasOwnProperty(i)) {
+        for (j = _on_queue[i].length; j--;) {
+          _on_queue[i][j].fired = false;
+        }
+      }
+    }
+    //_s._wD(_sm + ': Rebooting...');
+    _win.setTimeout(_s.beginDelayedInit, 20);
+  };
+
+  this.getMoviePercent = function() {
+    return (_s.o && typeof _s.o.PercentLoaded !== 'undefined' ? _s.o.PercentLoaded() : null);
+  };
+
+  this.beginDelayedInit = function() {
+    _windowLoaded = true;
+    _dcLoaded();
+    setTimeout(function() {
+      if (_initPending) {
+        return false;
+      }
+      _createMovie();
+      _initMovie();
+      _initPending = true;
+      return true;
+    }, 20);
+    _delayWaitForEI();
+  };
+
+  this.destruct = function() {
+    //_s._wD(_sm+'.destruct()');
+    _s.disable(true);
+  };
+
+  /*
+   * internal HTML5 event handling
+  */
+
+  function _html5_event(oFn) {
+    // wrap html5 event handlers so we don't call them on destroyed sounds
+    return function(e) {
+      if (!this._t || !this._t._a) {
+        if (this._t && this._t.sID) {
+          //_s._wD(_h5+'ignoring '+e.type+': '+this._t.sID);
+        } else {
+          //_s._wD(_h5+'ignoring '+e.type);
+        }
+        return null;
+      } else {
+        return oFn.call(this, e);
+      }
+    };
+  }
+
+  _html5_events = {
+
+    // HTML5 event-name-to-handler map
+    abort: _html5_event(function(e) {
+      //_s._wD(_h5+'abort: '+this._t.sID);
+    }),
+
+    // enough has loaded to play
+    canplay: _html5_event(function(e) {
+      if (this._t._html5_canplay) {
+        // this event has already fired. ignore.
+        return true;
+      }
+      this._t._html5_canplay = true;
+      //_s._wD(_h5+'canplay: '+this._t.sID+', '+this._t.url);
+      this._t._onbufferchange(0);
+      var position1K = (!isNaN(this._t.position)?this._t.position/1000:null);
+      // set the position if position was set before the sound loaded
+      if (this._t.position && this.currentTime !== position1K) {
+        //_s._wD(_h5+'canplay: setting position to '+position1K);
+        try {
+          this.currentTime = position1K;
+        } catch(ee) {
+          //_s._wD(_h5+'setting position failed: '+ee.message, 2);
+        }
+      }
+    }),
+
+    load: _html5_event(function(e) {
+      if (!this._t.loaded) {
+        this._t._onbufferchange(0);
+        // should be 1, and the same
+        this._t._whileloading(this._t.bytesTotal, this._t.bytesTotal, this._t._get_html5_duration());
+        this._t._onload(true);
+      }
+    }),
+
+    emptied: _html5_event(function(e) {
+      //_s._wD(_h5+'emptied: '+this._t.sID);
+    }),
+
+    ended: _html5_event(function(e) {
+      //_s._wD(_h5+'ended: '+this._t.sID);
+      this._t._onfinish();
+    }),
+
+    error: _html5_event(function(e) {
+      //_s._wD(_h5+'error: '+this.error.code);
+      // call load with error state?
+      this._t._onload(false);
+    }),
+
+    loadeddata: _html5_event(function(e) {
+      var t = this._t,
+          bytesTotal = t.bytesTotal || 1; // at least 1 byte, so math works
+      //_s._wD(_h5+'loadeddata: '+this._t.sID);
+      if (!t._loaded && !_isSafari) { // safari seems to nicely report progress events, eventually totalling 100%
+        t.duration = t._get_html5_duration();
+        // fire whileloading() with 100% values
+        t._whileloading(bytesTotal, bytesTotal, t._get_html5_duration());
+        t._onload(true);
+      }
+    }),
+
+    loadedmetadata: _html5_event(function(e) {
+      //_s._wD(_h5+'loadedmetadata: '+this._t.sID);
+    }),
+
+    loadstart: _html5_event(function(e) {
+      //_s._wD(_h5+'loadstart: '+this._t.sID);
+      // assume buffering at first
+      this._t._onbufferchange(1);
+    }),
+
+    play: _html5_event(function(e) {
+      //_s._wD(_h5+'play: '+this._t.sID+', '+this._t.url);
+      // once play starts, no buffering
+      this._t._onbufferchange(0);
+    }),
+
+    // TODO: verify if this is actually implemented anywhere yet.
+    playing: _html5_event(function(e) {
+      //_s._wD(_h5+'playing: '+this._t.sID+', '+this._t.url);
+      // once play starts, no buffering
+      this._t._onbufferchange(0);
+    }),
+
+    progress: _html5_event(function(e) {
+
+      if (this._t.loaded) {
+        return false;
+      }
+
+      var i, j, str, buffered = 0,
+          isProgress = (e.type === 'progress'),
+          ranges = e.target.buffered,
+          loaded = (e.loaded||0), // firefox 3.6 implements e.loaded/total (bytes)
+          total = (e.total||1);
+
+      if (ranges && ranges.length) {
+
+        // if loaded is 0, try TimeRanges implementation as % of load
+        // https://developer.mozilla.org/en/DOM/TimeRanges
+        for (i=ranges.length; i--;) {
+          buffered = (ranges.end(i) - ranges.start(i));
+        }
+
+        // linear case, buffer sum; does not account for seeking and HTTP partials / byte ranges
+        loaded = buffered/e.target.duration;
+
+        /*
+        if (isProgress && ranges.length > 1) {
+          str = [];
+          j = ranges.length;
+          for (i=0; i<j; i++) {
+            str.push(e.target.buffered.start(i) +'-'+ e.target.buffered.end(i));
+          }
+          //_s._wD(_h5+'progress: timeRanges: '+str.join(', '));
+        }
+        */
+
+        if (isProgress && !isNaN(loaded)) {
+          //_s._wD(_h5+'progress: '+this._t.sID+': ' + Math.floor(loaded*100)+'% loaded');
+        }
+
+      }
+
+      if (!isNaN(loaded)) {
+
+        this._t._onbufferchange(0); // if progress, likely not buffering
+        this._t._whileloading(loaded, total, this._t._get_html5_duration());
+
+        if (loaded && total && loaded === total) {
+          // in case "onload" doesn't fire (eg. gecko 1.9.2)
+          _html5_events.load.call(this, e);
+        }
+
+      }
+
+    }),
+
+    ratechange: _html5_event(function(e) {
+      //_s._wD(_h5+'ratechange: '+this._t.sID);
+    }),
+
+    suspend: _html5_event(function(e) {
+      // download paused/stopped, may have finished (eg. onload)
+      //_s._wD(_h5+'suspend: '+this._t.sID);
+      _html5_events.progress.call(this, e);
+    }),
+
+    stalled: _html5_event(function(e) {
+      //_s._wD(_h5+'stalled: '+this._t.sID);
+    }),
+
+    timeupdate: _html5_event(function(e) {
+      this._t._onTimer();
+    }),
+
+    waiting: _html5_event(function(e) { // see also: seeking
+      //_s._wD(_h5+'waiting: '+this._t.sID);
+      // playback faster than download rate, etc.
+      this._t._onbufferchange(1);
+    })
+
+  };
+
+  /*
+   * SMSound() (sound object) instance
+  */
+
+  SMSound = function(oOptions) {
+
+    var _t = this, _resetProperties, _stop_html5_timer, _start_html5_timer;
+    this.sID = oOptions.id;
+    this.url = oOptions.url;
+    this.options = _mixin(oOptions);
+    this.instanceOptions = this.options; // per-play-instance-specific options
+    this._iO = this.instanceOptions; // short alias
+    // assign property defaults
+    this.pan = this.options.pan;
+    this.volume = this.options.volume;
+    this._lastURL = null;
+    this.isHTML5 = false;
+    this._a = null;
+
+    // --- public methods ---
+
+    this.id3 = {};
+
+    this._debug = function() {
+      /*
+      // pseudo-private console.log()-style output
+      if (_s.debugMode) {
+        var stuff = null, msg = [], sF, sfBracket, maxLength = 64;
+        for (stuff in _t.options) {
+          if (_t.options[stuff] !== null) {
+            if (_t.options[stuff] instanceof Function) {
+              // handle functions specially
+              sF = _t.options[stuff].toString();
+              sF = sF.replace(/\s\s+/g, ' '); // normalize spaces
+              sfBracket = sF.indexOf('{');
+              msg.push(' ' + stuff + ': {' + sF.substr(sfBracket + 1, (Math.min(Math.max(sF.indexOf('\n') - 1, maxLength), maxLength))).replace(/\n/g, '') + '... }');
+            } else {
+              msg.push(' ' + stuff + ': ' + _t.options[stuff]);
+            }
+          }
+        }
+        //_s._wD('SMSound() merged options: {\n' + msg.join(', \n') + '\n}');
+      }
+      */
+    };
+
+    /*
+    this._debug();
+    */
+
+    this.load = function(oOptions) {
+      var oS = null;
+      if (typeof oOptions !== 'undefined') {
+        _t._iO = _mixin(oOptions, _t.options);
+        _t.instanceOptions = _t._iO;
+      } else {
+        oOptions = _t.options;
+        _t._iO = oOptions;
+        _t.instanceOptions = _t._iO;
+        if (_t._lastURL && _t._lastURL !== _t.url) {
+          //_wDS('manURL');
+          _t._iO.url = _t.url;
+          _t.url = null;
+        }
+      }
+      if (!_t._iO.url) {
+        _t._iO.url = _t.url;
+      }
+      //_s._wD('SMSound.load(): ' + _t._iO.url, 1);
+      if (_t._iO.url === _t.url && _t.readyState !== 0 && _t.readyState !== 2) {
+        //_wDS('onURL', 1);
+        return _t;
+      }
+      _t._lastURL = _t.url;
+      _t.loaded = false;
+      _t.readyState = 1;
+      _t.playState = 0;
+      if (_html5OK(_t._iO)) {
+        oS = _t._setup_html5(_t._iO);
+        if (!oS._called_load) {
+          //_s._wD(_h5+'load: '+_t.sID);
+          _t._html5_canplay = false;
+          oS.load();
+          oS._called_load = true;
+          if (_t._iO.autoPlay) {
+            _t.play();
+          }
+        } else {
+          //_s._wD(_h5+'ignoring request to load again: '+_t.sID);
+        }
+      } else {
+        try {
+          _t.isHTML5 = false;
+          _t._iO = _policyFix(_loopFix(_t._iO));
+          if (_fV === 8) {
+            _s.o._load(_t.sID, _t._iO.url, _t._iO.stream, _t._iO.autoPlay, (_t._iO.whileloading?1:0), _t._iO.loops||1, _t._iO.usePolicyFile);
+          } else {
+            _s.o._load(_t.sID, _t._iO.url, _t._iO.stream?true:false, _t._iO.autoPlay?true:false, _t._iO.loops||1, _t._iO.autoLoad?true:false, _t._iO.usePolicyFile);
+          }
+        } catch(e) {
+          //_wDS('smError', 2);
+          //_debugTS('onload', false);
+          _catchError({type:'SMSOUND_LOAD_JS_EXCEPTION', fatal:true});
+        }
+      }
+      return _t;
+    };
+
+    this.unload = function() {
+      // Flash 8/AS2 can't "close" a stream - fake it by loading an empty MP3
+      // Flash 9/AS3: Close stream, preventing further load
+      if (_t.readyState !== 0) {
+        //_s._wD('SMSound.unload(): "' + _t.sID + '"');
+        if (!_t.isHTML5) {
+          if (_fV === 8) {
+            _s.o._unload(_t.sID, _s.nullURL);
+          } else {
+            _s.o._unload(_t.sID);
+          }
+        } else {
+          _stop_html5_timer();
+          if (_t._a) {
+            // abort()-style method here, stop loading? (doesn't exist?)
+            _t._a.pause();
+            _t._a.src = ''; // https://developer.mozilla.org/En/Using_audio_and_video_in_Firefox#Stopping_the_download_of_media
+          }
+        }
+        // reset load/status flags
+        _resetProperties();
+      }
+      return _t;
+    };
+
+    this.destruct = function(_bFromSM) {
+      //_s._wD('SMSound.destruct(): "' + _t.sID + '"');
+      if (!_t.isHTML5) {
+        // kill sound within Flash
+        // Disable the onfailure handler
+        _t._iO.onfailure = null;
+        _s.o._destroySound(_t.sID);
+      } else {
+        _stop_html5_timer();
+        if (_t._a) {
+          // abort()-style method here, stop loading? (doesn't exist?)
+          _t._a.pause();
+          _t._a.src = ''; // https://developer.mozilla.org/En/Using_audio_and_video_in_Firefox#Stopping_the_download_of_media
+          if (!_useGlobalHTML5Audio) {
+            _t._remove_html5_events();
+          }
+          _t._a._t = null; // break potential circular reference
+          _t._a = null;
+        }
+      }
+      if (!_bFromSM) {
+        _s.destroySound(_t.sID, true); // ensure deletion from controller
+      }
+    };
+
+    this.play = function(oOptions, _updatePlayState) {
+      var fN = 'SMSound.play(): ', allowMulti, a;
+      _updatePlayState = _updatePlayState === undefined ? true : _updatePlayState; // default to true
+      if (!oOptions) {
+        oOptions = {};
+      }
+      _t._iO = _mixin(oOptions, _t._iO);
+      _t._iO = _mixin(_t._iO, _t.options);
+      _t.instanceOptions = _t._iO;
+      if (_t._iO.serverURL && !_t.connected) {
+        if (!_t.getAutoPlay()) {
+          //_s._wD(fN+' Netstream not connected yet - setting autoPlay');
+          _t.setAutoPlay(true);
+        }
+        return _t; // play will be called in _onconnect()
+      }
+      if (_html5OK(_t._iO)) {
+        _t._setup_html5(_t._iO);
+        _start_html5_timer();
+      }
+      if (_t.playState === 1 && !_t.paused) {
+        allowMulti = _t._iO.multiShot;
+        if (!allowMulti) {
+          //_s._wD(fN + '"' + _t.sID + '" already playing (one-shot)', 1);
+          return _t;
+        } else {
+          //_s._wD(fN + '"' + _t.sID + '" already playing (multi-shot)', 1);
+        }
+      }
+      if (!_t.loaded) {
+        if (_t.readyState === 0) {
+          //_s._wD(fN + 'Attempting to load "' + _t.sID + '"', 1);
+          // try to get this sound playing ASAP
+          if (!_t.isHTML5) {
+            _t._iO.autoPlay = true; // assign directly because setAutoPlay() increments the instanceCount
+          }
+          _t.load(_t._iO);
+        } else if (_t.readyState === 2) {
+          //_s._wD(fN + 'Could not load "' + _t.sID + '" - exiting', 2);
+          return _t;
+        } else {
+          //_s._wD(fN + '"' + _t.sID + '" is loading - attempting to play..', 1);
+        }
+      } else {
+        //_s._wD(fN + '"' + _t.sID + '"');
+      }
+      if (!_t.isHTML5 && _fV === 9 && _t.position > 0 && _t.position === _t.duration) {
+        // flash 9 needs a position reset if play() is called while at the end of a sound.
+        //_s._wD(fN + '"' + _t.sID + '": Sound at end, resetting to position:0');
+        _t._iO.position = 0;
+      }
+      /*
+       * Streams will pause when their buffer is full if they are being loaded.
+       * In this case paused is true, but the song hasn't started playing yet.
+       * If we just call resume() the onplay() callback will never be called.
+       * So only call resume() if the position is > 0.
+       * Another reason is because options like volume won't have been applied yet.
+      */
+      if (_t.paused && _t.position && _t.position > 0) { // https://gist.github.com/37b17df75cc4d7a90bf6
+        //_s._wD(fN + '"' + _t.sID + '" is resuming from paused state',1);
+        _t.resume();
+      } else {
+        //_s._wD(fN+'"'+ _t.sID+'" is starting to play');
+        _t.playState = 1;
+        _t.paused = false;
+        if (!_t.instanceCount || _t._iO.multiShotEvents || (!_t.isHTML5 && _fV > 8 && !_t.getAutoPlay())) {
+          _t.instanceCount++;
+        }
+        _t.position = (typeof _t._iO.position !== 'undefined' && !isNaN(_t._iO.position)?_t._iO.position:0);
+        if (!_t.isHTML5) {
+          _t._iO = _policyFix(_loopFix(_t._iO));
+        }
+        if (_t._iO.onplay && _updatePlayState) {
+          _t._iO.onplay.apply(_t);
+          _t._onplay_called = true;
+        }
+        _t.setVolume(_t._iO.volume, true);
+        _t.setPan(_t._iO.pan, true);
+        if (!_t.isHTML5) {
+          _s.o._start(_t.sID, _t._iO.loops || 1, (_fV === 9?_t._iO.position:_t._iO.position / 1000));
+        } else {
+          _start_html5_timer();
+          a = _t._setup_html5();
+          _t.setPosition(_t._iO.position);
+          a.play();
+        }
+      }
+      return _t;
+    };
+
+    this.start = this.play; // just for convenience
+
+    this.stop = function(bAll) {
+      if (_t.playState === 1) {
+        _t._onbufferchange(0);
+        _t.resetOnPosition(0);
+        if (!_t.isHTML5) {
+          _t.playState = 0;
+        }
+        _t.paused = false;
+        if (_t._iO.onstop) {
+          _t._iO.onstop.apply(_t);
+        }
+        if (!_t.isHTML5) {
+          _s.o._stop(_t.sID, bAll);
+          // hack for netStream: just unload
+          if (_t._iO.serverURL) {
+            _t.unload();
+          }
+        } else {
+          if (_t._a) {
+            _t.setPosition(0); // act like Flash, though
+            _t._a.pause(); // html5 has no stop()
+            _t.playState = 0;
+            _t._onTimer(); // and update UI
+            _stop_html5_timer();
+            _t.unload();
+          }
+        }
+        _t.instanceCount = 0;
+        _t._iO = {};
+      }
+      return _t;
+    };
+
+    this.setAutoPlay = function(autoPlay) {
+      //_s._wD('sound '+_t.sID+' turned autoplay ' + (autoPlay ? 'on' : 'off'));
+      _t._iO.autoPlay = autoPlay;
+      if (!_t.isHTML5) {
+        _s.o._setAutoPlay(_t.sID, autoPlay);
+        if (autoPlay) {
+          // only increment the instanceCount if the sound isn't loaded (TODO: verify RTMP)
+          if (!_t.instanceCount && _t.readyState === 1) {
+            _t.instanceCount++;
+            //_s._wD('sound '+_t.sID+' incremented instance count to '+_t.instanceCount);
+          }
+        }
+      }
+    };
+
+    this.getAutoPlay = function() {
+      return _t._iO.autoPlay;
+    };
+
+    this.setPosition = function(nMsecOffset) {
+      if (nMsecOffset === undefined) {
+        nMsecOffset = 0;
+      }
+      // Use the duration from the instance options, if we don't have a track duration yet.
+      var original_pos, position, position1K,
+          offset = (_t.isHTML5 ? Math.max(nMsecOffset,0) : Math.min(_t.duration || _t._iO.duration, Math.max(nMsecOffset, 0))); // position >= 0 and <= current available (loaded) duration
+      original_pos = _t.position;
+      _t.position = offset;
+      position1K = _t.position/1000;
+      _t.resetOnPosition(_t.position);
+      _t._iO.position = offset;
+      if (!_t.isHTML5) {
+        position = (_fV === 9 ? _t.position : position1K);
+        if (_t.readyState && _t.readyState !== 2) {
+          _s.o._setPosition(_t.sID, position, (_t.paused || !_t.playState)); // if paused or not playing, will not resume (by playing)
+        }
+      } else if (_t._a) {
+        // Set the position in the canplay handler if the sound is not ready yet
+        if (_t._html5_canplay) {
+          if (_t._a.currentTime !== position1K) {
+            /*
+             * DOM/JS errors/exceptions to watch out for:
+             * if seek is beyond (loaded?) position, "DOM exception 11"
+             * "INDEX_SIZE_ERR": DOM exception 1
+            */
+            //_s._wD('setPosition('+position1K+'): setting position');
+            try {
+              _t._a.currentTime = position1K;
+              if (_t.playState === 0 || _t.paused) {
+                // allow seek without auto-play/resume
+                _t._a.pause();
+              }
+            } catch(e) {
+              //_s._wD('setPosition('+position1K+'): setting position failed: '+e.message, 2);
+            }
+          }
+        } else {
+          //_s._wD('setPosition('+position1K+'): delaying, sound not ready');
+        }
+      }
+      if (_t.isHTML5) {
+        if (_t.paused) { // if paused, refresh UI right away
+          _t._onTimer(true); // force update
+        }
+      }
+      return _t;
+    };
+
+    this.pause = function(bCallFlash) {
+      if (_t.paused || (_t.playState === 0 && _t.readyState !== 1)) {
+        return _t;
+      }
+      //_s._wD('SMSound.pause()');
+      _t.paused = true;
+      if (!_t.isHTML5) {
+        if (bCallFlash || bCallFlash === undefined) {
+          _s.o._pause(_t.sID);
+        }
+      } else {
+        _t._setup_html5().pause();
+        _stop_html5_timer();
+      }
+      if (_t._iO.onpause) {
+        _t._iO.onpause.apply(_t);
+      }
+      return _t;
+    };
+
+    /*
+     * When auto-loaded streams pause on buffer full they have a playState of 0.
+     * We need to make sure that the playState is set to 1 when these streams "resume".
+     * When a paused stream is resumed, we need to trigger the onplay() callback if it
+     * hasn't been called already. In this case since the sound is being played for the
+     * first time, I think it's more appropriate to call onplay() rather than onresume().
+    */
+    this.resume = function() {
+      if (!_t.paused) {
+        return _t;
+      }
+      //_s._wD('SMSound.resume()');
+      _t.paused = false;
+      _t.playState = 1;
+      if (!_t.isHTML5) {
+        if (_t._iO.isMovieStar) {
+          // Bizarre Webkit bug (Chrome reported via 8tracks.com dudes): AAC content paused for 30+ seconds(?) will not resume without a reposition.
+          _t.setPosition(_t.position);
+        }
+        _s.o._pause(_t.sID); // flash method is toggle-based (pause/resume)
+      } else {
+        _t._setup_html5().play();
+        _start_html5_timer();
+      }
+      if (!_t._onplay_called && _t._iO.onplay) {
+        _t._iO.onplay.apply(_t);
+        _t._onplay_called = true;
+      } else if (_t._iO.onresume) {
+        _t._iO.onresume.apply(_t);
+      }
+      return _t;
+    };
+
+    this.togglePause = function() {
+      //_s._wD('SMSound.togglePause()');
+      if (_t.playState === 0) {
+        _t.play({
+          position: (_fV === 9 && !_t.isHTML5 ? _t.position : _t.position / 1000)
+        });
+        return _t;
+      }
+      if (_t.paused) {
+        _t.resume();
+      } else {
+        _t.pause();
+      }
+      return _t;
+    };
+
+    this.setPan = function(nPan, bInstanceOnly) {
+      if (typeof nPan === 'undefined') {
+        nPan = 0;
+      }
+      if (typeof bInstanceOnly === 'undefined') {
+        bInstanceOnly = false;
+      }
+      if (!_t.isHTML5) {
+        _s.o._setPan(_t.sID, nPan);
+      } // else { no HTML5 pan? }
+      _t._iO.pan = nPan;
+      if (!bInstanceOnly) {
+        _t.pan = nPan;
+        _t.options.pan = nPan;
+      }
+      return _t;
+    };
+
+    this.setVolume = function(nVol, bInstanceOnly) {
+      if (typeof nVol === 'undefined') {
+        nVol = 100;
+      }
+      if (typeof bInstanceOnly === 'undefined') {
+        bInstanceOnly = false;
+      }
+      if (!_t.isHTML5) {
+        _s.o._setVolume(_t.sID, (_s.muted && !_t.muted) || _t.muted?0:nVol);
+      } else if (_t._a) {
+        _t._a.volume = Math.max(0, Math.min(1, nVol/100)); // valid range: 0-1
+      }
+      _t._iO.volume = nVol;
+      if (!bInstanceOnly) {
+        _t.volume = nVol;
+        _t.options.volume = nVol;
+      }
+      return _t;
+    };
+
+    this.mute = function() {
+      _t.muted = true;
+      if (!_t.isHTML5) {
+        _s.o._setVolume(_t.sID, 0);
+      } else if (_t._a) {
+        _t._a.muted = true;
+      }
+      return _t;
+    };
+
+    this.unmute = function() {
+      _t.muted = false;
+      var hasIO = typeof _t._iO.volume !== 'undefined';
+      if (!_t.isHTML5) {
+        _s.o._setVolume(_t.sID, hasIO?_t._iO.volume:_t.options.volume);
+      } else if (_t._a) {
+        _t._a.muted = false;
+      }
+      return _t;
+    };
+
+    this.toggleMute = function() {
+      return (_t.muted?_t.unmute():_t.mute());
+    };
+
+    this.onposition = function(nPosition, oMethod, oScope) {
+      // TODO: allow for ranges, too? eg. (nPosition instanceof Array)
+      _t._onPositionItems.push({
+        position: nPosition,
+        method: oMethod,
+        scope: (typeof oScope !== 'undefined'?oScope:_t),
+        fired: false
+      });
+      return _t;
+    };
+
+    this.processOnPosition = function() {
+      var i, item, j = _t._onPositionItems.length;
+      if (!j || !_t.playState || _t._onPositionFired >= j) {
+        return false;
+      }
+      for (i=j; i--;) {
+        item = _t._onPositionItems[i];
+        if (!item.fired && _t.position >= item.position) {
+          item.method.apply(item.scope,[item.position]);
+          item.fired = true;
+          _s._onPositionFired++;
+        }
+      }
+      return true;
+    };
+
+    this.resetOnPosition = function(nPosition) {
+      // reset "fired" for items interested in this position
+      var i, item, j = _t._onPositionItems.length;
+      if (!j) {
+        return false;
+      }
+      for (i=j; i--;) {
+        item = _t._onPositionItems[i];
+        if (item.fired && nPosition <= item.position) {
+          item.fired = false;
+          _s._onPositionFired--;
+        }
+      }
+      return true;
+    };
+
+    /*
+     * private internals
+    */
+
+    _start_html5_timer = function() {
+      if (_t.isHTML5) {
+        _startTimer(_t);
+      }
+    };
+
+    _stop_html5_timer = function() {
+      if (_t.isHTML5) {
+        _stopTimer(_t);
+      }
+    };
+
+    _resetProperties = function() {
+      _t._onPositionItems = [];
+      _t._onPositionFired = 0;
+      _t._hasTimer = null;
+      _t._onplay_called = false;
+      _t._a = null;
+      _t._html5_canplay = false;
+      _t.bytesLoaded = null;
+      _t.bytesTotal = null;
+      _t.position = null;
+      _t.duration = (_t._iO && _t._iO.duration?_t._iO.duration:null);
+      _t.durationEstimate = null;
+      _t.failures = 0;
+      _t.loaded = false;
+      _t.playState = 0;
+      _t.paused = false;
+      _t.readyState = 0; // 0 = uninitialised, 1 = loading, 2 = failed/error, 3 = loaded/success
+      _t.muted = false;
+      _t.didBeforeFinish = false;
+      _t.didJustBeforeFinish = false;
+      _t.isBuffering = false;
+      _t.instanceOptions = {};
+      _t.instanceCount = 0;
+      _t.peakData = {
+        left: 0,
+        right: 0
+      };
+      _t.waveformData = {
+        left: [],
+        right: []
+      };
+      _t.eqData = []; // legacy: 1D array
+      _t.eqData.left = [];
+      _t.eqData.right = [];
+    };
+
+    _resetProperties();
+
+    /*
+     * pseudo-private SMSound internals
+    */
+
+    this._onTimer = function(bForce) {
+      // HTML5-only _whileplaying() etc.
+      var time, x = {};
+      if (_t._hasTimer || bForce) {
+        if (_t._a && (bForce || ((_t.playState > 0 || _t.readyState === 1) && !_t.paused))) { // TODO: May not need to track readyState (1 = loading)
+          _t.duration = _t._get_html5_duration();
+          _t.durationEstimate = _t.duration;
+          time = _t._a.currentTime?_t._a.currentTime*1000:0;
+          _t._whileplaying(time,x,x,x,x);
+          return true;
+        } else {
+         //_s._wD('_onTimer: Warn for "'+_t.sID+'": '+(!_t._a?'Could not find element. ':'')+(_t.playState === 0?'playState bad, 0?':'playState = '+_t.playState+', OK'));
+          return false;
+        }
+      }
+    };
+
+    this._get_html5_duration = function() {
+      var d = (_t._a ? _t._a.duration*1000 : (_t._iO ? _t._iO.duration : undefined)),
+          result = (d && !isNaN(d) && d !== Infinity ? d : (_t._iO ? _t._iO.duration : null));
+      return result;
+    };
+
+    this._setup_html5 = function(oOptions) {
+      var _iO = _mixin(_t._iO, oOptions), d = decodeURI,
+          _a = _useGlobalHTML5Audio ? _s._global_a : _t._a,
+          _dURL = d(_iO.url),
+          _oldIO = (_a && _a._t ? _a._t.instanceOptions : null);
+      if (_a) {
+        if (_a._t && _oldIO.url === _iO.url && (!_t._lastURL || (_t._lastURL === _oldIO.url))) {
+          return _a; // same url, ignore request
+        }
+        //_s._wD('setting new URL on existing object: ' + _dURL + (_t._lastURL ? ', old URL: ' + _t._lastURL : ''));
+        /*
+         * "First things first, I, Poppa.." (reset the previous state of the old sound, if playing)
+         * Fixes case with devices that can only play one sound at a time
+         * Otherwise, other sounds in mid-play will be terminated without warning and in a stuck state
+        */
+        if (_useGlobalHTML5Audio && _a._t && _a._t.playState && _iO.url !== _oldIO.url) {
+          _a._t.stop();
+        }
+        _resetProperties(); // new URL, so reset load/playstate and so on
+        _a.src = _iO.url;
+        _t.url = _iO.url;
+        _t._lastURL = _iO.url;
+        _a._called_load = false;
+      } else {
+        //_s._wD('creating HTML5 Audio() element with URL: '+_dURL);
+        _a = new Audio(_iO.url);
+        _a._called_load = false;
+        if (_useGlobalHTML5Audio) {
+          _s._global_a = _a;
+        }
+      }
+      _t.isHTML5 = true;
+      _t._a = _a; // store a ref on the track
+      _a._t = _t; // store a ref on the audio
+      _t._add_html5_events();
+      _a.loop = (_iO.loops>1?'loop':'');
+      if (_iO.autoLoad || _iO.autoPlay) {
+        _a.autobuffer = 'auto'; // early HTML5 implementation (non-standard)
+        _a.preload = 'auto'; // standard
+        _t.load();
+        _a._called_load = true;
+      } else {
+        _a.autobuffer = false; // early HTML5 implementation (non-standard)
+        _a.preload = 'none'; // standard
+      }
+      _a.loop = (_iO.loops>1?'loop':''); // boolean instead of "loop", for webkit? - spec says string. http://www.w3.org/TR/html-markup/audio.html#audio.attrs.loop
+      return _a;
+    };
+
+    this._add_html5_events = function() {
+
+      if (_t._a._added_events) {
+        return false;
+      }
+
+      var f;
+
+      function add(oEvt, oFn, bCapture) {
+        return _t._a ? _t._a.addEventListener(oEvt, oFn, bCapture||false) : null;
+      }
+
+      //_s._wD(_h5+'adding event listeners: '+_t.sID);
+      _t._a._added_events = true;
+
+      for (f in _html5_events) {
+        if (_html5_events.hasOwnProperty(f)) {
+          add(f, _html5_events[f]);
+        }
+      }
+
+      return true;
+
+    };
+
+    this._remove_html5_events = function() {
+
+      // Remove event listeners
+
+      var f;
+
+      function remove(oEvt, oFn, bCapture) {
+        return (_t._a ? _t._a.removeEventListener(oEvt, oFn, bCapture||false) : null);
+      }
+
+      //_s._wD(_h5+'removing event listeners: '+_t.sID);
+      _t._a._added_events = false;
+
+      for (f in _html5_events) {
+        if (_html5_events.hasOwnProperty(f)) {
+          remove(f, _html5_events[f]);
+        }
+      }
+
+    };
+
+    /*
+     * pseudo-private event internals
+    */
+
+    this._onload = function(nSuccess) {
+      var fN = 'SMSound._onload(): ', loadOK = (nSuccess?true:false);
+      //_s._wD(fN + '"' + _t.sID + '"' + (loadOK?' loaded.':' failed to load? - ' + _t.url), (loadOK?1:2));
+      /*
+      if (!loadOK && !_t.isHTML5) {
+        if (_s.sandbox.noRemote === true) {
+          //_s._wD(fN + _str('noNet'), 1);
+        }
+        if (_s.sandbox.noLocal === true) {
+          //_s._wD(fN + _str('noLocal'), 1);
+        }
+      }
+      */
+      _t.loaded = loadOK;
+      _t.readyState = loadOK?3:2;
+      _t._onbufferchange(0);
+      if (_t._iO.onload) {
+        _t._iO.onload.apply(_t, [loadOK]);
+      }
+      return true;
+    };
+
+    this._onbufferchange = function(nIsBuffering) {
+      var fN = 'SMSound._onbufferchange()';
+      if (_t.playState === 0) {
+        // ignore if not playing
+        return false;
+      }
+      if ((nIsBuffering && _t.isBuffering) || (!nIsBuffering && !_t.isBuffering)) {
+        return false;
+      }
+      _t.isBuffering = (nIsBuffering === 1);
+      if (_t._iO.onbufferchange) {
+        //_s._wD(fN + ': ' + nIsBuffering);
+        _t._iO.onbufferchange.apply(_t);
+      }
+      return true;
+    };
+
+    /*
+     * flash-only method, should fire only once at most
+     * at this point we just recreate failed sounds rather than trying to reconnect
+    */
+    this._onfailure = function(msg, level, code) {
+      _t.failures++;
+      //_s._wD('SMSound._onfailure(): "'+_t.sID+'" count '+_t.failures);
+      if (_t._iO.onfailure && _t.failures === 1) {
+        _t._iO.onfailure(_t, msg, level, code);
+      } else {
+        //_s._wD('SMSound._onfailure(): ignoring');
+      }
+    };
+
+    this._onbeforefinish = function() {
+      if (!_t.didBeforeFinish) {
+        _t.didBeforeFinish = true;
+        if (_t._iO.onbeforefinish) {
+          //_s._wD('SMSound._onbeforefinish(): "' + _t.sID + '"');
+          _t._iO.onbeforefinish.apply(_t);
+        }
+      }
+    };
+
+    this._onjustbeforefinish = function(msOffset) {
+      if (!_t.didJustBeforeFinish) {
+        _t.didJustBeforeFinish = true;
+        if (_t._iO.onjustbeforefinish) {
+          //_s._wD('SMSound._onjustbeforefinish(): "' + _t.sID + '"');
+          _t._iO.onjustbeforefinish.apply(_t);
+        }
+      }
+    };
+
+    this._onfinish = function() {
+      var _io_onfinish = _t._iO.onfinish; // store local copy before it gets trashed..
+      _t._onbufferchange(0);
+      _t.resetOnPosition(0);
+      if (_t._iO.onbeforefinishcomplete) {
+        _t._iO.onbeforefinishcomplete.apply(_t);
+      }
+      // reset some state items
+      _t.didBeforeFinish = false;
+      _t.didJustBeforeFinish = false;
+      if (_t.instanceCount) {
+        _t.instanceCount--;
+        if (!_t.instanceCount) {
+          // reset instance options
+          _t.playState = 0;
+          _t.paused = false;
+          _t.instanceCount = 0;
+          _t.instanceOptions = {};
+          _t._iO = {};
+          _stop_html5_timer();
+        }
+        if (!_t.instanceCount || _t._iO.multiShotEvents) {
+          // fire onfinish for last, or every instance
+          if (_io_onfinish) {
+            //_s._wD('SMSound._onfinish(): "' + _t.sID + '"');
+            _io_onfinish.apply(_t);
+          }
+        }
+      }
+    };
+
+    this._whileloading = function(nBytesLoaded, nBytesTotal, nDuration, nBufferLength) {
+      _t.bytesLoaded = nBytesLoaded;
+      _t.bytesTotal = nBytesTotal;
+      _t.duration = Math.floor(nDuration);
+      _t.bufferLength = nBufferLength;
+      if (!_t._iO.isMovieStar) {
+        if (_t._iO.duration) {
+          // use options, if specified and larger
+          _t.durationEstimate = (_t.duration > _t._iO.duration) ? _t.duration : _t._iO.duration;
+        } else {
+          _t.durationEstimate = parseInt((_t.bytesTotal / _t.bytesLoaded) * _t.duration, 10);
+        }
+        if (_t.durationEstimate === undefined) {
+          _t.durationEstimate = _t.duration;
+        }
+        if (_t.readyState !== 3 && _t._iO.whileloading) {
+          _t._iO.whileloading.apply(_t);
+        }
+      } else {
+        _t.durationEstimate = _t.duration;
+        if (_t.readyState !== 3 && _t._iO.whileloading) {
+          _t._iO.whileloading.apply(_t);
+        }
+      }
+    };
+
+    this._whileplaying = function(nPosition, oPeakData, oWaveformDataLeft, oWaveformDataRight, oEQData) {
+      if (isNaN(nPosition) || nPosition === null) {
+        return false; // flash safety net
+      }
+      _t.position = nPosition;
+      _t.processOnPosition();
+      if (!_t.isHTML5 && _fV > 8) {
+        if (_t._iO.usePeakData && typeof oPeakData !== 'undefined' && oPeakData) {
+          _t.peakData = {
+            left: oPeakData.leftPeak,
+            right: oPeakData.rightPeak
+          };
+        }
+        if (_t._iO.useWaveformData && typeof oWaveformDataLeft !== 'undefined' && oWaveformDataLeft) {
+          _t.waveformData = {
+            left: oWaveformDataLeft.split(','),
+            right: oWaveformDataRight.split(',')
+          };
+        }
+        if (_t._iO.useEQData) {
+          if (typeof oEQData !== 'undefined' && oEQData && oEQData.leftEQ) {
+            var eqLeft = oEQData.leftEQ.split(',');
+            _t.eqData = eqLeft;
+            _t.eqData.left = eqLeft;
+            if (typeof oEQData.rightEQ !== 'undefined' && oEQData.rightEQ) {
+              _t.eqData.right = oEQData.rightEQ.split(',');
+            }
+          }
+        }
+      }
+      if (_t.playState === 1) {
+        // special case/hack: ensure buffering is false if loading from cache (and not yet started)
+        if (!_t.isHTML5 && _s.flashVersion === 8 && !_t.position && _t.isBuffering) {
+          _t._onbufferchange(0);
+        }
+        if (_t._iO.whileplaying) {
+          _t._iO.whileplaying.apply(_t); // flash may call after actual finish
+        }
+        if ((_t.loaded || (!_t.loaded && _t._iO.isMovieStar)) && _t._iO.onbeforefinish && _t._iO.onbeforefinishtime && !_t.didBeforeFinish && _t.duration - _t.position <= _t._iO.onbeforefinishtime) {
+          _t._onbeforefinish();
+        }
+      }
+      return true;
+    };
+
+    this._onid3 = function(oID3PropNames, oID3Data) {
+      // oID3PropNames: string array (names)
+      // ID3Data: string array (data)
+      //_s._wD('SMSound._onid3(): "' + this.sID + '" ID3 data received.');
+      var oData = [], i, j;
+      for (i = 0, j = oID3PropNames.length; i < j; i++) {
+        oData[oID3PropNames[i]] = oID3Data[i];
+      }
+      _t.id3 = _mixin(_t.id3, oData);
+      if (_t._iO.onid3) {
+        _t._iO.onid3.apply(_t);
+      }
+    };
+
+    // flash + RTMP
+    this._onconnect = function(bSuccess) {
+      var fN = 'SMSound._onconnect(): ';
+      bSuccess = (bSuccess === 1);
+      //_s._wD(fN+'"'+_t.sID+'"'+(bSuccess?' connected.':' failed to connect? - '+_t.url), (bSuccess?1:2));
+      _t.connected = bSuccess;
+      if (bSuccess) {
+        _t.failures = 0;
+        if (_idCheck(_t.sID)) {
+          if (_t.getAutoPlay()) {
+            _t.play(undefined, _t.getAutoPlay()); // only update the play state if auto playing
+          } else if (_t._iO.autoLoad) {
+            _t.load();
+          }
+        }
+        if (_t._iO.onconnect) {
+          _t._iO.onconnect.apply(_t,[bSuccess]);
+        }
+      }
+    };
+
+    this._ondataerror = function(sError) {
+      // flash 9 wave/eq data handler
+      if (_t.playState > 0) { // hack: called at start, and end from flash at/after onfinish()
+        //_s._wD('SMSound._ondataerror(): ' + sError);
+        if (_t._iO.ondataerror) {
+          _t._iO.ondataerror.apply(_t);
+        }
+      }
+    };
+
+  }; // SMSound()
+
+  /*
+   * private soundManager internals
+  */
+
+  _getDocument = function() {
+    return (_doc.body || _doc._docElement || _doc.getElementsByTagName('div')[0]);
+  };
+
+  _id = function(sID) {
+    return _doc.getElementById(sID);
+  };
+
+  _mixin = function(oMain, oAdd) {
+    // non-destructive merge
+    var o1 = {}, i, o2, o;
+    for (i in oMain) { // clone c1
+      if (oMain.hasOwnProperty(i)) {
+        o1[i] = oMain[i];
+      }
+    }
+    o2 = (typeof oAdd === 'undefined'?_s.defaultOptions:oAdd);
+    for (o in o2) {
+      if (o2.hasOwnProperty(o) && typeof o1[o] === 'undefined') {
+        o1[o] = o2[o];
+      }
+    }
+    return o1;
+  };
+
+  _event = (function() {
+
+    var old = (_win.attachEvent),
+    evt = {
+      add: (old?'attachEvent':'addEventListener'),
+      remove: (old?'detachEvent':'removeEventListener')
+    };
+
+    function getArgs(oArgs) {
+      var args = _slice.call(oArgs), len = args.length;
+      if (old) {
+        args[1] = 'on' + args[1]; // prefix
+        if (len > 3) {
+          args.pop(); // no capture
+        }
+      } else if (len === 3) {
+        args.push(false);
+      }
+      return args;
+    }
+
+    function apply(args, sType) {
+      var element = args.shift(),
+          method = [evt[sType]];
+      if (old) {
+        element[method](args[0], args[1]);
+      } else {
+        element[method].apply(element, args);
+      }
+    }
+
+    function add() {
+      apply(getArgs(arguments), 'add');
+    }
+
+    function remove() {
+      apply(getArgs(arguments), 'remove');
+    }
+
+    return {
+      'add': add,
+      'remove': remove
+    };
+
+  }());
+
+  _html5OK = function(iO) {
+    return (!iO.serverURL && (iO.type?_html5CanPlay({type:iO.type}):_html5CanPlay({url:iO.url})||_s.html5Only)); // Use type, if specified. If HTML5-only mode, no other options, so just give 'er
+  };
+
+  _html5CanPlay = function(o) {
+
+    /*
+     * try to find MIME, test and return truthiness
+     * o = {
+     *  url: '/path/to/an.mp3',
+     *  type: 'audio/mp3'
+     * }
+    */
+
+    if (!_s.useHTML5Audio || !_s.hasHTML5) {
+      return false;
+    }
+
+    var url = (o.url || null),
+        mime = (o.type || null),
+        aF = _s.audioFormats,
+        result,
+        offset,
+        fileExt,
+        item;
+
+    function preferFlashCheck(kind) {
+      // whether flash should play a given type
+      return (_s.preferFlash && _hasFlash && !_s.ignoreFlash && (typeof _s.flash[kind] !== 'undefined' && _s.flash[kind]));
+    }
+
+    // account for known cases like audio/mp3
+    if (mime && _s.html5[mime] !== 'undefined') {
+      return (_s.html5[mime] && !preferFlashCheck(mime));
+    }
+
+    if (!_html5Ext) {
+      _html5Ext = [];
+      for (item in aF) {
+        if (aF.hasOwnProperty(item)) {
+          _html5Ext.push(item);
+          if (aF[item].related) {
+            _html5Ext = _html5Ext.concat(aF[item].related);
+          }
+        }
+      }
+      _html5Ext = new RegExp('\\.('+_html5Ext.join('|')+')(\\?.*)?$','i');
+    }
+
+    fileExt = (url ? url.toLowerCase().match(_html5Ext) : null); // TODO: Strip URL queries, etc.
+
+    if (!fileExt || !fileExt.length) {
+      if (!mime) {
+        return false;
+      } else {
+        // audio/mp3 -> mp3, result should be known
+        offset = mime.indexOf(';');
+        fileExt = (offset !== -1?mime.substr(0,offset):mime).substr(6); // strip "audio/X; codecs.."
+      }
+    } else {
+      fileExt = fileExt[1]; // match the raw extension name - "mp3", for example
+    }
+
+    if (fileExt && typeof _s.html5[fileExt] !== 'undefined') {
+      // result known
+      return (_s.html5[fileExt] && !preferFlashCheck(fileExt));
+    } else {
+      mime = 'audio/'+fileExt;
+      result = _s.html5.canPlayType({type:mime});
+      _s.html5[fileExt] = result;
+      // //_s._wD('canPlayType, found result: '+result);
+      return (result && _s.html5[mime] && !preferFlashCheck(mime));
+    }
+
+  };
+
+  _testHTML5 = function() {
+
+    if (!_s.useHTML5Audio || typeof Audio === 'undefined') {
+      return false;
+    }
+
+    // double-whammy: Opera 9.64 throws WRONG_ARGUMENTS_ERR if no parameter passed to Audio(), and Webkit + iOS happily tries to load "null" as a URL. :/
+    var a = (typeof Audio !== 'undefined' ? (_isOpera ? new Audio(null) : new Audio()) : null),
+        item, support = {}, aF, i;
+
+    function _cp(m) {
+      var canPlay, i, j, isOK = false;
+      if (!a || typeof a.canPlayType !== 'function') {
+        return false;
+      }
+      if (m instanceof Array) {
+        // iterate through all mime types, return any successes
+        for (i=0, j=m.length; i<j && !isOK; i++) {
+          if (_s.html5[m[i]] || a.canPlayType(m[i]).match(_s.html5Test)) {
+            isOK = true;
+            _s.html5[m[i]] = true;
+            // if flash can play and preferred, also mark it for use.
+            _s.flash[m[i]] = !!(_s.preferFlash && _hasFlash && m[i].match(_flashMIME));
+          }
+        }
+        return isOK;
+      } else {
+        canPlay = (a && typeof a.canPlayType === 'function' ? a.canPlayType(m) : false);
+        return !!(canPlay && (canPlay.match(_s.html5Test)));
+      }
+    }
+
+    // test all registered formats + codecs
+    aF = _s.audioFormats;
+    for (item in aF) {
+      if (aF.hasOwnProperty(item)) {
+        support[item] = _cp(aF[item].type);
+        support['audio/'+item] = support[item]; // write back generic type too, eg. audio/mp3
+        // assign flash
+        if (_s.preferFlash && !_s.ignoreFlash && item.match(_flashMIME)) {
+          _s.flash[item] = true;
+        } else {
+          _s.flash[item] = false;
+        }
+        // assign result to related formats, too
+        if (aF[item] && aF[item].related) {
+          for (i=aF[item].related.length; i--;) {
+            support['audio/'+aF[item].related[i]] = support[item]; // eg. audio/m4a
+            _s.html5[aF[item].related[i]] = support[item];
+            _s.flash[aF[item].related[i]] = support[item];
+          }
+        }
+      }
+    }
+
+    support.canPlayType = (a?_cp:null);
+    _s.html5 = _mixin(_s.html5, support);
+    return true;
+
+  };
+
+  _strings = {
+    /*
+    notReady: 'Not loaded yet - wait for soundManager.onload()/onready()',
+    notOK: 'Audio support is not available.',
+    domError: _smc + 'createMovie(): appendChild/innerHTML call failed. DOM not ready or other error.',
+    spcWmode: _smc + 'createMovie(): Removing wmode, preventing known SWF loading issue(s)',
+    swf404: _sm + ': Verify that %s is a valid path.',
+    tryDebug: 'Try ' + _sm + '.debugFlash = true for more security details (output goes to SWF.)',
+    checkSWF: 'See SWF output for more debug info.',
+    localFail: _sm + ': Non-HTTP page (' + _doc.location.protocol + ' URL?) Review Flash player security settings for this special case:\nhttp://www.macromedia.com/support/documentation/en/flashplayer/help/settings_manager04.html\nMay need to add/allow path, eg. c:/sm2/ or /users/me/sm2/',
+    waitFocus: _sm + ': Special case: Waiting for focus-related event..',
+    waitImpatient: _sm + ': Getting impatient, still waiting for Flash%s...',
+    waitForever: _sm + ': Waiting indefinitely for Flash (will recover if unblocked)...',
+    needFunction: _sm + ': Function object expected for %s',
+    badID: 'Warning: Sound ID "%s" should be a string, starting with a non-numeric character',
+    noMS: 'MovieStar mode not enabled. Exiting.',
+    currentObj: '--- ' + _sm + '._debug(): Current sound objects ---',
+    waitEI: _smc + 'initMovie(): Waiting for ExternalInterface call from Flash..',
+    waitOnload: _sm + ': Waiting for window.onload()',
+    docLoaded: _sm + ': Document already loaded',
+    onload: _smc + 'initComplete(): calling soundManager.onload()',
+    onloadOK: _sm + '.onload() complete',
+    init: _smc + 'init()',
+    didInit: _smc + 'init(): Already called?',
+    flashJS: _sm + ': Attempting to call Flash from JS..',
+    noPolling: _sm + ': Polling (whileloading()/whileplaying() support) is disabled.',
+    secNote: 'Flash security note: Network/internet URLs will not load due to security restrictions. Access can be configured via Flash Player Global Security Settings Page: http://www.macromedia.com/support/documentation/en/flashplayer/help/settings_manager04.html',
+    badRemove: 'Warning: Failed to remove flash movie.',
+    noPeak: 'Warning: peakData features unsupported for movieStar formats',
+    shutdown: _sm + '.disable(): Shutting down',
+    queue: _sm + ': Queueing %s handler',
+    smFail: _sm + ': Failed to initialise.',
+    smError: 'SMSound.load(): Exception: JS-Flash communication failed, or JS error.',
+    fbTimeout: 'No flash response, applying .'+_s.swfCSS.swfTimedout+' CSS..',
+    fbLoaded: 'Flash loaded',
+    fbHandler: _smc+'flashBlockHandler()',
+    manURL: 'SMSound.load(): Using manually-assigned URL',
+    onURL: _sm + '.load(): current URL already assigned.',
+    badFV: _sm + '.flashVersion must be 8 or 9. "%s" is invalid. Reverting to %s.',
+    as2loop: 'Note: Setting stream:false so looping can work (flash 8 limitation)',
+    noNSLoop: 'Note: Looping not implemented for MovieStar formats',
+    needfl9: 'Note: Switching to flash 9, required for MP4 formats.',
+    mfTimeout: 'Setting flashLoadTimeout = 0 (infinite) for off-screen, mobile flash case',
+    mfOn: 'mobileFlash::enabling on-screen flash repositioning',
+    policy: 'Enabling usePolicyFile for data access'
+    */
+  };
+
+  _str = function() { // o [,items to replace]
+    /*
+    var args = _slice.call(arguments), // real array, please
+    o = args.shift(), // first arg
+    str = (_strings && _strings[o]?_strings[o]:''), i, j;
+    if (str && args && args.length) {
+      for (i = 0, j = args.length; i < j; i++) {
+        str = str.replace('%s', args[i]);
+      }
+    }
+    return str;
+    */
+  };
+
+  _loopFix = function(sOpt) {
+    // flash 8 requires stream = false for looping to work
+    if (_fV === 8 && sOpt.loops > 1 && sOpt.stream) {
+      //_wDS('as2loop');
+      sOpt.stream = false;
+    }
+    return sOpt;
+  };
+
+  _policyFix = function(sOpt, sPre) {
+    if (sOpt && !sOpt.usePolicyFile && (sOpt.onid3 || sOpt.usePeakData || sOpt.useWaveformData || sOpt.useEQData)) {
+      //_s._wD((sPre || '') + _str('policy'));
+      sOpt.usePolicyFile = true;
+    }
+    return sOpt;
+  };
+
+  _complain = function(sMsg) {
+    if (typeof console !== 'undefined' && typeof console.warn !== 'undefined') {
+      console.warn(sMsg);
+    } else {
+      //_s._wD(sMsg);
+    }
+  };
+
+  _doNothing = function() {
+    return false;
+  };
+
+  _disableObject = function(o) {
+    var oProp;
+    for (oProp in o) {
+      if (o.hasOwnProperty(oProp) && typeof o[oProp] === 'function') {
+        o[oProp] = _doNothing;
+      }
+    }
+    oProp = null;
+  };
+
+  _failSafely = function(bNoDisable) {
+    // general failure exception handler
+    if (typeof bNoDisable === 'undefined') {
+      bNoDisable = false;
+    }
+    if (_disabled || bNoDisable) {
+      //_wDS('smFail', 2);
+      _s.disable(bNoDisable);
+    }
+  };
+
+  _normalizeMovieURL = function(smURL) {
+    var urlParams = null;
+    if (smURL) {
+      if (smURL.match(/\.swf(\?.*)?$/i)) {
+        urlParams = smURL.substr(smURL.toLowerCase().lastIndexOf('.swf?') + 4);
+        if (urlParams) {
+          return smURL; // assume user knows what they're doing
+        }
+      } else if (smURL.lastIndexOf('/') !== smURL.length - 1) {
+        smURL = smURL + '/';
+      }
+    }
+    return (smURL && smURL.lastIndexOf('/') !== - 1?smURL.substr(0, smURL.lastIndexOf('/') + 1):'./') + _s.movieURL;
+  };
+
+  _setVersionInfo = function() {
+
+    if (_fV !== 8 && _fV !== 9) {
+      //_s._wD(_str('badFV', _fV, _defaultFlashVersion));
+      _s.flashVersion = _defaultFlashVersion;
+    }
+    var isDebug = (_s.debugMode || _s.debugFlash?'_debug.swf':'.swf'); // debug flash movie, if applicable
+    if (_s.useHTML5Audio && !_s.html5Only && _s.audioFormats.mp4.required && _s.flashVersion < 9) {
+      //_s._wD(_str('needfl9'));
+      _s.flashVersion = 9;
+    }
+    _fV = _s.flashVersion; // short-hand for internal use
+    _s.version = _s.versionNumber + (_s.html5Only?' (HTML5-only mode)':(_fV === 9?' (AS3/Flash 9)':' (AS2/Flash 8)'));
+    // set up default options
+    if (_fV > 8) {
+      _s.defaultOptions = _mixin(_s.defaultOptions, _s.flash9Options);
+      _s.features.buffering = true;
+    }
+    if (_fV > 8 && _s.useMovieStar) {
+      // flash 9+ support for movieStar formats as well as MP3
+      _s.defaultOptions = _mixin(_s.defaultOptions, _s.movieStarOptions);
+      _s.filePatterns.flash9 = new RegExp('\\.(mp3|' + _s.netStreamTypes.join('|') + ')(\\?.*)?$', 'i');
+      _s.mimePattern = _s.netStreamMimeTypes;
+      _s.features.movieStar = true;
+    } else {
+      _s.useMovieStar = false;
+      _s.features.movieStar = false;
+    }
+    _s.filePattern = _s.filePatterns[(_fV !== 8?'flash9':'flash8')];
+    _s.movieURL = (_fV === 8?'soundmanager2.swf':'soundmanager2_flash9.swf').replace('.swf',isDebug);
+    _s.features.peakData = _s.features.waveformData = _s.features.eqData = (_fV > 8);
+  };
+
+  _setPolling = function(bPolling, bHighPerformance) {
+    if (!_s.o || !_s.allowPolling) {
+      return false;
+    }
+    _s.o._setPolling(bPolling, bHighPerformance);
+  };
+
+  _initDebug = function() {
+    if (_s.debugURLParam.test(_wl)) {
+      _s.debugMode = true; // allow force of debug mode via URL
+    }
+    /*
+    if (_id(_s.debugID)) {
+      return false;
+    }
+    var oD, oDebug, oTarget, oToggle, tmp;
+    if (_s.debugMode && !_id(_s.debugID) && ((!_hasConsole || !_s.useConsole) || (_s.useConsole && _hasConsole && !_s.consoleOnly))) {
+      oD = _doc.createElement('div');
+      oD.id = _s.debugID + '-toggle';
+      oToggle = {
+        'position': 'fixed',
+        'bottom': '0px',
+        'right': '0px',
+        'width': '1.2em',
+        'height': '1.2em',
+        'lineHeight': '1.2em',
+        'margin': '2px',
+        'textAlign': 'center',
+        'border': '1px solid #999',
+        'cursor': 'pointer',
+        'background': '#fff',
+        'color': '#333',
+        'zIndex': 10001
+      };
+      oD.appendChild(_doc.createTextNode('-'));
+      oD.onclick = _toggleDebug;
+      oD.title = 'Toggle SM2 debug console';
+      if (_ua.match(/msie 6/i)) {
+        oD.style.position = 'absolute';
+        oD.style.cursor = 'hand';
+      }
+      for (tmp in oToggle) {
+        if (oToggle.hasOwnProperty(tmp)) {
+          oD.style[tmp] = oToggle[tmp];
+        }
+      }
+      oDebug = _doc.createElement('div');
+      oDebug.id = _s.debugID;
+      oDebug.style.display = (_s.debugMode?'block':'none');
+      if (_s.debugMode && !_id(oD.id)) {
+        try {
+          oTarget = _getDocument();
+          oTarget.appendChild(oD);
+        } catch(e2) {
+          throw new Error(_str('domError')+' \n'+e2.toString());
+        }
+        oTarget.appendChild(oDebug);
+      }
+    }
+    oTarget = null;
+    */
+  };
+
+  _idCheck = this.getSoundById;
+
+  /*
+  _wDS = function(o, errorLevel) {
+    if (!o) {
+      return '';
+    } else {
+      return //_s._wD(_str(o), errorLevel);
+    }
+  };
+
+  // last-resort debugging option
+  if (_wl.indexOf('sm2-debug=alert') + 1 && _s.debugMode) {
+    _s._wD = function(sText) {window.alert(sText);};
+  }
+
+  _toggleDebug = function() {
+    var o = _id(_s.debugID),
+    oT = _id(_s.debugID + '-toggle');
+    if (!o) {
+      return false;
+    }
+    if (_debugOpen) {
+      // minimize
+      oT.innerHTML = '+';
+      o.style.display = 'none';
+    } else {
+      oT.innerHTML = '-';
+      o.style.display = 'block';
+    }
+    _debugOpen = !_debugOpen;
+  };
+
+  _debugTS = function(sEventType, bSuccess, sMessage) {
+    // troubleshooter debug hooks
+    if (typeof sm2Debugger !== 'undefined') {
+      try {
+        sm2Debugger.handleEvent(sEventType, bSuccess, sMessage);
+      } catch(e) {
+        // oh well
+      }
+    }
+    return true;
+  };
+  */
+
+  _getSWFCSS = function() {
+    var css = [];
+    if (_s.debugMode) {
+      css.push(_s.swfCSS.sm2Debug);
+    }
+    if (_s.debugFlash) {
+      css.push(_s.swfCSS.flashDebug);
+    }
+    if (_s.useHighPerformance) {
+      css.push(_s.swfCSS.highPerf);
+    }
+    return css.join(' ');
+  };
+
+  _flashBlockHandler = function() {
+    // *possible* flash block situation.
+    var name = _str('fbHandler'),
+        p = _s.getMoviePercent(),
+        css = _s.swfCSS,
+        error = {type:'FLASHBLOCK'};
+    if (_s.html5Only) {
+      return false;
+    }
+    if (!_s.ok()) {
+      if (_needsFlash) {
+        // make the movie more visible, so user can fix
+        _s.oMC.className = _getSWFCSS() + ' ' + css.swfDefault + ' ' + (p === null?css.swfTimedout:css.swfError);
+        //_s._wD(name+': '+_str('fbTimeout')+(p?' ('+_str('fbLoaded')+')':''));
+      }
+      _s.didFlashBlock = true;
+      _processOnEvents({type:'ontimeout', ignoreInit:true, error:error}); // fire onready(), complain lightly
+      _catchError(error);
+    } else {
+      // SM2 loaded OK (or recovered)
+      if (_s.didFlashBlock) {
+        //_s._wD(name+': Unblocked');
+      }
+      if (_s.oMC) {
+        _s.oMC.className = [_getSWFCSS(), css.swfDefault, css.swfLoaded + (_s.didFlashBlock?' '+css.swfUnblocked:'')].join(' ');
+      }
+    }
+  };
+
+  _addOnEvent = function(sType, oMethod, oScope) {
+    if (typeof _on_queue[sType] === 'undefined') {
+      _on_queue[sType] = [];
+    }
+    _on_queue[sType].push({
+      'method': oMethod,
+      'scope': (oScope || null),
+      'fired': false
+    });
+  };
+
+  _processOnEvents = function(oOptions) {
+    if (!oOptions) { // assume onready, if unspecified
+      oOptions = {
+        type: 'onready'
+      };
+    }
+    if (!_didInit && oOptions && !oOptions.ignoreInit) {
+      // not ready yet.
+      return false;
+    }
+    if (oOptions.type === 'ontimeout' && _s.ok()) {
+      // invalid case
+      return false;
+    }
+    var status = {
+          success: (oOptions && oOptions.ignoreInit?_s.ok():!_disabled)
+        },
+        srcQueue = (oOptions && oOptions.type?_on_queue[oOptions.type]||[]:[]), // queue specified by type, or none
+        queue = [], i, j,
+        args = [status],
+        canRetry = (_needsFlash && _s.useFlashBlock && !_s.ok());
+    if (oOptions.error) {
+      args[0].error = oOptions.error;
+    }
+    for (i = 0, j = srcQueue.length; i < j; i++) {
+      if (srcQueue[i].fired !== true) {
+        queue.push(srcQueue[i]);
+      }
+    }
+    if (queue.length) {
+      //_s._wD(_sm + ': Firing ' + queue.length + ' '+oOptions.type+'() item' + (queue.length === 1?'':'s'));
+      for (i = 0, j = queue.length; i < j; i++) {
+        if (queue[i].scope) {
+          queue[i].method.apply(queue[i].scope, args);
+        } else {
+          queue[i].method.apply(this, args);
+        }
+        if (!canRetry) { // flashblock case doesn't count here
+          queue[i].fired = true;
+        }
+      }
+    }
+    return true;
+  };
+
+  _initUserOnload = function() {
+    _win.setTimeout(function() {
+      if (_s.useFlashBlock) {
+        _flashBlockHandler();
+      }
+      _processOnEvents();
+      // call user-defined "onload", scoped to window
+      if (_s.onload instanceof Function) {
+        //_wDS('onload', 1);
+        _s.onload.apply(_win);
+        //_wDS('onloadOK', 1);
+      }
+      if (_s.waitForWindowLoad) {
+        _event.add(_win, 'load', _initUserOnload);
+      }
+    },1);
+  };
+
+  _detectFlash = function() {
+
+    // hat tip: Flash Detect library (BSD, (C) 2007) by Carl "DocYes" S. Yestrau - http://featureblend.com/javascript-flash-detection-library.html / http://featureblend.com/license.txt
+
+    if (_hasFlash !== undefined) {
+      // this work has already been done.
+      return _hasFlash;
+    }
+
+    var hasPlugin = false, n = navigator, nP = n.plugins, obj, type, types, AX = _win.ActiveXObject;
+
+    if (nP && nP.length) {
+
+      type = 'application/x-shockwave-flash';
+      types = n.mimeTypes;
+      if (types && types[type] && types[type].enabledPlugin && types[type].enabledPlugin.description) {
+        hasPlugin = true;
+      }
+
+    } else if (typeof AX !== 'undefined') {
+
+      try {
+        obj = new AX('ShockwaveFlash.ShockwaveFlash');
+      } catch(e) {
+        // oh well
+      }
+      hasPlugin = (!!obj);
+
+    }
+
+    _hasFlash = hasPlugin;
+
+    return hasPlugin;
+
+  };
+
+  _featureCheck = function() {
+
+    var needsFlash, item,
+        isSpecial = (_ua.match(/iphone os (1|2|3_0|3_1)/i)?true:false); // iPhone <= 3.1 has broken HTML5 audio(), but firmware 3.2 (iPad) + iOS4 works.
+
+    if (isSpecial) {
+      _s.hasHTML5 = false; // has Audio(), but is broken; let it load links directly.
+      _s.html5Only = true; // ignore flash case, however
+      if (_s.oMC) {
+        _s.oMC.style.display = 'none';
+      }
+      return false;
+    }
+
+    if (_s.useHTML5Audio) {
+      if (!_s.html5 || !_s.html5.canPlayType) {
+        //_s._wD('SoundManager: No HTML5 Audio() support detected.');
+        _s.hasHTML5 = false;
+        return true;
+      } else {
+        _s.hasHTML5 = true;
+      }
+      if (_isBadSafari) {
+        //_s._wD(_smc+'Note: Buggy HTML5 Audio in Safari on this OS X release, see https://bugs.webkit.org/show_bug.cgi?id=32159 - '+(!_hasFlash?' would use flash fallback for MP3/MP4, but none detected.':'will use flash fallback for MP3/MP4, if available'),1);
+        if (_detectFlash()) {
+          return true;
+        }
+      }
+    } else {
+      // flash needed (or, HTML5 needs enabling.)
+      return true;
+    }
+
+    for (item in _s.audioFormats) {
+      if (_s.audioFormats.hasOwnProperty(item)) {
+        if ( (_s.audioFormats[item].required && !_s.html5.canPlayType(_s.audioFormats[item].type)) || _s.flash[item] || _s.flash[_s.audioFormats[item].type]) {
+          // flash may be required, or preferred for this format
+          needsFlash = true;
+        }
+      }
+    }
+
+    // sanity check..
+    if (_s.ignoreFlash) {
+      needsFlash = false;
+    }
+
+    _s.html5Only = (_s.hasHTML5 && _s.useHTML5Audio && !needsFlash);
+
+    return (!_s.html5Only);
+
+  };
+
+  _startTimer = function(oSound) {
+    if (!oSound._hasTimer) {
+      oSound._hasTimer = true;
+    }
+  };
+
+  _stopTimer = function(oSound) {
+    if (oSound._hasTimer) {
+      oSound._hasTimer = false;
+    }
+  };
+
+  _catchError = function(options) {
+    options = (typeof options !== 'undefined' ? options : {});
+    if (_s.onerror instanceof Function) {
+      _s.onerror.apply(_win, [{type:(typeof options.type !== 'undefined' ? options.type : null)}]);
+    }
+    if (typeof options.fatal !== 'undefined' && options.fatal) {
+      _s.disable();
+    }
+  };
+
+  _badSafariFix = function() {
+    // special case: "bad" Safari (OS X 10.3 - 10.7) must fall back to flash for MP3/MP4
+    if (!_isBadSafari || !_detectFlash()) {
+      return false; // doesn't apply
+    }
+    var aF = _s.audioFormats, i, item;
+    for (item in aF) {
+      if (aF.hasOwnProperty(item)) {
+        if (item === 'mp3' || item === 'mp4') {
+          //_s._wD(_sm+': Using flash fallback for '+item+' format');
+          _s.html5[item] = false;
+          // assign result to related formats, too
+          if (aF[item] && aF[item].related) {
+            for (i = aF[item].related.length; i--;) {
+              _s.html5[aF[item].related[i]] = false;
+            }
+          }
+        }
+      }
+    }
+  };
+
+  /*
+   * pseudo-private flash/ExternalInterface methods
+  */
+
+  this._setSandboxType = function(sandboxType) {
+    /*
+    var sb = _s.sandbox;
+    sb.type = sandboxType;
+    sb.description = sb.types[(typeof sb.types[sandboxType] !== 'undefined'?sandboxType:'unknown')];
+    //_s._wD('Flash security sandbox type: ' + sb.type);
+    if (sb.type === 'localWithFile') {
+      sb.noRemote = true;
+      sb.noLocal = false;
+      //_wDS('secNote', 2);
+    } else if (sb.type === 'localWithNetwork') {
+      sb.noRemote = false;
+      sb.noLocal = true;
+    } else if (sb.type === 'localTrusted') {
+      sb.noRemote = false;
+      sb.noLocal = false;
+    }
+    */
+  };
+
+  this._externalInterfaceOK = function(flashDate) {
+    // flash callback confirming flash loaded, EI working etc.
+    // flashDate = approx. timing/delay info for JS/flash bridge
+    if (_s.swfLoaded) {
+      return false;
+    }
+    var eiTime = new Date().getTime();
+    //_s._wD(_smc+'externalInterfaceOK()' + (flashDate?' (~' + (eiTime - flashDate) + ' ms)':''));
+    //_debugTS('swf', true);
+    //_debugTS('flashtojs', true);
+    _s.swfLoaded = true;
+    _tryInitOnFocus = false;
+    if (_isBadSafari) {
+      _badSafariFix();
+    }
+    if (_isIE) {
+      // IE needs a timeout OR delay until window.onload - may need TODO: investigating
+      setTimeout(_init, 100);
+    } else {
+      _init();
+    }
+  };
+
+  /*
+   * private initialization helpers
+  */
+
+  _createMovie = function(smID, smURL) {
+
+    if (_didAppend && _appendSuccess) {
+      return false; // ignore if already succeeded
+    }
+
+    function _initMsg() {
+      //_s._wD('-- SoundManager 2 ' + _s.version + (!_s.html5Only && _s.useHTML5Audio?(_s.hasHTML5?' + HTML5 audio':', no HTML5 audio support'):'') + (!_s.html5Only ? (_s.useMovieStar?', MovieStar mode':'') + (_s.useHighPerformance?', high performance mode, ':', ') + (( _s.flashPollingInterval ? 'custom (' + _s.flashPollingInterval + 'ms)' : (_s.useFastPolling?'fast':'normal')) + ' polling') + (_s.wmode?', wmode: ' + _s.wmode:'') + (_s.debugFlash?', flash debug mode':'') + (_s.useFlashBlock?', flashBlock mode':'') : '') + ' --', 1);
+    }
+
+    if (_s.html5Only) {
+      // 100% HTML5 mode
+      _setVersionInfo();
+      _initMsg();
+      _s.oMC = _id(_s.movieID);
+      _init();
+      // prevent multiple init attempts
+      _didAppend = true;
+      _appendSuccess = true;
+      return false;
+    }
+
+    // flash path
+    var remoteURL = (smURL || _s.url),
+    localURL = (_s.altURL || remoteURL),
+    swfTitle = 'JS/Flash audio component (SoundManager 2)',
+    oEmbed, oMovie, oTarget = _getDocument(), tmp, movieHTML, oEl, extraClass = _getSWFCSS(), s, x, sClass, side = 'auto', isRTL = null, html = _doc.getElementsByTagName('html')[0];
+
+    isRTL = (html && html.dir && html.dir.match(/rtl/i));
+    smID = (typeof smID === 'undefined'?_s.id:smID);
+
+    function param(name, value) {
+      return '<param name="'+name+'" value="'+value+'" />';
+    }
+
+    // safety check for legacy (change to Flash 9 URL)
+    _setVersionInfo();
+    _s.url = _normalizeMovieURL(_overHTTP?remoteURL:localURL);
+    smURL = _s.url;
+
+    _s.wmode = (!_s.wmode && _s.useHighPerformance && !_s.useMovieStar?'transparent':_s.wmode);
+
+    if (_s.wmode !== null && (_ua.match(/msie 8/i) || (!_isIE && !_s.useHighPerformance)) && navigator.platform.match(/win32|win64/i)) {
+      /*
+       * extra-special case: movie doesn't load until scrolled into view when using wmode = anything but 'window' here
+       * does not apply when using high performance (position:fixed means on-screen), OR infinite flash load timeout
+       * wmode breaks IE 8 on Vista + Win7 too in some cases, as of January 2011 (?)
+      */
+      _s.specialWmodeCase = true;
+      //_wDS('spcWmode');
+      _s.wmode = null;
+    }
+
+    oEmbed = {
+      'name': smID,
+      'id': smID,
+      'src': smURL,
+      'width': side,
+      'height': side,
+      'quality': 'high',
+      'allowScriptAccess': _s.allowScriptAccess,
+      'bgcolor': _s.bgColor,
+      'pluginspage': _http+'//www.macromedia.com/go/getflashplayer',
+      'title': swfTitle,
+      'type': 'application/x-shockwave-flash',
+      'wmode': _s.wmode,
+      'hasPriority': 'true' // http://help.adobe.com/en_US/as3/mobile/WS4bebcd66a74275c36cfb8137124318eebc6-7ffd.html
+    };
+
+    if (_s.debugFlash) {
+      oEmbed.FlashVars = 'debug=1';
+    }
+
+    if (!_s.wmode) {
+      delete oEmbed.wmode; // don't write empty attribute
+    }
+
+    if (_isIE) {
+
+      // IE is "special".
+      oMovie = _doc.createElement('div');
+      movieHTML = [
+        '<object id="' + smID + '" data="' + smURL + '" type="' + oEmbed.type + '" title="' + oEmbed.title +'" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="' + _http+'//download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" width="' + oEmbed.width + '" height="' + oEmbed.height + '">',
+        param('movie', smURL),
+        param('AllowScriptAccess', _s.allowScriptAccess),
+        param('quality', oEmbed.quality),
+        (_s.wmode? param('wmode', _s.wmode): ''),
+        param('bgcolor', _s.bgColor),
+        param('hasPriority', 'true'),
+        (_s.debugFlash ? param('FlashVars', oEmbed.FlashVars) : ''),
+        '</object>'
+      ].join('');
+
+    } else {
+
+      oMovie = _doc.createElement('embed');
+      for (tmp in oEmbed) {
+        if (oEmbed.hasOwnProperty(tmp)) {
+          oMovie.setAttribute(tmp, oEmbed[tmp]);
+        }
+      }
+
+    }
+
+    _initDebug();
+    extraClass = _getSWFCSS();
+    oTarget = _getDocument();
+
+    if (oTarget) {
+
+      _s.oMC = (_id(_s.movieID) || _doc.createElement('div'));
+
+      if (!_s.oMC.id) {
+
+        _s.oMC.id = _s.movieID;
+        _s.oMC.className = _s.swfCSS.swfDefault + ' ' + extraClass;
+        s = null;
+        oEl = null;
+
+        if (!_s.useFlashBlock) {
+          if (_s.useHighPerformance) {
+            // on-screen at all times
+            s = {
+              'position': 'fixed',
+              'width': '8px',
+              'height': '8px',
+              // >= 6px for flash to run fast, >= 8px to start up under Firefox/win32 in some cases. odd? yes.
+              'bottom': '0px',
+              'left': '0px',
+              'overflow': 'hidden'
+            };
+          } else {
+            // hide off-screen, lower priority
+            s = {
+              'position': 'absolute',
+              'width': '6px',
+              'height': '6px',
+              'top': '-9999px',
+              'left': '-9999px'
+            };
+            if (isRTL) {
+              s.left = Math.abs(parseInt(s.left,10))+'px';
+            }
+          }
+        }
+
+        if (_isWebkit) {
+          _s.oMC.style.zIndex = 10000; // soundcloud-reported render/crash fix, safari 5
+        }
+
+        if (!_s.debugFlash) {
+          for (x in s) {
+            if (s.hasOwnProperty(x)) {
+              _s.oMC.style[x] = s[x];
+            }
+          }
+        }
+
+        try {
+          if (!_isIE) {
+            _s.oMC.appendChild(oMovie);
+          }
+          oTarget.appendChild(_s.oMC);
+          if (_isIE) {
+            oEl = _s.oMC.appendChild(_doc.createElement('div'));
+            oEl.className = _s.swfCSS.swfBox;
+            oEl.innerHTML = movieHTML;
+          }
+          _appendSuccess = true;
+        } catch(e) {
+          throw new Error(_str('domError')+' \n'+e.toString());
+        }
+
+      } else {
+
+        // SM2 container is already in the document (eg. flashblock use case)
+        sClass = _s.oMC.className;
+        _s.oMC.className = (sClass?sClass+' ':_s.swfCSS.swfDefault) + (extraClass?' '+extraClass:'');
+        _s.oMC.appendChild(oMovie);
+        if (_isIE) {
+          oEl = _s.oMC.appendChild(_doc.createElement('div'));
+          oEl.className = _s.swfCSS.swfBox;
+          oEl.innerHTML = movieHTML;
+        }
+        _appendSuccess = true;
+
+      }
+
+    }
+
+    _didAppend = true;
+    _initMsg();
+    //_s._wD(_smc+'createMovie(): Trying to load ' + smURL + (!_overHTTP && _s.altURL?' (alternate URL)':''), 1);
+
+    return true;
+
+  };
+
+  _initMovie = function() {
+
+    if (_s.html5Only) {
+      _createMovie();
+      return false;
+    }
+
+    // attempt to get, or create, movie
+    if (_s.o) {
+      return false; // may already exist
+    }
+
+    _s.o = _s.getMovie(_s.id); // inline markup
+
+    if (!_s.o) {
+      if (!_oRemoved) {
+        // try to create
+        _createMovie(_s.id, _s.url);
+      } else {
+        // try to re-append removed movie after reboot()
+        if (!_isIE) {
+          _s.oMC.appendChild(_oRemoved);
+        } else {
+          _s.oMC.innerHTML = _oRemovedHTML;
+        }
+        _oRemoved = null;
+        _didAppend = true;
+      }
+      _s.o = _s.getMovie(_s.id);
+    }
+
+    if (_s.o) {
+      //_wDS('waitEI');
+    }
+
+    if (_s.oninitmovie instanceof Function) {
+      setTimeout(_s.oninitmovie, 1);
+    }
+
+    return true;
+
+  };
+
+  _delayWaitForEI = function() {
+    setTimeout(_waitForEI, 1000);
+  };
+
+  _waitForEI = function() {
+
+    if (_waitingForEI) {
+      return false;
+    }
+
+    _waitingForEI = true;
+    _event.remove(_win, 'load', _delayWaitForEI);
+
+    if (_tryInitOnFocus && !_isFocused) {
+      // giant Safari 3.1 hack - assume mousemove = focus given lack of focus event
+      //_wDS('waitFocus');
+      return false;
+    }
+
+    var p;
+    if (!_didInit) {
+      p = _s.getMoviePercent();
+      //_s._wD(_str('waitImpatient', (p === 100?' (SWF loaded)':(p > 0?' (SWF ' + p + '% loaded)':''))));
+    }
+
+    setTimeout(function() {
+
+      p = _s.getMoviePercent();
+
+      if (!_didInit) {
+        //_s._wD(_sm + ': No Flash response within expected time.\nLikely causes: ' + (p === 0?'Loading ' + _s.movieURL + ' may have failed (and/or Flash ' + _fV + '+ not present?), ':'') + 'Flash blocked or JS-Flash security error.' + (_s.debugFlash?' ' + _str('checkSWF'):''), 2);
+        if (!_overHTTP && p) {
+          //_wDS('localFail', 2);
+          if (!_s.debugFlash) {
+            //_wDS('tryDebug', 2);
+          }
+        }
+        if (p === 0) {
+          // if 0 (not null), probably a 404.
+          //_s._wD(_str('swf404', _s.url));
+        }
+        //_debugTS('flashtojs', false, ': Timed out' + _overHTTP?' (Check flash security or flash blockers)':' (No plugin/missing SWF?)');
+      }
+
+      // give up / time-out, depending
+      if (!_didInit && _okToDisable) {
+        if (p === null) {
+          // SWF failed. Maybe blocked.
+          if (_s.useFlashBlock || _s.flashLoadTimeout === 0) {
+            if (_s.useFlashBlock) {
+              _flashBlockHandler();
+            }
+            //_wDS('waitForever');
+          } else {
+            // old SM2 behaviour, simply fail
+            _failSafely(true);
+          }
+
+        } else {
+          // flash loaded? Shouldn't be a blocking issue, then.
+          if (_s.flashLoadTimeout === 0) {
+             //_wDS('waitForever');
+          } else {
+            _failSafely(true);
+          }
+        }
+      }
+
+    }, _s.flashLoadTimeout);
+
+  };
+
+  _handleFocus = function() {
+    function cleanup() {
+      _event.remove(_win, 'focus', _handleFocus);
+      _event.remove(_win, 'load', _handleFocus);
+    }
+    if (_isFocused || !_tryInitOnFocus) {
+      cleanup();
+      return true;
+    }
+    _okToDisable = true;
+    _isFocused = true;
+    //_s._wD(_smc+'handleFocus()');
+    if (_isSafari && _tryInitOnFocus) {
+      _event.remove(_win, 'mousemove', _handleFocus);
+    }
+    // allow init to restart
+    _waitingForEI = false;
+    cleanup();
+    return true;
+  };
+
+  _initComplete = function(bNoDisable) {
+    if (_didInit) {
+      return false;
+    }
+    if (_s.html5Only) {
+      // all good.
+      //_s._wD('-- SoundManager 2: loaded --');
+      _didInit = true;
+      _initUserOnload();
+      //_debugTS('onload', true);
+      return true;
+    }
+    var wasTimeout = (_s.useFlashBlock && _s.flashLoadTimeout && !_s.getMoviePercent()),
+        error;
+    if (!wasTimeout) {
+      _didInit = true;
+      if (_disabled) {
+        error = {type: (!_hasFlash && _needsFlash ? 'NO_FLASH' : 'INIT_TIMEOUT')};
+      }
+    }
+    //_s._wD('-- SoundManager 2 ' + (_disabled?'failed to load':'loaded') + ' (' + (_disabled?'security/load error':'OK') + ') --', 1);
+    if (_disabled || bNoDisable) {
+      if (_s.useFlashBlock && _s.oMC) {
+        _s.oMC.className = _getSWFCSS() + ' ' + (_s.getMoviePercent() === null?_s.swfCSS.swfTimedout:_s.swfCSS.swfError);
+      }
+      _processOnEvents({type:'ontimeout', error:error});
+      //_debugTS('onload', false);
+      _catchError(error);
+      return false;
+    } else {
+      //_debugTS('onload', true);
+    }
+    _event.add(_win, 'unload', _doNothing); // prevent browser from showing cached state via back button, because flash will be dead
+    if (_s.waitForWindowLoad && !_windowLoaded) {
+      //_wDS('waitOnload');
+      _event.add(_win, 'load', _initUserOnload);
+      return false;
+    } else {
+      if (_s.waitForWindowLoad && _windowLoaded) {
+        //_wDS('docLoaded');
+      }
+      _initUserOnload();
+    }
+    return true;
+  };
+
+  _showSupport = function() {
+
+    var item, tests = [];
+    if (_s.useHTML5Audio && _s.hasHTML5) {
+      for (item in _s.audioFormats) {
+        if (_s.audioFormats.hasOwnProperty(item)) {
+          tests.push(item + ': ' + _s.html5[item] + (!_s.html5[item] && _hasFlash && _s.flash[item] ? ' (using flash)' : (_s.preferFlash && _s.flash[item] && _hasFlash ? ' (preferring flash)': (!_s.html5[item] ? ' (' + (_s.audioFormats[item].required ? 'required, ':'') + 'and no flash support)' : ''))));
+        }
+      }
+      //_s._wD('-- SoundManager 2: HTML5 support tests ('+_s.html5Test+'): '+tests.join(', ')+' --',1);
+    }
+
+  };
+
+  _init = function() {
+
+    //_wDS('init');
+
+    // called after onload()
+    if (_didInit) {
+      //_wDS('didInit');
+      return false;
+    }
+
+    function _cleanup() {
+      _event.remove(_win, 'load', _s.beginDelayedInit);
+    }
+
+    if (_s.html5Only) {
+      if (!_didInit) {
+        // we don't need no steenking flash!
+        _cleanup();
+        _s.enabled = true;
+        _initComplete();
+      }
+      return true;
+    }
+
+    // flash path
+    _initMovie();
+
+    try {
+      //_wDS('flashJS');
+      _s.o._externalInterfaceTest(false); // attempt to talk to Flash
+      if (!_s.allowPolling) {
+        //_wDS('noPolling', 1);
+      } else {
+        _setPolling(true, (_s.flashPollingInterval || (_s.useFastPolling ? 10 : 50)));
+      }
+      if (!_s.debugMode) {
+        _s.o._disableDebug();
+      }
+      _s.enabled = true;
+      //_debugTS('jstoflash', true);
+    } catch(e) {
+      //_s._wD('js/flash exception: ' + e.toString());
+      //_debugTS('jstoflash', false);
+      _catchError({type:'JS_TO_FLASH_EXCEPTION', fatal:true});
+      _failSafely(true); // don't disable, for reboot()
+      _initComplete();
+      return false;
+    }
+
+    _initComplete();
+    // event cleanup
+    _cleanup();
+    return true;
+
+  };
+
+  _dcLoaded = function() {
+    if (_didDCLoaded) {
+      return false;
+    }
+    _didDCLoaded = true;
+    _initDebug();
+
+    /*
+     * Temporary feature: allow force of HTML5 via URL params: sm2-usehtml5audio=0 or 1
+     * Ditto for sm2-preferFlash, too.
+    */
+    /*
+    (function(){
+      var a = 'sm2-usehtml5audio=', l = _wl.toLowerCase(), b = null,
+      a2 = 'sm2-preferflash=', b2 = null, hasCon = (typeof console !== 'undefined' && typeof console.log !== 'undefined');
+      if (l.indexOf(a) !== -1) {
+        b = (l.charAt(l.indexOf(a)+a.length) === '1');
+        if (hasCon) {
+          console.log((b?'Enabling ':'Disabling ')+'useHTML5Audio via URL parameter');
+        }
+        _s.useHTML5Audio = b;
+      }
+      if (l.indexOf(a2) !== -1) {
+        b2 = (l.charAt(l.indexOf(a2)+a2.length) === '1');
+        if (hasCon) {
+          console.log((b2?'Enabling ':'Disabling ')+'preferFlash via URL parameter');
+        }
+        _s.preferFlash = b2;
+      }
+    }());
+    */
+
+    if (!_hasFlash && _s.hasHTML5) {
+      //_s._wD('SoundManager: No Flash detected'+(!_s.useHTML5Audio?', enabling HTML5.':'. Trying HTML5-only mode.'));
+      _s.useHTML5Audio = true;
+      // make sure we aren't preferring flash, either
+      // TODO: preferFlash should not matter if flash is not installed. Currently, stuff breaks without the below tweak.
+      _s.preferFlash = false;
+    }
+
+    _testHTML5();
+    _s.html5.usingFlash = _featureCheck();
+    _needsFlash = _s.html5.usingFlash;
+
+    _showSupport();
+
+    if (!_hasFlash && _needsFlash) {
+      //_s._wD('SoundManager: Fatal error: Flash is needed to play some required formats, but is not available.');
+      // TODO: Fatal here vs. timeout approach, etc.
+      _s.flashLoadTimeout = 1; // hack: fail sooner.
+    }
+
+    if (_doc.removeEventListener) {
+      _doc.removeEventListener('DOMContentLoaded', _dcLoaded, false);
+    }
+    _initMovie();
+    return true;
+  };
+
+  _dcIE = function() {
+    if (_doc.readyState === 'complete') {
+      _dcLoaded();
+      _doc.detachEvent('onreadystatechange', _dcIE);
+    }
+    return true;
+  };
+
+  // sniff up-front
+  _detectFlash();
+
+  // focus and window load, init (primarily flash-driven)
+  _event.add(_win, 'focus', _handleFocus);
+  _event.add(_win, 'load', _handleFocus);
+  _event.add(_win, 'load', _delayWaitForEI);
+  if (_isSafari && _tryInitOnFocus) {
+    _event.add(_win, 'mousemove', _handleFocus); // massive Safari 3.1 focus hack
+  }
+
+  if (_doc.addEventListener) {
+    _doc.addEventListener('DOMContentLoaded', _dcLoaded, false);
+  } else if (_doc.attachEvent) {
+    _doc.attachEvent('onreadystatechange', _dcIE);
+  } else {
+    // no add/attachevent support - safe to assume no JS -> Flash either
+    //_debugTS('onload', false);
+    _catchError({type:'NO_DOM2_EVENTS', fatal:true});
+  }
+
+  if (_doc.readyState === 'complete') {
+    setTimeout(_dcLoaded,100);
+  }
+
+} // SoundManager()
+
+// SM2_DEFER details: http://www.schillmania.com/projects/soundmanager2/doc/getstarted/#lazy-loading
+if (typeof SM2_DEFER === 'undefined' || !SM2_DEFER) {
+  soundManager = new SoundManager();
+}
+
+// public interfaces
+window.SoundManager = SoundManager; // constructor
+window.soundManager = soundManager; // public API, flash callbacks etc
+
+}(window));
Index: /gs3-extensions/audioDB/trunk/src/interface/script/soundmanager2.js
===================================================================
--- /gs3-extensions/audioDB/trunk/src/interface/script/soundmanager2.js	(revision 26291)
+++ /gs3-extensions/audioDB/trunk/src/interface/script/soundmanager2.js	(revision 26291)
@@ -0,0 +1,3198 @@
+/** @license
+ * SoundManager 2: JavaScript Sound for the Web
+ * ----------------------------------------------
+ * http://schillmania.com/projects/soundmanager2/
+ *
+ * Copyright (c) 2007, Scott Schiller. All rights reserved.
+ * Code provided under the BSD License:
+ * http://schillmania.com/projects/soundmanager2/license.txt
+ *
+ * V2.97a.20110801
+*/
+
+/*global window, SM2_DEFER, sm2Debugger, console, document, navigator, setTimeout, setInterval, clearInterval, Audio */
+/*jslint regexp: true, sloppy: true, white: true, nomen: true, plusplus: true */
+
+(function(window) {
+
+var soundManager = null;
+
+function SoundManager(smURL, smID) {
+
+  this.flashVersion = 8;             // version of flash to require, either 8 or 9. Some API features require Flash 9.
+  this.debugMode = true;             // enable debugging output (div#soundmanager-debug, OR console if available+configured)
+  this.debugFlash = false;           // enable debugging output inside SWF, troubleshoot Flash/browser issues
+  this.useConsole = true;            // use firebug/safari console.log()-type debug console if available
+  this.consoleOnly = false;          // if console is being used, do not create/write to #soundmanager-debug
+  this.waitForWindowLoad = false;    // force SM2 to wait for window.onload() before trying to call soundManager.onload()
+  this.nullURL = 'about:blank';      // path to "null" (empty) MP3 file, used to unload sounds (Flash 8 only)
+  this.allowPolling = true;          // allow flash to poll for status update (required for whileplaying() events, peak, sound spectrum functions to work.)
+  this.useFastPolling = false;       // uses lower flash timer interval for higher callback frequency, best combined with useHighPerformance
+  this.useMovieStar = true;          // enable support for Flash 9.0r115+ (codename "MovieStar") MPEG4 audio formats (AAC, M4V, FLV, MOV etc.)
+  this.bgColor = '#ffffff';          // movie (.swf) background color, eg. '#000000'
+  this.useHighPerformance = false;   // position:fixed flash movie can help increase js/flash speed, minimize lag
+  this.flashPollingInterval = null;  // msec for polling interval. Defaults to 50 unless useFastPolling = true.
+  this.flashLoadTimeout = 1000;      // msec to wait for flash movie to load before failing (0 = infinity)
+  this.wmode = null;                 // string: flash rendering mode - null, transparent, opaque (last two allow layering of HTML on top)
+  this.allowScriptAccess = 'always'; // for scripting the SWF (object/embed property), either 'always' or 'sameDomain'
+  this.useFlashBlock = false;        // *requires flashblock.css, see demos* - allow recovery from flash blockers. Wait indefinitely and apply timeout CSS to SWF, if applicable.
+  this.useHTML5Audio = true;         // Beta feature: Use HTML5 Audio() where API is supported (most Safari, Chrome versions), Firefox (no MP3/MP4.) Ideally, transparent vs. Flash API where possible.
+  this.html5Test = /^(probably|maybe)$/i; // HTML5 Audio() format support test. Use /^probably$/i; if you want to be more conservative.
+  this.preferFlash = true;           // (experimental) if true and flash support present, will try to use flash for MP3/MP4 as needed since HTML5 audio support is still quirky in browsers.
+
+  this.audioFormats = {
+    /*
+     * determines HTML5 support + flash requirements.
+     * if no support for a "required" format, SM2 will fail to start.
+     * flash fallback is used for MP3 or MP4 if HTML5 can't play it (or if preferFlash = true)
+     * multiple MIME types may be tested while trying to get a positive canPlayType() response.
+    */
+    'mp3': {
+      'type': ['audio/mpeg; codecs="mp3"', 'audio/mpeg', 'audio/mp3', 'audio/MPA', 'audio/mpa-robust'],
+      'required': true
+    },
+    'mp4': {
+      'related': ['aac','m4a'], // additional formats under the MP4 container
+      'type': ['audio/mp4; codecs="mp4a.40.2"', 'audio/aac', 'audio/x-m4a', 'audio/MP4A-LATM', 'audio/mpeg4-generic'],
+      'required': false
+    },
+    'ogg': {
+      'type': ['audio/ogg; codecs=vorbis'],
+      'required': false
+    },
+    'wav': {
+      'type': ['audio/wav; codecs="1"', 'audio/wav', 'audio/wave', 'audio/x-wav'],
+      'required': false
+    }
+  };
+
+  this.defaultOptions = {
+    'autoLoad': false,             // enable automatic loading (otherwise .load() will be called on demand with .play(), the latter being nicer on bandwidth - if you want to .load yourself, you also can)
+    'stream': true,                // allows playing before entire file has loaded (recommended)
+    'autoPlay': false,             // enable playing of file as soon as possible (much faster if "stream" is true)
+    'loops': 1,                    // how many times to repeat the sound (position will wrap around to 0, setPosition() will break out of loop when >0)
+    'onid3': null,                 // callback function for "ID3 data is added/available"
+    'onload': null,                // callback function for "load finished"
+    'whileloading': null,          // callback function for "download progress update" (X of Y bytes received)
+    'onplay': null,                // callback for "play" start
+    'onpause': null,               // callback for "pause"
+    'onresume': null,              // callback for "resume" (pause toggle)
+    'whileplaying': null,          // callback during play (position update)
+    'onstop': null,                // callback for "user stop"
+    'onfailure': null,             // callback function for when playing fails
+    'onfinish': null,              // callback function for "sound finished playing"
+    'onbeforefinish': null,        // callback for "before sound finished playing (at [time])"
+    'onbeforefinishtime': 5000,    // offset (milliseconds) before end of sound to trigger beforefinish (eg. 1000 msec = 1 second)
+    'onbeforefinishcomplete': null,// function to call when said sound finishes playing
+    'onjustbeforefinish': null,    // callback for [n] msec before end of current sound
+    'onjustbeforefinishtime': 200, // [n] - if not using, set to 0 (or null handler) and event will not fire.
+    'multiShot': true,             // let sounds "restart" or layer on top of each other when played multiple times, rather than one-shot/one at a time
+    'multiShotEvents': false,      // fire multiple sound events (currently onfinish() only) when multiShot is enabled
+    'position': null,              // offset (milliseconds) to seek to within loaded sound data.
+    'pan': 0,                      // "pan" settings, left-to-right, -100 to 100
+    'type': null,                  // MIME-like hint for file pattern / canPlay() tests, eg. audio/mp3
+    'usePolicyFile': false,        // enable crossdomain.xml request for audio on remote domains (for ID3/waveform access)
+    'volume': 100                  // self-explanatory. 0-100, the latter being the max.
+  };
+
+  this.flash9Options = {      // flash 9-only options, merged into defaultOptions if flash 9 is being used
+    'isMovieStar': null,      // "MovieStar" MPEG4 audio mode. Null (default) = auto detect MP4, AAC etc. based on URL. true = force on, ignore URL
+    'usePeakData': false,     // enable left/right channel peak (level) data
+    'useWaveformData': false, // enable sound spectrum (raw waveform data) - WARNING: CPU-INTENSIVE: may set CPUs on fire.
+    'useEQData': false,       // enable sound EQ (frequency spectrum data) - WARNING: Also CPU-intensive.
+    'onbufferchange': null,   // callback for "isBuffering" property change
+    'ondataerror': null       // callback for waveform/eq data access error (flash playing audio in other tabs/domains)
+  };
+
+  this.movieStarOptions = { // flash 9.0r115+ MPEG4 audio options, merged into defaultOptions if flash 9+movieStar mode is enabled
+    'bufferTime': 3,        // seconds of data to buffer before playback begins (null = flash default of 0.1 seconds - if AAC playback is gappy, try increasing.)
+    'serverURL': null,      // rtmp: FMS or FMIS server to connect to, required when requesting media via RTMP or one of its variants
+    'onconnect': null,      // rtmp: callback for connection to flash media server
+    'duration': null        // rtmp: song duration (msec)
+  };
+
+  this.version = null;
+  this.versionNumber = 'V2.97a.20110801';
+  this.movieURL = null;
+  this.url = (smURL || null);
+  this.altURL = null;
+  this.swfLoaded = false;
+  this.enabled = false;
+  this.o = null;
+  this.movieID = 'sm2-container';
+  this.id = (smID || 'sm2movie');
+  this.swfCSS = {
+    'swfBox': 'sm2-object-box',
+    'swfDefault': 'movieContainer',
+    'swfError': 'swf_error', // SWF loaded, but SM2 couldn't start (other error)
+    'swfTimedout': 'swf_timedout',
+    'swfLoaded': 'swf_loaded',
+    'swfUnblocked': 'swf_unblocked', // or loaded OK
+    'sm2Debug': 'sm2_debug',
+    'highPerf': 'high_performance',
+    'flashDebug': 'flash_debug'
+  };
+  this.oMC = null;
+  this.sounds = {};
+  this.soundIDs = [];
+  this.muted = false;
+  this.debugID = 'soundmanager-debug';
+  this.debugURLParam = /([#?&])debug=1/i;
+  this.specialWmodeCase = false;
+  this.didFlashBlock = false;
+
+  this.filePattern = null;
+  this.filePatterns = {
+    'flash8': /\.mp3(\?.*)?$/i,
+    'flash9': /\.mp3(\?.*)?$/i
+  };
+
+  this.baseMimeTypes = /^\s*audio\/(?:x-)?(?:mp(?:eg|3))\s*(?:$|;)/i; // mp3
+  this.netStreamMimeTypes = /^\s*audio\/(?:x-)?(?:mp(?:eg|3))\s*(?:$|;)/i; // mp3, mp4, aac etc.
+  this.netStreamTypes = ['aac', 'flv', 'mov', 'mp4', 'm4v', 'f4v', 'm4a', 'mp4v', '3gp', '3g2']; // Flash v9.0r115+ "moviestar" formats
+  this.netStreamPattern = new RegExp('\\.(' + this.netStreamTypes.join('|') + ')(\\?.*)?$', 'i');
+  this.mimePattern = this.baseMimeTypes;
+
+  this.features = {
+    'buffering': false,
+    'peakData': false,
+    'waveformData': false,
+    'eqData': false,
+    'movieStar': false
+  };
+
+  this.sandbox = {
+    // <d>
+    'type': null,
+    'types': {
+      'remote': 'remote (domain-based) rules',
+      'localWithFile': 'local with file access (no internet access)',
+      'localWithNetwork': 'local with network (internet access only, no local access)',
+      'localTrusted': 'local, trusted (local+internet access)'
+    },
+    'description': null,
+    'noRemote': null,
+    'noLocal': null
+    // </d>
+  };
+
+  this.hasHTML5 = (typeof Audio !== 'undefined' && typeof new Audio().canPlayType !== 'undefined'); // switch for handling logic
+
+  // stores canPlayType() results, etc. treat as read-only.
+  this.html5 = {
+    // mp3: boolean
+    // mp4: boolean
+    'usingFlash': null // set if/when flash fallback is needed
+  };
+
+  // format support
+  this.flash = {
+    // mp3: boolean
+    // mp4: boolean
+  };
+
+  this.html5Only = false;   // determined at init time
+  this.ignoreFlash = false; // used for special cases (eg. iPad/iPhone/palm OS?)
+
+  /*
+   * a few private internals
+  */
+
+  var SMSound,
+  _s = this, _sm = 'soundManager', _smc = _sm+'::', _h5 = 'HTML5::', _id, _ua = navigator.userAgent, _win = window, _wl = _win.location.href.toString(), _fV = this.flashVersion, _doc = document, _doNothing, _init, _on_queue = [], _debugOpen = true, _debugTS, _didAppend = false, _appendSuccess = false, _didInit = false, _disabled = false, _windowLoaded = false, _wDS, _wdCount = 0, _initComplete, _mixin, _addOnEvent, _processOnEvents, _initUserOnload, _delayWaitForEI, _waitForEI, _setVersionInfo, _handleFocus, _strings, _initMovie, _dcLoaded, _didDCLoaded, _getDocument, _createMovie, _catchError, _setPolling, _initDebug, _debugLevels = ['log', 'info', 'warn', 'error'], _defaultFlashVersion = 8, _disableObject, _failSafely, _normalizeMovieURL, _oRemoved = null, _oRemovedHTML = null, _str, _flashBlockHandler, _getSWFCSS, _toggleDebug, _loopFix, _policyFix, _complain, _idCheck, _waitingForEI = false, _initPending = false, _smTimer, _onTimer, _startTimer, _stopTimer, _needsFlash = null, _featureCheck, _html5OK, _html5CanPlay, _html5Ext,  _dcIE, _testHTML5, _event, _slice = Array.prototype.slice, _useGlobalHTML5Audio = false, _hasFlash, _detectFlash, _badSafariFix, _html5_events, _showSupport,
+  _is_iDevice = _ua.match(/(ipad|iphone|ipod)/i), _likesHTML5 = (_ua.match(/(mobile|pre\/|xoom)/i) || _is_iDevice), _isIE = _ua.match(/msie/i), _isWebkit = _ua.match(/webkit/i), _isSafari = (_ua.match(/safari/i) && !_ua.match(/chrome/i)), _isOpera = (_ua.match(/opera/i)), 
+  _isBadSafari = (!_wl.match(/usehtml5audio/i) && !_wl.match(/sm2\-ignorebadua/i) && _isSafari && _ua.match(/OS X 10_6_([3-7])/i)), // Safari 4 and 5 occasionally fail to load/play HTML5 audio on Snow Leopard 10.6.3 through 10.6.7 due to bug(s) in QuickTime X and/or other underlying frameworks. :/ Confirmed bug. https://bugs.webkit.org/show_bug.cgi?id=32159
+  _hasConsole = (typeof console !== 'undefined' && typeof console.log !== 'undefined'), _isFocused = (typeof _doc.hasFocus !== 'undefined'?_doc.hasFocus():null), _tryInitOnFocus = (_isSafari && typeof _doc.hasFocus === 'undefined'), _okToDisable = !_tryInitOnFocus, _flashMIME = /(mp3|mp4|mpa)/i,
+  _overHTTP = (_doc.location?_doc.location.protocol.match(/http/i):null),
+  _http = (!_overHTTP ? 'http:' : '');
+
+  this.useAltURL = !_overHTTP; // use altURL if not "online"
+  this._global_a = null;
+
+  if (_likesHTML5) {
+    // prefer HTML5 for mobile + tablet-like devices, probably more reliable vs. flash at this point.
+    _s.useHTML5Audio = true;
+    _s.preferFlash = false;
+    if (_is_iDevice) {
+      // by default, use global feature. iOS onfinish() -> next may fail otherwise.
+      _s.ignoreFlash = true;
+      _useGlobalHTML5Audio = true;
+    }
+  }
+
+  /*
+   * public soundManager API
+  */
+
+  this.ok = function() {
+    return (_needsFlash?(_didInit && !_disabled):(_s.useHTML5Audio && _s.hasHTML5));
+  };
+
+  this.supported = this.ok; // legacy
+
+  this.getMovie = function(smID) {
+    return _isIE?_win[smID]:(_isSafari?_id(smID) || _doc[smID]:_id(smID));
+  };
+
+  this.createSound = function(oOptions) {
+    var _cs = _sm+'.createSound(): ',
+    thisOptions = null, oSound = null, _tO = null;
+    if (!_didInit || !_s.ok()) {
+      _complain(_cs + _str(!_didInit?'notReady':'notOK'));
+      return false;
+    }
+    if (arguments.length === 2) {
+      // function overloading in JS! :) ..assume simple createSound(id,url) use case
+      oOptions = {
+        'id': arguments[0],
+        'url': arguments[1]
+      };
+    }
+    thisOptions = _mixin(oOptions); // inherit from defaultOptions
+    _tO = thisOptions; // alias
+    // <d>
+    if (_tO.id.toString().charAt(0).match(/^[0-9]$/)) {
+      _s._wD(_cs + _str('badID', _tO.id), 2);
+    }
+    _s._wD(_cs + _tO.id + ' (' + _tO.url + ')', 1);
+    // </d>
+    if (_idCheck(_tO.id, true)) {
+      _s._wD(_cs + _tO.id + ' exists', 1);
+      return _s.sounds[_tO.id];
+    }
+
+    function make() {
+      thisOptions = _loopFix(thisOptions);
+      _s.sounds[_tO.id] = new SMSound(_tO);
+      _s.soundIDs.push(_tO.id);
+      return _s.sounds[_tO.id];
+    }
+
+    if (_html5OK(_tO)) {
+      oSound = make();
+      _s._wD('Loading sound '+_tO.id+' via HTML5');
+      oSound._setup_html5(_tO);
+    } else {
+      if (_fV > 8 && _s.useMovieStar) {
+        if (_tO.isMovieStar === null) {
+          _tO.isMovieStar = ((_tO.serverURL || (_tO.type?_tO.type.match(_s.netStreamPattern):false)||_tO.url.match(_s.netStreamPattern))?true:false);
+        }
+        if (_tO.isMovieStar) {
+          _s._wD(_cs + 'using MovieStar handling');
+        }
+        if (_tO.isMovieStar) {
+          if (_tO.usePeakData) {
+            _wDS('noPeak');
+            _tO.usePeakData = false;
+          }
+          if (_tO.loops > 1) {
+            _wDS('noNSLoop');
+          }
+        }
+      }
+      _tO = _policyFix(_tO, _cs);
+      oSound = make();
+      if (_fV === 8) {
+        _s.o._createSound(_tO.id, _tO.onjustbeforefinishtime, _tO.loops||1, _tO.usePolicyFile);
+      } else {
+        _s.o._createSound(_tO.id, _tO.url, _tO.onjustbeforefinishtime, _tO.usePeakData, _tO.useWaveformData, _tO.useEQData, _tO.isMovieStar, (_tO.isMovieStar?_tO.bufferTime:false), _tO.loops||1, _tO.serverURL, _tO.duration||null, _tO.autoPlay, true, _tO.autoLoad, _tO.usePolicyFile);
+        if (!_tO.serverURL) {
+          // We are connected immediately
+          oSound.connected = true;
+          if (_tO.onconnect) {
+            _tO.onconnect.apply(oSound);
+          }
+        }
+      }
+
+      if (!_tO.serverURL && (_tO.autoLoad || _tO.autoPlay)) {
+        oSound.load(_tO); // call load for non-rtmp streams
+      }
+    }
+    if (!_tO.serverURL && _tO.autoPlay) { // rtmp will play in onconnect
+      oSound.play();
+    }
+    return oSound;
+  };
+
+  this.destroySound = function(sID, _bFromSound) {
+    // explicitly destroy a sound before normal page unload, etc.
+    if (!_idCheck(sID)) {
+      return false;
+    }
+    var oS = _s.sounds[sID], i;
+    oS._iO = {}; // Disable all callbacks while the sound is being destroyed
+    oS.stop();
+    oS.unload();
+    for (i = 0; i < _s.soundIDs.length; i++) {
+      if (_s.soundIDs[i] === sID) {
+        _s.soundIDs.splice(i, 1);
+        break;
+      }
+    }
+    if (!_bFromSound) {
+      // ignore if being called from SMSound instance
+      oS.destruct(true);
+    }
+    oS = null;
+    delete _s.sounds[sID];
+    return true;
+  };
+
+  this.load = function(sID, oOptions) {
+    if (!_idCheck(sID)) {
+      return false;
+    }
+    return _s.sounds[sID].load(oOptions);
+  };
+
+  this.unload = function(sID) {
+    if (!_idCheck(sID)) {
+      return false;
+    }
+    return _s.sounds[sID].unload();
+  };
+
+  this.play = function(sID, oOptions) {
+    var fN = _sm+'.play(): ';
+    if (!_didInit || !_s.ok()) {
+      _complain(fN + _str(!_didInit?'notReady':'notOK'));
+      return false;
+    }
+    if (!_idCheck(sID)) {
+      if (!(oOptions instanceof Object)) {
+        oOptions = {
+          url: oOptions
+        }; // overloading use case: play('mySound','/path/to/some.mp3');
+      }
+      if (oOptions && oOptions.url) {
+        // overloading use case, create+play: .play('someID',{url:'/path/to.mp3'});
+        _s._wD(fN + 'attempting to create "' + sID + '"', 1);
+        oOptions.id = sID;
+        return _s.createSound(oOptions).play();
+      } else {
+        return false;
+      }
+    }
+    return _s.sounds[sID].play(oOptions);
+  };
+
+  this.start = this.play; // just for convenience
+
+  this.setPosition = function(sID, nMsecOffset) {
+    if (!_idCheck(sID)) {
+      return false;
+    }
+    return _s.sounds[sID].setPosition(nMsecOffset);
+  };
+
+  this.stop = function(sID) {
+    if (!_idCheck(sID)) {
+      return false;
+    }
+    _s._wD(_sm+'.stop(' + sID + ')', 1);
+    return _s.sounds[sID].stop();
+  };
+
+  this.stopAll = function() {
+    var oSound;
+    _s._wD(_sm+'.stopAll()', 1);
+    for (oSound in _s.sounds) {
+      if (_s.sounds.hasOwnProperty(oSound)) {
+        _s.sounds[oSound].stop(); // apply only to sound objects
+      }
+    }
+  };
+
+  this.pause = function(sID) {
+    if (!_idCheck(sID)) {
+      return false;
+    }
+    return _s.sounds[sID].pause();
+  };
+
+  this.pauseAll = function() {
+    var i;
+    for (i = _s.soundIDs.length; i--;) {
+      _s.sounds[_s.soundIDs[i]].pause();
+    }
+  };
+
+  this.resume = function(sID) {
+    if (!_idCheck(sID)) {
+      return false;
+    }
+    return _s.sounds[sID].resume();
+  };
+
+  this.resumeAll = function() {
+    var i;
+    for (i = _s.soundIDs.length; i--;) {
+      _s.sounds[_s.soundIDs[i]].resume();
+    }
+  };
+
+  this.togglePause = function(sID) {
+    if (!_idCheck(sID)) {
+      return false;
+    }
+    return _s.sounds[sID].togglePause();
+  };
+
+  this.setPan = function(sID, nPan) {
+    if (!_idCheck(sID)) {
+      return false;
+    }
+    return _s.sounds[sID].setPan(nPan);
+  };
+
+  this.setVolume = function(sID, nVol) {
+    if (!_idCheck(sID)) {
+      return false;
+    }
+    return _s.sounds[sID].setVolume(nVol);
+  };
+
+  this.mute = function(sID) {
+    var fN = _sm+'.mute(): ',
+    i = 0;
+    if (typeof sID !== 'string') {
+      sID = null;
+    }
+    if (!sID) {
+      _s._wD(fN + 'Muting all sounds');
+      for (i = _s.soundIDs.length; i--;) {
+        _s.sounds[_s.soundIDs[i]].mute();
+      }
+      _s.muted = true;
+    } else {
+      if (!_idCheck(sID)) {
+        return false;
+      }
+      _s._wD(fN + 'Muting "' + sID + '"');
+      return _s.sounds[sID].mute();
+    }
+    return true;
+  };
+
+  this.muteAll = function() {
+    _s.mute();
+  };
+
+  this.unmute = function(sID) {
+    var fN = _sm+'.unmute(): ', i;
+    if (typeof sID !== 'string') {
+      sID = null;
+    }
+    if (!sID) {
+      _s._wD(fN + 'Unmuting all sounds');
+      for (i = _s.soundIDs.length; i--;) {
+        _s.sounds[_s.soundIDs[i]].unmute();
+      }
+      _s.muted = false;
+    } else {
+      if (!_idCheck(sID)) {
+        return false;
+      }
+      _s._wD(fN + 'Unmuting "' + sID + '"');
+      return _s.sounds[sID].unmute();
+    }
+    return true;
+  };
+
+  this.unmuteAll = function() {
+    _s.unmute();
+  };
+
+  this.toggleMute = function(sID) {
+    if (!_idCheck(sID)) {
+      return false;
+    }
+    return _s.sounds[sID].toggleMute();
+  };
+
+  this.getMemoryUse = function() {
+    // flash-only
+    var ram = 0;
+    if (_s.o && _fV !== 8) {
+      ram = parseInt(_s.o._getMemoryUse(), 10);
+    }
+    return ram;
+  };
+
+  this.disable = function(bNoDisable) {
+    // destroy all functions
+    var i;
+    if (typeof bNoDisable === 'undefined') {
+      bNoDisable = false;
+    }
+    if (_disabled) {
+      return false;
+    }
+    _disabled = true;
+    _wDS('shutdown', 1);
+    for (i = _s.soundIDs.length; i--;) {
+      _disableObject(_s.sounds[_s.soundIDs[i]]);
+    }
+    _initComplete(bNoDisable); // fire "complete", despite fail
+    _event.remove(_win, 'load', _initUserOnload);
+    return true;
+  };
+
+  this.canPlayMIME = function(sMIME) {
+    var result;
+    if (_s.hasHTML5) {
+      result = _html5CanPlay({type:sMIME});
+    }
+    if (!_needsFlash || result) {
+      // no flash, or OK
+      return result;
+    } else {
+      return (sMIME?(sMIME.match(_s.mimePattern)?true:false):null);
+    }
+  };
+
+  this.canPlayURL = function(sURL) {
+    var result;
+    if (_s.hasHTML5) {
+      result = _html5CanPlay({url: sURL});
+    }
+    if (!_needsFlash || result) {
+      // no flash, or OK
+      return result;
+    } else {
+      return (sURL?(sURL.match(_s.filePattern)?true:false):null);
+    }
+  };
+
+  this.canPlayLink = function(oLink) {
+    if (typeof oLink.type !== 'undefined' && oLink.type) {
+      if (_s.canPlayMIME(oLink.type)) {
+        return true;
+      }
+    }
+    return _s.canPlayURL(oLink.href);
+  };
+
+  this.getSoundById = function(sID, suppressDebug) {
+    if (!sID) {
+      throw new Error(_sm+'.getSoundById(): sID is null/undefined');
+    }
+    var result = _s.sounds[sID];
+    if (!result && !suppressDebug) {
+      _s._wD('"' + sID + '" is an invalid sound ID.', 2);
+    }
+    return result;
+  };
+
+  this.onready = function(oMethod, oScope) {
+    var sType = 'onready';
+    if (oMethod && oMethod instanceof Function) {
+      if (_didInit) {
+        _s._wD(_str('queue', sType));
+      }
+      if (!oScope) {
+        oScope = _win;
+      }
+      _addOnEvent(sType, oMethod, oScope);
+      _processOnEvents();
+      return true;
+    } else {
+      throw _str('needFunction', sType);
+    }
+  };
+
+  this.ontimeout = function(oMethod, oScope) {
+    var sType = 'ontimeout';
+    if (oMethod && oMethod instanceof Function) {
+      if (_didInit) {
+        _s._wD(_str('queue', sType));
+      }
+      if (!oScope) {
+        oScope = _win;
+      }
+      _addOnEvent(sType, oMethod, oScope);
+      _processOnEvents({type:sType});
+      return true;
+    } else {
+      throw _str('needFunction', sType);
+    }
+  };
+
+  this._writeDebug = function(sText, sType, bTimestamp) {
+    // pseudo-private console.log()-style output
+    // <d>
+    var sDID = 'soundmanager-debug', o, oItem, sMethod;
+    if (!_s.debugMode) {
+      return false;
+    }
+    if (typeof bTimestamp !== 'undefined' && bTimestamp) {
+      sText = sText + ' | ' + new Date().getTime();
+    }
+    if (_hasConsole && _s.useConsole) {
+      sMethod = _debugLevels[sType];
+      if (typeof console[sMethod] !== 'undefined') {
+        console[sMethod](sText);
+      } else {
+        console.log(sText);
+      }
+      if (_s.useConsoleOnly) {
+        return true;
+      }
+    }
+    try {
+      o = _id(sDID);
+      if (!o) {
+        return false;
+      }
+      oItem = _doc.createElement('div');
+      if (++_wdCount % 2 === 0) {
+        oItem.className = 'sm2-alt';
+      }
+      if (typeof sType === 'undefined') {
+        sType = 0;
+      } else {
+        sType = parseInt(sType, 10);
+      }
+      oItem.appendChild(_doc.createTextNode(sText));
+      if (sType) {
+        if (sType >= 2) {
+          oItem.style.fontWeight = 'bold';
+        }
+        if (sType === 3) {
+          oItem.style.color = '#ff3333';
+        }
+      }
+      // o.appendChild(oItem); // top-to-bottom
+      o.insertBefore(oItem, o.firstChild); // bottom-to-top
+    } catch(e) {
+      // oh well
+    }
+    o = null;
+    // </d>
+    return true;
+  };
+  this._wD = this._writeDebug; // alias
+
+  this._debug = function() {
+    // <d>
+    var i, j;
+    _wDS('currentObj', 1);
+    for (i = 0, j = _s.soundIDs.length; i < j; i++) {
+      _s.sounds[_s.soundIDs[i]]._debug();
+    }
+    // </d>
+  };
+
+  this.reboot = function() {
+    // attempt to reset and init SM2
+    _s._wD(_sm+'.reboot()');
+    if (_s.soundIDs.length) {
+      _s._wD('Destroying ' + _s.soundIDs.length + ' SMSound objects...');
+    }
+    var i, j;
+    for (i = _s.soundIDs.length; i--;) {
+      _s.sounds[_s.soundIDs[i]].destruct();
+    }
+    // trash ze flash
+    try {
+      if (_isIE) {
+        _oRemovedHTML = _s.o.innerHTML;
+      }
+      _oRemoved = _s.o.parentNode.removeChild(_s.o);
+      _s._wD('Flash movie removed.');
+    } catch(e) {
+      // uh-oh.
+      _wDS('badRemove', 2);
+    }
+    // actually, force recreate of movie.
+    _oRemovedHTML = _oRemoved = _needsFlash = null;
+    _s.enabled = _didDCLoaded = _didInit = _waitingForEI = _initPending = _didAppend = _appendSuccess = _disabled = _s.swfLoaded = false;
+    _s.soundIDs = _s.sounds = [];
+    _s.o = null;
+    for (i in _on_queue) {
+      if (_on_queue.hasOwnProperty(i)) {
+        for (j = _on_queue[i].length; j--;) {
+          _on_queue[i][j].fired = false;
+        }
+      }
+    }
+    _s._wD(_sm + ': Rebooting...');
+    _win.setTimeout(_s.beginDelayedInit, 20);
+  };
+
+  this.getMoviePercent = function() {
+    return (_s.o && typeof _s.o.PercentLoaded !== 'undefined' ? _s.o.PercentLoaded() : null);
+  };
+
+  this.beginDelayedInit = function() {
+    _windowLoaded = true;
+    _dcLoaded();
+    setTimeout(function() {
+      if (_initPending) {
+        return false;
+      }
+      _createMovie();
+      _initMovie();
+      _initPending = true;
+      return true;
+    }, 20);
+    _delayWaitForEI();
+  };
+
+  this.destruct = function() {
+    _s._wD(_sm+'.destruct()');
+    _s.disable(true);
+  };
+
+  /*
+   * internal HTML5 event handling
+  */
+
+  function _html5_event(oFn) {
+    // wrap html5 event handlers so we don't call them on destroyed sounds
+    return function(e) {
+      if (!this._t || !this._t._a) {
+        if (this._t && this._t.sID) {
+          _s._wD(_h5+'ignoring '+e.type+': '+this._t.sID);
+        } else {
+          _s._wD(_h5+'ignoring '+e.type);
+        }
+        return null;
+      } else {
+        return oFn.call(this, e);
+      }
+    };
+  }
+
+  _html5_events = {
+
+    // HTML5 event-name-to-handler map
+    abort: _html5_event(function(e) {
+      _s._wD(_h5+'abort: '+this._t.sID);
+    }),
+
+    // enough has loaded to play
+    canplay: _html5_event(function(e) {
+      if (this._t._html5_canplay) {
+        // this event has already fired. ignore.
+        return true;
+      }
+      this._t._html5_canplay = true;
+      _s._wD(_h5+'canplay: '+this._t.sID+', '+this._t.url);
+      this._t._onbufferchange(0);
+      var position1K = (!isNaN(this._t.position)?this._t.position/1000:null);
+      // set the position if position was set before the sound loaded
+      if (this._t.position && this.currentTime !== position1K) {
+        _s._wD(_h5+'canplay: setting position to '+position1K);
+        try {
+          this.currentTime = position1K;
+        } catch(ee) {
+          _s._wD(_h5+'setting position failed: '+ee.message, 2);
+        }
+      }
+    }),
+
+    load: _html5_event(function(e) {
+      if (!this._t.loaded) {
+        this._t._onbufferchange(0);
+        // should be 1, and the same
+        this._t._whileloading(this._t.bytesTotal, this._t.bytesTotal, this._t._get_html5_duration());
+        this._t._onload(true);
+      }
+    }),
+
+    emptied: _html5_event(function(e) {
+      _s._wD(_h5+'emptied: '+this._t.sID);
+    }),
+
+    ended: _html5_event(function(e) {
+      _s._wD(_h5+'ended: '+this._t.sID);
+      this._t._onfinish();
+    }),
+
+    error: _html5_event(function(e) {
+      _s._wD(_h5+'error: '+this.error.code);
+      // call load with error state?
+      this._t._onload(false);
+    }),
+
+    loadeddata: _html5_event(function(e) {
+      var t = this._t,
+          bytesTotal = t.bytesTotal || 1; // at least 1 byte, so math works
+      _s._wD(_h5+'loadeddata: '+this._t.sID);
+      if (!t._loaded && !_isSafari) { // safari seems to nicely report progress events, eventually totalling 100%
+        t.duration = t._get_html5_duration();
+        // fire whileloading() with 100% values
+        t._whileloading(bytesTotal, bytesTotal, t._get_html5_duration());
+        t._onload(true);
+      }
+    }),
+
+    loadedmetadata: _html5_event(function(e) {
+      _s._wD(_h5+'loadedmetadata: '+this._t.sID);
+    }),
+
+    loadstart: _html5_event(function(e) {
+      _s._wD(_h5+'loadstart: '+this._t.sID);
+      // assume buffering at first
+      this._t._onbufferchange(1);
+    }),
+
+    play: _html5_event(function(e) {
+      _s._wD(_h5+'play: '+this._t.sID+', '+this._t.url);
+      // once play starts, no buffering
+      this._t._onbufferchange(0);
+    }),
+
+    // TODO: verify if this is actually implemented anywhere yet.
+    playing: _html5_event(function(e) {
+      _s._wD(_h5+'playing: '+this._t.sID+', '+this._t.url);
+      // once play starts, no buffering
+      this._t._onbufferchange(0);
+    }),
+
+    progress: _html5_event(function(e) {
+
+      if (this._t.loaded) {
+        return false;
+      }
+
+      var i, j, str, buffered = 0,
+          isProgress = (e.type === 'progress'),
+          ranges = e.target.buffered,
+          loaded = (e.loaded||0), // firefox 3.6 implements e.loaded/total (bytes)
+          total = (e.total||1);
+
+      if (ranges && ranges.length) {
+
+        // if loaded is 0, try TimeRanges implementation as % of load
+        // https://developer.mozilla.org/en/DOM/TimeRanges
+        for (i=ranges.length; i--;) {
+          buffered = (ranges.end(i) - ranges.start(i));
+        }
+
+        // linear case, buffer sum; does not account for seeking and HTTP partials / byte ranges
+        loaded = buffered/e.target.duration;
+
+        // <d>
+        if (isProgress && ranges.length > 1) {
+          str = [];
+          j = ranges.length;
+          for (i=0; i<j; i++) {
+            str.push(e.target.buffered.start(i) +'-'+ e.target.buffered.end(i));
+          }
+          _s._wD(_h5+'progress: timeRanges: '+str.join(', '));
+        }
+        // </d>
+
+        if (isProgress && !isNaN(loaded)) {
+          _s._wD(_h5+'progress: '+this._t.sID+': ' + Math.floor(loaded*100)+'% loaded');
+        }
+
+      }
+
+      if (!isNaN(loaded)) {
+
+        this._t._onbufferchange(0); // if progress, likely not buffering
+        this._t._whileloading(loaded, total, this._t._get_html5_duration());
+
+        if (loaded && total && loaded === total) {
+          // in case "onload" doesn't fire (eg. gecko 1.9.2)
+          _html5_events.load.call(this, e);
+        }
+
+      }
+
+    }),
+
+    ratechange: _html5_event(function(e) {
+      _s._wD(_h5+'ratechange: '+this._t.sID);
+    }),
+
+    suspend: _html5_event(function(e) {
+      // download paused/stopped, may have finished (eg. onload)
+      _s._wD(_h5+'suspend: '+this._t.sID);
+      _html5_events.progress.call(this, e);
+    }),
+
+    stalled: _html5_event(function(e) {
+      _s._wD(_h5+'stalled: '+this._t.sID);
+    }),
+
+    timeupdate: _html5_event(function(e) {
+      this._t._onTimer();
+    }),
+
+    waiting: _html5_event(function(e) { // see also: seeking
+      _s._wD(_h5+'waiting: '+this._t.sID);
+      // playback faster than download rate, etc.
+      this._t._onbufferchange(1);
+    })
+
+  };
+
+  /*
+   * SMSound() (sound object) instance
+  */
+
+  SMSound = function(oOptions) {
+
+    var _t = this, _resetProperties, _stop_html5_timer, _start_html5_timer;
+    this.sID = oOptions.id;
+    this.url = oOptions.url;
+    this.options = _mixin(oOptions);
+    this.instanceOptions = this.options; // per-play-instance-specific options
+    this._iO = this.instanceOptions; // short alias
+    // assign property defaults
+    this.pan = this.options.pan;
+    this.volume = this.options.volume;
+    this._lastURL = null;
+    this.isHTML5 = false;
+    this._a = null;
+
+    // --- public methods ---
+
+    this.id3 = {};
+
+    this._debug = function() {
+      // <d>
+      // pseudo-private console.log()-style output
+      if (_s.debugMode) {
+        var stuff = null, msg = [], sF, sfBracket, maxLength = 64;
+        for (stuff in _t.options) {
+          if (_t.options[stuff] !== null) {
+            if (_t.options[stuff] instanceof Function) {
+              // handle functions specially
+              sF = _t.options[stuff].toString();
+              sF = sF.replace(/\s\s+/g, ' '); // normalize spaces
+              sfBracket = sF.indexOf('{');
+              msg.push(' ' + stuff + ': {' + sF.substr(sfBracket + 1, (Math.min(Math.max(sF.indexOf('\n') - 1, maxLength), maxLength))).replace(/\n/g, '') + '... }');
+            } else {
+              msg.push(' ' + stuff + ': ' + _t.options[stuff]);
+            }
+          }
+        }
+        _s._wD('SMSound() merged options: {\n' + msg.join(', \n') + '\n}');
+      }
+      // </d>
+    };
+
+    // <d>
+    this._debug();
+    // </d>
+
+    this.load = function(oOptions) {
+      var oS = null;
+      if (typeof oOptions !== 'undefined') {
+        _t._iO = _mixin(oOptions, _t.options);
+        _t.instanceOptions = _t._iO;
+      } else {
+        oOptions = _t.options;
+        _t._iO = oOptions;
+        _t.instanceOptions = _t._iO;
+        if (_t._lastURL && _t._lastURL !== _t.url) {
+          _wDS('manURL');
+          _t._iO.url = _t.url;
+          _t.url = null;
+        }
+      }
+      if (!_t._iO.url) {
+        _t._iO.url = _t.url;
+      }
+      _s._wD('SMSound.load(): ' + _t._iO.url, 1);
+      if (_t._iO.url === _t.url && _t.readyState !== 0 && _t.readyState !== 2) {
+        _wDS('onURL', 1);
+        return _t;
+      }
+      _t._lastURL = _t.url;
+      _t.loaded = false;
+      _t.readyState = 1;
+      _t.playState = 0;
+      if (_html5OK(_t._iO)) {
+        oS = _t._setup_html5(_t._iO);
+        if (!oS._called_load) {
+          _s._wD(_h5+'load: '+_t.sID);
+          _t._html5_canplay = false;
+          oS.load();
+          oS._called_load = true;
+          if (_t._iO.autoPlay) {
+            _t.play();
+          }
+        } else {
+          _s._wD(_h5+'ignoring request to load again: '+_t.sID);
+        }
+      } else {
+        try {
+          _t.isHTML5 = false;
+          _t._iO = _policyFix(_loopFix(_t._iO));
+          if (_fV === 8) {
+            _s.o._load(_t.sID, _t._iO.url, _t._iO.stream, _t._iO.autoPlay, (_t._iO.whileloading?1:0), _t._iO.loops||1, _t._iO.usePolicyFile);
+          } else {
+            _s.o._load(_t.sID, _t._iO.url, _t._iO.stream?true:false, _t._iO.autoPlay?true:false, _t._iO.loops||1, _t._iO.autoLoad?true:false, _t._iO.usePolicyFile);
+          }
+        } catch(e) {
+          _wDS('smError', 2);
+          _debugTS('onload', false);
+          _catchError({type:'SMSOUND_LOAD_JS_EXCEPTION', fatal:true});
+        }
+      }
+      return _t;
+    };
+
+    this.unload = function() {
+      // Flash 8/AS2 can't "close" a stream - fake it by loading an empty MP3
+      // Flash 9/AS3: Close stream, preventing further load
+      if (_t.readyState !== 0) {
+        _s._wD('SMSound.unload(): "' + _t.sID + '"');
+        if (!_t.isHTML5) {
+          if (_fV === 8) {
+            _s.o._unload(_t.sID, _s.nullURL);
+          } else {
+            _s.o._unload(_t.sID);
+          }
+        } else {
+          _stop_html5_timer();
+          if (_t._a) {
+            // abort()-style method here, stop loading? (doesn't exist?)
+            _t._a.pause();
+            _t._a.src = ''; // https://developer.mozilla.org/En/Using_audio_and_video_in_Firefox#Stopping_the_download_of_media
+          }
+        }
+        // reset load/status flags
+        _resetProperties();
+      }
+      return _t;
+    };
+
+    this.destruct = function(_bFromSM) {
+      _s._wD('SMSound.destruct(): "' + _t.sID + '"');
+      if (!_t.isHTML5) {
+        // kill sound within Flash
+        // Disable the onfailure handler
+        _t._iO.onfailure = null;
+        _s.o._destroySound(_t.sID);
+      } else {
+        _stop_html5_timer();
+        if (_t._a) {
+          // abort()-style method here, stop loading? (doesn't exist?)
+          _t._a.pause();
+          _t._a.src = ''; // https://developer.mozilla.org/En/Using_audio_and_video_in_Firefox#Stopping_the_download_of_media
+          if (!_useGlobalHTML5Audio) {
+            _t._remove_html5_events();
+          }
+          _t._a._t = null; // break potential circular reference
+          _t._a = null;
+        }
+      }
+      if (!_bFromSM) {
+        _s.destroySound(_t.sID, true); // ensure deletion from controller
+      }
+    };
+
+    this.play = function(oOptions, _updatePlayState) {
+      var fN = 'SMSound.play(): ', allowMulti, a;
+      _updatePlayState = _updatePlayState === undefined ? true : _updatePlayState; // default to true
+      if (!oOptions) {
+        oOptions = {};
+      }
+      _t._iO = _mixin(oOptions, _t._iO);
+      _t._iO = _mixin(_t._iO, _t.options);
+      _t.instanceOptions = _t._iO;
+      if (_t._iO.serverURL && !_t.connected) {
+        if (!_t.getAutoPlay()) {
+          _s._wD(fN+' Netstream not connected yet - setting autoPlay');
+          _t.setAutoPlay(true);
+        }
+        return _t; // play will be called in _onconnect()
+      }
+      if (_html5OK(_t._iO)) {
+        _t._setup_html5(_t._iO);
+        _start_html5_timer();
+      }
+      if (_t.playState === 1 && !_t.paused) {
+        allowMulti = _t._iO.multiShot;
+        if (!allowMulti) {
+          _s._wD(fN + '"' + _t.sID + '" already playing (one-shot)', 1);
+          return _t;
+        } else {
+          _s._wD(fN + '"' + _t.sID + '" already playing (multi-shot)', 1);
+        }
+      }
+      if (!_t.loaded) {
+        if (_t.readyState === 0) {
+          _s._wD(fN + 'Attempting to load "' + _t.sID + '"', 1);
+          // try to get this sound playing ASAP
+          if (!_t.isHTML5) {
+            _t._iO.autoPlay = true; // assign directly because setAutoPlay() increments the instanceCount
+          }
+          _t.load(_t._iO);
+        } else if (_t.readyState === 2) {
+          _s._wD(fN + 'Could not load "' + _t.sID + '" - exiting', 2);
+          return _t;
+        } else {
+          _s._wD(fN + '"' + _t.sID + '" is loading - attempting to play..', 1);
+        }
+      } else {
+        _s._wD(fN + '"' + _t.sID + '"');
+      }
+      if (!_t.isHTML5 && _fV === 9 && _t.position > 0 && _t.position === _t.duration) {
+        // flash 9 needs a position reset if play() is called while at the end of a sound.
+        _s._wD(fN + '"' + _t.sID + '": Sound at end, resetting to position:0');
+        _t._iO.position = 0;
+      }
+      /*
+       * Streams will pause when their buffer is full if they are being loaded.
+       * In this case paused is true, but the song hasn't started playing yet.
+       * If we just call resume() the onplay() callback will never be called.
+       * So only call resume() if the position is > 0.
+       * Another reason is because options like volume won't have been applied yet.
+      */
+      if (_t.paused && _t.position && _t.position > 0) { // https://gist.github.com/37b17df75cc4d7a90bf6
+        _s._wD(fN + '"' + _t.sID + '" is resuming from paused state',1);
+        _t.resume();
+      } else {
+        _s._wD(fN+'"'+ _t.sID+'" is starting to play');
+        _t.playState = 1;
+        _t.paused = false;
+        if (!_t.instanceCount || _t._iO.multiShotEvents || (!_t.isHTML5 && _fV > 8 && !_t.getAutoPlay())) {
+          _t.instanceCount++;
+        }
+        _t.position = (typeof _t._iO.position !== 'undefined' && !isNaN(_t._iO.position)?_t._iO.position:0);
+        if (!_t.isHTML5) {
+          _t._iO = _policyFix(_loopFix(_t._iO));
+        }
+        if (_t._iO.onplay && _updatePlayState) {
+          _t._iO.onplay.apply(_t);
+          _t._onplay_called = true;
+        }
+        _t.setVolume(_t._iO.volume, true);
+        _t.setPan(_t._iO.pan, true);
+        if (!_t.isHTML5) {
+          _s.o._start(_t.sID, _t._iO.loops || 1, (_fV === 9?_t._iO.position:_t._iO.position / 1000));
+        } else {
+          _start_html5_timer();
+          a = _t._setup_html5();
+          _t.setPosition(_t._iO.position);
+          a.play();
+        }
+      }
+      return _t;
+    };
+
+    this.start = this.play; // just for convenience
+
+    this.stop = function(bAll) {
+      if (_t.playState === 1) {
+        _t._onbufferchange(0);
+        _t.resetOnPosition(0);
+        if (!_t.isHTML5) {
+          _t.playState = 0;
+        }
+        _t.paused = false;
+        if (_t._iO.onstop) {
+          _t._iO.onstop.apply(_t);
+        }
+        if (!_t.isHTML5) {
+          _s.o._stop(_t.sID, bAll);
+          // hack for netStream: just unload
+          if (_t._iO.serverURL) {
+            _t.unload();
+          }
+        } else {
+          if (_t._a) {
+            _t.setPosition(0); // act like Flash, though
+            _t._a.pause(); // html5 has no stop()
+            _t.playState = 0;
+            _t._onTimer(); // and update UI
+            _stop_html5_timer();
+            _t.unload();
+          }
+        }
+        _t.instanceCount = 0;
+        _t._iO = {};
+      }
+      return _t;
+    };
+
+    this.setAutoPlay = function(autoPlay) {
+      _s._wD('sound '+_t.sID+' turned autoplay ' + (autoPlay ? 'on' : 'off'));
+      _t._iO.autoPlay = autoPlay;
+      if (!_t.isHTML5) {
+        _s.o._setAutoPlay(_t.sID, autoPlay);
+        if (autoPlay) {
+          // only increment the instanceCount if the sound isn't loaded (TODO: verify RTMP)
+          if (!_t.instanceCount && _t.readyState === 1) {
+            _t.instanceCount++;
+            _s._wD('sound '+_t.sID+' incremented instance count to '+_t.instanceCount);
+          }
+        }
+      }
+    };
+
+    this.getAutoPlay = function() {
+      return _t._iO.autoPlay;
+    };
+
+    this.setPosition = function(nMsecOffset) {
+      if (nMsecOffset === undefined) {
+        nMsecOffset = 0;
+      }
+      // Use the duration from the instance options, if we don't have a track duration yet.
+      var original_pos, position, position1K,
+          offset = (_t.isHTML5 ? Math.max(nMsecOffset,0) : Math.min(_t.duration || _t._iO.duration, Math.max(nMsecOffset, 0))); // position >= 0 and <= current available (loaded) duration
+      original_pos = _t.position;
+      _t.position = offset;
+      position1K = _t.position/1000;
+      _t.resetOnPosition(_t.position);
+      _t._iO.position = offset;
+      if (!_t.isHTML5) {
+        position = (_fV === 9 ? _t.position : position1K);
+        if (_t.readyState && _t.readyState !== 2) {
+          _s.o._setPosition(_t.sID, position, (_t.paused || !_t.playState)); // if paused or not playing, will not resume (by playing)
+        }
+      } else if (_t._a) {
+        // Set the position in the canplay handler if the sound is not ready yet
+        if (_t._html5_canplay) {
+          if (_t._a.currentTime !== position1K) {
+            /*
+             * DOM/JS errors/exceptions to watch out for:
+             * if seek is beyond (loaded?) position, "DOM exception 11"
+             * "INDEX_SIZE_ERR": DOM exception 1
+            */
+            _s._wD('setPosition('+position1K+'): setting position');
+            try {
+              _t._a.currentTime = position1K;
+              if (_t.playState === 0 || _t.paused) {
+                // allow seek without auto-play/resume
+                _t._a.pause();
+              }
+            } catch(e) {
+              _s._wD('setPosition('+position1K+'): setting position failed: '+e.message, 2);
+            }
+          }
+        } else {
+          _s._wD('setPosition('+position1K+'): delaying, sound not ready');
+        }
+      }
+      if (_t.isHTML5) {
+        if (_t.paused) { // if paused, refresh UI right away
+          _t._onTimer(true); // force update
+        }
+      }
+      return _t;
+    };
+
+    this.pause = function(bCallFlash) {
+      if (_t.paused || (_t.playState === 0 && _t.readyState !== 1)) {
+        return _t;
+      }
+      _s._wD('SMSound.pause()');
+      _t.paused = true;
+      if (!_t.isHTML5) {
+        if (bCallFlash || bCallFlash === undefined) {
+          _s.o._pause(_t.sID);
+        }
+      } else {
+        _t._setup_html5().pause();
+        _stop_html5_timer();
+      }
+      if (_t._iO.onpause) {
+        _t._iO.onpause.apply(_t);
+      }
+      return _t;
+    };
+
+    /*
+     * When auto-loaded streams pause on buffer full they have a playState of 0.
+     * We need to make sure that the playState is set to 1 when these streams "resume".
+     * When a paused stream is resumed, we need to trigger the onplay() callback if it
+     * hasn't been called already. In this case since the sound is being played for the
+     * first time, I think it's more appropriate to call onplay() rather than onresume().
+    */
+    this.resume = function() {
+      if (!_t.paused) {
+        return _t;
+      }
+      _s._wD('SMSound.resume()');
+      _t.paused = false;
+      _t.playState = 1;
+      if (!_t.isHTML5) {
+        if (_t._iO.isMovieStar) {
+          // Bizarre Webkit bug (Chrome reported via 8tracks.com dudes): AAC content paused for 30+ seconds(?) will not resume without a reposition.
+          _t.setPosition(_t.position);
+        }
+        _s.o._pause(_t.sID); // flash method is toggle-based (pause/resume)
+      } else {
+        _t._setup_html5().play();
+        _start_html5_timer();
+      }
+      if (!_t._onplay_called && _t._iO.onplay) {
+        _t._iO.onplay.apply(_t);
+        _t._onplay_called = true;
+      } else if (_t._iO.onresume) {
+        _t._iO.onresume.apply(_t);
+      }
+      return _t;
+    };
+
+    this.togglePause = function() {
+      _s._wD('SMSound.togglePause()');
+      if (_t.playState === 0) {
+        _t.play({
+          position: (_fV === 9 && !_t.isHTML5 ? _t.position : _t.position / 1000)
+        });
+        return _t;
+      }
+      if (_t.paused) {
+        _t.resume();
+      } else {
+        _t.pause();
+      }
+      return _t;
+    };
+
+    this.setPan = function(nPan, bInstanceOnly) {
+      if (typeof nPan === 'undefined') {
+        nPan = 0;
+      }
+      if (typeof bInstanceOnly === 'undefined') {
+        bInstanceOnly = false;
+      }
+      if (!_t.isHTML5) {
+        _s.o._setPan(_t.sID, nPan);
+      } // else { no HTML5 pan? }
+      _t._iO.pan = nPan;
+      if (!bInstanceOnly) {
+        _t.pan = nPan;
+        _t.options.pan = nPan;
+      }
+      return _t;
+    };
+
+    this.setVolume = function(nVol, bInstanceOnly) {
+      if (typeof nVol === 'undefined') {
+        nVol = 100;
+      }
+      if (typeof bInstanceOnly === 'undefined') {
+        bInstanceOnly = false;
+      }
+      if (!_t.isHTML5) {
+        _s.o._setVolume(_t.sID, (_s.muted && !_t.muted) || _t.muted?0:nVol);
+      } else if (_t._a) {
+        _t._a.volume = Math.max(0, Math.min(1, nVol/100)); // valid range: 0-1
+      }
+      _t._iO.volume = nVol;
+      if (!bInstanceOnly) {
+        _t.volume = nVol;
+        _t.options.volume = nVol;
+      }
+      return _t;
+    };
+
+    this.mute = function() {
+      _t.muted = true;
+      if (!_t.isHTML5) {
+        _s.o._setVolume(_t.sID, 0);
+      } else if (_t._a) {
+        _t._a.muted = true;
+      }
+      return _t;
+    };
+
+    this.unmute = function() {
+      _t.muted = false;
+      var hasIO = typeof _t._iO.volume !== 'undefined';
+      if (!_t.isHTML5) {
+        _s.o._setVolume(_t.sID, hasIO?_t._iO.volume:_t.options.volume);
+      } else if (_t._a) {
+        _t._a.muted = false;
+      }
+      return _t;
+    };
+
+    this.toggleMute = function() {
+      return (_t.muted?_t.unmute():_t.mute());
+    };
+
+    this.onposition = function(nPosition, oMethod, oScope) {
+      // TODO: allow for ranges, too? eg. (nPosition instanceof Array)
+      _t._onPositionItems.push({
+        position: nPosition,
+        method: oMethod,
+        scope: (typeof oScope !== 'undefined'?oScope:_t),
+        fired: false
+      });
+      return _t;
+    };
+
+    this.processOnPosition = function() {
+      var i, item, j = _t._onPositionItems.length;
+      if (!j || !_t.playState || _t._onPositionFired >= j) {
+        return false;
+      }
+      for (i=j; i--;) {
+        item = _t._onPositionItems[i];
+        if (!item.fired && _t.position >= item.position) {
+          item.method.apply(item.scope,[item.position]);
+          item.fired = true;
+          _s._onPositionFired++;
+        }
+      }
+      return true;
+    };
+
+    this.resetOnPosition = function(nPosition) {
+      // reset "fired" for items interested in this position
+      var i, item, j = _t._onPositionItems.length;
+      if (!j) {
+        return false;
+      }
+      for (i=j; i--;) {
+        item = _t._onPositionItems[i];
+        if (item.fired && nPosition <= item.position) {
+          item.fired = false;
+          _s._onPositionFired--;
+        }
+      }
+      return true;
+    };
+
+    /*
+     * private internals
+    */
+
+    _start_html5_timer = function() {
+      if (_t.isHTML5) {
+        _startTimer(_t);
+      }
+    };
+
+    _stop_html5_timer = function() {
+      if (_t.isHTML5) {
+        _stopTimer(_t);
+      }
+    };
+
+    _resetProperties = function() {
+      _t._onPositionItems = [];
+      _t._onPositionFired = 0;
+      _t._hasTimer = null;
+      _t._onplay_called = false;
+      _t._a = null;
+      _t._html5_canplay = false;
+      _t.bytesLoaded = null;
+      _t.bytesTotal = null;
+      _t.position = null;
+      _t.duration = (_t._iO && _t._iO.duration?_t._iO.duration:null);
+      _t.durationEstimate = null;
+      _t.failures = 0;
+      _t.loaded = false;
+      _t.playState = 0;
+      _t.paused = false;
+      _t.readyState = 0; // 0 = uninitialised, 1 = loading, 2 = failed/error, 3 = loaded/success
+      _t.muted = false;
+      _t.didBeforeFinish = false;
+      _t.didJustBeforeFinish = false;
+      _t.isBuffering = false;
+      _t.instanceOptions = {};
+      _t.instanceCount = 0;
+      _t.peakData = {
+        left: 0,
+        right: 0
+      };
+      _t.waveformData = {
+        left: [],
+        right: []
+      };
+      _t.eqData = []; // legacy: 1D array
+      _t.eqData.left = [];
+      _t.eqData.right = [];
+    };
+
+    _resetProperties();
+
+    /*
+     * pseudo-private SMSound internals
+    */
+
+    this._onTimer = function(bForce) {
+      // HTML5-only _whileplaying() etc.
+      var time, x = {};
+      if (_t._hasTimer || bForce) {
+        if (_t._a && (bForce || ((_t.playState > 0 || _t.readyState === 1) && !_t.paused))) { // TODO: May not need to track readyState (1 = loading)
+          _t.duration = _t._get_html5_duration();
+          _t.durationEstimate = _t.duration;
+          time = _t._a.currentTime?_t._a.currentTime*1000:0;
+          _t._whileplaying(time,x,x,x,x);
+          return true;
+        } else {
+         _s._wD('_onTimer: Warn for "'+_t.sID+'": '+(!_t._a?'Could not find element. ':'')+(_t.playState === 0?'playState bad, 0?':'playState = '+_t.playState+', OK'));
+          return false;
+        }
+      }
+    };
+
+    this._get_html5_duration = function() {
+      var d = (_t._a ? _t._a.duration*1000 : (_t._iO ? _t._iO.duration : undefined)),
+          result = (d && !isNaN(d) && d !== Infinity ? d : (_t._iO ? _t._iO.duration : null));
+      return result;
+    };
+
+    this._setup_html5 = function(oOptions) {
+      var _iO = _mixin(_t._iO, oOptions), d = decodeURI,
+          _a = _useGlobalHTML5Audio ? _s._global_a : _t._a,
+          _dURL = d(_iO.url),
+          _oldIO = (_a && _a._t ? _a._t.instanceOptions : null);
+      if (_a) {
+        if (_a._t && _oldIO.url === _iO.url && (!_t._lastURL || (_t._lastURL === _oldIO.url))) {
+          return _a; // same url, ignore request
+        }
+        _s._wD('setting new URL on existing object: ' + _dURL + (_t._lastURL ? ', old URL: ' + _t._lastURL : ''));
+        /*
+         * "First things first, I, Poppa.." (reset the previous state of the old sound, if playing)
+         * Fixes case with devices that can only play one sound at a time
+         * Otherwise, other sounds in mid-play will be terminated without warning and in a stuck state
+        */
+        if (_useGlobalHTML5Audio && _a._t && _a._t.playState && _iO.url !== _oldIO.url) {
+          _a._t.stop();
+        }
+        _resetProperties(); // new URL, so reset load/playstate and so on
+        _a.src = _iO.url;
+        _t.url = _iO.url;
+        _t._lastURL = _iO.url;
+        _a._called_load = false;
+      } else {
+        _s._wD('creating HTML5 Audio() element with URL: '+_dURL);
+        _a = new Audio(_iO.url);
+        _a._called_load = false;
+        if (_useGlobalHTML5Audio) {
+          _s._global_a = _a;
+        }
+      }
+      _t.isHTML5 = true;
+      _t._a = _a; // store a ref on the track
+      _a._t = _t; // store a ref on the audio
+      _t._add_html5_events();
+      _a.loop = (_iO.loops>1?'loop':'');
+      if (_iO.autoLoad || _iO.autoPlay) {
+        _a.autobuffer = 'auto'; // early HTML5 implementation (non-standard)
+        _a.preload = 'auto'; // standard
+        _t.load();
+        _a._called_load = true;
+      } else {
+        _a.autobuffer = false; // early HTML5 implementation (non-standard)
+        _a.preload = 'none'; // standard
+      }
+      _a.loop = (_iO.loops>1?'loop':''); // boolean instead of "loop", for webkit? - spec says string. http://www.w3.org/TR/html-markup/audio.html#audio.attrs.loop
+      return _a;
+    };
+
+    this._add_html5_events = function() {
+
+      if (_t._a._added_events) {
+        return false;
+      }
+
+      var f;
+
+      function add(oEvt, oFn, bCapture) {
+        return _t._a ? _t._a.addEventListener(oEvt, oFn, bCapture||false) : null;
+      }
+
+      _s._wD(_h5+'adding event listeners: '+_t.sID);
+      _t._a._added_events = true;
+
+      for (f in _html5_events) {
+        if (_html5_events.hasOwnProperty(f)) {
+          add(f, _html5_events[f]);
+        }
+      }
+
+      return true;
+
+    };
+
+    this._remove_html5_events = function() {
+
+      // Remove event listeners
+
+      var f;
+
+      function remove(oEvt, oFn, bCapture) {
+        return (_t._a ? _t._a.removeEventListener(oEvt, oFn, bCapture||false) : null);
+      }
+
+      _s._wD(_h5+'removing event listeners: '+_t.sID);
+      _t._a._added_events = false;
+
+      for (f in _html5_events) {
+        if (_html5_events.hasOwnProperty(f)) {
+          remove(f, _html5_events[f]);
+        }
+      }
+
+    };
+
+    /*
+     * pseudo-private event internals
+    */
+
+    this._onload = function(nSuccess) {
+      var fN = 'SMSound._onload(): ', loadOK = (nSuccess?true:false);
+      _s._wD(fN + '"' + _t.sID + '"' + (loadOK?' loaded.':' failed to load? - ' + _t.url), (loadOK?1:2));
+      // <d>
+      if (!loadOK && !_t.isHTML5) {
+        if (_s.sandbox.noRemote === true) {
+          _s._wD(fN + _str('noNet'), 1);
+        }
+        if (_s.sandbox.noLocal === true) {
+          _s._wD(fN + _str('noLocal'), 1);
+        }
+      }
+      // </d>
+      _t.loaded = loadOK;
+      _t.readyState = loadOK?3:2;
+      _t._onbufferchange(0);
+      if (_t._iO.onload) {
+        _t._iO.onload.apply(_t, [loadOK]);
+      }
+      return true;
+    };
+
+    this._onbufferchange = function(nIsBuffering) {
+      var fN = 'SMSound._onbufferchange()';
+      if (_t.playState === 0) {
+        // ignore if not playing
+        return false;
+      }
+      if ((nIsBuffering && _t.isBuffering) || (!nIsBuffering && !_t.isBuffering)) {
+        return false;
+      }
+      _t.isBuffering = (nIsBuffering === 1);
+      if (_t._iO.onbufferchange) {
+        _s._wD(fN + ': ' + nIsBuffering);
+        _t._iO.onbufferchange.apply(_t);
+      }
+      return true;
+    };
+
+    /*
+     * flash-only method, should fire only once at most
+     * at this point we just recreate failed sounds rather than trying to reconnect
+    */
+    this._onfailure = function(msg, level, code) {
+      _t.failures++;
+      _s._wD('SMSound._onfailure(): "'+_t.sID+'" count '+_t.failures);
+      if (_t._iO.onfailure && _t.failures === 1) {
+        _t._iO.onfailure(_t, msg, level, code);
+      } else {
+        _s._wD('SMSound._onfailure(): ignoring');
+      }
+    };
+
+    this._onbeforefinish = function() {
+      if (!_t.didBeforeFinish) {
+        _t.didBeforeFinish = true;
+        if (_t._iO.onbeforefinish) {
+          _s._wD('SMSound._onbeforefinish(): "' + _t.sID + '"');
+          _t._iO.onbeforefinish.apply(_t);
+        }
+      }
+    };
+
+    this._onjustbeforefinish = function(msOffset) {
+      if (!_t.didJustBeforeFinish) {
+        _t.didJustBeforeFinish = true;
+        if (_t._iO.onjustbeforefinish) {
+          _s._wD('SMSound._onjustbeforefinish(): "' + _t.sID + '"');
+          _t._iO.onjustbeforefinish.apply(_t);
+        }
+      }
+    };
+
+    this._onfinish = function() {
+      var _io_onfinish = _t._iO.onfinish; // store local copy before it gets trashed..
+      _t._onbufferchange(0);
+      _t.resetOnPosition(0);
+      if (_t._iO.onbeforefinishcomplete) {
+        _t._iO.onbeforefinishcomplete.apply(_t);
+      }
+      // reset some state items
+      _t.didBeforeFinish = false;
+      _t.didJustBeforeFinish = false;
+      if (_t.instanceCount) {
+        _t.instanceCount--;
+        if (!_t.instanceCount) {
+          // reset instance options
+          _t.playState = 0;
+          _t.paused = false;
+          _t.instanceCount = 0;
+          _t.instanceOptions = {};
+          _t._iO = {};
+          _stop_html5_timer();
+        }
+        if (!_t.instanceCount || _t._iO.multiShotEvents) {
+          // fire onfinish for last, or every instance
+          if (_io_onfinish) {
+            _s._wD('SMSound._onfinish(): "' + _t.sID + '"');
+            _io_onfinish.apply(_t);
+          }
+        }
+      }
+    };
+
+    this._whileloading = function(nBytesLoaded, nBytesTotal, nDuration, nBufferLength) {
+      _t.bytesLoaded = nBytesLoaded;
+      _t.bytesTotal = nBytesTotal;
+      _t.duration = Math.floor(nDuration);
+      _t.bufferLength = nBufferLength;
+      if (!_t._iO.isMovieStar) {
+        if (_t._iO.duration) {
+          // use options, if specified and larger
+          _t.durationEstimate = (_t.duration > _t._iO.duration) ? _t.duration : _t._iO.duration;
+        } else {
+          _t.durationEstimate = parseInt((_t.bytesTotal / _t.bytesLoaded) * _t.duration, 10);
+        }
+        if (_t.durationEstimate === undefined) {
+          _t.durationEstimate = _t.duration;
+        }
+        if (_t.readyState !== 3 && _t._iO.whileloading) {
+          _t._iO.whileloading.apply(_t);
+        }
+      } else {
+        _t.durationEstimate = _t.duration;
+        if (_t.readyState !== 3 && _t._iO.whileloading) {
+          _t._iO.whileloading.apply(_t);
+        }
+      }
+    };
+
+    this._whileplaying = function(nPosition, oPeakData, oWaveformDataLeft, oWaveformDataRight, oEQData) {
+      if (isNaN(nPosition) || nPosition === null) {
+        return false; // flash safety net
+      }
+      _t.position = nPosition;
+      _t.processOnPosition();
+      if (!_t.isHTML5 && _fV > 8) {
+        if (_t._iO.usePeakData && typeof oPeakData !== 'undefined' && oPeakData) {
+          _t.peakData = {
+            left: oPeakData.leftPeak,
+            right: oPeakData.rightPeak
+          };
+        }
+        if (_t._iO.useWaveformData && typeof oWaveformDataLeft !== 'undefined' && oWaveformDataLeft) {
+          _t.waveformData = {
+            left: oWaveformDataLeft.split(','),
+            right: oWaveformDataRight.split(',')
+          };
+        }
+        if (_t._iO.useEQData) {
+          if (typeof oEQData !== 'undefined' && oEQData && oEQData.leftEQ) {
+            var eqLeft = oEQData.leftEQ.split(',');
+            _t.eqData = eqLeft;
+            _t.eqData.left = eqLeft;
+            if (typeof oEQData.rightEQ !== 'undefined' && oEQData.rightEQ) {
+              _t.eqData.right = oEQData.rightEQ.split(',');
+            }
+          }
+        }
+      }
+      if (_t.playState === 1) {
+        // special case/hack: ensure buffering is false if loading from cache (and not yet started)
+        if (!_t.isHTML5 && _s.flashVersion === 8 && !_t.position && _t.isBuffering) {
+          _t._onbufferchange(0);
+        }
+        if (_t._iO.whileplaying) {
+          _t._iO.whileplaying.apply(_t); // flash may call after actual finish
+        }
+        if ((_t.loaded || (!_t.loaded && _t._iO.isMovieStar)) && _t._iO.onbeforefinish && _t._iO.onbeforefinishtime && !_t.didBeforeFinish && _t.duration - _t.position <= _t._iO.onbeforefinishtime) {
+          _t._onbeforefinish();
+        }
+      }
+      return true;
+    };
+
+    this._onid3 = function(oID3PropNames, oID3Data) {
+      // oID3PropNames: string array (names)
+      // ID3Data: string array (data)
+      _s._wD('SMSound._onid3(): "' + this.sID + '" ID3 data received.');
+      var oData = [], i, j;
+      for (i = 0, j = oID3PropNames.length; i < j; i++) {
+        oData[oID3PropNames[i]] = oID3Data[i];
+      }
+      _t.id3 = _mixin(_t.id3, oData);
+      if (_t._iO.onid3) {
+        _t._iO.onid3.apply(_t);
+      }
+    };
+
+    // flash + RTMP
+    this._onconnect = function(bSuccess) {
+      var fN = 'SMSound._onconnect(): ';
+      bSuccess = (bSuccess === 1);
+      _s._wD(fN+'"'+_t.sID+'"'+(bSuccess?' connected.':' failed to connect? - '+_t.url), (bSuccess?1:2));
+      _t.connected = bSuccess;
+      if (bSuccess) {
+        _t.failures = 0;
+        if (_idCheck(_t.sID)) {
+          if (_t.getAutoPlay()) {
+            _t.play(undefined, _t.getAutoPlay()); // only update the play state if auto playing
+          } else if (_t._iO.autoLoad) {
+            _t.load();
+          }
+        }
+        if (_t._iO.onconnect) {
+          _t._iO.onconnect.apply(_t,[bSuccess]);
+        }
+      }
+    };
+
+    this._ondataerror = function(sError) {
+      // flash 9 wave/eq data handler
+      if (_t.playState > 0) { // hack: called at start, and end from flash at/after onfinish()
+        _s._wD('SMSound._ondataerror(): ' + sError);
+        if (_t._iO.ondataerror) {
+          _t._iO.ondataerror.apply(_t);
+        }
+      }
+    };
+
+  }; // SMSound()
+
+  /*
+   * private soundManager internals
+  */
+
+  _getDocument = function() {
+    return (_doc.body || _doc._docElement || _doc.getElementsByTagName('div')[0]);
+  };
+
+  _id = function(sID) {
+    return _doc.getElementById(sID);
+  };
+
+  _mixin = function(oMain, oAdd) {
+    // non-destructive merge
+    var o1 = {}, i, o2, o;
+    for (i in oMain) { // clone c1
+      if (oMain.hasOwnProperty(i)) {
+        o1[i] = oMain[i];
+      }
+    }
+    o2 = (typeof oAdd === 'undefined'?_s.defaultOptions:oAdd);
+    for (o in o2) {
+      if (o2.hasOwnProperty(o) && typeof o1[o] === 'undefined') {
+        o1[o] = o2[o];
+      }
+    }
+    return o1;
+  };
+
+  _event = (function() {
+
+    var old = (_win.attachEvent),
+    evt = {
+      add: (old?'attachEvent':'addEventListener'),
+      remove: (old?'detachEvent':'removeEventListener')
+    };
+
+    function getArgs(oArgs) {
+      var args = _slice.call(oArgs), len = args.length;
+      if (old) {
+        args[1] = 'on' + args[1]; // prefix
+        if (len > 3) {
+          args.pop(); // no capture
+        }
+      } else if (len === 3) {
+        args.push(false);
+      }
+      return args;
+    }
+
+    function apply(args, sType) {
+      var element = args.shift(),
+          method = [evt[sType]];
+      if (old) {
+        element[method](args[0], args[1]);
+      } else {
+        element[method].apply(element, args);
+      }
+    }
+
+    function add() {
+      apply(getArgs(arguments), 'add');
+    }
+
+    function remove() {
+      apply(getArgs(arguments), 'remove');
+    }
+
+    return {
+      'add': add,
+      'remove': remove
+    };
+
+  }());
+
+  _html5OK = function(iO) {
+    return (!iO.serverURL && (iO.type?_html5CanPlay({type:iO.type}):_html5CanPlay({url:iO.url})||_s.html5Only)); // Use type, if specified. If HTML5-only mode, no other options, so just give 'er
+  };
+
+  _html5CanPlay = function(o) {
+
+    /*
+     * try to find MIME, test and return truthiness
+     * o = {
+     *  url: '/path/to/an.mp3',
+     *  type: 'audio/mp3'
+     * }
+    */
+
+    if (!_s.useHTML5Audio || !_s.hasHTML5) {
+      return false;
+    }
+
+    var url = (o.url || null),
+        mime = (o.type || null),
+        aF = _s.audioFormats,
+        result,
+        offset,
+        fileExt,
+        item;
+
+    function preferFlashCheck(kind) {
+      // whether flash should play a given type
+      return (_s.preferFlash && _hasFlash && !_s.ignoreFlash && (typeof _s.flash[kind] !== 'undefined' && _s.flash[kind]));
+    }
+
+    // account for known cases like audio/mp3
+    if (mime && _s.html5[mime] !== 'undefined') {
+      return (_s.html5[mime] && !preferFlashCheck(mime));
+    }
+
+    if (!_html5Ext) {
+      _html5Ext = [];
+      for (item in aF) {
+        if (aF.hasOwnProperty(item)) {
+          _html5Ext.push(item);
+          if (aF[item].related) {
+            _html5Ext = _html5Ext.concat(aF[item].related);
+          }
+        }
+      }
+      _html5Ext = new RegExp('\\.('+_html5Ext.join('|')+')(\\?.*)?$','i');
+    }
+
+    fileExt = (url ? url.toLowerCase().match(_html5Ext) : null); // TODO: Strip URL queries, etc.
+
+    if (!fileExt || !fileExt.length) {
+      if (!mime) {
+        return false;
+      } else {
+        // audio/mp3 -> mp3, result should be known
+        offset = mime.indexOf(';');
+        fileExt = (offset !== -1?mime.substr(0,offset):mime).substr(6); // strip "audio/X; codecs.."
+      }
+    } else {
+      fileExt = fileExt[1]; // match the raw extension name - "mp3", for example
+    }
+
+    if (fileExt && typeof _s.html5[fileExt] !== 'undefined') {
+      // result known
+      return (_s.html5[fileExt] && !preferFlashCheck(fileExt));
+    } else {
+      mime = 'audio/'+fileExt;
+      result = _s.html5.canPlayType({type:mime});
+      _s.html5[fileExt] = result;
+      // _s._wD('canPlayType, found result: '+result);
+      return (result && _s.html5[mime] && !preferFlashCheck(mime));
+    }
+
+  };
+
+  _testHTML5 = function() {
+
+    if (!_s.useHTML5Audio || typeof Audio === 'undefined') {
+      return false;
+    }
+
+    // double-whammy: Opera 9.64 throws WRONG_ARGUMENTS_ERR if no parameter passed to Audio(), and Webkit + iOS happily tries to load "null" as a URL. :/
+    var a = (typeof Audio !== 'undefined' ? (_isOpera ? new Audio(null) : new Audio()) : null),
+        item, support = {}, aF, i;
+
+    function _cp(m) {
+      var canPlay, i, j, isOK = false;
+      if (!a || typeof a.canPlayType !== 'function') {
+        return false;
+      }
+      if (m instanceof Array) {
+        // iterate through all mime types, return any successes
+        for (i=0, j=m.length; i<j && !isOK; i++) {
+          if (_s.html5[m[i]] || a.canPlayType(m[i]).match(_s.html5Test)) {
+            isOK = true;
+            _s.html5[m[i]] = true;
+            // if flash can play and preferred, also mark it for use.
+            _s.flash[m[i]] = !!(_s.preferFlash && _hasFlash && m[i].match(_flashMIME));
+          }
+        }
+        return isOK;
+      } else {
+        canPlay = (a && typeof a.canPlayType === 'function' ? a.canPlayType(m) : false);
+        return !!(canPlay && (canPlay.match(_s.html5Test)));
+      }
+    }
+
+    // test all registered formats + codecs
+    aF = _s.audioFormats;
+    for (item in aF) {
+      if (aF.hasOwnProperty(item)) {
+        support[item] = _cp(aF[item].type);
+        support['audio/'+item] = support[item]; // write back generic type too, eg. audio/mp3
+        // assign flash
+        if (_s.preferFlash && !_s.ignoreFlash && item.match(_flashMIME)) {
+          _s.flash[item] = true;
+        } else {
+          _s.flash[item] = false;
+        }
+        // assign result to related formats, too
+        if (aF[item] && aF[item].related) {
+          for (i=aF[item].related.length; i--;) {
+            support['audio/'+aF[item].related[i]] = support[item]; // eg. audio/m4a
+            _s.html5[aF[item].related[i]] = support[item];
+            _s.flash[aF[item].related[i]] = support[item];
+          }
+        }
+      }
+    }
+
+    support.canPlayType = (a?_cp:null);
+    _s.html5 = _mixin(_s.html5, support);
+    return true;
+
+  };
+
+  _strings = {
+    // <d>
+    notReady: 'Not loaded yet - wait for soundManager.onload()/onready()',
+    notOK: 'Audio support is not available.',
+    domError: _smc + 'createMovie(): appendChild/innerHTML call failed. DOM not ready or other error.',
+    spcWmode: _smc + 'createMovie(): Removing wmode, preventing known SWF loading issue(s)',
+    swf404: _sm + ': Verify that %s is a valid path.',
+    tryDebug: 'Try ' + _sm + '.debugFlash = true for more security details (output goes to SWF.)',
+    checkSWF: 'See SWF output for more debug info.',
+    localFail: _sm + ': Non-HTTP page (' + _doc.location.protocol + ' URL?) Review Flash player security settings for this special case:\nhttp://www.macromedia.com/support/documentation/en/flashplayer/help/settings_manager04.html\nMay need to add/allow path, eg. c:/sm2/ or /users/me/sm2/',
+    waitFocus: _sm + ': Special case: Waiting for focus-related event..',
+    waitImpatient: _sm + ': Getting impatient, still waiting for Flash%s...',
+    waitForever: _sm + ': Waiting indefinitely for Flash (will recover if unblocked)...',
+    needFunction: _sm + ': Function object expected for %s',
+    badID: 'Warning: Sound ID "%s" should be a string, starting with a non-numeric character',
+    noMS: 'MovieStar mode not enabled. Exiting.',
+    currentObj: '--- ' + _sm + '._debug(): Current sound objects ---',
+    waitEI: _smc + 'initMovie(): Waiting for ExternalInterface call from Flash..',
+    waitOnload: _sm + ': Waiting for window.onload()',
+    docLoaded: _sm + ': Document already loaded',
+    onload: _smc + 'initComplete(): calling soundManager.onload()',
+    onloadOK: _sm + '.onload() complete',
+    init: _smc + 'init()',
+    didInit: _smc + 'init(): Already called?',
+    flashJS: _sm + ': Attempting to call Flash from JS..',
+    noPolling: _sm + ': Polling (whileloading()/whileplaying() support) is disabled.',
+    secNote: 'Flash security note: Network/internet URLs will not load due to security restrictions. Access can be configured via Flash Player Global Security Settings Page: http://www.macromedia.com/support/documentation/en/flashplayer/help/settings_manager04.html',
+    badRemove: 'Warning: Failed to remove flash movie.',
+    noPeak: 'Warning: peakData features unsupported for movieStar formats',
+    shutdown: _sm + '.disable(): Shutting down',
+    queue: _sm + ': Queueing %s handler',
+    smFail: _sm + ': Failed to initialise.',
+    smError: 'SMSound.load(): Exception: JS-Flash communication failed, or JS error.',
+    fbTimeout: 'No flash response, applying .'+_s.swfCSS.swfTimedout+' CSS..',
+    fbLoaded: 'Flash loaded',
+    fbHandler: _smc+'flashBlockHandler()',
+    manURL: 'SMSound.load(): Using manually-assigned URL',
+    onURL: _sm + '.load(): current URL already assigned.',
+    badFV: _sm + '.flashVersion must be 8 or 9. "%s" is invalid. Reverting to %s.',
+    as2loop: 'Note: Setting stream:false so looping can work (flash 8 limitation)',
+    noNSLoop: 'Note: Looping not implemented for MovieStar formats',
+    needfl9: 'Note: Switching to flash 9, required for MP4 formats.',
+    mfTimeout: 'Setting flashLoadTimeout = 0 (infinite) for off-screen, mobile flash case',
+    mfOn: 'mobileFlash::enabling on-screen flash repositioning',
+    policy: 'Enabling usePolicyFile for data access'
+    // </d>
+  };
+
+  _str = function() { // o [,items to replace]
+    // <d>
+    var args = _slice.call(arguments), // real array, please
+    o = args.shift(), // first arg
+    str = (_strings && _strings[o]?_strings[o]:''), i, j;
+    if (str && args && args.length) {
+      for (i = 0, j = args.length; i < j; i++) {
+        str = str.replace('%s', args[i]);
+      }
+    }
+    return str;
+    // </d>
+  };
+
+  _loopFix = function(sOpt) {
+    // flash 8 requires stream = false for looping to work
+    if (_fV === 8 && sOpt.loops > 1 && sOpt.stream) {
+      _wDS('as2loop');
+      sOpt.stream = false;
+    }
+    return sOpt;
+  };
+
+  _policyFix = function(sOpt, sPre) {
+    if (sOpt && !sOpt.usePolicyFile && (sOpt.onid3 || sOpt.usePeakData || sOpt.useWaveformData || sOpt.useEQData)) {
+      _s._wD((sPre || '') + _str('policy'));
+      sOpt.usePolicyFile = true;
+    }
+    return sOpt;
+  };
+
+  _complain = function(sMsg) {
+    if (typeof console !== 'undefined' && typeof console.warn !== 'undefined') {
+      console.warn(sMsg);
+    } else {
+      _s._wD(sMsg);
+    }
+  };
+
+  _doNothing = function() {
+    return false;
+  };
+
+  _disableObject = function(o) {
+    var oProp;
+    for (oProp in o) {
+      if (o.hasOwnProperty(oProp) && typeof o[oProp] === 'function') {
+        o[oProp] = _doNothing;
+      }
+    }
+    oProp = null;
+  };
+
+  _failSafely = function(bNoDisable) {
+    // general failure exception handler
+    if (typeof bNoDisable === 'undefined') {
+      bNoDisable = false;
+    }
+    if (_disabled || bNoDisable) {
+      _wDS('smFail', 2);
+      _s.disable(bNoDisable);
+    }
+  };
+
+  _normalizeMovieURL = function(smURL) {
+    var urlParams = null;
+    if (smURL) {
+      if (smURL.match(/\.swf(\?.*)?$/i)) {
+        urlParams = smURL.substr(smURL.toLowerCase().lastIndexOf('.swf?') + 4);
+        if (urlParams) {
+          return smURL; // assume user knows what they're doing
+        }
+      } else if (smURL.lastIndexOf('/') !== smURL.length - 1) {
+        smURL = smURL + '/';
+      }
+    }
+    return (smURL && smURL.lastIndexOf('/') !== - 1?smURL.substr(0, smURL.lastIndexOf('/') + 1):'./') + _s.movieURL;
+  };
+
+  _setVersionInfo = function() {
+
+    if (_fV !== 8 && _fV !== 9) {
+      _s._wD(_str('badFV', _fV, _defaultFlashVersion));
+      _s.flashVersion = _defaultFlashVersion;
+    }
+    var isDebug = (_s.debugMode || _s.debugFlash?'_debug.swf':'.swf'); // debug flash movie, if applicable
+    if (_s.useHTML5Audio && !_s.html5Only && _s.audioFormats.mp4.required && _s.flashVersion < 9) {
+      _s._wD(_str('needfl9'));
+      _s.flashVersion = 9;
+    }
+    _fV = _s.flashVersion; // short-hand for internal use
+    _s.version = _s.versionNumber + (_s.html5Only?' (HTML5-only mode)':(_fV === 9?' (AS3/Flash 9)':' (AS2/Flash 8)'));
+    // set up default options
+    if (_fV > 8) {
+      _s.defaultOptions = _mixin(_s.defaultOptions, _s.flash9Options);
+      _s.features.buffering = true;
+    }
+    if (_fV > 8 && _s.useMovieStar) {
+      // flash 9+ support for movieStar formats as well as MP3
+      _s.defaultOptions = _mixin(_s.defaultOptions, _s.movieStarOptions);
+      _s.filePatterns.flash9 = new RegExp('\\.(mp3|' + _s.netStreamTypes.join('|') + ')(\\?.*)?$', 'i');
+      _s.mimePattern = _s.netStreamMimeTypes;
+      _s.features.movieStar = true;
+    } else {
+      _s.useMovieStar = false;
+      _s.features.movieStar = false;
+    }
+    _s.filePattern = _s.filePatterns[(_fV !== 8?'flash9':'flash8')];
+    _s.movieURL = (_fV === 8?'soundmanager2.swf':'soundmanager2_flash9.swf').replace('.swf',isDebug);
+    _s.features.peakData = _s.features.waveformData = _s.features.eqData = (_fV > 8);
+  };
+
+  _setPolling = function(bPolling, bHighPerformance) {
+    if (!_s.o || !_s.allowPolling) {
+      return false;
+    }
+    _s.o._setPolling(bPolling, bHighPerformance);
+  };
+
+  _initDebug = function() {
+    if (_s.debugURLParam.test(_wl)) {
+      _s.debugMode = true; // allow force of debug mode via URL
+    }
+    // <d>
+    if (_id(_s.debugID)) {
+      return false;
+    }
+    var oD, oDebug, oTarget, oToggle, tmp;
+    if (_s.debugMode && !_id(_s.debugID) && ((!_hasConsole || !_s.useConsole) || (_s.useConsole && _hasConsole && !_s.consoleOnly))) {
+      oD = _doc.createElement('div');
+      oD.id = _s.debugID + '-toggle';
+      oToggle = {
+        'position': 'fixed',
+        'bottom': '0px',
+        'right': '0px',
+        'width': '1.2em',
+        'height': '1.2em',
+        'lineHeight': '1.2em',
+        'margin': '2px',
+        'textAlign': 'center',
+        'border': '1px solid #999',
+        'cursor': 'pointer',
+        'background': '#fff',
+        'color': '#333',
+        'zIndex': 10001
+      };
+      oD.appendChild(_doc.createTextNode('-'));
+      oD.onclick = _toggleDebug;
+      oD.title = 'Toggle SM2 debug console';
+      if (_ua.match(/msie 6/i)) {
+        oD.style.position = 'absolute';
+        oD.style.cursor = 'hand';
+      }
+      for (tmp in oToggle) {
+        if (oToggle.hasOwnProperty(tmp)) {
+          oD.style[tmp] = oToggle[tmp];
+        }
+      }
+      oDebug = _doc.createElement('div');
+      oDebug.id = _s.debugID;
+      oDebug.style.display = (_s.debugMode?'block':'none');
+      if (_s.debugMode && !_id(oD.id)) {
+        try {
+          oTarget = _getDocument();
+          oTarget.appendChild(oD);
+        } catch(e2) {
+          throw new Error(_str('domError')+' \n'+e2.toString());
+        }
+        oTarget.appendChild(oDebug);
+      }
+    }
+    oTarget = null;
+    // </d>
+  };
+
+  _idCheck = this.getSoundById;
+
+  // <d>
+  _wDS = function(o, errorLevel) {
+    if (!o) {
+      return '';
+    } else {
+      return _s._wD(_str(o), errorLevel);
+    }
+  };
+
+  // last-resort debugging option
+  if (_wl.indexOf('sm2-debug=alert') + 1 && _s.debugMode) {
+    _s._wD = function(sText) {window.alert(sText);};
+  }
+
+  _toggleDebug = function() {
+    var o = _id(_s.debugID),
+    oT = _id(_s.debugID + '-toggle');
+    if (!o) {
+      return false;
+    }
+    if (_debugOpen) {
+      // minimize
+      oT.innerHTML = '+';
+      o.style.display = 'none';
+    } else {
+      oT.innerHTML = '-';
+      o.style.display = 'block';
+    }
+    _debugOpen = !_debugOpen;
+  };
+
+  _debugTS = function(sEventType, bSuccess, sMessage) {
+    // troubleshooter debug hooks
+    if (typeof sm2Debugger !== 'undefined') {
+      try {
+        sm2Debugger.handleEvent(sEventType, bSuccess, sMessage);
+      } catch(e) {
+        // oh well
+      }
+    }
+    return true;
+  };
+  // </d>
+
+  _getSWFCSS = function() {
+    var css = [];
+    if (_s.debugMode) {
+      css.push(_s.swfCSS.sm2Debug);
+    }
+    if (_s.debugFlash) {
+      css.push(_s.swfCSS.flashDebug);
+    }
+    if (_s.useHighPerformance) {
+      css.push(_s.swfCSS.highPerf);
+    }
+    return css.join(' ');
+  };
+
+  _flashBlockHandler = function() {
+    // *possible* flash block situation.
+    var name = _str('fbHandler'),
+        p = _s.getMoviePercent(),
+        css = _s.swfCSS,
+        error = {type:'FLASHBLOCK'};
+    if (_s.html5Only) {
+      return false;
+    }
+    if (!_s.ok()) {
+      if (_needsFlash) {
+        // make the movie more visible, so user can fix
+        _s.oMC.className = _getSWFCSS() + ' ' + css.swfDefault + ' ' + (p === null?css.swfTimedout:css.swfError);
+        _s._wD(name+': '+_str('fbTimeout')+(p?' ('+_str('fbLoaded')+')':''));
+      }
+      _s.didFlashBlock = true;
+      _processOnEvents({type:'ontimeout', ignoreInit:true, error:error}); // fire onready(), complain lightly
+      _catchError(error);
+    } else {
+      // SM2 loaded OK (or recovered)
+      if (_s.didFlashBlock) {
+        _s._wD(name+': Unblocked');
+      }
+      if (_s.oMC) {
+        _s.oMC.className = [_getSWFCSS(), css.swfDefault, css.swfLoaded + (_s.didFlashBlock?' '+css.swfUnblocked:'')].join(' ');
+      }
+    }
+  };
+
+  _addOnEvent = function(sType, oMethod, oScope) {
+    if (typeof _on_queue[sType] === 'undefined') {
+      _on_queue[sType] = [];
+    }
+    _on_queue[sType].push({
+      'method': oMethod,
+      'scope': (oScope || null),
+      'fired': false
+    });
+  };
+
+  _processOnEvents = function(oOptions) {
+    if (!oOptions) { // assume onready, if unspecified
+      oOptions = {
+        type: 'onready'
+      };
+    }
+    if (!_didInit && oOptions && !oOptions.ignoreInit) {
+      // not ready yet.
+      return false;
+    }
+    if (oOptions.type === 'ontimeout' && _s.ok()) {
+      // invalid case
+      return false;
+    }
+    var status = {
+          success: (oOptions && oOptions.ignoreInit?_s.ok():!_disabled)
+        },
+        srcQueue = (oOptions && oOptions.type?_on_queue[oOptions.type]||[]:[]), // queue specified by type, or none
+        queue = [], i, j,
+        args = [status],
+        canRetry = (_needsFlash && _s.useFlashBlock && !_s.ok());
+    if (oOptions.error) {
+      args[0].error = oOptions.error;
+    }
+    for (i = 0, j = srcQueue.length; i < j; i++) {
+      if (srcQueue[i].fired !== true) {
+        queue.push(srcQueue[i]);
+      }
+    }
+    if (queue.length) {
+      _s._wD(_sm + ': Firing ' + queue.length + ' '+oOptions.type+'() item' + (queue.length === 1?'':'s'));
+      for (i = 0, j = queue.length; i < j; i++) {
+        if (queue[i].scope) {
+          queue[i].method.apply(queue[i].scope, args);
+        } else {
+          queue[i].method.apply(this, args);
+        }
+        if (!canRetry) { // flashblock case doesn't count here
+          queue[i].fired = true;
+        }
+      }
+    }
+    return true;
+  };
+
+  _initUserOnload = function() {
+    _win.setTimeout(function() {
+      if (_s.useFlashBlock) {
+        _flashBlockHandler();
+      }
+      _processOnEvents();
+      // call user-defined "onload", scoped to window
+      if (_s.onload instanceof Function) {
+        _wDS('onload', 1);
+        _s.onload.apply(_win);
+        _wDS('onloadOK', 1);
+      }
+      if (_s.waitForWindowLoad) {
+        _event.add(_win, 'load', _initUserOnload);
+      }
+    },1);
+  };
+
+  _detectFlash = function() {
+
+    // hat tip: Flash Detect library (BSD, (C) 2007) by Carl "DocYes" S. Yestrau - http://featureblend.com/javascript-flash-detection-library.html / http://featureblend.com/license.txt
+
+    if (_hasFlash !== undefined) {
+      // this work has already been done.
+      return _hasFlash;
+    }
+
+    var hasPlugin = false, n = navigator, nP = n.plugins, obj, type, types, AX = _win.ActiveXObject;
+
+    if (nP && nP.length) {
+
+      type = 'application/x-shockwave-flash';
+      types = n.mimeTypes;
+      if (types && types[type] && types[type].enabledPlugin && types[type].enabledPlugin.description) {
+        hasPlugin = true;
+      }
+
+    } else if (typeof AX !== 'undefined') {
+
+      try {
+        obj = new AX('ShockwaveFlash.ShockwaveFlash');
+      } catch(e) {
+        // oh well
+      }
+      hasPlugin = (!!obj);
+
+    }
+
+    _hasFlash = hasPlugin;
+
+    return hasPlugin;
+
+  };
+
+  _featureCheck = function() {
+
+    var needsFlash, item,
+        isSpecial = (_ua.match(/iphone os (1|2|3_0|3_1)/i)?true:false); // iPhone <= 3.1 has broken HTML5 audio(), but firmware 3.2 (iPad) + iOS4 works.
+
+    if (isSpecial) {
+      _s.hasHTML5 = false; // has Audio(), but is broken; let it load links directly.
+      _s.html5Only = true; // ignore flash case, however
+      if (_s.oMC) {
+        _s.oMC.style.display = 'none';
+      }
+      return false;
+    }
+
+    if (_s.useHTML5Audio) {
+      if (!_s.html5 || !_s.html5.canPlayType) {
+        _s._wD('SoundManager: No HTML5 Audio() support detected.');
+        _s.hasHTML5 = false;
+        return true;
+      } else {
+        _s.hasHTML5 = true;
+      }
+      if (_isBadSafari) {
+        _s._wD(_smc+'Note: Buggy HTML5 Audio in Safari on this OS X release, see https://bugs.webkit.org/show_bug.cgi?id=32159 - '+(!_hasFlash?' would use flash fallback for MP3/MP4, but none detected.':'will use flash fallback for MP3/MP4, if available'),1);
+        if (_detectFlash()) {
+          return true;
+        }
+      }
+    } else {
+      // flash needed (or, HTML5 needs enabling.)
+      return true;
+    }
+
+    for (item in _s.audioFormats) {
+      if (_s.audioFormats.hasOwnProperty(item)) {
+        if ( (_s.audioFormats[item].required && !_s.html5.canPlayType(_s.audioFormats[item].type)) || _s.flash[item] || _s.flash[_s.audioFormats[item].type]) {
+          // flash may be required, or preferred for this format
+          needsFlash = true;
+        }
+      }
+    }
+
+    // sanity check..
+    if (_s.ignoreFlash) {
+      needsFlash = false;
+    }
+
+    _s.html5Only = (_s.hasHTML5 && _s.useHTML5Audio && !needsFlash);
+
+    return (!_s.html5Only);
+
+  };
+
+  _startTimer = function(oSound) {
+    if (!oSound._hasTimer) {
+      oSound._hasTimer = true;
+    }
+  };
+
+  _stopTimer = function(oSound) {
+    if (oSound._hasTimer) {
+      oSound._hasTimer = false;
+    }
+  };
+
+  _catchError = function(options) {
+    options = (typeof options !== 'undefined' ? options : {});
+    if (_s.onerror instanceof Function) {
+      _s.onerror.apply(_win, [{type:(typeof options.type !== 'undefined' ? options.type : null)}]);
+    }
+    if (typeof options.fatal !== 'undefined' && options.fatal) {
+      _s.disable();
+    }
+  };
+
+  _badSafariFix = function() {
+    // special case: "bad" Safari (OS X 10.3 - 10.7) must fall back to flash for MP3/MP4
+    if (!_isBadSafari || !_detectFlash()) {
+      return false; // doesn't apply
+    }
+    var aF = _s.audioFormats, i, item;
+    for (item in aF) {
+      if (aF.hasOwnProperty(item)) {
+        if (item === 'mp3' || item === 'mp4') {
+          _s._wD(_sm+': Using flash fallback for '+item+' format');
+          _s.html5[item] = false;
+          // assign result to related formats, too
+          if (aF[item] && aF[item].related) {
+            for (i = aF[item].related.length; i--;) {
+              _s.html5[aF[item].related[i]] = false;
+            }
+          }
+        }
+      }
+    }
+  };
+
+  /*
+   * pseudo-private flash/ExternalInterface methods
+  */
+
+  this._setSandboxType = function(sandboxType) {
+    // <d>
+    var sb = _s.sandbox;
+    sb.type = sandboxType;
+    sb.description = sb.types[(typeof sb.types[sandboxType] !== 'undefined'?sandboxType:'unknown')];
+    _s._wD('Flash security sandbox type: ' + sb.type);
+    if (sb.type === 'localWithFile') {
+      sb.noRemote = true;
+      sb.noLocal = false;
+      _wDS('secNote', 2);
+    } else if (sb.type === 'localWithNetwork') {
+      sb.noRemote = false;
+      sb.noLocal = true;
+    } else if (sb.type === 'localTrusted') {
+      sb.noRemote = false;
+      sb.noLocal = false;
+    }
+    // </d>
+  };
+
+  this._externalInterfaceOK = function(flashDate) {
+    // flash callback confirming flash loaded, EI working etc.
+    // flashDate = approx. timing/delay info for JS/flash bridge
+    if (_s.swfLoaded) {
+      return false;
+    }
+    var eiTime = new Date().getTime();
+    _s._wD(_smc+'externalInterfaceOK()' + (flashDate?' (~' + (eiTime - flashDate) + ' ms)':''));
+    _debugTS('swf', true);
+    _debugTS('flashtojs', true);
+    _s.swfLoaded = true;
+    _tryInitOnFocus = false;
+    if (_isBadSafari) {
+      _badSafariFix();
+    }
+    if (_isIE) {
+      // IE needs a timeout OR delay until window.onload - may need TODO: investigating
+      setTimeout(_init, 100);
+    } else {
+      _init();
+    }
+  };
+
+  /*
+   * private initialization helpers
+  */
+
+  _createMovie = function(smID, smURL) {
+
+    if (_didAppend && _appendSuccess) {
+      return false; // ignore if already succeeded
+    }
+
+    function _initMsg() {
+      _s._wD('-- SoundManager 2 ' + _s.version + (!_s.html5Only && _s.useHTML5Audio?(_s.hasHTML5?' + HTML5 audio':', no HTML5 audio support'):'') + (!_s.html5Only ? (_s.useMovieStar?', MovieStar mode':'') + (_s.useHighPerformance?', high performance mode, ':', ') + (( _s.flashPollingInterval ? 'custom (' + _s.flashPollingInterval + 'ms)' : (_s.useFastPolling?'fast':'normal')) + ' polling') + (_s.wmode?', wmode: ' + _s.wmode:'') + (_s.debugFlash?', flash debug mode':'') + (_s.useFlashBlock?', flashBlock mode':'') : '') + ' --', 1);
+    }
+
+    if (_s.html5Only) {
+      // 100% HTML5 mode
+      _setVersionInfo();
+      _initMsg();
+      _s.oMC = _id(_s.movieID);
+      _init();
+      // prevent multiple init attempts
+      _didAppend = true;
+      _appendSuccess = true;
+      return false;
+    }
+
+    // flash path
+    var remoteURL = (smURL || _s.url),
+    localURL = (_s.altURL || remoteURL),
+    swfTitle = 'JS/Flash audio component (SoundManager 2)',
+    oEmbed, oMovie, oTarget = _getDocument(), tmp, movieHTML, oEl, extraClass = _getSWFCSS(), s, x, sClass, side = 'auto', isRTL = null, html = _doc.getElementsByTagName('html')[0];
+
+    isRTL = (html && html.dir && html.dir.match(/rtl/i));
+    smID = (typeof smID === 'undefined'?_s.id:smID);
+
+    function param(name, value) {
+      return '<param name="'+name+'" value="'+value+'" />';
+    }
+
+    // safety check for legacy (change to Flash 9 URL)
+    _setVersionInfo();
+    _s.url = _normalizeMovieURL(_overHTTP?remoteURL:localURL);
+    smURL = _s.url;
+
+    _s.wmode = (!_s.wmode && _s.useHighPerformance && !_s.useMovieStar?'transparent':_s.wmode);
+
+    if (_s.wmode !== null && (_ua.match(/msie 8/i) || (!_isIE && !_s.useHighPerformance)) && navigator.platform.match(/win32|win64/i)) {
+      /*
+       * extra-special case: movie doesn't load until scrolled into view when using wmode = anything but 'window' here
+       * does not apply when using high performance (position:fixed means on-screen), OR infinite flash load timeout
+       * wmode breaks IE 8 on Vista + Win7 too in some cases, as of January 2011 (?)
+      */
+      _s.specialWmodeCase = true;
+      _wDS('spcWmode');
+      _s.wmode = null;
+    }
+
+    oEmbed = {
+      'name': smID,
+      'id': smID,
+      'src': smURL,
+      'width': side,
+      'height': side,
+      'quality': 'high',
+      'allowScriptAccess': _s.allowScriptAccess,
+      'bgcolor': _s.bgColor,
+      'pluginspage': _http+'//www.macromedia.com/go/getflashplayer',
+      'title': swfTitle,
+      'type': 'application/x-shockwave-flash',
+      'wmode': _s.wmode,
+      'hasPriority': 'true' // http://help.adobe.com/en_US/as3/mobile/WS4bebcd66a74275c36cfb8137124318eebc6-7ffd.html
+    };
+
+    if (_s.debugFlash) {
+      oEmbed.FlashVars = 'debug=1';
+    }
+
+    if (!_s.wmode) {
+      delete oEmbed.wmode; // don't write empty attribute
+    }
+
+    if (_isIE) {
+
+      // IE is "special".
+      oMovie = _doc.createElement('div');
+      movieHTML = [
+        '<object id="' + smID + '" data="' + smURL + '" type="' + oEmbed.type + '" title="' + oEmbed.title +'" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="' + _http+'//download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" width="' + oEmbed.width + '" height="' + oEmbed.height + '">',
+        param('movie', smURL),
+        param('AllowScriptAccess', _s.allowScriptAccess),
+        param('quality', oEmbed.quality),
+        (_s.wmode? param('wmode', _s.wmode): ''),
+        param('bgcolor', _s.bgColor),
+        param('hasPriority', 'true'),
+        (_s.debugFlash ? param('FlashVars', oEmbed.FlashVars) : ''),
+        '</object>'
+      ].join('');
+
+    } else {
+
+      oMovie = _doc.createElement('embed');
+      for (tmp in oEmbed) {
+        if (oEmbed.hasOwnProperty(tmp)) {
+          oMovie.setAttribute(tmp, oEmbed[tmp]);
+        }
+      }
+
+    }
+
+    _initDebug();
+    extraClass = _getSWFCSS();
+    oTarget = _getDocument();
+
+    if (oTarget) {
+
+      _s.oMC = (_id(_s.movieID) || _doc.createElement('div'));
+
+      if (!_s.oMC.id) {
+
+        _s.oMC.id = _s.movieID;
+        _s.oMC.className = _s.swfCSS.swfDefault + ' ' + extraClass;
+        s = null;
+        oEl = null;
+
+        if (!_s.useFlashBlock) {
+          if (_s.useHighPerformance) {
+            // on-screen at all times
+            s = {
+              'position': 'fixed',
+              'width': '8px',
+              'height': '8px',
+              // >= 6px for flash to run fast, >= 8px to start up under Firefox/win32 in some cases. odd? yes.
+              'bottom': '0px',
+              'left': '0px',
+              'overflow': 'hidden'
+            };
+          } else {
+            // hide off-screen, lower priority
+            s = {
+              'position': 'absolute',
+              'width': '6px',
+              'height': '6px',
+              'top': '-9999px',
+              'left': '-9999px'
+            };
+            if (isRTL) {
+              s.left = Math.abs(parseInt(s.left,10))+'px';
+            }
+          }
+        }
+
+        if (_isWebkit) {
+          _s.oMC.style.zIndex = 10000; // soundcloud-reported render/crash fix, safari 5
+        }
+
+        if (!_s.debugFlash) {
+          for (x in s) {
+            if (s.hasOwnProperty(x)) {
+              _s.oMC.style[x] = s[x];
+            }
+          }
+        }
+
+        try {
+          if (!_isIE) {
+            _s.oMC.appendChild(oMovie);
+          }
+          oTarget.appendChild(_s.oMC);
+          if (_isIE) {
+            oEl = _s.oMC.appendChild(_doc.createElement('div'));
+            oEl.className = _s.swfCSS.swfBox;
+            oEl.innerHTML = movieHTML;
+          }
+          _appendSuccess = true;
+        } catch(e) {
+          throw new Error(_str('domError')+' \n'+e.toString());
+        }
+
+      } else {
+
+        // SM2 container is already in the document (eg. flashblock use case)
+        sClass = _s.oMC.className;
+        _s.oMC.className = (sClass?sClass+' ':_s.swfCSS.swfDefault) + (extraClass?' '+extraClass:'');
+        _s.oMC.appendChild(oMovie);
+        if (_isIE) {
+          oEl = _s.oMC.appendChild(_doc.createElement('div'));
+          oEl.className = _s.swfCSS.swfBox;
+          oEl.innerHTML = movieHTML;
+        }
+        _appendSuccess = true;
+
+      }
+
+    }
+
+    _didAppend = true;
+    _initMsg();
+    _s._wD(_smc+'createMovie(): Trying to load ' + smURL + (!_overHTTP && _s.altURL?' (alternate URL)':''), 1);
+
+    return true;
+
+  };
+
+  _initMovie = function() {
+
+    if (_s.html5Only) {
+      _createMovie();
+      return false;
+    }
+
+    // attempt to get, or create, movie
+    if (_s.o) {
+      return false; // may already exist
+    }
+
+    _s.o = _s.getMovie(_s.id); // inline markup
+
+    if (!_s.o) {
+      if (!_oRemoved) {
+        // try to create
+        _createMovie(_s.id, _s.url);
+      } else {
+        // try to re-append removed movie after reboot()
+        if (!_isIE) {
+          _s.oMC.appendChild(_oRemoved);
+        } else {
+          _s.oMC.innerHTML = _oRemovedHTML;
+        }
+        _oRemoved = null;
+        _didAppend = true;
+      }
+      _s.o = _s.getMovie(_s.id);
+    }
+
+    if (_s.o) {
+      _wDS('waitEI');
+    }
+
+    if (_s.oninitmovie instanceof Function) {
+      setTimeout(_s.oninitmovie, 1);
+    }
+
+    return true;
+
+  };
+
+  _delayWaitForEI = function() {
+    setTimeout(_waitForEI, 1000);
+  };
+
+  _waitForEI = function() {
+
+    if (_waitingForEI) {
+      return false;
+    }
+
+    _waitingForEI = true;
+    _event.remove(_win, 'load', _delayWaitForEI);
+
+    if (_tryInitOnFocus && !_isFocused) {
+      // giant Safari 3.1 hack - assume mousemove = focus given lack of focus event
+      _wDS('waitFocus');
+      return false;
+    }
+
+    var p;
+    if (!_didInit) {
+      p = _s.getMoviePercent();
+      _s._wD(_str('waitImpatient', (p === 100?' (SWF loaded)':(p > 0?' (SWF ' + p + '% loaded)':''))));
+    }
+
+    setTimeout(function() {
+
+      p = _s.getMoviePercent();
+
+      if (!_didInit) {
+        _s._wD(_sm + ': No Flash response within expected time.\nLikely causes: ' + (p === 0?'Loading ' + _s.movieURL + ' may have failed (and/or Flash ' + _fV + '+ not present?), ':'') + 'Flash blocked or JS-Flash security error.' + (_s.debugFlash?' ' + _str('checkSWF'):''), 2);
+        if (!_overHTTP && p) {
+          _wDS('localFail', 2);
+          if (!_s.debugFlash) {
+            _wDS('tryDebug', 2);
+          }
+        }
+        if (p === 0) {
+          // if 0 (not null), probably a 404.
+          _s._wD(_str('swf404', _s.url));
+        }
+        _debugTS('flashtojs', false, ': Timed out' + _overHTTP?' (Check flash security or flash blockers)':' (No plugin/missing SWF?)');
+      }
+
+      // give up / time-out, depending
+      if (!_didInit && _okToDisable) {
+        if (p === null) {
+          // SWF failed. Maybe blocked.
+          if (_s.useFlashBlock || _s.flashLoadTimeout === 0) {
+            if (_s.useFlashBlock) {
+              _flashBlockHandler();
+            }
+            _wDS('waitForever');
+          } else {
+            // old SM2 behaviour, simply fail
+            _failSafely(true);
+          }
+
+        } else {
+          // flash loaded? Shouldn't be a blocking issue, then.
+          if (_s.flashLoadTimeout === 0) {
+             _wDS('waitForever');
+          } else {
+            _failSafely(true);
+          }
+        }
+      }
+
+    }, _s.flashLoadTimeout);
+
+  };
+
+  _handleFocus = function() {
+    function cleanup() {
+      _event.remove(_win, 'focus', _handleFocus);
+      _event.remove(_win, 'load', _handleFocus);
+    }
+    if (_isFocused || !_tryInitOnFocus) {
+      cleanup();
+      return true;
+    }
+    _okToDisable = true;
+    _isFocused = true;
+    _s._wD(_smc+'handleFocus()');
+    if (_isSafari && _tryInitOnFocus) {
+      _event.remove(_win, 'mousemove', _handleFocus);
+    }
+    // allow init to restart
+    _waitingForEI = false;
+    cleanup();
+    return true;
+  };
+
+  _initComplete = function(bNoDisable) {
+    if (_didInit) {
+      return false;
+    }
+    if (_s.html5Only) {
+      // all good.
+      _s._wD('-- SoundManager 2: loaded --');
+      _didInit = true;
+      _initUserOnload();
+      _debugTS('onload', true);
+      return true;
+    }
+    var wasTimeout = (_s.useFlashBlock && _s.flashLoadTimeout && !_s.getMoviePercent()),
+        error;
+    if (!wasTimeout) {
+      _didInit = true;
+      if (_disabled) {
+        error = {type: (!_hasFlash && _needsFlash ? 'NO_FLASH' : 'INIT_TIMEOUT')};
+      }
+    }
+    _s._wD('-- SoundManager 2 ' + (_disabled?'failed to load':'loaded') + ' (' + (_disabled?'security/load error':'OK') + ') --', 1);
+    if (_disabled || bNoDisable) {
+      if (_s.useFlashBlock && _s.oMC) {
+        _s.oMC.className = _getSWFCSS() + ' ' + (_s.getMoviePercent() === null?_s.swfCSS.swfTimedout:_s.swfCSS.swfError);
+      }
+      _processOnEvents({type:'ontimeout', error:error});
+      _debugTS('onload', false);
+      _catchError(error);
+      return false;
+    } else {
+      _debugTS('onload', true);
+    }
+    _event.add(_win, 'unload', _doNothing); // prevent browser from showing cached state via back button, because flash will be dead
+    if (_s.waitForWindowLoad && !_windowLoaded) {
+      _wDS('waitOnload');
+      _event.add(_win, 'load', _initUserOnload);
+      return false;
+    } else {
+      if (_s.waitForWindowLoad && _windowLoaded) {
+        _wDS('docLoaded');
+      }
+      _initUserOnload();
+    }
+    return true;
+  };
+
+  _showSupport = function() {
+
+    var item, tests = [];
+    if (_s.useHTML5Audio && _s.hasHTML5) {
+      for (item in _s.audioFormats) {
+        if (_s.audioFormats.hasOwnProperty(item)) {
+          tests.push(item + ': ' + _s.html5[item] + (!_s.html5[item] && _hasFlash && _s.flash[item] ? ' (using flash)' : (_s.preferFlash && _s.flash[item] && _hasFlash ? ' (preferring flash)': (!_s.html5[item] ? ' (' + (_s.audioFormats[item].required ? 'required, ':'') + 'and no flash support)' : ''))));
+        }
+      }
+      _s._wD('-- SoundManager 2: HTML5 support tests ('+_s.html5Test+'): '+tests.join(', ')+' --',1);
+    }
+
+  };
+
+  _init = function() {
+
+    _wDS('init');
+
+    // called after onload()
+    if (_didInit) {
+      _wDS('didInit');
+      return false;
+    }
+
+    function _cleanup() {
+      _event.remove(_win, 'load', _s.beginDelayedInit);
+    }
+
+    if (_s.html5Only) {
+      if (!_didInit) {
+        // we don't need no steenking flash!
+        _cleanup();
+        _s.enabled = true;
+        _initComplete();
+      }
+      return true;
+    }
+
+    // flash path
+    _initMovie();
+
+    try {
+      _wDS('flashJS');
+      _s.o._externalInterfaceTest(false); // attempt to talk to Flash
+      if (!_s.allowPolling) {
+        _wDS('noPolling', 1);
+      } else {
+        _setPolling(true, (_s.flashPollingInterval || (_s.useFastPolling ? 10 : 50)));
+      }
+      if (!_s.debugMode) {
+        _s.o._disableDebug();
+      }
+      _s.enabled = true;
+      _debugTS('jstoflash', true);
+    } catch(e) {
+      _s._wD('js/flash exception: ' + e.toString());
+      _debugTS('jstoflash', false);
+      _catchError({type:'JS_TO_FLASH_EXCEPTION', fatal:true});
+      _failSafely(true); // don't disable, for reboot()
+      _initComplete();
+      return false;
+    }
+
+    _initComplete();
+    // event cleanup
+    _cleanup();
+    return true;
+
+  };
+
+  _dcLoaded = function() {
+    if (_didDCLoaded) {
+      return false;
+    }
+    _didDCLoaded = true;
+    _initDebug();
+
+    /*
+     * Temporary feature: allow force of HTML5 via URL params: sm2-usehtml5audio=0 or 1
+     * Ditto for sm2-preferFlash, too.
+    */
+    // <d>
+    (function(){
+      var a = 'sm2-usehtml5audio=', l = _wl.toLowerCase(), b = null,
+      a2 = 'sm2-preferflash=', b2 = null, hasCon = (typeof console !== 'undefined' && typeof console.log !== 'undefined');
+      if (l.indexOf(a) !== -1) {
+        b = (l.charAt(l.indexOf(a)+a.length) === '1');
+        if (hasCon) {
+          console.log((b?'Enabling ':'Disabling ')+'useHTML5Audio via URL parameter');
+        }
+        _s.useHTML5Audio = b;
+      }
+      if (l.indexOf(a2) !== -1) {
+        b2 = (l.charAt(l.indexOf(a2)+a2.length) === '1');
+        if (hasCon) {
+          console.log((b2?'Enabling ':'Disabling ')+'preferFlash via URL parameter');
+        }
+        _s.preferFlash = b2;
+      }
+    }());
+    // </d>
+
+    if (!_hasFlash && _s.hasHTML5) {
+      _s._wD('SoundManager: No Flash detected'+(!_s.useHTML5Audio?', enabling HTML5.':'. Trying HTML5-only mode.'));
+      _s.useHTML5Audio = true;
+      // make sure we aren't preferring flash, either
+      // TODO: preferFlash should not matter if flash is not installed. Currently, stuff breaks without the below tweak.
+      _s.preferFlash = false;
+    }
+
+    _testHTML5();
+    _s.html5.usingFlash = _featureCheck();
+    _needsFlash = _s.html5.usingFlash;
+
+    _showSupport();
+
+    if (!_hasFlash && _needsFlash) {
+      _s._wD('SoundManager: Fatal error: Flash is needed to play some required formats, but is not available.');
+      // TODO: Fatal here vs. timeout approach, etc.
+      _s.flashLoadTimeout = 1; // hack: fail sooner.
+    }
+
+    if (_doc.removeEventListener) {
+      _doc.removeEventListener('DOMContentLoaded', _dcLoaded, false);
+    }
+    _initMovie();
+    return true;
+  };
+
+  _dcIE = function() {
+    if (_doc.readyState === 'complete') {
+      _dcLoaded();
+      _doc.detachEvent('onreadystatechange', _dcIE);
+    }
+    return true;
+  };
+
+  // sniff up-front
+  _detectFlash();
+
+  // focus and window load, init (primarily flash-driven)
+  _event.add(_win, 'focus', _handleFocus);
+  _event.add(_win, 'load', _handleFocus);
+  _event.add(_win, 'load', _delayWaitForEI);
+  if (_isSafari && _tryInitOnFocus) {
+    _event.add(_win, 'mousemove', _handleFocus); // massive Safari 3.1 focus hack
+  }
+
+  if (_doc.addEventListener) {
+    _doc.addEventListener('DOMContentLoaded', _dcLoaded, false);
+  } else if (_doc.attachEvent) {
+    _doc.attachEvent('onreadystatechange', _dcIE);
+  } else {
+    // no add/attachevent support - safe to assume no JS -> Flash either
+    _debugTS('onload', false);
+    _catchError({type:'NO_DOM2_EVENTS', fatal:true});
+  }
+
+  if (_doc.readyState === 'complete') {
+    setTimeout(_dcLoaded,100);
+  }
+
+} // SoundManager()
+
+// SM2_DEFER details: http://www.schillmania.com/projects/soundmanager2/doc/getstarted/#lazy-loading
+if (typeof SM2_DEFER === 'undefined' || !SM2_DEFER) {
+  soundManager = new SoundManager();
+}
+
+// public interfaces
+window.SoundManager = SoundManager; // constructor
+window.soundManager = soundManager; // public API, flash callbacks etc
+
+}(window));
