Index: /main/trunk/model-sites-dev/mars/collect/amc-audioDB/etc/collectionConfig.xml
===================================================================
--- /main/trunk/model-sites-dev/mars/collect/amc-audioDB/etc/collectionConfig.xml	(revision 30439)
+++ /main/trunk/model-sites-dev/mars/collect/amc-audioDB/etc/collectionConfig.xml	(revision 30439)
@@ -0,0 +1,602 @@
+<?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 lang="en" name="creator"/>
+		<metadata lang="en" name="maintainer"/>
+		<metadata lang="en" name="public">true</metadata>
+	</metadataList>
+	<displayItemList>
+		<displayItem assigned="true" lang="en" name="description">
+      Demonstration of an audio content analysis based digital library, based around audioDB.  
+   </displayItem>
+		<displayItem assigned="true" lang="en" name="name">AMC + audioDB </displayItem>
+		<displayItem assigned="true" lang="en" name="description">
+		  Demonstration collection, based on the represented artists as the Australian Music Centre.  
+		  The collection demonstrates an experimental extension of Greenstone3, which 
+		  provides a music-based content-similarity search based on the Locality Sensitive Hashing (LSH)
+		  algorithm provided by audioDB.
+		</displayItem>
+		<displayItem assigned="true" lang="en" name="amc.title">titles</displayItem>
+		<displayItem assigned="true" lang="en" name="amc.artist">artists</displayItem>
+		<displayItem assigned="true" lang="en" name="document:text">text</displayItem>
+		<displayItem assigned="true" lang="en" name="document:ex.Title">Title</displayItem>
+		<displayItem assigned="true" lang="en" name="document:ex.Source">Source</displayItem>
+		<displayItem assigned="true" lang="en" name="document">document</displayItem>
+		<displayItem assigned="true" lang="en" name="section">section</displayItem>
+	</displayItemList>
+	<format/>
+	<search type="lucene">
+		<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="amc.title">
+			<displayItem lang="en" name="name">titles</displayItem>
+		</index>
+		<index name="amc.artist">
+			<displayItem lang="en" name="name">artists</displayItem>
+		</index>
+		<defaultIndex name="amc.title"/>
+		<indexOption name="casefold"/>
+		<indexOption name="stem"/>
+		<searchType name="plain"/>
+		<searchType name="simpleform"/>
+		<searchType name="advancedform"/>
+		<format>
+			<gsf:template match="documentNode">
+				<td valign="top">
+						<gsf:icon type="document"/>
+				</td>
+
+				<td>
+				  <xsl:if test="/page/pageResponse/service/@name = 'AudioQuery'">
+								(<script>
+    var rank=<xsl:value-of select="@rank"/>;
+    var perc=(rank-0.9)*100*10;
+    document.write(perc.toFixed(1));
+								</script>%) 
+				  </xsl:if>
+							<a>
+								<xsl:choose>
+									<xsl:when test="/page/pageResponse/collection/@name">
+										<xsl:attribute name="href"><xsl:value-of select="$library_name"/>?a=d&amp;c=<xsl:value-of select="/page/pageResponse/collection/@name"/>&amp;d=<xsl:value-of select="@nodeID"/>&amp;dt=<xsl:value-of select="@docType"/>&amp;p.frameOffset=<xsl:value-of select="@frameOffset"/>&amp;p.a=q&amp;p.s=<xsl:value-of select="/page/pageResponse/service/@name"/>&amp;hl=on&amp;ed=1#<xsl:value-of select="@nodeID"/></xsl:attribute>
+									</xsl:when>
+									<xsl:when test="@collection">
+										<xsl:attribute name="href"><xsl:value-of select="$library_name"/>?a=d&amp;c=<xsl:value-of select="@collection"/>&amp;d=<xsl:value-of select="@nodeID"/>&amp;dt=<xsl:value-of select="@docType"/>p.frameOffset=<xsl:value-of select="@frameOffset"/>&amp;p.a=q&amp;p.s=<xsl:value-of select="/page/pageResponse/service/@name"/>&amp;hl=on&amp;ed=1#<xsl:value-of select="@nodeID"/></xsl:attribute>
+									</xsl:when>
+								</xsl:choose>
+								
+								<gsf:metadata name="amc.title"/>
+							</a>
+				  <xsl:if test="/page/pageResponse/service/@name = 'AudioQuery'">
+<span style="font-style: italics; font-size: 90%" >
+Matching offset @
+<script>
+  <xsl:text disable-output-escaping="yes"> 
+    var frameOffsetStr="</xsl:text><xsl:value-of select="@frameOffset"/><xsl:text disable-output-escaping="yes">";
+    var frameOffsetList = frameOffsetStr.split(",");
+    for(i=0; i &lt; frameOffsetList.length; i++) {
+        var frameOffset = frameOffsetList[i];
+        var offsetInSecs=(250*frameOffset)/1000.0;
+        if (i &gt; 0) { document.write(", "); }
+        document.write(offsetInSecs.toFixed(2));
+    }
+  </xsl:text> 
+</script> secs
+</span>
+                                  </xsl:if>
+
+				</td>
+			</gsf:template>
+
+
+
+
+
+
+		</format>
+	</search>
+
+	<search type="audioDB" orthogonal="true">
+	</search>
+
+	<infodb type="jdbm"/>
+	<import>
+		<pluginList>
+			<plugin name="ZIPPlugin"/>
+			<plugin name="GreenstoneXMLPlugin"/>
+			<plugin name="EmbeddedMetadataPlugin"/>
+			<plugin name="AMCMetadataJSONPlugin"/>
+
+      <plugin name="AudioDBPlugin">
+          <option name="-compute_fft_features" value="true"/>
+          <option name="-enable_streaming" value="mp3"/>
+          <option name="-enable_cache"/>
+	  <option name="-process_exp" value="(?i)(\.m4a)$"/>
+      </plugin>
+
+
+			<plugin name="TextPlugin"/>
+			<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;amc.title;ex.amc.title;Title"/>
+			<option name="-mingroup" value="2"/>
+		</classifier>
+		<classifier name="AZCompactList">
+			<option name="-metadata" value="dc.Creator,amc.artist,ex.amc.artist"/>
+			<option name="-buttonname" value="Artists"/>
+			<option name="-mingroup" value="1"/>
+			<option name="-minnesting" value="40"/>
+		</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">
+						<gsf:choose-metadata>
+							<gsf:metadata name="dc.Title"/>
+							<gsf:metadata name="amc.title"/>
+							<gsf:metadata name="exp.Title"/>
+							<gsf:metadata name="Title"/>
+							<gsf:default>Untitled</gsf:default>
+						</gsf:choose-metadata>
+					</gsf:link>
+				</td>
+			</gsf:template>
+			<gsf:template match="classifierNode">
+				<td valign="top">
+					<gsf:link type="classifier">
+						<gsf:icon type="classifier"/>
+					</gsf:link>
+				</td>
+				<td valign="top">(<gsf:metadata name="numleafdocs"/>)</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="classifier">
+						<gsf:choose-metadata>
+							<gsf:metadata name="dc.Title"/>
+							<gsf:metadata name="amc.title"/>
+							<gsf:metadata name="exp.Title"/>
+							<gsf:metadata name="Title"/>
+							<gsf:default>Untitled</gsf:default>
+						</gsf:choose-metadata>
+					</gsf:link>
+					<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" mode="horizontal">
+				<gsf:link type="horizontal">
+					<gsf:metadata name="Title"/>
+				</gsf:link>
+			</gsf:template>
+		</format>
+	</browse>
+	<display>
+		<format>
+			<gsf:option name="TOC" value="false"/>
+			<gsf:template name="documentHeading">
+			  <!-- title will be dsiplayed in playbar at top of page, so supress showing title here -->
+			  <gsf:script src="interfaces/{$interface_name}/js/direct-edit-source.js"/>
+			  <xsl:call-template name="init-direct-edit"/>
+
+			</gsf:template>
+			<gsf:template name="documentContentXXX">
+				<xsl:param name="collName"/>
+				<xsl:variable name="docID" select="@docID"/>
+			</gsf:template>
+
+			<xsl:template name="documentContent">
+				<xsl:variable name="httpCollection">
+					sites/<xsl:value-of select="$site_name"/>/collect/<xsl:value-of select="/page/pageResponse/collection/@name"/>
+				</xsl:variable>
+				<xsl:variable name="assocFilePath">
+					<gsf:metadata name="assocfilepath" select="root"/>
+				</xsl:variable>
+				<xsl:variable name="cgiargFrameOffset">
+					<xsl:value-of select="/page/pageRequest/paramList/param[@name='p.frameOffset']/@value"/>
+				</xsl:variable>
+				<xsl:variable name="lastfmtrackurl">
+					<gsf:metadata name="dc.Identifier.lastfmtrackurl"/>
+				</xsl:variable>
+				<xsl:variable name="imageUrls">
+					<gsf:metadata multiple="true" name="EchoNest.Artist-RelatedImage" separator="&amp;quot;, &amp;quot;"/>
+				</xsl:variable>
+				<xsl:variable name="echonestid">
+					<gsf:metadata name="dc.Identifier"/>
+				</xsl:variable>
+				<div class="documenttext">
+
+					<ul class="playlist">
+					        <style>
+						  ul.playlist li {
+						    background-color: #87A41C;
+						  }
+
+						  ul.playlist li.sm2_playing {
+						    background-color: #657C0D;
+						  }
+
+						  ul.playlist li:hover {
+						    background-color: #778410;
+						  }
+
+						</style>
+						<li class="rounded">
+							<a href="{$httpCollection}/index/assoc/{$assocFilePath}/doc.mp3" id="mysong">Play all of: <gsf:choose-metadata><gsf:metadata name="dc.Title"/><gsf:metadata name="amc.title"/><gsf:metadata name="exp.Title"/><gsf:metadata name="Title"/><gsf:default>Untitled</gsf:default></gsf:choose-metadata></a>
+						</li>
+					</ul>
+
+					<ul style="font-size: 80%; margin-top: 10px; font-style: italics; ">
+						<li>Click on the green bar above <b>to start</b> playing.</li>
+						<li>Click again in play area (outside of time-line) <b>to pause</b>.</li>
+						<li>Click <b>within time-line</b> to jump to that section of song
+      (assuming enough buffered downloading has occurred).</li>
+					</ul>
+<!--
+only put in the "Play match @ offset if got a valid offset value
+-->
+					<xsl:choose>
+						<xsl:when test="$cgiargFrameOffset != '-1'">
+							<hr/>
+
+							<div style="cursor: pointer;">
+								<i>Play match @ offset <span id="mysongOffset"/></i>
+							</div>
+						</xsl:when>
+					</xsl:choose>
+					<hr/>
+					<form action="{$library_name}" method="get" name="QueryForm">
+						<input name="a" type="hidden" value="q"/>
+						<input name="sa" type="hidden">
+							<xsl:attribute name="value">
+								<xsl:value-of select="/page/pageRequest/@subaction"/>
+							</xsl:attribute>
+						</input>
+						<input name="rt" type="hidden" value="rd"/>
+						<input name="s" type="hidden" value="AudioQuery"/>
+						<input name="c" type="hidden" value="{$collName}"/>
+						<xsl:if test="not(paramList/param[@name='startPage'])">
+							<input name="startPage" type="hidden" value="1"/>
+						</xsl:if>
+						<xsl:choose>
+							<xsl:when test="/page/pageRequest/paramList/param[@name = 's1.maxDocs']">
+								<input name="s1.maxDocs" type="hidden">
+									<xsl:attribute name="value">
+										<xsl:value-of select="/page/pageRequest/paramList/param[@name = 's1.maxDocs']/@value"/>
+									</xsl:attribute>
+								</input>
+							</xsl:when>
+							<xsl:otherwise>
+								<input name="s1.maxDocs" type="hidden" value="100"/>
+							</xsl:otherwise>
+						</xsl:choose>
+						<xsl:choose>
+							<xsl:when test="/page/pageRequest/paramList/param[@name = 's1.hitsPerPage']">
+								<input name="s1.hitsPerPage" type="hidden">
+									<xsl:attribute name="value">
+										<xsl:value-of select="/page/pageRequest/paramList/param[@name = 's1.hitsPerPage']/@value"/>
+									</xsl:attribute>
+								</input>
+							</xsl:when>
+							<xsl:otherwise>
+								<input name="s1.hitsPerPage" type="hidden" value="20"/>
+							</xsl:otherwise>
+						</xsl:choose>
+						<input name="q" type="hidden" value="{$assocFilePath}" />
+						<input name="s1.query" type="hidden" value="{$assocFilePath}" />
+
+						<input name="s1.offset" type="hidden" value="0"/>
+						<input name="s1.length" type="hidden" value="200"/>
+						<div style="font-style: italics;">Start audio-based query @ offset <span id="mysongCurrentPos">0 secs</span>,
+with excerpt lasting <span class="editable-offset" id="mysongWindowDuration" style="cursor: pointer; border: 1px solid black; padding: 3px; width: 200px; min-width: 200px;">3.0</span> secs:<input onclick="preSubmit(this.form);" type="submit" value="Search"/></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/>
+					<script>
+						<xsl:text disable-output-escaping="yes">if (window.location.toString().match(/fancyplayer/i)) {
+      PP_CONFIG.usePeakData = true;
+      PP_CONFIG.useEQData = true;
+      PP_CONFIG.useFavIcon = true;
+    }
+
+    function playFromOffset(id,frameOffset) 
+    {
+      var msecOffset = 250 * frameOffset; 
+      idElem = document.getElementById(id);
+      pagePlayer.handleClick({target:idElem}); /* fake a click */
+      soundManager.stopAll();
+      /* soundManager.setPosition(id,5000); */
+      soundManager.play(id,{position: msecOffset});
+    }
+
+    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 frameLength = Math.round(lengthInSecs*1000/250.0);
+      form.elements["s1.length"].value = frameLength;
+
+      return true;
+    }</xsl:text>
+						<xsl:choose>
+							<xsl:when test="$cgiargFrameOffset != '-1'">
+								<xsl:text disable-output-escaping="yes">var allOffsets = "";
+      var frameOffsetStr="</xsl:text>
+								<xsl:value-of select="$cgiargFrameOffset"/>
+								<xsl:text disable-output-escaping="yes">";
+      var frameOffsetList = frameOffsetStr.split(",");
+      frameOffsetList.sort(function(a,b){return a-b});
+
+      for (i=0; i &lt; frameOffsetList.length; i++) {
+        var frameOffset = frameOffsetList[i];
+        var offsetInSecs=(250*frameOffset)/1000.0;
+
+        if (i &gt; 0) { allOffsets += ", "; }
+
+        var span_attr = "class=\"spanbuttonoff\" style=\"cursor: pointer;\"";
+        span_attr += " onmouseover=\"this.className='spanbuttonon'\"";
+        span_attr += " onmouseout=\"this.className='spanbuttonoff'\"";
+        span_attr += " onclick=\"playFromOffset('mysong'," + frameOffset + ")\"";
+
+        allOffsets += "&lt;span " + span_attr + "&gt;" + offsetInSecs + "&lt;/span&gt;";
+      }
+
+      var jumpDurationSpan = document.getElementById("mysongOffset");
+      jumpDurationSpan.innerHTML = allOffsets + " secs";</xsl:text>
+							</xsl:when>
+							<xsl:otherwise>var frameOffset=-1;</xsl:otherwise>
+						</xsl:choose>
+					</script>
+				</div>
+			</xsl:template>
+<!--
+Creates a header for the html page
+-->
+			<xsl:template name="create-html-headerXXXX">
+				<title><xsl:call-template name="pageTitle"/> ::<xsl:call-template name="siteName"/></title>
+				<link href="interfaces/{$interface_name}/style/core.css" rel="stylesheet" type="text/css"/>
+				<link href="favicon.ico" rel="shortcut icon"/>
+<!--
+Hook in Seaweed:  seamless web editing
+-->
+				<script src="interfaces/{$interface_name}/js/direct-edit-source.js" type="text/javascript">
+					<xsl:text>					</xsl:text>				</script>
+<!--
+Page player core CSS
+-->
+				<link href="ext/audioDB/css/page-player.css" rel="stylesheet" type="text/css"/>
+<!--
+soundManager.useFlashBlock: related CSS
+-->
+				<link href="ext/audioDB/css/flashblock.css" rel="stylesheet" type="text/css"/>
+<!--
+optional: annotations/sub-tracks/notes, and alternate themes
+-->
+				<link href="ext/audioDB/css/optional-annotations.css" rel="stylesheet" type="text/css"/>
+				<link href="ext/audioDB/css/optional-themes.css" rel="stylesheet" type="text/css"/>
+				<style type="text/css">ul.playlist li .comment {font-size:0.65em;opacity:0.5}</style>
+<!--
+soundManager API
+-->
+				<script src="ext/audioDB/script/soundmanager2-nodebug.js">
+					<xsl:text>					</xsl:text>				</script>
+				<script>
+					<xsl:text disable-output-escaping="yes">/* init Seaweed */
+
+
+    de.onready(function() {
+      try {
+        de.init();
+
+        de.doc.declarePropertySets({
+                offset: {
+                    phMarkup: '[Enter offset value]',
+                    name: "offset"
+                }
+           });
+      }
+      catch (err) {
+        alert("Seaweed failed to initialise: " + err.message);
+      }
+   });
+
+/* --------
+
+  Config override: This demo uses shiny flash 9 stuff, overwriting Flash 8-based defaults
+  Alternate PP_CONFIG object must be defined before soundManager.onready()/onload() fire.
+  Alternately, edit the config in page-player.js to simply use the values below by default
+
+-------- */
+
+/* demo only, but you can use these settings too.. */
+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/audioDB/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. */
+}</xsl:text>
+				</script>
+<!--
+Page player main script
+-->
+				<script src="ext/audioDB/script/page-player.js">
+					<xsl:text>					</xsl:text>				</script>
+<!--
+optional: Metadata UI prototype (not needed unless you want the bottom-most demo bits)
+-->
+				<script src="ext/audioDB/script/optional-page-player-metadata.js">
+					<xsl:text>					</xsl:text>				</script>
+			</xsl:template>
+
+
+
+			<xsl:template name="additionalHeaderContent">
+<!--
+Page player core CSS
+-->
+				<link href="ext/audioDB/css/page-player.css" rel="stylesheet" type="text/css"/>
+<!--
+soundManager.useFlashBlock: related CSS
+-->
+				<link href="ext/audioDB/css/flashblock.css" rel="stylesheet" type="text/css"/>
+<!--
+optional: annotations/sub-tracks/notes, and alternate themes
+-->
+				<link href="ext/audioDB/css/optional-annotations.css" rel="stylesheet" type="text/css"/>
+				<link href="ext/audioDB/css/optional-themes.css" rel="stylesheet" type="text/css"/>
+				<style type="text/css">ul.playlist li .comment {font-size:0.65em;opacity:0.5}</style>
+<!--
+soundManager API
+-->
+				<script src="ext/audioDB/script/soundmanager2-nodebug.js">
+					<xsl:text>					</xsl:text>				</script>
+				<script>
+					<xsl:text disable-output-escaping="yes">
+
+/* --------
+
+  Config override: This demo uses shiny flash 9 stuff, overwriting Flash 8-based defaults
+  Alternate PP_CONFIG object must be defined before soundManager.onready()/onload() fire.
+  Alternately, edit the config in page-player.js to simply use the values below by default
+
+-------- */
+
+/* demo only, but you can use these settings too.. */
+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/audioDB/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. */
+}</xsl:text>
+				</script>
+<!--
+Page player main script
+-->
+				<script src="ext/audioDB/script/page-player.js">
+					<xsl:text>					</xsl:text>				</script>
+<!--
+optional: Metadata UI prototype (not needed unless you want the bottom-most demo bits)
+-->
+				<script src="ext/audioDB/script/optional-page-player-metadata.js">
+					<xsl:text>					</xsl:text>				</script>
+			</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,amc.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/mars/collect/amc-audioDB/perllib/plugins/AMCMetadataJSONPlugin.pm
===================================================================
--- /main/trunk/model-sites-dev/mars/collect/amc-audioDB/perllib/plugins/AMCMetadataJSONPlugin.pm	(revision 30439)
+++ /main/trunk/model-sites-dev/mars/collect/amc-audioDB/perllib/plugins/AMCMetadataJSONPlugin.pm	(revision 30439)
@@ -0,0 +1,209 @@
+###########################################################################
+#
+# AMCMetadataJSONPlugin.pm -- A plugin for JSON files resulting from page 
+#                             scrape of artists on the Australian Music Centre
+#                             website
+#
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright 2016 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+package AMCMetadataJSONPlugin;
+
+
+use BasePlugin;
+use MetadataRead;
+
+use strict;
+no strict 'refs';
+use multiread;
+
+use Encode;
+use JSON;
+
+# methods with identical signatures take precedence in the order given in the ISA list.
+sub BEGIN {
+    @AMCMetadataJSONPlugin::ISA = ('MetadataRead', 'BasePlugin');
+}
+
+
+my $arguments = [
+      { 'name' => "process_exp",
+	'desc' => "{BasePlugin.process_exp}",
+	'type' => "regexp",
+	'reqd' => "no",
+	'deft' => &get_default_process_exp() }
+
+];
+
+
+my $options = { 'name'     => "AMCMetadataJSONPlugin",
+		'desc'     => "{AMCMetadataJSONPlugin.desc}",
+		'abstract' => "no",
+		'inherits' => "yes",
+		'args'     => $arguments };
+
+
+sub new
+{
+    my ($class) = shift (@_);
+    my ($pluginlist,$inputargs,$hashArgOptLists) = @_;
+    push(@$pluginlist, $class);
+
+    push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});
+    push(@{$hashArgOptLists->{"OptList"}},$options);
+
+    my $self = new BasePlugin($pluginlist, $inputargs, $hashArgOptLists);
+
+    return bless $self, $class;
+}
+
+
+sub get_default_process_exp
+{
+    return q^(?i)\.json$^;
+}
+
+sub file_block_read {
+    my $self = shift (@_);
+    my ($pluginfo, $base_dir, $file, $block_hash, $metadata, $gli) = @_;
+
+    my ($filename_full_path, $filename_no_path) = &util::get_full_filenames($base_dir, $file);
+
+    if (!-f $filename_full_path || !$self->can_process_this_file($filename_full_path)) {
+	return undef; # can't recognise
+    }
+
+    # set this so we know this is a metadata file - needed for incremental 
+    # build
+    # if this file changes, then we need to reimport everything
+    $block_hash->{'metadata_files'}->{$filename_full_path} = 1;
+
+    return 1;
+}
+
+sub metadata_read
+{
+    my $self = shift (@_);
+    my ($pluginfo, $base_dir, $file, $block_hash, 
+	$extrametakeys, $extrametadata, $extrametafile,
+	$processor, $gli, $aux) = @_;
+
+    # Read metadata from JSON files
+    my $filename = &util::filename_cat($base_dir, $file);
+
+    if (!-f $filename || !$self->can_process_this_file($filename)) {
+
+	return undef;
+    }
+    print STDERR "\n<Processing n='$file' p='AMCMetadataJSONPlugin'>\n" if ($gli);
+    print STDERR "AMCMetadataJSONPlugin: processing $file\n" if ($self->{'verbosity'}) > 1;
+
+    my $outhandle = $self->{'outhandle'};
+    my $failhandle = $self->{'failhandle'};
+
+    # add the file to the block list so that it won't be processed in read, as we will do all we can with it here
+    &util::block_filename($block_hash,$filename);
+
+
+    # Read the JSON file to get the metadata
+    my $json_file_content;
+    open(JSON_FILE, "$filename");
+    my $json_file_reader = new multiread();
+    $json_file_reader->set_handle('AMCMetadataJSONPlugin::JSON_FILE');
+    $json_file_reader->read_file(\$json_file_content);
+
+    # Would be nice if AMCMetadataJSONPlugin was extended to support a minus
+    # option to choose the character encoding the JSON file is in 
+    # For now we will assume it is always in UTF8
+
+    my $json_file_content_bytes = encode('UTF-8', $json_file_content);
+
+    $json_file_content = decode("utf8",$json_file_content_bytes);
+
+    close(JSON_FILE);
+
+    # Split the file into lines and read the first line (contains the metadata names)
+#    $json_file_content =~ s/\r/\n/g;  # Handle non-Unix line endings
+#    $json_file_content =~ s/\n+/\n/g;
+#    my @json_file_lines = split(/;/s, $json_file_content);
+
+#    my $matching_file = $file;
+#    $matching_filename =~ s/\.js/\.{ogg,mp3,wav}/;
+
+
+#    my $json_metadata = {};
+
+    print STDERR "**** json_metadata = $json_file_content\n";
+    # my $json_metadata = decode_json $json_file_content;
+    my $json_metadata = JSON->new->utf8->decode($json_file_content);
+
+    # We can't associate any metadata without knowing the file to associate it with
+    my $audio_url = $json_metadata->{"audio_url"};
+    if (!defined $audio_url) {
+	$self->print_error($outhandle, $failhandle, $gli, $filename, "No audio_url metadata in JSON file: $file");
+	
+	return -1;
+    }
+
+    my $local_audio_file = $audio_url;
+    $local_audio_file =~ s/^http:\/\/.*\///;
+    
+    print STDERR "***** local audio file = $local_audio_file\n";
+ 
+    foreach my $k (keys %$json_metadata) {
+	$json_metadata->{'amc.'.$k} = [ $json_metadata->{$k} ];
+	delete $json_metadata->{$k};
+    }
+
+
+#    my $json_filename = shift(@$json_trackurl_array);
+#    $json_filename =~ s/\"//g; # strip off quotes
+#    delete $json_metadata->{"track_url"};
+    
+    # Associate the metadata now
+    $local_audio_file = &util::filename_to_regex($local_audio_file);
+
+###  print STDERR "**** setting up mapping for: $json_filename\n";
+
+    $extrametadata->{$local_audio_file} = $json_metadata;
+    push(@$extrametakeys, $local_audio_file);
+    # record which file the metadata came from 
+    if (!defined $extrametafile->{$local_audio_file}) {
+	$extrametafile->{$local_audio_file} = {};
+    }
+    # maps the file to full path
+    $extrametafile->{$local_audio_file}->{$file} = $filename;
+
+    return 1; 
+}
+
+sub print_error
+{
+
+    my $self = shift(@_);
+    my ($outhandle, $failhandle, $gli, $file, $error) = @_;
+
+    print $outhandle "AMCMetadataJSONPlugin Error: $file: $error\n";
+    print $failhandle "AMCMetadataJSONPlugin Error: $file: $error\n";
+    print STDERR "<ProcessingError n='$file' r='$error'/>\n" if ($gli);
+}
+1;
