[open-ils-commits] [GIT] Evergreen ILS branch master updated. 180e3329fcce010b58b9e9ca826f9c1757e091e3

Evergreen Git git at git.evergreen-ils.org
Wed Feb 28 16:23:56 EST 2018


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Evergreen ILS".

The branch, master has been updated
       via  180e3329fcce010b58b9e9ca826f9c1757e091e3 (commit)
       via  33fe8e6a0824dfa6fc1884b1485f1a7ceb5b7b68 (commit)
       via  5b311a2525e500e86f9cb60aaceb0cd414f6c821 (commit)
       via  867cc29335d15c5c30a8311c12b150320a0f2f4f (commit)
       via  dc8348576b4e523e9f89d32f967b2c80996c4be9 (commit)
       via  3d1fcf23bcdf2cf473efa34336c11bbab5af5f6b (commit)
       via  5d3b69c77c92f21308d7df6fae340a6f5acc2e33 (commit)
       via  024ec4c056c9f536b6f9e018b760c9e19bdebe8a (commit)
       via  767e7caa07d9281730b52b5ba6d7ff78ba77fc89 (commit)
       via  952c1af10ad6501603199ebe8ea9e1568beffc84 (commit)
       via  fd45adb4bd298031dff98d31b571394db3a5397a (commit)
       via  57166723680ed2cbd5cb130d5a0c4d71e2ced7bc (commit)
       via  3817746d6c53f74f74451d53f018e73db6ca6bb6 (commit)
       via  194cc82b3192c5af15ec2dd51db9ae7e9560382e (commit)
       via  0df4f2951febd2db9c3eb3450690cf3a273c5a6d (commit)
       via  7edd82750b408c8f1eb5ebcb66a2de16d71cd46e (commit)
       via  a985c99897d9f2d53609be17c5abef67234a3635 (commit)
       via  78fd5304ed7bc7c04c1fec24e6c5cd26b503d73f (commit)
       via  5f1247385514bda1ce2b9bce06612b311bd71f11 (commit)
       via  9e3f4dc75f8636c430d4a144bd62396e5a825350 (commit)
       via  f5c6bffd3645e538d6908d5967004b5648b5478f (commit)
       via  f96108efd162213e0728b1286c3b5e5fbd86683a (commit)
       via  dafb624be8bc31b83e8b503d248f7131fed4c580 (commit)
       via  4d4a1c92c29061a7fbef649b0b1ab65c544a32f3 (commit)
       via  da1bc239fdefd358173e82b2c13d76a5aa6fd701 (commit)
       via  2fcd2d03891dba2474fb137e40aa1c8964311d10 (commit)
       via  b5abea61bc73cc092e415bd0d2ab3c805d25a1c7 (commit)
       via  d58bbd561aef5b2b48f28b2c84423dd233c78264 (commit)
       via  526584fa959bf9f03ae6adfb5ef2446d5b9b1d0b (commit)
       via  c12daecfc0bc0cf0303837a0d97f1c9e6589d61e (commit)
      from  8ec458c85b49fb5014ba9e7264d41fd3a55a30d1 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 180e3329fcce010b58b9e9ca826f9c1757e091e3
Author: Kathy Lussier <klussier at masslnc.org>
Date:   Mon Feb 26 15:04:30 2018 -0500

    LP#1744385: Additions and edits to release note entry
    
    Minor edits to the release notes entry. Also, I highlighted the increased
    use of Display Fields in the client since I thought it would be of
    interest to some users. I also incorporated information regarding
    default weights, which were added after Mike wrote up his release
    note for this feature.
    
    Signed-off-by: Kathy Lussier <klussier at masslnc.org>
    Signed-off-by: Dan Wells <dbw2 at calvin.edu>

diff --git a/docs/RELEASE_NOTES_NEXT/Architecture/search-display-infrastructure-improvements.adoc b/docs/RELEASE_NOTES_NEXT/Architecture/search-display-infrastructure-improvements.adoc
index 88b2f8c..0ed9de6 100644
--- a/docs/RELEASE_NOTES_NEXT/Architecture/search-display-infrastructure-improvements.adoc
+++ b/docs/RELEASE_NOTES_NEXT/Architecture/search-display-infrastructure-improvements.adoc
@@ -19,9 +19,9 @@ search. It is also fairly ineffective at achieving the goal of weighted keyword
 fields. Virtual Index Definitions will substantially alleviate the need for
 these workarounds and their consequences.
 
-  * A Virtual Index Definition is not required supply any configuration for
+  * A Virtual Index Definition does not require any configuration for
 extracting bibliographic data from records, but instead can become a sink for
-data collected by other index definitions which is then colocated together to
+data collected by other index definitions, which is then colocated together to
 supply a search target made up of the separately extracted data. Virtual Index
 Definitions are effectively treated as aggregate definitions, matching across
 all values extracted from constituent non-virtual index definitions.  They can
@@ -51,11 +51,14 @@ field.
 
 Increased use of Metabib Display Fields
 +++++++++++++++++++++++++++++++++++++++
-In extention of changes proposed in other available branches, we here use
-Metabib Display Fields to render catalog search results, intermediate metarecord
-results, and record detail pages.This will requires the addition of several new
-Metabib Display Field definitions, as well as Perl services to gather and render
-the data.
+We use Metabib Display Fields (newly available in 3.0) to render catalog search
+results, intermediate metarecord results, and record detail pages.This requires
+the addition of several new Metabib Display Field definitions, as well as Perl
+services to gather and render the data.
+
+We also use more Metabib Display Fields in the client. As a result, 
+bibliographic fields will display in proper case in more client interfaces and
+in Evergreen reports.
 
 Search Term Highlighting
 ++++++++++++++++++++++++
@@ -75,7 +78,7 @@ fields are searched as well as exposing concepts like stemming.
 Interfaces
 ++++++++++
 A new AngularJS "MARC Search/Facet Fields" interface has been created to replace
- the Dojo version, and both have been extended to support Virtual Index
+the Dojo version, and both have been extended to support Virtual Index
 Definition data supplier mapping and weighting.
 
 Settings & Permissions
@@ -112,6 +115,22 @@ been augmented to be able to return a data structure describing how the search
 was performed, in a way that allows a separate support API to gather a
 highlighted version of the Display Field data for a given record.
 
+Default Weights
++++++++++++++++
+By default, the following fields will be weighted more heavily in keyword 
+searches. Administrators can change these defaults by changing the values in the
+ "All searchable fields" virtual index in the "MARC Search/Facet Fields"
+interface.
+
+  * Title proper
+  * Main title (a new index limited to the words in the 245a)
+  * Personal author
+  * All subjects
+
+In addition, note indexes and the physical description index will receive
+less weight in default keyword searches.
+
+
 Re-ingest or Indexing Dependencies
 ++++++++++++++++++++++++++++++++++
 With the addition and modification of many Index Definitions, a full reingest is

commit 33fe8e6a0824dfa6fc1884b1485f1a7ceb5b7b68
Author: Kathy Lussier <klussier at masslnc.org>
Date:   Mon Feb 26 14:26:42 2018 -0500

    LP#1744385: Adding Mike's commit message as a starter release note entry
    
    Signed-off-by: Kathy Lussier <klussier at masslnc.org>
    Signed-off-by: Dan Wells <dbw2 at calvin.edu>

diff --git a/docs/RELEASE_NOTES_NEXT/Architecture/search-display-infrastructure-improvements.adoc b/docs/RELEASE_NOTES_NEXT/Architecture/search-display-infrastructure-improvements.adoc
new file mode 100644
index 0000000..88b2f8c
--- /dev/null
+++ b/docs/RELEASE_NOTES_NEXT/Architecture/search-display-infrastructure-improvements.adoc
@@ -0,0 +1,135 @@
+Virtual Index Definitions
+^^^^^^^^^^^^^^^^^^^^^^^^^
+The practical purpose of Virtual Index Definitions is to supply an Evergreen
+administrator with the ability to control the weighting and field inclusion of
+values in the general keyword index, commonly referred to as "the blob,"
+without requiring tricky configuration that has subtle semantics, an
+over-abundance of index definitions which can slow search generally, or the
+need to reingest all records on a regular basis as experiments are performed
+and the configuration refined. Significant results of recasting keyword indexes
+as a set of one or more Virtual Index Definitions will be simpler search
+configuration management, faster search speed overall, and more practical
+reconfiguration and adjustment as needed.
+
+Previous to this commit, in order to provide field-specific weighting to
+keyword matches against titles or authors, an administrator must duplicate many
+other index definitions and supply overriding weights to those duplicates. This
+not only complicates configuration, but slows down record ingest as well as
+search. It is also fairly ineffective at achieving the goal of weighted keyword
+fields. Virtual Index Definitions will substantially alleviate the need for
+these workarounds and their consequences.
+
+  * A Virtual Index Definition is not required supply any configuration for
+extracting bibliographic data from records, but instead can become a sink for
+data collected by other index definitions which is then colocated together to
+supply a search target made up of the separately extracted data. Virtual Index
+Definitions are effectively treated as aggregate definitions, matching across
+all values extracted from constituent non-virtual index definitions.  They can
+further make use of the Combined class functionality to colocate all values in a
+class together for matching even across virtual fields.
+
+  * Configuration allows for weighting of constituent index definitions that
+participate in a Virtual Index Definition. This weighting is separate from the
+weighting supplied when the index definition itself is a search target.
+
+  * The Evergreen QueryParser driver returns the list of fields actually
+searched using every user-supplied term set, including constituent expansion
+when a Virtual Index Definition is searched. In particular, this will facilitate
+Search Term Highlighting described below.
+
+  * Stock configuration changes make use of pre-existing, non-virtual index
+definitions mapped to new a Virtual Index Definition that implements the
+functionality provided by the keyword|keyword index definition. The
+keyword|keyword definition is left in place for the time being, until more data
+can be gathered about the real-world effect of removing it entirely and 
+replacing it with Virtual Index Definition mappings.
+
+  * New system administration functions will be created to facilitate
+modification of Virtual Index Definition mapping, avoiding the need for a full
+reingest when existing index definitions are added or removed from a virtual
+field.
+
+Increased use of Metabib Display Fields
++++++++++++++++++++++++++++++++++++++++
+In extention of changes proposed in other available branches, we here use
+Metabib Display Fields to render catalog search results, intermediate metarecord
+results, and record detail pages.This will requires the addition of several new
+Metabib Display Field definitions, as well as Perl services to gather and render
+the data.
+
+Search Term Highlighting
+++++++++++++++++++++++++
+This commit enables Search Term Highlighting in the OPAC on the main search
+results page, the record detail page, and intermediate pages such as metarecord
+grouped results page. Highlighting search terms will help the user determine why
+a particular record (or set of records) was retrieved.
+
+Highlighting of matched terms uses the same stemming used to accomplish the
+search, as configured per field and class.
+
+This feature will help the user more quickly determine the relevance of a
+particular record by calling their attention to search terms in context. Lastly,
+it will help familiarize the user with how records are searched, including which
+fields are searched as well as exposing concepts like stemming.
+
+Interfaces
+++++++++++
+A new AngularJS "MARC Search/Facet Fields" interface has been created to replace
+ the Dojo version, and both have been extended to support Virtual Index
+Definition data supplier mapping and weighting.
+
+Settings & Permissions
+++++++++++++++++++++++
+The new Virtual Index Definition data supplier mapping table, 
+config.metabib_field_virtual_map, requires the same permissions as the
+MARC Search/Facet Fields interface: CREATE_METABIB_FIELD, UPDATE_METABIB_FIELD,
+DELETE_METABIB_FIELD, or ADMIN_METABIB_FIELD for all actions
+
+There is a new template-level global configuration variable in config.tt2 called
+search.no_highlight which disables highlighting for users of that config.tt2
+instance.
+
+Public Catalog
+++++++++++++++
+The public and staff catalog will make use of new APIs to identify and display
+highlight-augmented values for those Display Fields used to render the search
+result pages, intermediate metarecord constituent pages, and record detail
+pages.  Highlighting of terms will be performed using the application of
+Template::Toolkit-driven CSS. A generic CSS class identifying a highlighted
+term, along with CSS classes identifying the search class and each search field
+will be available for use for customization of the highlighting. A stock CSS
+template is provided as a baseline upon which sites may expand.
+
+When highlighting is generally enabled, it may be turned on or off on a per-page
+basis through the use of a UI component which will request the page again
+without highlighting.
+
+Backend
++++++++
+There now exist several new database tables and functions primarily in support
+of search highlighting. Additionally, the QueryParser driver for Evergreen has
+been augmented to be able to return a data structure describing how the search
+was performed, in a way that allows a separate support API to gather a
+highlighted version of the Display Field data for a given record.
+
+Re-ingest or Indexing Dependencies
+++++++++++++++++++++++++++++++++++
+With the addition and modification of many Index Definitions, a full reingest is
+recommended.  However, search will continue to work as it did before the changes
+in this commit for those records that have not yet been reingested during that
+process.  Therefore a slow, rolling reingest is recommended.
+
+Performance Implications or Concerns
+++++++++++++++++++++++++++++++++++++
+Because the Metabib Display Fields infrastructure will eventually replace
+functionality that is significantly more CPU-intensive in the various forms of
+XML parsing, XSLT transformation, XPath calculation, and
+Metabib Virtual Record construction, it is expected that the overall CPU load
+will be reduced by this development, and ideally the overall time required to
+perform and render a search will likewise drop. It is unlikely that the speed 
+increase will be visible to users on a per-search basis, but that search in
+aggregate will become a smaller consumer of resources.
+
+
+
+

commit 5b311a2525e500e86f9cb60aaceb0cd414f6c821
Author: Mike Rylander <mrylander at gmail.com>
Date:   Mon Feb 26 11:52:27 2018 -0500

    LP#1744385: Remove debug timing display
    
    Signed-off-by: Mike Rylander <mrylander at gmail.com>
    Signed-off-by: Kathy Lussier <klussier at masslnc.org>
    Signed-off-by: Dan Wells <dbw2 at calvin.edu>

diff --git a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm
index e753057..d3aecaa 100644
--- a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm
+++ b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm
@@ -39,7 +39,7 @@ use constant COOKIE_ANON_CACHE => 'anoncache';
 use constant ANON_CACHE_MYLIST => 'mylist';
 use constant ANON_CACHE_STAFF_SEARCH => 'staffsearch';
 
-use constant DEBUG_TIMING => 1;
+use constant DEBUG_TIMING => 0;
 
 sub new {
     my($class, $apache, $ctx) = @_;

commit 867cc29335d15c5c30a8311c12b150320a0f2f4f
Author: Mike Rylander <mrylander at gmail.com>
Date:   Fri Feb 23 10:32:19 2018 -0500

    LP#1744385: Final seed data fixups
    
    Signed-off-by: Mike Rylander <mrylander at gmail.com>
    Signed-off-by: Kathy Lussier <klussier at masslnc.org>
    Signed-off-by: Dan Wells <dbw2 at calvin.edu>

diff --git a/Open-ILS/src/sql/Pg/950.data.seed-values.sql b/Open-ILS/src/sql/Pg/950.data.seed-values.sql
index fb829c6..ab4468d 100644
--- a/Open-ILS/src/sql/Pg/950.data.seed-values.sql
+++ b/Open-ILS/src/sql/Pg/950.data.seed-values.sql
@@ -214,7 +214,7 @@ INSERT INTO config.metabib_field ( id, field_class, name, label,
 INSERT INTO config.metabib_field (id, field_class, name,
     label, xpath, display_field, search_field, browse_field)
 VALUES (
-    38, 'keyword', 'edition',
+    38, 'identifier', 'edition',
     oils_i18n_gettext(38, 'Edition', 'cmf', 'label'),
     $$//mods33:mods/mods33:originInfo//mods33:edition[1]$$,
     TRUE, TRUE, FALSE
@@ -232,7 +232,7 @@ VALUES (
 INSERT INTO config.metabib_field (id, field_class, name,
     label, xpath, display_field, search_field, browse_field)
 VALUES (
-    40, 'keyword', 'publisher',
+    40, 'identifier', 'publisher',
     oils_i18n_gettext(40, 'Publisher', 'cmf', 'label'),
     $$//mods33:mods/mods33:originInfo//mods33:publisher[1]$$,
     TRUE, TRUE, FALSE
@@ -320,11 +320,11 @@ VALUES (
 INSERT INTO config.metabib_field (id, field_class, name, format,
     label, xpath, display_xpath, display_field, search_field, browse_field)
 VALUES (
-    52, 'keyword', 'origin_info', 'marcxml',
+    52, 'identifier', 'origin_info', 'marcxml',
     oils_i18n_gettext(52, 'Origin Info', 'cmf', 'label'),
     $$//*[@tag='260']$$,
     $$//*[local-name()='subfield' and contains('abc', at code)]$$,
-    TRUE, TRUE, FALSE
+    TRUE, FALSE, FALSE
 );
 
 INSERT INTO config.metabib_field (id, field_class, name, format, weight,
@@ -341,7 +341,7 @@ INSERT INTO config.metabib_field_virtual_map (real, virtual)
             45
       FROM  config.metabib_field
       WHERE search_field
-            AND id NOT IN (15, 45)
+            AND id NOT IN (15, 45, 38, 40)
             AND id NOT IN (SELECT real FROM config.metabib_field_virtual_map);
 
 UPDATE config.metabib_field_virtual_map SET weight = -1 WHERE real = 39;
diff --git a/Open-ILS/src/sql/Pg/953.data.MODS32-xsl.sql b/Open-ILS/src/sql/Pg/953.data.MODS32-xsl.sql
index 69b4ce6..488c636 100644
--- a/Open-ILS/src/sql/Pg/953.data.MODS32-xsl.sql
+++ b/Open-ILS/src/sql/Pg/953.data.MODS32-xsl.sql
@@ -98,6 +98,9 @@ Added Log Comment
 						<xsl:with-param name="chopString">
 							<xsl:value-of select="$title"/>
 						</xsl:with-param>
+                        <xsl:with-param name="punctuation">
+                          <xsl:text>,;/ </xsl:text>
+                        </xsl:with-param>
 					</xsl:call-template>
 				</xsl:variable>
 				<xsl:choose>
@@ -1353,6 +1356,45 @@ Added Log Comment
 		
 		<!--3.2 change tmee additional note fields-->
 		
+        <xsl:for-each select="marc:datafield[@tag=502]">
+            <note type="thesis">
+                <xsl:call-template name="uri"/>
+                <xsl:variable name="str">
+                    <xsl:for-each select="marc:subfield[@code!='6' or @code!='8']">
+                        <xsl:value-of select="."/>
+                        <xsl:text> </xsl:text>
+                    </xsl:for-each>
+                </xsl:variable>
+                <xsl:value-of select="substring($str,1,string-length($str)-1)"/>
+            </note>
+        </xsl:for-each>
+
+        <xsl:for-each select="marc:datafield[@tag=504]">
+            <note type="bibliography">
+                <xsl:call-template name="uri"/>
+                <xsl:variable name="str">
+                    <xsl:for-each select="marc:subfield[@code!='6' or @code!='8']">
+                        <xsl:value-of select="."/>
+                        <xsl:text> </xsl:text>
+                    </xsl:for-each>
+                </xsl:variable>
+                <xsl:value-of select="substring($str,1,string-length($str)-1)"/>
+            </note>
+        </xsl:for-each>
+
+        <xsl:for-each select="marc:datafield[@tag=508]">
+            <note type="creation/production credits">
+                <xsl:call-template name="uri"/>
+                <xsl:variable name="str">
+                    <xsl:for-each select="marc:subfield[@code!='6' or @code!='8']">
+                        <xsl:value-of select="."/>
+                        <xsl:text> </xsl:text>
+                    </xsl:for-each>
+                </xsl:variable>
+                <xsl:value-of select="substring($str,1,string-length($str)-1)"/>
+            </note>
+        </xsl:for-each>
+
 		<xsl:for-each select="marc:datafield[@tag=506]">
 			<note type="restrictions">
 				<xsl:call-template name="uri"></xsl:call-template>
@@ -1460,9 +1502,7 @@ Added Log Comment
 		
 
 		
-		
-		
-		<xsl:for-each select="marc:datafield[@tag=501 or @tag=502 or @tag=504 or @tag=507 or @tag=508 or  @tag=513 or @tag=514 or @tag=515 or @tag=516 or @tag=522 or @tag=524 or @tag=525 or @tag=526 or @tag=535 or @tag=536 or @tag=540 or @tag=541 or @tag=544 or @tag=545 or @tag=546 or @tag=547 or @tag=550 or @tag=552 or @tag=555 or @tag=556 or @tag=561 or @tag=562 or @tag=565 or @tag=567 or @tag=580 or @tag=581 or @tag=584 or @tag=585 or @tag=586]">
+        <xsl:for-each select="marc:datafield[@tag=501 or @tag=507 or @tag=513 or @tag=514 or @tag=515 or @tag=516 or @tag=522 or @tag=524 or @tag=525 or @tag=526 or @tag=535 or @tag=536 or @tag=540 or @tag=541 or @tag=544 or @tag=545 or @tag=546 or @tag=547 or @tag=550 or @tag=552 or @tag=555 or @tag=556 or @tag=561 or @tag=562 or @tag=565 or @tag=567 or @tag=580 or @tag=581 or @tag=584 or @tag=585 or @tag=586]">
 			<note>
 				<xsl:call-template name="uri"></xsl:call-template>
 				<xsl:variable name="str">
diff --git a/Open-ILS/src/sql/Pg/954.data.MODS33-xsl.sql b/Open-ILS/src/sql/Pg/954.data.MODS33-xsl.sql
index b3670ff..e824cdc 100644
--- a/Open-ILS/src/sql/Pg/954.data.MODS33-xsl.sql
+++ b/Open-ILS/src/sql/Pg/954.data.MODS33-xsl.sql
@@ -113,6 +113,9 @@ Revision 1.2 - Added Log Comment  2003/03/24 19:37:42  ckeith
 						<xsl:with-param name="chopString">
 							<xsl:value-of select="$title"/>
 						</xsl:with-param>
+                        <xsl:with-param name="punctuation">
+                          <xsl:text>,;/ </xsl:text>
+                        </xsl:with-param>
 					</xsl:call-template>
 				</xsl:variable>
 				<xsl:choose>
@@ -1390,6 +1393,45 @@ Revision 1.2 - Added Log Comment  2003/03/24 19:37:42  ckeith
 
 		<!--3.2 change tmee additional note fields-->
 
+        <xsl:for-each select="marc:datafield[@tag=502]">
+            <note type="thesis">
+                <xsl:call-template name="uri"/>
+                <xsl:variable name="str">
+                    <xsl:for-each select="marc:subfield[@code!='6' or @code!='8']">
+                        <xsl:value-of select="."/>
+                        <xsl:text> </xsl:text>
+                    </xsl:for-each>
+                </xsl:variable>
+                <xsl:value-of select="substring($str,1,string-length($str)-1)"/>
+            </note>
+        </xsl:for-each>
+
+        <xsl:for-each select="marc:datafield[@tag=504]">
+            <note type="bibliography">
+                <xsl:call-template name="uri"/>
+                <xsl:variable name="str">
+                    <xsl:for-each select="marc:subfield[@code!='6' or @code!='8']">
+                        <xsl:value-of select="."/>
+                        <xsl:text> </xsl:text>
+                    </xsl:for-each>
+                </xsl:variable>
+                <xsl:value-of select="substring($str,1,string-length($str)-1)"/>
+            </note>
+        </xsl:for-each>
+
+        <xsl:for-each select="marc:datafield[@tag=508]">
+            <note type="creation/production credits">
+                <xsl:call-template name="uri"/>
+                <xsl:variable name="str">
+                    <xsl:for-each select="marc:subfield[@code!='6' or @code!='8']">
+                        <xsl:value-of select="."/>
+                        <xsl:text> </xsl:text>
+                    </xsl:for-each>
+                </xsl:variable>
+                <xsl:value-of select="substring($str,1,string-length($str)-1)"/>
+            </note>
+        </xsl:for-each>
+
 		<xsl:for-each select="marc:datafield[@tag=506]">
 			<note type="restrictions">
 				<xsl:call-template name="uri"/>
@@ -1496,7 +1538,7 @@ Revision 1.2 - Added Log Comment  2003/03/24 19:37:42  ckeith
 		</xsl:for-each>
 
 		<xsl:for-each
-			select="marc:datafield[@tag=501 or @tag=502 or @tag=504 or @tag=507 or @tag=508 or  @tag=513 or @tag=514 or @tag=515 or @tag=516 or @tag=522 or @tag=524 or @tag=525 or @tag=526 or @tag=535 or @tag=536 or @tag=540 or @tag=541 or @tag=544 or @tag=545 or @tag=546 or @tag=547 or @tag=550 or @tag=552 or @tag=555 or @tag=556 or @tag=561 or @tag=562 or @tag=565 or @tag=567 or @tag=580 or @tag=581 or @tag=584 or @tag=585 or @tag=586]">
+            select="marc:datafield[@tag=501 or @tag=507 or @tag=513 or @tag=514 or @tag=515 or @tag=516 or @tag=522 or @tag=524 or @tag=525 or @tag=526 or @tag=535 or @tag=536 or @tag=540 or @tag=541 or @tag=544 or @tag=545 or @tag=546 or @tag=547 or @tag=550 or @tag=552 or @tag=555 or @tag=556 or @tag=561 or @tag=562 or @tag=565 or @tag=567 or @tag=580 or @tag=581 or @tag=584 or @tag=585 or @tag=586]">
 			<note>
 				<xsl:call-template name="uri"/>
 				<xsl:variable name="str">
diff --git a/Open-ILS/src/sql/Pg/upgrade/WWWW.data.display-field-seed-data.sql b/Open-ILS/src/sql/Pg/upgrade/WWWW.data.display-field-seed-data.sql
index 4230c34..5ec2eeb 100644
--- a/Open-ILS/src/sql/Pg/upgrade/WWWW.data.display-field-seed-data.sql
+++ b/Open-ILS/src/sql/Pg/upgrade/WWWW.data.display-field-seed-data.sql
@@ -9,7 +9,7 @@ UPDATE config.metabib_field SET display_xpath = facet_xpath, display_field = TRU
 INSERT INTO config.metabib_field (id, field_class, name, 
     label, xpath, display_field, search_field, browse_field)
 VALUES (
-    38, 'keyword', 'edition', 
+    38, 'identifier', 'edition', 
     oils_i18n_gettext(38, 'Edition', 'cmf', 'label'),
     $$//mods33:mods/mods33:originInfo//mods33:edition[1]$$,
     TRUE, TRUE, FALSE
@@ -27,7 +27,7 @@ VALUES (
 INSERT INTO config.metabib_field (id, field_class, name, 
     label, xpath, display_field, search_field, browse_field)
 VALUES (
-    40, 'keyword', 'publisher', 
+    40, 'identifier', 'publisher', 
     oils_i18n_gettext(40, 'Publisher', 'cmf', 'label'),
     $$//mods33:mods/mods33:originInfo//mods33:publisher[1]$$,
     TRUE, TRUE, FALSE
@@ -112,11 +112,11 @@ VALUES (
 INSERT INTO config.metabib_field (id, field_class, name, format,
     label, xpath, display_xpath, display_field, search_field, browse_field)
 VALUES (
-    52, 'keyword', 'origin_info', 'marcxml',
+    52, 'identifier', 'origin_info', 'marcxml',
     oils_i18n_gettext(52, 'Origin Info', 'cmf', 'label'),
     $$//*[@tag='260']$$,
     $$//*[local-name()='subfield' and contains('abc', at code)]$$,
-    TRUE, TRUE, FALSE
+    TRUE, FALSE, FALSE
 );
 
 
diff --git a/Open-ILS/src/sql/Pg/upgrade/YYYY.data.mods-title-punctuation-change.sql b/Open-ILS/src/sql/Pg/upgrade/YYYY.data.mods-title-punctuation-change.sql
index eb7e34e..febf832 100644
--- a/Open-ILS/src/sql/Pg/upgrade/YYYY.data.mods-title-punctuation-change.sql
+++ b/Open-ILS/src/sql/Pg/upgrade/YYYY.data.mods-title-punctuation-change.sql
@@ -4901,7 +4901,7 @@ Revision 1.2 - Added Log Comment  2003/03/24 19:37:42  ckeith
                 </xsl:for-each>
 
                 <xsl:for-each
-                        select="marc:datafield[@tag=501 or @tag=507 or @tag=513 or @tag=514 or @tag=515 or @tag=516 or @tag=522 or @tag=524 or @tag=525 or @tag=526 or @tag=535 or @tag=536 or @tag=540 or @tag=541 or @tag=544 or @tag=545 or @tag=546 or @tag=547 or @tag=550 or @tag=552 or @tag=555 or @tag=556 or @tag=561 or @tag=562 or @tag=565 or @tag=567 or @tag=580 or @tag=581 or @tag=584 or @tag=585 or @tag=586]">+
+                        select="marc:datafield[@tag=501 or @tag=507 or @tag=513 or @tag=514 or @tag=515 or @tag=516 or @tag=522 or @tag=524 or @tag=525 or @tag=526 or @tag=535 or @tag=536 or @tag=540 or @tag=541 or @tag=544 or @tag=545 or @tag=546 or @tag=547 or @tag=550 or @tag=552 or @tag=555 or @tag=556 or @tag=561 or @tag=562 or @tag=565 or @tag=567 or @tag=580 or @tag=581 or @tag=584 or @tag=585 or @tag=586]">
                         <note>
                                 <xsl:call-template name="uri"/>
                                 <xsl:variable name="str">
diff --git a/Open-ILS/src/sql/Pg/upgrade/ZZZZ.data.virtual_index_defs.sql b/Open-ILS/src/sql/Pg/upgrade/ZZZZ.data.virtual_index_defs.sql
index 491d009..9e4e425 100644
--- a/Open-ILS/src/sql/Pg/upgrade/ZZZZ.data.virtual_index_defs.sql
+++ b/Open-ILS/src/sql/Pg/upgrade/ZZZZ.data.virtual_index_defs.sql
@@ -17,7 +17,7 @@ INSERT INTO config.metabib_field_virtual_map (real, virtual)
             45
       FROM  config.metabib_field
       WHERE search_field
-            AND id NOT IN (15, 45)
+            AND id NOT IN (15, 45, 38, 40) -- keyword|keyword, self, edition, publisher
             AND id NOT IN (SELECT real FROM config.metabib_field_virtual_map);
 
 UPDATE config.metabib_field SET xpath=$$//mods32:mods/mods32:subject[not(descendant::mods32:geographicCode)]$$ WHERE id = 16;

commit dc8348576b4e523e9f89d32f967b2c80996c4be9
Author: Mike Rylander <mrylander at gmail.com>
Date:   Mon Feb 26 12:05:37 2018 -0500

    LP#1744385: Treat phrase terms the same as non-phrase terms WRT dictionaries
    
    Signed-off-by: Mike Rylander <mrylander at gmail.com>
    Signed-off-by: Kathy Lussier <klussier at masslnc.org>
    Signed-off-by: Dan Wells <dbw2 at calvin.edu>

diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Driver/Pg/QueryParser.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Driver/Pg/QueryParser.pm
index bd223cb..b3e64eb 100644
--- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Driver/Pg/QueryParser.pm
+++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Driver/Pg/QueryParser.pm
@@ -1805,19 +1805,14 @@ sub buildSQL {
     $lang ||= $self->node->plan->QueryParser->default_preferred_language;
     my $ts_configs = [];
 
-    if (@{$self->node->phrases}) {
-        # We assume we want 'simple' for phrases. Gives us less to match against later.
-        $ts_configs = ['simple'];
+    if (!@$fields) {
+        $ts_configs = $self->node->plan->QueryParser->class_ts_config($classname, $lang);
     } else {
-        if (!@$fields) {
-            $ts_configs = $self->node->plan->QueryParser->class_ts_config($classname, $lang);
-        } else {
-            for my $field (@$fields) {
-                push @$ts_configs, @{$self->node->plan->QueryParser->field_ts_config($classname, $field, $lang)};
-            }
+        for my $field (@$fields) {
+            push @$ts_configs, @{$self->node->plan->QueryParser->field_ts_config($classname, $field, $lang)};
         }
-        $ts_configs = [keys %{{map { $_ => 1 } @$ts_configs}}];
     }
+    $ts_configs = [keys %{{map { $_ => 1 } @$ts_configs}}];
 
     # Assume we want exact if none otherwise provided.
     # Because we can reasonably expect this to exist

commit 3d1fcf23bcdf2cf473efa34336c11bbab5af5f6b
Author: Mike Rylander <mrylander at gmail.com>
Date:   Thu Feb 22 15:19:14 2018 -0500

    LP#1744385: Adjust function for a change in PLPgSQL in PG 9.4.16
    
    Signed-off-by: Mike Rylander <mrylander at gmail.com>
    Signed-off-by: Kathy Lussier <klussier at masslnc.org>
    Signed-off-by: Dan Wells <dbw2 at calvin.edu>

diff --git a/Open-ILS/src/sql/Pg/300.schema.staged_search.sql b/Open-ILS/src/sql/Pg/300.schema.staged_search.sql
index 08ca281..e65df4a 100644
--- a/Open-ILS/src/sql/Pg/300.schema.staged_search.sql
+++ b/Open-ILS/src/sql/Pg/300.schema.staged_search.sql
@@ -1432,7 +1432,7 @@ BEGIN
         tsq_hstore := tsq_map::HSTORE;
     END IF;
 
-    FOR tsq, fields IN SELECT key, value FROM each(tsq_hstore) LOOP
+    FOR tsq, fields IN SELECT key, value FROM each(tsq_hstore::HSTORE) LOOP
         SELECT  ARRAY_AGG(unnest::INT) INTO afields
           FROM  unnest(regexp_split_to_array(fields,','));
         seen := seen || afields;
diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.highlight_search.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.highlight_search.sql
index ed50842..e0a9193 100644
--- a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.highlight_search.sql
+++ b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.highlight_search.sql
@@ -447,7 +447,7 @@ BEGIN
         tsq_hstore := tsq_map::HSTORE;
     END IF;
     
-    FOR tsq, fields IN SELECT key, value FROM each(tsq_hstore) LOOP
+    FOR tsq, fields IN SELECT key, value FROM each(tsq_hstore::HSTORE) LOOP
         SELECT  ARRAY_AGG(unnest::INT) INTO afields
           FROM  unnest(regexp_split_to_array(fields,','));
         seen := seen || afields;

commit 5d3b69c77c92f21308d7df6fae340a6f5acc2e33
Author: Mike Rylander <mrylander at gmail.com>
Date:   Thu Feb 22 13:08:51 2018 -0500

    LP#1744385: Add "Main Title" index definition and set reasonable defaults for virtual weighting
    
    Signed-off-by: Mike Rylander <mrylander at gmail.com>
    Signed-off-by: Kathy Lussier <klussier at masslnc.org>
    Signed-off-by: Dan Wells <dbw2 at calvin.edu>

diff --git a/Open-ILS/src/sql/Pg/950.data.seed-values.sql b/Open-ILS/src/sql/Pg/950.data.seed-values.sql
index d7cd409..fb829c6 100644
--- a/Open-ILS/src/sql/Pg/950.data.seed-values.sql
+++ b/Open-ILS/src/sql/Pg/950.data.seed-values.sql
@@ -327,6 +327,15 @@ VALUES (
     TRUE, TRUE, FALSE
 );
 
+INSERT INTO config.metabib_field (id, field_class, name, format, weight,
+    label, xpath, display_field, search_field, browse_field, facet_field)
+VALUES (
+    53, 'title', 'maintitle', 'marcxml', 10,
+    oils_i18n_gettext(53, 'Main Title', 'cmf', 'label'),
+    $$//*[@tag='245']/*[@code='a']$$,
+    FALSE, TRUE, FALSE, FALSE
+);
+
 INSERT INTO config.metabib_field_virtual_map (real, virtual)
     SELECT  id,
             45
@@ -335,6 +344,18 @@ INSERT INTO config.metabib_field_virtual_map (real, virtual)
             AND id NOT IN (15, 45)
             AND id NOT IN (SELECT real FROM config.metabib_field_virtual_map);
 
+UPDATE config.metabib_field_virtual_map SET weight = -1 WHERE real = 39;
+UPDATE config.metabib_field_virtual_map SET weight = 0 WHERE real = 41;
+UPDATE config.metabib_field_virtual_map SET weight = 0 WHERE real = 42;
+UPDATE config.metabib_field_virtual_map SET weight = 0 WHERE real = 46;
+UPDATE config.metabib_field_virtual_map SET weight = 0 WHERE real = 47;
+UPDATE config.metabib_field_virtual_map SET weight = 0 WHERE real = 48;
+UPDATE config.metabib_field_virtual_map SET weight = 0 WHERE real = 50;
+UPDATE config.metabib_field_virtual_map SET weight = 8 WHERE real = 6;
+UPDATE config.metabib_field_virtual_map SET weight = 8 WHERE real = 8;
+UPDATE config.metabib_field_virtual_map SET weight = 8 WHERE real = 16;
+UPDATE config.metabib_field_virtual_map SET weight = 12 WHERE real = 53;
+
 -- Modify existing config.metabib_field entries
 
 UPDATE config.metabib_field SET display_field = TRUE WHERE id IN (
diff --git a/Open-ILS/src/sql/Pg/upgrade/ZZZZ.data.virtual_index_defs.sql b/Open-ILS/src/sql/Pg/upgrade/ZZZZ.data.virtual_index_defs.sql
index fb868f4..491d009 100644
--- a/Open-ILS/src/sql/Pg/upgrade/ZZZZ.data.virtual_index_defs.sql
+++ b/Open-ILS/src/sql/Pg/upgrade/ZZZZ.data.virtual_index_defs.sql
@@ -3,6 +3,15 @@ BEGIN;
 INSERT INTO config.metabib_field (id, field_class, name, label, browse_field)
     VALUES (45, 'keyword', 'blob', 'All searchable fields', FALSE);
 
+INSERT INTO config.metabib_field (id, field_class, name, format, weight,
+    label, xpath, display_field, search_field, browse_field, facet_field)
+VALUES (
+    53, 'title', 'maintitle', 'marcxml', 10,
+    oils_i18n_gettext(53, 'Main Title', 'cmf', 'label'),
+    $$//*[@tag='245']/*[@code='a']$$,
+    FALSE, TRUE, FALSE, FALSE
+);
+
 INSERT INTO config.metabib_field_virtual_map (real, virtual)
     SELECT  id,
             45
@@ -13,6 +22,18 @@ INSERT INTO config.metabib_field_virtual_map (real, virtual)
 
 UPDATE config.metabib_field SET xpath=$$//mods32:mods/mods32:subject[not(descendant::mods32:geographicCode)]$$ WHERE id = 16;
 
+UPDATE config.metabib_field_virtual_map SET weight = -1 WHERE real = 39;
+UPDATE config.metabib_field_virtual_map SET weight = 0 WHERE real = 41;
+UPDATE config.metabib_field_virtual_map SET weight = 0 WHERE real = 42;
+UPDATE config.metabib_field_virtual_map SET weight = 0 WHERE real = 46;
+UPDATE config.metabib_field_virtual_map SET weight = 0 WHERE real = 47;
+UPDATE config.metabib_field_virtual_map SET weight = 0 WHERE real = 48;
+UPDATE config.metabib_field_virtual_map SET weight = 0 WHERE real = 50;
+UPDATE config.metabib_field_virtual_map SET weight = 8 WHERE real = 6;
+UPDATE config.metabib_field_virtual_map SET weight = 8 WHERE real = 8;
+UPDATE config.metabib_field_virtual_map SET weight = 8 WHERE real = 16;
+UPDATE config.metabib_field_virtual_map SET weight = 12 WHERE real = 53;
+
 -- Stemming for genre
 INSERT INTO config.metabib_field_ts_map (metabib_field, ts_config)
     SELECT 33, 'english_nostop' WHERE NOT EXISTS (

commit 024ec4c056c9f536b6f9e018b760c9e19bdebe8a
Author: Mike Rylander <mrylander at gmail.com>
Date:   Thu Feb 22 10:47:16 2018 -0500

    LP#1744385: Add genre stemming to baseline schema
    
    Signed-off-by: Mike Rylander <mrylander at gmail.com>
    Signed-off-by: Kathy Lussier <klussier at masslnc.org>
    Signed-off-by: Dan Wells <dbw2 at calvin.edu>

diff --git a/Open-ILS/src/sql/Pg/950.data.seed-values.sql b/Open-ILS/src/sql/Pg/950.data.seed-values.sql
index b0f6971..d7cd409 100644
--- a/Open-ILS/src/sql/Pg/950.data.seed-values.sql
+++ b/Open-ILS/src/sql/Pg/950.data.seed-values.sql
@@ -15677,6 +15677,8 @@ INSERT INTO config.metabib_class_ts_map(field_class, ts_config, index_weight, al
     ('subject','english_nostop','C',true),
     ('identifier','simple','A',true);
 
+INSERT INTO config.metabib_field_ts_map (metabib_field, ts_config) VALUES (33, 'english_nostop');
+
 INSERT INTO config.org_unit_setting_type (
     name, label, description, datatype, fm_class, update_perm, grp
 ) VALUES (

commit 767e7caa07d9281730b52b5ba6d7ff78ba77fc89
Author: Mike Rylander <mrylander at gmail.com>
Date:   Wed Feb 21 16:39:21 2018 -0500

    LP#1744385: Update seed data with more Display Field mappings
    
    Signed-off-by: Mike Rylander <mrylander at gmail.com>
    Signed-off-by: Kathy Lussier <klussier at masslnc.org>
    Signed-off-by: Dan Wells <dbw2 at calvin.edu>

diff --git a/Open-ILS/src/sql/Pg/950.data.seed-values.sql b/Open-ILS/src/sql/Pg/950.data.seed-values.sql
index a8ef6e2..b0f6971 100644
--- a/Open-ILS/src/sql/Pg/950.data.seed-values.sql
+++ b/Open-ILS/src/sql/Pg/950.data.seed-values.sql
@@ -374,6 +374,12 @@ INSERT INTO config.display_field_map (name, field, multi) VALUES
     ('tcn',                 26, FALSE),
     ('edition',             38, FALSE),
     ('physical_description',39, TRUE),
+    ('genre',               33, TRUE),
+    ('bibliography',        46, TRUE),
+    ('thesis',              47, TRUE),
+    ('performers',          49, TRUE),
+    ('production_credits',  48, TRUE),
+    ('general_note',        50, TRUE),
     ('publisher',           52, FALSE),
     ('abstract',            41, FALSE),
     ('toc',                 42, FALSE),
diff --git a/Open-ILS/src/sql/Pg/upgrade/WWWW.data.display-field-seed-data.sql b/Open-ILS/src/sql/Pg/upgrade/WWWW.data.display-field-seed-data.sql
index e87c170..4230c34 100644
--- a/Open-ILS/src/sql/Pg/upgrade/WWWW.data.display-field-seed-data.sql
+++ b/Open-ILS/src/sql/Pg/upgrade/WWWW.data.display-field-seed-data.sql
@@ -146,6 +146,12 @@ INSERT INTO config.display_field_map (name, field, multi) VALUES
     ('tcn',                 26, FALSE),
     ('edition',             38, FALSE),
     ('physical_description',39, TRUE),
+    ('genre',               33, TRUE),
+    ('bibliography',        46, TRUE),
+    ('thesis',              47, TRUE),
+    ('performers',          49, TRUE),
+    ('production_credits',  48, TRUE),
+    ('general_note',        50, TRUE),
     ('publisher',           52, FALSE),
     ('abstract',            41, FALSE),
     ('toc',                 42, FALSE),

commit 952c1af10ad6501603199ebe8ea9e1568beffc84
Author: Mike Rylander <mrylander at gmail.com>
Date:   Wed Feb 21 15:08:35 2018 -0500

    LP#1744385: Make use of short-term unAPI cache and parallelize metarecord constituent retrieval
    
    Signed-off-by: Mike Rylander <mrylander at gmail.com>
    Signed-off-by: Kathy Lussier <klussier at masslnc.org>
    Signed-off-by: Dan Wells <dbw2 at calvin.edu>

diff --git a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Search.pm b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Search.pm
index b95ffc0..c21566a 100644
--- a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Search.pm
+++ b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Search.pm
@@ -525,33 +525,43 @@ sub load_rresults {
     # load temporary_list settings for user and ou:
     $self->_load_lists_and_settings if ($ctx->{user});
 
+    my %mr_contents;
     # shove recs into context in search results order
     for my $rec_id (@$rec_ids) {
         my ($rec) = grep { $_->{$id_key} == $rec_id } @data;
         push(@{$ctx->{records}}, $rec);
 
         if ($is_meta) {
-            my $meta_results;
             try {
                 my $method = 'open-ils.search.biblio.multiclass.query';
                 $method .= '.staff' if $ctx->{is_staff};
                 my $ses = OpenSRF::AppSession->create('open-ils.search');
-                $self->timelog("Firing off the multiclass query");
+                $self->timelog("Firing off the multiclass query: ". $rec_id);
                 $args->{from_metarecord} = $rec_id;
                 # offset of main search does not apply to the MR
                 # constituents query
                 my $save_offset = $args->{offset};
                 $args->{offset} = 0;
-                my $req = $ses->request($method, $args, $query, 1);
+                $mr_contents{$rec_id} = $ses->request($method, $args, $query, 1);
                 $args->{offset} = $save_offset;
-                $meta_results = $req->gather(1);
-                $self->timelog("Returned from the multiclass query");
-
             } catch Error with {
                 my $err = shift;
                 $logger->error("multiclass search error: $err");
-                $meta_results = {count => 0, ids => []};
             };
+        }
+    }
+
+    # above we fire all searches in parallel, now we collect the results
+    if ($is_meta) {
+        for my $rec_id (@$rec_ids) {
+            my ($rec) = grep { $_->{$id_key} == $rec_id } @data;
+            my $meta_results;
+            if ($mr_contents{$rec_id}) {
+                $meta_results = $mr_contents{$rec_id}->gather(1);
+                $self->timelog("Returned from the multiclass query: ". $rec_id);
+            } else {
+                $meta_results = {count => 0, ids => []};
+            }
             my $meta_rec_ids = [map { $_->[0] } @{$meta_results->{ids}}];
             $rec->{mr_constituent_count} = $meta_results->{count};
             $rec->{mr_constituent_ids} = $meta_rec_ids;
diff --git a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Util.pm b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Util.pm
index 5505cd6..7ecddc8 100644
--- a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Util.pm
+++ b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Util.pm
@@ -398,26 +398,90 @@ sub get_records_and_facets {
         } else {
             $unapi_data->{marc_xml} = XML::LibXML->new->parse_string($unapi_data->{marc_xml})->documentElement;
             $tmp_data{$unapi_data->{id}} = $unapi_data;
+            $unapi_cache->put_cache($unapi_cache_key, { running => $$ }, 5);
         }
     }
 
-    my $unapi_req = $ses->request(
-        'open-ils.cstore.json_query',
-         {from => [
-            $unapi_type, '{'.join(',', at loop_recs).'}', 'marcxml', $flesh,
-            $unapi_args->{site}, 
-            $unapi_args->{depth}, 
-            $slimit,
-            undef, undef, $unapi_args->{pref_lib}
-        ]}
-    );
-
     my $hl_req = $hl_ses->request(
         'open-ils.search.fetch.metabib.display_field.highlight.atomic',
         $self->ctx->{query_struct}{additional_data}{highlight_map},
         @$rec_ids
     ) if (!$is_meta);
 
+    if (@loop_recs) {
+        my $unapi_req = $ses->request(
+            'open-ils.cstore.json_query',
+             {from => [
+                $unapi_type, '{'.join(',', at loop_recs).'}', 'marcxml', $flesh,
+                $unapi_args->{site}, 
+                $unapi_args->{depth}, 
+                $slimit,
+                undef, undef, $unapi_args->{pref_lib}
+            ]}
+        );
+    
+        my $data = $unapi_req->gather(1);
+    
+        $outer_self->timelog("get_records_and_facets(): got feed content");
+    
+        # Protect against requests for non-existent records
+        return unless ($data->{$unapi_type});
+    
+        my $doc = XML::LibXML->new->parse_string($data->{$unapi_type})->documentElement;
+    
+        $outer_self->timelog("get_records_and_facets(): parsed xml");
+        for my $xml ($doc->getElementsByTagName('record')) {
+            $xml = XML::LibXML->new->parse_string($xml->toString)->documentElement;
+    
+            # Protect against legacy invalid MARCXML that might not have a 901c
+            my $bre_id;
+            my $mmr_id;
+            my $bre_id_nodes =  $xml->find('*[@tag="901"]/*[@code="c"]');
+            if ($bre_id_nodes) {
+                $bre_id =  $bre_id_nodes->[0]->textContent;
+            } else {
+                $logger->warn("Missing 901 subfield 'c' in " . $xml->toString());
+            }
+        
+            if ($is_meta) {
+                # extract metarecord ID from mmr.unapi tag
+                for my $node ($xml->getElementsByTagName('abbr')) {
+                    my $title = $node->getAttribute('title');
+                    ($mmr_id = $title) =~ 
+                        s/tag:open-ils.org:U2\@mmr\/(\d+)\/.*/$1/g;
+                    last if $mmr_id;
+                }
+            }
+        
+            my $rec_id = $mmr_id ? $mmr_id : $bre_id;
+            $tmp_data{$rec_id} = {
+                id => $rec_id, 
+                bre_id => $bre_id, 
+                mmr_id => $mmr_id,
+                marc_xml => $xml
+            };
+        
+            if ($rec_id) {
+                # Let other backends grab our data now that we're done.
+                my $key = 'TPAC_unapi_cache_'.$rec_id.'_'.$unapi_cache_key_suffix;
+                my $cache_data = $unapi_cache->get_cache($key);
+                if (!$cache_data || $$cache_data{running} == $$) {
+                    $unapi_cache->put_cache($key, {
+                        bre_id => $bre_id,
+                        mmr_id => $mmr_id,
+                        id => $rec_id, 
+                        marc_xml => $xml->toString
+                    }, 10);
+                }
+            }
+        }
+    }
+
+    if (!$is_meta) {
+        my $hl_data = $hl_req->gather(1); # list of arrayref of hashrefs
+        $self->ctx->{_hl_data} = { map { ''.$$_[0]{source} => $_ } @$hl_data };
+        $outer_self->timelog("get_records_and_facets(): got highlighting content (". keys(%{$self->ctx->{_hl_data}}).")");
+    }
 
     my $facets = {};
     if ($facet_req) {
@@ -451,67 +515,6 @@ sub get_records_and_facets {
     }
     $search->kill_me;
 
-    my $data = $unapi_req->gather(1);
-
-    $outer_self->timelog("get_records_and_facets(): got feed content");
-
-    if (!$is_meta) {
-        my $hl_data = $hl_req->gather(1); # list of arrayref of hashrefs
-        $self->ctx->{_hl_data} = { map { ''.$$_[0]{source} => $_ } @$hl_data };
-        $outer_self->timelog("get_records_and_facets(): got highlighting content (". keys(%{$self->ctx->{_hl_data}}).")");
-    }
-
-    # Protect against requests for non-existent records
-    return unless $data->{$unapi_type};
-
-    my $doc = XML::LibXML->new->parse_string($data->{$unapi_type})->documentElement;
-
-    $outer_self->timelog("get_records_and_facets(): parsed xml");
-    for my $xml ($doc->getElementsByTagName('record')) {
-        $xml = XML::LibXML->new->parse_string($xml->toString)->documentElement;
-
-        # Protect against legacy invalid MARCXML that might not have a 901c
-        my $bre_id;
-        my $mmr_id;
-        my $bre_id_nodes =  $xml->find('*[@tag="901"]/*[@code="c"]');
-        if ($bre_id_nodes) {
-            $bre_id =  $bre_id_nodes->[0]->textContent;
-        } else {
-            $logger->warn("Missing 901 subfield 'c' in " . $xml->toString());
-        }
-    
-        if ($is_meta) {
-            # extract metarecord ID from mmr.unapi tag
-            for my $node ($xml->getElementsByTagName('abbr')) {
-                my $title = $node->getAttribute('title');
-                ($mmr_id = $title) =~ 
-                    s/tag:open-ils.org:U2\@mmr\/(\d+)\/.*/$1/g;
-                last if $mmr_id;
-            }
-        }
-    
-        my $rec_id = $mmr_id ? $mmr_id : $bre_id;
-        $tmp_data{$rec_id} = {
-            id => $rec_id, 
-            bre_id => $bre_id, 
-            mmr_id => $mmr_id,
-            marc_xml => $xml
-        };
-    
-        if ($rec_id) {
-            # Let other backends grab our data now that we're done.
-            my $key = 'TPAC_unapi_cache_'.$rec_id.'_'.$unapi_cache_key_suffix;
-            my $cache_data = $unapi_cache->get_cache($key);
-            if ($$cache_data{running}) {
-                $unapi_cache->put_cache($key, {
-                    bre_id => $bre_id,
-                    mmr_id => $mmr_id,
-                    id => $rec_id, 
-                    marc_xml => $xml->toString
-                }, 10);
-            }
-        }
-    }
 
     return ($facets, map { $tmp_data{$_} } @$rec_ids);
 }

commit fd45adb4bd298031dff98d31b571394db3a5397a
Author: Mike Rylander <mrylander at gmail.com>
Date:   Tue Feb 20 16:39:54 2018 -0500

    LP#1744385: Fix typo and allow stemmed search and highlighting of Genre
    
    Signed-off-by: Mike Rylander <mrylander at gmail.com>
    Signed-off-by: Kathy Lussier <klussier at masslnc.org>
    Signed-off-by: Dan Wells <dbw2 at calvin.edu>

diff --git a/Open-ILS/src/sql/Pg/300.schema.staged_search.sql b/Open-ILS/src/sql/Pg/300.schema.staged_search.sql
index eee307d..08ca281 100644
--- a/Open-ILS/src/sql/Pg/300.schema.staged_search.sql
+++ b/Open-ILS/src/sql/Pg/300.schema.staged_search.sql
@@ -1320,7 +1320,7 @@ CREATE OR REPLACE VIEW search.best_tsconfig AS
             COALESCE(f.ts_config, c.ts_config, 'simple') AS ts_config
       FROM  config.metabib_field m
             LEFT JOIN config.metabib_class_ts_map c ON (c.field_class = m.field_class AND c.index_weight = 'C')
-            LEFT JOIN config.metabib_field_ts_map f ON (f.metabib_field = m.id AND c.index_weight = 'C');
+            LEFT JOIN config.metabib_field_ts_map f ON (f.metabib_field = m.id AND f.index_weight = 'C');
 
 CREATE TYPE search.highlight_result AS ( id BIGINT, source BIGINT, field INT, value TEXT, highlight TEXT );
 
diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.highlight_search.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.highlight_search.sql
index cc3f913..ed50842 100644
--- a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.highlight_search.sql
+++ b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.highlight_search.sql
@@ -334,7 +334,7 @@ CREATE OR REPLACE VIEW search.best_tsconfig AS
             COALESCE(f.ts_config, c.ts_config, 'simple') AS ts_config
       FROM  config.metabib_field m
             LEFT JOIN config.metabib_class_ts_map c ON (c.field_class = m.field_class AND c.index_weight = 'C')
-            LEFT JOIN config.metabib_field_ts_map f ON (f.metabib_field = m.id AND c.index_weight = 'C');
+            LEFT JOIN config.metabib_field_ts_map f ON (f.metabib_field = m.id AND f.index_weight = 'C');
 
 CREATE TYPE search.highlight_result AS ( id BIGINT, source BIGINT, field INT, value TEXT, highlight TEXT );
 
diff --git a/Open-ILS/src/sql/Pg/upgrade/ZZZZ.data.virtual_index_defs.sql b/Open-ILS/src/sql/Pg/upgrade/ZZZZ.data.virtual_index_defs.sql
index 1618350..fb868f4 100644
--- a/Open-ILS/src/sql/Pg/upgrade/ZZZZ.data.virtual_index_defs.sql
+++ b/Open-ILS/src/sql/Pg/upgrade/ZZZZ.data.virtual_index_defs.sql
@@ -13,6 +13,13 @@ INSERT INTO config.metabib_field_virtual_map (real, virtual)
 
 UPDATE config.metabib_field SET xpath=$$//mods32:mods/mods32:subject[not(descendant::mods32:geographicCode)]$$ WHERE id = 16;
 
+-- Stemming for genre
+INSERT INTO config.metabib_field_ts_map (metabib_field, ts_config)
+    SELECT 33, 'english_nostop' WHERE NOT EXISTS (
+        SELECT 1 FROM config.metabib_field_ts_map WHERE metabib_field = 33 AND ts_config = 'english_nostop'
+    )
+;
+
 COMMIT;
 
 \qecho 

commit 57166723680ed2cbd5cb130d5a0c4d71e2ced7bc
Author: Mike Rylander <mrylander at gmail.com>
Date:   Mon Feb 19 17:50:15 2018 -0500

    LP#1744385: Limit UNIONs and fields therein to those that have different weights for the virtual map
    
    Signed-off-by: Mike Rylander <mrylander at gmail.com>
    Signed-off-by: Kathy Lussier <klussier at masslnc.org>
    Signed-off-by: Dan Wells <dbw2 at calvin.edu>

diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Driver/Pg/QueryParser.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Driver/Pg/QueryParser.pm
index bad7d58..bd223cb 100644
--- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Driver/Pg/QueryParser.pm
+++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Driver/Pg/QueryParser.pm
@@ -261,12 +261,13 @@ sub add_search_field_virtual_map {
     my $self = shift;
     my $realid = shift;
     my $virtid = shift;
+    my $weight = shift;
 
     $self->search_field_virtual_map->{by_virt}{$virtid} ||= [];
-    push @{$self->search_field_virtual_map->{by_virt}{$virtid}}, $realid;
+    push @{$self->search_field_virtual_map->{by_virt}{$virtid}}, { real => $realid, weight => $weight };
 
     $self->search_field_virtual_map->{by_real}{$realid} ||= [];
-    push @{$self->search_field_virtual_map->{by_real}{$realid}}, $virtid;
+    push @{$self->search_field_virtual_map->{by_real}{$realid}}, { virt => $virtid, weight => $weight };
 }
 
 sub search_field_class_by_id {
@@ -427,7 +428,7 @@ sub initialize_search_field_virtual_map {
     my $self = shift;
     my $cmfvm_list = shift;
 
-    __PACKAGE__->add_search_field_virtual_map( $_->real, $_->virtual )
+    __PACKAGE__->add_search_field_virtual_map( $_->real, $_->virtual, $_->weight )
         for (@$cmfvm_list);
 
     $logger->debug('Virtual field map: ' . Dumper($self->search_field_virtual_map));
@@ -635,7 +636,7 @@ sub TEST_SETUP {
     __PACKAGE__->add_relevance_bump( keyword => keyword => first_word => 1 );
     __PACKAGE__->add_relevance_bump( keyword => keyword => full_match => 1 );
     
-    __PACKAGE__->add_search_field_virtual_map( 6 => 15 );
+    __PACKAGE__->add_search_field_virtual_map( 6 => 15 => 5 );
 
     __PACKAGE__->class_ts_config( 'series', undef, 1, 'english_nostop' );
     __PACKAGE__->class_ts_config( 'title', undef, 1, 'english_nostop' );
@@ -1277,19 +1278,23 @@ sub flatten {
 
                             # UNION in the others ... group by class
                             for my $real_field (@$real_fields) {
-                                $node->add_vfield($real_field);
-                                $logger->debug("Looking up virtual field for real field $real_field");
+                                my $natural_field = $self->QueryParser->search_field_id_map->{by_id}{$$real_field{real}};
+
+                                $node->add_vfield($$real_field{real});
+                                $logger->debug("Looking up virtual field for real field $$real_field{real}");
                                 my $vtable = $node->table(
                                     $self->QueryParser
-                                        ->search_field_class_by_id($real_field)
+                                        ->search_field_class_by_id($$real_field{real})
                                         ->{classname}
                                 );
                                 $vtable_field_map{$vtable} ||= [];
-                                push @{$vtable_field_map{$vtable}}, $real_field;
+                                push(@{$vtable_field_map{$vtable}}, $$real_field{real})
+                                    if ($$real_field{weight} != $$natural_field{weight});
                             }
 
                             for my $vtable (keys %vtable_field_map) {
-                                my $real_fields = $vtable_field_map{$vtable};
+                                my $rfields = $vtable_field_map{$vtable};
+                                next unless (@$rfields);
 
                                 # NOTE: only real fields that match the (component) tsquery will
                                 #       get to contribute to and increased rank for the record.
@@ -1299,7 +1304,7 @@ sub flatten {
                                       . ${spc} x 6 . "FROM  $vtable AS fe\n"
                                       . ${spc} x 7 . "JOIN config.metabib_field_virtual_map AS fe_weight ON ("
                                             ."fe_weight.virtual = $possible_vfield AND "
-                                            ."fe_weight.real IN (".join(',',@$real_fields).") AND "
+                                            ."fe_weight.real IN (".join(',',@$rfields).") AND "
                                             ."fe_weight.real = fe.field)\n"
                                       . ${spc} x 7 . "JOIN ${talias}_xq ON (fe.index_vector @@ ${talias}_xq.tsq)"
                                 ;

commit 3817746d6c53f74f74451d53f018e73db6ca6bb6
Author: Mike Rylander <mrylander at gmail.com>
Date:   Mon Feb 19 16:48:33 2018 -0500

    LP#1744385: Parallelize highlight gathering with XML feed retrieval
    
    Signed-off-by: Mike Rylander <mrylander at gmail.com>
    Signed-off-by: Kathy Lussier <klussier at masslnc.org>
    Signed-off-by: Dan Wells <dbw2 at calvin.edu>

diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Search/Biblio.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Search/Biblio.pm
index 96e6a18..ca3f85a 100644
--- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Search/Biblio.pm
+++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Search/Biblio.pm
@@ -1342,7 +1342,8 @@ sub fetch_display_fields {
 }
 __PACKAGE__->register_method(
     method    => 'fetch_display_fields',
-    api_name  => 'open-ils.search.fetch.metabib.display_field.highlight'
+    api_name  => 'open-ils.search.fetch.metabib.display_field.highlight',
+    stream   => 1
 );
 
 
diff --git a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm
index c243d72..e753057 100644
--- a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm
+++ b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm
@@ -346,12 +346,24 @@ sub load_common {
 
     $ctx->{fetch_display_fields} = sub {
         my $id = shift;
-        return $U->simplereq(
+
+        if (@$id == 1) {
+            return $ctx->{_hl_data}{''.$$id[0]}
+                if ($ctx->{_hl_data}{''.$$id[0]});
+        }
+
+        $self->timelog("HL data not cached, fetching from server.");
+
+        my $rows = $U->simplereq(
             'open-ils.search', 
             'open-ils.search.fetch.metabib.display_field.highlight',
             $ctx->{query_struct}{additional_data}{highlight_map},
             map {int($_)} @$id
         );
+
+        $ctx->{_hl_data}{''.$$id[0]} = $rows if (@$id == 1);
+
+        return $rows;
     };
 
     return Apache2::Const::OK;
diff --git a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Util.pm b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Util.pm
index c788761..5505cd6 100644
--- a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Util.pm
+++ b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Util.pm
@@ -374,6 +374,7 @@ sub get_records_and_facets {
     );
 
     my %tmp_data;
+    my %hl_tmp_data;
     my $outer_self = $self;
 
     my $sdepth = $unapi_args->{flesh_depth};
@@ -385,6 +386,7 @@ sub get_records_and_facets {
     $flesh =~ s/}$/,mmr.unapi}/g if $is_meta;
 
     my $ses = OpenSRF::AppSession->create('open-ils.cstore');
+    my $hl_ses = OpenSRF::AppSession->create('open-ils.search');
 
     my @loop_recs;
     for my $bid (@$rec_ids) {
@@ -410,6 +412,13 @@ sub get_records_and_facets {
         ]}
     );
 
+    my $hl_req = $hl_ses->request(
+        'open-ils.search.fetch.metabib.display_field.highlight.atomic',
+        $self->ctx->{query_struct}{additional_data}{highlight_map},
+        @$rec_ids
+    ) if (!$is_meta);
+
+
     my $facets = {};
     if ($facet_req) {
         $self->timelog("get_records_and_facets():almost ready to fetch facets");
@@ -444,7 +453,13 @@ sub get_records_and_facets {
 
     my $data = $unapi_req->gather(1);
 
-    $outer_self->timelog("get_records_and_facets(): got response content");
+    $outer_self->timelog("get_records_and_facets(): got feed content");
+
+    if (!$is_meta) {
+        my $hl_data = $hl_req->gather(1); # list of arrayref of hashrefs
+        $self->ctx->{_hl_data} = { map { ''.$$_[0]{source} => $_ } @$hl_data };
+        $outer_self->timelog("get_records_and_facets(): got highlighting content (". keys(%{$self->ctx->{_hl_data}}).")");
+    }
 
     # Protect against requests for non-existent records
     return unless $data->{$unapi_type};
diff --git a/Open-ILS/src/templates/opac/parts/misc_util.tt2 b/Open-ILS/src/templates/opac/parts/misc_util.tt2
index e8d4895..e4bf98c 100644
--- a/Open-ILS/src/templates/opac/parts/misc_util.tt2
+++ b/Open-ILS/src/templates/opac/parts/misc_util.tt2
@@ -110,9 +110,7 @@
         args.hl = {};
         IF !CGI.param('no_highlight') && !search.no_highlight;
 
-            junk = ctx.timelog('Fetching of highlighted display fields for bib(s) ' _ args.df_bib_list.list.join(', ')); 
             args.display_field_list = ctx.fetch_display_fields(args.df_bib_list.list);
-            junk = ctx.timelog('Finished fetch of highlighted display fields for bib(s) ' _ args.df_bib_list.list.join(', ')); 
 
             junk = ctx.timelog('Mapping highlighted display fields for bib(s) ' _ args.df_bib_list.list.join(', ')); 
             FOR df IN args.display_field_list;

commit 194cc82b3192c5af15ec2dd51db9ae7e9560382e
Author: Mike Rylander <mrylander at gmail.com>
Date:   Mon Feb 19 16:46:59 2018 -0500

    LP#1744385: Add highlighting for ISBN and ISSN
    
    Signed-off-by: Mike Rylander <mrylander at gmail.com>
    Signed-off-by: Kathy Lussier <klussier at masslnc.org>
    Signed-off-by: Dan Wells <dbw2 at calvin.edu>

diff --git a/Open-ILS/src/templates/opac/parts/record/summary.tt2 b/Open-ILS/src/templates/opac/parts/record/summary.tt2
index 374182f..84b4b74 100644
--- a/Open-ILS/src/templates/opac/parts/record/summary.tt2
+++ b/Open-ILS/src/templates/opac/parts/record/summary.tt2
@@ -312,7 +312,11 @@ END;
 
 <h2 id='rdetail_record_details'>[% l("Record details") %]</h2>
 <ul>
-    [%- IF attrs.isbns.0;
+    [%- IF attrs.hl.isbn.size; FOR isbn IN attrs.hl.isbn %]
+    <li class='rdetail_isbns'>
+        <strong class='rdetail_label'>[% l('ISBN:'); %]</strong> [% isbn %]
+    </li>
+    [%- END; ELSIF attrs.isbns.0;
           FOR isbn IN attrs.isbns;
             isbn_extra = '';
             IF (matches = isbn.match('^(.+?)(\s.+)$'));
@@ -326,7 +330,11 @@ END;
     </li>
         [%- END %]
     [%- END %]
-    [%- IF attrs.issns.0; FOR issn IN attrs.issns %]
+    [%- IF attrs.hl.issn.size; FOR issn IN attrs.hl.issn %]
+    <li class='rdetail_issns'>
+        <strong class='rdetail_label'>[% l('ISSN:'); %]</strong> [% issn %]
+    </li>
+    [%- END; ELSIF attrs.issns.0; FOR issn IN attrs.issns %]
     <li class='rdetail_issns'>
         <strong class='rdetail_label'>[% l('ISSN:'); %]</strong>
         <span class='rdetail_value'>[% issn | html  %]</span>

commit 0df4f2951febd2db9c3eb3450690cf3a273c5a6d
Author: Mike Rylander <mrylander at gmail.com>
Date:   Fri Feb 16 12:35:41 2018 -0500

    LP#1744385: Speed up highlighting
    
    This commit removes a layer of opensrf-perl indirection and uses cstore
    instead of storage for retrieval.  This trims seconds off the render time
    of results and a bit off record detail.
    
    Signed-off-by: Mike Rylander <mrylander at gmail.com>
    Signed-off-by: Kathy Lussier <klussier at masslnc.org>
    Signed-off-by: Dan Wells <dbw2 at calvin.edu>

diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Search/Biblio.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Search/Biblio.pm
index 96ce5da..96e6a18 100644
--- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Search/Biblio.pm
+++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Search/Biblio.pm
@@ -1306,26 +1306,42 @@ sub staged_search {
     return cache_facets($facet_key, $new_ids, $IAmMetabib, $ignore_facet_classes) if $docache;
 }
 
-sub passthrough_fetch_display_fields {
+sub fetch_display_fields {
     my $self = shift;
     my $conn = shift;
     my $highlight_map = shift;
     my @records = @_;
 
-    return $U->storagereq(
-        'open-ils.storage.fetch.metabib.display_field.highlight',
-        $highlight_map,
-        @records
-    ) if (@records == 1);
+    unless (@records) {
+        $conn->respond_complete;
+        return;
+    }
 
-    return $U->storagereq(
-        'open-ils.storage.fetch.metabib.display_field.highlight.atomic',
-        $highlight_map,
-        \@records
-    );
+    my $hl_map_string = "''::HSTORE";
+    if (ref($highlight_map) =~ /HASH/) {
+        $hl_map_string = "";
+        for my $tsq (keys %$highlight_map) {
+            my $field_list = join(',', @{$$highlight_map{$tsq}});
+            $hl_map_string .= ' || ' if $hl_map_string;
+            $hl_map_string .= "hstore(($tsq)\:\:TEXT,'$field_list')";
+        }
+    }
+
+    my $e = new_editor();
+
+    for my $record ( @records ) {
+        next unless $record;
+        $conn->respond(
+            $e->json_query(
+                {from => ['search.highlight_display_fields', $record, $hl_map_string]}
+            )
+        );
+    }
+
+    return undef;
 }
 __PACKAGE__->register_method(
-    method    => 'passthrough_fetch_display_fields',
+    method    => 'fetch_display_fields',
     api_name  => 'open-ils.search.fetch.metabib.display_field.highlight'
 );
 
diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Publisher/metabib.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Publisher/metabib.pm
index eb3f423..506846a 100644
--- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Publisher/metabib.pm
+++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Publisher/metabib.pm
@@ -92,49 +92,6 @@ sub _initialize_parser {
     die("Cannot initialize $parser!") unless ($parser->initialization_complete);
 }
 
-sub fetch_highlighted_display_fields {
-    my $self = shift;
-    my $client = shift;
-    my $records = shift;
-    my $highlight_map = shift;
-
-    unless ($records) {
-        $client->respond_complete;
-        return;
-    }
-
-    my $hl_map_string = "''::HSTORE";
-    if (ref($highlight_map)) {
-        $hl_map_string = "";
-        for my $tsq (keys %$highlight_map) {
-            my $field_list = join(',', @{$$highlight_map{$tsq}});
-            $hl_map_string .= ' || ' if $hl_map_string;
-            $hl_map_string .= "hstore(($tsq)\:\:TEXT,'$field_list')";
-        }
-    }
-
-    my $sth = metabib::metarecord_source_map->db_Main->prepare(
-        "SELECT * FROM search.highlight_display_fields(?, $hl_map_string)"
-    );
-
-    $records = [$records] unless ref($records);
-    for my $record ( @$records ) {
-        next unless $record;
-        $sth->execute($record);
-        my $rows = $sth->fetchall_arrayref({});
-        $client->respond($rows);
-    }
-
-    return undef;
-}
-__PACKAGE__->register_method(
-    api_name    => 'open-ils.storage.fetch.metabib.display_field.highlight',
-    method      => 'fetch_highlighted_display_fields',
-    api_level   => 1,
-    stream      => 1
-);
-
-
 sub ordered_records_from_metarecord { # XXX Replace with QP-based search-within-MR
     my $self = shift;
     my $client = shift;
diff --git a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm
index e386d43..c243d72 100644
--- a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm
+++ b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm
@@ -39,7 +39,7 @@ use constant COOKIE_ANON_CACHE => 'anoncache';
 use constant ANON_CACHE_MYLIST => 'mylist';
 use constant ANON_CACHE_STAFF_SEARCH => 'staffsearch';
 
-use constant DEBUG_TIMING => 0;
+use constant DEBUG_TIMING => 1;
 
 sub new {
     my($class, $apache, $ctx) = @_;
@@ -51,6 +51,9 @@ sub new {
     $self->cgi(new CGI);
     $self->timelog("New page");
 
+    # Add a timelog helper to the context
+    $self->ctx->{timelog} = sub { return $self->timelog(@_) };
+
     OpenILS::Utils::CStoreEditor->init; # just in case
     $self->editor(new_editor());
 
@@ -346,8 +349,8 @@ sub load_common {
         return $U->simplereq(
             'open-ils.search', 
             'open-ils.search.fetch.metabib.display_field.highlight',
-            $id,
-            $ctx->{query_struct}{additional_data}{highlight_map}
+            $ctx->{query_struct}{additional_data}{highlight_map},
+            map {int($_)} @$id
         );
     };
 
diff --git a/Open-ILS/src/sql/Pg/300.schema.staged_search.sql b/Open-ILS/src/sql/Pg/300.schema.staged_search.sql
index 71a2e7d..eee307d 100644
--- a/Open-ILS/src/sql/Pg/300.schema.staged_search.sql
+++ b/Open-ILS/src/sql/Pg/300.schema.staged_search.sql
@@ -1324,7 +1324,7 @@ CREATE OR REPLACE VIEW search.best_tsconfig AS
 
 CREATE TYPE search.highlight_result AS ( id BIGINT, source BIGINT, field INT, value TEXT, highlight TEXT );
 
-CREATE OR REPLACE FUNCTION search.highlight_display_fields(
+CREATE OR REPLACE FUNCTION search.highlight_display_fields_impl(
     rid         BIGINT,
     tsq         TEXT,
     field_list  INT[] DEFAULT '{}'::INT[],
@@ -1410,7 +1410,7 @@ $$ LANGUAGE SQL IMMUTABLE LEAKPROOF STRICT COST 10;
 
 CREATE OR REPLACE FUNCTION search.highlight_display_fields(
     rid         BIGINT,
-    tsq_map     HSTORE, -- { '(a | b) & c' => '1,2,3,4', ...}
+    tsq_map     TEXT, -- { '(a | b) & c' => '1,2,3,4', ...}
     css_class   TEXT DEFAULT 'oils_SH',
     hl_all      BOOL DEFAULT TRUE,
     minwords    INT DEFAULT 5,
@@ -1420,18 +1420,25 @@ CREATE OR REPLACE FUNCTION search.highlight_display_fields(
     delimiter   TEXT DEFAULT ' ... '
 ) RETURNS SETOF search.highlight_result AS $f$
 DECLARE
-    tsq     TEXT;
-    fields  TEXT;
-    afields INT[];
-    seen    INT[];
+    tsq_hstore  TEXT;
+    tsq         TEXT;
+    fields      TEXT;
+    afields     INT[];
+    seen        INT[];
 BEGIN
-    FOR tsq, fields IN SELECT key, value FROM each(tsq_map) LOOP
+    IF (tsq_map ILIKE 'hstore%') THEN
+        EXECUTE 'SELECT ' || tsq_map INTO tsq_hstore;
+    ELSE
+        tsq_hstore := tsq_map::HSTORE;
+    END IF;
+
+    FOR tsq, fields IN SELECT key, value FROM each(tsq_hstore) LOOP
         SELECT  ARRAY_AGG(unnest::INT) INTO afields
           FROM  unnest(regexp_split_to_array(fields,','));
         seen := seen || afields;
 
         RETURN QUERY
-            SELECT * FROM search.highlight_display_fields(
+            SELECT * FROM search.highlight_display_fields_impl(
                 rid, tsq, afields, css_class, hl_all,minwords,
                 maxwords, shortwords, maxfrags, delimiter
             );
diff --git a/Open-ILS/src/sql/Pg/950.data.seed-values.sql b/Open-ILS/src/sql/Pg/950.data.seed-values.sql
index a66a12d..a8ef6e2 100644
--- a/Open-ILS/src/sql/Pg/950.data.seed-values.sql
+++ b/Open-ILS/src/sql/Pg/950.data.seed-values.sql
@@ -364,7 +364,7 @@ INSERT INTO config.display_field_map (name, field, multi) VALUES
     ('creators', 37, TRUE),
     ('subject', 16, TRUE),
     ('isbn', 18, TRUE),
-    ('series_title',         1, FALSE),
+    ('series_title',         1, TRUE),
     ('subject_geographic',  11, TRUE),
     ('subject_name',        12, TRUE),
     ('subject_temporal',    13, TRUE),
diff --git a/Open-ILS/src/sql/Pg/upgrade/WWWW.data.display-field-seed-data.sql b/Open-ILS/src/sql/Pg/upgrade/WWWW.data.display-field-seed-data.sql
index fae9b21..e87c170 100644
--- a/Open-ILS/src/sql/Pg/upgrade/WWWW.data.display-field-seed-data.sql
+++ b/Open-ILS/src/sql/Pg/upgrade/WWWW.data.display-field-seed-data.sql
@@ -136,7 +136,7 @@ UPDATE config.metabib_field SET display_field = TRUE WHERE id IN (
 -- Map display field names to config.metabib_field entries
 
 INSERT INTO config.display_field_map (name, field, multi) VALUES 
-    ('series_title',         1, FALSE),
+    ('series_title',         1, TRUE),
     ('subject_geographic',  11, TRUE),
     ('subject_name',        12, TRUE),
     ('subject_temporal',    13, TRUE),
diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.highlight_search.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.highlight_search.sql
index 7a4e551..cc3f913 100644
--- a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.highlight_search.sql
+++ b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.highlight_search.sql
@@ -338,7 +338,7 @@ CREATE OR REPLACE VIEW search.best_tsconfig AS
 
 CREATE TYPE search.highlight_result AS ( id BIGINT, source BIGINT, field INT, value TEXT, highlight TEXT );
 
-CREATE OR REPLACE FUNCTION search.highlight_display_fields(
+CREATE OR REPLACE FUNCTION search.highlight_display_fields_impl(
     rid         BIGINT,
     tsq         TEXT,
     field_list  INT[] DEFAULT '{}'::INT[],
@@ -424,7 +424,7 @@ $$ LANGUAGE SQL IMMUTABLE LEAKPROOF STRICT COST 10;
 
 CREATE OR REPLACE FUNCTION search.highlight_display_fields(
     rid         BIGINT,
-    tsq_map     HSTORE, -- { '(a | b) & c' => '1,2,3,4', ...}
+    tsq_map     TEXT, -- { '(a | b) & c' => '1,2,3,4', ...}
     css_class   TEXT DEFAULT 'oils_SH',
     hl_all      BOOL DEFAULT TRUE,
     minwords    INT DEFAULT 5,
@@ -434,18 +434,26 @@ CREATE OR REPLACE FUNCTION search.highlight_display_fields(
     delimiter   TEXT DEFAULT ' ... '
 ) RETURNS SETOF search.highlight_result AS $f$
 DECLARE
-    tsq     TEXT;
-    fields  TEXT;
-    afields INT[];
-    seen    INT[];
+    tsq_hstore  HSTORE;
+    tsq         TEXT;
+    fields      TEXT;
+    afields     INT[];
+    seen        INT[];
 BEGIN
-    FOR tsq, fields IN SELECT key, value FROM each(tsq_map) LOOP
+
+    IF (tsq_map ILIKE 'hstore%') THEN
+        EXECUTE 'SELECT ' || tsq_map INTO tsq_hstore;
+    ELSE
+        tsq_hstore := tsq_map::HSTORE;
+    END IF;
+    
+    FOR tsq, fields IN SELECT key, value FROM each(tsq_hstore) LOOP
         SELECT  ARRAY_AGG(unnest::INT) INTO afields
           FROM  unnest(regexp_split_to_array(fields,','));
         seen := seen || afields;
 
         RETURN QUERY
-            SELECT * FROM search.highlight_display_fields(
+            SELECT * FROM search.highlight_display_fields_impl(
                 rid, tsq, afields, css_class, hl_all,minwords,
                 maxwords, shortwords, maxfrags, delimiter
             );
diff --git a/Open-ILS/src/templates/opac/parts/misc_util.tt2 b/Open-ILS/src/templates/opac/parts/misc_util.tt2
index ba507bd..e8d4895 100644
--- a/Open-ILS/src/templates/opac/parts/misc_util.tt2
+++ b/Open-ILS/src/templates/opac/parts/misc_util.tt2
@@ -109,8 +109,12 @@
         args.display_fields = {};
         args.hl = {};
         IF !CGI.param('no_highlight') && !search.no_highlight;
+
+            junk = ctx.timelog('Fetching of highlighted display fields for bib(s) ' _ args.df_bib_list.list.join(', ')); 
             args.display_field_list = ctx.fetch_display_fields(args.df_bib_list.list);
+            junk = ctx.timelog('Finished fetch of highlighted display fields for bib(s) ' _ args.df_bib_list.list.join(', ')); 
 
+            junk = ctx.timelog('Mapping highlighted display fields for bib(s) ' _ args.df_bib_list.list.join(', ')); 
             FOR df IN args.display_field_list;
                 df_map = ctx.search_cdfm('field', df.field).0;
                 df_name = df_map.name();
@@ -126,6 +130,7 @@
                     args.hl.$df_name = df.highlight || df.value;
                 END;
             END;
+            junk = ctx.timelog('Finished mapping highlighted display fields for bib(s) ' _ args.df_bib_list.list.join(', ')); 
         END;
 
         # Map item types to schema.org types; impedance mismatch :(

commit 7edd82750b408c8f1eb5ebcb66a2de16d71cd46e
Author: Mike Rylander <mrylander at gmail.com>
Date:   Fri Feb 16 12:27:24 2018 -0500

    LP#1744385: Use series_title highlighting in OPAC
    
    Here we replace the series title link generation based directly on the MARCXML
    with the Display Field equivalent.  Note, the previous method created broken
    links in many cases, because it included more in the search terms than were
    being indexed by the stock series title definition.
    
    Signed-off-by: Mike Rylander <mrylander at gmail.com>
    
    Starting #	../../../../multi-source-attrs.sql
    
    Signed-off-by: Kathy Lussier <klussier at masslnc.org>
    Signed-off-by: Dan Wells <dbw2 at calvin.edu>

diff --git a/Open-ILS/src/templates/opac/parts/record/series.tt2 b/Open-ILS/src/templates/opac/parts/record/series.tt2
index 4be6b83..4c42baf 100644
--- a/Open-ILS/src/templates/opac/parts/record/series.tt2
+++ b/Open-ILS/src/templates/opac/parts/record/series.tt2
@@ -4,37 +4,49 @@
 
 BLOCK render_series;
     results = [];
-    FOR tag IN series_tags;
-        FOR node IN ctx.marc_xml.findnodes('//*[@tag="' _ tag _ '"]');
-            all_terms = [];
-            graphics = [];
-            series = '';
-            FOR subfield IN node.childNodes;
-                NEXT UNLESS subfield.nodeName == "subfield";
-                code = subfield.getAttribute('code');
-                IF code == '6';
-                   linked_fields = [subfield.textContent()];
-                   target_field = node.getAttribute('tag');
-                   get_linked_880s;
-                END;
-                NEXT UNLESS code.match('[a-z]');
-                # at this point, we actually have a partial term to use.
-                single_term = subfield.textContent | html;
-                all_terms.push(subfield.textContent.replace('[#"^$\+\-,\.:;&|\[\]()]', ' '));
-                total_term = all_terms.join(" ").replace('\s+$', '');
-
-                url = mkurl(ctx.opac_root _ '/results',
-                    { qtype=>'series', query=>total_term }, stop_parms.merge(expert_search_parms, general_search_parms, browse_search_parms, facet_search_parms)
-                );
-                series = series _ '<a href="' _ url _ '">' _ single_term _ '</a> ';
-            END;
-            FOREACH link880 IN graphics;
-                link = link880.value | html;
-                series = series _ '<div class="graphic880"' _ link880.dir _ '>' _ link _ '</div>';
-            END;
+    IF attrs.hl_display_fields.series_title.size;
+        FOREACH s IN attrs.hl_display_fields.series_title;
+            search_term = s.value.replace('[#"^$\+\-,\.:;&|\[\]()]', ' ').replace('\s+$', '') | html;
+    
+            url = mkurl(ctx.opac_root _ '/results',
+                { qtype=>'series', query=>search_term }, stop_parms.merge(expert_search_parms, general_search_parms, browse_search_parms, facet_search_parms)
+            );
+            series = '<a href="' _ url _ '">' _ s.highlight _ '</a> ';
             results.push(series);
         END;
-    END; 
+    ELSE;
+        FOR tag IN series_tags;
+            FOR node IN ctx.marc_xml.findnodes('//*[@tag="' _ tag _ '"]');
+                all_terms = [];
+                graphics = [];
+                series = '';
+                FOR subfield IN node.childNodes;
+                    NEXT UNLESS subfield.nodeName == "subfield";
+                    code = subfield.getAttribute('code');
+                    IF code == '6';
+                       linked_fields = [subfield.textContent()];
+                       target_field = node.getAttribute('tag');
+                       get_linked_880s;
+                    END;
+                    NEXT UNLESS code.match('[a-z]');
+                    # at this point, we actually have a partial term to use.
+                    single_term = subfield.textContent | html;
+                    all_terms.push(subfield.textContent.replace('[#"^$\+\-,\.:;&|\[\]()]', ' '));
+                    total_term = all_terms.join(" ").replace('\s+$', '');
+    
+                    url = mkurl(ctx.opac_root _ '/results',
+                        { qtype=>'series', query=>total_term }, stop_parms.merge(expert_search_parms, general_search_parms, browse_search_parms, facet_search_parms)
+                    );
+                    series = series _ '<a href="' _ url _ '">' _ single_term _ '</a> ';
+                END;
+                FOREACH link880 IN graphics;
+                    link = link880.value | html;
+                    series = series _ '<div class="graphic880"' _ link880.dir _ '>' _ link _ '</div>';
+                END;
+                results.push(series);
+            END;
+        END; 
+    END;
     FOR entry IN results;
     -%]
     <li class='rdetail_series_value'>[% entry %]</li>

commit a985c99897d9f2d53609be17c5abef67234a3635
Author: Mike Rylander <mrylander at gmail.com>
Date:   Wed Feb 14 12:52:21 2018 -0500

    LP#1744385: Optimize real-field additions to virtual field searches
    
    Now we only add on UNION query for each class providing real fields to a
    virtual field, rather than a UNION per real field.  This should reduce
    core-query run time.
    
    Signed-off-by: Mike Rylander <mrylander at gmail.com>
    Signed-off-by: Kathy Lussier <klussier at masslnc.org>
    Signed-off-by: Dan Wells <dbw2 at calvin.edu>

diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Driver/Pg/QueryParser.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Driver/Pg/QueryParser.pm
index 9774fd0..bad7d58 100644
--- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Driver/Pg/QueryParser.pm
+++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Driver/Pg/QueryParser.pm
@@ -1273,7 +1273,9 @@ sub flatten {
                     for my $possible_vfield (@$search_field_list) {
                         my $real_fields = $self->QueryParser->search_field_virtual_map->{by_virt}->{$possible_vfield};
                         if ($real_fields and @$real_fields) { # this is a virt field
-                            # UNION in the others ... group by class?
+                            my %vtable_field_map;
+
+                            # UNION in the others ... group by class
                             for my $real_field (@$real_fields) {
                                 $node->add_vfield($real_field);
                                 $logger->debug("Looking up virtual field for real field $real_field");
@@ -1282,6 +1284,12 @@ sub flatten {
                                         ->search_field_class_by_id($real_field)
                                         ->{classname}
                                 );
+                                $vtable_field_map{$vtable} ||= [];
+                                push @{$vtable_field_map{$vtable}}, $real_field;
+                            }
+
+                            for my $vtable (keys %vtable_field_map) {
+                                my $real_fields = $vtable_field_map{$vtable};
 
                                 # NOTE: only real fields that match the (component) tsquery will
                                 #       get to contribute to and increased rank for the record.
@@ -1291,7 +1299,7 @@ sub flatten {
                                       . ${spc} x 6 . "FROM  $vtable AS fe\n"
                                       . ${spc} x 7 . "JOIN config.metabib_field_virtual_map AS fe_weight ON ("
                                             ."fe_weight.virtual = $possible_vfield AND "
-                                            ."fe_weight.real = $real_field AND "
+                                            ."fe_weight.real IN (".join(',',@$real_fields).") AND "
                                             ."fe_weight.real = fe.field)\n"
                                       . ${spc} x 7 . "JOIN ${talias}_xq ON (fe.index_vector @@ ${talias}_xq.tsq)"
                                 ;

commit 78fd5304ed7bc7c04c1fec24e6c5cd26b503d73f
Author: Mike Rylander <mrylander at gmail.com>
Date:   Wed Feb 14 12:25:25 2018 -0500

    LP#1744385: Adjust virtual-combined-class real-field search
    
    Instead of searching by combined field within the rank-addition real fields,
    we'll just search on the fields itself.  This preserves the ranking additions
    provided by the real-virtual mapping.
    
    Signed-off-by: Mike Rylander <mrylander at gmail.com>
    Signed-off-by: Kathy Lussier <klussier at masslnc.org>
    Signed-off-by: Dan Wells <dbw2 at calvin.edu>

diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Driver/Pg/QueryParser.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Driver/Pg/QueryParser.pm
index a763f4d..9774fd0 100644
--- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Driver/Pg/QueryParser.pm
+++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Driver/Pg/QueryParser.pm
@@ -1277,29 +1277,24 @@ sub flatten {
                             for my $real_field (@$real_fields) {
                                 $node->add_vfield($real_field);
                                 $logger->debug("Looking up virtual field for real field $real_field");
-                                my $vclass = $self->QueryParser->search_field_class_by_id($real_field)->{classname};
-                                my $vtable = $node->table($vclass);
-                                my $vfield = 'field';
-                                my $vrecord = 'source';
-                                $from .= "\n" . ${spc} x 8 . "UNION ALL\n";
-
-                                if ($node->combined_search) { # real fields inherit combine'dness from the virtual field
-                                    $vtable = $node->combined_table($vclass);
-                                    $vfield = 'metabib_field';
-                                    $vrecord = 'record';
-                                    $from .= ${spc} x 5 . "SELECT 0::BIGINT AS id, fe.record AS source, fe.metabib_field AS field, "
-                                          . "'' AS value, fe.index_vector, fe_weight.weight, ${talias}_xq.tsq, ${talias}_xq.tsq_rank /* virtual field addition */\n";
-                                } else {
-                                    $from .= ${spc} x 5 . "SELECT fe.id, fe.source, fe.field, fe.value, fe.index_vector, "
-                                          . "fe_weight.weight, ${talias}_xq.tsq, ${talias}_xq.tsq_rank /* virtual field addition */\n";
-                                }
-                                
-                                $from .= ${spc} x 6 . "FROM  $vtable AS fe\n"
+                                my $vtable = $node->table(
+                                    $self->QueryParser
+                                        ->search_field_class_by_id($real_field)
+                                        ->{classname}
+                                );
+
+                                # NOTE: only real fields that match the (component) tsquery will
+                                #       get to contribute to and increased rank for the record.
+                                $from .= "\n" . ${spc} x 8 . "UNION ALL\n"
+                                      . ${spc} x 5 . "SELECT fe.id, fe.source, fe.field, fe.value, fe.index_vector, "
+                                      . "fe_weight.weight, ${talias}_xq.tsq, ${talias}_xq.tsq_rank /* virtual field addition */\n"
+                                      . ${spc} x 6 . "FROM  $vtable AS fe\n"
                                       . ${spc} x 7 . "JOIN config.metabib_field_virtual_map AS fe_weight ON ("
                                             ."fe_weight.virtual = $possible_vfield AND "
                                             ."fe_weight.real = $real_field AND "
-                                            ."fe_weight.real = fe.$vfield)\n"
-                                      . ${spc} x 7 . "JOIN ${talias}_xq ON (fe.index_vector @@ ${talias}_xq.tsq)";
+                                            ."fe_weight.real = fe.field)\n"
+                                      . ${spc} x 7 . "JOIN ${talias}_xq ON (fe.index_vector @@ ${talias}_xq.tsq)"
+                                ;
                             }
                         }
                     }

commit 5f1247385514bda1ce2b9bce06612b311bd71f11
Author: Mike Rylander <mrylander at gmail.com>
Date:   Fri Feb 9 15:19:31 2018 -0500

    LP#1744385: Various improvements based on testing
    
     * Improve author and publisher display fields
     * Reimplement Simple Record Extracts using Display Fields
     * Address potential failure in combined search collection
     * Provide useful helper function for inspecting transformed records
     * Implement MODS transforms specified by LoC documentation but not
       actually included in the stylesheet
     * Expand highlighting use to publisher, edition, and physical description
     * Reifying schema from updates
    
    Signed-off-by: Mike Rylander <mrylander at gmail.com>
    Signed-off-by: Kathy Lussier <klussier at masslnc.org>
    Signed-off-by: Dan Wells <dbw2 at calvin.edu>

diff --git a/Open-ILS/src/sql/Pg/030.schema.metabib.sql b/Open-ILS/src/sql/Pg/030.schema.metabib.sql
index 2f37b55..bc72c89 100644
--- a/Open-ILS/src/sql/Pg/030.schema.metabib.sql
+++ b/Open-ILS/src/sql/Pg/030.schema.metabib.sql
@@ -245,25 +245,25 @@ CREATE VIEW metabib.wide_display_entry AS
    This VIEW expands as well-known display fields are added. */
     SELECT
         bre.id AS source,
-        COALESCE(mcde_title.value, 'null') AS title,
-        COALESCE(mcde_author.value, 'null') AS author,
-        COALESCE(mcde_subject_geographic.value, 'null') AS subject_geographic,
-        COALESCE(mcde_subject_name.value, 'null') AS subject_name,
-        COALESCE(mcde_subject_temporal.value, 'null') AS subject_temporal,
-        COALESCE(mcde_subject_topic.value, 'null') AS subject_topic,
-        COALESCE(mcde_creators.value, 'null') AS creators,
-        COALESCE(mcde_isbn.value, 'null') AS isbn,
-        COALESCE(mcde_issn.value, 'null') AS issn,
-        COALESCE(mcde_upc.value, 'null') AS upc,
-        COALESCE(mcde_tcn.value, 'null') AS tcn,
-        COALESCE(mcde_edition.value, 'null') AS edition,
-        COALESCE(mcde_physical_description.value, 'null') AS physical_description,
-        COALESCE(mcde_publisher.value, 'null') AS publisher,
-        COALESCE(mcde_series_title.value, 'null') AS series_title,
-        COALESCE(mcde_abstract.value, 'null') AS abstract,
-        COALESCE(mcde_toc.value, 'null') AS toc,
-        COALESCE(mcde_pubdate.value, 'null') AS pubdate,
-        COALESCE(mcde_type_of_resource.value, 'null') AS type_of_resource
+        COALESCE(mcde_title.value, 'null')::TEXT AS title,
+        COALESCE(mcde_author.value, 'null')::TEXT AS author,
+        COALESCE(mcde_subject_geographic.value, 'null')::TEXT AS subject_geographic,
+        COALESCE(mcde_subject_name.value, 'null')::TEXT AS subject_name,
+        COALESCE(mcde_subject_temporal.value, 'null')::TEXT AS subject_temporal,
+        COALESCE(mcde_subject_topic.value, 'null')::TEXT AS subject_topic,
+        COALESCE(mcde_creators.value, 'null')::TEXT AS creators,
+        COALESCE(mcde_isbn.value, 'null')::TEXT AS isbn,
+        COALESCE(mcde_issn.value, 'null')::TEXT AS issn,
+        COALESCE(mcde_upc.value, 'null')::TEXT AS upc,
+        COALESCE(mcde_tcn.value, 'null')::TEXT AS tcn,
+        COALESCE(mcde_edition.value, 'null')::TEXT AS edition,
+        COALESCE(mcde_physical_description.value, 'null')::TEXT AS physical_description,
+        COALESCE(mcde_publisher.value, 'null')::TEXT AS publisher,
+        COALESCE(mcde_series_title.value, 'null')::TEXT AS series_title,
+        COALESCE(mcde_abstract.value, 'null')::TEXT AS abstract,
+        COALESCE(mcde_toc.value, 'null')::TEXT AS toc,
+        COALESCE(mcde_pubdate.value, 'null')::TEXT AS pubdate,
+        COALESCE(mcde_type_of_resource.value, 'null')::TEXT AS type_of_resource
     FROM biblio.record_entry bre
     LEFT JOIN metabib.compressed_display_entry mcde_title
         ON (bre.id = mcde_title.source AND mcde_title.name = 'title')
@@ -1027,6 +1027,8 @@ BEGIN
                   WHERE record = $1
                         AND metabib_field = $2
             $$ USING bib_id, vfield, rdata;
+        WHEN OTHERS THEN
+            -- ignore and move on
         END;
     END LOOP;
 END;
diff --git a/Open-ILS/src/sql/Pg/950.data.seed-values.sql b/Open-ILS/src/sql/Pg/950.data.seed-values.sql
index 94ea030..a66a12d 100644
--- a/Open-ILS/src/sql/Pg/950.data.seed-values.sql
+++ b/Open-ILS/src/sql/Pg/950.data.seed-values.sql
@@ -307,6 +307,26 @@ VALUES (
 )
 ;
 
+INSERT INTO config.metabib_field (id, field_class, name, format,
+    label, xpath, display_xpath, display_field, search_field, browse_field)
+VALUES (
+    51, 'author', 'first_author', 'mods32',
+    oils_i18n_gettext(51, 'Author', 'cmf', 'label'),
+    $$//mods32:mods/mods32:name[mods32:role/mods32:roleTerm[text()='creator']][1]$$,
+    $$//*[local-name()='namePart']$$,
+    TRUE, TRUE, FALSE
+);
+
+INSERT INTO config.metabib_field (id, field_class, name, format,
+    label, xpath, display_xpath, display_field, search_field, browse_field)
+VALUES (
+    52, 'keyword', 'origin_info', 'marcxml',
+    oils_i18n_gettext(52, 'Origin Info', 'cmf', 'label'),
+    $$//*[@tag='260']$$,
+    $$//*[local-name()='subfield' and contains('abc', at code)]$$,
+    TRUE, TRUE, FALSE
+);
+
 INSERT INTO config.metabib_field_virtual_map (real, virtual)
     SELECT  id,
             45
@@ -340,7 +360,7 @@ SELECT SETVAL('config.metabib_field_id_seq', GREATEST(1000, (SELECT MAX(id) FROM
 
 INSERT INTO config.display_field_map (name, field, multi) VALUES
     ('title', 6, FALSE),
-    ('author', 8, FALSE),
+    ('author', 51, FALSE),
     ('creators', 37, TRUE),
     ('subject', 16, TRUE),
     ('isbn', 18, TRUE),
@@ -354,7 +374,7 @@ INSERT INTO config.display_field_map (name, field, multi) VALUES
     ('tcn',                 26, FALSE),
     ('edition',             38, FALSE),
     ('physical_description',39, TRUE),
-    ('publisher',           40, FALSE),
+    ('publisher',           52, FALSE),
     ('abstract',            41, FALSE),
     ('toc',                 42, FALSE),
     ('type_of_resource',    43, FALSE),
diff --git a/Open-ILS/src/sql/Pg/999.functions.global.sql b/Open-ILS/src/sql/Pg/999.functions.global.sql
index dd36aa9..44157c1 100644
--- a/Open-ILS/src/sql/Pg/999.functions.global.sql
+++ b/Open-ILS/src/sql/Pg/999.functions.global.sql
@@ -2178,4 +2178,8 @@ BEGIN
 END;
 $$ LANGUAGE PLPGSQL;
 
+-- Handy function for transforming marc to a variant available on config.xml_transform
+CREATE OR REPLACE FUNCTION evergreen.marc_to (marc text, xfrm text) RETURNS TEXT AS $$
+    SELECT evergreen.xml_pretty_print(xslt_process($1,xslt)::XML)::TEXT FROM config.xml_transform WHERE name = $2;
+$$ LANGUAGE SQL;
 
diff --git a/Open-ILS/src/sql/Pg/reporter-schema.sql b/Open-ILS/src/sql/Pg/reporter-schema.sql
index 28d9d44..ce302a6 100644
--- a/Open-ILS/src/sql/Pg/reporter-schema.sql
+++ b/Open-ILS/src/sql/Pg/reporter-schema.sql
@@ -154,37 +154,20 @@ SELECT  r.id,
     r.quality,
     r.tcn_source,
     r.tcn_value,
-    CONCAT_WS(' ', FIRST(title.value),FIRST(title_np.val)) AS title,
-    FIRST(author.value) AS author,
-    STRING_AGG(DISTINCT publisher.value, ', ') AS publisher,
-    STRING_AGG(DISTINCT SUBSTRING(pubdate.value FROM $$\d+$$), ', ') AS pubdate,
-    CASE WHEN ARRAY_AGG( DISTINCT REPLACE(SUBSTRING(isbn.value FROM $$^\S+$$), '-', '') ) = '{NULL}'
+    evergreen.oils_json_to_text(d.title) AS title,
+    evergreen.oils_json_to_text(d.author) AS author,
+    evergreen.oils_json_to_text(d.publisher) AS publisher,
+    evergreen.oils_json_to_text(d.pubdate) AS pubdate,
+    CASE WHEN d.isbn = 'null'
         THEN NULL
-        ELSE ARRAY_AGG( DISTINCT REPLACE(SUBSTRING(isbn.value FROM $$^\S+$$), '-', '') )
+        ELSE (SELECT ARRAY(SELECT json_array_elements_text(d.isbn::JSON)))
     END AS isbn,
-    CASE WHEN ARRAY_AGG( DISTINCT REGEXP_REPLACE(issn.value, E'^\\S*(\\d{4})[-\\s](\\d{3,4}x?)', E'\\1 \\2') ) = '{NULL}'
+    CASE WHEN d.issn = 'null'
         THEN NULL
-        ELSE ARRAY_AGG( DISTINCT REGEXP_REPLACE(issn.value, E'^\\S*(\\d{4})[-\\s](\\d{3,4}x?)', E'\\1 \\2') )
+        ELSE (SELECT ARRAY(SELECT json_array_elements_text(d.issn::JSON)))
     END AS issn
   FROM  biblio.record_entry r
-    LEFT JOIN metabib.full_rec title ON (r.id = title.record AND title.tag = '245' AND title.subfield = 'a')
-    LEFT JOIN ( -- Grab 245 N and P subfields in the order that they appear.
-      SELECT b.record, string_agg(val, ' ') AS val FROM (
-             SELECT title_np.record, title_np.value AS val
-              FROM metabib.full_rec title_np
-              WHERE
-              title_np.tag = '245'
-                        AND title_np.subfield IN ('p','n')
-                        ORDER BY title_np.id
-                ) b
-                GROUP BY 1
-         ) title_np ON (title_np.record=r.id)
-    LEFT JOIN metabib.full_rec author ON (r.id = author.record AND author.tag IN ('100','110','111') AND author.subfield = 'a')
-    LEFT JOIN metabib.full_rec publisher ON (r.id = publisher.record AND (publisher.tag = '260' OR (publisher.tag = '264' AND publisher.ind2 = '1')) AND publisher.subfield = 'b')
-    LEFT JOIN metabib.full_rec pubdate ON (r.id = pubdate.record AND (pubdate.tag = '260' OR (pubdate.tag = '264' AND pubdate.ind2 = '1')) AND pubdate.subfield = 'c')
-    LEFT JOIN metabib.full_rec isbn ON (r.id = isbn.record AND isbn.tag IN ('024', '020') AND isbn.subfield IN ('a','z'))
-    LEFT JOIN metabib.full_rec issn ON (r.id = issn.record AND issn.tag = '022' AND issn.subfield = 'a')
-  GROUP BY 1,2,3,4,5;
+        JOIN metabib.wide_display_entry d ON (r.id = d.source);
 
 CREATE TABLE reporter.materialized_simple_record AS SELECT * FROM reporter.old_super_simple_record WHERE 1=0;
 ALTER TABLE reporter.materialized_simple_record ADD PRIMARY KEY (id);
diff --git a/Open-ILS/src/sql/Pg/upgrade/WWWW.data.display-field-seed-data.sql b/Open-ILS/src/sql/Pg/upgrade/WWWW.data.display-field-seed-data.sql
index b44afd4..fae9b21 100644
--- a/Open-ILS/src/sql/Pg/upgrade/WWWW.data.display-field-seed-data.sql
+++ b/Open-ILS/src/sql/Pg/upgrade/WWWW.data.display-field-seed-data.sql
@@ -99,6 +99,26 @@ VALUES (
 )
 ;
 
+INSERT INTO config.metabib_field (id, field_class, name, format,
+    label, xpath, display_xpath, display_field, search_field, browse_field)
+VALUES (
+    51, 'author', 'first_author', 'mods32',
+    oils_i18n_gettext(51, 'Author', 'cmf', 'label'),
+    $$//mods32:mods/mods32:name[mods32:role/mods32:roleTerm[text()='creator']][1]$$,
+    $$//*[local-name()='namePart']$$,
+    TRUE, TRUE, FALSE
+);
+
+INSERT INTO config.metabib_field (id, field_class, name, format,
+    label, xpath, display_xpath, display_field, search_field, browse_field)
+VALUES (
+    52, 'keyword', 'origin_info', 'marcxml',
+    oils_i18n_gettext(52, 'Origin Info', 'cmf', 'label'),
+    $$//*[@tag='260']$$,
+    $$//*[local-name()='subfield' and contains('abc', at code)]$$,
+    TRUE, TRUE, FALSE
+);
+
 
 -- Modify existing config.metabib_field entries
 
@@ -126,38 +146,40 @@ INSERT INTO config.display_field_map (name, field, multi) VALUES
     ('tcn',                 26, FALSE),
     ('edition',             38, FALSE),
     ('physical_description',39, TRUE),
-    ('publisher',           40, FALSE),
+    ('publisher',           52, FALSE),
     ('abstract',            41, FALSE),
     ('toc',                 42, FALSE),
     ('type_of_resource',    43, FALSE),
     ('pubdate',             44, FALSE)
 ;
 
+UPDATE config.display_field_map SET field = 51 WHERE name = 'author';
+
 -- Add a column to wide-display-entry per well-known field
 
-DROP VIEW metabib.wide_display_entry;
+DROP VIEW IF EXISTS metabib.wide_display_entry;
 CREATE VIEW metabib.wide_display_entry AS
     SELECT 
         bre.id AS source,
-        COALESCE(mcde_title.value, 'null') AS title,
-        COALESCE(mcde_author.value, 'null') AS author,
-        COALESCE(mcde_subject_geographic.value, 'null') AS subject_geographic,
-        COALESCE(mcde_subject_name.value, 'null') AS subject_name,
-        COALESCE(mcde_subject_temporal.value, 'null') AS subject_temporal,
-        COALESCE(mcde_subject_topic.value, 'null') AS subject_topic,
-        COALESCE(mcde_creators.value, 'null') AS creators,
-        COALESCE(mcde_isbn.value, 'null') AS isbn,
-        COALESCE(mcde_issn.value, 'null') AS issn,
-        COALESCE(mcde_upc.value, 'null') AS upc,
-        COALESCE(mcde_tcn.value, 'null') AS tcn,
-        COALESCE(mcde_edition.value, 'null') AS edition,
-        COALESCE(mcde_physical_description.value, 'null') AS physical_description,
-        COALESCE(mcde_publisher.value, 'null') AS publisher,
-        COALESCE(mcde_series_title.value, 'null') AS series_title,
-        COALESCE(mcde_abstract.value, 'null') AS abstract,
-        COALESCE(mcde_toc.value, 'null') AS toc,
-        COALESCE(mcde_pubdate.value, 'null') AS pubdate,
-        COALESCE(mcde_type_of_resource.value, 'null') AS type_of_resource
+        COALESCE(mcde_title.value, 'null')::TEXT AS title,
+        COALESCE(mcde_author.value, 'null')::TEXT AS author,
+        COALESCE(mcde_subject_geographic.value, 'null')::TEXT AS subject_geographic,
+        COALESCE(mcde_subject_name.value, 'null')::TEXT AS subject_name,
+        COALESCE(mcde_subject_temporal.value, 'null')::TEXT AS subject_temporal,
+        COALESCE(mcde_subject_topic.value, 'null')::TEXT AS subject_topic,
+        COALESCE(mcde_creators.value, 'null')::TEXT AS creators,
+        COALESCE(mcde_isbn.value, 'null')::TEXT AS isbn,
+        COALESCE(mcde_issn.value, 'null')::TEXT AS issn,
+        COALESCE(mcde_upc.value, 'null')::TEXT AS upc,
+        COALESCE(mcde_tcn.value, 'null')::TEXT AS tcn,
+        COALESCE(mcde_edition.value, 'null')::TEXT AS edition,
+        COALESCE(mcde_physical_description.value, 'null')::TEXT AS physical_description,
+        COALESCE(mcde_publisher.value, 'null')::TEXT AS publisher,
+        COALESCE(mcde_series_title.value, 'null')::TEXT AS series_title,
+        COALESCE(mcde_abstract.value, 'null')::TEXT AS abstract,
+        COALESCE(mcde_toc.value, 'null')::TEXT AS toc,
+        COALESCE(mcde_pubdate.value, 'null')::TEXT AS pubdate,
+        COALESCE(mcde_type_of_resource.value, 'null')::TEXT AS type_of_resource
     FROM biblio.record_entry bre 
     LEFT JOIN metabib.compressed_display_entry mcde_title 
         ON (bre.id = mcde_title.source AND mcde_title.name = 'title')
@@ -207,5 +229,26 @@ CREATE VIEW metabib.wide_display_entry AS
             AND mcde_type_of_resource.name = 'type_of_resource')
 ;
 
+CREATE OR REPLACE VIEW reporter.old_super_simple_record AS
+SELECT  r.id,
+    r.fingerprint,
+    r.quality,
+    r.tcn_source,
+    r.tcn_value,
+    evergreen.oils_json_to_text(d.title) AS title,
+    evergreen.oils_json_to_text(d.author) AS author,
+    evergreen.oils_json_to_text(d.publisher) AS publisher,
+    evergreen.oils_json_to_text(d.pubdate) AS pubdate,
+    CASE WHEN d.isbn = 'null'
+        THEN NULL
+        ELSE (SELECT ARRAY(SELECT json_array_elements_text(d.isbn::JSON)))
+    END AS isbn,
+    CASE WHEN d.issn = 'null'
+        THEN NULL
+        ELSE (SELECT ARRAY(SELECT json_array_elements_text(d.issn::JSON)))
+    END AS issn
+  FROM  biblio.record_entry r
+        JOIN metabib.wide_display_entry d ON (r.id = d.source);
+
 COMMIT;
 
diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.highlight_search.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.highlight_search.sql
index 2fc357b..7a4e551 100644
--- a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.highlight_search.sql
+++ b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.highlight_search.sql
@@ -322,6 +322,8 @@ BEGIN
                   WHERE record = $1
                         AND metabib_field = $2
             $$ USING bib_id, vfield, rdata;
+        WHEN OTHERS THEN
+            -- ignore and move on
         END;
     END LOOP;
 END;
@@ -555,5 +557,9 @@ BEGIN
 END;
 $function$ LANGUAGE plpgsql;
 
+CREATE OR REPLACE FUNCTION evergreen.marc_to (marc text, xfrm text) RETURNS TEXT AS $$
+    SELECT evergreen.xml_pretty_print(xslt_process($1,xslt)::XML)::TEXT FROM config.xml_transform WHERE name = $2;
+$$ LANGUAGE SQL;
+
 COMMIT;
 
diff --git a/Open-ILS/src/sql/Pg/upgrade/YYYY.data.mods-title-punctuation-change.sql b/Open-ILS/src/sql/Pg/upgrade/YYYY.data.mods-title-punctuation-change.sql
index 5efb1ff..eb7e34e 100644
--- a/Open-ILS/src/sql/Pg/upgrade/YYYY.data.mods-title-punctuation-change.sql
+++ b/Open-ILS/src/sql/Pg/upgrade/YYYY.data.mods-title-punctuation-change.sql
@@ -1358,6 +1358,45 @@ Added Log Comment
 
                 <!--3.2 change tmee additional note fields-->
 
+                <xsl:for-each select="marc:datafield[@tag=502]">
+                        <note type="thesis">
+                                <xsl:call-template name="uri"/>
+                                <xsl:variable name="str">
+                                        <xsl:for-each select="marc:subfield[@code!='6' or @code!='8']">
+                                                <xsl:value-of select="."/>
+                                                <xsl:text> </xsl:text>
+                                        </xsl:for-each>
+                                </xsl:variable>
+                                <xsl:value-of select="substring($str,1,string-length($str)-1)"/>
+                        </note>
+                </xsl:for-each>
+
+                <xsl:for-each select="marc:datafield[@tag=504]">
+                        <note type="bibliography">
+                                <xsl:call-template name="uri"/>
+                                <xsl:variable name="str">
+                                        <xsl:for-each select="marc:subfield[@code!='6' or @code!='8']">
+                                                <xsl:value-of select="."/>
+                                                <xsl:text> </xsl:text>
+                                        </xsl:for-each>
+                                </xsl:variable>
+                                <xsl:value-of select="substring($str,1,string-length($str)-1)"/>
+                        </note>
+                </xsl:for-each>
+
+                <xsl:for-each select="marc:datafield[@tag=508]">
+                        <note type="creation/production credits">
+                                <xsl:call-template name="uri"/>
+                                <xsl:variable name="str">
+                                        <xsl:for-each select="marc:subfield[@code!='6' or @code!='8']">
+                                                <xsl:value-of select="."/>
+                                                <xsl:text> </xsl:text>
+                                        </xsl:for-each>
+                                </xsl:variable>
+                                <xsl:value-of select="substring($str,1,string-length($str)-1)"/>
+                        </note>
+                </xsl:for-each>
+
                 <xsl:for-each select="marc:datafield[@tag=506]">
                         <note type="restrictions">
                                 <xsl:call-template name="uri"></xsl:call-template>
@@ -1467,7 +1506,7 @@ Added Log Comment
 
 
 
-                <xsl:for-each select="marc:datafield[@tag=501 or @tag=502 or @tag=504 or @tag=507 or @tag=508 or  @tag=513 or @tag=514 or @tag=515 or @tag=516 or @tag=522 or @tag=524 or @tag=525 or @tag=526 or @tag=535 or @tag=536 or @tag=540 or @tag=541 or @tag=544 or @tag=545 or @tag=546 or @tag=547 or @tag=550 or @tag=552 or @tag=555 or @tag=556 or @tag=561 or @tag=562 or @tag=565 or @tag=567 or @tag=580 or @tag=581 or @tag=584 or @tag=585 or @tag=586]">
+                <xsl:for-each select="marc:datafield[@tag=501 or @tag=507 or  @tag=513 or @tag=514 or @tag=515 or @tag=516 or @tag=522 or @tag=524 or @tag=525 or @tag=526 or @tag=535 or @tag=536 or @tag=540 or @tag=541 or @tag=544 or @tag=545 or @tag=546 or @tag=547 or @tag=550 or @tag=552 or @tag=555 or @tag=556 or @tag=561 or @tag=562 or @tag=565 or @tag=567 or @tag=580 or @tag=581 or @tag=584 or @tag=585 or @tag=586]">
                         <note>
                                 <xsl:call-template name="uri"></xsl:call-template>
                                 <xsl:variable name="str">
@@ -4717,6 +4756,45 @@ Revision 1.2 - Added Log Comment  2003/03/24 19:37:42  ckeith
 
                 <!--3.2 change tmee additional note fields-->
 
+                <xsl:for-each select="marc:datafield[@tag=502]">
+                        <note type="thesis">
+                                <xsl:call-template name="uri"/>
+                                <xsl:variable name="str">
+                                        <xsl:for-each select="marc:subfield[@code!='6' or @code!='8']">
+                                                <xsl:value-of select="."/>
+                                                <xsl:text> </xsl:text>
+                                        </xsl:for-each>
+                                </xsl:variable>
+                                <xsl:value-of select="substring($str,1,string-length($str)-1)"/>
+                        </note>
+                </xsl:for-each>
+
+                <xsl:for-each select="marc:datafield[@tag=504]">
+                        <note type="bibliography">
+                                <xsl:call-template name="uri"/>
+                                <xsl:variable name="str">
+                                        <xsl:for-each select="marc:subfield[@code!='6' or @code!='8']">
+                                                <xsl:value-of select="."/>
+                                                <xsl:text> </xsl:text>
+                                        </xsl:for-each>
+                                </xsl:variable>
+                                <xsl:value-of select="substring($str,1,string-length($str)-1)"/>
+                        </note>
+                </xsl:for-each>
+
+                <xsl:for-each select="marc:datafield[@tag=508]">
+                        <note type="creation/production credits">
+                                <xsl:call-template name="uri"/>
+                                <xsl:variable name="str">
+                                        <xsl:for-each select="marc:subfield[@code!='6' or @code!='8']">
+                                                <xsl:value-of select="."/>
+                                                <xsl:text> </xsl:text>
+                                        </xsl:for-each>
+                                </xsl:variable>
+                                <xsl:value-of select="substring($str,1,string-length($str)-1)"/>
+                        </note>
+                </xsl:for-each>
+
                 <xsl:for-each select="marc:datafield[@tag=506]">
                         <note type="restrictions">
                                 <xsl:call-template name="uri"/>
@@ -4823,7 +4901,7 @@ Revision 1.2 - Added Log Comment  2003/03/24 19:37:42  ckeith
                 </xsl:for-each>
 
                 <xsl:for-each
-                        select="marc:datafield[@tag=501 or @tag=502 or @tag=504 or @tag=507 or @tag=508 or  @tag=513 or @tag=514 or @tag=515 or @tag=516 or @tag=522 or @tag=524 or @tag=525 or @tag=526 or @tag=535 or @tag=536 or @tag=540 or @tag=541 or @tag=544 or @tag=545 or @tag=546 or @tag=547 or @tag=550 or @tag=552 or @tag=555 or @tag=556 or @tag=561 or @tag=562 or @tag=565 or @tag=567 or @tag=580 or @tag=581 or @tag=584 or @tag=585 or @tag=586]">+
+                        select="marc:datafield[@tag=501 or @tag=507 or @tag=513 or @tag=514 or @tag=515 or @tag=516 or @tag=522 or @tag=524 or @tag=525 or @tag=526 or @tag=535 or @tag=536 or @tag=540 or @tag=541 or @tag=544 or @tag=545 or @tag=546 or @tag=547 or @tag=550 or @tag=552 or @tag=555 or @tag=556 or @tag=561 or @tag=562 or @tag=565 or @tag=567 or @tag=580 or @tag=581 or @tag=584 or @tag=585 or @tag=586]">+
                         <note>
                                 <xsl:call-template name="uri"/>
                                 <xsl:variable name="str">
diff --git a/Open-ILS/src/templates/opac/parts/record/summary.tt2 b/Open-ILS/src/templates/opac/parts/record/summary.tt2
index 15d2a37..374182f 100644
--- a/Open-ILS/src/templates/opac/parts/record/summary.tt2
+++ b/Open-ILS/src/templates/opac/parts/record/summary.tt2
@@ -333,13 +333,22 @@ END;
     </li>
         [%- END %]
     [%- END %]
-    [%- IF attrs.phys_desc %]
+    [%- IF attrs.hl.physical_description.size %]
+    <li id='rdetail_phys_desc'>
+        <strong class='rdetail_label'>[% l("Physical Description:") %]</strong>
+        <span class='rdetail_value' highlighted='true'>[% attrs.hl.physical_description.join('<br/>') %]</span>
+    </li>
+    [%- ELSIF attrs.phys_desc %]
     <li id='rdetail_phys_desc'>
         <strong class='rdetail_label'>[% l("Physical Description:") %]</strong>
         <span class='rdetail_value'>[% attrs.phys_desc | html %]</span>
     </li>
     [%- END %]
-    [%- IF attrs.edition %]
+    [%- IF attrs.hl.edition %]
+    <li id='rdetail_edition'>
+        <strong class='rdetail_label'>[% l("Edition:") %]</strong>
+        <span class='rdetail_value' highlighted='true'>[% attrs.hl.edition %]</span>
+    [%- ELSIF attrs.edition %]
     <li id='rdetail_edition'>
         <strong class='rdetail_label'>[% l("Edition:") %]</strong>
         <span class='rdetail_value'>[% attrs.edition | html %]</span>
@@ -360,7 +369,12 @@ END;
         -%]
     </li>
     [%- END %]
-    [%- IF attrs.publisher %]
+    [%- IF attrs.hl.publisher %]
+    <li id='rdetail_publisher'>
+        <strong class='rdetail_label'>[% l("Publisher:") %]</strong>
+        <span class='rdetail_value' highlighted='true'>[% attrs.hl.publisher %]</span>
+    </li>
+    [%- ELSIF attrs.publisher %]
     <li id='rdetail_publisher'>
         <strong class='rdetail_label'>[% l("Publisher:") %]</strong>
         <span class='rdetail_value' property="publisher" typeof="Organization">

commit 9e3f4dc75f8636c430d4a144bd62396e5a825350
Author: Mike Rylander <mrylander at gmail.com>
Date:   Fri Jan 26 16:52:09 2018 -0500

    LP#1744385: Set best order for upgrade scripts
    
    Signed-off-by: Mike Rylander <mrylander at gmail.com>
    Signed-off-by: Kathy Lussier <klussier at masslnc.org>
    Signed-off-by: Dan Wells <dbw2 at calvin.edu>

diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.data.display-field-seed-data.sql b/Open-ILS/src/sql/Pg/upgrade/WWWW.data.display-field-seed-data.sql
similarity index 100%
rename from Open-ILS/src/sql/Pg/upgrade/XXXX.data.display-field-seed-data.sql
rename to Open-ILS/src/sql/Pg/upgrade/WWWW.data.display-field-seed-data.sql
diff --git a/Open-ILS/src/sql/Pg/upgrade/YYYY.data.virtual_index_defs.sql b/Open-ILS/src/sql/Pg/upgrade/ZZZZ.data.virtual_index_defs.sql
similarity index 100%
rename from Open-ILS/src/sql/Pg/upgrade/YYYY.data.virtual_index_defs.sql
rename to Open-ILS/src/sql/Pg/upgrade/ZZZZ.data.virtual_index_defs.sql

commit f5c6bffd3645e538d6908d5967004b5648b5478f
Author: Mike Rylander <mrylander at gmail.com>
Date:   Wed Jan 10 14:44:48 2018 -0500

    LP#1744385: Allow highlight disabling globally via config.tt2
    
    Also, add CC0 highlighter icon from https://pixabay.com/en/highlight-highlighter-highlighting-2022407/
    and provide highlight en/dis-able.
    
    Signed-off-by: Mike Rylander <miker at esilibrary.com>
    Signed-off-by: Kathy Lussier <klussier at masslnc.org>
    Signed-off-by: Dan Wells <dbw2 at calvin.edu>

diff --git a/Open-ILS/src/templates/opac/parts/config.tt2 b/Open-ILS/src/templates/opac/parts/config.tt2
index 28f730c..ac731cd 100644
--- a/Open-ILS/src/templates/opac/parts/config.tt2
+++ b/Open-ILS/src/templates/opac/parts/config.tt2
@@ -181,6 +181,9 @@ search.basic_config = {
 # Make metarecord search the default.
 #search.metarecord_default = 1;
 
+# Disable search term highlighting
+#search.no_highlight = 1;
+
 ##############################################################################
 # Show Google Book Previews
 # Set to 1 or 'true' to enable
diff --git a/Open-ILS/src/templates/opac/parts/misc_util.tt2 b/Open-ILS/src/templates/opac/parts/misc_util.tt2
index 2d48ccc..ba507bd 100644
--- a/Open-ILS/src/templates/opac/parts/misc_util.tt2
+++ b/Open-ILS/src/templates/opac/parts/misc_util.tt2
@@ -108,7 +108,7 @@
 
         args.display_fields = {};
         args.hl = {};
-        IF !CGI.param('no_highlight');
+        IF !CGI.param('no_highlight') && !search.no_highlight;
             args.display_field_list = ctx.fetch_display_fields(args.df_bib_list.list);
 
             FOR df IN args.display_field_list;
diff --git a/Open-ILS/src/templates/opac/parts/record/summary.tt2 b/Open-ILS/src/templates/opac/parts/record/summary.tt2
index 20b7d36..15d2a37 100644
--- a/Open-ILS/src/templates/opac/parts/record/summary.tt2
+++ b/Open-ILS/src/templates/opac/parts/record/summary.tt2
@@ -138,6 +138,18 @@
                     </a>
                 </div>
             [% END %]
+            [% IF !search.no_highlight %]
+            <div class="rdetail_aux_utils highlighting">
+              [% IF CGI.param('no_highlight') %]
+                <a href="[% mkurl('', {}, ['no_highlight']) %]" class="no-dec">
+              [% ELSE %]
+                <a href="[% mkurl('', {no_highlight => '1'}) %]" class="no-dec">
+              [% END %]
+                     <img src="[% ctx.media_prefix %]/images/highlight.png[% ctx.cache_key %]" alt="[% l('Toggle highlighting') %]" />
+                     [% CGI.param('no_highlight') ?  l('Enable Highlighting') : l('Disable Highlighting') %]
+                </a>
+            </div>
+            [% END %]
             [%- IF ctx.is_staff %]
             <div class="rdetail_aux_utils clear_addedcontent_cache">
                 <a href="[% ctx.media_prefix %]/opac/extras/ac/clearcache/all/r/[% ctx.bre_id | uri %]" class="no-dec" target="_blank">
diff --git a/Open-ILS/src/templates/opac/parts/searchbar.tt2 b/Open-ILS/src/templates/opac/parts/searchbar.tt2
index c33a897..0a5f62f 100644
--- a/Open-ILS/src/templates/opac/parts/searchbar.tt2
+++ b/Open-ILS/src/templates/opac/parts/searchbar.tt2
@@ -94,7 +94,7 @@ END;
               id='search_org_selector' show_loc_groups=1
         -%]
         </label>
-    <span>
+      <span>
         <input id="detail" type="hidden" name="detail_record_view" value="[% show_detail_view %]"/>
         <input id='search-submit-go' type="submit" value="[% l('Search') %]" class="opac-button"
             onclick='setTimeout(function(){$("search-submit-spinner").className=""; $("search-submit-go").className="hidden";[% IF ctx.depth_sel_button AND NOT took_care_of_form %] $("search-submit-go-depth").className="hidden";[% END %]}, 2000)'/>
@@ -103,7 +103,15 @@ END;
             onclick='setTimeout(function(){$("search-submit-spinner").className=""; $("search-submit-go").className="hidden"; $("search-submit-go-depth").className="hidden";}, 2000)' title="[% ctx.depth_sel_tooltip | html %]">[% ctx.depth_sel_button_label | html %]</button>
         [%- END %]
         <img id='search-submit-spinner' src='[% ctx.media_prefix %]/opac/images/progressbar_green.gif[% ctx.cache_key %]' style='height:16px;width:16px;' class='hidden' alt='[% l("Search In Progress") %]'/>
-    </span>
+        [%- IF took_care_of_form && !search.no_highlight %]
+        <label for="no_highlight">
+          <input type="checkbox" id="no_highlight" name="no_highlight" value="1"
+              onchange="search_modifier_onchange('no_highlight', this, true)"
+              [% CGI.param('no_highlight').size ? ' checked="checked"' : '' %] />
+          [% l('Disable Highlighting') %]
+        </label>
+        [%- END %]
+      </span>
     </div>
     [% IF ctx.bookbag %]
     <div id="search-only-bookbag-container">
diff --git a/Open-ILS/web/images/highlight.png b/Open-ILS/web/images/highlight.png
new file mode 100644
index 0000000..d550b46
Binary files /dev/null and b/Open-ILS/web/images/highlight.png differ

commit f96108efd162213e0728b1286c3b5e5fbd86683a
Author: Mike Rylander <mrylander at gmail.com>
Date:   Fri Jan 12 15:24:12 2018 -0500

    LP#1744385: Additional seed data and display field use in the OPAC
    
    ... and teach subjects.tt2 how to search with a facet in HL mode (for genre)
    
    Signed-off-by: Mike Rylander <mrylander at gmail.com>
    Signed-off-by: Kathy Lussier <klussier at masslnc.org>
    Signed-off-by: Dan Wells <dbw2 at calvin.edu>

diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.data.display-field-seed-data.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.data.display-field-seed-data.sql
index 6b1788b..b44afd4 100644
--- a/Open-ILS/src/sql/Pg/upgrade/XXXX.data.display-field-seed-data.sql
+++ b/Open-ILS/src/sql/Pg/upgrade/XXXX.data.display-field-seed-data.sql
@@ -4,6 +4,8 @@ BEGIN;
 
 -- NEW config.metabib_field entries
 
+UPDATE config.metabib_field SET display_xpath = facet_xpath, display_field = TRUE WHERE id = 33;
+
 INSERT INTO config.metabib_field (id, field_class, name, 
     label, xpath, display_field, search_field, browse_field)
 VALUES (
@@ -67,6 +69,36 @@ VALUES (
     TRUE, FALSE, FALSE
 );
 
+INSERT INTO config.metabib_field (id, field_class, name, 
+    label, xpath, display_field, search_field, browse_field)
+VALUES (
+    46, 'keyword', 'bibliography', 
+    oils_i18n_gettext(46, 'Bibliography', 'cmf', 'label'),
+    $$//mods33:note[@type='bibliography']$$,
+    TRUE, TRUE, FALSE
+),(
+    47, 'keyword', 'thesis', 
+    oils_i18n_gettext(47, 'Thesis', 'cmf', 'label'),
+    $$//mods33:note[@type='thesis']$$,
+    TRUE, TRUE, FALSE
+),(
+    48, 'keyword', 'production_credits', 
+    oils_i18n_gettext(48, 'Creation/Production Credits', 'cmf', 'label'),
+    $$//mods33:note[@type='creation/production credits']$$,
+    TRUE, TRUE, FALSE
+),(
+    49, 'keyword', 'performers', 
+    oils_i18n_gettext(49, 'Performers', 'cmf', 'label'),
+    $$//mods33:note[@type='performers']$$,
+    TRUE, TRUE, FALSE
+),(
+    50, 'keyword', 'general_note', 
+    oils_i18n_gettext(50, 'General Note', 'cmf', 'label'),
+    $$//mods33:note[not(@type)]$$,
+    TRUE, TRUE, FALSE
+)
+;
+
 
 -- Modify existing config.metabib_field entries
 
diff --git a/Open-ILS/src/sql/Pg/upgrade/YYYY.data.virtual_index_defs.sql b/Open-ILS/src/sql/Pg/upgrade/YYYY.data.virtual_index_defs.sql
index 65e67ed..1618350 100644
--- a/Open-ILS/src/sql/Pg/upgrade/YYYY.data.virtual_index_defs.sql
+++ b/Open-ILS/src/sql/Pg/upgrade/YYYY.data.virtual_index_defs.sql
@@ -8,7 +8,8 @@ INSERT INTO config.metabib_field_virtual_map (real, virtual)
             45
       FROM  config.metabib_field
       WHERE search_field
-            AND id NOT IN (15, 45);
+            AND id NOT IN (15, 45)
+            AND id NOT IN (SELECT real FROM config.metabib_field_virtual_map);
 
 UPDATE config.metabib_field SET xpath=$$//mods32:mods/mods32:subject[not(descendant::mods32:geographicCode)]$$ WHERE id = 16;
 
diff --git a/Open-ILS/src/templates/opac/parts/record/contents.tt2 b/Open-ILS/src/templates/opac/parts/record/contents.tt2
index 4f7897e..87057dc 100644
--- a/Open-ILS/src/templates/opac/parts/record/contents.tt2
+++ b/Open-ILS/src/templates/opac/parts/record/contents.tt2
@@ -1,15 +1,18 @@
 [%-
 contents =  [
     {
+        display_field => 'general_note',
         label => l('General Note: '),
         xpath => '//*[@tag="500"]'
     }, {
         label => l('With Note: '),
         xpath => '//*[@tag="501"]'
     }, {
+        display_field => 'thesis',
         label => l('Dissertation Note: '),
         xpath => '//*[@tag="502"]'
     }, {
+        display_field => 'bibliography',
         label => l('Bibliography, etc. Note: '),
         xpath => '//*[@tag="504"]'
     }, {
@@ -23,12 +26,14 @@ contents =  [
         label => l('Scale Note for Graphic Material: '),
         xpath => '//*[@tag="507"]'
     }, {
+        display_field => 'production_credits',
         label => l('Creation/Production Credits Note: '),
         xpath => '//*[@tag="508"]'
     }, {
         label => l('Citation/References Note: '),
         xpath => '//*[@tag="510"]'
     }, {
+        display_field => 'performers',
         label => l('Participant or Performer Note: '),
         xpath => '//*[@tag="511"]'
     }, {
@@ -187,7 +192,7 @@ BLOCK render_all_contents;
         content = '';
         df = cont.display_field;
         IF df AND attrs.hl.$df.size;
-            content = attrs.hl.$df.join('<br/>');
+            content = '<!-- highlighted -->' _ attrs.hl.$df.join('<br/>');
         ELSE;
             content = PROCESS render_contents(xpath=cont.xpath);
         END;
diff --git a/Open-ILS/src/templates/opac/parts/record/subjects.tt2 b/Open-ILS/src/templates/opac/parts/record/subjects.tt2
index ad02856..73ae64f 100644
--- a/Open-ILS/src/templates/opac/parts/record/subjects.tt2
+++ b/Open-ILS/src/templates/opac/parts/record/subjects.tt2
@@ -5,6 +5,7 @@
             label => l('Subject: '),
             xpath => '//*[@tag="600" or @tag="610" or @tag="611" or @tag="630" or @tag="650" or @tag="651"]'
         }, {
+            display_field => 'genre',
             label => l('Genre: '),
             facet => 'identifier|genre',
             joiner => ' -- ',
@@ -82,9 +83,14 @@
     END;
 
     BLOCK render_hl_subject;
-        '<span property="about">';
+        total_term = s.value;
+        IF s.facet;
+            total_term = s.facet _ '[' _ s.value _ ']';
+        END;
+
+        '<span property="about"><!-- highlighted -->';
         %]<a href="[%-
-               mkurl(ctx.opac_root _ '/results', {qtype=>'subject', query=>s.value}, stop_parms.merge(expert_search_parms, general_search_parms, browse_search_parms, facet_search_parms))
+               mkurl(ctx.opac_root _ '/results', {qtype=>'subject', query=>total_term}, stop_parms.merge(expert_search_parms, general_search_parms, browse_search_parms, facet_search_parms))
         -%]">[% s.highlight %]</a> [%-
         '</span>';
     END;
@@ -97,6 +103,7 @@
         IF df AND attrs.hl_display_fields.$df.size;
             content = [];
             FOREACH hl_s IN attrs.hl_display_fields.$df;
+                hl_s.facet = subj.facet;
                 next_s = PROCESS render_hl_subject(s=hl_s);
                 content.push(next_s);
             END;

commit dafb624be8bc31b83e8b503d248f7131fed4c580
Author: Mike Rylander <mrylander at gmail.com>
Date:   Mon Sep 11 15:24:55 2017 -0400

    LP#1744385: Search and Result Display improvements
    
    == Virtual Index Definitions
    
    The practical purpose of Virtual Index Definitions is to supply an Evergreen administrator with
    the ability to control the weighting and field inclusion of values in the general keyword index,
    commonly referred to as "the blob," without requiring tricky configuration that has subtle semantics, an
    over-abundance of index definitions which can slow search generally, or the need to reingest all
    records on a regular basis as experiments are performed and the configuration refined. Significant
    results of recasting keyword indexes as a set of one or more Virtual Index Definitions will be simpler
    search configuration management, faster search speed overall, and more practical reconfiguration and
    adjustment as needed.
    
    Previous to this commit, in order to provide field-specific weighting to keyword matches against titles or authors, an
    administrator must duplicate many other index definitions and supply overriding weights to those
    duplicates. This not only complicates configuration, but slows down record ingest as well as search. It
    is also fairly ineffective at achieving the goal of weighted keyword fields. Virtual Index Definitions will
    substantially alleviate the need for these workarounds and their consequences.
    
      * A Virtual Index Definition is not required supply any configuration for extracting bibliographic
        data from records, but instead can become a sink for data collected by other index definitions
        which is then colocated together to supply a search target made up of the separately extracted
        data. Virtual Index Definitions are effectively treated as aggregate definitions, matching across
        all values extracted from constituent non-virtual index definitions.  They can further make use
        of the Combined class functionality to colocate all values in a class together for matching even
        across virtual fields.
    
      * Configuration allows for weighting of constituent index definitions that participate in a
        Virtual Index Definition. This weighting is separate from the weighting supplied when the index
        definition itself is a search target.
    
      * The Evergreen QueryParser driver returns the list of fields actually searched using every
        user-supplied term set, including constituent expansion when a Virtual Index Definition is
        searched. In particular, this will facilitate Search Term Highlighting described below.
    
      * Stock configuration changes make use of pre-existing, non-virtual index definitions mapped
        to new a Virtual Index Definition that implements the functionality provided by the
        keyword|keyword index definition. The keyword|keyword definition is left in place for the time
        being, until more data can be gathered about the real-world effect of removing it entirely and
        replacing it with Virtual Index Definition mappings.
    
      * New system administration functions will be created to facilitate modification of Virtual Index
        Definition mapping, avoiding the need for a full reingest when existing index definitions are
        added or removed from a virtual field.
    
    == Increased use of Metabib Display Fields
    
    In extention of changes proposed in other available branches, we here use Metabib Display Fields
    to render catalog search results, intermediate metarecord results, and record detail pages.
    This will requires the addition of several new Metabib Display Field definitions, as well as Perl
    services to gather and render the data.
    
    == Search Term Highlighting
    
    This commit enables Search Term Highlighting in the OPAC on the main search results page, the record
    detail page, and intermediate pages such as metarecord grouped results page. Highlighting
    search terms will help the user determine why a particular record (or set of records) was retrieved.
    
    Highlighting of matched terms uses the same stemming used to accomplish the search, as configured
    per field and class.
    
    This feature will help the user more quickly determine the relevance of a particular record by calling their
    attention to search terms in context. Lastly, it will help familiarize the user with how records are
    searched, including which fields are searched as well as exposing concepts like stemming.
    
    == Interfaces
    
    A new AngularJS "MARC Search/Facet Fields" interface has been created to replace the Dojo version, and
    both have been extended to support Virtual Index Definition data supplier mapping and weighting.
    
    == Settings & Permissions
    
    The new Virtual Index Definition data supplier mapping table, config.metabib_field_virtual_map, requires
    the same permissions as the MARC Search/Facet Fields interface: CREATE_METABIB_FIELD, UPDATE_METABIB_FIELD,
    DELETE_METABIB_FIELD, or ADMIN_METABIB_FIELD for all actions
    
    There is a new template-level global configuration variable in config.tt2 called search.no_highlight
    which disables highlighting for users of that config.tt2 instance.
    
    == Public Catalog
    
    The public and staff catalog will make use of new APIs to identify and display highlight-augmented
    values for those Display Fields used to render the search result pages, intermediate metarecord
    constituent pages, and record detail pages.  Highlighting of terms will be performed using the
    application of Template::Toolkit-driven CSS. A generic CSS class identifying a highlighted term,
    along with CSS classes identifying the search class and each search field will be available for
    use for customization of the highlighting. A stock CSS
    template is provided as a baseline upon which sites may expand.
    
    When highlighting is generally enabled, it may be turned on or off on a per-page basis through the use of
    a UI component which will request the page again without highlighting.
    
    == Backend
    
    There now exist several new database tables and functions primarily in support of search highlighting.
    Additionally, the QueryParser driver for Evergreen has been augmented to be able to return a data structure
    describing how the search was performed, in a way that allows a separate support API to gather a highlighted
    version of the Display Field data for a given record.
    
    == Re-ingest or Indexing Dependencies
    
    With the addition and modification of many Index Definitions, a full reingest is recommended.  However, search
    will continue to work as it did before the changes in this commit for those records that have not yet been
    reingested during that process.  Therefore a slow, rolling reingest is recommended.
    
    == Performance Implications or Concerns
    
    Because the Metabib Display Fields infrastructure will eventually replace functionality that is significantly more
    CPU-intensive in the various forms of XML parsing, XSLT transformation, XPath calculation, and
    Metabib Virtual Record construction, it is expected that the overall CPU load will be reduced by this
    development, and ideally the overall time required to perform and render a search will likewise drop. It
    is unlikely that the speed increase will be visible to users on a per-search basis, but that search in
    aggregate will become a smaller consumer of resources.
    
    Signed-off-by: Mike Rylander <mrylander at gmail.com>
    Signed-off-by: Kathy Lussier <klussier at masslnc.org>
    Signed-off-by: Dan Wells <dbw2 at calvin.edu>

diff --git a/Open-ILS/examples/fm_IDL.xml b/Open-ILS/examples/fm_IDL.xml
index a84b556..ae53496 100644
--- a/Open-ILS/examples/fm_IDL.xml
+++ b/Open-ILS/examples/fm_IDL.xml
@@ -2761,7 +2761,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 			</actions>
 		</permacrud>
 	</class>
-	<class id="cxt" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="config::xml_transform" oils_persist:tablename="config.xml_transform" reporter:label="XML/XSLT Transform Definition">
+	<class id="cxt" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="config::xml_transform" oils_persist:tablename="config.xml_transform" reporter:label="XML/XSLT Transform Definition" oils_persist:field_safe="true">
 		<fields oils_persist:primary="name">
 			<field reporter:label="Name" name="name" reporter:datatype="text" />
 			<field reporter:label="Namespace URI" name="namespace_uri" reporter:datatype="text"/>
@@ -2801,7 +2801,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 
 	<class id="cmc" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="config::metabib_class" oils_persist:tablename="config.metabib_class" reporter:label="Metabib Class" oils_persist:field_safe="true">
 		<fields oils_persist:primary="name">
-			<field reporter:label="Name" name="name" reporter:datatype="text"/>
+			<field reporter:label="Name" name="name" reporter:datatype="text" reporter:selector="label"/>
 			<field reporter:label="Label" name="label" reporter:datatype="text" oils_persist:i18n="true"/>
 			<field reporter:label="Buoyant?" name="buoyant" reporter:datatype="bool" />
 			<field reporter:label="Restrict?" name="restrict" reporter:datatype="bool" />
@@ -2827,26 +2827,32 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 
 	<class id="cmf" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="config::metabib_field" oils_persist:tablename="config.metabib_field" reporter:label="Metabib Field" oils_persist:field_safe="true">
 		<fields oils_persist:primary="id" oils_persist:sequence="config.metabib_field_id_seq">
-			<field reporter:label="Class" name="field_class" reporter:datatype="link"/>
 			<field reporter:label="ID" name="id" reporter:datatype="id" reporter:selector="label"/>
-			<field reporter:label="Name" name="name" reporter:datatype="text"/>
+			<field reporter:label="Class" name="field_class" reporter:datatype="link"/>
 			<field reporter:label="Label" name="label" reporter:datatype="text" oils_persist:i18n="true"/>
-			<field reporter:label="XPath" name="xpath" reporter:datatype="text"/>
+			<field reporter:label="Name" name="name" reporter:datatype="text"/>
 			<field reporter:label="Weight" name="weight" reporter:datatype="int" />
+			<field reporter:label="XPath" name="xpath" reporter:datatype="text"/>
+			<field reporter:label="Joiner" name="joiner" reporter:datatype="text"/>
 			<field reporter:label="Format" name="format" reporter:datatype="link"/>
 			<field reporter:label="Search Field" name="search_field" reporter:datatype="bool" />
 			<field reporter:label="Facet Field" name="facet_field" reporter:datatype="bool" />
 			<field reporter:label="Facet XPath" name="facet_xpath" reporter:datatype="text" />
+			<field reporter:label="Display Field?" name="display_field" reporter:datatype="bool" />
 			<field reporter:label="Display XPath" name="display_xpath" reporter:datatype="text" />
 			<field reporter:label="Browse Field" name="browse_field" reporter:datatype="bool" />
 			<field reporter:label="Browse XPath" name="browse_xpath" reporter:datatype="text" />
+			<field reporter:label="Browse Sort XPath" name="browse_sort_xpath" reporter:datatype="text" />
+			<field reporter:label="Authority XPath" name="authority_xpath" reporter:datatype="text" />
 			<field reporter:label="Restrict?" name="restrict" reporter:datatype="bool" />
-			<field reporter:label="Display Field?" name="display_field" reporter:datatype="bool" />
 			<field reporter:label="Display Field Map" name="display_field_map" oils_persist:virtual="true" reporter:datatype="link"/>
+			<field reporter:label="Virtual Field Data Suppliers" name="data_sources" oils_persist:virtual="true" reporter:datatype="link"/>
 		</fields>
 		<links>
+			<link field="format" reltype="has_a" key="name" map="" class="cxt"/>
 			<link field="field_class" reltype="has_a" key="name" map="" class="cmc"/>
 			<link field="display_field_map" reltype="might_have" key="field" map="" class="cdfm"/>
+			<link field="data_sources" reltype="has_many" key="virtual" map="" class="cmfvm"/>
 		</links>
         <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
             <actions>
@@ -2857,6 +2863,28 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
             </actions>
         </permacrud>
 	</class>
+
+	<class id="cmfvm" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="config::metabib_field_virtual_map" oils_persist:tablename="config.metabib_field_virtual_map" reporter:label="Metabib Field Virtual Map" oils_persist:field_safe="true">
+		<fields oils_persist:primary="id" oils_persist:sequence="config.metabib_field_virtual_map_id_seq">
+			<field reporter:label="ID" name="id" reporter:datatype="id"/>
+			<field reporter:label="Real" name="real" reporter:datatype="link"/>
+			<field reporter:label="Virtual" name="virtual" reporter:datatype="link"/>
+			<field reporter:label="Weight" name="weight" reporter:datatype="int"/>
+		</fields>
+		<links>
+			<link field="real" reltype="has_a" key="id" map="" class="cmf"/>
+			<link field="virtual" reltype="has_a" key="id" map="" class="cmf"/>
+		</links>
+        <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
+            <actions>
+                <create permission="CREATE_METABIB_FIELD ADMIN_METABIB_FIELD" global_required="true"/>
+                <retrieve/>
+                <update permission="UPDATE_METABIB_FIELD ADMIN_METABIB_FIELD" global_required="true"/>
+                <delete permission="DELETE_METABIB_FIELD ADMIN_METABIB_FIELD" global_required="true"/>
+            </actions>
+        </permacrud>
+	</class>
+
 	<class id="cbho" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="config::best_hold_order" oils_persist:tablename="config.best_hold_order" reporter:label="Best-Hold Sort Order">
 		<fields oils_persist:primary="id" oils_persist:sequence="config.best_hold_order_id_seq">
 			<field reporter:label="ID" name="id" reporter:datatype="id" reporter:selector="name" />
@@ -3736,6 +3764,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 			<field name="field" reporter:datatype="link"/>
 			<field name="source" reporter:datatype="link"/>
 			<field name="value"  reporter:datatype="text"/>
+			<field name="highlight" oils_persist:virtual="true"  reporter:datatype="text"/>
 		</fields>
 		<links>
 			<link field="source" reltype="has_a" key="id" map="" class="bre"/>
@@ -3839,8 +3868,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 		oils_persist:tablename="config.display_field_map"
 		oils_obj:fieldmapper="config::display_field_map"
 		oils_persist:field_safe="true"
-		reporter:label="Display Field Map" 
-		oils_persist:readonly="true">
+		reporter:label="Display Field Map">
 		<fields oils_persist:primary="name">
 			<field name="name" reporter:datatype="text"/>
 			<field name="field" reporter:datatype="link"/>
diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Search/Biblio.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Search/Biblio.pm
index 06ec97d..96ce5da 100644
--- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Search/Biblio.pm
+++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Search/Biblio.pm
@@ -1306,6 +1306,30 @@ sub staged_search {
     return cache_facets($facet_key, $new_ids, $IAmMetabib, $ignore_facet_classes) if $docache;
 }
 
+sub passthrough_fetch_display_fields {
+    my $self = shift;
+    my $conn = shift;
+    my $highlight_map = shift;
+    my @records = @_;
+
+    return $U->storagereq(
+        'open-ils.storage.fetch.metabib.display_field.highlight',
+        $highlight_map,
+        @records
+    ) if (@records == 1);
+
+    return $U->storagereq(
+        'open-ils.storage.fetch.metabib.display_field.highlight.atomic',
+        $highlight_map,
+        \@records
+    );
+}
+__PACKAGE__->register_method(
+    method    => 'passthrough_fetch_display_fields',
+    api_name  => 'open-ils.search.fetch.metabib.display_field.highlight'
+);
+
+
 sub tag_circulated_records {
     my ($auth, $results, $metabib) = @_;
     my $e = new_editor(authtoken => $auth);
diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/CDBI/config.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/CDBI/config.pm
index 12f4f45..e91ff20 100644
--- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/CDBI/config.pm
+++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/CDBI/config.pm
@@ -34,6 +34,13 @@ __PACKAGE__->columns(Primary => 'id');
 __PACKAGE__->columns(Essential => qw/field_class name xpath weight format search_field facet_field display_xpath display_field/);
 #-------------------------------------------------------------------------------
 
+package config::metabib_field_virtual_map;
+use base qw/config/;
+__PACKAGE__->table('config_metabib_field_virtual_map');
+__PACKAGE__->columns(Primary => 'id');
+__PACKAGE__->columns(Essential => qw/real virtual/);
+#-------------------------------------------------------------------------------
+
 package config::identification_type;
 use base qw/config/;
 __PACKAGE__->table('config_identification_type');
diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Driver/Pg/QueryParser.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Driver/Pg/QueryParser.pm
index 4b45483..a763f4d 100644
--- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Driver/Pg/QueryParser.pm
+++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Driver/Pg/QueryParser.pm
@@ -8,6 +8,8 @@ use OpenSRF::Utils qw/:datetime/;
 use OpenSRF::Utils::JSON;
 use OpenILS::Application::AppUtils;
 use OpenILS::Utils::CStoreEditor;
+use OpenSRF::Utils::Logger qw($logger);
+use Data::Dumper;
 my $U = 'OpenILS::Application::AppUtils';
 
 my ${spc} = ' ' x 2;
@@ -228,6 +230,15 @@ sub search_field_id_map {
     return $self->custom_data->{search_field_id_map};
 }
 
+sub search_field_virtual_map {
+    my $self = shift;
+    my $map = shift;
+
+    $self->custom_data->{search_field_virtual_map} ||= {};
+    $self->custom_data->{search_field_virtual_map} = $map if ($map);
+    return $self->custom_data->{search_field_virtual_map};
+}
+
 sub add_search_field_id_map {
     my $self = shift;
     my $class = shift;
@@ -246,6 +257,18 @@ sub add_search_field_id_map {
     };
 }
 
+sub add_search_field_virtual_map {
+    my $self = shift;
+    my $realid = shift;
+    my $virtid = shift;
+
+    $self->search_field_virtual_map->{by_virt}{$virtid} ||= [];
+    push @{$self->search_field_virtual_map->{by_virt}{$virtid}}, $realid;
+
+    $self->search_field_virtual_map->{by_real}{$realid} ||= [];
+    push @{$self->search_field_virtual_map->{by_real}{$realid}}, $virtid;
+}
+
 sub search_field_class_by_id {
     my $self = shift;
     my $id = shift;
@@ -400,6 +423,17 @@ sub initialize_search_field_id_map {
     return $self->search_field_id_map;
 }
 
+sub initialize_search_field_virtual_map {
+    my $self = shift;
+    my $cmfvm_list = shift;
+
+    __PACKAGE__->add_search_field_virtual_map( $_->real, $_->virtual )
+        for (@$cmfvm_list);
+
+    $logger->debug('Virtual field map: ' . Dumper($self->search_field_virtual_map));
+    return $self->search_field_virtual_map;
+}
+
 sub initialize_aliases {
     my $self = shift;
     my $cmsa_list = shift;
@@ -513,6 +547,9 @@ sub initialize {
     $self->initialize_search_field_id_map( $args{config_metabib_field} )
         if ($args{config_metabib_field});
 
+    $self->initialize_search_field_virtual_map( $args{config_metabib_field_virtual_map} )
+        if ($args{config_metabib_field_virtual_map});
+
     $self->initialize_aliases( $args{config_metabib_search_alias} )
         if ($args{config_metabib_search_alias});
 
@@ -598,6 +635,8 @@ sub TEST_SETUP {
     __PACKAGE__->add_relevance_bump( keyword => keyword => first_word => 1 );
     __PACKAGE__->add_relevance_bump( keyword => keyword => full_match => 1 );
     
+    __PACKAGE__->add_search_field_virtual_map( 6 => 15 );
+
     __PACKAGE__->class_ts_config( 'series', undef, 1, 'english_nostop' );
     __PACKAGE__->class_ts_config( 'title', undef, 1, 'english_nostop' );
     __PACKAGE__->class_ts_config( 'author', undef, 1, 'english_nostop' );
@@ -635,6 +674,8 @@ sub TEST_SETUP {
     
     __PACKAGE__->add_search_field_alias( subject => name => 'bib.subjectName' );
     
+    #__PACKAGE__->search_class_combined( keyword => 1 );
+    __PACKAGE__->search_class_combined( author => 1 );
 }
 
 __PACKAGE__->default_search_class( 'keyword' );
@@ -1169,17 +1210,6 @@ sub flatten {
                     next;
                 }
 
-                my $table = $node->table;
-                my $ctable = $node->combined_table;
-                my $talias = $node->table_alias;
-
-                my $node_rank = 'COALESCE(' . $node->rank . " * ${talias}.weight, 0.0)";
-
-                $from .= "\n" . ${spc} x 4 ."LEFT JOIN (\n"
-                      . ${spc} x 5 . "SELECT fe.*, fe_weight.weight, ${talias}_xq.tsq, ${talias}_xq.tsq_rank /* search */\n"
-                      . ${spc} x 6 . "FROM  $table AS fe";
-                $from .= "\n" . ${spc} x 7 . "JOIN config.metabib_field AS fe_weight ON (fe_weight.id = fe.field)";
-
                 my @bump_fields;
                 my @field_ids;
                 if (@{$node->fields} > 0) {
@@ -1196,22 +1226,37 @@ sub flatten {
                     @bump_fields = @{$self->QueryParser->search_fields->{$node->classname}};
                 }
 
+                # use search_field_list to handle virtual index defs
+                my $search_field_list = $self->QueryParser->search_field_ids_by_class($node->classname);
+                $search_field_list = [@field_ids] if (@field_ids);
+
+                my $table = $node->table;
+                my $ctable = $node->combined_table;
+                my $talias = $node->table_alias;
+
+                my $node_rank = 'COALESCE(' . $node->rank . " * ${talias}.weight * 1000, 0.0)";
+
+                $from .= "\n" . ${spc} x 4 ."LEFT JOIN (\n"
+                      . ${spc} x 5 . "SELECT fe.*, fe_weight.weight, ${talias}_xq.tsq, ${talias}_xq.tsq_rank /* search */\n"
+                      . ${spc} x 6 . "FROM  $table AS fe\n"
+                      . ${spc} x 7 . "JOIN config.metabib_field AS fe_weight ON (fe_weight.id = fe.field)";
+
                 if ($node->dummy_count < @{$node->only_atoms} ) {
                     $with .= ",\n     " if $with;
                     $with .= "${talias}_xq AS (SELECT ". $node->tsquery ." AS tsq,". $node->tsquery_rank ." AS tsq_rank )";
                     if ($node->combined_search) {
-                        $from .= "\n" . ${spc} x 6 . "JOIN $ctable AS com ON (com.record = fe.source";
+                        $from .= "\n" . ${spc} x 7 . "JOIN $ctable AS com ON (com.record = fe.source";
                         if (@field_ids) {
                             $from .= " AND com.metabib_field IN (" . join(',', at field_ids) . "))";
                         } else {
                             $from .= " AND com.metabib_field IS NULL)";
                         }
-                        $from .= "\n" . ${spc} x 6 . "JOIN ${talias}_xq ON (com.index_vector @@ ${talias}_xq.tsq)";
+                        $from .= "\n" . ${spc} x 7 . "JOIN ${talias}_xq ON (com.index_vector @@ ${talias}_xq.tsq)";
                     } else {
-                        $from .= "\n" . ${spc} x 6 . "JOIN ${talias}_xq ON (fe.index_vector @@ ${talias}_xq.tsq)";
+                        $from .= "\n" . ${spc} x 7 . "JOIN ${talias}_xq ON (fe.index_vector @@ ${talias}_xq.tsq)";
                     }
                 } else {
-                    $from .= "\n" . ${spc} x 6 . ", (SELECT NULL::tsquery AS tsq, NULL:tsquery AS tsq_rank ) AS ${talias}_xq";
+                    $from .= "\n" . ${spc} x 7 . ", (SELECT NULL::tsquery AS tsq, NULL::tsquery AS tsq_rank ) AS ${talias}_xq";
                 }
 
                 if (@field_ids) {
@@ -1219,6 +1264,47 @@ sub flatten {
                         join(',', @field_ids) . ")";
                 }
 
+                # Even though virtual fields have all the real field data in
+                # their combined version, and thus a search against the real
+                # fields is not necessary to match records, we still want to
+                # UNION them in so we can get their virtual weight if they
+                # would match a search directly against them.
+                if ($node->dummy_count < @{$node->only_atoms} ) { # no point in searching real fields with no search terms
+                    for my $possible_vfield (@$search_field_list) {
+                        my $real_fields = $self->QueryParser->search_field_virtual_map->{by_virt}->{$possible_vfield};
+                        if ($real_fields and @$real_fields) { # this is a virt field
+                            # UNION in the others ... group by class?
+                            for my $real_field (@$real_fields) {
+                                $node->add_vfield($real_field);
+                                $logger->debug("Looking up virtual field for real field $real_field");
+                                my $vclass = $self->QueryParser->search_field_class_by_id($real_field)->{classname};
+                                my $vtable = $node->table($vclass);
+                                my $vfield = 'field';
+                                my $vrecord = 'source';
+                                $from .= "\n" . ${spc} x 8 . "UNION ALL\n";
+
+                                if ($node->combined_search) { # real fields inherit combine'dness from the virtual field
+                                    $vtable = $node->combined_table($vclass);
+                                    $vfield = 'metabib_field';
+                                    $vrecord = 'record';
+                                    $from .= ${spc} x 5 . "SELECT 0::BIGINT AS id, fe.record AS source, fe.metabib_field AS field, "
+                                          . "'' AS value, fe.index_vector, fe_weight.weight, ${talias}_xq.tsq, ${talias}_xq.tsq_rank /* virtual field addition */\n";
+                                } else {
+                                    $from .= ${spc} x 5 . "SELECT fe.id, fe.source, fe.field, fe.value, fe.index_vector, "
+                                          . "fe_weight.weight, ${talias}_xq.tsq, ${talias}_xq.tsq_rank /* virtual field addition */\n";
+                                }
+                                
+                                $from .= ${spc} x 6 . "FROM  $vtable AS fe\n"
+                                      . ${spc} x 7 . "JOIN config.metabib_field_virtual_map AS fe_weight ON ("
+                                            ."fe_weight.virtual = $possible_vfield AND "
+                                            ."fe_weight.real = $real_field AND "
+                                            ."fe_weight.real = fe.$vfield)\n"
+                                      . ${spc} x 7 . "JOIN ${talias}_xq ON (fe.index_vector @@ ${talias}_xq.tsq)";
+                            }
+                        }
+                    }
+                }
+
                 $from .= "\n" . ${spc} x 4 . ") AS $talias ON (m.source = ${talias}.source)";
 
                 my %used_bumps;
@@ -1239,9 +1325,9 @@ sub flatten {
 
                 if(scalar @bumps > 0 && scalar @{$node->only_positive_atoms} > 0) {
                     # Note: Previous rank function used search_normalize outright. Duplicating that here.
-                    $node_rank .= "\n" . ${spc} x 5 . "* evergreen.rel_bump(('{' || quote_literal(search_normalize(";
+                    $node_rank .= "\n" . ${spc} x 5 . "* COALESCE(evergreen.rel_bump(('{' || quote_literal(search_normalize(";
                     $node_rank .= join(")) || ',' || quote_literal(search_normalize(",map { $self->QueryParser->quote_phrase_value($_->content) } @{$node->only_positive_atoms});
-                    $node_rank .= ")) || '}')::TEXT[], " . $node->table_alias . ".value, '{" . join(",", at bumps) . "}'::TEXT[], '{" . join(",", at bumpmults) . "}'::NUMERIC[])";
+                    $node_rank .= ")) || '}')::TEXT[], " . $node->table_alias . ".value, '{" . join(",", at bumps) . "}'::TEXT[], '{" . join(",", at bumpmults) . "}'::NUMERIC[]),1.0)";
                 }
 
                 my $NOT = '';
@@ -1665,11 +1751,13 @@ sub fields {
 
 sub table_alias {
     my $self = shift;
+    my $suffix = shift;
 
     my $table_alias = "$self";
     $table_alias =~ s/^.*\(0(x[0-9a-fA-F]+)\)$/$1/go;
     $table_alias .= '_' . $self->name;
     $table_alias =~ s/\|/_/go;
+    $table_alias .= "_$suffix" if ($suffix);
 
     return $table_alias;
 }
@@ -1777,6 +1865,86 @@ sub buildSQL {
 #-------------------------------
 package OpenILS::Application::Storage::Driver::Pg::QueryParser::query_plan::node;
 use base 'QueryParser::query_plan::node';
+use List::MoreUtils qw/uniq/;
+use Data::Dumper;
+
+sub abstract_node_additions {
+    my $self = shift;
+    my $aq = shift;
+
+    my $hm = $self->plan
+                ->QueryParser
+                ->parse_tree
+                ->get_abstract_data('highlight_map') || {};
+
+    my $field_set = $self->fields;
+    $field_set = $self->plan->QueryParser->search_fields->{$self->classname}
+        if (!@$field_set);
+
+    my @field_ids = grep defined, (
+        map {
+            $self->plan->QueryParser->search_field_ids_by_class(
+                $self->classname, $_
+            )->[0]
+        } @$field_set
+    );
+
+    push @field_ids, @{$self->{vfields}} if $self->{vfields};
+
+    my $ts_query = $self->tsquery_rank;
+
+    # We need to rework the hash so fields are only ever pointed at once.
+    # That means if a field is already being looked at elsewhere then we'll
+    # need to separate it out and combine its preexisting tsqueries.  This
+    # will be fairly brute-force, and could be improved later, likely, with
+    # a clever algorithm.
+
+    my %inverted_hm;
+    for my $t (keys %$hm) {
+        for my $f (@{$$hm{$t}}) {
+            $inverted_hm{$f} = $t;
+        }
+    }
+
+    # Then, loop over new fields and put them in the inverted hash.
+    my @existing_fields = keys %inverted_hm;
+
+    for my $f (@field_ids) {
+        if (grep { $f == $_ } @existing_fields) { # We've seen the field, should we combine?
+            my $t = $inverted_hm{$f};
+            if ($t ne $ts_query) { # Different tsquery, do it!
+                $t .= ' || '. $ts_query;
+                $inverted_hm{$f} = $t;
+            }
+        } else { # New field
+            $inverted_hm{$f} = $ts_query;
+        }
+    }
+
+    # Now, flip it back over.
+    $hm = {};
+    for my $f (keys %inverted_hm) {
+        my $t = $inverted_hm{$f};
+        if ($$hm{$t}) {
+            push @{$$hm{$t}}, $f;
+        } else {
+            $$hm{$t} = [$f];
+        }
+    }
+
+    $self->plan
+        ->QueryParser
+        ->parse_tree
+        ->set_abstract_data('highlight_map', $hm);
+}
+
+sub add_vfield {
+    my $self = shift;
+    my $vfield = shift;
+
+    $self->{vfields} ||= [];
+    push @{$self->{vfields}}, $vfield;
+}
 
 sub only_atoms {
     my $self = shift;
@@ -1824,18 +1992,14 @@ sub dummy_count {
 
 sub table {
     my $self = shift;
-    my $table = shift;
-    $self->{table} = $table if ($table);
-    return $self->{table} if $self->{table};
-    return $self->table( 'metabib.' . $self->classname . '_field_entry' );
+    my $classname = shift || $self->classname;
+    return 'metabib.' . $classname . '_field_entry';
 }
 
 sub combined_table {
     my $self = shift;
-    my $ctable = shift;
-    $self->{ctable} = $ctable if ($ctable);
-    return $self->{ctable} if $self->{ctable};
-    return $self->combined_table( 'metabib.combined_' . $self->classname . '_field_entry' );
+    my $classname = shift || $self->classname;
+    return 'metabib.combined_' . $classname . '_field_entry';
 }
 
 sub combined_search {
@@ -1845,16 +2009,15 @@ sub combined_search {
 
 sub table_alias {
     my $self = shift;
-    my $table_alias = shift;
-    $self->{table_alias} = $table_alias if ($table_alias);
-    return $self->{table_alias} if ($self->{table_alias});
+    my $suffix = shift;
 
-    $table_alias = "$self";
+    my $table_alias = "$self";
     $table_alias =~ s/^.*\(0(x[0-9a-fA-F]+)\)$/$1/go;
     $table_alias .= '_' . $self->requested_class;
     $table_alias =~ s/\|/_/go;
+    $table_alias .= "_$suffix" if ($suffix);
 
-    return $self->table_alias( $table_alias );
+    return $table_alias;
 }
 
 sub tsquery {
@@ -1881,7 +2044,7 @@ sub tsquery_rank {
         push @atomlines, "\n" . ${spc} x 3 . $atom->sql;
     }
     $self->{tsquery_rank} = join(' ||', @atomlines);
-    $self->{tsquery_rank} = 'NULL::tsquery' unless $self->{tsquery_rank};
+    $self->{tsquery_rank} = "''::tsquery" unless $self->{tsquery_rank};
     return $self->{tsquery_rank};
 }
 
diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Publisher/metabib.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Publisher/metabib.pm
index c8c3ea7..eb3f423 100644
--- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Publisher/metabib.pm
+++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Publisher/metabib.pm
@@ -40,6 +40,11 @@ sub _initialize_parser {
                 'open-ils.cstore.direct.config.metabib_field.search.atomic',
                 { id => { "!=" => undef } }
             )->gather(1),
+        config_metabib_field_virtual_map    =>
+            $cstore->request(
+                'open-ils.cstore.direct.config.metabib_field_virtual_map.search.atomic',
+                { id => { "!=" => undef } }
+            )->gather(1),
         config_metabib_search_alias         =>
             $cstore->request(
                 'open-ils.cstore.direct.config.metabib_search_alias.search.atomic',
@@ -87,6 +92,49 @@ sub _initialize_parser {
     die("Cannot initialize $parser!") unless ($parser->initialization_complete);
 }
 
+sub fetch_highlighted_display_fields {
+    my $self = shift;
+    my $client = shift;
+    my $records = shift;
+    my $highlight_map = shift;
+
+    unless ($records) {
+        $client->respond_complete;
+        return;
+    }
+
+    my $hl_map_string = "''::HSTORE";
+    if (ref($highlight_map)) {
+        $hl_map_string = "";
+        for my $tsq (keys %$highlight_map) {
+            my $field_list = join(',', @{$$highlight_map{$tsq}});
+            $hl_map_string .= ' || ' if $hl_map_string;
+            $hl_map_string .= "hstore(($tsq)\:\:TEXT,'$field_list')";
+        }
+    }
+
+    my $sth = metabib::metarecord_source_map->db_Main->prepare(
+        "SELECT * FROM search.highlight_display_fields(?, $hl_map_string)"
+    );
+
+    $records = [$records] unless ref($records);
+    for my $record ( @$records ) {
+        next unless $record;
+        $sth->execute($record);
+        my $rows = $sth->fetchall_arrayref({});
+        $client->respond($rows);
+    }
+
+    return undef;
+}
+__PACKAGE__->register_method(
+    api_name    => 'open-ils.storage.fetch.metabib.display_field.highlight',
+    method      => 'fetch_highlighted_display_fields',
+    api_level   => 1,
+    stream      => 1
+);
+
+
 sub ordered_records_from_metarecord { # XXX Replace with QP-based search-within-MR
     my $self = shift;
     my $client = shift;
diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/QueryParser.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/QueryParser.pm
index 090b944..199a415 100644
--- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/QueryParser.pm
+++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/QueryParser.pm
@@ -1520,6 +1520,19 @@ package QueryParser::query_plan;
 use Data::Dumper;
 $Data::Dumper::Indent = 0;
 
+sub get_abstract_data {
+    my $self = shift;
+    my $key = shift;
+    return $self->{abstract_data}{$key};
+}
+
+sub set_abstract_data {
+    my $self = shift;
+    my $key = shift;
+    my $value = shift;
+    $self->{abstract_data}{$key} = $value;
+}
+
 sub atoms_only {
     my $self = shift;
     return @{$self->filters} == 0 &&
@@ -1741,7 +1754,7 @@ sub QueryParser {
 sub new {
     my $pkg = shift;
     $pkg = ref($pkg) || $pkg;
-    my %args = (query => [], joiner => '&', @_);
+    my %args = (abstract_data => {}, query => [], joiner => '&', @_);
 
     return bless \%args => $pkg;
 }
@@ -2076,6 +2089,9 @@ sub to_abstract_query {
     }
 
     $abstract_query->{children} ||= { QueryParser::_util::default_joiner() => $kids };
+    $$abstract_query{additional_data} = $self->{abstract_data}
+        if (keys(%{$self->{abstract_data}}));
+
     return $abstract_query;
 }
 
@@ -2301,6 +2317,9 @@ sub to_abstract_query {
         "fields" => $self->fields
     };
 
+    $self->abstract_node_additions($abstract_query)
+        if ($self->can('abstract_node_additions'));
+
     my $kids = [];
 
     for my $qatom (@{$self->query_atoms}) {
diff --git a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm
index 6aa1f58..e386d43 100644
--- a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm
+++ b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm
@@ -341,6 +341,16 @@ sub load_common {
     $self->load_org_util_funcs;
     $self->load_perm_funcs;
 
+    $ctx->{fetch_display_fields} = sub {
+        my $id = shift;
+        return $U->simplereq(
+            'open-ils.search', 
+            'open-ils.search.fetch.metabib.display_field.highlight',
+            $id,
+            $ctx->{query_struct}{additional_data}{highlight_map}
+        );
+    };
+
     return Apache2::Const::OK;
 }
 
diff --git a/Open-ILS/src/sql/Pg/002.schema.config.sql b/Open-ILS/src/sql/Pg/002.schema.config.sql
index 491f3bb..09b59cf 100644
--- a/Open-ILS/src/sql/Pg/002.schema.config.sql
+++ b/Open-ILS/src/sql/Pg/002.schema.config.sql
@@ -202,7 +202,7 @@ CREATE TABLE config.metabib_field (
 	field_class	TEXT	NOT NULL REFERENCES config.metabib_class (name),
 	name		TEXT	NOT NULL,
 	label		TEXT	NOT NULL,
-	xpath		TEXT	NOT NULL,
+	xpath		TEXT,
 	weight		INT	NOT NULL DEFAULT 1,
 	format		TEXT	NOT NULL REFERENCES config.xml_transform (name) DEFAULT 'mods33',
 	search_field	BOOL	NOT NULL DEFAULT TRUE,
@@ -215,7 +215,7 @@ CREATE TABLE config.metabib_field (
 	authority_xpath TEXT,
 	joiner      TEXT,
 	restrict	BOOL    DEFAULT FALSE NOT NULL,
-    display_field BOOL NOT NULL DEFAULT FALSE
+    display_field BOOL NOT NULL DEFAULT TRUE
 );
 COMMENT ON TABLE config.metabib_field IS $$
 XPath used for record indexing ingest
@@ -226,6 +226,27 @@ a "class" of either title, subject, author, keyword, series
 or identifier.
 $$;
 
+CREATE TABLE config.metabib_field_virtual_map (
+    id      SERIAL  PRIMARY KEY,
+    real    INT NOT NULL REFERENCES config.metabib_field (id),
+    virtual INT NOT NULL REFERENCES config.metabib_field (id),
+    weight  INT NOT NULL DEFAULT 1
+);
+COMMENT ON TABLE config.metabib_field_virtual_map IS $$
+Maps between real (physically extracted) index definitions
+and virtual (target sync, no required extraction of its own)
+index definitions.
+
+The virtual side may not extract any data of its own, but
+will collect data from all of the real fields.  This reduces
+extraction (ingest) overhead by eliminating duplcated extraction,
+and allows for searching across novel combinations of fields, such
+as names used as either subjects or authors.  By preserving this
+mapping rather than defining duplicate extractions, information
+about the originating, "real" index definitions can be used
+in interesting ways, such as highlighting in search results.
+$$;
+
 CREATE UNIQUE INDEX config_metabib_field_class_name_idx ON config.metabib_field (field_class, name);
 
 CREATE TABLE config.display_field_map (
diff --git a/Open-ILS/src/sql/Pg/030.schema.metabib.sql b/Open-ILS/src/sql/Pg/030.schema.metabib.sql
index 499073b..2f37b55 100644
--- a/Open-ILS/src/sql/Pg/030.schema.metabib.sql
+++ b/Open-ILS/src/sql/Pg/030.schema.metabib.sql
@@ -173,6 +173,19 @@ CREATE UNIQUE INDEX metabib_combined_series_field_entry_fakepk_idx ON metabib.co
 CREATE INDEX metabib_combined_series_field_entry_index_vector_idx ON metabib.combined_series_field_entry USING GIST (index_vector);
 CREATE INDEX metabib_combined_series_field_source_idx ON metabib.combined_series_field_entry (metabib_field);
 
+CREATE VIEW metabib.combined_all_field_entry AS
+    SELECT * FROM metabib.combined_title_field_entry
+        UNION ALL
+    SELECT * FROM metabib.combined_author_field_entry
+        UNION ALL
+    SELECT * FROM metabib.combined_subject_field_entry
+        UNION ALL
+    SELECT * FROM metabib.combined_keyword_field_entry
+        UNION ALL
+    SELECT * FROM metabib.combined_identifier_field_entry
+        UNION ALL
+    SELECT * FROM metabib.combined_series_field_entry;
+
 CREATE TABLE metabib.facet_entry (
 	id		BIGSERIAL	PRIMARY KEY,
 	source		BIGINT		NOT NULL,
@@ -230,28 +243,76 @@ CREATE VIEW metabib.compressed_display_entry AS
 CREATE VIEW metabib.wide_display_entry AS
 /* Table-like view of well-known display fields.   
    This VIEW expands as well-known display fields are added. */
-    SELECT 
+    SELECT
         bre.id AS source,
         COALESCE(mcde_title.value, 'null') AS title,
         COALESCE(mcde_author.value, 'null') AS author,
-        COALESCE(mcde_subject.value, 'null') AS subject,
+        COALESCE(mcde_subject_geographic.value, 'null') AS subject_geographic,
+        COALESCE(mcde_subject_name.value, 'null') AS subject_name,
+        COALESCE(mcde_subject_temporal.value, 'null') AS subject_temporal,
+        COALESCE(mcde_subject_topic.value, 'null') AS subject_topic,
         COALESCE(mcde_creators.value, 'null') AS creators,
-        COALESCE(mcde_isbn.value, 'null') AS isbn
-    -- ensure one row per bre regardless of the presence of display entries
-    FROM biblio.record_entry bre 
-    LEFT JOIN metabib.compressed_display_entry mcde_title 
+        COALESCE(mcde_isbn.value, 'null') AS isbn,
+        COALESCE(mcde_issn.value, 'null') AS issn,
+        COALESCE(mcde_upc.value, 'null') AS upc,
+        COALESCE(mcde_tcn.value, 'null') AS tcn,
+        COALESCE(mcde_edition.value, 'null') AS edition,
+        COALESCE(mcde_physical_description.value, 'null') AS physical_description,
+        COALESCE(mcde_publisher.value, 'null') AS publisher,
+        COALESCE(mcde_series_title.value, 'null') AS series_title,
+        COALESCE(mcde_abstract.value, 'null') AS abstract,
+        COALESCE(mcde_toc.value, 'null') AS toc,
+        COALESCE(mcde_pubdate.value, 'null') AS pubdate,
+        COALESCE(mcde_type_of_resource.value, 'null') AS type_of_resource
+    FROM biblio.record_entry bre
+    LEFT JOIN metabib.compressed_display_entry mcde_title
         ON (bre.id = mcde_title.source AND mcde_title.name = 'title')
-    LEFT JOIN metabib.compressed_display_entry mcde_author 
+    LEFT JOIN metabib.compressed_display_entry mcde_author
         ON (bre.id = mcde_author.source AND mcde_author.name = 'author')
-    LEFT JOIN metabib.compressed_display_entry mcde_subject 
+    LEFT JOIN metabib.compressed_display_entry mcde_subject
         ON (bre.id = mcde_subject.source AND mcde_subject.name = 'subject')
-    LEFT JOIN metabib.compressed_display_entry mcde_creators 
+    LEFT JOIN metabib.compressed_display_entry mcde_subject_geographic
+        ON (bre.id = mcde_subject_geographic.source
+            AND mcde_subject_geographic.name = 'subject_geographic')
+    LEFT JOIN metabib.compressed_display_entry mcde_subject_name
+        ON (bre.id = mcde_subject_name.source
+            AND mcde_subject_name.name = 'subject_name')
+    LEFT JOIN metabib.compressed_display_entry mcde_subject_temporal
+        ON (bre.id = mcde_subject_temporal.source
+            AND mcde_subject_temporal.name = 'subject_temporal')
+    LEFT JOIN metabib.compressed_display_entry mcde_subject_topic
+        ON (bre.id = mcde_subject_topic.source
+            AND mcde_subject_topic.name = 'subject_topic')
+    LEFT JOIN metabib.compressed_display_entry mcde_creators
         ON (bre.id = mcde_creators.source AND mcde_creators.name = 'creators')
-    LEFT JOIN metabib.compressed_display_entry mcde_isbn 
+    LEFT JOIN metabib.compressed_display_entry mcde_isbn
         ON (bre.id = mcde_isbn.source AND mcde_isbn.name = 'isbn')
+    LEFT JOIN metabib.compressed_display_entry mcde_issn
+        ON (bre.id = mcde_issn.source AND mcde_issn.name = 'issn')
+    LEFT JOIN metabib.compressed_display_entry mcde_upc
+        ON (bre.id = mcde_upc.source AND mcde_upc.name = 'upc')
+    LEFT JOIN metabib.compressed_display_entry mcde_tcn
+        ON (bre.id = mcde_tcn.source AND mcde_tcn.name = 'tcn')
+    LEFT JOIN metabib.compressed_display_entry mcde_edition
+        ON (bre.id = mcde_edition.source AND mcde_edition.name = 'edition')
+    LEFT JOIN metabib.compressed_display_entry mcde_physical_description
+        ON (bre.id = mcde_physical_description.source
+            AND mcde_physical_description.name = 'physical_description')
+    LEFT JOIN metabib.compressed_display_entry mcde_publisher
+        ON (bre.id = mcde_publisher.source AND mcde_publisher.name = 'publisher')
+    LEFT JOIN metabib.compressed_display_entry mcde_series_title
+        ON (bre.id = mcde_series_title.source AND mcde_series_title.name = 'series_title')
+    LEFT JOIN metabib.compressed_display_entry mcde_abstract
+        ON (bre.id = mcde_abstract.source AND mcde_abstract.name = 'abstract')
+    LEFT JOIN metabib.compressed_display_entry mcde_toc
+        ON (bre.id = mcde_toc.source AND mcde_toc.name = 'toc')
+    LEFT JOIN metabib.compressed_display_entry mcde_pubdate
+        ON (bre.id = mcde_pubdate.source AND mcde_pubdate.name = 'pubdate')
+    LEFT JOIN metabib.compressed_display_entry mcde_type_of_resource
+        ON (bre.id = mcde_type_of_resource.source
+            AND mcde_type_of_resource.name = 'type_of_resource')
 ;
 
-
 CREATE TABLE metabib.browse_entry (
     id BIGSERIAL PRIMARY KEY,
     value TEXT,
@@ -719,13 +780,14 @@ BEGIN
 
     -- Loop over the indexing entries
     FOR idx IN SELECT * FROM config.metabib_field WHERE id = ANY (only_fields) ORDER BY format LOOP
+        CONTINUE WHEN idx.xpath IS NULL OR idx.xpath = ''; -- pure virtual field
 
         process_idx := FALSE;
         IF idx.display_field AND 'display' = ANY (field_types) THEN process_idx = TRUE; END IF;
         IF idx.browse_field AND 'browse' = ANY (field_types) THEN process_idx = TRUE; END IF;
         IF idx.search_field AND 'search' = ANY (field_types) THEN process_idx = TRUE; END IF;
         IF idx.facet_field AND 'facet' = ANY (field_types) THEN process_idx = TRUE; END IF;
-        CONTINUE WHEN process_idx = FALSE;
+        CONTINUE WHEN process_idx = FALSE; -- disabled for all types
 
         joiner := COALESCE(idx.joiner, default_joiner);
 
@@ -884,10 +946,14 @@ BEGIN
     END LOOP;
 
 END;
-
 $func$ LANGUAGE PLPGSQL;
 
 CREATE OR REPLACE FUNCTION metabib.update_combined_index_vectors(bib_id BIGINT) RETURNS VOID AS $func$
+DECLARE
+    rdata       TSVECTOR;
+    vclass      TEXT;
+    vfield      INT;
+    rfields     INT[];
 BEGIN
     DELETE FROM metabib.combined_keyword_field_entry WHERE record = bib_id;
     INSERT INTO metabib.combined_keyword_field_entry(record, metabib_field, index_vector)
@@ -937,6 +1003,32 @@ BEGIN
         SELECT bib_id, NULL, strip(COALESCE(string_agg(index_vector::TEXT,' '),'')::tsvector)
         FROM metabib.identifier_field_entry WHERE source = bib_id;
 
+    -- For each virtual def, gather the data from the combined real field
+    -- entries and append it to the virtual combined entry.
+    FOR vfield, rfields IN SELECT virtual, ARRAY_AGG(real)  FROM config.metabib_field_virtual_map GROUP BY virtual LOOP
+        SELECT  field_class INTO vclass
+          FROM  config.metabib_field
+          WHERE id = vfield;
+
+        SELECT  string_agg(index_vector::TEXT,' ')::tsvector INTO rdata
+          FROM  metabib.combined_all_field_entry
+          WHERE record = bib_id
+                AND metabib_field = ANY (rfields);
+
+        BEGIN -- I cannot wait for INSERT ON CONFLICT ... 9.5, though
+            EXECUTE $$
+                INSERT INTO metabib.combined_$$ || vclass || $$_field_entry
+                    (record, metabib_field, index_vector) VALUES ($1, $2, $3)
+            $$ USING bib_id, vfield, rdata;
+        EXCEPTION WHEN unique_violation THEN
+            EXECUTE $$
+                UPDATE  metabib.combined_$$ || vclass || $$_field_entry
+                  SET   index_vector = index_vector || $3
+                  WHERE record = $1
+                        AND metabib_field = $2
+            $$ USING bib_id, vfield, rdata;
+        END;
+    END LOOP;
 END;
 $func$ LANGUAGE PLPGSQL;
 
@@ -1404,7 +1496,12 @@ BEGIN
 END;
 $func$ LANGUAGE PLPGSQL;
 
-CREATE OR REPLACE FUNCTION metabib.remap_metarecord_for_bib( bib_id BIGINT, fp TEXT, bib_is_deleted BOOL DEFAULT FALSE, retain_deleted BOOL DEFAULT FALSE ) RETURNS BIGINT AS $func$
+CREATE OR REPLACE FUNCTION metabib.remap_metarecord_for_bib(
+    bib_id bigint,
+    fp text,
+    bib_is_deleted boolean DEFAULT false,
+    retain_deleted boolean DEFAULT false
+) RETURNS bigint AS $function$
 DECLARE
     new_mapping     BOOL := TRUE;
     source_count    INT;
@@ -1415,11 +1512,11 @@ BEGIN
 
     -- We need to make sure we're not a deleted master record of an MR
     IF bib_is_deleted THEN
-        FOR old_mr IN SELECT id FROM metabib.metarecord WHERE master_record = bib_id LOOP
+        IF NOT retain_deleted THEN -- Go away for any MR that we're master of, unless retained
+            DELETE FROM metabib.metarecord_source_map WHERE source = bib_id;
+        END IF;
 
-            IF NOT retain_deleted THEN -- Go away for any MR that we're master of, unless retained
-                DELETE FROM metabib.metarecord_source_map WHERE source = bib_id;
-            END IF;
+        FOR old_mr IN SELECT id FROM metabib.metarecord WHERE master_record = bib_id LOOP
 
             -- Now, are there any more sources on this MR?
             SELECT COUNT(*) INTO source_count FROM metabib.metarecord_source_map WHERE metarecord = old_mr;
@@ -1491,8 +1588,7 @@ BEGIN
     RETURN old_mr;
 
 END;
-$func$ LANGUAGE PLPGSQL;
-
+$function$ LANGUAGE plpgsql;
 
 CREATE OR REPLACE FUNCTION biblio.map_authority_linking (bibid BIGINT, marc TEXT) RETURNS BIGINT AS $func$
     DELETE FROM authority.bib_linking WHERE bib = $1;
diff --git a/Open-ILS/src/sql/Pg/300.schema.staged_search.sql b/Open-ILS/src/sql/Pg/300.schema.staged_search.sql
index 820313f..71a2e7d 100644
--- a/Open-ILS/src/sql/Pg/300.schema.staged_search.sql
+++ b/Open-ILS/src/sql/Pg/300.schema.staged_search.sql
@@ -1315,6 +1315,139 @@ BEGIN
 END;
 $p$ LANGUAGE PLPGSQL ROWS 10;
 
+CREATE OR REPLACE VIEW search.best_tsconfig AS
+    SELECT  m.id AS id,
+            COALESCE(f.ts_config, c.ts_config, 'simple') AS ts_config
+      FROM  config.metabib_field m
+            LEFT JOIN config.metabib_class_ts_map c ON (c.field_class = m.field_class AND c.index_weight = 'C')
+            LEFT JOIN config.metabib_field_ts_map f ON (f.metabib_field = m.id AND c.index_weight = 'C');
+
+CREATE TYPE search.highlight_result AS ( id BIGINT, source BIGINT, field INT, value TEXT, highlight TEXT );
+
+CREATE OR REPLACE FUNCTION search.highlight_display_fields(
+    rid         BIGINT,
+    tsq         TEXT,
+    field_list  INT[] DEFAULT '{}'::INT[],
+    css_class   TEXT DEFAULT 'oils_SH',
+    hl_all      BOOL DEFAULT TRUE,
+    minwords    INT DEFAULT 5,
+    maxwords    INT DEFAULT 25,
+    shortwords  INT DEFAULT 0,
+    maxfrags    INT DEFAULT 0,
+    delimiter   TEXT DEFAULT ' ... '
+) RETURNS SETOF search.highlight_result AS $f$
+DECLARE
+    opts            TEXT := '';
+    v_css_class     TEXT := css_class;
+    v_delimiter     TEXT := delimiter;
+    v_field_list    INT[] := field_list;
+    hl_query        TEXT;
+BEGIN
+    IF v_delimiter LIKE $$%'%$$ OR v_delimiter LIKE '%"%' THEN --"
+        v_delimiter := ' ... ';
+    END IF;
+
+    IF NOT hl_all THEN
+        opts := opts || 'MinWords=' || minwords;
+        opts := opts || ', MaxWords=' || maxwords;
+        opts := opts || ', ShortWords=' || shortwords;
+        opts := opts || ', MaxFragments=' || maxfrags;
+        opts := opts || ', FragmentDelimiter="' || delimiter || '"';
+    ELSE
+        opts := opts || 'HighlightAll=TRUE';
+    END IF;
+
+    IF v_css_class LIKE $$%'%$$ OR v_css_class LIKE '%"%' THEN -- "
+        v_css_class := 'oils_SH';
+    END IF;
+
+    opts := opts || $$, StopSel=</b>, StartSel="<b class='$$ || v_css_class; -- "
+
+    IF v_field_list = '{}'::INT[] THEN
+        SELECT ARRAY_AGG(id) INTO v_field_list FROM config.metabib_field WHERE display_field;
+    END IF;
+
+    hl_query := $$
+        SELECT  de.id,
+                de.source,
+                de.field,
+                de.value AS value,
+                ts_headline(
+                    ts_config::REGCONFIG,
+                    evergreen.escape_for_html(de.value),
+                    $$ || quote_literal(tsq) || $$,
+                    $1 || ' ' || mf.field_class || ' ' || mf.name || $xx$'>"$xx$ -- "'
+                ) AS highlight
+          FROM  metabib.display_entry de
+                JOIN config.metabib_field mf ON (mf.id = de.field)
+                JOIN search.best_tsconfig t ON (t.id = de.field)
+          WHERE de.source = $2
+                AND field = ANY ($3)
+          ORDER BY de.id;$$;
+
+    RETURN QUERY EXECUTE hl_query USING opts, rid, v_field_list;
+END;
+$f$ LANGUAGE PLPGSQL;
+
+CREATE OR REPLACE FUNCTION evergreen.escape_for_html (TEXT) RETURNS TEXT AS $$
+    SELECT  regexp_replace(
+                regexp_replace(
+                    regexp_replace(
+                        $1,
+                        '&',
+                        '&',
+                        'g'
+                    ),
+                    '<',
+                    '<',
+                    'g'
+                ),
+                '>',
+                '>',
+                'g'
+            );
+$$ LANGUAGE SQL IMMUTABLE LEAKPROOF STRICT COST 10;
+
+CREATE OR REPLACE FUNCTION search.highlight_display_fields(
+    rid         BIGINT,
+    tsq_map     HSTORE, -- { '(a | b) & c' => '1,2,3,4', ...}
+    css_class   TEXT DEFAULT 'oils_SH',
+    hl_all      BOOL DEFAULT TRUE,
+    minwords    INT DEFAULT 5,
+    maxwords    INT DEFAULT 25,
+    shortwords  INT DEFAULT 0,
+    maxfrags    INT DEFAULT 0,
+    delimiter   TEXT DEFAULT ' ... '
+) RETURNS SETOF search.highlight_result AS $f$
+DECLARE
+    tsq     TEXT;
+    fields  TEXT;
+    afields INT[];
+    seen    INT[];
+BEGIN
+    FOR tsq, fields IN SELECT key, value FROM each(tsq_map) LOOP
+        SELECT  ARRAY_AGG(unnest::INT) INTO afields
+          FROM  unnest(regexp_split_to_array(fields,','));
+        seen := seen || afields;
+
+        RETURN QUERY
+            SELECT * FROM search.highlight_display_fields(
+                rid, tsq, afields, css_class, hl_all,minwords,
+                maxwords, shortwords, maxfrags, delimiter
+            );
+    END LOOP;
+
+    RETURN QUERY
+        SELECT  id,
+                source,
+                field,
+                value,
+                value AS highlight
+          FROM  metabib.display_entry
+          WHERE source = rid
+                AND NOT (field = ANY (seen));
+END;
+$f$ LANGUAGE PLPGSQL ROWS 10;
 
 COMMIT;
 
diff --git a/Open-ILS/src/sql/Pg/950.data.seed-values.sql b/Open-ILS/src/sql/Pg/950.data.seed-values.sql
index 5a2b0ff..94ea030 100644
--- a/Open-ILS/src/sql/Pg/950.data.seed-values.sql
+++ b/Open-ILS/src/sql/Pg/950.data.seed-values.sql
@@ -150,7 +150,7 @@ INSERT INTO config.metabib_field ( id, field_class, name, label, format, xpath,
 INSERT INTO config.metabib_field ( id, field_class, name, label, format, xpath, browse_field, display_field ) VALUES 
     (15, 'keyword', 'keyword', oils_i18n_gettext(15, 'General Keywords', 'cmf', 'label'), 'mods32', $$//mods32:mods/*[not(local-name()='originInfo')]$$, FALSE, FALSE ); -- /* to fool vim */;
 INSERT INTO config.metabib_field ( id, field_class, name, label, format, xpath, browse_field, display_field ) VALUES
-    (16, 'subject', 'complete', oils_i18n_gettext(16, 'All Subjects', 'cmf', 'label'), 'mods32', $$//mods32:mods/mods32:subject$$, FALSE, TRUE );
+    (16, 'subject', 'complete', oils_i18n_gettext(16, 'All Subjects', 'cmf', 'label'), 'mods32', $$//mods32:mods/mods32:subject[not(descendant::mods32:geographicCode)]$$, FALSE, TRUE );
 
 INSERT INTO config.metabib_field ( id, field_class, name, label, format, xpath, browse_field ) VALUES
     (17, 'identifier', 'accession', oils_i18n_gettext(17, 'Accession Number', 'cmf', 'label'), 'marcxml', $$//marc:controlfield[@tag='001']$$, FALSE );
@@ -187,6 +187,7 @@ INSERT INTO config.metabib_field ( id, field_class, name, label, format, xpath,
 
 INSERT INTO config.metabib_field ( id, field_class, name, label, format, xpath, browse_field, facet_field, facet_xpath, joiner ) VALUES
     (33, 'identifier', 'genre', oils_i18n_gettext(33, 'Genre', 'cmf', 'label'), 'marcxml', $$//marc:datafield[@tag='655']$$, FALSE, TRUE, $$//*[local-name()='subfield' and contains('abvxyz', at code)]$$, ' -- ' ); -- /* to fool vim */;
+UPDATE config.metabib_field SET display_xpath = facet_xpath, display_field = TRUE WHERE id = 33;
 
 UPDATE config.metabib_field SET joiner = ' -- ' WHERE field_class = 'subject' AND name NOT IN ('name');
 
@@ -210,6 +211,122 @@ INSERT INTO config.metabib_field ( id, field_class, name, label,
     (37, 'author', 'creator', oils_i18n_gettext(37, 'All Creators', 'cmf', 'label'),
      'mods32', $$//mods32:mods/mods32:name[mods32:role/mods32:roleTerm[text()='creator']]$$, TRUE, $$//*[local-name()='namePart']$$ ); -- /* to fool vim */;
 
+INSERT INTO config.metabib_field (id, field_class, name,
+    label, xpath, display_field, search_field, browse_field)
+VALUES (
+    38, 'keyword', 'edition',
+    oils_i18n_gettext(38, 'Edition', 'cmf', 'label'),
+    $$//mods33:mods/mods33:originInfo//mods33:edition[1]$$,
+    TRUE, TRUE, FALSE
+);
+
+INSERT INTO config.metabib_field (id, field_class, name,
+    label, xpath, display_field, search_field, browse_field)
+VALUES (
+    39, 'keyword', 'physical_description',
+    oils_i18n_gettext(39, 'Physical Descrption', 'cmf', 'label'),
+    $$(//mods33:mods/mods33:physicalDescription/mods33:form|//mods33:mods/mods33:physicalDescription/mods33:extent|//mods33:mods/mods33:physicalDescription/mods33:reformattingQuality|//mods33:mods/mods33:physicalDescription/mods33:internetMediaType|//mods33:mods/mods33:physicalDescription/mods33:digitalOrigin)$$,
+    TRUE, TRUE, FALSE
+);
+
+INSERT INTO config.metabib_field (id, field_class, name,
+    label, xpath, display_field, search_field, browse_field)
+VALUES (
+    40, 'keyword', 'publisher',
+    oils_i18n_gettext(40, 'Publisher', 'cmf', 'label'),
+    $$//mods33:mods/mods33:originInfo//mods33:publisher[1]$$,
+    TRUE, TRUE, FALSE
+);
+
+INSERT INTO config.metabib_field (id, field_class, name,
+    label, xpath, display_field, search_field, browse_field)
+VALUES (
+    41, 'keyword', 'abstract',
+    oils_i18n_gettext(41, 'Abstract', 'cmf', 'label'),
+    $$//mods33:mods/mods33:abstract$$,
+    TRUE, TRUE, FALSE
+);
+
+INSERT INTO config.metabib_field (id, field_class, name,
+    label, xpath, display_field, search_field, browse_field)
+VALUES (
+    42, 'keyword', 'toc',
+    oils_i18n_gettext(42, 'Table of Contents', 'cmf', 'label'),
+    $$//mods33:tableOfContents$$,
+    TRUE, TRUE, FALSE
+);
+
+INSERT INTO config.metabib_field (id, field_class, name,
+    label, xpath, display_field, search_field, browse_field)
+VALUES (
+    43, 'identifier', 'type_of_resource',
+    oils_i18n_gettext(43, 'Type of Resource', 'cmf', 'label'),
+    $$//mods33:mods/mods33:typeOfResource$$,
+    TRUE, FALSE, FALSE
+);
+
+INSERT INTO config.metabib_field (id, field_class, name,
+    label, xpath, display_field, search_field, browse_field)
+VALUES (
+    44, 'identifier', 'pubdate',
+    oils_i18n_gettext(44, 'Publication Date', 'cmf', 'label'),
+    $$//mods33:mods/mods33:originInfo//mods33:dateIssued[@encoding="marc"]|//mods33:mods/mods33:originInfo//mods33:dateIssued[1]$$,
+    TRUE, FALSE, FALSE
+);
+
+INSERT INTO config.metabib_field (id, field_class, name, label, browse_field)
+    VALUES (45, 'keyword', 'blob', oils_i18n_gettext(45, 'All searchable fields', 'cmf', 'label'), FALSE);
+
+INSERT INTO config.metabib_field (id, field_class, name,
+    label, xpath, display_field, search_field, browse_field)
+VALUES (
+    46, 'keyword', 'bibliography',
+    oils_i18n_gettext(46, 'Bibliography', 'cmf', 'label'),
+    $$//mods33:note[@type='bibliography']$$,
+    TRUE, TRUE, FALSE
+),(
+    47, 'keyword', 'thesis',
+    oils_i18n_gettext(47, 'Thesis', 'cmf', 'label'),
+    $$//mods33:note[@type='thesis']$$,
+    TRUE, TRUE, FALSE
+),(
+    48, 'keyword', 'production_credits',
+    oils_i18n_gettext(48, 'Creation/Production Credits', 'cmf', 'label'),
+    $$//mods33:note[@type='creation/production credits']$$,
+    TRUE, TRUE, FALSE
+),(
+    49, 'keyword', 'performers',
+    oils_i18n_gettext(49, 'Performers', 'cmf', 'label'),
+    $$//mods33:note[@type='performers']$$,
+    TRUE, TRUE, FALSE
+),(
+    50, 'keyword', 'general_note',
+    oils_i18n_gettext(50, 'General Note', 'cmf', 'label'),
+    $$//mods33:note[not(@type)]$$,
+    TRUE, TRUE, FALSE
+)
+;
+
+INSERT INTO config.metabib_field_virtual_map (real, virtual)
+    SELECT  id,
+            45
+      FROM  config.metabib_field
+      WHERE search_field
+            AND id NOT IN (15, 45)
+            AND id NOT IN (SELECT real FROM config.metabib_field_virtual_map);
+
+-- Modify existing config.metabib_field entries
+
+UPDATE config.metabib_field SET display_field = TRUE WHERE id IN (
+    1,  -- seriestitle
+    11, -- subject_geographic
+    12, -- subject_name
+    13, -- subject_temporal
+    14, -- subject_topic
+    19, -- ISSN
+    20, -- UPC
+    26  -- TCN
+);
 
 INSERT INTO config.metabib_field_index_norm_map (field,norm)
     SELECT  m.id,
@@ -226,7 +343,22 @@ INSERT INTO config.display_field_map (name, field, multi) VALUES
     ('author', 8, FALSE),
     ('creators', 37, TRUE),
     ('subject', 16, TRUE),
-    ('isbn', 18, TRUE)
+    ('isbn', 18, TRUE),
+    ('series_title',         1, FALSE),
+    ('subject_geographic',  11, TRUE),
+    ('subject_name',        12, TRUE),
+    ('subject_temporal',    13, TRUE),
+    ('subject_topic',       14, TRUE),
+    ('issn',                19, TRUE),
+    ('upc',                 20, TRUE),
+    ('tcn',                 26, FALSE),
+    ('edition',             38, FALSE),
+    ('physical_description',39, TRUE),
+    ('publisher',           40, FALSE),
+    ('abstract',            41, FALSE),
+    ('toc',                 42, FALSE),
+    ('type_of_resource',    43, FALSE),
+    ('pubdate',             44, FALSE)
 ;
 
 INSERT INTO config.metabib_search_alias (alias,field_class) VALUES ('kw','keyword');
diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.data.display-field-seed-data.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.data.display-field-seed-data.sql
index ea55482..6b1788b 100644
--- a/Open-ILS/src/sql/Pg/upgrade/XXXX.data.display-field-seed-data.sql
+++ b/Open-ILS/src/sql/Pg/upgrade/XXXX.data.display-field-seed-data.sql
@@ -7,46 +7,46 @@ BEGIN;
 INSERT INTO config.metabib_field (id, field_class, name, 
     label, xpath, display_field, search_field, browse_field)
 VALUES (
-    38, 'identifier', 'edition', 
+    38, 'keyword', 'edition', 
     oils_i18n_gettext(38, 'Edition', 'cmf', 'label'),
     $$//mods33:mods/mods33:originInfo//mods33:edition[1]$$,
-    TRUE, FALSE, FALSE
+    TRUE, TRUE, FALSE
 );
 
 INSERT INTO config.metabib_field (id, field_class, name, 
     label, xpath, display_field, search_field, browse_field)
 VALUES (
-    39, 'identifier', 'physical_description', 
+    39, 'keyword', 'physical_description', 
     oils_i18n_gettext(39, 'Physical Descrption', 'cmf', 'label'),
     $$(//mods33:mods/mods33:physicalDescription/mods33:form|//mods33:mods/mods33:physicalDescription/mods33:extent|//mods33:mods/mods33:physicalDescription/mods33:reformattingQuality|//mods33:mods/mods33:physicalDescription/mods33:internetMediaType|//mods33:mods/mods33:physicalDescription/mods33:digitalOrigin)$$,
-    TRUE, FALSE, FALSE
+    TRUE, TRUE, FALSE
 );
 
 INSERT INTO config.metabib_field (id, field_class, name, 
     label, xpath, display_field, search_field, browse_field)
 VALUES (
-    40, 'identifier', 'publisher', 
+    40, 'keyword', 'publisher', 
     oils_i18n_gettext(40, 'Publisher', 'cmf', 'label'),
     $$//mods33:mods/mods33:originInfo//mods33:publisher[1]$$,
-    TRUE, FALSE, FALSE
+    TRUE, TRUE, FALSE
 );
 
 INSERT INTO config.metabib_field (id, field_class, name, 
     label, xpath, display_field, search_field, browse_field)
 VALUES (
-    41, 'identifier', 'abstract', 
+    41, 'keyword', 'abstract', 
     oils_i18n_gettext(41, 'Abstract', 'cmf', 'label'),
     $$//mods33:mods/mods33:abstract$$,
-    TRUE, FALSE, FALSE
+    TRUE, TRUE, FALSE
 );
 
 INSERT INTO config.metabib_field (id, field_class, name, 
     label, xpath, display_field, search_field, browse_field)
 VALUES (
-    42, 'identifier', 'toc', 
+    42, 'keyword', 'toc', 
     oils_i18n_gettext(42, 'Table of Contents', 'cmf', 'label'),
     $$//mods33:tableOfContents$$,
-    TRUE, FALSE, FALSE
+    TRUE, TRUE, FALSE
 );
 
 INSERT INTO config.metabib_field (id, field_class, name, 
@@ -177,34 +177,3 @@ CREATE VIEW metabib.wide_display_entry AS
 
 COMMIT;
 
-/** ROLLBACK 
-
-BEGIN;
-DELETE FROM metabib.display_entry WHERE field IN (1,11,12,13,14,19,20,26,38,39,40,41,42,43,44);
-DELETE FROM config.display_field_map WHERE field IN (1,11,12,13,14,19,20,26,38,39,40,41,42,43,44);
-DELETE FROM config.metabib_field WHERE id IN (38,39,40,41,42,43,44);
-COMMIT;
-
-*/
-
--- Perform a full display field reingest, since we didn't do one during
--- the 3.0 upgrade when display fields were introduced.
-
-\qecho
-\qecho Reingesting display field entries.  This may take a while.
-\qecho This command can be stopped (control-c) and rerun later if needed:
-\qecho
-\qecho SELECT metabib.reingest_metabib_field_entries(id, TRUE, FALSE, TRUE, TRUE,     
-\qecho     (SELECT ARRAY_AGG(id)::INT[] FROM config.metabib_field WHERE display_field)) 
-\qecho     FROM biblio.record_entry WHERE id > 0; 
-\qecho
-
--- avoid displaying a row per entry by selecting the total count.
--- NOTE: extracting display data for deleted bibs because we occasionally
--- display deleted bib records.
-SELECT COUNT(*) AS bib_count FROM (
-  SELECT metabib.reingest_metabib_field_entries(id, TRUE, FALSE, TRUE, TRUE,     
-    (SELECT ARRAY_AGG(id)::INT[] FROM config.metabib_field WHERE display_field)) 
-  FROM biblio.record_entry WHERE id > 0
-) x;
-
diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.highlight_search.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.highlight_search.sql
new file mode 100644
index 0000000..2fc357b
--- /dev/null
+++ b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.highlight_search.sql
@@ -0,0 +1,559 @@
+BEGIN;
+
+ALTER TABLE config.metabib_field ALTER COLUMN xpath DROP NOT NULL;
+
+CREATE TABLE config.metabib_field_virtual_map (
+    id      SERIAL  PRIMARY KEY,
+    real    INT NOT NULL REFERENCES config.metabib_field (id),
+    virtual INT NOT NULL REFERENCES config.metabib_field (id),
+    weight  INT NOT NULL DEFAULT 1
+);
+COMMENT ON TABLE config.metabib_field_virtual_map IS $$
+Maps between real (physically extracted) index definitions
+and virtual (target sync, no required extraction of its own)
+index definitions.
+
+The virtual side may not extract any data of its own, but
+will collect data from all of the real fields.  This reduces
+extraction (ingest) overhead by eliminating duplcated extraction,
+and allows for searching across novel combinations of fields, such
+as names used as either subjects or authors.  By preserving this
+mapping rather than defining duplicate extractions, information
+about the originating, "real" index definitions can be used
+in interesting ways, such as highlighting in search results.
+$$;
+
+CREATE OR REPLACE VIEW metabib.combined_all_field_entry AS
+    SELECT * FROM metabib.combined_title_field_entry
+        UNION ALL
+    SELECT * FROM metabib.combined_author_field_entry
+        UNION ALL
+    SELECT * FROM metabib.combined_subject_field_entry
+        UNION ALL
+    SELECT * FROM metabib.combined_keyword_field_entry
+        UNION ALL
+    SELECT * FROM metabib.combined_identifier_field_entry
+        UNION ALL
+    SELECT * FROM metabib.combined_series_field_entry;
+
+
+CREATE OR REPLACE FUNCTION biblio.extract_metabib_field_entry (
+    rid BIGINT,
+    default_joiner TEXT,
+    field_types TEXT[],
+    only_fields INT[]
+) RETURNS SETOF metabib.field_entry_template AS $func$
+DECLARE
+    bib     biblio.record_entry%ROWTYPE;
+    idx     config.metabib_field%ROWTYPE;
+    xfrm        config.xml_transform%ROWTYPE;
+    prev_xfrm   TEXT;
+    transformed_xml TEXT;
+    xml_node    TEXT;
+    xml_node_list   TEXT[];
+    facet_text  TEXT;
+    display_text TEXT;
+    browse_text TEXT;
+    sort_value  TEXT;
+    raw_text    TEXT;
+    curr_text   TEXT;
+    joiner      TEXT := default_joiner; -- XXX will index defs supply a joiner?
+    authority_text TEXT;
+    authority_link BIGINT;
+    output_row  metabib.field_entry_template%ROWTYPE;
+    process_idx BOOL;
+BEGIN
+
+    -- Start out with no field-use bools set
+    output_row.browse_field = FALSE;
+    output_row.facet_field = FALSE;
+    output_row.display_field = FALSE;
+    output_row.search_field = FALSE;
+
+    -- Get the record
+    SELECT INTO bib * FROM biblio.record_entry WHERE id = rid;
+
+    -- Loop over the indexing entries
+    FOR idx IN SELECT * FROM config.metabib_field WHERE id = ANY (only_fields) ORDER BY format LOOP
+        CONTINUE WHEN idx.xpath IS NULL OR idx.xpath = ''; -- pure virtual field
+
+        process_idx := FALSE;
+        IF idx.display_field AND 'display' = ANY (field_types) THEN process_idx = TRUE; END IF;
+        IF idx.browse_field AND 'browse' = ANY (field_types) THEN process_idx = TRUE; END IF;
+        IF idx.search_field AND 'search' = ANY (field_types) THEN process_idx = TRUE; END IF;
+        IF idx.facet_field AND 'facet' = ANY (field_types) THEN process_idx = TRUE; END IF;
+        CONTINUE WHEN process_idx = FALSE; -- disabled for all types
+
+        joiner := COALESCE(idx.joiner, default_joiner);
+
+        SELECT INTO xfrm * from config.xml_transform WHERE name = idx.format;
+
+        -- See if we can skip the XSLT ... it's expensive
+        IF prev_xfrm IS NULL OR prev_xfrm <> xfrm.name THEN
+            -- Can't skip the transform
+            IF xfrm.xslt <> '---' THEN
+                transformed_xml := oils_xslt_process(bib.marc,xfrm.xslt);
+            ELSE
+                transformed_xml := bib.marc;
+            END IF;
+
+            prev_xfrm := xfrm.name;
+        END IF;
+
+        xml_node_list := oils_xpath( idx.xpath, transformed_xml, ARRAY[ARRAY[xfrm.prefix, xfrm.namespace_uri]] );
+
+        raw_text := NULL;
+        FOR xml_node IN SELECT x FROM unnest(xml_node_list) AS x LOOP
+            CONTINUE WHEN xml_node !~ E'^\\s*<';
+
+            -- XXX much of this should be moved into oils_xpath_string...
+            curr_text := ARRAY_TO_STRING(evergreen.array_remove_item_by_value(evergreen.array_remove_item_by_value(
+                oils_xpath( '//text()', -- get the content of all the nodes within the main selected node
+                    REGEXP_REPLACE( xml_node, E'\\s+', ' ', 'g' ) -- Translate adjacent whitespace to a single space
+                ), ' '), ''),  -- throw away morally empty (bankrupt?) strings
+                joiner
+            );
+
+            CONTINUE WHEN curr_text IS NULL OR curr_text = '';
+
+            IF raw_text IS NOT NULL THEN
+                raw_text := raw_text || joiner;
+            END IF;
+
+            raw_text := COALESCE(raw_text,'') || curr_text;
+
+            -- autosuggest/metabib.browse_entry
+            IF idx.browse_field THEN
+
+                IF idx.browse_xpath IS NOT NULL AND idx.browse_xpath <> '' THEN
+                    browse_text := oils_xpath_string( idx.browse_xpath, xml_node, joiner, ARRAY[ARRAY[xfrm.prefix, xfrm.namespace_uri]] );
+                ELSE
+                    browse_text := curr_text;
+                END IF;
+
+                IF idx.browse_sort_xpath IS NOT NULL AND
+                    idx.browse_sort_xpath <> '' THEN
+
+                    sort_value := oils_xpath_string(
+                        idx.browse_sort_xpath, xml_node, joiner,
+                        ARRAY[ARRAY[xfrm.prefix, xfrm.namespace_uri]]
+                    );
+                ELSE
+                    sort_value := browse_text;
+                END IF;
+
+                output_row.field_class = idx.field_class;
+                output_row.field = idx.id;
+                output_row.source = rid;
+                output_row.value = BTRIM(REGEXP_REPLACE(browse_text, E'\\s+', ' ', 'g'));
+                output_row.sort_value :=
+                    public.naco_normalize(sort_value);
+
+                output_row.authority := NULL;
+
+                IF idx.authority_xpath IS NOT NULL AND idx.authority_xpath <> '' THEN
+                    authority_text := oils_xpath_string(
+                        idx.authority_xpath, xml_node, joiner,
+                        ARRAY[
+                            ARRAY[xfrm.prefix, xfrm.namespace_uri],
+                            ARRAY['xlink','http://www.w3.org/1999/xlink']
+                        ]
+                    );
+
+                    IF authority_text ~ '^\d+$' THEN
+                        authority_link := authority_text::BIGINT;
+                        PERFORM * FROM authority.record_entry WHERE id = authority_link;
+                        IF FOUND THEN
+                            output_row.authority := authority_link;
+                        END IF;
+                    END IF;
+
+                END IF;
+
+                output_row.browse_field = TRUE;
+                -- Returning browse rows with search_field = true for search+browse
+                -- configs allows us to retain granularity of being able to search
+                -- browse fields with "starts with" type operators (for example, for
+                -- titles of songs in music albums)
+                IF idx.search_field THEN
+                    output_row.search_field = TRUE;
+                END IF;
+                RETURN NEXT output_row;
+                output_row.browse_field = FALSE;
+                output_row.search_field = FALSE;
+                output_row.sort_value := NULL;
+            END IF;
+
+            -- insert raw node text for faceting
+            IF idx.facet_field THEN
+
+                IF idx.facet_xpath IS NOT NULL AND idx.facet_xpath <> '' THEN
+                    facet_text := oils_xpath_string( idx.facet_xpath, xml_node, joiner, ARRAY[ARRAY[xfrm.prefix, xfrm.namespace_uri]] );
+                ELSE
+                    facet_text := curr_text;
+                END IF;
+
+                output_row.field_class = idx.field_class;
+                output_row.field = -1 * idx.id;
+                output_row.source = rid;
+                output_row.value = BTRIM(REGEXP_REPLACE(facet_text, E'\\s+', ' ', 'g'));
+
+                output_row.facet_field = TRUE;
+                RETURN NEXT output_row;
+                output_row.facet_field = FALSE;
+            END IF;
+
+            -- insert raw node text for display
+            IF idx.display_field THEN
+
+                IF idx.display_xpath IS NOT NULL AND idx.display_xpath <> '' THEN
+                    display_text := oils_xpath_string( idx.display_xpath, xml_node, joiner, ARRAY[ARRAY[xfrm.prefix, xfrm.namespace_uri]] );
+                ELSE
+                    display_text := curr_text;
+                END IF;
+
+                output_row.field_class = idx.field_class;
+                output_row.field = -1 * idx.id;
+                output_row.source = rid;
+                output_row.value = BTRIM(REGEXP_REPLACE(display_text, E'\\s+', ' ', 'g'));
+
+                output_row.display_field = TRUE;
+                RETURN NEXT output_row;
+                output_row.display_field = FALSE;
+            END IF;
+
+        END LOOP;
+
+        CONTINUE WHEN raw_text IS NULL OR raw_text = '';
+
+        -- insert combined node text for searching
+        IF idx.search_field THEN
+            output_row.field_class = idx.field_class;
+            output_row.field = idx.id;
+            output_row.source = rid;
+            output_row.value = BTRIM(REGEXP_REPLACE(raw_text, E'\\s+', ' ', 'g'));
+
+            output_row.search_field = TRUE;
+            RETURN NEXT output_row;
+            output_row.search_field = FALSE;
+        END IF;
+
+    END LOOP;
+
+END;
+$func$ LANGUAGE PLPGSQL;
+
+CREATE OR REPLACE FUNCTION metabib.update_combined_index_vectors(bib_id BIGINT) RETURNS VOID AS $func$
+DECLARE
+    rdata       TSVECTOR;
+    vclass      TEXT;
+    vfield      INT;
+    rfields     INT[];
+BEGIN
+    DELETE FROM metabib.combined_keyword_field_entry WHERE record = bib_id;
+    INSERT INTO metabib.combined_keyword_field_entry(record, metabib_field, index_vector)
+        SELECT bib_id, field, strip(COALESCE(string_agg(index_vector::TEXT,' '),'')::tsvector)
+        FROM metabib.keyword_field_entry WHERE source = bib_id GROUP BY field;
+    INSERT INTO metabib.combined_keyword_field_entry(record, metabib_field, index_vector)
+        SELECT bib_id, NULL, strip(COALESCE(string_agg(index_vector::TEXT,' '),'')::tsvector)
+        FROM metabib.keyword_field_entry WHERE source = bib_id;
+
+    DELETE FROM metabib.combined_title_field_entry WHERE record = bib_id;
+    INSERT INTO metabib.combined_title_field_entry(record, metabib_field, index_vector)
+        SELECT bib_id, field, strip(COALESCE(string_agg(index_vector::TEXT,' '),'')::tsvector)
+        FROM metabib.title_field_entry WHERE source = bib_id GROUP BY field;
+    INSERT INTO metabib.combined_title_field_entry(record, metabib_field, index_vector)
+        SELECT bib_id, NULL, strip(COALESCE(string_agg(index_vector::TEXT,' '),'')::tsvector)
+        FROM metabib.title_field_entry WHERE source = bib_id;
+
+    DELETE FROM metabib.combined_author_field_entry WHERE record = bib_id;
+    INSERT INTO metabib.combined_author_field_entry(record, metabib_field, index_vector)
+        SELECT bib_id, field, strip(COALESCE(string_agg(index_vector::TEXT,' '),'')::tsvector)
+        FROM metabib.author_field_entry WHERE source = bib_id GROUP BY field;
+    INSERT INTO metabib.combined_author_field_entry(record, metabib_field, index_vector)
+        SELECT bib_id, NULL, strip(COALESCE(string_agg(index_vector::TEXT,' '),'')::tsvector)
+        FROM metabib.author_field_entry WHERE source = bib_id;
+
+    DELETE FROM metabib.combined_subject_field_entry WHERE record = bib_id;
+    INSERT INTO metabib.combined_subject_field_entry(record, metabib_field, index_vector)
+        SELECT bib_id, field, strip(COALESCE(string_agg(index_vector::TEXT,' '),'')::tsvector)
+        FROM metabib.subject_field_entry WHERE source = bib_id GROUP BY field;
+    INSERT INTO metabib.combined_subject_field_entry(record, metabib_field, index_vector)
+        SELECT bib_id, NULL, strip(COALESCE(string_agg(index_vector::TEXT,' '),'')::tsvector)
+        FROM metabib.subject_field_entry WHERE source = bib_id;
+
+    DELETE FROM metabib.combined_series_field_entry WHERE record = bib_id;
+    INSERT INTO metabib.combined_series_field_entry(record, metabib_field, index_vector)
+        SELECT bib_id, field, strip(COALESCE(string_agg(index_vector::TEXT,' '),'')::tsvector)
+        FROM metabib.series_field_entry WHERE source = bib_id GROUP BY field;
+    INSERT INTO metabib.combined_series_field_entry(record, metabib_field, index_vector)
+        SELECT bib_id, NULL, strip(COALESCE(string_agg(index_vector::TEXT,' '),'')::tsvector)
+        FROM metabib.series_field_entry WHERE source = bib_id;
+
+    DELETE FROM metabib.combined_identifier_field_entry WHERE record = bib_id;
+    INSERT INTO metabib.combined_identifier_field_entry(record, metabib_field, index_vector)
+        SELECT bib_id, field, strip(COALESCE(string_agg(index_vector::TEXT,' '),'')::tsvector)
+        FROM metabib.identifier_field_entry WHERE source = bib_id GROUP BY field;
+    INSERT INTO metabib.combined_identifier_field_entry(record, metabib_field, index_vector)
+        SELECT bib_id, NULL, strip(COALESCE(string_agg(index_vector::TEXT,' '),'')::tsvector)
+        FROM metabib.identifier_field_entry WHERE source = bib_id;
+
+    -- For each virtual def, gather the data from the combined real field
+    -- entries and append it to the virtual combined entry.
+    FOR vfield, rfields IN SELECT virtual, ARRAY_AGG(real)  FROM config.metabib_field_virtual_map GROUP BY virtual LOOP
+        SELECT  field_class INTO vclass
+          FROM  config.metabib_field
+          WHERE id = vfield;
+
+        SELECT  string_agg(index_vector::TEXT,' ')::tsvector INTO rdata
+          FROM  metabib.combined_all_field_entry
+          WHERE record = bib_id
+                AND metabib_field = ANY (rfields);
+
+        BEGIN -- I cannot wait for INSERT ON CONFLICT ... 9.5, though
+            EXECUTE $$
+                INSERT INTO metabib.combined_$$ || vclass || $$_field_entry
+                    (record, metabib_field, index_vector) VALUES ($1, $2, $3)
+            $$ USING bib_id, vfield, rdata;
+        EXCEPTION WHEN unique_violation THEN
+            EXECUTE $$
+                UPDATE  metabib.combined_$$ || vclass || $$_field_entry
+                  SET   index_vector = index_vector || $3
+                  WHERE record = $1
+                        AND metabib_field = $2
+            $$ USING bib_id, vfield, rdata;
+        END;
+    END LOOP;
+END;
+$func$ LANGUAGE PLPGSQL;
+
+CREATE OR REPLACE VIEW search.best_tsconfig AS
+    SELECT  m.id AS id,
+            COALESCE(f.ts_config, c.ts_config, 'simple') AS ts_config
+      FROM  config.metabib_field m
+            LEFT JOIN config.metabib_class_ts_map c ON (c.field_class = m.field_class AND c.index_weight = 'C')
+            LEFT JOIN config.metabib_field_ts_map f ON (f.metabib_field = m.id AND c.index_weight = 'C');
+
+CREATE TYPE search.highlight_result AS ( id BIGINT, source BIGINT, field INT, value TEXT, highlight TEXT );
+
+CREATE OR REPLACE FUNCTION search.highlight_display_fields(
+    rid         BIGINT,
+    tsq         TEXT,
+    field_list  INT[] DEFAULT '{}'::INT[],
+    css_class   TEXT DEFAULT 'oils_SH',
+    hl_all      BOOL DEFAULT TRUE,
+    minwords    INT DEFAULT 5,
+    maxwords    INT DEFAULT 25,
+    shortwords  INT DEFAULT 0,
+    maxfrags    INT DEFAULT 0,
+    delimiter   TEXT DEFAULT ' ... '
+) RETURNS SETOF search.highlight_result AS $f$
+DECLARE
+    opts            TEXT := '';
+    v_css_class     TEXT := css_class;
+    v_delimiter     TEXT := delimiter;
+    v_field_list    INT[] := field_list;
+    hl_query        TEXT;
+BEGIN
+    IF v_delimiter LIKE $$%'%$$ OR v_delimiter LIKE '%"%' THEN --"
+        v_delimiter := ' ... ';
+    END IF;
+
+    IF NOT hl_all THEN
+        opts := opts || 'MinWords=' || minwords;
+        opts := opts || ', MaxWords=' || maxwords;
+        opts := opts || ', ShortWords=' || shortwords;
+        opts := opts || ', MaxFragments=' || maxfrags;
+        opts := opts || ', FragmentDelimiter="' || delimiter || '"';
+    ELSE
+        opts := opts || 'HighlightAll=TRUE';
+    END IF;
+
+    IF v_css_class LIKE $$%'%$$ OR v_css_class LIKE '%"%' THEN -- "
+        v_css_class := 'oils_SH';
+    END IF;
+
+    opts := opts || $$, StopSel=</b>, StartSel="<b class='$$ || v_css_class; -- "
+
+    IF v_field_list = '{}'::INT[] THEN
+        SELECT ARRAY_AGG(id) INTO v_field_list FROM config.metabib_field WHERE display_field;
+    END IF;
+
+    hl_query := $$
+        SELECT  de.id,
+                de.source,
+                de.field,
+                de.value AS value,
+                ts_headline(
+                    ts_config::REGCONFIG,
+                    evergreen.escape_for_html(de.value),
+                    $$ || quote_literal(tsq) || $$,
+                    $1 || ' ' || mf.field_class || ' ' || mf.name || $xx$'>"$xx$ -- "'
+                ) AS highlight
+          FROM  metabib.display_entry de
+                JOIN config.metabib_field mf ON (mf.id = de.field)
+                JOIN search.best_tsconfig t ON (t.id = de.field)
+          WHERE de.source = $2
+                AND field = ANY ($3)
+          ORDER BY de.id;$$;
+
+    RETURN QUERY EXECUTE hl_query USING opts, rid, v_field_list;
+END;
+$f$ LANGUAGE PLPGSQL;
+
+CREATE OR REPLACE FUNCTION evergreen.escape_for_html (TEXT) RETURNS TEXT AS $$
+    SELECT  regexp_replace(
+                regexp_replace(
+                    regexp_replace(
+                        $1,
+                        '&',
+                        '&',
+                        'g'
+                    ),
+                    '<',
+                    '<',
+                    'g'
+                ),
+                '>',
+                '>',
+                'g'
+            );
+$$ LANGUAGE SQL IMMUTABLE LEAKPROOF STRICT COST 10;
+
+CREATE OR REPLACE FUNCTION search.highlight_display_fields(
+    rid         BIGINT,
+    tsq_map     HSTORE, -- { '(a | b) & c' => '1,2,3,4', ...}
+    css_class   TEXT DEFAULT 'oils_SH',
+    hl_all      BOOL DEFAULT TRUE,
+    minwords    INT DEFAULT 5,
+    maxwords    INT DEFAULT 25,
+    shortwords  INT DEFAULT 0,
+    maxfrags    INT DEFAULT 0,
+    delimiter   TEXT DEFAULT ' ... '
+) RETURNS SETOF search.highlight_result AS $f$
+DECLARE
+    tsq     TEXT;
+    fields  TEXT;
+    afields INT[];
+    seen    INT[];
+BEGIN
+    FOR tsq, fields IN SELECT key, value FROM each(tsq_map) LOOP
+        SELECT  ARRAY_AGG(unnest::INT) INTO afields
+          FROM  unnest(regexp_split_to_array(fields,','));
+        seen := seen || afields;
+
+        RETURN QUERY
+            SELECT * FROM search.highlight_display_fields(
+                rid, tsq, afields, css_class, hl_all,minwords,
+                maxwords, shortwords, maxfrags, delimiter
+            );
+    END LOOP;
+
+    RETURN QUERY
+        SELECT  id,
+                source,
+                field,
+                value,
+                value AS highlight
+          FROM  metabib.display_entry
+          WHERE source = rid
+                AND NOT (field = ANY (seen));
+END;
+$f$ LANGUAGE PLPGSQL ROWS 10;
+ 
+CREATE OR REPLACE FUNCTION metabib.remap_metarecord_for_bib(
+    bib_id bigint,
+    fp text,
+    bib_is_deleted boolean DEFAULT false,
+    retain_deleted boolean DEFAULT false
+) RETURNS bigint AS $function$
+DECLARE
+    new_mapping     BOOL := TRUE;
+    source_count    INT;
+    old_mr          BIGINT;
+    tmp_mr          metabib.metarecord%ROWTYPE;
+    deleted_mrs     BIGINT[];
+BEGIN
+
+    -- We need to make sure we're not a deleted master record of an MR
+    IF bib_is_deleted THEN
+        IF NOT retain_deleted THEN -- Go away for any MR that we're master of, unless retained
+            DELETE FROM metabib.metarecord_source_map WHERE source = bib_id;
+        END IF;
+
+        FOR old_mr IN SELECT id FROM metabib.metarecord WHERE master_record = bib_id LOOP
+
+            -- Now, are there any more sources on this MR?
+            SELECT COUNT(*) INTO source_count FROM metabib.metarecord_source_map WHERE metarecord = old_mr;
+
+            IF source_count = 0 AND NOT retain_deleted THEN -- No other records
+                deleted_mrs := ARRAY_APPEND(deleted_mrs, old_mr); -- Just in case...
+                DELETE FROM metabib.metarecord WHERE id = old_mr;
+
+            ELSE -- indeed there are. Update it with a null cache and recalcualated master record
+                UPDATE  metabib.metarecord
+                  SET   mods = NULL,
+                        master_record = ( SELECT id FROM biblio.record_entry WHERE fingerprint = fp AND NOT deleted ORDER BY quality DESC LIMIT 1)
+                  WHERE id = old_mr;
+            END IF;
+        END LOOP;
+
+    ELSE -- insert or update
+
+        FOR tmp_mr IN SELECT m.* FROM metabib.metarecord m JOIN metabib.metarecord_source_map s ON (s.metarecord = m.id) WHERE s.source = bib_id LOOP
+
+            -- Find the first fingerprint-matching
+            IF old_mr IS NULL AND fp = tmp_mr.fingerprint THEN
+                old_mr := tmp_mr.id;
+                new_mapping := FALSE;
+
+            ELSE -- Our fingerprint changed ... maybe remove the old MR
+                DELETE FROM metabib.metarecord_source_map WHERE metarecord = tmp_mr.id AND source = bib_id; -- remove the old source mapping
+                SELECT COUNT(*) INTO source_count FROM metabib.metarecord_source_map WHERE metarecord = tmp_mr.id;
+                IF source_count = 0 THEN -- No other records
+                    deleted_mrs := ARRAY_APPEND(deleted_mrs, tmp_mr.id);
+                    DELETE FROM metabib.metarecord WHERE id = tmp_mr.id;
+                END IF;
+            END IF;
+
+        END LOOP;
+
+        -- we found no suitable, preexisting MR based on old source maps
+        IF old_mr IS NULL THEN
+            SELECT id INTO old_mr FROM metabib.metarecord WHERE fingerprint = fp; -- is there one for our current fingerprint?
+
+            IF old_mr IS NULL THEN -- nope, create one and grab its id
+                INSERT INTO metabib.metarecord ( fingerprint, master_record ) VALUES ( fp, bib_id );
+                SELECT id INTO old_mr FROM metabib.metarecord WHERE fingerprint = fp;
+
+            ELSE -- indeed there is. update it with a null cache and recalcualated master record
+                UPDATE  metabib.metarecord
+                  SET   mods = NULL,
+                        master_record = ( SELECT id FROM biblio.record_entry WHERE fingerprint = fp AND NOT deleted ORDER BY quality DESC LIMIT 1)
+                  WHERE id = old_mr;
+            END IF;
+
+        ELSE -- there was one we already attached to, update its mods cache and master_record
+            UPDATE  metabib.metarecord
+              SET   mods = NULL,
+                    master_record = ( SELECT id FROM biblio.record_entry WHERE fingerprint = fp AND NOT deleted ORDER BY quality DESC LIMIT 1)
+              WHERE id = old_mr;
+        END IF;
+
+        IF new_mapping THEN
+            INSERT INTO metabib.metarecord_source_map (metarecord, source) VALUES (old_mr, bib_id); -- new source mapping
+        END IF;
+
+    END IF;
+
+    IF ARRAY_UPPER(deleted_mrs,1) > 0 THEN
+        UPDATE action.hold_request SET target = old_mr WHERE target IN ( SELECT unnest(deleted_mrs) ) AND hold_type = 'M'; -- if we had to delete any MRs above, make sure their holds are moved
+    END IF;
+
+    RETURN old_mr;
+
+END;
+$function$ LANGUAGE plpgsql;
+
+COMMIT;
+
diff --git a/Open-ILS/src/sql/Pg/upgrade/YYYY.data.mods-title-punctuation-change.sql b/Open-ILS/src/sql/Pg/upgrade/YYYY.data.mods-title-punctuation-change.sql
new file mode 100644
index 0000000..5efb1ff
--- /dev/null
+++ b/Open-ILS/src/sql/Pg/upgrade/YYYY.data.mods-title-punctuation-change.sql
@@ -0,0 +1,6817 @@
+BEGIN;
+
+update config.xml_transform set xslt = $XXXX$<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet xmlns="http://www.loc.gov/mods/v3" xmlns:marc="http://www.loc.gov/MARC21/slim" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" exclude-result-prefixes="xlink marc" version="1.0">
+        <xsl:output encoding="UTF-8" indent="yes" method="xml"/>
+<!--
+Revision 1.14 - Fixed template isValid and fields 010, 020, 022, 024, 028, and 037 to output additional identifier elements
+  with corresponding @type and @invalid eq 'yes' when subfields z or y (in the case of 022) exist in the MARCXML ::: 2007/01/04 17:35:20 cred
+
+Revision 1.13 - Changed order of output under cartographics to reflect schema  2006/11/28 tmee
+
+Revision 1.12 - Updated to reflect MODS 3.2 Mapping  2006/10/11 tmee
+
+Revision 1.11 - The attribute objectPart moved from <languageTerm> to <language>
+      2006/04/08  jrad
+
+Revision 1.10 MODS 3.1 revisions to language and classification elements
+                                (plus ability to find marc:collection embedded in wrapper elements such as SRU zs: wrappers)
+                                2006/02/06  ggar
+
+Revision 1.9 subfield $y was added to field 242 2004/09/02 10:57 jrad
+
+Revision 1.8 Subject chopPunctuation expanded and attribute fixes 2004/08/12 jrad
+
+Revision 1.7 2004/03/25 08:29 jrad
+
+Revision 1.6 various validation fixes 2004/02/20 ntra
+
+Revision 1.5  2003/10/02 16:18:58  ntra
+MODS2 to MODS3 updates, language unstacking and
+de-duping, chopPunctuation expanded
+
+Revision 1.3  2003/04/03 00:07:19  ntra
+Revision 1.3 Additional Changes not related to MODS Version 2.0 by ntra
+
+Revision 1.2  2003/03/24 19:37:42  ckeith
+Added Log Comment
+
+-->
+        <xsl:template match="/">
+                <xsl:choose>
+                        <xsl:when test="//marc:collection">
+                                <modsCollection xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.loc.gov/mods/v3 http://www.loc.gov/standards/mods/v3/mods-3-2.xsd">
+                                        <xsl:for-each select="//marc:collection/marc:record">
+                                                <mods version="3.2">
+                                                        <xsl:call-template name="marcRecord"/>
+                                                </mods>
+                                        </xsl:for-each>
+                                </modsCollection>
+                        </xsl:when>
+                        <xsl:otherwise>
+                                <mods xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.2" xsi:schemaLocation="http://www.loc.gov/mods/v3 http://www.loc.gov/standards/mods/v3/mods-3-2.xsd">
+                                        <xsl:for-each select="//marc:record">
+                                                <xsl:call-template name="marcRecord"/>
+                                        </xsl:for-each>
+                                </mods>
+                        </xsl:otherwise>
+                </xsl:choose>
+        </xsl:template>
+        <xsl:template name="marcRecord">
+                <xsl:variable name="leader" select="marc:leader"/>
+                <xsl:variable name="leader6" select="substring($leader,7,1)"/>
+                <xsl:variable name="leader7" select="substring($leader,8,1)"/>
+                <xsl:variable name="controlField008" select="marc:controlfield[@tag='008']"/>
+                <xsl:variable name="typeOf008">
+                        <xsl:choose>
+                                <xsl:when test="$leader6='a'">
+                                        <xsl:choose>
+                                                <xsl:when test="$leader7='a' or $leader7='c' or $leader7='d' or $leader7='m'">BK</xsl:when>
+                                                <xsl:when test="$leader7='b' or $leader7='i' or $leader7='s'">SE</xsl:when>
+                                        </xsl:choose>
+                                </xsl:when>
+                                <xsl:when test="$leader6='t'">BK</xsl:when>
+                                <xsl:when test="$leader6='p'">MM</xsl:when>
+                                <xsl:when test="$leader6='m'">CF</xsl:when>
+                                <xsl:when test="$leader6='e' or $leader6='f'">MP</xsl:when>
+                                <xsl:when test="$leader6='g' or $leader6='k' or $leader6='o' or $leader6='r'">VM</xsl:when>
+                                <xsl:when test="$leader6='c' or $leader6='d' or $leader6='i' or $leader6='j'">MU</xsl:when>
+                        </xsl:choose>
+                </xsl:variable>
+                <xsl:for-each select="marc:datafield[@tag='245']">
+                        <titleInfo>
+                                <xsl:variable name="title">
+                                        <xsl:choose>
+                                                <xsl:when test="marc:subfield[@code='b']">
+                                                        <xsl:call-template name="specialSubfieldSelect">
+                                                                <xsl:with-param name="axis">b</xsl:with-param>
+                                                                <xsl:with-param name="beforeCodes">afgk</xsl:with-param>
+                                                        </xsl:call-template>
+                                                </xsl:when>
+                                                <xsl:otherwise>
+                                                        <xsl:call-template name="subfieldSelect">
+                                                                <xsl:with-param name="codes">abfgk</xsl:with-param>
+                                                        </xsl:call-template>
+                                                </xsl:otherwise>
+                                        </xsl:choose>
+                                </xsl:variable>
+                                <xsl:variable name="titleChop">
+                                        <xsl:call-template name="chopPunctuation">
+                                                <xsl:with-param name="chopString">
+                                                        <xsl:value-of select="$title"/>
+                                                </xsl:with-param>
+                                                <xsl:with-param name="punctuation">
+                                                    <xsl:text>,;/ </xsl:text>
+                                                </xsl:with-param>
+                                        </xsl:call-template>
+                                </xsl:variable>
+                                <xsl:choose>
+                                        <xsl:when test="@ind2>0">
+                                                <nonSort>
+                                                        <xsl:value-of select="substring($titleChop,1, at ind2)"/>
+                                                </nonSort>
+                                                <title>
+                                                        <xsl:value-of select="substring($titleChop, at ind2+1)"/>
+                                                </title>
+                                        </xsl:when>
+                                        <xsl:otherwise>
+                                                <title>
+                                                        <xsl:value-of select="$titleChop"/>
+                                                </title>
+                                        </xsl:otherwise>
+                                </xsl:choose>
+                                <xsl:if test="marc:subfield[@code='b']">
+                                        <subTitle>
+                                                <xsl:call-template name="chopPunctuation">
+                                                        <xsl:with-param name="chopString">
+                                                                <xsl:call-template name="specialSubfieldSelect">
+                                                                        <xsl:with-param name="axis">b</xsl:with-param>
+                                                                        <xsl:with-param name="anyCodes">b</xsl:with-param>
+                                                                        <xsl:with-param name="afterCodes">afgk</xsl:with-param>
+                                                                </xsl:call-template>
+                                                        </xsl:with-param>
+                                                </xsl:call-template>
+                                        </subTitle>
+                                </xsl:if>
+                                <xsl:call-template name="part"></xsl:call-template>
+                        </titleInfo>
+                        <!-- A form of title that ignores non-filing characters; useful
+                                 for not converting "L'Oreal" into "L' Oreal" at index time -->
+                        <titleNonfiling>
+                                <title>
+                                        <xsl:call-template name="chopPunctuation">
+                                                <xsl:with-param name="chopString">
+                                                        <xsl:call-template name="subfieldSelect">
+                                                                <xsl:with-param name="codes">abfgk</xsl:with-param>
+                                                        </xsl:call-template>
+                                                </xsl:with-param>
+                                        </xsl:call-template>
+                                </title>
+                                <xsl:call-template name="part"></xsl:call-template>
+                        </titleNonfiling>
+                        <!-- hybrid of titleInfo and titleNonfiling which will give us a preformatted string (for punctuation)
+                                 but also keep the nonSort stuff in a separate field (for sorting) -->
+                        <titleBrowse>
+                                <xsl:variable name="titleBrowseChop">
+                                        <xsl:call-template name="chopPunctuation">
+                                                <xsl:with-param name="chopString">
+                                                        <xsl:call-template name="subfieldSelect">
+                                                                <xsl:with-param name="codes">abfgk</xsl:with-param>
+                                                        </xsl:call-template>
+                                                </xsl:with-param>
+                                        </xsl:call-template>
+                                </xsl:variable>
+                                <xsl:choose>
+                                        <xsl:when test="@ind2>0">
+                                                <nonSort>
+                                                        <xsl:value-of select="substring($titleBrowseChop,1, at ind2)"/>
+                                                </nonSort>
+                                                <title>
+                                                        <xsl:value-of select="substring($titleBrowseChop, at ind2+1)"/>
+                                                </title>
+                                        </xsl:when>
+                                        <xsl:otherwise>
+                                                <title>
+                                                        <xsl:value-of select="$titleBrowseChop"/>
+                                                </title>
+                                        </xsl:otherwise>
+                                </xsl:choose>
+                                <xsl:call-template name="part"></xsl:call-template>
+                        </titleBrowse>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag='210']">
+                        <titleInfo type="abbreviated">
+                                <title>
+                                        <xsl:call-template name="chopPunctuation">
+                                                <xsl:with-param name="chopString">
+                                                        <xsl:call-template name="subfieldSelect">
+                                                                <xsl:with-param name="codes">a</xsl:with-param>
+                                                        </xsl:call-template>
+                                                </xsl:with-param>
+                                        </xsl:call-template>
+                                </title>
+                                <xsl:call-template name="subtitle"/>
+                        </titleInfo>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag='242']">
+                        <xsl:variable name="titleChop">
+                                <xsl:call-template name="chopPunctuation">
+                                        <xsl:with-param name="chopString">
+                                                <xsl:call-template name="subfieldSelect">
+                                                        <!-- 1/04 removed $h, b -->
+                                                        <xsl:with-param name="codes">a</xsl:with-param>
+                                                </xsl:call-template>
+                                        </xsl:with-param>
+                                </xsl:call-template>
+                        </xsl:variable>
+                        <titleInfo type="translated">
+                                <!--09/01/04 Added subfield $y-->
+                                <xsl:for-each select="marc:subfield[@code='y']">
+                                        <xsl:attribute name="lang">
+                                                <xsl:value-of select="text()"/>
+                                        </xsl:attribute>
+                                </xsl:for-each>
+                                <title>
+                                        <xsl:value-of select="$titleChop" />
+                                </title>
+                                <!-- 1/04 fix -->
+                                <xsl:call-template name="subtitle"/>
+                                <xsl:call-template name="part"/>
+                        </titleInfo>
+                        <titleInfo type="translated-nfi">
+                                <xsl:for-each select="marc:subfield[@code='y']">
+                                        <xsl:attribute name="lang">
+                                                <xsl:value-of select="text()"/>
+                                        </xsl:attribute>
+                                </xsl:for-each>
+                                <xsl:choose>
+                                        <xsl:when test="@ind2>0">
+                                                <nonSort>
+                                                        <xsl:value-of select="substring($titleChop,1, at ind2)"/>
+                                                </nonSort>
+                                                <title>
+                                                        <xsl:value-of select="substring($titleChop, at ind2+1)"/>
+                                                </title>
+                                        </xsl:when>
+                                        <xsl:otherwise>
+                                                <title>
+                                                        <xsl:value-of select="$titleChop" />
+                                                </title>
+                                        </xsl:otherwise>
+                                </xsl:choose>
+                                <xsl:call-template name="subtitle"/>
+                                <xsl:call-template name="part"/>
+                        </titleInfo>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag='246']">
+                        <titleInfo type="alternative">
+                                <xsl:for-each select="marc:subfield[@code='i']">
+                                        <xsl:attribute name="displayLabel">
+                                                <xsl:value-of select="text()"/>
+                                        </xsl:attribute>
+                                </xsl:for-each>
+                                <title>
+                                        <xsl:call-template name="chopPunctuation">
+                                                <xsl:with-param name="chopString">
+                                                        <xsl:call-template name="subfieldSelect">
+                                                                <!-- 1/04 removed $h, $b -->
+                                                                <xsl:with-param name="codes">af</xsl:with-param>
+                                                        </xsl:call-template>
+                                                </xsl:with-param>
+                                        </xsl:call-template>
+                                </title>
+                                <xsl:call-template name="subtitle"/>
+                                <xsl:call-template name="part"/>
+                        </titleInfo>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag='130']|marc:datafield[@tag='240']|marc:datafield[@tag='730'][@ind2!='2']">
+                        <xsl:variable name="nfi">
+                                <xsl:choose>
+                                        <xsl:when test="@tag='240'">
+                                                <xsl:value-of select="@ind2"/>
+                                        </xsl:when>
+                                        <xsl:otherwise>
+                                                <xsl:value-of select="@ind1"/>
+                                        </xsl:otherwise>
+                                </xsl:choose>
+                        </xsl:variable>
+                        <xsl:variable name="titleChop">
+                                <xsl:call-template name="uri" />
+                                <xsl:variable name="str">
+                                        <xsl:for-each select="marc:subfield">
+                                                <xsl:if test="(contains('adfklmor', at code) and (not(../marc:subfield[@code='n' or @code='p']) or (following-sibling::marc:subfield[@code='n' or @code='p'])))">
+                                                        <xsl:value-of select="text()"/>
+                                                        <xsl:text> </xsl:text>
+                                                </xsl:if>
+                                        </xsl:for-each>
+                                </xsl:variable>
+                                <xsl:call-template name="chopPunctuation">
+                                        <xsl:with-param name="chopString">
+                                                <xsl:value-of select="substring($str,1,string-length($str)-1)"/>
+                                        </xsl:with-param>
+                                </xsl:call-template>
+                        </xsl:variable>
+                        <titleInfo type="uniform">
+                                <title>
+                                        <xsl:value-of select="$titleChop"/>
+                                </title>
+                                <xsl:call-template name="part"/>
+                        </titleInfo>
+                        <titleInfo type="uniform-nfi">
+                                <xsl:choose>
+                                        <xsl:when test="$nfi>0">
+                                                <nonSort>
+                                                        <xsl:value-of select="substring($titleChop,1,$nfi)"/>
+                                                </nonSort>
+                                                <title>
+                                                        <xsl:value-of select="substring($titleChop,$nfi+1)"/>
+                                                </title>
+                                        </xsl:when>
+                                        <xsl:otherwise>
+                                                <title>
+                                                        <xsl:value-of select="$titleChop"/>
+                                                </title>
+                                        </xsl:otherwise>
+                                </xsl:choose>
+                                <xsl:call-template name="part"/>
+                        </titleInfo>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag='740'][@ind2!='2']">
+                        <xsl:variable name="titleChop">
+                                <xsl:call-template name="chopPunctuation">
+                                        <xsl:with-param name="chopString">
+                                                <xsl:call-template name="subfieldSelect">
+                                                        <xsl:with-param name="codes">ah</xsl:with-param>
+                                                </xsl:call-template>
+                                        </xsl:with-param>
+                                </xsl:call-template>
+                        </xsl:variable>
+                        <titleInfo type="alternative">
+                                <title>
+                                        <xsl:value-of select="$titleChop" />
+                                </title>
+                                <xsl:call-template name="part"/>
+                        </titleInfo>
+                        <titleInfo type="alternative-nfi">
+                                <xsl:choose>
+                                        <xsl:when test="@ind1>0">
+                                                <nonSort>
+                                                        <xsl:value-of select="substring($titleChop,1, at ind1)"/>
+                                                </nonSort>
+                                                <title>
+                                                        <xsl:value-of select="substring($titleChop, at ind1+1)"/>
+                                                </title>
+                                        </xsl:when>
+                                        <xsl:otherwise>
+                                                <title>
+                                                        <xsl:value-of select="$titleChop" />
+                                                </title>
+                                        </xsl:otherwise>
+                                </xsl:choose>
+                                <xsl:call-template name="part"/>
+                        </titleInfo>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag='100']">
+                        <name type="personal">
+                                <xsl:call-template name="uri" />
+                                <xsl:call-template name="nameABCDQ"/>
+                                <xsl:call-template name="affiliation"/>
+                                <role>
+                                        <roleTerm authority="marcrelator" type="text">creator</roleTerm>
+                                </role>
+                                <xsl:call-template name="role"/>
+                        </name>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag='110']">
+                        <name type="corporate">
+                                <xsl:call-template name="uri" />
+                                <xsl:call-template name="nameABCDN"/>
+                                <role>
+                                        <roleTerm authority="marcrelator" type="text">creator</roleTerm>
+                                </role>
+                                <xsl:call-template name="role"/>
+                        </name>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag='111']">
+                        <name type="conference">
+                                <xsl:call-template name="uri" />
+                                <xsl:call-template name="nameACDEQ"/>
+                                <role>
+                                        <roleTerm authority="marcrelator" type="text">creator</roleTerm>
+                                </role>
+                                <xsl:call-template name="role"/>
+                        </name>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag='700'][not(marc:subfield[@code='t'])]">
+                        <name type="personal">
+                                <xsl:call-template name="uri" />
+                                <xsl:call-template name="nameABCDQ"/>
+                                <xsl:call-template name="affiliation"/>
+                                <xsl:call-template name="role"/>
+                        </name>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag='710'][not(marc:subfield[@code='t'])]">
+                        <name type="corporate">
+                                <xsl:call-template name="uri" />
+                                <xsl:call-template name="nameABCDN"/>
+                                <xsl:call-template name="role"/>
+                        </name>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag='711'][not(marc:subfield[@code='t'])]">
+                        <name type="conference">
+                                <xsl:call-template name="uri" />
+                                <xsl:call-template name="nameACDEQ"/>
+                                <xsl:call-template name="role"/>
+                        </name>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag='720'][not(marc:subfield[@code='t'])]">
+                        <name>
+                                <xsl:if test="@ind1=1">
+                                        <xsl:attribute name="type">
+                                                <xsl:text>personal</xsl:text>
+                                        </xsl:attribute>
+                                </xsl:if>
+                                <namePart>
+                                        <xsl:value-of select="marc:subfield[@code='a']"/>
+                                </namePart>
+                                <xsl:call-template name="role"/>
+                        </name>
+                </xsl:for-each>
+                <typeOfResource>
+                        <xsl:if test="$leader7='c'">
+                                <xsl:attribute name="collection">yes</xsl:attribute>
+                        </xsl:if>
+                        <xsl:if test="$leader6='d' or $leader6='f' or $leader6='p' or $leader6='t'">
+                                <xsl:attribute name="manuscript">yes</xsl:attribute>
+                        </xsl:if>
+                        <xsl:choose>
+                                <xsl:when test="$leader6='a' or $leader6='t'">text</xsl:when>
+                                <xsl:when test="$leader6='e' or $leader6='f'">cartographic</xsl:when>
+                                <xsl:when test="$leader6='c' or $leader6='d'">notated music</xsl:when>
+                                <xsl:when test="$leader6='i'">sound recording-nonmusical</xsl:when>
+                                <xsl:when test="$leader6='j'">sound recording-musical</xsl:when>
+                                <xsl:when test="$leader6='k'">still image</xsl:when>
+                                <xsl:when test="$leader6='g'">moving image</xsl:when>
+                                <xsl:when test="$leader6='r'">three dimensional object</xsl:when>
+                                <xsl:when test="$leader6='m'">software, multimedia</xsl:when>
+                                <xsl:when test="$leader6='p'">mixed material</xsl:when>
+                        </xsl:choose>
+                </typeOfResource>
+                <xsl:if test="substring($controlField008,26,1)='d'">
+                        <genre authority="marc">globe</genre>
+                </xsl:if>
+                <xsl:if test="marc:controlfield[@tag='007'][substring(text(),1,1)='a'][substring(text(),2,1)='r']">
+                        <genre authority="marc">remote sensing image</genre>
+                </xsl:if>
+                <xsl:if test="$typeOf008='MP'">
+                        <xsl:variable name="controlField008-25" select="substring($controlField008,26,1)"></xsl:variable>
+                        <xsl:choose>
+                                <xsl:when test="$controlField008-25='a' or $controlField008-25='b' or $controlField008-25='c' or marc:controlfield[@tag=007][substring(text(),1,1)='a'][substring(text(),2,1)='j']">
+                                        <genre authority="marc">map</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-25='e' or marc:controlfield[@tag=007][substring(text(),1,1)='a'][substring(text(),2,1)='d']">
+                                        <genre authority="marc">atlas</genre>
+                                </xsl:when>
+                        </xsl:choose>
+                </xsl:if>
+                <xsl:if test="$typeOf008='SE'">
+                        <xsl:variable name="controlField008-21" select="substring($controlField008,22,1)"></xsl:variable>
+                        <xsl:choose>
+                                <xsl:when test="$controlField008-21='d'">
+                                        <genre authority="marc">database</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-21='l'">
+                                        <genre authority="marc">loose-leaf</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-21='m'">
+                                        <genre authority="marc">series</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-21='n'">
+                                        <genre authority="marc">newspaper</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-21='p'">
+                                        <genre authority="marc">periodical</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-21='w'">
+                                        <genre authority="marc">web site</genre>
+                                </xsl:when>
+                        </xsl:choose>
+                </xsl:if>
+                <xsl:if test="$typeOf008='BK' or $typeOf008='SE'">
+                        <xsl:variable name="controlField008-24" select="substring($controlField008,25,4)"></xsl:variable>
+                        <xsl:choose>
+                                <xsl:when test="contains($controlField008-24,'a')">
+                                        <genre authority="marc">abstract or summary</genre>
+                                </xsl:when>
+                                <xsl:when test="contains($controlField008-24,'b')">
+                                        <genre authority="marc">bibliography</genre>
+                                </xsl:when>
+                                <xsl:when test="contains($controlField008-24,'c')">
+                                        <genre authority="marc">catalog</genre>
+                                </xsl:when>
+                                <xsl:when test="contains($controlField008-24,'d')">
+                                        <genre authority="marc">dictionary</genre>
+                                </xsl:when>
+                                <xsl:when test="contains($controlField008-24,'e')">
+                                        <genre authority="marc">encyclopedia</genre>
+                                </xsl:when>
+                                <xsl:when test="contains($controlField008-24,'f')">
+                                        <genre authority="marc">handbook</genre>
+                                </xsl:when>
+                                <xsl:when test="contains($controlField008-24,'g')">
+                                        <genre authority="marc">legal article</genre>
+                                </xsl:when>
+                                <xsl:when test="contains($controlField008-24,'i')">
+                                        <genre authority="marc">index</genre>
+                                </xsl:when>
+                                <xsl:when test="contains($controlField008-24,'k')">
+                                        <genre authority="marc">discography</genre>
+                                </xsl:when>
+                                <xsl:when test="contains($controlField008-24,'l')">
+                                        <genre authority="marc">legislation</genre>
+                                </xsl:when>
+                                <xsl:when test="contains($controlField008-24,'m')">
+                                        <genre authority="marc">theses</genre>
+                                </xsl:when>
+                                <xsl:when test="contains($controlField008-24,'n')">
+                                        <genre authority="marc">survey of literature</genre>
+                                </xsl:when>
+                                <xsl:when test="contains($controlField008-24,'o')">
+                                        <genre authority="marc">review</genre>
+                                </xsl:when>
+                                <xsl:when test="contains($controlField008-24,'p')">
+                                        <genre authority="marc">programmed text</genre>
+                                </xsl:when>
+                                <xsl:when test="contains($controlField008-24,'q')">
+                                        <genre authority="marc">filmography</genre>
+                                </xsl:when>
+                                <xsl:when test="contains($controlField008-24,'r')">
+                                        <genre authority="marc">directory</genre>
+                                </xsl:when>
+                                <xsl:when test="contains($controlField008-24,'s')">
+                                        <genre authority="marc">statistics</genre>
+                                </xsl:when>
+                                <xsl:when test="contains($controlField008-24,'t')">
+                                        <genre authority="marc">technical report</genre>
+                                </xsl:when>
+                                <xsl:when test="contains($controlField008-24,'v')">
+                                        <genre authority="marc">legal case and case notes</genre>
+                                </xsl:when>
+                                <xsl:when test="contains($controlField008-24,'w')">
+                                        <genre authority="marc">law report or digest</genre>
+                                </xsl:when>
+                                <xsl:when test="contains($controlField008-24,'z')">
+                                        <genre authority="marc">treaty</genre>
+                                </xsl:when>
+                        </xsl:choose>
+                        <xsl:variable name="controlField008-29" select="substring($controlField008,30,1)"></xsl:variable>
+                        <xsl:choose>
+                                <xsl:when test="$controlField008-29='1'">
+                                        <genre authority="marc">conference publication</genre>
+                                </xsl:when>
+                        </xsl:choose>
+                </xsl:if>
+                <xsl:if test="$typeOf008='CF'">
+                        <xsl:variable name="controlField008-26" select="substring($controlField008,27,1)"></xsl:variable>
+                        <xsl:choose>
+                                <xsl:when test="$controlField008-26='a'">
+                                        <genre authority="marc">numeric data</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-26='e'">
+                                        <genre authority="marc">database</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-26='f'">
+                                        <genre authority="marc">font</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-26='g'">
+                                        <genre authority="marc">game</genre>
+                                </xsl:when>
+                        </xsl:choose>
+                </xsl:if>
+                <xsl:if test="$typeOf008='BK'">
+                        <xsl:if test="substring($controlField008,25,1)='j'">
+                                <genre authority="marc">patent</genre>
+                        </xsl:if>
+                        <xsl:if test="substring($controlField008,31,1)='1'">
+                                <genre authority="marc">festschrift</genre>
+                        </xsl:if>
+                        <xsl:variable name="controlField008-34" select="substring($controlField008,35,1)"></xsl:variable>
+                        <xsl:if test="$controlField008-34='a' or $controlField008-34='b' or $controlField008-34='c' or $controlField008-34='d'">
+                                <genre authority="marc">biography</genre>
+                        </xsl:if>
+                        <xsl:variable name="controlField008-33" select="substring($controlField008,34,1)"></xsl:variable>
+                        <xsl:choose>
+                                <xsl:when test="$controlField008-33='e'">
+                                        <genre authority="marc">essay</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='d'">
+                                        <genre authority="marc">drama</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='c'">
+                                        <genre authority="marc">comic strip</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='l'">
+                                        <genre authority="marc">fiction</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='h'">
+                                        <genre authority="marc">humor, satire</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='i'">
+                                        <genre authority="marc">letter</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='f'">
+                                        <genre authority="marc">novel</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='j'">
+                                        <genre authority="marc">short story</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='s'">
+                                        <genre authority="marc">speech</genre>
+                                </xsl:when>
+                        </xsl:choose>
+                </xsl:if>
+                <xsl:if test="$typeOf008='MU'">
+                        <xsl:variable name="controlField008-30-31" select="substring($controlField008,31,2)"></xsl:variable>
+                        <xsl:if test="contains($controlField008-30-31,'b')">
+                                <genre authority="marc">biography</genre>
+                        </xsl:if>
+                        <xsl:if test="contains($controlField008-30-31,'c')">
+                                <genre authority="marc">conference publication</genre>
+                        </xsl:if>
+                        <xsl:if test="contains($controlField008-30-31,'d')">
+                                <genre authority="marc">drama</genre>
+                        </xsl:if>
+                        <xsl:if test="contains($controlField008-30-31,'e')">
+                                <genre authority="marc">essay</genre>
+                        </xsl:if>
+                        <xsl:if test="contains($controlField008-30-31,'f')">
+                                <genre authority="marc">fiction</genre>
+                        </xsl:if>
+                        <xsl:if test="contains($controlField008-30-31,'o')">
+                                <genre authority="marc">folktale</genre>
+                        </xsl:if>
+                        <xsl:if test="contains($controlField008-30-31,'h')">
+                                <genre authority="marc">history</genre>
+                        </xsl:if>
+                        <xsl:if test="contains($controlField008-30-31,'k')">
+                                <genre authority="marc">humor, satire</genre>
+                        </xsl:if>
+                        <xsl:if test="contains($controlField008-30-31,'m')">
+                                <genre authority="marc">memoir</genre>
+                        </xsl:if>
+                        <xsl:if test="contains($controlField008-30-31,'p')">
+                                <genre authority="marc">poetry</genre>
+                        </xsl:if>
+                        <xsl:if test="contains($controlField008-30-31,'r')">
+                                <genre authority="marc">rehearsal</genre>
+                        </xsl:if>
+                        <xsl:if test="contains($controlField008-30-31,'g')">
+                                <genre authority="marc">reporting</genre>
+                        </xsl:if>
+                        <xsl:if test="contains($controlField008-30-31,'s')">
+                                <genre authority="marc">sound</genre>
+                        </xsl:if>
+                        <xsl:if test="contains($controlField008-30-31,'l')">
+                                <genre authority="marc">speech</genre>
+                        </xsl:if>
+                </xsl:if>
+                <xsl:if test="$typeOf008='VM'">
+                        <xsl:variable name="controlField008-33" select="substring($controlField008,34,1)"></xsl:variable>
+                        <xsl:choose>
+                                <xsl:when test="$controlField008-33='a'">
+                                        <genre authority="marc">art original</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='b'">
+                                        <genre authority="marc">kit</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='c'">
+                                        <genre authority="marc">art reproduction</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='d'">
+                                        <genre authority="marc">diorama</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='f'">
+                                        <genre authority="marc">filmstrip</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='g'">
+                                        <genre authority="marc">legal article</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='i'">
+                                        <genre authority="marc">picture</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='k'">
+                                        <genre authority="marc">graphic</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='l'">
+                                        <genre authority="marc">technical drawing</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='m'">
+                                        <genre authority="marc">motion picture</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='n'">
+                                        <genre authority="marc">chart</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='o'">
+                                        <genre authority="marc">flash card</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='p'">
+                                        <genre authority="marc">microscope slide</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='q' or marc:controlfield[@tag=007][substring(text(),1,1)='a'][substring(text(),2,1)='q']">
+                                        <genre authority="marc">model</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='r'">
+                                        <genre authority="marc">realia</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='s'">
+                                        <genre authority="marc">slide</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='t'">
+                                        <genre authority="marc">transparency</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='v'">
+                                        <genre authority="marc">videorecording</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='w'">
+                                        <genre authority="marc">toy</genre>
+                                </xsl:when>
+                        </xsl:choose>
+                </xsl:if>
+                <xsl:for-each select="marc:datafield[@tag=655]">
+                        <genre authority="marc">
+                                <xsl:attribute name="authority">
+                                        <xsl:value-of select="marc:subfield[@code='2']"/>
+                                </xsl:attribute>
+                                <xsl:call-template name="subfieldSelect">
+                                        <xsl:with-param name="codes">abvxyz</xsl:with-param>
+                                        <xsl:with-param name="delimeter">-</xsl:with-param>
+                                </xsl:call-template>
+                        </genre>
+                </xsl:for-each>
+                <originInfo>
+                        <xsl:variable name="MARCpublicationCode" select="normalize-space(substring($controlField008,16,3))"></xsl:variable>
+                        <xsl:if test="translate($MARCpublicationCode,'|','')">
+                                <place>
+                                        <placeTerm>
+                                                <xsl:attribute name="type">code</xsl:attribute>
+                                                <xsl:attribute name="authority">marccountry</xsl:attribute>
+                                                <xsl:value-of select="$MARCpublicationCode"/>
+                                        </placeTerm>
+                                </place>
+                        </xsl:if>
+                        <xsl:for-each select="marc:datafield[@tag=044]/marc:subfield[@code='c']">
+                                <place>
+                                        <placeTerm>
+                                                <xsl:attribute name="type">code</xsl:attribute>
+                                                <xsl:attribute name="authority">iso3166</xsl:attribute>
+                                                <xsl:value-of select="."/>
+                                        </placeTerm>
+                                </place>
+                        </xsl:for-each>
+                        <xsl:for-each select="marc:datafield[@tag=260]/marc:subfield[@code='a']">
+                                <place>
+                                        <placeTerm>
+                                                <xsl:attribute name="type">text</xsl:attribute>
+                                                <xsl:call-template name="chopPunctuationFront">
+                                                        <xsl:with-param name="chopString">
+                                                                <xsl:call-template name="chopPunctuation">
+                                                                        <xsl:with-param name="chopString" select="."/>
+                                                                </xsl:call-template>
+                                                        </xsl:with-param>
+                                                </xsl:call-template>
+                                        </placeTerm>
+                                </place>
+                        </xsl:for-each>
+                        <xsl:for-each select="marc:datafield[@tag=046]/marc:subfield[@code='m']">
+                                <dateValid point="start">
+                                        <xsl:value-of select="."/>
+                                </dateValid>
+                        </xsl:for-each>
+                        <xsl:for-each select="marc:datafield[@tag=046]/marc:subfield[@code='n']">
+                                <dateValid point="end">
+                                        <xsl:value-of select="."/>
+                                </dateValid>
+                        </xsl:for-each>
+                        <xsl:for-each select="marc:datafield[@tag=046]/marc:subfield[@code='j']">
+                                <dateModified>
+                                        <xsl:value-of select="."/>
+                                </dateModified>
+                        </xsl:for-each>
+                        <xsl:for-each select="marc:datafield[@tag=260]/marc:subfield[@code='b' or @code='c' or @code='g']">
+                                <xsl:choose>
+                                        <xsl:when test="@code='b'">
+                                                <publisher>
+                                                        <xsl:call-template name="chopPunctuation">
+                                                                <xsl:with-param name="chopString" select="."/>
+                                                                <xsl:with-param name="punctuation">
+                                                                        <xsl:text>:,;/ </xsl:text>
+                                                                </xsl:with-param>
+                                                        </xsl:call-template>
+                                                </publisher>
+                                        </xsl:when>
+                                        <xsl:when test="@code='c'">
+                                                <dateIssued>
+                                                        <xsl:call-template name="chopPunctuation">
+                                                                <xsl:with-param name="chopString" select="."/>
+                                                        </xsl:call-template>
+                                                </dateIssued>
+                                        </xsl:when>
+                                        <xsl:when test="@code='g'">
+                                                <dateCreated>
+                                                        <xsl:value-of select="."/>
+                                                </dateCreated>
+                                        </xsl:when>
+                                </xsl:choose>
+                        </xsl:for-each>
+                        <xsl:variable name="dataField260c">
+                                <xsl:call-template name="chopPunctuation">
+                                        <xsl:with-param name="chopString" select="marc:datafield[@tag=260]/marc:subfield[@code='c']"></xsl:with-param>
+                                </xsl:call-template>
+                        </xsl:variable>
+                        <xsl:variable name="controlField008-7-10" select="normalize-space(substring($controlField008, 8, 4))"></xsl:variable>
+                        <xsl:variable name="controlField008-11-14" select="normalize-space(substring($controlField008, 12, 4))"></xsl:variable>
+                        <xsl:variable name="controlField008-6" select="normalize-space(substring($controlField008, 7, 1))"></xsl:variable>
+                        <xsl:if test="$controlField008-6='e' or $controlField008-6='p' or $controlField008-6='r' or $controlField008-6='t' or $controlField008-6='s'">
+                                <xsl:if test="$controlField008-7-10 and ($controlField008-7-10 != $dataField260c)">
+                                        <dateIssued encoding="marc">
+                                                <xsl:value-of select="$controlField008-7-10"/>
+                                        </dateIssued>
+                                </xsl:if>
+                        </xsl:if>
+                        <xsl:if test="$controlField008-6='c' or $controlField008-6='d' or $controlField008-6='i' or $controlField008-6='k' or $controlField008-6='m' or $controlField008-6='q' or $controlField008-6='u'">
+                                <xsl:if test="$controlField008-7-10">
+                                        <dateIssued encoding="marc" point="start">
+                                                <xsl:value-of select="$controlField008-7-10"/>
+                                        </dateIssued>
+                                </xsl:if>
+                        </xsl:if>
+                        <xsl:if test="$controlField008-6='c' or $controlField008-6='d' or $controlField008-6='i' or $controlField008-6='k' or $controlField008-6='m' or $controlField008-6='q' or $controlField008-6='u'">
+                                <xsl:if test="$controlField008-11-14">
+                                        <dateIssued encoding="marc" point="end">
+                                                <xsl:value-of select="$controlField008-11-14"/>
+                                        </dateIssued>
+                                </xsl:if>
+                        </xsl:if>
+                        <xsl:if test="$controlField008-6='q'">
+                                <xsl:if test="$controlField008-7-10">
+                                        <dateIssued encoding="marc" point="start" qualifier="questionable">
+                                                <xsl:value-of select="$controlField008-7-10"/>
+                                        </dateIssued>
+                                </xsl:if>
+                        </xsl:if>
+                        <xsl:if test="$controlField008-6='q'">
+                                <xsl:if test="$controlField008-11-14">
+                                        <dateIssued encoding="marc" point="end" qualifier="questionable">
+                                                <xsl:value-of select="$controlField008-11-14"/>
+                                        </dateIssued>
+                                </xsl:if>
+                        </xsl:if>
+                        <xsl:if test="$controlField008-6='t'">
+                                <xsl:if test="$controlField008-11-14">
+                                        <copyrightDate encoding="marc">
+                                                <xsl:value-of select="$controlField008-11-14"/>
+                                        </copyrightDate>
+                                </xsl:if>
+                        </xsl:if>
+                        <xsl:for-each select="marc:datafield[@tag=033][@ind1=0 or @ind1=1]/marc:subfield[@code='a']">
+                                <dateCaptured encoding="iso8601">
+                                        <xsl:value-of select="."/>
+                                </dateCaptured>
+                        </xsl:for-each>
+                        <xsl:for-each select="marc:datafield[@tag=033][@ind1=2]/marc:subfield[@code='a'][1]">
+                                <dateCaptured encoding="iso8601" point="start">
+                                        <xsl:value-of select="."/>
+                                </dateCaptured>
+                        </xsl:for-each>
+                        <xsl:for-each select="marc:datafield[@tag=033][@ind1=2]/marc:subfield[@code='a'][2]">
+                                <dateCaptured encoding="iso8601" point="end">
+                                        <xsl:value-of select="."/>
+                                </dateCaptured>
+                        </xsl:for-each>
+                        <xsl:for-each select="marc:datafield[@tag=250]/marc:subfield[@code='a']">
+                                <edition>
+                                        <xsl:value-of select="."/>
+                                </edition>
+                        </xsl:for-each>
+                        <xsl:for-each select="marc:leader">
+                                <issuance>
+                                        <xsl:choose>
+                                                <xsl:when test="$leader7='a' or $leader7='c' or $leader7='d' or $leader7='m'">monographic</xsl:when>
+                                                <xsl:when test="$leader7='b' or $leader7='i' or $leader7='s'">continuing</xsl:when>
+                                        </xsl:choose>
+                                </issuance>
+                        </xsl:for-each>
+                        <xsl:for-each select="marc:datafield[@tag=310]|marc:datafield[@tag=321]">
+                                <frequency>
+                                        <xsl:call-template name="subfieldSelect">
+                                                <xsl:with-param name="codes">ab</xsl:with-param>
+                                        </xsl:call-template>
+                                </frequency>
+                        </xsl:for-each>
+                </originInfo>
+                <xsl:variable name="controlField008-35-37" select="normalize-space(translate(substring($controlField008,36,3),'|#',''))"></xsl:variable>
+                <xsl:if test="$controlField008-35-37">
+                        <language>
+                                <languageTerm authority="iso639-2b" type="code">
+                                        <xsl:value-of select="substring($controlField008,36,3)"/>
+                                </languageTerm>
+                        </language>
+                </xsl:if>
+                <xsl:for-each select="marc:datafield[@tag=041]">
+                        <xsl:for-each select="marc:subfield[@code='a' or @code='b' or @code='d' or @code='e' or @code='f' or @code='g' or @code='h']">
+                                <xsl:variable name="langCodes" select="."/>
+                                <xsl:choose>
+                                        <xsl:when test="../marc:subfield[@code='2']='rfc3066'">
+                                                <!-- not stacked but could be repeated -->
+                                                <xsl:call-template name="rfcLanguages">
+                                                        <xsl:with-param name="nodeNum">
+                                                                <xsl:value-of select="1"/>
+                                                        </xsl:with-param>
+                                                        <xsl:with-param name="usedLanguages">
+                                                                <xsl:text></xsl:text>
+                                                        </xsl:with-param>
+                                                        <xsl:with-param name="controlField008-35-37">
+                                                                <xsl:value-of select="$controlField008-35-37"></xsl:value-of>
+                                                        </xsl:with-param>
+                                                </xsl:call-template>
+                                        </xsl:when>
+                                        <xsl:otherwise>
+                                                <!-- iso -->
+                                                <xsl:variable name="allLanguages">
+                                                        <xsl:copy-of select="$langCodes"></xsl:copy-of>
+                                                </xsl:variable>
+                                                <xsl:variable name="currentLanguage">
+                                                        <xsl:value-of select="substring($allLanguages,1,3)"></xsl:value-of>
+                                                </xsl:variable>
+                                                <xsl:call-template name="isoLanguage">
+                                                        <xsl:with-param name="currentLanguage">
+                                                                <xsl:value-of select="substring($allLanguages,1,3)"></xsl:value-of>
+                                                        </xsl:with-param>
+                                                        <xsl:with-param name="remainingLanguages">
+                                                                <xsl:value-of select="substring($allLanguages,4,string-length($allLanguages)-3)"></xsl:value-of>
+                                                        </xsl:with-param>
+                                                        <xsl:with-param name="usedLanguages">
+                                                                <xsl:if test="$controlField008-35-37">
+                                                                        <xsl:value-of select="$controlField008-35-37"></xsl:value-of>
+                                                                </xsl:if>
+                                                        </xsl:with-param>
+                                                </xsl:call-template>
+                                        </xsl:otherwise>
+                                </xsl:choose>
+                        </xsl:for-each>
+                </xsl:for-each>
+                <xsl:variable name="physicalDescription">
+                        <!--3.2 change tmee 007/11 -->
+                        <xsl:if test="$typeOf008='CF' and marc:controlfield[@tag=007][substring(.,12,1)='a']">
+                                <digitalOrigin>reformatted digital</digitalOrigin>
+                        </xsl:if>
+                        <xsl:if test="$typeOf008='CF' and marc:controlfield[@tag=007][substring(.,12,1)='b']">
+                                <digitalOrigin>digitized microfilm</digitalOrigin>
+                        </xsl:if>
+                        <xsl:if test="$typeOf008='CF' and marc:controlfield[@tag=007][substring(.,12,1)='d']">
+                                <digitalOrigin>digitized other analog</digitalOrigin>
+                        </xsl:if>
+                        <xsl:variable name="controlField008-23" select="substring($controlField008,24,1)"></xsl:variable>
+                        <xsl:variable name="controlField008-29" select="substring($controlField008,30,1)"></xsl:variable>
+                        <xsl:variable name="check008-23">
+                                <xsl:if test="$typeOf008='BK' or $typeOf008='MU' or $typeOf008='SE' or $typeOf008='MM'">
+                                        <xsl:value-of select="true()"></xsl:value-of>
+                                </xsl:if>
+                        </xsl:variable>
+                        <xsl:variable name="check008-29">
+                                <xsl:if test="$typeOf008='MP' or $typeOf008='VM'">
+                                        <xsl:value-of select="true()"></xsl:value-of>
+                                </xsl:if>
+                        </xsl:variable>
+                        <xsl:choose>
+                                <xsl:when test="($check008-23 and $controlField008-23='f') or ($check008-29 and $controlField008-29='f')">
+                                        <form authority="marcform">braille</form>
+                                </xsl:when>
+                                <xsl:when test="($controlField008-23=' ' and ($leader6='c' or $leader6='d')) or (($typeOf008='BK' or $typeOf008='SE') and ($controlField008-23=' ' or $controlField008='r'))">
+                                        <form authority="marcform">print</form>
+                                </xsl:when>
+                                <xsl:when test="$leader6 = 'm' or ($check008-23 and $controlField008-23='s') or ($check008-29 and $controlField008-29='s')">
+                                        <form authority="marcform">electronic</form>
+                                </xsl:when>
+                                <xsl:when test="($check008-23 and $controlField008-23='b') or ($check008-29 and $controlField008-29='b')">
+                                        <form authority="marcform">microfiche</form>
+                                </xsl:when>
+                                <xsl:when test="($check008-23 and $controlField008-23='a') or ($check008-29 and $controlField008-29='a')">
+                                        <form authority="marcform">microfilm</form>
+                                </xsl:when>
+                        </xsl:choose>
+                        <!-- 1/04 fix -->
+                        <xsl:if test="marc:datafield[@tag=130]/marc:subfield[@code='h']">
+                                <form authority="gmd">
+                                        <xsl:call-template name="chopBrackets">
+                                                <xsl:with-param name="chopString">
+                                                        <xsl:value-of select="marc:datafield[@tag=130]/marc:subfield[@code='h']"></xsl:value-of>
+                                                </xsl:with-param>
+                                        </xsl:call-template>
+                                </form>
+                        </xsl:if>
+                        <xsl:if test="marc:datafield[@tag=240]/marc:subfield[@code='h']">
+                                <form authority="gmd">
+                                        <xsl:call-template name="chopBrackets">
+                                                <xsl:with-param name="chopString">
+                                                        <xsl:value-of select="marc:datafield[@tag=240]/marc:subfield[@code='h']"></xsl:value-of>
+                                                </xsl:with-param>
+                                        </xsl:call-template>
+                                </form>
+                        </xsl:if>
+                        <xsl:if test="marc:datafield[@tag=242]/marc:subfield[@code='h']">
+                                <form authority="gmd">
+                                        <xsl:call-template name="chopBrackets">
+                                                <xsl:with-param name="chopString">
+                                                        <xsl:value-of select="marc:datafield[@tag=242]/marc:subfield[@code='h']"></xsl:value-of>
+                                                </xsl:with-param>
+                                        </xsl:call-template>
+                                </form>
+                        </xsl:if>
+                        <xsl:if test="marc:datafield[@tag=245]/marc:subfield[@code='h']">
+                                <form authority="gmd">
+                                        <xsl:call-template name="chopBrackets">
+                                                <xsl:with-param name="chopString">
+                                                        <xsl:value-of select="marc:datafield[@tag=245]/marc:subfield[@code='h']"></xsl:value-of>
+                                                </xsl:with-param>
+                                        </xsl:call-template>
+                                </form>
+                        </xsl:if>
+                        <xsl:if test="marc:datafield[@tag=246]/marc:subfield[@code='h']">
+                                <form authority="gmd">
+                                        <xsl:call-template name="chopBrackets">
+                                                <xsl:with-param name="chopString">
+                                                        <xsl:value-of select="marc:datafield[@tag=246]/marc:subfield[@code='h']"></xsl:value-of>
+                                                </xsl:with-param>
+                                        </xsl:call-template>
+                                </form>
+                        </xsl:if>
+                        <xsl:if test="marc:datafield[@tag=730]/marc:subfield[@code='h']">
+                                <form authority="gmd">
+                                        <xsl:call-template name="chopBrackets">
+                                                <xsl:with-param name="chopString">
+                                                        <xsl:value-of select="marc:datafield[@tag=730]/marc:subfield[@code='h']"></xsl:value-of>
+                                                </xsl:with-param>
+                                        </xsl:call-template>
+                                </form>
+                        </xsl:if>
+                        <xsl:for-each select="marc:datafield[@tag=256]/marc:subfield[@code='a']">
+                                <form>
+                                        <xsl:value-of select="."></xsl:value-of>
+                                </form>
+                        </xsl:for-each>
+                        <xsl:for-each select="marc:controlfield[@tag=007][substring(text(),1,1)='c']">
+                                <xsl:choose>
+                                        <xsl:when test="substring(text(),14,1)='a'">
+                                                <reformattingQuality>access</reformattingQuality>
+                                        </xsl:when>
+                                        <xsl:when test="substring(text(),14,1)='p'">
+                                                <reformattingQuality>preservation</reformattingQuality>
+                                        </xsl:when>
+                                        <xsl:when test="substring(text(),14,1)='r'">
+                                                <reformattingQuality>replacement</reformattingQuality>
+                                        </xsl:when>
+                                </xsl:choose>
+                        </xsl:for-each>
+                        <!--3.2 change tmee 007/01 -->
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='c'][substring(text(),2,1)='b']">
+                                <form authority="smd">chip cartridge</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='c'][substring(text(),2,1)='c']">
+                                <form authority="smd">computer optical disc cartridge</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='c'][substring(text(),2,1)='j']">
+                                <form authority="smd">magnetic disc</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='c'][substring(text(),2,1)='m']">
+                                <form authority="smd">magneto-optical disc</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='c'][substring(text(),2,1)='o']">
+                                <form authority="smd">optical disc</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='c'][substring(text(),2,1)='r']">
+                                <form authority="smd">remote</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='c'][substring(text(),2,1)='a']">
+                                <form authority="smd">tape cartridge</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='c'][substring(text(),2,1)='f']">
+                                <form authority="smd">tape cassette</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='c'][substring(text(),2,1)='h']">
+                                <form authority="smd">tape reel</form>
+                        </xsl:if>
+
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='d'][substring(text(),2,1)='a']">
+                                <form authority="smd">celestial globe</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='d'][substring(text(),2,1)='e']">
+                                <form authority="smd">earth moon globe</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='d'][substring(text(),2,1)='b']">
+                                <form authority="smd">planetary or lunar globe</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='d'][substring(text(),2,1)='c']">
+                                <form authority="smd">terrestrial globe</form>
+                        </xsl:if>
+
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='o'][substring(text(),2,1)='o']">
+                                <form authority="smd">kit</form>
+                        </xsl:if>
+
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='a'][substring(text(),2,1)='d']">
+                                <form authority="smd">atlas</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='a'][substring(text(),2,1)='g']">
+                                <form authority="smd">diagram</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='a'][substring(text(),2,1)='j']">
+                                <form authority="smd">map</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='a'][substring(text(),2,1)='q']">
+                                <form authority="smd">model</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='a'][substring(text(),2,1)='k']">
+                                <form authority="smd">profile</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='a'][substring(text(),2,1)='r']">
+                                <form authority="smd">remote-sensing image</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='a'][substring(text(),2,1)='s']">
+                                <form authority="smd">section</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='a'][substring(text(),2,1)='y']">
+                                <form authority="smd">view</form>
+                        </xsl:if>
+
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='h'][substring(text(),2,1)='a']">
+                                <form authority="smd">aperture card</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='h'][substring(text(),2,1)='e']">
+                                <form authority="smd">microfiche</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='h'][substring(text(),2,1)='f']">
+                                <form authority="smd">microfiche cassette</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='h'][substring(text(),2,1)='b']">
+                                <form authority="smd">microfilm cartridge</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='h'][substring(text(),2,1)='c']">
+                                <form authority="smd">microfilm cassette</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='h'][substring(text(),2,1)='d']">
+                                <form authority="smd">microfilm reel</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='h'][substring(text(),2,1)='g']">
+                                <form authority="smd">microopaque</form>
+                        </xsl:if>
+
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='m'][substring(text(),2,1)='c']">
+                                <form authority="smd">film cartridge</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='m'][substring(text(),2,1)='f']">
+                                <form authority="smd">film cassette</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='m'][substring(text(),2,1)='r']">
+                                <form authority="smd">film reel</form>
+                        </xsl:if>
+
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='k'][substring(text(),2,1)='n']">
+                                <form authority="smd">chart</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='k'][substring(text(),2,1)='c']">
+                                <form authority="smd">collage</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='k'][substring(text(),2,1)='d']">
+                                <form authority="smd">drawing</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='k'][substring(text(),2,1)='o']">
+                                <form authority="smd">flash card</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='k'][substring(text(),2,1)='e']">
+                                <form authority="smd">painting</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='k'][substring(text(),2,1)='f']">
+                                <form authority="smd">photomechanical print</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='k'][substring(text(),2,1)='g']">
+                                <form authority="smd">photonegative</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='k'][substring(text(),2,1)='h']">
+                                <form authority="smd">photoprint</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='k'][substring(text(),2,1)='i']">
+                                <form authority="smd">picture</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='k'][substring(text(),2,1)='j']">
+                                <form authority="smd">print</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='k'][substring(text(),2,1)='l']">
+                                <form authority="smd">technical drawing</form>
+                        </xsl:if>
+
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='q'][substring(text(),2,1)='q']">
+                                <form authority="smd">notated music</form>
+                        </xsl:if>
+
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='g'][substring(text(),2,1)='d']">
+                                <form authority="smd">filmslip</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='g'][substring(text(),2,1)='c']">
+                                <form authority="smd">filmstrip cartridge</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='g'][substring(text(),2,1)='o']">
+                                <form authority="smd">filmstrip roll</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='g'][substring(text(),2,1)='f']">
+                                <form authority="smd">other filmstrip type</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='g'][substring(text(),2,1)='s']">
+                                <form authority="smd">slide</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='g'][substring(text(),2,1)='t']">
+                                <form authority="smd">transparency</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='r'][substring(text(),2,1)='r']">
+                                <form authority="smd">remote-sensing image</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='s'][substring(text(),2,1)='e']">
+                                <form authority="smd">cylinder</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='s'][substring(text(),2,1)='q']">
+                                <form authority="smd">roll</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='s'][substring(text(),2,1)='g']">
+                                <form authority="smd">sound cartridge</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='s'][substring(text(),2,1)='s']">
+                                <form authority="smd">sound cassette</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='s'][substring(text(),2,1)='d']">
+                                <form authority="smd">sound disc</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='s'][substring(text(),2,1)='t']">
+                                <form authority="smd">sound-tape reel</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='s'][substring(text(),2,1)='i']">
+                                <form authority="smd">sound-track film</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='s'][substring(text(),2,1)='w']">
+                                <form authority="smd">wire recording</form>
+                        </xsl:if>
+
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='f'][substring(text(),2,1)='c']">
+                                <form authority="smd">braille</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='f'][substring(text(),2,1)='b']">
+                                <form authority="smd">combination</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='f'][substring(text(),2,1)='a']">
+                                <form authority="smd">moon</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='f'][substring(text(),2,1)='d']">
+                                <form authority="smd">tactile, with no writing system</form>
+                        </xsl:if>
+
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='t'][substring(text(),2,1)='c']">
+                                <form authority="smd">braille</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='t'][substring(text(),2,1)='b']">
+                                <form authority="smd">large print</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='t'][substring(text(),2,1)='a']">
+                                <form authority="smd">regular print</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='t'][substring(text(),2,1)='d']">
+                                <form authority="smd">text in looseleaf binder</form>
+                        </xsl:if>
+
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='v'][substring(text(),2,1)='c']">
+                                <form authority="smd">videocartridge</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='v'][substring(text(),2,1)='f']">
+                                <form authority="smd">videocassette</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='v'][substring(text(),2,1)='d']">
+                                <form authority="smd">videodisc</form>
+                        </xsl:if>
+                        <xsl:if test="marc:controlfield[@tag=007][substring(text(),1,1)='v'][substring(text(),2,1)='r']">
+                                <form authority="smd">videoreel</form>
+                        </xsl:if>
+
+                        <xsl:for-each select="marc:datafield[@tag=856]/marc:subfield[@code='q'][string-length(.)>1]">
+                                <internetMediaType>
+                                        <xsl:value-of select="."></xsl:value-of>
+                                </internetMediaType>
+                        </xsl:for-each>
+                        <xsl:for-each select="marc:datafield[@tag=300]">
+                                <extent>
+                                        <xsl:call-template name="subfieldSelect">
+                                                <xsl:with-param name="codes">abce</xsl:with-param>
+                                        </xsl:call-template>
+                                </extent>
+                        </xsl:for-each>
+                </xsl:variable>
+                <xsl:if test="string-length(normalize-space($physicalDescription))">
+                        <physicalDescription>
+                                <xsl:copy-of select="$physicalDescription"></xsl:copy-of>
+                        </physicalDescription>
+                </xsl:if>
+                <xsl:for-each select="marc:datafield[@tag=520]">
+                        <abstract>
+                                <xsl:call-template name="uri"></xsl:call-template>
+                                <xsl:call-template name="subfieldSelect">
+                                        <xsl:with-param name="codes">ab</xsl:with-param>
+                                </xsl:call-template>
+                        </abstract>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=505]">
+                        <tableOfContents>
+                                <xsl:call-template name="uri"></xsl:call-template>
+                                <xsl:call-template name="subfieldSelect">
+                                        <xsl:with-param name="codes">agrt</xsl:with-param>
+                                </xsl:call-template>
+                        </tableOfContents>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=521]">
+                        <targetAudience>
+                                <xsl:call-template name="subfieldSelect">
+                                        <xsl:with-param name="codes">ab</xsl:with-param>
+                                </xsl:call-template>
+                        </targetAudience>
+                </xsl:for-each>
+                <xsl:if test="$typeOf008='BK' or $typeOf008='CF' or $typeOf008='MU' or $typeOf008='VM'">
+                        <xsl:variable name="controlField008-22" select="substring($controlField008,23,1)"></xsl:variable>
+                        <xsl:choose>
+                                <!-- 01/04 fix -->
+                                <xsl:when test="$controlField008-22='d'">
+                                        <targetAudience authority="marctarget">adolescent</targetAudience>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-22='e'">
+                                        <targetAudience authority="marctarget">adult</targetAudience>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-22='g'">
+                                        <targetAudience authority="marctarget">general</targetAudience>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-22='b' or $controlField008-22='c' or $controlField008-22='j'">
+                                        <targetAudience authority="marctarget">juvenile</targetAudience>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-22='a'">
+                                        <targetAudience authority="marctarget">preschool</targetAudience>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-22='f'">
+                                        <targetAudience authority="marctarget">specialized</targetAudience>
+                                </xsl:when>
+                        </xsl:choose>
+                </xsl:if>
+                <xsl:for-each select="marc:datafield[@tag=245]/marc:subfield[@code='c']">
+                        <note type="statement of responsibility">
+                                <xsl:value-of select="."></xsl:value-of>
+                        </note>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=500]">
+                        <note>
+                                <xsl:value-of select="marc:subfield[@code='a']"></xsl:value-of>
+                                <xsl:call-template name="uri"></xsl:call-template>
+                        </note>
+                </xsl:for-each>
+
+                <!--3.2 change tmee additional note fields-->
+
+                <xsl:for-each select="marc:datafield[@tag=506]">
+                        <note type="restrictions">
+                                <xsl:call-template name="uri"></xsl:call-template>
+                                <xsl:variable name="str">
+                                        <xsl:for-each select="marc:subfield[@code!='6' or @code!='8']">
+                                                <xsl:value-of select="."></xsl:value-of>
+                                                <xsl:text> </xsl:text>
+                                        </xsl:for-each>
+                                </xsl:variable>
+                                <xsl:value-of select="substring($str,1,string-length($str)-1)"></xsl:value-of>
+                        </note>
+                </xsl:for-each>
+
+                <xsl:for-each select="marc:datafield[@tag=510]">
+                        <note  type="citation/reference">
+                                <xsl:call-template name="uri"></xsl:call-template>
+                                <xsl:variable name="str">
+                                        <xsl:for-each select="marc:subfield[@code!='6' or @code!='8']">
+                                                <xsl:value-of select="."></xsl:value-of>
+                                                <xsl:text> </xsl:text>
+                                        </xsl:for-each>
+                                </xsl:variable>
+                                <xsl:value-of select="substring($str,1,string-length($str)-1)"></xsl:value-of>
+                        </note>
+                </xsl:for-each>
+
+
+                <xsl:for-each select="marc:datafield[@tag=511]">
+                        <note type="performers">
+                                <xsl:call-template name="uri"></xsl:call-template>
+                                <xsl:value-of select="marc:subfield[@code='a']"></xsl:value-of>
+                        </note>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=518]">
+                        <note type="venue">
+                                <xsl:call-template name="uri"></xsl:call-template>
+                                <xsl:value-of select="marc:subfield[@code='a']"></xsl:value-of>
+                        </note>
+                </xsl:for-each>
+
+                <xsl:for-each select="marc:datafield[@tag=530]">
+                        <note  type="additional physical form">
+                                <xsl:call-template name="uri"></xsl:call-template>
+                                <xsl:variable name="str">
+                                        <xsl:for-each select="marc:subfield[@code!='6' or @code!='8']">
+                                                <xsl:value-of select="."></xsl:value-of>
+                                                <xsl:text> </xsl:text>
+                                        </xsl:for-each>
+                                </xsl:variable>
+                                <xsl:value-of select="substring($str,1,string-length($str)-1)"></xsl:value-of>
+                        </note>
+                </xsl:for-each>
+
+                <xsl:for-each select="marc:datafield[@tag=533]">
+                        <note  type="reproduction">
+                                <xsl:call-template name="uri"></xsl:call-template>
+                                <xsl:variable name="str">
+                                        <xsl:for-each select="marc:subfield[@code!='6' or @code!='8']">
+                                                <xsl:value-of select="."></xsl:value-of>
+                                                <xsl:text> </xsl:text>
+                                        </xsl:for-each>
+                                </xsl:variable>
+                                <xsl:value-of select="substring($str,1,string-length($str)-1)"></xsl:value-of>
+                        </note>
+                </xsl:for-each>
+
+                <xsl:for-each select="marc:datafield[@tag=534]">
+                        <note  type="original version">
+                                <xsl:call-template name="uri"></xsl:call-template>
+                                <xsl:variable name="str">
+                                        <xsl:for-each select="marc:subfield[@code!='6' or @code!='8']">
+                                                <xsl:value-of select="."></xsl:value-of>
+                                                <xsl:text> </xsl:text>
+                                        </xsl:for-each>
+                                </xsl:variable>
+                                <xsl:value-of select="substring($str,1,string-length($str)-1)"></xsl:value-of>
+                        </note>
+                </xsl:for-each>
+
+                <xsl:for-each select="marc:datafield[@tag=538]">
+                        <note  type="system details">
+                                <xsl:call-template name="uri"></xsl:call-template>
+                                <xsl:variable name="str">
+                                        <xsl:for-each select="marc:subfield[@code!='6' or @code!='8']">
+                                                <xsl:value-of select="."></xsl:value-of>
+                                                <xsl:text> </xsl:text>
+                                        </xsl:for-each>
+                                </xsl:variable>
+                                <xsl:value-of select="substring($str,1,string-length($str)-1)"></xsl:value-of>
+                        </note>
+                </xsl:for-each>
+
+                <xsl:for-each select="marc:datafield[@tag=583]">
+                        <note type="action">
+                                <xsl:call-template name="uri"></xsl:call-template>
+                                <xsl:variable name="str">
+                                        <xsl:for-each select="marc:subfield[@code!='6' or @code!='8']">
+                                                <xsl:value-of select="."></xsl:value-of>
+                                                <xsl:text> </xsl:text>
+                                        </xsl:for-each>
+                                </xsl:variable>
+                                <xsl:value-of select="substring($str,1,string-length($str)-1)"></xsl:value-of>
+                        </note>
+                </xsl:for-each>
+
+
+
+
+
+                <xsl:for-each select="marc:datafield[@tag=501 or @tag=502 or @tag=504 or @tag=507 or @tag=508 or  @tag=513 or @tag=514 or @tag=515 or @tag=516 or @tag=522 or @tag=524 or @tag=525 or @tag=526 or @tag=535 or @tag=536 or @tag=540 or @tag=541 or @tag=544 or @tag=545 or @tag=546 or @tag=547 or @tag=550 or @tag=552 or @tag=555 or @tag=556 or @tag=561 or @tag=562 or @tag=565 or @tag=567 or @tag=580 or @tag=581 or @tag=584 or @tag=585 or @tag=586]">
+                        <note>
+                                <xsl:call-template name="uri"></xsl:call-template>
+                                <xsl:variable name="str">
+                                        <xsl:for-each select="marc:subfield[@code!='6' or @code!='8']">
+                                                <xsl:value-of select="."></xsl:value-of>
+                                                <xsl:text> </xsl:text>
+                                        </xsl:for-each>
+                                </xsl:variable>
+                                <xsl:value-of select="substring($str,1,string-length($str)-1)"></xsl:value-of>
+                        </note>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=034][marc:subfield[@code='d' or @code='e' or @code='f' or @code='g']]">
+                        <subject>
+                                <cartographics>
+                                        <coordinates>
+                                                <xsl:call-template name="subfieldSelect">
+                                                        <xsl:with-param name="codes">defg</xsl:with-param>
+                                                </xsl:call-template>
+                                        </coordinates>
+                                </cartographics>
+                        </subject>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=043]">
+                        <subject>
+                                <xsl:for-each select="marc:subfield[@code='a' or @code='b' or @code='c']">
+                                        <geographicCode>
+                                                <xsl:attribute name="authority">
+                                                        <xsl:if test="@code='a'">
+                                                                <xsl:text>marcgac</xsl:text>
+                                                        </xsl:if>
+                                                        <xsl:if test="@code='b'">
+                                                                <xsl:value-of select="following-sibling::marc:subfield[@code=2]"></xsl:value-of>
+                                                        </xsl:if>
+                                                        <xsl:if test="@code='c'">
+                                                                <xsl:text>iso3166</xsl:text>
+                                                        </xsl:if>
+                                                </xsl:attribute>
+                                                <xsl:value-of select="self::marc:subfield"></xsl:value-of>
+                                        </geographicCode>
+                                </xsl:for-each>
+                        </subject>
+                </xsl:for-each>
+                <!-- tmee 2006/11/27 -->
+                <xsl:for-each select="marc:datafield[@tag=255]">
+                        <subject>
+                                <xsl:for-each select="marc:subfield[@code='a' or @code='b' or @code='c']">
+                                <cartographics>
+                                        <xsl:if test="@code='a'">
+                                                <scale>
+                                                        <xsl:value-of select="."></xsl:value-of>
+                                                </scale>
+                                        </xsl:if>
+                                        <xsl:if test="@code='b'">
+                                                <projection>
+                                                        <xsl:value-of select="."></xsl:value-of>
+                                                </projection>
+                                        </xsl:if>
+                                        <xsl:if test="@code='c'">
+                                                <coordinates>
+                                                        <xsl:value-of select="."></xsl:value-of>
+                                                </coordinates>
+                                        </xsl:if>
+                                </cartographics>
+                                </xsl:for-each>
+                        </subject>
+                </xsl:for-each>
+
+                <xsl:apply-templates select="marc:datafield[653 >= @tag and @tag >= 600]"></xsl:apply-templates>
+                <xsl:apply-templates select="marc:datafield[@tag=656]"></xsl:apply-templates>
+                <xsl:for-each select="marc:datafield[@tag=752]">
+                        <subject>
+                                <hierarchicalGeographic>
+                                        <xsl:for-each select="marc:subfield[@code='a']">
+                                                <country>
+                                                        <xsl:call-template name="chopPunctuation">
+                                                                <xsl:with-param name="chopString" select="."></xsl:with-param>
+                                                        </xsl:call-template>
+                                                </country>
+                                        </xsl:for-each>
+                                        <xsl:for-each select="marc:subfield[@code='b']">
+                                                <state>
+                                                        <xsl:call-template name="chopPunctuation">
+                                                                <xsl:with-param name="chopString" select="."></xsl:with-param>
+                                                        </xsl:call-template>
+                                                </state>
+                                        </xsl:for-each>
+                                        <xsl:for-each select="marc:subfield[@code='c']">
+                                                <county>
+                                                        <xsl:call-template name="chopPunctuation">
+                                                                <xsl:with-param name="chopString" select="."></xsl:with-param>
+                                                        </xsl:call-template>
+                                                </county>
+                                        </xsl:for-each>
+                                        <xsl:for-each select="marc:subfield[@code='d']">
+                                                <city>
+                                                        <xsl:call-template name="chopPunctuation">
+                                                                <xsl:with-param name="chopString" select="."></xsl:with-param>
+                                                        </xsl:call-template>
+                                                </city>
+                                        </xsl:for-each>
+                                </hierarchicalGeographic>
+                        </subject>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=045][marc:subfield[@code='b']]">
+                        <subject>
+                                <xsl:choose>
+                                        <xsl:when test="@ind1=2">
+                                                <temporal encoding="iso8601" point="start">
+                                                        <xsl:call-template name="chopPunctuation">
+                                                                <xsl:with-param name="chopString">
+                                                                        <xsl:value-of select="marc:subfield[@code='b'][1]"></xsl:value-of>
+                                                                </xsl:with-param>
+                                                        </xsl:call-template>
+                                                </temporal>
+                                                <temporal encoding="iso8601" point="end">
+                                                        <xsl:call-template name="chopPunctuation">
+                                                                <xsl:with-param name="chopString">
+                                                                        <xsl:value-of select="marc:subfield[@code='b'][2]"></xsl:value-of>
+                                                                </xsl:with-param>
+                                                        </xsl:call-template>
+                                                </temporal>
+                                        </xsl:when>
+                                        <xsl:otherwise>
+                                                <xsl:for-each select="marc:subfield[@code='b']">
+                                                        <temporal encoding="iso8601">
+                                                                <xsl:call-template name="chopPunctuation">
+                                                                        <xsl:with-param name="chopString" select="."></xsl:with-param>
+                                                                </xsl:call-template>
+                                                        </temporal>
+                                                </xsl:for-each>
+                                        </xsl:otherwise>
+                                </xsl:choose>
+                        </subject>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=050]">
+                        <xsl:for-each select="marc:subfield[@code='b']">
+                                <classification authority="lcc">
+                                        <xsl:if test="../marc:subfield[@code='3']">
+                                                <xsl:attribute name="displayLabel">
+                                                        <xsl:value-of select="../marc:subfield[@code='3']"></xsl:value-of>
+                                                </xsl:attribute>
+                                        </xsl:if>
+                                        <xsl:value-of select="preceding-sibling::marc:subfield[@code='a'][1]"></xsl:value-of>
+                                        <xsl:text> </xsl:text>
+                                        <xsl:value-of select="text()"></xsl:value-of>
+                                </classification>
+                        </xsl:for-each>
+                        <xsl:for-each select="marc:subfield[@code='a'][not(following-sibling::marc:subfield[@code='b'])]">
+                                <classification authority="lcc">
+                                        <xsl:if test="../marc:subfield[@code='3']">
+                                                <xsl:attribute name="displayLabel">
+                                                        <xsl:value-of select="../marc:subfield[@code='3']"></xsl:value-of>
+                                                </xsl:attribute>
+                                        </xsl:if>
+                                        <xsl:value-of select="text()"></xsl:value-of>
+                                </classification>
+                        </xsl:for-each>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=082]">
+                        <classification authority="ddc">
+                                <xsl:if test="marc:subfield[@code='2']">
+                                        <xsl:attribute name="edition">
+                                                <xsl:value-of select="marc:subfield[@code='2']"></xsl:value-of>
+                                        </xsl:attribute>
+                                </xsl:if>
+                                <xsl:call-template name="subfieldSelect">
+                                        <xsl:with-param name="codes">ab</xsl:with-param>
+                                </xsl:call-template>
+                        </classification>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=080]">
+                        <classification authority="udc">
+                                <xsl:call-template name="subfieldSelect">
+                                        <xsl:with-param name="codes">abx</xsl:with-param>
+                                </xsl:call-template>
+                        </classification>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=060]">
+                        <classification authority="nlm">
+                                <xsl:call-template name="subfieldSelect">
+                                        <xsl:with-param name="codes">ab</xsl:with-param>
+                                </xsl:call-template>
+                        </classification>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=086][@ind1=0]">
+                        <classification authority="sudocs">
+                                <xsl:value-of select="marc:subfield[@code='a']"></xsl:value-of>
+                        </classification>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=086][@ind1=1]">
+                        <classification authority="candoc">
+                                <xsl:value-of select="marc:subfield[@code='a']"></xsl:value-of>
+                        </classification>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=086]">
+                        <classification>
+                                <xsl:attribute name="authority">
+                                        <xsl:value-of select="marc:subfield[@code='2']"></xsl:value-of>
+                                </xsl:attribute>
+                                <xsl:value-of select="marc:subfield[@code='a']"></xsl:value-of>
+                        </classification>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=084]">
+                        <classification>
+                                <xsl:attribute name="authority">
+                                        <xsl:value-of select="marc:subfield[@code='2']"></xsl:value-of>
+                                </xsl:attribute>
+                                <xsl:call-template name="subfieldSelect">
+                                        <xsl:with-param name="codes">ab</xsl:with-param>
+                                </xsl:call-template>
+                        </classification>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=440]">
+                        <relatedItem type="series">
+                                <xsl:variable name="titleChop">
+                                        <xsl:call-template name="chopPunctuation">
+                                                <xsl:with-param name="chopString">
+                                                        <xsl:call-template name="subfieldSelect">
+                                                                <xsl:with-param name="codes">av</xsl:with-param>
+                                                        </xsl:call-template>
+                                                </xsl:with-param>
+                                        </xsl:call-template>
+                                </xsl:variable>
+                                <titleInfo>
+                                        <title>
+                                                <xsl:value-of select="$titleChop" />
+                                        </title>
+                                        <xsl:call-template name="part"></xsl:call-template>
+                                </titleInfo>
+                                <titleInfo type="nfi">
+                                        <xsl:choose>
+                                                <xsl:when test="@ind2>0">
+                                                        <nonSort>
+                                                                <xsl:value-of select="substring($titleChop,1, at ind2)"/>
+                                                        </nonSort>
+                                                        <title>
+                                                                <xsl:value-of select="substring($titleChop, at ind2+1)"/>
+                                                        </title>
+                                                        <xsl:call-template name="part"/>
+                                                </xsl:when>
+                                                <xsl:otherwise>
+                                                        <title>
+                                                                <xsl:value-of select="$titleChop" />
+                                                        </title>
+                                                </xsl:otherwise>
+                                        </xsl:choose>
+                                        <xsl:call-template name="part"></xsl:call-template>
+                                </titleInfo>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=490][@ind1=0]">
+                        <relatedItem type="series">
+                                <titleInfo>
+                                        <title>
+                                                <xsl:call-template name="chopPunctuation">
+                                                        <xsl:with-param name="chopString">
+                                                                <xsl:call-template name="subfieldSelect">
+                                                                        <xsl:with-param name="codes">av</xsl:with-param>
+                                                                </xsl:call-template>
+                                                        </xsl:with-param>
+                                                </xsl:call-template>
+                                        </title>
+                                        <xsl:call-template name="part"></xsl:call-template>
+                                </titleInfo>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=510]">
+                        <relatedItem type="isReferencedBy">
+                                <note>
+                                        <xsl:call-template name="subfieldSelect">
+                                                <xsl:with-param name="codes">abcx3</xsl:with-param>
+                                        </xsl:call-template>
+                                </note>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=534]">
+                        <relatedItem type="original">
+                                <xsl:call-template name="relatedTitle"></xsl:call-template>
+                                <xsl:call-template name="relatedName"></xsl:call-template>
+                                <xsl:if test="marc:subfield[@code='b' or @code='c']">
+                                        <originInfo>
+                                                <xsl:for-each select="marc:subfield[@code='c']">
+                                                        <publisher>
+                                                                <xsl:value-of select="."></xsl:value-of>
+                                                        </publisher>
+                                                </xsl:for-each>
+                                                <xsl:for-each select="marc:subfield[@code='b']">
+                                                        <edition>
+                                                                <xsl:value-of select="."></xsl:value-of>
+                                                        </edition>
+                                                </xsl:for-each>
+                                        </originInfo>
+                                </xsl:if>
+                                <xsl:call-template name="relatedIdentifierISSN"></xsl:call-template>
+                                <xsl:for-each select="marc:subfield[@code='z']">
+                                        <identifier type="isbn">
+                                                <xsl:value-of select="."></xsl:value-of>
+                                        </identifier>
+                                </xsl:for-each>
+                                <xsl:call-template name="relatedNote"></xsl:call-template>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=700][marc:subfield[@code='t']]">
+                        <relatedItem>
+                                <xsl:call-template name="constituentOrRelatedType"></xsl:call-template>
+                                <titleInfo>
+                                        <title>
+                                                <xsl:call-template name="chopPunctuation">
+                                                        <xsl:with-param name="chopString">
+                                                                <xsl:call-template name="specialSubfieldSelect">
+                                                                        <xsl:with-param name="anyCodes">tfklmorsv</xsl:with-param>
+                                                                        <xsl:with-param name="axis">t</xsl:with-param>
+                                                                        <xsl:with-param name="afterCodes">g</xsl:with-param>
+                                                                </xsl:call-template>
+                                                        </xsl:with-param>
+                                                </xsl:call-template>
+                                        </title>
+                                        <xsl:call-template name="part"></xsl:call-template>
+                                </titleInfo>
+                                <name type="personal">
+                                        <namePart>
+                                                <xsl:call-template name="specialSubfieldSelect">
+                                                        <xsl:with-param name="anyCodes">aq</xsl:with-param>
+                                                        <xsl:with-param name="axis">t</xsl:with-param>
+                                                        <xsl:with-param name="beforeCodes">g</xsl:with-param>
+                                                </xsl:call-template>
+                                        </namePart>
+                                        <xsl:call-template name="termsOfAddress"></xsl:call-template>
+                                        <xsl:call-template name="nameDate"></xsl:call-template>
+                                        <xsl:call-template name="role"></xsl:call-template>
+                                </name>
+                                <xsl:call-template name="relatedForm"></xsl:call-template>
+                                <xsl:call-template name="relatedIdentifierISSN"></xsl:call-template>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=710][marc:subfield[@code='t']]">
+                        <relatedItem>
+                                <xsl:call-template name="constituentOrRelatedType"></xsl:call-template>
+                                <titleInfo>
+                                        <title>
+                                                <xsl:call-template name="chopPunctuation">
+                                                        <xsl:with-param name="chopString">
+                                                                <xsl:call-template name="specialSubfieldSelect">
+                                                                        <xsl:with-param name="anyCodes">tfklmorsv</xsl:with-param>
+                                                                        <xsl:with-param name="axis">t</xsl:with-param>
+                                                                        <xsl:with-param name="afterCodes">dg</xsl:with-param>
+                                                                </xsl:call-template>
+                                                        </xsl:with-param>
+                                                </xsl:call-template>
+                                        </title>
+                                        <xsl:call-template name="relatedPartNumName"></xsl:call-template>
+                                </titleInfo>
+                                <name type="corporate">
+                                        <xsl:for-each select="marc:subfield[@code='a']">
+                                                <namePart>
+                                                        <xsl:value-of select="."></xsl:value-of>
+                                                </namePart>
+                                        </xsl:for-each>
+                                        <xsl:for-each select="marc:subfield[@code='b']">
+                                                <namePart>
+                                                        <xsl:value-of select="."></xsl:value-of>
+                                                </namePart>
+                                        </xsl:for-each>
+                                        <xsl:variable name="tempNamePart">
+                                                <xsl:call-template name="specialSubfieldSelect">
+                                                        <xsl:with-param name="anyCodes">c</xsl:with-param>
+                                                        <xsl:with-param name="axis">t</xsl:with-param>
+                                                        <xsl:with-param name="beforeCodes">dgn</xsl:with-param>
+                                                </xsl:call-template>
+                                        </xsl:variable>
+                                        <xsl:if test="normalize-space($tempNamePart)">
+                                                <namePart>
+                                                        <xsl:value-of select="$tempNamePart"></xsl:value-of>
+                                                </namePart>
+                                        </xsl:if>
+                                        <xsl:call-template name="role"></xsl:call-template>
+                                </name>
+                                <xsl:call-template name="relatedForm"></xsl:call-template>
+                                <xsl:call-template name="relatedIdentifierISSN"></xsl:call-template>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=711][marc:subfield[@code='t']]">
+                        <relatedItem>
+                                <xsl:call-template name="constituentOrRelatedType"></xsl:call-template>
+                                <titleInfo>
+                                        <title>
+                                                <xsl:call-template name="chopPunctuation">
+                                                        <xsl:with-param name="chopString">
+                                                                <xsl:call-template name="specialSubfieldSelect">
+                                                                        <xsl:with-param name="anyCodes">tfklsv</xsl:with-param>
+                                                                        <xsl:with-param name="axis">t</xsl:with-param>
+                                                                        <xsl:with-param name="afterCodes">g</xsl:with-param>
+                                                                </xsl:call-template>
+                                                        </xsl:with-param>
+                                                </xsl:call-template>
+                                        </title>
+                                        <xsl:call-template name="relatedPartNumName"></xsl:call-template>
+                                </titleInfo>
+                                <name type="conference">
+                                        <namePart>
+                                                <xsl:call-template name="specialSubfieldSelect">
+                                                        <xsl:with-param name="anyCodes">aqdc</xsl:with-param>
+                                                        <xsl:with-param name="axis">t</xsl:with-param>
+                                                        <xsl:with-param name="beforeCodes">gn</xsl:with-param>
+                                                </xsl:call-template>
+                                        </namePart>
+                                </name>
+                                <xsl:call-template name="relatedForm"></xsl:call-template>
+                                <xsl:call-template name="relatedIdentifierISSN"></xsl:call-template>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=730][@ind2=2]">
+                        <relatedItem>
+                                <xsl:call-template name="constituentOrRelatedType"></xsl:call-template>
+                                <titleInfo>
+                                        <title>
+                                                <xsl:call-template name="chopPunctuation">
+                                                        <xsl:with-param name="chopString">
+                                                                <xsl:call-template name="subfieldSelect">
+                                                                        <xsl:with-param name="codes">adfgklmorsv</xsl:with-param>
+                                                                </xsl:call-template>
+                                                        </xsl:with-param>
+                                                </xsl:call-template>
+                                        </title>
+                                        <xsl:call-template name="part"></xsl:call-template>
+                                </titleInfo>
+                                <xsl:call-template name="relatedForm"></xsl:call-template>
+                                <xsl:call-template name="relatedIdentifierISSN"></xsl:call-template>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=740][@ind2=2]">
+                        <relatedItem>
+                                <xsl:call-template name="constituentOrRelatedType"></xsl:call-template>
+                                <xsl:variable name="titleChop">
+                                        <xsl:call-template name="chopPunctuation">
+                                                <xsl:with-param name="chopString">
+                                                        <xsl:value-of select="marc:subfield[@code='a']"></xsl:value-of>
+                                                </xsl:with-param>
+                                        </xsl:call-template>
+                                </xsl:variable>
+                                <titleInfo>
+                                        <title>
+                                                <xsl:value-of select="$titleChop" />
+                                        </title>
+                                        <xsl:call-template name="part"></xsl:call-template>
+                                </titleInfo>
+                                <titleInfo type="nfi">
+                                        <xsl:choose>
+                                                <xsl:when test="@ind1>0">
+                                                        <nonSort>
+                                                                <xsl:value-of select="substring($titleChop,1, at ind1)"/>
+                                                        </nonSort>
+                                                        <title>
+                                                                <xsl:value-of select="substring($titleChop, at ind1+1)"/>
+                                                        </title>
+                                                </xsl:when>
+                                                <xsl:otherwise>
+                                                        <title>
+                                                                <xsl:value-of select="$titleChop" />
+                                                        </title>
+                                                </xsl:otherwise>
+                                        </xsl:choose>
+                                        <xsl:call-template name="part"></xsl:call-template>
+                                </titleInfo>
+                                <xsl:call-template name="relatedForm"></xsl:call-template>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=760]|marc:datafield[@tag=762]">
+                        <relatedItem type="series">
+                                <xsl:call-template name="relatedItem76X-78X"></xsl:call-template>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=765]|marc:datafield[@tag=767]|marc:datafield[@tag=777]|marc:datafield[@tag=787]">
+                        <relatedItem>
+                                <xsl:call-template name="relatedItem76X-78X"></xsl:call-template>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=775]">
+                        <relatedItem type="otherVersion">
+                                <xsl:call-template name="relatedItem76X-78X"></xsl:call-template>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=770]|marc:datafield[@tag=774]">
+                        <relatedItem type="constituent">
+                                <xsl:call-template name="relatedItem76X-78X"></xsl:call-template>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=772]|marc:datafield[@tag=773]">
+                        <relatedItem type="host">
+                                <xsl:call-template name="relatedItem76X-78X"></xsl:call-template>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=776]">
+                        <relatedItem type="otherFormat">
+                                <xsl:call-template name="relatedItem76X-78X"></xsl:call-template>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=780]">
+                        <relatedItem type="preceding">
+                                <xsl:call-template name="relatedItem76X-78X"></xsl:call-template>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=785]">
+                        <relatedItem type="succeeding">
+                                <xsl:call-template name="relatedItem76X-78X"></xsl:call-template>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=786]">
+                        <relatedItem type="original">
+                                <xsl:call-template name="relatedItem76X-78X"></xsl:call-template>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=800]">
+                        <relatedItem type="series">
+                                <titleInfo>
+                                        <title>
+                                                <xsl:call-template name="chopPunctuation">
+                                                        <xsl:with-param name="chopString">
+                                                                <xsl:call-template name="specialSubfieldSelect">
+                                                                        <xsl:with-param name="anyCodes">tfklmorsv</xsl:with-param>
+                                                                        <xsl:with-param name="axis">t</xsl:with-param>
+                                                                        <xsl:with-param name="afterCodes">g</xsl:with-param>
+                                                                </xsl:call-template>
+                                                        </xsl:with-param>
+                                                </xsl:call-template>
+                                        </title>
+                                        <xsl:call-template name="part"></xsl:call-template>
+                                </titleInfo>
+                                <name type="personal">
+                                        <namePart>
+                                                <xsl:call-template name="chopPunctuation">
+                                                        <xsl:with-param name="chopString">
+                                                                <xsl:call-template name="specialSubfieldSelect">
+                                                                        <xsl:with-param name="anyCodes">aq</xsl:with-param>
+                                                                        <xsl:with-param name="axis">t</xsl:with-param>
+                                                                        <xsl:with-param name="beforeCodes">g</xsl:with-param>
+                                                                </xsl:call-template>
+                                                        </xsl:with-param>
+                                                </xsl:call-template>
+                                        </namePart>
+                                        <xsl:call-template name="termsOfAddress"></xsl:call-template>
+                                        <xsl:call-template name="nameDate"></xsl:call-template>
+                                        <xsl:call-template name="role"></xsl:call-template>
+                                </name>
+                                <xsl:call-template name="relatedForm"></xsl:call-template>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=810]">
+                        <relatedItem type="series">
+                                <titleInfo>
+                                        <title>
+                                                <xsl:call-template name="chopPunctuation">
+                                                        <xsl:with-param name="chopString">
+                                                                <xsl:call-template name="specialSubfieldSelect">
+                                                                        <xsl:with-param name="anyCodes">tfklmorsv</xsl:with-param>
+                                                                        <xsl:with-param name="axis">t</xsl:with-param>
+                                                                        <xsl:with-param name="afterCodes">dg</xsl:with-param>
+                                                                </xsl:call-template>
+                                                        </xsl:with-param>
+                                                </xsl:call-template>
+                                        </title>
+                                        <xsl:call-template name="relatedPartNumName"></xsl:call-template>
+                                </titleInfo>
+                                <name type="corporate">
+                                        <xsl:for-each select="marc:subfield[@code='a']">
+                                                <namePart>
+                                                        <xsl:value-of select="."></xsl:value-of>
+                                                </namePart>
+                                        </xsl:for-each>
+                                        <xsl:for-each select="marc:subfield[@code='b']">
+                                                <namePart>
+                                                        <xsl:value-of select="."></xsl:value-of>
+                                                </namePart>
+                                        </xsl:for-each>
+                                        <namePart>
+                                                <xsl:call-template name="specialSubfieldSelect">
+                                                        <xsl:with-param name="anyCodes">c</xsl:with-param>
+                                                        <xsl:with-param name="axis">t</xsl:with-param>
+                                                        <xsl:with-param name="beforeCodes">dgn</xsl:with-param>
+                                                </xsl:call-template>
+                                        </namePart>
+                                        <xsl:call-template name="role"></xsl:call-template>
+                                </name>
+                                <xsl:call-template name="relatedForm"></xsl:call-template>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=811]">
+                        <relatedItem type="series">
+                                <titleInfo>
+                                        <title>
+                                                <xsl:call-template name="chopPunctuation">
+                                                        <xsl:with-param name="chopString">
+                                                                <xsl:call-template name="specialSubfieldSelect">
+                                                                        <xsl:with-param name="anyCodes">tfklsv</xsl:with-param>
+                                                                        <xsl:with-param name="axis">t</xsl:with-param>
+                                                                        <xsl:with-param name="afterCodes">g</xsl:with-param>
+                                                                </xsl:call-template>
+                                                        </xsl:with-param>
+                                                </xsl:call-template>
+                                        </title>
+                                        <xsl:call-template name="relatedPartNumName"/>
+                                </titleInfo>
+                                <name type="conference">
+                                        <namePart>
+                                                <xsl:call-template name="specialSubfieldSelect">
+                                                        <xsl:with-param name="anyCodes">aqdc</xsl:with-param>
+                                                        <xsl:with-param name="axis">t</xsl:with-param>
+                                                        <xsl:with-param name="beforeCodes">gn</xsl:with-param>
+                                                </xsl:call-template>
+                                        </namePart>
+                                        <xsl:call-template name="role"/>
+                                </name>
+                                <xsl:call-template name="relatedForm"/>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag='830']">
+                        <relatedItem type="series">
+                                <xsl:variable name="titleChop">
+                                        <xsl:call-template name="chopPunctuation">
+                                                <xsl:with-param name="chopString">
+                                                        <xsl:call-template name="subfieldSelect">
+                                                                <xsl:with-param name="codes">adfgklmorsv</xsl:with-param>
+                                                        </xsl:call-template>
+                                                </xsl:with-param>
+                                        </xsl:call-template>
+                                </xsl:variable>
+                                <titleInfo>
+                                        <title>
+                                                <xsl:value-of select="$titleChop" />
+                                        </title>
+                                        <xsl:call-template name="part"/>
+                                </titleInfo>
+                                <titleInfo type="nfi">
+                                        <xsl:choose>
+                                                <xsl:when test="@ind2>0">
+                                                        <nonSort>
+                                                                <xsl:value-of select="substring($titleChop,1, at ind2)"/>
+                                                        </nonSort>
+                                                        <title>
+                                                                <xsl:value-of select="substring($titleChop, at ind2+1)"/>
+                                                        </title>
+                                                </xsl:when>
+                                                <xsl:otherwise>
+                                                        <title>
+                                                                <xsl:value-of select="$titleChop" />
+                                                        </title>
+                                                </xsl:otherwise>
+                                        </xsl:choose>
+                                        <xsl:call-template name="part"/>
+                                </titleInfo>
+                                <xsl:call-template name="relatedForm"/>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag='856'][@ind2='2']/marc:subfield[@code='q']">
+                        <relatedItem>
+                                <internetMediaType>
+                                        <xsl:value-of select="."/>
+                                </internetMediaType>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag='020']">
+                        <xsl:call-template name="isInvalid">
+                                <xsl:with-param name="type">isbn</xsl:with-param>
+                        </xsl:call-template>
+                        <xsl:if test="marc:subfield[@code='a']">
+                                <identifier type="isbn">
+                                        <xsl:value-of select="marc:subfield[@code='a']"/>
+                                </identifier>
+                        </xsl:if>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag='024'][@ind1='0']">
+                        <xsl:call-template name="isInvalid">
+                                <xsl:with-param name="type">isrc</xsl:with-param>
+                        </xsl:call-template>
+                        <xsl:if test="marc:subfield[@code='a']">
+                                <identifier type="isrc">
+                                        <xsl:value-of select="marc:subfield[@code='a']"/>
+                                </identifier>
+                        </xsl:if>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag='024'][@ind1='2']">
+                        <xsl:call-template name="isInvalid">
+                                <xsl:with-param name="type">ismn</xsl:with-param>
+                        </xsl:call-template>
+                        <xsl:if test="marc:subfield[@code='a']">
+                                <identifier type="ismn">
+                                        <xsl:value-of select="marc:subfield[@code='a']"/>
+                                </identifier>
+                        </xsl:if>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag='024'][@ind1='4']">
+                        <xsl:call-template name="isInvalid">
+                                <xsl:with-param name="type">sici</xsl:with-param>
+                        </xsl:call-template>
+                        <identifier type="sici">
+                                <xsl:call-template name="subfieldSelect">
+                                        <xsl:with-param name="codes">ab</xsl:with-param>
+                                </xsl:call-template>
+                        </identifier>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag='022']">
+                        <xsl:call-template name="isInvalid">
+                                <xsl:with-param name="type">issn</xsl:with-param>
+                        </xsl:call-template>
+                        <identifier type="issn">
+                                <xsl:value-of select="marc:subfield[@code='a']"/>
+                        </identifier>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag='010']">
+                        <xsl:call-template name="isInvalid">
+                                <xsl:with-param name="type">lccn</xsl:with-param>
+                        </xsl:call-template>
+                        <identifier type="lccn">
+                                <xsl:value-of select="normalize-space(marc:subfield[@code='a'])"/>
+                        </identifier>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag='028']">
+                        <identifier>
+                                <xsl:attribute name="type">
+                                        <xsl:choose>
+                                                <xsl:when test="@ind1='0'">issue number</xsl:when>
+                                                <xsl:when test="@ind1='1'">matrix number</xsl:when>
+                                                <xsl:when test="@ind1='2'">music plate</xsl:when>
+                                                <xsl:when test="@ind1='3'">music publisher</xsl:when>
+                                                <xsl:when test="@ind1='4'">videorecording identifier</xsl:when>
+                                        </xsl:choose>
+                                </xsl:attribute>
+                                <!--<xsl:call-template name="isInvalid"/>--> <!-- no $z in 028 -->
+                                <xsl:call-template name="subfieldSelect">
+                                        <xsl:with-param name="codes">
+                                                <xsl:choose>
+                                                        <xsl:when test="@ind1='0'">ba</xsl:when>
+                                                        <xsl:otherwise>ab</xsl:otherwise>
+                                                </xsl:choose>
+                                        </xsl:with-param>
+                                </xsl:call-template>
+                        </identifier>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag='037']">
+                        <identifier type="stock number">
+                                <!--<xsl:call-template name="isInvalid"/>--> <!-- no $z in 037 -->
+                                <xsl:call-template name="subfieldSelect">
+                                        <xsl:with-param name="codes">ab</xsl:with-param>
+                                </xsl:call-template>
+                        </identifier>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag='856'][marc:subfield[@code='u']]">
+                        <identifier>
+                                <xsl:attribute name="type">
+                                        <xsl:choose>
+                                                <xsl:when test="starts-with(marc:subfield[@code='u'],'urn:doi') or starts-with(marc:subfield[@code='u'],'doi')">doi</xsl:when>
+                                                <xsl:when test="starts-with(marc:subfield[@code='u'],'urn:hdl') or starts-with(marc:subfield[@code='u'],'hdl') or starts-with(marc:subfield[@code='u'],'http://hdl.loc.gov')">hdl</xsl:when>
+                                                <xsl:otherwise>uri</xsl:otherwise>
+                                        </xsl:choose>
+                                </xsl:attribute>
+                                <xsl:choose>
+                                        <xsl:when test="starts-with(marc:subfield[@code='u'],'urn:hdl') or starts-with(marc:subfield[@code='u'],'hdl') or starts-with(marc:subfield[@code='u'],'http://hdl.loc.gov') ">
+                                                <xsl:value-of select="concat('hdl:',substring-after(marc:subfield[@code='u'],'http://hdl.loc.gov/'))"></xsl:value-of>
+                                        </xsl:when>
+                                        <xsl:otherwise>
+                                                <xsl:value-of select="marc:subfield[@code='u']"></xsl:value-of>
+                                        </xsl:otherwise>
+                                </xsl:choose>
+                        </identifier>
+                        <xsl:if test="starts-with(marc:subfield[@code='u'],'urn:hdl') or starts-with(marc:subfield[@code='u'],'hdl')">
+                                <identifier type="hdl">
+                                        <xsl:if test="marc:subfield[@code='y' or @code='3' or @code='z']">
+                                                <xsl:attribute name="displayLabel">
+                                                        <xsl:call-template name="subfieldSelect">
+                                                                <xsl:with-param name="codes">y3z</xsl:with-param>
+                                                        </xsl:call-template>
+                                                </xsl:attribute>
+                                        </xsl:if>
+                                        <xsl:value-of select="concat('hdl:',substring-after(marc:subfield[@code='u'],'http://hdl.loc.gov/'))"></xsl:value-of>
+                                </identifier>
+                        </xsl:if>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=024][@ind1=1]">
+                        <identifier type="upc">
+                                <xsl:call-template name="isInvalid"/>
+                                <xsl:value-of select="marc:subfield[@code='a']"/>
+                        </identifier>
+                </xsl:for-each>
+                <!-- 1/04 fix added $y -->
+                <xsl:for-each select="marc:datafield[@tag=856][marc:subfield[@code='u']]">
+                        <location>
+                                <url>
+                                        <xsl:if test="marc:subfield[@code='y' or @code='3']">
+                                                <xsl:attribute name="displayLabel">
+                                                        <xsl:call-template name="subfieldSelect">
+                                                                <xsl:with-param name="codes">y3</xsl:with-param>
+                                                        </xsl:call-template>
+                                                </xsl:attribute>
+                                        </xsl:if>
+                                        <xsl:if test="marc:subfield[@code='z' ]">
+                                                <xsl:attribute name="note">
+                                                        <xsl:call-template name="subfieldSelect">
+                                                                <xsl:with-param name="codes">z</xsl:with-param>
+                                                        </xsl:call-template>
+                                                </xsl:attribute>
+                                        </xsl:if>
+                                        <xsl:value-of select="marc:subfield[@code='u']"></xsl:value-of>
+
+                                </url>
+                        </location>
+                </xsl:for-each>
+
+                        <!-- 3.2 change tmee 856z  -->
+
+
+                <xsl:for-each select="marc:datafield[@tag=852]">
+                        <location>
+                                <physicalLocation>
+                                        <xsl:call-template name="displayLabel"></xsl:call-template>
+                                        <xsl:call-template name="subfieldSelect">
+                                                <xsl:with-param name="codes">abje</xsl:with-param>
+                                        </xsl:call-template>
+                                </physicalLocation>
+                        </location>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=506]">
+                        <accessCondition type="restrictionOnAccess">
+                                <xsl:call-template name="subfieldSelect">
+                                        <xsl:with-param name="codes">abcd35</xsl:with-param>
+                                </xsl:call-template>
+                        </accessCondition>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=540]">
+                        <accessCondition type="useAndReproduction">
+                                <xsl:call-template name="subfieldSelect">
+                                        <xsl:with-param name="codes">abcde35</xsl:with-param>
+                                </xsl:call-template>
+                        </accessCondition>
+                </xsl:for-each>
+                <recordInfo>
+                        <xsl:for-each select="marc:datafield[@tag=040]">
+                                <recordContentSource authority="marcorg">
+                                        <xsl:value-of select="marc:subfield[@code='a']"></xsl:value-of>
+                                </recordContentSource>
+                        </xsl:for-each>
+                        <xsl:for-each select="marc:controlfield[@tag=008]">
+                                <recordCreationDate encoding="marc">
+                                        <xsl:value-of select="substring(.,1,6)"></xsl:value-of>
+                                </recordCreationDate>
+                        </xsl:for-each>
+                        <xsl:for-each select="marc:controlfield[@tag=005]">
+                                <recordChangeDate encoding="iso8601">
+                                        <xsl:value-of select="."></xsl:value-of>
+                                </recordChangeDate>
+                        </xsl:for-each>
+                        <xsl:for-each select="marc:controlfield[@tag=001]">
+                                <recordIdentifier>
+                                        <xsl:if test="../marc:controlfield[@tag=003]">
+                                                <xsl:attribute name="source">
+                                                        <xsl:value-of select="../marc:controlfield[@tag=003]"></xsl:value-of>
+                                                </xsl:attribute>
+                                        </xsl:if>
+                                        <xsl:value-of select="."></xsl:value-of>
+                                </recordIdentifier>
+                        </xsl:for-each>
+                        <xsl:for-each select="marc:datafield[@tag=040]/marc:subfield[@code='b']">
+                                <languageOfCataloging>
+                                        <languageTerm authority="iso639-2b" type="code">
+                                                <xsl:value-of select="."></xsl:value-of>
+                                        </languageTerm>
+                                </languageOfCataloging>
+                        </xsl:for-each>
+                </recordInfo>
+        </xsl:template>
+        <xsl:template name="displayForm">
+                <xsl:for-each select="marc:subfield[@code='c']">
+                        <displayForm>
+                                <xsl:value-of select="."></xsl:value-of>
+                        </displayForm>
+                </xsl:for-each>
+        </xsl:template>
+        <xsl:template name="affiliation">
+                <xsl:for-each select="marc:subfield[@code='u']">
+                        <affiliation>
+                                <xsl:value-of select="."></xsl:value-of>
+                        </affiliation>
+                </xsl:for-each>
+        </xsl:template>
+        <xsl:template name="uri">
+                <xsl:for-each select="marc:subfield[@code='u']">
+                        <xsl:attribute name="xlink:href">
+                                <xsl:value-of select="."></xsl:value-of>
+                        </xsl:attribute>
+                </xsl:for-each>
+                <xsl:for-each select="marc:subfield[@code='0']">
+                        <xsl:choose>
+                                <xsl:when test="contains(text(), ')')">
+                                        <xsl:attribute name="xlink:href">
+                                                <xsl:value-of select="substring-after(text(), ')')"></xsl:value-of>
+                                        </xsl:attribute>
+                                </xsl:when>
+                                <xsl:otherwise>
+                                        <xsl:attribute name="xlink:href">
+                                                <xsl:value-of select="."></xsl:value-of>
+                                        </xsl:attribute>
+                                </xsl:otherwise>
+                        </xsl:choose>
+                </xsl:for-each>
+        </xsl:template>
+        <xsl:template name="role">
+                <xsl:for-each select="marc:subfield[@code='e']">
+                        <role>
+                                <roleTerm type="text">
+                                        <xsl:value-of select="."></xsl:value-of>
+                                </roleTerm>
+                        </role>
+                </xsl:for-each>
+                <xsl:for-each select="marc:subfield[@code='4']">
+                        <role>
+                                <roleTerm authority="marcrelator" type="code">
+                                        <xsl:value-of select="."></xsl:value-of>
+                                </roleTerm>
+                        </role>
+                </xsl:for-each>
+        </xsl:template>
+        <xsl:template name="part">
+                <xsl:variable name="partNumber">
+                        <xsl:call-template name="specialSubfieldSelect">
+                                <xsl:with-param name="axis">n</xsl:with-param>
+                                <xsl:with-param name="anyCodes">n</xsl:with-param>
+                                <xsl:with-param name="afterCodes">fgkdlmor</xsl:with-param>
+                        </xsl:call-template>
+                </xsl:variable>
+                <xsl:variable name="partName">
+                        <xsl:call-template name="specialSubfieldSelect">
+                                <xsl:with-param name="axis">p</xsl:with-param>
+                                <xsl:with-param name="anyCodes">p</xsl:with-param>
+                                <xsl:with-param name="afterCodes">fgkdlmor</xsl:with-param>
+                        </xsl:call-template>
+                </xsl:variable>
+                <xsl:if test="string-length(normalize-space($partNumber))">
+                        <partNumber>
+                                <xsl:call-template name="chopPunctuation">
+                                        <xsl:with-param name="chopString" select="$partNumber"></xsl:with-param>
+                                </xsl:call-template>
+                        </partNumber>
+                </xsl:if>
+                <xsl:if test="string-length(normalize-space($partName))">
+                        <partName>
+                                <xsl:call-template name="chopPunctuation">
+                                        <xsl:with-param name="chopString" select="$partName"></xsl:with-param>
+                                </xsl:call-template>
+                        </partName>
+                </xsl:if>
+        </xsl:template>
+        <xsl:template name="relatedPart">
+                <xsl:if test="@tag=773">
+                        <xsl:for-each select="marc:subfield[@code='g']">
+                                <part>
+                                        <text>
+                                                <xsl:value-of select="."></xsl:value-of>
+                                        </text>
+                                </part>
+                        </xsl:for-each>
+                        <xsl:for-each select="marc:subfield[@code='q']">
+                                <part>
+                                        <xsl:call-template name="parsePart"></xsl:call-template>
+                                </part>
+                        </xsl:for-each>
+                </xsl:if>
+        </xsl:template>
+        <xsl:template name="relatedPartNumName">
+                <xsl:variable name="partNumber">
+                        <xsl:call-template name="specialSubfieldSelect">
+                                <xsl:with-param name="axis">g</xsl:with-param>
+                                <xsl:with-param name="anyCodes">g</xsl:with-param>
+                                <xsl:with-param name="afterCodes">pst</xsl:with-param>
+                        </xsl:call-template>
+                </xsl:variable>
+                <xsl:variable name="partName">
+                        <xsl:call-template name="specialSubfieldSelect">
+                                <xsl:with-param name="axis">p</xsl:with-param>
+                                <xsl:with-param name="anyCodes">p</xsl:with-param>
+                                <xsl:with-param name="afterCodes">fgkdlmor</xsl:with-param>
+                        </xsl:call-template>
+                </xsl:variable>
+                <xsl:if test="string-length(normalize-space($partNumber))">
+                        <partNumber>
+                                <xsl:value-of select="$partNumber"></xsl:value-of>
+                        </partNumber>
+                </xsl:if>
+                <xsl:if test="string-length(normalize-space($partName))">
+                        <partName>
+                                <xsl:value-of select="$partName"></xsl:value-of>
+                        </partName>
+                </xsl:if>
+        </xsl:template>
+        <xsl:template name="relatedName">
+                <xsl:for-each select="marc:subfield[@code='a']">
+                        <name>
+                                <namePart>
+                                        <xsl:value-of select="."></xsl:value-of>
+                                </namePart>
+                        </name>
+                </xsl:for-each>
+        </xsl:template>
+        <xsl:template name="relatedForm">
+                <xsl:for-each select="marc:subfield[@code='h']">
+                        <physicalDescription>
+                                <form>
+                                        <xsl:value-of select="."></xsl:value-of>
+                                </form>
+                        </physicalDescription>
+                </xsl:for-each>
+        </xsl:template>
+        <xsl:template name="relatedExtent">
+                <xsl:for-each select="marc:subfield[@code='h']">
+                        <physicalDescription>
+                                <extent>
+                                        <xsl:value-of select="."></xsl:value-of>
+                                </extent>
+                        </physicalDescription>
+                </xsl:for-each>
+        </xsl:template>
+        <xsl:template name="relatedNote">
+                <xsl:for-each select="marc:subfield[@code='n']">
+                        <note>
+                                <xsl:value-of select="."></xsl:value-of>
+                        </note>
+                </xsl:for-each>
+        </xsl:template>
+        <xsl:template name="relatedSubject">
+                <xsl:for-each select="marc:subfield[@code='j']">
+                        <subject>
+                                <temporal encoding="iso8601">
+                                        <xsl:call-template name="chopPunctuation">
+                                                <xsl:with-param name="chopString" select="."></xsl:with-param>
+                                        </xsl:call-template>
+                                </temporal>
+                        </subject>
+                </xsl:for-each>
+        </xsl:template>
+        <xsl:template name="relatedIdentifierISSN">
+                <xsl:for-each select="marc:subfield[@code='x']">
+                        <identifier type="issn">
+                                <xsl:value-of select="."></xsl:value-of>
+                        </identifier>
+                </xsl:for-each>
+        </xsl:template>
+        <xsl:template name="relatedIdentifierLocal">
+                <xsl:for-each select="marc:subfield[@code='w']">
+                        <identifier type="local">
+                                <xsl:value-of select="."></xsl:value-of>
+                        </identifier>
+                </xsl:for-each>
+        </xsl:template>
+        <xsl:template name="relatedIdentifier">
+                <xsl:for-each select="marc:subfield[@code='o']">
+                        <identifier>
+                                <xsl:value-of select="."></xsl:value-of>
+                        </identifier>
+                </xsl:for-each>
+        </xsl:template>
+        <xsl:template name="relatedItem76X-78X">
+                <xsl:call-template name="displayLabel"></xsl:call-template>
+                <xsl:call-template name="relatedTitle76X-78X"></xsl:call-template>
+                <xsl:call-template name="relatedName"></xsl:call-template>
+                <xsl:call-template name="relatedOriginInfo"></xsl:call-template>
+                <xsl:call-template name="relatedLanguage"></xsl:call-template>
+                <xsl:call-template name="relatedExtent"></xsl:call-template>
+                <xsl:call-template name="relatedNote"></xsl:call-template>
+                <xsl:call-template name="relatedSubject"></xsl:call-template>
+                <xsl:call-template name="relatedIdentifier"></xsl:call-template>
+                <xsl:call-template name="relatedIdentifierISSN"></xsl:call-template>
+                <xsl:call-template name="relatedIdentifierLocal"></xsl:call-template>
+                <xsl:call-template name="relatedPart"></xsl:call-template>
+        </xsl:template>
+        <xsl:template name="subjectGeographicZ">
+                <geographic>
+                        <xsl:call-template name="chopPunctuation">
+                                <xsl:with-param name="chopString" select="."></xsl:with-param>
+                        </xsl:call-template>
+                </geographic>
+        </xsl:template>
+        <xsl:template name="subjectTemporalY">
+                <temporal>
+                        <xsl:call-template name="chopPunctuation">
+                                <xsl:with-param name="chopString" select="."></xsl:with-param>
+                        </xsl:call-template>
+                </temporal>
+        </xsl:template>
+        <xsl:template name="subjectTopic">
+                <topic>
+                        <xsl:call-template name="chopPunctuation">
+                                <xsl:with-param name="chopString" select="."></xsl:with-param>
+                        </xsl:call-template>
+                </topic>
+        </xsl:template>
+        <!-- 3.2 change tmee 6xx $v genre -->
+        <xsl:template name="subjectGenre">
+                <genre>
+                        <xsl:call-template name="chopPunctuation">
+                                <xsl:with-param name="chopString" select="."></xsl:with-param>
+                        </xsl:call-template>
+                </genre>
+        </xsl:template>
+
+        <xsl:template name="nameABCDN">
+                <xsl:for-each select="marc:subfield[@code='a']">
+                        <namePart>
+                                <xsl:call-template name="chopPunctuation">
+                                        <xsl:with-param name="chopString" select="."></xsl:with-param>
+                                </xsl:call-template>
+                        </namePart>
+                </xsl:for-each>
+                <xsl:for-each select="marc:subfield[@code='b']">
+                        <namePart>
+                                <xsl:value-of select="."></xsl:value-of>
+                        </namePart>
+                </xsl:for-each>
+                <xsl:if test="marc:subfield[@code='c'] or marc:subfield[@code='d'] or marc:subfield[@code='n']">
+                        <namePart>
+                                <xsl:call-template name="subfieldSelect">
+                                        <xsl:with-param name="codes">cdn</xsl:with-param>
+                                </xsl:call-template>
+                        </namePart>
+                </xsl:if>
+        </xsl:template>
+        <xsl:template name="nameABCDQ">
+                <namePart>
+                        <xsl:call-template name="chopPunctuation">
+                                <xsl:with-param name="chopString">
+                                        <xsl:call-template name="subfieldSelect">
+                                                <xsl:with-param name="codes">aq</xsl:with-param>
+                                        </xsl:call-template>
+                                </xsl:with-param>
+                                <xsl:with-param name="punctuation">
+                                        <xsl:text>:,;/ </xsl:text>
+                                </xsl:with-param>
+                        </xsl:call-template>
+                </namePart>
+                <xsl:call-template name="termsOfAddress"></xsl:call-template>
+                <xsl:call-template name="nameDate"></xsl:call-template>
+        </xsl:template>
+        <xsl:template name="nameACDEQ">
+                <namePart>
+                        <xsl:call-template name="subfieldSelect">
+                                <xsl:with-param name="codes">acdeq</xsl:with-param>
+                        </xsl:call-template>
+                </namePart>
+        </xsl:template>
+        <xsl:template name="constituentOrRelatedType">
+                <xsl:if test="@ind2=2">
+                        <xsl:attribute name="type">constituent</xsl:attribute>
+                </xsl:if>
+        </xsl:template>
+        <xsl:template name="relatedTitle">
+                <xsl:for-each select="marc:subfield[@code='t']">
+                        <titleInfo>
+                                <title>
+                                        <xsl:call-template name="chopPunctuation">
+                                                <xsl:with-param name="chopString">
+                                                        <xsl:value-of select="."></xsl:value-of>
+                                                </xsl:with-param>
+                                        </xsl:call-template>
+                                </title>
+                        </titleInfo>
+                </xsl:for-each>
+        </xsl:template>
+        <xsl:template name="relatedTitle76X-78X">
+                <xsl:for-each select="marc:subfield[@code='t']">
+                        <titleInfo>
+                                <title>
+                                        <xsl:call-template name="chopPunctuation">
+                                                <xsl:with-param name="chopString">
+                                                        <xsl:value-of select="."></xsl:value-of>
+                                                </xsl:with-param>
+                                        </xsl:call-template>
+                                </title>
+                                <xsl:if test="marc:datafield[@tag!=773]and marc:subfield[@code='g']">
+                                        <xsl:call-template name="relatedPartNumName"></xsl:call-template>
+                                </xsl:if>
+                        </titleInfo>
+                </xsl:for-each>
+                <xsl:for-each select="marc:subfield[@code='p']">
+                        <titleInfo type="abbreviated">
+                                <title>
+                                        <xsl:call-template name="chopPunctuation">
+                                                <xsl:with-param name="chopString">
+                                                        <xsl:value-of select="."></xsl:value-of>
+                                                </xsl:with-param>
+                                        </xsl:call-template>
+                                </title>
+                                <xsl:if test="marc:datafield[@tag!=773]and marc:subfield[@code='g']">
+                                        <xsl:call-template name="relatedPartNumName"></xsl:call-template>
+                                </xsl:if>
+                        </titleInfo>
+                </xsl:for-each>
+                <xsl:for-each select="marc:subfield[@code='s']">
+                        <titleInfo type="uniform">
+                                <title>
+                                        <xsl:call-template name="chopPunctuation">
+                                                <xsl:with-param name="chopString">
+                                                        <xsl:value-of select="."></xsl:value-of>
+                                                </xsl:with-param>
+                                        </xsl:call-template>
+                                </title>
+                                <xsl:if test="marc:datafield[@tag!=773]and marc:subfield[@code='g']">
+                                        <xsl:call-template name="relatedPartNumName"></xsl:call-template>
+                                </xsl:if>
+                        </titleInfo>
+                </xsl:for-each>
+        </xsl:template>
+        <xsl:template name="relatedOriginInfo">
+                <xsl:if test="marc:subfield[@code='b' or @code='d'] or marc:subfield[@code='f']">
+                        <originInfo>
+                                <xsl:if test="@tag=775">
+                                        <xsl:for-each select="marc:subfield[@code='f']">
+                                                <place>
+                                                        <placeTerm>
+                                                                <xsl:attribute name="type">code</xsl:attribute>
+                                                                <xsl:attribute name="authority">marcgac</xsl:attribute>
+                                                                <xsl:value-of select="."></xsl:value-of>
+                                                        </placeTerm>
+                                                </place>
+                                        </xsl:for-each>
+                                </xsl:if>
+                                <xsl:for-each select="marc:subfield[@code='d']">
+                                        <publisher>
+                                                <xsl:value-of select="."></xsl:value-of>
+                                        </publisher>
+                                </xsl:for-each>
+                                <xsl:for-each select="marc:subfield[@code='b']">
+                                        <edition>
+                                                <xsl:value-of select="."></xsl:value-of>
+                                        </edition>
+                                </xsl:for-each>
+                        </originInfo>
+                </xsl:if>
+        </xsl:template>
+        <xsl:template name="relatedLanguage">
+                <xsl:for-each select="marc:subfield[@code='e']">
+                        <xsl:call-template name="getLanguage">
+                                <xsl:with-param name="langString">
+                                        <xsl:value-of select="."></xsl:value-of>
+                                </xsl:with-param>
+                        </xsl:call-template>
+                </xsl:for-each>
+        </xsl:template>
+        <xsl:template name="nameDate">
+                <xsl:for-each select="marc:subfield[@code='d']">
+                        <namePart type="date">
+                                <xsl:call-template name="chopPunctuation">
+                                        <xsl:with-param name="chopString" select="."></xsl:with-param>
+                                </xsl:call-template>
+                        </namePart>
+                </xsl:for-each>
+        </xsl:template>
+        <xsl:template name="subjectAuthority">
+                <xsl:if test="@ind2!=4">
+                        <xsl:if test="@ind2!=' '">
+                                <xsl:if test="@ind2!=8">
+                                        <xsl:if test="@ind2!=9">
+                                                <xsl:attribute name="authority">
+                                                        <xsl:choose>
+                                                                <xsl:when test="@ind2=0">lcsh</xsl:when>
+                                                                <xsl:when test="@ind2=1">lcshac</xsl:when>
+                                                                <xsl:when test="@ind2=2">mesh</xsl:when>
+                                                                <!-- 1/04 fix -->
+                                                                <xsl:when test="@ind2=3">nal</xsl:when>
+                                                                <xsl:when test="@ind2=5">csh</xsl:when>
+                                                                <xsl:when test="@ind2=6">rvm</xsl:when>
+                                                                <xsl:when test="@ind2=7">
+                                                                        <xsl:value-of select="marc:subfield[@code='2']"></xsl:value-of>
+                                                                </xsl:when>
+                                                        </xsl:choose>
+                                                </xsl:attribute>
+                                        </xsl:if>
+                                </xsl:if>
+                        </xsl:if>
+                </xsl:if>
+        </xsl:template>
+        <xsl:template name="subjectAnyOrder">
+                <xsl:for-each select="marc:subfield[@code='v' or @code='x' or @code='y' or @code='z']">
+                        <xsl:choose>
+                                <xsl:when test="@code='v'">
+                                        <xsl:call-template name="subjectGenre"></xsl:call-template>
+                                </xsl:when>
+                                <xsl:when test="@code='x'">
+                                        <xsl:call-template name="subjectTopic"></xsl:call-template>
+                                </xsl:when>
+                                <xsl:when test="@code='y'">
+                                        <xsl:call-template name="subjectTemporalY"></xsl:call-template>
+                                </xsl:when>
+                                <xsl:when test="@code='z'">
+                                        <xsl:call-template name="subjectGeographicZ"></xsl:call-template>
+                                </xsl:when>
+                        </xsl:choose>
+                </xsl:for-each>
+        </xsl:template>
+        <xsl:template name="specialSubfieldSelect">
+                <xsl:param name="anyCodes"></xsl:param>
+                <xsl:param name="axis"></xsl:param>
+                <xsl:param name="beforeCodes"></xsl:param>
+                <xsl:param name="afterCodes"></xsl:param>
+                <xsl:variable name="str">
+                        <xsl:for-each select="marc:subfield">
+                                <xsl:if test="contains($anyCodes, @code)      or (contains($beforeCodes, at code) and following-sibling::marc:subfield[@code=$axis])      or (contains($afterCodes, at code) and preceding-sibling::marc:subfield[@code=$axis])">
+                                        <xsl:value-of select="text()"></xsl:value-of>
+                                        <xsl:text> </xsl:text>
+                                </xsl:if>
+                        </xsl:for-each>
+                </xsl:variable>
+                <xsl:value-of select="substring($str,1,string-length($str)-1)"></xsl:value-of>
+        </xsl:template>
+
+        <!-- 3.2 change tmee 6xx $v genre -->
+        <xsl:template match="marc:datafield[@tag=600]">
+                <subject>
+                        <xsl:call-template name="subjectAuthority"></xsl:call-template>
+                        <name type="personal">
+                                <xsl:call-template name="uri" />
+                                <namePart>
+                                        <xsl:call-template name="chopPunctuation">
+                                                <xsl:with-param name="chopString">
+                                                        <xsl:call-template name="subfieldSelect">
+                                                                <xsl:with-param name="codes">aq</xsl:with-param>
+                                                        </xsl:call-template>
+                                                </xsl:with-param>
+                                        </xsl:call-template>
+                                </namePart>
+                                <xsl:call-template name="termsOfAddress"></xsl:call-template>
+                                <xsl:call-template name="nameDate"></xsl:call-template>
+                                <xsl:call-template name="affiliation"></xsl:call-template>
+                                <xsl:call-template name="role"></xsl:call-template>
+                        </name>
+                        <xsl:call-template name="subjectAnyOrder"></xsl:call-template>
+                </subject>
+        </xsl:template>
+        <xsl:template match="marc:datafield[@tag=610]">
+                <subject>
+                        <xsl:call-template name="subjectAuthority"></xsl:call-template>
+                        <name type="corporate">
+                                <xsl:call-template name="uri" />
+                                <xsl:for-each select="marc:subfield[@code='a']">
+                                        <namePart>
+                                                <xsl:value-of select="."></xsl:value-of>
+                                        </namePart>
+                                </xsl:for-each>
+                                <xsl:for-each select="marc:subfield[@code='b']">
+                                        <namePart>
+                                                <xsl:value-of select="."></xsl:value-of>
+                                        </namePart>
+                                </xsl:for-each>
+                                <xsl:if test="marc:subfield[@code='c' or @code='d' or @code='n' or @code='p']">
+                                        <namePart>
+                                                <xsl:call-template name="subfieldSelect">
+                                                        <xsl:with-param name="codes">cdnp</xsl:with-param>
+                                                </xsl:call-template>
+                                        </namePart>
+                                </xsl:if>
+                                <xsl:call-template name="role"></xsl:call-template>
+                        </name>
+                        <xsl:call-template name="subjectAnyOrder"></xsl:call-template>
+                </subject>
+        </xsl:template>
+        <xsl:template match="marc:datafield[@tag=611]">
+                <subject>
+                        <xsl:call-template name="subjectAuthority"></xsl:call-template>
+                        <name type="conference">
+                                <xsl:call-template name="uri" />
+                                <namePart>
+                                        <xsl:call-template name="subfieldSelect">
+                                                <xsl:with-param name="codes">abcdeqnp</xsl:with-param>
+                                        </xsl:call-template>
+                                </namePart>
+                                <xsl:for-each select="marc:subfield[@code='4']">
+                                        <role>
+                                                <roleTerm authority="marcrelator" type="code">
+                                                        <xsl:value-of select="."></xsl:value-of>
+                                                </roleTerm>
+                                        </role>
+                                </xsl:for-each>
+                        </name>
+                        <xsl:call-template name="subjectAnyOrder"></xsl:call-template>
+                </subject>
+        </xsl:template>
+        <xsl:template match="marc:datafield[@tag=630]">
+                <subject>
+                        <xsl:call-template name="subjectAuthority"></xsl:call-template>
+                        <xsl:variable name="titleChop">
+                                <xsl:call-template name="chopPunctuation">
+                                        <xsl:with-param name="chopString">
+                                                <xsl:call-template name="subfieldSelect">
+                                                        <xsl:with-param name="codes">adfhklor</xsl:with-param>
+                                                </xsl:call-template>
+                                        </xsl:with-param>
+                                </xsl:call-template>
+                        </xsl:variable>
+                        <titleInfo>
+                                <title>
+                                        <xsl:value-of select="$titleChop" />
+                                </title>
+                                <xsl:call-template name="part"></xsl:call-template>
+                        </titleInfo>
+                        <titleInfo type="nfi">
+                                <xsl:choose>
+                                        <xsl:when test="@ind1>0">
+                                                <nonSort>
+                                                        <xsl:value-of select="substring($titleChop,1, at ind1)"/>
+                                                </nonSort>
+                                                <title>
+                                                        <xsl:value-of select="substring($titleChop, at ind1+1)"/>
+                                                </title>
+                                                <xsl:call-template name="part"/>
+                                        </xsl:when>
+                                        <xsl:otherwise>
+                                                <title>
+                                                        <xsl:value-of select="$titleChop" />
+                                                </title>
+                                        </xsl:otherwise>
+                                </xsl:choose>
+                                <xsl:call-template name="part"></xsl:call-template>
+                        </titleInfo>
+                        <xsl:call-template name="subjectAnyOrder"></xsl:call-template>
+                </subject>
+        </xsl:template>
+        <xsl:template match="marc:datafield[@tag=650]">
+                <subject>
+                        <xsl:call-template name="subjectAuthority"></xsl:call-template>
+                        <topic>
+                                <xsl:call-template name="uri" />
+                                <xsl:call-template name="chopPunctuation">
+                                        <xsl:with-param name="chopString">
+                                                <xsl:call-template name="subfieldSelect">
+                                                        <xsl:with-param name="codes">abcd</xsl:with-param>
+                                                </xsl:call-template>
+                                        </xsl:with-param>
+                                </xsl:call-template>
+                        </topic>
+                        <xsl:call-template name="subjectAnyOrder"></xsl:call-template>
+                </subject>
+        </xsl:template>
+        <xsl:template match="marc:datafield[@tag=651]">
+                <subject>
+                        <xsl:call-template name="subjectAuthority"></xsl:call-template>
+                        <xsl:for-each select="marc:subfield[@code='a']">
+                                <geographic>
+                                        <xsl:call-template name="uri" />
+                                        <xsl:call-template name="chopPunctuation">
+                                                <xsl:with-param name="chopString" select="."></xsl:with-param>
+                                        </xsl:call-template>
+                                </geographic>
+                        </xsl:for-each>
+                        <xsl:call-template name="subjectAnyOrder"></xsl:call-template>
+                </subject>
+        </xsl:template>
+        <xsl:template match="marc:datafield[@tag=653]">
+                <subject>
+                        <xsl:for-each select="marc:subfield[@code='a']">
+                                <topic>
+                                        <xsl:call-template name="uri" />
+                                        <xsl:value-of select="."></xsl:value-of>
+                                </topic>
+                        </xsl:for-each>
+                </subject>
+        </xsl:template>
+        <xsl:template match="marc:datafield[@tag=656]">
+                <subject>
+                        <xsl:if test="marc:subfield[@code=2]">
+                                <xsl:attribute name="authority">
+                                        <xsl:value-of select="marc:subfield[@code=2]"></xsl:value-of>
+                                </xsl:attribute>
+                        </xsl:if>
+                        <occupation>
+                                <xsl:call-template name="uri" />
+                                <xsl:call-template name="chopPunctuation">
+                                        <xsl:with-param name="chopString">
+                                                <xsl:value-of select="marc:subfield[@code='a']"></xsl:value-of>
+                                        </xsl:with-param>
+                                </xsl:call-template>
+                        </occupation>
+                </subject>
+        </xsl:template>
+        <xsl:template name="termsOfAddress">
+                <xsl:if test="marc:subfield[@code='b' or @code='c']">
+                        <namePart type="termsOfAddress">
+                                <xsl:call-template name="chopPunctuation">
+                                        <xsl:with-param name="chopString">
+                                                <xsl:call-template name="subfieldSelect">
+                                                        <xsl:with-param name="codes">bc</xsl:with-param>
+                                                </xsl:call-template>
+                                        </xsl:with-param>
+                                </xsl:call-template>
+                        </namePart>
+                </xsl:if>
+        </xsl:template>
+        <xsl:template name="displayLabel">
+                <xsl:if test="marc:subfield[@code='i']">
+                        <xsl:attribute name="displayLabel">
+                                <xsl:value-of select="marc:subfield[@code='i']"></xsl:value-of>
+                        </xsl:attribute>
+                </xsl:if>
+                <xsl:if test="marc:subfield[@code='3']">
+                        <xsl:attribute name="displayLabel">
+                                <xsl:value-of select="marc:subfield[@code='3']"></xsl:value-of>
+                        </xsl:attribute>
+                </xsl:if>
+        </xsl:template>
+        <xsl:template name="isInvalid">
+                <xsl:param name="type"/>
+                <xsl:if test="marc:subfield[@code='z'] or marc:subfield[@code='y']">
+                        <identifier>
+                                <xsl:attribute name="type">
+                                        <xsl:value-of select="$type"/>
+                                </xsl:attribute>
+                                <xsl:attribute name="invalid">
+                                        <xsl:text>yes</xsl:text>
+                                </xsl:attribute>
+                                <xsl:if test="marc:subfield[@code='z']">
+                                        <xsl:value-of select="marc:subfield[@code='z']"/>
+                                </xsl:if>
+                                <xsl:if test="marc:subfield[@code='y']">
+                                        <xsl:value-of select="marc:subfield[@code='y']"/>
+                                </xsl:if>
+                        </identifier>
+                </xsl:if>
+        </xsl:template>
+        <xsl:template name="subtitle">
+                <xsl:if test="marc:subfield[@code='b']">
+                        <subTitle>
+                                <xsl:call-template name="chopPunctuation">
+                                        <xsl:with-param name="chopString">
+                                                <xsl:value-of select="marc:subfield[@code='b']"/>
+                                                <!--<xsl:call-template name="subfieldSelect">
+                                                        <xsl:with-param name="codes">b</xsl:with-param>
+                                                </xsl:call-template>-->
+                                        </xsl:with-param>
+                                </xsl:call-template>
+                        </subTitle>
+                </xsl:if>
+        </xsl:template>
+        <xsl:template name="script">
+                <xsl:param name="scriptCode"></xsl:param>
+                <xsl:attribute name="script">
+                        <xsl:choose>
+                                <xsl:when test="$scriptCode='(3'">Arabic</xsl:when>
+                                <xsl:when test="$scriptCode='(B'">Latin</xsl:when>
+                                <xsl:when test="$scriptCode='$1'">Chinese, Japanese, Korean</xsl:when>
+                                <xsl:when test="$scriptCode='(N'">Cyrillic</xsl:when>
+                                <xsl:when test="$scriptCode='(2'">Hebrew</xsl:when>
+                                <xsl:when test="$scriptCode='(S'">Greek</xsl:when>
+                        </xsl:choose>
+                </xsl:attribute>
+        </xsl:template>
+        <xsl:template name="parsePart">
+                <!-- assumes 773$q= 1:2:3<4
+                     with up to 3 levels and one optional start page
+                -->
+                <xsl:variable name="level1">
+                        <xsl:choose>
+                                <xsl:when test="contains(text(),':')">
+                                        <!-- 1:2 -->
+                                        <xsl:value-of select="substring-before(text(),':')"></xsl:value-of>
+                                </xsl:when>
+                                <xsl:when test="not(contains(text(),':'))">
+                                        <!-- 1 or 1<3 -->
+                                        <xsl:if test="contains(text(),'<')">
+                                                <!-- 1<3 -->
+                                                <xsl:value-of select="substring-before(text(),'<')"></xsl:value-of>
+                                        </xsl:if>
+                                        <xsl:if test="not(contains(text(),'<'))">
+                                                <!-- 1 -->
+                                                <xsl:value-of select="text()"></xsl:value-of>
+                                        </xsl:if>
+                                </xsl:when>
+                        </xsl:choose>
+                </xsl:variable>
+                <xsl:variable name="sici2">
+                        <xsl:choose>
+                                <xsl:when test="starts-with(substring-after(text(),$level1),':')">
+                                        <xsl:value-of select="substring(substring-after(text(),$level1),2)"></xsl:value-of>
+                                </xsl:when>
+                                <xsl:otherwise>
+                                        <xsl:value-of select="substring-after(text(),$level1)"></xsl:value-of>
+                                </xsl:otherwise>
+                        </xsl:choose>
+                </xsl:variable>
+                <xsl:variable name="level2">
+                        <xsl:choose>
+                                <xsl:when test="contains($sici2,':')">
+                                        <!--  2:3<4  -->
+                                        <xsl:value-of select="substring-before($sici2,':')"></xsl:value-of>
+                                </xsl:when>
+                                <xsl:when test="contains($sici2,'<')">
+                                        <!-- 1: 2<4 -->
+                                        <xsl:value-of select="substring-before($sici2,'<')"></xsl:value-of>
+                                </xsl:when>
+                                <xsl:otherwise>
+                                        <xsl:value-of select="$sici2"></xsl:value-of>
+                                        <!-- 1:2 -->
+                                </xsl:otherwise>
+                        </xsl:choose>
+                </xsl:variable>
+                <xsl:variable name="sici3">
+                        <xsl:choose>
+                                <xsl:when test="starts-with(substring-after($sici2,$level2),':')">
+                                        <xsl:value-of select="substring(substring-after($sici2,$level2),2)"></xsl:value-of>
+                                </xsl:when>
+                                <xsl:otherwise>
+                                        <xsl:value-of select="substring-after($sici2,$level2)"></xsl:value-of>
+                                </xsl:otherwise>
+                        </xsl:choose>
+                </xsl:variable>
+                <xsl:variable name="level3">
+                        <xsl:choose>
+                                <xsl:when test="contains($sici3,'<')">
+                                        <!-- 2<4 -->
+                                        <xsl:value-of select="substring-before($sici3,'<')"></xsl:value-of>
+                                </xsl:when>
+                                <xsl:otherwise>
+                                        <xsl:value-of select="$sici3"></xsl:value-of>
+                                        <!-- 3 -->
+                                </xsl:otherwise>
+                        </xsl:choose>
+                </xsl:variable>
+                <xsl:variable name="page">
+                        <xsl:if test="contains(text(),'<')">
+                                <xsl:value-of select="substring-after(text(),'<')"></xsl:value-of>
+                        </xsl:if>
+                </xsl:variable>
+                <xsl:if test="$level1">
+                        <detail level="1">
+                                <number>
+                                        <xsl:value-of select="$level1"></xsl:value-of>
+                                </number>
+                        </detail>
+                </xsl:if>
+                <xsl:if test="$level2">
+                        <detail level="2">
+                                <number>
+                                        <xsl:value-of select="$level2"></xsl:value-of>
+                                </number>
+                        </detail>
+                </xsl:if>
+                <xsl:if test="$level3">
+                        <detail level="3">
+                                <number>
+                                        <xsl:value-of select="$level3"></xsl:value-of>
+                                </number>
+                        </detail>
+                </xsl:if>
+                <xsl:if test="$page">
+                        <extent unit="page">
+                                <start>
+                                        <xsl:value-of select="$page"></xsl:value-of>
+                                </start>
+                        </extent>
+                </xsl:if>
+        </xsl:template>
+        <xsl:template name="getLanguage">
+                <xsl:param name="langString"></xsl:param>
+                <xsl:param name="controlField008-35-37"></xsl:param>
+                <xsl:variable name="length" select="string-length($langString)"></xsl:variable>
+                <xsl:choose>
+                        <xsl:when test="$length=0"></xsl:when>
+                        <xsl:when test="$controlField008-35-37=substring($langString,1,3)">
+                                <xsl:call-template name="getLanguage">
+                                        <xsl:with-param name="langString" select="substring($langString,4,$length)"></xsl:with-param>
+                                        <xsl:with-param name="controlField008-35-37" select="$controlField008-35-37"></xsl:with-param>
+                                </xsl:call-template>
+                        </xsl:when>
+                        <xsl:otherwise>
+                                <language>
+                                        <languageTerm authority="iso639-2b" type="code">
+                                                <xsl:value-of select="substring($langString,1,3)"></xsl:value-of>
+                                        </languageTerm>
+                                </language>
+                                <xsl:call-template name="getLanguage">
+                                        <xsl:with-param name="langString" select="substring($langString,4,$length)"></xsl:with-param>
+                                        <xsl:with-param name="controlField008-35-37" select="$controlField008-35-37"></xsl:with-param>
+                                </xsl:call-template>
+                        </xsl:otherwise>
+                </xsl:choose>
+        </xsl:template>
+        <xsl:template name="isoLanguage">
+                <xsl:param name="currentLanguage"></xsl:param>
+                <xsl:param name="usedLanguages"></xsl:param>
+                <xsl:param name="remainingLanguages"></xsl:param>
+                <xsl:choose>
+                        <xsl:when test="string-length($currentLanguage)=0"></xsl:when>
+                        <xsl:when test="not(contains($usedLanguages, $currentLanguage))">
+                                <language>
+                                        <xsl:if test="@code!='a'">
+                                                <xsl:attribute name="objectPart">
+                                                        <xsl:choose>
+                                                                <xsl:when test="@code='b'">summary or subtitle</xsl:when>
+                                                                <xsl:when test="@code='d'">sung or spoken text</xsl:when>
+                                                                <xsl:when test="@code='e'">libretto</xsl:when>
+                                                                <xsl:when test="@code='f'">table of contents</xsl:when>
+                                                                <xsl:when test="@code='g'">accompanying material</xsl:when>
+                                                                <xsl:when test="@code='h'">translation</xsl:when>
+                                                        </xsl:choose>
+                                                </xsl:attribute>
+                                        </xsl:if>
+                                        <languageTerm authority="iso639-2b" type="code">
+                                                <xsl:value-of select="$currentLanguage"></xsl:value-of>
+                                        </languageTerm>
+                                </language>
+                                <xsl:call-template name="isoLanguage">
+                                        <xsl:with-param name="currentLanguage">
+                                                <xsl:value-of select="substring($remainingLanguages,1,3)"></xsl:value-of>
+                                        </xsl:with-param>
+                                        <xsl:with-param name="usedLanguages">
+                                                <xsl:value-of select="concat($usedLanguages,$currentLanguage)"></xsl:value-of>
+                                        </xsl:with-param>
+                                        <xsl:with-param name="remainingLanguages">
+                                                <xsl:value-of select="substring($remainingLanguages,4,string-length($remainingLanguages))"></xsl:value-of>
+                                        </xsl:with-param>
+                                </xsl:call-template>
+                        </xsl:when>
+                        <xsl:otherwise>
+                                <xsl:call-template name="isoLanguage">
+                                        <xsl:with-param name="currentLanguage">
+                                                <xsl:value-of select="substring($remainingLanguages,1,3)"></xsl:value-of>
+                                        </xsl:with-param>
+                                        <xsl:with-param name="usedLanguages">
+                                                <xsl:value-of select="concat($usedLanguages,$currentLanguage)"></xsl:value-of>
+                                        </xsl:with-param>
+                                        <xsl:with-param name="remainingLanguages">
+                                                <xsl:value-of select="substring($remainingLanguages,4,string-length($remainingLanguages))"></xsl:value-of>
+                                        </xsl:with-param>
+                                </xsl:call-template>
+                        </xsl:otherwise>
+                </xsl:choose>
+        </xsl:template>
+        <xsl:template name="chopBrackets">
+                <xsl:param name="chopString"></xsl:param>
+                <xsl:variable name="string">
+                        <xsl:call-template name="chopPunctuation">
+                                <xsl:with-param name="chopString" select="$chopString"></xsl:with-param>
+                        </xsl:call-template>
+                </xsl:variable>
+                <xsl:if test="substring($string, 1,1)='['">
+                        <xsl:value-of select="substring($string,2, string-length($string)-2)"></xsl:value-of>
+                </xsl:if>
+                <xsl:if test="substring($string, 1,1)!='['">
+                        <xsl:value-of select="$string"></xsl:value-of>
+                </xsl:if>
+        </xsl:template>
+        <xsl:template name="rfcLanguages">
+                <xsl:param name="nodeNum"></xsl:param>
+                <xsl:param name="usedLanguages"></xsl:param>
+                <xsl:param name="controlField008-35-37"></xsl:param>
+                <xsl:variable name="currentLanguage" select="."></xsl:variable>
+                <xsl:choose>
+                        <xsl:when test="not($currentLanguage)"></xsl:when>
+                        <xsl:when test="$currentLanguage!=$controlField008-35-37 and $currentLanguage!='rfc3066'">
+                                <xsl:if test="not(contains($usedLanguages,$currentLanguage))">
+                                        <language>
+                                                <xsl:if test="@code!='a'">
+                                                        <xsl:attribute name="objectPart">
+                                                                <xsl:choose>
+                                                                        <xsl:when test="@code='b'">summary or subtitle</xsl:when>
+                                                                        <xsl:when test="@code='d'">sung or spoken text</xsl:when>
+                                                                        <xsl:when test="@code='e'">libretto</xsl:when>
+                                                                        <xsl:when test="@code='f'">table of contents</xsl:when>
+                                                                        <xsl:when test="@code='g'">accompanying material</xsl:when>
+                                                                        <xsl:when test="@code='h'">translation</xsl:when>
+                                                                </xsl:choose>
+                                                        </xsl:attribute>
+                                                </xsl:if>
+                                                <languageTerm authority="rfc3066" type="code">
+                                                        <xsl:value-of select="$currentLanguage"/>
+                                                </languageTerm>
+                                        </language>
+                                </xsl:if>
+                        </xsl:when>
+                        <xsl:otherwise>
+                        </xsl:otherwise>
+                </xsl:choose>
+        </xsl:template>
+        <xsl:template name="datafield">
+                <xsl:param name="tag"/>
+                <xsl:param name="ind1"><xsl:text> </xsl:text></xsl:param>
+                <xsl:param name="ind2"><xsl:text> </xsl:text></xsl:param>
+                <xsl:param name="subfields"/>
+                <xsl:element name="marc:datafield">
+                        <xsl:attribute name="tag">
+                                <xsl:value-of select="$tag"/>
+                        </xsl:attribute>
+                        <xsl:attribute name="ind1">
+                                <xsl:value-of select="$ind1"/>
+                        </xsl:attribute>
+                        <xsl:attribute name="ind2">
+                                <xsl:value-of select="$ind2"/>
+                        </xsl:attribute>
+                        <xsl:copy-of select="$subfields"/>
+                </xsl:element>
+        </xsl:template>
+
+        <xsl:template name="subfieldSelect">
+                <xsl:param name="codes"/>
+                <xsl:param name="delimeter"><xsl:text> </xsl:text></xsl:param>
+                <xsl:variable name="str">
+                        <xsl:for-each select="marc:subfield">
+                                <xsl:if test="contains($codes, @code)">
+                                        <xsl:value-of select="text()"/><xsl:value-of select="$delimeter"/>
+                                </xsl:if>
+                        </xsl:for-each>
+                </xsl:variable>
+                <xsl:value-of select="substring($str,1,string-length($str)-string-length($delimeter))"/>
+        </xsl:template>
+
+        <xsl:template name="buildSpaces">
+                <xsl:param name="spaces"/>
+                <xsl:param name="char"><xsl:text> </xsl:text></xsl:param>
+                <xsl:if test="$spaces>0">
+                        <xsl:value-of select="$char"/>
+                        <xsl:call-template name="buildSpaces">
+                                <xsl:with-param name="spaces" select="$spaces - 1"/>
+                                <xsl:with-param name="char" select="$char"/>
+                        </xsl:call-template>
+                </xsl:if>
+        </xsl:template>
+
+        <xsl:template name="chopPunctuation">
+                <xsl:param name="chopString"/>
+                <xsl:param name="punctuation"><xsl:text>.:,;/ </xsl:text></xsl:param>
+                <xsl:variable name="length" select="string-length($chopString)"/>
+                <xsl:choose>
+                        <xsl:when test="$length=0"/>
+                        <xsl:when test="contains($punctuation, substring($chopString,$length,1))">
+                                <xsl:call-template name="chopPunctuation">
+                                        <xsl:with-param name="chopString" select="substring($chopString,1,$length - 1)"/>
+                                        <xsl:with-param name="punctuation" select="$punctuation"/>
+                                </xsl:call-template>
+                        </xsl:when>
+                        <xsl:when test="not($chopString)"/>
+                        <xsl:otherwise><xsl:value-of select="$chopString"/></xsl:otherwise>
+                </xsl:choose>
+        </xsl:template>
+
+        <xsl:template name="chopPunctuationFront">
+                <xsl:param name="chopString"/>
+                <xsl:variable name="length" select="string-length($chopString)"/>
+                <xsl:choose>
+                        <xsl:when test="$length=0"/>
+                        <xsl:when test="contains('.:,;/[ ', substring($chopString,1,1))">
+                                <xsl:call-template name="chopPunctuationFront">
+                                        <xsl:with-param name="chopString" select="substring($chopString,2,$length - 1)"/>
+                                </xsl:call-template>
+                        </xsl:when>
+                        <xsl:when test="not($chopString)"/>
+                        <xsl:otherwise><xsl:value-of select="$chopString"/></xsl:otherwise>
+                </xsl:choose>
+        </xsl:template>
+</xsl:stylesheet>$XXXX$ where name = $$mods32$$;
+
+update config.xml_transform set xslt = $XXXX$<xsl:stylesheet xmlns="http://www.loc.gov/mods/v3" xmlns:marc="http://www.loc.gov/MARC21/slim"
+        xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+        exclude-result-prefixes="xlink marc" version="1.0">
+        <xsl:output encoding="UTF-8" indent="yes" method="xml"/>
+
+        <xsl:variable name="ascii">
+                <xsl:text> !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~</xsl:text>
+        </xsl:variable>
+
+        <xsl:variable name="latin1">
+                <xsl:text> ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ</xsl:text>
+        </xsl:variable>
+        <!-- Characters that usually don't need to be escaped -->
+        <xsl:variable name="safe">
+                <xsl:text>!'()*-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~</xsl:text>
+        </xsl:variable>
+
+        <xsl:variable name="hex">0123456789ABCDEF</xsl:variable>
+
+    <!-- Evergreen specific: revert Revision 1.23, so we can have those authority xlink attributes back. -->
+
+        <!--MARC21slim2MODS3-3.xsl
+Revision 1.27 - Mapped 648 to <subject> 2009/03/13 tmee
+Revision 1.26 - Added subfield $s mapping for 130/240/730  2008/10/16 tmee
+Revision 1.25 - Mapped 040e to <descriptiveStandard> and Leader/18 to <descriptive standard>aacr2  2008/09/18 tmee
+Revision 1.24 - Mapped 852 subfields $h, $i, $j, $k, $l, $m, $t to <shelfLocation> and 852 subfield $u to <physicalLocation> with @xlink 2008/09/17 tmee
+Revision 1.23 - Commented out xlink/uri for subfield 0 for 130/240/730, 100/700, 110/710, 111/711 as these are currently unactionable  2008/09/17  tmee
+Revision 1.22 - Mapped 022 subfield $l to type "issn-l" subfield $m to output identifier element with corresponding @type and @invalid eq 'yes'2008/09/17  tmee
+Revision 1.21 - Mapped 856 ind2=1 or ind2=2 to <relatedItem><location><url>  2008/07/03  tmee
+Revision 1.20 - Added genre w/@auth="contents of 2" and type= "musical composition"  2008/07/01  tmee
+Revision 1.19 - Added genre offprint for 008/24+ BK code 2  2008/07/01  tmee
+Revision 1.18 - Added xlink/uri for subfield 0 for 130/240/730, 100/700, 110/710, 111/711  2008/06/26  tmee
+Revision 1.17 - Added mapping of 662 2008/05/14 tmee
+Revision 1.16 - Changed @authority from "marc" to "marcgt" for 007 and 008 codes mapped to a term in <genre> 2007/07/10  tmee
+Revision 1.15 - For field 630, moved call to part template outside title element  2007/07/10  tmee
+Revision 1.14 - Fixed template isValid and fields 010, 020, 022, 024, 028, and 037 to output additional identifier elements with corresponding @type and @invalid eq 'yes' when subfields z or y (in the case of 022) exist in the MARCXML ::: 2007/01/04 17:35:20 cred
+Revision 1.13 - Changed order of output under cartographics to reflect schema  2006/11/28  tmee
+Revision 1.12 - Updated to reflect MODS 3.2 Mapping  2006/10/11  tmee
+Revision 1.11 - The attribute objectPart moved from <languageTerm> to <language>  2006/04/08  jrad
+Revision 1.10 - MODS 3.1 revisions to language and classification elements  (plus ability to find marc:collection embedded in wrapper elements such as SRU zs: wrappers)  2006/02/06  ggar
+Revision 1.9 - Subfield $y was added to field 242 2004/09/02 10:57 jrad
+Revision 1.8 - Subject chopPunctuation expanded and attribute fixes 2004/08/12 jrad
+Revision 1.7 - 2004/03/25 08:29 jrad
+Revision 1.6 - Various validation fixes 2004/02/20 ntra
+Revision 1.5 - MODS2 to MODS3 updates, language unstacking and de-duping, chopPunctuation expanded  2003/10/02 16:18:58  ntra
+Revision 1.3 - Additional Changes not related to MODS Version 2.0 by ntra
+Revision 1.2 - Added Log Comment  2003/03/24 19:37:42  ckeith
+-->
+        <xsl:template match="/">
+                <xsl:choose>
+                        <xsl:when test="//marc:collection">
+                                <modsCollection xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+                                        xsi:schemaLocation="http://www.loc.gov/mods/v3 http://www.loc.gov/standards/mods/v3/mods-3-2.xsd">
+                                        <xsl:for-each select="//marc:collection/marc:record">
+                                                <mods version="3.3">
+                                                        <xsl:call-template name="marcRecord"/>
+                                                </mods>
+                                        </xsl:for-each>
+                                </modsCollection>
+                        </xsl:when>
+                        <xsl:otherwise>
+                                <mods xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.3"
+                                        xsi:schemaLocation="http://www.loc.gov/mods/v3 http://www.loc.gov/standards/mods/v3/mods-3-2.xsd">
+                                        <xsl:for-each select="//marc:record">
+                                                <xsl:call-template name="marcRecord"/>
+                                        </xsl:for-each>
+                                </mods>
+                        </xsl:otherwise>
+                </xsl:choose>
+        </xsl:template>
+        <xsl:template name="marcRecord">
+                <xsl:variable name="leader" select="marc:leader"/>
+                <xsl:variable name="leader6" select="substring($leader,7,1)"/>
+                <xsl:variable name="leader7" select="substring($leader,8,1)"/>
+                <xsl:variable name="controlField008" select="marc:controlfield[@tag='008']"/>
+                <xsl:variable name="typeOf008">
+                        <xsl:choose>
+                                <xsl:when test="$leader6='a'">
+                                        <xsl:choose>
+                                                <xsl:when
+                                                        test="$leader7='a' or $leader7='c' or $leader7='d' or $leader7='m'">BK</xsl:when>
+                                                <xsl:when test="$leader7='b' or $leader7='i' or $leader7='s'">SE</xsl:when>
+                                        </xsl:choose>
+                                </xsl:when>
+                                <xsl:when test="$leader6='t'">BK</xsl:when>
+                                <xsl:when test="$leader6='p'">MM</xsl:when>
+                                <xsl:when test="$leader6='m'">CF</xsl:when>
+                                <xsl:when test="$leader6='e' or $leader6='f'">MP</xsl:when>
+                                <xsl:when test="$leader6='g' or $leader6='k' or $leader6='o' or $leader6='r'">VM</xsl:when>
+                                <xsl:when test="$leader6='c' or $leader6='d' or $leader6='i' or $leader6='j'"
+                                >MU</xsl:when>
+                        </xsl:choose>
+                </xsl:variable>
+                <xsl:for-each select="marc:datafield[@tag='245']">
+                        <titleInfo>
+                                <xsl:variable name="title">
+                                        <xsl:choose>
+                                                <xsl:when test="marc:subfield[@code='b']">
+                                                        <xsl:call-template name="specialSubfieldSelect">
+                                                                <xsl:with-param name="axis">b</xsl:with-param>
+                                                                <xsl:with-param name="beforeCodes">afgk</xsl:with-param>
+                                                        </xsl:call-template>
+                                                </xsl:when>
+                                                <xsl:otherwise>
+                                                        <xsl:call-template name="subfieldSelect">
+                                                                <xsl:with-param name="codes">abfgk</xsl:with-param>
+                                                        </xsl:call-template>
+                                                </xsl:otherwise>
+                                        </xsl:choose>
+                                </xsl:variable>
+                                <xsl:variable name="titleChop">
+                                        <xsl:call-template name="chopPunctuation">
+                                                <xsl:with-param name="chopString">
+                                                        <xsl:value-of select="$title"/>
+                                                </xsl:with-param>
+                                                <xsl:with-param name="punctuation">
+                                                    <xsl:text>,;/ </xsl:text>
+                                                </xsl:with-param>
+                                        </xsl:call-template>
+                                </xsl:variable>
+                                <xsl:choose>
+                                        <xsl:when test="@ind2>0">
+                                                <nonSort>
+                                                        <xsl:value-of select="substring($titleChop,1, at ind2)"/>
+                                                </nonSort>
+                                                <title>
+                                                        <xsl:value-of select="substring($titleChop, at ind2+1)"/>
+                                                </title>
+                                        </xsl:when>
+                                        <xsl:otherwise>
+                                                <title>
+                                                        <xsl:value-of select="$titleChop"/>
+                                                </title>
+                                        </xsl:otherwise>
+                                </xsl:choose>
+                                <xsl:if test="marc:subfield[@code='b']">
+                                        <subTitle>
+                                                <xsl:call-template name="chopPunctuation">
+                                                        <xsl:with-param name="chopString">
+                                                                <xsl:call-template name="specialSubfieldSelect">
+                                                                        <xsl:with-param name="axis">b</xsl:with-param>
+                                                                        <xsl:with-param name="anyCodes">b</xsl:with-param>
+                                                                        <xsl:with-param name="afterCodes">afgk</xsl:with-param>
+                                                                </xsl:call-template>
+                                                        </xsl:with-param>
+                                                </xsl:call-template>
+                                        </subTitle>
+                                </xsl:if>
+                                <xsl:call-template name="part"/>
+                        </titleInfo>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag='210']">
+                        <titleInfo type="abbreviated">
+                                <title>
+                                        <xsl:call-template name="chopPunctuation">
+                                                <xsl:with-param name="chopString">
+                                                        <xsl:call-template name="subfieldSelect">
+                                                                <xsl:with-param name="codes">a</xsl:with-param>
+                                                        </xsl:call-template>
+                                                </xsl:with-param>
+                                        </xsl:call-template>
+                                </title>
+                                <xsl:call-template name="subtitle"/>
+                        </titleInfo>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag='242']">
+                        <titleInfo type="translated">
+                                <!--09/01/04 Added subfield $y-->
+                                <xsl:for-each select="marc:subfield[@code='y']">
+                                        <xsl:attribute name="lang">
+                                                <xsl:value-of select="text()"/>
+                                        </xsl:attribute>
+                                </xsl:for-each>
+                                <xsl:for-each select="marc:subfield[@code='i']">
+                                        <xsl:attribute name="displayLabel">
+                                                <xsl:value-of select="text()"/>
+                                        </xsl:attribute>
+                                </xsl:for-each>
+                                <title>
+                                        <xsl:call-template name="chopPunctuation">
+                                                <xsl:with-param name="chopString">
+                                                        <xsl:call-template name="subfieldSelect">
+                                                                <!-- 1/04 removed $h, b -->
+                                                                <xsl:with-param name="codes">a</xsl:with-param>
+                                                        </xsl:call-template>
+                                                </xsl:with-param>
+                                        </xsl:call-template>
+                                </title>
+                                <!-- 1/04 fix -->
+                                <xsl:call-template name="subtitle"/>
+                                <xsl:call-template name="part"/>
+                        </titleInfo>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag='246']">
+                        <titleInfo type="alternative">
+                                <xsl:for-each select="marc:subfield[@code='i']">
+                                        <xsl:attribute name="displayLabel">
+                                                <xsl:value-of select="text()"/>
+                                        </xsl:attribute>
+                                </xsl:for-each>
+                                <title>
+                                        <xsl:call-template name="chopPunctuation">
+                                                <xsl:with-param name="chopString">
+                                                        <xsl:call-template name="subfieldSelect">
+                                                                <!-- 1/04 removed $h, $b -->
+                                                                <xsl:with-param name="codes">af</xsl:with-param>
+                                                        </xsl:call-template>
+                                                </xsl:with-param>
+                                        </xsl:call-template>
+                                </title>
+                                <xsl:call-template name="subtitle"/>
+                                <xsl:call-template name="part"/>
+                        </titleInfo>
+                </xsl:for-each>
+                <xsl:for-each
+                        select="marc:datafield[@tag='130']|marc:datafield[@tag='240']|marc:datafield[@tag='730'][@ind2!='2']">
+                        <titleInfo type="uniform">
+                                <title>
+                                                <xsl:call-template name="uri"/>
+
+                                        <xsl:variable name="str">
+                                                <xsl:for-each select="marc:subfield">
+                                                        <xsl:if
+                                                                test="(contains('adfklmors', at code) and (not(../marc:subfield[@code='n' or @code='p']) or (following-sibling::marc:subfield[@code='n' or @code='p'])))">
+                                                                <xsl:value-of select="text()"/>
+                                                                <xsl:text> </xsl:text>
+                                                        </xsl:if>
+                                                </xsl:for-each>
+                                        </xsl:variable>
+                                        <xsl:call-template name="chopPunctuation">
+                                                <xsl:with-param name="chopString">
+                                                        <xsl:value-of select="substring($str,1,string-length($str)-1)"/>
+                                                </xsl:with-param>
+                                        </xsl:call-template>
+                                </title>
+                                <xsl:call-template name="part"/>
+                        </titleInfo>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag='740'][@ind2!='2']">
+                        <titleInfo type="alternative">
+                                <title>
+                                        <xsl:call-template name="chopPunctuation">
+                                                <xsl:with-param name="chopString">
+                                                        <xsl:call-template name="subfieldSelect">
+                                                                <xsl:with-param name="codes">ah</xsl:with-param>
+                                                        </xsl:call-template>
+                                                </xsl:with-param>
+                                        </xsl:call-template>
+                                </title>
+                                <xsl:call-template name="part"/>
+                        </titleInfo>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag='100']">
+                        <name type="personal">
+
+                                <xsl:call-template name="uri"/>
+
+                                <xsl:call-template name="nameABCDQ"/>
+                                <xsl:call-template name="affiliation"/>
+                                <role>
+                                        <roleTerm authority="marcrelator" type="text">creator</roleTerm>
+                                </role>
+                                <xsl:call-template name="role"/>
+                        </name>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag='110']">
+                        <name type="corporate">
+
+                                        <xsl:call-template name="uri"/>
+
+                                <xsl:call-template name="nameABCDN"/>
+                                <role>
+                                        <roleTerm authority="marcrelator" type="text">creator</roleTerm>
+                                </role>
+                                <xsl:call-template name="role"/>
+                        </name>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag='111']">
+                        <name type="conference">
+
+                                        <xsl:call-template name="uri"/>
+
+                                <xsl:call-template name="nameACDEQ"/>
+                                <role>
+                                        <roleTerm authority="marcrelator" type="text">creator</roleTerm>
+                                </role>
+                                <xsl:call-template name="role"/>
+                        </name>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag='700'][not(marc:subfield[@code='t'])]">
+                        <name type="personal">
+
+                                        <xsl:call-template name="uri"/>
+
+                                <xsl:call-template name="nameABCDQ"/>
+                                <xsl:call-template name="affiliation"/>
+                                <xsl:call-template name="role"/>
+                        </name>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag='710'][not(marc:subfield[@code='t'])]">
+                        <name type="corporate">
+
+                                        <xsl:call-template name="uri"/>
+
+                                <xsl:call-template name="nameABCDN"/>
+                                <xsl:call-template name="role"/>
+                        </name>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag='711'][not(marc:subfield[@code='t'])]">
+                        <name type="conference">
+
+                                        <xsl:call-template name="uri"/>
+
+                                <xsl:call-template name="nameACDEQ"/>
+                                <xsl:call-template name="role"/>
+                        </name>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag='720'][not(marc:subfield[@code='t'])]">
+                        <name>
+                                <xsl:if test="@ind1=1">
+                                        <xsl:attribute name="type">
+                                                <xsl:text>personal</xsl:text>
+                                        </xsl:attribute>
+                                </xsl:if>
+                                <namePart>
+                                        <xsl:value-of select="marc:subfield[@code='a']"/>
+                                </namePart>
+                                <xsl:call-template name="role"/>
+                        </name>
+                </xsl:for-each>
+                <typeOfResource>
+                        <xsl:if test="$leader7='c'">
+                                <xsl:attribute name="collection">yes</xsl:attribute>
+                        </xsl:if>
+                        <xsl:if test="$leader6='d' or $leader6='f' or $leader6='p' or $leader6='t'">
+                                <xsl:attribute name="manuscript">yes</xsl:attribute>
+                        </xsl:if>
+                        <xsl:choose>
+                                <xsl:when test="$leader6='a' or $leader6='t'">text</xsl:when>
+                                <xsl:when test="$leader6='e' or $leader6='f'">cartographic</xsl:when>
+                                <xsl:when test="$leader6='c' or $leader6='d'">notated music</xsl:when>
+                                <xsl:when test="$leader6='i'">sound recording-nonmusical</xsl:when>
+                                <xsl:when test="$leader6='j'">sound recording-musical</xsl:when>
+                                <xsl:when test="$leader6='k'">still image</xsl:when>
+                                <xsl:when test="$leader6='g'">moving image</xsl:when>
+                                <xsl:when test="$leader6='r'">three dimensional object</xsl:when>
+                                <xsl:when test="$leader6='m'">software, multimedia</xsl:when>
+                                <xsl:when test="$leader6='p'">mixed material</xsl:when>
+                        </xsl:choose>
+                </typeOfResource>
+                <xsl:if test="substring($controlField008,26,1)='d'">
+                        <genre authority="marcgt">globe</genre>
+                </xsl:if>
+                <xsl:if
+                        test="marc:controlfield[@tag='007'][substring(text(),1,1)='a'][substring(text(),2,1)='r']">
+                        <genre authority="marcgt">remote-sensing image</genre>
+                </xsl:if>
+                <xsl:if test="$typeOf008='MP'">
+                        <xsl:variable name="controlField008-25" select="substring($controlField008,26,1)"/>
+                        <xsl:choose>
+                                <xsl:when
+                                        test="$controlField008-25='a' or $controlField008-25='b' or $controlField008-25='c' or marc:controlfield[@tag=007][substring(text(),1,1)='a'][substring(text(),2,1)='j']">
+                                        <genre authority="marcgt">map</genre>
+                                </xsl:when>
+                                <xsl:when
+                                        test="$controlField008-25='e' or marc:controlfield[@tag=007][substring(text(),1,1)='a'][substring(text(),2,1)='d']">
+                                        <genre authority="marcgt">atlas</genre>
+                                </xsl:when>
+                        </xsl:choose>
+                </xsl:if>
+                <xsl:if test="$typeOf008='SE'">
+                        <xsl:variable name="controlField008-21" select="substring($controlField008,22,1)"/>
+                        <xsl:choose>
+                                <xsl:when test="$controlField008-21='d'">
+                                        <genre authority="marcgt">database</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-21='l'">
+                                        <genre authority="marcgt">loose-leaf</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-21='m'">
+                                        <genre authority="marcgt">series</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-21='n'">
+                                        <genre authority="marcgt">newspaper</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-21='p'">
+                                        <genre authority="marcgt">periodical</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-21='w'">
+                                        <genre authority="marcgt">web site</genre>
+                                </xsl:when>
+                        </xsl:choose>
+                </xsl:if>
+                <xsl:if test="$typeOf008='BK' or $typeOf008='SE'">
+                        <xsl:variable name="controlField008-24" select="substring($controlField008,25,4)"/>
+                        <xsl:choose>
+                                <xsl:when test="contains($controlField008-24,'a')">
+                                        <genre authority="marcgt">abstract or summary</genre>
+                                </xsl:when>
+                                <xsl:when test="contains($controlField008-24,'b')">
+                                        <genre authority="marcgt">bibliography</genre>
+                                </xsl:when>
+                                <xsl:when test="contains($controlField008-24,'c')">
+                                        <genre authority="marcgt">catalog</genre>
+                                </xsl:when>
+                                <xsl:when test="contains($controlField008-24,'d')">
+                                        <genre authority="marcgt">dictionary</genre>
+                                </xsl:when>
+                                <xsl:when test="contains($controlField008-24,'e')">
+                                        <genre authority="marcgt">encyclopedia</genre>
+                                </xsl:when>
+                                <xsl:when test="contains($controlField008-24,'f')">
+                                        <genre authority="marcgt">handbook</genre>
+                                </xsl:when>
+                                <xsl:when test="contains($controlField008-24,'g')">
+                                        <genre authority="marcgt">legal article</genre>
+                                </xsl:when>
+                                <xsl:when test="contains($controlField008-24,'i')">
+                                        <genre authority="marcgt">index</genre>
+                                </xsl:when>
+                                <xsl:when test="contains($controlField008-24,'k')">
+                                        <genre authority="marcgt">discography</genre>
+                                </xsl:when>
+                                <xsl:when test="contains($controlField008-24,'l')">
+                                        <genre authority="marcgt">legislation</genre>
+                                </xsl:when>
+                                <xsl:when test="contains($controlField008-24,'m')">
+                                        <genre authority="marcgt">theses</genre>
+                                </xsl:when>
+                                <xsl:when test="contains($controlField008-24,'n')">
+                                        <genre authority="marcgt">survey of literature</genre>
+                                </xsl:when>
+                                <xsl:when test="contains($controlField008-24,'o')">
+                                        <genre authority="marcgt">review</genre>
+                                </xsl:when>
+                                <xsl:when test="contains($controlField008-24,'p')">
+                                        <genre authority="marcgt">programmed text</genre>
+                                </xsl:when>
+                                <xsl:when test="contains($controlField008-24,'q')">
+                                        <genre authority="marcgt">filmography</genre>
+                                </xsl:when>
+                                <xsl:when test="contains($controlField008-24,'r')">
+                                        <genre authority="marcgt">directory</genre>
+                                </xsl:when>
+                                <xsl:when test="contains($controlField008-24,'s')">
+                                        <genre authority="marcgt">statistics</genre>
+                                </xsl:when>
+                                <xsl:when test="contains($controlField008-24,'t')">
+                                        <genre authority="marcgt">technical report</genre>
+                                </xsl:when>
+                                <xsl:when test="contains($controlField008-24,'v')">
+                                        <genre authority="marcgt">legal case and case notes</genre>
+                                </xsl:when>
+                                <xsl:when test="contains($controlField008-24,'w')">
+                                        <genre authority="marcgt">law report or digest</genre>
+                                </xsl:when>
+                                <xsl:when test="contains($controlField008-24,'z')">
+                                        <genre authority="marcgt">treaty</genre>
+                                </xsl:when>
+                        </xsl:choose>
+                        <xsl:variable name="controlField008-29" select="substring($controlField008,30,1)"/>
+                        <xsl:choose>
+                                <xsl:when test="$controlField008-29='1'">
+                                        <genre authority="marcgt">conference publication</genre>
+                                </xsl:when>
+                        </xsl:choose>
+                </xsl:if>
+                <xsl:if test="$typeOf008='CF'">
+                        <xsl:variable name="controlField008-26" select="substring($controlField008,27,1)"/>
+                        <xsl:choose>
+                                <xsl:when test="$controlField008-26='a'">
+                                        <genre authority="marcgt">numeric data</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-26='e'">
+                                        <genre authority="marcgt">database</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-26='f'">
+                                        <genre authority="marcgt">font</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-26='g'">
+                                        <genre authority="marcgt">game</genre>
+                                </xsl:when>
+                        </xsl:choose>
+                </xsl:if>
+                <xsl:if test="$typeOf008='BK'">
+                        <xsl:if test="substring($controlField008,25,1)='j'">
+                                <genre authority="marcgt">patent</genre>
+                        </xsl:if>
+                        <xsl:if test="substring($controlField008,25,1)='2'">
+                                <genre authority="marcgt">offprint</genre>
+                        </xsl:if>
+                        <xsl:if test="substring($controlField008,31,1)='1'">
+                                <genre authority="marcgt">festschrift</genre>
+                        </xsl:if>
+                        <xsl:variable name="controlField008-34" select="substring($controlField008,35,1)"/>
+                        <xsl:if
+                                test="$controlField008-34='a' or $controlField008-34='b' or $controlField008-34='c' or $controlField008-34='d'">
+                                <genre authority="marcgt">biography</genre>
+                        </xsl:if>
+                        <xsl:variable name="controlField008-33" select="substring($controlField008,34,1)"/>
+                        <xsl:choose>
+                                <xsl:when test="$controlField008-33='e'">
+                                        <genre authority="marcgt">essay</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='d'">
+                                        <genre authority="marcgt">drama</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='c'">
+                                        <genre authority="marcgt">comic strip</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='l'">
+                                        <genre authority="marcgt">fiction</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='h'">
+                                        <genre authority="marcgt">humor, satire</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='i'">
+                                        <genre authority="marcgt">letter</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='f'">
+                                        <genre authority="marcgt">novel</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='j'">
+                                        <genre authority="marcgt">short story</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='s'">
+                                        <genre authority="marcgt">speech</genre>
+                                </xsl:when>
+                        </xsl:choose>
+                </xsl:if>
+                <xsl:if test="$typeOf008='MU'">
+                        <xsl:variable name="controlField008-30-31" select="substring($controlField008,31,2)"/>
+                        <xsl:if test="contains($controlField008-30-31,'b')">
+                                <genre authority="marcgt">biography</genre>
+                        </xsl:if>
+                        <xsl:if test="contains($controlField008-30-31,'c')">
+                                <genre authority="marcgt">conference publication</genre>
+                        </xsl:if>
+                        <xsl:if test="contains($controlField008-30-31,'d')">
+                                <genre authority="marcgt">drama</genre>
+                        </xsl:if>
+                        <xsl:if test="contains($controlField008-30-31,'e')">
+                                <genre authority="marcgt">essay</genre>
+                        </xsl:if>
+                        <xsl:if test="contains($controlField008-30-31,'f')">
+                                <genre authority="marcgt">fiction</genre>
+                        </xsl:if>
+                        <xsl:if test="contains($controlField008-30-31,'o')">
+                                <genre authority="marcgt">folktale</genre>
+                        </xsl:if>
+                        <xsl:if test="contains($controlField008-30-31,'h')">
+                                <genre authority="marcgt">history</genre>
+                        </xsl:if>
+                        <xsl:if test="contains($controlField008-30-31,'k')">
+                                <genre authority="marcgt">humor, satire</genre>
+                        </xsl:if>
+                        <xsl:if test="contains($controlField008-30-31,'m')">
+                                <genre authority="marcgt">memoir</genre>
+                        </xsl:if>
+                        <xsl:if test="contains($controlField008-30-31,'p')">
+                                <genre authority="marcgt">poetry</genre>
+                        </xsl:if>
+                        <xsl:if test="contains($controlField008-30-31,'r')">
+                                <genre authority="marcgt">rehearsal</genre>
+                        </xsl:if>
+                        <xsl:if test="contains($controlField008-30-31,'g')">
+                                <genre authority="marcgt">reporting</genre>
+                        </xsl:if>
+                        <xsl:if test="contains($controlField008-30-31,'s')">
+                                <genre authority="marcgt">sound</genre>
+                        </xsl:if>
+                        <xsl:if test="contains($controlField008-30-31,'l')">
+                                <genre authority="marcgt">speech</genre>
+                        </xsl:if>
+                </xsl:if>
+                <xsl:if test="$typeOf008='VM'">
+                        <xsl:variable name="controlField008-33" select="substring($controlField008,34,1)"/>
+                        <xsl:choose>
+                                <xsl:when test="$controlField008-33='a'">
+                                        <genre authority="marcgt">art original</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='b'">
+                                        <genre authority="marcgt">kit</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='c'">
+                                        <genre authority="marcgt">art reproduction</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='d'">
+                                        <genre authority="marcgt">diorama</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='f'">
+                                        <genre authority="marcgt">filmstrip</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='g'">
+                                        <genre authority="marcgt">legal article</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='i'">
+                                        <genre authority="marcgt">picture</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='k'">
+                                        <genre authority="marcgt">graphic</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='l'">
+                                        <genre authority="marcgt">technical drawing</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='m'">
+                                        <genre authority="marcgt">motion picture</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='n'">
+                                        <genre authority="marcgt">chart</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='o'">
+                                        <genre authority="marcgt">flash card</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='p'">
+                                        <genre authority="marcgt">microscope slide</genre>
+                                </xsl:when>
+                                <xsl:when
+                                        test="$controlField008-33='q' or marc:controlfield[@tag=007][substring(text(),1,1)='a'][substring(text(),2,1)='q']">
+                                        <genre authority="marcgt">model</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='r'">
+                                        <genre authority="marcgt">realia</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='s'">
+                                        <genre authority="marcgt">slide</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='t'">
+                                        <genre authority="marcgt">transparency</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='v'">
+                                        <genre authority="marcgt">videorecording</genre>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-33='w'">
+                                        <genre authority="marcgt">toy</genre>
+                                </xsl:when>
+                        </xsl:choose>
+                </xsl:if>
+
+                <!-- 1.20 047 genre tmee-->
+
+                <xsl:for-each select="marc:datafield[@tag=047]">
+                        <genre authority="marcgt">
+                                <xsl:attribute name="authority">
+                                        <xsl:value-of select="marc:subfield[@code='2']"/>
+                                </xsl:attribute>
+                                <xsl:call-template name="subfieldSelect">
+                                        <xsl:with-param name="codes">abcdef</xsl:with-param>
+                                        <xsl:with-param name="delimeter">-</xsl:with-param>
+                                </xsl:call-template>
+                        </genre>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=655]">
+                        <genre authority="marcgt">
+                                <xsl:attribute name="authority">
+                                        <xsl:value-of select="marc:subfield[@code='2']"/>
+                                </xsl:attribute>
+                                <xsl:call-template name="subfieldSelect">
+                                        <xsl:with-param name="codes">abvxyz</xsl:with-param>
+                                        <xsl:with-param name="delimeter">-</xsl:with-param>
+                                </xsl:call-template>
+                        </genre>
+                </xsl:for-each>
+                <originInfo>
+                        <xsl:variable name="MARCpublicationCode"
+                                select="normalize-space(substring($controlField008,16,3))"/>
+                        <xsl:if test="translate($MARCpublicationCode,'|','')">
+                                <place>
+                                        <placeTerm>
+                                                <xsl:attribute name="type">code</xsl:attribute>
+                                                <xsl:attribute name="authority">marccountry</xsl:attribute>
+                                                <xsl:value-of select="$MARCpublicationCode"/>
+                                        </placeTerm>
+                                </place>
+                        </xsl:if>
+                        <xsl:for-each select="marc:datafield[@tag=044]/marc:subfield[@code='c']">
+                                <place>
+                                        <placeTerm>
+                                                <xsl:attribute name="type">code</xsl:attribute>
+                                                <xsl:attribute name="authority">iso3166</xsl:attribute>
+                                                <xsl:value-of select="."/>
+                                        </placeTerm>
+                                </place>
+                        </xsl:for-each>
+                        <xsl:for-each select="marc:datafield[@tag=260]/marc:subfield[@code='a']">
+                                <place>
+                                        <placeTerm>
+                                                <xsl:attribute name="type">text</xsl:attribute>
+                                                <xsl:call-template name="chopPunctuationFront">
+                                                        <xsl:with-param name="chopString">
+                                                                <xsl:call-template name="chopPunctuation">
+                                                                        <xsl:with-param name="chopString" select="."/>
+                                                                </xsl:call-template>
+                                                        </xsl:with-param>
+                                                </xsl:call-template>
+                                        </placeTerm>
+                                </place>
+                        </xsl:for-each>
+                        <xsl:for-each select="marc:datafield[@tag=046]/marc:subfield[@code='m']">
+                                <dateValid point="start">
+                                        <xsl:value-of select="."/>
+                                </dateValid>
+                        </xsl:for-each>
+                        <xsl:for-each select="marc:datafield[@tag=046]/marc:subfield[@code='n']">
+                                <dateValid point="end">
+                                        <xsl:value-of select="."/>
+                                </dateValid>
+                        </xsl:for-each>
+                        <xsl:for-each select="marc:datafield[@tag=046]/marc:subfield[@code='j']">
+                                <dateModified>
+                                        <xsl:value-of select="."/>
+                                </dateModified>
+                        </xsl:for-each>
+                        <xsl:for-each
+                                select="marc:datafield[@tag=260]/marc:subfield[@code='b' or @code='c' or @code='g']">
+                                <xsl:choose>
+                                        <xsl:when test="@code='b'">
+                                                <publisher>
+                                                        <xsl:call-template name="chopPunctuation">
+                                                                <xsl:with-param name="chopString" select="."/>
+                                                                <xsl:with-param name="punctuation">
+                                                                        <xsl:text>:,;/ </xsl:text>
+                                                                </xsl:with-param>
+                                                        </xsl:call-template>
+                                                </publisher>
+                                        </xsl:when>
+                                        <xsl:when test="@code='c'">
+                                                <dateIssued>
+                                                        <xsl:call-template name="chopPunctuation">
+                                                                <xsl:with-param name="chopString" select="."/>
+                                                        </xsl:call-template>
+                                                </dateIssued>
+                                        </xsl:when>
+                                        <xsl:when test="@code='g'">
+                                                <dateCreated>
+                                                        <xsl:value-of select="."/>
+                                                </dateCreated>
+                                        </xsl:when>
+                                </xsl:choose>
+                        </xsl:for-each>
+                        <xsl:variable name="dataField260c">
+                                <xsl:call-template name="chopPunctuation">
+                                        <xsl:with-param name="chopString"
+                                                select="marc:datafield[@tag=260]/marc:subfield[@code='c']"/>
+                                </xsl:call-template>
+                        </xsl:variable>
+                        <xsl:variable name="controlField008-7-10"
+                                select="normalize-space(substring($controlField008, 8, 4))"/>
+                        <xsl:variable name="controlField008-11-14"
+                                select="normalize-space(substring($controlField008, 12, 4))"/>
+                        <xsl:variable name="controlField008-6"
+                                select="normalize-space(substring($controlField008, 7, 1))"/>
+                        <xsl:if
+                                test="$controlField008-6='e' or $controlField008-6='p' or $controlField008-6='r' or $controlField008-6='t' or $controlField008-6='s'">
+                                <xsl:if test="$controlField008-7-10 and ($controlField008-7-10 != $dataField260c)">
+                                        <dateIssued encoding="marc">
+                                                <xsl:value-of select="$controlField008-7-10"/>
+                                        </dateIssued>
+                                </xsl:if>
+                        </xsl:if>
+                        <xsl:if
+                                test="$controlField008-6='c' or $controlField008-6='d' or $controlField008-6='i' or $controlField008-6='k' or $controlField008-6='m' or $controlField008-6='q' or $controlField008-6='u'">
+                                <xsl:if test="$controlField008-7-10">
+                                        <dateIssued encoding="marc" point="start">
+                                                <xsl:value-of select="$controlField008-7-10"/>
+                                        </dateIssued>
+                                </xsl:if>
+                        </xsl:if>
+                        <xsl:if
+                                test="$controlField008-6='c' or $controlField008-6='d' or $controlField008-6='i' or $controlField008-6='k' or $controlField008-6='m' or $controlField008-6='q' or $controlField008-6='u'">
+                                <xsl:if test="$controlField008-11-14">
+                                        <dateIssued encoding="marc" point="end">
+                                                <xsl:value-of select="$controlField008-11-14"/>
+                                        </dateIssued>
+                                </xsl:if>
+                        </xsl:if>
+                        <xsl:if test="$controlField008-6='q'">
+                                <xsl:if test="$controlField008-7-10">
+                                        <dateIssued encoding="marc" point="start" qualifier="questionable">
+                                                <xsl:value-of select="$controlField008-7-10"/>
+                                        </dateIssued>
+                                </xsl:if>
+                        </xsl:if>
+                        <xsl:if test="$controlField008-6='q'">
+                                <xsl:if test="$controlField008-11-14">
+                                        <dateIssued encoding="marc" point="end" qualifier="questionable">
+                                                <xsl:value-of select="$controlField008-11-14"/>
+                                        </dateIssued>
+                                </xsl:if>
+                        </xsl:if>
+                        <xsl:if test="$controlField008-6='t'">
+                                <xsl:if test="$controlField008-11-14">
+                                        <copyrightDate encoding="marc">
+                                                <xsl:value-of select="$controlField008-11-14"/>
+                                        </copyrightDate>
+                                </xsl:if>
+                        </xsl:if>
+                        <xsl:for-each
+                                select="marc:datafield[@tag=033][@ind1=0 or @ind1=1]/marc:subfield[@code='a']">
+                                <dateCaptured encoding="iso8601">
+                                        <xsl:value-of select="."/>
+                                </dateCaptured>
+                        </xsl:for-each>
+                        <xsl:for-each select="marc:datafield[@tag=033][@ind1=2]/marc:subfield[@code='a'][1]">
+                                <dateCaptured encoding="iso8601" point="start">
+                                        <xsl:value-of select="."/>
+                                </dateCaptured>
+                        </xsl:for-each>
+                        <xsl:for-each select="marc:datafield[@tag=033][@ind1=2]/marc:subfield[@code='a'][2]">
+                                <dateCaptured encoding="iso8601" point="end">
+                                        <xsl:value-of select="."/>
+                                </dateCaptured>
+                        </xsl:for-each>
+                        <xsl:for-each select="marc:datafield[@tag=250]/marc:subfield[@code='a']">
+                                <edition>
+                                        <xsl:value-of select="."/>
+                                </edition>
+                        </xsl:for-each>
+                        <xsl:for-each select="marc:leader">
+                                <issuance>
+                                        <xsl:choose>
+                                                <xsl:when
+                                                        test="$leader7='a' or $leader7='c' or $leader7='d' or $leader7='m'"
+                                                        >monographic</xsl:when>
+                                                <xsl:when test="$leader7='b' or $leader7='i' or $leader7='s'"
+                                                >continuing</xsl:when>
+                                        </xsl:choose>
+                                </issuance>
+                        </xsl:for-each>
+                        <xsl:for-each select="marc:datafield[@tag=310]|marc:datafield[@tag=321]">
+                                <frequency>
+                                        <xsl:call-template name="subfieldSelect">
+                                                <xsl:with-param name="codes">ab</xsl:with-param>
+                                        </xsl:call-template>
+                                </frequency>
+                        </xsl:for-each>
+                </originInfo>
+                <xsl:variable name="controlField008-35-37"
+                        select="normalize-space(translate(substring($controlField008,36,3),'|#',''))"/>
+                <xsl:if test="$controlField008-35-37">
+                        <language>
+                                <languageTerm authority="iso639-2b" type="code">
+                                        <xsl:value-of select="substring($controlField008,36,3)"/>
+                                </languageTerm>
+                        </language>
+                </xsl:if>
+                <xsl:for-each select="marc:datafield[@tag=041]">
+                        <xsl:for-each
+                                select="marc:subfield[@code='a' or @code='b' or @code='d' or @code='e' or @code='f' or @code='g' or @code='h']">
+                                <xsl:variable name="langCodes" select="."/>
+                                <xsl:choose>
+                                        <xsl:when test="../marc:subfield[@code='2']='rfc3066'">
+                                                <!-- not stacked but could be repeated -->
+                                                <xsl:call-template name="rfcLanguages">
+                                                        <xsl:with-param name="nodeNum">
+                                                                <xsl:value-of select="1"/>
+                                                        </xsl:with-param>
+                                                        <xsl:with-param name="usedLanguages">
+                                                                <xsl:text/>
+                                                        </xsl:with-param>
+                                                        <xsl:with-param name="controlField008-35-37">
+                                                                <xsl:value-of select="$controlField008-35-37"/>
+                                                        </xsl:with-param>
+                                                </xsl:call-template>
+                                        </xsl:when>
+                                        <xsl:otherwise>
+                                                <!-- iso -->
+                                                <xsl:variable name="allLanguages">
+                                                        <xsl:copy-of select="$langCodes"/>
+                                                </xsl:variable>
+                                                <xsl:variable name="currentLanguage">
+                                                        <xsl:value-of select="substring($allLanguages,1,3)"/>
+                                                </xsl:variable>
+                                                <xsl:call-template name="isoLanguage">
+                                                        <xsl:with-param name="currentLanguage">
+                                                                <xsl:value-of select="substring($allLanguages,1,3)"/>
+                                                        </xsl:with-param>
+                                                        <xsl:with-param name="remainingLanguages">
+                                                                <xsl:value-of
+                                                                        select="substring($allLanguages,4,string-length($allLanguages)-3)"
+                                                                />
+                                                        </xsl:with-param>
+                                                        <xsl:with-param name="usedLanguages">
+                                                                <xsl:if test="$controlField008-35-37">
+                                                                        <xsl:value-of select="$controlField008-35-37"/>
+                                                                </xsl:if>
+                                                        </xsl:with-param>
+                                                </xsl:call-template>
+                                        </xsl:otherwise>
+                                </xsl:choose>
+                        </xsl:for-each>
+                </xsl:for-each>
+                <xsl:variable name="physicalDescription">
+                        <!--3.2 change tmee 007/11 -->
+                        <xsl:if test="$typeOf008='CF' and marc:controlfield[@tag=007][substring(.,12,1)='a']">
+                                <digitalOrigin>reformatted digital</digitalOrigin>
+                        </xsl:if>
+                        <xsl:if test="$typeOf008='CF' and marc:controlfield[@tag=007][substring(.,12,1)='b']">
+                                <digitalOrigin>digitized microfilm</digitalOrigin>
+                        </xsl:if>
+                        <xsl:if test="$typeOf008='CF' and marc:controlfield[@tag=007][substring(.,12,1)='d']">
+                                <digitalOrigin>digitized other analog</digitalOrigin>
+                        </xsl:if>
+                        <xsl:variable name="controlField008-23" select="substring($controlField008,24,1)"/>
+                        <xsl:variable name="controlField008-29" select="substring($controlField008,30,1)"/>
+                        <xsl:variable name="check008-23">
+                                <xsl:if
+                                        test="$typeOf008='BK' or $typeOf008='MU' or $typeOf008='SE' or $typeOf008='MM'">
+                                        <xsl:value-of select="true()"/>
+                                </xsl:if>
+                        </xsl:variable>
+                        <xsl:variable name="check008-29">
+                                <xsl:if test="$typeOf008='MP' or $typeOf008='VM'">
+                                        <xsl:value-of select="true()"/>
+                                </xsl:if>
+                        </xsl:variable>
+                        <xsl:choose>
+                                <xsl:when
+                                        test="($check008-23 and $controlField008-23='f') or ($check008-29 and $controlField008-29='f')">
+                                        <form authority="marcform">braille</form>
+                                </xsl:when>
+                                <xsl:when
+                                        test="($controlField008-23=' ' and ($leader6='c' or $leader6='d')) or (($typeOf008='BK' or $typeOf008='SE') and ($controlField008-23=' ' or $controlField008='r'))">
+                                        <form authority="marcform">print</form>
+                                </xsl:when>
+                                <xsl:when
+                                        test="$leader6 = 'm' or ($check008-23 and $controlField008-23='s') or ($check008-29 and $controlField008-29='s')">
+                                        <form authority="marcform">electronic</form>
+                                </xsl:when>
+                                <xsl:when
+                                        test="($check008-23 and $controlField008-23='b') or ($check008-29 and $controlField008-29='b')">
+                                        <form authority="marcform">microfiche</form>
+                                </xsl:when>
+                                <xsl:when
+                                        test="($check008-23 and $controlField008-23='a') or ($check008-29 and $controlField008-29='a')">
+                                        <form authority="marcform">microfilm</form>
+                                </xsl:when>
+                        </xsl:choose>
+                        <!-- 1/04 fix -->
+                        <xsl:if test="marc:datafield[@tag=130]/marc:subfield[@code='h']">
+                                <form authority="gmd">
+                                        <xsl:call-template name="chopBrackets">
+                                                <xsl:with-param name="chopString">
+                                                        <xsl:value-of select="marc:datafield[@tag=130]/marc:subfield[@code='h']"
+                                                        />
+                                                </xsl:with-param>
+                                        </xsl:call-template>
+                                </form>
+                        </xsl:if>
+                        <xsl:if test="marc:datafield[@tag=240]/marc:subfield[@code='h']">
+                                <form authority="gmd">
+                                        <xsl:call-template name="chopBrackets">
+                                                <xsl:with-param name="chopString">
+                                                        <xsl:value-of select="marc:datafield[@tag=240]/marc:subfield[@code='h']"
+                                                        />
+                                                </xsl:with-param>
+                                        </xsl:call-template>
+                                </form>
+                        </xsl:if>
+                        <xsl:if test="marc:datafield[@tag=242]/marc:subfield[@code='h']">
+                                <form authority="gmd">
+                                        <xsl:call-template name="chopBrackets">
+                                                <xsl:with-param name="chopString">
+                                                        <xsl:value-of select="marc:datafield[@tag=242]/marc:subfield[@code='h']"
+                                                        />
+                                                </xsl:with-param>
+                                        </xsl:call-template>
+                                </form>
+                        </xsl:if>
+                        <xsl:if test="marc:datafield[@tag=245]/marc:subfield[@code='h']">
+                                <form authority="gmd">
+                                        <xsl:call-template name="chopBrackets">
+                                                <xsl:with-param name="chopString">
+                                                        <xsl:value-of select="marc:datafield[@tag=245]/marc:subfield[@code='h']"
+                                                        />
+                                                </xsl:with-param>
+                                        </xsl:call-template>
+                                </form>
+                        </xsl:if>
+                        <xsl:if test="marc:datafield[@tag=246]/marc:subfield[@code='h']">
+                                <form authority="gmd">
+                                        <xsl:call-template name="chopBrackets">
+                                                <xsl:with-param name="chopString">
+                                                        <xsl:value-of select="marc:datafield[@tag=246]/marc:subfield[@code='h']"
+                                                        />
+                                                </xsl:with-param>
+                                        </xsl:call-template>
+                                </form>
+                        </xsl:if>
+                        <xsl:if test="marc:datafield[@tag=730]/marc:subfield[@code='h']">
+                                <form authority="gmd">
+                                        <xsl:call-template name="chopBrackets">
+                                                <xsl:with-param name="chopString">
+                                                        <xsl:value-of select="marc:datafield[@tag=730]/marc:subfield[@code='h']"
+                                                        />
+                                                </xsl:with-param>
+                                        </xsl:call-template>
+                                </form>
+                        </xsl:if>
+                        <xsl:for-each select="marc:datafield[@tag=256]/marc:subfield[@code='a']">
+                                <form>
+                                        <xsl:value-of select="."/>
+                                </form>
+                        </xsl:for-each>
+                        <xsl:for-each select="marc:controlfield[@tag=007][substring(text(),1,1)='c']">
+                                <xsl:choose>
+                                        <xsl:when test="substring(text(),14,1)='a'">
+                                                <reformattingQuality>access</reformattingQuality>
+                                        </xsl:when>
+                                        <xsl:when test="substring(text(),14,1)='p'">
+                                                <reformattingQuality>preservation</reformattingQuality>
+                                        </xsl:when>
+                                        <xsl:when test="substring(text(),14,1)='r'">
+                                                <reformattingQuality>replacement</reformattingQuality>
+                                        </xsl:when>
+                                </xsl:choose>
+                        </xsl:for-each>
+                        <!--3.2 change tmee 007/01 -->
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='c'][substring(text(),2,1)='b']">
+                                <form authority="smd">chip cartridge</form>
+                        </xsl:if>
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='c'][substring(text(),2,1)='c']">
+                                <form authority="smd">computer optical disc cartridge</form>
+                        </xsl:if>
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='c'][substring(text(),2,1)='j']">
+                                <form authority="smd">magnetic disc</form>
+                        </xsl:if>
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='c'][substring(text(),2,1)='m']">
+                                <form authority="smd">magneto-optical disc</form>
+                        </xsl:if>
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='c'][substring(text(),2,1)='o']">
+                                <form authority="smd">optical disc</form>
+                        </xsl:if>
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='c'][substring(text(),2,1)='r']">
+                                <form authority="smd">remote</form>
+                        </xsl:if>
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='c'][substring(text(),2,1)='a']">
+                                <form authority="smd">tape cartridge</form>
+                        </xsl:if>
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='c'][substring(text(),2,1)='f']">
+                                <form authority="smd">tape cassette</form>
+                        </xsl:if>
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='c'][substring(text(),2,1)='h']">
+                                <form authority="smd">tape reel</form>
+                        </xsl:if>
+
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='d'][substring(text(),2,1)='a']">
+                                <form authority="smd">celestial globe</form>
+                        </xsl:if>
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='d'][substring(text(),2,1)='e']">
+                                <form authority="smd">earth moon globe</form>
+                        </xsl:if>
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='d'][substring(text(),2,1)='b']">
+                                <form authority="smd">planetary or lunar globe</form>
+                        </xsl:if>
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='d'][substring(text(),2,1)='c']">
+                                <form authority="smd">terrestrial globe</form>
+                        </xsl:if>
+
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='o'][substring(text(),2,1)='o']">
+                                <form authority="smd">kit</form>
+                        </xsl:if>
+
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='a'][substring(text(),2,1)='d']">
+                                <form authority="smd">atlas</form>
+                        </xsl:if>
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='a'][substring(text(),2,1)='g']">
+                                <form authority="smd">diagram</form>
+                        </xsl:if>
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='a'][substring(text(),2,1)='j']">
+                                <form authority="smd">map</form>
+                        </xsl:if>
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='a'][substring(text(),2,1)='q']">
+                                <form authority="smd">model</form>
+                        </xsl:if>
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='a'][substring(text(),2,1)='k']">
+                                <form authority="smd">profile</form>
+                        </xsl:if>
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='a'][substring(text(),2,1)='r']">
+                                <form authority="smd">remote-sensing image</form>
+                        </xsl:if>
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='a'][substring(text(),2,1)='s']">
+                                <form authority="smd">section</form>
+                        </xsl:if>
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='a'][substring(text(),2,1)='y']">
+                                <form authority="smd">view</form>
+                        </xsl:if>
+
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='h'][substring(text(),2,1)='a']">
+                                <form authority="smd">aperture card</form>
+                        </xsl:if>
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='h'][substring(text(),2,1)='e']">
+                                <form authority="smd">microfiche</form>
+                        </xsl:if>
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='h'][substring(text(),2,1)='f']">
+                                <form authority="smd">microfiche cassette</form>
+                        </xsl:if>
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='h'][substring(text(),2,1)='b']">
+                                <form authority="smd">microfilm cartridge</form>
+                        </xsl:if>
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='h'][substring(text(),2,1)='c']">
+                                <form authority="smd">microfilm cassette</form>
+                        </xsl:if>
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='h'][substring(text(),2,1)='d']">
+                                <form authority="smd">microfilm reel</form>
+                        </xsl:if>
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='h'][substring(text(),2,1)='g']">
+                                <form authority="smd">microopaque</form>
+                        </xsl:if>
+
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='m'][substring(text(),2,1)='c']">
+                                <form authority="smd">film cartridge</form>
+                        </xsl:if>
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='m'][substring(text(),2,1)='f']">
+                                <form authority="smd">film cassette</form>
+                        </xsl:if>
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='m'][substring(text(),2,1)='r']">
+                                <form authority="smd">film reel</form>
+                        </xsl:if>
+
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='k'][substring(text(),2,1)='n']">
+                                <form authority="smd">chart</form>
+                        </xsl:if>
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='k'][substring(text(),2,1)='c']">
+                                <form authority="smd">collage</form>
+                        </xsl:if>
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='k'][substring(text(),2,1)='d']">
+                                <form authority="smd">drawing</form>
+                        </xsl:if>
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='k'][substring(text(),2,1)='o']">
+                                <form authority="smd">flash card</form>
+                        </xsl:if>
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='k'][substring(text(),2,1)='e']">
+                                <form authority="smd">painting</form>
+                        </xsl:if>
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='k'][substring(text(),2,1)='f']">
+                                <form authority="smd">photomechanical print</form>
+                        </xsl:if>
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='k'][substring(text(),2,1)='g']">
+                                <form authority="smd">photonegative</form>
+                        </xsl:if>
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='k'][substring(text(),2,1)='h']">
+                                <form authority="smd">photoprint</form>
+                        </xsl:if>
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='k'][substring(text(),2,1)='i']">
+                                <form authority="smd">picture</form>
+                        </xsl:if>
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='k'][substring(text(),2,1)='j']">
+                                <form authority="smd">print</form>
+                        </xsl:if>
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='k'][substring(text(),2,1)='l']">
+                                <form authority="smd">technical drawing</form>
+                        </xsl:if>
+
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='q'][substring(text(),2,1)='q']">
+                                <form authority="smd">notated music</form>
+                        </xsl:if>
+
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='g'][substring(text(),2,1)='d']">
+                                <form authority="smd">filmslip</form>
+                        </xsl:if>
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='g'][substring(text(),2,1)='c']">
+                                <form authority="smd">filmstrip cartridge</form>
+                        </xsl:if>
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='g'][substring(text(),2,1)='o']">
+                                <form authority="smd">filmstrip roll</form>
+                        </xsl:if>
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='g'][substring(text(),2,1)='f']">
+                                <form authority="smd">other filmstrip type</form>
+                        </xsl:if>
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='g'][substring(text(),2,1)='s']">
+                                <form authority="smd">slide</form>
+                        </xsl:if>
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='g'][substring(text(),2,1)='t']">
+                                <form authority="smd">transparency</form>
+                        </xsl:if>
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='r'][substring(text(),2,1)='r']">
+                                <form authority="smd">remote-sensing image</form>
+                        </xsl:if>
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='s'][substring(text(),2,1)='e']">
+                                <form authority="smd">cylinder</form>
+                        </xsl:if>
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='s'][substring(text(),2,1)='q']">
+                                <form authority="smd">roll</form>
+                        </xsl:if>
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='s'][substring(text(),2,1)='g']">
+                                <form authority="smd">sound cartridge</form>
+                        </xsl:if>
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='s'][substring(text(),2,1)='s']">
+                                <form authority="smd">sound cassette</form>
+                        </xsl:if>
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='s'][substring(text(),2,1)='d']">
+                                <form authority="smd">sound disc</form>
+                        </xsl:if>
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='s'][substring(text(),2,1)='t']">
+                                <form authority="smd">sound-tape reel</form>
+                        </xsl:if>
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='s'][substring(text(),2,1)='i']">
+                                <form authority="smd">sound-track film</form>
+                        </xsl:if>
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='s'][substring(text(),2,1)='w']">
+                                <form authority="smd">wire recording</form>
+                        </xsl:if>
+
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='f'][substring(text(),2,1)='c']">
+                                <form authority="smd">braille</form>
+                        </xsl:if>
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='f'][substring(text(),2,1)='b']">
+                                <form authority="smd">combination</form>
+                        </xsl:if>
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='f'][substring(text(),2,1)='a']">
+                                <form authority="smd">moon</form>
+                        </xsl:if>
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='f'][substring(text(),2,1)='d']">
+                                <form authority="smd">tactile, with no writing system</form>
+                        </xsl:if>
+
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='t'][substring(text(),2,1)='c']">
+                                <form authority="smd">braille</form>
+                        </xsl:if>
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='t'][substring(text(),2,1)='b']">
+                                <form authority="smd">large print</form>
+                        </xsl:if>
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='t'][substring(text(),2,1)='a']">
+                                <form authority="smd">regular print</form>
+                        </xsl:if>
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='t'][substring(text(),2,1)='d']">
+                                <form authority="smd">text in looseleaf binder</form>
+                        </xsl:if>
+
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='v'][substring(text(),2,1)='c']">
+                                <form authority="smd">videocartridge</form>
+                        </xsl:if>
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='v'][substring(text(),2,1)='f']">
+                                <form authority="smd">videocassette</form>
+                        </xsl:if>
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='v'][substring(text(),2,1)='d']">
+                                <form authority="smd">videodisc</form>
+                        </xsl:if>
+                        <xsl:if
+                                test="marc:controlfield[@tag=007][substring(text(),1,1)='v'][substring(text(),2,1)='r']">
+                                <form authority="smd">videoreel</form>
+                        </xsl:if>
+
+                        <xsl:for-each
+                                select="marc:datafield[@tag=856]/marc:subfield[@code='q'][string-length(.)>1]">
+                                <internetMediaType>
+                                        <xsl:value-of select="."/>
+                                </internetMediaType>
+                        </xsl:for-each>
+                        <xsl:for-each select="marc:datafield[@tag=300]">
+                                <extent>
+                                        <xsl:call-template name="subfieldSelect">
+                                                <xsl:with-param name="codes">abce</xsl:with-param>
+                                        </xsl:call-template>
+                                </extent>
+                        </xsl:for-each>
+                </xsl:variable>
+                <xsl:if test="string-length(normalize-space($physicalDescription))">
+                        <physicalDescription>
+                                <xsl:copy-of select="$physicalDescription"/>
+                        </physicalDescription>
+                </xsl:if>
+                <xsl:for-each select="marc:datafield[@tag=520]">
+                        <abstract>
+                                <xsl:call-template name="uri"/>
+                                <xsl:call-template name="subfieldSelect">
+                                        <xsl:with-param name="codes">ab</xsl:with-param>
+                                </xsl:call-template>
+                        </abstract>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=505]">
+                        <tableOfContents>
+                                <xsl:call-template name="uri"/>
+                                <xsl:call-template name="subfieldSelect">
+                                        <xsl:with-param name="codes">agrt</xsl:with-param>
+                                </xsl:call-template>
+                        </tableOfContents>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=521]">
+                        <targetAudience>
+                                <xsl:call-template name="subfieldSelect">
+                                        <xsl:with-param name="codes">ab</xsl:with-param>
+                                </xsl:call-template>
+                        </targetAudience>
+                </xsl:for-each>
+                <xsl:if test="$typeOf008='BK' or $typeOf008='CF' or $typeOf008='MU' or $typeOf008='VM'">
+                        <xsl:variable name="controlField008-22" select="substring($controlField008,23,1)"/>
+                        <xsl:choose>
+                                <!-- 01/04 fix -->
+                                <xsl:when test="$controlField008-22='d'">
+                                        <targetAudience authority="marctarget">adolescent</targetAudience>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-22='e'">
+                                        <targetAudience authority="marctarget">adult</targetAudience>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-22='g'">
+                                        <targetAudience authority="marctarget">general</targetAudience>
+                                </xsl:when>
+                                <xsl:when
+                                        test="$controlField008-22='b' or $controlField008-22='c' or $controlField008-22='j'">
+                                        <targetAudience authority="marctarget">juvenile</targetAudience>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-22='a'">
+                                        <targetAudience authority="marctarget">preschool</targetAudience>
+                                </xsl:when>
+                                <xsl:when test="$controlField008-22='f'">
+                                        <targetAudience authority="marctarget">specialized</targetAudience>
+                                </xsl:when>
+                        </xsl:choose>
+                </xsl:if>
+                <xsl:for-each select="marc:datafield[@tag=245]/marc:subfield[@code='c']">
+                        <note type="statement of responsibility">
+                                <xsl:value-of select="."/>
+                        </note>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=500]">
+                        <note>
+                                <xsl:value-of select="marc:subfield[@code='a']"/>
+                                <xsl:call-template name="uri"/>
+                        </note>
+                </xsl:for-each>
+
+                <!--3.2 change tmee additional note fields-->
+
+                <xsl:for-each select="marc:datafield[@tag=506]">
+                        <note type="restrictions">
+                                <xsl:call-template name="uri"/>
+                                <xsl:variable name="str">
+                                        <xsl:for-each select="marc:subfield[@code!='6' or @code!='8']">
+                                                <xsl:value-of select="."/>
+                                                <xsl:text> </xsl:text>
+                                        </xsl:for-each>
+                                </xsl:variable>
+                                <xsl:value-of select="substring($str,1,string-length($str)-1)"/>
+                        </note>
+                </xsl:for-each>
+
+                <xsl:for-each select="marc:datafield[@tag=510]">
+                        <note type="citation/reference">
+                                <xsl:call-template name="uri"/>
+                                <xsl:variable name="str">
+                                        <xsl:for-each select="marc:subfield[@code!='6' or @code!='8']">
+                                                <xsl:value-of select="."/>
+                                                <xsl:text> </xsl:text>
+                                        </xsl:for-each>
+                                </xsl:variable>
+                                <xsl:value-of select="substring($str,1,string-length($str)-1)"/>
+                        </note>
+                </xsl:for-each>
+
+
+                <xsl:for-each select="marc:datafield[@tag=511]">
+                        <note type="performers">
+                                <xsl:call-template name="uri"/>
+                                <xsl:value-of select="marc:subfield[@code='a']"/>
+                        </note>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=518]">
+                        <note type="venue">
+                                <xsl:call-template name="uri"/>
+                                <xsl:value-of select="marc:subfield[@code='a']"/>
+                        </note>
+                </xsl:for-each>
+
+                <xsl:for-each select="marc:datafield[@tag=530]">
+                        <note type="additional physical form">
+                                <xsl:call-template name="uri"/>
+                                <xsl:variable name="str">
+                                        <xsl:for-each select="marc:subfield[@code!='6' or @code!='8']">
+                                                <xsl:value-of select="."/>
+                                                <xsl:text> </xsl:text>
+                                        </xsl:for-each>
+                                </xsl:variable>
+                                <xsl:value-of select="substring($str,1,string-length($str)-1)"/>
+                        </note>
+                </xsl:for-each>
+
+                <xsl:for-each select="marc:datafield[@tag=533]">
+                        <note type="reproduction">
+                                <xsl:call-template name="uri"/>
+                                <xsl:variable name="str">
+                                        <xsl:for-each select="marc:subfield[@code!='6' or @code!='8']">
+                                                <xsl:value-of select="."/>
+                                                <xsl:text> </xsl:text>
+                                        </xsl:for-each>
+                                </xsl:variable>
+                                <xsl:value-of select="substring($str,1,string-length($str)-1)"/>
+                        </note>
+                </xsl:for-each>
+
+                <xsl:for-each select="marc:datafield[@tag=534]">
+                        <note type="original version">
+                                <xsl:call-template name="uri"/>
+                                <xsl:variable name="str">
+                                        <xsl:for-each select="marc:subfield[@code!='6' or @code!='8']">
+                                                <xsl:value-of select="."/>
+                                                <xsl:text> </xsl:text>
+                                        </xsl:for-each>
+                                </xsl:variable>
+                                <xsl:value-of select="substring($str,1,string-length($str)-1)"/>
+                        </note>
+                </xsl:for-each>
+
+                <xsl:for-each select="marc:datafield[@tag=538]">
+                        <note type="system details">
+                                <xsl:call-template name="uri"/>
+                                <xsl:variable name="str">
+                                        <xsl:for-each select="marc:subfield[@code!='6' or @code!='8']">
+                                                <xsl:value-of select="."/>
+                                                <xsl:text> </xsl:text>
+                                        </xsl:for-each>
+                                </xsl:variable>
+                                <xsl:value-of select="substring($str,1,string-length($str)-1)"/>
+                        </note>
+                </xsl:for-each>
+
+                <xsl:for-each select="marc:datafield[@tag=583]">
+                        <note type="action">
+                                <xsl:call-template name="uri"/>
+                                <xsl:variable name="str">
+                                        <xsl:for-each select="marc:subfield[@code!='6' or @code!='8']">
+                                                <xsl:value-of select="."/>
+                                                <xsl:text> </xsl:text>
+                                        </xsl:for-each>
+                                </xsl:variable>
+                                <xsl:value-of select="substring($str,1,string-length($str)-1)"/>
+                        </note>
+                </xsl:for-each>
+
+                <xsl:for-each
+                        select="marc:datafield[@tag=501 or @tag=502 or @tag=504 or @tag=507 or @tag=508 or  @tag=513 or @tag=514 or @tag=515 or @tag=516 or @tag=522 or @tag=524 or @tag=525 or @tag=526 or @tag=535 or @tag=536 or @tag=540 or @tag=541 or @tag=544 or @tag=545 or @tag=546 or @tag=547 or @tag=550 or @tag=552 or @tag=555 or @tag=556 or @tag=561 or @tag=562 or @tag=565 or @tag=567 or @tag=580 or @tag=581 or @tag=584 or @tag=585 or @tag=586]">+
+                        <note>
+                                <xsl:call-template name="uri"/>
+                                <xsl:variable name="str">
+                                        <xsl:for-each select="marc:subfield[@code!='6' or @code!='8']">
+                                                <xsl:value-of select="."/>
+                                                <xsl:text> </xsl:text>
+                                        </xsl:for-each>
+                                </xsl:variable>
+                                <xsl:value-of select="substring($str,1,string-length($str)-1)"/>
+                        </note>
+                </xsl:for-each>
+                <xsl:for-each
+                        select="marc:datafield[@tag=034][marc:subfield[@code='d' or @code='e' or @code='f' or @code='g']]">
+                        <subject>
+                                <cartographics>
+                                        <coordinates>
+                                                <xsl:call-template name="subfieldSelect">
+                                                        <xsl:with-param name="codes">defg</xsl:with-param>
+                                                </xsl:call-template>
+                                        </coordinates>
+                                </cartographics>
+                        </subject>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=043]">
+                        <subject>
+                                <xsl:for-each select="marc:subfield[@code='a' or @code='b' or @code='c']">
+                                        <geographicCode>
+                                                <xsl:attribute name="authority">
+                                                        <xsl:if test="@code='a'">
+                                                                <xsl:text>marcgac</xsl:text>
+                                                        </xsl:if>
+                                                        <xsl:if test="@code='b'">
+                                                                <xsl:value-of select="following-sibling::marc:subfield[@code=2]"/>
+                                                        </xsl:if>
+                                                        <xsl:if test="@code='c'">
+                                                                <xsl:text>iso3166</xsl:text>
+                                                        </xsl:if>
+                                                </xsl:attribute>
+                                                <xsl:value-of select="self::marc:subfield"/>
+                                        </geographicCode>
+                                </xsl:for-each>
+                        </subject>
+                </xsl:for-each>
+                <!-- tmee 2006/11/27 -->
+                <xsl:for-each select="marc:datafield[@tag=255]">
+                        <subject>
+                                <xsl:for-each select="marc:subfield[@code='a' or @code='b' or @code='c']">
+                                        <cartographics>
+                                                <xsl:if test="@code='a'">
+                                                        <scale>
+                                                                <xsl:value-of select="."/>
+                                                        </scale>
+                                                </xsl:if>
+                                                <xsl:if test="@code='b'">
+                                                        <projection>
+                                                                <xsl:value-of select="."/>
+                                                        </projection>
+                                                </xsl:if>
+                                                <xsl:if test="@code='c'">
+                                                        <coordinates>
+                                                                <xsl:value-of select="."/>
+                                                        </coordinates>
+                                                </xsl:if>
+                                        </cartographics>
+                                </xsl:for-each>
+                        </subject>
+                </xsl:for-each>
+
+                <xsl:apply-templates select="marc:datafield[653 >= @tag and @tag >= 600]"/>
+                <xsl:apply-templates select="marc:datafield[@tag=656]"/>
+                <xsl:for-each select="marc:datafield[@tag=752 or @tag=662]">
+                        <subject>
+                                <hierarchicalGeographic>
+                                        <xsl:for-each select="marc:subfield[@code='a']">
+                                                <country>
+                                                        <xsl:call-template name="chopPunctuation">
+                                                                <xsl:with-param name="chopString" select="."/>
+                                                        </xsl:call-template>
+                                                </country>
+                                        </xsl:for-each>
+                                        <xsl:for-each select="marc:subfield[@code='b']">
+                                                <state>
+                                                        <xsl:call-template name="chopPunctuation">
+                                                                <xsl:with-param name="chopString" select="."/>
+                                                        </xsl:call-template>
+                                                </state>
+                                        </xsl:for-each>
+                                        <xsl:for-each select="marc:subfield[@code='c']">
+                                                <county>
+                                                        <xsl:call-template name="chopPunctuation">
+                                                                <xsl:with-param name="chopString" select="."/>
+                                                        </xsl:call-template>
+                                                </county>
+                                        </xsl:for-each>
+                                        <xsl:for-each select="marc:subfield[@code='d']">
+                                                <city>
+                                                        <xsl:call-template name="chopPunctuation">
+                                                                <xsl:with-param name="chopString" select="."/>
+                                                        </xsl:call-template>
+                                                </city>
+                                        </xsl:for-each>
+                                        <xsl:for-each select="marc:subfield[@code='e']">
+                                                <citySection>
+                                                        <xsl:call-template name="chopPunctuation">
+                                                                <xsl:with-param name="chopString" select="."/>
+                                                        </xsl:call-template>
+                                                </citySection>
+                                        </xsl:for-each>
+                                        <xsl:for-each select="marc:subfield[@code='g']">
+                                                <region>
+                                                        <xsl:call-template name="chopPunctuation">
+                                                                <xsl:with-param name="chopString" select="."/>
+                                                        </xsl:call-template>
+                                                </region>
+                                        </xsl:for-each>
+                                        <xsl:for-each select="marc:subfield[@code='h']">
+                                                <extraterrestrialArea>
+                                                        <xsl:call-template name="chopPunctuation">
+                                                                <xsl:with-param name="chopString" select="."/>
+                                                        </xsl:call-template>
+                                                </extraterrestrialArea>
+                                        </xsl:for-each>
+                                </hierarchicalGeographic>
+                        </subject>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=045][marc:subfield[@code='b']]">
+                        <subject>
+                                <xsl:choose>
+                                        <xsl:when test="@ind1=2">
+                                                <temporal encoding="iso8601" point="start">
+                                                        <xsl:call-template name="chopPunctuation">
+                                                                <xsl:with-param name="chopString">
+                                                                        <xsl:value-of select="marc:subfield[@code='b'][1]"/>
+                                                                </xsl:with-param>
+                                                        </xsl:call-template>
+                                                </temporal>
+                                                <temporal encoding="iso8601" point="end">
+                                                        <xsl:call-template name="chopPunctuation">
+                                                                <xsl:with-param name="chopString">
+                                                                        <xsl:value-of select="marc:subfield[@code='b'][2]"/>
+                                                                </xsl:with-param>
+                                                        </xsl:call-template>
+                                                </temporal>
+                                        </xsl:when>
+                                        <xsl:otherwise>
+                                                <xsl:for-each select="marc:subfield[@code='b']">
+                                                        <temporal encoding="iso8601">
+                                                                <xsl:call-template name="chopPunctuation">
+                                                                        <xsl:with-param name="chopString" select="."/>
+                                                                </xsl:call-template>
+                                                        </temporal>
+                                                </xsl:for-each>
+                                        </xsl:otherwise>
+                                </xsl:choose>
+                        </subject>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=050]">
+                        <xsl:for-each select="marc:subfield[@code='b']">
+                                <classification authority="lcc">
+                                        <xsl:if test="../marc:subfield[@code='3']">
+                                                <xsl:attribute name="displayLabel">
+                                                        <xsl:value-of select="../marc:subfield[@code='3']"/>
+                                                </xsl:attribute>
+                                        </xsl:if>
+                                        <xsl:value-of select="preceding-sibling::marc:subfield[@code='a'][1]"/>
+                                        <xsl:text> </xsl:text>
+                                        <xsl:value-of select="text()"/>
+                                </classification>
+                        </xsl:for-each>
+                        <xsl:for-each
+                                select="marc:subfield[@code='a'][not(following-sibling::marc:subfield[@code='b'])]">
+                                <classification authority="lcc">
+                                        <xsl:if test="../marc:subfield[@code='3']">
+                                                <xsl:attribute name="displayLabel">
+                                                        <xsl:value-of select="../marc:subfield[@code='3']"/>
+                                                </xsl:attribute>
+                                        </xsl:if>
+                                        <xsl:value-of select="text()"/>
+                                </classification>
+                        </xsl:for-each>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=082]">
+                        <classification authority="ddc">
+                                <xsl:if test="marc:subfield[@code='2']">
+                                        <xsl:attribute name="edition">
+                                                <xsl:value-of select="marc:subfield[@code='2']"/>
+                                        </xsl:attribute>
+                                </xsl:if>
+                                <xsl:call-template name="subfieldSelect">
+                                        <xsl:with-param name="codes">ab</xsl:with-param>
+                                </xsl:call-template>
+                        </classification>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=080]">
+                        <classification authority="udc">
+                                <xsl:call-template name="subfieldSelect">
+                                        <xsl:with-param name="codes">abx</xsl:with-param>
+                                </xsl:call-template>
+                        </classification>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=060]">
+                        <classification authority="nlm">
+                                <xsl:call-template name="subfieldSelect">
+                                        <xsl:with-param name="codes">ab</xsl:with-param>
+                                </xsl:call-template>
+                        </classification>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=086][@ind1=0]">
+                        <classification authority="sudocs">
+                                <xsl:value-of select="marc:subfield[@code='a']"/>
+                        </classification>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=086][@ind1=1]">
+                        <classification authority="candoc">
+                                <xsl:value-of select="marc:subfield[@code='a']"/>
+                        </classification>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=086]">
+                        <classification>
+                                <xsl:attribute name="authority">
+                                        <xsl:value-of select="marc:subfield[@code='2']"/>
+                                </xsl:attribute>
+                                <xsl:value-of select="marc:subfield[@code='a']"/>
+                        </classification>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=084]">
+                        <classification>
+                                <xsl:attribute name="authority">
+                                        <xsl:value-of select="marc:subfield[@code='2']"/>
+                                </xsl:attribute>
+                                <xsl:call-template name="subfieldSelect">
+                                        <xsl:with-param name="codes">ab</xsl:with-param>
+                                </xsl:call-template>
+                        </classification>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=440]">
+                        <relatedItem type="series">
+                                <titleInfo>
+                                        <title>
+                                                <xsl:call-template name="chopPunctuation">
+                                                        <xsl:with-param name="chopString">
+                                                                <xsl:call-template name="subfieldSelect">
+                                                                        <xsl:with-param name="codes">av</xsl:with-param>
+                                                                </xsl:call-template>
+                                                        </xsl:with-param>
+                                                </xsl:call-template>
+                                        </title>
+                                        <xsl:call-template name="part"/>
+                                </titleInfo>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=490][@ind1=0]">
+                        <relatedItem type="series">
+                                <titleInfo>
+                                        <title>
+                                                <xsl:call-template name="chopPunctuation">
+                                                        <xsl:with-param name="chopString">
+                                                                <xsl:call-template name="subfieldSelect">
+                                                                        <xsl:with-param name="codes">av</xsl:with-param>
+                                                                </xsl:call-template>
+                                                        </xsl:with-param>
+                                                </xsl:call-template>
+                                        </title>
+                                        <xsl:call-template name="part"/>
+                                </titleInfo>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=510]">
+                        <relatedItem type="isReferencedBy">
+                                <note>
+                                        <xsl:call-template name="subfieldSelect">
+                                                <xsl:with-param name="codes">abcx3</xsl:with-param>
+                                        </xsl:call-template>
+                                </note>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=534]">
+                        <relatedItem type="original">
+                                <xsl:call-template name="relatedTitle"/>
+                                <xsl:call-template name="relatedName"/>
+                                <xsl:if test="marc:subfield[@code='b' or @code='c']">
+                                        <originInfo>
+                                                <xsl:for-each select="marc:subfield[@code='c']">
+                                                        <publisher>
+                                                                <xsl:value-of select="."/>
+                                                        </publisher>
+                                                </xsl:for-each>
+                                                <xsl:for-each select="marc:subfield[@code='b']">
+                                                        <edition>
+                                                                <xsl:value-of select="."/>
+                                                        </edition>
+                                                </xsl:for-each>
+                                        </originInfo>
+                                </xsl:if>
+                                <xsl:call-template name="relatedIdentifierISSN"/>
+                                <xsl:for-each select="marc:subfield[@code='z']">
+                                        <identifier type="isbn">
+                                                <xsl:value-of select="."/>
+                                        </identifier>
+                                </xsl:for-each>
+                                <xsl:call-template name="relatedNote"/>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=700][marc:subfield[@code='t']]">
+                        <relatedItem>
+                                <xsl:call-template name="constituentOrRelatedType"/>
+                                <titleInfo>
+                                        <title>
+                                                <xsl:call-template name="chopPunctuation">
+                                                        <xsl:with-param name="chopString">
+                                                                <xsl:call-template name="specialSubfieldSelect">
+                                                                        <xsl:with-param name="anyCodes">tfklmorsv</xsl:with-param>
+                                                                        <xsl:with-param name="axis">t</xsl:with-param>
+                                                                        <xsl:with-param name="afterCodes">g</xsl:with-param>
+                                                                </xsl:call-template>
+                                                        </xsl:with-param>
+                                                </xsl:call-template>
+                                        </title>
+                                        <xsl:call-template name="part"/>
+                                </titleInfo>
+                                <name type="personal">
+                                        <namePart>
+                                                <xsl:call-template name="specialSubfieldSelect">
+                                                        <xsl:with-param name="anyCodes">aq</xsl:with-param>
+                                                        <xsl:with-param name="axis">t</xsl:with-param>
+                                                        <xsl:with-param name="beforeCodes">g</xsl:with-param>
+                                                </xsl:call-template>
+                                        </namePart>
+                                        <xsl:call-template name="termsOfAddress"/>
+                                        <xsl:call-template name="nameDate"/>
+                                        <xsl:call-template name="role"/>
+                                </name>
+                                <xsl:call-template name="relatedForm"/>
+                                <xsl:call-template name="relatedIdentifierISSN"/>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=710][marc:subfield[@code='t']]">
+                        <relatedItem>
+                                <xsl:call-template name="constituentOrRelatedType"/>
+                                <titleInfo>
+                                        <title>
+                                                <xsl:call-template name="chopPunctuation">
+                                                        <xsl:with-param name="chopString">
+                                                                <xsl:call-template name="specialSubfieldSelect">
+                                                                        <xsl:with-param name="anyCodes">tfklmorsv</xsl:with-param>
+                                                                        <xsl:with-param name="axis">t</xsl:with-param>
+                                                                        <xsl:with-param name="afterCodes">dg</xsl:with-param>
+                                                                </xsl:call-template>
+                                                        </xsl:with-param>
+                                                </xsl:call-template>
+                                        </title>
+                                        <xsl:call-template name="relatedPartNumName"/>
+                                </titleInfo>
+                                <name type="corporate">
+                                        <xsl:for-each select="marc:subfield[@code='a']">
+                                                <namePart>
+                                                        <xsl:value-of select="."/>
+                                                </namePart>
+                                        </xsl:for-each>
+                                        <xsl:for-each select="marc:subfield[@code='b']">
+                                                <namePart>
+                                                        <xsl:value-of select="."/>
+                                                </namePart>
+                                        </xsl:for-each>
+                                        <xsl:variable name="tempNamePart">
+                                                <xsl:call-template name="specialSubfieldSelect">
+                                                        <xsl:with-param name="anyCodes">c</xsl:with-param>
+                                                        <xsl:with-param name="axis">t</xsl:with-param>
+                                                        <xsl:with-param name="beforeCodes">dgn</xsl:with-param>
+                                                </xsl:call-template>
+                                        </xsl:variable>
+                                        <xsl:if test="normalize-space($tempNamePart)">
+                                                <namePart>
+                                                        <xsl:value-of select="$tempNamePart"/>
+                                                </namePart>
+                                        </xsl:if>
+                                        <xsl:call-template name="role"/>
+                                </name>
+                                <xsl:call-template name="relatedForm"/>
+                                <xsl:call-template name="relatedIdentifierISSN"/>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=711][marc:subfield[@code='t']]">
+                        <relatedItem>
+                                <xsl:call-template name="constituentOrRelatedType"/>
+                                <titleInfo>
+                                        <title>
+                                                <xsl:call-template name="chopPunctuation">
+                                                        <xsl:with-param name="chopString">
+                                                                <xsl:call-template name="specialSubfieldSelect">
+                                                                        <xsl:with-param name="anyCodes">tfklsv</xsl:with-param>
+                                                                        <xsl:with-param name="axis">t</xsl:with-param>
+                                                                        <xsl:with-param name="afterCodes">g</xsl:with-param>
+                                                                </xsl:call-template>
+                                                        </xsl:with-param>
+                                                </xsl:call-template>
+                                        </title>
+                                        <xsl:call-template name="relatedPartNumName"/>
+                                </titleInfo>
+                                <name type="conference">
+                                        <namePart>
+                                                <xsl:call-template name="specialSubfieldSelect">
+                                                        <xsl:with-param name="anyCodes">aqdc</xsl:with-param>
+                                                        <xsl:with-param name="axis">t</xsl:with-param>
+                                                        <xsl:with-param name="beforeCodes">gn</xsl:with-param>
+                                                </xsl:call-template>
+                                        </namePart>
+                                </name>
+                                <xsl:call-template name="relatedForm"/>
+                                <xsl:call-template name="relatedIdentifierISSN"/>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=730][@ind2=2]">
+                        <relatedItem>
+                                <xsl:call-template name="constituentOrRelatedType"/>
+                                <titleInfo>
+                                        <title>
+                                                <xsl:call-template name="chopPunctuation">
+                                                        <xsl:with-param name="chopString">
+                                                                <xsl:call-template name="subfieldSelect">
+                                                                        <xsl:with-param name="codes">adfgklmorsv</xsl:with-param>
+                                                                </xsl:call-template>
+                                                        </xsl:with-param>
+                                                </xsl:call-template>
+                                        </title>
+                                        <xsl:call-template name="part"/>
+                                </titleInfo>
+                                <xsl:call-template name="relatedForm"/>
+                                <xsl:call-template name="relatedIdentifierISSN"/>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=740][@ind2=2]">
+                        <relatedItem>
+                                <xsl:call-template name="constituentOrRelatedType"/>
+                                <titleInfo>
+                                        <title>
+                                                <xsl:call-template name="chopPunctuation">
+                                                        <xsl:with-param name="chopString">
+                                                                <xsl:value-of select="marc:subfield[@code='a']"/>
+                                                        </xsl:with-param>
+                                                </xsl:call-template>
+                                        </title>
+                                        <xsl:call-template name="part"/>
+                                </titleInfo>
+                                <xsl:call-template name="relatedForm"/>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=760]|marc:datafield[@tag=762]">
+                        <relatedItem type="series">
+                                <xsl:call-template name="relatedItem76X-78X"/>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each
+                        select="marc:datafield[@tag=765]|marc:datafield[@tag=767]|marc:datafield[@tag=777]|marc:datafield[@tag=787]">
+                        <relatedItem>
+                                <xsl:call-template name="relatedItem76X-78X"/>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=775]">
+                        <relatedItem type="otherVersion">
+                                <xsl:call-template name="relatedItem76X-78X"/>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=770]|marc:datafield[@tag=774]">
+                        <relatedItem type="constituent">
+                                <xsl:call-template name="relatedItem76X-78X"/>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=772]|marc:datafield[@tag=773]">
+                        <relatedItem type="host">
+                                <xsl:call-template name="relatedItem76X-78X"/>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=776]">
+                        <relatedItem type="otherFormat">
+                                <xsl:call-template name="relatedItem76X-78X"/>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=780]">
+                        <relatedItem type="preceding">
+                                <xsl:call-template name="relatedItem76X-78X"/>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=785]">
+                        <relatedItem type="succeeding">
+                                <xsl:call-template name="relatedItem76X-78X"/>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=786]">
+                        <relatedItem type="original">
+                                <xsl:call-template name="relatedItem76X-78X"/>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=800]">
+                        <relatedItem type="series">
+                                <titleInfo>
+                                        <title>
+                                                <xsl:call-template name="chopPunctuation">
+                                                        <xsl:with-param name="chopString">
+                                                                <xsl:call-template name="specialSubfieldSelect">
+                                                                        <xsl:with-param name="anyCodes">tfklmorsv</xsl:with-param>
+                                                                        <xsl:with-param name="axis">t</xsl:with-param>
+                                                                        <xsl:with-param name="afterCodes">g</xsl:with-param>
+                                                                </xsl:call-template>
+                                                        </xsl:with-param>
+                                                </xsl:call-template>
+                                        </title>
+                                        <xsl:call-template name="part"/>
+                                </titleInfo>
+                                <name type="personal">
+                                        <namePart>
+                                                <xsl:call-template name="chopPunctuation">
+                                                        <xsl:with-param name="chopString">
+                                                                <xsl:call-template name="specialSubfieldSelect">
+                                                                        <xsl:with-param name="anyCodes">aq</xsl:with-param>
+                                                                        <xsl:with-param name="axis">t</xsl:with-param>
+                                                                        <xsl:with-param name="beforeCodes">g</xsl:with-param>
+                                                                </xsl:call-template>
+                                                        </xsl:with-param>
+                                                </xsl:call-template>
+                                        </namePart>
+                                        <xsl:call-template name="termsOfAddress"/>
+                                        <xsl:call-template name="nameDate"/>
+                                        <xsl:call-template name="role"/>
+                                </name>
+                                <xsl:call-template name="relatedForm"/>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=810]">
+                        <relatedItem type="series">
+                                <titleInfo>
+                                        <title>
+                                                <xsl:call-template name="chopPunctuation">
+                                                        <xsl:with-param name="chopString">
+                                                                <xsl:call-template name="specialSubfieldSelect">
+                                                                        <xsl:with-param name="anyCodes">tfklmorsv</xsl:with-param>
+                                                                        <xsl:with-param name="axis">t</xsl:with-param>
+                                                                        <xsl:with-param name="afterCodes">dg</xsl:with-param>
+                                                                </xsl:call-template>
+                                                        </xsl:with-param>
+                                                </xsl:call-template>
+                                        </title>
+                                        <xsl:call-template name="relatedPartNumName"/>
+                                </titleInfo>
+                                <name type="corporate">
+                                        <xsl:for-each select="marc:subfield[@code='a']">
+                                                <namePart>
+                                                        <xsl:value-of select="."/>
+                                                </namePart>
+                                        </xsl:for-each>
+                                        <xsl:for-each select="marc:subfield[@code='b']">
+                                                <namePart>
+                                                        <xsl:value-of select="."/>
+                                                </namePart>
+                                        </xsl:for-each>
+                                        <namePart>
+                                                <xsl:call-template name="specialSubfieldSelect">
+                                                        <xsl:with-param name="anyCodes">c</xsl:with-param>
+                                                        <xsl:with-param name="axis">t</xsl:with-param>
+                                                        <xsl:with-param name="beforeCodes">dgn</xsl:with-param>
+                                                </xsl:call-template>
+                                        </namePart>
+                                        <xsl:call-template name="role"/>
+                                </name>
+                                <xsl:call-template name="relatedForm"/>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=811]">
+                        <relatedItem type="series">
+                                <titleInfo>
+                                        <title>
+                                                <xsl:call-template name="chopPunctuation">
+                                                        <xsl:with-param name="chopString">
+                                                                <xsl:call-template name="specialSubfieldSelect">
+                                                                        <xsl:with-param name="anyCodes">tfklsv</xsl:with-param>
+                                                                        <xsl:with-param name="axis">t</xsl:with-param>
+                                                                        <xsl:with-param name="afterCodes">g</xsl:with-param>
+                                                                </xsl:call-template>
+                                                        </xsl:with-param>
+                                                </xsl:call-template>
+                                        </title>
+                                        <xsl:call-template name="relatedPartNumName"/>
+                                </titleInfo>
+                                <name type="conference">
+                                        <namePart>
+                                                <xsl:call-template name="specialSubfieldSelect">
+                                                        <xsl:with-param name="anyCodes">aqdc</xsl:with-param>
+                                                        <xsl:with-param name="axis">t</xsl:with-param>
+                                                        <xsl:with-param name="beforeCodes">gn</xsl:with-param>
+                                                </xsl:call-template>
+                                        </namePart>
+                                        <xsl:call-template name="role"/>
+                                </name>
+                                <xsl:call-template name="relatedForm"/>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag='830']">
+                        <relatedItem type="series">
+                                <titleInfo>
+                                        <title>
+                                                <xsl:call-template name="chopPunctuation">
+                                                        <xsl:with-param name="chopString">
+                                                                <xsl:call-template name="subfieldSelect">
+                                                                        <xsl:with-param name="codes">adfgklmorsv</xsl:with-param>
+                                                                </xsl:call-template>
+                                                        </xsl:with-param>
+                                                </xsl:call-template>
+                                        </title>
+                                        <xsl:call-template name="part"/>
+                                </titleInfo>
+                                <xsl:call-template name="relatedForm"/>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag='856'][@ind2='2']/marc:subfield[@code='q']">
+                        <relatedItem>
+                                <internetMediaType>
+                                        <xsl:value-of select="."/>
+                                </internetMediaType>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag='020']">
+                        <xsl:call-template name="isInvalid">
+                                <xsl:with-param name="type">isbn</xsl:with-param>
+                        </xsl:call-template>
+                        <xsl:if test="marc:subfield[@code='a']">
+                                <identifier type="isbn">
+                                        <xsl:value-of select="marc:subfield[@code='a']"/>
+                                </identifier>
+                        </xsl:if>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag='024'][@ind1='0']">
+                        <xsl:call-template name="isInvalid">
+                                <xsl:with-param name="type">isrc</xsl:with-param>
+                        </xsl:call-template>
+                        <xsl:if test="marc:subfield[@code='a']">
+                                <identifier type="isrc">
+                                        <xsl:value-of select="marc:subfield[@code='a']"/>
+                                </identifier>
+                        </xsl:if>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag='024'][@ind1='2']">
+                        <xsl:call-template name="isInvalid">
+                                <xsl:with-param name="type">ismn</xsl:with-param>
+                        </xsl:call-template>
+                        <xsl:if test="marc:subfield[@code='a']">
+                                <identifier type="ismn">
+                                        <xsl:value-of select="marc:subfield[@code='a']"/>
+                                </identifier>
+                        </xsl:if>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag='024'][@ind1='4']">
+                        <xsl:call-template name="isInvalid">
+                                <xsl:with-param name="type">sici</xsl:with-param>
+                        </xsl:call-template>
+                        <identifier type="sici">
+                                <xsl:call-template name="subfieldSelect">
+                                        <xsl:with-param name="codes">ab</xsl:with-param>
+                                </xsl:call-template>
+                        </identifier>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag='022']">
+                        <xsl:if test="marc:subfield[@code='a']">
+                                <xsl:call-template name="isInvalid">
+                                        <xsl:with-param name="type">issn</xsl:with-param>
+                                </xsl:call-template>
+                                <identifier type="issn">
+                                        <xsl:value-of select="marc:subfield[@code='a']"/>
+                                </identifier>
+                        </xsl:if>
+                        <xsl:if test="marc:subfield[@code='l']">
+                                <xsl:call-template name="isInvalid">
+                                        <xsl:with-param name="type">issn-l</xsl:with-param>
+                                </xsl:call-template>
+                                <identifier type="issn-l">
+                                        <xsl:value-of select="marc:subfield[@code='l']"/>
+                                </identifier>
+                        </xsl:if>
+                </xsl:for-each>
+
+
+
+                <xsl:for-each select="marc:datafield[@tag='010']">
+                        <xsl:call-template name="isInvalid">
+                                <xsl:with-param name="type">lccn</xsl:with-param>
+                        </xsl:call-template>
+                        <identifier type="lccn">
+                                <xsl:value-of select="normalize-space(marc:subfield[@code='a'])"/>
+                        </identifier>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag='028']">
+                        <identifier>
+                                <xsl:attribute name="type">
+                                        <xsl:choose>
+                                                <xsl:when test="@ind1='0'">issue number</xsl:when>
+                                                <xsl:when test="@ind1='1'">matrix number</xsl:when>
+                                                <xsl:when test="@ind1='2'">music plate</xsl:when>
+                                                <xsl:when test="@ind1='3'">music publisher</xsl:when>
+                                                <xsl:when test="@ind1='4'">videorecording identifier</xsl:when>
+                                        </xsl:choose>
+                                </xsl:attribute>
+                                <!--<xsl:call-template name="isInvalid"/>-->
+                                <!-- no $z in 028 -->
+                                <xsl:call-template name="subfieldSelect">
+                                        <xsl:with-param name="codes">
+                                                <xsl:choose>
+                                                        <xsl:when test="@ind1='0'">ba</xsl:when>
+                                                        <xsl:otherwise>ab</xsl:otherwise>
+                                                </xsl:choose>
+                                        </xsl:with-param>
+                                </xsl:call-template>
+                        </identifier>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag='037']">
+                        <identifier type="stock number">
+                                <!--<xsl:call-template name="isInvalid"/>-->
+                                <!-- no $z in 037 -->
+                                <xsl:call-template name="subfieldSelect">
+                                        <xsl:with-param name="codes">ab</xsl:with-param>
+                                </xsl:call-template>
+                        </identifier>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag='856'][marc:subfield[@code='u']]">
+                        <identifier>
+                                <xsl:attribute name="type">
+                                        <xsl:choose>
+                                                <xsl:when
+                                                        test="starts-with(marc:subfield[@code='u'],'urn:doi') or starts-with(marc:subfield[@code='u'],'doi')"
+                                                        >doi</xsl:when>
+                                                <xsl:when
+                                                        test="starts-with(marc:subfield[@code='u'],'urn:hdl') or starts-with(marc:subfield[@code='u'],'hdl') or starts-with(marc:subfield[@code='u'],'http://hdl.loc.gov')"
+                                                        >hdl</xsl:when>
+                                                <xsl:otherwise>uri</xsl:otherwise>
+                                        </xsl:choose>
+                                </xsl:attribute>
+                                <xsl:choose>
+                                        <xsl:when
+                                                test="starts-with(marc:subfield[@code='u'],'urn:hdl') or starts-with(marc:subfield[@code='u'],'hdl') or starts-with(marc:subfield[@code='u'],'http://hdl.loc.gov') ">
+                                                <xsl:value-of
+                                                        select="concat('hdl:',substring-after(marc:subfield[@code='u'],'http://hdl.loc.gov/'))"
+                                                />
+                                        </xsl:when>
+                                        <xsl:otherwise>
+                                                <xsl:value-of select="marc:subfield[@code='u']"/>
+                                        </xsl:otherwise>
+                                </xsl:choose>
+                        </identifier>
+                        <xsl:if
+                                test="starts-with(marc:subfield[@code='u'],'urn:hdl') or starts-with(marc:subfield[@code='u'],'hdl')">
+                                <identifier type="hdl">
+                                        <xsl:if test="marc:subfield[@code='y' or @code='3' or @code='z']">
+                                                <xsl:attribute name="displayLabel">
+                                                        <xsl:call-template name="subfieldSelect">
+                                                                <xsl:with-param name="codes">y3z</xsl:with-param>
+                                                        </xsl:call-template>
+                                                </xsl:attribute>
+                                        </xsl:if>
+                                        <xsl:value-of
+                                                select="concat('hdl:',substring-after(marc:subfield[@code='u'],'http://hdl.loc.gov/'))"
+                                        />
+                                </identifier>
+                        </xsl:if>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=024][@ind1=1]">
+                        <identifier type="upc">
+                                <xsl:call-template name="isInvalid"/>
+                                <xsl:value-of select="marc:subfield[@code='a']"/>
+                        </identifier>
+                </xsl:for-each>
+
+                <!-- 1/04 fix added $y -->
+
+                <!-- 1.21  tmee-->
+                <xsl:for-each select="marc:datafield[@tag=856][@ind2=1][marc:subfield[@code='u']]">
+                        <relatedItem type="otherVersion">
+                                <location>
+                                        <url>
+                                                <xsl:if test="marc:subfield[@code='y' or @code='3']">
+                                                        <xsl:attribute name="displayLabel">
+                                                                <xsl:call-template name="subfieldSelect">
+                                                                        <xsl:with-param name="codes">y3</xsl:with-param>
+                                                                </xsl:call-template>
+                                                        </xsl:attribute>
+                                                </xsl:if>
+                                                <xsl:if test="marc:subfield[@code='z' ]">
+                                                        <xsl:attribute name="note">
+                                                                <xsl:call-template name="subfieldSelect">
+                                                                        <xsl:with-param name="codes">z</xsl:with-param>
+                                                                </xsl:call-template>
+                                                        </xsl:attribute>
+                                                </xsl:if>
+                                                <xsl:value-of select="marc:subfield[@code='u']"/>
+                                        </url>
+                                </location>
+                        </relatedItem>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=856][@ind2=2][marc:subfield[@code='u']]">
+                        <relatedItem>
+                                <location>
+                                        <url>
+                                                <xsl:if test="marc:subfield[@code='y' or @code='3']">
+                                                        <xsl:attribute name="displayLabel">
+                                                                <xsl:call-template name="subfieldSelect">
+                                                                        <xsl:with-param name="codes">y3</xsl:with-param>
+                                                                </xsl:call-template>
+                                                        </xsl:attribute>
+                                                </xsl:if>
+                                                <xsl:if test="marc:subfield[@code='z' ]">
+                                                        <xsl:attribute name="note">
+                                                                <xsl:call-template name="subfieldSelect">
+                                                                        <xsl:with-param name="codes">z</xsl:with-param>
+                                                                </xsl:call-template>
+                                                        </xsl:attribute>
+                                                </xsl:if>
+                                                <xsl:value-of select="marc:subfield[@code='u']"/>
+                                        </url>
+                                </location>
+                        </relatedItem>
+                </xsl:for-each>
+
+                <!-- 3.2 change tmee 856z  -->
+
+                <!-- 1.24  tmee  -->
+                <xsl:for-each select="marc:datafield[@tag=852]">
+                        <location>
+                                <xsl:if test="marc:subfield[@code='a' or @code='b' or @code='e']">
+                                        <physicalLocation>
+                                                <xsl:call-template name="subfieldSelect">
+                                                        <xsl:with-param name="codes">abe</xsl:with-param>
+                                                </xsl:call-template>
+                                        </physicalLocation>
+                                </xsl:if>
+
+                                <xsl:if test="marc:subfield[@code='u']">
+                                        <physicalLocation>
+                                                <xsl:call-template name="uri"/>
+                                                <xsl:call-template name="subfieldSelect">
+                                                        <xsl:with-param name="codes">u</xsl:with-param>
+                                                </xsl:call-template>
+                                        </physicalLocation>
+                                </xsl:if>
+
+                                <xsl:if
+                                        test="marc:subfield[@code='h' or @code='i' or @code='j' or @code='k' or @code='l' or @code='m' or @code='t']">
+                                        <shelfLocation>
+                                                <xsl:call-template name="subfieldSelect">
+                                                        <xsl:with-param name="codes">hijklmt</xsl:with-param>
+                                                </xsl:call-template>
+                                        </shelfLocation>
+                                </xsl:if>
+                        </location>
+                </xsl:for-each>
+
+                <xsl:for-each select="marc:datafield[@tag=506]">
+                        <accessCondition type="restrictionOnAccess">
+                                <xsl:call-template name="subfieldSelect">
+                                        <xsl:with-param name="codes">abcd35</xsl:with-param>
+                                </xsl:call-template>
+                        </accessCondition>
+                </xsl:for-each>
+                <xsl:for-each select="marc:datafield[@tag=540]">
+                        <accessCondition type="useAndReproduction">
+                                <xsl:call-template name="subfieldSelect">
+                                        <xsl:with-param name="codes">abcde35</xsl:with-param>
+                                </xsl:call-template>
+                        </accessCondition>
+                </xsl:for-each>
+
+                <recordInfo>
+                        <!-- 1.25  tmee-->
+
+
+                        <xsl:for-each select="marc:leader[substring($leader,19,1)='a']">
+                                <descriptionStandard>aacr2</descriptionStandard>
+                        </xsl:for-each>
+
+                        <xsl:for-each select="marc:datafield[@tag=040]">
+                                <xsl:if test="marc:subfield[@code='e']">
+                                        <descriptionStandard>
+                                                <xsl:value-of select="marc:subfield[@code='e']"/>
+                                        </descriptionStandard>
+                                </xsl:if>
+                                <recordContentSource authority="marcorg">
+                                        <xsl:value-of select="marc:subfield[@code='a']"/>
+                                </recordContentSource>
+                        </xsl:for-each>
+                        <xsl:for-each select="marc:controlfield[@tag=008]">
+                                <recordCreationDate encoding="marc">
+                                        <xsl:value-of select="substring(.,1,6)"/>
+                                </recordCreationDate>
+                        </xsl:for-each>
+
+                        <xsl:for-each select="marc:controlfield[@tag=005]">
+                                <recordChangeDate encoding="iso8601">
+                                        <xsl:value-of select="."/>
+                                </recordChangeDate>
+                        </xsl:for-each>
+                        <xsl:for-each select="marc:controlfield[@tag=001]">
+                                <recordIdentifier>
+                                        <xsl:if test="../marc:controlfield[@tag=003]">
+                                                <xsl:attribute name="source">
+                                                        <xsl:value-of select="../marc:controlfield[@tag=003]"/>
+                                                </xsl:attribute>
+                                        </xsl:if>
+                                        <xsl:value-of select="."/>
+                                </recordIdentifier>
+                        </xsl:for-each>
+                        <xsl:for-each select="marc:datafield[@tag=040]/marc:subfield[@code='b']">
+                                <languageOfCataloging>
+                                        <languageTerm authority="iso639-2b" type="code">
+                                                <xsl:value-of select="."/>
+                                        </languageTerm>
+                                </languageOfCataloging>
+                        </xsl:for-each>
+                </recordInfo>
+        </xsl:template>
+        <xsl:template name="displayForm">
+                <xsl:for-each select="marc:subfield[@code='c']">
+                        <displayForm>
+                                <xsl:value-of select="."/>
+                        </displayForm>
+                </xsl:for-each>
+        </xsl:template>
+        <xsl:template name="affiliation">
+                <xsl:for-each select="marc:subfield[@code='u']">
+                        <affiliation>
+                                <xsl:value-of select="."/>
+                        </affiliation>
+                </xsl:for-each>
+        </xsl:template>
+        <xsl:template name="uri">
+                <xsl:for-each select="marc:subfield[@code='u']">
+                        <xsl:attribute name="xlink:href">
+                                <xsl:value-of select="."/>
+                        </xsl:attribute>
+                </xsl:for-each>
+                <xsl:for-each select="marc:subfield[@code='0']">
+                        <xsl:choose>
+                                <xsl:when test="contains(text(), ')')">
+                                        <xsl:attribute name="xlink:href">
+                                                <xsl:value-of select="substring-after(text(), ')')"></xsl:value-of>
+                                        </xsl:attribute>
+                                </xsl:when>
+                                <xsl:otherwise>
+                                        <xsl:attribute name="xlink:href">
+                                                <xsl:value-of select="."></xsl:value-of>
+                                        </xsl:attribute>
+                                </xsl:otherwise>
+                        </xsl:choose>
+                </xsl:for-each>
+        </xsl:template>
+        <xsl:template name="role">
+                <xsl:for-each select="marc:subfield[@code='e']">
+                        <role>
+                                <roleTerm type="text">
+                                        <xsl:value-of select="."/>
+                                </roleTerm>
+                        </role>
+                </xsl:for-each>
+                <xsl:for-each select="marc:subfield[@code='4']">
+                        <role>
+                                <roleTerm authority="marcrelator" type="code">
+                                        <xsl:value-of select="."/>
+                                </roleTerm>
+                        </role>
+                </xsl:for-each>
+        </xsl:template>
+        <xsl:template name="part">
+                <xsl:variable name="partNumber">
+                        <xsl:call-template name="specialSubfieldSelect">
+                                <xsl:with-param name="axis">n</xsl:with-param>
+                                <xsl:with-param name="anyCodes">n</xsl:with-param>
+                                <xsl:with-param name="afterCodes">fgkdlmor</xsl:with-param>
+                        </xsl:call-template>
+                </xsl:variable>
+                <xsl:variable name="partName">
+                        <xsl:call-template name="specialSubfieldSelect">
+                                <xsl:with-param name="axis">p</xsl:with-param>
+                                <xsl:with-param name="anyCodes">p</xsl:with-param>
+                                <xsl:with-param name="afterCodes">fgkdlmor</xsl:with-param>
+                        </xsl:call-template>
+                </xsl:variable>
+                <xsl:if test="string-length(normalize-space($partNumber))">
+                        <partNumber>
+                                <xsl:call-template name="chopPunctuation">
+                                        <xsl:with-param name="chopString" select="$partNumber"/>
+                                </xsl:call-template>
+                        </partNumber>
+                </xsl:if>
+                <xsl:if test="string-length(normalize-space($partName))">
+                        <partName>
+                                <xsl:call-template name="chopPunctuation">
+                                        <xsl:with-param name="chopString" select="$partName"/>
+                                </xsl:call-template>
+                        </partName>
+                </xsl:if>
+        </xsl:template>
+        <xsl:template name="relatedPart">
+                <xsl:if test="@tag=773">
+                        <xsl:for-each select="marc:subfield[@code='g']">
+                                <part>
+                                        <text>
+                                                <xsl:value-of select="."/>
+                                        </text>
+                                </part>
+                        </xsl:for-each>
+                        <xsl:for-each select="marc:subfield[@code='q']">
+                                <part>
+                                        <xsl:call-template name="parsePart"/>
+                                </part>
+                        </xsl:for-each>
+                </xsl:if>
+        </xsl:template>
+        <xsl:template name="relatedPartNumName">
+                <xsl:variable name="partNumber">
+                        <xsl:call-template name="specialSubfieldSelect">
+                                <xsl:with-param name="axis">g</xsl:with-param>
+                                <xsl:with-param name="anyCodes">g</xsl:with-param>
+                                <xsl:with-param name="afterCodes">pst</xsl:with-param>
+                        </xsl:call-template>
+                </xsl:variable>
+                <xsl:variable name="partName">
+                        <xsl:call-template name="specialSubfieldSelect">
+                                <xsl:with-param name="axis">p</xsl:with-param>
+                                <xsl:with-param name="anyCodes">p</xsl:with-param>
+                                <xsl:with-param name="afterCodes">fgkdlmor</xsl:with-param>
+                        </xsl:call-template>
+                </xsl:variable>
+                <xsl:if test="string-length(normalize-space($partNumber))">
+                        <partNumber>
+                                <xsl:value-of select="$partNumber"/>
+                        </partNumber>
+                </xsl:if>
+                <xsl:if test="string-length(normalize-space($partName))">
+                        <partName>
+                                <xsl:value-of select="$partName"/>
+                        </partName>
+                </xsl:if>
+        </xsl:template>
+        <xsl:template name="relatedName">
+                <xsl:for-each select="marc:subfield[@code='a']">
+                        <name>
+                                <namePart>
+                                        <xsl:value-of select="."/>
+                                </namePart>
+                        </name>
+                </xsl:for-each>
+        </xsl:template>
+        <xsl:template name="relatedForm">
+                <xsl:for-each select="marc:subfield[@code='h']">
+                        <physicalDescription>
+                                <form>
+                                        <xsl:value-of select="."/>
+                                </form>
+                        </physicalDescription>
+                </xsl:for-each>
+        </xsl:template>
+        <xsl:template name="relatedExtent">
+                <xsl:for-each select="marc:subfield[@code='h']">
+                        <physicalDescription>
+                                <extent>
+                                        <xsl:value-of select="."/>
+                                </extent>
+                        </physicalDescription>
+                </xsl:for-each>
+        </xsl:template>
+        <xsl:template name="relatedNote">
+                <xsl:for-each select="marc:subfield[@code='n']">
+                        <note>
+                                <xsl:value-of select="."/>
+                        </note>
+                </xsl:for-each>
+        </xsl:template>
+        <xsl:template name="relatedSubject">
+                <xsl:for-each select="marc:subfield[@code='j']">
+                        <subject>
+                                <temporal encoding="iso8601">
+                                        <xsl:call-template name="chopPunctuation">
+                                                <xsl:with-param name="chopString" select="."/>
+                                        </xsl:call-template>
+                                </temporal>
+                        </subject>
+                </xsl:for-each>
+        </xsl:template>
+        <xsl:template name="relatedIdentifierISSN">
+                <xsl:for-each select="marc:subfield[@code='x']">
+                        <identifier type="issn">
+                                <xsl:value-of select="."/>
+                        </identifier>
+                </xsl:for-each>
+        </xsl:template>
+        <xsl:template name="relatedIdentifierLocal">
+                <xsl:for-each select="marc:subfield[@code='w']">
+                        <identifier type="local">
+                                <xsl:value-of select="."/>
+                        </identifier>
+                </xsl:for-each>
+        </xsl:template>
+        <xsl:template name="relatedIdentifier">
+                <xsl:for-each select="marc:subfield[@code='o']">
+                        <identifier>
+                                <xsl:value-of select="."/>
+                        </identifier>
+                </xsl:for-each>
+        </xsl:template>
+        <xsl:template name="relatedItem76X-78X">
+                <xsl:call-template name="displayLabel"/>
+                <xsl:call-template name="relatedTitle76X-78X"/>
+                <xsl:call-template name="relatedName"/>
+                <xsl:call-template name="relatedOriginInfo"/>
+                <xsl:call-template name="relatedLanguage"/>
+                <xsl:call-template name="relatedExtent"/>
+                <xsl:call-template name="relatedNote"/>
+                <xsl:call-template name="relatedSubject"/>
+                <xsl:call-template name="relatedIdentifier"/>
+                <xsl:call-template name="relatedIdentifierISSN"/>
+                <xsl:call-template name="relatedIdentifierLocal"/>
+                <xsl:call-template name="relatedPart"/>
+        </xsl:template>
+        <xsl:template name="subjectGeographicZ">
+                <geographic>
+                        <xsl:call-template name="chopPunctuation">
+                                <xsl:with-param name="chopString" select="."/>
+                        </xsl:call-template>
+                </geographic>
+        </xsl:template>
+        <xsl:template name="subjectTemporalY">
+                <temporal>
+                        <xsl:call-template name="chopPunctuation">
+                                <xsl:with-param name="chopString" select="."/>
+                        </xsl:call-template>
+                </temporal>
+        </xsl:template>
+        <xsl:template name="subjectTopic">
+                <topic>
+                        <xsl:call-template name="chopPunctuation">
+                                <xsl:with-param name="chopString" select="."/>
+                        </xsl:call-template>
+                </topic>
+        </xsl:template>
+        <!-- 3.2 change tmee 6xx $v genre -->
+        <xsl:template name="subjectGenre">
+                <genre>
+                        <xsl:call-template name="chopPunctuation">
+                                <xsl:with-param name="chopString" select="."/>
+                        </xsl:call-template>
+                </genre>
+        </xsl:template>
+
+        <xsl:template name="nameABCDN">
+                <xsl:for-each select="marc:subfield[@code='a']">
+                        <namePart>
+                                <xsl:call-template name="chopPunctuation">
+                                        <xsl:with-param name="chopString" select="."/>
+                                </xsl:call-template>
+                        </namePart>
+                </xsl:for-each>
+                <xsl:for-each select="marc:subfield[@code='b']">
+                        <namePart>
+                                <xsl:value-of select="."/>
+                        </namePart>
+                </xsl:for-each>
+                <xsl:if
+                        test="marc:subfield[@code='c'] or marc:subfield[@code='d'] or marc:subfield[@code='n']">
+                        <namePart>
+                                <xsl:call-template name="subfieldSelect">
+                                        <xsl:with-param name="codes">cdn</xsl:with-param>
+                                </xsl:call-template>
+                        </namePart>
+                </xsl:if>
+        </xsl:template>
+        <xsl:template name="nameABCDQ">
+                <namePart>
+                        <xsl:call-template name="chopPunctuation">
+                                <xsl:with-param name="chopString">
+                                        <xsl:call-template name="subfieldSelect">
+                                                <xsl:with-param name="codes">aq</xsl:with-param>
+                                        </xsl:call-template>
+                                </xsl:with-param>
+                                <xsl:with-param name="punctuation">
+                                        <xsl:text>:,;/ </xsl:text>
+                                </xsl:with-param>
+                        </xsl:call-template>
+                </namePart>
+                <xsl:call-template name="termsOfAddress"/>
+                <xsl:call-template name="nameDate"/>
+        </xsl:template>
+        <xsl:template name="nameACDEQ">
+                <namePart>
+                        <xsl:call-template name="subfieldSelect">
+                                <xsl:with-param name="codes">acdeq</xsl:with-param>
+                        </xsl:call-template>
+                </namePart>
+        </xsl:template>
+        <xsl:template name="constituentOrRelatedType">
+                <xsl:if test="@ind2=2">
+                        <xsl:attribute name="type">constituent</xsl:attribute>
+                </xsl:if>
+        </xsl:template>
+        <xsl:template name="relatedTitle">
+                <xsl:for-each select="marc:subfield[@code='t']">
+                        <titleInfo>
+                                <title>
+                                        <xsl:call-template name="chopPunctuation">
+                                                <xsl:with-param name="chopString">
+                                                        <xsl:value-of select="."/>
+                                                </xsl:with-param>
+                                        </xsl:call-template>
+                                </title>
+                        </titleInfo>
+                </xsl:for-each>
+        </xsl:template>
+        <xsl:template name="relatedTitle76X-78X">
+                <xsl:for-each select="marc:subfield[@code='t']">
+                        <titleInfo>
+                                <title>
+                                        <xsl:call-template name="chopPunctuation">
+                                                <xsl:with-param name="chopString">
+                                                        <xsl:value-of select="."/>
+                                                </xsl:with-param>
+                                        </xsl:call-template>
+                                </title>
+                                <xsl:if test="marc:datafield[@tag!=773]and marc:subfield[@code='g']">
+                                        <xsl:call-template name="relatedPartNumName"/>
+                                </xsl:if>
+                        </titleInfo>
+                </xsl:for-each>
+                <xsl:for-each select="marc:subfield[@code='p']">
+                        <titleInfo type="abbreviated">
+                                <title>
+                                        <xsl:call-template name="chopPunctuation">
+                                                <xsl:with-param name="chopString">
+                                                        <xsl:value-of select="."/>
+                                                </xsl:with-param>
+                                        </xsl:call-template>
+                                </title>
+                                <xsl:if test="marc:datafield[@tag!=773]and marc:subfield[@code='g']">
+                                        <xsl:call-template name="relatedPartNumName"/>
+                                </xsl:if>
+                        </titleInfo>
+                </xsl:for-each>
+                <xsl:for-each select="marc:subfield[@code='s']">
+                        <titleInfo type="uniform">
+                                <title>
+                                        <xsl:call-template name="chopPunctuation">
+                                                <xsl:with-param name="chopString">
+                                                        <xsl:value-of select="."/>
+                                                </xsl:with-param>
+                                        </xsl:call-template>
+                                </title>
+                                <xsl:if test="marc:datafield[@tag!=773]and marc:subfield[@code='g']">
+                                        <xsl:call-template name="relatedPartNumName"/>
+                                </xsl:if>
+                        </titleInfo>
+                </xsl:for-each>
+        </xsl:template>
+        <xsl:template name="relatedOriginInfo">
+                <xsl:if test="marc:subfield[@code='b' or @code='d'] or marc:subfield[@code='f']">
+                        <originInfo>
+                                <xsl:if test="@tag=775">
+                                        <xsl:for-each select="marc:subfield[@code='f']">
+                                                <place>
+                                                        <placeTerm>
+                                                                <xsl:attribute name="type">code</xsl:attribute>
+                                                                <xsl:attribute name="authority">marcgac</xsl:attribute>
+                                                                <xsl:value-of select="."/>
+                                                        </placeTerm>
+                                                </place>
+                                        </xsl:for-each>
+                                </xsl:if>
+                                <xsl:for-each select="marc:subfield[@code='d']">
+                                        <publisher>
+                                                <xsl:value-of select="."/>
+                                        </publisher>
+                                </xsl:for-each>
+                                <xsl:for-each select="marc:subfield[@code='b']">
+                                        <edition>
+                                                <xsl:value-of select="."/>
+                                        </edition>
+                                </xsl:for-each>
+                        </originInfo>
+                </xsl:if>
+        </xsl:template>
+        <xsl:template name="relatedLanguage">
+                <xsl:for-each select="marc:subfield[@code='e']">
+                        <xsl:call-template name="getLanguage">
+                                <xsl:with-param name="langString">
+                                        <xsl:value-of select="."/>
+                                </xsl:with-param>
+                        </xsl:call-template>
+                </xsl:for-each>
+        </xsl:template>
+        <xsl:template name="nameDate">
+                <xsl:for-each select="marc:subfield[@code='d']">
+                        <namePart type="date">
+                                <xsl:call-template name="chopPunctuation">
+                                        <xsl:with-param name="chopString" select="."/>
+                                </xsl:call-template>
+                        </namePart>
+                </xsl:for-each>
+        </xsl:template>
+        <xsl:template name="subjectAuthority">
+                <xsl:if test="@ind2!=4">
+                        <xsl:if test="@ind2!=' '">
+                                <xsl:if test="@ind2!=8">
+                                        <xsl:if test="@ind2!=9">
+                                                <xsl:attribute name="authority">
+                                                        <xsl:choose>
+                                                                <xsl:when test="@ind2=0">lcsh</xsl:when>
+                                                                <xsl:when test="@ind2=1">lcshac</xsl:when>
+                                                                <xsl:when test="@ind2=2">mesh</xsl:when>
+                                                                <!-- 1/04 fix -->
+                                                                <xsl:when test="@ind2=3">nal</xsl:when>
+                                                                <xsl:when test="@ind2=5">csh</xsl:when>
+                                                                <xsl:when test="@ind2=6">rvm</xsl:when>
+                                                                <xsl:when test="@ind2=7">
+                                                                        <xsl:value-of select="marc:subfield[@code='2']"/>
+                                                                </xsl:when>
+                                                        </xsl:choose>
+                                                </xsl:attribute>
+                                        </xsl:if>
+                                </xsl:if>
+                        </xsl:if>
+                </xsl:if>
+        </xsl:template>
+        <xsl:template name="subjectAnyOrder">
+                <xsl:for-each select="marc:subfield[@code='v' or @code='x' or @code='y' or @code='z']">
+                        <xsl:choose>
+                                <xsl:when test="@code='v'">
+                                        <xsl:call-template name="subjectGenre"/>
+                                </xsl:when>
+                                <xsl:when test="@code='x'">
+                                        <xsl:call-template name="subjectTopic"/>
+                                </xsl:when>
+                                <xsl:when test="@code='y'">
+                                        <xsl:call-template name="subjectTemporalY"/>
+                                </xsl:when>
+                                <xsl:when test="@code='z'">
+                                        <xsl:call-template name="subjectGeographicZ"/>
+                                </xsl:when>
+                        </xsl:choose>
+                </xsl:for-each>
+        </xsl:template>
+        <xsl:template name="specialSubfieldSelect">
+                <xsl:param name="anyCodes"/>
+                <xsl:param name="axis"/>
+                <xsl:param name="beforeCodes"/>
+                <xsl:param name="afterCodes"/>
+                <xsl:variable name="str">
+                        <xsl:for-each select="marc:subfield">
+                                <xsl:if
+                                        test="contains($anyCodes, @code)      or (contains($beforeCodes, at code) and following-sibling::marc:subfield[@code=$axis])      or (contains($afterCodes, at code) and preceding-sibling::marc:subfield[@code=$axis])">
+                                        <xsl:value-of select="text()"/>
+                                        <xsl:text> </xsl:text>
+                                </xsl:if>
+                        </xsl:for-each>
+                </xsl:variable>
+                <xsl:value-of select="substring($str,1,string-length($str)-1)"/>
+        </xsl:template>
+
+        <!-- 3.2 change tmee 6xx $v genre -->
+        <xsl:template match="marc:datafield[@tag=600]">
+                <subject>
+                        <xsl:call-template name="subjectAuthority"/>
+                        <name type="personal">
+                                <xsl:call-template name="termsOfAddress"/>
+                                <namePart>
+                                        <xsl:call-template name="chopPunctuation">
+                                                <xsl:with-param name="chopString">
+                                                        <xsl:call-template name="subfieldSelect">
+                                                                <xsl:with-param name="codes">aq</xsl:with-param>
+                                                        </xsl:call-template>
+                                                </xsl:with-param>
+                                        </xsl:call-template>
+                                </namePart>
+                                <xsl:call-template name="nameDate"/>
+                                <xsl:call-template name="affiliation"/>
+                                <xsl:call-template name="role"/>
+                        </name>
+                        <xsl:call-template name="subjectAnyOrder"/>
+                </subject>
+        </xsl:template>
+        <xsl:template match="marc:datafield[@tag=610]">
+                <subject>
+                        <xsl:call-template name="subjectAuthority"/>
+                        <name type="corporate">
+                                <xsl:for-each select="marc:subfield[@code='a']">
+                                        <namePart>
+                                                <xsl:value-of select="."/>
+                                        </namePart>
+                                </xsl:for-each>
+                                <xsl:for-each select="marc:subfield[@code='b']">
+                                        <namePart>
+                                                <xsl:value-of select="."/>
+                                        </namePart>
+                                </xsl:for-each>
+                                <xsl:if test="marc:subfield[@code='c' or @code='d' or @code='n' or @code='p']">
+                                        <namePart>
+                                                <xsl:call-template name="subfieldSelect">
+                                                        <xsl:with-param name="codes">cdnp</xsl:with-param>
+                                                </xsl:call-template>
+                                        </namePart>
+                                </xsl:if>
+                                <xsl:call-template name="role"/>
+                        </name>
+                        <xsl:call-template name="subjectAnyOrder"/>
+                </subject>
+        </xsl:template>
+        <xsl:template match="marc:datafield[@tag=611]">
+                <subject>
+                        <xsl:call-template name="subjectAuthority"/>
+                        <name type="conference">
+                                <namePart>
+                                        <xsl:call-template name="subfieldSelect">
+                                                <xsl:with-param name="codes">abcdeqnp</xsl:with-param>
+                                        </xsl:call-template>
+                                </namePart>
+                                <xsl:for-each select="marc:subfield[@code='4']">
+                                        <role>
+                                                <roleTerm authority="marcrelator" type="code">
+                                                        <xsl:value-of select="."/>
+                                                </roleTerm>
+                                        </role>
+                                </xsl:for-each>
+                        </name>
+                        <xsl:call-template name="subjectAnyOrder"/>
+                </subject>
+        </xsl:template>
+        <xsl:template match="marc:datafield[@tag=630]">
+                <subject>
+                        <xsl:call-template name="subjectAuthority"/>
+                        <titleInfo>
+                                <title>
+                                        <xsl:call-template name="chopPunctuation">
+                                                <xsl:with-param name="chopString">
+                                                        <xsl:call-template name="subfieldSelect">
+                                                                <xsl:with-param name="codes">adfhklor</xsl:with-param>
+                                                        </xsl:call-template>
+                                                </xsl:with-param>
+                                        </xsl:call-template>
+                                </title>
+                                <xsl:call-template name="part"/>
+                        </titleInfo>
+                        <xsl:call-template name="subjectAnyOrder"/>
+                </subject>
+        </xsl:template>
+        <!-- 1.27 648 tmee-->
+        <xsl:template match="marc:datafield[@tag=648]">
+                <subject>
+                        <xsl:if test="marc:subfield[@code=2]">
+                                <xsl:attribute name="authority">
+                                        <xsl:value-of select="marc:subfield[@code=2]"/>
+                                </xsl:attribute>
+                        </xsl:if>
+                        <xsl:call-template name="uri"/>
+
+                        <xsl:call-template name="subjectAuthority"/>
+                        <temporal>
+                                <xsl:call-template name="chopPunctuation">
+                                        <xsl:with-param name="chopString">
+                                                <xsl:call-template name="subfieldSelect">
+                                                        <xsl:with-param name="codes">abcd</xsl:with-param>
+                                                </xsl:call-template>
+                                        </xsl:with-param>
+                                </xsl:call-template>
+                        </temporal>
+                        <xsl:call-template name="subjectAnyOrder"/>
+
+                </subject>
+        </xsl:template>
+        <xsl:template match="marc:datafield[@tag=650]">
+                <subject>
+                        <xsl:call-template name="subjectAuthority"/>
+                        <topic>
+                                <xsl:call-template name="chopPunctuation">
+                                        <xsl:with-param name="chopString">
+                                                <xsl:call-template name="subfieldSelect">
+                                                        <xsl:with-param name="codes">abcd</xsl:with-param>
+                                                </xsl:call-template>
+                                        </xsl:with-param>
+                                </xsl:call-template>
+                        </topic>
+                        <xsl:call-template name="subjectAnyOrder"/>
+                </subject>
+        </xsl:template>
+        <xsl:template match="marc:datafield[@tag=651]">
+                <subject>
+                        <xsl:call-template name="subjectAuthority"/>
+                        <xsl:for-each select="marc:subfield[@code='a']">
+                                <geographic>
+                                        <xsl:call-template name="chopPunctuation">
+                                                <xsl:with-param name="chopString" select="."/>
+                                        </xsl:call-template>
+                                </geographic>
+                        </xsl:for-each>
+                        <xsl:call-template name="subjectAnyOrder"/>
+                </subject>
+        </xsl:template>
+        <xsl:template match="marc:datafield[@tag=653]">
+                <subject>
+                        <xsl:for-each select="marc:subfield[@code='a']">
+                                <topic>
+                                        <xsl:value-of select="."/>
+                                </topic>
+                        </xsl:for-each>
+                </subject>
+        </xsl:template>
+        <xsl:template match="marc:datafield[@tag=656]">
+                <subject>
+                        <xsl:if test="marc:subfield[@code=2]">
+                                <xsl:attribute name="authority">
+                                        <xsl:value-of select="marc:subfield[@code=2]"/>
+                                </xsl:attribute>
+                        </xsl:if>
+                        <occupation>
+                                <xsl:call-template name="chopPunctuation">
+                                        <xsl:with-param name="chopString">
+                                                <xsl:value-of select="marc:subfield[@code='a']"/>
+                                        </xsl:with-param>
+                                </xsl:call-template>
+                        </occupation>
+                </subject>
+        </xsl:template>
+        <xsl:template name="termsOfAddress">
+                <xsl:if test="marc:subfield[@code='b' or @code='c']">
+                        <namePart type="termsOfAddress">
+                                <xsl:call-template name="chopPunctuation">
+                                        <xsl:with-param name="chopString">
+                                                <xsl:call-template name="subfieldSelect">
+                                                        <xsl:with-param name="codes">bc</xsl:with-param>
+                                                </xsl:call-template>
+                                        </xsl:with-param>
+                                </xsl:call-template>
+                        </namePart>
+                </xsl:if>
+        </xsl:template>
+        <xsl:template name="displayLabel">
+                <xsl:if test="marc:subfield[@code='i']">
+                        <xsl:attribute name="displayLabel">
+                                <xsl:value-of select="marc:subfield[@code='i']"/>
+                        </xsl:attribute>
+                </xsl:if>
+                <xsl:if test="marc:subfield[@code='3']">
+                        <xsl:attribute name="displayLabel">
+                                <xsl:value-of select="marc:subfield[@code='3']"/>
+                        </xsl:attribute>
+                </xsl:if>
+        </xsl:template>
+        <xsl:template name="isInvalid">
+                <xsl:param name="type"/>
+                <xsl:if
+                        test="marc:subfield[@code='z'] or marc:subfield[@code='y']  or marc:subfield[@code='m']">
+                        <identifier>
+                                <xsl:attribute name="type">
+                                        <xsl:value-of select="$type"/>
+                                </xsl:attribute>
+                                <xsl:attribute name="invalid">
+                                        <xsl:text>yes</xsl:text>
+                                </xsl:attribute>
+                                <xsl:if test="marc:subfield[@code='z']">
+                                        <xsl:value-of select="marc:subfield[@code='z']"/>
+                                </xsl:if>
+                                <xsl:if test="marc:subfield[@code='y']">
+                                        <xsl:value-of select="marc:subfield[@code='y']"/>
+                                </xsl:if>
+                                <xsl:if test="marc:subfield[@code='m']">
+                                        <xsl:value-of select="marc:subfield[@code='m']"/>
+                                </xsl:if>
+                        </identifier>
+                </xsl:if>
+        </xsl:template>
+        <xsl:template name="subtitle">
+                <xsl:if test="marc:subfield[@code='b']">
+                        <subTitle>
+                                <xsl:call-template name="chopPunctuation">
+                                        <xsl:with-param name="chopString">
+                                                <xsl:value-of select="marc:subfield[@code='b']"/>
+                                                <!--<xsl:call-template name="subfieldSelect">
+                                                        <xsl:with-param name="codes">b</xsl:with-param>
+                                                </xsl:call-template>-->
+                                        </xsl:with-param>
+                                </xsl:call-template>
+                        </subTitle>
+                </xsl:if>
+        </xsl:template>
+        <xsl:template name="script">
+                <xsl:param name="scriptCode"/>
+                <xsl:attribute name="script">
+                        <xsl:choose>
+                                <xsl:when test="$scriptCode='(3'">Arabic</xsl:when>
+                                <xsl:when test="$scriptCode='(B'">Latin</xsl:when>
+                                <xsl:when test="$scriptCode='$1'">Chinese, Japanese, Korean</xsl:when>
+                                <xsl:when test="$scriptCode='(N'">Cyrillic</xsl:when>
+                                <xsl:when test="$scriptCode='(2'">Hebrew</xsl:when>
+                                <xsl:when test="$scriptCode='(S'">Greek</xsl:when>
+                        </xsl:choose>
+                </xsl:attribute>
+        </xsl:template>
+        <xsl:template name="parsePart">
+                <!-- assumes 773$q= 1:2:3<4
+                     with up to 3 levels and one optional start page
+                -->
+                <xsl:variable name="level1">
+                        <xsl:choose>
+                                <xsl:when test="contains(text(),':')">
+                                        <!-- 1:2 -->
+                                        <xsl:value-of select="substring-before(text(),':')"/>
+                                </xsl:when>
+                                <xsl:when test="not(contains(text(),':'))">
+                                        <!-- 1 or 1<3 -->
+                                        <xsl:if test="contains(text(),'<')">
+                                                <!-- 1<3 -->
+                                                <xsl:value-of select="substring-before(text(),'<')"/>
+                                        </xsl:if>
+                                        <xsl:if test="not(contains(text(),'<'))">
+                                                <!-- 1 -->
+                                                <xsl:value-of select="text()"/>
+                                        </xsl:if>
+                                </xsl:when>
+                        </xsl:choose>
+                </xsl:variable>
+                <xsl:variable name="sici2">
+                        <xsl:choose>
+                                <xsl:when test="starts-with(substring-after(text(),$level1),':')">
+                                        <xsl:value-of select="substring(substring-after(text(),$level1),2)"/>
+                                </xsl:when>
+                                <xsl:otherwise>
+                                        <xsl:value-of select="substring-after(text(),$level1)"/>
+                                </xsl:otherwise>
+                        </xsl:choose>
+                </xsl:variable>
+                <xsl:variable name="level2">
+                        <xsl:choose>
+                                <xsl:when test="contains($sici2,':')">
+                                        <!--  2:3<4  -->
+                                        <xsl:value-of select="substring-before($sici2,':')"/>
+                                </xsl:when>
+                                <xsl:when test="contains($sici2,'<')">
+                                        <!-- 1: 2<4 -->
+                                        <xsl:value-of select="substring-before($sici2,'<')"/>
+                                </xsl:when>
+                                <xsl:otherwise>
+                                        <xsl:value-of select="$sici2"/>
+                                        <!-- 1:2 -->
+                                </xsl:otherwise>
+                        </xsl:choose>
+                </xsl:variable>
+                <xsl:variable name="sici3">
+                        <xsl:choose>
+                                <xsl:when test="starts-with(substring-after($sici2,$level2),':')">
+                                        <xsl:value-of select="substring(substring-after($sici2,$level2),2)"/>
+                                </xsl:when>
+                                <xsl:otherwise>
+                                        <xsl:value-of select="substring-after($sici2,$level2)"/>
+                                </xsl:otherwise>
+                        </xsl:choose>
+                </xsl:variable>
+                <xsl:variable name="level3">
+                        <xsl:choose>
+                                <xsl:when test="contains($sici3,'<')">
+                                        <!-- 2<4 -->
+                                        <xsl:value-of select="substring-before($sici3,'<')"/>
+                                </xsl:when>
+                                <xsl:otherwise>
+                                        <xsl:value-of select="$sici3"/>
+                                        <!-- 3 -->
+                                </xsl:otherwise>
+                        </xsl:choose>
+                </xsl:variable>
+                <xsl:variable name="page">
+                        <xsl:if test="contains(text(),'<')">
+                                <xsl:value-of select="substring-after(text(),'<')"/>
+                        </xsl:if>
+                </xsl:variable>
+                <xsl:if test="$level1">
+                        <detail level="1">
+                                <number>
+                                        <xsl:value-of select="$level1"/>
+                                </number>
+                        </detail>
+                </xsl:if>
+                <xsl:if test="$level2">
+                        <detail level="2">
+                                <number>
+                                        <xsl:value-of select="$level2"/>
+                                </number>
+                        </detail>
+                </xsl:if>
+                <xsl:if test="$level3">
+                        <detail level="3">
+                                <number>
+                                        <xsl:value-of select="$level3"/>
+                                </number>
+                        </detail>
+                </xsl:if>
+                <xsl:if test="$page">
+                        <extent unit="page">
+                                <start>
+                                        <xsl:value-of select="$page"/>
+                                </start>
+                        </extent>
+                </xsl:if>
+        </xsl:template>
+        <xsl:template name="getLanguage">
+                <xsl:param name="langString"/>
+                <xsl:param name="controlField008-35-37"/>
+                <xsl:variable name="length" select="string-length($langString)"/>
+                <xsl:choose>
+                        <xsl:when test="$length=0"/>
+                        <xsl:when test="$controlField008-35-37=substring($langString,1,3)">
+                                <xsl:call-template name="getLanguage">
+                                        <xsl:with-param name="langString" select="substring($langString,4,$length)"/>
+                                        <xsl:with-param name="controlField008-35-37" select="$controlField008-35-37"/>
+                                </xsl:call-template>
+                        </xsl:when>
+                        <xsl:otherwise>
+                                <language>
+                                        <languageTerm authority="iso639-2b" type="code">
+                                                <xsl:value-of select="substring($langString,1,3)"/>
+                                        </languageTerm>
+                                </language>
+                                <xsl:call-template name="getLanguage">
+                                        <xsl:with-param name="langString" select="substring($langString,4,$length)"/>
+                                        <xsl:with-param name="controlField008-35-37" select="$controlField008-35-37"/>
+                                </xsl:call-template>
+                        </xsl:otherwise>
+                </xsl:choose>
+        </xsl:template>
+        <xsl:template name="isoLanguage">
+                <xsl:param name="currentLanguage"/>
+                <xsl:param name="usedLanguages"/>
+                <xsl:param name="remainingLanguages"/>
+                <xsl:choose>
+                        <xsl:when test="string-length($currentLanguage)=0"/>
+                        <xsl:when test="not(contains($usedLanguages, $currentLanguage))">
+                                <language>
+                                        <xsl:if test="@code!='a'">
+                                                <xsl:attribute name="objectPart">
+                                                        <xsl:choose>
+                                                                <xsl:when test="@code='b'">summary or subtitle</xsl:when>
+                                                                <xsl:when test="@code='d'">sung or spoken text</xsl:when>
+                                                                <xsl:when test="@code='e'">libretto</xsl:when>
+                                                                <xsl:when test="@code='f'">table of contents</xsl:when>
+                                                                <xsl:when test="@code='g'">accompanying material</xsl:when>
+                                                                <xsl:when test="@code='h'">translation</xsl:when>
+                                                        </xsl:choose>
+                                                </xsl:attribute>
+                                        </xsl:if>
+                                        <languageTerm authority="iso639-2b" type="code">
+                                                <xsl:value-of select="$currentLanguage"/>
+                                        </languageTerm>
+                                </language>
+                                <xsl:call-template name="isoLanguage">
+                                        <xsl:with-param name="currentLanguage">
+                                                <xsl:value-of select="substring($remainingLanguages,1,3)"/>
+                                        </xsl:with-param>
+                                        <xsl:with-param name="usedLanguages">
+                                                <xsl:value-of select="concat($usedLanguages,$currentLanguage)"/>
+                                        </xsl:with-param>
+                                        <xsl:with-param name="remainingLanguages">
+                                                <xsl:value-of
+                                                        select="substring($remainingLanguages,4,string-length($remainingLanguages))"
+                                                />
+                                        </xsl:with-param>
+                                </xsl:call-template>
+                        </xsl:when>
+                        <xsl:otherwise>
+                                <xsl:call-template name="isoLanguage">
+                                        <xsl:with-param name="currentLanguage">
+                                                <xsl:value-of select="substring($remainingLanguages,1,3)"/>
+                                        </xsl:with-param>
+                                        <xsl:with-param name="usedLanguages">
+                                                <xsl:value-of select="concat($usedLanguages,$currentLanguage)"/>
+                                        </xsl:with-param>
+                                        <xsl:with-param name="remainingLanguages">
+                                                <xsl:value-of
+                                                        select="substring($remainingLanguages,4,string-length($remainingLanguages))"
+                                                />
+                                        </xsl:with-param>
+                                </xsl:call-template>
+                        </xsl:otherwise>
+                </xsl:choose>
+        </xsl:template>
+        <xsl:template name="chopBrackets">
+                <xsl:param name="chopString"/>
+                <xsl:variable name="string">
+                        <xsl:call-template name="chopPunctuation">
+                                <xsl:with-param name="chopString" select="$chopString"/>
+                        </xsl:call-template>
+                </xsl:variable>
+                <xsl:if test="substring($string, 1,1)='['">
+                        <xsl:value-of select="substring($string,2, string-length($string)-2)"/>
+                </xsl:if>
+                <xsl:if test="substring($string, 1,1)!='['">
+                        <xsl:value-of select="$string"/>
+                </xsl:if>
+        </xsl:template>
+        <xsl:template name="rfcLanguages">
+                <xsl:param name="nodeNum"/>
+                <xsl:param name="usedLanguages"/>
+                <xsl:param name="controlField008-35-37"/>
+                <xsl:variable name="currentLanguage" select="."/>
+                <xsl:choose>
+                        <xsl:when test="not($currentLanguage)"/>
+                        <xsl:when
+                                test="$currentLanguage!=$controlField008-35-37 and $currentLanguage!='rfc3066'">
+                                <xsl:if test="not(contains($usedLanguages,$currentLanguage))">
+                                        <language>
+                                                <xsl:if test="@code!='a'">
+                                                        <xsl:attribute name="objectPart">
+                                                                <xsl:choose>
+                                                                        <xsl:when test="@code='b'">summary or subtitle</xsl:when>
+                                                                        <xsl:when test="@code='d'">sung or spoken text</xsl:when>
+                                                                        <xsl:when test="@code='e'">libretto</xsl:when>
+                                                                        <xsl:when test="@code='f'">table of contents</xsl:when>
+                                                                        <xsl:when test="@code='g'">accompanying material</xsl:when>
+                                                                        <xsl:when test="@code='h'">translation</xsl:when>
+                                                                </xsl:choose>
+                                                        </xsl:attribute>
+                                                </xsl:if>
+                                                <languageTerm authority="rfc3066" type="code">
+                                                        <xsl:value-of select="$currentLanguage"/>
+                                                </languageTerm>
+                                        </language>
+                                </xsl:if>
+                        </xsl:when>
+                        <xsl:otherwise> </xsl:otherwise>
+                </xsl:choose>
+        </xsl:template>
+
+    <xsl:template name="datafield">
+                <xsl:param name="tag"/>
+                <xsl:param name="ind1">
+                        <xsl:text> </xsl:text>
+                </xsl:param>
+                <xsl:param name="ind2">
+                        <xsl:text> </xsl:text>
+                </xsl:param>
+                <xsl:param name="subfields"/>
+                <xsl:element name="marc:datafield">
+                        <xsl:attribute name="tag">
+                                <xsl:value-of select="$tag"/>
+                        </xsl:attribute>
+                        <xsl:attribute name="ind1">
+                                <xsl:value-of select="$ind1"/>
+                        </xsl:attribute>
+                        <xsl:attribute name="ind2">
+                                <xsl:value-of select="$ind2"/>
+                        </xsl:attribute>
+                        <xsl:copy-of select="$subfields"/>
+                </xsl:element>
+        </xsl:template>
+
+        <xsl:template name="subfieldSelect">
+                <xsl:param name="codes">abcdefghijklmnopqrstuvwxyz</xsl:param>
+                <xsl:param name="delimeter">
+                        <xsl:text> </xsl:text>
+                </xsl:param>
+                <xsl:variable name="str">
+                        <xsl:for-each select="marc:subfield">
+                                <xsl:if test="contains($codes, @code)">
+                                        <xsl:value-of select="text()"/>
+                                        <xsl:value-of select="$delimeter"/>
+                                </xsl:if>
+                        </xsl:for-each>
+                </xsl:variable>
+                <xsl:value-of select="substring($str,1,string-length($str)-string-length($delimeter))"/>
+        </xsl:template>
+
+        <xsl:template name="buildSpaces">
+                <xsl:param name="spaces"/>
+                <xsl:param name="char">
+                        <xsl:text> </xsl:text>
+                </xsl:param>
+                <xsl:if test="$spaces>0">
+                        <xsl:value-of select="$char"/>
+                        <xsl:call-template name="buildSpaces">
+                                <xsl:with-param name="spaces" select="$spaces - 1"/>
+                                <xsl:with-param name="char" select="$char"/>
+                        </xsl:call-template>
+                </xsl:if>
+        </xsl:template>
+
+        <xsl:template name="chopPunctuation">
+                <xsl:param name="chopString"/>
+                <xsl:param name="punctuation">
+                        <xsl:text>.:,;/ </xsl:text>
+                </xsl:param>
+                <xsl:variable name="length" select="string-length($chopString)"/>
+                <xsl:choose>
+                        <xsl:when test="$length=0"/>
+                        <xsl:when test="contains($punctuation, substring($chopString,$length,1))">
+                                <xsl:call-template name="chopPunctuation">
+                                        <xsl:with-param name="chopString" select="substring($chopString,1,$length - 1)"/>
+                                        <xsl:with-param name="punctuation" select="$punctuation"/>
+                                </xsl:call-template>
+                        </xsl:when>
+                        <xsl:when test="not($chopString)"/>
+                        <xsl:otherwise>
+                                <xsl:value-of select="$chopString"/>
+                        </xsl:otherwise>
+                </xsl:choose>
+        </xsl:template>
+
+        <xsl:template name="chopPunctuationFront">
+                <xsl:param name="chopString"/>
+                <xsl:variable name="length" select="string-length($chopString)"/>
+                <xsl:choose>
+                        <xsl:when test="$length=0"/>
+                        <xsl:when test="contains('.:,;/[ ', substring($chopString,1,1))">
+                                <xsl:call-template name="chopPunctuationFront">
+                                        <xsl:with-param name="chopString" select="substring($chopString,2,$length - 1)"
+                                        />
+                                </xsl:call-template>
+                        </xsl:when>
+                        <xsl:when test="not($chopString)"/>
+                        <xsl:otherwise>
+                                <xsl:value-of select="$chopString"/>
+                        </xsl:otherwise>
+                </xsl:choose>
+        </xsl:template>
+
+        <xsl:template name="chopPunctuationBack">
+                <xsl:param name="chopString"/>
+                <xsl:param name="punctuation">
+                        <xsl:text>.:,;/] </xsl:text>
+                </xsl:param>
+                <xsl:variable name="length" select="string-length($chopString)"/>
+                <xsl:choose>
+                        <xsl:when test="$length=0"/>
+                        <xsl:when test="contains($punctuation, substring($chopString,$length,1))">
+                                <xsl:call-template name="chopPunctuation">
+                                        <xsl:with-param name="chopString" select="substring($chopString,1,$length - 1)"/>
+                                        <xsl:with-param name="punctuation" select="$punctuation"/>
+                                </xsl:call-template>
+                        </xsl:when>
+                        <xsl:when test="not($chopString)"/>
+                        <xsl:otherwise>
+                                <xsl:value-of select="$chopString"/>
+                        </xsl:otherwise>
+                </xsl:choose>
+        </xsl:template>
+
+        <!-- nate added 12/14/2007 for lccn.loc.gov: url encode ampersand, etc. -->
+        <xsl:template name="url-encode">
+
+                <xsl:param name="str"/>
+
+                <xsl:if test="$str">
+                        <xsl:variable name="first-char" select="substring($str,1,1)"/>
+                        <xsl:choose>
+                                <xsl:when test="contains($safe,$first-char)">
+                                        <xsl:value-of select="$first-char"/>
+                                </xsl:when>
+                                <xsl:otherwise>
+                                        <xsl:variable name="codepoint">
+                                                <xsl:choose>
+                                                        <xsl:when test="contains($ascii,$first-char)">
+                                                                <xsl:value-of
+                                                                        select="string-length(substring-before($ascii,$first-char)) + 32"
+                                                                />
+                                                        </xsl:when>
+                                                        <xsl:when test="contains($latin1,$first-char)">
+                                                                <xsl:value-of
+                                                                        select="string-length(substring-before($latin1,$first-char)) + 160"/>
+                                                                <!-- was 160 -->
+                                                        </xsl:when>
+                                                        <xsl:otherwise>
+                                                                <xsl:message terminate="no">Warning: string contains a character
+                                                                        that is out of range! Substituting "?".</xsl:message>
+                                                                <xsl:text>63</xsl:text>
+                                                        </xsl:otherwise>
+                                                </xsl:choose>
+                                        </xsl:variable>
+                                        <xsl:variable name="hex-digit1"
+                                                select="substring($hex,floor($codepoint div 16) + 1,1)"/>
+                                        <xsl:variable name="hex-digit2" select="substring($hex,$codepoint mod 16 + 1,1)"/>
+                                        <!-- <xsl:value-of select="concat('%',$hex-digit2)"/> -->
+                                        <xsl:value-of select="concat('%',$hex-digit1,$hex-digit2)"/>
+                                </xsl:otherwise>
+                        </xsl:choose>
+                        <xsl:if test="string-length($str) > 1">
+                                <xsl:call-template name="url-encode">
+                                        <xsl:with-param name="str" select="substring($str,2)"/>
+                                </xsl:call-template>
+                        </xsl:if>
+                </xsl:if>
+        </xsl:template>
+</xsl:stylesheet>$XXXX$ where name = $$mods33$$;
+
+COMMIT;
+
diff --git a/Open-ILS/src/sql/Pg/upgrade/YYYY.data.virtual_index_defs.sql b/Open-ILS/src/sql/Pg/upgrade/YYYY.data.virtual_index_defs.sql
new file mode 100644
index 0000000..65e67ed
--- /dev/null
+++ b/Open-ILS/src/sql/Pg/upgrade/YYYY.data.virtual_index_defs.sql
@@ -0,0 +1,42 @@
+BEGIN;
+
+INSERT INTO config.metabib_field (id, field_class, name, label, browse_field)
+    VALUES (45, 'keyword', 'blob', 'All searchable fields', FALSE);
+
+INSERT INTO config.metabib_field_virtual_map (real, virtual)
+    SELECT  id,
+            45
+      FROM  config.metabib_field
+      WHERE search_field
+            AND id NOT IN (15, 45);
+
+UPDATE config.metabib_field SET xpath=$$//mods32:mods/mods32:subject[not(descendant::mods32:geographicCode)]$$ WHERE id = 16;
+
+COMMIT;
+
+\qecho 
+\qecho Reingesting all records.  This may take a while. 
+\qecho This command can be stopped (control-c) and rerun later if needed: 
+\qecho 
+\qecho DO $FUNC$
+\qecho DECLARE
+\qecho     same_marc BOOL;
+\qecho BEGIN
+\qecho     SELECT INTO same_marc enabled FROM config.internal_flag WHERE name = 'ingest.reingest.force_on_same_marc';
+\qecho     UPDATE config.internal_flag SET enabled = true WHERE name = 'ingest.reingest.force_on_same_marc';
+\qecho     UPDATE biblio.record_entry SET id=id WHERE not deleted AND id > 0;
+\qecho     UPDATE config.internal_flag SET enabled = same_marc WHERE name = 'ingest.reingest.force_on_same_marc';
+\qecho END;
+\qecho $FUNC$;
+
+DO $FUNC$
+DECLARE
+    same_marc BOOL;
+BEGIN
+    SELECT INTO same_marc enabled FROM config.internal_flag WHERE name = 'ingest.reingest.force_on_same_marc';
+    UPDATE config.internal_flag SET enabled = true WHERE name = 'ingest.reingest.force_on_same_marc';
+    UPDATE biblio.record_entry SET id=id WHERE not deleted AND id > 0;
+    UPDATE config.internal_flag SET enabled = same_marc WHERE name = 'ingest.reingest.force_on_same_marc';
+END;
+$FUNC$;
+
diff --git a/Open-ILS/src/support-scripts/test-scripts/query_parser.pl b/Open-ILS/src/support-scripts/test-scripts/query_parser.pl
index 6f835de..ebc0777 100755
--- a/Open-ILS/src/support-scripts/test-scripts/query_parser.pl
+++ b/Open-ILS/src/support-scripts/test-scripts/query_parser.pl
@@ -80,6 +80,11 @@ if (!$noconnect) {
                 'open-ils.cstore.direct.config.metabib_field.search.atomic',
                 { id => { "!=" => undef } }
             )->gather(1),
+        config_metabib_field_virtual_map    =>
+            $cstore->request(
+                'open-ils.cstore.direct.config.metabib_field_virtual_map.search.atomic',
+                { id => { "!=" => undef } }
+            )->gather(1),
         config_metabib_search_alias         =>
             $cstore->request(
                 'open-ils.cstore.direct.config.metabib_search_alias.search.atomic',
@@ -100,10 +105,11 @@ if (!$noconnect) {
 }
 
 $parser->parse;
-
-print "Parsed query tree:\n" . Dumper($parser->parse_tree) unless $quiet;
-
 my $sql = $parser->toSQL;
 $sql =~ s/^\s*$//gm;
+
+print "Parsed query tree:\n" . Dumper($parser) unless $quiet;
+print "Abstract query:\n" . Dumper($parser->parse_tree->to_abstract_query) unless $quiet;
+
 print "SQL:\n$sql\n\n" unless $quiet;
 
diff --git a/Open-ILS/src/templates/conify/global/config/metabib_field.tt2 b/Open-ILS/src/templates/conify/global/config/metabib_field.tt2
index 95fec5a..39dcf26 100644
--- a/Open-ILS/src/templates/conify/global/config/metabib_field.tt2
+++ b/Open-ILS/src/templates/conify/global/config/metabib_field.tt2
@@ -17,7 +17,13 @@
             autoHeight='true'
             editOnEnter='true'>
         <thead>
-            <tr><th field='xpath' width='25%'/></tr>
+            <tr><th field='xpath' width='25%'/>
+                <th field='vdata_suppliers' get='getCmfvm' formatter='formatCmfvmLink'>
+                        [% l('Data Suppliers') %]
+                </th>
+            </tr>
+      </thead>
+
         </thead>
     </table>
 </div>
@@ -25,6 +31,22 @@
 <script type="text/javascript">
     dojo.require('openils.Util');
     dojo.require('openils.widget.AutoGrid');
+
+    function getCmfvm(rowId, item) {
+      if (!item) return '';
+      return this.grid.store.getValue(item, 'id');
+    }
+
+    function formatCmfvmLink(id) {
+      if (id) {
+        return "<a href='" + oilsBasePath +
+          "/conify/global/config/metabib_field_virtual_map/"
+          + id + "'>[% l('Manage') %]</a>";
+        } else {
+          return "";
+      }
+    }
+
     openils.Util.addOnLoad( function() { mbFieldGrid.loadAll(); } );
 </script>
 [% END %]
diff --git a/Open-ILS/src/templates/conify/global/config/metabib_field_virtual_map.tt2 b/Open-ILS/src/templates/conify/global/config/metabib_field_virtual_map.tt2
new file mode 100644
index 0000000..a19e370
--- /dev/null
+++ b/Open-ILS/src/templates/conify/global/config/metabib_field_virtual_map.tt2
@@ -0,0 +1,77 @@
+[% WRAPPER base.tt2 %]
+<h1>[% l('Virtual Field Data Providers') %]</h1> <br/>
+
+<div dojoType="dijit.layout.ContentPane" layoutAlign="client" class='oils-header-panel'>
+    <div>[% l('Virtual Field Data Providers') %]</div>
+    <div>
+        <button dojoType='dijit.form.Button' onClick='cmfvmGrid.showCreateDialog()'>[% l('New Map') %]</button>
+        <button dojoType='dijit.form.Button' onClick='cmfvmGrid.deleteSelected()'>[% l('Delete Selected') %]</button>
+        <button dojoType='dijit.form.Button' onClick='cmfvmGrid.showClonePane()'>[% l('Clone Selected') %]</button>
+    </div>
+</div>
+
+<div dojoType="dijit.layout.ContentPane" layoutAlign="client">
+    <span>[% l('Record Attribute Type: ') %]</span><div id='attr-def-div'></div>
+</div>
+
+<div dojoType="dijit.layout.ContentPane" layoutAlign="client">
+    <table  jsId="cmfvmGrid"
+            autoHeight='true'
+            dojoType="openils.widget.AutoGrid"
+            fieldOrder="['id', 'real', 'virtual', 'weight']"
+            query="{id: '*'}"
+            defaultCellWidth='"25%"'
+            fmClass='cmfvm'
+            showPaginator='true'
+            editOnEnter='true'>
+    </table>
+ </div>
+
+<script type ="text/javascript">
+
+    dojo.require('dijit.form.FilteringSelect');
+    dojo.require('openils.widget.AutoGrid');
+    dojo.require('openils.widget.AutoFieldWidget');
+    dojo.require('openils.PermaCrud');
+
+    var cmfId = '[% ctx.page_args.0 %]';
+
+    openils.Util.addOnLoad(
+        function() {
+
+            var selector = new openils.widget.AutoFieldWidget({
+                fmClass : 'cmfvm',
+                fmField : 'virtual',
+                parentNode : dojo.byId('attr-def-div')
+            });
+
+            selector.build(
+                function(w, ww) {
+                    dojo.connect(w, 'onChange', 
+                        function(newVal) {
+
+                            // see if this attr def supports composite entries
+                            w.store.fetch({
+                              query : {virtual : ''+newVal}
+                            });
+                            
+                            cmfvmGrid.resetStore();
+                            cmfvmGrid.loadAll({order_by : {cmfvm : 'id'}}, {virtual : newVal});
+                            cmfvmGrid.overrideWidgetArgs.vritual = {dijitArgs : {value : newVal}};
+                            // ^-- why is this not working?
+                        }
+                    );
+
+                    // if a cmf is already selected via URL, fetch the cmfvm's
+                    if (cmfId) w.attr('value', cmfId);
+                }
+            );
+
+            // hide the progress indicator since we're not loading any data up front
+            dojo.style(cmfvmGrid.loadProgressIndicator, 'visibility', 'hidden');
+        }
+    );
+
+</script>
+
+[% END %]
diff --git a/Open-ILS/src/templates/opac/css/style.css.tt2 b/Open-ILS/src/templates/opac/css/style.css.tt2
index aade957..e176ed7 100644
--- a/Open-ILS/src/templates/opac/css/style.css.tt2
+++ b/Open-ILS/src/templates/opac/css/style.css.tt2
@@ -3333,3 +3333,13 @@ label[for*=expert_]
 [id^="toggled-inline-"]:target{
     display: inline;
 }
+
+.oils_SH {
+    font-weight: bolder;
+    background-color: #99ff99;
+}
+
+.oils_SH.identifier {
+    font-weight: bolder;
+    background-color: #42b0f4;
+}
diff --git a/Open-ILS/src/templates/opac/parts/misc_util.tt2 b/Open-ILS/src/templates/opac/parts/misc_util.tt2
index 97cbd1e..2d48ccc 100644
--- a/Open-ILS/src/templates/opac/parts/misc_util.tt2
+++ b/Open-ILS/src/templates/opac/parts/misc_util.tt2
@@ -84,10 +84,50 @@
     END;
 
     # Extract MARC fields from XML
-    #   get_marc_attrs( { marc_xml => doc } )
+    #   get_marc_attrs( args = { marc_xml => doc } )
     BLOCK get_marc_attrs;
+        USE Dumper;
         xml = args.marc_xml;
 
+        args.bibid = [];
+        FOR bibid IN xml.findnodes('//*[@tag="901"]/*[@code="c"]');
+            args.bibid.push(bibid.textContent);
+        END;
+
+        args.df_bib_list = args.bibid;
+        args.bibid = args.bibid.0; 
+
+        IF args.mr_constituent_ids.size && !args.df_bib_list.size;
+            args.df_bib_list = args.mr_constituent_ids;
+        END;
+
+
+        # Gather display field data for this record and map it
+        # to a display field map.  Hopefully, one day, this can
+        # replace the XPath below entirely.
+
+        args.display_fields = {};
+        args.hl = {};
+        IF !CGI.param('no_highlight');
+            args.display_field_list = ctx.fetch_display_fields(args.df_bib_list.list);
+
+            FOR df IN args.display_field_list;
+                df_map = ctx.search_cdfm('field', df.field).0;
+                df_name = df_map.name();
+                IF df_map.multi() == 't';
+                    IF NOT args.hl_display_fields.$df_name;
+                        args.hl_display_fields.$df_name = [];
+                        args.hl.$df_name = [];
+                    END;
+                    args.hl_display_fields.$df_name.push(df);
+                    args.hl.$df_name.push(df.highlight || df.value);
+                ELSIF !args.hl_display_fields.$df_name.defined;
+                    args.hl_display_fields.$df_name = df;
+                    args.hl.$df_name = df.highlight || df.value;
+                END;
+            END;
+        END;
+
         # Map item types to schema.org types; impedance mismatch :(
         args.schema.itemtype = {};
         schema_typemap = {};
@@ -726,12 +766,6 @@
         END;
         args.mmr_unique_bib = mmr_unique_bib;
 
-        args.bibid = [];
-        FOR bibid IN xml.findnodes('//*[@tag="901"]/*[@code="c"]');
-            args.bibid.push(bibid.textContent);
-        END;
-        args.bibid = args.bibid.0; 
-
         IF args.ebook_test_id;
             args.ebook.ebook_id = args.ebook_test_id;
             args.ebook.vendor = 'ebook_test';
diff --git a/Open-ILS/src/templates/opac/parts/record/authors.tt2 b/Open-ILS/src/templates/opac/parts/record/authors.tt2
index 3f0dd2f..4140e78 100644
--- a/Open-ILS/src/templates/opac/parts/record/authors.tt2
+++ b/Open-ILS/src/templates/opac/parts/record/authors.tt2
@@ -23,8 +23,23 @@ authors = [
     }
 ];
 
+BLOCK find_hl_value;
+    outlist = [];
+    norm_needle = PROCESS normalize_string(unnorm_string=needle);
+    FOREACH hl IN attrs.display_field_list;
+        norm_value = PROCESS normalize_string(unnorm_string=hl.value);
+        outlist.push(hl.highlight) IF norm_value == norm_needle;
+    END;
+
+    outlist.0;
+END;
+
+BLOCK normalize_string;
+    unnorm_string.replace('[#"^$\+\-,\.:;&|\[\]()]', ' ').replace('\s+',' ').replace('^\s+','').replace('\s+$','');
+END;
+
 BLOCK normalize_qterm;
-    subfield.textContent.replace('[#"^$\+\-,\.:;&|\[\]()]', ' ');
+    PROCESS normalize_string(unnorm_string=subfield.textContent);
 END;
 
 BLOCK normalize_authors;
@@ -120,14 +135,23 @@ BLOCK build_author_links;
             END;
             iprop = iprop _ '"';
         END;
+
+        link_term = link_term.replace('^\s+', '');
+        match_term = link_term _ ' ' _ birthdate _ ' ' _ deathdate;
+        matching_author_hl = PROCESS find_hl_value needle=match_term;
+
         authtml = ' <span class="rdetail-author-div"' _ iprop _ ' resource="' _ contrib_ref _ '"><a href="' _ url _ '"><span resource="' _ contrib_ref _ '">';
         IF iprop; authtml = authtml _ '<span property="name">'; END;
-        authtml = authtml _ link_term.replace('^\s+', '');
+        IF matching_author_hl;
+            authtml = authtml _ matching_author_hl;
+        ELSE;
+            authtml = authtml _ link_term;
+        END;
         IF iprop; authtml = authtml _ '</span>'; END;
-        IF birthdate;
+        IF birthdate AND !matching_author_hl;
             authtml = authtml _ ' <span property="birthDate">' _ birthdate _ '</span>-';
         END;
-        IF deathdate;
+        IF deathdate AND !matching_author_hl;
             authtml = authtml _ '<span property="deathDate">' _ deathdate _ '</span>';
         END;
         authtml = authtml _ '</span></a>'; # End search link
diff --git a/Open-ILS/src/templates/opac/parts/record/contents.tt2 b/Open-ILS/src/templates/opac/parts/record/contents.tt2
index 29fc33b..4f7897e 100644
--- a/Open-ILS/src/templates/opac/parts/record/contents.tt2
+++ b/Open-ILS/src/templates/opac/parts/record/contents.tt2
@@ -13,6 +13,7 @@ contents =  [
         label => l('Bibliography, etc. Note: '),
         xpath => '//*[@tag="504"]'
     }, {
+        display_field => 'toc',
         label => l('Formatted Contents Note: '),
         xpath => '//*[@tag="505"]'
     }, {
@@ -46,6 +47,7 @@ contents =  [
         label => l('Date/Time and Place of an Event Note: '),
         xpath => '//*[@tag="518"]'
     }, {
+        display_field => 'abstract',
         label => l('Summary, etc.: '),
         xpath => '//*[@tag="520"]'
     }, {
@@ -178,11 +180,17 @@ BLOCK render_contents;
             '</div>';
         END;
     END;
-END 
-%]
-[%  BLOCK render_all_contents;
+END;
+
+BLOCK render_all_contents;
     FOREACH cont IN contents;
-        content = PROCESS render_contents(xpath=cont.xpath);
+        content = '';
+        df = cont.display_field;
+        IF df AND attrs.hl.$df.size;
+            content = attrs.hl.$df.join('<br/>');
+        ELSE;
+            content = PROCESS render_contents(xpath=cont.xpath);
+        END;
         IF content.match('\S');
 -%]
 <tr>
diff --git a/Open-ILS/src/templates/opac/parts/record/subjects.tt2 b/Open-ILS/src/templates/opac/parts/record/subjects.tt2
index b0702a4..ad02856 100644
--- a/Open-ILS/src/templates/opac/parts/record/subjects.tt2
+++ b/Open-ILS/src/templates/opac/parts/record/subjects.tt2
@@ -1,6 +1,7 @@
 [% 
     subjects = [
         {
+            display_field => 'subject',
             label => l('Subject: '),
             xpath => '//*[@tag="600" or @tag="610" or @tag="611" or @tag="630" or @tag="650" or @tag="651"]'
         }, {
@@ -78,13 +79,42 @@
             END;
             '</span>';
         END;
-    END 
+    END;
+
+    BLOCK render_hl_subject;
+        '<span property="about">';
+        %]<a href="[%-
+               mkurl(ctx.opac_root _ '/results', {qtype=>'subject', query=>s.value}, stop_parms.merge(expert_search_parms, general_search_parms, browse_search_parms, facet_search_parms))
+        -%]">[% s.highlight %]</a> [%-
+        '</span>';
+    END;
 %]
 
 [%  BLOCK render_all_subjects;
     FOREACH subj IN subjects;
-        content = PROCESS render_subject(s=subj);
-        IF content.match('\S');
+        content = '';
+        df = subj.display_field;
+        IF df AND attrs.hl_display_fields.$df.size;
+            content = [];
+            FOREACH hl_s IN attrs.hl_display_fields.$df;
+                next_s = PROCESS render_hl_subject(s=hl_s);
+                content.push(next_s);
+            END;
+
+            content = content.join('<br/>');
+%]
+            <table class='rdetail_subject'>
+                <tbody>
+                    <tr>
+                        <td class='rdetail_subject_type'>[% subj.label %]</td>
+                        <td class='rdetail_subject_value'>[% content %]</td>
+                    </tr>
+                </tbody>
+            </table>
+[%          
+        ELSE;
+            content = PROCESS render_subject(s=subj);
+            IF content.match('\S');
 %]
         <table class='rdetail_subject'>
             <tbody>
@@ -94,6 +124,7 @@
                 </tr>
             </tbody>
         </table>
+            [%- END; %]
         [%- END; %]
     [%- END; %]
 [%- END %]
diff --git a/Open-ILS/src/templates/opac/parts/record/summary.tt2 b/Open-ILS/src/templates/opac/parts/record/summary.tt2
index d26810d..20b7d36 100644
--- a/Open-ILS/src/templates/opac/parts/record/summary.tt2
+++ b/Open-ILS/src/templates/opac/parts/record/summary.tt2
@@ -11,7 +11,7 @@
 [%-# This holds the record summary information %]
 <div id="rdetail_summary_header">
     <div id='rdetail_title_div'>
-        <h1 id='rdetail_title' property="name">[% attrs.title_extended | html %]</h1>
+        <h1 id='rdetail_title' property="name">[% IF attrs.hl.title; attrs.hl.title; ELSE; attrs.title_extended | html; END %]</h1>
         [%-
             FOR link880 IN attrs.graphic_titles;
                 FOR alt IN link880.graphic;
diff --git a/Open-ILS/src/templates/opac/parts/result/table.tt2 b/Open-ILS/src/templates/opac/parts/result/table.tt2
index 5ab8e9a..df787f7 100644
--- a/Open-ILS/src/templates/opac/parts/result/table.tt2
+++ b/Open-ILS/src/templates/opac/parts/result/table.tt2
@@ -92,7 +92,7 @@
                                                     <a class='record_title search_link' name='record_[% rec.id %]'
                                                         href="[% record_url %]"
                                                         [% html_text_attr('title', l('Display record details for "[_1]"', attrs.title)) %]>
-                                                        [% attrs.title | html %]
+                                                        [% IF attrs.hl.title; attrs.hl.title; ELSE; attrs.title | html; END %]
                                                      </a>
                                                      [% IF rec.mr_constituent_count.defined && rec.mr_constituent_count > 1 %]
                                                      <span title="[% l('This group contains [_1] records', rec.mr_constituent_count) %]">
@@ -122,7 +122,7 @@ END;
                                                                 href="[%- 
                                                                     authorquery = attrs.author | replace('[#"^$\+\-,\.:;&|\[\]()]', ' ');
                                                                     mkurl(ctx.opac_root _ '/results', {qtype => 'author', query => authorquery}, general_search_parms.merge(expert_search_parms, browse_search_parms, facet_search_parms))
-                                                                    -%]" rel="nofollow" vocab="">[% attrs.author | html %]</a>
+                                                                    -%]" rel="nofollow" vocab="">[% IF attrs.hl.author; attrs.hl.author; ELSE; attrs.author | html; END %]</a>
 [%-
 FOR entry IN attrs.graphic_authors;
     FOR alt IN entry.graphic;
diff --git a/Open-ILS/src/templates/staff/admin/server/config/metabib_field.tt2 b/Open-ILS/src/templates/staff/admin/server/config/metabib_field.tt2
new file mode 100644
index 0000000..97f4031
--- /dev/null
+++ b/Open-ILS/src/templates/staff/admin/server/config/metabib_field.tt2
@@ -0,0 +1,64 @@
+[%
+  WRAPPER "staff/base.tt2";
+  ctx.page_title = l("Metabib Fields");
+  ctx.page_app = "egAdminConfig";
+  ctx.page_ctrl = 'MetabibField';
+%]
+
+[% BLOCK APP_JS %]
+<script src="[% ctx.media_prefix %]/js/ui/default/staff/services/grid.js"></script>
+<script src="[% ctx.media_prefix %]/js/ui/default/staff/services/fm_record_editor.js"></script>
+<script src="[% ctx.media_prefix %]/js/ui/default/staff/services/ui.js"></script>
+<script src="[% ctx.media_prefix %]/js/ui/default/staff/admin/server/config/metabib_field.js"></script>
+<link rel="stylesheet" href="[% ctx.base_path %]/staff/css/admin.css" />
+[% END %]
+
+<div class="container-fluid" style="text-align:center">
+  <div class="alert alert-info alert-less-pad strong-text-2">
+    [% l('Metabib Fields') %]
+  </div>
+</div>
+
+<div class="row">
+  <div class="col-md-2 form-group">
+      <label class="pull-right">[% l('Search Class') %]</label>
+  </div>
+  <div class="col-md-2 form-group nullable">
+      <select class="form-control" ng-model="search_class">
+        <option value="">[% l('All classes') %]</option>
+        <option value="keyword">[% l('Keyword') %]</option>
+        <option value="title">[% l('Title') %]</option>
+        <option value="author">[% l('Author') %]</option>
+        <option value="subject">[% l('Subject') %]</option>
+        <option value="series">[% l('Series') %]</option>
+        <option value="identifier">[% l('Identifier') %]</option>
+      </select>
+  </div>
+</div>
+
+<eg-grid
+    id-field="id"
+    idl-class="cmf"
+    grid-controls="gridControls"
+    features="-multiselect"
+    persist-key="admin.server.config.metabib_field.grid"
+    dateformat="{{$root.egDateAndTimeFormat}}">
+
+    <eg-grid-menu-item handler="new_record" label="[% l('New Record') %]"></eg-grid-menu-item>
+    <eg-grid-action handler="edit_record" label="[% l('Edit Record') %]"></eg-grid-action>
+    <eg-grid-action handler="delete_record" label="[% l('Delete Record') %]"></eg-grid-action>
+
+    <eg-grid-field label="[% l('ID') %]"    path='id' required hidden></eg-grid-field>
+    <eg-grid-field label="[% l('Label') %]" path="label" required></eg-grid-field>
+    <eg-grid-field label="[% l('Class') %]" path="field_class"></eg-grid-field>
+    <eg-grid-field label="[% l('Field') %]" path="name" hidden></eg-grid-field>
+    <eg-grid-field label="[% l('Search Field') %]" path='search_field'></eg-grid-field>
+    <eg-grid-field label="[% l('Facet Field') %]" path='facet_field'></eg-grid-field>
+    <eg-grid-field label="[% l('Display Field') %]" path='display_field'></eg-grid-field>
+    <eg-grid-field label="[% l('Browse Field') %]" path='browse_field'></eg-grid-field>
+    <eg-grid-field label="[% l('Data Suppliers') %]">
+        <a href="./admin/server/config/metabib_field_virtual_map?cmf={{item.id}}" target="_blank">[% l('Manage'); %]</a>
+    </eg-grid-field>
+</eg-grid>
+
+[% END %]
diff --git a/Open-ILS/src/templates/staff/admin/server/config/metabib_field_virtual_map.tt2 b/Open-ILS/src/templates/staff/admin/server/config/metabib_field_virtual_map.tt2
new file mode 100644
index 0000000..4959c66
--- /dev/null
+++ b/Open-ILS/src/templates/staff/admin/server/config/metabib_field_virtual_map.tt2
@@ -0,0 +1,41 @@
+[%
+  WRAPPER "staff/base.tt2";
+  ctx.page_title = l("Virtual Field Data Providers");
+  ctx.page_app = "egAdminConfig";
+  ctx.page_ctrl = 'MetabibFieldVirtualMap';
+%]
+
+[% BLOCK APP_JS %]
+<script src="[% ctx.media_prefix %]/js/ui/default/staff/services/grid.js"></script>
+<script src="[% ctx.media_prefix %]/js/ui/default/staff/services/fm_record_editor.js"></script>
+<script src="[% ctx.media_prefix %]/js/ui/default/staff/services/ui.js"></script>
+<script src="[% ctx.media_prefix %]/js/ui/default/staff/admin/server/config/metabib_field_virtual_map.js"></script>
+<link rel="stylesheet" href="[% ctx.base_path %]/staff/css/admin.css" />
+[% END %]
+
+<div class="container-fluid" style="text-align:center">
+  <div class="alert alert-info alert-less-pad strong-text-2">
+    [% l('Virtual Field Data Providers') %]
+  </div>
+</div>
+
+<eg-grid
+    id-field="id"
+    idl-class="cmfvm"
+    grid-controls="gridControls"
+    features="-multiselect"
+    main-label="{{cmf.label()}}"
+    persist-key="admin.server.config.metabib_field_virtual_map.grid"
+    dateformat="{{$root.egDateAndTimeFormat}}">
+
+    <eg-grid-menu-item handler="new_record" label="[% l('New Record') %]"></eg-grid-menu-item>
+    <eg-grid-action handler="edit_record" label="[% l('Edit Record') %]"></eg-grid-action>
+    <eg-grid-action handler="delete_record" label="[% l('Delete Record') %]"></eg-grid-action>
+
+    <eg-grid-field label="[% l('ID') %]"    path='id' required hidden></eg-grid-field>
+    <eg-grid-field label="[% l('Virtual') %]" path="virtual.label"></eg-grid-field>
+    <eg-grid-field label="[% l('Real') %]" path="real.label"></eg-grid-field>
+    <eg-grid-field label="[% l('Weight') %]" path="weight"></eg-grid-field>
+</eg-grid>
+
+[% END %]
diff --git a/Open-ILS/web/js/ui/default/staff/admin/server/config/metabib_field.js b/Open-ILS/web/js/ui/default/staff/admin/server/config/metabib_field.js
new file mode 100644
index 0000000..3f28e49
--- /dev/null
+++ b/Open-ILS/web/js/ui/default/staff/admin/server/config/metabib_field.js
@@ -0,0 +1,93 @@
+angular.module('egAdminConfig',
+    ['ngRoute','ui.bootstrap','egCoreMod','egUiMod','egGridMod','egFmRecordEditorMod'])
+
+.controller('MetabibField',
+       ['$scope','$q','$timeout','$location','$window','$uibModal','egCore','egGridDataProvider',
+        'egConfirmDialog',
+function($scope , $q , $timeout , $location , $window , $uibModal , egCore , egGridDataProvider ,
+         egConfirmDialog) {
+
+    egCore.startup.go(); // standalone mode requires manual startup
+
+    $scope.search_class = '';
+    $scope.$watch('search_class', function(newVal, oldVal) {
+        if (newVal != oldVal) {
+            $scope.gridControls.setQuery(generateQuery($scope.search_class));
+            $scope.gridControls.refresh();
+        }
+    });
+
+    $scope.new_record = function() {
+        spawn_editor();
+    }
+
+    $scope.edit_record = function(items) {
+        if (items.length != 1) return;
+        spawn_editor(items[0].id);
+    }
+
+    spawn_editor = function(id) {
+        var templ;
+        if (arguments.length == 1) {
+            templ = '<eg-edit-fm-record idl-class="cmf" mode="update" record-id="id" on-save="ok" on-cancel="cancel"></eg-edit-fm-record>';
+        } else {
+            templ = '<eg-edit-fm-record idl-class="cmf" mode="create" on-save="ok" on-cancel="cancel"></eg-edit-fm-record>';
+        }
+        gridControls = $scope.gridControls;
+        $uibModal.open({
+            template : templ,
+            backdrop: 'static',
+            controller : [
+                        '$scope', '$uibModalInstance',
+                function($scope ,  $uibModalInstance) {
+                    $scope.id = id;
+
+                    $scope.ok = function($event) {
+                        $uibModalInstance.close();
+                        gridControls.refresh();
+                    }
+    
+                    $scope.cancel = function($event) {
+                        $uibModalInstance.dismiss();
+                    }
+                }
+            ]
+        });
+    }
+
+    $scope.delete_record = function(selected) {
+        if (!selected || !selected.length) return;
+
+        egCore.pcrud.retrieve('cmf', selected[0].id).then(function(rec) {
+            egConfirmDialog.open(
+                egCore.strings.EG_CONFIRM_DELETE_RECORD_TITLE,
+                egCore.strings.EG_CONFIRM_DELETE_RECORD_BODY,
+                { id : rec.id() } // TODO replace with selector if available?
+            ).result.then(function() {
+                egCore.pcrud.remove(rec).then(function() {
+                    $scope.gridControls.refresh();
+                });
+            });
+        });
+    }
+
+    function generateQuery(search_class) {
+        var q = { 'id' : { '!=' : null } };
+
+        if (search_class) {
+            q.field_class = search_class;
+        }
+
+        return q;
+    }
+
+    $scope.gridControls = {
+        activateItem : function (i) { return $scope.edit_record([i]) },
+        setQuery : function() {
+            return generateQuery($scope.search_class);
+        },
+        setSort : function() {
+            return ['label'];
+        }
+    }
+}])
diff --git a/Open-ILS/web/js/ui/default/staff/admin/server/config/metabib_field_virtual_map.js b/Open-ILS/web/js/ui/default/staff/admin/server/config/metabib_field_virtual_map.js
new file mode 100644
index 0000000..1c2ffb2
--- /dev/null
+++ b/Open-ILS/web/js/ui/default/staff/admin/server/config/metabib_field_virtual_map.js
@@ -0,0 +1,98 @@
+angular.module('egAdminConfig',
+    ['ngRoute','ui.bootstrap','egCoreMod','egUiMod','egGridMod','egFmRecordEditorMod'])
+
+.controller('MetabibFieldVirtualMap',
+       ['$scope','$q','$timeout','$location','$window','$uibModal','egCore','egGridDataProvider',
+        'egConfirmDialog',
+function($scope , $q , $timeout , $location , $window , $uibModal , egCore , egGridDataProvider ,
+         egConfirmDialog) {
+
+    egCore.startup.go(); // standalone mode requires manual startup
+
+    $scope.cmf = null;
+
+    $scope.virt_field = $location.search().cmf || '';
+    if ($scope.virt_field) egCore.pcrud.retrieve('cmf', $scope.virt_field).then(function(c) { $scope.cmf = c });
+
+    $scope.$watch('virt_field', function(newVal, oldVal) {
+        if (newVal != oldVal) {
+            egCore.pcrud.retrieve('cmf', newVal).then(function(c) { $scope.cmf = c });
+            $scope.gridControls.setQuery(generateQuery($scope.virt_field));
+            $scope.gridControls.refresh();
+        }
+    });
+
+    $scope.new_record = function() {
+        spawn_editor();
+    }
+
+    $scope.edit_record = function(items) {
+        if (items.length != 1) return;
+        spawn_editor(items[0].id);
+    }
+
+    spawn_editor = function(id) {
+        var templ;
+        if (arguments.length == 1) {
+            templ = '<eg-edit-fm-record idl-class="cmfvm" mode="update" record-id="id" on-save="ok" on-cancel="cancel"></eg-edit-fm-record>';
+        } else {
+            templ = '<eg-edit-fm-record idl-class="cmfvm" mode="create" on-save="ok" on-cancel="cancel"></eg-edit-fm-record>';
+        }
+        gridControls = $scope.gridControls;
+        $uibModal.open({
+            template : templ,
+            backdrop: 'static',
+            controller : [
+                        '$scope', '$uibModalInstance',
+                function($scope ,  $uibModalInstance) {
+                    $scope.id = id;
+
+                    $scope.ok = function($event) {
+                        $uibModalInstance.close();
+                        gridControls.refresh();
+                    }
+    
+                    $scope.cancel = function($event) {
+                        $uibModalInstance.dismiss();
+                    }
+                }
+            ]
+        });
+    }
+
+    $scope.delete_record = function(selected) {
+        if (!selected || !selected.length) return;
+
+        egCore.pcrud.retrieve('cmfvm', selected[0].id).then(function(rec) {
+            egConfirmDialog.open(
+                egCore.strings.EG_CONFIRM_DELETE_RECORD_TITLE,
+                egCore.strings.EG_CONFIRM_DELETE_RECORD_BODY,
+                { id : rec.id() } // TODO replace with selector if available?
+            ).result.then(function() {
+                egCore.pcrud.remove(rec).then(function() {
+                    $scope.gridControls.refresh();
+                });
+            });
+        });
+    }
+
+    function generateQuery(virt_field) {
+        var q = { 'id' : { '!=' : null } };
+
+        if (virt_field) {
+            q.virtual = virt_field;
+        }
+
+        return q;
+    }
+
+    $scope.gridControls = {
+        activateItem : function (i) { return $scope.edit_record([i]) },
+        setQuery : function() {
+            return generateQuery($scope.virt_field);
+        },
+        setSort : function() {
+            return ['label'];
+        }
+    }
+}])
diff --git a/Open-ILS/web/js/ui/default/staff/services/fm_record_editor.js b/Open-ILS/web/js/ui/default/staff/services/fm_record_editor.js
index 4cb38e5..a7ca7c6 100644
--- a/Open-ILS/web/js/ui/default/staff/services/fm_record_editor.js
+++ b/Open-ILS/web/js/ui/default/staff/services/fm_record_editor.js
@@ -139,21 +139,12 @@ angular.module('egFmRecordEditorMod',
 
             function flatten_linked_values(cls, list) {
                 var results = [];
-                var fields = egCore.idl.classes[cls].fields;
-                var id_field;
-                var selector;
-                angular.forEach(fields, function(fld) {
-                    if (fld.datatype == 'id') {
-                        id_field = fld.name;
-                        selector = fld.selector ? fld.selector : id_field;
-                        return;
-                    }
-                });
+                var id_field = egCore.idl.classes[cls].pkey;
+                var selector = egCore.idl.classes[cls].field_map[id_field].selector || id_field;
                 angular.forEach(list, function(item) {
-                    var rec = egCore.idl.toHash(item);
                     results.push({
-                        id : rec[id_field],
-                        name : rec[selector]
+                        id : item[id_field](),
+                        name : item[selector]()
                     });
                 });
                 return results;
@@ -175,7 +166,7 @@ angular.module('egFmRecordEditorMod',
                         }
                     }
                     if (field.datatype == 'link') {
-                    egCore.pcrud.retrieveAll(
+                        egCore.pcrud.retrieveAll(
                             field.class, {}, {atomic : true}
                         ).then(function(list) {
                             field.linked_values = flatten_linked_values(field.class, list);
diff --git a/Open-ILS/web/js/ui/default/staff/services/grid.js b/Open-ILS/web/js/ui/default/staff/services/grid.js
index ed21ae0..fc3a05b 100644
--- a/Open-ILS/web/js/ui/default/staff/services/grid.js
+++ b/Open-ILS/web/js/ui/default/staff/services/grid.js
@@ -1650,6 +1650,8 @@ angular.module('egGridMod',
         // idlClass as the base.
         cols.idlFieldFromPath = function(dotpath) {
             var class_obj = egCore.idl.classes[cols.idlClass];
+            if (!dotpath) return null;
+
             var path_parts = dotpath.split(/\./);
 
             var idl_parent;
@@ -1913,7 +1915,7 @@ angular.module('egGridMod',
                     angular.forEach(provider.columnsProvider.columns, 
                         function(col) {
                             // only query IDL-tracked columns
-                            if (!col.adhoc && (col.required || col.visible))
+                            if (!col.adhoc && col.name && col.path && (col.required || col.visible))
                                 queryFields[col.name] = col.path;
                         }
                     );

commit 4d4a1c92c29061a7fbef649b0b1ab65c544a32f3
Author: Bill Erickson <berickxx at gmail.com>
Date:   Thu Oct 26 16:24:30 2017 -0400

    LP#1727487 Display field JS utils more docs
    
    Signed-off-by: Bill Erickson <berickxx at gmail.com>
    Signed-off-by: Kathy Lussier <klussier at masslnc.org>
    Signed-off-by: Dan Wells <dbw2 at calvin.edu>

diff --git a/Open-ILS/web/js/ui/default/staff/cat/services/record.js b/Open-ILS/web/js/ui/default/staff/cat/services/record.js
index 22df857..5560553 100644
--- a/Open-ILS/web/js/ui/default/staff/cat/services/record.js
+++ b/Open-ILS/web/js/ui/default/staff/cat/services/record.js
@@ -226,12 +226,23 @@ angular.module('egCoreMod')
  * Note that 'mwde' objects (which are proper IDL objects) only contain
  * the prescribed fields from the IDL (and database view), while the
  * 'mfde' hash-based objects contain all configured display fields,
- * including local/custom fields.
+ * including custom fields.
+ * 
+ * MWDE objects are best suited to cases where the available set of
+ * display fields must be auto-generated from the IDL.  They work well
+ * with egGrids because it can automatically determine from the IDL
+ * which fields should be added to the column picker.
+ *
+ * MFDE lists are well suited to cases where the set of fields to
+ * display is known in advance (e.g. hard-coded in the template) or when
+ * the caller needs data for custom fields.  FWIW, MFDE data is slightly
+ * leaner for retrieval in that it does not require the JSON round-trip
+ * for delivery.
  *
  * Example:
  *
  *  --
- *  // Display well-known fields
+ *  // MVR-style canned fields
  *
  *  $scope.record = copy.call_number().record();
  *
@@ -276,10 +287,10 @@ angular.module('egCoreMod')
      * Converts JSON-encoded values within a mwde object to Javascript
      * native strings, numbers, and arrays.
      *
-     * @collapseMulti collapse array (multi) fields down to a single string
-     * with values separated by a comma+space.  Useful for quickly 
-     * building displays (e.g. grids) without having to first munge 
-     * the array into a string.
+     * @collapseMulti collapse multi=true array values down to a single 
+     * comma-separated string.  This is useful for quickly  building 
+     * displays (e.g. grids) without having to first munge the array 
+     * into a string.
      */
     service.mwdeJSONToJS = function(entry, collapseMulti) {
         angular.forEach(egCore.idl.classes.mwde.fields, function(f) {
@@ -296,7 +307,7 @@ angular.module('egCoreMod')
      * Non-multi values are strings or numbers.
      * Multi values are arrays of strings or numbers.
      *
-     * @collapseMulti See service.mwdeJSONToJS()
+     * @collapseMulti See egBibDisplay.mwdeJSONToJS()
      */
     service.mfdeToHash = function(entries, collapseMulti) {
         var hash = service.mfdeToMetaHash(entries, collapseMulti);
@@ -311,7 +322,7 @@ angular.module('egCoreMod')
      * The scalar_or_array value is a string/number or an array of
      * string/numbers
      *
-     * @collapseMulti See service.mwdeJSONToJS()
+     * @collapseMulti See egBibDisplay.mwdeJSONToJS()
      */
     service.mfdeToMetaHash = function(entries, collapseMulti) {
         var hash = {};
@@ -329,10 +340,10 @@ angular.module('egCoreMod')
             if (entry.multi() == 't') {
                 if (collapseMulti) {
                     if (angular.isArray(hash[entry.name()].value)) {
-                        // new collapsed string
+                        // start a new collapsed string
                         hash[entry.name()].value = entry.value();
                     } else {
-                        // append to collapsed string
+                        // append to collapsed string in progress
                         hash[entry.name()].value += ', ' + entry.value();
                     }
                 } else {

commit da1bc239fdefd358173e82b2c13d76a5aa6fd701
Author: Bill Erickson <berickxx at gmail.com>
Date:   Thu Oct 26 15:55:46 2017 -0400

    LP#1727487 Webstaff record summary uses display fields
    
    Signed-off-by: Bill Erickson <berickxx at gmail.com>
    Signed-off-by: Kathy Lussier <klussier at masslnc.org>
    Signed-off-by: Dan Wells <dbw2 at calvin.edu>

diff --git a/Open-ILS/src/templates/staff/cat/share/t_record_summary.tt2 b/Open-ILS/src/templates/staff/cat/share/t_record_summary.tt2
index e11eead..c98b087 100644
--- a/Open-ILS/src/templates/staff/cat/share/t_record_summary.tt2
+++ b/Open-ILS/src/templates/staff/cat/share/t_record_summary.tt2
@@ -43,16 +43,16 @@
     <div class="flex-cell flex-2">
       <a target="_self" 
         href="[% ctx.base_path %]/staff/cat/catalog/record/{{record.id()}}">
-        {{mvr.title()}}
+        {{rec_display.title}}
       </a>
     </div>
 
     <div class="flex-cell strong-text">[% l('Author:') %]</div>
-    <div class="flex-cell flex-2">{{mvr.author()}}</div>
+    <div class="flex-cell flex-2">{{rec_display.author}}</div>
 
     <div class="flex-cell strong-text">[% l('Pub Date:') %]</div>
     <div class="flex-cell">
-      {{mvr.pubdate()}}
+      {{rec_display.pubdate}}
     </div>
 
     <div class="flex-cell strong-text">[% l('Database ID:') %]</div>
@@ -66,12 +66,12 @@
     <div class="flex-cell flex-2">
       <a target="_self" 
         href="[% ctx.base_path %]/staff/cat/catalog/record/{{record.id()}}">
-        {{mvr.title()}}
+        {{rec_display.title}}
       </a>
     </div>
 
     <div class="flex-cell strong-text">[% l('Edition:') %]</div>
-    <div class="flex-cell">{{mvr.edition()}}</div>
+    <div class="flex-cell">{{rec_display.edition}}</div>
 
     <div class="flex-cell strong-text">[% l('TCN:') %]</div>
     <div class="flex-cell">{{record.tcn_value()}}</div>
@@ -82,11 +82,11 @@
 
   <div class="flex-row">
     <div class="flex-cell strong-text">[% l('Author:') %]</div>
-    <div class="flex-cell flex-2">{{mvr.author()}}</div>
+    <div class="flex-cell flex-2">{{rec_display.author}}</div>
 
     <div class="flex-cell strong-text">[% l('Pub Date:') %]</div>
     <div class="flex-cell">
-      {{mvr.pubdate()}}
+      {{rec_display.pubdate}}
     </div>
 
     <div class="flex-cell strong-text">[% l('Database ID:') %]</div>
diff --git a/Open-ILS/web/js/ui/default/staff/cat/services/record.js b/Open-ILS/web/js/ui/default/staff/cat/services/record.js
index ba66c00..22df857 100644
--- a/Open-ILS/web/js/ui/default/staff/cat/services/record.js
+++ b/Open-ILS/web/js/ui/default/staff/cat/services/record.js
@@ -143,25 +143,20 @@ angular.module('egCoreMod')
         },
         templateUrl : './cat/share/t_record_summary',
         controller : 
-                   ['$scope','egCore','$sce',
-            function($scope , egCore , $sce) {
+                   ['$scope','egCore','$sce','egBibDisplay',
+            function($scope , egCore , $sce , egBibDisplay) {
 
                 function loadRecord() {
                     egCore.pcrud.retrieve('bre', $scope.recordId, {
                         flesh : 1,
                         flesh_fields : {
-                            bre : ['creator','editor']
+                            bre : ['creator','editor','flat_display_entries']
                         }
                     }).then(function(rec) {
                         rec.owner(egCore.org.get(rec.owner()));
                         $scope.record = rec;
-                    });
-                    egCore.net.request(
-                        'open-ils.search',
-                        'open-ils.search.biblio.record.mods_slim.retrieve.authoritative',
-                        $scope.recordId
-                    ).then(function(mvr) {
-                        $scope.mvr = mvr;
+                        $scope.rec_display = 
+                            egBibDisplay.mfdeToHash(rec.flat_display_entries());
                     });
                     $scope.bib_cn = null;
                     $scope.bib_cn_tooltip = '';

commit 2fcd2d03891dba2474fb137e40aa1c8964311d10
Author: Bill Erickson <berickxx at gmail.com>
Date:   Thu Oct 26 15:17:45 2017 -0400

    LP#1727487 Webstaff In-House-Use uses display fields
    
    Replace reporter.simple_record data with metabib display fields.
    
    Use flat_display_entries instead of wide_display_entry partially as an
    example, but also because it requires slightly less data munging on the
    DB side.
    
    Signed-off-by: Bill Erickson <berickxx at gmail.com>
    Signed-off-by: Kathy Lussier <klussier at masslnc.org>
    
    Conflicts:
    	Open-ILS/web/js/ui/default/staff/circ/in_house_use/app.js
    
    Signed-off-by: Kathy Lussier <klussier at masslnc.org>
    Signed-off-by: Dan Wells <dbw2 at calvin.edu>

diff --git a/Open-ILS/src/templates/staff/circ/in_house_use/index.tt2 b/Open-ILS/src/templates/staff/circ/in_house_use/index.tt2
index 9889557..df39540 100644
--- a/Open-ILS/src/templates/staff/circ/in_house_use/index.tt2
+++ b/Open-ILS/src/templates/staff/circ/in_house_use/index.tt2
@@ -8,6 +8,7 @@
 [% BLOCK APP_JS %]
 <script src="[% ctx.media_prefix %]/js/ui/default/staff/services/grid.js"></script>
 <script src="[% ctx.media_prefix %]/js/ui/default/staff/services/ui.js"></script>
+<script src="[% ctx.media_prefix %]/js/ui/default/staff/cat/services/record.js"></script>
 [% INCLUDE 'staff/circ/share/circ_strings.tt2' %]
 <script src="[% ctx.media_prefix %]/js/ui/default/staff/circ/in_house_use/app.js"></script>
 [% END %]
diff --git a/Open-ILS/web/js/ui/default/staff/circ/in_house_use/app.js b/Open-ILS/web/js/ui/default/staff/circ/in_house_use/app.js
index 6d0d352..8899aca 100644
--- a/Open-ILS/web/js/ui/default/staff/circ/in_house_use/app.js
+++ b/Open-ILS/web/js/ui/default/staff/circ/in_house_use/app.js
@@ -8,8 +8,10 @@ angular.module('egInHouseUseApp',
 })
 
 .controller('InHouseUseCtrl',
-       ['$scope','egCore','egGridDataProvider','egConfirmDialog', 'egAlertDialog',
-function($scope,  egCore,  egGridDataProvider , egConfirmDialog, egAlertDialog) {
+       ['$scope','egCore','egGridDataProvider','egConfirmDialog', 
+        'egAlertDialog','egBibDisplay',
+function($scope , egCore , egGridDataProvider , egConfirmDialog, 
+         egAlertDialog , egBibDisplay) {
 
     var countCap;
     var countMax;
@@ -95,7 +97,10 @@ function($scope,  egCore,  egGridDataProvider , egConfirmDialog, egAlertDialog)
                     flesh_fields : {
                         acp : ['call_number','location'],
                         acn : ['record', 'prefix', 'suffix'],
-                        bre : ['simple_record']
+                        // We don't need to display a wide range of bib
+                        // fields in this UI.  Fetch the flat display since
+                        // it requires less DB-side munging (and as an example).  
+                        bre : ['flat_display_entries']
                     },
                     select : { bre : ['id'] } // avoid fleshing MARC
                 }
@@ -109,6 +114,11 @@ function($scope,  egCore,  egGridDataProvider , egConfirmDialog, egAlertDialog)
 
                 coArgs.copyid = copy.id();
 
+                copy.call_number().record().flat_display_entries(
+                    egBibDisplay.mfdeToHash(
+                        copy.call_number().record().flat_display_entries())
+                );
+
                 // LP1507807: Display the copy alert if the setting is on.
                 if ($scope.copyAlert && copy.alert_message()) {
                     egAlertDialog.open(copy.alert_message()).result;
@@ -152,7 +162,7 @@ function($scope,  egCore,  egGridDataProvider , egConfirmDialog, egAlertDialog)
             var item = {num_uses : resp.length};
             item.copy = data.copy;
             item.title = data.title || 
-                data.copy.call_number().record().simple_record().title();
+                data.copy.call_number().record().flat_display_entries().title;
             item.index = checkouts.length;
 
             checkouts.unshift(item);

commit b5abea61bc73cc092e415bd0d2ab3c805d25a1c7
Author: Bill Erickson <berickxx at gmail.com>
Date:   Thu Oct 26 15:14:15 2017 -0400

    LP#1727487 Items out display uses collapsed display fields
    
    Signed-off-by: Bill Erickson <berickxx at gmail.com>
    Signed-off-by: Kathy Lussier <klussier at masslnc.org>
    Signed-off-by: Dan Wells <dbw2 at calvin.edu>

diff --git a/Open-ILS/web/js/ui/default/staff/circ/patron/items_out.js b/Open-ILS/web/js/ui/default/staff/circ/patron/items_out.js
index e3e4617..b209d18 100644
--- a/Open-ILS/web/js/ui/default/staff/circ/patron/items_out.js
+++ b/Open-ILS/web/js/ui/default/staff/circ/patron/items_out.js
@@ -128,16 +128,16 @@ function($scope , $q , $routeParams , $timeout , egCore , egUser , patronSvc ,
             circ.circ_lib(egCore.org.get(circ.circ_lib())); // local fleshing
 
             // Translate bib display field JSON blobs to JS.
+            // Collapse multi/array fields down to comma-separated strings.
             egBibDisplay.mwdeJSONToJS(
-                circ.target_copy().call_number().record().wide_display_entry());
+                circ.target_copy().call_number().record().wide_display_entry(), true);
 
             if (circ.target_copy().call_number().id() == -1) {
                 // dummy-up a record for precat items
                 circ.target_copy().call_number().record().wide_display_entry({
                     title : function() {return circ.target_copy().dummy_title()},
                     author : function() {return circ.target_copy().dummy_author()},
-                    // ISBN is a multi=true field.
-                    isbn : function() {return [circ.target_copy().dummy_isbn()]}
+                    isbn : function() {return circ.target_copy().dummy_isbn()}
                 })
             }
 

commit d58bbd561aef5b2b48f28b2c84423dd233c78264
Author: Bill Erickson <berickxx at gmail.com>
Date:   Thu Oct 26 15:10:17 2017 -0400

    LP#1727487 Webstaff display fields collapseMulti option
    
    Support an option in the webstaff-side display field munging code to
    collapse array/multi values down to a single comma-separated string.
    
    This is useful for buidling displays (grids especially) where you have a
    single spot to put a field's value (e.g. a list of ISBN's) and don't want
    to munge the data by hand in each UI.
    
    Signed-off-by: Bill Erickson <berickxx at gmail.com>
    Signed-off-by: Kathy Lussier <klussier at masslnc.org>
    Signed-off-by: Dan Wells <dbw2 at calvin.edu>

diff --git a/Open-ILS/web/js/ui/default/staff/cat/services/record.js b/Open-ILS/web/js/ui/default/staff/cat/services/record.js
index 7aa25e1..ba66c00 100644
--- a/Open-ILS/web/js/ui/default/staff/cat/services/record.js
+++ b/Open-ILS/web/js/ui/default/staff/cat/services/record.js
@@ -280,11 +280,19 @@ angular.module('egCoreMod')
     /**
      * Converts JSON-encoded values within a mwde object to Javascript
      * native strings, numbers, and arrays.
+     *
+     * @collapseMulti collapse array (multi) fields down to a single string
+     * with values separated by a comma+space.  Useful for quickly 
+     * building displays (e.g. grids) without having to first munge 
+     * the array into a string.
      */
-    service.mwdeJSONToJS = function(entry) {
+    service.mwdeJSONToJS = function(entry, collapseMulti) {
         angular.forEach(egCore.idl.classes.mwde.fields, function(f) {
             if (f.virtual) return;
-            entry[f.name](JSON.parse(entry[f.name]()));
+            var val = JSON.parse(entry[f.name]());
+            if (collapseMulti && angular.isArray(val))
+                val = val.join(', ');
+            entry[f.name](val);
         });
     }
 
@@ -292,9 +300,11 @@ angular.module('egCoreMod')
      * Converts a list of 'mfde' entry objects to a simple key=>value hash.
      * Non-multi values are strings or numbers.
      * Multi values are arrays of strings or numbers.
+     *
+     * @collapseMulti See service.mwdeJSONToJS()
      */
-    service.mfdeToHash = function(entries) {
-        var hash = service.mfdeToMetaHash(entries);
+    service.mfdeToHash = function(entries, collapseMulti) {
+        var hash = service.mfdeToMetaHash(entries, collapseMulti);
         angular.forEach(hash, 
             function(sub_hash, name) { hash[name] = sub_hash.value });
         return hash;
@@ -305,8 +315,10 @@ angular.module('egCoreMod')
      * {name => field_name, label => field_label, value => scalar_or_array}
      * The scalar_or_array value is a string/number or an array of
      * string/numbers
+     *
+     * @collapseMulti See service.mwdeJSONToJS()
      */
-    service.mfdeToMetaHash = function(entries) {
+    service.mfdeToMetaHash = function(entries, collapseMulti) {
         var hash = {};
         angular.forEach(entries, function(entry) {
 
@@ -320,7 +332,17 @@ angular.module('egCoreMod')
             }
 
             if (entry.multi() == 't') {
-                hash[entry.name()].value.push(entry.value());
+                if (collapseMulti) {
+                    if (angular.isArray(hash[entry.name()].value)) {
+                        // new collapsed string
+                        hash[entry.name()].value = entry.value();
+                    } else {
+                        // append to collapsed string
+                        hash[entry.name()].value += ', ' + entry.value();
+                    }
+                } else {
+                    hash[entry.name()].value.push(entry.value());
+                }
             } else {
                 hash[entry.name()].value = entry.value();
             }

commit 526584fa959bf9f03ae6adfb5ef2446d5b9b1d0b
Author: Bill Erickson <berickxx at gmail.com>
Date:   Thu Oct 26 12:25:51 2017 -0400

    LP#1727487 Webstaff Items Out uses display fields
    
    Signed-off-by: Bill Erickson <berickxx at gmail.com>
    Signed-off-by: Kathy Lussier <klussier at masslnc.org>
    
    Conflicts:
    	Open-ILS/web/js/ui/default/staff/circ/patron/items_out.js
    
    Signed-off-by: Kathy Lussier <klussier at masslnc.org>
    Signed-off-by: Dan Wells <dbw2 at calvin.edu>

diff --git a/Open-ILS/src/templates/staff/circ/patron/t_items_out.tt2 b/Open-ILS/src/templates/staff/circ/patron/t_items_out.tt2
index 4efa432b..2f705ce 100644
--- a/Open-ILS/src/templates/staff/circ/patron/t_items_out.tt2
+++ b/Open-ILS/src/templates/staff/circ/patron/t_items_out.tt2
@@ -90,7 +90,7 @@
   <eg-grid-field label="[% l('Fines Stopped') %]" path='stop_fines'></eg-grid-field>
   <eg-grid-field label="[% l('Title') %]" path="target_copy.call_number.record.simple_record.title" name="title">
     <a target="_self" href="[% ctx.base_path %]/staff/cat/catalog/record/{{item.target_copy().call_number().record().id()}}">
-      {{item.target_copy().call_number().record().simple_record().title()}}
+      {{item.target_copy().call_number().record().wide_display_entry().title()}}
     </a>
   </eg-grid-field>
   <eg-grid-field path="*" hidden></eg-grid-field>
@@ -102,7 +102,7 @@
   <eg-grid-field path="target_copy.call_number.prefix.label" label="[% l('CN Prefix') %]" hidden></eg-grid-field>
   <eg-grid-field path="target_copy.call_number.suffix.label" label="[% l('CN Suffix') %]" hidden></eg-grid-field>
   <eg-grid-field path="target_copy.call_number.record.*" hidden></eg-grid-field>
-  <eg-grid-field path="target_copy.call_number.record.simple_record.*" hidden></eg-grid-field>
+  <eg-grid-field path="target_copy.call_number.record.wide_display_entry.*" hidden></eg-grid-field>
 </eg-grid>
 </div>
 
diff --git a/Open-ILS/web/js/ui/default/staff/circ/patron/items_out.js b/Open-ILS/web/js/ui/default/staff/circ/patron/items_out.js
index ac189f9..e3e4617 100644
--- a/Open-ILS/web/js/ui/default/staff/circ/patron/items_out.js
+++ b/Open-ILS/web/js/ui/default/staff/circ/patron/items_out.js
@@ -5,10 +5,12 @@
 angular.module('egPatronApp')
 
 .controller('PatronItemsOutCtrl',
-       ['$scope','$q','$routeParams','$timeout','egCore','egUser','patronSvc','$location',
-        'egGridDataProvider','$uibModal','egCirc','egConfirmDialog','egBilling','$window',
-function($scope,  $q,  $routeParams,  $timeout,  egCore , egUser,  patronSvc , $location, 
-         egGridDataProvider , $uibModal , egCirc , egConfirmDialog , egBilling , $window) {
+       ['$scope','$q','$routeParams','$timeout','egCore','egUser','patronSvc',
+        '$location','egGridDataProvider','$uibModal','egCirc','egConfirmDialog',
+        'egBilling','$window','egBibDisplay',
+function($scope , $q , $routeParams , $timeout , egCore , egUser , patronSvc , 
+         $location , egGridDataProvider , $uibModal , egCirc , egConfirmDialog , 
+         egBilling , $window , egBibDisplay) {
 
     // list of noncatatloged circulations. Define before initTab to 
     // avoid any possibility of race condition, since they are loaded
@@ -108,7 +110,7 @@ function($scope,  $q,  $routeParams,  $timeout,  egCore , egUser,  patronSvc , $
                     circ : ['target_copy', 'workstation', 'checkin_workstation'],
                     acp : ['call_number', 'holds_count', 'status', 'circ_lib'],
                     acn : ['record', 'owning_lib', 'prefix', 'suffix'],
-                    bre : ['simple_record']
+                    bre : ['wide_display_entry']
                 },
                 // avoid fetching the MARC blob by specifying which 
                 // fields on the bre to select.  More may be needed.
@@ -125,12 +127,17 @@ function($scope,  $q,  $routeParams,  $timeout,  egCore , egUser,  patronSvc , $
         }).then(deferred.resolve, null, function(circ) {
             circ.circ_lib(egCore.org.get(circ.circ_lib())); // local fleshing
 
+            // Translate bib display field JSON blobs to JS.
+            egBibDisplay.mwdeJSONToJS(
+                circ.target_copy().call_number().record().wide_display_entry());
+
             if (circ.target_copy().call_number().id() == -1) {
                 // dummy-up a record for precat items
-                circ.target_copy().call_number().record().simple_record({
+                circ.target_copy().call_number().record().wide_display_entry({
                     title : function() {return circ.target_copy().dummy_title()},
                     author : function() {return circ.target_copy().dummy_author()},
-                    isbn : function() {return circ.target_copy().dummy_isbn()}
+                    // ISBN is a multi=true field.
+                    isbn : function() {return [circ.target_copy().dummy_isbn()]}
                 })
             }
 
@@ -353,8 +360,8 @@ function($scope,  $q,  $routeParams,  $timeout,  egCore , egUser,  patronSvc , $
                 circ : egCore.idl.toHash(circ),
                 copy : egCore.idl.toHash(circ.target_copy()),
                 call_number : egCore.idl.toHash(circ.target_copy().call_number()),
-                title : circ.target_copy().call_number().record().simple_record().title(),
-                author : circ.target_copy().call_number().record().simple_record().author(),
+                title : circ.target_copy().call_number().record().wide_display_entry().title(),
+                author : circ.target_copy().call_number().record().wide_display_entry().author()
             })
         });
 

commit c12daecfc0bc0cf0303837a0d97f1c9e6589d61e
Author: Bill Erickson <berickxx at gmail.com>
Date:   Wed Oct 25 18:07:53 2017 -0400

    LP#1727487 Display field seed data WIP
    
    Signed-off-by: Bill Erickson <berickxx at gmail.com>
    Signed-off-by: Kathy Lussier <klussier at masslnc.org>
    Signed-off-by: Dan Wells <dbw2 at calvin.edu>

diff --git a/Open-ILS/examples/fm_IDL.xml b/Open-ILS/examples/fm_IDL.xml
index 04f3420..a84b556 100644
--- a/Open-ILS/examples/fm_IDL.xml
+++ b/Open-ILS/examples/fm_IDL.xml
@@ -3807,10 +3807,23 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 			<field name="source" reporter:label="Record ID" reporter:datatype="id" />
 			<field name="title" reporter:label="Title" reporter:datatype="text"/>
 			<field name="author" reporter:label="Author" reporter:datatype="text"/>
-			<field name="subject" reporter:label="Subject" reporter:datatype="text"/>
 			<field name="creators" reporter:label="Creators" reporter:datatype="text"/>
 			<field name="isbn" reporter:label="ISBN" reporter:datatype="text"/>
-			<!-- TODO add all well-known fields -->
+			<field name="issn" reporter:label="ISSN" reporter:datatype="text"/>
+			<field name="upc" reporter:label="UPC" reporter:datatype="text"/>
+			<field name="tcn" reporter:label="TCN" reporter:datatype="text"/>
+			<field name="edition" reporter:label="Edition" reporter:datatype="text"/>
+			<field name="physical_description" reporter:label="Physical Description" reporter:datatype="text"/>
+			<field name="publisher" reporter:label="Publisher" reporter:datatype="text"/>
+			<field name="series_title" reporter:label="Series Title" reporter:datatype="text"/>
+			<field name="subject_geographic" reporter:label="Geographic Subject" reporter:datatype="text"/>
+			<field name="subject_name" reporter:label="Name Subject" reporter:datatype="text"/>
+			<field name="subject_temporal" reporter:label="Temporal Subject" reporter:datatype="text"/>
+			<field name="subject_topic" reporter:label="Topic Subject" reporter:datatype="text"/>
+			<field name="abstract" reporter:label="Abstract" reporter:datatype="text"/>
+			<field name="toc" reporter:label="Table of Contents" reporter:datatype="text"/>
+			<field name="pubdate" reporter:label="Publication Date" reporter:datatype="text"/>
+			<field name="type_of_resource" reporter:label="Type of Resource" reporter:datatype="text"/>
 		</fields>
 		<links>
 			<link field="source" reltype="has_a" key="id" map="" class="bre"/>
diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.data.display-field-seed-data.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.data.display-field-seed-data.sql
new file mode 100644
index 0000000..ea55482
--- /dev/null
+++ b/Open-ILS/src/sql/Pg/upgrade/XXXX.data.display-field-seed-data.sql
@@ -0,0 +1,210 @@
+BEGIN;
+
+-- SELECT evergreen.upgrade_deps_block_check('TODO', :eg_version);
+
+-- NEW config.metabib_field entries
+
+INSERT INTO config.metabib_field (id, field_class, name, 
+    label, xpath, display_field, search_field, browse_field)
+VALUES (
+    38, 'identifier', 'edition', 
+    oils_i18n_gettext(38, 'Edition', 'cmf', 'label'),
+    $$//mods33:mods/mods33:originInfo//mods33:edition[1]$$,
+    TRUE, FALSE, FALSE
+);
+
+INSERT INTO config.metabib_field (id, field_class, name, 
+    label, xpath, display_field, search_field, browse_field)
+VALUES (
+    39, 'identifier', 'physical_description', 
+    oils_i18n_gettext(39, 'Physical Descrption', 'cmf', 'label'),
+    $$(//mods33:mods/mods33:physicalDescription/mods33:form|//mods33:mods/mods33:physicalDescription/mods33:extent|//mods33:mods/mods33:physicalDescription/mods33:reformattingQuality|//mods33:mods/mods33:physicalDescription/mods33:internetMediaType|//mods33:mods/mods33:physicalDescription/mods33:digitalOrigin)$$,
+    TRUE, FALSE, FALSE
+);
+
+INSERT INTO config.metabib_field (id, field_class, name, 
+    label, xpath, display_field, search_field, browse_field)
+VALUES (
+    40, 'identifier', 'publisher', 
+    oils_i18n_gettext(40, 'Publisher', 'cmf', 'label'),
+    $$//mods33:mods/mods33:originInfo//mods33:publisher[1]$$,
+    TRUE, FALSE, FALSE
+);
+
+INSERT INTO config.metabib_field (id, field_class, name, 
+    label, xpath, display_field, search_field, browse_field)
+VALUES (
+    41, 'identifier', 'abstract', 
+    oils_i18n_gettext(41, 'Abstract', 'cmf', 'label'),
+    $$//mods33:mods/mods33:abstract$$,
+    TRUE, FALSE, FALSE
+);
+
+INSERT INTO config.metabib_field (id, field_class, name, 
+    label, xpath, display_field, search_field, browse_field)
+VALUES (
+    42, 'identifier', 'toc', 
+    oils_i18n_gettext(42, 'Table of Contents', 'cmf', 'label'),
+    $$//mods33:tableOfContents$$,
+    TRUE, FALSE, FALSE
+);
+
+INSERT INTO config.metabib_field (id, field_class, name, 
+    label, xpath, display_field, search_field, browse_field)
+VALUES (
+    43, 'identifier', 'type_of_resource', 
+    oils_i18n_gettext(43, 'Type of Resource', 'cmf', 'label'),
+    $$//mods33:mods/mods33:typeOfResource$$,
+    TRUE, FALSE, FALSE
+);
+
+INSERT INTO config.metabib_field (id, field_class, name, 
+    label, xpath, display_field, search_field, browse_field)
+VALUES (
+    44, 'identifier', 'pubdate', 
+    oils_i18n_gettext(44, 'Publication Date', 'cmf', 'label'),
+    $$//mods33:mods/mods33:originInfo//mods33:dateIssued[@encoding="marc"]|//mods33:mods/mods33:originInfo//mods33:dateIssued[1]$$,
+    TRUE, FALSE, FALSE
+);
+
+
+-- Modify existing config.metabib_field entries
+
+UPDATE config.metabib_field SET display_field = TRUE WHERE id IN (
+    1,  -- seriestitle
+    11, -- subject_geographic 
+    12, -- subject_name
+    13, -- subject_temporal
+    14, -- subject_topic
+    19, -- ISSN
+    20, -- UPC
+    26  -- TCN
+);
+
+-- Map display field names to config.metabib_field entries
+
+INSERT INTO config.display_field_map (name, field, multi) VALUES 
+    ('series_title',         1, FALSE),
+    ('subject_geographic',  11, TRUE),
+    ('subject_name',        12, TRUE),
+    ('subject_temporal',    13, TRUE),
+    ('subject_topic',       14, TRUE),
+    ('issn',                19, TRUE),
+    ('upc',                 20, TRUE),
+    ('tcn',                 26, FALSE),
+    ('edition',             38, FALSE),
+    ('physical_description',39, TRUE),
+    ('publisher',           40, FALSE),
+    ('abstract',            41, FALSE),
+    ('toc',                 42, FALSE),
+    ('type_of_resource',    43, FALSE),
+    ('pubdate',             44, FALSE)
+;
+
+-- Add a column to wide-display-entry per well-known field
+
+DROP VIEW metabib.wide_display_entry;
+CREATE VIEW metabib.wide_display_entry AS
+    SELECT 
+        bre.id AS source,
+        COALESCE(mcde_title.value, 'null') AS title,
+        COALESCE(mcde_author.value, 'null') AS author,
+        COALESCE(mcde_subject_geographic.value, 'null') AS subject_geographic,
+        COALESCE(mcde_subject_name.value, 'null') AS subject_name,
+        COALESCE(mcde_subject_temporal.value, 'null') AS subject_temporal,
+        COALESCE(mcde_subject_topic.value, 'null') AS subject_topic,
+        COALESCE(mcde_creators.value, 'null') AS creators,
+        COALESCE(mcde_isbn.value, 'null') AS isbn,
+        COALESCE(mcde_issn.value, 'null') AS issn,
+        COALESCE(mcde_upc.value, 'null') AS upc,
+        COALESCE(mcde_tcn.value, 'null') AS tcn,
+        COALESCE(mcde_edition.value, 'null') AS edition,
+        COALESCE(mcde_physical_description.value, 'null') AS physical_description,
+        COALESCE(mcde_publisher.value, 'null') AS publisher,
+        COALESCE(mcde_series_title.value, 'null') AS series_title,
+        COALESCE(mcde_abstract.value, 'null') AS abstract,
+        COALESCE(mcde_toc.value, 'null') AS toc,
+        COALESCE(mcde_pubdate.value, 'null') AS pubdate,
+        COALESCE(mcde_type_of_resource.value, 'null') AS type_of_resource
+    FROM biblio.record_entry bre 
+    LEFT JOIN metabib.compressed_display_entry mcde_title 
+        ON (bre.id = mcde_title.source AND mcde_title.name = 'title')
+    LEFT JOIN metabib.compressed_display_entry mcde_author 
+        ON (bre.id = mcde_author.source AND mcde_author.name = 'author')
+    LEFT JOIN metabib.compressed_display_entry mcde_subject 
+        ON (bre.id = mcde_subject.source AND mcde_subject.name = 'subject')
+    LEFT JOIN metabib.compressed_display_entry mcde_subject_geographic 
+        ON (bre.id = mcde_subject_geographic.source 
+            AND mcde_subject_geographic.name = 'subject_geographic')
+    LEFT JOIN metabib.compressed_display_entry mcde_subject_name 
+        ON (bre.id = mcde_subject_name.source 
+            AND mcde_subject_name.name = 'subject_name')
+    LEFT JOIN metabib.compressed_display_entry mcde_subject_temporal 
+        ON (bre.id = mcde_subject_temporal.source 
+            AND mcde_subject_temporal.name = 'subject_temporal')
+    LEFT JOIN metabib.compressed_display_entry mcde_subject_topic 
+        ON (bre.id = mcde_subject_topic.source 
+            AND mcde_subject_topic.name = 'subject_topic')
+    LEFT JOIN metabib.compressed_display_entry mcde_creators 
+        ON (bre.id = mcde_creators.source AND mcde_creators.name = 'creators')
+    LEFT JOIN metabib.compressed_display_entry mcde_isbn 
+        ON (bre.id = mcde_isbn.source AND mcde_isbn.name = 'isbn')
+    LEFT JOIN metabib.compressed_display_entry mcde_issn 
+        ON (bre.id = mcde_issn.source AND mcde_issn.name = 'issn')
+    LEFT JOIN metabib.compressed_display_entry mcde_upc 
+        ON (bre.id = mcde_upc.source AND mcde_upc.name = 'upc')
+    LEFT JOIN metabib.compressed_display_entry mcde_tcn 
+        ON (bre.id = mcde_tcn.source AND mcde_tcn.name = 'tcn')
+    LEFT JOIN metabib.compressed_display_entry mcde_edition 
+        ON (bre.id = mcde_edition.source AND mcde_edition.name = 'edition')
+    LEFT JOIN metabib.compressed_display_entry mcde_physical_description 
+        ON (bre.id = mcde_physical_description.source 
+            AND mcde_physical_description.name = 'physical_description')
+    LEFT JOIN metabib.compressed_display_entry mcde_publisher 
+        ON (bre.id = mcde_publisher.source AND mcde_publisher.name = 'publisher')
+    LEFT JOIN metabib.compressed_display_entry mcde_series_title 
+        ON (bre.id = mcde_series_title.source AND mcde_series_title.name = 'series_title')
+    LEFT JOIN metabib.compressed_display_entry mcde_abstract 
+        ON (bre.id = mcde_abstract.source AND mcde_abstract.name = 'abstract')
+    LEFT JOIN metabib.compressed_display_entry mcde_toc 
+        ON (bre.id = mcde_toc.source AND mcde_toc.name = 'toc')
+    LEFT JOIN metabib.compressed_display_entry mcde_pubdate 
+        ON (bre.id = mcde_pubdate.source AND mcde_pubdate.name = 'pubdate')
+    LEFT JOIN metabib.compressed_display_entry mcde_type_of_resource 
+        ON (bre.id = mcde_type_of_resource.source 
+            AND mcde_type_of_resource.name = 'type_of_resource')
+;
+
+COMMIT;
+
+/** ROLLBACK 
+
+BEGIN;
+DELETE FROM metabib.display_entry WHERE field IN (1,11,12,13,14,19,20,26,38,39,40,41,42,43,44);
+DELETE FROM config.display_field_map WHERE field IN (1,11,12,13,14,19,20,26,38,39,40,41,42,43,44);
+DELETE FROM config.metabib_field WHERE id IN (38,39,40,41,42,43,44);
+COMMIT;
+
+*/
+
+-- Perform a full display field reingest, since we didn't do one during
+-- the 3.0 upgrade when display fields were introduced.
+
+\qecho
+\qecho Reingesting display field entries.  This may take a while.
+\qecho This command can be stopped (control-c) and rerun later if needed:
+\qecho
+\qecho SELECT metabib.reingest_metabib_field_entries(id, TRUE, FALSE, TRUE, TRUE,     
+\qecho     (SELECT ARRAY_AGG(id)::INT[] FROM config.metabib_field WHERE display_field)) 
+\qecho     FROM biblio.record_entry WHERE id > 0; 
+\qecho
+
+-- avoid displaying a row per entry by selecting the total count.
+-- NOTE: extracting display data for deleted bibs because we occasionally
+-- display deleted bib records.
+SELECT COUNT(*) AS bib_count FROM (
+  SELECT metabib.reingest_metabib_field_entries(id, TRUE, FALSE, TRUE, TRUE,     
+    (SELECT ARRAY_AGG(id)::INT[] FROM config.metabib_field WHERE display_field)) 
+  FROM biblio.record_entry WHERE id > 0
+) x;
+

-----------------------------------------------------------------------

Summary of changes:
 Open-ILS/examples/fm_IDL.xml                       |   61 +-
 .../lib/OpenILS/Application/Search/Biblio.pm       |   41 +
 .../lib/OpenILS/Application/Storage/CDBI/config.pm |    7 +
 .../Application/Storage/Driver/Pg/QueryParser.pm   |  248 +-
 .../Application/Storage/Publisher/metabib.pm       |    5 +
 .../lib/OpenILS/Application/Storage/QueryParser.pm |   21 +-
 .../src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm    |   25 +
 .../perlmods/lib/OpenILS/WWW/EGCatLoader/Search.pm |   24 +-
 .../perlmods/lib/OpenILS/WWW/EGCatLoader/Util.pm   |  148 +-
 Open-ILS/src/sql/Pg/002.schema.config.sql          |   25 +-
 Open-ILS/src/sql/Pg/030.schema.metabib.sql         |  144 +-
 Open-ILS/src/sql/Pg/300.schema.staged_search.sql   |  140 +
 Open-ILS/src/sql/Pg/950.data.seed-values.sql       |  187 +-
 Open-ILS/src/sql/Pg/953.data.MODS32-xsl.sql        |   46 +-
 Open-ILS/src/sql/Pg/954.data.MODS33-xsl.sql        |   44 +-
 Open-ILS/src/sql/Pg/999.functions.global.sql       |    4 +
 Open-ILS/src/sql/Pg/reporter-schema.sql            |   35 +-
 .../upgrade/WWWW.data.display-field-seed-data.sql  |  260 +
 .../Pg/upgrade/XXXX.schema.highlight_search.sql    |  573 ++
 .../YYYY.data.mods-title-punctuation-change.sql    | 6895 ++++++++++++++++++++
 .../Pg/upgrade/ZZZZ.data.virtual_index_defs.sql    |   71 +
 .../support-scripts/test-scripts/query_parser.pl   |   12 +-
 .../conify/global/config/metabib_field.tt2         |   24 +-
 .../global/config/metabib_field_virtual_map.tt2    |   77 +
 Open-ILS/src/templates/opac/css/style.css.tt2      |   10 +
 Open-ILS/src/templates/opac/parts/config.tt2       |    3 +
 Open-ILS/src/templates/opac/parts/misc_util.tt2    |   51 +-
 .../src/templates/opac/parts/record/authors.tt2    |   32 +-
 .../src/templates/opac/parts/record/contents.tt2   |   21 +-
 .../src/templates/opac/parts/record/series.tt2     |   70 +-
 .../src/templates/opac/parts/record/subjects.tt2   |   44 +-
 .../src/templates/opac/parts/record/summary.tt2    |   46 +-
 Open-ILS/src/templates/opac/parts/result/table.tt2 |    4 +-
 Open-ILS/src/templates/opac/parts/searchbar.tt2    |   12 +-
 .../staff/admin/server/config/metabib_field.tt2    |   64 +
 .../server/config/metabib_field_virtual_map.tt2    |   41 +
 .../templates/staff/cat/share/t_record_summary.tt2 |   14 +-
 .../templates/staff/circ/in_house_use/index.tt2    |    1 +
 .../templates/staff/circ/patron/t_items_out.tt2    |    4 +-
 Open-ILS/web/images/highlight.png                  |  Bin 0 -> 928 bytes
 .../staff/admin/server/config/metabib_field.js     |   93 +
 .../server/config/metabib_field_virtual_map.js     |   98 +
 .../web/js/ui/default/staff/cat/services/record.js |   64 +-
 .../js/ui/default/staff/circ/in_house_use/app.js   |   18 +-
 .../js/ui/default/staff/circ/patron/items_out.js   |   23 +-
 .../ui/default/staff/services/fm_record_editor.js  |   19 +-
 Open-ILS/web/js/ui/default/staff/services/grid.js  |    4 +-
 ...search-display-infrastructure-improvements.adoc |  154 +
 48 files changed, 9710 insertions(+), 297 deletions(-)
 create mode 100644 Open-ILS/src/sql/Pg/upgrade/WWWW.data.display-field-seed-data.sql
 create mode 100644 Open-ILS/src/sql/Pg/upgrade/XXXX.schema.highlight_search.sql
 create mode 100644 Open-ILS/src/sql/Pg/upgrade/YYYY.data.mods-title-punctuation-change.sql
 create mode 100644 Open-ILS/src/sql/Pg/upgrade/ZZZZ.data.virtual_index_defs.sql
 create mode 100644 Open-ILS/src/templates/conify/global/config/metabib_field_virtual_map.tt2
 create mode 100644 Open-ILS/src/templates/staff/admin/server/config/metabib_field.tt2
 create mode 100644 Open-ILS/src/templates/staff/admin/server/config/metabib_field_virtual_map.tt2
 create mode 100644 Open-ILS/web/images/highlight.png
 create mode 100644 Open-ILS/web/js/ui/default/staff/admin/server/config/metabib_field.js
 create mode 100644 Open-ILS/web/js/ui/default/staff/admin/server/config/metabib_field_virtual_map.js
 create mode 100644 docs/RELEASE_NOTES_NEXT/Architecture/search-display-infrastructure-improvements.adoc


hooks/post-receive
-- 
Evergreen ILS


More information about the open-ils-commits mailing list