Index: /main/trunk/model-sites-dev/multimodal-mdl/collect/js-dsp-my-ipod/REBUILD.sh
===================================================================
--- /main/trunk/model-sites-dev/multimodal-mdl/collect/js-dsp-my-ipod/REBUILD.sh	(revision 28433)
+++ /main/trunk/model-sites-dev/multimodal-mdl/collect/js-dsp-my-ipod/REBUILD.sh	(revision 28433)
@@ -0,0 +1,1 @@
+full-rebuild.pl  -site localsite -removeold -import:OIDtype incremental my-ipod
Index: /main/trunk/model-sites-dev/multimodal-mdl/collect/js-dsp-my-ipod/etc/collectionConfig.xml
===================================================================
--- /main/trunk/model-sites-dev/multimodal-mdl/collect/js-dsp-my-ipod/etc/collectionConfig.xml	(revision 28433)
+++ /main/trunk/model-sites-dev/multimodal-mdl/collect/js-dsp-my-ipod/etc/collectionConfig.xml	(revision 28433)
@@ -0,0 +1,747 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<CollectionConfig xmlns:gsf="http://www.greenstone.org/greenstone3/schema/ConfigFormat" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+  <metadataList>
+    <metadata name="creator"></metadata>
+    <metadata name="maintainer"></metadata>
+    <metadata name="public">true</metadata>
+  </metadataList>
+  <displayItemList>
+    <displayItem assigned="true" lang="en" name="name">Redefining Boundaries</displayItem>
+    <displayItem assigned="true" lang="en" name="description"></displayItem>
+  </displayItemList>
+  <!-- Global format statement -->
+  <format>
+    <gsf:template name="choose-title">
+      
+      <gsf:choose-metadata>
+	<gsf:metadata name="dc.Title"/>
+	<gsf:metadata name="exp.Title"/>
+	<gsf:metadata name="ex.dc.Title"/>
+	<gsf:metadata name="ex.Title"/>
+	<gsf:metadata name="Title"/>
+	<gsf:default>Untitled</gsf:default>
+      </gsf:choose-metadata>
+      
+      <gsf:switch>
+	<gsf:metadata name='dc.Creator'/>
+	<gsf:when test='exists'>
+	  
+	  <gsf:switch>
+	    <gsf:metadata name="dc.Creator"/>
+	    <gsf:when test="notEquals" test-value="Unknown">
+	      
+	      by <i><gsf:metadata name='dc.Creator'/></i>
+	    </gsf:when>
+	  </gsf:switch>
+	  
+	</gsf:when>
+      </gsf:switch>			
+    </gsf:template>    
+  </format>
+
+  <search type="mgpp">
+    <level name="document">
+      <displayItem lang="en" name="name">document</displayItem>
+    </level>
+    <level name="section">
+      <displayItem lang="en" name="name">section</displayItem>
+    </level>
+    <defaultLevel name="document"/>
+    <index name="text">
+      <displayItem lang="en" name="name">text</displayItem>
+    </index>
+    <index name="dc.Title,ex.dc.Title,Title">
+			<displayItem lang="en" name="name">titles</displayItem>
+    </index>
+    <index name="Source">
+      <displayItem lang="en" name="name">filenames</displayItem>
+    </index>
+    <defaultIndex name="text"/>
+    <searchType name="plain"/>
+    <searchType name="simpleform"/>
+    <searchType name="advancedform"/>
+
+    
+    <!-- Search Format Statement -->
+    <format>
+      <gsf:template match="documentNode">
+
+	<gsf:variable name="cgiargFrameLength">
+	  <xsl:value-of select="/page/pageRequest/paramList/param[@name='p.frameLength']/@value"/>
+	</gsf:variable>
+
+	<xsl:variable name="cgiargYScaleSimImg"><xsl:choose>
+	  <xsl:when test="/page/pageRequest/paramList/param[@name='p.yScaleSimImg']/@value != ''"><xsl:value-of select="/page/pageRequest/paramList/param[@name='p.yScaleSimImg']/@value"/></xsl:when>
+	  <xsl:otherwise>0.5</xsl:otherwise>
+	</xsl:choose>
+	</xsl:variable>
+
+	<td valign="top">
+	  <gsf:icon type="document"/>
+	</td>
+	<td>
+	  <xsl:choose>
+	    <xsl:when test="@rank != 'NaN'">
+  	      (<script>
+	        var rank=<xsl:value-of select="@rank"/>;
+	        var perc=(rank-0.9)*100*10;
+	        document.write(perc.toFixed(1));
+	       </script>%) 
+	    </xsl:when>
+	  </xsl:choose>
+	  
+	  <xsl:choose>
+	    <xsl:when test="/page/pageResponse/service[@name='AudioQuery']">
+  	      <a>
+	        <xsl:attribute name="href"><xsl:value-of select="$library_name"/>/collection/<xsl:value-of select="/page/pageResponse/collection/@name"/>/document/<xsl:value-of select="@nodeID"/>?p.frameOffset=<xsl:value-of select="@frameOffset"/>&amp;p.frameLength=<xsl:value-of select="/page/pageRequest/paramList/param[@name='s1.length']/@value"/>&amp;p.a=q&amp;p.s=<xsl:value-of select="/page/pageResponse/service/@name"/>&amp;p.yScaleSimImg=<xsl:value-of select="$cgiargYScaleSimImg"/>
+
+	        </xsl:attribute>
+		
+                <xsl:call-template name="choose-title"/>
+	      </a>
+	    </xsl:when>
+	    <xsl:otherwise>
+	      <gsf:link>
+                <xsl:call-template name="choose-title"/>
+	      </gsf:link>
+	    </xsl:otherwise>
+	  </xsl:choose>
+	  
+	  <gsf:switch>
+	    <gsf:metadata name="artist"/>
+	    <gsf:when test="exists">
+	      by <gsf:metadata name="artist"/>
+	    </gsf:when>
+	  </gsf:switch>
+
+	  <gsf:switch>
+	    <gsf:metadata name="js.LabelledStructure"/>
+	    <gsf:when test="exists">
+	      <br/><i style="font-size: 80%">(Labelled structure: <gsf:metadata name="js.LabelledStructure"/>)</i>
+	    </gsf:when>
+	  </gsf:switch>
+	  
+	</td>
+      </gsf:template>
+    </format>
+
+  </search>
+
+  <search type="audioDB" orthogonal="true" />
+  
+  <infodb type="jdbm"/>
+
+  <import>
+    <pluginList>
+      <plugin name="ZIPPlugin"/>
+      <plugin name="GreenstoneXMLPlugin"/>
+      <plugin name="EmbeddedMetadataPlugin"/>
+      
+      <plugin name="AudioDBPlugin">
+	<option name="-compute_fft_features" value="true"/>
+	<option name="-enable_streaming" value="mp3"/>
+	<option name="-compute_mir_features" value="true"/>
+	<option name="-retrieve_mir_metadata" value="true"/>
+	<option name="-enable_cache"/>
+      </plugin>
+      
+      <plugin name="TextPlugin"/>
+      <plugin name="HTMLPlugin"/>
+      <plugin name="EmailPlugin"/>
+      <plugin name="PDFPlugin"/>
+      <plugin name="RTFPlugin"/>
+      <plugin name="WordPlugin"/>
+      <plugin name="PostScriptPlugin"/>
+      <plugin name="PowerPointPlugin"/>
+      <plugin name="ExcelPlugin"/>
+      <plugin name="ImagePlugin"/>
+      <plugin name="ISISPlugin"/>
+      <plugin name="NulPlugin"/>
+      <plugin name="OAIPlugin"/>
+      <plugin name="MetadataXMLPlugin"/>
+      <plugin name="ArchivesInfPlugin"/>
+      <plugin name="DirectoryPlugin"/>
+    </pluginList>
+  </import>
+
+  <browse>
+    <classifier name="AZCompactList">
+      <option name="-metadata" value="dc.Title;ex.dc.Title;Title"/>
+      <option name="-mingroup" value="2"/>
+      <option name="-removeprefix" value="(?i)Le|La|Les|The|A\\s+"/>
+    </classifier>
+
+    <classifier name="AZCompactList">
+      <option name="-metadata" value="dc.Creator"/>
+      <option name="-buttonname" value="Artists"/>
+      <option name="-mingroup" value="1"/>
+      <option name="-minnesting" value="40"/>
+    </classifier>
+
+    <classifier name="AZCompactList">
+      <option name="-metadata" value="dc.Title.albumtitle"/>
+      <option name="-buttonname" value="Albums"/>
+      <option name="-mingroup" value="1"/>
+      <option name="-minnesting" value="40"/>
+    </classifier>
+
+
+    <!--
+
+    <classifier name="List">
+      <option name="-metadata" value="dc.Title;Title"/>
+      <option name="-partition_type_within_level" value="approximate_size"/>
+    </classifier>
+    <classifier name="List">
+      <option name="-metadata" value="dc.Creator"/>
+      <option name="-button_name" value="Artists"/>
+      <option name="-partition_type_within_level" value="approximate_size"/>
+    </classifier>
+		
+    -->
+
+    <format>
+      <gsf:template match="documentNode">
+	<td valign="top">
+	  <gsf:link type="document">
+	    <gsf:icon type="document"/>
+	  </gsf:link>
+	</td>
+	<td valign="top">
+	  <gsf:link type="source">
+	    <gsf:choose-metadata>
+	      <gsf:metadata name="thumbicon"/>
+	      <gsf:metadata name="srcicon"/>
+	    </gsf:choose-metadata>
+	  </gsf:link>
+	</td>
+	<td valign="top">
+	  <gsf:link type="document">
+	    <!-- Defined in the global format statement -->
+	    <xsl:call-template name="choose-title"/>
+	    
+	    <gsf:switch>
+	      <gsf:metadata name="dc.Title" />
+	      <gsf:when test="equals" test-value="Unknown">
+		<br/><i>(<gsf:metadata name="Source"/>)</i>
+	      </gsf:when>
+	    </gsf:switch>
+	    
+	  </gsf:link>
+	</td>
+      </gsf:template>
+      
+      <gsf:template match="classifierNode[@classifierStyle = 'VList']">
+	<td valign="top">
+	  <gsf:link type="classifier">
+	    <gsf:icon type="classifier"/>
+	  </gsf:link>
+	</td>
+	<td valign="top">
+	  <gsf:link type="source">
+	    <gsf:choose-metadata>
+	      <gsf:metadata name="thumbicon"/>
+	      <gsf:metadata name="srcicon"/>
+	    </gsf:choose-metadata>
+	  </gsf:link>
+	</td>
+	<td valign="top">
+	  <!-- Defined in the global format statement -->
+	  <xsl:call-template name="choose-title"/>
+	  <gsf:switch>
+	    <gsf:metadata name="Source"/>
+	    <gsf:when test="exists"><br/><i>(<gsf:metadata name="Source"/>)</i></gsf:when>
+	  </gsf:switch>
+	</td>
+      </gsf:template>
+      <gsf:template match="classifierNode[@classifierStyle = 'HList']">
+	<gsf:link type="classifier">
+	  <gsf:metadata name="Title"/>
+	</gsf:link>
+      </gsf:template>
+    </format>
+  </browse>
+
+  <display>
+    <format>
+      <gsf:option name="TOC" value="false"/>
+
+      <!-- 
+	   Overwriting this template allows you to change the heading of the document.
+      -->
+      <gsf:template name="documentHeading">
+	
+	<xsl:variable name="httpCollection">
+	  <xsl:value-of select="/page/pageResponse/collection/metadataList/metadata[@name='httpPath']"/>
+	</xsl:variable>
+
+	<!-- Metadata derived from finger-printing --> 
+	
+	<xsl:call-template name="discovery-block">
+	  <xsl:with-param name="httpCollection" select="$httpCollection"/>
+	</xsl:call-template>
+
+      </gsf:template>
+
+      
+      <!-- 
+	   Overwriting this template can be used to redefine the content of the whole document. 
+	   This is useful for simple documents, but not recommended for more complex documents
+	   (e.g. hierachical and paged documents) as it can prevent any sub-sections from showing.
+      -->
+      <!-- 
+	   <gsf:template name="documentContent">
+	   <xsl:call-template name="wrappedSectionImage"/>
+	   <xsl:call-template name="wrappedSectionText"/>
+	   </gsf:template>
+      -->
+
+      <!--
+	  Overwriting this template can be used to change the content of section headings.
+      -->
+      <!--
+	  <gsf:template name="sectionHeading">
+	  <xsl:call-template name="choose-title"/>
+	  </gsf:template>
+      -->
+      
+      <!--
+	  Overwriting this template can be used to change the content of the top-level section.
+      -->
+      <!--
+	  <gsf:template name="topLevelSectionContent">
+	  <xsl:call-template name="wrappedSectionImage"/>
+	  <xsl:call-template name="wrappedSectionText"/>
+	  </gsf:template>
+      -->
+      
+      <!--
+	  Overwriting this template can be used to change the content of sections.
+      -->
+
+      <!--
+	  <gsf:template name="sectionContent">
+	  <xsl:call-template name="wrappedSectionImage"/>
+	  <xsl:call-template name="wrappedSectionText"/>
+	  </gsf:template>
+      -->
+      	
+      <xsl:template name="additionalHeaderContent">
+	
+
+	<xsl:call-template name="soundmanager2-header"/>
+	<xsl:call-template name="js-mad-header"/>
+	
+	<!-- Bespoke jquery-ui extension for turnstyle open/close blocks -->
+	<gsf:style  src="ext/jquery-ui-extra/turnstyle-block.css"/>
+	<gsf:script src="ext/jquery-ui-extra/turnstyle-block.js"/>
+	
+	<!-- The Javascript DSP files for computing chroma features in the browser -->
+	<xsl:call-template name="javascript-dsp-header"/>
+	
+
+	<!-- Javascript support for running, sending input into, monitoring, and stopping Meandre flows -->
+	<gsf:script src="ext/meandre/meandre-controller.js"/>
+
+	<gsf:style>
+	  .metadata-stripes td { padding: 4px; }
+	  .metadata-stripes tr:nth-child(odd)  {background: #CCC}
+	  .metadata-stripes tr:nth-child(even) {background: #FFF}      
+	  
+	  .vis-heading  { font-style:italic; }
+
+	  #rightSidebar { display: none; }
+	</gsf:style>
+	
+      </xsl:template>
+
+
+      <xsl:template name="documentContent">
+	
+<!--
+	<xsl:call-template name="init-document-xsl-vars"/>
+-->	
+
+	<!-- declare $httpCollection = $httpPath (for better consistency with other places in Greenstone XSL files) -->
+	<xsl:variable name="httpCollection">
+	  <xsl:value-of select="/page/pageResponse/collection/metadataList/metadata[@name='httpPath']"/>
+	</xsl:variable>
+
+	<xsl:variable name="assocFilePath"><gsf:metadata name="assocfilepath" select="root"/></xsl:variable>
+	<xsl:variable name="Source"><gsf:metadata name="Source" select="root"/></xsl:variable>
+
+	<gsf:variable name="cgiargFrameOffset">
+	  <xsl:value-of select="/page/pageRequest/paramList/param[@name='p.frameOffset']/@value"/>
+	</gsf:variable>
+
+	<gsf:variable name="cgiargFrameLength">
+	  <xsl:value-of select="/page/pageRequest/paramList/param[@name='p.frameLength']/@value"/>
+	</gsf:variable>
+
+	<xsl:variable name="cgiargYScaleSimImg"><xsl:choose>
+	  <xsl:when test="/page/pageRequest/paramList/param[@name='p.yScaleSimImg']/@value != ''"><xsl:value-of select="/page/pageRequest/paramList/param[@name='p.yScaleSimImg']/@value"/></xsl:when>
+	  <xsl:otherwise>0.5</xsl:otherwise>
+	</xsl:choose>
+	</xsl:variable>
+	
+	<!-- CAA = Content Analysis Algorithm -->
+	<xsl:variable name="cgiargCAAlgorithm">
+	  <xsl:choose>
+	    <xsl:when test="/page/pageRequest/paramList/param[@name='p.caAlgorithm']/@value != ''"><xsl:value-of select="/page/pageRequest/paramList/param[@name='p.caAlgorithm']/@value"/></xsl:when>
+	    <xsl:otherwise>1</xsl:otherwise>
+	  </xsl:choose>
+	</xsl:variable>
+
+	<!-- *** -->
+	<!-- Main Audio Player -->
+	<!-- *** -->
+
+	<div class="documenttext"> 
+	  
+	  <xsl:call-template name="audio-icon-cache"/>
+
+	  <ul class="playlist">
+	    <li class="rounded" >
+	      
+	      <gsf:script src="{$httpCollection}/script2/hybrid-audio-player.js"/>
+
+
+	      <a id="mysong" style="padding-bottom: 2px;"
+		 onclick="togglePlayVisual(document.getElementById('mainPlayButton'))"
+		 href="{$httpCollection}/index/assoc/{$assocFilePath}/doc.mp3">
+		<span>
+		  <img id="mainPlayButton" src="ext/diy-audio-player/images/play32.png" 
+		       width="32"
+		       height="32"  
+		       onmouseover="playHighlightOn(this)"
+		       onmouseout="playHighlightOff(this)"
+		       onclick="var event = arguments[0] || window.event; togglePlay(event,this)"
+		       style="vertical-align: middle;"/>
+		  Play/Pause
+		  <span id="extraPlayText"></span>
+		</span>    
+	      </a>
+	      
+	      <gsf:script src="ext/diy-audio-player/script/audioDB-play.js"/>
+
+	      <xsl:choose>
+		<xsl:when test="($cgiargFrameOffset != '-1') and ($cgiargFrameOffset != '')">
+		  
+		  <div style="background-color: rgb(40%,40%,20%)">
+		    <script type="text/javascript">
+		      <xsl:text disable-output-escaping="yes">
+
+			var frameOffsetStr=gs.variables.cgiargFrameOffset;
+			var frameLength=gs.variables.cgiargFrameLength;
+
+		      </xsl:text>
+		    </script>
+
+
+		    <svg xmlns="http://www.w3.org/2000/svg" 
+			 version="1.1"
+			 id="svgAudioDBSegments" 
+			 width="100%" height="24"
+			 onLoadXX="svgAudioDBInit()">
+		    </svg>
+		  </div>
+		</xsl:when>
+	      </xsl:choose>
+	      
+	      <xsl:call-template name="structuredAudioPlayerBlock"/>
+	      
+	      <xsl:call-template name="processingPopup"/>
+	      
+	      
+	      <div style="width: 100%; display: none;" id="doublePlay">
+		
+		<script type="text/javascript">
+		  <xsl:text disable-output-escaping="yes">
+		    
+		    // At time of writing this code, this needs to be an OGG file to work in Firefox
+		    var source = "</xsl:text><gsf:metadata name="Source" select="root"/><xsl:text disable-output-escaping="yes">";
+		    
+		    var self_sim_png = source.replace(/\.(ogg|mp3|wav)$/,".png");
+		    var collect = "</xsl:text><xsl:value-of select="/page/pageResponse/collection/@name"/><xsl:text disable-output-escaping="yes">";
+
+		  </xsl:text>
+		</script>
+
+		<gsf:script src="ext/diy-audio-player/script/similarity-matrix-play.js"/>
+
+		<audio style="width: 49%;" id="leftsong" controls="controls" >
+		  <source src="{$httpCollection}/index/assoc/{$assocFilePath}/doc.ogg" />
+		  <source src="{$httpCollection}/index/assoc/{$assocFilePath}/doc.mp3" />
+		  <source src="{$httpCollection}/index/assoc/{$assocFilePath}/doc.wav" />
+		</audio>
+		<audio style="width: 49%;" id="rightsong" controls="controls" >
+		  <source src="{$httpCollection}/index/assoc/{$assocFilePath}/doc.ogg" />
+		  <source src="{$httpCollection}/index/assoc/{$assocFilePath}/doc.mp3" />
+		  <source src="{$httpCollection}/index/assoc/{$assocFilePath}/doc.wav" />
+		</audio>
+	      </div>
+
+
+	      <!-- Real Time Analysis (RTA) audio -->
+	      <div style="width: 100%;">		
+		<audio id="rta-audio-element" style="width: 100%;">
+		  <source src="{$httpCollection}/index/assoc/{$assocFilePath}/doc.ogg"/>
+		  <source src="{$httpCollection}/index/assoc/{$assocFilePath}/doc.mp3"/>
+		  <source src="{$httpCollection}/index/assoc/{$assocFilePath}/doc.wav"/>
+		</audio>
+	      </div>
+	      
+	      <xsl:call-template name="workflow-block"/>
+
+	      <div id="controlMarker"/>
+
+	      <div id="svg-canvas-overlay" style="position: relative">
+      
+		<!-- drawing canvas -->
+		<div style="width: 100%; position: absolute; left: 0px; top: 0px;">
+		  <div style="position: relative">
+		    <div>
+		      <!-- **** better if 100% width, but issue with JS reading these values ??? -->
+		      <canvas id="freq-plot" 
+			      width="941" height="494" style="background-color: #cccccc;"></canvas>
+		    </div>
+		  </div>
+		</div>
+
+		<div style="width: 100%; position: absolute; left: 0px; top: 0px;">
+		  <div style="position: relative">
+		    <div>
+		      <!-- **** better if 100% width, but issue with JS reading these values ??? -->
+		      <canvas id="freq-plot-labels" 
+			      width="941" height="494" style="background-color: transparent"></canvas>
+		    </div>
+		  </div>
+		</div>
+
+		<!-- left/right-mix circle cursor -->
+		<div style="background-color: transparent; position: relative; left: 0px; top: 0px;">
+		  <svg xmlns="http://www.w3.org/2000/svg" 
+		       xmlns:xlink="http://www.w3.org/1999/xlink" 
+		       version="1.1"
+		       id="svgSimilarityPlay" 
+		       width="100%"
+		       onLoad="svgInitSimilarityPlay()">
+		    <g id="simPlayLineGroup" transform="scale(1.0,{$cgiargYScaleSimImg})">
+		      <!-- image loaded here, with yScaleSimImg applied to group -->
+		    </g>
+		    <g id="playtracker" transform="translate(0,0)" 
+		       onclick="dualPlay(evt)"
+		       onmousemove="playTrackerMove(evt)"
+		       onmouseout="playTrackerOff(evt)"
+		       style="visibility: hidden">
+		      <circle cx="0" cy="0" r="20"
+			      stroke="black" stroke-width="1" fill="rgba(100%,100%,50%,0.7)" />
+		      <circle cx="0" cy="0" r="1"
+			      stroke="black" stroke-width="1" fill="black" />
+		      <g transform="translate(-15,-15)" style="visibility: hidden;">
+			<image id="playtrackerBusy" 
+			       width="30" height="30"
+			       xlink:href="ext/diy-audio-player/images/wait30trans.gif" />
+		      </g>
+		      
+		      <g>
+			<g transform="rotate(-90)">
+			  <g transform="translate(-20,-25)">
+			    <text id="rightTime" style="font-size: 80%;">L: secs</text>
+			  </g>
+			</g>
+			<g transform="translate(-20,30)">
+			  <text id="leftTime" style="font-size: 80%;">R: secs</text>
+			</g>
+		      </g>
+		      
+		    </g>
+		  </svg>
+		</div>
+		
+
+	      </div><!-- end of svg-canvas-overly-->
+
+	      <xsl:call-template name="visualization-mode-block"/>
+
+	    </li>
+	  </ul>
+	  
+	  <hr/>
+
+	  <xsl:call-template name="settings-form">
+	    <xsl:with-param name="cgiargYScaleSimImg" select="$cgiargYScaleSimImg"/>
+	  </xsl:call-template>
+	  
+	  <xsl:call-template name="computed-data">
+	    <xsl:with-param name="httpCollection" select="$httpCollection"/>
+	    <xsl:with-param name="assocFilePath" select="$assocFilePath"/>
+	  </xsl:call-template>
+
+
+	  <hr/>
+
+<script>
+  <xsl:text disable-output-escaping="yes">
+    useFancyPlayer = 1;
+
+    /* if (window.location.toString().match(/fancyplayer/i)) { */
+    if (useFancyPlayer) { 
+      PP_CONFIG.usePeakData = true;
+      PP_CONFIG.useEQData = true;
+      // PP_CONFIG.useFavIcon = true;
+    }
+
+    function onFinishSP()
+    {   
+      soundManager._onfinish(); 
+      togglePlayVisual(mainPlayButton); 
+    }
+
+      var mySoundObj;
+
+    function playFromOffset(id,frameOffset) 
+    {
+      var msecOffset = 250 * frameOffset; 
+      idElem = document.getElementById(id);
+      pagePlayer.handleClick({target:idElem}); /* fake a click */
+      soundManager.stopAll();
+
+      var options = {};
+      options.position = msecOffset;
+
+      soundManager.play(id,options);
+
+      togglePlayMode = "pause";
+      playHighlightOff(document.getElementById("mainPlayButton"),32);
+    }
+
+    function preSubmit(form) 
+    {
+      var currentPosElem = document.getElementById("mysongCurrentPos");
+      var offsetInMSecs = currentPosElem.getAttribute("offsetInMSecs");
+      var frameOffset = Math.round(offsetInMSecs/250.0);
+      form.elements["s1.offset"].value = frameOffset;
+
+      //var lengthInSecs = document.getElementById("mysongWindowDuration").innerHTML;
+      var lengthInSecs = form.elements["mysongWindowDuration"].value;
+
+      var frameLength = Math.round(lengthInSecs*1000/250.0);
+      form.elements["s1.length"].value = frameLength;
+
+      return true;
+    }
+
+    function searchSubmit(frameOffset) 
+    {
+      var form = document.getElementById("QueryForm");
+
+      form.elements["s1.offset"].value = frameOffset;
+
+      //var lengthInSecs = document.getElementById("mysongWindowDuration").innerHTML;
+      var lengthInSecs = form.elements["mysongWindowDuration"].value;
+
+      var frameLength = Math.round(lengthInSecs*1000/250.0);
+      form.elements["s1.length"].value = frameLength;
+
+      form.submit();
+    }
+
+
+
+    function rescaleImage() 
+    {
+      var form = document.getElementById("RescaleForm");
+
+      var rescaleSize = form.elements["ResizeScale"].value;
+
+      var currentURL = document.location.toString();
+      var newURL;
+      if (currentURL.match(/p.yScaleSimImg=(\d+(?:\.\d+))/)) {
+        newURL = currentURL.replace(/p.yScaleSimImg=(\d+(?:\.\d+))/,"p.yScaleSimImg="+rescaleSize);
+      }
+      else {
+        var urlParts = currentURL.split("#");
+	newURL = urlParts.shift();
+        newURL += "&amp;p.yScaleSimImg="+rescaleSize;
+	newURL += "#" + urlParts.join("#");
+      }
+
+      document.location = newURL;
+    }
+
+    function updateCAAlgorithm()
+    {
+
+      var form = document.getElementById("UpdateCAForm");
+
+      var caaMenu = form.elements["caAlgorithm"];
+
+      var caIndexPos = caaMenu.options[caaMenu.selectedIndex].value
+
+      var currentURL = document.location.toString();
+      var newURL;
+      if (currentURL.match(/p.caAlgorithm=(\d+)/)) {
+        newURL = currentURL.replace(/p.caAlgorithm=(\d+)/,"p.caAlgorithm="+caIndexPos);
+      }
+      else {
+        var urlParts = currentURL.split("#");
+	newURL = urlParts.shift();
+        newURL += "&amp;p.caAlgorithm="+caIndexPos;
+	newURL += "#" + urlParts.join("#");
+      }
+
+      document.location = newURL;
+
+    }
+
+
+
+  </xsl:text>
+
+</script>
+
+
+    </div>
+  </xsl:template>
+
+
+
+
+    </format>
+  </display>
+
+  <replaceListRef id="gs2-standard"/>
+  <replaceListRef id="gs2-image" />
+  <serviceRackList>
+    <!-- comment out the following serviceRack if you want to disable OAI for this collection -->
+    <serviceRack name="OAIPMH">
+      <ListMetadataFormats>
+	<!--What metadata sets to support is collection specific. To support other metadata schema, simply add a metadataFormat element here.
+	    The support of unqualified Dublin Core metadata set is mandatory in the oai specification.
+	-->
+	<metadataFormat metadataPrefix="oai_dc">
+	  <metadataPrefix>oai_dc</metadataPrefix>
+	  <schema>http://www.openarchives.org/OAI/2.0/oai_dc.xsd</schema>
+	  <metadataNamespace>http://www.openarchives.org/OAI/2.0/oai_dc/</metadataNamespace>
+	  <!--<metadataElements>dc.Title,dc.Creator,dc.Subject,dc.Description,dc.Publisher,dc.Contributor,dc.Date,dc.Type,dc.Format,dc.Identifier,dc.Source,dc.Language,dc.Relation,dc.Coverage,dc.Rights</metadataElements>-->
+	  <mappingList>
+	    <!-- 
+		 The mapping is in the form: <publicly supported metadata name>,<mapped metadata name>, short as <A>,<B> 
+		 The first metadata name is medatory; if there is no mapped name followed, then the first name must be used by the records and
+		 searchable in the database, otherwise it is the mapped name stored in the database. The number of mapping elements matches the
+		 number of external metadata of the records. If only one name is present, the returned metadata will use this name plus the retrieved value;
+		 if both <A>,<B> are present, the returned metadata will use <A>'s name plus <B>'s value retrieved from database.
+		 
+		 **Bear in mind: if this mapping list is not present, the standard dc. metadata names (15 in total) will be used to retrieve metadata in the database.
+		 
+		 **The only case when this mapping is not present is that: 1. this metadata format is oai_dc; 2. the metadata is also stored in the database by Dublin Core's names.
+	    -->
+	    <mapping>dc:title,Title</mapping>
+	    <!-- This mapping example means that the dc.Title is requested and the value of the metadata Title, which is used in this repository, is returned as response. -->
+	  </mappingList>
+	</metadataFormat>
+      </ListMetadataFormats>
+    </serviceRack> 
+  </serviceRackList>
+</CollectionConfig>
Index: /main/trunk/model-sites-dev/multimodal-mdl/collect/js-dsp-my-ipod/script/browser-detect.js
===================================================================
--- /main/trunk/model-sites-dev/multimodal-mdl/collect/js-dsp-my-ipod/script/browser-detect.js	(revision 28433)
+++ /main/trunk/model-sites-dev/multimodal-mdl/collect/js-dsp-my-ipod/script/browser-detect.js	(revision 28433)
@@ -0,0 +1,117 @@
+var BrowserDetect = {
+	init: function () {
+		this.browser = this.searchString(this.dataBrowser) || "An unknown browser";
+		this.version = this.searchVersion(navigator.userAgent)
+			|| this.searchVersion(navigator.appVersion)
+			|| "an unknown version";
+		this.OS = this.searchString(this.dataOS) || "an unknown OS";
+	},
+	searchString: function (data) {
+		for (var i=0;i<data.length;i++)	{
+			var dataString = data[i].string;
+			var dataProp = data[i].prop;
+			this.versionSearchString = data[i].versionSearch || data[i].identity;
+			if (dataString) {
+				if (dataString.indexOf(data[i].subString) != -1)
+					return data[i].identity;
+			}
+			else if (dataProp)
+				return data[i].identity;
+		}
+	},
+	searchVersion: function (dataString) {
+		var index = dataString.indexOf(this.versionSearchString);
+		if (index == -1) return;
+		return parseFloat(dataString.substring(index+this.versionSearchString.length+1));
+	},
+	dataBrowser: [
+		{
+			string: navigator.userAgent,
+			subString: "Chrome",
+			identity: "Chrome"
+		},
+		{ 	string: navigator.userAgent,
+			subString: "OmniWeb",
+			versionSearch: "OmniWeb/",
+			identity: "OmniWeb"
+		},
+		{
+			string: navigator.vendor,
+			subString: "Apple",
+			identity: "Safari",
+			versionSearch: "Version"
+		},
+		{
+			prop: window.opera,
+			identity: "Opera",
+			versionSearch: "Version"
+		},
+		{
+			string: navigator.vendor,
+			subString: "iCab",
+			identity: "iCab"
+		},
+		{
+			string: navigator.vendor,
+			subString: "KDE",
+			identity: "Konqueror"
+		},
+		{
+			string: navigator.userAgent,
+			subString: "Firefox",
+			identity: "Firefox"
+		},
+		{
+			string: navigator.vendor,
+			subString: "Camino",
+			identity: "Camino"
+		},
+		{		// for newer Netscapes (6+)
+			string: navigator.userAgent,
+			subString: "Netscape",
+			identity: "Netscape"
+		},
+		{
+			string: navigator.userAgent,
+			subString: "MSIE",
+			identity: "Explorer",
+			versionSearch: "MSIE"
+		},
+		{
+			string: navigator.userAgent,
+			subString: "Gecko",
+			identity: "Mozilla",
+			versionSearch: "rv"
+		},
+		{ 		// for older Netscapes (4-)
+			string: navigator.userAgent,
+			subString: "Mozilla",
+			identity: "Netscape",
+			versionSearch: "Mozilla"
+		}
+	],
+	dataOS : [
+		{
+			string: navigator.platform,
+			subString: "Win",
+			identity: "Windows"
+		},
+		{
+			string: navigator.platform,
+			subString: "Mac",
+			identity: "Mac"
+		},
+		{
+			   string: navigator.userAgent,
+			   subString: "iPhone",
+			   identity: "iPhone/iPod"
+	    },
+		{
+			string: navigator.platform,
+			subString: "Linux",
+			identity: "Linux"
+		}
+	]
+
+};
+BrowserDetect.init();
Index: /main/trunk/model-sites-dev/multimodal-mdl/collect/js-dsp-my-ipod/script/hybrid-audio-player.js
===================================================================
--- /main/trunk/model-sites-dev/multimodal-mdl/collect/js-dsp-my-ipod/script/hybrid-audio-player.js	(revision 28433)
+++ /main/trunk/model-sites-dev/multimodal-mdl/collect/js-dsp-my-ipod/script/hybrid-audio-player.js	(revision 28433)
@@ -0,0 +1,169 @@
+
+Element.prototype.getElementWidth = function() {
+    if (typeof this.clip !== "undefined") {
+	return this.clip.width;
+    } else {
+	if (this.style.pixelWidth) {
+	    return this.style.pixelWidth;
+	} else {
+	    return this.offsetWidth;
+	}
+    }
+};
+
+Element.prototype.getElementHeight = function() {
+    if (typeof this.clip !== "undefined") {
+	return this.clip.height;
+    } else {
+	if (this.style.pixelHeight) {
+	    return this.style.pixelHeight;
+	} else {
+	    return this.offsetHeight;
+	}
+    }
+};
+
+
+function isDefined(v) {
+    return typeof v !== "undefined";
+}
+
+/* // ***** */
+/* Move above in to more general header file */
+
+
+// Useful shorthands
+var SVG_NS ="http://www.w3.org/2000/svg";
+var XLINK_NS = "http://www.w3.org/1999/xlink";
+
+
+var hasStructuredAudio  = false;
+var hasChromaSelfSimMap = false;
+
+var allData      = null;
+var yScaleSimImg = null;
+var caAlgorithm  = null;
+var duration     = null;
+
+
+// ******
+// * Frequency Player/Plotter part of Hybrid Player
+// ******
+
+function freqPlayerAudioPlay(event)
+{
+    console.info("Audio play pressed");
+
+    if (audioMode == "stopped") {
+	// Nolonger used (Firefox fails to fire this event on a fresh 'play' once an existing play has finished)
+
+	// take a fresh snapshot of the transform mode selected in the web page
+
+	//var transformMode = $('input:radio[name=visualization]:checked').val();
+	//chromaTransform.setTransformMode(transformMode);
+
+    }
+    audioMode = "playing";
+}
+
+function freqPlayerAudioPause()
+{
+    console.info("Audio pause pressed");
+    audioMode = "paused";
+
+    // if stoping dualPlay
+    leftSong.pause();
+    rightSong.pause();
+    baseSong.volume = 1.0;
+
+}
+
+function freqPlayerAudioEnded()
+{
+    console.info("Audio play/playlist ended");
+    console.log("reset freq plot called");
+
+    audioMode = "stopped";
+    needsRefresh = true;
+
+    frequencyPlotter.reset();
+
+}
+
+// ******
+// * Meandre (server-side) workflow part of Hybrid Player
+// ******
+//
+// Started when 'play' is pressed
+
+// (workflows now in their own folder '$httpCollection/script/meandre-workflow/*.js)
+// the global variable 'meandreWorkflows' stores which flows are available
+
+
+
+
+
+// ******
+// * Structured Audio (CAA) part of Hybrid Player
+// ******
+
+function caaInit() 
+{
+    // duration information is now available
+    var audio = document.getElementById('rta-audio-element');
+    duration = audio.duration;
+    
+    if (!isDefined(allData)) {
+	// degenerate case
+	
+	var ground_truth = []; // empty ground truth
+	
+	var numSegs = 4;
+	var gap = duration/numSegs;
+	
+	var label = [ "a", "b" ];
+	var val   = [ 0, 1];
+	
+	var equal_spacing = [];
+	for (var i=0; i<numSegs; i++) {
+	    equal_spacing.push( {o: i*gap, f: i*gap+gap, l: label[i%2], a: val[i%2] } );
+	}
+
+	allData = [ ground_truth, equal_spacing ]; 
+
+	caAlgorithm = 1;
+	hasStructuredAudio = true;
+    }
+
+    svgGTStructuredInit();
+    svgCAStructuredInit(caAlgorithm);
+    svgAudioDBInit();
+}
+
+
+allData = gs.documentMetadata["json.data"];
+
+// ****
+
+// The following is actually the XSLT page param
+// 'p.yScaleSimImg;, which presumably automatically generates
+// gs.cgiParams.yScaleSimImg (if present).  Defaults to 0.5
+
+yScaleSimImg=gs.variables.cgiargYScaleSimImg || 0.5; 
+
+caAlgorithm=gs.variables.cgiargCAAlgorithm;
+
+$(function() {
+
+    var audio = document.getElementById('rta-audio-element');
+    audio.addEventListener('loadedmetadata', caaInit, false);
+
+    audio.addEventListener('MozAudioAvailable', freqPlayerAudioAvailable, false);
+    audio.addEventListener('loadedmetadata', freqPlayerLoadedAudioMetadata, false);
+
+    audio.addEventListener('play',  freqPlayerAudioPlay,  false);
+    audio.addEventListener('pause', freqPlayerAudioPause, false);
+    audio.addEventListener('ended', freqPlayerAudioEnded, false);
+      
+});
+
Index: /main/trunk/model-sites-dev/multimodal-mdl/collect/js-dsp-my-ipod/script/meandre-workflow/chromagram.js
===================================================================
--- /main/trunk/model-sites-dev/multimodal-mdl/collect/js-dsp-my-ipod/script/meandre-workflow/chromagram.js	(revision 28433)
+++ /main/trunk/model-sites-dev/multimodal-mdl/collect/js-dsp-my-ipod/script/meandre-workflow/chromagram.js	(revision 28433)
@@ -0,0 +1,198 @@
+
+
+var ChromagramMeandreWorkflow = function() {
+
+    var domain_prefix = window.location.protocol + "//" + window.location.hostname;
+
+    this.meandreController = new MeandreController(domain_prefix,"1714","1712");
+
+    this.baseURI     = "http://greenstone.org/meandre/flows/chromagram-v1/";
+    this.serviceHead = "http://greenstone.org/meandre/flows/chromagram-v1/instance/greenstone-audio-web-service-head/0";
+    this.serviceTail = "http://greenstone.org/meandre/flows/chromagram-v1/instance/float32-frame-web-service-buffer/5";
+
+    this.flowPort = null;
+
+    this.meandreFrameSize = null;
+    this.meandreDataOutput = new Array();
+
+    this.meandreCount = 0;
+}
+
+
+ChromagramMeandreWorkflow.prototype.thisMeandreFlowIsRunning = function() {
+    return this.flowPort != null;
+}
+
+ChromagramMeandreWorkflow.prototype.processThisMeandreFlowOutputDataCallback = function(oEvent,oReq) {
+
+
+    var arrayBuffer = oReq.response; // Note: not oReq.responseText
+
+    if (arrayBuffer.byteLength) {
+	console.log("*** get-data callback: Recieved binary data: raw byte array buffer len = " + arrayBuffer.byteLength);
+	
+	console.log("*** type of arrayBuffer: " + toType(arrayBuffer));
+
+	var float32Array = new Float32Array(arrayBuffer); 
+
+	console.info("*** get-data callback: number of frames received = " + float32Array.length/this.meandreFrameSize);
+
+
+	// Break it up into frames
+
+	//payload.data = float32Array;
+	this.meandreDataOutput.push(float32Array);
+    }
+}
+
+
+
+ChromagramMeandreWorkflow.prototype.processThisMeandreFlowOutputData = function(flowPort) {
+
+    // does flowPort need to be passed in as a parameter, now this is method not a function?
+
+    var getinfo_options = {cmd: "get-info" };
+
+    var info_props = this.meandreController.webComponentProperties(flowPort,this.serviceTail,getinfo_options)
+
+    // values stored in 'info_props' are strings => need to make sure we treat get numeric fields such
+    // as 'numFrames' as an integer
+
+    var numFramesAvailable = parseInt(info_props.numFrames);
+    if (isDefined(numFramesAvailable)) {
+	this.meandreFrameSize = parseInt(info_props.frameSize); 
+    }
+    else {
+	numFramesAvailable = 0;
+    }
+
+//    console.log("*** Meandre count = " + meandreCount);    
+
+    if (numFramesAvailable>0) {
+
+	var getNumFrames = Math.min(1000,numFramesAvailable);
+
+	console.info("get-data request: Number of frames available = " + numFramesAvailable, ", number of frames requested = " + getNumFrames);
+
+
+
+//	console.log("***** doing a get-data");
+	var getdata_options = {cmd: "get-data", numFrames: getNumFrames };
+	var payload = this.meandreController.binaryWebComponent(flowPort,this.serviceTail,getdata_options,
+								this.processThisMeandreFlowOutputDataCallback,this);
+
+	// delay the next call to 'get-info' to give the 'get-data' a chance to reach the server
+	var that = this;
+	setTimeout(function() {
+	    that.processThisMeandreFlowOutputData(flowPort);
+	}, 400);
+
+    }
+    else {
+	console.log("*** Sending 'done' command");
+	var done_options = {cmd: "done" };
+	this.meandreController.webComponent(flowPort,this.serviceHead,done_options);
+
+	// disable 'stop' and make 'run' active again
+	$('#meandre-stop-button').attr("disabled", "disabled");
+	$('#meandre-run-button').removeAttr("disabled");
+    }
+
+    this.meandreCount++;
+}
+
+
+ChromagramMeandreWorkflow.prototype.runThisMeandreFlow = function(elem,playCallback) {
+
+    if (this.thisMeandreFlowIsRunning()) {
+	console.error("runThisMeandreFlow(): The flow is already running on port " + this.flowPort);
+	return;
+    }
+
+    var $progressElem = $('#processing');
+    var $progressTitleElem = $('#processingTitle');
+    var $progressTextElem = $('#processingText');
+
+    var displayProgress = ($progressElem.length>0) ? true : false;
+    if (displayProgress) {
+	$progressTitleElem.html("Starting Meandre Workflow ...");
+	$progressTextElem.css('display','none');
+	$progressElem.css('display','block');
+    }
+
+
+    var flow_token = this.meandreController.runFlow(this.baseURI);
+    //console.log("**** got flow token : " + flow_token);	  
+    
+    // Give the flow time to start up ...
+    var that = this;
+
+    setTimeout(function() {
+	// Now find out which port it is running on ...
+ 	var flow_props = that.meandreController.runningFlowProperties(flow_token);
+	var flow_port =  flow_props.port;
+
+	var attempts = 0;
+	while ((flow_port==null) || (flow_port <= 0)) {
+	    console.info("port returned as " + flow_port + ", trying again");
+ 	    flow_props = that.meandreController.runningFlowProperties(flow_token);
+	    flow_port =  flow_props.port;	    
+	    attempts++;
+
+	    if (attempts==10) {
+		break;
+	    }
+	}
+	
+	console.info("Running Meandre flow on port : " + flow_port);
+	that.flowPort = flow_port;
+	
+	$('#meandre-run-button').attr("disabled", "disabled");
+	$('#meandre-stop-button').removeAttr("disabled");
+	
+	//$('#meandre-run-button').button({ disabled: true });
+	//$('#meandre-stop-button').button({disabled: false});
+	
+	var start_options = { 
+	    cmd: "generate-audio-signal", 
+	    docOID: "wibble",
+	    site: gs.xsltParams["site_name"],
+	    collect: collect,
+	    assocPath: gs.documentMetadata["assocfilepath"],
+	    assocFile: "doc.wav"
+	};
+
+	that.meandreController.webComponent(that.flowPort,that.serviceHead,start_options);
+	
+	setTimeout(function() { 
+	    that.processThisMeandreFlowOutputData(that.flowPort);
+
+	    if (displayProgress) {
+		$progressElem.css('display','none');
+		$progressTextElem.css('display','block');
+	    }
+
+	    if (elem!=null) {
+		// runFlow has been triggered by clicking on the 'run' button
+		togglePlay(null,document.getElementById('mainPlayButton'));
+	    }
+	    else if (playCallback!=null) {
+		playCallback();
+	    }
+
+	}, 700);
+
+    }, 800);
+}
+
+ChromagramMeandreWorkflow.prototype.stopThisMeandreFlow = function(elem) {
+    
+    this.meandreController.abortFlow(this.flowPort);
+    
+    $('#meandre-stop-button').attr("disabled", "disabled");
+    $('#meandre-run-button').removeAttr("disabled");
+    
+    //$('#meandre-run-button').button({ disabled: false });
+    //$('#meandre-stop-button').button({disabled: true});    
+}
+
Index: /main/trunk/model-sites-dev/multimodal-mdl/collect/js-dsp-my-ipod/script/meandre-workflow/js-dynamic-mix.js
===================================================================
--- /main/trunk/model-sites-dev/multimodal-mdl/collect/js-dsp-my-ipod/script/meandre-workflow/js-dynamic-mix.js	(revision 28433)
+++ /main/trunk/model-sites-dev/multimodal-mdl/collect/js-dsp-my-ipod/script/meandre-workflow/js-dynamic-mix.js	(revision 28433)
@@ -0,0 +1,298 @@
+
+
+var JSDynamicMixMeandreWorkflow = function() {
+
+    var domain_prefix = window.location.protocol + "//" + window.location.hostname;
+
+    this.meandreController = new MeandreController(domain_prefix,"1714","1712");
+
+    this.baseURI     = "http://greenstone.org/meandre/flows/dynamic-javascript-mixer/"
+    this.serviceHead = this.baseURI + "instance/greenstone-audio-web-service-head/0";
+    this.serviceTail = this.baseURI + "instance/float32-frame-web-service-buffer/3";
+
+    this.serviceJSDynamic = this.baseURI + "instance/dynamic-javascript-computation-component/2";
+
+    this.flowPort = null;
+
+    this.meandreFrameSize = null;
+    this.meandreDataOutput = new Array();
+
+    this.meandreCount = 0;
+}
+
+
+JSDynamicMixMeandreWorkflow.prototype.thisMeandreFlowIsRunning = function() {
+    return this.flowPort != null;
+}
+
+function bin2String(array,range) {
+    var result = "";
+
+    var excerpt = range || 5000;
+
+    var lowcut = Math.min(array.length,excerpt);
+        
+    result += "low cut: " + lowcut + "\n";
+    for (var i = 0; i < lowcut; i++) {
+	result += String.fromCharCode(65+array[i]);
+	if (((i+1)%200)==0) {
+	    result += "\n";
+	}
+    }
+    
+    result += "\n";
+
+
+    var highcut = Math.max(array.length-excerpt,0);
+    result += "high cut: " + highcut + "\n";
+
+    for (var i = highcut; i < array.length; i++) {
+	result += String.fromCharCode(65+array[i]);
+	if (((i+1)%200)==0) {
+	    result += "\n";
+	}
+    }
+    result += "\n";
+
+    return result;
+}
+
+JSDynamicMixMeandreWorkflow.prototype.processThisMeandreFlowOutputDataCallback = function(oEvent,oReq) {
+
+
+    var arrayBuffer = oReq.response; // Note: not oReq.responseText
+
+    if (arrayBuffer.byteLength) {
+	//console.log("*** get-data callback: Recieved binary data: raw byte array buffer len = " + arrayBuffer.byteLength);
+
+	//console.log("*** type of arrayBuffer: " + toType(arrayBuffer));
+
+	//var float32Array = new Float32Array(arrayBuffer); 
+	var byteArray = new Uint8Array(arrayBuffer); 
+	var byteArrayLen = byteArray.length;
+
+	var fixPos = new Array();
+	for (var i=0; i<byteArrayLen; i++) {
+	    if ((byteArray[i]==10)) {
+		    // && ((i<byteArrayLen-1) && (byteArray[i+1]==13))) {
+		// Despite the 'response' from the servlet being set to content type 'application/octet'
+		// the output streamed through the server is still treated as text, and a '10' in the binary
+		// stream is changed to '13', '10'
+
+		fixPos.push(i-1); 
+	    }
+	}
+
+	var fixPosLen = fixPos.length;
+	//console.log("*** fix pos len = " + fixPosLen);
+
+	var fixedByteArrayLen = byteArrayLen - fixPosLen;
+	var fixedByteArray = new Uint8Array(fixedByteArrayLen);
+
+	var prevPos = 0;
+	var newPos = 0;
+
+	for (var i=0; i<fixPosLen; i++) {
+	    var currFixPos = fixPos[i];
+
+	    var sliceArray = byteArray.subarray(prevPos,currFixPos);
+	    fixedByteArray.set(sliceArray,newPos);
+
+	    prevPos = currFixPos+1; // shift over erroneous <CR> (char 13)
+	    newPos += sliceArray.length;
+
+	}
+
+	var remainingSliceArray = byteArray.subarray(prevPos);
+	fixedByteArray.set(remainingSliceArray,newPos);
+	
+	if ((fixedByteArray.length % 4) != 0) {
+	    console.error("Fixed Returned binary data is not a multiple of 4");
+
+	    this.meandreDataOutput.push(byteArray);
+	}
+	else {
+	    //console.log("fixed byte array len = " + fixedByteArray.length);
+
+	    var float32Array = new Float32Array(fixedByteArray.buffer); 
+
+	    //console.log("float array len = " + float32Array.length);
+
+	    var meandreFrameSize = this.meandreFrameSize;
+	    var numFramesReceived = float32Array.length/meandreFrameSize;
+	    
+	    //console.log("** meandre output frameSize = " + meandreFrameSize);
+	    console.info("*** get-data callback: number of frames received = " + numFramesReceived);
+
+	    for (var i=0; i<numFramesReceived; i++) {
+		var startPos = i*meandreFrameSize;
+		var endPos   = startPos + meandreFrameSize -1;
+		var frame = float32Array.subarray(startPos,endPos);
+	    
+		//console.log("*** frameSize=" + meandreFrameSize + ", start pos=" + startPos + ", endPos=" + endPos + ", pushing on frame of size: " + frame.length);
+
+		this.meandreDataOutput.push(frame);
+	    }	    
+	}	
+    }
+}
+
+
+
+JSDynamicMixMeandreWorkflow.prototype.processThisMeandreFlowOutputData = function(flowPort) {
+
+    // does flowPort need to be passed in as a parameter, now this is method not a function?
+
+    var getinfo_options = {cmd: "get-info" };
+
+    var info_props = this.meandreController.webComponentProperties(flowPort,this.serviceTail,getinfo_options)
+
+    // values stored in 'info_props' are strings => need to make sure we treat get numeric fields such
+    // as 'numFrames' as an integer
+
+    var numFramesAvailable = parseInt(info_props.numFrames);
+    if (isDefined(numFramesAvailable)) {
+	this.meandreFrameSize = parseInt(info_props.frameSize); 
+    }
+    else {
+	numFramesAvailable = 0;
+    }
+
+//    console.log("*** Meandre count = " + meandreCount);    
+
+    if (numFramesAvailable>0) {
+
+	var getNumFrames = Math.min(600,numFramesAvailable);
+
+	console.info("get-data request: Number of frames available = " + numFramesAvailable, ", number of frames requested = " + getNumFrames);
+
+//	console.log("***** doing a get-data");
+	var getdata_options = {cmd: "get-data", numFrames: getNumFrames };
+	var payload = this.meandreController.binaryWebComponent(flowPort,this.serviceTail,getdata_options,
+								this.processThisMeandreFlowOutputDataCallback,this);
+
+	// delay the next call to 'get-info' to give the 'get-data' a chance to reach the server
+	var that = this;
+	setTimeout(function() {
+	    that.processThisMeandreFlowOutputData(flowPort);
+	}, 800);
+
+    }
+    else {
+	console.log("*** Sending 'done' command");
+	var done_options = {cmd: "done" };
+	this.meandreController.webComponent(flowPort,this.serviceHead,done_options);
+
+	// disable 'stop' and make 'run' active again
+	$('#meandre-stop-button').attr("disabled", "disabled");
+	$('#meandre-run-button').removeAttr("disabled");
+    }
+
+    this.meandreCount++;
+}
+
+
+JSDynamicMixMeandreWorkflow.prototype.runThisMeandreFlow = function(elem,playCallback) {
+
+    if (this.thisMeandreFlowIsRunning()) {
+	console.error("runThisMeandreFlow(): The flow is already running on port " + this.flowPort);
+	return;
+    }
+
+    var $progressElem = $('#processing');
+    var $progressTitleElem = $('#processingTitle');
+    var $progressTextElem = $('#processingText');
+
+    var displayProgress = ($progressElem.length>0) ? true : false;
+    if (displayProgress) {
+	$progressTitleElem.html("Starting Meandre Workflow ...");
+	$progressTextElem.css('display','none');
+	$progressElem.css('display','block');
+    }
+
+
+    var flow_token = this.meandreController.runFlow(this.baseURI);
+    //console.log("**** got flow token : " + flow_token);	  
+    
+    // Give the flow time to start up ...
+    var that = this;
+    setTimeout(function() {
+	// Now find out which port it is running on ...
+ 	var flow_props = that.meandreController.runningFlowProperties(flow_token);
+	var flow_port =  flow_props.port;
+
+	var attempts = 0;
+	while ((flow_port==null) || (flow_port <= 0)) {
+	    console.info("port returned as " + flow_port + ", trying again");
+ 	    flow_props = that.meandreController.runningFlowProperties(flow_token);
+	    flow_port =  flow_props.port;	    
+	    attempts++;
+
+	    if (attempts==10) {
+		break;
+	    }
+	}
+
+	console.info("Running Meandre flow on port : " + flow_port);
+	that.flowPort = flow_port;
+	
+	$('#meandre-run-button').attr("disabled", "disabled");
+	$('#meandre-stop-button').removeAttr("disabled");
+	
+	//$('#meandre-run-button').button({ disabled: true });
+	//$('#meandre-stop-button').button({disabled: false});
+	
+
+	// send over the user's custom javascript
+	var script_str = $("#js-dynamic-code").val();
+
+	var script_options = { 
+	    code: encodeURIComponent(script_str) // effectively double encode to get it through the proxy-server
+	};
+
+	that.meandreController.webComponent(that.flowPort,that.serviceJSDynamic,script_options);
+
+
+	var start_options = { 
+	    cmd: "generate-audio-signal", 
+	    docOID: "wibble",
+	    site: gs.xsltParams["site_name"],
+	    collect: collect,
+	    assocPath: gs.documentMetadata["assocfilepath"],
+	    assocFile: "doc.wav"
+	};
+
+	that.meandreController.webComponent(that.flowPort,that.serviceHead,start_options);
+	
+	setTimeout(function() { 
+	    that.processThisMeandreFlowOutputData(that.flowPort);
+
+	    if (displayProgress) {
+		$progressElem.css('display','none');
+		$progressTextElem.css('display','block');
+	    }
+
+	    if (elem!=null) {
+		// runFlow has been triggered by clicking on the 'run' button
+		togglePlay(null,document.getElementById('mainPlayButton'));
+	    }
+	    else if (playCallback!=null) {
+		playCallback();
+	    }
+
+	}, 800);
+
+    }, 800);
+}
+
+JSDynamicMixMeandreWorkflow.prototype.stopThisMeandreFlow = function(elem) {
+    
+    this.meandreController.abortFlow(this.flowPort);
+    
+    $('#meandre-stop-button').attr("disabled", "disabled");
+    $('#meandre-run-button').removeAttr("disabled");
+    
+    //$('#meandre-run-button').button({ disabled: false });
+    //$('#meandre-stop-button').button({disabled: true});    
+}
+
Index: /main/trunk/model-sites-dev/multimodal-mdl/collect/js-dsp-my-ipod/transform/pages/about.xsl
===================================================================
--- /main/trunk/model-sites-dev/multimodal-mdl/collect/js-dsp-my-ipod/transform/pages/about.xsl	(revision 28433)
+++ /main/trunk/model-sites-dev/multimodal-mdl/collect/js-dsp-my-ipod/transform/pages/about.xsl	(revision 28433)
@@ -0,0 +1,525 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE videocollection [
+  <!ENTITY ndash "&#8211;">
+  <!ENTITY mdash "&#8212;">
+]>
+<xsl:stylesheet version="1.0"
+	xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+	xmlns:java="http://xml.apache.org/xslt/java"
+	xmlns:util="xalan://org.greenstone.gsdl3.util.XSLTUtil"
+	xmlns:gslib="http://www.greenstone.org/skinning"
+	extension-element-prefixes="java util"
+	exclude-result-prefixes="java util">
+
+	<!-- use the 'main' layout -->
+	<xsl:include href="layouts/main.xsl"/>
+
+	<!-- set page title -->
+	<xsl:template name="pageTitle"><gslib:collectionName/></xsl:template>
+
+	<!-- set page breadcrumbs -->
+	<xsl:template name="breadcrumbs"><gslib:siteLink/><gslib:rightArrow/></xsl:template>
+
+	<!-- the page content -->
+	<xsl:template match="/page">
+  
+		<!--Display the description text of the current collection,
+		and if some services are available then create a list
+		of links for each service within a <ul id="servicelist"> element.-->
+
+    <xsl:variable name="httpPath"> 
+      <xsl:value-of select="/page/pageResponse/collection/metadataList/metadata[@name='httpPath']" />
+    </xsl:variable>
+
+
+    <style>
+      p.about { text-align: justify; }
+      h2 { /* line-height: 135%; */ }
+      h3 { margin-top: 4pt; margin-bottom: 7pt; line-height: 135%; }
+
+        a.mashup {text-decoration: none; } 
+	a.mashup:link    {color:#000080;}  /* unvisited link */
+	a.mashup:visited {color:#303080;}  /* visited link */
+	a.mashup:hover   {color:#000040;}  /* mouse over link */
+	a.mashup:active  {color:#0000a0;}
+
+    </style>
+
+
+    <script src="{$httpPath}/script/browser-detect.js" type="text/javascript">
+	/* space filler needed */
+    </script>
+
+
+<div style="width: 800px; margin-left: auto; margin-right: auto;">
+
+
+<h2>A Musical Web Observatory: </h2>
+
+<h3><i><font size="+2">Connecting People with Data, Documents, and Algorithms</font></i></h3>
+
+<div style="background-color: #DD3611; color: white; padding: 4pt; margin-bottom: 6pt;">
+<table>
+
+  <tr>
+    <td>
+       <img src="{$httpPath}/images/firefox-128.png" />
+    </td>
+    <td>
+	<p class="about">
+	  <i><font size="+2">
+	    An experiment with Firefox's Advanced
+	    Audio Processing Extension ...
+	  </font></i>
+	</p>
+
+	<p class="about">
+	  <i><font size="+2">
+... featuring a mash-up of 
+<a class="mashup" href="http://www.greenstone.org" target="_blank">Greenstone</a>,
+<a class="mashup" href="http://www.omras2.org/audioDB" target="_blank">AudioDB</a>, and
+<a class="mashup" href="http://seasr.org/meandre/" target="_blank">Meandre</a>.
+	  </font></i>
+	</p>
+
+
+          <div id="bd-version" style="display:none;" class="about">
+	    <p>
+	      <img src="{$httpPath}/images/warning-icon.png" />
+	        Version of Firefox detected:
+	          <script type="text/javascript">
+	            document.write(BrowserDetect.version);
+	          </script>
+	    </p>
+	    <p>
+            You need to upgrade to a more recent version of Firefox 
+	        (v4.0 or greater) to access all the audio features of 
+	        this demonstration.
+	    </p>
+          </div>
+
+          <div id="bd-browser" style="display:none;" class="about">
+
+	    <p>
+	      <img src="{$httpPath}/images/warning-icon.png" />
+Browser detected:
+	      <script type="text/javascript">
+	        document.write(BrowserDetect.browser);
+	      </script>
+ 	    </p>
+            <p>You need to access this web-site using Firefox 
+	        (v4.0 or greater) to access all the audio features provided.
+	    </p>
+          </div>
+
+
+
+
+  <script>
+    <xsl:text disable-output-escaping="yes">
+
+if (BrowserDetect.browser == "Firefox") {
+  if (BrowserDetect.version &lt; 4) {
+    document.getElementById("bd-version").style.display="block";
+
+  }
+}
+else {
+  document.getElementById("bd-browser").style.display="block";
+
+}
+      </xsl:text>
+    </script>
+
+
+
+
+    </td>
+  </tr>
+</table>
+</div>
+
+<p class="about">This project is currently work in progress.  The sequence of development so far has been:
+
+<style>
+  li { padding-bottom: 10px; }
+
+</style>
+
+
+<ol>
+  <li>
+  <i>Starting point:</i> Manual (command-line) aggregation of disparate
+    resources prior to building the DL.  A set of bespoke Greenstone
+    document processing plugins corrals the heterogeneous gathered
+    data into a unified (homogeneous) canonical form that the DL can
+    access and display.  Everything presented in the DL is
+    either pre-computed (such as the self-similarity heat-maps) or else
+    computed at build-time.
+  </li>
+
+   <li>
+     <i>Audio-fingerprinting:</i> as before, but now metadata about the audio
+     songs is now enriched through a set of audio-fingerprinting web
+     services.  Everything presented in the DL is still pre-computed
+     or else computed at build-timeâhowever,  the inclusion in the document
+     view of a &quot;Discovery&quot; block allows a user to begin to
+     access and explore through linked-data, information related to
+     the song.
+   </li>
+
+  <li>
+    <i>Client-side audio processing (and visualization):</i> the
+    Pre-computed self-similarity heat-maps are dropped from the
+    collection building process in preference for the same information
+    being computed through Javascript running in the user's web
+    browser.
+  </li>
+
+  <li>
+    <i>Embedded Meandre workflows:</i> the Meandre Workbench is
+    integrated into Greenstone.  Audio documents in the Greenstone
+    digital library can now be dispatched and be processed by the
+    selected Meandre, and output from the workflow returned to the
+    Greenstone document viewâfor example, playing audio that has been
+    processed and output from the workflow.
+  </li>
+
+  <li>
+    <i>Client-side workflows:</i> the client-side Javascript
+    processing code is refactored to follow the same methodology as
+    Meandre components.
+  </li>
+
+  <li>
+    <i>Client/Server hybrid workflows:</i> the Greenstone/Meandre
+    integration is extended to support the dynamic 
+    transmission of <tt>executeCallBack()</tt> methods written 
+    in the user's browser in Javascript to be run on the
+    Meandre server as part of the active workflow.
+  </li>
+
+  <li>
+    <i>Forging ahead:</i> the next area to be worked on is upgrading
+    the level of Greenstone/Meandre integration so that data produced
+    by the workflows can be incorporated back into the underlying
+    digital library itself, rather than being (as it currently stands)
+    transitory data that only lives for the duration of the web page
+    being viewed.  This will form an implementation stepping-stone to
+    a more generalized ability to have data retrieved from other
+    external resources (located through the Discovery block
+    linked-data portion of the document view) ingested in to the DL
+    collection.
+  </li>
+
+
+</ol>
+
+</p>
+
+
+
+<!--
+
+<p class="about">This digital library collection demonstrates the
+integration of a variety of sources of structural metadata from both
+automatically derived content analysis and manually labelled
+ground-truth data to form a rich interactive web application suitable
+for musicologists (as the target end-users) to explore a collated set
+of music files.</p>
+
+<p class="about">While the base digital library system, <a
+href="http://www.greenstone.org" target="_blank">Greenstone</a>, is
+designed to operate with any web browser, the audio features this
+particular DL collection demonstrates relies on audio processing
+features currently only available in Firefox.  Using one of the other
+web browsers you will be able to access most features of the digital
+library collection, but when you access a particular song you may find
+playing the audioâin particular the panned audio
+effectâdoes not work.</p>
+-->
+
+
+<!--
+<p class="about">The developed system combines the open source capabilities of
+Greenstone, \cite{Greenstone}, NEMA \cite{Nema}, Salami \cite{Salami},
+and AudioDB \cite{AudioDB}.
+
+%%
+NEMA and Salami have been previously described in this article, and contribute 
+manual and audio content based metadata.
+%%
+AudioDB is a raw-audio content based searching algorithm based on Local-Sensitivity Hashing \cite{LSH}.
+%%
+Greenstone is a versatile digital library architecture with an
+extensible service-based architecture that.  In
+addition to the text-based searching and browsing capability to
+organize content, Greenstone provides the framework in which to harness the
+structural metadata from NEMA and Salami, and the audio-content based
+search functionality of audioDB.
+
+-->
+
+
+
+<h3>A Walkthrough</h3>
+
+
+<p class="about">The following walkthrough is for the initial incarnation of the DL collection, where all
+the information presented is either precomputed or computed at build time.</p>
+
+<p class="about">Taking as a starting point a set of music files identified as worthy
+of study, the <a href="#browse">figure below</a> shows the result of browsing
+the formed digital library collection <a href="dev?a=b&amp;rt=s&amp;s=ClassifierBrowse&amp;c=salami-audioDB&amp;cl=CL1" target="_blank">by title</a> from a web browser.
+The figure is a useful snapshot in which to orientate ourselves with
+the main structure and features to the digital library.  Functionality that
+persistently reoccurs is accessible through the header to the page.</p>
+
+<p class="about">This includes:
+<ul>
+
+<li>help and preferences (top-right);</li>
+<li>a quick-search option (located just
+below) with links to more sophisticated searching options; and</li>
+<li>pin-pointing where within the site a user is currently located
+(top-left).</li>
+</ul>
+
+
+<a name="browse" />
+<table style="width: 700px; margin-left: auto; margin-right: auto; margin-bottom: 6pt;">
+  <tr>
+    <td style="border: solid 1px;">
+      <img style="width: 700px" src="{$httpPath}/images/figs/cropped/salami-browse.png" />
+    </td>
+  </tr>
+  <tr style="background-color: #bbeebb">
+    <td>
+      <i>Browsing in the digital library
+  <a href="dev?a=b&amp;rt=s&amp;s=ClassifierBrowse&amp;c=salami-audioDB&amp;cl=CL1" target="_blank">by titles</a>.</i>
+    </td>
+  </tr>
+</table>
+
+
+The specific content to this location within the site (in this case
+browsing by title) is shown beneath the main banner.  Various
+groupings of title can be accessed by clicking on the bookshelf icons
+vertically aligned as the main part of the page: currently <a
+href="dev?a=b&amp;rt=s&amp;s=ClassifierBrowse&amp;c=salami-audioDB&amp;cl=CL1#CL1.2">CâD</a>
+is open, with the remaining letters to the alphabet below this,
+accessed through scrolling.</p>
+
+
+
+
+<p class="about">Interested in the song <i>Candela</i> our curious musicologist clicks
+on <a href="dev?a=d&amp;ed=1&amp;book=off&amp;c=salami-audioDB&amp;d=D145&amp;dt=simple&amp;sib=1&amp;p.a=b&amp;p.sa=&amp;p.s=ClassifierBrowse" target="_blank">the link for this</a>.  This brings up the document view to this song:</p>
+
+<a name="self-similarity" />
+<table style="width: 700px; margin-left: auto; margin-right: auto; margin-bottom: 6pt;">
+  <tr>
+    <td style="border: solid 1px;">
+      <img style="width: 700px" src="{$httpPath}/images/figs/cropped/salami-self-similarity2.png" />
+    </td>
+  </tr>
+  <tr style="background-color: #bbeebb">
+    <td>
+      <i>The <a href="dev?a=d&amp;ed=1&amp;book=off&amp;c=salami-audioDB&amp;d=D145&amp;dt=simple&amp;sib=1&amp;p.a=b&amp;p.sa=&amp;p.s=ClassifierBrowse" target="_blank">musicologically enriched document view</a> for</i> Candela.
+    </td>
+  </tr>
+</table>
+
+<p class="about">Normally in a digital
+library the document view brings up a page that is strongly derived
+from textual metadata.  If the document viewed was a text-document,
+some summary information such as title and author is typically
+presented, say in tabular form, before the main text is presented.
+Even in the case of multimedia digital libraries, the view presented
+is still strongly derived from textual metadata: this time including
+details such as the length of the video, the TV company that produced
+it, whether captions are available, and so forth, accompanied with an
+embedded video player for viewing the contentâessentially more
+textual metadata (in this case the URL to the video content) which in
+terms of the user-interface is largely divorced from the other
+elements displayed on the page.</p>
+
+<p class="about">This contrasts sharply with the document view developed in this
+digital library.
+Naturally it allows the song to be played (akin to the embedded video player),
+however this is largely of secondary importance to the 
+other functionality available this is much more closely
+integrated.</p>
+
+<p class="about">The most striking visual component to the document view is a
+self-similarity &quot;heat map&quot; where the duration of the song forms both
+the <i>x</i>- and <i>y</i>-axis, and a red pixel located at a given <i>(x,y)</i>
+co-ordinate in the map represents a location where two parts of the
+song are strongly similar, proportionally shifting to blue to
+represent dissimilar.  Given this configuration, the leading diagonal
+to the matrix (<i>x=y</i>) is always coloured red as this represents the
+comparison of one part of the song with itself.</p>
+
+<p class="about">When the user moves the mouse cursor around the self-similarity map
+a highlighting circle is shown to emphasize the area the user is over,
+with a black dot at the centre (visible in in
+the <a href="#self-similarity">above figure</a>); annotated vertically
+and horizontally are the two time-offsets in seconds that that point
+in the map corresponds to.  Clicking the cursor at this point results
+in the audio being played <i>simultaneously</i> from these two points.
+To aid the musicologist in listening to the two parts of the song, one
+part is panned to the left speaker, and the other to the right (this
+was implemented using the extended audio API provided by Firefox, and
+so this particular feature only work when viewing the collection with
+this browserâsee implementation details below).  In our figure,
+the musicologist has zeroed in the location <i>x=33</i>, <i>y=97</i>
+which corresponds to the start of a strong red diagonal that occurs
+some distance off the leading diagonal.  Listening to the two sounds
+played (most reliably done with headphones on), they hear that these
+two sections of the song are indeed repeating sections of the guitar
+piece <i>Candela</i> with a minor variation in the latter section
+where a recorder is also playing in the arrangement.</p>
+
+<p class="about">The structured audio time-lines (labelled A, B, ..., and 6, 5, 2,
+... in the figure) located above the self-similarity map are another
+area of enriched musical content in the digital library. The upper
+line shows the ground-truth data for this song generated by
+the <a href="http://www.music-ir.org/?q=node/14" target="_blank">Salami project</a>;
+the lower line is generated by an algorithmically based content
+analysis algorithm.</p>
+
+<p class="about">While there is some agreement between these two lines, there are
+also significant differences.  The play and search buttons within the
+structured time-lines (the latter represented by a magnifying glass)
+allow the user to investigate further these structures.  We shall
+return to the search functionality shortly (which is content based,
+using <a href="http://omras2.doc.gold.ac.uk/software/audiodb/" target="_blank">AudioDB</a>),
+but in the meantime note that with the time-lines positioned above the
+self-similarity map, there is further opportunity to study the
+differences between the two structured time-line.  It is certainly the
+case that there are strong visual cues in the map that line up with
+the algorithmic time-line, even though they do not align with a
+boundary in the ground-truth data, and the user can click on these
+parts of the similarity map to hear what is occurring at these
+points.</p>
+
+
+
+<a name="resultspage" />
+<table style="width: 700px; margin-left: auto; margin-right: auto; margin-bottom: 6pt;">
+  <tr>
+    <td style="border: solid 1px;">
+      <img style="width: 350px" src="{$httpPath}/images/figs/cropped/salami-audiodb-search-resultspage-halfcut.png" />
+    </td>
+    <td style="border: solid 1px;">
+      <img style="width: 350px" src="{$httpPath}/images/figs/cropped/salami-structured-search-resultspage-halfcut.png" />
+    </td>
+  </tr>
+  <tr style="background-color: #bbeebb">
+    <td colspan="2">
+      <i>Audio content based search results: left) the 
+	<a href="dev?a=q&amp;sa=&amp;rt=rd&amp;s=AudioQuery&amp;c=salami-audioDB&amp;startPage=1&amp;s1.maxDocs=100&amp;s1.hitsPerPage=20&amp;q=D206.dir&amp;s1.query=D206.dir&amp;s1.offset=263&amp;s1.length=24&amp;mysongWindowDuration=6" target="_blank">result list</a> from
+      an audio content based query taken from an extract of </i>
+      Michelle; <i>and right)
+      the <a href="dev?a=q&amp;sa=&amp;rt=rd&amp;s=TextQuery&amp;c=salami-audioDB&amp;startPage=1&amp;s1.query=%22b+b+c+b+c%22&amp;s1.index=JS" target="_blank">result of a structured music search</a> for
+      content containing &quot;b b c b a&quot; as a sequence.</i>
+    </td>
+  </tr>
+</table>
+
+<p class="about">Returning to the search capability provided by the structured
+time-lines, the <a href="#resultspage">above figure (left)</a> show the result of
+using this feature while study the song <i>Michelle</i> by The
+Beatles.  In this case the user selected the section of the
+ground-truth time-line corresponding to section starting &quot;I want you
+...&quot;, but could have equally used the algorithmically calculated
+time-line, or in fact paused the song playing at any point, and
+started a match from there.</p>
+
+
+<p class="about">Not surprisingly <i>Michelle</i> is returned as the top hit (at
+92.1%)âwe shall see shortly that this is because the system found
+several sections of the song that matched thisâthe next hit being
+<i>Bigger Than JC</i> at 74.4%, and so on down, where only one hit
+per song occurs.  Clicking on the top hit,
+the <a href="#audiodb">figure below</a> shows the document view that is
+displayed, focusing in on the key area to this screen.  This time the
+time-line area has an additional bar: the points within the song that
+AudioDB found to be similar.  Like the other time-lines, a play button
+is present on these segments so the user can play the matching points
+directly.  In this case
+clicking on them reveals the matching sections found correspond to
+melodically repeating sections of the song, only with different lyrics
+(&quot;I love you ...&quot; and &quot;I need you ...&quot;).</p>
+
+
+<p class="about">A further form of musical content-based searching is available through
+the main header to the digital library.  Instead of searching by title
+or artist (which are also available) the user can click on this
+&quot;search by&quot; menu next to the quick-search text box and select
+&quot;ground-truth structure&quot; instead.
+The <a href="#resultspage">figure above</a> (right) shows the result of using this
+option, where the user has entered &quot;b b c b c&quot; as the query, in
+other words searching for songs that have two sections in a row the
+same, then a new section, then returning to the original section,
+before progressing to a recurrence of the second distinct section.  In
+pop and rock music this is a popular sequence corresponding to verse,
+verse, chorus, verse, chorus.  A more intriguing framing of a query
+along these linesâequally possible in the digital libraryâwould be
+to go to the fielded search page (accessible through the <i>advanced
+  search</i> link below the quick-search box, and entered the same
+music structure query, but this time combine it with other fielded
+query terms (Genre=Blues OR Jazz, Year&lt;1950).  Results from this
+query would let the musicologist explore potential evidence of this
+pattern of sections being used in two of the key musical genres that
+influenced the development of Rock and Roll music.</p>
+
+
+<a name="audiodb" />
+<table style="width: 700px; margin-left: auto; margin-right: auto; margin-bottom: 6pt;">
+  <tr>
+    <td style="border: solid 1px;">
+      <img style="width: 700px" src="{$httpPath}/images/figs/cropped/salami-audiodb-search2.png" />
+    </td>
+  </tr>
+  <tr style="background-color: #bbeebb">
+    <td>
+      <i>The document view for</i> Michelle <i><a href="dev?a=d&amp;c=salami-audioDB&amp;d=D206&amp;dt=simple&amp;p.frameOffset=133,393,264,262,392&amp;p.frameLength=24&amp;p.a=q&amp;p.s=AudioQuery&amp;hl=on&amp;ed=1#D206" target="_blank">augmented with the locations of the matches</a> of the audio query.</i>
+    </td>
+  </tr>
+</table>
+
+
+
+
+<h3>Implementation details</h3>
+
+<p class="about">The core part of the interactive elements in the document view were
+implemented using SVG combined with Javascript.  The left- and
+right-panning interactively available from the self-similarity map was
+implemented by processing the raw audio stream, made accessible by the
+Firefox Audio extension
+<a href="https://wiki.mozilla.org/Audio_Data_API" target="_blank">API</a>.</p>
+
+<p class="about">AudioDB content based searching was integrated into Greenstone through
+two components of the digital library software architecture: its
+build-time document processing plugin system, and its runtime
+message-passing service-base framework.  The developed plugin accepts
+a wide range of audio formats (including OGG and MP3), and converts
+them to WAV, the format needed by AudioDB for processing.  The new
+search service took the form of a proxy, accepting messages in the
+XML syntax used by Greenstone, turning them into the necessary calls
+to the AudioDB command-line interface, and then converting the output
+from AudioDB back into the XML syntax expected by the digital library
+architecture.  Finally, the two parts were packaged to operate as a
+Greenstone extension; the software is available at:
+<a href="http://trac.greenstone.org/gs3-extensions/audioDB/trunk/src" target="_blank">http://trac.greenstone.org/gs3-extensions/audioDB/trunk/src</a>.</p>
+
+</div>
+
+
+	</xsl:template>
+
+
+</xsl:stylesheet>  
+
Index: /main/trunk/model-sites-dev/multimodal-mdl/collect/js-dsp-my-ipod/transform/pages/document.xsl
===================================================================
--- /main/trunk/model-sites-dev/multimodal-mdl/collect/js-dsp-my-ipod/transform/pages/document.xsl	(revision 28433)
+++ /main/trunk/model-sites-dev/multimodal-mdl/collect/js-dsp-my-ipod/transform/pages/document.xsl	(revision 28433)
@@ -0,0 +1,895 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet version="1.0"
+	xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+	xmlns:java="http://xml.apache.org/xslt/java"
+	xmlns:util="xalan://org.greenstone.gsdl3.util.XSLTUtil"
+	xmlns:gslib="http://www.greenstone.org/skinning"
+	xmlns:gsf="http://www.greenstone.org/greenstone3/schema/ConfigFormat"
+	xmlns:xlink="http://www.w3.org/1999/xlink" 
+	extension-element-prefixes="java util"
+	exclude-result-prefixes="java util gsf">
+  
+
+  <!-- *** -->
+  <!-- Document header -->
+  <!-- *** -->
+
+  <xsl:template name="soundmanager2-header">
+
+    <!-- soundManager2 API -->
+    <gsf:style src="ext/sound-manager2/css/flashblock.css" />  
+    <gsf:script src="ext/sound-manager2/script/soundmanager2-nodebug.js"/>
+
+    <!-- The Page player (variant of SoundManger) main script -->
+    <gsf:script src="ext/sound-manager2/script/page-player.js"/>
+    <gsf:style src="ext/sound-manager2/css/page-player.css" />
+        
+    <!-- optional: annotations/sub-tracks/notes, and alternate themes -->
+    <gsf:style src="ext/sound-manager2/css/optional-annotations.css" />
+    <gsf:style src="ext/sound-manager2/css/optional-themes.css" />
+
+    <!-- optional: Metadata UI prototype (not needed unless you want the bottom-most demo bits) -->
+    <gsf:script src="ext/sound-manager2/script/optional-page-player-metadata.js"/>
+    
+    <gsf:style>
+      ul.playlist li .comment {font-size:0.65em;opacity:0.5}
+    </gsf:style>
+    
+    <!-- Customization of page-player for this collection -->
+
+    <gsf:script>
+
+      soundManager.flashVersion = 9;
+      soundManager.preferFlash = true;        /* for visualization effects */
+      soundManager.useHighPerformance = true; /* keep flash on screen, boost performance */
+      soundManager.wmode = "transparent";     /* transparent SWF, if possible */
+      soundManager.useFastPolling = true;     /* increased JS callback frequency */
+      soundManager.url = "ext/sound-manager2/swf/";
+
+      /* custom page player configuration */
+
+      var PP_CONFIG = {
+        autoStart:       false,  /* begin playing first sound when page loads */
+	playNext:        false,  /* stop after one sound, or play through list until end */
+	useThrottling:   false,  /* try to rate-limit potentially-expensive calls (eg. dragging position around) */
+	usePeakData:     true,   /* [Flash 9 only] whether or not to show peak data (left/right channel values) - nor noticable on CPU */
+	useWaveformData: false,  /* [Flash 9 only] show raw waveform data - WARNING: LIKELY VERY CPU-HEAVY */
+	useEQData:       false,  /* [Flash 9 only] show EQ (frequency spectrum) data */
+	useFavIcon:      false,  /* try to apply peakData to address bar (Firefox + Opera) - performance note: appears to make Firefox 3 do some temporary, heavy disk access/swapping/garbage collection at first(?) - may be too heavy on CPU */
+	useMovieStar:    true    /* Flash 9.0r115+ only: Support for a subset of MPEG4 formats. */
+      }
+    </gsf:script>
+  </xsl:template>
+
+
+  <!-- CAA = Content Analysis Algorithm -->
+  <xsl:variable name="cgiargCAAlgorithm">
+    <xsl:choose>
+      <xsl:when test="/page/pageRequest/paramList/param[@name='p.caAlgorithm']/@value != ''"><xsl:value-of select="/page/pageRequest/paramList/param[@name='p.caAlgorithm']/@value"/></xsl:when>
+      <xsl:otherwise>1</xsl:otherwise>
+    </xsl:choose>
+  </xsl:variable>
+
+  <!-- *** -->
+  <!-- The Javascript DSP files for computing chroma features in the browser -->
+  <!-- *** -->
+
+  <xsl:template name="javascript-dsp-header">
+    <gsf:script src="ext/js-dsp/dsp-custom.js"/>
+    <gsf:script src="ext/js-dsp/chroma-transform.js"/>
+    <gsf:script src="ext/js-dsp/frequency-plotter.js"/>
+    <gsf:script src="ext/js-dsp/frequency-player.js"/>
+
+
+    <gsf:script src="ext/js-dsp/component/crockford-inheritance.js"/>
+    <gsf:script src="ext/js-dsp/component/workflow-core.js"/>
+    <gsf:script src="ext/js-dsp/component/audio-mixer.js"/>
+    <gsf:script src="ext/js-dsp/component/wf-freq-spectrum.js"/>
+    <gsf:script src="ext/js-dsp/component/wf-filter-bank.js"/>
+    <gsf:script src="ext/js-dsp/component/wf-chroma-transform.js"/>
+    <gsf:script src="ext/js-dsp/component/active-workflow.js"/>
+
+  </xsl:template>
+
+  <xsl:template name="processingPopup">
+    <div>
+      <style type="text/css">	
+	#processing { 
+	  width: 100%; 
+	  height: 100%; 
+	  position: absolute; 
+	  z-index: 10; 
+	  left: 0px; 
+	  top: 0px; 
+	  background-color: rgba(255,255,255,0.75); 
+	  opacity: 1; 
+	  display: none;
+	}
+
+	#processingMessage { 
+	  position: absolute;
+	  padding: 10px;
+	  border-radius: 10px; 
+	  margin-left: 50%; 
+	  width: 380px; 
+	  height: 105px; 
+	  left: -250px; top: 200px; 
+	  background-color: rgba(255,255,255,1);
+	  box-shadow: 0px 0px 30px rgba(0,0,0,0.8); 
+	}
+
+	#processingMessage p { 
+	  font-size: 18px; 
+	  text-align: center; 
+	  font-family: 
+	  sans-serif; 
+	  font-weight: bold; 
+	  color: #666; 
+	}
+      </style>
+      
+      <div id="processing">
+	<div id="processingMessage">
+	  <h2 id="processingTitle" class="ui-state-default ui-corner-all" style="padding: 8px; font-size: 110%; width: auto;">
+	    Heading
+	  </h2>
+	  <p id="processingText">text</p>
+	</div>
+      </div>
+    </div>
+
+  </xsl:template>
+
+  <!-- *** -->
+  <!-- * Discovery -->
+  <!-- *** -->
+
+  <xsl:template name="discovery-block">
+    
+    <div id="fingerprint-turnstyle">
+
+      <div style="background-image: none; background-color: rgb(80%,80%,20%);">
+	Discovery: <xsl:call-template name="choose-title"/>
+      </div>
+
+      <div class="documenttext" style="display: none;">
+	<xsl:call-template name="fingerprintMetadataBlock" />
+      </div>
+
+    </div>
+
+    <script>
+      <xsl:text disable-output-escaping="yes">
+	$(function(){
+	transformToTurnstyleBlock("fingerprint");
+	});
+      </xsl:text>
+    </script>
+    
+  </xsl:template>
+
+  <xsl:template name="fingerprintMetadataBlock">
+    
+    <xsl:variable name="httpCollection"><xsl:value-of select="/page/pageResponse/collection/metadataList/metadata[@name='httpPath']"/></xsl:variable>
+    <xsl:variable name="assocFilePath"><gsf:metadata name="assocfilepath" select="root"/></xsl:variable>
+
+
+    <xsl:variable name="musicbrainzsongid">
+      <gsf:metadata name="dc.Identifier.musicbrainzsongid"/>
+    </xsl:variable>
+
+    <xsl:variable name="musicbrainzalbumid">
+      <gsf:metadata name="dc.Source.musicbrainzalbumid"/>
+    </xsl:variable>
+
+    <xsl:variable name="musicbrainzartistid">
+      <gsf:metadata name="dc.Creator.musicbrainzartistid"/>
+    </xsl:variable>
+    
+    <xsl:variable name="lastfmtrackurl">
+      <gsf:metadata name="dc.Identifier.lastfmtrackurl"/>
+    </xsl:variable>
+
+    <xsl:variable name="echonestsongid">
+      <gsf:metadata name="dc.Identifier.echonestsongid"/>
+    </xsl:variable>
+    
+      <table class="metadata-stripes">
+	<tbody>
+	  <tr>
+	    <td>
+	      Title
+	    </td>
+	    <td>
+	      <gsf:metadata name="dc.Title"/>
+	    </td>
+	  </tr>
+	  
+	  <tr>
+	    <td>Album Title</td>
+	    <td><gsf:metadata name="dc.Title.albumtitle"/></td>
+	  </tr>
+	  
+	  <tr>
+	    <td>Artist</td>
+	    <td><gsf:metadata name="dc.Creator"/></td>
+	  </tr>
+	  
+	  <tr valign="top">
+	    <td>Artist Summary</td>
+	    <td><i><gsf:metadata name="LastFM.LastFMArtistWikiSummary"/></i></td>
+	  </tr>
+	  
+<!--
+dc.Identifier.echonestsongid
+dc.Identifier.echonestartistid
+
+dc.Identifier.lastfmtrackurl
+dc.Identifier.lastfmalbumurl
+dc.Identifier.lastfmartisturl
+
+//dc.Identifier
+dc.Identifier.musicbrainzalbumid
+dc.Identifier.musicbrainzartistid
+dc.Identifier.musicbrainzsongid
+dc.Identifier.playmeartistid
+
+-->
+
+	  <tr>
+	    <td colspan="2">
+
+	      <xsl:for-each select="/page/pageResponse/document/metadataList/metadata[@name = 'dc.Relation.artistrelatedimage']">
+		<xsl:if test="position() &lt;= 6">
+		  <a target="_blank">
+		    <xsl:attribute name='href'>
+		      <xsl:value-of disable-output-escaping="yes" select="."/>
+		    </xsl:attribute>
+		    
+		    <img width="150">
+		      <xsl:attribute name='src'>
+			<xsl:value-of disable-output-escaping="yes" select="."/>
+		      </xsl:attribute>
+		    </img>
+		  </a>
+		</xsl:if>
+	      </xsl:for-each>
+	    </td>
+	  </tr>
+
+	  <tr>
+	    <td>Linked Data</td>
+	    <td>
+	      <!--
+		  <gsf:metadata name="dc.Identifier"/><br />
+	      -->
+
+	      <table>
+		<tr>
+		  <td>
+		    MusicBrainz song id: 
+		  </td>
+		  <td>
+		    <a href="http://dbtune.org/musicbrainz/resource/track/{$musicbrainzsongid}" target="#musicbrainz">
+		      <xsl:copy-of select="$musicbrainzsongid"/>
+		    </a>
+		  </td>
+		</tr>
+
+		<tr>
+		  <td>
+		    MusicBrainz album id: 
+		  </td>
+		  <td>
+		    <a href="http://dbtune.org/musicbrainz/resource/record/{$musicbrainzalbumid}" target="#musicbrainz">
+		      <xsl:copy-of select="$musicbrainzalbumid"/>
+		    </a>
+		  </td>
+		</tr>
+
+		<tr>
+		  <td>
+		    MusicBrainz artist id: 
+		  </td>
+		  <td>
+		    <a href="http://dbtune.org/musicbrainz/page/artist/{$musicbrainzartistid}" target="#musicbrainz">
+		      <xsl:copy-of select="$musicbrainzartistid"/>
+		    </a>
+		  </td>
+		</tr>
+		<tr>
+		  <td colspan="2">	      
+		    <a href="{$lastfmtrackurl}" target="#lastfm">
+		      <xsl:copy-of select="$lastfmtrackurl"/>
+		    </a>
+		  </td>
+		</tr>
+		<tr>
+		  <td>
+		    EchoNest song id:
+		  </td>
+		  <td>
+		    <a href="{$echonestsongid}" target="#echonestsongid">
+		      <xsl:copy-of select="$echonestsongid"/>
+		    </a>
+		  </td>
+		</tr>
+	      </table>
+
+	    </td>
+	  </tr>
+	  
+
+	</tbody>
+      </table>
+  </xsl:template>
+
+
+
+  <!-- *** -->
+  <!-- * Audio Player -->
+  <!-- *** -->
+
+
+  <xsl:template name="js-mad-header">
+
+        <gsf:script src="ext/js-mad/script/mad.js"/>
+        <gsf:script src="ext/js-mad/script/rq_table.js"/>
+        <gsf:script src="ext/js-mad/script/imdct_s.js"/>
+        <gsf:script src="ext/js-mad/script/huffman.js"/>
+        <gsf:script src="ext/js-mad/script/bit.js"/>
+        <gsf:script src="ext/js-mad/script/stream.js"/>
+        <gsf:script src="ext/js-mad/script/layer3.js"/>
+        <gsf:script src="ext/js-mad/script/frame.js"/>
+        <gsf:script src="ext/js-mad/script/synth.js"/>
+       
+        <gsf:script src="ext/js-mad/script/arraybuffer/bytestream.js"/>
+        <gsf:script src="ext/js-mad/script/arraybuffer/filestream.js"/>
+        <gsf:script src="ext/js-mad/script/arraybuffer/substream.js"/>
+        <gsf:script src="ext/js-mad/script/arraybuffer/arraystream.js"/>
+        <gsf:script src="ext/js-mad/script/arraybuffer/ajaxstream.js"/>
+
+        <gsf:script src="ext/js-mad/script/binarystring/bytestream.js"/>
+        <gsf:script src="ext/js-mad/script/binarystring/filestream.js"/>
+        <gsf:script src="ext/js-mad/script/binarystring/substream.js"/>
+        <gsf:script src="ext/js-mad/script/binarystring/stringstream.js"/>
+        <gsf:script src="ext/js-mad/script/binarystring/ajaxstream.js"/>
+
+        <gsf:script src="ext/js-mad/script/id3v22stream.js"/>
+        <gsf:script src="ext/js-mad/script/id3v23stream.js"/>
+        <gsf:script src="ext/js-mad/script/mp3file.js"/>
+        
+<!--
+        <gsf:script src="ext/js-mad/script/player.js"/>
+-->
+
+        <gsf:script src="ext/js-mad/script/sink.min.js"/>
+
+<!--
+        <gsf:script src="ext/js-mad/script/require.js"/>
+-->
+<!--
+        <gsf:script src="ext/js-mad/script/sink-light.js"/>
+-->
+
+        <gsf:script src="ext/js-mad/script/browser-detect.js"/>
+        <gsf:script src="ext/js-mad/script/main-jsmad.js"/>
+
+  </xsl:template>
+
+
+  <xsl:template name="audio-icon-cache">
+    <div style="display:none;">
+      <!-- pre-load various play/pause images to help with speed of interface update -->
+      <img src="ext/diy-audio-player/images/play32Highlight.png" />
+      <img src="ext/diy-audio-player/images/pause32.png" />
+      <img src="ext/diy-audio-player/images/pause32Highlight.png" />
+      <img src="ext/diy-audio-player/images/play20Highlight.png" />
+      <img src="ext/diy-audio-player/images/stop32.png" />
+      <img src="ext/diy-audio-player/images/stop32Highlight.png" />
+      <img src="ext/diy-audio-player/images/search20Highlight.png" />	
+    </div>
+  </xsl:template>
+
+
+  <!-- *** -->
+  <!-- * Workflow control -->
+  <!-- *** -->
+
+  <xsl:template name="workflow-block">
+    <xsl:variable name="httpCollection">
+      <xsl:value-of select="/page/pageResponse/collection/metadataList/metadata[@name='httpPath']"/>
+    </xsl:variable>
+
+    <div id="workflow-turnstyle">
+
+      <div style="background-image: none; background-color: rgb(80%,80%,20%);">
+	Workflow
+      </div>
+
+      <div class="documenttext hide" style="color: white; background-color: rgb(40%,40%,20%); padding: 8px;">
+	
+<!--
+	<form style="padding-left: 8px;">
+	  <span class="vis-heading">Input Selection:</span>
+	  <input type="radio" name="inputSelection" onclick="setInputSelectionMode(this)" value="left"/>Left only
+	  <input type="radio" name="inputSelection" onclick="setInputSelectionMode(this)" value="right"/>Right only
+	  <input type="radio" name="inputSelection" onclick="setInputSelectionMode(this)" value="diff"/>Average
+	  <input type="radio" name="inputSelection" onclick="setInputSelectionMode(this)" value="mix" checked="checked"/>Difference
+	</form>
+	<hr/>
+-->
+
+	<form style="padding-left: 8px; height: 48px;">
+	  <span class="vis-heading" style="padding-right: 10px" >Meandre Workflow:</span>
+
+	  <select id="meandre-workflow-pos" onChange="loadSelectedWorkflow(this)" style="font-size: 90%; padding 8px;">
+	    <option value="0" selected="selected">Chromagram</option>
+	    <option value="1" >Dynamic Javascript Mixer</option>
+	  </select>
+
+	  <div style="float: right;" id="meandre-buttons">
+	 
+	    <button type="button" id="meandre-run-button"  
+		    onclick="selectedMeandreWorkflow.runThisMeandreFlow(this)">
+	      <img id="meandre-run-button" src="ext/diy-audio-player/images/play32.png" 
+		   width="32"
+		   height="32"  
+		   XXonmouseover="playHighlightOn(this)"
+		   XXonmouseout="playHighlightOff(this)"
+		   XXonclick="runThisMeandreFlow(this)"
+		   style="vertical-align: middle;"/>
+	      Run
+	    </button>
+
+	    <button type="button" id="meandre-stop-button" onclick="selectedMeandreWorkflow.stopThisMeandreFlow(this)" disabled="disabled">
+	      <img id="meandre-stop-button" src="ext/diy-audio-player/images/stop32.png" 
+		   width="32"
+		   height="32"  
+		   XXonmouseover="stopHighlightOn(this)"
+		   XXonmouseout="stopHighlightOff(this)"
+		   XXonclick="stopThisMeandreFlow(this)"
+		   style="vertical-align: middle;"/>
+	      Stop
+	    </button>
+
+<!--
+	    <button type="button" id="meandre-run-button" onclick="runThisMeandreFlow(this)" >Run</button>
+	    <button type="button" id="meandre-stop-button" onclick="stopThisMeandreFlow(this)" disabled="disabled">Stop</button>
+-->
+
+	  </div>
+
+	</form>
+
+	<style>
+	  #meandre-buttons button:hover:enabled {
+	    background-color: #CCCC33;
+	    color: #FFFFFF;
+	  }
+	</style>
+	  
+
+	<div style="position: relative;">
+	  <iframe id="workbenchFrame" 
+		  style="width: 100%; height: 400px;" >
+	    If you see this, then your browser does not support the iframe element.
+	  </iframe>
+
+	</div>
+
+	<gsf:script src="{$httpCollection}/script/meandre-workflow/chromagram.js"/>
+	<gsf:script src="{$httpCollection}/script/meandre-workflow/js-dynamic-mix.js"/>
+	
+	<gsf:script>
+	  var chromagramMeandreWorkflow = new ChromagramMeandreWorkflow();
+	  var jsDynamicMixMeandreWorkflow = new JSDynamicMixMeandreWorkflow();
+
+	  var meandreWorkflows = [ chromagramMeandreWorkflow, jsDynamicMixMeandreWorkflow ];
+
+	  var selectedMeandreWorkflowPos =$('#meandre-workflow-pos option:selected').val();
+	  var selectedMeandreWorkflow = meandreWorkflows[selectedMeandreWorkflowPos];
+
+	  selectedMeandreWorkflow.meandreController.loadWorkbench( "workbenchFrame",selectedMeandreWorkflowPos);
+	  
+	  function loadSelectedWorkflow(elem) { 	       
+	      selectedMeandreWorkflowPos = elem.value;
+	      selectedMeandreWorkflow = meandreWorkflows[selectedMeandreWorkflowPos];
+
+	    if (selectedMeandreWorkflowPos==1) {
+	      $('#jsdynamic-turnstyle').show();
+	    }
+	    else {
+	      $('#jsdynamic-turnstyle').hide();
+	    }
+
+	    console.info("Loading in new Meandre workbench flow (pos=" + selectedMeandreWorkflowPos+ ")");		
+	    selectedMeandreWorkflow.meandreController.loadWorkbench("workbenchFrame",selectedMeandreWorkflowPos);
+
+	  }
+	</gsf:script>
+	
+
+
+
+	<div id="jsdynamic-turnstyle" style="display:none">
+	  
+	  <div style="background-image: none; background-color: rgb(80%,80%,20%);">
+	    Dynamic Javascript Meandre Component
+	  </div>
+
+	  <div class="documenttext hide" style="color: white; background-color: rgb(40%,40%,20%); padding: 8px;">
+
+	    <textarea id="js-dynamic-code" style="width:100%; height: 520px; font-size: 60%">
+	      <xsl:text disable-output-escaping="yes">
+
+
+var arrayBinding = new JavaImporter(java.lang.reflect.Array);
+
+var JSDynamicComponent = function() {
+  this.frameCount = 0;
+}
+
+JSDynamicComponent.prototype.executeCallBack = function(cc) {
+
+  with(arrayBinding) {
+
+    if ((this.frameCount % 1000)==0) {
+      print("JSDynamicComponent: " + this.frameCount + "\n");
+    }
+
+    var inputObject = cc.getDataComponentFromInput("input");
+    var rawInput1DArray = inputObject;
+
+    var rawOutput1DArray = Array.newInstance(java.lang.Double.TYPE, rawInput1DArray.length);
+
+    for (var i=1; i&lt;rawOutput1DArray.length; i++) {
+      var diff = Array.getDouble(rawInput1DArray,i) - Array.getDouble(rawInput1DArray, i-1);
+      Array.setDouble(rawOutput1DArray,i,diff);
+    }
+
+    cc.pushDataComponentToOutput("output", rawOutput1DArray);
+
+    this.frameCount++;
+  }
+
+}
+
+var jsDynamicComponent = new JSDynamicComponent();
+
+	      </xsl:text>
+	    </textarea>
+	  </div> <!-- end of Dynamic JS turnstyle block -->
+	</div>
+
+      </div>
+
+    </div>
+
+    <script>
+      <xsl:text disable-output-escaping="yes">
+	$(function(){
+	    transformToTurnstyleBlock("workflow");
+	    transformToTurnstyleBlock("jsdynamic");
+	});	
+      </xsl:text>
+    </script>
+  </xsl:template>
+
+
+  <!-- *** -->
+  <!-- * Structured audio player -->
+  <!-- *** -->
+ 
+  <xsl:template name="structuredAudioPlayerBlock">
+
+    <gsf:script src="ext/diy-audio-player/script/structured-audio-play.js"/>
+    
+    <div style="background-color: rgb(40%,40%,20%)">
+      <svg xmlns="http://www.w3.org/2000/svg" 
+           xmlns:xlink="http://www.w3.org/1999/xlink" 
+	   version="1.1"
+           id="svgGroundTruthSegments" 
+	   width="100%" height="24"
+           onLoadXX="svgGTStructuredInit()">
+      </svg>
+    </div>
+    
+    <div style="background-color: rgb(40%,40%,20%)">
+      <svg xmlns="http://www.w3.org/2000/svg" 
+           xmlns:xlink="http://www.w3.org/1999/xlink" 
+	   version="1.1"
+           id="svgContentAnalysisSegments" 
+	   width="100%" height="24"
+           onLoadXX="svgCAStructuredInit({$cgiargCAAlgorithm})">
+      </svg>
+    </div>
+  </xsl:template>
+  
+  <xsl:template name="visualization-mode-block">
+    
+    <div class="documenttext" style="color: white; background-color: rgb(40%,40%,20%); padding-top: 4px;">
+
+      <span class="vix-heading">Max Values:</span>
+      <div style="padding-left: 8px">
+	<style>
+	  span.mv-fixed { display: inline-block; width: 30pt; }
+	</style>
+	<table width="100%">
+	  <tr>
+	    <td><span class="mv-fixed" id="freqSpectrumMax"     >0.000</span>(Freq Spectrum)       </td>
+	    <td><span class="mv-fixed" id="freqPowerSpectrumMax">0.000</span>(Freq Power Spectrum) </td>
+	    <td><span class="mv-fixed" id="filterBankMax"       >0.000</span>(Filter Bank)         </td>
+	    <td><span class="mv-fixed" id="chromaFeaturesMax"   >0.000</span>(Chroma Features)     </td>
+	  </tr>
+	</table>
+      </div>
+      <hr/>
+  
+      <form style="padding-left: 8px; padding-right: 8px; padding-bottom: 0px;">
+	<div style="float: left;">
+	  <span class="vis-heading">Visualization:</span>
+<!--
+	<input type="radio" name="visualization" onclick="setTransformMode(this)" value="freqSpectrum" />Frequency Spectrum 
+	<input type="radio" name="visualization" onclick="setTransformMode(this)" value="freqPowerSpectrum"/>Frequency Power Spectrum
+-->
+	
+	  <input type="radio" name="visualization" onclick="setTransformMode(this)" value="filterBank"/>Filter Bank 
+	  <input type="radio" name="visualization" onclick="setTransformMode(this)" value="chromaFeatures" checked="checked"/>Chroma Features
+	</div>
+
+	<div style="float: left; padding-left: 140px;">
+	  <span class="vis-heading">Colour Mapping:</span>
+	  <input type="radio" name="colorMapping" onclick="setColorMappingMode(this)" value="rgb"/>RGB Intensity
+	  <input type="radio" name="colorMapping" onclick="setColorMappingMode(this)" value="hsl" checked="checked"/>HSL Heat
+	</div>
+      </form>
+      
+      <div style="clear: both; padding-top: 4px; padding-bottom: 4px;"><hr/></div>
+
+<!--
+      <form style="padding-left: 8px;">
+	<span class="vis-heading">Colour Mapping:</span>
+	<input type="radio" name="colorMapping" onclick="setColorMappingMode(this)" value="rgb"/>RGB Intensity
+	<input type="radio" name="colorMapping" onclick="setColorMappingMode(this)" value="hsl" checked="checked"/>HSL Heat Map
+      </form>
+      <hr/>
+-->
+
+	<form style="padding-left: 8px; padding-bottom: 0px;">
+	  <span class="vis-heading">On Pause:</span>
+	  <input type="checkbox" name="similarityMatrix" onclick="plotSimilarityMatrixWhenPaused(this)"/>Show Similarity Matrix
+	</form>
+	<hr/>
+
+    </div>
+    
+  </xsl:template>
+
+  <!-- *** -->
+  <!-- * Settings form -->
+  <!-- *** -->
+
+  <xsl:template name="settings-form">
+    <xsl:param name="cgiargYScaleSimImg"/>
+
+    <xsl:variable name="httpCollection">
+      <xsl:value-of select="/page/pageResponse/collection/metadataList/metadata[@name='httpPath']"/>
+    </xsl:variable>
+
+    <div id="settings-turnstyle" style="margin: 6px;">
+      <div style="background-image: none; background-color: rgb(80%,80%,20%);">
+	Audio Content Search
+      </div>
+      <div class="documenttext" style="display: none;">
+
+
+      <form id="QueryForm" name="QueryForm" method="get" action="{$library_name}">
+	<input type="hidden" name="a" value="q"/>
+	<input type="hidden" name="sa"><xsl:attribute name="value"><xsl:value-of select="/page/pageRequest/@subaction"/></xsl:attribute></input>
+	<input type="hidden" name="rt" value="rd"/>
+	
+	<input type="hidden" name="s" value="AudioQuery"/>
+	<input type="hidden" name="c" value="{$collName}"/>
+	<xsl:if test="not(paramList/param[@name='startPage'])">
+	  <input type="hidden" name="startPage" value="1"/>
+	</xsl:if>
+	<xsl:choose>
+	  <xsl:when test="/page/pageRequest/paramList/param[@name = 's1.maxDocs']">
+	    <input type="hidden" name="s1.maxDocs">
+	      <xsl:attribute name="value">
+		<xsl:value-of select="/page/pageRequest/paramList/param[@name = 's1.maxDocs']/@value"/>
+	      </xsl:attribute>
+	    </input>
+	  </xsl:when>
+	  <xsl:otherwise>
+	    <input type="hidden" name="s1.maxDocs" value="100"/>
+	  </xsl:otherwise>
+	</xsl:choose>
+	<xsl:choose>
+	  <xsl:when test="/page/pageRequest/paramList/param[@name = 's1.hitsPerPage']">
+	    <input type="hidden" name="s1.hitsPerPage">
+	      <xsl:attribute name="value">
+		<xsl:value-of select="/page/pageRequest/paramList/param[@name = 's1.hitsPerPage']/@value"/>
+	      </xsl:attribute>
+	    </input>
+	  </xsl:when>
+	  <xsl:otherwise>
+	    <input type="hidden" name="s1.hitsPerPage" value="20"/>
+	  </xsl:otherwise>
+	</xsl:choose>
+	
+	<input type="hidden" name="q">
+	  <xsl:attribute name="value"><xsl:value-of select="/page/pageResponse/document/documentNode/@nodeID"/>.dir</xsl:attribute>
+	</input>
+	
+	
+	<input type="hidden" name="s1.query">
+<!--
+	  <xsl:attribute name="value"><xsl:value-of select="/page/pageResponse/document/documentNode/@nodeID"/>.dir</xsl:attribute>
+-->
+	  <xsl:attribute name="value"><xsl:value-of select="/page/pageResponse/document/@nodeID"/>.dir</xsl:attribute>
+	</input>
+	
+	<input type="hidden" name="s1.offset" value="0" />
+	<input type="hidden" name="s1.length" value="200" />
+	
+	<div style="font-style: italics;">Start new query @ offset
+	<span id="mysongCurrentPos">0 secs</span>,
+	with excerpt lasting
+	
+	<input type="text" name="mysongWindowDuration" size="4" value="6" />
+	<!--
+	    <span id="mysongWindowDuration" class="editable-offset"
+	    style="cursor: pointer; border: 1px solid black; padding: 3px; width: 200px; min-width: 200px;">6.0</span> 
+	-->
+	secs:
+
+	<input type="submit" value="Search" onclick="preSubmit(this.form);" />
+	</div>
+
+	
+	<ul style="font-size: 80%; margin-top: 8px; font-style: italics;" >
+	  <li>Use the <b>Play all of</b> bar to get to the part of the song you are interested in.</li>
+	  <li>... the <b>query @ offset</b> value will change accordingly as the song progresses.</li>
+	  <li>Click <b>pause</b> (anywhere outside of the time-line) to mark the spot you want to start the new music query.</li>
+	  <li>Optionally click on the <b>excerpt lasting</b> value and edit, if you want to change the length of excerpt used in the match.</li>
+	  <li>Finally, click the <b>Search</b> button to initiate the new query.</li>
+	</ul>
+	
+      </form>
+
+      <hr/>
+      
+<!--
+      <form id="RescaleForm" name="RescaleForm" method="get" action="{$library_name}">
+	<div style="font-style: italics;">
+	  Make the scale factor for the y-dimension of the self-similarity
+	  image be
+	  <input type="text" name="ResizeScale" value="{$cgiargYScaleSimImg}"
+	         size="3" /> then 
+	  <input type="button" name="ResizeImage" value="Resize Image" 
+	         onclick="javascript:rescaleImage()" />
+	  
+	</div>
+      </form>
+      
+      <hr/>
+-->
+
+      <!-- **** currently not displayed -->
+
+      <form id="UpdateCAForm" name="UpdateCAForm" method="get" action="{$library_name}" style="display: none;">
+	<div style="font-style: italics;">
+	  
+	  Show the song structure automatically computed by analyzing
+	  the audio data using algorithm 
+
+	  <select id="caaMenu" name="caAlgorithm">
+	    <option value="1">BV1</option>
+	    <option value="2">BV2</option>
+	    <option value="3">GP7</option>
+	    <option value="4">MHRAG2</option>
+	    <option value="5">MND1</option>
+	    <option value="6">WB1</option>
+
+<!--
+	    <option value="-1">or hide</option>
+-->
+
+	  </select>: 
+
+	  <input type="button" name="Reload" value="Reload" 
+	         onclick="updateCAAlgorithm()" />
+
+	</div>
+      </form>
+
+	<script>
+	  <xsl:text disable-output-escaping="yes"> 
+	    if (hasStructuredAudio) {
+	      var caaMenu = document.getElementById("caaMenu");
+               caaMenu.options[caAlgorithm-1].selected = 1;
+	    }
+	  </xsl:text>
+	</script>
+      
+
+      </div>
+    </div>
+    <script>
+      <xsl:text disable-output-escaping="yes">
+	$(function(){
+	transformToTurnstyleBlock("settings");
+	});
+      </xsl:text>
+    </script>
+
+  </xsl:template>
+
+
+  <!-- *** -->
+  <!-- * Computed Data -->
+  <!-- *** -->
+
+
+  <xsl:template name="computed-data">
+    <xsl:param name="httpCollection"/>
+    <xsl:param name="assocFilePath"/>
+
+    <div id="computed-turnstyle" style="margin: 6px;">
+      <div style="background-image: none; background-color: rgb(80%,80%,20%);">
+	Computed Data
+      </div>
+
+      <div class="documenttext" style="display: none;">
+	<table class="metadata-stripes" style="width: 100%">
+	  <tbody>
+	    <tr>
+	      <td>jAudio Features</td><td><a href="{$httpCollection}/index/assoc/{$assocFilePath}/jaudio.xml">download ACE XML feature values file</a></td>
+	    </tr>
+	    
+	    <tr>
+	      <td>jSongMiner Metadata</td><td><a href="{$httpCollection}/index/assoc/{$assocFilePath}/jsongminer.xml">download ACE XML classifications file</a></td>
+	    </tr>
+	    
+	  </tbody>
+	</table>
+      </div>
+    </div>
+
+    <gsf:script>
+	$(function(){
+	  transformToTurnstyleBlock("computed");
+	});
+    </gsf:script>
+
+
+    <div id="original-turnstyle" style="margin: 6px;">
+      <div style="background-image: none; background-color: rgb(80%,80%,20%);">
+	The Original Audio
+      </div>
+
+      <div style="display: none;">
+
+	<div>
+	  <audio style="width: 100%;" id="original-audio" controls="controls" >
+	    <source src="{$httpCollection}/index/assoc/{$assocFilePath}/doc.ogg" />
+	    <source src="{$httpCollection}/index/assoc/{$assocFilePath}/doc.mp3" />
+	    <source src="{$httpCollection}/index/assoc/{$assocFilePath}/doc.wav" />
+	  </audio>
+	</div>
+
+      </div>
+    </div>
+
+    <gsf:script>
+	$(function(){
+	  transformToTurnstyleBlock("original");
+	});
+    </gsf:script>
+
+
+  </xsl:template>
+
+</xsl:stylesheet>
Index: /main/trunk/model-sites-dev/multimodal-mdl/collect/salami-ground-truth/REBUILD.sh
===================================================================
--- /main/trunk/model-sites-dev/multimodal-mdl/collect/salami-ground-truth/REBUILD.sh	(revision 28433)
+++ /main/trunk/model-sites-dev/multimodal-mdl/collect/salami-ground-truth/REBUILD.sh	(revision 28433)
@@ -0,0 +1,1 @@
+full-rebuild.pl  -site localsite -removeold -import:OIDtype incremental my-ipod
Index: /main/trunk/model-sites-dev/multimodal-mdl/collect/salami-ground-truth/etc/collectionConfig.xml
===================================================================
--- /main/trunk/model-sites-dev/multimodal-mdl/collect/salami-ground-truth/etc/collectionConfig.xml	(revision 28433)
+++ /main/trunk/model-sites-dev/multimodal-mdl/collect/salami-ground-truth/etc/collectionConfig.xml	(revision 28433)
@@ -0,0 +1,747 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<CollectionConfig xmlns:gsf="http://www.greenstone.org/greenstone3/schema/ConfigFormat" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+  <metadataList>
+    <metadata name="creator"></metadata>
+    <metadata name="maintainer"></metadata>
+    <metadata name="public">true</metadata>
+  </metadataList>
+  <displayItemList>
+    <displayItem assigned="true" lang="en" name="name">Redefining Boundaries</displayItem>
+    <displayItem assigned="true" lang="en" name="description"></displayItem>
+  </displayItemList>
+  <!-- Global format statement -->
+  <format>
+    <gsf:template name="choose-title">
+      
+      <gsf:choose-metadata>
+	<gsf:metadata name="dc.Title"/>
+	<gsf:metadata name="exp.Title"/>
+	<gsf:metadata name="ex.dc.Title"/>
+	<gsf:metadata name="ex.Title"/>
+	<gsf:metadata name="Title"/>
+	<gsf:default>Untitled</gsf:default>
+      </gsf:choose-metadata>
+      
+      <gsf:switch>
+	<gsf:metadata name='dc.Creator'/>
+	<gsf:when test='exists'>
+	  
+	  <gsf:switch>
+	    <gsf:metadata name="dc.Creator"/>
+	    <gsf:when test="notEquals" test-value="Unknown">
+	      
+	      by <i><gsf:metadata name='dc.Creator'/></i>
+	    </gsf:when>
+	  </gsf:switch>
+	  
+	</gsf:when>
+      </gsf:switch>			
+    </gsf:template>    
+  </format>
+
+  <search type="mgpp">
+    <level name="document">
+      <displayItem lang="en" name="name">document</displayItem>
+    </level>
+    <level name="section">
+      <displayItem lang="en" name="name">section</displayItem>
+    </level>
+    <defaultLevel name="document"/>
+    <index name="text">
+      <displayItem lang="en" name="name">text</displayItem>
+    </index>
+    <index name="dc.Title,ex.dc.Title,Title">
+			<displayItem lang="en" name="name">titles</displayItem>
+    </index>
+    <index name="Source">
+      <displayItem lang="en" name="name">filenames</displayItem>
+    </index>
+    <defaultIndex name="text"/>
+    <searchType name="plain"/>
+    <searchType name="simpleform"/>
+    <searchType name="advancedform"/>
+
+    
+    <!-- Search Format Statement -->
+    <format>
+      <gsf:template match="documentNode">
+
+	<gsf:variable name="cgiargFrameLength">
+	  <xsl:value-of select="/page/pageRequest/paramList/param[@name='p.frameLength']/@value"/>
+	</gsf:variable>
+
+	<xsl:variable name="cgiargYScaleSimImg"><xsl:choose>
+	  <xsl:when test="/page/pageRequest/paramList/param[@name='p.yScaleSimImg']/@value != ''"><xsl:value-of select="/page/pageRequest/paramList/param[@name='p.yScaleSimImg']/@value"/></xsl:when>
+	  <xsl:otherwise>0.5</xsl:otherwise>
+	</xsl:choose>
+	</xsl:variable>
+
+	<td valign="top">
+	  <gsf:icon type="document"/>
+	</td>
+	<td>
+	  <xsl:choose>
+	    <xsl:when test="@rank != 'NaN'">
+  	      (<script>
+	        var rank=<xsl:value-of select="@rank"/>;
+	        var perc=(rank-0.9)*100*10;
+	        document.write(perc.toFixed(1));
+	       </script>%) 
+	    </xsl:when>
+	  </xsl:choose>
+	  
+	  <xsl:choose>
+	    <xsl:when test="/page/pageResponse/service[@name='AudioQuery']">
+  	      <a>
+	        <xsl:attribute name="href"><xsl:value-of select="$library_name"/>/collection/<xsl:value-of select="/page/pageResponse/collection/@name"/>/document/<xsl:value-of select="@nodeID"/>?p.frameOffset=<xsl:value-of select="@frameOffset"/>&amp;p.frameLength=<xsl:value-of select="/page/pageRequest/paramList/param[@name='s1.length']/@value"/>&amp;p.a=q&amp;p.s=<xsl:value-of select="/page/pageResponse/service/@name"/>&amp;p.yScaleSimImg=<xsl:value-of select="$cgiargYScaleSimImg"/>
+
+	        </xsl:attribute>
+		
+                <xsl:call-template name="choose-title"/>
+	      </a>
+	    </xsl:when>
+	    <xsl:otherwise>
+	      <gsf:link>
+                <xsl:call-template name="choose-title"/>
+	      </gsf:link>
+	    </xsl:otherwise>
+	  </xsl:choose>
+	  
+	  <gsf:switch>
+	    <gsf:metadata name="artist"/>
+	    <gsf:when test="exists">
+	      by <gsf:metadata name="artist"/>
+	    </gsf:when>
+	  </gsf:switch>
+
+	  <gsf:switch>
+	    <gsf:metadata name="js.LabelledStructure"/>
+	    <gsf:when test="exists">
+	      <br/><i style="font-size: 80%">(Labelled structure: <gsf:metadata name="js.LabelledStructure"/>)</i>
+	    </gsf:when>
+	  </gsf:switch>
+	  
+	</td>
+      </gsf:template>
+    </format>
+
+  </search>
+
+  <search type="audioDB" orthogonal="true" />
+  
+  <infodb type="jdbm"/>
+
+  <import>
+    <pluginList>
+      <plugin name="ZIPPlugin"/>
+      <plugin name="GreenstoneXMLPlugin"/>
+      <plugin name="EmbeddedMetadataPlugin"/>
+      
+      <plugin name="AudioDBPlugin">
+	<option name="-compute_fft_features" value="true"/>
+	<option name="-enable_streaming" value="mp3"/>
+	<option name="-compute_mir_features" value="true"/>
+	<option name="-retrieve_mir_metadata" value="true"/>
+	<option name="-enable_cache"/>
+      </plugin>
+      
+      <plugin name="TextPlugin"/>
+      <plugin name="HTMLPlugin"/>
+      <plugin name="EmailPlugin"/>
+      <plugin name="PDFPlugin"/>
+      <plugin name="RTFPlugin"/>
+      <plugin name="WordPlugin"/>
+      <plugin name="PostScriptPlugin"/>
+      <plugin name="PowerPointPlugin"/>
+      <plugin name="ExcelPlugin"/>
+      <plugin name="ImagePlugin"/>
+      <plugin name="ISISPlugin"/>
+      <plugin name="NulPlugin"/>
+      <plugin name="OAIPlugin"/>
+      <plugin name="MetadataXMLPlugin"/>
+      <plugin name="ArchivesInfPlugin"/>
+      <plugin name="DirectoryPlugin"/>
+    </pluginList>
+  </import>
+
+  <browse>
+    <classifier name="AZCompactList">
+      <option name="-metadata" value="dc.Title;ex.dc.Title;Title"/>
+      <option name="-mingroup" value="2"/>
+      <option name="-removeprefix" value="(?i)Le|La|Les|The|A\\s+"/>
+    </classifier>
+
+    <classifier name="AZCompactList">
+      <option name="-metadata" value="dc.Creator"/>
+      <option name="-buttonname" value="Artists"/>
+      <option name="-mingroup" value="1"/>
+      <option name="-minnesting" value="40"/>
+    </classifier>
+
+    <classifier name="AZCompactList">
+      <option name="-metadata" value="dc.Title.albumtitle"/>
+      <option name="-buttonname" value="Albums"/>
+      <option name="-mingroup" value="1"/>
+      <option name="-minnesting" value="40"/>
+    </classifier>
+
+
+    <!--
+
+    <classifier name="List">
+      <option name="-metadata" value="dc.Title;Title"/>
+      <option name="-partition_type_within_level" value="approximate_size"/>
+    </classifier>
+    <classifier name="List">
+      <option name="-metadata" value="dc.Creator"/>
+      <option name="-button_name" value="Artists"/>
+      <option name="-partition_type_within_level" value="approximate_size"/>
+    </classifier>
+		
+    -->
+
+    <format>
+      <gsf:template match="documentNode">
+	<td valign="top">
+	  <gsf:link type="document">
+	    <gsf:icon type="document"/>
+	  </gsf:link>
+	</td>
+	<td valign="top">
+	  <gsf:link type="source">
+	    <gsf:choose-metadata>
+	      <gsf:metadata name="thumbicon"/>
+	      <gsf:metadata name="srcicon"/>
+	    </gsf:choose-metadata>
+	  </gsf:link>
+	</td>
+	<td valign="top">
+	  <gsf:link type="document">
+	    <!-- Defined in the global format statement -->
+	    <xsl:call-template name="choose-title"/>
+	    
+	    <gsf:switch>
+	      <gsf:metadata name="dc.Title" />
+	      <gsf:when test="equals" test-value="Unknown">
+		<br/><i>(<gsf:metadata name="Source"/>)</i>
+	      </gsf:when>
+	    </gsf:switch>
+	    
+	  </gsf:link>
+	</td>
+      </gsf:template>
+      
+      <gsf:template match="classifierNode[@classifierStyle = 'VList']">
+	<td valign="top">
+	  <gsf:link type="classifier">
+	    <gsf:icon type="classifier"/>
+	  </gsf:link>
+	</td>
+	<td valign="top">
+	  <gsf:link type="source">
+	    <gsf:choose-metadata>
+	      <gsf:metadata name="thumbicon"/>
+	      <gsf:metadata name="srcicon"/>
+	    </gsf:choose-metadata>
+	  </gsf:link>
+	</td>
+	<td valign="top">
+	  <!-- Defined in the global format statement -->
+	  <xsl:call-template name="choose-title"/>
+	  <gsf:switch>
+	    <gsf:metadata name="Source"/>
+	    <gsf:when test="exists"><br/><i>(<gsf:metadata name="Source"/>)</i></gsf:when>
+	  </gsf:switch>
+	</td>
+      </gsf:template>
+      <gsf:template match="classifierNode[@classifierStyle = 'HList']">
+	<gsf:link type="classifier">
+	  <gsf:metadata name="Title"/>
+	</gsf:link>
+      </gsf:template>
+    </format>
+  </browse>
+
+  <display>
+    <format>
+      <gsf:option name="TOC" value="false"/>
+
+      <!-- 
+	   Overwriting this template allows you to change the heading of the document.
+      -->
+      <gsf:template name="documentHeading">
+	
+	<xsl:variable name="httpCollection">
+	  <xsl:value-of select="/page/pageResponse/collection/metadataList/metadata[@name='httpPath']"/>
+	</xsl:variable>
+
+	<!-- Metadata derived from finger-printing --> 
+	
+	<xsl:call-template name="discovery-block">
+	  <xsl:with-param name="httpCollection" select="$httpCollection"/>
+	</xsl:call-template>
+
+      </gsf:template>
+
+      
+      <!-- 
+	   Overwriting this template can be used to redefine the content of the whole document. 
+	   This is useful for simple documents, but not recommended for more complex documents
+	   (e.g. hierachical and paged documents) as it can prevent any sub-sections from showing.
+      -->
+      <!-- 
+	   <gsf:template name="documentContent">
+	   <xsl:call-template name="wrappedSectionImage"/>
+	   <xsl:call-template name="wrappedSectionText"/>
+	   </gsf:template>
+      -->
+
+      <!--
+	  Overwriting this template can be used to change the content of section headings.
+      -->
+      <!--
+	  <gsf:template name="sectionHeading">
+	  <xsl:call-template name="choose-title"/>
+	  </gsf:template>
+      -->
+      
+      <!--
+	  Overwriting this template can be used to change the content of the top-level section.
+      -->
+      <!--
+	  <gsf:template name="topLevelSectionContent">
+	  <xsl:call-template name="wrappedSectionImage"/>
+	  <xsl:call-template name="wrappedSectionText"/>
+	  </gsf:template>
+      -->
+      
+      <!--
+	  Overwriting this template can be used to change the content of sections.
+      -->
+
+      <!--
+	  <gsf:template name="sectionContent">
+	  <xsl:call-template name="wrappedSectionImage"/>
+	  <xsl:call-template name="wrappedSectionText"/>
+	  </gsf:template>
+      -->
+      	
+      <xsl:template name="additionalHeaderContent">
+	
+
+	<xsl:call-template name="soundmanager2-header"/>
+	<xsl:call-template name="js-mad-header"/>
+	
+	<!-- Bespoke jquery-ui extension for turnstyle open/close blocks -->
+	<gsf:style  src="ext/jquery-ui-extra/turnstyle-block.css"/>
+	<gsf:script src="ext/jquery-ui-extra/turnstyle-block.js"/>
+	
+	<!-- The Javascript DSP files for computing chroma features in the browser -->
+	<xsl:call-template name="javascript-dsp-header"/>
+	
+
+	<!-- Javascript support for running, sending input into, monitoring, and stopping Meandre flows -->
+	<gsf:script src="ext/meandre/meandre-controller.js"/>
+
+	<gsf:style>
+	  .metadata-stripes td { padding: 4px; }
+	  .metadata-stripes tr:nth-child(odd)  {background: #CCC}
+	  .metadata-stripes tr:nth-child(even) {background: #FFF}      
+	  
+	  .vis-heading  { font-style:italic; }
+
+	  #rightSidebar { display: none; }
+	</gsf:style>
+	
+      </xsl:template>
+
+
+      <xsl:template name="documentContent">
+	
+<!--
+	<xsl:call-template name="init-document-xsl-vars"/>
+-->	
+
+	<!-- declare $httpCollection = $httpPath (for better consistency with other places in Greenstone XSL files) -->
+	<xsl:variable name="httpCollection">
+	  <xsl:value-of select="/page/pageResponse/collection/metadataList/metadata[@name='httpPath']"/>
+	</xsl:variable>
+
+	<xsl:variable name="assocFilePath"><gsf:metadata name="assocfilepath" select="root"/></xsl:variable>
+	<xsl:variable name="Source"><gsf:metadata name="Source" select="root"/></xsl:variable>
+
+	<gsf:variable name="cgiargFrameOffset">
+	  <xsl:value-of select="/page/pageRequest/paramList/param[@name='p.frameOffset']/@value"/>
+	</gsf:variable>
+
+	<gsf:variable name="cgiargFrameLength">
+	  <xsl:value-of select="/page/pageRequest/paramList/param[@name='p.frameLength']/@value"/>
+	</gsf:variable>
+
+	<xsl:variable name="cgiargYScaleSimImg"><xsl:choose>
+	  <xsl:when test="/page/pageRequest/paramList/param[@name='p.yScaleSimImg']/@value != ''"><xsl:value-of select="/page/pageRequest/paramList/param[@name='p.yScaleSimImg']/@value"/></xsl:when>
+	  <xsl:otherwise>0.5</xsl:otherwise>
+	</xsl:choose>
+	</xsl:variable>
+	
+	<!-- CAA = Content Analysis Algorithm -->
+	<xsl:variable name="cgiargCAAlgorithm">
+	  <xsl:choose>
+	    <xsl:when test="/page/pageRequest/paramList/param[@name='p.caAlgorithm']/@value != ''"><xsl:value-of select="/page/pageRequest/paramList/param[@name='p.caAlgorithm']/@value"/></xsl:when>
+	    <xsl:otherwise>1</xsl:otherwise>
+	  </xsl:choose>
+	</xsl:variable>
+
+	<!-- *** -->
+	<!-- Main Audio Player -->
+	<!-- *** -->
+
+	<div class="documenttext"> 
+	  
+	  <xsl:call-template name="audio-icon-cache"/>
+
+	  <ul class="playlist">
+	    <li class="rounded" >
+	      
+	      <gsf:script src="{$httpCollection}/script2/hybrid-audio-player.js"/>
+
+
+	      <a id="mysong" style="padding-bottom: 2px;"
+		 onclick="togglePlayVisual(document.getElementById('mainPlayButton'))"
+		 href="{$httpCollection}/index/assoc/{$assocFilePath}/doc.mp3">
+		<span>
+		  <img id="mainPlayButton" src="ext/diy-audio-player/images/play32.png" 
+		       width="32"
+		       height="32"  
+		       onmouseover="playHighlightOn(this)"
+		       onmouseout="playHighlightOff(this)"
+		       onclick="var event = arguments[0] || window.event; togglePlay(event,this)"
+		       style="vertical-align: middle;"/>
+		  Play/Pause
+		  <span id="extraPlayText"></span>
+		</span>    
+	      </a>
+	      
+	      <gsf:script src="ext/diy-audio-player/script/audioDB-play.js"/>
+
+	      <xsl:choose>
+		<xsl:when test="($cgiargFrameOffset != '-1') and ($cgiargFrameOffset != '')">
+		  
+		  <div style="background-color: rgb(40%,40%,20%)">
+		    <script type="text/javascript">
+		      <xsl:text disable-output-escaping="yes">
+
+			var frameOffsetStr=gs.variables.cgiargFrameOffset;
+			var frameLength=gs.variables.cgiargFrameLength;
+
+		      </xsl:text>
+		    </script>
+
+
+		    <svg xmlns="http://www.w3.org/2000/svg" 
+			 version="1.1"
+			 id="svgAudioDBSegments" 
+			 width="100%" height="24"
+			 onLoadXX="svgAudioDBInit()">
+		    </svg>
+		  </div>
+		</xsl:when>
+	      </xsl:choose>
+	      
+	      <xsl:call-template name="structuredAudioPlayerBlock"/>
+	      
+	      <xsl:call-template name="processingPopup"/>
+	      
+	      
+	      <div style="width: 100%; display: none;" id="doublePlay">
+		
+		<script type="text/javascript">
+		  <xsl:text disable-output-escaping="yes">
+		    
+		    // At time of writing this code, this needs to be an OGG file to work in Firefox
+		    var source = "</xsl:text><gsf:metadata name="Source" select="root"/><xsl:text disable-output-escaping="yes">";
+		    
+		    var self_sim_png = source.replace(/\.(ogg|mp3|wav)$/,".png");
+		    var collect = "</xsl:text><xsl:value-of select="/page/pageResponse/collection/@name"/><xsl:text disable-output-escaping="yes">";
+
+		  </xsl:text>
+		</script>
+
+		<gsf:script src="ext/diy-audio-player/script/similarity-matrix-play.js"/>
+
+		<audio style="width: 49%;" id="leftsong" controls="controls" >
+		  <source src="{$httpCollection}/index/assoc/{$assocFilePath}/doc.ogg" />
+		  <source src="{$httpCollection}/index/assoc/{$assocFilePath}/doc.mp3" />
+		  <source src="{$httpCollection}/index/assoc/{$assocFilePath}/doc.wav" />
+		</audio>
+		<audio style="width: 49%;" id="rightsong" controls="controls" >
+		  <source src="{$httpCollection}/index/assoc/{$assocFilePath}/doc.ogg" />
+		  <source src="{$httpCollection}/index/assoc/{$assocFilePath}/doc.mp3" />
+		  <source src="{$httpCollection}/index/assoc/{$assocFilePath}/doc.wav" />
+		</audio>
+	      </div>
+
+
+	      <!-- Real Time Analysis (RTA) audio -->
+	      <div style="width: 100%;">		
+		<audio id="rta-audio-element" style="width: 100%;">
+		  <source src="{$httpCollection}/index/assoc/{$assocFilePath}/doc.ogg"/>
+		  <source src="{$httpCollection}/index/assoc/{$assocFilePath}/doc.mp3"/>
+		  <source src="{$httpCollection}/index/assoc/{$assocFilePath}/doc.wav"/>
+		</audio>
+	      </div>
+	      
+	      <xsl:call-template name="workflow-block"/>
+
+	      <div id="controlMarker"/>
+
+	      <div id="svg-canvas-overlay" style="position: relative">
+      
+		<!-- drawing canvas -->
+		<div style="width: 100%; position: absolute; left: 0px; top: 0px;">
+		  <div style="position: relative">
+		    <div>
+		      <!-- **** better if 100% width, but issue with JS reading these values ??? -->
+		      <canvas id="freq-plot" 
+			      width="941" height="494" style="background-color: #cccccc;"></canvas>
+		    </div>
+		  </div>
+		</div>
+
+		<div style="width: 100%; position: absolute; left: 0px; top: 0px;">
+		  <div style="position: relative">
+		    <div>
+		      <!-- **** better if 100% width, but issue with JS reading these values ??? -->
+		      <canvas id="freq-plot-labels" 
+			      width="941" height="494" style="background-color: transparent"></canvas>
+		    </div>
+		  </div>
+		</div>
+
+		<!-- left/right-mix circle cursor -->
+		<div style="background-color: transparent; position: relative; left: 0px; top: 0px;">
+		  <svg xmlns="http://www.w3.org/2000/svg" 
+		       xmlns:xlink="http://www.w3.org/1999/xlink" 
+		       version="1.1"
+		       id="svgSimilarityPlay" 
+		       width="100%"
+		       onLoad="svgInitSimilarityPlay()">
+		    <g id="simPlayLineGroup" transform="scale(1.0,{$cgiargYScaleSimImg})">
+		      <!-- image loaded here, with yScaleSimImg applied to group -->
+		    </g>
+		    <g id="playtracker" transform="translate(0,0)" 
+		       onclick="dualPlay(evt)"
+		       onmousemove="playTrackerMove(evt)"
+		       onmouseout="playTrackerOff(evt)"
+		       style="visibility: hidden">
+		      <circle cx="0" cy="0" r="20"
+			      stroke="black" stroke-width="1" fill="rgba(100%,100%,50%,0.7)" />
+		      <circle cx="0" cy="0" r="1"
+			      stroke="black" stroke-width="1" fill="black" />
+		      <g transform="translate(-15,-15)" style="visibility: hidden;">
+			<image id="playtrackerBusy" 
+			       width="30" height="30"
+			       xlink:href="ext/diy-audio-player/images/wait30trans.gif" />
+		      </g>
+		      
+		      <g>
+			<g transform="rotate(-90)">
+			  <g transform="translate(-20,-25)">
+			    <text id="rightTime" style="font-size: 80%;">L: secs</text>
+			  </g>
+			</g>
+			<g transform="translate(-20,30)">
+			  <text id="leftTime" style="font-size: 80%;">R: secs</text>
+			</g>
+		      </g>
+		      
+		    </g>
+		  </svg>
+		</div>
+		
+
+	      </div><!-- end of svg-canvas-overly-->
+
+	      <xsl:call-template name="visualization-mode-block"/>
+
+	    </li>
+	  </ul>
+	  
+	  <hr/>
+
+	  <xsl:call-template name="settings-form">
+	    <xsl:with-param name="cgiargYScaleSimImg" select="$cgiargYScaleSimImg"/>
+	  </xsl:call-template>
+	  
+	  <xsl:call-template name="computed-data">
+	    <xsl:with-param name="httpCollection" select="$httpCollection"/>
+	    <xsl:with-param name="assocFilePath" select="$assocFilePath"/>
+	  </xsl:call-template>
+
+
+	  <hr/>
+
+<script>
+  <xsl:text disable-output-escaping="yes">
+    useFancyPlayer = 1;
+
+    /* if (window.location.toString().match(/fancyplayer/i)) { */
+    if (useFancyPlayer) { 
+      PP_CONFIG.usePeakData = true;
+      PP_CONFIG.useEQData = true;
+      // PP_CONFIG.useFavIcon = true;
+    }
+
+    function onFinishSP()
+    {   
+      soundManager._onfinish(); 
+      togglePlayVisual(mainPlayButton); 
+    }
+
+      var mySoundObj;
+
+    function playFromOffset(id,frameOffset) 
+    {
+      var msecOffset = 250 * frameOffset; 
+      idElem = document.getElementById(id);
+      pagePlayer.handleClick({target:idElem}); /* fake a click */
+      soundManager.stopAll();
+
+      var options = {};
+      options.position = msecOffset;
+
+      soundManager.play(id,options);
+
+      togglePlayMode = "pause";
+      playHighlightOff(document.getElementById("mainPlayButton"),32);
+    }
+
+    function preSubmit(form) 
+    {
+      var currentPosElem = document.getElementById("mysongCurrentPos");
+      var offsetInMSecs = currentPosElem.getAttribute("offsetInMSecs");
+      var frameOffset = Math.round(offsetInMSecs/250.0);
+      form.elements["s1.offset"].value = frameOffset;
+
+      //var lengthInSecs = document.getElementById("mysongWindowDuration").innerHTML;
+      var lengthInSecs = form.elements["mysongWindowDuration"].value;
+
+      var frameLength = Math.round(lengthInSecs*1000/250.0);
+      form.elements["s1.length"].value = frameLength;
+
+      return true;
+    }
+
+    function searchSubmit(frameOffset) 
+    {
+      var form = document.getElementById("QueryForm");
+
+      form.elements["s1.offset"].value = frameOffset;
+
+      //var lengthInSecs = document.getElementById("mysongWindowDuration").innerHTML;
+      var lengthInSecs = form.elements["mysongWindowDuration"].value;
+
+      var frameLength = Math.round(lengthInSecs*1000/250.0);
+      form.elements["s1.length"].value = frameLength;
+
+      form.submit();
+    }
+
+
+
+    function rescaleImage() 
+    {
+      var form = document.getElementById("RescaleForm");
+
+      var rescaleSize = form.elements["ResizeScale"].value;
+
+      var currentURL = document.location.toString();
+      var newURL;
+      if (currentURL.match(/p.yScaleSimImg=(\d+(?:\.\d+))/)) {
+        newURL = currentURL.replace(/p.yScaleSimImg=(\d+(?:\.\d+))/,"p.yScaleSimImg="+rescaleSize);
+      }
+      else {
+        var urlParts = currentURL.split("#");
+	newURL = urlParts.shift();
+        newURL += "&amp;p.yScaleSimImg="+rescaleSize;
+	newURL += "#" + urlParts.join("#");
+      }
+
+      document.location = newURL;
+    }
+
+    function updateCAAlgorithm()
+    {
+
+      var form = document.getElementById("UpdateCAForm");
+
+      var caaMenu = form.elements["caAlgorithm"];
+
+      var caIndexPos = caaMenu.options[caaMenu.selectedIndex].value
+
+      var currentURL = document.location.toString();
+      var newURL;
+      if (currentURL.match(/p.caAlgorithm=(\d+)/)) {
+        newURL = currentURL.replace(/p.caAlgorithm=(\d+)/,"p.caAlgorithm="+caIndexPos);
+      }
+      else {
+        var urlParts = currentURL.split("#");
+	newURL = urlParts.shift();
+        newURL += "&amp;p.caAlgorithm="+caIndexPos;
+	newURL += "#" + urlParts.join("#");
+      }
+
+      document.location = newURL;
+
+    }
+
+
+
+  </xsl:text>
+
+</script>
+
+
+    </div>
+  </xsl:template>
+
+
+
+
+    </format>
+  </display>
+
+  <replaceListRef id="gs2-standard"/>
+  <replaceListRef id="gs2-image" />
+  <serviceRackList>
+    <!-- comment out the following serviceRack if you want to disable OAI for this collection -->
+    <serviceRack name="OAIPMH">
+      <ListMetadataFormats>
+	<!--What metadata sets to support is collection specific. To support other metadata schema, simply add a metadataFormat element here.
+	    The support of unqualified Dublin Core metadata set is mandatory in the oai specification.
+	-->
+	<metadataFormat metadataPrefix="oai_dc">
+	  <metadataPrefix>oai_dc</metadataPrefix>
+	  <schema>http://www.openarchives.org/OAI/2.0/oai_dc.xsd</schema>
+	  <metadataNamespace>http://www.openarchives.org/OAI/2.0/oai_dc/</metadataNamespace>
+	  <!--<metadataElements>dc.Title,dc.Creator,dc.Subject,dc.Description,dc.Publisher,dc.Contributor,dc.Date,dc.Type,dc.Format,dc.Identifier,dc.Source,dc.Language,dc.Relation,dc.Coverage,dc.Rights</metadataElements>-->
+	  <mappingList>
+	    <!-- 
+		 The mapping is in the form: <publicly supported metadata name>,<mapped metadata name>, short as <A>,<B> 
+		 The first metadata name is medatory; if there is no mapped name followed, then the first name must be used by the records and
+		 searchable in the database, otherwise it is the mapped name stored in the database. The number of mapping elements matches the
+		 number of external metadata of the records. If only one name is present, the returned metadata will use this name plus the retrieved value;
+		 if both <A>,<B> are present, the returned metadata will use <A>'s name plus <B>'s value retrieved from database.
+		 
+		 **Bear in mind: if this mapping list is not present, the standard dc. metadata names (15 in total) will be used to retrieve metadata in the database.
+		 
+		 **The only case when this mapping is not present is that: 1. this metadata format is oai_dc; 2. the metadata is also stored in the database by Dublin Core's names.
+	    -->
+	    <mapping>dc:title,Title</mapping>
+	    <!-- This mapping example means that the dc.Title is requested and the value of the metadata Title, which is used in this repository, is returned as response. -->
+	  </mappingList>
+	</metadataFormat>
+      </ListMetadataFormats>
+    </serviceRack> 
+  </serviceRackList>
+</CollectionConfig>
Index: /main/trunk/model-sites-dev/multimodal-mdl/collect/salami-ground-truth/script2/browser-detect.js
===================================================================
--- /main/trunk/model-sites-dev/multimodal-mdl/collect/salami-ground-truth/script2/browser-detect.js	(revision 28433)
+++ /main/trunk/model-sites-dev/multimodal-mdl/collect/salami-ground-truth/script2/browser-detect.js	(revision 28433)
@@ -0,0 +1,117 @@
+var BrowserDetect = {
+	init: function () {
+		this.browser = this.searchString(this.dataBrowser) || "An unknown browser";
+		this.version = this.searchVersion(navigator.userAgent)
+			|| this.searchVersion(navigator.appVersion)
+			|| "an unknown version";
+		this.OS = this.searchString(this.dataOS) || "an unknown OS";
+	},
+	searchString: function (data) {
+		for (var i=0;i<data.length;i++)	{
+			var dataString = data[i].string;
+			var dataProp = data[i].prop;
+			this.versionSearchString = data[i].versionSearch || data[i].identity;
+			if (dataString) {
+				if (dataString.indexOf(data[i].subString) != -1)
+					return data[i].identity;
+			}
+			else if (dataProp)
+				return data[i].identity;
+		}
+	},
+	searchVersion: function (dataString) {
+		var index = dataString.indexOf(this.versionSearchString);
+		if (index == -1) return;
+		return parseFloat(dataString.substring(index+this.versionSearchString.length+1));
+	},
+	dataBrowser: [
+		{
+			string: navigator.userAgent,
+			subString: "Chrome",
+			identity: "Chrome"
+		},
+		{ 	string: navigator.userAgent,
+			subString: "OmniWeb",
+			versionSearch: "OmniWeb/",
+			identity: "OmniWeb"
+		},
+		{
+			string: navigator.vendor,
+			subString: "Apple",
+			identity: "Safari",
+			versionSearch: "Version"
+		},
+		{
+			prop: window.opera,
+			identity: "Opera",
+			versionSearch: "Version"
+		},
+		{
+			string: navigator.vendor,
+			subString: "iCab",
+			identity: "iCab"
+		},
+		{
+			string: navigator.vendor,
+			subString: "KDE",
+			identity: "Konqueror"
+		},
+		{
+			string: navigator.userAgent,
+			subString: "Firefox",
+			identity: "Firefox"
+		},
+		{
+			string: navigator.vendor,
+			subString: "Camino",
+			identity: "Camino"
+		},
+		{		// for newer Netscapes (6+)
+			string: navigator.userAgent,
+			subString: "Netscape",
+			identity: "Netscape"
+		},
+		{
+			string: navigator.userAgent,
+			subString: "MSIE",
+			identity: "Explorer",
+			versionSearch: "MSIE"
+		},
+		{
+			string: navigator.userAgent,
+			subString: "Gecko",
+			identity: "Mozilla",
+			versionSearch: "rv"
+		},
+		{ 		// for older Netscapes (4-)
+			string: navigator.userAgent,
+			subString: "Mozilla",
+			identity: "Netscape",
+			versionSearch: "Mozilla"
+		}
+	],
+	dataOS : [
+		{
+			string: navigator.platform,
+			subString: "Win",
+			identity: "Windows"
+		},
+		{
+			string: navigator.platform,
+			subString: "Mac",
+			identity: "Mac"
+		},
+		{
+			   string: navigator.userAgent,
+			   subString: "iPhone",
+			   identity: "iPhone/iPod"
+	    },
+		{
+			string: navigator.platform,
+			subString: "Linux",
+			identity: "Linux"
+		}
+	]
+
+};
+BrowserDetect.init();
Index: /main/trunk/model-sites-dev/multimodal-mdl/collect/salami-ground-truth/script2/hybrid-audio-player.js
===================================================================
--- /main/trunk/model-sites-dev/multimodal-mdl/collect/salami-ground-truth/script2/hybrid-audio-player.js	(revision 28433)
+++ /main/trunk/model-sites-dev/multimodal-mdl/collect/salami-ground-truth/script2/hybrid-audio-player.js	(revision 28433)
@@ -0,0 +1,215 @@
+
+Element.prototype.getElementWidth = function() {
+    if (typeof this.clip !== "undefined") {
+	return this.clip.width;
+    } else {
+	if (this.style.pixelWidth) {
+	    return this.style.pixelWidth;
+	} else {
+	    return this.offsetWidth;
+	}
+    }
+};
+
+Element.prototype.getElementHeight = function() {
+    if (typeof this.clip !== "undefined") {
+	return this.clip.height;
+    } else {
+	if (this.style.pixelHeight) {
+	    return this.style.pixelHeight;
+	} else {
+	    return this.offsetHeight;
+	}
+    }
+};
+
+
+function isDefined(v) {
+    return typeof v !== "undefined";
+}
+
+/* // ***** */
+/* Move above in to more general header file */
+
+
+// Useful shorthands
+var SVG_NS ="http://www.w3.org/2000/svg";
+var XLINK_NS = "http://www.w3.org/1999/xlink";
+
+
+var hasStructuredAudio  = false;
+var hasChromaSelfSimMap = false;
+
+var allData      = null;
+var yScaleSimImg = null;
+var caAlgorithm  = null;
+var duration     = null;
+
+var webAudioContext = null;
+//var webAudioSource = null;
+//var webAudioJSProcessor = null;
+
+if (typeof AudioContext == "function") {
+    webAudioContext = new AudioContext();
+} else if (typeof webkitAudioContext == "function") {
+    webAudioContext = new webkitAudioContext();
+}
+
+
+// ******
+// * Frequency Player/Plotter part of Hybrid Player
+// ******
+
+function freqPlayerAudioPlay(event)
+{
+    console.info("Audio play pressed");
+
+    if (audioMode == "stopped") {
+	// Nolonger used (Firefox fails to fire this event on a fresh 'play' once an existing play has finished)
+
+	// take a fresh snapshot of the transform mode selected in the web page
+
+	//var transformMode = $('input:radio[name=visualization]:checked').val();
+	//chromaTransform.setTransformMode(transformMode);
+
+    }
+    audioMode = "playing";
+}
+
+function freqPlayerAudioPause()
+{
+    console.info("Audio pause pressed");
+    audioMode = "paused";
+
+    // if stoping dualPlay
+    leftSong.pause();
+    rightSong.pause();
+    baseSong.volume = 1.0;
+
+}
+
+function freqPlayerAudioEnded()
+{
+    console.info("Audio play/playlist ended");
+
+    audioMode = "stopped";
+    needsRefresh = true;
+
+    //console.log("reset freq plot called");
+    //frequencyPlotter.reset();
+
+}
+
+// ******
+// * Meandre (server-side) workflow part of Hybrid Player
+// ******
+//
+// Started when 'play' is pressed
+
+// (workflows now in their own folder '$httpCollection/script/meandre-workflow/*.js)
+// the global variable 'meandreWorkflows' stores which flows are available
+
+
+
+
+
+// ******
+// * Structured Audio (CAA) part of Hybrid Player
+// ******
+
+function caaInit() 
+{
+    // duration information is now available
+    var audio = document.getElementById('rta-audio-element');
+    duration = audio.duration;
+    
+    if (!isDefined(allData)) {
+	// degenerate case
+	
+	var ground_truth = []; // empty ground truth
+	
+	var numSegs = 4;
+	var gap = duration/numSegs;
+	
+	var label = [ "a", "b" ];
+	var val   = [ 0, 1];
+	
+	var equal_spacing = [];
+	for (var i=0; i<numSegs; i++) {
+	    equal_spacing.push( {o: i*gap, f: i*gap+gap, l: label[i%2], a: val[i%2] } );
+	}
+
+	allData = [ ground_truth, equal_spacing ]; 
+
+	caAlgorithm = 1;
+	hasStructuredAudio = true;
+    }
+
+    svgGTStructuredInit();
+    svgCAStructuredInit(caAlgorithm);
+    svgAudioDBInit();
+}
+
+
+allData = gs.documentMetadata["json.data"];
+
+// ****
+
+// The following is actually the XSLT page param
+// 'p.yScaleSimImg;, which presumably automatically generates
+// gs.cgiParams.yScaleSimImg (if present).  Defaults to 0.5
+
+yScaleSimImg=gs.variables.cgiargYScaleSimImg || 0.5; 
+
+caAlgorithm=gs.variables.cgiargCAAlgorithm;
+
+
+$(function() {
+
+    var audio = document.getElementById('rta-audio-element');
+    audio.addEventListener('loadedmetadata', caaInit, false);
+
+    audio.addEventListener('MozAudioAvailable', freqPlayerAudioAvailable, false);
+    audio.addEventListener('loadedmetadata', freqPlayerLoadedAudioMetadata, false);
+
+    audio.addEventListener('play',  freqPlayerAudioPlay,  false);
+    audio.addEventListener('pause', freqPlayerAudioPause, false);
+    audio.addEventListener('ended', freqPlayerAudioEnded, false);
+
+
+    console.log("****### Adding dual play loadmetadata event listeners in hybrid-audio-player.js");
+    baseSong = document.getElementById("rta-audio-element");
+    baseSong.addEventListener('loadedmetadata', initPannedPlaybackSampleRate, false);
+
+    leftSong = document.getElementById("leftsong");
+    leftSong.addEventListener('MozAudioAvailable', audioAvailableLeft, false);
+    leftSong.addEventListener('loadedmetadata', loadedMetadataLeft, false);
+
+    rightSong = document.getElementById("rightsong");
+    rightSong.addEventListener('MozAudioAvailable', audioAvailableRight, false);
+    rightSong.addEventListener('loadedmetadata', loadedMetadataRight, false);
+
+
+    var controlMarkerDiv = document.getElementById("controlMarker");
+    controlMarkerDiv.addEventListener('mousedown', playFromOffsetRTAEvent, false);
+
+/*
+    var oControlDiv = controlMarker.previousSibling;
+    console.log("** ocontrol = " + oControlDiv + ",  type = " + oControlDiv.nodeType)
+    // skip over any text nodes ... (done this way to cope with browser differences)
+    while (oControlDiv && oControlDiv.nodeType != 1) {
+	oControlDiv = oControlDiv.previousSibling;
+	console.log("** in loop ocontrol = " + oControlDiv + ",  type = " + oControlDiv.nodeType)
+    }
+
+    if (oControlDiv) {
+	oControlDiv.setAttribute("onmousedown","javascript:playFromOffsetRTAEvent(event)");
+	//oControlDiv.addEventListener('mousedown', playFromOffsetRTAEvent, false);
+	//oControlDiv.addEventListener('mousedown', playFromOffsetRTAEvent, false);
+    }
+    else {
+	console.warn("Warning: failed to find SoundManager2 PagePlayer oControl div");
+    }
+*/
+
+});
Index: /main/trunk/model-sites-dev/multimodal-mdl/collect/salami-ground-truth/script2/main-play-notes.js
===================================================================
--- /main/trunk/model-sites-dev/multimodal-mdl/collect/salami-ground-truth/script2/main-play-notes.js	(revision 28433)
+++ /main/trunk/model-sites-dev/multimodal-mdl/collect/salami-ground-truth/script2/main-play-notes.js	(revision 28433)
@@ -0,0 +1,131 @@
+
+var playNoteOverlayMode = "paused";
+
+PhotoNote.prototype.Play = function()
+{
+    //console.log("*** Activate Play for this note!!");
+   // console.log("*** this.rect" + this.rect);
+
+    var mysong   = document.getElementById("mysong");
+    var barWidth = mysong.getElementWidth();
+
+    //var mevent = new Event();
+    //var mevent = document.createEvent("MouseEvent");
+    // mevt.initMouseEvent("click",true,true,...); 
+
+    //var selfSimImg = document.getElementById("selfSimImgId");
+    //var imgWidth   = selfSimImg.getAttribute("width");
+    //var imgHeight  = selfSimImg.getAttribute("height") * yScaleSimImg;
+    
+    var img_x = $("#selfSimImgId").offset().left;
+    var img_y = $("#selfSimImgId").offset().top;
+
+
+    var mevent = new Object();
+    mevent.pageX = img_x + this.rect.left;
+    mevent.pageY = img_y + this.rect.top;
+
+    console.log("*** toggle play mode = " + togglePlayMode);
+    console.log("*** playTrackerMode = " + playTrackerMode);
+
+/*
+    if (togglePlayMode.match("pause")) { 
+	// (counter-intuitively) means it is playing
+	if (playTrackerMode.match("playing")) {
+	    // in dualPlay() mode
+	    togglePlay(mevent,this);
+	}
+    }
+    else {
+	// 
+	dualPlay(mevent);
+    }
+*/
+
+
+
+    if (playNoteOverlayMode == "paused") {
+	playNoteOverlayMode = "playing";
+	dualPlay(mevent);
+    }
+    else {
+	playNoteOverlayMode = "paused";
+	togglePlay(mevent,this);
+    }
+  
+
+
+    // code for cancel =>
+    //this.oldRect = null;
+    //this.gui.TextTitle.innerHTML = this.gui.TextBox.value;
+    //this.text = this.gui.TextBox.value
+    //this.UnSelect();
+}
+
+PhotoNote.prototype.appendPlayElement = function()
+{
+    var currentNote = this;
+
+    var newButtonPlay = document.createElement('a');
+    newButtonPlay.setAttribute("class", "annotator-save annotator-inline");
+    newButtonPlay.innerHTML='Play';
+    newButtonPlay.onmouseover = function(){_zoomEnabled = false;};
+    newButtonPlay.onmouseout = function(){_zoomEnabled = true;};
+    newButtonPlay.onclick = function() {
+        currentNote.Play();            
+    };
+
+    this.buttonsDiv.appendChild(newButtonPlay);
+}
+
+
+
+OverlayNotes.prototype.getNotes = function(divID,metaname)
+{
+    if(gs.variables[metaname] == null || gs.variables[metaname] == undefined)
+    {
+	console.log("No photo notes");
+	return;
+    }
+    
+    for(var i = 0; i < gs.variables[metaname].length; i++)
+    {
+	var metavals = gs.variables[metaname];
+	var note = metavals[i];
+	if(!note)
+	{
+	    continue;
+	}
+
+	var newNote = new PhotoNote(note.caption, divID, i+1, new PhotoNoteRect(note.area.x,note.area.y,note.area.width,note.area.height));
+	newNote.appendPlayElement();
+
+	var that = this;
+	newNote.onsave   = function(note) { return that.saveFunction(note) };
+	newNote.ondelete = function(note) { return that.deleteFunction(note) };
+
+	this.notes.AddNote(newNote);
+	this.posCount++;
+    }
+    
+    this.addNoteOverAndOutHandlers();
+}
+
+OverlayNotes.prototype.AddNote = function()
+{
+    this.posCount++;
+
+    var photoPos = $("#"+this.divID).offset();
+    
+    var newNote = new PhotoNote('Add note text here...',this.divID,this.posCount,new PhotoNoteRect(20,20,50,50));
+    newNote.appendPlayElement();
+
+    var that = this;
+    newNote.onsave   = function(note) { return that.saveFunction(note) };
+    newNote.ondelete = function(note) { return that.deleteFunction(note) };
+    this.notes.AddNote(newNote);
+    
+    this.addNoteOverAndOutHandlers();
+    newNote.Select();
+}
+
Index: /main/trunk/model-sites-dev/multimodal-mdl/collect/salami-ground-truth/script2/meandre-workflow/chromagram.js
===================================================================
--- /main/trunk/model-sites-dev/multimodal-mdl/collect/salami-ground-truth/script2/meandre-workflow/chromagram.js	(revision 28433)
+++ /main/trunk/model-sites-dev/multimodal-mdl/collect/salami-ground-truth/script2/meandre-workflow/chromagram.js	(revision 28433)
@@ -0,0 +1,198 @@
+
+
+var ChromagramMeandreWorkflow = function() {
+
+    var domain_prefix = window.location.protocol + "//" + window.location.hostname;
+
+    this.meandreController = new MeandreController(domain_prefix,"1714","1712");
+
+    this.baseURI     = "http://greenstone.org/meandre/flows/chromagram-v1/";
+    this.serviceHead = "http://greenstone.org/meandre/flows/chromagram-v1/instance/greenstone-audio-web-service-head/0";
+    this.serviceTail = "http://greenstone.org/meandre/flows/chromagram-v1/instance/float32-frame-web-service-buffer/5";
+
+    this.flowPort = null;
+
+    this.meandreFrameSize = null;
+    this.meandreDataOutput = new Array();
+
+    this.meandreCount = 0;
+}
+
+
+ChromagramMeandreWorkflow.prototype.thisMeandreFlowIsRunning = function() {
+    return this.flowPort != null;
+}
+
+ChromagramMeandreWorkflow.prototype.processThisMeandreFlowOutputDataCallback = function(oEvent,oReq) {
+
+
+    var arrayBuffer = oReq.response; // Note: not oReq.responseText
+
+    if (arrayBuffer.byteLength) {
+	console.log("*** get-data callback: Recieved binary data: raw byte array buffer len = " + arrayBuffer.byteLength);
+	
+	console.log("*** type of arrayBuffer: " + toType(arrayBuffer));
+
+	var float32Array = new Float32Array(arrayBuffer); 
+
+	console.info("*** get-data callback: number of frames received = " + float32Array.length/this.meandreFrameSize);
+
+
+	// Break it up into frames
+
+	//payload.data = float32Array;
+	this.meandreDataOutput.push(float32Array);
+    }
+}
+
+
+
+ChromagramMeandreWorkflow.prototype.processThisMeandreFlowOutputData = function(flowPort) {
+
+    // does flowPort need to be passed in as a parameter, now this is method not a function?
+
+    var getinfo_options = {cmd: "get-info" };
+
+    var info_props = this.meandreController.webComponentProperties(flowPort,this.serviceTail,getinfo_options)
+
+    // values stored in 'info_props' are strings => need to make sure we treat get numeric fields such
+    // as 'numFrames' as an integer
+
+    var numFramesAvailable = parseInt(info_props.numFrames);
+    if (isDefined(numFramesAvailable)) {
+	this.meandreFrameSize = parseInt(info_props.frameSize); 
+    }
+    else {
+	numFramesAvailable = 0;
+    }
+
+//    console.log("*** Meandre count = " + meandreCount);    
+
+    if (numFramesAvailable>0) {
+
+	var getNumFrames = Math.min(1000,numFramesAvailable);
+
+	console.info("get-data request: Number of frames available = " + numFramesAvailable, ", number of frames requested = " + getNumFrames);
+
+
+
+//	console.log("***** doing a get-data");
+	var getdata_options = {cmd: "get-data", numFrames: getNumFrames };
+	var payload = this.meandreController.binaryWebComponent(flowPort,this.serviceTail,getdata_options,
+								this.processThisMeandreFlowOutputDataCallback,this);
+
+	// delay the next call to 'get-info' to give the 'get-data' a chance to reach the server
+	var that = this;
+	setTimeout(function() {
+	    that.processThisMeandreFlowOutputData(flowPort);
+	}, 400);
+
+    }
+    else {
+	console.log("*** Sending 'done' command");
+	var done_options = {cmd: "done" };
+	this.meandreController.webComponent(flowPort,this.serviceHead,done_options);
+
+	// disable 'stop' and make 'run' active again
+	$('#meandre-stop-button').attr("disabled", "disabled");
+	$('#meandre-run-button').removeAttr("disabled");
+    }
+
+    this.meandreCount++;
+}
+
+
+ChromagramMeandreWorkflow.prototype.runThisMeandreFlow = function(elem,playCallback) {
+
+    if (this.thisMeandreFlowIsRunning()) {
+	console.error("runThisMeandreFlow(): The flow is already running on port " + this.flowPort);
+	return;
+    }
+
+    var $progressElem = $('#processing');
+    var $progressTitleElem = $('#processingTitle');
+    var $progressTextElem = $('#processingText');
+
+    var displayProgress = ($progressElem.length>0) ? true : false;
+    if (displayProgress) {
+	$progressTitleElem.html("Starting Meandre Workflow ...");
+	$progressTextElem.css('display','none');
+	$progressElem.css('display','block');
+    }
+
+
+    var flow_token = this.meandreController.runFlow(this.baseURI);
+    //console.log("**** got flow token : " + flow_token);	  
+    
+    // Give the flow time to start up ...
+    var that = this;
+
+    setTimeout(function() {
+	// Now find out which port it is running on ...
+ 	var flow_props = that.meandreController.runningFlowProperties(flow_token);
+	var flow_port =  flow_props.port;
+
+	var attempts = 0;
+	while ((flow_port==null) || (flow_port <= 0)) {
+	    console.info("port returned as " + flow_port + ", trying again");
+ 	    flow_props = that.meandreController.runningFlowProperties(flow_token);
+	    flow_port =  flow_props.port;	    
+	    attempts++;
+
+	    if (attempts==10) {
+		break;
+	    }
+	}
+	
+	console.info("Running Meandre flow on port : " + flow_port);
+	that.flowPort = flow_port;
+	
+	$('#meandre-run-button').attr("disabled", "disabled");
+	$('#meandre-stop-button').removeAttr("disabled");
+	
+	//$('#meandre-run-button').button({ disabled: true });
+	//$('#meandre-stop-button').button({disabled: false});
+	
+	var start_options = { 
+	    cmd: "generate-audio-signal", 
+	    docOID: "wibble",
+	    site: gs.xsltParams["site_name"],
+	    collect: collect,
+	    assocPath: gs.documentMetadata["assocfilepath"],
+	    assocFile: "doc.wav"
+	};
+
+	that.meandreController.webComponent(that.flowPort,that.serviceHead,start_options);
+	
+	setTimeout(function() { 
+	    that.processThisMeandreFlowOutputData(that.flowPort);
+
+	    if (displayProgress) {
+		$progressElem.css('display','none');
+		$progressTextElem.css('display','block');
+	    }
+
+	    if (elem!=null) {
+		// runFlow has been triggered by clicking on the 'run' button
+		togglePlay(null,document.getElementById('mainPlayButton'));
+	    }
+	    else if (playCallback!=null) {
+		playCallback();
+	    }
+
+	}, 700);
+
+    }, 800);
+}
+
+ChromagramMeandreWorkflow.prototype.stopThisMeandreFlow = function(elem) {
+    
+    this.meandreController.abortFlow(this.flowPort);
+    
+    $('#meandre-stop-button').attr("disabled", "disabled");
+    $('#meandre-run-button').removeAttr("disabled");
+    
+    //$('#meandre-run-button').button({ disabled: false });
+    //$('#meandre-stop-button').button({disabled: true});    
+}
+
Index: /main/trunk/model-sites-dev/multimodal-mdl/collect/salami-ground-truth/script2/meandre-workflow/js-dynamic-mix.js
===================================================================
--- /main/trunk/model-sites-dev/multimodal-mdl/collect/salami-ground-truth/script2/meandre-workflow/js-dynamic-mix.js	(revision 28433)
+++ /main/trunk/model-sites-dev/multimodal-mdl/collect/salami-ground-truth/script2/meandre-workflow/js-dynamic-mix.js	(revision 28433)
@@ -0,0 +1,298 @@
+
+
+var JSDynamicMixMeandreWorkflow = function() {
+
+    var domain_prefix = window.location.protocol + "//" + window.location.hostname;
+
+    this.meandreController = new MeandreController(domain_prefix,"1714","1712");
+
+    this.baseURI     = "http://greenstone.org/meandre/flows/dynamic-javascript-mixer/"
+    this.serviceHead = this.baseURI + "instance/greenstone-audio-web-service-head/0";
+    this.serviceTail = this.baseURI + "instance/float32-frame-web-service-buffer/3";
+
+    this.serviceJSDynamic = this.baseURI + "instance/dynamic-javascript-computation-component/2";
+
+    this.flowPort = null;
+
+    this.meandreFrameSize = null;
+    this.meandreDataOutput = new Array();
+
+    this.meandreCount = 0;
+}
+
+
+JSDynamicMixMeandreWorkflow.prototype.thisMeandreFlowIsRunning = function() {
+    return this.flowPort != null;
+}
+
+function bin2String(array,range) {
+    var result = "";
+
+    var excerpt = range || 5000;
+
+    var lowcut = Math.min(array.length,excerpt);
+        
+    result += "low cut: " + lowcut + "\n";
+    for (var i = 0; i < lowcut; i++) {
+	result += String.fromCharCode(65+array[i]);
+	if (((i+1)%200)==0) {
+	    result += "\n";
+	}
+    }
+    
+    result += "\n";
+
+
+    var highcut = Math.max(array.length-excerpt,0);
+    result += "high cut: " + highcut + "\n";
+
+    for (var i = highcut; i < array.length; i++) {
+	result += String.fromCharCode(65+array[i]);
+	if (((i+1)%200)==0) {
+	    result += "\n";
+	}
+    }
+    result += "\n";
+
+    return result;
+}
+
+JSDynamicMixMeandreWorkflow.prototype.processThisMeandreFlowOutputDataCallback = function(oEvent,oReq) {
+
+
+    var arrayBuffer = oReq.response; // Note: not oReq.responseText
+
+    if (arrayBuffer.byteLength) {
+	//console.log("*** get-data callback: Recieved binary data: raw byte array buffer len = " + arrayBuffer.byteLength);
+
+	//console.log("*** type of arrayBuffer: " + toType(arrayBuffer));
+
+	//var float32Array = new Float32Array(arrayBuffer); 
+	var byteArray = new Uint8Array(arrayBuffer); 
+	var byteArrayLen = byteArray.length;
+
+	var fixPos = new Array();
+	for (var i=0; i<byteArrayLen; i++) {
+	    if ((byteArray[i]==10)) {
+		    // && ((i<byteArrayLen-1) && (byteArray[i+1]==13))) {
+		// Despite the 'response' from the servlet being set to content type 'application/octet'
+		// the output streamed through the server is still treated as text, and a '10' in the binary
+		// stream is changed to '13', '10'
+
+		fixPos.push(i-1); 
+	    }
+	}
+
+	var fixPosLen = fixPos.length;
+	//console.log("*** fix pos len = " + fixPosLen);
+
+	var fixedByteArrayLen = byteArrayLen - fixPosLen;
+	var fixedByteArray = new Uint8Array(fixedByteArrayLen);
+
+	var prevPos = 0;
+	var newPos = 0;
+
+	for (var i=0; i<fixPosLen; i++) {
+	    var currFixPos = fixPos[i];
+
+	    var sliceArray = byteArray.subarray(prevPos,currFixPos);
+	    fixedByteArray.set(sliceArray,newPos);
+
+	    prevPos = currFixPos+1; // shift over erroneous <CR> (char 13)
+	    newPos += sliceArray.length;
+
+	}
+
+	var remainingSliceArray = byteArray.subarray(prevPos);
+	fixedByteArray.set(remainingSliceArray,newPos);
+	
+	if ((fixedByteArray.length % 4) != 0) {
+	    console.error("Fixed Returned binary data is not a multiple of 4");
+
+	    this.meandreDataOutput.push(byteArray);
+	}
+	else {
+	    //console.log("fixed byte array len = " + fixedByteArray.length);
+
+	    var float32Array = new Float32Array(fixedByteArray.buffer); 
+
+	    //console.log("float array len = " + float32Array.length);
+
+	    var meandreFrameSize = this.meandreFrameSize;
+	    var numFramesReceived = float32Array.length/meandreFrameSize;
+	    
+	    //console.log("** meandre output frameSize = " + meandreFrameSize);
+	    console.info("*** get-data callback: number of frames received = " + numFramesReceived);
+
+	    for (var i=0; i<numFramesReceived; i++) {
+		var startPos = i*meandreFrameSize;
+		var endPos   = startPos + meandreFrameSize -1;
+		var frame = float32Array.subarray(startPos,endPos);
+	    
+		//console.log("*** frameSize=" + meandreFrameSize + ", start pos=" + startPos + ", endPos=" + endPos + ", pushing on frame of size: " + frame.length);
+
+		this.meandreDataOutput.push(frame);
+	    }	    
+	}	
+    }
+}
+
+
+
+JSDynamicMixMeandreWorkflow.prototype.processThisMeandreFlowOutputData = function(flowPort) {
+
+    // does flowPort need to be passed in as a parameter, now this is method not a function?
+
+    var getinfo_options = {cmd: "get-info" };
+
+    var info_props = this.meandreController.webComponentProperties(flowPort,this.serviceTail,getinfo_options)
+
+    // values stored in 'info_props' are strings => need to make sure we treat get numeric fields such
+    // as 'numFrames' as an integer
+
+    var numFramesAvailable = parseInt(info_props.numFrames);
+    if (isDefined(numFramesAvailable)) {
+	this.meandreFrameSize = parseInt(info_props.frameSize); 
+    }
+    else {
+	numFramesAvailable = 0;
+    }
+
+//    console.log("*** Meandre count = " + meandreCount);    
+
+    if (numFramesAvailable>0) {
+
+	var getNumFrames = Math.min(600,numFramesAvailable);
+
+	console.info("get-data request: Number of frames available = " + numFramesAvailable, ", number of frames requested = " + getNumFrames);
+
+//	console.log("***** doing a get-data");
+	var getdata_options = {cmd: "get-data", numFrames: getNumFrames };
+	var payload = this.meandreController.binaryWebComponent(flowPort,this.serviceTail,getdata_options,
+								this.processThisMeandreFlowOutputDataCallback,this);
+
+	// delay the next call to 'get-info' to give the 'get-data' a chance to reach the server
+	var that = this;
+	setTimeout(function() {
+	    that.processThisMeandreFlowOutputData(flowPort);
+	}, 800);
+
+    }
+    else {
+	console.log("*** Sending 'done' command");
+	var done_options = {cmd: "done" };
+	this.meandreController.webComponent(flowPort,this.serviceHead,done_options);
+
+	// disable 'stop' and make 'run' active again
+	$('#meandre-stop-button').attr("disabled", "disabled");
+	$('#meandre-run-button').removeAttr("disabled");
+    }
+
+    this.meandreCount++;
+}
+
+
+JSDynamicMixMeandreWorkflow.prototype.runThisMeandreFlow = function(elem,playCallback) {
+
+    if (this.thisMeandreFlowIsRunning()) {
+	console.error("runThisMeandreFlow(): The flow is already running on port " + this.flowPort);
+	return;
+    }
+
+    var $progressElem = $('#processing');
+    var $progressTitleElem = $('#processingTitle');
+    var $progressTextElem = $('#processingText');
+
+    var displayProgress = ($progressElem.length>0) ? true : false;
+    if (displayProgress) {
+	$progressTitleElem.html("Starting Meandre Workflow ...");
+	$progressTextElem.css('display','none');
+	$progressElem.css('display','block');
+    }
+
+
+    var flow_token = this.meandreController.runFlow(this.baseURI);
+    //console.log("**** got flow token : " + flow_token);	  
+    
+    // Give the flow time to start up ...
+    var that = this;
+    setTimeout(function() {
+	// Now find out which port it is running on ...
+ 	var flow_props = that.meandreController.runningFlowProperties(flow_token);
+	var flow_port =  flow_props.port;
+
+	var attempts = 0;
+	while ((flow_port==null) || (flow_port <= 0)) {
+	    console.info("port returned as " + flow_port + ", trying again");
+ 	    flow_props = that.meandreController.runningFlowProperties(flow_token);
+	    flow_port =  flow_props.port;	    
+	    attempts++;
+
+	    if (attempts==10) {
+		break;
+	    }
+	}
+
+	console.info("Running Meandre flow on port : " + flow_port);
+	that.flowPort = flow_port;
+	
+	$('#meandre-run-button').attr("disabled", "disabled");
+	$('#meandre-stop-button').removeAttr("disabled");
+	
+	//$('#meandre-run-button').button({ disabled: true });
+	//$('#meandre-stop-button').button({disabled: false});
+	
+
+	// send over the user's custom javascript
+	var script_str = $("#js-dynamic-code").val();
+
+	var script_options = { 
+	    code: encodeURIComponent(script_str) // effectively double encode to get it through the proxy-server
+	};
+
+	that.meandreController.webComponent(that.flowPort,that.serviceJSDynamic,script_options);
+
+
+	var start_options = { 
+	    cmd: "generate-audio-signal", 
+	    docOID: "wibble",
+	    site: gs.xsltParams["site_name"],
+	    collect: collect,
+	    assocPath: gs.documentMetadata["assocfilepath"],
+	    assocFile: "doc.wav"
+	};
+
+	that.meandreController.webComponent(that.flowPort,that.serviceHead,start_options);
+	
+	setTimeout(function() { 
+	    that.processThisMeandreFlowOutputData(that.flowPort);
+
+	    if (displayProgress) {
+		$progressElem.css('display','none');
+		$progressTextElem.css('display','block');
+	    }
+
+	    if (elem!=null) {
+		// runFlow has been triggered by clicking on the 'run' button
+		togglePlay(null,document.getElementById('mainPlayButton'));
+	    }
+	    else if (playCallback!=null) {
+		playCallback();
+	    }
+
+	}, 800);
+
+    }, 800);
+}
+
+JSDynamicMixMeandreWorkflow.prototype.stopThisMeandreFlow = function(elem) {
+    
+    this.meandreController.abortFlow(this.flowPort);
+    
+    $('#meandre-stop-button').attr("disabled", "disabled");
+    $('#meandre-run-button').removeAttr("disabled");
+    
+    //$('#meandre-run-button').button({ disabled: false });
+    //$('#meandre-stop-button').button({disabled: true});    
+}
+
Index: /main/trunk/model-sites-dev/multimodal-mdl/collect/salami-ground-truth/transform/pages/about.xsl
===================================================================
--- /main/trunk/model-sites-dev/multimodal-mdl/collect/salami-ground-truth/transform/pages/about.xsl	(revision 28433)
+++ /main/trunk/model-sites-dev/multimodal-mdl/collect/salami-ground-truth/transform/pages/about.xsl	(revision 28433)
@@ -0,0 +1,525 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE videocollection [
+  <!ENTITY ndash "&#8211;">
+  <!ENTITY mdash "&#8212;">
+]>
+<xsl:stylesheet version="1.0"
+	xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+	xmlns:java="http://xml.apache.org/xslt/java"
+	xmlns:util="xalan://org.greenstone.gsdl3.util.XSLTUtil"
+	xmlns:gslib="http://www.greenstone.org/skinning"
+	extension-element-prefixes="java util"
+	exclude-result-prefixes="java util">
+
+	<!-- use the 'main' layout -->
+	<xsl:include href="layouts/main.xsl"/>
+
+	<!-- set page title -->
+	<xsl:template name="pageTitle"><gslib:collectionName/></xsl:template>
+
+	<!-- set page breadcrumbs -->
+	<xsl:template name="breadcrumbs"><gslib:siteLink/><gslib:rightArrow/></xsl:template>
+
+	<!-- the page content -->
+	<xsl:template match="/page">
+  
+		<!--Display the description text of the current collection,
+		and if some services are available then create a list
+		of links for each service within a <ul id="servicelist"> element.-->
+
+    <xsl:variable name="httpPath"> 
+      <xsl:value-of select="/page/pageResponse/collection/metadataList/metadata[@name='httpPath']" />
+    </xsl:variable>
+
+
+    <style>
+      p.about { text-align: justify; }
+      h2 { /* line-height: 135%; */ }
+      h3 { margin-top: 4pt; margin-bottom: 7pt; line-height: 135%; }
+
+        a.mashup {text-decoration: none; } 
+	a.mashup:link    {color:#000080;}  /* unvisited link */
+	a.mashup:visited {color:#303080;}  /* visited link */
+	a.mashup:hover   {color:#000040;}  /* mouse over link */
+	a.mashup:active  {color:#0000a0;}
+
+    </style>
+
+
+    <script src="{$httpPath}/script/browser-detect.js" type="text/javascript">
+	/* space filler needed */
+    </script>
+
+
+<div style="width: 800px; margin-left: auto; margin-right: auto;">
+
+
+<h2>A Musical Web Observatory: </h2>
+
+<h3><i><font size="+2">Connecting People with Data, Documents, and Algorithms</font></i></h3>
+
+<div style="background-color: #DD3611; color: white; padding: 4pt; margin-bottom: 6pt;">
+<table>
+
+  <tr>
+    <td>
+       <img src="{$httpPath}/images/firefox-128.png" />
+    </td>
+    <td>
+	<p class="about">
+	  <i><font size="+2">
+	    An experiment with Firefox's Advanced
+	    Audio Processing Extension ...
+	  </font></i>
+	</p>
+
+	<p class="about">
+	  <i><font size="+2">
+... featuring a mash-up of 
+<a class="mashup" href="http://www.greenstone.org" target="_blank">Greenstone</a>,
+<a class="mashup" href="http://www.omras2.org/audioDB" target="_blank">AudioDB</a>, and
+<a class="mashup" href="http://seasr.org/meandre/" target="_blank">Meandre</a>.
+	  </font></i>
+	</p>
+
+
+          <div id="bd-version" style="display:none;" class="about">
+	    <p>
+	      <img src="{$httpPath}/images/warning-icon.png" />
+	        Version of Firefox detected:
+	          <script type="text/javascript">
+	            document.write(BrowserDetect.version);
+	          </script>
+	    </p>
+	    <p>
+            You need to upgrade to a more recent version of Firefox 
+	        (v4.0 or greater) to access all the audio features of 
+	        this demonstration.
+	    </p>
+          </div>
+
+          <div id="bd-browser" style="display:none;" class="about">
+
+	    <p>
+	      <img src="{$httpPath}/images/warning-icon.png" />
+Browser detected:
+	      <script type="text/javascript">
+	        document.write(BrowserDetect.browser);
+	      </script>
+ 	    </p>
+            <p>You need to access this web-site using Firefox 
+	        (v4.0 or greater) to access all the audio features provided.
+	    </p>
+          </div>
+
+
+
+
+  <script>
+    <xsl:text disable-output-escaping="yes">
+
+if (BrowserDetect.browser == "Firefox") {
+  if (BrowserDetect.version &lt; 4) {
+    document.getElementById("bd-version").style.display="block";
+
+  }
+}
+else {
+  document.getElementById("bd-browser").style.display="block";
+
+}
+      </xsl:text>
+    </script>
+
+
+
+
+    </td>
+  </tr>
+</table>
+</div>
+
+<p class="about">This project is currently work in progress.  The sequence of development so far has been:
+
+<style>
+  li { padding-bottom: 10px; }
+
+</style>
+
+
+<ol>
+  <li>
+  <i>Starting point:</i> Manual (command-line) aggregation of disparate
+    resources prior to building the DL.  A set of bespoke Greenstone
+    document processing plugins corrals the heterogeneous gathered
+    data into a unified (homogeneous) canonical form that the DL can
+    access and display.  Everything presented in the DL is
+    either pre-computed (such as the self-similarity heat-maps) or else
+    computed at build-time.
+  </li>
+
+   <li>
+     <i>Audio-fingerprinting:</i> as before, but now metadata about the audio
+     songs is now enriched through a set of audio-fingerprinting web
+     services.  Everything presented in the DL is still pre-computed
+     or else computed at build-timeâhowever,  the inclusion in the document
+     view of a &quot;Discovery&quot; block allows a user to begin to
+     access and explore through linked-data, information related to
+     the song.
+   </li>
+
+  <li>
+    <i>Client-side audio processing (and visualization):</i> the
+    Pre-computed self-similarity heat-maps are dropped from the
+    collection building process in preference for the same information
+    being computed through Javascript running in the user's web
+    browser.
+  </li>
+
+  <li>
+    <i>Embedded Meandre workflows:</i> the Meandre Workbench is
+    integrated into Greenstone.  Audio documents in the Greenstone
+    digital library can now be dispatched and be processed by the
+    selected Meandre, and output from the workflow returned to the
+    Greenstone document viewâfor example, playing audio that has been
+    processed and output from the workflow.
+  </li>
+
+  <li>
+    <i>Client-side workflows:</i> the client-side Javascript
+    processing code is refactored to follow the same methodology as
+    Meandre components.
+  </li>
+
+  <li>
+    <i>Client/Server hybrid workflows:</i> the Greenstone/Meandre
+    integration is extended to support the dynamic 
+    transmission of <tt>executeCallBack()</tt> methods written 
+    in the user's browser in Javascript to be run on the
+    Meandre server as part of the active workflow.
+  </li>
+
+  <li>
+    <i>Forging ahead:</i> the next area to be worked on is upgrading
+    the level of Greenstone/Meandre integration so that data produced
+    by the workflows can be incorporated back into the underlying
+    digital library itself, rather than being (as it currently stands)
+    transitory data that only lives for the duration of the web page
+    being viewed.  This will form an implementation stepping-stone to
+    a more generalized ability to have data retrieved from other
+    external resources (located through the Discovery block
+    linked-data portion of the document view) ingested in to the DL
+    collection.
+  </li>
+
+
+</ol>
+
+</p>
+
+
+
+<!--
+
+<p class="about">This digital library collection demonstrates the
+integration of a variety of sources of structural metadata from both
+automatically derived content analysis and manually labelled
+ground-truth data to form a rich interactive web application suitable
+for musicologists (as the target end-users) to explore a collated set
+of music files.</p>
+
+<p class="about">While the base digital library system, <a
+href="http://www.greenstone.org" target="_blank">Greenstone</a>, is
+designed to operate with any web browser, the audio features this
+particular DL collection demonstrates relies on audio processing
+features currently only available in Firefox.  Using one of the other
+web browsers you will be able to access most features of the digital
+library collection, but when you access a particular song you may find
+playing the audioâin particular the panned audio
+effectâdoes not work.</p>
+-->
+
+
+<!--
+<p class="about">The developed system combines the open source capabilities of
+Greenstone, \cite{Greenstone}, NEMA \cite{Nema}, Salami \cite{Salami},
+and AudioDB \cite{AudioDB}.
+
+%%
+NEMA and Salami have been previously described in this article, and contribute 
+manual and audio content based metadata.
+%%
+AudioDB is a raw-audio content based searching algorithm based on Local-Sensitivity Hashing \cite{LSH}.
+%%
+Greenstone is a versatile digital library architecture with an
+extensible service-based architecture that.  In
+addition to the text-based searching and browsing capability to
+organize content, Greenstone provides the framework in which to harness the
+structural metadata from NEMA and Salami, and the audio-content based
+search functionality of audioDB.
+
+-->
+
+
+
+<h3>A Walkthrough</h3>
+
+
+<p class="about">The following walkthrough is for the initial incarnation of the DL collection, where all
+the information presented is either precomputed or computed at build time.</p>
+
+<p class="about">Taking as a starting point a set of music files identified as worthy
+of study, the <a href="#browse">figure below</a> shows the result of browsing
+the formed digital library collection <a href="dev?a=b&amp;rt=s&amp;s=ClassifierBrowse&amp;c=salami-audioDB&amp;cl=CL1" target="_blank">by title</a> from a web browser.
+The figure is a useful snapshot in which to orientate ourselves with
+the main structure and features to the digital library.  Functionality that
+persistently reoccurs is accessible through the header to the page.</p>
+
+<p class="about">This includes:
+<ul>
+
+<li>help and preferences (top-right);</li>
+<li>a quick-search option (located just
+below) with links to more sophisticated searching options; and</li>
+<li>pin-pointing where within the site a user is currently located
+(top-left).</li>
+</ul>
+
+
+<a name="browse" />
+<table style="width: 700px; margin-left: auto; margin-right: auto; margin-bottom: 6pt;">
+  <tr>
+    <td style="border: solid 1px;">
+      <img style="width: 700px" src="{$httpPath}/images/figs/cropped/salami-browse.png" />
+    </td>
+  </tr>
+  <tr style="background-color: #bbeebb">
+    <td>
+      <i>Browsing in the digital library
+  <a href="dev?a=b&amp;rt=s&amp;s=ClassifierBrowse&amp;c=salami-audioDB&amp;cl=CL1" target="_blank">by titles</a>.</i>
+    </td>
+  </tr>
+</table>
+
+
+The specific content to this location within the site (in this case
+browsing by title) is shown beneath the main banner.  Various
+groupings of title can be accessed by clicking on the bookshelf icons
+vertically aligned as the main part of the page: currently <a
+href="dev?a=b&amp;rt=s&amp;s=ClassifierBrowse&amp;c=salami-audioDB&amp;cl=CL1#CL1.2">CâD</a>
+is open, with the remaining letters to the alphabet below this,
+accessed through scrolling.</p>
+
+
+
+
+<p class="about">Interested in the song <i>Candela</i> our curious musicologist clicks
+on <a href="dev?a=d&amp;ed=1&amp;book=off&amp;c=salami-audioDB&amp;d=D145&amp;dt=simple&amp;sib=1&amp;p.a=b&amp;p.sa=&amp;p.s=ClassifierBrowse" target="_blank">the link for this</a>.  This brings up the document view to this song:</p>
+
+<a name="self-similarity" />
+<table style="width: 700px; margin-left: auto; margin-right: auto; margin-bottom: 6pt;">
+  <tr>
+    <td style="border: solid 1px;">
+      <img style="width: 700px" src="{$httpPath}/images/figs/cropped/salami-self-similarity2.png" />
+    </td>
+  </tr>
+  <tr style="background-color: #bbeebb">
+    <td>
+      <i>The <a href="dev?a=d&amp;ed=1&amp;book=off&amp;c=salami-audioDB&amp;d=D145&amp;dt=simple&amp;sib=1&amp;p.a=b&amp;p.sa=&amp;p.s=ClassifierBrowse" target="_blank">musicologically enriched document view</a> for</i> Candela.
+    </td>
+  </tr>
+</table>
+
+<p class="about">Normally in a digital
+library the document view brings up a page that is strongly derived
+from textual metadata.  If the document viewed was a text-document,
+some summary information such as title and author is typically
+presented, say in tabular form, before the main text is presented.
+Even in the case of multimedia digital libraries, the view presented
+is still strongly derived from textual metadata: this time including
+details such as the length of the video, the TV company that produced
+it, whether captions are available, and so forth, accompanied with an
+embedded video player for viewing the contentâessentially more
+textual metadata (in this case the URL to the video content) which in
+terms of the user-interface is largely divorced from the other
+elements displayed on the page.</p>
+
+<p class="about">This contrasts sharply with the document view developed in this
+digital library.
+Naturally it allows the song to be played (akin to the embedded video player),
+however this is largely of secondary importance to the 
+other functionality available this is much more closely
+integrated.</p>
+
+<p class="about">The most striking visual component to the document view is a
+self-similarity &quot;heat map&quot; where the duration of the song forms both
+the <i>x</i>- and <i>y</i>-axis, and a red pixel located at a given <i>(x,y)</i>
+co-ordinate in the map represents a location where two parts of the
+song are strongly similar, proportionally shifting to blue to
+represent dissimilar.  Given this configuration, the leading diagonal
+to the matrix (<i>x=y</i>) is always coloured red as this represents the
+comparison of one part of the song with itself.</p>
+
+<p class="about">When the user moves the mouse cursor around the self-similarity map
+a highlighting circle is shown to emphasize the area the user is over,
+with a black dot at the centre (visible in in
+the <a href="#self-similarity">above figure</a>); annotated vertically
+and horizontally are the two time-offsets in seconds that that point
+in the map corresponds to.  Clicking the cursor at this point results
+in the audio being played <i>simultaneously</i> from these two points.
+To aid the musicologist in listening to the two parts of the song, one
+part is panned to the left speaker, and the other to the right (this
+was implemented using the extended audio API provided by Firefox, and
+so this particular feature only work when viewing the collection with
+this browserâsee implementation details below).  In our figure,
+the musicologist has zeroed in the location <i>x=33</i>, <i>y=97</i>
+which corresponds to the start of a strong red diagonal that occurs
+some distance off the leading diagonal.  Listening to the two sounds
+played (most reliably done with headphones on), they hear that these
+two sections of the song are indeed repeating sections of the guitar
+piece <i>Candela</i> with a minor variation in the latter section
+where a recorder is also playing in the arrangement.</p>
+
+<p class="about">The structured audio time-lines (labelled A, B, ..., and 6, 5, 2,
+... in the figure) located above the self-similarity map are another
+area of enriched musical content in the digital library. The upper
+line shows the ground-truth data for this song generated by
+the <a href="http://www.music-ir.org/?q=node/14" target="_blank">Salami project</a>;
+the lower line is generated by an algorithmically based content
+analysis algorithm.</p>
+
+<p class="about">While there is some agreement between these two lines, there are
+also significant differences.  The play and search buttons within the
+structured time-lines (the latter represented by a magnifying glass)
+allow the user to investigate further these structures.  We shall
+return to the search functionality shortly (which is content based,
+using <a href="http://omras2.doc.gold.ac.uk/software/audiodb/" target="_blank">AudioDB</a>),
+but in the meantime note that with the time-lines positioned above the
+self-similarity map, there is further opportunity to study the
+differences between the two structured time-line.  It is certainly the
+case that there are strong visual cues in the map that line up with
+the algorithmic time-line, even though they do not align with a
+boundary in the ground-truth data, and the user can click on these
+parts of the similarity map to hear what is occurring at these
+points.</p>
+
+
+
+<a name="resultspage" />
+<table style="width: 700px; margin-left: auto; margin-right: auto; margin-bottom: 6pt;">
+  <tr>
+    <td style="border: solid 1px;">
+      <img style="width: 350px" src="{$httpPath}/images/figs/cropped/salami-audiodb-search-resultspage-halfcut.png" />
+    </td>
+    <td style="border: solid 1px;">
+      <img style="width: 350px" src="{$httpPath}/images/figs/cropped/salami-structured-search-resultspage-halfcut.png" />
+    </td>
+  </tr>
+  <tr style="background-color: #bbeebb">
+    <td colspan="2">
+      <i>Audio content based search results: left) the 
+	<a href="dev?a=q&amp;sa=&amp;rt=rd&amp;s=AudioQuery&amp;c=salami-audioDB&amp;startPage=1&amp;s1.maxDocs=100&amp;s1.hitsPerPage=20&amp;q=D206.dir&amp;s1.query=D206.dir&amp;s1.offset=263&amp;s1.length=24&amp;mysongWindowDuration=6" target="_blank">result list</a> from
+      an audio content based query taken from an extract of </i>
+      Michelle; <i>and right)
+      the <a href="dev?a=q&amp;sa=&amp;rt=rd&amp;s=TextQuery&amp;c=salami-audioDB&amp;startPage=1&amp;s1.query=%22b+b+c+b+c%22&amp;s1.index=JS" target="_blank">result of a structured music search</a> for
+      content containing &quot;b b c b a&quot; as a sequence.</i>
+    </td>
+  </tr>
+</table>
+
+<p class="about">Returning to the search capability provided by the structured
+time-lines, the <a href="#resultspage">above figure (left)</a> show the result of
+using this feature while study the song <i>Michelle</i> by The
+Beatles.  In this case the user selected the section of the
+ground-truth time-line corresponding to section starting &quot;I want you
+...&quot;, but could have equally used the algorithmically calculated
+time-line, or in fact paused the song playing at any point, and
+started a match from there.</p>
+
+
+<p class="about">Not surprisingly <i>Michelle</i> is returned as the top hit (at
+92.1%)âwe shall see shortly that this is because the system found
+several sections of the song that matched thisâthe next hit being
+<i>Bigger Than JC</i> at 74.4%, and so on down, where only one hit
+per song occurs.  Clicking on the top hit,
+the <a href="#audiodb">figure below</a> shows the document view that is
+displayed, focusing in on the key area to this screen.  This time the
+time-line area has an additional bar: the points within the song that
+AudioDB found to be similar.  Like the other time-lines, a play button
+is present on these segments so the user can play the matching points
+directly.  In this case
+clicking on them reveals the matching sections found correspond to
+melodically repeating sections of the song, only with different lyrics
+(&quot;I love you ...&quot; and &quot;I need you ...&quot;).</p>
+
+
+<p class="about">A further form of musical content-based searching is available through
+the main header to the digital library.  Instead of searching by title
+or artist (which are also available) the user can click on this
+&quot;search by&quot; menu next to the quick-search text box and select
+&quot;ground-truth structure&quot; instead.
+The <a href="#resultspage">figure above</a> (right) shows the result of using this
+option, where the user has entered &quot;b b c b c&quot; as the query, in
+other words searching for songs that have two sections in a row the
+same, then a new section, then returning to the original section,
+before progressing to a recurrence of the second distinct section.  In
+pop and rock music this is a popular sequence corresponding to verse,
+verse, chorus, verse, chorus.  A more intriguing framing of a query
+along these linesâequally possible in the digital libraryâwould be
+to go to the fielded search page (accessible through the <i>advanced
+  search</i> link below the quick-search box, and entered the same
+music structure query, but this time combine it with other fielded
+query terms (Genre=Blues OR Jazz, Year&lt;1950).  Results from this
+query would let the musicologist explore potential evidence of this
+pattern of sections being used in two of the key musical genres that
+influenced the development of Rock and Roll music.</p>
+
+
+<a name="audiodb" />
+<table style="width: 700px; margin-left: auto; margin-right: auto; margin-bottom: 6pt;">
+  <tr>
+    <td style="border: solid 1px;">
+      <img style="width: 700px" src="{$httpPath}/images/figs/cropped/salami-audiodb-search2.png" />
+    </td>
+  </tr>
+  <tr style="background-color: #bbeebb">
+    <td>
+      <i>The document view for</i> Michelle <i><a href="dev?a=d&amp;c=salami-audioDB&amp;d=D206&amp;dt=simple&amp;p.frameOffset=133,393,264,262,392&amp;p.frameLength=24&amp;p.a=q&amp;p.s=AudioQuery&amp;hl=on&amp;ed=1#D206" target="_blank">augmented with the locations of the matches</a> of the audio query.</i>
+    </td>
+  </tr>
+</table>
+
+
+
+
+<h3>Implementation details</h3>
+
+<p class="about">The core part of the interactive elements in the document view were
+implemented using SVG combined with Javascript.  The left- and
+right-panning interactively available from the self-similarity map was
+implemented by processing the raw audio stream, made accessible by the
+Firefox Audio extension
+<a href="https://wiki.mozilla.org/Audio_Data_API" target="_blank">API</a>.</p>
+
+<p class="about">AudioDB content based searching was integrated into Greenstone through
+two components of the digital library software architecture: its
+build-time document processing plugin system, and its runtime
+message-passing service-base framework.  The developed plugin accepts
+a wide range of audio formats (including OGG and MP3), and converts
+them to WAV, the format needed by AudioDB for processing.  The new
+search service took the form of a proxy, accepting messages in the
+XML syntax used by Greenstone, turning them into the necessary calls
+to the AudioDB command-line interface, and then converting the output
+from AudioDB back into the XML syntax expected by the digital library
+architecture.  Finally, the two parts were packaged to operate as a
+Greenstone extension; the software is available at:
+<a href="http://trac.greenstone.org/gs3-extensions/audioDB/trunk/src" target="_blank">http://trac.greenstone.org/gs3-extensions/audioDB/trunk/src</a>.</p>
+
+</div>
+
+
+	</xsl:template>
+
+
+</xsl:stylesheet>  
+
Index: /main/trunk/model-sites-dev/multimodal-mdl/collect/salami-ground-truth/transform/pages/document.xsl
===================================================================
--- /main/trunk/model-sites-dev/multimodal-mdl/collect/salami-ground-truth/transform/pages/document.xsl	(revision 28433)
+++ /main/trunk/model-sites-dev/multimodal-mdl/collect/salami-ground-truth/transform/pages/document.xsl	(revision 28433)
@@ -0,0 +1,895 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet version="1.0"
+	xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+	xmlns:java="http://xml.apache.org/xslt/java"
+	xmlns:util="xalan://org.greenstone.gsdl3.util.XSLTUtil"
+	xmlns:gslib="http://www.greenstone.org/skinning"
+	xmlns:gsf="http://www.greenstone.org/greenstone3/schema/ConfigFormat"
+	xmlns:xlink="http://www.w3.org/1999/xlink" 
+	extension-element-prefixes="java util"
+	exclude-result-prefixes="java util gsf">
+  
+
+  <!-- *** -->
+  <!-- Document header -->
+  <!-- *** -->
+
+  <xsl:template name="soundmanager2-header">
+
+    <!-- soundManager2 API -->
+    <gsf:style src="ext/sound-manager2/css/flashblock.css" />  
+    <gsf:script src="ext/sound-manager2/script/soundmanager2-nodebug.js"/>
+
+    <!-- The Page player (variant of SoundManger) main script -->
+    <gsf:script src="ext/sound-manager2/script/page-player.js"/>
+    <gsf:style src="ext/sound-manager2/css/page-player.css" />
+        
+    <!-- optional: annotations/sub-tracks/notes, and alternate themes -->
+    <gsf:style src="ext/sound-manager2/css/optional-annotations.css" />
+    <gsf:style src="ext/sound-manager2/css/optional-themes.css" />
+
+    <!-- optional: Metadata UI prototype (not needed unless you want the bottom-most demo bits) -->
+    <gsf:script src="ext/sound-manager2/script/optional-page-player-metadata.js"/>
+    
+    <gsf:style>
+      ul.playlist li .comment {font-size:0.65em;opacity:0.5}
+    </gsf:style>
+    
+    <!-- Customization of page-player for this collection -->
+
+    <gsf:script>
+
+      soundManager.flashVersion = 9;
+      soundManager.preferFlash = true;        /* for visualization effects */
+      soundManager.useHighPerformance = true; /* keep flash on screen, boost performance */
+      soundManager.wmode = "transparent";     /* transparent SWF, if possible */
+      soundManager.useFastPolling = true;     /* increased JS callback frequency */
+      soundManager.url = "ext/sound-manager2/swf/";
+
+      /* custom page player configuration */
+
+      var PP_CONFIG = {
+        autoStart:       false,  /* begin playing first sound when page loads */
+	playNext:        false,  /* stop after one sound, or play through list until end */
+	useThrottling:   false,  /* try to rate-limit potentially-expensive calls (eg. dragging position around) */
+	usePeakData:     true,   /* [Flash 9 only] whether or not to show peak data (left/right channel values) - nor noticable on CPU */
+	useWaveformData: false,  /* [Flash 9 only] show raw waveform data - WARNING: LIKELY VERY CPU-HEAVY */
+	useEQData:       false,  /* [Flash 9 only] show EQ (frequency spectrum) data */
+	useFavIcon:      false,  /* try to apply peakData to address bar (Firefox + Opera) - performance note: appears to make Firefox 3 do some temporary, heavy disk access/swapping/garbage collection at first(?) - may be too heavy on CPU */
+	useMovieStar:    true    /* Flash 9.0r115+ only: Support for a subset of MPEG4 formats. */
+      }
+    </gsf:script>
+  </xsl:template>
+
+
+  <!-- CAA = Content Analysis Algorithm -->
+  <xsl:variable name="cgiargCAAlgorithm">
+    <xsl:choose>
+      <xsl:when test="/page/pageRequest/paramList/param[@name='p.caAlgorithm']/@value != ''"><xsl:value-of select="/page/pageRequest/paramList/param[@name='p.caAlgorithm']/@value"/></xsl:when>
+      <xsl:otherwise>1</xsl:otherwise>
+    </xsl:choose>
+  </xsl:variable>
+
+  <!-- *** -->
+  <!-- The Javascript DSP files for computing chroma features in the browser -->
+  <!-- *** -->
+
+  <xsl:template name="javascript-dsp-header">
+    <gsf:script src="ext/js-dsp/dsp-custom.js"/>
+    <gsf:script src="ext/js-dsp/chroma-transform.js"/>
+    <gsf:script src="ext/js-dsp/frequency-plotter.js"/>
+    <gsf:script src="ext/js-dsp/frequency-player.js"/>
+
+
+    <gsf:script src="ext/js-dsp/component/crockford-inheritance.js"/>
+    <gsf:script src="ext/js-dsp/component/workflow-core.js"/>
+    <gsf:script src="ext/js-dsp/component/audio-mixer.js"/>
+    <gsf:script src="ext/js-dsp/component/wf-freq-spectrum.js"/>
+    <gsf:script src="ext/js-dsp/component/wf-filter-bank.js"/>
+    <gsf:script src="ext/js-dsp/component/wf-chroma-transform.js"/>
+    <gsf:script src="ext/js-dsp/component/active-workflow.js"/>
+
+  </xsl:template>
+
+  <xsl:template name="processingPopup">
+    <div>
+      <style type="text/css">	
+	#processing { 
+	  width: 100%; 
+	  height: 100%; 
+	  position: absolute; 
+	  z-index: 10; 
+	  left: 0px; 
+	  top: 0px; 
+	  background-color: rgba(255,255,255,0.75); 
+	  opacity: 1; 
+	  display: none;
+	}
+
+	#processingMessage { 
+	  position: absolute;
+	  padding: 10px;
+	  border-radius: 10px; 
+	  margin-left: 50%; 
+	  width: 380px; 
+	  height: 105px; 
+	  left: -250px; top: 200px; 
+	  background-color: rgba(255,255,255,1);
+	  box-shadow: 0px 0px 30px rgba(0,0,0,0.8); 
+	}
+
+	#processingMessage p { 
+	  font-size: 18px; 
+	  text-align: center; 
+	  font-family: 
+	  sans-serif; 
+	  font-weight: bold; 
+	  color: #666; 
+	}
+      </style>
+      
+      <div id="processing">
+	<div id="processingMessage">
+	  <h2 id="processingTitle" class="ui-state-default ui-corner-all" style="padding: 8px; font-size: 110%; width: auto;">
+	    Heading
+	  </h2>
+	  <p id="processingText">text</p>
+	</div>
+      </div>
+    </div>
+
+  </xsl:template>
+
+  <!-- *** -->
+  <!-- * Discovery -->
+  <!-- *** -->
+
+  <xsl:template name="discovery-block">
+    
+    <div id="fingerprint-turnstyle">
+
+      <div style="background-image: none; background-color: rgb(80%,80%,20%);">
+	Discovery: <xsl:call-template name="choose-title"/>
+      </div>
+
+      <div class="documenttext" style="display: none;">
+	<xsl:call-template name="fingerprintMetadataBlock" />
+      </div>
+
+    </div>
+
+    <script>
+      <xsl:text disable-output-escaping="yes">
+	$(function(){
+	transformToTurnstyleBlock("fingerprint");
+	});
+      </xsl:text>
+    </script>
+    
+  </xsl:template>
+
+  <xsl:template name="fingerprintMetadataBlock">
+    
+    <xsl:variable name="httpCollection"><xsl:value-of select="/page/pageResponse/collection/metadataList/metadata[@name='httpPath']"/></xsl:variable>
+    <xsl:variable name="assocFilePath"><gsf:metadata name="assocfilepath" select="root"/></xsl:variable>
+
+
+    <xsl:variable name="musicbrainzsongid">
+      <gsf:metadata name="dc.Identifier.musicbrainzsongid"/>
+    </xsl:variable>
+
+    <xsl:variable name="musicbrainzalbumid">
+      <gsf:metadata name="dc.Source.musicbrainzalbumid"/>
+    </xsl:variable>
+
+    <xsl:variable name="musicbrainzartistid">
+      <gsf:metadata name="dc.Creator.musicbrainzartistid"/>
+    </xsl:variable>
+    
+    <xsl:variable name="lastfmtrackurl">
+      <gsf:metadata name="dc.Identifier.lastfmtrackurl"/>
+    </xsl:variable>
+
+    <xsl:variable name="echonestsongid">
+      <gsf:metadata name="dc.Identifier.echonestsongid"/>
+    </xsl:variable>
+    
+      <table class="metadata-stripes">
+	<tbody>
+	  <tr>
+	    <td>
+	      Title
+	    </td>
+	    <td>
+	      <gsf:metadata name="dc.Title"/>
+	    </td>
+	  </tr>
+	  
+	  <tr>
+	    <td>Album Title</td>
+	    <td><gsf:metadata name="dc.Title.albumtitle"/></td>
+	  </tr>
+	  
+	  <tr>
+	    <td>Artist</td>
+	    <td><gsf:metadata name="dc.Creator"/></td>
+	  </tr>
+	  
+	  <tr valign="top">
+	    <td>Artist Summary</td>
+	    <td><i><gsf:metadata name="LastFM.LastFMArtistWikiSummary"/></i></td>
+	  </tr>
+	  
+<!--
+dc.Identifier.echonestsongid
+dc.Identifier.echonestartistid
+
+dc.Identifier.lastfmtrackurl
+dc.Identifier.lastfmalbumurl
+dc.Identifier.lastfmartisturl
+
+//dc.Identifier
+dc.Identifier.musicbrainzalbumid
+dc.Identifier.musicbrainzartistid
+dc.Identifier.musicbrainzsongid
+dc.Identifier.playmeartistid
+
+-->
+
+	  <tr>
+	    <td colspan="2">
+
+	      <xsl:for-each select="/page/pageResponse/document/metadataList/metadata[@name = 'dc.Relation.artistrelatedimage']">
+		<xsl:if test="position() &lt;= 6">
+		  <a target="_blank">
+		    <xsl:attribute name='href'>
+		      <xsl:value-of disable-output-escaping="yes" select="."/>
+		    </xsl:attribute>
+		    
+		    <img width="150">
+		      <xsl:attribute name='src'>
+			<xsl:value-of disable-output-escaping="yes" select="."/>
+		      </xsl:attribute>
+		    </img>
+		  </a>
+		</xsl:if>
+	      </xsl:for-each>
+	    </td>
+	  </tr>
+
+	  <tr>
+	    <td>Linked Data</td>
+	    <td>
+	      <!--
+		  <gsf:metadata name="dc.Identifier"/><br />
+	      -->
+
+	      <table>
+		<tr>
+		  <td>
+		    MusicBrainz song id: 
+		  </td>
+		  <td>
+		    <a href="http://dbtune.org/musicbrainz/resource/track/{$musicbrainzsongid}" target="#musicbrainz">
+		      <xsl:copy-of select="$musicbrainzsongid"/>
+		    </a>
+		  </td>
+		</tr>
+
+		<tr>
+		  <td>
+		    MusicBrainz album id: 
+		  </td>
+		  <td>
+		    <a href="http://dbtune.org/musicbrainz/resource/record/{$musicbrainzalbumid}" target="#musicbrainz">
+		      <xsl:copy-of select="$musicbrainzalbumid"/>
+		    </a>
+		  </td>
+		</tr>
+
+		<tr>
+		  <td>
+		    MusicBrainz artist id: 
+		  </td>
+		  <td>
+		    <a href="http://dbtune.org/musicbrainz/page/artist/{$musicbrainzartistid}" target="#musicbrainz">
+		      <xsl:copy-of select="$musicbrainzartistid"/>
+		    </a>
+		  </td>
+		</tr>
+		<tr>
+		  <td colspan="2">	      
+		    <a href="{$lastfmtrackurl}" target="#lastfm">
+		      <xsl:copy-of select="$lastfmtrackurl"/>
+		    </a>
+		  </td>
+		</tr>
+		<tr>
+		  <td>
+		    EchoNest song id:
+		  </td>
+		  <td>
+		    <a href="{$echonestsongid}" target="#echonestsongid">
+		      <xsl:copy-of select="$echonestsongid"/>
+		    </a>
+		  </td>
+		</tr>
+	      </table>
+
+	    </td>
+	  </tr>
+	  
+
+	</tbody>
+      </table>
+  </xsl:template>
+
+
+
+  <!-- *** -->
+  <!-- * Audio Player -->
+  <!-- *** -->
+
+
+  <xsl:template name="js-mad-header">
+
+        <gsf:script src="ext/js-mad/script/mad.js"/>
+        <gsf:script src="ext/js-mad/script/rq_table.js"/>
+        <gsf:script src="ext/js-mad/script/imdct_s.js"/>
+        <gsf:script src="ext/js-mad/script/huffman.js"/>
+        <gsf:script src="ext/js-mad/script/bit.js"/>
+        <gsf:script src="ext/js-mad/script/stream.js"/>
+        <gsf:script src="ext/js-mad/script/layer3.js"/>
+        <gsf:script src="ext/js-mad/script/frame.js"/>
+        <gsf:script src="ext/js-mad/script/synth.js"/>
+       
+        <gsf:script src="ext/js-mad/script/arraybuffer/bytestream.js"/>
+        <gsf:script src="ext/js-mad/script/arraybuffer/filestream.js"/>
+        <gsf:script src="ext/js-mad/script/arraybuffer/substream.js"/>
+        <gsf:script src="ext/js-mad/script/arraybuffer/arraystream.js"/>
+        <gsf:script src="ext/js-mad/script/arraybuffer/ajaxstream.js"/>
+
+        <gsf:script src="ext/js-mad/script/binarystring/bytestream.js"/>
+        <gsf:script src="ext/js-mad/script/binarystring/filestream.js"/>
+        <gsf:script src="ext/js-mad/script/binarystring/substream.js"/>
+        <gsf:script src="ext/js-mad/script/binarystring/stringstream.js"/>
+        <gsf:script src="ext/js-mad/script/binarystring/ajaxstream.js"/>
+
+        <gsf:script src="ext/js-mad/script/id3v22stream.js"/>
+        <gsf:script src="ext/js-mad/script/id3v23stream.js"/>
+        <gsf:script src="ext/js-mad/script/mp3file.js"/>
+        
+<!--
+        <gsf:script src="ext/js-mad/script/player.js"/>
+-->
+
+        <gsf:script src="ext/js-mad/script/sink.min.js"/>
+
+<!--
+        <gsf:script src="ext/js-mad/script/require.js"/>
+-->
+<!--
+        <gsf:script src="ext/js-mad/script/sink-light.js"/>
+-->
+
+        <gsf:script src="ext/js-mad/script/browser-detect.js"/>
+        <gsf:script src="ext/js-mad/script/main-jsmad.js"/>
+
+  </xsl:template>
+
+
+  <xsl:template name="audio-icon-cache">
+    <div style="display:none;">
+      <!-- pre-load various play/pause images to help with speed of interface update -->
+      <img src="ext/diy-audio-player/images/play32Highlight.png" />
+      <img src="ext/diy-audio-player/images/pause32.png" />
+      <img src="ext/diy-audio-player/images/pause32Highlight.png" />
+      <img src="ext/diy-audio-player/images/play20Highlight.png" />
+      <img src="ext/diy-audio-player/images/stop32.png" />
+      <img src="ext/diy-audio-player/images/stop32Highlight.png" />
+      <img src="ext/diy-audio-player/images/search20Highlight.png" />	
+    </div>
+  </xsl:template>
+
+
+  <!-- *** -->
+  <!-- * Workflow control -->
+  <!-- *** -->
+
+  <xsl:template name="workflow-block">
+    <xsl:variable name="httpCollection">
+      <xsl:value-of select="/page/pageResponse/collection/metadataList/metadata[@name='httpPath']"/>
+    </xsl:variable>
+
+    <div id="workflow-turnstyle">
+
+      <div style="background-image: none; background-color: rgb(80%,80%,20%);">
+	Workflow
+      </div>
+
+      <div class="documenttext hide" style="color: white; background-color: rgb(40%,40%,20%); padding: 8px;">
+	
+<!--
+	<form style="padding-left: 8px;">
+	  <span class="vis-heading">Input Selection:</span>
+	  <input type="radio" name="inputSelection" onclick="setInputSelectionMode(this)" value="left"/>Left only
+	  <input type="radio" name="inputSelection" onclick="setInputSelectionMode(this)" value="right"/>Right only
+	  <input type="radio" name="inputSelection" onclick="setInputSelectionMode(this)" value="diff"/>Average
+	  <input type="radio" name="inputSelection" onclick="setInputSelectionMode(this)" value="mix" checked="checked"/>Difference
+	</form>
+	<hr/>
+-->
+
+	<form style="padding-left: 8px; height: 48px;">
+	  <span class="vis-heading" style="padding-right: 10px" >Meandre Workflow:</span>
+
+	  <select id="meandre-workflow-pos" onChange="loadSelectedWorkflow(this)" style="font-size: 90%; padding 8px;">
+	    <option value="0" selected="selected">Chromagram</option>
+	    <option value="1" >Dynamic Javascript Mixer</option>
+	  </select>
+
+	  <div style="float: right;" id="meandre-buttons">
+	 
+	    <button type="button" id="meandre-run-button"  
+		    onclick="selectedMeandreWorkflow.runThisMeandreFlow(this)">
+	      <img id="meandre-run-button" src="ext/diy-audio-player/images/play32.png" 
+		   width="32"
+		   height="32"  
+		   XXonmouseover="playHighlightOn(this)"
+		   XXonmouseout="playHighlightOff(this)"
+		   XXonclick="runThisMeandreFlow(this)"
+		   style="vertical-align: middle;"/>
+	      Run
+	    </button>
+
+	    <button type="button" id="meandre-stop-button" onclick="selectedMeandreWorkflow.stopThisMeandreFlow(this)" disabled="disabled">
+	      <img id="meandre-stop-button" src="ext/diy-audio-player/images/stop32.png" 
+		   width="32"
+		   height="32"  
+		   XXonmouseover="stopHighlightOn(this)"
+		   XXonmouseout="stopHighlightOff(this)"
+		   XXonclick="stopThisMeandreFlow(this)"
+		   style="vertical-align: middle;"/>
+	      Stop
+	    </button>
+
+<!--
+	    <button type="button" id="meandre-run-button" onclick="runThisMeandreFlow(this)" >Run</button>
+	    <button type="button" id="meandre-stop-button" onclick="stopThisMeandreFlow(this)" disabled="disabled">Stop</button>
+-->
+
+	  </div>
+
+	</form>
+
+	<style>
+	  #meandre-buttons button:hover:enabled {
+	    background-color: #CCCC33;
+	    color: #FFFFFF;
+	  }
+	</style>
+	  
+
+	<div style="position: relative;">
+	  <iframe id="workbenchFrame" 
+		  style="width: 100%; height: 400px;" >
+	    If you see this, then your browser does not support the iframe element.
+	  </iframe>
+
+	</div>
+
+	<gsf:script src="{$httpCollection}/script/meandre-workflow/chromagram.js"/>
+	<gsf:script src="{$httpCollection}/script/meandre-workflow/js-dynamic-mix.js"/>
+	
+	<gsf:script>
+	  var chromagramMeandreWorkflow = new ChromagramMeandreWorkflow();
+	  var jsDynamicMixMeandreWorkflow = new JSDynamicMixMeandreWorkflow();
+
+	  var meandreWorkflows = [ chromagramMeandreWorkflow, jsDynamicMixMeandreWorkflow ];
+
+	  var selectedMeandreWorkflowPos =$('#meandre-workflow-pos option:selected').val();
+	  var selectedMeandreWorkflow = meandreWorkflows[selectedMeandreWorkflowPos];
+
+	  selectedMeandreWorkflow.meandreController.loadWorkbench( "workbenchFrame",selectedMeandreWorkflowPos);
+	  
+	  function loadSelectedWorkflow(elem) { 	       
+	      selectedMeandreWorkflowPos = elem.value;
+	      selectedMeandreWorkflow = meandreWorkflows[selectedMeandreWorkflowPos];
+
+	    if (selectedMeandreWorkflowPos==1) {
+	      $('#jsdynamic-turnstyle').show();
+	    }
+	    else {
+	      $('#jsdynamic-turnstyle').hide();
+	    }
+
+	    console.info("Loading in new Meandre workbench flow (pos=" + selectedMeandreWorkflowPos+ ")");		
+	    selectedMeandreWorkflow.meandreController.loadWorkbench("workbenchFrame",selectedMeandreWorkflowPos);
+
+	  }
+	</gsf:script>
+	
+
+
+
+	<div id="jsdynamic-turnstyle" style="display:none">
+	  
+	  <div style="background-image: none; background-color: rgb(80%,80%,20%);">
+	    Dynamic Javascript Meandre Component
+	  </div>
+
+	  <div class="documenttext hide" style="color: white; background-color: rgb(40%,40%,20%); padding: 8px;">
+
+	    <textarea id="js-dynamic-code" style="width:100%; height: 520px; font-size: 60%">
+	      <xsl:text disable-output-escaping="yes">
+
+
+var arrayBinding = new JavaImporter(java.lang.reflect.Array);
+
+var JSDynamicComponent = function() {
+  this.frameCount = 0;
+}
+
+JSDynamicComponent.prototype.executeCallBack = function(cc) {
+
+  with(arrayBinding) {
+
+    if ((this.frameCount % 1000)==0) {
+      print("JSDynamicComponent: " + this.frameCount + "\n");
+    }
+
+    var inputObject = cc.getDataComponentFromInput("input");
+    var rawInput1DArray = inputObject;
+
+    var rawOutput1DArray = Array.newInstance(java.lang.Double.TYPE, rawInput1DArray.length);
+
+    for (var i=1; i&lt;rawOutput1DArray.length; i++) {
+      var diff = Array.getDouble(rawInput1DArray,i) - Array.getDouble(rawInput1DArray, i-1);
+      Array.setDouble(rawOutput1DArray,i,diff);
+    }
+
+    cc.pushDataComponentToOutput("output", rawOutput1DArray);
+
+    this.frameCount++;
+  }
+
+}
+
+var jsDynamicComponent = new JSDynamicComponent();
+
+	      </xsl:text>
+	    </textarea>
+	  </div> <!-- end of Dynamic JS turnstyle block -->
+	</div>
+
+      </div>
+
+    </div>
+
+    <script>
+      <xsl:text disable-output-escaping="yes">
+	$(function(){
+	    transformToTurnstyleBlock("workflow");
+	    transformToTurnstyleBlock("jsdynamic");
+	});	
+      </xsl:text>
+    </script>
+  </xsl:template>
+
+
+  <!-- *** -->
+  <!-- * Structured audio player -->
+  <!-- *** -->
+ 
+  <xsl:template name="structuredAudioPlayerBlock">
+
+    <gsf:script src="ext/diy-audio-player/script/structured-audio-play.js"/>
+    
+    <div style="background-color: rgb(40%,40%,20%)">
+      <svg xmlns="http://www.w3.org/2000/svg" 
+           xmlns:xlink="http://www.w3.org/1999/xlink" 
+	   version="1.1"
+           id="svgGroundTruthSegments" 
+	   width="100%" height="24"
+           onLoadXX="svgGTStructuredInit()">
+      </svg>
+    </div>
+    
+    <div style="background-color: rgb(40%,40%,20%)">
+      <svg xmlns="http://www.w3.org/2000/svg" 
+           xmlns:xlink="http://www.w3.org/1999/xlink" 
+	   version="1.1"
+           id="svgContentAnalysisSegments" 
+	   width="100%" height="24"
+           onLoadXX="svgCAStructuredInit({$cgiargCAAlgorithm})">
+      </svg>
+    </div>
+  </xsl:template>
+  
+  <xsl:template name="visualization-mode-block">
+    
+    <div class="documenttext" style="color: white; background-color: rgb(40%,40%,20%); padding-top: 4px;">
+
+      <span class="vix-heading">Max Values:</span>
+      <div style="padding-left: 8px">
+	<style>
+	  span.mv-fixed { display: inline-block; width: 30pt; }
+	</style>
+	<table width="100%">
+	  <tr>
+	    <td><span class="mv-fixed" id="freqSpectrumMax"     >0.000</span>(Freq Spectrum)       </td>
+	    <td><span class="mv-fixed" id="freqPowerSpectrumMax">0.000</span>(Freq Power Spectrum) </td>
+	    <td><span class="mv-fixed" id="filterBankMax"       >0.000</span>(Filter Bank)         </td>
+	    <td><span class="mv-fixed" id="chromaFeaturesMax"   >0.000</span>(Chroma Features)     </td>
+	  </tr>
+	</table>
+      </div>
+      <hr/>
+  
+      <form style="padding-left: 8px; padding-right: 8px; padding-bottom: 0px;">
+	<div style="float: left;">
+	  <span class="vis-heading">Visualization:</span>
+<!--
+	<input type="radio" name="visualization" onclick="setTransformMode(this)" value="freqSpectrum" />Frequency Spectrum 
+	<input type="radio" name="visualization" onclick="setTransformMode(this)" value="freqPowerSpectrum"/>Frequency Power Spectrum
+-->
+	
+	  <input type="radio" name="visualization" onclick="setTransformMode(this)" value="filterBank"/>Filter Bank 
+	  <input type="radio" name="visualization" onclick="setTransformMode(this)" value="chromaFeatures" checked="checked"/>Chroma Features
+	</div>
+
+	<div style="float: left; padding-left: 140px;">
+	  <span class="vis-heading">Colour Mapping:</span>
+	  <input type="radio" name="colorMapping" onclick="setColorMappingMode(this)" value="rgb"/>RGB Intensity
+	  <input type="radio" name="colorMapping" onclick="setColorMappingMode(this)" value="hsl" checked="checked"/>HSL Heat
+	</div>
+      </form>
+      
+      <div style="clear: both; padding-top: 4px; padding-bottom: 4px;"><hr/></div>
+
+<!--
+      <form style="padding-left: 8px;">
+	<span class="vis-heading">Colour Mapping:</span>
+	<input type="radio" name="colorMapping" onclick="setColorMappingMode(this)" value="rgb"/>RGB Intensity
+	<input type="radio" name="colorMapping" onclick="setColorMappingMode(this)" value="hsl" checked="checked"/>HSL Heat Map
+      </form>
+      <hr/>
+-->
+
+	<form style="padding-left: 8px; padding-bottom: 0px;">
+	  <span class="vis-heading">On Pause:</span>
+	  <input type="checkbox" name="similarityMatrix" onclick="plotSimilarityMatrixWhenPaused(this)"/>Show Similarity Matrix
+	</form>
+	<hr/>
+
+    </div>
+    
+  </xsl:template>
+
+  <!-- *** -->
+  <!-- * Settings form -->
+  <!-- *** -->
+
+  <xsl:template name="settings-form">
+    <xsl:param name="cgiargYScaleSimImg"/>
+
+    <xsl:variable name="httpCollection">
+      <xsl:value-of select="/page/pageResponse/collection/metadataList/metadata[@name='httpPath']"/>
+    </xsl:variable>
+
+    <div id="settings-turnstyle" style="margin: 6px;">
+      <div style="background-image: none; background-color: rgb(80%,80%,20%);">
+	Audio Content Search
+      </div>
+      <div class="documenttext" style="display: none;">
+
+
+      <form id="QueryForm" name="QueryForm" method="get" action="{$library_name}">
+	<input type="hidden" name="a" value="q"/>
+	<input type="hidden" name="sa"><xsl:attribute name="value"><xsl:value-of select="/page/pageRequest/@subaction"/></xsl:attribute></input>
+	<input type="hidden" name="rt" value="rd"/>
+	
+	<input type="hidden" name="s" value="AudioQuery"/>
+	<input type="hidden" name="c" value="{$collName}"/>
+	<xsl:if test="not(paramList/param[@name='startPage'])">
+	  <input type="hidden" name="startPage" value="1"/>
+	</xsl:if>
+	<xsl:choose>
+	  <xsl:when test="/page/pageRequest/paramList/param[@name = 's1.maxDocs']">
+	    <input type="hidden" name="s1.maxDocs">
+	      <xsl:attribute name="value">
+		<xsl:value-of select="/page/pageRequest/paramList/param[@name = 's1.maxDocs']/@value"/>
+	      </xsl:attribute>
+	    </input>
+	  </xsl:when>
+	  <xsl:otherwise>
+	    <input type="hidden" name="s1.maxDocs" value="100"/>
+	  </xsl:otherwise>
+	</xsl:choose>
+	<xsl:choose>
+	  <xsl:when test="/page/pageRequest/paramList/param[@name = 's1.hitsPerPage']">
+	    <input type="hidden" name="s1.hitsPerPage">
+	      <xsl:attribute name="value">
+		<xsl:value-of select="/page/pageRequest/paramList/param[@name = 's1.hitsPerPage']/@value"/>
+	      </xsl:attribute>
+	    </input>
+	  </xsl:when>
+	  <xsl:otherwise>
+	    <input type="hidden" name="s1.hitsPerPage" value="20"/>
+	  </xsl:otherwise>
+	</xsl:choose>
+	
+	<input type="hidden" name="q">
+	  <xsl:attribute name="value"><xsl:value-of select="/page/pageResponse/document/documentNode/@nodeID"/>.dir</xsl:attribute>
+	</input>
+	
+	
+	<input type="hidden" name="s1.query">
+<!--
+	  <xsl:attribute name="value"><xsl:value-of select="/page/pageResponse/document/documentNode/@nodeID"/>.dir</xsl:attribute>
+-->
+	  <xsl:attribute name="value"><xsl:value-of select="/page/pageResponse/document/@nodeID"/>.dir</xsl:attribute>
+	</input>
+	
+	<input type="hidden" name="s1.offset" value="0" />
+	<input type="hidden" name="s1.length" value="200" />
+	
+	<div style="font-style: italics;">Start new query @ offset
+	<span id="mysongCurrentPos">0 secs</span>,
+	with excerpt lasting
+	
+	<input type="text" name="mysongWindowDuration" size="4" value="6" />
+	<!--
+	    <span id="mysongWindowDuration" class="editable-offset"
+	    style="cursor: pointer; border: 1px solid black; padding: 3px; width: 200px; min-width: 200px;">6.0</span> 
+	-->
+	secs:
+
+	<input type="submit" value="Search" onclick="preSubmit(this.form);" />
+	</div>
+
+	
+	<ul style="font-size: 80%; margin-top: 8px; font-style: italics;" >
+	  <li>Use the <b>Play all of</b> bar to get to the part of the song you are interested in.</li>
+	  <li>... the <b>query @ offset</b> value will change accordingly as the song progresses.</li>
+	  <li>Click <b>pause</b> (anywhere outside of the time-line) to mark the spot you want to start the new music query.</li>
+	  <li>Optionally click on the <b>excerpt lasting</b> value and edit, if you want to change the length of excerpt used in the match.</li>
+	  <li>Finally, click the <b>Search</b> button to initiate the new query.</li>
+	</ul>
+	
+      </form>
+
+      <hr/>
+      
+<!--
+      <form id="RescaleForm" name="RescaleForm" method="get" action="{$library_name}">
+	<div style="font-style: italics;">
+	  Make the scale factor for the y-dimension of the self-similarity
+	  image be
+	  <input type="text" name="ResizeScale" value="{$cgiargYScaleSimImg}"
+	         size="3" /> then 
+	  <input type="button" name="ResizeImage" value="Resize Image" 
+	         onclick="javascript:rescaleImage()" />
+	  
+	</div>
+      </form>
+      
+      <hr/>
+-->
+
+      <!-- **** currently not displayed -->
+
+      <form id="UpdateCAForm" name="UpdateCAForm" method="get" action="{$library_name}" style="display: none;">
+	<div style="font-style: italics;">
+	  
+	  Show the song structure automatically computed by analyzing
+	  the audio data using algorithm 
+
+	  <select id="caaMenu" name="caAlgorithm">
+	    <option value="1">BV1</option>
+	    <option value="2">BV2</option>
+	    <option value="3">GP7</option>
+	    <option value="4">MHRAG2</option>
+	    <option value="5">MND1</option>
+	    <option value="6">WB1</option>
+
+<!--
+	    <option value="-1">or hide</option>
+-->
+
+	  </select>: 
+
+	  <input type="button" name="Reload" value="Reload" 
+	         onclick="updateCAAlgorithm()" />
+
+	</div>
+      </form>
+
+	<script>
+	  <xsl:text disable-output-escaping="yes"> 
+	    if (hasStructuredAudio) {
+	      var caaMenu = document.getElementById("caaMenu");
+               caaMenu.options[caAlgorithm-1].selected = 1;
+	    }
+	  </xsl:text>
+	</script>
+      
+
+      </div>
+    </div>
+    <script>
+      <xsl:text disable-output-escaping="yes">
+	$(function(){
+	transformToTurnstyleBlock("settings");
+	});
+      </xsl:text>
+    </script>
+
+  </xsl:template>
+
+
+  <!-- *** -->
+  <!-- * Computed Data -->
+  <!-- *** -->
+
+
+  <xsl:template name="computed-data">
+    <xsl:param name="httpCollection"/>
+    <xsl:param name="assocFilePath"/>
+
+    <div id="computed-turnstyle" style="margin: 6px;">
+      <div style="background-image: none; background-color: rgb(80%,80%,20%);">
+	Computed Data
+      </div>
+
+      <div class="documenttext" style="display: none;">
+	<table class="metadata-stripes" style="width: 100%">
+	  <tbody>
+	    <tr>
+	      <td>jAudio Features</td><td><a href="{$httpCollection}/index/assoc/{$assocFilePath}/jaudio.xml">download ACE XML feature values file</a></td>
+	    </tr>
+	    
+	    <tr>
+	      <td>jSongMiner Metadata</td><td><a href="{$httpCollection}/index/assoc/{$assocFilePath}/jsongminer.xml">download ACE XML classifications file</a></td>
+	    </tr>
+	    
+	  </tbody>
+	</table>
+      </div>
+    </div>
+
+    <gsf:script>
+	$(function(){
+	  transformToTurnstyleBlock("computed");
+	});
+    </gsf:script>
+
+
+    <div id="original-turnstyle" style="margin: 6px;">
+      <div style="background-image: none; background-color: rgb(80%,80%,20%);">
+	The Original Audio
+      </div>
+
+      <div style="display: none;">
+
+	<div>
+	  <audio style="width: 100%;" id="original-audio" controls="controls" >
+	    <source src="{$httpCollection}/index/assoc/{$assocFilePath}/doc.ogg" />
+	    <source src="{$httpCollection}/index/assoc/{$assocFilePath}/doc.mp3" />
+	    <source src="{$httpCollection}/index/assoc/{$assocFilePath}/doc.wav" />
+	  </audio>
+	</div>
+
+      </div>
+    </div>
+
+    <gsf:script>
+	$(function(){
+	  transformToTurnstyleBlock("original");
+	});
+    </gsf:script>
+
+
+  </xsl:template>
+
+</xsl:stylesheet>
Index: /main/trunk/model-sites-dev/multimodal-mdl/collect/selfsim-my-ipod/REBUILD.sh
===================================================================
--- /main/trunk/model-sites-dev/multimodal-mdl/collect/selfsim-my-ipod/REBUILD.sh	(revision 28433)
+++ /main/trunk/model-sites-dev/multimodal-mdl/collect/selfsim-my-ipod/REBUILD.sh	(revision 28433)
@@ -0,0 +1,1 @@
+full-rebuild.pl  -site localsite -removeold -import:OIDtype incremental my-ipod
Index: /main/trunk/model-sites-dev/multimodal-mdl/collect/selfsim-my-ipod/etc/collectionConfig.xml
===================================================================
--- /main/trunk/model-sites-dev/multimodal-mdl/collect/selfsim-my-ipod/etc/collectionConfig.xml	(revision 28433)
+++ /main/trunk/model-sites-dev/multimodal-mdl/collect/selfsim-my-ipod/etc/collectionConfig.xml	(revision 28433)
@@ -0,0 +1,747 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<CollectionConfig xmlns:gsf="http://www.greenstone.org/greenstone3/schema/ConfigFormat" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+  <metadataList>
+    <metadata name="creator"></metadata>
+    <metadata name="maintainer"></metadata>
+    <metadata name="public">true</metadata>
+  </metadataList>
+  <displayItemList>
+    <displayItem assigned="true" lang="en" name="name">Redefining Boundaries</displayItem>
+    <displayItem assigned="true" lang="en" name="description"></displayItem>
+  </displayItemList>
+  <!-- Global format statement -->
+  <format>
+    <gsf:template name="choose-title">
+      
+      <gsf:choose-metadata>
+	<gsf:metadata name="dc.Title"/>
+	<gsf:metadata name="exp.Title"/>
+	<gsf:metadata name="ex.dc.Title"/>
+	<gsf:metadata name="ex.Title"/>
+	<gsf:metadata name="Title"/>
+	<gsf:default>Untitled</gsf:default>
+      </gsf:choose-metadata>
+      
+      <gsf:switch>
+	<gsf:metadata name='dc.Creator'/>
+	<gsf:when test='exists'>
+	  
+	  <gsf:switch>
+	    <gsf:metadata name="dc.Creator"/>
+	    <gsf:when test="notEquals" test-value="Unknown">
+	      
+	      by <i><gsf:metadata name='dc.Creator'/></i>
+	    </gsf:when>
+	  </gsf:switch>
+	  
+	</gsf:when>
+      </gsf:switch>			
+    </gsf:template>    
+  </format>
+
+  <search type="mgpp">
+    <level name="document">
+      <displayItem lang="en" name="name">document</displayItem>
+    </level>
+    <level name="section">
+      <displayItem lang="en" name="name">section</displayItem>
+    </level>
+    <defaultLevel name="document"/>
+    <index name="text">
+      <displayItem lang="en" name="name">text</displayItem>
+    </index>
+    <index name="dc.Title,ex.dc.Title,Title">
+			<displayItem lang="en" name="name">titles</displayItem>
+    </index>
+    <index name="Source">
+      <displayItem lang="en" name="name">filenames</displayItem>
+    </index>
+    <defaultIndex name="text"/>
+    <searchType name="plain"/>
+    <searchType name="simpleform"/>
+    <searchType name="advancedform"/>
+
+    
+    <!-- Search Format Statement -->
+    <format>
+      <gsf:template match="documentNode">
+
+	<gsf:variable name="cgiargFrameLength">
+	  <xsl:value-of select="/page/pageRequest/paramList/param[@name='p.frameLength']/@value"/>
+	</gsf:variable>
+
+	<xsl:variable name="cgiargYScaleSimImg"><xsl:choose>
+	  <xsl:when test="/page/pageRequest/paramList/param[@name='p.yScaleSimImg']/@value != ''"><xsl:value-of select="/page/pageRequest/paramList/param[@name='p.yScaleSimImg']/@value"/></xsl:when>
+	  <xsl:otherwise>0.5</xsl:otherwise>
+	</xsl:choose>
+	</xsl:variable>
+
+	<td valign="top">
+	  <gsf:icon type="document"/>
+	</td>
+	<td>
+	  <xsl:choose>
+	    <xsl:when test="@rank != 'NaN'">
+  	      (<script>
+	        var rank=<xsl:value-of select="@rank"/>;
+	        var perc=(rank-0.9)*100*10;
+	        document.write(perc.toFixed(1));
+	       </script>%) 
+	    </xsl:when>
+	  </xsl:choose>
+	  
+	  <xsl:choose>
+	    <xsl:when test="/page/pageResponse/service[@name='AudioQuery']">
+  	      <a>
+	        <xsl:attribute name="href"><xsl:value-of select="$library_name"/>/collection/<xsl:value-of select="/page/pageResponse/collection/@name"/>/document/<xsl:value-of select="@nodeID"/>?p.frameOffset=<xsl:value-of select="@frameOffset"/>&amp;p.frameLength=<xsl:value-of select="/page/pageRequest/paramList/param[@name='s1.length']/@value"/>&amp;p.a=q&amp;p.s=<xsl:value-of select="/page/pageResponse/service/@name"/>&amp;p.yScaleSimImg=<xsl:value-of select="$cgiargYScaleSimImg"/>
+
+	        </xsl:attribute>
+		
+                <xsl:call-template name="choose-title"/>
+	      </a>
+	    </xsl:when>
+	    <xsl:otherwise>
+	      <gsf:link>
+                <xsl:call-template name="choose-title"/>
+	      </gsf:link>
+	    </xsl:otherwise>
+	  </xsl:choose>
+	  
+	  <gsf:switch>
+	    <gsf:metadata name="artist"/>
+	    <gsf:when test="exists">
+	      by <gsf:metadata name="artist"/>
+	    </gsf:when>
+	  </gsf:switch>
+
+	  <gsf:switch>
+	    <gsf:metadata name="js.LabelledStructure"/>
+	    <gsf:when test="exists">
+	      <br/><i style="font-size: 80%">(Labelled structure: <gsf:metadata name="js.LabelledStructure"/>)</i>
+	    </gsf:when>
+	  </gsf:switch>
+	  
+	</td>
+      </gsf:template>
+    </format>
+
+  </search>
+
+  <search type="audioDB" orthogonal="true" />
+  
+  <infodb type="jdbm"/>
+
+  <import>
+    <pluginList>
+      <plugin name="ZIPPlugin"/>
+      <plugin name="GreenstoneXMLPlugin"/>
+      <plugin name="EmbeddedMetadataPlugin"/>
+      
+      <plugin name="AudioDBPlugin">
+	<option name="-compute_fft_features" value="true"/>
+	<option name="-enable_streaming" value="mp3"/>
+	<option name="-compute_mir_features" value="true"/>
+	<option name="-retrieve_mir_metadata" value="true"/>
+	<option name="-enable_cache"/>
+      </plugin>
+      
+      <plugin name="TextPlugin"/>
+      <plugin name="HTMLPlugin"/>
+      <plugin name="EmailPlugin"/>
+      <plugin name="PDFPlugin"/>
+      <plugin name="RTFPlugin"/>
+      <plugin name="WordPlugin"/>
+      <plugin name="PostScriptPlugin"/>
+      <plugin name="PowerPointPlugin"/>
+      <plugin name="ExcelPlugin"/>
+      <plugin name="ImagePlugin"/>
+      <plugin name="ISISPlugin"/>
+      <plugin name="NulPlugin"/>
+      <plugin name="OAIPlugin"/>
+      <plugin name="MetadataXMLPlugin"/>
+      <plugin name="ArchivesInfPlugin"/>
+      <plugin name="DirectoryPlugin"/>
+    </pluginList>
+  </import>
+
+  <browse>
+    <classifier name="AZCompactList">
+      <option name="-metadata" value="dc.Title;ex.dc.Title;Title"/>
+      <option name="-mingroup" value="2"/>
+      <option name="-removeprefix" value="(?i)Le|La|Les|The|A\\s+"/>
+    </classifier>
+
+    <classifier name="AZCompactList">
+      <option name="-metadata" value="dc.Creator"/>
+      <option name="-buttonname" value="Artists"/>
+      <option name="-mingroup" value="1"/>
+      <option name="-minnesting" value="40"/>
+    </classifier>
+
+    <classifier name="AZCompactList">
+      <option name="-metadata" value="dc.Title.albumtitle"/>
+      <option name="-buttonname" value="Albums"/>
+      <option name="-mingroup" value="1"/>
+      <option name="-minnesting" value="40"/>
+    </classifier>
+
+
+    <!--
+
+    <classifier name="List">
+      <option name="-metadata" value="dc.Title;Title"/>
+      <option name="-partition_type_within_level" value="approximate_size"/>
+    </classifier>
+    <classifier name="List">
+      <option name="-metadata" value="dc.Creator"/>
+      <option name="-button_name" value="Artists"/>
+      <option name="-partition_type_within_level" value="approximate_size"/>
+    </classifier>
+		
+    -->
+
+    <format>
+      <gsf:template match="documentNode">
+	<td valign="top">
+	  <gsf:link type="document">
+	    <gsf:icon type="document"/>
+	  </gsf:link>
+	</td>
+	<td valign="top">
+	  <gsf:link type="source">
+	    <gsf:choose-metadata>
+	      <gsf:metadata name="thumbicon"/>
+	      <gsf:metadata name="srcicon"/>
+	    </gsf:choose-metadata>
+	  </gsf:link>
+	</td>
+	<td valign="top">
+	  <gsf:link type="document">
+	    <!-- Defined in the global format statement -->
+	    <xsl:call-template name="choose-title"/>
+	    
+	    <gsf:switch>
+	      <gsf:metadata name="dc.Title" />
+	      <gsf:when test="equals" test-value="Unknown">
+		<br/><i>(<gsf:metadata name="Source"/>)</i>
+	      </gsf:when>
+	    </gsf:switch>
+	    
+	  </gsf:link>
+	</td>
+      </gsf:template>
+      
+      <gsf:template match="classifierNode[@classifierStyle = 'VList']">
+	<td valign="top">
+	  <gsf:link type="classifier">
+	    <gsf:icon type="classifier"/>
+	  </gsf:link>
+	</td>
+	<td valign="top">
+	  <gsf:link type="source">
+	    <gsf:choose-metadata>
+	      <gsf:metadata name="thumbicon"/>
+	      <gsf:metadata name="srcicon"/>
+	    </gsf:choose-metadata>
+	  </gsf:link>
+	</td>
+	<td valign="top">
+	  <!-- Defined in the global format statement -->
+	  <xsl:call-template name="choose-title"/>
+	  <gsf:switch>
+	    <gsf:metadata name="Source"/>
+	    <gsf:when test="exists"><br/><i>(<gsf:metadata name="Source"/>)</i></gsf:when>
+	  </gsf:switch>
+	</td>
+      </gsf:template>
+      <gsf:template match="classifierNode[@classifierStyle = 'HList']">
+	<gsf:link type="classifier">
+	  <gsf:metadata name="Title"/>
+	</gsf:link>
+      </gsf:template>
+    </format>
+  </browse>
+
+  <display>
+    <format>
+      <gsf:option name="TOC" value="false"/>
+
+      <!-- 
+	   Overwriting this template allows you to change the heading of the document.
+      -->
+      <gsf:template name="documentHeading">
+	
+	<xsl:variable name="httpCollection">
+	  <xsl:value-of select="/page/pageResponse/collection/metadataList/metadata[@name='httpPath']"/>
+	</xsl:variable>
+
+	<!-- Metadata derived from finger-printing --> 
+	
+	<xsl:call-template name="discovery-block">
+	  <xsl:with-param name="httpCollection" select="$httpCollection"/>
+	</xsl:call-template>
+
+      </gsf:template>
+
+      
+      <!-- 
+	   Overwriting this template can be used to redefine the content of the whole document. 
+	   This is useful for simple documents, but not recommended for more complex documents
+	   (e.g. hierachical and paged documents) as it can prevent any sub-sections from showing.
+      -->
+      <!-- 
+	   <gsf:template name="documentContent">
+	   <xsl:call-template name="wrappedSectionImage"/>
+	   <xsl:call-template name="wrappedSectionText"/>
+	   </gsf:template>
+      -->
+
+      <!--
+	  Overwriting this template can be used to change the content of section headings.
+      -->
+      <!--
+	  <gsf:template name="sectionHeading">
+	  <xsl:call-template name="choose-title"/>
+	  </gsf:template>
+      -->
+      
+      <!--
+	  Overwriting this template can be used to change the content of the top-level section.
+      -->
+      <!--
+	  <gsf:template name="topLevelSectionContent">
+	  <xsl:call-template name="wrappedSectionImage"/>
+	  <xsl:call-template name="wrappedSectionText"/>
+	  </gsf:template>
+      -->
+      
+      <!--
+	  Overwriting this template can be used to change the content of sections.
+      -->
+
+      <!--
+	  <gsf:template name="sectionContent">
+	  <xsl:call-template name="wrappedSectionImage"/>
+	  <xsl:call-template name="wrappedSectionText"/>
+	  </gsf:template>
+      -->
+      	
+      <xsl:template name="additionalHeaderContent">
+	
+
+	<xsl:call-template name="soundmanager2-header"/>
+	<xsl:call-template name="js-mad-header"/>
+	
+	<!-- Bespoke jquery-ui extension for turnstyle open/close blocks -->
+	<gsf:style  src="ext/jquery-ui-extra/turnstyle-block.css"/>
+	<gsf:script src="ext/jquery-ui-extra/turnstyle-block.js"/>
+	
+	<!-- The Javascript DSP files for computing chroma features in the browser -->
+	<xsl:call-template name="javascript-dsp-header"/>
+	
+
+	<!-- Javascript support for running, sending input into, monitoring, and stopping Meandre flows -->
+	<gsf:script src="ext/meandre/meandre-controller.js"/>
+
+	<gsf:style>
+	  .metadata-stripes td { padding: 4px; }
+	  .metadata-stripes tr:nth-child(odd)  {background: #CCC}
+	  .metadata-stripes tr:nth-child(even) {background: #FFF}      
+	  
+	  .vis-heading  { font-style:italic; }
+
+	  #rightSidebar { display: none; }
+	</gsf:style>
+	
+      </xsl:template>
+
+
+      <xsl:template name="documentContent">
+	
+<!--
+	<xsl:call-template name="init-document-xsl-vars"/>
+-->	
+
+	<!-- declare $httpCollection = $httpPath (for better consistency with other places in Greenstone XSL files) -->
+	<xsl:variable name="httpCollection">
+	  <xsl:value-of select="/page/pageResponse/collection/metadataList/metadata[@name='httpPath']"/>
+	</xsl:variable>
+
+	<xsl:variable name="assocFilePath"><gsf:metadata name="assocfilepath" select="root"/></xsl:variable>
+	<xsl:variable name="Source"><gsf:metadata name="Source" select="root"/></xsl:variable>
+
+	<gsf:variable name="cgiargFrameOffset">
+	  <xsl:value-of select="/page/pageRequest/paramList/param[@name='p.frameOffset']/@value"/>
+	</gsf:variable>
+
+	<gsf:variable name="cgiargFrameLength">
+	  <xsl:value-of select="/page/pageRequest/paramList/param[@name='p.frameLength']/@value"/>
+	</gsf:variable>
+
+	<xsl:variable name="cgiargYScaleSimImg"><xsl:choose>
+	  <xsl:when test="/page/pageRequest/paramList/param[@name='p.yScaleSimImg']/@value != ''"><xsl:value-of select="/page/pageRequest/paramList/param[@name='p.yScaleSimImg']/@value"/></xsl:when>
+	  <xsl:otherwise>0.5</xsl:otherwise>
+	</xsl:choose>
+	</xsl:variable>
+	
+	<!-- CAA = Content Analysis Algorithm -->
+	<xsl:variable name="cgiargCAAlgorithm">
+	  <xsl:choose>
+	    <xsl:when test="/page/pageRequest/paramList/param[@name='p.caAlgorithm']/@value != ''"><xsl:value-of select="/page/pageRequest/paramList/param[@name='p.caAlgorithm']/@value"/></xsl:when>
+	    <xsl:otherwise>1</xsl:otherwise>
+	  </xsl:choose>
+	</xsl:variable>
+
+	<!-- *** -->
+	<!-- Main Audio Player -->
+	<!-- *** -->
+
+	<div class="documenttext"> 
+	  
+	  <xsl:call-template name="audio-icon-cache"/>
+
+	  <ul class="playlist">
+	    <li class="rounded" >
+	      
+	      <gsf:script src="{$httpCollection}/script2/hybrid-audio-player.js"/>
+
+
+	      <a id="mysong" style="padding-bottom: 2px;"
+		 onclick="togglePlayVisual(document.getElementById('mainPlayButton'))"
+		 href="{$httpCollection}/index/assoc/{$assocFilePath}/doc.mp3">
+		<span>
+		  <img id="mainPlayButton" src="ext/diy-audio-player/images/play32.png" 
+		       width="32"
+		       height="32"  
+		       onmouseover="playHighlightOn(this)"
+		       onmouseout="playHighlightOff(this)"
+		       onclick="var event = arguments[0] || window.event; togglePlay(event,this)"
+		       style="vertical-align: middle;"/>
+		  Play/Pause
+		  <span id="extraPlayText"></span>
+		</span>    
+	      </a>
+	      
+	      <gsf:script src="ext/diy-audio-player/script/audioDB-play.js"/>
+
+	      <xsl:choose>
+		<xsl:when test="($cgiargFrameOffset != '-1') and ($cgiargFrameOffset != '')">
+		  
+		  <div style="background-color: rgb(40%,40%,20%)">
+		    <script type="text/javascript">
+		      <xsl:text disable-output-escaping="yes">
+
+			var frameOffsetStr=gs.variables.cgiargFrameOffset;
+			var frameLength=gs.variables.cgiargFrameLength;
+
+		      </xsl:text>
+		    </script>
+
+
+		    <svg xmlns="http://www.w3.org/2000/svg" 
+			 version="1.1"
+			 id="svgAudioDBSegments" 
+			 width="100%" height="24"
+			 onLoadXX="svgAudioDBInit()">
+		    </svg>
+		  </div>
+		</xsl:when>
+	      </xsl:choose>
+	      
+	      <xsl:call-template name="structuredAudioPlayerBlock"/>
+	      
+	      <xsl:call-template name="processingPopup"/>
+	      
+	      
+	      <div style="width: 100%; display: none;" id="doublePlay">
+		
+		<script type="text/javascript">
+		  <xsl:text disable-output-escaping="yes">
+		    
+		    // At time of writing this code, this needs to be an OGG file to work in Firefox
+		    var source = "</xsl:text><gsf:metadata name="Source" select="root"/><xsl:text disable-output-escaping="yes">";
+		    
+		    var self_sim_png = source.replace(/\.(ogg|mp3|wav)$/,".png");
+		    var collect = "</xsl:text><xsl:value-of select="/page/pageResponse/collection/@name"/><xsl:text disable-output-escaping="yes">";
+
+		  </xsl:text>
+		</script>
+
+		<gsf:script src="ext/diy-audio-player/script/similarity-matrix-play.js"/>
+
+		<audio style="width: 49%;" id="leftsong" controls="controls" >
+		  <source src="{$httpCollection}/index/assoc/{$assocFilePath}/doc.ogg" />
+		  <source src="{$httpCollection}/index/assoc/{$assocFilePath}/doc.mp3" />
+		  <source src="{$httpCollection}/index/assoc/{$assocFilePath}/doc.wav" />
+		</audio>
+		<audio style="width: 49%;" id="rightsong" controls="controls" >
+		  <source src="{$httpCollection}/index/assoc/{$assocFilePath}/doc.ogg" />
+		  <source src="{$httpCollection}/index/assoc/{$assocFilePath}/doc.mp3" />
+		  <source src="{$httpCollection}/index/assoc/{$assocFilePath}/doc.wav" />
+		</audio>
+	      </div>
+
+
+	      <!-- Real Time Analysis (RTA) audio -->
+	      <div style="width: 100%;">		
+		<audio id="rta-audio-element" style="width: 100%;">
+		  <source src="{$httpCollection}/index/assoc/{$assocFilePath}/doc.ogg"/>
+		  <source src="{$httpCollection}/index/assoc/{$assocFilePath}/doc.mp3"/>
+		  <source src="{$httpCollection}/index/assoc/{$assocFilePath}/doc.wav"/>
+		</audio>
+	      </div>
+	      
+	      <xsl:call-template name="workflow-block"/>
+
+	      <div id="controlMarker"/>
+
+	      <div id="svg-canvas-overlay" style="position: relative">
+      
+		<!-- drawing canvas -->
+		<div style="width: 100%; position: absolute; left: 0px; top: 0px;">
+		  <div style="position: relative">
+		    <div>
+		      <!-- **** better if 100% width, but issue with JS reading these values ??? -->
+		      <canvas id="freq-plot" 
+			      width="941" height="494" style="background-color: #cccccc;"></canvas>
+		    </div>
+		  </div>
+		</div>
+
+		<div style="width: 100%; position: absolute; left: 0px; top: 0px;">
+		  <div style="position: relative">
+		    <div>
+		      <!-- **** better if 100% width, but issue with JS reading these values ??? -->
+		      <canvas id="freq-plot-labels" 
+			      width="941" height="494" style="background-color: transparent"></canvas>
+		    </div>
+		  </div>
+		</div>
+
+		<!-- left/right-mix circle cursor -->
+		<div style="background-color: transparent; position: relative; left: 0px; top: 0px;">
+		  <svg xmlns="http://www.w3.org/2000/svg" 
+		       xmlns:xlink="http://www.w3.org/1999/xlink" 
+		       version="1.1"
+		       id="svgSimilarityPlay" 
+		       width="100%"
+		       onLoad="svgInitSimilarityPlay()">
+		    <g id="simPlayLineGroup" transform="scale(1.0,{$cgiargYScaleSimImg})">
+		      <!-- image loaded here, with yScaleSimImg applied to group -->
+		    </g>
+		    <g id="playtracker" transform="translate(0,0)" 
+		       onclick="dualPlay(evt)"
+		       onmousemove="playTrackerMove(evt)"
+		       onmouseout="playTrackerOff(evt)"
+		       style="visibility: hidden">
+		      <circle cx="0" cy="0" r="20"
+			      stroke="black" stroke-width="1" fill="rgba(100%,100%,50%,0.7)" />
+		      <circle cx="0" cy="0" r="1"
+			      stroke="black" stroke-width="1" fill="black" />
+		      <g transform="translate(-15,-15)" style="visibility: hidden;">
+			<image id="playtrackerBusy" 
+			       width="30" height="30"
+			       xlink:href="ext/diy-audio-player/images/wait30trans.gif" />
+		      </g>
+		      
+		      <g>
+			<g transform="rotate(-90)">
+			  <g transform="translate(-20,-25)">
+			    <text id="rightTime" style="font-size: 80%;">L: secs</text>
+			  </g>
+			</g>
+			<g transform="translate(-20,30)">
+			  <text id="leftTime" style="font-size: 80%;">R: secs</text>
+			</g>
+		      </g>
+		      
+		    </g>
+		  </svg>
+		</div>
+		
+
+	      </div><!-- end of svg-canvas-overly-->
+
+	      <xsl:call-template name="visualization-mode-block"/>
+
+	    </li>
+	  </ul>
+	  
+	  <hr/>
+
+	  <xsl:call-template name="settings-form">
+	    <xsl:with-param name="cgiargYScaleSimImg" select="$cgiargYScaleSimImg"/>
+	  </xsl:call-template>
+	  
+	  <xsl:call-template name="computed-data">
+	    <xsl:with-param name="httpCollection" select="$httpCollection"/>
+	    <xsl:with-param name="assocFilePath" select="$assocFilePath"/>
+	  </xsl:call-template>
+
+
+	  <hr/>
+
+<script>
+  <xsl:text disable-output-escaping="yes">
+    useFancyPlayer = 1;
+
+    /* if (window.location.toString().match(/fancyplayer/i)) { */
+    if (useFancyPlayer) { 
+      PP_CONFIG.usePeakData = true;
+      PP_CONFIG.useEQData = true;
+      // PP_CONFIG.useFavIcon = true;
+    }
+
+    function onFinishSP()
+    {   
+      soundManager._onfinish(); 
+      togglePlayVisual(mainPlayButton); 
+    }
+
+      var mySoundObj;
+
+    function playFromOffset(id,frameOffset) 
+    {
+      var msecOffset = 250 * frameOffset; 
+      idElem = document.getElementById(id);
+      pagePlayer.handleClick({target:idElem}); /* fake a click */
+      soundManager.stopAll();
+
+      var options = {};
+      options.position = msecOffset;
+
+      soundManager.play(id,options);
+
+      togglePlayMode = "pause";
+      playHighlightOff(document.getElementById("mainPlayButton"),32);
+    }
+
+    function preSubmit(form) 
+    {
+      var currentPosElem = document.getElementById("mysongCurrentPos");
+      var offsetInMSecs = currentPosElem.getAttribute("offsetInMSecs");
+      var frameOffset = Math.round(offsetInMSecs/250.0);
+      form.elements["s1.offset"].value = frameOffset;
+
+      //var lengthInSecs = document.getElementById("mysongWindowDuration").innerHTML;
+      var lengthInSecs = form.elements["mysongWindowDuration"].value;
+
+      var frameLength = Math.round(lengthInSecs*1000/250.0);
+      form.elements["s1.length"].value = frameLength;
+
+      return true;
+    }
+
+    function searchSubmit(frameOffset) 
+    {
+      var form = document.getElementById("QueryForm");
+
+      form.elements["s1.offset"].value = frameOffset;
+
+      //var lengthInSecs = document.getElementById("mysongWindowDuration").innerHTML;
+      var lengthInSecs = form.elements["mysongWindowDuration"].value;
+
+      var frameLength = Math.round(lengthInSecs*1000/250.0);
+      form.elements["s1.length"].value = frameLength;
+
+      form.submit();
+    }
+
+
+
+    function rescaleImage() 
+    {
+      var form = document.getElementById("RescaleForm");
+
+      var rescaleSize = form.elements["ResizeScale"].value;
+
+      var currentURL = document.location.toString();
+      var newURL;
+      if (currentURL.match(/p.yScaleSimImg=(\d+(?:\.\d+))/)) {
+        newURL = currentURL.replace(/p.yScaleSimImg=(\d+(?:\.\d+))/,"p.yScaleSimImg="+rescaleSize);
+      }
+      else {
+        var urlParts = currentURL.split("#");
+	newURL = urlParts.shift();
+        newURL += "&amp;p.yScaleSimImg="+rescaleSize;
+	newURL += "#" + urlParts.join("#");
+      }
+
+      document.location = newURL;
+    }
+
+    function updateCAAlgorithm()
+    {
+
+      var form = document.getElementById("UpdateCAForm");
+
+      var caaMenu = form.elements["caAlgorithm"];
+
+      var caIndexPos = caaMenu.options[caaMenu.selectedIndex].value
+
+      var currentURL = document.location.toString();
+      var newURL;
+      if (currentURL.match(/p.caAlgorithm=(\d+)/)) {
+        newURL = currentURL.replace(/p.caAlgorithm=(\d+)/,"p.caAlgorithm="+caIndexPos);
+      }
+      else {
+        var urlParts = currentURL.split("#");
+	newURL = urlParts.shift();
+        newURL += "&amp;p.caAlgorithm="+caIndexPos;
+	newURL += "#" + urlParts.join("#");
+      }
+
+      document.location = newURL;
+
+    }
+
+
+
+  </xsl:text>
+
+</script>
+
+
+    </div>
+  </xsl:template>
+
+
+
+
+    </format>
+  </display>
+
+  <replaceListRef id="gs2-standard"/>
+  <replaceListRef id="gs2-image" />
+  <serviceRackList>
+    <!-- comment out the following serviceRack if you want to disable OAI for this collection -->
+    <serviceRack name="OAIPMH">
+      <ListMetadataFormats>
+	<!--What metadata sets to support is collection specific. To support other metadata schema, simply add a metadataFormat element here.
+	    The support of unqualified Dublin Core metadata set is mandatory in the oai specification.
+	-->
+	<metadataFormat metadataPrefix="oai_dc">
+	  <metadataPrefix>oai_dc</metadataPrefix>
+	  <schema>http://www.openarchives.org/OAI/2.0/oai_dc.xsd</schema>
+	  <metadataNamespace>http://www.openarchives.org/OAI/2.0/oai_dc/</metadataNamespace>
+	  <!--<metadataElements>dc.Title,dc.Creator,dc.Subject,dc.Description,dc.Publisher,dc.Contributor,dc.Date,dc.Type,dc.Format,dc.Identifier,dc.Source,dc.Language,dc.Relation,dc.Coverage,dc.Rights</metadataElements>-->
+	  <mappingList>
+	    <!-- 
+		 The mapping is in the form: <publicly supported metadata name>,<mapped metadata name>, short as <A>,<B> 
+		 The first metadata name is medatory; if there is no mapped name followed, then the first name must be used by the records and
+		 searchable in the database, otherwise it is the mapped name stored in the database. The number of mapping elements matches the
+		 number of external metadata of the records. If only one name is present, the returned metadata will use this name plus the retrieved value;
+		 if both <A>,<B> are present, the returned metadata will use <A>'s name plus <B>'s value retrieved from database.
+		 
+		 **Bear in mind: if this mapping list is not present, the standard dc. metadata names (15 in total) will be used to retrieve metadata in the database.
+		 
+		 **The only case when this mapping is not present is that: 1. this metadata format is oai_dc; 2. the metadata is also stored in the database by Dublin Core's names.
+	    -->
+	    <mapping>dc:title,Title</mapping>
+	    <!-- This mapping example means that the dc.Title is requested and the value of the metadata Title, which is used in this repository, is returned as response. -->
+	  </mappingList>
+	</metadataFormat>
+      </ListMetadataFormats>
+    </serviceRack> 
+  </serviceRackList>
+</CollectionConfig>
Index: /main/trunk/model-sites-dev/multimodal-mdl/collect/selfsim-my-ipod/script2/browser-detect.js
===================================================================
--- /main/trunk/model-sites-dev/multimodal-mdl/collect/selfsim-my-ipod/script2/browser-detect.js	(revision 28433)
+++ /main/trunk/model-sites-dev/multimodal-mdl/collect/selfsim-my-ipod/script2/browser-detect.js	(revision 28433)
@@ -0,0 +1,117 @@
+var BrowserDetect = {
+	init: function () {
+		this.browser = this.searchString(this.dataBrowser) || "An unknown browser";
+		this.version = this.searchVersion(navigator.userAgent)
+			|| this.searchVersion(navigator.appVersion)
+			|| "an unknown version";
+		this.OS = this.searchString(this.dataOS) || "an unknown OS";
+	},
+	searchString: function (data) {
+		for (var i=0;i<data.length;i++)	{
+			var dataString = data[i].string;
+			var dataProp = data[i].prop;
+			this.versionSearchString = data[i].versionSearch || data[i].identity;
+			if (dataString) {
+				if (dataString.indexOf(data[i].subString) != -1)
+					return data[i].identity;
+			}
+			else if (dataProp)
+				return data[i].identity;
+		}
+	},
+	searchVersion: function (dataString) {
+		var index = dataString.indexOf(this.versionSearchString);
+		if (index == -1) return;
+		return parseFloat(dataString.substring(index+this.versionSearchString.length+1));
+	},
+	dataBrowser: [
+		{
+			string: navigator.userAgent,
+			subString: "Chrome",
+			identity: "Chrome"
+		},
+		{ 	string: navigator.userAgent,
+			subString: "OmniWeb",
+			versionSearch: "OmniWeb/",
+			identity: "OmniWeb"
+		},
+		{
+			string: navigator.vendor,
+			subString: "Apple",
+			identity: "Safari",
+			versionSearch: "Version"
+		},
+		{
+			prop: window.opera,
+			identity: "Opera",
+			versionSearch: "Version"
+		},
+		{
+			string: navigator.vendor,
+			subString: "iCab",
+			identity: "iCab"
+		},
+		{
+			string: navigator.vendor,
+			subString: "KDE",
+			identity: "Konqueror"
+		},
+		{
+			string: navigator.userAgent,
+			subString: "Firefox",
+			identity: "Firefox"
+		},
+		{
+			string: navigator.vendor,
+			subString: "Camino",
+			identity: "Camino"
+		},
+		{		// for newer Netscapes (6+)
+			string: navigator.userAgent,
+			subString: "Netscape",
+			identity: "Netscape"
+		},
+		{
+			string: navigator.userAgent,
+			subString: "MSIE",
+			identity: "Explorer",
+			versionSearch: "MSIE"
+		},
+		{
+			string: navigator.userAgent,
+			subString: "Gecko",
+			identity: "Mozilla",
+			versionSearch: "rv"
+		},
+		{ 		// for older Netscapes (4-)
+			string: navigator.userAgent,
+			subString: "Mozilla",
+			identity: "Netscape",
+			versionSearch: "Mozilla"
+		}
+	],
+	dataOS : [
+		{
+			string: navigator.platform,
+			subString: "Win",
+			identity: "Windows"
+		},
+		{
+			string: navigator.platform,
+			subString: "Mac",
+			identity: "Mac"
+		},
+		{
+			   string: navigator.userAgent,
+			   subString: "iPhone",
+			   identity: "iPhone/iPod"
+	    },
+		{
+			string: navigator.platform,
+			subString: "Linux",
+			identity: "Linux"
+		}
+	]
+
+};
+BrowserDetect.init();
Index: /main/trunk/model-sites-dev/multimodal-mdl/collect/selfsim-my-ipod/script2/hybrid-audio-player.js
===================================================================
--- /main/trunk/model-sites-dev/multimodal-mdl/collect/selfsim-my-ipod/script2/hybrid-audio-player.js	(revision 28433)
+++ /main/trunk/model-sites-dev/multimodal-mdl/collect/selfsim-my-ipod/script2/hybrid-audio-player.js	(revision 28433)
@@ -0,0 +1,215 @@
+
+Element.prototype.getElementWidth = function() {
+    if (typeof this.clip !== "undefined") {
+	return this.clip.width;
+    } else {
+	if (this.style.pixelWidth) {
+	    return this.style.pixelWidth;
+	} else {
+	    return this.offsetWidth;
+	}
+    }
+};
+
+Element.prototype.getElementHeight = function() {
+    if (typeof this.clip !== "undefined") {
+	return this.clip.height;
+    } else {
+	if (this.style.pixelHeight) {
+	    return this.style.pixelHeight;
+	} else {
+	    return this.offsetHeight;
+	}
+    }
+};
+
+
+function isDefined(v) {
+    return typeof v !== "undefined";
+}
+
+/* // ***** */
+/* Move above in to more general header file */
+
+
+// Useful shorthands
+var SVG_NS ="http://www.w3.org/2000/svg";
+var XLINK_NS = "http://www.w3.org/1999/xlink";
+
+
+var hasStructuredAudio  = false;
+var hasChromaSelfSimMap = false;
+
+var allData      = null;
+var yScaleSimImg = null;
+var caAlgorithm  = null;
+var duration     = null;
+
+var webAudioContext = null;
+//var webAudioSource = null;
+//var webAudioJSProcessor = null;
+
+if (typeof AudioContext == "function") {
+    webAudioContext = new AudioContext();
+} else if (typeof webkitAudioContext == "function") {
+    webAudioContext = new webkitAudioContext();
+}
+
+
+// ******
+// * Frequency Player/Plotter part of Hybrid Player
+// ******
+
+function freqPlayerAudioPlay(event)
+{
+    console.info("Audio play pressed");
+
+    if (audioMode == "stopped") {
+	// Nolonger used (Firefox fails to fire this event on a fresh 'play' once an existing play has finished)
+
+	// take a fresh snapshot of the transform mode selected in the web page
+
+	//var transformMode = $('input:radio[name=visualization]:checked').val();
+	//chromaTransform.setTransformMode(transformMode);
+
+    }
+    audioMode = "playing";
+}
+
+function freqPlayerAudioPause()
+{
+    console.info("Audio pause pressed");
+    audioMode = "paused";
+
+    // if stoping dualPlay
+    leftSong.pause();
+    rightSong.pause();
+    baseSong.volume = 1.0;
+
+}
+
+function freqPlayerAudioEnded()
+{
+    console.info("Audio play/playlist ended");
+
+    audioMode = "stopped";
+    needsRefresh = true;
+
+    //console.log("reset freq plot called");
+    //frequencyPlotter.reset();
+
+}
+
+// ******
+// * Meandre (server-side) workflow part of Hybrid Player
+// ******
+//
+// Started when 'play' is pressed
+
+// (workflows now in their own folder '$httpCollection/script/meandre-workflow/*.js)
+// the global variable 'meandreWorkflows' stores which flows are available
+
+
+
+
+
+// ******
+// * Structured Audio (CAA) part of Hybrid Player
+// ******
+
+function caaInit() 
+{
+    // duration information is now available
+    var audio = document.getElementById('rta-audio-element');
+    duration = audio.duration;
+    
+    if (!isDefined(allData)) {
+	// degenerate case
+	
+	var ground_truth = []; // empty ground truth
+	
+	var numSegs = 4;
+	var gap = duration/numSegs;
+	
+	var label = [ "a", "b" ];
+	var val   = [ 0, 1];
+	
+	var equal_spacing = [];
+	for (var i=0; i<numSegs; i++) {
+	    equal_spacing.push( {o: i*gap, f: i*gap+gap, l: label[i%2], a: val[i%2] } );
+	}
+
+	allData = [ ground_truth, equal_spacing ]; 
+
+	caAlgorithm = 1;
+	hasStructuredAudio = true;
+    }
+
+    svgGTStructuredInit();
+    svgCAStructuredInit(caAlgorithm);
+    svgAudioDBInit();
+}
+
+
+allData = gs.documentMetadata["json.data"];
+
+// ****
+
+// The following is actually the XSLT page param
+// 'p.yScaleSimImg;, which presumably automatically generates
+// gs.cgiParams.yScaleSimImg (if present).  Defaults to 0.5
+
+yScaleSimImg=gs.variables.cgiargYScaleSimImg || 0.5; 
+
+caAlgorithm=gs.variables.cgiargCAAlgorithm;
+
+
+$(function() {
+
+    var audio = document.getElementById('rta-audio-element');
+    audio.addEventListener('loadedmetadata', caaInit, false);
+
+    audio.addEventListener('MozAudioAvailable', freqPlayerAudioAvailable, false);
+    audio.addEventListener('loadedmetadata', freqPlayerLoadedAudioMetadata, false);
+
+    audio.addEventListener('play',  freqPlayerAudioPlay,  false);
+    audio.addEventListener('pause', freqPlayerAudioPause, false);
+    audio.addEventListener('ended', freqPlayerAudioEnded, false);
+
+
+    console.log("****### Adding dual play loadmetadata event listeners in hybrid-audio-player.js");
+    baseSong = document.getElementById("rta-audio-element");
+    baseSong.addEventListener('loadedmetadata', initPannedPlaybackSampleRate, false);
+
+    leftSong = document.getElementById("leftsong");
+    leftSong.addEventListener('MozAudioAvailable', audioAvailableLeft, false);
+    leftSong.addEventListener('loadedmetadata', loadedMetadataLeft, false);
+
+    rightSong = document.getElementById("rightsong");
+    rightSong.addEventListener('MozAudioAvailable', audioAvailableRight, false);
+    rightSong.addEventListener('loadedmetadata', loadedMetadataRight, false);
+
+
+    var controlMarkerDiv = document.getElementById("controlMarker");
+    controlMarkerDiv.addEventListener('mousedown', playFromOffsetRTAEvent, false);
+
+/*
+    var oControlDiv = controlMarker.previousSibling;
+    console.log("** ocontrol = " + oControlDiv + ",  type = " + oControlDiv.nodeType)
+    // skip over any text nodes ... (done this way to cope with browser differences)
+    while (oControlDiv && oControlDiv.nodeType != 1) {
+	oControlDiv = oControlDiv.previousSibling;
+	console.log("** in loop ocontrol = " + oControlDiv + ",  type = " + oControlDiv.nodeType)
+    }
+
+    if (oControlDiv) {
+	oControlDiv.setAttribute("onmousedown","javascript:playFromOffsetRTAEvent(event)");
+	//oControlDiv.addEventListener('mousedown', playFromOffsetRTAEvent, false);
+	//oControlDiv.addEventListener('mousedown', playFromOffsetRTAEvent, false);
+    }
+    else {
+	console.warn("Warning: failed to find SoundManager2 PagePlayer oControl div");
+    }
+*/
+
+});
Index: /main/trunk/model-sites-dev/multimodal-mdl/collect/selfsim-my-ipod/script2/main-play-notes.js
===================================================================
--- /main/trunk/model-sites-dev/multimodal-mdl/collect/selfsim-my-ipod/script2/main-play-notes.js	(revision 28433)
+++ /main/trunk/model-sites-dev/multimodal-mdl/collect/selfsim-my-ipod/script2/main-play-notes.js	(revision 28433)
@@ -0,0 +1,131 @@
+
+var playNoteOverlayMode = "paused";
+
+PhotoNote.prototype.Play = function()
+{
+    //console.log("*** Activate Play for this note!!");
+   // console.log("*** this.rect" + this.rect);
+
+    var mysong   = document.getElementById("mysong");
+    var barWidth = mysong.getElementWidth();
+
+    //var mevent = new Event();
+    //var mevent = document.createEvent("MouseEvent");
+    // mevt.initMouseEvent("click",true,true,...); 
+
+    //var selfSimImg = document.getElementById("selfSimImgId");
+    //var imgWidth   = selfSimImg.getAttribute("width");
+    //var imgHeight  = selfSimImg.getAttribute("height") * yScaleSimImg;
+    
+    var img_x = $("#selfSimImgId").offset().left;
+    var img_y = $("#selfSimImgId").offset().top;
+
+
+    var mevent = new Object();
+    mevent.pageX = img_x + this.rect.left;
+    mevent.pageY = img_y + this.rect.top;
+
+    console.log("*** toggle play mode = " + togglePlayMode);
+    console.log("*** playTrackerMode = " + playTrackerMode);
+
+/*
+    if (togglePlayMode.match("pause")) { 
+	// (counter-intuitively) means it is playing
+	if (playTrackerMode.match("playing")) {
+	    // in dualPlay() mode
+	    togglePlay(mevent,this);
+	}
+    }
+    else {
+	// 
+	dualPlay(mevent);
+    }
+*/
+
+
+
+    if (playNoteOverlayMode == "paused") {
+	playNoteOverlayMode = "playing";
+	dualPlay(mevent);
+    }
+    else {
+	playNoteOverlayMode = "paused";
+	togglePlay(mevent,this);
+    }
+  
+
+
+    // code for cancel =>
+    //this.oldRect = null;
+    //this.gui.TextTitle.innerHTML = this.gui.TextBox.value;
+    //this.text = this.gui.TextBox.value
+    //this.UnSelect();
+}
+
+PhotoNote.prototype.appendPlayElement = function()
+{
+    var currentNote = this;
+
+    var newButtonPlay = document.createElement('a');
+    newButtonPlay.setAttribute("class", "annotator-save annotator-inline");
+    newButtonPlay.innerHTML='Play';
+    newButtonPlay.onmouseover = function(){_zoomEnabled = false;};
+    newButtonPlay.onmouseout = function(){_zoomEnabled = true;};
+    newButtonPlay.onclick = function() {
+        currentNote.Play();            
+    };
+
+    this.buttonsDiv.appendChild(newButtonPlay);
+}
+
+
+
+OverlayNotes.prototype.getNotes = function(divID,metaname)
+{
+    if(gs.variables[metaname] == null || gs.variables[metaname] == undefined)
+    {
+	console.log("No photo notes");
+	return;
+    }
+    
+    for(var i = 0; i < gs.variables[metaname].length; i++)
+    {
+	var metavals = gs.variables[metaname];
+	var note = metavals[i];
+	if(!note)
+	{
+	    continue;
+	}
+
+	var newNote = new PhotoNote(note.caption, divID, i+1, new PhotoNoteRect(note.area.x,note.area.y,note.area.width,note.area.height));
+	newNote.appendPlayElement();
+
+	var that = this;
+	newNote.onsave   = function(note) { return that.saveFunction(note) };
+	newNote.ondelete = function(note) { return that.deleteFunction(note) };
+
+	this.notes.AddNote(newNote);
+	this.posCount++;
+    }
+    
+    this.addNoteOverAndOutHandlers();
+}
+
+OverlayNotes.prototype.AddNote = function()
+{
+    this.posCount++;
+
+    var photoPos = $("#"+this.divID).offset();
+    
+    var newNote = new PhotoNote('Add note text here...',this.divID,this.posCount,new PhotoNoteRect(20,20,50,50));
+    newNote.appendPlayElement();
+
+    var that = this;
+    newNote.onsave   = function(note) { return that.saveFunction(note) };
+    newNote.ondelete = function(note) { return that.deleteFunction(note) };
+    this.notes.AddNote(newNote);
+    
+    this.addNoteOverAndOutHandlers();
+    newNote.Select();
+}
+
Index: /main/trunk/model-sites-dev/multimodal-mdl/collect/selfsim-my-ipod/script2/meandre-workflow/chromagram.js
===================================================================
--- /main/trunk/model-sites-dev/multimodal-mdl/collect/selfsim-my-ipod/script2/meandre-workflow/chromagram.js	(revision 28433)
+++ /main/trunk/model-sites-dev/multimodal-mdl/collect/selfsim-my-ipod/script2/meandre-workflow/chromagram.js	(revision 28433)
@@ -0,0 +1,198 @@
+
+
+var ChromagramMeandreWorkflow = function() {
+
+    var domain_prefix = window.location.protocol + "//" + window.location.hostname;
+
+    this.meandreController = new MeandreController(domain_prefix,"1714","1712");
+
+    this.baseURI     = "http://greenstone.org/meandre/flows/chromagram-v1/";
+    this.serviceHead = "http://greenstone.org/meandre/flows/chromagram-v1/instance/greenstone-audio-web-service-head/0";
+    this.serviceTail = "http://greenstone.org/meandre/flows/chromagram-v1/instance/float32-frame-web-service-buffer/5";
+
+    this.flowPort = null;
+
+    this.meandreFrameSize = null;
+    this.meandreDataOutput = new Array();
+
+    this.meandreCount = 0;
+}
+
+
+ChromagramMeandreWorkflow.prototype.thisMeandreFlowIsRunning = function() {
+    return this.flowPort != null;
+}
+
+ChromagramMeandreWorkflow.prototype.processThisMeandreFlowOutputDataCallback = function(oEvent,oReq) {
+
+
+    var arrayBuffer = oReq.response; // Note: not oReq.responseText
+
+    if (arrayBuffer.byteLength) {
+	console.log("*** get-data callback: Recieved binary data: raw byte array buffer len = " + arrayBuffer.byteLength);
+	
+	console.log("*** type of arrayBuffer: " + toType(arrayBuffer));
+
+	var float32Array = new Float32Array(arrayBuffer); 
+
+	console.info("*** get-data callback: number of frames received = " + float32Array.length/this.meandreFrameSize);
+
+
+	// Break it up into frames
+
+	//payload.data = float32Array;
+	this.meandreDataOutput.push(float32Array);
+    }
+}
+
+
+
+ChromagramMeandreWorkflow.prototype.processThisMeandreFlowOutputData = function(flowPort) {
+
+    // does flowPort need to be passed in as a parameter, now this is method not a function?
+
+    var getinfo_options = {cmd: "get-info" };
+
+    var info_props = this.meandreController.webComponentProperties(flowPort,this.serviceTail,getinfo_options)
+
+    // values stored in 'info_props' are strings => need to make sure we treat get numeric fields such
+    // as 'numFrames' as an integer
+
+    var numFramesAvailable = parseInt(info_props.numFrames);
+    if (isDefined(numFramesAvailable)) {
+	this.meandreFrameSize = parseInt(info_props.frameSize); 
+    }
+    else {
+	numFramesAvailable = 0;
+    }
+
+//    console.log("*** Meandre count = " + meandreCount);    
+
+    if (numFramesAvailable>0) {
+
+	var getNumFrames = Math.min(1000,numFramesAvailable);
+
+	console.info("get-data request: Number of frames available = " + numFramesAvailable, ", number of frames requested = " + getNumFrames);
+
+
+
+//	console.log("***** doing a get-data");
+	var getdata_options = {cmd: "get-data", numFrames: getNumFrames };
+	var payload = this.meandreController.binaryWebComponent(flowPort,this.serviceTail,getdata_options,
+								this.processThisMeandreFlowOutputDataCallback,this);
+
+	// delay the next call to 'get-info' to give the 'get-data' a chance to reach the server
+	var that = this;
+	setTimeout(function() {
+	    that.processThisMeandreFlowOutputData(flowPort);
+	}, 400);
+
+    }
+    else {
+	console.log("*** Sending 'done' command");
+	var done_options = {cmd: "done" };
+	this.meandreController.webComponent(flowPort,this.serviceHead,done_options);
+
+	// disable 'stop' and make 'run' active again
+	$('#meandre-stop-button').attr("disabled", "disabled");
+	$('#meandre-run-button').removeAttr("disabled");
+    }
+
+    this.meandreCount++;
+}
+
+
+ChromagramMeandreWorkflow.prototype.runThisMeandreFlow = function(elem,playCallback) {
+
+    if (this.thisMeandreFlowIsRunning()) {
+	console.error("runThisMeandreFlow(): The flow is already running on port " + this.flowPort);
+	return;
+    }
+
+    var $progressElem = $('#processing');
+    var $progressTitleElem = $('#processingTitle');
+    var $progressTextElem = $('#processingText');
+
+    var displayProgress = ($progressElem.length>0) ? true : false;
+    if (displayProgress) {
+	$progressTitleElem.html("Starting Meandre Workflow ...");
+	$progressTextElem.css('display','none');
+	$progressElem.css('display','block');
+    }
+
+
+    var flow_token = this.meandreController.runFlow(this.baseURI);
+    //console.log("**** got flow token : " + flow_token);	  
+    
+    // Give the flow time to start up ...
+    var that = this;
+
+    setTimeout(function() {
+	// Now find out which port it is running on ...
+ 	var flow_props = that.meandreController.runningFlowProperties(flow_token);
+	var flow_port =  flow_props.port;
+
+	var attempts = 0;
+	while ((flow_port==null) || (flow_port <= 0)) {
+	    console.info("port returned as " + flow_port + ", trying again");
+ 	    flow_props = that.meandreController.runningFlowProperties(flow_token);
+	    flow_port =  flow_props.port;	    
+	    attempts++;
+
+	    if (attempts==10) {
+		break;
+	    }
+	}
+	
+	console.info("Running Meandre flow on port : " + flow_port);
+	that.flowPort = flow_port;
+	
+	$('#meandre-run-button').attr("disabled", "disabled");
+	$('#meandre-stop-button').removeAttr("disabled");
+	
+	//$('#meandre-run-button').button({ disabled: true });
+	//$('#meandre-stop-button').button({disabled: false});
+	
+	var start_options = { 
+	    cmd: "generate-audio-signal", 
+	    docOID: "wibble",
+	    site: gs.xsltParams["site_name"],
+	    collect: collect,
+	    assocPath: gs.documentMetadata["assocfilepath"],
+	    assocFile: "doc.wav"
+	};
+
+	that.meandreController.webComponent(that.flowPort,that.serviceHead,start_options);
+	
+	setTimeout(function() { 
+	    that.processThisMeandreFlowOutputData(that.flowPort);
+
+	    if (displayProgress) {
+		$progressElem.css('display','none');
+		$progressTextElem.css('display','block');
+	    }
+
+	    if (elem!=null) {
+		// runFlow has been triggered by clicking on the 'run' button
+		togglePlay(null,document.getElementById('mainPlayButton'));
+	    }
+	    else if (playCallback!=null) {
+		playCallback();
+	    }
+
+	}, 700);
+
+    }, 800);
+}
+
+ChromagramMeandreWorkflow.prototype.stopThisMeandreFlow = function(elem) {
+    
+    this.meandreController.abortFlow(this.flowPort);
+    
+    $('#meandre-stop-button').attr("disabled", "disabled");
+    $('#meandre-run-button').removeAttr("disabled");
+    
+    //$('#meandre-run-button').button({ disabled: false });
+    //$('#meandre-stop-button').button({disabled: true});    
+}
+
Index: /main/trunk/model-sites-dev/multimodal-mdl/collect/selfsim-my-ipod/script2/meandre-workflow/js-dynamic-mix.js
===================================================================
--- /main/trunk/model-sites-dev/multimodal-mdl/collect/selfsim-my-ipod/script2/meandre-workflow/js-dynamic-mix.js	(revision 28433)
+++ /main/trunk/model-sites-dev/multimodal-mdl/collect/selfsim-my-ipod/script2/meandre-workflow/js-dynamic-mix.js	(revision 28433)
@@ -0,0 +1,298 @@
+
+
+var JSDynamicMixMeandreWorkflow = function() {
+
+    var domain_prefix = window.location.protocol + "//" + window.location.hostname;
+
+    this.meandreController = new MeandreController(domain_prefix,"1714","1712");
+
+    this.baseURI     = "http://greenstone.org/meandre/flows/dynamic-javascript-mixer/"
+    this.serviceHead = this.baseURI + "instance/greenstone-audio-web-service-head/0";
+    this.serviceTail = this.baseURI + "instance/float32-frame-web-service-buffer/3";
+
+    this.serviceJSDynamic = this.baseURI + "instance/dynamic-javascript-computation-component/2";
+
+    this.flowPort = null;
+
+    this.meandreFrameSize = null;
+    this.meandreDataOutput = new Array();
+
+    this.meandreCount = 0;
+}
+
+
+JSDynamicMixMeandreWorkflow.prototype.thisMeandreFlowIsRunning = function() {
+    return this.flowPort != null;
+}
+
+function bin2String(array,range) {
+    var result = "";
+
+    var excerpt = range || 5000;
+
+    var lowcut = Math.min(array.length,excerpt);
+        
+    result += "low cut: " + lowcut + "\n";
+    for (var i = 0; i < lowcut; i++) {
+	result += String.fromCharCode(65+array[i]);
+	if (((i+1)%200)==0) {
+	    result += "\n";
+	}
+    }
+    
+    result += "\n";
+
+
+    var highcut = Math.max(array.length-excerpt,0);
+    result += "high cut: " + highcut + "\n";
+
+    for (var i = highcut; i < array.length; i++) {
+	result += String.fromCharCode(65+array[i]);
+	if (((i+1)%200)==0) {
+	    result += "\n";
+	}
+    }
+    result += "\n";
+
+    return result;
+}
+
+JSDynamicMixMeandreWorkflow.prototype.processThisMeandreFlowOutputDataCallback = function(oEvent,oReq) {
+
+
+    var arrayBuffer = oReq.response; // Note: not oReq.responseText
+
+    if (arrayBuffer.byteLength) {
+	//console.log("*** get-data callback: Recieved binary data: raw byte array buffer len = " + arrayBuffer.byteLength);
+
+	//console.log("*** type of arrayBuffer: " + toType(arrayBuffer));
+
+	//var float32Array = new Float32Array(arrayBuffer); 
+	var byteArray = new Uint8Array(arrayBuffer); 
+	var byteArrayLen = byteArray.length;
+
+	var fixPos = new Array();
+	for (var i=0; i<byteArrayLen; i++) {
+	    if ((byteArray[i]==10)) {
+		    // && ((i<byteArrayLen-1) && (byteArray[i+1]==13))) {
+		// Despite the 'response' from the servlet being set to content type 'application/octet'
+		// the output streamed through the server is still treated as text, and a '10' in the binary
+		// stream is changed to '13', '10'
+
+		fixPos.push(i-1); 
+	    }
+	}
+
+	var fixPosLen = fixPos.length;
+	//console.log("*** fix pos len = " + fixPosLen);
+
+	var fixedByteArrayLen = byteArrayLen - fixPosLen;
+	var fixedByteArray = new Uint8Array(fixedByteArrayLen);
+
+	var prevPos = 0;
+	var newPos = 0;
+
+	for (var i=0; i<fixPosLen; i++) {
+	    var currFixPos = fixPos[i];
+
+	    var sliceArray = byteArray.subarray(prevPos,currFixPos);
+	    fixedByteArray.set(sliceArray,newPos);
+
+	    prevPos = currFixPos+1; // shift over erroneous <CR> (char 13)
+	    newPos += sliceArray.length;
+
+	}
+
+	var remainingSliceArray = byteArray.subarray(prevPos);
+	fixedByteArray.set(remainingSliceArray,newPos);
+	
+	if ((fixedByteArray.length % 4) != 0) {
+	    console.error("Fixed Returned binary data is not a multiple of 4");
+
+	    this.meandreDataOutput.push(byteArray);
+	}
+	else {
+	    //console.log("fixed byte array len = " + fixedByteArray.length);
+
+	    var float32Array = new Float32Array(fixedByteArray.buffer); 
+
+	    //console.log("float array len = " + float32Array.length);
+
+	    var meandreFrameSize = this.meandreFrameSize;
+	    var numFramesReceived = float32Array.length/meandreFrameSize;
+	    
+	    //console.log("** meandre output frameSize = " + meandreFrameSize);
+	    console.info("*** get-data callback: number of frames received = " + numFramesReceived);
+
+	    for (var i=0; i<numFramesReceived; i++) {
+		var startPos = i*meandreFrameSize;
+		var endPos   = startPos + meandreFrameSize -1;
+		var frame = float32Array.subarray(startPos,endPos);
+	    
+		//console.log("*** frameSize=" + meandreFrameSize + ", start pos=" + startPos + ", endPos=" + endPos + ", pushing on frame of size: " + frame.length);
+
+		this.meandreDataOutput.push(frame);
+	    }	    
+	}	
+    }
+}
+
+
+
+JSDynamicMixMeandreWorkflow.prototype.processThisMeandreFlowOutputData = function(flowPort) {
+
+    // does flowPort need to be passed in as a parameter, now this is method not a function?
+
+    var getinfo_options = {cmd: "get-info" };
+
+    var info_props = this.meandreController.webComponentProperties(flowPort,this.serviceTail,getinfo_options)
+
+    // values stored in 'info_props' are strings => need to make sure we treat get numeric fields such
+    // as 'numFrames' as an integer
+
+    var numFramesAvailable = parseInt(info_props.numFrames);
+    if (isDefined(numFramesAvailable)) {
+	this.meandreFrameSize = parseInt(info_props.frameSize); 
+    }
+    else {
+	numFramesAvailable = 0;
+    }
+
+//    console.log("*** Meandre count = " + meandreCount);    
+
+    if (numFramesAvailable>0) {
+
+	var getNumFrames = Math.min(600,numFramesAvailable);
+
+	console.info("get-data request: Number of frames available = " + numFramesAvailable, ", number of frames requested = " + getNumFrames);
+
+//	console.log("***** doing a get-data");
+	var getdata_options = {cmd: "get-data", numFrames: getNumFrames };
+	var payload = this.meandreController.binaryWebComponent(flowPort,this.serviceTail,getdata_options,
+								this.processThisMeandreFlowOutputDataCallback,this);
+
+	// delay the next call to 'get-info' to give the 'get-data' a chance to reach the server
+	var that = this;
+	setTimeout(function() {
+	    that.processThisMeandreFlowOutputData(flowPort);
+	}, 800);
+
+    }
+    else {
+	console.log("*** Sending 'done' command");
+	var done_options = {cmd: "done" };
+	this.meandreController.webComponent(flowPort,this.serviceHead,done_options);
+
+	// disable 'stop' and make 'run' active again
+	$('#meandre-stop-button').attr("disabled", "disabled");
+	$('#meandre-run-button').removeAttr("disabled");
+    }
+
+    this.meandreCount++;
+}
+
+
+JSDynamicMixMeandreWorkflow.prototype.runThisMeandreFlow = function(elem,playCallback) {
+
+    if (this.thisMeandreFlowIsRunning()) {
+	console.error("runThisMeandreFlow(): The flow is already running on port " + this.flowPort);
+	return;
+    }
+
+    var $progressElem = $('#processing');
+    var $progressTitleElem = $('#processingTitle');
+    var $progressTextElem = $('#processingText');
+
+    var displayProgress = ($progressElem.length>0) ? true : false;
+    if (displayProgress) {
+	$progressTitleElem.html("Starting Meandre Workflow ...");
+	$progressTextElem.css('display','none');
+	$progressElem.css('display','block');
+    }
+
+
+    var flow_token = this.meandreController.runFlow(this.baseURI);
+    //console.log("**** got flow token : " + flow_token);	  
+    
+    // Give the flow time to start up ...
+    var that = this;
+    setTimeout(function() {
+	// Now find out which port it is running on ...
+ 	var flow_props = that.meandreController.runningFlowProperties(flow_token);
+	var flow_port =  flow_props.port;
+
+	var attempts = 0;
+	while ((flow_port==null) || (flow_port <= 0)) {
+	    console.info("port returned as " + flow_port + ", trying again");
+ 	    flow_props = that.meandreController.runningFlowProperties(flow_token);
+	    flow_port =  flow_props.port;	    
+	    attempts++;
+
+	    if (attempts==10) {
+		break;
+	    }
+	}
+
+	console.info("Running Meandre flow on port : " + flow_port);
+	that.flowPort = flow_port;
+	
+	$('#meandre-run-button').attr("disabled", "disabled");
+	$('#meandre-stop-button').removeAttr("disabled");
+	
+	//$('#meandre-run-button').button({ disabled: true });
+	//$('#meandre-stop-button').button({disabled: false});
+	
+
+	// send over the user's custom javascript
+	var script_str = $("#js-dynamic-code").val();
+
+	var script_options = { 
+	    code: encodeURIComponent(script_str) // effectively double encode to get it through the proxy-server
+	};
+
+	that.meandreController.webComponent(that.flowPort,that.serviceJSDynamic,script_options);
+
+
+	var start_options = { 
+	    cmd: "generate-audio-signal", 
+	    docOID: "wibble",
+	    site: gs.xsltParams["site_name"],
+	    collect: collect,
+	    assocPath: gs.documentMetadata["assocfilepath"],
+	    assocFile: "doc.wav"
+	};
+
+	that.meandreController.webComponent(that.flowPort,that.serviceHead,start_options);
+	
+	setTimeout(function() { 
+	    that.processThisMeandreFlowOutputData(that.flowPort);
+
+	    if (displayProgress) {
+		$progressElem.css('display','none');
+		$progressTextElem.css('display','block');
+	    }
+
+	    if (elem!=null) {
+		// runFlow has been triggered by clicking on the 'run' button
+		togglePlay(null,document.getElementById('mainPlayButton'));
+	    }
+	    else if (playCallback!=null) {
+		playCallback();
+	    }
+
+	}, 800);
+
+    }, 800);
+}
+
+JSDynamicMixMeandreWorkflow.prototype.stopThisMeandreFlow = function(elem) {
+    
+    this.meandreController.abortFlow(this.flowPort);
+    
+    $('#meandre-stop-button').attr("disabled", "disabled");
+    $('#meandre-run-button').removeAttr("disabled");
+    
+    //$('#meandre-run-button').button({ disabled: false });
+    //$('#meandre-stop-button').button({disabled: true});    
+}
+
Index: /main/trunk/model-sites-dev/multimodal-mdl/collect/selfsim-my-ipod/transform/pages/about.xsl
===================================================================
--- /main/trunk/model-sites-dev/multimodal-mdl/collect/selfsim-my-ipod/transform/pages/about.xsl	(revision 28433)
+++ /main/trunk/model-sites-dev/multimodal-mdl/collect/selfsim-my-ipod/transform/pages/about.xsl	(revision 28433)
@@ -0,0 +1,525 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE videocollection [
+  <!ENTITY ndash "&#8211;">
+  <!ENTITY mdash "&#8212;">
+]>
+<xsl:stylesheet version="1.0"
+	xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+	xmlns:java="http://xml.apache.org/xslt/java"
+	xmlns:util="xalan://org.greenstone.gsdl3.util.XSLTUtil"
+	xmlns:gslib="http://www.greenstone.org/skinning"
+	extension-element-prefixes="java util"
+	exclude-result-prefixes="java util">
+
+	<!-- use the 'main' layout -->
+	<xsl:include href="layouts/main.xsl"/>
+
+	<!-- set page title -->
+	<xsl:template name="pageTitle"><gslib:collectionName/></xsl:template>
+
+	<!-- set page breadcrumbs -->
+	<xsl:template name="breadcrumbs"><gslib:siteLink/><gslib:rightArrow/></xsl:template>
+
+	<!-- the page content -->
+	<xsl:template match="/page">
+  
+		<!--Display the description text of the current collection,
+		and if some services are available then create a list
+		of links for each service within a <ul id="servicelist"> element.-->
+
+    <xsl:variable name="httpPath"> 
+      <xsl:value-of select="/page/pageResponse/collection/metadataList/metadata[@name='httpPath']" />
+    </xsl:variable>
+
+
+    <style>
+      p.about { text-align: justify; }
+      h2 { /* line-height: 135%; */ }
+      h3 { margin-top: 4pt; margin-bottom: 7pt; line-height: 135%; }
+
+        a.mashup {text-decoration: none; } 
+	a.mashup:link    {color:#000080;}  /* unvisited link */
+	a.mashup:visited {color:#303080;}  /* visited link */
+	a.mashup:hover   {color:#000040;}  /* mouse over link */
+	a.mashup:active  {color:#0000a0;}
+
+    </style>
+
+
+    <script src="{$httpPath}/script/browser-detect.js" type="text/javascript">
+	/* space filler needed */
+    </script>
+
+
+<div style="width: 800px; margin-left: auto; margin-right: auto;">
+
+
+<h2>A Musical Web Observatory: </h2>
+
+<h3><i><font size="+2">Connecting People with Data, Documents, and Algorithms</font></i></h3>
+
+<div style="background-color: #DD3611; color: white; padding: 4pt; margin-bottom: 6pt;">
+<table>
+
+  <tr>
+    <td>
+       <img src="{$httpPath}/images/firefox-128.png" />
+    </td>
+    <td>
+	<p class="about">
+	  <i><font size="+2">
+	    An experiment with Firefox's Advanced
+	    Audio Processing Extension ...
+	  </font></i>
+	</p>
+
+	<p class="about">
+	  <i><font size="+2">
+... featuring a mash-up of 
+<a class="mashup" href="http://www.greenstone.org" target="_blank">Greenstone</a>,
+<a class="mashup" href="http://www.omras2.org/audioDB" target="_blank">AudioDB</a>, and
+<a class="mashup" href="http://seasr.org/meandre/" target="_blank">Meandre</a>.
+	  </font></i>
+	</p>
+
+
+          <div id="bd-version" style="display:none;" class="about">
+	    <p>
+	      <img src="{$httpPath}/images/warning-icon.png" />
+	        Version of Firefox detected:
+	          <script type="text/javascript">
+	            document.write(BrowserDetect.version);
+	          </script>
+	    </p>
+	    <p>
+            You need to upgrade to a more recent version of Firefox 
+	        (v4.0 or greater) to access all the audio features of 
+	        this demonstration.
+	    </p>
+          </div>
+
+          <div id="bd-browser" style="display:none;" class="about">
+
+	    <p>
+	      <img src="{$httpPath}/images/warning-icon.png" />
+Browser detected:
+	      <script type="text/javascript">
+	        document.write(BrowserDetect.browser);
+	      </script>
+ 	    </p>
+            <p>You need to access this web-site using Firefox 
+	        (v4.0 or greater) to access all the audio features provided.
+	    </p>
+          </div>
+
+
+
+
+  <script>
+    <xsl:text disable-output-escaping="yes">
+
+if (BrowserDetect.browser == "Firefox") {
+  if (BrowserDetect.version &lt; 4) {
+    document.getElementById("bd-version").style.display="block";
+
+  }
+}
+else {
+  document.getElementById("bd-browser").style.display="block";
+
+}
+      </xsl:text>
+    </script>
+
+
+
+
+    </td>
+  </tr>
+</table>
+</div>
+
+<p class="about">This project is currently work in progress.  The sequence of development so far has been:
+
+<style>
+  li { padding-bottom: 10px; }
+
+</style>
+
+
+<ol>
+  <li>
+  <i>Starting point:</i> Manual (command-line) aggregation of disparate
+    resources prior to building the DL.  A set of bespoke Greenstone
+    document processing plugins corrals the heterogeneous gathered
+    data into a unified (homogeneous) canonical form that the DL can
+    access and display.  Everything presented in the DL is
+    either pre-computed (such as the self-similarity heat-maps) or else
+    computed at build-time.
+  </li>
+
+   <li>
+     <i>Audio-fingerprinting:</i> as before, but now metadata about the audio
+     songs is now enriched through a set of audio-fingerprinting web
+     services.  Everything presented in the DL is still pre-computed
+     or else computed at build-timeâhowever,  the inclusion in the document
+     view of a &quot;Discovery&quot; block allows a user to begin to
+     access and explore through linked-data, information related to
+     the song.
+   </li>
+
+  <li>
+    <i>Client-side audio processing (and visualization):</i> the
+    Pre-computed self-similarity heat-maps are dropped from the
+    collection building process in preference for the same information
+    being computed through Javascript running in the user's web
+    browser.
+  </li>
+
+  <li>
+    <i>Embedded Meandre workflows:</i> the Meandre Workbench is
+    integrated into Greenstone.  Audio documents in the Greenstone
+    digital library can now be dispatched and be processed by the
+    selected Meandre, and output from the workflow returned to the
+    Greenstone document viewâfor example, playing audio that has been
+    processed and output from the workflow.
+  </li>
+
+  <li>
+    <i>Client-side workflows:</i> the client-side Javascript
+    processing code is refactored to follow the same methodology as
+    Meandre components.
+  </li>
+
+  <li>
+    <i>Client/Server hybrid workflows:</i> the Greenstone/Meandre
+    integration is extended to support the dynamic 
+    transmission of <tt>executeCallBack()</tt> methods written 
+    in the user's browser in Javascript to be run on the
+    Meandre server as part of the active workflow.
+  </li>
+
+  <li>
+    <i>Forging ahead:</i> the next area to be worked on is upgrading
+    the level of Greenstone/Meandre integration so that data produced
+    by the workflows can be incorporated back into the underlying
+    digital library itself, rather than being (as it currently stands)
+    transitory data that only lives for the duration of the web page
+    being viewed.  This will form an implementation stepping-stone to
+    a more generalized ability to have data retrieved from other
+    external resources (located through the Discovery block
+    linked-data portion of the document view) ingested in to the DL
+    collection.
+  </li>
+
+
+</ol>
+
+</p>
+
+
+
+<!--
+
+<p class="about">This digital library collection demonstrates the
+integration of a variety of sources of structural metadata from both
+automatically derived content analysis and manually labelled
+ground-truth data to form a rich interactive web application suitable
+for musicologists (as the target end-users) to explore a collated set
+of music files.</p>
+
+<p class="about">While the base digital library system, <a
+href="http://www.greenstone.org" target="_blank">Greenstone</a>, is
+designed to operate with any web browser, the audio features this
+particular DL collection demonstrates relies on audio processing
+features currently only available in Firefox.  Using one of the other
+web browsers you will be able to access most features of the digital
+library collection, but when you access a particular song you may find
+playing the audioâin particular the panned audio
+effectâdoes not work.</p>
+-->
+
+
+<!--
+<p class="about">The developed system combines the open source capabilities of
+Greenstone, \cite{Greenstone}, NEMA \cite{Nema}, Salami \cite{Salami},
+and AudioDB \cite{AudioDB}.
+
+%%
+NEMA and Salami have been previously described in this article, and contribute 
+manual and audio content based metadata.
+%%
+AudioDB is a raw-audio content based searching algorithm based on Local-Sensitivity Hashing \cite{LSH}.
+%%
+Greenstone is a versatile digital library architecture with an
+extensible service-based architecture that.  In
+addition to the text-based searching and browsing capability to
+organize content, Greenstone provides the framework in which to harness the
+structural metadata from NEMA and Salami, and the audio-content based
+search functionality of audioDB.
+
+-->
+
+
+
+<h3>A Walkthrough</h3>
+
+
+<p class="about">The following walkthrough is for the initial incarnation of the DL collection, where all
+the information presented is either precomputed or computed at build time.</p>
+
+<p class="about">Taking as a starting point a set of music files identified as worthy
+of study, the <a href="#browse">figure below</a> shows the result of browsing
+the formed digital library collection <a href="dev?a=b&amp;rt=s&amp;s=ClassifierBrowse&amp;c=salami-audioDB&amp;cl=CL1" target="_blank">by title</a> from a web browser.
+The figure is a useful snapshot in which to orientate ourselves with
+the main structure and features to the digital library.  Functionality that
+persistently reoccurs is accessible through the header to the page.</p>
+
+<p class="about">This includes:
+<ul>
+
+<li>help and preferences (top-right);</li>
+<li>a quick-search option (located just
+below) with links to more sophisticated searching options; and</li>
+<li>pin-pointing where within the site a user is currently located
+(top-left).</li>
+</ul>
+
+
+<a name="browse" />
+<table style="width: 700px; margin-left: auto; margin-right: auto; margin-bottom: 6pt;">
+  <tr>
+    <td style="border: solid 1px;">
+      <img style="width: 700px" src="{$httpPath}/images/figs/cropped/salami-browse.png" />
+    </td>
+  </tr>
+  <tr style="background-color: #bbeebb">
+    <td>
+      <i>Browsing in the digital library
+  <a href="dev?a=b&amp;rt=s&amp;s=ClassifierBrowse&amp;c=salami-audioDB&amp;cl=CL1" target="_blank">by titles</a>.</i>
+    </td>
+  </tr>
+</table>
+
+
+The specific content to this location within the site (in this case
+browsing by title) is shown beneath the main banner.  Various
+groupings of title can be accessed by clicking on the bookshelf icons
+vertically aligned as the main part of the page: currently <a
+href="dev?a=b&amp;rt=s&amp;s=ClassifierBrowse&amp;c=salami-audioDB&amp;cl=CL1#CL1.2">CâD</a>
+is open, with the remaining letters to the alphabet below this,
+accessed through scrolling.</p>
+
+
+
+
+<p class="about">Interested in the song <i>Candela</i> our curious musicologist clicks
+on <a href="dev?a=d&amp;ed=1&amp;book=off&amp;c=salami-audioDB&amp;d=D145&amp;dt=simple&amp;sib=1&amp;p.a=b&amp;p.sa=&amp;p.s=ClassifierBrowse" target="_blank">the link for this</a>.  This brings up the document view to this song:</p>
+
+<a name="self-similarity" />
+<table style="width: 700px; margin-left: auto; margin-right: auto; margin-bottom: 6pt;">
+  <tr>
+    <td style="border: solid 1px;">
+      <img style="width: 700px" src="{$httpPath}/images/figs/cropped/salami-self-similarity2.png" />
+    </td>
+  </tr>
+  <tr style="background-color: #bbeebb">
+    <td>
+      <i>The <a href="dev?a=d&amp;ed=1&amp;book=off&amp;c=salami-audioDB&amp;d=D145&amp;dt=simple&amp;sib=1&amp;p.a=b&amp;p.sa=&amp;p.s=ClassifierBrowse" target="_blank">musicologically enriched document view</a> for</i> Candela.
+    </td>
+  </tr>
+</table>
+
+<p class="about">Normally in a digital
+library the document view brings up a page that is strongly derived
+from textual metadata.  If the document viewed was a text-document,
+some summary information such as title and author is typically
+presented, say in tabular form, before the main text is presented.
+Even in the case of multimedia digital libraries, the view presented
+is still strongly derived from textual metadata: this time including
+details such as the length of the video, the TV company that produced
+it, whether captions are available, and so forth, accompanied with an
+embedded video player for viewing the contentâessentially more
+textual metadata (in this case the URL to the video content) which in
+terms of the user-interface is largely divorced from the other
+elements displayed on the page.</p>
+
+<p class="about">This contrasts sharply with the document view developed in this
+digital library.
+Naturally it allows the song to be played (akin to the embedded video player),
+however this is largely of secondary importance to the 
+other functionality available this is much more closely
+integrated.</p>
+
+<p class="about">The most striking visual component to the document view is a
+self-similarity &quot;heat map&quot; where the duration of the song forms both
+the <i>x</i>- and <i>y</i>-axis, and a red pixel located at a given <i>(x,y)</i>
+co-ordinate in the map represents a location where two parts of the
+song are strongly similar, proportionally shifting to blue to
+represent dissimilar.  Given this configuration, the leading diagonal
+to the matrix (<i>x=y</i>) is always coloured red as this represents the
+comparison of one part of the song with itself.</p>
+
+<p class="about">When the user moves the mouse cursor around the self-similarity map
+a highlighting circle is shown to emphasize the area the user is over,
+with a black dot at the centre (visible in in
+the <a href="#self-similarity">above figure</a>); annotated vertically
+and horizontally are the two time-offsets in seconds that that point
+in the map corresponds to.  Clicking the cursor at this point results
+in the audio being played <i>simultaneously</i> from these two points.
+To aid the musicologist in listening to the two parts of the song, one
+part is panned to the left speaker, and the other to the right (this
+was implemented using the extended audio API provided by Firefox, and
+so this particular feature only work when viewing the collection with
+this browserâsee implementation details below).  In our figure,
+the musicologist has zeroed in the location <i>x=33</i>, <i>y=97</i>
+which corresponds to the start of a strong red diagonal that occurs
+some distance off the leading diagonal.  Listening to the two sounds
+played (most reliably done with headphones on), they hear that these
+two sections of the song are indeed repeating sections of the guitar
+piece <i>Candela</i> with a minor variation in the latter section
+where a recorder is also playing in the arrangement.</p>
+
+<p class="about">The structured audio time-lines (labelled A, B, ..., and 6, 5, 2,
+... in the figure) located above the self-similarity map are another
+area of enriched musical content in the digital library. The upper
+line shows the ground-truth data for this song generated by
+the <a href="http://www.music-ir.org/?q=node/14" target="_blank">Salami project</a>;
+the lower line is generated by an algorithmically based content
+analysis algorithm.</p>
+
+<p class="about">While there is some agreement between these two lines, there are
+also significant differences.  The play and search buttons within the
+structured time-lines (the latter represented by a magnifying glass)
+allow the user to investigate further these structures.  We shall
+return to the search functionality shortly (which is content based,
+using <a href="http://omras2.doc.gold.ac.uk/software/audiodb/" target="_blank">AudioDB</a>),
+but in the meantime note that with the time-lines positioned above the
+self-similarity map, there is further opportunity to study the
+differences between the two structured time-line.  It is certainly the
+case that there are strong visual cues in the map that line up with
+the algorithmic time-line, even though they do not align with a
+boundary in the ground-truth data, and the user can click on these
+parts of the similarity map to hear what is occurring at these
+points.</p>
+
+
+
+<a name="resultspage" />
+<table style="width: 700px; margin-left: auto; margin-right: auto; margin-bottom: 6pt;">
+  <tr>
+    <td style="border: solid 1px;">
+      <img style="width: 350px" src="{$httpPath}/images/figs/cropped/salami-audiodb-search-resultspage-halfcut.png" />
+    </td>
+    <td style="border: solid 1px;">
+      <img style="width: 350px" src="{$httpPath}/images/figs/cropped/salami-structured-search-resultspage-halfcut.png" />
+    </td>
+  </tr>
+  <tr style="background-color: #bbeebb">
+    <td colspan="2">
+      <i>Audio content based search results: left) the 
+	<a href="dev?a=q&amp;sa=&amp;rt=rd&amp;s=AudioQuery&amp;c=salami-audioDB&amp;startPage=1&amp;s1.maxDocs=100&amp;s1.hitsPerPage=20&amp;q=D206.dir&amp;s1.query=D206.dir&amp;s1.offset=263&amp;s1.length=24&amp;mysongWindowDuration=6" target="_blank">result list</a> from
+      an audio content based query taken from an extract of </i>
+      Michelle; <i>and right)
+      the <a href="dev?a=q&amp;sa=&amp;rt=rd&amp;s=TextQuery&amp;c=salami-audioDB&amp;startPage=1&amp;s1.query=%22b+b+c+b+c%22&amp;s1.index=JS" target="_blank">result of a structured music search</a> for
+      content containing &quot;b b c b a&quot; as a sequence.</i>
+    </td>
+  </tr>
+</table>
+
+<p class="about">Returning to the search capability provided by the structured
+time-lines, the <a href="#resultspage">above figure (left)</a> show the result of
+using this feature while study the song <i>Michelle</i> by The
+Beatles.  In this case the user selected the section of the
+ground-truth time-line corresponding to section starting &quot;I want you
+...&quot;, but could have equally used the algorithmically calculated
+time-line, or in fact paused the song playing at any point, and
+started a match from there.</p>
+
+
+<p class="about">Not surprisingly <i>Michelle</i> is returned as the top hit (at
+92.1%)âwe shall see shortly that this is because the system found
+several sections of the song that matched thisâthe next hit being
+<i>Bigger Than JC</i> at 74.4%, and so on down, where only one hit
+per song occurs.  Clicking on the top hit,
+the <a href="#audiodb">figure below</a> shows the document view that is
+displayed, focusing in on the key area to this screen.  This time the
+time-line area has an additional bar: the points within the song that
+AudioDB found to be similar.  Like the other time-lines, a play button
+is present on these segments so the user can play the matching points
+directly.  In this case
+clicking on them reveals the matching sections found correspond to
+melodically repeating sections of the song, only with different lyrics
+(&quot;I love you ...&quot; and &quot;I need you ...&quot;).</p>
+
+
+<p class="about">A further form of musical content-based searching is available through
+the main header to the digital library.  Instead of searching by title
+or artist (which are also available) the user can click on this
+&quot;search by&quot; menu next to the quick-search text box and select
+&quot;ground-truth structure&quot; instead.
+The <a href="#resultspage">figure above</a> (right) shows the result of using this
+option, where the user has entered &quot;b b c b c&quot; as the query, in
+other words searching for songs that have two sections in a row the
+same, then a new section, then returning to the original section,
+before progressing to a recurrence of the second distinct section.  In
+pop and rock music this is a popular sequence corresponding to verse,
+verse, chorus, verse, chorus.  A more intriguing framing of a query
+along these linesâequally possible in the digital libraryâwould be
+to go to the fielded search page (accessible through the <i>advanced
+  search</i> link below the quick-search box, and entered the same
+music structure query, but this time combine it with other fielded
+query terms (Genre=Blues OR Jazz, Year&lt;1950).  Results from this
+query would let the musicologist explore potential evidence of this
+pattern of sections being used in two of the key musical genres that
+influenced the development of Rock and Roll music.</p>
+
+
+<a name="audiodb" />
+<table style="width: 700px; margin-left: auto; margin-right: auto; margin-bottom: 6pt;">
+  <tr>
+    <td style="border: solid 1px;">
+      <img style="width: 700px" src="{$httpPath}/images/figs/cropped/salami-audiodb-search2.png" />
+    </td>
+  </tr>
+  <tr style="background-color: #bbeebb">
+    <td>
+      <i>The document view for</i> Michelle <i><a href="dev?a=d&amp;c=salami-audioDB&amp;d=D206&amp;dt=simple&amp;p.frameOffset=133,393,264,262,392&amp;p.frameLength=24&amp;p.a=q&amp;p.s=AudioQuery&amp;hl=on&amp;ed=1#D206" target="_blank">augmented with the locations of the matches</a> of the audio query.</i>
+    </td>
+  </tr>
+</table>
+
+
+
+
+<h3>Implementation details</h3>
+
+<p class="about">The core part of the interactive elements in the document view were
+implemented using SVG combined with Javascript.  The left- and
+right-panning interactively available from the self-similarity map was
+implemented by processing the raw audio stream, made accessible by the
+Firefox Audio extension
+<a href="https://wiki.mozilla.org/Audio_Data_API" target="_blank">API</a>.</p>
+
+<p class="about">AudioDB content based searching was integrated into Greenstone through
+two components of the digital library software architecture: its
+build-time document processing plugin system, and its runtime
+message-passing service-base framework.  The developed plugin accepts
+a wide range of audio formats (including OGG and MP3), and converts
+them to WAV, the format needed by AudioDB for processing.  The new
+search service took the form of a proxy, accepting messages in the
+XML syntax used by Greenstone, turning them into the necessary calls
+to the AudioDB command-line interface, and then converting the output
+from AudioDB back into the XML syntax expected by the digital library
+architecture.  Finally, the two parts were packaged to operate as a
+Greenstone extension; the software is available at:
+<a href="http://trac.greenstone.org/gs3-extensions/audioDB/trunk/src" target="_blank">http://trac.greenstone.org/gs3-extensions/audioDB/trunk/src</a>.</p>
+
+</div>
+
+
+	</xsl:template>
+
+
+</xsl:stylesheet>  
+
Index: /main/trunk/model-sites-dev/multimodal-mdl/collect/selfsim-my-ipod/transform/pages/document.xsl
===================================================================
--- /main/trunk/model-sites-dev/multimodal-mdl/collect/selfsim-my-ipod/transform/pages/document.xsl	(revision 28433)
+++ /main/trunk/model-sites-dev/multimodal-mdl/collect/selfsim-my-ipod/transform/pages/document.xsl	(revision 28433)
@@ -0,0 +1,895 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet version="1.0"
+	xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+	xmlns:java="http://xml.apache.org/xslt/java"
+	xmlns:util="xalan://org.greenstone.gsdl3.util.XSLTUtil"
+	xmlns:gslib="http://www.greenstone.org/skinning"
+	xmlns:gsf="http://www.greenstone.org/greenstone3/schema/ConfigFormat"
+	xmlns:xlink="http://www.w3.org/1999/xlink" 
+	extension-element-prefixes="java util"
+	exclude-result-prefixes="java util gsf">
+  
+
+  <!-- *** -->
+  <!-- Document header -->
+  <!-- *** -->
+
+  <xsl:template name="soundmanager2-header">
+
+    <!-- soundManager2 API -->
+    <gsf:style src="ext/sound-manager2/css/flashblock.css" />  
+    <gsf:script src="ext/sound-manager2/script/soundmanager2-nodebug.js"/>
+
+    <!-- The Page player (variant of SoundManger) main script -->
+    <gsf:script src="ext/sound-manager2/script/page-player.js"/>
+    <gsf:style src="ext/sound-manager2/css/page-player.css" />
+        
+    <!-- optional: annotations/sub-tracks/notes, and alternate themes -->
+    <gsf:style src="ext/sound-manager2/css/optional-annotations.css" />
+    <gsf:style src="ext/sound-manager2/css/optional-themes.css" />
+
+    <!-- optional: Metadata UI prototype (not needed unless you want the bottom-most demo bits) -->
+    <gsf:script src="ext/sound-manager2/script/optional-page-player-metadata.js"/>
+    
+    <gsf:style>
+      ul.playlist li .comment {font-size:0.65em;opacity:0.5}
+    </gsf:style>
+    
+    <!-- Customization of page-player for this collection -->
+
+    <gsf:script>
+
+      soundManager.flashVersion = 9;
+      soundManager.preferFlash = true;        /* for visualization effects */
+      soundManager.useHighPerformance = true; /* keep flash on screen, boost performance */
+      soundManager.wmode = "transparent";     /* transparent SWF, if possible */
+      soundManager.useFastPolling = true;     /* increased JS callback frequency */
+      soundManager.url = "ext/sound-manager2/swf/";
+
+      /* custom page player configuration */
+
+      var PP_CONFIG = {
+        autoStart:       false,  /* begin playing first sound when page loads */
+	playNext:        false,  /* stop after one sound, or play through list until end */
+	useThrottling:   false,  /* try to rate-limit potentially-expensive calls (eg. dragging position around) */
+	usePeakData:     true,   /* [Flash 9 only] whether or not to show peak data (left/right channel values) - nor noticable on CPU */
+	useWaveformData: false,  /* [Flash 9 only] show raw waveform data - WARNING: LIKELY VERY CPU-HEAVY */
+	useEQData:       false,  /* [Flash 9 only] show EQ (frequency spectrum) data */
+	useFavIcon:      false,  /* try to apply peakData to address bar (Firefox + Opera) - performance note: appears to make Firefox 3 do some temporary, heavy disk access/swapping/garbage collection at first(?) - may be too heavy on CPU */
+	useMovieStar:    true    /* Flash 9.0r115+ only: Support for a subset of MPEG4 formats. */
+      }
+    </gsf:script>
+  </xsl:template>
+
+
+  <!-- CAA = Content Analysis Algorithm -->
+  <xsl:variable name="cgiargCAAlgorithm">
+    <xsl:choose>
+      <xsl:when test="/page/pageRequest/paramList/param[@name='p.caAlgorithm']/@value != ''"><xsl:value-of select="/page/pageRequest/paramList/param[@name='p.caAlgorithm']/@value"/></xsl:when>
+      <xsl:otherwise>1</xsl:otherwise>
+    </xsl:choose>
+  </xsl:variable>
+
+  <!-- *** -->
+  <!-- The Javascript DSP files for computing chroma features in the browser -->
+  <!-- *** -->
+
+  <xsl:template name="javascript-dsp-header">
+    <gsf:script src="ext/js-dsp/dsp-custom.js"/>
+    <gsf:script src="ext/js-dsp/chroma-transform.js"/>
+    <gsf:script src="ext/js-dsp/frequency-plotter.js"/>
+    <gsf:script src="ext/js-dsp/frequency-player.js"/>
+
+
+    <gsf:script src="ext/js-dsp/component/crockford-inheritance.js"/>
+    <gsf:script src="ext/js-dsp/component/workflow-core.js"/>
+    <gsf:script src="ext/js-dsp/component/audio-mixer.js"/>
+    <gsf:script src="ext/js-dsp/component/wf-freq-spectrum.js"/>
+    <gsf:script src="ext/js-dsp/component/wf-filter-bank.js"/>
+    <gsf:script src="ext/js-dsp/component/wf-chroma-transform.js"/>
+    <gsf:script src="ext/js-dsp/component/active-workflow.js"/>
+
+  </xsl:template>
+
+  <xsl:template name="processingPopup">
+    <div>
+      <style type="text/css">	
+	#processing { 
+	  width: 100%; 
+	  height: 100%; 
+	  position: absolute; 
+	  z-index: 10; 
+	  left: 0px; 
+	  top: 0px; 
+	  background-color: rgba(255,255,255,0.75); 
+	  opacity: 1; 
+	  display: none;
+	}
+
+	#processingMessage { 
+	  position: absolute;
+	  padding: 10px;
+	  border-radius: 10px; 
+	  margin-left: 50%; 
+	  width: 380px; 
+	  height: 105px; 
+	  left: -250px; top: 200px; 
+	  background-color: rgba(255,255,255,1);
+	  box-shadow: 0px 0px 30px rgba(0,0,0,0.8); 
+	}
+
+	#processingMessage p { 
+	  font-size: 18px; 
+	  text-align: center; 
+	  font-family: 
+	  sans-serif; 
+	  font-weight: bold; 
+	  color: #666; 
+	}
+      </style>
+      
+      <div id="processing">
+	<div id="processingMessage">
+	  <h2 id="processingTitle" class="ui-state-default ui-corner-all" style="padding: 8px; font-size: 110%; width: auto;">
+	    Heading
+	  </h2>
+	  <p id="processingText">text</p>
+	</div>
+      </div>
+    </div>
+
+  </xsl:template>
+
+  <!-- *** -->
+  <!-- * Discovery -->
+  <!-- *** -->
+
+  <xsl:template name="discovery-block">
+    
+    <div id="fingerprint-turnstyle">
+
+      <div style="background-image: none; background-color: rgb(80%,80%,20%);">
+	Discovery: <xsl:call-template name="choose-title"/>
+      </div>
+
+      <div class="documenttext" style="display: none;">
+	<xsl:call-template name="fingerprintMetadataBlock" />
+      </div>
+
+    </div>
+
+    <script>
+      <xsl:text disable-output-escaping="yes">
+	$(function(){
+	transformToTurnstyleBlock("fingerprint");
+	});
+      </xsl:text>
+    </script>
+    
+  </xsl:template>
+
+  <xsl:template name="fingerprintMetadataBlock">
+    
+    <xsl:variable name="httpCollection"><xsl:value-of select="/page/pageResponse/collection/metadataList/metadata[@name='httpPath']"/></xsl:variable>
+    <xsl:variable name="assocFilePath"><gsf:metadata name="assocfilepath" select="root"/></xsl:variable>
+
+
+    <xsl:variable name="musicbrainzsongid">
+      <gsf:metadata name="dc.Identifier.musicbrainzsongid"/>
+    </xsl:variable>
+
+    <xsl:variable name="musicbrainzalbumid">
+      <gsf:metadata name="dc.Source.musicbrainzalbumid"/>
+    </xsl:variable>
+
+    <xsl:variable name="musicbrainzartistid">
+      <gsf:metadata name="dc.Creator.musicbrainzartistid"/>
+    </xsl:variable>
+    
+    <xsl:variable name="lastfmtrackurl">
+      <gsf:metadata name="dc.Identifier.lastfmtrackurl"/>
+    </xsl:variable>
+
+    <xsl:variable name="echonestsongid">
+      <gsf:metadata name="dc.Identifier.echonestsongid"/>
+    </xsl:variable>
+    
+      <table class="metadata-stripes">
+	<tbody>
+	  <tr>
+	    <td>
+	      Title
+	    </td>
+	    <td>
+	      <gsf:metadata name="dc.Title"/>
+	    </td>
+	  </tr>
+	  
+	  <tr>
+	    <td>Album Title</td>
+	    <td><gsf:metadata name="dc.Title.albumtitle"/></td>
+	  </tr>
+	  
+	  <tr>
+	    <td>Artist</td>
+	    <td><gsf:metadata name="dc.Creator"/></td>
+	  </tr>
+	  
+	  <tr valign="top">
+	    <td>Artist Summary</td>
+	    <td><i><gsf:metadata name="LastFM.LastFMArtistWikiSummary"/></i></td>
+	  </tr>
+	  
+<!--
+dc.Identifier.echonestsongid
+dc.Identifier.echonestartistid
+
+dc.Identifier.lastfmtrackurl
+dc.Identifier.lastfmalbumurl
+dc.Identifier.lastfmartisturl
+
+//dc.Identifier
+dc.Identifier.musicbrainzalbumid
+dc.Identifier.musicbrainzartistid
+dc.Identifier.musicbrainzsongid
+dc.Identifier.playmeartistid
+
+-->
+
+	  <tr>
+	    <td colspan="2">
+
+	      <xsl:for-each select="/page/pageResponse/document/metadataList/metadata[@name = 'dc.Relation.artistrelatedimage']">
+		<xsl:if test="position() &lt;= 6">
+		  <a target="_blank">
+		    <xsl:attribute name='href'>
+		      <xsl:value-of disable-output-escaping="yes" select="."/>
+		    </xsl:attribute>
+		    
+		    <img width="150">
+		      <xsl:attribute name='src'>
+			<xsl:value-of disable-output-escaping="yes" select="."/>
+		      </xsl:attribute>
+		    </img>
+		  </a>
+		</xsl:if>
+	      </xsl:for-each>
+	    </td>
+	  </tr>
+
+	  <tr>
+	    <td>Linked Data</td>
+	    <td>
+	      <!--
+		  <gsf:metadata name="dc.Identifier"/><br />
+	      -->
+
+	      <table>
+		<tr>
+		  <td>
+		    MusicBrainz song id: 
+		  </td>
+		  <td>
+		    <a href="http://dbtune.org/musicbrainz/resource/track/{$musicbrainzsongid}" target="#musicbrainz">
+		      <xsl:copy-of select="$musicbrainzsongid"/>
+		    </a>
+		  </td>
+		</tr>
+
+		<tr>
+		  <td>
+		    MusicBrainz album id: 
+		  </td>
+		  <td>
+		    <a href="http://dbtune.org/musicbrainz/resource/record/{$musicbrainzalbumid}" target="#musicbrainz">
+		      <xsl:copy-of select="$musicbrainzalbumid"/>
+		    </a>
+		  </td>
+		</tr>
+
+		<tr>
+		  <td>
+		    MusicBrainz artist id: 
+		  </td>
+		  <td>
+		    <a href="http://dbtune.org/musicbrainz/page/artist/{$musicbrainzartistid}" target="#musicbrainz">
+		      <xsl:copy-of select="$musicbrainzartistid"/>
+		    </a>
+		  </td>
+		</tr>
+		<tr>
+		  <td colspan="2">	      
+		    <a href="{$lastfmtrackurl}" target="#lastfm">
+		      <xsl:copy-of select="$lastfmtrackurl"/>
+		    </a>
+		  </td>
+		</tr>
+		<tr>
+		  <td>
+		    EchoNest song id:
+		  </td>
+		  <td>
+		    <a href="{$echonestsongid}" target="#echonestsongid">
+		      <xsl:copy-of select="$echonestsongid"/>
+		    </a>
+		  </td>
+		</tr>
+	      </table>
+
+	    </td>
+	  </tr>
+	  
+
+	</tbody>
+      </table>
+  </xsl:template>
+
+
+
+  <!-- *** -->
+  <!-- * Audio Player -->
+  <!-- *** -->
+
+
+  <xsl:template name="js-mad-header">
+
+        <gsf:script src="ext/js-mad/script/mad.js"/>
+        <gsf:script src="ext/js-mad/script/rq_table.js"/>
+        <gsf:script src="ext/js-mad/script/imdct_s.js"/>
+        <gsf:script src="ext/js-mad/script/huffman.js"/>
+        <gsf:script src="ext/js-mad/script/bit.js"/>
+        <gsf:script src="ext/js-mad/script/stream.js"/>
+        <gsf:script src="ext/js-mad/script/layer3.js"/>
+        <gsf:script src="ext/js-mad/script/frame.js"/>
+        <gsf:script src="ext/js-mad/script/synth.js"/>
+       
+        <gsf:script src="ext/js-mad/script/arraybuffer/bytestream.js"/>
+        <gsf:script src="ext/js-mad/script/arraybuffer/filestream.js"/>
+        <gsf:script src="ext/js-mad/script/arraybuffer/substream.js"/>
+        <gsf:script src="ext/js-mad/script/arraybuffer/arraystream.js"/>
+        <gsf:script src="ext/js-mad/script/arraybuffer/ajaxstream.js"/>
+
+        <gsf:script src="ext/js-mad/script/binarystring/bytestream.js"/>
+        <gsf:script src="ext/js-mad/script/binarystring/filestream.js"/>
+        <gsf:script src="ext/js-mad/script/binarystring/substream.js"/>
+        <gsf:script src="ext/js-mad/script/binarystring/stringstream.js"/>
+        <gsf:script src="ext/js-mad/script/binarystring/ajaxstream.js"/>
+
+        <gsf:script src="ext/js-mad/script/id3v22stream.js"/>
+        <gsf:script src="ext/js-mad/script/id3v23stream.js"/>
+        <gsf:script src="ext/js-mad/script/mp3file.js"/>
+        
+<!--
+        <gsf:script src="ext/js-mad/script/player.js"/>
+-->
+
+        <gsf:script src="ext/js-mad/script/sink.min.js"/>
+
+<!--
+        <gsf:script src="ext/js-mad/script/require.js"/>
+-->
+<!--
+        <gsf:script src="ext/js-mad/script/sink-light.js"/>
+-->
+
+        <gsf:script src="ext/js-mad/script/browser-detect.js"/>
+        <gsf:script src="ext/js-mad/script/main-jsmad.js"/>
+
+  </xsl:template>
+
+
+  <xsl:template name="audio-icon-cache">
+    <div style="display:none;">
+      <!-- pre-load various play/pause images to help with speed of interface update -->
+      <img src="ext/diy-audio-player/images/play32Highlight.png" />
+      <img src="ext/diy-audio-player/images/pause32.png" />
+      <img src="ext/diy-audio-player/images/pause32Highlight.png" />
+      <img src="ext/diy-audio-player/images/play20Highlight.png" />
+      <img src="ext/diy-audio-player/images/stop32.png" />
+      <img src="ext/diy-audio-player/images/stop32Highlight.png" />
+      <img src="ext/diy-audio-player/images/search20Highlight.png" />	
+    </div>
+  </xsl:template>
+
+
+  <!-- *** -->
+  <!-- * Workflow control -->
+  <!-- *** -->
+
+  <xsl:template name="workflow-block">
+    <xsl:variable name="httpCollection">
+      <xsl:value-of select="/page/pageResponse/collection/metadataList/metadata[@name='httpPath']"/>
+    </xsl:variable>
+
+    <div id="workflow-turnstyle">
+
+      <div style="background-image: none; background-color: rgb(80%,80%,20%);">
+	Workflow
+      </div>
+
+      <div class="documenttext hide" style="color: white; background-color: rgb(40%,40%,20%); padding: 8px;">
+	
+<!--
+	<form style="padding-left: 8px;">
+	  <span class="vis-heading">Input Selection:</span>
+	  <input type="radio" name="inputSelection" onclick="setInputSelectionMode(this)" value="left"/>Left only
+	  <input type="radio" name="inputSelection" onclick="setInputSelectionMode(this)" value="right"/>Right only
+	  <input type="radio" name="inputSelection" onclick="setInputSelectionMode(this)" value="diff"/>Average
+	  <input type="radio" name="inputSelection" onclick="setInputSelectionMode(this)" value="mix" checked="checked"/>Difference
+	</form>
+	<hr/>
+-->
+
+	<form style="padding-left: 8px; height: 48px;">
+	  <span class="vis-heading" style="padding-right: 10px" >Meandre Workflow:</span>
+
+	  <select id="meandre-workflow-pos" onChange="loadSelectedWorkflow(this)" style="font-size: 90%; padding 8px;">
+	    <option value="0" selected="selected">Chromagram</option>
+	    <option value="1" >Dynamic Javascript Mixer</option>
+	  </select>
+
+	  <div style="float: right;" id="meandre-buttons">
+	 
+	    <button type="button" id="meandre-run-button"  
+		    onclick="selectedMeandreWorkflow.runThisMeandreFlow(this)">
+	      <img id="meandre-run-button" src="ext/diy-audio-player/images/play32.png" 
+		   width="32"
+		   height="32"  
+		   XXonmouseover="playHighlightOn(this)"
+		   XXonmouseout="playHighlightOff(this)"
+		   XXonclick="runThisMeandreFlow(this)"
+		   style="vertical-align: middle;"/>
+	      Run
+	    </button>
+
+	    <button type="button" id="meandre-stop-button" onclick="selectedMeandreWorkflow.stopThisMeandreFlow(this)" disabled="disabled">
+	      <img id="meandre-stop-button" src="ext/diy-audio-player/images/stop32.png" 
+		   width="32"
+		   height="32"  
+		   XXonmouseover="stopHighlightOn(this)"
+		   XXonmouseout="stopHighlightOff(this)"
+		   XXonclick="stopThisMeandreFlow(this)"
+		   style="vertical-align: middle;"/>
+	      Stop
+	    </button>
+
+<!--
+	    <button type="button" id="meandre-run-button" onclick="runThisMeandreFlow(this)" >Run</button>
+	    <button type="button" id="meandre-stop-button" onclick="stopThisMeandreFlow(this)" disabled="disabled">Stop</button>
+-->
+
+	  </div>
+
+	</form>
+
+	<style>
+	  #meandre-buttons button:hover:enabled {
+	    background-color: #CCCC33;
+	    color: #FFFFFF;
+	  }
+	</style>
+	  
+
+	<div style="position: relative;">
+	  <iframe id="workbenchFrame" 
+		  style="width: 100%; height: 400px;" >
+	    If you see this, then your browser does not support the iframe element.
+	  </iframe>
+
+	</div>
+
+	<gsf:script src="{$httpCollection}/script/meandre-workflow/chromagram.js"/>
+	<gsf:script src="{$httpCollection}/script/meandre-workflow/js-dynamic-mix.js"/>
+	
+	<gsf:script>
+	  var chromagramMeandreWorkflow = new ChromagramMeandreWorkflow();
+	  var jsDynamicMixMeandreWorkflow = new JSDynamicMixMeandreWorkflow();
+
+	  var meandreWorkflows = [ chromagramMeandreWorkflow, jsDynamicMixMeandreWorkflow ];
+
+	  var selectedMeandreWorkflowPos =$('#meandre-workflow-pos option:selected').val();
+	  var selectedMeandreWorkflow = meandreWorkflows[selectedMeandreWorkflowPos];
+
+	  selectedMeandreWorkflow.meandreController.loadWorkbench( "workbenchFrame",selectedMeandreWorkflowPos);
+	  
+	  function loadSelectedWorkflow(elem) { 	       
+	      selectedMeandreWorkflowPos = elem.value;
+	      selectedMeandreWorkflow = meandreWorkflows[selectedMeandreWorkflowPos];
+
+	    if (selectedMeandreWorkflowPos==1) {
+	      $('#jsdynamic-turnstyle').show();
+	    }
+	    else {
+	      $('#jsdynamic-turnstyle').hide();
+	    }
+
+	    console.info("Loading in new Meandre workbench flow (pos=" + selectedMeandreWorkflowPos+ ")");		
+	    selectedMeandreWorkflow.meandreController.loadWorkbench("workbenchFrame",selectedMeandreWorkflowPos);
+
+	  }
+	</gsf:script>
+	
+
+
+
+	<div id="jsdynamic-turnstyle" style="display:none">
+	  
+	  <div style="background-image: none; background-color: rgb(80%,80%,20%);">
+	    Dynamic Javascript Meandre Component
+	  </div>
+
+	  <div class="documenttext hide" style="color: white; background-color: rgb(40%,40%,20%); padding: 8px;">
+
+	    <textarea id="js-dynamic-code" style="width:100%; height: 520px; font-size: 60%">
+	      <xsl:text disable-output-escaping="yes">
+
+
+var arrayBinding = new JavaImporter(java.lang.reflect.Array);
+
+var JSDynamicComponent = function() {
+  this.frameCount = 0;
+}
+
+JSDynamicComponent.prototype.executeCallBack = function(cc) {
+
+  with(arrayBinding) {
+
+    if ((this.frameCount % 1000)==0) {
+      print("JSDynamicComponent: " + this.frameCount + "\n");
+    }
+
+    var inputObject = cc.getDataComponentFromInput("input");
+    var rawInput1DArray = inputObject;
+
+    var rawOutput1DArray = Array.newInstance(java.lang.Double.TYPE, rawInput1DArray.length);
+
+    for (var i=1; i&lt;rawOutput1DArray.length; i++) {
+      var diff = Array.getDouble(rawInput1DArray,i) - Array.getDouble(rawInput1DArray, i-1);
+      Array.setDouble(rawOutput1DArray,i,diff);
+    }
+
+    cc.pushDataComponentToOutput("output", rawOutput1DArray);
+
+    this.frameCount++;
+  }
+
+}
+
+var jsDynamicComponent = new JSDynamicComponent();
+
+	      </xsl:text>
+	    </textarea>
+	  </div> <!-- end of Dynamic JS turnstyle block -->
+	</div>
+
+      </div>
+
+    </div>
+
+    <script>
+      <xsl:text disable-output-escaping="yes">
+	$(function(){
+	    transformToTurnstyleBlock("workflow");
+	    transformToTurnstyleBlock("jsdynamic");
+	});	
+      </xsl:text>
+    </script>
+  </xsl:template>
+
+
+  <!-- *** -->
+  <!-- * Structured audio player -->
+  <!-- *** -->
+ 
+  <xsl:template name="structuredAudioPlayerBlock">
+
+    <gsf:script src="ext/diy-audio-player/script/structured-audio-play.js"/>
+    
+    <div style="background-color: rgb(40%,40%,20%)">
+      <svg xmlns="http://www.w3.org/2000/svg" 
+           xmlns:xlink="http://www.w3.org/1999/xlink" 
+	   version="1.1"
+           id="svgGroundTruthSegments" 
+	   width="100%" height="24"
+           onLoadXX="svgGTStructuredInit()">
+      </svg>
+    </div>
+    
+    <div style="background-color: rgb(40%,40%,20%)">
+      <svg xmlns="http://www.w3.org/2000/svg" 
+           xmlns:xlink="http://www.w3.org/1999/xlink" 
+	   version="1.1"
+           id="svgContentAnalysisSegments" 
+	   width="100%" height="24"
+           onLoadXX="svgCAStructuredInit({$cgiargCAAlgorithm})">
+      </svg>
+    </div>
+  </xsl:template>
+  
+  <xsl:template name="visualization-mode-block">
+    
+    <div class="documenttext" style="color: white; background-color: rgb(40%,40%,20%); padding-top: 4px;">
+
+      <span class="vix-heading">Max Values:</span>
+      <div style="padding-left: 8px">
+	<style>
+	  span.mv-fixed { display: inline-block; width: 30pt; }
+	</style>
+	<table width="100%">
+	  <tr>
+	    <td><span class="mv-fixed" id="freqSpectrumMax"     >0.000</span>(Freq Spectrum)       </td>
+	    <td><span class="mv-fixed" id="freqPowerSpectrumMax">0.000</span>(Freq Power Spectrum) </td>
+	    <td><span class="mv-fixed" id="filterBankMax"       >0.000</span>(Filter Bank)         </td>
+	    <td><span class="mv-fixed" id="chromaFeaturesMax"   >0.000</span>(Chroma Features)     </td>
+	  </tr>
+	</table>
+      </div>
+      <hr/>
+  
+      <form style="padding-left: 8px; padding-right: 8px; padding-bottom: 0px;">
+	<div style="float: left;">
+	  <span class="vis-heading">Visualization:</span>
+<!--
+	<input type="radio" name="visualization" onclick="setTransformMode(this)" value="freqSpectrum" />Frequency Spectrum 
+	<input type="radio" name="visualization" onclick="setTransformMode(this)" value="freqPowerSpectrum"/>Frequency Power Spectrum
+-->
+	
+	  <input type="radio" name="visualization" onclick="setTransformMode(this)" value="filterBank"/>Filter Bank 
+	  <input type="radio" name="visualization" onclick="setTransformMode(this)" value="chromaFeatures" checked="checked"/>Chroma Features
+	</div>
+
+	<div style="float: left; padding-left: 140px;">
+	  <span class="vis-heading">Colour Mapping:</span>
+	  <input type="radio" name="colorMapping" onclick="setColorMappingMode(this)" value="rgb"/>RGB Intensity
+	  <input type="radio" name="colorMapping" onclick="setColorMappingMode(this)" value="hsl" checked="checked"/>HSL Heat
+	</div>
+      </form>
+      
+      <div style="clear: both; padding-top: 4px; padding-bottom: 4px;"><hr/></div>
+
+<!--
+      <form style="padding-left: 8px;">
+	<span class="vis-heading">Colour Mapping:</span>
+	<input type="radio" name="colorMapping" onclick="setColorMappingMode(this)" value="rgb"/>RGB Intensity
+	<input type="radio" name="colorMapping" onclick="setColorMappingMode(this)" value="hsl" checked="checked"/>HSL Heat Map
+      </form>
+      <hr/>
+-->
+
+	<form style="padding-left: 8px; padding-bottom: 0px;">
+	  <span class="vis-heading">On Pause:</span>
+	  <input type="checkbox" name="similarityMatrix" onclick="plotSimilarityMatrixWhenPaused(this)"/>Show Similarity Matrix
+	</form>
+	<hr/>
+
+    </div>
+    
+  </xsl:template>
+
+  <!-- *** -->
+  <!-- * Settings form -->
+  <!-- *** -->
+
+  <xsl:template name="settings-form">
+    <xsl:param name="cgiargYScaleSimImg"/>
+
+    <xsl:variable name="httpCollection">
+      <xsl:value-of select="/page/pageResponse/collection/metadataList/metadata[@name='httpPath']"/>
+    </xsl:variable>
+
+    <div id="settings-turnstyle" style="margin: 6px;">
+      <div style="background-image: none; background-color: rgb(80%,80%,20%);">
+	Audio Content Search
+      </div>
+      <div class="documenttext" style="display: none;">
+
+
+      <form id="QueryForm" name="QueryForm" method="get" action="{$library_name}">
+	<input type="hidden" name="a" value="q"/>
+	<input type="hidden" name="sa"><xsl:attribute name="value"><xsl:value-of select="/page/pageRequest/@subaction"/></xsl:attribute></input>
+	<input type="hidden" name="rt" value="rd"/>
+	
+	<input type="hidden" name="s" value="AudioQuery"/>
+	<input type="hidden" name="c" value="{$collName}"/>
+	<xsl:if test="not(paramList/param[@name='startPage'])">
+	  <input type="hidden" name="startPage" value="1"/>
+	</xsl:if>
+	<xsl:choose>
+	  <xsl:when test="/page/pageRequest/paramList/param[@name = 's1.maxDocs']">
+	    <input type="hidden" name="s1.maxDocs">
+	      <xsl:attribute name="value">
+		<xsl:value-of select="/page/pageRequest/paramList/param[@name = 's1.maxDocs']/@value"/>
+	      </xsl:attribute>
+	    </input>
+	  </xsl:when>
+	  <xsl:otherwise>
+	    <input type="hidden" name="s1.maxDocs" value="100"/>
+	  </xsl:otherwise>
+	</xsl:choose>
+	<xsl:choose>
+	  <xsl:when test="/page/pageRequest/paramList/param[@name = 's1.hitsPerPage']">
+	    <input type="hidden" name="s1.hitsPerPage">
+	      <xsl:attribute name="value">
+		<xsl:value-of select="/page/pageRequest/paramList/param[@name = 's1.hitsPerPage']/@value"/>
+	      </xsl:attribute>
+	    </input>
+	  </xsl:when>
+	  <xsl:otherwise>
+	    <input type="hidden" name="s1.hitsPerPage" value="20"/>
+	  </xsl:otherwise>
+	</xsl:choose>
+	
+	<input type="hidden" name="q">
+	  <xsl:attribute name="value"><xsl:value-of select="/page/pageResponse/document/documentNode/@nodeID"/>.dir</xsl:attribute>
+	</input>
+	
+	
+	<input type="hidden" name="s1.query">
+<!--
+	  <xsl:attribute name="value"><xsl:value-of select="/page/pageResponse/document/documentNode/@nodeID"/>.dir</xsl:attribute>
+-->
+	  <xsl:attribute name="value"><xsl:value-of select="/page/pageResponse/document/@nodeID"/>.dir</xsl:attribute>
+	</input>
+	
+	<input type="hidden" name="s1.offset" value="0" />
+	<input type="hidden" name="s1.length" value="200" />
+	
+	<div style="font-style: italics;">Start new query @ offset
+	<span id="mysongCurrentPos">0 secs</span>,
+	with excerpt lasting
+	
+	<input type="text" name="mysongWindowDuration" size="4" value="6" />
+	<!--
+	    <span id="mysongWindowDuration" class="editable-offset"
+	    style="cursor: pointer; border: 1px solid black; padding: 3px; width: 200px; min-width: 200px;">6.0</span> 
+	-->
+	secs:
+
+	<input type="submit" value="Search" onclick="preSubmit(this.form);" />
+	</div>
+
+	
+	<ul style="font-size: 80%; margin-top: 8px; font-style: italics;" >
+	  <li>Use the <b>Play all of</b> bar to get to the part of the song you are interested in.</li>
+	  <li>... the <b>query @ offset</b> value will change accordingly as the song progresses.</li>
+	  <li>Click <b>pause</b> (anywhere outside of the time-line) to mark the spot you want to start the new music query.</li>
+	  <li>Optionally click on the <b>excerpt lasting</b> value and edit, if you want to change the length of excerpt used in the match.</li>
+	  <li>Finally, click the <b>Search</b> button to initiate the new query.</li>
+	</ul>
+	
+      </form>
+
+      <hr/>
+      
+<!--
+      <form id="RescaleForm" name="RescaleForm" method="get" action="{$library_name}">
+	<div style="font-style: italics;">
+	  Make the scale factor for the y-dimension of the self-similarity
+	  image be
+	  <input type="text" name="ResizeScale" value="{$cgiargYScaleSimImg}"
+	         size="3" /> then 
+	  <input type="button" name="ResizeImage" value="Resize Image" 
+	         onclick="javascript:rescaleImage()" />
+	  
+	</div>
+      </form>
+      
+      <hr/>
+-->
+
+      <!-- **** currently not displayed -->
+
+      <form id="UpdateCAForm" name="UpdateCAForm" method="get" action="{$library_name}" style="display: none;">
+	<div style="font-style: italics;">
+	  
+	  Show the song structure automatically computed by analyzing
+	  the audio data using algorithm 
+
+	  <select id="caaMenu" name="caAlgorithm">
+	    <option value="1">BV1</option>
+	    <option value="2">BV2</option>
+	    <option value="3">GP7</option>
+	    <option value="4">MHRAG2</option>
+	    <option value="5">MND1</option>
+	    <option value="6">WB1</option>
+
+<!--
+	    <option value="-1">or hide</option>
+-->
+
+	  </select>: 
+
+	  <input type="button" name="Reload" value="Reload" 
+	         onclick="updateCAAlgorithm()" />
+
+	</div>
+      </form>
+
+	<script>
+	  <xsl:text disable-output-escaping="yes"> 
+	    if (hasStructuredAudio) {
+	      var caaMenu = document.getElementById("caaMenu");
+               caaMenu.options[caAlgorithm-1].selected = 1;
+	    }
+	  </xsl:text>
+	</script>
+      
+
+      </div>
+    </div>
+    <script>
+      <xsl:text disable-output-escaping="yes">
+	$(function(){
+	transformToTurnstyleBlock("settings");
+	});
+      </xsl:text>
+    </script>
+
+  </xsl:template>
+
+
+  <!-- *** -->
+  <!-- * Computed Data -->
+  <!-- *** -->
+
+
+  <xsl:template name="computed-data">
+    <xsl:param name="httpCollection"/>
+    <xsl:param name="assocFilePath"/>
+
+    <div id="computed-turnstyle" style="margin: 6px;">
+      <div style="background-image: none; background-color: rgb(80%,80%,20%);">
+	Computed Data
+      </div>
+
+      <div class="documenttext" style="display: none;">
+	<table class="metadata-stripes" style="width: 100%">
+	  <tbody>
+	    <tr>
+	      <td>jAudio Features</td><td><a href="{$httpCollection}/index/assoc/{$assocFilePath}/jaudio.xml">download ACE XML feature values file</a></td>
+	    </tr>
+	    
+	    <tr>
+	      <td>jSongMiner Metadata</td><td><a href="{$httpCollection}/index/assoc/{$assocFilePath}/jsongminer.xml">download ACE XML classifications file</a></td>
+	    </tr>
+	    
+	  </tbody>
+	</table>
+      </div>
+    </div>
+
+    <gsf:script>
+	$(function(){
+	  transformToTurnstyleBlock("computed");
+	});
+    </gsf:script>
+
+
+    <div id="original-turnstyle" style="margin: 6px;">
+      <div style="background-image: none; background-color: rgb(80%,80%,20%);">
+	The Original Audio
+      </div>
+
+      <div style="display: none;">
+
+	<div>
+	  <audio style="width: 100%;" id="original-audio" controls="controls" >
+	    <source src="{$httpCollection}/index/assoc/{$assocFilePath}/doc.ogg" />
+	    <source src="{$httpCollection}/index/assoc/{$assocFilePath}/doc.mp3" />
+	    <source src="{$httpCollection}/index/assoc/{$assocFilePath}/doc.wav" />
+	  </audio>
+	</div>
+
+      </div>
+    </div>
+
+    <gsf:script>
+	$(function(){
+	  transformToTurnstyleBlock("original");
+	});
+    </gsf:script>
+
+
+  </xsl:template>
+
+</xsl:stylesheet>
