[open-ils-commits] [GIT] Evergreen ILS branch tags/rel_2_6_0 created. e0ff2567fcba83e9e9e9736bc06a36aa87f3a1b3

Evergreen Git git at git.evergreen-ils.org
Sun Apr 20 22:28:07 EDT 2014


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, tags/rel_2_6_0 has been created
        at  e0ff2567fcba83e9e9e9736bc06a36aa87f3a1b3 (commit)

- Log -----------------------------------------------------------------
commit e0ff2567fcba83e9e9e9736bc06a36aa87f3a1b3
Author: Dan Wells <dbw2 at calvin.edu>
Date:   Wed Apr 16 11:45:38 2014 -0400

    Bumping version numbers, adding Upgrade Script and Changelog
    
    Signed-off-by: Dan Wells <dbw2 at calvin.edu>

diff --git a/ChangeLog b/ChangeLog
index 1f72b2c..a40b891 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,4800 @@
-Evergreen doesn't keep a GNU-style ChangeLog except in release tarballs.
-Those seeking a change log are encouraged to run 'git log -v', or read
-it online at: http://git.evergreen-ils.org/?p=Evergreen.git;a=log
+commit 659a07064a6ba60029f51de375aadd61bfb994ca
+Author: Dan Scott <dscott at laurentian.ca>
+Date:   Wed Apr 16 10:42:49 2014 -0400
+
+    LP#1308590 Fix schema.org type mapping
+    
+    The switch to config.coded_value_map for format icon types and labels
+    inadvertently broke schema.org type mapping. Restore it and attempt
+    to take advantage of the finer-grained types that are now available
+    to us.
+    
+    Signed-off-by: Dan Scott <dscott at laurentian.ca>
+    Signed-off-by: Galen Charlton <gmc at esilibrary.com>
+
+30	4	Open-ILS/src/templates/opac/parts/misc_util.tt2
+
+commit 11e4e20c2a2d6e5a66278b49b5c3434c087f1d96
+Author: Dan Wells <dbw2 at calvin.edu>
+Date:   Wed Apr 16 09:56:53 2014 -0400
+
+    Compile and Tweak Release Notes for 2.6.0
+    
+    Also, add '.txt' to template name, since our build process expects
+    and uses that extension.
+    
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+557	0	docs/RELEASE_NOTES_2_6.txt
+0	18	docs/RELEASE_NOTES_NEXT/Administration/staff-initials.txt
+0	98	docs/RELEASE_NOTES_NEXT/Cataloging/fixed_fields_enhancements.txt
+0	39	docs/RELEASE_NOTES_NEXT/Cataloging/marc_export_replacement.txt
+0	24	docs/RELEASE_NOTES_NEXT/Circulation/lost_min_max_item_pricing.txt
+0	17	docs/RELEASE_NOTES_NEXT/Circulation/user_editor_update_expire_date_button.txt
+0	40	docs/RELEASE_NOTES_NEXT/OPAC/Composite_Record_Attributes.txt
+0	13	docs/RELEASE_NOTES_NEXT/OPAC/Disable_Autosuggest.txt
+0	21	docs/RELEASE_NOTES_NEXT/OPAC/Located_URI_visibility.txt
+0	45	docs/RELEASE_NOTES_NEXT/OPAC/Multi_Valued_fields.txt
+0	5	docs/RELEASE_NOTES_NEXT/OPAC/OpenSearch.txt
+0	33	docs/RELEASE_NOTES_NEXT/OPAC/TPAC_library_pages.txt
+0	38	docs/RELEASE_NOTES_NEXT/OPAC/TPAC_metarecords.txt
+0	8	docs/RELEASE_NOTES_NEXT/OPAC/WCAG.txt
+0	36	docs/RELEASE_NOTES_NEXT/OPAC/stripe_payments.txt
+0	18	docs/RELEASE_NOTES_NEXT/RELEASE_NOTE_TEMPLATE
+18	0	docs/RELEASE_NOTES_NEXT/RELEASE_NOTE_TEMPLATE.txt
+3	46	docs/RELEASE_NOTES_NEXT/_acknowledgments
+0	21	docs/RELEASE_NOTES_NEXT/removal_of_ingest.txt
+ create mode 100644 docs/RELEASE_NOTES_2_6.txt
+ delete mode 100644 docs/RELEASE_NOTES_NEXT/Administration/staff-initials.txt
+ delete mode 100644 docs/RELEASE_NOTES_NEXT/Cataloging/fixed_fields_enhancements.txt
+ delete mode 100644 docs/RELEASE_NOTES_NEXT/Cataloging/marc_export_replacement.txt
+ delete mode 100644 docs/RELEASE_NOTES_NEXT/Circulation/lost_min_max_item_pricing.txt
+ delete mode 100644 docs/RELEASE_NOTES_NEXT/Circulation/user_editor_update_expire_date_button.txt
+ delete mode 100644 docs/RELEASE_NOTES_NEXT/OPAC/Composite_Record_Attributes.txt
+ delete mode 100644 docs/RELEASE_NOTES_NEXT/OPAC/Disable_Autosuggest.txt
+ delete mode 100644 docs/RELEASE_NOTES_NEXT/OPAC/Located_URI_visibility.txt
+ delete mode 100644 docs/RELEASE_NOTES_NEXT/OPAC/Multi_Valued_fields.txt
+ delete mode 100644 docs/RELEASE_NOTES_NEXT/OPAC/OpenSearch.txt
+ delete mode 100644 docs/RELEASE_NOTES_NEXT/OPAC/TPAC_library_pages.txt
+ delete mode 100644 docs/RELEASE_NOTES_NEXT/OPAC/TPAC_metarecords.txt
+ delete mode 100644 docs/RELEASE_NOTES_NEXT/OPAC/WCAG.txt
+ delete mode 100644 docs/RELEASE_NOTES_NEXT/OPAC/stripe_payments.txt
+ delete mode 100644 docs/RELEASE_NOTES_NEXT/RELEASE_NOTE_TEMPLATE
+ create mode 100644 docs/RELEASE_NOTES_NEXT/RELEASE_NOTE_TEMPLATE.txt
+ delete mode 100644 docs/RELEASE_NOTES_NEXT/removal_of_ingest.txt
+
+commit 1a2d5bb17a1a4c65a29442c0784d2e1f2e58c981
+Author: Dan Wells <dbw2 at calvin.edu>
+Date:   Mon Feb 24 17:43:29 2014 -0500
+
+    Bump OpenILS.pm version
+    
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+1	1	Open-ILS/src/perlmods/lib/OpenILS.pm
+
+commit ab9c7849a19aae60a5b61e8a09d6412ff275616b
+Author: Dan Wells <dbw2 at calvin.edu>
+Date:   Tue Apr 15 22:37:26 2014 -0400
+
+    Translation updates - po files
+    
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+6	6	build/i18n/po/AutoFieldWidget.js/en-GB.po
+2579	2427	build/i18n/po/db.seed/cs-CZ.po
+2347	2284	build/i18n/po/db.seed/de-DE.po
+2347	2284	build/i18n/po/db.seed/en-CA.po
+2347	2284	build/i18n/po/db.seed/en-GB.po
+2347	2284	build/i18n/po/db.seed/es-ES.po
+2349	2286	build/i18n/po/db.seed/fr-CA.po
+2349	2286	build/i18n/po/db.seed/hy-AM.po
+2347	2284	build/i18n/po/db.seed/oc-FR.po
+2348	2285	build/i18n/po/db.seed/pt-BR.po
+2348	2285	build/i18n/po/db.seed/ru-RU.po
+2345	2282	build/i18n/po/db.seed/tr-TR.po
+14	14	build/i18n/po/fm_IDL.dtd/fr-CA.po
+5	4	build/i18n/po/lang.dtd/cs-CZ.po
+
+commit e8b967aaaebe16682b52e359ff93c22114a0ce7a
+Author: Galen Charlton <gmc at esilibrary.com>
+Date:   Thu Apr 10 10:40:01 2014 -0700
+
+    LP#1306176: force installation of Business::Stripe from CPAN
+    
+    Business::Stripe can fail to pass its tests on platforms that
+    happen to have Pod::Simple 3.24 or later and Test::Pod.  In
+    particular, Debian Jessie and Ubuntu Trusty meet those conditions
+    (since the OpenSRF installation process installs libtest-pod-perl)
+    and Debian Wheezy with backports enabled does as well.
+    
+    Since the failing test cases are only for POD, this patches moves
+    Business::Stripe to the CPAN_MODULES_FORCE list across the board.
+    
+    This can be undone if/when Business::Stripe releases a fix for
+    the POD validation warnings.
+    
+    Signed-off-by: Galen Charlton <gmc at esilibrary.com>
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+
+1	1	Open-ILS/src/extras/install/Makefile.debian-squeeze
+1	1	Open-ILS/src/extras/install/Makefile.debian-wheezy
+1	1	Open-ILS/src/extras/install/Makefile.fedora
+1	1	Open-ILS/src/extras/install/Makefile.ubuntu-lucid
+1	1	Open-ILS/src/extras/install/Makefile.ubuntu-precise
+
+commit f1fa38c29611f0e84d343d1543c3602cf6799b2b
+Author: Ben Shum <bshum at biblio.org>
+Date:   Thu Apr 10 17:47:26 2014 -0400
+
+    LP#1304559 - stamping upgrade script for vandelay_record_attr_to_flat
+    
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+
+1	1	Open-ILS/src/sql/Pg/002.schema.config.sql
+78	0	Open-ILS/src/sql/Pg/upgrade/0879.function.vandelay_record_attr_to_flat.sql
+0	78	Open-ILS/src/sql/Pg/upgrade/XXXX.function.vandelay_record_attr_to_flat.sql
+ create mode 100644 Open-ILS/src/sql/Pg/upgrade/0879.function.vandelay_record_attr_to_flat.sql
+ delete mode 100644 Open-ILS/src/sql/Pg/upgrade/XXXX.function.vandelay_record_attr_to_flat.sql
+
+commit d42fbecebddbb33bbb83fad4e7994d8b08237b76
+Author: Dan Wells <dbw2 at calvin.edu>
+Date:   Thu Apr 10 09:15:07 2014 -0400
+
+    LP#1304559 Fix slow Vandelay-based imports
+    
+    Whether a planning limitation or otherwise, we have seen a few cases
+    where queries run very, very slowly (appear to hang) when using the
+    updated metabib.record_attr view in a WHERE clause.
+    
+    The simplest code change is to switch Vandelay to use the intermediate
+    '_flat' view instead, and early reports indicate that this at least
+    gets us back to a functional state.
+    
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+
+2	2	Open-ILS/src/sql/Pg/012.schema.vandelay.sql
+78	0	Open-ILS/src/sql/Pg/upgrade/XXXX.function.vandelay_record_attr_to_flat.sql
+ create mode 100644 Open-ILS/src/sql/Pg/upgrade/XXXX.function.vandelay_record_attr_to_flat.sql
+
+commit 12319bb483d9a0d1e53db552b1f44f6866dcfea1
+Author: Dan Scott <dscott at laurentian.ca>
+Date:   Thu Apr 10 10:54:19 2014 -0400
+
+    LP#1305958 Fix copy table header ID error
+    
+    Currently there is a <td headers='copy_header_date_format'> entry in
+    copy_table.tt2 that does not link to an associated table header with an
+    ID of that value. The desired target ID is "copy_header_create_date".
+    
+    Signed-off-by: Dan Scott <dscott at laurentian.ca>
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+1	1	Open-ILS/src/templates/opac/parts/record/copy_table.tt2
+
+commit e953ba1b9a3260d352f62ca7fa44fd45188e0308
+Author: Mike Rylander <mrylander at gmail.com>
+Date:   Thu Apr 10 13:03:30 2014 -0400
+
+    LP#1306133: Avoid metabib.rec_descriptor where possible
+    
+    metabib.rec_descriptor has been a view over other data structures
+    for some time now, but with the advent of the new attribute infrastructure
+    it is a view over a view over a view, variously transforming IDs to
+    a slim table to an HSTORE structure and finally to a wide table. Thus,
+    it is extremely expensive to query. So we won't unless we're asked to.
+    Which, in the TPAC world, is never.
+    
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+    Signed-off-by: Doug Kyle <dkyle at grpl.org>
+
+15	5	Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Publisher/metabib.pm
+
+commit ce9f58a3a8293ebf9070587f7c4b5806e196ceb6
+Author: Galen Charlton <gmc at esilibrary.com>
+Date:   Thu Apr 3 14:54:11 2014 -0400
+
+    LP#1302113: acknowledgments for 2.6.0
+    
+    Signed-off-by: Galen Charlton <gmc at esilibrary.com>
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+62	0	docs/RELEASE_NOTES_NEXT/_acknowledgments
+ create mode 100644 docs/RELEASE_NOTES_NEXT/_acknowledgments
+
+commit 490c214516fff7a4032fd131782ce46efb45e3e6
+Author: Galen Charlton <gmc at esilibrary.com>
+Date:   Thu Apr 3 14:52:08 2014 -0400
+
+    LP#1302113: define a file for storing lists of folks to acknowledge in the release notes
+    
+    If a file called _acknowlegments is present in the docs/RELEASE_NOTES_NEXT
+    directory, its contents will be appended to the end of the release
+    notes under an "Acknowledgments" heading when
+    create_release_notes.sh is run.
+    
+    Signed-off-by: Galen Charlton <gmc at esilibrary.com>
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+3	0	docs/RELEASE_NOTES_NEXT/README
+7	0	docs/RELEASE_NOTES_NEXT/create_release_notes.sh
+
+commit 97d18d648de58b4e2b65b99891041b54551d0c6e
+Author: Mike Rylander <mrylander at gmail.com>
+Date:   Wed Apr 2 13:11:25 2014 -0400
+
+    LP#1301510 Align element name with Fixed Field type
+    
+    We depend on the field name in the XUL to line up the fixed field
+    value maps in the database with the appropriate context menus. ELvl
+    was not capitalized the same in all required spots, causing the
+    context menu to render but be ineffective.
+    
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+    Signed-off-by: Remington Steed <rjs7 at calvin.edu>
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+1	1	Open-ILS/xul/staff_client/server/cat/marcedit.xul
+
+commit f82055d180f0249be8de9013a36d22a04943f6a9
+Author: Mike Rylander <mrylander at gmail.com>
+Date:   Mon Apr 7 15:42:45 2014 -0400
+
+    LP#1303987: Fully populate Ills from context menu
+    
+    The Ills fixed field is 4 characters long (allowing for up to four
+    types of illustrations to be noted, per 008/006), but the fixed field
+    editor dropdown menus are not (a) multi-select capable nor (b) ready
+    to support multi-value-per-field, because, well Ills is the only one
+    like this, and that would be a pretty big complication to the code.
+    However, even though multi-select is not supported, we should still
+    apply the value selected and update the fixed field, otherwise the
+    value is not updated in the record itself.
+    
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+    Signed-off-by: Remington Steed <rjs7 at calvin.edu>
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+4	3	Open-ILS/src/perlmods/lib/OpenILS/Application/Cat.pm
+5	0	Open-ILS/xul/staff_client/server/cat/marcedit.js
+
+commit 0757600b7a18e1f80aa54078b494b4f562b38370
+Author: Lebbeous Fogle-Weekley <lebbeous at esilibrary.com>
+Date:   Tue Feb 18 12:55:15 2014 -0500
+
+    LP#1281678 Fixed field context menus should trigger close confirmation dialog
+    
+    Same for using the Physical Characteristics Wizard.
+    
+    Thanks Dan Wells for the spot.
+    
+    Signed-off-by: Lebbeous Fogle-Weekley <lebbeous at esilibrary.com>
+    Signed-off-by: Remington Steed <rjs7 at calvin.edu>
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+2	0	Open-ILS/xul/staff_client/server/cat/marcedit.js
+
+commit 81a71b098ddac1b621acb4b680edce841177e083
+Author: Mike Rylander <mrylander at gmail.com>
+Date:   Wed Apr 2 16:03:39 2014 -0400
+
+    Reset the displayed mouse cursor
+    
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+    Signed-off-by: Remington Steed <rjs7 at calvin.edu>
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+1	0	Open-ILS/web/js/dojo/openils/widget/PhysCharWizard.js
+
+commit 3d59a013070b41565e67398cb19d246095a05b3d
+Author: Jeff Godin <jgodin at tadl.org>
+Date:   Wed Oct 30 13:17:25 2013 -0400
+
+    Add alert in user editor for method errors
+    
+    Add an alert() in the user editor so that method errors are not
+    silent.
+    
+    Without this, a method error (such as when saving a patron fails at
+    the db level) is silent. Better to at least inform the user that
+    something is amiss.
+    
+    Signed-off-by: Jeff Godin <jgodin at tadl.org>
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+
+3	0	Open-ILS/web/js/ui/default/actor/user/register.js
+
+commit 36595be8ff3bbc71a447611e34447b34f8edd4b3
+Author: Ben Shum <bshum at biblio.org>
+Date:   Mon Apr 7 15:59:17 2014 -0400
+
+    LP#1301955: disable autosuggest by default
+    
+    Until we solve the accessibility issues caused by autosuggest as noted in
+    https://bugs.launchpad.net/evergreen/+bug/1187993, we shall disable the
+    feature by default for new installations.
+    
+    An entry for the release notes is included.
+    
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+    Signed-off-by: Galen Charlton <gmc at esilibrary.com>
+
+1	1	Open-ILS/src/sql/Pg/950.data.seed-values.sql
+13	0	docs/RELEASE_NOTES_NEXT/OPAC/Disable_Autosuggest.txt
+ create mode 100644 docs/RELEASE_NOTES_NEXT/OPAC/Disable_Autosuggest.txt
+
+commit 920631430091bfbb4051caafcbbb9ed54dc70b14
+Author: Kathy Lussier <klussier at masslnc.org>
+Date:   Wed Apr 2 15:18:24 2014 -0400
+
+    LP1301567: New format icons
+    
+    This set adds icons for the new formats that can now be represented due to
+    the recent MVF work. Many thanks to Jim Keenan at C/W MARS for creating
+    many of these icons.
+    
+    The serial.png icon was borrowed from the Koha project and was originally
+    contributed by VOKAL (Vermont Organization of Koha Automated Libraries).
+    
+    Signed-off-by: Kathy Lussier <klussier at masslnc.org>
+    Signed-off-by: Galen Charlton <gmc at esilibrary.com>
+
+-	-	Open-ILS/web/images/format_icons/icon_format/blu-ray.png
+-	-	Open-ILS/web/images/format_icons/icon_format/braille.png
+-	-	Open-ILS/web/images/format_icons/icon_format/casaudiobook.png
+-	-	Open-ILS/web/images/format_icons/icon_format/casmusic.png
+-	-	Open-ILS/web/images/format_icons/icon_format/cassette.png
+-	-	Open-ILS/web/images/format_icons/icon_format/cd.png
+-	-	Open-ILS/web/images/format_icons/icon_format/cdaudiobook.png
+-	-	Open-ILS/web/images/format_icons/icon_format/cdmusic.png
+-	-	Open-ILS/web/images/format_icons/icon_format/dvd.png
+-	-	Open-ILS/web/images/format_icons/icon_format/eaudio.png
+-	-	Open-ILS/web/images/format_icons/icon_format/ebook.png
+-	-	Open-ILS/web/images/format_icons/icon_format/equip.png
+-	-	Open-ILS/web/images/format_icons/icon_format/evideo.png
+-	-	Open-ILS/web/images/format_icons/icon_format/lpbook.png
+-	-	Open-ILS/web/images/format_icons/icon_format/map2.png
+-	-	Open-ILS/web/images/format_icons/icon_format/microform.png
+-	-	Open-ILS/web/images/format_icons/icon_format/phono.png
+-	-	Open-ILS/web/images/format_icons/icon_format/phonomusic.png
+-	-	Open-ILS/web/images/format_icons/icon_format/phonospoken.png
+-	-	Open-ILS/web/images/format_icons/icon_format/score2.png
+-	-	Open-ILS/web/images/format_icons/icon_format/serial.png
+-	-	Open-ILS/web/images/format_icons/icon_format/vhs.png
+41	0	Open-ILS/web/images/licenses.txt
+ create mode 100644 Open-ILS/web/images/format_icons/icon_format/cassette.png
+ create mode 100644 Open-ILS/web/images/format_icons/icon_format/cd.png
+ create mode 100644 Open-ILS/web/images/format_icons/icon_format/map2.png
+ create mode 100644 Open-ILS/web/images/format_icons/icon_format/phono.png
+ create mode 100644 Open-ILS/web/images/format_icons/icon_format/score2.png
+
+commit ee08716d5e5db5da88bd2f2fb764832e9f6a4945
+Author: Bill Erickson <berick at esilibrary.com>
+Date:   Fri Mar 21 21:05:14 2014 -0400
+
+    LP#1115599: Ignore canceled lineitems during batch cancel
+    
+    Continue ignoring already-canceled lineitems during batch cancel so that
+    a) no unnecessary calls are made and b) staff can be alerted when no
+    viable lineitems were selected for the requested action.
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Kathy Lussier <klussier at masslnc.org>
+    Signed-off-by: Galen Charlton <gmc at esilibrary.com>
+
+7	2	Open-ILS/web/js/ui/default/acq/common/li_table.js
+
+commit 834091dcdf59e6011239212a443969550855e027
+Author: Kathy Lussier <klussier at masslnc.org>
+Date:   Wed Jan 29 17:07:29 2014 -0500
+
+    LP#1115599: Allow cancelled lineitems to be received and invoiced
+    
+    Acquisitions staff need to be able to receive and invoice cancelled items,
+    particularly when those items are backordered. This branch restores the
+    ability to perform these actions on cancelled lineitems from the PO
+    screen.
+    
+    Signed-off-by: Kathy Lussier <klussier at masslnc.org>
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Galen Charlton <gmc at esilibrary.com>
+
+1	2	Open-ILS/web/js/ui/default/acq/common/li_table.js
+
+commit 0a762feebd9ddb45584182ea438bd6693e524cdf
+Author: Lebbeous Fogle-Weekley <lebbeous at esilibrary.com>
+Date:   Thu Feb 20 12:21:57 2014 -0500
+
+    LP#1282704: Serials: in routing lists, avoid extra page breaks wasting paper at print time
+    
+    If you're using batch receive, and you have two copies (and therefore
+    two streams) that you're receiving with the Routing List? checkbox
+    checked, but only one of those streams actually has a routing list,
+    you'll note before this patch is applied that you get an extra page of
+    blank paper if you print the routing list that pops up.
+    
+    This fixes that.
+    
+    Signed-off-by: Lebbeous Fogle-Weekley <lebbeous at esilibrary.com>
+    Signed-off-by: Galen Charlton <gmc at esilibrary.com>
+
+4	1	Open-ILS/web/js/ui/default/serial/print_routing_list_users.js
+
+commit 149ffb312303594a4667e09abca5c670dd2de954
+Author: Galen Charlton <gmc at esilibrary.com>
+Date:   Tue Apr 8 14:15:11 2014 -0700
+
+    LP#1303940: pin schema upgrade to 0878
+    
+    Signed-off-by: Galen Charlton <gmc at esilibrary.com>
+
+1	1	Open-ILS/src/sql/Pg/002.schema.config.sql
+107	0	Open-ILS/src/sql/Pg/upgrade/0878.schema.browse-ingest-null-protect.sql
+0	107	Open-ILS/src/sql/Pg/upgrade/XXXX.schema.browse-ingest-null-protect.sql
+ create mode 100644 Open-ILS/src/sql/Pg/upgrade/0878.schema.browse-ingest-null-protect.sql
+ delete mode 100644 Open-ILS/src/sql/Pg/upgrade/XXXX.schema.browse-ingest-null-protect.sql
+
+commit 9984b11f6766106f6d8c5b2e05331f9cf2dbf571
+Author: Galen Charlton <gmc at esilibrary.com>
+Date:   Tue Apr 8 14:09:46 2014 -0700
+
+    LP#1303940: don't attempt to store NULL values in keyword, browse, or facet indexes
+    
+    This patch implements a suggestion by Dan Wells and builds on Mike
+    Rylander's patch to skip inserting into field_entry and facet
+    indexes values that have been normalized to NULL.  As a side effect,
+    the following warning will no longer be logged when attempting
+    to store such values in the facet index:
+    
+    WARNING:  Use of uninitialized value in subroutine entry at /usr/lib/perl/5.18/Unicode/Normalize.pm line 80.
+    CONTEXT:  PL/Perl function "force_unicode_normal_form"
+    
+    Signed-off-by: Galen Charlton <gmc at esilibrary.com>
+
+5	1	Open-ILS/src/sql/Pg/030.schema.metabib.sql
+5	1	Open-ILS/src/sql/Pg/upgrade/XXXX.schema.browse-ingest-null-protect.sql
+
+commit c964cd4ce0fc97db9b726d6ada4902f6388c255e
+Author: Mike Rylander <mrylander at gmail.com>
+Date:   Mon Apr 7 14:03:51 2014 -0400
+
+    LP#1303940: Protect against bogus data that can breaking indexing
+    
+    In at least the case of browse indexing, some MARC contents can
+    cause us problems when normalization (such as stripping all
+    punctuation) can leave us with a NULL value for index-intended
+    data. The patch avoids the specific case of browse data being null
+    and causing an ingest failure.
+    
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+    Jason Stephenson <jstephenson at mvlc.org>
+    Signed-off-by: Galen Charlton <gmc at esilibrary.com>
+
+2	0	Open-ILS/src/sql/Pg/030.schema.metabib.sql
+103	0	Open-ILS/src/sql/Pg/upgrade/XXXX.schema.browse-ingest-null-protect.sql
+ create mode 100644 Open-ILS/src/sql/Pg/upgrade/XXXX.schema.browse-ingest-null-protect.sql
+
+commit 1764ceb2f02eed93baa7128cf048f3302afe5f16
+Author: Galen Charlton <gmc at esilibrary.com>
+Date:   Tue Apr 8 13:38:50 2014 -0700
+
+    LP#1303940: improve readability of test case
+    
+    This patch adds some whitespace and a comment in the MARCXML
+    to clarify the sort of data that triggers the bug.
+    
+    Signed-off-by: Galen Charlton <gmc at esilibrary.com>
+
+17	1	Open-ILS/src/sql/Pg/t/regress/lp1303940-browse-hates-null.pg
+
+commit 16eec856033ee3f3b7f5b4c73068e52a575be3c2
+Author: Jason Stephenson <jstephenson at mvlc.org>
+Date:   Mon Apr 7 15:41:02 2014 -0400
+
+    LP 1303940: pg_tap regression test.
+    
+    Add a pg_tap test to insert a record that should trigger the problem
+    fixed by LP 1303940. If the test fails, we have a regression.
+    
+    Signed-off-by: Jason Stephenson <jstephenson at mvlc.org>
+    Signed-off-by: Galen Charlton <gmc at esilibrary.com>
+
+11	0	Open-ILS/src/sql/Pg/t/regress/lp1303940-browse-hates-null.pg
+ create mode 100644 Open-ILS/src/sql/Pg/t/regress/lp1303940-browse-hates-null.pg
+
+commit f23274d750213f8d9332ee5edc443f70b432b1de
+Author: Dan Wells <dbw2 at calvin.edu>
+Date:   Wed Apr 2 14:31:24 2014 -0400
+
+    Simple typo fix in docs
+    
+    Credit for spotting this to Erica Rohlfs.
+    
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+1	1	docs/RELEASE_NOTES_NEXT/OPAC/TPAC_metarecords.txt
+
+commit 4d40cf71a7aed9551a770dccc33ec26e6f91210c
+Author: Benjamin <benjamin.wiens at gmail.com>
+Date:   Mon Mar 31 16:37:06 2014 -0400
+
+    LP#1300267 Documentation: Reset Staff Client Password (e.g. Admin)
+    
+    Signed-off-by: Benjamin <benjamin.wiens at gmail.com>
+    Signed-off-by: Yamil Suarez <yamil at yamil.com>
+
+11	3	docs/circulation/circulation_patron_records.txt
+
+commit 2760e95d2658fb4594f35b78e6b559f987e51a63
+Author: Benjamin <benjamin.wiens at gmail.com>
+Date:   Mon Mar 31 16:29:11 2014 -0400
+
+    LP#1300267 Documentation: Reset Staff Client Password (e.g. Admin)
+    
+    Signed-off-by: Benjamin <benjamin.wiens at gmail.com>
+    Signed-off-by: Yamil Suarez <yamil at yamil.com>
+
+17	0	docs/circulation/circulation_patron_records.txt
+
+commit c3c8b74d5169ef31d9801054ddd66f0320e6591b
+Author: Dan Wells <dbw2 at calvin.edu>
+Date:   Mon Mar 31 15:59:25 2014 -0400
+
+    Remove unwanted index recreation
+    
+    After some discussion, it was noted that this index was formally
+    dropped eons ago.  The fact we are re-dropping it in this upgrade
+    is just a precaution, so there is no need to try to recreate it.
+    
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+0	6	Open-ILS/src/sql/Pg/upgrade/0875.schema.authority.in-line-headings.sql
+
+commit 7d8628dfa3432ed005c0a07b3ffddf41833c68d4
+Author: Dan Wells <dbw2 at calvin.edu>
+Date:   Mon Mar 31 13:43:29 2014 -0400
+
+    Translation updates - newpot
+    
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+2378	2304	build/i18n/po/db.seed/db.seed.pot
+83	66	build/i18n/po/tpac/tpac.pot
+
+commit d9bfd83ced4a5723c74ef2000d7b47b7f84541cd
+Author: Dan Wells <dbw2 at calvin.edu>
+Date:   Mon Mar 31 13:33:30 2014 -0400
+
+    Translation updates - po files
+    
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+14	14	build/i18n/po/AutoFieldWidget.js/en-GB.po
+6	6	build/i18n/po/cat.properties/en-GB.po
+10	10	build/i18n/po/circ.properties/en-GB.po
+6	6	build/i18n/po/common.properties/en-GB.po
+1845	1492	build/i18n/po/db.seed/cs-CZ.po
+1490	1288	build/i18n/po/db.seed/de-DE.po
+1496	1291	build/i18n/po/db.seed/en-CA.po
+1496	1291	build/i18n/po/db.seed/en-GB.po
+1492	1290	build/i18n/po/db.seed/es-ES.po
+1503	1298	build/i18n/po/db.seed/fr-CA.po
+1503	1300	build/i18n/po/db.seed/hy-AM.po
+1490	1288	build/i18n/po/db.seed/oc-FR.po
+1496	1294	build/i18n/po/db.seed/pt-BR.po
+1495	1293	build/i18n/po/db.seed/ru-RU.po
+1487	1285	build/i18n/po/db.seed/tr-TR.po
+2563	2507	build/i18n/po/fm_IDL.dtd/cs-CZ.po
+2557	2501	build/i18n/po/fm_IDL.dtd/de-DE.po
+2561	2505	build/i18n/po/fm_IDL.dtd/en-CA.po
+2560	2504	build/i18n/po/fm_IDL.dtd/en-GB.po
+2559	2503	build/i18n/po/fm_IDL.dtd/es-ES.po
+2556	2500	build/i18n/po/fm_IDL.dtd/fr-CA.po
+2561	2505	build/i18n/po/fm_IDL.dtd/hy-AM.po
+2556	2500	build/i18n/po/fm_IDL.dtd/oc-FR.po
+2560	2504	build/i18n/po/fm_IDL.dtd/pt-BR.po
+2560	2504	build/i18n/po/fm_IDL.dtd/ru-RU.po
+2556	2500	build/i18n/po/fm_IDL.dtd/tr-TR.po
+9	6	build/i18n/po/ils_events.xml/en-GB.po
+11	4	build/i18n/po/lang.dtd/ar-AR.po
+20	7	build/i18n/po/lang.dtd/cs-CZ.po
+11	4	build/i18n/po/lang.dtd/de-DE.po
+19	6	build/i18n/po/lang.dtd/en-CA.po
+19	6	build/i18n/po/lang.dtd/en-GB.po
+30	23	build/i18n/po/lang.dtd/es-ES.po
+19	6	build/i18n/po/lang.dtd/fr-CA.po
+19	6	build/i18n/po/lang.dtd/hy-AM.po
+11	4	build/i18n/po/lang.dtd/oc-FR.po
+19	6	build/i18n/po/lang.dtd/pt-BR.po
+19	6	build/i18n/po/lang.dtd/ru-RU.po
+11	4	build/i18n/po/lang.dtd/tr-TR.po
+5	5	build/i18n/po/offline.properties/en-GB.po
+4	4	build/i18n/po/opac.dtd/cs-CZ.po
+12	12	build/i18n/po/patron.properties/en-GB.po
+21	17	build/i18n/po/register.js/cs-CZ.po
+19	15	build/i18n/po/register.js/de-DE.po
+20	16	build/i18n/po/register.js/en-CA.po
+24	20	build/i18n/po/register.js/en-GB.po
+20	16	build/i18n/po/register.js/es-ES.po
+20	16	build/i18n/po/register.js/fr-CA.po
+20	16	build/i18n/po/register.js/hy-AM.po
+20	16	build/i18n/po/register.js/oc-FR.po
+20	16	build/i18n/po/register.js/pt-BR.po
+19	15	build/i18n/po/register.js/ru-RU.po
+20	16	build/i18n/po/register.js/tr-TR.po
+26	12	build/i18n/po/reports.dtd/cs-CZ.po
+8	8	build/i18n/po/reports.dtd/de-DE.po
+21	11	build/i18n/po/reports.dtd/en-CA.po
+27	13	build/i18n/po/reports.dtd/en-GB.po
+21	11	build/i18n/po/reports.dtd/es-ES.po
+20	13	build/i18n/po/reports.dtd/fr-CA.po
+21	11	build/i18n/po/reports.dtd/hy-AM.po
+21	14	build/i18n/po/reports.dtd/pt-BR.po
+21	11	build/i18n/po/reports.dtd/ru-RU.po
+8	8	build/i18n/po/reports.dtd/tr-TR.po
+13	13	build/i18n/po/selfcheck.js/en-GB.po
+7	7	build/i18n/po/serial.properties/en-GB.po
+
+commit f92e1ff3c646f0fd300efb935ae11ca1593ab6c1
+Author: Ben Shum <bshum at biblio.org>
+Date:   Fri Mar 28 16:53:39 2014 -0400
+
+    LP#1259665 Stamping upgrade for 800t search and facets
+    
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+
+1	1	Open-ILS/src/sql/Pg/002.schema.config.sql
+25	0	Open-ILS/src/sql/Pg/upgrade/0877.data.re-add_800_t_search_and_facets.sql
+0	25	Open-ILS/src/sql/Pg/upgrade/XXXX.data.re-add_800_t_search_and_facets.sql
+ create mode 100644 Open-ILS/src/sql/Pg/upgrade/0877.data.re-add_800_t_search_and_facets.sql
+ delete mode 100644 Open-ILS/src/sql/Pg/upgrade/XXXX.data.re-add_800_t_search_and_facets.sql
+
+commit ca359decc05131f82a7ebd4146c4acb68b7c4010
+Author: Dan Wells <dbw2 at calvin.edu>
+Date:   Thu Mar 27 14:19:34 2014 -0400
+
+    LP#1259665 Split series browse config from search
+    
+    When we added browse support in 2.5, we took extra care to ensure that
+    our series browse entries would sort and display reliably.
+    
+    800t does not specify non-filing characters, so it was excluded from
+    browse.  Unfortunately, since browse and search had a single root
+    config, this removed 800t from search as well.
+    
+    While we may want to reconsider expanding later on, this commit takes
+    a conservative approach, and uses all series values for search and
+    facets, but only entries with a usable filing indicator will be
+    extracted for browse.  It accomplishes this by splitting the series
+    config in two, one config for search/faceting, and a second config
+    dedicated to browse (similar to what was done for title).
+    
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+
+4	2	Open-ILS/src/sql/Pg/950.data.seed-values.sql
+25	0	Open-ILS/src/sql/Pg/upgrade/XXXX.data.re-add_800_t_search_and_facets.sql
+ create mode 100644 Open-ILS/src/sql/Pg/upgrade/XXXX.data.re-add_800_t_search_and_facets.sql
+
+commit ab20899685ce2660424ad732bbeceb87b4a18f29
+Author: Yamil Suarez <yamil at yamil.com>
+Date:   Fri Mar 28 11:45:11 2014 -0400
+
+    Documentation: Changed return type of staging_importer() SP
+    
+    Now it returns VOID, before it retunred NULL and gave an error
+
+1	1	docs/admin_initial_setup/migrating_your_data.txt
+
+commit 2d2e504c633ed30557324acf5ecff7971e68d581
+Author: Jason Stephenson <jstephenson at mvlc.org>
+Date:   Tue Mar 25 13:59:55 2014 -0400
+
+    LP1297435: Make 0872 upgrade require less hand holding.
+    
+    Add a count() around the metabib.remap_metarecord_for_bib call in the
+    final select statement.  This allows the script to run without the
+    user having to scroll through rows of output.
+    
+    Signed-off-by: Jason Stephenson <jstephenson at mvlc.org>
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+
+1	1	Open-ILS/src/sql/Pg/upgrade/0872.functions.metarecord-deleted-constituents.sql
+
+commit 988605ececad7850f2a7276b64a697b6b5c9ae31
+Author: Dan Wells <dbw2 at calvin.edu>
+Date:   Fri Mar 21 22:44:42 2014 -0400
+
+    LP#1290496: The quest for knowledge is over
+    
+    An apparently bad query plan causes Z39.50 searches of local
+    catalog to take an extremely long time to complete.  One theory
+    is that metabib.rec_descriptor is the culprit, but that has not
+    been verified.
+    
+    This commit works around the immediate problem, but will need to
+    be revisited.  Some questions include:
+    
+    1) Should we rewrite parts of open-ils.search.biblio.multiclass
+    (and the underlying storage methods) to use the new attr structures
+    more directly, rather than through a view of a view?
+    
+    2) Alternately, should we rip it out?  If so, we will need to also
+    remove/nullify the "use_staged_search" option, since there will be
+    no functional non-staged offering.
+    
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+    Signed-off-by: Jason Stephenson <jstephenson at mvlc.org>
+
+1	1	Open-ILS/src/perlmods/lib/OpenILS/Application/Search/Biblio.pm
+
+commit 5c364369b66ee41644dcc0b10b5dbf2695448faa
+Author: Remington Steed <rjs7 at calvin.edu>
+Date:   Tue Mar 25 09:30:38 2014 -0400
+
+    Change xref syntax to avoid docs processing bug
+    
+    The current Documentation processing script can't handle the newer xref
+    syntax for cross references. Let's use the older syntax for now, and
+    consider changing over in the future, after the processing bug is fixed.
+    
+    Signed-off-by: Remington Steed <rjs7 at calvin.edu>
+
+2	2	docs/admin/staff_client-button_bar_toolbar.txt
+
+commit 18815ea422392e43683f182b235ac61f81307cb3
+Author: Remington Steed <rjs7 at calvin.edu>
+Date:   Thu Mar 20 15:52:30 2014 -0400
+
+    Docs: Revive/merge content into "Using the Staff Client"
+    
+    This commit brings in three old sections and merges with any similar
+    content.
+    
+    - Revive old section about sticky check box settings
+    - Merge old section about Font and Sound settings
+    
+      Adds a brief section about zooming in the OPAC, and otherwise only
+      reformats some lines to make them git-friendly.
+    
+    - Docs: Fix and copy Customize Toolbars section
+    
+      The old "Customizable Toolbar" docs section is already revived in the
+      Evergreen Book "System Configuration and Customization" chapter. Since
+      this feature seems to belong under "Using the Staff Client ->
+      Workstation Administration", this commit duplicates it into that
+      chapter. This also fixes a few asciidoc bugs in both places. And it
+      fixes one bug in root.txt which caused "phonelist.txt" to be mentioned
+      at the bottom of this section, but not actually included in the docs
+      structure.
+    
+      In addition, the section "Button Bar/Toolbar" that was also under
+      "Workstation Administration" has been moved up a level, since it
+      pertains more to staff client users rather than admins. And the
+      admin-specific content at the end of that section has been replaced
+      with a link to the newly duplicated "Customizable Toolbar" section.
+    
+      The result of this reorganization should be:
+    
+      - Using the Staff Client
+        - Button Bar/Toolbar (for staff client users)
+        - Workstation Administration
+          - Customizable Toolbar (for staff client admins)
+    
+    Signed-off-by: Remington Steed <rjs7 at calvin.edu>
+
+15	14	docs/admin/customize_staff_client.txt
+36	0	docs/admin/staff_client-button_bar_toolbar.txt
+17	0	docs/admin/staff_client-sticky_settings.txt
+77	54	docs/admin/workstation_admin.txt
+-	-	docs/media/staff_client-3.png
+-	-	docs/media/staff_client-4.png
+11	1	docs/root.txt
+ create mode 100644 docs/admin/staff_client-button_bar_toolbar.txt
+ create mode 100644 docs/admin/staff_client-sticky_settings.txt
+ create mode 100644 docs/media/staff_client-3.png
+ create mode 100644 docs/media/staff_client-4.png
+
+commit f0b6585d367484fe2f8af0a93f28aa564c6788db
+Author: Remington Steed <rjs7 at calvin.edu>
+Date:   Thu Mar 20 14:53:00 2014 -0400
+
+    Docs: Revive old section about Column Picker
+    
+    Signed-off-by: Remington Steed <rjs7 at calvin.edu>
+
+29	0	docs/admin/staff_client-column_picker.txt
+-	-	docs/media/column_picker_dojo.png
+-	-	docs/media/column_picker_xul.png
+-	-	docs/media/column_picker_xul_save.png
+2	0	docs/root.txt
+ create mode 100644 docs/admin/staff_client-column_picker.txt
+ create mode 100644 docs/media/column_picker_dojo.png
+ create mode 100644 docs/media/column_picker_xul.png
+ create mode 100644 docs/media/column_picker_xul_save.png
+
+commit 6b106f78729b14df6171cb1bc3afdd56be76b349
+Author: Remington Steed <rjs7 at calvin.edu>
+Date:   Thu Mar 20 10:53:36 2014 -0400
+
+    Add missing screenshot files for new 2.5 Acq import feature
+    
+    Signed-off-by: Remington Steed <rjs7 at calvin.edu>
+
+-	-	docs/media/marc_batch_import_acq_overlay.png
+-	-	docs/media/marc_batch_import_popup.png
+ create mode 100644 docs/media/marc_batch_import_acq_overlay.png
+ create mode 100644 docs/media/marc_batch_import_popup.png
+
+commit 028bde53833a7cca0e5dca483f03f4bb6d49495b
+Author: Remington Steed <rjs7 at calvin.edu>
+Date:   Wed Mar 19 15:56:44 2014 -0400
+
+    Docs: Reformat numbered lists into AsciiDoc syntax
+    
+    This commit improves list formatting in the Batch Importing section by
+    converting various hard-coded numbered lists into AsciiDoc syntax. Where
+    images are included, those are forced to be inline by adding a '+' to the
+    preceeding line. And whitespace was removed from the end of two lines. No
+    other changes are included.
+    
+    Signed-off-by: Remington Steed <rjs7 at calvin.edu>
+
+48	52	docs/cataloging/batch_importing_MARC.txt
+
+commit b70e768abe78289675e5967032644751eb5ee15a
+Author: Remington Steed <rjs7 at calvin.edu>
+Date:   Mon Jan 13 09:44:55 2014 -0500
+
+    Document new 2.5 feature in Acq docs
+    
+    This commit adds documentation in two places for the new Acq feature
+    "Opportunistic Acquisitions In-Process Copy Overlay". First, a short
+    note is added to the "Load MARC Order Records" doc. Second, the feature
+    is described more thoroughly in the "Batch Importing MARC Records" doc.
+    Also, this commit cleans up a hard-coded ordered list and a few small
+    wording and formatting problems.
+    
+    Signed-off-by: Remington Steed <rjs7 at calvin.edu>
+
+7	6	docs/acquisitions/vandelay_acquisitions_integration.txt
+36	30	docs/cataloging/batch_importing_MARC.txt
+
+commit ade704b8a9bb64132fea036bc80a8a0ea920ee55
+Author: Ben Shum <bshum at biblio.org>
+Date:   Wed Mar 19 10:13:06 2014 -0400
+
+    LP#1230557 Stamping upgrade script for perm_list_group_admin
+    
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+
+1	1	Open-ILS/src/sql/Pg/002.schema.config.sql
+18	0	Open-ILS/src/sql/Pg/upgrade/0876.data.perm_list_group_system_admin.sql
+0	18	Open-ILS/src/sql/Pg/upgrade/XXXX.data.perm_list_group_system_admin.sql
+ create mode 100644 Open-ILS/src/sql/Pg/upgrade/0876.data.perm_list_group_system_admin.sql
+ delete mode 100644 Open-ILS/src/sql/Pg/upgrade/XXXX.data.perm_list_group_system_admin.sql
+
+commit a58a18d77fae346988ae46992622356a45d3d93b
+Author: Mark Cooper <markchristophercooper at gmail.com>
+Date:   Wed Sep 25 10:06:48 2013 -0700
+
+    LP#1230557 Adding more groups to perm_list
+    
+    By default some of the perm groups do not have their
+    application_perm in the perm_list. This adds them.
+    
+    Signed-off-by: Mark Cooper <markchristophercooper at gmail.com>
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+    
+    Conflicts:
+    	Open-ILS/src/sql/Pg/950.data.seed-values.sql
+
+11	1	Open-ILS/src/sql/Pg/950.data.seed-values.sql
+18	0	Open-ILS/src/sql/Pg/upgrade/XXXX.data.perm_list_group_system_admin.sql
+ create mode 100644 Open-ILS/src/sql/Pg/upgrade/XXXX.data.perm_list_group_system_admin.sql
+
+commit 6f098024da7d79fd950c096a3f8eeecb6226d3fd
+Author: Jason Etheridge <jason at esilibrary.com>
+Date:   Fri Nov 8 14:12:43 2013 -0500
+
+    remove XUL @persist from list column definitions
+    
+    We moved away from @persist a long time ago, but some cruft remained.  This
+    would cause a local file, localstore.rdf, to balloon in size as columns were
+    adjusted in XUL-based lists.  Since this is an XML file, writing and parsing
+    it can get very expensive if the file grows too large, which it has done for
+    some people.
+    
+    This change keeps that file from growing further based on these list columns,
+    but it may be worth deleting the localstore.rdf file or creating a new staff
+    client profile (uninstalling and reinstalling the staff client DOES NOT
+    accomplish this).
+    
+    Signed-off-by: Jason Etheridge <jason at esilibrary.com>
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+
+1	1	Open-ILS/xul/staff_client/server/cat/copy_summary.xul
+24	163	Open-ILS/xul/staff_client/server/circ/util.js
+76	76	Open-ILS/xul/staff_client/server/patron/util.js
+10	28	Open-ILS/xul/staff_client/server/serial/manage_items.js
+
+commit 4ffa6220773038b7c8956612479b074e3803b56d
+Author: Ben Shum <bshum at biblio.org>
+Date:   Tue Mar 18 22:44:56 2014 -0400
+
+    LP#1253163: stamping upgrade for authority.in-line-headings
+    
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+
+1	1	Open-ILS/src/sql/Pg/002.schema.config.sql
+56	0	Open-ILS/src/sql/Pg/upgrade/0875.schema.authority.in-line-headings.sql
+0	56	Open-ILS/src/sql/Pg/upgrade/XXXX.schema.authority.in-line-headings.sql
+ create mode 100644 Open-ILS/src/sql/Pg/upgrade/0875.schema.authority.in-line-headings.sql
+ delete mode 100644 Open-ILS/src/sql/Pg/upgrade/XXXX.schema.authority.in-line-headings.sql
+
+commit fa417ff21862e05cbf12d98e45acc919c5755596
+Author: Dan Wells <dbw2 at calvin.edu>
+Date:   Mon Mar 17 16:47:55 2014 -0400
+
+    LP#1253163: Replace dropped unique index, if we can
+    
+    Not sure if this is necessary, but since we drop this index, we might
+    want to make an effort to recreate it if we can (but don't die if we
+    cannot).
+    
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+
+6	0	Open-ILS/src/sql/Pg/upgrade/XXXX.schema.authority.in-line-headings.sql
+
+commit 3f0411f5968a17bfe87ad4203f6d8760e9cd68fd
+Author: Dan Wells <dbw2 at calvin.edu>
+Date:   Mon Mar 17 13:03:49 2014 -0400
+
+    LP#1253163: Make authority functions more truthful
+    
+    One discovery we made on this bug was that PG can break if we
+    conveniently label functions as IMMUTABLE when they are now.  Let's
+    go ahead and reclass some authority functions as STABLE STRICT to
+    better fit reality.
+    
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+
+4	4	Open-ILS/src/sql/Pg/011.schema.authority.sql
+6	1	Open-ILS/src/sql/Pg/upgrade/XXXX.schema.authority.in-line-headings.sql
+
+commit cccf8938f544d82a47b6df5c8c918a53e1aff728
+Author: Mike Rylander <mrylander at gmail.com>
+Date:   Fri Feb 28 16:45:40 2014 -0500
+
+    LP#1253163: Materialize authority headings
+    
+    There seems to be a bug in Postgres 9.3+ that does not like the
+    circuitous route we take to indexing authority headings.  So, we
+    get around this by storing the actual heading values instead of
+    indexing a function over the MARC.
+    
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+
+3	4	Open-ILS/src/perlmods/lib/OpenILS/Application/Search/Authority.pm
+1	0	Open-ILS/src/sql/Pg/000.english.pg93.fts-config.sql
+16	3	Open-ILS/src/sql/Pg/011.schema.authority.sql
+2	2	Open-ILS/src/sql/Pg/800.fkeys.sql
+45	0	Open-ILS/src/sql/Pg/upgrade/XXXX.schema.authority.in-line-headings.sql
+ create mode 120000 Open-ILS/src/sql/Pg/000.english.pg93.fts-config.sql
+ create mode 100644 Open-ILS/src/sql/Pg/upgrade/XXXX.schema.authority.in-line-headings.sql
+
+commit 7e488141a61b30f431a6cf551922aaa2863bc77d
+Author: Ben Shum <bshum at biblio.org>
+Date:   Tue Mar 18 21:39:10 2014 -0400
+
+    LP#1243023: Stamping upgrade script for oils_expath-tweaks
+    
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+
+1	1	Open-ILS/src/sql/Pg/002.schema.config.sql
+611	0	Open-ILS/src/sql/Pg/upgrade/0874.function.oils_xpath-tweaks-for-newer-pg.sql
+0	611	Open-ILS/src/sql/Pg/upgrade/XXXX.function.oils_xpath-tweaks-for-newer-pg.sql
+ create mode 100644 Open-ILS/src/sql/Pg/upgrade/0874.function.oils_xpath-tweaks-for-newer-pg.sql
+ delete mode 100644 Open-ILS/src/sql/Pg/upgrade/XXXX.function.oils_xpath-tweaks-for-newer-pg.sql
+
+commit 8e5dc73ba37421898f3d5d8bfa0e35b74715d8de
+Author: Dan Wells <dbw2 at calvin.edu>
+Date:   Tue Mar 18 21:15:25 2014 -0400
+
+    LP#1243023: Add optional quick reingest to upgrade script
+    
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+
+8	0	Open-ILS/src/sql/Pg/upgrade/XXXX.function.oils_xpath-tweaks-for-newer-pg.sql
+
+commit 624e0dc7066033051b5715afe7dbf1e3fbb88749
+Author: Dan Wells <dbw2 at calvin.edu>
+Date:   Mon Mar 10 17:02:33 2014 -0400
+
+    LP#1243023 Add upgrade script and pgTAP test
+    
+    For fixes to XPATH extraction encoding.
+    
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+    Signed-off-by: Remington Steed <rjs7 at calvin.edu>
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+
+10	0	Open-ILS/src/sql/Pg/t/regress/lp1243023_decoded_xpath_extracts.pg
+603	0	Open-ILS/src/sql/Pg/upgrade/XXXX.function.oils_xpath-tweaks-for-newer-pg.sql
+ create mode 100644 Open-ILS/src/sql/Pg/t/regress/lp1243023_decoded_xpath_extracts.pg
+ create mode 100644 Open-ILS/src/sql/Pg/upgrade/XXXX.function.oils_xpath-tweaks-for-newer-pg.sql
+
+commit cdb49401755d803d51b863de06d1df08345342c4
+Author: Mike Rylander <mrylander at gmail.com>
+Date:   Mon Mar 3 14:34:30 2014 -0500
+
+    LP#1243023: Clean up string handling variable types
+    
+    Similar to the previous commit, this was really TEXT, no need to flip
+    back and forth between that and XML.
+    
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+
+6	21	Open-ILS/src/sql/Pg/030.schema.metabib.sql
+
+commit a3a81ab4f00db4207f559cf309a59d2b30cac3ec
+Author: Mike Rylander <mrylander at gmail.com>
+Date:   Mon Mar 3 14:28:13 2014 -0500
+
+    LP#1243023: Make sure URLs are not broken
+    
+    We need to make sure that the URLs we extract contain decoded Famous Five
+    characters, not entities.
+    
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+
+3	3	Open-ILS/src/sql/Pg/076.functions.url_verify.sql
+
+commit d3987e2030981ea8882a6d688f81e4eb7be3397b
+Author: Mike Rylander <mrylander at gmail.com>
+Date:   Mon Mar 3 14:26:46 2014 -0500
+
+    LP#1243023: Clean up string handling variable types
+    
+    It was already TEXT, no need to flip back and forth between that
+    and XML.
+    
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+
+2	2	Open-ILS/src/sql/Pg/011.schema.authority.sql
+
+commit 6d079ea592f5982225689ec6abce9e602eff7b10
+Author: Mike Rylander <mrylander at gmail.com>
+Date:   Mon Mar 3 14:07:42 2014 -0500
+
+    LP#1243023: Teach oils_xpath() to decode specific enties in text nodes
+    
+    Because of a behavioral change in Postgres' XML code (specifically, when
+    casting XML as TEXT, the Famous Five XML entities are not decoded), we
+    are seeing doubled encodings in XML and HTML output, as well as in indexed
+    data.  To combat this, we will now check the first character of each
+    array element returned by XPATH() and, if it is not '<', we will decode
+    the entities ourselves.
+    
+    Also included in this commit is some cleanup of the surrounding file
+    content, which was just confusing and useless in the modern era.
+    
+    The contents of his commit, followed by:
+    
+     =# drop function evergreen.oils_xpath(text,text,anyarray)
+    
+    are enough to address the OP's complaint about browse data.
+    
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+
+45	179	Open-ILS/src/sql/Pg/002.functions.config.sql
+
+commit d59d8f95af806bf218f3c45fc558a582a91393da
+Author: Bill Erickson <berick at esilibrary.com>
+Date:   Mon Mar 17 11:53:22 2014 -0400
+
+    LP#1294156 TPAC activate hold Submit on load w/ barcode
+    
+    Repairs an error introduced by b055fe4, where the Submit button was left
+    inactive on initial page load, even when a valid barcode was already
+    set.
+    
+    Overall, this change paritally rolls back b055fe4 to simplify the
+    implementation.
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+
+9	9	Open-ILS/web/js/ui/default/opac/staff.js
+
+commit 7c3b2dae0b1fca098c4804f52cadf406c29fd458
+Author: Bill Erickson <berick at esilibrary.com>
+Date:   Thu Mar 13 10:27:13 2014 -0400
+
+    LP#1287967 upgrade notes re: removing reporter view
+    
+    ...and it's reinstallation requirements.
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+
+9	0	docs/RELEASE_NOTES_NEXT/OPAC/Composite_Record_Attributes.txt
+
+commit 356b8262679babe942fcea96c9e628058fc48c9b
+Author: Ben Shum <bshum at biblio.org>
+Date:   Thu Mar 6 17:46:30 2014 -0500
+
+    LP1287967 - drop reporter.classic_current_circ view as part of 0864 upgrade
+    
+    As noted in the bug description, attempts to run 0864.MVF_CRA-upgrade.sql will
+    fail on a database where the reporter.classic_current_circ view is present.
+    
+    Add a DROP VIEW IF EXISTS and then include a note that administrators will need
+    to recreate the VIEW afterwards if desired.
+    
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+
+4	0	Open-ILS/src/sql/Pg/upgrade/0864.MVF_CRA-upgrade.sql
+
+commit befdd0b7c9703ff94ee3f3f74aae4d1fd42e4469
+Author: Dan Scott <dscott at laurentian.ca>
+Date:   Sat Mar 15 08:54:39 2014 -0400
+
+    Fix XML comment breakage in opensrf.xml.example
+    
+    Per http://www.w3.org/TR/REC-xml/#sec-comments, 'For compatibility, the string
+    " -- " (double-hyphen) MUST NOT occur within comments.'
+    
+    XML parsers that cared about specs choked on our --localhost reference.
+    
+    Signed-off-by: Dan Scott <dscott at laurentian.ca>
+
+1	1	Open-ILS/examples/opensrf.xml.example
+
+commit 5e4d60cacabafccb0c1c11ccb4565f8d5251df7e
+Author: Galen Charlton <gmc at esilibrary.com>
+Date:   Fri Feb 28 10:06:40 2014 -0800
+
+    LP#1286248: remove references to osrf_ctl.sh
+    
+    This patch replaces references to osrf_ctl.sh, which is deprecated
+    as of OpenSRF 2.3.0, with opensrf_control.  It also names
+    2.3.0 as the minimum required version of OpenSRF.
+    
+    brick_ctl.sh gets the most changes as a consequence.  In particular:
+    
+    * the stop_{c,perl}/[re]start_{c,perl} actions are removed, as
+      osrf_control behaves exactly the same when stopping or starting
+      services.
+    * the -s option for working with a single service is now documented,
+      and is restricted to the stop_osrf/[re]start_osrf actions
+    
+    It should be noted that for brick-based setups (and other kinds of
+    multi-server setups) better control can be had by using opensrf_control
+    directly.
+    
+    Signed-off-by: Galen Charlton <gmc at esilibrary.com>
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+1	1	Open-ILS/examples/opensrf.xml.example
+24	28	Open-ILS/src/support-scripts/brick_ctl.sh
+2	2	build/tools/update.sh
+2	2	docs/installation/server_upgrade.txt
+2	8	docs/reports/reporter_add_data_source.txt
+
+commit 10e245f7f8170990977cc8de48d1955719c440ae
+Author: Remington Steed <rjs7 at calvin.edu>
+Date:   Wed Mar 5 17:57:24 2014 -0500
+
+    LP1198983: Remove deprecated useragent.override variable
+    
+    To quote Dan Wells in bug comment #6:
+    
+    Back in the 2.2 days, Evergreen had code which set the
+    'general.useragent.override' to something like 'Mozilla/5.0 (Windows; U;
+    Windows NT 6.1; en-US; rv:1.9.2.25) Gecko/20111212 oils_xulrunner
+    /xul/rel_2_2_0/server/'. For anyone who once had a 2.2 client installed
+    and upgraded from it, this setting persists (this is the situation for
+    most stations in our library).
+    
+    Since this string does not match the new test for 'open_ils_staff_client'
+    in the useragent, these clients are not properly streaming requests. This
+    problem was most easily noticed in Vandelay progress bars (they always
+    jumped from 0% to 100%).
+    
+    This commit adds the code provided by Bill Erickson in the LP bug
+    comments. To test it, you can add the 'general.useragent.override'
+    setting to your staff client with any value (using the 'about:config'
+    interface), then run this code and check that your setting is gone.
+    
+    Signed-off-by: Remington Steed <rjs7 at calvin.edu>
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+14	0	Open-ILS/xul/staff_client/chrome/content/OpenILS/data.js
+
+commit 291bce0dee74ae7f2dd70abe1af73a27c2b0d438
+Author: Bill Erickson <berick at esilibrary.com>
+Date:   Tue Feb 18 14:38:07 2014 -0500
+
+    LP#1281750 Ignore deleted users in usrgroup info APIs
+    
+    Ignore deleted users in these API calls:
+    
+    open-ils.actor.usergroup.members.balance_owed
+    open-ils.actor.usergroup.members.retrieve
+    open-ils.actor.usergroup.leaders.retrieve
+    open-ils.actor.address.members
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Remington Steed <rjs7 at calvin.edu>
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+10	5	Open-ILS/src/perlmods/lib/OpenILS/Application/Actor/UserGroups.pm
+
+commit 9ce26cc38dfcd10be1faccca6236da881e5ee7eb
+Author: Dan Wells <dbw2 at calvin.edu>
+Date:   Tue Mar 11 15:04:39 2014 -0400
+
+    LP#1277731: pgTAP for action.hold_request_permit_test()
+    
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+    Signed-off-by: Remington Steed <rjs7 at calvin.edu>
+
+15	0	Open-ILS/src/sql/Pg/live_t/lp1277731_hold_permit_test.pg
+ create mode 100644 Open-ILS/src/sql/Pg/live_t/lp1277731_hold_permit_test.pg
+
+commit 906ba880fb73d2b477f94b7bda17f31d324403f1
+Author: Dan Wells <dbw2 at calvin.edu>
+Date:   Tue Mar 11 14:33:58 2014 -0400
+
+    LP#1277731: Stamping upgrade for hold_test_params
+    
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+1	1	Open-ILS/src/sql/Pg/002.schema.config.sql
+387	0	Open-ILS/src/sql/Pg/upgrade/0873.function.hold_test_params.sql
+0	387	Open-ILS/src/sql/Pg/upgrade/XXXX.function.hold_test_params.sql
+ create mode 100644 Open-ILS/src/sql/Pg/upgrade/0873.function.hold_test_params.sql
+ delete mode 100644 Open-ILS/src/sql/Pg/upgrade/XXXX.function.hold_test_params.sql
+
+commit 2542c713ea4a0d686d7b7ceae352929b60a80806
+Author: Mike Rylander <mrylander at gmail.com>
+Date:   Tue Mar 4 15:47:12 2014 -0500
+
+    LP#1277731: Disambiguate parameter/column names
+    
+    Due to slightly different and more strict disabiguation rules
+    for parameters and column names in PLPGSQL in modern versions
+    of Postgres, our hold matrix functions were failing in 9.3.
+    
+    This commit attempts to address that by declaring and using
+    aliases for parameters that share names with columns used in
+    in-line SQL.
+    
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+11	7	Open-ILS/src/sql/Pg/110.hold_matrix.sql
+387	0	Open-ILS/src/sql/Pg/upgrade/XXXX.function.hold_test_params.sql
+ create mode 100644 Open-ILS/src/sql/Pg/upgrade/XXXX.function.hold_test_params.sql
+
+commit fcd7de207a1c6f97f53f8fbade62ab9385c9e113
+Author: Galen Charlton <gmc at esilibrary.com>
+Date:   Fri Mar 7 08:11:59 2014 -0800
+
+    LP#1289450: OpenSRF 2.3.0 is the minimum required version
+    
+    This patch updates the installation and upgrade documentation
+    to reflect the decision to make OpenSRF 2.3.0 be the minimum
+    required version.
+    
+    Signed-off-by: Galen Charlton <gmc at esilibrary.com>
+    Signed-off-by: Remington Steed <rjs7 at calvin.edu>
+
+1	1	docs/installation/server_installation.txt
+1	1	docs/installation/server_upgrade.txt
+
+commit b9f8c5bcd24ccbda14210d9700d3404cb78ede16
+Author: Ben Shum <bshum at biblio.org>
+Date:   Mon Mar 10 12:55:04 2014 -0400
+
+    LP1284864 - stamping upgrade for deleted metarecord function fixing
+    
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+
+1	1	Open-ILS/src/sql/Pg/002.schema.config.sql
+355	0	Open-ILS/src/sql/Pg/upgrade/0872.functions.metarecord-deleted-constituents.sql
+0	355	Open-ILS/src/sql/Pg/upgrade/XXXX.functions.metarecord-deleted-constituents.sql
+ create mode 100644 Open-ILS/src/sql/Pg/upgrade/0872.functions.metarecord-deleted-constituents.sql
+ delete mode 100644 Open-ILS/src/sql/Pg/upgrade/XXXX.functions.metarecord-deleted-constituents.sql
+
+commit f4d5813d7d5dfe22fef69871fb2d8c2685b43ceb
+Author: Mike Rylander <mrylander at gmail.com>
+Date:   Mon Mar 10 12:43:24 2014 -0400
+
+    LP#1284864: Forcibly update deleted MR masters
+    
+    Query derived from one by Ben Shum, altered to take deleted-record retention
+    configuration into account.
+    
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+
+12	0	Open-ILS/src/sql/Pg/upgrade/XXXX.functions.metarecord-deleted-constituents.sql
+
+commit 5f0306865e871aab3e072bfb1cdf191340efb680
+Author: Mike Rylander <mrylander at gmail.com>
+Date:   Fri Mar 7 15:48:35 2014 -0500
+
+    LP#1284864: Don't leak deleted constituent records
+    
+    There were times when deleted constituent records were leaking into
+    the display of metarecord results.  In particular, when a metarecord's
+    lead record was deleted, the lead was not recalculated.  We address
+    this situation directly now in the remapper.
+    
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+
+72	28	Open-ILS/src/sql/Pg/030.schema.metabib.sql
+1	1	Open-ILS/src/sql/Pg/990.schema.unapi.sql
+343	0	Open-ILS/src/sql/Pg/upgrade/XXXX.functions.metarecord-deleted-constituents.sql
+ create mode 100644 Open-ILS/src/sql/Pg/upgrade/XXXX.functions.metarecord-deleted-constituents.sql
+
+commit d470c2dcf5ffb4b1d28f783f8eb356fdc4f6ab06
+Author: Mike Rylander <mrylander at gmail.com>
+Date:   Mon Mar 10 12:31:51 2014 -0400
+
+    Stamping upgrade script for TPAC metarecord / formats repairs and usability additions
+    
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+
+1	1	Open-ILS/src/sql/Pg/002.schema.config.sql
+127	0	Open-ILS/src/sql/Pg/upgrade/0871.data.tpac-format-selector.sql
+0	125	Open-ILS/src/sql/Pg/upgrade/XXXX.data.tpac-format-selector.sql
+ create mode 100644 Open-ILS/src/sql/Pg/upgrade/0871.data.tpac-format-selector.sql
+ delete mode 100644 Open-ILS/src/sql/Pg/upgrade/XXXX.data.tpac-format-selector.sql
+
+commit 03c8b3326e16cf0be42b9d8f2de8dae337970aaf
+Author: Bill Erickson <berick at esilibrary.com>
+Date:   Thu Mar 6 16:40:31 2014 -0500
+
+    LP#1284864 correct TPAC metarecord list pagination
+    
+    Set the template hit_count value for metarecord constituent records page
+    to show the correct counts and pagination.
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+
+1	0	Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Search.pm
+
+commit c6750416e373ab76b42ed593131c33bed21a8b0c
+Author: Bill Erickson <berick at esilibrary.com>
+Date:   Tue Mar 4 10:42:22 2014 -0500
+
+    LP#1284864 repair MR hold possibilty depth calculation
+    
+    Fixes a bug where the hold possibility checks for metarecords used the
+    depth of the selection OU instead of depth 0 when no depth was defined.
+    This prevented holds from being placed in some instances, particularly
+    when no hold boundaries were defined (or equaled zero).
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+
+3	0	Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Holds.pm
+
+commit 097d661976213564d516cebba31b2b132ae8ab13
+Author: Bill Erickson <berick at esilibrary.com>
+Date:   Mon Mar 3 11:52:57 2014 -0500
+
+    LP#1284864 MR opac-visible constituent records
+    
+    The number of constituent records for a metarecord during searching is
+    now consitently based on the presence of an opac visible copy and not a
+    holdable copy.  This affects the constituent record counts in MR results
+    lists and the records displayed in the constituent records list.  (Icons
+    were already checking visibility instead of holdability).
+    
+    Holdable formats are still derived from records with holdable copies.
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+
+5	1	Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Holds.pm
+16	2	Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Publisher/action.pm
+3	1	Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Search.pm
+
+commit 3bd56efa634f801972a32879ca8910fc6c35e9e6
+Author: Bill Erickson <berick at esilibrary.com>
+Date:   Mon Mar 3 11:08:54 2014 -0500
+
+    LP#1284864 MR display avoid fetching master
+    
+    Remove unnecessary code to fetch the MR master when compiling MR
+    constituent records lists, since the master record was slipping into the
+    results set, where it should not have been.  This code is unneeded and
+    is a holdover from an earlier experiment.
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+
+0	15	Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Search.pm
+
+commit ccffb35178754772a0ef46405ced4da0ef563b95
+Author: Bill Erickson <berick at esilibrary.com>
+Date:   Fri Feb 28 10:07:11 2014 -0500
+
+    LP#1284864 MR holds w/o formats disallowed
+    
+    During MR hold placement, if the MR has zero holdable formats, disallow
+    the hold.
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+
+13	0	Open-ILS/src/templates/opac/css/style.css.tt2
+36	3	Open-ILS/src/templates/opac/parts/place_hold.tt2
+
+commit 4788e06a66f01b27ead04beea1e9965393609945
+Author: Bill Erickson <berick at esilibrary.com>
+Date:   Thu Feb 27 17:22:52 2014 -0500
+
+    LP#1284864 MR holds display and edit repairs
+    
+    * Repair format icons for MR and non-MR holds
+    * Allow all filters to be cleared from a MR hold (w/o resulting in a
+      server error).
+    * during editing, if a hold has a selection_depth, use that to further
+      limit the available formats and languages in the edit selectors.
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+
+6	2	Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Account.pm
+1	1	Open-ILS/src/templates/opac/myopac/holds.tt2
+4	3	Open-ILS/src/templates/opac/parts/metarecord_hold_filters.tt2
+
+commit b52b7aa0cda76a74972c3332f85c0e2f86f32469
+Author: Bill Erickson <berick at esilibrary.com>
+Date:   Thu Feb 27 16:37:25 2014 -0500
+
+    LP#1284864 metarecord holds wording repairs
+    
+    Indicate to the patron that selecting no format means that any available
+    format may be used to fill the hold.  Ditto language.
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+
+1	1	Open-ILS/src/templates/opac/myopac/holds/edit.tt2
+3	1	Open-ILS/src/templates/opac/parts/metarecord_hold_filters.tt2
+
+commit 0f65347f3b4daa7bfe4235ce941b7e9844d665c4
+Author: Bill Erickson <berick at esilibrary.com>
+Date:   Thu Feb 27 16:27:55 2014 -0500
+
+    LP#1284864 metarecord filtered constituent record counts
+    
+    Ensure the count of constiuent records in the MR results lists is
+    derived from the filtered record set (search org, depth, holdable, etc.)
+    and not all records.
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+
+23	27	Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Search.pm
+
+commit 3ea360d2465b8ee37c459b5095fcff31f5b3bbd6
+Author: Bill Erickson <berick at esilibrary.com>
+Date:   Thu Feb 27 16:15:06 2014 -0500
+
+    LP#1284864 TPAC scoped constituent MR records list
+    
+    Limit bib records to those within the search scope in the MR constituent
+    records list page.
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+
+6	6	Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Search.pm
+
+commit bf7abdba7bac3c4affb7968a20be31fd2c17b9c9
+Author: Bill Erickson <berick at esilibrary.com>
+Date:   Wed Feb 26 10:35:25 2014 -0500
+
+    LP#1284864 TPAC format selector attribute / values
+    
+    Creates a new search_format record attribute, which is responsible for
+    driving the catalog search format selector.  The values are derived from
+    the icon_format attriute, with a few notable changes (for starters).
+    
+    1. The 'book' search_format contains large print and has the label "All
+    Books".
+    
+    2. The 'music' search_format contains all music, regardless of sound
+    record format (or other attributes) and has the label "All Music"
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+
+117	1	Open-ILS/src/sql/Pg/950.data.seed-values.sql
+125	0	Open-ILS/src/sql/Pg/upgrade/XXXX.data.tpac-format-selector.sql
+ create mode 100644 Open-ILS/src/sql/Pg/upgrade/XXXX.data.tpac-format-selector.sql
+
+commit 227cd9c0df17e8e7ea96fd11b807b8ac7e3e37ae
+Author: Bill Erickson <berick at esilibrary.com>
+Date:   Tue Feb 25 16:47:03 2014 -0500
+
+    LP#1284864 TPAC metarecord display record count in results
+    
+    Next to each metarecord containing more than one record, display the
+    count of constituent records next to the record title in parentheses.
+    This allows the user to see at a glance if a record is really grouped or
+    simply a single-record "group".
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+
+19	4	Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Search.pm
+10	3	Open-ILS/src/templates/opac/parts/result/table.tt2
+
+commit bb720c69ed4c082947ee8052ac6cc9f4a5f26491
+Author: Bill Erickson <berick at esilibrary.com>
+Date:   Tue Feb 25 15:33:32 2014 -0500
+
+    LP#1284864 display code value code in composite def builder
+    
+    When selected code values to add to a composite definition in the coded
+    value map composite def. editor, display both the label and the code, as
+    many people or more familiar w/ the codes than the labels.
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+
+4	1	Open-ILS/web/js/ui/default/conify/global/config/composite_attr_entry_definition.js
+
+commit 168f5c9b535b33cc41d7b539a5254b20c71dddfd
+Author: Bill Erickson <berick at esilibrary.com>
+Date:   Tue Feb 25 15:27:58 2014 -0500
+
+    LP#1284864 coded value map cloning
+    
+    Added a "clone selected" option to the coded value map grid.  For CCVMs
+    which have composite definitions, clone the composite definition as
+    well.
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+
+38	0	Open-ILS/src/templates/conify/global/config/coded_value_map.tt2
+
+commit b055fe4a99b58d2ac1634398a1bc85d8581a8316
+Author: Bill Erickson <berick at esilibrary.com>
+Date:   Tue Feb 25 14:58:06 2014 -0500
+
+    LP#1284864 propagate patron barcode to advanced hold options
+    
+    1. Staff searches the catalog within the staff client, not focused on a
+    patron.
+    
+    2. Staff types a barcode into the patron barcode input
+    
+    3. Staff clicks "Advanced Holds Options" and the typed barcode now
+    propagates to the metarecord hold page.
+    
+    --
+    
+    Minor HTML cleanup to avoid 350+-wide character columns.
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+
+13	3	Open-ILS/src/templates/opac/parts/place_hold.tt2
+25	3	Open-ILS/web/js/ui/default/opac/staff.js
+
+commit 17287cf79206e1d6a61fd6ef796a442410cab722
+Author: Bill Erickson <berick at esilibrary.com>
+Date:   Tue Feb 25 13:59:34 2014 -0500
+
+    LP#1284864 show all formats in record details page
+    
+    For records which have multiple formats (e.g. DVD and BLU-RAY), show all
+    formats in the details page, similar to the search results pages.
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+
+6	3	Open-ILS/src/templates/opac/parts/record/summary.tt2
+
+commit 630e14da165fa7aa399a1ced6a92e968b1d440fc
+Author: Bill Erickson <berick at esilibrary.com>
+Date:   Tue Feb 25 13:59:00 2014 -0500
+
+    LP#1284864 added missing stock blu-ray icon
+    
+    For now, it matches the DVD icon.
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+
+-	-	Open-ILS/web/images/format_icons/icon_format/blu-ray.png
+ create mode 100644 Open-ILS/web/images/format_icons/icon_format/blu-ray.png
+
+commit f1024961703cce732ed6fd1e5cb11dd96795e67e
+Author: Elliot V <evoris at slcconline.edu>
+Date:   Thu Mar 6 23:43:00 2014 -0600
+
+    LP#1077811 Inconsistent INSTALL Instructions
+    
+    The preamble to the installation instructions, intended for
+    developers, is a bit unclear. The instructions describe actions
+    that should take place at two different points in the installation.
+    
+    This commit moves the instructions to download and install the Dojo
+    Toolkit until after the opensrf Linux user already owns the
+    /openils directory. It also adds the appropriate note for non-devs
+    to skip this section.
+    
+    Signed-off-by: Elliot V <evoris at slcconline.edu>
+    Signed-off-by: Remington Steed <rjs7 at calvin.edu>
+
+21	13	docs/installation/server_installation.txt
+
+commit 19f438573115de734a21588071a65c329d621e81
+Author: Ben Shum <bshum at biblio.org>
+Date:   Fri Mar 7 08:49:16 2014 -0500
+
+    LP1288938 - final adjustments for 0870 upgrade script
+    
+    These were missed from the original and resulted in the fix not being complete.
+    
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+
+3	3	Open-ILS/src/sql/Pg/upgrade/0870.function.located_uris_act_as_copies-fix.sql
+
+commit 5d62e7d5f1c9ed0e82e158bd4027e5b7599605c3
+Author: Dan Wells <dbw2 at calvin.edu>
+Date:   Thu Mar 6 18:17:56 2014 -0500
+
+    Forward-port 2.5.2-2.5.3 upgrade script
+    
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+553	0	Open-ILS/src/sql/Pg/version-upgrade/2.5.2-2.5.3-upgrade-db.sql
+ create mode 100644 Open-ILS/src/sql/Pg/version-upgrade/2.5.2-2.5.3-upgrade-db.sql
+
+commit 19c624fb0be862a4a005bb74f8f86cc085942f08
+Author: Dan Wells <dbw2 at calvin.edu>
+Date:   Wed Mar 5 12:24:19 2014 -0500
+
+    LP#1287510 Add missing column to upgrade script
+    
+    If you come via upgrade and not a fresh 2.5 DB, you are probably
+    missing the action.aged_hold_request.behind_desk column.  Add it in a
+    harmless way.
+    
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+
+4	0	Open-ILS/src/sql/Pg/upgrade/0868.schema.all_hold_behind_desk.sql
+
+commit 7063355b1e0a5e1b8dfcedbe3a5779c1b9f2423a
+Author: Ben Shum <bshum at biblio.org>
+Date:   Thu Mar 6 15:16:45 2014 -0500
+
+    LP1288938 - stamping upgrade script
+    
+    With minor fixing to remove the unneeded bits of the upgrade scripts.
+    
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+
+1	1	Open-ILS/src/sql/Pg/002.schema.config.sql
+57	0	Open-ILS/src/sql/Pg/upgrade/0870.function.located_uris_act_as_copies-fix.sql
+0	508	Open-ILS/src/sql/Pg/upgrade/XXXX.function.located_uris_act_as_copies-fix.sql
+ create mode 100644 Open-ILS/src/sql/Pg/upgrade/0870.function.located_uris_act_as_copies-fix.sql
+ delete mode 100644 Open-ILS/src/sql/Pg/upgrade/XXXX.function.located_uris_act_as_copies-fix.sql
+
+commit 7b52df52c7259ec73e7719d04cb10fc4269cb9db
+Author: Mike Rylander <mrylander at gmail.com>
+Date:   Thu Mar 6 11:28:46 2014 -0500
+
+    LP#1288938: Leaking URIs ... don't do that
+    
+    Ben Shum spotted an issue where the old behavior
+    could leak hidden URIs.  Being more explicit in the
+    WHERE clause addresses this.
+    
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+
+2	2	Open-ILS/src/sql/Pg/990.schema.unapi.sql
+508	0	Open-ILS/src/sql/Pg/upgrade/XXXX.function.located_uris_act_as_copies-fix.sql
+ create mode 100644 Open-ILS/src/sql/Pg/upgrade/XXXX.function.located_uris_act_as_copies-fix.sql
+
+commit 51473ec010d210d82fc4fbbaf40cc846512b88fb
+Author: Bill Erickson <berick at esilibrary.com>
+Date:   Thu Mar 6 13:10:19 2014 -0500
+
+    LP#1287973 recover row breaks in TPAC advanced search
+    
+    Avoid long horizontal filter rows in the advanced search page by
+    recovering the original clear/both on each row of filters to force a new
+    line.
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+
+1	1	Open-ILS/src/templates/opac/css/style.css.tt2
+
+commit 0cbadccad019f5130e04e6d74cdd36b1c15c7c8e
+Author: Jason Etheridge <jason at esilibrary.com>
+Date:   Wed Feb 12 11:49:37 2014 -0500
+
+    LP#1279420 Add Test::Output prerequisite
+    
+    Build tests require Test::Output. Add packages for Test::Output to
+    the prerequite installer Makefiles.
+    
+    Signed-off-by: Jason Etheridge <jason at esilibrary.com>
+    Signed-off-by: Jeff Godin <jgodin at tadl.org>
+
+1	0	Open-ILS/src/extras/install/Makefile.debian-squeeze
+1	0	Open-ILS/src/extras/install/Makefile.debian-wheezy
+1	0	Open-ILS/src/extras/install/Makefile.fedora
+1	0	Open-ILS/src/extras/install/Makefile.ubuntu-lucid
+1	0	Open-ILS/src/extras/install/Makefile.ubuntu-precise
+
+commit c1e03c02216ed8a5916e44714d621a55b0b95fc7
+Author: Ben Shum <bshum at biblio.org>
+Date:   Fri Feb 28 12:38:36 2014 -0500
+
+    LP1272316 - Stamping upgrade script for pre-calculate-prox-adjustment
+    
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+
+1	1	Open-ILS/src/sql/Pg/002.schema.config.sql
+18	0	Open-ILS/src/sql/Pg/upgrade/0869.schema.pre-calculate-prox-adjustment.sql
+0	16	Open-ILS/src/sql/Pg/upgrade/XXXX.schema.pre-calculate-prox-adjustment.sql
+ create mode 100644 Open-ILS/src/sql/Pg/upgrade/0869.schema.pre-calculate-prox-adjustment.sql
+ delete mode 100644 Open-ILS/src/sql/Pg/upgrade/XXXX.schema.pre-calculate-prox-adjustment.sql
+
+commit af966c3f322b4ad9d5a046026f57da5ca5cc995d
+Author: Mike Rylander <mrylander at gmail.com>
+Date:   Fri Feb 14 12:01:37 2014 -0500
+
+    LP1272316 - Calculate proximity in the DB for speed
+    
+    We need to calculate and store a (potenially adjusted) proxmity for
+    each hold and copy for use in targetting and optimization of op
+    capture.  Before this commit, we do that within the hold target
+    code itself.  Now we'll do it when the hold-copy map is inserted,
+    because we have the same information available at that time as we
+    have in the targeter.  This will both speed up the apparent cost of
+    the calculation, because it avoids the cost of a network round-trip,
+    and the total number of SELECTs we must issue, because the proximity
+    value will now be cached for use by the proximity map function.
+    
+    Backward compatability is retained for the create_prox_map() function
+    in case any other code is depending on that.
+    
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+    Signed-off-by: Chris Sharp <csharp at georgialibraries.org>
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+
+14	10	Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Publisher/action.pm
+9	0	Open-ILS/src/sql/Pg/090.schema.action.sql
+16	0	Open-ILS/src/sql/Pg/upgrade/XXXX.schema.pre-calculate-prox-adjustment.sql
+ create mode 100644 Open-ILS/src/sql/Pg/upgrade/XXXX.schema.pre-calculate-prox-adjustment.sql
+
+commit 4cb16a9f07180d4ef99c960834994e32b82d5881
+Author: Lebbeous Fogle-Weekley <lebbeous at esilibrary.com>
+Date:   Fri Jan 24 12:33:13 2014 -0500
+
+    LP1272316 - Followup to make ou_ancestor_setting() even faster
+    
+    Signed-off-by: Lebbeous Fogle-Weekley <lebbeous at esilibrary.com>
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+    Signed-off-by: Chris Sharp <csharp at georgialibraries.org>
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+
+10	8	Open-ILS/src/perlmods/lib/OpenILS/Application/AppUtils.pm
+
+commit 181c784c8b075a1b3e1dfbd2a3471af2ee843797
+Author: Lebbeous Fogle-Weekley <lebbeous at esilibrary.com>
+Date:   Fri Jan 24 12:24:06 2014 -0500
+
+    LP1272316 - Speed up these settings lookups in the hold targeter that get repeated a ...
+    
+    ... lot when there are lots of copies for a hold.
+    
+    Signed-off-by: Lebbeous Fogle-Weekley <lebbeous at esilibrary.com>
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+    Signed-off-by: Chris Sharp <csharp at georgialibraries.org>
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+
+15	14	Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Publisher/action.pm
+
+commit 1e3a50f758103b726bfede5f98e65e3b6799e831
+Author: Bill Erickson <berick at esilibrary.com>
+Date:   Thu Jun 6 11:13:35 2013 -0400
+
+    LP#1179660: remove call to undefined initialize func
+    
+    Remove call to nonexistant function Search::Z3950->initialize.  Prior to
+    now, this would have quietly failed, but with AUTOLOAD to be removed
+    from OpenSRF, it would fail with full shock and awe.
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Galen Charlton <gmc at esilibrary.com>
+    
+    Conflicts:
+    	Open-ILS/src/perlmods/lib/OpenILS/Application/Search.pm
+
+0	1	Open-ILS/src/perlmods/lib/OpenILS/Application/Search.pm
+
+commit ac3f30740999ea3e1c95e0031697bb7589c6ed83
+Author: Dan Wells <dbw2 at calvin.edu>
+Date:   Mon Feb 24 16:31:16 2014 -0500
+
+    Translation updates - newpot
+    
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+25	1	build/i18n/po/acq.js/acq.js.pot
+1554	1292	build/i18n/po/db.seed/db.seed.pot
+2554	2498	build/i18n/po/fm_IDL.dtd/fm_IDL.dtd.pot
+9	2	build/i18n/po/lang.dtd/lang.dtd.pot
+15	11	build/i18n/po/register.js/register.js.pot
+6	6	build/i18n/po/reports.dtd/reports.dtd.pot
+728	460	build/i18n/po/tpac/tpac.pot
+
+commit 8267e3af9a2787c9ea1f4b8dcdcea78394206e20
+Author: Dan Wells <dbw2 at calvin.edu>
+Date:   Mon Feb 24 16:21:32 2014 -0500
+
+    Translation updates - po files
+    
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+64	11	build/i18n/po/AutoFieldWidget.js/cs-CZ.po
+61	9	build/i18n/po/AutoFieldWidget.js/de-DE.po
+61	9	build/i18n/po/AutoFieldWidget.js/en-CA.po
+61	9	build/i18n/po/AutoFieldWidget.js/en-GB.po
+61	9	build/i18n/po/AutoFieldWidget.js/es-ES.po
+61	9	build/i18n/po/AutoFieldWidget.js/fr-CA.po
+65	10	build/i18n/po/AutoFieldWidget.js/hy-AM.po
+61	9	build/i18n/po/AutoFieldWidget.js/oc-FR.po
+61	9	build/i18n/po/AutoFieldWidget.js/pt-BR.po
+61	9	build/i18n/po/AutoFieldWidget.js/ru-RU.po
+61	9	build/i18n/po/AutoFieldWidget.js/tr-TR.po
+8	4	build/i18n/po/cat.properties/cs-CZ.po
+7	3	build/i18n/po/cat.properties/de-DE.po
+7	3	build/i18n/po/cat.properties/en-CA.po
+7	3	build/i18n/po/cat.properties/en-GB.po
+7	3	build/i18n/po/cat.properties/es-ES.po
+7	3	build/i18n/po/cat.properties/fr-CA.po
+8	4	build/i18n/po/cat.properties/hy-AM.po
+7	3	build/i18n/po/cat.properties/oc-FR.po
+7	3	build/i18n/po/cat.properties/pt-BR.po
+7	3	build/i18n/po/cat.properties/ru-RU.po
+7	3	build/i18n/po/cat.properties/tr-TR.po
+2365	2265	build/i18n/po/db.seed/cs-CZ.po
+2179	2174	build/i18n/po/db.seed/de-DE.po
+2202	2176	build/i18n/po/db.seed/en-CA.po
+2202	2176	build/i18n/po/db.seed/en-GB.po
+2198	2175	build/i18n/po/db.seed/es-ES.po
+2221	2195	build/i18n/po/db.seed/fr-CA.po
+2506	2361	build/i18n/po/db.seed/hy-AM.po
+2185	2174	build/i18n/po/db.seed/oc-FR.po
+2208	2182	build/i18n/po/db.seed/pt-BR.po
+2211	2185	build/i18n/po/db.seed/ru-RU.po
+2173	2171	build/i18n/po/db.seed/tr-TR.po
+268	261	build/i18n/po/ils_events.xml/cs-CZ.po
+263	257	build/i18n/po/ils_events.xml/de-DE.po
+266	260	build/i18n/po/ils_events.xml/en-CA.po
+266	260	build/i18n/po/ils_events.xml/en-GB.po
+265	259	build/i18n/po/ils_events.xml/es-ES.po
+267	261	build/i18n/po/ils_events.xml/fr-CA.po
+267	261	build/i18n/po/ils_events.xml/hy-AM.po
+265	259	build/i18n/po/ils_events.xml/pt-BR.po
+265	259	build/i18n/po/ils_events.xml/ru-RU.po
+
+commit e406e36122b07f97f1c6ec6d5397550b03949b1b
+Author: Dan Wells <dbw2 at calvin.edu>
+Date:   Fri Feb 21 16:34:58 2014 -0500
+
+    Stamping 0868 - 'behind_desk' fixes
+    
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+1	1	Open-ILS/src/sql/Pg/002.schema.config.sql
+189	0	Open-ILS/src/sql/Pg/upgrade/0868.schema.all_hold_behind_desk.sql
+0	187	Open-ILS/src/sql/Pg/upgrade/XXXX.schema.all_hold_behind_desk.sql
+ create mode 100644 Open-ILS/src/sql/Pg/upgrade/0868.schema.all_hold_behind_desk.sql
+ delete mode 100644 Open-ILS/src/sql/Pg/upgrade/XXXX.schema.all_hold_behind_desk.sql
+
+commit 81d720fefe89c2a9a38b9658a44a3b0bf69cee4a
+Author: Dan Wells <dbw2 at calvin.edu>
+Date:   Fri Feb 21 15:58:50 2014 -0500
+
+    Stamping 0864-0867 for MVF, CRA, and TPAC MRs
+    
+    That is, Multi-valued Fields, Composite Record Attibutes, and TPAC
+    Metarecord support.
+    
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+1	1	Open-ILS/src/sql/Pg/002.schema.config.sql
+900	0	Open-ILS/src/sql/Pg/upgrade/0864.MVF_CRA-upgrade.sql
+41	0	Open-ILS/src/sql/Pg/upgrade/0865.schema.convert-MR-holdable_formats.sql
+567	0	Open-ILS/src/sql/Pg/upgrade/0866.schema.unapi-mmr.sql
+161	0	Open-ILS/src/sql/Pg/upgrade/0867.data.mmr-holds-formats.sql
+0	898	Open-ILS/src/sql/Pg/upgrade/QQQQ.MVF_CRA-upgrade.sql
+0	39	Open-ILS/src/sql/Pg/upgrade/ZZZZ.schema.convert-MR-holdable_formats.sql
+0	565	Open-ILS/src/sql/Pg/upgrade/ZZZZ.schema.unapi-mmr.sql
+0	159	Open-ILS/src/sql/Pg/upgrade/ZZZZZ.data.mmr-holds-formats.sql
+ create mode 100644 Open-ILS/src/sql/Pg/upgrade/0864.MVF_CRA-upgrade.sql
+ create mode 100644 Open-ILS/src/sql/Pg/upgrade/0865.schema.convert-MR-holdable_formats.sql
+ create mode 100644 Open-ILS/src/sql/Pg/upgrade/0866.schema.unapi-mmr.sql
+ create mode 100644 Open-ILS/src/sql/Pg/upgrade/0867.data.mmr-holds-formats.sql
+ delete mode 100644 Open-ILS/src/sql/Pg/upgrade/QQQQ.MVF_CRA-upgrade.sql
+ delete mode 100644 Open-ILS/src/sql/Pg/upgrade/ZZZZ.schema.convert-MR-holdable_formats.sql
+ delete mode 100644 Open-ILS/src/sql/Pg/upgrade/ZZZZ.schema.unapi-mmr.sql
+ delete mode 100644 Open-ILS/src/sql/Pg/upgrade/ZZZZZ.data.mmr-holds-formats.sql
+
+commit c7503c77fab597029a53097fb8f414b72382a1c0
+Author: Bill Erickson <berick at esilibrary.com>
+Date:   Fri Feb 21 13:48:07 2014 -0500
+
+    LP#1053397 Prevent display non-opac-visible icons / hold formats
+    
+    Avoid showing coded value maps for icons, hold formats, and hold
+    languages where the coded value's opac_visible value is FALSE.
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+3	2	Open-ILS/src/templates/opac/myopac/holds.tt2
+6	4	Open-ILS/src/templates/opac/parts/metarecord_hold_filters.tt2
+6	17	Open-ILS/src/templates/opac/parts/misc_util.tt2
+
+commit 00c36d702f909079294eba5d0ef591fb1a85a1f8
+Author: Bill Erickson <berick at esilibrary.com>
+Date:   Fri Feb 21 12:19:14 2014 -0500
+
+    LP#1053397 icon / metarcord format additions
+    
+     * Adds a new blu-ray format for icon and metarecord holds
+    
+     * Remove large-print items from the generic "book" attribute for icons
+       and holds.
+    
+       For icons, this means we will no longer see two icons displayed for a
+       single large-print book.
+    
+       For holds, this means that to receive a large-print book, one has to
+       select the large-print book format.  "book" alone will not result in
+       a large-print item being targted.
+    
+       Note that when building a data set for the format selector drop-down,
+       it might make sense to keep large-print items in the generic "book"
+       format.  That'll come later.
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+22	2	Open-ILS/src/sql/Pg/950.data.seed-values.sql
+1	1	Open-ILS/src/sql/Pg/upgrade/QQQQ.MVF_CRA-upgrade.sql
+17	0	Open-ILS/src/sql/Pg/upgrade/ZZZZZ.data.mmr-holds-formats.sql
+
+commit 0a6b913e0cbc025626bcf12d98e04f9d49448c9c
+Author: Bill Erickson <berick at esilibrary.com>
+Date:   Fri Feb 21 10:19:00 2014 -0500
+
+    LP#1053397 MR list return to grouped results
+    
+    Show a "Return to Grouped Search Results" link from the metarecord
+    constituent records page.
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+8	0	Open-ILS/src/templates/opac/results.tt2
+
+commit 3fd258fda0af6cf5cc53c7a87974027d694d6add
+Author: Bill Erickson <berick at esilibrary.com>
+Date:   Thu Feb 20 15:05:11 2014 -0500
+
+    LP#1053397 staff client MR results paging repair
+    
+    When selecting a record from the list of metarecord constituents, the
+    paging controls (start/previous/next/end) within the staff client should
+    page through the constiuents, not the original search.
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+1	1	Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Search.pm
+
+commit 4c8fc7fbb8733e27d480b838df2e86f1f1cc7ce7
+Author: Bill Erickson <berick at esilibrary.com>
+Date:   Thu Feb 20 14:48:53 2014 -0500
+
+    LP#1053397 MR holds displays selected formats
+    
+    In a patron's holds list, only show formats in the format column
+    matching the patron's selected hold formats.
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+16	4	Open-ILS/src/templates/opac/myopac/holds.tt2
+19	8	Open-ILS/src/templates/opac/parts/misc_util.tt2
+
+commit f5bc354c5d6dffd1a89514bd159b2051bfb90271
+Author: Mike Rylander <mrylander at gmail.com>
+Date:   Wed Feb 19 17:11:29 2014 -0500
+
+    LP#1053397: Use the new data structures for looking up language indexing configuration
+    
+    Also, from Dan Wells:
+    
+    First, we don't want to fully exclude records which don't have a
+    metabib.record_attr_vector_list entry, so we do a LEFT JOIN instead
+    for that table.  Otherwise, some records error out when ingesting
+    (see placeholder record -1 in the stock data set).
+    
+    Second, let's add a check for 'active' which appears to have been
+    always missing.
+    
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+31	10	Open-ILS/src/sql/Pg/030.schema.metabib.sql
+111	0	Open-ILS/src/sql/Pg/upgrade/QQQQ.MVF_CRA-upgrade.sql
+
+commit 3dfd7055bb024a385165ceca9e88b49014a8e515
+Author: Mike Rylander <mrylander at gmail.com>
+Date:   Wed Feb 19 13:06:32 2014 -0500
+
+    LP#1053397: Correct operator thinko on CRA sorters
+    
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+1	1	Open-ILS/src/sql/Pg/030.schema.metabib.sql
+1	1	Open-ILS/src/sql/Pg/upgrade/QQQQ.MVF_CRA-upgrade.sql
+
+commit f2e96e0ebf3f0f75e0d770ccc755406d5df84c09
+Author: Mike Rylander <mrylander at gmail.com>
+Date:   Tue Feb 18 16:53:53 2014 -0500
+
+    LP1053397: Don't leak memory; Cache compiled ccraed values
+    
+    We were leaking memory in a PLPGSQL function that compiles the
+    query_int from a ccraed value.  Stop doing that!
+    
+    Also, implement a self-invalidating (upon table update) cache
+    for compiled composite attr defs.  This brings concerto reingest
+    down from 50+ seconds to under 10.
+    
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+38	3	Open-ILS/src/sql/Pg/030.schema.metabib.sql
+38	3	Open-ILS/src/sql/Pg/upgrade/QQQQ.MVF_CRA-upgrade.sql
+
+commit c2c8b2796d14b8375ddca631a74d7ed75b882a20
+Author: Bill Erickson <berick at esilibrary.com>
+Date:   Mon Feb 17 15:08:11 2014 -0500
+
+    LP#1053397 catch-all 'music' icon_format attribute value
+    
+    Many records in the Evergreen sample data have item_type=j and no sound
+    recording format.  This seems likely to happen in the wild, as well.
+    The new coded value captures everying with item_type=j and no sr_format.
+    
+    Also included is a "music.png" icon, which looks like a pair of happy
+    eigth notes.
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+12	0	Open-ILS/src/sql/Pg/950.data.seed-values.sql
+11	0	Open-ILS/src/sql/Pg/upgrade/ZZZZZ.data.mmr-holds-formats.sql
+-	-	Open-ILS/web/images/format_icons/icon_format/music.png
+ create mode 100644 Open-ILS/web/images/format_icons/icon_format/music.png
+
+commit d8e33af69f190503798823e979e9ea80307c50dd
+Author: Mike Rylander <mrylander at gmail.com>
+Date:   Mon Feb 17 14:03:02 2014 -0500
+
+    LP#1269911: Cast bigint to int
+    
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+1	1	Open-ILS/src/sql/Pg/030.schema.metabib.sql
+1	1	Open-ILS/src/sql/Pg/upgrade/QQQQ.MVF_CRA-upgrade.sql
+
+commit 019f80a810c8d2e81e5602936b02d73b67a15d27
+Author: Bill Erickson <berick at esilibrary.com>
+Date:   Mon Feb 17 09:24:40 2014 -0500
+
+    LP#1053397 filter MR icons/formats repair
+    
+    Only limit the scope of the MR attributes in the presence of a hard hold
+    boundary when searching for which attributes to display in the hold
+    placement form.
+    
+    In other words, don't limit the attributes based on search parameters,
+    since searching at Branch 1 does not necesssarily meany you only want to
+    place holds on formats available at branch 1.
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+9	4	Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Holds.pm
+
+commit 6d328afcc86a28fdd9cf43294b4c630b02807a95
+Author: Bill Erickson <berick at esilibrary.com>
+Date:   Fri Feb 14 17:25:44 2014 -0500
+
+    LP#1053397 filter MR icons/formats by org scope
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+18	15	Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Holds.pm
+3	2	Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Account.pm
+
+commit 16e8e0e59e913c551a429d1fb3f2dc1b126e2099
+Author: Mike Rylander <mrylander at gmail.com>
+Date:   Fri Feb 14 16:06:59 2014 -0500
+
+    LP#1053397: Add optional org filter to "has holdable copies", and use that in open-ils.circ.holds.metarecord.filterd_records
+    
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+11	2	Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Holds.pm
+12	11	Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Publisher/action.pm
+4	2	Open-ILS/src/sql/Pg/040.schema.asset.sql
+49	0	Open-ILS/src/sql/Pg/upgrade/ZZZZ.schema.unapi-mmr.sql
+
+commit b0ff3c9e3e839dd16b4260763817c4a9078c8339
+Author: Bill Erickson <berick at esilibrary.com>
+Date:   Fri Feb 14 14:34:02 2014 -0500
+
+    LP#1053397 apply org scope to metarecord attributes
+    
+    When loading record attributes (cra, ccvm, etc.) for constituent
+    records, limit the attributes to those contained by records which have
+    holdings within the provided (search) scope.
+    
+    With this, for example, a search at Branch 1 for metarecords will only
+    show format icons for constituent records that have holdings at BR1.
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+19	4	Open-ILS/src/sql/Pg/990.schema.unapi.sql
+19	3	Open-ILS/src/sql/Pg/upgrade/ZZZZ.schema.unapi-mmr.sql
+
+commit c62821619ce2a00128aa9cc4a7b19d6e94f1b4fa
+Author: Bill Erickson <berick at esilibrary.com>
+Date:   Fri Feb 14 12:23:02 2014 -0500
+
+    LP#1053397 repair one-hit redirect logic for metarecords
+    
+    * Only perform the single-hit redirect if there is only one metarecord
+      search result and the MR only has a single constituent record.
+    
+    * Repair the record id logic so the redirect jumps to the correct
+      record.
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+11	3	Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Search.pm
+
+commit f77269997a72f188ca8a733f5125175bf2b83dc2
+Author: Bill Erickson <berick at esilibrary.com>
+Date:   Thu Feb 13 16:28:01 2014 -0500
+
+    LP#1269911 global flag for opac format selector attribute
+    
+    Adds a new config.global_flag for defining which record attribute the
+    OPAC will use to find formats for the format selector.
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+14	0	Open-ILS/src/sql/Pg/950.data.seed-values.sql
+15	0	Open-ILS/src/sql/Pg/upgrade/ZZZZZ.data.mmr-holds-formats.sql
+1	1	Open-ILS/src/templates/opac/parts/config.tt2
+
+commit 811325f638f9291752de1134f61fa073732ed3f7
+Author: Bill Erickson <berick at esilibrary.com>
+Date:   Thu Feb 13 15:28:39 2014 -0500
+
+    LP#1269911 seed data SQL repairs
+    
+    Products of merge conflict resolution with the mvf-cra branch.
+    
+    * repaired syntax error
+    * removed some duplicate global flag entries
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+1	26	Open-ILS/src/sql/Pg/950.data.seed-values.sql
+
+commit d6f40df7f4f0b4d9210dc7aee5ab9771a63cbb5b
+Author: Bill Erickson <berick at esilibrary.com>
+Date:   Tue Feb 11 10:33:01 2014 -0500
+
+    LP#1269911 'large print book' is also a 'book'
+    
+    Remove the item_form != d component of the "book" composite definition.
+    I think this more closely matches how humans would interpret it.
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+    
+    Conflicts:
+    	Open-ILS/src/sql/Pg/950.data.seed-values.sql
+    
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+1	1	Open-ILS/src/sql/Pg/950.data.seed-values.sql
+1	1	Open-ILS/src/sql/Pg/upgrade/QQQQ.MVF_CRA-upgrade.sql
+
+commit b2e4783726756af658f0fee069c7780425955cd1
+Author: Bill Erickson <berick at esilibrary.com>
+Date:   Mon Feb 10 14:01:05 2014 -0500
+
+    LP#1053397 TPAC Metarecords release notes
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+38	0	docs/RELEASE_NOTES_NEXT/OPAC/TPAC_metarecords.txt
+ create mode 100644 docs/RELEASE_NOTES_NEXT/OPAC/TPAC_metarecords.txt
+
+commit fc99f4f2230061922f8bea0e061f04d240a1ddfa
+Author: Bill Erickson <berick at esilibrary.com>
+Date:   Mon Feb 10 14:01:47 2014 -0500
+
+    LP#1053397 TPAC metarecord search and holds UI
+    
+    API, TPAC backend, and UI bits for TPAC metarecord searching and holds.
+    
+    * Group Formats and Editions options in advanced search / searchbar
+    * MR holds placement form, allowing selected formats and languages
+    * MR holds targeting updated to work w/ new holdable formats composite
+      definitions
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+151	25	Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Holds.pm
+56	60	Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Publisher/action.pm
+132	6	Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Account.pm
+43	10	Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Search.pm
+46	12	Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Util.pm
+4	1	Open-ILS/src/perlmods/lib/OpenILS/WWW/EGWeb.pm
+1	0	Open-ILS/src/templates/opac/css/style.css.tt2
+4	2	Open-ILS/src/templates/opac/myopac/holds.tt2
+9	0	Open-ILS/src/templates/opac/myopac/holds/edit.tt2
+15	1	Open-ILS/src/templates/opac/parts/advanced/search.tt2
+7	0	Open-ILS/src/templates/opac/parts/config.tt2
+89	0	Open-ILS/src/templates/opac/parts/metarecord_hold_filters.tt2
+21	20	Open-ILS/src/templates/opac/parts/misc_util.tt2
+11	0	Open-ILS/src/templates/opac/parts/place_hold.tt2
+37	6	Open-ILS/src/templates/opac/parts/result/table.tt2
+22	2	Open-ILS/src/templates/opac/results.tt2
+3	2	Open-ILS/web/js/ui/default/opac/simple.js
+ create mode 100644 Open-ILS/src/templates/opac/parts/metarecord_hold_filters.tt2
+
+commit e6421bcacd6e7c8cd13e871e1961f14c939151c6
+Author: Bill Erickson <berick at esilibrary.com>
+Date:   Mon Feb 10 14:00:21 2014 -0500
+
+    LP#1053397 DB metarecord seed data
+    
+    Seed data for representing the holdable formats for metarecords.  This
+    is a subset of the "icon_format" collection, excluding the electronic
+    resources.
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+226	110	Open-ILS/src/sql/Pg/950.data.seed-values.sql
+116	0	Open-ILS/src/sql/Pg/upgrade/ZZZZZ.data.mmr-holds-formats.sql
+ create mode 100644 Open-ILS/src/sql/Pg/upgrade/ZZZZZ.data.mmr-holds-formats.sql
+
+commit 36e3c0a8d4861eb8d877664623ef925331e45bb1
+Author: Mike Rylander <mrylander at gmail.com>
+Date:   Mon Feb 10 13:59:23 2014 -0500
+
+    LP#1053397 DB for metarecords unapi and holds
+    
+    Schema for unapi metarecord access (unap.mmr()) and associated
+    components.
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+12	12	Open-ILS/src/sql/Pg/040.schema.asset.sql
+322	5	Open-ILS/src/sql/Pg/990.schema.unapi.sql
+39	0	Open-ILS/src/sql/Pg/upgrade/ZZZZ.schema.convert-MR-holdable_formats.sql
+500	0	Open-ILS/src/sql/Pg/upgrade/ZZZZ.schema.unapi-mmr.sql
+ create mode 100644 Open-ILS/src/sql/Pg/upgrade/ZZZZ.schema.convert-MR-holdable_formats.sql
+ create mode 100644 Open-ILS/src/sql/Pg/upgrade/ZZZZ.schema.unapi-mmr.sql
+
+commit 586acbd644362c823bd9865e61bf130fb0b4fc11
+Author: Bill Erickson <berick at esilibrary.com>
+Date:   Mon Feb 10 13:54:43 2014 -0500
+
+    LP#1053397 IDL class mraf for metabib::record_attr_flat
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+15	0	Open-ILS/examples/fm_IDL.xml
+
+commit 922a53a5b64f0d23eacba5eb1c834a6cd60e46fb
+Author: Mike Rylander <mrylander at gmail.com>
+Date:   Mon Feb 10 14:10:38 2014 -0500
+
+    LP#1269911: Release notes for Composite Record Attributes
+    
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+31	0	docs/RELEASE_NOTES_NEXT/OPAC/Composite_Record_Attributes.txt
+ create mode 100644 docs/RELEASE_NOTES_NEXT/OPAC/Composite_Record_Attributes.txt
+
+commit 5a7add8fe93ac1228bf4791401d109df90c3d380
+Author: Mike Rylander <mrylander at gmail.com>
+Date:   Mon Feb 10 14:02:22 2014 -0500
+
+    LP#1269911: Release notes for Multi-valued Fields and Controlled Attributes
+    
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+45	0	docs/RELEASE_NOTES_NEXT/OPAC/Multi_Valued_fields.txt
+ create mode 100644 docs/RELEASE_NOTES_NEXT/OPAC/Multi_Valued_fields.txt
+
+commit e4ca479407e3dd17b16a4e53868b9e09881e6ce5
+Author: Bill Erickson <berick at esilibrary.com>
+Date:   Mon Feb 10 14:12:15 2014 -0500
+
+    LP#1053397: removed extraneous MR formats global flag
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+0	11	Open-ILS/src/sql/Pg/upgrade/QQQQ.MVF_CRA-upgrade.sql
+
+commit 33961761022b2021b2428d1909f75b8aeb972af3
+Author: Bill Erickson <berick at esilibrary.com>
+Date:   Thu Feb 6 13:31:18 2014 -0500
+
+    LP#1269911: TPAC generates format selector from icon_format attr
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+1	1	Open-ILS/src/templates/opac/parts/config.tt2
+
+commit 734d2302b72a0f7d55f23a2ed92e7313c10cee03
+Author: Bill Erickson <berick at esilibrary.com>
+Date:   Wed Feb 5 16:18:38 2014 -0500
+
+    LP#1269911: composite attributes: configurable "icons" attribute
+    
+    Honor the configurable icon attribute within the TPAC.
+    
+    Create a default set of icons, by copying from the existing icons,
+    which roughly map to the new "icon_format" record attribute
+    definition mappings.
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+11	12	Open-ILS/src/templates/opac/parts/misc_util.tt2
+-	-	Open-ILS/web/images/format_icons/icon_format/book.png
+-	-	Open-ILS/web/images/format_icons/icon_format/braille.png
+-	-	Open-ILS/web/images/format_icons/icon_format/casaudiobook.png
+-	-	Open-ILS/web/images/format_icons/icon_format/casmusic.png
+-	-	Open-ILS/web/images/format_icons/icon_format/cdaudiobook.png
+-	-	Open-ILS/web/images/format_icons/icon_format/cdmusic.png
+-	-	Open-ILS/web/images/format_icons/icon_format/dvd.png
+-	-	Open-ILS/web/images/format_icons/icon_format/eaudio.png
+-	-	Open-ILS/web/images/format_icons/icon_format/ebook.png
+-	-	Open-ILS/web/images/format_icons/icon_format/equip.png
+-	-	Open-ILS/web/images/format_icons/icon_format/evideo.png
+-	-	Open-ILS/web/images/format_icons/icon_format/kit.png
+-	-	Open-ILS/web/images/format_icons/icon_format/lpbook.png
+-	-	Open-ILS/web/images/format_icons/icon_format/map.png
+-	-	Open-ILS/web/images/format_icons/icon_format/microform.png
+-	-	Open-ILS/web/images/format_icons/icon_format/phonomusic.png
+-	-	Open-ILS/web/images/format_icons/icon_format/phonospoken.png
+-	-	Open-ILS/web/images/format_icons/icon_format/picture.png
+-	-	Open-ILS/web/images/format_icons/icon_format/score.png
+-	-	Open-ILS/web/images/format_icons/icon_format/serial.png
+-	-	Open-ILS/web/images/format_icons/icon_format/software.png
+-	-	Open-ILS/web/images/format_icons/icon_format/vhs.png
+ create mode 100644 Open-ILS/web/images/format_icons/icon_format/book.png
+ create mode 100644 Open-ILS/web/images/format_icons/icon_format/braille.png
+ create mode 100644 Open-ILS/web/images/format_icons/icon_format/casaudiobook.png
+ create mode 100644 Open-ILS/web/images/format_icons/icon_format/casmusic.png
+ create mode 100644 Open-ILS/web/images/format_icons/icon_format/cdaudiobook.png
+ create mode 100644 Open-ILS/web/images/format_icons/icon_format/cdmusic.png
+ create mode 100644 Open-ILS/web/images/format_icons/icon_format/dvd.png
+ create mode 100644 Open-ILS/web/images/format_icons/icon_format/eaudio.png
+ create mode 100644 Open-ILS/web/images/format_icons/icon_format/ebook.png
+ create mode 100644 Open-ILS/web/images/format_icons/icon_format/equip.png
+ create mode 100644 Open-ILS/web/images/format_icons/icon_format/evideo.png
+ create mode 100644 Open-ILS/web/images/format_icons/icon_format/kit.png
+ create mode 100644 Open-ILS/web/images/format_icons/icon_format/lpbook.png
+ create mode 100644 Open-ILS/web/images/format_icons/icon_format/map.png
+ create mode 100644 Open-ILS/web/images/format_icons/icon_format/microform.png
+ create mode 100644 Open-ILS/web/images/format_icons/icon_format/phonomusic.png
+ create mode 100644 Open-ILS/web/images/format_icons/icon_format/phonospoken.png
+ create mode 100644 Open-ILS/web/images/format_icons/icon_format/picture.png
+ create mode 100644 Open-ILS/web/images/format_icons/icon_format/score.png
+ create mode 100644 Open-ILS/web/images/format_icons/icon_format/serial.png
+ create mode 100644 Open-ILS/web/images/format_icons/icon_format/software.png
+ create mode 100644 Open-ILS/web/images/format_icons/icon_format/vhs.png
+
+commit c33b7cf919db4eb087502322ad3b82572bb54f65
+Author: Bill Erickson <berick at esilibrary.com>
+Date:   Tue Jan 21 17:47:41 2014 -0500
+
+    LP#1269911 composite attributes admin UI
+    
+    New interface for managing composite record attribute definitions:
+    
+    /eg/conify/global/config/composite_attr_entry_definition/<id>
+    
+    The UI for a coded value map is accessed from an existing coded value
+    via a new "Manage" link column in the CCVM table.  The UI allows staff
+    to build tree-shaped boolean composite definitions for CCVMs in terms
+    of existing CCVMs.
+    
+    Additionally, the record attribute definition UI now has a link from
+    each definition to the coded value map page for the attribute.
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+6	1	Open-ILS/src/templates/conify/global/config/coded_value_map.tt2
+100	0	Open-ILS/src/templates/conify/global/config/composite_attr_entry_definition.tt2
+24	1	Open-ILS/src/templates/conify/global/config/record_attr_definition.tt2
+385	0	Open-ILS/web/js/ui/default/conify/global/config/composite_attr_entry_definition.js
+ create mode 100644 Open-ILS/src/templates/conify/global/config/composite_attr_entry_definition.tt2
+ create mode 100644 Open-ILS/web/js/ui/default/conify/global/config/composite_attr_entry_definition.js
+
+commit 00ced69379ad8101beaf2cdfa410d72ece9bc6b0
+Author: Mike Rylander <mrylander at gmail.com>
+Date:   Wed Jan 15 16:48:13 2014 -0500
+
+    LP#1269911: Upgrade script for MVF and CRA
+    
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+2	2	Open-ILS/src/sql/Pg/002.schema.config.sql
+62	53	Open-ILS/src/sql/Pg/030.schema.metabib.sql
+39	27	Open-ILS/src/sql/Pg/990.schema.unapi.sql
+763	0	Open-ILS/src/sql/Pg/upgrade/QQQQ.MVF_CRA-upgrade.sql
+ create mode 100644 Open-ILS/src/sql/Pg/upgrade/QQQQ.MVF_CRA-upgrade.sql
+
+commit abe6bdf09ea832296baf41daa5dadc378b2fef08
+Author: Mike Rylander <mrylander at gmail.com>
+Date:   Wed Jan 15 16:00:52 2014 -0500
+
+    LP#1269911: Teach QueryParser new tricks
+    
+    QP Needs to be made aware of several new structures in the database.
+    
+    First, we have added a new sort-supporting table called metabib.record_sorter
+    which holds values extracted by crad.sorter=true attrs.  This is used instead
+    of the mrd.attrs->"something" hstore composite.
+    
+    Next, we teach QP how to convert from a list of user-supplied values across
+    many dynamic filters (based on crad) into an intarray query of ids extracted
+    from config.coded_value_map (in the case of controlled attributes) or
+    metabib.uncontrolled_record_attr_value (in the case of, you guessed it,
+    uncontrolled attributes).  This query is applied against the vlist column
+    of metabib.record_attr_vector_list, which is GIN indexed for speed.
+    
+    Finally, metabib.record_attr is now a view over metabib.record_attr_vector_list
+    and is consequently going to be slow for general use.  We restrict
+    its inclusion in the core query to only the case of a during() filter
+    which requires access to the value of a bib's Date2 field.  For the
+    other common case, requiring access to the Date1 field, we instead
+    use the pubdate sort value now stored in metabib.record_sorter.  We
+    might consider making the specific sorter attribute used configurable
+    so that we can change the definition of pubdate down the road, but it
+    starts out (and generally stays) defined as equivalent to Date1.
+    
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+97	23	Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Driver/Pg/QueryParser.pm
+
+commit bcc5d4146b49b174be4b8511d791fcfdb6a448b9
+Author: Mike Rylander <mrylander at gmail.com>
+Date:   Wed Jan 15 13:17:39 2014 -0500
+
+    LP#1269911: Teach the IDL about MVF- and CRA-related structures
+    
+    IDL link from ccvm => ccraed via composite_def field
+    
+    IDL selector attribute for ccvm class
+    
+    ccraed gets CUD actions
+    
+    In conify/global/config/coded_value_map, if the selected attr type is
+    composite=true, show a link from each coded value to manage the
+    composite definition.
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+76	2	Open-ILS/examples/fm_IDL.xml
+40	2	Open-ILS/src/templates/conify/global/config/coded_value_map.tt2
+
+commit d2b047058e99da0ce2c944643a03b432beb4dda5
+Author: Mike Rylander <mrylander at gmail.com>
+Date:   Tue Jan 14 16:28:04 2014 -0500
+
+    LP#1269911: Database elements of MVF and CRA
+    
+    * Teach vandelay.marc21_physical_characteristics() to see all 007's
+    
+    We use vandelay.marc21_physical_characteristics() to extract fixed
+    field data that lives in the 007.  Before this change, it would
+    only look at the first 007 in the record.  Now it will look at
+    all of them in turn, supporting configurations such as DVD+BluRay.
+    
+    * Add intarray extension
+    
+    We need intarray for GIN index support of integer arrays, which is
+    how we'll be storing the in-use record attribute value identifiers.
+    
+    * Hidy hole in which to stick "uncontrolled" values
+    
+    In order to make use of the massive speed increases provided by
+    intarray indexing, we need to use (you guessed it) integers.  But
+    uncontrolled record attributes are not necessarily (or even very
+    often) numbers.  We will store them in a table of unique (per
+    attribute) values, and use the id from that table in our intarray
+    indexing.  That id comes from a DECREMENTING serial that starts
+    at -1 and counts downward.  This avoids collision with the other
+    set of integers (the id from config.coded_value_map) that we will
+    use for controlled record attribute values.
+    
+    * Add a multi flag for record attrs
+    
+    We pre-coordinate which record attrs are allowed to be multi-valued
+    with this new bool.  Most can be, we set the default to true and
+    adjust the seed data for those that should be false (sorters and
+    fields in the leader).
+    
+    * New intarray-focused attribute extraction
+    
+    We rewrite the record attribute extraction to capture all the
+    record-supplied values for each attribute (where multi is true)
+    and store that list in the new (fkey-corrected) metabib.record_attr_vector_list
+    table.  Only filters make it into this table.
+    
+    We also insert a parameter after the record id to accept a list of
+    record attributes we want to rewrite. This defaults to NULL to rewrite
+    all of them.
+    
+    Sorters are stored in a new, separate table built specifically for them.
+    
+    metabib.record_attr becomes a vew atop metabib.record_attr_vector_list
+    which expands the intarray stored therein into an hstore. For
+    multi=true attributes, only one will be returned through this view,
+    as is HSTORE's way, and which will be returned is undefined.  However
+    this view is only provided for the purpose of backward compat with
+    reports or other locally defined logic.
+    
+    And, finally, baseline seed data
+    
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+7	0	Open-ILS/src/sql/Pg/002.schema.config.sql
+20	20	Open-ILS/src/sql/Pg/012.schema.vandelay.sql
+343	90	Open-ILS/src/sql/Pg/030.schema.metabib.sql
+189	8	Open-ILS/src/sql/Pg/950.data.seed-values.sql
+1	0	Open-ILS/src/sql/Pg/create_database_extensions.sql
+
+commit 0bb4915e5129c21a2600eb28205a8f111cba1f2b
+Author: Remington Steed <rjs7 at calvin.edu>
+Date:   Fri Feb 21 09:54:47 2014 -0500
+
+    Fix syntax error in seed data
+    
+    Signed-off-by: Remington Steed <rjs7 at calvin.edu>
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+1	1	Open-ILS/src/sql/Pg/950.data.seed-values.sql
+
+commit 29304452c4e2096851bc77649d1f93fe6f71de53
+Author: Dan Wells <dbw2 at calvin.edu>
+Date:   Thu Feb 20 16:35:21 2014 -0500
+
+    Stamping 0863 - Stripe credit card payment options
+    
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+1	1	Open-ILS/src/sql/Pg/002.schema.config.sql
+51	0	Open-ILS/src/sql/Pg/upgrade/0863.data.stripe-payments.sql
+0	51	Open-ILS/src/sql/Pg/upgrade/XXXX.data.stripe-payments.sql
+ create mode 100644 Open-ILS/src/sql/Pg/upgrade/0863.data.stripe-payments.sql
+ delete mode 100644 Open-ILS/src/sql/Pg/upgrade/XXXX.data.stripe-payments.sql
+
+commit 93eb1aedf289963d480f7c31a177782a5abd6d6a
+Author: Lebbeous Fogle-Weekley <lebbeous at esilibrary.com>
+Date:   Fri Oct 11 01:13:44 2013 -0400
+
+    Release note for Stripe payment support
+    
+    Signed-off-by: Lebbeous Fogle-Weekley <lebbeous at esilibrary.com>
+    Signed-off-by: Remington Steed <rjs7 at calvin.edu>
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+36	0	docs/RELEASE_NOTES_NEXT/OPAC/stripe_payments.txt
+ create mode 100644 docs/RELEASE_NOTES_NEXT/OPAC/stripe_payments.txt
+
+commit af47ebafaaca04aef6fe00d01bcd6278eb3e3c8a
+Author: Lebbeous Fogle-Weekley <lebbeous at esilibrary.com>
+Date:   Thu Sep 19 11:00:00 2013 -0400
+
+    Support Stripe payments with some new code and some rearranged code ...
+    
+    ... behind the open-ils.circ.money.payment method.
+    
+    - Also add Business::Stripe as a CPAN module to the pre-reqs installers.
+    - If payment processor is Stripe, only show form if Javascript enabled.
+    
+    Our implementation of payments via Stripe doesn't work without Javascript.
+    That's part of the point. Using Stripe really limits a site's worries
+    about PCI compliance because users' credit card number and security
+    codes are never transmitted to the [Evergreen] server at all.  That data
+    goes to Stripe instead (using Javascript) and from that we get back a
+    one-time token from Stripe to give to our server instead.
+    
+    Thanks to Jason Boyer at the Indiana State Library for recognizing the
+    value of supporting approaches like that in Evergreen and for starting
+    the work.
+    
+    Signed-off-by: Lebbeous Fogle-Weekley <lebbeous at esilibrary.com>
+    
+    Conflicts:
+    	Open-ILS/src/templates/opac/myopac/main_payment_form.tt2
+    
+    Signed-off-by: Remington Steed <rjs7 at calvin.edu>
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+1	0	Open-ILS/src/extras/install/Makefile.debian-squeeze
+1	0	Open-ILS/src/extras/install/Makefile.debian-wheezy
+1	0	Open-ILS/src/extras/install/Makefile.fedora
+1	0	Open-ILS/src/extras/install/Makefile.ubuntu-lucid
+1	0	Open-ILS/src/extras/install/Makefile.ubuntu-precise
+1	37	Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/CreditCard.pm
+149	33	Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Money.pm
+1	1	Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Account.pm
+2	1	Open-ILS/src/templates/opac/myopac/main_pay.tt2
+22	11	Open-ILS/src/templates/opac/myopac/main_payment_form.tt2
+2	2	Open-ILS/src/templates/opac/parts/base.tt2
+4	0	Open-ILS/src/templates/opac/parts/js.tt2
+3	6	Open-ILS/src/templates/opac/parts/stripe.tt2
+
+commit a153ad569a0ff9fda10f3c3769c37d6aea200100
+Author: Lebbeous Fogle-Weekley <lebbeous at esilibrary.com>
+Date:   Thu Sep 19 09:51:47 2013 -0400
+
+    DB upgrade script for Stripe payments; seed data; minor template fixes
+    
+    Signed-off-by: Lebbeous Fogle-Weekley <lebbeous at esilibrary.com>
+    
+    Conflicts:
+    	Open-ILS/src/templates/opac/myopac/main_payment_form.tt2
+    
+    Signed-off-by: Remington Steed <rjs7 at calvin.edu>
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+4	4	Open-ILS/src/sql/Pg/950.data.seed-values.sql
+51	0	Open-ILS/src/sql/Pg/upgrade/XXXX.data.stripe-payments.sql
+6	7	Open-ILS/src/templates/opac/myopac/main_payment_form.tt2
+3	1	Open-ILS/src/templates/opac/parts/stripe.tt2
+ create mode 100644 Open-ILS/src/sql/Pg/upgrade/XXXX.data.stripe-payments.sql
+
+commit cdbcc32c5ae433b3c287079eaaa0773b547615bf
+Author: Jason Boyer <JBoyer1 at library.in.gov>
+Date:   Thu Sep 19 09:45:25 2013 -0400
+
+    Separate stripe js into stripe.tt2, add seed data for ou settings
+    
+    Signed-off-by: Remington Steed <rjs7 at calvin.edu>
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+27	0	Open-ILS/src/sql/Pg/950.data.seed-values.sql
+2	35	Open-ILS/src/templates/opac/parts/base.tt2
+36	0	Open-ILS/src/templates/opac/parts/stripe.tt2
+ create mode 100644 Open-ILS/src/templates/opac/parts/stripe.tt2
+
+commit 18ba41d6913e74de1ce86ca9fe30a16b18feb364
+Author: Jason Boyer <JBoyer1 at library.in.gov>
+Date:   Thu Sep 19 09:16:30 2013 -0400
+
+    Rough draft of integrating Stripe support into the opac payment page.
+    
+    Conflicts:
+    	Open-ILS/src/templates/opac/myopac/main_payment_form.tt2
+    	Open-ILS/src/templates/opac/parts/base.tt2
+    
+    Signed-off-by: Remington Steed <rjs7 at calvin.edu>
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+38	22	Open-ILS/src/templates/opac/myopac/main_payment_form.tt2
+38	3	Open-ILS/src/templates/opac/parts/base.tt2
+
+commit bc33a3e8c8a4313849ea3a1775c3d30cabf946a3
+Author: Dan Wells <dbw2 at calvin.edu>
+Date:   Thu Feb 20 10:01:46 2014 -0500
+
+    Duplicate 0851 as 0862 for backport clarity
+    
+    Rather than backport 0851 after 0852 has already been backported,
+    let's give 0851 a second number.  It probably wouldn't have bitten
+    anyone, but there's no harm in running this upgrade again, and I
+    don't think it hurts to be extra clear.
+    
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+1	1	Open-ILS/src/sql/Pg/002.schema.config.sql
+358	0	Open-ILS/src/sql/Pg/upgrade/0862.function.remove_extra_utf8_decodes.sql
+ create mode 100644 Open-ILS/src/sql/Pg/upgrade/0862.function.remove_extra_utf8_decodes.sql
+
+commit c0c10611404f55ef1d1146de053854b17e9b66ab
+Author: Ben Shum <bshum at biblio.org>
+Date:   Wed Feb 19 14:39:06 2014 -0500
+
+    LP1223903 - Also bump the schema config
+    
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+
+1	1	Open-ILS/src/sql/Pg/002.schema.config.sql
+
+commit c0a0fc6e1298bf8921e0cb15039763127b1b70fe
+Author: Ben Shum <bshum at biblio.org>
+Date:   Wed Feb 19 14:22:37 2014 -0500
+
+    LP1223903 - Stamping upgrade script for new authority_record_entry indexes
+    
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+
+8	0	Open-ILS/src/sql/Pg/upgrade/0861.index.authority_record_entry.sql
+0	2	Open-ILS/src/sql/Pg/upgrade/XXXX.index.authority_record_entry.sql
+ create mode 100644 Open-ILS/src/sql/Pg/upgrade/0861.index.authority_record_entry.sql
+ delete mode 100644 Open-ILS/src/sql/Pg/upgrade/XXXX.index.authority_record_entry.sql
+
+commit e495dbb7811b35dbae4e121ff5dbf3b33550d619
+Author: Jason Stephenson <jstephenson at mvlc.org>
+Date:   Thu Feb 6 11:18:49 2014 -0500
+
+    LP1223903 - Add release notes for rewrite of marc_export.
+    
+    Signed-off-by: Jason Stephenson <jstephenson at mvlc.org>
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+
+39	0	docs/RELEASE_NOTES_NEXT/Cataloging/marc_export_replacement.txt
+ create mode 100644 docs/RELEASE_NOTES_NEXT/Cataloging/marc_export_replacement.txt
+
+commit 2c28f9b728425e46e00c3ff11583206b9f1ca14c
+Author: Jason Stephenson <jstephenson at mvlc.org>
+Date:   Wed Feb 5 11:24:05 2014 -0500
+
+    LP1223903 - Rewrite marc_export.in in support-scripts.
+    
+    This commit rewrites marc_export.in in the support-scripts  src directory.
+    It will still be transformed into marc_export at build time.  This change
+    replaces the current marc_export scipt with a faster, DBI based alternative.
+    
+    The replacement support nearly all of the features of the original, except
+    for the progress output.  Much of this information is harder to gather
+    with the new design.
+    
+    This is a squashed, rebased commit of previous work.
+    
+    Signed-off-by: Jason Stephenson <jstephenson at mvlc.org>
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+
+698	313	Open-ILS/src/support-scripts/marc_export.in
+
+commit 1108b8b634cf60cedf9bb7e722146a9ea08e1dd2
+Author: Jason Stephenson <jstephenson at mvlc.org>
+Date:   Tue Dec 10 15:16:21 2013 -0500
+
+    LP1223903 - Add indexes to authority.record_entry.
+    
+    We want indexes on edit_date and create_date for authority.record_entry
+    so that date-based searching is faster for authority record export.  It
+    likely will prove useful for other features.
+    
+    Signed-off-by: Jason Stephenson <jstephenson at mvlc.org>
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+
+2	0	Open-ILS/src/sql/Pg/011.schema.authority.sql
+2	0	Open-ILS/src/sql/Pg/upgrade/XXXX.index.authority_record_entry.sql
+ create mode 100644 Open-ILS/src/sql/Pg/upgrade/XXXX.index.authority_record_entry.sql
+
+commit b9edf30f9f2e5bcda86c4724496e6261b64148a0
+Author: Jason Stephenson <jstephenson at mvlc.org>
+Date:   Thu Sep 26 01:53:35 2013 -0400
+
+    LP1223903 - Add from_bare_hash to Fieldmapper.pm.
+    
+    Teach the Perl Fieldmapper.pm to build objects from a hashref in a
+    similar manner to how the JS Fieldmapper already can.  You might use
+    it if you retrieved a database row as a hashref, like so:
+    
+    my $hashref = {};
+    my $class = Fieldmapper::class_for_hint('bre');
+    my $bre = $class->from_bare_hash($hashref);
+    
+    We also modify the Fieldmapper's properties method to sort the array of
+    field names it returns by position.  This makes the return value a lot
+    more useful for on the fly object construction and other fancy tricks.
+    
+    Signed-off-by: Jason Stephenson <jstephenson at mvlc.org>
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+
+15	1	Open-ILS/src/perlmods/lib/OpenILS/Utils/Fieldmapper.pm
+
+commit 6c16a446894d47776ec336115c096b165ffe4b6a
+Author: Bill Erickson <berick at esilibrary.com>
+Date:   Wed Feb 19 10:22:37 2014 -0500
+
+    LP#1262722 Fix DB supersedes/deprecates pgtap test
+    
+    Sort multi-value arrays before passing them off to pgtap for test
+    comparison. Otherwise, pgtap tests may fail with:
+    
+    Failed test 5
+            have: {AAAC,AAAB}
+            want: {AAAB,AAAC}
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Jeff Godin <jgodin at tadl.org>
+
+8	1	Open-ILS/src/sql/Pg/t/db_patch_dep_checks.pg
+
+commit 4be795262dc199453a4e632f19d8a5f8aa94d01c
+Author: Mike Rylander <mrylander at gmail.com>
+Date:   Tue Feb 18 13:01:08 2014 -0500
+
+    Stamping upgrade script for supsersede/deprecate logic fixes
+    
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+
+1	1	Open-ILS/src/sql/Pg/002.schema.config.sql
+64	0	Open-ILS/src/sql/Pg/upgrade/0860.schema.deprecate-supersede-check-repairs.sql
+0	58	Open-ILS/src/sql/Pg/upgrade/XXXX.schema.deprecate-supersede-check-repairs.sql
+ create mode 100644 Open-ILS/src/sql/Pg/upgrade/0860.schema.deprecate-supersede-check-repairs.sql
+ delete mode 100644 Open-ILS/src/sql/Pg/upgrade/XXXX.schema.deprecate-supersede-check-repairs.sql
+
+commit b7f0b1da24b626c92d84245298b228d37cb6ca60
+Author: Bill Erickson <berick at esilibrary.com>
+Date:   Thu Dec 19 10:27:26 2013 -0500
+
+    DB patch supersede/deprecate logic repairs; unit tests
+    
+    * Fix some thinkos in the various DB functions for calculating
+      supersedes/deprecation logic.
+    
+    * Added a pgtap test
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+
+5	5	Open-ILS/src/sql/Pg/002.schema.config.sql
+36	0	Open-ILS/src/sql/Pg/t/db_patch_dep_checks.pg
+58	0	Open-ILS/src/sql/Pg/upgrade/XXXX.schema.deprecate-supersede-check-repairs.sql
+ create mode 100644 Open-ILS/src/sql/Pg/t/db_patch_dep_checks.pg
+ create mode 100644 Open-ILS/src/sql/Pg/upgrade/XXXX.schema.deprecate-supersede-check-repairs.sql
+
+commit 6d750a0023cc1197b460d2e254d1ba89c376f18a
+Author: Mike Rylander <mrylander at gmail.com>
+Date:   Tue Feb 18 12:47:42 2014 -0500
+
+    Stamping upgrade for Granular Staff Initials settings
+    
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+
+1	1	Open-ILS/src/sql/Pg/002.schema.config.sql
+94	0	Open-ILS/src/sql/Pg/upgrade/0859.data.staff-initials-settings.sql
+0	94	Open-ILS/src/sql/Pg/upgrade/XXXX.data.staff-initials-settings.sql
+ create mode 100644 Open-ILS/src/sql/Pg/upgrade/0859.data.staff-initials-settings.sql
+ delete mode 100644 Open-ILS/src/sql/Pg/upgrade/XXXX.data.staff-initials-settings.sql
+
+commit 4583dd596b9fee642049ba4206bd44a5428f71b3
+Author: Ben Shum <bshum at biblio.org>
+Date:   Tue May 28 14:54:27 2013 -0400
+
+    Add granular settings for requiring staff initials for notes
+    
+    Up till now, there has only been one setting for making staff initials required
+    for all of the various note fields. Instead, let's break this up into separate
+    org unit settings for each type of note field, giving us more flexiblity in
+    making use of the append staff initials feature.
+    
+    These three types of notes will now have settings to add initials for each:
+    
+    - patron penalties/messages
+    - patron information notes
+    - copy (item) notes
+    
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+
+23	5	Open-ILS/src/sql/Pg/950.data.seed-values.sql
+94	0	Open-ILS/src/sql/Pg/upgrade/XXXX.data.staff-initials-settings.sql
+1	1	Open-ILS/xul/staff_client/server/cat/copy_notes.xul
+1	1	Open-ILS/xul/staff_client/server/patron/edit_standing_penalty.js
+1	1	Open-ILS/xul/staff_client/server/patron/info_notes.xul
+1	1	Open-ILS/xul/staff_client/server/patron/new_standing_penalty.js
+18	0	docs/RELEASE_NOTES_NEXT/Administration/staff-initials.txt
+ create mode 100644 Open-ILS/src/sql/Pg/upgrade/XXXX.data.staff-initials-settings.sql
+ create mode 100644 docs/RELEASE_NOTES_NEXT/Administration/staff-initials.txt
+
+commit 30096667a05670ba6c3a80eb3038be905c66f2d3
+Author: Lebbeous Fogle-Weekley <lebbeous at esilibrary.com>
+Date:   Tue Feb 18 12:15:18 2014 -0500
+
+    LP#1272074 Physical Characteristics Wizard for the MARC Editor (Part II)
+    
+    These files should have been in the other commit with the above title,
+    but I lost them in a rebase effort.
+    
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+523	0	Open-ILS/web/js/dojo/openils/widget/PhysCharWizard.js
+15	0	Open-ILS/web/js/dojo/openils/widget/nls/PhysCharWizard.js
+ create mode 100644 Open-ILS/web/js/dojo/openils/widget/PhysCharWizard.js
+ create mode 100644 Open-ILS/web/js/dojo/openils/widget/nls/PhysCharWizard.js
+
+commit 3eee581dd7ba3f0c9acb5522cc7c8c32d262184d
+Author: Dan Wells <dbw2 at calvin.edu>
+Date:   Tue Feb 18 12:01:29 2014 -0500
+
+    Stamping 0858: Fixed field enhancements
+    
+    Also, move test file to a possibly better location.
+    
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+1	1	Open-ILS/src/sql/Pg/002.schema.config.sql
+0	65	Open-ILS/src/sql/Pg/live_t/XXXX.fixed_field_enhancements.pg
+65	0	Open-ILS/src/sql/Pg/t/regress/lp1272074_0858_fixed_field_enhancements.pg
+11	0	Open-ILS/src/sql/Pg/upgrade/0858.data.fixed_field_enhancements.sql
+0	11	Open-ILS/src/sql/Pg/upgrade/XXXX.data.fixed_field_enhancements.sql
+ delete mode 100644 Open-ILS/src/sql/Pg/live_t/XXXX.fixed_field_enhancements.pg
+ create mode 100644 Open-ILS/src/sql/Pg/t/regress/lp1272074_0858_fixed_field_enhancements.pg
+ create mode 100644 Open-ILS/src/sql/Pg/upgrade/0858.data.fixed_field_enhancements.sql
+ delete mode 100644 Open-ILS/src/sql/Pg/upgrade/XXXX.data.fixed_field_enhancements.sql
+
+commit df26f9e2ecdabe8e76e318941e7c093ae8602318
+Author: Lebbeous Fogle-Weekley <lebbeous at esilibrary.com>
+Date:   Thu Jan 23 16:02:02 2014 -0500
+
+    LP#1272074 Release notes (with pictures!) of fixed fields MARC editor enhancements
+    
+    Signed-off-by: Lebbeous Fogle-Weekley <lebbeous at esilibrary.com>
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+98	0	docs/RELEASE_NOTES_NEXT/Cataloging/fixed_fields_enhancements.txt
+-	-	docs/media/ffer-007-00.png
+-	-	docs/media/ffer-007-smd.png
+-	-	docs/media/ffer-open-wizard.png
+-	-	docs/media/ffer-record-type.png
+-	-	docs/media/ffer-right-click.png
+ create mode 100644 docs/RELEASE_NOTES_NEXT/Cataloging/fixed_fields_enhancements.txt
+ create mode 100644 docs/media/ffer-007-00.png
+ create mode 100644 docs/media/ffer-007-smd.png
+ create mode 100644 docs/media/ffer-open-wizard.png
+ create mode 100644 docs/media/ffer-record-type.png
+ create mode 100644 docs/media/ffer-right-click.png
+
+commit 35cca918cedf4a6d07b0aa274677c37d84b053fc
+Author: Lebbeous Fogle-Weekley <lebbeous at esilibrary.com>
+Date:   Mon Nov 18 12:31:47 2013 -0500
+
+    LP#1272074 Fix faulty physical characteristics seed data
+    
+    For 007 (00/a=f), "subfield" e (Level of contraction) starts at position
+    5, not 4.
+    
+    Signed-off-by: Lebbeous Fogle-Weekley <lebbeous at esilibrary.com>
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+1	1	Open-ILS/src/sql/Pg/950.data.seed-values.sql
+65	0	Open-ILS/src/sql/Pg/live_t/XXXX.fixed_field_enhancements.pg
+11	0	Open-ILS/src/sql/Pg/upgrade/XXXX.data.fixed_field_enhancements.sql
+ create mode 100644 Open-ILS/src/sql/Pg/live_t/XXXX.fixed_field_enhancements.pg
+ create mode 100644 Open-ILS/src/sql/Pg/upgrade/XXXX.data.fixed_field_enhancements.sql
+
+commit b11902269b05f5da847cbb51a23fdf2046dea1ca
+Author: Lebbeous Fogle-Weekley <lebbeous at esilibrary.com>
+Date:   Tue Nov 12 17:51:57 2013 -0500
+
+    LP#1272074 Physical Characteristics Wizard for the MARC Editor
+    
+    Right-click in an 007 field to find a new entry in the context menu that
+    launches this wizard.  The prompts and suggested values come from data
+    already found in the database.
+    
+    Signed-off-by: Lebbeous Fogle-Weekley <lebbeous at esilibrary.com>
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+2	0	Open-ILS/web/opac/locale/en-US/lang.dtd
+2	1	Open-ILS/xul/staff_client/chrome/content/cat/opac.js
+1	0	Open-ILS/xul/staff_client/chrome/content/main/constants.js
+48	2	Open-ILS/xul/staff_client/server/cat/marcedit.js
+3	0	Open-ILS/xul/staff_client/server/cat/marcedit.xul
+
+commit 7e12a0c8d7eacdbd8ca454b55678ae256408bcde
+Author: Lebbeous Fogle-Weekley <lebbeous at esilibrary.com>
+Date:   Mon Nov 11 17:52:03 2013 -0500
+
+    LP#1272074 Context menus suggesting values for marc fixed field editor
+    
+    Signed-off-by: Lebbeous Fogle-Weekley <lebbeous at esilibrary.com>
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+57	0	Open-ILS/src/perlmods/lib/OpenILS/Application/Cat.pm
+111	0	Open-ILS/xul/staff_client/server/cat/marcedit.js
+
+commit 7e459294d1e49c0e3397b897fb4d4b733a23bb99
+Author: Bill Erickson <berick at esilibrary.com>
+Date:   Tue Feb 18 08:53:59 2014 -0500
+
+    LP#1187035 Remove OpenILS::Utils::Editor part 4.
+    
+    Make sure all CStoreEditors in ClosedDates run updates in transactions,
+    roll back transactions on error, and commit the transactions on success.
+    
+    Added a live test for closed data updating.
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Jeff Godin <jgodin at tadl.org>
+
+15	13	Open-ILS/src/perlmods/lib/OpenILS/Application/Actor/ClosedDates.pm
+17	1	Open-ILS/src/perlmods/live_t/04-overdue_with_closed_dates.t
+
+commit 8eda1c2ab441ca2e26c6b8b18675860e890746e4
+Author: Jeff Godin <jgodin at tadl.org>
+Date:   Mon Feb 17 22:31:28 2014 -0500
+
+    LP#1187035 Remove OpenILS::Utils::Editor part 3.
+    
+    Remove obsolete lib/OpenILS/Utils/Editor.pm from MANIFEST.
+    
+    Signed-off-by: Jeff Godin <jgodin at tadl.org>
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+
+0	1	Open-ILS/src/perlmods/MANIFEST
+
+commit bb222e7580187965e3e722a76505ee634beb5987
+Author: Bill Erickson <berick at esilibrary.com>
+Date:   Thu Jun 6 09:21:37 2013 -0400
+
+    LP#1187035 Remove OpenILS::Utils::Editor part 2.
+    
+    * Address 2 places where we were calling $e->request with a
+     CStoreEditor for a storage method.  Since CStoreEditor assumes all
+     calls go to open-ils.cstore, these would have failed.
+    
+    * While we're in a cleaning mood, remove some obsolete commented code.
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Jeff Godin <jgodin at tadl.org>
+
+6	2	Open-ILS/src/perlmods/lib/OpenILS/Application/Circ.pm
+6	2	Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/NonCat.pm
+0	4	Open-ILS/src/perlmods/lib/OpenILS/Application/Search/Zips.pm
+
+commit 0199ecdf97d6651bfb423310e7f20e10b20e151b
+Author: Jeff Godin <jgodin at tadl.org>
+Date:   Sat Jun 1 00:35:37 2013 -0400
+
+    LP#1187035 Remove OpenILS::Utils::Editor
+    
+    OpenILS::Utils::Editor is obsolete, yet still referenced in a number
+    of places. Let's remove it.
+    
+    Signed-off-by: Jeff Godin <jgodin at tadl.org>
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+
+1	1	Open-ILS/src/perlmods/lib/OpenILS/Application/Actor/ClosedDates.pm
+3	4	Open-ILS/src/perlmods/lib/OpenILS/Application/Circ.pm
+1	2	Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/NonCat.pm
+0	4	Open-ILS/src/perlmods/lib/OpenILS/Application/Search/Biblio.pm
+1	2	Open-ILS/src/perlmods/lib/OpenILS/Application/Search/Zips.pm
+0	544	Open-ILS/src/perlmods/lib/OpenILS/Utils/Editor.pm
+1	2	Open-ILS/src/perlmods/t/14-OpenILS-Utils.t
+ delete mode 100644 Open-ILS/src/perlmods/lib/OpenILS/Utils/Editor.pm
+
+commit 1fefe2cecb464ea10ff4a2d0e673c2663bab086a
+Author: Jason Etheridge <jason at esilibrary.com>
+Date:   Fri Jan 24 17:51:45 2014 -0500
+
+    LP#1272575 Use getElementById over querySelector
+    
+    Favor document.getElementById over document.querySelector for simple
+    by-id element referencing.
+    
+    Signed-off-by: Jason Etheridge <jason at esilibrary.com>
+    Signed-off-by: Jeff Godin <jgodin at tadl.org>
+
+4	4	Open-ILS/src/templates/opac/parts/result/table.tt2
+
+commit 796ed67e12b1aa5cb88a8519e2e8228fbfa2726c
+Author: Pasi Kallinen <pasi.kallinen at pttk.fi>
+Date:   Tue May 28 10:45:02 2013 +0300
+
+    LP#1184885 ACQ: i18n for search abbreviations
+    
+    Allow translating the Acq Search dropdown class name abbreviations.
+    
+    Signed-off-by: Pasi Kallinen <pasi.kallinen at pttk.fi>
+    Signed-off-by: Jeff Godin <jgodin at tadl.org>
+
+6	0	Open-ILS/web/js/dojo/openils/acq/nls/acq.js
+4	2	Open-ILS/web/js/ui/default/acq/search/unified.js
+
+commit a380379e291f1b0d42f15a1875c172fd2dc6892f
+Author: Bill Erickson <berick at esilibrary.com>
+Date:   Mon Feb 17 17:14:37 2014 -0500
+
+    LP#1187029 release notes typo repair for ingest cleanup
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+
+1	1	docs/RELEASE_NOTES_NEXT/removal_of_ingest.txt
+
+commit bc073517f19e89028feb5921d6c438beb5430d5c
+Author: Jeff Godin <jgodin at tadl.org>
+Date:   Tue May 7 15:58:51 2013 -0400
+
+    LP#1187029 Remove unused open-ils.ingest service
+    
+    Remove open-ils.ingest service and related scripts and code.
+    
+    In addition to removing OpenILS::Application::Ingest, this commit
+    removes code that was commented out at the time of open-ils.ingest's
+    replacement with in-db ingest, example configuration elements, a
+    use_ok test, and the following obsolete scripts which made use of or
+    were otherwise related to open-ils.ingest:
+    
+    * Open-ILS/src/extras/import/direct_ingest.pl
+    * Open-ILS/src/extras/import/generate-srfsh-indexer.pl
+    * Open-ILS/src/extras/import/importer.sh
+    
+    The included release notes recommend removal of the open-ils.ingest service
+    from configuration files when upgrading, and suggest removal of Ingest.pm from
+    its location in @INC.
+    
+    Signed-off-by: Jeff Godin <jgodin at tadl.org>
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+
+0	28	Open-ILS/examples/opensrf.xml.example
+0	122	Open-ILS/src/extras/import/direct_ingest.pl
+0	30	Open-ILS/src/extras/import/generate-srfsh-indexer.pl
+0	36	Open-ILS/src/extras/import/importer.sh
+0	1	Open-ILS/src/perlmods/MANIFEST
+0	6	Open-ILS/src/perlmods/lib/OpenILS/Application/Cat.pm
+0	8	Open-ILS/src/perlmods/lib/OpenILS/Application/Cat/AuthCommon.pm
+0	1453	Open-ILS/src/perlmods/lib/OpenILS/Application/Ingest.pm
+1	2	Open-ILS/src/perlmods/t/01-OpenILS-Application.t
+21	0	docs/RELEASE_NOTES_NEXT/removal_of_ingest.txt
+ delete mode 100755 Open-ILS/src/extras/import/direct_ingest.pl
+ delete mode 100755 Open-ILS/src/extras/import/generate-srfsh-indexer.pl
+ delete mode 100755 Open-ILS/src/extras/import/importer.sh
+ delete mode 100644 Open-ILS/src/perlmods/lib/OpenILS/Application/Ingest.pm
+ create mode 100644 docs/RELEASE_NOTES_NEXT/removal_of_ingest.txt
+
+commit 60ee958d1ea29a2f5ad4fba40936ef022164c36c
+Author: Jeff Godin <jgodin at tadl.org>
+Date:   Fri May 31 22:47:49 2013 -0400
+
+    LP#1187034 Remove obsolete collections code
+    
+    Remove obsolete collections code
+    
+    Specifically:
+    
+    open-ils.collections.users_owing_money.retrieve
+    open-ils.storage.money.collections.users_owing_money
+    
+    Signed-off-by: Jeff Godin <jgodin at tadl.org>
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+
+0	75	Open-ILS/src/perlmods/lib/OpenILS/Application/Collections.pm
+0	95	Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Publisher/money.pm
+
+commit be5803f14b193e0f39b50731624c6206baa08bb1
+Author: Jeff Godin <jgodin at tadl.org>
+Date:   Mon Feb 17 17:12:33 2014 +0000
+
+    Stamping 0857 for located uri visibility changes
+    
+    Stamping 0857 for located uri visibility changes, also adjusting
+    upgrade script to use ARRAY_AGG over ARRAY_ACCUM (which recently
+    landed in master).
+    
+    LP 1271630 Allow Located URIs to supply copy-like visibility to bibs
+    https://bugs.launchpad.net/evergreen/+bug/1271630
+    
+    LP 874296  Replace ARRAY_ACCUM with ARRAY_AGG (and STRING_AGG)
+    https://bugs.launchpad.net/evergreen/+bug/874296
+    
+    Signed-off-by: Jeff Godin <jgodin at tadl.org>
+
+1	1	Open-ILS/src/sql/Pg/002.schema.config.sql
+508	0	Open-ILS/src/sql/Pg/upgrade/0857.function.located_uris_act_as_copies.sql
+0	506	Open-ILS/src/sql/Pg/upgrade/XXXX.function.located_uris_act_as_copies.sql
+ create mode 100644 Open-ILS/src/sql/Pg/upgrade/0857.function.located_uris_act_as_copies.sql
+ delete mode 100644 Open-ILS/src/sql/Pg/upgrade/XXXX.function.located_uris_act_as_copies.sql
+
+commit e4cbe67a9bd8788f8e750c8ca298489e05749cd2
+Author: Mike Rylander <mrylander at gmail.com>
+Date:   Thu Jan 23 10:40:16 2014 -0500
+
+    Release notes
+    
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+    Signed-off-by: Jeff Godin <jgodin at tadl.org>
+
+21	0	docs/RELEASE_NOTES_NEXT/OPAC/Located_URI_visibility.txt
+ create mode 100644 docs/RELEASE_NOTES_NEXT/OPAC/Located_URI_visibility.txt
+
+commit 169805f66636b9eecf043b3d9e1bb5dc6094381f
+Author: Mike Rylander <mrylander at gmail.com>
+Date:   Fri Feb 7 10:27:11 2014 -0500
+
+    Teach evergreen.located_uris() about the new URI visiblity flag
+    
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+    Signed-off-by: Jeff Godin <jgodin at tadl.org>
+
+17	8	Open-ILS/src/sql/Pg/990.schema.unapi.sql
+33	0	Open-ILS/src/sql/Pg/upgrade/XXXX.function.located_uris_act_as_copies.sql
+
+commit 3f6d29e7619e52642db0ab7d7a53b4eefcc9c418
+Author: Mike Rylander <mrylander at gmail.com>
+Date:   Wed Jan 22 11:09:33 2014 -0500
+
+    Upgrade script
+    
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+    Signed-off-by: Jeff Godin <jgodin at tadl.org>
+
+473	0	Open-ILS/src/sql/Pg/upgrade/XXXX.function.located_uris_act_as_copies.sql
+ create mode 100644 Open-ILS/src/sql/Pg/upgrade/XXXX.function.located_uris_act_as_copies.sql
+
+commit b11cd783e94c73b886229a574dc28c93ecb3b88b
+Author: Mike Rylander <mrylander at gmail.com>
+Date:   Wed Jan 22 11:06:50 2014 -0500
+
+    Global flag for setting Located URI behavioral mode
+    
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+    Signed-off-by: Jeff Godin <jgodin at tadl.org>
+
+12	0	Open-ILS/src/sql/Pg/950.data.seed-values.sql
+
+commit 091d78ad18ba311457c82dab3579444a3f6ecc89
+Author: Mike Rylander <mrylander at gmail.com>
+Date:   Wed Jan 22 11:00:24 2014 -0500
+
+    Check behavioral setting for Located URIs
+    
+    When the opac.located_uri.act_as_copy Global Flag is enabled, treat
+    Located URIs like copies for visibility testing purposes.  We use
+    actor.org_unit_full_path instead of actor.org_unit_descendants so
+    that we do not lose the desirable "licensed here" modeling that
+    Located URIs provide.
+    
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+    Signed-off-by: Jeff Godin <jgodin at tadl.org>
+
+21	3	Open-ILS/src/sql/Pg/300.schema.staged_search.sql
+
+commit 1f023b6b4ac489e296c18d222d9c1e1cdb490962
+Author: Mike Rylander <mrylander at gmail.com>
+Date:   Thu Dec 12 17:08:17 2013 -0500
+
+    evergreen.located_uris() returns a rank, and we should use it
+    
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+    Signed-off-by: Jeff Godin <jgodin at tadl.org>
+
+1	1	Open-ILS/src/sql/Pg/990.schema.unapi.sql
+
+commit 0ec0ddcbf19384858460c57784d97768ffe050d3
+Author: Chris Sharp <csharp at georgialibraries.org>
+Date:   Tue Nov 26 12:00:42 2013 -0500
+
+    Change "Alias" to "Holds Alias" in Patron Search.
+    
+    This same field is referred to as "OPAC/Staff Client Holds Alias" in
+    the Register Patron interface.  This change is for consistency in labeling.
+    
+    Signed-off-by: Chris Sharp <csharp at georgialibraries.org>
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+
+1	1	Open-ILS/web/opac/locale/en-US/lang.dtd
+
+commit c317a6ec9450119fc75c2510f6e01f6f30b184f5
+Author: Jeff Godin <jgodin at tadl.org>
+Date:   Wed Jan 22 23:40:50 2014 -0500
+
+    Release notes for "Update Expire Date" button
+    
+    Add release notes for "Update Expire Date" button in user editor.
+    
+    Signed-off-by: Jeff Godin <jgodin at tadl.org>
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+
+17	0	docs/RELEASE_NOTES_NEXT/Circulation/user_editor_update_expire_date_button.txt
+ create mode 100644 docs/RELEASE_NOTES_NEXT/Circulation/user_editor_update_expire_date_button.txt
+
+commit 6807a06a11d309e94dbc5e286e45a5fdd3eaecab
+Author: Jeff Godin <jgodin at tadl.org>
+Date:   Wed Oct 30 15:42:15 2013 -0400
+
+    Add button to update expire date field
+    
+    When updating/renewing a patron (expired or not), it would be
+    convenient to have a means of populating the expire date field with
+    a value of perm_interval + today. Currently, staff are required to
+    manually enter a date, or could toggle the profile from one profile
+    then back to the desired profile, but this is not ideal.
+    
+    This commit adds a new button next to the expire date, which when
+    activated will re-calculate the date based on the current profile's
+    perm_interval and today's date.
+    
+    This is similar to how the expire date is populated when creating a
+    new user, or when changing the profile group. A button is used here
+    so that the updating of the expire date is an intentional process,
+    not one that happens upon any edit.
+    
+    Signed-off-by: Jeff Godin <jgodin at tadl.org>
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+
+6	1	Open-ILS/src/templates/actor/user/register_table.tt2
+2	1	Open-ILS/web/js/dojo/openils/actor/nls/register.js
+25	0	Open-ILS/web/js/ui/default/actor/user/register.js
+
+commit c49b4d90cd4be6b157db8658e5d6cbb04ecf6c70
+Author: Ben Shum <bshum at biblio.org>
+Date:   Thu Feb 13 00:05:38 2014 -0500
+
+    Stamping upgrade for STRING_AGG fix for metabib.staged_browse()
+    
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+
+1	1	Open-ILS/src/sql/Pg/002.schema.config.sql
+212	0	Open-ILS/src/sql/Pg/upgrade/0856.schema.metabib_staged_browse.sql
+0	207	Open-ILS/src/sql/Pg/upgrade/XXXX.schema.metabib_staged_browse.sql
+ create mode 100644 Open-ILS/src/sql/Pg/upgrade/0856.schema.metabib_staged_browse.sql
+ delete mode 100644 Open-ILS/src/sql/Pg/upgrade/XXXX.schema.metabib_staged_browse.sql
+
+commit 497530956ab59cb627d1bde13d63103ac064468c
+Author: Dan Scott <dscott at laurentian.ca>
+Date:   Wed Feb 12 14:48:46 2014 -0500
+
+    STRING_AGG() fix for metabib.staged_browse()
+    
+    We need to supply TEXT values to STRING_AGG(), so cast the input INTEGER
+    accordingly.
+    
+    Also, I LIKE ALL-CAPS.
+    
+    Signed-off-by: Dan Scott <dscott at laurentian.ca>
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+
+3	3	Open-ILS/src/sql/Pg/030.schema.metabib.sql
+207	0	Open-ILS/src/sql/Pg/upgrade/XXXX.schema.metabib_staged_browse.sql
+ create mode 100644 Open-ILS/src/sql/Pg/upgrade/XXXX.schema.metabib_staged_browse.sql
+
+commit 598267dd0ad047f8b424a63e2bf2f44ed7e51bcd
+Author: Dan Scott <dscott at laurentian.ca>
+Date:   Tue Feb 11 10:50:38 2014 -0500
+
+    Release notes for WCAG compliance for the TPAC
+    
+    Super basic, but gives a pointer to the WCAG overview for
+    more information.
+    
+    Signed-off-by: Dan Scott <dscott at laurentian.ca>
+
+8	0	docs/RELEASE_NOTES_NEXT/OPAC/WCAG.txt
+ create mode 100644 docs/RELEASE_NOTES_NEXT/OPAC/WCAG.txt
+
+commit 40a5441e8efe575fab1219b2702bf0b86be24999
+Author: Bill Erickson <berick at esilibrary.com>
+Date:   Tue Feb 11 09:16:09 2014 -0500
+
+    LP#1268636 add expressive facet link titles
+    
+    Let the user know exactly what clicking on a facet will do.
+    
+    Thanks to Dan Scott for the suggestion.
+    
+    * Note that accessibility validators may dislike the repetitive titles,
+      but clearly adding them provides more information (for everyone).
+      Plus, as facets pile up, there's no reasonable way to differentiate
+      between all titles, anyway, without title attributes becoming too
+      long and unreadable.
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Dan Scott <dscott at laurentian.ca>
+
+11	3	Open-ILS/src/templates/opac/parts/result/facets.tt2
+
+commit 4cb854e866d373b276e47886b76a8668cdd2eef8
+Author: Dan Scott <dscott at laurentian.ca>
+Date:   Mon Feb 10 22:59:50 2014 -0500
+
+    Remove useless image-based fines border
+    
+    The images ended up looking like displaced blocks, but
+    aren't necessary anyway. If one really wants a border,
+    use CSS.
+    
+    Signed-off-by: Dan Scott <dscott at laurentian.ca>
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+
+0	24	Open-ILS/src/templates/opac/parts/myopac/main_base.tt2
+
+commit b1ce5b6650e0ee875a7919b84ea0543e0de2d2c6
+Author: Dan Scott <dscott at laurentian.ca>
+Date:   Mon Feb 10 22:54:17 2014 -0500
+
+    Remove extraneous ] in holds TPAC page
+    
+    Signed-off-by: Dan Scott <dscott at laurentian.ca>
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+
+1	1	Open-ILS/src/templates/opac/myopac/holds.tt2
+
+commit de175930957778ea54e318502083b1c46d76eb96
+Author: Bill Erickson <berick at esilibrary.com>
+Date:   Fri Jan 17 09:03:58 2014 -0500
+
+    LP#1268636 Add helpful empty search term message
+    
+    When a search is submitted with no query value, instead of silently
+    redirecting the user the home page, direct the user to the results page
+    and show a helpful message (within the low-hits template).
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Dan Scott <dscott at laurentian.ca>
+
+1	4	Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Search.pm
+5	1	Open-ILS/src/templates/opac/parts/result/lowhits.tt2
+
+commit d1ff8f87c6cbe6806b8f7e05f512553e7c5ac29c
+Author: Bill Erickson <berick at esilibrary.com>
+Date:   Fri Jan 17 09:01:38 2014 -0500
+
+    LP#1268636 improve fines warning color contrast
+    
+    Use the text_attention CSS color instead of the text_badnews for the my
+    account fines label, since the badnews color does not contrast highly
+    engouh with the dark green background for WCAG compliance.
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Dan Scott <dscott at laurentian.ca>
+
+8	0	Open-ILS/src/templates/opac/css/style.css.tt2
+
+commit 5960428a33b6ac3dfbd9e9fb0bc3687b2de43c1e
+Author: Bill Erickson <berick at esilibrary.com>
+Date:   Fri Jan 17 09:00:24 2014 -0500
+
+    LP#1268636 remove a few invalid attrs / unused tags
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Dan Scott <dscott at laurentian.ca>
+
+2	7	Open-ILS/src/templates/opac/parts/result/table.tt2
+
+commit 37880c146fa45d17e9c38349990bd309d9581468
+Author: Bill Erickson <berick at esilibrary.com>
+Date:   Wed Jan 15 13:58:52 2014 -0500
+
+    LP#1268636 additional myopac nav headers
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Dan Scott <dscott at laurentian.ca>
+
+1	0	Open-ILS/src/templates/opac/myopac/circ_history.tt2
+1	0	Open-ILS/src/templates/opac/myopac/circs.tt2
+1	0	Open-ILS/src/templates/opac/myopac/hold_history.tt2
+1	0	Open-ILS/src/templates/opac/myopac/holds.tt2
+1	0	Open-ILS/src/templates/opac/myopac/holds/edit.tt2
+1	0	Open-ILS/src/templates/opac/myopac/lists.tt2
+1	0	Open-ILS/src/templates/opac/myopac/main.tt2
+1	0	Open-ILS/src/templates/opac/myopac/main_payment_form.tt2
+1	0	Open-ILS/src/templates/opac/myopac/main_payments.tt2
+1	0	Open-ILS/src/templates/opac/myopac/prefs.tt2
+1	0	Open-ILS/src/templates/opac/myopac/prefs_my_lists.tt2
+2	1	Open-ILS/src/templates/opac/myopac/prefs_notify.tt2
+1	0	Open-ILS/src/templates/opac/myopac/prefs_settings.tt2
+1	0	Open-ILS/src/templates/opac/myopac/update_email.tt2
+1	0	Open-ILS/src/templates/opac/myopac/update_password.tt2
+1	0	Open-ILS/src/templates/opac/myopac/update_username.tt2
+4	3	Open-ILS/src/templates/opac/parts/bookbag_actions.tt2
+1	0	Open-ILS/src/templates/opac/parts/myopac/base.tt2
+
+commit 77c252fb12f804e4ab57beb24ea74e3b87419982
+Author: Bill Erickson <berick at esilibrary.com>
+Date:   Wed Jan 15 11:46:28 2014 -0500
+
+    LP#1268636 TPAC avoid <b> tags in pref lib msg
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Dan Scott <dscott at laurentian.ca>
+
+1	1	Open-ILS/src/templates/opac/parts/pref_lib_display.tt2
+
+commit 62ba91a8c8ff2e356e0b3434e983191b4fbf475e
+Author: Bill Erickson <berick at esilibrary.com>
+Date:   Wed Jan 15 11:42:42 2014 -0500
+
+    LP#1268636 TPAC more nav headers for search results
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Dan Scott <dscott at laurentian.ca>
+
+3	0	Open-ILS/src/templates/opac/parts/result/table.tt2
+1	0	Open-ILS/src/templates/opac/results.tt2
+
+commit ffda9748ee7e38d5e049ade9a9d59f7cd49cb646
+Author: Bill Erickson <berick at esilibrary.com>
+Date:   Wed Jan 15 10:44:44 2014 -0500
+
+    LP#1268636 TPAC initial navigation headers
+    
+    Added a screen-reader only CSS class ("sr-only") for adding content
+    which should only be read by screen readers and is otherwise invisible.
+    
+    Added hidden generic <h1> and page-specific <h2> entries to improve
+    web accessibility navigation.
+    
+    Additional content-specific headers (h3 and down) are recommended for
+    content grouping, but not included in this commit.
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Dan Scott <dscott at laurentian.ca>
+
+1	0	Open-ILS/src/templates/opac/advanced.tt2
+1	0	Open-ILS/src/templates/opac/browse.tt2
+1	0	Open-ILS/src/templates/opac/cnbrowse.tt2
+16	0	Open-ILS/src/templates/opac/css/style.css.tt2
+1	0	Open-ILS/src/templates/opac/home.tt2
+2	0	Open-ILS/src/templates/opac/login.tt2
+1	0	Open-ILS/src/templates/opac/mylist.tt2
+3	0	Open-ILS/src/templates/opac/parts/base.tt2
+1	0	Open-ILS/src/templates/opac/parts/searchbar.tt2
+1	0	Open-ILS/src/templates/opac/password_reset.tt2
+1	0	Open-ILS/src/templates/opac/place_hold.tt2
+1	0	Open-ILS/src/templates/opac/record.tt2
+1	0	Open-ILS/src/templates/opac/register.tt2
+1	0	Open-ILS/src/templates/opac/results.tt2
+1	0	Open-ILS/src/templates/opac/sms_cn.tt2
+1	0	Open-ILS/src/templates/opac/temp_warn.tt2
+
+commit 552928cee45238127b188c078bf309a20f8a8259
+Author: Bill Erickson <berick at esilibrary.com>
+Date:   Wed Jan 8 16:29:15 2014 -0500
+
+    LP#1268636 My account various repairs
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Dan Scott <dscott at laurentian.ca>
+
+1	0	Open-ILS/src/templates/opac/css/style.css.tt2
+7	4	Open-ILS/src/templates/opac/myopac/circ_history.tt2
+29	25	Open-ILS/src/templates/opac/myopac/circs.tt2
+19	18	Open-ILS/src/templates/opac/myopac/hold_history.tt2
+21	23	Open-ILS/src/templates/opac/myopac/holds.tt2
+14	12	Open-ILS/src/templates/opac/myopac/lists.tt2
+11	4	Open-ILS/src/templates/opac/myopac/main.tt2
+36	25	Open-ILS/src/templates/opac/myopac/main_payment_form.tt2
+2	1	Open-ILS/src/templates/opac/myopac/main_payments.tt2
+29	78	Open-ILS/src/templates/opac/myopac/prefs.tt2
+3	2	Open-ILS/src/templates/opac/myopac/prefs_my_lists.tt2
+22	14	Open-ILS/src/templates/opac/myopac/prefs_notify.tt2
+19	10	Open-ILS/src/templates/opac/myopac/prefs_settings.tt2
+4	1	Open-ILS/src/templates/opac/parts/bookbag_actions.tt2
+14	8	Open-ILS/src/templates/opac/parts/header.tt2
+22	17	Open-ILS/src/templates/opac/parts/myopac/base.tt2
+31	18	Open-ILS/src/templates/opac/parts/myopac/main_base.tt2
+4	1	Open-ILS/src/templates/opac/parts/myopac/prefs_base.tt2
+5	4	Open-ILS/src/templates/opac/parts/result/table.tt2
+
+commit 3bb0bfbdc91b3ba235cc72fa9c5173152062f085
+Author: Bill Erickson <berick at esilibrary.com>
+Date:   Mon Dec 30 16:14:19 2013 -0500
+
+    LP#1268636 avoid empty <ul>'s in browse
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Dan Scott <dscott at laurentian.ca>
+
+23	6	Open-ILS/src/templates/opac/browse.tt2
+4	1	Open-ILS/src/templates/opac/parts/advanced/expert.tt2
+0	1	Open-ILS/src/templates/opac/parts/advanced/numeric.tt2
+
+commit 161815ed45e1eb468ddf342af25cf64b1bd80a94
+Author: Bill Erickson <berick at esilibrary.com>
+Date:   Mon Dec 30 15:36:53 2013 -0500
+
+    LP#1268636 advanced search repairs
+    
+    * avoid dupe IDs
+    * removes extraneous <div>'s
+    * clean up attrs w/ preceding spaces
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Dan Scott <dscott at laurentian.ca>
+
+3	3	Open-ILS/src/templates/opac/css/style.css.tt2
+4	1	Open-ILS/src/templates/opac/parts/advanced/global_row.tt2
+6	6	Open-ILS/src/templates/opac/parts/advanced/search.tt2
+
+commit 14eb3d30a9b3ec118f1225c992e96a3ca93c6375
+Author: Bill Erickson <berick at esilibrary.com>
+Date:   Mon Dec 23 11:39:50 2013 -0500
+
+    LP#1268636 alt tags and cleanup continued
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Dan Scott <dscott at laurentian.ca>
+
+11	0	Open-ILS/src/templates/opac/parts/header.tt2
+1	1	Open-ILS/src/templates/opac/parts/homesearch.tt2
+11	12	Open-ILS/src/templates/opac/parts/record/awards.tt2
+6	5	Open-ILS/src/templates/opac/parts/record/cnbrowse.tt2
+2	2	Open-ILS/src/templates/opac/parts/record/copy_table.tt2
+1	1	Open-ILS/src/templates/opac/parts/record/extras.tt2
+4	3	Open-ILS/src/templates/opac/parts/record/summary.tt2
+3	3	Open-ILS/src/templates/opac/parts/result/table.tt2
+
+commit 3e1e2b918368d6b921b9aad2c45e0b0cc0878760
+Author: Bill Erickson <berick at esilibrary.com>
+Date:   Fri Dec 20 11:42:06 2013 -0500
+
+    LP#1268636 more expressive <a> titles in search results
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Dan Scott <dscott at laurentian.ca>
+
+16	8	Open-ILS/src/templates/opac/parts/result/table.tt2
+
+commit ba5effb8b480bae8ee201ca7afa5a4465136b7f8
+Author: Bill Erickson <berick at esilibrary.com>
+Date:   Fri Dec 20 11:13:48 2013 -0500
+
+    LP#1268636 HTML validation repairs
+    
+    remove invalid span at nowrap attribute
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Dan Scott <dscott at laurentian.ca>
+
+1	1	Open-ILS/src/templates/opac/parts/result/paginate.tt2
+
+commit 94a50c8f782fafa5fac404891f1955e7a6f57d08
+Author: Bill Erickson <berick at esilibrary.com>
+Date:   Fri Dec 20 11:13:32 2013 -0500
+
+    LP#1268636 additional label repairs
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Dan Scott <dscott at laurentian.ca>
+
+2	2	Open-ILS/src/templates/opac/results.tt2
+
+commit b114e4f963003e490530af1de94a7e15384d930a
+Author: Bill Erickson <berick at esilibrary.com>
+Date:   Fri Dec 20 11:12:30 2013 -0500
+
+    LP#1268636 HTML table attributes validation repairs
+    
+    Replace old-school inline cellpadding, cellspacing, border attributes
+    with CSS.
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Dan Scott <dscott at laurentian.ca>
+
+14	0	Open-ILS/src/templates/opac/css/style.css.tt2
+1	1	Open-ILS/src/templates/opac/myopac/circs.tt2
+2	2	Open-ILS/src/templates/opac/myopac/holds.tt2
+2	2	Open-ILS/src/templates/opac/myopac/lists.tt2
+1	1	Open-ILS/src/templates/opac/myopac/main_payment_form.tt2
+1	1	Open-ILS/src/templates/opac/parts/anon_list.tt2
+1	1	Open-ILS/src/templates/opac/parts/record/copy_table.tt2
+3	4	Open-ILS/src/templates/opac/parts/result/table.tt2
+
+commit d818dbbee5d3536f811c999a79e4228990d752a0
+Author: Bill Erickson <berick at esilibrary.com>
+Date:   Fri Dec 20 11:07:01 2013 -0500
+
+    LP#1268636 facets get more specific more/less titles
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Dan Scott <dscott at laurentian.ca>
+
+9	2	Open-ILS/src/templates/opac/parts/result/facets.tt2
+
+commit be91b108928aad16866fbb32346d23da7db494f3
+Author: Bill Erickson <berick at esilibrary.com>
+Date:   Thu Dec 19 12:57:42 2013 -0500
+
+    LP#1268636 home page label / alt repairs
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Dan Scott <dscott at laurentian.ca>
+
+2	1	Open-ILS/src/templates/opac/parts/homesearch.tt2
+14	9	Open-ILS/src/templates/opac/parts/searchbar.tt2
+
+commit 462a352a44553f4815536c9de595570685bfcd83
+Author: Ben Shum <bshum at biblio.org>
+Date:   Sat Feb 8 11:14:23 2014 -0500
+
+    Fix copy_info variables one last time for library_name_link purposes
+    
+    In cd056eba75038c6a1fabd2a83ba97d81a444bc75, I fixed record by inadvertently
+    passing around the wrong variables. In fact, we do not need the value set
+    there, and we broke results view as a result of the swap around.
+    
+    Put things right what once went wrong.
+    
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+    Signed-off-by: Dan Scott <dscott at laurentian.ca>
+
+1	3	Open-ILS/src/templates/opac/parts/record/copy_table.tt2
+1	1	Open-ILS/src/templates/opac/parts/result/table.tt2
+
+commit aa8ea3ca943785ea982d87ad2bf51419812786f2
+Author: Dan Scott <dscott at laurentian.ca>
+Date:   Tue Nov 26 12:44:51 2013 -0500
+
+    Address some remaining hardcoded install prefixes
+    
+    Ran a clean install of Evergreen on Ubuntu Precise and most things were
+    more or less working using simple "./configure; make; make install" with
+    the major exception of the TPAC. It turned out that there is a simple
+    variable that can be tweaked in the Apache config; a better way to
+    handle this might be to preprocess the source file at make time, but for
+    now at least we set the variable.
+    
+    In addition, clean up two remaining scripts that have hardcoded paths.
+    
+    Signed-off-by: Dan Scott <dscott at laurentian.ca>
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+
+2	1	Open-ILS/examples/apache/eg_vhost.conf.in
+2	1	Open-ILS/examples/apache_24/eg_vhost.conf.in
+12	5	Open-ILS/src/Makefile.am
+0	248	Open-ILS/src/support-scripts/action_trigger_runner.pl
+248	0	Open-ILS/src/support-scripts/action_trigger_runner.pl.in
+0	180	Open-ILS/src/support-scripts/offline-blocked-list.pl
+180	0	Open-ILS/src/support-scripts/offline-blocked-list.pl.in
+ delete mode 100755 Open-ILS/src/support-scripts/action_trigger_runner.pl
+ create mode 100755 Open-ILS/src/support-scripts/action_trigger_runner.pl.in
+ delete mode 100755 Open-ILS/src/support-scripts/offline-blocked-list.pl
+ create mode 100755 Open-ILS/src/support-scripts/offline-blocked-list.pl.in
+
+commit 66772286f65981bf7102a58b9e0990a77679986d
+Author: Dan Scott <dscott at laurentian.ca>
+Date:   Fri Feb 7 18:42:41 2014 -0500
+
+    Sign off on upgrade script for (STRING|ARRAY)_AGG
+    
+    Signed-off-by: Dan Scott <dscott at laurentian.ca>
+
+1	1	Open-ILS/src/sql/Pg/002.schema.config.sql
+2003	0	Open-ILS/src/sql/Pg/upgrade/0855.change_to_array_agg.sql
+0	2003	Open-ILS/src/sql/Pg/upgrade/XXXX.change_to_array_agg.sql
+ create mode 100644 Open-ILS/src/sql/Pg/upgrade/0855.change_to_array_agg.sql
+ delete mode 100644 Open-ILS/src/sql/Pg/upgrade/XXXX.change_to_array_agg.sql
+
+commit ecf5858253c0b5d834ed3fceeefd7cd82284caa8
+Author: Dan Scott <dscott at laurentian.ca>
+Date:   Fri Feb 7 18:12:10 2014 -0500
+
+    Tweak STRING_AGG() arguments (expects TEXT or BYTEA)
+    
+    Signed-off-by: Dan Scott <dscott at laurentian.ca>
+
+7	7	Open-ILS/examples/fm_IDL.xml
+
+commit 3e2a33a5222df66b6b81ec997d4bbd53ea287571
+Author: Ben Shum <bshum at biblio.org>
+Date:   Fri Feb 7 06:34:00 2014 -0500
+
+    Add upgrade script for changeover to array_agg() and string_agg()
+    
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+    Signed-off-by: Dan Scott <dscott at laurentian.ca>
+
+2003	0	Open-ILS/src/sql/Pg/upgrade/XXXX.change_to_array_agg.sql
+ create mode 100644 Open-ILS/src/sql/Pg/upgrade/XXXX.change_to_array_agg.sql
+
+commit c546e887e445df8daaa0aa41e31b825195e41e2b
+Author: Ben Shum <bshum at biblio.org>
+Date:   Fri Feb 7 01:18:08 2014 -0500
+
+    Found a few last functions that need changing to native SQL
+    
+    These new uses probably went in more recently as authority fixes. Updated them to
+    use the native functions as well.
+    
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+    Signed-off-by: Dan Scott <dscott at laurentian.ca>
+
+3	3	Open-ILS/src/sql/Pg/011.schema.authority.sql
+3	3	Open-ILS/src/sql/Pg/030.schema.metabib.sql
+
+commit e6eb17aa52e6dab2bbbb12674a717fcdf01023d4
+Author: Dan Scott <dscott at laurentian.ca>
+Date:   Thu Jan 16 20:59:13 2014 -0500
+
+    Keep dropping and creating array_accum()
+    
+    We want to keep array_accum() around for now to support any custom SQL that
+    sites might have generated. Plus, we don't want it to show up in our search
+    path ahead of the native array_agg()!
+    
+    We can always rebase this as a fix into the previous commit to squash history a
+    bit. "Nope, that never happened!"
+    
+    Signed-off-by: Dan Scott <dscott at laurentian.ca>
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+
+2	2	Open-ILS/src/sql/Pg/002.functions.aggregate.sql
+
+commit d80e70c488b572fa197f15f43e2a818b032585f1
+Author: Ben Shum <bshum at biblio.org>
+Date:   Fri May 18 00:27:24 2012 -0400
+
+    More native SQL functions
+    
+    Found four more places that this needed to be changed.
+    
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+    Signed-off-by: Dan Scott <dscott at laurentian.ca>
+
+7	7	Open-ILS/examples/fm_IDL.xml
+2	2	Open-ILS/src/sql/Pg/002.functions.aggregate.sql
+1	1	Open-ILS/src/sql/Pg/002.functions.config.sql
+1	1	Open-ILS/src/sql/Pg/300.schema.staged_search.sql
+
+commit fc5bd43ec0fda187efa34b001b84ca6919b10f43
+Author: Dan Scott <dscott at laurentian.ca>
+Date:   Tue Jan 3 11:53:49 2012 -0500
+
+    Prevent {NULL} values from blocking bib saving
+    
+    With both the old ARRAY_ACCUM and ARRAY_AGG, and with array_nulls on,
+    PostgreSQL 9.0 on Debian Squeeze was generating values of '{NULL}'
+    rather than actual nulls. This would in turn prevent bibs without ISBNs
+    or ISSNs from being saved successfully. A CASE statement protects
+    against that problem and returns a clean NULL.
+    
+    Signed-off-by: Dan Scott <dscott at laurentian.ca>
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+
+8	2	Open-ILS/src/sql/Pg/reporter-schema.sql
+
+commit 29b2929c394211f9a3ac5fe64b78b9698ae2a58e
+Author: Dan Scott <dscott at laurentian.ca>
+Date:   Sun Oct 16 10:26:00 2011 -0400
+
+    ARRAY_ACCUM() -> ARRAY_AGG() for new authority nfi functions
+    
+    Fix the new places where array_accum() has been able to sneak into the
+    schema.
+    
+    Signed-off-by: Dan Scott <dscott at laurentian.ca>
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+
+3	3	Open-ILS/src/sql/Pg/011.schema.authority.sql
+
+commit ac0024830fc8289c826a77bed396589ac7c2042e
+Author: Dan Scott <dscott at laurentian.ca>
+Date:   Thu Oct 13 18:56:26 2011 -0400
+
+    Teach asset.merge_record_assets about STRING_AGG()
+    
+    Now that asset.merge_record_assets() is working, cut over to
+    STRING_AGG() so it can iterate over those unnecessary nodes faster :)
+    
+    Signed-off-by: Dan Scott <dscott at laurentian.ca>
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+
+8	10	Open-ILS/src/sql/Pg/999.functions.global.sql
+
+commit 1a042ec22d9150ca6a05a87ddeb371b9802d7262
+Author: Dan Scott <dscott at laurentian.ca>
+Date:   Thu Oct 13 10:45:25 2011 -0400
+
+    One more STRING_AGG() conversion
+    
+    Teach biblio.indexing_ingest_or_delete() to use STRING_AGG() where
+    appropriate.
+    
+    Signed-off-by: Dan Scott <dscott at laurentian.ca>
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+
+1	1	Open-ILS/src/sql/Pg/030.schema.metabib.sql
+
+commit 616f47d742b6a773b1ce099d90dc073b6143bc2c
+Author: Dan Scott <dscott at laurentian.ca>
+Date:   Wed Oct 12 14:20:46 2011 -0400
+
+    Native SQL functions for Vandelay
+    
+    Use STRING_AGG() where appropriate instead of
+    ARRAY_TO_STRING(ARRAY_ACCUM()), and ARRAY_AGG() instead of
+    ARRAY_ACCUM().
+    
+    Signed-off-by: Dan Scott <dscott at laurentian.ca>
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+
+9	9	Open-ILS/src/sql/Pg/012.schema.vandelay.sql
+
+commit bd50424f525f4a32ccc965b3835fee7256015254
+Author: Dan Scott <dscott at laurentian.ca>
+Date:   Tue Oct 11 23:53:33 2011 -0400
+
+    Replace ARRAY_ACCUM() custom function with ARRAY_AGG()
+    
+    Tested each replacement to ensure that the return of NULL instead of
+    '{}' empty array doesn't break anything - although some functions didn't
+    seem to work with either function (for example,
+    asset.merge_record_assets() doesn't seem to actually move an 856 from
+    the source to the target record).
+    
+    Also replace ARRAY_TO_STRING(ARRAY_AGG()) with STRING_AGG() in a couple
+    of places; see
+    http://www.depesz.com/index.php/2010/02/17/waiting-for-9-0-string_agg/
+    for one reason why (likely performance gain).
+    
+    Signed-off-by: Dan Scott <dscott at laurentian.ca>
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+
+1	1	Open-ILS/src/sql/Pg/000.functions.general.sql
+2	2	Open-ILS/src/sql/Pg/030.schema.metabib.sql
+3	3	Open-ILS/src/sql/Pg/100.circ_matrix.sql
+1	1	Open-ILS/src/sql/Pg/110.hold_matrix.sql
+6	6	Open-ILS/src/sql/Pg/300.schema.staged_search.sql
+1	1	Open-ILS/src/sql/Pg/990.schema.unapi.sql
+1	1	Open-ILS/src/sql/Pg/999.functions.global.sql
+3	3	Open-ILS/src/sql/Pg/example.reporter-extension.sql
+6	6	Open-ILS/src/sql/Pg/reporter-schema.sql
+
+commit 746bd28c045d38313e5b8c66eefd5adb6b3bec0f
+Author: Ben Shum <bshum at biblio.org>
+Date:   Thu Feb 6 00:33:33 2014 -0500
+
+    OpenSearch release note
+    
+    Add a short release note about the return of OpenSearch support.
+    
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+
+5	0	docs/RELEASE_NOTES_NEXT/OPAC/OpenSearch.txt
+ create mode 100644 docs/RELEASE_NOTES_NEXT/OPAC/OpenSearch.txt
+
+commit a1cfeda380e2ddd1f2de12a73ef616fbdb6a108c
+Author: Dan Scott <dscott at laurentian.ca>
+Date:   Tue Jan 14 23:46:41 2014 -0500
+
+    Restore OpenSearch support and use TPAC search
+    
+    This enables users to easily add the Evergreen search engine to their browser's
+    built-in set of search engines, and most importantly directs searches to the
+    TPAC instead of the weird old Supercat interface.
+    
+    Signed-off-by: Dan Scott <dscott at laurentian.ca>
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+
+3	2	Open-ILS/src/perlmods/lib/OpenILS/WWW/SuperCat.pm
+1	0	Open-ILS/src/templates/opac/parts/base.tt2
+
+commit bd17b2fa124c5de44c593414442af696501fd640
+Author: Bill Erickson <berick at esilibrary.com>
+Date:   Mon Feb 3 15:50:51 2014 -0500
+
+    Bumping base schema version to match latest upgrade
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Jeff Godin <jgodin at tadl.org>
+
+1	1	Open-ILS/src/sql/Pg/002.schema.config.sql
+
+commit cd056eba75038c6a1fabd2a83ba97d81a444bc75
+Author: Ben Shum <bshum at biblio.org>
+Date:   Fri Jan 24 23:56:45 2014 -0500
+
+    Fix copy_info variables for result and record view
+    
+    Because we yanked out the code that generates the link into a separate INCLUDE
+    file, the function was looking for something for copy_info. The one for result
+    was missing entirely and the one for record was backwards.
+    
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+    Signed-off-by: Dan Scott <dscott at laurentian.ca>
+
+1	1	Open-ILS/src/templates/opac/parts/record/copy_table.tt2
+2	1	Open-ILS/src/templates/opac/parts/result/table.tt2
+
+commit 536e1cea766d9136e9d0f87fdf97fb6722926be1
+Author: Dan Scott <dscott at laurentian.ca>
+Date:   Thu Jan 23 13:51:30 2014 -0500
+
+    KPAC library page: give the kids some style
+    
+    Just the bare minimum: some padding around the body, and a font colour and size
+    that's reasonably consistent with the rest of the look of the KPAC for h2 and
+    h3 elements.
+    
+    Yes, I know there is text-transform:uppercase and h2 is sized at 48px but that
+    seems to be used for "You saved it!" and "Get it!" banner things. On the
+    library info page, we're using headings for headings.
+    
+    Signed-off-by: Dan Scott <dscott at laurentian.ca>
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+
+18	0	Open-ILS/web/css/skin/default/kpac/style.css
+
+commit 7831ed7153eb21a565f1827ac3331434de2341b7
+Author: Dan Scott <dscott at laurentian.ca>
+Date:   Thu Jan 23 12:10:50 2014 -0500
+
+    Clean up the breadcrumb trail in the KPAC
+    
+    Links to the library pages don't maintain GET context, so we can't feed search
+    or "Get It" links in the breadcrumb trail, currently. We can revisit this,
+    of course.
+    
+    Wasn't there some fairy tale about kids and a breadcrumb trail... once upon a
+    time?
+    
+    Signed-off-by: Dan Scott <dscott at laurentian.ca>
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+
+1	1	Open-ILS/src/templates/kpac/parts/breadcrumb.tt2
+
+commit fd015294eca4169d373eee8ecda798245e5ea24e
+Author: Dan Scott <dscott at laurentian.ca>
+Date:   Thu Jan 23 12:05:20 2014 -0500
+
+    KPAC root, OPAC root: we all live under one root
+    
+    Signed-off-by: Dan Scott <dscott at laurentian.ca>
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+
+7	1	Open-ILS/src/templates/opac/parts/library/core_info.tt2
+6	1	Open-ILS/src/templates/opac/parts/library_name_link.tt2
+
+commit a49b91ff2afbffe4dc09dfd2df02893c4733d8ca
+Author: Dan Scott <dscott at laurentian.ca>
+Date:   Thu Jan 23 11:41:52 2014 -0500
+
+    Begin enabling KPAC-branded library info page
+    
+    This needs work and is going to get squashed like a bug when we're through.
+    
+    Yeesh.
+    
+    Signed-off-by: Dan Scott <dscott at laurentian.ca>
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+
+1	0	Open-ILS/src/perlmods/lib/OpenILS/WWW/EGKPacLoader.pm
+6	0	Open-ILS/src/templates/kpac/library.tt2
+2	51	Open-ILS/src/templates/opac/library.tt2
+50	0	Open-ILS/src/templates/opac/parts/library/core_info.tt2
+ create mode 100644 Open-ILS/src/templates/kpac/library.tt2
+ create mode 100644 Open-ILS/src/templates/opac/parts/library/core_info.tt2
+
+commit c747313ae6b181b1a1eff01ca59b65380145b6a9
+Author: Dan Scott <dscott at laurentian.ca>
+Date:   Thu Jan 23 09:10:59 2014 -0500
+
+    KPAC: Won't somebody think of the children's record details?
+    
+    Factor out the library name link logic into a separate template that can be
+    included by TPAC search results, TPAC record details, and KPAC record details.
+    
+    Notice along the way that the KPAC is devoid of copy-level structured data,
+    but save that for later.
+    
+    Signed-off-by: Dan Scott <dscott at laurentian.ca>
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+
+1	7	Open-ILS/src/templates/kpac/parts/copy_table.tt2
+13	0	Open-ILS/src/templates/opac/parts/library_name_link.tt2
+2	11	Open-ILS/src/templates/opac/parts/record/copy_table.tt2
+1	12	Open-ILS/src/templates/opac/parts/result/table.tt2
+ create mode 100644 Open-ILS/src/templates/opac/parts/library_name_link.tt2
+
+commit df5cc7561eacee316fda5756756f1e50260c13af
+Author: Dan Scott <dscott at laurentian.ca>
+Date:   Wed Jan 22 10:12:37 2014 -0500
+
+    TPAC: Link library in results page to library page
+    
+    Dan Wells noticed that the links on results pages went to a different location
+    (potentially, depending on the "prefer external library uri" OUS) than the
+    links on record pages. Make things consistent.
+    
+    Signed-off-by: Dan Scott <dscott at laurentian.ca>
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+
+8	2	Open-ILS/src/templates/opac/parts/result/table.tt2
+
+commit 3f639a83df73a99a63210e3b8d353aff3c1bcbf6
+Author: Dan Wells <dbw2 at calvin.edu>
+Date:   Wed Jan 22 16:40:36 2014 -0500
+
+    Translation updates - newpot
+    
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+57	5	build/i18n/po/AutoFieldWidget.js/AutoFieldWidget.js.pot
+5	1	build/i18n/po/cat.properties/cat.properties.pot
+2179	2179	build/i18n/po/db.seed/db.seed.pot
+259	255	build/i18n/po/ils_events.xml/ils_events.xml.pot
+39	3	build/i18n/po/serial.js/serial.js.pot
+121	25	build/i18n/po/tpac/tpac.pot
+
+commit 02a40d11fc5dc91976593b2fc9c57b0d70a2f786
+Author: Dan Wells <dbw2 at calvin.edu>
+Date:   Wed Jan 22 16:24:32 2014 -0500
+
+    Translation updates - po files
+    
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+9	9	build/i18n/po/Searcher.js/es-ES.po
+4	4	build/i18n/po/admin.properties/es-ES.po
+21	21	build/i18n/po/authority.js/es-ES.po
+31	27	build/i18n/po/cat.properties/es-ES.po
+4	4	build/i18n/po/cat.properties/hy-AM.po
+3	3	build/i18n/po/circ.properties/cs-CZ.po
+11	11	build/i18n/po/circ.properties/es-ES.po
+9	9	build/i18n/po/circ.properties/hy-AM.po
+4	4	build/i18n/po/common.properties/es-ES.po
+5	5	build/i18n/po/common.properties/hy-AM.po
+6	6	build/i18n/po/conify.js/es-ES.po
+53	16	build/i18n/po/db.seed/cs-CZ.po
+24	21	build/i18n/po/db.seed/es-ES.po
+498	260	build/i18n/po/db.seed/hy-AM.po
+41	41	build/i18n/po/fm_IDL.dtd/hy-AM.po
+22	19	build/i18n/po/ils_events.xml/es-ES.po
+6	5	build/i18n/po/ils_events.xml/hy-AM.po
+12	12	build/i18n/po/lang.dtd/cs-CZ.po
+17	17	build/i18n/po/lang.dtd/es-ES.po
+210	202	build/i18n/po/lang.dtd/hy-AM.po
+52	41	build/i18n/po/offline.properties/es-ES.po
+4	4	build/i18n/po/offline.properties/hy-AM.po
+4	4	build/i18n/po/offline.properties/oc-FR.po
+4	4	build/i18n/po/opac.dtd/es-ES.po
+24	24	build/i18n/po/patron.properties/es-ES.po
+11	11	build/i18n/po/patron.properties/hy-AM.po
+21	20	build/i18n/po/pickup_and_return.js/es-ES.po
+6	6	build/i18n/po/pull_list.js/es-ES.po
+11	11	build/i18n/po/register.js/es-ES.po
+6	6	build/i18n/po/register.js/hy-AM.po
+20	8	build/i18n/po/reports.dtd/es-ES.po
+27	24	build/i18n/po/selfcheck.js/es-ES.po
+12	12	build/i18n/po/selfcheck.js/hy-AM.po
+8	4	build/i18n/po/serial.properties/cs-CZ.po
+7	3	build/i18n/po/serial.properties/de-DE.po
+7	3	build/i18n/po/serial.properties/en-CA.po
+7	3	build/i18n/po/serial.properties/en-GB.po
+11	7	build/i18n/po/serial.properties/es-ES.po
+7	3	build/i18n/po/serial.properties/fr-CA.po
+10	6	build/i18n/po/serial.properties/hy-AM.po
+7	3	build/i18n/po/serial.properties/oc-FR.po
+7	3	build/i18n/po/serial.properties/pt-BR.po
+7	3	build/i18n/po/serial.properties/tr-TR.po
+
+commit 9f00f0942e7959e8b3d822ae221aae1ba1537749
+Author: Jeff Godin <jgodin at tadl.org>
+Date:   Wed Jan 22 09:56:34 2014 -0500
+
+    Stamping 0854: data.min_max_prices
+    
+    Stamping 0854 and resolving permission ID conflicts due to drift.
+    
+    Signed-off-by: Jeff Godin <jgodin at tadl.org>
+
+2	2	Open-ILS/src/sql/Pg/950.data.seed-values.sql
+55	0	Open-ILS/src/sql/Pg/upgrade/0854.data.min_max_prices.sql
+0	55	Open-ILS/src/sql/Pg/upgrade/XXXX.data.min_max_prices.sql
+ create mode 100644 Open-ILS/src/sql/Pg/upgrade/0854.data.min_max_prices.sql
+ delete mode 100644 Open-ILS/src/sql/Pg/upgrade/XXXX.data.min_max_prices.sql
+
+commit e9c5319bc8d8535113cd1b4c28f132fe7d21a957
+Author: Remington Steed <rjs7 at calvin.edu>
+Date:   Tue Sep 24 16:54:37 2013 -0400
+
+    Release notes for lp1207903: new lost billing min/max setting
+    
+    Signed-off-by: Remington Steed <rjs7 at calvin.edu>
+    Signed-off-by: Jeff Godin <jgodin at tadl.org>
+
+24	0	docs/RELEASE_NOTES_NEXT/Circulation/lost_min_max_item_pricing.txt
+ create mode 100644 docs/RELEASE_NOTES_NEXT/Circulation/lost_min_max_item_pricing.txt
+
+commit e42e9b047c91c21d34db19a0ff7afd7ebcddf367
+Author: Dan Wells <dbw2 at calvin.edu>
+Date:   Fri Dec 14 14:02:22 2012 -0500
+
+    Add new option for max/min lost item pricing
+    
+    In addition to a 'default' price when price is missing or zero,
+    we can also accommodate a range of prices by saying it should be
+    at least 'X' and not more than 'Y'.  This also allows you to
+    effectively set a fixed price for all lost items by setting min
+    and max to an equal amount.
+    
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+    Signed-off-by: Jeff Godin <jgodin at tadl.org>
+
+21	10	Open-ILS/src/perlmods/lib/OpenILS/Application/AppUtils.pm
+2	0	Open-ILS/src/perlmods/lib/OpenILS/Const.pm
+23	1	Open-ILS/src/sql/Pg/950.data.seed-values.sql
+55	0	Open-ILS/src/sql/Pg/upgrade/XXXX.data.min_max_prices.sql
+ create mode 100644 Open-ILS/src/sql/Pg/upgrade/XXXX.data.min_max_prices.sql
+
+commit 3699196475f8bf160232e1e9f2718afb3681e4d5
+Author: Dan Wells <dbw2 at calvin.edu>
+Date:   Tue Jan 21 15:07:29 2014 -0500
+
+    Stamping 0853: 'Prefer external URL' OUS
+    
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+1	1	Open-ILS/src/sql/Pg/002.schema.config.sql
+18	0	Open-ILS/src/sql/Pg/upgrade/0853.data.prefer_external_url_OUS.sql
+0	18	Open-ILS/src/sql/Pg/upgrade/XXXX.data.prefer_external_url_OUS.sql
+ create mode 100644 Open-ILS/src/sql/Pg/upgrade/0853.data.prefer_external_url_OUS.sql
+ delete mode 100644 Open-ILS/src/sql/Pg/upgrade/XXXX.data.prefer_external_url_OUS.sql
+
+commit 46f49173b6a08f4c7b755de728edbe6bafb9879a
+Author: Dan Scott <dscott at laurentian.ca>
+Date:   Tue Jan 14 22:12:16 2014 -0500
+
+    Release notes for the TPAC library web pages
+    
+    Signed-off-by: Dan Scott <dscott at laurentian.ca>
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+33	0	docs/RELEASE_NOTES_NEXT/OPAC/TPAC_library_pages.txt
+ create mode 100644 docs/RELEASE_NOTES_NEXT/OPAC/TPAC_library_pages.txt
+
+commit 796eff67ab1768d629a46e96daf6a06c81a265e5
+Author: Dan Scott <dscott at laurentian.ca>
+Date:   Tue Jan 14 21:33:34 2014 -0500
+
+    Add upgrade script for lib.prefer_external_url OUS
+    
+    Signed-off-by: Dan Scott <dscott at laurentian.ca>
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+18	0	Open-ILS/src/sql/Pg/upgrade/XXXX.data.prefer_external_url_OUS.sql
+ create mode 100644 Open-ILS/src/sql/Pg/upgrade/XXXX.data.prefer_external_url_OUS.sql
+
+commit 2a2fcf40455c7892fcb9e8f5e82af837a058f054
+Author: Dan Scott <dscott at laurentian.ca>
+Date:   Mon Jan 6 14:33:04 2014 -0500
+
+    Copy details link to Evergreen library page by default
+    
+    Add a new library setting, 'lib.prefer_external_url', to force library names in
+    copy details pages to link to their associated 'lib.info_url' setting rather
+    than the Evergreen-generated page. In the absence of a 'lib.info_url' setting,
+    the name will fall back to being linked to the Evergreen-generated page.
+    
+    Per discussion with Ben Shum and Kathy Lussier.
+    
+    Signed-off-by: Dan Scott <dscott at laurentian.ca>
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+10	1	Open-ILS/src/sql/Pg/950.data.seed-values.sql
+2	1	Open-ILS/src/templates/opac/parts/record/copy_table.tt2
+
+commit ac5acbf9cb94831e5cc498d66a8a25b6b7952390
+Author: Dan Scott <dscott at laurentian.ca>
+Date:   Mon Jan 6 13:59:50 2014 -0500
+
+    Improve label for library's external web site
+    
+    Normal humans will find "Library web site" more meaningful than "External web
+    site"; thanks to Kathy Lussier for the suggestion!
+    
+    Signed-off-by: Dan Scott <dscott at laurentian.ca>
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+1	1	Open-ILS/src/templates/opac/library.tt2
+
+commit d38ef46d258cec3a467a28763fa23354598ce2ae
+Author: Dan Scott <dscott at laurentian.ca>
+Date:   Mon Jan 6 13:19:17 2014 -0500
+
+    %l instead of %H if we're using AM/PM for default time formats
+    
+    Thanks again to the indefatiguable Ben Shum for this catch!
+    
+    Signed-off-by: Dan Scott <dscott at laurentian.ca>
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+2	2	Open-ILS/src/templates/opac/parts/library/hours.tt2
+
+commit f4e137ffde417e4b24e71304954a5da47a45b261
+Author: Dan Scott <dscott at laurentian.ca>
+Date:   Mon Jan 6 12:22:28 2014 -0500
+
+    Use the 'format.time' OUS to format library hours
+    
+    Sparked by a concern that Ben Shum had over the display of library hours in 24
+    hour format, I eventually figured out that we could use the Template::Toolkit
+    Date module to format the times according to library preferences. And given
+    that we already have a format.time OUS, let's use it.
+    
+    Signed-off-by: Dan Scott <dscott at laurentian.ca>
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+24	14	Open-ILS/src/templates/opac/parts/library/hours.tt2
+
+commit 8d4ab1b6c3ded757e1ce7558491e03c97323843a
+Author: Dan Scott <dscott at laurentian.ca>
+Date:   Mon Oct 28 11:26:55 2013 -0400
+
+    TPAC Library schema info - add some caching
+    
+    Rather than hitting the database every time, cache our requests for a
+    period of time. It's unlikely that hours of operation or addresses are
+    going to change very often...
+    
+    Signed-off-by: Dan Scott <dscott at laurentian.ca>
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+26	13	Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Library.pm
+
+commit 21b326f5ce113e95626f8912d76751c25f064155
+Author: Dan Scott <dscott at laurentian.ca>
+Date:   Tue Dec 17 16:29:35 2013 -0500
+
+    Link from copies to library info page
+    
+    In the absence of a specific lib.info_url org unit setting, link to the library
+    info page.
+    
+    If we _do_ have a lib.info_url org unit setting, link from the library info
+    page to to the external web site.
+    
+    Rather than wrapping everything in the table cell as the seller, focus
+    on the <a> and give it an explicit Library typeof attribute; then we can
+    offer up the name of the library as the name attribute, should the
+    crawler be too lazy to follow the link.
+    
+    Signed-off-by: Dan Scott <dscott at laurentian.ca>
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+7	3	Open-ILS/src/templates/opac/parts/record/copy_table.tt2
+
+commit 92c77d5ffe133198f612afcc8bcd16f74af69d19
+Author: Dan Scott <dscott at laurentian.ca>
+Date:   Sat Oct 26 17:32:22 2013 -0400
+
+    First inklings of schema.org support for library pages
+    
+    Adds a TPAC page where the information for a given library can be publicly
+    exposed; in addition, that information is marked up with schema.org structured
+    data so that, for example, a search engine can offer up the hours of operation
+    and contact information for a given branch right on the search results page.
+    
+    We give the content-wrapper a main-content for indentation, to be consistent
+    with other pages in the TPAC.
+    
+    We also add the cargo-cult common-full-pad div for a bottom margin.
+    
+    Signed-off-by: Dan Scott <dscott at laurentian.ca>
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+2	0	Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm
+62	0	Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Library.pm
+57	0	Open-ILS/src/templates/opac/library.tt2
+57	0	Open-ILS/src/templates/opac/parts/library/hours.tt2
+ create mode 100644 Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Library.pm
+ create mode 100644 Open-ILS/src/templates/opac/library.tt2
+ create mode 100644 Open-ILS/src/templates/opac/parts/library/hours.tt2
+
+commit a8cb33092ae4e0424c904359e255ebdb7807881c
+Author: Pasi Kallinen <pasi.kallinen at pttk.fi>
+Date:   Tue May 28 20:18:06 2013 +0300
+
+    LP969312: No warning for Delete All from Catalog in Copy Buckets
+    
+    Add a confirmation dialog popup.
+    
+    Signed-off-by: Pasi Kallinen <pasi.kallinen at pttk.fi>
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+
+4	0	Open-ILS/xul/staff_client/server/cat/copy_buckets.js
+1	0	Open-ILS/xul/staff_client/server/locale/en-US/cat.properties
+
+commit dc6e1e86cae4b223ce22031c94b3a756f280fe0b
+Author: Bill Erickson <berick at esilibrary.com>
+Date:   Thu Oct 10 16:05:57 2013 -0400
+
+    New live test for fetching and update bre/MARC data
+    
+    Fetch a record, test the title, add a new subfield, update the record,
+    and test that the new subfield survived the update.
+    
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Dan Scott <dscott at laurentian.ca>
+
+83	0	Open-ILS/src/perlmods/live_t/06-bib_rec_fetch_update.t
+ create mode 100644 Open-ILS/src/perlmods/live_t/06-bib_rec_fetch_update.t
+
+commit 8c7731fb8f3f2c5bc333d1f2e8d4057085598027
+Author: Mike Rylander <mrylander at gmail.com>
+Date:   Thu Jan 16 15:46:41 2014 -0500
+
+    And renaming the test
+    
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+
+0	79	Open-ILS/src/sql/Pg/live_t/0852.fixed_field_enhancements.pg
+79	0	Open-ILS/src/sql/Pg/live_t/0852.prox_adjust.pg
+ delete mode 100644 Open-ILS/src/sql/Pg/live_t/0852.fixed_field_enhancements.pg
+ create mode 100644 Open-ILS/src/sql/Pg/live_t/0852.prox_adjust.pg
+
+commit aec65bd03b02d9ba26ae3e0819afbf7cfe522ed7
+Author: Mike Rylander <mrylander at gmail.com>
+Date:   Thu Jan 16 15:44:58 2014 -0500
+
+    Renumbering the test
+    
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+
+79	0	Open-ILS/src/sql/Pg/live_t/0852.fixed_field_enhancements.pg
+0	79	Open-ILS/src/sql/Pg/live_t/XXXX.fixed_field_enhancements.pg
+0	95	Open-ILS/src/sql/Pg/upgrade/XXXX.function.prox_adjust.sql
+ create mode 100644 Open-ILS/src/sql/Pg/live_t/0852.fixed_field_enhancements.pg
+ delete mode 100644 Open-ILS/src/sql/Pg/live_t/XXXX.fixed_field_enhancements.pg
+ delete mode 100644 Open-ILS/src/sql/Pg/upgrade/XXXX.function.prox_adjust.sql
+
+commit 9c7b271e94b900d2e11aab35ad69a7ed88825e1e
+Author: Mike Rylander <mrylander at gmail.com>
+Date:   Thu Jan 16 15:44:48 2014 -0500
+
+    Renumbering the upgrade script
+    
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+
+1	1	Open-ILS/src/sql/Pg/002.schema.config.sql
+97	0	Open-ILS/src/sql/Pg/upgrade/0852.function.prox_adjust.sql
+ create mode 100644 Open-ILS/src/sql/Pg/upgrade/0852.function.prox_adjust.sql
+
+commit 9a010a19dc2bde9a78c60aa50a9c5b0b32a996c8
+Author: Lebbeous Fogle-Weekley <lebbeous at esilibrary.com>
+Date:   Thu Jan 16 14:59:25 2014 -0500
+
+    Test for Mike's proximity adjustment fix two commits back
+    
+    Being placed in Open-ILS/src/sql/Pg/live_t, the test requires stock and
+    Concerto data be loaded.
+    
+    Signed-off-by: Lebbeous Fogle-Weekley <lebbeous at esilibrary.com>
+    Signed-off-by: Mike Rylander <mrylander at gmail.com>
+
+79	0	Open-ILS/src/sql/Pg/live_t/XXXX.fixed_field_enhancements.pg
+ create mode 100644 Open-ILS/src/sql/Pg/live_t/XXXX.fixed_field_enhancements.pg
+
+commit ecbe401dccb9bd621b7b03be8d7e47df46f932b1
+Author: Dan Wells <dbw2 at calvin.edu>
+Date:   Tue Jan 14 14:59:56 2014 -0500
+
+    Stamping 0851 - changes for Encode.pm 2.54+
+    
+    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
+
+1	1	Open-ILS/src/sql/Pg/002.schema.config.sql
+356	0	Open-ILS/src/sql/Pg/upgrade/0851.function.remove_extra_utf8_decodes.sql
+0	356	Open-ILS/src/sql/Pg/upgrade/XXXX.function.remove_extra_utf8_decodes.sql
+ create mode 100644 Open-ILS/src/sql/Pg/upgrade/0851.function.remove_extra_utf8_decodes.sql
+ delete mode 100644 Open-ILS/src/sql/Pg/upgrade/XXXX.function.remove_extra_utf8_decodes.sql
+
+commit 38fcad90924639560e8433de831a45bdb796df1c
+Author: Dan Scott <dscott at laurentian.ca>
+Date:   Thu Jan 9 12:19:38 2014 -0500
+
+    Fedora needs Locale::Maketext::Lexicon too
+    
+    Per commit 66c45b647, install Locale::Maketext::Lexicon on Fedora to satisfy
+    that dependency. How did _this_ one slip by so long! Thank heavens for
+    tests.
+    
+    Signed-off-by: Dan Scott <dscott at laurentian.ca>
+    Signed-off-by: Chris Sharp <csharp at georgialibraries.org>
+
+1	0	Open-ILS/src/extras/install/Makefile.fedora
+
+commit 5bf117cbae57247a736043496c49bd6c920d131a
+Author: Dan Scott <dscott at laurentian.ca>
+Date:   Sat Oct 13 01:23:35 2012 -0400
+
+    Tests: Ensure TT2 templates parse cleanly
+    
+    File::Find and Test::Output make it easy to check for any stderr
+    returned from the TT2 extractor.
+    
+    Signed-off-by: Dan Scott <dscott at laurentian.ca>
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+
+28	0	Open-ILS/src/perlmods/t/22-template-toolkit-parse.t
+ create mode 100644 Open-ILS/src/perlmods/t/22-template-toolkit-parse.t
+
+commit 812a726341db6abb0ec0e95e2bf54b7e0d21311d
+Author: Dan Scott <dscott at laurentian.ca>
+Date:   Wed Jan 8 22:39:57 2014 -0500
+
+    Repair the live_t regression tests
+    
+    When we added more realistic hours of operation for some of the branches,
+    several of the live_t regression tests failed because they depended on the
+    default hours of operation for BR4. Rather than change the regression test,
+    just switch BR4 back to the default hours of operation and use BR1 as the
+    closed-on-weekends branch instead.
+    
+    Signed-off-by: Dan Scott <dscott at laurentian.ca>
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+
+4	4	Open-ILS/tests/datasets/sql/libraries.sql
+
+commit 24d254d578be8e36ba91fac95af9d3875fe6517f
+Author: Lebbeous Fogle-Weekley <lebbeous at esilibrary.com>
+Date:   Mon Jan 6 11:44:56 2014 -0500
+
+    TPAC: Add Notes label to that row in small-screen My Account->Holds
+    
+    Signed-off-by: Lebbeous Fogle-Weekley <lebbeous at esilibrary.com>
+    Signed-off-by: Dan Scott <dscott at laurentian.ca>
+
+1	0	Open-ILS/src/templates/opac/css/style.css.tt2
+
+commit f90cd00be05c706087f62e9c4173c6c43a48ddb1
+Author: Dan Scott <dscott at laurentian.ca>
+Date:   Mon Dec 30 01:47:19 2013 -0500
+
+    TPAC: Display public hold notes in user holds list
+    
+    If a given hold has a note marked as public, and not marked for staff, then
+    display the note in the My Account -> Holds list. This enhancement also
+    includes sample notes for each hold, to include data that ensures that the TPAC
+    does not display any hold notes that are not marked public, or which are marked
+    for staff.
+    
+    Signed-off-by: Dan Scott <dscott at laurentian.ca>
+    Signed-off-by: Lebbeous Fogle-Weekley <lebbeous at esilibrary.com>
+
+7	0	Open-ILS/src/templates/opac/css/style.css.tt2
+12	0	Open-ILS/src/templates/opac/myopac/holds.tt2
+16	0	Open-ILS/tests/datasets/sql/env_create.sql
+
+commit 10551250dca09a952986b7cc51bea8837db8f02a
+Author: Lebbeous Fogle-Weekley <lebbeous at esilibrary.com>
+Date:   Mon Jan 6 11:27:57 2014 -0500
+
+    TPAC: Get rid of all unneccessary uppercase and some bold
+    
+    This gets rid of all places in the TPAC where CSS uses text-transform:
+    uppercase or capitalize.  The former is bad for readability, and the
+    latter can only confuse users when strings might appear to be
+    capitalized differently in one context than another (esp. users'
+    personal names).
+    
+    This mostly, but not exclusively, affects the My Account section.
+    Also, one wholly unused CSS class was removed altogether.
+    
+    It also gets rid of some bold style that was applied too liberally to
+    the whole contents of tables.
+    
+    Signed-off-by: Lebbeous Fogle-Weekley <lebbeous at esilibrary.com>
+    Signed-off-by: Dan Scott <dscott at laurentian.ca>
+
+0	22	Open-ILS/src/templates/opac/css/style.css.tt2
+
+commit 15d3db176737390b141dcd09ad08aad31e14807d
+Author: Dan Scott <dscott at laurentian.ca>
+Date:   Mon Jan 6 11:07:17 2014 -0500
+
+    Make sample phone numbers "(xxx) xxx-xxxx" format
+    
+    The extra hyphen between the closing parenthesis and the 4th digit was just
+    plain weird. Thanks to Ben Shum for mentioning this in IRC!
+    
+    Signed-off-by: Dan Scott <dscott at laurentian.ca>
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+
+4	4	Open-ILS/tests/datasets/sql/libraries.sql
+
+commit a1b07a3722012b3684965d2e698526be676f6042
+Author: Dan Scott <dscott at laurentian.ca>
+Date:   Tue Dec 17 13:05:43 2013 -0500
+
+    Sample library external URLs, phone numbers, and emails
+    
+    Supply reasonable URLs and contact information for the branches.
+    
+    Signed-off-by: Dan Scott <dscott at laurentian.ca>
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+
+13	0	Open-ILS/tests/datasets/sql/libraries.sql
+
+commit 4a6d1787208b1c0019083d03da04f39f7bb27e99
+Author: Dan Scott <dscott at laurentian.ca>
+Date:   Tue Dec 17 12:02:56 2013 -0500
+
+    Add sample library addresses and hours of operation
+    
+    Provide branch-level granularity of addresses and hours of operation, using
+    different addresses in some cases for mailing vs. billing vs. ILL vs. holds for
+    more realism.
+    
+    Signed-off-by: Dan Scott <dscott at laurentian.ca>
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+
+37	0	Open-ILS/tests/datasets/sql/env_create.sql
+1	0	Open-ILS/tests/datasets/sql/env_destroy.sql
+35	4	Open-ILS/tests/datasets/sql/libraries.sql
+
+commit bcb902397123ebf504eee654d9e5552c4e08cc89
+Author: Dan Scott <dscott at laurentian.ca>
+Date:   Tue Dec 17 10:16:32 2013 -0500
+
+    Move default actor.org_unit entries into sample data
+    
+    The only actor.org_unit entry we absolutely require in the sample data is the
+    consortium, as many things are owned by it. Otherwise, we should treat the
+    libraries and associated settings such as addresses as sample data.
+    
+    Signed-off-by: Dan Scott <dscott at laurentian.ca>
+    Signed-off-by: Bill Erickson <berick at esilibrary.com>
+    Signed-off-by: Ben Shum <bshum at biblio.org>
+
+1	22	Open-ILS/src/sql/Pg/950.data.seed-values.sql
+24	0	Open-ILS/tests/datasets/sql/libraries.sql
+3	0	Open-ILS/tests/datasets/sql/load_all.sql
+3	0	Open-ILS/tests/datasets/sql/load_concerto.sql
+ create mode 100644 Open-ILS/tests/datasets/sql/libraries.sql
+
+commit 3f2a30ddc19817ac4174e9188e173b11548db518
+Author: Remington Steed <rjs7 at calvin.edu>
+Date:   Tue Dec 17 11:17:25 2013 -0500
+
+    Docs: bug fixes in new files
+    
+    This commit fixes a small bug in the new Action Triggers chapter and a
+    few small formatting bugs in the new subsection in the Holds Management
+    chapter. It also fixes a small wording typo in the Holds Management intro.
+    
+    Signed-off-by: Remington Steed <rjs7 at calvin.edu>
+
+1	1	docs/admin/actiontriggers.txt
+9	6	docs/circulation/holds.txt
+
+commit a22c60d395b9865f386a3d38aa6f6ed7aec05d22
+Author: Dan Scott <dscott at laurentian.ca>
+Date:   Mon Dec 16 14:10:05 2013 -0500
+
+    Update README to address Apache locking problem
+    
+    Because Apache is still running as the opensrf user, we need to change the
+    ownership of the lock directory to enable Apache to write to it.
+    
+    Also cut over to the osrf_config script instead of the osrf_ctl.sh script to
+    avoid deprecation warnings.
+    
+    Signed-off-by: Dan Scott <dscott at laurentian.ca>
+
+10	2	docs/installation/server_installation.txt
+
+commit b88b6e6cee138082cb00d7c54c2072ede37d2ecd
+Author: Remington Steed <rjs7 at calvin.edu>
+Date:   Wed Nov 20 09:40:10 2013 -0500
+
+    Revive and update Action Triggers docs for 2.5
+    
+    This commit revives the missing Action Triggers docs section, last seen
+    in the 2.0 version of the docs. Also, several small corrections and
+    wording edits were made, as well as a few actual feature changes since
+    version 2.0.  The most explicit of these feature changes is the addition
+    of a basic description for a new Event Definition field in 2.5: "Event
+    Repeatability Delay".
+    
+    Signed-off-by: Remington Steed <rjs7 at calvin.edu>
+
+217	0	docs/admin/actiontriggers.txt
+2	0	docs/root.txt
+ create mode 100644 docs/admin/actiontriggers.txt
diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application.pm
index d750216..ed2829b 100644
--- a/Open-ILS/src/perlmods/lib/OpenILS/Application.pm
+++ b/Open-ILS/src/perlmods/lib/OpenILS/Application.pm
@@ -7,7 +7,7 @@ use OpenILS::Utils::Fieldmapper;
 sub ils_version {
     # version format is "x-y-z", for example "2-0-0" for Evergreen 2.0.0
     # For branches, format is "x-y"
-    return "HEAD";
+    return "2-6-0";
 }
 
 __PACKAGE__->register_method(
diff --git a/Open-ILS/src/sql/Pg/002.schema.config.sql b/Open-ILS/src/sql/Pg/002.schema.config.sql
index 9b02560..7e2c282 100644
--- a/Open-ILS/src/sql/Pg/002.schema.config.sql
+++ b/Open-ILS/src/sql/Pg/002.schema.config.sql
@@ -92,6 +92,7 @@ CREATE TRIGGER no_overlapping_deps
     FOR EACH ROW EXECUTE PROCEDURE evergreen.array_overlap_check ('deprecates');
 
 INSERT INTO config.upgrade_log (version, applied_to) VALUES ('0879', :eg_version); -- dbwells/bshum
+INSERT INTO config.upgrade_log (version, applied_to) VALUES ('2.6.0', :eg_version);
 
 CREATE TABLE config.bib_source (
 	id		SERIAL	PRIMARY KEY,
diff --git a/Open-ILS/src/sql/Pg/version-upgrade/2.5.3-2.6.0-upgrade-db.sql b/Open-ILS/src/sql/Pg/version-upgrade/2.5.3-2.6.0-upgrade-db.sql
new file mode 100644
index 0000000..482bc85
--- /dev/null
+++ b/Open-ILS/src/sql/Pg/version-upgrade/2.5.3-2.6.0-upgrade-db.sql
@@ -0,0 +1,5851 @@
+--Upgrade Script for 2.5.3 to 2.6.0
+\set eg_version '''2.6.0'''
+BEGIN;
+INSERT INTO config.upgrade_log (version, applied_to) VALUES ('2.6.0', :eg_version);
+
+-- check whether patch can be applied
+SELECT evergreen.upgrade_deps_block_check('0851', :eg_version);
+
+CREATE OR REPLACE FUNCTION evergreen.maintain_901 () RETURNS TRIGGER AS $func$
+use strict;
+use MARC::Record;
+use MARC::File::XML (BinaryEncoding => 'UTF-8');
+use MARC::Charset;
+use Encode;
+use Unicode::Normalize;
+
+MARC::Charset->assume_unicode(1);
+
+my $schema = $_TD->{table_schema};
+my $marc = MARC::Record->new_from_xml($_TD->{new}{marc});
+
+my @old901s = $marc->field('901');
+$marc->delete_fields(@old901s);
+
+if ($schema eq 'biblio') {
+    my $tcn_value = $_TD->{new}{tcn_value};
+
+    # Set TCN value to record ID?
+    my $id_as_tcn = spi_exec_query("
+        SELECT enabled
+        FROM config.global_flag
+        WHERE name = 'cat.bib.use_id_for_tcn'
+    ");
+    if (($id_as_tcn->{processed}) && $id_as_tcn->{rows}[0]->{enabled} eq 't') {
+        $tcn_value = $_TD->{new}{id}; 
+        $_TD->{new}{tcn_value} = $tcn_value;
+    }
+
+    my $new_901 = MARC::Field->new("901", " ", " ",
+        "a" => $tcn_value,
+        "b" => $_TD->{new}{tcn_source},
+        "c" => $_TD->{new}{id},
+        "t" => $schema
+    );
+
+    if ($_TD->{new}{owner}) {
+        $new_901->add_subfields("o" => $_TD->{new}{owner});
+    }
+
+    if ($_TD->{new}{share_depth}) {
+        $new_901->add_subfields("d" => $_TD->{new}{share_depth});
+    }
+
+    $marc->append_fields($new_901);
+} elsif ($schema eq 'authority') {
+    my $new_901 = MARC::Field->new("901", " ", " ",
+        "c" => $_TD->{new}{id},
+        "t" => $schema,
+    );
+    $marc->append_fields($new_901);
+} elsif ($schema eq 'serial') {
+    my $new_901 = MARC::Field->new("901", " ", " ",
+        "c" => $_TD->{new}{id},
+        "t" => $schema,
+        "o" => $_TD->{new}{owning_lib},
+    );
+
+    if ($_TD->{new}{record}) {
+        $new_901->add_subfields("r" => $_TD->{new}{record});
+    }
+
+    $marc->append_fields($new_901);
+} else {
+    my $new_901 = MARC::Field->new("901", " ", " ",
+        "c" => $_TD->{new}{id},
+        "t" => $schema,
+    );
+    $marc->append_fields($new_901);
+}
+
+my $xml = $marc->as_xml_record();
+$xml =~ s/\n//sgo;
+$xml =~ s/^<\?xml.+\?\s*>//go;
+$xml =~ s/>\s+</></go;
+$xml =~ s/\p{Cc}//go;
+
+# Embed a version of OpenILS::Application::AppUtils->entityize()
+# to avoid having to set PERL5LIB for PostgreSQL as well
+
+$xml = NFC($xml);
+
+# Convert raw ampersands to entities
+$xml =~ s/&(?!\S+;)/&amp;/gso;
+
+# Convert Unicode characters to entities
+$xml =~ s/([\x{0080}-\x{fffd}])/sprintf('&#x%X;',ord($1))/sgoe;
+
+$xml =~ s/[\x00-\x1f]//go;
+$_TD->{new}{marc} = $xml;
+
+return "MODIFY";
+$func$ LANGUAGE PLPERLU;
+
+CREATE OR REPLACE FUNCTION maintain_control_numbers() RETURNS TRIGGER AS $func$
+use strict;
+use MARC::Record;
+use MARC::File::XML (BinaryEncoding => 'UTF-8');
+use MARC::Charset;
+use Encode;
+use Unicode::Normalize;
+
+MARC::Charset->assume_unicode(1);
+
+my $record = MARC::Record->new_from_xml($_TD->{new}{marc});
+my $schema = $_TD->{table_schema};
+my $rec_id = $_TD->{new}{id};
+
+# Short-circuit if maintaining control numbers per MARC21 spec is not enabled
+my $enable = spi_exec_query("SELECT enabled FROM config.global_flag WHERE name = 'cat.maintain_control_numbers'");
+if (!($enable->{processed}) or $enable->{rows}[0]->{enabled} eq 'f') {
+    return;
+}
+
+# Get the control number identifier from an OU setting based on $_TD->{new}{owner}
+my $ou_cni = 'EVRGRN';
+
+my $owner;
+if ($schema eq 'serial') {
+    $owner = $_TD->{new}{owning_lib};
+} else {
+    # are.owner and bre.owner can be null, so fall back to the consortial setting
+    $owner = $_TD->{new}{owner} || 1;
+}
+
+my $ous_rv = spi_exec_query("SELECT value FROM actor.org_unit_ancestor_setting('cat.marc_control_number_identifier', $owner)");
+if ($ous_rv->{processed}) {
+    $ou_cni = $ous_rv->{rows}[0]->{value};
+    $ou_cni =~ s/"//g; # Stupid VIM syntax highlighting"
+} else {
+    # Fall back to the shortname of the OU if there was no OU setting
+    $ous_rv = spi_exec_query("SELECT shortname FROM actor.org_unit WHERE id = $owner");
+    if ($ous_rv->{processed}) {
+        $ou_cni = $ous_rv->{rows}[0]->{shortname};
+    }
+}
+
+my ($create, $munge) = (0, 0);
+
+my @scns = $record->field('035');
+
+foreach my $id_field ('001', '003') {
+    my $spec_value;
+    my @controls = $record->field($id_field);
+
+    if ($id_field eq '001') {
+        $spec_value = $rec_id;
+    } else {
+        $spec_value = $ou_cni;
+    }
+
+    # Create the 001/003 if none exist
+    if (scalar(@controls) == 1) {
+        # Only one field; check to see if we need to munge it
+        unless (grep $_->data() eq $spec_value, @controls) {
+            $munge = 1;
+        }
+    } else {
+        # Delete the other fields, as with more than 1 001/003 we do not know which 003/001 to match
+        foreach my $control (@controls) {
+            $record->delete_field($control);
+        }
+        $record->insert_fields_ordered(MARC::Field->new($id_field, $spec_value));
+        $create = 1;
+    }
+}
+
+my $cn = $record->field('001')->data();
+# Special handling of OCLC numbers, often found in records that lack 003
+if ($cn =~ /^o(c[nm]|n)\d/) {
+    $cn =~ s/^o(c[nm]|n)0*(\d+)/$2/;
+    $record->field('003')->data('OCoLC');
+    $create = 0;
+}
+
+# Now, if we need to munge the 001, we will first push the existing 001/003
+# into the 035; but if the record did not have one (and one only) 001 and 003
+# to begin with, skip this process
+if ($munge and not $create) {
+
+    my $scn = "(" . $record->field('003')->data() . ")" . $cn;
+
+    # Do not create duplicate 035 fields
+    unless (grep $_->subfield('a') eq $scn, @scns) {
+        $record->insert_fields_ordered(MARC::Field->new('035', '', '', 'a' => $scn));
+    }
+}
+
+# Set the 001/003 and update the MARC
+if ($create or $munge) {
+    $record->field('001')->data($rec_id);
+    $record->field('003')->data($ou_cni);
+
+    my $xml = $record->as_xml_record();
+    $xml =~ s/\n//sgo;
+    $xml =~ s/^<\?xml.+\?\s*>//go;
+    $xml =~ s/>\s+</></go;
+    $xml =~ s/\p{Cc}//go;
+
+    # Embed a version of OpenILS::Application::AppUtils->entityize()
+    # to avoid having to set PERL5LIB for PostgreSQL as well
+
+    $xml = NFC($xml);
+
+    # Convert raw ampersands to entities
+    $xml =~ s/&(?!\S+;)/&amp;/gso;
+
+    # Convert Unicode characters to entities
+    $xml =~ s/([\x{0080}-\x{fffd}])/sprintf('&#x%X;',ord($1))/sgoe;
+
+    $xml =~ s/[\x00-\x1f]//go;
+    $_TD->{new}{marc} = $xml;
+
+    return "MODIFY";
+}
+
+return;
+$func$ LANGUAGE PLPERLU;
+
+CREATE OR REPLACE FUNCTION public.naco_normalize( TEXT, TEXT ) RETURNS TEXT AS $func$
+
+    use strict;
+    use Unicode::Normalize;
+    use Encode;
+
+    my $str = shift;
+    my $sf = shift;
+
+    # Apply NACO normalization to input string; based on
+    # http://www.loc.gov/catdir/pcc/naco/SCA_PccNormalization_Final_revised.pdf
+    #
+    # Note that unlike a strict reading of the NACO normalization rules,
+    # output is returned as lowercase instead of uppercase for compatibility
+    # with previous versions of the Evergreen naco_normalize routine.
+
+    # Convert to upper-case first; even though final output will be lowercase, doing this will
+    # ensure that the German eszett (ß) and certain ligatures (ff, fi, ffl, etc.) will be handled correctly.
+    # If there are any bugs in Perl's implementation of upcasing, they will be passed through here.
+    $str = uc $str;
+
+    # remove non-filing strings
+    $str =~ s/\x{0098}.*?\x{009C}//g;
+
+    $str = NFKD($str);
+
+    # additional substitutions - 3.6.
+    $str =~ s/\x{00C6}/AE/g;
+    $str =~ s/\x{00DE}/TH/g;
+    $str =~ s/\x{0152}/OE/g;
+    $str =~ tr/\x{0110}\x{00D0}\x{00D8}\x{0141}\x{2113}\x{02BB}\x{02BC}]['/DDOLl/d;
+
+    # transformations based on Unicode category codes
+    $str =~ s/[\p{Cc}\p{Cf}\p{Co}\p{Cs}\p{Lm}\p{Mc}\p{Me}\p{Mn}]//g;
+
+	if ($sf && $sf =~ /^a/o) {
+		my $commapos = index($str, ',');
+		if ($commapos > -1) {
+			if ($commapos != length($str) - 1) {
+                $str =~ s/,/\x07/; # preserve first comma
+			}
+		}
+	}
+
+    # since we've stripped out the control characters, we can now
+    # use a few as placeholders temporarily
+    $str =~ tr/+&@\x{266D}\x{266F}#/\x01\x02\x03\x04\x05\x06/;
+    $str =~ s/[\p{Pc}\p{Pd}\p{Pe}\p{Pf}\p{Pi}\p{Po}\p{Ps}\p{Sk}\p{Sm}\p{So}\p{Zl}\p{Zp}\p{Zs}]/ /g;
+    $str =~ tr/\x01\x02\x03\x04\x05\x06\x07/+&@\x{266D}\x{266F}#,/;
+
+    # decimal digits
+    $str =~ tr/\x{0660}-\x{0669}\x{06F0}-\x{06F9}\x{07C0}-\x{07C9}\x{0966}-\x{096F}\x{09E6}-\x{09EF}\x{0A66}-\x{0A6F}\x{0AE6}-\x{0AEF}\x{0B66}-\x{0B6F}\x{0BE6}-\x{0BEF}\x{0C66}-\x{0C6F}\x{0CE6}-\x{0CEF}\x{0D66}-\x{0D6F}\x{0E50}-\x{0E59}\x{0ED0}-\x{0ED9}\x{0F20}-\x{0F29}\x{1040}-\x{1049}\x{1090}-\x{1099}\x{17E0}-\x{17E9}\x{1810}-\x{1819}\x{1946}-\x{194F}\x{19D0}-\x{19D9}\x{1A80}-\x{1A89}\x{1A90}-\x{1A99}\x{1B50}-\x{1B59}\x{1BB0}-\x{1BB9}\x{1C40}-\x{1C49}\x{1C50}-\x{1C59}\x{A620}-\x{A629}\x{A8D0}-\x{A8D9}\x{A900}-\x{A909}\x{A9D0}-\x{A9D9}\x{AA50}-\x{AA59}\x{ABF0}-\x{ABF9}\x{FF10}-\x{FF19}/0-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-9/;
+
+    # intentionally skipping step 8 of the NACO algorithm; if the string
+    # gets normalized away, that's fine.
+
+    # leading and trailing spaces
+    $str =~ s/\s+/ /g;
+    $str =~ s/^\s+//;
+    $str =~ s/\s+$//g;
+
+    return lc $str;
+$func$ LANGUAGE 'plperlu' STRICT IMMUTABLE;
+
+-- Currently, the only difference from naco_normalize is that search_normalize
+-- turns apostrophes into spaces, while naco_normalize collapses them.
+CREATE OR REPLACE FUNCTION public.search_normalize( TEXT, TEXT ) RETURNS TEXT AS $func$
+
+    use strict;
+    use Unicode::Normalize;
+    use Encode;
+
+    my $str = shift;
+    my $sf = shift;
+
+    # Apply NACO normalization to input string; based on
+    # http://www.loc.gov/catdir/pcc/naco/SCA_PccNormalization_Final_revised.pdf
+    #
+    # Note that unlike a strict reading of the NACO normalization rules,
+    # output is returned as lowercase instead of uppercase for compatibility
+    # with previous versions of the Evergreen naco_normalize routine.
+
+    # Convert to upper-case first; even though final output will be lowercase, doing this will
+    # ensure that the German eszett (ß) and certain ligatures (ff, fi, ffl, etc.) will be handled correctly.
+    # If there are any bugs in Perl's implementation of upcasing, they will be passed through here.
+    $str = uc $str;
+
+    # remove non-filing strings
+    $str =~ s/\x{0098}.*?\x{009C}//g;
+
+    $str = NFKD($str);
+
+    # additional substitutions - 3.6.
+    $str =~ s/\x{00C6}/AE/g;
+    $str =~ s/\x{00DE}/TH/g;
+    $str =~ s/\x{0152}/OE/g;
+    $str =~ tr/\x{0110}\x{00D0}\x{00D8}\x{0141}\x{2113}\x{02BB}\x{02BC}][/DDOLl/d;
+
+    # transformations based on Unicode category codes
+    $str =~ s/[\p{Cc}\p{Cf}\p{Co}\p{Cs}\p{Lm}\p{Mc}\p{Me}\p{Mn}]//g;
+
+	if ($sf && $sf =~ /^a/o) {
+		my $commapos = index($str, ',');
+		if ($commapos > -1) {
+			if ($commapos != length($str) - 1) {
+                $str =~ s/,/\x07/; # preserve first comma
+			}
+		}
+	}
+
+    # since we've stripped out the control characters, we can now
+    # use a few as placeholders temporarily
+    $str =~ tr/+&@\x{266D}\x{266F}#/\x01\x02\x03\x04\x05\x06/;
+    $str =~ s/[\p{Pc}\p{Pd}\p{Pe}\p{Pf}\p{Pi}\p{Po}\p{Ps}\p{Sk}\p{Sm}\p{So}\p{Zl}\p{Zp}\p{Zs}]/ /g;
+    $str =~ tr/\x01\x02\x03\x04\x05\x06\x07/+&@\x{266D}\x{266F}#,/;
+
+    # decimal digits
+    $str =~ tr/\x{0660}-\x{0669}\x{06F0}-\x{06F9}\x{07C0}-\x{07C9}\x{0966}-\x{096F}\x{09E6}-\x{09EF}\x{0A66}-\x{0A6F}\x{0AE6}-\x{0AEF}\x{0B66}-\x{0B6F}\x{0BE6}-\x{0BEF}\x{0C66}-\x{0C6F}\x{0CE6}-\x{0CEF}\x{0D66}-\x{0D6F}\x{0E50}-\x{0E59}\x{0ED0}-\x{0ED9}\x{0F20}-\x{0F29}\x{1040}-\x{1049}\x{1090}-\x{1099}\x{17E0}-\x{17E9}\x{1810}-\x{1819}\x{1946}-\x{194F}\x{19D0}-\x{19D9}\x{1A80}-\x{1A89}\x{1A90}-\x{1A99}\x{1B50}-\x{1B59}\x{1BB0}-\x{1BB9}\x{1C40}-\x{1C49}\x{1C50}-\x{1C59}\x{A620}-\x{A629}\x{A8D0}-\x{A8D9}\x{A900}-\x{A909}\x{A9D0}-\x{A9D9}\x{AA50}-\x{AA59}\x{ABF0}-\x{ABF9}\x{FF10}-\x{FF19}/0-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-9/;
+
+    # intentionally skipping step 8 of the NACO algorithm; if the string
+    # gets normalized away, that's fine.
+
+    # leading and trailing spaces
+    $str =~ s/\s+/ /g;
+    $str =~ s/^\s+//;
+    $str =~ s/\s+$//g;
+
+    return lc $str;
+$func$ LANGUAGE 'plperlu' STRICT IMMUTABLE;
+
+-- Evergreen DB patch XXXX.data.prefer_external_url_OUS.sql
+--
+-- FIXME: insert description of change, if needed
+--
+
+-- check whether patch can be applied
+SELECT evergreen.upgrade_deps_block_check('0853', :eg_version);
+
+INSERT into config.org_unit_setting_type
+( name, grp, label, description, datatype, fm_class ) VALUES
+( 'lib.prefer_external_url', 'lib',
+  'Use external "library information URL" in copy table, if available',
+  'If set to true, the library name in the copy details section will link to the URL associated with the "Library information URL" library setting rather than the library information page generated by Evergreen.',
+  'bool', null
+);
+
+
+SELECT evergreen.upgrade_deps_block_check('0854', :eg_version);
+
+INSERT INTO permission.perm_list ( id, code, description ) VALUES (
+    553,
+    'UPDATE_ORG_UNIT_SETTING.circ.min_item_price',
+    oils_i18n_gettext(
+        553,
+        'UPDATE_ORG_UNIT_SETTING.circ.min_item_price',
+        'ppl',
+        'description'
+    )
+), (
+	554,
+    'UPDATE_ORG_UNIT_SETTING.circ.max_item_price',
+    oils_i18n_gettext(
+        554,
+        'UPDATE_ORG_UNIT_SETTING.circ.max_item_price',
+        'ppl',
+        'description'
+    )
+);
+
+INSERT into config.org_unit_setting_type
+    ( name, grp, label, description, datatype, fm_class )
+VALUES (
+    'circ.min_item_price',
+	'finance',
+    oils_i18n_gettext(
+        'circ.min_item_price',
+        'Minimum Item Price',
+        'coust', 'label'),
+    oils_i18n_gettext(
+        'circ.min_item_price',
+        'When charging for lost items, charge this amount as a minimum.',
+        'coust', 'description'),
+    'currency',
+    NULL
+), (
+    'circ.max_item_price',
+    'finance',
+    oils_i18n_gettext(
+        'circ.max_item_price',
+        'Maximum Item Price',
+        'coust', 'label'),
+    oils_i18n_gettext(
+        'circ.max_item_price',
+        'When charging for lost items, limit the charge to this as a maximum.',
+        'coust', 'description'),
+    'currency',
+    NULL
+);
+
+-- Compiled list of all changed functions and views where we went from:
+--   array_accum() to array_agg()
+--   array_to_string(array_agg()) to string_agg()
+
+
+SELECT evergreen.upgrade_deps_block_check('0855', :eg_version);
+
+-- from 000.functions.general.sql
+
+
+-- from 002.functions.config.sql
+
+CREATE OR REPLACE FUNCTION public.extract_marc_field ( TEXT, BIGINT, TEXT, TEXT ) RETURNS TEXT AS $$
+    SELECT regexp_replace(string_agg(output,' '),$4,'','g') FROM oils_xpath_table('id', 'marc', $1, $3, 'id='||$2)x(id INT, output TEXT);
+$$ LANGUAGE SQL;
+
+
+-- from 011.schema.authority.sql
+
+CREATE OR REPLACE FUNCTION authority.axis_authority_tags(a TEXT) RETURNS INT[] AS $$
+    SELECT ARRAY_AGG(field) FROM authority.browse_axis_authority_field_map WHERE axis = $1;
+$$ LANGUAGE SQL;
+
+CREATE OR REPLACE FUNCTION authority.axis_authority_tags_refs(a TEXT) RETURNS INT[] AS $$
+    SELECT ARRAY_AGG(y) from (
+       SELECT  unnest(ARRAY_CAT(
+                 ARRAY[a.field],
+                 (SELECT ARRAY_AGG(x.id) FROM authority.control_set_authority_field x WHERE x.main_entry = a.field)
+             )) y
+       FROM  authority.browse_axis_authority_field_map a
+       WHERE axis = $1) x
+$$ LANGUAGE SQL;
+
+CREATE OR REPLACE FUNCTION authority.btag_authority_tags(btag TEXT) RETURNS INT[] AS $$
+    SELECT ARRAY_AGG(authority_field) FROM authority.control_set_bib_field WHERE tag = $1
+$$ LANGUAGE SQL;
+
+CREATE OR REPLACE FUNCTION authority.btag_authority_tags_refs(btag TEXT) RETURNS INT[] AS $$
+    SELECT ARRAY_AGG(y) from (
+        SELECT  unnest(ARRAY_CAT(
+                    ARRAY[a.authority_field],
+                    (SELECT ARRAY_AGG(x.id) FROM authority.control_set_authority_field x WHERE x.main_entry = a.authority_field)
+                )) y
+      FROM  authority.control_set_bib_field a
+      WHERE a.tag = $1) x
+$$ LANGUAGE SQL;
+
+CREATE OR REPLACE FUNCTION authority.atag_authority_tags(atag TEXT) RETURNS INT[] AS $$
+    SELECT ARRAY_AGG(id) FROM authority.control_set_authority_field WHERE tag = $1
+$$ LANGUAGE SQL;
+
+CREATE OR REPLACE FUNCTION authority.atag_authority_tags_refs(atag TEXT) RETURNS INT[] AS $$
+    SELECT ARRAY_AGG(y) from (
+        SELECT  unnest(ARRAY_CAT(
+                    ARRAY[a.id],
+                    (SELECT ARRAY_AGG(x.id) FROM authority.control_set_authority_field x WHERE x.main_entry = a.id)
+                )) y
+      FROM  authority.control_set_authority_field a
+      WHERE a.tag = $1) x
+$$ LANGUAGE SQL;
+
+
+-- from 012.schema.vandelay.sql
+
+CREATE OR REPLACE FUNCTION vandelay.extract_rec_attrs ( xml TEXT, attr_defs TEXT[]) RETURNS hstore AS $_$
+DECLARE
+    transformed_xml TEXT;
+    prev_xfrm       TEXT;
+    normalizer      RECORD;
+    xfrm            config.xml_transform%ROWTYPE;
+    attr_value      TEXT;
+    new_attrs       HSTORE := ''::HSTORE;
+    attr_def        config.record_attr_definition%ROWTYPE;
+BEGIN
+
+    FOR attr_def IN SELECT * FROM config.record_attr_definition WHERE name IN (SELECT * FROM UNNEST(attr_defs)) ORDER BY format LOOP
+
+        IF attr_def.tag IS NOT NULL THEN -- tag (and optional subfield list) selection
+            SELECT  STRING_AGG(x.value, COALESCE(attr_def.joiner,' ')) INTO attr_value
+              FROM  vandelay.flatten_marc(xml) AS x
+              WHERE x.tag LIKE attr_def.tag
+                    AND CASE
+                        WHEN attr_def.sf_list IS NOT NULL
+                            THEN POSITION(x.subfield IN attr_def.sf_list) > 0
+                        ELSE TRUE
+                        END
+              GROUP BY x.tag
+              ORDER BY x.tag
+              LIMIT 1;
+
+        ELSIF attr_def.fixed_field IS NOT NULL THEN -- a named fixed field, see config.marc21_ff_pos_map.fixed_field
+            attr_value := vandelay.marc21_extract_fixed_field(xml, attr_def.fixed_field);
+
+        ELSIF attr_def.xpath IS NOT NULL THEN -- and xpath expression
+
+            SELECT INTO xfrm * FROM config.xml_transform WHERE name = attr_def.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(xml,xfrm.xslt);
+                ELSE
+                    transformed_xml := xml;
+                END IF;
+
+                prev_xfrm := xfrm.name;
+            END IF;
+
+            IF xfrm.name IS NULL THEN
+                -- just grab the marcxml (empty) transform
+                SELECT INTO xfrm * FROM config.xml_transform WHERE xslt = '---' LIMIT 1;
+                prev_xfrm := xfrm.name;
+            END IF;
+
+            attr_value := oils_xpath_string(attr_def.xpath, transformed_xml, COALESCE(attr_def.joiner,' '), ARRAY[ARRAY[xfrm.prefix, xfrm.namespace_uri]]);
+
+        ELSIF attr_def.phys_char_sf IS NOT NULL THEN -- a named Physical Characteristic, see config.marc21_physical_characteristic_*_map
+            SELECT  m.value::TEXT INTO attr_value
+              FROM  vandelay.marc21_physical_characteristics(xml) v
+                    JOIN config.marc21_physical_characteristic_value_map m ON (m.id = v.value)
+              WHERE v.subfield = attr_def.phys_char_sf
+              LIMIT 1; -- Just in case ...
+
+        END IF;
+
+        -- apply index normalizers to attr_value
+        FOR normalizer IN
+            SELECT  n.func AS func,
+                    n.param_count AS param_count,
+                    m.params AS params
+              FROM  config.index_normalizer n
+                    JOIN config.record_attr_index_norm_map m ON (m.norm = n.id)
+              WHERE attr = attr_def.name
+              ORDER BY m.pos LOOP
+                EXECUTE 'SELECT ' || normalizer.func || '(' ||
+                    quote_nullable( attr_value ) ||
+                    CASE
+                        WHEN normalizer.param_count > 0
+                            THEN ',' || REPLACE(REPLACE(BTRIM(normalizer.params,'[]'),E'\'',E'\\\''),E'"',E'\'')
+                            ELSE ''
+                        END ||
+                    ')' INTO attr_value;
+
+        END LOOP;
+
+        -- Add the new value to the hstore
+        new_attrs := new_attrs || hstore( attr_def.name, attr_value );
+
+    END LOOP;
+
+    RETURN new_attrs;
+END;
+$_$ LANGUAGE PLPGSQL;
+
+CREATE OR REPLACE FUNCTION vandelay.extract_rec_attrs ( xml TEXT ) RETURNS hstore AS $_$
+    SELECT vandelay.extract_rec_attrs( $1, (SELECT ARRAY_AGG(name) FROM config.record_attr_definition));
+$_$ LANGUAGE SQL;
+
+CREATE OR REPLACE FUNCTION vandelay.match_set_test_marcxml(
+    match_set_id INTEGER, record_xml TEXT, bucket_id INTEGER 
+) RETURNS SETOF vandelay.match_set_test_result AS $$
+DECLARE
+    tags_rstore HSTORE;
+    svf_rstore  HSTORE;
+    coal        TEXT;
+    joins       TEXT;
+    query_      TEXT;
+    wq          TEXT;
+    qvalue      INTEGER;
+    rec         RECORD;
+BEGIN
+    tags_rstore := vandelay.flatten_marc_hstore(record_xml);
+    svf_rstore := vandelay.extract_rec_attrs(record_xml);
+
+    CREATE TEMPORARY TABLE _vandelay_tmp_qrows (q INTEGER);
+    CREATE TEMPORARY TABLE _vandelay_tmp_jrows (j TEXT);
+
+    -- generate the where clause and return that directly (into wq), and as
+    -- a side-effect, populate the _vandelay_tmp_[qj]rows tables.
+    wq := vandelay.get_expr_from_match_set(match_set_id, tags_rstore);
+
+    query_ := 'SELECT DISTINCT(record), ';
+
+    -- qrows table is for the quality bits we add to the SELECT clause
+    SELECT STRING_AGG(
+        'COALESCE(n' || q::TEXT || '.quality, 0)', ' + '
+    ) INTO coal FROM _vandelay_tmp_qrows;
+
+    -- our query string so far is the SELECT clause and the inital FROM.
+    -- no JOINs yet nor the WHERE clause
+    query_ := query_ || coal || ' AS quality ' || E'\n';
+
+    -- jrows table is for the joins we must make (and the real text conditions)
+    SELECT STRING_AGG(j, E'\n') INTO joins
+        FROM _vandelay_tmp_jrows;
+
+    -- add those joins and the where clause to our query.
+    query_ := query_ || joins || E'\n';
+
+    -- join the record bucket
+    IF bucket_id IS NOT NULL THEN
+        query_ := query_ || 'JOIN container.biblio_record_entry_bucket_item ' ||
+            'brebi ON (brebi.target_biblio_record_entry = record ' ||
+            'AND brebi.bucket = ' || bucket_id || E')\n';
+    END IF;
+
+    query_ := query_ || 'JOIN biblio.record_entry bre ON (bre.id = record) ' || 'WHERE ' || wq || ' AND not bre.deleted';
+
+    -- this will return rows of record,quality
+    FOR rec IN EXECUTE query_ USING tags_rstore, svf_rstore LOOP
+        RETURN NEXT rec;
+    END LOOP;
+
+    DROP TABLE _vandelay_tmp_qrows;
+    DROP TABLE _vandelay_tmp_jrows;
+    RETURN;
+END;
+$$ LANGUAGE PLPGSQL;
+
+CREATE OR REPLACE FUNCTION vandelay.flatten_marc_hstore(
+    record_xml TEXT
+) RETURNS HSTORE AS $func$
+BEGIN
+    RETURN (SELECT
+        HSTORE(
+            ARRAY_AGG(tag || (COALESCE(subfield, ''))),
+            ARRAY_AGG(value)
+        )
+        FROM (
+            SELECT  tag, subfield, ARRAY_AGG(value)::TEXT AS value
+              FROM  (SELECT tag,
+                            subfield,
+                            CASE WHEN tag = '020' THEN -- caseless -- isbn
+                                LOWER((REGEXP_MATCHES(value,$$^(\S{10,17})$$))[1] || '%')
+                            WHEN tag = '022' THEN -- caseless -- issn
+                                LOWER((REGEXP_MATCHES(value,$$^(\S{4}[- ]?\S{4})$$))[1] || '%')
+                            WHEN tag = '024' THEN -- caseless -- upc (other)
+                                LOWER(value || '%')
+                            ELSE
+                                value
+                            END AS value
+                      FROM  vandelay.flatten_marc(record_xml)) x
+                GROUP BY tag, subfield ORDER BY tag, subfield
+        ) subquery
+    );
+END;
+$func$ LANGUAGE PLPGSQL;
+
+CREATE OR REPLACE FUNCTION vandelay.get_expr_from_match_set_point(
+    node vandelay.match_set_point,
+    tags_rstore HSTORE
+) RETURNS TEXT AS $$
+DECLARE
+    q           TEXT;
+    i           INTEGER;
+    this_op     TEXT;
+    children    INTEGER[];
+    child       vandelay.match_set_point;
+BEGIN
+    SELECT ARRAY_AGG(id) INTO children FROM vandelay.match_set_point
+        WHERE parent = node.id;
+
+    IF ARRAY_LENGTH(children, 1) > 0 THEN
+        this_op := vandelay._get_expr_render_one(node);
+        q := '(';
+        i := 1;
+        WHILE children[i] IS NOT NULL LOOP
+            SELECT * INTO child FROM vandelay.match_set_point
+                WHERE id = children[i];
+            IF i > 1 THEN
+                q := q || ' ' || this_op || ' ';
+            END IF;
+            i := i + 1;
+            q := q || vandelay.get_expr_from_match_set_point(child, tags_rstore);
+        END LOOP;
+        q := q || ')';
+        RETURN q;
+    ELSIF node.bool_op IS NULL THEN
+        PERFORM vandelay._get_expr_push_qrow(node);
+        PERFORM vandelay._get_expr_push_jrow(node, tags_rstore);
+        RETURN vandelay._get_expr_render_one(node);
+    ELSE
+        RETURN '';
+    END IF;
+END;
+$$  LANGUAGE PLPGSQL;
+
+
+-- from 030.schema.metabib.sql
+
+CREATE OR REPLACE FUNCTION biblio.extract_located_uris( bib_id BIGINT, marcxml TEXT, editor_id INT ) RETURNS VOID AS $func$
+DECLARE
+    uris            TEXT[];
+    uri_xml         TEXT;
+    uri_label       TEXT;
+    uri_href        TEXT;
+    uri_use         TEXT;
+    uri_owner_list  TEXT[];
+    uri_owner       TEXT;
+    uri_owner_id    INT;
+    uri_id          INT;
+    uri_cn_id       INT;
+    uri_map_id      INT;
+BEGIN
+
+    -- Clear any URI mappings and call numbers for this bib.
+    -- This leads to acn / auricnm inflation, but also enables
+    -- old acn/auricnm's to go away and for bibs to be deleted.
+    FOR uri_cn_id IN SELECT id FROM asset.call_number WHERE record = bib_id AND label = '##URI##' AND NOT deleted LOOP
+        DELETE FROM asset.uri_call_number_map WHERE call_number = uri_cn_id;
+        DELETE FROM asset.call_number WHERE id = uri_cn_id;
+    END LOOP;
+
+    uris := oils_xpath('//*[@tag="856" and (@ind1="4" or @ind1="1") and (@ind2="0" or @ind2="1")]',marcxml);
+    IF ARRAY_UPPER(uris,1) > 0 THEN
+        FOR i IN 1 .. ARRAY_UPPER(uris, 1) LOOP
+            -- First we pull info out of the 856
+            uri_xml     := uris[i];
+
+            uri_href    := (oils_xpath('//*[@code="u"]/text()',uri_xml))[1];
+            uri_label   := (oils_xpath('//*[@code="y"]/text()|//*[@code="3"]/text()',uri_xml))[1];
+            uri_use     := (oils_xpath('//*[@code="z"]/text()|//*[@code="2"]/text()|//*[@code="n"]/text()',uri_xml))[1];
+
+            IF uri_label IS NULL THEN
+                uri_label := uri_href;
+            END IF;
+            CONTINUE WHEN uri_href IS NULL;
+
+            -- Get the distinct list of libraries wanting to use 
+            SELECT  ARRAY_AGG(
+                        DISTINCT REGEXP_REPLACE(
+                            x,
+                            $re$^.*?\((\w+)\).*$$re$,
+                            E'\\1'
+                        )
+                    ) INTO uri_owner_list
+              FROM  UNNEST(
+                        oils_xpath(
+                            '//*[@code="9"]/text()|//*[@code="w"]/text()|//*[@code="n"]/text()',
+                            uri_xml
+                        )
+                    )x;
+
+            IF ARRAY_UPPER(uri_owner_list,1) > 0 THEN
+
+                -- look for a matching uri
+                IF uri_use IS NULL THEN
+                    SELECT id INTO uri_id
+                        FROM asset.uri
+                        WHERE label = uri_label AND href = uri_href AND use_restriction IS NULL AND active
+                        ORDER BY id LIMIT 1;
+                    IF NOT FOUND THEN -- create one
+                        INSERT INTO asset.uri (label, href, use_restriction) VALUES (uri_label, uri_href, uri_use);
+                        SELECT id INTO uri_id
+                            FROM asset.uri
+                            WHERE label = uri_label AND href = uri_href AND use_restriction IS NULL AND active;
+                    END IF;
+                ELSE
+                    SELECT id INTO uri_id
+                        FROM asset.uri
+                        WHERE label = uri_label AND href = uri_href AND use_restriction = uri_use AND active
+                        ORDER BY id LIMIT 1;
+                    IF NOT FOUND THEN -- create one
+                        INSERT INTO asset.uri (label, href, use_restriction) VALUES (uri_label, uri_href, uri_use);
+                        SELECT id INTO uri_id
+                            FROM asset.uri
+                            WHERE label = uri_label AND href = uri_href AND use_restriction = uri_use AND active;
+                    END IF;
+                END IF;
+
+                FOR j IN 1 .. ARRAY_UPPER(uri_owner_list, 1) LOOP
+                    uri_owner := uri_owner_list[j];
+
+                    SELECT id INTO uri_owner_id FROM actor.org_unit WHERE shortname = uri_owner;
+                    CONTINUE WHEN NOT FOUND;
+
+                    -- we need a call number to link through
+                    SELECT id INTO uri_cn_id FROM asset.call_number WHERE owning_lib = uri_owner_id AND record = bib_id AND label = '##URI##' AND NOT deleted;
+                    IF NOT FOUND THEN
+                        INSERT INTO asset.call_number (owning_lib, record, create_date, edit_date, creator, editor, label)
+                            VALUES (uri_owner_id, bib_id, 'now', 'now', editor_id, editor_id, '##URI##');
+                        SELECT id INTO uri_cn_id FROM asset.call_number WHERE owning_lib = uri_owner_id AND record = bib_id AND label = '##URI##' AND NOT deleted;
+                    END IF;
+
+                    -- now, link them if they're not already
+                    SELECT id INTO uri_map_id FROM asset.uri_call_number_map WHERE call_number = uri_cn_id AND uri = uri_id;
+                    IF NOT FOUND THEN
+                        INSERT INTO asset.uri_call_number_map (call_number, uri) VALUES (uri_cn_id, uri_id);
+                    END IF;
+
+                END LOOP;
+
+            END IF;
+
+        END LOOP;
+    END IF;
+
+    RETURN;
+END;
+$func$ LANGUAGE PLPGSQL;
+
+-- from 100.circ_matrix.sql
+
+CREATE OR REPLACE FUNCTION actor.calculate_system_penalties( match_user INT, context_org INT ) RETURNS SETOF actor.usr_standing_penalty AS $func$
+DECLARE
+    user_object         actor.usr%ROWTYPE;
+    new_sp_row          actor.usr_standing_penalty%ROWTYPE;
+    existing_sp_row     actor.usr_standing_penalty%ROWTYPE;
+    collections_fines   permission.grp_penalty_threshold%ROWTYPE;
+    max_fines           permission.grp_penalty_threshold%ROWTYPE;
+    max_overdue         permission.grp_penalty_threshold%ROWTYPE;
+    max_items_out       permission.grp_penalty_threshold%ROWTYPE;
+    max_lost            permission.grp_penalty_threshold%ROWTYPE;
+    max_longoverdue     permission.grp_penalty_threshold%ROWTYPE;
+    tmp_grp             INT;
+    items_overdue       INT;
+    items_out           INT;
+    items_lost          INT;
+    items_longoverdue   INT;
+    context_org_list    INT[];
+    current_fines        NUMERIC(8,2) := 0.0;
+    tmp_fines            NUMERIC(8,2);
+    tmp_groc            RECORD;
+    tmp_circ            RECORD;
+    tmp_org             actor.org_unit%ROWTYPE;
+    tmp_penalty         config.standing_penalty%ROWTYPE;
+    tmp_depth           INTEGER;
+BEGIN
+    SELECT INTO user_object * FROM actor.usr WHERE id = match_user;
+
+    -- Max fines
+    SELECT INTO tmp_org * FROM actor.org_unit WHERE id = context_org;
+
+    -- Fail if the user has a high fine balance
+    LOOP
+        tmp_grp := user_object.profile;
+        LOOP
+            SELECT * INTO max_fines FROM permission.grp_penalty_threshold WHERE grp = tmp_grp AND penalty = 1 AND org_unit = tmp_org.id;
+
+            IF max_fines.threshold IS NULL THEN
+                SELECT parent INTO tmp_grp FROM permission.grp_tree WHERE id = tmp_grp;
+            ELSE
+                EXIT;
+            END IF;
+
+            IF tmp_grp IS NULL THEN
+                EXIT;
+            END IF;
+        END LOOP;
+
+        IF max_fines.threshold IS NOT NULL OR tmp_org.parent_ou IS NULL THEN
+            EXIT;
+        END IF;
+
+        SELECT * INTO tmp_org FROM actor.org_unit WHERE id = tmp_org.parent_ou;
+
+    END LOOP;
+
+    IF max_fines.threshold IS NOT NULL THEN
+
+        RETURN QUERY
+            SELECT  *
+              FROM  actor.usr_standing_penalty
+              WHERE usr = match_user
+                    AND org_unit = max_fines.org_unit
+                    AND (stop_date IS NULL or stop_date > NOW())
+                    AND standing_penalty = 1;
+
+        SELECT INTO context_org_list ARRAY_AGG(id) FROM actor.org_unit_full_path( max_fines.org_unit );
+
+        SELECT  SUM(f.balance_owed) INTO current_fines
+          FROM  money.materialized_billable_xact_summary f
+                JOIN (
+                    SELECT  r.id
+                      FROM  booking.reservation r
+                      WHERE r.usr = match_user
+                            AND r.pickup_lib IN (SELECT * FROM unnest(context_org_list))
+                            AND xact_finish IS NULL
+                                UNION ALL
+                    SELECT  g.id
+                      FROM  money.grocery g
+                      WHERE g.usr = match_user
+                            AND g.billing_location IN (SELECT * FROM unnest(context_org_list))
+                            AND xact_finish IS NULL
+                                UNION ALL
+                    SELECT  circ.id
+                      FROM  action.circulation circ
+                      WHERE circ.usr = match_user
+                            AND circ.circ_lib IN (SELECT * FROM unnest(context_org_list))
+                            AND xact_finish IS NULL ) l USING (id);
+
+        IF current_fines >= max_fines.threshold THEN
+            new_sp_row.usr := match_user;
+            new_sp_row.org_unit := max_fines.org_unit;
+            new_sp_row.standing_penalty := 1;
+            RETURN NEXT new_sp_row;
+        END IF;
+    END IF;
+
+    -- Start over for max overdue
+    SELECT INTO tmp_org * FROM actor.org_unit WHERE id = context_org;
+
+    -- Fail if the user has too many overdue items
+    LOOP
+        tmp_grp := user_object.profile;
+        LOOP
+
+            SELECT * INTO max_overdue FROM permission.grp_penalty_threshold WHERE grp = tmp_grp AND penalty = 2 AND org_unit = tmp_org.id;
+
+            IF max_overdue.threshold IS NULL THEN
+                SELECT parent INTO tmp_grp FROM permission.grp_tree WHERE id = tmp_grp;
+            ELSE
+                EXIT;
+            END IF;
+
+            IF tmp_grp IS NULL THEN
+                EXIT;
+            END IF;
+        END LOOP;
+
+        IF max_overdue.threshold IS NOT NULL OR tmp_org.parent_ou IS NULL THEN
+            EXIT;
+        END IF;
+
+        SELECT INTO tmp_org * FROM actor.org_unit WHERE id = tmp_org.parent_ou;
+
+    END LOOP;
+
+    IF max_overdue.threshold IS NOT NULL THEN
+
+        RETURN QUERY
+            SELECT  *
+              FROM  actor.usr_standing_penalty
+              WHERE usr = match_user
+                    AND org_unit = max_overdue.org_unit
+                    AND (stop_date IS NULL or stop_date > NOW())
+                    AND standing_penalty = 2;
+
+        SELECT  INTO items_overdue COUNT(*)
+          FROM  action.circulation circ
+                JOIN  actor.org_unit_full_path( max_overdue.org_unit ) fp ON (circ.circ_lib = fp.id)
+          WHERE circ.usr = match_user
+            AND circ.checkin_time IS NULL
+            AND circ.due_date < NOW()
+            AND (circ.stop_fines = 'MAXFINES' OR circ.stop_fines IS NULL);
+
+        IF items_overdue >= max_overdue.threshold::INT THEN
+            new_sp_row.usr := match_user;
+            new_sp_row.org_unit := max_overdue.org_unit;
+            new_sp_row.standing_penalty := 2;
+            RETURN NEXT new_sp_row;
+        END IF;
+    END IF;
+
+    -- Start over for max out
+    SELECT INTO tmp_org * FROM actor.org_unit WHERE id = context_org;
+
+    -- Fail if the user has too many checked out items
+    LOOP
+        tmp_grp := user_object.profile;
+        LOOP
+            SELECT * INTO max_items_out FROM permission.grp_penalty_threshold WHERE grp = tmp_grp AND penalty = 3 AND org_unit = tmp_org.id;
+
+            IF max_items_out.threshold IS NULL THEN
+                SELECT parent INTO tmp_grp FROM permission.grp_tree WHERE id = tmp_grp;
+            ELSE
+                EXIT;
+            END IF;
+
+            IF tmp_grp IS NULL THEN
+                EXIT;
+            END IF;
+        END LOOP;
+
+        IF max_items_out.threshold IS NOT NULL OR tmp_org.parent_ou IS NULL THEN
+            EXIT;
+        END IF;
+
+        SELECT INTO tmp_org * FROM actor.org_unit WHERE id = tmp_org.parent_ou;
+
+    END LOOP;
+
+
+    -- Fail if the user has too many items checked out
+    IF max_items_out.threshold IS NOT NULL THEN
+
+        RETURN QUERY
+            SELECT  *
+              FROM  actor.usr_standing_penalty
+              WHERE usr = match_user
+                    AND org_unit = max_items_out.org_unit
+                    AND (stop_date IS NULL or stop_date > NOW())
+                    AND standing_penalty = 3;
+
+        SELECT  INTO items_out COUNT(*)
+          FROM  action.circulation circ
+                JOIN  actor.org_unit_full_path( max_items_out.org_unit ) fp ON (circ.circ_lib = fp.id)
+          WHERE circ.usr = match_user
+                AND circ.checkin_time IS NULL
+                AND (circ.stop_fines IN (
+                    SELECT 'MAXFINES'::TEXT
+                    UNION ALL
+                    SELECT 'LONGOVERDUE'::TEXT
+                    UNION ALL
+                    SELECT 'LOST'::TEXT
+                    WHERE 'true' ILIKE
+                    (
+                        SELECT CASE
+                            WHEN (SELECT value FROM actor.org_unit_ancestor_setting('circ.tally_lost', circ.circ_lib)) ILIKE 'true' THEN 'true'
+                            ELSE 'false'
+                        END
+                    )
+                    UNION ALL
+                    SELECT 'CLAIMSRETURNED'::TEXT
+                    WHERE 'false' ILIKE
+                    (
+                        SELECT CASE
+                            WHEN (SELECT value FROM actor.org_unit_ancestor_setting('circ.do_not_tally_claims_returned', circ.circ_lib)) ILIKE 'true' THEN 'true'
+                            ELSE 'false'
+                        END
+                    )
+                    ) OR circ.stop_fines IS NULL)
+                AND xact_finish IS NULL;
+
+           IF items_out >= max_items_out.threshold::INT THEN
+            new_sp_row.usr := match_user;
+            new_sp_row.org_unit := max_items_out.org_unit;
+            new_sp_row.standing_penalty := 3;
+            RETURN NEXT new_sp_row;
+           END IF;
+    END IF;
+
+    -- Start over for max lost
+    SELECT INTO tmp_org * FROM actor.org_unit WHERE id = context_org;
+
+    -- Fail if the user has too many lost items
+    LOOP
+        tmp_grp := user_object.profile;
+        LOOP
+
+            SELECT * INTO max_lost FROM permission.grp_penalty_threshold WHERE grp = tmp_grp AND penalty = 5 AND org_unit = tmp_org.id;
+
+            IF max_lost.threshold IS NULL THEN
+                SELECT parent INTO tmp_grp FROM permission.grp_tree WHERE id = tmp_grp;
+            ELSE
+                EXIT;
+            END IF;
+
+            IF tmp_grp IS NULL THEN
+                EXIT;
+            END IF;
+        END LOOP;
+
+        IF max_lost.threshold IS NOT NULL OR tmp_org.parent_ou IS NULL THEN
+            EXIT;
+        END IF;
+
+        SELECT INTO tmp_org * FROM actor.org_unit WHERE id = tmp_org.parent_ou;
+
+    END LOOP;
+
+    IF max_lost.threshold IS NOT NULL THEN
+
+        RETURN QUERY
+            SELECT  *
+            FROM  actor.usr_standing_penalty
+            WHERE usr = match_user
+                AND org_unit = max_lost.org_unit
+                AND (stop_date IS NULL or stop_date > NOW())
+                AND standing_penalty = 5;
+
+        SELECT  INTO items_lost COUNT(*)
+        FROM  action.circulation circ
+            JOIN  actor.org_unit_full_path( max_lost.org_unit ) fp ON (circ.circ_lib = fp.id)
+        WHERE circ.usr = match_user
+            AND circ.checkin_time IS NULL
+            AND (circ.stop_fines = 'LOST')
+            AND xact_finish IS NULL;
+
+        IF items_lost >= max_lost.threshold::INT AND 0 < max_lost.threshold::INT THEN
+            new_sp_row.usr := match_user;
+            new_sp_row.org_unit := max_lost.org_unit;
+            new_sp_row.standing_penalty := 5;
+            RETURN NEXT new_sp_row;
+        END IF;
+    END IF;
+
+    -- Start over for max longoverdue
+    SELECT INTO tmp_org * FROM actor.org_unit WHERE id = context_org;
+
+    -- Fail if the user has too many longoverdue items
+    LOOP
+        tmp_grp := user_object.profile;
+        LOOP
+
+            SELECT * INTO max_longoverdue 
+                FROM permission.grp_penalty_threshold 
+                WHERE grp = tmp_grp AND 
+                    penalty = 35 AND 
+                    org_unit = tmp_org.id;
+
+            IF max_longoverdue.threshold IS NULL THEN
+                SELECT parent INTO tmp_grp 
+                    FROM permission.grp_tree WHERE id = tmp_grp;
+            ELSE
+                EXIT;
+            END IF;
+
+            IF tmp_grp IS NULL THEN
+                EXIT;
+            END IF;
+        END LOOP;
+
+        IF max_longoverdue.threshold IS NOT NULL 
+                OR tmp_org.parent_ou IS NULL THEN
+            EXIT;
+        END IF;
+
+        SELECT INTO tmp_org * FROM actor.org_unit WHERE id = tmp_org.parent_ou;
+
+    END LOOP;
+
+    IF max_longoverdue.threshold IS NOT NULL THEN
+
+        RETURN QUERY
+            SELECT  *
+            FROM  actor.usr_standing_penalty
+            WHERE usr = match_user
+                AND org_unit = max_longoverdue.org_unit
+                AND (stop_date IS NULL or stop_date > NOW())
+                AND standing_penalty = 35;
+
+        SELECT INTO items_longoverdue COUNT(*)
+        FROM action.circulation circ
+            JOIN actor.org_unit_full_path( max_longoverdue.org_unit ) fp 
+                ON (circ.circ_lib = fp.id)
+        WHERE circ.usr = match_user
+            AND circ.checkin_time IS NULL
+            AND (circ.stop_fines = 'LONGOVERDUE')
+            AND xact_finish IS NULL;
+
+        IF items_longoverdue >= max_longoverdue.threshold::INT 
+                AND 0 < max_longoverdue.threshold::INT THEN
+            new_sp_row.usr := match_user;
+            new_sp_row.org_unit := max_longoverdue.org_unit;
+            new_sp_row.standing_penalty := 35;
+            RETURN NEXT new_sp_row;
+        END IF;
+    END IF;
+
+
+    -- Start over for collections warning
+    SELECT INTO tmp_org * FROM actor.org_unit WHERE id = context_org;
+
+    -- Fail if the user has a collections-level fine balance
+    LOOP
+        tmp_grp := user_object.profile;
+        LOOP
+            SELECT * INTO max_fines FROM permission.grp_penalty_threshold WHERE grp = tmp_grp AND penalty = 4 AND org_unit = tmp_org.id;
+
+            IF max_fines.threshold IS NULL THEN
+                SELECT parent INTO tmp_grp FROM permission.grp_tree WHERE id = tmp_grp;
+            ELSE
+                EXIT;
+            END IF;
+
+            IF tmp_grp IS NULL THEN
+                EXIT;
+            END IF;
+        END LOOP;
+
+        IF max_fines.threshold IS NOT NULL OR tmp_org.parent_ou IS NULL THEN
+            EXIT;
+        END IF;
+
+        SELECT * INTO tmp_org FROM actor.org_unit WHERE id = tmp_org.parent_ou;
+
+    END LOOP;
+
+    IF max_fines.threshold IS NOT NULL THEN
+
+        RETURN QUERY
+            SELECT  *
+              FROM  actor.usr_standing_penalty
+              WHERE usr = match_user
+                    AND org_unit = max_fines.org_unit
+                    AND (stop_date IS NULL or stop_date > NOW())
+                    AND standing_penalty = 4;
+
+        SELECT INTO context_org_list ARRAY_AGG(id) FROM actor.org_unit_full_path( max_fines.org_unit );
+
+        SELECT  SUM(f.balance_owed) INTO current_fines
+          FROM  money.materialized_billable_xact_summary f
+                JOIN (
+                    SELECT  r.id
+                      FROM  booking.reservation r
+                      WHERE r.usr = match_user
+                            AND r.pickup_lib IN (SELECT * FROM unnest(context_org_list))
+                            AND r.xact_finish IS NULL
+                                UNION ALL
+                    SELECT  g.id
+                      FROM  money.grocery g
+                      WHERE g.usr = match_user
+                            AND g.billing_location IN (SELECT * FROM unnest(context_org_list))
+                            AND g.xact_finish IS NULL
+                                UNION ALL
+                    SELECT  circ.id
+                      FROM  action.circulation circ
+                      WHERE circ.usr = match_user
+                            AND circ.circ_lib IN (SELECT * FROM unnest(context_org_list))
+                            AND circ.xact_finish IS NULL ) l USING (id);
+
+        IF current_fines >= max_fines.threshold THEN
+            new_sp_row.usr := match_user;
+            new_sp_row.org_unit := max_fines.org_unit;
+            new_sp_row.standing_penalty := 4;
+            RETURN NEXT new_sp_row;
+        END IF;
+    END IF;
+
+    -- Start over for in collections
+    SELECT INTO tmp_org * FROM actor.org_unit WHERE id = context_org;
+
+    -- Remove the in-collections penalty if the user has paid down enough
+    -- This penalty is different, because this code is not responsible for creating 
+    -- new in-collections penalties, only for removing them
+    LOOP
+        tmp_grp := user_object.profile;
+        LOOP
+            SELECT * INTO max_fines FROM permission.grp_penalty_threshold WHERE grp = tmp_grp AND penalty = 30 AND org_unit = tmp_org.id;
+
+            IF max_fines.threshold IS NULL THEN
+                SELECT parent INTO tmp_grp FROM permission.grp_tree WHERE id = tmp_grp;
+            ELSE
+                EXIT;
+            END IF;
+
+            IF tmp_grp IS NULL THEN
+                EXIT;
+            END IF;
+        END LOOP;
+
+        IF max_fines.threshold IS NOT NULL OR tmp_org.parent_ou IS NULL THEN
+            EXIT;
+        END IF;
+
+        SELECT * INTO tmp_org FROM actor.org_unit WHERE id = tmp_org.parent_ou;
+
+    END LOOP;
+
+    IF max_fines.threshold IS NOT NULL THEN
+
+        SELECT INTO context_org_list ARRAY_AGG(id) FROM actor.org_unit_full_path( max_fines.org_unit );
+
+        -- first, see if the user had paid down to the threshold
+        SELECT  SUM(f.balance_owed) INTO current_fines
+          FROM  money.materialized_billable_xact_summary f
+                JOIN (
+                    SELECT  r.id
+                      FROM  booking.reservation r
+                      WHERE r.usr = match_user
+                            AND r.pickup_lib IN (SELECT * FROM unnest(context_org_list))
+                            AND r.xact_finish IS NULL
+                                UNION ALL
+                    SELECT  g.id
+                      FROM  money.grocery g
+                      WHERE g.usr = match_user
+                            AND g.billing_location IN (SELECT * FROM unnest(context_org_list))
+                            AND g.xact_finish IS NULL
+                                UNION ALL
+                    SELECT  circ.id
+                      FROM  action.circulation circ
+                      WHERE circ.usr = match_user
+                            AND circ.circ_lib IN (SELECT * FROM unnest(context_org_list))
+                            AND circ.xact_finish IS NULL ) l USING (id);
+
+        IF current_fines IS NULL OR current_fines <= max_fines.threshold THEN
+            -- patron has paid down enough
+
+            SELECT INTO tmp_penalty * FROM config.standing_penalty WHERE id = 30;
+
+            IF tmp_penalty.org_depth IS NOT NULL THEN
+
+                -- since this code is not responsible for applying the penalty, it can't 
+                -- guarantee the current context org will match the org at which the penalty 
+                --- was applied.  search up the org tree until we hit the configured penalty depth
+                SELECT INTO tmp_org * FROM actor.org_unit WHERE id = context_org;
+                SELECT INTO tmp_depth depth FROM actor.org_unit_type WHERE id = tmp_org.ou_type;
+
+                WHILE tmp_depth >= tmp_penalty.org_depth LOOP
+
+                    RETURN QUERY
+                        SELECT  *
+                          FROM  actor.usr_standing_penalty
+                          WHERE usr = match_user
+                                AND org_unit = tmp_org.id
+                                AND (stop_date IS NULL or stop_date > NOW())
+                                AND standing_penalty = 30;
+
+                    IF tmp_org.parent_ou IS NULL THEN
+                        EXIT;
+                    END IF;
+
+                    SELECT * INTO tmp_org FROM actor.org_unit WHERE id = tmp_org.parent_ou;
+                    SELECT INTO tmp_depth depth FROM actor.org_unit_type WHERE id = tmp_org.ou_type;
+                END LOOP;
+
+            ELSE
+
+                -- no penalty depth is defined, look for exact matches
+
+                RETURN QUERY
+                    SELECT  *
+                      FROM  actor.usr_standing_penalty
+                      WHERE usr = match_user
+                            AND org_unit = max_fines.org_unit
+                            AND (stop_date IS NULL or stop_date > NOW())
+                            AND standing_penalty = 30;
+            END IF;
+    
+        END IF;
+
+    END IF;
+
+    RETURN;
+END;
+$func$ LANGUAGE plpgsql;
+
+
+-- from 110.hold_matrix.sql
+
+CREATE OR REPLACE FUNCTION action.hold_request_permit_test( pickup_ou INT, request_ou INT, match_item BIGINT, match_user INT, match_requestor INT, retargetting BOOL ) RETURNS SETOF action.matrix_test_result AS $func$
+DECLARE
+    matchpoint_id        INT;
+    user_object        actor.usr%ROWTYPE;
+    age_protect_object    config.rule_age_hold_protect%ROWTYPE;
+    standing_penalty    config.standing_penalty%ROWTYPE;
+    transit_range_ou_type    actor.org_unit_type%ROWTYPE;
+    transit_source        actor.org_unit%ROWTYPE;
+    item_object        asset.copy%ROWTYPE;
+    item_cn_object     asset.call_number%ROWTYPE;
+    item_status_object  config.copy_status%ROWTYPE;
+    item_location_object    asset.copy_location%ROWTYPE;
+    ou_skip              actor.org_unit_setting%ROWTYPE;
+    result            action.matrix_test_result;
+    hold_test        config.hold_matrix_matchpoint%ROWTYPE;
+    use_active_date   TEXT;
+    age_protect_date  TIMESTAMP WITH TIME ZONE;
+    hold_count        INT;
+    hold_transit_prox    INT;
+    frozen_hold_count    INT;
+    context_org_list    INT[];
+    done            BOOL := FALSE;
+    hold_penalty TEXT;
+BEGIN
+    SELECT INTO user_object * FROM actor.usr WHERE id = match_user;
+    SELECT INTO context_org_list ARRAY_AGG(id) FROM actor.org_unit_full_path( pickup_ou );
+
+    result.success := TRUE;
+
+    -- The HOLD penalty block only applies to new holds.
+    -- The CAPTURE penalty block applies to existing holds.
+    hold_penalty := 'HOLD';
+    IF retargetting THEN
+        hold_penalty := 'CAPTURE';
+    END IF;
+
+    -- Fail if we couldn't find a user
+    IF user_object.id IS NULL THEN
+        result.fail_part := 'no_user';
+        result.success := FALSE;
+        done := TRUE;
+        RETURN NEXT result;
+        RETURN;
+    END IF;
+
+    SELECT INTO item_object * FROM asset.copy WHERE id = match_item;
+
+    -- Fail if we couldn't find a copy
+    IF item_object.id IS NULL THEN
+        result.fail_part := 'no_item';
+        result.success := FALSE;
+        done := TRUE;
+        RETURN NEXT result;
+        RETURN;
+    END IF;
+
+    SELECT INTO matchpoint_id action.find_hold_matrix_matchpoint(pickup_ou, request_ou, match_item, match_user, match_requestor);
+    result.matchpoint := matchpoint_id;
+
+    SELECT INTO ou_skip * FROM actor.org_unit_setting WHERE name = 'circ.holds.target_skip_me' AND org_unit = item_object.circ_lib;
+
+    -- Fail if the circ_lib for the item has circ.holds.target_skip_me set to true
+    IF ou_skip.id IS NOT NULL AND ou_skip.value = 'true' THEN
+        result.fail_part := 'circ.holds.target_skip_me';
+        result.success := FALSE;
+        done := TRUE;
+        RETURN NEXT result;
+        RETURN;
+    END IF;
+
+    -- Fail if user is barred
+    IF user_object.barred IS TRUE THEN
+        result.fail_part := 'actor.usr.barred';
+        result.success := FALSE;
+        done := TRUE;
+        RETURN NEXT result;
+        RETURN;
+    END IF;
+
+    SELECT INTO item_cn_object * FROM asset.call_number WHERE id = item_object.call_number;
+    SELECT INTO item_status_object * FROM config.copy_status WHERE id = item_object.status;
+    SELECT INTO item_location_object * FROM asset.copy_location WHERE id = item_object.location;
+
+    -- Fail if we couldn't find any matchpoint (requires a default)
+    IF matchpoint_id IS NULL THEN
+        result.fail_part := 'no_matchpoint';
+        result.success := FALSE;
+        done := TRUE;
+        RETURN NEXT result;
+        RETURN;
+    END IF;
+
+    SELECT INTO hold_test * FROM config.hold_matrix_matchpoint WHERE id = matchpoint_id;
+
+    IF hold_test.holdable IS FALSE THEN
+        result.fail_part := 'config.hold_matrix_test.holdable';
+        result.success := FALSE;
+        done := TRUE;
+        RETURN NEXT result;
+    END IF;
+
+    IF item_object.holdable IS FALSE THEN
+        result.fail_part := 'item.holdable';
+        result.success := FALSE;
+        done := TRUE;
+        RETURN NEXT result;
+    END IF;
+
+    IF item_status_object.holdable IS FALSE THEN
+        result.fail_part := 'status.holdable';
+        result.success := FALSE;
+        done := TRUE;
+        RETURN NEXT result;
+    END IF;
+
+    IF item_location_object.holdable IS FALSE THEN
+        result.fail_part := 'location.holdable';
+        result.success := FALSE;
+        done := TRUE;
+        RETURN NEXT result;
+    END IF;
+
+    IF hold_test.transit_range IS NOT NULL THEN
+        SELECT INTO transit_range_ou_type * FROM actor.org_unit_type WHERE id = hold_test.transit_range;
+        IF hold_test.distance_is_from_owner THEN
+            SELECT INTO transit_source ou.* FROM actor.org_unit ou JOIN asset.call_number cn ON (cn.owning_lib = ou.id) WHERE cn.id = item_object.call_number;
+        ELSE
+            SELECT INTO transit_source * FROM actor.org_unit WHERE id = item_object.circ_lib;
+        END IF;
+
+        PERFORM * FROM actor.org_unit_descendants( transit_source.id, transit_range_ou_type.depth ) WHERE id = pickup_ou;
+
+        IF NOT FOUND THEN
+            result.fail_part := 'transit_range';
+            result.success := FALSE;
+            done := TRUE;
+            RETURN NEXT result;
+        END IF;
+    END IF;
+ 
+    FOR standing_penalty IN
+        SELECT  DISTINCT csp.*
+          FROM  actor.usr_standing_penalty usp
+                JOIN config.standing_penalty csp ON (csp.id = usp.standing_penalty)
+          WHERE usr = match_user
+                AND usp.org_unit IN ( SELECT * FROM unnest(context_org_list) )
+                AND (usp.stop_date IS NULL or usp.stop_date > NOW())
+                AND csp.block_list LIKE '%' || hold_penalty || '%' LOOP
+
+        result.fail_part := standing_penalty.name;
+        result.success := FALSE;
+        done := TRUE;
+        RETURN NEXT result;
+    END LOOP;
+
+    IF hold_test.stop_blocked_user IS TRUE THEN
+        FOR standing_penalty IN
+            SELECT  DISTINCT csp.*
+              FROM  actor.usr_standing_penalty usp
+                    JOIN config.standing_penalty csp ON (csp.id = usp.standing_penalty)
+              WHERE usr = match_user
+                    AND usp.org_unit IN ( SELECT * FROM unnest(context_org_list) )
+                    AND (usp.stop_date IS NULL or usp.stop_date > NOW())
+                    AND csp.block_list LIKE '%CIRC%' LOOP
+    
+            result.fail_part := standing_penalty.name;
+            result.success := FALSE;
+            done := TRUE;
+            RETURN NEXT result;
+        END LOOP;
+    END IF;
+
+    IF hold_test.max_holds IS NOT NULL AND NOT retargetting THEN
+        SELECT    INTO hold_count COUNT(*)
+          FROM    action.hold_request
+          WHERE    usr = match_user
+            AND fulfillment_time IS NULL
+            AND cancel_time IS NULL
+            AND CASE WHEN hold_test.include_frozen_holds THEN TRUE ELSE frozen IS FALSE END;
+
+        IF hold_count >= hold_test.max_holds THEN
+            result.fail_part := 'config.hold_matrix_test.max_holds';
+            result.success := FALSE;
+            done := TRUE;
+            RETURN NEXT result;
+        END IF;
+    END IF;
+
+    IF item_object.age_protect IS NOT NULL THEN
+        SELECT INTO age_protect_object * FROM config.rule_age_hold_protect WHERE id = item_object.age_protect;
+        IF hold_test.distance_is_from_owner THEN
+            SELECT INTO use_active_date value FROM actor.org_unit_ancestor_setting('circ.holds.age_protect.active_date', item_cn_object.owning_lib);
+        ELSE
+            SELECT INTO use_active_date value FROM actor.org_unit_ancestor_setting('circ.holds.age_protect.active_date', item_object.circ_lib);
+        END IF;
+        IF use_active_date = 'true' THEN
+            age_protect_date := COALESCE(item_object.active_date, NOW());
+        ELSE
+            age_protect_date := item_object.create_date;
+        END IF;
+        IF age_protect_date + age_protect_object.age > NOW() THEN
+            IF hold_test.distance_is_from_owner THEN
+                SELECT INTO item_cn_object * FROM asset.call_number WHERE id = item_object.call_number;
+                SELECT INTO hold_transit_prox prox FROM actor.org_unit_proximity WHERE from_org = item_cn_object.owning_lib AND to_org = pickup_ou;
+            ELSE
+                SELECT INTO hold_transit_prox prox FROM actor.org_unit_proximity WHERE from_org = item_object.circ_lib AND to_org = pickup_ou;
+            END IF;
+
+            IF hold_transit_prox > age_protect_object.prox THEN
+                result.fail_part := 'config.rule_age_hold_protect.prox';
+                result.success := FALSE;
+                done := TRUE;
+                RETURN NEXT result;
+            END IF;
+        END IF;
+    END IF;
+
+    IF NOT done THEN
+        RETURN NEXT result;
+    END IF;
+
+    RETURN;
+END;
+$func$ LANGUAGE plpgsql;
+
+
+-- from 300.schema.staged_search.sql
+
+
+-- from 990.schema.unapi.sql
+
+CREATE OR REPLACE FUNCTION evergreen.array_remove_item_by_value(inp ANYARRAY, el ANYELEMENT)
+RETURNS anyarray AS $$
+    SELECT ARRAY_AGG(x.e) FROM UNNEST( $1 ) x(e) WHERE x.e <> $2;
+$$ LANGUAGE SQL STABLE;
+
+
+-- from 999.functions.global.sql
+
+CREATE OR REPLACE FUNCTION asset.merge_record_assets( target_record BIGINT, source_record BIGINT ) RETURNS INT AS $func$
+DECLARE
+    moved_objects INT := 0;
+    source_cn     asset.call_number%ROWTYPE;
+    target_cn     asset.call_number%ROWTYPE;
+    metarec       metabib.metarecord%ROWTYPE;
+    hold          action.hold_request%ROWTYPE;
+    ser_rec       serial.record_entry%ROWTYPE;
+    ser_sub       serial.subscription%ROWTYPE;
+    acq_lineitem  acq.lineitem%ROWTYPE;
+    acq_request   acq.user_request%ROWTYPE;
+    booking       booking.resource_type%ROWTYPE;
+    source_part   biblio.monograph_part%ROWTYPE;
+    target_part   biblio.monograph_part%ROWTYPE;
+    multi_home    biblio.peer_bib_copy_map%ROWTYPE;
+    uri_count     INT := 0;
+    counter       INT := 0;
+    uri_datafield TEXT;
+    uri_text      TEXT := '';
+BEGIN
+
+    -- move any 856 entries on records that have at least one MARC-mapped URI entry
+    SELECT  INTO uri_count COUNT(*)
+      FROM  asset.uri_call_number_map m
+            JOIN asset.call_number cn ON (m.call_number = cn.id)
+      WHERE cn.record = source_record;
+
+    IF uri_count > 0 THEN
+        
+        -- This returns more nodes than you might expect:
+        -- 7 instead of 1 for an 856 with $u $y $9
+        SELECT  COUNT(*) INTO counter
+          FROM  oils_xpath_table(
+                    'id',
+                    'marc',
+                    'biblio.record_entry',
+                    '//*[@tag="856"]',
+                    'id=' || source_record
+                ) as t(i int,c text);
+    
+        FOR i IN 1 .. counter LOOP
+            SELECT  '<datafield xmlns="http://www.loc.gov/MARC21/slim"' || 
+			' tag="856"' ||
+			' ind1="' || FIRST(ind1) || '"'  ||
+			' ind2="' || FIRST(ind2) || '">' ||
+                        STRING_AGG(
+                            '<subfield code="' || subfield || '">' ||
+                            regexp_replace(
+                                regexp_replace(
+                                    regexp_replace(data,'&','&amp;','g'),
+                                    '>', '&gt;', 'g'
+                                ),
+                                '<', '&lt;', 'g'
+                            ) || '</subfield>', ''
+                        ) || '</datafield>' INTO uri_datafield
+              FROM  oils_xpath_table(
+                        'id',
+                        'marc',
+                        'biblio.record_entry',
+                        '//*[@tag="856"][position()=' || i || ']/@ind1|' ||
+                        '//*[@tag="856"][position()=' || i || ']/@ind2|' ||
+                        '//*[@tag="856"][position()=' || i || ']/*/@code|' ||
+                        '//*[@tag="856"][position()=' || i || ']/*[@code]',
+                        'id=' || source_record
+                    ) as t(id int,ind1 text, ind2 text,subfield text,data text);
+
+            -- As most of the results will be NULL, protect against NULLifying
+            -- the valid content that we do generate
+            uri_text := uri_text || COALESCE(uri_datafield, '');
+        END LOOP;
+
+        IF uri_text <> '' THEN
+            UPDATE  biblio.record_entry
+              SET   marc = regexp_replace(marc,'(</[^>]*record>)', uri_text || E'\\1')
+              WHERE id = target_record;
+        END IF;
+
+    END IF;
+
+	-- Find and move metarecords to the target record
+	SELECT	INTO metarec *
+	  FROM	metabib.metarecord
+	  WHERE	master_record = source_record;
+
+	IF FOUND THEN
+		UPDATE	metabib.metarecord
+		  SET	master_record = target_record,
+			mods = NULL
+		  WHERE	id = metarec.id;
+
+		moved_objects := moved_objects + 1;
+	END IF;
+
+	-- Find call numbers attached to the source ...
+	FOR source_cn IN SELECT * FROM asset.call_number WHERE record = source_record LOOP
+
+		SELECT	INTO target_cn *
+		  FROM	asset.call_number
+		  WHERE	label = source_cn.label
+			AND owning_lib = source_cn.owning_lib
+			AND record = target_record
+			AND NOT deleted;
+
+		-- ... and if there's a conflicting one on the target ...
+		IF FOUND THEN
+
+			-- ... move the copies to that, and ...
+			UPDATE	asset.copy
+			  SET	call_number = target_cn.id
+			  WHERE	call_number = source_cn.id;
+
+			-- ... move V holds to the move-target call number
+			FOR hold IN SELECT * FROM action.hold_request WHERE target = source_cn.id AND hold_type = 'V' LOOP
+		
+				UPDATE	action.hold_request
+				  SET	target = target_cn.id
+				  WHERE	id = hold.id;
+		
+				moved_objects := moved_objects + 1;
+			END LOOP;
+
+		-- ... if not ...
+		ELSE
+			-- ... just move the call number to the target record
+			UPDATE	asset.call_number
+			  SET	record = target_record
+			  WHERE	id = source_cn.id;
+		END IF;
+
+		moved_objects := moved_objects + 1;
+	END LOOP;
+
+	-- Find T holds targeting the source record ...
+	FOR hold IN SELECT * FROM action.hold_request WHERE target = source_record AND hold_type = 'T' LOOP
+
+		-- ... and move them to the target record
+		UPDATE	action.hold_request
+		  SET	target = target_record
+		  WHERE	id = hold.id;
+
+		moved_objects := moved_objects + 1;
+	END LOOP;
+
+	-- Find serial records targeting the source record ...
+	FOR ser_rec IN SELECT * FROM serial.record_entry WHERE record = source_record LOOP
+		-- ... and move them to the target record
+		UPDATE	serial.record_entry
+		  SET	record = target_record
+		  WHERE	id = ser_rec.id;
+
+		moved_objects := moved_objects + 1;
+	END LOOP;
+
+	-- Find serial subscriptions targeting the source record ...
+	FOR ser_sub IN SELECT * FROM serial.subscription WHERE record_entry = source_record LOOP
+		-- ... and move them to the target record
+		UPDATE	serial.subscription
+		  SET	record_entry = target_record
+		  WHERE	id = ser_sub.id;
+
+		moved_objects := moved_objects + 1;
+	END LOOP;
+
+	-- Find booking resource types targeting the source record ...
+	FOR booking IN SELECT * FROM booking.resource_type WHERE record = source_record LOOP
+		-- ... and move them to the target record
+		UPDATE	booking.resource_type
+		  SET	record = target_record
+		  WHERE	id = booking.id;
+
+		moved_objects := moved_objects + 1;
+	END LOOP;
+
+	-- Find acq lineitems targeting the source record ...
+	FOR acq_lineitem IN SELECT * FROM acq.lineitem WHERE eg_bib_id = source_record LOOP
+		-- ... and move them to the target record
+		UPDATE	acq.lineitem
+		  SET	eg_bib_id = target_record
+		  WHERE	id = acq_lineitem.id;
+
+		moved_objects := moved_objects + 1;
+	END LOOP;
+
+	-- Find acq user purchase requests targeting the source record ...
+	FOR acq_request IN SELECT * FROM acq.user_request WHERE eg_bib = source_record LOOP
+		-- ... and move them to the target record
+		UPDATE	acq.user_request
+		  SET	eg_bib = target_record
+		  WHERE	id = acq_request.id;
+
+		moved_objects := moved_objects + 1;
+	END LOOP;
+
+	-- Find parts attached to the source ...
+	FOR source_part IN SELECT * FROM biblio.monograph_part WHERE record = source_record LOOP
+
+		SELECT	INTO target_part *
+		  FROM	biblio.monograph_part
+		  WHERE	label = source_part.label
+			AND record = target_record;
+
+		-- ... and if there's a conflicting one on the target ...
+		IF FOUND THEN
+
+			-- ... move the copy-part maps to that, and ...
+			UPDATE	asset.copy_part_map
+			  SET	part = target_part.id
+			  WHERE	part = source_part.id;
+
+			-- ... move P holds to the move-target part
+			FOR hold IN SELECT * FROM action.hold_request WHERE target = source_part.id AND hold_type = 'P' LOOP
+		
+				UPDATE	action.hold_request
+				  SET	target = target_part.id
+				  WHERE	id = hold.id;
+		
+				moved_objects := moved_objects + 1;
+			END LOOP;
+
+		-- ... if not ...
+		ELSE
+			-- ... just move the part to the target record
+			UPDATE	biblio.monograph_part
+			  SET	record = target_record
+			  WHERE	id = source_part.id;
+		END IF;
+
+		moved_objects := moved_objects + 1;
+	END LOOP;
+
+	-- Find multi_home items attached to the source ...
+	FOR multi_home IN SELECT * FROM biblio.peer_bib_copy_map WHERE peer_record = source_record LOOP
+		-- ... and move them to the target record
+		UPDATE	biblio.peer_bib_copy_map
+		  SET	peer_record = target_record
+		  WHERE	id = multi_home.id;
+
+		moved_objects := moved_objects + 1;
+	END LOOP;
+
+	-- And delete mappings where the item's home bib was merged with the peer bib
+	DELETE FROM biblio.peer_bib_copy_map WHERE peer_record = (
+		SELECT (SELECT record FROM asset.call_number WHERE id = call_number)
+		FROM asset.copy WHERE id = target_copy
+	);
+
+    -- Finally, "delete" the source record
+    DELETE FROM biblio.record_entry WHERE id = source_record;
+
+	-- That's all, folks!
+	RETURN moved_objects;
+END;
+$func$ LANGUAGE plpgsql;
+
+-- from reporter-schema.sql
+
+CREATE OR REPLACE VIEW reporter.simple_record AS
+SELECT	r.id,
+	s.metarecord,
+	r.fingerprint,
+	r.quality,
+	r.tcn_source,
+	r.tcn_value,
+	title.value AS title,
+	uniform_title.value AS uniform_title,
+	author.value AS author,
+	publisher.value AS publisher,
+	SUBSTRING(pubdate.value FROM $$\d+$$) AS pubdate,
+	series_title.value AS series_title,
+	series_statement.value AS series_statement,
+	summary.value AS summary,
+	ARRAY_AGG( DISTINCT REPLACE(SUBSTRING(isbn.value FROM $$^\S+$$), '-', '') ) AS isbn,
+	ARRAY_AGG( DISTINCT REGEXP_REPLACE(issn.value, E'^\\S*(\\d{4})[-\\s](\\d{3,4}x?)', E'\\1 \\2') ) AS issn,
+	ARRAY((SELECT DISTINCT value FROM metabib.full_rec WHERE tag = '650' AND subfield = 'a' AND record = r.id)) AS topic_subject,
+	ARRAY((SELECT DISTINCT value FROM metabib.full_rec WHERE tag = '651' AND subfield = 'a' AND record = r.id)) AS geographic_subject,
+	ARRAY((SELECT DISTINCT value FROM metabib.full_rec WHERE tag = '655' AND subfield = 'a' AND record = r.id)) AS genre,
+	ARRAY((SELECT DISTINCT value FROM metabib.full_rec WHERE tag = '600' AND subfield = 'a' AND record = r.id)) AS name_subject,
+	ARRAY((SELECT DISTINCT value FROM metabib.full_rec WHERE tag = '610' AND subfield = 'a' AND record = r.id)) AS corporate_subject,
+	ARRAY((SELECT value FROM metabib.full_rec WHERE tag = '856' AND subfield IN ('3','y','u') AND record = r.id ORDER BY CASE WHEN subfield IN ('3','y') THEN 0 ELSE 1 END)) AS external_uri
+  FROM	biblio.record_entry r
+	JOIN metabib.metarecord_source_map s ON (s.source = r.id)
+	LEFT JOIN metabib.full_rec uniform_title ON (r.id = uniform_title.record AND uniform_title.tag = '240' AND uniform_title.subfield = 'a')
+	LEFT JOIN metabib.full_rec title ON (r.id = title.record AND title.tag = '245' AND title.subfield = 'a')
+	LEFT JOIN metabib.full_rec author ON (r.id = author.record AND author.tag = '100' AND author.subfield = 'a')
+	LEFT JOIN metabib.full_rec publisher ON (r.id = publisher.record AND publisher.tag = '260' AND publisher.subfield = 'b')
+	LEFT JOIN metabib.full_rec pubdate ON (r.id = pubdate.record AND pubdate.tag = '260' 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')
+	LEFT JOIN metabib.full_rec series_title ON (r.id = series_title.record AND series_title.tag IN ('830','440') AND series_title.subfield = 'a')
+	LEFT JOIN metabib.full_rec series_statement ON (r.id = series_statement.record AND series_statement.tag = '490' AND series_statement.subfield = 'a')
+	LEFT JOIN metabib.full_rec summary ON (r.id = summary.record AND summary.tag = '520' AND summary.subfield = 'a')
+  GROUP BY 1,2,3,4,5,6,7,8,9,10,11,12,13,14;
+
+CREATE OR REPLACE VIEW reporter.old_super_simple_record AS
+SELECT  r.id,
+    r.fingerprint,
+    r.quality,
+    r.tcn_source,
+    r.tcn_value,
+    FIRST(title.value) 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}'
+        THEN NULL
+        ELSE ARRAY_AGG( DISTINCT REPLACE(SUBSTRING(isbn.value FROM $$^\S+$$), '-', '') )
+    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}'
+        THEN NULL
+        ELSE ARRAY_AGG( DISTINCT REGEXP_REPLACE(issn.value, E'^\\S*(\\d{4})[-\\s](\\d{3,4}x?)', E'\\1 \\2') )
+    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 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;
+
+
+
+SELECT evergreen.upgrade_deps_block_check('0856', :eg_version);
+
+CREATE OR REPLACE FUNCTION metabib.staged_browse(
+    query                   TEXT,
+    fields                  INT[],
+    context_org             INT,
+    context_locations       INT[],
+    staff                   BOOL,
+    browse_superpage_size   INT,
+    count_up_from_zero      BOOL,   -- if false, count down from -1
+    result_limit            INT,
+    next_pivot_pos          INT
+) RETURNS SETOF metabib.flat_browse_entry_appearance AS $p$
+DECLARE
+    curs                    REFCURSOR;
+    rec                     RECORD;
+    qpfts_query             TEXT;
+    aqpfts_query            TEXT;
+    afields                 INT[];
+    bfields                 INT[];
+    result_row              metabib.flat_browse_entry_appearance%ROWTYPE;
+    results_skipped         INT := 0;
+    row_counter             INT := 0;
+    row_number              INT;
+    slice_start             INT;
+    slice_end               INT;
+    full_end                INT;
+    all_records             BIGINT[];
+    all_brecords             BIGINT[];
+    all_arecords            BIGINT[];
+    superpage_of_records    BIGINT[];
+    superpage_size          INT;
+BEGIN
+    IF count_up_from_zero THEN
+        row_number := 0;
+    ELSE
+        row_number := -1;
+    END IF;
+
+    OPEN curs FOR EXECUTE query;
+
+    LOOP
+        FETCH curs INTO rec;
+        IF NOT FOUND THEN
+            IF result_row.pivot_point IS NOT NULL THEN
+                RETURN NEXT result_row;
+            END IF;
+            RETURN;
+        END IF;
+
+
+        -- Gather aggregate data based on the MBE row we're looking at now, authority axis
+        SELECT INTO all_arecords, result_row.sees, afields
+                ARRAY_AGG(DISTINCT abl.bib), -- bibs to check for visibility
+                STRING_AGG(DISTINCT aal.source::TEXT, $$,$$), -- authority record ids
+                ARRAY_AGG(DISTINCT map.metabib_field) -- authority-tag-linked CMF rows
+
+          FROM  metabib.browse_entry_simple_heading_map mbeshm
+                JOIN authority.simple_heading ash ON ( mbeshm.simple_heading = ash.id )
+                JOIN authority.authority_linking aal ON ( ash.record = aal.source )
+                JOIN authority.bib_linking abl ON ( aal.target = abl.authority )
+                JOIN authority.control_set_auth_field_metabib_field_map_refs map ON (
+                    ash.atag = map.authority_field
+                    AND map.metabib_field = ANY(fields)
+                )
+          WHERE mbeshm.entry = rec.id;
+
+
+        -- Gather aggregate data based on the MBE row we're looking at now, bib axis
+        SELECT INTO all_brecords, result_row.authorities, bfields
+                ARRAY_AGG(DISTINCT source),
+                STRING_AGG(DISTINCT authority::TEXT, $$,$$),
+                ARRAY_AGG(DISTINCT def)
+          FROM  metabib.browse_entry_def_map
+          WHERE entry = rec.id
+                AND def = ANY(fields);
+
+        SELECT INTO result_row.fields STRING_AGG(DISTINCT x::TEXT, $$,$$) FROM UNNEST(afields || bfields) x;
+
+        result_row.sources := 0;
+        result_row.asources := 0;
+
+        -- Bib-linked vis checking
+        IF ARRAY_UPPER(all_brecords,1) IS NOT NULL THEN
+
+            full_end := ARRAY_LENGTH(all_brecords, 1);
+            superpage_size := COALESCE(browse_superpage_size, full_end);
+            slice_start := 1;
+            slice_end := superpage_size;
+
+            WHILE result_row.sources = 0 AND slice_start <= full_end LOOP
+                superpage_of_records := all_brecords[slice_start:slice_end];
+                qpfts_query :=
+                    'SELECT NULL::BIGINT AS id, ARRAY[r] AS records, ' ||
+                    '1::INT AS rel FROM (SELECT UNNEST(' ||
+                    quote_literal(superpage_of_records) || '::BIGINT[]) AS r) rr';
+
+                -- We use search.query_parser_fts() for visibility testing.
+                -- We're calling it once per browse-superpage worth of records
+                -- out of the set of records related to a given mbe, until we've
+                -- either exhausted that set of records or found at least 1
+                -- visible record.
+
+                SELECT INTO result_row.sources visible
+                    FROM search.query_parser_fts(
+                        context_org, NULL, qpfts_query, NULL,
+                        context_locations, 0, NULL, NULL, FALSE, staff, FALSE
+                    ) qpfts
+                    WHERE qpfts.rel IS NULL;
+
+                slice_start := slice_start + superpage_size;
+                slice_end := slice_end + superpage_size;
+            END LOOP;
+
+            -- Accurate?  Well, probably.
+            result_row.accurate := browse_superpage_size IS NULL OR
+                browse_superpage_size >= full_end;
+
+        END IF;
+
+        -- Authority-linked vis checking
+        IF ARRAY_UPPER(all_arecords,1) IS NOT NULL THEN
+
+            full_end := ARRAY_LENGTH(all_arecords, 1);
+            superpage_size := COALESCE(browse_superpage_size, full_end);
+            slice_start := 1;
+            slice_end := superpage_size;
+
+            WHILE result_row.asources = 0 AND slice_start <= full_end LOOP
+                superpage_of_records := all_arecords[slice_start:slice_end];
+                qpfts_query :=
+                    'SELECT NULL::BIGINT AS id, ARRAY[r] AS records, ' ||
+                    '1::INT AS rel FROM (SELECT UNNEST(' ||
+                    quote_literal(superpage_of_records) || '::BIGINT[]) AS r) rr';
+
+                -- We use search.query_parser_fts() for visibility testing.
+                -- We're calling it once per browse-superpage worth of records
+                -- out of the set of records related to a given mbe, via
+                -- authority until we've either exhausted that set of records
+                -- or found at least 1 visible record.
+
+                SELECT INTO result_row.asources visible
+                    FROM search.query_parser_fts(
+                        context_org, NULL, qpfts_query, NULL,
+                        context_locations, 0, NULL, NULL, FALSE, staff, FALSE
+                    ) qpfts
+                    WHERE qpfts.rel IS NULL;
+
+                slice_start := slice_start + superpage_size;
+                slice_end := slice_end + superpage_size;
+            END LOOP;
+
+
+            -- Accurate?  Well, probably.
+            result_row.aaccurate := browse_superpage_size IS NULL OR
+                browse_superpage_size >= full_end;
+
+        END IF;
+
+        IF result_row.sources > 0 OR result_row.asources > 0 THEN
+
+            -- The function that calls this function needs row_number in order
+            -- to correctly order results from two different runs of this
+            -- functions.
+            result_row.row_number := row_number;
+
+            -- Now, if row_counter is still less than limit, return a row.  If
+            -- not, but it is less than next_pivot_pos, continue on without
+            -- returning actual result rows until we find
+            -- that next pivot, and return it.
+
+            IF row_counter < result_limit THEN
+                result_row.browse_entry := rec.id;
+                result_row.value := rec.value;
+
+                RETURN NEXT result_row;
+            ELSE
+                result_row.browse_entry := NULL;
+                result_row.authorities := NULL;
+                result_row.fields := NULL;
+                result_row.value := NULL;
+                result_row.sources := NULL;
+                result_row.sees := NULL;
+                result_row.accurate := NULL;
+                result_row.aaccurate := NULL;
+                result_row.pivot_point := rec.id;
+
+                IF row_counter >= next_pivot_pos THEN
+                    RETURN NEXT result_row;
+                    RETURN;
+                END IF;
+            END IF;
+
+            IF count_up_from_zero THEN
+                row_number := row_number + 1;
+            ELSE
+                row_number := row_number - 1;
+            END IF;
+
+            -- row_counter is different from row_number.
+            -- It simply counts up from zero so that we know when
+            -- we've reached our limit.
+            row_counter := row_counter + 1;
+        END IF;
+    END LOOP;
+END;
+$p$ LANGUAGE PLPGSQL;
+
+
+/*
+ * Copyright (C) 2014  Equinox Software, Inc.
+ * Mike Rylander <miker at esilibrary.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+
+
+SELECT evergreen.upgrade_deps_block_check('0857', :eg_version);
+
+INSERT INTO config.global_flag (name, enabled, label)
+VALUES (
+    'opac.located_uri.act_as_copy',
+    FALSE,
+    oils_i18n_gettext(
+        'opac.located_uri.act_as_copy',
+        'When enabled, Located URIs will provide visiblity behavior identical to copies.',
+        'cgf',
+        'label'
+    )
+);
+
+CREATE OR REPLACE FUNCTION search.query_parser_fts (
+
+    param_search_ou INT,
+    param_depth     INT,
+    param_query     TEXT,
+    param_statuses  INT[],
+    param_locations INT[],
+    param_offset    INT,
+    param_check     INT,
+    param_limit     INT,
+    metarecord      BOOL,
+    staff           BOOL,
+    deleted_search  BOOL,
+    param_pref_ou   INT DEFAULT NULL
+) RETURNS SETOF search.search_result AS $func$
+DECLARE
+
+    current_res         search.search_result%ROWTYPE;
+    search_org_list     INT[];
+    luri_org_list       INT[];
+    tmp_int_list        INT[];
+
+    check_limit         INT;
+    core_limit          INT;
+    core_offset         INT;
+    tmp_int             INT;
+
+    core_result         RECORD;
+    core_cursor         REFCURSOR;
+    core_rel_query      TEXT;
+
+    total_count         INT := 0;
+    check_count         INT := 0;
+    deleted_count       INT := 0;
+    visible_count       INT := 0;
+    excluded_count      INT := 0;
+
+    luri_as_copy        BOOL;
+BEGIN
+
+    check_limit := COALESCE( param_check, 1000 );
+    core_limit  := COALESCE( param_limit, 25000 );
+    core_offset := COALESCE( param_offset, 0 );
+
+    SELECT COALESCE( enabled, FALSE ) INTO luri_as_copy FROM config.global_flag WHERE name = 'opac.located_uri.act_as_copy';
+
+    -- core_skip_chk := COALESCE( param_skip_chk, 1 );
+
+    IF param_search_ou > 0 THEN
+        IF param_depth IS NOT NULL THEN
+            SELECT ARRAY_AGG(distinct id) INTO search_org_list FROM actor.org_unit_descendants( param_search_ou, param_depth );
+        ELSE
+            SELECT ARRAY_AGG(distinct id) INTO search_org_list FROM actor.org_unit_descendants( param_search_ou );
+        END IF;
+
+        IF luri_as_copy THEN
+            SELECT ARRAY_AGG(distinct id) INTO luri_org_list FROM actor.org_unit_full_path( param_search_ou );
+        ELSE
+            SELECT ARRAY_AGG(distinct id) INTO luri_org_list FROM actor.org_unit_ancestors( param_search_ou );
+        END IF;
+
+    ELSIF param_search_ou < 0 THEN
+        SELECT ARRAY_AGG(distinct org_unit) INTO search_org_list FROM actor.org_lasso_map WHERE lasso = -param_search_ou;
+
+        FOR tmp_int IN SELECT * FROM UNNEST(search_org_list) LOOP
+
+            IF luri_as_copy THEN
+                SELECT ARRAY_AGG(distinct id) INTO tmp_int_list FROM actor.org_unit_full_path( tmp_int );
+            ELSE
+                SELECT ARRAY_AGG(distinct id) INTO tmp_int_list FROM actor.org_unit_ancestors( tmp_int );
+            END IF;
+
+            luri_org_list := luri_org_list || tmp_int_list;
+        END LOOP;
+
+        SELECT ARRAY_AGG(DISTINCT x.id) INTO luri_org_list FROM UNNEST(luri_org_list) x(id);
+
+    ELSIF param_search_ou = 0 THEN
+        -- reserved for user lassos (ou_buckets/type='lasso') with ID passed in depth ... hack? sure.
+    END IF;
+
+    IF param_pref_ou IS NOT NULL THEN
+            IF luri_as_copy THEN
+                SELECT ARRAY_AGG(distinct id) INTO tmp_int_list FROM actor.org_unit_full_path( param_pref_ou );
+            ELSE
+                SELECT ARRAY_AGG(distinct id) INTO tmp_int_list FROM actor.org_unit_ancestors( param_pref_ou );
+            END IF;
+
+        luri_org_list := luri_org_list || tmp_int_list;
+    END IF;
+
+    OPEN core_cursor FOR EXECUTE param_query;
+
+    LOOP
+
+        FETCH core_cursor INTO core_result;
+        EXIT WHEN NOT FOUND;
+        EXIT WHEN total_count >= core_limit;
+
+        total_count := total_count + 1;
+
+        CONTINUE WHEN total_count NOT BETWEEN  core_offset + 1 AND check_limit + core_offset;
+
+        check_count := check_count + 1;
+
+        IF NOT deleted_search THEN
+
+            PERFORM 1 FROM biblio.record_entry b WHERE NOT b.deleted AND b.id IN ( SELECT * FROM unnest( core_result.records ) );
+            IF NOT FOUND THEN
+                -- RAISE NOTICE ' % were all deleted ... ', core_result.records;
+                deleted_count := deleted_count + 1;
+                CONTINUE;
+            END IF;
+
+            PERFORM 1
+              FROM  biblio.record_entry b
+                    JOIN config.bib_source s ON (b.source = s.id)
+              WHERE s.transcendant
+                    AND b.id IN ( SELECT * FROM unnest( core_result.records ) );
+
+            IF FOUND THEN
+                -- RAISE NOTICE ' % were all transcendant ... ', core_result.records;
+                visible_count := visible_count + 1;
+
+                current_res.id = core_result.id;
+                current_res.rel = core_result.rel;
+
+                tmp_int := 1;
+                IF metarecord THEN
+                    SELECT COUNT(DISTINCT s.source) INTO tmp_int FROM metabib.metarecord_source_map s WHERE s.metarecord = core_result.id;
+                END IF;
+
+                IF tmp_int = 1 THEN
+                    current_res.record = core_result.records[1];
+                ELSE
+                    current_res.record = NULL;
+                END IF;
+
+                RETURN NEXT current_res;
+
+                CONTINUE;
+            END IF;
+
+            PERFORM 1
+              FROM  asset.call_number cn
+                    JOIN asset.uri_call_number_map map ON (map.call_number = cn.id)
+                    JOIN asset.uri uri ON (map.uri = uri.id)
+              WHERE NOT cn.deleted
+                    AND cn.label = '##URI##'
+                    AND uri.active
+                    AND ( param_locations IS NULL OR array_upper(param_locations, 1) IS NULL )
+                    AND cn.record IN ( SELECT * FROM unnest( core_result.records ) )
+                    AND cn.owning_lib IN ( SELECT * FROM unnest( luri_org_list ) )
+              LIMIT 1;
+
+            IF FOUND THEN
+                -- RAISE NOTICE ' % have at least one URI ... ', core_result.records;
+                visible_count := visible_count + 1;
+
+                current_res.id = core_result.id;
+                current_res.rel = core_result.rel;
+
+                tmp_int := 1;
+                IF metarecord THEN
+                    SELECT COUNT(DISTINCT s.source) INTO tmp_int FROM metabib.metarecord_source_map s WHERE s.metarecord = core_result.id;
+                END IF;
+
+                IF tmp_int = 1 THEN
+                    current_res.record = core_result.records[1];
+                ELSE
+                    current_res.record = NULL;
+                END IF;
+
+                RETURN NEXT current_res;
+
+                CONTINUE;
+            END IF;
+
+            IF param_statuses IS NOT NULL AND array_upper(param_statuses, 1) > 0 THEN
+
+                PERFORM 1
+                  FROM  asset.call_number cn
+                        JOIN asset.copy cp ON (cp.call_number = cn.id)
+                  WHERE NOT cn.deleted
+                        AND NOT cp.deleted
+                        AND cp.status IN ( SELECT * FROM unnest( param_statuses ) )
+                        AND cn.record IN ( SELECT * FROM unnest( core_result.records ) )
+                        AND cp.circ_lib IN ( SELECT * FROM unnest( search_org_list ) )
+                  LIMIT 1;
+
+                IF NOT FOUND THEN
+                    PERFORM 1
+                      FROM  biblio.peer_bib_copy_map pr
+                            JOIN asset.copy cp ON (cp.id = pr.target_copy)
+                      WHERE NOT cp.deleted
+                            AND cp.status IN ( SELECT * FROM unnest( param_statuses ) )
+                            AND pr.peer_record IN ( SELECT * FROM unnest( core_result.records ) )
+                            AND cp.circ_lib IN ( SELECT * FROM unnest( search_org_list ) )
+                      LIMIT 1;
+
+                    IF NOT FOUND THEN
+                    -- RAISE NOTICE ' % and multi-home linked records were all status-excluded ... ', core_result.records;
+                        excluded_count := excluded_count + 1;
+                        CONTINUE;
+                    END IF;
+                END IF;
+
+            END IF;
+
+            IF param_locations IS NOT NULL AND array_upper(param_locations, 1) > 0 THEN
+
+                PERFORM 1
+                  FROM  asset.call_number cn
+                        JOIN asset.copy cp ON (cp.call_number = cn.id)
+                  WHERE NOT cn.deleted
+                        AND NOT cp.deleted
+                        AND cp.location IN ( SELECT * FROM unnest( param_locations ) )
+                        AND cn.record IN ( SELECT * FROM unnest( core_result.records ) )
+                        AND cp.circ_lib IN ( SELECT * FROM unnest( search_org_list ) )
+                  LIMIT 1;
+
+                IF NOT FOUND THEN
+                    PERFORM 1
+                      FROM  biblio.peer_bib_copy_map pr
+                            JOIN asset.copy cp ON (cp.id = pr.target_copy)
+                      WHERE NOT cp.deleted
+                            AND cp.location IN ( SELECT * FROM unnest( param_locations ) )
+                            AND pr.peer_record IN ( SELECT * FROM unnest( core_result.records ) )
+                            AND cp.circ_lib IN ( SELECT * FROM unnest( search_org_list ) )
+                      LIMIT 1;
+
+                    IF NOT FOUND THEN
+                        -- RAISE NOTICE ' % and multi-home linked records were all copy_location-excluded ... ', core_result.records;
+                        excluded_count := excluded_count + 1;
+                        CONTINUE;
+                    END IF;
+                END IF;
+
+            END IF;
+
+            IF staff IS NULL OR NOT staff THEN
+
+                PERFORM 1
+                  FROM  asset.opac_visible_copies
+                  WHERE circ_lib IN ( SELECT * FROM unnest( search_org_list ) )
+                        AND record IN ( SELECT * FROM unnest( core_result.records ) )
+                  LIMIT 1;
+
+                IF NOT FOUND THEN
+                    PERFORM 1
+                      FROM  biblio.peer_bib_copy_map pr
+                            JOIN asset.opac_visible_copies cp ON (cp.copy_id = pr.target_copy)
+                      WHERE cp.circ_lib IN ( SELECT * FROM unnest( search_org_list ) )
+                            AND pr.peer_record IN ( SELECT * FROM unnest( core_result.records ) )
+                      LIMIT 1;
+
+                    IF NOT FOUND THEN
+
+                        -- RAISE NOTICE ' % and multi-home linked records were all visibility-excluded ... ', core_result.records;
+                        excluded_count := excluded_count + 1;
+                        CONTINUE;
+                    END IF;
+                END IF;
+
+            ELSE
+
+                PERFORM 1
+                  FROM  asset.call_number cn
+                        JOIN asset.copy cp ON (cp.call_number = cn.id)
+                  WHERE NOT cn.deleted
+                        AND NOT cp.deleted
+                        AND cp.circ_lib IN ( SELECT * FROM unnest( search_org_list ) )
+                        AND cn.record IN ( SELECT * FROM unnest( core_result.records ) )
+                  LIMIT 1;
+
+                IF NOT FOUND THEN
+
+                    PERFORM 1
+                      FROM  biblio.peer_bib_copy_map pr
+                            JOIN asset.copy cp ON (cp.id = pr.target_copy)
+                      WHERE NOT cp.deleted
+                            AND cp.circ_lib IN ( SELECT * FROM unnest( search_org_list ) )
+                            AND pr.peer_record IN ( SELECT * FROM unnest( core_result.records ) )
+                      LIMIT 1;
+
+                    IF NOT FOUND THEN
+
+                        PERFORM 1
+                          FROM  asset.call_number cn
+                                JOIN asset.copy cp ON (cp.call_number = cn.id)
+                          WHERE cn.record IN ( SELECT * FROM unnest( core_result.records ) )
+                                AND NOT cp.deleted
+                          LIMIT 1;
+
+                        IF FOUND THEN
+                            -- RAISE NOTICE ' % and multi-home linked records were all visibility-excluded ... ', core_result.records;
+                            excluded_count := excluded_count + 1;
+                            CONTINUE;
+                        END IF;
+                    END IF;
+
+                END IF;
+
+            END IF;
+
+        END IF;
+
+        visible_count := visible_count + 1;
+
+        current_res.id = core_result.id;
+        current_res.rel = core_result.rel;
+
+        tmp_int := 1;
+        IF metarecord THEN
+            SELECT COUNT(DISTINCT s.source) INTO tmp_int FROM metabib.metarecord_source_map s WHERE s.metarecord = core_result.id;
+        END IF;
+
+        IF tmp_int = 1 THEN
+            current_res.record = core_result.records[1];
+        ELSE
+            current_res.record = NULL;
+        END IF;
+
+        RETURN NEXT current_res;
+
+        IF visible_count % 1000 = 0 THEN
+            -- RAISE NOTICE ' % visible so far ... ', visible_count;
+        END IF;
+
+    END LOOP;
+
+    current_res.id = NULL;
+    current_res.rel = NULL;
+    current_res.record = NULL;
+    current_res.total = total_count;
+    current_res.checked = check_count;
+    current_res.deleted = deleted_count;
+    current_res.visible = visible_count;
+    current_res.excluded = excluded_count;
+
+    CLOSE core_cursor;
+
+    RETURN NEXT current_res;
+
+END;
+$func$ LANGUAGE PLPGSQL;
+
+CREATE OR REPLACE FUNCTION unapi.holdings_xml (
+    bid BIGINT,
+    ouid INT,
+    org TEXT,
+    depth INT DEFAULT NULL,
+    includes TEXT[] DEFAULT NULL::TEXT[],
+    slimit HSTORE DEFAULT NULL,
+    soffset HSTORE DEFAULT NULL,
+    include_xmlns BOOL DEFAULT TRUE,
+    pref_lib INT DEFAULT NULL
+)
+RETURNS XML AS $F$
+     SELECT  XMLELEMENT(
+                 name holdings,
+                 XMLATTRIBUTES(
+                    CASE WHEN $8 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
+                    CASE WHEN ('bre' = ANY ($5)) THEN 'tag:open-ils.org:U2 at bre/' || $1 || '/' || $3 ELSE NULL END AS id,
+                    (SELECT record_has_holdable_copy FROM asset.record_has_holdable_copy($1)) AS has_holdable
+                 ),
+                 XMLELEMENT(
+                     name counts,
+                     (SELECT  XMLAGG(XMLELEMENT::XML) FROM (
+                         SELECT  XMLELEMENT(
+                                     name count,
+                                     XMLATTRIBUTES('public' as type, depth, org_unit, coalesce(transcendant,0) as transcendant, available, visible as count, unshadow)
+                                 )::text
+                           FROM  asset.opac_ou_record_copy_count($2,  $1)
+                                     UNION
+                         SELECT  XMLELEMENT(
+                                     name count,
+                                     XMLATTRIBUTES('staff' as type, depth, org_unit, coalesce(transcendant,0) as transcendant, available, visible as count, unshadow)
+                                 )::text
+                           FROM  asset.staff_ou_record_copy_count($2, $1)
+                                     UNION
+                         SELECT  XMLELEMENT(
+                                     name count,
+                                     XMLATTRIBUTES('pref_lib' as type, depth, org_unit, coalesce(transcendant,0) as transcendant, available, visible as count, unshadow)
+                                 )::text
+                           FROM  asset.opac_ou_record_copy_count($9,  $1)
+                                     ORDER BY 1
+                     )x)
+                 ),
+                 CASE
+                     WHEN ('bmp' = ANY ($5)) THEN
+                        XMLELEMENT(
+                            name monograph_parts,
+                            (SELECT XMLAGG(bmp) FROM (
+                                SELECT  unapi.bmp( id, 'xml', 'monograph_part', evergreen.array_remove_item_by_value( evergreen.array_remove_item_by_value($5,'bre'), 'holdings_xml'), $3, $4, $6, $7, FALSE)
+                                  FROM  biblio.monograph_part
+                                  WHERE record = $1
+                            )x)
+                        )
+                     ELSE NULL
+                 END,
+                 XMLELEMENT(
+                     name volumes,
+                     (SELECT XMLAGG(acn ORDER BY rank, name, label_sortkey) FROM (
+                        -- Physical copies
+                        SELECT  unapi.acn(y.id,'xml','volume',evergreen.array_remove_item_by_value( evergreen.array_remove_item_by_value($5,'holdings_xml'),'bre'), $3, $4, $6, $7, FALSE), y.rank, name, label_sortkey
+                        FROM evergreen.ranked_volumes($1, $2, $4, $6, $7, $9, $5) AS y
+                        UNION ALL
+                        -- Located URIs
+                        SELECT unapi.acn(uris.id,'xml','volume',evergreen.array_remove_item_by_value( evergreen.array_remove_item_by_value($5,'holdings_xml'),'bre'), $3, $4, $6, $7, FALSE), uris.rank, name, label_sortkey
+                        FROM evergreen.located_uris($1, $2, $9) AS uris
+                     )x)
+                 ),
+                 CASE WHEN ('ssub' = ANY ($5)) THEN
+                     XMLELEMENT(
+                         name subscriptions,
+                         (SELECT XMLAGG(ssub) FROM (
+                            SELECT  unapi.ssub(id,'xml','subscription','{}'::TEXT[], $3, $4, $6, $7, FALSE)
+                              FROM  serial.subscription
+                              WHERE record_entry = $1
+                        )x)
+                     )
+                 ELSE NULL END,
+                 CASE WHEN ('acp' = ANY ($5)) THEN
+                     XMLELEMENT(
+                         name foreign_copies,
+                         (SELECT XMLAGG(acp) FROM (
+                            SELECT  unapi.acp(p.target_copy,'xml','copy',evergreen.array_remove_item_by_value($5,'acp'), $3, $4, $6, $7, FALSE)
+                              FROM  biblio.peer_bib_copy_map p
+                                    JOIN asset.copy c ON (p.target_copy = c.id)
+                              WHERE NOT c.deleted AND p.peer_record = $1
+                            LIMIT ($6 -> 'acp')::INT
+                            OFFSET ($7 -> 'acp')::INT
+                        )x)
+                     )
+                 ELSE NULL END
+             );
+$F$ LANGUAGE SQL STABLE;
+
+
+
+SELECT evergreen.upgrade_deps_block_check('0858', :eg_version);
+
+-- Fix faulty seed data. Otherwise for ptype 'f' we have subfield 'e'
+-- overlapping subfield 'd'
+UPDATE config.marc21_physical_characteristic_subfield_map
+    SET start_pos = 5
+    WHERE ptype_key = 'f' AND subfield = 'e';
+
+-- Evergreen DB patch 0859.data.staff-initials-settings.sql
+--
+-- More granular configuration settings for requiring use of staff initials
+--
+
+-- check whether patch can be applied
+SELECT evergreen.upgrade_deps_block_check('0859', :eg_version);
+
+-- add new granular settings for requiring use of staff initials
+INSERT INTO config.org_unit_setting_type
+    (name, grp, label, description, datatype)
+    VALUES (
+        'ui.staff.require_initials.patron_standing_penalty',
+        'gui',
+        oils_i18n_gettext(
+            'ui.staff.require_initials.patron_standing_penalty',
+            'Require staff initials for entry/edit of patron standing penalties and messages.',
+            'coust',
+            'label'
+        ),
+        oils_i18n_gettext(
+            'ui.staff.require_initials.patron_standing_penalty',
+            'Appends staff initials and edit date into patron standing penalties and messages.',
+            'coust',
+            'description'
+        ),
+        'bool'
+    ), (
+        'ui.staff.require_initials.patron_info_notes',
+        'gui',
+        oils_i18n_gettext(
+            'ui.staff.require_initials.patron_info_notes',
+            'Require staff initials for entry/edit of patron notes.',
+            'coust',
+            'label'
+        ),
+        oils_i18n_gettext(
+            'ui.staff.require_initials.patron_info_notes',
+            'Appends staff initials and edit date into patron note content.',
+            'coust',
+            'description'
+        ),
+        'bool'
+    ), (
+        'ui.staff.require_initials.copy_notes',
+        'gui',
+        oils_i18n_gettext(
+            'ui.staff.require_initials.copy_notes',
+            'Require staff initials for entry/edit of copy notes.',
+            'coust',
+            'label'
+        ),
+        oils_i18n_gettext(
+            'ui.staff.require_initials.copy_notes',
+            'Appends staff initials and edit date into copy note content..',
+            'coust',
+            'description'
+        ),
+        'bool'
+    );
+
+-- Update any existing setting so that the original set value is now passed to
+-- one of the newer settings.
+
+UPDATE actor.org_unit_setting
+SET name = 'ui.staff.require_initials.patron_standing_penalty'
+WHERE name = 'ui.staff.require_initials';
+
+-- Add similar values for new settings as old ones to preserve existing configured
+-- functionality.
+
+INSERT INTO actor.org_unit_setting (org_unit, name, value)
+SELECT org_unit, 'ui.staff.require_initials.patron_info_notes', value
+FROM actor.org_unit_setting
+WHERE name = 'ui.staff.require_initials.patron_standing_penalty';
+
+INSERT INTO actor.org_unit_setting (org_unit, name, value)
+SELECT org_unit, 'ui.staff.require_initials.copy_notes', value
+FROM actor.org_unit_setting
+WHERE name = 'ui.staff.require_initials.patron_standing_penalty';
+
+-- Update setting logs so that the original setting name's history is now transferred
+-- over to one of the newer settings.
+
+UPDATE config.org_unit_setting_type_log
+SET field_name = 'ui.staff.require_initials.patron_standing_penalty'
+WHERE field_name = 'ui.staff.require_initials';
+
+-- Remove the old setting entirely
+
+DELETE FROM config.org_unit_setting_type WHERE name = 'ui.staff.require_initials';
+
+
+-- oh, the irony
+SELECT evergreen.upgrade_deps_block_check('0860', :eg_version);
+
+CREATE OR REPLACE FUNCTION evergreen.array_overlap_check (/* field */) RETURNS TRIGGER AS $$
+DECLARE
+    fld     TEXT;
+    cnt     INT;
+BEGIN
+    fld := TG_ARGV[0];
+    EXECUTE 'SELECT COUNT(*) FROM '|| TG_TABLE_SCHEMA ||'.'|| TG_TABLE_NAME ||' WHERE '|| fld ||' && ($1).'|| fld INTO cnt USING NEW;
+    IF cnt > 0 THEN
+        RAISE EXCEPTION 'Cannot insert duplicate array into field % of table %', fld, TG_TABLE_SCHEMA ||'.'|| TG_TABLE_NAME;
+    END IF;
+    RETURN NEW;
+END;
+$$ LANGUAGE PLPGSQL;
+
+
+CREATE OR REPLACE FUNCTION evergreen.upgrade_list_applied_deprecates ( my_db_patch TEXT ) RETURNS SETOF evergreen.patch AS $$
+    SELECT  DISTINCT l.version
+      FROM  config.upgrade_log l
+            JOIN config.db_patch_dependencies d ON (l.version = ANY(d.deprecates))
+      WHERE d.db_patch = $1
+$$ LANGUAGE SQL;
+
+-- List applied db patches that are superseded by (and block the application of) my_db_patch
+CREATE OR REPLACE FUNCTION evergreen.upgrade_list_applied_supersedes ( my_db_patch TEXT ) RETURNS SETOF evergreen.patch AS $$
+    SELECT  DISTINCT l.version
+      FROM  config.upgrade_log l
+            JOIN config.db_patch_dependencies d ON (l.version = ANY(d.supersedes))
+      WHERE d.db_patch = $1
+$$ LANGUAGE SQL;
+
+
+CREATE OR REPLACE FUNCTION evergreen.upgrade_deps_block_check ( my_db_patch TEXT, my_applied_to TEXT ) RETURNS BOOL AS $$
+DECLARE 
+    deprecates TEXT;
+    supersedes TEXT;
+BEGIN
+    IF NOT evergreen.upgrade_verify_no_dep_conflicts( my_db_patch ) THEN
+        SELECT  STRING_AGG(patch, ', ') INTO deprecates FROM evergreen.upgrade_list_applied_deprecates(my_db_patch);
+        SELECT  STRING_AGG(patch, ', ') INTO supersedes FROM evergreen.upgrade_list_applied_supersedes(my_db_patch);
+        RAISE EXCEPTION '
+Upgrade script % can not be applied:
+  applied deprecated scripts %
+  applied superseded scripts %
+  deprecated by %
+  superseded by %',
+            my_db_patch,
+            (SELECT ARRAY_AGG(patch) FROM evergreen.upgrade_list_applied_deprecates(my_db_patch)),
+            (SELECT ARRAY_AGG(patch) FROM evergreen.upgrade_list_applied_supersedes(my_db_patch)),
+            evergreen.upgrade_list_applied_deprecated(my_db_patch),
+            evergreen.upgrade_list_applied_superseded(my_db_patch);
+    END IF;
+
+    INSERT INTO config.upgrade_log (version, applied_to) VALUES (my_db_patch, my_applied_to);
+    RETURN TRUE;
+END;
+$$ LANGUAGE PLPGSQL;
+
+
+
+SELECT evergreen.upgrade_deps_block_check('0861', :eg_version);
+
+CREATE INDEX authority_record_entry_create_date_idx ON authority.record_entry ( create_date );
+CREATE INDEX authority_record_entry_edit_date_idx ON authority.record_entry ( edit_date );
+
+
+
+SELECT evergreen.upgrade_deps_block_check('0863', :eg_version);
+
+
+-- cheat sheet for enabling Stripe payments:
+--  'credit.payments.allow' must be true, and among other things it drives the
+--      opac to render a payment form at all
+--  NEW 'credit.processor.stripe.enabled' must be true  (kind of redundant but
+--      my fault for setting the precedent with c.p.{authorizenet|paypal|payflowpro}.enabled)
+--  'credit.default.processor' must be 'Stripe'
+--  NEW 'credit.processor.stripe.pubkey' must be set
+--  NEW 'credit.processor.stripe.secretkey' must be set
+
+INSERT into config.org_unit_setting_type
+( name, grp, label, description, datatype, fm_class ) VALUES
+
+    ( 'credit.processor.stripe.enabled', 'credit',
+    oils_i18n_gettext('credit.processor.stripe.enabled',
+        'Enable Stripe payments',
+        'coust', 'label'),
+    oils_i18n_gettext('credit.processor.stripe.enabled',
+        'Enable Stripe payments',
+        'coust', 'description'),
+    'bool', null)
+
+,( 'credit.processor.stripe.pubkey', 'credit',
+    oils_i18n_gettext('credit.processor.stripe.pubkey',
+        'Stripe publishable key',
+        'coust', 'label'),
+    oils_i18n_gettext('credit.processor.stripe.pubkey',
+        'Stripe publishable key',
+        'coust', 'description'),
+    'string', null)
+
+,( 'credit.processor.stripe.secretkey', 'credit',
+    oils_i18n_gettext('credit.processor.stripe.secretkey',
+        'Stripe secret key',
+        'coust', 'label'),
+    oils_i18n_gettext('credit.processor.stripe.secretkey',
+        'Stripe secret key',
+        'coust', 'description'),
+    'string', null)
+;
+
+UPDATE config.org_unit_setting_type
+SET description = 'This might be "AuthorizeNet", "PayPal", "PayflowPro", or "Stripe".'
+WHERE name = 'credit.processor.default' AND description = 'This might be "AuthorizeNet", "PayPal", etc.'; -- don't clobber local edits or i18n
+
+
+SELECT evergreen.upgrade_deps_block_check('0864', :eg_version);
+
+CREATE EXTENSION intarray;
+
+-- while we have this opportunity, and before we start collecting 
+-- CCVM IDs (below) carve out a nice space for stock ccvm values
+UPDATE config.coded_value_map SET id = id + 10000 WHERE id > 556;
+SELECT SETVAL('config.coded_value_map_id_seq'::TEXT, 
+    (SELECT GREATEST(max(id), 10000) FROM config.coded_value_map));
+
+ALTER TABLE config.record_attr_definition ADD COLUMN multi BOOL NOT NULL DEFAULT TRUE, ADD COLUMN composite BOOL NOT NULL DEFAULT FALSE;
+
+UPDATE  config.record_attr_definition
+  SET   multi = FALSE
+  WHERE name IN ('bib_level','control_type','pubdate','cat_form','enc_level','item_type','titlesort','authorsort');
+
+CREATE OR REPLACE FUNCTION vandelay.marc21_physical_characteristics( marc TEXT) RETURNS SETOF biblio.marc21_physical_characteristics AS $func$
+DECLARE
+    rowid   INT := 0;
+    _007    TEXT;
+    ptype   config.marc21_physical_characteristic_type_map%ROWTYPE;
+    psf     config.marc21_physical_characteristic_subfield_map%ROWTYPE;
+    pval    config.marc21_physical_characteristic_value_map%ROWTYPE;
+    retval  biblio.marc21_physical_characteristics%ROWTYPE;
+BEGIN
+
+    FOR _007 IN SELECT oils_xpath_string('//*', value) FROM UNNEST(oils_xpath('//*[@tag="007"]', marc)) x(value) LOOP
+        IF _007 IS NOT NULL AND _007 <> '' THEN
+            SELECT * INTO ptype FROM config.marc21_physical_characteristic_type_map WHERE ptype_key = SUBSTRING( _007, 1, 1 );
+
+            IF ptype.ptype_key IS NOT NULL THEN
+                FOR psf IN SELECT * FROM config.marc21_physical_characteristic_subfield_map WHERE ptype_key = ptype.ptype_key LOOP
+                    SELECT * INTO pval FROM config.marc21_physical_characteristic_value_map WHERE ptype_subfield = psf.id AND value = SUBSTRING( _007, psf.start_pos + 1, psf.length );
+
+                    IF pval.id IS NOT NULL THEN
+                        rowid := rowid + 1;
+                        retval.id := rowid;
+                        retval.ptype := ptype.ptype_key;
+                        retval.subfield := psf.id;
+                        retval.value := pval.id;
+                        RETURN NEXT retval;
+                    END IF;
+
+                END LOOP;
+            END IF;
+        END IF;
+    END LOOP;
+
+    RETURN;
+END;
+$func$ LANGUAGE PLPGSQL;
+
+CREATE OR REPLACE FUNCTION vandelay.marc21_extract_fixed_field_list( marc TEXT, ff TEXT ) RETURNS TEXT[] AS $func$
+DECLARE
+    rtype       TEXT;
+    ff_pos      RECORD;
+    tag_data    RECORD;
+    val         TEXT;
+    collection  TEXT[] := '{}'::TEXT[];
+BEGIN
+    rtype := (vandelay.marc21_record_type( marc )).code;
+    FOR ff_pos IN SELECT * FROM config.marc21_ff_pos_map WHERE fixed_field = ff AND rec_type = rtype ORDER BY tag DESC LOOP
+        IF ff_pos.tag = 'ldr' THEN
+            val := oils_xpath_string('//*[local-name()="leader"]', marc);
+            IF val IS NOT NULL THEN
+                val := SUBSTRING( val, ff_pos.start_pos + 1, ff_pos.length );
+                collection := collection || val;
+            END IF;
+        ELSE
+            FOR tag_data IN SELECT value FROM UNNEST( oils_xpath( '//*[@tag="' || UPPER(ff_pos.tag) || '"]/text()', marc ) ) x(value) LOOP
+                val := SUBSTRING( tag_data.value, ff_pos.start_pos + 1, ff_pos.length );
+                collection := collection || val;
+            END LOOP;
+        END IF;
+        val := REPEAT( ff_pos.default_val, ff_pos.length );
+        collection := collection || val;
+    END LOOP;
+
+    RETURN collection;
+END;
+$func$ LANGUAGE PLPGSQL;
+
+CREATE OR REPLACE FUNCTION biblio.marc21_extract_fixed_field_list( rid BIGINT, ff TEXT ) RETURNS TEXT[] AS $func$
+    SELECT * FROM vandelay.marc21_extract_fixed_field_list( (SELECT marc FROM biblio.record_entry WHERE id = $1), $2 );
+$func$ LANGUAGE SQL;
+
+-- DECREMENTING serial starts at -1
+CREATE SEQUENCE metabib.uncontrolled_record_attr_value_id_seq INCREMENT BY -1;
+
+CREATE TABLE metabib.uncontrolled_record_attr_value (
+    id      BIGINT  PRIMARY KEY DEFAULT nextval('metabib.uncontrolled_record_attr_value_id_seq'),
+    attr    TEXT    NOT NULL REFERENCES config.record_attr_definition (name),
+    value   TEXT    NOT NULL
+);
+CREATE UNIQUE INDEX muv_once_idx ON metabib.uncontrolled_record_attr_value (attr,value);
+
+CREATE TABLE metabib.record_attr_vector_list (
+    source  BIGINT  PRIMARY KEY REFERENCES  biblio.record_entry (id),
+    vlist   INT[]   NOT NULL -- stores id from ccvm AND murav
+);
+CREATE INDEX mrca_vlist_idx ON metabib.record_attr_vector_list USING gin ( vlist gin__int_ops );
+
+CREATE TABLE metabib.record_sorter (
+    id      BIGSERIAL   PRIMARY KEY,
+    source  BIGINT      NOT NULL REFERENCES biblio.record_entry (id) ON DELETE CASCADE,
+    attr    TEXT        NOT NULL REFERENCES config.record_attr_definition (name) ON DELETE CASCADE,
+    value   TEXT        NOT NULL
+);
+CREATE INDEX metabib_sorter_source_idx ON metabib.record_sorter (source); -- we may not need one of this or the next ... stats will tell
+CREATE INDEX metabib_sorter_s_a_idx ON metabib.record_sorter (source, attr);
+CREATE INDEX metabib_sorter_a_v_idx ON metabib.record_sorter (attr, value);
+
+CREATE TEMP TABLE attr_set ON COMMIT DROP AS SELECT  DISTINCT id AS source, (each(attrs)).key,(each(attrs)).value FROM metabib.record_attr;
+DELETE FROM attr_set WHERE BTRIM(value) = '';
+
+-- Grab sort values for the new sorting mechanism
+INSERT INTO metabib.record_sorter (source,attr,value)
+    SELECT  a.source, a.key, a.value
+      FROM  attr_set a
+            JOIN config.record_attr_definition d ON (d.name = a.key AND d.sorter AND a.value IS NOT NULL);
+
+-- Rewrite uncontrolled SVF record attrs as the seeds of an intarray vector
+INSERT INTO metabib.uncontrolled_record_attr_value (attr,value)
+    SELECT  DISTINCT a.key, a.value
+      FROM  attr_set a
+            JOIN config.record_attr_definition d ON (d.name = a.key AND d.filter AND a.value IS NOT NULL)
+            LEFT JOIN config.coded_value_map m ON (m.ctype = a.key)
+      WHERE m.id IS NULL;
+
+-- Now construct the record-specific vector from the SVF data
+INSERT INTO metabib.record_attr_vector_list (source,vlist)
+    SELECT  a.id, ARRAY_AGG(COALESCE(u.id, c.id))
+      FROM  metabib.record_attr a
+            JOIN attr_set ON (a.id = attr_set.source)
+            LEFT JOIN metabib.uncontrolled_record_attr_value u ON (u.attr = attr_set.key AND u.value = attr_set.value)
+            LEFT JOIN config.coded_value_map c ON (c.ctype = attr_set.key AND c.code = attr_set.value)
+      WHERE COALESCE(u.id,c.id) IS NOT NULL
+      GROUP BY 1;
+
+DROP VIEW IF EXISTS reporter.classic_current_circ; 
+DROP VIEW metabib.rec_descriptor;
+DROP TABLE metabib.record_attr;
+
+CREATE TYPE metabib.record_attr_type AS (
+    id      BIGINT,
+    attrs   HSTORE
+);
+
+CREATE TABLE config.composite_attr_entry_definition(
+    coded_value INT  PRIMARY KEY NOT NULL REFERENCES config.coded_value_map (id) ON UPDATE CASCADE ON DELETE CASCADE,
+    definition  TEXT NOT NULL -- JSON
+);
+
+CREATE OR REPLACE VIEW metabib.record_attr_id_map AS
+    SELECT id, attr, value FROM metabib.uncontrolled_record_attr_value
+        UNION
+    SELECT  c.id, c.ctype AS attr, c.code AS value
+      FROM  config.coded_value_map c
+            JOIN config.record_attr_definition d ON (d.name = c.ctype AND NOT d.composite);
+
+CREATE VIEW metabib.composite_attr_id_map AS
+    SELECT  c.id, c.ctype AS attr, c.code AS value
+      FROM  config.coded_value_map c
+            JOIN config.record_attr_definition d ON (d.name = c.ctype AND d.composite);
+
+CREATE OR REPLACE VIEW metabib.full_attr_id_map AS
+    SELECT id, attr, value FROM metabib.record_attr_id_map
+        UNION
+    SELECT id, attr, value FROM metabib.composite_attr_id_map;
+
+
+-- Back-compat view ... we're moving to an INTARRAY world
+CREATE VIEW metabib.record_attr_flat AS
+    SELECT  v.source AS id,
+            m.attr,
+            m.value
+      FROM  metabib.full_attr_id_map m
+            JOIN  metabib.record_attr_vector_list v ON ( m.id = ANY( v.vlist ) );
+
+CREATE VIEW metabib.record_attr AS
+    SELECT id, HSTORE( ARRAY_AGG( attr ), ARRAY_AGG( value ) ) AS attrs FROM metabib.record_attr_flat GROUP BY 1;
+
+CREATE VIEW metabib.rec_descriptor AS
+    SELECT  id,
+            id AS record,
+            (populate_record(NULL::metabib.rec_desc_type, attrs)).*
+      FROM  metabib.record_attr;
+
+CREATE OR REPLACE FUNCTION metabib.compile_composite_attr_cache_init () RETURNS BOOL AS $f$
+    $_SHARED{metabib_compile_composite_attr_cache} = {}
+        if ! exists $_SHARED{metabib_compile_composite_attr_cache};
+    return exists $_SHARED{metabib_compile_composite_attr_cache};
+$f$ LANGUAGE PLPERLU;
+
+CREATE OR REPLACE FUNCTION metabib.compile_composite_attr_cache_disable () RETURNS BOOL AS $f$
+    delete $_SHARED{metabib_compile_composite_attr_cache};
+    return ! exists $_SHARED{metabib_compile_composite_attr_cache};
+$f$ LANGUAGE PLPERLU;
+
+CREATE OR REPLACE FUNCTION metabib.compile_composite_attr_cache_invalidate () RETURNS BOOL AS $f$
+    SELECT metabib.compile_composite_attr_cache_disable() AND metabib.compile_composite_attr_cache_init();
+$f$ LANGUAGE SQL;
+
+CREATE OR REPLACE FUNCTION metabib.composite_attr_def_cache_inval_tgr () RETURNS TRIGGER AS $f$
+BEGIN
+    PERFORM metabib.compile_composite_attr_cache_invalidate();
+    RETURN NULL;
+END;
+$f$ LANGUAGE PLPGSQL;
+
+CREATE TRIGGER ccraed_cache_inval_tgr AFTER INSERT OR UPDATE OR DELETE ON config.composite_attr_entry_definition FOR EACH STATEMENT EXECUTE PROCEDURE metabib.composite_attr_def_cache_inval_tgr();
+    
+CREATE OR REPLACE FUNCTION metabib.compile_composite_attr ( cattr_def TEXT ) RETURNS query_int AS $func$
+
+    use JSON::XS;
+
+    my $json = shift;
+    my $def = decode_json($json);
+
+    die("Composite attribute definition not supplied") unless $def;
+
+    my $_cache = (exists $_SHARED{metabib_compile_composite_attr_cache}) ? 1 : 0;
+
+    return $_SHARED{metabib_compile_composite_attr_cache}{$json}
+        if ($_cache && $_SHARED{metabib_compile_composite_attr_cache}{$json});
+
+    sub recurse {
+        my $d = shift;
+        my $j = '&';
+        my @list;
+
+        if (ref $d eq 'HASH') { # node or AND
+            if (exists $d->{_attr}) { # it is a node
+                my $plan = spi_prepare('SELECT * FROM metabib.full_attr_id_map WHERE attr = $1 AND value = $2', qw/TEXT TEXT/);
+                my $id = spi_exec_prepared(
+                    $plan, {limit => 1}, $d->{_attr}, $d->{_val}
+                )->{rows}[0]{id};
+                spi_freeplan($plan);
+                return $id;
+            } elsif (exists $d->{_not} && scalar(keys(%$d)) == 1) { # it is a NOT
+                return '!' . recurse($$d{_not});
+            } else { # an AND list
+                @list = map { recurse($$d{$_}) } sort keys %$d;
+            }
+        } elsif (ref $d eq 'ARRAY') {
+            $j = '|';
+            @list = map { recurse($_) } @$d;
+        }
+
+        @list = grep { defined && $_ ne '' } @list;
+
+        return '(' . join($j, at list) . ')' if @list;
+        return '';
+    }
+
+    my $val = recurse($def) || undef;
+    $_SHARED{metabib_compile_composite_attr_cache}{$json} = $val if $_cache;
+    return $val;
+
+$func$ IMMUTABLE LANGUAGE plperlu;
+
+CREATE OR REPLACE FUNCTION metabib.compile_composite_attr ( cattr_id INT ) RETURNS query_int AS $func$
+    SELECT metabib.compile_composite_attr(definition) FROM config.composite_attr_entry_definition WHERE coded_value = $1;
+$func$ STRICT IMMUTABLE LANGUAGE SQL;
+
+
+CREATE OR REPLACE FUNCTION public.oils_tsearch2 () RETURNS TRIGGER AS $$
+DECLARE
+    normalizer      RECORD;
+    value           TEXT := '';
+    temp_vector     TEXT := '';
+    ts_rec          RECORD;
+    cur_weight      "char";
+BEGIN
+
+    value := NEW.value;
+    NEW.index_vector = ''::tsvector;
+
+    IF TG_TABLE_NAME::TEXT ~ 'field_entry$' THEN
+        FOR normalizer IN
+            SELECT  n.func AS func,
+                    n.param_count AS param_count,
+                    m.params AS params
+              FROM  config.index_normalizer n
+                    JOIN config.metabib_field_index_norm_map m ON (m.norm = n.id)
+              WHERE field = NEW.field AND m.pos < 0
+              ORDER BY m.pos LOOP
+                EXECUTE 'SELECT ' || normalizer.func || '(' ||
+                    quote_literal( value ) ||
+                    CASE
+                        WHEN normalizer.param_count > 0
+                            THEN ',' || REPLACE(REPLACE(BTRIM(normalizer.params,'[]'),E'\'',E'\\\''),E'"',E'\'')
+                            ELSE ''
+                        END ||
+                    ')' INTO value;
+
+        END LOOP;
+
+        NEW.value = value;
+
+        FOR normalizer IN
+            SELECT  n.func AS func,
+                    n.param_count AS param_count,
+                    m.params AS params
+              FROM  config.index_normalizer n
+                    JOIN config.metabib_field_index_norm_map m ON (m.norm = n.id)
+              WHERE field = NEW.field AND m.pos >= 0
+              ORDER BY m.pos LOOP
+                EXECUTE 'SELECT ' || normalizer.func || '(' ||
+                    quote_literal( value ) ||
+                    CASE
+                        WHEN normalizer.param_count > 0
+                            THEN ',' || REPLACE(REPLACE(BTRIM(normalizer.params,'[]'),E'\'',E'\\\''),E'"',E'\'')
+                            ELSE ''
+                        END ||
+                    ')' INTO value;
+
+        END LOOP;
+   END IF;
+
+    IF TG_TABLE_NAME::TEXT ~ 'browse_entry$' THEN
+
+        value :=  ARRAY_TO_STRING(
+            evergreen.regexp_split_to_array(value, E'\\W+'), ' '
+        );
+        value := public.search_normalize(value);
+        NEW.index_vector = to_tsvector(TG_ARGV[0]::regconfig, value);
+
+    ELSIF TG_TABLE_NAME::TEXT ~ 'field_entry$' THEN
+        FOR ts_rec IN
+
+            SELECT DISTINCT m.ts_config, m.index_weight
+            FROM config.metabib_class_ts_map m
+                 LEFT JOIN metabib.record_attr_vector_list r ON (r.source = NEW.source)
+                 LEFT JOIN config.coded_value_map ccvm ON (
+                    ccvm.ctype IN ('item_lang', 'language') AND
+                    ccvm.code = m.index_lang AND
+                    r.vlist @> intset(ccvm.id)
+                )
+            WHERE m.field_class = TG_ARGV[0]
+                AND m.active
+                AND (m.always OR NOT EXISTS (SELECT 1 FROM config.metabib_field_ts_map WHERE metabib_field = NEW.field))
+                AND (m.index_lang IS NULL OR ccvm.id IS NOT NULL)
+                        UNION
+            SELECT DISTINCT m.ts_config, m.index_weight
+            FROM config.metabib_field_ts_map m
+                 LEFT JOIN metabib.record_attr_vector_list r ON (r.source = NEW.source)
+                 LEFT JOIN config.coded_value_map ccvm ON (
+                    ccvm.ctype IN ('item_lang', 'language') AND
+                    ccvm.code = m.index_lang AND
+                    r.vlist @> intset(ccvm.id)
+                )
+            WHERE m.metabib_field = NEW.field
+                AND m.active
+                AND (m.index_lang IS NULL OR ccvm.id IS NOT NULL)
+            ORDER BY index_weight ASC
+
+        LOOP
+
+            IF cur_weight IS NOT NULL AND cur_weight != ts_rec.index_weight THEN
+                NEW.index_vector = NEW.index_vector || setweight(temp_vector::tsvector,cur_weight);
+                temp_vector = '';
+            END IF;
+
+            cur_weight = ts_rec.index_weight;
+            SELECT INTO temp_vector temp_vector || ' ' || to_tsvector(ts_rec.ts_config::regconfig, value)::TEXT;
+
+        END LOOP;
+        NEW.index_vector = NEW.index_vector || setweight(temp_vector::tsvector,cur_weight);
+    ELSE
+        NEW.index_vector = to_tsvector(TG_ARGV[0]::regconfig, value);
+    END IF;
+
+    RETURN NEW;
+END;
+$$ LANGUAGE PLPGSQL;
+
+-- add new sr_format attribute definition
+
+INSERT INTO config.record_attr_definition (name, label, phys_char_sf)
+VALUES (
+    'sr_format', 
+    oils_i18n_gettext('sr_format', 'Sound recording format', 'crad', 'label'),
+    '62'
+);
+
+INSERT INTO config.coded_value_map (id, ctype, code, value) VALUES
+(557, 'sr_format', 'a', oils_i18n_gettext(557, '16 rpm', 'ccvm', 'value')),
+(558, 'sr_format', 'b', oils_i18n_gettext(558, '33 1/3 rpm', 'ccvm', 'value')),
+(559, 'sr_format', 'c', oils_i18n_gettext(559, '45 rpm', 'ccvm', 'value')),
+(560, 'sr_format', 'f', oils_i18n_gettext(560, '1.4 m. per second', 'ccvm', 'value')),
+(561, 'sr_format', 'd', oils_i18n_gettext(561, '78 rpm', 'ccvm', 'value')),
+(562, 'sr_format', 'e', oils_i18n_gettext(562, '8 rpm', 'ccvm', 'value')),
+(563, 'sr_format', 'l', oils_i18n_gettext(563, '1 7/8 ips', 'ccvm', 'value')),
+(586, 'item_form', 'o', oils_i18n_gettext('586', 'Online', 'ccvm', 'value')),
+(587, 'item_form', 'q', oils_i18n_gettext('587', 'Direct electronic', 'ccvm', 'value'));
+
+INSERT INTO config.coded_value_map
+    (id, ctype, code, value, search_label) VALUES 
+(564, 'icon_format', 'book', 
+    oils_i18n_gettext(564, 'Book', 'ccvm', 'value'),
+    oils_i18n_gettext(564, 'Book', 'ccvm', 'search_label')),
+(565, 'icon_format', 'braille', 
+    oils_i18n_gettext(565, 'Braille', 'ccvm', 'value'),
+    oils_i18n_gettext(565, 'Braille', 'ccvm', 'search_label')),
+(566, 'icon_format', 'software', 
+    oils_i18n_gettext(566, 'Software and video games', 'ccvm', 'value'),
+    oils_i18n_gettext(566, 'Software and video games', 'ccvm', 'search_label')),
+(567, 'icon_format', 'dvd', 
+    oils_i18n_gettext(567, 'DVD', 'ccvm', 'value'),
+    oils_i18n_gettext(567, 'DVD', 'ccvm', 'search_label')),
+(568, 'icon_format', 'ebook', 
+    oils_i18n_gettext(568, 'E-book', 'ccvm', 'value'),
+    oils_i18n_gettext(568, 'E-book', 'ccvm', 'search_label')),
+(569, 'icon_format', 'eaudio', 
+    oils_i18n_gettext(569, 'E-audio', 'ccvm', 'value'),
+    oils_i18n_gettext(569, 'E-audio', 'ccvm', 'search_label')),
+(570, 'icon_format', 'kit', 
+    oils_i18n_gettext(570, 'Kit', 'ccvm', 'value'),
+    oils_i18n_gettext(570, 'Kit', 'ccvm', 'search_label')),
+(571, 'icon_format', 'map', 
+    oils_i18n_gettext(571, 'Map', 'ccvm', 'value'),
+    oils_i18n_gettext(571, 'Map', 'ccvm', 'search_label')),
+(572, 'icon_format', 'microform', 
+    oils_i18n_gettext(572, 'Microform', 'ccvm', 'value'),
+    oils_i18n_gettext(572, 'Microform', 'ccvm', 'search_label')),
+(573, 'icon_format', 'score', 
+    oils_i18n_gettext(573, 'Music Score', 'ccvm', 'value'),
+    oils_i18n_gettext(573, 'Music Score', 'ccvm', 'search_label')),
+(574, 'icon_format', 'picture', 
+    oils_i18n_gettext(574, 'Picture', 'ccvm', 'value'),
+    oils_i18n_gettext(574, 'Picture', 'ccvm', 'search_label')),
+(575, 'icon_format', 'equip', 
+    oils_i18n_gettext(575, 'Equipment, games, toys', 'ccvm', 'value'),
+    oils_i18n_gettext(575, 'Equipment, games, toys', 'ccvm', 'search_label')),
+(576, 'icon_format', 'serial', 
+    oils_i18n_gettext(576, 'Serials and magazines', 'ccvm', 'value'),
+    oils_i18n_gettext(576, 'Serials and magazines', 'ccvm', 'search_label')),
+(577, 'icon_format', 'vhs', 
+    oils_i18n_gettext(577, 'VHS', 'ccvm', 'value'),
+    oils_i18n_gettext(577, 'VHS', 'ccvm', 'search_label')),
+(578, 'icon_format', 'evideo', 
+    oils_i18n_gettext(578, 'E-video', 'ccvm', 'value'),
+    oils_i18n_gettext(578, 'E-video', 'ccvm', 'search_label')),
+(579, 'icon_format', 'cdaudiobook', 
+    oils_i18n_gettext(579, 'CD Audiobook', 'ccvm', 'value'),
+    oils_i18n_gettext(579, 'CD Audiobook', 'ccvm', 'search_label')),
+(580, 'icon_format', 'cdmusic', 
+    oils_i18n_gettext(580, 'CD Music recording', 'ccvm', 'value'),
+    oils_i18n_gettext(580, 'CD Music recording', 'ccvm', 'search_label')),
+(581, 'icon_format', 'casaudiobook', 
+    oils_i18n_gettext(581, 'Cassette audiobook', 'ccvm', 'value'),
+    oils_i18n_gettext(581, 'Cassette audiobook', 'ccvm', 'search_label')),
+(582, 'icon_format', 'casmusic',
+    oils_i18n_gettext(582, 'Audiocassette music recording', 'ccvm', 'value'),
+    oils_i18n_gettext(582, 'Audiocassette music recording', 'ccvm', 'search_label')),
+(583, 'icon_format', 'phonospoken', 
+    oils_i18n_gettext(583, 'Phonograph spoken recording', 'ccvm', 'value'),
+    oils_i18n_gettext(583, 'Phonograph spoken recording', 'ccvm', 'search_label')),
+(584, 'icon_format', 'phonomusic', 
+    oils_i18n_gettext(584, 'Phonograph music recording', 'ccvm', 'value'),
+    oils_i18n_gettext(584, 'Phonograph music recording', 'ccvm', 'search_label')),
+(585, 'icon_format', 'lpbook', 
+    oils_i18n_gettext(585, 'Large Print Book', 'ccvm', 'value'),
+    oils_i18n_gettext(585, 'Large Print Book', 'ccvm', 'search_label'))
+;
+
+-- add the new icon format attribute definition
+
+INSERT INTO config.global_flag (name, label, value, enabled) VALUES (
+    'opac.icon_attr',
+    oils_i18n_gettext(
+        'opac.icon_attr', 
+        'OPAC Format Icons Attribute',
+        'cgf',
+        'label'
+    ),
+    'icon_format', 
+    TRUE
+);
+
+INSERT INTO config.record_attr_definition 
+    (name, label, multi, filter, composite) VALUES (
+    'icon_format',
+    oils_i18n_gettext(
+        'icon_format',
+        'OPAC Format Icons',
+        'crad',
+        'label'
+    ),
+    TRUE, TRUE, TRUE
+);
+
+-- icon format composite definitions
+
+INSERT INTO config.composite_attr_entry_definition 
+    (coded_value, definition) VALUES
+--book
+(564, '{"0":[{"_attr":"item_type","_val":"a"},{"_attr":"item_type","_val":"t"}],"1":{"_not":[{"_attr":"item_form","_val":"a"},{"_attr":"item_form","_val":"b"},{"_attr":"item_form","_val":"c"},{"_attr":"item_form","_val":"d"},{"_attr":"item_form","_val":"f"},{"_attr":"item_form","_val":"o"},{"_attr":"item_form","_val":"q"},{"_attr":"item_form","_val":"r"},{"_attr":"item_form","_val":"s"}]},"2":[{"_attr":"bib_level","_val":"a"},{"_attr":"bib_level","_val":"c"},{"_attr":"bib_level","_val":"d"},{"_attr":"bib_level","_val":"m"}]}'),
+
+-- braille
+(565, '{"0":{"_attr":"item_type","_val":"a"},"1":{"_attr":"item_form","_val":"f"}}'),
+
+-- software
+(566, '{"_attr":"item_type","_val":"m"}'),
+
+-- dvd
+(567, '{"_attr":"vr_format","_val":"v"}'),
+
+-- ebook
+(568, '{"0":[{"_attr":"item_type","_val":"a"},{"_attr":"item_type","_val":"t"}],"1":[{"_attr":"item_form","_val":"o"},{"_attr":"item_form","_val":"s"},{"_attr":"item_form","_val":"q"}],"2":[{"_attr":"bib_level","_val":"a"},{"_attr":"bib_level","_val":"c"},{"_attr":"bib_level","_val":"d"},{"_attr":"bib_level","_val":"m"}]}'),
+
+-- eaudio
+(569, '{"0":{"_attr":"item_type","_val":"i"},"1":[{"_attr":"item_form","_val":"o"},{"_attr":"item_form","_val":"q"},{"_attr":"item_form","_val":"s"}]}'),
+
+-- kit
+(570, '[{"_attr":"item_type","_val":"o"},{"_attr":"item_type","_val":"p"}]'),
+
+-- map
+(571, '[{"_attr":"item_type","_val":"e"},{"_attr":"item_type","_val":"f"}]'),
+
+-- microform
+(572, '[{"_attr":"item_form","_val":"a"},{"_attr":"item_form","_val":"b"},{"_attr":"item_form","_val":"c"}]'),
+
+-- score
+(573, '[{"_attr":"item_type","_val":"c"},{"_attr":"item_type","_val":"d"}]'),
+
+-- picture
+(574, '{"_attr":"item_type","_val":"k"}'),
+
+-- equip
+(575, '{"_attr":"item_type","_val":"r"}'),
+
+-- serial
+(576, '[{"_attr":"bib_level","_val":"b"},{"_attr":"bib_level","_val":"s"}]'),
+
+-- vhs
+(577, '{"_attr":"vr_format","_val":"b"}'),
+
+-- evideo
+(578, '{"0":{"_attr":"item_type","_val":"g"},"1":[{"_attr":"item_form","_val":"o"},{"_attr":"item_form","_val":"s"},{"_attr":"item_form","_val":"q"}]}'),
+
+-- cdaudiobook
+(579, '{"0":{"_attr":"item_type","_val":"i"},"1":{"_attr":"sr_format","_val":"f"}}'),
+
+-- cdmusic
+(580, '{"0":{"_attr":"item_type","_val":"j"},"1":{"_attr":"sr_format","_val":"f"}}'),
+
+-- casaudiobook
+(581, '{"0":{"_attr":"item_type","_val":"i"},"1":{"_attr":"sr_format","_val":"l"}}'),
+
+-- casmusic
+(582, '{"0":{"_attr":"item_type","_val":"j"},"1":{"_attr":"sr_format","_val":"l"}}'),
+
+-- phonospoken
+(583, '{"0":{"_attr":"item_type","_val":"i"},"1":[{"_attr":"sr_format","_val":"a"},{"_attr":"sr_format","_val":"b"},{"_attr":"sr_format","_val":"c"},{"_attr":"sr_format","_val":"d"},{"_attr":"sr_format","_val":"e"}]}'),
+
+-- phonomusic
+(584, '{"0":{"_attr":"item_type","_val":"j"},"1":[{"_attr":"sr_format","_val":"a"},{"_attr":"sr_format","_val":"b"},{"_attr":"sr_format","_val":"c"},{"_attr":"sr_format","_val":"d"},{"_attr":"sr_format","_val":"e"}]}'),
+
+-- lpbook
+(585, '{"0":[{"_attr":"item_type","_val":"a"},{"_attr":"item_type","_val":"t"}],"1":{"_attr":"item_form","_val":"d"},"2":[{"_attr":"bib_level","_val":"a"},{"_attr":"bib_level","_val":"c"},{"_attr":"bib_level","_val":"d"},{"_attr":"bib_level","_val":"m"}]}');
+
+
+
+
+CREATE OR REPLACE FUNCTION unapi.mra (
+    obj_id BIGINT,
+    format TEXT,
+    ename TEXT,
+    includes TEXT[],
+    org TEXT,
+    depth INT DEFAULT NULL,
+    slimit HSTORE DEFAULT NULL,
+    soffset HSTORE DEFAULT NULL,
+    include_xmlns BOOL DEFAULT TRUE
+) RETURNS XML AS $F$
+    SELECT  XMLELEMENT(
+        name attributes,
+        XMLATTRIBUTES(
+            CASE WHEN $9 THEN 'http://open-ils.org/spec/indexing/v1' ELSE NULL END AS xmlns,
+            'tag:open-ils.org:U2 at mra/' || $1 AS id, 
+            'tag:open-ils.org:U2 at bre/' || $1 AS record 
+        ),  
+        (SELECT XMLAGG(foo.y)
+          FROM (
+            SELECT  XMLELEMENT(
+                        name field,
+                        XMLATTRIBUTES(
+                            mra.attr AS name,
+                            cvm.value AS "coded-value",
+                            cvm.id AS "cvmid",
+                            rad.composite,
+                            rad.multi,
+                            rad.filter,
+                            rad.sorter
+                        ),
+                        mra.value
+                    )
+              FROM  metabib.record_attr_flat mra
+                    JOIN config.record_attr_definition rad ON (mra.attr = rad.name)
+                    LEFT JOIN config.coded_value_map cvm ON (cvm.ctype = mra.attr AND code = mra.value)
+              WHERE mra.id = $1
+            )foo(y)
+        )   
+    )   
+$F$ LANGUAGE SQL STABLE;
+
+
+SELECT evergreen.upgrade_deps_block_check('0865', :eg_version);
+
+-- First, explode the field into constituent parts
+WITH format_parts_array AS (
+    SELECT  a.id,
+            STRING_TO_ARRAY(a.holdable_formats, '-') AS parts
+      FROM  action.hold_request a
+      WHERE a.hold_type = 'M'
+            AND a.fulfillment_time IS NULL
+), format_parts_wide AS (
+    SELECT  id,
+            regexp_split_to_array(parts[1], '') AS item_type,
+            regexp_split_to_array(parts[2], '') AS item_form,
+            parts[3] AS item_lang
+      FROM  format_parts_array
+), converted_formats_flat AS (
+    SELECT  id, 
+            CASE WHEN ARRAY_LENGTH(item_type,1) > 0
+                THEN '"0":[{"_attr":"item_type","_val":"' || ARRAY_TO_STRING(item_type,'"},{"_attr":"item_type","_val":"') || '"}]'
+                ELSE '"0":""'
+            END AS item_type,
+            CASE WHEN ARRAY_LENGTH(item_form,1) > 0
+                THEN '"1":[{"_attr":"item_form","_val":"' || ARRAY_TO_STRING(item_form,'"},{"_attr":"item_form","_val":"') || '"}]'
+                ELSE '"1":""'
+            END AS item_form,
+            CASE WHEN item_lang <> ''
+                THEN '"2":[{"_attr":"item_lang","_val":"' || item_lang ||'"}]'
+                ELSE '"2":""'
+            END AS item_lang
+      FROM  format_parts_wide
+) UPDATE action.hold_request SET holdable_formats = '{' ||
+        converted_formats_flat.item_type || ',' ||
+        converted_formats_flat.item_form || ',' ||
+        converted_formats_flat.item_lang || '}'
+    FROM converted_formats_flat WHERE converted_formats_flat.id = action.hold_request.id;
+
+
+
+SELECT evergreen.upgrade_deps_block_check('0866', :eg_version);
+
+DROP FUNCTION asset.record_has_holdable_copy (BIGINT);
+CREATE FUNCTION asset.record_has_holdable_copy ( rid BIGINT, ou INT DEFAULT NULL) RETURNS BOOL AS $f$
+BEGIN
+    PERFORM 1
+        FROM
+            asset.copy acp
+            JOIN asset.call_number acn ON acp.call_number = acn.id
+            JOIN asset.copy_location acpl ON acp.location = acpl.id
+            JOIN config.copy_status ccs ON acp.status = ccs.id
+        WHERE
+            acn.record = rid
+            AND acp.holdable = true
+            AND acpl.holdable = true
+            AND ccs.holdable = true
+            AND acp.deleted = false
+            AND acp.circ_lib IN (SELECT id FROM actor.org_unit_descendants(COALESCE($2,(SELECT id FROM evergreen.org_top()))))
+        LIMIT 1;
+    IF FOUND THEN
+        RETURN true;
+    END IF;
+    RETURN FALSE;
+END;
+$f$ LANGUAGE PLPGSQL;
+
+DROP FUNCTION asset.metarecord_has_holdable_copy (BIGINT);
+CREATE FUNCTION asset.metarecord_has_holdable_copy ( rid BIGINT, ou INT DEFAULT NULL) RETURNS BOOL AS $f$
+BEGIN
+    PERFORM 1
+        FROM
+            asset.copy acp
+            JOIN asset.call_number acn ON acp.call_number = acn.id
+            JOIN asset.copy_location acpl ON acp.location = acpl.id
+            JOIN config.copy_status ccs ON acp.status = ccs.id
+            JOIN metabib.metarecord_source_map mmsm ON acn.record = mmsm.source
+        WHERE
+            mmsm.metarecord = rid
+            AND acp.holdable = true
+            AND acpl.holdable = true
+            AND ccs.holdable = true
+            AND acp.deleted = false
+            AND acp.circ_lib IN (SELECT id FROM actor.org_unit_descendants(COALESCE($2,(SELECT id FROM evergreen.org_top()))))
+        LIMIT 1;
+    IF FOUND THEN
+        RETURN true;
+    END IF;
+    RETURN FALSE;
+END;
+$f$ LANGUAGE PLPGSQL;
+
+CREATE OR REPLACE FUNCTION asset.opac_ou_metarecord_copy_count (org INT, rid BIGINT) RETURNS TABLE (depth INT, org_unit INT, visible BIGINT, available BIGINT, unshadow BIGINT, transcendant INT) AS $f$
+DECLARE
+    ans RECORD;
+    trans INT;
+BEGIN
+    SELECT 1 INTO trans FROM biblio.record_entry b JOIN config.bib_source src ON (b.source = src.id) JOIN metabib.metarecord_source_map m ON (m.source = b.id) WHERE src.transcendant AND m.metarecord = rid;
+
+    FOR ans IN SELECT u.id, t.depth FROM actor.org_unit_ancestors(org) AS u JOIN actor.org_unit_type t ON (u.ou_type = t.id) LOOP
+        RETURN QUERY
+        SELECT  ans.depth,
+                ans.id,
+                COUNT( av.id ),
+                SUM( CASE WHEN cp.status IN (0,7,12) THEN 1 ELSE 0 END ),
+                COUNT( av.id ),
+                trans
+          FROM  
+                actor.org_unit_descendants(ans.id) d
+                JOIN asset.opac_visible_copies av ON (av.circ_lib = d.id)
+                JOIN asset.copy cp ON (cp.id = av.copy_id)
+                JOIN metabib.metarecord_source_map m ON (m.metarecord = rid AND m.source = av.record)
+          GROUP BY 1,2,6;
+
+        IF NOT FOUND THEN
+            RETURN QUERY SELECT ans.depth, ans.id, 0::BIGINT, 0::BIGINT, 0::BIGINT, trans;
+        END IF;
+
+    END LOOP;
+
+    RETURN;
+END;
+$f$ LANGUAGE PLPGSQL;
+
+CREATE OR REPLACE FUNCTION asset.opac_lasso_metarecord_copy_count (i_lasso INT, rid BIGINT) RETURNS TABLE (depth INT, org_unit INT, visible BIGINT, available BIGINT, unshadow BIGINT, transcendant INT) AS $f$
+DECLARE
+    ans RECORD;
+    trans INT;
+BEGIN
+    SELECT 1 INTO trans FROM biblio.record_entry b JOIN config.bib_source src ON (b.source = src.id) JOIN metabib.metarecord_source_map m ON (m.source = b.id) WHERE src.transcendant AND m.metarecord = rid;
+
+    FOR ans IN SELECT u.org_unit AS id FROM actor.org_lasso_map AS u WHERE lasso = i_lasso LOOP
+        RETURN QUERY
+        SELECT  -1,
+                ans.id,
+                COUNT( av.id ),
+                SUM( CASE WHEN cp.status IN (0,7,12) THEN 1 ELSE 0 END ),
+                COUNT( av.id ),
+                trans
+          FROM
+                actor.org_unit_descendants(ans.id) d
+                JOIN asset.opac_visible_copies av ON (av.circ_lib = d.id)
+                JOIN asset.copy cp ON (cp.id = av.copy_id)
+                JOIN metabib.metarecord_source_map m ON (m.metarecord = rid AND m.source = av.record)
+          GROUP BY 1,2,6;
+
+        IF NOT FOUND THEN
+            RETURN QUERY SELECT ans.depth, ans.id, 0::BIGINT, 0::BIGINT, 0::BIGINT, trans;
+        END IF;
+
+    END LOOP;   
+                
+    RETURN;     
+END;            
+$f$ LANGUAGE PLPGSQL;
+
+CREATE OR REPLACE FUNCTION asset.staff_ou_metarecord_copy_count (org INT, rid BIGINT) RETURNS TABLE (depth INT, org_unit INT, visible BIGINT, available BIGINT, unshadow BIGINT, transcendant INT) AS $f$
+DECLARE         
+    ans RECORD; 
+    trans INT;
+BEGIN
+    SELECT 1 INTO trans FROM biblio.record_entry b JOIN config.bib_source src ON (b.source = src.id) JOIN metabib.metarecord_source_map m ON (m.source = b.id) WHERE src.transcendant AND m.metarecord = rid;
+
+    FOR ans IN SELECT u.id, t.depth FROM actor.org_unit_ancestors(org) AS u JOIN actor.org_unit_type t ON (u.ou_type = t.id) LOOP
+        RETURN QUERY
+        SELECT  ans.depth,
+                ans.id,
+                COUNT( cp.id ),
+                SUM( CASE WHEN cp.status IN (0,7,12) THEN 1 ELSE 0 END ),
+                COUNT( cp.id ),
+                trans
+          FROM
+                actor.org_unit_descendants(ans.id) d
+                JOIN asset.copy cp ON (cp.circ_lib = d.id AND NOT cp.deleted)
+                JOIN asset.call_number cn ON (cn.id = cp.call_number AND NOT cn.deleted)
+                JOIN metabib.metarecord_source_map m ON (m.metarecord = rid AND m.source = cn.record)
+          GROUP BY 1,2,6;
+
+        IF NOT FOUND THEN
+            RETURN QUERY SELECT ans.depth, ans.id, 0::BIGINT, 0::BIGINT, 0::BIGINT, trans;
+        END IF;
+
+    END LOOP;
+
+    RETURN;
+END;
+$f$ LANGUAGE PLPGSQL;
+
+CREATE OR REPLACE FUNCTION asset.staff_lasso_metarecord_copy_count (i_lasso INT, rid BIGINT) RETURNS TABLE (depth INT, org_unit INT, visible BIGINT, available BIGINT, unshadow BIGINT, transcendant INT) AS $f$
+DECLARE
+    ans RECORD;
+    trans INT;
+BEGIN
+    SELECT 1 INTO trans FROM biblio.record_entry b JOIN config.bib_source src ON (b.source = src.id) JOIN metabib.metarecord_source_map m ON (m.source = b.id) WHERE src.transcendant AND m.metarecord = rid;
+
+    FOR ans IN SELECT u.org_unit AS id FROM actor.org_lasso_map AS u WHERE lasso = i_lasso LOOP
+        RETURN QUERY
+        SELECT  -1,
+                ans.id,
+                COUNT( cp.id ),
+                SUM( CASE WHEN cp.status IN (0,7,12) THEN 1 ELSE 0 END ),
+                COUNT( cp.id ),
+                trans
+          FROM
+                actor.org_unit_descendants(ans.id) d
+                JOIN asset.copy cp ON (cp.circ_lib = d.id AND NOT cp.deleted)
+                JOIN asset.call_number cn ON (cn.id = cp.call_number AND NOT cn.deleted)
+                JOIN metabib.metarecord_source_map m ON (m.metarecord = rid AND m.source = cn.record)
+          GROUP BY 1,2,6;
+
+        IF NOT FOUND THEN
+            RETURN QUERY SELECT ans.depth, ans.id, 0::BIGINT, 0::BIGINT, 0::BIGINT, trans;
+        END IF;
+
+    END LOOP;
+
+    RETURN;
+END;
+$f$ LANGUAGE PLPGSQL;
+
+CREATE OR REPLACE FUNCTION unapi.mmr_mra (
+    obj_id BIGINT,
+    format TEXT,
+    ename TEXT,
+    includes TEXT[],
+    org TEXT,
+    depth INT DEFAULT NULL,
+    slimit HSTORE DEFAULT NULL,
+    soffset HSTORE DEFAULT NULL,
+    include_xmlns BOOL DEFAULT TRUE,
+    pref_lib INT DEFAULT NULL
+) RETURNS XML AS $F$
+    SELECT  XMLELEMENT(
+        name attributes,
+        XMLATTRIBUTES(
+            CASE WHEN $9 THEN 'http://open-ils.org/spec/indexing/v1' ELSE NULL END AS xmlns,
+            'tag:open-ils.org:U2 at mmr/' || $1 AS metarecord
+        ),
+        (SELECT XMLAGG(foo.y)
+          FROM (
+            SELECT  DISTINCT ON (COALESCE(cvm.id,uvm.id))
+                    COALESCE(cvm.id,uvm.id),
+                    XMLELEMENT(
+                        name field,
+                        XMLATTRIBUTES(
+                            mra.attr AS name,
+                            cvm.value AS "coded-value",
+                            cvm.id AS "cvmid",
+                            rad.composite,
+                            rad.multi,
+                            rad.filter,
+                            rad.sorter
+                        ),
+                        mra.value
+                    )
+              FROM  metabib.record_attr_flat mra
+                    JOIN config.record_attr_definition rad ON (mra.attr = rad.name)
+                    LEFT JOIN config.coded_value_map cvm ON (cvm.ctype = mra.attr AND code = mra.value)
+                    LEFT JOIN metabib.uncontrolled_record_attr_value uvm ON (uvm.attr = mra.attr AND uvm.value = mra.value)
+              WHERE mra.id IN (
+                    WITH aou AS (SELECT COALESCE(id, (evergreen.org_top()).id) AS id 
+                        FROM actor.org_unit WHERE shortname = $5 LIMIT 1)
+                    SELECT source 
+                    FROM metabib.metarecord_source_map, aou
+                    WHERE metarecord = $1 AND (
+                        EXISTS (
+                            SELECT 1 FROM asset.opac_visible_copies 
+                            WHERE record = source AND circ_lib IN (
+                                SELECT id FROM actor.org_unit_descendants(aou.id, $6)) 
+                            LIMIT 1
+                        )
+                        OR EXISTS (SELECT 1 FROM located_uris(source, aou.id, $10) LIMIT 1)
+                    )
+                )
+              ORDER BY 1
+            )foo(id,y)
+        )
+    )
+$F$ LANGUAGE SQL STABLE;
+
+CREATE OR REPLACE FUNCTION evergreen.ranked_volumes(
+    bibid BIGINT[],
+    ouid INT,
+    depth INT DEFAULT NULL,
+    slimit HSTORE DEFAULT NULL,
+    soffset HSTORE DEFAULT NULL,
+    pref_lib INT DEFAULT NULL,
+    includes TEXT[] DEFAULT NULL::TEXT[]
+) RETURNS TABLE (id BIGINT, name TEXT, label_sortkey TEXT, rank BIGINT) AS $$
+    SELECT ua.id, ua.name, ua.label_sortkey, MIN(ua.rank) AS rank FROM (
+        SELECT acn.id, aou.name, acn.label_sortkey,
+            evergreen.rank_ou(aou.id, $2, $6), evergreen.rank_cp_status(acp.status),
+            RANK() OVER w
+        FROM asset.call_number acn
+            JOIN asset.copy acp ON (acn.id = acp.call_number)
+            JOIN actor.org_unit_descendants( $2, COALESCE(
+                $3, (
+                    SELECT depth
+                    FROM actor.org_unit_type aout
+                        INNER JOIN actor.org_unit ou ON ou_type = aout.id
+                    WHERE ou.id = $2
+                ), $6)
+            ) AS aou ON (acp.circ_lib = aou.id)
+        WHERE acn.record = ANY ($1)
+            AND acn.deleted IS FALSE
+            AND acp.deleted IS FALSE
+            AND CASE WHEN ('exclude_invisible_acn' = ANY($7)) THEN
+                EXISTS (
+                    SELECT 1
+                    FROM asset.opac_visible_copies
+                    WHERE copy_id = acp.id AND record = acn.record
+                ) ELSE TRUE END
+        GROUP BY acn.id, acp.status, aou.name, acn.label_sortkey, aou.id
+        WINDOW w AS (
+            ORDER BY evergreen.rank_ou(aou.id, $2, $6), evergreen.rank_cp_status(acp.status)
+        )
+    ) AS ua
+    GROUP BY ua.id, ua.name, ua.label_sortkey
+    ORDER BY rank, ua.name, ua.label_sortkey
+    LIMIT ($4 -> 'acn')::INT
+    OFFSET ($5 -> 'acn')::INT;
+$$
+LANGUAGE SQL STABLE;
+
+CREATE OR REPLACE FUNCTION evergreen.ranked_volumes
+    ( bibid BIGINT, ouid INT, depth INT DEFAULT NULL, slimit HSTORE DEFAULT NULL, soffset HSTORE DEFAULT NULL, pref_lib INT DEFAULT NULL, includes TEXT[] DEFAULT NULL::TEXT[] )
+    RETURNS TABLE (id BIGINT, name TEXT, label_sortkey TEXT, rank BIGINT)
+    AS $$ SELECT * FROM evergreen.ranked_volumes(ARRAY[$1],$2,$3,$4,$5,$6,$7) $$ LANGUAGE SQL STABLE;
+
+
+CREATE OR REPLACE FUNCTION evergreen.located_uris (
+    bibid BIGINT[],
+    ouid INT,
+    pref_lib INT DEFAULT NULL
+) RETURNS TABLE (id BIGINT, name TEXT, label_sortkey TEXT, rank INT) AS $$
+    WITH all_orgs AS (SELECT COALESCE( enabled, FALSE ) AS flag FROM config.global_flag WHERE name = 'opac.located_uri.act_as_copy')
+    SELECT DISTINCT ON (id) * FROM (
+    SELECT acn.id, COALESCE(aou.name,aoud.name), acn.label_sortkey, evergreen.rank_ou(aou.id, $2, $3) AS pref_ou
+      FROM asset.call_number acn
+           INNER JOIN asset.uri_call_number_map auricnm ON acn.id = auricnm.call_number
+           INNER JOIN asset.uri auri ON auri.id = auricnm.uri
+           LEFT JOIN actor.org_unit_ancestors( COALESCE($3, $2) ) aou ON (acn.owning_lib = aou.id)
+           LEFT JOIN actor.org_unit_descendants( COALESCE($3, $2) ) aoud ON (acn.owning_lib = aoud.id),
+           all_orgs
+      WHERE acn.record = ANY ($1)
+          AND acn.deleted IS FALSE
+          AND auri.active IS TRUE
+          AND ((NOT all_orgs.flag AND aou.id IS NOT NULL) OR COALESCE(aou.id,aoud.id) IS NOT NULL)
+    UNION
+    SELECT acn.id, COALESCE(aou.name,aoud.name) AS name, acn.label_sortkey, evergreen.rank_ou(aou.id, $2, $3) AS pref_ou
+      FROM asset.call_number acn
+           INNER JOIN asset.uri_call_number_map auricnm ON acn.id = auricnm.call_number
+           INNER JOIN asset.uri auri ON auri.id = auricnm.uri
+           LEFT JOIN actor.org_unit_ancestors( $2 ) aou ON (acn.owning_lib = aou.id)
+           LEFT JOIN actor.org_unit_descendants( $2 ) aoud ON (acn.owning_lib = aoud.id),
+           all_orgs
+      WHERE acn.record = ANY ($1)
+          AND acn.deleted IS FALSE
+          AND auri.active IS TRUE
+          AND ((NOT all_orgs.flag AND aou.id IS NOT NULL) OR COALESCE(aou.id,aoud.id) IS NOT NULL))x
+    ORDER BY id, pref_ou DESC;
+$$
+LANGUAGE SQL STABLE;
+
+CREATE OR REPLACE FUNCTION evergreen.located_uris ( bibid BIGINT, ouid INT, pref_lib INT DEFAULT NULL)
+    RETURNS TABLE (id BIGINT, name TEXT, label_sortkey TEXT, rank INT)
+    AS $$ SELECT * FROM evergreen.located_uris(ARRAY[$1],$2,$3) $$ LANGUAGE SQL STABLE;
+
+
+CREATE OR REPLACE FUNCTION unapi.mmr_holdings_xml (
+    mid BIGINT,
+    ouid INT,
+    org TEXT,
+    depth INT DEFAULT NULL,
+    includes TEXT[] DEFAULT NULL::TEXT[],
+    slimit HSTORE DEFAULT NULL,
+    soffset HSTORE DEFAULT NULL,
+    include_xmlns BOOL DEFAULT TRUE,
+    pref_lib INT DEFAULT NULL
+)
+RETURNS XML AS $F$
+     SELECT  XMLELEMENT(
+                 name holdings,
+                 XMLATTRIBUTES(
+                    CASE WHEN $8 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
+                    CASE WHEN ('mmr' = ANY ($5)) THEN 'tag:open-ils.org:U2 at mmr/' || $1 || '/' || $3 ELSE NULL END AS id,
+                    (SELECT metarecord_has_holdable_copy FROM asset.metarecord_has_holdable_copy($1)) AS has_holdable
+                 ),
+                 XMLELEMENT(
+                     name counts,
+                     (SELECT  XMLAGG(XMLELEMENT::XML) FROM (
+                         SELECT  XMLELEMENT(
+                                     name count,
+                                     XMLATTRIBUTES('public' as type, depth, org_unit, coalesce(transcendant,0) as transcendant, available, visible as count, unshadow)
+                                 )::text
+                           FROM  asset.opac_ou_metarecord_copy_count($2,  $1)
+                                     UNION
+                         SELECT  XMLELEMENT(
+                                     name count,
+                                     XMLATTRIBUTES('staff' as type, depth, org_unit, coalesce(transcendant,0) as transcendant, available, visible as count, unshadow)
+                                 )::text
+                           FROM  asset.staff_ou_metarecord_copy_count($2, $1)
+                                     UNION
+                         SELECT  XMLELEMENT(
+                                     name count,
+                                     XMLATTRIBUTES('pref_lib' as type, depth, org_unit, coalesce(transcendant,0) as transcendant, available, visible as count, unshadow)
+                                 )::text
+                           FROM  asset.opac_ou_metarecord_copy_count($9,  $1)
+                                     ORDER BY 1
+                     )x)
+                 ),
+                 -- XXX monograph_parts and foreign_copies are skipped in MRs ... put them back some day?
+                 XMLELEMENT(
+                     name volumes,
+                     (SELECT XMLAGG(acn ORDER BY rank, name, label_sortkey) FROM (
+                        -- Physical copies
+                        SELECT  unapi.acn(y.id,'xml','volume',evergreen.array_remove_item_by_value( evergreen.array_remove_item_by_value($5,'holdings_xml'),'bre'), $3, $4, $6, $7, FALSE), y.rank, name, label_sortkey
+                        FROM evergreen.ranked_volumes((SELECT ARRAY_AGG(source) FROM metabib.metarecord_source_map WHERE metarecord = $1), $2, $4, $6, $7, $9, $5) AS y
+                        UNION ALL
+                        -- Located URIs
+                        SELECT unapi.acn(uris.id,'xml','volume',evergreen.array_remove_item_by_value( evergreen.array_remove_item_by_value($5,'holdings_xml'),'bre'), $3, $4, $6, $7, FALSE), uris.rank, name, label_sortkey
+                        FROM evergreen.located_uris((SELECT ARRAY_AGG(source) FROM metabib.metarecord_source_map WHERE metarecord = $1), $2, $9) AS uris
+                     )x)
+                 ),
+                 CASE WHEN ('ssub' = ANY ($5)) THEN
+                     XMLELEMENT(
+                         name subscriptions,
+                         (SELECT XMLAGG(ssub) FROM (
+                            SELECT  unapi.ssub(id,'xml','subscription','{}'::TEXT[], $3, $4, $6, $7, FALSE)
+                              FROM  serial.subscription
+                              WHERE record_entry IN (SELECT source FROM metabib.metarecord_source_map WHERE metarecord = $1)
+                        )x)
+                     )
+                 ELSE NULL END
+             );
+$F$ LANGUAGE SQL STABLE;
+
+
+
+SELECT evergreen.upgrade_deps_block_check('0867', :eg_version);
+
+INSERT INTO config.global_flag (name, label, value, enabled) VALUES (
+    'opac.metarecord.holds.format_attr', 
+    oils_i18n_gettext(
+        'opac.metarecord.holds.format_attr',
+        'OPAC Metarecord Hold Formats Attribute', 
+        'cgf',
+        'label'
+    ),
+    'mr_hold_format', 
+    TRUE
+);
+
+-- until we have a custom attribute for the selector, 
+-- default to the icon_format attribute
+INSERT INTO config.global_flag (name, label, value, enabled) VALUES (
+    'opac.format_selector.attr', 
+    oils_i18n_gettext(
+        'opac.format_selector.attr', 
+        'OPAC Format Selector Attribute', 
+        'cgf',
+        'label'
+    ),
+    'icon_format', 
+    TRUE
+);
+
+
+INSERT INTO config.record_attr_definition 
+    (name, label, multi, filter, composite) 
+VALUES (
+    'mr_hold_format', 
+    oils_i18n_gettext(
+        'mr_hold_format',
+        'Metarecord Hold Formats', 
+        'crad',
+        'label'
+    ),
+    TRUE, TRUE, TRUE
+);
+
+-- these formats are a subset of the "icon_format" attribute,
+-- modified to exclude electronic resources, which are not holdable
+
+-- for i18n purposes, these have to be listed individually
+INSERT INTO config.coded_value_map
+    (id, ctype, code, value, search_label) VALUES 
+(588, 'mr_hold_format', 'book', 
+    oils_i18n_gettext(588, 'Book', 'ccvm', 'value'),
+    oils_i18n_gettext(588, 'Book', 'ccvm', 'search_label')),
+(589, 'mr_hold_format', 'braille', 
+    oils_i18n_gettext(589, 'Braille', 'ccvm', 'value'),
+    oils_i18n_gettext(589, 'Braille', 'ccvm', 'search_label')),
+(590, 'mr_hold_format', 'software', 
+    oils_i18n_gettext(590, 'Software and video games', 'ccvm', 'value'),
+    oils_i18n_gettext(590, 'Software and video games', 'ccvm', 'search_label')),
+(591, 'mr_hold_format', 'dvd', 
+    oils_i18n_gettext(591, 'DVD', 'ccvm', 'value'),
+    oils_i18n_gettext(591, 'DVD', 'ccvm', 'search_label')),
+(592, 'mr_hold_format', 'kit', 
+    oils_i18n_gettext(592, 'Kit', 'ccvm', 'value'),
+    oils_i18n_gettext(592, 'Kit', 'ccvm', 'search_label')),
+(593, 'mr_hold_format', 'map', 
+    oils_i18n_gettext(593, 'Map', 'ccvm', 'value'),
+    oils_i18n_gettext(593, 'Map', 'ccvm', 'search_label')),
+(594, 'mr_hold_format', 'microform', 
+    oils_i18n_gettext(594, 'Microform', 'ccvm', 'value'),
+    oils_i18n_gettext(594, 'Microform', 'ccvm', 'search_label')),
+(595, 'mr_hold_format', 'score', 
+    oils_i18n_gettext(595, 'Music Score', 'ccvm', 'value'),
+    oils_i18n_gettext(595, 'Music Score', 'ccvm', 'search_label')),
+(596, 'mr_hold_format', 'picture', 
+    oils_i18n_gettext(596, 'Picture', 'ccvm', 'value'),
+    oils_i18n_gettext(596, 'Picture', 'ccvm', 'search_label')),
+(597, 'mr_hold_format', 'equip', 
+    oils_i18n_gettext(597, 'Equipment, games, toys', 'ccvm', 'value'),
+    oils_i18n_gettext(597, 'Equipment, games, toys', 'ccvm', 'search_label')),
+(598, 'mr_hold_format', 'serial', 
+    oils_i18n_gettext(598, 'Serials and magazines', 'ccvm', 'value'),
+    oils_i18n_gettext(598, 'Serials and magazines', 'ccvm', 'search_label')),
+(599, 'mr_hold_format', 'vhs', 
+    oils_i18n_gettext(599, 'VHS', 'ccvm', 'value'),
+    oils_i18n_gettext(599, 'VHS', 'ccvm', 'search_label')),
+(600, 'mr_hold_format', 'cdaudiobook', 
+    oils_i18n_gettext(600, 'CD Audiobook', 'ccvm', 'value'),
+    oils_i18n_gettext(600, 'CD Audiobook', 'ccvm', 'search_label')),
+(601, 'mr_hold_format', 'cdmusic', 
+    oils_i18n_gettext(601, 'CD Music recording', 'ccvm', 'value'),
+    oils_i18n_gettext(601, 'CD Music recording', 'ccvm', 'search_label')),
+(602, 'mr_hold_format', 'casaudiobook', 
+    oils_i18n_gettext(602, 'Cassette audiobook', 'ccvm', 'value'),
+    oils_i18n_gettext(602, 'Cassette audiobook', 'ccvm', 'search_label')),
+(603, 'mr_hold_format', 'casmusic',
+    oils_i18n_gettext(603, 'Audiocassette music recording', 'ccvm', 'value'),
+    oils_i18n_gettext(603, 'Audiocassette music recording', 'ccvm', 'search_label')),
+(604, 'mr_hold_format', 'phonospoken', 
+    oils_i18n_gettext(604, 'Phonograph spoken recording', 'ccvm', 'value'),
+    oils_i18n_gettext(604, 'Phonograph spoken recording', 'ccvm', 'search_label')),
+(605, 'mr_hold_format', 'phonomusic', 
+    oils_i18n_gettext(605, 'Phonograph music recording', 'ccvm', 'value'),
+    oils_i18n_gettext(605, 'Phonograph music recording', 'ccvm', 'search_label')),
+(606, 'mr_hold_format', 'lpbook', 
+    oils_i18n_gettext(606, 'Large Print Book', 'ccvm', 'value'),
+    oils_i18n_gettext(606, 'Large Print Book', 'ccvm', 'search_label'))
+;
+
+-- but we can auto-generate the composite definitions
+
+DO $$
+    DECLARE format TEXT;
+BEGIN
+    FOR format IN SELECT UNNEST(
+        '{book,braille,software,dvd,kit,map,microform,score,picture,equip,serial,vhs,cdaudiobook,cdmusic,casaudiobook,casmusic,phonospoken,phonomusic,lpbook}'::text[]) LOOP
+
+        INSERT INTO config.composite_attr_entry_definition 
+            (coded_value, definition) VALUES
+            (
+                -- get the ID from the new ccvm above
+                (SELECT id FROM config.coded_value_map 
+                    WHERE code = format AND ctype = 'mr_hold_format'),
+                -- get the def of the matching ccvm attached to the icon_format attr
+                (SELECT definition FROM config.composite_attr_entry_definition ccaed
+                    JOIN config.coded_value_map ccvm ON (ccaed.coded_value = ccvm.id)
+                    WHERE ccvm.ctype = 'icon_format' AND ccvm.code = format)
+            );
+    END LOOP; 
+END $$;
+
+INSERT INTO config.coded_value_map
+    (id, ctype, code, value, search_label) VALUES 
+(607, 'icon_format', 'music', 
+    oils_i18n_gettext(607, 'Musical Sound Recording (Unknown Format)', 'ccvm', 'value'),
+    oils_i18n_gettext(607, 'Musical Sound Recording (Unknown Format)', 'ccvm', 'search_label'));
+
+INSERT INTO config.composite_attr_entry_definition 
+    (coded_value, definition) VALUES
+(607, '{"0":{"_attr":"item_type","_val":"j"},"1":{"_not":[{"_attr":"sr_format","_val":"a"},{"_attr":"sr_format","_val":"b"},{"_attr":"sr_format","_val":"c"},{"_attr":"sr_format","_val":"d"},{"_attr":"sr_format","_val":"f"},{"_attr":"sr_format","_val":"e"},{"_attr":"sr_format","_val":"l"}]}}');
+
+-- icon for blu-ray
+INSERT INTO config.coded_value_map
+    (id, ctype, code, value, search_label) VALUES 
+(608, 'icon_format', 'blu-ray', 
+    oils_i18n_gettext(608, 'Blu-ray', 'ccvm', 'value'),
+    oils_i18n_gettext(608, 'Blu-ray', 'ccvm', 'search_label'));
+INSERT INTO config.composite_attr_entry_definition 
+    (coded_value, definition) VALUES (608, '{"_attr":"vr_format","_val":"s"}');
+
+-- metarecord hold format for blu-ray
+INSERT INTO config.coded_value_map
+    (id, ctype, code, value, search_label) VALUES 
+(609, 'mr_hold_format', 'blu-ray', 
+    oils_i18n_gettext(609, 'Blu-ray', 'ccvm', 'value'),
+    oils_i18n_gettext(609, 'Blu-ray', 'ccvm', 'search_label'));
+INSERT INTO config.composite_attr_entry_definition 
+    (coded_value, definition) VALUES (609, '{"_attr":"vr_format","_val":"s"}');
+
+
+
+SELECT evergreen.upgrade_deps_block_check('0869', :eg_version);
+
+CREATE OR REPLACE FUNCTION action.hold_copy_calculated_proximity_update () RETURNS TRIGGER AS $f$
+BEGIN
+    NEW.proximity := action.hold_copy_calculated_proximity(NEW.hold,NEW.target_copy);
+    RETURN NEW;
+END;
+$f$ LANGUAGE PLPGSQL;
+
+CREATE TRIGGER hold_copy_proximity_update_tgr BEFORE INSERT OR UPDATE ON action.hold_copy_map FOR EACH ROW EXECUTE PROCEDURE action.hold_copy_calculated_proximity_update ();
+
+-- Now, cause the update we need in a HOT-friendly manner (http://pgsql.tapoueh.org/site/html/misc/hot.html)
+UPDATE action.hold_copy_map SET proximity = proximity WHERE proximity IS NULL;
+
+
+/*
+ * Copyright (C) 2014  Equinox Software, Inc.
+ * Mike Rylander <miker at esilibrary.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+
+
+SELECT evergreen.upgrade_deps_block_check('0870', :eg_version);
+
+CREATE OR REPLACE FUNCTION evergreen.located_uris (
+    bibid BIGINT[],
+    ouid INT,
+    pref_lib INT DEFAULT NULL
+) RETURNS TABLE (id BIGINT, name TEXT, label_sortkey TEXT, rank INT) AS $$
+    WITH all_orgs AS (SELECT COALESCE( enabled, FALSE ) AS flag FROM config.global_flag WHERE name = 'opac.located_uri.act_as_copy')
+    SELECT DISTINCT ON (id) * FROM (
+    SELECT acn.id, COALESCE(aou.name,aoud.name), acn.label_sortkey, evergreen.rank_ou(aou.id, $2, $3) AS pref_ou
+      FROM asset.call_number acn
+           INNER JOIN asset.uri_call_number_map auricnm ON acn.id = auricnm.call_number
+           INNER JOIN asset.uri auri ON auri.id = auricnm.uri
+           LEFT JOIN actor.org_unit_ancestors( COALESCE($3, $2) ) aou ON (acn.owning_lib = aou.id)
+           LEFT JOIN actor.org_unit_descendants( COALESCE($3, $2) ) aoud ON (acn.owning_lib = aoud.id),
+           all_orgs
+      WHERE acn.record = ANY ($1)
+          AND acn.deleted IS FALSE
+          AND auri.active IS TRUE
+          AND ((NOT all_orgs.flag AND aou.id IS NOT NULL) OR (all_orgs.flag AND COALESCE(aou.id,aoud.id) IS NOT NULL))
+    UNION
+    SELECT acn.id, COALESCE(aou.name,aoud.name) AS name, acn.label_sortkey, evergreen.rank_ou(aou.id, $2, $3) AS pref_ou
+      FROM asset.call_number acn
+           INNER JOIN asset.uri_call_number_map auricnm ON acn.id = auricnm.call_number
+           INNER JOIN asset.uri auri ON auri.id = auricnm.uri
+           LEFT JOIN actor.org_unit_ancestors( $2 ) aou ON (acn.owning_lib = aou.id)
+           LEFT JOIN actor.org_unit_descendants( $2 ) aoud ON (acn.owning_lib = aoud.id),
+           all_orgs
+      WHERE acn.record = ANY ($1)
+          AND acn.deleted IS FALSE
+          AND auri.active IS TRUE
+          AND ((NOT all_orgs.flag AND aou.id IS NOT NULL) OR (all_orgs.flag AND COALESCE(aou.id,aoud.id) IS NOT NULL)))x
+    ORDER BY id, pref_ou DESC;
+$$
+LANGUAGE SQL STABLE;
+
+
+
+
+SELECT evergreen.upgrade_deps_block_check('0871', :eg_version);
+
+INSERT INTO config.record_attr_definition 
+    (name, label, multi, filter, composite) VALUES (
+        'search_format', 
+        oils_i18n_gettext('search_format', 'Search Formats', 'crad', 'label'),
+        TRUE, TRUE, TRUE
+    );
+
+INSERT INTO config.coded_value_map
+    (id, ctype, code, value, search_label) VALUES 
+(610, 'search_format', 'book', 
+    oils_i18n_gettext(610, 'All Books', 'ccvm', 'value'),
+    oils_i18n_gettext(610, 'All Books', 'ccvm', 'search_label')),
+(611, 'search_format', 'braille', 
+    oils_i18n_gettext(611, 'Braille', 'ccvm', 'value'),
+    oils_i18n_gettext(611, 'Braille', 'ccvm', 'search_label')),
+(612, 'search_format', 'software', 
+    oils_i18n_gettext(612, 'Software and video games', 'ccvm', 'value'),
+    oils_i18n_gettext(612, 'Software and video games', 'ccvm', 'search_label')),
+(613, 'search_format', 'dvd', 
+    oils_i18n_gettext(613, 'DVD', 'ccvm', 'value'),
+    oils_i18n_gettext(613, 'DVD', 'ccvm', 'search_label')),
+(614, 'search_format', 'ebook', 
+    oils_i18n_gettext(614, 'E-book', 'ccvm', 'value'),
+    oils_i18n_gettext(614, 'E-book', 'ccvm', 'search_label')),
+(615, 'search_format', 'eaudio', 
+    oils_i18n_gettext(615, 'E-audio', 'ccvm', 'value'),
+    oils_i18n_gettext(615, 'E-audio', 'ccvm', 'search_label')),
+(616, 'search_format', 'kit', 
+    oils_i18n_gettext(616, 'Kit', 'ccvm', 'value'),
+    oils_i18n_gettext(616, 'Kit', 'ccvm', 'search_label')),
+(617, 'search_format', 'map', 
+    oils_i18n_gettext(617, 'Map', 'ccvm', 'value'),
+    oils_i18n_gettext(617, 'Map', 'ccvm', 'search_label')),
+(618, 'search_format', 'microform', 
+    oils_i18n_gettext(618, 'Microform', 'ccvm', 'value'),
+    oils_i18n_gettext(618, 'Microform', 'ccvm', 'search_label')),
+(619, 'search_format', 'score', 
+    oils_i18n_gettext(619, 'Music Score', 'ccvm', 'value'),
+    oils_i18n_gettext(619, 'Music Score', 'ccvm', 'search_label')),
+(620, 'search_format', 'picture', 
+    oils_i18n_gettext(620, 'Picture', 'ccvm', 'value'),
+    oils_i18n_gettext(620, 'Picture', 'ccvm', 'search_label')),
+(621, 'search_format', 'equip', 
+    oils_i18n_gettext(621, 'Equipment, games, toys', 'ccvm', 'value'),
+    oils_i18n_gettext(621, 'Equipment, games, toys', 'ccvm', 'search_label')),
+(622, 'search_format', 'serial', 
+    oils_i18n_gettext(622, 'Serials and magazines', 'ccvm', 'value'),
+    oils_i18n_gettext(622, 'Serials and magazines', 'ccvm', 'search_label')),
+(623, 'search_format', 'vhs', 
+    oils_i18n_gettext(623, 'VHS', 'ccvm', 'value'),
+    oils_i18n_gettext(623, 'VHS', 'ccvm', 'search_label')),
+(624, 'search_format', 'evideo', 
+    oils_i18n_gettext(624, 'E-video', 'ccvm', 'value'),
+    oils_i18n_gettext(624, 'E-video', 'ccvm', 'search_label')),
+(625, 'search_format', 'cdaudiobook', 
+    oils_i18n_gettext(625, 'CD Audiobook', 'ccvm', 'value'),
+    oils_i18n_gettext(625, 'CD Audiobook', 'ccvm', 'search_label')),
+(626, 'search_format', 'cdmusic', 
+    oils_i18n_gettext(626, 'CD Music recording', 'ccvm', 'value'),
+    oils_i18n_gettext(626, 'CD Music recording', 'ccvm', 'search_label')),
+(627, 'search_format', 'casaudiobook', 
+    oils_i18n_gettext(627, 'Cassette audiobook', 'ccvm', 'value'),
+    oils_i18n_gettext(627, 'Cassette audiobook', 'ccvm', 'search_label')),
+(628, 'search_format', 'casmusic',
+    oils_i18n_gettext(628, 'Audiocassette music recording', 'ccvm', 'value'),
+    oils_i18n_gettext(628, 'Audiocassette music recording', 'ccvm', 'search_label')),
+(629, 'search_format', 'phonospoken', 
+    oils_i18n_gettext(629, 'Phonograph spoken recording', 'ccvm', 'value'),
+    oils_i18n_gettext(629, 'Phonograph spoken recording', 'ccvm', 'search_label')),
+(630, 'search_format', 'phonomusic', 
+    oils_i18n_gettext(630, 'Phonograph music recording', 'ccvm', 'value'),
+    oils_i18n_gettext(630, 'Phonograph music recording', 'ccvm', 'search_label')),
+(631, 'search_format', 'lpbook', 
+    oils_i18n_gettext(631, 'Large Print Book', 'ccvm', 'value'),
+    oils_i18n_gettext(631, 'Large Print Book', 'ccvm', 'search_label')),
+(632, 'search_format', 'music', 
+    oils_i18n_gettext(632, 'All Music', 'ccvm', 'label'),
+    oils_i18n_gettext(632, 'All Music', 'ccvm', 'search_label')),
+(633, 'search_format', 'blu-ray', 
+    oils_i18n_gettext(633, 'Blu-ray', 'ccvm', 'value'),
+    oils_i18n_gettext(633, 'Blu-ray', 'ccvm', 'search_label'));
+
+
+
+-- copy the composite definition from icon_format into 
+-- search_format for a baseline data set
+DO $$
+    DECLARE format config.coded_value_map%ROWTYPE;
+BEGIN
+    FOR format IN SELECT * 
+        FROM config.coded_value_map WHERE ctype = 'icon_format'
+    LOOP
+        INSERT INTO config.composite_attr_entry_definition 
+            (coded_value, definition) VALUES
+            (
+                -- get the ID from the new ccvm above
+                (SELECT id FROM config.coded_value_map 
+                    WHERE code = format.code AND ctype = 'search_format'),
+
+                -- def of the matching icon_format attr
+                (SELECT definition FROM config.composite_attr_entry_definition 
+                    WHERE coded_value = format.id)
+            );
+    END LOOP; 
+END $$;
+
+-- modify the 'book' definition so that it includes large print
+UPDATE config.composite_attr_entry_definition 
+    SET definition = '{"0":[{"_attr":"item_type","_val":"a"},{"_attr":"item_type","_val":"t"}],"1":{"_not":[{"_attr":"item_form","_val":"a"},{"_attr":"item_form","_val":"b"},{"_attr":"item_form","_val":"c"},{"_attr":"item_form","_val":"f"},{"_attr":"item_form","_val":"o"},{"_attr":"item_form","_val":"q"},{"_attr":"item_form","_val":"r"},{"_attr":"item_form","_val":"s"}]},"2":[{"_attr":"bib_level","_val":"a"},{"_attr":"bib_level","_val":"c"},{"_attr":"bib_level","_val":"d"},{"_attr":"bib_level","_val":"m"}]}'
+    WHERE coded_value = 610;
+
+-- modify 'music' to include all recorded music, regardless of format
+UPDATE config.composite_attr_entry_definition 
+    SET definition = '{"_attr":"item_type","_val":"j"}'
+    WHERE coded_value = 632;
+
+UPDATE config.global_flag 
+    SET value = 'search_format' 
+    WHERE name = 'opac.format_selector.attr';
+
+
+
+SELECT evergreen.upgrade_deps_block_check('0872', :eg_version);
+
+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$
+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
+        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;
+
+            -- 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 = old_mr 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;
+$func$ LANGUAGE PLPGSQL;
+
+DROP FUNCTION metabib.remap_metarecord_for_bib( bib_id BIGINT, fp TEXT );
+
+CREATE OR REPLACE FUNCTION biblio.indexing_ingest_or_delete () RETURNS TRIGGER AS $func$
+DECLARE
+    tmp_bool BOOL;
+BEGIN
+
+    IF NEW.deleted THEN -- If this bib is deleted
+
+        PERFORM * FROM config.internal_flag WHERE
+            name = 'ingest.metarecord_mapping.preserve_on_delete' AND enabled;
+
+        tmp_bool := FOUND; -- Just in case this is changed by some other statement
+
+        PERFORM metabib.remap_metarecord_for_bib( NEW.id, NEW.fingerprint, TRUE, tmp_bool );
+
+        IF NOT tmp_bool THEN
+            -- One needs to keep these around to support searches
+            -- with the #deleted modifier, so one should turn on the named
+            -- internal flag for that functionality.
+            DELETE FROM metabib.record_attr_vector_list WHERE source = NEW.id;
+        END IF;
+
+        DELETE FROM authority.bib_linking WHERE bib = NEW.id; -- Avoid updating fields in bibs that are no longer visible
+        DELETE FROM biblio.peer_bib_copy_map WHERE peer_record = NEW.id; -- Separate any multi-homed items
+        DELETE FROM metabib.browse_entry_def_map WHERE source = NEW.id; -- Don't auto-suggest deleted bibs
+        RETURN NEW; -- and we're done
+    END IF;
+
+    IF TG_OP = 'UPDATE' THEN -- re-ingest?
+        PERFORM * FROM config.internal_flag WHERE name = 'ingest.reingest.force_on_same_marc' AND enabled;
+
+        IF NOT FOUND AND OLD.marc = NEW.marc THEN -- don't do anything if the MARC didn't change
+            RETURN NEW;
+        END IF;
+    END IF;
+
+    -- Record authority linking
+    PERFORM * FROM config.internal_flag WHERE name = 'ingest.disable_authority_linking' AND enabled;
+    IF NOT FOUND THEN
+        PERFORM biblio.map_authority_linking( NEW.id, NEW.marc );
+    END IF;
+
+    -- Flatten and insert the mfr data
+    PERFORM * FROM config.internal_flag WHERE name = 'ingest.disable_metabib_full_rec' AND enabled;
+    IF NOT FOUND THEN
+        PERFORM metabib.reingest_metabib_full_rec(NEW.id);
+
+        -- Now we pull out attribute data, which is dependent on the mfr for all but XPath-based fields
+        PERFORM * FROM config.internal_flag WHERE name = 'ingest.disable_metabib_rec_descriptor' AND enabled;
+        IF NOT FOUND THEN
+            PERFORM metabib.reingest_record_attributes(NEW.id, NULL, NEW.marc, TG_OP = 'INSERT' OR OLD.deleted);
+        END IF;
+    END IF;
+
+    -- Gather and insert the field entry data
+    PERFORM metabib.reingest_metabib_field_entries(NEW.id);
+
+    -- Located URI magic
+    IF TG_OP = 'INSERT' THEN
+        PERFORM * FROM config.internal_flag WHERE name = 'ingest.disable_located_uri' AND enabled;
+        IF NOT FOUND THEN
+            PERFORM biblio.extract_located_uris( NEW.id, NEW.marc, NEW.editor );
+        END IF;
+    ELSE
+        PERFORM * FROM config.internal_flag WHERE name = 'ingest.disable_located_uri' AND enabled;
+        IF NOT FOUND THEN
+            PERFORM biblio.extract_located_uris( NEW.id, NEW.marc, NEW.editor );
+        END IF;
+    END IF;
+
+    -- (re)map metarecord-bib linking
+    IF TG_OP = 'INSERT' THEN -- if not deleted and performing an insert, check for the flag
+        PERFORM * FROM config.internal_flag WHERE name = 'ingest.metarecord_mapping.skip_on_insert' AND enabled;
+        IF NOT FOUND THEN
+            PERFORM metabib.remap_metarecord_for_bib( NEW.id, NEW.fingerprint );
+        END IF;
+    ELSE -- we're doing an update, and we're not deleted, remap
+        PERFORM * FROM config.internal_flag WHERE name = 'ingest.metarecord_mapping.skip_on_update' AND enabled;
+        IF NOT FOUND THEN
+            PERFORM metabib.remap_metarecord_for_bib( NEW.id, NEW.fingerprint );
+        END IF;
+    END IF;
+
+    RETURN NEW;
+END;
+$func$ LANGUAGE PLPGSQL;
+
+CREATE OR REPLACE FUNCTION unapi.mmr (
+    obj_id BIGINT,
+    format TEXT,
+    ename TEXT,
+    includes TEXT[],
+    org TEXT,
+    depth INT DEFAULT NULL,
+    slimit HSTORE DEFAULT NULL,
+    soffset HSTORE DEFAULT NULL,
+    include_xmlns BOOL DEFAULT TRUE,
+    pref_lib INT DEFAULT NULL
+)
+RETURNS XML AS $F$
+DECLARE
+    mmrec   metabib.metarecord%ROWTYPE;
+    leadrec biblio.record_entry%ROWTYPE;
+    subrec biblio.record_entry%ROWTYPE;
+    layout  unapi.bre_output_layout%ROWTYPE;
+    xfrm    config.xml_transform%ROWTYPE;
+    ouid    INT;
+    xml_buf TEXT; -- growing XML document
+    tmp_xml TEXT; -- single-use XML string
+    xml_frag TEXT; -- single-use XML fragment
+    top_el  TEXT;
+    output  XML;
+    hxml    XML;
+    axml    XML;
+    subxml  XML; -- subordinate records elements
+    sub_xpath TEXT; 
+    parts   TEXT[]; 
+BEGIN
+
+    -- xpath for extracting bre.marc values from subordinate records 
+    -- so they may be appended to the MARC of the master record prior
+    -- to XSLT processing.
+    -- subjects, isbn, issn, upc -- anything else?
+    sub_xpath := 
+      '//*[starts-with(@tag, "6") or @tag="020" or @tag="022" or @tag="024"]';
+
+    IF org = '-' OR org IS NULL THEN
+        SELECT shortname INTO org FROM evergreen.org_top();
+    END IF;
+
+    SELECT id INTO ouid FROM actor.org_unit WHERE shortname = org;
+
+    IF ouid IS NULL THEN
+        RETURN NULL::XML;
+    END IF;
+
+    SELECT INTO mmrec * FROM metabib.metarecord WHERE id = obj_id;
+    IF NOT FOUND THEN
+        RETURN NULL::XML;
+    END IF;
+
+    -- TODO: aggregate holdings from constituent records
+    IF format = 'holdings_xml' THEN -- the special case
+        output := unapi.mmr_holdings_xml(
+            obj_id, ouid, org, depth,
+            evergreen.array_remove_item_by_value(includes,'holdings_xml'),
+            slimit, soffset, include_xmlns, pref_lib);
+        RETURN output;
+    END IF;
+
+    SELECT * INTO layout FROM unapi.bre_output_layout WHERE name = format;
+
+    IF layout.name IS NULL THEN
+        RETURN NULL::XML;
+    END IF;
+
+    SELECT * INTO xfrm FROM config.xml_transform WHERE name = layout.transform;
+
+    SELECT INTO leadrec * FROM biblio.record_entry WHERE id = mmrec.master_record;
+
+    -- Grab distinct MVF for all records if requested
+    IF ('mra' = ANY (includes)) THEN 
+        axml := unapi.mmr_mra(obj_id,NULL,NULL,NULL,org,depth,NULL,NULL,TRUE,pref_lib);
+    ELSE
+        axml := NULL::XML;
+    END IF;
+
+    xml_buf = leadrec.marc;
+
+    hxml := NULL::XML;
+    IF ('holdings_xml' = ANY (includes)) THEN
+        hxml := unapi.mmr_holdings_xml(
+                    obj_id, ouid, org, depth,
+                    evergreen.array_remove_item_by_value(includes,'holdings_xml'),
+                    slimit, soffset, include_xmlns, pref_lib);
+    END IF;
+
+    subxml := NULL::XML;
+    parts := '{}'::TEXT[];
+    FOR subrec IN SELECT bre.* FROM biblio.record_entry bre
+         JOIN metabib.metarecord_source_map mmsm ON (mmsm.source = bre.id)
+         JOIN metabib.metarecord mmr ON (mmr.id = mmsm.metarecord)
+         WHERE mmr.id = obj_id AND NOT bre.deleted
+         ORDER BY CASE WHEN bre.id = mmr.master_record THEN 0 ELSE bre.id END
+         LIMIT COALESCE((slimit->'bre')::INT, 5) LOOP
+
+        IF subrec.id = leadrec.id THEN CONTINUE; END IF;
+        -- Append choice data from the the non-lead records to the 
+        -- the lead record document
+
+        parts := parts || xpath(sub_xpath, subrec.marc::XML)::TEXT[];
+    END LOOP;
+
+    SELECT ARRAY_TO_STRING( ARRAY_AGG( DISTINCT p ), '' )::XML INTO subxml FROM UNNEST(parts) p;
+
+    -- append data from the subordinate records to the 
+    -- main record document before applying the XSLT
+
+    IF subxml IS NOT NULL THEN 
+        xml_buf := REGEXP_REPLACE(xml_buf, 
+            '</record>(.*?)$', subxml || '</record>' || E'\\1');
+    END IF;
+
+    IF format = 'marcxml' THEN
+         -- If we're not using the prefixed namespace in 
+         -- this record, then remove all declarations of it
+        IF xml_buf !~ E'<marc:' THEN
+           xml_buf := REGEXP_REPLACE(xml_buf, 
+            ' xmlns:marc="http://www.loc.gov/MARC21/slim"', '', 'g');
+        END IF; 
+    ELSE
+        xml_buf := oils_xslt_process(xml_buf, xfrm.xslt)::XML;
+    END IF;
+
+    -- update top_el to reflect the change in xml_buf, which may
+    -- now be a different type of document (e.g. record -> mods)
+    top_el := REGEXP_REPLACE(xml_buf, E'^.*?<((?:\\S+:)?' || 
+        layout.holdings_element || ').*$', E'\\1');
+
+    IF axml IS NOT NULL THEN 
+        xml_buf := REGEXP_REPLACE(xml_buf, 
+            '</' || top_el || '>(.*?)$', axml || '</' || top_el || E'>\\1');
+    END IF;
+
+    IF hxml IS NOT NULL THEN
+        xml_buf := REGEXP_REPLACE(xml_buf, 
+            '</' || top_el || '>(.*?)$', hxml || '</' || top_el || E'>\\1');
+    END IF;
+
+    IF ('mmr.unapi' = ANY (includes)) THEN 
+        output := REGEXP_REPLACE(
+            xml_buf,
+            '</' || top_el || '>(.*?)',
+            XMLELEMENT(
+                name abbr,
+                XMLATTRIBUTES(
+                    'http://www.w3.org/1999/xhtml' AS xmlns,
+                    'unapi-id' AS class,
+                    'tag:open-ils.org:U2 at mmr/' || obj_id || '/' || org AS title
+                )
+            )::TEXT || '</' || top_el || E'>\\1'
+        );
+    ELSE
+        output := xml_buf;
+    END IF;
+
+    -- remove ignorable whitesace
+    output := REGEXP_REPLACE(output::TEXT,E'>\\s+<','><','gs')::XML;
+    RETURN output;
+END;
+$F$ LANGUAGE PLPGSQL STABLE;
+
+-- Forcibly remap deleted master records, retaining the linkage if so configured.
+SELECT  count(metabib.remap_metarecord_for_bib( bre.id, bre.fingerprint, TRUE, COALESCE(flag.enabled,FALSE)))
+  FROM  metabib.metarecord metar
+        JOIN biblio.record_entry bre ON bre.id = metar.master_record,
+        config.internal_flag flag
+  WHERE bre.deleted = TRUE AND flag.name = 'ingest.metarecord_mapping.preserve_on_delete';
+
+
+
+SELECT evergreen.upgrade_deps_block_check('0873', :eg_version);
+
+CREATE OR REPLACE FUNCTION action.find_hold_matrix_matchpoint(pickup_ou integer, request_ou integer, match_item bigint, match_user integer, match_requestor integer)
+  RETURNS integer AS
+$func$
+DECLARE
+    requestor_object    actor.usr%ROWTYPE;
+    user_object         actor.usr%ROWTYPE;
+    item_object         asset.copy%ROWTYPE;
+    item_cn_object      asset.call_number%ROWTYPE;
+    my_item_age         INTERVAL;
+    rec_descriptor      metabib.rec_descriptor%ROWTYPE;
+    matchpoint          config.hold_matrix_matchpoint%ROWTYPE;
+    weights             config.hold_matrix_weights%ROWTYPE;
+    denominator         NUMERIC(6,2);
+    v_pickup_ou         ALIAS FOR pickup_ou;
+    v_request_ou         ALIAS FOR request_ou;
+BEGIN
+    SELECT INTO user_object         * FROM actor.usr                WHERE id = match_user;
+    SELECT INTO requestor_object    * FROM actor.usr                WHERE id = match_requestor;
+    SELECT INTO item_object         * FROM asset.copy               WHERE id = match_item;
+    SELECT INTO item_cn_object      * FROM asset.call_number        WHERE id = item_object.call_number;
+    SELECT INTO rec_descriptor      * FROM metabib.rec_descriptor   WHERE record = item_cn_object.record;
+
+    SELECT INTO my_item_age age(coalesce(item_object.active_date, now()));
+
+    -- The item's owner should probably be the one determining if the item is holdable
+    -- How to decide that is debatable. Decided to default to the circ library (where the item lives)
+    -- This flag will allow for setting it to the owning library (where the call number "lives")
+    PERFORM * FROM config.internal_flag WHERE name = 'circ.holds.weight_owner_not_circ' AND enabled;
+
+    -- Grab the closest set circ weight setting.
+    IF NOT FOUND THEN
+        -- Default to circ library
+        SELECT INTO weights hw.*
+          FROM config.weight_assoc wa
+               JOIN config.hold_matrix_weights hw ON (hw.id = wa.hold_weights)
+               JOIN actor.org_unit_ancestors_distance( item_object.circ_lib ) d ON (wa.org_unit = d.id)
+          WHERE active
+          ORDER BY d.distance
+          LIMIT 1;
+    ELSE
+        -- Flag is set, use owning library
+        SELECT INTO weights hw.*
+          FROM config.weight_assoc wa
+               JOIN config.hold_matrix_weights hw ON (hw.id = wa.hold_weights)
+               JOIN actor.org_unit_ancestors_distance( item_cn_object.owning_lib ) d ON (wa.org_unit = d.id)
+          WHERE active
+          ORDER BY d.distance
+          LIMIT 1;
+    END IF;
+
+    -- No weights? Bad admin! Defaults to handle that anyway.
+    IF weights.id IS NULL THEN
+        weights.user_home_ou    := 5.0;
+        weights.request_ou      := 5.0;
+        weights.pickup_ou       := 5.0;
+        weights.item_owning_ou  := 5.0;
+        weights.item_circ_ou    := 5.0;
+        weights.usr_grp         := 7.0;
+        weights.requestor_grp   := 8.0;
+        weights.circ_modifier   := 4.0;
+        weights.marc_type       := 3.0;
+        weights.marc_form       := 2.0;
+        weights.marc_bib_level  := 1.0;
+        weights.marc_vr_format  := 1.0;
+        weights.juvenile_flag   := 4.0;
+        weights.ref_flag        := 0.0;
+        weights.item_age        := 0.0;
+    END IF;
+
+    -- Determine the max (expected) depth (+1) of the org tree and max depth of the permisson tree
+    -- If you break your org tree with funky parenting this may be wrong
+    -- Note: This CTE is duplicated in the find_circ_matrix_matchpoint function, and it may be a good idea to split it off to a function
+    -- We use one denominator for all tree-based checks for when permission groups and org units have the same weighting
+    WITH all_distance(distance) AS (
+            SELECT depth AS distance FROM actor.org_unit_type
+        UNION
+            SELECT distance AS distance FROM permission.grp_ancestors_distance((SELECT id FROM permission.grp_tree WHERE parent IS NULL))
+	)
+    SELECT INTO denominator MAX(distance) + 1 FROM all_distance;
+
+    -- To ATTEMPT to make this work like it used to, make it reverse the user/requestor profile ids.
+    -- This may be better implemented as part of the upgrade script?
+    -- Set usr_grp = requestor_grp, requestor_grp = 1 or something when this flag is already set
+    -- Then remove this flag, of course.
+    PERFORM * FROM config.internal_flag WHERE name = 'circ.holds.usr_not_requestor' AND enabled;
+
+    IF FOUND THEN
+        -- Note: This, to me, is REALLY hacky. I put it in anyway.
+        -- If you can't tell, this is a single call swap on two variables.
+        SELECT INTO user_object.profile, requestor_object.profile
+                    requestor_object.profile, user_object.profile;
+    END IF;
+
+    -- Select the winning matchpoint into the matchpoint variable for returning
+    SELECT INTO matchpoint m.*
+      FROM  config.hold_matrix_matchpoint m
+            /*LEFT*/ JOIN permission.grp_ancestors_distance( requestor_object.profile ) rpgad ON m.requestor_grp = rpgad.id
+            LEFT JOIN permission.grp_ancestors_distance( user_object.profile ) upgad ON m.usr_grp = upgad.id
+            LEFT JOIN actor.org_unit_ancestors_distance( v_pickup_ou ) puoua ON m.pickup_ou = puoua.id
+            LEFT JOIN actor.org_unit_ancestors_distance( v_request_ou ) rqoua ON m.request_ou = rqoua.id
+            LEFT JOIN actor.org_unit_ancestors_distance( item_cn_object.owning_lib ) cnoua ON m.item_owning_ou = cnoua.id
+            LEFT JOIN actor.org_unit_ancestors_distance( item_object.circ_lib ) iooua ON m.item_circ_ou = iooua.id
+            LEFT JOIN actor.org_unit_ancestors_distance( user_object.home_ou  ) uhoua ON m.user_home_ou = uhoua.id
+      WHERE m.active
+            -- Permission Groups
+         -- AND (m.requestor_grp        IS NULL OR upgad.id IS NOT NULL) -- Optional Requestor Group?
+            AND (m.usr_grp              IS NULL OR upgad.id IS NOT NULL)
+            -- Org Units
+            AND (m.pickup_ou            IS NULL OR (puoua.id IS NOT NULL AND (puoua.distance = 0 OR NOT m.strict_ou_match)))
+            AND (m.request_ou           IS NULL OR (rqoua.id IS NOT NULL AND (rqoua.distance = 0 OR NOT m.strict_ou_match)))
+            AND (m.item_owning_ou       IS NULL OR (cnoua.id IS NOT NULL AND (cnoua.distance = 0 OR NOT m.strict_ou_match)))
+            AND (m.item_circ_ou         IS NULL OR (iooua.id IS NOT NULL AND (iooua.distance = 0 OR NOT m.strict_ou_match)))
+            AND (m.user_home_ou         IS NULL OR (uhoua.id IS NOT NULL AND (uhoua.distance = 0 OR NOT m.strict_ou_match)))
+            -- Static User Checks
+            AND (m.juvenile_flag        IS NULL OR m.juvenile_flag = user_object.juvenile)
+            -- Static Item Checks
+            AND (m.circ_modifier        IS NULL OR m.circ_modifier = item_object.circ_modifier)
+            AND (m.marc_type            IS NULL OR m.marc_type = COALESCE(item_object.circ_as_type, rec_descriptor.item_type))
+            AND (m.marc_form            IS NULL OR m.marc_form = rec_descriptor.item_form)
+            AND (m.marc_bib_level       IS NULL OR m.marc_bib_level = rec_descriptor.bib_level)
+            AND (m.marc_vr_format       IS NULL OR m.marc_vr_format = rec_descriptor.vr_format)
+            AND (m.ref_flag             IS NULL OR m.ref_flag = item_object.ref)
+            AND (m.item_age             IS NULL OR (my_item_age IS NOT NULL AND m.item_age > my_item_age))
+      ORDER BY
+            -- Permission Groups
+            CASE WHEN rpgad.distance    IS NOT NULL THEN 2^(2*weights.requestor_grp - (rpgad.distance/denominator)) ELSE 0.0 END +
+            CASE WHEN upgad.distance    IS NOT NULL THEN 2^(2*weights.usr_grp - (upgad.distance/denominator)) ELSE 0.0 END +
+            -- Org Units
+            CASE WHEN puoua.distance    IS NOT NULL THEN 2^(2*weights.pickup_ou - (puoua.distance/denominator)) ELSE 0.0 END +
+            CASE WHEN rqoua.distance    IS NOT NULL THEN 2^(2*weights.request_ou - (rqoua.distance/denominator)) ELSE 0.0 END +
+            CASE WHEN cnoua.distance    IS NOT NULL THEN 2^(2*weights.item_owning_ou - (cnoua.distance/denominator)) ELSE 0.0 END +
+            CASE WHEN iooua.distance    IS NOT NULL THEN 2^(2*weights.item_circ_ou - (iooua.distance/denominator)) ELSE 0.0 END +
+            CASE WHEN uhoua.distance    IS NOT NULL THEN 2^(2*weights.user_home_ou - (uhoua.distance/denominator)) ELSE 0.0 END +
+            -- Static User Checks       -- Note: 4^x is equiv to 2^(2*x)
+            CASE WHEN m.juvenile_flag   IS NOT NULL THEN 4^weights.juvenile_flag ELSE 0.0 END +
+            -- Static Item Checks
+            CASE WHEN m.circ_modifier   IS NOT NULL THEN 4^weights.circ_modifier ELSE 0.0 END +
+            CASE WHEN m.marc_type       IS NOT NULL THEN 4^weights.marc_type ELSE 0.0 END +
+            CASE WHEN m.marc_form       IS NOT NULL THEN 4^weights.marc_form ELSE 0.0 END +
+            CASE WHEN m.marc_vr_format  IS NOT NULL THEN 4^weights.marc_vr_format ELSE 0.0 END +
+            CASE WHEN m.ref_flag        IS NOT NULL THEN 4^weights.ref_flag ELSE 0.0 END +
+            -- Item age has a slight adjustment to weight based on value.
+            -- This should ensure that a shorter age limit comes first when all else is equal.
+            -- NOTE: This assumes that intervals will normally be in days.
+            CASE WHEN m.item_age            IS NOT NULL THEN 4^weights.item_age - 86400/EXTRACT(EPOCH FROM m.item_age) ELSE 0.0 END DESC,
+            -- Final sort on id, so that if two rules have the same sorting in the previous sort they have a defined order
+            -- This prevents "we changed the table order by updating a rule, and we started getting different results"
+            m.id;
+
+    -- Return just the ID for now
+    RETURN matchpoint.id;
+END;
+$func$ LANGUAGE 'plpgsql';
+
+CREATE OR REPLACE FUNCTION action.hold_request_permit_test( pickup_ou INT, request_ou INT, match_item BIGINT, match_user INT, match_requestor INT, retargetting BOOL ) RETURNS SETOF action.matrix_test_result AS $func$
+DECLARE
+    matchpoint_id        INT;
+    user_object        actor.usr%ROWTYPE;
+    age_protect_object    config.rule_age_hold_protect%ROWTYPE;
+    standing_penalty    config.standing_penalty%ROWTYPE;
+    transit_range_ou_type    actor.org_unit_type%ROWTYPE;
+    transit_source        actor.org_unit%ROWTYPE;
+    item_object        asset.copy%ROWTYPE;
+    item_cn_object     asset.call_number%ROWTYPE;
+    item_status_object  config.copy_status%ROWTYPE;
+    item_location_object    asset.copy_location%ROWTYPE;
+    ou_skip              actor.org_unit_setting%ROWTYPE;
+    result            action.matrix_test_result;
+    hold_test        config.hold_matrix_matchpoint%ROWTYPE;
+    use_active_date   TEXT;
+    age_protect_date  TIMESTAMP WITH TIME ZONE;
+    hold_count        INT;
+    hold_transit_prox    INT;
+    frozen_hold_count    INT;
+    context_org_list    INT[];
+    done            BOOL := FALSE;
+    hold_penalty TEXT;
+    v_pickup_ou ALIAS FOR pickup_ou;
+    v_request_ou ALIAS FOR request_ou;
+BEGIN
+    SELECT INTO user_object * FROM actor.usr WHERE id = match_user;
+    SELECT INTO context_org_list ARRAY_AGG(id) FROM actor.org_unit_full_path( v_pickup_ou );
+
+    result.success := TRUE;
+
+    -- The HOLD penalty block only applies to new holds.
+    -- The CAPTURE penalty block applies to existing holds.
+    hold_penalty := 'HOLD';
+    IF retargetting THEN
+        hold_penalty := 'CAPTURE';
+    END IF;
+
+    -- Fail if we couldn't find a user
+    IF user_object.id IS NULL THEN
+        result.fail_part := 'no_user';
+        result.success := FALSE;
+        done := TRUE;
+        RETURN NEXT result;
+        RETURN;
+    END IF;
+
+    SELECT INTO item_object * FROM asset.copy WHERE id = match_item;
+
+    -- Fail if we couldn't find a copy
+    IF item_object.id IS NULL THEN
+        result.fail_part := 'no_item';
+        result.success := FALSE;
+        done := TRUE;
+        RETURN NEXT result;
+        RETURN;
+    END IF;
+
+    SELECT INTO matchpoint_id action.find_hold_matrix_matchpoint(v_pickup_ou, v_request_ou, match_item, match_user, match_requestor);
+    result.matchpoint := matchpoint_id;
+
+    SELECT INTO ou_skip * FROM actor.org_unit_setting WHERE name = 'circ.holds.target_skip_me' AND org_unit = item_object.circ_lib;
+
+    -- Fail if the circ_lib for the item has circ.holds.target_skip_me set to true
+    IF ou_skip.id IS NOT NULL AND ou_skip.value = 'true' THEN
+        result.fail_part := 'circ.holds.target_skip_me';
+        result.success := FALSE;
+        done := TRUE;
+        RETURN NEXT result;
+        RETURN;
+    END IF;
+
+    -- Fail if user is barred
+    IF user_object.barred IS TRUE THEN
+        result.fail_part := 'actor.usr.barred';
+        result.success := FALSE;
+        done := TRUE;
+        RETURN NEXT result;
+        RETURN;
+    END IF;
+
+    SELECT INTO item_cn_object * FROM asset.call_number WHERE id = item_object.call_number;
+    SELECT INTO item_status_object * FROM config.copy_status WHERE id = item_object.status;
+    SELECT INTO item_location_object * FROM asset.copy_location WHERE id = item_object.location;
+
+    -- Fail if we couldn't find any matchpoint (requires a default)
+    IF matchpoint_id IS NULL THEN
+        result.fail_part := 'no_matchpoint';
+        result.success := FALSE;
+        done := TRUE;
+        RETURN NEXT result;
+        RETURN;
+    END IF;
+
+    SELECT INTO hold_test * FROM config.hold_matrix_matchpoint WHERE id = matchpoint_id;
+
+    IF hold_test.holdable IS FALSE THEN
+        result.fail_part := 'config.hold_matrix_test.holdable';
+        result.success := FALSE;
+        done := TRUE;
+        RETURN NEXT result;
+    END IF;
+
+    IF item_object.holdable IS FALSE THEN
+        result.fail_part := 'item.holdable';
+        result.success := FALSE;
+        done := TRUE;
+        RETURN NEXT result;
+    END IF;
+
+    IF item_status_object.holdable IS FALSE THEN
+        result.fail_part := 'status.holdable';
+        result.success := FALSE;
+        done := TRUE;
+        RETURN NEXT result;
+    END IF;
+
+    IF item_location_object.holdable IS FALSE THEN
+        result.fail_part := 'location.holdable';
+        result.success := FALSE;
+        done := TRUE;
+        RETURN NEXT result;
+    END IF;
+
+    IF hold_test.transit_range IS NOT NULL THEN
+        SELECT INTO transit_range_ou_type * FROM actor.org_unit_type WHERE id = hold_test.transit_range;
+        IF hold_test.distance_is_from_owner THEN
+            SELECT INTO transit_source ou.* FROM actor.org_unit ou JOIN asset.call_number cn ON (cn.owning_lib = ou.id) WHERE cn.id = item_object.call_number;
+        ELSE
+            SELECT INTO transit_source * FROM actor.org_unit WHERE id = item_object.circ_lib;
+        END IF;
+
+        PERFORM * FROM actor.org_unit_descendants( transit_source.id, transit_range_ou_type.depth ) WHERE id = v_pickup_ou;
+
+        IF NOT FOUND THEN
+            result.fail_part := 'transit_range';
+            result.success := FALSE;
+            done := TRUE;
+            RETURN NEXT result;
+        END IF;
+    END IF;
+ 
+    FOR standing_penalty IN
+        SELECT  DISTINCT csp.*
+          FROM  actor.usr_standing_penalty usp
+                JOIN config.standing_penalty csp ON (csp.id = usp.standing_penalty)
+          WHERE usr = match_user
+                AND usp.org_unit IN ( SELECT * FROM unnest(context_org_list) )
+                AND (usp.stop_date IS NULL or usp.stop_date > NOW())
+                AND csp.block_list LIKE '%' || hold_penalty || '%' LOOP
+
+        result.fail_part := standing_penalty.name;
+        result.success := FALSE;
+        done := TRUE;
+        RETURN NEXT result;
+    END LOOP;
+
+    IF hold_test.stop_blocked_user IS TRUE THEN
+        FOR standing_penalty IN
+            SELECT  DISTINCT csp.*
+              FROM  actor.usr_standing_penalty usp
+                    JOIN config.standing_penalty csp ON (csp.id = usp.standing_penalty)
+              WHERE usr = match_user
+                    AND usp.org_unit IN ( SELECT * FROM unnest(context_org_list) )
+                    AND (usp.stop_date IS NULL or usp.stop_date > NOW())
+                    AND csp.block_list LIKE '%CIRC%' LOOP
+    
+            result.fail_part := standing_penalty.name;
+            result.success := FALSE;
+            done := TRUE;
+            RETURN NEXT result;
+        END LOOP;
+    END IF;
+
+    IF hold_test.max_holds IS NOT NULL AND NOT retargetting THEN
+        SELECT    INTO hold_count COUNT(*)
+          FROM    action.hold_request
+          WHERE    usr = match_user
+            AND fulfillment_time IS NULL
+            AND cancel_time IS NULL
+            AND CASE WHEN hold_test.include_frozen_holds THEN TRUE ELSE frozen IS FALSE END;
+
+        IF hold_count >= hold_test.max_holds THEN
+            result.fail_part := 'config.hold_matrix_test.max_holds';
+            result.success := FALSE;
+            done := TRUE;
+            RETURN NEXT result;
+        END IF;
+    END IF;
+
+    IF item_object.age_protect IS NOT NULL THEN
+        SELECT INTO age_protect_object * FROM config.rule_age_hold_protect WHERE id = item_object.age_protect;
+        IF hold_test.distance_is_from_owner THEN
+            SELECT INTO use_active_date value FROM actor.org_unit_ancestor_setting('circ.holds.age_protect.active_date', item_cn_object.owning_lib);
+        ELSE
+            SELECT INTO use_active_date value FROM actor.org_unit_ancestor_setting('circ.holds.age_protect.active_date', item_object.circ_lib);
+        END IF;
+        IF use_active_date = 'true' THEN
+            age_protect_date := COALESCE(item_object.active_date, NOW());
+        ELSE
+            age_protect_date := item_object.create_date;
+        END IF;
+        IF age_protect_date + age_protect_object.age > NOW() THEN
+            IF hold_test.distance_is_from_owner THEN
+                SELECT INTO item_cn_object * FROM asset.call_number WHERE id = item_object.call_number;
+                SELECT INTO hold_transit_prox prox FROM actor.org_unit_proximity WHERE from_org = item_cn_object.owning_lib AND to_org = v_pickup_ou;
+            ELSE
+                SELECT INTO hold_transit_prox prox FROM actor.org_unit_proximity WHERE from_org = item_object.circ_lib AND to_org = v_pickup_ou;
+            END IF;
+
+            IF hold_transit_prox > age_protect_object.prox THEN
+                result.fail_part := 'config.rule_age_hold_protect.prox';
+                result.success := FALSE;
+                done := TRUE;
+                RETURN NEXT result;
+            END IF;
+        END IF;
+    END IF;
+
+    IF NOT done THEN
+        RETURN NEXT result;
+    END IF;
+
+    RETURN;
+END;
+$func$ LANGUAGE plpgsql;
+
+
+
+SELECT evergreen.upgrade_deps_block_check('0874', :eg_version);
+
+DROP FUNCTION IF EXISTS evergreen.oils_xpath( TEXT, TEXT, ANYARRAY);
+DROP FUNCTION IF EXISTS public.oils_xpath(TEXT, TEXT, ANYARRAY);
+DROP FUNCTION IF EXISTS public.oils_xpath(TEXT, TEXT);
+DROP FUNCTION IF EXISTS public.oils_xslt_process(TEXT, TEXT);
+
+CREATE OR REPLACE FUNCTION evergreen.xml_famous5_to_text( TEXT ) RETURNS TEXT AS $f$
+ SELECT REPLACE(
+            REPLACE(
+                REPLACE(
+                    REPLACE(
+                        REPLACE( $1, '&lt;', '<'),
+                        '&gt;',
+                        '>'
+                    ),
+                    '&apos;',
+                    $$'$$
+                ), -- ' ... vim
+                '&quot;',
+                '"'
+            ),
+            '&amp;',
+            '&'
+        );
+$f$ LANGUAGE SQL IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION evergreen.oils_xpath ( TEXT, TEXT, TEXT[] ) RETURNS TEXT[] AS $f$
+    SELECT  ARRAY_AGG(
+                CASE WHEN strpos(x,'<') = 1 THEN -- It's an element node
+                    x
+                ELSE -- it's text-ish
+                    evergreen.xml_famous5_to_text(x)
+                END
+            )
+      FROM  UNNEST(XPATH( $1, $2::XML, $3 )::TEXT[]) x;
+$f$ LANGUAGE SQL IMMUTABLE;
+
+-- Trust me, it's just simpler to duplicate these...
+CREATE OR REPLACE FUNCTION evergreen.oils_xpath ( TEXT, TEXT ) RETURNS TEXT[] AS $f$
+    SELECT  ARRAY_AGG(
+                CASE WHEN strpos(x,'<') = 1 THEN -- It's an element node
+                    x
+                ELSE -- it's text-ish
+                    evergreen.xml_famous5_to_text(x)
+                END
+            )
+      FROM  UNNEST(XPATH( $1, $2::XML)::TEXT[]) x;
+$f$ LANGUAGE SQL IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION evergreen.oils_xslt_process(TEXT, TEXT) RETURNS TEXT AS $func$
+  use strict;
+
+  use XML::LibXSLT;
+  use XML::LibXML;
+
+  my $doc = shift;
+  my $xslt = shift;
+
+  # The following approach uses the older XML::LibXML 1.69 / XML::LibXSLT 1.68
+  # methods of parsing XML documents and stylesheets, in the hopes of broader
+  # compatibility with distributions
+  my $parser = $_SHARED{'_xslt_process'}{parsers}{xml} || XML::LibXML->new();
+
+  # Cache the XML parser, if we do not already have one
+  $_SHARED{'_xslt_process'}{parsers}{xml} = $parser
+    unless ($_SHARED{'_xslt_process'}{parsers}{xml});
+
+  my $xslt_parser = $_SHARED{'_xslt_process'}{parsers}{xslt} || XML::LibXSLT->new();
+
+  # Cache the XSLT processor, if we do not already have one
+  $_SHARED{'_xslt_process'}{parsers}{xslt} = $xslt_parser
+    unless ($_SHARED{'_xslt_process'}{parsers}{xslt});
+
+  my $stylesheet = $_SHARED{'_xslt_process'}{stylesheets}{$xslt} ||
+    $xslt_parser->parse_stylesheet( $parser->parse_string($xslt) );
+
+  $_SHARED{'_xslt_process'}{stylesheets}{$xslt} = $stylesheet
+    unless ($_SHARED{'_xslt_process'}{stylesheets}{$xslt});
+
+  return $stylesheet->output_string(
+    $stylesheet->transform(
+      $parser->parse_string($doc)
+    )
+  );
+
+$func$ LANGUAGE 'plperlu' STRICT IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION authority.simple_heading_set( marcxml TEXT ) RETURNS SETOF authority.simple_heading AS $func$
+DECLARE
+    res             authority.simple_heading%ROWTYPE;
+    acsaf           authority.control_set_authority_field%ROWTYPE;
+    tag_used        TEXT;
+    nfi_used        TEXT;
+    sf              TEXT;
+    cset            INT;
+    heading_text    TEXT;
+    joiner_text     TEXT;
+    sort_text       TEXT;
+    tmp_text        TEXT;
+    tmp_xml         TEXT;
+    first_sf        BOOL;
+    auth_id         INT DEFAULT COALESCE(NULLIF(oils_xpath_string('//*[@tag="901"]/*[local-name()="subfield" and @code="c"]', marcxml), ''), '0')::INT; 
+BEGIN
+
+    SELECT control_set INTO cset FROM authority.record_entry WHERE id = auth_id;
+
+    IF cset IS NULL THEN
+        SELECT  control_set INTO cset
+          FROM  authority.control_set_authority_field
+          WHERE tag IN ( SELECT  UNNEST(XPATH('//*[starts-with(@tag,"1")]/@tag',marcxml::XML)::TEXT[]))
+          LIMIT 1;
+    END IF;
+
+    res.record := auth_id;
+
+    FOR acsaf IN SELECT * FROM authority.control_set_authority_field WHERE control_set = cset LOOP
+
+        res.atag := acsaf.id;
+        tag_used := acsaf.tag;
+        nfi_used := acsaf.nfi;
+        joiner_text := COALESCE(acsaf.joiner, ' ');
+
+        FOR tmp_xml IN SELECT UNNEST(XPATH('//*[@tag="'||tag_used||'"]', marcxml::XML)::TEXT[]) LOOP
+
+            heading_text := COALESCE(
+                oils_xpath_string('./*[contains("'||acsaf.display_sf_list||'", at code)]', tmp_xml, joiner_text),
+                ''
+            );
+
+            IF nfi_used IS NOT NULL THEN
+
+                sort_text := SUBSTRING(
+                    heading_text FROM
+                    COALESCE(
+                        NULLIF(
+                            REGEXP_REPLACE(
+                                oils_xpath_string('./@ind'||nfi_used, tmp_xml::TEXT),
+                                $$\D+$$,
+                                '',
+                                'g'
+                            ),
+                            ''
+                        )::INT,
+                        0
+                    ) + 1
+                );
+
+            ELSE
+                sort_text := heading_text;
+            END IF;
+
+            IF heading_text IS NOT NULL AND heading_text <> '' THEN
+                res.value := heading_text;
+                res.sort_value := public.naco_normalize(sort_text);
+                res.index_vector = to_tsvector('keyword'::regconfig, res.sort_value);
+                RETURN NEXT res;
+            END IF;
+
+        END LOOP;
+
+    END LOOP;
+
+    RETURN;
+END;
+$func$ LANGUAGE PLPGSQL IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION url_verify.extract_urls ( session_id INT, item_id INT ) RETURNS INT AS $$
+DECLARE
+    last_seen_tag TEXT;
+    current_tag TEXT;
+    current_sf TEXT;
+    current_url TEXT;
+    current_ord INT;
+    current_url_pos INT;
+    current_selector url_verify.url_selector%ROWTYPE;
+BEGIN
+    current_ord := 1;
+
+    FOR current_selector IN SELECT * FROM url_verify.url_selector s WHERE s.session = session_id LOOP
+        current_url_pos := 1;
+        LOOP
+            SELECT  (oils_xpath(current_selector.xpath || '/text()', b.marc))[current_url_pos] INTO current_url
+              FROM  biblio.record_entry b
+                    JOIN container.biblio_record_entry_bucket_item c ON (c.target_biblio_record_entry = b.id)
+              WHERE c.id = item_id;
+
+            EXIT WHEN current_url IS NULL;
+
+            SELECT  (oils_xpath(current_selector.xpath || '/../@tag', b.marc))[current_url_pos] INTO current_tag
+              FROM  biblio.record_entry b
+                    JOIN container.biblio_record_entry_bucket_item c ON (c.target_biblio_record_entry = b.id)
+              WHERE c.id = item_id;
+
+            IF current_tag IS NULL THEN
+                current_tag := last_seen_tag;
+            ELSE
+                last_seen_tag := current_tag;
+            END IF;
+
+            SELECT  (oils_xpath(current_selector.xpath || '/@code', b.marc))[current_url_pos] INTO current_sf
+              FROM  biblio.record_entry b
+                    JOIN container.biblio_record_entry_bucket_item c ON (c.target_biblio_record_entry = b.id)
+              WHERE c.id = item_id;
+
+            INSERT INTO url_verify.url (session, item, url_selector, tag, subfield, ord, full_url)
+              VALUES ( session_id, item_id, current_selector.id, current_tag, current_sf, current_ord, current_url);
+
+            current_url_pos := current_url_pos + 1;
+            current_ord := current_ord + 1;
+        END LOOP;
+    END LOOP;
+
+    RETURN current_ord - 1;
+END;
+$$ LANGUAGE PLPGSQL;
+
+CREATE OR REPLACE FUNCTION biblio.extract_metabib_field_entry ( rid BIGINT, default_joiner TEXT ) 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;
+    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;
+BEGIN
+
+    -- Start out with no field-use bools set
+    output_row.browse_field = FALSE;
+    output_row.facet_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 ORDER BY format LOOP
+
+        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;
+
+        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.reingest_record_attributes (rid BIGINT, pattr_list TEXT[] DEFAULT NULL, prmarc TEXT DEFAULT NULL, rdeleted BOOL DEFAULT TRUE) RETURNS VOID AS $func$
+DECLARE
+    transformed_xml TEXT;
+    rmarc           TEXT := prmarc;
+    tmp_val         TEXT;
+    prev_xfrm       TEXT;
+    normalizer      RECORD;
+    xfrm            config.xml_transform%ROWTYPE;
+    attr_vector     INT[] := '{}'::INT[];
+    attr_vector_tmp INT[];
+    attr_list       TEXT[] := pattr_list;
+    attr_value      TEXT[];
+    norm_attr_value TEXT[];
+    tmp_xml         TEXT;
+    attr_def        config.record_attr_definition%ROWTYPE;
+    ccvm_row        config.coded_value_map%ROWTYPE;
+BEGIN
+
+    IF attr_list IS NULL OR rdeleted THEN -- need to do the full dance on INSERT or undelete
+        SELECT ARRAY_AGG(name) INTO attr_list FROM config.record_attr_definition;
+    END IF;
+
+    IF rmarc IS NULL THEN
+        SELECT marc INTO rmarc FROM biblio.record_entry WHERE id = rid;
+    END IF;
+
+    FOR attr_def IN SELECT * FROM config.record_attr_definition WHERE NOT composite AND name = ANY( attr_list ) ORDER BY format LOOP
+
+        attr_value := '{}'::TEXT[];
+        norm_attr_value := '{}'::TEXT[];
+        attr_vector_tmp := '{}'::INT[];
+
+        SELECT * INTO ccvm_row FROM config.coded_value_map c WHERE c.ctype = attr_def.name LIMIT 1; 
+
+        -- tag+sf attrs only support SVF
+        IF attr_def.tag IS NOT NULL THEN -- tag (and optional subfield list) selection
+            SELECT  ARRAY[ARRAY_TO_STRING(ARRAY_AGG(value), COALESCE(attr_def.joiner,' '))] INTO attr_value
+              FROM  (SELECT * FROM metabib.full_rec ORDER BY tag, subfield) AS x
+              WHERE record = rid
+                    AND tag LIKE attr_def.tag
+                    AND CASE
+                        WHEN attr_def.sf_list IS NOT NULL 
+                            THEN POSITION(subfield IN attr_def.sf_list) > 0
+                        ELSE TRUE
+                    END
+              GROUP BY tag
+              ORDER BY tag
+              LIMIT 1;
+
+        ELSIF attr_def.fixed_field IS NOT NULL THEN -- a named fixed field, see config.marc21_ff_pos_map.fixed_field
+            attr_value := vandelay.marc21_extract_fixed_field_list(rmarc, attr_def.fixed_field);
+
+            IF NOT attr_def.multi THEN
+                attr_value := ARRAY[attr_value[1]];
+            END IF;
+
+        ELSIF attr_def.xpath IS NOT NULL THEN -- and xpath expression
+
+            SELECT INTO xfrm * FROM config.xml_transform WHERE name = attr_def.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(rmarc,xfrm.xslt);
+                ELSE
+                    transformed_xml := rmarc;
+                END IF;
+    
+                prev_xfrm := xfrm.name;
+            END IF;
+
+            IF xfrm.name IS NULL THEN
+                -- just grab the marcxml (empty) transform
+                SELECT INTO xfrm * FROM config.xml_transform WHERE xslt = '---' LIMIT 1;
+                prev_xfrm := xfrm.name;
+            END IF;
+
+            FOR tmp_xml IN SELECT oils_xpath(attr_def.xpath, transformed_xml, ARRAY[ARRAY[xfrm.prefix, xfrm.namespace_uri]]) LOOP
+                tmp_val := oils_xpath_string(
+                                '//*',
+                                tmp_xml,
+                                COALESCE(attr_def.joiner,' '),
+                                ARRAY[ARRAY[xfrm.prefix, xfrm.namespace_uri]]
+                            );
+                IF tmp_val IS NOT NULL AND BTRIM(tmp_val) <> '' THEN
+                    attr_value := attr_value || tmp_val;
+                    EXIT WHEN NOT attr_def.multi;
+                END IF;
+            END LOOP;
+
+        ELSIF attr_def.phys_char_sf IS NOT NULL THEN -- a named Physical Characteristic, see config.marc21_physical_characteristic_*_map
+            SELECT  ARRAY_AGG(m.value) INTO attr_value
+              FROM  vandelay.marc21_physical_characteristics(rmarc) v
+                    LEFT JOIN config.marc21_physical_characteristic_value_map m ON (m.id = v.value)
+              WHERE v.subfield = attr_def.phys_char_sf AND (m.value IS NOT NULL AND BTRIM(m.value) <> '')
+                    AND ( ccvm_row.id IS NULL OR ( ccvm_row.id IS NOT NULL AND v.id IS NOT NULL) );
+
+            IF NOT attr_def.multi THEN
+                attr_value := ARRAY[attr_value[1]];
+            END IF;
+
+        END IF;
+
+                -- apply index normalizers to attr_value
+        FOR tmp_val IN SELECT value FROM UNNEST(attr_value) x(value) LOOP
+            FOR normalizer IN
+                SELECT  n.func AS func,
+                        n.param_count AS param_count,
+                        m.params AS params
+                  FROM  config.index_normalizer n
+                        JOIN config.record_attr_index_norm_map m ON (m.norm = n.id)
+                  WHERE attr = attr_def.name
+                  ORDER BY m.pos LOOP
+                    EXECUTE 'SELECT ' || normalizer.func || '(' ||
+                    COALESCE( quote_literal( tmp_val ), 'NULL' ) ||
+                        CASE
+                            WHEN normalizer.param_count > 0
+                                THEN ',' || REPLACE(REPLACE(BTRIM(normalizer.params,'[]'),E'\'',E'\\\''),E'"',E'\'')
+                                ELSE ''
+                            END ||
+                    ')' INTO tmp_val;
+
+            END LOOP;
+            IF tmp_val IS NOT NULL AND BTRIM(tmp_val) <> '' THEN
+                norm_attr_value := norm_attr_value || tmp_val;
+            END IF;
+        END LOOP;
+        
+        IF attr_def.filter THEN
+            -- Create unknown uncontrolled values and find the IDs of the values
+            IF ccvm_row.id IS NULL THEN
+                FOR tmp_val IN SELECT value FROM UNNEST(norm_attr_value) x(value) LOOP
+                    IF tmp_val IS NOT NULL AND BTRIM(tmp_val) <> '' THEN
+                        BEGIN -- use subtransaction to isolate unique constraint violations
+                            INSERT INTO metabib.uncontrolled_record_attr_value ( attr, value ) VALUES ( attr_def.name, tmp_val );
+                        EXCEPTION WHEN unique_violation THEN END;
+                    END IF;
+                END LOOP;
+
+                SELECT ARRAY_AGG(id) INTO attr_vector_tmp FROM metabib.uncontrolled_record_attr_value WHERE attr = attr_def.name AND value = ANY( norm_attr_value );
+            ELSE
+                SELECT ARRAY_AGG(id) INTO attr_vector_tmp FROM config.coded_value_map WHERE ctype = attr_def.name AND code = ANY( norm_attr_value );
+            END IF;
+
+            -- Add the new value to the vector
+            attr_vector := attr_vector || attr_vector_tmp;
+        END IF;
+
+        IF attr_def.sorter AND norm_attr_value[1] IS NOT NULL THEN
+            DELETE FROM metabib.record_sorter WHERE source = rid AND attr = attr_def.name;
+            INSERT INTO metabib.record_sorter (source, attr, value) VALUES (rid, attr_def.name, norm_attr_value[1]);
+        END IF;
+
+    END LOOP;
+
+/* We may need to rewrite the vlist to contain
+   the intersection of new values for requested
+   attrs and old values for ignored attrs. To
+   do this, we take the old attr vlist and
+   subtract any values that are valid for the
+   requested attrs, and then add back the new
+   set of attr values. */
+
+    IF ARRAY_LENGTH(pattr_list, 1) > 0 THEN 
+        SELECT vlist INTO attr_vector_tmp FROM metabib.record_attr_vector_list WHERE source = rid;
+        SELECT attr_vector_tmp - ARRAY_AGG(id::INT) INTO attr_vector_tmp FROM metabib.full_attr_id_map WHERE attr = ANY (pattr_list);
+        attr_vector := attr_vector || attr_vector_tmp;
+    END IF;
+
+    -- On to composite attributes, now that the record attrs have been pulled.  Processed in name order, so later composite
+    -- attributes can depend on earlier ones.
+    PERFORM metabib.compile_composite_attr_cache_init();
+    FOR attr_def IN SELECT * FROM config.record_attr_definition WHERE composite AND name = ANY( attr_list ) ORDER BY name LOOP
+
+        FOR ccvm_row IN SELECT * FROM config.coded_value_map c WHERE c.ctype = attr_def.name ORDER BY value LOOP
+
+            tmp_val := metabib.compile_composite_attr( ccvm_row.id );
+            CONTINUE WHEN tmp_val IS NULL OR tmp_val = ''; -- nothing to do
+
+            IF attr_def.filter THEN
+                IF attr_vector @@ tmp_val::query_int THEN
+                    attr_vector = attr_vector + intset(ccvm_row.id);
+                    EXIT WHEN NOT attr_def.multi;
+                END IF;
+            END IF;
+
+            IF attr_def.sorter THEN
+                IF attr_vector @@ tmp_val THEN
+                    DELETE FROM metabib.record_sorter WHERE source = rid AND attr = attr_def.name;
+                    INSERT INTO metabib.record_sorter (source, attr, value) VALUES (rid, attr_def.name, ccvm_row.code);
+                END IF;
+            END IF;
+
+        END LOOP;
+
+    END LOOP;
+
+    IF ARRAY_LENGTH(attr_vector, 1) > 0 THEN
+        IF rdeleted THEN -- initial insert OR revivication
+            DELETE FROM metabib.record_attr_vector_list WHERE source = rid;
+            INSERT INTO metabib.record_attr_vector_list (source, vlist) VALUES (rid, attr_vector);
+        ELSE
+            UPDATE metabib.record_attr_vector_list SET vlist = attr_vector WHERE source = rid;
+        END IF;
+    END IF;
+
+END;
+
+$func$ LANGUAGE PLPGSQL;
+
+
+ALTER TABLE authority.record_entry DISABLE TRIGGER a_marcxml_is_well_formed;
+ALTER TABLE authority.record_entry DISABLE TRIGGER aaa_auth_ingest_or_delete;
+ALTER TABLE authority.record_entry DISABLE TRIGGER b_maintain_901;
+ALTER TABLE authority.record_entry DISABLE TRIGGER c_maintain_control_numbers;
+ALTER TABLE authority.record_entry DISABLE TRIGGER map_thesaurus_to_control_set;
+
+
+SELECT evergreen.upgrade_deps_block_check('0875', :eg_version);
+
+ALTER TABLE authority.record_entry ADD COLUMN heading TEXT, ADD COLUMN simple_heading TEXT;
+
+DROP INDEX IF EXISTS authority.unique_by_heading_and_thesaurus;
+DROP INDEX IF EXISTS authority.by_heading_and_thesaurus;
+DROP INDEX IF EXISTS authority.by_heading;
+
+-- Update without indexes for HOT update
+UPDATE  authority.record_entry
+  SET   heading = authority.normalize_heading( marc ),
+        simple_heading = authority.simple_normalize_heading( marc );
+
+CREATE INDEX by_heading_and_thesaurus ON authority.record_entry (heading) WHERE deleted IS FALSE or deleted = FALSE;
+CREATE INDEX by_heading ON authority.record_entry (simple_heading) WHERE deleted IS FALSE or deleted = FALSE;
+
+-- Add the trigger
+CREATE OR REPLACE FUNCTION authority.normalize_heading_for_upsert () RETURNS TRIGGER AS $f$
+BEGIN
+    NEW.heading := authority.normalize_heading( NEW.marc );
+    NEW.simple_heading := authority.simple_normalize_heading( NEW.marc );
+    RETURN NEW;
+END;
+$f$ LANGUAGE PLPGSQL;
+
+CREATE TRIGGER update_headings_tgr BEFORE INSERT OR UPDATE ON authority.record_entry FOR EACH ROW EXECUTE PROCEDURE authority.normalize_heading_for_upsert();
+
+ALTER FUNCTION authority.normalize_heading(TEXT, BOOL) STABLE STRICT;
+ALTER FUNCTION authority.normalize_heading(TEXT) STABLE STRICT;
+ALTER FUNCTION authority.simple_normalize_heading(TEXT) STABLE STRICT;
+ALTER FUNCTION authority.simple_heading_set(TEXT) STABLE STRICT;
+
+
+ALTER TABLE authority.record_entry ENABLE TRIGGER a_marcxml_is_well_formed;
+ALTER TABLE authority.record_entry ENABLE TRIGGER aaa_auth_ingest_or_delete;
+ALTER TABLE authority.record_entry ENABLE TRIGGER b_maintain_901;
+ALTER TABLE authority.record_entry ENABLE TRIGGER c_maintain_control_numbers;
+ALTER TABLE authority.record_entry ENABLE TRIGGER map_thesaurus_to_control_set;
+
+
+
+SELECT evergreen.upgrade_deps_block_check('0876', :eg_version);
+
+INSERT INTO permission.perm_list ( code, description ) VALUES
+ ( 'group_application.user.staff.admin.system_admin', oils_i18n_gettext( '',
+    'Allow a user to add/remove users to/from the "System Administrator" group', 'ppl', 'description' )),
+ ( 'group_application.user.staff.cat_admin', oils_i18n_gettext( '', 
+    'Allow a user to add/remove users to/from the "Cataloging Administrator" group', 'ppl', 'description' )),
+ ( 'group_application.user.staff.circ_admin', oils_i18n_gettext( '', 
+    'Allow a user to add/remove users to/from the "Circulation Administrator" group', 'ppl', 'description' )),
+ ( 'group_application.user.staff.data_review', oils_i18n_gettext( '', 
+    'Allow a user to add/remove users to/from the "Data Review" group', 'ppl', 'description' )),
+ ( 'group_application.user.staff.volunteers', oils_i18n_gettext( '', 
+    'Allow a user to add/remove users to/from the "Volunteers" group', 'ppl', 'description' ))
+;
+
+
+SELECT evergreen.upgrade_deps_block_check('0877', :eg_version);
+
+-- Don't use Series search field as the browse field
+UPDATE config.metabib_field SET
+	browse_field = FALSE,
+	browse_xpath = NULL,
+	browse_sort_xpath = NULL,
+	xpath = $$//mods32:mods/mods32:relatedItem[@type="series"]/mods32:titleInfo[not(@type="nfi")]$$
+WHERE id = 1;
+
+-- Create a new series browse config
+INSERT INTO config.metabib_field ( id, field_class, name, label, format, xpath, search_field, authority_xpath, browse_field, browse_sort_xpath ) VALUES
+    (32, 'series', 'browse', oils_i18n_gettext(32, 'Series Title (Browse)', 'cmf', 'label'), 'mods32', $$//mods32:mods/mods32:relatedItem[@type="series"]/mods32:titleInfo[@type="nfi"]$$, FALSE, '//@xlink:href', TRUE, $$*[local-name() != "nonSort"]$$ );
+
+SELECT evergreen.upgrade_deps_block_check('0878', :eg_version);
+
+CREATE OR REPLACE FUNCTION metabib.reingest_metabib_field_entries( bib_id BIGINT, skip_facet BOOL DEFAULT FALSE, skip_browse BOOL DEFAULT FALSE, skip_search BOOL DEFAULT FALSE ) RETURNS VOID AS $func$
+DECLARE
+    fclass          RECORD;
+    ind_data        metabib.field_entry_template%ROWTYPE;
+    mbe_row         metabib.browse_entry%ROWTYPE;
+    mbe_id          BIGINT;
+    b_skip_facet    BOOL;
+    b_skip_browse   BOOL;
+    b_skip_search   BOOL;
+    value_prepped   TEXT;
+BEGIN
+
+    SELECT COALESCE(NULLIF(skip_facet, FALSE), EXISTS (SELECT enabled FROM config.internal_flag WHERE name =  'ingest.skip_facet_indexing' AND enabled)) INTO b_skip_facet;
+    SELECT COALESCE(NULLIF(skip_browse, FALSE), EXISTS (SELECT enabled FROM config.internal_flag WHERE name =  'ingest.skip_browse_indexing' AND enabled)) INTO b_skip_browse;
+    SELECT COALESCE(NULLIF(skip_search, FALSE), EXISTS (SELECT enabled FROM config.internal_flag WHERE name =  'ingest.skip_search_indexing' AND enabled)) INTO b_skip_search;
+
+    PERFORM * FROM config.internal_flag WHERE name = 'ingest.assume_inserts_only' AND enabled;
+    IF NOT FOUND THEN
+        IF NOT b_skip_search THEN
+            FOR fclass IN SELECT * FROM config.metabib_class LOOP
+                -- RAISE NOTICE 'Emptying out %', fclass.name;
+                EXECUTE $$DELETE FROM metabib.$$ || fclass.name || $$_field_entry WHERE source = $$ || bib_id;
+            END LOOP;
+        END IF;
+        IF NOT b_skip_facet THEN
+            DELETE FROM metabib.facet_entry WHERE source = bib_id;
+        END IF;
+        IF NOT b_skip_browse THEN
+            DELETE FROM metabib.browse_entry_def_map WHERE source = bib_id;
+        END IF;
+    END IF;
+
+    FOR ind_data IN SELECT * FROM biblio.extract_metabib_field_entry( bib_id ) LOOP
+
+	-- don't store what has been normalized away
+        CONTINUE WHEN ind_data.value IS NULL;
+
+        IF ind_data.field < 0 THEN
+            ind_data.field = -1 * ind_data.field;
+        END IF;
+
+        IF ind_data.facet_field AND NOT b_skip_facet THEN
+            INSERT INTO metabib.facet_entry (field, source, value)
+                VALUES (ind_data.field, ind_data.source, ind_data.value);
+        END IF;
+
+        IF ind_data.browse_field AND NOT b_skip_browse THEN
+            -- A caveat about this SELECT: this should take care of replacing
+            -- old mbe rows when data changes, but not if normalization (by
+            -- which I mean specifically the output of
+            -- evergreen.oils_tsearch2()) changes.  It may or may not be
+            -- expensive to add a comparison of index_vector to index_vector
+            -- to the WHERE clause below.
+
+            CONTINUE WHEN ind_data.sort_value IS NULL;
+
+            value_prepped := metabib.browse_normalize(ind_data.value, ind_data.field);
+            SELECT INTO mbe_row * FROM metabib.browse_entry
+                WHERE value = value_prepped AND sort_value = ind_data.sort_value;
+
+            IF FOUND THEN
+                mbe_id := mbe_row.id;
+            ELSE
+                INSERT INTO metabib.browse_entry
+                    ( value, sort_value ) VALUES
+                    ( value_prepped, ind_data.sort_value );
+
+                mbe_id := CURRVAL('metabib.browse_entry_id_seq'::REGCLASS);
+            END IF;
+
+            INSERT INTO metabib.browse_entry_def_map (entry, def, source, authority)
+                VALUES (mbe_id, ind_data.field, ind_data.source, ind_data.authority);
+        END IF;
+
+        IF ind_data.search_field AND NOT b_skip_search THEN
+            -- Avoid inserting duplicate rows
+            EXECUTE 'SELECT 1 FROM metabib.' || ind_data.field_class ||
+                '_field_entry WHERE field = $1 AND source = $2 AND value = $3'
+                INTO mbe_id USING ind_data.field, ind_data.source, ind_data.value;
+                -- RAISE NOTICE 'Search for an already matching row returned %', mbe_id;
+            IF mbe_id IS NULL THEN
+                EXECUTE $$
+                INSERT INTO metabib.$$ || ind_data.field_class || $$_field_entry (field, source, value)
+                    VALUES ($$ ||
+                        quote_literal(ind_data.field) || $$, $$ ||
+                        quote_literal(ind_data.source) || $$, $$ ||
+                        quote_literal(ind_data.value) ||
+                    $$);$$;
+            END IF;
+        END IF;
+
+    END LOOP;
+
+    IF NOT b_skip_search THEN
+        PERFORM metabib.update_combined_index_vectors(bib_id);
+    END IF;
+
+    RETURN;
+END;
+$func$ LANGUAGE PLPGSQL;
+
+
+
+SELECT evergreen.upgrade_deps_block_check('0879', :eg_version);
+
+CREATE OR REPLACE FUNCTION vandelay._get_expr_push_jrow(
+    node vandelay.match_set_point,
+    tags_rstore HSTORE
+) RETURNS VOID AS $$
+DECLARE
+    jrow        TEXT;
+    my_alias    TEXT;
+    op          TEXT;
+    tagkey      TEXT;
+    caseless    BOOL;
+    jrow_count  INT;
+    my_using    TEXT;
+    my_join     TEXT;
+BEGIN
+    -- remember $1 is tags_rstore, and $2 is svf_rstore
+
+    caseless := FALSE;
+    SELECT COUNT(*) INTO jrow_count FROM _vandelay_tmp_jrows;
+    IF jrow_count > 0 THEN
+        my_using := ' USING (record)';
+        my_join := 'FULL OUTER JOIN';
+    ELSE
+        my_using := '';
+        my_join := 'FROM';
+    END IF;
+
+    IF node.tag IS NOT NULL THEN
+        caseless := (node.tag IN ('020', '022', '024'));
+        tagkey := node.tag;
+        IF node.subfield IS NOT NULL THEN
+            tagkey := tagkey || node.subfield;
+        END IF;
+    END IF;
+
+    IF node.negate THEN
+        IF caseless THEN
+            op := 'NOT LIKE';
+        ELSE
+            op := '<>';
+        END IF;
+    ELSE
+        IF caseless THEN
+            op := 'LIKE';
+        ELSE
+            op := '=';
+        END IF;
+    END IF;
+
+    my_alias := 'n' || node.id::TEXT;
+
+    jrow := my_join || ' (SELECT *, ';
+    IF node.tag IS NOT NULL THEN
+        jrow := jrow  || node.quality ||
+            ' AS quality FROM metabib.full_rec mfr WHERE mfr.tag = ''' ||
+            node.tag || '''';
+        IF node.subfield IS NOT NULL THEN
+            jrow := jrow || ' AND mfr.subfield = ''' ||
+                node.subfield || '''';
+        END IF;
+        jrow := jrow || ' AND (';
+        jrow := jrow || vandelay._node_tag_comparisons(caseless, op, tags_rstore, tagkey);
+        jrow := jrow || ')) ' || my_alias || my_using || E'\n';
+    ELSE    -- svf
+        jrow := jrow || 'id AS record, ' || node.quality ||
+            ' AS quality FROM metabib.record_attr_flat mraf WHERE mraf.attr = ''' ||
+            node.svf || ''' AND mraf.value ' || op || ' $2->''' || node.svf || ''') ' ||
+            my_alias || my_using || E'\n';
+    END IF;
+    INSERT INTO _vandelay_tmp_jrows (j) VALUES (jrow);
+END;
+$$ LANGUAGE PLPGSQL;
+
+
+COMMIT;
+
+-- Not running changes from example.reporter-extension.sql since these are
+-- not installed by default, but including a helpful note.
+\qecho
+\qecho **** NOTICE ****
+\qecho 'There were changes in example.reporter-extension.sql.'
+\qecho 'Please run that script again if you use it in your system'
+\qecho 'to apply new changes.'
+\qecho
+\qecho
+\qecho **** Certain improvements in 2.6, particularly attribute improvements,
+\qecho **** require a reingest of all your bib records.  In order to allow
+\qecho **** this to continue without locking your entire bibliographic data
+\qecho **** set, consider generating an SQL script with the following queries,
+\qecho **** then running it via psql.
+\qecho ****
+\qecho **** If you have a large number of bibs (100,000+), please consider this
+\qecho **** as a starting point only, as you will likely wish to parallelize
+\qecho **** this is some fashion.
+\qecho ****
+\qecho **** If you require a more responsive catalog/database while reingesting,
+\qecho **** consider adding 'pg_sleep()' calls between each reingest update.
+\qecho
+\qecho '\\t'
+\qecho '\\o /tmp/reingest_2.6_bib_recs.sql'
+\qecho 'SELECT ''-- Grab current setting'';'
+\qecho 'SELECT ''\\set force_reingest '' || enabled FROM config.internal_flag WHERE name = ''ingest.reingest.force_on_same_marc'';'
+\qecho 'SELECT ''update config.internal_flag set enabled = true where name = ''''ingest.reingest.force_on_same_marc'''';'';'
+\qecho 'SELECT ''update biblio.record_entry set id = id where id = '' || id || '';'' FROM biblio.record_entry WHERE NOT DELETED AND id > 0;'
+\qecho 'SELECT ''-- Restore previous setting'';'
+\qecho 'SELECT ''update config.internal_flag set enabled = :force_reingest where name = \'\'ingest.reingest.force_on_same_marc\'\';'';'
+\qecho '\\o'
+\qecho '\\t'
diff --git a/Open-ILS/xul/staff_client/chrome/content/main/about.html b/Open-ILS/xul/staff_client/chrome/content/main/about.html
index 2737f47..dfce22e 100644
--- a/Open-ILS/xul/staff_client/chrome/content/main/about.html
+++ b/Open-ILS/xul/staff_client/chrome/content/main/about.html
@@ -1,7 +1,7 @@
 <html><head><script></script></head><body onload="var x = document.getElementById('version'); var version ='/xul/server/'.split(/\//)[2]; if (version == 'server') { version = 'versionless debug build'; } x.appendChild(document.createTextNode(version));">
 <h1 style="text-decoration: underline">Evergreen</h1>
 <p>Target Server ID: <span id="version"></span></p>
-<p>$HeadURL$</p>
+<p>http://git.evergreen-ils.org/?p=Evergreen.git;a=shortlog;h=refs/heads/tags/rel_2_6_0</p>
 <h2>What is Evergreen?</h2>
 <blockquote>
 <p>
diff --git a/Open-ILS/xul/staff_client/defaults/preferences/prefs.js b/Open-ILS/xul/staff_client/defaults/preferences/prefs.js
index 0613a13..6b55006 100644
--- a/Open-ILS/xul/staff_client/defaults/preferences/prefs.js
+++ b/Open-ILS/xul/staff_client/defaults/preferences/prefs.js
@@ -11,7 +11,7 @@ pref("toolkit.singletonWindowType", "eg_main");
 pref("open-ils.enable_join_tabs", true);
 
 // We'll use this one to help brand some build information into the client, and rely on subversion keywords
-pref("open-ils.repository.headURL","$HeadURL$");
+pref("open-ils.repository.headURL","http://git.evergreen-ils.org/?p=Evergreen.git;a=shortlog;h=refs/heads/tags/rel_2_6_0");
 pref("open-ils.repository.author","$Author$");
 pref("open-ils.repository.revision","$Revision$");
 pref("open-ils.repository.date","$Date$");
diff --git a/Open-ILS/xul/staff_client/windowssetup.nsi b/Open-ILS/xul/staff_client/windowssetup.nsi
index a954357..f1fd419 100644
--- a/Open-ILS/xul/staff_client/windowssetup.nsi
+++ b/Open-ILS/xul/staff_client/windowssetup.nsi
@@ -3,7 +3,7 @@
 ; HM NIS Edit Wizard helper defines
 ; Old versions of makensis don't like this, moved to Makefile
 ;!define /file PRODUCT_VERSION "client/VERSION"
-!define PRODUCT_TAG "Master"
+!define PRODUCT_TAG "2.6"
 !define PRODUCT_INSTALL_TAG "${PRODUCT_TAG}"
 !define UI_IMAGESET "beta"
 ;!define UI_IMAGESET "release"
diff --git a/README b/README
deleted file mode 120000
index b57451a..0000000
--- a/README
+++ /dev/null
@@ -1 +0,0 @@
-docs/installation/server_installation.txt
\ No newline at end of file
diff --git a/README b/README
new file mode 100644
index 0000000..7f0f93f
--- /dev/null
+++ b/README
@@ -0,0 +1,597 @@
+Installing the Evergreen server
+===============================
+:toc:
+:numbered:
+
+Preamble: referenced user accounts
+----------------------------------
+
+In subsequent sections, we will refer to a number of different accounts, as
+follows:
+
+  * Linux user accounts:
+    ** The *user* Linux account is the account that you use to log onto the
+       Linux system as a regular user.
+    ** The *root* Linux account is an account that has system administrator
+       privileges. On Debian and Fedora you can switch to this account from
+       your *user* account by issuing the `su -` command and entering the
+       password for the *root* account when prompted. On Ubuntu you can switch
+       to this account from your *user* account using the `sudo su -` command
+       and entering the password for your *user* account when prompted.
+    ** The *opensrf* Linux account is an account that you create when installing
+       OpenSRF. You can switch to this account from the *root* account by
+       issuing the `su - opensrf` command.
+    ** The *postgres* Linux account is created automatically when you install
+       the PostgreSQL database server. You can switch to this account from the
+       *root* account by issuing the `su - postgres` command.
+  * PostgreSQL user accounts:
+    ** The *evergreen* PostgreSQL account is a superuser account that you will
+       create to connect to the PostgreSQL database server.
+  * Evergreen administrator account:
+    ** The *egadmin* Evergreen account is an administrator account for
+       Evergreen that you will use to test connectivity and configure your
+       Evergreen instance.
+
+Preamble: developer instructions
+--------------------------------
+
+[NOTE]
+Skip this section if you are using an official release tarball downloaded
+from http://evergreen-ils.org/downloads
+
+Developers working directly with the source code from the Git repository,
+rather than an official release tarball, must install some extra packages
+and perform one step before they can proceed with the `./configure` step.
+
+As the *root* Linux account, install the following packages:
+
+  * autoconf
+  * automake
+  * libtool
+
+As the *user* Linux account, issue the following command in the Evergreen
+source directory to generate the configure script and Makefiles:
+
+[source, bash]
+------------------------------------------------------------------------------
+autoreconf -i
+------------------------------------------------------------------------------
+
+Installing prerequisites
+------------------------
+
+Evergreen has a number of prerequisite packages that must be installed
+before you can successfully configure, compile, and install Evergreen.
+
+1. Begin by installing the most recent version of OpenSRF (2.3.0 or later).
+   You can download OpenSRF releases from http://evergreen-ils.org/opensrf-downloads/
+2. On many distributions, it is necessary to install PostgreSQL 9 from external
+   repositories.
++
+  * On Debian Squeeze, open `/etc/apt/sources.list` in a text editor as the
+    *root* Linux account and add the following line:
++
+[source, bash]
+------------------------------------------------------------------------------
+deb http://backports.debian.org/debian-backports squeeze-backports main contrib
+------------------------------------------------------------------------------
++
+  * On Ubuntu Lucid, you can use a PPA (personal package archive), which are 
+    package sources hosted on Launchpad. The one most commonly used by Evergreen
+    Community members is maintained by Martin Pitt, who also maintains the
+    official PostgreSQL packages for Ubuntu. As the *root* Linux account, issue
+    the following commands to add the PPA source:
++
+[source, bash]
+------------------------------------------------------------------------------
+apt-get install python-software-properties
+add-apt-repository ppa:pitti/postgresql
+------------------------------------------------------------------------------
++
+  * Ubuntu Precise comes with PostgreSQL 9, so no additional steps are required.
++
+  * Fedora comes with PostgreSQL 9, so no additional steps are required.
++
+3. On Debian and Ubuntu, run `aptitude update` as the *root* Linux account to
+   retrieve the new packages from the backports repository.
+4. Issue the following commands as the *root* Linux account to install
+   prerequisites using the `Makefile.install` prerequisite installer,
+   substituting `debian-squeeze`, `fedora`, `ubuntu-lucid`, or
+   `ubuntu-precise` for <osname> below:
++
+[source, bash]
+------------------------------------------------------------------------------
+make -f Open-ILS/src/extras/Makefile.install <osname>
+------------------------------------------------------------------------------
++
+5. Add the libdbi-libdbd libraries to the system dynamic library path by
+   issuing the following commands as the *root* Linux account:
++
+[NOTE]
+You should skip this step if installing on Ubuntu Precise. The ubuntu-precise
+target uses libdbd-pgsql from packages.
++
+.Debian / Ubuntu Lucid
+[source, bash]
+------------------------------------------------------------------------------
+echo "/usr/local/lib/dbd" > /etc/ld.so.conf.d/eg.conf
+ldconfig
+------------------------------------------------------------------------------
++
+.Fedora
+[source, bash]
+------------------------------------------------------------------------------
+echo "/usr/lib64/dbd" > /etc/ld.so.conf.d/eg.conf
+ldconfig
+------------------------------------------------------------------------------
+
+Configuration and compilation instructions
+------------------------------------------
+
+For the time being, we are still installing everything in the `/openils/`
+directory. From the Evergreen source directory, issue the following commands as
+the *user* Linux account to configure and build Evergreen:
+
+[source, bash]
+------------------------------------------------------------------------------
+PATH=/openils/bin:$PATH ./configure --prefix=/openils --sysconfdir=/openils/conf
+make
+------------------------------------------------------------------------------
+
+These instructions assume that you have also installed OpenSRF under `/openils/`.
+If not, please adjust PATH as needed so that the Evergreen `configure` script
+can find `osrf_config`.
+
+Installation instructions
+-------------------------
+
+1. Once you have configured and compiled Evergreen, issue the following
+   command as the *root* Linux account to install Evergreen, build the server
+   portion of the staff client, and copy example configuration files to
+   `/openils/conf`.
+   Change the value of the `STAFF_CLIENT_STAMP_ID` variable to match the version
+   of the staff client that you will use to connect to the Evergreen server.
++
+[source, bash]
+------------------------------------------------------------------------------
+make STAFF_CLIENT_STAMP_ID=rel_2_6_0 install
+------------------------------------------------------------------------------
++
+2. The server portion of the staff client expects `http://hostname/xul/server`
+   to resolve. Issue the following commands as the *root* Linux account to
+   create a symbolic link pointing to the `server` subdirectory of the server
+   portion of the staff client that we just built using the staff client ID
+   'rel_name':
++
+[source, bash]
+------------------------------------------------------------------------------
+cd /openils/var/web/xul
+ln -sf rel_name/server server
+------------------------------------------------------------------------------
+
+Change ownership of the Evergreen files
+---------------------------------------
+
+All files in the `/openils/` directory and subdirectories must be owned by the
+`opensrf` user. Issue the following command as the *root* Linux account to
+change the ownership on the files:
+
+[source, bash]
+------------------------------------------------------------------------------
+chown -R opensrf:opensrf /openils
+------------------------------------------------------------------------------
+
+Additional Instructions for Developers
+--------------------------------------
+
+[NOTE]
+Skip this section if you are using an official release tarball downloaded
+from http://evergreen-ils.org/downloads
+
+Developers working directly with the source code from the Git repository,
+rather than an official release tarball, need to install the Dojo Toolkit
+set of JavaScript libraries. The appropriate version of Dojo is included in
+Evergreen release tarballs. Developers should install the Dojo 1.3.3 version
+of Dojo by issuing the following commands as the *opensrf* Linux account:
+
+[source, bash]
+------------------------------------------------------------------------------
+wget http://download.dojotoolkit.org/release-1.3.3/dojo-release-1.3.3.tar.gz
+tar -C /openils/var/web/js -xzf dojo-release-1.3.3.tar.gz
+cp -r /openils/var/web/js/dojo-release-1.3.3/* /openils/var/web/js/dojo/.
+------------------------------------------------------------------------------
+
+
+Configure the Apache Web server
+-------------------------------
+
+1. Use the example configuration files in `Open-ILS/examples/apache/` (for
+Apache versions below 2.4) or `Open-ILS/examples/apache_24/` (for Apache
+versions 2.4 or greater) to configure your Web server for the Evergreen
+catalog, staff client, Web services, and administration interfaces. Issue the
+following commands as the *root* Linux account:
++
+.Debian and Ubuntu
+[source,bash]
+------------------------------------------------------------------------------
+cp Open-ILS/examples/apache/eg.conf       /etc/apache2/sites-available/
+cp Open-ILS/examples/apache/eg_vhost.conf /etc/apache2/
+cp Open-ILS/examples/apache/eg_startup    /etc/apache2/
+# Now set up SSL
+mkdir /etc/apache2/ssl
+cd /etc/apache2/ssl
+------------------------------------------------------------------------------
++
+.Fedora
+[source,bash]
+------------------------------------------------------------------------------
+cp Open-ILS/examples/apache_24/eg_24.conf       /etc/httpd/conf.d/
+cp Open-ILS/examples/apache_24/eg_vhost_24.conf /etc/httpd/eg_vhost.conf
+cp Open-ILS/examples/apache/eg_startup          /etc/httpd/
+# Now set up SSL
+mkdir /etc/httpd/ssl
+cd /etc/httpd/ssl
+------------------------------------------------------------------------------
++
+2. The `openssl` command cuts a new SSL key for your Apache server. For a
+production server, you should purchase a signed SSL certificate, but you can
+just use a self-signed certificate and accept the warnings in the staff client
+and browser during testing and development. Create an SSL key for the Apache
+server by issuing the following command as the *root* Linux account:
++
+[source,bash]
+------------------------------------------------------------------------------
+openssl req -new -x509 -days 365 -nodes -out server.crt -keyout server.key
+------------------------------------------------------------------------------
++
+3. As the *root* Linux account, edit the `eg.conf` file that you copied into
+place.
+  a. To enable access to the offline upload / execute interface from any
+     workstation on any network, make the following change (and note that
+     you *must* secure this for a production instance):
+     * (Apache 2.2): Replace `Allow from 10.0.0.0/8` with `Allow from all`
+     * (Apache 2.4): Replace `Require host 10.0.0.0/8` with `Require all granted`
+  b. (Fedora): Change references from the non-existent `/etc/apache2/` directory
+     to `/etc/httpd/`.
+4. Change the user for the Apache server.
+  * (Debian and Ubuntu): As the *root* Linux account, edit
+    `/etc/apache2/envvars`.  Change `export APACHE_RUN_USER=www-data` to 
+    `export APACHE_RUN_USER=opensrf`.
+  * (Fedora): As the *root* Linux account , edit `/etc/httpd/conf/httpd.conf`.
+    Change `User apache` to `User opensrf`.
+5. Configure Apache with performance settings appropriate for Evergreen:
+  * (Debian and Ubuntu): As the *root* Linux account, edit
+    `/etc/apache2/apache2.conf`:
+  * (Fedora): As the *root* Linux account, edit `/etc/httpd/conf/httpd.conf`:
+    a. Change `KeepAliveTimeout` to `1`. Higher values reduce the chance of
+       a request timing out unexpectedly, but increase the risk of using up
+       all available Apache child processes.
+    b. 'Optional': Change `MaxKeepAliveRequests` to `100`
+    c. Update the prefork configuration section to suit your environment. The
+       following settings apply to a busy system:
++
+[source,bash]
+------------------------------------------------------------------------------
+<IfModule mpm_prefork_module>
+   StartServers           20
+   MinSpareServers         5
+   MaxSpareServers        15
+   MaxClients            150
+   MaxRequestsPerChild 10000
+</IfModule>
+------------------------------------------------------------------------------
++
+6. (Fedora): As the *root* Linux account, edit the `/etc/httpd/eg_vhost.conf`
+   file to change references from the non-existent `/etc/apache2/` directory
+   to `/etc/httpd/`.
+7. (Debian and Ubuntu): As the *root* Linux account, enable the Evergreen site:
++
+[source,bash]
+------------------------------------------------------------------------------
+a2dissite default  # OPTIONAL: disable the default site (the "It Works" page)
+a2ensite eg.conf
+------------------------------------------------------------------------------
+8. (Ubuntu): As the *root* Linux account, enable Apache to write
+   to the lock directory; this is currently necessary because Apache
+   is running as the `opensrf` user:
++
+[source,bash]
+------------------------------------------------------------------------------
+chown opensrf /var/lock/apache2
+------------------------------------------------------------------------------
+
+Configure OpenSRF for the Evergreen application
+-----------------------------------------------
+There are a number of example OpenSRF configuration files in `/openils/conf/`
+that you can use as a template for your Evergreen installation. Issue the
+following commands as the *opensrf* Linux account:
+
+[source, bash]
+------------------------------------------------------------------------------
+cp -b /openils/conf/opensrf_core.xml.example /openils/conf/opensrf_core.xml
+cp -b /openils/conf/opensrf.xml.example /openils/conf/opensrf.xml
+------------------------------------------------------------------------------
+
+When you installed OpenSRF, you created four Jabber users on two
+separate domains and edited the `opensrf_core.xml` file accordingly. Please
+refer back to the OpenSRF README and, as the *opensrf* Linux account, edit the
+Evergreen version of the `opensrf_core.xml` file using the same Jabber users
+and domains as you used while installing and testing OpenSRF.
+
+[NOTE]
+The `-b` flag tells the `cp` command to create a backup version of the
+destination file. The backup version of the destination file has a tilde (`~`)
+appended to the file name, so if you have forgotten the Jabber users and
+domains, you can retrieve the settings from the backup version of the files.
+
+`eg_db_config`, described in the following section, sets the database
+connection information in `opensrf.xml` for you.
+
+Creating the Evergreen database
+-------------------------------
+
+Setting up the PostgreSQL server
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+For production use, most libraries install the PostgreSQL database server on a
+dedicated machine. Therefore, by default, the `Makefile.install` prerequisite
+installer does *not* install the PostgreSQL 9 database server that is required
+by every Evergreen system. You can install the packages required by Debian or
+Ubuntu Lucid on the machine of your choice using the following commands as the
+*root* Linux account:
+
+.(Debian / Ubuntu / Fedora) Installing PostgreSQL server packages
+
+Each OS build target provides the postgres server installation packages
+required for each operating system.  To install Postgres server packages, 
+use the make target 'postgres-server-<OSTYPE>'.  Choose the most appropriate 
+command below based on your operating system.
+
+[source, bash]
+------------------------------------------------------------------------------
+make -f Open-ILS/src/extras/Makefile.install postgres-server-debian-wheezy
+make -f Open-ILS/src/extras/Makefile.install postgres-server-debian-squeeze
+make -f Open-ILS/src/extras/Makefile.install postgres-server-ubuntu-lucid
+make -f Open-ILS/src/extras/Makefile.install postgres-server-ubuntu-precise
+make -f Open-ILS/src/extras/Makefile.install postgres-server-fedora
+------------------------------------------------------------------------------
+
+.(Fedora) Postgres initialization
+
+Installing Postgres on Fedora also requires you to initialize the PostgreSQL
+cluster and start the service. Issue the following commands as the *root* user:
+
+[source, bash]
+------------------------------------------------------------------------------
+postgresql-setup initdb
+systemctl start postgresql
+------------------------------------------------------------------------------
+
+For a standalone PostgreSQL server, install the following Perl modules as the
+*root* Linux account:
+
+.(Debian / Ubuntu) Installing additional Perl modules on a standalone PostgreSQL 9 server
+[source, bash]
+------------------------------------------------------------------------------
+aptitude install gcc libxml-libxml-perl libxml-libxslt-perl
+cpan Business::ISBN
+cpan JSON::XS
+cpan Library::CallNumber::LC
+cpan MARC::Record
+cpan MARC::File::XML
+cpan UUID::Tiny
+cpan Rose::URI
+------------------------------------------------------------------------------
+
+.(Fedora) Installing additional Perl modules on a standalone PostgreSQL 9 server
+[source, bash]
+------------------------------------------------------------------------------
+yum install gcc perl-XML-LibXML perl-XML-LibXSLT perl-Business-ISBN
+yum install perl-Library-CallNumber-LC perl-MARC-Record perl-MARC-Charset
+yum install perl-MARC-File-XML perl-UUID-Tiny
+------------------------------------------------------------------------------
+
+You need to create a PostgreSQL superuser to create and access the database.
+Issue the following command as the *postgres* Linux account to create a new
+PostgreSQL superuser named `evergreen`. When prompted, enter the new user's
+password:
+
+[source, bash]
+------------------------------------------------------------------------------
+createuser -s -P evergreen
+------------------------------------------------------------------------------
+
+.Enabling connections to the PostgreSQL database
+
+Your PostgreSQL database may be configured by default to prevent connections,
+for example, it might reject attempts to connect via TCP/IP or from other
+servers. To enable TCP/IP connections from localhost, check your `pg_hba.conf`
+file, found in the `/etc/postgresql/` directory on Debian and Ubuntu, and in
+the `/var/lib/pgsql/data/` directory on Fedora. A simple way to enable TCP/IP
+connections from localhost to all databases with password authentication, which
+would be suitable for a test install of Evergreen on a single server, is to
+ensure the file contains the following entries _before_ any "host ... ident"
+entries:
+
+------------------------------------------------------------------------------
+host    all             all             ::1/128                 md5
+host    all             all             127.0.0.1/32            md5
+------------------------------------------------------------------------------
+
+When you change the `pg_hba.conf` file, you will need to reload PostgreSQL to
+make the changes take effect.  For more information on configuring connectivity
+to PostgreSQL, see
+http://www.postgresql.org/docs/devel/static/auth-pg-hba-conf.html
+
+Creating the Evergreen database and schema
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Once you have created the *evergreen* PostgreSQL account, you also need to
+create the database and schema, and configure your configuration files to point
+at the database server. Issue the following command as the *root* Linux account
+from inside the Evergreen source directory, replacing <user>, <password>,
+<hostname>, <port>, and <dbname> with the appropriate values for your
+PostgreSQL database (where <user> and <password> are for the *evergreen*
+PostgreSQL account you just created), and replace <admin-user> and <admin-pass>
+with the values you want for the *egadmin* Evergreen administrator account:
+
+[source, bash]
+------------------------------------------------------------------------------
+perl Open-ILS/src/support-scripts/eg_db_config --update-config \
+       --service all --create-database --create-schema --create-offline \
+       --user <user> --password <password> --hostname <hostname> --port <port> \
+       --database <dbname> --admin-user <admin-user> --admin-pass <admin-pass>
+------------------------------------------------------------------------------
+
+This creates the database and schema and configures all of the services in
+your `/openils/conf/opensrf.xml` configuration file to point to that database.
+It also creates the configuration files required by the Evergreen `cgi-bin`
+administration scripts, and sets the user name and password for the *egadmin*
+Evergreen administrator account to your requested values.
+
+You can get a complete set of options for `eg_db_config.pl` by passing the
+`--help` parameter.
+
+Loading sample data
+~~~~~~~~~~~~~~~~~~~
+If you add the `--load-all-sample` parameter to the `eg_db_config` command,
+a set of authority and bibliographic records, call numbers, copies, staff
+and regular users, and transactions will be loaded into your target
+database. This sample dataset is commonly referred to as the _concerto_
+sample data, and can be useful for testing out Evergreen functionality and
+for creating problem reports that developers can easily recreate with their
+own copy of the _concerto_ sample data.
+
+Creating the database on a remote server
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+In a production instance of Evergreen, your PostgreSQL server should be
+installed on a dedicated server.
+
+PostgreSQL 9.1 and later
+^^^^^^^^^^^^^^^^^^^^^^^^
+To create the database instance on a remote database server running PostgreSQL
+9.1 or later, simply use the `--create-database` flag on `eg_db_config`.
+
+Starting Evergreen
+------------------
+1. As the *root* Linux account, start the `memcached` and `ejabberd` services
+(if they aren't already running):
++
+[source, bash]
+------------------------------------------------------------------------------
+/etc/init.d/ejabberd start
+/etc/init.d/memcached start
+------------------------------------------------------------------------------
++
+2. As the *opensrf* Linux account, start Evergreen. The `-l` flag in the
+following command is only necessary if you want to force Evergreen to treat the
+hostname as `localhost`; if you configured `opensrf.xml` using the real
+hostname of your machine as returned by `perl -ENet::Domain 'print
+Net::Domain::hostfqdn() . "\n";'`, you should not use the `-l` flag.
++
+[source, bash]
+------------------------------------------------------------------------------
+osrf_control -l --start-all
+------------------------------------------------------------------------------
++
+  ** If you receive the error message `bash: osrf_control: command not found`,
+     then your environment variable `PATH` does not include the `/openils/bin`
+     directory; this should have been set in the *opensrf* Linux account's
+     `.bashrc` configuration file. To manually set the `PATH` variable, edit the
+     configuration file `~/.bashrc` as the *opensrf* Linux account and add the
+     following line:
++
+[source, bash]
+------------------------------------------------------------------------------
+export PATH=$PATH:/openils/bin
+------------------------------------------------------------------------------
++
+3. As the *opensrf* Linux account, generate the Web files needed by the staff
+   client and catalogue and update the organization unit proximity (you need to do
+   this the first time you start Evergreen, and after that each time you change
+   the library hierarchy in `config.cgi`):
++
+[source, bash]
+------------------------------------------------------------------------------
+autogen.sh -u
+------------------------------------------------------------------------------
++
+4. As the *root* Linux account, restart the Apache Web server:
++
+[source, bash]
+------------------------------------------------------------------------------
+/etc/init.d/apache2 restart
+------------------------------------------------------------------------------
++
+If the Apache Web server was running when you started the OpenSRF services, you
+might not be able to successfully log in to the OPAC or staff client until the
+Apache Web server is restarted.
+
+Testing connections to Evergreen
+--------------------------------
+
+Once you have installed and started Evergreen, test your connection to
+Evergreen via `srfsh`. As the *opensrf* Linux account, issue the following
+commands to start `srfsh` and try to log onto the Evergreen server using the
+*egadmin* Evergreen administrator user name and password that you set using the
+`eg_db_config` command:
+
+[source, bash]
+------------------------------------------------------------------------------
+/openils/bin/srfsh
+srfsh% login <admin-user> <admin-pass>
+------------------------------------------------------------------------------
+
+You should see a result like:
+
+    Received Data: "250bf1518c7527a03249858687714376"
+    ------------------------------------
+    Request Completed Successfully
+    Request Time in seconds: 0.045286
+    ------------------------------------
+
+    Received Data: {
+       "ilsevent":0,
+       "textcode":"SUCCESS",
+       "desc":" ",
+       "pid":21616,
+       "stacktrace":"oils_auth.c:304",
+       "payload":{
+          "authtoken":"e5f9827cc0f93b503a1cc66bee6bdd1a",
+          "authtime":420
+       }
+
+    }
+
+    ------------------------------------
+    Request Completed Successfully
+    Request Time in seconds: 1.336568
+    ------------------------------------
+
+If this does not work, it's time to do some troubleshooting.
+
+  * As the *opensrf* Linux account, run the `settings-tester.pl` script to see
+    if it finds any system configuration problems. The script is found at
+    `Open-ILS/src/support-scripts/settings-tester.pl` in the Evergreen source
+    tree.
+  * Follow the steps in the http://evergreen-ils.org/dokuwiki/doku.php?id=troubleshooting:checking_for_errors[troubleshooting guide].
+  * If you have faithfully followed the entire set of installation steps
+    listed here, you are probably extremely close to a working system.
+    Gather your configuration files and log files and contact the
+    http://evergreen-ils.org/communicate/mailing-lists/[Evergreen development 
+mailing list] for assistance before making any drastic changes to your system
+    configuration.
+
+Getting help
+------------
+
+Need help installing or using Evergreen? Join the mailing lists at
+http://evergreen-ils.org/communicate/mailing-lists/ or contact us on the Freenode
+IRC network on the #evergreen channel.
+
+License
+-------
+This work is licensed under the Creative Commons Attribution-ShareAlike 3.0
+Unported License. To view a copy of this license, visit
+http://creativecommons.org/licenses/by-sa/3.0/ or send a letter to Creative
+Commons, 444 Castro Street, Suite 900, Mountain View, California, 94041, USA.
diff --git a/configure.ac b/configure.ac
index 99370e4..127413e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -20,8 +20,8 @@
 
 export PATH=${PATH}:/usr/sbin
 AC_PREREQ(2.61)
-AC_INIT(Open-ILS, trunk, open-ils-dev at list.georgialibraries.org)
-AM_INIT_AUTOMAKE([OpenILS], [trunk])
+AC_INIT(Open-ILS, 2.6.0, open-ils-dev at list.georgialibraries.org)
+AM_INIT_AUTOMAKE([OpenILS], [2.6.0])
 AC_REVISION($Revision: 0.1 $)
 AC_CONFIG_SRCDIR([configure.ac])
 AC_CONFIG_SUBDIRS([Open-ILS/xul/staff_client/external/libmar])

commit 659a07064a6ba60029f51de375aadd61bfb994ca
Author: Dan Scott <dscott at laurentian.ca>
Date:   Wed Apr 16 10:42:49 2014 -0400

    LP#1308590 Fix schema.org type mapping
    
    The switch to config.coded_value_map for format icon types and labels
    inadvertently broke schema.org type mapping. Restore it and attempt
    to take advantage of the finer-grained types that are now available
    to us.
    
    Signed-off-by: Dan Scott <dscott at laurentian.ca>
    Signed-off-by: Galen Charlton <gmc at esilibrary.com>

diff --git a/Open-ILS/src/templates/opac/parts/misc_util.tt2 b/Open-ILS/src/templates/opac/parts/misc_util.tt2
index 63b82b4..4a0cf58 100644
--- a/Open-ILS/src/templates/opac/parts/misc_util.tt2
+++ b/Open-ILS/src/templates/opac/parts/misc_util.tt2
@@ -91,9 +91,35 @@
         # Map item types to schema.org types; impedance mismatch :(
         args.schema.itemtype = {};
         schema_typemap = {};
-        schema_typemap.a = 'http://schema.org/Book';
-        schema_typemap.e = 'http://schema.org/Map';
-        schema_typemap.j = 'http://schema.org/MusicAlbum';
+
+        schema_typemap.bluray = 'Movie'; # Movie could also be TVSeries
+        schema_typemap.book = 'Book';
+        schema_typemap.braille = 'Book';
+        schema_typemap.casaudiobook = 'Book AudioObject';
+        schema_typemap.casmusic = 'MusicAlbum';
+        schema_typemap.cdaudiobook = 'Book AudioObject';
+        schema_typemap.cdmusic = 'MusicAlbum';
+        schema_typemap.dvd = 'Movie';
+        schema_typemap.eaudio = 'AudioObject';
+        schema_typemap.ebook = 'Book';
+        # schema_typemap.equip = '';
+        schema_typemap.evideo = 'Movie';
+        # schema_typemap.kit = '';
+        schema_typemap.lpbook = 'Book';
+        schema_typemap.map = 'Map';
+        # schema_typemap.microform = '';
+        schema_typemap.music = 'MusicAlbum';
+        schema_typemap.phonomusic = 'MusicAlbum';
+        # schema_typemap.phonospoken = '';
+        # schema_typemap.picture = ''; Painting or Photograph?
+        schema_typemap.score = 'Book'; # schema.org has no generic Music type
+        schema_typemap.serial = 'Periodical';
+        schema_typemap.software = 'SoftwareApplication';
+        schema_typemap.vhs = 'Movie';
+
+        schema_typemap.a = 'Book';
+        schema_typemap.e = 'Map';
+        schema_typemap.j = 'MusicAlbum';
 
         # Hard-coded to match defaults in config.copy_status for all OPAC-visible statuses
         schema_copy_status = {};
@@ -438,7 +464,7 @@
                 NEXT IF ccvm.opac_visible == 'f';
 
                 format = {};
-                type = node.textContent;
+                type = ccvm.code.remove('-'); # blu-ray to bluray
                 format.label = ccvm.search_label || ccvm.value;
                 format.icon = PROCESS get_ccvm_icon ccvm=ccvm;
                 format.itemtype = schema_typemap.$type || 'CreativeWork';

commit 11e4e20c2a2d6e5a66278b49b5c3434c087f1d96
Author: Dan Wells <dbw2 at calvin.edu>
Date:   Wed Apr 16 09:56:53 2014 -0400

    Compile and Tweak Release Notes for 2.6.0
    
    Also, add '.txt' to template name, since our build process expects
    and uses that extension.
    
    Signed-off-by: Dan Wells <dbw2 at calvin.edu>

diff --git a/docs/RELEASE_NOTES_2_6.txt b/docs/RELEASE_NOTES_2_6.txt
new file mode 100644
index 0000000..1f370f4
--- /dev/null
+++ b/docs/RELEASE_NOTES_2_6.txt
@@ -0,0 +1,557 @@
+Evergreen 2.6 Release Notes
+===========================
+:toc:
+:numbered:
+
+Upgrade notes
+-------------
+
+OPAC
+~~~~
+
+TPAC library pages
+^^^^^^^^^^^^^^^^^^
+Evergreen 2.5 introduced the `Library information URL` library setting to
+associate a web page with a library. If set, this value was used as the target
+of the library link in the copy table on the record details page. However, the
+new default behavior is to link to the automatically generated TPAC library
+page, which in turn links to the external web site.
+
+If you wish to maintain the previous behavior, you can set the `Use external
+library information URL` library setting to `True`.
+
+
+Disable Autosuggest by Default
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+As described in https://bugs.launchpad.net/evergreen/+bug/1187993, the 
+community is aware of ongoing accessibility issues caused through use of 
+the autosuggest feature of the Evergreen catalog. The decision has been 
+made to disable autosuggest by default for new installations. Existing sites
+are cautioned to take note of this change and decide for themselves whether
+to discontinue use.
+
+It is possible to disable the autosuggest feature via a global flag. Look in
+`Admin -> Server Administration -> Global Flags`, find the `OPAC: Show
+auto-completing suggestions dialog...` setting, then edit and uncheck the
+`Enabled` box.
+
+
+
+Miscellaneous
+~~~~~~~~~~~~~
+
+Removal of open-ils.ingest service
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+The open-ils.ingest service is no longer required, and has been
+removed.
+
+You should update your opensrf.xml file to remove references to
+open-ils.ingest, and you may also wish to remove the
+OpenILS/Application/Ingest.pm file from your Perl @INC path.
+
+In opensrf.xml, remove the entire <open-ils.ingest> element from the
+<apps> element, and remove <appname>open-ils.ingest</appname> from
+any <activeapps> elements where it is present.
+
+If you have the perldoc command installed, you can use the following
+command to locate the path on disk of the Ingest.pm file, which is
+no longer required and can be removed:
+
+[source, bash]
+-----------------------------------------------------------------
+perldoc -l OpenILS::Application::Ingest
+-----------------------------------------------------------------
+
+
+Reporter view 'classic_current_circ' dropped
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+As part of the DB upgrade, the reporter view
+"reporter.classic_current_circ" was dropped.  If you previously
+installed this view from example.reporter-extension.sql, it will
+have to be re-installed by executing the "CREATE OR REPLACE
+VIEW reporter.classic_current_circ AS..." SQL once again from
+example.reporter-extension.sql.
+
+
+
+New Features
+------------
+
+Administration
+~~~~~~~~~~~~~~
+
+Add granular settings for requiring staff initials for notes
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+There are now three separate library settings for controlling whether staff 
+are required to input their initials when creating different types of notes.
+See new library settings below.
+
+Any pre-existing library setting for requiring staff initials are preserved 
+during the upgrade process. After upgrading, you may choose to change the set
+behavior for any of the three new settings.
+
+New Library Settings
++++++++++++++++++++++
+ * Require staff initials for entry/edit of patron standing penalties and messages. (ui.staff.require_initials.patron_standing_penalty)
+ * Require staff initials for entry/edit of patron notes. (ui.staff.require_initials.patron_info_notes)
+ * Require staff initials for entry/edit of copy notes. (ui.staff.require_initials.copy_notes)
+
+
+Cataloging
+~~~~~~~~~~
+
+Enhancements to Evergreen's MARC Editor Concerning Fixed Fields
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+This work is a combination of two features. One provides suggested
+values in a right-click context menus for fixed field values based on
+the 'type' of the record being edited. The other provides a wizard to
+help specifically with the Physical Characteristics of the record, i.e.
+the 007 field.
+
+Right-Click Context Menus
++++++++++++++++++++++++++
+Users will be able to right-click on the value control for fixed fields
+in the MARC Editor, and Evergreen will provide a menu from which the
+user can select a possible value. This will work for fixed fields where
+Evergreen already contains information from the Library of Congress's
+MARC 21 standard.
+
+Example:
+
+image::media/ffer-right-click.png["Right-clicking the BLvl field"]
+
+Evergreen already comes loaded with information from the Library of
+Congress's MARC 21 standard on possible values for some fixed fields.
+
+The following table shows which fixed fields for which 'Record Types'
+have values already loaded into Evergreen.
+
+---------------------------------------------------------
+
+ Fixed Field |          Record Types
+-------------+-----------------------------------
+ Audn        | {BKS,COM,REC,SCO,SER,VIS}
+ BLvl        | {BKS,COM,MAP,MIX,REC,SCO,SER,VIS}
+ Form        | {BKS,MAP,MIX,REC,SCO,SER,VIS}
+ Lang        | {BKS,COM,MAP,MIX,REC,SCO,SER,VIS}
+ LitF        | {BKS}
+ Type        | {BKS,COM,MAP,MIX,REC,SCO,SER,VIS}
+
+
+---------------------------------------------------------
+
+A 'Record Type' is itself a combination of the 'Type of Record' (fixed
+field name: Type) and 'Bibliographic Level' (fixed field name: BLvl)
+elements of the MARC leader (positions 06 and 07 respectively). You can
+see a record's Record Type in the MARC Editor as shown in
+this screenshot:
+
+'Record Type':
+
+image::media/ffer-record-type.png["This Record Type is REC"]
+
+A user may add values to these fixed fields as well as to other fixed
+fields through the MARC Coded Value Maps interface found under the Admin
+-> Server Administration menu in the staff client. These are grouped by
+Record Attribute Types (a superset of fixed fields) which have labels
+such as 'Alph', 'Biog', 'Videorecording format', and 'Language'.
+
+From LOC Fixed Fields documentation, 'Alph' is 'Original alphabet or
+script of title', 'Biog' is 'Biography', 'Videorecording format' is from
+the 007 field, 'Language' is positions 35-37 of the 008, and so on.
+Other Record Attribute Types such as 'Author' are, of course, not fixed
+fields at all.
+
+When users add new values here, the right-click context menus of the
+fixed fields in the MARC Editor will include those values.
+
+All values added for any fixed field in the Coded Value Map will display
+for any 'Record Type' that uses that fixed field.
+
+Users of the MARC Editor always retain the option of leaving a fixed
+field blank, entering the special values # or |, or entering a value not
+provided by the right-click context menu.
+
+Physical Characteristics Wizard
++++++++++++++++++++++++++++++++
+By right-clicking on an existing or new 007 field in the MARC Editor, users
+will be able to enter a wizard that leads them step-by-step through the
+positions in that 007 field, telling them the significance of the current
+position and providing a drop-down list of possible values.
+
+Launching the Physical Characteristics Wizard:
+
+image::media/ffer-open-wizard.png["Launching the Physical Characteristics Wizard"]
+
+Choosing the Category of Material:
+
+image::media/ffer-007-00.png["Choosing the Category of Material"]
+
+Choosing a value for a later position:
+
+image::media/ffer-007-smd.png["Choosing a value for a later position"]
+
+
+marc_export script replacement
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+The `/openils/bin/marc_export` script is completely rewritten.  This
+new version accepts all of the same command line options as the old
+version as well as some new options.
+
+The rewritten `marc_export` talks directly to your Evergreen database
+and is a great deal faster than the previous version.  Because the new
+script talks directly to the database, it needs to know how to
+connect.  To facilitate this, a new option, `--store`, was added that
+allows the user to specify one of three Evergreen storage backends to
+use when exporting records.  The valid choices are `reporter`,
+`cstore`, or `storage`.  The default of `reporter` should work in most
+cases, but if you do have a separate reporter database and you know
+you want to talk directly to your main production database, then you
+will probably want to choose either `cstore` or `storage`.
+
+In addition to the `--store` option, a `--since` option is also added
+so that you can specify output of an update file of records changed,
+added, and/or deleted since the given date.  The `--since` option uses
+a fairly flexible date parser and can accept a wide range of date
+formats including ISO 8601, man common date formats such as M/D/Y
+(common in the US) or D/Mon/Y (with the first 3 characters or more of
+the month spelled out), as well as several less common date formats.
+Special date strings such as `yesterday`, `today`, `yesterday week`,
+and `today week` are also supported.  For more information see the
+VALID DATE FORMATS section of the `Date::Manip::Date` man page.
+Available online here:
+
+http://search.cpan.org/~sbeck/Date-Manip-6.42/lib/Date/Manip/Date.pod#VALID_DATE_FORMATS
+
+There is one final difference between the new script and the old
+`marc_export`.  The new script does not output progress as it
+executes.  Many of the statistics that the script reported are not
+readily available to the new script.  It was deemed better to just not
+output any progress rather than to output something different from the
+old program.  If your scripts parse the output from `marc_export`,
+they will need to modified not to expect any.
+
+
+Circulation
+~~~~~~~~~~~
+
+Lost Item Billing: New Min/Max Price Settings
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+When an item is marked lost, the user is typically billed for the item.
+In Evergreen, they can either be charged the amount recorded in the item
+object, or if that value is blank (or zero), charged a default price
+(controlled by settings).
+
+In addition to these existing settings, now we can accommodate a range of
+prices by saying the patron should be billed at least 'X' and not more
+than 'Y'. This also allows you to effectively set a fixed price for all
+lost items by setting min and max to the same amount.
+
+New Org Unit Settings
++++++++++++++++++++++
+ * Minimum Item Price: circ.min_item_price
+ * Maximum Item Price: circ.max_item_price
+
+New Permissions
++++++++++++++++
+ * UPDATE_ORG_UNIT_SETTING.circ.min_item_price
+ * UPDATE_ORG_UNIT_SETTING.circ.max_item_price
+
+
+User Editor: "Update Expire Date" button
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+A new button labeled "Update Expire Date" is added in the user
+editor next to expire date field. This button can be used to
+re-calculate the user's expire date based on the current profile's
+permission interval and today's date.
+
+This is similar to how the expire date is populated when creating a
+new user, or when changing the profile group.
+
+This button simplifies the process of "renewing" a user, by
+eliminating the requirement that staff manually enter a new expire
+date.
+
+A button is used here so that the updating of the expire date
+remains an  intentional process, not one that happens upon any edit.
+
+
+OPAC
+~~~~
+
+Composite Record Attributes
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+With this feature we create an abstraction on top of the Record Attribute
+infrastructure to allow the aggregation of multiple, cross-Attribute values
+under a single search filter value, accessible through new, dynamic filters.
+
+Each QueryParser filter will be created by the addition of a Composite Record
+Attribute Definition. For instance, one may wish to create a Composite Record
+Attribute Definition for an abstract "Item Type" interface component that
+uses information from the item_type, vr_format, bib_level and item_form
+Record Attribute Definitions, with each Composite Record Attribute Value
+having a different combination of Record Attribute Values from some or all of
+these Record Attribute Definitions. In this way, as single interface
+component might be presented as a dropdown with options such as "All Books",
+"All video recordings", "DVDs", "VHS Tapes", "E-Books", "Audio Books" and
+"Large Print Books". Of particular note are the "DVDs" and "VHS Tapes"
+entries, which include information from Record Attribute Definitions
+completely separate from the others. Additionally, the Composite Record
+Attribute Values defined by this Composite Record Attribute Definition
+can be used to drive behavioral logic, such as alternate icon display or
+link generation, in upgrade-friendly template adjustments.
+
+Included in this development is a replacement for the single-attribute
+Format filter supplied for basic search.  Instead, a Composite Attribute
+is used to combine the values from Item Type, Item Form and Videorecording
+Format in various ways that provide a more patron-friendly set of choices.
+
+This new Format filter can be adjusted, or even replaced with a completely
+local one, through configuration and without template adjustment.
+
+
+
+Located URI visibility options
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Before this, Evergreen restricted the visibility of bibliographic records
+that make use of Located URIs in a way that attempts to model licensing
+restrictions.
+
+There now exists a global flag to allow sites the option of changing the
+behaviour of Located URIs so that they act in a way analogous to copies
+for visibility testing.  When the opac.located_uri.act_as_copy global flag
+is enabled, Located URIs will cause their containing bib records to become
+visible in searches where the URI is in scope to either ancestors of the
+search library, as before, or descendents of the search library, as copies
+do.  As before, if a preferred library is supplied by the user, it is
+added to the list of visible org units to check.
+
+Additionally, while the underlying UnAPI and supporting code was capable
+of providing a reasonable and logical sort order for the Located URIs when
+embedded as XML holdings elements, the client-facing UnAPI method was not
+making use of that.  It now does, and uses the same sorting algorithm as
+is used for copies.
+
+
+Multi-valued Record Attributes and Controlled Record Attributes
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Having identified common use cases and reasonable restrictions that can be
+placed on the feature set, we have extended the Record Attribute
+infrastructure to support both the extraction and storage of all instances
+of a defined Attribute found within a bibliographic record, as well as
+provide new and more powerful indexing of existing data, in several ways.
+
+Record Attributes can now be defined by configuration as either single-valued
+or multi-valued. For any Attribute configured as single-valued, only the
+first value extracted from a record will be stored. This configuration
+parameter and restriction is in place to support potential query
+optimizations based on foreknowledge of whether a given Attribute is multi-
+valued or not.
+
+Record Attributes will be defined by configuration as either controlled or
+uncontrolled. A controlled Record Attribute is one that has entries in the
+Coded Value Map infrastructure specifying the valid values the record may
+carry for this attribute. If defined as a controlled Attribute, any unknown
+values extracted from a record will be ignored. Uncontrolled Attributes,
+however, may contain any value. This configuration parameter and restriction
+also supports potential query optimization.
+
+We store uncontrolled attribute values in a new table with a monotonically
+decreasing ID sequence, separating it from controlled values, reducing storage
+requirements by retaining only unique values, and making lookup faster.
+
+Restrictions
+++++++++++++
+ * A Record Attribute's values must match Coded Value Map entries if it is to be a Controlled Attribute. Coded Value Map control is indicated by a new "controlled" boolean on the config.record_attr_definition table.
+ * Record Attributes must "opt in" to multi-valued-ness. Record Attributes will opt in via a new "multi" boolean on config.record_attr_definition; this restriction enforces site config requirements by being explicit about the definition of "multi" fields.
+ * If controlled but not opt'd in to multi-mode, only the first value will be recorded but the new search mechanism will be used.
+ * Only single-valued Record Attributes will be available for use by the system as Sort Axes.
+ * Only controlled Record Attributes will be available for use by the TPAC as dynamically generated filter UI components, such as filter dropdowns or multi-selects.
+
+New External Dependency
++++++++++++++++++++++++
+This new feature requires the addition of the intarray extension to Postgres.
+This is a stock extension available on most linux distributions via the same
+package as the already-required plperl extension.
+
+
+Restore OpenSearch Support
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+Restore previously held functionality from JSPAC to support OpenSearch in TPAC. 
+This allows users to easily add the Evergreen search engine to their browser's 
+built-in set of search engines.
+
+
+Accepting payments with Stripe
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Stripe is a payment processing service that lets
+sites take credit card payments without payment card information ever
+touching the sites' own servers.
+
+NOTE: Using Stripe as a payment processor means that clients *must*
+have Javascript enabled in order to submit fine payments through your
+OPAC.
+
+Library Settings
+++++++++++++++++
+The following settings need to be set at the appropriate org level for
+sites wanting to use Stripe.
+
+ * "Allow Credit Card Payments" (should be 'true')
+
+   credit.payments.allow
+
+ * "Enable Stripe payments" (should be 'true')
+
+   credit.processor.stripe.enabled
+
+ * "Stripe publishable key" (value provided by Stripe)
+
+   credit.processor.stripe.pubkey
+
+ * "Stripe secret key" (value provided by Stripe)
+
+   credit.processor.stripe.secretkey
+
+ * "Name default credit processor" (should be 'Stripe')
+
+   credit.processor.default
+
+
+TPAC library pages
+^^^^^^^^^^^^^^^^^^
+This feature adds one web page per library in the system to the TPAC at
+http://hostname/eg/opac/library/<SHORTNAME> and
+http://hostname/eg/opac/library/<ID>. The pages publish the following
+information from Evergreen (if available):
+
+* Name of the library
+* Link to the lbrary web site (from `Library Information URL` library setting)
+* Opening hours
+* Email address
+* Phone number
+* Mailing address
+* Link to parent library (if applicable)
+
+Library pages are linked from the copy table on the record details page.
+
+Structured data
++++++++++++++++
+The library web pages publish schema.org structured data, which can enable
+search engines and other systems to better understand your libraries and their
+resources.
+
+
+TPAC Metarecord Search and Holds
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+This feature adds support for searching and placing holds against 
+metarecords.
+
+Metarecord Searching
+++++++++++++++++++++
+In the top search bar and in the advanced search page, there is a new
+search modifier labeled "Group Formats and Editions".  When selected,
+searches are performed against metarecords and metarecords are shown
+in the results list.
+
+For each metarecord, format icons for all constituent records are shown.
+When a use clicks on a metarecord, if the metarecord has multiple
+constituent records, the user is taken to the constituent records
+list.  Similarly, when a metarecord only has one constituent record,
+the user is directed to the record detail page for the constituent
+record.
+
+Metarecord Holds
+++++++++++++++++
+Clicking the place hold link from the metarecord results page shows
+the available formats and languages for the metarecord, allowing
+the user to limit the scope of the hold.  Non-metarecord holds now
+get a new "Advanced Holds Options" link which allows user to promote
+a title hold to a metarecord hold, thus providing access 
+to the formats / editions selector, before the hold is placed.
+
+In the My Account holds list, icons for all selected formats are 
+displayed in the Format columns for the hold.  When editing a 
+metarecord hold, users may modify the desired formats and languages.
+
+Configuration
++++++++++++++
+Admins may disable this feature by un-commenting the "metarecord.disabled"
+attribute in config.tt2
+
+
+Web Content Accessibility Guidelines (WCAG) Compliance
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+To make the catalog more accessible to users with a range of disabilities,
+including blindness and low vision, the catalog has been revised to better
+comply with the Web Content Accessibility Guidelines (WCAG) 2.0. These
+revisions target level "AA" of compliance.
+
+For more information on WCAG, see http://www.w3.org/WAI/intro/wcag
+
+
+Acknowledgments
+---------------
+The Evergreen project would like to acknowledge the following
+organizations who commissioned developments in this release of
+Evergreen:
+
+ * Butler Public Library, IN, USA
+ * British Columbia Libraries Cooperative
+ * Carnegie Public Library of Steuben County, IN, USA
+ * Centerville-Center Township Public Library, IN, USA
+ * Flora Public Library, IN, USA
+ * Hagerstown - Jefferson Township Library, IN, USA
+ * Howe Library, Hanover, NH, USA
+ * Massachusetts Library Network Cooperative
+ * Newton County Public Library, IN, USA
+ * Noble County Public Library, IN, USA
+ * Natural Resources Canada
+ * North of Boston Library Exchange
+ * Perry County Public Library, IN, USA
+ * Plainfield-Guilford Township Public Library, IN, USA
+ * Rodgers Memorial Library, Hudson, NH, USA
+ * Statistics Canada
+ * Union County Public Library, IN, USA
+ * Westfield Washington Public Library, IN, USA
+
+We would also like to thank the following individuals who contributed
+code and documentations patches to this release of Evergreen:
+
+ * Jason Boyer
+ * Galen Charlton
+ * Mark Cooper
+ * Bill Erickson
+ * Jason Etheridge
+ * Lebbeous Fogle-Weekley
+ * Jeff Godin
+ * Pasi Kallinen
+ * Mike Rylander
+ * Dan Scott
+ * Chris Sharp
+ * Ben Shum
+ * Remington Steed
+ * Jason Stephenson
+ * Yamil Suarez
+ * Elliot Voris
+ * Dan Wells
+
+We also thank the following organizations whose employees contributed
+patches:
+
+ * Berklee College of Music
+ * Bibliomation
+ * Calvin College
+ * Equinox Software, Inc.
+ * Georgia Public Library Service
+ * Indiana State Library
+ * Laurentian University
+ * Merrimack Valley Library Consortium
+ * Pohjois-Karjalan Tietotekniikkakeskus Oy
+ * Saint Louis Christian College
+ * Traverse Area District Library
+
+We regret any omissions.  If a contributor has been inadvertantly
+missed, please open a bug at http://bugs.launchpad.net/evergreen/
+with a correction.
+
diff --git a/docs/RELEASE_NOTES_NEXT/Administration/staff-initials.txt b/docs/RELEASE_NOTES_NEXT/Administration/staff-initials.txt
deleted file mode 100644
index b0ae98b..0000000
--- a/docs/RELEASE_NOTES_NEXT/Administration/staff-initials.txt
+++ /dev/null
@@ -1,18 +0,0 @@
-Add granular settings for requiring staff initials for notes
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-There are now three separate library settings for controlling whether staff 
-are required to input their initials when creating different types of notes.
-See new library settings below.
-
-Any pre-existing library setting for requiring staff initials are preserved 
-during the upgrade process. After upgrading, you may choose to change the set
-behavior for any of the three new settings.
-
-New Library Settings
-+++++++++++++++++++++
-
- * Require staff initials for entry/edit of patron standing penalties and messages. (ui.staff.require_initials.patron_standing_penalty)
- * Require staff initials for entry/edit of patron notes. (ui.staff.require_initials.patron_info_notes)
- * Require staff initials for entry/edit of copy notes. (ui.staff.require_initials.copy_notes)
-
diff --git a/docs/RELEASE_NOTES_NEXT/Cataloging/fixed_fields_enhancements.txt b/docs/RELEASE_NOTES_NEXT/Cataloging/fixed_fields_enhancements.txt
deleted file mode 100644
index 1ef3859..0000000
--- a/docs/RELEASE_NOTES_NEXT/Cataloging/fixed_fields_enhancements.txt
+++ /dev/null
@@ -1,98 +0,0 @@
-= Enhancements to Evergreen's MARC Editor Concerning Fixed Fields =
-
-
-This work is a combination of two features. One provides suggested
-values in a right-click context menus for fixed field values based on
-the 'type' of the record being edited. The other provides a wizard to
-help specifically with the Physical Characteristics of the record, i.e.
-the 007 field.
-
-== Right-Click Context Menus ==
-
-Users will be able to right-click on the value control for fixed fields
-in the MARC Editor, and Evergreen will provide a menu from which the
-user can select a possible value. This will work for fixed fields where
-Evergreen already contains information from the Library of Congress's
-MARC 21 standard.
-
-Example:
-
-image::media/ffer-right-click.png["Right-clicking the BLvl field"]
-
-Evergreen already comes loaded with information from the Library of
-Congress's MARC 21 standard on possible values for some fixed fields.
-
-The following table shows which fixed fields for which 'Record Types'
-have values already loaded into Evergreen.
-
----------------------------------------------------------
-
- Fixed Field |          Record Types
--------------+-----------------------------------
- Audn        | {BKS,COM,REC,SCO,SER,VIS}
- BLvl        | {BKS,COM,MAP,MIX,REC,SCO,SER,VIS}
- Form        | {BKS,MAP,MIX,REC,SCO,SER,VIS}
- Lang        | {BKS,COM,MAP,MIX,REC,SCO,SER,VIS}
- LitF        | {BKS}
- Type        | {BKS,COM,MAP,MIX,REC,SCO,SER,VIS}
-
-
----------------------------------------------------------
-
-A 'Record Type' is itself a combination of the 'Type of Record' (fixed
-field name: Type) and 'Bibliographic Level' (fixed field name: BLvl)
-elements of the MARC leader (positions 06 and 07 respectively). You can
-see a record's Record Type in the MARC Editor as shown in
-this screenshot:
-
-'Record Type':
-
-image::media/ffer-record-type.png["This Record Type is REC"]
-
-A user may add values to these fixed fields as well as to other fixed
-fields through the MARC Coded Value Maps interface found under the Admin
--> Server Administration menu in the staff client. These are grouped by
-Record Attribute Types (a superset of fixed fields) which have labels
-such as 'Alph', 'Biog', 'Videorecording format', and 'Language'.
-
-From LOC Fixed Fields documentation, 'Alph' is 'Original alphabet or
-script of title', 'Biog' is 'Biography', 'Videorecording format' is from
-the 007 field, 'Language' is positions 35-37 of the 008, and so on.
-Other Record Attribute Types such as 'Author' are, of course, not fixed
-fields at all.
-
-When users add new values here, the right-click context menus of the
-fixed fields in the MARC Editor will include those values.
-
-All values added for any fixed field in the Coded Value Map will display
-for any 'Record Type' that uses that fixed field.
-
-Users of the MARC Editor always retain the option of leaving a fixed
-field blank, entering the special values # or |, or entering a value not
-provided by the right-click context menu.
-
-== Physical Characteristics Wizard ==
-
-By right-clicking on an existing or new 007 field in the MARC Editor, users
-will be able to enter a wizard that leads them step-by-step through the
-positions in that 007 field, telling them the significance of the current
-position and providing a drop-down list of possible values.
-
-Launching the Physical Characteristics Wizard:
-
-image::media/ffer-open-wizard.png["Launching the Physical Characteristics Wizard"]
-
-Choosing the Category of Material:
-
-image::media/ffer-007-00.png["Choosing the Category of Material"]
-
-Choosing a value for a later position:
-
-image::media/ffer-007-smd.png["Choosing a value for a later position"]
-
-
-////
-vim: ft=asciidoc
-////
-
-
diff --git a/docs/RELEASE_NOTES_NEXT/Cataloging/marc_export_replacement.txt b/docs/RELEASE_NOTES_NEXT/Cataloging/marc_export_replacement.txt
deleted file mode 100644
index 6202726..0000000
--- a/docs/RELEASE_NOTES_NEXT/Cataloging/marc_export_replacement.txt
+++ /dev/null
@@ -1,39 +0,0 @@
-marc_export script replacement
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-The `/openils/bin/marc_export` script is completely rewritten.  This
-new version accepts all of the same command line options as the old
-version as well as some new options.
-
-The rewritten `marc_export` talks directly to your Evergreen database
-and is a great deal faster than the previous version.  Because the new
-script talks directly to the database, it needs to know how to
-connect.  To facilitate this, a new option, `--store`, was added that
-allows the user to specify one of three Evergreen storage backends to
-use when exporting records.  The valid choices are `reporter`,
-`cstore`, or `storage`.  The default of `reporter` should work in most
-cases, but if you do have a separate reporter database and you know
-you want to talk directly to your main production database, then you
-will probably want to choose either `cstore` or `storage`.
-
-In addition to the `--store` option, a `--since` option is also added
-so that you can specify output of an update file of records changed,
-added, and/or deleted since the given date.  The `--since` option uses
-a fairly flexible date parser and can accept a wide range of date
-formats including ISO 8601, man common date formats such as M/D/Y
-(common in the US) or D/Mon/Y (with the first 3 characters or more of
-the month spelled out), as well as several less common date formats.
-Special date strings such as `yesterday`, `today`, `yesterday week`,
-and `today week` are also supported.  For more information see the
-VALID DATE FORMATS section of the `Date::Manip::Date` man page.
-Available online here:
-
-http://search.cpan.org/~sbeck/Date-Manip-6.42/lib/Date/Manip/Date.pod#VALID_DATE_FORMATS
-
-There is one final difference between the new script and the old
-`marc_export`.  The new script does not output progress as it
-executes.  Many of the statistics that the script reported are not
-readily available to the new script.  It was deemed better to just not
-output any progress rather than to output something different from the
-old program.  If your scripts parse the output from `marc_export`,
-they will need to modified not to expect any.
diff --git a/docs/RELEASE_NOTES_NEXT/Circulation/lost_min_max_item_pricing.txt b/docs/RELEASE_NOTES_NEXT/Circulation/lost_min_max_item_pricing.txt
deleted file mode 100644
index 7ae826d..0000000
--- a/docs/RELEASE_NOTES_NEXT/Circulation/lost_min_max_item_pricing.txt
+++ /dev/null
@@ -1,24 +0,0 @@
-Lost Item Billing: New Min/Max Price Settings
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-When an item is marked lost, the user is typically billed for the item.
-In Evergreen, they can either be charged the amount recorded in the item
-object, or if that value is blank (or zero), charged a default price
-(controlled by settings).
-
-In addition to these existing settings, now we can accommodate a range of
-prices by saying the patron should be billed at least 'X' and not more
-than 'Y'. This also allows you to effectively set a fixed price for all
-lost items by setting min and max to the same amount.
-
-New Org Unit Settings
-+++++++++++++++++++++
-
- * Minimum Item Price: circ.min_item_price
- * Maximum Item Price: circ.max_item_price
-
-New Permissions
-+++++++++++++++
-
- * UPDATE_ORG_UNIT_SETTING.circ.min_item_price
- * UPDATE_ORG_UNIT_SETTING.circ.max_item_price
diff --git a/docs/RELEASE_NOTES_NEXT/Circulation/user_editor_update_expire_date_button.txt b/docs/RELEASE_NOTES_NEXT/Circulation/user_editor_update_expire_date_button.txt
deleted file mode 100644
index 1b66ade..0000000
--- a/docs/RELEASE_NOTES_NEXT/Circulation/user_editor_update_expire_date_button.txt
+++ /dev/null
@@ -1,17 +0,0 @@
-User Editor: "Update Expire Date" button
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-A new button labeled "Update Expire Date" is added in the user
-editor next to expire date field. This button can be used to
-re-calculate the user's expire date based on the current profile's
-permission interval and today's date.
-
-This is similar to how the expire date is populated when creating a
-new user, or when changing the profile group.
-
-This button simplifies the process of "renewing" a user, by
-eliminating the requirement that staff manually enter a new expire
-date.
-
-A button is used here so that the updating of the expire date
-remains an  intentional process, not one that happens upon any edit.
-
diff --git a/docs/RELEASE_NOTES_NEXT/OPAC/Composite_Record_Attributes.txt b/docs/RELEASE_NOTES_NEXT/OPAC/Composite_Record_Attributes.txt
deleted file mode 100644
index 6fade74..0000000
--- a/docs/RELEASE_NOTES_NEXT/OPAC/Composite_Record_Attributes.txt
+++ /dev/null
@@ -1,40 +0,0 @@
-Composite Record Attributes
-^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-With this feature we create an abstraction on top of the Record Attribute
-infrastructure to allow the aggregation of multiple, cross-Attribute values
-under a single search filter value, accessible through new, dynamic filters.
-
-Each QueryParser filter will be created by the addition of a Composite Record
-Attribute Definition. For instance, one may wish to create a Composite Record
-Attribute Definition for an abstract "Item Type" interface component that
-uses information from the item_type, vr_format, bib_level and item_form
-Record Attribute Definitions, with each Composite Record Attribute Value
-having a different combination of Record Attribute Values from some or all of
-these Record Attribute Definitions. In this way, as single interface
-component might be presented as a dropdown with options such as "All Books",
-"All video recordings", "DVDs", "VHS Tapes", "E-Books", "Audio Books" and
-"Large Print Books". Of particular note are the "DVDs" and "VHS Tapes"
-entries, which include information from Record Attribute Definitions
-completely separate from the others. Additionally, the Composite Record
-Attribute Values defined by this Composite Record Attribute Definition
-can be used to drive behavioral logic, such as alternate icon display or
-link generation, in upgrade-friendly template adjustments.
-
-Included in this development is a replacement for the single-attribute
-Format filter supplied for basic search.  Instead, a Composite Attribute
-is used to combine the values from Item Type, Item Form and Videorecording
-Format in various ways that provide a more patron-friendly set of choices.
-
-This new Format filter can be adjusted, or even replaced with a completely
-local one, through configuration and without template adjustment.
-
-Upgrade Notes
-+++++++++++++
-
-As part of the DB upgrade, the reporter view
-"reporter.classic_current_circ" was dropped.  If you previously
-installed this view from example.reporter-extension.sql, it will
-have to be re-installed by executing the "CREATE OR REPLACE
-VIEW reporter.classic_current_circ AS..." SQL once again from
-example.reporter-extension.sql.
diff --git a/docs/RELEASE_NOTES_NEXT/OPAC/Disable_Autosuggest.txt b/docs/RELEASE_NOTES_NEXT/OPAC/Disable_Autosuggest.txt
deleted file mode 100644
index 9d9dbd6..0000000
--- a/docs/RELEASE_NOTES_NEXT/OPAC/Disable_Autosuggest.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-Disable Autosuggest by Default
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-As described in https://bugs.launchpad.net/evergreen/+bug/1187993, the 
-community is aware of ongoing accessibility issues caused through use of 
-the autosuggest feature of the Evergreen catalog. The decision has been 
-made to disable autosuggest by default for new installations. Existing sites
-are cautioned to take note of this change and decide for themselves whether
-to discontinue use.
-
-It is possible to disable the autosuggest feature by setting the following 
-global flag to false and restarting apache. Look in Admin -> Server 
-Administration -> Global Flags -> OPAC: Show auto-completing suggestions 
-dialog...
diff --git a/docs/RELEASE_NOTES_NEXT/OPAC/Located_URI_visibility.txt b/docs/RELEASE_NOTES_NEXT/OPAC/Located_URI_visibility.txt
deleted file mode 100644
index 4ef9b0e..0000000
--- a/docs/RELEASE_NOTES_NEXT/OPAC/Located_URI_visibility.txt
+++ /dev/null
@@ -1,21 +0,0 @@
-Located URI visibility options
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-Before this, Evergreen restricted the visibility of bibliographic records
-that make use of Located URIs in a way that attempts to model licensing
-restrictions.
-
-There now exists a global flag to allow sites the option of changing the
-behaviour of Located URIs so that they act in a way analogous to copies
-for visibility testing.  When the opac.located_uri.act_as_copy global flag
-is enabled, Located URIs will cause their containing bib records to become
-visible in searches where the URI is in scope to either ancestors of the
-search library, as before, or descendents of the search library, as copies
-do.  As before, if a preferred library is supplied by the user, it is
-added to the list of visible org units to check.
-
-Additionally, while the underlying UnAPI and supporting code was capable
-of providing a reasonable and logical sort order for the Located URIs when
-embedded as XML holdings elements, the client-facing UnAPI method was not
-making use of that.  It now does, and uses the same sorting algorithm as
-is used for copies.
-
diff --git a/docs/RELEASE_NOTES_NEXT/OPAC/Multi_Valued_fields.txt b/docs/RELEASE_NOTES_NEXT/OPAC/Multi_Valued_fields.txt
deleted file mode 100644
index 03ff170..0000000
--- a/docs/RELEASE_NOTES_NEXT/OPAC/Multi_Valued_fields.txt
+++ /dev/null
@@ -1,45 +0,0 @@
-Multi-valued Record Attributes and Controlled Record Attributes
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Having identified common use cases and reasonable restrictions that can be
-placed on the feature set, we have extended the Record Attribute
-infrastructure to support both the extraction and storage of all instances
-of a defined Attribute found within a bibliographic record, as well as
-provide new and more powerful indexing of existing data, in several ways.
-
-Record Attributes can now be defined by configuration as either single-valued
-or multi-valued. For any Attribute configured as single-valued, only the
-first value extracted from a record will be stored. This configuration
-parameter and restriction is in place to support potential query
-optimizations based on foreknowledge of whether a given Attribute is multi-
-valued or not.
-
-Record Attributes will be defined by configuration as either controlled or
-uncontrolled. A controlled Record Attribute is one that has entries in the
-Coded Value Map infrastructure specifying the valid values the record may
-carry for this attribute. If defined as a controlled Attribute, any unknown
-values extracted from a record will be ignored. Uncontrolled Attributes,
-however, may contain any value. This configuration parameter and restriction
-also supports potential query optimization.
-
-We store uncontrolled attribute values in a new table with a monotonically
-decreasing ID sequence, separating it from controlled values, reducing storage
-requirements by retaining only unique values, and making lookup faster.
-
-Restrictions
-++++++++++++
-
- * A Record Attribute's values must match Coded Value Map entries if it is to be a Controlled Attribute. Coded Value Map control is indicated by a new "controlled" boolean on the config.record_attr_definition table.
- * Record Attributes must "opt in" to multi-valued-ness. Record Attributes will opt in via a new "multi" boolean on config.record_attr_definition; this restriction enforces site config requirements by being explicit about the definition of "multi" fields.
- * If controlled but not opt'd in to multi-mode, only the first value will be recorded but the new search mechanism will be used.
- * Only single-valued Record Attributes will be available for use by the system as Sort Axes.
- * Only controlled Record Attributes will be available for use by the TPAC as dynamically generated filter UI components, such as filter dropdowns or multi-selects.
-
-New External Dependency
-+++++++++++++++++++++++
-
-This new feature requires the addition of the intarray extension to Postgres.
-This is a stock extension available on most linux distributions via the same
-package as the already-required plperl extension.
-
-
diff --git a/docs/RELEASE_NOTES_NEXT/OPAC/OpenSearch.txt b/docs/RELEASE_NOTES_NEXT/OPAC/OpenSearch.txt
deleted file mode 100644
index 82e983b..0000000
--- a/docs/RELEASE_NOTES_NEXT/OPAC/OpenSearch.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-Restore OpenSearch Support
-^^^^^^^^^^^^^^^^^^^^^^^^^^
-Restore previously held functionality from JSPAC to support OpenSearch in TPAC. 
-This allows users to easily add the Evergreen search engine to their browser's 
-built-in set of search engines.
diff --git a/docs/RELEASE_NOTES_NEXT/OPAC/TPAC_library_pages.txt b/docs/RELEASE_NOTES_NEXT/OPAC/TPAC_library_pages.txt
deleted file mode 100644
index e9f08b0..0000000
--- a/docs/RELEASE_NOTES_NEXT/OPAC/TPAC_library_pages.txt
+++ /dev/null
@@ -1,33 +0,0 @@
-= TPAC library pages =
-
-This feature adds one web page per library in the system to the TPAC at
-http://hostname/eg/opac/library/<SHORTNAME> and
-http://hostname/eg/opac/library/<ID>. The pages publish the following
-information from Evergreen (if available):
-
-* Name of the library
-* Link to the lbrary web site (from `Library Information URL` library setting)
-* Opening hours
-* Email address
-* Phone number
-* Mailing address
-* Link to parent library (if applicable)
-
-Library pages are linked from the copy table on the record details page.
-
-== Structured data ==
-
-The library web pages publish schema.org structured data, which can enable
-search engines and other systems to better understand your libraries and their
-resources.
-
-== Upgrade notes ==
-
-Evergreen 2.5 introduced the `Library information URL` library setting to
-associate a web page with a library. If set, this value was used as the target
-of the library link in the copy table on the record details page. However, the
-new default behavior is to link to the automatically generated TPAC library
-page, which in turn links to the external web site.
-
-If you wish to maintain the previous behavior, you can set the `Use external
-library information URL` library setting to `True`.
diff --git a/docs/RELEASE_NOTES_NEXT/OPAC/TPAC_metarecords.txt b/docs/RELEASE_NOTES_NEXT/OPAC/TPAC_metarecords.txt
deleted file mode 100644
index da33111..0000000
--- a/docs/RELEASE_NOTES_NEXT/OPAC/TPAC_metarecords.txt
+++ /dev/null
@@ -1,38 +0,0 @@
-= TPAC Metarecord Search and Holds =
-
-This feature adds support for searching and placing holds against 
-metarecords.
-
-== Metarecord Searching ==
-
-In the top search bar and in the advanced search page, there is a new
-search modifier labeled "Group Formats and Editions".  When selected,
-searches are performed against metarecords and metarecords are shown
-in the results list.
-
-For each metarecord, format icons for all constituent records are shown.
-When a use clicks on a metarecord, if the metarecord has multiple
-constituent records, the user is taken to the constituent records
-list.  Similarly, when a metarecord only has one constituent record,
-the user is directed to the record detail page for the constituent
-record.
-
-== Metarecord Holds ==
-
-Clicking the place hold link from the metarecord results page shows
-the available formats and languages for the metarecord, allowing
-the user to limit the scope of the hold.  Non-metarecord holds now
-get a new "Advanced Holds Options" link which allows user to promote
-a title hold to a metarecord hold, thus providing access 
-to the formats / editions selector, before the hold is placed.
-
-In the My Account holds list, icons for all selected formats are 
-displayed in the Format columns for the hold.  When editing a 
-metarecord hold, users may modify the desired formats and languages.
-
-
-== Configuration ==
-
-Admins may disable this feature by un-commenting the "metarecord.disabled"
-attribute in config.tt2
-
diff --git a/docs/RELEASE_NOTES_NEXT/OPAC/WCAG.txt b/docs/RELEASE_NOTES_NEXT/OPAC/WCAG.txt
deleted file mode 100644
index 2cc3098..0000000
--- a/docs/RELEASE_NOTES_NEXT/OPAC/WCAG.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-= Web Content Accessibility Guidelines (WCAG) Compliance =
-
-To make the catalog more accessible to users with a range of disabilities,
-including blindness and low vision, the catalog has been revised to better
-comply with the Web Content Accessibility Guidelines (WCAG) 2.0. These
-revisions target level "AA" of compliance.
-
-For more information on WCAG, see http://www.w3.org/WAI/intro/wcag
diff --git a/docs/RELEASE_NOTES_NEXT/OPAC/stripe_payments.txt b/docs/RELEASE_NOTES_NEXT/OPAC/stripe_payments.txt
deleted file mode 100644
index aac86b3..0000000
--- a/docs/RELEASE_NOTES_NEXT/OPAC/stripe_payments.txt
+++ /dev/null
@@ -1,36 +0,0 @@
-Accepting payments with Stripe
-==============================
-
-Stripe is a payment processing service that lets
-sites take credit card payments without payment card information ever
-touching the sites' own servers.
-
-NOTE: Using Stripe as a payment processor means that clients *must*
-have Javascript enabled in order to submit fine payments through your
-OPAC.
-
-Library Settings
-----------------
-
-The following settings need to be set at the appropriate org level for
-sites wanting to use Stripe.
-
- * "Allow Credit Card Payments" (should be 'true')
-
-   credit.payments.allow
-
- * "Enable Stripe payments" (should be 'true')
-
-   credit.processor.stripe.enabled
-
- * "Stripe publishable key" (value provided by Stripe)
-
-   credit.processor.stripe.pubkey
-
- * "Stripe secret key" (value provided by Stripe)
-
-   credit.processor.stripe.secretkey
-
- * "Name default credit processor" (should be 'Stripe')
-
-   credit.processor.default
diff --git a/docs/RELEASE_NOTES_NEXT/RELEASE_NOTE_TEMPLATE b/docs/RELEASE_NOTES_NEXT/RELEASE_NOTE_TEMPLATE.txt
similarity index 100%
rename from docs/RELEASE_NOTES_NEXT/RELEASE_NOTE_TEMPLATE
rename to docs/RELEASE_NOTES_NEXT/RELEASE_NOTE_TEMPLATE.txt
diff --git a/docs/RELEASE_NOTES_NEXT/_acknowledgments b/docs/RELEASE_NOTES_NEXT/_acknowledgments
index 2768f4a..1694836 100644
--- a/docs/RELEASE_NOTES_NEXT/_acknowledgments
+++ b/docs/RELEASE_NOTES_NEXT/_acknowledgments
@@ -2,60 +2,17 @@ The Evergreen project would like to acknowledge the following
 organizations who commissioned developments in this release of
 Evergreen:
 
- * Butler Public Library, IN, USA
- * British Columbia Libraries Cooperative
- * Carnegie Public Library of Steuben County, IN, USA
- * Centerville-Center Township Public Library, IN, USA
- * Flora Public Library, IN, USA
- * Hagerstown - Jefferson Township Library, IN, USA
- * Howe Library, Hanover, NH, USA
- * Massachusetts Library Network Cooperative
- * Newton County Public Library, IN, USA
- * Noble County Public Library, IN, USA
- * Natural Resources Canada
- * North of Boston Library Exchange
- * Perry County Public Library, IN, USA
- * Plainfield-Guilford Township Public Library, IN, USA
- * Rodgers Memorial Library, Hudson, NH, USA
- * Statistics Canada
- * Union County Public Library, IN, USA
- * Westfield Washington Public Library, IN, USA
+ * **TODO**
 
 We would also like to thank the following individuals who contributed
 code and documentations patches to this release of Evergreen:
 
- * Jason Boyer
- * Galen Charlton
- * Mark Cooper
- * Bill Erickson
- * Jason Etheridge
- * Lebbeous Fogle-Weekley
- * Jeff Godin
- * Pasi Kallinen
- * Mike Rylander
- * Dan Scott
- * Chris Sharp
- * Ben Shum
- * Remington Steed
- * Jason Stephenson
- * Yamil Suarez
- * Elliot Voris
- * Dan Wells
+ * **TODO**
 
 We also thank the following organizations whose employees contributed
 patches:
 
- * Berklee College of Music
- * Bibliomation
- * Calvin College
- * Equinox Software, Inc.
- * Georgia Public Library Service
- * Indiana State Library
- * Laurentian University
- * Merrimack Valley Library Consortium
- * Pohjois-Karjalan Tietotekniikkakeskus Oy
- * Saint Louis Christian College
- * Traverse Area District Library
+ * **TODO**
 
 We regret any omissions.  If a contributor has been inadvertantly
 missed, please open a bug at http://bugs.launchpad.net/evergreen/
diff --git a/docs/RELEASE_NOTES_NEXT/removal_of_ingest.txt b/docs/RELEASE_NOTES_NEXT/removal_of_ingest.txt
deleted file mode 100644
index 863afdf..0000000
--- a/docs/RELEASE_NOTES_NEXT/removal_of_ingest.txt
+++ /dev/null
@@ -1,21 +0,0 @@
-Removal of open-ils.ingest service
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-The open-ils.ingest service is no longer required, and has been
-removed.
-
-You should update your opensrf.xml file to remove references to
-open-ils.ingest, and you may also wish to remove the
-OpenILS/Application/Ingest.pm file from your Perl @INC path.
-
-In opensrf.xml, remove the entire <open-ils.ingest> element from the
-<apps> element, and remove <appname>open-ils.ingest</appname> from
-any <activeapps> elements where it is present.
-
-If you have the perldoc command installed, you can use the following
-command to locate the path on disk of the Ingest.pm file, which is
-no longer required and can be removed:
-
-[source, bash]
------------------------------------------------------------------
-perldoc -l OpenILS::Application::Ingest
------------------------------------------------------------------

commit 1a2d5bb17a1a4c65a29442c0784d2e1f2e58c981
Author: Dan Wells <dbw2 at calvin.edu>
Date:   Mon Feb 24 17:43:29 2014 -0500

    Bump OpenILS.pm version
    
    Signed-off-by: Dan Wells <dbw2 at calvin.edu>

diff --git a/Open-ILS/src/perlmods/lib/OpenILS.pm b/Open-ILS/src/perlmods/lib/OpenILS.pm
index d7235ce..626b272 100644
--- a/Open-ILS/src/perlmods/lib/OpenILS.pm
+++ b/Open-ILS/src/perlmods/lib/OpenILS.pm
@@ -6,6 +6,6 @@ OpenILS - Client and server support for the Evergreen open source library system
 
 =cut
 
-our $VERSION = '2.4';
+our $VERSION = '2.0600';
 
 1;

commit 3aa9799d3cf8991f0b5644dd88a2ca2ee7a30291
Author: Dan Wells <dbw2 at calvin.edu>
Date:   Thu Jan 16 15:07:40 2014 -0500

    Changes to smooth out make_release
    
    1) Make the fake 'HeadURL' into a URL which works with our web repo.
    Note that this has 'tags/' hardcoded in, so it only works with true
    release branches (e.g. rel_x_y_z) not "working" branches
    (e.g. rel_x_y).
    
    2) Change range selector when building log to better exclude commits
    from previous releases.
    
    Signed-off-by: Dan Wells <dbw2 at calvin.edu>

diff --git a/build/tools/make_release b/build/tools/make_release
index c52565d..36b37f0 100755
--- a/build/tools/make_release
+++ b/build/tools/make_release
@@ -2,7 +2,7 @@
 
 GIT_ABS=`git rev-parse --show-toplevel`
 GIT_BRANCH=`git rev-parse --abbrev-ref HEAD | sed 's|.*/||'`
-HEADURLBASE="http://git.evergreen-ils.org/Evergreen.git?h=refs/heads/"
+HEADURLBASE="http://git.evergreen-ils.org/?p=Evergreen.git;a=shortlog;h=refs/heads/tags/"
 HEADURL="$HEADURLBASE$GIT_BRANCH"
 
 # Drop to the root of the checkout
@@ -258,7 +258,7 @@ if [ $PREV_BRANCH != "PACKAGE" ]; then
     grep -i -m 1 Signed-off-by ChangeLog &> /dev/null
     if [ $? -ne 0 ]; then
         echo "Building ChangeLog"
-        git log --cherry-pick --right-only --no-merges --pretty --summary --numstat $PREV_BRANCH..HEAD > $GIT_ABS/ChangeLog
+        git log --cherry-pick --right-only --no-merges --pretty --summary --numstat $PREV_BRANCH...HEAD > $GIT_ABS/ChangeLog
     else
         echo "Not overwriting existing ChangeLog!"
     fi

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


hooks/post-receive
-- 
Evergreen ILS


More information about the open-ils-commits mailing list